2017Pwnhub杯-CUIT校赛
这是CUIT第十三届校赛啦,也是我参加的第一次校赛。
在被虐到崩溃的过程中也学到了一些东西。
这次比赛是从5.27早上十点打到5.28晚上十点,共36小时,中间睡了五六个小时吧。(我还算是我们队休息时间比较长的了)|(•_•) |•_•) |_•) |•) | )
这次我队总分1500,校内排名第六。
在下贡献了四道题目,总计450。
MISC: 1
RE: 2
PWN: 1
杂项就不多说了,说一下RE和PWN吧。
先放官方给出的wp,我对题目不一样的看法会放在后面作为参考。
RE100:
引用Nu1l的wp
t = [157,151,141,181,132,,187,251,186,145,140,144,189,253,145,128,254,188,145,141,254,170,171,179]
s=''
for v int t:
for i in xrange(0x100):
if(~(~(i | 0xCE) | ~(~i | 0x31))&0xff == v:
s+=chr(i)
print sRE150:
首先修复一下该程序:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <elf.h> #define ENTRY 0x08048320
#define FILE_OFF 0x320
#define COUNT 0x432 int main(int argc,char *argv[]){
Elf32_Ehdr ehdr;
unsigned char buf[COUNT] = {};
assert(argc == ); int fd = open(argv[],O_RDWR);//打开文件
assert(fd>); assert(lseek(fd,,SEEK_SET)!=-);//读取elf头
assert(read(fd,&ehdr,sizeof(ehdr)) == sizeof(ehdr));
ehdr.e_entry = ENTRY;//修改入口地址 assert(lseek(fd,,SEEK_SET)!=-);//回写elf头
assert(write(fd,&ehdr,sizeof(ehdr)) == sizeof(ehdr)); //解密
assert(lseek(fd,FILE_OFF,SEEK_SET)!=-);//读取被加密的代码
assert(read(fd,buf,COUNT) == COUNT);
int i = ;
while(i<COUNT){
buf[i] = (buf[i]^)<< | (buf[i]^)>>;
i++;
} assert(lseek(fd,FILE_OFF,SEEK_SET)!=-);//写入
assert(write(fd,buf,COUNT) == COUNT); close(fd); return ;
}然后IDA中去花,分析得到算法。
#include <stdio.h> unsigned char code[]={0x73,0x8D,0xF2,0x4C,0xC7,0xD4,0x7B,0xF7,0x18,0x32,0x71,0xD,0xCF,0xDC,0x67,0x4F,0x7F,0xB,0x6D,}; int main(void){
int i = ; while(code[i]){
code[i] = code[i]^;
i++;
} i = ;
while(code[i]){
code[i] = ((code[i]^i)<<(i%)) | ((code[i]^i)>>( - (i%)));
i++;
} printf("%s\n",code);
return ;
}最后得到flag:
SYC{>>Wh06m1>>R0Ot}
pwn50:
Escape from Jail
python的Jail(python沙箱逃逸),过滤是这样的。
通过查看python的builtins,得知可以使用getattr去调用函数。
getattr(os,"system")("/bin/sh")起shell之后直接读flag就行了。
接下来说一下我在解题过程中的一些不一样的东西:
RE100:
上面最后出flag的时候用的是穷举,但是我发现程序中关键算法的部分本身就是可逆的。
flag[i] = ~(~(flag[i] | 0xCE) | ~(~flag[i] | 0x31));这是他原来的算法。
在我测试过程中,发现它等同于另一条语句。
flag[i] ^= 0xCE所以完全可以不用穷举,可以直接利用以下代码。
#include <stdio.h>
int main(void){ int flag[]={
0x9d,0x97,0x8d,0xb5,0x84,0xbb,0xfb,0xba,0x91,0x8c,0x90,0xbd,0xfd,0x91,0x80,0xfe,0xbc,0x91,0x8d,0xfe,0xaa,0xab,0xb3
};
int i=;
for ( i = ; i < ; ++i ){
flag[i] = ~(~(flag[i] | 0xCE) | ~(~flag[i] | 0x31));
}
for(i=;i<;++i)
printf("%x ",flag[i]); return ;
}RE150:
我在解题时并没有去试着完全修复ELF文件。
我利用gdb在解密代码后下断,然后dump出解密后的关键代码。
再将这段代码替换到原文件对应的部分,再到IDA中进行分析。
由于中间带花的部分我不会去......所以最后手动翻译了整段代码。(很傻,不建议像我这样做。)
后面的做法就一样啦。
PWN50:
前面差不多,我也用了getattr这个函数去调用system,
但是最后我并没有去拿shell,而是用"cat *"
列出了所有文件的内容。(因为这里还过滤掉了 . 所以不能"cat flag.txt")