A new network open source tool called graftcp (GitHub page) has been discovered in everyday attacks by the Sysdig Threat Research Team (TRT). Nowadays, threat actors try to improve their techniques by using new tools (as we mentioned in the PRoot article) to enhance the compatibility of their code to hit as many targets as possible and hide their traces properly.
Graftcp is a tool that allows attackers to set up a local proxy to conceal direct connections to well-known malicious domains or IPs and avoid detection. The innovative feature of this gadget is that it can re-route the traffic coming from a specific process without changing the global network configurations.
In this article, we will explain how graftcp works, why the attackers find this useful, and how to detect this kind of activity with Falco.
What is the difference with similar tools?
This is not the first time that we analyzed on our honeypot, threat actors trying to hide malicious connections by using SOCKS, SOCK5S, or classic network proxies. But when they try to perform this kind of action, they often struggle with firewall configurations, network configurations, or library loadings. Changes to these components are really unusual and are generally detected easily.
We’ve already seen some tools similar to graftcp (like tsocks or proxychains) that provide similar functions, despite the fact that they’re based on different mechanisms.
These tools use the ld_preload hack to wrap the default connect() syscall into a custom one. When starting a new connection, this tool checks if the destination IP is local. Otherwise, it will redirect the connection to the specified proxies. But the ld_preload trick is used in different techniques with different purposes, and is generally detectable since it edits the ld.so.preload file. Therefore, this stratagem is exploitable only for dynamically linked programs (e.g., scripts written in Python or Go).
So why is Graftcp cool?
Graftcp is a unique tool that sets itself apart from similar ones by its ability to hide and redirect network connections coming from a specific process. Unlike other tools that require changes to network configurations or wrap syscalls, graftcp is based on a clever utilization of the fork and ptrace system calls.
How does graftcp work?
When a new process is launched, graftcp forks it and traces it using the ptrace syscall. And when a connection is made, the call is intercepted, temporarily stopped, redirected to a local proxy, and then executed. This makes graftcp versatile and applicable to any type of process, not just dynamically linked executables.
With graftcp, you can execute any command (or open a new shell as well) and all network connections related to the spawned process will be routed through the local proxy. To ensure this, you only need to run the commands with the “graftcp” command preceding them.
Here is the architecture used:
Make things work
To get started with graftcp, let’s configure the environment:
- Choosing the desired proxy mode
- Entering your proxy credentials
- Setting the port for the local proxy
Once the configuration is complete, you can launch the local proxy by executing the graftcp command, which will spawn a listening process waiting for connections to redirect to your local proxy. As you can see here:
In a separate shell session, we are running the following commands:
18.104.22.168[email protected]:/# ./graftcp/graftcp curl ifconfig.me 22.214.171.124 [email protected]:/# ./graftcp/graftcp curl dockerhub.com <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd"> <html> <head> <title>301 Moved Permanently</title> </head> <body> <h1>Moved Permanently</h1> <p>Object moved permanently -- see URI list</p> </body> </html>Code language: Perl (perl)
What do we see?
The behavior of graftcp can be detected by monitoring the connect() system call. If the attacker runs a simple curl command preceded by the graftcp command, we’ll see two connections: the first against local proxy, and the second from host to the remote proxy server. As you can see here:
connect curl 127.0.0.1:36812 127.0.0.1:2233 | cmdline: curl ifconfig.me | parent cmdline:graftcp curl ifconfig.me connect graftcp-local 172.17.0.2:52086 126.96.36.199:443 | cmdline: graftcp-local -config graftcp/local/graftcp-local.conf | parent cmdline: graftcp-local -config graftcp/local/graftcp-local.confCode language: Perl (perl)
Despite what we see with a regular execution of the same command:
connect curl 172.17.0.2:37496 188.8.131.52:80 | cmdline: curl curl ifconfig.me | parent cmdline: bashCode language: Perl (perl)
Detect graftcp with Falco
Thanks to its behavior, graftcp can be easily detected when low visibility on processes and syscalls is in place. The Sysdig Threat Research Team (TRT) has developed two Falco rules to detect the usage of the graftcp tool.
Falco, an incubating project under the CNCF, provides real-time detection of unusual activities in cloud-native environments by sending alerts. Users have the option to utilize the default rules within Falco or create their own custom rules using its straightforward and adaptable language.
The first rule is based on the usage of ptrace syscall abused by graftcp to trace the process and eventually intercept and reroute the connections.
- rule: PTRACE anti-debug attempt condition: > evt.type=ptrace and evt.dir=> and evt.arg.request=1 and proc_name_exists output: > Detected potential PTRACE_TRACEME anti-debug attempt (proc.name=%proc.name proc.args=%proc.args fd.name=%fd.name proc.cmdline=%proc.pcmdline proc.pname=%proc.pname container=%container.info proc.pcmdline=%proc.pcmdline user.uid=%user.uid user.name=%user.name group.gid=%group.gid container.id=%container.id container.name=%container.name image=%container.image.repository) priority: WARNING - macro: localhost_connection condition: > ((((evt.type in (accept,listen,connect) and evt.dir=<)) and (fd.typechar = 4 or fd.typechar = 6)) and (fd.ip = "0.0.0.0" or fd.net = "127.0.0.0/8") and (evt.rawres >= 0 or evt.res = EINPROGRESS))Code language: Perl (perl)
The second one relies more on the network aspects of this tool, so it detects connections to localhost executed by processes with names that seem to be associated with graftcp.
- rule: Graftcp local proxy detected condition: > localhost_connection and (proc.name in ("graftcp", "graftcp-local") or proc.pname in ("graftcp", "graftcp-local")) output: > A connection to a potential local proxy was detected (proc.name=%proc.name proc.args=%proc.args fd.name=%fd.name proc.cmdline=%proc.pcmdline proc.pname=%proc.pname container=%container.info proc.pcmdline=%proc.pcmdline user.uid=%user.uid user.name=%user.name group.gid=%group.gid container.id=%container.id container.name=%container.name image=%container.image.repository) priority: WARNINGCode language: Perl (perl)
Threat actors’ tools are always evolving and becoming more and more sophisticated, as we can see with graftcp. Keeping the ruleset updated is the first step to detect new threats and, right after, using tools like Falco is crucial to have a wider and deeper visibility on systems.
Graftcp is a new technique that enables attackers to conceal their malicious or suspicious connections in a more advanced and challenging-to-detect manner than previous methods. This tool is used for defense evasion and is particularly useful when attackers need to hide and keep a connection alive, such as when they set up and deploy a miner on a remote host.
Having a runtime detection layer such as Falco that can identify this type of behavior is fundamental for your company’s security operations. This will enable you to detect such threats and minimize the risks of exploitation, cryptomining costs, and attacker persistence on your network.