Files
NetExec/nxc/helpers/even6_parser.py
T
danwroy 08fb634d7d print to display in helpers/modules, restored version print in cli
even6_parser, pfx, get-network
Database-related modules left alone
2025-10-26 23:31:06 -07:00

215 lines
7.7 KiB
Python

# SPDX-License-Identifier: GPL-2.0+
import struct
import uuid
from datetime import datetime
from nxc.logger import nxc_logger
class Substitution:
def __init__(self, buf, offset):
(sub_token, sub_id, sub_type) = struct.unpack_from("<BHB", buf, offset)
self.length = 4
self._id = sub_id
self._type = sub_type
self._optional = sub_token == 0x0e
def xml(self, template=None):
value = template.values[self._id]
if value.type == 0x0:
return None if self._optional else ""
if self._type == 0x1:
return value.data.decode("utf16")
elif self._type == 0x4:
return str(struct.unpack("<B", value.data)[0])
elif self._type == 0x6:
return str(struct.unpack("<H", value.data)[0])
elif self._type == 0x8:
return str(struct.unpack("<I", value.data)[0])
elif self._type == 0xa:
return str(struct.unpack("<Q", value.data)[0])
elif self._type == 0x11:
# see http://integriography.wordpress.com/2010/01/16/using-phython-to-parse-and-present-windows-64-bit-timestamps/
return datetime.utcfromtimestamp(struct.unpack("<Q", value.data)[0] / 1e7 - 11644473600).isoformat()
elif self._type == 0x13:
# see http://www.gossamer-threads.com/lists/apache/bugs/386930
revision, number_of_sub_ids = struct.unpack_from("<BB", value.data)
iav = struct.unpack_from(">Q", value.data, 2)[0]
sub_ids = [struct.unpack("<I", value.data[8 + 4 * i:12 + 4 * i])[0] for i in range(number_of_sub_ids)]
return "S-{}-{}-{}".format(revision, iav, "-".join([str(sub_id) for sub_id in sub_ids]))
elif self._type == 0x15 or self._type == 0x10:
return value.data.hex()
elif self._type == 0x21:
return value.template.xml()
elif self._type == 0xf:
return str(uuid.UUID(bytes_le=value.data))
else:
nxc_logger.display(f"Unknown value type {hex(value.type)}")
class Value:
def __init__(self, buf, offset):
token, string_type, length = struct.unpack_from("<BBH", buf, offset)
self._val = buf[offset + 4:offset + 4 + length * 2].decode("utf16")
self.length = 4 + length * 2
def xml(self, template=None):
return self._val
class Attribute:
def __init__(self, buf, offset):
struct.unpack_from("<B", buf, offset)
self._name = Name(buf, offset + 1)
(next_token) = struct.unpack_from("<B", buf, offset + 1 + self._name.length)
if next_token[0] == 0x05 or next_token == 0x45:
self._value = Value(buf, offset + 1 + self._name.length)
elif next_token[0] == 0x0e:
self._value = Substitution(buf, offset + 1 + self._name.length)
else:
nxc_logger.display(f"Unknown attribute next_token {hex(next_token[0])} {hex(offset + 1 + self._name.length)}")
self.length = 1 + self._name.length + self._value.length
def xml(self, template=None):
val = self._value.xml(template)
return None if val is None else f'{self._name.val}="{val}"'
class Name:
def __init__(self, buf, offset):
hashs, length = struct.unpack_from("<HH", buf, offset)
self.val = buf[offset + 4:offset + 4 + length * 2].decode("utf16")
self.length = 4 + (length + 1) * 2
class Element:
def __init__(self, buf, offset):
token, dependency_id, length = struct.unpack_from("<BHI", buf, offset)
self._name = Name(buf, offset + 7)
self._dependency = dependency_id
ofs = offset + 7 + self._name.length
if token == 0x41:
struct.unpack_from("<I", buf, ofs)
ofs += 4
self._children = []
self._attributes = []
while True:
next_token = buf[ofs]
if next_token == 0x06 or next_token == 0x46:
attr = Attribute(buf, ofs)
self._attributes.append(attr)
ofs += attr.length
elif next_token == 0x02:
self._empty = False
ofs += 1
while True:
next_token = buf[ofs]
if next_token == 0x01 or next_token == 0x41:
element = Element(buf, ofs)
elif next_token == 0x04:
ofs += 1
break
elif next_token == 0x05:
element = Value(buf, ofs)
elif next_token == 0x0e or next_token == 0x0d:
element = Substitution(buf, ofs)
else:
nxc_logger.display(f"Unknown intern next_token {hex(next_token)} {hex(ofs)}")
break
self._children.append(element)
ofs += element.length
break
elif next_token == 0x03:
self._empty = True
ofs += 1
break
else:
nxc_logger.display(f"Unknown element next_token {hex(next_token)} {hex(ofs)}")
break
self.length = ofs - offset
def xml(self, template=None):
if self._dependency != 0xFFFF and template.values[self._dependency].type == 0x00:
return ""
attrs = filter(lambda x: x is not None, (x.xml(template) for x in self._attributes))
attrs = " ".join(attrs)
if len(attrs) > 0:
attrs = " " + attrs
if self._empty:
return f"<{self._name.val}{attrs}/>"
else:
children = (x.xml(template) for x in self._children)
return "<{}{}>{}</{}>".format(self._name.val, attrs, "".join(children), self._name.val)
class ValueSpec:
def __init__(self, buf, offset, value_offset):
self.length, self.type, value_eof = struct.unpack_from("<HBB", buf, offset)
self.data = buf[value_offset:value_offset + self.length]
if self.type == 0x21:
self.template = BinXML(buf, value_offset)
class TemplateInstance:
def __init__(self, buf, offset):
token, unknown0, guid, length, next_token = struct.unpack_from("<BB16sIB", buf, offset)
if next_token == 0x0F:
self._xml = BinXML(buf, offset + 0x16)
eof, num_values = struct.unpack_from("<BI", buf, offset + 22 + self._xml.length)
values_length = 0
self.values = []
for x in range(num_values):
value = ValueSpec(buf, offset + 22 + self._xml.length + 5 + x * 4, offset + 22 + self._xml.length + 5 + num_values * 4 + values_length)
self.values.append(value)
values_length += value.length
self.length = 22 + self._xml.length + 5 + num_values * 4 + values_length
else:
nxc_logger.display(f"Unknown template token {hex(next_token)}")
def xml(self, template=None):
return self._xml.xml(self)
class BinXML:
def __init__(self, buf, offset):
header_token, major_version, minor_version, flags, next_token = struct.unpack_from("<BBBBB", buf, offset)
if next_token == 0x0C:
self._element = TemplateInstance(buf, offset + 4)
elif next_token == 0x01 or next_token == 0x41:
self._element = Element(buf, offset + 4)
else:
nxc_logger.display(f"Unknown binxml token {hex(next_token)}")
self.length = 4 + self._element.length
def xml(self, template=None):
return self._element.xml(template)
class ResultSet:
def __init__(self, buf):
total_size, header_size, event_offset, bookmark_offset, binxml_size = struct.unpack_from("<IIIII", buf)
self._xml = BinXML(buf, 0x14)
def xml(self):
return self._xml.xml()