做者:ZERO 所屬團隊:Arctic Shell 前端
參考文獻:《sql注入攻擊與防護》web
使用平臺:pikachu漏洞練習平臺sql
在owasp發佈的top10排行榜中注入漏洞一直是危害排名極高的漏洞,數據庫注入一直是web中一個使人頭疼的問題。數據庫
這並非戲言,其實SQL注入漏洞最主要的造成緣由是在進行數據交互中,當前端的數據傳入後端進行處理時,因爲沒有作嚴格的判斷,致使其傳入的「數據」在拼接到SQL語句中以後,因爲其特殊性,被看成SQL語句的一部分被執行,從而致使數據庫受損(被脫褲、被刪除、甚至整個服務器權限淪陷)。編程
本文將從web程序的基本原理開始理解SQL注入,而後找到SQL注入利用(本次將演示利用information-schema注入進行一次完整的入侵過程再現)。後端
在平常web開發中,咱們會來開發出許多的web應用來服務於咱們的平常生活,隨着人們生活質量的提升,web應用的形式也愈來愈多,但大部分的web應用依舊有着相同點,他們都具有交互性,且多半是數據庫進行驅動的,在當下的互聯網中,用數據庫驅動的web應用多如牛毛,他們一般含有一個後臺數據庫以及不少頁面,而在這些頁面中包含了利用某種編程語言來寫成的服務器端腳本,這些腳本做用於web頁面來與用戶進行交互時從數據庫中提取特定的數據。服務器
表示層是一個web應用的最高層,將該web應用的具體功能以及信息呈現給用戶,還能夠與其餘層進行交互。架構
邏輯層(中間層)是用來處理細節以達到控制應用的目的。編程語言
而存儲層包括數據庫服務器,用來進行的信息的檢索和存貯。post
一般的交互方式就是表示層向中間層發出請求,中間層經過查詢、檢索存儲層,獲取信息來響應該請求。這就是一次完成的交互過程。
三層架構有一個基本原則:表示層不能直接於數據層通訊,在三層架構中,全部通訊必須都經過中間層。
前面講了那麼多理論的東西,究竟什麼是SQL注入呢?
SQL注入就是構造SQL語句並將他們插入到傳入的參數中發動的攻擊,而後將這些參數遞交給後臺SQL服務器加以解析並執行。
這裏我將用一個最基本的數字型注入來演示一個基本SQL注入
一個基本的查詢頁面長這樣的:
咱們輸入一個「1」試一試
這裏能夠看出查詢了兩個字段,猜想hello後的應該是用戶名,下面的應該是用戶所對應的郵箱
所以猜測SQL語句的構造多是這樣的:
select 字段1,字段2 from 表 where id =1
那咱們如何得到表的其餘數據呢?(俗稱爆表)
這裏就能夠來嘗試構造一個利用了:1 or 1=1
(在SQL中or是若是第一個條件和第二個條件中只要有一個成立,則 OR 運算符顯示一條記錄。1=1永久返回爲真,因此where後輸入的值將永遠爲真)
由於是post方法,咱們使用hackbar進行post提交,來遍歷整個表
一次基礎的SQL注入利用就演示完成了。
自己咱們很難獲取到web應用的源代碼,這樣會致使咱們不知道設計者如何設計的,找到SQL注入,這就須要藉助黑客自己的自我思惟能力來進行測試。藉助推理來進行測試的通常步驟:向服務器發送請求,而後查看其中的異常來獲取信息。
在web注入靶場中咱們能夠經過看源碼知道這個web應用的構造,來完成利用,而在實際的測試中,碰到的都是是不開源的web應用,致使對於內部構造徹底不清楚,在實際的測試中通常黑客採用讓SQL報錯的方式來猜想內部構造,以達到找到注入點的目的。
我將經過字符型注入來演示經過SQL報錯來查找注入
字符型注入這類利用的通常方式是:先來閉合測試,構造合法的SQL來欺騙後臺。
利用的通常樣式:xxx (符號閉合) or 1=1(註釋)
一般一個輸入框咱們事先並不知道輸入的內容再被傳入時被當作字符仍是數字,這時就能夠經過報錯來進行判斷,SQL中字符和數字的區別是數字不用’’或者」」來進行修飾,而字符則須要,因而咱們則須要判斷兩次,先判斷這個輸入框是數字型的仍是字符型的在判斷他是用哪一個修飾符來進行修飾
報錯內容提示列名不存在,這個報錯提示咱們SQL服務器認爲這個值不是一個數字,那末就是一個列,而後SQL去尋找這個列,而後固然什麼都找不到,就返回報錯了,經過這裏咱們能夠判斷出應該輸入的類型
接着來判斷修飾符
查詢後結果
從報錯提示中能夠分析出雙引號並無傳遞進數據庫服務器裏,也就是存儲層,咱們再試一個單引號
再次返回報錯,在這個報錯中咱們能夠看出修飾符已經進入到了SQL服務器中並執行,說明存在注入點,接着能夠來開始進行注入了,知道了該用哪一個修飾符進行閉合,這時構造個利用將會變的更加容易。
(每當咱們傳遞一個值到SQL構造語句中的時候,若是傳遞的一個值是須要符號修飾的,那末SQL語句會自帶一個符號去進行閉合,例如:傳值爲a,到SQL語句中就會使這樣:select xxx,xxx from xxx where id=’a’,那兩個單引號就是SQL構造語句中用來進行參數閉合的,簡單的說,只要你輸入一個須要符號修飾的詞語,後臺就會自動給它加一個修飾符號,這也就是咱們爲什麼要把前面進行符號閉合,可是後面就會多了一個‘ 符號,咱們直接註釋掉就行了。一樣的方法,利用order by 能夠猜想有幾個字段,道理相同,這裏就不贅述了。)
information_schema數據庫是MySQL自帶的,它提供了訪問數據庫元數據的方式。
元數據是關於數據的數據,如數據庫名或表名,列的數據類型,或訪問權限等。有些時候用於表述該信息的其餘術語包括「數據詞典」和「系統目錄」。
也就是說information_schma能夠查到你的全部的搭建的數據庫名、表名和列的數據類型,在一切條件未知的狀況下,存在注入點的話咱們能夠直接嘗試對information_schema進行訪問,從而得到更多的信息。
例如:
SCHEMATA:提供了當前MySQL實例中全部數據庫的信息
TABLES:全部數據庫表的信息
CONLUMNS:提供了列信息
既然要從一個信息數據庫開始注入,也就是另一個數據庫,咱們就不能在當前的數據庫下進行查詢,可是當前數據庫查詢下還存在一個注入點,因此說如何才能同時查詢兩次呢?這個時候咱們就能夠用到union聯合注入了,而union的做用是將兩個或多個select語句查詢語句結果合併起來
幾個值得注意的地方:
1.UNION必須由兩條或兩條以上的SELECT語句組成,語句之間用關鍵字UNION分隔
2. UNION中的每一個查詢的列數(字段數)必須相同
3. UNION會從查詢結果集中自動去除了重複行
好比:
主查詢:
select username,password form member where name=「zero「 (union查詢)union select id,password form member where id=1
構造 payload:
xx' union select database(),user()#
說明:
Database():這個是查詢數據庫名稱
user():這個是使用者權限
仍是使用字符型注入,在前面的報錯中咱們知到了兩個字段和注入點是單引號,開始注入
首先獲取基本信息:當前數據庫名稱
xxx’union select database(),user()#
獲取到當前數據庫名稱:pikachu
經過information_schema來獲取pikachu中有多少個表以及表的名稱
xxx’union select table_schema,table_name from information_schema.tables where table_schema=」pikachu」#
獲取到表名:users
獲取列:
xxx’union select table_name,column_name from information_schema.columns where table_name=’users’#
整理獲取到的信息來獲取密碼:
xxx’union select username,password from users#