Breaking RSA
The room can be found at https://tryhackme.com/room/breakrsa.
RSA is a encryption technique used in asymmetric key cryptography. It relies on the fact that multiplying two large prime numbers (p and q) is easy, but factoring a huge number (n) into factors is pretty difficult. By huge number I mean very very huge - 1000 digits huge, even.
This room talks about a weakness in RSA key generation, in which the chosen prime numbers (p and q) are not far apart. In such a case, Fermat's Factorization method can be used to factor the modulus (the huge number we talked about earlier), which is part of the public key. I think this paper titled "Fermat Factorization in the Wild" by Hanno Böck has a detailed explanation of it. It's linked at the bottom.
Enumeration
Port Scan
So now that the theory is out of the way, let us run a nmap SYN scan on the remote server.
nmap -sS -sV 10.10.142.96This shows some open services.

I also ran a UDP scan and that took a while (18 mins?) to complete, and I found one more service (DHCP client) there on port 68, but I think that does not count for the answer to the first question.
Webserver directory enumeration
We know there is a http server, so lets see what it has on it. The root directory on the server http://10.10.142.96 has some text on it, but nothing really helpful.

Let us check if there are any other common directories that this webserver is exposing.
What that bit of code does is make URLs by replacing the word "FUZZ" with the words found in the list, and then make HTTP requests to those URLs. Only the URLs that respond with a Status Codes 200, 204, 301, 302, 307, 401 and 403 are logged, and I save these ones to a file.

So this gives us a hidden directory, which i wont name, but lets call it hidden_dir. So we browse to http://10.10.143.96/<hidden_dir> . It has two files, a text file called log.txt, and a RSA public key file called id_rsa.pub.

The file explains the SSH concept we discussed before. It also tells us SSH root login is enabled on the server. This means we can login directly as root when connecting to the server using ssh later.
Cryptography
Making the key usable
Next, we try to read the public key file, id_rsa.pub using openssl.

It seems openssl can't load it? On viewing the contents of the file using cat it starts with a ssh-rsa text, followed by some base64 characters. So far, the keys I have run into in the introtocrypto TryHackMe room had this header: ----BEGIN PRIVATE KEY---- and had a .pem extension. This one is different.

Disclaimer: We are now entering trial and error territory. This is probably normal? I think.
So, I can think of two ways to deal with this problem.
Decode the Base64 in the key file:
The cut command leaves only the base64 portion of the key, and we try to decode it. Yeah, this won't do.

Find a way to view a ssh-rsa key: With some googling I found that
ssh-keygencan convert this ssh-rsa key into a pem key. We are familiar with that one! Amazing.Magic conversion code:
The -e flag makes it convert the OpenSSH key file and turn it into a different format, here -m specifies it to the the PEM format. We write this output to id_rsa.pem
We can load this in openssl which we were using earlier.
This gives us the modulus (n) in what seems to be base64. It also tells us how long the key is. That's one of the answers to the room.
This does not translate to anything meaningful on base64 decoding either. So I went googling again..
And found this. https://crypto.stackexchange.com/questions/18031/how-to-find-modulus-from-a-rsa-public-key
And realised this was getting very complicated very fast.
Key manipulation using Python pycryptodome to obtain the modulus
I also remembered that the question page says to use pycryptodome to do the RSA calculcations, so lets try that approach. We can always come back to this one.
Time to bring the crAzY python skillz out.
This is a long number. Since this the answer to one of the questions, I intentionally removed the last 10 digits.
Factoring the modulus
So now that we have n, we need to factor it. We could write code to do that, code that would be able to handle large numbers. OR. We could use a list of all the numbers and their known prime factors. Yep, that exists. Enter factordb.com
So running our modulus through factordb, we get the prime factors as follows:
The difference of these numbers is indeed very small.
Calculating and Dumping the private key
Now to calculate the private key, d.
d = modinv(e, lcm((p-1),(q-1))), where e = 65537 (given)
We can do this in python 3.8+ with the following expression:
So, now that we have d, we should be able to craft the private key, and dump it to the filesystem, and use it to ssh into the root user's account on the server.
We should have a file by the name of private_key in the directory that we opened the python shell in.
Let's trying ssh'ing into 10.10.142.96.

A couple of things I learnt here after spending *only* a couple hours:
The private key needs to have permissions 600 or 400, else the ssh client throws an error. Do
chmod 600 <filename>to change permissions. 600 is a mask for the user having read and write permissions on the file.*deep breaths* This part was very annoying but there are way too many types of RSA keys.
Exporting a private RSA key in OpenSSH format will export the corresponding public key instead. Found this out by comparing the public key from before and private key I generated and finding out they are the same. Moreover, the private key from a new keypair generated using
ssh-keygenis way larger than whatever private key we exported here.
So many keys
So I had to do some more trial and error with the other export key types that PyCryptodome offers (PEM and DER). I exported both of them as private_key.pem and private_key.der and changed their permissions to 600.
Then I tried using them to ssh into the server. The PEM key worked, the DER one did not.
Fin.
The flag was there upon logging in.

Notes/Links
Fermat Factorization in the Wild: https://eprint.iacr.org/2023/026.pdf.
The wordlist used with ffuf is from Daniel Miessler's Seclist Repository, https://github.com/danielmiessler/SecLists.
ffuz can be found at https://github.com/ffuf/ffuf and for more info on HTTP Status Codes, this is a good read https://developer.mozilla.org/en-US/docs/Web/HTTP/Status. It helped me out when making backend APIs at my last job.
wget is a tool used to make HTTP requests and retrieve files using it. It can use other protocols too. For details, https://www.gnu.org/software/wget/.
cat basically prints the content of a file to the terminal.
grep only shows lines that contain the string patterns it is given as arguments. The -v flag only shows lines that DO NOT contain the string pattern.
PyCryptodome - https://www.pycryptodome.org/
I'll probably write the factoring code and try it by hand too at some point, but not today.
The PEM key seems to be PKCS#1/OpenSSL compliant, as per the superuser link: https://superuser.com/questions/1515261/how-to-quickly-identify-ssh-private-key-file-formats
Last updated