Git Product home page Git Product logo

nidhogg's Introduction

Nidhogg

Logo

image image

Nidhogg is a multi-functional rootkit to showcase the variety of operations that can be done from kernel space. The goal of Nidhogg is to provide an all-in-one and easy-to-use rootkit with multiple helpful functionalities for operations. Besides that, it can also easily be integrated with your C2 framework.

Nidhogg can work on any version of x64 Windows 10 and Windows 11.

This repository contains a kernel driver with a C++ program to communicate with it.

If you want to know more, check out the wiki for a detailed explanation.

Current Features

  • Process hiding and unhiding
  • Process elevation
  • Process protection (anti-kill and dumping)
  • Bypass pe-sieve
  • Thread hiding and unhiding
  • Thread protection (anti-kill)
  • File protection (anti-deletion and overwriting)
  • Registry keys and values protection (anti-deletion and overwriting)
  • Registry keys and values hiding
  • Querying currently protected processes, threads, files, hidden ports, registry keys and values
  • Function patching
  • Built-in AMSI bypass
  • Built-in ETW patch
  • Process signature (PP/PPL) modification
  • Can be reflectively loaded
  • Shellcode Injection
    • APC
    • NtCreateThreadEx
  • DLL Injection
    • APC
    • NtCreateThreadEx
  • Querying kernel callbacks
    • ObCallbacks
    • Process and thread creation routines
    • Image loading routines
    • Registry callbacks
  • Removing and restoring kernel callbacks
  • ETWTI tampering
  • Module hiding
  • Driver hiding and unhiding
  • Credential Dumping
  • Port hiding/unhiding
  • Script execution
  • Initial operations

Reflective loading

Since version v0.3, Nidhogg can be reflectively loaded with kdmapper but because PatchGuard will be automatically triggered if the driver registers callbacks, Nidhogg will not register any callback. Meaning, that if you are loading the driver reflectively these features will be disabled by default:

  • Process protection
  • Thread protection
  • Registry operations

Script Execution

Since version v1.0, Nidhogg can execute NidhoggScripts - a tool that allows one to execute a couple of commands one after another, thus, creating playbooks for Nidhogg. To see how to write one check out the wiki

Initial Operations

Since version v1.0, Nidhogg can execute NidhoggScripts as initial operations as well. Meaning, that if it spots the file out.ndhg in the root of the project directory (the same directory as the Python file) it will execute the file each time the driver is running.

PatchGuard triggering features

These are the features known to trigger PatchGuard, you can still use them at your own risk.

  • Process hiding
  • File protecting

Basic Usage

To see the available commands you can run NidhoggClient.exe or look at the wiki for detailed information regarding how to use each command, the parameters it takes and how it works.

NidhoggClient.exe

# Simple usage: Hiding a process
NidhoggClient.exe process hide 3110

Setup

Building the client

To compile the client, you will need to have Visual Studio 2022 installed and then just build the project like any other Visual Studio project.

Building the driver

To compile the project, you will need the following tools:

Clone the repository and build the driver.

Driver Testing

To test it in your testing environment run those commands with elevated cmd:

bcdedit /set testsigning on

After rebooting, create a service and run the driver:

sc create nidhogg type= kernel binPath= C:\Path\To\Driver\Nidhogg.sys
sc start nidhogg

Debugging

To debug the driver in your testing environment run this command with elevated cmd and reboot your computer:

bcdedit /debug on

After the reboot, you can see the debugging messages in tools such as DebugView.

Resources

Contributions

Thanks a lot to those people who contributed to this project:

nidhogg's People

Contributors

idov31 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nidhogg's Issues

[FEATURE] Get signature level offset dynamically

More of a QoL change than anything but instead of hardcoding offsets and choosing them from the windows version you can get it dynamically by getting the base addr of PsGetProcessSignatureLevel and looking at these bytes
ida64_7SOYoSGz6J

A few bugs to fix.

General notes

  • Pretty much every single IOCTL handler has incorrect input buffer checking.
    • size % sizeof(X) == 0 is true when size == 0, so passing an empty buffer to pretty much any of them will crash you.
    • None of the user supplied pointers in the buffers are are probed for length/alignment/actually being an UM pointer.
    • Data inside user supplied pointers is not copied and creates TOCTOU vulnerabilities.
  • For none of the things you end up signature scanning, do you validate whether the dereferenced offsets make any sense or are even inside the image.
  • Use mutexes consistently. Some of your APIs expect the caller to acquire the mutex, some of them acquire it themselves. There are no comments that indicate this and FAST_MUTEX is not recursive. IIRC there were places that the data wasn't protected by a mutex at all.
  • What is the point of copying over every single signature to its own paged pool, instead of just using it directly (or at least to a stack buffer since size is known at compile time).
  • You already use AutoLock. Same thing can be done for 90% of the allocations to avoid the goto Cleanup spam.
  • There are no SAL annotations for anything.

Bugs list

  • Incorrect iteration / removal from sparse array.

    • If you're iterating an array and decrementing its size while doing that, you'll miss/leak half of the entries.
    • If the array is sparse and you remove not from the end, decrementing the size will make you miss/leak last entry.
      for (ULONG i = 0; i < this->DisabledCallbacksCount; i++) {
      if (this->DisabledCallbacks[i].CallbackAddress == Callback->CallbackAddress) {
      DisabledCallback->CallbackAddress = this->DisabledCallbacks[i].CallbackAddress;
      DisabledCallback->Entry = this->DisabledCallbacks[i].Entry;
      DisabledCallback->Type = this->DisabledCallbacks[i].Type;
      this->DisabledCallbacksCount--;
      status = STATUS_SUCCESS;
      break;
      }
      }

      for (ULONG i = 0; i < this->Files.FilesCount; i++) {
      ExFreePoolWithTag(this->Files.FilesPath[i], DRIVER_TAG);
      this->Files.FilesPath[i] = nullptr;
      this->Files.FilesCount--;
      }

      for (ULONG i = 0; i < this->Files.FilesCount; i++)
      if (_wcsicmp(this->Files.FilesPath[i], path) == 0) {
      ExFreePoolWithTag(this->Files.FilesPath[i], DRIVER_TAG);
      this->Files.FilesPath[i] = nullptr;
      this->Files.FilesCount--;
      return true;
      }

      for (ULONG i = 0; i < this->hiddenDrivers.Count; i++) {
      RemoveHiddenDriver(i);
      }

      for (ULONG i = 0; i < this->hiddenDrivers.Count; i++) {
      if (this->hiddenDrivers.Items[i].DriverName != nullptr)
      if (_wcsicmp(this->hiddenDrivers.Items[i].DriverName, item.DriverName) == 0) {
      ExFreePoolWithTag(this->hiddenDrivers.Items[i].DriverName, DRIVER_TAG);
      this->hiddenDrivers.Items[i].DriverName = NULL;
      this->hiddenDrivers.Items[i].originalEntry = NULL;
      this->hiddenDrivers.Count--;
      return true;
      }
      }

      for (ULONG i = 0; i < this->HiddenProcesses.PidsCount; i++) {
      if (this->HiddenProcesses.Processes[i].Pid == pid) {
      entry = this->HiddenProcesses.Processes[i].ListEntry;
      this->HiddenProcesses.Processes[i].Pid = 0;
      this->HiddenProcesses.PidsCount--;
      break;
      }
      }

      for (ULONG i = 0; i < this->ProtectedThreads.TidsCount; i++)
      if (this->ProtectedThreads.Threads[i] == tid) {
      this->ProtectedThreads.Threads[i] = 0;
      this->ProtectedThreads.TidsCount--;
      return true;
      }
  • Comparing thread ID with thread object.

    if (info->Threads[i].ClientId.UniqueThread == PsGetCurrentThread())

  • Missing buffer size check and assumption that an UNICODE_STRING will be null terminated. MAX_PATH Buffers and assumption of C disk isn't something you'd expect from a driver either.

    WCHAR fullPath[MAX_PATH + 1] = DEFAULT_DRIVE_LETTER;
    auto stack = IoGetCurrentIrpStackLocation(Irp);
    if (!stack || !stack->FileObject)
    return ((tNtfsIrpFunction)NidhoggFileUtils->GetNtfsCallback(0).Address)(DeviceObject, Irp);
    if (stack->FileObject->FileName.Length == 0)
    return ((tNtfsIrpFunction)NidhoggFileUtils->GetNtfsCallback(0).Address)(DeviceObject, Irp);
    wcscat(fullPath, stack->FileObject->FileName.Buffer);

  • Dereferencing object you have not acquired if PsLookupThreadByThreadId is unsuccessful.

    status = PsLookupThreadByThreadId(info->Threads[i].ClientId.UniqueThread, Thread);
    if (!NT_SUCCESS(status) || PsIsThreadTerminating(*Thread)) {
    ObDereferenceObject(*Thread);
    *Thread = NULL;
    continue;
    }

  • Incorrect size for terminating character.

    WCHAR* buffer = (WCHAR*)ExAllocatePoolWithTag(PagedPool, wcslen(item.DriverName) * sizeof(WCHAR) + 1, DRIVER_TAG);

  • Missing removal of hooks on driver unload.

    AntiAnalysis::~AntiAnalysis() {

  • Object is not dereferenced anywhere.

    status = FindAlertableThread(pid, &TargetThread);

    status = PsLookupProcessByProcessId(ULongToHandle(ModuleInformation->Pid), &targetProcess);

  • Missing output buffer length validation for the callbacks array that is populated from an unbounded list.

    for (ULONG i = 0; i < callbacksListCount; i++) {
    if (ReplacedFunction && ReplacerFunction) {
    if (currentCallback->Function == ReplacedFunction)
    currentCallback->Function = ReplacerFunction;
    }
    else {
    Callbacks->Callbacks[i].CallbackAddress = (ULONG64)currentCallback->Function;
    Callbacks->Callbacks[i].Context = currentCallback->Context;
    if (NT_SUCCESS(MatchCallback((PVOID)Callbacks->Callbacks[i].CallbackAddress, driverName)))
    strcpy_s(Callbacks->Callbacks[i].DriverName, driverName);
    }
    currentCallback = (PCM_CALLBACK)currentCallback->List.Flink;
    }

    for (SIZE_T i = 0; i < routinesCount; i++) {
    currentRoutine = *(PULONG64)(routinesList + (i * 8));
    currentRoutine &= ~(1ULL << 3) + 1;
    if (ReplacedFunction && ReplacerFunction) {
    if (*(PULONG64)(currentRoutine) == ReplacedFunction)
    *(PULONG64)(currentRoutine) = ReplacerFunction;
    }
    else {
    Callbacks->Routines[i].CallbackAddress = *(PULONG64)(currentRoutine);
    if (NT_SUCCESS(MatchCallback((PVOID)Callbacks->Routines[i].CallbackAddress, driverName)))
    strcpy_s(Callbacks->Routines[i].DriverName, driverName);
    }
    }

  • Missing null checks.

    Nidhogg/Nidhogg/Nidhogg.cpp

    Lines 210 to 214 in d8697ca

    NidhoggProccessUtils = new ProcessUtils();
    NidhoggFileUtils = new FileUtils();
    NidhoggMemoryUtils = new MemoryUtils();
    NidhoggAntiAnalysis = new AntiAnalysis();
    NidhoggRegistryUtils = new RegistryUtils();

  • Missing lock for iteration of PsLoadedModuleList.

    for (PLIST_ENTRY pListEntry = PsLoadedModuleList->InLoadOrderLinks.Flink;

    PLIST_ENTRY pListEntry = PsLoadedModuleList->InLoadOrderLinks.Flink;

  • Missing address space / VAD locks.

    NTSTATUS MemoryUtils::VadHideObject(PEPROCESS Process, ULONG_PTR TargetAddress) {

  • Trusting usermode PEB pointers to be valid or for the address space to be intact at all.

    for (PLIST_ENTRY pListEntry = targetPeb->LoaderData->InLoadOrderModuleList.Flink;

    for (PLIST_ENTRY pListEntry = targetPeb->LoaderData->InLoadOrderModuleList.Flink;

  • Trusting any RVA to be correct while parsing PE headers or for the pointer to be valid at all.

    PVOID MemoryUtils::GetFunctionAddress(PVOID moduleBase, CHAR* functionName) {

  • All allocated features are leaked in case of failure in driver entry.

    InitializeFeatures();

  • MmHighestUserAddress, MmUserProbeAddress, MmSystemRangeStart are a better choice. Not that this really does any useful validation.

    Nidhogg/Nidhogg/pch.h

    Lines 9 to 11 in d8697ca

    #define VALID_USERMODE_MEMORY(MemAddress)(MemAddress > 0 && MemAddress < 0x7FFFFFFFFFFFFFFF)
    #define VALID_KERNELMODE_MEMORY(MemAddress)(MemAddress > 0x8000000000000000 && MemAddress < 0xFFFFFFFFFFFFFFFF)
    #define VALID_ADDRESS(MemAddress)(VALID_USERMODE_MEMORY(MemAddress) || VALID_KERNELMODE_MEMORY(MemAddress))

  • Operator new is not allowed to return null, consider using std::nothrow version instead. The opposite is true for operator delete where it allows being passed in a null pointer, but ExFreePoolWithTag doesn't.

    void* operator new(size_t size) {
    return ExAllocatePoolWithTag(NonPagedPool, size, DRIVER_TAG);
    }

  • Missing NTSTATUS check.

    MmCopyVirtualMemory(PsGetCurrentProcess(), &this->PrevEtwTiValue, PsGetCurrentProcess(), &enableProviderInfo->IsEnabled, sizeof(ULONG), KernelMode, &bytesWritten);

PatchGuard causes BSOD

我想我已修复它,如果您仍然遇到 BSOD,请重新打开此问题 :)。

WIN10 Microsoft Windows [version 10.0.18363.418]

When I use PChunter to detect its stealth effect,The system immediately blue screen

image

Originally posted by @scareing in #3 (comment)

[FEATURE] -- Initial operations on startup

Hello, I would like to know how I can make it so that when the driver loads automatically, it does things for me without needing the usermode interface? for example: I create a service and configure the driver to start automatically when the driver starts it finds the file C:\Windows\System32\test.dll and inject it into the explorer.exe process?

[BUG] Windows 11 compiling issues

i compiled the driver and tested it on windows 7 pro x64 and windows 11 enterprise x64 and when i start the driver i got a blue screen with the error "SYSTEM THREAD EXCEPTION NOT HANDLED" both machines were with the test mode activated so I can load the driver, do you know how I solve this error?

BSOD

by Patchguard

[FEATURE]

I was thinking maybe a way to communicate with the rootkit from another PC (your main pc) maybe with host and port, or something similar and execute commands.

Compiling Error

On Win 11 VM with VS2022 I'm trying to compile but I'm getting

Severity	Code	Description	Project	File	Line	Suppression State
Error		The BaseOutputPath/OutputPath property is not set for project 'Nidhogg.vcxproj'.  Please check to make sure that you have specified a valid combination of Configuration and Platform for this project.  Configuration='Release'  Platform='x64'.  This error may also appear if some other project is trying to follow a project-to-project reference to this project, this project has been unloaded or is not included in the solution, and the referencing project does not build using the same or an equivalent Configuration or Platform.	C:\Users\User\Desktop\Nidhogg-master\Nidhogg\Nidhogg.vcxproj	C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\amd64\Microsoft.Common.CurrentVersion.targets	823	

What can be the reason?

Thanks

[BUG] BSOD bug in the file protect(I have use EfiGuard closed PatchGuard )

Describe the bug
BSOD bug in the file protect(I have use EfiGuard closed PatchGuard )

To Reproduce
Steps to reproduce the behavior:

  1. Running function...
  2. Caused...

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Versions

  • OS & Build windows 10 LTSC 21h2
  • Nidhogg's Version 1.0
  • Function that you attempted to run & error code

Additional context
Add any other context about the problem here.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.