In version 0.147.3 of valheim there is a possibility to receive and extract the passwords entered by the user.
Responsible disclosure:
I send an Email to the developer Team of irongatestudio, but unfortunately they didd’t respond to me.
This is only possible if you control the server binaries!
at this moment there was no possibility to mark or save servers as favorite in valheim self, so you either need to connect directly to the ip or search for the server name. this behavior makes this attack more reliable.
the attack mode is a phishing attack and described in the following steps
- manipulate the server assembly to extract the received passwords
- set up a dedicate server with the same name as the target server
- wait for user connections and receive the passwords
- crack the md5 password
digging into the game assembly
my first idea to extract the transmitted password was to read the udp stream but this seems to compressed in some way so i started to disassemble the game files.
valheim uses the unity engine, so the code should be in c#. c# as based on the .NET framework which can be easy decompiled in the most cases.
I took a look into the valheim dedicated server directory and found a promising file called assembly_valheim.dll
open the file with some .NET decompiler and you will get the hole source code. A quick search for the term „password“ will give me a some interesting methods, especially the method „HashPassword“ tells me how passwords in valheim are hashed. This part will be imported later when we want to decrypt the passwords.
but first i want to extract the password from the user input. the server console gives me a hint. if a user enters an incorrect password, this message will show up in the console.
i quick search for this message points me to the correct location in the code. In the class ZNet
the method RPC_PeerInfo
does some checks, also the password check can be found here.
As we can see the if statement checks if the server password is equal to the the variable b
so b
should hold the desired password entered by the user.
reassemble
Now we only need to extract the value of b
. There are of course many possibilities to achieve this. My first try was to edit the IL Instructor and replace the endPointString
variable with b
so the server will write the password into the console. This is very easy and can be done without loading any other dependencies.
just replacing
this will change the name of the variable b
into text3
, but this doesn’t matter, both variables are the same.
after replacing the assembly with my new „extended“ version the server will write the password to the console.
optimize output
As the password is still not readable and also its not the „finest“ way to copy & paste „strange“ strings out of a console i wanted to force the server to write these passwords to a file. On c# there are nice one liners out there to do this
but unfortunately every time the server crashed by executing AppendAllText
. I figured out that not all System.IO methods are implemented in the valheim assembly. Instead of messing up with editing the IL instructor it is much more easier to simple load all assemblies from the server folder, with all these dependencies i was able to simple edit the code and recompile the assembly. i found out that the StreamWriter is available and implemented the following lines of code.
Now the server is writing the passwords to the file passwords.txt, nice 🙂
crack the md5 password
As we could see before, the passwords are hashed with MD5. MD5 is really weak, lots of rainbow tables are out there and next to some free online services, with tools like hashcat and john you can perform some bruteforce attacks.
But the output really doesn’t look like a MD5 string. This is because the bytes from the password string are MD5 hashed but no sum was calculated out of the bytes.
So i thought converting this, lets call it „strange“ string back to bytes and calculate the sum should give me a valid MD5 sum or not?
lets try this, i go and enter the password 123456789
on my server and retrieve it from my password.txt
i wrote a little tool to receive the bytes from the string and calculate me the MD5 sum.
253f3f3f323b45383f3f181f1b624d0b
looks promising, lets hash the cleartext password with cyberchef to prove this.
25f9e794323b453885f5181f1b624d0b
this looks nearly similar, but unfortunately nearly is absolute not helpful if you plan to crack a password. but what happens here?
As we could see in the code from valheim, there is a call Encoding.ASCII.GetString(bytes2);
i extended my tool with some debugging information to understand this
Enter Password:
123456789
String in ASCII Bytes: 49 50 51 52 53 54 55 56 57
Bytes after MD5 Hash: 37 249 231 148 50 59 69 56 133 245 24 31 27 98 77 11
MD5 Sum: 25f9e794323b453885f5181f1b624d0b
String from ASCII Bytes after MD5 Hash: %???2;E8??↑▼←bM♂
Reverse:
Bytes from ASCII String after MD5 Hash: 37 63 63 63 50 59 69 56 63 63 24 31 27 98 77 11
MD5 Sum: 253f3f3f323b45383f3f181f1b624d0b
so the answer is called ASCII. ASCII max byte (decimal) is 127. every higher byte will be converted into byte 63 as we can see here.
this means there is no way to convert this back because some information are lost after the Encoding.ASCII.GetString(bytes2);
command.
The only way to crack these passwords, was to write my own cracker that will do the same thing.
- Read clear text passwords from a wordlist
- md5 hash the bytes
- get the ascii string from the bytes
- compare it with the „strange string“
As we already have this code, this was no big deal.
you can find the tool on my github
Also if you are not able to crack the password, you can simple modify the valheim.dll of your client to not encrypt the password and provide the encrypted password what you have captured to enter the desired server.