Tuesday, April 19, 2011

Protocols #5, Quote of the Day

The quote of the day protocol, defined in RFC 865, specifies a standard that when implemented will return a quote when port 17 is connected to in TCP, or when a datagram is sent to it in UDP.

This implementation in Node.js, is similar to the daytime protocol I built earlier, it introduces an array of quotes of which one is randomly chosen to
#!/usr/bin/nodejs
var net = require('net');
var dgram = require('dgram');

var quotes = [
"Time is an illusion. Lunchtime doubly so.\n - Douglas Adams",
"The quieter you become the more you can hear.\n - Baba Ram Dass",
"Wisdom lies in knowing when to remember and when to forget.\n - Ayn Rand",
"Chance favors the prepared mind.\n - Louis Pasteur",
"The advertisement is the most truthful part of a newspaper.\n - Thomas Jefferson",
"To communicate through silence is a link between the thoughts of man.\n - Marcel Marceau",
"There are periods when...to dare, is the highest wisdom.\n - William Ellery Channing"
];

function getquote() {
randno = Math.floor ( Math.random() * quotes.length );
return quotes[randno] + "\n";
}

//TCP
var tcpserver = net.createServer(function (socket) {
socket.end(getquote());
})

//UDP
var udpserver = dgram.createSocket("udp4", function (msg, rinfo) {
var ret = new Buffer(getquote());
udpserver.send(ret, 0, ret.length, rinfo.port, rinfo.address);
});

//Bind and serve (Port 17 is actual)
tcpserver.listen(8017, "127.0.0.1");
udpserver.bind(8017, "127.0.0.1");

Protocols #4, Daytime

Time for another simple protocol: Daytime

"A useful debugging and measurement tool is a daytime service. A daytime service simply sends a the current date and time as a character string without regard to the input." - RFC 867

This time we will use a more complex Javascript function, the Date().toISOString(), which will return the date in an ISO compliant manner.

As usual the actual port for this protocol is 13, but I don't want to run it as root, yet.
//RFC 867 Daytime in Node.js
var net = require('net');
var dgram = require('dgram');

function gettime() {
var d = new Date();
return d.toISOString() + "\n";
}

//TCP
var tcpserver = net.createServer(function (socket) {
socket.end(gettime());
})

//UDP
var udpserver = dgram.createSocket("udp4", function (msg, rinfo) {
var ret = new Buffer(gettime());
udpserver.send(ret, 0, ret.length, rinfo.port, rinfo.address);
});

//Bind and serve
tcpserver.listen(8013, "127.0.0.1");
udpserver.bind(8013, "127.0.0.1");

Protocols #3, Discard

Let's build a discard protocol from Node.js:

RFC 863: "A useful debugging and measurement tool is a discard service. A discard service simply throws away any data it receives."

For the time being, we'll just leave this not logging anything; although in the future we may want to connect this to a UNIX socket to make a honeypot, that fun can come later.

The discard protocol is essentially the same as the echo protocol, except it has blank functions and the ports are changed (the port should really be 9, but unless you are root you aren't allowed to touch low ports).

//An implementation of the discared protocol RFC 863
var net = require('net');
var dgram = require('dgram');

var tcpserver = net.createServer(function(socket) { })
var udpserver = dgram.createSocket("udp4", function(msg, rinfo) { });

//Bind and serve
tcpserver.listen(8009, "127.0.0.1");
udpserver.bind(8009, "127.0.0.1");

Protocols #2, Echo 2.0

To the point, in this article I'll build the echo protocol in 17 lines of code, including whitespace and comments.

Let's face it, C is a very cumbersome language to program network communications in.  Java and Python are only slightly better, but what about JavaScript?

Introducing: Node.js, it has the speed of the V8 engine, the ability to be dynamic like Python, and well, has Java in the name! (Nobody really likes you Java, you are a necessary evil that was invented to run on toasters so they could talk to the blender.)


What is Node?
Node is essentially a JavaScript runtime built on top of V8 that introduces sockets, and file I/O.  And it is non-blocking, which is awesome.

What is non-blocking?
I'm glad you asked. Imagine, if you will your Apache Server, it is running multiple threads, and as soon as a connection is made, one thread takes that connection and serves it until the connection is terminated. If you want a thousand people to connect, you need a thousand threads.

Node on the other hand, takes connections similarly, except everything is based upon callbacks. When a connection is made, a function is called, let's say is to render a PHP page, Node hooks a callback to the end, and forgets about it; returning to service more connections. When the PHP page is finally done reading from the disk, connecting to the database, and running code, the page is returned to Node, who places it on the output stack, and will eventually send it away. This makes Node highly efficient as it never waits for one operation to complete before the next is started.

There is one more thing to love about node though, remember that 205 line echo protocol I wrote in C? How does 17 lines sound, where the whole thing handles both TCP and UDP simultaneously, along with as many connections as I want?

//Echo Protocol RFC 862
var net = require('net');
var dgram = require('dgram');

//TCP
var tcpserver = net.createServer(function (socket) {
socket.pipe(socket);
})

//UDP
var udpserver = dgram.createSocket("udp4", function (msg, rinfo) {
udpserver.send(msg, 0, msg.length, rinfo.port, rinfo.address);
});

//Bind and serve
tcpserver.listen(8007, "127.0.0.1");
udpserver.bind(8007, "127.0.0.1");

I predict home brew protocols are going to be on the rise with Node, when development gets this easy there is sure to be lots of innovation.

Sunday, April 17, 2011

Python Binary Woes (PyInstaller to the rescue)

I obviously like Python very much. It is nice and speedy for most of the things I use it for, the code is very easy to maintain, and its data structures are beautiful.  However, there is one thing that I truly don't like about it: distribution. There are eggs, and tarballs, apps, installers, and executables. How horrifying!

Writing creation scripts for all of these is a nightmare, and for small projects (aren't they all when they are written in Python), it is too much of a hassle. At least Windows and Mac have standalone executable builders.

But what about the lonely Linux/UNIX? You could either require the user to download a bunch of python eggs that they don't have, install them, then run your script, only to find they have the wrong Python version; or you could bundle them all up with a handy little tool called: PyInstaller.


You're probably thinking, "Whoa, who does this guy think he is, breaking the UNIX file hierarchy like that?". Here is the deal, while it may be fine and dandy passing out source code and requiring users to download dependencies and such there are a few reasons you might not want to do it:
  1. Your source code is proprietary, I know, I know, proprietary stuff is evil, but it could happen!
  2. You want to distribute your code off-line and want to ensure all dependencies are satisfied.
  3. Your users cry when they see a command line.
  4. You like things in a clean, tidy, single executable.
 Now on to the HOWTO:
  1. Download PyInstaller
  2. Extract it.
  3. cd to the extracted folder and run "python Configure.py"
  4. Run "python Makespec.py -F /path/to/your/script.py"
  5. Run "python Build.py /path/to/your/spec.spec" You should have received the location of the .spec file in the output of Makespec.py.
  6. Go have lunch, the executable is in a subdirectory of the PyInstaller directory.
There are a few problems though, some files don't like being built due to the way imports are done, just play around with those using the full paths for imports rather than the Python shortcuts and it should all work.

Tuesday, April 5, 2011

Ubuntu Firewall Alerts

Notification of an attempted connection.
At the university I study at, every machine is assigned a net-accessible IP address; as you can imagine this is immensely useful as you don't need to worry about trying to bypass firewalls when you need to SSH somewhere.  There is a catch though, save for torrents (including LiveCDs that take hours to download manually, but minutes by torrent) there is no firewall.

That is okay by me though, I use Ubuntu; meaning I don't get viruses, and the only port I have remotely open is for the IPP because the network is Windows.  Recently I have wanted to see all of the garbage that is coming in.  I originally hacked something up in nc, but decided that wasn't good enough, here is my solution, that includes notifying you when someone attempts to connect to your port (this is a feature missing in all of the Linux firewalls I have found and seems to be a common complaint)  the finished product will look something like the photo above.

Ingredients:
  • Ubuntu / Distro of your choice.
  • iptables (installed by default in Ubuntu 10.10)
  • gufw (sudo apt-get install gufw)
  • notify-send / espeak / xmessage / zenity / other communication interface

Instructions:
  1. Install all of the above.
  2. Under System > Administration > Firewall Configuration, set Incoming to Reject; and turn on the Firewall.
  3. Copy the shell script below to your machine:
  4. #!/bin/bash

    lastlog=$(dmesg | grep UFW\ BLOCK | tail -1)

    while [ 1 -gt 0 ]; do

    sleep 1

    curlog=$(dmesg | grep UFW\ BLOCK | tail -1)

    if [ "$curlog" != "$lastlog" ]; then
    #get information.
    ip=$( echo $curlog | cut -d = -f5 | cut -d \ -f1)
    port=$( echo $curlog | cut -d = -f14 | cut -d \ -f1)
    portfrom=$( echo $curlog | cut -d = -f13 | cut -d \ -f1)
    lastlog=$(dmesg | grep UFW\ BLOCK | tail -1)

    #send message.
    notify-send "Src: $ip:$portfrom Dest: $port" -u critical -i security-low
    fi

    done
  5. For this to work though, you will need the program notify-send, if it is not installed, you could replace it with espeak (to have your computer announce that you dropped a connection), xmessage, or zenity.
  6. Watch how many times you are attacked.  (You might want to consider posting/looking up your findings to dshield)