Geography

Getting To

Based on Jingle’s suggestion I’ll head to Frosty’s Beach, just around the feet of Christmas Island from the Orientation Dock.

image-20231217085522072

Location Layout

Santa and the Goose of Christmas Island are waiting for me by the dock. The island also has sponsor booths as well as Morcel Nougat waiting by the Snowball Hero game.

image-20231217090152331Click for full size image

Inside Santa’s Surf Shack, there’s a cranberry pi and Ginger Breddie:

image-20231217170740410

Santa

Santa welcomes me to the game and gives the backstory for how he ended up in these tropical islands:

Santa

Santa

Welcome to the Geese Islands, fellow traveler! This one is called Christmas Island. Nooo ho ho, not that Christmas Island.

After countless years of shivering and shaking through each holiday season, I thought to myself, “Why not trade the snowflakes for sunbeams, just once?”

Oh, the North Pole has its charm, but the bones do yearn for a bit of warmth now and then.

The notion was suggested by my good friend, Chat North Pole Technology, or as we like to call it, ‘ChatNPT’. That’s the one we use, but there’s a whole slew of other AI platforms. You should try them out!

It came to me describing palm trees and gentle waves, saying, “Santa, let your holidays take flight to Geese Islands, where the warmth isn’t just a setting.”

“There, every day is a sunny scene straight out of a vintage film reel.”

I chuckled at the thought, my belly shaking like a bowl full of jelly.

But the AI persisted, “Winter’s best kept secret: the balmy breezes of Geese Islands!”

And I must confess, the sound of that did stroke my beard with curiosity.

So, I called a meeting with the elves, the reindeer, and Mrs. Claus, of course.The elves were all a-buzz with the idea of crafting toys with a view of the ocean!

Thus, we packed up our sleighs and ChatNPT charted a course for the Geese Islands, a tropical paradise just north of the equator..

And I must say, there’s something quite magical about a Christmas carol sung to the strum of a ukulele.

After all, the magic of the holidays isn’t in the snow or the cold, but in the love and the care that we put into each and every gift.

So here’s to trying new things, to following the sunshine, and to the Geese Islands, where the holiday cheer is sun-kissed and the Christmas spirit is as warm as the tropical breeze.

And it’s all thanks to a little nudge from ChatNPT.

Now, why not start off your vacation with a snowball fight with Morcel, or check out my surf shack on the other end of the beach?

However you decide to relax, be sure to soak in all the whimsical beauty of these magical islands, and enjoy the activities to the fullest!

The Goose of Christmas Island just says:

Goose of Christmas Island

Goose of Christmas Island

Honk honk

It gives me a new lay for around the mast of my boat:

image-20231217090639058

Snowball fight

Challenge

Arriving here unlocks two objectives in my badge. The first says:

image-20240103115757734

I’ll find Marcel Nougat by the “Free Snowball Fights” sign:

image-20231217090808638

Morcel introduces the challenge:

Morcel Nougat

Morcel Nougat

Hey there, I’m Morcel Nougat, elf extraordinaire!

You won’t believe this, but we’re on a magical tropical island called Christmas Island, and it even has snow!

I’m so glad ChatNPT suggested we come here this year!

Santa, some elves, and I are having a snowball fight, and we’d love you to join us. Santa’s really good, so trust me when I say it’s way more fun when played with other people.

But hey, if you can figure out a way to play solo by tinkering with client side variables or parameters to go solo mode, go for it!

There’s also ways to make the elves’ snowballs do no damage, and all kinds of other shenanigans, but you didn’t hear that from me.

Just remember, it’s all about having fun and sharing the joy of the holiday season with each other.

So, are you in? We’d really love your company in this epic snowball battle!

Game Overview

The game starts with a menu:

image-20231217091304559

The modes are “VS Santa” and “VS Players”. I can create a room and get an ID to share with others, or enter a random room.

I’ll pick “VS Santa” so I can complete the challenge. I’m swarmed by Elves and Santa throwing snowballs, and it’s very difficult to stay alive.

image-20231217170248450

Source Analysis

Finding Source

I’ll open the Chrome browser dev tools and look in the “Sources”, where under “room/” I’ll find game page loaded in the iFrame:

image-20231217162948152

The JavaScript for the game is in this file. There’s a lot of interesting stuff in here.

Single Player Mode

Morcel Nougat suggested getting into Single Player mode. This is initialized in the JavaScript here:

  var singlePlayer = "false"
  function checkAndUpdateSinglePlayer() {
    const localStorageValue = localStorage.getItem('singlePlayer');
    if (localStorageValue === 'true' || localStorageValue === 'false') {
      singlePlayer = String(localStorageValue === 'true');
    }
    const urlParams = new URLSearchParams(window.location.search);
    const urlValue = urlParams.get('singlePlayer');
    if (urlValue === 'true' || urlValue === 'false') {
      singlePlayer = String(urlValue === 'true');
    }
  }

checkAndUpdateSinglePlayer is called shortly after during page initiation. This is looking for the value singlePlayer in local storage and again in the url parameters.

Damage

The function snowballHitsEntity is interesting:

  function snowballHitsEntity(entity, snowball) {
    if (snowball.isdying || entity.isdefeated) return
    if (snowball.owner_entityobj !== entity) {
      if (gameType === 'free-for-all') {
...[snip]...
      } else if ((entity === player || entity.entity_type === 'otherPlayer') && (snowball.owner_entityobj.entity_type === 'elf' || snowball.owner_entityobj.entity_type === 'santa')) {
        snowball.isdying = true
        snowball.playAnimThenDestroy();
        if (entity === player) {
          entity.takehit(snowballDmg, snowball.owner_entityobj)
        }
      } else if (entity.entity_type === 'elf' && snowball.owner_entityobj.entity_type !== 'elf' && snowball.owner_entityobj.entity_type !== 'santa') {
...[snip]...
      } else if (entity.entity_type === 'santa') {
        snowball.isdying = true
        snowball.playAnimThenDestroy();
        if (typeof santaObject.tintTimeoutInterval === 'number') {
          clearInterval(santaObject.tintTimeoutInterval)
        }
        santaObject.tintTimeoutInterval = setTimeout(function() {
          santaObject.clearTint();
        }, 2000)
        if (snowball.owner_entityobj.assigned_id === assigned_id || singlePlayer === "true") {
          santaObject.setTint(myPlayerTint);
          if (ws.readyState === WebSocket.OPEN) {
            ws.send(JSON.stringify({a: 's', i: playerId}));
          }
        } else {
          santaObject.setTint(otherPlayerTint);
        }
      } else if (entity.entity_type === 'dwarf' && ['santa','elf'].includes(snowball.owner_entityobj.entity_type)) {
        snowball.isdying = true
        snowball.playAnimThenDestroy();
      }
    }
  }

There are several different options here, but one interesting case is when the entity hit is a player and the snowball’s owner is Santa or an Elf. It calls entity.takehit(snowballDmg, snowball.owner_entityobj).

It’s also interesting to see what happens when Santa is hit. Some of the code is for turning Santa a color based on which player threw the snowball. Then it sends a message over the websocket:

          if (ws.readyState === WebSocket.OPEN) {
            ws.send(JSON.stringify({a: 's', i: playerId}));
          }

So there’s no ability to change the amount of damage that Santa’s taking. It’s just up to the server. I did play a bit with sending hit messages over the websocket to see if I could defeat Santa quickly, but didn’t succeed.

Single Player Mode

I’ll go back to the menu before the game, and look at its source. The function buildAndGotoUrl is interesting:

  function buildAndGotoUrl(roomId, gamet, roomt) {
    var new_url = window.location.href.split('/').slice(0, -1).join('/') + '/room/'
    new_url += "?username=" + username 
    new_url += "&roomId=" + roomId
    new_url += "&roomType=" + roomt
    new_url += "&gameType=" + gamet
    if (resourceId && resourceId.length) {
        new_url += "&id=" + resourceId
    }
    if (playerAvatar && playerAvatar.length) {
        new_url += "&dna=" + playerAvatar
    }
    window.location.href = new_url
  }

I know the game behaves differently if the singlePlayer parameter is set to true. I’ll put a breakpoint in this function by clicking on the line number:

image-20231217164631337

Now I select “Random Match Making”, and when it hits the breakpoint, I’ll go to the dev tools console. First, it’s important to make sure the console is targeted at the right window:

image-20231217164742439

Then, in the console, I’ll do a parameter injection by updating the gamet parameter to include both it’s current value and singlePlayer:

image-20231217164910730

Now I’ll let the code continue, and when I join the game, Elf the dwarf is on my team:

image-20231217164958517

Elf is quite strong, and I don’t really need to do much else here to win the match. He launches many snowballs at once that do serious damage. When Santa goes down:

image-20231205162811647

Other Cheats

There are tons of other things I can do to tilt the game in my favor. Immediately on entering the game, I’ll drop into the console and can do some of the following:

  • Modify the player.takehit function by running player.takehit = () => {} in the dev tools console. This changes that function that’s called when I take a hit to do nothing!
image-20231217165848784
  • Increase elfThrowDelay and santaThrowDelay. They are set to 2000 and 500 respectively (2 and 0.5 seconds). By changing them to 60 seconds or more, then I almost never get targeted.
  • Mess with santaHitBoxSize. It initialized to [60, 60, 70, 70]. Multiplying each of those by 10 makes for a much easier throw!

Epilogue

Morcel is impressed:

Morcel Nougat

Morcel Nougat

You’re like a snowball fighting ninja! A real-life legend. Can I have your autograph!?

Back with Santa, he recommends checking out the rest of the island:

Santa

Santa

Congratulations! You are a true snowball fight champion and thank you so much for helping out Ginger Breddie!

Oh, it feels like the warm and gentle winds are starting to pick up!

The perfect time to head back to your boat and embark on an adventure to all the other whimsical places the Geese Islands have to offer!

Safe travels my friend and thank you again for your help!

Linux 101

Challenge

Before leaving Frosty’s Beach, there’s one more objective in the badge:

image-20240103121706827

I’ll head to the Surf Shack, where Ginger Breddie and the Linux 101 terminal await.

Ginger Breddie

Ginger Breddie

Hey, welcome to Santa’s Surf Shack on tropical Christmas Island! I’m just hanging ten here, taking it easy while brushing up on my Linux skills.

You ever tried getting into Linux? It’s a super cool way to play around with computers.

Can you believe ChatNPT suggested this trip to the Geese Islands this year? I’m so thrilled!

Kudos to ChatNPT, eh? The sunshine, the waves, and my surfboard – simply loving it!

So, what do you have planned? Care to join me in a Linux session?

The terminal has a split screen with instructions on the top and a terminal on the bottom:

image-20231217171359173

Solution

I’ll walk through and explain the answers in this video:

Here’s the series of questions and answers:

  1. The North Pole 🎁 Present Maker: All the presents on this system have been stolen by trolls. Capture trolls by following instructions here and 🎁’s will appear in the green bar below. Run the command “hintme” to receive a hint.
      yes
    
  2. Perform a directory listing of your home directory to find a troll and retrieve a present!
      elf@20de0aa600bb:~$ ls
      HELP  troll_19315479765589239  workshop
    
  3. Now find the troll inside the troll.
      elf@20de0aa600bb:~$ cat troll_19315479765589239 
      troll_24187022596776786
    
  4. Great, now remove the troll in your home directory.
      elf@20de0aa600bb:~$ rm troll_19315479765589239 
    
  5. Print the present working directory using a command.
      elf@20de0aa600bb:~$ pwd
      /home/elf
    
  6. Good job but it looks like another troll hid itself in your home directory. Find the hidden troll!
      elf@20de0aa600bb:~$ ls -a
      .  ..  .bash_history  .bash_logout  .bashrc  .profile  .troll_5074624024543078  HELP  workshop
    
  7. Excellent, now find the troll in your command history.
      elf@20de0aa600bb:~$ history
       1  echo troll_9394554126440791
       2  ls
       3  cat troll_19315479765589239 
       4  rm troll_19315479765589239 
       5  pwd
       6  ls -a
       7  history
    
  8. Find the troll in your environment variables.
      elf@20de0aa600bb:~$ envSHELL=/bin/bashTMUX=/tmp/tmux-1050/default,17,0HOSTNAME=20de0aa600bb
      RESOURCE_ID=5208a138-9b29-4dbf-9532-8767e9951ae3
      GREENSTATUSPREFIX=presents
      PWD=/home/elf
      LOGNAME=elf
      SESSNAME=Troll Wrangler
      z_TROLL=troll_20249649541603754
      HOME=/home/elf
      LANG=C.UTF-8
      LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:
      HHCUSERNAME=real0xdf
      AREA=cisantassurfshack
      BPUSERHOME=/home/elf
      LESSCLOSE=/usr/bin/lesspipe %s %s
      TERM=screen
      LESSOPEN=| /usr/bin/lesspipe %s
      USER=elf
      TOKENS=linux101
      TMUX_PANE=%2
      BPUSER=elf
      SHLVL=3
      LC_ALL=C.UTF-8
      PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
      MAIL=/var/mail/elf
      LOCATION=7,7
      _=/usr/bin/env
    
  9. Next, head into the workshop.
      elf@20de0aa600bb:~$ cd workshop/
    
  10. A troll is hiding in one of the workshop toolboxes. Use “grep” while ignoring case to find which toolbox the troll is in.
      elf@20de0aa600bb:~/workshop$ ls
      electrical       toolbox_142.txt  toolbox_189.txt  toolbox_234.txt  toolbox_280.txt  toolbox_326.txt  toolbox_372.txt  toolbox_418.txt  toolbox_464.txt  toolbox_6.txt
      present_engine   toolbox_143.txt  toolbox_19.txt   toolbox_235.txt  toolbox_281.txt  toolbox_327.txt  toolbox_373.txt  toolbox_419.txt  toolbox_465.txt  toolbox_60.txt
      toolbox_0.txt    toolbox_144.txt  toolbox_190.txt  toolbox_236.txt  toolbox_282.txt  toolbox_328.txt  toolbox_374.txt  toolbox_42.txt   toolbox_466.txt  toolbox_61.txt
      toolbox_1.txt    toolbox_145.txt  toolbox_191.txt  toolbox_237.txt  toolbox_283.txt  toolbox_329.txt  toolbox_375.txt  toolbox_420.txt  toolbox_467.txt  toolbox_62.txt
    ...[snip]...
      elf@20de0aa600bb:~/workshop$ grep -ir troll *
      toolbox_191.txt:tRoLl.4056180441832623
    
  11. A troll is blocking the present_engine from starting. Run the present_engine binary to retrieve this troll.
      elf@b5cb36ca662a:~/workshop$ ./present_engine
      bash: ./present_engine: Permission denied
      elf@b5cb36ca662a:~/workshop$ chmod +x ./present_engine
      elf@b5cb36ca662a:~/workshop$ ./present_engine 
      troll.898906189498077
    
  12. Trolls have blown the fuses in /home/elf/workshop/electrical. cd into electrical and rename blown_fuse0 to fuse0.
      elf@b5cb36ca662a:~/workshop$ cd electrical/
      elf@b5cb36ca662a:~/workshop/electrical$ mv blown_fuse0 fuse0
    
  13. Now, make a symbolic link (symlink) named fuse1 that points to fuse0
      elf@b5cb36ca662a:~/workshop/electrical$ ln -s fuse0 fuse1
    
  14. Make a copy of fuse1 named fuse2.
      elf@b5cb36ca662a:~/workshop/electrical$ cp fuse1 fuse2
    
  15. We need to make sure trolls don’t come back. Add the characters “TROLL_REPELLENT” into the file fuse2.
      elf@b5cb36ca662a:~/workshop/electrical$ echo "TROLL_REPELLENT" >> fuse2
    
  16. Find the troll somewhere in /opt/troll_den. Entering find . from within the directory does solve this one. Interestingly, find . | grep -i troll does not.
      elf@79c9ff8666d4:/opt/troll_den$ find .
      ...[snip]...
    
  17. Find the file somewhere in /opt/troll_den that is owned by the user troll.
      elf@79c9ff8666d4:/opt/troll_den$ find . -user troll
      ./apps/showcase/src/main/resources/template/ajaxErrorContainers/tr0LL_9528909612014411
    
  18. Find the file created by trolls that is greater than 108 kilobytes and less than 110 kilobytes located somewhere in /opt/troll_den.
      elf@b5cb36ca662a:/opt/troll_den$ find . -size +108k -size -110k
      ./plugins/portlet-mocks/src/test/java/org/apache/t_r_o_l_l_2579728047101724
    
  19. List running processes to find another troll.
      elf@b5cb36ca662a:/opt/troll_den$ ps aux
      USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
      init           1  0.0  0.0  20112 16572 pts/0    Ss+  22:20   0:00 /usr/bin/python3 /usr/local/bin/tmuxp load ./mysession.yaml
      elf         6945  0.6  0.0  31520 26868 pts/2    S+   22:31   0:00 /usr/bin/python3 /14516_troll
      elf         7198  0.0  0.0   7672  3312 pts/3    R+   22:31   0:00 ps aux
    
  20. The 14516_troll process is listening on a TCP port. Use a command to have the only listening port display to the screen.
      elf@79c9ff8666d4:/opt/troll_den$ netstat -tnlp
      (Not all processes could be identified, non-owned process info
       will not be shown, you would have to be root to see it all.)
      Active Internet connections (only servers)
      Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
      tcp        0      0 0.0.0.0:54321           0.0.0.0:*               LISTEN      2939/python3
    
  21. The service listening on port 54321 is an HTTP server. Interact with this server to retrieve the last troll.
      elf@b5cb36ca662a:/opt/troll_den$ curl localhost:54321
      troll.73180338045875
    
  22. Your final task is to stop the 14516_troll process to collect the remaining presents.
      elf@b5cb36ca662a:/opt/troll_den$ ps aux
      USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
      init           1  0.0  0.0  20112 16572 pts/0    Ss+  22:20   0:00 /usr/bin/python3 /usr/local/bin/tmuxp load ./mysession.yaml
      elf         2939  0.0  0.0 105616 27472 pts/2    S+   22:31   0:00 /usr/bin/python3 /14516_troll
      elf        11297  0.0  0.0   7672  3236 pts/3    R+   22:38   0:00 ps aux
      elf@b5cb36ca662a:/opt/troll_den$ kill 2939
    

Congratulations, you caught all the trolls and retrieved all the presents!

Epilogue

Ginger is impressed:

Ginger Breddie

Ginger Breddie

Wow, if your surfing skills are as good as your Linux skills, you could be winning competitions!