Sophos XG 漏洞调试环境搭建
0x00 前言
Sophos UTM 和 Sophos XG 是两款不同的产品,前者偏向于通用威胁管理,后者偏向于硬件防火墙。本文将要介绍 Sophos XG 漏洞调试环境的搭建方法。
0x01 简介
本文将要介绍以下内容:
- 环境搭建
- jetty 调试环境搭建
- csc 配置文件解密
- Postgresql 数据库查询
0x02 基础知识
架构如下图
注:图片引用自 https://codewhitesec.blogspot.com/2020/07/sophos-xg-tale-of-unfortunate-re.html
总的来说,分为以下三部分:
- Jetty:处理 Web 数据,将数据转发至 csc 作进一步处理
- csc:主程序:加载 Perl Packages,实现主要功能
- Postgresql:用来存储数据
我在实际研究过程中,这三部分遇到了以下问题:
- Jetty:添加调试信息后无法启动 java
- csc:csc 加载 Perl Packages 后会自动删除,无法获得 Perl Packages 的实现细节
- Postgresql:用户权限低,无法查询数据库表
下面将要逐个介绍三个问题的解决方法
0x03 环境搭建
1.下载安装包
官方网站默认只提供最新版本的下载,但是可以通过猜测正确的版本号下载旧版本
- 例如 18.5.3 Virtual Installers: Firewall OS for VMware: https://download.sophos.com/network/SophosFirewall/installers/VI-18.5.3_MR-3.VMW-408.zip
- 18.5.2 Virtual Installers: Firewall OS for VMware: https://download.sophos.com/network/SophosFirewall/installers/VI-18.5.2_MR-2.VMW-380.zip
2.导入 VMware Workstation
下载得到 zip 文件,解压后运行 sf_virtual.ovf
3.VMware Workstation 网卡配置
需要添加两个网卡 VMnet7
和 VMnet8
,VMnet7 设置为 Host-only
和 172.16.16.0
,VMnet8 设置为 NAT
,具体方法如下:
(1)VMnet7
打开 VMware Workstation,依次选择 Edit
-> Virtual Network Editor...
Add Network...
-> VMnet7
VMnet7 设置为:
- Type: Host-only
- Subnet Address: 172.16.16.0
(2)VMnet8
VMnet8 设置为:
- Type: NAT
4.Sophos XG 网卡配置
- Network Adapter 设置为
VMnet7
- Network Adapter 2 设置为
VMnet8
- Network Adapter 3 设置为
VMnet8
配置如下图
5.启动 Sophos XG
默认登录口令: admin
6.查看 IP 地址
依次输入 1.Newwork Configuration
-> 1.Interface Configuration
得到 LAN 的 ip 为 172.16.16.16
7.进入 Web 配置页面进行激活
浏览器访问 https://172.16.16.16:4444
注册页面选择: I don't have a serial number(start a trial)
按照提示进行注册
注册成功后,重新访问 https://172.16.16.16:4444 进行配置
0x04 jetty 调试环境搭建
1.查看 Java 进程相关信息
执行命令: ps ww|grep java
输出:
java 3238 923 root 1393m 264m S /lib/jvm/java-11-openjdk/bin/java -Xmx384m -Xms12m -Xss256k -XX:MaxMetaspaceSize=100m -Dhybrid.enabled=false -Djna.tmpdir=/tmp/java -Djava.io.tmpdir=/tmp/java -Dsun.jnu.encoding=UTF-8 -Dfile.encoding=UTF-8 -Djava.awt.headless=true -Djetty.home=/usr/share/jetty -Djetty.base=/usr/share/jetty -jar /usr/share/jetty/start.jar --lib=/usr/share/webconsole/properties/
从输出中得到 Java 版本为 java-11-openjdk
2.定位配置文件
配置文件路径为 /usr/bin/jetty
,内容如下:
#!/bin/sh
if [ "${RAM}" == "2GB" ]; then
heap_size=256
elif [ "${RAM}" == "4GB" ]; then
heap_size=384
else
heap_size=512
fi
HYBRID_ENABLED=false
if [ $HYBRID_ENABLED = true ]; then
HYBRID_ENABLED=`opcode gethainfo -s nosync | grep -q "hamode=1" && echo "true" || echo "false"`
fi
if [ ! -d /tmp/java ]; then
mkdir /tmp/java
fi
/scripts/umnt_mount_dir.sh "JVM" "/tmp/java" "mount"
##
# sun.jnu.encoding=UTF-8 - System property is required with file.encoding otherwise some java APIs unable to read file having double byte characters in file name.
##
exec /lib/jvm/java-11-openjdk/bin/java -Xmx${heap_size}m -Xms12m -Xss256k "-XX:MaxMetaspaceSize=100m" "-Dhybrid.enabled=${HYBRID_ENABLED}" "-Djna.tmpdir=/tmp/java" "-Djava.io.tmpdir=/tmp/java" "-Dsun.jnu.encoding=UTF-8" "-Dfile.encoding=UTF-8" "-Djava.awt.headless=true" "-Djetty.home=/usr/share/jetty" "-Djetty.base=/usr/share/jetty" -jar /usr/share/jetty/start.jar "--lib=/usr/share/webconsole/properties/"
/scripts/umnt_mount_dir.sh "JVM" "/tmp/java"
exit $?
3.添加调试参数
修改文件属性: mount -o rw,remount /
在 exec 所在行添加调试参数: "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000"
4.重启服务
执行命令: service tomcat:restart -ds nosync
查看服务状态: service -S | grep tomcat
发现 tomcat 状态为 STOPPED
为了获得详细的报错信息,直接运行 /usr/bin/jetty
输出:
Error occurred during initialization of VM
Could not find agent library jdwp on the library path, with error: libjdwp.so: cannot open shared object file: No such file or directory
发现是 JDK 的问题,这里选择替换一个完整的 JDK
5.替换 JDK
下载 jdk-11.0.15_linux-x64_bin.tar.gz 并上传至 Sophos XG
备份原文件夹: cp -r /lib/jvm/java-11-openjdk /lib/jvm/java-11-openjdk_backup
将 jdk-11.0.15_linux-x64_bin.tar.gz 解压: tar zxvf /tmp/jdk-11.0.15_linux-x64_bin.tar.gz
替换 /lib/jvm/java-11-openjdk
:
rm -rf /lib/jvm/java-11-openjdk
cp -r /tmp/jdk-11.0.15 /lib/jvm/java-11-openjdk
6.再次重启服务
执行命令: service tomcat:restart -ds nosync
查看服务状态: service -S | grep tomcat
发现 tomcat 状态为 RUNNING
确认参数被修改,执行命令: ps ww|grep java
输出:
java 1827 923 root 1454m 158m S /lib/jvm/java-11-openjdk/bin/java -Xmx384m -Xms12m -Xss256k -XX:MaxMetaspaceSize=100m -Dhybrid.enabled=false -Djna.tmpdir=/tmp/java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000 -Djava.io.tmpdir=/tmp/java -Dsun.jnu.encoding=UTF-8 -Dfile.encoding=UTF-8 -Djava.awt.headless=true -Djetty.home=/usr/share/jetty -Djetty.base=/usr/share/jetty -jar /usr/share/jetty/start.jar --lib=/usr/share/webconsole/properties/
7.修改防火墙规则
执行命令: iptables -I INPUT -p tcp --dport 8000 -j ACCEPT
8.使用 IDEA 远程调试
如下图
在调试过程中,如果遇到无法下断点的情况,重启 java 服务即可: service tomcat:restart -ds nosync
0x05 csc 配置文件解密
查看 csc 进程相关信息
执行命令: ps ww|grep csc
部分输出:
csc 859 1 root 25916 23600 S csc -L 3 -w -c /_conf/cscconf.bin
csc 869 859 root 8628 452 S csc -L 3 -w -c /_conf/cscconf.bin
cfs 870 859 root 34736 29380 S {cfs} csc -L 3 -w -c /_conf/cscconf.bin
listener 871 859 root 21752 15088 S {listener} csc -L 3 -w -c /_conf/cscconf.bin
lcdd 889 871 root 21108 13556 S {lcdd} csc -L 3 -w -c /_conf/cscconf.bin
postgres 890 871 root 29712 25040 S {postgres} csc -L 3 -w -c /_conf/cscconf.bin
sigdb 891 871 root 26756 23208 S {sigdb} csc -L 3 -w -c /_conf/cscconf.bin
reportdb 892 871 root 26756 23104 S {reportdb} csc -L 3 -w -c /_conf/cscconf.bin
awarrensmtp 893 871 root 25916 22296 S {awarrensmtp} csc -L 3 -w -c /_conf/cscconf.bin
csc 进程读取 /_conf/cscconf.bin
作为配置文件,而 /_conf/cscconf.bin
是一个加密的文件,所以这里需要对 /_conf/cscconf.bin
进行解密
这里我采用的方法是通过 IDA 修改程序代码,改变实现逻辑,导出解密后的配置文件
使用 IDA 加载 csc,查看 main()
函数的实现逻辑,部分代码:
signed int __cdecl csc_main(int a1, char *const *a2)
{
//****ignore code*****//
if ( strlen(v14) > 4 )
{
v4 = strlen(v14);
if ( !strcmp(&v14[v4 - 4], ".bin") )
{
extract_conf((int)v14);
v17 = 1;
v14 = "/_conf/csc/csc.conf";
}
}
//****ignore code*****//
if ( v17 )
system(
"rm -rf /_conf/csc/csc /_conf/csc/csc.conf /_conf/csc/cscconf/ /_conf/csc/constants.conf /_conf/csc/cscconf.tar.g"
"z /_conf/csc/global.conf /_conf/csc/cfsconf /_conf/csc/service /_conf/csc/bind_file_list");
//****ignore code*****//
}
分析以上代码,csc 先调用 extract_conf()
函数导出配置,最后执行系统命令 rm -rf /_conf/csc/csc /_conf/csc/csc.conf /_conf/csc/cscconf/ /_conf/csc/constants.conf /_conf/csc/cscconf.tar.gz /_conf/csc/global.conf /_conf/csc/cfsconf /_conf/csc/service /_conf/csc/bind_file_list
删除配置文件,导致我们无法直接获得相关配置文件
查看 extract_conf()
函数的实现代码:
unsigned int __cdecl extract_conf(int a1)
{
int v2; // [esp+18h] [ebp-10h]
unsigned int v3; // [esp+1Ch] [ebp-Ch]
v3 = __readgsdword(0x14u);
system("mount --make-private /_conf/csc");
if ( mount("none", "/_conf/csc", "tmpfs", 0, 0) )
{
puts("mount tmpfs failed");
exit(70);
}
v2 = sub_8052494(a1, "/_conf/csc/cscconf.tar.gz");
if ( v2 == -1 )
{
printf("Cannot read file %s\n", a1);
exit(70);
}
if ( v2 == -2 )
{
printf("Cannot read file2 %s\n", a1);
exit(70);
}
system("tar -zxf /_conf/csc/cscconf.tar.gz -C /_conf/csc");
return __readgsdword(0x14u) ^ v3;
}
分析以上代码,csc 先调用 sub_8052494()
函数对 /_conf/csc/cscconf.tar.gz
进行解密,接着执行系统命令 tar -zxf /_conf/csc/cscconf.tar.gz -C /_conf/csc
将配置文件释放到文件夹 /_conf/csc
综合以上分析,我们可以采取以下方式导出配置文件:修改 csc 程序,将释放路径 /_conf/csc
修改为另一路径,例如 /var/aaaaa
,那么,csc 在删除配置文件时,由于指定了固定的绝对路径,导致无法删除新的文件夹,这样我们就能从中获得完整的配置文件
具体的实现方法如下:
(1) 修改 csc
使用 IDA 加载 csc,查看 Exports
,找到 extract_conf
,双击进入 IDA View
,定位到字符串 tar -zxf /_conf/csc/cscconf.tar.gz -C /_conf/csc
,如下图
切换到 Hex View,如下图
将 /_conf/csc
修改为 /var/aaaaa
,如下图
右键选择 Apply changes
依次选择 Edit
-> Patch program
-> Apply patches to input file...
-> OK
,生成新的文件 csc
(2) 替换 csc
通过 ssh 登录,上传新的文件 csc,保存至 /tmp/csc
备份 csc 并进行替换,执行以下命令:
mount -o rw,remount /
cp /usr/bin/csc /usr/bin/csc_original
mkdir /var/aaaaa
cp /tmp/csc /usr/bin/csc
chmod 755 /usr/bin/csc
ll /usr/bin/csc
reboot
(3) 确认配置文件是否导出成功
等待系统重启,进入底层 shell,依次输入 5.Device Management
-> 3.Advanced Shell
查看文件夹 /var/aaaaa
,如下图
配置文件导出成功
(4) 恢复 csc
mount -o rw,remount /
cp /usr/bin/csc_original /usr/bin/csc
reboot
(5) 下载配置文件
通过 ssh 登录,下载文件夹 /var/aaaaa
中的内容
0x06 Postgresql 数据库查询
查看端口信息,执行命令: netstat -tulpen |grep postgres
输出:
tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN 65534 3800 1087/postgres
tcp 0 0 127.0.0.1:5433 0.0.0.0:* LISTEN 65534 5846 1182/postgres
tcp 0 0 127.0.0.1:5434 0.0.0.0:* LISTEN 65534 5813 1161/postgres
通过搜索,发现以上三个数据库的连接信息依次对应以下三个文件:
- /usr/share/webconsole/properties/ConnectionPool.cfg
- /usr/share/webconsole/properties/ConnectionPoolForReports.cfg
- /usr/share/webconsole/properties/ConnectionPoolForSignature.cfg
文件中的配置信息如下:
- JDBCConnectionURL=jdbc:postgresql://127.0.0.1:5432/corporate?user=pgrouser&autoReconnect=true
- JDBCConnectionURL=jdbc:postgresql://127.0.0.1:5433/iviewdb?user=pgrouser&autoReconnect=true
- JDBCConnectionURL=jdbc:postgresql://127.0.0.1:5434/signature?user=pgrouser&autoReconnect=true
测试命令 1:
psql -p 5432 corporate -U pgrouser
corporate=> \d
输出:
ERROR: permission denied for relation pg_class
提示没有权限
测试命令 2:
psql -p 5432 corporate -U pgrouser
select * from tbluser;
能够获得用户信息
注:
将用户 pgrouser 换成 nobody 具体相同的权限
从以上信息得知,用户 pgrouser 和 nobody 都不是 root 用户,功能受限,下面尝试寻找 root 用户
对解密的 csc 配置文件进行检测,定位到 \service\postgres.csc
,关键文件内容:
EXEC /bin/synccmd "/sbin/pg_dump -U pgroot corporate -a --disable-triggers -t tblhavmac -f /tmp/corphavmac"
EXEC /bin/synccmd "/sbin/pg_dump -U pgroot corporate -a --disable-triggers -t tblinterface -t tblipaddress -f /tmp/corpifdb"
EXEC /bin/synccmd "/sbin/pg_dump -U pgroot corporate -a --disable-triggers -n config -T tbllivesslvpnusers -T tblhbcloudcredential -f /tmp/corpdb"
找到关键用户 pgroot
测试命令 3:
psql -U pgroot -d corporate
\d
执行成功
0x07 小结
本文介绍了在搭建 Sophos XG 调试环境过程中一些问题的解决方法。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: Zimbra-SOAP-API 开发指南4——邮件导出和文件夹共享
下一篇: Jvm 常量池
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论