setbuf | mailer

Author Avatar
Aryb1n 7月 03, 2018

code_blue CTF 2017 的一道题目, 名字叫mailer, 和setbuf有关的
本来想复现一道堆的, 算了, 先把这个复现一下
结构体大概是

struct mailer{
    int flag1;
    int flag2;
    char content[0x100];    // 0x100 == 256
};

大致功能如下


*** Secret Mailer Service ***
Welcome to Secret Mailer Service!
Post your secret letters here ;)

1. Add a letter
2. Delete a letter
3. Post a letter
4. Quit
> 1

Input your contents: 222

Done!

1. Add a letter
2. Delete a letter
3. Post a letter
4. Quit
> 3

Which letter do you want to post?
ID (0-4): 0

Which filter do you want to apply?
0. No filter
1. XOR filter
2. Reverse filter
> 0

Done!

仔细看过么有发现什么明显的洞…

又读了一遍, 发现在 post letter这个略显多余的功能里可以选择调用的函数…

int __cdecl post_m(mailer *a1, FILE *s)
{
  int result; // eax@4
  int v3; // [sp+8h] [bp-10h]@5
  int v4; // [sp+Ch] [bp-Ch]@1

  puts("\nWhich letter do you want to post?");
  printf("ID (0-%d): ", 4);
  v4 = getn();
  if ( v4 >= 0 && v4 <= 4 && a1[v4].flag1 )
  {
    puts("\nWhich filter do you want to apply?");
    sub_80488F8();
    v3 = getn();
    if ( v3 <= 2 )
    {
=>      off_804B048[v3](s, a1[v4].content, a1[v4].flag2);
      result = puts("\nDone!");
    }
    else
    {
      result = puts("Invalid filter.");
    }
  }
  else
  {
    result = puts("Invalid ID.");
  }
  return result;
}

洞在我指向的这个地方, 这里只判断getn() <=2, 如果输入一个负数, 那么就能调用到0x804b048之前的函数了, 但…我们不能控制参数

因为参考了大佬的做法…所以这里就是问题的关键, 这个如果调用一个setbuf函数
就是…把某个mailers的content设为stream的缓冲区

stream = fopen("/dev/null", "a");
setbuf(stream, mailers[i].content)

只要使用库函数往流stream写入数据, 就会写入stream的缓冲区mailers[i].content

而我们在sub_8048742

fwrite(buf, 1, n, stream)

可以将buf中的内容写到stream

所以只要两个mailer配合
先在mailers[1]里写入适当内容
然后post一次mailers[0], 输入一个负值, 调用setbuf (setbuf的offset是-15)
然后再post一次mailers[1], 选择no_filter, 调用fwrite
就可以把mailers[1].content的内容写到mailers[0].content, 然后溢出就可以, 写ROP了

buf1 -> stream -> buf0

mdzz…昨晚的idb没存….气的吐血

那就不写poc了, 2233333

需要注意的点,

  1. 为了溢出的方便, 我们把stream和最后一个mailers绑定起来, 这样子, 只要往stream写两次就能够溢出了, 第一次填充, 第二次写payload…因为每个mailer的content大小是相等的,所以至少要两次才OK

所以我们要add 5个mailer, 在mailers[0..3]的某一个中写入ROP链, 为了叙述方便, 我们不妨假设写到了mailers[0], 然后post(mailers[4], -15), 就用setbuf把最后一个mailer和stream绑定起来了, 之后, post(mailers[1], 0), 写入一次padding, 再post(mailers[0], 0), 写入ROP链, 就OK了