Hola Visitante

Mostrar Mensajes

Esta sección te permite ver todos los posts escritos por este usuario. Ten en cuenta que sólo puedes ver los posts escritos en zonas a las que tienes acceso en este momento.


Mensajes - Berni69

Páginas: [1] 2 3 ... 76
1
Noticias del Blog / Shaping con Iptables: Limitando CPS
« en: Febrero 24, 2019, 02:41:50 pm »

Publícalo aquí y miraremos a ver si te podemos echar un cable.

Un saludo



2
Noticias del Blog / LibBeat en PHP - Creando nuestro "log-shipper".
« en: Febrero 02, 2019, 07:25:00 pm »

En mi último proyecto me he visto en la necesidad de enviar datos desde una apliación PHP contra un elasticsearch que tenía montado. Los requisitos  del proyecto eran:





  • Insertar trazas operacionales en ElasticSearch
  • Usar el protocolo Beats en un puerto específico
  • Hacerlo en PHP




Qué es ElasticSearch ?





ElasticSearch es un motor de búsqueda basado en Lucene, provee capacidad de búsqueda de texto avanzada, distribuida, y multi tenant. Proporciona fiabilidad, escalabilidad y proporciona múltiples formas de acceso a sus datos.  Lucene es una base de datos no relacional (NoSql) de alto rendimineto hecha en Java y orientada a documentos, almacena los documentos en forma de JSON.  Habitualmente, cuando se hace referencia a ElasticSearch se habla del stack de elasticsearch (ELK/BELK):









  • ElasticSearch: Base de datos no relacional dónde se almacena información.
  • Logstash: Procesa y prepara los documentos para insertarlos dentro de elasticsearch.
  • Kibana: Herramienta de visualización de datos.
  • Beats: Envía logs a la plataforma ELK para que sean indexados en elasticsearch.




ELK Stack
Flujo de información ELK




¿Qué es Beats?





Como ya se ha comentado en el punto anterior, Beats es el encargado de enviar información a elasticsearch. Más que una pieza de software es un concepto, todos los shippers de la familia beats tienen en común que están escritos en Go y utilizan la librería libbeat para implementar el protocolo lumberjack v2 utilizado entre logstash y los shippers beats.  Existen múltiples shippers dentro de la família de beats. Los más comunes son:





  • Filebeat: Lee información de archivos de texto planos y los envía a logstash.
  • WinLogBeat: Envía logs de windows al Stack ELK.
  • PacketBeat: Captura paquetes en la red y los envía a ELK.
  • HeartBeat: Envía paquetes para saber si una máquina esta activa o no.
  • MetricBeat: Colecciona métricas de salud de las máquinas donde esta instalado y lo envía a ELK.
  • Y muchos más implementados por la comunidad




¿Cómo funciona Beats?





Tras mucho buscar no encontré nada en la red que me pudiera servir, todo el mundo terminaba usando el protocolo HTTP contra la API de Elasticsearch o contra una instancia de Logstash. Por esta razón, decidí investigar como funcionaba el protocolo de Beats. Este software implementa un protocolo conocido como Lumberjack en su segunda versión. Es un protocolo desarrollado inicialmente para logstash pero extendido y mejorado para ser más eficiente en su segunda versión.





La única información que encontré es el siguiente archivo en Github https://github.com/logstash-plugins/logstash-input-beats/blame/master/PROTOCOL.md#L12, dónde se explica vagamente el tipo de tramas que componen el protocolo pero no su uso.





Un paquete de Beats puede contener más de una trama la descripción básica de la trama es la siguiente:





### Framing

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +---------------+---------------+-------------------------------+
     |   version(1)  |   frame type  |     payload ...               |
     +---------------------------------------------------------------+
     |   payload continued...                                        |
     +---------------------------------------------------------------+



Cada trama es autocontenida y no está relacionada con la anterior. Para poder enviar una trama es necesario enviar una trama del tipo “Window” especificando el número de tramas de que se enviarán en el mismo paquete, si no se envía en el mismo paquete logstash no puede recontruir la información.  Despues de la trama window se añadirán tramas de datos (Json, Gzip, Data,..), por lo que un paquete de 3 mensajes tendría la siguiente forma:





|W(3)J(Payload1)J(Payload2)J(Payload3)|



Tras este mensaje el servidor debe responder con un ack y con el último mensaje procesado:





|A(3)|



Cómo no encontré nada hecho en PHP en GitHub decidí implementar mi propia implementación de lumberjack v2. La podéis encontrar en





https://github.com/berni69/libbeat-php





O si usáis composer, podéis instalarla con:





composer require berni69/libbeat



Una vez integrada en el proyecto, es tan sencilla de usar como:





use libbeat\BeatSender;
$beat = new  BeatSender('192.168.26.12', 5044);
$beat->send("test_log");
$beat->set_compression_rate(0);
$beat->send(["test_log2", "test_log3"]);



Este sencillo código permite enviar a logstash los mensajes “test_log”, test_log2 y test_log3 mediante el protocolo beats.





El caso típico de uso es enviar las excepciones de PHP al stack de elastic para poder depurar en caso de problemas. Esto es muy útil si se crea una cola dónde se van añadiendo todas las excepciones y un proceso asíncrono va procesando la cola y la va volcando a elastic usando el código anterior para no penalizar la ejecución de PHP.








3
Noticias del Blog / Security Headers en Wordpress
« en: Febrero 02, 2019, 02:28:15 pm »

Esta breve entrada tratará de enseñar como se debe configurar de manera segura una instalación de wordpress. El requisito para que esto funcione debe ser tener wordpress con un certificado seguro (SSL/TLS) configurado.





¿Qué son los security headers o encabezados/cabeceras de seguridad?





Son extensiones que proporciona el consorcio de W3C para proteger al usuario contra ataques malintencionados al navegador de un cliente. Este tipo de cabeceras son eficaces para bloqeuar recursos de terceros que no se cargan debidamente, o de dominios no confiables. Otras impiden que la web se cargue como un iframe o incrustada dentro de algún dipo de contenedor para evitar clickjacking (robo de clicks).





Una vez sabemos para que son las security headers, deberemos editar el archivo .htaccess  de nuestro wordpress:





Y añadir el siguiente bloque.





Options +FollowSymLinks -Indexes
php_flag display_errors Off
php_flag session.cookie_httponly on
php_flag session.cookie_secure on

RewriteCond %{REQUEST_METHOD} ^(TRACE|DELETE|TRACK) [NC]
RewriteRule ^(.*)$ - [F,L]

SetEnvIf Host ^www.bitsdelocos.es$ is_main_domain
Header set X-Content-Type-Options nosniff env=is_main_domain
Header set X-XSS-Protection "1; mode=block" env=is_main_domain
Header unset X-Powered-By env=is_main_domain
Header unset X-Pingback env=is_main_domain
Header unset SERVER env=is_main_domain
Header set Content-Security-Policy "default-src 'self' https: data: wss: 'unsafe-inline' 'unsafe-eval';" env=is_main_domain
Header set strict-transport-security "max-age=300; preload" env=is_main_domain





Las 4 primeras líneas impiden que se listen archivos en las carpetas que no poseen ningun index.php que cargue por defecto, se muestren errores que pueden exponer información sensible del servidor al haber un error o que se obtenga información de debug con los métodos trace y track del servidor apache.





La línea de SetEnvIf es útil si tenemos subdominios sin SSL y no queremos que esta configuración se herede en ellos, en caso de que todo esté securizado se puede eliminar y quitar “env=is_main_domain” de las demás.  





Con estas modificaciones se consigue añadir los headers necesarios para poder tener un wordpress seguro en la capa de “navegador”, y ocultar información sensible del servidor web que pudiera dar pistas a un atacante de nuestra infraestructura.








4
Noticias del Blog / SWifi Keygen 1.0.0.6
« en: Enero 17, 2019, 12:46:37 pm »

La forma más sencilla es con airodump, con el comando net wlan de windows se puede llegar a sacar pero no recuerdo la sintaxis o con netstubler (no se si aun funciona en las nuevas versiones de windows).



5
Noticias del Blog / Automatizando ACLs en SQUID
« en: Enero 03, 2019, 09:47:03 pm »

Buenas noches en esta entrada os traigo una forma muy sencilla de automatizar el uso de SQUID como proxy de nagevación temporal.





¿Qué es un proxy de navegación?I





Un proxy, o servidor proxy, en una red informática, es un servidor  —programa o dispositivo—, que hace de intermediario en las peticiones  de recursos que realiza un cliente (A) a otro servidor (C) (Wikipedia).





Proxy inverso/ Reverse Proxy
Arquitectura de un proxy inverso








Los proxys web son dispositivos que se utilizan para permitir, acelerar, inspeccionar  o  cachear peticiones a recursos web (HTTP/HTTPS). Esto permite reducir el ancho de banda usado, acelerar la navegación, o modificar contenido en función de reglas de capa 7. Este comportamiento es muy útil para poder controlar qué el tráfico que esta circulando por la red. Existen varios tipos de proxy según su arquitectura:





  • Proxys transparentes: Este tipo de proxys se añade de forma transparente en el flujo de la conexión de internet y el usuario sin que este tenga que configurar nada en su equipo (Las direcciones IP de origen y de destino no son alteradas)
  • Reverse Proxys: Este tipo de proxys instalan entre la entrada de internet y los servidores web, su funcionamiento se basa en cachean peticiones estáticas para liberar a los servidores web de tener que procesarlas cada vez que les llegan.
  • Forward Proxys: Este tipo d e proxys de navegación se encargan de cachear, aplicar ACLs, inspección de tráfico,.. pero es el usuario final que debe configurar el equipo para reenviar las peticiones al proxy.




Forward Proxy
Arquitectura del ForwardProxy




¿Qué es squid?





SQUID es un proxy open source (http://www.squid-cache.org/) pensado para optimizar el uso de la web implementando cachés de contenido. Puede funcionar tanto como reverse proxy como forward proxy, es decir, sirve para optimizar la navegación de internet como para mejorar el delivery de una página web.





Para instalar SQUID en Centos 7 basta con ejecutar :





    yum -y install epel-release
    yum -y update
    yum clean all
    yum -y install squid
    systemctl start squid
    systemctl enable squid



De este modo tendremos SQUID funcionando accesible desde todas las redes privadas, para una una instalación doméstica es suficiente pero si se desea hilar más fino, squid necesita algunos tuneos. Para que no se pueda conectar todo el mundo ni acceder a todo el contenido SQUID incorpora varias ACLs modificables a través de su configuración. (/etc/squid/squid.conf)






# Example rule allowing access from your local networks.
# Adapt to list your (internal) IP networks from where browsing
# should be allowed
acl localnet src 0.0.0.1-0.255.255.255 # RFC 1122 "this" network (LAN)
acl localnet src 10.0.0.0/8 # RFC 1918 local private network (LAN)
acl localnet src 100.64.0.0/10 # RFC 6598 shared address space (CGN)
acl localnet src 169.254.0.0/16 # RFC 3927 link-local (directly plugged) machines
acl localnet src 172.16.0.0/12 # RFC 1918 local private network (LAN)
acl localnet src 192.168.0.0/16 # RFC 1918 local private network (LAN)
acl localnet src fc00::/7       # RFC 4193 local private network range
acl localnet src fe80::/10       # RFC 4291 link-local (directly plugged) machines




¿Porqué no deberíamos dejar todos los rangos privado abiertos?





En una empresa, no todos los segmentos de red deben tener acceso libre a internet puesto que durante un ataque, simplifica mucho la instalación de software malicioso, el control del malware y la posible exfiltración de información.





¿Cómo securizarlo?





En una época donde la agilidad no es un mérito sino un requisito, es necesario implementar una solución que pueda ser ágil sin comprometer la integridad de los sistemas de la información. Por esta razón, tener que editar el archivo de configuración cada vez que un servidor debe conectarse es no es funcional. Por suerte, SQUID implementa un tipo de ACLs para llamar a scripts/binarios externos:





external_acl_type acl_ext ttl=10 %SRC /etc/squid/acl_ext.py
acl ExtAcl external acl_ext
http_access allow ExtAcl



Con estas tres líneas, SQUID será capaz de comunicarse con un componente externo enviando la dirección IP de origen, en este caso un script de Python que se conectará a una DB MySql dónde estarán las reglas de acceso:





#!/usr/bin/python

import mysql.connector
import sys
import logging

logger = logging.getLogger('squid_auth')
logger.setLevel(logging.DEBUG)
fh = logging.FileHandler('/var/log/squid_ext.log')
fh.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)


def match_acl(src):
    """USAGE:The function returns True if the user and passwd match False otherwise"""
    # Write your own function definition.
    # Use mysql, files, /etc/passwd or some service or whatever you want
    mydb = mysql.connector.connect(
        host="mydb.example.com",
        user="db_user",
        passwd="db_pwd",
        database="mydb"
    )
    mycursor = mydb.cursor()
    mycursor.execute("SELECT count(*) as c FROM squid_acls where valid_to >= now() and `start_ip` <= INET_ATON(%s) and `end_ip` >= INET_ATON(%s)",(src,src))
    myresult = mycursor.fetchall()
    logger.debug(myresult)
    return myresult[0][0] > 0


try:
    while True:
        # read a line from stdin
        src = sys.stdin.readline().strip()
        if src:
            if match_acl(src):
                logger.error("{}: OK".format(src))
                sys.stdout.write('OK\n')
            else:
                logger.error("{}: OK".format(src))
                sys.stdout.write('ERR\n')
            # Flush the output to stdout.
            sys.stdout.flush()
except Exception as ex:
    logger.error(ex)



Como backend tengo un una aplicación de Laravel que gestiona la tabla de mysql, el archivo de migración de esta tabla es:





<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddSquidAclTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('squid_acls', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('start_ip');
            $table->integer('end_ip');
            $table->timestamp('valid_to');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('squid_acls');
    }
}




El controlador de la API sería para esta tabla sería:





<?php

namespace App\Http\Controllers;

use App\Library\Networking\IpHelpers;
use App\Models\SquidAcl;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class SquidAclController extends Controller
{
    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        request()->validate([
            'ip' => 'required',
            'time' => 'required|numeric'
        ]);

        $range = IpHelpers::getIpRange($request->input('ip'));
        if ($range != null) {

            $squid = new SquidAcl();
            $squid->start_ip = $range['start_ip'];
            $squid->end_ip = $range['end_ip'];
            $squid->valid_to = DB::raw('NOW() + INTERVAL ' . $request->input('time') . ' MINUTE');
            $squid->save();
            return response()->json(['result' => 1]);
        }
        return response()->json(['result' => 0]);
    }
}




La clase IpHelper que se encarga de obtener los rangos de IPs contenidos en un CIDR, en una IP, o en un dominio:





<?php
namespace App\Library\Networking;

class IpHelpers
{

    public static function getIpRange($cidr)
    {
        if (self::isIpv4($cidr)) {
            $start = $end = ip2long($cidr);
            return array('start_ip' => $start, 'end_ip' => $end);
        } elseif (self::isCidr($cidr)) {

            list($ip, $mask) = explode('/', $cidr);

            $maskBinStr = str_repeat("1", $mask) . str_repeat("0", 32 - $mask);      //net mask binary string
            $inverseMaskBinStr = str_repeat("0", $mask) . str_repeat("1", 32 - $mask); //inverse mask

            $ipLong = ip2long($ip);
            $ipMaskLong = bindec($maskBinStr);
            $inverseIpMaskLong = bindec($inverseMaskBinStr);
            $netWork = $ipLong &amp; $ipMaskLong;

            $start = $netWork + 1;//ignore network ID(eg: 192.168.1.0)

            $end = ($netWork | $inverseIpMaskLong) - 1; //ignore brocast IP(eg: 192.168.1.255)
            return array('start_ip' => $start, 'end_ip' => $end);
        } else {
            putenv('RES_OPTIONS=retrans:1 retry:1 timeout:1 attempts:1');
            $cidr = gethostbyname($cidr);
            if (isset($cidr) &amp;&amp; self::isIpv4($cidr)) {
                return self::getIpRange($cidr);
            }
            return null;
        }

    }

    public static function isIpv4($ip)
    {
        return filter_var($ip, FILTER_VALIDATE_IP) !== false;
    }

    public static function isCidr($cidr)
    {
        $parts = explode('/', $cidr);
        if (count($parts) != 2) {
            return false;
        }

        $ip = $parts[0];
        $netmask = intval($parts[1]);

        if ($netmask < 0) {
            return false;
        }

        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
            return $netmask <= 32;
        }

        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
            return $netmask <= 128;
        }

        return false;
    }

}



Y para finalizar la ruta a la API:





Route::middleware('auth:api')->post('admin/squid/acl', 'SquidAclController@store');




Por ejemplo, si deseamos dar permisos temorales de conexión durante 60 minutos, bastaría con lanzar:





curl https://localhost/api/admin/squid/acl --data 'ip=192.168.33.33&amp;time=60' -H "Authorization: Bearer XXXXX" --http1.1



Donde XXXX es el token del usuario que tiene permisos para ejecutar esta acción.



6
Noticias del Blog / Automatizando ACLs en SQUID
« en: Enero 03, 2019, 08:09:45 pm »

7
Noticias del Blog / SWifi Keygen 1.0.0.6
« en: Enero 03, 2019, 07:50:49 pm »

Hola,


Arreglado el link


Saludos,



8

Me alegro que te haya servido!



9

Buenos días Eva, pues la verdad es que no conozco ningún servicio gratuito que permita lo que necesitas, lo que si conozco son servicios baratos. Por ejemplo, yo tengo unos VPS de arubacloud que cuestan 1€/mes y dominios que por 1 o 2 euros al año lo tienes.



10

Buenas tardes,


Hace ya algún tiempo publiqué una entrada haciendo referencia a túneling mediante SSH (https://www.bitsdelocos.es/2015/08/tunnel-ssh-con-raspbian-y-bitvisessh/). En esta entrada, versará sobre túneling sobre DNS (Domain Name Server). El concepto es el mismo: sobre un flujo de peticiones DNS insertar consultas forjadas de un modo conveniente parainyectar información de otro protocolo sobre DNS y así saltarse las protección de un firewall. La definición de un túnel en informática es:


Se conoce como túnel o tunneling a la técnica que consiste en encapsular un protocolo de red sobre otro (protocolo de red encapsulador) creando un túnel de información dentro de una red de computadoras.


Para poder llevar a cabo este escenario, necesitaremos:



  • Servidor: VPS o un equipo linux con una IP de internet estática.

  • Cliente: Sistema operativo linux o una máquina virtual con linux en su defecto.

  • Tener control sobre un dominio y sus entradas de DNS.

  • Tener chrome con la extensión SwitchyOmega.


La idea principal se basa en crear un subdominio al que se le harán las peticiones de DNS y un NS (Name Server o Servidor de nombres) al que enviar las peticiones malformadas. Necesitaremos añadir la siguiente configuración en nuestro DNS público:



  • tunel.bitsdelocos.es (NS apuntando a ns.bitsdelocos.es)

  • ns.bitsdelocos.es (A apuntando a la IP del VPS)


De este modo se conseguirá que todas las peticiones DNS del tipo xxxx.tunel.bitsdelocos.es se envíen a ns.bitsdelocos.es. Lo siguiente que necesitamos es montar un servidor de nombres que haga la función de resolver de paquetes generados maliciosamente que le lleguen. En este caso usaremos iodine (https://github.com/yarrick/iodine) . He usado debian 9 base como servidor de DNS. Para hacer el build de iodine necesitaremos ejecutar como super usuario:



apt-get install gcc make autoconf libz-dev git
git clone https://github.com/yarrick/iodine.git
cd iodine
make && make install

Si todo ha ido bien iodine estará instalado en nuestro sistema:



root@Debi:~# iodine -v
iodine IP over DNS tunneling client
Git version: 27e5d6f

Para hacer funcionar este servidor de DNS bastará con ejecutar:



iodined -c -P <PASSWORD> -n <IP ESTATICA> 172.16.0.1 tunel.bitsdelocos.es -F /var/run/iodine.pid

En el caso de que estemos usando la red local 172.16.0.0/24 podremos cambiar este rango por uno que no estemos usando.


Para comprobar que todo salió bien, se puede ejecutar el comando ip addr show para ver si se asignó una ip a la interfaz virtual dnsX:



root@Debi:~# ip addr show dev dns0
11: dns0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1130 qdisc pfifo_fast state UNKNOWN group default qlen 500
    link/none
    inet 172.16.0.1/27 scope global dns0
       valid_lft forever preferred_lft forever

En nuestro PC debemos ejecutar el cliente que nos levantará el túnel contra el NS ns.bitsdelocos.es haciendo uso de resoluciones DNS al subdominio tunel.bitsdelocos.es. Para ello lanzaremos iodine en el cliente del siguiente modo:



iodine  -P <PASSWORD> <IP DNS FORWARDER> tunel.bitsdelocos.es -F /var/run/iodine.pid

Donde   es la ip del forwarder que use la red a la que estamos conectados o bien un servidor externo como el NS de google (8.8.8.8). Si no ha habido errores se podrá levantar un proxy SOCKS5 con el comando SSH:



ssh -fN -D *:8080 root@172.16.0.1

La IP 172.168.0.1 es la ip que se le habrá asignado a la interfaz dnsX en el servidor.


Para comprobar que todo ha ido bien se debe instalar el plugin switchy omega en el navegador chrome y configurarlo:

 


La IP que aparece en la captura es la ip de la máquina virtual donde se está ejecutando el cliente de iodine.


Para comprobar si ha ido bien la configruación del proxy, debemos abrir una web y con F12 inspeccionar la ip remota de la página abierta, si corresponde con la ip de nuestro proxy significa que habrá funcionado.


Se ha configurado Switchy omega con Chrome.


Otro modo de comprobar si funciona es usando CURL en un terminal linux



[root@localhost ~]# curl --socks5-hostname  127.0.0.1:8080 www.bitsdelocos.es -v
* About to connect() to proxy 127.0.0.1 port 8080 (#0)
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: www.bitsdelocos.es
> Accept: */*
>
< HTTP/1.1 302 Found
< Server: openresty
< Date: Sun, 21 Oct 2018 15:52:40 GMT
< Content-Type: text/html; charset=iso-8859-1
< Content-Length: 211
< Connection: keep-alive
< Location: https://www.bitsdelocos.es/

Este método de túneling es mucho menos efectivo que el túnneling por ssh ya que el overhead introducido es mucho mayor.



11
Noticias del Blog / Shaping con nginx: Limitando CPS (II)
« en: Septiembre 10, 2018, 09:32:36 am »

Hace unos días, se me planteó el problema de limitar las CPS (conexiones por segundo a un servicio de APIs externo), por lo que mi primera idea fue limitarlo en el proxy de salida de los servidores (SQUID). Pero eso implicaba cambiar y tunear las IPtables de una forma poco dinámica ya que si el proveedor está en una CDN habría que montar un proceso de actualización de reglas,.. o bien limitarlo para todas las salidas externas del proxy con lo que no resultaba ser una buena opción así que seguí buscando,… en este caso encontré nginx como proxy inverso con el módulo limit_req_zone que permite hacer rate limiting de peticiones.


Siguiendo el esquema de la entrada anterior (Shaping con Iptables: Limitando CPS):



Y la misma arquitectura de pruebas:

























Nombre del ServidorIPDescripción
shaper0110.112.112.101Nginx Reverse Proxy
webserver0110.112.112.102Servidor web con nginx
server0110.112.112.106Envío de tráfico

Para simplificar configuraciones, y la lectura de los scripts se han hecho 2 suposiciones.



  1. Tenemos acceso privilegiado a la máquina (sudo -i) o similar.

  2. En el archivo de hosts (/etc/hosts) de cada máquina se ha añadido lo siguiente:
    10.112.112.101 shaper01
    10.112.112.102 webserver01
    10.112.112.106 server01



Para las pruebas se ha habilitado la siguiente zona en nuestro nginx (/etc/nginx/conf.d/rate-limit.conf):



limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
server {
    listen       80;
    server_name  shaper01;
    location / {
       limit_req zone=mylimit;
       proxy_set_header Host "webserver01";
       proxy_pass http://webserver01;

    }
}

En esta zona se indica que todas las peticiones con el server_name “shaper01”, en la ruta / e hijas se aplicará un rate-limiting de 10r/s, y tras aplicar esta  limitación serán reenviadas las peticiones contra el servidor webserver01.


El único cambio que hay que hacer en el programa cliente es la url dónde apuntarán sus peticiones, en este caso, se deberán abrir contra el servidor shaper01 en lugar del endpoint de la API.


Las pruebas se han lanzado con curl igual que en la entrada anterior:



while [ 1 ]; do curl shaper01 -s > /dev/null; done

Tras analizar los resultados del nginx del server web, podemos afirmar que está funcionando el rate-limiting.


Conexiones Por segundo usando nginx



12
Noticias del Blog / Shaping con Iptables: Limitando CPS
« en: Septiembre 07, 2018, 10:33:16 pm »

Buenas noches, después de mucho tiempo sin pasarme por aquí, esta noche os traigo una pequeña entrada para ver como se puede configurar un rate limiting (shaping) en función de las conexiones por segundo en lugar del por ancho de banda (bandwidth).


Durante el transcurso de esta semana, me han consultado si se podría limitar el consumo de una API REST de un proveedor externo a priori no debería ser mucho problema, cuando te piden esto lo primero que piensas es en limitar el ancho de banda consumido en un packetshaper/firewall aplicando políticas de QoS. Pero esta vez, se solicitó que se limitara por transacciones por segundo permitidas. Tras revisarlo con los compañeros nunca habíamos montado nada así por lo que me he dispuesto a investigar un poco más y he llegado la solución que os contaré en este post.


En la siguiente imagen se describe la arquitectura inicial, en el recuadro rojo se muestra que existen N instancias de una aplicación que competirán por 10 conexiones por segundo contra la API externa (verde).





Por definición las aplicaciones intentan usar todos los recursos que pueden para llevar a cabo su cometido lo más rápido posible.


La arquitectura propuesta para poder limitar realizar el rate-limiting de salida contra la API externa, pasa por montar un proxy HTTP (en este caso squid pero valdría cualquier proxy http/https) que tenga visibilidad sobre todas las conexiones que se realizan a la API y en él crear una política de de connection_tracking con Iptables. De este modo la arquitectura quedaría de la siguiente forma:



Para hacer la prueba de concepto he montado 3 máquinas linux con Centos 7 (1GB de RAM cada una y dos núcleos deberían sobrar para la prueba). A partir de ahora las máquinas recibirán el nombre:

























Nombre del ServidorIPDescripción
shaper0110.112.112.101Squid + Iptables
webserver0110.112.112.102Servidor web con nginx
server0110.112.112.106Envío de tráfico

Para simplificar configuraciones, y la lectura de los scripts se han hecho 2 suposiciones.



  1. Tenemos acceso privilegiado a la máquina (sudo -i) o similar.

  2. En el archivo de hosts (/etc/hosts) de cada máquina se ha añadido lo siguiente:
    10.112.112.101 shaper01
    10.112.112.102 webserver01
    10.112.112.106 server01



En el servidor webserver01, he instalado un nginx de prueba para que nos sirva contenido estático y poder ver sus logs:


yum install epel-release
yum install nginx
systemctl enable nginx
systemctl start nginx

En el servidor shaper01 he instalado squid y iptables:



yum install epel-release -y
yum install iptables-services -y
yum -y install squid
echo "cache deny all" >> /etc/squid/squid.conf
systemctl restart iptables squid
systemctl enable iptables squid

En este punto Iptables estan bloqueando todo el tráfico por defecto por que en los siguientes comandos, voy a resetear estos parámetros (no lo hagáis así si ya está instalado y tiene reglas por configuradas):



iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
iptables -t nat -F
iptables -t mangle -F
iptables -F
iptables -X

El siguiente paso es configurar las reglas para limitar el número de conexiones por segundo:



iptables --new-chain RATE-LIMIT
iptables --append INPUT  --match conntrack --ctstate NEW --jump RATE-LIMIT
iptables --append RATE-LIMIT \
    --match hashlimit \
    --hashlimit-mode dstip \
    --hashlimit-upto 10/sec \
    --hashlimit-burst 9 \
    --hashlimit-name conn_rate_limit \
    --jump ACCEPT
iptables --append RATE-LIMIT --jump REJECT

Con este comando creamos una nueva “cadena” en iptables que se ejecutará cuando haya una nueva conexión y no haya hecho match con ninguna regla existente.

Explicación del comando:



  1. match hashlimit: Tipo de plugin de iptables que se aplicará en este caso hashlimit (variación avanzada del módulo de limits)

  2. hashlimit-mode dstip: Permite agrupar los (CPS) por ip de destino, origen,..  

  3. hashlimit-upto 10/sec: Número de conexiones máximas por unidad de tiempo

  4. hashlimit-burst 9: Ráfaga máxima soportada

  5. hashlimit-name conn_rate_limit: Nombre con el que guardara la información internamente

  6. jump REJECT: Acción por omisión permite hacer ACCEPT/DROP/REJECT. Se ha creado con reject porque avisa al origen de que no es posible establecer la conexión. Si se hiciera con DROP la aplicación quedaría esperando hasta obtener un TimeOut ralentizando mucho el proceso de captura de errores y reintentos.


En el servidor server01, se ha configurado el un curl para que use nginx y vaya haciendo peticiones:



export http_proxy="http://shaper01:3128"
export https_proxy="http://shaper01:3128"
while [ 1 ]; do curl webserver01 -s > /dev/null; done

Si todo ha ido bien en el nginx deberíamos ver logs como el siguiente:



10.112.112.101 - - [07/Sep/2018:19:49:58 +0000] "GET / HTTP/1.1" 200 3700 "-" "curl/7.29.0" "10.112.112.106"

Para comprobar que está funcionando correctamente, he lanzado el while con el curl en el server01 sin haber activado las iptables y tras un tiempo he ejecutado los comandos para hacer el rate-limiting. Tras esto he analizado el fichero de log de nginx con algo de ayuda de bash y excel:



cat access.log  | cut -d " " -f 4 | uniq -c
      3 [07/Sep/2018:21:03:12
     74 [07/Sep/2018:21:03:13
     74 [07/Sep/2018:21:03:14
     74 [07/Sep/2018:21:03:15
     75 [07/Sep/2018:21:03:16
     75 [07/Sep/2018:21:03:17
     75 [07/Sep/2018:21:03:18
     74 [07/Sep/2018:21:03:19
     74 [07/Sep/2018:21:03:20
     74 [07/Sep/2018:21:03:21
     74 [07/Sep/2018:21:03:22
     75 [07/Sep/2018:21:03:23
     74 [07/Sep/2018:21:03:24
     75 [07/Sep/2018:21:03:25
     74 [07/Sep/2018:21:03:26
     75 [07/Sep/2018:21:03:27
     75 [07/Sep/2018:21:03:28
      9 [07/Sep/2018:21:03:29
     11 [07/Sep/2018:21:03:46
     10 [07/Sep/2018:21:03:47
     10 [07/Sep/2018:21:03:48
     10 [07/Sep/2018:21:03:49
     10 [07/Sep/2018:21:03:50
     10 [07/Sep/2018:21:03:51
      8 [07/Sep/2018:21:03:52
      8 [07/Sep/2018:21:03:53
     10 [07/Sep/2018:21:03:54
     10 [07/Sep/2018:21:03:55
     10 [07/Sep/2018:21:03:56
     10 [07/Sep/2018:21:03:57
     10 [07/Sep/2018:21:03:58

Si graficamos la información, se observa claramente el momento dónde he activado el rate-limiting:


Espero que os resulte de utilidad o almenos entretenida la lectura.



13
Noticias del Blog / SWifi Keygen 1.0.0.6
« en: Mayo 23, 2018, 12:30:12 pm »

Buenas tardes,

He corregido los links de descarga.

Saludos,



14
Noticias del Blog / Integración OSSIM - Elasticsearch
« en: Febrero 22, 2018, 10:35:29 am »

Qué es ossim?


El software de seguridad OSSIM, del inglés  Open Source Security Information Management, es un conjunto de herramientas de seguridad (recogida de logs, monitorización, escaneo de vulnerabilidades,…) orquestadas para conseguir una solución de seguridad capaz  de correlacionar y detectar eventos de seguridad y vulnerabilidades en una infraestructura  determinada.


Tras haber gestionado ossim, me he dado cuenta que la integración de OSSIM con el mundo exterior es algo complicada.. expresiones regulares, creación de nuevos plugins, tener que pasar siempre por syslog,… Para evitar estos problemas se ha desarrollado un nuevo datasource de ossim para permitir la integración de OSSIM con elasticsearch.


El código se encuentra en mi repositorio público:


https://github.com/berni69/ossim-agent-elasticsearch


El código que se debe añadir a ossim es:


ParserElastic.py

ElasticDetector.py


Además se debe modificar el componente Agent.py (línea 559 aprox) para añadir un nuevo tipo de datasource.



                elif plugin.get("config", "source") == "elasticsearch":
                    parser = ParserElastic(self.conf, plugin, None)
                    parser.start()
                    self.detector_objs.append(parser)

Para que esto funcione se debe añadir la librería de elasticsearch para python:



pip install elasticsearch

Ejemplo de configuración:


https://raw.githubusercontent.com/berni69/ossim-plugins-elasticsearch/master/elasticsearch-example.cfg



15
Noticias del Blog / Mantén tus dispositivos actualizados con Ansible
« en: Diciembre 07, 2017, 12:43:23 am »

Si te gusta cacharrear como a mi, al final terminas teniendo varios dispositivos conectados a la red de tu casa y otros tantos distribuidos en el cloud, una de las tareas más tediosas a las que te puedes enfrentar es irlos actualizado a medida que pasa el tiempo. No a todos estos dispositivos me conecto habitualmente por lo que no siempre recuerdo actualizarlos, para solucionar esto he decidido que voy a usar Ansible. Esta pieza de software se define como:



Ansible es categorizado como una herramienta de orquestación. Maneja nodos a través de SSH y no requiere ningún software remoto adicional (excepto Python 2.4 o posterior para instalarlo). Wikipedia


Para poder instalar Ansible es necesario disponer de Pip y Python en nuestro sistema. Yo lo decidí instalar en mi Raspberry Pi por lo que además tuve que instalar software adicional:



apt-get update
apt-get upgrade python
apt-get install libssl-dev libffi5-dev python-dev build-essential
cd /tmp/
wget wget https://bootstrap.pypa.io/get-pip.py
python get-pip.py
pip install ansible

Dependiendo de la velocidad de la tarjeta SD de tu Raspberry Pi y la versión de ésta, puede tardar casi una hora en instalar todo el software necesario.


Una vez instalado el software, debemos crear el inventario de máquinas en /etc/ansible/hosts



mkdir /etc/ansible/
touch /etc/ansible/hosts

En mi caso voy a crear un grupo de servidores llamado servers que contiene un servidor vps y 2 raspberrys:



[servers]
mivps.example.com   ansible_connection=ssh  ansible_user=root
rpi1                ansible_connection=local #Host donde ejecuto ansible
rpi2                ansible_connection=ssh  ansible_user=pi    ansible_host=192.168.1.13

Donde la primera columna es el nombre del dispositivo al que nos vamos a conectar, ansible_host es la ip en el caso de que el nombre no se pueda resolver por dns y ansible_user es el usuario que usará ansible para conectarse al dispositivo.


Habitualmente, si no se especifica lo contrario, ansible intentará usar la clave ssh del usuario local para conectarse a los servidores remotos, si el usuario no tiene ninguna clave ssh generada, la crearemos.



mkdir $HOME/.ssh
chmod 600 $HOME/.ssh
ssh-keygen -t ecdsa -C "miusuario@miequipo"

Este proceso debe generar 2 claves (pública y privada) llamadas ~/.ssh/id_ecdsa.pub y ~/.ssh/id_ecdsa. Debemos copiar la clave pública (.pub) en el archivo authorized_keys del servidor remoto, para ello ejecutaremos el comando:



ssh-copy-id -i ~/.ssh/id_ecdsa root@mivps.example.com

Si queremos probar que se han copiado las claves ssh correctamente y tenemos acceso podemos ejecutar el comando



root@rpi1:~# ansible servers -m ping
mivps.example.com | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
rpi1 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
rpi2 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}


Si todos los hosts aparecen como success, es que la instalación de claves ha ido correctamente.


Una vez copiadas todas las claves en los servidores, debemos crear el archivo /etc/ansible/update.yml:



---

- hosts: servers
  become: true
  become_user: root
  become_method: sudo
  tasks:
    - name: Update packages list [APT]
      apt: update_cache=yes
      when: ansible_os_family == 'Debian'
    - name: Upgrade packages [APT]
      apt: upgrade=safe
      when: ansible_os_family == 'Debian'
    - name: Upgrade packages [YUM]
      yum:
        name: '*'
        state: latest
        update_cache: yes
      when: ansible_os_family == 'RedHat'

Para finalizar, debemos lanzar el comando



root@rpi1:~# ansible-playbook /etc/ansible/update.yml

PLAY [servers] *********************************************************************************************************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************************************************************************************************
ok: [mivps.example.com]
ok: [rpi2]
ok: [rpi1]

TASK [Update packages list] ********************************************************************************************************************************************************************************
changed: [mivps.example.com]
changed: [rpi2]
changed: [rpi1]

TASK [Upgrade packages] ************************************************************************************************************************************************************************************
changed: [mivps.example.com]
changed: [rpi1]
changed: [rpi2]

PLAY RECAP *************************************************************************************************************************************************************************************************
mivps.example.com          : ok=3    changed=2    unreachable=0    failed=0  
rpi1                       : ok=3    changed=2    unreachable=0    failed=0  
rpi2                       : ok=3    changed=2    unreachable=0    failed=0  


Si todos los hosts aparecen como 0 failed y 0 unreachable es que la ejecución del script ha ido correctamente.



Páginas: [1] 2 3 ... 76