Skip to content

Instantly share code, notes, and snippets.

@kornelski
Created January 3, 2011 00:55
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save kornelski/762984 to your computer and use it in GitHub Desktop.
Hack me!
(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.
})()();
@kornelski
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment