淺析mysql存儲過程

2020-12-09 湖南蟻景

去年的強網杯,出了一道mysql堆疊注入叫隨便注,這道題被好多比賽玩了一整年,直到現在還是有各種新姿勢,但是今天我忽然想到似乎沒有對這個題目有一個很認真的分析,因此這裡總結一下這個題目的出題用意和原本的預期做法:

堆疊注入

Stacked injections:堆疊注入。從名詞的含義就可以看到應該是一堆sql語句(多條)一起執行。而在真實的運用中也是這樣的,我們知道在mysql中,主要是命令行中,每一條語句結尾加 ; 表示語句結束。這樣我們就想到了是不是可以多句一起使用。這個叫做stacked injection。代碼中和一般查詢不同的是,使用了multi_query函數

在SQL中,分號(;)是用來表示一條sql語句的結束。試想一下我們在 ; 結束一個sql語句後繼續構造下一條語句,會不會一起執行?因此這個想法也就造就了堆疊注入。而union injection(聯合注入)也是將兩條語句合併在一起,兩者之間有什麼區別麼?區別就在於union 或者union all執行的語句類型是有限的,可以用來執行查詢語句,而堆疊注入可以執行的是任意的語句。

源碼分析

<?php

$inject = $_GET['inject'] ?? false;

if ($inject) {

$preg_match = 'return preg_match("/select|update|show|use|updatexml|extractvalue|exp|pow|char|delete|ascii|substr|sleep|if|strcmp|left|mid|concat|drop|insert|where|\./i", $inject);';

if (eval($preg_match)) {

echo "您輸入了敏感字符!";

exit();

}

if(stristr($inject, "set") && stristr($inject, "prepare")){

echo "請不要同時輸入set和prepare";

exit();

}

當時的強網杯似乎在stristr這個函數上漏寫了i導致大家用大小寫繞過,但是沒事這個不是重點(逃)

這裡過濾了很多查詢關鍵字,比如select,比如盲注用的函數,基本上是沒有辦法的,但是這裡是堆疊注入,就給了我們以執行多條sql語句的機會。

很多同學自然就想到了set+prepare的預處理語句,但是這裡規定了不能夠同時輸入set和prepaere,又被堵死了,但是mysql還有一個可以讓語句分開執行且達到等同於一起執行的效果,這裡介紹一下正解,mysql的存儲過程。

存儲過程

存儲過程(Stored Procedure)是一種在資料庫中存儲複雜程序,以便外部程序調用的一種資料庫對象。

存儲過程是為了完成特定功能的SQL語句集,經編譯創建並保存在資料庫中,用戶可通過指定存儲過程的名字並給定參數(需要時)來調用執行。

存儲過程思想上很簡單,就是資料庫 SQL 語言層面的代碼封裝與重用。類比面向對象編程的類。說白了,存儲過程就是具有名字的一段代碼,用來完成一個特定的功能。

大家看下面這個很熟悉的例子,這個例子在網絡上是教程範例,給大家熟悉一下。無非就是in和out。

create 存儲過程,然後call調用。

鑑於很多人不太理解這個in和out的區別,我們再簡單提一提。

in——傳入參數(只索取,不給予)

調用者可以給"過程"一個值,但是過程不會把這個值返回給你。比如

mysql> delimiter $$

mysql> set @p_in=1;

mysql> create procedure in_param(in p_in int)

-> begin

->   select p_in;

->   set p_in=2;

-> select p_in;

-> end$$

mysql> delimiter ;

mysql> call in_param(@p_in);

+------+

| p_in |

+------+

| 1 |

+------+

1 row in set (0.00 sec)

#因為這裡先set了p_in=1,所以存儲過程裡select p_in的值為1

+------+

| p_in |

+------+

| 2 |

+------+

1 row in set (0.00 sec)

#然後set p_in=2,所以存儲過程裡第二個select p_in的值為2

Query OK, 0 rows affected (0.00 sec)

mysql> select @ p_in;

+------+

| p_in |

+------+

| NULL |

+------+

1 row in set (0.00 sec)

#存儲過程執行完,他不會把這個值調用者,調用者在過程外是不能夠使用這個變化後的值的

in參數就是只能輸入,不能夠輸出,執行完過程,in參數是不會改變的。

out——傳出參數(不索取,只給予)

out這個參數剛好就是反過來,調用者無論怎麼給參數賦初始值,"過程"裡都是當作空值開始處理,然後將處理好的值返回給調用者。

分離預處理語句

好了說了這麼多,我們還是要結合題目來看看,題目這裡明顯是要用預處理set 和 prepare來做,但是不能夠同時輸入。經過上面的講解,我們可以想到,雖然set和prepare不能夠同時輸入,但是我只要把set給封裝到一個"過程"中去,是不是就可以利用存儲過程來代替set呢?

再理一遍大家很熟悉的set preare的注入poc怎麼寫:

這個地方的string就是我們要執行的sql語句的16進位表示,stmt則是預處理語句的別名。然後我們把他分為兩個部分:

首先我們需要創建一個將set包含進去的存儲過程,然後分析輸入和輸出參數:

in參數是sql注入語句的16進位,因為需要繞過敏感字符過濾,並且我們需要輸入這個hex給過程拿去利用;out參數則是我們的set裡的@string——預處理語句,在"過程"中賦值好以後,拿出來給我們的prepare使用。因此我們的poc可以這麼寫:下面的uuid代表php代碼生成的隨機數。第一次輸入存儲過程的定義:

114514';

create procedure `{$uuid}`(out string text(1024), in hex text(1024))

BEGIN

SET string = hex;

END;

;--

第二次用call調用這個存儲過程(@decoded其實就是傳參,傳到上一個poc的string位置,為了和string區分開,就用了另一個名詞):

之後就會正常的執行set+prepare的注入了。

總結

其實大家如果實在不清楚這個in和out,可以使用inout來代替,inout參數是既可以輸入,又可以輸出。

說白了存儲過程就是sql語句裡的函數,可以封裝代碼,所以比賽中如果遇到了不能一起使用的關鍵字,可以嘗試著使用存儲過程將其分割開。

合天網安實驗室相關實驗推薦==繞過UNION&SELECT過濾(針對於過濾,我們要善用編碼,來繞過關鍵字過濾。本實驗主要介紹繞過UNION&SELECT過濾的技巧。)

相關焦點

  • MySQL創建存儲過程
    存儲過程是資料庫管理中常用的技術之一,可以很方便的做些類似數據統計、數據分析等工作,市場上的SQL SERVER、ORACLE、MySQL都支持存儲過程,但不同的資料庫環境語法結構有點區別,本案例給大家講解下MySQL創建存儲過程的方法使用常規的創建存儲過程方法,發現各種報錯,無法執行
  • 淺析 MySQL 存儲引擎序列屬性
    每個表只能有一個列具備AUTO_INCREMENT屬性,並且為整數型AUTO_INCREMENT列不能包含NULL值(MySQL會自動設置為NOT NULL)AUTO_INCREMENT列上必選要有索引,常見為primary key和unique index二、MyISAM存儲引擎
  • MySql基礎,MySql視圖&索引&存儲過程&觸發器
    存儲過程是一組為了完成特定功能的 SQL 語句集合。使用存儲過程的目的是將常用或複雜的工作預先用 SQL 語句寫好並用一個指定名稱存儲起來,這個過程經編譯和優化後存儲在資料庫伺服器中,因此稱為存儲過程。當以後需要資料庫提供與已定義好的存儲過程的功能相同的服務時,只需調用「CALL存儲過程名字」即可自動完成。
  • MySQL存儲過程使用解析
    mysql存儲過程存儲過程(Stored Procedure)是一種在資料庫中存儲複雜程序,以便外部程序調用的一種資料庫對象。目的是為了完成特定功能的SQL語句集,經編譯創建並保存在資料庫中,用戶可通過指定存儲過程的名字並給定參數(需要時)來調用執行。說白了就是資料庫 SQL語言層面的代碼封裝與重用。創建的存儲過程通常保存在資料庫的數據字典中。
  • 關於mysql存儲過程和事務的概述
    存儲過程是sql語句和流程控制語句的預編譯集合,以一個名稱存儲並作為一個單元進行處理。基本語法:過程體:示例:存儲過程的參數:1.創建無參的存儲過程:2.創建帶有輸入參數和輸出參數的存儲過程:創建複合結構的存儲過程:1.使用條件判斷語句的存儲過程:2.使用循環語句的存儲過程
  • MySQL存儲過程批量插入百萬條數據
    最近在做一個項目,需要批量插入一批數據(ps:隨機的),試想了一下,就想用mysql的存儲過程試下,因為是在個人本機測試的,可能插入的過百秒現在說下批量創建100萬條數據第一步:創建存儲過程:delimiter $$create procedure
  • MySQL創建存儲過程-百家號 - 百度經驗
    存儲過程是資料庫管理中常用的技術之一,可以很方便的做些類似數據統計、數據分析等工作,市場上的SQL SERVER、ORACLE、MySQL都支持存儲過程,但不同的資料庫環境語法結構有點區別,本案例給大家講解下MySQL創建存儲過程的方法使用常規的創建存儲過程方法,發現各種報錯,無法執行
  • MySQL 高級 - 存儲過程和函數(上)
    1.1 存儲過程和函數概述存儲過程和函數是 事先經過編譯並存儲在資料庫中的一段 SQL 語句的集合,調用存儲過程和函數可以簡化應用開發人員的很多工作,減少數據在資料庫和應用伺服器之間的傳輸,對於提高數據處理的效率是有好處的。存儲過程和函數的區別在於函數必須有返回值,而存儲過程沒有。
  • 一鍵導出mysql視圖、函數、存儲過程、事件、觸發器的定義腳本
    所以就順便整了一鍵導出視圖、函數、存儲過程、事件、觸發器的定義腳本,下面一起來看看吧~一鍵導出腳本腳本明細如下: .function,procedure,event,trigger&34;$db_name&34;+%Y-%m-%d %H:%M:%S&34;&34;& 視圖if [[ $output_type == *&34;* ]]then echo &34; >> $save_file echo &34; >> $save_file echo &34; >> $save_file mysql
  • MySQL底層存儲結構
    2814:32 ibtmp1root@test:/var/lib/mysql#General Tablespace:一般表空間,就是平時我們用於存儲自己業務表中的數據用的表空間文件。如下圖所示,他們在物理上不一定是有序的,可能剛開始是有序的,但是隨著增刪改的操作可能就無序了,但是在邏輯上是有序的:一個page頁中的多行記錄,再結合多個page頁,就形成如下的存儲結構:頁與頁直接是雙向鍊表,頁內的行記錄直接是單向鍊表。如下所示:page頁中的每一個箭頭可以理解為一行數據。基於上面的圖,當我們要查詢某一行記錄的時候,是通過下面的過程來查找的。
  • mysql存儲過程詳解,跟老韓一起學習吧
    那就跟著老韓學習mysql存儲過程把,學完了之後這個問題迎刃而解,Let's go。一、概念;存儲過程(Stored Procedure)是在大型資料庫系統中,一組為了完成特定功能的SQL 語句集,它存儲在資料庫中,一次編譯後永久有效,用戶通過指定存儲過程的名字並給出參數(如果該存儲過程帶有參數)來執行它。存儲過程是資料庫中的一個重要對象。
  • MySQL存儲過程詳解
    作為過來人我剛開始也有這樣的苦惱,今天就給大家說說這個存儲過程該如何創建和使用。什麼是存儲過程存儲過程是一組可編程的函數,是為了完成特定功能的SQL語句集,經編譯創建並保存在資料庫中,用戶可通過指定存儲過程的名字並給定參數(需要時)來調用執行。
  • 我是如何在五分鐘內完成Centos7系統下遷移mysql的存儲路徑的
    工單場景centos7系統下使用rpm包安裝了一個mysql,隨著數據量大,發現系統的根目錄快慢了,於是需要遷移mysql的默認存儲路徑。,裡面會記錄系統的存儲路徑。實施過程1.先停止mysqld服務systemctl stop mysqld
  • MySQL存儲過程的使用總結
    >一、MySQL存儲過程的創建 建立個存儲過程,將商品編號g_id=』 hadoop_001』這本書的價格加10元,並顯示結果。>//CALL add_price()二、MySQL存儲過程的參數 分別建立個帶參數in、out、inout的存儲過程:1、帶in的參數DELIMITER//CREATE PROCEDURE demo_in(IN p_in INT)
  • 刪除行對MySQL序列有什麼影響?
    >每個表只能有一個列具備AUTO_INCREMENT屬性,並且為整數型AUTO_INCREMENT列不能包含NULL值(MySQL會自動設置為NOT NULL)AUTO_INCREMENT列上必選要有索引,常見為primary key和unique index備註:由於存儲引擎的不同對於序列的定義和使用存在差異
  • MySQL不同存儲引擎的數據備份與恢復
    在之前的幾篇文章中,我們以MySQL為例對數據備份進行了粗略的解讀,本文我們依然以MySQL為例,講講面對不同的存儲引擎如何做數據備份與恢復。  為了應對不同的數據處理,MySQL提供了十幾種不同的存儲引擎,不過,我們沒有必要一一去了解,因為熟悉使用MySQL的人都知道,比較常用的存儲引擎有兩個,分別是MyISAM和InnoDB。
  • MySQL5.7升級到MySQL8全過程指導總結
    今天主要介紹從5.7升級到8.0版本的過程及注意事項,有想做版本升級的小夥伴可以參考下。一、注意事項mysql從5.7升級到8.0是支持的,但是只支持GA版本的升級,並且要求版本為5.7.9或者更高在升級到8.0之前,建議升級到5.7的最新版本。
  • Centos7 Mysql5.7.28升級到5.7.31過程
    Centos7 Mysql 5.7系列升級版本過程前言在作業系統為centos的生產環境伺服器需要進行等保2.0評測,使用綠盟科技的掃描軟體掃描後檢測出一大批漏洞編寫一鍵安裝腳本vim mysql5.7.28_install.shRPM包位置https://dev.mysql.com/downloads/mysql/作業系統選擇Red Hat Enterprise Linux /Oracle Linux34;================================&34;正在卸載Mysql&34;===========
  • mysql的存儲過程的概念及創建語法詳解
    存儲過程存儲過程是一組為了完成特定功能的 SQL 語句集合使用存儲過程的目的是將常用或複雜 的工作,預先用 SQL語句寫好並用一個指定名稱存儲起來,這個過程經編譯和優化後存儲 在資料庫伺服器中,因此稱為存儲過程。以後需要資料庫提供與已定義好的存儲過程的功 能相同的服務時,只需用 CALL 語句來調用存儲過程名字,即可自動完成命令。
  • 原來MySQL的存儲過程也可以這麼玩?
    一、什麼是存儲過程?MySQL5.0版本開始支持的存儲過程。存儲過程(Stored Procedure)是一種在資料庫中存儲複雜程序,以便外部程序調用的一種資料庫對象。存儲過程是為了完成特定功能的SQL語句集,經編譯創建並保存在資料庫中,用戶可通過指定存儲過程的名字並給定參數(需要時)來調用執行。