[WARGAME NDH 2016] Write-Up – Crypto: A balanced RSA a day keeps the security analyst away!

06
juil.
2016
  • Google Plus
  • LinkedIn
  • Viadeo
Posted by: Yann C.  /   Category: Cryptanalyse / Cryptographie / Cryptologie / CTF / Events / NDH / NDH2k16 / Wargame   /   Pas de commentaire

Présentation d’un write-up de résolution du challenge « Crypto – A balanced RSA a day keeps the security analyst away! » du WARGAME de la Nuit du Hack 2016.

Le weekend du 02-03 juillet 2016 se déroulait le WARGAME de la Nuit du Hack 2016 sous forme d’un CTF Jeopardy. Ayant eu l’occasion et le temps d’y participer avec quelques collègues et amis, voici un write-up de résolution d’un des challenges auquel nous avons pu participer.

  • Catégorie : Crypto
  • Nom : A balanced RSA a day keeps the security analyst away!
  • Description : hey guys, i have intercepted a communication between freeman and majinboo about challs for tonight, and i wanted to troll them by divulgating flags… Unfortunately, i was not able to do so however i got some infos about the tool they use in their encrypted communication. here is what i have so far : rsa public key of freeman, used to encode an aes 256 key with no salt, which is then used to encode the flag.
  • URL : http://static.wargame.ndh/rsa.zip (download rsa.zip)
  • Points : 150

tl;dr : extraction de N et e de pub_key, factordb p et q, rsatool privatekey.pem, openssl pour déchiffrer le flag

Un petit challenge de crypto ! Commençons par regarder le contenu de l’archive :

root@kali 14:23 [~/ndh2k16/rsa/rsa] # ll
total 20
drwxrwxr-x 2 root root 4096 juin 23 19:42 .
drwxrwxr-x 3 root root 4096 juil. 6 14:23 ..
-rw-rw-r-- 1 root root 259 juin 12 12:16 aes_key_cipher
-rw-rw-r-- 1 root root 160 juin 23 19:41 ciphermessage
-rw-rw-r-- 1 root root 455 juin 12 12:10 pub_key
  • pub_key : la clé asymétrique publique RSA de freeman;
  • aes_key_cipher : la clé symétrique AES256 chiffrée via la clé privée RSA de freeman sans salt (que l’on n’a pas…);
  • ciphermessage : le flag chiffré via la clé AES précédente.

Il faut donc :

  1. Retrouver la clé privée RSA de freeman à partir de sa clé publique;
  2. Déchiffrer le contenu de « aes_key_cipher » à partir de la clé privée afin d’obtenir la clé secrète AES;
  3. Déchiffrer « ciphermessage » à partir de la clé secrète AES256 précédemment obtenue.

Regardons de quoi est faite la clé publique de freeman et notamment son exposant (e) et son modulus (N) :

root@kali 13:49 [~/ndh2k16/rsa] # openssl rsa -pubin -in pub_key -text -modulus
Public-Key: (2072 bit)
Modulus:
 00:8d:a5:69:19:b5:26:d4:52:25:ac:ed:4b:e6:45:
 22:ce:f0:4a:63:91:0b:9f:6f:fe:a6:b1:12:55:41:
 01:3b:e4:5d:48:b6:fb:26:71:b7:54:0e:6a:4e:0b:
 55:e3:a9:e4:c4:5a:8d:5f:54:a0:69:9c:65:32:d4:
 a1:28:7f:ac:b0:08:b1:c5:6e:35:d6:01:dc:2a:9e:
 2e:66:51:89:ea:a3:5d:22:d7:be:a2:52:c1:ec:f2:
 70:31:ab:65:7d:5b:35:e8:2c:de:70:f8:25:9d:2e:
 14:e9:86:f3:62:e3:e8:6e:7b:d8:e4:81:2a:52:f2:
 e8:cc:2f:69:b8:b0:c9:59:77:8f:db:24:0a:8e:17:
 cb:95:72:45:70:12:d8:3b:6c:72:72:90:e5:0b:8e:
 7d:a2:8f:eb:df:ab:f5:23:da:03:b9:4b:94:32:2a:
 f4:21:f9:ca:02:ad:e6:04:da:ab:92:cd:9c:28:24:
 44:36:f1:15:fd:be:d7:6d:2c:85:00:7a:ca:7f:ce:
 49:89:3a:f8:0e:79:55:63:2e:c7:b8:9f:56:fa:b0:
 18:76:e0:fe:88:29:9a:37:34:0d:43:9c:b2:e0:1b:
 3c:07:e6:0c:88:47:42:1b:fe:04:9d:59:95:40:6b:
 26:f4:a0:8b:20:d1:49:b3:c6:1a:ae:a3:53:1d:62:
 f8:f8:d1:e2:87
Exponent: 65537 (0x10001)
Modulus=8DA56919B526D45225ACED4BE64522CEF04A63910B9F6FFEA6B1125541013BE45D48B6FB2671B7540E6A4E0B55E3A9E4C45A8D5F54A0699C6532D4A1287FACB008B1C56E35D601DC2A9E2E665189EAA35D22D7BEA252C1ECF27031AB657D5B35E82CDE70F8259D2E14E986F362E3E86E7BD8E4812A52F2E8CC2F69B8B0C959778FDB240A8E17CB9572457012D83B6C727290E50B8E7DA28FEBDFABF523DA03B94B94322AF421F9CA02ADE604DAAB92CD9C28244436F115FDBED76D2C85007ACA7FCE49893AF80E7955632EC7B89F56FAB01876E0FE88299A37340D439CB2E01B3C07E60C8847421BFE049D5995406B26F4A08B20D149B3C61AAEA3531D62F8F8D1E287
writing RSA key
-----BEGIN PUBLIC KEY-----
MIIBJTANBgkqhkiG9w0BAQEFAAOCARIAMIIBDQKCAQQAjaVpGbUm1FIlrO1L5kUi
zvBKY5ELn2/+prESVUEBO+RdSLb7JnG3VA5qTgtV46nkxFqNX1SgaZxlMtShKH+s
sAixxW411gHcKp4uZlGJ6qNdIte+olLB7PJwMatlfVs16CzecPglnS4U6YbzYuPo
bnvY5IEqUvLozC9puLDJWXeP2yQKjhfLlXJFcBLYO2xycpDlC459oo/r36v1I9oD
uUuUMir0IfnKAq3mBNqrks2cKCRENvEV/b7XbSyFAHrKf85JiTr4DnlVYy7HuJ9W
+rAYduD+iCmaNzQNQ5yy4Bs8B+YMiEdCG/4EnVmVQGsm9KCLINFJs8YarqNTHWL4
+NHihwIDAQAB
-----END PUBLIC KEY-----

On converti la valeur hexadécimale du modulus (N) en décimal :

root@kali 13:50 [~/ndh2k16/rsa] # python -c "print int('8DA56919B526D45225ACED4BE64522CEF04A63910B9F6FFEA6B1125541013BE45D48B6FB2671B7540E6A4E0B55E3A9E4C45A8D5F54A0699C6532D4A1287FACB008B1C56E35D601DC2A9E2E665189EAA35D22D7BEA252C1ECF27031AB657D5B35E82CDE70F8259D2E14E986F362E3E86E7BD8E4812A52F2E8CC2F69B8B0C959778FDB240A8E17CB9572457012D83B6C727290E50B8E7DA28FEBDFABF523DA03B94B94322AF421F9CA02ADE604DAAB92CD9C28244436F115FDBED76D2C85007ACA7FCE49893AF80E7955632EC7B89F56FAB01876E0FE88299A37340D439CB2E01B3C07E60C8847421BFE049D5995406B26F4A08B20D149B3C61AAEA3531D62F8F8D1E287', 16)"

On a donc :

  • e : 65537
  • N :
299996217561787292756826251240073744022587364427659002955601969311597453693948323421942282716737653493469667806494795328718748694431287426493332498123774403296361258944222401796946976412532226598881087042326060698386611304550152758781853605660146138394024484376984580234460609993575374222942038026173435262460884234328411077658271473762471945787635582916630508147146325427058379173689622281755189370552117476758492729644576568772220182957835384550972772092654842082706142246481708409910183742375894996805693099913395071166112170527842473265346582564838421321907545834628201837626578791668861148755559537560386588395858682503

Tentons de factoriser N via « factordb« .

factordb

factordb

Bingo ! On obtient p et q, ce qui nous fait :

  • e : 65537
  • N :
299996217561787292756826251240073744022587364427659002955601969311597453693948323421942282716737653493469667806494795328718748694431287426493332498123774403296361258944222401796946976412532226598881087042326060698386611304550152758781853605660146138394024484376984580234460609993575374222942038026173435262460884234328411077658271473762471945787635582916630508147146325427058379173689622281755189370552117476758492729644576568772220182957835384550972772092654842082706142246481708409910183742375894996805693099913395071166112170527842473265346582564838421321907545834628201837626578791668861148755559537560386588395858682503
  • p : 10038779
  • q :
29883735617826360432561196061799322808340273695402498944901762386799973751185111597928620872791168477109583526691323250438997481111127899766827469568139153506254222644429407380812644287968908031433014616849923750526494437675154793105999604698952545762191247000953460598590785791138083050034475111582139148840798690192144988714092767034962314220448082671869806890573676881128509669720752123515737259536455327561100082952775090354336935095177947890970881228947747737320060761022999750259487109176912351273565550144434404937703297435658507201458123798206776075248548238249711627044143395493501863997161361711457796649957

Il nous faut maintenant déterminer d. L’outil « rsatool.py » est particulièrement adapté pour cela. Il permet même de régénérer la « privatekey.pem » automatiquement :

wget https://raw.github.com/ius/rsatool/master/rsatool.py
sudo pip install rsa
sudo pip install gmpy
root@kali 13:56 [~/ndh2k16/rsa] # python rsatool.py
Usage: rsatool.py [options]

Options:
 -h, --help show this help message and exit
 -p P prime
 -q Q prime
 -n N modulus
 -d D private exponent
 -e E public exponent (default: 65537)
 -o FILENAME output filename
 -f FORMAT output format (DER, PEM) (default: PEM)
 -v also display CRT-RSA representation
Usage: rsatool.py [options]

rsatool.py: error: Either (p, q) or (n, d) needs to be specified

Par soucis de visibilité, la commande qui suit de lancement de « rsatool » ne comprend pas les valeurs complètes de N, p et q :

root@kali 13:57 [~/ndh2k16/rsa] # python rsatool.py -p value_p -q value_q -n value_n -e 65537 -o privatekey.pem
Using (p, q) to initialise RSA instance

n =
8da56919b526d45225aced4be64522cef04a63910b9f6ffea6b1125541013be45d48b6fb2671b754
0e6a4e0b55e3a9e4c45a8d5f54a0699c6532d4a1287facb008b1c56e35d601dc2a9e2e665189eaa3
5d22d7bea252c1ecf27031ab657d5b35e82cde70f8259d2e14e986f362e3e86e7bd8e4812a52f2e8
cc2f69b8b0c959778fdb240a8e17cb9572457012d83b6c727290e50b8e7da28febdfabf523da03b9
4b94322af421f9ca02ade604daab92cd9c28244436f115fdbed76d2c85007aca7fce49893af80e79
55632ec7b89f56fab01876e0fe88299a37340d439cb2e01b3c07e60c8847421bfe049d5995406b26
f4a08b20d149b3c61aaea3531d62f8f8d1e287

e = 65537 (0x10001)

d =
832110ab2c16a116e1965b5a87800b80c7374bcd1dde39b22ffea11d47a31e0266364263206b696f
9b6d48e78aca4ad08d02ca47d421be8b1fcb2756e83234e3b143f1a30289c9414fe32af711a0b23e
faa244265d7220d49bfd36df47d47f1a65f35df7bb5e8f0ae7067ae7af31fb387df833e0eb66a425
3a268c5db5b37527cbd15b3de490334255ca3b59e0dd3e04b5bdc47a2997811f061bf5793e563007
54de5833c20f3d26e462590d27473cfcf10a20be329cb197389bc2476ce2d47648865fdff66034cd
47f90c3d83310841cb338eb6a58e577ff7624dad765559677bf638688edff35710010be99c86e355
a41bcd9b960d82b313c20da1dee473f3764759

p = 10038779 (0x992dfb)

q =
ecb98b849f081ab8e52f72310984d30963eea0069c8b9b8d43820228d5af136b93cc901481cbc932
009a3976d599457a9b128afddabb82d3be40e307bfa64c36868047f59a1e4dadade41a737c53612f
bc29c54b4ab461001144c18274d605145eba22e0c62c2a05ad884b0afb9ecd7cec9cf92c44ff05be
52271999b0cec6b7dfb3edba50be9ecd315cfd34247d4c5fa8c62b0e8a67d22bcfa7add17478c443
93b1524e048db062dbcb04bd04aeb8e338c969b84e746f7018e3cbacf5cb9d49fa4937aa183f9e25
13c45bd496f33aef03d894fa1194ba18909ad9f513f112b401c2418d7707c07cbf59cc0cd60dbb2c
7df8ef07e9784fd659e4adfedb2c73e5

Saving PEM as privatekey.pem

La clé privée de freeman a été recréée via la déduction de la valeur de « d ». celle-ci est automatiquement sauvée par « rsatool » dans « privatekey.pem ».

Passons à la récupération (déchiffrement) de la clé symétrique AES contenue dans « aes_key_cipher » :

root@kali 14:10 [~/ndh2k16/rsa] # openssl rsautl -decrypt -in aes_key_cipher -out plaintext -inkey privatekey.pem && cat plaintext
rsa_hackerzvoice_for_win

On a la clé secrète « rsa_hackerzvoice_for_win » !

Déchiffrons le cipher final pour obtenir le flag :

root@kali 14:11 [~/ndh2k16/rsa] # openssl aes256 -d -in ciphermessage -out secrets.txt -nosalt && cat secrets.txt
enter aes-256-cbc decryption password: rsa_hackerzvoice_for_win
hey dude!
keep it up! https://www.youtube.com/watch?v=1F81S50xL8I
btw, i think the flag for this chall should be: ndh2k16_cac4015707
freeman

Flag : ndh2k16_cac4015707

Merci à toute l’équipe de la NDH2K16 pour cet événement et pour toute l’organisation !

Salutations à nj8, St0rn, Emiya, Mido, downgrade, Ryuk@n et tout ceux dont je n’ai hélas pas le pseudo :), on remet ça quand vous voulez 😉 // Gr3etZ

Sources & ressources :

  • Google Plus
  • LinkedIn
  • Viadeo
Yann C.

About the Author : Yann C.

Consultant en sécurité informatique et s’exerçant dans ce domaine depuis le début des années 2000 en autodidacte par passion, plaisir et perspectives, il maintient le portail ASafety pour présenter des articles, des projets personnels, des recherches et développements, ainsi que des « advisory » de vulnérabilités décelées notamment au cours de pentest.