Geckome  
\-------  
Another web challenge, this time served at
http://d2b24dd8.quals2018.oooverflow.io. After logging in with the provided
credentials `[email protected]:admin`, we are redirected to the following
[browser test page](http://d2b24dd8.quals2018.oooverflow.io/browsertest.php):

```html  
<html>  
<head>  
<title>Testing the browser...</title>  
<style>  
#animated_div {  
width:120px;  
height:47px;  
background: #92B901;  
color: #ffffff;  
position: relative;  
font-weight:bold;  
font-size:20px;  
padding:10px;  
-webkit-animation:animated_div 5s 1;  
border-radius:5px;  
-webkit-border-radius:5px;  
}

@-webkit-keyframes animated_div  
{  
0% {-webkit-transform: rotate(0deg);left:0px;}  
25% {-webkit-transform: rotate(20deg);left:0px;}  
50% {-webkit-transform: rotate(0deg);left:500px;}  
55% {-webkit-transform: rotate(0deg);left:500px;}  
70% {-webkit-transform: rotate(0deg);left:500px;background:#1ec7e6;}  
100% {-webkit-transform: rotate(-360deg);left:0px;}  
}

  
</style>  
</head>

<video id="v" autoplay> </video>  
  

Click me to print the page.

  
<link rel="prerender" href="https://news.ycombinator.com/">  
<div id="animated_div">OOOverflow Securityyy</div>  
<script>  
var f = "";  
if (navigator.onLine)  
f += "o";  
f += navigator.vendor;  
function p() {  
window.print();  
}  
/* incompatible  
window.onbeforeprint = function () {  
// some code  
}  
*/  
f += navigator.mimeTypes.length;  
x=0; for ( i in navigator ) { x += 1; } f += x;  
x=0; for ( i in window ) { x += 1; } f += x;  
// hash  
function str2ab(str) {  
var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char  
var bufView = new Uint16Array(buf);  
for (var i=0, strLen=str.length; i<strLen; i++) {  
bufView[i] = str.charCodeAt(i);  
}  
return buf;  
}  
function sha256(str) {  
// We transform the string into an arraybuffer.  
var buffer = str2ab(str);  
return crypto.subtle.digest({name:"SHA-256"}, buffer).then(function (hash) {  
return hex(hash);  
});  
}

function hex(buffer) {  
var hexCodes = [];  
var view = new DataView(buffer);  
for (var i = 0; i < view.byteLength; i += 4) {  
// Using getUint32 reduces the number of iterations needed (we process 4 bytes
each time)  
var value = view.getUint32(i)  
// toString(16) will give the hex representation of the number without padding  
var stringValue = value.toString(16)  
// We use concatenation and slice for padding  
var padding = '00000000'  
var paddedValue = (padding + stringValue).slice(-padding.length)  
hexCodes.push(paddedValue);  
}

// Join all the hex strings into one  
return hexCodes.join("");  
}  
f += navigator.plugins[0].filename;  
f += navigator.plugins[1].description;

sha256(f).then(function(digest) {  
if (digest ==
"31c6b7c46ff55afc8c5e64f42cc9b48dde6a04b5ca434038cd2af8bd3fd1483a") {  
window.location = "flag.php?f=" +btoa(f);  
} else {  
x = document.getElementById("animated_div");  
z = document.createElement("div");  
z.innerHTML = "Test Failed";  
z.id="animated_div";  
setTimeout(function() {x.appendChild(z)}, 5000);  
}  
});  
console.log("FIN");  
</script>  
</html>  
```

A quick overview of the inline script suggests that the flag can be accessed
by the admin iff a matching browser is used. The client is checked for the
presence of certain plugins, the ability to execute selected APIs outside
secure-contexts such as `SubtleCrypto` and lack of support for
`window.onbeforeprint` (see the commented out code in the js). Moreover,
several `-webkit-` prefixed CSS rules wink at WebKit-powered user agents.

By cross-checking all the conditions, the list of possible candidates reduced
to Google Chrome between versions 37 and 39 (included). At this point it was
just a matter of running these [old browsers](https://google-
chrome.en.uptodown.com/ubuntu/old) inside a VM, dump the list of plugins along
with other features exploited by the fingerprinting function and use a bit of
(brute) force.

```python  
import hashlib  
import sys

h = '31c6b7c46ff55afc8c5e64f42cc9b48dde6a04b5ca434038cd2af8bd3fd1483a'

mime_types = range(0, 10)  
navigator = range(0, 46)  
windows = range(150, 231)

vendors = ['Google Inc.']  
plugin0_filenames = ['', 'libwidevinecdmadapter.so',
'libppGoogleNaClPluginChrome.dll', 'undefined', 'libpepflashplayer.dll',
'libppGoogleNaClPluginChrome.so', 'internal-remoting-viewer',
'libpepflashplayer.so', 'internal-nacl-plugin', 'internal-pdf-viewer',
'mhjfbmdgcfjbbpaeojofohoefgiehjai', 'libwidevinecdmadapter.dll', 'libpdf.so',
'libpdf.dll']  
plugin1_descr = ['', 'This plugin allows you to securely access other
computers that have been shared with you. To use this plugin you must first
install the Chrome Remote Desktop webapp.', 'undefined', 'Shockwave Flash 14.0
r0', 'Enables Widevine licenses for playback of HTML audio/video content.',
'Portable Document Format', 'Enables Widevine licenses for playback of HTML
audio/video content. (version: Something fresh)'] + ['Shockwave Flash {}.{}
r0'.format(maj, mino) for maj in range(18) for mino in range(5)]

for ven in vendors:  
for mt in mime_types:  
for nav in navigator:  
for win in windows:  
for p0 in plugin0_filenames:  
for p1 in plugin1_descr:  
# simulate utf-16 encoding  
data = ''.join(c+'\x00' for c in 'o{}{}{}{}{}{}'.format(ven, mt, nav, win, p0,
p1))  
if h == hashlib.sha256(data).hexdigest():  
print('[FOUND] {}'.format(data))  
sys.exit(0)  
```

The script returns the string `oGoogle Inc.828186libpepflashplayer.soThis
plugin allows you to securely access other computers that have been shared
with you. To use this plugin you must first install the Chrome Remote Desktop
webapp.` that can be used, in a base64-encoded form, to access the flag:

```bash  
$ curl
'http://d2b24dd8.quals2018.oooverflow.io/flag.php?f=b0dvb2dsZSBJbmMuODI4MTg2bGlicGVwZmxhc2hwbGF5ZXIuc29UaGlzIHBsdWdpbiBhbGxvd3MgeW91IHRvIHNlY3VyZWx5IGFjY2VzcyBvdGhlciBjb21wdXRlcnMgdGhhdCBoYXZlIGJlZW4gc2hhcmVkIHdpdGggeW91LiBUbyB1c2UgdGhpcyBwbHVnaW4geW91IG11c3QgZmlyc3QgaW5zdGFsbCB0aGUgPGEgaHJlZj0iaHR0cHM6Ly9jaHJvbWUuZ29vZ2xlLmNvbS9yZW1vdGVkZXNrdG9wIj5DaHJvbWUgUmVtb3RlIERlc2t0b3A8L2E+IHdlYmFwcC4='  
OOO{th3r3c@nb30nly0n3br0ws3r!}  
```

Flag: `OOO{th3r3c@nb30nly0n3br0ws3r!}`

Original writeup
(https://mhackeroni.it/archive/2018/05/20/defconctfquals-2018-all-
writeups.html#geckome).