1 /*
2 * decode_pptp.c
3 *
4 * Microsoft PPTP MS-CHAP. Derived from Aleph One's anger.c.
5 *
6 * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
7 * Copyright (c) 2000 Aleph One <aleph1@securityfocus.com>
8 *
9 * $Id: decode_pptp.c,v 1.4 2001/03/15 08:33:02 dugsong Exp $
10 */
11
12 #include "config.h"
13
14 #include <sys/types.h>
15 #include <netinet/in.h>
16 #include <openssl/sha.h>
17
18 #include <stdio.h>
19 #include <string.h>
20
21 #include "buf.h"
22 #include "decode.h"
23
24 struct pptp_gre_header {
25 u_char flags; /* bitfield */
26 u_char ver; /* should be PPTP_GRE_VER (enhanced GRE) */
27 u_short protocol; /* should be PPTP_GRE_PROTO (ppp-encaps) */
28 u_short payload_len; /* size of ppp payload, not inc. gre header */
29 u_short call_id; /* peer's call_id for this session */
30 u_int32_t seq; /* sequence number. Present if S==1 */
31 u_int32_t ack; /* seq number of highest packet recieved by */
32 /* sender in this session */
33 };
34
35 #define PPTP_GRE_PROTO 0x880B
36 #define PPTP_GRE_VER 0x1
37
38 #define PPTP_GRE_IS_C(f) ((f) & 0x80)
39 #define PPTP_GRE_IS_R(f) ((f) & 0x40)
40 #define PPTP_GRE_IS_K(f) ((f) & 0x20)
41 #define PPTP_GRE_IS_S(f) ((f) & 0x10)
42 #define PPTP_GRE_IS_A(f) ((f) & 0x80)
43
44 struct ppp_header {
45 u_char address;
46 u_char control;
47 u_short proto;
48 };
49
50 #define PPP_PROTO_CHAP 0xc223
51
52 struct ppp_lcp_chap_header {
53 u_char code;
54 u_char ident;
55 u_short length;
56 };
57
58 #define PPP_CHAP_CODE_CHALLENGE 1
59 #define PPP_CHAP_CODE_RESPONSE 2
60
61 struct ppp_chap_challenge {
62 u_char size;
63 union {
64 u_char challenge_v1[8];
65 u_char challenge_v2[16];
66 struct {
67 u_char lanman[24];
68 u_char nt[24];
69 u_char flag;
70 } response_v1;
71 struct {
72 u_char peer_challenge[16];
73 u_char reserved[8];
74 u_char nt[24];
75 u_char flag;
76 } response_v2;
77 } value;
78 /* name */
79 };
80
81 struct challenge {
82 u_char version;
83 u_char challenge[16];
84 };
85
86 int
decode_pptp(u_char * buf,int len,u_char * obuf,int olen)87 decode_pptp(u_char *buf, int len, u_char *obuf, int olen)
88 {
89 static struct challenge save_challenge;
90 struct buf outbuf;
91 struct pptp_gre_header *pgh;
92 struct ppp_header *ppp;
93 struct ppp_lcp_chap_header *chap;
94 struct ppp_chap_challenge *chapch;
95 u_short proto;
96 u_char *p, name[64], digest[SHA_DIGEST_LENGTH];
97 SHA_CTX ctx;
98 int i, pghlen;
99
100 buf_init(&outbuf, obuf, olen);
101
102 if (len < (pghlen = sizeof(*pgh)))
103 return (0);
104
105 pgh = (struct pptp_gre_header *)buf;
106
107 if ((pgh->ver & 0x7f) != PPTP_GRE_VER ||
108 ntohs(pgh->protocol) != PPTP_GRE_PROTO ||
109 PPTP_GRE_IS_C(pgh->flags) || PPTP_GRE_IS_R(pgh->flags) ||
110 PPTP_GRE_IS_K(pgh->flags) == 0 || (pgh->flags & 0xf) != 0) {
111 return (0);
112 }
113 if (PPTP_GRE_IS_S(pgh->flags) == 0)
114 return (0);
115
116 if (PPTP_GRE_IS_A(pgh->ver) == 0)
117 pghlen -= sizeof(pgh->ack);
118
119 if (len - pghlen < ntohs(pgh->payload_len))
120 return (0);
121
122 ppp = (struct ppp_header *)(pgh + 1);
123
124 if (ppp->address != 0xff && ppp->control != 0x3) {
125 proto = pntohs(ppp);
126 chap = (struct ppp_lcp_chap_header *)
127 ((u_char *)ppp + sizeof(proto));
128 }
129 else {
130 proto = ntohs(ppp->proto);
131 chap = (struct ppp_lcp_chap_header *)(ppp + 1);
132 }
133 if (proto != PPP_PROTO_CHAP)
134 return (0);
135
136 switch (chap->code) {
137
138 case PPP_CHAP_CODE_CHALLENGE:
139 chapch = (struct ppp_chap_challenge *)(chap + 1);
140
141 if (chapch->size == 8) {
142 save_challenge.version = 1;
143 memcpy(save_challenge.challenge,
144 chapch->value.challenge_v1, 8);
145 }
146 else if (chapch->size == 16) {
147 save_challenge.version = 2;
148 memcpy(save_challenge.challenge,
149 chapch->value.challenge_v2, 16);
150 }
151 else save_challenge.version = 0;
152 break;
153
154 case PPP_CHAP_CODE_RESPONSE:
155 if (save_challenge.version == 0)
156 break;
157
158 chapch = (struct ppp_chap_challenge *)(chap + 1);
159 i = ntohs(chap->length) - 54;
160 if (i > 63) i = 63;
161 memcpy(name, (u_char *)chap + 54, i);
162 name[i] = '\0';
163
164 buf_putf(&outbuf, "%s:0:", name);
165
166 if (save_challenge.version == 1) {
167 for (i = 0; i < 8; i++) {
168 buf_putf(&outbuf, "%02X",
169 save_challenge.challenge[i]);
170 }
171 buf_put(&outbuf, ":", 1);
172
173 for (i = 0; i < 24; i++) {
174 buf_putf(&outbuf, "%02X",
175 chapch->value.response_v1.lanman[i]);
176 }
177 buf_put(&outbuf, ":", 1);
178
179 for (i = 0; i < 24; i++) {
180 buf_putf(&outbuf, "%02X",
181 chapch->value.response_v1.nt[i]);
182 }
183 buf_put(&outbuf, "\n", 1);
184 }
185 else if (save_challenge.version == 2) {
186 chapch = (struct ppp_chap_challenge *)(chap + 1);
187 if ((p = strchr(name, '\\')) == NULL)
188 p = name;
189
190 SHA1_Init(&ctx);
191 SHA1_Update(&ctx, chapch->value.response_v2.peer_challenge, 16);
192 SHA1_Update(&ctx, save_challenge.challenge, 16);
193 SHA1_Update(&ctx, p, strlen(p));
194 SHA1_Final(digest, &ctx);
195
196 for (i = 0; i < 8; i++) {
197 buf_putf(&outbuf, "%02X", digest[i]);
198 }
199 buf_putf(&outbuf, ":000000000000000000000000000000000000000000000000:");
200 for (i = 0; i < 24; i++) {
201 buf_putf(&outbuf, "%02X",
202 chapch->value.response_v2.nt[i]);
203 }
204 buf_put(&outbuf, "\n", 1);
205
206 save_challenge.version = 0;
207 }
208 break;
209 }
210 buf_end(&outbuf);
211
212 return (buf_len(&outbuf));
213 }
214
215