본문 바로가기
Wargame Write-Up/HackCTF

[HackCTF] (Reversing) Static 풀이

by snwo 2020. 3. 14.

문제를 다운받고 실행하면 Nope 이 나온다.

ELF64 파일인데, 아이다로 열어보면 사용되는함수밖에 나오지 않는다.

 

int __cdecl __libc_start_main( int (__cdecl *main)(int, char **, char **), int argc, char **ubp_av, void (*init)(void), void (*fini)(void), void (*rtld_fini)(void), void *stack_end)

__libc_start_main 함수이다. 이 함수에서 main 함수를 호출하는데,

동적분석으로 인자로 받는 main함수의 위치를 알아보자


main 함수는 0x555555554a3a 에 있다고한다.


[ main ]

 

지금부터 메인함수를 나눠서 설명해드릴께요

 

 0x555555554a42:    mov    DWORD PTR [rbp-0x24],edi
 0x555555554a45:    mov    QWORD PTR [rbp-0x30],rsi
  • rbp-0x24 : argc ( main함수 인자개수 )
  • rbp-0x30 : argv ( main함수 인자 )
   0x555555554a58:    lea    rdi,[rip+0x151]        # "team_name"
   0x555555554a5f:    call   0x5555555546a0 <getenv@plt>
   0x555555554a64:    mov    QWORD PTR [rbp-0x10],rax
   0x555555554a68:    cmp    QWORD PTR [rbp-0x10],0x0
   0x555555554a6d:    je     0x555555554af3
   0x555555554a73:    mov    rax,QWORD PTR [rbp-0x10]
   0x555555554a77:    mov    edx,0x4
   0x555555554a7c:    lea    rsi,[rip+0x137]        # "bi0s"
   0x555555554a83:    mov    rdi,rax
   0x555555554a86:    call   0x5555555546b0 <strncmp@plt>
   0x555555554a8b:    test   eax,eax
   0x555555554a8d:    jne    0x555555554af3

 team_name 이란 환경변수값을 가져와서 있는지없는지 검사후, 그 값을 bi0s 와 비교 (조건 불만족시 종료 )

 

   0x555555554a8f:    cmp    DWORD PTR [rbp-0x24],0x2
   0x555555554a93:    je     0x555555554aa8
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   0x555555554aa8:    mov    rax,QWORD PTR [rbp-0x30]
   0x555555554aac:    add    rax,0x8
   0x555555554ab0:    mov    rdx,QWORD PTR [rax]
   0x555555554ab3:    mov    rax,QWORD PTR [rbp-0x10]
   0x555555554ab7:    mov    rsi,rdx
   0x555555554aba:    mov    rdi,rax
   0x555555554abd:    call   0x55555555487c

main 함수의 인자가 두개이면, 0x55555555487c  호출,

인자 :  argv[1](main함수 두번째인자), "bi0s" 

 

   0x555555554ac2:    mov    DWORD PTR [rbp-0x14],eax
   0x555555554ac5:    cmp    DWORD PTR [rbp-0x14],0x1
   0x555555554ac9:    jne    0x555555554ae0
   0x555555554acb:    mov    rax,QWORD PTR [rbp-0x30]
   0x555555554acf:    add    rax,0x8
   0x555555554ad3:    mov    rax,QWORD PTR [rax]
   0x555555554ad6:    mov    rdi,rax
   0x555555554ad9:    call   0x555555554830
   0x555555554ade:    jmp    0x555555554b04

0x55555555487c 의 리턴값이 1이면, 0x55555554830 호출하고 종료 


[ 0x55555554830 ]

암호화된 문자열 출력함수

HackCTF{ %s }


[ 0x55555555487c ]

문자열 암호화 후 비교함수 

   0x555555554885:    mov    QWORD PTR [rbp-0x68],rdi
   0x555555554889:    mov    QWORD PTR [rbp-0x70],rsi
   0x55555555488d:    mov    DWORD PTR [rbp-0x18],0x0
   0x555555554894:    mov    DWORD PTR [rbp-0x1c],0x0
   0x55555555489b:    movabs rax,0x3931383137313631
   0x5555555548a5:    mov    QWORD PTR [rbp-0x40],rax
   0x5555555548a9:    movabs rax,0x3731363138333632
   0x5555555548b3:    mov    QWORD PTR [rbp-0x38],rax
   0x5555555548b7:    mov    DWORD PTR [rbp-0x30],0x31393139
   0x5555555548be:    mov    WORD PTR [rbp-0x2c],0x3439
   0x5555555548c4:    mov    BYTE PTR [rbp-0x2a],0x0
  • rbp-0x68 : "bi0s"
  • rbp-0x70 : argv[1] ( 입력한 문자열 )
  • rbp-0x40 : "1617181926381617919194"
   0x5555555548c8:    mov    rax,QWORD PTR [rbp-0x70]
   0x5555555548cc:    mov    rdi,rax
   0x5555555548cf:    call   0x5555555546c0 <strlen@plt>
   0x5555555548d4:    cmp    rax,0x16
   0x5555555548d8:    je     0x5555555548e4

 입력한 문자열 길이가 0x16 (22) 이여야한다.

 

   0x5555555548e4:    mov    DWORD PTR [rbp-0x14],0x0
   0x5555555548eb:    jmp    0x555555554907
   0x5555555548ed:    mov    eax,DWORD PTR [rbp-0x14]
   0x5555555548f0:    movsxd rdx,eax
   0x5555555548f3:    mov    rax,QWORD PTR [rbp-0x68]
   0x5555555548f7:    add    rax,rdx
   0x5555555548fa:    movzx  eax,BYTE PTR [rax]
   0x5555555548fd:    movsx  eax,al
   0x555555554900:    add    DWORD PTR [rbp-0x18],eax
   0x555555554903:    add    DWORD PTR [rbp-0x14],0x1
   0x555555554907:    mov    eax,DWORD PTR [rbp-0x14]
   0x55555555490a:    movsxd rbx,eax
   0x55555555490d:    mov    rax,QWORD PTR [rbp-0x68]
   0x555555554911:    mov    rdi,rax
   0x555555554914:    call   0x5555555546c0 <strlen@plt>
   0x555555554919:    cmp    rbx,rax
   0x55555555491c:    jb     0x5555555548ed

while( i < 4 ) {

    [ rbp-0x18 ] += [ rbp-0x68 ][ i ]    # "bi0s"

}

rbp-0x68 = 0x16e (366)

   0x55555555492d:    mov    ecx,DWORD PTR [rbp-0x18]
   0x555555554930:    mov    edx,0x88888889
   0x555555554935:    mov    eax,ecx
   0x555555554937:    imul   edx
   0x555555554939:    lea    eax,[rdx+rcx*1]
   0x55555555493c:    sar    eax,0x4
   0x55555555493f:    mov    edx,eax
   0x555555554941:    mov    eax,ecx
   0x555555554943:    sar    eax,0x1f
   0x555555554946:    sub    edx,eax
   0x555555554948:    mov    eax,edx
   0x55555555494a:    mov    DWORD PTR [rbp-0x18],eax

[rbp-0x18] = (0x16e * 0x88888889 의 상위 8바이트) >> 4 - 0x16e >> 0x1F (31)

[rbp-0x18] = 0xC (12)

 

   0x55555555494d:    cmp    DWORD PTR [rbp-0x1c],0x16
   0x555555554951:    je     0x5555555549b9
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   0x55555555497d:    mov    eax,DWORD PTR [rbp-0x1c]
   0x555555554980:    movsxd rdx,eax
   0x555555554983:    mov    rax,QWORD PTR [rbp-0x70]
   0x555555554987:    add    rax,rdx
   0x55555555498a:    movzx  eax,BYTE PTR [rax]
   0x55555555498d:    sub    eax,0x4
   0x555555554990:    mov    edx,eax
   0x555555554992:    mov    eax,DWORD PTR [rbp-0x1c]
   0x555555554995:    cdqe   
   0x555555554997:    mov    BYTE PTR [rbp+rax*1-0x60],dl   `다음코드는 99b`
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   0x555555554953:    mov    eax,DWORD PTR [rbp-0x1c]
   0x555555554956:    and    eax,0x1
   0x555555554959:    test   eax,eax
   0x55555555495b:    jne    0x55555555497d
   0x55555555495d:    mov    eax,DWORD PTR [rbp-0x1c]
   0x555555554960:    movsxd rdx,eax
   0x555555554963:    mov    rax,QWORD PTR [rbp-0x70]
   0x555555554967:    add    rax,rdx
   0x55555555496a:    movzx  eax,BYTE PTR [rax]
   0x55555555496d:    add    eax,0x4
   0x555555554970:    mov    edx,eax
   0x555555554972:    mov    eax,DWORD PTR [rbp-0x1c]
   0x555555554975:    cdqe   
   0x555555554977:    mov    BYTE PTR [rbp+rax*1-0x60],dl
   0x55555555497b:    jmp    0x55555555499b
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   0x55555555499b:    mov    eax,DWORD PTR [rbp-0x1c]
   0x55555555499e:    cdqe   
   0x5555555549a0:    movzx  edx,BYTE PTR [rbp+rax*1-0x60]
   0x5555555549a5:    mov    eax,DWORD PTR [rbp-0x18]
   0x5555555549a8:    xor    edx,eax
   0x5555555549aa:    mov    eax,DWORD PTR [rbp-0x1c]
   0x5555555549ad:    cdqe   
   0x5555555549af:    mov    BYTE PTR [rbp+rax*1-0x60],dl
   0x5555555549b3:    add    DWORD PTR [rbp-0x1c],0x1
   0x5555555549b7:    jmp    0x55555555494d

while ( i < 0x16 (22) ) {

if (i%2==1) 

    [rbp-0x60][ i ] = [ rbp-0x70 ][ i ] - 4

else

    [rbp-0x60][ i ] = [ rbp-0x70 ][ i ] + 4    #짝수홀수 구분, 짝수는 +4, 홀수는 -4

 

[rbp-0x60][ i ] = [rbp-0x60][ i ] ^ 0xC

i++

}

 

   0x5555555549c9:    lea    rax,[rbp-0x60]
   0x5555555549cd:    mov    rdi,rax
   0x5555555549d0:    call   0x5555555546c0 <strlen@plt>
   0x5555555549d5:    sub    eax,0x1
   0x5555555549d8:    mov    DWORD PTR [rbp-0x14],eax
   0x5555555549db:    jmp    0x555555554a19
   0x5555555549dd:    lea    rax,[rbp-0x60]
   0x5555555549e1:    mov    rdi,rax
   0x5555555549e4:    call   0x5555555546c0 <strlen@plt>
   0x5555555549e9:    mov    rdx,rax
   0x5555555549ec:    mov    eax,DWORD PTR [rbp-0x14]
   0x5555555549ef:    cdqe   
   0x5555555549f1:    sub    rdx,rax
   0x5555555549f4:    mov    rax,rdx
   0x5555555549f7:    sub    rax,0x1
   0x5555555549fb:    movzx  edx,BYTE PTR [rbp+rax*1-0x60]
   0x555555554a00:    mov    eax,DWORD PTR [rbp-0x14]
   0x555555554a03:    cdqe   
   0x555555554a05:    movzx  eax,BYTE PTR [rbp+rax*1-0x40]
   0x555555554a0a:    cmp    dl,al
   0x555555554a0c:    je     0x555555554a15
   0x555555554a0e:    mov    eax,0x0
   0x555555554a13:    jmp    0x555555554a33
   0x555555554a15:    sub    DWORD PTR [rbp-0x14],0x1
   0x555555554a19:    cmp    DWORD PTR [rbp-0x14],0x0
   0x555555554a1d:    jns    0x5555555549dd
   0x555555554a1f:    mov    DWORD PTR [rbp-0x24],0x0
   0x555555554a26:    cmp    DWORD PTR [rbp-0x24],0x1
   0x555555554a2a:    jne    0x555555554a2e

i=0x16

t = 0x15

while( i>0 ) {

if ( [rbp-0x60][ i-t ] != [rbp-0x40][ t ] ) #문자열을 역순으로 가져온다

    #종료

t--

}


[ 최종 암호화루틴 ]

 

[rbp-0x40] : "1617181926381617919194"

[rbp-0x18] = 0xC

[rbp-0x68] = 0x16e

i=0

while ( i < 0x16 (22) ) {

if (i%2==1) 

    [rbp-0x60][ i ] = [ rbp-0x70 ][ i ] - 4

else

    [rbp-0x60][ i ] = [ rbp-0x70 ][ i ] + 4    

[rbp-0x60][ i ] = [rbp-0x60][ i ] ^ 0xC

i++

}

i=0x16

t = 0x15

while( i>0 ) {

if ( [rbp-0x60][ i-t ] != [rbp-0x40][ t ] )

    break

t--

}

 

헨드레이하느라 힘들었다. 이제 이걸 이용해 복호화하는 코드로 옮겨보자


[ python ]

 

[rbp-0x40] 에서 [rbp-2B] ~ [rbp-0x40] 이렇게 역순으로 가져오기때문에, 

역순으로 변수에 저장한다.

encoded="1617181926381617919194"
encoded=encoded[::-1] 
var18=0xC
var68=0x16e
s=""
for i in range(0,0x16):
        t=ord(encoded[i])^var18
        if i%2==1:
                t+=4
        else :
                t-=4
        s+=chr(t)

print("HackCTF{"+s+"}")

flag 가 의미없는 숫자로 나오길래 망했다 생각했지만, FLAG 였다.

 

[배운점]

 

handray 와 동적분석