#!/usr/bin/env python # # Copyright Stefan Metzmacher 2011-2012 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # This is useful to sync passwords from an AD domain. # # $ # $ source4/scripting/devel/repl_cleartext_pwd.py \ # -Uadministrator%A1b2C3d4 \ # 172.31.9.219 DC=bla,DC=base /tmp/cookie cleartext_utf8 131085 displayName # # starting at usn[0] # dn: CN=Test User1,CN=Users,DC=bla,DC=base # cleartext_utf8: A1b2C3d4 # displayName:: VABlAHMAdAAgAFUAcwBlAHIAMQA= # # # up to usn[16449] # $ # $ source4/scripting/devel/repl_cleartext_pwd.py \ # -Uadministrator%A1b2C3d4 # 172.31.9.219 DC=bla,DC=base cookie_file cleartext_utf8 131085 displayName # # starting at usn[16449] # # up to usn[16449] # $ # import sys # Find right direction when running from source tree sys.path.insert(0, "bin/python") import samba.getopt as options from optparse import OptionParser from samba.dcerpc import drsuapi, drsblobs, misc from samba.ndr import ndr_pack, ndr_unpack, ndr_print import binascii import hashlib import Crypto.Cipher.ARC4 import struct import os from ldif import LDIFWriter class globals: def __init__(self): self.global_objs = {} self.ldif = LDIFWriter(sys.stdout) def add_attr(self, dn, attname, vals): if dn not in self.global_objs: self.global_objs[dn] = {} self.global_objs[dn][attname] = vals def print_all(self): for dn, obj in self.global_objs.items(): self.ldif.unparse(dn, obj) continue self.global_objs = {} ########### main code ########### if __name__ == "__main__": parser = OptionParser("repl_cleartext_pwd.py [options] server dn cookie_file cleartext_name [attid attname]") sambaopts = options.SambaOptions(parser) credopts = options.CredentialsOptions(parser) parser.add_option_group(credopts) (opts, args) = parser.parse_args() if len(args) < 4 or len(args) == 5: parser.error("more arguments required") server = args[0] dn = args[1] cookie_file = args[2] if len(cookie_file) == 0: cookie_file = None cleartext_name = args[3] if len(args) >= 5: attid = int(args[4]) attname = args[5] else: attid = -1 attname = None lp = sambaopts.get_loadparm() creds = credopts.get_credentials(lp) if not creds.authentication_requested(): parser.error("You must supply credentials") gls = globals() try: f = open(cookie_file, 'r') store_blob = f.read() f.close() store_hdr = store_blob[0:28] (store_version, \ store_dn_len, store_dn_ofs, \ store_hwm_len, store_hwm_ofs, \ store_utdv_len, store_utdv_ofs) = \ struct.unpack("= 20 confounder = spl_crypt[0:16] enc_buffer = spl_crypt[16:] m5 = hashlib.md5() m5.update(user_session_key) m5.update(confounder) enc_key = m5.digest() rc4 = Crypto.Cipher.ARC4.new(enc_key) plain_buffer = rc4.decrypt(enc_buffer) (crc32_v) = struct.unpack("