OneOS protocols#
OneOS is an operating system built by Oliver Cooper (oeed) around their programs, which are mostly built around the Bedrock GUI framework.
The protocols are not security-aware, for the most part. Apart from the major security issues described below, message validation is poorly handled and very sensitive to any packet error. They should only be used for compatibility with existing OneOS / Bedrock ecosystems.
Message formats#
The modem usage on OneOS is mainly thought for wireless modems, as the
module implementing functions to handle this format is called Wireless
and some mechanisms are an attempt at distinguishing between packets sent
on a given channel.
All messages in the protocols used by OneOS are tables that are serialized using textutils.serialize (which means modem messages are actually strings with OneOS), containing the following members:
content
: the serialized content using textutils.serialize.senderID
: the computer numerical identifier, obtained through os.getComputerID.senderName
: the computer label, obtained through os.getComputerLabel.channel
: the channel on which the message is present.replyChannel
: an indication to the received about which channel to reply on; should be equal to the “reply channel” sent along the line.messageID
: the message numerical identifier, either picked at pseudorandom between 0 and 10000 or chosen by the protocol implementation.destinationID
: the destination computer identifier, which is based on its identifier returned by os.getComputerID once again. This member isnil
when broadcasting.
The message identifier is used for ignoring a sent message when receiving,
and the destinationID
serves for ignoring messages for other computers
on the given channel.
Notice that reply channels are always the request channel plus one.
This is actually what the Wireless
code does in OneOS if you don’t
explicitely define a reply channel (see SendMessage
:
reply = reply or channel + 1
).
Using the OneOS Wireless
module, more specifically the synchronous function
to receive messages RecieveMessage
(the typo on “receive” is everywhere in
OneOS…), the default timeout when unspecified is 1 second.
OneOS Ping Protocol#
This protocol uses two modem channels:
4201
(a.k.aPing
) for sending ping “requests”.4202
(a.k.aPingReply
) for sending ping replies.
These two channels are used for exchanging OneOS messages (see Message formats).
Ping “requests” are supposed to have the string “Ping!” set as the content, and ping replies are supposed to have the string “Pong!” set as the content. Any ping requests containing something else than “Ping!” shall not be answered.
OneOS Turtle Protocol#
The protocol uses two modem channels:
4202
(a.k.aTurtleRemote
) for sending turtle requests.4203
(a.k.aTurtleRemoteReply
) for replying to turtle requests.
These channels are used for exchanging OneOS messages (see
Message formats), in a request/response manner: requests are
emitted on the TurtleRemote
channel, and replies are emitted
on the TurtleRemoteReply
.
If the sent message on the TurtleRemote
is the “Ping!” string, then
the turtle responds with the “Pong!” string on the TurtleRemoteReply
channel. Otherwise, requests’ and replies’ contents are supposed to be tables,
where requests always define the action
key as a string to determine
the action type.
The device requesting a turtle to execute an action waits for a timeframe depending on which command it sent and the accompanying data.
Known requests are the following:
"move"
The turtle is asked to move a certain distance in a certain direction, using functions such as turtle.forward.
The request also defines the following fields:
direction
: the direction in which to move, amongst the following:"forward"
,"back"
,"up"
,"down"
.
distance
: the distance in blocks for the turtle to move.The device requesting the application waits for
1 + distance / 2
seconds.The turtle answers with the following fields:
success
: whether the turtle has succeeded to move as much as required (true
) or not (false
); in case the turtle has moved for less than the requested distance,false
will be returned.
distance
: the traveled distance, in blocks.
reason
: the reason, as a string (ifsuccess
isfalse
), ornil
.
"turn"
The turtle is asked to turn in a certain direction, using functions such as turtle.turnLeft.
The request also defines the following fields:
left
: a boolean indicating if the turn should be towards the left of the turtle (true
) or to the right of the turtle (right
).
turns
: the number of turns to make.The device requesting the application waits for
1 + turns / 2
seconds.The turtle answers with the following fields:
success
: whether the turtle has succeeded to turn as much as required (true
) or not (false
); in case the turtle has turned for less than the requested number of turns,false
will be returned.
turns
: the number of turns performed.
"place"
The turtle is asked to place a block in a given direction, using functions such as turtle.place.
The request also defines the following fields:
slot
: the slot in which to take the item to place.
direction
: the direction in which to place, which can beup
for placing up,down
for placing down, or any other value for placing in the direction the turtle is currently facing.The device requesting the action waits for 1.4 seconds.
The turtle answers with the following fields:
success
: whether the block has been placed or not.
"dig"
The turtle is asked to dig in a certain direction, using functions such as turtle.digUp.
The request also defines the following field:
direction
: the direction in which to dig, which can beup
for digging up,down
for digging down, or any other value for digging in the direction the turtle is currently facing.The device requesting the application waits for 1.4 seconds.
The turtle answers with the following fields:
success
: whether a block was broken (true
) or not (false
).
"attack"
The turtle is asked to attack, using a function such as turtle.attack.
The request also defines the following fields:
direction
: the direction in which to attack, which can beup
for attacking up,down
for attacking down, or any other value for attacking in the direction the turtle is currently facing.
times
: the number of times to attack, without delay, as a number.If the number of times to attack is equal to zero, then the turtle is supposed to attack once, and check if an entity is present. If that’s the case, then it sleeps for .4 seconds and attacks an other time. Success is determined by whether an entity was attacked the first time.
Otherwise, if the number of times to attack is more than zero, then the turtle attacks the given number of times; the success is determined by whether an entity was attacked on the last attack.
The device requesting the application waits for 9 seconds.
The turtle answers with the following fields:
success
: whether success has been achieved (true
), or not (false
); see the definition of it depending on the given number of times above.
"detect"
The turtle is asked to detect whether a solid block is in front of it or not, using a function such as turtle.detect.
The request also defines the following field:
direction
: the direction in which to detect, which can beup
for detecting up,down
for detecting down, or any other value for detecting in the direction the turtle is currently facing.The device requesting the application waits for 1.05 seconds.
The turtle answers with the following fields:
success
: whether a solid block is in front of the turtle in the given direction (true
) or not (false
).
"drop"
The turtle is asked to drop an item in the given direction, using a function such as turtle.drop.
The request also defines the following fields:
slot
: the slot in which to take the item to drop.
amount
: the amount of items to drop from the selected stack.
direction
: the direction in which to drop, which can beup
for dropping up,down
for dropping down, or any other value for dropping in the direction the turtle is currently facing.The device requesting the action waits for 1.05 seconds.
The turtle answers with the following fields:
success
: whether at least one item has been dropped (true
) or not (false
).
"suck"
The turtle is asked to suck an item from the given direction, using a function such as turtle.suck.
The request also defines the following fields:
slot
: the slot in which to suck the item to.
direction
: the direction from which to suck, which can beup
for sucking from top,down
for sucking from bottom, or any other value for sucking from the direction the turtle is currently facing.The device requesting the action waits for 1.05 seconds.
The turtle answers with the following fields:
success
: whether at least one item has been sucked (true
) or not (false
).
"compare"
The turtle is asked to compare an item in a given slot with a block in front of the turtle in a given direction, using a function such as turtle.compare.
The request also defines the following fields:
slot
: the slot in which to find the item to compare the block to.
direction
: the direction in which to look for the block to compare the item to, which can beup
for looking up,down
for looking down, or any other value for looking in the direction the turtle is currently facing.The device requesting the application waits for 1.05 seconds.
The turtle answers with the following fields:
success
: whether the item in the slot and the block looked at in the given direction are the same (true
) or not (false
).
"compareTo"
The turtle is asked to compare an item in a given slot with an item in another slot, using a function such as turtle.compareTo.
The request also defines the following fields:
slot
: the slot in which to find the first item.
otherSlot
: the slot in which to find the second item.The device requesting the application waits for 1.05 seconds.
The turtle answers with the following fields:
success
: whether the item in the two slots in the given direction are the same (true
) or not (false
).
"getState"
The turtle is asked to return its state, as a string. By default, this string is
"Idle"
, but it can be get and set over the protocol and used by a local application.The device requesting the application waits for 1.05 seconds.
The turtle answers with the following fields:
value
: the current state, as a string.
"setState"
The turtle is asked to set its state to the given value, as a string. By default, this string is
"Idle"
, but it can be set over the protocol and used by a local application.The request also defines the following fields:
value
: the new state of the turtle, as a string.The device requesting the application waits for 1.05 seconds.
The turtle answers with the following field:
success
: whether the state has been set successfully (true
) or not (false
).
"fuelLevel"
The turtle is asked to return its current fuel level, using a function such as turtle.getFuelLevel.
The device requesting the application waits for 1 second.
The turtle answers with the following field:
value
: the current fuel level of the turtle.
"refuel"
The turtle is asked to refuel, using a function such as turtle.refuel.
The request also defines the following field:
amount
: the amount of items to take (ifnil
, the default value is 64).The turtle then attempts to find a slot in its inventory with at least one item with fuel, and consumes at most the given amount.
The device requesting the application waits for 1.8 seconds (
1 + .05 * 16
).The turtle answers with the following fields:
success
: whether at least one fuel item has been consumed to refuel the turtle (true
) or not (false
).
slot
: the slot number at which the fuel item has been found and removed,nil
if no fuel item was consumed.
"itemCount"
The turtle is asked to return its item count, using a function such as turtle.getItemCount.
The request also defines the following field:
slot
: the number of the slot to check.The device requesting the application waits for 1 second.
The turtle answers with the following field:
value
: the value?
"itemSpace"
The turtle is asked to return its item space, using a function such as turtle.getItemSpace.
The request also defines the following field:
slot
: the number of the slot to check.The device requesting the application waits for 1 second.
The turtle answers with the following fields:
value
: the space left in the given slot, as a number.Note that in the OneOS source, the protocol is only implemented in a
Turtle
API and not used by a system application; I could not find any application online using this API…
OneOS Transmit Protocol#
This protocol is used by the Transmit application in OneOS. The idea behind this application is to send files (“sending mode”), or wait for other devices to send files to the current device (“receiving mode”).
The protocol uses the following channels:
4204
(a.k.aTransmitDiscovery
) for probing devices in receiving mode.4205
(a.k.aTransmitDiscoveryReply
) for sending replies to the probes described above.4206
(a.k.aTransmitRequest
) for asking a device to send a file to it.4207
(a.k.aTransmitRequestReply
) for replying to the request described above by a yes or a no.4208
(a.k.aTransmitSent
) for sending the file data in one go.
These five channels are used for exchanging OneOS messages (see Message formats).
Discovery is used by devices in sending mode for the device selection menu,
when the user wants to select to which devices it will try to transfer. Such
probes are done every second; it must use the “Discovery” string as the
message content on the TransmitDiscovery
channel, while requesting an
answer to the TransmitDiscoveryReply
channel. To these probes, the devices
in receiving modes must answer with a TransmitDiscoveryReply
with a table
as its payload, containing the following members:
id
: the identifier, as obtained through os.getComputerID.name
: the device name, as obtained through os.getComputerLabel.
Once the user has chosen the file and the device to which to send it to,
the device sends a message to the receiving device on the TransmitRequest
channel, as a table with the following members:
senderName
: the name of the device sending the transmit request, as obtained through os.getComputerLabel.fileName
: the name of the file to be sent.
Then the receiving device can display a pop-up to the user to choose if the
file is accepted or not. When the user has replied, the receiving device
answers the request on the TransmitRequestReply
channel as requested,
with a table with the following members as content:
accept
: a boolean indicating if yes or no the file has been accepted by the user.
If the file has been accepted, the sending device then sends a message on the
TransmitSend
channel targetted at the same receiving device, with a
table with the following members as the content:
data
: the data of the file, as the string.fileName
: the name of the file to be sent, should be the same as the one advertised in the message onTransmitRequest
earlier.
And the process ends here (there is no acknowledgment from the receiving device, it is supposed that the file arrived successfully).
This utility has major security issues, however they are not particularly inherent to the protocol and they can be mitigated in any reimplementation. The issues are the following:
The
fileName
field in the message on theTransmitSend
request can be different from the one advertised in the message onTransmitRequest
; and for saving the file, the utility uses the one in the former. This can be very misleading, if not a security issue. This can be mitigated by checking, at theTransmitSend
message reception if the file has already been approved.The
TransmitRequest
/TransmitRequestReply
step is actually completely optional, as the utility will gladly save any file you send to it. The mitigation quoted before should do the trick, as it requires the sender to get its request approved first.In order to save the file, the final path is obtained by appending the given file name to “/Desktop/Documents/” without sanitizing the input. This allows for path traversal attacks by setting the filename in the
TransmitSend
step to “../../startup” for example. Combined with the previous security vulnerability, this gives you a wormable attack that can affect any OneOS device as soon as it is in receiving mode. This vulnerability can be corrected through file name sanitization at both theTransmitRequest
andTransmitSend
steps.
The only limit that the mitigations brings is, you can only receiving one file
at a time with a given file name from a given sending device (because any
transmit request doesn’t have an ID that’s repercuted in the message on
the TransmitSend
message). That’s a totally acceptable limit for most
usages.
Ultimate Door Lock Protocol#
Ultimate Door Lock, also known as Door Lock on OneOS, is a program for locking doors using dedicated Pocket Computers (referred to as PDA in the code), which will (only) serve as “keys”, like NFC-enabled devices in the real world.
The application runs on both the computer dedicated to the door lock (and interacting with it through redstone), and the pocket computer, which must be dedicated to being the key as the door lock application is run at startup and must be running for the process to work.
The concept of the application is:
You register PDAs by putting them in a disk drive connected to the computer managing the door lock; a fingerprint will automatically be generated on the Pocket Computer, and this fingerprint will be added to a whitelist.
The door lock pings on a dedicated channel every .5 seconds.
If a PDA receives the ping on the given channel, it sends its fingerprint to a second channel dedicated to requests.
The door lock receives the request. If the received fingerprint is included in the whitelist and the request comes from within the distance in the settings (between 5 and 15 blocks), then the door opens.
If the door is open and no request has been successful in the last .6 seconds, the door closes.
The application is obviously security sensitive, and takes that fact into account as in case of error, the door stays locked. However, there are major security issues to this system:
The PDA registration is enabled at all time; this means you can put a disk drive next to the computer from the outside, and have your PDA registered; a mitigation would be to only allow registration at certain times.
The secret between the PDA and the door lock, called “fingerprint”, can be extracted from any PDA in wireless range by emitting a ping and gathering fingerprints from nearby devices, and try them out in surrounding doors; this is actually a real world issue as well, with attackers abusing credit card NFC in public spaces. A mitigation could be not to reveal the fingerprint but answer to unique challenges with hashes and salts.
The random finger print is 256 bytes between 32 and 126, which if the generator was truly random should be \(95 ^ {256}\) possibilities. However, the current program uses
math.random()
without setting the seed usingmath.randomseed()
. This means if you know in which ten minutes the door is likely to have been generated, and there is only one PDA registered, you only have to test \(6e{10}\) possibilities, which is significantly less. However the previous method of sniffing fingerprints stays significantly quicker and easier. See Randomness and entropy for more information.There is no timeout for a given computer if bruteforcing is attempted.
This is why this protocol is not recommended for new programs. However, this description is here to understand existing communications between Ultimate Door Lock enabled devices, and possibly attack those installations in PvP environment.
The protocol uses three modem channels:
4210
(a.k.aUltimateDoorlockPing
) for regular pings from the door lock.4211
(a.k.aUltimateDoorlockRequest
) for door lock requests from the PDA.4212
(a.k.aUltimateDoorlockRequestReply
) for door lock replies.
These three channels are used for exchanging OneOS messages (see Message formats).
On the doorlock ping channel, the content is the “Ping!” string.
On the doorlock request channel, the content is the fingerprint as a string,
and on the doorlock reply channel, the content is a boolean which equals
either true
if the door has been unlocked (whitelisted fingerprint and
pocket computer within range), false
otherwise.