Hegemons Login Analysis
This page is intended to share/organize the information I learn while tinkering with the Second Life client now that its been GPLed.
I am not a guru, developer etc... I'm just playing around as a learning experience.
I am attempting to create an extremely basic server that just allows the Client to login, hopefully to a empty null world and maybe send some very basic information such as the suns position, area name, amount of money, 1 or 2 prims, flat terrain etc... I want to create it from scratch without relying on the SL viewer code or the libsecondlife stuff to ensure i understand everything. I would also like the server to handle all the elements of the login, ie not using a web server for the login stuff.
So far the server allows the completion of step 1 of the Authentication Flow
Its not very advanced or prwdy and works by parroting the clients requests back to it, this is enough of a hack to trick the client into continuing however incorrect sequence numbers etc are sent.
Stuff used: netcat, wireshark(Ethereal), C#/Mono/Monodevelop
I'm doing this under Ubuntu but any form of Linux should be fine (theres also a port of SL on Solaris now apparently), netcat and wireshark have windows ports also. I have never actually learned C#, but i have done Java, C and C++ so with the help of Google its fairly easy to work it out as I go. I chose C# as I haven't used it much previously, its also being incorporate into SL for the scripting language and libsecondlife appears to be written in it.
Step 1. The Authentication Flow just describes this as:
Viewer(client)--------->User Server * Secure Message checkum request - Protocol Level Supported? Yes/No. * Port 12036
which doesn't really give us an in depth description of everything thats happening, probably the quickest way is to analyses what the client does and try to emulate the servers responses.
Firstly the client needs to be started with the correct command line parameter (found here). This tells the client to send the initial UDP packets to the localhost.
./secondlife -user localhost
Then netcat need to be set to listen on UDP port 12036:
hegemon@ender:~$ sudo nc -u -l -p 12036 @������+U_{q�Y)$�ͫ `������+U_{q�Y)$�ͫ @������+U_{q�Y)$�ͫ ����`������+U_{q�Y)$�ͫ `������+U_{q�Y)$�ͫ @������+U_{q�Y)$�ͫ ���`������+U_{q�Y)$�ͫ @������+U_{q�Y)$�ͫ ���`������+U_{q�Y)$�ͫ `������+U_{q�Y)$�ͫ `������+U_{q�Y)$�ͫ �����+U_{q�Y)$�ͫ ���`������+U_{q�Y)$�ͫ �����+U_{q�Y)$�ͫ[[]]
This successfully makes the client send its response to localhost, its then not receiving anything back and disconnecting. The outputted information isn't very usefull so the next step is to fireup wireshark, set it to listen on the loopback interface and find out whats being sent (Alternatively netcat has the ability to output a hexdump also with the -o flag, its also possible to pipe the output to the 'hexdump' unix command however wireshark is probably nicer and can be used to analyze the client connecting to the actual server for comparison).
Wireshark gives us:
Client>Server 0000 00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00 ........ ......E. 0010 00 34 00 00 40 00 40 11 b7 62 c0 a8 01 03 c0 a8 .4..@.@. .b...... 0020 01 03 94 ad 2f 04 00 20 83 88 40 00 00 01 ff ff ..../.. ..@..... 0030 ff fa 2f c7 ac c1 79 ca f6 24 2a bc 12 e6 36 48 ../...y. .$*...6H 0040 be 04 .. 0000 00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00 ........ ......E. 0010 00 34 00 00 40 00 40 11 b7 62 c0 a8 01 03 c0 a8 .4..@.@. .b...... 0020 01 03 94 ad 2f 04 00 20 83 88 60 00 00 01 ff ff ..../.. ..`..... 0030 ff fa 2f c7 ac c1 79 ca f6 24 2a bc 12 e6 36 48 ../...y. .$*...6H 0040 be 04 .. 0000 00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00 ........ ......E. 0010 00 34 00 00 40 00 40 11 b7 62 c0 a8 01 03 c0 a8 .4..@.@. .b...... 0020 01 03 94 ad 2f 04 00 20 83 88 40 00 00 02 ff ff ..../.. ..@..... 0030 ff fa 2f c7 ac c1 79 ca f6 24 2a bc 12 e6 36 48 ../...y. .$*...6H 0040 be 04 ..
These are the 1st 3 packets, there where around 16 in total but its the same thing over and over.
So now we begin the packet analysis. We are only interested in the Data part of the packets, the first 42 bytes contains information such as source and destination ports/addresses, protocol information etc... which is what routers use to determin where to push these things around the internet to get it to your computer. This is shown in wireshark, so just select the data which highlights the following data packets.
40 00 00 01 ff ff ff fa 2f c7 ac c1 79 ca f6 24 2a bc 12 e6 36 48 be 04 60 00 00 01 ff ff ff fa 2f c7 ac c1 79 ca f6 24 2a bc 12 e6 36 48 be 04 40 00 00 02 ff ff ff fa 2f c7 ac c1 79 ca f6 24 2a bc 12 e6 36 48 be 04
You will notice there are only 2 bytes that are changing, the 1st and 4th, this is because there is no response so the client will keep resending the same data until there is one or it gives up.
By looking at the packet layout we can start to see what is being sent. There is also the libsecondlife analysis.
The first byte is the byte contains the bitmask flags, LL_ZERO_CODE_FLAG 0x80, LL_RELIABLE_FLAG 0x40, LL_RESENT_FLAG 0x20, LL_ACK_FLAG 0x10. To understand exactly whats happening in the first byte its best to look at it in binary. In the first packet we have 0x40, 4 in binary is 1000 and 0 is obviously 0000, which is 10000000, the first bit is 1 which means it wants an ack packet back so that it knows it was successfully received, if none is returned it will resend the packet, which is what packet 2 is.
The first byte in packet 2 is 0x60, in binary 10100000, in this packet the first and 3rd bits are set, so it wants an ack and it is a packet that has been resent. The 2rd packet is 0x40 again so its a new packet. not a resent one.
The next 3 bytes are marked as the sequence number, 000001, the first packet sent, then it is repeated in the resent packed and when the client decides to send a new packet rather then resend it increments it to 2. When an ack is sent back I believe it uses this sequence number for the ID, which tells the client it was received and doesn't need it to be resent.
The next bytes are listed as the 'frequency', its really means the messageID so the system knows the difference between a request for the version information and a request to close the connection, they are defined in the message template file /linden/scripts/messages/message_template.msg in the viewers source code, they are also available from libsecondlife here and you can also find the individual ones on this wiki here, there are 6 'fixed' ones shown near the top, we are encountering 0xFFFFFFFA which is the RequestSecureChecksum, we can check the template which shows that the packet only contains a LLUUID, that is the next 16 bytes and is a unique number for our client which is the remaining bytes. This is the client check to make sure the server is talking the same protocol version.
A majority of the messages are not 'fixed' ones. The number of bytes that makes the frequency is variable, so if a byte isn't 0xFF then that byte is the last byte in the frequency. Currently I'm not sure how to convert the frequency number to the specific message, or workout the checksum as it appears the client loads the template file in (probably at compile time), and docs say it assigns the numbers at runtime, but the fixed ones are enough for the first login step and we can use what we know is a valid checksum number by asking the client for its checksum.