-
Notifications
You must be signed in to change notification settings - Fork 6
Socket Code Template
We could waste a lot of time building “publishing” plugins to send Ruckus fuzz messages across the network, but what would be the point?
- Ruby already has good libraries for that
- You’d still be no closer to fuzzing a DeviceIoControl call
- The plugin would still only handle 70-80% of the network cases
- You still wouldn’t have serverside support.
8 times out of 10 if you’re fuzzing something, it’s the serverside of a network protocol. For that case, here’s a template in our recommended network programming environment, EventMachine:
%w[ rubygems eventmachine ruckus my_protocol ].each {|x| require x}
Everything you care about is in my_protocol. I have no idea what it might be.
# Boilerplate common to all network clientside code
module Clientside
def post_init
@buf = ""
@timeout = 1
go
end
def tx(buf, &block)
watchdog
send_data(buf)
@handler = block if block_given?
end
def watchdog
@timer.try(:cancel)
@timer = EventMachine::Timer.new(@timeout) { close_connection }
end
def receive_data(buf)
@buf << buf
@handler.try(:call)
end
def unbind; go; end
end
An EventMachine-ism: every connection is defined by a Module, which is how you tell EventMachine what to do with the connections it makes.
For our purposes, we need to define three handler functions in that module:
- post_init – “initialize”. We arrange to call “go” when initialization is done.
- receive_data – called any time one or more bytes of data arrives at our socket. Here, we just buffer and delegate.
- unbind – called when we lose the connection. Here, we just ask for another connection.
We also define a couple more methods.
Our tx wraps send_data, which will deliver 1, 10, or 10,000,000 bytes across a socket gracefully without locking up I/O.
Here, we’ve extended that with a watchdog timer that will fire if we don’t get anything back from the server.
More importantly, we gave send_data a block argument, which will be called as soon as we get a response from the server.
# Enough handler code to get you past login
module Login; include Clientside
attr_accessor :user, :pass
def go
tx(MyProtocol::Login.new :user => @user, :pass => @pass) do
resp, @buf = MyProtocol::LoginResponse.factory(@buf)
if(resp.kind_of? MyProtocol::LoginFailure)
fail(resp)
else
ok(resp)
end
end
end
def fail(resp)
raise resp.reason.str.value
end
end
On “go”, we send a login message with a block that gets called when the login response appears. We check the response and delegate to “ok” if it succeeded.
# Attack a specific message type
module AttackMessage; include Login
def ok
tx(MyProtocol::Message :data => fuzz.next)
end
end
You could put all the preceding code up to “AttackMessage” into a file and “require” it, and just define these 5 lines of code to implement an attack. “ok” was called because our login succeeded.
def go; EventMachine::connect("localhost", 7777, AttackMessage); end
EventMachine::run {
10.times { go }
}
More boilerplate. This program is going to land in the EventMachine::run loop and never leave it. Run is going to call select() and dispatch I/O. We are running 10 concurrent connections with no threads, resupplying connections every time “unbind” is called on one of them.