The Blind Exploits To Rule Watchguard Firewalls Vulnerabilities

Source :- https://tutorialboy24.blogspot.com/2022/09/the-blind-exploits-to-rule-watchguard.html

 

Preface

Early this year, WatchGuard firewalls have been under attack multiple times, most notably by the Russian APT Sandworm and their malware, Cyclops Blink. Over the course of 4 months, the editor released three firmware updates, patching numerous critical vulnerabilities.

Coincidently, this was when I started looking for bugs in such firewalls for a red team engagement. This started a race against the clock: I needed to find a vulnerability - and make an exploit work - before a patch was released. Coincidentally, most of the vulnerabilities were blind, while knowledge was critical: despite having the same firmware, WG devices run on different CPU architectures and libc versions.

This blog post will follow the journey in which I discover 5 vulnerabilities - 2 patched along the way - and build 8 distinct exploits, and finally obtain an unpatched pre-authentication remote root 0-day on every WatchGuard Firebox/XTM appliance.

Introduction

Initial foothold

In 2021, while performing a red team engagement, my colleagues found a camera with weak credentials on our client's external network and managed to escalate the bug to RCE. To their disappointment, however, the camera could only reach one machine in the internal network: a firewall of the WatchGuard Firebox brand. Since I had a few days free, they asked me if I could have a quick look at it, and see if there were no low-hanging fruits.

Watchguard offers two main brands, Firebox and XTM appliances. Both come with various models (Firebox T10, T15, M440, M500, etc.), various computer architectures (x86_64, AARCH, PowerPC), and obviously, various firmware versions.

We weren't sure about the precise version of the target, but since the client was very serious security-wise, we expected it to be fully updated. A few queries on static files of the exposed HTTP interfaces confirmed it.

There was no way to find out the precise model or architecture however, so since the constructor also made its appliances available as a VMware virtual machine, I decided these were problems for later and imported the last version of the FireboxV VM into VirtualBox.

Attack surface

Watchguard firewalls expose two web interfaces: a standard "user" interface on ports 80/443, and an administration interface on ports 8080 / 4117. At the time, a quick Shodan search showed thousands of the latter, blatantly exposed on the internet.

This administration interface is built from a cherrypy python backend, but every sensitive action is done by sending XML-RPC requests to a C binary called wgagent. The binary runs in 64 bits, is not PIE, and is partial-RelRO; the system, however, has ASLR. Citing Wikipedia:

XML-RPC is a remote procedure call (RPC) protocol that uses XML to encode its calls and HTTP as a transport mechanism.

The only pre-authentication endpoint is /agent/login, to... authenticate. Here's an example authentication attempt:

 

Although the authentication was properly implemented (no logic bugs), this already felt like a very interesting attack surface: XML parsed using C.

XML-RPC parsing

XML-RPC expects a method name and parameters of various types and returns a response.

Parameters can be scalars, numbers, strings, dates, or more complex types like structures. You can think of the structure type as an associative array, like a dict in python. Each key-value pair is called a member.

The target, wgagent, always expects a single parameter with a "structure" type. If we go back to the example request, we can see this parameter, which contains a structure made of 4 members:

 

Internally, the binary uses libxml2  to parse the input. It produces a C structure containing the name of the XML-RPC method and a linked list of parameters, which themselves contain a linked list of members,  xmlrpc_member .

 

The XML-RPC request above would yield 4 members:

 

Every C structure and character buffer gets allocated dynamically, on the heap.

To send binary data, such as new firmware or encrypted files, member values ​​​​can also be sent as base64 using the following construct:

 

Additionally, to reduce the size of the POST data, the whole XML-RPC request can be gzip-compressed.

While looking at the implementation of the state machine, the first vulnerability erupted.

Vulnerability #1: Blind alphanumeric .bss overflow

Primitive

While parsing the XML, wgagent keeps track of its current position by storing the XPath of the current XML tag in a buffer located in the .bss, named current_xpath. For instance, while parsing the login request1, current_xpath would successively have the values ​​​​/methodCall , /methodCall/methodName, /methodCall/params, ..., /methodCall/params/param/value/struct/member/name, and then /methodCall/params/param/struct, /methodCall/params/param, etc.

When entering a new XML tag, the router concatenates a / and its name to the previous current_xpath value using strcat(). When parsing an exit tag, a NULL byte is written to replace the last / value.

For instance, here are the successive values ​​​​while parsing <A><B><C></C></B></A> (⊙ NULL BYTE):

 

However, the implementation is lazy: there's no bound check. By sending an XML document with a huge XML tag, strcat() writes out of bounds.

This bug comes with a few limitations:

we can only send characters that are a valid XML tag (az, 0-9 for instance, but not ? or,), and NULL bytes.

current_xpath is very close to the end of the BSS; nothing of interest comes after it in this section.

Luckily for us, security mitigations are not up to date. This solves both our problems:

Since the binary is not PIE, a lot of its addresses are known, and can be written in alphanumeric characters (for instance, 0x414450 would be PDA followed by 5 null bytes)

Since randomize_va_space is set to 1, right after the BSS comes the heap, which we can overwrite.

The glibc (ptmalloc) of the appliance I had was at version 2.28, which supports tcache with no mitigations. As such, the first chunk of the heap segment is the tcache array (tcache_perthread_struct). However, the tcache is very much solicited while the XML is being parsed (lots of allocations of various sizes), and overwriting anything but the first tcache bin (for chunks of size 0x20) yields a crash.

As a result, the primitive comes down to being able to overwrite the tcache pointer for chunks of size 0x20 with alpha-numeric characters.

Exploitation

While parsing the XML-RPC parameters, the binary will allocate a member structure to store a name, value, and the current size of the value. If a member has been parsed completely (<member> and </member> tags have been parsed ), and no <name> has been provided, the member and its value are freed. Otherwise, the program will process the request, return a response, and then free every member (and their name/value). As such, we can :

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值