CTF/Writeup

Hack.lu CTF 2018 BabyReverse

JeonYoungSin 2018. 10. 25. 21:18

해당 바이너리와 같은 경우 핵스레이가 안되서 gdb로 디버깅하면서 코드 분석을 했다.


먼저 objudmp로 대충 봐보면 섹션이 하나밖에 없고 크기가 작아서 분석하는데 어려움은 없었다.


0000000000400080 <.text>:

  400080: eb 50                 jmp    0x4000d2

  400082: 48 31 c0              xor    rax,rax 

  400085: fe c0                 inc    al

  400087: 48 31 ff              xor    rdi,rdi

  40008a: 48 ff c7              inc    rdi

  40008d: 5e                    pop    rsi

  40008e: b2 2e                 mov    dl,0x2e

  400090: 0f 05                 syscall 

  400092: 2c 2e                 sub    al,0x2e

  400094: ff cf                 dec    edi

  400096: 0f 05                 syscall 

  400098: 48 0f b6 7e 01        movzx  rdi,BYTE PTR [rsi+0x1] 

  40009d: 48 31 3e              xor    QWORD PTR [rsi],rdi

  4000a0: 48 ff c6              inc    rsi

  4000a3: 48 ff ca              dec    rdx

  4000a6: 75 f0                 jne    0x400098 ; 반복문 end

  4000a8: 83 e1 2e              and    ecx,0x2e

  4000ab: 80 c1 26              add    cl,0x26

  4000ae: 48 8d 7e 07           lea    rdi,[rsi+0x7]

  4000b2: 48 8d 77 cb           lea    rsi,[rdi-0x35]

  4000b6: f3 a6                 repz cmps BYTE PTR ds:[rsi],BYTE PTR es:[rdi]

  4000b8: 48 85 c9              test   rcx,rcx

  4000bb: 75 49                 jne    0x400106

  4000bd: 34 2f                 xor    al,0x2f

  4000bf: 68 59 61 79 21        push   0x21796159

  4000c4: 48 89 e6              mov    rsi,rsp

  4000c7: b2 04                 mov    dl,0x4

  4000c9: bf 01 00 00 00        mov    edi,0x1

  4000ce: 0f 05                 syscall 

  4000d0: eb 34                 jmp    0x400106

  4000d2: e8 ab ff ff ff        call   0x400082 

  4000d7: 57                    push   rdi

  4000d8: 65 6c                 gs ins BYTE PTR es:[rdi],dx

  4000da: 63 6f 6d              movsxd ebp,DWORD PTR [rdi+0x6d]

  4000dd: 65 20 74 6f 20        and    BYTE PTR gs:[rdi+rbp*2+0x20],dh

  4000e2: 74 68                 je     0x40014c

  4000e4: 69 73 20 43 68 61 6c  imul   esi,DWORD PTR [rbx+0x20],0x6c616843

  4000eb: 6c                    ins    BYTE PTR es:[rdi],dx

  4000ec: 21 20                 and    DWORD PTR [rax],esp

  4000ee: 0a 45 6e              or     al,BYTE PTR [rbp+0x6e]

  4000f1: 74 65                 je     0x400158

  4000f3: 72 20                 jb     0x400115

  4000f5: 74 68                 je     0x40015f

  4000f7: 65 20 4b 65           and    BYTE PTR gs:[rbx+0x65],cl

  4000fb: 79 20                 jns    0x40011d

  4000fd: 74 6f                 je     0x40016e

  4000ff: 20 77 69              and    BYTE PTR [rdi+0x69],dh

  400102: 6e                    outs   dx,BYTE PTR ds:[rsi]

  400103: 3a 20                 cmp    ah,BYTE PTR [rax]

  400105: 00 31                 add    BYTE PTR [rcx],dh

  400107: c0                    (bad)  

  400108: b0 3c                 mov    al,0x3c

  40010a: 0f 05                 syscall 

  40010c: 0a 0d 06 1c 22 38     or     cl,BYTE PTR [rip+0x38221c06]        # 0x38621d18

  400112: 18 26                 sbb    BYTE PTR [rsi],ah

  400114: 36 0f 39              ss (bad) 

  400117: 2b 1c 59              sub    ebx,DWORD PTR [rcx+rbx*2]

  40011a: 42 2c 36              rex.X sub al,0x36

  40011d: 1a 2c 26              sbb    ch,BYTE PTR [rsi+riz*1]

  400120: 1c 17                 sbb    al,0x17

  400122: 2d 39 57 43 01        sub    eax,0x1435739

  400127: 07                    (bad)  

  400128: 2b 38                 sub    edi,DWORD PTR [rax]

  40012a: 09 07                 or     DWORD PTR [rdi],eax

  40012c: 1a 01                 sbb    al,BYTE PTR [rcx]

  40012e: 17                    (bad)  

  40012f: 13 13                 adc    edx,DWORD PTR [rbx]

  400131: 17                    (bad)  

  400132: 2d 39 0a 0d 06        sub    eax,0x60d0a39

  400137: 46 5c                 rex.RX pop rsp

  400139: 7d                    .byte 0x7d



전체적인 흐름은 syscall을 통해 입력 값을 받고 input[i]^input[i+1] 연산을 총 46회 반복한다.


이 값이 특정영역의 값과 같으면 되는데 특정영역의 값은  repz cmps BYTE PTR ds:[rsi],BYTE PTR es:[rdi] 요 명령어 실행 시 rdi 레지스터에 존재하는 주소에서 46 byte 값을 써주면 된다.


로직이 간단해서 코드 짜는건 간단했고 z3로 돌려주니 flag가 나왔다.


from z3 import *


result = [0x0a,0x0d,0x06,0x1c,0x22,0x38,0x18,0x26,0x36,0x0f,0x39,0x2b,0x1c,0x59,0x42,0x2c,0x36,0x1a,0x2c,0x26,0x1c,0x17,0x2d,0x39,0x57,0x43,0x01,0x07,0x2b,0x38,0x09,0x07,0x1a,0x01,0x17,0x13,0x13,0x17,0x2d,0x39,0x0a,0x0d,0x06,0x46,0x5c,0x7d,0x00]

a = []

s = Solver()


for i in range(0,47):

    a.append(BitVec('a['+str(i)+']',8))


for i in range(0,46):

    s.add( (a[i]^a[i+1])==result[i])


flag = ""

while s.check() == z3.sat:

    flag = ""

    m = s.model()

    for i in range(0, 47):

        flag += chr(int(str(m[a[i]])))

    if "flag" in flag:

        print flag

    for i in range(0,47):

        s.add(m[a[i]]!=a[i])



Flag = flag{Yay_if_th1s_is_yer_f1rst_gnisrever_flag!}