-
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
Add script to decode F5 BIG-IP cookies. #892
Conversation
Ping. |
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.
Thanks for the script and sorry for the late reply. The script looks good. I think we just need some small changes and we will be ready to commit.
scripts/f5-cookie-decode.nse
Outdated
local host = split[1] | ||
local port = split[2] | ||
|
||
local packed = string.pack("<I", tonumber(host)) |
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.
Please specify size because default size differs across platforms.
scripts/f5-cookie-decode.nse
Outdated
end | ||
|
||
if next(decoded) then | ||
return decoded |
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.
Can you make the script return a stdnse.output_table() to generate XML output automatically?
scripts/f5-cookie-decode.nse
Outdated
@@ -0,0 +1,70 @@ | |||
-- See here: https://support.f5.com/csp/article/K6917 | |||
description = [[ | |||
Decodes any unencrypted F5 BIG-IP cookies in the HTTP response. |
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.
Can you add a little more documentation about this? Maybe just add a reference link.
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 would be the reference link no?
https://support.f5.com/csp/article/K6917
Not sure what else to add here or should that go in the description?
No problem. I've updated this. Let me know what you think. Note that I added the local host = tonumber(split[1])
...
if host then
...
end to handle the case where the cookie is encrypted since the script does not work for encrypted cookies. |
Also note that it seems: if next(decoded) then
return decoded
end Doesn't work with Like so:
Is there some way to avoid that? |
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.
A few more ideas for your script.
scripts/f5-cookie-decode.nse
Outdated
local split = stdnse.strsplit("%.", cookie.value) | ||
|
||
local host = tonumber(split[1]) | ||
local port = split[2] |
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 is shadowing function parameters host
and port
from above. While not technically incorrect, it muddies the code.
scripts/f5-cookie-decode.nse
Outdated
local host = tonumber(split[1]) | ||
local port = split[2] | ||
|
||
if host 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.
Strictly speaking, you are not really checking anywhere that the cookie truly has the expected value. All you know at this point is that the cookie consists of a valid number, integer or float, positive or negative, which is optionally followed by a dot and an arbitrary string. So the code tries to process values like -99E+99
or 0.!@$%
, resulting in run-time complaints.
You might want to consider constructs like:
local chost, cport = cookie.value:match("^(%d+)%.(%d+)%.")
if chost and tonumber(chost) < 0x100000000 and tonumber(cport) < 0x10000 then
scripts/f5-cookie-decode.nse
Outdated
table.insert(values, utf8.codepoint(c)) | ||
end | ||
|
||
local ip_address = stdnse.strjoin(".", values) |
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 can be collapsed into a one-liner like this one:
chost = table.concat({("BBBB"):unpack(("<I4"):pack(chost))}, ".", 1, 4)
scripts/f5-cookie-decode.nse
Outdated
end | ||
|
||
local ip_address = stdnse.strjoin(".", values) | ||
port = tonumber(stdnse.tohex(string.pack("<H", port)), 16) |
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.
Similarly you could use pack
- unpack
to make it very clear what is going on here:
cport = (">I2"):unpack(("<I2"):pack(cport))
scripts/f5-cookie-decode.nse
Outdated
local ip_address = stdnse.strjoin(".", values) | ||
port = tonumber(stdnse.tohex(string.pack("<H", port)), 16) | ||
|
||
table.insert(decoded, string.format("%s:%s:%s", cookie.name, ip_address, 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.
If you are ambitious, it would be nice if the XML output was truly structured. For cookie BIGipServeragdncdcqd05_pool=1193829386.24866.0000
this could be something like:
<cookie>
<pool>agdncdcqd05_pool</pool>
<address>
<addr>10.100.40.71</addr>
<type>ipv4</type>
</address>
<port>8801</port>
</cookie>
(Adding the IPv4 designation, which might look overbearing right now, also gives you the opportunity to add decoding for IPv6 cookies in the future without breaking backward compatibility of the output .)
You can still keep your current compact format for the regular textual output by maintaining two tables, one for the XML output and one for the textual, and then return the findings as follows:
if #output > 0 then
return output, stdnse.format_output(true, text_output)
end
If you do decide to add the XML output then do not forget to add the corresponding XML output example to the documentation section above.
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.
Just to make it clear, nmap does not give you a way how to produce a rich XML like the ideal I have outlined. This is what you could get:
<table key="cookies">
<table>
<elem key="pool">agdncdcqd05_pool</elem>
<table key="address">
<elem key="addr">10.100.40.71</elem>
<elem key="type">ipv4</elem>
</table>
<elem key="port">8801</elem>
</table>
<table>
...another cookie...
</table>
</table>
See https://nmap.org/book/nse-api.html#nse-structured-output
scripts/f5-cookie-decode.nse
Outdated
end | ||
end | ||
|
||
return decoded |
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.
As you said, it does not really make sense to return zero-length findings. You should be able to use #decoded
for that test.
scripts/f5-cookie-decode.nse
Outdated
local http = require "http" | ||
local shortport = require "shortport" | ||
local stdnse = require "stdnse" | ||
local string = require "string" |
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.
Do not forget to import table
.
Thanks! I've updated this. Is this sufficient so far? I did not work on the structured output yet. |
Added the structured output. Unfortunately I have one more issue.
When it should be like this:
|
Two tweaks: First, the description should be a little more, well, descriptive. You know what information F5 cookies carry but a casual user might not. It would be nice if somebody just browsing the scripts could get a basic idea what the script is about (without following up the provided link). It does not have to be extensive. As an example, OpenVAS has this to say about the cookie:
And Metasploit:
The second tweak is that the script should be renamed to be more consistent with other scripts, by prefixing it with "http-". It could be "http-bigip-cookie" or "http-f5-bigip-cookie". |
Ok. I'll update the script name and fix the description. |
That is the "unnamed" table representing each cookie. There are two ways how to deal with it:
|
BTW, you do not have to always use It could be as simple as: local result = {
pool = cookie.name:sub(12),
address = {host = host, type = "ipv4"},
port = port}
table.insert(output, result) |
Ah ok. I updated the script to avoid most of those calls now. :) |
Port is not really part of the IP address so it should be moved one level up. Please take a look at other scripts (e.g. @cldrn Paulino, any more thoughts before merging? |
👍 Thanks! I will add that soon. I've fixed the port part. |
I added the |
Looks good to me. Let's give it a few days in case @cldrn has more feedback. One triviality: One false-negative case: local response = http.get(host, port, path, {redirect_ok=false}) |
Ok thanks!. I've added those changes. |
Great work. I don't have any more requests except for including the reference URL in the description so it gets displayed on NSE documentation as well. (Instead of a comment inside the file) Thanks for the effort @sethjackson! |
Thanks! I've added the URL to the description instead. |
This just adds a script to decode any unencrypted BIG-IP cookies in the response.
See this support article for information on the encoding scheme: https://support.f5.com/csp/article/K6917