Summary
A critical Heap Buffer Overflow vulnerability has been identified in the AIS::Message class of AIS-catcher. This vulnerability allows an attacker to write approximately 1KB of arbitrary data into a 128-byte buffer.
We have successfully demonstrated Remote Code Execution (RCE) by exploiting this vulnerability. By overwriting adjacent C++ objects (specifically std::vector pointers), we achieved an Arbitrary Read/Write primitive, which was then used to hijack control flow and execute arbitrary commands.
Technical Details
1. The Root Cause: Byte vs. Bit Confusion
The vulnerability stems from a logical error in the bounds checking mechanism within Source/Marine/Message.cpp.
The AIS::Message class defines a fixed-size buffer:
// Source/Marine/Message.h
#define MAX_AIS_LENGTH (128 * 8) // 1024 bits
uint8_t data[128]; // 128 bytes
However, the setUint method incorrectly compares the length in bytes against the maximum length in bits:
// Source/Marine/Message.cpp
bool Message::setUint(int start, int len, unsigned val)
{
// VULNERABILITY:
// 'length >> 3' is the current length in BYTES.
// 'MAX_AIS_LENGTH' is 1024 (BITS).
// The check allows 'length' to reach 1024 BYTES before stopping.
// The buffer 'data' is only 128 BYTES.
if (length >> 3 >= MAX_AIS_LENGTH)
return false;
// ... write operation proceeds, overflowing 'data' by up to 896 bytes ...
}
2. Exploitation Path: From Overflow to RCE
The AIS::Message object layout in memory typically places the data buffer adjacent to other critical members, such as std::vector<std::string> NMEA.
Memory Layout:
[ data (128 bytes) ] [ padding ] [ NMEA vector (24 bytes) ] ...
Attack Chain:
- Overflow: We use
setUint to write past the 128-byte data buffer.
- Object Corruption: We overwrite the internal pointers of the
NMEA vector (_M_start, _M_finish, _M_end_of_storage).
- Arbitrary Read/Write: By controlling the vector's
_M_start and _M_finish pointers, we can trick the program into reading from or writing to any memory address when it accesses NMEA elements.
- RCE: We use this arbitrary write primitive to overwrite a function return address on the stack (or a GOT entry), redirecting execution to our shellcode or a ROP chain.
PoC (Proof of Concept)
We have developed a PoC that confirms the crash and the ability to overwrite memory.
1. Crash Verification (ASan)
This simple PoC triggers the overflow, causing AddressSanitizer to report a heap-buffer-overflow.
// poc.cpp
#include "Message.h"
int main() {
AIS::Message msg;
msg.clear();
// Write to bit offset 2000 (byte 250), far beyond the 128-byte limit
msg.setUint(2000, 32, 0xDEADBEEF);
return 0;
}
2. RCE Capability
In our internal testing, we successfully exploited this to execute arbitrary system commands (e.g., popping a calculator or shell) on a Linux environment by overwriting the return address.
Impact
- Remote Code Execution (RCE): Confirmed. An attacker can execute arbitrary code with the privileges of the
AIS-catcher process.
- Denial of Service (DoS): Trivial to crash the service by sending oversized packets.
Summary
A critical Heap Buffer Overflow vulnerability has been identified in the
AIS::Messageclass ofAIS-catcher. This vulnerability allows an attacker to write approximately 1KB of arbitrary data into a 128-byte buffer.We have successfully demonstrated Remote Code Execution (RCE) by exploiting this vulnerability. By overwriting adjacent C++ objects (specifically
std::vectorpointers), we achieved an Arbitrary Read/Write primitive, which was then used to hijack control flow and execute arbitrary commands.Technical Details
1. The Root Cause: Byte vs. Bit Confusion
The vulnerability stems from a logical error in the bounds checking mechanism within
Source/Marine/Message.cpp.The
AIS::Messageclass defines a fixed-size buffer:However, the
setUintmethod incorrectly compares the length in bytes against the maximum length in bits:2. Exploitation Path: From Overflow to RCE
The
AIS::Messageobject layout in memory typically places thedatabuffer adjacent to other critical members, such asstd::vector<std::string> NMEA.Memory Layout:
Attack Chain:
setUintto write past the 128-bytedatabuffer.NMEAvector (_M_start,_M_finish,_M_end_of_storage)._M_startand_M_finishpointers, we can trick the program into reading from or writing to any memory address when it accessesNMEAelements.PoC (Proof of Concept)
We have developed a PoC that confirms the crash and the ability to overwrite memory.
1. Crash Verification (ASan)
This simple PoC triggers the overflow, causing AddressSanitizer to report a
heap-buffer-overflow.2. RCE Capability
In our internal testing, we successfully exploited this to execute arbitrary system commands (e.g., popping a calculator or shell) on a Linux environment by overwriting the return address.
Impact
AIS-catcherprocess.