64位利用格式化字符串修改got表
例题:newstartweek3 put or system
老规矩 先checksec和代码审计:
看到开了canary 和NX(但是对于这道题的话 canary是没有用的) ,然后源码这边也没有发现有system函数,也没有后门函数,所以我们需要自己在libc里面找,然后就有bin/sh 那么我们就只用把got表里的puts改为system 那么在最后就会执行system(bin/sh)而不是puts(‘bin/sh’)因为got表里的内容是我们的真实函数的内容,动态链接引用一个函数也需要使用got表,所以这道题就可以用修改got表来攻击了!
先是我们输入一个1,让v4等于1,进入循环,然后在第一个buf这里输入格式化字符泄露出puts的真实地址然后找出libc的基地址,这里对于我们修改got的内容还需要一个工具就是fmtstr_payload,如果现在还不知道原理的话,也没关系,因为现在我也不知道,但是我们需要他是怎么使用的。一般来说的话我们的常规用法是这样的fmtstr_payload(offset, {puts_got: system_addr})其中offset就是我们可控制的偏移量,在这里就相当于是我们泄露出puts函数的时候使用的多少$s,而puts——got顾名思义就是其在got表的地址,system——addr就是system函数的真实地址!
那就开始找到这个n吧
发现是在第八位,然后我们一般构造的格式化字符串泄露是不是 p32(要泄露的函数)+%n$s,但是在64位这里也这样构造的话就不行,因为64位有效字节6字节,而高位的两字节全为0,printf在遇到\x00会截断,导致地址无法泄露,所以地址要放在后边,格式化字符串要放在前边,但是这样的话我们的格式化字符就需要进行改变了,我们的就这样构造payload=b'%9$sAAAA'+p64(elf.got['puts']) 在这里解释一下,因为64位的都是8位,所以这里的AAAA就是为了补齐栈区,当泄露出来之后就可以进行我们的攻击了。
exp如上,这里又学到了新的攻击方式修改got表和新的工具fmtstr_payload但是保护开启了Full RELRO这样的话got表就不能进行修改
orw
例题:newstartweek3 orw&rop
这里有个新的知识沙盒,沙盒是什么?就介绍一下沙盒的机制,也就是我们常说的沙箱,英文名sandbox,是计算机领域的虚拟技术,常见于安全方向。一般说来,我们会将不受信任的软件放在沙箱中运行,一旦该软件有恶意行为,则禁止该程序的进一步运行,不会对真实系统造成任何危害。而在ctf中 沙盒会禁用一些函数,这样我们平时一般执行的execve或者open等等的函数就不能够进行使用!!
看到源码中出现了sanbox就是沙盒机制,遇到沙盒那么我们需要一个工具去看看他到底啊禁用了哪些函数,这个工具就是seccomp-tools
当然这需要我们在虚拟机安装seccoomp-tools,然后输入seccomp-tools dump ./我们需要看的elf文件,这样就可以看到系统禁用了哪些函数
这道题你会发现goto 0006是return allow就是允许执行,但是goto 0007就是return kill 就是被禁止的函数,这道题发现禁用了系统调用,但是read open write函数没有被禁用,一般做法就是使用这三个函数就是open打开文件,read去读取文件,write去输出文件直接打印出我们想要的flag。
那么这道题该怎么做?首先就是看见他开启的canary和nx,发现第一个read和printf可以使用格式化字符串泄露出canary和puts的真实地址。那就先去调试一下找出我们可以控制的字符位置。
发现我们控制能够控制的字符在第6个位置,然后canary在第11个位置,那么就构造我们的payload来泄露出我们的canary和 puts的真实地址,这是64位的,那么我们泄露的函数地址应该在格式化字符的后面,payload =b'%11$p%8$saaaaaaa' +p64(got_addr)就是这样就可以泄露出我们想要的东西。
解释一下这样写的payload,就是在第二个read的时候栈溢出并且绕过canary,然后构造一个read函数,然后在系统给我们开辟的可读可写的地方写0x100的东西,在返回那个地址执行我们写入的shellcode,就可以打印出我们的flag了,但是记住这只是打印出flag,而不能获取电脑的权限,所以是会出现eof的,然后在解释一下open read 和write函数的参数吧,shellcraft.open("filename")
shellcraft.read(mod,addr,nbytes)
shellcraft.write(mod,addr,nbytes)
这里的read的mod我们选择的模式是3从文件中读取,write的mod选择1就是标准输出,read的第二个参数就是从哪个地址进行读取,write同理,nbytes就是读取多少的字节。而orw有三种方法,第一种就是使用系统的shellcraft给我们现成的orw函数,第二就是通过寄存器调用,第三就是手写汇编。
new startweek3 stack migration revenge
很明显看题目就是栈迁移,源码审计和checksec
发现没有开启pie和canary,不能进行got表修改,也是很简单的漏洞逻辑,
这里我们发现给我们的溢出之后的大小远远不能够写下我们的payload,所以需要栈迁移的,那么肯定需要这里的read函数,那么我们去看看汇编指令(如果不看别人的exp的话我还想不到这一步),因为我们需要的read写的地址由rax传入rsi所以我们需要控制rax,而rax是由rbp+buf控制的,所以我么只需要控制这里就可再次执行read函数,那么我们第一次的payload应该写成payload = b'a'*0x50 +p64(bss +0x50) +p64(read)为啥这样就把程序转到我们要写的bss段去执行read了 为啥这里是bss+0x50呢。因为rbp+buf,而buf相对于rbp的偏移是0x50,所以就需要这样,当我们发送过去之后在次执行read函数,第二次的payload就这样payload=p64(rdi_addr)+p64(got_addr)+p64(plt_addr)+p64(rbp_addr) +p64(bss +0x800)+p64(read)+payload.ljust(0x50, b'\x00')+p64(bss -0x8) +p64(leave_ret)泄露出我们的puts函数的真实地址,在迁移到bss段再次执行read,而这里为什么要+0x800呢 就是为了开大一点,为了防止覆盖got表或其它重要数据导致报错。最后我们的payload =p64(rdi_addr) +p64(bin_sh) +p64(sys_addr)
payload =payload.ljust(0x50, b'\x00') +p64(bss +0x800 -0x58) +p64(leave_ret)就构造这样就可以成功获取到它的权限了,完整exp如下
看来栈迁移这点知识还需要再次精进一下,还有对于汇编指令的学习,还得加快学习进度了!