#!/usr/bin/perl ## fauxsmb.pl - Simulate an SMB session setup ## (c)2006 Joe Stewart use IO::Socket; my $port = "445"; $SIG{'ALRM'} = sub { die "timeout" }; my @resp1 = qw(00 00 00 55 ff 53 4d 42 72 00 00 00 00 98 53 c8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff fe 00 00 00 00 11 05 00 03 32 00 01 00 04 41 00 00 00 00 01 00 00 00 00 00 fd f3 00 80 60 cc 75 07 41 2e c4 01 f0 00 00 10 00 91 4d 15 73 b5 10 19 46 b3 48 53 87 7d c4 05 4e); for (@resp1) { $r1 .= chr(hex) } my @resp2 = qw(00 00 00 d7 ff 53 4d 42 73 16 00 00 c0 98 07 c8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff fe 00 08 10 00 04 ff 00 d7 00 00 00 62 00 ac 00 4e 54 4c 4d 53 53 50 00 02 00 00 00 06 00 06 00 30 00 00 00 15 82 8a c0 5d 27 e2 f4 c1 97 df 18 00 00 00 00 00 00 00 00 2c 00 2c 00 36 00 00 00 4c 00 41 00 42 00 02 00 06 00 4c 00 41 00 42 00 01 00 06 00 4c 00 41 00 42 00 04 00 06 00 6c 00 61 00 62 00 03 00 06 00 6c 00 61 00 62 00 00 00 00 00 00 57 00 69 00 6e 00 64 00 6f 00 77 00 73 00 20 00 35 00 2e 00 30 00 00 00 57 00 69 00 6e 00 64 00 6f 00 77 00 73 00 20 00 32 00 30 00 30 00 30 00 20 00 4c 00 41 00 4e 00 20 00 4d 00 61 00 6e 00 61 00 67 00 65 00 72 00 00); for (@resp2) { $r2 .= chr(hex) } my @resp3 = qw(00 00 00 75 ff 53 4d 42 73 00 00 00 00 98 07 c8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff fe 00 08 20 00 04 ff 00 75 00 00 00 00 00 4a 00 00 57 00 69 00 6e 00 64 00 6f 00 77 00 73 00 20 00 35 00 2e 00 30 00 00 00 57 00 69 00 6e 00 64 00 6f 00 77 00 73 00 20 00 32 00 30 00 30 00 30 00 20 00 4c 00 41 00 4e 00 20 00 4d 00 61 00 6e 00 61 00 67 00 65 00 72 00 00); for (@resp3) { $r3 .= chr(hex) } my @resp4 = qw(00 00 00 38 ff 53 4d 42 75 00 00 00 00 98 07 c8 00 00 00 00 00 00 00 00 00 00 00 00 00 08 ff fe 00 08 30 00 07 ff 00 38 00 01 00 ff 01 00 00 ff 01 00 00 07 00 49 50 43 00 00 00 00); for (@resp4) { $r4 .= chr(hex) } my @resp5 = qw(00 00 00 87 ff 53 4d 42 a2 00 00 00 00 98 07 c8 00 00 00 00 00 00 00 00 00 00 00 00 00 08 dc 04 00 08 40 00 2a ff 00 87 00 00 00 40 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 ff 05 00 00 00 06 00 06 00 40 00 00 00 10 00 10 00 47 00 00 00 15 8a 88 e0 48 00 9b 01 12 00 9b 01 12 00 7a f2); for (@resp5) { $r5 .= chr(hex) } my @resp6 = qw(00 00 00 7c ff 53 4d 42 25 00 00 00 00 98 07 c8 00 00 00 00 00 00 00 00 00 00 00 00 00 08 dc 04 00 08 50 00 0a 00 00 44 00 00 00 00 00 38 00 00 00 44 00 38 00 00 00 00 00 45 00 00 05 00 0c 03 10 00 00 00 44 00 00 00 01 00 00 00 b8 10 b8 10 11 dc 00 00 0c 00 5c 50 49 50 45 5c 6c 73 61 73 73 00 00 00 01 00 00 00 00 00 00 00 04 5d 88 8a eb 1c c9 11 9f e8 08 00 2b 10 48 60 02 00 00 00); for (@resp6) { $r6 .= chr(hex) } my @resp7 = qw(00 00 00 2f ff 53 4d 42 2f 00 00 00 00 98 07 c8 00 00 00 00 00 00 00 00 00 00 00 00 00 08 ff fe 00 08 60 00 06 ff 00 2f 00 b8 10 ff ff 00 00 00 00 00 00); for (@resp7) { $r7 .= chr(hex) } print "Starting Faux SMB Server Emulation on port $port\n"; my $sock = IO::Socket::INET->new( LocalPort => $port, Type => SOCK_STREAM, Reuse => 1, Listen => 10) or die "Fatal: Couldn't bind to port $port (Already in use?)\n"; while ($remote = $sock->accept()) { my ($req1, $req2, $req3, $req4, $req5, $req6, $req7, $req8); my ($shellcode, $listenport, $cpport, $cbip, $cshell, $bshell, $buf); my $sockpeer = $remote->peername; next unless $sockpeer; my ($port, $addr) = unpack_sockaddr_in($sockpeer); my $ip = inet_ntoa($addr); logger("Connection from $ip"); eval { alarm(30); if ($remote->connected()) { # req1 $remote->recv($req1,4); hexlogger($req1); if (substr($req1,0,2) eq "\x00\x00") { logger("Netbios Session packet detected"); } else { goto GETREST } $req1 = netbiosrecv($req1); if(substr($req1,4,1) eq "\x72") { logger("SMB Negotiate Protocol Request Detected (0x72)"); } else { logger("Unexpected SMB Request" . sprintf("0x%x", ord(substr($req1,4,1)))) } if ($req1 =~ /Windows for Workgroups 3.1a/) { logger("Possible HOD exploit in progress"); } logger("Sending SMB session response"); $remote->send($r1); # req2 $remote->recv($req2,4); hexlogger($req2); if (substr($req2,0,2) eq "\x00\x00") { logger("Netbios Session packet detected"); } else { goto GETREST } $req2 = netbiosrecv($req2); if(substr($req2,4,1) eq "\x73") { logger("SMB Session Setup AndX Request Detected (0x73)"); } else { logger("Unexpected SMB Request" . sprintf("0x%x", ord(substr($req2,4,1)))) } if ($req2 =~ /NTLMSSP\x00\x01\x00\x00\x00/) { logger("NTLMSSP_NEGOTIATE message detected"); } logger("Sending SMB session response"); $remote->send($r2); # req3 $remote->recv($req3,4); hexlogger($req3); if (substr($req3,0,2) eq "\x00\x00") { logger("Netbios Session packet detected"); } else { goto GETREST } $req3 = netbiosrecv($req3); if(substr($req3,4,1) eq "\x73") { logger("SMB Session Setup AndX Request Detected (0x73)"); } else { logger("Unexpected SMB Request" . sprintf("0x%x", ord(substr($req3,4,1)))) } if ($req3 =~ /NTLMSSP\x00\x03\x00\x00\x00/) { logger("NTLMSSP_AUTH message detected"); } logger("Sending SMB session response"); $remote->send($r3); } # req4 if ($remote->connected()) { $remote->recv($req4,4); hexlogger($req4); if (substr($req4,0,2) eq "\x00\x00") { logger("Netbios Session packet detected"); } else { goto GETREST } $req4 = netbiosrecv($req4); if(substr($req4,4,1) eq "\x75") { logger("SMB Session Connect AndX Request Detected (0x75)"); } else { logger("Unexpected SMB Request" . sprintf("0x%x", ord(substr($req4,4,1)))) } if ($req4 =~ /\x69\x00\x70\x00\x63\x00\x24/) { logger("ipc\$ connect path detected"); } logger("Sending SMB session response"); $remote->send($r4); # req5 $remote->recv($req5,4); hexlogger($req5); if (substr($req5,0,2) eq "\x00\x00") { logger("Netbios Session packet detected"); } else { goto GETREST } $req5 = netbiosrecv($req5); if(substr($req5,4,1) eq "\xa2") { logger("SMB Session Create AndX Request Detected (0xa2)"); } else { logger("Unexpected SMB Request" . sprintf("0x%x", ord(substr($req5,4,1)))) } if ($req5 =~ /\x5c\x00\x6c\x00\x73\x00\x61\x00\x72\x00\x70\x00\x63\x00\x00/) { logger("lsarpc create path detected"); } logger("Sending SMB session response"); $remote->send($r5); # req6 $remote->recv($req6,4); hexlogger($req6); if (substr($req6,0,2) eq "\x00\x00") { logger("Netbios Session packet detected"); } else { goto GETREST } $req6 = netbiosrecv($req6); if(substr($req6,4,1) eq "\x25") { logger("SMB Transaction Request Detected (0x25)"); } else { logger("Unexpected SMB Request" . sprintf("0x%x", ord(substr($req6,4,1)))) } if ($req6 =~ /\x05\x00\x0b.*\x6a\x28\x19\x39\x0c\xb1\xd0\x11\x9b\xa8\x00\xc0\x4f\xd9\x2e\xf5/) { logger("DCERPC Bind LSA_DS detected"); } logger("Sending SMB session response"); $remote->send($r6); # req7 (screq2k) $remote->recv($req7,4); hexlogger($req7); if (substr($req7,0,2) eq "\x00\x00") { logger("Netbios Session packet detected"); } else { goto GETREST } $req7 = netbiosrecv($req7); if(substr($req7,4,1) eq "\x2f") { logger("SMB Write AndX Request Detected (0x2f)"); } else { logger("Unexpected SMB Request" . sprintf("0x%x", ord(substr($req7,4,1)))) } if ($req7 =~ /\x09\x00\xad\x0d\x00/) { logger("DCERPC LSA_DS DsRoleUpgradeDownlevelServer exploit detected"); } if ($req7 =~ /\xeb\x00\x10\x00\x5b\x00\x4b\x00\x33\x00\xc9\x00\x66\x00\xb9\x00/) { logger("HOD reverseshell detected"); $cshell = 1; } elsif($req7 =~ /\xeb\x00\x10\x00\x5a\x00\x4a\x00\x33\x00\xc9\x00\x66\x00\xb9\x00/) { logger("HOD bindshell detected"); $bshell = 1; } else { logger("Unknown shellcode detected"); } logger("Sending SMB session response"); $remote->send($r7); # req8 (screq2k2) $remote->recv($req8,4); hexlogger($req8); if (substr($req8,0,2) eq "\x00\x00") { logger("Netbios Session packet detected"); } else { goto GETREST } $req8 = netbiosrecv($req8); if(substr($req8,4,1) eq "\x25") { logger("SMB Transaction Detected (0x25)"); } else { logger("Unexpected SMB Request" . sprintf("0x%x", ord(substr($req8,4,1)))) } if ($cshell) { if ($req8 =~ /\x12\x00\x41\x00\xf1\x00(.)\x00(.)\x00(.)\x00(.)\x00\xf1\x00\x9b\x00\x99\x00(.)\x00(.)\x00\x12\x00\x55/) { $cbip = (ord($1) ^ 0x99) . "." . (ord($2) ^ 0x99) . "." . (ord($3) ^ 0x99) . "." . (ord($4) ^ 0x99); $cbport = (unpack("s", $6 . $5) ^ 0x9999) & 0xffff; logger("Connect-back port is $cbport"); logger("Connect-back ip is $cbip"); &cbshell($cbip, $cbport); close($remote); } else { logger("Could not find connectback address and port in shellcode") } } elsif ($bshell) { if ($req8 =~ /\x12\x00\x41\x00\x5e\x00\x9e\x00\x9b\x00\x99\x00(.)\x00(.)\x00\xaa\x00\x59/) { $listenport = (unpack("s", $2 . $1) ^ 0x9999) & 0xffff; logger("Bind port is $listenport"); &bindshell($listenport); close($remote); } else { logger("Could not find bind port in shellcode") } } } GETREST: while($remote->connected()) { $remote->recv($buf,16); my $bytes = length($buf); last unless ($bytes > 0); hexlogger($buf); logger("$bytes unknown bytes"); } alarm(0); logger("Closing connection\n"); close($remote); }; if ($@) { if ($@ =~ /alarm|timeout/i) { close($remote); logger("Connection timed out\n"); } elsif ($@ =~ /invalid/i) { alarm(0); logger("Invalid connection (not SMB)\n"); close($remote); } else { alarm(0); die "Fatal: $@\n"; } } } sub logger { my $msg = shift; print STDOUT "$msg\n"; open(OUT,">>/tmp/sandnetsmb.log") or do {warn "Log output failed: $!"; return }; print OUT "$msg\n"; close OUT; } sub hexlogger { my $b; my $c = 0; for (split(//, shift)) { $c++; $b .= sprintf("%02x ", ord); unless ($c % 24) { $b .= "\n" } } logger("$c bytes received"); logger($b); } sub bindshell { my $bindport = shift; my $shell; logger("Binding shell on port $bindport"); my $sock2 = IO::Socket::INET->new( LocalPort => $bindport, Type => SOCK_STREAM, Reuse => 1, Listen => 10) or do { logger("Couldn't bind to port $bindport (Already in use?)\n"); return }; eval { alarm(30); while($shell = $sock2->accept()) { my ($pport, $addr, $ip); my $peern = $shell->peername; if ($peern) { ($pport, $addr) = unpack_sockaddr_in($peern); $ip = inet_ntoa($addr); } else { $ip = "unknown" } logger("Connection on $bindport from $ip"); $shell->send("\nMicrosoft Windows 2000 [Version 5.00.2195]\n(C) Copyright 1985-1999 Microsoft Corp.\n"); $shell->send("\nC:\\WINNT\\system32>"); INP: while (<$shell>) { chomp; logger("C:\\WINNT\\system32>$_"); if (/exit/) { close($shell) } else { $shell->send("\nC:\\WINNT\\system32>"); } } alarm(0); close($shell); last; } }; if ($@) { if ($@ =~ /alarm|timeout|invalid/i) { alarm(0); logger("Connection timed out\n"); close($shell); } else { alarm(0); die "Fatal: $@\n"; } } } sub cbshell { my ($connectip, $connectport) = @_; logger("Connecting reverse shell to $connectip\:$connectport"); sleep 3; my $shell = IO::Socket::INET->new(PeerAddr => $connectip, PeerPort => $connectport, Proto => 'tcp') or do { logger("Connection failed\n"); return }; $shell->send("\nMicrosoft Windows 2000 [Version 5.00.2195]\n(C) Copyright 1985-1999 Microsoft Corp.\n"); $shell->send("\nC:\\WINNT\\system32>"); while (<$shell>) { chomp; logger("C:\\WINNT\\system32>$_"); if (/exit/) { close($shell) } else { $shell->send("\nC:\\WINNT\\system32>"); } } close($shell); } sub netbiosrecv { my $header = shift; my ($buf, $pkt); my $len = unpack("n", substr($header,2,2)); if ($len > 0) { logger("Processing netbios packet with length $len"); } else { logger("Short Netbios req"); return } while(length($pkt) < $len ) { $remote->recv($buf,1); $pkt .= $buf; } hexlogger($pkt); if (substr($pkt,0,4) eq "\xffSMB") { logger("SMB Header detected") } return $pkt; }