course starting at
Take Penetration Testing with Kali Linux to gain invaluable penetration testing skills and earn your OSCP.
On a recent penetration test, we encountered an installation of CA ARCserve Backup on one of the target systems that piqued our interest. Like most “good” enterprise applications, ARCserve has processes that are running as SYSTEM so naturally, we went straight to work looking for vulnerabilities.
According to the vendor, CA ARCserve Backup delivers industry-leading, enterprise-class data protection for a wide range of operating environments. The CA ARCserve authentication service (caauthd.exe) validates the caroot user login and equivalence. It is required for GUI and backup server communication and uses a dynamic TCP port to serve incoming connections. Through our analysis, CA ARCserve Backup r16 sp1 fully patched was proven to be vulnerable and earlier versions, including r12.5, r15.0 and r16.0, were found to be vulnerable as well.
By replacing a particular xdr_rwslist object expected in an RPC authentication packet with another xdr_rwobject, the function sub_416E80 will call a non-existent or invalid virtual function that can be controlled by the attacker. Authentication is not required to trigger the bug and successful exploitation of this vulnerability for the caauthd.exe process will lead to remote code execution with NT AUTHORITY\SYSTEM privileges. Failed exploitation attempts will lead to a denial of service condition on the target system.
The code for our initial proof of concept is shown below.
The application crashes while the sub_416E80 function in the caauthd.exe module calls a virtual function of a RWSlist object at address 0x00416F48 as shown below in Figure 1:
In a legitimate RPC authentication packet, the RWSlist object looks like the following:
Since the caauthd.exe service does not check the type of the xdr_rwobject before dereferencing its vtable at address 0x00416F40 (Figure 1), omitting the RWSList object container can allow an attacker to load an invalid address into the EAX register, eventually controlling the execution flow (CALL EAX instruction at 0x00416F48, Figure 1).
The Exception Analysis previously presented refers to the caauthd.exe service crash induced by the following RPC packet (opcode 0x7a):
In the above code, the xdr_rwlist object was simply removed from the original buffer and sent to the target. As can be seen below, the vtable for the xdr_rwstring object does not contain a valid virtual function at offset +64h:
The resultant crash leads us to reach the following conclusion: the “vtable escape” forces the value 0x2f to be loaded into the EIP register instead of a valid virtual function address, causing an access violation while trying to execute instructions at that invalid memory location.
One possible way to control the execution flow is to replace the xdr_rwstring presented in the previous section with another xdr_rwobject. To quickly prove remote code execution with Data Execution Prevention disabled, we used the xdr_rwtime object. For this object, the vtable entry at offset 64h points to the middle of an ASCII string belonging to the .rdata section of rwxdr.dll as shown below.
Since the address 0x276e7365 falls within the heap range, an attacker could try to remotely allocate shellcode at that memory location, sending malicious crafted packets to the caauthd.exe service, before triggering the vulnerability.
“Unfortunately”, at least one function was proven to leak memory while processing incoming RPC packets. The function rwxdr.dll!xdr_string3, which performs the username xdr_string3 structure deserialization, doesn’t seem to correctly deallocate memory after its use.
As a result, sending multiple crafted RPC packets and specifying a large size for the username field, an attacker can reach the 0x276e0000 memory range in a couple of minutes.
The xdr structure used in our PoC is as follows:
The following PoC demonstrates the theory presented above:
Looking back our debugger after launching the proof of concept, we can see that we have complete control:
In the video below, you can see the proof of concept in action, with the debugger suspending execution at our breakpoint.