Skip to content

Commit 21aad83

Browse files
committed
handle duplicate custom assembly error by deleting offending assembly and retrying creation
1 parent 284b6b3 commit 21aad83

3 files changed

Lines changed: 47 additions & 2 deletions

File tree

pysqlrecon/lib/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from typing import Any
33
from rich.table import Table
44

5+
from pysqlrecon.lib.exceptions import DuplicateAssemblyError
56
from pysqlrecon.logger import logger, console
67
from pysqlrecon.lib.sqlagent import SqlAgentMixin
78
from pysqlrecon.lib.clr import ClrMixin
@@ -11,6 +12,10 @@
1112

1213
class PySqlRecon(SqlAgentMixin, ClrMixin, ModuleMixin, QueryMixin):
1314

15+
# https://learn.microsoft.com/en-us/sql/relational-databases/errors-events/database-engine-events-and-errors-6000-to-6999?view=sql-server-ver16
16+
DUPLICATE_ASM_ERROR = 6285
17+
18+
1419
def __init__(self, target, domain, username, password, port, link, impersonate,
1520
db, hashes, aesKey, kerberos, no_pass, dc_ip, windows_auth) -> None:
1621

@@ -205,9 +210,15 @@ def print_replies(self) -> None:
205210
for keys in list(self.ms_sql.replies.keys()):
206211
for i, key in enumerate(self.ms_sql.replies[keys]):
207212
if key['TokenType'] == tds.TDS_ERROR_TOKEN:
213+
error_num = key['Number']
208214
error = "(%s): Line %d: %s" % (key['ServerName'].decode('utf-16le'), key['LineNumber'], key['MsgText'].decode('utf-16le'))
209215
self.lastError = tds.SQLErrorException("ERROR: Line %d: %s" % (key['LineNumber'], key['MsgText'].decode('utf-16le')))
210216
logger.error(error)
217+
218+
# handle duplicate assembly error
219+
if error_num == PySqlRecon.DUPLICATE_ASM_ERROR:
220+
raise DuplicateAssemblyError(error)
221+
211222
exit()
212223

213224
elif key['TokenType'] == tds.TDS_INFO_TOKEN:

pysqlrecon/lib/exceptions.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import re
2+
3+
4+
class DuplicateAssemblyError(Exception):
5+
"""
6+
Exception raised for creation of a CLR assembly that already exsists
7+
"""
8+
9+
def __init__(self, message):
10+
self.assembly_name = ""
11+
12+
# extract the name of the assembly from the message
13+
match = re.search(r'name "(.*?)"', message)
14+
if match:
15+
self.assembly_name = match.group(1)

pysqlrecon/modules/clr.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from pathlib import Path
55
from hashlib import sha512
66

7+
from pysqlrecon.lib.exceptions import DuplicateAssemblyError
78
from pysqlrecon.logger import logger
89
from pysqlrecon.lib import PySqlRecon
910

@@ -86,7 +87,8 @@ def main(
8687

8788
#####
8889
# Create the custom assembly
89-
pysqlrecon.create_asm(asm_name, dll_bytes)
90+
create_assembly(pysqlrecon, asm_name, dll_bytes, function)
91+
9092
if not pysqlrecon.check_assembly(asm_name):
9193
logger.error("Failed to create custom assembly")
9294
logger.info("Cleaning up...")
@@ -122,4 +124,21 @@ def main(
122124
pysqlrecon.delete_tasm_resources(asm_name, function)
123125

124126
pysqlrecon.disconnect()
125-
127+
128+
129+
# recursive func to create assembly and handle duplicate assmebly error by deleting and re-creating
130+
# fix for https://github.com/Tw1sm/PySQLRecon/issues/1
131+
def create_assembly(pysqlrecon, asm_name, dll_bytes, function):
132+
try:
133+
pysqlrecon.create_asm(asm_name, dll_bytes)
134+
135+
except DuplicateAssemblyError as e:
136+
logger.warning("Duplicate assembly detected - will try to delete and re-create")
137+
138+
pysqlrecon.delete_tasm_resources(e.assembly_name, function)
139+
logger.info(f"Deleted the offending duplicate assembly '{e.assembly_name}'")
140+
141+
logger.info(f"Attempting to re-create assembly with name '{asm_name}'")
142+
pysqlrecon.create_asm(asm_name, dll_bytes)
143+
144+

0 commit comments

Comments
 (0)