반응형

포너블 공부 2일차. 여전히 카나리 릭, 파이썬과 싸우고 있다.

파이썬 문법, pwntools 모듈 등이 나에겐 너무 생소한지라 아직까진 어려운데 어쩌겠습니까... 해야죠 네 ...

 

이번 문제도 역시 Canary Leak을 이용해 풀어야 하는 문제이다. 문제를 한번 자세히 보도록 하자.

(문제 출처 : https://dreamhack.io/wargame/challenges/33 )

 

ssp_001

Description 이 문제는 작동하고 있는 서비스(ssp_001)의 바이너리와 소스코드가 주어집니다. 프로그램의 취약점을 찾고 SSP 방어 기법을 우회하여 익스플로잇해 셸을 획득한 후, "flag" 파일을 읽으세

dreamhack.io

이 문제는 작동하고 있는 서비스(ssp_001)의 바이너리와 소스코드가 주어집니다.
프로그램의 취약점을 찾고 SSP 방어 기법을 우회하여 익스플로잇해 셸을 획득한 후, “flag” 파일을 읽으세요.
“flag” 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
플래그의 형식은 DH{…} 입니다.

라고 한다. 저기서 등장하는 SSP는 stack smashing protocol이다.

 

문제를 보면

get_shell()함수를 실행시키는 것을 목적으로 하면 될 것 같다.

main()함수를 보면, 

box[0x40], name[0x40], selset[2], idx, name_len이라는 변수를 선언해주고, 

while(1) 안에서 switch_case 문을 실행해준다.

switch안에 들어가는 인자는 read함수에서 받아오니 이건 p.send를 써야하겠다... 라는 생각을 하며 진행해보도록 하자. 

총 세 가지 기능이 구현되어있는데,

F : fill the box

P : print box value

E : fill name buffer and return.

이렇게 되어있다. 이제 checksec을 해보자.

#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);
}
// target
void get_shell()
{
    system("/bin/sh");
}

void print_box(unsigned char *box, int idx)
{
    printf("Element of index %d is : %02x\n", idx, box[idx]);
}
void menu()
{
    puts("[F]ill the box");
    puts("[P]rint the box");
    puts("[E]xit");
    printf("> ");
}
int main(int argc, char *argv[])
{
    unsigned char box[0x40] = {};
    char name[0x40] = {};
    char select[2] = {};
    int idx = 0, name_len = 0;
    initialize();
    while (1)
    {
        menu();
        read(0, select, 2);
        switch (select[0])
        {
        case 'F':
            printf("box input : ");
            read(0, box, sizeof(box));
            break;
        case 'P':
            printf("Element index : ");
            scanf("%d", &idx);
            print_box(box, idx);
            break;
        case 'E':
            printf("Name Size : ");
            scanf("%d", &name_len);
            printf("Name : ");
            read(0, name, name_len);
            return 0;
        default:
            break;
        }
    }
}

 

Canary가 적용되어있으니 어쨋든 Leak을 해주어야할 것 같다. Canary Leak을 하기 위해서는(다른 방법은 아직 모른다..) 스택의 데이터를 출력해주는 함수가 필요한데, 딱 적당하게 P 기능에서 이를 수행해준다.

P 기능 내의 print_box를 살펴보자.

void print_box(unsigned char *box, int idx)
{printf("Element of index %d is : %02x\n", idx, box[idx]);}

box[idx]는 사실 *(box + idx) 라고 볼 수 있는거니까, box 배열의 base address에서부터 idx만큼 떨어져있는 곳의 데이터를 말하는 것이다. 따라서 이를 이용하면 Canary 값을 읽을 수 있다.

그럼 한번 스택 상황을 보러 가볼까?

일단 처음에, 공간을 0x94만큼 잡아주는 것을 볼 수 있다.

pwndbg를 이용해 까보았더니  cmp eax, 0x50 즉, 'P'에 해당하면, <main + 192>로 jmp 해준다. <main+192>부터 보면, [ebp-0x88]의 주소를 PUSH해서 print_box로 넘겨주는 것을 볼수 있다. 그렇다면, box의 주소는 0x88일테니까,

그림을 그려봐야겠다.

이런 느낌일 것이다.

그렇다면, P기능에서 81개의 아무 데이터나 넣고, 그 다음 3바이트의 canary 값을 받아오면 canary leak을 할 수 있겠다.

exploit 코드

그리고, 일단 get_shell의 주소를 받아와야한다.

exploit 코드

이렇게 했으면, canary 값도 받아왔고, get_shell의 주소도 구했으니 RET 주소에 get_shell의 주소만 넣으면 되겠다.

exploit 코드

이렇게 구성하면 될 것 같다.

이제 실행을 해볼까?

히히 야호~ 성공했다. 끗.

반응형

+ Recent posts