Patches for http.lua and adding support in httpspider.lua
Vinamra Bhatia <[email protected]>
| Newsgroups | gmane.comp.security.nmap.devel |
|---|---|
| Message-ID | <CAP+gV2zrYPJ8m66fv+BRmY-cf=ssm04N5gDsaXNW6h2sRN1hFw@mail.gmail.com> |
Hello All,
I was trying to add cookie support in httpspider.lua as I wanted to check
my XSS Script. However, I wasn't able to receive cookies on making minor
modifications to the library. I was trying to use DVWA for the purpose
which was running on a VM in my machine.
After quite a few hours of debugging, I found this.
When the spider library goes to {ip}/dvwa/, it gets a cookie in return and
in Location Header, we have login.php.
Instead of going to /dvwa/login.php, it rather goes to login.php. Since
login.php doesnt exist in the VM, it returns of 404 error code.
I realized that url_parse function in the library isnt taking into account
the relative URLs perfectly. Thus, I am submitting a patch which I feel
will solve the problem.
Now, i also noticed that in HTTP library get function, if a link redirects,
it fails to take the cookie generated by the previous link. Hence, We need
to append the cookies accordingly.
I have taken care of the following 3 scenarios:
1. if the response received from the redirect doesnt have any cookie, it
becomes equal to the previous cookie.
2. If response received generates a cookie and the name of the cookie is
different from the previous cookie, it appends it simply in the
option.cookies table.
3. If response received generates a cookie and the name of the cookie is
same as the previous redirect cookie, it updates the value in that
particular cookie name.
I would love to receive feedbacks on this and would request you all to
please test the patches.
I am also attaching the modifications I did in httpspider library to add
cookie support.
Pull Requests for the same patches:
https://github.com/nmap/nmap/pull/912
https://github.com/nmap/nmap/pull/913
Cheers
Vinamra
_______________________________________________
Sent through the dev mailing list
https://nmap.org/mailman/listinfo/dev
Archived at http://seclists.org/nmap-dev/
httpspiderlib.patch
(text/x-patch, 3.7 KB)
Index: nselib/httpspider.lua
===================================================================
--- nselib/httpspider.lua (revision 36817)
+++ nselib/httpspider.lua (working copy)
@@ -125,6 +125,7 @@
o.timeout = options.timeout or 10000
o.whitelist = o.whitelist or {}
o.blacklist = o.blacklist or {}
+ o.cookies = o.cookies or {}
local removewww = function(url) return string.gsub(url, "^www%.", "") end
-- set up the appropriate matching functions
@@ -633,7 +634,7 @@
o:loadLibraryArguments()
o:loadDefaultArguments()
- local response = http.get(o.host, o.port, '/', { timeout = o.options.timeout, redirect_ok = o.options.redirect_ok, no_cache = o.options.no_cache } )
+ local response = http.get(o.host, o.port, '/', { timeout = o.options.timeout, redirect_ok = o.options.redirect_ok, no_cache = o.options.no_cache, cookies=o.options.cookies } )
if ( not(response) or 'table' ~= type(response) ) then
return
@@ -832,7 +833,7 @@
end
if is_web_file then
stdnse.debug2("%s: Using GET: %s", LIBRARY_NAME, file)
- response = http.get(url:getHost(), url:getPort(), url:getFile(), { timeout = self.options.timeout, redirect_ok = self.options.redirect_ok, no_cache = self.options.no_cache } )
+ response = http.get(url:getHost(), url:getPort(), url:getFile(), { timeout = self.options.timeout, redirect_ok = self.options.redirect_ok, no_cache = self.options.no_cache, cookies = self.options.cookies } )
else
stdnse.debug2("%s: Using HEAD: %s", LIBRARY_NAME, file)
response = http.head(url:getHost(), url:getPort(), url:getFile())
@@ -839,7 +840,29 @@
end
else
-- fetch the url, and then push it to the processed table
- response = http.get(url:getHost(), url:getPort(), url:getFile(), { timeout = self.options.timeout, redirect_ok = self.options.redirect_ok, no_cache = self.options.no_cache } )
+ response = http.get(url:getHost(), url:getPort(), url:getFile(), { timeout = self.options.timeout, redirect_ok = self.options.redirect_ok, no_cache = self.options.no_cache, cookies = self.options.cookies } )
+ if (self.options and self.options.cookies and #self.options.cookies>0) then
+ --We replace the value of the cookie if same name cookie exists
+ --Else, we append it in the end.
+ local flag = 0
+ for k,v in pairs(response.cookies) do
+ for k1,v1 in pairs(self.options.cookies) do
+ flag = 0
+ if(v.name == v1.name) then
+ self.options.cookies[k1].value = response.cookies[k].value
+ flag = 1
+ break
+ end
+ end
+ if (flag == 0) then
+ self.options.cookies[#options.cookies+1] = response.cookies[k]
+ end
+ end
+ else
+ if self.options and self.options.cookies then
+ self.options.cookies = response.cookies
+ end
+ end
end
self.processed[tostring(url)] = true
@@ -906,7 +929,9 @@
if ( nil == self.options.doscraping ) then
self.options.doscraping = stdnse.get_script_args(sn .. ".doscraping")
end
-
+ if ( nil == self.options.cookies ) then
+ self.options.cookies = stdnse.get_script_args(sn .. ".cookies")
+ end
end,
-- Loads the argument on a library level
@@ -937,6 +962,9 @@
if ( nil == self.options.doscraping ) then
self.options.doscraping = stdnse.get_script_args(ln .. ".doscraping")
end
+ if ( nil == self.options.cookies ) then
+ self.options.cookies = stdnse.get_script_args(ln .. ".cookies")
+ end
end,
-- Loads any defaults for arguments that were not set
httplib.patch
(text/x-patch, 1.9 KB)
Index: nselib/http.lua
===================================================================
--- nselib/http.lua (revision 36817)
+++ nselib/http.lua (working copy)
@@ -1571,7 +1571,11 @@
if ( not(u.host) ) then
-- we're dealing with a relative url
u.host = stdnse.get_hostname(host)
- u.path = ((u.path:sub(1,1) == "/" and "" ) or "/" ) .. u.path -- ensuring leading slash
+ if ( u.path:sub(1,1) == "/") then
+ u.path = ((u.path:sub(1,1) == "/" and "" ) or "/" ) .. u.path -- ensuring leading slash
+ else
+ u.path = ((path:sub(1,1) == "/" and "" ) or "/" ) .. path .. ((path:sub(#path,#path) == "/" and "" ) or "/" ) .. u.path
+ end
end
-- do port fixup
u.port = u.port or get_default_port(u.scheme) or port.number
@@ -1640,6 +1644,30 @@
response, state = lookup_cache("GET", u.host, u.port, u.path, options);
if ( response == nil ) then
response = generic_request(u.host, u.port, "GET", u.path, options)
+ if(response.cookies and #response.cookies>0) then
+ if (options and options.cookies and #options.cookies>0) then
+ --We replace the value of the cookie if same name cookie exists
+ --Else, we append it in the end.
+ local flag = 0
+ for k,v in pairs(response.cookies) do
+ for k1,v1 in pairs(options.cookies) do
+ flag = 0
+ if(v.name == v1.name) then
+ options.cookies[k1].value = response.cookies[k].value
+ flag = 1
+ break
+ end
+ end
+ if (flag == 0) then
+ options.cookies[#options.cookies+1] = response.cookies[k]
+ end
+ end
+ else
+ if options and options.cookies then
+ options.cookies = response.cookies
+ end
+ end
+ end
insert_cache(state, response);
end
u = parse_redirect(host, port, path, response)