RedVelvet

gdb를 이용해 리버싱을 해보면 우선 사용자의 input을 받은 다음 func1 ~ func15 까지 15개의 함수에 사용자 input을 2~3개씩 쪼개서 각 함수의 인자로 넣어준다. 그리고 함수안에서 어떠한 계산 후 계산의 결과와 input 값이 일치하는지 확인 후 일치하면 HAPPINESS!라는 문자열이 출력된다.

한 함수라도 통과하지 못하면 프로그램이 종료한다.

함수를 전부 통과하게되면 각 함수마다 한번씩 총 15번 HAPPINESS!라는 문자열이 출력된 후 전부 통과하게 되면 플래그를 뱉어준다.


처음에는 손으로 직접 리버싱하여 함수를 분석한 후 약간(?) 노가다로 키를 구하는 방식으로 하다가 더 편한 방법을 찾았다.

python에 z3라는 라이브러리를 이용하면 수학식을 계산해서 값을 뽑아줄 수 있다.

 

func10까지는 노가다로 구했다가 func11부터 15까지는 라이브러리를 이용해 풀었다.

아래는 키를 구하는 코드다.

#sha256_hash = 0a435f46288bb5a764d13fca6c901d3750cee73fd7689ce79ef6dc0ff8f380e5
from z3 import *

s = Solver()

for i in range(1,27):
        globals()['a%i'%i]=BitVec('a%i'%i,32)

#func1
s.add(a1 * 2 * (a1 ^ a2)  - a2 == 0x2a6a)
s.add(a1 > 0x55)
s.add(a1 <= 0x5f)
s.add(a2 > 0x60)
s.add(a2 <= 0x6f)

#func2
s.add(a2 % a3 == 0x7)
s.add(a2 > 0x5a)

#func3
s.add(a3 / a4 +(a4 ^ a3) == 0x15)
s.add(a3 <= 0x63)
s.add(a4 <= 0x77)

#func4
s.add(a5 == 0x5f)

#func5
s.add((a6 + a5)^(a5 ^ a6 ^ a5 ) == 0xe1)
s.add(a5 > 0x5a)
s.add(a6 <= 0x59)

#func6
s.add(a6 <= a7)
s.add(a7 <= a8)
s.add(a6 > 0x55)
s.add(a7 > 0x6e)
s.add(a8 > 0x73)
s.add((a7+a8) ^ (a6 + a7) == 0x2c)
s.add((a7 + a8)%a6 + a7  == 0xa1)

#func7
s.add(a8 >= a9)
s.add(a9 >= a10)
s.add(a8 <= 0x77)
s.add(a9 > 0x5a)
s.add(a10 <= 0x59)
s.add((a8 + a10) ^ (a9 + a10) == 0x7a)
s.add((a8 + a10) % a9 + a10 == 0x65)

#func8
s.add(a10 <= a11)
s.add(a11 <= a12)
s.add(a12 <= 0x72)
s.add((a10 + a11) / a12 * a11 == 0x61)
s.add((a12 ^ (a10 - a11)) * a11 == 0xffffd898)

#func9
s.add(a12 == a13)
s.add(a13 >= a14)
s.add(a14 <= 0x63)
s.add(a14 + a12 * (a14 - a13) - a12 == 0xfffffa5d)

#func10
s.add(a14 >= a15)
s.add(a15 >= a16)
s.add(a15 * (a14 + a16 + 1) - a16 == 0x3c9a)
s.add(a15 > 0x5a)
s.add(a15 <= 0x63)

#func11
s.add(a17 >= a16)
s.add(a16 >= a18)
s.add(a17 > 0x64)
s.add(a17 <= 0x68)
s.add(a16 + (a17 ^ (a17- a18)) - a18 == 0x46)
s.add((a17 + a18) / a16 + a16 == 0x44)

#func12
s.add(a18 >= a19)
s.add(a19 >= a20)
s.add(a19 <= 0x3b)
s.add(a20 <= 0x2c)
s.add(a18 + (a19 ^ (a20 + a19)) - a20 == 0x6f)
s.add((a19 ^ (a19 - a20)) + a19 == 0x65)

#func13
s.add(a22 + (a21 ^ (a20 + a22)) - a20 == 0x10d)
s.add((a22 ^ (a21 - a20)) + a21 == 0xb9)
s.add(a20 <= a21)
s.add(a21 <= a22)
s.add(a20 > 0x28)
s.add(a21 > 0x5a)
s.add(a22 <= 0x6d)

#func14
s.add(a22 + (a23 ^ (a22 + a23)) - a24 == 0xb9)
s.add(a22 >= a24)
s.add(a23 >= a24)
s.add(a23 <= 0x63)
s.add(a24 > 0x5a)

#func15
s.add((a26 ^ ((a25 - a24) * a25)) - a24 == 0x4be)
s.add((a24 ^ ((a26 - a25) * a26)) + a25 == 0xfffffbf6)
s.add(a25 >= a26)
s.add(a25 >= a24)
s.add(a26 > 0x5f)
s.add(a25 <= 0x6d)

print s.check()
#print s.model()

if (s.check() == sat):
        values =s.model()
        flag=""
        for i in range(1,27):
                obj = globals()['a%i' % i]
                char = values[obj].as_long()
                flag += chr(char)
        print flag


FLAG : What_You_Wanna_Be?:)_lc_la



lc_la라고 나오는데 이 값을 your flag에 입력하면 flag를 뱉지 않는다.

gdb로 어셈을 보다보면 sha256으로 내가 입력한 flag를 암호화한 다음 gdb 내에 있는 0a435f46288bb5a764d13fca6c901d3750cee73fd7689ce79ef6dc0ff8f380e5 이 값과 비교를 해서 같으면 플래그를 뱉어준다.

아마 저 암호화된 값은 진짜 flag를 SHA256으로 암호화 한 것으로 보인다.

게싱으로 lc를 la로 바꿔서 What_You_Wanna_Be?:)_la_la로 입력하면 플래그를 뱉어준다.


Ref. http://revers3r.tistory.com/103?category=112084

Ref. https://github.com/AnisBoss/CTFs/blob/master/Codegate%20CTF%202018/RedVelvet%20-%20254pts%20(Rev)/solve.py


'CTF > Codegate' 카테고리의 다른 글

codegate2019 20000  (0) 2019.02.07
codegate 2018 super marimo  (0) 2019.01.19
CodeGate2018 BaskinRobins31  (0) 2018.07.14

+ Recent posts