Showing posts with label AlexCTF. Show all posts
Showing posts with label AlexCTF. Show all posts

Tuesday, February 7, 2017

AlexCTF 2017 - Crypto


CR1: Ultracoded (50)


Starting out with a very simple one, here's the description:

Fady didn't understand well the difference between encryption and encoding, so instead of encrypting some secret message to pass to his friend, he encoded it!
Hint: Fady's encoding doens't handly any special character

Initially we're given a file (named zero_one) with a bunch of spelled-out bits:

...ZERO ONE ZERO ZERO ONE ONE ZERO ZERO ZERO ONE ONE ZERO ONE ZERO ZERO ONE ZERO ZERO ONE ONE ZERO ZERO ZERO ZERO ZERO ONE ONE ZERO ZERO ONE ONE ONE ZERO ONE ZERO ZERO ONE ONE ZERO ZERO ZERO ONE ONE ZERO ONE ZERO ZERO ONE ZERO ZERO ONE ONE ZERO ZERO ZERO ZERO ZERO ONE ONE ONE ZERO ONE ZERO ONE ZERO ONE ZERO ZERO ONE ONE ZERO ZERO ZERO ONE ONE ZERO ONE ZERO ZERO ONE ZERO ONE ZERO ZERO ZERO ZERO ZERO ONE ZERO ONE ONE ONE ZERO ONE ZERO ONE ZERO ONE ZERO ZERO ONE ZERO ZERO ONE ZERO ONE ZERO ZERO ZERO ZERO ONE ONE ZERO ZERO ONE ONE ZERO ZERO ZERO ZERO ZERO ONE ONE ONE ZERO ONE ZERO ONE ZERO ONE ZERO ZERO ONE ONE ZERO ZERO ZERO ONE ONE ZERO ONE ZERO ZERO ONE ZERO ZERO...

First thing to do in this situation is to use a bit of sed to convert them all to their original form:

$ cat zero_one | sed 's/ //g;s/ZERO/0/g;s/ONE/1/g;'

0100110001101001001100000110011101001100011010010011000001110101010011000110100101000001011101010100100101000011001100000111010101001100011010010011000001100111010011000101001100110100011101000100110001101001010000010111010001001001010000110011010001110101010011000101001100110100011001110100110001010011010000010111010101001100011010010011010001110101010010010100001100110100011101000100110001010011001100000111010001001001010000110011010001110101010011000110100100110100011101010100100101000011001100000111010001001100010100110100000101110101010011000101001100110000011101000100110001010011010000010111010101001100011010010011010001100111010011000101001100110000011101000100100101000011001101000111010101001100011010010011010001110101010010010100001100110100011101010100110001010011010000010111010101001100010100110011000001110101010010010100001100110100011101010100110001101001001100000111010001001001010000110011010001110100010011000110100101000001011101000100110001010011001100000110011101001100011010010011010001110101010011000110100100110100011001110100110001101001010000010111010001001100011010010011000001110101010010010100001100110100011101000100110001101001010000010111010101001100011010010011010001110100010011000101001101000001011101000100100101000011001100000111010001001100010100110100000101110100010010010100001100110000011101010100110001101001001100000110011101001100010100010011110100111101

Next we can find what this turns into with some perl:

$ cat zero_one | sed 's/ //g;s/ZERO/0/g;s/ONE/1/g;' | perl -lpe '$_=pack"B*",$_'

Li0gLi0uLiAuIC0uLi0gLS4tLiAtIC4uLS4gLSAuLi4uIC4tLS0tIC4uLi4uIC0tLSAuLS0tLSAuLi4gLS0tIC4uLi4uIC4uLSAuLS0uIC4uLi0tIC4tLiAtLS0gLi4uLi4gLiAtLi0uIC4tLiAuLi4tLSAtIC0tLSAtIC0uLi0gLQ==

Now we have some Base64 we can decode:

$ cat zero_one | sed 's/ //g;s/ZERO/0/g;s/ONE/1/g;' | perl -lpe '$_=pack"B*",$_' | base64 -D

.- .-.. . -..- -.-. - ..-. - .... .---- ..... --- .---- ... --- ..... ..- .--. ...-- .-. --- ..... . -.-. .-. ...-- - --- - -..- -

Aaaand now we have some Morse code, which ended up being decoded using - http://morsecode.scphillips.com/translator.html
If anyone knows a good command-line tool for this, please leave a comment below! Would love to add that to the one-liner!

Using the online tool, we get this result:

ALEXCTFTH15O1SO5UP3RO5ECR3TOTXT

It wasn't over yet, this wasn't the flag based on their flag format, but it wasn't too difficult to spot the encoding, all O characters were really underscores:

ALEXCTF{TH15_1S_5UP3R_5ECR3T_TXT}





CR2: Many time secrets (100)


Description:

This time Fady learned from his old mistake and decided to use onetime pad as his encryption technique, but he never knew why people call it one time pad!

Not sure who this Fady person is, sounds familiar... Sounds like we need to crack a poorly encrypted message with OTP issues.
Downloading the file they provide, called msg, we see it's a few lines of hex:

0529242a631234122d2b36697f13272c207f2021283a6b0c7908
2f28202a302029142c653f3c7f2a2636273e3f2d653e25217908
322921780c3a235b3c2c3f207f372e21733a3a2b37263b313012
2f6c363b2b312b1e64651b6537222e37377f2020242b6b2c2d5d
283f652c2b31661426292b653a292c372a2f20212a316b283c09
29232178373c270f682c216532263b2d3632353c2c3c2a293504
613c37373531285b3c2a72273a67212a277f373a243c20203d5d
243a202a633d205b3c2d3765342236653a2c7423202f3f652a18
2239373d6f740a1e3c651f207f2c212a247f3d2e65262430791c
263e203d63232f0f20653f207f332065262c3168313722367918
2f2f372133202f142665212637222220733e383f2426386b

Looking up common techniques for cracking OTP we can find the Many Time Pad Attack / the Crib Dragging technique - http://crypto.stackexchange.com/questions/59/taking-advantage-of-one-time-pad-key-reuse

There's a very nice python library for crib dragging here - https://github.com/SpiderLabs/cribdrag

This allows us to easily read in msg file and start the process of discovery. First we need the messages on one line:

$ cat msg | tr -d '\n'; echo

0529242a631234122d2b36697f13272c207f2021283a6b0c79082f28202a302029142c653f3c7f2a2636273e3f2d653e25217908322921780c3a235b3c2c3f207f372e21733a3a2b37263b3130122f6c363b2b312b1e64651b6537222e37377f2020242b6b2c2d5d283f652c2b31661426292b653a292c372a2f20212a316b283c0929232178373c270f682c216532263b2d3632353c2c3c2a293504613c37373531285b3c2a72273a67212a277f373a243c20203d5d243a202a633d205b3c2d3765342236653a2c7423202f3f652a182239373d6f740a1e3c651f207f2c212a247f3d2e65262430791c263e203d63232f0f20653f207f332065262c31683137223679182f2f372133202f142665212637222220733e383f2426386b

Then we pass this in as the first argument to the cribdrag.py tool, initially we have a blank canvas:

./cribdrag/cribdrag.py 0529242a631234122d2b36697f13272c207f2021283a6b0c79082f28202a302029142c653f3c7f2a2636273e3f2d653e25217908322921780c3a235b3c2c3f207f372e21733a3a2b37263b3130122f6c363b2b312b1e64651b6537222e37377f2020242b6b2c2d5d283f652c2b31661426292b653a292c372a2f20212a316b283c0929232178373c270f682c216532263b2d3632353c2c3c2a293504613c37373531285b3c2a72273a67212a277f373a243c20203d5d243a202a633d205b3c2d3765342236653a2c7423202f3f652a182239373d6f740a1e3c651f207f2c212a247f3d2e65262430791c263e203d63232f0f20653f207f332065262c31683137223679182f2f372133202f142665212637222220733e383f2426386b

Your message is currently:
0       ________________________________________
40      ________________________________________
80      ________________________________________
120     ________________________________________
160     ________________________________________
200     ________________________________________
240     ________________________________________
280     ____
Your key is currently:
0       ________________________________________
40      ________________________________________
80      ________________________________________
120     ________________________________________
160     ________________________________________
200     ________________________________________
240     ________________________________________
280     ____
Please enter your crib:

Now we know that the flag will be in the format ALEXCTF{...}, so we can start with that:

Please enter your crib: ALEXCTF{
*** 0: "Dear Fri"
1: "hho;Q`TV"
2: "ef&JwFkP"
3: "k/WlQymM"
4: ""^qJnp"
5: "SxWuhb/"
6: "u^hsu=9h"
7: "Sann*+U\"
...

Many examples were dropped (276), and a few of them were intelligible. The first one looked like a good candidate, starting with 0, we identify it as a 'message'.

Enter the correct position, 'none' for no match, or 'end' to quit: 0
Is this crib part of the message or key? Please enter 'message' or 'key': message
Your message is currently:
0       ALEXCTF{________________________________
40      ________________________________________
80      ________________________________________
120     ________________________________________
160     ________________________________________
200     ________________________________________
240     ________________________________________
280     ____
Your key is currently:
0       Dear Fri________________________________
40      ________________________________________
80      ________________________________________
120     ________________________________________
160     ________________________________________
200     ________________________________________
240     ________________________________________
280     ____
Please enter your crib:

"Dear Friend," makes the most sense in the clue we have, so going with that we can find more information:

Please enter your crib: Dear Friend,
0: "ALEXCTF{HERE"

This time 0 is the key, next we can guess underscore is after 'HERE' in the flag from the normal flag format. Continuing this process onwards will fill in the full flag:

Please enter your crib: ALEXCTF{HERE_
*** 260: "ncryption sch"
Enter the correct position, 'none' for no match, or 'end' to quit: 260
Is this crib part of the message or key? Please enter 'message' or 'key': message
Please enter your crib: encryption scheme
259: "}ALEXCTF{HERE_GOE"
Enter the correct position, 'none' for no match, or 'end' to quit: 259
Is this crib part of the message or key? Please enter 'message' or 'key': key
Please enter your crib: }ALEXCTF{HERE_GOES_
*** 207: "ecure, Let Me know "
Enter the correct position, 'none' for no match, or 'end' to quit: 207
Is this crib part of the message or key? Please enter 'message' or 'key': message
Please enter your crib: }ALEXCTF{HERE_GOES_
*** 233: "agree with me to us"
Enter the correct position, 'none' for no match, or 'end' to quit: 233
Is this crib part of the message or key? Please enter 'message' or 'key': message
Please enter your crib: agree with me to use this encryption scheme
233: "}ALEXCTF{HERE_GOES_THE_KEY}ALEXCTF{HERE_GOE"


Enter the correct position, 'none' for no match, or 'end' to quit: 233
Is this crib part of the message or key? Please enter 'message' or 'key': key
Your message is currently:
0       ALEXCTF{HERE____________________________
40      ________________________________________
80      ________________________________________
120     ________________________________________
160     ________________________________________
200     _______}ALEXCTF{HERE_GOES________}ALEXCT
240     F{HERE_GOES_THE_KEY}ALEXCTF{HERE_GOE____
280     ____
Your key is currently:
0       Dear Friend,____________________________
40      ________________________________________
80      ________________________________________
120     ________________________________________
160     ________________________________________
200     _______ecure, Let Me know _______agree w
240     ith me to use this encryption scheme____
280     ____
Please enter your crib:

...

Enter the correct position, 'none' for no match, or 'end' to quit: none
No changes made.
Your message is currently:
0       ALEXCTF{HERE_GOES_THE_KEY}ALEXCTF{HERE_G
40      OES_THE_KEY}ALEXCTF{HERE_GOES_THE_KEY}AL
80      EXCTF{HERE_GOES_THE_KEY}ALEXCTF{HERE_GOE
120     S_THE_KEY}ALEXCTF{HERE_GOES_THE_KEY}ALEX
160     CTF{HERE_GOES_THE_KEY}ALEXCTF{HERE_GOES_
200     THE_KEY}ALEXCTF{HERE_GOES_THE_KEY}ALEXCT
240     F{HERE_GOES_THE_KEY}ALEXCTF{HERE_GOES_TH
280     E_KEY
Your key is currently:
0       Dear Friend, This time I understood my m
40      istake and used One time pad encryption
80      scheme, I heard that it is the only encr
120     yption method that is mathematically pro
160     ven to be not cracked ever if the key is
200      kept secure, Let Me know if you agree w
240     ith me to use this encryption scheme alw
280     ays 

Flag:

ALEXCTF{HERE_GOES_THE_KEY}




CR4: Poor RSA (200)


Description:

This time Fady decided to go for modern cryptography implementations, He is fascinated with choosing his own prime numbers, so he picked up RSA once more. Yet he was unlucky again!

poor_rsa.tar.gz

This was a challenge where a little crypto education would've helped. Started this one off by looking up previous write-ups for RSA based challenges on a CTF. This one turned out to be great! - https://0x90r00t.com/2015/09/20/ekoparty-pre-ctf-2015-cry100-rsa-2070-write-up/

Extracting the tar.gz gave us two files, a encrypted flag and a public key:

-rw-r--r--@  1 user  staff    69B Dec 11 01:08 flag.b64
-rw-r--r--@  1 user  staff   162B Dec 11 00:59 key.pub

Walking through that writeup made this process very simple, starting off by identifying how many bits are used on the public key:

Modulus (399 bit):
    52:a9:9e:24:9e:e7:cf:3c:0c:bf:96:3a:00:96:61:
    77:2b:c9:cd:f6:e1:e3:fb:fc:6e:44:a0:7a:5e:0f:
    89:44:57:a9:f8:1c:3a:e1:32:ac:56:83:d3:5b:28:
    ba:5c:32:42:43
Exponent: 65537 (0x10001)

Looks like we also got an odd amount of bits (no pun intended).
Now we need to format the hex values to get the integer product:

openssl rsa -noout -text -inform PEM -in key.pub -pubin | grep -Evi 'mod|exp' | tr -d ':\n '

Then to get the int value, pass it into python:

$ openssl rsa -noout -text -inform PEM -in key.pub -pubin | grep -Evi 'mod|exp' | tr -d ':\n ' | xargs python -c 'import sys; print int(sys.argv[1], 16)'

833810193564967701912362955539789451139872863794534923259743419423089229206473091408403560311191545764221310666338878019

Now we can query factordb for this value: http://www.factordb.com/index.php?query=833810193564967701912362955539789451139872863794534923259743419423089229206473091408403560311191545764221310666338878019

We end up seeing there is a match!


This turns out to be:
863653476616376575308866344984576466644942572246900013156919 * 965445304326998194798282228842484732438457170595999523426901

Now that we have p & q, we can generate the private key using RSATool - https://github.com/ius/rsatool

$ python ./rsatool/rsatool.py -p 863653476616376575308866344984576466644942572246900013156919 -q 965445304326998194798282228842484732438457170595999523426901 -o ./priv.key

Finally we just need to decrypt the flag using openssl:

$ openssl rsautl -decrypt -in flag.raw -inkey priv.key

This drops the Flag:

ALEXCTF{SMALL_PRIMES_ARE_BAD}

Monday, February 6, 2017

AlexCTF 2017 - Forensics & Scripting



Fore3: USB probing (150)


On this challenge we're given a pcap and a description mentioning something is to be found from a USB data transfer. Noticed lots of USB-based pcap challenges on AlexCTF & BITSCTF this year...

One of our agents managed to sniff important piece of data transferred transmitted via USB, he told us that this pcap file contains all what we need to recover the data can you find it ?

fore2.pcap

Firing up wireshark and sorting the packets by size, we can see on the largest one there's a familiar segment in the data section:


Looks like there's a png in here!  By right clicking and selecting "Leftover Capture Data" > "Copy" > "...as Hex Dump" will give us the bytes we need for this challenge.  Throwing that into vim and doing a quick deletion of the first column, then %s/ //g; %s/\n//g will give us one string of hex.  Now we can export the binary data (saved as ./raw) with something like this:


cat ./raw | xargs python -c 'import sys; print sys.argv[1].decode("hex")'  > out1.png

Now we can check out this png for filetype & exif

$ file out1.png
out1.png: PNG image data, 460 x 130, 8-bit/color RGBA, interlaced

$ exiftool out1.png
ExifTool Version Number         : 10.08
File Name                       : out1.png
Directory                       : .
File Size                       : 60 kB
File Modification Date/Time     : 2017:02:06 18:09:03-08:00
File Access Date/Time           : 2017:02:05 19:13:06-08:00
File Inode Change Date/Time     : 2017:02:06 18:09:03-08:00
File Permissions                : rw-r--r--
File Type                       : PNG
File Type Extension             : png
MIME Type                       : image/png
Image Width                     : 460
Image Height                    : 130
Bit Depth                       : 8
Color Type                      : RGB with Alpha
Compression                     : Deflate/Inflate
Filter                          : Adaptive
Interlace                       : Adam7 Interlace
Gamma                           : 2.2
Background Color                : 255 255 255
Pixels Per Unit X               : 2835
Pixels Per Unit Y               : 2835
Pixel Units                     : meters
Modify Date                     : 2016:12:31 19:24:31
Comment                         : Created with GIMP
Warning                         : Corrupted PNG image
Image Size                      : 460x130
Megapixels                      : 0.060


It worked! It's a little corrupted, but as you can see below as we view the image (with alpha fixed), it's good enough to read the flag:




SC1: Math Bot (100)



It is well known that computers can do tedious math faster than human.

nc 195.154.53.62 1337


On this challenge I ended up one of my own tools, PwnUp!  It's a CLI utility for pwntools which allows you to scaffold out a quick client for a remote interactive challenge. Here's a sample run setting up the client for this challenge:


pwnup
[*] Running PwnUp 1.0.6
 [?] Choose a type.
       1) ssh
    2> 2) remote
       3) local
[*] You Chose: remote
host > 195.154.53.62
port > 1337
[+] Opening connection to 195.154.53.62 on port 1337: Done
[*] Press <Ctrl-D> to stop recording ...
[*] Switching to interactive mode
                __________
         ______/ ________ \______
       _/      ____________      \_
     _/____________    ____________\_
    /  ___________ \  / ___________  \
   /  /XXXXXXXXXXX\ \/ /XXXXXXXXXXX\  \
  /  /############/    \############\  \
  |  \XXXXXXXXXXX/ _  _ \XXXXXXXXXXX/  |
__|\_____   ___   //  \\   ___   _____/|__
[_       \     \  X    X  /     /       _]
__|     \ \                    / /     |__
[____  \ \ \   ____________   / / /  ____]
     \  \ \ \/||.||.||.||.||\/ / /  /
      \_ \ \  ||.||.||.||.||  / / _/
        \ \   ||.||.||.||.||   / /
         \_   ||_||_||_||_||   _/
           \     ........     /
            \________________/

Our system system has detected human traffic from your IP!
Please prove you are a bot
Question  1 :
218318831115561303988112386917565 / 13366707491950058576832163796786 =

This dumps the client:

#!/usr/bin/env python
from pwn import *

r = remote('195.154.53.62', 1337)

def main():
  print(r.recvuntil('66707491950058576832163796786 =\n'))
  r.send('16.333029749251356\n')
  r.send('\n')

if __name__ == "__main__":
  main()

The initial client setup has been done, now we just have to generalize the maths. Through a couple iterations, it ended up looking something like this:

#!/usr/bin/env python
from pwn import *

r = remote('195.154.53.62', 1337)

def main():
  for x in range(250):
    print r.recvuntil(' :\n')
    x = r.recvuntil('=\n').replace('=', '')
    print 'Q: {}'.format(x)

    value = 0
    _l, op, _r, _ = x.split(' ')
    _l = int(_l)
    _r = int(_r)

    if op is '+':
      value = _l + _r
    elif op is '-':
      value = _l - _r
    elif op is '*':
      value = _l * _r
    elif op is '%':
      value = _l % _r
    elif op is '/':
      value = _l / _r

    print 'R: {}'.format(value)
    r.sendline('{}'.format(value))

  print r.recvline()
  print r.recvline()
  print r.recvline()
  print r.recvline()

  r.interactive();

if __name__ == "__main__":
  main()


Running this script gives us:

......
Q: 174942629367119018977343151908382 - 15526770931750616720349747677112

R: 159415858435368402256993404231270
Question  247 :

Q: 60323767070161082714762485861860 + 233868579061398884615403732403639

R: 294192346131559967330166218265499
Question  248 :

Q: 249001744992309701987741377654436 + 119589169821601639702529040150239

R: 368590914813911341690270417804675
Question  249 :

Q: 186075071179272307783795940653753 + 205359634338042277068417382152009

R: 391434705517314584852213322805762
Question  250 :

Q: 103090646436160362683705207412345 + 111725961983915005271322948765063

R: 214816608420075367955028156177408
Well no human got time to solve 500 ridiculous math challenges

Congrats MR bot!

Tell your human operator flag is: ALEXCTF{1_4M_l33t_b0t}

Dropping the flag around question 250:

ALEXCTF{1_4M_l33t_b0t}





SC2: Cutie Cat (150)


Usually steganography challenges give me confidence, this one however, did not.  It was still a fun challenge, but I ended up coming back to it and the hint gave away the answer for me.  Initially I had tried many methods, alpha masks, lsb, threshold tweaking / bit layers, xor, etc.  Here is the description with the hint:

yeah steganography challenges are the worst... that's why we got only ~~one ~~ two steganography challenges .
Hint: It scripting because we need a python library to solve the challenge, one that is made in japan.

Searching a bit through the internets for python libraries made in japan, lead me to this page - https://pypi.python.org/pypi?%3Aaction=search&term=japanese

On here, if you search for stego, you find this library - https://pypi.python.org/pypi/steganography/0.1.1

After installing it and running it against the image, it was instant gratification:

$ steganography -d cat_with_secrets.png

ALEXCTF{CATS_HIDE_SECRETS_DONT_THEY}


Again, not the most exciting stego challenge, but I was happy it lead to a moment of recon : )


AlexCTF 2017 - Reverse Engineering: Gifted (50) & unVM me (250)


The challenges on AlexCTF were very fun, I ended up pushing myself further trying out new techniques and categories I usually don't touch as much.


Gifted


This was a very simple challenge, just strings the binary and there you go!

$ strings gifted | grep -i alexctf

AlexCTF{Y0u_h4v3_45t0n15h1ng_futur3_1n_r3v3r5ing}



unVM me


This challenge was a lot of fun, and not something you usually see. It was a python reversing challenge where you were given a pyc. Here's the description:

If I tell you what version of python I used .. where is the fun in that?

unvm_me.pyc

Looking around for a python decompiler, we can find this - https://github.com/gstarnberger/uncompyle

Creating a new python virtual environment for this uncompyle tool we can extract the source easily:

mkdir blah
$ virtualenv blah
$ source ./blah/bin/activate
$ pip install uncompyle2
$ ./blah/bin/uncompyle6 ./unvm_me.pyc > unvms.py

Looking at the source we have:

$ cat unvms.py

import md5
md5s = [174282896860968005525213562254350376167L, 137092044126081477479435678296496849608L, 126300127609096051658061491018211963916L, 314989972419727999226545215739316729360L, 256525866025901597224592941642385934114L, 115141138810151571209618282728408211053L, 8705973470942652577929336993839061582L, 256697681645515528548061291580728800189L, 39818552652170274340851144295913091599L, 65313561977812018046200997898904313350L, 230909080238053318105407334248228870753L, 196125799557195268866757688147870815374L, 74874145132345503095307276614727915885L]

print 'Can you turn me back to python ? ...'
flag = raw_input('well as you wish.. what is the flag: ')
if len(flag) > 69:
    print 'nice try'
    exit()
if len(flag) % 5 != 0:
    print 'nice try'
    exit()
for i in range(0, len(flag), 5):
    s = flag[i:i + 5]
    if int('0x' + md5.new(s).hexdigest(), 16) != md5s[i / 5]:
        print 'nice try'
        exit()

print 'Congratz now you have the flag'

So now that we have this, it's pretty easy to see what else we need to do, we just have to crack 13 MD5 hashes.
Adding this line under the md5s list helped print out the hashes:

for x in md5s: print '{0:032x}'.format(x)

This yields the output:

831daa3c843ba8b087c895f0ed305ce7
6722f7a07246c6af20662b855846c2c8
5f04850fec81a27ab5fc98befa4eb40c
ecf8dcac7503e63a6a3667c5fb94f610
c0fd15ae2c3931bc1e140523ae934722
569f606fd6da5d612f10cfb95c0bde6d
068cb5a1cf54c078bf0e7e89584c1a4e
c11e2cd82d1f9fbd7e4d6ee9581ff3bd
1df4c637d625313720f45706a48ff20f
3122ef3a001aaecdb8dd9d843c029e06
adb778a0f729293e7e0b19b96a4c5a61
938c747c6a051b3e163eb802a325148e
38543c5e820dd9403b57beff6020596d

Using john we can crack these pretty quickly:

$ john --incremental=LowerNum hashes --format=raw-md5

Here's the result:

831daa3c843ba8b087c895f0ed305ce7: ALEXC
6722f7a07246c6af20662b855846c2c8: TF{dv
5f04850fec81a27ab5fc98befa4eb40c: 5d4s2
ecf8dcac7503e63a6a3667c5fb94f610: vj8nk
c0fd15ae2c3931bc1e140523ae934722: 43s8d
569f606fd6da5d612f10cfb95c0bde6d: 8l6m1
068cb5a1cf54c078bf0e7e89584c1a4e: n5l67
c11e2cd82d1f9fbd7e4d6ee9581ff3bd: ds9v4
1df4c637d625313720f45706a48ff20f: 1n52n
3122ef3a001aaecdb8dd9d843c029e06: v37j4
adb778a0f729293e7e0b19b96a4c5a61: 81h3d
938c747c6a051b3e163eb802a325148e: 28n4b
38543c5e820dd9403b57beff6020596d: 6v3k}

Now with some sed & tr, we have the flag!

$ cat solution | sed 's/.*://g' | tr -d '\n '; echo

ALEXCTF{dv5d4s2vj8nk43s8d8l6m1ds9v41n52nv37j481h3d28n4b6v3k}