Tuesday, April 3, 2012

Detecting Dionaea Honeypot using Nmap

While doing some research, which will be published later. I (with the help of @nevdull77) discovered that the low interaction honeypot Dionaea is easy to detect and using a few Nmap NSE scripts easy to discover.

Honeypots are valuable tools for many of us doing security research, a way to follow trends and If lucky enable us to get hold of new samples and/or exploits.

Low interaction honeypots are in most cases used to lure automatic scripted attacks, which seldom, if ever do background checks on the target system. This might be the reason why not so much attention has been devoted to avoid detection(fingerprinting).

Organizations/individuals running these honeypots, would (I assume) not like to give away their presence at least, not this easy. Not to get to speculative.. but one could guess that if there is one type of honeypot other types maybe close by...

Also it would most likely be bad if lists of know honeypots gets passed around as this could possibility affect the research and the insight for those running these honeypots. It would also be trivial to include these targets as a blacklist in new strains of malware or future tools.

Three different scripts has been "developed" to target the following Dionaea services:
  • SMB
  • SSL (used by HTTPS and SIP-TLS) 
  • MySQL
There are most likely (judging by the Dionaea code) more ways to do a positive identification of the system so consider this a start for future research.

As I have no intention of making research more difficult or disclosing installed systems, this information was send to the maintainer of Dionaea whom I had a good dialog with even thought I put him a "strange" position . Part of our conversation was forwarded to the Dionaea/Nepenthes mailing list: http://sourceforge.net/mailarchive/message.php?msg_id=29067712.

At this time the scripts are not yet public, but as the mail above is public you should be able to do your own detection manually.

Scripts published below ..

I would also like to say that I totally agree that trying to mimic a service 1:1 is hard, if not impossible to achieve. To get the functionality that is included in Dionaea today requires lot of work and understanding of the protocols being emulated. That is important to remember!

It's a sad fact that it is so much simpler to find "flaws" in other peoples creations then trying to create something flawless yourself.

But I like to compare this and similar research into honeypot detection to anti forensic research, research that might look as helping attackers but my view is that anything that I can find/think off has most likely already been done by someone else, someone that might not disclose it's finding to the developer/community ..

I would also like to thank @lvdeijk for letting me "detect" his honeypot.
--------------
dionaea-detect-mysql.nse

description = [[
The low interaction honeypot Dionaea is remotely detectable using information in the response from the MySQL service.

Part of the script use code from another Nmap script created by: Patrik Karlsson

Although Dionaea is built for automatic attacks which would most likely not check the target before exploitation.
However having a honeypot that can be easily fingerprinted could attract unwanted attention to the organization running the service.

Thanks to Patrik Karlsson for his invaluable help during the research!

]]

author = "Mikael Keri"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"default", "discovery", "safe"}

require 'shortport'
require 'stdnse'
require 'mysql'

portrule = shortport.port_or_service(3306, "mysql")

action = function( host, port )

    local socket = nmap.new_socket()
    local result = {}

    socket:set_timeout(5000)
   
        local status, response = socket:connect(host, port)
        status, response = mysql.receiveGreeting( socket )
      
        status, response = mysql.loginRequest( socket, { authversion = "post41", charset = response.charset }, "root", nil, response.salt )  
                     if status and response.errorcode == 0 then
                 status, query_result = mysql.sqlQuery( socket, "SELECT @@version" )
                   end
        socket:close()
              
                if(query_result == "Learn SQL!") then
                  findings = ("Dionaea MySQL service detected: " .. query_result)      
                end  
    return stdnse.format_output(true, findings)  
end

----------
dionaea-detect-smb.nse:


description = [[
The low interaction honeypot Dionaea is remotely detectable using information from the SMB service.
The following two problems has been discovered:

1) The NetBIOS name is "hardcode" into the installation. One can changed it but few if any users change settings outside the configuration file
2) The system times remains the same over time and is set to the date/time when the honeypot was started.

Part of this script use code from other Nmap scripts created by: Thomas Buchanan and Ron Bowes

Although Dionaea is built for automatic attacks which would most likely not check the target before exploitation.
However having a honeypot that can be easily finger printed could attract unwanted attention to the organization running the service.

Thanks to Patrik Karlsson for his invaluable help during the research!

]]

--- Output:
--Host script results:
--| dionaea-detect-smb:
--|   NetBIOS name indicates a Dionaea honeypot: HOMEUSER-3AF6FE
--|   Time does not update between request - R1:2012-03-09 20:08:40:  R2:2012-03-09 20:08:40
--|_  Dionaea daemon uptime: 0 days, 1:07:31.00


author = "Mikael Keri, Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"default", "discovery", "safe"}

require 'smb'
require 'stdnse'

hostrule = function(host)
    return smb.get_port(host) ~= nil
end

function add_to_output(output_table, label, value, value_if_nil)
    if (value == nil and value_if_nil ~= nil) then
        value = value_if_nil
    end
   
    if (value ~= nil) then
        table.insert(output_table, string.format("%s: %s", label, value) )
    end
end

action = function(host)
    local response = {}

    local status, result = smb.get_os(host)
    stdnse.sleep(2)
    local status, result2 = smb.get_os(host)

    local os_string, time_string, time_string2
    
       if (result['server'] == "HOMEUSER-3AF6FE") then
             add_to_output( response, "NetBIOS name indicates a Dionaea honeypot", result[ "server" ] )
        end
   
    if (result['date']) then
        time_string = string.format("%s", result['date'])
    end

    if (result2['date']) then
        time_string2 = string.format("%s", result2['date'])
        end
         
         if(time_string == time_string2) then
          add_to_output( response, "Time does not update between request - R1:" .. time_string, " R2:" ..time_string2 )
         end

  local tm = {}
  tm.year, tm.month, tm.day, tm.hour, tm.min, tm.sec = (time_string):match("^(%d+)%-(%d+)%-(%d+) (%d+):(%d+):(%d+)$")
  local uptime = (os.time() - os.time(tm))
  
     local days, hours, minutes, seconds, htime, mtime, stime
        days = math.floor(uptime / 86400)
        htime = math.fmod(uptime, 86400)
        hours = math.floor(htime / 3600)
        mtime = math.fmod(htime, 3600)
        minutes = math.floor(mtime / 60)
        stime = math.fmod(mtime, 60)
        seconds = stime / 1

        local dayLabel

        if days == 1 then
                dayLabel = "day"
        else
                dayLabel = "days"
        end

        uptime =  string.format("%d %s, %d:%02d:%05.2f", days, dayLabel, hours, minutes, seconds)
      if(time_string == time_string2) then
        add_to_output( response, "Dionaea daemon uptime", uptime)   
      end
    return stdnse.format_output(true, response)
end


---------
dionaea-detect-ssl.nse:

description = [[
The low interaction honeypot Dionaea is remotely detectable using information from the certificate used in the HTTPS and SIP-TLS services .
One can also calculate the uptime for Dionaea using the informaton in the certificate.

To the defence of the Dionaea developer this issue has been noted and written about. Although I understand the usability perspective the issue is still there for anyone who looks.

http://carnivore.it/2011/04/13/convenience

Part of the script use code from another Nmap script created by: David Fifield
Although Dionaea is built for automatic attacks which would most likely not check the target before exploitation.
However having a honeypot that can be easily finger printed could attract unwanted attention to the organization running the service.

Thanks to Patrik Karlsson for his invaluable help during the research!
]]


--- Output:
--Host script results:
--| dionaea-detect-ssl:
--|   Standard Dionaea certificat detected : commonName=Nepenthes Development Team/organizationName=dionaea.carnivore.it/countryName=DE
--|_  Dionaea daemon uptime: 11 days, 16:36:39.00

author = "Mikael Keri"

license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = { "default", "safe", "discovery" }

require 'sslcert'
require 'shortport'
require 'stdnse'

portrule = function(host, port)
    return shortport.ssl(host, port) or sslcert.isPortSupported(port)
end

function add_to_output(output_table, label, value, value_if_nil)
        if (value == nil and value_if_nil ~= nil) then
                value = value_if_nil
        end

        if (value ~= nil) then
                table.insert(output_table, string.format("%s: %s", label, value) )
        end
end

function table_find(t, value)
    local i, v
    for i, v in ipairs(t) do
        if v == value then
            return i
        end
    end
    return nil
end

local NON_VERBOSE_FIELDS = { "commonName", "organizationName",
    "stateOrProvinceName", "countryName" }

function stringify_name(name)
    local fields = {}
    local _, k, v
    for _, k in ipairs(NON_VERBOSE_FIELDS) do
        v = name[k]
        if v then
            fields[#fields + 1] = string.format("%s=%s", k, v)
        end
    end
    return stdnse.strjoin("/", fields)
end

 function date_to_string(date)
        return os.date("%Y-%m-%d %H:%M:%S", os.time(date))
 end

action = function(host, port)
local  response = {}
   
 local status, cert = sslcert.getCertificate(host, port)
  local tm = {}
  tm.year, tm.month, tm.day, tm.hour, tm.min, tm.sec = date_to_string(cert.validity.notBefore):match("^(%d+)%-(%d+)%-(%d+) (%d+):(%d+):(%d+)$")
  local uptime = (os.time() - os.time(tm))

     local  days, hours, minutes, seconds, htime, mtime, stime
        days = math.floor(uptime / 86400)
        htime = math.fmod(uptime, 86400)
        hours = math.floor(htime / 3600)
        mtime = math.fmod(htime, 3600)
        minutes = math.floor(mtime / 60)
        stime = math.fmod(mtime, 60)
        seconds = stime / 1

      local  dayLabel

        if days == 1 then
                dayLabel = "day"
        else
                dayLabel = "days"
       end
  uptime =  string.format("%d %s, %d:%02d:%05.2f", days, dayLabel, hours, minutes, seconds)

      if(stringify_name(cert.subject)  == "commonName=Nepenthes Development Team/organizationName=dionaea.carnivore.it/countryName=DE") then
             add_to_output( response, "Standard Dionaea certificat detected ",stringify_name(cert.subject))
             add_to_output( response, "Dionaea daemon uptime",uptime)  
         end

 return stdnse.format_output(true, response)
end


/Micke

3 comments:

  1. Hi Mikael,
    I am developing a test-bed for malware detection/behavior. I was thinking of using Dionaea. But after reading through your blog I am hesitant.

    ReplyDelete
  2. Do you still think that Dionaea is not a suitable option to be used as a honey pot?

    ReplyDelete
  3. Hi Waqar,

    Short answer, yes I think Dionaea is a suitable option for a low interaction honeypot. The things I was pushing for in my research was the fact that Dionaea is detectable in quite an easy manner. With that knowledge it is up to you to decide if a possible detection would be unsuitable for your needs. Please compare this possibility against the great functionality that Dionaea do offer.


    /Micke

    ReplyDelete