• Stars
    star
    665
  • Rank 67,810 (Top 2 %)
  • Language
    C++
  • License
    BSD 3-Clause "New...
  • Created almost 2 years ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

PoC Implementation of a fully dynamic call stack spoofer

SilentMoonwalk

PoC Implementation of a fully dynamic call stack spoofer

TL;DR

SilentMoonwalk is a PoC implementation of a fully dynamic call stack spoofer, implementing a technique to remove the original caller from the call stack, using ROP to desynchronize unwinding from control flow.

Authors

This PoC is the result of a joint research done on the topic of stack spoofing. The authors of the research are:

I want to stress that this work would have been impossible without the work of Waldo-IRC and Trickster0, which both contributed to the early stages of the PoC, and to the research behind the PoC.

Overview

This repository demonstrates a PoC implementation to spoof the call stack when calling arbitrary Windows APIs.

This attempt was inspired by this Twitter thread, and this Twitter thread, where sensei namazso showed and suggested to extend the stack unwinding approach with a ROP chain to both desynchronize the unwinding from real control flow and restore the original stack afterwards.

This PoC attempts to do something similar to the above, and uses a desync stack to completely hide the original call stack, also removing the EXE image base from it. Upon return, a ROP gadget is invoked to restore the original stack. In the code, this process is repeated 10 times in a loop, using different frames at each iteration, to prove stability.

Supported Modes

The tool currently supports 2 modes, where one is actually a wrong patch to a non-working pop RBP frame identified, which operates by shifting the current RSP and adding two fake frames to the call stack. As it operates using synthetic frames, I refer to this mode as "SYNTHETIC".

When selecting the frame that unwinds by popping the RBP register from the stack, the tool might select an unsuitable frame, ending up in an abruptly cut call stack, as observable below.

Windows 10 Call Stack - Cut

Synthetic Call Stack Mode

A silly solution to the problem would be to create two fake frames and link them back to the cut call stack. This would create a sort of apparently legit call stack, even without a suitable frame which unwinds calling POP RBP, but:

  • You would lose the advantage of the desync technique
  • The stack would be still unwindable
  • The resulting call stack could seem legit just on the first glance, but it would probably not pass a strict check

The result of the _synthetic spoof can be observed in the image below:

Windows 10 Call Stack - Apparently Legit, non unwoundable - getchar

Figure 1: Windows 10 - Apparently Legit, non unwoundable call stack whereby the EXE module was completely removed (calling no parameters function getchar)

Note: This operation mode is disabled by default. To enable this mode, change the CALLSTACK_TYPE to 1

Desync Stack Mode

This mode is the right solution to the above problem, whereby the non-suitable frame is simply replaced by another, suitable one.

Windows 10 Call Stack - Legit, unwoundable - MessageBoxExA

Figure 2: Windows 10 - Legit, unwoundable call stack whereby the EXE module was completely removed (calling 4 parameters function MessageBoxA)

Utility

In the repository, you can find also a little util to inspect runtime functions, which might be useful to analyse runtime function entries.

UnwindInspector.exe -h

 Unwind Inspector v0.100000

 Mandatory args:
   -m <module>: Target DLL
   -f <function>: Target Function
   -a <function-address>: Target Function Address

Sample Output:

UnwindInspector.exe -m kernelbase -a 0x7FFAAE12182C
[*] Using function address 0x7ffaae12182c

  Runtime Function (0x000000000000182C, 0x00000000000019ED)
  Unwind Info Address: 0x000000000026AA88
    Version: 0
    Ver + Flags: 00000000
    SizeOfProlog: 0x1f
    CountOfCodes: 0xc
    FrameRegister: 0x0
    FrameOffset: 0x0
    UnwindCodes:
    [00h] Frame: 0x741f - 0x04  - UWOP_SAVE_NONVOL     (RDI, 0x001f)
    [01h] Frame: 0x0015 - 0x00  - UWOP_PUSH_NONVOL     (RAX, 0x0015)
    [02h] Frame: 0x641f - 0x04  - UWOP_SAVE_NONVOL     (RSI, 0x001f)
    [03h] Frame: 0x0014 - 0x00  - UWOP_PUSH_NONVOL     (RAX, 0x0014)
    [04h] Frame: 0x341f - 0x04  - UWOP_SAVE_NONVOL     (RBX, 0x001f)
    [05h] Frame: 0x0012 - 0x00  - UWOP_PUSH_NONVOL     (RAX, 0x0012)
    [06h] Frame: 0xb21f - 0x02  - UWOP_ALLOC_SMALL     (R11, 0x001f)
    [07h] Frame: 0xf018 - 0x00  - UWOP_PUSH_NONVOL     (R15, 0x0018)
    [08h] Frame: 0xe016 - 0x00  - UWOP_PUSH_NONVOL     (R14, 0x0016)
    [09h] Frame: 0xd014 - 0x00  - UWOP_PUSH_NONVOL     (R13, 0x0014)
    [0ah] Frame: 0xc012 - 0x00  - UWOP_PUSH_NONVOL     (R12, 0x0012)
    [0bh] Frame: 0x5010 - 0x00  - UWOP_PUSH_NONVOL     (RBP, 0x0010)

Build

In order to build the POC and observe a similar behaviour to the one in the picture, ensure to:

  • Disable GS (/GS-)
  • Disable Code Optimisation (/Od)
  • Disable Whole Program Optimisation (Remove /GL)
  • Disable size and speed preference (Remove /Os, /Ot)
  • Enable intrinsic if not enabled (/Oi)

Previous Work

It's worth mentioning previous work done on this topic, which built the foundation of this work.

  • Return Address Spoofing: Original technique and idea, by Namaszo. Every other PoC I'm aware of was built on top of that.
  • YouMayPasser: This amazing work by Arash is the first properly done extension of the Return Address Spoofing PoC by Namaszo.
  • VulcanRaven: A call stack spoofer that operates the spoofing by synthetically creating a Thread Stack mirroring another real call stack.
  • Unwinder: A very nice Rust PoC implementation of a call stack spoofer which operates by parsing unwind code information to replace frames in the call stack.

Credits

  • Huge shoutout to waldo-irc and trickster0, which collaborated with me on this research. I owe everything to them.
  • All the credit for the idea behind this goes to namaszo, which I personally consider a genius. He also cross checked this PoC before release, so huge thanks to him.

Notes

  • [SYNTHETIC STACK ONLY]: For a limitation in the way I'm locating the gadgets, the maximum number of arguments is 8 for now (it is TRIVIAL to modify and add more params, but I couldn't bother).
  • [DSESYNC STACK ONLY]: For a limitation in how I'm setting up the spoofer, the maximum number of supported arguments is 4 for now.
  • Testing on this one was pretty limited. There might be exceptions I'm not aware of at the moment.
  • Unwinding involving 128-bit registers was no tested.
  • Calling functions that use 128-bit registers is not officially supported.

More Repositories

1

inceptor

Template-Driven AV/EDR Evasion Framework
Assembly
1,561
star
2

SysWhispers3

SysWhispers on Steroids - AV/EDR evasion via direct system calls.
Python
1,256
star
3

CVE-2021-40444

CVE-2021-40444 - Fully Weaponized Microsoft Office Word RCE Exploit
HTML
795
star
4

CheeseTools

Self-developed tools for Lateral Movement/Code Execution
C#
683
star
5

chameleon

PowerShell Script Obfuscator
Python
485
star
6

vortex

VPN Overall Reconnaissance, Testing, Enumeration and eXploitation Toolkit
Python
419
star
7

CandyPotato

Pure C++, weaponized, fully automated implementation of RottenPotatoNG
C++
298
star
8

DriverJack

Hijacking valid driver services to load arbitrary (signed) drivers abusing native symbolic links and NT paths
C++
246
star
9

SharpSelfDelete

C# implementation of the research by @jonaslyk and the drafted PoC from @LloydLabs
C#
147
star
10

NimlineWhispers3

A tool for converting SysWhispers3 syscalls for use with Nim projects
Nim
137
star
11

RpcProxyInvoke

Simple POC library to execute arbitrary calls proxying them via NdrServerCall2 or similar
C++
100
star
12

klezVirus.github.io

CyberSec Blog
JavaScript
96
star
13

SharpLdapRelayScan

C# Port of LdapRelayScan
C#
77
star
14

koppeling-p

Adaptive DLL hijacking / dynamic export forwarding - EAT preserve
Python
66
star
15

DCKFinder

Dangling COM Keys Finder
C++
14
star
16

deser-node

NodeJS Deserialization Payload Generator
JavaScript
9
star
17

codegrepper

Pure python, self-contained, silly implementation of a SAST tool
Python
8
star
18

mapt-run

Simple script to setup a local hosted network for Mobile Application Penetration Testing
Shell
8
star
19

faceless

Faceless - Simple Tool for Text-File Anonymization
Python
7
star
20

msf-revhttp-gen

Little utility to facilitate Metasploit Reverse HTTP Payloads
Shell
7
star
21

nmap-report

A simple tool that can be use to extract usful information from a nmap scan
Shell
7
star
22

CryptoCheck

NIST-CAVS Extended - Encryption Auto Testing Toolkit
Python
4
star
23

deser-py

Python Deserialization Payload Generator
Python
4
star
24

deser-ruby

Ruby Deserialization Payload Generator
Ruby
4
star
25

nx_reporter

Rapid7 Nexpose template-based report generator
Python
4
star
26

muts-opt-encoder

Independent implementation of the optimized SUB-Encoder
Python
4
star
27

klezVirus

Temporary unavailable...
3
star
28

php-ipfinder

A simple tool to enumerate various info on a set of IP addresses
PHP
2
star
29

cves

Public Advisories Redirector
1
star
30

cors-security-remove

JavaScript
1
star
31

Posts

Offensive Security Certifications Reviews
1
star
32

oldrivrs

some old drivers and misc crap from a while ago
C
1
star