首页 > 代码库 > 2017CUIT校赛-线上赛

2017CUIT校赛-线上赛

2017Pwnhub杯-CUIT校赛

这是CUIT第十三届校赛啦,也是我参加的第一次校赛。

在被虐到崩溃的过程中也学到了一些东西。

这次比赛是从5.27早上十点打到5.28晚上十点,共36小时,中间睡了五六个小时吧。(我还算是我们队休息时间比较长的了)|(?_?) |?_?) |_?) |?) | )

这次我队总分1500,校内排名第六。

在下贡献了四道题目,总计450。

MISC: 1

RE: 2

PWN: 1

杂项就不多说了,说一下RE和PWN吧。

先放官方给出的wp,我对题目不一样的看法会放在后面作为参考。

 


 

RE100:

引用Nu1l的wp

 

1 t = [157,151,141,181,132,,187,251,186,145,140,144,189,253,145,128,254,188,145,141,254,170,171,179]
2 s=‘‘
3 for v int t:
4     for i in xrange(0x100):
5         if(~(~(i | 0xCE) | ~(~i | 0x31))&0xff == v:
6             s+=chr(i)
7 print s

 

RE150:

首先修复一下该程序:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <fcntl.h>
 4 #include <unistd.h>
 5 #include <assert.h>
 6 #include <elf.h>
 7 
 8 #define ENTRY 0x08048320
 9 #define FILE_OFF 0x320
10 #define COUNT 0x432
11 
12 int main(int argc,char *argv[]){
13     Elf32_Ehdr ehdr;
14     unsigned char buf[COUNT] = {0};
15     assert(argc == 2);
16 
17     int fd = open(argv[1],O_RDWR);//打开文件
18     assert(fd>0);
19 
20     assert(lseek(fd,0,SEEK_SET)!=-1);//读取elf头
21     assert(read(fd,&ehdr,sizeof(ehdr)) == sizeof(ehdr));
22     ehdr.e_entry = ENTRY;//修改入口地址
23     
24     assert(lseek(fd,0,SEEK_SET)!=-1);//回写elf头
25     assert(write(fd,&ehdr,sizeof(ehdr)) == sizeof(ehdr));
26 
27     //解密
28     assert(lseek(fd,FILE_OFF,SEEK_SET)!=-1);//读取被加密的代码
29     assert(read(fd,buf,COUNT) == COUNT);
30     int i = 0;
31     while(i<COUNT){
32         buf[i] = (buf[i]^66)<<5 | (buf[i]^66)>>3;
33         i++;
34     }
35     
36     assert(lseek(fd,FILE_OFF,SEEK_SET)!=-1);//写入
37     assert(write(fd,buf,COUNT) == COUNT);
38     
39     close(fd);
40 
41     return 0;
42 }

 

然后IDA中去花,分析得到算法。

 

 1 #include <stdio.h>
 2 
 3 unsigned char code[]={0x73,0x8D,0xF2,0x4C,0xC7,0xD4,0x7B,0xF7,0x18,0x32,0x71,0xD,0xCF,0xDC,0x67,0x4F,0x7F,0xB,0x6D,0};
 4 
 5 int main(void){
 6     int i = 0;
 7     
 8     while(code[i]){
 9         code[i] = code[i]^32;
10         i++;
11     }
12     
13     i = 0;
14     while(code[i]){
15         code[i] = ((code[i]^i)<<(i%8)) | ((code[i]^i)>>(8 - (i%8)));
16         i++;
17     }
18 
19     printf("%s\n",code);
20     return 0;
21 }

 

 

最后得到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

所以完全可以不用穷举,可以直接利用以下代码。

 1 #include <stdio.h>
 2 int main(void){
 3     
 4     int flag[]={
 5         0x9d,0x97,0x8d,0xb5,0x84,0xbb,0xfb,0xba,0x91,0x8c,0x90,0xbd,0xfd,0x91,0x80,0xfe,0xbc,0x91,0x8d,0xfe,0xaa,0xab,0xb3
 6     };
 7     int i=0;
 8     for ( i = 0; i < 23; ++i ){
 9     flag[i] = ~(~(flag[i] | 0xCE) | ~(~flag[i] | 0x31));
10     }
11     for(i=0;i<23;++i)
12         printf("%x ",flag[i]);
13     
14     
15     return 0;
16 }

RE150:

我在解题时并没有去试着完全修复ELF文件。

我利用gdb在解密代码后下断,然后dump出解密后的关键代码。

再将这段代码替换到原文件对应的部分,再到IDA中进行分析。

由于中间带花的部分我不会去......所以最后手动翻译了整段代码。(很傻,不建议像我这样做。)

后面的做法就一样啦。

PWN50:

前面差不多,我也用了getattr这个函数去调用system,

但是最后我并没有去拿shell,而是用"cat *"

列出了所有文件的内容。(因为这里还过滤掉了  .  所以不能"cat flag.txt")

 

 

 

 

2017CUIT校赛-线上赛