The task’s description points at data recovery from a broken RAID array:
“One of my drives failed”
Reusing All of Internal Disks
The ZIP contains 3 disk images, the 2nd of which is faulty:
512M 1.img
0B 2.img
512M 3.img
1.img
& 3.img
are different, ruling out a (completely trivial) RAID 1.
By far, the most common 3-drive configuration that allows for recovery (in case a single drive fails) is RAID 5. Let’s go with that.
Once you acquaint yourself with RAID 5 (you may wish to do so now), array reconstruction is fairly simple to implement. The hard part is detecting the array’s block size & drive order (as that affects the parity schedule) – but all it takes for this task is a few educated guesses and a modicum of luck.
import numpy as np
def xor_blocks(lhs, rhs):
assert len(lhs) == len(rhs)
lhs = np.frombuffer(lhs, dtype=np.uint8)
rhs = np.frombuffer(rhs, dtype=np.uint8)
return (lhs ^ rhs).tostring()
drives = (
open("1.img"), # Drive 0 - OK
open("2.img"), # Drive 1 - Faulty
open("3.img") # Drive 2 - OK
)
extracted = open("recovered.img", 'w')
parity_drive = 2 # The first stripe stores parity information on this drive. Rotates with every iteration.
block_size = 64 * 1024 # An educated guess. It's possible that other sizes would work well enough for flag recovery.
# Each iteration recovers a stripe
while True:
drive_blocks = [d.read(block_size) for d in drives]
if len(drive_blocks[0]) == 0:
print "Done"
exit()
if parity_drive == 0:
# 0 | Parity - Valid
# 1 | Block1 - Missing
# 2 | Block2 - Valid
extracted.write(xor_blocks(drive_blocks[0], drive_blocks[2]))
extracted.write(drive_blocks[2])
elif parity_drive == 1:
# 0 | Block1 - Valid
# 1 | Parity - Missing
# 2 | Block2 - Valid
extracted.write(drive_blocks[0])
extracted.write(drive_blocks[2])
elif parity_drive == 2:
# 0 | Block1 - Valid
# 1 | Block2 - Missing
# 2 | Parity - Valid
extracted.write(drive_blocks[0])
extracted.write(xor_blocks(drive_blocks[0], drive_blocks[2]))
# Set the next stripe's parity drive (2, 0, 1, 2, 0, 1, 2, 0, 1, .....)
parity_drive = (parity_drive + 1) % len(drives)
We tried booting from recovered.img
(Using VirtualBox & VBoxManage convertfromraw
to create a VDI) — as 1.img contains a proper MBR — but that failed spectacularly 🙁
Next, we ran PhotoRec on the recovered drive. It emitted a bunch of (useless) text files and a single JPG:
And that’s all there was to it!
(That’s literally the flag’s text in the picture – no conversion of any sort was required)