Mostrando entradas con la etiqueta remote. Mostrar todas las entradas
Mostrando entradas con la etiqueta remote. Mostrar todas las entradas

domingo, 27 de abril de 2014

[Parte 4] CURL en PHP

Cabecera post personalizada a un host remoto 

Esto sucede cuando solo podemos ver ciertas partes de un sitio web, el sitio necesita unas cabeceras especiales, que tendriamos que olfatear con algun intermediario tal como puede ser: Live HTTP HEADERS, HTTPFox, Burp Suite, Tamper Data...


En este ejemplo estoy olfateando las cabeceras HTTP usando de intermediario HTTPFox (Complemento de firefox).

En este caso nosotros usaremos la opcion CURLOPT_HTTPHEADER.

CURLOPT_HTTPHEADER - Un array de campos a configurar para el Header HTTP, en el formato: array('Content-Type: text/plain','Content-length: 100');

CURLOPT_HEADER - TRUE para incluir el header en el OUTPUT.

 <?php

 $url = "https://tuhost.com/";
 $referer = "https://tuhost.com";

 $ch = curl_init(); // iniciamos curl
 curl_setopt($ch, CURLOPT_URL, $url); // establecemos la url
 curl_setopt($ch, CURLOPT_VERBOSE, 1); // muestra como pasa todo
 curl_setopt($ch, CURLOPT_HEADER, 1); // muestra las cabeceras que el servidor nos devuelve
 curl_setopt($ch, CURLOPT_STDERR, fopen('log_curl.txt','a+')); // en este archivo se guarda lo de verbose
 curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/plain')); //modificamos nuestra cabecera
 curl_setopt($ch, CURLOPT_REFERER, $referer); // ponemos desde donde venimos
 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // devolvemos el contenido de la pagina
 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); // quitamos la verificacion del certificado
 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // seguimos cualquier redireccion
 curl_setopt($ch, CURLOPT_COOKIEFILE, fopen('cookies.txt','a+')); // le decimos donde van las cookies
 curl_setopt($ch, CURLOPT_COOKIEJAR, fopen('cookies.txt','a+')); // le decimos que escriba las cookies aqui

 $result = curl_exec($ch); // ejecutamos y guardamos
 
  curl_close($ch); // cerramos curl, liberamos memoria

 print $result; // mostramos el resultado

?>

Subir un archivo a un sitio remoto usando un formulario HTML

Tu debes usar un formulario utilizando el metodo POST pero con algunos cambios. En este ejemplo, donde el formulario contiene enctype='multipart/form-data'. Usamos el array superglobal $_FILE para leer el archivo y pasarlo por los campos post con el signo @. Tal como lo siguiente:

 curl_setopt($ch, CURLOPT_POSTFIELDS, array("$field_name"=>"@".$_FILES['file']['tmp_name']));

En este ejemplo les muestro como subimos un archivo remotamente a la pagina xup.in:

 <?php
   set_time_limit(0);
   $url = "http://www0.xup.in/exec/xupload.php?uid=&key=";
   $user_agent = "Mozilla/5.0 (Windows NT 6.1; rv:28.0) Gecko/20100101 Firefox/28.0";
   $referer = "http://www.xup.in/";
   $directory=dirname(__FILE__).'\files/';
   if(isset($_FILES['f1'])){
      move_uploaded_file($_FILES['f1']['tmp_name'],"files/".$_FILES['f1']['name']);
      $ch = curl_init();
      curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
      curl_setopt($ch, CURLOPT_REFERER, $referer);
      curl_setopt($ch, CURLOPT_URL, $url);
      curl_setopt($ch, CURLOPT_POSTFIELDS, array("F1"=>"@".$directory.$_FILES['f1']['name']));
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
      curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
      $result = curl_exec($ch);
      if(curl_errno($ch))
  {
      echo 'Curl error: ' . curl_error($ch);
  }
      curl_close($ch);
      unlink($directory.$_FILES['f1']['name']);
      //echo $result;
      preg_match_all('/<input type="text" name="t1" size="90" class="inp" value="(.*?)" onclick="highlight\(this\);" \/>/', $result, $matches);
      //echo '<p><img src="'.$matches[1][0].'" alt="img" /></p>';
      echo '<p><b>Link: <a href="'.$matches[1][0].'" target="_blank">Archive Link</a></p>';
      //print_r($matches);
   }else{
      echo '
         <form action="upload_curl.php" method="post" enctype="multipart/form-data">
            <label for="f1">Filename:</label>
            <input type="file" name="f1" id="f1"><br>
            <input type="submit" name="submit" value="Submit">
         </form>

      ';   
   }
?>


En este caso tenemos un uploader y una carpeta llamada files/ en la cual se sube el fihcero luego envia una peticion subiendo el fichero y por ultimo nos envia el enlace, una cosa importante aqui es que agregamos la funcion curl_error($ch) que nos muestra si ocurre un error en cURL. Con la funcion curl_errno($ch) nos arroja un numero el cual tiene un mensaje especifico de error.

Nota: Recuerda que siempre que hago referencia a $ch es por que ahi se almacena la sesion de cURL.

Subir un archivo por FTP

Tu tienes la opcion en cURL de usar todos los comandos FTP. Por ejemplo, si quieres subir un archivo:

 <?php
if(isset($_POST['enviar'])){
    $ftp_user = "tuusuario";
    $ftp_pass = "tucontraseña";
    $url = "tuurloipdetuweb";
    $ftp_server = "ftp://". $ftp_user . ":" . $ftp_pass . "@" . $url;
    $archivo_a_subir = realpath($_FILES['userfile']['tmp_name']);
    $tamaño_del_archivo = filesize($archivo_a_subir);
    $fp = fopen($archivo_a_subir, 'rb');
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $ftp_server . $_FILES['userfile']['name']);
    curl_setopt($ch, CURLOPT_VERBOSE, 1);
    curl_setopt($ch, CURLOPT_UPLOAD, 1);
    curl_setopt($ch, CURLOPT_INFILE, $fp);
    curl_setopt($ch, CURLOPT_INFILESIZE, $tamaño_del_archivo);
    if(curl_errno($ch)){
        echo "Ha ocurrido un error: " . curl_error($ch);
    }
    $result = curl_exec($ch);
    curl_close($ch);
    echo "Archivo subido correctamente<br />";
    print $result;
}else{
    echo '
        <form action="" method="post" enctype="multipart/form-data">
            <p><input type="file" name="userfile" /></p>
            <p><input type="submit" name="enviar" value="Subir!" /></p>
        </form>
    ';
}
?>

CURLOPT_INFILE - El fichero que el proceso de transferencia debe leer a la hora de subir el archivo.

CURLOPT_INFILESIZE - El tamaño esperado en bytes, del fichero cuando se esta subiendo un fichero al sitio remoto. Tenganse en cuenta que el uso de esta opcion no detendra a libcurl a la hora de enviar mas datos, exactamente lo que se envia depende de CURLOPT_READFUNCTION.

Eliminar un archivo y mostrarlos por FTP

Tu tienes la opcion de usar comandos FTP con cURL. Alguna lista de comandos puedes encontrarla en: http://en.wikipedia.org/wiki/List_of_FTP_commands

Veamos un ejemplo de Eliminar un archivo y como mostrar los archivos tambien de una carpeta.

 <!DOCTYPE html>
<html>
<head>
 <title>ELIMINAR ARCHIVOS FTP</title>
 <meta charset="utf8">
</head>
<body>
<h1>Eliminar archivo</h1>
<form action="" method="post">
 <p><b>Nombre de la carpeta: </b><input type="text" name="carpeta" placeholder="tucarpeta/" /><small>No es necesario especificarla</small></p>
 <p><b>Nombre del archivo: </b><input type="text" name="archivo" placeholder="archivo.jpg" /></p>
 <input type="submit" name="enviar" />
</form>
<h1>Mostrar archivos de la carpeta</h1>
<form action="" method="post">
 <p><b>Nombre de la carpeta: </b><input type="text" name="directorio" placeholder="tucarpeta/" /><small>Es necesario especificarla para mostrar el contenido del directorio</small></p>
 <input type="submit" name="enviar2" />
</form>
<?php
 /* Variables para el FTP */
 $ftp_user = "tuusuario";
    $ftp_pass = "tucontraseña";
    $url = "tuhost.com/";

    $ftp_server = "ftp://". $ftp_user . ":" . $ftp_pass . "@" . $url;

    /* Funcion para eliminar el archivo */
    if(isset($_POST['enviar'])){
    function delete($carpeta = null , $archivo){
     global $ftp_user, $ftp_pass, $url, $ftp_server;
  if($carpeta == null){
   $carpeta = "public_html/";
  }
  $postfields[] = "CWD ". $carpeta;
  $postfields[] = "DELE " . $archivo;

  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $ftp_server);
  curl_setopt($ch, CURLOPT_POSTQUOTE, $postfields);
  $result = curl_exec($ch);
  if(curl_errno($ch)){
   echo curl_error($ch);
  }
  curl_close($ch);

  print $result;
 }
    $carpeta = $_POST['carpeta'];
    $archivo = $_POST['archivo'];
    delete($carpeta,$archivo);

 }
 /* Listar directorio */
 if(isset($_POST['enviar2'])){
  function listar_dir($directorio){
   global $ftp_user, $ftp_pass;
   $url = "tuhost.com/".$directorio;
   $ftp_server = "ftp://". $ftp_user . ":" . $ftp_pass . "@" . $url;
   $ch = curl_init();
   curl_setopt($ch, CURLOPT_URL, $ftp_server);
   curl_setopt($ch, CURLOPT_FTPLISTONLY, 1);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
   $output = curl_exec($ch);
   if(curl_errno($ch)){
     echo curl_error($ch);
    }
   curl_close($ch);
   $files = explode("\n", $output);
   print_r($files);
  }
  $directorio = $_POST['directorio'];
  listar_dir($directorio);
 }
?>
</body>
</html>

CURLOPT_POSTQUOTE - Un array de comandos FTP a ejecutar en el servidor despues de que se realice la peticion FTP.

CURLOPT_FTPLISTONLY - TRUE para solo listar nombres de un directorio FTP.


Opciones LibcURL

Podemos ver una lista de opciones sobre la libreria cURL en: http://www.php.net/manual/es/function.curl-setopt.php

Rastrear peticiones

Rastrear las peticiones o ver sus cabeceras, es una manera de saber si estamos haciendo bien algo en cURL, existen muchas herramientas las cuales podemos utilizar como intermediario para poder ver las peticiones, como vimos arriba usabamos HTTP FOX.
Y como comentabamos esta disponible tambien Burp Suite, Live HTTP Headers, Tamper Data, etc.

 
Hasta aqui la parte de este tutorial, nos vemos en la proxima parte que espero sea la ultima :).
 

sábado, 5 de abril de 2014

[Parte 6] Seguridad en PHP

Archivos y comandos

En esta parte veremos los riesgos asociados a los archivos y los comandos de shell, en php existen muchas funciones que se utilizan para el manejo de archivos y comandos de shell, es por eso que en este apartado veremos cuales nos pueden afectar y como podemos solucionarlos.

Atravesando el sistema de archivos

Muchas veces leemos archivos usando fopen() u otras funciones de php, las cuales en lugar de meterlas asi solamente la cadena para que lo lea el archivo, lo leemos usando variables o campos de entrada en la pagina web, de esta manera estamos dando un punto a una vulnerabilidad, un ejemplo de un tipo de codigo asi es el siguiente:

 
Como puedes ver en la imagen hay una variable llamada archivo, con la cual pide el archivo de determinada ruta (/ruta/para) en la cual se encuentran todos los archivos, de manera que si alguien entra a la url de ejemplo:

http://ejemplo.com/index.php?archivo=miarchivo

Se abre el archivo llamado miarchivo.txt y se muestra en la web....

Como mostramos en la parte 5 de seguridad en php donde hablabamos sobre la manipulacion del nombre del archivo y que esta vulnerabilidad tambien era llamada LFI en la cual hay un articulo en este mismo BLOG bien definido, pues en este caso estamos usando otro tipo de funcion pero es casi lo mismo por lo cual tambien podemos evitar el tipo de extension usando un null byte (), siendo nuestro ataque de la siguiente manera:

http://ejemplo.com/index.php?archivo=../etc/passwd

Incluyendose el archivo /etc/passwd correctamente y evitando el tipo de archivo .txt
 
Tal como dijimos en la parte 1 de seguridad en php "nosotros los programadores ponemos las reglas a nuestras aplicaciones"... por lo cual nosotros le podemos decir que solo queremos que en la entrada solo haya caracteres alfanumericos usando la funcion ctype_alpha():


O como lo hicimos en la parte 5 de seguridad en php podemos usar la funcion basename():



Riesgos de archivos remotos



PHP tiene una directiva llamada allow_url_fopen activada por defecto. La cual permite hacer referencia a archivos remotos como si fuesen archivos locales, de esta manera poder mostrarlos en el HTML. 

Usaremos la funcion file_get_contents() la cual transmite un fichero entero a una cadena. 


De esta manera podriamos pedir una shell en un formato .txt que este alojado en nuestro servidor, y al pedirla se incluira el codigo PHP dejandonos ejecutar comandos.

La lista de shell la puedes encontrar en esta web: http://www.r57shell.net/

Este ataque tambien es conocido como Remote File Inclusion (RFI).

Para solucionar este tipo de ataques podemos usar la funcion nativa de php htmlentities() de manera que al mostrar el codigo no lo interprete y solo se vea el codigo fuente en si...

htmlentities() lo que hace es convertir todos los caracteres aplicables a entidades html.



Inyeccion de comandos

Usar comandos del sistema en PHP es peligroso ya que puede ocurrir una vulnerabilidad llamada RCE (Remote Code Execution), la cual nos deja ejecutar comandos de manera remota.

Por ejemplo, podemos usar la funcion exec() la cual ejecuta algun comando del sistema devolviendo la ultima linea solamente, pero podemos almacenar en una matriz como segundo argumento de manera que devolvamos todos los elementos del array como uno solo en la matriz...



Esta forma de usarlo es peligrosa ya que muestra muchos directorios y archivos sensibles, aunque en este caso no usamos ningun campo de entrada si lo usaramos podriamos intentar controlar comandos a conveniencia, es por eso que es mejor escapar este tipo de entradas... de la siguiente manera:


La funcion escapeshellcmd() escapa meta-caracteres del interprete de comandos, con meta-caracteres se hace referencia a caracteres que tienen un significado especial en una consola de comandos.

La funcion escapeshellarg() escapa una cadena a ser usada como argumento del interprete de comandos.

Estas como puedes ver no son las unicas maneras de ejecutar comandos, podemos usar otras funciones nativas de PHP tales como: system(), passthru(), popen(), shell_exec().

Referencias:

* Essential PHP Security
* PHP documentacion oficial
* Wikipedia