SkillAgentSearch skills...

Malproxy

Proxy system calls over an RPC channel

Install / Use

/learn @amitwaisel/Malproxy
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Malproxy

Proxy system calls over an RPC channel

Abstract

During a classic cyber attack, one of the major offensive goals is to execute code remotely on valuable machines. The purpose of that code varies on the spectrum from information extraction to physical damage. As defenders, our goal is to detect and eliminate any malicious code activity, while hackers continuously find ways to bypass the most advanced detection mechanisms. It’s an endless cat-and-mouse game where new mitigations and features are continuously added to the endpoint protection solutions and even the operating system (OS) itself, to protect the users against newly discovered attack techniques.

In this paper, we present a new approach for malicious code to bypass most of endpoint protection measures. Our approach covertly proxies the malicious code operations over the network, never deploying the actual malicious code on the victim side. We are going to execute code on an endpoint, without really storing the code on disk or loading it to memory. This technique potentially allows attackers to run malicious code on remote victims, in such a way that the code is undetected by the victim’s security solutions. We denote this technique as malproxying.

Interesting Use Cases

We chose some use cases on which we demonstrate the capabilities of our malproxying solution. Each use case is based on widely used hacking tools, which adversaries may upload and execute on the victims machines. By using our malproxying technique, they will be able to proxy the malicious activity and avoid storing those files on the victim side.

The tools we chose to proxy are netcat, sysinternal’s psexec and mimikatz. Proxying each tool requires handling some challenges as we describe below.

Netcat Proxying

Netcat tool for Windows uses Winsock library to create sockets for connecting or listening on certain ports over TCP or UDP. Thus, it is required to proxy socket-related API. As socket is merely a handle to system resources, it can be handled the same way like any other handle type. For our demonstration purposes, we focus on synchronous socket operations.

[TBD]

PsExec Proxying

PsExec is a light-weight tool that remotely executes processes on other systems, without having to manually install client software. PsExec's most powerful uses include launching interactive command-prompts on remote systems and remote-enabling tools like IpConfig that otherwise do not have the ability to show information about remote systems.

Note: Some antivirus scanners report that one or more of the tools are infected with a "remote admin" virus. None of the PsTools contain viruses, but they have been used by viruses, which is why they trigger virus notifications.

We would like to run psexec from a victim machine and execute code on another victim, without deploying the suspicious file on the first victim.

[TBD]

Mimikatz Proxying

Mimikatz is an open-source tool, developed by Benjamin Delpi, that is capable of extracting plaintexts passwords, hashes, PIN codes and kerberos tickets from memory. Mimikatz can also perform pass-the-hash, pass-the-ticket or build Golden tickets. That’s why its techniques and implementation are widely used by adversaries that wish to put their hands on valuable strong Windows accounts.

[TBD]

Malproxy Solution

Our goal is to implement and show a proof of concept for allowing malicious code execution on an endpoint, without really storing the code on disk or loading it to memory.

Our approach can be implemented on various operating systems. We chose to focus on Windows environment as this is the most popular operating system, both for users and malware, and it is by far the most attacked operating system that exists today.

As a proof of concept, we make some assumptions about the environment. We assume the attacker has remote code execution capabilities on the victim, with highest NT AUTHORITY\SYSTEM privileges that allow the execution of our victim-side component. We assume all operations of that component may be monitored by endpoint security solution — as to be discussed in the "Bypassing Endpoint Security" section below.

We will start by discussing about emulation. A piece of software which is executed in some environment may interact with that environment, thus change its execution flow based on data received from its environment. Basically, total control of the environment in which a software executes it, allows us to control the output it returns to the software.

An application that does not use any external function is fully self-contained and its execution flow is predetermined on compilation time. On the other hand, when an application relies on the operating system calls and reacts to the environment and ecosystem in which it is executed, the execution flow may differ among different machines and platforms. Therefore, controlling the output returned from the system calls will control and change the way the code is executed. This fundamental fact is the base for any sandboxing tool or virtualization platform.

The foundations of our solution lay on the emulation/virtualization of system calls mechanism that exists on most popular operating systems. We created a tool that has two main components, called stubs:

  1. One runs on the attacker machine, and we will refer to it as the attacker stub. This is the attacker side of the tool; its purpose is to emulate any kind of Windows PE file (DLL or EXE) and control all the system calls that are called from inside the sandboxed file.
  2. The other runs on the victim machine, and we will refer to it as the victim stub. This is the victim side of our solution; its purpose is to receive system call requests, execute those and send the response back to the attacker side.

Both components communicate over some network protocol that allows the attacker side to send system call requests to the victim side. As mentioned above, those system calls can be either Win32 API functions or Native API functions. We will dive deeper into both possibilities later on.

By proxying the relevant imported system calls from the attacker side to the victim component, the emulated code "at home" executes the same code flow as it would have been executed if it was launched directly on the victim side.

For example, one of the use cases we show below in detail is running Mimikatz tool to dump and parse credentials from LSASS.exe memory. In order to achieve its goal, Mimikatz imports some system calls which allow it to interact with LSASS.exe and read its virtual memory: OpenProcess, OpenProcessToken, NtQuerySystemInformation, NtQueryInformationProcess, ReadProcessMemory, RtlAdjustPrivilege and more. There are many other system calls Mimikatz tool imports, but those execute the same flow on every Windows environment, therefore it doesn’t matter whether we execute them on the attacker machine or on the victim machine. Some of those functions are BCryptGenerateSymetricKey, BCryptDecrypt, RtlEqualUnicodeString, ConvertSidToStringSidW and others. By analyzing all the system calls executed by Mimikatz, we have carefully chosen what functions should be proxied, and built our attacker and victims stubs accordingly. By proxying those functions, executing Mimikatz on the attacker machine will actually open a handle to LSASS.exe on the victim machine, and the memory buffer returned from ReadProcessMemory will contain data from the victim-side LSASS.exe. During the execution, Mimikatz is loaded in the attacker machine’s memory - far away from the victim’s machine and its endpoint protection solutions. As far as Mimikatz tool is concerned, all system calls are executed on the local OS. Our attacker-side stub replaces the precompiled Mimikatz’s IAT to direct the relevant function imports to the proxy stubs, instead of the original OS exported implementation. This topic is described in detail below.

Proxying Windows system calls is far from being trivial. Win32 API functions have several possible prototypes, which we describe below. We partially covered those types in our proof of concept. Future research and work may cover the rest to allow proxying of any Win32 API call.

Proxying Win32 API Functions

Our solution has to deal with all aspects of different prototypes when it proxies any Win32 API or any Native API function:

  1. The attacker side has to simulate the same calling convention as the original API function, so the emulated malicious code will behave as expected.
  2. The attacker side has to serialize all input arguments — primitives and pointers, so they will be parsed and analyzed by the victim side.
  3. The victim side has to serialize all output arguments. The attacker side has to deserialize them and set the original output arguments accordingly.
  4. The return value must be serialized on the victim side and parsed on the attacker side. Dealing with the return value may be quite complicated, as explained below.

We have to pay attention to some possible pitfalls:

  1. Input/output buffer arguments may contain pointers to other internal structures. The serialization and parsing logic can be recursively applied to proxy those internal objects.
  2. In our proof of concept we implemented a default shallow serialization so internal pointers are serialized/parsed by-value. This means that one side may encounter a pointer to some memory address which is valid on the other side.
  3. Our implementation supports adding custom code for serialization and parse of every structure — so all internal pointers will be proxied correctly. For example, when a linked-list node is passed, it might be required to serialize and deserialize the entire list - because the malicious code iterates over it. Therefore, the malicious logic dictates how those structures have to be handled.

Handling Input Arguments

Input arguments passed to the proxied functions are treated as follows:

  1. Primitives

Related Skills

View on GitHub
GitHub Stars100
CategoryDevelopment
Updated2mo ago
Forks15

Languages

C#

Security Score

80/100

Audited on Jan 29, 2026

No findings