Secure Blob Runner
Shellcode with ROP via fs_base leak
Initial Impressions
We are provided with the challenge source code (chall.c), which appears to be a simple shellcode runner. It uses mmap to allocate a memory region with read and execute (RX) permissions, loading your shellcode into it—assuming you pass both the byte check and the seccomp filter.
#include <stdlib.h>
#include <stdnoreturn.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdint.h>
#include <seccomp.h>
int check(char* code) {
for (int i = 0; i < 0x1000; i += 1) {
// block our syscall bytes the LAZY way:)
if (code[i] == 0x0f || code[i] == 0x05 || code[i] == 0xcd || code[i] == 0x80)
return 1;
}
// install seccomp filters as extra security!!
// it shouldn't matter though, since syscall is blocked anyways
scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_KILL);
if (!ctx)
return 1;
if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0) < 0)
return 1;
if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sendfile), 0) < 0)
return 1;
if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0) < 0)
return 1;
seccomp_load(ctx);
return 0;
}
void call_shellcode(char* code) {
__asm__(
".intel_syntax noprefix\n"
"mov rax, rdi\n"
"mov rsp, 0\n"
"mov rbp, 0\n"
"mov rbx, 0\n"
"mov rcx, 0\n"
"mov rdx, 0\n"
"mov rdi, 0\n"
"mov rsi, 0\n"
"mov r8, 0\n"
"mov r9, 0\n"
"mov r10, 0\n"
"mov r11, 0\n"
"mov r12, 0\n"
"mov r13, 0\n"
"mov r14, 0\n"
"mov r15, 0\n"
"jmp rax\n"
".att_syntax\n"
);
}
int main() {
setbuf(stdin, 0);
setbuf(stdout, 0);
char* code = mmap((void*)0x13370000, 0x1000, 7, MAP_SHARED | MAP_ANONYMOUS, 0, 0);
printf("Blob Runner> ");
fgets(code, 0x1000, stdin);
mprotect(code, 0x1000, 5);
if (!check(code)) {
call_shellcode(code);
} else {
printf("Bad Blob!\n");
}
}Analysis
The filters are pretty easy to understand.
Seccomp filters only permit the use of
open,sendfileandexitsyscallsShellcode cannot contain the following bytes which are
syscallbytes for x64 and x86
Looking at the previous welcomectf which this challenge was based of, we see that the solution is a polymorphic shellcode because of the rwx permissions set
But this time we don't have write permissions over the mmaped region - lets ROP instead!.
We see that when we jump to our mmaped region at 0x13370000, we note that all registers are cleared besides fs_base
We note that the mmaped region is adjacent to libc which means we can use find gadgets like syscall in libc as the relative offset stays the same!
Last updated