This commit is contained in:
2025-12-15 13:31:12 +01:00
commit 26e0102f58
10165 changed files with 233472 additions and 0 deletions

BIN
2/Basics1/challenge Executable file

Binary file not shown.

11
2/Basics1/txt Normal file
View File

@@ -0,0 +1,11 @@
token=0x7eb14d7dbc4f74ab4225e75d49a35a22a25a49b74027a35c25a61d648f1650bf5e42aa5f2fad key=0x16d02e
Heres the result after XORing the token with the provided key (repeating the 3byte key across the whole token):
68 61 63 6b 6c 61 62 7b 6c 33 37 73 5f 73 74 34
72 74 5f 67 6e 31 73 72 33 76 33 72 5f 38 46 6f
70 54 7a 71 39 7d
Interpreting those bytes as ASCII gives: hacklab{l37s_st4rt_gn1sr3v3r_8FopTzq9}

BIN
2/Basics2/a.out Executable file

Binary file not shown.

BIN
2/Basics2/challenge Executable file

Binary file not shown.

23
2/Basics2/test.c Normal file
View File

@@ -0,0 +1,23 @@
#include <stdint.h>
#include <stdio.h>
#include <sys/types.h>
//aufg1
//uint8_t token[] = { 0x7e, 0xb1, 0x4d, 0x7d, 0xbc, 0x4f, 0x74, 0xab, 0x42, 0x25, 0xe7, 0x5d, 0x49, 0xa3, 0x5a, 0x22, 0xa2, 0x5a, 0x49, 0xb7, 0x40, 0x27, 0xa3, 0x5c, 0x25, 0xa6, 0x1d, 0x64, 0x8f, 0x16, 0x50, 0xbf, 0x5e, 0x42, 0xaa, 0x5f, 0x2f, 0xad };
//uint8_t key[] = { 0x16, 0xd0, 0x2e};
char test[] = "hacklab{ ";
uint8_t token[] = {0x0b, 0xb6, 0xd5, 0x04, 0xc3, 0xab, 0x0d, 0xd0, 0x86, 0x0f, 0xcb, 0x9b, 0x01, 0xcc, 0xa9, 0x1c, 0x98, 0xd5, 0x1e, 0xd9, 0x9b, 0x1f, 0xde, 0xa9, 0x7d, 0xdd, 0xab, 0x09, 0xdd, 0xc4, 0x08, 0xbc, 0xcf, 0x00};
uint8_t key[] = {0x4d, 0x89, 0x94, 0x00};
int main(int argc, char** args){
for(uint8_t i=0; i<sizeof(token); i++){
uint8_t c=token[i];
c = c ^ key[i%3];
c += 0x22;
putc(c, stdout);
//printf("%x ", c);
}
}

6
2/Basics2/test.py Normal file
View File

@@ -0,0 +1,6 @@
token=0x7eb14d7dbc4f74ab4225e75d49a35a22a25a49b74027a35c25a61d648f1650bf5e42aa5f2fad
key=0x16d02e
for c in token.to_bytes():
out = token ^ key;
print(out)

12
2/Basics3/README Normal file
View File

@@ -0,0 +1,12 @@
Welcome to basics3!
-----
We encrypted the flag, but we lost our decryption routine.
We only remember the key we used: 02723
You will find the encryption software in your home directory.
Can you recover the flag?
Hints
-----
Code may do weird things, you don't have to understand all of it if you
can calculate the same result or the input for some result (without knowing exactly what happens).

BIN
2/Basics3/a.out Executable file

Binary file not shown.

BIN
2/Basics3/challenge Executable file

Binary file not shown.

3
2/Basics3/flag.enc Normal file
View File

@@ -0,0 +1,3 @@
2c 1d 5d b1 67 85 0f 52 69 93 1c 2d 79 f0 4b c2
64 bd 0f da 95 88 16 0c 2f 5e 9e 68 ee f4 1e b6
b8 a7 7d 43 a8 00 51 c4 fe 54 10 26 f1 d3 2b

53
2/Basics3/test.c Normal file
View File

@@ -0,0 +1,53 @@
#include <stdint.h>
#include <stdio.h>
#include <sys/types.h>
char test[] = "hacklab{ ";
unsigned int start_key=2723;
//paste flag.enc here (add ", 0x")
char text[] = {0x2c, 0x1d, 0x5d, 0xb1, 0x67, 0x85, 0x0f, 0x52, 0x69, 0x93, 0x1c, 0x2d, 0x79, 0xf0, 0x4b, 0xc2, 0x64, 0xbd, 0x0f, 0xda, 0x95, 0x88, 0x16, 0x0c, 0x2f, 0x5e, 0x9e, 0x68, 0xee, 0xf4, 0x1e, 0xb6, 0xb8, 0xa7, 0x7d, 0x43, 0xa8, 0x00, 0x51, 0xc4, 0xfe, 0x54, 0x10, 0x26, 0xf1, 0xd3, 0x2b};
typedef uint8_t byte;
byte scramble_key(unsigned int *key_input){
*key_input = (*key_input * 0x41c64e6d + 0x3039) % 0x80000000;
return *(byte *)((long)key_input + 3) ^
(byte)*key_input ^ *(byte *)((long)key_input + 1) ^ *(byte *)((long)key_input + 2);
}
void encrypt(uint32_t key,char *text,ulong len)
{
byte bVar1;
uint32_t local_1c [4];
int i;
local_1c[0] = key;
for (i = 0; (ulong)(long)i < len; i = i + 1) {
bVar1 = scramble_key(local_1c);
text[i] = bVar1 ^ text[i];
text[i] = text[i] + 'O';
}
return;
}
void decrypt(uint32_t key,char *text,ulong len)
{
byte bVar1;
uint32_t local_1c [4];
int i;
local_1c[0] = key;
for (i = 0; (ulong)(long)i < len; i = i + 1) {
bVar1 = scramble_key(local_1c);
text[i] = text[i] - 'O';
text[i] = bVar1 ^ text[i];
}
return;
}
int main(int argc, char** args){
decrypt(start_key, text, sizeof(text));
for(uint8_t i=0; i<sizeof(text); i++)
printf("%c", text[i]);
}

15
2/Smoak1/README Normal file
View File

@@ -0,0 +1,15 @@
Welcome to smoak1!
-----
In this challenge, the flag is not directly in the binary, but there is a service running on 31334.
If you give the right responses, it will show you the flag.
To test if you know the algorithm or are just a very good guesser, we implemented two cycles for the check.
You can reach the flagservice with
nc localhost 31334
The flag is also the password for smoak2.
Hints
-----
Some things are the same all the time and are worth looking for on the internet.

BIN
2/Smoak1/a.out Executable file

Binary file not shown.

BIN
2/Smoak1/challenge Executable file

Binary file not shown.

70
2/Smoak1/test.c Normal file
View File

@@ -0,0 +1,70 @@
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
uint64_t generate_challenge(){
time_t tVar1;
long challenge;
uint8_t rnds [9];
tVar1 = time((time_t *)0x0);
srand((uint)tVar1);
memset(rnds,0,9);
challenge = 0;
for (uint8_t i = 0; i < 8; i = i + 1) {
rnds[i] = (uint8_t)rand();
challenge = challenge * 0x100 + (ulong)rnds[i];
}
for(uint8_t i=0; i<sizeof(rnds); i++)
printf("%02X ", rnds[i]);
printf("\n");
printf("Challenge: %llX\n",challenge);
return challenge;
}
unsigned int FUN_001011b0(char *param_1,long param_2)
{
long start;
char *next_char_p;
int i;
char character;
unsigned int mask;
long len;
char *input_char;
mask = 0xffffffff;
len = param_2;
input_char = param_1;
while (start = len + -1, len != 0) {
next_char_p = input_char + 1;
character = *input_char;
for (i = 0; len = start, input_char = next_char_p, i < 8; i = i + 1) {
if ((((int)character ^ mask) & 1) == 0) {
mask = mask >> 1;
}
else {
mask = mask >> 1 ^ 0xedb88320;
}
character = character >> 1;
}
}
return mask ^ 0xffffffff;
}
int main(int argc, char** args){
//uint64_t challenge = generate_challenge();
uint64_t challenge = 0x84223EB2051265E3;
uint8_t rnds[9];
for(uint8_t i=0; i<8; i++){
rnds[7-i] = challenge & 0xFF;
challenge>>=8;
}
uint64_t resp = FUN_001011b0(rnds, 8);
printf("%ld", resp);
}

13
2/Smoak2/README Normal file
View File

@@ -0,0 +1,13 @@
Welcome to smoak2!
-----
Here we have a slightly more complicated challenge for you. Use
your knowledge from previous tasks, find known functions or
structures and discover the new parts.
You can reach the flagservice with
nc localhost 31335
Hints
-----
Sometimes, chars are 8 bits long but represent fewer bits of the data.

BIN
2/Smoak2/challenge Executable file

Binary file not shown.

12
2/Smoak2/test.c Normal file
View File

@@ -0,0 +1,12 @@
response = base64_enc(challenge+" "+CRC32(challenge))
use crc poly=0x04C11DB7 and print as decimal number
https://www.crccalc.com/?crc=JSYCBPFOWSSKPK&method=CRC-32/ISO-HDLC&datatype=ascii&outtype=dec
"JSYCBPFOWSSKPK 1029423621"
||
vv
"SlNZQ0JQRk9XU1NLUEsgMTAyOTQyMzYyMQ=="

66
2/bonus1/BRIEFING.txt Normal file
View File

@@ -0,0 +1,66 @@
TUBS README ISS
1. Introduction
This challenge consists of an obfuscated program, which out-
puts 512 bytes, most of which are generated randomly. 32
bytes, however, are not generated by an prng. Those 32 bytes
representated as hex values make up the secret, necessary to
acquire the flag.
The goal of this challenge is to find the randomness intro-
ducing instructions and patch them such, that the prng out-
put is constant 0. An example output may look like this:
1b c3 fa 7a 3a d0 97 6c
a2 b4 29 fb dc d1 d1 39
c0 58 e2 1b 9a f8 3f dc
31 b4 1d 0d 19 d0 ac 2e
36 4a 4c 51 40 5a 33 8c
. . . . . . . .
. . . . . . . .
. . . . . . . .
86 f9 61 95 fa 9e 94 c4
41 7e 0a 8c e3 db f9 3e
7a 1d 28 95 22 31 f2 0e
3b 54 c0 b2 b0 1a 52 77
e6 1f 84 f2 25 99 d5 25
After successfully disabling the random number source, the
output may look like this:
00 00 af 00 00 00 00 00
00 00 00 00 56 00 00 00
ff 00 00 00 00 00 00 00
00 00 00 00 01 00 00 00
00 00 00 00 00 00 00 3e
. . . . . . . .
. . . . . . . .
. . . . . . . .
00 aa 00 00 00 00 00 00
00 00 67 00 00 00 00 00
80 00 00 00 00 00 00 00
00 00 00 00 00 10 00 00
00 00 00 00 00 00 c9 00
In that case the flag can be acquired by running the command
"get_token af56ff013e...aa678010c9" on the VM.
TUBS 1

21
2/bonus1/README Normal file
View File

@@ -0,0 +1,21 @@
Welcome to bonus1!
-----
Read the BRIEFING.txt (using the program 'more' is recommended).
Hints
-----
A dynamic binary instrumentation framework like Intel PIN might come in
handy (i. e. do not try to solve this challenge with a static analysis
approach - it might melt your computer and/or your brain).
https://www.intel.com/content/www/us/en/developer/articles/tool/pin-a-dynamic-binary-instrumentation-tool.html
The Intel PIN manual is a good starting point
(https://software.intel.com/sites/landingpage/pintool/docs/98869/Pin/doc/html/index.html).
Besides, there are a lot of ready-to-use PIN tools(/opt/pin/source/tools/SimpleExamples);
you might want to take a look at the pinatrace tool (SimpleExamples, **not** ManualExamples)
that is already shipped with Intel PIN.
If you're solving the challenge on your local
machine, turning off ASLR might be a good idea (e. g. disabling ASLR per process via 'setarch -R').

BIN
2/bonus1/challenge Executable file

Binary file not shown.

48
2/lance1/README Normal file
View File

@@ -0,0 +1,48 @@
Welcome to lance1!
-----
We have implemented a rudimentary class system in C, but somehow
our internal logic is missing. So there is this binary which has
several functions (and none of them are called anywhere). You have
to figure out, what the functions are doing and insert function
calls to execute the actions described below. To patch the binary,
simply put the address of the function to call and it's arguments
in the patches.yaml file in the following format:
```
- - <func-addr>
- - <arg 1>
- <arg 2>
- <arg 3>
...
```
Arguments can be addresses or numbers. Afterwards, run patch.py
which will generate a new binary called `patched` with the new
calls in it.
```
$ ./patch.py
$ ./patched
```
To get the flag, call the right functions with the correct
arguments in the described order and provide the execution hash
to `get_token`.
You should "implement" the following actions:
John prints the information about his account. After he
recognizes that he has not enough money on it, he deposits
another 25€.
Felicity transfers some money to Laurel, so that their accounts
have the exact same balance.
John, Felicity and Laurel all check (in this order) their
new balances.
The flag is also the password for lance2.
Hints
-----
You don't need to reverse the functions updateExecutionHash, printExcHash, argHashToSign, appendArgToSign.
Just skip calls to them, since they are only needed to check which functions you've called.

BIN
2/lance1/challenge Executable file

Binary file not shown.

60
2/lance1/patch.py Executable file
View File

@@ -0,0 +1,60 @@
#!/usr/bin/env python3
from pwn import *
import sys
import stat
from pathlib import Path
import yaml
nop_length = 256
e = ELF("challenge", checksec=False)
context.binary = e
nops_offset = list(e.search(b"\x90"*nop_length))[0]
def main():
calls = yaml.safe_load(open("patches.yaml"))
assembly = ""
asm_len = 0
for call in calls:
args = call[1]
addr = call[0]
tmp = ""
if len(args) >= 1:
tmp += f"mov rdi, {hex(args[0])}\n"
if len(args) >= 2:
tmp += f"mov rsi, {hex(args[1])}\n"
if len(args) >= 3:
tmp += f"mov rdx, {hex(args[2])}\n"
if len(args) >= 4:
tmp += f"mov rcx, {hex(args[3])}\n"
if len(args) >= 5:
tmp += f"mov r8, {hex(args[4])}\n"
if len(args) >= 6:
tmp += f"mov r9, {hex(args[5])}\n"
args = args[6:]
args = args[::-1]
while len(args) > 0:
tmp += f"push {hex(args[0])}\n"
args = args[1:]
asm_len += len(asm(tmp)) + 5
assembly += tmp + f"call {addr}\n"
if asm_len > nop_length:
print("Too much calls/arguments, not enough space")
exit(1)
e.asm(nops_offset, assembly)
e.save("patched")
p = Path("patched")
p.chmod(p.stat().st_mode | stat.S_IEXEC)
if __name__ == "__main__":
main()
print("Patched version created. Run './patched' to see the results.")

3
2/lance1/patches.yaml Normal file
View File

@@ -0,0 +1,3 @@
- - 0x401724
- - 0x4041D0
- 1337

17
2/queen1/test Normal file
View File

@@ -0,0 +1,17 @@
solve with HSgpt:
TL;DR
The program is a tiny “Collatzstep” challenge.
main creates two random numbers:
N=1000000+random() a large (≈1million) starting value.
k=abs( (random() & 0xFF) ) a small nonnegative integer (0255).
func0 prints “Challenge: N k\n>>> ”, reads an integer answer from stdin, calls func1(N,k), and checks whether the returned value equals answer. If it does, it prints “Correct.” and returns0; otherwise it prints “Wrong.” and returns1.
func1 implements k iterations of the Collatz (3n+1) map on the value n that is passed in w0.
Challenge: 524465851 157
The result after performing 157 Collatzsteps on the starting value 524465851 is: 526
Challenge: 1871541254 68
Result after 68 Collatz steps:30046216

17
2/queen2/README Normal file
View File

@@ -0,0 +1,17 @@
Welcome to queen2!
-----
We just learned about creating a GUI for applications, so we had
to try it. It's very basic, but it works! WOW! A new level of user
experience in contrast to these old style command line programs.
Sometimes, this event-stuff is a bit tricky because you don't
see directly which code is executed if you interact with the GUI..
Can you uncover the secret message we put into this program?
The flag is also the password for queen3.
Hints
-----
A debugger could be of great help after you identified interesting code regions.
You get the flag by passing your findings as parameter (in decimal) to the `get_token`-command on this VM.

BIN
2/queen2/a.out Executable file

Binary file not shown.

BIN
2/queen2/challenge Executable file

Binary file not shown.

24
2/queen2/test.c Normal file
View File

@@ -0,0 +1,24 @@
#include <stdint.h>
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
char* FUN_001022f0(char* param_1,uint16_t param_2,int64_t len)
{
for (uint16_t i = 0; i < len; i = i + 1) {
*(char *)(param_1 + i) =
*(char *)(param_1 + i) ^
(char)(((int)(uint)param_2 >> ((char)(i % 2 << 3) & 0x1f)) % 0x100);
}
return param_1;
}
int main(int argc, char** args){
char local_78 [] = { 0x63, 0x39, 0x52, 0x24, 0x45, 0x35, 0x54, 0x77, 0x00, 0x1f, 0x4e, 0x22, 0x45, 0x24, 0x50, 0x24, 0x45, 0x22, 0x00, 0x22, 0x48, 0x33, 0x00, 0x34, 0x4f, 0x2e, 0x45, 0x25, 0x00, 0x37, 0x53, 0x76, 0x42, 0x3f, 0x54, 0x25, 0x00, 0x7e, 0x55, 0x26, 0x50, 0x33, 0x52, 0x76, 0x4c, 0x33, 0x46, 0x22, 0x00, 0x22, 0x4f, 0x76, 0x4c, 0x39, 0x57, 0x33, 0x52, 0x76, 0x52, 0x3f, 0x47, 0x3e, 0x54, 0x7f, 0x00, 0x22, 0x4f, 0x76, 0x47, 0x33, 0x54, 0x76, 0x54, 0x3e, 0x45, 0x76, 0x41, 0x38, 0x53, 0x21, 0x45, 0x24, 0x01, 0x56, 0x00, 0x25, 0x73, 0x00, 0x4e, 0x6f, 0x70, 0x65, 0x00, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f };
char* res;
//memcpy(local_78,"c9R$E5Tw",0x55);
res = FUN_001022f0(local_78,0x5620,0x55);
printf("%s", res);
}

45
2/queen2/txt Normal file
View File

@@ -0,0 +1,45 @@
combine the buttons to get the right number, which is checked in _INIT_2:
if (copy_from_param2 == 0x5620) {
local_98 = (undefined *)FUN_001022f0(local_78,0x5620,0x55);
}
which has been altered inbefore in _FINI_2:
for (i = 0; i < 0x10; i = i + 1) {
local_1a = local_1a << 1;
main_window_obj = gtk_builder_get_object(gtkbuilder,local_a8[i]);
iVar1 = gtk_toggle_button_get_active(main_window_obj);
if (iVar1 != 0) {
local_1a = local_1a + 1;
}
}
local_1a = local_1a ^ 0x1033;
so the number we are trying to get is: 0x5620 ^ 0x1033 == 0x4613
values of buttons were for me:
0010 0040 0800 0020
0100 0400 0080 2000
0200 0004 1000 0008
0002 4000 8000 0001
which results in the pattern:
x o o o
o x o o
x o o o
x x o x
x=pressed
now read this pattern left to right, top to bottom as 16bit variable, msb first
in my case: 0x848d == 33933
execute
get_token 33933

19
2/queen3/README Normal file
View File

@@ -0,0 +1,19 @@
Welcome to queen3!
-----
Programming in C is often error prone, so we decided to try a new
language. In contrast to C, it is much safer, but these newer
languages often use some core libraries for fancy constructs and
language features. So the disassembly looks kind of ugly.
Nevertheless, are you able to reverse this program?
You can reach the flagservice with
nc localhost 31338
Hints
-----
First, identify the language and try to understand the use of the called language core functions.
Strings are not always terminated with a null-byte. It might be helpful to
identify some strings and create char-arrays for them in the disassembler before
reversing the whole prorgam.

BIN
2/queen3/challenge Executable file

Binary file not shown.