Rubis
Description
Hello C-Team,
During our investigation of Omniflags, we came across a cluster of ships called Rubis that was used to store top-secret information randomly in one of the ships and would rotate this secret every few days to stop attackers from finding the secret. It has been long since Rubric was deprecated however, we found out Rubis still contains a key component that will assist in the rescue of the prisoners from the space prison. We managed to get the source code that was used to run Rubis and for better or for worse, Rubis is still running at
<ip>:<port>
. We need you to unlock the ship that contains the flag so we can save the prisoners.Godspeed, HQ
Ship Ahoy!
Connecting to the server, we have a few options:
Prints out 5 seemingly random numbers
Prints out
n
ande
Prints out a hex string
Asks for a ship number and password, unlocks the ship if the password is correct
We are also given a challenge.py
file which consists of the code running this server, so let's check it out
First, we have an RSA
class, which I annotated with ###
For the most part, __init__
describes the initialization of RSA, two large primes p
and q
, an integer e
such that gcd(e, phi) = 1
where phi = (p - 1)(q - 1)
, n = pq
, and the secret key d
is the inverse of e
in modular n
Encryption and decryption follow the same steps as normal RSA
What's peculiar is that instead of randomly generating p
,q
first, e
is initialized and p
,q
are chosen until they satisfy the GCD requirement. Also, the two primes are not truly randomly generated, as they are both dependent on x
and thus are relatively close primes. This means n
is likely easy to factor
Secondly, there is a Ship
class, which is straightforward
Finally, we have a Cluster
class
From this, we make a few observations
All ships, except for the current ship, has password
pa$$w0rd
and dataNothing to see here :( Better luck next time!
The current ship is the "special ship" we want, with a password we don't know and the data is the flag!
The previous ships are 5 randomly generated values from 1 to 1000000 generated before generating the value for the current ship
We also have some class functions, which corresponds to the input options we have on the server
This is called by input 1. Get previous ships
This is called by input 3. Get password hint
It encrypts the master password with RSA then turns it into a hex string
This is called by input 4. Unlock a ship
It checks if the password is same as the ship's password, then prints the data if it is
It exists if we fail to open the ship, so it is not possible to brute force
Now we have all the information we need, let's try to get the flag!
Note - Be careful when restarting the session, as the RSA values and previous ships are randomly generated on bootup and will be different each time. If we need to restart, we'll need to go through all the steps again!
We will need the password, so let's get that. Start a session than choose option 2 to get the value of n
and e
. If we want to decrypt the password, we need the secret key d
Let's try factoring n
to get p
and q
It runs pretty fast due to the poor generation of p
and q
We can then calculate phi = (p - 1)(q - 1)
and d = e^(-1) mod phi
Now we have the secret key for RSA, so let's get the password hint with input 3. Since it's a hex string, we need to convert it to its numerical value
We get that the password is f32m47'5_f4c702124710n_m37h0d_f02_7h3_w1n!!
So we have the password, now we need to find the special ship to get the flag. How will we do that? Aren't the ships randomly generated? Also unlockShip
will call exit(1)
if we fail to unlock a ship, so we can't try them all until our password works :(
Now I had to think what option 1. Get the previous ships meant, since it was the only one we haven't used yet. It seemingly has nothing to do with the current ship as it is randomly and independently generating numbers for the previous ship, then the current ship. At least, in theory...
Consider random.seed(round(time.time()))
This sets a seed, but what does that mean? In reality, there is no such thing as true random. For the most part we use pseudorandom generators, which are a sequence of seemingly random numbers. For any one seed, there is a different sequence of numbers
But if we have the same seed, we will have the exact same sequence of numbers. This is why you need to change seeds on every use
We can try to exploit this fact and try to get the same seed that the server uses on bootup. Check the time when you run the server and keep track of it. Then, get the previous ships. We will compare different times as seeds until the first 5 numbers match the previous ships:
Now we have the 6th number generated by the seed, which must be our current ship! Select option 4, then pass in the ship number and the password to get the flag
Flag
magpie{17_w45n'7_72u1y_24nd0m_4f732_411}
Last updated