## Terminal - Snowball Fight

### Challenge

There’s another archade game in the Speaker Unpreparedness room, Snowball Fight, and Tangle Coalbox is standing next to it:

Howdy gumshoe. I’m Tangle Coalbox, resident sleuth in the North Pole.

If you’re up for a challenge, I’d ask you to look at this here Snowball Game.

We tested an earlier version this summer, but that one had web socket vulnerabilities.

This version seems simple enough on the Easy level, but the Impossible level is, well…

I’d call it impossible, but I just saw someone beat it! I’m sure something’s off here.

Could it be that the name a player provides has some connection to how the forts are laid out?

Knowing that, I can see how an elf might feed their Hard name into an Easy game to cheat a bit.

But on Impossible, the best you get are rejected player names in the page comments. Can you use those somehow?

Check out Tom Liston’s talk for more info, if you need it.

### Solution

#### Game

The challenge opens up with a menu to select a difficulty and a player name:

Clicking play loads a game like Battleship:

Some experimentation proves what Tagle and the splash screen suggested - giving the same name produces the same game board on the enemy’s side, which implies that the placement of the ships is somehow calculated based on the name input.

The difficulty of the game doesn’t impact the ship placement. It only impacts how good a shot the computer is (on insane it doesn’t miss), and how the name is set. For Easy and Medium, the player sets the name. For Hard, it’s set by the computer and displayed to the user like above. For Impossible!, it’s set by the computer and redacted:

Also for Impossible!, there is a comment in the HTML which gives 624 unused seeds (names) that are not used before redacting the userd one, presumably the one that follows:

It’s important to use the dev tools to view the page I’m actually view, and not “view-source”, which requests a new copy of the same page, and will get different numbers.

#### Calculate Name

Mersenne Twister is a widely used pseudo random number generator (PRNG). There are attacks against it where if you know the previous 624 values to come out of the PRNG, you can calculate the next value. Tom Listen gave a talk on this at this years KringleCon.

Since there are 624 unused values in the comments for the Impossible! level, I’ll assume those are the previous values to come out of the site. I’ll try to use those to calculate the value for the current came. First, copy those seeds into a file:

$wc -l rejects 624 rejects$ head rejects
2943688594 - Not random enough
529760399 - Not random enough
3341229050 - Not random enough
3370692404 - Not random enough
3346136354 - Not random enough
1025288101 - Not random enough
4092998779 - Not random enough
2472302771 - Not random enough
1630727217 - Not random enough
2274450635 - Not random enough


I want just the seeds in a file, so I’ll use awk to isolate the numbers and sponge to write back to the same file:

$cat rejects | awk '{print$1}' | sponge rejects
$head rejects 2943688594 529760399 3341229050 3370692404 3346136354 1025288101 4092998779 2472302771 1630727217 2274450635  mersenne-twister-predictor will take 624 32-bit integers and return the next numbers that will be generated. The example on the page will run until killed and make a lot of numbers. I’ll just use head -1 to get the next one, as that’s all that’s needed: root@kali# mt19937predict rejects | head -1 3963570317  Now I can open another window and play easy with this name. Once I know where all the ships are (I’ve yet to send (8,5), as that will clear the screen), I can go back to the Impossible window and hit every shot: It is important to do the impossible in the in-game window to get credit for solving. ## Naughty/Nice Part 1 ### Hints Tangle suggests applying this same technique to the Naughty/Nice list: Crikey - that’s it! You’ve done the Impossible! You’ve impressed this old elf today. Great work identifying and abusing the pseudo-random sequence. Now, the REAL question is, how else can this be abused? Do you think someone could try and cheat the Naughty/Nice Blockchain with this? If you have control over to bytes in a file, it’s easy to create MD5 hash collisions. One hint added in the badge: • If you have control over to bytes in a file, it’s easy to create MD5 hash collisions. Problem is: there’s that nonce that he would have to know ahead of time. Talking to Tinsel Upatree in Santa’s Office as Santa will also provide context for this challenge: Howdy Santa! Just guarding the Naughty/Nice list on your desk. Santa, I don’t know if you’ve heard, but something is very, very wrong… We tabulated the latest score of the Naughty/Nice Blockchain. Jack Frost is the nicest being in the world! Jack Frost!?! As you know, we only really start checking the Naughty/Nice totals as we get closer to the holidays. Out of nowhere, Jack Frost has this crazy score… positive 4,294,935,958 nice points! No one has EVER gotten a score that high! No one knows how it happened. Most of us recall Jack having a NEGATIVE score only a few days ago… Worse still, his huge positive score seems to have happened way back in March. Our first thought was that he somehow changed the blockchain - but, as you know, that isn’t possible. We ran a validation of the blockchain and it all checks out. Even the smallest change to any block should make it invalid. Blockchains are huge, so we cut a one minute chunk from when Jack’s big score registered back in March. You can get a slice of the Naughty/Nice blockchain on your desk. You can get some tools to help you here. Tangle Coalbox, in the Speaker UNPreparedness room. has been talking with attendees about the issue. The tools link provides OfficialNaughtyNiceBlockchainEducationPack.zip, and I can download blockchain.dat from the scroll on the table. ### Understand Tools The tools come with a Docker image, a public/private key pair, and a Python file: $ unzip -l OfficialNaughtyNiceBlockchainEducationPack
Archive:  OfficialNaughtyNiceBlockchainEducationPack.zip
Length      Date    Time    Name
---------  ---------- -----   ----
311  2020-12-08 17:37   OfficialNaughtyNiceBlockchainEducationPack/Dockerfile
638  2020-12-08 17:37   OfficialNaughtyNiceBlockchainEducationPack/docker.sh
22301  2020-12-08 20:21   OfficialNaughtyNiceBlockchainEducationPack/naughty_nice.py
450  2020-11-24 18:14   OfficialNaughtyNiceBlockchainEducationPack/official_public.pem
1679  2020-11-24 18:14   OfficialNaughtyNiceBlockchainEducationPack/private.pem
---------                     -------
25379                     5 files


The Python file is really well documented, and contains two classes that can be used to interact with the blockchain.

I can import this file, and then load the .dat file into it:

>>> import naughty_nice


Now I can interact with the blocks:

>>> len(c.blocks)
1548
>>> c.blocks[0]
Chain Index: 128449
Nonce: e3e12de5edfb51e2
RID: aecbf777616d9fa4
Document Count: 1
Score: 000000dc (220)
Sign: 1 (Nice)
Data item: 1
Data Type: 05 (PDF)
Data Length: 000003a7
Data: b'255044462d312e330a332030206f626a0a3c3c2f54797065202f506167650a2f506172656e742031203020520a2f5265736f75726365732032203020520a2f436f6e74656e74732034203020523e3e0a656e646f626a0a342030206f626a0a3c3c2f46696c746572202f466c6174654465636f6465202f4c656e677468203138323e3e0a73747265616d0a789c658eb10e82301884779ee212174da4b4a550ba9ae8e0dc1728e1078a501240797d51e3609c2eb9bbdc7712d788b34c638d4e16c9454048c6396c8db37d59a960c240a94d72d80a7bdb4e4458fc4008e37ac4c985ce0d3e60753366a280927c68e0f0a0c68523cafb82400f9a30b8db27297d838a5c8f71cbc61a7e6107d8ee17b91d29c41b79eeeb780cf1d2523cb7d4d7d80999994ca5b2d0ca68a3722db4fc5b484dc172f55e4813a912c925ff969e1a4c421d0a656e6473747265616d0a656e646f626a0a312030206f626a0a3c3c2f54797065202f50616765730a2f4b696473205b3320302052205d0a2f436f756e7420310a2f4d65646961426f78205b302030203631322e3030203739322e30305d0a3e3e0a656e646f626a0a352030206f626a0a3c3c2f54797065202f466f6e740a2f42617365466f6e74202f54696d65732d526f6d616e0a2f53756274797065202f54797065310a2f456e636f64696e67202f57696e416e7369456e636f64696e670a3e3e0a656e646f626a0a322030206f626a0a3c3c0a2f50726f63536574205b2f504446202f54657874202f496d61676542202f496d61676543202f496d616765495d0a2f466f6e74203c3c0a2f46312035203020520a3e3e0a2f584f626a656374203c3c0a3e3e0a3e3e0a656e646f626a0a372030206f626a0a3c3c0a2f54797065202f436174616c6f670a2f50616765732031203020520a2f4f70656e416374696f6e205b3320302052202f46697448206e756c6c5d0a2f506167654c61796f7574202f4f6e65436f6c756d6e0a3e3e0a656e646f626a0a787265660a3020380a303030303030303030302036353533352066200a30303030303030333339203030303030206e200a30303030303030353234203030303030206e200a30303030303030303039203030303030206e200a30303030303030303837203030303030206e200a30303030303030363238203030303030206e200a30303030303030373337203030303030206e200a747261696c65720a3c3c0a2f53697a6520380a2f526f6f742037203020520a3e3e0a7374617274787265660a3834300a2525454f460a0a'
Date: 03/24
Time: 13:21:00
PreviousHash: c6e2e6ecb785e7132c8003ab5aaba88d
Data Hash to Sign: 03cfb11504b8eee93b26aeb0d8ac39ff


### Predicting Nonces

The nonces are 64-bit ints. For example:

>>> hex(c.blocks[0].nonce)
'0xe3e12de5edfb51e2'


To calculate them, I’ll use the same library I used in the Snowball Fight game, mersenne-twister-predictor, this time, inside Python. When it was using 32-bit ints, I needed to give it 624 values to then get the next one. Since the nonces are 64-bit (twice as long), I need only half as many to predict the next. I’ll use blocks 0 to 311 to fill in the predictor:

>>> from mt19937predictor import MT19937Predictor
>>> predictor = MT19937Predictor()
>>> for b in c.blocks[:312]:
...     predictor.setrandbits(b.nonce, 64)
...


The nonce for block 312 matches the predictor’s calculation:

>>> hex(predictor.getrandbits(64))
'0xd177a402ebe05817'
>>> hex(c.blocks[312].nonce)
'0xd177a402ebe05817'


With that understanding, this script will give the answer to the challenge:

#!/usr/bin/env python3

import naughty_nice
from mt19937predictor import MT19937Predictor

predictor = MT19937Predictor()

for b in c.blocks:
predictor.setrandbits(b.nonce, 64)

for i in range(c.blocks[-1].index+1, 130001):
print(f'Block {i} nonce: {predictor.getrandbits(64):016x}')


Running it prints the following nonces up to index 130000, which is the one needed to solve the objective:

$python3 11a.py Block 129997 nonce: b744baba65ed6fce Block 129998 nonce: 01866abd00f13aed Block 129999 nonce: 844f6b07bd9403e4 Block 130000 nonce: 57066318f32f729d  Flag: 57066318f32f729d ## Naught/Nice Part 2 ### Hints No terminal or elves for this one, but there are hints in the badge from the previous terminal: • Qwerty Petabyte is giving a talk about blockchain tomfoolery! • The idea that Jack could somehow change the data in a block without invalidating the whole chain just collides with the concept of hashes and blockchains. While there’s no way it could happen, maybe if you look at the block that seems like it got changed, it might help. • Apparently Jack was able to change just 4 bytes in the block to completely change everything about it. It’s like some sort of evil game to him. • A blockchain works by “chaining” blocks together - each new block includes a hash of the previous block. That previous hash value is included in the data that is hashed - and that hash value will be in the next block. So there’s no way that Jack could change an existing block without it messing up the chain… • If Jack was somehow able to change the contents of the block AND the document without changing the hash… that would require a very UNIque hash COLLision. • Shinny Upatree swears that he doesn’t remember writing the contents of the document found in that block. Maybe looking closely at the documents, you might find something interesting. ### Find Tampered Block The challenge states that the modified block has a specific SHA256 hash. This script should identify it: #!/usr/bin/env python3 import naughty_nice from Crypto.Hash import SHA256 c = naughty_nice.Chain(load=True, filename='blockchain.dat') target_hash = '58a3b9335a6ceb0234c12d35a0564c4ef0e90152d0eb2ce2082383b38028a90f' for i,b in enumerate(c.blocks): h = SHA256.new() h.update(b.block_data_signed()) if h.hexdigest() == target_hash: print(f'[+] Found block with target hash.\n Index {b.index}\n i in file: {i}') c.save_a_block(i, filename='jf.block') break  The index is 1010 in the given file, or 129459 overall: $ python3 OfficialNaughtyNiceBlockchainEducationPack//11b.py
[+] Found block with target hash.
Index 129459
i in file: 1010


Looking at the block itself, it’s the max score, with a sign of nice. There are two attachments, a binary blob and a PDF:

>>> c.blocks[1010]
Chain Index: 129459
Nonce: a9447e5771c704f4
PID: 0000000000012fd1
RID: 000000000000020f
Document Count: 2
Score: ffffffff (4294967295)
Sign: 1 (Nice)
Data item: 1
Data Type: ff (Binary blob)
Data Length: 0000006c
ffe8d8f09'
Data item: 2
Data Type: 05 (PDF)
Data Length: 00009f57
Data: b'255044462d312e330a...[snip]...
Date: 03/24
Time: 13:21:41
PreviousHash: 4a91947439046c2dbaa96db38e924665
Data Hash to Sign: 347979fece8d403e06f89f8633b5231a


### Evaluate Documents

#### Get PDF

I’ll dump the documents associated with this block:

>>> jf = c.blocks[1010]
>>> jf.dump_doc(1)
Document dumped as: 129459.bin
>>> jf.dump_doc(2)
Document dumped as: 129459.pdf


The .bin file is completely random. I can’t make anything out of it.

The .pdf is interesting. It’s full of nothing but praise for Jack Frost:

Clearly this is a fake.

#### Map IDs

A PDF file is a bunch of text sections describing ojbects, fonts, pages, images, and text, and the various sections point to each other.

pdfid and pdf-parser are two tools from Didier Stevens that are useful for parsing PDFs.

pdfid shows the various elements in a given PDF:

$pdfid 129459.pdf PDFiD 0.2.7 129459.pdf PDF Header: %PDF-1.3 obj 23 endobj 23 stream 8 endstream 8 xref 1 trailer 1 startxref 1 /Page 2 /Encrypt 0 /ObjStm 0 /JS 0 /JavaScript 0 /AA 0 /OpenAction 0 /AcroForm 0 /JBIG2Decode 0 /RichMedia 0 /Launch 0 /EmbeddedFile 0 /XFA 0 /Colors > 2^24 0  When looking for malicious documents, it’s useful to look for elements like JS, JaveScript, and OpenAction. What stands out to me about this PDF is the two /Page objects, even though I only saw one page. The /Catalog is the root of the file. An example /Catalog would look like: obj 1 0 << /Type /Catalog /Pages 2 0 R /PageMode /UseOutlines /Outlines 3 0 R >>  Jack Frost’s PDF has the following /Catalog: $ pdf-parser -o 1 129459.pdf
obj 1 0
Type: /Catalog
Referencing: 2 0 R

<<
/Type /Catalog
/_Go_Away /Santa
/Pages '2 0 R      0ùÙ¿W\x8e<ªå\rx\x8fçó\x1dd¯ª\x1e¡ò¡=cu>\x1a¥¿\x80bOÃF¿ÖgÊ÷I\x95\x91Ä\x02\x01í«\x03¹ï\x95\x99\x1c[I\x9f\x86Ü\x859\x85\x90\x99\xadT°\x1es?å§¤\x89¹2\x95ÿTh\x03MIy8èù¸Ë:ÃÏPð\x1b2[\x9b\x17tu\x95B+sxð%\x02á©°¬\x85(\x01z\x9e'
>>


There’s a few odd things. /_Go_Away /Santa is an interesting string, and suggests I’m on the right path. Also, there’s not typically this string of random junk in the /Pages string.

This element references element 2, a /Page object:

$pdf-parser -o 2 129459.pdf obj 2 0 Type: /Pages Referencing: 23 0 R << /Type /Pages /Count 1 /Kids [23 0 R] >>  That one references object 23, which references objects 16 and 17: $ pdf-parser -o 23 129459.pdf
obj 23 0
Type: /Page
Referencing: 16 0 R, 17 0 R, 2 0 R

<<
/Type /Page
/Contents 16 0 R
/Resources 17 0 R
/MediaBox [0 0 612 792]
/Parent 2 0 R
>>


I can make a tree of the references:

1 Catalog
2 Page
23 Kids
16 Contents
17 Resources
18 Font
19 F1
20 FontDescriptor
21 FontFile
22 ToUnicode


But there’s another page object at object 3:

$pdf-parser -o 3 129459.pdf obj 3 0 Type: /Pages Referencing: 15 0 R << /Type /Pages /Count 1 /Kids [15 0 R] >>  Mapping it out:  3 Page 15 Kids 4 Contents 5 Resources 6 Font 7 F1 8 FontDescriptor 9 FontFile2 10 ToUnicode 11 F2 12 FontDescriptor 13 FontFile2 14 ToUnicode  This is basically an entire different document, just never referenced by the PDF. If I open the PDF in a text editor and change the Catalog to point to object 3 instead of object 2, it is a completely different PDF: The document describes how Jack Front did something terrible, and Shinny was submitting him for max naughty points. I suspect that Jack arrange for this to happen, as well as the frozen pipes back at Shinny’s house, so he could submit the report. ### MD5 Attack #### Overview Jack needed to submit this report as Shinny with the valid bad report, have it signed, and then go back and modify the block chain later so that the new report would show up but the report would still be valid. The reason he could do this is that the integrity of this blockchain is based on MD5 hashes. In the hints there’s a fantastic presentation by Ange Albertini on hash attacks. It goes into a lot of attacks, but the one here is the UNICOLL attack. To pull off this attack, someone must start with a given document. There is a calculation that can be made such that what looks like random garbage will finish out that 64-byte block, as well as one block beyond it. Once that is there, you can add one to the 10th byte in the last legit block, and subtrack one from the 10th byte in the last random block, and the MD5 hash will stay the same. Also, you can append data to the end of the random block and it will still work. Jack Frost did this attack twice on the block he submitted to the naught/nice blockchain - once on the naughty / nice flag, and once in the PDF. #### Block I’ll write the block in question to a file: >>> with open('jf.block', 'wb') as f: f.write(jf.block_data_signed()) ... 41411  The file outputs the hash given in the prompt: $ sha256sum jf.block
58a3b9335a6ceb0234c12d35a0564c4ef0e90152d0eb2ce2082383b38028a90f  jf.block


Click for full size image

If Jack were to start with just the data leading up to the attached files, including the header data for the first file, shown in yellow highlight:

On running the UNICOLL attack, it will fill out the rest of this block and a full next block with random stuff. Then Jack can add one to the 10th byte in the second to last block, and subtract one from the 10th byte in the last block, and the MD5 won’t change. In this case, that byte he adds one to is the naughty/nice flag, so he can submit it as 0 (naughty), but later flip it to 1 (nice) just by changing the meaningless byte in the random attachment as well.

He can do then append his double path PDF to the block, including the header with file type (0x05) and size (0x9f57) up to the point where the page is defined (yellow highlight):

The random data generated in the attack gets appended as part of the /Pages string, and most PDF readers are forgiving enough to process through that. Jack can then append the rest of the PDF.

There are now two places that Jack can change without changing the MD5 of the document. So he submits the report (as Shinny) with max value and naughty, and the PDF pointing to the report Shinny wrote. Once it’s verified and in the system, he edits the block chain, incrementing the naughty/nice flag from 0 to 1 (and decrementing 0x40 bytes later in the random binary attachment), and then decrementing the /Catalog in the PDF to point to the other document (and incrementing the byte 0x40 later in the randomness in the string). This modified document still has the same MD5 hash, so the next block’s hash still shows it valid.

### Undo It

To undo it, I’ll change four bytes in jf-mod.block using a hex editor:

$diff <( xxd jf.block ) <( xxd jf-mod-block ) 5c5 < 00000040: 3266 6666 6666 6666 6631 6666 3030 3030 2ffffffff1ff0000 --- > 00000040: 3266 6666 6666 6666 6630 6666 3030 3030 2ffffffff0ff0000 9c9 < 00000080: 22d9 8729 6fcb 0f18 8dd6 0388 bf20 350f "..)o........ 5. --- > 00000080: 22d9 8729 6fcb 0f18 8dd7 0388 bf20 350f "..)o........ 5. 17c17 < 00000100: 7461 2f50 6167 6573 2032 2030 2052 2020 ta/Pages 2 0 R --- > 00000100: 7461 2f50 6167 6573 2033 2030 2052 2020 ta/Pages 3 0 R 21c21 < 00000140: 0201 edab 03b9 ef95 991c 5b49 9f86 dc85 ..........[I.... --- > 00000140: 0201 edab 03b9 ef95 991b 5b49 9f86 dc85 ..........[I....$ md5sum jf.block jf-mod-block
b10b4a6bd373b61f32f4fd3a0cdfbf84  jf.block
b10b4a6bd373b61f32f4fd3a0cdfbf84  jf-mod-block


There’s one byte different on four rows, but the MD5sums are still the same.

The SHA256 of this block solves the objective:

\$ sha256sum jf-mod-block
`

## Story

In Santa’s Office, Tinsel tells me to head out onto the balcony:

You - you did it! You solved the mystery!

Quickly, go out to the balcony to be recognized!

Out there, Santa Congratulates me:

Thank you for foiling Jack’s foul plot!

He sent that magical portrait so he could become me and destroy the holidays!

Due to your incredible work, you have set everything right and saved the holiday season!

Congratulations on a job well done!

Ho Ho Ho!

Jack Frost, in his prison jumpsuit, is not happy:

My plan was NEARLY perfect… but I never expected someone with your skills to come around and ruin my plan for ruining the holidays!

And now, they’re gonna put me in jail for my deeds.