1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
| import subprocess, hashlib, hmac, struct, base64, xml.etree.ElementTree as ET, re from ntlm_auth.ntlm import SessionSecurity
TSHARK = r"C:\Users\27728\Desktop\ctf-tools\flow analysis\CTF-NetA-V2.12.01-crack\CTF-NetA-V2.12.01\plugins\Wireshark\tshark.exe" PCAP = '1-pth.pcapng' password = "pass@word1" def get_nt_hash(password): # 1. 转换为 UTF-16LE 编码 # 2. 计算 MD4 哈希 nt_hash = hashlib.new('md4', password.encode('utf-16le')).digest() return nt_hash.hex()
NT_HASH = bytes.fromhex(get_nt_hash(password)) NEGOTIATE_FLAGS = 0xe2888235 SESSIONS = [ {'name':'stream4','stream':4,'username':'administrator','domain':'pc','ntproofstr':'3fa965e4d9af9a92bde5cefcdd309acb','enc_session_key':'61b54d6014e72b71a599bbdd677c4458'}, {'name':'stream5','stream':5,'username':'administrator','domain':'pc','ntproofstr':'eac0fa03a412b0a3d029dcea2a386231','enc_session_key':'e77cd0055bd64e5fe587c45a01145321'}, {'name':'stream9','stream':9,'username':'administrator','domain':'pc','ntproofstr':'74a74f048964fa4a31781a5f55d4aed9','enc_session_key':'d3b900336d18e709f9e846cadd818481'}, ] NS={ 's':'http://www.w3.org/2003/05/soap-envelope', 'a':'http://schemas.xmlsoap.org/ws/2004/08/addressing', 'w':'http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd', 'rsp':'http://schemas.microsoft.com/wbem/wsman/1/windows/shell', 'p':'http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd', }
class RC4: def __init__(self, key): self.S=list(range(256)); j=0 for i in range(256): j=(j+self.S[i]+key[i%len(key)])%256 self.S[i],self.S[j]=self.S[j],self.S[i] self.i=0; self.j=0 def crypt(self,data): out=bytearray() for byte in data: self.i=(self.i+1)%256 self.j=(self.j+self.S[self.i])%256 self.S[self.i],self.S[self.j]=self.S[self.j],self.S[self.i] k=self.S[(self.S[self.i]+self.S[self.j])%256] out.append(byte^k) return bytes(out)
def hmac_md5(key, data): return hmac.new(key,data,hashlib.md5).digest()
def exported_key(user, domain, ntproof, enc_sess): resp_key = hmac_md5(NT_HASH, (user.upper()+domain).encode('utf-16-le')) sess_base = hmac_md5(resp_key, bytes.fromhex(ntproof)) return RC4(sess_base).crypt(bytes.fromhex(enc_sess))
def extract_stream_data(stream): cmd=[TSHARK,'-r',PCAP,'-Y',f'tcp.stream=={stream} and tcp.len>0','-T','fields','-e','ip.src','-e','tcp.payload'] res=subprocess.run(cmd,capture_output=True,text=True) client=bytearray(); server=bytearray() for line in res.stdout.splitlines(): if not line.strip(): continue parts=line.split('\t') if len(parts)<2 or not parts[1]: continue try: data=bytes.fromhex(parts[1].replace(':','"''"')) except Exception: continue if parts[0]=='10.10.10.80': client.extend(data) else: server.extend(data) return bytes(client), bytes(server)
def extract_messages(data): msgs=[] markers=[b'Content-Type: application/octet-stream\r\n\r\n', b'Content-Type: application/octet-stream\r\n'] pos=0 while True: found=[] for m in markers: idx=data.find(m,pos) if idx!=-1: found.append((idx,m)) if not found: break idx, marker = min(found, key=lambda x:x[0]) start=idx+len(marker) while data[start:start+2]==b'\r\n': start+=2 end=data.find(b'--Encrypted Boundary', start) if end==-1: break payload=data[start:end] if payload.endswith(b'\r\n'): payload=payload[:-2] msgs.append(payload) pos=end+1 return msgs
def unwrap_msgs(msgs, ek, source): ss = SessionSecurity(NEGOTIATE_FLAGS, ek, source=source) out=[] for i,p in enumerate(msgs): siglen=struct.unpack('<I',p[:4])[0] sig=p[4:20] if siglen==16 else p[:16] enc=p[20:] if siglen==16 else p[16:] try: dec=ss.unwrap(enc,sig) out.append((i,dec,None)) except Exception as e: out.append((i,None,e)) return out
def decode_stream_text(text): try: return base64.b64decode(text).decode('gbk', errors='replace') except Exception: try: return base64.b64decode(text).decode('utf-8', errors='replace') except Exception: return text
for s in SESSIONS: ek=exported_key(s['username'],s['domain'],s['ntproofstr'],s['enc_session_key']) cli_raw, srv_raw = extract_stream_data(s['stream']) cli = unwrap_msgs(extract_messages(cli_raw), ek, 'server') srv = unwrap_msgs(extract_messages(srv_raw), ek, 'client') print('\n'+'='*30, s['name'], '='*30) for label, seq in [('CLIENT',cli),('SERVER',srv)]: print('\n--',label,'--') for idx,dec,err in seq: if err: print(f'[{idx}] ERROR {err}') continue text=dec.decode('utf-8','replace') root=ET.fromstring(text) action = root.find('.//a:Action', NS) if action is not None: print(f'[{idx}] Action:', action.text.split('/')[-1]) cmd = root.find('.//rsp:CommandLine/rsp:Command', NS) if cmd is not None: print(' Command:', cmd.text) args=root.findall('.//rsp:CommandLine/rsp:Arguments', NS) if args: print(' Args:', ' | '.join(a.text or '"''"' for a in args)) for st in root.findall('.//rsp:Stream', NS): nm=st.attrib.get('Name') end=st.attrib.get('End') data=(st.text or '"''"').strip() if data: plain=decode_stream_text(data) plain=plain.replace('\r','"''"') plain=re.sub(r'\x00','"''"',plain) print(f' Stream {nm} End={end}:') print(plain[:1200]) for ec in root.findall('.//rsp:ExitCode', NS): print(' ExitCode:', ec.text)
|