setbuf | mailer
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
需要注意的点,
- 为了溢出的方便, 我们把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了