Skip to content

Hint

Contents

bomb write-up

일단 r2 로 bomb 을 정적 분석해보자. main 함수를 분석해보면 단순히 입력 값이 1 또는 yellow 일 때 yellow 함수로 보내주고 2 또는 green 일 때 green 함수로 보내주고 3 또는 blue 일 때 blue 함수로 보내주며 4 또는 red 일 때 red 함수로 보내준다. 또 exit 또는 quit 을 입력하면 단순히 프로그램을 종료한다.

yellow 함수

  1. s sym.yellow 로 yello 함수를 찾고 pdf 명령으로 함수의 어셈블리어를 분석해보자. 분석해보면 입력받은 값을 아스키코드 0x38, 0x34, 0x33, 0x37, 0x31, 0x30, 0x36, 0x35 와 비교한다. 이것을 문장으로 나타내면 "84371065" 이다. 만약 이 값이 입력되면 0x804c124 주소를 0 으로 초기화 하는데 이곳은 <wire_yello> 섹션이다.

  2. objdump -D bomb | grep wire -A2 명령어로 나머지 wire 도 있는지 확인해보니 wire_yello, wire_red, wire_green, wire_blue 섹션이 각각 01 00 의 값으로 초기화되어 있었다. 그러므로 폭탄은 이 wire 섹션들이 모두 0 으로 바뀌었을 때 해체된다고 유추할 수 있다.

green 함수

BOF(Buffer Overflow) 할 줄 알아야 함. 패스.

red 함수

초기화

  • red_preflight 함수 호출

  • [var_4h] = str.ABCDEFGHJKLMNPQRSTUVWXYZ23456789

  • [var_8h] = 0

  • 0x80498ba 로 점프

red_preflight 함수
  • [obj.r] - (0x804c264) = 0x6b8b4567

  • [obj.r + 4] - (0x804c268) = 0x6b8b4567

  • [obj.r + 8] - (0x804c26c) = 0x6b8b4567

  • [obj.buffer] = (0x15 길이의 입력한 문자열)

dl, al 비교

0x0804984c 8b45f8 mov eax, dword [var_8h] 0x0804984f 0fb6904cc204. movzx edx, byte [eax + obj.buffer] ; [0x804c24c:1]=0 0x08049856 a16cc20408 mov eax, dword [0x804c26c] ; [0x804c26c:4]=0 0x0804985b 83e01f and eax, 0x1f 0x0804985e 0345fc add eax, dword [var_4h] 0x08049861 0fb600 movzx eax, byte [eax] 0x08049864 38c2 cmp dl, al 0x08049866 740f je 0x8049877

wire_red 를 0 으로 만드는 조건

먼저 red 함수에서 wire_red 를 0 로 만드는 코드는 다음과 같다. 만약 jle 가 실행된다면 0x804984c 로 점프하기 때문에 빨간선이 해제되지 않는다. 따라서 [var_8h] 는 0x12 보다 커야 한다. 0x12 는 상수이기 때문에 조사할 것이 없고 [var_8h] 를 결정하는 요소를 찾자.

```assembly
0x080498ba      837df812       cmp dword [var_8h], 0x12  
0x080498be      7e8c           jle 0x804984c             
0x080498c0      c70528c10408.  mov dword obj.wire_red, 0 
```

[var_8h] 를 결정하는 요소

[var_8h] 는 다음 두 코드가 결정한다.

  • 이 코드에서 [var_8h] 이 초기화되고 다시는 실행되지 않는다. [var_8h] 이 처음에는 0 이라는 정보 외에는 얻을 것이 없으니 더 이상 조사할 필요 없다.

    0x08049843      c745f8000000.  mov dword [var_8h], 0
    
  • 이 코드에서 [var_8h] 에 1 을 더한다. 그런데 이 코드는 어떤 분기에 의해 실행이 결정된다. 이제 그 분기 조건을 역추적해야 한다. 또한 그 분기가 0x12 번 이상 실행되면 빨간선이 해제된다는 것을 직관적으로 이해할 수 있다.

    0x080498b6      8345f801       add dword [var_8h], 1
    

[var_8h] 에 1 을 더하는 분기 조건

[var_8h] 에 1 을 더하는 분기 조건은 다음의 코드와 같다. 이 코드는 cmp 문으로 dl 과 al 을 비교하여 같으면 [var_8h] 에 1 을 더하는 분기로 점프한다. 따라서 dl 과 al 은 같아야 한다. 그럼 이제 dl 과 al 을 결정하는 요소를 조사하자.

0x0804984c      8b45f8         mov eax, dword [var_8h]
0x0804984f      0fb6904cc204.  movzx edx, byte [eax + obj.buffer] ; [0x804c24c:1]=0
0x08049856      a16cc20408     mov eax, dword [0x804c26c]  ; [0x804c26c:4]=0
0x0804985b      83e01f         and eax, 0x1f
0x0804985e      0345fc         add eax, dword [var_4h]
0x08049861      0fb600         movzx eax, byte [eax]
0x08049864      38c2           cmp dl, al
0x08049866      740f           je 0x8049877
al 을 결정하는 조건
0x08049856      a16cc20408     mov eax, dword [0x804c26c]  ; [0x804c26c:4]=0
0x0804985b      83e01f         and eax, 0x1f
0x0804985e      0345fc         add eax, dword [var_4h]
0x08049861      0fb600         movzx eax, byte [eax]

위의 코드에서 확인할 수 있듯이 al 을 결정하는 요소는 [0x804c26c] 과 [var_4h] 이다. [var_4h] 는 "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" 이라는 문자열의 주소로 초기화되고 바뀌지 않는다. 이제 [0x804c26c] 를 결정하는 조건을 조사해야 한다.

[0x804c26c] 를 결정하는 조건

[0x804c26c] 는 다음 두 코드에서 결정된다.

이 코드는 red_preflight 함수의 코드이다. rand 함수를 통해 랜덤값을 받다. 그런데 srand 함수로 시드값을 지정해주지 않아서 값은 항상 0x643c9869 로 초기화된다.

0x080497c3      e8fcefffff     call sym.imp.rand           ; int rand(void)
0x080497c8      a36cc20408     mov dword [0x804c26c], eax  ; [0x804c26c:4]=0

이 코드는 red 함수의 코드이다. 결론적으로 eax 와 edx 의 OR 연산 결과값을 [0x804c26c] 에 저장하고 있기 때문에 eax 와 edx 를 결정하는 요소를 역추적해보자.

0x08049889      09d0           or eax, edx
0x0804988b      a36cc20408     mov dword [0x804c26c], eax  ; [0x804c26c:4]=0
eax 와 edx 를 결정하는 코드

eax 를 결정하는 코드 : red_preflight 함수에서 rand 함수의 결과값인 0x327b23c6 이 저장된다. 이것은 상수이므로 더 이상 조사할 필요 없다.

0x08049881      a168c20408     mov eax, dword [0x804c268]  ; [0x804c268:4]=0
0x08049886      c1e01b         shl eax, 0x1b

edx 를 결정하는 코드 : edx 를 [0x804c26c] 가 결정하고 있는데 이 값은 위에서 조사했듯이 0x643c9869 이다. 이것도 상수이므로 더 이상 조사할 필요 없다.

0x08049877      a16cc20408     mov eax, dword [0x804c26c]  ; [0x804c26c:4]=0
0x0804987c      89c2           mov edx, eax
0x0804987e      c1ea05         shr edx, 5
dl 을 결정하는 조건
0x0804984c      8b45f8         mov eax, dword [var_8h]
0x0804984f      0fb6904cc204.  movzx edx, byte [eax + obj.buffer] ; [0x804c24c:1]=0

위의 코드에서 확인할 수 있듯이 dl 을 결정하는 요소는 [var_8h] 과 [obj.buffer] 이다. [var_8h] 는 0 으로 초기값이 정해진다는 것을 이미 알고 있으니 [obj.buffer] 만 조사하면 된다. 그런데 [obj.buffer] 는 입력값이다.


중간정리

지금까지 조사한 결과를 복기해보면 wire_red 를 0 으로 만들기 위해 [var_8h] 를 0x12 보다 크게 만들어야 한다. 그런데 [var_8h] 의 초기값은 0 이고 1 을 더하는 조건이 dl 과 al 이 같게 되는 것이다. 그러므로 이 조건이 0x12 번 이상 만족되어야 빨간선이 해제된다는 것을 이해할 수 있다.

al 을 결정하는 조건은 [0x804c26c] (실제값 0x643c9869) 와 [var_4h] (실제값 ABCD... 문자열의 주소)였고 이 둘은 상수였다. dl 은 [var_8h] (실제값 0 부터 1씩커짐) 와 [obj.buffer] 가 결정하는데 [var_8h] 은 상수고 [obj.buffer] 가 변수로써 입력한 값이다.


blue 함수

  • wire_blue 를 0 으로 만드는 코드는 다음과 같다. 이 코드는 어떤 분기에 의해 실행되기 때문에 그 분기의 조건을 역추적하자.

    0x08049add      a140c10408     mov eax, dword obj.wire_blue ; [0x804c140:4]=1
    0x08049ae2      83e801         sub eax, 1
    0x08049ae5      a340c10408     mov dword obj.wire_blue, eax ; [0x804c140:4]=1
    
  • 다음 코드의 jne 가 실행되지 않아야 1 번의 코드가 실행되서 파란선이 해제된다. 즉 cmp 명령어로 obj.solution 과 [var_8h] 를 비교하고 있는데 이 둘이 같아야만 파란선이 해제되는 루틴으로 넘어간다는 것이다. 그런데 obj.solution 은 blue 함수에서 0x40475194 의 값을 갖는 상수이다. 상수는 입력한 값과 관계없이 불변하기 때문에 더 이상 조사할 것이 없다. 그러니 이제 [var_8h] 를 결정하는 요소를 역추적해보자.

    0x08049ac7      a184a30408     mov eax, dword obj.solution ; [0x804a384:4]=0x40475194
    0x08049acc      3945f8         cmp dword [var_8h], eax
    0x08049acf      751b           jne 0x8049aec
    
  • [var_8h] 을 결정하는 코드 조사해보면 다음의 두 코드에서 [var_8h] 를 수정하고 있다는 것을 알 수 있다.

    • 0x08049a77      8b45fc         mov eax, dword [var_4h]
      0x08049a7a      8b4004         mov eax, dword [eax + 4]    ; [0x4:4]=-1 ; 4
      0x08049a7d      3145f8         xor dword [var_8h], eax
      
    • 0x080499fc      c745fc60c104.  mov dword [var_4h], obj.graph ; 0x804c160
      0x08049a03      8b45fc         mov eax, dword [var_4h]
      0x08049a06      8b4004         mov eax, dword [eax + 4]    ; [0x4:4]=-1 ; 4
      0x08049a09      8945f8         mov dword [var_8h], eax