Using fibers to run in-memory code in a different and stealthy way.

Overview

Description

A fiber is a unit of execution that must be manually scheduled by the application rather than rely on the priority-based scheduling mechanism built into Windows. Fibers are often called lightweight threads. For more detailed information about what are and how fibers work consult the official documentation. Fibers allow to have multiple execution flows in a single thread, each one with its own registers' state and stack. On the other hand, fibers are invisible to the kernel, which makes them a stealthier (and cheaper) method to execute in-memory code than spawning new threads.

One thread can create multiple fibers, and switch between them at desire by calling the SwitchToFiber function. Before that, the current thread itself must have become a fiber by calling ConvertThreadToFiber since only a fiber can create other fibers. Finally, in order to create a fiber that, when scheduled, executes an in-memory code (for example, after reflectively loaded a PE or some shellcode) it is just needed to make a call to CreateFiber.

The SwitchToFiber function is the most important part of this process and where all the magic occurs. This function allows to schedule one fiber or another, all happening on user space. According to the official documentation, "the SwitchToFiber function saves the state information of the current fiber and restores the state of the specified fiber". This mean that when this function is called, the registers' values and the stack are switched from the current fiber state to the target fiber state, allowing to "hide" the stack of the current fiber once the process is completed. This also allows to continue the execution of the target fiber from the same point where the execution was stopped (the same way that it happens when the scheduler switches between threads according to its own priority logic).

And this is exactly what this simple PoC does:

  • First, we have a loader, which will use DInvoke to manually map the dll that contains our payload.
  • After that, the loader will turn the current thread into a fiber (known from now on as the control fiber). The control fiber will enjoy of a "normal" stack since the loader is being run from a PE on disk.
  • The loader will then create a new fiber to run the run() function exported by the manually mapped dll. This fiber will be known as the payload fiber from now on.
  • The control fiber will switch to the payload fiber, which will execute whatever code the payload contains. Once the payload needs to enter on an alertable state (for example, when a call to Sleep is required), the payload fiber switches back to the control fiber, hiding its stack (which may contain several IOC os malicious activity).
  • The control fiber performs the call to Sleep. When the call returns, it will switch again to the payload fiber so it can continue its execution.

This process repeats indefinitely.

Advantages

The use of fibers may be advantageous for some types of payloads (like a C2 beacon) for some of these reasons:

  • Fibers allow to run in-memory code without the need of using the instructions JMP or CALL from the loader pointing to unbacked memory regions.
  • This execution is performed without the creation of new threads, preventing the generation of callbacks from the kernel that can be collected by an EDR.
  • The payload fiber's stack can be hidden when the payload enters on an alertable state or when it needs to wait for a pending I/O operation. This is done using a control fiber with a normal stack that runs code from disk. This "hiding" is cheaper and easier to implement that the regular thread stack spoofing process.
  • The fibers are invisible to the kernel and all the switching procedure happens on user space, which makes it easier to hide from an EDR.

Cons

  • Only one fiber can be scheduled at a time on a thread, which means that in order to get real concurrency using fibers you need to spawn more threads.
  • Although the payload fiber's stack is hidden when the control fiber is switched back, it remains in the process memory and it could be spotted by a memory inspection.
  • Obfuscation is still needed in order to hide the in-memory implant, this is just about hiding the stack and the execution method.

Compilation

Since we are using LITCRYPT plugin to obfuscate string literals, it is required to set up the environment variable LITCRYPT_ENCRYPT_KEY before compiling the code:

C:\Users\User\Desktop\Fiber> set LITCRYPT_ENCRYPT_KEY="yoursupersecretkey"

After that, simply compile both the payload and the loader and run the last one:

C:\Users\User\Desktop\Fiber\payload> cargo build --release
C:\Users\User\Desktop\Fiber\loader> cargo build --release
C:\Users\User\Desktop\Fiber\loader\target\release> loader.exe

Usage

There is not much mistery on this PoC execution. All it has to be done is to run the loader and use any tool like ProcessHacker to inspect the thread stack. Since the payload switches back to the control fiber before sleeping, the payload fiber's stack remains hidden most of the time. You will see in the output how the two fibers are consecutively scheduled following the already commented logic.

The code is commented to show how to use, create and schedule fibers. You will notice that both the loader and the payload offered as example are "stuck" on an infinite loop, which allows to indefinitely switch between fibers and continue the execution.

If a different payload wants to be tested, just modify the path located on line 32 of the file src::main.rs of the loader. In that case, the new dll has to export a run(PVOID) function that will receive as input parameter the address of the control fiber. This function has to switch back to the control fiber in order to call the Sleep function, although you can modify this behavior at will to fit your requirements.

Another way to test this tool with a random payload is to perform IAT hooking to redirect any call to the Sleep function (or any other imported function) made by the payload to a function located on the loader, allowing to switch back to the control fiber when this call occurs. Up to you.

In the following screenshots we can see how the stack of the current threat moves from one private memory region to another as we switch fibers:

Stack in Process Hacker Stack in Process Hacker

You might also like...
An attempt to rewrite lite-client for TON Blockchain in Rust using ton-labs-adnl library.

An attempt to rewrite lite-client for TON Blockchain in Rust using ton-labs-adnl library.

Cyg will help you to secure files in your repository directly using PGP encryption

cyg: Secure files in your repository Cyg will help you to secure files in your repository directly using PGP encryption. The name "cyg" was inspired b

Kepler is a vulnerability database and lookup store and API currently utilising National Vulnerability Database and NPM Advisories as data sources
Kepler is a vulnerability database and lookup store and API currently utilising National Vulnerability Database and NPM Advisories as data sources

Kepler — Kepler is a vulnerability database and lookup store and API currently utilising National Vulnerability Database and NPM Advisories as data so

Steals browser passwords and cookies and sends to webhook.
Steals browser passwords and cookies and sends to webhook.

Browser-Stealer Steals browser passwords and cookies and sends to webhook. Donating Educational Purposes Only This code is made so you can learn from

Xori is an automation-ready disassembly and static analysis library for PE32, 32+ and shellcode
Xori is an automation-ready disassembly and static analysis library for PE32, 32+ and shellcode

Xori - Custom disassembly framework Xori is an automation-ready disassembly and static analysis library that consumes shellcode or PE binaries and pro

🕵️‍♀️ Find, locate, and query files for ops and security experts ⚡️⚡️⚡️
🕵️‍♀️ Find, locate, and query files for ops and security experts ⚡️⚡️⚡️

Recon Find, locate, and query files for ops and security experts Key Features • How To Use • Download • Contributing • License Key Features Query with

Semi-automatic OSINT framework and package manager

sn0int sn0int (pronounced /snoɪnt/) is a semi-automatic OSINT framework and package manager. It was built for IT security professionals and bug hunter

A Comprehensive Web Fuzzer and Content Discovery Tool

rustbuster A Comprehensive Web Fuzzer and Content Discovery Tool Introduction Check the blog post: Introducing Rustbuster — A Comprehensive Web Fuzzer

A simple menu to keep all your most used one-liners and scripts in one place
A simple menu to keep all your most used one-liners and scripts in one place

Dama Desktop Agnostic Menu Aggregate This program aims to be a hackable, easy to use menu that can be paired to lightweight window managers in order t

Owner
Kurosh Dabbagh Escalante
nt authority\kurosh
Kurosh Dabbagh Escalante
Memory hacking library for windows.

Memory hacking library for windows.

sy1ntexx 40 Jan 3, 2023
A simple allocator written in Rust that manages memory in fixed-size chunks.

Simple Chunk Allocator A simple no_std allocator written in Rust that manages memory in fixed-size chunks/blocks. Useful for basic no_std binaries whe

Philipp Schuster 7 Aug 8, 2022
Breaking your Rust code for fun and profit

Breaking your Rust code for fun & profit this is an architecture-preview, not all components are there This is a mutation testing framework for Rust c

null 542 Jan 4, 2023
Attempts to suspend all known AV/EDRs processes on Windows using syscalls and the undocumented NtSuspendProcess API. Made with <3 for pentesters. Written in Rust.

Ronflex Attempts to suspend all known AV/EDRs processes on Windows using syscalls and the undocumented NtSuspendProcess API. Made with <3 for penteste

null 5 Apr 17, 2023
Secure sandboxing system for untrusted code execution

Godbox Secure sandboxing system for untrusted code execution. It uses isolate which uses specific functionnalities of the Linux kernel, thus godbox no

Nathanael Demacon 19 Dec 14, 2022
A cryptographically verifiable code review system for the cargo (Rust) package manager.

image credit cargo-crev A cryptographically verifiable code review system for the cargo (Rust) package manager. Introduction Crev is a language and ec

crev - Code REView system 1.8k Jan 5, 2023
How-to: Sanitize your Rust code!

rust-san How-to: Sanitize your Rust code! Intro How to use the sanitizers? Examples AddressSanitizer Out of bounds access Use after free LeakSanitizer

Jorge Aparicio 359 Dec 22, 2022
A library for building tools to determine if vulnerabilities are reachable in a code base.

Overview Vuln Reach is a library for developing tools that determine if a given vulnerability is reachable. Provided to the open source community by P

Phylum 3 May 5, 2023
A simple port scanner built using rust-lang

A simple port scanner built using rust-lang

Krisna Pranav 1 Nov 6, 2021
Linux LPE using polkit-1 written in Rust.

CVE-2021-4024-Rust Linux LPE using polkit-1 written in Rust. Build instructions Install rust if you haven't already git clone https://github.com/deoxy

Kevin Pham 1 Feb 3, 2022