|
| 1 | +import argparse |
| 2 | +import binascii |
| 3 | +import datetime |
| 4 | +import random |
| 5 | +import socket |
| 6 | +import string |
| 7 | +import struct |
| 8 | +import sys |
| 9 | +import uuid |
| 10 | +import filetimes, rpcBind, rpcRequest |
| 11 | + |
| 12 | +from dcerpc import MSRPCHeader, MSRPCBindNak |
| 13 | +from rpcBase import rpcBase |
| 14 | + |
| 15 | +config = {} |
| 16 | + |
| 17 | +def main(): |
| 18 | + parser = argparse.ArgumentParser() |
| 19 | + parser.add_argument("ip", action="store", help="The IP address or hostname of the KMS host.", type=str) |
| 20 | + parser.add_argument("port", nargs="?", action="store", default=1688, help="The port the KMS service is listening on. The default is \"1688\".", type=int) |
| 21 | + parser.add_argument("-m", "--mode", dest="mode", choices=["WindowsVista","Windows7","Windows8","Windows81","Office2010","Office2013"], default="Windows7") |
| 22 | + parser.add_argument("-v", "--verbose", dest="verbose", action="store_const", const=True, default=False, help="Enable this flag to turn on verbose output.") |
| 23 | + parser.add_argument("-d", "--debug", dest="debug", action="store_const", const=True, default=False, help="Enable this flag to turn on debug output. Implies \"-v\".") |
| 24 | + config.update(vars(parser.parse_args())) |
| 25 | + config['call_id'] = 1 |
| 26 | + if config['debug']: |
| 27 | + config['verbose'] = True |
| 28 | + updateConfig() |
| 29 | + s = socket.socket() |
| 30 | + print "Connecting to %s on port %d..." % (config['ip'], config['port']) |
| 31 | + s.connect((config['ip'], config['port'])) |
| 32 | + if config['verbose']: |
| 33 | + print "Connection successful!" |
| 34 | + binder = rpcBind.bind('', config) |
| 35 | + RPC_Bind = str(binder.generateRequest()) |
| 36 | + if config['verbose']: |
| 37 | + print "Sending RPC bind request..." |
| 38 | + s.send(RPC_Bind) |
| 39 | + try: |
| 40 | + bindResponse = s.recv(1024) |
| 41 | + except socket.error, e: |
| 42 | + if e[0] == 104: |
| 43 | + print "Error: Connection reset by peer. Exiting..." |
| 44 | + sys.exit() |
| 45 | + else: |
| 46 | + raise |
| 47 | + if bindResponse == '' or not bindResponse: |
| 48 | + print "No data received! Exiting..." |
| 49 | + sys.exit() |
| 50 | + packetType = MSRPCHeader(bindResponse)['type'] |
| 51 | + if packetType == rpcBase.packetType['bindAck']: |
| 52 | + if config['verbose']: |
| 53 | + print "RPC bind acknowledged." |
| 54 | + #config['call_id'] += 1 |
| 55 | + ''' |
| 56 | + request = CreateRequest() |
| 57 | + requester = rpcRequest.request(request, config) |
| 58 | + s.send(request) |
| 59 | + response = s.recv(1024) |
| 60 | + if config['debug']: |
| 61 | + print "Response:", binascii.b2a_hex(response), len(response) |
| 62 | + parsed = ReadResponse(response) |
| 63 | + ''' |
| 64 | + elif packetType == rpcBase.packetType['bindNak']: |
| 65 | + print MSRPCBindNak(bindResponse).dump() |
| 66 | + sys.exit() |
| 67 | + else: |
| 68 | + print "Something went wrong." |
| 69 | + sys.exit() |
| 70 | + |
| 71 | +def updateConfig(): |
| 72 | + if config['mode'] == 'WindowsVista': |
| 73 | + config['RequiredClientCount'] = 25 |
| 74 | + config['KMSProtocolMajorVersion'] = 4 |
| 75 | + config['KMSProtocolMinorVersion'] = 0 |
| 76 | + config['KMSClientLicenseStatus'] = 2 |
| 77 | + config['KMSClientAppID'] = "55c92734-d682-4d71-983e-d6ec3f16059f" |
| 78 | + config['KMSClientSkuID'] = "cfd8ff08-c0d7-452b-9f60-ef5c70c32094" |
| 79 | + config['KMSClientKMSCountedID'] = "212a64dc-43b1-4d3d-a30c-2fc69d2095c6" |
| 80 | + elif config['mode'] == 'Windows7': |
| 81 | + config['RequiredClientCount'] = 25 |
| 82 | + config['KMSProtocolMajorVersion'] = 4 |
| 83 | + config['KMSProtocolMinorVersion'] = 0 |
| 84 | + config['KMSClientLicenseStatus'] = 2 |
| 85 | + config['KMSClientAppID'] = "55c92734-d682-4d71-983e-d6ec3f16059f" |
| 86 | + config['KMSClientSkuID'] = "ae2ee509-1b34-41c0-acb7-6d4650168915" |
| 87 | + config['KMSClientKMSCountedID'] = "7fde5219-fbfa-484a-82c9-34d1ad53e856" |
| 88 | + elif config['mode'] == 'Windows8': |
| 89 | + config['RequiredClientCount'] = 25 |
| 90 | + config['KMSProtocolMajorVersion'] = 5 |
| 91 | + config['KMSProtocolMinorVersion'] = 0 |
| 92 | + config['KMSClientLicenseStatus'] = 2 |
| 93 | + config['KMSClientAppID'] = "55c92734-d682-4d71-983e-d6ec3f16059f" |
| 94 | + config['KMSClientSkuID'] = "458e1bec-837a-45f6-b9d5-925ed5d299de" |
| 95 | + config['KMSClientKMSCountedID'] = "3c40b358-5948-45af-923b-53d21fcc7e79" |
| 96 | + elif config['mode'] == 'Windows81': |
| 97 | + config['RequiredClientCount'] = 25 |
| 98 | + config['KMSProtocolMajorVersion'] = 6 |
| 99 | + config['KMSProtocolMinorVersion'] = 0 |
| 100 | + config['KMSClientLicenseStatus'] = 2 |
| 101 | + config['KMSClientAppID'] = "55c92734-d682-4d71-983e-d6ec3f16059f" |
| 102 | + config['KMSClientSkuID'] = "81671aaf-79d1-4eb1-b004-8cbbe173afea" |
| 103 | + config['KMSClientKMSCountedID'] = "cb8fc780-2c05-495a-9710-85afffc904d7" |
| 104 | + elif config['mode'] == 'Office2010': |
| 105 | + config['RequiredClientCount'] = 5 |
| 106 | + config['KMSProtocolMajorVersion'] = 4 |
| 107 | + config['KMSProtocolMinorVersion'] = 0 |
| 108 | + config['KMSClientLicenseStatus'] = 2 |
| 109 | + config['KMSClientAppID'] = "59a52881-a989-479d-af46-f275c6370663" |
| 110 | + config['KMSClientSkuID'] = "6f327760-8c5c-417c-9b61-836a98287e0c" |
| 111 | + config['KMSClientKMSCountedID'] = "e85af946-2e25-47b7-83e1-bebcebeac611" |
| 112 | + elif config['mode'] == 'Office2013': |
| 113 | + config['RequiredClientCount'] = 5 |
| 114 | + config['KMSProtocolMajorVersion'] = 5 |
| 115 | + config['KMSProtocolMinorVersion'] = 0 |
| 116 | + config['KMSClientLicenseStatus'] = 2 |
| 117 | + config['KMSClientAppID'] = "0ff1ce15-a989-479d-af46-f275c6370663" |
| 118 | + config['KMSClientSkuID'] = "b322da9c-a2e2-4058-9e4e-f59a6970bd69" |
| 119 | + config['KMSClientKMSCountedID'] = "e6a6f1bf-9d40-40c3-aa9f-c77ba21578c0" |
| 120 | + |
| 121 | +def CreateRequestBase(): |
| 122 | + # Init requestDict |
| 123 | + requestDict = {} |
| 124 | + |
| 125 | + # KMS Protocol Version |
| 126 | + requestDict['MajorVer'] = config['KMSProtocolMajorVersion'] |
| 127 | + requestDict['MinorVer'] = config['KMSProtocolMinorVersion'] |
| 128 | + |
| 129 | + # KMS Client is NOT a VM |
| 130 | + requestDict['IsClientVM'] = 0 |
| 131 | + |
| 132 | + # License Status |
| 133 | + requestDict['LicenseStatus'] = config['KMSClientLicenseStatus'] |
| 134 | + |
| 135 | + # Grace Time |
| 136 | + requestDict['GraceTime'] = 43200 |
| 137 | + |
| 138 | + # Application ID |
| 139 | + requestDict['ApplicationId'] = uuid.UUID(config['KMSClientAppID']) |
| 140 | + |
| 141 | + # SKU ID |
| 142 | + requestDict['SkuId'] = uuid.UUID(config['KMSClientSkuID']) |
| 143 | + |
| 144 | + # KMS Counted ID |
| 145 | + requestDict['KmsCountedId'] = uuid.UUID(config['KMSClientKMSCountedID']) |
| 146 | + |
| 147 | + # CMID |
| 148 | + requestDict['ClientMachineId'] = uuid.uuid4() |
| 149 | + |
| 150 | + # Minimum Clients |
| 151 | + requestDict['RequiredClientCount'] = config['RequiredClientCount'] |
| 152 | + |
| 153 | + # Current Time |
| 154 | + requestDict['RequestTime'] = filetimes.dt_to_filetime(datetime.datetime.utcnow()) |
| 155 | + |
| 156 | + # Generate Random Machine Name (Up to 63 Characters) |
| 157 | + requestDict['MachineName'] = ''.join(random.choice(string.letters + string.digits) for i in range(32)) |
| 158 | + |
| 159 | + # Debug Stuff |
| 160 | + if config['debug']: |
| 161 | + print "Request Base Dictionary:", requestDict |
| 162 | + |
| 163 | + request = str() |
| 164 | + request += struct.pack('<H', requestDict['MinorVer']) |
| 165 | + request += struct.pack('<H', requestDict['MajorVer']) |
| 166 | + request += struct.pack('<I', requestDict['IsClientVM']) |
| 167 | + request += struct.pack('<I', requestDict['LicenseStatus']) |
| 168 | + request += struct.pack('<I', requestDict['GraceTime']) |
| 169 | + request += requestDict['ApplicationId'].bytes_le |
| 170 | + request += requestDict['SkuId'].bytes_le |
| 171 | + request += requestDict['KmsCountedId'].bytes_le |
| 172 | + request += requestDict['ClientMachineId'].bytes_le |
| 173 | + request += struct.pack('<I', requestDict['RequiredClientCount']) |
| 174 | + request += struct.pack('>Q', requestDict['RequestTime']) |
| 175 | + request += requestDict['ClientMachineId'].bytes_le |
| 176 | + request += requestDict['MachineName'].encode('utf-16le') |
| 177 | + request += ('\0' * 32).encode('utf-16le') |
| 178 | + if config['debug']: |
| 179 | + print "Request Base:", binascii.b2a_hex(request), len(request) |
| 180 | + |
| 181 | + return request |
| 182 | + |
| 183 | +def CreateRequestV4(): |
| 184 | + # Update the call ID |
| 185 | + config['call_id'] += 1 |
| 186 | + |
| 187 | + # Create KMS Client Request Base |
| 188 | + requestBase = CreateRequestBase() |
| 189 | + |
| 190 | + # Create Hash |
| 191 | + hashed = str(kmsRequestV4.main(bytearray(requestBase))) |
| 192 | + |
| 193 | + # Generate Request |
| 194 | + bodyLength = len(requestBase) + len(hashed) |
| 195 | + if bodyLength % 8 == 0: |
| 196 | + paddingLength = 0 |
| 197 | + else: |
| 198 | + paddingLength = 8 - bodyLength % 8 |
| 199 | + v4Data = { |
| 200 | + "BodyLength" : bodyLength, |
| 201 | + "BodyLength2" : bodyLength, |
| 202 | + "Hash" : hashed, |
| 203 | + "Padding" : str(bytearray(functions.arrayFill([], paddingLength, 0x00))) |
| 204 | + } |
| 205 | + if config['debug']: |
| 206 | + print "Request V4 Data:", v4Data |
| 207 | + request = str() |
| 208 | + request += struct.pack('<I',v4Data["BodyLength"]) |
| 209 | + request += struct.pack('<I',v4Data["BodyLength2"]) |
| 210 | + request += requestBase |
| 211 | + request += v4Data["Hash"] |
| 212 | + request += v4Data["Padding"] |
| 213 | + if config['debug']: |
| 214 | + print "Request V4:", binascii.b2a_hex(request), len(request) |
| 215 | + |
| 216 | + return request |
| 217 | + |
| 218 | +def CreateRequestV5(): |
| 219 | + # Update the call ID |
| 220 | + config['call_id'] += 1 |
| 221 | + |
| 222 | + # Generate a Random Salt Key |
| 223 | + randomSalt = bytearray(random.getrandbits(8) for i in range(16)) |
| 224 | + |
| 225 | + # Set KMS Client Request Base |
| 226 | + requestBase = CreateRequestBase(); |
| 227 | + |
| 228 | + ''' |
| 229 | + # AES-128 Encrypt |
| 230 | + ENC = 1 |
| 231 | + DEC = 0 |
| 232 | + key = bytearray([ 0xCD, 0x7E, 0x79, 0x6F, 0x2A, 0xB2, 0x5D, 0xCB, 0x55, 0xFF, 0xC8, 0xEF, 0x83, 0x64, 0xC4, 0x70 ]) |
| 233 | + cipher = M2Crypto.EVP.Cipher(alg='aes_128_cbc', key=str(key), iv=str(randomSalt), op=ENC) |
| 234 | + crypted = cipher.update(requestBase) |
| 235 | + ''' |
| 236 | + |
| 237 | + # Generate Request |
| 238 | + bodyLength = 4 + len(randomSalt) + len(crypted) |
| 239 | + if bodyLength % 8 == 0: |
| 240 | + paddingLength = 0 |
| 241 | + else: |
| 242 | + paddingLength = 8 - bodyLength % 8 |
| 243 | + v5Data = { |
| 244 | + "Version" : 5, |
| 245 | + "BodyLength" : bodyLength, |
| 246 | + "BodyLength2" : bodyLength, |
| 247 | + "Encrypted" : crypted, |
| 248 | + "Padding" : str(bytearray(functions.arrayFill(bytearray(), paddingLength, 0x00))) |
| 249 | + } |
| 250 | + if config['debug']: |
| 251 | + print "Request V5 Data:", v5Data |
| 252 | + request = str() |
| 253 | + request += struct.pack('<I',v5Data["BodyLength"]) |
| 254 | + request += struct.pack('<I',v5Data["BodyLength2"]) |
| 255 | + request += struct.pack('<H',0) |
| 256 | + request += struct.pack('<H',v5Data["Version"]) |
| 257 | + request += randomSalt |
| 258 | + request += crypted |
| 259 | + request += v5Data["Padding"] |
| 260 | + if config['debug']: |
| 261 | + print "Request V5:", binascii.b2a_hex(request), len(request) |
| 262 | + |
| 263 | + # Return Request |
| 264 | + return request |
| 265 | + |
| 266 | +def CreateRequest(): |
| 267 | + # KMS Protocol Major Version |
| 268 | + if config['KMSProtocolMajorVersion'] == 4: |
| 269 | + request = CreateRequestV4() |
| 270 | + elif config['KMSProtocolMajorVersion'] == 5: |
| 271 | + request = CreateRequestV5() |
| 272 | + else: |
| 273 | + return None |
| 274 | + return RPCMessageWrapper(request) |
| 275 | + |
| 276 | +def RPCMessageWrapper(request): |
| 277 | + # Create the dictionary of data |
| 278 | + wrapperDict = {} |
| 279 | + wrapperDict['Version'] = '\x05' |
| 280 | + wrapperDict['VersionMinor'] = '\x00' |
| 281 | + wrapperDict['PacketType'] = '\x00' |
| 282 | + wrapperDict['PacketFlags'] = '\x03' |
| 283 | + wrapperDict['DataRepresentation'] = struct.pack('<I', 0x10) |
| 284 | + wrapperDict['FragLength'] = struct.pack('<H', len(request) + 24) |
| 285 | + wrapperDict['AuthLength'] = struct.pack('<H', 0) |
| 286 | + wrapperDict['CallId'] = struct.pack('<I', config['call_id']) |
| 287 | + wrapperDict['AllocHint'] = struct.pack('<I', len(request)) |
| 288 | + wrapperDict['ContextId'] = struct.pack('<H', 0) |
| 289 | + wrapperDict['Opnum'] = struct.pack('<H', 0) |
| 290 | + if config['debug']: |
| 291 | + print "RPC Wrapper Dictionary:", wrapperDict |
| 292 | + |
| 293 | + wrapper = str() |
| 294 | + wrapper += wrapperDict['Version'] |
| 295 | + wrapper += wrapperDict['VersionMinor'] |
| 296 | + wrapper += wrapperDict['PacketType'] |
| 297 | + wrapper += wrapperDict['PacketFlags'] |
| 298 | + wrapper += wrapperDict['DataRepresentation'] |
| 299 | + wrapper += wrapperDict['FragLength'] |
| 300 | + wrapper += wrapperDict['AuthLength'] |
| 301 | + wrapper += wrapperDict['CallId'] |
| 302 | + wrapper += wrapperDict['AllocHint'] |
| 303 | + wrapper += wrapperDict['ContextId'] |
| 304 | + wrapper += wrapperDict['Opnum'] |
| 305 | + wrapper += request |
| 306 | + if config['debug']: |
| 307 | + print "Wrapped Request:", binascii.b2a_hex(wrapper), len(wrapper) |
| 308 | + |
| 309 | + # Return the wrapped request |
| 310 | + return wrapper |
| 311 | + |
| 312 | +def ReadResponse(data): |
| 313 | + unknownDataSize = 8 |
| 314 | + version1 = data[unknownDataSize + 2] |
| 315 | + version2 = data[unknownDataSize + 0] |
| 316 | + |
| 317 | + if version1 == 4 and version2 == 0: |
| 318 | + print "Received V4 response" |
| 319 | + response = ReadResponseV4(data) |
| 320 | + elif version1 == 5 and version2 == 0: |
| 321 | + print "Received V5 response" |
| 322 | + response = ReadResponseV5(data) |
| 323 | + else: |
| 324 | + print "Unhandled response version", version1 |
| 325 | + return response |
| 326 | + |
| 327 | +def ReadResponseV4(data): |
| 328 | + responseDict = {} |
| 329 | + return responseDict |
| 330 | + |
| 331 | +def ReadResponseV5(data): |
| 332 | + responseDict = {} |
| 333 | + return responseDict |
| 334 | + |
| 335 | +if __name__ == "__main__": |
| 336 | + main() |
0 commit comments