-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TFTP Version Script #548
TFTP Version Script #548
Conversation
… except via LPeg.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exciting! I look forward to testing this, and I hope we can gather a good set of fingerprints to cover lots of different TFTP servers.
nmap-service-probes
Outdated
@@ -11691,22 +11691,6 @@ match msrpc m|^\x04\x06\0\0\x10\0\0\0\0\0\0\0| | |||
|
|||
match netprobe m|^\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0$| p/Mega System Technologies NetProbe Lite environmental sensor/ d/specialized/ | |||
|
|||
match tftp m|^\0\x05\0\x02\0The IP address is not in the range of allowable addresses\.\0| p/SolarWinds tftpd/ i/IP disallowed/ o/Windows/ cpe:/a:solarwinds:tftp_server/ cpe:/o:microsoft:windows/a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should leave these match lines here, since they are useful for users who do not use NSE. The tftp-version script could even check to be sure there hasn't already been a match from -sV
before proceeding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Restored probes.
scripts/tftp-version.nse
Outdated
local OPCODE_DATA = 3 | ||
local OPCODE_ERROR = 5 | ||
|
||
local responses = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could load these fingerprints from an external file like we do for http-default-accounts
or ike-version
. Need comments to annotate what these fields are for and what format to use. Probably a more compact representation would be helpful, too:
{
2, "The IP address is not in the range of allowable addresses.",
{
p="SolarWinds tftpd", i="IP disallowed", o="Windows",
cpe={"a:solarwinds:tftp_server", "o:microsoft:windows/a",}
}
}
or similar. Table keys that are valid identifiers can be specified without the ["brackets-and-quotes"]
syntax.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, compacted slightly and followed the example of ike-version
.
scripts/tftp-version.nse
Outdated
} | ||
|
||
local record_match = function(port, sw) | ||
if sw.p then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to peacefully coexist with version info set by other means (i.e. nmap-service-probes
). Check out how other version-category scripts do this: http-server-header
, snmp-info
, etc. Decide whether to append or replace the existing version info.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added, should now only append to the version information.
scripts/tftp-version.nse
Outdated
-- should respond back to the port matching the sending script. | ||
-- | ||
-- Note that due to API limitations, we can't know if the response came from | ||
-- the host we sent the request to, so we must assume it does. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we could do socket:get_info()
after this receive
to verify this? I agree, there are better underlying C calls for doing this, but to get it working with what we have, that could be an improvement. Also, we should be able to use stdnse.get_timeout
to improve the timeout for the receive from the default 30 seconds. This would allow us to retransmit a couple times if necessary without taking too long.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a socket:get_info()
check. Not sure what you mean with setting the timeout. Do you mean lower it to something like 5 seconds, and sending something say 3 times if there's no response?
-- Parse the response. | ||
local pkt = parse(res) | ||
if not pkt then | ||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some debug statements for these nil
returns would be helpful to know at what point we encountered a problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added, all unsuccessful runs should now have a debug message.
scripts/tftp-version.nse
Outdated
|
||
author = "Mak Kolybabi <mak@kolybabi.com>" | ||
license = "Same as Nmap--See https://nmap.org/book/man-legal.html" | ||
categories = {"default", "discovery", "safe", "version"} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think "discovery" is appropriate, because we're not discovering anything, only determining version, which is already covered by "version." Will have to think about "default" and "safe" vs "intrusive" because we're requesting a nonexistent file. How big of a deal is that? I'd guess not many places check TFTP logs, but do you have a better idea?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels non-intrusive to me because:
- Most other intrusive scripts are exploits, bruteforcing, or enumeration
- There's a small chance of accessing sensitive information due to the random filename
- The traffic generated is very minimal
scripts/tftp-version.nse
Outdated
|
||
-- Populate the service information by referencing our list of software | ||
-- responses. | ||
identify_software(pkt, port) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about unidentified software? Have identify_software
return the match info instead of setting it in the port
object directly. Then do the port.version
setting here in the action function; if there's no match, return output showing the message and code that were returned and requesting user to submit it to dev@nmap.org.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added.
Been doing some testing, here are my observations:
And here's another fingerprint: table.insert(fingerprints, {
1, "File not found", {
p = "Netkit tftpd or atftpd",
cpe = {"a:netkit:netkit", "a:lefebvre:atftpd"},
}}) |
Added the fingerprint format info, the new fingerprint, and the Assuming I'm reading the man pages right, switching to using a single socket, then calling |
Just pushed this script! Made some changes based on research into #608 as well as trying to support more indicators for the future (other opcodes, malformed packets, etc. that might be returned by clumsy tftp servers). Looking forward to using it! |
As suggested here, I've made a TFTP version script.
The script could use a lot more testing on different targets. I have successfully tested against a new free download of SolarWinds TFTP and against non-TFTP services and unrecognized TFTP services.
The way matching against fingerprints occurs is the simplest thing I could think of. If there's a good way to either parse a file of fingerprints to generate the hardwired table, that would be good. Also, regexes are not in use, but could be added if necessary. Couldn't find any PCRE exposed, only LPeg which doesn't match up very well with the fingerprint format. I also removed the probe matches. Not sure if that was appropriate.
Finally, if
recvfrom()
was exposed to the NSE that would be desirable. I worry about receiving packets from other hosts unintentionally, or receiving packets during the brief window during which we're swapping sockets. Not sure if Nmap has protections against that.Anyways, if you want things changed or hit bugs, let me know and I'll fix them as soon as I can. Next up: nbd-info!