# Fortios 逆向笔记 **FortiOS** 是 Fortinet 公司为其 **FortiGate 等安全设备**(如防火墙、UTM、安全路由器等)开发的专有操作系统。它是一个**专注于网络安全功能的嵌入式操作系统**,整合了防火墙、VPN、入侵防御系统(IPS)、防病毒、Web 过滤、应用控制、沙箱等安全功能。 由于是定制系统,登录后也是定制命令行,不能像Linux那样执行命令。早期的一些产品也会提供进入后台shell的命令(https://docs.fortinet.com/document/fortiweb/7.6.3/administration-guide/517783/run-backend-shell-commands),但本次逆向的目标产品系统中并没有该命令。起初对该系统目录结构不了解因此打算先对其系统镜像解包静态分析。在后续分析中查阅资料发现该系统的分析资料很多([1]、[2]、[3])。 ## 文件系统逆向 系统镜像是vmdk格式,可以直接7zip解包后用cpio解压文件系统。当然也可以通过虚拟机添加硬盘后再挂载的方法查看vmdk镜像内容。但这里遇到了一些问题:起初总是挂载失败dmesg显示: ```bash 240.073748]EXT4-fs(sdb2): I/0 error while writing superblock 240.073760]EXT4-fs(sdb2): mount failed 240.074578]Aborting journal on device sdb2-8. ... ``` 这时发现目标镜像磁盘格式是ext3,而挂载目标镜像磁盘的系统磁盘格式是ext4。试着找了一个Ubuntu16.04该系统磁盘格式与目标镜像磁盘格式相同,这次成功挂载。但挂载后发现磁盘可读不可写,即使以可读可写的权限挂载依然无法修改镜像中的内容。最后尝试复制一个新镜像,这里使用qemu自带命令: ```bash # 安装qemu工具(如未安装) sudo apt-get install qemu-utils # 转换/修复VMDK文件 qemu-img convert -O vmdk corrupted.vmdk new.vmdk ``` 复制后即可正常修改镜像内的文件了。 若直接修改镜像内文件启动系统后,系统会直接报错退出,原因是该系统在启动前有完整性校验检查,在smit程序sub_40CA50函数内: ```c if ( !(unsigned int)sub_40B3C0(&qword_619D40) ) { if ( (unsigned int)fe_n_disk_data_is_backup() ) message0("** booting from BACKUP device\n"); if ( (int)fips_check_firmware(0LL) <= 0 ) <--patch point { message0("Firmware integrity check failed!\n"); sub_40FC00(); message1("Power down...\n"); while ( 1 ) pause(); } message0("Firmware integrity check succeeded!\n"); } ``` 可以将完整性校验函数返回值的校验逻辑修改(小于等于零改为大于零)直接跳过检测。 ## 定位用户密码存储路径 FortiOS 不会以明文或标准 Linux 格式(如 `/etc/passwd`, `/etc/shadow`)存储用户密码。通过grep登录密码验证相关字符串(如 “Login incorrect”)可以定位密码验证主要逻辑在libauth.so中实现,接着再写脚本定位哪些应用链接了libauth.so库: ```bash $ cat 1.sh for f in ./bin/*; do if file "$f" | grep -q ELF; then if ldd "$f" 2>/dev/null | grep -q "libauth"; then echo "$f" fi fi done ``` 搜索结果并不多,逐个确认即可,最后定位到程序 getty。用户密码校验流程在libauth.so的`admin_login`函数实现。最终调用libnocmdbase.so的`valid_passwd`函数将输入的密码加密后与之前存储的加密后的密码做比较,若相同则调用 `/bin/cli`启动用户定制命令行。动态调试时未定位用户密码存储的路径,遂通过strace进行调试: ``` ... openat(AT_FDCWD, "/dev/cmdb/18", O_RDONLY|O_NOFOLLOW) = 5 ... openat(AT_FDCWD, "/dev/cmdb/6", O_RDONLY|O_NOFOLLOW) = 5 ... ``` 发现在输入用户名后会打开`/dev/cmdb`下的文件获取其内容。查看该文件内容: ```bash # cat /dev/cmdb/18 ����N!#E maintainerXXXXXXXXXXXXXXWIPhF adminSH23oDvM09OXSF5nKnkZTO/fVoiwFzJfWfx/8MTGU+mRmLehSfGX28xbX35q0Q=A1G remote_wildcardXXUp2ozpdysrQA1H admin_ssoXXXXXXXXXXXXXXC# ``` 可发现加密后的admin用户密码。 ## 参考资料 [1] https://www.noways.io/blogs/tech/fortigate-firmware-analysis [2] https://forum.butian.net/share/2166 [3] https://github.com/sysirq/note/tree/f2a44d7a192a5de1e30e7e8aa945339b89822bac/%E5%AE%89%E5%85%A8%E7%A0%94%E7%A9%B6/%E6%BC%8F%E6%B4%9E%E7%A0%94%E7%A9%B6/Fortinet