mirror of
https://github.com/Pennyw0rth/NetExec.git
synced 2026-11-07 09:26:01 -10:00
215 lines
7.7 KiB
Python
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()
|