一、代碼審查方法
(1)從進(jìn)入點(diǎn)開(kāi)始追蹤用戶向應(yīng)用程序提交的數(shù)據(jù),審查負(fù)責(zé)處理這些數(shù)據(jù)的代碼;
(2)在代碼中搜索表示存在常見(jiàn)漏洞的簽名,并審查這些簽名,確定某個(gè)漏洞是否確實(shí)存在;
(3)對(duì)內(nèi)在危險(xiǎn)的代碼進(jìn)行逐行審查,理解應(yīng)用程序的邏輯,并確定其中存在的所有問(wèn)題
(4)應(yīng)用程序可能擴(kuò)展了類庫(kù)與接口,在進(jìn)行審查之前應(yīng)了解這些定制的范圍 并相應(yīng)調(diào)整審查方法
需要進(jìn)行仔細(xì)審查的組件包括:關(guān)鍵安全機(jī)制(驗(yàn)證、會(huì)話管理、訪問(wèn)控制、輸入確認(rèn))、外部組件接口以及任何使用本地代碼的情況 。
二、常見(jiàn)漏洞簽名
(1)XSS
String link = “<a href=” + HttpUtility.UrlDecode(Request.QueryString
[“refURL”]) + “&SiteID=” + SiteId + “&Path=” + HttpUtility.UrlEncode
(Request.QueryString[“Path”]) + “</a>”;
objCell.InnerHtml = link;
(2)SQL注入
直接使用用戶輸入?
StringBuilder SqlQuery = newStringBuilder(“SELECT name, accno FROM
TblCustomers WHERE “ + SqlWhere);
if(Request.QueryString[“CID”] != null &&
Request.QueryString[“PageId”] == “2”)
{
SqlQuery.Append(“ AND CustomerID = “);
}
...
在代碼中搜索關(guān)鍵字:
“SELECT
“INSERT
“DELETE
“ AND
“ OR
“ WHERE
“ ORDER BY
(3)路徑遍歷
通過(guò)在代碼中搜索任何與文件名有關(guān)的查詢字符串參數(shù)(如AttachName等)以及在相關(guān)語(yǔ)言中搜尋所有文件API并檢查提交它們的參數(shù),就可以迅速確定相關(guān)的功能。
public byte[] GetAttachment(HttpRequest Request)
{
FileStream fsAttachment = new FileStream(SpreadsheetPath +
HttpUtility.UrlDecode(Request.QueryString[“AttachName”]),
FileMode.Open, FileAccess.Read, FileShare.Read);
byte[] bAttachment = new byte[fsAttachment.Length];
fsAttachment.Read(FileContent, 0,
Convert.ToInt32(fsAttachment.Length,
CultureInfo.CurrentCulture));
fsAttachment.Close();
(4)任意重定向?
private void handleCancel()
{
httpResponse.Redirect(HttpUtility.UrlDecode(Request.QueryString[
“refURL”]) + “&SiteCode=” +
Request.QueryString[“SiteCode”].ToString() +
“&UserId=” + Request.QueryString[“UserId”].ToString());
}
JS:
url = document.URL;
index = url.indexOf(‘?redir=’);
target = unescape(url.substring(index + 7, url.length));
target = unescape(target);
if ((index = target.indexOf(‘//’)) > 0) {
target = target.substring (index + 2, target.length);
index = target.indexOf(‘/’);
target = target.substring(index, target.length);
}
target = unescape(target);
document.location = target;
(5)OS命令注入
void send_mail(const char *message, const char *addr)
{
char sendMailCmd[4096];
snprintf(sendMailCmd, 4096, “echo ‘%s’ | sendmail %s”, message, addr);
system(sendMailCmd);
return;
}
(6)后門密碼
private UserProfile validateUser(String username, String password)
{
UserProfile up = getUserProfile(username);
if (checkCredentials(up, password) ||
“oculiomnium”.equals(password))
return up;
return null;
}
(7)本地代碼漏洞
a. 緩沖區(qū)溢出?
BOOL CALLBACK CFiles::EnumNameProc(LPTSTR pszName)
{
char strFileName[MAX_PATH];
strcpy(strFileName, pszName);
...
}
b. 整數(shù)漏洞
有符號(hào)的整數(shù)與無(wú)符號(hào)的整數(shù)進(jìn)行比較,就會(huì)有問(wèn)題
BOOL CALLBACK CFiles::EnumNameProc(LPTSTR pszName, int len)
{
char strFileName[MAX_PATH];
if (len < sizeof(strFileName))
strcpy(strFileName, pszName);
...
}
c. 格式化字符串漏洞
通過(guò)檢查printf與FormatMessage系列函數(shù)的用法,如果發(fā)現(xiàn)格式化字符串參數(shù)并未硬編碼,而是由用戶控制,就可以確定這類漏洞。
(8)源代碼注釋
關(guān)鍵詞:bug、 problem、 bad、 hope、 todo、 fix、 overflow、 crash、 inject、 xss、 trust
三、JAVA平臺(tái)?
(1)確定用戶提交的數(shù)據(jù)
JAVA應(yīng)用程序通過(guò)javax.servlet.http.HttpServletRequest接口獲取用戶提交的輸入,該接口對(duì)javax.servlet.servletRequest接口進(jìn)行了擴(kuò)展。API如下:

(2)會(huì)話交互
javax.servlet.http.HttpSession接口保存和檢索當(dāng)前會(huì)話中的信息,每會(huì)話存儲(chǔ)是字符串名稱與對(duì)象值之間的一個(gè)映射。

(3)潛在危險(xiǎn)的API
1、文件訪問(wèn)
? ? 主要的類為有:
????java.io.File
? ??java.io.FileInputStream
? ? java.io.FileOutputStream
????java.io.FileReader
????java.io.FileWriter
2、數(shù)據(jù)庫(kù)訪問(wèn)
? ??java.sql.Connection.createStatement
????java.sql.Statement.execute
????java.sql.Statement.executeQuery
以下API更可靠,允許應(yīng)用程序創(chuàng)建一個(gè)預(yù)先編譯的SQL語(yǔ)句,并以可靠且類型安全的方式指定它的參數(shù)占位符的值:
java.sql.Connection.prepareStatement
java.sql.PreparedStatement.setString
java.sql.PreparedStatement.setInt
java.sql.PreparedStatement.setBoolean
java.sql.PreparedStatement.setObject
java.sql.PreparedStatement.execute
java.sql.PreparedStatement.executeQuery
3、動(dòng)態(tài)代碼執(zhí)行
4、OS命令執(zhí)行
? ??java.lang.runtime.Runtime.getRuntime
????java.lang.runtime.Runtime.exec
? ? 攻擊成功:
? ??String userinput = “calc”;
????Runtime.getRuntime.exec(userinput);
? ? 攻擊失?。?br>? ??String userinput = “| calc”;
????Runtime.getRuntime.exec(“notepad “ + userinput);? ??【notepad后有空格】
? ? 攻擊成功 :
? ??String userinput = “\\..\\system32\\calc”;
????Runtime.getRuntime().exec(“notepad” + userinput);? 【notepad后無(wú)空格】
5、URL重定向
? ??javax.servlet.http.HttpServletResponse.sendRedirect
????javax.servlet.http.HttpServletResponse.setStatus
????javax.servlet.http.HttpServletResponse.addHeader
6、套接字
? ? java.net.Socket
(4)配置Java環(huán)境
web.xml是配置文件。主要配置項(xiàng)有:
login-config:配置認(rèn)證細(xì)節(jié),兩類驗(yàn)證分別是基于表單的(頁(yè)面由form-login-page元素指定)與在auth-method元素中指定的Basic-Auth或Client-Cert,如果使用基于表單的認(rèn)證,指定的表單必須有j_security_check動(dòng)作,須提交j_username與j_password參數(shù)。
security-constraint:如果定義了login-config,就可以使用security-constraint元素限定資源。這個(gè)元素可用于定義受保護(hù)的資源,可以使用url-pattern元素定義資源集。如:<url-pattern>/admin/*</url-pattern>,分別在role-name與principal-name元素中定義的角色與主要用戶可以訪問(wèn)的資源
session-config:會(huì)話超時(shí)時(shí)間 (分鐘)
error-page:error-code與exception-type分別處理HTTP錯(cuò)誤代碼與Java異常
init-param:配置初始化參數(shù),listings應(yīng)設(shè)置為false; debug應(yīng)設(shè)置為0
除web.xml文件外,可能還包含次要配置文件weblogic.xml文件等,都應(yīng)檢查
四、ASP.NET
(1)確定用戶提交的數(shù)據(jù)
ASP.NET通過(guò)System.Web.HttpRequest類獲取用戶提交的輸入。

(2)會(huì)話交互
使用session屬性 保存和檢索當(dāng)前會(huì)話中的信息。
Session["MyName"] = txtMyName.Text;
lblWelcome.Text = "Welcome "+Session["MyName"];
用戶個(gè)性化配置中,數(shù)據(jù)以下列方式保存和檢索:
Profile.MyName =? txtMyName.Text;?
lblWelcome.Text = "Welcome "+Profile.MyName;
System.Web.SessionStage.HttpSessionState 類也用于保存和檢索會(huì)話中的信息。

(3)潛在危險(xiǎn)的API
1、 文件訪問(wèn)
System.IO.File類
下面的類常用于讀取與寫入文件內(nèi)容:
System.IO.FileStream
System.IO.StreamReader
System.IO.StreamWriter
以下兩個(gè)直接拼接用戶輸入 的操作都會(huì)造成路徑遍歷漏洞。
string userinput = "..\\boot.ini";
FileStream fs = File.Open("C:\\temp\\" + userinput,FileMode.OpenOrCreate);
string userinput = “..\\foo.txt”;
FileStream fs = new FileStream(“F:\\tmp\\” + userinput,FileMode.OpenOrCreate);
2、數(shù)據(jù)庫(kù)訪問(wèn)
System.Data.SqlClient.SqlCommand
System.Data.SqlClient.SqlDataAdapter
System.Data.Oledb.OleDbCommand
System.Data.Odbc.OdbcCommand
System.Data.SqlServerCe.SqlCeCommand
通過(guò)它們的Parameters屬性支持預(yù)處理語(yǔ)句,允許應(yīng)用程序創(chuàng)建一個(gè)包含參數(shù)占位符的SQL語(yǔ)句,并以可靠且類型安全的方式設(shè)定這些占位符的值。
3、動(dòng)態(tài)代碼執(zhí)行
Eval函數(shù)接受一個(gè)包含VBScript表達(dá)式的字符串自變量。
Execute和ExecuteGlobal接受一個(gè)包含ASP代碼的字符串。
4、OS命令執(zhí)行
System.Diagnostics.Start.Process
System.Diagnostics.Start.ProcessStartInfo
5、URL重定向
System.Web.HttpResponse.Redirect
System.Web.HttpResponse.Status
System.Web.HttpResponse.StatusCode
System.Web.HttpResponse.AddHeader
System.Web.HttpResponse.AppendHeader
Server.Transfer
6、套接字
System.Net.Sockets.Socket
(4)配置 ASP.NET環(huán)境
we.config XML文件包含ASP.NET環(huán)境的配置設(shè)置。




反常情況:
a. $GLOBALS是一個(gè)包含在腳本全局范圍內(nèi)定義的所有變量的引用的數(shù)組。使用它可以根據(jù)名稱訪問(wèn)其他變量
b. 如果配置 指令 register_globals被激活,PHP會(huì)為所有請(qǐng)求參數(shù)(即$_REQUEST數(shù)組中的全部數(shù)據(jù))建立全局變量。這表示,應(yīng)用程序可通過(guò)與相關(guān)參數(shù)相同的名稱引用一個(gè)變量,從而訪問(wèn)用戶輸入。
c. PHP還在$_SERVER數(shù)組中增加了一個(gè)數(shù)據(jù),用于處理在請(qǐng)求中收到的任何定制HTTP消息 頭。如提交消息頭Foo: Bar,則生成:$_SERVER['HTTP_FOO'] = "Bar"
d. 名稱包含下標(biāo)的輸入?yún)?shù)被自動(dòng)轉(zhuǎn)換為數(shù)組。如:https://xxx/xxx.php?query[a]=foo&query[b]=bar,將使$_GET['query'] 變量的值轉(zhuǎn)換成一個(gè)包含兩個(gè)成員 的數(shù)組 。
(2)會(huì)話交互
PHP使用$_SESSION數(shù)組保存和檢索用戶會(huì)話中的信息。如:
$_SESSION[‘MyName’] = $_GET[‘username’]; // store user’s name
echo “Welcome “ . $_SESSION[‘MyName’]; // retrieve user’s name
$HTTP_SESSION_VARS數(shù)組的用法與上面的數(shù)組相同。如果register_globals被激活,那么全局變量將通過(guò)以下方式保存在當(dāng)前會(huì)話中:
$MyName = $_GET[‘username’];
session_register(“MyName”);
PS: register_globals 在PHP 6已經(jīng)刪除。
(3)潛在危險(xiǎn)的API
1、文件訪問(wèn)
fopen、readfile、 file、 fpassthru、 gzopen、gzfile、gzpassthru、 readgzfile、 copy、rename、rmdir、mkdir、unlink、file_get_contents、file_put_contents、parse_ini_file
下面的函數(shù)可用于包含并執(zhí)行一個(gè)指定的PHP腳本:
include、include_once、require、require_once、virtual
遠(yuǎn)程文件檢索協(xié)議 :


PHP 5.2以后引入了一個(gè)新選項(xiàng)allow_url_include,這個(gè)默認(rèn)的配置 防止前面提到的方法在調(diào)用 文件包含函數(shù)時(shí)用于指定一個(gè)遠(yuǎn)程文件。
2、數(shù)據(jù)庫(kù)訪問(wèn)
mysql_query、mssql_query、pg_query
下面的函數(shù)用于創(chuàng)建預(yù)處理語(yǔ)句,允許應(yīng)用程序建立一個(gè)包含參數(shù)占位符的SQL查詢,并以可靠而且類型安全的方式設(shè)定這些占位符的值:
mysqli->prepare、stmt->prepare、stmt->bind_param、stmt->execute、odbc_prepare
3、動(dòng)態(tài)代碼執(zhí)行
eval、call_user_func、call_user_func_array、call_user_method、call_user_method_array、create_function
分號(hào)可以連接幾個(gè)語(yǔ)句。
搜索與替代正則表達(dá)式的preg_replace函數(shù),如果以/e選項(xiàng)調(diào)用,可用于運(yùn)行一段特殊的PHP代碼。
PHP可以通過(guò)一個(gè)包含函數(shù)名稱的變量動(dòng)態(tài)調(diào)用該函數(shù),下面的代碼將調(diào)用在查詢字符串func參數(shù)中指定的函數(shù):<?php $var=$_GET[‘func’]; $var();?> 用戶可以通過(guò)修改func參數(shù)的值,使應(yīng)用程序調(diào)用任意一個(gè)沒(méi)有參數(shù)的函數(shù),如phpinfo.
4、OS命令執(zhí)行
exec、passthru、popen、proc_open、shell_exec、system、反單引號(hào) (`)
| 可以連接命令
5、URL重定向
http_redirect、header、HttpMessage::setResponseCode、HttpMessage::setHeaders
一般用http_redirect,但是header也可以,如header("Location:/target.php");
6、套接字
socket_create、socket_connect、socket_write、socket_send、socket_recv、fsockopen、 pfsockopen
fsockopen與 pfsockopen 可用于打開(kāi)連接指定主機(jī)與端口的套接字,并返回一個(gè)可用在fwrite和fgets等標(biāo)準(zhǔn)文件函數(shù)中的文件指針。
7、配置 PHP環(huán)境(php.ini)
(1)使用全局變量注冊(cè)
如果register_globals被激活,PHP會(huì)為所有請(qǐng)求參數(shù)建立全局變量,如果PHP不要求變量在使用前被初始化,就會(huì)導(dǎo)致安全漏洞 。
PS: register_globals 在PHP 6已經(jīng)刪除。
(2)安全模式
safe_mode被激活后,PHP會(huì)對(duì)一些危險(xiǎn)函數(shù)做限制:
a. shell_exec被禁用
b. mail函數(shù)的additional_parameters參數(shù)被禁用
c. exec函數(shù)僅能執(zhí)行safe_mode_exec_dir指定目標(biāo)下的可執(zhí)行程序,命令字符串中的元字符被自動(dòng)轉(zhuǎn)義
PS: 安全模式在PHP 6已經(jīng)刪除。
(3)magic quotes
雖然激活magic_quotes_gpc指令會(huì)將請(qǐng)求中包含的任何單引號(hào)、雙引號(hào)、反斜線和空字符都會(huì)有生個(gè)反斜線自動(dòng) 轉(zhuǎn)義,但是由于其局限性與不規(guī)則性,建議禁用該 選項(xiàng)。
PS: 在PHP 6已經(jīng)刪除。
(4)其他選項(xiàng):

六、Perl
CGI.pm 是最常用于創(chuàng)建Web應(yīng)用程序的Perl模塊
(1)確定用戶提交的數(shù)據(jù)

(2)會(huì)話交互
Perl模塊CGISession.pm對(duì)模塊CGI.pm進(jìn)行擴(kuò)展,為會(huì)話追蹤與數(shù)據(jù)存儲(chǔ)提供支持:
$q->session_data(“MyName”=>param(“username”)); // store user’s name
print “Welcome “ . $q->session_data(“MyName”); // retrieve user’s name
(3)潛在危險(xiǎn)的API
1、文件訪問(wèn)
open與sysopen
如果文件名參數(shù)的開(kāi)頭或結(jié)尾為管道符(|),就可以執(zhí)行任意命令。
2、數(shù)據(jù)庫(kù)訪問(wèn)
selectall_arrayref函數(shù) 用于向數(shù)據(jù)庫(kù)發(fā)送一個(gè)查詢,并以一系列數(shù)組的形式檢索查詢結(jié)果。
do 函數(shù) 用于執(zhí)行一個(gè)查詢,并返回受影響的行的數(shù)量。
prepare與execute用于創(chuàng)建預(yù)處理語(yǔ)句,同樣的會(huì)添加占位符,以防止SQL注入。
3、動(dòng)態(tài)代碼執(zhí)行
eval,分號(hào)分隔符連接語(yǔ)句
4、OS命令執(zhí)行
system、exec、qx、反單引號(hào)(`)
5、URL? ?重定向
redirect函數(shù)
6、套接字
socket與connect
7、配置Perl環(huán)境
污染模式(taint mode):#!/usr/bin/perl -T
當(dāng)以taint 模式運(yùn)行時(shí),解釋器會(huì)追蹤該程序以外提交的每一個(gè)輸入,并把它當(dāng)做被污染的輸入處理。如果另一個(gè)變量根據(jù)一個(gè)受污染的數(shù)據(jù)分配它的值,那么Perl也認(rèn)為它受到污染。
這個(gè)模式旨在防止許多類型的漏洞,但只有當(dāng)開(kāi)發(fā)者使用適當(dāng)?shù)恼齽t表達(dá)式從被污染的輸入中提取“清潔“的數(shù)據(jù)時(shí)它才會(huì)有效。
七、JavaScript
重點(diǎn)審查以下API:

八、數(shù)據(jù)庫(kù)代碼組件
1、SQL注入
不同的數(shù)據(jù)庫(kù)平臺(tái)使用不同的方法動(dòng)態(tài)執(zhí)行包含SQL語(yǔ)句的字符串:
?MS-SQL — EXEC
?Oracle — EXECUTE IMMEDIATE
Sybase — EXEC
DB2 — EXEC SQL
在Oracle中,存儲(chǔ)過(guò)程默認(rèn)在定義者權(quán)限而非調(diào)用者權(quán)限下運(yùn)行,因此,如果應(yīng)用程序使用一個(gè)低權(quán)限帳戶訪問(wèn)數(shù)據(jù)庫(kù),并且使用DBA建立存儲(chǔ)過(guò)程,攻擊者就可以利用某個(gè)過(guò)程中存在的SQL注入漏洞提升自己的權(quán)限,并執(zhí)行任意數(shù)據(jù)庫(kù)查詢。
2、調(diào)用危險(xiǎn)函數(shù)
a. Powerful default stored procedures in MS-SQL and Sybase that allow execution of commands, registry access, and so on
b. Functions that provide access to the file system
c. User-defi ned functions that link to libraries outside the database
d. Functions that result in network access, such as through OpenRowSet in MS-SQL or a database link in Oracle
九、代碼瀏覽工具
Source Insight