1. 程式人生 > >存在於檔名中的SQL手工注入

存在於檔名中的SQL手工注入

SQL注入已經在前一章為大家介紹了個大概,本文將講述我遇到的本以為是檔案上傳漏洞,卻是以檔名觸發的SQL注入!

本文分享的內容同樣來自於一道CTF題!

1. 直接進入正題

      (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 !<