DownUnderCTF was this weekend. Here are some writeups for challenges I personally solved.

Challenges sectioned off by category:

Misc

floormat

echo -e "\n{f.__init__.__globals__[FLAG]}\nF\nFragment" | nc pwn-2021.duc.tf 31903

There’s a FLAG global variable. You can supply a custom format string; it gets formatted with f = a floormat pattern object.

https://www.geeksforgeeks.org/vulnerability-in-str-format-in-python/

Objects in python have __init__ which is a method (alongside other methods). Methods have __globals__ which is a dictionary of all the globals, just subset it for FLAG.

DUCTF{fenomenal_flags_from_funky_formats_ffffff}

builder

.mpd extension, ASCII text, first line mentions a .ldr file extension. Google around for that, looks like it’s actually Lego CAD model related stuff.

http://www.melkert.net/LDCad/download

https://www.ldraw.org/parts/latest-parts.html Need complete.zip as the ldraw directory

the 3d model It’s kind of incomplete looking… This is on the bottom side…

enter image description here

So we have to attach those C shapes to the red bricks.

enter image description here DUCTF{CaD4L3G0!}

Crypto

Substitution Cipher I

Use https://sagecell.sagemath.org/, easier than installing SAGE.

Wrote a brute-force decrypt function (hey, why not), tested it out, then ran it on the Unicode string of the provided file. Lots of Unicode weirdness with Python saving this encrypted output.

def encrypt(msg, f):
    for c in msg:
        print(chr(c), c, f.substitute(c))
    outval = [chr(f.substitute(c)) for c in msg]
    print(outval)
    return ''.join(outval)

def decrypt(enc, f):
    enc = [ord(c) for c in enc]
    allchars = list(range(0,255))
    outarr = []
    for c in enc:
        m = next(filter(lambda trychar: f.substitute(trychar) == c, allchars))
        print(c, m, chr(m))
        outarr.append(chr(m))
    return ''.join(outarr)

P.<x> = PolynomialRing(ZZ)
f = 13*x^2 + 3*x + 7

FLAG = b'ligma'

enc = encrypt(FLAG, f)
print(enc)
print("#############")
dec = decrypt(enc, f)
print(dec)

flagenc = '\ueba3\U00016feb\ue4c5\U00016753\U000301bd𪃵𢙿疗𫢋𥆛\U0001fd03\u4db9𬑽蒵\U0001cb71𫢋𪃵蒵\U0001fd03\U0001cb71𩕑疗𪲳\U0001cb71窇蒵\U00031af3'
print("#############")
dec = decrypt(flagenc, f)
print(dec)

Note: One needs to get the unicode via some method like open("output.txt", "r").read(). Opening the file in binary mode will not work; you don’t want a bytestring, you need python to parse the Unicode characters properly. Cyberchef escape-character-encoding didn’t work, for example. Script output:

l 108 151963
i 105 143647
g 103 138233
m 109 154787
a 97 122615
['𥆛', '𣄟', '𡯹', '𥲣', '\U0001def7']
𥆛𣄟𡯹𥲣𝻷
#############
151963 108 l
143647 105 i
138233 103 g
154787 109 m
122615 97 a
ligma
#############
60323 68 D
94187 85 U
58565 67 C
91987 84 T
63917 70 F
197053 123 {
172277 115 s
140927 104 h
30103 48 0
178315 117 u
151963 108 l
130307 100 d
19897 39 '
181373 118 v
33973 51 3
117617 95 _
178315 117 u
172277 115 s
33973 51 3
130307 100 d
117617 95 _
169297 114 r
30103 48 0
175283 116 t
117617 95 _
31367 49 1
33973 51 3
203507 125 }
DUCTF{sh0uld'v3_us3d_r0t_13}

Flag: DUCTF{sh0uld'v3_us3d_r0t_13}

Forensics

That’s not my name

The download is a pcap file. Open it up in Wireshark, looks like there’s a lot of weird DNS requests with really long and nonsensical names - gotta be DNS exfil. Filter for ip.dst == 3.24.188.205, sure enough it’s all nonsensical DNS queries.

Right-click on the Name field within Query, and Apply as Column. Export displayed packets as CSV.

Open in Excel or any CSV viewer, take the whole name column, paste it into Cyberchef. Looks like they’re hexadecimal-encoding the data, but the periods and 2nd and top-level domains will interfere.

In Cyberchef, just find-replace qawesrdtfgyhuj.xyz with a blank string, then do the same for periods. Convert From Hex. Download the resulting data, run strings on it and grep for DUCTF.

DUCTF{c4t_g07_y0ur_n4m3}

Cloud

Bad Bucket

It’s a totally open GCP bucket.

gsutil ls -r gs://the-bad-bucket-ductf/
gsutil cat gs://the-bad-bucket-ductf/buckets/.notaflag

DUCTF{if_you_are_beggining_your_cloud_journey_goodluck!}

Not as Bad Bucket

For me, it actually still worked:

gsutil ls -r gs://ductf-not-as-bad-ductf
gsutil cat gs://ductf-not-as-bad-ductf/pics/flag.txt

DUCTF{all_AUTHENTICATED_users_means_ALL_AUTHENTICATED_USERS_silly}

Judging by the flag text, it purely just takes the fact that I’m logged into any GCP account, and lets me in. I was logged into a GCP account for the Lost n Found challenge, so I’m guessing this is why it worked - total shot in the dark, though.

Lost n Found

A legacy.json file was supplied, allowing you to log into a Google Cloud service account.

{
  "type": "service_account",
  "project_id": "ductf-lost-n-found",
  "private_key_id": "204a0a9969f97549e646f592d1732f5e478492d7",
  "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCxEd53/PMy+kTz\nf0WTfkk5V7QTc746dz3/RAdgisBm0pJz/prrUKc8g6RfaG7x5EhDIKymNytALcrR\nl/OM9+zDtkK8+r8lwcn/rqH+upPS0fJrVxRElZVLbK6hUn/6dX48n2zV7ANanPuG\nhBR6jICi7aCGUYMch7BocMhMvrtidUaMghp0hjUIO3Gkn+MDwmxhonqsCHJG0VHM\nDDE+NpOIhahjqvlSx6r+4SJjSPgvUElvyg9fo6EcQBk7lKE5ZYKXukBhuDfoWSiw\nMqL4N60sZA3bxlkgopW1Z6feqJTyzogbbsV5ude0+HOo3ATrx+ffnz05VTecHLLp\n5vrjkrR3AgMBAAECggEAB2fc6x3MOiSXf6uiCFIu09QkNvAPU7irAiMhP9ttwp8p\n+un6Jr9fzzseQ9NFWJ6Ymx4hum3yRCPmKK/3Qr0XzPOxhN/j4LtjLGtsYRACoL2h\nKvYgZeHvtZDdGOgvbBU/618rmSLe3QpVxsF9bca0lpvjq9p65lWSfjvBVNxhT/PP\n56aHHUsd1S3d1pwx71sNTWQqVJVg5JVaJx4SVuF7aGDYV9LPOi+dZPRmJV1YiH7v\nMpRQ6TOrsbK5yowIon3j8mm8S0Fxh6w46+6oKozC7DNIc93zsDKCy0c7kgFuBWpz\ne3+Wfz8fKCdc5D+gfDaPCUbFqZxEHFYRnkBbZiaM0QKBgQDaw5lRaBWl3Fu5mTwg\nByjW7zXdKusZhP6RbMV3R/77hiyawuqp12dEgWLLRo0pq0KOtpS93BfjectqndcJ\nq7xODHuWQfZAQNvR9LSsyxf2W160G2KeQajR/OUHvyjHUDRsgDy8q4vGc9ojodwK\n7is+eGdnr4HcRH5+zuaq1dXkbwKBgQDPNX025k/zu1vvSm3kF1AE68vP9kLY/oIU\n2ipKi0t11s0r03OIpBy6Hs8GiHejAgB+5tTLQS4S3wfsO4D17Z+jSK7Ejl0efxJw\nB0apYo2w76LBmDD2uWlfzlzQYwZinfs/8TUGBNpAxHqVjPm+ayl7ACBNzCTTHSKM\n/TXEqJgEeQKBgQDaZ08pA+Yg6ee1WvO48gzm0HkRLmj62FkirNpT5M//IwxjEdgf\n6kpSDW6pjO0fvbg8LLJA/nvnAdCAx8ZJBGiB71pvP7lumpIbgdfjbvukW8Inw/No\nFhtKUdYCLumyWzOLY1e/8PAiF8Wfr1e0neUUgDaUQJdAZi13wm5t/gCGBwKBgHFH\nGLEOr97bKqNi2Ti81e4ayk1in6DpYkvsCPq/s/0z9O5kpuCod1v4w80ahe0DhynZ\nH7QOahW/ACHRVescgQ1PCtxBx/6IEZhVIfgv/K4iE6Qqg3oeWtEZi/wQZsk6/MQ0\nJXyo4nhN8YYYj9/dzcuEgiSF2gvf/ad+NgrQ8GphAoGAcQH3rRoC/IFhUCYbX4Ya\nE/9tHj6U+oG/q4C7Yba/oJ/mPa5NMZtidUj1IwdQCgB3oO7slz0hseXi5iG4viHl\n8FJKxMy2LGJ4+cPjSgOLKaA2iBMxCrIsCFM39qa+8SnBxaXg+UopyFsK7GQIYkoY\nEm/drz8sZGJKBFJoE+NJyWM=\n-----END PRIVATE KEY-----\n",
  "client_email": "legacy-svc-account@ductf-lost-n-found.iam.gserviceaccount.com",
  "client_id": "103100904971904770440",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/legacy-svc-account%40ductf-lost-n-found.iam.gserviceaccount.com"
}

Authenticate with gcloud auth activate-service-account legacy-svc-account@ductf-lost-n-found.iam.gserviceaccount.com --key-file legacy.json.

And verify with gcloud auth list.

Set the project: gcloud config set project ductf-lost-n-found

And now check out the GCP secrets.

$ gcloud secrets list
NAME         CREATED              REPLICATION_POLICY  LOCATIONS
unused_data  2021-09-21T05:20:41  automatic           -

$ gcloud secrets describe unused_data
createTime: '2021-09-21T05:20:41.876436Z'
etag: '"15cc7a8f10dbd4"'
name: projects/216026370280/secrets/unused_data
replication:
  automatic: {}

$ gcloud secrets versions list unused_data
NAME  STATE    CREATED              DESTROYED
1     enabled  2021-09-21T05:20:45  -

$ gcloud secrets versions access 1 --secret=unused_data; echo
CiQA+H4IQ1Jq5yU+Ta7XvpOhnpYLiRYXxem6jVTzdqKxGaczATsSZgCa9lYSABC+4ve1pQuvy80nJi/pWv5hntGiPOiO7CQoC/Iqw1XOCgDBdmYEi9ynYb/qykTRDZiyGaheHSReUf0ZNr/hUjPrIXq2VCGSMtF1RFVt73Rp1i3/baMJxLOSmCN3cbT0xQ==

This is base64, but decoding it did not yield anything useful. I was not able to solve this challenge.

Most APIs were inaccessible to this service account or were simply disabled. I did notice that kms worked, and found this:

$ gcloud kms keyrings list --location=global
NAME
projects/ductf-lost-n-found/locations/global/keyRings/empty-keyring

But wasn’t able to get anything useful out of it. Post-competition, the official writeups revealed that there was a hidden kms keyring in a different location. Close!