From 0bca0ca5579b396ff8e1435968b6f9a32411ea0b Mon Sep 17 00:00:00 2001 From: Ruben Date: Thu, 17 Jul 2014 13:45:08 +1000 Subject: [PATCH 1/9] Added Replace.py module. Module capable of replacing a string within a HTML document. --- plugins/Replace.py | 56 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 plugins/Replace.py diff --git a/plugins/Replace.py b/plugins/Replace.py new file mode 100644 index 0000000..9b21baa --- /dev/null +++ b/plugins/Replace.py @@ -0,0 +1,56 @@ +import os,subprocess,logging,time,re +import argparse +from plugins.plugin import Plugin +from plugins.CacheKill import CacheKill + +class Replace(CacheKill,Plugin): + name = "Replace" + optname = "replace" + implements = ["handleResponse","handleHeader","connectionMade"] + has_opts = True + desc = "Replace arbitrary content in HTML content" + + def initialize(self,options): + '''Called if plugin is enabled, passed the options namespace''' + self.options = options + self.match_str = options.match_str + self.replace_str = options.replace_str + + if self.options.preserve_cache: + self.implements.remove("handleHeader") + self.implements.remove("connectionMade") + + self.ctable = {} + self.dtable = {} + self.mime = "text/html" + + print "[*] Replace plugin online" + + def handleResponse(self,request,data): + ip,hn,mime = self._get_req_info(request) + + if self._should_replace(ip,hn,mime) and (not self.replace_str==self.search_str==None) and (not self.search_str==""): + data = self._insert_html(data,post=[(self.match_str,self._get_payload())]) + + self.ctable[ip] = time.time() + self.dtable[ip+hn] = True + + logging.info("%s [%s] Replaced '%s' with '%s'" % (request.client.getClientIP(), request.headers['host'], self.match_str, self.replace_str)) + + return {'request':request,'data':data} + + return + + def add_options(self,options): + options.add_argument("--replace-str",type=str,default="",help="String you would like to replace.") + options.add_argument("--search-str",type=str,default="",help="String you would like to replace --replace-str with. Default: '' (empty string)") + options.add_argument("--preserve-cache",action="store_true",help="Don't kill the server/client caching.") + + def _should_replace(self,ip,hn,mime): + return mime.find(self.mime)!=-1 + + def _get_req_info(self,request): + ip = request.client.getClientIP() + hn = request.client.getRequestHostname() + mime = request.client.headers['Content-Type'] + return (ip,hn,mime) From 2142cf24c5ebfcfbf6a6649457a3676f36c3b777 Mon Sep 17 00:00:00 2001 From: Ruben Date: Thu, 17 Jul 2014 14:01:48 +1000 Subject: [PATCH 2/9] A replace function makes this module so much more useful --- plugins/Replace.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Replace.py b/plugins/Replace.py index 9b21baa..d1f04ed 100644 --- a/plugins/Replace.py +++ b/plugins/Replace.py @@ -30,7 +30,7 @@ class Replace(CacheKill,Plugin): ip,hn,mime = self._get_req_info(request) if self._should_replace(ip,hn,mime) and (not self.replace_str==self.search_str==None) and (not self.search_str==""): - data = self._insert_html(data,post=[(self.match_str,self._get_payload())]) + data = self.replace(self.search_str, self.replace_str) self.ctable[ip] = time.time() self.dtable[ip+hn] = True From 3031412133ac0139b12956ed7355240903d48baf Mon Sep 17 00:00:00 2001 From: Ruben Date: Thu, 17 Jul 2014 14:21:29 +1000 Subject: [PATCH 3/9] Added availible modules to the README file --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 053419c..c969a43 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,18 @@ Quick tutorial and examples at http://sign0f4.blogspot.it This tool is completely based on sergio-proxy https://code.google.com/p/sergio-proxy/ and is an attempt to revive and update the project. +Availible modules: +- ArpSpoof - Redirect traffic using arp-spoofing +- BrowserProfiler - Attempts to enumerate all browser plugins of connected clients +- CacheKill - Kills page caching by modifying headers +- FilePwn - Backdoor executables being sent over http using bdfactory +- Inject - Inject arbitrary content into HTML content +- JavaPwn - Performs drive-by attacks on clients with out-of-date java browser plugins +- jskeylogger - Injects a javascript keylogger into clients webpages +- Replace - Replace arbitary content in HTML content +- SMBAuth - Evoke SMB challenge-response auth attempts +- Upsidedownternet - Flips images 180 degrees + So far the most significant changes have been: - Arpspoof plugin has been completely re-written to use scapy (Now able to poison via arp-requests and arp-replies) From 3d3099fb004c3666100c9e1e94db83bee7fa7235 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 17 Jul 2014 20:46:01 +1000 Subject: [PATCH 4/9] Replace on self is useless --- plugins/Replace.py | 78 +++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/plugins/Replace.py b/plugins/Replace.py index d1f04ed..7d6261b 100644 --- a/plugins/Replace.py +++ b/plugins/Replace.py @@ -4,53 +4,53 @@ from plugins.plugin import Plugin from plugins.CacheKill import CacheKill class Replace(CacheKill,Plugin): - name = "Replace" - optname = "replace" - implements = ["handleResponse","handleHeader","connectionMade"] - has_opts = True - desc = "Replace arbitrary content in HTML content" - - def initialize(self,options): - '''Called if plugin is enabled, passed the options namespace''' - self.options = options - self.match_str = options.match_str + name = "Replace" + optname = "replace" + implements = ["handleResponse","handleHeader","connectionMade"] + has_opts = True + desc = "Replace arbitrary content in HTML content" + + def initialize(self,options): + '''Called if plugin is enabled, passed the options namespace''' + self.options = options + self.search_str = options.search_str self.replace_str = options.replace_str - if self.options.preserve_cache: - self.implements.remove("handleHeader") - self.implements.remove("connectionMade") + if self.options.keep_cache: + self.implements.remove("handleHeader") + self.implements.remove("connectionMade") - self.ctable = {} - self.dtable = {} - self.mime = "text/html" - + self.ctable = {} + self.dtable = {} + self.mime = "text/html" + print "[*] Replace plugin online" - def handleResponse(self,request,data): - ip,hn,mime = self._get_req_info(request) + def handleResponse(self,request,data): + ip,hn,mime = self._get_req_info(request) - if self._should_replace(ip,hn,mime) and (not self.replace_str==self.search_str==None) and (not self.search_str==""): - data = self.replace(self.search_str, self.replace_str) + if self._should_replace(ip,hn,mime) and (not self.replace_str==self.search_str==None) and (not self.search_str==""): + data = data.replace(self.search_str, self.replace_str) + self.ctable[ip] = time.time() + self.dtable[ip+hn] = True - self.ctable[ip] = time.time() - self.dtable[ip+hn] = True + logging.info("%s [%s] Replaced '%s' with '%s'" % (request.client.getClientIP(), request.headers['host'], self.search_str, self.replace_str)) - logging.info("%s [%s] Replaced '%s' with '%s'" % (request.client.getClientIP(), request.headers['host'], self.match_str, self.replace_str)) - - return {'request':request,'data':data} - + return {'request':request,'data':data} + return - def add_options(self,options): - options.add_argument("--replace-str",type=str,default="",help="String you would like to replace.") - options.add_argument("--search-str",type=str,default="",help="String you would like to replace --replace-str with. Default: '' (empty string)") - options.add_argument("--preserve-cache",action="store_true",help="Don't kill the server/client caching.") + def add_options(self,options): + options.add_argument("--replace-str",type=str,default="",help="String you would like to replace.") + options.add_argument("--search-str",type=str,default="",help="String you would like to replace --replace-str with. Default: '' (empty string)") + options.add_argument("--keep-cache",action="store_true",help="Don't kill the server/client caching.") - def _should_replace(self,ip,hn,mime): - return mime.find(self.mime)!=-1 - - def _get_req_info(self,request): - ip = request.client.getClientIP() - hn = request.client.getRequestHostname() - mime = request.client.headers['Content-Type'] - return (ip,hn,mime) + def _should_replace(self,ip,hn,mime): + return mime.find(self.mime)!=-1 + + def _get_req_info(self,request): + ip = request.client.getClientIP() + hn = request.client.getRequestHostname() + mime = request.client.headers['Content-Type'] + + return (ip,hn,mime) From d6f3405f718785b2ca827d17764c8a809435781c Mon Sep 17 00:00:00 2001 From: root Date: Fri, 18 Jul 2014 08:39:06 +1000 Subject: [PATCH 5/9] Added regex support. Plugin now takes a search and replace string (no regex supported) or a regex file. Regex file format is: \t Regex file contains pyton regexes so matching groups can be used --- plugins/Replace.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/plugins/Replace.py b/plugins/Replace.py index 7d6261b..6fb22fc 100644 --- a/plugins/Replace.py +++ b/plugins/Replace.py @@ -15,11 +15,16 @@ class Replace(CacheKill,Plugin): self.options = options self.search_str = options.search_str self.replace_str = options.replace_str + self.regex_file = options.regex_file if self.options.keep_cache: self.implements.remove("handleHeader") self.implements.remove("connectionMade") + if self.search_str==self.replace_str=="" and self.regex_file is None: + print "[*] Please provide a search and replace string or a regex file" + quit() + self.ctable = {} self.dtable = {} self.mime = "text/html" @@ -29,18 +34,27 @@ class Replace(CacheKill,Plugin): def handleResponse(self,request,data): ip,hn,mime = self._get_req_info(request) - if self._should_replace(ip,hn,mime) and (not self.replace_str==self.search_str==None) and (not self.search_str==""): - data = data.replace(self.search_str, self.replace_str) + if self._should_replace(ip,hn,mime): + + if self.search_str==self.replace_str!="": + data = data.replace(self.search_str, self.replace_str) + logging.info("%s [%s] Replaced '%s' with '%s'" % (request.client.getClientIP(), request.headers['host'], self.search_str, self.replace_str)) + + if self.regex_file is not None: + for line in self.regex_file: + replaceRegex = line.split("\t") + data = re.sub(replaceRegex[0], replaceRegex[1], data) + logging.info("%s [%s] Replaced '%s' with '%s'" % (request.client.getClientIP(), request.headers['host'], replaceRegex[0], replaceRegex[1])) + self.ctable[ip] = time.time() self.dtable[ip+hn] = True - logging.info("%s [%s] Replaced '%s' with '%s'" % (request.client.getClientIP(), request.headers['host'], self.search_str, self.replace_str)) - return {'request':request,'data':data} return def add_options(self,options): + options.add_argument("--regex-file",type=file,help="Load file with regexes") options.add_argument("--replace-str",type=str,default="",help="String you would like to replace.") options.add_argument("--search-str",type=str,default="",help="String you would like to replace --replace-str with. Default: '' (empty string)") options.add_argument("--keep-cache",action="store_true",help="Don't kill the server/client caching.") From 5c1dbb35969a3f99b6cf1eca7edc237e2b2256e6 Mon Sep 17 00:00:00 2001 From: Ruben Date: Fri, 18 Jul 2014 14:29:55 +1000 Subject: [PATCH 6/9] Try except added to re.sub to prevent plugin from crashing if incorrect regexes where provided. Removed default values for search_str and replace_str --- plugins/Replace.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/plugins/Replace.py b/plugins/Replace.py index 6fb22fc..75198bb 100644 --- a/plugins/Replace.py +++ b/plugins/Replace.py @@ -21,7 +21,7 @@ class Replace(CacheKill,Plugin): self.implements.remove("handleHeader") self.implements.remove("connectionMade") - if self.search_str==self.replace_str=="" and self.regex_file is None: + if (self.search_str==self.replace_str==None or self.search_str==self.replace_str=="") and self.regex_file is None: print "[*] Please provide a search and replace string or a regex file" quit() @@ -36,15 +36,21 @@ class Replace(CacheKill,Plugin): if self._should_replace(ip,hn,mime): - if self.search_str==self.replace_str!="": + # Did the user provide us a search and replace str? + if self.search_str==self.replace_str!=None and self.search_str==self.replace_str!="": data = data.replace(self.search_str, self.replace_str) logging.info("%s [%s] Replaced '%s' with '%s'" % (request.client.getClientIP(), request.headers['host'], self.search_str, self.replace_str)) + # DI the user provide us with a regex file? if self.regex_file is not None: for line in self.regex_file: replaceRegex = line.split("\t") - data = re.sub(replaceRegex[0], replaceRegex[1], data) - logging.info("%s [%s] Replaced '%s' with '%s'" % (request.client.getClientIP(), request.headers['host'], replaceRegex[0], replaceRegex[1])) + try: + data = re.sub(replaceRegex[0], replaceRegex[1], data) + + logging.info("%s [%s] Replaced '%s' with '%s'" % (request.client.getClientIP(), request.headers['host'], replaceRegex[0], replaceRegex[1])) + except Exception, e: + logging.error("%s [%s] Your provided regex (%s) or replace value (%s) is empyt or invalid. Please debug your provided regex(es)" % (request.client.getClientIP(), request.headers['host'], replaceRegex[0], replaceRegex[1])) self.ctable[ip] = time.time() self.dtable[ip+hn] = True @@ -54,9 +60,9 @@ class Replace(CacheKill,Plugin): return def add_options(self,options): - options.add_argument("--regex-file",type=file,help="Load file with regexes") - options.add_argument("--replace-str",type=str,default="",help="String you would like to replace.") - options.add_argument("--search-str",type=str,default="",help="String you would like to replace --replace-str with. Default: '' (empty string)") + options.add_argument("--replace-str",type=str,help="String you would like to replace.") + options.add_argument("--search-str",type=str,help="String you would like to replace --replace-str with. Default: '' (empty string)") + options.add_argument("--regex-file",type=file,help="Load file with regexes. File format: [tab][new-line]") options.add_argument("--keep-cache",action="store_true",help="Don't kill the server/client caching.") def _should_replace(self,ip,hn,mime): From 3fb5f3d20dd301f89888b18320fb6d416aad36c4 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 18 Jul 2014 20:29:08 +1000 Subject: [PATCH 7/9] Fixed bug where plugin stopped replacing --- plugins/Replace.py | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/plugins/Replace.py b/plugins/Replace.py index 75198bb..fa0499f 100644 --- a/plugins/Replace.py +++ b/plugins/Replace.py @@ -21,10 +21,15 @@ class Replace(CacheKill,Plugin): self.implements.remove("handleHeader") self.implements.remove("connectionMade") - if (self.search_str==self.replace_str==None or self.search_str==self.replace_str=="") and self.regex_file is None: + if self.search_str==self.replace_str=="" and self.regex_file is None: print "[*] Please provide a search and replace string or a regex file" quit() + self.regexes = [] + if self.regex_file is not None: + for line in self.regex_file: + self.regexes.append(line.strip().split("\t")) + self.ctable = {} self.dtable = {} self.mime = "text/html" @@ -35,22 +40,20 @@ class Replace(CacheKill,Plugin): ip,hn,mime = self._get_req_info(request) if self._should_replace(ip,hn,mime): - # Did the user provide us a search and replace str? - if self.search_str==self.replace_str!=None and self.search_str==self.replace_str!="": + if self.search_str!="" and self.replace_str!="": data = data.replace(self.search_str, self.replace_str) logging.info("%s [%s] Replaced '%s' with '%s'" % (request.client.getClientIP(), request.headers['host'], self.search_str, self.replace_str)) - # DI the user provide us with a regex file? - if self.regex_file is not None: - for line in self.regex_file: - replaceRegex = line.split("\t") - try: - data = re.sub(replaceRegex[0], replaceRegex[1], data) - logging.info("%s [%s] Replaced '%s' with '%s'" % (request.client.getClientIP(), request.headers['host'], replaceRegex[0], replaceRegex[1])) - except Exception, e: - logging.error("%s [%s] Your provided regex (%s) or replace value (%s) is empyt or invalid. Please debug your provided regex(es)" % (request.client.getClientIP(), request.headers['host'], replaceRegex[0], replaceRegex[1])) + # Did the user provide us with a regex file? + for regex in self.regexes: + try: + data = re.sub(regex[0], regex[1], data) + + logging.info("%s [%s] Replaced '%s' with '%s'" % (request.client.getClientIP(), request.headers['host'], regex[0], regex[1])) + except Exception, e: + logging.error("%s [%s] Your provided regex (%s) or replace value (%s) is empyt or invalid. Please debug your provided regex(es)" % (request.client.getClientIP(), request.headers['host'], regex[0], regex[1])) self.ctable[ip] = time.time() self.dtable[ip+hn] = True @@ -60,8 +63,8 @@ class Replace(CacheKill,Plugin): return def add_options(self,options): - options.add_argument("--replace-str",type=str,help="String you would like to replace.") - options.add_argument("--search-str",type=str,help="String you would like to replace --replace-str with. Default: '' (empty string)") + options.add_argument("--replace-str",type=str,default="",help="String you would like to replace.") + options.add_argument("--search-str",type=str,default="",help="String you would like to replace --replace-str with. Default: '' (empty string)") options.add_argument("--regex-file",type=file,help="Load file with regexes. File format: [tab][new-line]") options.add_argument("--keep-cache",action="store_true",help="Don't kill the server/client caching.") From 60e8856d365f2cf8003980a9fddc5bacfee9948a Mon Sep 17 00:00:00 2001 From: root Date: Fri, 18 Jul 2014 20:48:36 +1000 Subject: [PATCH 8/9] Cleanup --- plugins/Replace.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/plugins/Replace.py b/plugins/Replace.py index fa0499f..50238d6 100644 --- a/plugins/Replace.py +++ b/plugins/Replace.py @@ -11,25 +11,25 @@ class Replace(CacheKill,Plugin): desc = "Replace arbitrary content in HTML content" def initialize(self,options): - '''Called if plugin is enabled, passed the options namespace''' self.options = options + self.search_str = options.search_str self.replace_str = options.replace_str self.regex_file = options.regex_file - if self.options.keep_cache: - self.implements.remove("handleHeader") - self.implements.remove("connectionMade") - - if self.search_str==self.replace_str=="" and self.regex_file is None: - print "[*] Please provide a search and replace string or a regex file" - quit() + if (self.search_str==None or self.search_str=="") and self.regex_file is None: + sys.exit("[*] Please provide a search string or a regex file") self.regexes = [] if self.regex_file is not None: + print "[*] Loading regexes from file" for line in self.regex_file: self.regexes.append(line.strip().split("\t")) + if self.options.keep_cache: + self.implements.remove("handleHeader") + self.implements.remove("connectionMade") + self.ctable = {} self.dtable = {} self.mime = "text/html" @@ -40,8 +40,8 @@ class Replace(CacheKill,Plugin): ip,hn,mime = self._get_req_info(request) if self._should_replace(ip,hn,mime): - # Did the user provide us a search and replace str? - if self.search_str!="" and self.replace_str!="": + + if self.search_str!=None and self.search_str!="": data = data.replace(self.search_str, self.replace_str) logging.info("%s [%s] Replaced '%s' with '%s'" % (request.client.getClientIP(), request.headers['host'], self.search_str, self.replace_str)) @@ -51,9 +51,9 @@ class Replace(CacheKill,Plugin): try: data = re.sub(regex[0], regex[1], data) - logging.info("%s [%s] Replaced '%s' with '%s'" % (request.client.getClientIP(), request.headers['host'], regex[0], regex[1])) + logging.info("%s [%s] Occurances matching '%s' replaced with '%s'" % (request.client.getClientIP(), request.headers['host'], regex[0], regex[1])) except Exception, e: - logging.error("%s [%s] Your provided regex (%s) or replace value (%s) is empyt or invalid. Please debug your provided regex(es)" % (request.client.getClientIP(), request.headers['host'], regex[0], regex[1])) + logging.error("%s [%s] Your provided regex (%s) or replace value (%s) is empty or invalid. Please debug your provided regex(es)" % (request.client.getClientIP(), request.headers['host'], regex[0], regex[1])) self.ctable[ip] = time.time() self.dtable[ip+hn] = True @@ -63,8 +63,8 @@ class Replace(CacheKill,Plugin): return def add_options(self,options): + options.add_argument("--search-str",type=str,default=None,help="String you would like to replace --replace-str with. Default: '' (empty string)") options.add_argument("--replace-str",type=str,default="",help="String you would like to replace.") - options.add_argument("--search-str",type=str,default="",help="String you would like to replace --replace-str with. Default: '' (empty string)") options.add_argument("--regex-file",type=file,help="Load file with regexes. File format: [tab][new-line]") options.add_argument("--keep-cache",action="store_true",help="Don't kill the server/client caching.") From 25e46dca2fef7a12c2e24da92c4ec46f6daad2a7 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 18 Jul 2014 20:55:55 +1000 Subject: [PATCH 9/9] Added Linkrewriter description to plugin list --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 37982ac..c2497cd 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Availible modules: - Inject - Inject arbitrary content into HTML content - JavaPwn - Performs drive-by attacks on clients with out-of-date java browser plugins - jskeylogger - Injects a javascript keylogger into clients webpages +- Linkrewriter - Rewrites all href attributes to a specified url - Replace - Replace arbitary content in HTML content - SMBAuth - Evoke SMB challenge-response auth attempts - Upsidedownternet - Flips images 180 degrees