Hack me!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function(){ | |
// prevent exceptions from escaping outside function (backtrace could be revealing) | |
try { | |
// this is ASCII 'Secret!' represented as integers | |
var secret = [1399153522,1702109440]; | |
var secretlength = 7; | |
// function that contains secret must finish executing before anything untrusted is called, | |
// otherwise source of arguments.callee.caller would reveal the secret | |
return function(){ | |
try { | |
// this is just minified off-the-shelf implementation of sha1 that takes array of integers (encoded 4 chars per element) | |
function sha1bin(x,L){var i,j=0,w=[],a=1732584193,b=-271733879,c=-1732584194,d=271733878,e=-1009589776,f=0xFFFF,H='0123456789abcdef';function S(x,y,l){l=(x&f)+(y&f);return(x>>16)+(y>>16)+(l>>16)<<16|l&f}function R(n,c){return n<<c|n>>>32-c}x[L>>5]|=128<<24-L%32;x[(L+64>>9<<4)+15]=L;for(;j<x.length;j+=16){var A=a,B=b,C=c,D=d,E=e;for(i=0;i<80;i++){t=S(S(R(a,5),i<20?b&c|~b&d:i<40?b^c^d:i<60?b&c|b&d|c&d:b^c^d),S(S(e,w[i]=i<16?x[j+i]:R(w[i-3]^w[i-8]^w[i-14]^w[i-16],1)),i<20?1518500249:i<40?1859775393:i<60?-1894007588:-899497514));e=d;d=c;c=R(b,30);b=a;a=t}a=S(a,A);b=S(b,B);c=S(c,C);d=S(d,D);e=S(e,E)}x=[a,b,c,d,e];j='';for(i=0;i<20;i++){j+=H[(x[i>>2]>>(3-i%4)*8+4)&15]+H[(x[i>>2]>>(3-i%4)*8)&15]}return j} | |
// I'm assuming it's not possible to swap or attach getter to any part of window.location.href | |
var href = window.location.href; | |
var href_verification = '', href_escaped = ''; | |
var char_code; | |
// Those are URL-safe characters. Since I can't trust charCodeAt() to return real values, I'll rebuild the string using this map and compare to the original. | |
var char_code_to_char = {33:"!", 35:"#", 36:"$", 37:"%", 38:"&", 39:"'", 40:"(", 41:")", 42:"*", 43:"+", 44:",", 45:"-", 46:".", 47:"/", 48:"0", 49:"1", 50:"2", 51:"3", 52:"4", 53:"5", 54:"6", 55:"7", 56:"8", 57:"9", 58:":", 59:";", 61:"=", 63:"?", 64:"@", 65:"A", 66:"B", 67:"C", 68:"D", 69:"E", 70:"F", 71:"G", 72:"H", 73:"I", 74:"J", 75:"K", 76:"L", 77:"M", 78:"N", 79:"O", 80:"P", 81:"Q", 82:"R", 83:"S", 84:"T", 85:"U", 86:"V", 87:"W", 88:"X", 89:"Y", 90:"Z", 91:"[", 93:"]", 94:"^", 95:"_", 97:"a", 98:"b", 99:"c", 100:"d", 101:"e", 102:"f", 103:"g", 104:"h", 105:"i", 106:"j", 107:"k", 108:"l", 109:"m", 110:"n", 111:"o", 112:"p", 113:"q", 114:"r", 115:"s", 116:"t", 117:"u", 118:"v", 119:"w", 120:"x", 121:"y", 122:"z", 123:"{", 124:"|", 125:"}"}; | |
// calling escape() is not an option, so here's custom solution. | |
var char_code_to_escaped_char = {37:"%25", 38:"%26", 39:"%27", 43:"%2B", 47:"%2F", 59:"%3B", 61:"%3D", 63:"%3F", 94:"%5E", 124:"%7C"}; | |
for(var i=0; i < href.length; i++) { | |
// cast in case charCodeAt returned object with evil valueOf | |
char_code = 0+href.charCodeAt(i); | |
if (!(char_code in char_code_to_char)) return; | |
href_verification += char_code_to_char[char_code]; | |
href_escaped += char_code_to_escaped_char[char_code] || char_code_to_char[char_code]; | |
// simply appends to secret array. It's bit-twiddling equivalent of "secret" + href | |
secret[(i+secretlength) >> 2] |= char_code << 24 - (i+secretlength)*8 % 32; | |
} | |
// if charCodeAt lied, then char_code_to_char was mapped to different letter, and won't equal href. | |
if (href_verification != href) return; | |
// hashed secret+url and url is sent to server, allowing server to verify authenticity of the URL. | |
// (although hashing method should use HMAC to prevent extension attacks) | |
alert('window.location.href = http://example.com?sha1=' + sha1bin(secret,8*(secretlength+href.length)) + '&url=' + href_escaped); | |
} catch(e) {} | |
} | |
} catch(e) {} | |
// arguments could be another way to store the secret - the upside is that source of the function wouldn't contain the secret. | |
})()(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is code of a bookmarklet that is supposed to read URL of page it's executed in a way that cannot be spoofed with CSRF.
Description on JSMentors list
Deletion of
String.prototype.charCodeAt
reverting to built-in function is actually a WebKit bug, so I've removed that bit.