Palantir is a Lua scriptable, portable, tiny reverse shell, using a human readable protocol written in C and Lua.
$ cmake . && make
Required:
Supported:
$ palantir [-dhlv] [-a TOKEN] HOST PORT
d
Start as serverh
Shows the usage informationl
Shows the licensev
Shows the versiona
Authentication token
-- exit
Shutdown client-- halt
Shutdown server
All input will be evaluated and execute as Lua commands. The internal function
os.shell
will execute system commands by using the users default shell and
return the results where strerr
will be mapped to stdout
.
- Tab autocompletes keywords, functions, globals and commands
- Ctrl+n inserts a new line
- Ctrl+x termintates the shell
Only available if compiled with
readline
support.
A user specific profile can
be placed under ~/.palantir.lua
.
New global constants and functions will be defined which contain all shell specific extensions.
SERVER
The command line optiond
TOKEN
The command line argumenta
HOST
The command line argumentHOST
PORT
The command line argumentPORT
HOME
The stated users home directoryBUILD
The compiled build informationDEBUG
The compiled debug flagVERSION
The compiled version number
The network functions share one socket and are not meant to be re-opened:
net.server(host, port)
net.client(host, port)
net.connect(host, port)
net.listen(host, port)
net.accept()
net.recv()
net.send(command, param)
The operating system functions will extend the Lua build-in os
library:
os.path(path)
os.prompt(prompt)
os.shell(command)
os.sleep(milliseconds)
The default shell functionality can be extended by creating custom event callbacks in the users profile. There are four different event sources:
server_ready()
Called when the server is connectedserver_<command>(param)
Called when the server receives a<command>
client_<command>(param)
Called when the client receives a<command>
client_prompt(line)
Called when the client processes a prompt
All callbacks except server_ready
must return a boolean
. In case true
is returned, all further processing will be prevented. The client_ready
callback must return a string
, which will be displayed by the client.
The <command>
names will be converted to lowercase.
Here is an example on how to implement an simple Echo Server:
function server_ready()
return 'This is an echo server'
end
function server_echo(param)
net.send('ECHO', param)
return true
end
function client_echo(param)
io.write(param .. '\n')
return true
end
function client_prompt(line)
net.send('ECHO', line)
return true
end
The Palantir protocol consists of two layers:
- Network Layer (transportation handled by
C
) - Command Layer (interpretation handled by
Lua
)
A network frame is build according to the following format:
CHECKSUM (4 bytes) | SIZE (4 bytes) | DATA (n bytes)
The CHECKSUM
is a bitwise CRC-32 over the DATA
field only.
If an authentication TOKEN
is provided, the network frames checksum will be
pre-feed with the CRC-32 of the token before calculation.
A command is build according to the following format:
COMMAND (4 bytes) | BLANK (1 byte) | PARAM (n bytes)
Each command consists of a 5
byte command header followed by 0
to n
bytes of param
. A command header will end with a single blank
character
for better readability.
If an unknown command is received, no error will be raised, instead it will be ignored by the client and server.
HELO <user>@<host>:<path>
TEXT <text>
EXEC <command>
PATH <path>
HALT
Server: HELO root@localhost:/
Client: PATH var
Server: HELO root@localhost:/var
Client: EXEC return os.shell('echo hello')
Server: TEXT hello
Server: HELO root@localhost:/var
Client: HALT
Licensed under the terms of the MIT License.