- Install Node 7
- Open ports UDP 53 and TCP 80 and 8081 on your firewall
- Run
npm install
- Start everything with
sudo node start.js
on Linux/OS X ornode start.js --disable-curses --logfile debug.log
on Windows - Point your Switch to the DNS server
- Go to the eShop or another area that will trigger the captive portal
- Watch the shell connect
The default way to work with PegaSwitch is via the shell. Type help
after the Switch connects to get a list of commands.
To disable the shell (and just work with the API), comment out the following line in exploit/main.js
:
setupListener(sc);
64-bit values (pointers, primarily) are represented using a JavaScript array containing [lo, hi]
, where each is 32-bit.
paddr(address)
-- Convert a 64-bit value into a hex string representationadd2(a, b)
-- Adds two 64-bit values or adds a 64-bit value and a numbernullptr(address)
-- Returns true if the given 64-bit value is 0eq(a, b)
-- Returns true if the two 64-bit values are equalparseAddr(address)
-- Takes a hex string and parses into a 64-bit value
Sploitcore is the centerpoint of PegaSwitch, providing all of the core functionality and most of the important API. These are all methods on the sploitcore object.
dumpaddr(address, count)
-- Takes an address and a number of 32-bit values to logread4(address, offset)
-- Reads a 32-bit value fromaddress + offset * 4
read8(address, offset)
-- Reads a 64-bit value fromaddress + offset * 4
write4(value, address, offset)
-- Writes a 32-bit value toaddress + offset * 4
write8(value, address, offset)
-- Writes a 64-bit value toaddress + offset * 4
memview(address, size, cb)
-- Callscb
with an ArrayBuffer pointing to the view of memory requested. DO NOT keep that view or any object using it around; you will tank the GC and your Switch will crashgetAddr(obj)
-- Returns the address of a given JavaScript objectmref(offset)
-- Returns the address of the main module (the application binary itself) plus the given (32-bit) offsetgetBase()
-- Returns the base address of WebKitgetSP()
-- Returns the current stack pointer (current as of a function call in JS), primarily useful for JOP/ROP chainsmalloc(bytes)
-- Returns an address to an allocated bufferfree(addr)
-- Frees a bufferbridge
andcall
-- Documented belowsvc(id, registers, dump_regs)
-- Call a specific SVC, passing an array of registers and optionally dumping all regs (dump_regs == true/false)getTLS()
-- Gets address of TLSstr2buf(str)
-- Allocates a buffer for a null-terminated string and returns the addressreadString(addr, length)
-- Reads a string fromaddr
. If length is not passed or -1, the string is expected to be null-terminatedgc()
-- Force garbage collection
sploitcore.call
allows you to call native functions by address. It takes the following parameters, with the first being required:
address
- Function address. Either a 32-bit offset from the main module address, or a 64-bit absolute pointerargs
- Array of arguments, to go in x0+fargs
- Array of floats, to go in d0+registers
- Array of raw registers (x16 and x30 not assignable)dump_regs
- Boolean to set whether registers should be dumped upon return
This function always returns the 64-bit value in x0.
Bridge allows you to wrap a native function into a JavaScript function. Example:
var strlen = sc.bridge(0x43A6E8, int, char_p);
log(strlen('foo')); // Logs 3 to the console
The first parameter is the address (same format as call
), second is the return type, the rest are arguments.
The following are valid types:
null
-- Used forvoid
returnsint
void_p
-- Arbitrary pointerchar_p
-- String pointerfloat
-- Floating point argument; currently only supported for arguments, not returns
You can override the IP it responds with the --ip
argument to node start.js
. eg sudo node start.js --ip 1.2.3.4
The full curses interface on Windows is supported using WSL only. We will not provide support for native cmd.exe as it lacks necessary functionality.
You can, however, use --disable-curses
and write the debug log out to a file for reading.