Build an OpenStreetMap server on Ubuntu 10.04

Index
1.-Introduction
2.-Let’s start
3.-Preparing the database
4.-Install Mapnik library
5.-Install prepared world boundary data
6.-Render your first map
7.-Troubleshooting

1.-Introduction

Firstly I woudl like to thank “rw”, the author of the post this post is about. This post is based (95%) on this one (currently not available, but you can check it out here)

My main intention is spread this post to all my viewers and save here this knowledge about OSM platform to have at least an online reference for everyone (and of course, for me). This is neither an introduction nor post information about OSM, but just technical info about building up your own OSM server. I also would like to improve my knowledge about this server (I don’t want just to download, install and run it, it would be nice trying to understand it).

I won’t just copy and paste the same content of there, because (as an ordinary large installation) I had problems installing this platform and I solved then, so I will write here everything I saw, I solved, and my personal conclusions. I also will go in depth in some issues like explaining some commands and stuff.

2.-Let’s start

Upgrade your system

Just for security issues, it is recommended to update and upgrade your system, but not necessary.

sudo apt-get update
sudo apt-get upgrade

Get some system tools

sudo apt-get install subversion autoconf screen munin-node munin htop

Subversion: we’ll use it to donwload files from some repositories.
Autoconf: software to generate autoconfig scripts.
Screen: Screen is a full-screen window manager that multiplexes a physical terminal between several processes, typically interactive shells.
Munin-node: software to monitoring our server from the client.
Munin: client of munin-node.
Htop: software to check and monitoring the system used resources.

Organize your filesystem a bit

cd ~
mkdir src bin planet

  • src: source of mapnik.
  • bin: here we’ll have the scripts to generate the image and load the database.
  • planet: planet (or piece) database we’re gonna build up.

Get the latest planet (OSM file)

Well, in this part we can download the entire world wide database (nowadays [20 dec 2012] is 24GBs) or maybe we can download not the world but a piece. Just for testing I will choose download a piece.

cd planet
wget http://planet.openstreetmap.org/planet-latest.osm.bz2

3.-Preparing the database

Here we’re gonna download postgresql to deploy our own database there and some required libraries to use it.

sudo apt-get install postgresql-8.4-postgis postgresql-contrib-8.4
sudo apt-get install postgresql-server-dev-8.4
sudo apt-get install build-essential libxml2-dev
sudo apt-get install libgeos-dev libpq-dev libbz2-dev proj

Build-essential: This package contains an informational list of packages which are considered essential for building Debian packages.
Libxml2-dev: Very useful if you wish to develop your own programs using the GNOME XML library.
Libgeos-dev: GEOS provides a spatial object model and fundamental geometric functions. It implements the geometry model defined in the OpenGIS Consortium Simple Features Specification for SQL.
Libpq-dev: Header files and static library for compiling C programs to link with the libpq library in order to communicate with a PostgreSQL database backend.
Libbz2-dev: Static libraries and include files for the bzip2 compressor library.
Proj: Standard Unix filter function which converts geographic longitude and latitude coordinates into cartesian coordinates, by means of a wide variety of cartographic projection functions.

Install osm2pgsql from the repository

We firstly download osm2pgsql from the repository and after that, configurate it. osm2pgsql is a utility program that converts OpenStreetMap data to PostgreSQL databases.

cd ~/bin
svn co http://svn.openstreetmap.org/applications/utils/export/osm2pgsql/
cd osm2pgsql
./autogen.sh (Error?)
./configure
make

Configure the PostGIS database

edit /etc/postgresql/8.4/main/postgresql.conf in four places. These changes help with the large quantities of data that we are using.

107: shared_buffers = 128MB # 16384 for 8.1 and earlier
170: checkpoint_segments = 20
(new line): maintenance_work_mem = 256MB # 256000 for 8.1 and earlier
387: autovacuum = off

edit /etc/sysctl.conf

(new line) kernel.shmmax=268435456

Remind that the above only takes effect after a reboot. Making this work immediately requires the following.

sudo sysctl kernel.shmmax=268435456

Restart postgres to enable the changes.

sudo /etc/init.d/postgresql-8.4 restart

Create a database called “gis”. Some of our future tools presume that you will use this database name. Substitute your username for “username” in two places below. This should be the username that will render maps with mapnik.
Note from delanover author: I had problems with the username so I decided to use the same username that in the computer server system.

sudo -u postgres -i
createuser username # answer yes for superuser
createdb -E UTF8 -O username gis
createlang plpgsql gis
exit

Set up PostGIS on the postresql database.

psql -f /usr/share/postgresql/8.4/contrib/postgis.sql -d gis

This should respond with many lines ending with


CREATE FUNCTION
COMMIT

Substitute your username for “username” in two places in the next line. This should be the username that will render maps with mapnik.

echo “ALTER TABLE geometry_columns OWNER TO username; ALTER TABLE spatial_ref_sys OWNER TO username;” | psql -d gis

Should reply with

ALTER TABLE
ALTER TABLE

Enable intarray

psql -f /usr/share/postgresql/8.4/contrib/_int.sql -d gis

Replies with many lines ending with


CREATE FUNCTION
CREATE OPERATOR CLASS

Set the Spatial Reference Identifier (SRID) on the new database.

psql -f ~/bin/osm2pgsql/900913.sql -d gis

Should reply with

INSERT 0 1

Load planet into the database with osm2pgsql

cd ~/bin/osm2pgsql
./osm2pgsql -S default.style –slim -d gis -C 2048 ~/planet/YourFileMap.osm.bz2 (Error?)

Note: load 8.4GB take 30 hours, and particularly 1.4GB took me 3-4 hours (it depends of the I/O), so be patient.

Completed planet_osm_roads
Copying planet_osm_polygon to cluster by geometry finished
Copying planet_osm_line to cluster by geometry finished
Creating indexes on planet_osm_polygon finished
All indexes on planet_osm_polygon created in 4257s
Completed planet_osm_polygon
Creating indexes on planet_osm_line finished
All indexes on planet_osm_line created in 5053s
Completed planet_osm_line
Stopped table: planet_osm_ways in 16095s
Osm2pgsql took 29436s overall

4.-Install Mapnik library

sudo apt-get install libltdl3-dev libpng12-dev libtiff4-dev libicu-dev
sudo apt-get install libboost-python1.40-dev python-cairo-dev python-nose
sudo apt-get install libboost1.40-dev libboost-filesystem1.40-dev
sudo apt-get install libboost-iostreams1.40-dev libboost-regex1.40-dev libboost-thread1.40-dev
sudo apt-get install libboost-program-options1.40-dev libboost-python1.40-dev
sudo apt-get install libfreetype6-dev libcairo2-dev libcairomm-1.0-dev
sudo apt-get install libgeotiff-dev libtiff4 libtiff4-dev libtiffxx0c2
sudo apt-get install libsigc++-dev libsigc++0c2 libsigx-2.0-2 libsigx-2.0-dev
sudo apt-get install libgdal1-dev python-gdal
sudo apt-get install imagemagick

Libltdl3-dev: A small library that aims at hiding the various difficulties of dlopening libraries from programmers. It is a system independent dlopen wrapper for GNU libtool.
Libpng12-dev: Library implementing an interface for reading and writing PNG format files.
Libtiff4-dev: Library providing support for the Tag Image File Format (TIFF), a widely used format for storing image data. This package includes the development files, static library, and header files.
Libicu-dev: ICU is a C++ and C library that provides robust and full-featured Unicode and locale support. This package contains the development files for ICU along with programs used to manipulate data files found in the ICU sources.
Libboost libraries: Boost provides free peer-reviewed portable C++ source libraries.
Python libraries: So obvious.
Libfreetype6-dev: This package contains all supplementary files (static library, headers and documentation) you need to develop your own programs using the FreeType 2 library (digital typography library).
Libcairo2-dev: Cairo is a multi-platform library providing anti-aliased vector-based rendering for multiple target backends.
Libgeotiff-dev: The GeoTIFF standard has been developed for reading, and writing geographic meta-information tags on top of TIFF raster.
Tiff libraries: So obvious, to work with tiff format.
Libsigc libraries: implement a typesafe callback system for standard C++. It allows you to define signals and to connect those signals to any callback function, either global or a member function, regardless of whether it is static or virtual.
Libgdal1-dev: GDAL is a translator library for raster geospatial data formats. As a library, it presents a single abstract data model to the calling application for all supported formats.
Imagemagick: software suite to create, edit, compose, or convert bitmap images.

Build Mapnik library from source.

cd ~/src
svn co http://svn.mapnik.org/tags/release-0.7.1/ mapnik (Error? offline)
cd mapnik
python scons/scons.py configure INPUT_PLUGINS=all OPTIMIZATION=3 SYSTEM_FONTS=/usr/share/fonts/truetype/ (Error? boost version)
python scons/scons.py #be patient here
sudo python scons/scons.py install
sudo ldconfig

Confirm that Mapnik library is installed.

python
>>> import mapnik
>>>

Install Mapnik tools

cd ~/bin
svn co http://svn.openstreetmap.org/applications/rendering/mapnik

5.-Install prepared world boundary data

cd ~/bin/mapnik
mkdir world_boundaries
wget http://tile.openstreetmap.org/world_boundaries-spherical.tgz
tar xvzf world_boundaries-spherical.tgz
cd world_boundaries
wget http://tile.openstreetmap.org/processed_p.tar.bz2
bunzip2 processed_p.tar.bz2
tar xvf processed_p.tar
wget http://tile.openstreetmap.org/shoreline_300.tar.bz2
bunzip2 shoreline_300.tar.bz2
tar xvf shoreline_300.tar

6.-Render your first map

cd ~/bin/mapnik
chmod +x generate_xml.py
./generate_xml.py –dbname gis –accept-none [IMPORTANT NOTE]

IMPORTANT NOTE: I don’t know why but the double hyphen is not seen. Remember is “–” (two “-“) and not only one “-“.

Include files written successfully! Pass the osm.xml file as an argument if you want to serialize a new version or test reading the XML

Now we finally generate the image.

./generate_image.py (Error?)

The result of this is having a 10000x5000px PNG image of England en your mapnik folder. Remember, be patient.

Hope you enjoy this tutorial!

7.-Troubleshooting

Error 1: Configuring at installing osm2pgsql
Output error at performing ./configure when installing osm2pgsql:

Can’t exec “libtoolize”: No such file or directory at /usr/bin/autoreconf line 189.
Use of uninitialized value in pattern match (m//) at /usr/bin/autoreconf line 189.
autoreconf: Entering directory `.’
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal –force -I m4
configure.ac:41: warning: macro `AM_PROG_LIBTOOL’ not found in library
autoreconf: configure.ac: tracing
autoreconf: configure.ac: not using Libtool
autoreconf: running: /usr/bin/autoconf –force
configure.ac:41: error: possibly undefined macro: AM_PROG_LIBTOOL
If this token and others are legitimate, please use m4_pattern_allow.
See the Autoconf documentation.
autoreconf: /usr/bin/autoconf failed with exit status: 1

Solution
You can’t exec libtoolize, so you must install libtool before continue, writting down:

sudo apt-get install libtool

Error 2: Loading planet into the database
Maybe you get this error while loading the data:

The target database has the intarray contrib module loaded.
While required for earlier versions of osm2pgsql, intarray
is now unnecessary and will interfere with osm2pgsql’s array
handling. Please use a database without intarray.

Error occurred, cleaning up

To fix it, we’ll do some fix located in the official documentation.

sudo -u postgres -i -H
dropdb ptgis
### here the old database is dropped
createdb -E UTF8 -O ptuser ptgis
createlang plpgsql ptgis

# for Ubuntu <=9.10: # psql -d ptgis -f /usr/share/postgresql/8.3/contrib/_int.sql ### (do not execute this line) psql -d ptgis -f /usr/share/postgresql-8.3-postgis/lwpostgis.sql # for Ubuntu >=10.04:
#psql -d ptgis -f /usr/share/postgresql/8.4/contrib/_int.sql ### (do not execute this line)
psql -d ptgis -f /usr/share/postgresql/8.4/contrib/postgis.sql
psql ptgis -c “ALTER TABLE geometry_columns OWNER TO ptuser”
psql ptgis -c “ALTER TABLE spatial_ref_sys OWNER TO ptuser”
exit

# for Ubuntu <=9.10: sudo /etc/init.d/postgresql-8.3 reload # for Ubuntu >=10.04:
sudo /etc/init.d/postgresql-8.4 reload

psql ptgis ptuser -f osm2pgsql/900913.sql

Now, we try to load the data again.

Error 3: Offline mapnik repository
I set this up as an error because who knows, maybe someday is online again. But now it is not, so let’s find another place to download it.
We need to download git software in order to download from a git repository, and after that, we’ll be able to download mapnik from here

sudo apt-get install git-core
git clone https://github.com/mapnik/mapnik.git

Error 4: Boost version >= 1.47 required
We can actually check our boost version looking at line 30 in /usr/include/boost/version.hpp file to realize that we don’t have 1.47 version or greater, so, we have to upgrade it. This is not that simple than apt-get install, but is this simple: download and install it.

We need to download the last version (http://www.boost.org/) (nowadays, 1.52, from http://sourceforge.net/projects/boost/files/boost/1.52.0/). We select tar.bz2 file, unzip it, configure it and so on.

bunzip2 boost_1_52_0.tar.bz2
tar xvf boost_1_52_0.tar
./bootstrap.sh
./b2
sudo ./b2 install

Error 5: Needed files don’t exist!
After trying to generate the image (what a bad luck, failing in the last step…) this error might be returned to you.

RuntimeError: Shape Plugin: shapefile ‘/home/lipman/bin/mapnik/world_boundaries/110m_admin_0_boundary_lines_land.shp’ does not exist encountered during parsing of layer ‘necountries’ in Layer at line 58 of ‘osm.xml’

The only problem here is we need many files that we don’t have, so let’s download and move them to fix it into world_boundaries folder.
I found that files here. We have to donwload this below:

  • 110m_admin_0_boundary_lines_land.shp
  • 110m_admin_0_boundary_lines_land.dbf
  • 10m_populated_places.shp (*)
  • 10m_populated_places.dbf (*)

(*): We have to rename them to “ne_10m…”

¿Entradas ARP Estáticas contra ataques Man in the Middle?

Un poco de teoría sobre MitM y ARP

El protocolo ARP es el encargado de traducir de direcciones IP a MAC (y el inverso, traduce de MAC a IP lógicamente). Cuando estamos conectados a internet desde un portátil a traves de una red wireless, usamos este protocolo para saber a dónde tenemos que enviar nuestros paquetes (al router claramente) para que puedan ir a través de Internet y demás.

El envenenamiento de las tablas ARP consiste en decirle al ordenador víctima desde el ordenador atacante “el router se encuentra en esta otra dirección (la del atacante)”. De esta manera, la víctima piensa que le está enviando los paquetes al router, y realmente se los envía al atacante. Así, éste puede ver todo el tráfico de la víctima, que luego redirige al router, y realiza el camino inverso.

En la siguiente imagen, vemos una tabla ARP normal. Subrayado y en primer lugar, tenemos la dirección del router. Luego, dos direcciones de un par de equipos, broadcast, etc. Aquí no hay nada raro, está todo en orden.

Ahora, vamos a envenenar la tabla ARP desde un ordenador atacante.
Como podemos ver, aparece otro ordenador con IP 192.168.2.103 (el atacante), y la MAC del router ha cambiado. Si os dais cuenta, es la misma que la del atacante.

Nota: para ver la tabla ARP desde Windows se hace mediante arp -a

Solución: ¿Poner entradas ARP estáticas?

Teóricamente, si ponemos entradas estáticas estamos seguros, ya que de esta forma ningún atacante puede cambiarlas para hacer pensar al ordenador víctima que el router está en otra dirección distinta. ¿Es lógico no? Si no se puede cambiar esto, se enviará siempre hacia el router.

Pues bien, vamos allá. Poner entradas ARP estáticas en Windows es más complicado que usar simplemente el comando ARP. Nuestra primera intención es hacerle caso a lo que nos dice la ayuda de ARP de la consola, y es usar:

arp -s IP MAC

Pero no funciona. Como he dicho, es algo más complicado. De hecho, uno de los motivos de crear esta entrada es para guardar cómo se hace, y así no tener que buscarlo si en un futuro es requerido hacerlo.

Primero de todo, necesitamos saber el nombre de la conexión. Para ello lo hacemos mediante:

netsh interface ip show config

Como podemos ver, el nombre de mi conexión es “Conexión de red inalámbrica”.
Después, ejecutamos el siguiente comando:

netsh interface ipv4 add neighbors “NOMBRE_CONEXIÓN” IP MAC

Importante: daros cuenta que la MAC está separada por guiones y no por dos puntos.

Volvemos a reproducir el ataque

¿Qué sucede si reproducimos de nuevo el ataque? ¿Seremos completamente invulnerables? La respuesta es no, no estamos seguros. Y ahora viene el porqué: el envenenamiento de la tabla ARP consiste en enviar paquetes hacia la víctima y el router para que le envien los paquetes al atacante. De esta forma ve todo lo que va de la víctima al router (y por tanto hacia Internet) y viceversa. Si le decimos al ordenador víctima que el router está en una dirección (con entradas estáticas), el router todavía seguirá pensando que el ordenador atacante es en realidad el de la víctima.

Paquetes ARP que envía el atacante. Como podemos ver, le dice al router “la dirección del ordenador (víctima) está en mi MAC” y le dice a la víctima “la dirección del router está en mi MAC”.

Un dibujo de cómo quedaría ahora el envío de paquetes:

Conclusiones

Principalmente de este asunto saco dos conclusiones importantes.
La primera de todas es, que para que sea realmente seguro, habría que poner estática también la entrada ARP del router que vaya dirigida hacia el ordenador. De esta forma no se alteraría nada de nada, y todo iría por su camino correspondiente.

La segunda conclusión es la siguiente: ¿realmente nos merece la pena poner entradas estáticas en nuestro ordenador en caso de no poder hacerlo en el router? Me explico: si no lo hacemos en el router, el atacante podrá obtener los paquetes que vienen del router (e Internet) hacia la victima y no los otros vale, pero es interesante tener las entradas dinámicas, para que si un atacante nos envenena nuestra tabla, nos demos cuentas (hay programas que detectan cuando una tabla ARP es cambiada y nos avisan, como Marmita).

Conclusión de las conclusiones: si podemos poner estáticas las entradas del ordenador y el router perfecto. Si no, es interesante dejarlas dinámicas y tener un programa que nos avise cuando sean cambiadas.

IPTables (filter)

El objetivo de esta entrada es recopilar funciones así como definiciones básicas sobre IPTables, más concretamente de la tabla filter. Si hay algo mal explicado, confuso, que está mal, o que no está, os animo a que me aviséis para poder mejorarlo. Por otra parte, esta entrada no busca ser algo ultra profesional, ni tener mil ejemplos (solo los justos para su entendimiento), ni definiciones complicadas y detalladas.

INDICE
1.-Definición IPTables
2.-Estructura de las reglas
3.-Algunas notas teóricas sobre cómo funciona IPTables
4.-Tabla FILTER
    4.1.-El parámetro Match (-m)
    4.2.-El protocolo TCP
    4.3.-Ejemplos
5.-Comandos
6.-Parámetros

1.-Definición IPTables

IPTables, framework localizado en el núcleo de Linux, permite el tratamiento de paquetes de red. De esta forma, podemos administrar todos los paquetes que pasan por nuestra máquina, y realizar con ellos lo que creamos conveniente, funcionando así como cortafuegos.

2.-Estructura de las reglas

  • FILTER: Filtrado de paquetes
    • INPUT
    • OUTPUT
    • FORWARD
  • NAT
  • MANGLE

3.-Algunas notas teóricas sobre cómo funciona IPTables

  1. IPTables usa por defecto la regla FILTER (filtrado). Si queremos indicarle que use otra, se lo indicaremos con -t mangle/nat.
  2. Las reglas se añaden en una lista y se miran de arriba a abajo. Cuando un paquete coincide con una regla, se realiza lo que pone en dicha regla. ¿Qué quiere decir esto? Imaginemos que tenemos dos reglas en el siguiente orden: “NO acepto paquetes de la IP X.X.X.X” y “Acepto paquetes de la IP X.X.X.X que vayan por este puerto”. De esta manera, cuando se reciba cualquier paquete, se desechará ya que coincide con la primera regla, independientemente de todo lo demás. Sin embargo, si hubiesemos puesto las reglas en el orden inverso, aceptariamos solamente paquetes de esa IP que vaya por ese puerto, y el resto se desechan. Por esto, es muy importante el orden en el que se escriben las reglas.

4.-Tabla FILTER

Esta tabla nos permite filtrar paquetes, y tratarlos.
Dentro de esta tabla, tenemos 3 cadenas:

  • INPUT: Afecta a los paquetes que van dirigidos hacia el propio equipo.
  • OUTPUT: Afeta a los paquetes que van dirigidos desde el propio equipo. Generados localmente que salen al exterior.
  • FORWARD: Los paquetes que usan nuestro equipo para ir a otros. No van destinados a nuestro equipo, lo usa para reenviar paquetes a un objetivo concreto.

4.1.-El parámetro Match (-m)

El parámetro match nos permite seleccionar unos paquetes determinados, dependiendo de lo que queramos seleccionar concretamente. Nos proporciona más flexibilidad a la hora de filtrar.

4.1.1.-Match time
Nos permite seleccionar paquetes teniendo en cuenta el tiempo. Esto nos permite filtrar paquetes dependiendo de la hora y día del dispositivo en donde se estén añadiendo las reglas de IPTables.
El siguiente ejemplo bloquea todo el tráfico de lunes a viernes por la noche.
iptables -A OUTPUT -s 0/0 -m time –timestart 00:00 –timestop 08:00 –weekdays Mon,Tue,Wed,Thu,Fri -j DROP

4.1.2.-Match state
Nos permite seleccionar paquetes dependiendo del estado de estos. Hay 4 tipos:

  • INVALID: el paquete no ha podido ser identificado por alguna razón. Se conoce como inválido, por tanto no habría problemas en dropearlo.
  • ESTABILSHED: el paquete está asociado a una conexión en la que se envían paquetes en ambos sentidos y que está corriendo.
  • NEW: el paquete que inicia una nueva conexión o que está asociado con una conexión que no envía paquetes en ambas direcciones.
  • RELATED: el paquete empieza una nueva conexión, pero está asociado a una conexión ya existente, como una trasnferencia de datos FTP o un error ICMP. Nos permite trackear la transferencia.

Ejemplo:
iptables -A INPUT -m state –state INVALID -j DROP

4.1.3.-Match mac
Nos permite seleccionar paquetes en función de la dirección MAC. Podriamos filtrar los paquetes que vengan de una MAC determinada de la siguiente manera:
iptables -A INPUT -m mac –mac-source XX:XX:XX:XX:XX:XX -j DROP

4.1.3.-Match multiport (opción de -p tcp)
Nos permite seleccionar varios puertos, ya sean de destino u origen. Se usa –dports y –sports.
iptables -A INPUT -p tcp –match multiport —dports 80,443,100:1500 -j ACCEPT

4.2.-El protocolo TCP

Para hacer referencia a este protocolo, tendremos que especificarlo mediante -p tcp.
–dport: puerto de destino. Se pueden poner en rangos o uno a uno. Ejemplo:
iptables -A INPUT -p tcp –dport 2000:2500 -j DROP
iptables -A INPUT -p tcp –dport 80 -j DROP

–sport: puerto de origen. Lo mismo que dport.

Nota: Para poner múltiples puertos, hay que hacerlo con match multiport (ver 4.1.4)

–tcp-flags: nos permite indicar los FLAGS que queremos que estén activos. La primera cadena es la de los flags que queremos examinar, y la segunda, es la de los flags que queremos que estén activos.

Ejemplo: queremos que esté activo el flag SYN y no-activo el de PSH:
iptables -A OUTPUT -p tcp –tcp-flags SYN,PSH SYN -j DROP
Queremos que esté activo el de SYN y el de PSH:
iptables -A OUTPUT -p tcp –tcp-flags ALL SYN,PSH -j DROP

4.3.-Ejemplos

4.3.1.-Filtrar los paquetes que provengan de una dirección MAC determinada
iptables -A INPUT -m mac –mac-source XX:XX:XX:XX:XX:XX -j DROP

4.3.2.-Permitir que sólamente una determinada MAC pueda comunicarse
iptables -A INPUT -m mac –mac-source XX:XX:XX:XX:XX:XX -j ACCEPT
iptables -A INPUT -j DROP

o

iptables -P INPUT DROP # Establecemos una politica de dropeo en los inputs
iptables -A INPUT -m mac –mac-source XX:XX:XX:XX:XX:XX -j ACCEPT

4.3.3.-Eliminar reglas determinadas
iptables -L -n –line-numbers # Listamos las reglas (numerándolas)
iptables -D INPUT 2 # Seleccionamos la que queramos eliminar y su tabla (la 2 de la INPUT).

4.3.4.-Bloquear puertos concretos
iptables -A OUTPUT -p tcp –dport 80 -j DROP

4.3.5.-Filtrar paquetes de una red entera
iptables -A INPUT -s 192.168.2.0/24 -j DROP

4.3.6.-Prohibir el tráfico a una web
iptables -A OUTPUT -d IP.IP.IP.IP -j DROP
o
iptables -A OUTPUT -s IP.IP.IP.IP -j DROP

4.3.7.-Prohibir el tráfico a una web en un determinado rango de horas y determinados dias.
iptables -A OUTPUT -d IP.IP.IP.IP -m time –timestart 11:00 –timestop 12:00 –weekdays Mon,Tue,Wed,Thu,Fri -j DROP

4.3.8.-Listar las cadenas de una tabla (-t filter/nat/mangle) (sin opciones)
iptables -L

4.3.9.-Listar las cadenas de una tabla con opciones: para que salgan las reglas numeradas y para que salgan las estadísticas de transferencia de datos
iptables -nvx –line-numbers -L

4.3.10.-Resetear el contador a cero (de los paquetes y bytes)
iptables -Z

5.-Comandos

-A (–append): agrega una nueva regla al final de la cadena seleccionada.
Recordar que hay tres tablas (filter, nat y mangle) y en cada una, hay cadenas. Las reglas, van encadenadas en cada cadena.
-I (–insert): inserta encima del número de la regla de la cadena, una nueva regla (ver ejemplo más abajo).
-D (–delete): elimina una regla de la cadena seleccionada
-L (–list): lista todas las reglas
-F (–flush): borra o limpia las reglas
-Z (–zero) contadores de bytes de todas las cadenas a cero)
-N (–new-chain): crea una nueva cadena
-X (–delete-chain): elimina la cadena especificada
-P (–policy): configura una política a la cadena y target dado
-h (–help): da una descripción de la sintaxis del comando

Ejemplo de -I
Como dije anteriormente, hay tablas (filter, nat, mangle), y en cada tabla hay cadenas (input, output, …), y cada cadena tiene reglas que vamos insertando, y cada regla tiene un número, ya que el orden es altamente importante. Si ponemos primero una regla que dice “dropear todos los paquetes del input” y luego decimos “aceptar los paquetes que pasan por una IP”, siempre se va a ejecutar lo primero y no habrá transmisión. Es por esto que el orden es importante.
Con -A (–append) las reglas las vamos poniendo una detrás de otra. Con -I (–insert) podemos especificar la posición de la regla en la cadena de la siguiente forma. Ejemplo: imaginemos que al principio tenemos 3 reglas
A)
B)
C)

Si hacemos un: -I OUTPUT 2 -j DROP esta regla se situará encima de la segunda.

A)
-I OUTPUT…
B)
C)

6.-Parámetros

-p (–protocol): protocolo del paquete a chequear (tcp, udp, icmp, all). El argumento ! es la selección inversa
-s (–source): dirección de origen específica o un rango usando la máscara o prefijo. Argumento !
-d (–destination): dirección destino
-j (–jump) especifica el target de la regla. Qué hacer con el paquete que coincida con la regla (aceptar, rechazar) (ACCEPT, DROP (tirar), REJECT (inalcanzable, paquete ICMP de error))
-i (–in-interface): nombre de la interfaz por donde el paquete fue recibido (solo para cadenas INPUT, FORWARD y PREROUTING). Argumento !.
-O (–out-interface): nombre de la interfaz por donde el paquete se envía o sale (solo para cadenas OUTPUT, FORWARD, y POSTROUTING). Argumento !.
-f (–fragment): la regla se refiere al segundo y siguientes fragmentos o paquetes fragmentados.
-t (–table): especifica la tabla a usar.
-m (–match)

¿Qué sabe Tuenti de nosotros?

Como todos sabemos (o deberiamos saber), al menos en España disponemos de los derechos de acceso, modificación, cancelación y oposición, y la gran mayoria de la gente no lo sabe, o no los usa.

Por poner un ejemplo práctico, al cabo del tiempo a nuestr mail nos llegan muchos correos de falso spam. Digo falso spam porque para nosotros es spam (ya que es correo no deseado) pero nos lo mandan porque tiempo atrás nos registramos en algún sitio y accedimos a que guardasen nuestros datos y nos enviasen correo. Es cierto que se tarda medio segundo en eliminarlo, por eso se suele hacer ya que es lo mas fácil y rápido, pero si nos detenemos un momento en el mensaje, en la parte de abajo suele (o deberia) tener un enlace para poder evitar que nos manden más correo (darnos de baja).

El caso es que con la legislación española, además de facilitarnos un medio para poder ejercer nuestros derechos (acceso, modificación…) debe de indicar quién es el responsable del fichero de datos y dónde está situado. Hace tiempo salió una noticia de que uno pidió sus datos en Facebook, y se lo dieron y tal, y bueno, ha llovido bastante desde es momento y en Facebook tenemos ya la opción de descargar nuestros datos (y archivos subidos).

Si nos vamos a configuración de la cuenta, en la parte de abajo tenemos un enlace que dice “Descarga una copia de tu información.” que incluye además como dije, archivos subidos, como imágenes. Esto no es instantáneo, sino que lo has de solicitar y tarda un tiempo en prepararse (cuestión de horas), y luego si que puedes descargarlo.

Total, que me hice la pregunta de, ¿y Tuenti qué guardará de nosotros? Así que no me lo pensé dos veces. A pesar de conocerme el procedimiento legal, primero de todo les envié un mail solicitando información, y me dijeron que tenia que enviarles una carta a una dirección adjuntando una copia del DNI, una carta con mis datos (nombre, edad, ubicación), y un impreso que tenia que firmar (el primero). Envié la carta, y además la certifiqué para confirmar que había llegado.

Volviendo al tema legal, he de comentar dos cosas: legalmente, nos tienen que responder en el periodo de máximo un mes. Una vez realizado el derecho de acceso a tus datos personales, si no es por causas mayores, no puedes volver a hacerlo hasta dentro de un año.

Hace poco recibí el paquete de vuelta cuyo contenido era un par de hojas impresas y un CD, del cual pude deducir que estaba escrito por una chica (y posteriormente los metadatos me dijeron que se llamaba Laura y usaba un Mac, gracias FOCA).

El contenido del CD era un PDF (lo que me habian imprimido) y una carpeta que contenia un screenshot y 4 CSV’s.

El screenshot es el siguiente:

Con respecto a los CSV’s, el primero de ellos contiene datos respecto a los amigos: nombre, ciudad, edad, ID, y fecha de cuando empezamos a ser amigos en la red social.
El segundo CSV es un simple log de las IP desde donde se ha conectado a la cuenta: Id, fecha, IP, “admin ID” (ni idea que es esto, igual es en el caso de ser admin?, me lo pone a 0 todo el rato). Importante destacar que viene desde el momento de registro, en mi caso desde 2009.
El tercer CSV contiene los mensajes privados, aunque de una forma más caótica, ya que técnicamente no es un CSV, ni siquiera sé muy bien como lo han hecho. De repeten aparecen varios contactos, luego un mensaje, luego más contactos…
El último CSV contiene datos del muro con los siguientes datos: Nombre, ciudad, edad, ID, fecha, texto y tipo. He de decir que también está ordenado de forma caótica y no es completamente un CSV.
La verdad es que me esperaba que me adjuntasen también las imágenes que habia subido (como en el caso de Facebook)… pero no ha sido el caso.

Conclusión hasta aquí: es interesante ver qué tienen las empresas sobre nosotros, así que animo a que ejerzais vuestros derechos, que para algo están.

Con respecto al tema de la seguridad me han surgido varias preguntas y reflexiones:
-Lo único personal que tuve que enviar fue una fotocopia del DNI (ni siquiera compulsada) además de los datos que están en la red social y cualquiera puede verlos. Se podría hacer la fotocopia a alguien sin que se diera cuenta y enviarlo en su nombre? No me cabe la menor duda, sobre todo si se trata de alguien cercano como un familiar, o si se piensa un poco la manera.
-Si se pudiese suplantar la identidad y poder realizar los derechos de acceso, ¿podriamos realizar también los derechos de oposición? (vamos, cerrarle el Tuenti a alguien).

Desarrollando un sistema de encriptación útil y básico

Desde hace mucho tiempo que la criptología es uno de los temas que apasionan, aunque para indagar de verdad necesitas alto conocimiento matemático que espero algún dia nos enseñen en la uni. Sin ningún tipo de conocimiento básico, lo primero que se nos puede ocurrir para encriptar un texto, es la rotación (método Cesar) o la traducción.

El término traducción al que me refiero puede ser muy amplio, y esta idea que le da un toque personal a esta entrada, me viene de hace muchos años cuando oí en la tele que el japonés originariamente se diseñó para que unos cuantos lo hablasen y no les entendieran, como un tipo de encriptación del lenguaje. Cierto o no, nos vamos a valer de eso.

El tema de la rotación no tiene mucho misterio. Se basa en rotar el abecedario, de manera que si hacemos una rotación 3:

Osease, que el texto “hola mundo”, podria quedar encriptado de la siguiente manera, “krod pxpgr”. Una persona que vea esto puede sacar algunas deducciones y hacer pruebas.

  • Al haber un espacio entre dos grupos de letras, se puede deducir que se tratan de dos palabras.
  • Al no ser de un tamaño raro, se pueden considerar letras que forman palabras, sin más.
  • Para desencriptarlo, lo primero que se nos puede ocurrir es hacer una rotación debido a lo fácil que es programar algo, para que nos rote un texto de manera automática de todas las formas posibles.

Como podemos deducir, la rotación sin más, no es un método seguro. Pero, ¿y si además de rotar hacemos una traducción? Esa era mi idea desde el principio, y valiéndome de lo que conté del japonés, podemos usar los propios kanjis del japonés para traducir (aunque usaré ‘kanas’ para los más quisquillosos).

De manera que (traduciendo también el espacio en blanco), nuestro “krod pxpgr” se puede transformar en un “ゼかとつこにギヲちな” por poner un ejemplo.

Ya parece un poco más complicado de desencriptar, ¿verdad? Vamos a pararnos aquí y vamos a pensar en la herramienta desencriptradora, ya que si hacemos una encriptación, es lógico que necesitamos otra herramienta que nos recorra el camino inverso.

En este proceso, hemos necesitado dos premisas: la primera de ellas es la rotación que hemos tomado, y la segunda, la traducción. El tema de la traducción no tiene ningún misterio, ya que en una matriz podemos tener todos los caracteres que vamos a traducir, y en otra la traducción de cada uno. Y por último, el tema de la rotación, lo podemos pasar en la propia cadena, me explico, después de traducir “hola mundo” por “krod pxpgr”, al usar una rotación 3, podemos traducir el texto originario a “krod pxpgr3”. Y posteriormente lo traducimos a kanjis japoneses ゼかとつこにギヲちな. De esta forma hacemos lo siguiente para desencriptar: traducimos -> obtenemos el número de rotación -> rotamos.

Perfecto, pues ya tenemos nuestra cadena encriptada a un lenguaje con símbolos raros que no tienen absolutamente nada que ver con los nuestros. Sin embargo, esto sigue teniendo varios fallos.

A lo largo de la historia, las personas han sido capaces de desencriptar lenguajes escritos (como los jeroglíficos por ejemplo), entonces, desencriptar un simple “hola mundo” debe ser pan comido. Esto lo han conseguido observando el patrón que siguen las palabras, la cantidad de veces que se usan las letras (por ejemplo, para el castellano en particular, las vocales y los espacios en blanco son muy usados) ¿Cómo podemos hacer más fuerte el sistema? Podemos hacer algo en relación a lo que hemos explicado anteriormente con la rotación.

Podemos hacer que cada vez que hagamos un mensaje, aunque sea el mismo, se traduzca de distinta manera, ya que cada vez lo rotamos de forma distinta. Esto no es muy complicado, ya que como pasamos en el propio mensaje las posiciones en las que lo rotamos, desrotarlo debe ser dificil.

De esta forma, cuando encriptemos una frase, en esa propia frase estará la clave para desencriptarla.

Todavía más
¿Cómo podemos hacer esto todavia más fuerte? Recordais las dos matrices de las que hablé antes?, una con los caracteres a traducir y otra con la traducción. Para hacer todavía más fuerte esto, podemos valernos de caracteres de distintos idiomas (para liarlo más) y que, a la hora de traducir, en lugar de traducir letras, traduzcamos sílabas. Tendremos más cosas que traducir claro está, pero será más fuerte por tener más variedad en el conjunto.

Un saludo, lipman

Twitter Stalker. Script para obtener datos de una cuenta de Twitter

Mitad por entretenimiento y mitad por motivos personales, me vi desarrollando una aplicación en Bash que me permitiera obtener los datos de una cuenta de Twitter, a partir del nombre de usuario del que quisiera obtener dichos datos.

Hace algunos dias la terminé, y ayer la traducí a PHP, puesta hoy pública (aunque todavia no el código) para detectar posibles fallos y ser reportado de algún tipo de bug o comentario, es por eso por lo que animo a que cualquiera que tenga un rato la pruebe: http://old.delanover.com/projects/twitter.

Quisiera relatar un poco la experiencia que tuve en este post. Como dije, al principio la escribí en Bash. Viene muy bien saber comandos de linux para esto, y en el proceso de creación del script descubrí algunas cosas interesantes de Bash.

El comando paste, nos permite juntar dos ficheros desde la consola. Pero no de la misma forma que hariamos con cat archivo1 archivo2. De esta última forma, concatenariamos archivos. Entenderemos este comando mejor con un ejemplo:
Archivo 1
Hola
Adios
Archivo 2
Mundo
Mundo

Realizamos: paste archivo1 archivo2 > final y obtenemos un fichero final cuyo contenido es:
Hola Mundo
Adios Mundo
(Palabras separadas por un tabulador)

Parece que no, pero puede ser útil este comando, y con lo sencillo que es, me parecia raro no haber oido hablar de él.

También tuve que lidiar con la búsqueda de expresiones regulares de forma un-greedy (o non-greedy). ¿Qué es esto? Lo veremos también claro con un ejemplo. Imaginemos que tenemos la siguiente string: inicio intermedio fin basura basura fin y queremos obtener lo que hay entre inicio y fin (el primer fin, no el último). Usando expresiones regulares, podriamos pensar en algo así:

grep 'inicio.*fin' -o archivoCualquiera (el -o es para que nos muestre todo lo que abarca esa expresión regular. Es decir, que nosotros queremos: “inicio intermedio fin basura basura fin“, pero en lugar de eso, nos devuelve “inicio intermedio fin basura basura fin“. ¿Pero por qué? Porque primero busca “inicio”, después busca todos los carácteres posibles (todos los que simbolizan el punto) y cuando ya los tiene todos, se pone a buscar hacia atrás (de izquierda a derecha) “fin”. En otras palabras se podría interpretar con que empieza a buscar “inicio” por la izquierda y “fin” por la derecha, y muestra todo lo que hay de por medio.

El caso es que yo no quería esto. Yo quería que empezase a buscar por la derecha, y siguiese buscando desde ese momento hacia la derecha. De esta forma obtendríamos el “inicio intermedio fin basura basura fin“. Pues bien, este método de buscar se llama non-greedy o un-greedy, y nativamente, bash no lo permite y digo nativamente, porque grep tiene un parámetro que nos permite usar expresiones regulares de Perl y este sí que permite hacer lo que buscamos.

Solución final: grep -P 'inicio.*?fin' -o archivoCualquiera

Simplemente añadiendo un símbolo de interrogración tras el asterisco.

Volviendo al tema del script, mencionar que he usado la API de twitter que podeis encontrar aquí: https://dev.twitter.com/docs/api
Un apunte: Twitter permite como máximo 150 peticiones por hora por IP. Parecen suficientes o incluso muchas, pero innumerables veces me ha saltado el error de que he excedido el límite.

Por otra parte, al re-programarlo en PHP y al tratarse de que las respuestas vienen dadas en formato JSON, éste tiene una función que ayuda mucho: json_decode. El resultado no se trata como una matriz cualquiera, así que hablaré un poco. Por un lado, miraremos la estructura de esto. Para acceder a las propiedades del primer nivel sería tan fácil como:

$objeto = json_decode($cadena_json);
echo $objeto->{'created_at'}; //Ejemplo de acceso a un primer nivel
echo $objeto->{'user'}->{'name'}; //Ejemplo de acceso a un segundo nivel

De esta forma podemos acceder individualmente. Para ver todo el contenido de la petición es todavía más sencillo:

$objeto = json_decode($cadena_json);
var_dump($objeto);

Insisto en que lo probeis y me comentéis algo: http://old.delanover.com/twitter

Un saludo, lipman

[Comando lftp] Copias de seguridad en Android en modo local.

Siento todo este tiempo sin escribir, he estado ocupado con temas de la universidad hasta este dia. Pero bueno, intenté despedirme durante un tiempo con una entrada especial como la de Vodafone.

Aunque no haya publicado nada desde entonces, tengo en mente varias entradas, así que volver a estar asiduo (o eso espero).

Empezaré la entrada lanzando una pregunta. ¿Estamos preparados para perder nuestro smartphone? Todos sabemos que la respuesta es no. En ese caso la mayoria de la gente perdería desde contactos hasta fotos. Pero vamos a intentar que este no sea nuestro caso.

Paso 1: la nube puede ser nuestra amiga.

Desde hace tiempo, he dejado de agregar contactos al móvil de forma tradicional, es decir, desde el propio teléfono añadir el contacto. Desde ahora, uso mi cuenta de GMail para agregar ahí a los contactos y posteriormente, actualizar los de mi teléfono teniéndolo sincronizado a dicha cuenta.

Ventajas:
Como principal ventaja, está si perdemos el teléfono, los contactos los seguimos teniendo en nuestra cuenta. Igualmente añado, que podemos añadir contactos desde el teléfono a la cuenta de GMail.
Control de tus contactos desde el ordenador, clasificación, puedes ponerles imágenes, y todo lo que puedes hacer desde tu teléfono, pero más cómodo incluso.

Paso 2: copia de seguridad de todos nuestros archivos

El objetivo original de esta entrada era mayormente este paso, ya que era el entretenido realmente, pero ya que estoy, he añadido el paso anterior ya que también me parece interesante.

Lo primero que haremos será bajarnos una aplicación para Android (gratuita): FTPDroid (también existe la versión de pago).

Esta aplicación nos permitirá convertir nuestro teléfono en un servidor FTP en donde nos conectaremos desde el ordenador y haremos copias de seguridad. Si, para hacer copias de seguridad solo necesitamos un cable y copiar-pegar, pero eso no es entretenido, se busca una manera más entretenida.

Configuración:


Añadimos un usuario y contraseña, y por defecto, la ruta en la cual accederemos será la de la tarjeta. Podriamos hacer una copia de seguridad de todo el teléfono, pero a mi personalmente me interesa la tarjeta, ya que es ahí en donde solemos meter canciones, recibir archivos, guardar ficheros, fotografias, grabaciones, etc. En este ultimo caso, cambiariamos la ruta que está, por / aunque algunos archivos no nos dejan copiarlos (supongo que teniendo el teléfono rooteado si que te dejará).

En la parte de opciones, desactivamos “Enable anonymous” para que solamente podamos acceder al teléfono a través del nombre de usuario y contraseña previamente establecido (por si acaso).

Una vez configurado esto, ya podemos acceder a nuestro teléfono desde el navegador. Si la IP local de nuestro teléfono fuese 192.168.1.100, accederiamos de la siguiente manera: ftp://192.168.1.100:2121

Comando lft
Ahora, desde la consola realizaremos la copia de ficheros, pero en lugar de usar el comando ftp como todos hemos pensado, usaremos lftp.

A diferencia de ftp, lftp permite realizar algunas más cosas, pero nos centraremos en una sola, y es en la función “mirror”.

Usaremos esta función para hacer copia de seguridad de nuestra tarjeta. Desde la consola, nos situamos en la carpeta en donde queremos llevar la copia de seguridad y seguimos los siguientes pasos:

sftp 192.168.1.100 -p 2121

Tras conectarnos establecemos el nombre de usuario y contraseña

user Usuario Contraseña

Usamos la función mirror, estableciendo que queremos copiar desde la ruta / (Nota: se copia recursivamente por defecto) (Nota 2: recordemos que / equivale a /mnt/sdcard ya que es lo que hemos configurado en nuestro teléfono).

mirror /

Este proceso nos puede llevar largos minutos, dependiendo de lo que tengamos en el teléfono claro. Ahora viene lo realmente beneficioso e interesante. Al cabo del tiempo habremos sacado nuevas fotos y tendremos nuevos archivos. ¿Tendremos que copiarlos todos de nuevo? No. ¿Hay alguna función que nos permita copiar solo los nuevos? En efecto. Además, esto también nos es útil por si hemos tenido algún problema al hacer la primera copia, como una desconexión a internet o algo.

mirror / -n

Nos queda hacer un último paso. Al realizar esto, igual tenemos problemas con los permisos. Yo mismo he tenido problemas haciéndolo en Windows, ya que no me dejaba accceder a nada de lo que habia copiado.

Para ello, realizamos un cambio de permisos. Si no nos queremo complicar y estamos en Windows, nos vamos a la carpeta donde hemos hecho la copia y hacemos un chmod recursivo:

chmod -R 777 /

Algo más acerca de LFTP

Dentro de las opciones que nos ofrece el comando mirror, podemos hacer un reverse mirror, que viene siendo lo mismo pero al revés, es decir, en vez de bajarnos del servidor un arbol con sus descendientes, lo subimos.

mirror / -R

En general, lftp es más potente que ftp. Una diferencia con respecto el comando ftp es que con lftp podemos combinar comandos locales de la consola y comandos propios de lftp. Por ejemplo, desde una sola línea podriamos comprimir el directorio actual (local), subirlo al servidor, y luego borrarlo del directorio local:

!(tar -cvvf target.tar * && gzip target.tar) && put target.tar.gz && !(rm target.tar.gz)

Como podemos ver, el símbolo de exclamación nos permite ejecutar en el sitio local.
Otra diferencia es que con lftp podemos trabajar fácilmente con el grep. Imaginemos que queremos todos los ficheros que no sean carpetas de nuestr servidor:

ls | grep '^[^d]'

lftp además de soportar transferencias ftp como hemos estado viendo, también soporta http y sus respectivas versiones encriptadas (ftps y https).

Por último, también interesante, es que lftp puede ejecutar scripts mediante el comando -f de la siguiente manera. Suponiendo que tenemos un archivo llamado script con el siguiente contenido:

connect 192.168.1.100 -p 2121
user Usuario Contraseña
ls

Al ejecutar lftp -f script se ejecuta todo el contenido del script, nos devuelve el ls del directorio remoto y volvemos a tener la consola operativa.

Un saludo, lipman

Parte 2 – Descuido en Vodafone.es permite acceder a cualquier cuenta de usuario y obtener datos de cualquier teléfono

Parte 1 del Post.

Tras meses sin hacer nada los de Vodafone.es, el pasado jueves dia 8 publiqué un Proof of Concept de la inseguridad que esta página proveia, hasta el punto de poder entrar en cualquier cuenta a partir únicamente del número de teléfono de la “víctima”.

En este momento (dia 14 de diciembre), unos 6 días después de la publicación, he vuelto a entrar a Vodafone.es y me he dado cuenta de que han mejorado la seguridad: en lugar de tener que pasar una puerta delgada de madera, tenemos que pasar a través de dos.

El principal fallo residía en la obtención de una nueva contraseña, dándole a “recordar contraseña”. Esto es lo que habia antes de ser “arreglado”:

Ahora:

Como podemos ver no ha cambiado mucho, podemos elegir de poner nuestro teléfono, y es realmente lo mismo. Donde si notamos el cambio es en la segunda parte. Antes:

Ahora:

La primera parte (lo de la pregunta secreta) aparece una vez la hemos establecido (la primera vez que realicé la prueba no aparecia, y al finalizarla, me pedia que la introdujese). Lo que si que aparece ya fijo es lo demás.
Por un lado, necesitamos la identificación (vease, DNI y demás) y por otro, podemos elegir entre: introducir la entidad en donde tenemos domiciliada nuestra factura, o introducir los 4 últimos dígitos de nuestra cuenta (hmm interesante esto último…).

Aquí ya va mi primer comentario y el resultado de más pruebas realizadas:

  • Necesitamos el DNI (cosa relativamente fácil de conseguir, vease ingeniería social. Además, es obvio que si esto se le hace a alguien, es porque se le conoce).
  • Se puede volver a usar fuerza bruta. Si señores, se puede volver a usar fuerza bruta. Sigue sin haber ningún tipo de expiración por cantidad de veces, captcha, o cualquier tipo de arreglo.

Tras esto, nos vamos al paso 3. El paso 3 anteriormente era el siguiente:

Ahora es este:

¿Diferencia? ninguna. ¿Se puede volver a usar fuerza bruta? Si, se puede.

Conclusión hasta el momento: Han hecho el sistema algo más seguro, siendo necesario ahora el DNI de la víctima. Como dije anteriormente, no lo han arreglado, simplemente han puesto una traba más, que tampoco es nada del otro mundo.

Problema añadido: Si nos fijamos en el paso dos (el antes y el después), a partir de ahora hay que meter los 4 últimos dígitos del número de cuenta. ¿Qué quiere decir esto? Que ya no habrá diferencia entre “titular” y “usuario”, y si logramos entrar, veremos todos los datos sin ningún tipo de impedimento (aunque el que habia antes tampoco es que lo fuera demasiado).

Otras mejoras de seguridad

Con respecto al tema de la fuerza bruta, se han puesto al dia en lo que es el login principal. Solamente nos deja meter un cierto número de intentos, 5 para ser exactos. Y aquí si que realmente no se puede bruteforcear. Sin embargo, repito, el fallo principal no está en el login, sino en la parte de recuperar la password, por lo que todavia queda por arreglar.

Por otra parte, el buscador lo han cambiado (al fin) ya que sufría más de un XSS en distintos argumentos, en el que insistí mucho. Buscador viejo:

Buscador nuevo:

El tema de las Cookies

La verdad es que en el otro post lo mencioné muy por encima porque tampoco queria entrar al tema, ya que no era tan importante como el problema principal. De todos modos, estoy contento de que por lo visto, algún tipo de efecto ha tenido que haber tras hacer la publicación anterior, ya que como dije, en meses no lo habian arreglado, y de repente, 6 dias después de la publicación (justo antes de publicarla volví a comprobar si habian hecho algo nuevo y nada..) me encuentro con que han hecho algo, poco, pero algo.

Principalmente, una de las partes que más me sorprenden de Vodafone, es que guarda la contraseña y el usuario (y el usuario es ni más ni menos que el número de teléfono), en una cookie, de la siguiente forma.

Todo el mundo sabe (o debería) que nunca jamás se debe guardar en una cookie los credenciales, aunque estén encriptados. En el caso de robar una cookie de alguien, podemos obtener su teléfono (punto de ataque) y su contraseña, que aunque esté encriptada, no es difícil de mostrar tras esos asteriscos.

Fallos XSS con los que podriamos robar cookies:
Viejos
Uno
Dos

Todavia persistentes
[Uno] [Enlace]
[Filtro interesante (WAF)] [Filtro Bypasseado] [Imagen] (En varios argumentos de la URL)

Otros:
[Este lo han intentado arreglar de alguna forma.. pero la página nunca termina de cargar]

Animo a que pongais más si los encontrais.

Un saludo, lipman

Descuido en Vodafone.es permite acceder a cualquier cuenta de usuario y obtener datos de cualquier teléfono

Nota: han arreglado algunas cosillas, aunque todavia sigue quedando este fallo. Parte 2 del Post.

“Esto” está descubierto y reportado desde hace más de medio año… He intercambiado mails y conversaciones telefónicas con Vodafone y con la propia policia (GDT). Tenia un post explicándolo todo detalladamente además de un PDF que mandé a ambas partes, pero visto que no lo arreglan nunca, no lo voy a publicar. Lo que haré será un mini resumen, y se acabó, ya que quiero olvidarme de este tema completamente.

Antes de nada os hago un spoiler: no es nada del otro mundo. Solo es una muestra de cómo una absurda tonteria, nos permite hacer cosas que no deberiamos. Es más, esto indica que este descuido es realmente grave, ya que cualquiera puede explotarlo.

Empezaré con el debate respecto al título elegido de esta entrada. Ojalá hubiera podido poner “Bug en Vodafone.es…” o “Fallo de seguridad/Vulnerabilidad..”. En fin, múltiples son los adjetivos para ello. Pero no, pongo descuido por no poner incompetencia, ya que guardar en una cookie el nombre de usuario (teléfono) y la contraseña (encripada, pero eso da igual) no es un fallo de programación, no es un bug, no es una vulnerabilidad… es ser un incompetente. Menciono también que tiene XSSs varios, sin ir más lejos, creo recordar que el propio buscador tenía.

Como dije anteriormente, voy a ser breve, y no voy a dar detalles. Solo decir esto: no seas gilipollas.

Como dice el título, este descuido nos permite meternos en la cuenta de usuario a partir únicamente de su número de teléfono. Y si no tiene cuenta, también nos lo permite porque le podemos registrar nosotros mismos.
Uno de los orígenes de este problema, es que si le damos a “olvidar contraseña”, podemos poner el número de teléfono objetivo y nuestra dirección de correo. Nos mandan una clave numerica de 4 digitos al movil para que la introduzcamos y establezcamos una nueva contraseña. Pues bien, podemos hacer fuerza bruta tranquilamente que al final, daremos con esa clave que no puede ser otra que alguna entre 0000 y 9999. Una forma para hacer fuerza bruta sin ser un 5uP3RH4X0R es usar el iMacros para Firefox, haciendo:

SET !LOOP 1000
URL GOTO=http://canalonline.vodafone.es/cpar/do/alta/changePassword?uuid=XXXXXXXX&claveAntigua={{!loop}}&claveNueva=1234&rePassword=1234

(Esta iría desde 1000 hasta 9999, y estableceria como nueva contraseña 1234).
Así que nada, después de esto ya podemos meternos en la cuenta. Pero no podemos acceder a todos los datos, que pena. No podemos porque tenemos que ser titular, y para eso, tenemos que validarnos. ¿Como? Pues hay varias formas. Una de ellas es introduciendo los 4 últimos dígitos de nuestra cuenta bancaria asociada.

¿Otra vez 4 números? Esto me suena de antes… Exacto. iMacros de nuevo. Y claro, si aquí tampoco ponemos nada que nos impida un bruteforce como un captcha o una expiración de la sesión, pues igualmente podemos petarlo. Y efectivamente, se puede.

Datos comprometidos (entre otros tantos): DNI, nombre, dirección postal, factura electrónica (con mas telefonos claro, que a su vez igual tambien son de Vodafone), códigos PIN y PUK (ideal por si robamos un teléfono verdad?)…

Yo flipo con las empresas. Pero sobretodo con su pasotismo a la hora de no arreglar nada, ni contactar conmigo siquiera. En fin…

Conclusiones:
-Se puede bruteforcear todo vodafone.es sin problemas
-Se puede robar una cookie con datos como la contraseña y usuario para suplantarse (ya que presenta varios XSS).
-Poned un puto captcha! de una vez.
-Insisto en que la gravedad de este asunto es que es demasiado fácil realizar esto, no hay que ser un experto ni tener conocimientos de nada.
-Seria curioso saber cuantas leyes se pasan por el forro los de Vodafone, como la de las auditorias (a saber si las hacen siquiera, o si les hacen caso), sin contar con las que hacen mención a que hay que proteger bien los datos.

Dato adicional: Vodafone no es la única compañia de telecomunicaciones cuya identidad de sus usuarios se basa en algo tan simple. Aunque lo de guardar en la cookie las password, todavia me sigue costando creerlo. Ahí lo dejo caer…

Retweetealo!
Mi Twitter

Seguridad a la hora de crear entradas en WordPress

INDICE
0.-Resumen
1.-Introducción
2.-Buscando un algoritmo
3.-Implementando nuestro sistema en WordPress
3.1.-Añadiendo posts a nuestra base de datos
3.1.1.-Analizando la tabla de wp_posts
3.1.2.-Nuestra consulta
3.1.3.-La tabla wp_postmeta
3.2.-Implementando la seguridad en nuestra aplicación
3.3.-Conclusión y funcionamiento final
4.-Códigos finales completos

0.-Resumen

En este post intentaré explicar un método casero para poder escribir en nuestro respectivo blog de WordPress desde cualquier lugar sin tener que preocuparnos en que nos estén analizando el tráfico. Ideal por si estamos en una red que no es la nuestra, como en casa de algún conocido o en un hotel.

1.-Introducción

Una de las responsabilidades que tenemos/tienen los bloggers es de mantener actualizado nuestro blog que tanto queremos, incluso si nos encontramos en otros lugares. Sin embargo, no todos disponemos de 3G y algunos tenemos que ir mendigando WiFi por los hoteles, o en casa de un pariente. Yo, con lo paranoico que soy que incluso uso la versión encriptada de Google, siempre trato de intentar comprometer lo menos posible mis datos.

Si no tenemos puesto SSL en nuestro blog de WordPress, y nos logueamos en una red que puedan tener monitorizada, fácilmente nos sacan nuestro user y pass, por lo que tendremos que buscar una alternativa para loguearnos que sea más segura que nuestra propia cuenta.

2.-Buscando un algoritmo

Una idea que se me ha ocurrido para esto, es identificarnos con un hash que varíe, de forma que si es obtenido por algún tercero, no le sirva para nada. Lo más fácil de recordar que varíe, es el tiempo, así que podriamos usar un algoritmo basado en:

  • Caracteres alfanuméricos.
  • Caracteres especiales.
  • Caracteres que varien automáticamente (en función del tiempo).
  • Caracteres que varien de forma controlada.
  • Mayúsculas y minúsculas.

Un ejemplo podria ser en base al siguiente:
///XXlipmanYY///
En donde XX es el dia del mes, y YY la hora. He elegido este par de números debido a que varian lo suficientemente rápido como para que no se reutilicen, y lo suficientemente lento como para controlarlos. Además de esto, usaremos un truco para añadir un caracter aleatorio fácil de recordar. Dependiendo del dia de la semana (lunes, martes…) teclearemos una tecla debajo de los números, dependiendo del dia que sea. Por ejemplo, cuando sea lunes, pulsamos la Q, cuando sea martes la W… (notese que seria en mayúsculas).

Ejemplo completo:
Lunes 20 a las 8AM: ///20Qlipman8///
Martes 21 a las 15PM: ///21lWipman15///
Viernes 24 a las 2AM: ///24lipmTan2///

Notese que las letras mayúsculas “aleatorias” las vamos alternando en las posiciones entre la palabra “lipman”. Para que quede bien, necesitamos palabras de 6 caracteres.
De aquí también podemos descatar lo imprescindible que es que una contraseña no empiece por números o por letras cercanas a los extremos del alfabeto, para que sea todavia más improbable que un brute force nos descubra la contraseña.

3.-Implementando nuestro sistema en WordPress

Ya tenemos el diseño (respecto a la seguridad) de nuestra aplicación, por lo que queda la parte más entretenida: realizar una aplicación para comunicarnos con WordPress implementando nuestro sistema. Voy a poner solo lo que es esencial: comunicación entre nuestra aplicación y la base de datos para añadir entradas. Por nuestra cuenta podriamos desarrollar más cosas, como una mejor interfaz gráfica, pero esto lo dejaré a parte ya que seguramente dejaré esto como un plugin (ya hablaré más adelante) y haré mejoras en todo.

3.1.-Añadiendo posts a nuestra base de datos

Para nuestra suerte, la base de datos de WordPress (y en general la de cualquier CMS) suele ser sencillita, así que no deberiamos de tener problemas para manejarla.
Lo primero de todo, aprovecharemos el fichero de wp-config.php para conectar a nuestra base de datos. Este fichero es el primero que se genera cuando creamos nuestro sitio en WordPress, y contiene los datos de nuestra base de datos: nombre, usuario, contraseña… Así que le haremos un include.

3.1.1.-Analizando la tabla de wp_posts

Lo interesante de este tipo de situaciones, es analizarlas y aprovecharlas para intentar entender el funcionamiento interior de WordPress, por ello, no me limitaré a hacer, copiar y pegar código simplemente, sino que se intentará explicará todo.

A continuación, vamos a escribir los campos que tendremos que tocar (osease, todos menos los que suelen ir a NULL), explicandolos un poco, sobre todo, los que sean menos obvios.

Nombre Comentario
ID Id (PK) del post
post_author ID del autor
post_date Fecha de escritura
post_date_gmt Fecha de escritura (GMT)
post_content Contenido del post
post_title Titulo
post_status Estado: publicado, borrador..
comment_status Permitir comentarios
ping_status Permitir pingback
post_name Nombre parseado (*)
post_modified Fecha de modificación
post_modified_gmt Fecha de modificación (GMT)
post_parent A quien pertenece (*)
guid URL parseada (*)
menu_order Orden: 0
post_type Indica si es un post
comment_count Contador de comentarios

-Nombre parseado: Se obtiene en función del titulo. Si tenemos el siguiente titulo: “Hola Mundo”, obtendremos: “hola-mundo”. Osease, lo que aparece (si lo tenemos configurado así) de enlace.

-A quien pertenece: Esto solo hace referencia a los borradores y demás. Con respecto a los posts publicados, ni caso.

-URL parseada: Esta seria la URL del post en el caso de tenerlo configurado de manera que se viera la ID en la URL. Un ejemplo, en el caso de delanover, si escribiesemos un post con ID 1234, este campo seria: http://delanover.com/?p=1234

3.1.2.-Nuestra consulta

De momento, llevamos lo siguiente:

//Incluimos los datos de configuración de nuestra base de datos
include('wp-config.php');

mysql_connect(DB_HOST, DB_USER, DB_PASSWORD) or die("Error al conectar");

//Creamos la consulta
$consulta_principal = "INSERT INTO `wp_posts`(`ID`, `post_author`, `post_date`, `post_date_gmt`,
	`post_content`, `post_title`, `post_status`, `comment_status`, `ping_status`,
	`post_name`,`post_modified`, `post_modified_gmt`,
	`post_parent`, `guid`, `menu_order`, `post_type`, `comment_count`) VALUES
	('$id', 1,$fecha,$fecha_gmt,'$contenido','$titulo','publish','open','open',
	'$titulo_parseado',$fecha,$fecha_gmt,0,'$id_parseada',0,'post',0)";
		
$resultado_principal = mysql_query($consulta_principal);

Como podemos observar en nuestra consulta, hay variables y valores constantes. Me limitaré a contar un poco las variables al igual que la forma de obtenerlas, ya que los valores constantes son un tanto redundantes.

-ID: Es la ID que tendrá nuestro post. Esta ID se consigue obteniendo el valor máximo de todas las IDs que ya hay, incrementando su valor en uno, de la siguiente manera:

SELECT MAX(ID) from `wp_posts`

-Fecha: Es la fecha de creación de nuestra entrada. Tiene un formato específico y estricto que deberemos seguir para que nos funcione correctamente. El formato es el siguiente: AAAA-MM-DD HH:MM:SS
Obtendremos este formato de la siguiente manera:

$fecha = "DATE '" . date("Y-n-j H:i:s",time()) . "'";

Nota: notese que hay que concatenar “DATE ‘” a nuestra fecha, para que a la hora de introducirlo a la BD lo reconozca como tal.

-FechaGMT: Lo mismo que el anterior, incrementando +2 horas. Todo esto de las fechas, depende totalmente de donde nos encontramos.

$fecha_gmt = "DATE '" . date("Y-n-j ",time()) . (date("H",time())+2) . date(":i:s",time()) . "'";

-Contenido y Titulo: Este par de campos, sencillamente son lo que escribimos de titulo y contenido, por lo que no hay que tratar demasiado.

-ID parseada: Como comenté anteriormente, no es muy dificil de conseguir, simplemente seria concatenando una constante a la ID:

$id_parseada = "http://delanover.com/test_wordpss/?p=" . $id;

-Titulo parseado: Esta la he dejado para el final ya que es la más largilla de hacer, para la cual he creado una función específica. En principio, al ser el enlace, lo unico que puede contener son letras (quitaré las tildes), numeros, guiones bajos y guiones. Por lo que haré lo siguiente:

$titulo_parseado = parsear_titulo($titulo);

function parsear_titulo($titulo){
  //pasamos a minusculas y cambiamos caracteres
  $titulo = strtolower($titulo);
  $titulo = str_replace(" ", "-", $titulo);
  $titulo = str_replace("á", "a", $titulo);
  $titulo = str_replace("é", "e", $titulo);
  $titulo = str_replace("í", "i", $titulo);
  $titulo = str_replace("ó", "o", $titulo);
  $titulo = str_replace("ú", "u", $titulo);
  
  $caracteres_permitidos = array("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "ñ", "o", "p",
  			"q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "1", "2", "3", "4", "5", "6", "7", "8", "9",
  			"0", "_", "-");
  			
  //Si nos encontramos con un caracter no permitido (que no salga en el array anterior), lo eliminamos
  for($a=0;$a

3.1.3.-La tabla wp_postmeta

Afortunadamente para nosotros, el tratamiento de esta tabla será todavia más sencillo, y limitaré mi explicación por no tener demasiado que ver con el tema principal.

Explicaré brevemente los detalles dentro del código fuente:


//Obtenemos el ID maximo
$consulta_metapost = "SELECT MAX(meta_id) from `wp_postmeta`";
$respuesta_metapost= mysql_query($consulta_metapost);
if($resultado=mysql_fetch_array($respuesta_metapost))
	$_id = $resultado[0]+1;

//Introducimos el ID recogido, el ID anterior que teniamos del post, y dos valores constantes
$consulta2 = "INSERT INTO `wp_postmeta`(`meta_id`, `post_id`, `meta_key`,
`meta_value`) VALUES ($_id,$id,'_edit_last',1)";
$resultado_consulta2 = mysql_query($consulta2);
	
$_id++; //Aumentamos el ID ya que vamos a insertar otra fila
//Obtenemos un valor que meteremos, compuesto por el tiempo y el ID del autor
$meta_valor = time() . ":1";
$consulta3 = "INSERT INTO `wp_postmeta`(`meta_id`, `post_id`, `meta_key`,
`meta_value`) VALUES ($_id,$id,'_edit_lock','$meta_valor')";
$resultado_consulta3 = mysql_query($consulta3);

3.2.-Implementando la seguridad en nuestra aplicación

Muy bien, con todo esto ya deberia de funcionarnos el sistema, pero claro, falta lo más importante, implementar la seguridad con ese hash dinámico que generamos.

Lo más sencillo es crear una función que nos devuelva un valor booleano, en función de si el hash introducido es verdadero (entonces se ejecuta) o falso (devolviendo un error).

function comprobar_hash($hash){
$hora = date("H", time())+6; //Obtenemos la hora (la adecuamos en función de la hora del servidor a la hora de nuestro pais)
$dia = date("j", time()); //Obtenemos el dia

//Nuestro salt
$cadena = "lipman";

//En función del dia, generamos un resultado u otro
switch(date("N", time())){
  case 1:
  $nueva_cadena = "Q" . $cadena[0] . $cadena[1] . $cadena[2] . $cadena[3] . $cadena[4] . $cadena[5];
  break;
  case 2: $nueva_cadena = $cadena[0] . "W" . $cadena[1] . $cadena[2] . $cadena[3] . $cadena[4] . $cadena[5]; break;
  case 3: $nueva_cadena = $cadena[0] . $cadena[1] . "E" . $cadena[2] . $cadena[3] . $cadena[4] . $cadena[5]; break;
  case 4: $nueva_cadena = $cadena[0] . $cadena[1] . $cadena[2] . "R" . $cadena[3] . $cadena[4] . $cadena[5]; break;
  case 5: $nueva_cadena = $cadena[0] . $cadena[1] . $cadena[2] . $cadena[3] . "T" . $cadena[4] . $cadena[5]; break;
  case 6: $nueva_cadena = $cadena[0] . $cadena[1] . $cadena[2] . $cadena[3] . $cadena[4] . "Y" . $cadena[5]; break;
  case 7: $nueva_cadena = $cadena[0] . $cadena[1] . $cadena[2] . $cadena[3] . $cadena[4] . $cadena[5] . "U"; break;
  default:
  	$nueva_cadena = "error";
  	
}

//Obtenemos la cadena formada y la pasamos a MD5
$resultado = "///" . $dia . $nueva_cadena . $hora . "///";
$resultado = md5($resultado);

//Finalmente comprobamos si coincide con el hash pasado por parámetro
if($resultado==$hash)
	$final = "Verdadero";
else
	$final = "Falso";

return $final;
}

3.3.-Conclusión y funcionamiento final

Nos falta diseñar la página de "login" en la que tendriamos que recoger el titulo de la entrada, el contenido, y el hash en MD5. Este hash en MD5 recordemos que es nuestra contraseña aleatoria pasada a MD5. Un apunte respecto a esto: imaginemos que nos están esnifando la red y tal. Vale, usamos este sistema y todos felices, pero si a la hora de crear nuestro hash MD5 (para que posteriormente lo valide) usamos una herramienta externa en una página web, nos esnifan esto, y no tiene mucho sentido.

Para ello, recomiendo que tengais un programa o algo, ya que desde la consola de Windows, a diferencia de la Linux, no se puede obtener el MD5 de una cadena. Si no, si teneis un servidor web instalado, lo haceis desde ahí usando la función de PHP "md5".

4.-Códigos finales completos

crear.html




Metemos el hash

Titulo

Contenido

create.php

error
"; function parsear_titulo($titulo){ //Pasamos a minusculas y quitamos las tildes $titulo = strtolower($titulo); $titulo = str_replace(" ", "-", $titulo); $titulo = str_replace("á", "a", $titulo); $titulo = str_replace("é", "e", $titulo); $titulo = str_replace("í", "i", $titulo); $titulo = str_replace("ó", "o", $titulo); $titulo = str_replace("ú", "u", $titulo); $caracteres_permitidos = array("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "ñ", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "_", "-"); //Si encontramos un caracter que no está en el array de permitidos, lo eliminamos for($a=0;$a