# Open-source toolset of an Ivanti CSA attacker
In recent incident responses where the root cause was an Ivanti CSA compromise, Synacktiv’s CSIRT came across multiple open-source tools used by threat actors. This article dives into each of these tools, their functionalities and discusses efficient detection capabilities.
Looking to improve your skills? Discover our **trainings** sessions! Learn more.
# Introduction
In September and October 2024, Ivanti published multiple1 security2 advisories3 regarding security policy bypasses and remote code execution vulnerabilities in their Cloud Services Appliance (CSA) product. It was later revealed by FortiGuard Labs Threat Research’s work4 that some threat actors had been actively chaining these vulnerabilities as early as September 9, 2024, before any security advisory or patch was publicly released by Ivanti.
In some compromise scenarios, even though the initial access stemmed from the exploitation of zero-day vulnerabilities, later stages were short of such proficient attacker tradecraft. Threat actors were seen using known malicious tools and noisy payloads for lateral movement, persistence and credential dumping.
Synacktiv’s CSIRT was recently in charge of different forensic investigations where the root cause was a vulnerable CSA appliance exposed to the internet. During these engagements, we found a set of open-source tools used by the attacker to achieve its goals. In this article, we take a tour of the OSS toolset from an Ivanti CSA exploiter and discuss related detection capabilities.
# Tunnels
## suo5
After initial compromise of the Ivanti CSA appliance, the attacker managed to move to an internet-facing Exchange Server used for OWA connections. They planted an HTTP proxy tunnel going by the name of **suo5**. Available publicly on GitHub, with an initial commit dated February 2023, this tool is presented as a more performant alternative to other tunnelling tools such as reGeorg and Neo-reGeorg.
Interestingly enough, the GLASSTOKEN custom webshell, used during intrusions linked to the exploitation of 0-day vulnerabilities in Ivanti Connect Secure VPN5 in January 2024, was based on the Neo-reGeorg tool. Additionally, the reGeorg tool was used as a commodity webshell in attacks linked to the exploitation of 0-day vulnerabilities in Microsoft Exchange6 in March 2021.
The `suo5.aspx` webshell was dropped on the Exchange Server at the location `C:Program FilesMicrosoftExchange ServerV15FrontEndHttpProxyowaauthOutlookEN.aspx`. This name could be a reference to HAFNIUM-related activities during post-exploitation of the Microsoft Exchange vulnerabilities7 in March 2021.
### Functionalities
For suo5 to work, an attacker-accessible web server (usually a server exposed to the internet) must run suo5 server-side code, available in .NET, Java or PHP (experimental). In our test case, the `OutlookEN.aspx` page run by the IIS component of the Exchange Server is the .NET-flavor of suo5 server-side code.
On the attacker’s side, a SOCKS5 proxy must be set up and the suo5 binary communicates with the server-side code to transmit TCP data encapsulated in the HTTP(S) communication.
“`
$ ./suo5 -t https://mail.corporation.local/owa/auth/OutlookEN.aspx [INFO] 02-27 13:28 header: User-Agent: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.1.2.3 Referer: https://mail.corporation.local/owa/auth/ [INFO] 02-27 13:28 method: POST [INFO] 02-27 13:28 connecting to target https://mail.corporation.local/owa/auth/OutlookEN.aspx [INFO] 02-27 13:28 got data offset, 0 [WARN] 02-27 13:28 the target may behind a reverse proxy, fallback to HalfDuplex mode [INFO] 02-27 13:28 starting tunnel at 127.0.0.1:1111 [Tunnel Info] Target: https://mail.corporation.local/owa/auth/OutlookEN.aspx Proxy: socks5://127.0.0.1:1111 Mode: half [INFO] 02-27 13:28 creating a test connection to the remote target [INFO] 02-27 13:28 start connection to 127.0.0.1:0 [INFO] 02-27 13:28 successfully connected to 127.0.0.1:0 [INFO] 02-27 13:28 connection closed, 127.0.0.1:0 [INFO] 02-27 13:28 congratulations! everything works fine [INFO] 02-27 13:28 start connection to 192.168.123.15:22 [INFO] 02-27 13:28 successfully connected to 192.168.123.15:22
“`
Using a tool like `proxychains`, the attacker can then communicate with any system accessible by the Exchange Server. This enables him to get a foothold inside the internal network of the victim. In our test case, using suo5 enables us to connect to a system ( `192.168.123.15`) on another subnet, which would have been otherwise inaccessible:
“`
$ proxychains ssh [email protected] [proxychains] config file found: /etc/proxychains4.conf [proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4 [proxychains] DLL init: proxychains-ng 4.16 [proxychains] Strict chain … 127.0.0.1:1111 … 192.168.123.15:22 … OK [email protected]’s password: Linux lab-victim 6.1.0-28-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.119-1 (2024-11-22) x86_64
“`
The blog post associated with the tool8 explains how suo5 achieves better performance than its competitors: it uses the `chunked` directive for the `Transfer-Encoding` HTTP/1.1 header9. This essentially means that the request’s sender can keep the connection open until it notifies the recipient that the entire message has been sent. In this mode, all encapsulated TCP packets are contained in a single HTTP connection, reducing overhead of multiple HTTP requests and responses. This is the ” **full duplex**” mode advertised in the GitHub project’s `README`:
Due to a limitation in .NET HTTP request processing10, the “full-duplex” mode cannot be used. The tool then falls back to ” **half-duplex**” mode, where only the response is sent as a continuous data stream, but requests are sent as separate HTTP requests. The goal of “half-duplex” mode is also to bypass restrictions of an Nginx reverse proxy that would stand between the suo5 client and the server-side code. By default, Nginx buffers requests11, a limitation that cannot be circumvented without modifying the reverse proxy’s configuration. However, Nginx also buffers responses by default except if the `X-Accel-Buffering: no` header field is sent as part of the response12 (which is the case for the suo5 webshell). This results in a connection still having better performance than Neo-reGeorg:
### Detection
To detect the server-side file (either on disk or loaded in memory), we want to create a YARA rule that avoids using easily changeable data like function and variable names. We want to focus on detecting functionalities of the webshell. One contextual IOC that we could use, however, is the `User-Agent` that acts as a kind of “password” so that only the client is authorized to connect to the webshell. Careless attackers might leave the default value:
“`
Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.1.2.3
“`
This is the User-Agent of a Chrome browser (version 109.1.2.3) on an LG Nexus 5 smartphone (Android 6.0 – Marshmallow).
Stealthier attackers will change the `User-Agent` checked by the server:
“`
private bool checkAuth() { string ua = Request.Headers.Get(“User-Agent”); if (ua == null || !ua.Equals(“CUSTOM_USER_AGENT”)) { return false; }
“`
They will then pass that `User-Agent` string as an argument to the suo5 client, via the `–ua` flag:
“`
$ ./suo5 –target https://mail.corporation.local/owa/auth/OutlookEN.aspx –ua “CUSTOM_USER_AGENT”
“`
Due to the nature of this string, which goal is to discriminate against other suo5 clients or unintentional connections to the webshell, there is a high chance that it will be relatively unique, leaving an interesting IOC for DFIR and SOC analysts.
The following YARA rule focuses on key characteristics of the webshell:
– Default User-Agent.
– `X-Accel-Buffering: no` response header.
– User-Agent-based authentication.
– Usage of TCP client to proxy communications.
– Binary serialization and de-serialization.
– Byte XORing and random key generation.
“`
rule SYNACKTIV_WEBSHELL_ASPX_Suo5_May25 : WEBSHELL COMMODITY FILE { meta: description = “Detects the .NET version of the suo5 webshell” author = “Synacktiv, Maxence Fossat [@cybiosity]” id = “d30a7232-f00b-45ab-9419-f43b1611445a” date = “2025-05-12” modified = “2025-05-12” reference = “https://www.synacktiv.com/en/publications/open-source-toolset-of-an-ivanti-csa-attacker” license = “DRL-1.1” […] score = 75 tags = “WEBSHELL, COMMODITY, FILE” tlp = “TLP:CLEAR” pap = “PAP:CLEAR” strings: $user_agent = “.Equals(“Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.1.2.3″)” ascii // default User-Agent $header = “Response.AddHeader(“X-Accel-Buffering”, “no”)” ascii // X-Accel-Buffering response header $xor = /= (byte)(w{1,1023}[w{1,1023}] ^ w{1,1023});/ // XOR operation // suspicious functions $s1 = “Request.Headers.Get(“User-Agent”)” ascii $s2 = “if (Request.ContentType.Equals(“application/plain”))” ascii $s3 = “Response.ContentType = “application/octet-stream”;” ascii $s4 = “= Request.BinaryRead(Request.ContentLength);” ascii $s5 = “= Response.OutputStream;” ascii $s6 = “new TcpClient()” ascii $s7 = “.BeginConnect(” ascii $s8 = “.GetStream().Write(” ascii $s9 = “new BinaryWriter(” ascii $s10 = “new BinaryReader(” ascii $s11 = “.ReadBytes(4)” ascii $s12 = “BitConverter.GetBytes((Int32)” ascii $s13 = “BitConverter.ToInt32(” ascii $s14 = “Array.Reverse(” ascii $s15 = “new Random().NextBytes(” ascii condition: filesize %s” $s3 = “Reverse socks5 server handshake ok from %s (encrypted: %v)” $s4 = “Recv exit signal from remote, exit now” $s5 = “socks consult transfer mode or parse target: %s” condition: ( uint16be( 0 ) == 0x4d5a or uint32be( 0 ) == 0x7f454c46 or uint32be( 0 ) == 0xcffaedfe or uint32be(0) == 0xcefaedfe ) and filesize .tmp`.
The script triggers the task’s execution, deletes the task, reads the content of the `.tmp` file through an SMB connection to the `ADMIN$` share and then deletes this file. This means the script only communicates with port 445 throughout its execution.
The `atexec-pro.py` script works quite differently. First of all, an alternative to RPC over SMB is offered, relying on RPC over TCP/IP36 for task manipulation. This protocol uses the RPC Endpoint Mapper, listening on port 135, to resolve the dynamic endpoint (high ports, ranging typically from 49152 to 6553537) of the `ITaskSchedulerService` interface. While it is interesting to have another option, most Windows Firewall configurations will, by default in AD domain networks, block incoming requests to dynamic ports, rendering this method of connection useless.
Once the connection is established, the tool presents itself as a shell:
“`
$ python3 atexec-pro.py -i TSCH corporation.local/[email protected] [!] This will work ONLY on Windows >= Vista Password: [*] Connecting to DCE/RPC as corporation.localAdministrator [*] Successfully bound. [+] Type help for list of commands. 🚀 ATShell ([email protected])> help Documented commands (use ‘help -v’ for verbose/’help ‘ for details): Run Command =========== cmd_exec ps_exec Post Exploitation ================= download execute_assembly upload
“`
Remote command execution works as follows:
It works similarly for .NET assembly execution. For upload and download, the file’s content is encoded and read from or placed into the task’s description.
Overall, the following functionalities are available:
– Command Prompt command execution.
– PowerShell command execution.
– File upload.
– File download.
– .NET assembly execution.
– Interaction with `ITaskSchedulerService` via RPC over SMB or RPC over TCP/IP.
Due to the way files are transferred (via the `Description` field of the task), file upload, file download and .NET assembly execution only support files up to 1 MB in size.
### Detection
What `atexec-pro.py` makes up for in functionality, it lacks in stealth. Every command launched through the Task Scheduler first goes through a PowerShell script, as defined in the task XML definition:
“`
powershell.exe -NonInteractive -enc {ps_command}
“`
where `{ps_command}` is replaced by `atexec-pro.py` with a base64-encoded PowerShell script. The default scripts provided for each command of the tool can easily be flagged as suspicious:
– Base 64 encoding and decoding.
– AES encryption and decryption.
– Interaction with the Task Scheduler service via the Task Scheduler Scripting Objects38.
As such, even on default Windows Event Log configurations where Script Block Logging is not fully enabled and only suspicious scripts are logged, Event ID 4104 events are generated in Microsoft-Windows-PowerShell\Operational for each execution of an **atexec-pro**’s command.
This results in the following Sigma rule:
“`
title: atexec-pro – Suspicious PowerShell script id: 8da0570e-adc3-4d2d-8acf-07f8cde5db3a status: experimental description: Suspicious PowerShell script contents related to execution of atexec-pro remote execution tool license: DRL-1.1 references: – https://www.synacktiv.com/en/publications/open-source-toolset-of-an-ivanti-csa-attacker author: Synacktiv, Maxence Fossat [@cybiosity] date: 2025-05-12 modified: 2025-05-12 tags: – attack.execution – attack.t1053 – tlp.clear – pap.clear logsource: product: windows category: ps_script definition: Script Block Logging must be enabled detection: selection_base: EventID: 4104 ScriptBlockText|contains|all: – ‘[System.Convert]::ToBase64String(‘ – ‘[System.Convert]::FromBase64String(‘ – ‘New-Object System.Security.Cryptography.AesManaged’ – ‘[System.Security.Cryptography.CipherMode]::CBC’ – ‘.CreateEncryptor()’ – ‘.CreateDecryptor()’ – ‘New-Object -ComObject Schedule.Service’ – ‘.GetTask(‘ – ‘.RegistrationInfo.Description’ – ‘.RegisterTaskDefinition(‘ selection_script_cmd: ScriptBlockText|contains: ‘iex’ selection_script_upload: ScriptBlockText|contains: ‘Set-Content -Path ‘ selection_script_download: ScriptBlockText|contains: ‘Get-Content -Path ‘ selection_script_net: ScriptBlockText|contains|all: – ‘[System.Reflection.Assembly]::Load(‘ – ‘New-Object System.IO.StreamWriter’ – ‘.Invoke(‘ – ‘New-Object System.IO.StreamReader(‘ condition: selection_base and 1 of selection_script* falsepositives: – Legitimate scripts using these cmdlets level: high
“`
A similar rule can be created based on command line content if process creation is logged.
As for forensic artefacts left by the execution of the original `atexec.py` script, the following article explores them (and many more remote code execution tools ;).
# Conclusion
Throughout this article, we discovered three tools actively used by threat actors to tunnel traffic to and from the internal network ( **suo5**, **iox**) and to execute code remotely ( **atexec-pro**). We analysed their core capabilities and used them to create YARA and Sigma detection rules, focusing on broad detection, harder defence evasion and low false positive rates.
**All detection rules created for this article will be maintained in the following GitHub repository.**
_If your organization needs assistance in removing doubt or responding to a security incident, please feel free to contact Synacktiv’s CSIRT._
– 1. https://forums.ivanti.com/s/article/Security-Advisory-Ivanti-Cloud-Serv…
– 2. https://forums.ivanti.com/s/article/Security-Advisory-Ivanti-CSA-4-6-Cl…
– 3. https://forums.ivanti.com/s/article/Security-Advisory-Ivanti-CSA-Cloud-…
– 4. https://www.fortinet.com/blog/threat-research/burning-zero-days-suspect…
– 5. https://www.volexity.com/blog/2024/01/10/active-exploitation-of-two-zer…
– 6. https://www.volexity.com/blog/2021/03/02/active-exploitation-of-microso…
– 7. https://www.rapid7.com/blog/post/2021/03/23/defending-against-the-zero-…
– 8. https://koalr.me/posts/suo5-a-hign-performace-http-socks/
– 9. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Enco…
– 10. https://github.com/zema1/suo5/blob/33e8bd382894ef580b4d0fe25cb6b9667d87…
– 11. http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_request_…
– 12. http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering
– 13. https://github.com/salesforce/ja3
– 14. https://github.com/FoxIO-LLC/ja4
– 15. https://pkg.go.dev/github.com/refraction-networking/utls
– 16. https://attack.mitre.org/software/S0040/
– 17. http://rootkiter.com/EarthWorm/en/index.html
– 18. https://web.archive.org/web/20031102204118/http://www.cnhonker.com/inde…
– 19. https://medium.com/@theCTIGuy/honkers-union-of-china-huc-quantity-and-q…
– 20. https://asec.ahnlab.com/en/38156/
– 21. https://www.welivesecurity.com/2022/04/27/lookback-ta410-umbrella-cyber…
– 22. https://www.secureworks.com/research/htran
– 23. https://blog.talosintelligence.com/new-zardoor-backdoor/
– 24. https://www.freebuf.com/sectool/259634.html
– 25. https://cloud.google.com/blog/topics/threat-intelligence/pst-want-shell…
– 26. https://www.cisa.gov/news-events/cybersecurity-advisories/aa23-144a
– 27. https://github.com/SEKOIA-IO/Community/blob/79d47dd0853e18e316298ecb8ae…
– 28. https://github.com/SigmaHQ/sigma/blob/d804e9cba10fa2e3bdabeca0cc330158c…
– 29. https://tip.golang.org/src/cmd/compile/abi-internal#amd64-architecture
– 30. https://github.com/fortra/impacket/blob/ae0ec300f8a43c8554fa99a6566815c…
– 31. https://github.com/fortra/impacket
– 32. https://github.com/Ridter/atexec-pro
– 33. https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/7…
– 34. https://github.com/fortra/impacket/blob/ae0ec300f8a43c8554fa99a6566815c…
– 35. https://github.com/fortra/impacket/blob/ae0ec300f8a43c8554fa99a6566815c…
– 36. https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/9…
– 37. https://learn.microsoft.com/en-us/troubleshoot/windows-server/networkin…
– 38. https://learn.microsoft.com/en-us/windows/win32/taskschd/task-scheduler…