この大会は2019/9/14 5:00(JST)~2019/9/16 5:00(JST)に開催されました。
今回もチームで参戦。結果は2301点で1301チーム中52位でした。
自分で解けた問題をWriteupとして書いておきます。
mcgriddlev2 (Misc 1)
問題にフラグが書いてあった。
flag{W3lcome_7o_CSAW_QUALS_2019!}
beleaf (Rev 50)
Ghidraでデコンパイルする。
undefined8 FUN_001008a1(void) { size_t sVar1; long lVar2; long in_FS_OFFSET; ulong local_b0; char local_98 [136]; long local_10; local_10 = *(long *)(in_FS_OFFSET + 0x28); printf("Enter the flag\n>>> "); __isoc99_scanf(&DAT_00100a78,local_98); sVar1 = strlen(local_98); if (sVar1 < 0x21) { puts("Incorrect!"); /* WARNING: Subroutine does not return */ exit(1); } local_b0 = 0; while (local_b0 < sVar1) { lVar2 = FUN_001007fa((ulong)(uint)(int)local_98[local_b0]); if (lVar2 != *(long *)(&DAT_003014e0 + local_b0 * 8)) { puts("Incorrect!"); /* WARNING: Subroutine does not return */ exit(1); } local_b0 = local_b0 + 1; } puts("Correct!"); if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) { /* WARNING: Subroutine does not return */ __stack_chk_fail(); } return 0; }
入力文字の先頭から1バイトずつに対して、FUN_001007faの結果、DAT_003014e0の先頭から8バイトごとに比較し、同じであればよい。
long FUN_001007fa(char cParm1) { long local_10; local_10 = 0; while ((local_10 != -1 && ((int)cParm1 != *(int *)(&DAT_00301020 + local_10 * 4)))) { if ((int)cParm1 < *(int *)(&DAT_00301020 + local_10 * 4)) { local_10 = local_10 * 2 + 1; } else { if (*(int *)(&DAT_00301020 + local_10 * 4) < (int)cParm1) { local_10 = (local_10 + 1) * 2; } } } return local_10; }
FUN_001007faは複雑なので、1文字ずつブルートフォースして、フラグを割り出す。
def fun_001007fa(c, d): l10 = 0 while (l10 != -1) and (ord(c) != ord(d[l10])): if ord(c) < ord(d[l10]): l10 = l10 * 2 + 1 else: if ord(d[l10]) < ord(c): l10 = (l10 + 1) * 2 if l10 >= len(d): return -1 return l10 data1 = 'wf{_ny}\xffblr\xff\xff\xff\xff\xff\xffaei\xffot' + '\xff' * 16 + 'g' \ + '\xff' * 6 + 'u' + '\xff' * 253 + '\x00' * 4 data2 = [0x01, 0x09, 0x11, 0x27, 0x02, 0x00, 0x12, 0x03, 0x08, 0x12, 0x09, \ 0x12, 0x11, 0x01, 0x03, 0x13, 0x04, 0x03, 0x05, 0x15, 0x2e, 0x0a, 0x03, \ 0x0a, 0x12, 0x03, 0x01, 0x2e, 0x16, 0x2e, 0x0a, 0x12, 0x06] flag = '' for i in range(len(data2)): for code in range(32, 127): if fun_001007fa(chr(code), data1) == data2[i]: flag += chr(code) break print flag
flag{we_beleaf_in_your_re_future}
byte_me (Crypto 50)
$ nc crypto.chal.csaw.io 1003 8e3a4d70926b32ebb4b80e01189400f5086f25345940d66251babd2416e8eead8ffd5269278d9698812b891f577ff29c Tell me something: 1 1 9dda04f64d140ce28198d71a17c9a16a264e34905a8e2b98de75bfbb62511843f9695b9b19b68e18a855fd4165a0759d8ea390f066b50eb675fffeff8495c3ea Tell me something: 11 11 62dce69af355d465f4a088272724eff92f1c4ea0d91991823fccedaf1d94571bdfd97444cbfb5c6ed1b34a55899e2c3ebaaf99f38e84a6fd0a6642df7b712128 Tell me something: 111 111 abc5b8172151e716c60c523e39216edf9251a2a5cdb06e5750347aea2dc55c770f429cd2f7dd7fe3745678f9a5883ae2c03462ccf07acd173cdb0f5e301aded0 Tell me something: 1111 1111 53f47a70d13d8e20d1cc42c0a2325d0040212da4ec2809de85334b33cc6b042000e44eac9de2d4936504f9d473256119d1c243a49e01912ddcc6d23ef2a48a23 Tell me something: 11111 11111 857b2920911fb76c7e85cd19827ed6720049a29b122473108f213308d65e51440c533b2662c66c23cfc090435366f5ec5e8087e099425589c07996f8296d674e Tell me something: 111111 111111 6d066dc3da495754785925f977d4608fbf82745fb42de4a14cf7611290ca1b25ed6ec3190c45cb32d73597863acff829ad25096ca29779d444c0577dacffa349 Tell me something: 1111111 1111111 2287829082fa2e8505e659b4334112e165950407b7ab634c61cad1948b1d86209f2192349315b3c582dee17c2921778172ce67fb239624c51e6923269fd224e8 Tell me something: 11111111 11111111 6158350a39f891f48c7aadd6016929e97f86432532d9efeb845bfc0db2042e4892423d64fd379ac0dea7528d983d6a039d18dee79e57138fff3851561de63909 Tell me something: 111111111 111111111 cdc2c9e31679b591e6aab11bfde5844badbd372bd6aecde3fc525b8216abb3d9a208e24b91039bd0959c0203fe587844b1ffbc6a86dfb84a5c404c4886028243 Tell me something: 1111111111 1111111111 0ea89afaacfba70ad2e826db9f07ee8d8a4d7d46228f6d80574b08bc7f17c3345f9d429b73e80185b613dd695fd8cc0c0265317e33ee102b19bc1526b84b9696 Tell me something: 11111111111 11111111111 8cb20a624038412d7aea7d0b09a3e5a1c8683a01bd349eee78d2cfacb308c8a267fa6f630031312508447603446ef1a5a63a57ba14017694cce47b8e08b81d44 Tell me something: 111111111111 111111111111 22d566a71035fec1b7c7e58ca65f64e23f2479b333df5d120194ea7f36360bdc218db8645397986cb5a53e4f31ea8900c63916fb939a745b5efb806323c0c416 Tell me something: 1111111111111 1111111111111 43fb5cdacd8325351d9288a49cd7a490756f30735e7ae58c85384630d75165abe7dcd9b4db0739d553e79e90e7a5438ce0593a91ded5f8ddd2d7db8ae76726b7 Tell me something: 11111111111111 11111111111111 6b117dc1904ba5a12a03e46ec2aebc058293d384389a2abcb752fac6b6e5c4f3432cb3e234c61b987401528b974a717e7157d9d202b615dbb015f73e7baaf38b Tell me something: 111111111111111 111111111111111 6b117dc1904ba5a12a03e46ec2aebc057f61f330259ba1ccc54ac820b909598e8a2f7bc303ba9bfa81c0d66799e8bda3391c47ff2e503469dd03aa35d905adca Tell me something: 1111111111111111 1111111111111111 6b117dc1904ba5a12a03e46ec2aebc0561b740da7797aaab1349a9bb74d1e37b086f25345940d66251babd2416e8eead8ffd5269278d9698812b891f577ff29c Tell me something: 11111111111111111 11111111111111111 6b117dc1904ba5a12a03e46ec2aebc058bee55c773bc41bee18bd3a30a8e69b2264e34905a8e2b98de75bfbb62511843f9695b9b19b68e18a855fd4165a0759d8ea390f066b50eb675fffeff8495c3ea
AES暗号と推測できる。14バイト入力以降、暗号の最初の16バイトが同じ。
$ nc crypto.chal.csaw.io 1003 61835cf30e584280675ba53d13cc1ee9e6eacfc06b1a067d455e3f5ca9ec2ba1e38c5804b51b070717cf7116d9d6ad9a Tell me something: 11111111111111111 11111111111111111 0071526a819c004eddfc086ca46cc5afaa1d3d0aafb3875c4f1b486779ee314123954b52b47f09098f87b3466f5679df3a4237df6e0bb82ade1e43acdc0c448b140c08213d26ff80ed32e0ee8e3d5c0c Tell me something: 111111111111111111111111111111111 111111111111111111111111111111111 0071526a819c004eddfc086ca46cc5af82f1811eb70021838da3a52c5c5934c0aa1d3d0aafb3875c4f1b486779ee314123954b52b47f09098f87b3466f5679df3a4237df6e0bb82ade1e43acdc0c448b140c08213d26ff80ed32e0ee8e3d5c0c
16バイト同じデータを追加してみる。暗号も最後16バイトは同じデータになった。ECBモードのようだ。
17バイト入力で、80バイトになったので、以下のような構成になっているはず。
0123456789abcdef SSFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFP 0123456789abcdef SSxxxxxxxxxxxxxx xxxFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF PPPPPPPPPPPPPPPP
1文字ずつはみ出させ、暗号結果を比較し、フラグを求める。そう思ってスクリプトを作成したがうまくいかない。アクセスするたびに先頭のsaltの長さが変わっていると思われる。
flag: 45バイト x: 5バイトで80バイトの暗号化データになった場合 0123456789abcdef SSSSSSSSSSSSSSxx xxxFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF PPPPPPPPPPPPPPPP 0123456789abcdef SSSSSSSSSSSSSSxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxF xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFPPPP 0123456789abcdef SSSSSSSSSSSSSSxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxF FFFFFFFFFFFFFFFF xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFPPPP
このことを考慮してスクリプトを作成する。
import socket def recvuntil(s, tail): data = '' while True: if tail in data: return data data += s.recv(1) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('crypto.chal.csaw.io', 1003)) data = recvuntil(s, '\n').rstrip() print data enc_len = len(data) / 2 print enc_len #### research salt length #### LEN_FLAG = 45 for i in range(16): data = recvuntil(s, ': ') try_text = '1' * (i + 1) print data + try_text s.sendall(try_text + '\n') data = recvuntil(s, '\n').rstrip() print data enc = recvuntil(s, '\n').rstrip() print enc if len(enc) / 2 != enc_len: salt_len = 63 - LEN_FLAG - i break #### get flag byte by byte #### flag = '' for i in range(LEN_FLAG): for code in range(32, 127): head_blocks = 'x' * (16 * 4 - salt_len - i - 1) + flag + chr(code) try_text = head_blocks + 'x' * (16 * 4 - i - 1) data = recvuntil(s, ': ') print data + try_text s.sendall(try_text + '\n') data = recvuntil(s, '\n').rstrip() print data enc = recvuntil(s, '\n').rstrip() print enc enc4 = enc[32*3:32*4] enc8 = enc[32*7:32*8] if enc4 == enc8: flag += chr(code) break print flag
flag{y0u_kn0w_h0w_B10cks_Are_n0T_r31iab13...}
count_on_me (Crypto 100)
$ nc crypto.chal.csaw.io 1002 Send me a random seed 1111222233334444 Encrypted flag: FF�����q����+b뾅n�u��RĬ�a�Rر:]�[�&G\�H� ����k�]��4+a��&ZXQy$T�&������E�pr��_���͜o gL��Z*���^N�`�Pot ?�`��O��s���*lT���T��Di��w�� �J�j�Lֹ��J:������.�/�����.�س��^Ǩ�d�e �l?� �5@�ʰ�n#��9Na� ��vZ�Ń���3�x� d��U��V�'bI�� Ww� UE�C���I�</��d�=�n�u ]˝{p0��j����O��$�w }~��9-��+:��yɴ����JmkR-�K����D���X��Ҩ) �82���cn3�_(������Ҿ�G���4/=���syFp��f9Z'��$� `[1��YB�� �H��2N�F�����X �S�b�#2�8�{ �s��: ��oRG�P��ߨ�GG�Y4��aq��xbx�3���A�&�~n �f���|�"��$�t3E�ƶ�Ay�ȯ�iA50���6Z���%����G^ �#7lgH�η�4��s�x��a���NxtӡK�]e��Q6��QUw��� ��/=BTZ\mk�w�#۵����@ o�� 3t���L�!����G�W U��5ח,�S��������:�ǩ��_�&�L�n������^ɯ��h0 �����A.P���gF�j}���7dε�^SU�i�?V��0i�;mA�� �; 4F�\�M�*��P"�az����0��x2�^x��0� ]͓D�Q� SR���l�q�F���B2'�^��{-���b�N��^��5�ٕ���Lɥ �`�'�rq.%�g�`8�U��mP�w|:��S�t���h ��� E�� �"UDO��Ɗ�=� ²��Zi�D����-���ž���v7��I���� ��kZ�~�z�Q��|F���&��Ԡ�9���iT��L�#:�� aG� �k!ᬡB�:a�e�8Lل��'����ԧ�%i!e� "\=>_%�3�!����0Ś3�5�z�#)�Bh��-�`)�a����i�� 3�|\������ X��_��9���;�� g���v8^z�����!}� )2��qʦzo����wN#��{�o�@(8��b�@����8M�,ƒ| �B@����x�Ι�;\� �>m��GWYBg,�xc���ڎ�,��A3� �t�N��ʝ�ιI��������ӳ����!�� ��i�}y��) ��' ��9���F"�ӂz�HLL �I�`���yՉĔqj�~(�fi8x�t �u��V��T ���]#~��W:zf�_��qJխ���X�@5u �|)e����|2�r��� M�&�5KK�94����Dc�m�yr"�gϚYў -�g��&'����w> 0�E��C3�O�jR7Όޅ���_��$m"�j �"'hy�v%%�Tw*�����0 6��[[�p��}���\����<��� �,����͌�?���&}֞�jMd��7B���L(]� �\H-�'�t�Jo k��=��lQm>T���Ƽk�{_�� #���e,������6/=�-?� 2�uCG���Mتp�i$�d�5 ��j�-����"�f�Y엕�o�<Z�P�R }DG*ۧ�ɲ�%n�';1��~����B���_5��Y�m�~$���%aŹ m� O>^7��:^��+_s���v\�s��(f,����r���i��v �nYM�5њ�gc �G#h����˘���ŒB/�}���&R���i 1 R ,�ǖ�b~��:S�=�8 J� ��rKOӨx���ydw���.�?���� U,��t��éܗf�X � �����Zm2��+�4g��'��{z'�"�T J�:��<�[.��W/ͩ[a>g�U�[���ié<�_����|d�� �3F�'�&�Ç�ޏ��W���5�)y�0��[�x�������.�� �ͮ���7��9q���"^v�-@�:C�SD6�~�s0�ȖVva�(lf2w, 1s��$0�Kp��8`� �8vą*�MͿ6��5evg<;ϕ�U՜vEuMu�� )���ʘ��hM?KE/��&x����dTI��}��q��O�M�BkUӊO�u �j��-�=e������r��L� Ƀ��v��dOEm8U�b��/q�}� �'}��<7ٹJ�/�)t����D|�Ԛ�2����@Y2xG��^%F[�W�� ��d� Ȁ��@"�I ��ȑd���:��#�-ߙ �cA��\��$D� !Q���1�1z�=Q����G��MfU�7�5!�Ypsd�z 5�eFi@�����6b�H�p]x:��ZMQ5�B��iu��;��Φ�� ;.�a/L�����:&6���+����ۃ�`�����'93�)S�琋��� �2 ���x&��[�\X�UA�(Nu���6��|��Ć��^\�0V�����Y%� ��d�\�MNjq�;�p�7�܄�j�|����R�·��(�2�������� ���K�����`��G� ��\xv��u,�U|��k1�L� p���߈�) #��5�D�)��{5�K�M��d�qQ�.Wa�NS1/^��� cWg���� >W%˭E ���V)Z��)Ư@��8�雩Ȯ���m.α �F. ����ʦ �,#������6��5��eBA�$��'Y~��\��s�on����#}�|�$� ڜP�����t�y�lP$,����&ß�/;�%١u�n�=S�C"�̣ `���y� )i��N ,�]���FC]�J��K�{Z��y��3����$b�� Ew��ƧE��r�ڢ��Ut㶛�rA H�&�g�gN�Krc�v�� ��9P�g� �f���NE�b.�T��G|hS���C��(�'eQ����r��� ��B!w�4(�b䢎��m :���(0����c�򂠮��mt�60�K���� x}I�bX=���=|��W��klnr1� mq��G%��]{-]~��� ܟ���c�D���6����V$�T`����M"�L �rnE��NO�I' �?�CVx� ��z���*�ɯ���s��֒�F&�Y4����4�?�wI��v2��� �H���2�U�J���1��o, ��k�{s��xQ����1����+�c� ���E��D;���C�>�o- h{�&�I��� �;��2��r�YLyD��< �_�Y^ai儹���y//j��X�� Q��/�� ���L]���9&t� ��cJV�s1�Mv����ph���Ԣ�� S���N�9'=���W^�~�X˨����!�9AM>ˉ�䃽S���&�( �Xѹ�T��B�(,�R��P擜Z��`#��I�ߞ���'�c�~��gP� ޠՏC�? �(�&��#Ǔפ�ڧ�:w�/��ubpe] ���{K��C���p��%���}�������������YC���AbJ�, 1t]������/U�ɦ��w�I�5(��T+.,�pU�K�����b pr��o�' ���4ԧ����Q����~�3,9ϯ��0�����z� yOL� �L/B��䩕��[���z��B�BhMw~Sy���`QȐq+��X� �5=�h�2e�01g��>�6���w��[�Ym�e”�@n+� à}'=� ��|��$b�rs��J�V�s\�����ju+���#� 3p�� 2�.�q� �>� ɷm�����7]�l��Ap �>"�� �/�?�� `���G�Y��e�� j�6 U�"\x����NK �i�5B���4u� ];}�L�/�Ķ�z���v�C�Va��y%���iDv���n\B)T�.��!� �N�bS�Z\��;u]�G\�.� �1i^L� .��� ��6�?S���� � �?�����Ѣ�������<�Sz�~V�� ��7���}��7������ ���2hƃ��>��r<A���Aպm ܜ|R��n������B �&�ݽ�gG��"$���VRڃ_�Ė�J�d\�W O��ؽ.���j���� �����6A���Е�i��Z�;��-���+aaK�5�u Te�y���p��7 hr����d7 � ^���w�Ҍ�-u{S���]ވ��Z%��80�f� B�NJ��ڢNP&5G) &Qm�d4ר�`�S��0 �M h��p�ړ �� ]G7@��X���X3P�l�c�v��vϸk�HY#��9�@��x!Ak�Ox���a �9w�R����Xf����fdi����% $l� $9�����p��@-�� ���ƥ8�x�.��L&�l v<�'d�P�fu��Ay:��"w!ɨ@�V k�Z*m=o��Z[����r� ��06�K���#ZV~@j^6%=.� �=b��<E ��7SRN��9�%#�����t٨��k��g��Y�ɖq�!�n ��-�fk�^%ĺ�S�x�E�eBx}�͜y���F�s�vYѻ)�� ��z>lߒC�� S�x�e�B��P�r0���\.<e��) )�BA ���=B5M�O���b��Lhs,:�l!�./_ε���[+� �!'�HK9qD��J�nT#/M�����=K�Ъ�r�m���������� �%�E�����W�xLF$��e��*��C����])�ҫ������WK��� ����l ��:����Ɠ�*��;~~�W� ��b�}�x��Q� ��� ��� �_h‚N�i��!��6�8�3#��g�D��W�oGS�o�IՄ��,�� Okay bye
サーバ処理の概要は以下の通り。
・randomのseedを数値(16桁)で指定する。 ・100回、以下を実行する。 ・'Encrypted Flag: <flag>'の暗号化を表示 ※暗号化 ・blocks: 16バイトごとの配列(\x00パディング) ・4バイトランダム整数→16バイトリトルエンディアン aes.encrypt(16バイトリトルエンディアン) ^ block
暗号化データの長さから暗号化対象は3ブロック分であることがわかる。つまりランダム値を取得する処理を300回行うことになる。最初のブロックの平文が"Encrypted Flag: "と分かっているため、最初のブロックと別のブロックで、同じランダム値になれば、XORで平文を求めることができる。まずは300回の中で同じランダム値になるものを探す。
import random init = 1000000000000000 for seed in range(init, init + 1000000): random.seed(seed) rv = [] for i in range(300): rv.append(random.getrandbits(32)) if len(set(rv)) != 300: print 'seed =', seed print list(set([x for x in rv if rv.count(x) > 1]))[0]
この結果は以下の通り。
seed = 1000000000026100 3908936488 seed = 1000000000027013 1797854874 seed = 1000000000242922 888417342 seed = 1000000000303303 2077519103 seed = 1000000000394343 1302182496 seed = 1000000000533328 2485904517 seed = 1000000000673051 3982022670 seed = 1000000000721327 3930063372 seed = 1000000000732217 3280084977 seed = 1000000000764544 2876139729 seed = 1000000000802182 3602748008 seed = 1000000000862650 982727507 seed = 1000000000890137 2088408045 seed = 1000000000958167 1824344903
さらに異なるブロック間で同じものを探す。
import random seeds = [1000000000026100, 1000000000027013, 1000000000242922] doubles = [3908936488, 1797854874, 888417342] for i in range(len(seeds)): random.seed(seeds[i]) print 'seed =', seeds[i] for j in range(300): rv = random.getrandbits(32) if rv == doubles[i]: print j, j % 3
この結果は以下の通り。
seed = 1000000000026100 113 2 253 1 seed = 1000000000027013 60 0 260 2 seed = 1000000000242922 12 0 121 1
この情報を元に復号する。
import socket import random from Crypto.Cipher import AES def recvuntil(s, tail): data = '' while True: if tail in data: return data data += s.recv(1) def str_xor(s1, s2): return ''.join(chr(ord(a) ^ ord(b)) for a, b in zip(s1, s2)) PT1 = 'Encrypted Flag: ' #### SEED = 1000000000242922 #### SEED = 1000000000242922 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('crypto.chal.csaw.io', 1002)) data = recvuntil(s, '\n').rstrip() print data print SEED s.sendall(str(SEED) + '\n') data = recvuntil(s, '\n').rstrip() print data encs = [] for _ in range(100): data = s.recv(48) print data encs.append(data) data = recvuntil(s, '\n').rstrip() print data data = recvuntil(s, '\n').rstrip() print data index1 = 12 enc1 = encs[index1 // 3][16*(index1%3):16*(index1%3)+16] key = str_xor(PT1, enc1) index2 = 121 enc2 = encs[index2 // 3][16*(index2%3):16*(index2%3)+16] pt2 = str_xor(key, enc2) #### SEED = 1000000000027013 #### SEED = 1000000000027013 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('crypto.chal.csaw.io', 1002)) data = recvuntil(s, '\n').rstrip() print data print SEED s.sendall(str(SEED) + '\n') data = recvuntil(s, '\n').rstrip() print data encs = [] for _ in range(100): data = s.recv(48) print data encs.append(data) data = recvuntil(s, '\n').rstrip() print data data = recvuntil(s, '\n').rstrip() print data index1 = 60 enc1 = encs[index1 // 3][16*(index1%3):16*(index1%3)+16] key = str_xor(PT1, enc1) index2 = 260 enc2 = encs[index2 // 3][16*(index2%3):16*(index2%3)+16] pt3 = str_xor(key, enc2) print flag = pt2 + pt3 print flag
実行結果は以下の通り。
Send me a random seed 1000000000242922 Encrypted flag: b謇D・ サ・-ムF]テ/゚ヒC゙woセセ遊返怕}ux|。ナヨ・ア]yヲ ЖN「q)・ソ・ トp6d夷Aュ{ヘQ_ ク萼 傳ケヲ禅頓 l・暝ヨヲータD・e郗ッ・ゥ{cw・ゥ誣オ縉!ァサュョ牒ア頚・ M・*ー戓dンッソj・kW斈bVィ~ケ砕v4給・・・,t pdQ0齦・Tqn憚・Y犲Rスfウez「0キ俸q・督皛;ネ鉈・ ス・ナnワY<瀅キ-ヒ"ヒe7テ9i・f}諫V+9チナ鯑6キワ3 0ヘrEKセ密リ~ &コ「フXFgN 乳・J4ンユEa&レD酢脾ン>」ハ ・P&]・yg~イトイU ・6稹・・ta$・・ Aウo$IエNYr : : フ*・hカSィz輩・B。1SVgIw*Jノマホ〔ソX?・・Bln 矍ヲ郝・ウチ$ウュ・jvワ・・須m ・イMA殄kヒ」V晄 スyスア}[2・Rン・暴Z^ャK・敵1ヒリ,ヘト・屑$Y・・,ョシ ・・#J這ー=嘴уモW・伴軽シ ッAハムャソpヒ4サゥ&乗Syォ1苓サeエEュツレキvヲチr熬Q毆 ノwW3293禪;・・d+GW?ッA薜・z・€嶝コ燈hm遮滾 鳰媾チ{・ネロエ5フ・・1Wヨ8{ラモ簔?ム垳s・ユi・lリAヵM 0!ィ=□WM輦悔ニA・ ゥ・\ホPエョI衣テG# Okay bye flag{U_c@n_coUn7_0n_m3_l1kE_123}
flag{U_c@n_coUn7_0n_m3_l1kE_123}
DES 2 Bites (Crypto 200)
暗号化のイメージはこのような感じ。
plainText --(key1, DES暗号)--> byte --(key2, DES暗号) --> cipherText
DES2Bytes.txt、DES2Bytes.encが与えられているので、その組み合わせから鍵を求める必要がありそう。key1, key2ともDESのWeak keyが使われているとヒントが出たため、下記のURLの内容を参考に総当たりする。
https://en.wikipedia.org/wiki/Weak_key https://crypto.stackexchange.com/questions/12214/can-you-explain-weak-keys-for-des
from Crypto.Cipher import DES import binascii import itertools IV = '13371337' def getNibbleLength(offset): if str(offset)[0] == '9': return len(str(offset)) + 1 return len(str(offset)) def decodeText(cipherText, offset): nibbleLen = getNibbleLength(offset) output = '' for i in range(0, len(cipherText), nibbleLen): val = int(cipherText[i:i+nibbleLen]) - offset if val > 10: val -= 1 output += hex(val)[2] output = output.decode('hex') return output def padInput(input): bS = len(input) / 8 if len(input) % 8 != 0: return input.ljust((bS+1) * 8, '_') return input def unpadInput(input): return input.rstrip('_') def desEncrypt(input, key): cipher = DES.new(key, DES.MODE_OFB, IV) msg = cipher.encrypt(padInput(input)) return msg def desDecrypt(input, key): cipher = DES.new(key, DES.MODE_OFB, IV) msg = unpadInput(cipher.decrypt(input)) return msg #### get keys #### with open('DES2Bytes.enc', 'r') as f: ct = f.read() ct = decodeText(ct, 9133337) ct = binascii.unhexlify(ct) with open('DES2Bytes.txt', 'r') as f: pt = f.read() vuln_keys = [ '0101010101010101', 'FEFEFEFEFEFEFEFE', 'E0E0E0E0F1F1F1F1', '1F1F1F1F0E0E0E0E', '0000000000000000', 'FFFFFFFFFFFFFFFF', 'E1E1E1E1F0F0F0F0', '1E1E1E1E0F0F0F0F', '011F011F010E010E', '1F011F010E010E01', '01E001E001F101F1', 'E001E001F101F101', '01FE01FE01FE01FE', 'FE01FE01FE01FE01', '1FE01FE00EF10EF1', 'E01FE01FF10EF10E', '1FFE1FFE0EFE0EFE', 'FE1FFE1FFE0EFE0E', 'E0FEE0FEF1FEF1FE', 'FEE0FEE0FEF1FEF1', '1F1F01010E0E0101', 'E00101E0F10101F1', '011F1F01010E0E01', 'FE1F01E0FE0E01F1', '1F01011F0E01010E', 'FE011FE0FE010EF1', '01011F1F01010E0E', 'E01F1FE0F10E0EF1', 'E0E00101F1F10101', 'FE0101FEFE0101FE', 'FEFE0101FEFE0101', 'E01F01FEF10E01FE', 'FEE01F01FEF10E01', 'E0011FFEF1010EFE', 'E0FE1F01F1FE0E01', 'FE1F1FFEFE0E0EFE', 'FEE0011FFEF1010E', '1FFE01E00EFE01F1', 'E0FE011FF1FE010E', '01FE1FE001FE0EF1', 'E0E01F1FF1F10E0E', '1FE001FE0EF101FE', 'FEFE1F1FFEFE0E0E', '01E01FFE01F10EFE', 'FE1FE001FE0EF101', '0101E0E00101F1F1', 'E01FFE01F10EFE01', '1F1FE0E00E0EF1F1', 'FE01E01FFE01F10E', '1F01FEE00E01FEF1', 'E001FE1FF101FE0E', '011FFEE0010EFEF1', '01E0E00101F1F101', '1F01E0FE0E01F1FE', '1FFEE0010EFEF001', '011FE0FE010EF1FE', '1FE0FE010EF1FE01', '0101FEFE0101FEFE', '01FEFE0101FEFE01', '1F1FFEFE0E0EFEFE', '1FE0E01F0EF1F10E', 'FEFEE0E0FEFEF1F1', '01FEE01F01FEF10E', 'E0FEFEE0F1FEFEF1', '01E0FE1F01F1FE0E', 'FEE0E0FEFEF1F1FE', '1FFEFE1F0EFEFE0E', 'E0E0FEFEF1F1FEFE' ] for keys in itertools.product(vuln_keys, repeat=2): key1 = binascii.unhexlify(keys[0]) key2 = binascii.unhexlify(keys[1]) byte = desEncrypt(pt, key1) cipherText = desEncrypt(byte, key2) if cipherText == ct: break print 'key1 =', key1.encode('hex') print 'key2 =', key2.encode('hex') #### decrypt #### with open('FLAG.enc', 'r') as f: ct = f.read() ct = decodeText(ct, 9133337) ct = binascii.unhexlify(ct) enc_flag = desDecrypt(ct, key2) flag = desDecrypt(enc_flag, key1) print flag
実行結果は以下の通り。
key1 = fe1ffe1ffe0efe0e key2 = fe01e01ffe01f10e Er ehrbaren nochmals bummelte mi la abziehen. Sah hing mirs gewi gro sie was fast hand. Oder zum ruh man ists teil kind zaun. Wahres ist verlor das jungen der wurden dem spahte. Oha ganz gang und bart hast neu zur sind. Leer wer und bett ehe tur herr. Gegenuber wer vermodert ihm belustigt argerlich. Zarte ri nacht zehen licht es. Wo du schleiche sudwesten getrunken fu. Wohnzimmer so regungslos nettigkeit aufzulosen wu. Ubelnehmen bis kartoffeln stockwerke das des dazwischen gro aufgespart. Gegen haute ihr kommt vor euern. Ich hinter schwer bundel sog dir linken. Doch ja eile so warf du haar kein wenn zu. Du ja schlanken te weiterhin zerfasert besserung la ausblasen geheimnis. Vergrast funkelte trostlos ab menschen da kollegen. Steh sich bart zu bett stie mehr ja. Ewige sie die oha kalte steht. Ein schonheit anzeichen man wie gru spazieren bewirtung ausdenken. Heiland heruber pa je so trocken. Tal nachdem schritt alt traurig. Mitwisser vom gegenteil bin ten uberhaupt. Gar aus stunde messer schlie. Behutsam zog ehrbaren geholfen ihm eigentum mir. Schleiche je se schwachen angerufen. Gro schoner bin anrufen langsam offenen nachdem fingern. Birkendose lattenzaun so geschlafen vorsichtig vielleicht am bodenlosen. Ture ja se floh ganz. Geborene schmalen tadellos ort hob sag geholfen vom schlafen hinunter. Zeigte nieder bin weg die mutter wie kummer fellen lassig. Also nun igen sog wei brot. Hufschmied mut man wohlgefuhl mir grasgarten. Eine arme ihm also tat zum dank hut furs. Madchens brannten nur auf gerberei man heiraten hindurch. Langsam ihr schlank wandern gar mag melodie. Bis ist nur vom herein heftig bilder. Herkommen anzeichen bis vor ernsthaft ein argerlich meisterin. Wurden spater uns liegen bin ein des spital. Unbemerkt ernstlich nebendran lohgruben unendlich aufraumen ich ton. Verlohnt he zwischen ab in einander pa. Bodenlosen he zu vorpfeifen dachkammer. Schwachem mannsbild ri schreibet um. Eia dessen lustig weg sachen neckte suchte. Wendete zuhorer dritten ein nachdem antwort gesicht tur den ton. Leuchtete neugierig dahinging vergnugen man ehe. Kam nachtessen was vertreiben brotkugeln see. Unendlich die auf hellroten kreiselnd kellnerin schonsten. Um du mischen schurze melodie ei geschah. Was froh ihn als wach wie sehr tief. Abwarts brachte mu stillen lacheln nachdem la te. Des schuttelte drechslers stockwerke ehe hausdacher. Sich auch zu ei dies chen sa he gern. <<flag{~tak3_0n3_N!bbI3_@t_@_t!m3~}>> Am knopf viere sa es essen te. Bis lag mehrmals launisch nirgends eck oha. Ab im er brotlose he herunter prachtig liebsten. Mancherlei so lattenzaun scherzwort em zu aufgespart ob dammerigen. Zusammen abraumen brauchte tut bezahlen behalten ton ige. Wach gang ein auf ihn ding froh ganz leid. Mi geblendet ab polemisch kammertur um pa verstehen. Wochen wahres du fu katzen mi gelang suchte zu. Vorwarts zu bummelte sa brauchen bi an. Sagen begru tat fromm man lie dabei uns. Kennt reden zahne da im recht leuen mager. Handen an zu sachte werdet ku durren gefegt. Sie zaunpfahle abendsuppe verbergend gesprachig ein aufzulosen auskleiden. Braunen auffiel stunden tag ers. Hab blatt durch lernt ferne die nur. Beinahe bestand alt saubere ton wahrend sondern. Wachsamen holzspane in kellnerin filzhutes um he. Du verdrossen in launischen da es lattenzaun. Bodenlosen ri pa zu bescheiden fu feierabend. Pa bummelte im so em eigentum gebogene. Anzeichen in schreiben so kraftiger bekummert aufstehen. Geschlafen nachtessen ach neu wer aufzulosen den bescheiden nettigkeit. Sitzt darum ruhig neu aus zog flo. Geschah lag ins saubere des lustige raschen dritten lichten hin. Man aller trost herrn roten war armen ihr lag.
復号結果の中にフラグが紛れ込んでいる。
flag{~tak3_0n3_N!bbI3_@t_@_t!m3~}
SuperCurve (Crypto 300)
$ nc crypto.chal.csaw.io 1000 a = 1 b = -1 p = 14753 n = 7919 Public key: (5169, 6687) What is the secret?
楕円曲線上のDLPの問題。orderが小さいので、総当たりする。
import socket from supercurve import SuperCurve, curve def recvuntil(s, tail): data = '' while True: if tail in data: return data data += s.recv(1) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('crypto.chal.csaw.io', 1000)) curve = SuperCurve( field = 14753, order = 7919, a = 1, b = -1, g = (1, 1), ) base = curve.g data = recvuntil(s, '?').rstrip() print data pub = eval(data.split('\n')[4].split(': ')[1]) for sec in range(1, curve.order): mul = curve.mult(sec, base) if mul == pub: print sec break s.sendall(str(sec) + '\n') data = recvuntil(s, '\n').rstrip() print data data = recvuntil(s, '\n').rstrip() print data
実行結果は以下の通り。
a = 1 b = -1 p = 14753 n = 7919 Public key: (2242, 12492) What is the secret? 3397 flag{use_good_params}
flag{use_good_params}
Fault Box (Crypto 400)
$ nc crypto.chal.csaw.io 1001 ==================================== fault box ==================================== 1. print encrypted flag 2. print encrypted fake flag 3. print encrypted fake flag (TEST) 4. encrypt ==================================== 1 762D2A4856553D24DE9110BBA2DDBE1AAB44890BAAADB6CA30529BC2A7FF5CF408EEBBFBA5E5A909041F104FB67D9E61D96660BAE342A830A87409FD73386831FB1894C9F13B91F6762E0689E8558B22A88A8EECDD69ED9DC0845C918930FC3962D49E8E3DBA065B5AAB6EC3F4ED77F6C04AF0EDD72AE5704D944DAAD93B9C4DB48F5969BD96A88FF54AC3E46DBD64133345958501A467E28DFFB3F42533C4D58520B4394FA4A45AB39888D5403D9B300FE9EA7AD2E2A36ACFED57ECD0AAA354D0521D7BD49760A2AA66DE84BBEEEE55C86340D0251F956DC89DE5C2D7695C1868A0BA2EDB1F759BB423DEDB4AB8D7224B44186B6D5B3428D8C44D8E494F7D7D ==================================== fault box ==================================== 1. print encrypted flag 2. print encrypted fake flag 3. print encrypted fake flag (TEST) 4. encrypt ==================================== 2 807BEFEDF208BB8F7D950D266C8D7291C9408BB3FF7A9C6670A1D51B9FEE1DD9C2DD2A337860EC5FB1A92293CF8A4A5439867E04BFC6D60FC180DECBD206A6D5451C1AC8DFD396E0ABF20386A092B96668F6DD7EB875FC81173E7B420A95FA9CA70269F51045CA189E9BCA87CACBBF23179F2B1B1B5D5E3F6B2F82DE0904A39E06AE6FFE8D699B38815C2D7C28D9BD5D26FBF57B3898A8E41E828DE881EABAF6B2BC5519561ED3724FDFD38D8613E51C01E8F8432E15DB44DBCC94D0C536BC7E7AF01FD65F7BEB3098A220146A86E131B06173DF2F189C0E649ACED38527EE36B78899BFF172F25BB690981865DA127FD0261671F7442035485D46C951A91EED ==================================== fault box ==================================== 1. print encrypted flag 2. print encrypted fake flag 3. print encrypted fake flag (TEST) 4. encrypt ==================================== 3 3FE0F12C0A5742D6C62740CD448309DE810EE3C2F10A675F02090F1142075DF6903309509BD8EF5844329D0E12B9AEB9DCA565A2F000684FFA8A5813B32031D6814A302CAB5C9BB2D2475C6ED625D527E43D279DDBC76FF9DBAFF1D97F2C9C7C939AF9096AB0BC4AFC1CC6AE150EDF18CB567D0F2B8DBDBAAF1CB4A68476E5245960FF058E4BD3E7A26FE8F0E0FEB8C6237C4088F9D9A8990B28FC0BB4C5415A76C6074F72AE79302D9B90B0874C2DA17317E2A5CDB303BB24076C63BC4F55C178CE622BC2634794D5EDF85AF2D19F84F724D1CFE2F9F7AB8E47CF55A69546B639D9119F14A1C9270599B0ABC371F481D6B1557E8B26B2A03B6368415D784FC5 ==================================== fault box ==================================== 1. print encrypted flag 2. print encrypted fake flag 3. print encrypted fake flag (TEST) 4. encrypt ==================================== 4 input the data:0 EDE7070934B122B7B106E715E536EAA5874E7E571D83E3EE4ADFC46BF413898819F86630C906621F4203A99FFA19DDBE485A4B4303395E171C189301C73960A87B1D73FB7D5D4C9FAA2B212742D1D148F953752CE05F90EFAAB06565F35ECDF6AA98A450C3009C860EA9582DA5CBD9954419D46935F3934A528D0D98A1F09D060C725AD04382BBCB06498E9AF6CD925D5553933459BBB3C7ABBBFDD758C749E4C6468119342399FB701BC18B24D7DE753227EF51FA7BF2A735E35DA8E07BBAFC9182299A7A3B0287B3E4D2A93072B6A594CD55F35271D6EDA99BB9E8D1181A4C3252F73054CC6619B95550B04B1A98D4A42CDE8C155759B428637317610E657 ==================================== fault box ==================================== 1. print encrypted flag 2. print encrypted fake flag 3. print encrypted fake flag (TEST) 4. encrypt ==================================== 4 input the data:0 EDE7070934B122B7B106E715E536EAA5874E7E571D83E3EE4ADFC46BF413898819F86630C906621F4203A99FFA19DDBE485A4B4303395E171C189301C73960A87B1D73FB7D5D4C9FAA2B212742D1D148F953752CE05F90EFAAB06565F35ECDF6AA98A450C3009C860EA9582DA5CBD9954419D46935F3934A528D0D98A1F09D060C725AD04382BBCB06498E9AF6CD925D5553933459BBB3C7ABBBFDD758C749E4C6468119342399FB701BC18B24D7DE753227EF51FA7BF2A735E35DA8E07BBAFC9182299A7A3B0287B3E4D2A93072B6A594CD55F35271D6EDA99BB9E8D1181A4C3252F73054CC6619B95550B04B1A98D4A42CDE8C155759B428637317610E657 ==================================== fault box ==================================== 1. print encrypted flag 2. print encrypted fake flag 3. print encrypted fake flag (TEST) 4. encrypt ====================================
サーバの処理の概要は以下の通り。
p, x = gen_prime() - base: 1024bitランダム整数 - off: base + offが素数となる最小値のoff - p: base + off - x: off q, y = gen_prime() - base: 1024bitランダム整数 - off: base + offが素数となる最小値のoff - q: base + off - y: off n = p * q e = 0x10001 phi = (p-1) * (q-1) d = inverse(e, phi) fake_flag = 'fake_flag{(yの32バイト16進数大文字)}' →yはあまり大きい数字にならない。 ■enc_flag pow(FLAG, e, n) -> 16進数大文字表記 ■enc_fake_flag pow(fake_flag, e, n) -> 16進数大文字表記 ■enc_fake_flag_TEST ep = inverse(d, p-1) eq = inverse(d, q-1) qinv = inverse(q, p) c1 = pow(fake_flag, ep, p) c2 = pow(fake_flag, eq, q) ^ x h = (qinv * (c1 - c2)) % p c = c2 + h*q -> 16進数大文字表記 ■enc_msg pow(input, e, n)
enc_msg以外を2回実行すると、パラメータがリセットされるので、1~3のうち得られないデータがある。また、タイトルからRSA-CRT Fault Attackを利用するような気がする。いろいろ試したり、検討したりした結果、以下の方針とする。
1.enc_msgで2,4,16の暗号化数値を取得し、Nを算出する。 2.enc_flagでフラグの暗号化数値を取得する。(これは外せない) 3.enc_fake_flag_TESTでfake_flagの暗号化データ(c2が誤っている)を取得する。 4.すでに2回enc_msg以外を使用しているので、enc_fake_flagで得られるはずの数値はブルートフォースで適切なものを探す。 5.3,4の結果からRSA-CRT Fault Attackを使って、Nを素因数分解する。 6.5の結果から2で取得した暗号化数値を復号する。
import socket from Crypto.Util.number import * def recvuntil(s, tail): data = '' while True: if tail in data: return data data += s.recv(1) def egcd(a, b): x,y, u,v = 0,1, 1,0 while a != 0: q, r = b//a, b%a m, n = x-u*q, y-v*q b,a, x,y, u,v = a,r, u,v, m,n gcd = b return gcd, x, y s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('crypto.chal.csaw.io', 1001)) data = recvuntil(s, 'encrypt\n').rstrip() print data data = recvuntil(s, '\n').rstrip() print data #### calculate N #### try_rsa_enc = [] for m in [2, 4, 16]: print '4' s.sendall('4\n') data = recvuntil(s, 'data:') print data + chr(m) s.sendall(chr(m) + '\n') data = recvuntil(s, '\n').rstrip() print data enc = int(data, 16) try_rsa_enc.append(enc) data = recvuntil(s, 'encrypt\n').rstrip() print data data = recvuntil(s, '\n').rstrip() print data diff1 = (try_rsa_enc[0]) ** 2 - try_rsa_enc[1] diff2 = (try_rsa_enc[1]) ** 2 - try_rsa_enc[2] N, _, _ = egcd(diff1, diff2) e = 0x10001 for i in range(100, 1, -1): if N % i == 0: N = N / i #### get encrypted flag #### print '1' s.sendall('1\n') data = recvuntil(s, '\n').rstrip() print data c = int(data, 16) data = recvuntil(s, 'encrypt\n').rstrip() print data data = recvuntil(s, '\n').rstrip() print data #### get fake flag (FAULT) #### print '3' s.sendall('3\n') data = recvuntil(s, '\n').rstrip() print data c2 = int(data, 16) #### calclate p, q (Brute Force) #### for y in range(4096): fake_flag = 'fake_flag{%s}' % (('%X' % y).rjust(32, '0')) c1 = pow(bytes_to_long(fake_flag), e, N) p, _, _ = egcd(pow(c2 - c1, e, N), N) if p > 1 and p < N: q = N / p break assert p * q == N #### decrypt flag #### phi = (p - 1) * (q - 1) d = inverse(e, phi) m = pow(c, d, N) flag = long_to_bytes(m) print flag
実行結果は以下の通り。
==================================== fault box ==================================== 1. print encrypted flag 2. print encrypted fake flag 3. print encrypted fake flag (TEST) 4. encrypt ==================================== 4 input the data: 851D6D9C07943581FF5252E8A885C64600668D05D26DB97687B5AB68531E667786CE792E57916ECCAC637C0D895F57ED31A1CD4A8B4CA78AD54F13C66005DE2E2765804FF61A2258544F79E611E78634FE909558C2F419867E945B9FD7CF516C627401DD1C0BBD8BD265F9E6110105609270A84D8A9BEEDE3E9BD94D38C888AEE4B6EC29605DD532B193315BE4A2C78943DD6B662058D93BBE3EE7B0B7D6A54C3309F7375986F4371E521DA68700033F407E2405BFA82D7D5BCE8D0F5D2FF2AC3DBBFCE4A1F782C60E225DDB4973C4E1D6B10CE8E23D242362E7CB838A2A36733F585FB0DBD92755F8569FB595DD81B9AE0999A330C6E9A33361E67F1D5EF8C ==================================== fault box ==================================== 1. print encrypted flag 2. print encrypted fake flag 3. print encrypted fake flag (TEST) 4. encrypt ==================================== 4 input the data: 17831212B2DB05436E7E3021D12089C78223853577606D6B2421E1AA06E65AA0934D214F64ECA61C12C508544560FCB98BC177286D00BB65A2FB49242E11B4EA5E05AAB2A89DBBF20B6FD78AD7436AFE0F415BF4AE64B0D8CEFC587D60C614E5922829EADD754EE377C9E15E03D7C1E8E545452BAED350D5DECA6E0CE65E72DD9954D15321C6B9A557A2FF52631B0C05917E341925D7CFD7E6DEDDBBB468E4F99EFEA89EBE3F213A9CCBD73980C681B217B326FCFC2355545596B76B4119137F73C40062DEF6DC0F1F57A68F4C0A61F95979854A63DCDC4110C0D47376D7F03FADC9CBC82A4B6BA2EF3D70274422228A943C178D8DF64D47C5DBA42F92F2A602 ==================================== fault box ==================================== 1. print encrypted flag 2. print encrypted fake flag 3. print encrypted fake flag (TEST) 4. encrypt ==================================== 4 input the data: 131293C26592B866F22504428549D0457964E9617D321BEBE7F6A48778BB93D681396BF4D773D4C1F992CD6EF670C8A38067F0A55BC594582277B7651905D40A88CC6F405CB5F31A88836FF6CF8B50F647B5D412DB5689EACFAB59C3DF61D184666CC2B67B31FEEEA58F18485E3851D7EE8BF8D24E873F91780AEDF570AFA966546B0659E4ED16E6A83A2570EFDC59D6BAF9DDB1FB1E39D6D9FD275A281E7B376634D68C559B3365179E597A504AFF430DCC73CBFB99D2210A5A1533A149ABCE64163E362AB06A066AF4AF0D8BFC69A5437050D9266AA2588673E3111D8745BB02DCF59B55B7F3F09A35C10F67D1CAC55A6C4B11B58776B4C974266CBF4E95F9 ==================================== fault box ==================================== 1. print encrypted flag 2. print encrypted fake flag 3. print encrypted fake flag (TEST) 4. encrypt ==================================== 1 CC11224FBCD599ADF47C4B06965B61E2A98C031DFE3A0CBFAD4C01FF7A99D4715EA6C3882305E30369779371A6E4F16C9D0484995ED74D971E21B59D4FD28E95A569A4F54E87694714FCBAF368B5DD6A723292AA26F51BA444585A9FFC9DDB5BA8B4168E64E3310FE6696E6E1E04BC19A872A3E28558CC2DD35D4F3D73BA3BA7AC2303F2A279C20D04D339E3CF6EF10B9B3B97C9238E5A93FCD2722DD00C51AD7324AB0DC5C86310B12FF95D4C183C3AF3214C1D08BE88181F7C08FC397871A212A6997C6603792AF769BFB616BA17BC4351804D9ACB1FCE8A078EFD95240A4AC7E50F4A1E6D982ECD8A5B9C29AFEF44C85E30C28C19142868C0B11086DE901 ==================================== fault box ==================================== 1. print encrypted flag 2. print encrypted fake flag 3. print encrypted fake flag (TEST) 4. encrypt ==================================== 3 20B1A2D3D32FD90013A160B644E3B438DEDE2D49D03C22E3236A4B0CE7B7E50F3EF31CF52D32FB7E65C38EE09E9A035E523FA3A3260079B756B089D9DB7B106AC6EBD0A69F49DC0EAB76239818B385D43B562C76823A726B8051F283E513823EA9C6E81E2F80D3661B5974667244FFEDA882DAB1D693D664CD6B0510C6F38D6C43C79EA09CDE55435DD33A720DD810ABC74915FC6FEA58EC83CE4A6DE257B1B47B1765EFB1E4A578A3FD657A691DCBD4A4C450B90BE5E3AFB6015E79620B3C188C0C7852008C258F6DD662D13214F05FE17660C1AA545D9FC5F1243E573D484AF832E53C9CDA555672DB6AB333B0AEEFE8D0BA529C6874162E8EB4B60753ED49 flag{ooo000_f4ul7y_4nd_pr3d1c74bl3_000ooo}
flag{ooo000_f4ul7y_4nd_pr3d1c74bl3_000ooo}