由於轉了onenote行列,所以已經好久沒有發表新的隨筆了,但是想想還是非常有必要的,這幾天開始學習php代碼審計,所以先開始發這一些的隨筆吧!
首先就先通過十大測試平台dvwa開始學習吧,先在這裡帶上參考的大牛鏈接,感謝分享
1.http://drops.wooyun.org/papers/483
2.http://www.lxway.com/86980986.htm is_numeric 函數繞過
3.http://www.cnblogs.com/Safe3/archive/2008/08/22/1274095.html 字符編碼繞過 寬字節注入
這裡先帶入最簡單low級別的php代碼
$id = $_GET['id'];//未作任何過濾,防注入處理 $getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'"; $result = mysql_query($getid) or die('<pre>' . mysql_error() . '</pre>' );
看到這裡我們可以知道這段代碼其實對id沒有進行處理,導致sql注入漏洞,ok,各種注入都可以,在這裡就不再詳敘了!
medium級別,代碼:
$id=$_GET['id']; $id=mysql_real_escape_string($id);//這裡對id進行了轉義的操作 $getid="SELECTfirst_name,last_nameFROMusersWHEREuser_id=$id";
mysql_real_escape_string 函數對id參數進行了轉義操作,具體常見的轉義包括
這裡我想應該有2張方法來繞過這個處理:
1.數值型注入
由於這個函數主要針對的是字符型特殊字符的處理,這樣我們可以不使用特殊字符來進行注入,即數值注入
構造:1 untion select user,password from users
由此可以獲得users表中的賬號密碼,當然你會說要是是不知道具體表名列名改怎麼辦?ok,我們可以嘗試使用union bool注入
構造:1+union+select+1,(select+case+when+char(72)=(select mid(table_name,0,1) from information_schema.tables limit 0,1)+then+2+end)
其中char()中的數值需要變換以及limit,這樣子可能會比較花時間,我們可以寫個python腳本(ps:先占個坑),其實用延時注入也同樣可以實現這樣的效果
2.寬字節注入
mysql_real_escape_string 對參數進行轉義的方法就是添加一個‘\’,它的url編碼就是%5c ,這樣我們在參數中添加%df%5c%27 ,其中%df%5c為合法的gbk字符
那麼經過該函數一處理,可以發現會變成%df%5c%5c%27 ,這樣子%df%5c會吞掉一個%5c 變成 一個gbk字符+ \\\'
而mysql的轉義符也是'\' 相當於注入了一個單引號
構造:1%df%5c%27%20||1+--+
同樣的addslashes函數也存在同樣的問題,具體參考文章開始的鏈接
high級別的php代碼
$id=$_GET['id']; $id=stripslashes($id);//剔除參數中的斜槓 $id=mysql_real_escape_string($id);//對id中的特殊字符進行轉義 if(is_numeric($id)){//判斷是否是數值或數值字符串 ...
好吧,這樣一來,我覺得還是變得很安全了,前面2個函數對字符型的注入進行了處理,緊接著is_numeric函數則對數值型注入進行了處理。
然而這樣子仍然可以造成sql注入,不過是二次注入,且限制的條件也比較苛刻但是仍有機會造成注入
比如執行sql語句
insert into test(type) values($s);
此時傳入的字符串$s=0x31206f722031
這樣看可以知道這是一個16進制數,可以通過該函數的檢測,然後對16進制解碼我們可以發現$s其實實際的值為 ‘1 or 1’
那麼這樣操作數據庫裡會變成什麼樣子
可以看到數據庫將這串16進制數進行了轉碼變成了1 or 1 那麼到時候進行數據庫取值然後不經處理帶入到另一個sql語句中就會造成二次注入.所以我們在寫代碼的時候不能盲目的信任數據庫裡的數據,在取出數據時仍需要進行檢測。
sql部分的代碼就分析到這裡,如有不正確的地方,歡迎拍磚!
下篇准備sql blind :)