# WU SEETF ## Crypto ### BabyRC4 ![](https://hackmd.io/_uploads/S1ideJPw3.png) chall.py: ```python= from Crypto.Cipher import ARC4 from os import urandom key = urandom(16) flag = b'SEE{?????????????????????????????????}'[::-1] def enc(ptxt): cipher = ARC4.new(key) return cipher.encrypt(ptxt) print(f"c0 = bytes.fromhex('{enc(flag).hex()}')") print(f"c1 = bytes.fromhex('{enc(b'a'*36).hex()}')") """ c0 = bytes.fromhex('b99665ef4329b168cc1d672dd51081b719e640286e1b0fb124403cb59ddb3cc74bda4fd85dfc') c1 = bytes.fromhex('a5c237b6102db668ce467579c702d5af4bec7e7d4c0831e3707438a6a3c818d019d555fc') """ ``` - Đây là dạng mã hóa RC4 và trong đoạn mã này sử dụng chung một key trong mục đích mã hóa. Chúng ta đã biết được một bản rõ `b'a' * 36` và hai đoạn ciphertext `c0` mã hóa flag, `c1` mã hóa `b'a' * 36` - Vì vậy để giải chall này chúng ta sẽ đem xor bản rõ với c1 để tìm key và xor tiếp với c0 để ra flag. solved.py: ```python= from Crypto.Cipher import ARC4 from pwn import * key="c4a356d7714cd709af271418a663b4ce2a8d1f1c2d695082111559c7c2a979b178b4349d" key=bytes.fromhex(key) def enc(ptxt): cipher = ARC4.new(key) return cipher.encrypt(ptxt) def decrypt(ciphertext, key): cipher = ARC4.new(key) plaintext = cipher.decrypt(ciphertext) return plaintext # print(key) a=b'a' * 36 c0 = bytes.fromhex('b99665ef4329b168cc1d672dd51081b719e640286e1b0fb124403cb59ddb3cc74bda4fd85dfc') c1 = bytes.fromhex('a5c237b6102db668ce467579c702d5af4bec7e7d4c0831e3707438a6a3c818d019d555fc') # a53f2e6a416a31b746d3cd5c3e4f0e74d644d3d01e5af1539d01f74170f9555c068c0738 # b50a2d636a2767c46165708acb816ec0 # print(enc(bytes.fromhex(a)).hex()) # b=xor(a,c1) b=xor(c0,key) print(b) # b="1c54525953040700025b125412125418520a3e5522133e52543404133e132417520f1a24f83e" # d=decrypt(c0,key) # print(d) #}5382efac:s5ss5y3k_4Cr_35Uer_rEv3n{E\x99_ ``` - Vì lúc mã hóa đã đảo ngược lại flag nên chúng ta sẽ reverse lại flag: > SEE{n3vEr_reU53_rC4_k3y5ss5s:cafe2835} ### Dumb Chall ![](https://hackmd.io/_uploads/Bk4eI1Pv2.png) chall.py: ```python= import random import time from Crypto.Util.number import bytes_to_long, isPrime from secret import FLAG def fail(): print("You have disappointed the pigeon.") exit(-1) def generate_prime_number(bits: int = 128) -> int: num = random.getrandbits(bits) while not isPrime(num): num += 1 return num def generate_random_boolean() -> bool: return bool(random.getrandbits(1)) def first_verify(g, p, y, C, w, r) -> bool: assert w return ((y * C) % p) == pow(g, w, p) def second_verify(g, p, y, C, w, r) -> bool: assert r return pow(g, r, p) == C p = generate_prime_number() g = random.getrandbits(128) x = bytes_to_long(FLAG.encode()) y = pow(g, x, p) print(f"p = {p}") print(f"g = {g}") print(f"y = {y}") print("Something something zero-knowledge proofs blah blah...") print("Why not just issue the challenge and the verification at the same time? Saves TCP overhead!") seen_c = set() for round in range(30): w, r = None, None choice = generate_random_boolean() if not choice: w = int(input("Enter w: ")) C = int(input("Enter C: ")) if C in seen_c: fail() seen_c.add(C) verify = first_verify else: r = int(input("Enter r: ")) C = int(input("Enter C: ")) if C in seen_c: fail() seen_c.add(C) verify = second_verify if not verify(g, p, y, C, w, r): fail() else: print(f"You passed round {round + 1}.") time.sleep(1) print( "You were more likely to get hit by lightning than proof correctly 30 times in a row, you must know the secret right?" ) print(f"A flag for your troubles - {FLAG}") ``` - Bài này chúng ta cần vượt qua 30 vòng xác minh, mỗi vòng xác minh sẽ ngẫu nhiên 1 trong 2 dạng xác minh sau.![](https://hackmd.io/_uploads/Skfd81DDh.png) - Với second_verify thì khá dễ ràng khi chúng ta biết được g và p rồi. Mình chọn r là một số bất kì và C = pow(g,r,p) - Còn firse_verify để thỏa mãn `((y * C) % p) == pow(g, w, p)` thì mình chọn w=0 do đó C = y^-1. Để đảm bảo C mỗi vòng sẽ khác nhau mình sẽ thêm kp vào để không lặp lại. solved.py: ```python= from pwn import * s = connect('win.the.seetf.sg', 3002) s.recvuntil(b'p =') p=int((s.recvuntil(b'\n').strip()).decode()) print(p) s.recvuntil(b'g =') g=int((s.recvuntil(b'\n').strip()).decode()) print(g) s.recvuntil(b'y =') y =int((s.recvuntil(b'\n').strip()).decode()) print(y) for i in range(30): da=(s.recv()).decode() print(da) if da.endswith('Enter w: '):# y*C % p = g^w % p s.sendline(str(p-1).encode()) print(s.recv().decode()) s.sendline(str((pow(y,-1,p)+ p * i)).encode()) elif da.endswith('Enter r: '): s.sendline(str(i+1).encode())# g^r % p = C => print(s.recv().decode()) s.sendline(str(pow(g,i+1,p)).encode()) s.interactive() #SEE{1_571ll_h4v3_n0_kn0wl3d63} ``` > SEE{1_571ll_h4v3_n0_kn0wl3d63} ### OpenEndedRSA ![](https://hackmd.io/_uploads/BkylikwDh.png) chall.py ```python= from Crypto.Util.number import * from gmpy2 import iroot # this helps with super accurate square root calculations! flag = b'????????????????????????' m = bytes_to_long(flag) e = 0x10001 pp = bytes_to_long(b'????????????????') s = 1 assert isPrime(pp) while not isPrime(s): p = getPrime(512) s = p**2 + pp**2 assert iroot(s-pp**2,2) == (p, True) # quick demo on how to use iroot() assert s%2 == 1 # duh, s is a prime number after all! q = getPrime(512) n = p*q c = pow(m,e,n) print(f'n = {n}') print(f'e = {e}') print(f'c = {c}') print(f's = {s}') """ n = 102273879596517810990377282423472726027460443064683939304011542123196710774901060989067270532492298567093229128321692329740628450490799826352111218401958040398966213264648582167008910307308861267119229380385416523073063233676439205431787341959762456158735901628476769492808819670332459690695414384805355960329 e = 65537 c = 51295852362773645802164495088356504014656085673555383524516532497310520206771348899894261255951572784181072534252355368923583221684536838148556235818725495078521334113983852688551123368250626610738927980373728679163439512668552165205712876265795806444660262239275273091657848381708848495732343517789776957423 s = 128507372710876266809116441521071993373501360950301439928940005102517141449185048274058750442578112761334152960722557830781512085114879670147631965370048855192288440768620271468214898335819263102540763641617908275932788291551543955368740728922769245855304034817063220790250913667769787523374734049532482184053 """ ``` - Chall này ta thấy `s= p**2 + pp**2` nên ta có thể tính được p bằng cách dùng tool https://www.alpertron.com.ar/FSQUARES.HTM để tính hoặc đơn giản hơn là ta lấy căn bậc 2 của `s`. - Ta thu được `p=11336109240426199545380121772211758030643077084354723510396623108046045877936239312932896062461038721613541632921592699626408876519614365179680368296156007` - Đã có được p ta giải mã theo mật mã RSA và thu được flag. solved.py: ```python= from Crypto.Util.number import * from gmpy2 import iroot e = 65537 n = 102273879596517810990377282423472726027460443064683939304011542123196710774901060989067270532492298567093229128321692329740628450490799826352111218401958040398966213264648582167008910307308861267119229380385416523073063233676439205431787341959762456158735901628476769492808819670332459690695414384805355960329 e = 65537 c = 51295852362773645802164495088356504014656085673555383524516532497310520206771348899894261255951572784181072534252355368923583221684536838148556235818725495078521334113983852688551123368250626610738927980373728679163439512668552165205712876265795806444660262239275273091657848381708848495732343517789776957423 s = 128507372710876266809116441521071993373501360950301439928940005102517141449185048274058750442578112761334152960722557830781512085114879670147631965370048855192288440768620271468214898335819263102540763641617908275932788291551543955368740728922769245855304034817063220790250913667769787523374734049532482184053 p=11336109240426199545380121772211758030643077084354723510396623108046045877936239312932896062461038721613541632921592699626408876519614365179680368296156007 q=n//p phi=(p-1)* (q-1) d=inverse(e,phi) m=long_to_bytes(pow(c,d,n)) print(m) SEE{0dd_3vEN:deadbeef} ``` > SEE{0dd_3vEN:deadbeef} ### Semaphore ![](https://hackmd.io/_uploads/rktMnyPvn.png) chall.py: ```python= import ecdsa # https://pypi.org/project/ecdsa/ import os flag = os.environ.get('FLAG', 'SEE{not_the_real_flag}').encode() sk = ecdsa.SigningKey.generate() for nibble in flag.hex(): signature = sk.sign(flag + nibble.encode()) print(signature.hex()) # Code ends here. The output is printed below. ''' 04a22664841747a475192a7f9b6461404c0f85c46810d00d1a18249338e5bb58fe32e6580e6aab74dad040e1e7ae0a2d 4992c6691ae1e326f5038d050bce13d5007625c3c694a86dc9a75748f395ae80b5d904b6464f0e17b2df17e6b9f540ee 836b146003baaf00b28403ca52b7df2d949350cf4e57b7e9f981b6ee9293c93d44977f102b5bd4000d93890ebfff2d28 5e7d2389cb92df48845cf3d70a172e458de9456743964568c2532f080ea5b4ba70301b27f5d9019f5d0ac4aafd2147af 1cf28514e763cf6494814e0d64d32bd20ce99a983e88dc66225aaa4246c58ab6f33a2bfe441e023582b47937ac8d15a4 1a1980d999797b5af80d4f550d741708352f738c137f8ca6e1fd9dd3b70fa75f800f865b6b5098fb95c62ab40a80594f 83b70fc96da176c34f616a48be43ebc22b090545a52b972cc784d55c79996ef842493514a6969db7c5d34b9ef6fcd28e 99c5d66a1f7f79d5b194397af66a347b7cba9dc5d327424aea71bc82fba1bbf5d50acd57e6eea4fa366a542f1a91e350 37f606bfdc2004293292509364f154173a1c13aea5f6dd75be8b5cb0343e92c8efc405e7956b73132afa80d327521a8b 012a666c3dbf7a64760acf459fd4ad4de7a235ee8866c3810227c8f7cbcddda79130c46b820bff9521965dfe44de32af ceb8fdf5acaf767a76f40ae6112b5c402a2e4e7713631e4c51e963fa61b193fd8ef0fbcbf088e5b525d1d808c5d094dd 71b1a7e5b7816b1de309daa88a8a3883a37d28650532ecbc3f462b005b353266011bdf3d642d78822c8c7299449f1f22 02caf72b6060b761d23c9bdfd4e9296a34bfd0a364eba5a81ae842a117bdd82c28ac8c692911b7d3eedbf3c543d0f48d b959a90d2aab7a2be3684b69328d35ed9694d9df0eb4ea6e6938c806838d0db6b76718b9e7fc4268c14c17246f499af9 03b422faff6fd1de0dff181977560def1bef40ee307957d15039b06c202bc5827eba1d0e2c5027051fb5dc093bded056 fa5f0046485ea006d5917d353d3cba2010c3b5edbe87352f7450dd155c15e38de1d990be4754c5c0ff24d37a8f01af92 f027161939478e23ac9b99d56e37a0cdd76175a42892f8d7cb0dcc84964663d672c9f23812d016d445ff5c7589725c6d 30b8757465a5ec8801a5a190eb296d7d2c9ea3b1eb2c62f6062a0a8b5115f30c054cb0d5eeaba480dabfb3c5c70abef0 889087215877cabd0c743f5864306db81fa46e91eac31b759b0d23afc036235d265c609e37117b9d15266ce8ecc5db2b 9c76eae7ec44540bd41c06ba9c25b4734c9bbf68880494a38e0b118fca93677fa5770b98c0b982245a207880036e6445 2bd29f6aa55103be42b16e394a1190a03f8a22b7b7162a5d03c0423a19de47b4b8167bc330690f36db02ef5377624c80 c9b933108fad16ffd1275ea14e4b506d9c9c03df4287f99a71c09402c3a11c19932ad14af8468a84aedd8615a762d366 2e564b6e2730d220a65de2899ec7a99056c3d8e89f0178b5e974483bcc9b5949f69908777f7332bb4fe84d431e8a5a35 2f687205c31b07820a872e2a3d4e6897561ee3873086b445570a66b13232ade40e38397b648a5cac7a9a324664ece3bf 2dca9b0a9e96472b18119921a681d23d2ec3acacd1b9c0a011e23ca24407808be25e04edcbc736b9b11b6a167a2d297a b2781278a3acd8768ca8ba1ad698a3b775c330df9a7837d18f9796cd838e5714e461f1bbfd1d3af9230c05ea33bc5555 191447109bb7de900a70e06170e492fd84d908fde7ccd2a5ed6a28c1860e655958d2f54e4638a54cbebbd35a61b528dc 54e0e6509a899baf44574eaa7d302bf00e5edfd8b0d0fa62f74524bf92bea63384773489c69e64b4b757afc9da0ecda4 941d9cb5676e366157d8bd6c92b7687539acb7a06bc611f8ad64871f0e6a598385957517aeb9972b719477bbdb31865f 1741225d735cc11377c31e8976a269473d66d8f788f34822cae720cd82f0e99af50807d1edb7513ba14efc097183d192 f5568fc82c2ca245465533f9b98bb537c9bc8e2e050d00cdf431e8acf6ed5c69b88f93760cb7fe85128a22db83242ba4 d00c1c38ff9cd6e15846aac2e821b9d60846a96d0688f86f40ea3178030868579300e2c0aa9cf9ae373ae9f817fe7ae5 76fb8669a5694795efaa9b4e38c0a306112054c891f9f871a80b6caec231f35b45c0c6ca8f64423861a5d5d09362af51 cffe394dd32e1bd6c71d300412f6551512a9eb71be7eb4b53c702caae94ae8673bf95cb7e76a0bb06e345e7e35305efa cc82ce7885a5ac4bc08bdbd13976e3cd3b2a3f439180a329e826275e3dee8386720bf28d75596c289b5bc0b9d364eef9 4f4eb4b9bb6c6deaf1173763dbd1518079096d8863a4140dca9c01693ae4bfaab6f125e0ed5a5f20200b8c1a86e58ef8 9cad001be5d25df58a5a804ca97d9e6c7f32d6779fc020bf68727a83548382c5dc4e12359e0914cf7fca879c60fce06d 1f7091b011dfdd1ea0dcb6071f85d5c75642e37517d5263d4b468490496f90abb26e02307aa54d3d4dfde6d80626d933 7a05a981041f8e406fc69a5569c5aa2c2fa8a4c6445e3bd974a19f9fb3720cb5218c79e5eb586bfc3915d0e7ca7a9638 71b8b89846f6849a17cd6258695790f7c71945e0c6b8fd3f297809ad61ddd9f73f8ec4538e45d1d420f328fefd71fd39 d8397c87bd54c91a060d0565ff0f6edc0af0287889cd7a03ac321ea9ae1999f370ee8881b2a01b924f4fbc199cf1d868 5b848e0310b6d652310686af9cbbc6d08f42e37eb83c3c0cec22e643f859c30fc7bbeb8c1fe4e16c8dcf9e325a685a7a 4cc8713a14a5a074ecc112e22192bb162e1d5ea303939dbf2bbb9620da0ff9eb326fb5b30c7c133283a7949230ee7177 fa7e00b2da873ad104a50df8639ee6e8e702e256fd4a8ebbb25bde28988750eefcef91d4ec891458f3e700fef132071f 1fdfd4432de9d3647a194cf8d66b3d8a5e3eac5bb1e832b366ed37b4b7875fa6346b1b65bb3f068c61358ad7b7e5ee5e 0d660198e6c811a34136dc087693e81ebbd5877c722a7624ddb682043e5d24c8cf892f13b2cf2383f476f12e68bd94b5 e8f9d1f42b54c76836bae42b05bba24ffcdd0dd935380b615223a0c6ca1569a448d74cbb78e47bca635dade3e802c8a5 04a21057c034f7cb9eff39935f464aa5d4dc027b9d5da05ee5f097f12f40a4046f87683ad1638e1e05e61246ee178fbd cabf588910bce6d41552ac5addb00f196f90c809dc6856f8e8c7490338b98bc423d2cf42c3e3faa73ab171a5a8544433 d61eeaa195eaa6970dc99e4e0ed779ee0e450f4b73917b6fd00f4bd99b26a0bb05313cdc8915d17d7b0d9942410658af c758b4cf5847593c4cb4e356ec865e8797d74a564cf9ad1549feb4d8439e8598d0b69cd44c3267d36c1d7317303e2aa1 bd21290aee61dd300f3850b567114c8f5a1b6f8b170711b8b79f225a04961c5c39903d100a8725025da33922beba9098 a832c1f4b54699f59adff2dc5d9401888ef48eb1e3dee75d6b24334db5d8cdbe17cc87131fcfeb2fc59a084a817047a1 9251d8c0e198b84bb52e656388a4a5fc7e487dd777effa80cce8f0a9feab8b5a96bffeb73f36984c16fbb1214e2cfe65 8e2bc98948c3d0989ef1fcb26620a383a41414e55b5844e6e61e50335c18c097c1850c78acd776ffe4d35194227fb358 f18f9004efa7d5c6201faa99481df0870403f0952beffcecf9bae9eb05be06e777c83bd3fe30ba8666d72292c9f6c093 a07f86f2a093ca8d6fdbc63cb56d3527e6c85225fb77f86efea0dc1550333e7b5abcb49368c60a70ef4cf8456600b73e a520893f94bc749b07d25d8bd1185105c001f12f4e0004733f6b1ff2197925941891f343f3eaa97bfcd461776b46217d 739c2f2c68b83569cccfb8d9178ac5e5299723fedae515d6df245ad5a0964b91f9a5a6e869c7ef57598fd33757db51a3 cb59854d3b20c9f5d432e205af140bfbd34ccee0b579f67e6ceefd91e64815df1e84969a9ee2a57bd6e559d7ef9ec3c9 1b9556ba0691912615c25a08eebb0b56e46ee639c56ef2b979322e5cbc797c9c83fa59b83c5e9e45b9b7eb51eaa1ed77 0f49b18563052f9b64ebbc1a9e0fa1e5685e09c8bd266e4231e42fd25ac74f7bea9d4decd17bd9b5c9b8c808a3751612 77f08e003539e15a5a5f860cb8e9cd42ae239c9c2c7bb7d7e094b15834c86f70e4b8bb22fde71ddb4a6916b2e9725d00 5073b22c6ac1c3171e01bfaaf0ab55b2d8be72fc259efe5c36bc1cdfa2a15db2e682411d4289bd66090417aa9893c46a a11eadfd3a5c22820b1bc815088bebf74804b8479a77a8b72641a2743f6a1401038006cb90c777d7f29f42f519ef1545 e06f918ac5e068884627b2b30968e5241c8f7be6a66c92357f905eb734c7d2a8e0da5e2b355749dfa684173aa0cfaba7 ddcfe5abc02ba60668d6d87420fb1d74fc54b97707ff01cf2a0200ddf2eb708e40e9d9ae89841df4bb0e5c1aea8b6885 c7c7389b6a06f11386435449c154c1b6878c01288eeab32e0f54ce92a5c5b7c90a978a9ce4ea61efc3d2c8617f6fa6c4 41ead48d0c0640dc03cea84b6ed19d20a545de95953270a5c20043ccd84179f46d99ee44bf4a8798a09c174ff8aac7a1 c0219509f94da75f18f1fd56aecfa7b9021de999a571a4dda2be8de2ebd439ae242fd85c8742886af570cd6f0a4c58a2 d6fe36dc75694a4459a6f54294f17ece7f4fdc09e7e8fb2b992e72a0ab92da0f00f7b73282c804815b4c674778b760bd becb1781197c26b711796ebde491bdd2c1e8ce6fe70cdf255ff8af6badf01e977f06af4f047bb2485e5bf530e4413b32 586c6d74c886fa28de23b66a5616e7b0924c08ce87e8cce6826f3b3ef4c653d9bd103c9c8d8f9051017b7cdc4aed2507 e6480c201a46f1a537af82279a6936d0ef4b1d0e5ea60c56126c4ef38fb42bf1d881451498242173d850751c4f6b0b40 5e092141eec07faddd009722c58aa6042e404b144f1e29f76a1f0b8db7452bca3298373cb17cdf1afe0792b50500e97b f877b834ed12f579caed92aa8fb4708ea7629aaea623c63d863b31571cbce32464bbb6f4dc62bd5a37ac860a89f3d169 e6c6d06cc146fd1b488bae21ed510b483d8e118396186623ce876b3081538731190d2a81f57cdb1a2fe86ab02ac1f804 b0693ac1b3aa3d921ed516c5c7e7162cfa17567d41dfddbf46692ab01b3b23c60e6a1778064290126fdeea97f225768d 503349510da1d0c30f6a7738f710ec4a3d38074f0baee3ea374606ac6ddb104a7ff5765cf86c189613cd19d898ecc1ef c3b232a6769c8fb966fd9ebcccab5c9a55fdb211685e2b9136d818c3058a505e575a9d891eb61087b2e44c3a3863ffde d8413b76bcf223d39e74c02b99fa9ef4dcfe5ef2bedd366e2f9121fd90c764a7980c2927d61f98ddb7513c2a00162738 7f5df9befb7bd6820dd4b855cd5eb1d33c128423947e7601c88a3e922b3ad444bd39fd719cda592da81626578633bcd7 b13436a9210dcfb8ac294ae29fc92f750e9087a7cd39387a84efbf6c890ecc30f44eb6f6343892de42f4368e092963a7 c6800eb141fae73be3f14e18aa303c569a303374828799d6881bfa33eb5ead1ccb3c6e0ddd04baeef518347e1b75a1c2 2f9e95add8b9cb8d394eee05b61d3795843ce031e412c9d50c429d61460812e34a5c710b8949b0cafc6396b6cbe144f2 1cb85d64987c1a89272ccba305480e2dd6ea84104578be8d7bfc817ce95fd023b69d2da01a241aa40273c7f2f1bd3862 928dd997dcb9eeb7035a5b41cfb8e6227ba4df81d12184c7117af18919a65e865c578a52870c06aca8bbc51d6b1ee68f bff6eeb1e169f08e0aa215fcb49ac59b24a07416328d1fa64939063b9d811b47d89345f8980ee9fc514d0681b87a1a18 0869e138cb6c94f3aa4eba51c921052cbf61cc5ddae4a352b74c8ce8e8e92f6d77b6158c07a140bf8d640fc4ea05e209 dd6991b4b8945a16f372981b965cf7ca68e1d252dec7206623054e308661fae9861b7fcac3d493654d01e9dcc8d7dc21 cfa5a9251a1afd5ae0c7ec1b0526b3c0e809ec1313f531417e18fa8c3ec8bdbf9324fe8e5637fcfcf884ca05ad574e90 a3ca6bc05146bba763dd89ee448dca3868062a5f7ecd6eb4827567dac06cd468ed3a3ff218e16773767ce67954418041 ddafe8b0a311ec80c3914444208e1240568efb7493038c50c4eb4d34361ca12b2bece6d833d909761945b5b10c5ff94e b146adb3a575922705ba342f6904c9bbb92f5a94261f47edac363f7dde7d50020cd280a308a40bc8f82d692099de6687 7424a27cc2cda56f525948c33872f91326ed5638f6169c398585a87eb519e1294f66a30331b33f35aced9d0599a83c9a 88185e1182ab98f591b235fa9f59985cc46ad443f285d9e029de0e03d7c5636881ba7123775ba908a885b132842910e1 fadca658a0a25295f5121f6087701c83cf9737f5a747945c282cecfb5ec0488d6cecc49235cd8accfeb3c2c5c76398f9 d64b25adb930fc2deb30a6e45e6999f34317a82e80eabdc489e46c4e29cab2a618fd2a45e5bb17b43ae4dc8f851d17af 047217194a01a40a045d1c74a06328d3ec001730a0fde471367db054dcbac53f683f3f522308f40f7dd3a6a467093897 1b5cb6cecce1bdf9ea0c68fb90a4ace3991f8fa6c19dbf9792dbab79faab39e0b0663730de3396c6bb3d40e386880c72 6361f675be68f096e54cd833f4e06b50f0388370bdf65fa4c4db0d4448ff89b48b694246bf3da3c9d9c8e7b24289281d 557e1657574aa4d54cc39981bfc31f97b37edb14ec7f197d161bd0409a99bb1867a54b2c5dca27db5ed29eeb907114cf f141467f8e7ae6a012a746547c318551f8eb6090882baed7834ee8e0daa48878e822d8afdbe7b525d5b90d8152c59eba 744e97057789f5431586ca9e5e42c0d9bf2d5810e145c64c054e58211cdf6afcb21b56b1f778f33d3c731df01aeba4a7 b27c148ef046e856aa895ba02b9f8f982d42e3e5776c4b8f0c0e738c2e201efe2f70645286faae60a822663746233ba4 b53ce532c98b059a24c890d3d12492cfc7fb92172b9dda4f31d296185f34ec5dedc35714a5c73d117cedd037a1f4ef3c ''' ```