티스토리 뷰

Wargame & CTF/CTF

[Codegate 2018] RedVelvet

Tribal 2018. 2. 5. 14:55

  Reversing 분야의 문제이다. 사용자로부터 flag 값을 입력받는다. 바이너리에는 총 15개의 flag 검증 루틴이 존재하고, 사용자로부터 입력받아 검증된 flag가 SHA256으로 연산했을 때 특정 값과 동일해야 한다.


  중간에 Anti-Reversing이 걸려있긴 한데, 바이너리 패치로 간단하게 우회할 수 있으므로 무시해도 되며, 중요한 부분은 func 함수와 SHA256 연산 후, strcmp 함수이다. func 함수의 루틴은 z3나 순수 리버싱으로 풀어도 되지만, 귀찮아서 angr를 사용하였다.


angr 소스코드

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
#!/usr/bin/python
import angr
 
def main():
    p = angr.Project('./RedVelvet', load_options={"auto_load_libs": False})
    state = p.factory.blank_state(addr=0x4011A9)
 
    hinput = state.se.BVS('input'27 * 8)
    for byte in hinput.chop(8):
        state.add_constraints(byte >= 0x20)
        state.add_constraints(byte <= 0x7D)
 
    state.add_constraints(hinput.chop(8)[0== 'W')
    state.add_constraints(hinput.chop(8)[1== 'h')
    state.add_constraints(hinput.chop(8)[2== 'a')
    state.add_constraints(hinput.chop(8)[3== 't')
    state.add_constraints(hinput.chop(8)[4== '_')
    state.add_constraints(hinput.chop(8)[5== 'Y')
    state.add_constraints(hinput.chop(8)[6== 'o')
    state.add_constraints(hinput.chop(8)[7== 'u')
    state.add_constraints(hinput.chop(8)[8== '_')
    state.add_constraints(hinput.chop(8)[9== 'W')
    state.add_constraints(hinput.chop(8)[10== 'a')
    state.add_constraints(hinput.chop(8)[11== 'n')
    state.add_constraints(hinput.chop(8)[12== 'n')
    state.add_constraints(hinput.chop(8)[13== 'a')
    state.add_constraints(hinput.chop(8)[14== '_')
    state.add_constraints(hinput.chop(8)[15== 'B')
    state.add_constraints(hinput.chop(8)[16== 'e')
    state.add_constraints(hinput.chop(8)[17== '?')
    state.add_constraints(hinput.chop(8)[18== ':')
    state.add_constraints(hinput.chop(8)[19== ')')
    state.add_constraints(hinput.chop(8)[20== '_')
    state.add_constraints(hinput.chop(8)[21== 'l')
    state.add_constraints(hinput.chop(8)[22== 'c')
    state.add_constraints(hinput.chop(8)[23== '_')
    state.add_constraints(hinput.chop(8)[24== 'l')
    state.add_constraints(hinput.chop(8)[25== 'a')
    
 
    path_group = p.factory.simgr(state)
    path_group.explore(find=0x401606, avoid=0x401626)
 
    found = path_group.found[0]
    print found.state.posix.dumps(0).split('\0')[0]
 
if __name__ == '__main__':
    main()
 
cs

  angr의 수행 결과, "What_You_Wanna_Be?:)_lc_la" 라는 문자열을 얻을 수 있었는데, 실제로 입력해 보면 검증루틴을 전부 통과하는 것을 확인할 수 있다. 이것으로 풀리면 좋겠지만, 아쉽게도 SHA256으로 연산된 해시 값의 결과가 다르기 때문에 인증 flag는 아니다. 그래서 z3를 추가로 사용하여 값을 확인해 보았다.


z3 소스코드

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#!/usr/bin/python
from z3 import *
 
def solver1(s, x, y):
    s.add(x * 2 * (y ^ x) - y == 10858, x > 85, x <= 95, y > 96, y <= 111)
 
def solver2(s, x, y):
    s.add(x % y == 7, y > 90 )
 
def solver3(s, x, y):
    s.add(x / y + (y ^ x) == 21, x <= 99, y <= 119)
 
def solver4(s, x, y):
    s.add(((y ^ x ^ y) + ((y ^ x ^ y) >> 32)*0x100000000 % y) + x == 137, x > 115 y == 95)
 
def solver5(s, x, y):
    s.add(((y + x) ^ (x ^ y ^ x)) == 225, x > 90, y <= 89)
 
def solver6(s, x, y, z):
    s.add(x <= y, y <= z, x > 85, y > 110, z > 115, ((y + z) ^ (x + y)) == 44, (y + z) % x + y == 161)
 
def solver7(s, x, y, z):
    s.add(x >= y, y >= z, x <= 119, y > 90, z <= 89, ((x + z) ^ (y + z)) == 122, (x + z) % y + z == 101)
 
def solver8(s, x, y, z):
    s.add(x <= y, y <= z, z <= 114, (x + y) / z * y == 97, (z ^ (x - y)) * y == -10088, z <= 114)
 
def solver9(s, x, y, z):
    s.add(x == y, y >= z, z <= 99, z + x * (z - y) - x == -1443)
 
def solver10(s, x, y, z):
    s.add(x >= y, y >= z, y * (x + z + 1- z == 15514, y > 90, y <= 99)
 
def solver11(s, x, y, z):
    s.add(y >= x, x >= z, y > 100, y <= 104, x + (y ^ (y - z)) - z == 70, (y + z) / x + x == 68)
 
def solver12(s, x, y, z):
    s.add(x >= y, y >= z, y <= 59, z <= 44, x + (y ^ (z + y)) - z == 111, (y ^ (y - z)) + y == 101)
 
def solver13(s, x, y, z):
    s.add(x <= y, y <= z, x > 40, y > 90, z <= 109, z + (y ^ (z + x)) - x == 269, (z ^ (y - x)) + y == 185)
 
def solver14(s, x, y, z):
    s.add(x >= z, y >= z, y <= 99, z > 90, x + (y ^ (y + x)) - z == 185)
 
def solver15(s, x, y, z):
    s.add(y >= z, y >= x, z > 95, y <= 109, ((y - x) * y ^ z) - x == 1214, ((z - y) * z ^ x) + y == -1034)
 
def main():
    array = [ BitVec('a%i'%i,8for i in range(0,26)]
 
    s = Solver()
#    solver1(s, array[0], array[1])
#    solver2(s, array[1], array[2])
#    solver3(s, array[2], array[3])
#    solver4(s, array[3], array[4])
#    solver5(s, array[4], array[5])
#    solver6(s, array[5], array[6], array[7])
#    solver7(s, array[7], array[8], array[9])
#    solver8(s, array[9], array[10], array[11])
#    solver9(s, array[11], array[12], array[13])
#    solver10(s, array[13], array[14], array[15])
#    solver11(s, array[15], array[16], array[17])
#    solver12(s, array[17], array[18], array[19])
    solver13(s, array[19], array[20], array[21])
    solver14(s, array[21], array[22], array[23])
    solver15(s, array[23], array[24], array[25])
 
    for i in range(026):
        s.add(array[i] >= 0x20 and array[i] <= 0x7e)
 
    print s.check()
    print s.model()
 
if __name__ == '__main__':
    main()
 
cs

  중간 중간 sat를 만족하지 않는 식이 작성되어, angr의 결과를 어느정도 신뢰하여 주석처리 하였다. 그래서 맨 뒷 9자를 확인해본 결과, "?:)_l`_la"를 얻을 수 있었다. angr의 결과와 매우 유사한데, 이유는 solver14의 결과로 제법 다양한 값이 나올 수 있기 때문에 그렇다. 검증 루틴을 전부 통과할 수 있는 flag 값은 여러 개이지만, SHA256 해시 값이 다르게 되는 이유이다.


  c와 `를 넣으면 검증 루틴을 통과하지만, 인증 flag가 아니기 때문에 더 다양한 문자가 나올 수 있다고 추측할 수 있고, `와 c 사이의 문자를 하나씩 입력해본 결과, a인 것을 확인할 수 있었다.



'Wargame & CTF > CTF' 카테고리의 다른 글

[Codegate 2018] Super Marimo  (0) 2018.02.05
[Codegate 2018] BaskinRobins31  (0) 2018.02.05
[Defcon 2017 예선] beatmeonthedl  (0) 2017.05.01
[Defcon 2017 예선] smashme  (0) 2017.05.01
[Code Gate 2017] Messenger  (0) 2017.02.16
댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
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