henrydenhengst

Pentesting with SNMP

Aug 21st, 2015
502
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2. <#
  3. .SYNOPSIS
  4. SNMP Recon Module
  5. Author: Dave (https://zerodaveexploit.wordpress.com/)
  6. License: BSD 3-Clause
  7. Required Depencencies: Snmputil.exe should be present on the system (http://technet.microsoft.com/en-us/library/cc722584.aspx), but if it's not, this script can optionally write it to disk temporarily and clean up provided you add in your own base64 encoded snmputil.exe (I can't redistribute it).
  8. Version 0.1
  9. .DESCRIPTION
  10. It's purely reconnaissance and queries the target hosts over SNMP to get info like:
  11. *Local user accounts (Are there local accounts that shouldn't be here?)
  12. *Installed software (Is vulnerable third party software installed?)
  13. *Running processes (Is this box running SQL? SCOM? etc.)
  14. *Established/Listening TCP and UDP connections (so you can port scan without a port scan)
  15. *Remote IPs and ports for the connections (see relationships between servers, e.g., "Who does the web server talk to?  On what port?  Where is XYZ sending its data?"
  16. *NIC info (Which servers are dual (or more) homed?  What are the IPs?)
  17. Some things that makes this tactic nice is that you don't need a valid domain account to get any of this info, just the SNMP community string. This is good info to enumerate prior to launching any attacks as it transposes the normal noisiness of recon into something that is hopefully less noticeable in the event logs.
  18. .EXAMPLE
  19. C:\PS> . .\Invoke-SnmpSweep.ps1
  20. C:\PS> Invoke-SnmpSweep -hosts @("host1", "host2", "hostN") -community "SecretButSharedEverywhere" -reports "all" -writeTmp "true"
  21.     -hosts - An array of systems to run against.  Easier way to do this might be to read from a file and use that.  
  22.             E.g., $hosts = Get-Content servers.txt; Invoke-SnmpSweep -hosts $hosts
  23.     -community - The SNMP community string.  Obtain it either by brute forcing, or grabbing it from a captured system.
  24.             Control Panel > Administrative Tools > Services > SNMP Service > Traps
  25.     -reports - The category of information you want to query
  26.         Possible -report options are: 'process', 'tcp', 'udp', 'users', 'ips', 'sw', and 'all'
  27.         Default is "all"
  28.     -writeTmp - Whether its okay to write a temporary snmputil.exe in case it isn't already present on the system.
  29.         Writes to C:\windows\temp\snmputil.exe
  30.         Default is "false"
  31.         *Note:  I probably can't redistribute Microsoft's snmputil.exe, so you'll need to obtain it, then use the helper code in this script to convert it to a base64 string
  32. #>
  33.  
  34.  
  35. # Check if the SNMP community is valid against this host to prevent further queries from being run against it if not.
  36. Function CheckError($cmd, $target, $community)
  37. {
  38.     $out = iex "$cmd walk $target $community .1.3.6.1.2.1.1.5"
  39.  
  40.     Try
  41.     {
  42.     If ($out.Contains("error"))
  43.     {
  44.         #Write-Output "[!] There was an error running against $target"
  45.         Write-Output "[!] Error: $out"
  46.         If ($out.CompareTo("error on SnmpMgrOpen 0") -eq 0)
  47.         {
  48.             Write-Output "[!] Could not reach $target, probably a network / ACL issue"
  49.         }
  50.         ElseIf ($out.CompareTo("error on SnmpMgrRequest 40") -eq 0)
  51.         {
  52.             Write-Output "[!] Bad community string?"
  53.         }
  54.        
  55.         return ""
  56.     }
  57.     Else
  58.     {
  59.         return $False
  60.     }
  61.     }
  62.     Catch
  63.     {
  64.         return $False
  65.     }
  66. }
  67.  
  68.  
  69. Function CheckSnmpUtil($cmd)
  70. {
  71.     try
  72.     {
  73.         $tmp = iex $cmd
  74.     }
  75.     catch
  76.     {
  77.         #Write-Output "[!] This system doesn't have $cmd installed."
  78.         return $false
  79.     }
  80.  
  81.     return $true
  82. }
  83.  
  84. # Only used if Microsoft's snmputil.exe isn't found and user has specifically allowed writing of tmp files with -writeTmp option to the script.
  85. # If written, it'll be cleaned up at the end
  86. # Note, you need to fill in the file's base64 value here because I'm not permitted to just redistribute it.
  87. Function CreateTempSnmpUtil($snmpTmpPath = "C:\windows\temp\snmputil.exe")
  88. {
  89.     $snmpUtilb64 = ""
  90.  
  91.     if ([string]::IsNullOrEmpty($snmpUtilb64))
  92.     {
  93.         return $false
  94.     }
  95.     else
  96.     {
  97.         $ByteArray = [System.Convert]::FromBase64String($snmpUtilb64);
  98.         [System.IO.File]::WriteAllBytes($snmpTmpPath, $ByteArray);
  99.         return $snmpTmpPath
  100.     }
  101. }
  102.  
  103. Function GetKeyFromVal($hash, $val)
  104. {
  105.     $hash.getenumerator() | % { if ($_.value -eq $val){ return $_.key }}
  106. }
  107.  
  108. # Returns an array of values corresponding to the queried OID.
  109. # E.g., querying for system users will return ["Account1"],["Account2]
  110. Function SnmpGet ($cmd, $target, $community, $oid)
  111. {
  112.     $out = iex "$cmd walk $target $community $oid"
  113.     $linerex = "Variable\s+=\s+(?:[\w\d\.]+)\s"
  114.     $results = $out -split $linerex
  115.     $return = @()
  116.    
  117.     foreach ($line in $results)
  118.     {
  119.         If ($line -match "Value\s+=\s")
  120.         {
  121.             $line = $line -replace "Value\s+=\s+(String|TimeTicks|Integer32|IpAddress|ObjectID)\s{1}",""
  122.             $return += $line
  123.         }
  124.     }
  125.     return $return
  126. }
  127.  
  128. # Iterate over targets array and print TSV to screen.  User can decide what to do with the output.
  129. # $report contains what you want to query.   Default is 'all'
  130. Function RunSnmpSweep ($servers, $community, $report="all", $snmp_cmd)
  131. {
  132.     #$all_oids = @{ "System Name" = ".1.3.6.1.2.1.1.5"; "Domain" = ".1.3.6.1.4.1.77.1.4"; "Host Uptime" = ".1.3.6.1.2.1.25.1.1"; "System sysuptime" = ".1.3.6.1.2.1.1.3"; "Drives" = ".1.3.6.1.2.1.25.2.3.1.3"; "Local users" = ".1.3.6.1.4.1.77.1.2.25"; "Running Processes" = ".1.3.6.1.2.1.25.4.2.1.2" ;  "Process Status" = ".1.3.6.1.2.1.25.4.2.1.7" ;  "Commandline Params" = ".1.3.6.1.2.1.25.4.2.1.5" ;  "Installed software" = ".1.3.6.1.2.1.25.6.3.1.2" ;  "SW Installed Date" = ".1.3.6.1.2.1.25.6.3.1.5"; "Route Destinations" = ".1.3.6.1.2.1.4.21.1" ;  "IP Addresses" = ".1.3.6.1.2.1.4.20.1.1" ;  "TCP Table Conn Status" = ".1.3.6.1.2.1.6.13.1.1" ;  "TCP Table Local IP" = ".1.3.6.1.2.1.6.13.1.2" ;  "TCP Table Local Port" = ".1.3.6.1.2.1.6.13.1.3" ; "TCP Table Remote IP" = ".1.3.6.1.2.1.6.13.1.4" ;  "TCP Table Remote Port" = ".1.3.6.1.2.1.6.13.1.5" ;  "UDP Table Remote IP" = ".1.3.6.1.2.1.7.5.1.1" ;  "UDP Table Local Port" = ".1.3.6.1.2.1.7.5.1.2" }
  133.  
  134.     # Report 1:  Process info
  135.     if ($report -eq "all" -or $report -eq "process")
  136.     {
  137.         # TSV Headers
  138.         Write-Output "Name`tDomain`tProcName`tStatus`tArgs"
  139.         foreach ($server in $servers)
  140.         {
  141.             $Str_server_name = SnmpGet $snmp_cmd $server $community ".1.3.6.1.2.1.1.5"
  142.             $Str_server_domain = SnmpGet $snmp_cmd $server $community ".1.3.6.1.4.1.77.1.4"
  143.             $Arr_running_processes = SnmpGet $snmp_cmd $server $community ".1.3.6.1.2.1.25.4.2.1.2"
  144.             $Arr_process_status = SnmpGet $snmp_cmd $server $community ".1.3.6.1.2.1.25.4.2.1.7"
  145.             $Arr_process_args = SnmpGet $snmp_cmd $server $community ".1.3.6.1.2.1.25.4.2.1.5"
  146.  
  147.             # Write out report, fix status code too
  148.             for ($i = 0; $i -lt $Arr_process_status.length; $i++)
  149.             {
  150.                 $Arr_process_status[$i] = $Arr_process_status[$i] -replace "1","Running"
  151.                 $Arr_process_status[$i] = $Arr_process_status[$i] -replace "2","Runnable"
  152.                 $Arr_process_status[$i] = $Arr_process_status[$i] -replace "3","Not Runnable"
  153.                 $Arr_process_status[$i] = $Arr_process_status[$i] -replace "4","Invalid"
  154.  
  155.                 Write-Output "$Str_server_name`t$Str_server_domain`t$($Arr_running_processes[$i])`t$($Arr_process_status[$i])`t$($Arr_process_args[$i])"
  156.  
  157.             }
  158.  
  159.         }
  160.  
  161.         Write-Output "`n`n"
  162.     }
  163.  
  164.     # Report 2: TCP Connections
  165.     if ($report -eq "all"  -or $report -eq "tcp")
  166.     {
  167.         Write-Output "Name`tDomain`tLocalIP`tLocalPort`tRemoteIP`tRemotePort`tConnStatus"
  168.  
  169.         foreach ($server in $servers)
  170.         {
  171.             $Str_server_name = SnmpGet $snmp_cmd $server $community ".1.3.6.1.2.1.1.5"
  172.             $Str_server_domain = SnmpGet $snmp_cmd $server $community ".1.3.6.1.4.1.77.1.4"
  173.             $tcp_local_ip = SnmpGet $snmp_cmd $server $community ".1.3.6.1.2.1.6.13.1.2"
  174.             $tcp_local_port = SnmpGet $snmp_cmd $server $community ".1.3.6.1.2.1.6.13.1.3"
  175.             $tcp_remote_ip = SnmpGet $snmp_cmd $server $community ".1.3.6.1.2.1.6.13.1.4"
  176.             $tcp_remote_port = SnmpGet $snmp_cmd $server $community ".1.3.6.1.2.1.6.13.1.5"
  177.             $tcp_status = SnmpGet $snmp_cmd $server $community ".1.3.6.1.2.1.6.13.1.1"
  178.  
  179.             for ($i = 0; $i -lt $tcp_status.length; $i++)
  180.             {
  181.                 # Make human readable
  182.                 $tcp_status[$i] = $tcp_status[$i] -replace "1","Closed"
  183.                 $tcp_status[$i] = $tcp_status[$i] -replace "2","Listen"
  184.                 $tcp_status[$i] = $tcp_status[$i] -replace "3","SynSent"
  185.                 $tcp_status[$i] = $tcp_status[$i] -replace "4","SynReceived"
  186.                 $tcp_status[$i] = $tcp_status[$i] -replace "5","Established"
  187.                 $tcp_status[$i] = $tcp_status[$i] -replace "6","FinWait1"
  188.                 $tcp_status[$i] = $tcp_status[$i] -replace "7","FinWait2"
  189.                 $tcp_status[$i] = $tcp_status[$i] -replace "8","CloseWait"
  190.                 $tcp_status[$i] = $tcp_status[$i] -replace "9","LastACK"
  191.                 $tcp_status[$i] = $tcp_status[$i] -replace "10","Closing"
  192.                 $tcp_status[$i] = $tcp_status[$i] -replace "11","TimeWait"
  193.                 $tcp_status[$i] = $tcp_status[$i] -replace "12","DeleteTCB"
  194.  
  195.                 Write-Output "$Str_server_name`t$Str_server_domain`t$($tcp_local_ip[$i])`t$($tcp_local_port[$i])`t$($tcp_remote_ip[$i])`t$($tcp_remote_port[$i])`t$( $tcp_status[$i] )"
  196.  
  197.             }
  198.         }
  199.  
  200.         Write-Output "`n`n"
  201.     }
  202.  
  203.     # Report 3: UDP Connections
  204.     if ($report -eq "all"  -or $report -eq "udp")
  205.     {
  206.         Write-Output "Name`tDomain`tRemoteIP`tLocalPort"
  207.  
  208.         foreach ($server in $servers)
  209.         {
  210.             $Str_server_name = SnmpGet $snmp_cmd $server $community ".1.3.6.1.2.1.1.5"
  211.             $Str_server_domain = SnmpGet $snmp_cmd $server $community ".1.3.6.1.4.1.77.1.4"
  212.             $udp_remote_ip = SnmpGet $snmp_cmd $server $community ".1.3.6.1.2.1.7.5.1.1"
  213.             $udp_local_port = SnmpGet $snmp_cmd $server $community ".1.3.6.1.2.1.7.5.1.2"
  214.  
  215.             for ($i = 0; $i -lt $udp_remote_ip.length; $i++)
  216.             {
  217.                 Write-Output "$Str_server_name`t$Str_server_domain`t$($udp_remote_ip[$i])`t$($udp_local_port[$i])"
  218.             }
  219.         }
  220.         Write-Output "`n`n"
  221.     }
  222.  
  223.     # Report 4: Local Users
  224.     if ($report -eq "all"  -or $report -eq "users")
  225.     {
  226.         Write-Output "Name`tDomain`tLocalUserAccounts"
  227.  
  228.         foreach ($server in $servers)
  229.         {
  230.             $Str_server_name = SnmpGet $snmp_cmd $server $community ".1.3.6.1.2.1.1.5"
  231.             $Str_server_domain = SnmpGet $snmp_cmd $server $community ".1.3.6.1.4.1.77.1.4"
  232.             $local_users = SnmpGet $snmp_cmd $server $community ".1.3.6.1.4.1.77.1.2.25"
  233.  
  234.             for ($i = 0; $i -lt $local_users.length; $i++)
  235.             {
  236.                 Write-Output "$Str_server_name`t$Str_server_domain`t$($local_users[$i])"
  237.             }
  238.         }
  239.         Write-Output "`n`n"
  240.     }
  241.  
  242.     # Report 5: Multihomed Systems
  243.     if ($report -eq "all"  -or $report -eq "ips")
  244.     {
  245.         Write-Output "Name`tDomain`tNetworkInterfaces"
  246.  
  247.         foreach ($server in $servers)
  248.         {
  249.             $Str_server_name = SnmpGet $snmp_cmd $server $community ".1.3.6.1.2.1.1.5"
  250.             $Str_server_domain = SnmpGet $snmp_cmd $server $community ".1.3.6.1.4.1.77.1.4"
  251.             $ip_addresses = SnmpGet $snmp_cmd $server $community ".1.3.6.1.2.1.4.20.1.1"
  252.  
  253.             for ($i = 0; $i -lt $ip_addresses.length; $i++)
  254.             {
  255.                 Write-Output "$Str_server_name`t$Str_server_domain`t$($ip_addresses[$i])"
  256.             }
  257.         }
  258.         Write-Output "`n`n"
  259.     }
  260.  
  261.  
  262.     # Report 6: Installed Software
  263.     # Installed software  .1.3.6.1.2.1.25.6.3.1.2
  264.     # Installed Date  .1.3.6.1.2.1.25.6.3.1.5
  265.     # Excluding date for now, will dev a way to make human readable if this is important
  266.     if ($report -eq "all"  -or $report -eq "sw")
  267.     {
  268.         Write-Output "Name`tDomain`tSoftware"
  269.  
  270.         foreach ($server in $servers)
  271.         {
  272.             $Str_server_name = SnmpGet $snmp_cmd $server $community ".1.3.6.1.2.1.1.5"
  273.             $Str_server_domain = SnmpGet $snmp_cmd $server $community ".1.3.6.1.4.1.77.1.4"
  274.             $installed_software = SnmpGet $snmp_cmd $server $community ".1.3.6.1.2.1.25.6.3.1.2"
  275.             $install_date = SnmpGet $snmp_cmd $server $community " .1.3.6.1.2.1.25.6.3.1.5"
  276.  
  277.             for ($i = 0; $i -lt $installed_software.length; $i++)
  278.             {
  279.                 Write-Output "$Str_server_name`t$Str_server_domain`t$($installed_software[$i])"
  280.             }
  281.         }
  282.         Write-Output "`n`n"
  283.     }
  284.  
  285. }
  286.  
  287.  
  288.  
  289. ####### Main Function #######
  290. Function Invoke-SnmpSweep
  291. {
  292.  
  293. [cmdletbinding()] Param (
  294.     [array]$hosts,
  295.     [string]$community,
  296.     [string]$reports = "all",
  297.     [string]$writeTmp = "false"
  298.     )
  299.  
  300.     $snmp_cmd = "snmputil"
  301.     $snmpTmpPath = "C:\windows\temp\snmputil.exe"
  302.     $cleanup = $false
  303.  
  304.     if ( (CheckSnmpUtil $snmp_cmd) -eq $false )
  305.     {
  306.         if ($writeTmp -match "^true")
  307.         {
  308.             $snmp_cmd = CreateTempSnmpUtil
  309.             if ($snmp_cmd -eq $false) # false returned if the user hasn't specified b64 data for the binary
  310.             {
  311.                 Write-Output "`n[!] Error: snmputil.exe was not found on this system, and you haven't added it to this script"
  312.                 Write-Output "`n`tObtain it from the Windows NT Resource Kit (I probaby can't redistribute it), or from one of your servers"
  313.                 Write-Output "`tThen convert it to a base64 string and paste it into the value of the `$snmpUtilb64 variable in this script"
  314.                 Write-Output "`tReference: http://support.microsoft.com/kb/232663"
  315.                 Write-Output "`tExample code:"
  316.                 Write-Output "Function ConvertToB64(`$FilePath)`n{`n`t`$ByteArray = [System.IO.File]::ReadAllBytes(`$FilePath);`n`t`$Base64String = [System.Convert]::ToBase64String(`$ByteArray);`n`treturn `$Base64String`n}"
  317.                 return ""
  318.             }
  319.  
  320.             Write-Output "[*] Created temp snmputil.exe in $snmpTmpPath"
  321.             $cleanup = $true
  322.         }
  323.         else
  324.         {
  325.             Write-Output "`n[!] SnmpUtil.exe was not found on this system and 'writeTmp' is not set to 'true' so we aren't writing it"
  326.             Write-Output "[!] If you're okay with writing a temporary exe to the system rerun with something like: "
  327.             Write-Output "[!] Invoke-Snmpsweep -hosts localhost -community secretString -reports all -writeTmp true"
  328.             Write-Output "Exiting"
  329.             return ""
  330.         }
  331.     }
  332.  
  333.     $valid_hosts = @()
  334.    
  335.     foreach ($h in $hosts)
  336.     {
  337.    
  338.         # Preprocessing
  339.  
  340.         # Check for errors (invalid community, ACLs, etc.)
  341.         If($e = CheckError $snmp_cmd $h $community)
  342.         {
  343.             Write-Output "[*] This community string seems to be invalid for: $h"
  344.             Write-Output $e
  345.             continue
  346.         }
  347.         else { $valid_hosts += $h }
  348.    
  349.     } # end foreach
  350.  
  351.     if ($valid_hosts.Length -gt 0)
  352.     {
  353.         RunSnmpSweep $valid_hosts $community $reports $snmp_cmd
  354.     }
  355.     else
  356.     {
  357.         Write-Output "[*] There were no hosts with known SNMP communities"
  358.     }
  359.    
  360.    if ($cleanup -eq $true)
  361.     {
  362.         Write-Output "[*] Removing snmputil from $snmpTmpPath"
  363.         Remove-Item $snmpTmpPath
  364.     }
  365.  
  366.     Write-Output "[*] Done!"
  367. }
Advertisement
Add Comment
Please, Sign In to add comment