def RdpAnalysis(self): RdpAllEvent = 0 RowCount = 0 Rdppath = "C:\Windows\System32\winevt\Logs\Microsoft-Windows-TerminalServices-RemoteConnectionManager%4Operational.evtx" with evtx.Evtx(Rdppath) as log: for _ in log.records(): RdpAllEvent += 1 soup = BeautifulSoup(_.xml(), "lxml") System_ = soup.find("system") EventId = int(System_.find("eventid").text) if EventId == 1149: RowCount += 1 self.tableWidgetRdp.setRowCount(RowCount) self.tableWidgetRdp.setColumnCount(4) with evtx.Evtx(Rdppath) as log: EventCounter = 0 for x in range(1, RdpAllEvent + 1): try: CurrentProg = "%d" % int((x / RdpAllEvent) * 100) print(CurrentProg) self.progress.setValue(int(CurrentProg)) getone = log.get_record(x) soup = BeautifulSoup(getone.xml(), "lxml") System_ = soup.find("system") EventId = int(System_.find("eventid").text) UserData = soup.find("userdata") if EventId == 1149: TimeCreated = System_.find("timecreated").get( "systemtime") CondenseTime = str(transtime( TimeCreated.split('.')[0])) UserName = UserData.find("param1").text UserPcName = UserData.find("param2").text AccessIP = UserData.find("param3").text RdpTempList = [ CondenseTime, UserName, UserPcName, AccessIP ] for floop, sloop in zip(range(0, len(RdpTempList)), RdpTempList): self.tableWidgetRdp.setColumnWidth(floop, 200) self.tableWidgetRdp.setItem( EventCounter, floop, QTableWidgetItem(sloop)) EventCounter += 1 except UnicodeDecodeError: pass self.tableWidgetRdp.show() print("[+] RDP Analysis Done !")
def getUSBlog(evtxfile): os.mkdir('result') result = open('./result/usb_eventlog.csv', 'w') result.write('EventID,Time,Event,Product,SerialNum,lifetime\n') vendor, product, revision, serialNum, lifetime = "", "", "", "", "" with evtx.Evtx(evtxfile) as log: for record in log.records(): preRecord = record.xml() preTime = getEvtTime(preRecord) break count = 0 print("\n\n[+] Processing...\n") with evtx.Evtx(evtxfile) as log: for record in log.records(): xmlstr = record.xml() evtid = int(getEvtID(xmlstr)) evtTime = getEvtTime(xmlstr) if preTime == evtTime: count += 1 else: if count == 25 and preTime != evtTime: state = "Mounted" result.write( str(evtid) + "," + evtTime + "," + state + "," + product + "," + serialNum + "," + lifetime + "\n") elif count == 8 and preTime != evtTime: state = "Unmounted" result.write( str(evtid) + "," + evtTime + "," + state + "," + product + "," + serialNum + "," + lifetime + "\n") count = 1 offset = xmlstr.find("DISK&") if offset > 0: tmpOffset = xmlstr.find("lifetime") - 3 tmp = xmlstr[offset:tmpOffset] startOffset = tmp.find("VEN_") + 4 endOffset = tmp.find("&PROD") vendor = tmp[startOffset:endOffset] startOffset = tmp.find("PROD_") + 5 endOffset = tmp.find("&REV") product = tmp[startOffset:endOffset] startOffset = tmp.find("#") + 1 endOffset = startOffset + tmp[startOffset:].find("&") serialNum = tmp[startOffset:endOffset] offset = xmlstr.find("lifetime") if offset > 0: tmpOffset = xmlstr.find("xmlns:auto") tmp = xmlstr[offset:tmpOffset] startOffset = tmp.find("=\"{") + 2 endOffset = tmp.find("}") + 1 lifetime = tmp[startOffset:endOffset] preRecord = record.xml() preTime = getEvtTime(preRecord) result.close() print("\n[+] Completed!\n")
def main(inputfile, output): print(inputfile, output) outputfile = open(output, "w") outputfile.write("Date & Time,Event,User name,IP Address,Computer") Event_Desc = { '21': 'Session Connected', '22': 'Shell Notification Started', '24': 'Session Disconnected', '25': 'Session Reconnected' } with evtx.Evtx(inputfile) as log: for record in log.records(): root = ET.fromstring(record.xml()) if root[0][1].text in ['21', '24', '25']: if root[1][0][2].text != 'LOCAL': outputfile.write("\n") dt = parse(root[0][7].attrib['SystemTime']).strftime( '%Y-%m-%d %H:%M:%S %Z%z') eventd = Event_Desc[str(root[0][1].text)] outputfile.write(dt + "," + eventd + "," + root[1][0][0].text + "," + root[1][0][2].text + "," + root[0][12].text) print('-' * 5 + "Entry " + '-' * 5) print('Date/Time - ', dt) print('Event - ', eventd) print('User name - ', root[1][0][0].text) print('IP Address - ', root[1][0][2].text) print('Computer - ', root[0][12].text)
def dump(_path): with evtx.Evtx(_path) as log: print(e_views.XML_HEADER) print("<Events>") for record in log.records(): print(record.xml()) print("</Events>")
def Magic(): import argparse ps_scripts_ran = [] parser = argparse.ArgumentParser() parser.add_argument("evtx", type=str) args = parser.parse_args() with evtx.Evtx(args.evtx) as log: for each in log.records(): elm = each.lxml() R_ID = (elm.xpath("//event:EventID", namespaces={"event": schema})[0].text) Sour = (elm.xpath("//event:Channel", namespaces={"event": schema})[0].text) ctime = (elm.xpath("//event:TimeCreated", namespaces={"event": schema})[0].get("SystemTime")) User = (elm.xpath("//event:Security", namespaces={"event": schema})[0].get("UserID")) path = (elm.xpath( "//EventData:Data[@Name='ScriptBlockText']/text()", namespaces={"EventData": schema})) exists = False for item in ps_scripts_ran: if item[4] == path: exists = True if not exists: ps_scripts_ran.append([ R_ID, Sour, str(ctime).replace(" ", " T") + "Z", User, path ]) return ps_scripts_ran
def main(): if (len(sys.argv) != 2): print("\033[31m[-]\033[0m Invalid number of arguments!") print(" \033[33mpython3 malicious-pwsh.py <file.evtx>\033[0m") exit(1) print("\033[32mConverting " + sys.argv[1] + " to XML... \033[0m") # Partial code from evtx_dump.py with evtx.Evtx(sys.argv[1]) as log: xmlevents = "<Events>" for record in log.records(): xmlevents += (record.xml()) xmlevents += "</Events>" print("\033[32mRunning freq.py... \033[0m") dictevents = xmltodict.parse(xmlevents) for event in dictevents['Events']['Event']: if event['System']['EventID']['#text'] == "4103": eventdata = (event['EventData']['Data'][0]['#text']) score = subprocess.check_output("./freq.py -m \"" + eventdata + "\" english_mixedcase.freq", shell=True) if (float(score) < 5.0): print("\033[31m[-]\033[0m Likely obfuscated PowerShell!") print(" Freq.py score: \033[31m" + score.decode("utf-8") + "\033[0m") if len(eventdata) > 300: eventdata = eventdata[0:299] + "..." print(eventdata + "\n")
def main(): if len(sys.argv) != 2: usage() elif sys.argv[1] == 'h': # If too many arguments or 'h' is used call usage usage() args = sys.argv[1] winlog = open('win_eventlog.xml', 'w') # Prepair output file x = 'Script ran on: ' + ctime() winlog.write(x) x = '\n' winlog.write(x) try: with evtx.Evtx(args) as log: # Convert file and output results print(e_views.XML_HEADER) winlog.write(e_views.XML_HEADER) print("<Events>") winlog.write("<Events>") for record in log.records(): print(record.xml() + '\n') winlog.write(record.xml() + '\n') print("</Events>") winlog.write("</Events>") except: print 'Error!!!' usage() winlog.close()
def process_file(file_location): results_list = [] with evtx.Evtx(file_location) as log: for record in log.records(): results_list.append(dict(xmltodict.parse(record.xml()))) return results_list
def test_continue_parsing_after_corrupt_ascii(data_path): ''' regression test demonstrating issue 37. Args: data_path (str): the file system path of the test directory. ''' attempted = 0 completed = 0 failed = 0 with evtx.Evtx(os.path.join(data_path, 'dns_log_malformed.evtx')) as log: for chunk in log.chunks(): for record in chunk.records(): try: attempted += 1 assert record.xml() is not None completed += 1 except UnicodeDecodeError: failed += 1 # this small log file has exactly five records. assert attempted == 5 # the first record is valid. assert completed == 1 # however the remaining four have corrupted ASCII strings, # which we are unable to decode. assert failed == 4
def EventlogTotal(real_file_path, filename): result = [] eventlog_count = 0 with evtx.Evtx(filename) as log: for i, rec in enumerate(log.records()): try: xml_str = rec.xml() except: continue if xml_str != '': root = XML.fromstring(xml_str) # Event Tag assert len(XML._namespaces(root)) == 2 event_total_information = Eventlog_Total_Information() result.append(event_total_information) result[eventlog_count].event_id = root[0][1].text if 'TimeCreated' in root[0][5].tag: result[eventlog_count].time_created = root[0][5].get( 'SystemTime').replace(' ', 'T') + 'Z' else: result[eventlog_count].time_created = root[0][7].get( 'SystemTime').replace(' ', 'T') + 'Z' result[eventlog_count].user_sid = root[0][-1].get('UserID') result[eventlog_count].source = real_file_path result[eventlog_count].data = html.unescape(xml_str) eventlog_count = eventlog_count + 1 return result
def iter_evtx2xml(evtx_file): """ Generator function to read events from evtx file and convert to xml :param evtx_file: file path string :return: generator to xml string representation of evtx event """ global error_counter, event_counter error_counter = 0 event_counter = 0 try: with evtx.Evtx(evtx_file) as log: # process each log entry and return xml representation for record in log.records(): event_counter += 1 try: yield record.xml() except Exception as err: error_counter += 1 # logger.error("Failed to convert EVTX to XML for %s. Error count: %d" % (evtx_file, error_counter)) except Exception as err: raise if error_counter: CONSOLE( "[cyan][evtx2json][/cyan] Failed to read {} events.".format(error_counter) )
def on_click(self): textboxValue = self.textbox.text() whiteList = [4663,4656,4658,4660,4657,5039,4670,4608,4624] with evtx.Evtx(textboxValue) as log: record = log.get_record(self.counter) soup = BeautifulSoup(record.xml(),"html.parser") system_ = soup.find("system") # EventId Filter EventId = int(system_.find("eventid").text) print(EventId) for wlist in whiteList: if wlist == EventId: UrlPath = "https://docs.microsoft.com/ko-kr/windows/security/threat-protection/auditing/event-" + str( EventId) r = requests.get(UrlPath) html = r.content.decode() soup = BeautifulSoup(html, "html.parser") EventExplain = soup.find("main", {"id": "main"}) EventTitle = EventExplain.find("h1").text if "404" in EventTitle: pass else: self.textbox2.setText(str(wlist)+"\n"+EventTitle) else: pass self.counter = self.counter+1
def test_render_record(system): ''' regression test demonstrating formatting a record to xml. Args: system (bytes): the system.evtx test file contents. pytest fixture. ''' fh = evtx.FileHeader(system, 0x0) chunk = one(fh.chunks()) record = one(chunk.records()) xml = record.xml() assert xml == textwrap.dedent('''\ <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event"><System><Provider Name="Microsoft-Windows-Eventlog" Guid="{fc65ddd8-d6ef-4962-83d5-6e5cfe9ce148}"></Provider> <EventID Qualifiers="">105</EventID> <Version>0</Version> <Level>4</Level> <Task>105</Task> <Opcode>0</Opcode> <Keywords>0x8000000000000000</Keywords> <TimeCreated SystemTime="2012-03-14 04:17:43.354563"></TimeCreated> <EventRecordID>12049</EventRecordID> <Correlation ActivityID="" RelatedActivityID=""></Correlation> <Execution ProcessID="820" ThreadID="2868"></Execution> <Channel>System</Channel> <Computer>WKS-WIN764BITB.shieldbase.local</Computer> <Security UserID=""></Security> </System> <UserData><AutoBackup xmlns:auto-ns3="http://schemas.microsoft.com/win/2004/08/events" xmlns="http://manifests.microsoft.com/win/2004/08/windows/eventlog"><Channel>System</Channel> <BackupPath>C:\\Windows\\System32\\Winevt\\Logs\\Archive-System-2012-03-14-04-17-39-932.evtx</BackupPath> </AutoBackup> </UserData> </Event> ''')
def search(opts): with evtx.Evtx(opts.file.strip()) as log: for chunk in log.chunks(): for record in chunk.records(): xml = record.xml() pattern = opts.pattern.strip() if (pattern in xml): print(xml)
def evtxDumpFunc(evtxPath, xmlPath): # Function to convert an input .evtx file into an xml file # with open(xmlPath, 'w') as xmlFile: with evtx.Evtx(evtxPath) as log: xmlFile.write(e_views.XML_HEADER) xmlFile.write("<Events>") for record in log.records(): xmlFile.write(record.xml()) xmlFile.write("</Events>")
def evtx_parse(): file = 'Microsoft-Windows-DriverFrameworks-UserMode%4Operational.evtx' with evtx.Evtx(file) as log: id = 0 for record in log.records(): #print(dir(record)) with open(output_path + str(id) + '_record.xml', 'w') as fd: fd.write(record.xml()) id += 1
def corelation(): with evtx.Evtx(config['file']['path']) as rec: new = list(rec.records()) # print(len(new)) ind = 0 while (len(new) > ind): abx = convert_xml_to_json(new[ind].xml()) ind += 1 yield abx
def test_chunks2(security): ''' regression test parsing some known fields in the file chunks. Args: security (bytes): the security.evtx test file contents. pytest fixture. ''' fh = evtx.FileHeader(security, 0x0) # collected empirically expecteds = [ {'start_file': 1, 'end_file': 91, 'start_log': 1, 'end_log': 91}, {'start_file': 92, 'end_file': 177, 'start_log': 92, 'end_log': 177}, {'start_file': 178, 'end_file': 260, 'start_log': 178, 'end_log': 260}, {'start_file': 261, 'end_file': 349, 'start_log': 261, 'end_log': 349}, {'start_file': 350, 'end_file': 441, 'start_log': 350, 'end_log': 441}, {'start_file': 442, 'end_file': 530, 'start_log': 442, 'end_log': 530}, {'start_file': 531, 'end_file': 622, 'start_log': 531, 'end_log': 622}, {'start_file': 623, 'end_file': 711, 'start_log': 623, 'end_log': 711}, {'start_file': 712, 'end_file': 802, 'start_log': 712, 'end_log': 802}, {'start_file': 803, 'end_file': 888, 'start_log': 803, 'end_log': 888}, {'start_file': 889, 'end_file': 976, 'start_log': 889, 'end_log': 976}, {'start_file': 977, 'end_file': 1063, 'start_log': 977, 'end_log': 1063}, {'start_file': 1064, 'end_file': 1148, 'start_log': 1064, 'end_log': 1148}, {'start_file': 1149, 'end_file': 1239, 'start_log': 1149, 'end_log': 1239}, {'start_file': 1240, 'end_file': 1327, 'start_log': 1240, 'end_log': 1327}, {'start_file': 1328, 'end_file': 1414, 'start_log': 1328, 'end_log': 1414}, {'start_file': 1415, 'end_file': 1501, 'start_log': 1415, 'end_log': 1501}, {'start_file': 1502, 'end_file': 1587, 'start_log': 1502, 'end_log': 1587}, {'start_file': 1588, 'end_file': 1682, 'start_log': 1588, 'end_log': 1682}, {'start_file': 1683, 'end_file': 1766, 'start_log': 1683, 'end_log': 1766}, {'start_file': 1767, 'end_file': 1847, 'start_log': 1767, 'end_log': 1847}, {'start_file': 1848, 'end_file': 1942, 'start_log': 1848, 'end_log': 1942}, {'start_file': 1943, 'end_file': 2027, 'start_log': 1943, 'end_log': 2027}, {'start_file': 2028, 'end_file': 2109, 'start_log': 2028, 'end_log': 2109}, {'start_file': 2110, 'end_file': 2201, 'start_log': 2110, 'end_log': 2201}, {'start_file': 2202, 'end_file': 2261, 'start_log': 2202, 'end_log': 2261}, ] for i, chunk in enumerate(fh.chunks()): # collected empirically if i < 26: assert chunk.check_magic() is True assert chunk.magic() == 'ElfChnk\x00' assert chunk.calculate_header_checksum() == chunk.header_checksum() assert chunk.calculate_data_checksum() == chunk.data_checksum() expected = expecteds[i] assert chunk.file_first_record_number() == expected['start_file'] assert chunk.file_last_record_number() == expected['end_file'] assert chunk.log_first_record_number() == expected['start_log'] assert chunk.log_last_record_number() == expected['end_log'] else: assert chunk.check_magic() is False assert chunk.magic() == EMPTY_MAGIC
def get_xml_info(): for evt_buff in get_evt_buff(system_evt): fh = evtx.FileHeader(evt_buff, 0x0) for record_str, record in evtx_file_xml_view(fh): print record_str system = get_child(to_lxml(record_str.decode("gbk").encode("utf-8")), 'System') print get_child(system, 'EventID').text break
def main(): import argparse parser = argparse.ArgumentParser(description="Dump EVTX file into XML.") parser.add_argument("evtx", type=str, help="Path to the Windows EVTX file") args = parser.parse_args() with evtx.Evtx(args.evtx) as log: for record in log.records(): print(record.xml())
def test_issue_43(data_path): ''' regression test demonstrating issue 43. Args: data_path (str): the file system path of the test directory. ''' with evtx.Evtx(os.path.join(data_path, 'issue_43.evtx')) as log: bad_rec = get_record_by_num(log, 508) _ = bad_rec.xml()
def test_render_records_lxml2(security): ''' regression test demonstrating formatting records to xml. Args: security (bytes): the security.evtx test file contents. pytest fixture. ''' fh = evtx.FileHeader(security, 0x0) for i, chunk in enumerate(fh.chunks()): for j, record in enumerate(chunk.records()): assert record.lxml() is not None
def test_render_records(system): ''' regression test demonstrating formatting records to xml. Args: system (bytes): the system.evtx test file contents. pytest fixture. ''' fh = evtx.FileHeader(system, 0x0) for chunk in fh.chunks(): for record in chunk.records(): assert record.xml() is not None
def parse_evtx(opts): with open(save_directory + os.sep + os.path.split(opts.file)[1] + '.json', 'w')as outfile: #outfile.write(codecs.BOM_UTF8) with evtx.Evtx(opts.file.strip()) as log: for chunk in log.chunks(): for record in chunk.records(): xml = record.xml() xmlstr = xmltodict.parse(xml, encoding='utf-8') json.dump(xmlstr, outfile, skipkeys=True, ensure_ascii=False, separators=(',', ':'), encoding='utf-8', sort_keys=True) outfile.write('\n')
def main(f): try: with evtx.Evtx(f) as log: for record in log.records(): event = record.lxml() if event[0].find("{http://schemas.microsoft.com/win/2004/08/events/event}EventID").text == "4104": add_to_LOGS(event[0],event[1]) output_LOGS() except IOError: print("IOError. Check permissions and path to the file actually exists.") print(usage())
def get_events(input_file, parse_xml=False): """ Opens a Windows Event Log and returns XML information from the event record. """ with evtx.Evtx(input_file) as event_log: for record in event_log.records(): if parse_xml: yield record.lxml() else: yield record.xml()
def validate_log_files(file_list): # For a log file to be valid, it needs to have at least one # record, otherwise there's no point in processing it! bad_files = {} bad_files_count = 0 new_file_list = [] #Check to see if the evtx file is big enough to store data for file_path in file_list: MadeItThrough = True with open(file_path, "rb") as file: buffer = mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ) try: header = evtx.FileHeader( buffer, 0x0) #All evtx files will have to have a header if header.verify(): if header.first_chunk().first_record()._offset >= buffer.size( ): bad_files[bad_files_count] = {} bad_files[bad_files_count]['path'] = file_path bad_files[bad_files_count][ 'reason'] = "File is too small to contain valid records." bad_files_count = bad_files_count + 1 MadeItThrough = False else: bad_files[bad_files_count] = {} bad_files[bad_files_count]['path'] = file_path bad_files[bad_files_count][ 'reason'] = "Failed EVTX header verification." bad_files_count = bad_files_count + 1 MadeItThrough = False except Exception as e: bad_files[bad_files_count] = {} bad_files[bad_files_count]['path'] = file_path bad_files[bad_files_count][ 'reason'] = e.message + ": File may be corrupt, or there's something wrong with my code." bad_files_count = bad_files_count + 1 MadeItThrough = False if MadeItThrough == True: new_file_list.append(file_path) del buffer return_data = {} return_data['count'] = len(new_file_list) return_data['files_to_process'] = [] return_data['files_to_process'] = new_file_list return_data['errors'] = {} return_data['errors'] = bad_files return return_data
def test_parse_records2(security): ''' regression test demonstrating that all record metadata can be parsed. Args: security (bytes): the security.evtx test file contents. pytest fixture. ''' fh = evtx.FileHeader(security, 0x0) for i, chunk in enumerate(fh.chunks()): for j, record in enumerate(chunk.records()): assert record.magic() == 0x2a2a
def test_DeleteRecordStep(src_evtx_001, filter_single_record_without_res_template): wf = Workflow() step = DeleteRecordStep(filter_single_record_without_res_template) wf.add_step(step) wf.run(src_evtx_001[0], src_evtx_001[1]) with evtx.Evtx(src_evtx_001[1]) as output: fh = output.get_file_header() # check header assert fh.verify() is True
def get_events(input_file, parse_xml=False): # https://chapinb.com/python-forensics-handbook/ch03_event_logs.html#iterate-over-record-xml-data-evtx with evtx.Evtx(input_file) as event_log: for record in event_log.records(): if parse_xml: evtxXML = record.lxml() yield evtxXML else: evtxXML = record.xml() yield evtxXML