How to Convert Base64-Encoded objectSid to Human-Readable SID Format in Linux Using ldapsearch


2 views

In Active Directory environments, the objectSid attribute stores security identifiers (SIDs) in a binary format that's typically base64-encoded when retrieved via LDAP. The human-readable SID format (like S-1-5-21-1270179133-2928470170-2248674342-4324) is what administrators commonly work with.

Here's a complete solution to convert the base64-encoded objectSid to human-readable format on Linux:

#!/bin/bash
# Extract and decode objectSid
OBJECT_SID="AQUAAAAAAAUVAAAAPWW1S5rojK4mDAiG5BAAAA=="
echo $OBJECT_SID | base64 -d | xxd -ps -u | sed -e 's/$..$/\\x\1/g' | xargs -0 printf "%s" | xxd -ps -u | sed -e 's/^00//' -e 's/$........$$....$$....$$.*$/S-1-\1-\2-\3-\4/' -e 's/$..$$..$$..$$..$/\4\3\2\1/g' -e 's/$..$$..$/\2\1/g' -e 's/^/S-1-/' -e 's/-$[0-9A-F]\{8\}$/-\1/g' -e 's/$[0-9A-F]\{4\}$$/0x\1/g' | awk -F '-' '{for (i=2;i<=NF;i++) {if ($i ~ /^0x/) printf "-%d",strtonum($i); else printf "-%d",strtonum("0x"$i);} printf "\n";}'

The conversion involves several steps:

  1. Base64 decoding the objectSid
  2. Converting to hexadecimal representation
  3. Parsing the SID structure components
  4. Formatting into the human-readable SID string

For more maintainable code, here's a Python solution:

import base64
import struct

def convert_object_sid(object_sid):
    binary = base64.b64decode(object_sid)
    revision = struct.unpack('B', binary[0:1])[0]
    sub_authority_count = struct.unpack('B', binary[1:2])[0]
    identifier_authority = struct.unpack('>Q', b'\x00\x00' + binary[2:8])[0]
    sub_authorities = struct.unpack('<%dI' % sub_authority_count, binary[8:8+4*sub_authority_count])
    
    sid = 'S-%d-%d' % (revision, identifier_authority)
    for sub_authority in sub_authorities:
        sid += '-%d' % (sub_authority)
        
    return sid

# Example usage
print(convert_object_sid("AQUAAAAAAAUVAAAAPWW1S5rojK4mDAiG5BAAAA=="))

Here's how to combine this with your original ldapsearch command:

ldapsearch -LLL -H ldap://dc.example.com:389 -b dc=example,dc=lk -D example\\administrator -w adminPassword "(sAMAccountName=bob)" objectSid | awk '/objectSid::/ {print $2}' | base64 -d | xxd -ps -u | sed -e 's/$..$/\\x\1/g' | xargs -0 printf "%s" | xxd -ps -u | sed -e 's/^00//' -e 's/$........$$....$$....$$.*$/S-1-\1-\2-\3-\4/' -e 's/$..$$..$$..$$..$/\4\3\2\1/g' -e 's/$..$$..$/\2\1/g' -e 's/^/S-1-/' -e 's/-$[0-9A-F]\{8\}$/-\1/g' -e 's/$[0-9A-F]\{4\}$$/0x\1/g' | awk -F '-' '{for (i=2;i<=NF;i++) {if ($i ~ /^0x/) printf "-%d",strtonum($i); else printf "-%d",strtonum("0x"$i);} printf "\n";}'

When working with Active Directory through LDAP queries, you'll often encounter the objectSid attribute, which represents security identifiers in binary format. The challenge is converting this Base64-encoded value into the standard SID format (e.g., S-1-5-21-...) that administrators recognize.

A typical LDAP query might return something like:

objectSid:: AQUAAAAAAAUVAAAAPWW1S5rojK4mDAiG5BAAAA==

You'll need these Linux packages:

sudo apt-get install ldap-utils python3
pip install pyasn1

Here's a reliable Python solution:

import base64
import struct

def convert_binary_sid_to_string(binary_sid):
    version = struct.unpack('B', binary_sid[0:1])[0]
    sub_authority_count = struct.unpack('B', binary_sid[1:2])[0]
    identifier_authority = struct.unpack('>Q', b'\x00\x00' + binary_sid[2:8])[0]
    sub_authorities = struct.unpack('<' + 'L' * sub_authority_count, binary_sid[8:8 + 4 * sub_authority_count])
    sid = 'S-{0}-{1}'.format(version, identifier_authority)
    for sub_auth in sub_authorities:
        sid += '-{0}'.format(sub_auth)
    return sid

# Usage:
base64_sid = "AQUAAAAAAAUVAAAAPWW1S5rojK4mDAiG5BAAAA=="
binary_sid = base64.b64decode(base64_sid)
print(convert_binary_sid_to_string(binary_sid))

For quick conversions in shell:

echo "AQUAAAAAAAUVAAAAPWW1S5rojK4mDAiG5BAAAA==" | base64 -d | xxd -ps | sed -e 's/$..$/\1 /g' -e 's/^ //' | awk '{
    printf "S-%d", strtonum("0x" $1);
    printf "-%d", strtonum("0x" sprintf("%02s%02s%02s%02s%02s", $7, $6, $5, $4, $3, $2));
    for(i=8; i<=NF; i+=4) {
        printf "-%d", strtonum("0x" sprintf("%02s%02s%02s%02s", $(i+3), $(i+2), $(i+1), $i));
    }
    print "";
}'

Combine the conversion with your original query:

ldapsearch -LLL -H ldap://dc.example.com:389 -b dc=example,dc=com -D example\\administrator -w password "(sAMAccountName=bob)" | \
awk '/objectSid::/ {print $2}' | \
base64 -d | \
xxd -ps | \
sed -e 's/$..$/\1 /g' -e 's/^ //' | \
awk '{
    printf "S-%d", strtonum("0x" $1);
    printf "-%d", strtonum("0x" sprintf("%02s%02s%02s%02s%02s", $7, $6, $5, $4, $3, $2));
    for(i=8; i<=NF; i+=4) {
        printf "-%d", strtonum("0x" sprintf("%02s%02s%02s%02s", $(i+3), $(i+2), $(i+1), $i));
    }
    print "";
}'

Error: "Invalid base64 input"
Fix: Ensure the objectSid is properly extracted. Some LDAP outputs include spaces or line breaks.

Error: Incorrect SID format
Fix: Verify the byte ordering in your conversion script matches the SID structure specification.