added official hacktheboo2024 writeups
This commit is contained in:
parent
1f7a9b0566
commit
e3c46450f7
327 changed files with 14303 additions and 0 deletions
112
htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/README.md
Normal file
112
htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/README.md
Normal file
|
@ -0,0 +1,112 @@
|
|||
<img src="../../assets/banner.png" style="zoom: 80%;" align=center />
|
||||
|
||||
<img src="../../assets/htb.png" style="zoom: 80%;" align='left' /><font size="6">CryptOfTheUndead</font>
|
||||
|
||||
9<sup>th</sup> 10 24 / Document No. D24.102.170
|
||||
|
||||
Prepared By: clubby789
|
||||
|
||||
Challenge Author: clubby789
|
||||
|
||||
Difficulty: <font color=green>Very Easy</font>
|
||||
|
||||
Classification: Official
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Synopsis
|
||||
|
||||
CryptOfTheUndead is a Very Easy reversing challenge. Players will reverse engineer a ransomware binary to uncover a static key, then decrypt a file to gain the flag.
|
||||
|
||||
## Skills Required
|
||||
- Decompiler usage
|
||||
## Skills Learned
|
||||
- Recognizing cryptographic primitives
|
||||
- Bypassing program checks
|
||||
|
||||
# Solution
|
||||
|
||||
We're provided two files; `crypt` and `flag.txt.undead`. Running `crypt` gives us an error:
|
||||
|
||||
```
|
||||
Usage: ./crypt file_to_encrypt
|
||||
```
|
||||
so we can surmise that this is possibly some kind of ransomware, used to encrypt files. `flag.txt.undead` seems to contain random bytes, so it is likely encrypted.
|
||||
|
||||
## Analysis
|
||||
|
||||
Opening it in a decompiler, we can see the program is not stripped.
|
||||
|
||||
```c
|
||||
int32_t main(int32_t argc, char** argv, char** envp)
|
||||
int32_t return
|
||||
|
||||
if (argc s<= 1) {
|
||||
char const* const program_name = "crypt"
|
||||
|
||||
if (argc == 1)
|
||||
program_name = *argv
|
||||
|
||||
return = 1
|
||||
printf(format: "Usage: %s file_to_encrypt\n", program_name)
|
||||
```
|
||||
We begin by checking the args, and printing a help string if used incorrectly.
|
||||
|
||||
We then check the file argument passed, and ensure it doesn't end with `.undead`:
|
||||
|
||||
```c
|
||||
char* old_filename = argv[1]
|
||||
|
||||
if (ends_with(old_filename, ".undead") != 0) {
|
||||
return = 2
|
||||
puts(str: "error: that which is undead may not be encrypted")
|
||||
```
|
||||
|
||||
We'll then allocate space for our new filename, likely used for the post-encryption fike, and append `.undead` to the old filename.
|
||||
|
||||
```c
|
||||
uint64_t new_filename_len = strlen(old_filename) + 9
|
||||
char* new_filename_buf = malloc(bytes: new_filename_len)
|
||||
strncpy(new_filename_buf, old_filename, new_filename_len)
|
||||
*(new_filename_buf + strlen(new_filename_buf)) = '.undead'
|
||||
```
|
||||
|
||||
We then perform the encryption.
|
||||
```c
|
||||
if (read_file(old_filename, &nbytes_1, &buf_1) != 0)
|
||||
return main.cold() __tailcall
|
||||
|
||||
uint64_t nbytes = nbytes_1
|
||||
void* buf = buf_1
|
||||
encrypt_buf(buf, nbytes, "BRAAAAAAAAAAAAAAAAAAAAAAAAAINS!!")
|
||||
int32_t return_1 = rename(old: old_filename, new: new_filename_buf)
|
||||
return = return_1
|
||||
```
|
||||
`main.cold` is a short function that prints an error message then exits. If the read is successful, we call `encrypt_buf` on it. We then use `rename` to rename the file to the new name.
|
||||
|
||||
Looking into `encrypt_buf`:
|
||||
|
||||
```c
|
||||
int64_t encrypt_buf(char* buf, uint64_t buflen, uint8_t* key)
|
||||
uint8_t nonce[0xc]
|
||||
nonce[0].q = 0
|
||||
nonce[8].d = 0
|
||||
struct chacha_ctx ctx
|
||||
chacha20_init_context(&ctx, key, &nonce, 0)
|
||||
chacha20_xor(&ctx, buf, buflen)
|
||||
```
|
||||
We can see it uses `chacha20` to encrypt a buffer with a given key and a nonce of 0. Even if this file was stripped, we could recognize this as `chacha20` by the cryptographic constant used in `chacha20_init_context`:
|
||||
|
||||
```c
|
||||
__builtin_strncpy(dest: &arg1[0x10], src: "expand 32-byte k", n: 0x10)
|
||||
```
|
||||
|
||||
## Decryption
|
||||
|
||||
Knowing the algorithm (chacha20) and the key (`BRAAAAAAAAAAAAAAAAAAAAAAAAAINS!!`) is enough to encrypt this file. However, we can use a useful property of chacha20 instead. It is a reversible stream cipher, meaning that the 'encrypt' operation can be re-run on ciphertext with the same key to produce the plaintext.
|
||||
|
||||
The binary prevents this by checking for the `.undead` suffix. However, we can either patch that check out, or simply rename `flag.txt.undead` to `flag.txt`. We then run the binary on `flag.txt`, and read `flag.txt.undead` to reveal the flag.
|
||||
|
Binary file not shown.
|
@ -0,0 +1,7 @@
|
|||
.PHONY := clean
|
||||
|
||||
crypt: main.c chacha.c chacha.h
|
||||
gcc main.c chacha.c -O2 -o crypt
|
||||
|
||||
clean:
|
||||
rm -f crypt
|
106
htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/src/chacha.c
Normal file
106
htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/src/chacha.c
Normal file
|
@ -0,0 +1,106 @@
|
|||
// SOURCE: https://github.com/Ginurx/chacha20-c/blob/master/chacha20.c
|
||||
|
||||
#include "chacha.h"
|
||||
static uint32_t rotl32(uint32_t x, int n) {
|
||||
return (x << n) | (x >> (32 - n));
|
||||
}
|
||||
|
||||
static uint32_t pack4(const uint8_t *a) {
|
||||
uint32_t res = 0;
|
||||
res |= (uint32_t)a[0] << 0 * 8;
|
||||
res |= (uint32_t)a[1] << 1 * 8;
|
||||
res |= (uint32_t)a[2] << 2 * 8;
|
||||
res |= (uint32_t)a[3] << 3 * 8;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void unpack4(uint32_t src, uint8_t *dst) {
|
||||
dst[0] = (src >> 0 * 8) & 0xff;
|
||||
dst[1] = (src >> 1 * 8) & 0xff;
|
||||
dst[2] = (src >> 2 * 8) & 0xff;
|
||||
dst[3] = (src >> 3 * 8) & 0xff;
|
||||
}
|
||||
|
||||
static void chacha20_init_block(struct chacha20_context *ctx, uint8_t key[], uint8_t nonce[]) {
|
||||
memcpy(ctx->key, key, sizeof(ctx->key));
|
||||
memcpy(ctx->nonce, nonce, sizeof(ctx->nonce));
|
||||
|
||||
const uint8_t *magic_constant = (uint8_t*)"expand 32-byte k";
|
||||
ctx->state[0] = pack4(magic_constant + 0 * 4);
|
||||
ctx->state[1] = pack4(magic_constant + 1 * 4);
|
||||
ctx->state[2] = pack4(magic_constant + 2 * 4);
|
||||
ctx->state[3] = pack4(magic_constant + 3 * 4);
|
||||
ctx->state[4] = pack4(key + 0 * 4);
|
||||
ctx->state[5] = pack4(key + 1 * 4);
|
||||
ctx->state[6] = pack4(key + 2 * 4);
|
||||
ctx->state[7] = pack4(key + 3 * 4);
|
||||
ctx->state[8] = pack4(key + 4 * 4);
|
||||
ctx->state[9] = pack4(key + 5 * 4);
|
||||
ctx->state[10] = pack4(key + 6 * 4);
|
||||
ctx->state[11] = pack4(key + 7 * 4);
|
||||
ctx->state[12] = 0;
|
||||
ctx->state[13] = pack4(nonce + 0 * 4);
|
||||
ctx->state[14] = pack4(nonce + 1 * 4);
|
||||
ctx->state[15] = pack4(nonce + 2 * 4);
|
||||
|
||||
memcpy(ctx->nonce, nonce, sizeof(ctx->nonce));
|
||||
}
|
||||
|
||||
static void chacha20_block_set_counter(struct chacha20_context *ctx, uint64_t counter) {
|
||||
ctx->state[12] = (uint32_t)counter;
|
||||
ctx->state[13] = pack4(ctx->nonce + 0 * 4) + (uint32_t)(counter >> 32);
|
||||
}
|
||||
|
||||
static void chacha20_block_next(struct chacha20_context *ctx) {
|
||||
for (int i = 0; i < 16; i++) ctx->keystream32[i] = ctx->state[i];
|
||||
|
||||
#define CHACHA20_QUARTERROUND(x, a, b, c, d) \
|
||||
x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 16); \
|
||||
x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 12); \
|
||||
x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 8); \
|
||||
x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 7);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
CHACHA20_QUARTERROUND(ctx->keystream32, 0, 4, 8, 12)
|
||||
CHACHA20_QUARTERROUND(ctx->keystream32, 1, 5, 9, 13)
|
||||
CHACHA20_QUARTERROUND(ctx->keystream32, 2, 6, 10, 14)
|
||||
CHACHA20_QUARTERROUND(ctx->keystream32, 3, 7, 11, 15)
|
||||
CHACHA20_QUARTERROUND(ctx->keystream32, 0, 5, 10, 15)
|
||||
CHACHA20_QUARTERROUND(ctx->keystream32, 1, 6, 11, 12)
|
||||
CHACHA20_QUARTERROUND(ctx->keystream32, 2, 7, 8, 13)
|
||||
CHACHA20_QUARTERROUND(ctx->keystream32, 3, 4, 9, 14)
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++) ctx->keystream32[i] += ctx->state[i];
|
||||
|
||||
uint32_t *counter = ctx->state + 12;
|
||||
counter[0]++;
|
||||
if (0 == counter[0]) {
|
||||
counter[1]++;
|
||||
assert(0 != counter[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void chacha20_init_context(struct chacha20_context *ctx, uint8_t key[], uint8_t nonce[], uint64_t counter) {
|
||||
memset(ctx, 0, sizeof(struct chacha20_context));
|
||||
|
||||
chacha20_init_block(ctx, key, nonce);
|
||||
chacha20_block_set_counter(ctx, counter);
|
||||
|
||||
ctx->counter = counter;
|
||||
ctx->position = 64;
|
||||
}
|
||||
|
||||
void chacha20_xor(struct chacha20_context *ctx, uint8_t *bytes, size_t n_bytes) {
|
||||
uint8_t *keystream8 = (uint8_t*)ctx->keystream32;
|
||||
for (size_t i = 0; i < n_bytes; i++)
|
||||
{
|
||||
if (ctx->position >= 64)
|
||||
{
|
||||
chacha20_block_next(ctx);
|
||||
ctx->position = 0;
|
||||
}
|
||||
bytes[i] ^= keystream8[ctx->position];
|
||||
ctx->position++;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
// SOURCE: https://github.com/Ginurx/chacha20-c/blob/master/chacha20.h
|
||||
#ifndef CHACHA_H
|
||||
#define CHACHA_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
struct chacha20_context {
|
||||
uint32_t keystream32[16];
|
||||
size_t position;
|
||||
uint8_t key[32];
|
||||
uint8_t nonce[12];
|
||||
uint64_t counter;
|
||||
uint32_t state[16];
|
||||
};
|
||||
|
||||
void chacha20_init_context(struct chacha20_context *ctx, uint8_t key[], uint8_t nonce[], uint64_t counter);
|
||||
|
||||
void chacha20_xor(struct chacha20_context *ctx, uint8_t *bytes, size_t n_bytes);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,87 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "chacha.h"
|
||||
|
||||
int ends_with(const char* string, const char* suffix) {
|
||||
size_t s_len = strlen(string);
|
||||
size_t suf_len = strlen(suffix);
|
||||
if (suf_len > s_len) return 0;
|
||||
return strncmp(string + s_len - suf_len, suffix, suf_len) == 0;
|
||||
}
|
||||
|
||||
int read_file(const char* path, size_t* out_len, char** out_buf) {
|
||||
int fd = open(path, O_RDONLY);
|
||||
if (fd < 0) return fd;
|
||||
size_t amnt_read = 0;
|
||||
size_t buf_sz = 1024;
|
||||
char* buf = malloc(buf_sz);
|
||||
while (1) {
|
||||
ssize_t res;
|
||||
if ((res = read(fd, buf + amnt_read, buf_sz - amnt_read)) < 0) {
|
||||
close(fd);
|
||||
free(buf);
|
||||
return res;
|
||||
}
|
||||
amnt_read += res;
|
||||
if (res == 0) {
|
||||
close(fd);
|
||||
*out_buf = buf;
|
||||
*out_len = amnt_read;
|
||||
return 0;
|
||||
}
|
||||
if (!(buf = realloc(buf, buf_sz + 1024))) {
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
buf_sz += 1024;
|
||||
}
|
||||
}
|
||||
|
||||
void encrypt_buf(char* buffer, size_t buflen, uint8_t* key) {
|
||||
struct chacha20_context ctx;
|
||||
uint8_t nonce[12] = { 0 };
|
||||
chacha20_init_context(&ctx, key, nonce, 0);
|
||||
chacha20_xor(&ctx, buffer, buflen);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s file_to_encrypt\n", (argc > 0) ? argv[0] : "crypt");
|
||||
return 1;
|
||||
}
|
||||
const char* file = argv[1];
|
||||
if (ends_with(file, ".undead")) {
|
||||
puts("error: that which is undead may not be encrypted");
|
||||
return 2;
|
||||
}
|
||||
size_t new_filename_len = strlen(file) + sizeof(".undead") + 1;
|
||||
char* new_filename = malloc(new_filename_len);
|
||||
strncpy(new_filename, file, new_filename_len);
|
||||
strncat(new_filename, ".undead", new_filename_len);
|
||||
char* filebuf;
|
||||
size_t filelen;
|
||||
if (read_file(file, &filelen, &filebuf)) {
|
||||
perror("error reading file");
|
||||
return 3;
|
||||
}
|
||||
|
||||
encrypt_buf(filebuf, filelen, "BRAAAAAAAAAAAAAAAAAAAAAAAAAINS!!");
|
||||
if (rename(file, new_filename)) {
|
||||
perror("error renaming file");
|
||||
return 4;
|
||||
}
|
||||
int fd = open(new_filename, O_WRONLY | O_TRUNC);
|
||||
if (fd < 0) {
|
||||
perror("error opening new file");
|
||||
return 5;
|
||||
}
|
||||
write(fd, filebuf, filelen);
|
||||
close(fd);
|
||||
puts("successfully zombified your file!");
|
||||
return 0;
|
||||
}
|
101
htb/hacktheboo2024/rev/[Very Easy] Graverobber/README.md
Normal file
101
htb/hacktheboo2024/rev/[Very Easy] Graverobber/README.md
Normal file
|
@ -0,0 +1,101 @@
|
|||
<img src="../../assets/banner.png" style="zoom: 80%;" align=center />
|
||||
|
||||
<img src="../../assets/htb.png" style="zoom: 80%;" align='left' /><font size="6">Graverobber</font>
|
||||
|
||||
4<sup>th</sup> 10 24 / Document No. D24.102.X168
|
||||
|
||||
Prepared By: clubby789
|
||||
|
||||
Challenge Author: clubby789
|
||||
|
||||
Difficulty: <font color=green>Very Easy</font>
|
||||
|
||||
Classification: Official
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Synopsis
|
||||
|
||||
Graverobber is a Very Easy reversing challenge. Players will use `strace` to identify binary functionality, then scripting to uncover the flag.
|
||||
|
||||
## Skills Learned
|
||||
- strace
|
||||
- basic scripting
|
||||
|
||||
|
||||
# Solution
|
||||
|
||||
If we run the provided binary, we're given an error message.
|
||||
|
||||
```
|
||||
We took a wrong turning!
|
||||
```
|
||||
|
||||
## Tracing
|
||||
|
||||
We can use `strace` to try and guess what the binary is doing.
|
||||
|
||||
```c
|
||||
$ strace ./robber
|
||||
/* SNIP */
|
||||
newfstatat(AT_FDCWD, "H/", 0x7ffcbd70cf50, 0) = -1 ENOENT (No such file or directory)
|
||||
write(1, "We took a wrong turning!\n", 25We took a wrong turning!
|
||||
) = 25
|
||||
exit_group(1) = ?
|
||||
+++ exited with 1 +++
|
||||
```
|
||||
|
||||
We're trying to use `newfstatat` (a specialized version of the `stat` syscall used for file metadata) on some directory `H`. If we create it and run again:
|
||||
|
||||
```c
|
||||
newfstatat(AT_FDCWD, "H/", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
|
||||
newfstatat(AT_FDCWD, "H/T/", 0x7fff03f91e00, 0) = -1 ENOENT (No such file or directory)
|
||||
write(1, "We took a wrong turning!\n", 25We took a wrong turning!
|
||||
```
|
||||
|
||||
Looks like it will open several directories in sequence. We'll write a script to automate creating them.
|
||||
|
||||
## Scripting
|
||||
|
||||
We'll begin by deleting and creating a directory to work in.
|
||||
|
||||
```py
|
||||
import os
|
||||
import shutil
|
||||
from pwn import *
|
||||
|
||||
try:
|
||||
shutil.rmtree("directories")
|
||||
os.mkdir("directories")
|
||||
except Exception:
|
||||
pass
|
||||
os.chdir("directories")
|
||||
```
|
||||
|
||||
We'll then loop, running the binary under `strace` (using `-e` to filter to only the `newfstatat` calls):
|
||||
|
||||
```py
|
||||
while True:
|
||||
with context.local(log_level='ERROR'):
|
||||
p = process(["strace", "-e", "newfstatat", "../robber"])
|
||||
out = p.recvall().decode()
|
||||
p.close()
|
||||
```
|
||||
|
||||
We'll then look at the last call to see the last path expected, and use that to create a directory. We'll also break if the error message isn't printed as we've likely found the whole path.
|
||||
|
||||
```py
|
||||
if 'wrong turning' not in out: break
|
||||
stats = [line for line in out.split("\n") if "newfstatat" in line]
|
||||
# Get last line, and get the content of the string
|
||||
path = stats[-1].split('"')[1]
|
||||
# Remove separators and print path
|
||||
print(path.replace("/", ""))
|
||||
# Recursively make the directory
|
||||
os.makedirs(path)
|
||||
```
|
||||
|
||||
On running this script, we'll get the flag.
|
23
htb/hacktheboo2024/rev/[Very Easy] Graverobber/htb/solve.py
Executable file
23
htb/hacktheboo2024/rev/[Very Easy] Graverobber/htb/solve.py
Executable file
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/env python3
|
||||
import os
|
||||
import shutil
|
||||
from pwn import *
|
||||
|
||||
try:
|
||||
shutil.rmtree("directories")
|
||||
os.mkdir("directories")
|
||||
except Exception:
|
||||
pass
|
||||
os.chdir("directories")
|
||||
|
||||
while True:
|
||||
with context.local(log_level='ERROR'):
|
||||
p = process(["strace", "-e", "newfstatat", "../robber"])
|
||||
out = p.recvall().decode()
|
||||
p.close()
|
||||
if 'wrong turning' not in out: break
|
||||
stats = [line for line in out.split("\n") if "newfstatat" in line]
|
||||
path = stats[-1].split('"')[1]
|
||||
print(path.replace("/", ""))
|
||||
os.makedirs(path)
|
||||
|
Binary file not shown.
1
htb/hacktheboo2024/rev/[Very Easy] Graverobber/src/.gitignore
vendored
Normal file
1
htb/hacktheboo2024/rev/[Very Easy] Graverobber/src/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
directories
|
|
@ -0,0 +1,7 @@
|
|||
.PHONY := clean
|
||||
|
||||
robber: main.c
|
||||
gcc main.c -o robber
|
||||
|
||||
clean:
|
||||
rm -f robber
|
56
htb/hacktheboo2024/rev/[Very Easy] Graverobber/src/main.c
Normal file
56
htb/hacktheboo2024/rev/[Very Easy] Graverobber/src/main.c
Normal file
|
@ -0,0 +1,56 @@
|
|||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
// HTB{br34k1n9_d0wn_th3_sysc4ll5}
|
||||
uint32_t parts[] = {
|
||||
U'H',
|
||||
U'T',
|
||||
U'B',
|
||||
U'{',
|
||||
U'b',
|
||||
U'r',
|
||||
U'3',
|
||||
U'4',
|
||||
U'k',
|
||||
U'1',
|
||||
U'n',
|
||||
U'9',
|
||||
U'_',
|
||||
U'd',
|
||||
U'0',
|
||||
U'w',
|
||||
U'n',
|
||||
U'_',
|
||||
U't',
|
||||
U'h',
|
||||
U'3',
|
||||
U'_',
|
||||
U's',
|
||||
U'y',
|
||||
U's',
|
||||
U'c',
|
||||
U'4',
|
||||
U'l',
|
||||
U'l',
|
||||
U'5',
|
||||
U'}',
|
||||
0,
|
||||
};
|
||||
|
||||
#define N_PARTS sizeof(parts)/sizeof(parts[0])
|
||||
|
||||
int main() {
|
||||
char buf[(N_PARTS * 2) + 4] = { 0 };
|
||||
struct stat st;
|
||||
for (int i = 0; i < N_PARTS; i++) {
|
||||
buf[i * 2] = parts[i];
|
||||
buf[(i * 2) + 1] = '/';
|
||||
if (stat(buf, &st)) {
|
||||
puts("We took a wrong turning!");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
puts("We found the treasure! (I hope it's not cursed)");
|
||||
}
|
52
htb/hacktheboo2024/rev/[Very Easy] SpookyPass/README.md
Normal file
52
htb/hacktheboo2024/rev/[Very Easy] SpookyPass/README.md
Normal file
|
@ -0,0 +1,52 @@
|
|||
<img src="../../assets/banner.png" style="zoom: 80%;" align=center />
|
||||
|
||||
<img src="../../assets/htb.png" style="zoom: 80%;" align='left' /><font size="6">SpookyPass</font>
|
||||
|
||||
4<sup>th</sup> 10 24 / Document No. D24.102.169
|
||||
|
||||
Prepared By: clubby789
|
||||
|
||||
Challenge Author: clubby789
|
||||
|
||||
Difficulty: <font color=green>Very Easy</font>
|
||||
|
||||
Classification: Official
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Synopsis
|
||||
|
||||
SpookyPass is a Very Easy reversing challenge. Players will use `strings` to identify a password.
|
||||
|
||||
## Skills Learned
|
||||
- `strings`
|
||||
|
||||
# Solution
|
||||
|
||||
Running the binary, we're given a password prompt:
|
||||
|
||||
```
|
||||
Welcome to the SPOOKIEST party of the year.
|
||||
Before we let you in, you'll need to give us the password: foo
|
||||
You're not a real ghost; clear off!
|
||||
```
|
||||
|
||||
We'll use `strings` to look for hidden data in the program:
|
||||
|
||||
```sh
|
||||
$ strings ./pass
|
||||
# .. SNIP ..
|
||||
Welcome to the
|
||||
[1;3mSPOOKIEST
|
||||
[0m party of the year.
|
||||
Before we let you in, you'll need to give us the password:
|
||||
s3cr3t_p455_f0r_gh05t5_4nd_gh0ul5
|
||||
Welcome inside!
|
||||
You're not a real ghost; clear off!
|
||||
# .. SNIP ..
|
||||
```
|
||||
|
||||
If we try `s3cr3t_p455_f0r_gh05t5_4nd_gh0ul5` as the password, we'll be accepted and receive the flag.
|
Binary file not shown.
|
@ -0,0 +1,7 @@
|
|||
.PHONY := clean
|
||||
|
||||
pass: main.c
|
||||
gcc main.c -o pass
|
||||
|
||||
clean:
|
||||
rm -f pass
|
53
htb/hacktheboo2024/rev/[Very Easy] SpookyPass/src/main.c
Normal file
53
htb/hacktheboo2024/rev/[Very Easy] SpookyPass/src/main.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// HTB{un0bfu5c4t3d_5tr1ng5}
|
||||
uint32_t parts[] = {
|
||||
U'H',
|
||||
U'T',
|
||||
U'B',
|
||||
U'{',
|
||||
U'u',
|
||||
U'n',
|
||||
U'0',
|
||||
U'b',
|
||||
U'f',
|
||||
U'u',
|
||||
U'5',
|
||||
U'c',
|
||||
U'4',
|
||||
U't',
|
||||
U'3',
|
||||
U'd',
|
||||
U'_',
|
||||
U'5',
|
||||
U't',
|
||||
U'r',
|
||||
U'1',
|
||||
U'n',
|
||||
U'g',
|
||||
U'5',
|
||||
U'}',
|
||||
0,
|
||||
};
|
||||
#define N_PARTS sizeof(parts)/sizeof(parts[0])
|
||||
|
||||
int main() {
|
||||
char buf[128];
|
||||
char flagbuf[N_PARTS] = { 0 };
|
||||
puts("Welcome to the \x1b[1;3mSPOOKIEST\x1b[0m party of the year!");
|
||||
printf("Before we let you in, you'll need to give us the password: ");
|
||||
fgets(buf, sizeof(buf), stdin);
|
||||
char* nl;
|
||||
if (nl = strchr(buf, '\n')) *nl = 0;
|
||||
if (strcmp(buf, "s3cr3t_p455_f0r_gh05t5_4nd_gh0ul5") == 0) {
|
||||
puts("Welcome inside!");
|
||||
for (int i = 0; i < N_PARTS; i++) {
|
||||
flagbuf[i] = parts[i];
|
||||
}
|
||||
puts(flagbuf);
|
||||
} else {
|
||||
puts("You're not a real ghost; clear off!");
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue