Code for this project can be found on Github here.
I have been spending a lot of time lately programming in C and the verbosity and memory management have ben wearing on me. In my day job I have worked mostly in Clojure for the past few years so working on projects in C has felt a bit clunky. I have really been missing all of the great functional programming niceties I have come to enjoy from Clojure.
So why am I playing with Haskell here? Well I also dabble in Haskell as it has a lot of really cool features without the JVM start up time. So, I wanted to exercise that interest a bit. So how can we write a fuzzer in Haskell?
For those of you unfamiliar with a fuzzer, it is essentially a program that sends data to another program in attempts to trigger a buffer overflow exception. Using the fuzzer you increase the size of the payload until you can get the program under analysis to crash. Normally in the security world fuzzers are written in Python, Ruby, or Perl an look something like this:
#!/usr/bin/python
import socket
import os
import sys
CRASH = "\x41" * 7
EIP = "\x42\x42\x42\x42"
SHELLCODE = "\x43" * 43
buffer="HELP " + CRASH + EIP + SHELLCODE + "\r\n"
print "[*] Sending evil HTTP request"
expl = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
expl.connect(("192.168.99.102", 4321))
data = expl.recv(1024)
print "\n[*] Server Banner: %s" % data
print "\n[*] Buffer: %s" % buffer
expl.send(buffer)
data1 = expl.recv(1024)
print "\n[*] Server Response: %s" % data1
expl.close()
Essentially what this does is open a tcp socket connnection to a machine and then sends and receives data. The send and receive data part is often different from application to application as some applications will send first and others will wait to receive first. So how might we open a tcp socket connection in Haskell and send some data?
Through a short Google search I found this tcp library. This seems like it will be helpful.
Using stack we set ourselves up with a skeleton project following the quickstart:
We also need to update our fuzz.cabal
and stack.yaml
with some dependencies:
stack.yaml
# Packages to be pulled from upstream that are not in the resolver (e.g., acme-missiles-0.3)
extra-deps: [network-simple-0.4.0.5]
fuzz.cabal
library
hs-source-dirs: src
exposed-modules: Lib
build-depends: base >= 4.7 && < 5
, bytestring
, network-simple
default-language: Haskell2010
executable fuzz-exe
hs-source-dirs: app
main-is: Main.hs
ghc-options: -threaded -rtsopts -with-rtsopts=-N
build-depends: base
, bytestring
, fuzz
, network-simple
default-language: Haskell2010
The two dependencies we have added are network-simple
which is the
TCP library we found earlier and bytestring
which is a library
included with Haskell we need to require into our project. You’ll
notice that in the stack.yaml file a version is appended after the
name of the library. This version number can be derived from a Haskell
libraries info page
like this one. You’ll
see that at the time of this writing 0.4.0.5
is the latest version.
Next we write our code:
module Lib
( fuzz
) where
import qualified Data.ByteString as BS
import Network.Simple.TCP
host :: String
host = "127.0.0.1"
port :: String
port = "4444"
payload :: BS.ByteString
payload = BS.pack $ take 500 $ repeat 0x41
fuzz :: IO ()
fuzz = do
putStrLn $ "About to fuzz " ++ host
connect host port $ \(connectionSocket, remoteAddr) -> do
putStrLn $ "Connection established to " ++ show remoteAddr
send connectionSocket payload
The code is pretty self explanatory. We:
- import the libraries we need for dealing with TCP
- define some constants
- define the payload that we want to send across the wire, in this case, a series of 500 A’s.
- setup our IO Monad which prints some helpful messaging, makes our connection, and sends the payload over the socket.
If we startup a netcat listener using nc -nlvp 4444
in one terminal:
:~$ nc -nlvp 4444
And compile our program with stack doing in a separate terminal:
stack build
We can execute our new program with stack exec fuzz-exe
and should
see some output on the netcat side:
:~$ nc -nlvp 4444
Connection from 127.0.0.1:53340
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
And it works! we see our payload of A’s gets sent accross the network.