Next Friday (Nov 17, 2023) is the 2023 Square CTF, and Iβve decided that my schoolβs cybersecurity club is going to participate. In an effort to prepare, weβre going to work through a selection of the 2022 challenges.
I want to sincerely say thank you to all of the Square CTF contributors for hosting such a great event. π
The challenges weβre going to host:
Spoiler! I wasnβt able to get all of the challenges to host easily. Iβve specifically chosen:
- EZ pwn 1
- EZ pwn 2
- Developerβs Hubris
- Huge Primes
- Korean Space Program A.K.A. Inv-characters
Itβs very possible that Iβm missing something obvious, and that I shouldnβtβve had the errors I did. Iβm still putting this document out there, just for future reference.
Future club members may find these modified challenges zipped in NKCyber Documents/CST/Meeting Resources/2023-11-10.
Getting the zip files
Square has generously provided archives of past challenges as zip files:
https://squarectf.com/2022/data/ezpwn1.zip
https://squarectf.com/2022/data/ezpwn2.zip
https://squarectf.com/2022/data/ezre1.zip
https://squarectf.com/2022/data/emojihunt.zip
https://squarectf.com/2022/data/squarepaymentterminal.zip
https://squarectf.com/2022/data/hardcopy.zip
https://squarectf.com/2022/data/roplikeeasy.zip
https://squarectf.com/2022/data/roplikemedium.zip
https://squarectf.com/2022/data/roplikehard.zip
https://squarectf.com/2022/data/threeitemmenu.zip
https://squarectf.com/2022/data/itsrightthere.zip
https://squarectf.com/2022/data/yetanotherreversingactivity.zip
https://squarectf.com/2022/data/alexhanlonhastheflag.zip
https://squarectf.com/2022/data/xark.zip
https://squarectf.com/2022/data/goinginblind.zip
https://squarectf.com/2022/data/nojs.zip
https://squarectf.com/2022/data/developershubris.zip
https://squarectf.com/2022/data/blockchain.zip
We can download all of the zip files and extract them with this script:
Using Docker?
Of these, itβs important to note that not every directory comes with a Dockerfile. We can check this with Python:
β
ez-pwn-1
β
ez-pwn-2
β ez-re-1
β emoji_hunt
β sqUARe_paymenT_terminal_pt1
β hard-copy
β
ROPlike-easy
β
ROPlike-medium
β
ROPlike-hard
β
three_item_menu
β its-right-there
β yet-another-reversing-activity
β
AlexHanlonHasTheFlag
β
xark
β
GoingInBlind
β
nojs
β
DevelopersHubris
β BLOCKchain
Given that my club is only going to have a few hours to work through the problems, Iβve chosen to not worry about hosting the challenges that donβt come with Docker containers.
So, what happens if we host one of these Dockerfiles?
Letβs start with ez-pwn-1
as an example.
There are a couple files:
And if we are in the directory, we can build it with:
Visiting the url hosted by the Docker container returns ERR_INVALID_HTTP_RESPONSE
, and populates the logs with:
: not found.1
sh: 2: Host:: not found
I donβt know why this is.
We can try again with ez-pwn-2
. Letβs use the run.sh
:
So, we can use:
This has the same issue, and returns:
Letβs check how many actually host a web interface with Docker:
β ez-pwn-1
β ez-pwn-2
β ROPlike-easy
β ROPlike-medium
β ROPlike-hard
β three_item_menu
β
AlexHanlonHasTheFlag - works with docker compose up
β
xark - works with docker compose up
β
GoingInBlind - works with docker compose up
β
nojs - works after modifying Dockerfile (see below)
β
DevelopersHubris - worked first try, ironically
nojs modifications
nojs
errored out in the Dockerfile on line ADD keys/deploy_id_rsa /root/.ssh/id_rsa
, but after commenting out the lines 5-8, it then errored out on installing openjdk-11-jre
. I removed the requirement for openjdk-11-jre
, and it worked perfectly. Iβm not sure why these were required, but everything seems to work fine without them. I ran with ./run.sh
with no errors. Spoiler: it would not always work without errors.
Great! We now have the 5 challenges weβre going to do this Friday.
We can move them into a separate directory with:
So, we get the list:
approved/
βββ AlexHanlonHasTheFlag
βββ DevelopersHubris
βββ GoingInBlind
βββ nojs
βββ xark
All of these have a run.sh
except for xark
.
So, we can add a run.sh
to the xark
folder:
Deployment fights back
From there, I copied the file to a Digital Ocean Droplet to host for this Friday.
(Where Square2022Approved.zip
contains all of the modifications described above)
On the Digital Ocean Droplet, I then wrote the script:
which was able to install almost all of the selected challenges. DevelopersHubris originally errored out with:
Non-resolvable parent POM for com.example:DevelopersHubris:0.0.1-SNAPSHOT: Could not transfer artifact org.springframework.boot:spring-boot-starter-parent:pom:2.7.5 from/to central (https://repo.maven.apache.org/maven2): transfer failed for https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-starter-parent/2.7.5/spring-boot-starter-parent-2.7.5.pom and 'parent.relativePath' points at no local POM @ line 6, column 11: Remote host terminated the handshake: SSL peer shut down incorrectly
but, I ran again and it worked fine.
However, despite all of these working fine on my laptop, we run into some issues on the Droplet:
Emoji | Title | Performance Impact |
---|---|---|
π₯ | AlexHanlonHasTheFlag | 100% CPU (repeated crashes) |
π₯ | GoingInBlind | 100% CPU (repeated crashes) |
β | DevelopersHubris | 10% CPU |
π₯ | nojs | 100% CPU (repeated crashes) |
π₯ | xark | 100% CPU (repeated crashes) |
So, it looks like the first two are crashing due to self signed certificates.
Show all
2023-11-09T16:33:43.040751Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.31' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server - GPL.
2023-11-09 16:34:38+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.31-1.el8 started.
2023-11-09 16:34:40+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2023-11-09 16:34:40+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.31-1.el8 started.
'/var/lib/mysql/mysql.sock' -> '/var/run/mysqld/mysqld.sock'
2023-11-09T16:34:41.713217Z 0 [Warning] [MY-011068] [Server] The syntax '--skip-host-cache' is deprecated and will be removed in a future release. Please use SET GLOBAL host_cache_size=0 instead.
2023-11-09T16:34:41.725478Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.31) starting as process 1
2023-11-09T16:34:41.766279Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2023-11-09T16:34:43.370891Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2023-11-09T16:34:45.659096Z 0 [System] [MY-010229] [Server] Starting XA crash recovery...
2023-11-09T16:34:45.827484Z 0 [System] [MY-010232] [Server] XA crash recovery finished.
2023-11-09T16:34:48.290338Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
2023-11-09T16:34:48.296914Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
2023-11-09T16:34:48.399412Z 0 [Warning] [MY-011810] [Server] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
2023-11-09T16:34:50.303363Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.31' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server - GPL.
And nojs was crashing due to not having Java:
2023/11/09 17:26:20 worker 8228973497722964186 failed to initialize: failed to initialize selenium: exec: "java": executable file not found in $PATH
and xark was crashing as well:
Show all
Listening on port 3001 in prod
crushes table doesn't exist, initializing...
node:internal/process/promises:289
triggerUncaughtException(err, true /* fromPromise */);
^
Error: Connection lost: The server closed the connection.
at Protocol.end (/app/node_modules/mysql/lib/protocol/Protocol.js:112:13)
at Socket.<anonymous> (/app/node_modules/mysql/lib/Connection.js:94:28)
at Socket.<anonymous> (/app/node_modules/mysql/lib/Connection.js:526:10)
at Socket.emit (node:events:527:35)
at endReadableNT (node:internal/streams/readable:1589:12)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
--------------------
at Protocol._enqueue (/app/node_modules/mysql/lib/protocol/Protocol.js:144:48)
at Connection.query (/app/node_modules/mysql/lib/Connection.js:198:25)
at /app/node_modules/knex/lib/dialects/mysql/index.js:132:18
at new Promise (<anonymous>)
at Client_MySQL._query (/app/node_modules/knex/lib/dialects/mysql/index.js:126:12)
at executeQuery (/app/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
at Client_MySQL.query (/app/node_modules/knex/lib/client.js:146:12)
at Runner.query (/app/node_modules/knex/lib/execution/runner.js:123:36)
at Runner.queryArray (/app/node_modules/knex/lib/execution/runner.js:217:21)
at Runner.queryArray (/app/node_modules/knex/lib/execution/runner.js:269:31) {
fatal: true,
code: 'PROTOCOL_CONNECTION_LOST'
}
Node.js v21.1.0
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
I must appreciate the irony that DevelopersHubris was the only one working.
Current status: Our meeting is tomorrow, and only one challenge is properly hosted.
Fixing nojs
This one seems straightforward.
So, it turns out that, despite the fact it worked on my machine, we need to adjust the docker image to include OpenJDK.
See modified Dockerfile
Iβve waited for go build -installsuffix 'static' -o /notes-site .
to finish for about 10 hours now. Go usually compiles super quickly, so Iβm not sure whatβs going wrong. I bet thereβs an easy solution, but iterative development is hard when you have to wait hours on a slow machine. Iβm giving up and trying a previous year. This feels like a performance limitation.
Are challenges from 2021 easy to host?
https://squarectf.com/2021/data/its-just-an-xor.zip
https://squarectf.com/2021/data/im-a-credential-ghoul.zip
https://squarectf.com/2021/data/out-of-cash.zip
https://squarectf.com/2021/data/korean-space-program.zip
https://squarectf.com/2021/data/memory-safe-hex-decode.zip
https://squarectf.com/2021/data/card-theft.zip
https://squarectf.com/2021/data/huge-primes.zip
https://squarectf.com/2021/data/collatzeral-damage.zip
https://squarectf.com/2021/data/burnt-bread.zip
https://squarectf.com/2021/data/gil-triangle.zip
https://squarectf.com/2021/data/memory-safe-strcmp.zip
See download script
So, 2021:
β
re-its-just-an-xor
β
crypto-im-a-credential-ghoul
β
out-of-cash
β
inv-characters
β rust-rev-2
β
card-theft
β
hugeprimes
β crypto-collatzeral-damage
β
burnt-bread
β
gil-triangle
β rust-rev-1
Iβm sad I donβt get to geek out about about Rust, as rust-rev-1
and rust-rev-2
donβt seem easy to host, but this is at least showing progress.
Using an abomination of a Bash/Python one-liner, I found thereβs quite a lot of socat-based challanges. These should all work as well. (Though, I havenβt tested them.) Theyβre just netcat based, and I want some browser-based challenges as well.
HugePrimes
Lets try hugeprimes
π€.
Letβs look at its Dockerfile (comments removed):
This is a tiny Dockerfile. Thereβs a chance this might not fight backβ¦
This is huge! It works.π
Iβm currently at two non-netcat Dockerfiles, which is a 100% improvement. At this rate, weβre going to have all of the browser challenges working in no time.
inv-characters
This challenge has the same super simple Dockerfile listed above!
And it runs!
Iβm calling that three total challenges. π
Our status so far:
Legend:
- β has a Dockerfile, works
- π₯ Worked on my machine, but crashed on the server
- π₯οΈ Used SSH, and I didnβt want to host that.
- π± uses socat (connect through netcat)
- β has no Dockerfile; usually isnβt easily hosted
β
inv-characters
β
hugeprimes
β
DevelopersHubris
π₯ AlexHanlonHasTheFlag
π₯ GoingInBlind
π₯ nojs
π₯ xark
π₯οΈ crypto-im-a-credential-ghoul
π± ez-pwn-1
π± ez-pwn-2
π± ROPlike-easy
π± ROPlike-medium
π± ROPlike-hard
π± re-its-just-an-xor
π± out-of-cash
π± card-theft
π± burnt-bread
π± gil-triangle
β rust-rev-2
β crypto-collatzeral-damage
β rust-rev-1
β ez-re-1
β emoji_hunt
β sqUARe_paymenT_terminal_pt1
β hard-copy
β its-right-there
β yet-another-reversing-activity
β BLOCKchain
A new hope
I want at least 5 challenges to cover on Friday, but it bugs me that several challenges keep crashing on our droplet.
I see three paths forward:
- Go back another year
- Try and resolve the Docker issues
Well, I liked what I saw of AlexHanlonHasTheFlag when it was working, so Iβll try that again.
Resource limiations, part 2
Iβm giving up on nojs. Iβve waited for too many hours for the Docker image to build, to no avail.
Iβm going to try AlexHanlonHasTheFlag, because weβve covered SQL injections before, and I might be able to fix the errors.
Just checking:
Apparently, the logs I saw the last time I ran it are actually the exact same I see in my laptop. However, the db image is definitely failing.
Going into each Dockerfile, I notice that both the db application and the Java application run without error. However, the db application closes immediately and exits.
However, adding a bash command to the end of the Dockerfile works to keep the container alive, as long as the file is run with -t
:
I tested the second solution, and it seemed to keep the container alive with no worries.
Unfortunately, this did not resolve my issue, and running docker compose
continued to use 100% of my CPU repeatedly boot-looping the db container, with no errors to explain a crash.
This StackOverflow response says that these errors are produced when MySql is trying to run with too little RAM. Yeah, that checks out.
However, weβre literally storing one record for these challenges, so the idea it needs more than a megabyte of RAM seems absurd.
They suggest:
And then again, you could just increase RAM on your server if you can afford it.
π₯²
So, I yoinky sploinkied the configuration file into mysql.config
, and added the line:
Hereβs my testing command for the Dockerfile, for personal reference:
Then, I stumbled upon this GitHub repo for configuring MySql to run with low memory, but even that wasnβt enough.
If I had more time, Iβd migrate everything to SQLite, and it would all work. However, I guess weβre just picking a different strategy now.
It looks like the minimum system requirements for MySql is around 2 GB RAM, which is above the System RAM of 1GB.
OS: Ubuntu 22.04.3 LTS x86_64
Host: Droplet 20171212
Kernel: 5.15.0-84-generic
Uptime: 42 days, 55 mins
Packages: 750 (dpkg), 5 (snap)
Shell: bash 5.1.16
Resolution: 1024x768
Terminal: /dev/pts/0
CPU: DO-Regular (1) @ 2.199GHz
GPU: 00:02.0 Red Hat, Inc. Virtio GPU
Memory: 572MiB / 957MiB
Back to ez-pwn-1
I looked at the solution, and found that people were expected to use netcat to connect. That would have been helpful to put in the README.md, ngl. I had issues originally because I thought they expected people to use the browser. From netcat, it works perfectly. Iβm sorry I doubted you, ez-pwn-1. π
Well, thatβs a relief. I probably should have looked through the walkthroughs a while ago.
So, that gives us these challenges for Friday:
- EZ pwn 1
- EZ pwn 2
- Developerβs Hubris
- Huge Primes
- Korean Space Program A.K.A. Inv-characters
At this point, I give everything a good old rm * -rf
and I start with the challenges from above.
I write a new hosting script:
Running all of these Docker images bumps our RAM up from 400M/1G to 700M/1G, so weβre kinda pushing our Droplet to its limits. Iβm sure itβll be fine.
Allow all solutions on the firewall
CTFd resources
Club members should check the Google Drive for the CTFd resources for this event.