DEV Community

loading...
Cover image for picoCTF 2021 -Easy Peasy writeup-

picoCTF 2021 -Easy Peasy writeup-

Shitian Daxiang
Bio := struct {Identity, Undergrad, Research}{ "Ainu descendants", "📊 Data Science", "🔬 Privacy Preserving Data Mining"}
Updated on ・2 min read

Description

A one-time pad is unbreakable, but can you manage to recover the flag? (Wrap with picoCTF{}) nc mercury.picoctf.net 36981 otp.py

Solution

$ nc mercury.picoctf.net 36981
******************Welcome to our OTP implementation!******************
This is the encrypted flag!
5b1e564b6e415c0e394e0401384b08553a4e5c597b6d4a5c5a684d50013d6e4b

What data would you like to encrypt? picoCTF{abcdefg}
Here ya go!
41085d333b367227195b540f5033302f

What data would you like to encrypt?
Enter fullscreen mode Exit fullscreen mode

It takes an encrypted 32-byte flag, and shows that it can encrypt any character on input. Next, read the attached otp.py.

#!/usr/bin/python3 -u
import os.path

KEY_FILE = "key"
KEY_LEN = 50000
FLAG_FILE = "flag"


def startup(key_location):
    flag = open(FLAG_FILE).read()
    kf = open(KEY_FILE, "rb").read()

    start = key_location
    stop = key_location + len(flag)

    key = kf[start:stop]
    key_location = stop

    result = list(map(lambda p, k: "{:02x}".format(ord(p) ^ k), flag, key))
    print("This is the encrypted flag!\n{}\n".format("".join(result)))

    return key_location

def encrypt(key_location):
    ui = input("What data would you like to encrypt? ").rstrip()
    if len(ui) == 0 or len(ui) > KEY_LEN:
        return -1

    start = key_location
    stop = key_location + len(ui)

    kf = open(KEY_FILE, "rb").read()

    if stop >= KEY_LEN:
        stop = stop % KEY_LEN
        key = kf[start:] + kf[:stop]
    else:
        key = kf[start:stop]
    key_location = stop

    result = list(map(lambda p, k: "{:02x}".format(ord(p) ^ k), ui, key))

    print("Here ya go!\n{}\n".format("".join(result)))

    return key_location


print("******************Welcome to our OTP implementation!******************")
c = startup(0)
while c >= 0:
    c = encrypt(c)
Enter fullscreen mode Exit fullscreen mode

So far, we know that the encrypted flag is 5541103a246e415e036c4c5f0e3d415a513e4a560050644859536b4f57003d4c, the length of the flag is 32 bytes, and the length of the key is 50000 bytes from the source code. From the source code, we know that the length of the key is 50000 bytes. From the "stop >= KEY_LEN" in the source code, we know that if the start position of the key exceeds 50000, it will return to the beginning. And then, send 32 bytes of \x00 at the second "what data would you like to encrypt?", the key will be visible by xor.

$ python3 -c "print('\x00'*(50000-32)+'\n'+'\x00'*32)" | nc mercury.picoctf.net 36981
31613e5c7862345c7839376b355557525c7863305c7862315c7864345c7831
345c7865345c7865365c7864335c7866335a7733375c786566525b5c783165
245c786639325c7866362f5c7863655c7837665c7861315c7863665c786432
5d525c7831317d355c786465555c7865365c7839665c7865637d5c7866345c
78633334605c7864395c7864345c786638555c7838655c786662645c786633
5c7864335c7861635c7862385c7861375c783831795c786363665c7839615c
7864615c786466785c7831375c7838335c786134735c7866667e5c7839646b
52405c786338695c7865625c7839665c7839335c7831372e5c7831375b5c78
61305c7830315c7861653b5c786231685c7861615c786235535c7866355c78
65667a5c7
.
.
.
What data would you like to encrypt? Here ya go!
6227295e455c7838375c7866375c7862355c786430635c7838665c7863365c78
Enter fullscreen mode Exit fullscreen mode

Now all that is left is to xor the flag 5541103a246e415e036c4c5f0e3d415a513e4a560050644859536b4f57003d4c to the key 6227295e455c7838375c7866375c7862355c786430635c 7838665c7863365c78, the decryption is completed.

Alt Text

Conclusion

In some cryptography, you need to be able to read the given source code to solve the problem. This is a good question that requires Python skills and an idea of how to consume the key.

Discussion (0)