1. 程式人生 > >2017CUIT校賽-線上賽

2017CUIT校賽-線上賽

pre 函數 fine 算法 int print fcntl images include

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校賽-線上賽