Nmap Development mailing list archives

Re: [NSE Script] MySQL Server Information


From: Kris Katterjohn <katterjohn () gmail com>
Date: Sun, 16 Dec 2007 18:07:57 -0600

jah wrote:
Hi Kris,

I've been playing with your script and I wanted to run something by you.

I'm always getting every server capability returned even though, when using wireshark to decode the mysql server greeting, I can see that often the flag for Long Passwords, ODBC and SSL are not set (flag 0xA22C). I've never done any bitwise operations before, nor used lua but it seems to me that bit.bor(num, 1) returns num if true and num+1 if false whereas bit.band(num, 1) returns 1 if true and 0 if false. Given that 0 evaluates to True in lua, I've replaced

   "if bit.bor(num, 1) then"

with

   "if bit.band(num, 1) > 0 then"

and now I'm getting the correct results.  What do you think?
You'll notice I didn't copy this to nmap-dev in case I turn out to be wrong and foolish!!!


D'oh! You're most definitely not wrong or foolish here! :) I have forwarded this to the list; I hope you don't mind.

The server I've been testing with has all of these tested capabilities, so nothing seemed out of the ordinary to me. You're correct in that it should be AND and not OR, and also in that I messed up the boolean test.

I've attached a new script with this change.  Thanks!

Great script by the way. I found another thing while I was playing. I found a webpage that reveals the php mysql_connect command yesterday and, as if by magic, your post to nmap-dev followed shortly after so I took the opportunity to see if I could mod the script and connect to it with the supplied credentials. After playing for a while, running your script was causing nmap to hammer my cpu and I found that I'd been blocked by the mysql server and got the following response (the names have been changed to protect the stupid):
Initiating SCRIPT ENGINE at 22:20

   SCRIPT ENGINE: TCP 192.168.1.1:12439 > 85.234.xxx.xxx:3306 | CONNECT
   SCRIPT ENGINE: TCP 192.168.1.1:12439 < 85.234.xxx.xxx:3306 |
   n....i.Host 'me!' is blocked because of many connection errors;
   unblock with 'mysqladmin flush-hosts'

and it seemed to hang right after:

   SCRIPT ENGINE: TCP 192.168.1.1:12439 > 85.234.xxx.xxx:3306 | CLOSE

It may, or may not, be worth testing for this.


Did this error happen with my script verbatim, or only with your modded version?

I've just been reading on this, and one possibility is just the actual network connection between you and the host. Another thing could be my script causing this. I'm certainly no expert on the MySQL protocol (or Lua as you can tell :D).

I really need to go study as I have my Calculus final tomorrow, but I'll look into this. Thanks for testing and bringing it to my attention.


Regards,

jah


Thanks a lot,
Kris Katterjohn
-- Connect to MySQL server and print information such as the protocol and
-- version numbers, thread id, status, capabilities and the password salt

id = "MySQL Server Information"

description = "Connects to a MySQL server and prints information"

author = "Kris Katterjohn <katterjohn () gmail com>"

license = "Look at Nmap's COPYING"

categories = { "discovery", "safe" }

require 'shortport'
require 'bit'

-- Grabs NUL-terminated string
local getstring = function(orig)
        local str = ""
        local index = 1

        while orig:byte(index) ~= 0 do
                str = str .. string.char(orig:byte(index))

                index = index + 1
        end

        return str
end

-- Convert two bytes into a number
ntohs = function(num)
        local b1 = bit.band(num:byte(1), 255)
        local b2 = bit.band(num:byte(2), 255)

        return bit.bor(b1, bit.lshift(b2, 8))
end

-- Convert three bytes into a number
ntoh3 = function(num)
        local b1 = bit.band(num:byte(1), 255)
        local b2 = bit.band(num:byte(2), 255)
        local b3 = bit.band(num:byte(3), 255)

        return bit.bor(b1, bit.lshift(b2, 8), bit.lshift(b3, 16))
end

-- Convert four bytes into a number
ntohl = function(num)
        local b1 = bit.band(num:byte(1), 255)
        local b2 = bit.band(num:byte(2), 255)
        local b3 = bit.band(num:byte(3), 255)
        local b4 = bit.band(num:byte(4), 255)

        return bit.bor(b1, bit.lshift(b2, 8), bit.lshift(b3, 16), bit.lshift(b4, 24))
end

-- Convert number to a list of capabilities for printing
capabilities = function(num)
        local caps = ""

        if bit.band(num, 1) > 0 then
                caps = caps .. "Long Passwords, "
        end

        if bit.band(num, 8) > 0 then
                caps = caps .. "Connect with DB, "
        end

        if bit.band(num, 32) > 0 then
                caps = caps .. "Compress, "
        end

        if bit.band(num, 64) > 0 then
                caps = caps .. "ODBC, "
        end

        if bit.band(num, 2048) > 0 then
                caps = caps .. "SSL, "
        end

        if bit.band(num, 8192) > 0 then
                caps = caps .. "Transactions, "
        end

        if bit.band(num, 32768) > 0 then
                caps = caps .. "Secure Connection, "
        end

        return caps:gsub(", $", "")
end

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

action = function(host, port)
        local sock
        local response = ""
        local output = ""

        sock = nmap.new_socket()

        sock:set_timeout(5000)

        sock:connect(host.ip, port.number)

        while true do
                local status, line = sock:receive_lines(1)

                if not status then
                        break
                end

                response = response .. line
        end

        sock:close()

        local length = ntoh3(response:sub(1, 3))

        if length ~= response:len() - 4 then
                return "Invalid greeting (Not MySQL?)"
        end

        -- Keeps track of where we are in the binary data
        local offset = 1 + 4

        local protocol = response:byte(offset)

        offset = offset + 1

        local version = getstring(response:sub(offset))

        offset = offset + version:len() + 1

        local threadid = ntohl(response:sub(offset, offset + 4))

        offset = offset + 4

        local salt = getstring(response:sub(offset))

        offset = offset + salt:len() + 1

        local caps = capabilities(ntohs(response:sub(offset, offset + 2)))

        offset = offset + 2

        offset = offset + 1

        local status = ""

        if ntohs(response:sub(offset, offset + 2)) == 2 then
                status = "Autocommit"
        end

        offset = offset + 2

        offset = offset + 13 -- unused

        if response:len() - offset + 1 == 13 then
                salt = salt .. getstring(response:sub(offset))
        end

        output = output .. "Protocol: " .. protocol .. "\n"
        output = output .. "Version: " .. version .. "\n"
        output = output .. "Thread ID: " .. threadid .. "\n"

        if caps:len() > 0 then
                output = output .. "Some Capabilities: " .. caps .. "\n"
        end

        if status:len() > 0 then
                output = output .. "Status: " .. status .. "\n"
        end

        output = output .. "Salt: " .. salt .. "\n"

        return output
end


_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://SecLists.Org

Current thread: