Accidentally solving the Swisscom 2025 security.txt challenge


swisscom bug hunter card

Background

A while ago, I was mindlessly browsing the Meetup website, looking for some local meetups. I accidentally ended up on a 2024 Swisscom security.txt Challenge Writeup blog post that sounded like fun.

Turns out, this is a yearly thing1:

$ curl -s https://swisscom.ch/.well-known/security.txt | tail -n 2
# Canihazchallenge: aHR0cHM6Ly9naXRodWIuY29tL3N3aXNzY29tL3NlY3VyaXR5dHh0L2Jsb2IvbWFzdGVyL2NoYWxsZW5nZXMvMjAyNS53b3o=

For the base64-challenged, that string leads to 2025.woz file on Swisscom’s github.

My thought was: Hm, I wonder how hard it would be?

Turns out… it was rather pleasant.

I’m going to walk you through some of it here2.

Writeup

First things first, what the hell is a .woz, right?

$ file 2025.woz 
2025.woz: Apple ][ WOZ 2.0 Disk Image, 5.25 inch, ant0inet

Ah, Apple II – the machine I never had, having grown up behind the Iron Curtain.

Still, fun. What happens when you boot it?

first boot

I’ll spare you the boring bits3, CATALOG reveals a few scripts (A), two binaries (B), and a text file (T):

catalog

The target is obviously to run the FLAG binary, but BRUN FLAG magically doesn’t work:

brun flag doesn’t work

It throws ERROR #8, which my oft-used stochastic parrotry interprets as a general Input/Output error4.

So something’s screwed up with the binary.

After a bit of a dig, I ended up with a woz2dsk script that can convert the unwieldy .woz format to a more readable5 .dsk format.

A huge advantage is that you can still boot the .dsk in the typical emulators.

And from there, it was a bit of figuring out what’s wrong with the file, and how to repair it.

Should you embark on this journey, you might find the following links valuable:

And how was I going to solve it? Ruby, obviously. All 91 lines of it, including moderately extensive comments and debug out:

#!/usr/bin/env ruby

# ...

require 'pp'

# ...

def human_name(name)
  name.map { |x| (x ^ 0x80).chr }.join.strip
end

File.open('a.dsk', 'r+b:ascii-8bit') do |f|
  # ...
      # patch it?
      if human_name(name) == 'FLAG'
        # ...
        puts %[Patching done, now load it up... then: "brun flag"]
      end
  # ...
end

# I mean, I said I'm not telling, right?

Overall, it was a fun exercise6 that ended in a rather satisfying:

success

Even better: a few days later I received a cache of Swisscom SWAG, including the card above and some fun stickers (“PoC or it didn’t happen”, “I hacked Swisscom and all I got was this lousy sticker.”, etc)7.

100% would try again next year – and recommend it to others. ;)

If for nothing else, then for the “surely it can’t be that hard” aspect.

Game on.

  1. Who woulda thunk, by the blog post title, right?

  2. Not all of it, because in bird culture that’s considered a dick move.

  3. That your favorite flavor of stochastic parrotry explains in sufficient detail in under 50 seconds.

  4. Reminds me of the old DOS joke: “Who the hell is General I/O error, and why is he reading my disk?”

  5. In hex editor, I mean…

  6. Took about 3-4 hours (from an Apple II virgin) to get the flag, then probably the same time to make it fully repeatable and put a bow on the Ruby.

  7. Thank you, ant0inet!