实现PROXY穿越(9):NTLMv1 response
2009-11-15 10:01
309 查看
最近忙,事比较多,活多了,还要降薪,唉。没什么时间看书,将以前的一些技术blog也移到这里。NTLM在去年年底和今年年初研究过一阵子,写了总结和
例子程序。里面涉及很多算法,在网上查了很久。(下面是以前的博客)最近想实现一个通过PROXY穿越的网络编程,将相关的内容进行一下汇总。很多东西来
自网络共产主义,也应该为共产主义有所回馈。介绍NTLMv1 response的实现 。
经过了前面的准备,可以进入计算NTLM的响应。NTLM响应分为NTLM v1,NTLMv2,NTLM session
v2三种。具体使用哪种进行,由客户端和proxy进行协商确定,在讨论client和proxy的交互过程中,我们需能计算不同的response。
服务器(Proxy)提供一个8-byte的challenge. 客户端用于进行LM response和NT
response的计算,服务器自己也根据密码进行计算,校验和Client送过来的数值。LM and NT
responses都是24bytes。
对于NTLM Response,也就是我们常说的NTLMv1的方式,可以表述如下:
服务器发送一个8字节的随机数作为challenge。
客户端返回48字节的response。下面描述NTLMv1的步骤:
步骤一:获取挑战值
从服务器中获取8字节的challenge:
C = 8-byte server challenge,
random
步骤二:计算LM-HASH
根据用户密码计算LM-HASH,获得16字节的hash值,在后面加上5个空字节,总共21个字节,将21字节平均分割为三个7字节,然后进行DES计算:
K1 | K2 | K3 = LM-Hash | 5-bytes-0
R1 = DES(K1,C) | DES(K2,C) | DES(K3,C)
步骤三:计算NT-HASH
根据用户密码计算NT-HASH,获得16字节的hash值,在后面加上5个空字节,总共21个字节,将21字节平均分割为三个7字节,然后进行DES计算:
K1 | K2 | K3 = NT-Hash | 5-bytes-0
R2 = DES(K1,C) | DES(K2,C) | DES(K3,C)
步骤四:获取NTLMv1 response
response = R1 | R2
我们在DES的算法中,key的输入是64比特,将这8个字节分别去掉CRC校验位(第8位),生成56比特的key。现在我们直接输入为56字节比
特,可以通过LM-Hash中介绍的使用str_to_key函数,将这56比特的key变为64比特的key作为DES算法的输入,或者我们直接在
DES算法中增加一个函数用于处理直接56比特key的输入。如下:
static int ip_56key_seq[] ={
50,43,36,29,22,15,8,
1,
51,44,37,30,23,16,
9, 2,
52,45,38,31,24,
17,10,3,
53,46,39,32,
56,49,42,35,28,21,14,
7,
55,48,41,34,27,20,
13,
6,54,47,40,33,26,
19,12,5,
25,18,11,4};
void algorithm_des_56key(IN unsigned char * src, IN unsigned char *
secrect,
OUT unsigned char * dst){
unsigned
char s[64],key[64],L[32],R[32],K[48],E[48];
int i =
0;
storebit(src,8,s);
storebit(secrect,8,key);
//step1: initial permutation src and
key
initail_permutation(s,ip_data_seq,64,s);
initail_permutation(key,ip_56key_seq,56,key);
//step2:16次计算
//获取原始的L0和R0
memcpy(L,s,32);
memcpy(R,s+32,32);
//进行16次计算
for(i = 0; i
< 16 ; i++){
//获取K
getkey(key,key_offset[i]);
initail_permutation(key,ip_key,48,K);
//F计算
initail_permutation(R,ip_e,48,E);
xorbit(E,K,48,E);
s_box_function(E,s1,E);
s_box_function(E + 6,s2,E + 4);
s_box_function(E + 12,s3,E + 8);
s_box_function(E + 18,s4,E + 12);
s_box_function(E + 24,s5,E + 16);
s_box_function(E + 30,s6,E + 20);
s_box_function(E + 36,s7,E + 24);
s_box_function(E + 42,s8,E + 28);
initail_permutation(E,ip_p,32,E);
xorbit(E,L,32,E);
memcpy(L,R,32);
memcpy(R,E,32);
}
memcpy(s,R,32);
memcpy(s+32,L,32);
initail_permutation(s,inverse_ip_p,64,s);
parsebit(s,dst,8);
}
下面,我们给出NTLM v1 reponse的程序:
void ntlmv1_response(IN char * passwd, IN int passwd_len,IN
unsigned char * chanllenge,
OUT unsigned char * dst, OUT int *
dst_len){
unsigned
char hash[21];
//K1 | K2 | K3 = LM-Hash | 5-bytes-0
//R1 = DES(K1,C) | DES(K2,C) | DES(K3,C)
lm_hash(passwd, hash,NULL);
memset(hash
+ 16,0,5);
algorithm_des_56key(chanllenge, hash,dst);
algorithm_des_56key(chanllenge, hash+7,dst+8);
algorithm_des_56key(chanllenge, hash+14,dst+16);
//K1 | K2 | K3 = NT-Hash | 5-bytes-0
//R2 = DES(K1,C) | DES(K2,C) | DES(K3,C)
nt_hash(passwd, 0,hash,NULL);
memset(hash
+ 16,0,5);
algorithm_des_56key(chanllenge,hash,dst+24);
algorithm_des_56key(chanllenge,hash+7,dst+32);
algorithm_des_56key(chanllenge,hash+14,dst+40);
if(dst_len
!= NULL)
* dst_len =
48;
}
NTLM
v1响应实际上是将LM响应和NT响应合并发送,这是最容易计算的。LM是用于最古老的客户端,是最原始的响应类型;NT响应,也叫做NTLM响应,用于基于NT的客户端,例如Windows
2000和XP。如果我们进行抓包,大部分Proxy穿越不使用NTLMv1这个古老的方式,当然如果自己编写的客户端使用这种方式,并成功和Proxy协商,穿越没有问题。
相关链接:我的网络通信相关文章
NTLM的实现:
实现PROXY穿越(16):NTLM的PROXY穿越
实现PROXY穿越(15):NTLM Session Security
实现PROXY穿越(14):NTLM type3 Message
实现PROXY穿越(13):NTLM type2 Message
实现PROXY穿越(12):NTLM type1 Message
实现PROXY穿越(11):NTLMv2 session response
实现PROXY穿越(10):NTLMv2 response
实现PROXY穿越(9):NTLMv1 response
实现PROXY穿越(8):NT-Hash的实现
实现PROXY穿越(7):MD4和MD5
实现PROXY穿越(6):LM-Hash的实现
实现PROXY穿越(5):DES算法之三
实现PROXY穿越(4):DES算法之二
实现PROXY穿越(3):DES算法之一
实现PROXY穿越(2):Base64算法
实现PROXY穿越(1):流程和NTLM算法
例子程序。里面涉及很多算法,在网上查了很久。(下面是以前的博客)最近想实现一个通过PROXY穿越的网络编程,将相关的内容进行一下汇总。很多东西来
自网络共产主义,也应该为共产主义有所回馈。介绍NTLMv1 response的实现 。
经过了前面的准备,可以进入计算NTLM的响应。NTLM响应分为NTLM v1,NTLMv2,NTLM session
v2三种。具体使用哪种进行,由客户端和proxy进行协商确定,在讨论client和proxy的交互过程中,我们需能计算不同的response。
服务器(Proxy)提供一个8-byte的challenge. 客户端用于进行LM response和NT
response的计算,服务器自己也根据密码进行计算,校验和Client送过来的数值。LM and NT
responses都是24bytes。
对于NTLM Response,也就是我们常说的NTLMv1的方式,可以表述如下:
服务器发送一个8字节的随机数作为challenge。
客户端返回48字节的response。下面描述NTLMv1的步骤:
步骤一:获取挑战值
从服务器中获取8字节的challenge:
C = 8-byte server challenge,
random
步骤二:计算LM-HASH
根据用户密码计算LM-HASH,获得16字节的hash值,在后面加上5个空字节,总共21个字节,将21字节平均分割为三个7字节,然后进行DES计算:
K1 | K2 | K3 = LM-Hash | 5-bytes-0
R1 = DES(K1,C) | DES(K2,C) | DES(K3,C)
步骤三:计算NT-HASH
根据用户密码计算NT-HASH,获得16字节的hash值,在后面加上5个空字节,总共21个字节,将21字节平均分割为三个7字节,然后进行DES计算:
K1 | K2 | K3 = NT-Hash | 5-bytes-0
R2 = DES(K1,C) | DES(K2,C) | DES(K3,C)
步骤四:获取NTLMv1 response
response = R1 | R2
我们在DES的算法中,key的输入是64比特,将这8个字节分别去掉CRC校验位(第8位),生成56比特的key。现在我们直接输入为56字节比
特,可以通过LM-Hash中介绍的使用str_to_key函数,将这56比特的key变为64比特的key作为DES算法的输入,或者我们直接在
DES算法中增加一个函数用于处理直接56比特key的输入。如下:
static int ip_56key_seq[] ={
50,43,36,29,22,15,8,
1,
51,44,37,30,23,16,
9, 2,
52,45,38,31,24,
17,10,3,
53,46,39,32,
56,49,42,35,28,21,14,
7,
55,48,41,34,27,20,
13,
6,54,47,40,33,26,
19,12,5,
25,18,11,4};
void algorithm_des_56key(IN unsigned char * src, IN unsigned char *
secrect,
OUT unsigned char * dst){
unsigned
char s[64],key[64],L[32],R[32],K[48],E[48];
int i =
0;
storebit(src,8,s);
storebit(secrect,8,key);
//step1: initial permutation src and
key
initail_permutation(s,ip_data_seq,64,s);
initail_permutation(key,ip_56key_seq,56,key);
//step2:16次计算
//获取原始的L0和R0
memcpy(L,s,32);
memcpy(R,s+32,32);
//进行16次计算
for(i = 0; i
< 16 ; i++){
//获取K
getkey(key,key_offset[i]);
initail_permutation(key,ip_key,48,K);
//F计算
initail_permutation(R,ip_e,48,E);
xorbit(E,K,48,E);
s_box_function(E,s1,E);
s_box_function(E + 6,s2,E + 4);
s_box_function(E + 12,s3,E + 8);
s_box_function(E + 18,s4,E + 12);
s_box_function(E + 24,s5,E + 16);
s_box_function(E + 30,s6,E + 20);
s_box_function(E + 36,s7,E + 24);
s_box_function(E + 42,s8,E + 28);
initail_permutation(E,ip_p,32,E);
xorbit(E,L,32,E);
memcpy(L,R,32);
memcpy(R,E,32);
}
memcpy(s,R,32);
memcpy(s+32,L,32);
initail_permutation(s,inverse_ip_p,64,s);
parsebit(s,dst,8);
}
下面,我们给出NTLM v1 reponse的程序:
void ntlmv1_response(IN char * passwd, IN int passwd_len,IN
unsigned char * chanllenge,
OUT unsigned char * dst, OUT int *
dst_len){
unsigned
char hash[21];
//K1 | K2 | K3 = LM-Hash | 5-bytes-0
//R1 = DES(K1,C) | DES(K2,C) | DES(K3,C)
lm_hash(passwd, hash,NULL);
memset(hash
+ 16,0,5);
algorithm_des_56key(chanllenge, hash,dst);
algorithm_des_56key(chanllenge, hash+7,dst+8);
algorithm_des_56key(chanllenge, hash+14,dst+16);
//K1 | K2 | K3 = NT-Hash | 5-bytes-0
//R2 = DES(K1,C) | DES(K2,C) | DES(K3,C)
nt_hash(passwd, 0,hash,NULL);
memset(hash
+ 16,0,5);
algorithm_des_56key(chanllenge,hash,dst+24);
algorithm_des_56key(chanllenge,hash+7,dst+32);
algorithm_des_56key(chanllenge,hash+14,dst+40);
if(dst_len
!= NULL)
* dst_len =
48;
}
NTLM
v1响应实际上是将LM响应和NT响应合并发送,这是最容易计算的。LM是用于最古老的客户端,是最原始的响应类型;NT响应,也叫做NTLM响应,用于基于NT的客户端,例如Windows
2000和XP。如果我们进行抓包,大部分Proxy穿越不使用NTLMv1这个古老的方式,当然如果自己编写的客户端使用这种方式,并成功和Proxy协商,穿越没有问题。
相关链接:我的网络通信相关文章
NTLM的实现:
实现PROXY穿越(16):NTLM的PROXY穿越
实现PROXY穿越(15):NTLM Session Security
实现PROXY穿越(14):NTLM type3 Message
实现PROXY穿越(13):NTLM type2 Message
实现PROXY穿越(12):NTLM type1 Message
实现PROXY穿越(11):NTLMv2 session response
实现PROXY穿越(10):NTLMv2 response
实现PROXY穿越(9):NTLMv1 response
实现PROXY穿越(8):NT-Hash的实现
实现PROXY穿越(7):MD4和MD5
实现PROXY穿越(6):LM-Hash的实现
实现PROXY穿越(5):DES算法之三
实现PROXY穿越(4):DES算法之二
实现PROXY穿越(3):DES算法之一
实现PROXY穿越(2):Base64算法
实现PROXY穿越(1):流程和NTLM算法
相关文章推荐
- 实现PROXY穿越(12):NTLM type1 Message
- 实现PROXY穿越(13):NTLM type2 Message
- 实现PROXY穿越(15):NTLM Session Security
- 实现PROXY穿越(10):NTLMv2 response
- 实现PROXY穿越(2):Base64算法
- 实现PROXY穿越(7):MD4和MD5
- 实现PROXY穿越(14):NTLM type3 Message
- NTLM的PROXY穿越
- 实现PROXY穿越(3):DES算法之一
- 实现PROXY穿越(8):NT-Hash的实现
- 实现PROXY穿越(4):DES算法之二
- 实现PROXY穿越(5):DES算法之三
- NTLM认证的proxy客户端的Java实现-NTLM_Proxy.java
- 实现PROXY穿越(1):流程和NTLM算法
- 实现PROXY穿越(6):LM-Hash的实现
- NTLM认证的proxy客户端的Java实现-NTLM.java
- 实现PROXY穿越(11):NTLMv2 session response