My 802.1X Supplicant for FreeBSD

类别:编程语言 点击:0 评论:0 推荐:
mysupplicant是我自己写的一个FreeBSD下的802.1X认证客户端。上次提到了学校网络改用DHCP分配IP,而且增加了802.1X认证,于是打算为实验室的网关服务器(FreeBSD)写一个认证客户端。 程序基于BPF,所以在BSD下不需要libpcap和libnet就可以控制数据链路层的数据帧,关于怎么使用BPF,可以参考man手册(man bpf)。花了两天时间按照标准的协议写了个基本代码,md5加密。测试时告诉我认证失败,但用户名和密码没错,晕………于是抓了些windows下用锐杰的802.1X客户端Ruijie Supplican(学校网络中心给的,也就是我上次破解的那个)认证过程的数据包,发现认证交换机是实达的,而且它在EAPoL的数据帧后面附加了一些它自己的数据,附加的数据中还有几个字节变化,于是猜想可能实达还有它自己的一套认证机制,而且就藏在这些附加的数据里面。不管这么多,在我的程序里直接把抓包得到的附加数据也附加到EAPoL后面,再测试时认证成功,^_^可不一会就收到交换机发的Logoff的EAPoL帧。再仔细看抓的包,原来认证客户端每20秒给交换机发一个类型为0xBF的EAPoL帧。上网搜了下,找到个源代码mystar,使用libpcap+libnet写的认证客户端,里面有实达的认证机制。于是按照mystar中所了解的实达的认证机制修改了我的程序,包括标准EAPoL后面附加的数据,和每20秒发送的数据帧。再测试,这下连认证都通不过了。再改,把标准EAPoL帧后附加的数据改成我自己抓包得到的数据(想当然这样修改,至于这些附加的数据包到底起什么作用,我不知道,有时间的话我会详细逆向下Ruijie Supplican,希望自己也能从中分析透实达的认证机制,像mystar的作者一样),每20秒发送的数据帧用mystar的。成功了…………现在程序已在实验室用了1天,一切都正常,应该说可以正常工作了吧。 写最初的代码花了两天时间,调试也花了两天时间,还好看到了mystar才能调试成功。这里谢谢mystar的作者netxray@byhh,他对实达的认证机制分析得很透,佩服!! 程序参考了IEEE Std 802.1X-2001,RFC1994 PPP Challenge Handshake Authentication Protocol (CHAP)和RFC2284 PPP Extensible Authentication Protocol (EAP)。代码写的很烂,只能供自己使用,拿出来都感觉有点丢人^_^如有什么建议,感激不尽。(如需要所有源代码,可以给我邮件。我免费提供,还包括上面的3篇参考文献和mystarV0.1-src)下面贴出程序的主要代码mysupplicant.c: #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "global.h" #include "md5.h" #define ETHERTYPE_8021X 0x888e #define EAPOL_Packet 0x00 #define EAPOL_Start 0x01 #define EAPOL_Logoff 0x02 #define EAP_Request 1 #define EAP_Response 2 #define EAP_Success 3 #define EAP_Failure 4 #define EAP_TYPE_Identity 1 #define EAP_TYPE_MD5Challenge 4 typedef unsigned char int8; typedef unsigned short int16; typedef unsigned long int32; struct bpf_insn insns[] = { BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),//加载halfword以太网链路层的type BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_8021X, 0, 1),//判断是否是802.1X数据包,是则返回给本程序 BPF_STMT(BPF_RET+BPF_K, (u_int)-1), BPF_STMT(BPF_RET+BPF_K, 0), }; typedef struct EAPOLforEthernet//EAPOL在Ethernet上的帧格式 { int16 ethertype; int8 version; int8 type; int16 length; }EAPOL; typedef struct EAPformat//EAP的帧格式 { int8 code; int8 id; int16 length; int8 type; }__attribute__((packed)) EAP; typedef union { u_int32_t ulValue; u_int8_t btValue[4]; }ULONG_BYTEARRAY; ULONG_BYTEARRAY m_serialNo; //序列号,收到第一个有效的Authentication-Success-packet时初始化 ULONG_BYTEARRAY m_key; //密码加密键值,在main()函数开始时初始化 char standardMAC[6]={0x01,0x80,0xc2,0x00,0x00,0x03};//标准802.1X组播MAC地址 char name[7]="1234567";//用户名 char pass[6]="123456";//密码 char * nic="lnc0";//网卡名 char pad[]={"\xff\xff\x37\x77x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\\xff\xff\xff\xff\xff\xf5\x71\x00\x00\x13\x11\x38\x30\x32\x31\x78\\x2e\x65\x78\x65\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x28\x00\x00\x00\ \x00\x00\x13\x11\x00\x28\x1a\x28\x00\x00\x13\x11\x17\x22\x60\x63\ \x67\x65\x91\x66\x92\x94\x68\x92\x91\x64\x96\x95\x67\x91\x93\x95\ \x94\x93\x63\x62\x64\x61\x67\x6b\x84\xae\x77\x97\x6c\x6b\x00\x00\ \x13\x11\x18\x06\x00\x00\x00\x01"};//每个本机发送的链路层帧后面附加这些字符,每帧1000byte,实达交换机自己的验证机制?? /*char pad[] = { //实达专有响应附加包 0xFF,0xFF,0x37,0x77,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x08,0x15,0x00,0x00,0x13,0x11,0x38,0x30,0x32,0x31,0x78, 0x2E,0x65,0x78,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x1F,0x00,0x00,0x00, 0x00,0x00,0x13,0x11,0x00,0x28,0x1A,0x28,0x00,0x00,0x13,0x11,0x17,0x22,0x92,0x68, 0x64,0x66,0x92,0x94,0x62,0x66,0x91,0x93,0x95,0x62,0x93,0x93,0x91,0x94,0x64,0x61, 0x64,0x64,0x65,0x66,0x68,0x94,0x98,0xA7,0x61,0x67,0x65,0x67,0x9C,0x6B,0x00,0x00, 0x13,0x11,0x18,0x06,0x00,0x00,0x00,0x01};*/ char echoPackaget = { //echo包,用于每20秒钟激活一次 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x8E,0x01,0xBF, 0x00,0x1E,0xFF,0xFF,0x37,0x77,0x7F,0x9F,0xF7,0xFF,0x00,0x00,0xFF,0xFF,0x37,0x77, 0x7F,0x9F,0xF7,0xFF,0x00,0x00,0xFF,0xFF,0x37,0x77,0x7F,0x3F,0xFF}; void sig_intr(int signo); //发送logoff包 on exit with Ctrl+C char * buf; char * p; int8 dstMAC[6]={0,}; int bpf; int blen; unsigned char circleCheck[2]; //那两个鬼值 unsigned char Alog(unsigned char BForAlog) { int a=0,b=0,c=0,d=0,iRt; a=BForAlog; c=a; d=a; c&=0x40; b=a; d>>=2; c|=d; d=a; c>>=2; d&=0x20; c|=d; d=a; c>>=2; d&=0x10; c|=d; d=a; d&=2; bcode!=EAP_Request) ||(((EAP *)(p+12+sizeof(EAPOL)))->type!=EAP_TYPE_Identity)) { printf("EAP Request Identity format error!\n"); goto retry; } id=((EAP *)(p+12+sizeof(EAPOL)))->id; memcpy(dstMAC,p+6,6); //构造EAP Response Identity帧 printf("send EAP Response Identity packet!\n"); memset(buf,0,blen); memcpy(buf,dstMAC,6); ((EAPOL *)(buf+12))->ethertype=htons(0x888E); ((EAPOL *)(buf+12))->version=1; ((EAPOL *)(buf+12))->type=EAPOL_Packet; ((EAPOL *)(buf+12))->length=htons(sizeof(EAP)+sizeof(name)); ((EAP *)(buf+12+sizeof(EAPOL)))->code=EAP_Response; ((EAP *)(buf+12+sizeof(EAPOL)))->id=id; ((EAP *)(buf+12+sizeof(EAPOL)))->length=htons(sizeof(EAP)+sizeof(name)); ((EAP *)(buf+12+sizeof(EAPOL)))->type=EAP_TYPE_Identity; memcpy(buf+12+sizeof(EAPOL)+sizeof(EAP),name,sizeof(name)); memcpy(buf+12+sizeof(EAPOL)+sizeof(EAP)+sizeof(name),pad,sizeof(pad)); if(1000!=write(bpf,buf,1000)) //发送EAP Response Identity帧 { perror("write EAP Response Identity error"); goto retry; } //读取EAP Request MD5-Challenge帧 FD_ZERO(&readset); FD_SET(bpf, &readset); ioctl(bpf,BIOCFLUSH); if(1!=select(bpf+1,&readset,NULL,NULL,&timeout)) { perror("select read EAP Request MD5-Challenge"); goto retry; } if(-1==read(bpf,buf,blen)) { perror("read EAP Request MD5-Challenge errorr"); goto retry; } p=buf+((struct bpf_hdr *)buf)->bh_hdrlen; if((((EAPOL *)(p+12))->type!=EAPOL_Packet)||(((EAP *)(p+12+sizeof(EAPOL)))->code!=EAP_Request) ||(((EAP *)(p+12+sizeof(EAPOL)))->type!=EAP_TYPE_MD5Challenge)) { printf("EAP Request MD5-Challenge format error!\n"); goto retry; } id=((EAP *)(p+12+sizeof(EAPOL)))->id; challengelen=*((char *)(p+12+sizeof(EAPOL)+sizeof(EAP))); //printf("challengelen %d\n",challengelen); if((bufmd5=(char *)malloc(1+challengelen+sizeof(pass)))==NULL) { perror("malloc bufmd5 error"); close(bpf); exit(1); } /*The Response Value is the one-way hash calculated over a stream of octets consisting of the Identifier, followed by (concatenated with) the "secret", followed by (concatenated with) the Challenge Value. The length of the Response Value depends upon the hash algorithm used (16 octets for MD5).见RFC1994*/ memset(bufmd5,0,1+challengelen+sizeof(pass)); *bufmd5=id; memcpy(bufmd5+1,pass,sizeof(pass)); memcpy(bufmd5+1+sizeof(pass),p+12+sizeof(EAPOL)+sizeof(EAP)+1,challengelen); MD5Init(&context);//计算md5值 MD5Update(&context, bufmd5, 1+challengelen+sizeof(pass)); MD5Final(md5Hash, &context); //构造EAP Response MD5-Challenge帧 printf("send EAP Response MD5-Challenge packet!\n"); memset(buf,0,blen); memcpy(buf,dstMAC,6); ((EAPOL *)(buf+12))->ethertype=htons(0x888E); ((EAPOL *)(buf+12))->version=1; ((EAPOL *)(buf+12))->type=EAPOL_Packet; ((EAPOL *)(buf+12))->length=htons(sizeof(EAP)+sizeof(name)+challengelen+1);//这里的1是EAP里的value-size ((EAP *)(buf+12+sizeof(EAPOL)))->code=EAP_Response; ((EAP *)(buf+12+sizeof(EAPOL)))->id=id; ((EAP *)(buf+12+sizeof(EAPOL)))->length=htons(sizeof(EAP)+sizeof(name)+challengelen+1); ((EAP *)(buf+12+sizeof(EAPOL)))->type=EAP_TYPE_MD5Challenge; *(char *)(buf+12+sizeof(EAPOL)+sizeof(EAP))=16;//md5 hash长度 memcpy(buf+12+sizeof(EAPOL)+sizeof(EAP)+1,md5Hash,16); memcpy(buf+12+sizeof(EAPOL)+sizeof(EAP)+1+16,name,sizeof(name)); memcpy(buf+12+sizeof(EAPOL)+sizeof(EAP)+1+16+sizeof(name),pad,sizeof(pad)); if(1000!=write(bpf,buf,1000)) //发送EAP Response MD5-Challenge帧 { perror("write EAP Response MD5-Challenge error"); goto retry; } //读取EAP success或fail帧 FD_ZERO(&readset); FD_SET(bpf, &readset); ioctl(bpf,BIOCFLUSH); if(1!=select(bpf+1,&readset,NULL,NULL,&timeout)) { perror("select read EAP authentication result"); goto retry; } if(-1==read(bpf,buf,blen)) { perror("read EAP authentication result errorr"); goto retry; } p=buf+((struct bpf_hdr *)buf)->bh_hdrlen; if((((EAPOL *)(p+12))->type!=EAPOL_Packet)||(((EAP *)(p+12+sizeof(EAPOL)))->id!=id)) { printf("EAP result packet error!\n"); goto retry; } if(((EAP *)(p+12+sizeof(EAPOL)))->code==EAP_Success) { printf("EAP authentication success!\n"); tmp=ntohs( *((int16*)(p+0x10)) ); uTemp.ulValue = *((int32 *)(p+(0x11+tmp)-0x08)); m_key.btValue[0] = Alog(uTemp.btValue[3]); m_key.btValue[1] = Alog(uTemp.btValue[2]); m_key.btValue[2] = Alog(uTemp.btValue[1]); m_key.btValue[3] = Alog(uTemp.btValue[0]); printf("Keeping sending echo every 20s... \n"); while(1) { sleep(20); ULONG_BYTEARRAY uCrypt1,uCrypt2,uCrypt1_After,uCrypt2_After; m_serialNo.ulValue++; //m_serialNo is initialized at the beginning of main() of mystar.c, and //m_key is initialized in mystar.c when the 1st Authentication-Success packet is received. uCrypt1.ulValue = m_key.ulValue + m_serialNo.ulValue; uCrypt2.ulValue = m_serialNo.ulValue; memcpy( echoPackage, dstMAC, 6 ); uCrypt1_After.ulValue = htonl( uCrypt1.ulValue ); uCrypt2_After.ulValue = htonl( uCrypt2.ulValue ); echoPackage[0x18] = Alog(uCrypt1_After.btValue[0]); echoPackage[0x19] = Alog(uCrypt1_After.btValue[1]); echoPackage[0x1a] = Alog(uCrypt1_After.btValue[2]); echoPackage[0x1b] = Alog(uCrypt1_After.btValue[3]); echoPackage[0x22] = Alog(uCrypt2_After.btValue[0]); echoPackage[0x23] = Alog(uCrypt2_After.btValue[1]); echoPackage[0x24] = Alog(uCrypt2_After.btValue[2]); echoPackage[0x25] = Alog(uCrypt2_After.btValue[3]); while(write(bpf,echoPackage, 0x2d)!=0x2d) ; ioctl(bpf,BIOCFLUSH); } } else { printf("EAP authentication fail!\n"); goto retry; } //sleep(3600); //goto retry; //睡眠1小时后重新认证 close(bpf);//不会到这 return 0; } void sig_intr(int signo) { if(buf!=NULL) { //构造802.1X的EAPOL-Logoff帧 memset(buf,0,blen); if((dstMAC[0]==0)&&(dstMAC[1]==0)&&(dstMAC[2]==0)) memcpy(buf,standardMAC,6); else memcpy(buf,dstMAC,6); ((EAPOL *)(buf+12))->ethertype=htons(0x888E); ((EAPOL *)(buf+12))->version=1; ((EAPOL *)(buf+12))->type=EAPOL_Logoff; ((EAPOL *)(buf+12))->length=0; if((12+sizeof(EAPOL))!= write(bpf,buf,12+sizeof(EAPOL))) //发送802.1X的EAPOL-Logoff帧 { perror("write EAPOL_Logoff error"); } } _exit(0); }

本文地址:http://com.8s8s.com/it/it21789.htm