trustedsec / cve-2019-19781

This is a tool published for the Citrix ADC (NetScaler) vulnerability. We are only disclosing this due to others publishing the exploit code first.
Other
570 stars 127 forks source link

Scanner gives false negatives #8

Closed Q1984 closed 4 years ago

Q1984 commented 4 years ago

Scanner gives false negative results, but manually curling gives the smb.

trustedsec commented 4 years ago

Can you check with the latest version? Heard some earlier reports of that but was before I put more refined exception handling in place

trustedsec commented 4 years ago

Closing this one, I can confirm this is not the case.

nosnilmot commented 4 years ago

Latest version of python requests library does not play well with this. It will normalize/canonicalize URLs before sending the request, eliminating the directory traversal from the request, and also follows redirects making it less clear what happened.

eg. The 'req.url' at the end here shows a redirect was followed:

$ python3 
Python 3.7.4 (default, Dec 13 2019, 01:02:18) 
[GCC 7.3.1 20180712 (Red Hat 7.3.1-6)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> req = requests.get('https://x.x.x.x/vpn/../vpns/etc/smb.conf')
>>> req.content
b'<!DOCTYPE html PUBLIC "-//W3C//DTD XDEV_HTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
... snipped ...
</body>\r\n</html>\r\n'
>>> req.status_code
200
>>> req.url
'https://x.x.x.x/vpn/tmindex.html'

Latest requests library allows not following redirects, but will still normalize the request URL, which hides the vulnerability:

$ python3
Python 3.7.4 (default, Dec 13 2019, 01:02:18)
[GCC 7.3.1 20180712 (Red Hat 7.3.1-6)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> req = requests.get('https://x.x.x.x/vpn/../vpns/etc/smb.conf', allow_redirects=False)
>>> req.content
b'<html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8"><script type="text/javascript" src="/vpn/resources.js"></script><script type="text/javascript" language="javascript">var Resources = new ResourceManager("/logon/themes/Default/resources/{lang}", "REDIRECTION_BODY");</script></head><body><span id="This object may be found "></span><a href="/vpn/tmindex.html"><span id="here"></span></a><span id="Trailing phrase after here"></span><script type="text/javascript" language="javascript">Resources.Load();</script></body></html>'
>>> req.status_code
302
>>> req.url
'https://x.x.x.x/vpns/etc/smb.conf'
>>> 
nosnilmot commented 4 years ago

Correction: the problematic library is actually urllib3 (which was also downgraded when I downgraded requests). The new behaviour appears to have been introduced in version 1.25.0.

mlgualtieri commented 4 years ago

Just was looking for a solution to this myself. I was left scratching my head, as I don't see an option to prevent urllib from preprocessing the URL. Also tried a rewrite to use pycurl but the ../ is also removed from the URL using that library.

Verified with tcpdump the GET request being made is: GET /vpns/cfg/smb.conf HTTP/1.1

A real hacky workaround is to execute the curl binary via os.system.

Q1984 commented 4 years ago

As the same as in the exploit script. Gives a false negative and exit.

nosnilmot commented 4 years ago

Also tried a rewrite to use pycurl but the ../ is also removed from the URL using that library.

You can use the "path as is" option in PyCurl: curl.setopt(pycurl.PATH_AS_IS, 1)

A real hacky workaround is to execute the curl binary via os.system.

Ewwwww

trustedsec commented 4 years ago

I'm using requests 2.18.4 and is working fine:

root@stronghold-nix:/home/relik/Desktop/git/cve-2019-19781# pip3 freeze | grep requests requests==2.18.4

trustedsec commented 4 years ago

Digging into this

trustedsec commented 4 years ago

I've updated the requirements section to reflect that the version of requests needs to be 2.18.4 or above (most recent version in pip repositories is 2.22). This does appear to be a bug in older version of python requests.

Running pip3 install -r requirements should alleviate any issues.

nosnilmot commented 4 years ago

requests isn't actually the issue, urllib3 is - versions since 1.25.0 use a new url parser that rewrites/normalizes URLs and eliminates the directory traversal. the problem is with new versions, not old.

trustedsec commented 4 years ago

Thanks for the info, for the time being I put a check in for requirements to be <=urllib3==1.24.3.

Looks to be this one here:

Upgraded urllib3.utils.parse_url() to be RFC 3986 compliant. (Pull #1487)

trustedsec commented 4 years ago

https://github.com/urllib3/urllib3/pull/1487

ThomasBjorseth-BI commented 4 years ago

I downloaded this script on Saturday, and again today. The version from Saturday works as expected and gives me 3 positives. The version from today has a different output (no separate line per server scanned), and gives me 0 positives. I have tested this on two different Linux servers, one on the inside of our firewall, and one on the outside. Both servers have the same versions of both "requests" and "liburl3".

trustedsec commented 4 years ago

I do not appear to be able to reproduce this - I've scanned entire class B's, and C's without any issues and shows them properly. I would ensure you have the proper outbound filtering rules for the ports you are scanning. The only thing that has substantially changed since Saturday is a more defined response from the smb.conf but wouldn't have any impact on anything else related to detect/non detect.

root@stronghold-nix:/home/relik/Desktop/git/cve-2019-19781# ./cve-2019-19781_scanner.py /24 8889


/ \ \ / / | | \ / \/ |/ \ / |/ ____ / \/ | | | \ \ / /| | ____ ) | | | || | () |____| | () | / / () || | | | \ \/ / | |____/ /| | | || |_, |__| |__, | / / > < | | | | \ / | | / /| || || | / / | | / / / / | () || | _| \/ |__| |__|\/ || // || // /_/ __/ ||

CVE-2019-19781-Scanner Company: TrustedSec Written by: Dave Kennedy This will look to see if the remote system is still vulnerable to CVE-2019-19781. This will only scan one host at a time. You can use CIDR notations as well for example: 192.168.1.1/24 You can use hostnames instead of IP addresses also. Example: python3 cve-2019-19781_scanner.py 192.168.1.1/24 443 Example2: python3 cve-2019-19781_scanner.py 192.168.1.1 443 Example3: python3 cve-2019-19781_scanner.py fakewebsiteaddress.com 443 Example4: python3 cve-2019-19781_scanner.py as15169 443 Usage: python3 cve-2019-19781_scanner.py targetip targetport

[!] This Citrix ADC Server: is still vulnerable to CVE-2019-19781. Tested 256 Servers : 1 were vulnerable

root@stronghold-nix:/home/relik/Desktop/git/cve-2019-19781#
ThomasBjorseth-BI commented 4 years ago

Since I am scanning from the same two servers (one at work, one at home), I find it weird that outbound rules would impact this. The script from Saturday gives me three positives both from at home and work, while the script from today gives me zero positives.

The older version has three example commands in the header, the newer version has four. The file sizes differ with approx 2000 bytes.

trustedsec commented 4 years ago

Mentioned in previously response, there were changes on Saturday and through Sunday which would indicate the file size difference. The main changes on Saturday were to ensure and validate it was a Citrix server. Are the three you are scanning actually Citrix systems.

ThomasBjorseth-BI commented 4 years ago

Some of them are, and the output from the older version of the script indicates the different responses while it traverses through the subnet:

[-] Server xxx.yyy.zzz.1 does not appear to be a Citrix server. [-] ConnectionError: Server xxx.yyy.zzz.2 did not respond to a web request or the port (80) is not open. [!] This Citrix ADC Server: xxx.yyy.zzz.3 is still vulnerable to CVE-2019-19781. [-] ReadTimeout: Server xxx.yyy.zzz.4 timed out and didn't respond on port: 80. [*] Awesome! The server xxx.yyy.zzz.5 is not vulnerable.

The newer version of the script gives me no output per server, just a summary line at the end.

trustedsec commented 4 years ago

Yes, the readout from the servers was removed/minimized and just gives a summary report out at the end. Sorry to hear it's not reporting out, I have validated that it is properly looking for the servers and is finding them. I would check around to see if you can actually get the responses back. It is working as intended.

hevnsnt commented 4 years ago

I just did a pip3 install -r requirements.txt

which resulted in Successfully installed urllib3-1.24.3 whois-0.9.5

Seems to be working on my end:

[!] This Citrix ADC Server: x.x.x.116 is still vulnerable to CVE-2019-19781. Finished testing 1 servers: Found 1 to be vulnerable. Below is a list system(s) identified:

x.x.x.116

trustedsec commented 4 years ago

If you want the output similarly to Saturday, you can type:

python3 cve-2019-19781.py ipaddr port verbose

Will need to git pull the latest version, just added verbose option.

trustedsec commented 4 years ago

Going to close this one out since it appears fixed in the requirements for now. I submitted for newer versions of urllib3 and will see if they fix. If you follow the installation of versions in the requirements it works fine.

trustedsec commented 4 years ago

Opened a new issue for urllib3 here: https://github.com/urllib3/urllib3/issues/1781

trustedsec commented 4 years ago

This has been addressed in a better way by using prepare. It is now working in all versions of urllib3.

with requests.Session() as s: r = requests.Request(method='POST', url=url, data=data, headers=headers) prep = r.prepare() prep.url = url req = s.send(prep, verify=False)