SUCTF 2019-EasySQL

0x00
知識點:
1:堆疊注入
2:sql_mode : 它定義了 MySQL 應支持的 SQL 語法,以及應該在數據上執行何種確認檢查,其中的 PIPES_AS_CONCAT 將 || 視爲字符串的鏈接操做符而非 "或" 運算符。
3:,1
沒有過濾
的時候能夠直接注入*php

0x01 解題
此題能掃到源碼:html

<?php
session_start();mysql

include_once "config.php";

$post = array();
$get = array();
global $MysqlLink;

//GetPara();
$MysqlLink = mysqli_connect("localhost",$datauser,$datapass);
if(!$MysqlLink){
    die("Mysql Connect Error!");
}
$selectDB = mysqli_select_db($MysqlLink,$dataName);
if(!$selectDB){
    die("Choose Database Error!");
}

foreach ($_POST as $k=>$v){
    if(!empty($v)&&is_string($v)){
        $post[$k] = trim(addslashes($v));
    }
}
foreach ($_GET as $k=>$v){
    }
}
//die();
?>
Give me your flag, I will tell you if the flag is right.

<?phpsql

if(isset($post['query'])){
    $BlackList = "prepare|flag|unhex|xml|drop|create|insert|like|regexp|outfile|readfile|where|from|union|update|delete|if|sleep|extractvalue|updatexml|or|and|&|\"";
    //var_dump(preg_match("/{$BlackList}/is",$post['query']));
    if(preg_match("/{$BlackList}/is",$post['query'])){
        //echo $post['query'];
        die("Nonono.");
    }
    if(strlen($post['query'])>40){
        die("Too long.");
    }
    $sql = "select ".$post['query']."||flag from Flag";
    mysqli_multi_query($MysqlLink,$sql);
    do{
        if($res = mysqli_store_result($MysqlLink)){
            while($row = mysqli_fetch_row($res)){
                print_r($row);
            }
        }
    }while(@mysqli_next_result($MysqlLink));

}

?>

看到mysql_multi_query(),能夠堆疊注入數據庫

關鍵的查詢代碼是 select $post['query']||flag from Flag
咱們讓 || 不是邏輯或session

預期解:
經過堆疊注入sql_mode的值爲PIPES_AS_CONCAT
1;set sql_mode=PIPES_AS_CONCAT;select 1
設置sql_mode爲PIPES_AS_CONCAT後可改變'||'的含義爲鏈接字符串。
在oracle 缺省支持 經過 ‘ || ’ 來實現字符串拼接,但在mysql 缺省不支持。須要調整mysql 的sql_mode 模式:pipes_as_concat 來實現oracle 的一些功能
原語句中||的含義爲或運算,當前面一個字段查詢到數據時,就不會再執行。改變語義後就是將前一個字段的查詢結果和後一個字段查詢結果進行拼接。這樣兩個字段都會被查詢
構造payload:1;set sql_mode=PIPES_AS_CONCAT;select 1
注:
這個模式下進行查詢的時候,使用字母鏈接會報錯,使用數字鏈接纔會查詢出數據,由於這個 || 至關因而將 select 1 和 select flag from flag 的結果拼接在一塊兒oracle

關於非預期解 : ,1拼接一下,不難理解 : select ,1||flag from Flag等同於 select *,1 from Flag函數

注:
sql_mode 經常使用值說明post

官方手冊專門有一節介紹 https://dev.mysql.com/doc/refman/5.6/en/sql-mode.html 。 SQL Mode 定義了兩個方面:MySQL應支持的SQL語法,以及應該在數據上執行何種確認檢查。fetch

  1. SQL語法支持類

ONLY_FULL_GROUP_BY 對於GROUP BY聚合操做,若是在SELECT中的列、HAVING或者ORDER BY子句的列,沒有在GROUP BY中出現,那麼這個SQL是不合法的。是能夠理解的,由於不在 group by 的列查出來展現會有矛盾。
在5.7中默認啓用,因此在實施5.6升級到5.7的過程須要注意: Expression #1 of SELECT list is not in GROUP BY
clause and contains nonaggregated column
'1066export.ebay_order_items.TransactionID' which
is not functionally dependent on columns in GROUP BY
clause; this is incompatible with sql_mode=only_full_group_by

ANSI_QUOTES 啓用 ANSI_QUOTES 後,不能用雙引號來引用字符串,由於它被解釋爲識別符,做用與 ` 同樣。設置它之後,update t set f1="" ...,會報 Unknown column '' in 'field list 這樣的語法錯誤。

PIPES_AS_CONCAT 將 || 視爲字符串的鏈接操做符而非 或 運算符,這和Oracle數據庫是同樣的,也和字符串的拼接函數 CONCAT() 相相似。

NO_TABLE_OPTIONS 使用 SHOW CREATE TABLE 時不會輸出MySQL特有的語法部分,如 ENGINE ,這個在使用 mysqldump 跨DB種類遷移的時候須要考慮。

NO_AUTO_CREATE_USER 字面意思不自動建立用戶。在給MySQL用戶受權時,咱們習慣使用 GRANT ... ON ... TO dbuser 順道一塊兒建立用戶。設置該選項後就與oracle操做相似,受權以前必須先創建用戶。5.7.7開始也默認了。

  1. 數據檢查類

NO_ZERO_DATE 認爲日期 '0000-00-00' 非法,與是否設置後面的嚴格模式有關。

若是設置了嚴格模式,則 NO_ZERO_DATE 天然知足。但若是是 INSERT IGNORE 或 UPDATE IGNORE,'0000-00-00'依然容許且只顯示warning

若是在非嚴格模式下,設置了NO_ZERO_DATE,效果與上面同樣,'0000-00-00'容許但顯示warning;若是沒有設置NO_ZERO_DATE,no warning,當作徹底合法的值。

NO_ZERO_IN_DATE狀況與上面相似,不一樣的是控制日期和天,是否可爲 0 ,即 2010-01-00 是否合法。

NO_ENGINE_SUBSTITUTION 使用 ALTER TABLE或CREATE TABLE 指定 ENGINE 時, 須要的存儲引擎被禁用或未編譯,該如何處理。啓用NO_ENGINE_SUBSTITUTION時,那麼直接拋出錯誤;不設置此值時,CREATE用默認的存儲引擎替代,ATLER不進行更改,並拋出一個 warning .

STRICT_TRANS_TABLES 設置它,表示啓用嚴格模式。 

注意 STRICT_TRANS_TABLES 不是幾種策略的組合,單獨指 INSERT、UPDATE出現少值或無效值該如何處理:

前面提到的把 '' 傳給int,嚴格模式下非法,若啓用非嚴格模式則變成0,產生一個warning

Out Of Range,變成插入最大邊界值

A value is missing when a new row to be inserted does not contain a value for a non-NULL column that has no explicit DEFAULT clause in its definition

sql_mode通常來講不多去關注它,沒有遇到實際問題以前不會去啓停上面的條目。咱們常設置的 sql_mode 是 ANSI、STRICT_TRANS_TABLES、TRADITIONAL,ansi和traditional是上面的幾種組合。

ANSI:更改語法和行爲,使其更符合標準SQL至關於REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE

TRADITIONAL:更像傳統SQL數據庫系統,該模式的簡單描述是當在列中插入不正確的值時「給出錯誤而不是警告」。至關於 STRICT_TRANS_TABLES, STRICT_ALL_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER, NO_ENGINE_SUBSTITUTION

ORACLE:至關於 PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, NO_KEY_OPTIONS, NO_TABLE_OPTIONS, NO_FIELD_OPTIONS, NO_AUTO_CREATE_USER

不管何種mode,產生error以後就意味着單條sql執行失敗,對於支持事務的表,則致使當前事務回滾;但若是沒有放在事務中執行,或者不支持事務的存儲引擎表,則可能致使數據不一致。MySQL認爲,相比直接報錯終止,數據不一致問題更嚴重。因而 STRICT_TRANS_TABLES 對非事務表依然儘量的讓寫入繼續,好比給個"最合理"的默認值或截斷。而對於 STRICT_ALL_TABLES,若是是單條更新,則不影響,但若是更新的是多條,第一條成功,後面失敗則會出現部分更新。

5.6.6 之後版本默認就是NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES,5.5默認爲 '' 。

關於非預期解 : ,1拼接一下,不難理解 : select ,1||flag from Flag等同於 select *,1 from Flag
參考連接:
https://www.e-learn.cn/content/qita/2719846

https://www.jianshu.com/p/5644f7c39c68

https://www.cnblogs.com/piperck/p/9835695.html

相關文章
相關標籤/搜索