全网首一份!你最需要的PPTP MS-CHAP V2 挑战响应编程模拟计算教程!代码基于RFC2759,附全部源码!

本文基于网络密码课上的实验

本来想水一水就过去,代码就网上找找,不行就GPT写,但是!一份都找不到,找到的代码都是跑不了的,总会是就是乱七八糟。所以准备认真的写一份。

代码编译成功的前提是要预先装好openssl库!

本随笔主要有三个内容:

  1. 编写程序,模拟计算NTResponse、AuthenticatorResponse,
  2. 根据前期PPTP实验中捕获的数据包中CHAP协议的挑战响应认证数据,在未知用户口令情况下编程实现CHAP认证口令的破解

在单向数据条件下(仅能截获用户数据)实现CHAP认证口令的破解

首先放一个我自己抓的包,可以看到,这是chap协议挑战响应的三次握手,

那么我们继续进行,编程模拟,就要先搞清楚每个字段代表的什么,文档中第一个包的描述,给的是Authenticator challenge

也就是我住的第一个包里的value

这是第二个包,16字节peer-challenge,8位的0,24位的NT-Response

value内的值,对应看

第三个包,内容是s=authticator-response

接下来我们开始编程实现,每一个字段都是由对应的函数计算得出

一、编写程序,模拟计算NTResponse、AuthenticatorResponse

1.查阅RFC2759文档,找到描述的计算NTResponse的函数

复制代码
NT-Response的值是由GenerateNTResponse()计算得出,看到该函数有四个输入,分别是AuthenticatorChallenge(16)、PeerChallenge(16)、UserName和Password,一个输出Response(24)
复制代码
 
复制代码
此外,有三个函数对输入进行处理:ChallengeHash:对两个挑战值hash,结果放到challenge中。NtPasswordHash:对password做hash,结果放到password中。ChallengeResponse:对challenge和passwordhash做运算,结果得到NT-Response。

2.根据文档描述编写代码

GenerateNTResponse()函数

复制代码
1 void GenerateNTResponse(const HCRYPTPROV hProv, const BYTE* auth_challenge, const BYTE* peer_challenge, const char* user_name, const wchar_t* password, BYTE* response)
2 {
3     BYTE challenge[8];
4     BYTE password_hash[16];
5 
6     _ChallengeHash(hProv, peer_challenge, auth_challenge, user_name, challenge);
7     _NtPasswordHash(hProv, password, password_hash);
8     _ChallengeResponse(hProv, challenge, password_hash, response);
9 }

_ChallengeHash()函数,对peer challenge、auth challenge、user name连接然后进行sha1哈希,结果放到challenge中返回

复制代码
 1 void _ChallengeHash(const HCRYPTPROV hProv, const BYTE* peer_challenge, const BYTE* auth_challenge, const char* user_name, BYTE* challenge)
 2 {
 3     HCRYPTHASH hHash = 0;
 4     if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
 5         throw "CryptCreateHash failed (SHA1)";
 6     if (!CryptHashData(hHash, peer_challenge, 16, 0))
 7         throw "CryptHashData failed (peer challenge)";
 8     if (!CryptHashData(hHash, auth_challenge, 16, 0))
 9         throw "CryptHashData failed (auth challenge)";
10     if (!CryptHashData(hHash, (const BYTE*)user_name,
11         (DWORD)strlen(user_name), 0))
12         throw "CryptHashData failed (user name)";
13     DWORD hash_len = SHA1LEN;
14     BYTE hash_buffer[SHA1LEN];
15     if (!CryptGetHashParam(hHash, HP_HASHVAL, hash_buffer,
16         &hash_len, 0))
17         throw "CryptGetHashParam failed (challenge hash)";
18     memcpy(challenge, hash_buffer, 8);
19 
20 }

_NtPasswordHash函数():将password做MD4哈希,然后返回password_hash中

复制代码
 1 void _NtPasswordHash(const HCRYPTPROV hProv, const wchar_t* password, BYTE* password_hash)
 2 {
 3     HCRYPTHASH hHash = 0;
 4     if (!CryptCreateHash(hProv, CALG_MD4, 0, 0, &hHash))
 5         throw "CryptCreateHash failed (MD4)";
 6     if (!CryptHashData(hHash, (const BYTE*)password, lstrlenW(password) << 1, 0))
 7         throw "CryptHashData failed (user password)";
 8     DWORD hash_len = MD4LEN;
 9     BYTE hash_buffer[MD4LEN];
10     if (!CryptGetHashParam(hHash, HP_HASHVAL, hash_buffer, &hash_len, 0))
11         throw "CryptGetHashParam failed (NT password hash)";
12     memcpy(password_hash, hash_buffer, 16);
13 }

ChallengeResponse()函数:首先将16位passwordhash后面填充五个0变成21位,接着分成三个长度为7的密钥,分别对challenge做三次DES加密,三次加密结果放到response中

复制代码
 1 void _ChallengeResponse(const HCRYPTPROV hProv, const BYTE* challenge, const BYTE* password_hash, BYTE* response)
 2 {
 3     BYTE z_password_hash[21];
 4     memset(z_password_hash, 0, 21);
 5     memcpy(z_password_hash, password_hash, 16);
 6 
 7     _DesEncrypt(hProv, challenge, z_password_hash, response);
 8     _DesEncrypt(hProv, challenge, z_password_hash + 7, response + 8);
 9     _DesEncrypt(hProv, challenge, z_password_hash + 14, response + 16);
10 }

接下来我们来看DES加密函数,由于每次给的密钥都是7位长度,所以加密前首先调用EXPAND()函数对密钥进行扩展,扩展到8位,这里的加密模式是ECB(电子密码本)加密,加密的结果放到result中

复制代码
 1 typedef struct {
 2     BLOBHEADER key_header;
 3     DWORD key_length;
 4     BYTE key_data[8];
 5 } DESKey;
 6 
 7 void EXPAND(BYTE* key);
 8 
 9 void _DesEncrypt(const HCRYPTPROV hProv, const BYTE* data, const BYTE* key, BYTE* result)
10 {
11     // Fill CryptoAPI-required key structure
12     DESKey des_key;
13     des_key.key_header.bType = PLAINTEXTKEYBLOB;
14     des_key.key_header.bVersion = CUR_BLOB_VERSION;
15     des_key.key_header.reserved = 0;
16     des_key.key_header.aiKeyAlg = CALG_DES;
17     des_key.key_length = 8;
18     memcpy(des_key.key_data, key, 7);
19     EXPAND(des_key.key_data);
20 
21     HCRYPTKEY hKey;
22     // import key BLOB
23     if (!CryptImportKey(hProv, (BYTE*)&des_key,
24         sizeof(des_key), 0, 0, &hKey))
25         throw "CryptImportKey failed";
26     // set ECB mode required by RFC
27     DWORD des_mode = CRYPT_MODE_ECB;
28     if (!CryptSetKeyParam(hKey, KP_MODE, (BYTE*)&des_mode, 0))
29         throw "CryptSetKeyParam failed (ECB mode)";
30     // set initialization vector
31     BYTE IV[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
32     if (!CryptSetKeyParam(hKey, KP_IV, &IV[0], 0))
33         throw "CryptSetKeyParam failed (init vector)";
34     // encrypt
35     DWORD data_len = 8;
36     memcpy(result, data, 8);    // encrypt in-place
37     if (!CryptEncrypt(hKey, 0, FALSE, 0, (BYTE*)&result[0], &data_len, 8))
38         throw "CryptEncrypt failed (DES)";
39 }
40 

下面来看一下密钥扩展函数,该函数的具体流程如下:

  1. 创建了一个名为new_key的字节数组,用于存储扩展后的密钥。

  2. 接下来,使用一个循环来处理每个7位的数据包。循环从0到7迭代,共8次。

  3. 在每次迭代中,根据当前的索引值i,获取原始密钥中的两个相邻的八位字节。如果i大于0,则取索引为i-1的字节作为左字节;否则,取索引为0的字节作为左字节。右字节的获取方式类似,如果i小于7,则取索引为i的字节作为右字节;否则,取索引为6的字节作为右字节。

  4. 接着,通过位运算将左字节和右字节中的位进行清除,只保留当前7位的数据。左字节通过与操作符&和右移操作符>>实现,右字节通过与操作符&和左移操作符<<实现。

  5. 然后,将左字节和右字节进行位移操作,将它们移动到最终的位置。左字节通过左移操作符<<实现,右字节通过右移操作符>>实现。

  6. 最后,将左字节和右字节进行按位或操作,得到最终的八位字节,并将其存储在new_key数组中对应的位置。

    复制代码
     1 void EXPAND(BYTE* key)
     2 {
     3     BYTE left_octet, right_octet;
     4     BYTE new_key[8];
     5     // split original key into eight 7-bit packs:
     6     // 00000001 11111122 22222333 3333444 44455555 55666666 67777777
     7     for (int i = 0; i < 8; i++)
     8     {
     9         // fetch two adjacent octets of key containing current 7 bits
    10         left_octet = key[i > 0 ? i - 1 : 0];
    11         right_octet = key[i < 7 ? i : 6];
    12         // clear all bits except current 7 ones
    13         left_octet &= 0xFF >> (8 - i);
    14         right_octet &= 0xFF << (i + 1);
    15         // shift bits to their final position
    16         left_octet = left_octet << (8 - i);
    17         right_octet = right_octet >> i;
    18         // combine into resulting octet
    19         new_key[i] = left_octet | right_octet;
    20     }
    21     memcpy(key, new_key, 8);
    22 }

    至此,我们就算出来了NtResponse

    2.计算AunthenticatorResponse

    复制代码
    首先查看文档,得知输入有Password、NT-Response、PeerChallenge、AuthenticatorChallenge、UserName
    复制代码
    输出AuthenticatorResponse。该函数处理流程如下:
    1. 该函数里面定义了长度16的PasswordHash和PasswordHashHash,长度为8的Challenge。首先,使用MD4算法对密码进行哈希处理,得到PasswordHash。
    2. 然后,对PasswordHash进行再次哈希处理,得到PasswordHashHash。
    3. 接着,使用SHA算法对PasswordHashHash、NT-Response和Magic1进行哈希处理,得到Digest。
    4. 使用ChallengeHash函数对PeerChallenge、AuthenticatorChallenge和UserName进行哈希处理,得到Challenge。
    5. 再次使用SHA算法对Digest、Challenge和Magic2进行哈希处理,得到最终的Digest

    下面是具体实现代码

复制代码
 1 void GenerateAuthenticatorResponse(const HCRYPTPROV hProv, const wchar_t* password_unicode, const BYTE* NTResponse, const BYTE* PeerChalleng, const BYTE* AuthenticatorChallenge, const char* UserName)
 2 {
 3     BYTE Magic1[39] = { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
 4     0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
 5     0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
 6     0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
 7     BYTE Magic2[41] = { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
 8     0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
 9     0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
10     0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
11     0x6E };
12     BYTE Passwordhash[16];
13     _NtPasswordHash(hProv, password_unicode, Passwordhash);
14     BYTE PasswordHashhash[16];
15     _NtPasswordHashHash(hProv, Passwordhash, PasswordHashhash);
16     SHA_CTX Context;
17     SHA1_Init(&Context);
18     SHA1_Update(&Context, PasswordHashhash, 16);
19     SHA1_Update(&Context, NTResponse, 24);
20     SHA1_Update(&Context, Magic1, 39);
21     unsigned char aa[SHA_DIGEST_LENGTH];
22     SHA1_Final(aa, &Context);
23     BYTE Challenge[8];
24     _ChallengeHash(hProv, PeerChalleng, AuthenticatorChallenge, UserName, Challenge);
25     SHA1_Init(&Context);
26     SHA1_Update(&Context, aa, sizeof(aa));
27     SHA1_Update(&Context, Challenge, 8);
28     SHA1_Update(&Context, Magic2, 41);
29     unsigned char bb[SHA_DIGEST_LENGTH];
30     SHA1_Final(bb, &Context);
31     cout << endl << "AuthenticatorResponse: s=";
32     for (int i = 0; i < 20; i++)
33     {
34         printf("%02X", (unsigned char)bb[i]);
35     }
36 }

3.运行程序,将结果和wireshark抓包内容进行比对

NT-Response:DA2191E86678231E62B5D628CBA859031B1E6082533B32B5

AuthenticatorResponse: s=2AA71CBBDD95F43ABA628329A0271A8DD1114310

全部代码如下:注意展开

复制代码
  1 #pragma comment(lib, "libssl.lib")
  2 #pragma comment(lib, "libcrypto.lib")
  3 #include <stdio.h>
  4 #include <fstream>
  5 #include <tchar.h>
  6 #include <windows.h>
  7 #include <WinCrypt.h>
  8 #include <openssl/sha.h>
  9 #include<string>
 10 #include<iostream>
 11 #include <openssl/des.h>
 12 using namespace std;
 13 
 14 void print_array(const BYTE* array, DWORD length);
 15 void GenerateNTResponse(const HCRYPTPROV hProv, const BYTE* auth_challenge, const BYTE* peer_challenge, const char* user_name, const wchar_t* password, BYTE* response);
 16 void GenerateAuthenticatorResponse(const HCRYPTPROV hProv, const wchar_t* password_unicode, const BYTE* NTResponse, const BYTE* PeerChalleng, const BYTE* AuthenticatorChallenge, const char* UserName);
 17 void Challenge1(const HCRYPTPROV hProv, const BYTE* auth_challenge, const BYTE* peer_challenge, const char* user_name, BYTE* response);
 18 void _NtPasswordHash(const HCRYPTPROV hProv, const wchar_t* password, BYTE* password_hash);
 19 BYTE nt_response[24];
 20 int main()
 21 {
 22     const char* user_name = "WA_042";
 23     const wchar_t* password = L"123456";
 24     const BYTE auth_challenge[] = { 0x11,0xD8,0x2A,0x82,0x0F,
 25                                    0xBE,0xB0,0x30,0x73,0xB1,0xF7,
 26                                    0x03,0x73,0x22,0x26,0xBF };
 27     const BYTE peer_challenge[] = { 0xC1,0xD4,0x43,0x9D,0xBD,0x65,
 28                                    0xA2,0x74,0xB9,0x7A,0xF0,0x3F,
 29                                    0x98,0x00,0x6D,0x75 };
 30     HCRYPTPROV hProv = 0;
 31 
 32     CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
 33     //wcout << password;
 34     printf("User name: %s\n", user_name);
 35     wprintf(L"User password: %s\n", password);
 36     printf("Authenticator challenge: ");
 37     print_array(auth_challenge, 16);
 38     printf("\n");
 39     printf("Peer challenge: "); print_array(peer_challenge, 16);
 40     printf("\n");
 41     GenerateNTResponse(hProv, auth_challenge, peer_challenge, user_name, password, nt_response);
 42     printf("NT Response: "); print_array(nt_response, 24);
 43     GenerateAuthenticatorResponse(hProv, password, nt_response, peer_challenge, auth_challenge, user_name);
 44     cout << endl;
 45     Challenge1(hProv, auth_challenge, peer_challenge, user_name, nt_response);
 46     cout << endl << "挑战一结束";
 47     return 0;
 48 }
 49 
 50 void Challenge1(const HCRYPTPROV hProv, const BYTE* auth_challenge, const BYTE* peer_challenge, const char* user_name, BYTE* response)
 51 {
 52     std::ifstream file("passlib.txt");
 53     if (!file) {
 54         std::cerr << "无法打开文件" << std::endl;
 55     }
 56 
 57     string line;
 58     while (std::getline(file, line)) {
 59         BYTE Nt_response[24];
 60         wchar_t* wc = new wchar_t[line.size()];
 61         swprintf(wc, 100, L"%S", line.c_str());
 62         // wcout << wc << endl;
 63         GenerateNTResponse(hProv, auth_challenge, peer_challenge, user_name, wc, Nt_response);
 64         //cout << Nt_response << endl;
 65         for (int i = 0; i < 24; i++)
 66         {
 67 
 68             if (Nt_response[i] != nt_response[i])
 69             {
 70                 cout << "破解失败" << endl;
 71                 break;
 72             }
 73             else
 74             {
 75                 cout << "破解成功!密码为:";
 76                 wcout << wc << endl;
 77                 break;
 78             }
 79             // 处理读取到的数据
 80         }
 81     }
 82 
 83     file.close();
 84 
 85 
 86 }
 87 void _DesDecrypt(unsigned char* NTResponse, unsigned char* key, unsigned char* decrypted_result);
 88 
 89 const CHAR hex_digits[] = "0123456789ABCDEF";
 90 
 91 void print_array(const BYTE* array, DWORD length)
 92 {
 93     printf("0x");
 94     for (DWORD i = 0; i < length; i++)
 95         printf("%c%c", hex_digits[array[i] >> 4],
 96             hex_digits[array[i] & 0xf]);
 97 }
 98 
 99 
100 void _ChallengeHash(const HCRYPTPROV hProv, const BYTE* peer_challenge, const BYTE* auth_challenge, const char* user_name, BYTE* challenge);
101 void _NtPasswordHash(const HCRYPTPROV hProv, const wchar_t* password, BYTE* password_hash);
102 void _ChallengeResponse(const HCRYPTPROV hProv, const BYTE* challenge, const BYTE* password_hash, BYTE* response);
103 void _NtPasswordHashHash(const HCRYPTPROV hProv, BYTE* password, BYTE* password_hash);
104 void GenerateNTResponse(const HCRYPTPROV hProv, const BYTE* auth_challenge, const BYTE* peer_challenge, const char* user_name, const wchar_t* password, BYTE* response)
105 {
106     BYTE challenge[8];
107     BYTE password_hash[16];
108 
109     _ChallengeHash(hProv, peer_challenge, auth_challenge, user_name, challenge);
110     _NtPasswordHash(hProv, password, password_hash);
111     _ChallengeResponse(hProv, challenge, password_hash, response);
112 }
113 void GenerateAuthenticatorResponse(const HCRYPTPROV hProv, const wchar_t* password_unicode, const BYTE* NTResponse, const BYTE* PeerChalleng, const BYTE* AuthenticatorChallenge, const char* UserName)
114 {
115     BYTE Magic1[39] = { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
116     0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
117     0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
118     0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
119     BYTE Magic2[41] = { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
120     0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
121     0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
122     0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
123     0x6E };
124     BYTE Passwordhash[16];
125     _NtPasswordHash(hProv, password_unicode, Passwordhash);
126     BYTE PasswordHashhash[16];
127     _NtPasswordHashHash(hProv, Passwordhash, PasswordHashhash);
128     SHA_CTX Context;
129     SHA1_Init(&Context);
130     SHA1_Update(&Context, PasswordHashhash, 16);
131     SHA1_Update(&Context, NTResponse, 24);
132     SHA1_Update(&Context, Magic1, 39);
133     unsigned char aa[SHA_DIGEST_LENGTH];
134     SHA1_Final(aa, &Context);
135     BYTE Challenge[8];
136     _ChallengeHash(hProv, PeerChalleng, AuthenticatorChallenge, UserName, Challenge);
137     SHA1_Init(&Context);
138     SHA1_Update(&Context, aa, sizeof(aa));
139     SHA1_Update(&Context, Challenge, 8);
140     SHA1_Update(&Context, Magic2, 41);
141     unsigned char bb[SHA_DIGEST_LENGTH];
142     SHA1_Final(bb, &Context);
143     cout << endl << "AuthenticatorResponse: s=";
144     for (int i = 0; i < 20; i++)
145     {
146         printf("%02X", (unsigned char)bb[i]);
147     }
148 }
149 #define SHA1LEN 20
150 
151 void _ChallengeHash(const HCRYPTPROV hProv, const BYTE* peer_challenge, const BYTE* auth_challenge, const char* user_name, BYTE* challenge)
152 {
153     HCRYPTHASH hHash = 0;
154     if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
155         throw "CryptCreateHash failed (SHA1)";
156     if (!CryptHashData(hHash, peer_challenge, 16, 0))
157         throw "CryptHashData failed (peer challenge)";
158     if (!CryptHashData(hHash, auth_challenge, 16, 0))
159         throw "CryptHashData failed (auth challenge)";
160     if (!CryptHashData(hHash, (const BYTE*)user_name,
161         (DWORD)strlen(user_name), 0))
162         throw "CryptHashData failed (user name)";
163     DWORD hash_len = SHA1LEN;
164     BYTE hash_buffer[SHA1LEN];
165     if (!CryptGetHashParam(hHash, HP_HASHVAL, hash_buffer,
166         &hash_len, 0))
167         throw "CryptGetHashParam failed (challenge hash)";
168     memcpy(challenge, hash_buffer, 8);
169 
170 }
171 
172 
173 #define MD4LEN 16
174 
175 void _NtPasswordHash(const HCRYPTPROV hProv, const wchar_t* password, BYTE* password_hash)
176 {
177     HCRYPTHASH hHash = 0;
178     if (!CryptCreateHash(hProv, CALG_MD4, 0, 0, &hHash))
179         throw "CryptCreateHash failed (MD4)";
180     if (!CryptHashData(hHash, (const BYTE*)password, lstrlenW(password) << 1, 0))
181         throw "CryptHashData failed (user password)";
182     DWORD hash_len = MD4LEN;
183     BYTE hash_buffer[MD4LEN];
184     if (!CryptGetHashParam(hHash, HP_HASHVAL, hash_buffer, &hash_len, 0))
185         throw "CryptGetHashParam failed (NT password hash)";
186     memcpy(password_hash, hash_buffer, 16);
187 }
188 void _NtPasswordHashHash(const HCRYPTPROV hProv, BYTE* passwordhash, BYTE* password_hashhash)
189 {
190     HCRYPTHASH hHashhash = 0;
191     if (!CryptCreateHash(hProv, CALG_MD4, 0, 0, &hHashhash))
192         throw "CryptCreateHash failed (MD4)";
193     if (!CryptHashData(hHashhash, passwordhash, 16, 0))
194         throw "CryptHashData failed (user password)";
195     DWORD hash_len = MD4LEN;
196     BYTE hash_buffer[MD4LEN];
197     if (!CryptGetHashParam(hHashhash, HP_HASHVAL, hash_buffer, &hash_len, 0))
198         throw "CryptGetHashParam failed (NT password hash)";
199 
200     memcpy(password_hashhash, hash_buffer, 16);
201     //cout << endl; print_array(password_hashhash, 16);
202 }
203 
204 void _DesEncrypt(const HCRYPTPROV hProv, const BYTE* data, const BYTE* key, BYTE* result);
205 void _ChallengeResponse(const HCRYPTPROV hProv, const BYTE* challenge, const BYTE* password_hash, BYTE* response)
206 {
207     BYTE z_password_hash[21];
208     memset(z_password_hash, 0, 21);
209     memcpy(z_password_hash, password_hash, 16);
210 
211     _DesEncrypt(hProv, challenge, z_password_hash, response);
212     _DesEncrypt(hProv, challenge, z_password_hash + 7, response + 8);
213     _DesEncrypt(hProv, challenge, z_password_hash + 14, response + 16);
214 }
215 typedef struct {
216     BLOBHEADER key_header;
217     DWORD key_length;
218     BYTE key_data[8];
219 } DESKey;
220 
221 void EXPAND(BYTE* key);
222 
223 void _DesEncrypt(const HCRYPTPROV hProv, const BYTE* data, const BYTE* key, BYTE* result)
224 {
225     // Fill CryptoAPI-required key structure
226     DESKey des_key;
227     des_key.key_header.bType = PLAINTEXTKEYBLOB;
228     des_key.key_header.bVersion = CUR_BLOB_VERSION;
229     des_key.key_header.reserved = 0;
230     des_key.key_header.aiKeyAlg = CALG_DES;
231     des_key.key_length = 8;
232     memcpy(des_key.key_data, key, 7);
233     EXPAND(des_key.key_data);
234 
235     HCRYPTKEY hKey;
236     // import key BLOB
237     if (!CryptImportKey(hProv, (BYTE*)&des_key,
238         sizeof(des_key), 0, 0, &hKey))
239         throw "CryptImportKey failed";
240     // set ECB mode required by RFC
241     DWORD des_mode = CRYPT_MODE_ECB;
242     if (!CryptSetKeyParam(hKey, KP_MODE, (BYTE*)&des_mode, 0))
243         throw "CryptSetKeyParam failed (ECB mode)";
244     // set initialization vector
245     BYTE IV[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
246     if (!CryptSetKeyParam(hKey, KP_IV, &IV[0], 0))
247         throw "CryptSetKeyParam failed (init vector)";
248     // encrypt
249     DWORD data_len = 8;
250     memcpy(result, data, 8);    // encrypt in-place
251     if (!CryptEncrypt(hKey, 0, FALSE, 0, (BYTE*)&result[0], &data_len, 8))
252         throw "CryptEncrypt failed (DES)";
253 }
254 
255 void EXPAND(BYTE* key)
256 {
257     BYTE left_octet, right_octet;
258     BYTE new_key[8];
259     // split original key into eight 7-bit packs:
260     // 00000001 11111122 22222333 3333444 44455555 55666666 67777777
261     for (int i = 0; i < 8; i++)
262     {
263         // fetch two adjacent octets of key containing current 7 bits
264         left_octet = key[i > 0 ? i - 1 : 0];
265         right_octet = key[i < 7 ? i : 6];
266         // clear all bits except current 7 ones
267         left_octet &= 0xFF >> (8 - i);
268         right_octet &= 0xFF << (i + 1);
269         // shift bits to their final position
270         left_octet = left_octet << (8 - i);
271         right_octet = right_octet >> i;
272         // combine into resulting octet
273         new_key[i] = left_octet | right_octet;
274     }
275     memcpy(key, new_key, 8);
276 }

View Code

二、根据前期PPTP实验中捕获的数据包中CHAP协议的挑战响应认证数据,在未知用户口令情况下编程实现CHAP认证口令的破解

思路:编写一个challenge1()函数,创建一个自己的字典,使用字典进行爆破,每次读入字典中的一个密码文本,然后调用GenerateNTResponse()函数计算NT-Response,与正确的进行比对,如果成功,则输出密码

1.编写challenge1()函数

复制代码
 1 void Challenge1(const HCRYPTPROV hProv, const BYTE* auth_challenge, const BYTE* peer_challenge, const char* user_name, BYTE* response)
 2 {
 3     std::ifstream file("passlib.txt");
 4     if (!file) {
 5         std::cerr << "无法打开文件" << std::endl;
 6     }
 7 
 8     string line;
 9     while (std::getline(file, line)) {
10         BYTE Nt_response[24];
11         wchar_t* wc = new wchar_t[line.size()];
12         swprintf(wc, 100, L"%S", line.c_str());
13         // wcout << wc << endl;
14         GenerateNTResponse(hProv, auth_challenge, peer_challenge, user_name, wc, Nt_response);
15         //cout << Nt_response << endl;
16         for (int i = 0; i < 24; i++)
17         {
18 
19             if (Nt_response[i] != nt_response[i])
20             {
21                 cout << "破解失败" << endl;
22                 break;
23             }
24             else
25             {
26                 cout << "破解成功!密码为:";
27                 wcout << wc << endl;
28                 break;
29             }
30             // 处理读取到的数据
31         }
32     }
33 
34     file.close();
35 
36 
37 }

运行字典爆破

三、在单向数据条件下(仅能截获用户数据)实现CHAP认证口令的破解

思路:单向数据条件下,意味着只能获取用户数据NT-Response、PeerChallenge、UserName。那么根据NtResponse的计算原理,采用逆向破解的思路。首先:由于NtResponse是由passwordhash分成三部分作密钥对challenge加密的密文连接得到,那么先将NtResponse拆分成三部分,对应每部分passwordhash对challenge做DES加密的结果。

因此,破解思路是,每次读入字典里的密钥做hash作为密钥,然后将NtResponse三个部分分别作为DES函数的输入,记录DES函数的输出,比较三个输出是否相同,如果相同,则破解成功。

注意,我能运行成功是因为我的目录里面有passlib.txt字典文件,大家可以创建自己的字典文件

1.编写代码

源码如下,注意,已经折叠,点击展开

复制代码
  1 #define _CRT_SECURE_NO_WARNINGS C4996
  2 #include <iostream>
  3 #include <stdio.h>
  4 #include <openssl/ssl.h>
  5 #include <stdlib.h>
  6 #include <string.h>
  7 #include <openssl/sha.h>
  8 #include <openssl/md4.h>
  9 #include <openssl/des.h>
 10 
 11 int  readfile(char* pass[]) {
 12     FILE* file = fopen("./passlib.txt", "r");
 13     if (file == NULL) {
 14         perror("Error opening file");
 15         return 0;
 16     }
 17 
 18     char buffer[100];
 19     int count = 0;
 20 
 21     while (fgets(buffer, sizeof(buffer), file) != NULL) {
 22         buffer[strcspn(buffer, "\n")] = 0;
 23         pass[count] = _strdup(buffer);
 24         count++;
 25     }
 26 
 27     fclose(file);
 28 
 29 
 30     return count;
 31 }
 32 
 33 void des_decrypt(unsigned char* key, unsigned char* NTResponse, unsigned char* decrypted_result) {
 34     DES_cblock des_key;
 35     memcpy(des_key, key, 8);
 36     DES_key_schedule key_schedule;
 37     DES_set_key_unchecked(&des_key, &key_schedule);
 38     DES_ecb_encrypt((DES_cblock*)NTResponse, (DES_cblock*)decrypted_result, &key_schedule, DES_DECRYPT);
 39 }
 40 void expand(unsigned char* t, unsigned char* k)
 41 {
 42     k[0] = t[0] & 0xfe;
 43     k[1] = (t[0] << 7 | t[1] >> 1) & 0xfe;
 44     k[2] = (t[1] << 6 | t[2] >> 2) & 0xfe;
 45     k[3] = (t[2] << 5 | t[3] >> 3) & 0xfe;
 46     k[4] = (t[3] << 4 | t[4] >> 4) & 0xfe;
 47     k[5] = (t[4] << 3 | t[5] >> 5) & 0xfe;
 48     k[6] = (t[5] << 2 | t[6] >> 6) & 0xfe;
 49     k[7] = (t[6] << 1) & 0xfe;
 50 }
 51 int main()
 52 {
 53     unsigned char peer_challenge[17] = { 0xC1,0xD4,0x43,0x9D,0xBD,0x65,0xA2,0x74,0xB9,0x7A,0xF0,0x3F,0x98,0x00,0x6D,0x75 ,'\0' };
 54     char username[7] = { 0x77,0x61,0x5f,0x30,0x34,0x32,'\0' };
 55     unsigned char challenge[8] = { 0x00 };
 56     unsigned char NTResponse[25] = { 0xDA ,0x21,0x91 ,0xE8 ,0x66 ,0x78 ,0x23 ,0x1E ,0x62 ,0xB5
 57         ,0xD6 ,0x28 ,0xCB ,0xA8 ,0x59 ,0x03 ,0x1B ,0x1E ,0x60 ,0x82 ,0x53 ,0x3B ,0x32 ,0xB5,'\0' };
 58 
 59     const char* pass[100];
 60     int loop = readfile((char**)pass);
 61     int has_found = 0;
 62 
 63     unsigned char response1[9] = { 0x00 };
 64     unsigned char response2[9] = { 0x00 };
 65     unsigned char response3[9] = { 0x00 };
 66 
 67     strncat((char*)response1, (char*)NTResponse, 8);
 68     response1[8] = '\0';
 69     strncat((char*)response2, (char*)NTResponse + 8, 8);
 70     response2[8] = '\0';
 71     strncat((char*)response3, (char*)NTResponse + 16, 8);
 72     response3[8] = '\0';
 73     printf("read the password in pass.txt:\n");
 74     for (int i = 0; i < loop; i++) {
 75         printf("%s\n", pass[i]);
 76     }
 77 
 78     for (int j = 0; j < loop; j++)
 79     {
 80 
 81         unsigned char password_hash[21] = { 0x00 };
 82         unsigned char password[10] = { 0x00 };
 83         strncpy((char*)password, pass[j], strlen(pass[j]));
 84 
 85         password[strlen(pass[j])] = '\0';
 86 
 87         int pass_len = strlen((char*)password);
 88 
 89         unsigned char* unicode_password;
 90         unicode_password = (unsigned char*)malloc(sizeof(unsigned char) * pass_len * 2);
 91         for (int i = 0; i < pass_len; i++) {
 92             unicode_password[i * 2] = password[i];
 93             unicode_password[i * 2 + 1] = 0;
 94         }
 95 
 96         MD4((unsigned char*)unicode_password, pass_len * sizeof(unsigned short), password_hash);
 97 
 98         char zero[5] = { 0x00,0x00,0x00,0x00,0x00 };
 99 
100         strncat((char*)password_hash, zero, 5);
101 
102         unsigned char ks1[9] = { 0x00 };
103         unsigned char ks2[9] = { 0x00 };
104         unsigned char ks3[9] = { 0x00 };
105 
106         unsigned char pass1[8] = { 0x00 };
107         unsigned char pass2[8] = { 0x00 };
108         unsigned char pass3[8] = { 0x00 };
109 
110         for (int i = 0; i < 7; i++)
111         {
112             pass1[i] = password_hash[i];
113         }
114         for (int i = 0; i < 7; i++)
115         {
116             pass2[i] = password_hash[i + 7];
117         }
118         for (int i = 0; i < 7; i++)
119         {
120             pass3[i] = password_hash[i + 14];
121         }
122 
123         expand(pass1, ks1);
124 
125         expand(pass2, ks2);
126 
127         expand(pass3, ks3);
128 
129 
130         unsigned char result1[32] = { 0x00 };
131         unsigned char result2[32] = { 0x00 };
132         unsigned char result3[32] = { 0x00 };
133 
134         des_decrypt(ks1, response1, result1);
135         des_decrypt(ks2, response2, result2);
136         des_decrypt(ks3, response3, result3);
137 
138         if (strcmp((char*)result1, (char*)result2) == 0)
139         {
140             if (strcmp((char*)result1, (char*)result3) == 0)
141             {
142                 printf("\n");
143                 printf("Find! The password is:%s", pass[j]);
144                 has_found = 1;
145                 break;
146             }
147         }
148 
149     }
150     for (int i = 0; i < loop; i++) {
151         free((void*)pass[i]);
152     }
153 
154     if (has_found == 0)
155         printf("Cannot Find the password");
156 }

单向数据源码

2.运行代码

至此,实验结束

顺便附上python源码,欢迎批评指正!

复制代码
  1 # coding = utf-8
  2 import binascii
  3 from builtins import bytes
  4 
  5 from Crypto.Hash import SHA1,SHA,MD4
  6 from Crypto.Cipher import DES,ARC4
  7 
  8 def GenerateNTResponse(AuthenticatorChallenge,PeerChalleng,UserName,password_unicode):
  9     PasswordHash=Nt_password_hash(password_unicode)
 10     #print_hex(PasswordHash)
 11     Challenge=ChallengeHash(PeerChalleng,AuthenticatorChallenge,UserName)
 12     challenge_resposn=ChallengeResponse(PasswordHash,Challenge)
 13     return challenge_resposn
 14 
 15 def ChallengeHash(PeerChalleng,AuthenticatorChallenge,UserName):
 16     Challenge=SHA1.new()
 17     Challenge.update(PeerChalleng)
 18     Challenge.update(AuthenticatorChallenge)
 19     Challenge.update(UserName)
 20     return Challenge.digest()[:8]
 21 def Expand(rawkey):  #expand 7Bytes to 8 Bytes
 22     tmp_key = []
 23     for i in rawkey[:7]:
 24         tmp_key.append(i)
 25     key = []
 26     for i in range(8):
 27         key.append(b'\x00')
 28     # -------------------------
 29     key[0] = tmp_key[0]
 30     for i in range(1, 7):
 31         key[i] = ((tmp_key[i - 1] << (8 - i)) & 0xff) | (tmp_key[i] >> i)
 32     key[7] =  (tmp_key[6] << 1) & 0xff
 33     global b
 34     for i in range(len(key)):
 35         b = 1
 36         for j in range(1, 8):
 37             t = (key[i] >> j)
 38             b = (t ^ b) & 0x1 #
 39         key[i] = (key[i] & 0xfe) | b
 40     ans = b''
 41     for i in range(8):
 42         ans += bytes([key[i]])
 43     return ans
 44 def ChallengeResponse(PasswordHash,Challenge):
 45     zero = b'\x00'
 46     while(len(PasswordHash) < 21): # important
 47         PasswordHash += zero #zero-padded to 21 octets
 48     res = DES.new(Expand(PasswordHash[0:7]), DES.MODE_ECB).encrypt(Challenge)
 49     res += DES.new(Expand(PasswordHash[7:14]), DES.MODE_ECB).encrypt(Challenge)
 50     res += DES.new(Expand(PasswordHash[14:21]), DES.MODE_ECB).encrypt(Challenge)
 51     return res
 52 
 53 def Nt_password_hash(Password):
 54     PasswordHash=MD4.new(Password)
 55     return PasswordHash.digest()
 56 
 57 def Nt_password_hashhash(Passwordhash):
 58     PasswordHashhash=MD4.new(Passwordhash)
 59     return PasswordHashhash.digest()
 60 
 61 def GenerateAuthenticatorResponse(password_unicode,NTResponse,PeerChalleng,AuthenticatorChallenge,UserName):
 62     Magic1 =b'\x4D\x61\x67\x69\x63\x20\x73\x65\x72\x76\x65\x72\x20\x74\x6F\x20\x63\x6C\x69\x65\x6E\x74\x20\x73\x69\x67\x6E\x69\x6E\x67\x20\x63\x6F\x6E\x73\x74\x61\x6E\x74'
 63     Magic2 = bytes([0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,0x6E])
 64     Passwordhash=Nt_password_hash(password_unicode)
 65     PasswordHashhash=Nt_password_hashhash(Passwordhash)
 66     Context=SHA.new()
 67     Context.update(PasswordHashhash)
 68     Context.update(NTResponse)
 69     Context.update(Magic1)
 70     aa=Context.digest()
 71     Challenge=ChallengeHash(PeerChalleng,AuthenticatorChallenge,UserName)
 72     Context=SHA.new()
 73     Context.update(aa)
 74     Context.update(Challenge)
 75     Context.update(Magic2)
 76     aa=Context.digest()
 77     return b'S=' + binascii.hexlify(aa)[:40]
 78 def print_hex(s):
 79     for i in s:
 80         print('\%#x' % i, end='')
 81     print('')
 82 
 83 
 84 if __name__ == "__main__":
 85 
 86     UserName = 'WA_042'.encode("utf8")
 87     password = '123456'.encode("utf8")
 88     AuthenticatorChallenge = b'\x11\xD8\x2A\x82\x0F\xBE\xB0\x30\x73\xB1\xF7\x03\x73\x22\x26\xBF'
 89     PeerChalleng = b'\xC1\xD4\x43\x9D\xBD\x65\xA2\x74\xB9\x7A\xF0\x3F\x98\x00\x6D\x75'
 90     password_unicode = b''
 91     for ch in password:
 92         password_unicode += bytes([ch])
 93         password_unicode +=b'\x00'
 94     NTResponse=GenerateNTResponse(AuthenticatorChallenge, PeerChalleng, UserName, password_unicode)
 95     PasswordHashhash = Nt_password_hashhash(Nt_password_hash(password_unicode))
 96     AuthenticatorResponse=GenerateAuthenticatorResponse(password_unicode,NTResponse,PeerChalleng,AuthenticatorChallenge,UserName)
 97     print("用户名:",UserName)
 98     print("密码:",password)
 99     print("挑战响应值:")
100     print_hex(NTResponse)
101     print("AuthenticatorResponse: ",AuthenticatorResponse)

View Code

相关推荐
F_D_Z2 个月前
SSL VPN | Easyconnect下载&安装&使用 (详尽)
网络·网络协议·ssl·vpn·easyconnect
empty0.02 个月前
MAC-Win11虚拟机双VPN环境内网穿透解决思路
macos·内网穿透·虚拟机·vpn
OKXLIN3 个月前
macOS 卸载被锁的FortiClient软件步骤
macos·vpn
LXMXHJ4 个月前
软件-vscode-plantUML-drawio
vscode·vpn
墨鸦_Cormorant4 个月前
VPN 的入门介绍
服务器·网络·安全·vpn
读书笔记控5 个月前
VPN是什么?
科普·vpn
空暝5 个月前
VPN的概述
网络·数据库·vpn
墨渊04.5 个月前
华为防火墙配置 SSL VPN
vpn·虚拟专用网络
悟道子HD6 个月前
VPN软件常见问题(技巧)总结
windows·经验分享·vpn·问题总结·软件·proton·windscript