상세 컨텐츠

본문 제목

[DefCamp CTF 2015 Quals] Entry Language (Reverse 100)

SYSTEM HACKING/CTF, etc

by koharin 2022. 5. 11. 12:07

본문

728x90
반응형

64bit 바이너리이다.


Code Analysis

signed __int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  signed __int64 result; // rax
  char s; // [rsp+0h] [rbp-110h]
  unsigned __int64 v5; // [rsp+108h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  printf("Enter the password: ", a2, a3);
  if ( !fgets(&s, 255, stdin) )
    return 0LL;
  if ( (unsigned int)sub_4006FD(&s, 255LL) )
  {
    puts("Incorrect password!");
    result = 1LL;
  }
  else
  {
    puts("Nice!");
    result = 0LL;
  }
  return result;
}
  • sub_4006FD 함수로 입력값 s 전달 후, 함수 return 값이 참이면 “Incorrect password” 출력 후 result 값을 리턴한다. 거짓이면 “Nice” 출력 후 result 값을 0으로 리턴한다.

 

signed __int64 __fastcall sub_4006FD(__int64 a1)
{
  signed int i; // [rsp+14h] [rbp-24h]
  const char *v3; // [rsp+18h] [rbp-20h]
  const char *v4; // [rsp+20h] [rbp-18h]
  const char *v5; // [rsp+28h] [rbp-10h]

  v3 = "Dufhbmf";
  v4 = "pG`imos";
  v5 = "ewUglpt";
  for ( i = 0; i <= 11; ++i )
  {
    if ( (&v3)[i % 3][2 * (i / 3)] - *(char *)(i + a1) != 1 )
      return 1LL;
  }
  return 0LL;
}
  • sub_4006FD 함수에서는 입력값과 지역변수 문자열로 연산 후 1이 아니면 1을 리턴해서 main에서는 0이 아닌 값이므로 “Incorrect password”가 출력될 것이고, 모든 반복문에서 연산 결과가 1이면 0을 리턴해서 main에서는 조건이 거짓일 때로 분기하여 “Nice”를 출력한다.

 

Exploit using angr

함수 주소 구하기

.text:00000000004007E8 main            proc near               ; DATA XREF: start+1D↑o
.text:00000000004007E8
.text:00000000004007E8 s               = byte ptr -110h
.text:00000000004007E8 var_8           = qword ptr -8
.text:00000000004007E8
.text:00000000004007E8 ; __unwind {
.text:00000000004007E8                 push    rbp
.text:00000000004007E9                 mov     rbp, rsp
.text:00000000004007EC                 sub     rsp, 110h
.text:00000000004007F3                 mov     rax, fs:28h
.text:00000000004007FC                 mov     [rbp+var_8], rax
.text:0000000000400800                 xor     eax, eax
.text:0000000000400802                 mov     edi, offset format ; "Enter the password: "
.text:0000000000400807                 mov     eax, 0
.text:000000000040080C                 call    _printf
.text:0000000000400811                 mov     rdx, cs:stdin   ; stream
.text:0000000000400818                 lea     rax, [rbp+s]
.text:000000000040081F                 mov     esi, 0FFh       ; n
.text:0000000000400824                 mov     rdi, rax        ; s
.text:0000000000400827                 call    _fgets
.text:000000000040082C                 test    rax, rax
.text:000000000040082F                 jz      short loc_400866
.text:0000000000400831                 lea     rax, [rbp+s]
.text:0000000000400838                 mov     rdi, rax
.text:000000000040083B                 call    sub_4006FD
.text:0000000000400840                 test    eax, eax
.text:0000000000400842                 jnz     short loc_400855
.text:0000000000400844                 mov     edi, offset s   ; "Nice!"
.text:0000000000400849                 call    _puts
.text:000000000040084E                 mov     eax, 0
.text:0000000000400853                 jmp     short loc_40086B
.text:0000000000400855 ; ---------------------------------------------------------------------------
.text:0000000000400855
.text:0000000000400855 loc_400855:                             ; CODE XREF: main+5A↑j
.text:0000000000400855                 mov     edi, offset aIncorrectPassw ; "Incorrect password!"
.text:000000000040085A                 call    _puts
.text:000000000040085F                 mov     eax, 1
.text:0000000000400864                 jmp     short loc_40086B

IDA로 확인한 어셈블리 코드다.
main() 함수 if문에서 조건에 따라 분기하여 가는 두 주소를 찾는다.

sub_4006FD 함수 리턴값이 eax 레지스터에 저장되는데,  `test eax, eax` 로 비교 후 `jnz short loc_400855`에 따라 결과가 0이 아닐 경우, 즉 참일 경우 0x400855 주소로 이동한다. 0이면 jnz 코드 다음 주소인 0x400844로 이동한다.

따라서 “Nice”가 출력되는 0x400844 주소로 이동하는 경로를 찾아야 하고, “Incorrect password!”를 출력하는 0x400855 주소로 이동하는 경로를 피해야 한다.


Simulation Managers

Simulation Managers에서는 explore() API를 통해 find, avoid에 주소를 지정하여 실행 시 찾는 주소에서 실행을 멈출 수 있다. 실행을 진행하면서 active stash에서의 상태가 find 조건과 일치하면, found stash로 상태를 옮기고 실행을 종료한다.


Simulation managers explore() 사용1 - 주소로 찾기

#!/usr/bin/python 
import angr

# load binary
p = angr.Project('r100', auto_load_libs=False)

# get state from entrypoint
state = p.factory.entry_state()

# use simulation manager
simgr = p.factory.simgr(state)

# search path
simgr.explore(find=0x400844, avoid=0x400855)

print(simgr.found)
print(simgr.found[0].posix.dumps(0))

코드를 실행하면, found stash에 0x400844 주소에서의 상태가 저장된 것을 확인할 수 있다. found stash에 저장된 상태에서 Code_Talkers 문자열을 확인할 수 있다.



Code_Talkers가 비밀번호인 것 같아서 입력값으로 줬더니 “Nice!”가 출력된걸 확인할 수 있다.

 

Simulation managers explore() 사용2 - 문자열로 찾기

#!/usr/bin/python 
import angr

# load binary
p = angr.Project('r100', auto_load_libs=False)

# get state from entrypoint
state = p.factory.entry_state()

# use simulation manager
simgr = p.factory.simgr(state)

# search path
simgr.explore(find=lambda s:b'Nice' in s.posix.dumps(1))
print(simgr.found)
print(simgr.found[0].posix.dumps(0))
print(simgr.found[0].posix.dumps(1))

728x90
반응형

관련글 더보기