宣告:
由于筆者能力有限,難免出現各種錯誤和漏洞,全文僅作為個人筆記,僅供參考,
筆記內容來源于各類網課、書籍,
本章節內容來源:《Web安全攻防滲透測驗實戰指南》
一、思維導圖

二、SQL注入
1. SQL注入基礎
1.1 SQL注入介紹
SQL注入指的是:Web應用程式對用戶輸入的資料的合法性沒有判斷,前端傳入后端的引數是攻擊者可控的,并且引數帶入資料庫執行,攻擊者可以通過構造不同SQL陳述句來實作對資料庫的任意操作,
例如后端的PHP代碼如下:
$query = "select * from users where id = $_GET['id']"
由于這里的引數可控,并且帶入資料庫執行,所有攻擊者可以構建SQL陳述句進行攻擊,
例如將id=1 or 1 --+,PHP的查詢陳述句變成:
select * from users where id = 1 or 1 --
就會列印所有users的資料,
1.2 SQL注入原理
SQL注入發生需要兩個條件:
- 引數用戶可控:用戶可以控制前端傳到后端的引數值
- 引數帶入資料庫執行:傳入的引數拼接到SQL陳述句,并在帶入資料庫中執行
引數滿足上述條件,攻擊者便可以開始測驗有無注入漏洞,如果后端對前端傳入的引數沒有過濾,后端的SQL陳述句就可能發生注入,
一般的后端SQL陳述句型別的條件陳述句(where條件)可分為數字型和字符型(單引號閉合,雙引號閉合),常見如下:
where id=1
where id='1'
where id="1"
where id=(1)
where id=('1')
where id=("1")
where id=(('1'))
where id=(("1"))
where id=((('1')))
where id=((("1")))
...
如果后端沒有過濾引數,我們使用'、"和注釋符(--+、#、%23)來判斷有無注入點,
- 在數字型后添加'和"都會報錯,添加注釋符(--+、#、%23)不會報錯
- 在字符型中單引號閉合后添加"不會報錯,添加'和注釋符會報錯
- 在字符型中雙引號閉合后添加'不會報錯,添加"和注釋符會報錯
先判斷是數字型還是字符型(閉合符號)在判斷外部有無括號和括號數量,之后構建特殊SQL陳述句進行注入,
1.3 與MySQL注入有關的知識
(1). 在MySQL5.0以后,MySQL默認在資料庫中存放一個"information_schema"的資料庫,
在該庫中存盤著所有的資料庫資訊(資料庫名,表名,欄位名和相關屬性),其中有三個表尤其重要:schemata,tables,columns,
- schemata中記錄了用戶創建的所有資料庫名和資訊,資料庫名的欄位名為schema_name,
- tables中記錄了用戶創建的所有表名和資訊,資料庫名、表名的欄位名分為table_schema,table_name,
- columns中記錄了用戶創建的所有欄位名和資訊,資料庫名、表名、欄位名的欄位名分為table_schema,table_name,column_name,
(2) MySQL的查詢陳述句,可以使用條件,也可以不使用條件
- 不使用條件:select colum_name ... from database_name.table_name
- 使用條件:select column_name ... from database_name.table_name where 條件 [and/or 條件]
(3) Limit的用法
limit格式為Limit m,n,m表示起始位置(從0開始,區別substr從1開始),n表示取幾條記錄,
例如limit 0,1 表示取出第一條記錄開始,取出1條記錄,
limit可在SQL注入中用于限制輸出的資料數量,在報錯注入中,輸出的字符有限(受相應的變數控制),我們使用limit控制輸出數量,最終全部獲取,
(4) 幾個函式和系統變數
- database():當前使用的資料庫
- user():當前登陸的MySQL用戶
- version()/@@version:當前資料的版本
(5) 注釋符
- #
- --(空格/TAB/換行)
- /**/
在SQL注入中,可以使用--+,+會被php解釋為空格;%23是#的URL編碼,
(6) 行內注釋
行內注釋形式為:/*! code */,其中的代碼會被作為SQL陳述句執行,

在SQL注入中,可用于繞過過濾,
1.4 Union注入攻擊
適用條件:
- 傳入的引數使SQL陳述句報錯(或傳入引數的值不在范圍內),頁面回傳資料例外(為空等)
- 對于關鍵詞:union,select,from,order by沒有過濾,或可以繞過,
傳入引數的值不在范圍內:例如user的id從0開始遞增,我們取id=-1,
步驟:
測驗引數名假定為id,
- id可以控制頁面:id為不同值,頁面回傳不同的資料
- id可以讓SQL陳述句報錯:頁面回傳資料例外(可能會爆出后臺SQL陳述句)
- 可以執行id里面的SQL陳述句:id=-1 or 1,回傳正常的資料,就是執行了or 1的這個陳述句
- 使用order by進行欄位數判斷:從1開始,依次二分法,
- 使用union select確定資料回顯位置:一般在頁面上,有的在會在img,a等標簽的url中,
- 使用union select進行資料獲取,
存在風險的代碼舉例:

1.5 Boolean注入攻擊
適用條件:
- 構造報錯SQL陳述句和不在范圍內的引數值,頁面只會顯示兩種狀態(正常,不正常)
- 對于關鍵詞:substr,ascii,ord,select,form,limit引數沒有過濾,或者可以繞過
- 過濾了union
可以使用Boolean注入攻擊的顯著特征就是:頁面根據用戶的引數輸入,只用兩種狀態,
一般使用BurpSuite和撰寫腳本爆破最便捷,
步驟:
測驗引數名假定為id,
- id可以控制頁面:id為不同值,頁面回傳不同的資料(頁面狀態A)
- id可以讓SQL陳述句報錯:頁面回傳資料例外(頁面狀態B)
- id = -1 or substr( dataabse() , 1, 1) ='a' --+ 或 id = -1 or ascii(substr( dataabse() , 1, 1) )>-0--+ 等進行爆破出資料庫名,根據頁面顯示狀態判斷,由于-1為假,只用or后為真,才會回傳正確的頁面(頁面狀態A),
- 同理使用d = -1 or substr( (select table_name from information_schema.tables wehere table_schema = database() limit $0$,1) , $1$, 1) = 101 --+ 在$0$和$1$進行遞增爆破,即可爆破出表名
存在風險的代碼舉例:

1.6 報錯注入攻擊
適用條件:
- 構造報錯SQL陳述句,也會將報錯資訊顯示(也可能不顯示)
- 讓函式報錯是,頁面一定會顯示報錯資訊,例如updatexml中的引數應符合xpath語法,我們構造的引數讓updatexml報錯,頁面把updatexml的報錯資訊顯示,
- 對于關鍵詞:concat,cancat_ws,gourp_concat,updatexml,extractvalue引數沒有過濾,或者可以繞過
報錯注入主要是利用函式報錯,將我們需要的資訊同時爆處理,但是輸出的資訊長度受限,需要配合limit進行控制,
- id可以控制頁面:id為不同值,頁面回傳不同的資料,
- 引數中使用報錯函式updatexml或extractvalue進行報錯,錯誤可以顯示在頁面,
- 使用id=-1 or (select ( updatexml(1, concat(0x7e, version()) ,1) ) ) --+爆出資料庫版本,
- 使用id=-1 or (select ( updatexml(1, concat(0x7e, (select table_name from information_schema.tables where table_schema=database() limit $1$,1) ) ,1) ) ) --+ 在$1$處進行遞增,即可爆破出全部表名,
存在風險的代碼舉例:

2. SQL注入進階
2.1 時間注入攻擊
與布爾盲注型別,但是是由于對用用戶的引數輸入只有一種顯示狀態,不存在顯示例外情況,
我們需要結合函式sleep和if(expr1,expr2,expr3)進行攻擊,
在if中如果,expr1為TRUE,則if回傳expr2,否則回傳expr3,
例如使用:
if(lenght(database()) >1 ,sleep(5) ,1)
表示如果資料庫名長度大于1,查詢休眠5秒,反應在頁面中就是,請求的回傳的時間大于5秒(在F12,網路面板可看到),
使用如下:
if(substr(database(),1,1) ='s', sleep(5), 1)
判斷資料庫名第一個字符是否是s,如果是頁面回傳時間大于5s,
后面的爆破操作以此類推,
使用自定義寫的腳本爆破效果較好,
2.2 堆疊查詢注入攻擊
后端獲取的引數,使用PDO的方式進行資料查詢,但仍將引數拼接到查詢陳述句中,導致PDO沒有起到預編譯效果,程式任然存在SQL注入漏洞,
例如下面的代碼:

使用PDO執行SQL陳述句,可以執行多條陳述句,不過這樣通常不能直接得到注入結果,因為PDO只會回傳第一條SQL陳述句的執行結果,所以在第二條陳述句中可以用update更新資料或者使用時間盲注獲取資料,
令id = 1'; select if (ord(substr(user(),1,1) ==114,sleep(3),1); %23時,執行陳述句為:
select * from users where id = '1'; select if (ord(substr(user(),1,1)) =114,sleep(3),1); #
通過后面的時間盲注陳述句爆出資料,
2.3 二次注入攻擊
二次注入可以理解為,攻擊者構造的惡意資料存盤在資料庫后,惡意資料被讀取并進入到SQL查詢陳述句所導致的注入,防御者可能在用戶輸入惡意資料時對其中的特殊字符進行了轉義處理,但在惡意資料插入到資料庫時被處理的資料又被還原并存盤在資料庫中,當Web程式呼叫存盤在資料庫中的惡意資料并執行SQL查詢時,就發生了SQL二次注入,
二次注入,可以概括為以下兩步:
-
第一步:插入惡意資料
進行資料庫插入資料時,對其中的特殊字符進行了轉義處理,在寫入資料庫的時候又保留了原來的資料, -
第二步:參考惡意資料
開發者默認存入資料庫的資料都是安全的,在進行查詢時,直接從資料庫中取出惡意資料,沒有進行進一步的檢驗的處理,
2.4 寬位元組注入攻擊
- 使用GBK編碼繞過對單引號的過濾,
- 使用嵌套查詢繞過對select中where的條件中單引號過濾,
2.5 cookie注入攻擊
注入點在cookie處,
2.6 base64注入攻擊
輸入的引數轉為base64編碼進行攻擊,
2.7 XFF注入攻擊
注入點在X-Forwarded-For處,
3. SQL繞過技巧
3.1 大小寫繞過
例如將and,寫成AnD,anD,aNd等形式繞過,
3.2 雙寫繞過
例如將union,寫成uniunionon,ununionion等形式,
3.3 編碼繞過
對引數進行一次或多次的URL編碼,
3.4 行內注釋繞過
使用行內注釋繞過,例如and寫成 /*! and*/,
4. SQL注入修復建議
4.1 過濾危險字符,
采用正則過濾union,sleep,load_file等關鍵詞,
4.2 使用預編譯陳述句
使用PDO預編譯陳述句,不能將變數直接拼接到PDO陳述句中,而是使用占位符進行資料庫的增加、洗掉、修改、查詢,
附:
文中的風險代碼舉例來源于《Web安全攻防滲透測驗實戰指南》第四章,
二次注入介紹來源:
- 作者:Ackerzy
- 鏈接:https://www.jianshu.com/p/3fe7904683ac
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/298887.html
標籤:其他
