Java NetBios Decoy
Page 1 of 2 12 LastLast
Results 1 to 10 of 13

Thread: Java NetBios Decoy

  1. #1
    Member
    Join Date
    Aug 2003
    Posts
    42

    Java NetBios Decoy

    This thread is a continuation of one that was started by h3r3tic a little while ago. It can be found at http://www.antionline.com/showthread...122#post701122

    This is my first thread here so please try to overlook my lack of formatting skills.

    h3r3tic was looking for a way to spoof nbtstat responses so that if someone was trying to use nbtstat to find out about file sharing on his computer and such, he could send them a bogus name table that looked like a genuine nbtstat response. Also he wanted to log the potential attacker's IP address and I would imagine any other iformation that one can get their hands on about the attacker.

    Just a note: I don't have an nbtstat packet dump handy right now so my description might be a little hard to follow, I'll post one as soon as I get my hands on one

    If you've never seen an nbtstat response before this is what it looks like:

    Vic>nbtstat -a some.ip.address

    Local Area Connection 4:
    Node IpAddress: [some.ip.address] Scope Id: []

    NetBIOS Remote Machine Name Table

    Name Type Status
    ---------------------------------------------
    COMPUTER <00> UNIQUE Registered
    WORKGROUP <00> GROUP Registered
    COMPUTER <20> UNIQUE Registered
    WORKGROUP <1E> GROUP Registered
    WORKGROUP <1D> UNIQUE Registered
    ..__MSBROWSE__.<01> GROUP Registered

    MAC Address = 00-A0-CC-3A-34-E3

    You can look at Rioter's NetBios tutorial of you want to find out what an attacker can do once he's gotten this far.

    h3r3tic's original solution was to use code that was taken from a java networking tutorial which set up a TCP connection on port 139. The server was capapble of handling multiple simultaneous connections and used a BufferedReader and PrintWriter combination to handle the input and output. These two objects are useful for reading and writing text to the socket, and my original suggestion was that he was probably going to have to use DataInput/DataOutput streams to mimic the actual program because I thought it was unlikely that it was purely ascii characters being shipped around. The actual problems with this approach were much more involved but I didn't figure that out until I actually started messing around with nbtstat.

    While NetBios does have a server process sitting on TCP port 139, nbtstat actually uses UDP port 137 for all of its communication. So I fired up my network analyzer and started sending nbtstat requests around the office with the intention of reverse engineering the protocol.

    I have written a Java program that will reply to nbtstat requests in a manner that the client process accepts. You will find several of the values used in the program have been hard coded in, and the code is not pretty, but before you flame me to death let me just say that it is Friday night, and I'd rather be drinking than prettying up my code. You can always use command line arguments to bind these variables on your own if you want. This program was tested in an enviornment that contained Windows 2000/XP/NT machines, and the class files were generated using JSDK1.4.0-3.....I think, certainly nothing earlier than that.

    The basic server part of the program Opens up a DataGramSocket on a random port and waits for an incoming connection when a UDP packet is sent it passes the packet off to an Object that implements the Runnable interface and its run() method takes it from there. A new DatagramSocket opens immediately to accept new incoming connections. Here's the server code.

    Code:
    import java.net.*;
    import java.io.*;
    
    public class NetBiosDecoy {
        public static void main(String[] args) throws IOException {
            DatagramSocket s = null;
    	DatagramPacket p = null;
            boolean listening = true;
    	int BUFFER_LENGTH = 1024;
    	byte[] buffer;
    
            try {
    	    if(args.length != 1){
    		System.out.println("NetBiosDecoy: Usage - NetBiosDecoy <port>");
    		System.exit(0);
    	    }
                s = new DatagramSocket(Integer.parseInt(args[0]));
           	    while (listening){
    		buffer = new byte[BUFFER_LENGTH];
    		p = new DatagramPacket(buffer, BUFFER_LENGTH);
    	        s.receive(p);
    		NetBiosDecoyThread t = new NetBiosDecoyThread(p);
    		new Thread(t).start();
    	    }
    	    s.close();
    	} 
    	catch (IOException e) {
                System.err.println("Could not listen on port" + args[0] + ".");
                System.exit(-1);
            }
        }
    }
    This is the actual program that you're going to run from the command line.
    Its usage is : java NetBiosDecoy <port> where port # is 137.
    I have the port number as a command line argument from back when I wasn't sure
    what port was being used for nbtstat.

    The main method doesn't really need to throw IOException, I think I just left that in there from when I copied and pasted the original code. Remeber, you have to shut NetBios off before you run the program otherwise the port will already be in use. You can shut NetBios off by going to network connections->local area network->properties->tcp/ip protocol->Advanced->WINS and clicking on "Disable Netbios".

    Okay, the Runnable object is called NetBiosDecoyThread here's the code.

    Code:
    import java.io.*;
    import java.net.*;
    
    public class NetBiosDecoyThread implements Runnable {
        
        protected DatagramPacket p  = null;
        protected DatagramSocket sock = null;
        protected NetBiosPacketCreator creator;
        protected byte[] in;
        protected byte[] out;
        protected byte numberOfTableEntries;
    
        public NetBiosDecoyThread(DatagramPacket p) {
    
    	this.p= p;
    	in = p.getData();
    	numberOfTableEntries = 5;
    	creator = new NetBiosPacketCreator(in,  numberOfTableEntries, "*");
    
        }
        
        public void run() {
    	
            try {
    	    byte[] in = p.getData();
    	    byte[] out = creator.createNbtStatResponsePacket();
    	    System.out.println("Received the Packet with length " + p.getLength() + " from Address " + p.getAddress().getHostName());	    
    	    DatagramPacket outgoing = new DatagramPacket(out, 0, out.length,p.getAddress(), 137);
    	    DatagramSocket sock = new DatagramSocket();
    	    sock.send(outgoing);
    	    sock.close();
    	} 
    	catch (IOException e) {
    	    e.printStackTrace();
    	}
    
        }
    }
    There's not too much going on in this class, the server process hands the incoming packet off to this class at which point the run method goes to work. This class creates a NetBiosPacketCreator object which is what actually puts the response packet together for us. The run method prints the attacker's IP address to the standard out but it could just as easily have been written to a file with a few extra lines of code. There's not much more you're going to be able to determine about the incoming packet.

    The class that does thet grunt work is called NetBiosPacketCreator, it's kind of a mess, I'm sorry, really I am.

    Code:
    public class NetBiosPacketCreator {
    
        protected byte[] in; // incoming byte[] need for sequence #
        protected byte[] response; // The response buffer
        protected final int NETBIOS_NAME_LENGTH = 32; 
        protected final int COUNT_FIELDS_LENGTH = 8;
        protected final int RESPONSE_FIELD_LENGTH = 18;
        protected final int BASE_PACKET_LENGTH = 121;
        protected byte[] netBiosName; // Our encoded netbios name
        protected byte numberOfTableEntries; //How many fake table entries?
    
    
        /* The constructor first creates the encoded netbios name
         * and then creates the response array whose size is dependant
         * on the number of fake nametable entries we are sending back.
         */
    
        public NetBiosPacketCreator(byte[] in, byte numberOfTableEntries, String asciiName) {
    	try{
    	    netBiosName = encodeNetBiosName(asciiName);
    	}
    	catch(Exception e) {e.printStackTrace();}
    	this.numberOfTableEntries = numberOfTableEntries;
    	// The size of the response array is 121 + (18 * numberOfTableEntries)
    	response = new byte[BASE_PACKET_LENGTH + (numberOfTableEntries * RESPONSE_FIELD_LENGTH)];
    	this.in = in;
    
        }
        
    
        /* This function does most of the work for the program
         * It creates our response packet which is then sent back
         * to the NetBiosDecoyThread to be shipped out on the wire
         */
    
        public byte[] createNbtStatResponsePacket() {
    
    	byte[] entryName = new byte[RESPONSE_FIELD_LENGTH];
    	int index = 0;
    	// set the sequence number
    	response[index++] = in[0];
    	response[index++] = in[1];
    	// the message type for a response is 84 00 = 132 0
    	response[index++] = (byte)132;
    	response[index++] = 0;
    	String fakeEntry = "BITEME.........";
    	byte[] temp = fakeEntry.getBytes();
    	for (int i = 0; i < entryName.length;i++){
    	    if (i < 15)
    		entryName[i] = temp[i];
    	    else if(i == 15)
    		entryName[i] = 1;
    	    else if (i == 16) 
    		entryName[i] = 68;
    	    else
    		entryName[i] = 0;
    	}
    		
    
    	//Set the count fields which are all 0 except the fourth byte which is set to 1
    	for(int i = 0;i < COUNT_FIELDS_LENGTH;i++) {
    	    if(i == 3)
    		response[index++] = 1;
    	    else
    		response[index++] = 0;
    	}
    	//Next comes the name length field, which is 0x20 or 32  
    	response[index++] = 32;
    	//The next 32 bytes are the name field encoded by splitting each byte of the name into two nibbles and adding 41(65) to them.
    	for(int i = 0;i < NETBIOS_NAME_LENGTH;i++){
    	    response[index++] = netBiosName[i];
    	}
    	//add the null delimeter
    	response[index++] = 0;
    	// Question type and Question Class
    	response[index++] = 0;
    	response[index++] = 33; 
    	response[index++] = 0;
    	response[index++] = 1;
    	// Now five 0 bytes for reasons I have yet to figure out
    	for(int i = 0;i < 5;i++)
    	    response[index++] = 0;
    	// The next two bytes tell us about the remaining data in the packet
    	response[index++] = 119;  // Length field that doesn't really add up
    	response[index++] = numberOfTableEntries;
    	// Now comes the fake share names
    	for(int i = 0; i < numberOfTableEntries;i++){
    	    for(int j = 0; j < entryName.length;j++)
    		response[index++] = entryName[j];
    	}
    	//Now the MAC Address
    	response[index++] = 0;
    	response[index++] = 14;
    	response[index++] = 44;
    	response[index++] = 22;
    	response[index++] = 5;
    	response[index++] = 68;
    	//Now just pad the rest with zeros
    	while(index < response.length)
    	    response[index++] = 0;
    	return response;
        }
    
        // This function takes a sixteen character or less netbois name and encodes it
       
        public byte[] encodeNetBiosName(String name) throws Exception{
    	
    	if (name.length() > 16)
    	    throw new Exception("NetBios Name too long");
    	
    	int  high;
    	byte[] netBiosEncoded = new byte[NETBIOS_NAME_LENGTH];
    	int missingLowNibble;
    	byte character;
            int  low;
            int temp;
    	int index;
    
    	index = 0;
    	byte[] netBiosBytes;
    
    	netBiosBytes = name.getBytes();
    	for(int i = 0; i < netBiosBytes.length;i++){
    	    temp = netBiosBytes[i];
    	    high = temp >> 4;
    	    missingLowNibble = high << 4;
    	    low = temp -  missingLowNibble;
    	    high += 65;
    	    low += 65;
    	    netBiosEncoded[index++] = (byte)high;
    	    netBiosEncoded[index++] = (byte)low;
    	}
    	while(index < NETBIOS_NAME_LENGTH)
    	    netBiosEncoded[index++] = 65;
    	return netBiosEncoded;
        }
    	
    }

    Okay lets talk a little bit about the contents of an nbtstat packet. After you strip away the Ethernet, IP, and UDP headers you are left with the packet's body of data which is kind of a wierd size. Each fake nametable entry that you add to the packet adds 18 bytes onto the size of the packet but the base amount of bytes is 121, so it's most common to see packet sizes like 217(four), 235(five), and 253(six) after you add the 42 bytes for all of the headers.

    The first two bytes in the nbtstat data make up its sequence number. The sequence number is two bytes long, but instead of incrementing on the request packet, the response simply uses the same sequence number as the request. I guess this makes sense since UDP maintains no connection. sense since, that doesn't sound right. Anyway, that's the only thing that we need the incoming packet for. You simply take the first two bytes off of the incoming packet and stick them in the beginning of your response array.

    The next two bytes are used to determine what kind of nbtstat packet we're dealing with. Requests are 01 00, while responses are 84 00, these are hex numbers remember. There's another two byte combination for broadcast packets, which you'll see a ton of on any network running NetBios. NetBios is a very chatty protocol, but I never bother to take a good look at any of the broadcast packets.

    Okay next we have the QDcount, ANcount, NScount, and ARcount fields, I'm not too sure what these do so if anyone out there can enlighten me I would apprieciate it. These are four two byte fields for a total of 8 bytes. In a request, the QDcount field is 00 01 and the rest are 00 00 while in a response packet the ANcount field is 00 01 and the rest are 00 00, I have no idea why.

    Next up is my favorite part, the NetBios Name field. This is a 32 byte field although I think I read that it can be larger in the RFC document, anyway, I haven't encountered that situation. NetBios names can be up to 16 alphnumeric characters, so why 32 bytes you ask? NetBios encodes its name by using the following scheme. Take the netbios name character by character. For each character, split the byte into two nibbles, and make those four bits the low bits in two new bytes. Then add 0x41 to each, or the letter 'A'. If the Netbios name is less than 16 characters long than simply fill in the remaining bytes with 0x41 until you have 32 bytes. All of the nbtstat packets that I sent or received used "*" as thet netBios name which is like the wildcard name. The broadcast packets all used real names, which I didn't bother to decode. So when you split the "*" into two nibbles you get 02 and 0A, which turn into 43 and 4B after you add 'A' to them. Which is C and K. So much of the nbtstat traffic you see will have CKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA as the NetBios name field when view through a network analyzer, and now you know why. I have written a function that will encode a String variable into a byte[] of size 32. Maybe you can figure out a more elegant way of splitting up the byte into nibbles, I'm not so hot when it comes to bitwise operators, plus Java doesn't have an unsigned byte. I'm sure there's some well know way of doing it that I didn't see, so please suggestions are welcome.

    Okay, after that you have a null delimeter and the Question class and type fields so the next 3 bytes look like this 00 21 01

    Then there are five null bytes for no good reason 00 00 00 00 00

    The next two bytes tell you about the rest of the packet, although I'm not exactly sure what the first byte is trying to tell us. The second byte tells us home many nametable entries are being returned, that was easy to figure out, but the first byte is different, it appears to be some sort of length field but it isn't the number of remaining bytes in the packet, or the total number of bytes, however, it does go up and down by 18 when you add or remove a nametable entry so it has to be related to the size of the packet somehow. Anyway, I discovered that the program will still work with an incorrect value for this field so it doesn't really matter, but I must admit, I am curious.

    Now come the nametable entries. These are 18 bytes apeice. Here you have an entry
    JOHNNY5 <00> UNIQUE Registered
    the entry name is up to 15 bytes long, then after that comes the hex number you see, in this example its 00. then one byte denotes whether or not the entry is UNIQUE or GROUP or whatever. I think C4 is group and 44 is unique or maybe its the other way around. On account of how these are fake it doesn't matter anyway. The last byte is a null delimeter.

    God how much longer do we have? I did start drinking though so that's cool.

    alright after that is six bytes for the MAC address, I tried to make mine look authentic but you could have yours spell out something witty.

    Then its just null bytes for the rest of the packet. It was really bothering me that there's this really odd number of pad bytes tacked on to the end of the packet. I would really like to know why that is.

    So once this packet is created it gets sent back to the NetBiosDecoyThread and shipped out.

    These classes should compile right from jump street but I have to restart my computer in order to find out so I'll post a change if I notice any mistakes. Thanks for reading my post, have fun, I'm gonna get drunk.

    Oh yea, and for those of you out there that need an alternative to morphine, you could always try RFC 1001, the NetBios specification:
    http://www.cis.ohio-state.edu/cgi-bin/rfc/rfc1001.html

    Vic

  2. #2
    Elite Hacker
    Join Date
    Mar 2003
    Posts
    1,407
    I have gotten this to work locally, but for some reason it won't work for anyone outside my lan. I have a router and setup port forwarding for port 137 to the computer with this program, and I shut off iptables, and it didn't work. Does anyone have any insight into a way for this to work from the internet. By the way, really good job with this VicC, I could never have taken it this far. Pretty cool little program. Thanks.

  3. #3
    Member
    Join Date
    Sep 2003
    Posts
    69
    i can only seem to compile the 3rd piece of code, but not the first to keep gettin symbol error or something
    Signature image is too tall!

  4. #4
    i was havin problems compiling stuff, just recently got the newest jdk from the sun site, fixed my problem

  5. #5
    Member
    Join Date
    Aug 2003
    Posts
    42
    Just a quick suggestion, if the third piece of code(NetBiosPacketCreator) is compiling but
    the other two aren't , you may need to set your CLASSPATH variable to point to the
    directory that contains the .java files. Even though this shouldn't be the case I
    have encountered some problems similar to this when trying to compile on Windows
    machines. Are you using Windows? The reason for this being that NetBiosPacketCreator
    does not contain any references to the objects defined by my code, while the first two
    classes both contain objects that are user defined. NetBiosDecoy contains a reference
    to NetBiosDecoyThread, and NetBiosDecoyThread contains a reference to
    NetBiosPacketCreator. I could be totally mistaken about this. If you would post
    your compile error I would probably be able to give you a definite answer

  6. #6
    Member
    Join Date
    Sep 2003
    Posts
    69
    ok here it is, and i do have windows
    Signature image is too tall!

  7. #7
    Member
    Join Date
    Sep 2003
    Posts
    69
    i just downloaded the linux sdk and ran it, it gives me the same errors
    Signature image is too tall!

  8. #8
    Member
    Join Date
    Aug 2003
    Posts
    42
    Okay, my first suggestion is this:
    If all of the files are in the directory C:\Sun\AppServer\jdk\bin what I would like you to do is edit your CLASSPATH to inculde that directory. I would imagine that you definitely know how to do this, but just in case you don't, on your windows machine you want to Open Control Panel and goto System->Advanced->Envioronment Variables. You should see the CLASSPATH variable under User Variables. If you don't have a CLASSPATH variable you'll have to create it, but if it already exists, edit it to include the above path. I always have to restart my Windows machine in order for the change to take place, but there is probably another way to get it to register. You can check to see if the change was successful by typing "echo %CLASSPATH%" at the command line.

    On your linux machine you will have to type something like set $CLASSPATH = $CLASSPATH:/path/to/java/files, but to make the change permanent, I would edit my .cshrc file. Again you can check to see if the new value for CLASSPATH is correct by using the "echo" command.

    Please let me know if you have either done this already or if you try it and it doesn't work, because the errors that you are getting are symptomatic of a missing CLASSPATH variable.

    I guess I don't have a second suggestion.

  9. #9
    Member
    Join Date
    Aug 2003
    Posts
    42
    Okay, here is the nbtstat packet dump that I said I would post. The actual nbtstat data is highlighted in red. This image, coupled with my description of the packet contents above, should be enough to give you a real good idea of how my program works. Thanks, enjoy!

  10. #10
    Member
    Join Date
    Sep 2003
    Posts
    69
    ok i tried setting the class varible but no luck, would you be able to post the compiled code or something for us?
    Signature image is too tall!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •