HNCTF_PyJail练习
通过HNCTF的题目学习PyJail
分析过程和wp主要参考:
https://zhuanlan.zhihu.com/p/578966149
calc_jail_beginner
下载附件
|  |  | 
payload
|  |  | 
calc_jail_beginner_level1
|  |  | 
过滤了
|  |  | 
payload1
|  |  | 
payload2
从显示带有元组的子类入手
|  |  | 
其中的b会被ban,使用getattr()函数
|  |  | 
但其中的单引号会被ban,使用ascii2chr的拼接
|  |  | 
得到
|  |  | 
对__subclasses__同样的方式绕过
|  |  | 
倒数第四个子类<class 'os._wrap_close'>,则payload
|  |  | 
使用以上方法绕过,得到
|  |  | 
calc_jail_beginner_level2
|  |  | 
限制传入字符不大于13
参数逃逸
|  |  | 
calc_jail_beginner_level2.5
|  |  | 
payload
|  |  | 
就会进到Pdb里面,随后pj直接一句话RCE
calc_jail_beginner_level3
|  |  | 
限制传入字符不大于7
可以通过help函数来进行RCE
开始输入help(),进入到help界面,然后随便找个模块,例如os输入,此时就会显示os模块的帮助页面,输入!sh就能进到shell里面去。
payload
|  |  | 
python2 input
|  |  | 
- 在python 2中,
input函数从标准输入接收输入,并且自动eval求值,返回求出来的值;- 在python 2中,
raw_input函数从标准输入接收输入,返回输入字符串;- 在python 3中,
input函数从标准输入接收输入,返回输入字符串;- 可以认为,python 2
input()= python 2eval(raw_input())= python 3eval(input())
如果碰到python 2中间用了input函数,那么我们就可以直接一句话RCE:
|  |  | 
lake lake lake
|  |  | 
这个key变量是全局变量,可以用globals()来泄露所有全局变量的值
|  |  | 
|  |  | 
l@ke l@ke l@ke
|  |  | 
calc_jail_beginner_level3的方法不能完全生效
|  |  | 
laKe laKe laKe
|  |  | 
这道题涉及到对python random库中函数的分析
分析过程参考
|  |  | 
payload
|  |  | 
4 byte command
题目无附件,有回显
|  |  | 
payload
|  |  | 
另外,读取server.py发现
|  |  | 
直接将输入的内容作为os.system()参数
其他短字符串绕过姿势可以参考
https://xiaolong22333.top/archives/201/
lak3 lak3 lak3
|  |  | 
tyPe Ch@nnEl
|  |  | 
侧信道注入….没打通
calc_jail_beginner_level4
|  |  | 
Show subclasses with tuple:
|  |  | 
但’被ban了 **方法1:**利用bytes的ASCII list初始化方式
|  |  | 
**方法2:**利用__doc__魔术方法
可以从__doc__里面去找,用索引的方式得到想要的字符,并拼接在一起,得到我们想要的字符串。
|  |  | 
找到对应的偏移量
|  |  | 
得到19,然后在payload里面直接使用().__doc__[19],就得到了字符's'
payload
|  |  | 
**方法3:**直接读flag
|  |  | 
calc_jail_beginner_level4.0.5
没有源码
|  |  | 
calc_jail_beginner_level4的两种方法仍然可以用
calc_jail_beginner_level4.1
|  |  | 
把bytes删掉了
Show subclasses with tuple:
|  |  | 
发现byte类在索引6
|  |  | 
#转换为
|  |  | 
calc_jail_beginner_level4.2
|  |  | 
Show subclasses with tuple:
索引byte的方法仍然可以用
|  |  | 
题目将+也ban了,__doc__魔法函数的方法无法直接用
可以改变字符串的拼接方法
|  |  | 
payload
|  |  | 
calc_jail_beginner_level4.3
|  |  | 
calc_jail_beginner_level4.2的payload仍然可以用
|  |  | 
calc_jail_beginner_level5
没有附件,只有回显
|  |  | 
按题目hint输入dir()得到
|  |  | 
随后尝试一句话RCE
|  |  | 
calc_jail_beginner_level5.1
|  |  | 
尝试dir(),随后一句话RCE,发现__import__可能被删了
|  |  | 
尝试Show subclasses with tuple
|  |  | 
calc_jail_beginner_level6
|  |  | 
几乎把所有的hook给ban了
参考https://ctftime.org/writeup/31883
利用_posixsubprocess.fork_exec来RCE
但如果我们直接import _posixsubprocess,会触发audit hook:
|  |  | 
可以通过如下方法绕过:
|  |  | 
或者
|  |  | 
因为是多次exec,所以我们可以输入多行代码:
|  |  | 
calc_jail_beginner_level6.1
|  |  | 
使用海象运算符
|  |  | 
但是起来shell会立刻断掉
|  |  | 
手段也是越来越离谱
s@Fe safeeval
|  |  | 
基于代码字节码的操作码来拦截
无法直接用__import__。类似地,也没法用__builtins__这些变量。
用lambda表达式包裹起一句话RCE:
|  |  | 
顺便查看一波源代码
|  |  | 
在github连接中,查看test_expr的定义
|  |  | 
我们的payload被解析出来的操作码:
|  |  | 
都在题目所给的Black List里面
calc_jail_beginner_level7
|  |  | 
根据python抽象语法树(AST)来拦截输入的
知识盲区了,目前只能照抄:
我们试着输入
1+1:
1 2 3 4 5 6E Pls input your code: (last line must contain only --HNCTF) 1+1 --HNCTF ERROR: Banned statement <ast.Expr object at 0x7f6c147ff6d0> Press any key to continue发现的确ban了Expr,也就是展示的确实是Black List。
不能
import,不能定义函数,也不能用lambda表达式,但是可以执行多行代码。这个时候,我想到了类的定义。经过一段时间的搜索,我找到了如下writeup:
1 2https://gynvael.coldwind.pl/n/python_sandbox_escape # [organizers] Robin_Jadoul solution(不得不说Robin真的太强了,organizers太强了,是我难以企及的偶像……)
1 2 3@exec @input class X: pass这份代码里面只有两个函数装饰器和一个类定义,应该不包含拦截的东西。果然,输入进去之后,程序得到了结果:
1 2 3 4 5 6 7 8E Pls input your code: (last line must contain only --HNCTF) @exec @input class X: pass --HNCTF check is passed!now the result is: <class '__main__.X'>此时再输入一句话RCE的payload:
1__import__('os').system('sh')就可以拿到shell。
 
     
     
     
    