Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Jiab77/6c38f6566d68784f4591b60c0269a8f0 to your computer and use it in GitHub Desktop.
Save Jiab77/6c38f6566d68784f4591b60c0269a8f0 to your computer and use it in GitHub Desktop.
Get connected friends on Second Life from terminal

Get connected friends on Second Life from terminal

If you are like me, lazy but able to get some crazy ideas sometime πŸ˜… then you might have wondered how to get your connected friends on Second Life without being forced to connect on their website.

I must admit that what I'm gonna explain is working only because Linden Labs seems to have no clue about how security should be implemented correctly...

The above sentence is only valid if you've not enabled the MFA on your account.

For example, if a bad actor gets hands on your session cookie, nothing will avoid that bad actor to impersonate your account without any time limit!

This is due to the fact that till the session cookie is refreshed / actualized with the involved watch command, it will never expire!! (while a forced session cookie expiration / renewal would have been expected at some point...)

I've been able to get connected under my own account after days of not having used their website!! 😱

How so?! you might wonder... Simply by replacing the assigned session cookie by the one used in the magic command that will be explained later...

TLDR

If you don't want to read the whole logic behind the idea, here is the magic command πŸ˜‰

  • With internal names displayed:

    $ watch -n5 "curl --silent -b session-token=[YOUR-SESSION-TOKEN-HERE] -A 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36' https://secondlife.com/my/loadWidgetContent.php?widget=widgetFriends | htmlq '#widgetFriendsOnlineContent' | grep -i -A2 'trigger online' | grep -i 'span' | grep -v '<br>' | sed -e 's/<span title=\"/(/' | sed -e 's/\">/) /' | sed -e 's|</span>||'"
    
  • Similar to what is displayed on website:

    $ watch -n5 "curl --silent -b session-token=[YOUR-SESSION-TOKEN-HERE] -A 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36' https://secondlife.com/my/loadWidgetContent.php?widget=widgetFriends | htmlq '#widgetFriendsOnlineContent' | grep -i -A2 'trigger online' | grep -i 'span' | grep -v '<br>' | sed -e 's/<span title=\"/(/' | sed -e 's/\">/) /' | sed -e 's|</span>||' | sed -e 's/ Resident//'"
    

Replace [YOUR-SESSION-TOKEN-HERE] with the one assigned once you get connected.

Result:

image

The output is refreshed every 5 seconds.

I guess you understand that I've redacted all sensible information πŸ˜…

Update

I've made a small project related to this work, you can find it here.

Get your session cookie

We all love cookies, don't you? 😁

In order to let the magic command getting access to your friends list, you'll need to get your current session cookie once connected.

To do so, open the web console with the [F12] key on your keyboard, go to the Application tab and select the Cookies section on the left:

image

Note the value of session-token in a safe place for later use in the magic command.

Install htmlq

To ease the parsing of the HTML content, a good friend of mine told me to give a try to htmlq. I you already know jQuery, you can think the same but for CLI πŸ˜‰

# Install 'cargo' first
$ sudo apt install cargo

# Then use 'cargo' to install 'htmlq'
$ cargo install htmlq

# Create required symlink
$ sudo ln -sfvn $(which htmlq) /usr/bin/htmlq

Target the friends list

Here is where things gets a little tricky to find.

image

As the website structure is still pretty old and far from to be modern, I was expecting to find the friends list code in the server side HTML source but surprisingly, nope πŸ˜…

They have used what they call, a widget written in PHP but loaded on the client side within JS code:

image

The logic here is the following:

  1. The JS code will load the widgetFriends widget using the loadWidgetContent.php loader written in PHP
  2. The server side generated content is then pushed on client side into the widgetFriendsBody DIV tag line 442 on the picture

So the code coming from server side that you can see on the picture above is then overloaded on client side to become:

image

Now the idea is to target the widgetFriendsOnlineContent DIV tag with htmlq and parse the content with grep and sed to transform this:

image

Into this:

image

You can't see very well here but basically the output will be formated that way:

(Internal Name) Display Name

Magic command

So... All of this to finally ends on:

$ watch -n5 "curl --silent -b session-token=[YOUR-SESSION-TOKEN-HERE] -A 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36' https://secondlife.com/my/loadWidgetContent.php?widget=widgetFriends | htmlq '#widgetFriendsOnlineContent' | grep -i -A2 'trigger online' | grep -i 'span' | grep -v '<br>' | sed -e 's/<span title=\"/(/' | sed -e 's/\">/) /' | sed -e 's|</span>||'"

Where:

  • watch -n5
    • Refresh / Re-run the command every 5 seconds
  • curl --silent -b session-token=[YOUR-SESSION-TOKEN-HERE] -A 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36' https://secondlife.com/my/loadWidgetContent.php?widget=widgetFriends
    • Connect on Second Life with your own session cookie
    • Hide the default curl User-Agent
    • and invoke the widgetFriends PHP widget
  • htmlq '#widgetFriendsOnlineContent'
    • Target the widgetFriendsOnlineContent DIV tag
  • grep -i -A2 'trigger online'
    • Filter by online users only
  • grep -i 'span'
    • Filter SPAN tags only
  • grep -v '<br>'
    • Remove extra BR tags captured from the first grep invocation
  • sed -e 's/<span title=\"/(/' | sed -e 's/\">/) /' | sed -e 's|</span>||'
    • Convert <span title="Internal Name">Display Name</span>
    • To (Internal Name) Display Name

Known issue

As you might have observed, the generated command does not parse the SPAN tag that hold the username but instead, it parse the one that holds the internal name and display name of each users.

The main reason to that is because initially, every usernames in Second Life were supposed to be composed by Firstname + Lastname from the randomly suggested names.

This restriction has been removed several years later to only ask for a single Nickname + Resident added internally as Lastname to kinda restore / keep using internally the old naming format Firstname + Lastname.

So what does it means in the end?

It means that users created before the restriction being lifted will have their usernames composed that way:

  • SuggestedRandomFirstname + SuggestedRandomLastname

While newer users will get their usernames composed that way:

  • SuggestedRandomNickname + Resident appended

Can you solve the issue?

Yes!

By adding another sed invocation to remove the extra appended Resident string from the output that way:

  • sed -e 's/ Resident//'

So the magic command becomes:

$ watch -n5 "curl --silent -b session-token=[YOUR-SESSION-TOKEN-HERE] -A 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36' https://secondlife.com/my/loadWidgetContent.php?widget=widgetFriends | htmlq '#widgetFriendsOnlineContent' | grep -i -A2 'trigger online' | grep -i 'span' | grep -v '<br>' | sed -e 's/<span title=\"/(/' | sed -e 's/\">/) /' | sed -e 's|</span>||' | sed -e 's/ Resident//'"

Can this be screwed up?

Unfortunately... Yes 😒

Second Life recently announced that they have finally implemented MFA as additional protection of user accounts. Well done Second Life! 🀘

Follow instructions provided here if you are interested.

How could it be screwed up?

When the MFA is enabled, it will then ask for an additional TOTP to be authenticated. This might then break the way the magic command is working and then involve the need to simulate that MFA payload...

Final result

image

Improvements

Based on the following research and work, I'll convert this magic command into a little bash script with arguments.

I'll put the link here once created.

Risks

In the introduction I've mentioned that there is a risk in using this magic command because it directly use your session cookie. If a bad actor can gets hands on it, it can simply impersonnate you and connect on your behalf.

What the bad actor needs to do?

  1. Take the value of session-token=[YOUR-SESSION-TOKEN-HERE] from the magic command
  2. Open the browser and navigate to https://secondlife.com/my/account/login.php
  3. Open the web console and change the assigned session cookie value to the one stolen from step 1.
  4. The bad actor is now connected on your behalf...

How does it works?

When you connect on Second Life, even if you still haven't given your username and password, a session cookie is created with an automatically assigned session-token. I guess that session-token is then linked to your account when the connection has been successful and certainly revoked at some point if no connection has been made with it.

How can it be improved?

According to my limited knowledge in the Security domain (I know, I'm probably too much humble on that statement πŸ˜…), here is what should be done to improve the security of their authentication process:

  1. the session-token should not be generated prior the authentication being successful but instead, should be generated only after the successful authentication.
  2. the session-token should be automatically revoked at a certain time even if it's still valid, forcing the user to authenticate again once revoked.

The reason behind the automated token revocation is to limit the access of your account to the bad actor. For example, I've discovered this "lack of security knowledge" like two or three weeks ago, the last run of my magic command was probably 10 days ago and the used session-token is still valid and I could even re-use it to get connected on the Second Life website under my own account...

Later observations

This section will contains post observations and might not be very clean.

Captured login cookies

image

I've observed that the session-token can be forced and rewritten while the sessionid and the csrftoken are genereted during the login.

The locale value can be set to any ISO-639-1 2 or 4 letters country code. example: fr, en-US.

Credits

Made with ❀️ of hacking by Jiab77.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment