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