> To save the future you have to look at the past. Someone from the
> inside sent you an access code to a bank account with a lot of
> money. Can you handle the past and decrypt the code to save the
> future?
The challenge consists of a source code and program output file, with
the twist being that it's a COBOL program doing crypto:
identification division.
program-id. otp.
environment division.
input-output section.
file-control.
select key-file assign to 'key.txt'
organization line sequential.
data division.
file section.
fd key-file.
01 key-data pic x(50).
procedure division.
open input key-file.
read key-file into ws-key end-read.
display 'Enter your message to encrypt:'.
move 1 to ws-ctr.
perform 50 times
call 'getchar' end-call
move return-code to ws-parse
move ws-parse to ws-flag
call 'CBL_XOR' using ws-key(ws-ctr:1) ws-flag by value
ws-xor-len end-call
display ws-flag with no advancing
add 1 to ws-ctr end-add
end-perform.
cleanup.
close key-file.
goback.
end program otp.
I happen to have studied a few tutorials for that language, so
translation of the main procedure to equivalent Ruby code wasn't too
hard:
key = open(key_file, &:read)
ctr = 1
50.times do
flag = getchar
flag[ctr] ^= key[ctr]
print flag
ctr += 1
end
Curiously enough this looks like a proper OTP implementation, so the
devil must be lurking somewhere else. I have never understood COBOL
storage instructions, so instead of poring over comically verbose
documentation I opted for compiling the program instead. Using `cobc
-x -o otp otp.cob` and suitable input and key files I've tried it out
myself and noticed a troubling pattern, the output characters form a
repeating pattern of 10 characters! Looking at the code again the
culprit is the following line:
77 ws-ctr pic 9(1).
Who would have guessed that programming languages allowing you to
restrict integer types to arbitrary ranges are a thing. How
underhanded! This bug reduces the crypto involved to breaking
repeating key XOR, something I've done twice so far for Cryptopals.
Plugging in my old code didn't work though since the ciphertext is
laughably short and doesn't quite resemble English, so a slightly
different approach is required.
The cryptography term for a short piece of known plaintext is crib.
According to a team mate the flag format is `flag{1337_shit}`, so
`flag{` is an obvious one to look for. The idea is to XOR the crib
into a specific position of the ciphertext to obtain a piece of the
keystream, deriving the key resulting in the same keystream, creating
a new keystream from that key and performing a partial decryption of
the ciphertext using it. This way a bigger part of the plaintext can
be obtained and with a bit of luck, a slightly bigger crib. The
process can be repeated until a crib of 10 characters or the whole
plaintext has been guessed. My script automates it with all possible
offsets, so after a dozen iterations one of the printed strings was: