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
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开始也默认了。
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