#!/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] # $ # from __future__ import print_function 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 = {} def attid_equal(a1, a2): return (a1 & 0xffffffff) == (a2 & 0xffffffff) ########### main code ########### if __name__ == "__main__": parser = OptionParser("repl_cleartext_pwd.py [options] server dn cookie_file clear_utf8_name [attid attname attmode] [clear_utf16_name") sambaopts = options.SambaOptions(parser) credopts = options.CredentialsOptions(parser) parser.add_option_group(credopts) (opts, args) = parser.parse_args() if len(args) == 4: pass elif len(args) == 7: pass elif len(args) >= 8: pass else: parser.error("more arguments required - given=%d" % (len(args))) server = args[0] dn = args[1] cookie_file = args[2] if len(cookie_file) == 0: cookie_file = None clear_utf8_name = args[3] if len(args) >= 7: try: attid = int(args[4], 16) except Exception: attid = int(args[4]) attname = args[5] attmode = args[6] if attmode not in ["raw", "utf8"]: parser.error("attmode should be 'raw' or 'utf8'") else: attid = -1 attname = None attmode = "raw" if len(args) >= 8: clear_utf16_name = args[7] else: clear_utf16_name = 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("