SQL注入已經在前一章爲你們介紹了個大概,本文將講述我遇到的本覺得是文件上傳漏洞,倒是以文件名觸發的SQL注入!web
本文分享的內容一樣來自於一道CTF題!sql
1. 直接進入正題shell
(1) 初步探測數據庫
先看一下主頁面(題目須要註冊登陸,這裏直接跳過了)瀏覽器
就這個頁面,我不知道你看到的時候會怎麼認爲,個人第一想法就是他必定是一個文件上傳漏洞拿flag。因而我開始了我得上傳之旅,一開始仍是有一些欣喜,以爲超簡單的一道題:文件上傳拿shell就完事了。因而經過burp抓包,修改請求頭,成功的將小立刻傳到了服務器(這裏很少解釋,文件上傳之後再和你們分享)。卻發現根本沒法得到文件所在路徑,也就是隻能上傳,卻沒法利用。安全
小結:當思考網站是否爲文件上傳漏洞時,不只僅要考慮是否能上傳木馬文件,還要考慮文件被上傳到服務器之後,文件所在的位置,也就是可否被利用。(本題大牛應該直接就能發現不是文件上傳,由於根本沒法得到上傳文件所在路徑)服務器
(2)嘗試進行SQL注入測試
沒辦法只能繼續尋找漏洞所在,再來看一下上傳了幾個文件以後的網站:網站
在頁面(上圖)中能夠清楚地看到已經上傳的文件(名)。這說明文件被上傳到了數據庫中,同時瀏覽器從數據庫中讀取了上傳的文件,那麼這個過程就有可能觸發SQL注入。因而在文件名中先嚐試輸入select database() 命令(我認爲如今不必直接去探測數據庫邏輯,構造可執行的SQL語句,不過你也能夠直接構造能在服務器可SQL語句格式)並上傳。編碼
你會發現當文件名爲select database().jpg的時候,輸出的文件名爲database().jpg。而當輸入文件名爲aaa database().jpg時,輸出的文件名也爲aaa database().jpg。那麼就可判斷,服務器將select過濾了,而後在嘗試其餘命令,發現from也被過濾掉了。(select database()是暴數據庫名的一種方式)
(3)嘗試繞過
既然服務器將select命令過濾掉了,那說名必定有貓膩,那麼就嘗試繞過。
首先嚐試解決select和from被過濾的問題,我嘗試了編碼方式,發現服務器返回信息沒有解碼,這說明編碼後在數據庫中不能將其轉變成命令執行,所以不可行。而後嘗雙寫(也是一種常見的繞過方式)。驚喜的發現selselectect能夠成功繞過。一樣frfromom也能成功繞過。
由以上得出結論服務器可能存在SQL注入。(由於在文件名中過濾掉了select 和from兩個經常使用SQL命令,併成功繞過了過濾)
2. 肯定文件名觸發SQL注入
解決了過濾,我盟來構造一下可以被數據庫執行的SQL語句,
(1) 猜想服務器經過命令:insert into 表名('filename',...) values('你上傳的文件名',...);來將數據存儲到數據庫。
(2) 構造語句:'+(selselectect database())+' 。
(3) 拼接後的sql語句爲:insert into 表名('filename',...) values('文件名'+(selselectect cdatabase())+'.jpg',...);
所以嘗試 1'+(selselectect database())+'.jpg 。服務器返回0,說明SQL語句被執行了,但沒法輸出執行結果。
3. 開始操做
首先考慮是返回數據時數據被過濾掉了,嘗試改成輸出十六進制,'+(selselectect hex(database()))+'.jpg 。服務器返回" 7765625 "。
7765625解碼爲" web "。(貌似成功注入)這裏我當時也是信誓旦旦的覺得完成了,能夠進一步猜表猜字段了。
可是要注意的是本題還設置了一種截斷,即:插入數據庫文件名中若是包括SQL語句,那麼在返回信息時,服務器將對字母進行截斷(某些特殊字符也會截斷或過濾)。這是一個很大的坑,可是若是你經驗豐富可能很容易發現這個截斷,判斷依據以下:
由於當你構造的文件名爲 '+(selselectect hex(database()))+'.jpg 。服務器返回" 7765625 "。而輸入 111'+(selselectect hex(database()))+'.jpg 時,返回的信息爲765736 (=7765625+111)。
但輸入 a111'+(selselectect hex(database()))+'.jpg 時,仍返回7765625。
所以便可以說明命令:1'+(selselectect hex(database()))+'.jpg的返回值爲何爲0(由於返回數據是字符,不是數值,所以只能返回0)。也能夠判斷服務器進行了字符(英文字母等)截斷。
解決辦法是:嘗試其餘進製表示。二進制表示失敗(多是服務器設置問題,我也沒咋弄清楚爲啥二進制返回0)。因而使用conv命令,將16進制轉換爲10進制:CONV(N,from_base,to_base) N是要轉換的數據,from_base是原進制,to_base是目標進制。
(1) 構造命令:'+(selselectect conv(hex(database()),16,10))+'.jpg 。返回一個帶小數點的數值。
這是由於返回值太大,系統使用科學計數法(xx e xxxxx)表示,所以使用substr作長度限制。substr(str,pos,len) str字符串,從pos開始的位置,截取len個字符(空白也算字符)。
(2) 構造命令:'+(selselectect conv(substr(hex(database()),1,12),16,10))+ '.jpg ,(通過不斷測試發現長度最大爲12,長度大於12返回值就會以科學計數法表示)返回10進制數:131277325825392 轉化爲16進製爲7765625f7570,轉換成字符:web_up(Unicode編碼:12個字節至關於6個字符)
構造命令'+(selselectect conv(substr(hex(database()),13,25),16,10))+ '.jpg ,返回10進制數:1819238756 轉化爲16進製爲6c6f6164,轉換成字符:load
獲得數據庫名:web_upload
(3) 獲得數據庫名,那麼就能夠猜表名了。
構造命令: '+(selselectect+conv(substr(hex((selselectect table_name frfromom information_schema.tables where table_schema='web_upload' limit 1,1)),1,12),16,10))+'.jpg
'+(selselectect+conv(substr(hex((selselectect table_name frfromom information_schema.tables where table_schema='web_upload' limit 1,1)),13,12),16,10))+'.jpg
經過改變substr的參數,最後將獲得的字符鏈接獲得表名:hello_flag_is_here
(4) 獲得表名,那麼猜字段。
構造命令: '+(seleselectect+conv(substr(hex((selselectect COLUMN_NAME frfromom information_schema.COLUMNS where TABLE_NAME = 'hello_flag_is_here' limit 1,1)),1,12),16,10))+'.jpg
經過改變substr的參數,最後將獲得的字符鏈接獲得字段:i_am_flag
(5) CTF的宗旨,能夠拿flag了。
構造命令: '+(selselectect+CONV(substr(hex((seselectlect i_am_flag frfromom hello_flag_is_here limit 0,1)),1,12),16,10))+'.jpg
經過改變substr的參數,最後將獲得的字符鏈接獲得flag。 拿到flag,注入完成。
具體暴庫過程,可參考上一篇文章
4. 總結
知識點:
文件上傳,不只要注意是否能上傳,還要考慮文件位置。文件是否可以被利用。
與數據庫交互並回顯,有可能觸發SQL注入。
SQL語句重寫繞過。
SQL語句的巧妙構造。
編碼轉換的巧妙運用。
本文供安全人員參考。以上是小白給你們的經驗分享,望大佬們多多指教 Thank You !