// Doorknob.java - listens on select TCP sockets for incoming portscans and probes // Gathers data and tries to mess with would-be intruder // Heavily threaded, does not use NBIO // By Rowland http://home.comcast.net/~rowland3 import java.io.*; import java.net.*; import java.util.*; class dnIntruderInfo extends Object { InetAddress rhost; int port; byte[] initBytes; // any data intruder sent immediately upon connect byte[] replyBytes; // any data intruder sent as reply dnIntruderInfo(InetAddress _rhost, int _port, byte[] _initBytes, byte[] _replyBytes) { rhost= _rhost; port= _port; initBytes= _initBytes; replyBytes= _replyBytes; } static final char[] hex= {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; static final String printableBytes(byte[] bytes) { if (bytes== null) return "*NONE*"; StringBuffer s= new StringBuffer(); int i, j= 0; for (i= 0; i< bytes.length; i++) { int b= bytes[i]; if (b< 0) b= 256+b; // byte is signed type! if (b< ' ' || b> 0x7f) { for (int c= j; c< i; c++) { s.append((char)bytes[c]); } int d1= (int)(b>> 4) % 16; int d2= (int)b & 0xf; s.append(" 0x"+ hex[d1]+ hex[d2]+ " "); j= i+1; } } for (int c= j; c< i; c++) { s.append((char)bytes[c]); } return s.toString(); } public String toString() { String rhostname= null; try { rhostname= rhost.getHostName(); } catch (Exception E) { rhostname="*CAN'T RESOLVE*"; } String s= rhost.getHostAddress()+ "\t"+ rhostname+ "\t"+ port+ "\t"+ printableBytes(initBytes)+ "\t"+ printableBytes(replyBytes); return s; } public String summaryString() { String rhostname= null; try { rhostname= rhost.getHostName(); } catch (Exception E) { rhostname="*CAN'T RESOLVE*"; } String s= rhost.getHostAddress()+ "\t"+ rhostname+ "\t"+ port; return s; } public String hostDomain() { String rhostaddr= rhost.getHostAddress(); String rhostname= null; try { rhostname= rhost.getHostName(); } catch (Exception E) { rhostname= rhostaddr; } if (!rhostname.equals(rhostaddr)) { int ix= rhostname.lastIndexOf('.'); ix= rhostname.lastIndexOf('.', ix-1); if (ix< 0) return rhostname; // better than nothing return rhostname.substring(ix+1); } // make the most of dotted quad... int ix= rhostname.indexOf('.'); ix= rhostname.indexOf('.', ix+1); if (ix< 0) return rhostname; // better than nothing return rhostname.substring(0, ix); } } class dnConnThread extends Thread { static Random rand= new Random(); Socket sconn; int port; dnConnThread(Socket _sconn, int _port) { sconn= _sconn; port= _port; } public void run() { try { InetAddress rhost= sconn.getInetAddress(); OutputStream os= sconn.getOutputStream(); InputStream is= sconn.getInputStream(); // does intruder initiate exchange? Thread.sleep(100); byte[] initBytes= null; int iavail= is.available(); if (iavail> 0) { initBytes= new byte[iavail]; is.read(initBytes); } if (initBytes!= null) { // echo it back to intruder os.write(initBytes); } else { // feed intruder some junk: int size= 1000+ rand.nextInt()%500; byte[] randbytes= new byte[size]; rand.nextBytes(randbytes); os.write(randbytes); } Thread.sleep(1000); // any reply? iavail= is.available(); byte[] replyBytes= null; if (iavail> 0) { if (iavail> 100) iavail= 100; // reasonable log entry size. replyBytes= new byte[iavail]; is.read(replyBytes); } dnIntruderInfo ii= new dnIntruderInfo(rhost, port, initBytes, replyBytes); Doorknob.gotIntruderInfo(ii); } catch (Exception E) { System.err.println("dnConnThread: "+ E.toString()); } } } /** Thread to listen on a TCP port **/ class dnListenThread extends Thread { int port; dnListenThread(int _port) { port= _port; } public void run() { try { ServerSocket ss= new ServerSocket(port); System.out.println("dnlistenThread: "+ port+ " listening"); while (true) { Socket sconn= ss.accept(); dnConnThread ct= new dnConnThread(sconn, port); ct.start(); } } catch (Exception E) { System.err.println("dnlistenThread: "+ port+ " "+ E.toString()); } } } public class Doorknob { final static int ports[]= {135, 139, 444, 445, 555, 593, // RPC vulnerability 901, // swat 1025, 1243, // SubSeven 2772, 2773, 3128, // squid 3129, 3410, // OptixPro Trojan 4444, // krb544 4899, // Remote Administrator 5400, 5490, // HTTP connect? 6129, // Dameware 6588, // AnalogX proxy 6670, 6711, 6776, 6777, // Bagle/Beagle worm backdoor 6969, 7215, 12345, 17300, // W32.Weird (Kuang2) 21544, 23456, 27374, // SubSeven 30100, 31789, 31337, 32888, 46986, 50505, 54283}; static void flogwrite(OutputStream flog, String s) throws IOException { flog.write(s.getBytes()); } /** gotIntruderInfo callback from threads **/ static public synchronized void gotIntruderInfo(dnIntruderInfo ii) { java.util.Date d= new java.util.Date(); System.out.println("Doorknob: Incoming at "+ d.toString()); try { FileOutputStream flog= new FileOutputStream("Doorknob."+ ii.port+ ".log", true); // open to append flogwrite(flog, d.toString()+ ":\t"+ ii.toString()+ "\n"); flog.close(); FileOutputStream flogdom= new FileOutputStream("DoorknobDom."+ ii.hostDomain()+ ".log", true); // open to append flogwrite(flogdom, ii.summaryString()+ "\n"); } catch (Exception E) { System.err.println("Doorknob: "+ E.getMessage()); System.out.println(ii.toString()); // better than nothing } } static void listen(int port) { dnListenThread lt= new dnListenThread(port); lt.start(); } public static void main(String args[]) { int i; for (i= 0; i< ports.length; i++) { listen(ports[i]); } } }