|
/**************************************************************************** |
|
* EAPoL MD5 client for SDU * |
|
**************************************************************************** |
|
* THE CODE IS BASED ON * |
|
* https://github.com/gmsj0001/shnu-h3c * |
|
* https://github.com/pod32g/MD5 * |
|
***************************************************************************/ |
|
|
|
#include <unistd.h> |
|
#include <sys/ioctl.h> |
|
#include <sys/socket.h> |
|
#include <linux/if_packet.h> |
|
#include <linux/if.h> |
|
#include <arpa/inet.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <stdint.h> |
|
#include <string.h> |
|
#include <signal.h> |
|
|
|
#define PROGEXIT_SUCC 0 |
|
#define PROGEXIT_AUTH_FAIL 1 |
|
#define PROGEXIT_USAGE 2 |
|
#define PROGEXIT_PROTO_FAIL 3 |
|
#define PROGEXIT_PRIVILEGE_FAIL 4 |
|
#define PROGEXIT_SYSCALL_FAIL 5 |
|
|
|
#define ETH_P_PAE 0x888e |
|
#define EAPOL_VER 1 |
|
#define EAPOL_EAPPACKET 0 |
|
#define EAPOL_START 1 |
|
#define EAPOL_LOGOFF 2 |
|
#define EAP_REQUEST 1 |
|
#define EAP_RESPONSE 2 |
|
#define EAP_SUCCESS 3 |
|
#define EAP_FAILURE 4 |
|
#define EAP_PULSE_ID 1 |
|
#define EAP_TYPE_IDENTITY 1 |
|
#define EAP_TYPE_MD5 4 |
|
#define EAP_TYPE_ALLOCATED 7 |
|
#define PKT_SIZE 1500 |
|
|
|
/* global variables of the client */ |
|
|
|
static const uint8_t s_broadcast_addr[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x03}; |
|
static char *s_interface = "eno1"; |
|
static uint8_t s_local_addr[6]; |
|
static int s_fd; |
|
static char *g_username; |
|
static char *g_password; |
|
|
|
/* ether, eapol, eap pack functions */ |
|
|
|
static uint16_t pack_eap(uint8_t *buf, uint16_t len, |
|
uint8_t code, uint8_t id, uint8_t type) |
|
{ |
|
uint16_t delta = 0; |
|
if (code == EAP_REQUEST || code == EAP_RESPONSE) |
|
{ |
|
buf -= 1; |
|
len += 1; |
|
delta += 1; |
|
buf[0] = type; |
|
} |
|
buf -= 4; |
|
len += 4; |
|
delta += 4; |
|
buf[0] = code; |
|
buf[1] = id; |
|
*(uint16_t*)&buf[2] = htons(len); |
|
return delta; |
|
} |
|
|
|
static uint16_t pack_eapol(uint8_t *buf, uint16_t len, |
|
uint8_t ver, uint8_t type) |
|
{ |
|
uint16_t delta = 0; |
|
buf -= 4; |
|
buf[0] = ver; |
|
buf[1] = type; |
|
*(uint16_t*)&buf[2] = htons(len); |
|
len += 4; |
|
delta += 4; |
|
return delta; |
|
} |
|
|
|
static uint16_t pack_eth(uint8_t *buf, uint16_t len, |
|
const uint8_t dst[6], const uint8_t src[6], uint16_t type) |
|
{ |
|
uint16_t delta = 0; |
|
buf -= 14; |
|
len += 14; |
|
delta += 14; |
|
memcpy(buf, dst, 6); |
|
memcpy(buf + 6, src, 6); |
|
*(uint16_t*)&buf[12] = htons(type); |
|
return delta; |
|
} |
|
|
|
/* main authentication procedure */ |
|
static void authentication(void) |
|
{ |
|
s_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE)); |
|
if (s_fd < 0) |
|
{ |
|
fprintf(stderr, "Create socket failed.\n"); |
|
exit(PROGEXIT_SYSCALL_FAIL); |
|
} |
|
struct ifreq req; |
|
memset(&req, 0, sizeof(struct ifreq)); |
|
strcpy(req.ifr_name, s_interface); |
|
if (ioctl(s_fd, SIOCGIFINDEX, &req) < 0) |
|
{ |
|
fprintf(stderr, "Get interface index failed.\n"); |
|
exit(PROGEXIT_SYSCALL_FAIL); |
|
} |
|
struct sockaddr_ll addr; |
|
memset(&addr, 0, sizeof(struct sockaddr_ll)); |
|
addr.sll_family = AF_PACKET; |
|
addr.sll_ifindex = req.ifr_ifindex; |
|
if (bind(s_fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_ll)) < 0) |
|
{ |
|
fprintf(stderr, "Bind interface failed.\n"); |
|
} |
|
uint32_t size = sizeof(struct sockaddr_ll); |
|
if (getsockname(s_fd, (struct sockaddr*)&addr, &size) < 0) |
|
{ |
|
fprintf(stderr, "Get MAC address failed.\n"); |
|
} |
|
memcpy(s_local_addr, addr.sll_addr, addr.sll_halen); |
|
|
|
/*send eapol start */ |
|
fprintf(stderr, "EAPoL Start\n"); |
|
uint8_t buf0[PKT_SIZE]; |
|
uint8_t *buf = &buf0[14+4]; |
|
memset(buf0, 0, PKT_SIZE); |
|
uint16_t len = 0, delta; |
|
len += (delta = pack_eapol(buf, len, EAPOL_VER, EAPOL_START)); |
|
len += (delta = pack_eth((buf -= delta), len, s_broadcast_addr, s_local_addr, ETH_P_PAE)); |
|
buf -= delta; |
|
send(s_fd, buf, len, 0); |
|
|
|
/* listening */ |
|
while (1) |
|
{ |
|
buf = &buf0[0]; |
|
recv(s_fd, buf, PKT_SIZE, 0); |
|
|
|
uint8_t eth_dst_addr[6], eth_src_addr[6]; |
|
memcpy(eth_dst_addr, &buf[0], 6); |
|
memcpy(eth_src_addr, &buf[6], 6); |
|
uint16_t eth_proto = ntohs(*(uint16_t*)&buf[12]); |
|
buf += 14; |
|
|
|
/* filtering */ |
|
if (eth_proto == ETH_P_PAE && !memcmp(eth_dst_addr, s_local_addr, 6)) |
|
{ |
|
uint8_t eapol_ver = buf[0]; |
|
uint8_t eapol_type = buf[1]; |
|
uint16_t eapol_len = ntohs(*(uint16_t*)&buf[2]); |
|
buf += 4; |
|
|
|
if (eapol_type == EAPOL_EAPPACKET) |
|
{ |
|
uint8_t eap_code = buf[0]; |
|
uint8_t eap_id = buf[1]; |
|
uint16_t eap_len = ntohs(*(uint16_t*)&buf[2]); |
|
buf += 4; |
|
|
|
if (eap_code == EAP_REQUEST) |
|
{ |
|
uint8_t eap_type = buf[0]; |
|
buf += 1; |
|
|
|
len = 0; |
|
if (eap_type == EAP_TYPE_IDENTITY) |
|
{ |
|
/*************************** |
|
* identity request data: * |
|
* <empty> * |
|
* identity response data: * |
|
* username * |
|
***************************/ |
|
fprintf(stderr, "EAP Request Identity\n"); |
|
strcpy(buf, g_username); |
|
len = strlen(g_username); |
|
} |
|
else if (eap_type == EAP_TYPE_MD5) |
|
{ |
|
/*************************************************** |
|
* md5 challenge request data: * |
|
* chap_len(0x10) chap(16 bytes) * |
|
* md5 challenge response data: * |
|
* md5_len(0x10) md5of{eap_id, password, chap} * |
|
***************************************************/ |
|
fprintf(stderr, "EAP Request MD5\n"); |
|
uint8_t digest[16]; |
|
void md5sum(const uint8_t *msg, size_t len, |
|
uint8_t *digest); |
|
memmove(&buf[1+strlen(g_password)], &buf[1], 16); |
|
buf[0] = eap_id; |
|
memcpy(&buf[1], g_password, strlen(g_password)); |
|
md5sum(buf, 1+strlen(g_password)+16, digest); |
|
buf[0] = 16; |
|
memcpy(&buf[1], digest, 16); |
|
len = 17; |
|
} |
|
else |
|
{ |
|
fprintf(stderr, "Unknown EAP request type %d.\n", eap_type); |
|
exit(PROGEXIT_PROTO_FAIL); |
|
} |
|
|
|
/* pack and response */ |
|
len += (delta = pack_eap(buf, len, EAP_RESPONSE, eap_id, eap_type)); |
|
len += (delta = pack_eapol((buf -= delta), len, EAPOL_VER, eapol_type)); |
|
len += (delta = pack_eth((buf -= delta), len, s_broadcast_addr, s_local_addr, ETH_P_PAE)); |
|
buf -= delta; |
|
send(s_fd, buf, len, 0); |
|
} |
|
else if (eap_code == EAP_SUCCESS) |
|
{ |
|
/* success, start pulse thread */ |
|
fprintf(stderr, "EAP Success\n"); |
|
} |
|
else if (eap_code == EAP_FAILURE) |
|
{ |
|
/* failed, exit */ |
|
fprintf(stderr, "EAP Failure\n"); |
|
exit(PROGEXIT_AUTH_FAIL); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
/* send logoff before exit */ |
|
static void signal_exit(int signo) |
|
{ |
|
uint8_t buf0[PKT_SIZE]; |
|
uint8_t *buf = &buf0[14+4]; |
|
fprintf(stderr, "EAPoL Logoff\n"); |
|
uint16_t len = 0, delta; |
|
len += (delta = pack_eapol(buf, len, EAPOL_VER, EAPOL_LOGOFF)); |
|
len += (delta = pack_eth((buf -= delta), len, s_broadcast_addr, s_local_addr, ETH_P_PAE)); |
|
buf -= delta; |
|
send(s_fd, buf, len, 0); |
|
exit(0); |
|
} |
|
|
|
/* program entry */ |
|
void main(int argc, char *argv[]) |
|
{ |
|
if (getuid()) |
|
{ |
|
fprintf(stderr, "Require root privilege.\n"); |
|
exit(PROGEXIT_PRIVILEGE_FAIL); |
|
} |
|
if (argc < 3 || argc > 4) |
|
{ |
|
fprintf(stderr, "Usage: %s username password [interface]\n", argv[0]); |
|
exit(PROGEXIT_USAGE); |
|
} |
|
g_username = (char *) malloc(strlen(argv[1])+1); |
|
strcpy(g_username, argv[1]); |
|
g_password = (char *) malloc(strlen(argv[2])+1); |
|
strcpy(g_password, argv[2]); |
|
if (argc == 4) |
|
{ |
|
s_interface = (char *) malloc(strlen(argv[3])+1); |
|
strcpy(s_interface, argv[3]); |
|
} |
|
|
|
/* erase argv */ |
|
int i; |
|
for (i = 1; i < argc; i++) |
|
memset(argv[i], ' ', strlen(argv[i])+1); |
|
|
|
signal(SIGINT, &signal_exit); |
|
signal(SIGTERM, &signal_exit); |
|
|
|
authentication(); |
|
} |
|
|
|
/* md5 calculating module */ |
|
|
|
#define LEFTROTATE(x, c) (((x) << (c)) | ((x) >> (32 - (c)))) |
|
|
|
const uint32_t k[64] = { |
|
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee , |
|
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501 , |
|
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be , |
|
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821 , |
|
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa , |
|
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8 , |
|
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed , |
|
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a , |
|
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c , |
|
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70 , |
|
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05 , |
|
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665 , |
|
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039 , |
|
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1 , |
|
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1 , |
|
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 }; |
|
|
|
const uint32_t r[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, |
|
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, |
|
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, |
|
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21}; |
|
|
|
void to_bytes(uint32_t val, uint8_t *bytes) |
|
{ |
|
bytes[0] = (uint8_t) val; |
|
bytes[1] = (uint8_t) (val >> 8); |
|
bytes[2] = (uint8_t) (val >> 16); |
|
bytes[3] = (uint8_t) (val >> 24); |
|
} |
|
|
|
uint32_t to_uint32(const uint8_t *bytes) |
|
{ |
|
return (uint32_t) bytes[0] |
|
| ((uint32_t) bytes[1] << 8) |
|
| ((uint32_t) bytes[2] << 16) |
|
| ((uint32_t) bytes[3] << 24); |
|
} |
|
|
|
void md5sum(const uint8_t *initial_msg, size_t initial_len, uint8_t *digest) |
|
{ |
|
uint32_t h0, h1, h2, h3; |
|
|
|
uint8_t *msg = NULL; |
|
|
|
size_t new_len, offset; |
|
uint32_t w[16]; |
|
uint32_t a, b, c, d, i, f, g, temp; |
|
|
|
h0 = 0x67452301; |
|
h1 = 0xefcdab89; |
|
h2 = 0x98badcfe; |
|
h3 = 0x10325476; |
|
|
|
for (new_len = initial_len + 1; new_len % (512/8) != 448/8; new_len++); |
|
|
|
msg = (uint8_t*)malloc(new_len + 8); |
|
memcpy(msg, initial_msg, initial_len); |
|
msg[initial_len] = 0x80; |
|
for (offset = initial_len + 1; offset < new_len; offset++) |
|
msg[offset] = 0; |
|
|
|
to_bytes(initial_len*8, msg + new_len); |
|
to_bytes(initial_len>>29, msg + new_len + 4); |
|
|
|
for(offset=0; offset<new_len; offset += (512/8)) { |
|
for (i = 0; i < 16; i++) |
|
w[i] = to_uint32(msg + offset + i*4); |
|
|
|
a = h0; |
|
b = h1; |
|
c = h2; |
|
d = h3; |
|
|
|
for(i = 0; i<64; i++) { |
|
|
|
if (i < 16) { |
|
f = (b & c) | ((~b) & d); |
|
g = i; |
|
} else if (i < 32) { |
|
f = (d & b) | ((~d) & c); |
|
g = (5*i + 1) % 16; |
|
} else if (i < 48) { |
|
f = b ^ c ^ d; |
|
g = (3*i + 5) % 16; |
|
} else { |
|
f = c ^ (b | (~d)); |
|
g = (7*i) % 16; |
|
} |
|
|
|
temp = d; |
|
d = c; |
|
c = b; |
|
b = b + LEFTROTATE((a + f + k[i] + w[g]), r[i]); |
|
a = temp; |
|
|
|
} |
|
|
|
h0 += a; |
|
h1 += b; |
|
h2 += c; |
|
h3 += d; |
|
|
|
} |
|
|
|
free(msg); |
|
|
|
to_bytes(h0, digest); |
|
to_bytes(h1, digest + 4); |
|
to_bytes(h2, digest + 8); |
|
to_bytes(h3, digest + 12); |
|
} |