Hegemons Login Analysis

From Second Life Wiki
Revision as of 19:14, 26 January 2007 by Hegemon Skall (talk | contribs)
Jump to navigation Jump to search

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 since it doesn't appear to be in the compiled client), 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.

Lets looks at a valid response by sniffing an actual connection to the server

Client:
0000   00 e0 a0 a6 66 70 00 18 f3 04 90 4c 08 00 45 00  ....fp.....L..E.
0010   00 34 00 00 40 00 40 11 41 e0 c0 a8 01 03 42 96  .4..@.@.A.....B.
0020   f4 97 94 6e 2f 04 00 20 2f e6 40 00 00 01 ff ff  ...n/.. /.@.....
0030   ff fa 16 89 02 b0 75 38 50 f1 8f 41 fe a7 6e 9a  ......u8P..A..n.
0040   f7 98                                            ..

Server:
0000   00 18 f3 04 90 4c 00 e0 a0 a6 66 70 08 00 45 00  .....L....fp..E.
0010   00 40 72 bf 40 00 2d 11 e2 14 42 96 f4 97 c0 a8  .@r.@.-...B.....
0020   01 03 2f 04 94 6e 00 2c 14 38 00 00 00 01 ff ff  ../..n.,.8......
0030   ff ff 00 02 c4 e4 95 9d 00 00 00 00 01 0d 16 89  ................
0040   02 b0 75 38 50 f1 8f 41 fe a7 6e 9a f7 98        ..u8P..A..n...

Server:
0000   00 18 f3 04 90 4c 00 e0 a0 a6 66 70 08 00 45 00  .....L....fp..E.
0010   00 29 72 c3 40 00 2d 11 e2 27 42 96 f4 97 c0 a8  .)r.@.-..'B.....
0020   01 03 2f 04 94 6e 00 15 42 79 00 00 00 02 ff ff  ../..n..By......
0030   ff fb 01 01 00 00 00 00 00 00 00 00              ............

Client:
0000   00 e0 a0 a6 66 70 00 18 f3 04 90 4c 08 00 45 00  ....fp.....L..E.
0010   00 24 00 00 40 00 40 11 41 f0 c0 a8 01 03 42 96  .$..@.@.A.....B.
0020   f4 97 94 6e 2f 04 00 10 43 82 00 00 00 02 ff ff  ...n/...C.......
0030   ff fd                                            ..