从网络设备或其他IoT设备提取到固件之后进行安全分析和漏洞挖掘工作,对 Sophos UTM进行安全分析时,发现其具体提供Web功能的是一个Linux文件,并没有发现web功能实现的html代码,通过Burp Suite抓包Web请求发现所有web页面的请求展示都是通过该Linux文件实现,自然必须对其进行解析才行继续分析,但难度非常大,一度束手无策,经过几天的详细排查分析,最终得以解决。
由于国内外资料网站均没有对Sophos UTM固件文件的反编译资料,故梳理成文,分享给大家。
分析
UTM是Unified Threat Management的缩写,简称为统一威胁管理,各个安全厂商都有自己的UTM产品,比较出名的是Fortinet、WatchGuard、Sophos等等。
此次需要进行安全分析的产品就是Sophos UTM,官方网站为:
https://www.sophos.com/en-us/products/unified-threat-management.aspx
获取到的固件文件为一个完整打包好的ISO光盘文件,使用VmWare Workstation安装之后, 就可以进入到UTM页面中。
本地访问的地址是:
https://192.168.21.100:4444/
一般来说获取一个ssh shell将会非常有助于安全分析,比完全从Web入手难度就要下降几个等级,下面就先来获取命令行shell。
1. 获取ssh shell & root shell
Sophos UTM默认情况下不允许使用ssh shell,必须在web页面中开启,Management-System Settings-Shell Acess开启shell功能。
注意要选择 "Allow password authentication",否则要使用证书验证,比较麻烦,不方便分析。
接着输入root和loginuser 两个用户的密码,并使用loginuserssh 登录。
1a@DESKTOP-22L12IV:$ ssh loginuser@192.168.21.100 2loginuser@192.168.21.100's password: 3Last login: Mon Nov 9 05:34:23 2020 from 192.168.21.1 4 5 6Sophos UTM 7(C) Copyright 2000-2014 Sophos Limited and others. All rights reserved. 8Sophos is a registered trademark of Sophos Limited and Sophos Group. 9All other product and company names mentioned are trademarks or registered10trademarks of their respective owners.1112For more copyright information look at /doc/astaro-license.txt13or http://www.astaro.com/doc/astaro-license.txt1415NOTE: If not explicitly approved by Sophos support, any modifications16 done by root will void your support.1718loginuser@test:/home/login > su19Password:20test:/home/login # id21uid=0(root) gid=0(root) groups=0(root),890(xorp)22test:/home/login # uname -a23Linux test 3.8.13.27-0.176377654.gd7350fc-smp64 #1 SMP Wed Sep 17 10:45:23 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux24test:/home/login # cat /proc/version25Linux version 3.8.13.27-0.176377654.gd7350fc-smp64 (abuild@axgbuild) (gcc version 4.3.4 [gcc-4_3-branch revision 152973] (SUSE Linux) ) #1 SMP Wed Sep 17 10:45:23 UTC 201426test:/home/login # cat /etc/version27 9.20800828test:/home/login #
2. 登录抓包
接下来就是登录抓包进行登录验证分析,使用的工具是Burp Suite Pro,正确配置之后,就可以有完整的登录验证包。
1POST /webadmin.plx HTTP/1.1 2Host: 192.168.21.100:4444 3User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0 4Accept: text/javascript, text/html, application/xml, text/xml, */* 5Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 6Accept-Encoding: gzip, deflate 7X-Requested-With: XMLHttpRequest 8X-Prototype-Version: 1.5.1.1 9Content-type: application/x-www-form-urlencoded; charset=UTF-810Content-Length: 28711Origin: https://192.168.21.100:444412Connection: close13Referer: https://192.168.21.100:4444/1415{"objs": [{"elements": {"login_username": "admin", "login_password": "test0011"}, "FID": "login_process"}], "SID": "0", "browser": "gecko", "backend_version": -1, "loc": "english", "_cookie": null, "wdebug": 0, "RID": "1604979704552_0.8572369473251601", "current_uuid": "", "ipv6": true}
发现登陆是使用json格式进行网络请求,方法是POST,请求的的接口文件是webadmin.plx,同时登陆之后的页面请求和展示都是通过webadmin.plx进行数据交互,接下来就是对webadmin.plx进行解析分析。
疑难问题
截止到此处,还没有遇到无法解决的问题,但深入文件分析时却给了沉重的一击,先来看webadmin.plx的文件属性:
1test:/var/sec/chroot-httpd/var/webadmin # file webadmin.plx2webadmin.plx: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.5, dynamically linked (uses shared libs), stripped
32位可执行文件,没有异常,但是当使用GDB调试的时候提示:
GDB提示文件格式不正确,事实是该文件可以执行:
1test:/var/sec/chroot-httpd/var/webadmin # ./webadmin.plx2[19370] WARN: Use of uninitialized value $ENV{"REQUEST_METHOD"} in string eq at /wfe/asg/modules/asg_fcgi.pm line 59.3test:/var/sec/chroot-httpd/var/webadmin #
有正常的错误返回,说明webadmin.plx文件正常,执行正常。
又发现该文件没有任何的Section:
1a@DESKTOP-22L12IV:$ readelf -S webadmin.plx2There are no sections in this file.
IDA Pro又能够正常解析elf文件,只有 LOAD节。
两眼一抓瞎,这时该怎么办?
GDB调试进程,失败。
尝试使用GDB附加调试进程,失败+1,not in executable format: File format not recognized。
尝试GDB附加父进程,然后调试子进程,失败+1,not in executable format: File format not recognized。
尝试GDB dumps内存,失败+1,not in executable format: File format not recognized。
GDB Server远程调试,失败+1,not in executable format: File format not recognized。
获取两个不同版本的webadmin.plx文件,进行补丁对比,无差别,失败+1。
查找分析ELF反调试手段,失败+1。
最后得出结论,GDB调试无效,继续接着找其他办法。
梳理一下目前得到的信息:
- webadmin.plx负责处理UTM系统登录,页面交互处理等等工作,是一个主体处理文件。
- ELF可执行程序,32位。
- 可正常执行。
- GDB调试无效。
- 无反调试。
- 补丁对比无效。
若进行安全分析和漏洞挖掘,就必须剁掉webadmin.plx,接着分析吧。
确认Perl 编译器
分析webadmin.plx,查找ELF中的字符串,其中几个字段尤为可疑:
1a@DESKTOP-22L12IV:Sophos_UTM$ strings webadmin.plx |grep Perl 2psym_Perl_newSVpv 3psym_Perl_stack_grow 4psym_Perl_Itmps_floor_ptr 5psym_Perl_sv_setiv 6psym_Perl_markstack_grow 7psym_Perl_Iexit_flags_ptr 8psym_Perl_save_int 9psym_Perl_push_scope 10psym_Perl_Isv_no_ptr 11psym_Perl_call_sv 12psym_Perl_Imarkstack_max_ptr 13psym_Perl_Istack_base_ptr 14psym_Perl_Gop_mutex_ptr 15psym_Perl_eval_pv 16psym_Perl_Gthr_key_ptr 17psym_Perl_call_list 18psym_Perl_Icurstackinfo_ptr 19psym_Perl_get_context 20psym_Perl_Guse_safe_putenv_ptr 21psym_Perl_IXpv_ptr 22psym_Perl_pop_scope
很明显,跟Perl有很大的关系。
IDA中也显示同样的结果,怀疑该webadmin.plx是由Perl编译出来的,接下来就是验证自己的想法。
搜索引擎中查找资料,发现主流有三款程序可以从Perl代码编译成ELF软件:PerlAPP,PerlCC,Perl2EXE,而针对Perl ELF反编译就只有52破解网站上有一份PerlAPP在Windows下的资料,Linux下的资料一无所有,也是奇葩,Perl越混越差了。
从IDA对webadmin.plx的反编译代码中分析查找,找到一处关键字:
1 v1 = *(_DWORD *)psym_Perl_Istack_sp_ptr(a1); 2 v2 = (int **)psym_Perl_Imarkstack_ptr_ptr(a1); 3 v3 = **v2; 4 --*v2; 5 v4 = (v1 - (*(_DWORD *)psym_Perl_Istack_base_ptr(a1) + 4 * v3)) >> 2; 6 v18 = sub_804E6EC(); 7 v33 = a1; 8 v34 = psym_Perl_get_hv(a1, "PerlApp::lic", 1); //PerlApp::lic,此处为关键字 9 if ( v4 )10 v19 = *(_DWORD *)(*(_DWORD *)psym_Perl_Istack_base_ptr(a1) + 4 * (v3 + 1));11 else12 v19 = psym_Perl_Isv_undef_ptr(a1);13 v20 = *(int **)(v18 + 48);14 licFree(*(_DWORD *)(v18 + 56));15 *(_DWORD *)(v18 + 56) = 0;
从PerlApp::lic关键字来分析,基本可以确认webadmin.plx是使用PerlAPP编译而成的ELF文件。
问题复现
webadmin.plx确认是由PerlAPP工具编译而来,接下来就来验证一下,在Linux环境下搭建一套PerlAPP环境。
PerlAPP的全称是Perl Dev Kit(PDK),由ActiveState公司开发,但是其已经在2016年不再进行更新维护,在2020年10月份正式终止软件生命周期。
https://www.activestate.com/blog/perl-dev-kit-pdk-now-end-of-life/
软件终止更新还好,影响不大,但网络上Linux版本的PerlAPP非常难找,最终是在一个不起眼的小网站上下载到了低版本的安装包(这又是一个辛酸的故事),进行安装测试。
PerlApp安装需要32位Active Perl(必须),而非操作系统自带的perl,又下载了一个低版本的Active Perl,才算完成PDK的安装(一把辛酸泪)。
最后拿一个最简单的perl示例代码来进行测试:
1[test@192 Desktop]$ cat test.pl 2#!/usr/bin/perl 34print "Hello, World!";5[test@192 Desktop]$ perl test.pl 6Hello, World!7[test@192 Desktop]$
使用PerlApp进行编译测试:
shell中也能够正常执行:
1[test@192 Desktop]$ ./test 2Hello, World! # 正常执行3[test@192 Desktop]$
使用GDB调试编译好的程序:
1[test@192 Desktop]$ gdb test 2GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-119.el7 3Copyright (C) 2013 Free Software Foundation, Inc. 4License GPLv3+: GNU GPL version 3 or later 5This is free software: you are free to change and redistribute it. 6There is NO WARRANTY, to the extent permitted by law. Type "show copying" 7and "show warranty" for details. 8This GDB was configured as "x86_64-redhat-linux-gnu". 9For bug reporting instructions, please see:10...11"/home/test/Desktop/test": not in executable format: File format not recognized # 同样的报错提示12(gdb)
好吧,同样的not in executable format: File format not recognized报错提示,完美复刻webadmin.plx遇到的问题。
反编译Perl源码
现在来梳理一下目前的信息:
1. webadmin.plx是使用 PerlApp编译而成的ELF文件
2. 不能使用GDB调试,GDB Server也不行
3. 网络上没有Linux反编译Perl的资料
在团队小伙伴ztop(此处应该有掌声)的帮助下,发现使用IDA的linux_server,结合IDA远程调试,就可以完美绕过GDB无法调试的问题。在Centos 7中无法使用IDA远程调试,不知道具体原因是什么,遂放弃,选择使用Kali 2018 R4,IDA的主机为Windows。
1root@kali:~# chmod +x linux_server 2root@kali:~# ./linux_server 3IDA Linux 32-bit remote debug server(ST) v1.22. Hex-Rays (c) 2004-2017 4Listening on 0.0.0.0:23946... 5========================================================= 6[1] Accepting connection from 192.168.21.1... 7Warning: Section header string table index 26 is out of bounds 8Hello, World! 9Looking for GNU DWARF file at "/usr/lib32/2651bcf6f5569acd1dba629eaaaa5f002af684.debug"... no.10Looking for GNU DWARF file at "/usr/lib32/.debug/2651bcf6f5569acd1dba629eaaaa5f002af684.debug"... no.11[1] Closing connection from 192.168.21.1...12==========================================================
linux_server的监听23946端口,需要在宿主机进行配置。
webadmin.plx的main函数中:
1signed int __cdecl paperl_main(int a1, int a2, int a3, _DWORD *a4, int (__cdecl *a5)(int)) 2{ 3 signed int v5; // ebx 4 int v7; // [esp+10h] [ebp-8h] 5 6 v7 = dword_805B4F8; 7 v5 = paperl_create((int ***)&v7, a1, a2, a3, a4, a5, 1); //此函数内部进行perl 代码执行。 8 paperl_destruct(v7); 9 return v5;10}
进入到paperl_create()函数内部:
1 ptr = sub_804C370(**v43, "*SCRIPTNAME", (int)"scriptname");2 if ( ptr )3 {4 v27 = (int *)sub_804C370(**v43, ptr, (int)"script"); //此函数对perl代码进行初始化5 v43[9] = v27;6 if ( !v27 || (v28 = (char *)sub_804C2D0(strlen(ptr) + 14, (int)"hashline"), (v43[8] = (int *)v28) == 0) )
找到关键代码位置:
1LOAD:0804E224 jz loc_804E32E 2LOAD:0804E22A mov eax, [edi] 3LOAD:0804E22C mov ecx, offset aScript ; "script" 4LOAD:0804E231 mov edx, [ebp+ptr] 5LOAD:0804E237 mov eax, [eax] 6LOAD:0804E239 call sub_804C370 ; 函数执行后,解密出perl代码 7LOAD:0804E23E mov [edi+24h], eax 8LOAD:0804E241 test eax, eax 9LOAD:0804E243 jz loc_804E51710LOAD:0804E249 mov edx, [ebp+ptr]11LOAD:0804E24F cld12LOAD:0804E250 mov ecx, 0FFFFFFFFh13LOAD:0804E255 xor eax, eax
经过一系列的仔细调试和分析,最终发现0804E239 call sub_804C370函数执行后,eax 指向堆的内存中出现了#!/usr/bin/perl字符,
验证它:
很明显都是明文字符,dump出来进行校验,获取到完整的webadmin.plx功能的perl源码:
1# setting line discipline to utf8 -------------------------- 2binmode( STDOUT, ':utf8' ); 3binmode( STDIN, ':utf8' ); 4 5# getting our paths 6my ( $apppath, $appname ) = &get_path_and_appname(); 7 8# load core config ------------------------------------------ 9die '[' . $$ . '] DIED: core configuration could not be found' unless -e $RealBin . '/core/res/config.ph';10my $config_basic = read_ph( $RealBin . '/core/res/config.ph' );11die "Could not read core config in [$RealBin/core/res/config.ph]!" unless $config_basic;1213# fetching application config ------------------------------14die '[' . $$ . '] DIED: application configuration could not be found' unless -l $RealBin . '/config';15my $config_app = read_ph( $RealBin . '/config' );16die "Could not read config for [" . $appname . "] in [" . $RealBin . "/config]!" unless $config_app;1718# initialize Astaro::Logdispatcher -------------------------19Astaro::Logdispatcher->init({20 syslogname => 'webadmin',21 myname => 'webadmin',22 redirect_stdout => 0,23 redirect_stderr => 0,24 configfile => 'core/res/core-log.conf',25 configset => {26 logvars => {27 logbitmask => 7,28 syslogmtypeinfo => 1,29 syslogcallerinfo => 1,30 tofilehandle => 031 }32 },33 logfiler => [34 '+ .',35 ],36 printfile => '/dev/null'37});
至此完整的获取Sophos UTM webadmin功能的perl源代码,剩余的工作就是基础的代码审计和漏洞挖掘。
梳理总结
Perl编译的ELF文件在执行时,会在/tmp/目录下生成libperl.so文件,perl 代码通过调用so文件接口j来执行,本次调试释放路径是/tmp/pdk-root/757fcfe556133c27007d41e4e52f4425/libperl.so ,也可以通过hook so的函数来达到获取perl源码的目的。
Perl语言编译的ELF文件,如何进行反编译,网络上没有任何有价值的信息,之前对python和go编译的ELF文件都有过反编译经验,按道理来说同样是能够通过反编译来获取源代码,但是GDB无法调试ELF困扰了很长时间,动态获取源码相对于静态去逆向解密算法要简单很多,虽然最后也并不简单。
其中的工作并没有去逆向解密算法,理清楚算法的情况下,可以编写脚本静态还原perl源代码,但以安全分析或漏洞挖掘为目标,算是告一段落了,后续工作也可以编写IDA的python脚本,动态提取源代码。
资料索引
1. demo
https://utm.trysophos.com/
2. 从PDK打包的可执行程序里面解出完整的Perl源码
https://www.52pojie.cn/thread-317216-1-1.html
注意事项
1. VmWare Workstation安装固件ISO需要选择低版本的兼容性,否则无法安装。
2. Active Perl要选择X32位安装包,X64的安装包无法安装PDK。