SNMP Write Abuse – RCE via NET-SNMP-EXTEND-MIB
When a Linux host runs net-snmp with a read-write community string, you can inject arbitrary OS commands via the NET-SNMP-EXTEND-MIB. The MIB allows appending new rows to the nsExtendObjects table over SNMP, each row defining a command the daemon will execute on demand. Because snmpd typically runs as root, the commands execute with full privileges.
You cannot modify entries already defined in snmpd.conf, but you can freely add new ones. Commands are triggered when the nsExtendObjects table is read via snmpwalk — this is the run-on-read behaviour that makes the technique work without requiring a second write step.
You need a valid read-write community string. Finding one is an enumeration task. If you only have a read-only community string this technique does not apply.
Prerequisites
Install the required MIB packages on your attack box. Without these, snmpset and snmpwalk cannot resolve the NET-SNMP-EXTEND-MIB names:
Enable all MIBs by editing /etc/snmp/snmp.conf and commenting out or removing the mibs : line, then adding:
mibs +ALLVerify the MIB is available:
Injecting a Command
Register a new command in the nsExtendObjects table with three snmpset OIDs in a single call. The command name is an arbitrary string identifier — use something that blends in or is unique enough to track:
nsExtendStatus = createAndGo creates the row and activates it immediately. nsExtendCommand must be the absolute path to the binary. nsExtendArgs passes arguments.
Triggering Execution and Reading Output
Reading the nsExtendObjects table triggers all registered commands and returns their output:
NET-SNMP-EXTEND-MIB::nsExtendCommand."cmd1" = STRING: /bin/bash NET-SNMP-EXTEND-MIB::nsExtendArgs."cmd1" = STRING: -c "id" NET-SNMP-EXTEND-MIB::nsExtendOutput1Line."cmd1" = STRING: uid=0(root) gid=0(root) groups=0(root) NET-SNMP-EXTEND-MIB::nsExtendResult."cmd1" = INTEGER: 0
The output appears in nsExtendOutput1Line for single-line results or nsExtendOutLine for multi-line output. A result of 0 means the command executed successfully.
Getting a Reverse Shell
Start a listener:
Inject a Python reverse shell. Use a unique command name to avoid collisions with previous entries:
Trigger by walking the table:
Your listener receives a root shell. The snmpwalk call will appear to hang — that is normal while the shell is active.
If Python3 is not available, try a bash reverse shell:
Semi-Interactive Shell with snmp-shell
For a more interactive experience without manually crafting each snmpset, snmp-shell automates the inject-walk cycle and simulates a shell prompt:
This gives you a pseudo-interactive shell running as root. Commands that require a fully interactive TTY (vim, mysql client, su) do not work through this interface — use it for enumeration and then drop a proper reverse shell.
SNMPv3 with Write Access
If the target uses SNMPv3 with auth and privacy, the same technique applies but the snmpset syntax changes:
Trigger the same way with snmpwalk using matching SNMPv3 credentials.
Cleanup
Remove injected entries after the engagement to leave the service in its original state:
Setting nsExtendStatus to destroy removes the row from the table.
Before exploiting, confirm write access is available — see SNMP Write-Enabled Community String for the verification workflow.
References
-
mxrch Automated shell simulation over NET-SNMP-EXTEND-MIB with write access.
-
Abusing Linux SNMP for RCEmogwailabs.de/en/blog/2019/10/abusing-linux-snmp-for-rce (opens in new tab)
MOGWAI LABS Technical background on NET-SNMP-EXTEND-MIB abuse with root privilege context.
-
net-snmp.sourceforge.netnet-snmp.sourceforge.net/docs/mibs/NET-SNMP-EXTEND-MIB.txt (opens in new tab)
NET-SNMP-EXTEND-MIB definition Official MIB file defining nsExtendObjects table structure and access permissions.
Was this helpful?
Your feedback helps improve this page.