- Hello and welcome to Offensive Golang Bonanza.
I'm Ben, hi, Defcon 29.
We're gonna talk about Golang malware.
Little a bit about myself,
my first Defcon talk was at Defcon 13.
I'm the host of a hacker-themed podcast
where we interview a lot of people around this community.
Very in-depth, very technical.
Please check that out and I have
a bunch of random projects on GitHub.
So what this talk is gonna be,
there's two ways to consume it.
One, you can just listen to me describe
a whole bunch of Golang malware components
and you'll get a sense of what's out there,
what's available, what's possible.
And if you wanna go in-depth, there are links
on all of the slides to the actual code repos themself,
code samples, interviews, news articles, all kinds of stuff.
So to start with, I'm gonna do a little bit of back story
on my hacker crew and a little bit on Golang
and why it's so interesting to malware developers.
And then we'll start going through
various components and tools.
So in the beginning, I was interested in
anti-censorship surrounding a particular Iranian election.
I was taking a look at the Tor's obfuscation proxy,
obfsproxy2 at the time, and I thought I could do better.
And so I started the Ratnet project
which is a pretty cool NIDS evasion thing
we're gonna talk about later
and I was using that project as an excuse to learn Golang.
And what I learned is that Golang is magic.
Unlike any programming language I've used before,
just anything you need, anything you would normally
have to install as a separate library or utility,
it's just there for you.
Everything from crypto, networking libraries,
virtual file systems are supported natively
which is totally unique.
The compiler cross-compiles easily to every other
architecture and operating system.
There's built-in test frameworks, vendored in frameworks,
it's garbage collected, it has a very efficient
thread implementation and it has its own assembler.
And the third party library support is totally unparalleled,
so Rust is years away just to answer the question
of why don't I rewrite everything in Rust?
But the main reason that I love Go
is that it is the fastest way to be done
and my goal is not to reinvent every wheel.
My goal is when I start a project
is to be done with the project and use the project.
And the fastest way to learn Go, the way I learned,
is a document called Effective Go on the Golang website
which assumes that you already know how to program
and just tells you what's different about Go.
I highly recommend that to anyone who wants to learn Go
especially if you already know how to program.
So a few relevant facts about Go.
It is not interpreted.
I'm not sure why people seem to get that misconception.
It is statically compiled.
However, it also, every Go binary includes
a kind of monolithic runtime
which is like 800K on most operating systems.
So it's a bit of overhead per binary.
And then all of your code is statically compiled
on top of that, all of the dependencies and everything
that aren't already in the runtime.
The embedded assembly language
is based on Plan9's assembly language,
so it's a little bit crazy.
We don't have time to go into it,
but I did a write-up that will kind of help you cope.
It's linked on this slide.
I recommend checking that out.
So to get into the story, so Stuxnet happened,
and everyone got very hot on environmental keying.
I environmentally keyed payloads.
Josh Pitts made a tool in Golang
to do environmentally keyed payloads called Ebowla.
They got very popular with the red teamers at the time.
And so all of the EDRs and AV companies
wanted to write sigs for Ebowla,
but they had never seen a Golang hacker tool before.
And so they all ended up writing signatures
for the Golang runtime
which is included in every Golang process.
So what happened next is that all of the AV utilities
triggered on every Go binary including the installer,
but it also included the very prevalent orchestration tools,
Docker and Terraform.
And so as a result, they all had to
pull those sigs very quickly,
because people need their Terraform.
And this is a pattern that malware developers look for.
We call the jar2exe pattern
where basically if you have anything
that makes a native binary for you,
but it has one legitimate user
that means the AV companies need to whitelist it
and they have trouble creating sigs for like Java
inside a jar2exe binary.
They have trouble creating sigs for Python
inside a py2exe binary if those are whitelisted.
And similarly, they have trouble creating sigs
for Go code which is statically compiled
past the Go runtime.
So realizing that and also
I had this sweet exfiltration library
I had been working on called Ratnet,
I started talking to other security people
that were interested in Go
and we got together, shared ideas,
things escalated very quickly,
and we, you know, this has happened in the past with Python.
Now it's happening with Go.
And we made a bit of a community, probably the best
example of this is there's a particular Slack server
where #golang, the Slack channel,
has like literally, it's like
the best place on the Internet.
It has like all the people working in Golang malware
basically hang out there.
They share ideas, they're really nice to each other.
There's no kind of like political
or weird other Internet nonsense.
It's just people helping each other with projects,
suggesting project ideas, and it's just amazing.
So we're gonna talk about tools from a lot of people
in this chatroom.
I boldfaced the ones that are specifically mentioned
in this deck, but everybody in there,
just thank you, it's been totally critical for my sanity
especially over the last year.
And I especially wanna thank the community organizer,
jeffmcjunkin for keeping most of the crazy out.
So just a quick word about offense and defense,
all of these tools are open source.
We post the code, we hope that
the people who work on operating system and defenses
and defensive tools will study these
and learn how they can improve
some of the problems especially the bypass tools
exploit have been around for 10, 20,
and in some cases 30 years.
So having, it's not 0-day, it's just like,
things have been broken for a long time.
You can't just bury your hand in the sand.
So we're trying to make things better
by helping people understand how things actually work.
And on that note, I'm gonna talk briefly about
what tools exist for reversing Go binaries.
There aren't a lot that are useful.
Even now, the most useful one is probably
the Go Reversing Toolkit.
They have a tool called Redress
which is fairly successful at extracting metadata
from stripped Go binaries including dependencies
and compiler versions.
And then there's a few IDA scripts and blog posts
linked on this slide which give you some clues as to
how to go about reversing a Go binary,
but it's still pretty primitive.
And I think a lot of the trouble is that
the static compilation aspect,
if you ever try to open up an embedded C program
that's statically compiled in IDA,
you end up having to sort of manually work out
what a lot of the functions do.
There are kind of flare signatures,
but I haven't seen that for Golang yet.
So some of the core components
for the rest of the tools we're gonna talk about.
The first one, the one that gets used by almost everything
is our fork of Go standard debug library.
So Go comes with a library called debug.
It parses all binary formats PE, for Windows Elf, Linux,
and Mach-O for OSX.
We forked that, fixed a bunch of bugs,
and added support for editing the file,
changing things by their fields,
and then writing the file back out once you've changed it.
So we turned it into an
arbitrary binary modification framework
and we also made it parse files
that are already loaded into memory.
And also you can write them back out to memory,
but you need a tool we're gonna talk about later.
But this is especially cool,
because you can parse your own process
which lets you do a lot of neat malware tricks,
as we'll see, and you can also inject shellcode into
a file on disk which is also pretty handy.
So the parser entry points for PE, Elf, and Mach-O
are always either new file or new file from memory.
The generator entry points are always called bytes
in case you're looking at the code.
Also some of the stuff we added,
we added base relocations and relocations.
We added imported address table fix-ups,
the ability to add sections,
the ability to hook entry points,
and the ability to access and add signatures
which comes up in a lot of the malware tools we're using,
but this might be useful for other things as well.
Another core component is cppgo.
We got this from Loren Segal.
We just forked and added support for
the Apple M1 for ARM 64.
Basically this is a way from Go to make native calls
into any other library using any ABI,
any calling convention.
So it comes with standard call, cdecl, and thiscall.
And so this is absolutely critical
for a lot of malware functionality from Go.
I highly recommend you check it out.
It's a great example of Go assembler.
Moving on to the exploitation tools category.
Our first exploitation tool is called binjection
and this uses the Binject debug binary modification platform
and adds a layer on top of it
which implements a variety of different algorithms
for inserting shellcode into a binary,
predominately hooking the entry point,
but it wouldn't necessarily have to be.
So there's a command line utility.
You can also use it as a library.
And so it's very extensible
and we've implemented a variety of algorithms
including for PE, the one we use the most often these days
is just adding a new section.
You hook the entry point to point to the new section.
At the end of the new section,
you have it point back to the original entry point.
So basically file starts, runs your shellcode
in the new section, jumps back to the original entry point.
Modern PEs don't have a lot of code cave space anymore.
I guess there have been compiler improvements,
so this is the most successful method for PE we found.
For ELF, we have a variety of different methods.
We're probably gonna add more.
We have Silvio Cesare's original padding infection method
which we updated a little bit, so it supports
position independent executables, and we also,
sblip from the channel also implemented a
completely new injection method based on PT_NOTE
which is in there and we also have
ctors or constructor hooking for shared libraries.
So not only can you hook an executable,
you can also inject shellcode into a shared library
and have that run when the library loads.
For Mach-O, we're predominately hooking the entry point
and using the one giant code cave
which is in all Mach-O binaries
before that first load segment.
I'm not sure why that is always the case,
but there's always one giant code cave
you can fit a bunch of shellcode in, I don't know.
Just a quick example of what the code looks like.
This is the whole Silvio method from binjection.
There are no, there's no weird offsets, there's no hex math.
You can just read it and it's referring to the actual fields
in the file format and that's coming from binjectdebug.
And this is the right layer of abstraction
that you wanna code injection algorithms in
and that's kind of the whole point,
so it's easy to understand the algorithm.
Just by reading the code, it's easy to add new algorithms.
Now what kind of kicked off the binjectdebug
and binjection project was the desire to make
the old tool from Josh Pitts's backdoorfactory work again.
So backdoorfactory stopped working
and we were like, "Hey, let's just
rewrite this whole thing in Go."
We broke it into modules and we ended up
with binjectdebug binjection.
And finally, we needed to
close the loop with backdoorfactory.
So backdoorfactory is the thing, man in the middle,
someone's who's trying to download a binary,
it injects shellcode into the binary automatically.
It was beautiful, red teamers loved it,
got to use it all the time, and then it stopped working,
and we were all very sad.
Backdoorfactory originally worked with a tool called
Ettercap which is terrible and old.
I mean it worked at the time, but it was into curses,
and there's a better Go rewrite called bettercap
which adds support for more man in the middle methods.
And so we decided to use bettercap for the rewrite.
And then we already had binjection.
So basically, bettercap has a scripting language
called caplet scripts and they already had
implemented a script for bettercap called
download-autopwn which intercepts web downloads
and replaces them with a malicious payload.
So it doesn't inject it into a file,
it just replaces it entirely, but we just started from that.
And then in the caplet language only,
it exposes read file and write file commands.
It's the only way you can interact with anything
outside of JavaScript.
And so, we figure we'll just make a named pipe server
and use read file and write file to pass
the file being man in the middled out to binjection,
inject your shellcode, and then use a read file
to read it back in through another pipe,
back into the caplet, and return it to the user.
So that looks like this.
So you can use bettercap to man in the middle
someone's download using ARP spoofing, DNS poisoning,
DHCPv6 or anything else bettercap supports.
Their download request comes to you,
you go out to the server
they were originally trying to access,
and download the file they were trying to get.
And then you pass that file through the new pipe server,
the new backdoorfactory to binjection
where shellcode gets injected into the executables.
And then the whole thing gets repackaged
and passed back to the user and they think it was the file
they were trying to download.
Open it, run it, run your shellcode.
That's the general idea.
So our implementation of backdoorfactory lives in Binject.
Basically what it does, it starts up this pipe server,
it spits out the caplet and bettercap config files
that you need and it tells you exactly
what bettercap command to run which is just mainly
'cause I kept forgetting how to use bettercap.
You may need to customize that caplet file
in the bettercap config.
You'll have to customize the caplet
if you want to support different user agents.
If you only wanna trigger on certain user agents,
you can do that by regular expression
or if you only wanna trigger on certain file extensions,
you can also edit that in the caplet.
Also by default, it will do ARP spoofing
that might be too loud.
If you wanna do DNS poisoning,
you'll have to edit the default bettercap config
that comes out of there.
So some features that we added,
we added support for unpacking archives.
So it'll actually, if someone's trying to download a TGZ
or a ZIP file, it will unzip that on the fly,
inject all of the binaries inside it,
then re-zip it and pass it back to the user.
We're also working on adding support
for re-signing the binary with a stolen or purchased key
and we'll work on that in a sec.
And we also ported this to Wifi Pineapple,
because back in the day, running backdoorfactory
on a malicious access point was super fun
and Golang supports easy cross-compilation to MIPS32.
So there are links to the bettercap
and backdoorfactory packages we made on this slide.
So quick demo.
So on the right, we're downloading a file wget
and unzipping it, running it, and it says
I'm a simple program, blah, blah, blah.
Now in the upper left, we're starting the pipe server
which opens up some named pipes to binjection
and it gave us, generated some bettercap configs,
gives us the command to run bettercap in another window.
We run bettercap and it starts the ARP spoof
and intercepting files using our caplet.
So we go and download the same file
we just downloaded again.
You can see the size's a little bit different.
Unzip that, run the binary inside,
and you can see it printed test
in addition to the original output.
That is a shellcode we made
that we use as a test shellcode which prints test,
so that's proof that our shellcode has been injected
and also the original program still ran.
So that's the new backdoorfactory.
So because the files are being passed in by a pipe,
we actually don't, we lose the extension of the file
on the way in.
We don't get that through the pipe,
so we're actually using MIME.
So we're using a Go library to determine the MIME type
and then we have the switch statement
based on the MIME type on what injection to do
like that's how we figure out what file it is.
So if you wanna extend it, you can just extend it
by MIME type which is actually pretty awesome.
There's different MIME types for like jars than zips
which is pretty cool, 'cause some programs will tell you
they're the same format.
And the main call to binjection looks like this
inside backdoorfactory, it's injective binary.
It does a quick check of the magic number
to see if it's a Mach-O, ELF, or PE.
And then it calls, it pulls the appropriate shellcode
and then calls Binject near the bottom there
to inject the appropriate shellcode into the binary.
So signing from Golang is also very well-supported.
The two main libraries I'd recommend that you check out,
one is called Limelighter which,
it does authenticode signing of EXEs and DLLs.
You can either use a real cert or it'll make one up for you
which is also kind of handy for EDR evasion.
Another one that's a little bit heavier,
but signs everything is Relic and Relic
not only does the authenticode signing stuff,
it also supports like CentOS RPMs, Debian DEB files,
Java JAR files, Silverlight XAP files which is pretty handy
if you can still find some Silverlight.
PowerScript, Android APKs, and Mach-Os, and DMGs for Macs.
So there's a lot of possibilities for extending
backdoorfactory to new and interesting file formats.
So moving onto a different exploitation tool.
From C-Sto, we have goWMIExec
which actually brings the ability to just do remote WMI,
Windows Management Interface calls to Go
which lets you just run random shell commands
on some target Windows machine out in space.
There's also another library
that gives you full SMB support, go-smb2.
And so if you put those two together,
you can replicate in packets smbexec functionality,
so you can upload a file with go-smb to a target
and then you can execute it with goWMIExec.
So you can put this in your implant
and have it like auto-spread,
or you can use it as an initial inject
assuming you have creds for a Windows box.
And so in code, it's kind of just as easy as this.
I couldn't fit all of the file upload stuff in there,
but you can see the WMI call.
Basically, you just, you pass a username, password,
or you can use a hash if you have it,
'cause C-Sto is magic and like the domain
and the client name and stuff,
you can either randomize those or they're optional.
So it's pretty easy to use.
And for a full example of smbexec in Go
including the file upload stuff,
check out the source code bundle on the Defcon media server
for my Defcon 29 Workshop: Writing Golang Malware
and there's a lot more detail in the workshop slides.
So some other exploitation tools,
don't have time to go into,
but gophish is a very popular phishing toolkit.
Gobuster is good for brute-forcing sub-domains.
There's a little DNS server you can use for XXEs.
It's also good for DNS blackholing
which is good for Android reversing.
And there's also modlishka which is a phishing reverse proxy
which has some novel 2FA bypass stuff in it.
So those are all Go repos you should check out
or use as a reference.
Moving onto EDR and NIDS evasion tools.
The most important one is garble.
This is the state of the art Golang obfuscator.
It does not do control obfuscation unfortunately,
but hopefully that's coming.
But it will strip out almost all Go metadata
and with the optional dash literals command,
it will replace string literals with lambdas
which is very important for avoiding sigs.
And gobfuscate was a bit broken.
It was slow, it didn't work with Go modules,
it had trouble with dependencies.
Garble fixes all of that, it's actually remarkably fast,
it's incredibly easy to use,
and I haven't seen it choke on anything at all yet
which is amazing, so there's really no reason
not to use garble on everything as far as I know.
And definitely try that Redress tool.
Try Redress on something before you garble it
and then try it after you garble it and see what happens.
That's probably a good time.
So in terms of NIDS evasion,
there's a lot of kind of network code out there.
My own project is Ratnet.
It works, it has a couple of unique features.
It works on store and forward,
so it actually is not stream-based.
It bundles messages up into batches
and each message is individually and end-encrypted,
but the batches are also encrypted separately for every hop.
It works on mesh routing,
so every Ratnet node acts as a router.
And it also supports pluggable transports.
You can have different transports between hops.
You can also support multiple transports at once
and you can dynamically change between transports.
So the transports that we ship with,
we have UDP, TLS, HTTPS which is like cloud-fronting,
and we also have DNS, and AWS S3 as a transport
which is pretty neat.
And this also works without the Internet
as just a mesh routing middleware
and I'm working on a handheld Ratnet-based hardware device
which will come out as a crowd supply next year,
so watch this space for that.
So a couple of use cases that we support with Ratnet.
One is, say you've hit a bunch of machines with an implant
and you, not all of them have direct Internet access
and you want pivot, you want to be able to talk
to all of the implants from your C2.
So what you can do is you can make an implant
where the implants find each other using mDNS or multicast.
And if they can't get to the Internet directly,
they will just automatically route all of their messages out
through one of their peers.
And if any one of those peers can find their way
out to the Internet to the C2, you can actually,
it'll just automatically make a network
and you can talk to all of the implants,
because the implants in the middle
will automatically act as a router,
'cause that's how Ratnet works.
So there's actually a demo of this working
also in the workshop source code.
The other use case that we wanna support is
if you drop an implant into an egress proxy data center.
So if all web traffic or like almost all traffic is blocked
out to the open Internet from where you are,
you can still usually get out with DNS,
because the local DNS server will hopefully pass
look-ups out through recursion.
So that's why the, that's what the DNS transport is for.
You also might find yourself in a situation
where lots of things are blocked,
but some things are whitelisted,
and in those situations, typically AWS is whitelisted,
because almost everything is using AWS
at least a little bit.
So there's a lot of other Ratnet, sorry,
there's a lot of other Golang tunnels
and proxies to look at other than Ratnet.
So some of the popular ones are Chashell and Chisel
which got used together
in a ransomware attack very recently.
There's a link in this to a very interesting breakdown
of some ransomware that used those two.
And there's also Wireguard as a distributed VPN
which is actually commercial product
which is implemented in Go and very worth checking out.
It's a lot easier to set up than OpenVPN just in general.
And so there's a lot of other tunnel and proxy code in Go,
because Go is typically very stable.
Probably more resulted the built-in testing framework
than anything else, but there's a lot of
good network stuff in Go.
Moving on to another EDR evasion tool.
There's pandorasbox, so I mentioned that Golang
has native support for a virtual file system.
That means that anytime in Go you're referring to a file,
you can totally control the file abstraction.
It doesn't really have to go to the file system.
You can make a, for example, an encrypted in-memory
virtual file system and use it exactly the same way
from your Go code that you talk to normal files
and that is what pandorasbox does.
It basically is a shim between the MemGuard library
which tries as hard as it possibly can
to give you a secure enclave in memory
to protect what you're putting in a MemGuarded region
from tools like Volatility or other analysis tools.
And so basically pandorasbox is the bridge between
the Golang file abstraction and MemGuard,
but it gives you an encrypted VFS very, very easily.
Definitely worth checking out.
So this is another one of my tools,
I call it the Universal Loader.
I implemented reflective DLL loading in Golang
for all platforms including the Apple M1,
so it actually works with ARM 64.
This might be the first loader I've seen anywhere
that actually supports the M1.
Although other than that, it's doing a lot of sort of
traditional reflective DLL loading stuff.
So reflective DLL loading basically mimics the behavior
of the system loader when it loads
a dynamic library into a process.
It just does all the things the system loader does
as best it can, so it loads the library
into the process, lets you call functions
that were in the library, but doing it reflectively
means that you never need to touch disk
which is the main advantage.
If you never touch disk, maybe a V never triggers.
Duh-duh-duh, so...the back ends for the Universal Loader
for Windows, OSX, and Linux are a little bit different.
The Windows method does not use the system loader.
It does use some Go assembly to walk the PEB
and figure out, and then it uses binjectdebug
to like parse the process you're in
and like figure out the imports and exports of everything.
And there is a branch of the Universal Loader
that actually does the import address table fix-ups.
It's called import address table.
And so if you are loading a library
that depends on other libraries,
you will definitely need to use the IAT branch.
The OSX method actually does use the system loader.
We followed a training from MalwareUnicorn
which I highly recommend checking out on writing OSX malware
and it actually finds where the dynamic loader library
is in memory and then parses it with Binject,
finds a couple of key functions in there
that for some reason OSX is the only operating system
that has a built-in part of the operating system
that lets you load a library from RAM.
Both Windows and Linux require a file somewhere,
but OSX does not, so we just use that,
"Oh, load a library from RAM" method
and Bob's your uncle, so that's kind of why
we're using the system loader for OSX and no one else.
And then the Linux method
does not use the system loader either,
but it also does not use memfd.
It really does a reflective library load for Linux.
Memfd is a Linux RAM disk
and the previous loaders for Golang just dumped your
library to memfd and then just loaded it with dlopen.
We do not do that, although it is easy and it works.
Use of memfd is unusual and it's easy to detect.
So doing an actual reflective library load
is a bit stealthier and that's what we're doing.
So this is what it looks like in code.
The interface, as I said in code, is the same
for all operating systems.
Basically, you got your library loaded in a buffer.
You make a new loader with new loader,
you call loader.LoadLibrary.
That's the universal, loading your buffer as a library,
and that will under the hood work differently
for whatever operating system you compile it for,
but the interface remains the same.
And then you can just call exported functions in it
with that library.call.
In this example, we're calling the function
called the runme, we're passing it the argument seven.
So this is just a super simple example,
but it's gonna be exactly like this
for every operating system.
The only thing that'll change is the library
that you actually load.
So a couple of notes.
Because you're not using the system loader,
the libraries that you're dependent on
will not automatically be loaded for you.
So for Windows, you have to use the IAT branch as I said.
But then every library that you depend on,
you have to call syscall.MustLoadDLL for that library
to make sure that it's already loaded and present for you
before you use Universal,
but it'll automatically work it out from there.
And for Linux, I would just recommend
that you statically compile the libraries
you need to load with Universal,
'cause you can do that for Linux.
It doesn't really work for Windows,
but if you just statically compile a library
like it'll just work fine and it's easy.
All right, moving on to our next tool is Donut.
Donut is amazing, it is a payload creation framework
that lets you convert any executable, DLL, .NET assembly,
or VBS to an encrypted injectable shellcode.
And then it is also the assembly loader
that decrypts and loads those payloads into a process.
It is very configurable.
Definitely check it out.
One of its cool features is that it supports remote loads,
so you can actually configure the loader
to pull down the rest of the payload from a web server
instead of having to bundle it in which is pretty sick.
And so I ported the utility that converts things
to Donut payloads to Go,
so that you can use it from an implant or from a C2.
And you might be wondering why would you wanna do this.
We'll see an example in a minute.
Turns out to be a surprisingly handy thing to do
and because it's Pure Go, you can now do this from
any operating system.
So most people's C2s are on Linux, not Windows,
so that comes in handy.
So a note, you could use both Universal or Donut
as a module system for your implants.
A note on why you might wanna do one or the other.
So basically, Donuts,
you can make run in a process all by themself.
Universal will try and load a library
in your current process.
There are a few situations that will break Universal,
because there are things that don't
like running not on the main thread.
For example, mimikatz starts up some COM hosting stuff
that doesn't work right if it's not on the main thread.
So I don't think it's ever gonna work right in Universal
which means, but it works fine through Donut as we'll see.
And there's also a Go scheduler bug that's linked
and so you can often run into problems
if you try and load two Go runtimes in the same thread.
So if you're loading another Go program with Universal,
you might be better off with Donut instead
just to avoid, a load is possible.
It is easier to avoid having two runtimes in one process
and so you can just use Donut instead of Universal
in that situation.
There's another payload creation framework called Scarecrow
which is very popular and definitely worth checking out.
It does some kind of funny stuff.
It signs its loader using Limelighter
as we mentioned before even if you don't
give it a cert, it'll just sign it anyway
as a way of reducing EDR signal.
And its kind of unique and most badass feature
is that it implements, it disables the Windows Event Toolkit
which a lot of EDRs rely on by unhooking itself
in memory from EDR, or sorry, from ETW
which is super cool and worth checking out.
And this is open source too, so that's like
code worth stealing or just use Scarecrow.
A lot of people do.
So now, bananaphone I almost put
in the core components category.
It is so cool, and so important,
and so awesome for EDR evasion.
It is an implementation of Hell's Gate
or direct system calls in Go.
There's a link to the original paper here,
but basically what that means, there are stubs in NTDLL
that everything is in Windows compiled to use
that then in turn calls system calls.
But those stubs in NTDLL are commonly hooked
or monitored by EDR.
And so you can just parse NTDLL,
'cause it's already loaded in your process, I guarantee.
So you can look at your run process memory, look at NTDLL,
figure out where those direct system calls go,
set up a call frame yourself,
and just call them directly and not bother
going through NTDLL thus avoiding hooks.
That's what Hell's Gate is.
So bananaphone is a completely transparent implementation
of Hell's Gate, it's very easy to port existing Go code
that uses syscall to bananaphone,
because C-Sto was kind enough to
make a version of the mkwinsyscall utility
that converts headers to Go stubs.
He made a version of that called make direct win syscall
which converts headers to Hell's Gate-d Go stubs
and it works exactly the same way as syscall,
so it's just mad easy to convert syscall code over.
Highly recommend doing that.
It also has a unique improvement
over traditional Hell's Gate found kind of by accident,
but there's auto mode will actually detect
when your in-memory NTDLL has been hooked by EDR
and automatically fall back to reloading
a fresh copy of NTDLL from disk
instead of the hooked version, the one on disk
will not be hooked and you can parse the one on disk
to figure out where the, to make the direct syscall to
and it works just as well.
And although this creates theoretically more signal,
because loading another copy of NTDLL is sketchy,
in practice, this actually works pretty well.
It works on one of the more popular EDRs
without triggering anything.
So that's kind of neat.
There's also an implementation of Heaven's Gate in Go
called gopherheaven and this is another
EDR evasion technique where you call 64-bit code
from 32-bit code, 'cause nobody
is expecting 32-bit code, boy.
And so this is pretty slick.
And this also has a really great example
of 32-bit 386 Go assembly in case you need that
for some reason.
This is one of the few examples that works.
All right, so we've gone over a bunch of EDR evasion
and NIDS evasion tools.
Let's go on to post-exploitation which is super fun,
'cause it's the loot.
So go-mimikatz, basically
this combines go-donut and bananaphone.
It downloads mimikatz to memory,
makes it into a donut payload, injects it into itself,
into its own process of bananaphone system calls
and it lets you run mimikatz on systems
where you really shouldn't be able to.
The whole program is 150 lines of code.
This is the best example of bananaphone and go-donut.
There's the go-donut bit up top
and the bananaphone bit down bottom.
I couldn't fit 150 lines in a slide,
but you can pull it up on a browser.
I made a quick demo.
I cross-compiled go-mimikatz to Windows AMD 64.
That's all you have to do
to cross-compile it in Go by the way, super easy.
I copied it to an SMB share with the name gm.exe.
I did not garble it and I set up a Win10 Edge,
let it update, Defender's enabled, I'm running from SMB,
and I get the little like proof strings up.
And then I just run it and bam, mimikatz runs,
nothing flags, and I can interact with it
which is just crazy.
So that's current mimikatz, current Win10 Edge.
You will get caught by behavioral stuff
once you start doing stuff in mimikatz,
so you will have to do some other trickery
to avoid the behavioral detections.
There's another utility worth checking out from vyrus
called msflib which makes your
implants work with Metasploit.
It has all of the like Metasploit URL generation magic.
It also uses bananaphone.
It also has code to run a payload in the current process
or inject a payload into a remote process.
Very cool, very worth checking out.
Writing a Windows service in Go
can be a little bit of a pain in the ass.
There's an example link there,
but capnspacehook has made the taskmaster utility
that a lot of people used to interact
with the Windows Task Scheduler as a method of persistence
to avoid having to create a Windows service.
You can just schedule a task to run your thing periodically.
Definitely check that out.
Gscript is a whole other talk.
There was a Defcon 26 talk on it.
It uses an embedded JavaScript interpreter
to make a scripting language for droppers.
There's like a thousand sample gscripts in ahhh's
gscript repo that do things like disable AV, EDR,
firewalls, you can make registry changes,
you can set up persistence, you can do all kinds of things.
So definitely check out gscript,
it's a completely other hour long talk.
Another tool from C-Sto for DIT dumping.
This is another thing that Impacket does,
but Impacket in Python is very slow.
It takes hours to dump a DIT.
C-Sto's tool can do it in minutes.
Definitely check that out
if you wanna dump hashes from a DIT.
And the old Lazagne tool that steals browser passwords,
mail passwords, all kinds of passwords.
It's been ported to Go, goLazagne.
However, it does require CGO
which means you need to set up an external C compiler.
However, the only reason it needs CGO
is because of the dependency on SQLite,
because the browser password databases are SQLite databases,
but there is now a Pure Go implementation of SQLite
which I've linked, so someone some day
will modify goLazagne to no longer require CGO
and that would be lovely, thank you.
There's a few other post-exploitation tools
you should check out including sudophisher
which is hilarious from audibleblink
that actually is an ASKPASS replacement
that will log the sudo password,
so it's just like a funny thing to do.
And also rclone is just utility
to loot things from cloud storage.
So those may come in handy.
And then we have a couple of complete C2 frameworks
entirely implemented in Go.
The heavy hitter in this space is sliver
which is an open-source alternative to Cobalt Strike.
It's coming along, it's under active development.
It's designed to be used by a team,
so the C2 is multi-user, multi-operator
which is pretty awesome.
It has a huge list of features.
It has an implant build in obfuscate framework.
There's so much in there.
I don't have time to go into, definitely check out the wiki
on their GitHub for instructions on how to set it up
and check out the dev branches,
because they have a lot of really cool stuff cooking.
And peer pressure them into doing
their own Defcon talk at some point. (laughs)
Another C2 framework definitely worth mentioning is merlin.
The only downside of merlin is that it's single operator,
but it has some unique features that are
not really in anything else.
It supports a ton of injection methods,
but the one that sticks out
is that it has an implementation in Go of QueueUserAPC.
Definitely worth checking that out.
It also has integration with Donut
and another common loader which is sRDI.
And it does support many C2 protocols also like sliver,
but it has QUIC support which is pretty cool.
So that's my time, thank you very much.
As a reminder, I do host a podcast called "Hack the Planet"
and there are a few interviews we've done on
"Hack the Planet" relevant to this talk.
We have an interview with Josh Pitts which is phenomenal,
the author of Ebowla and the original backdoorfactory.
And we have another episode entirely on Golang malware
featuring C-Sto and capnspacehook,
the authors of some of the utilities I mentioned earlier.
So thank you very much, bye, Defcon 29.
And I hope I gave you some ideas for writing Golang malware,
or even improving detections,
or reversing for Golang malware, thank you.