Skip to content

Instantly share code, notes, and snippets.

@santrancisco
Last active February 14, 2024 05:50
Show Gist options
  • Save santrancisco/c416eb4622fa2156d4ae78393db1a1bf to your computer and use it in GitHub Desktop.
Save santrancisco/c416eb4622fa2156d4ae78393db1a1bf to your computer and use it in GitHub Desktop.
seccomp_filter

Prepare environment:

Install libseccomp-dev:

apt install libseccomp-dev

Build udf and main:

go build udf.go
go mod init libseccomp-golang 
go mod tidy
go build main.go

Test it out:

With no seccomp filter, child process and directory listing in main works:

ubuntu@ip-172-31-28-239:~/seccomp$ ./main ./udf

[-] Seccomp filter is not applied
[+] Starting child process....
[+] Done with child process....
Printing to stdout from inside child process

Perform GET to https://google.com

&{200 OK 200 HTTP/2.0 2 0 map[Alt-Svc:[h3=":443"; ma=2592000,h3-29=":443"; ma=2592000] Cache-Control:[private, max-age=0] Content-Security-Policy-Report-Only:[object-src 'none';base-uri 'self';script-src 'nonce-HXtgEOiLxvI_MdqfVfryEg' 'strict-dynamic' 'report-sample' 'unsafe-eval' 'unsafe-inline' https: http:;report-uri https://csp.withgoogle.com/csp/gws/other-hp] Content-Type:[text/html; charset=ISO-8859-1] Date:[Wed, 14 Feb 2024 00:27:47 GMT] Expires:[-1] P3p:[CP="This is not a P3P policy! See g.co/p3phelp for more info."] Server:[gws] Set-Cookie:[1P_JAR=2024-02-14-00; expires=Fri, 15-Mar-2024 00:27:47 GMT; path=/; domain=.google.com; Secure AEC=Ae3NU9Mm3rbUT5tSM175zJFhHN73opy7CPj2jYYdM1_DM0C2T_1tzZ6w1A; expires=Mon, 12-Aug-2024 00:27:47 GMT; path=/; domain=.google.com; Secure; HttpOnly; SameSite=lax NID=511=hCFETK4yLqCuffxXCKX3j8oqb4Jd7eng4OXPbpCh9HLskiYvnfWbMQPUulrgp74OFJkxs0KeVrA9T9sep489i2F65Mdnoz7k-oX-woldylE-dBZpw98VESOZ7XZSwNQlMjYI_evF0mu67H1L-g0SAwGcx7uR7NwD0whVB1JCvk4; expires=Thu, 15-Aug-2024 00:27:47 GMT; path=/; domain=.google.com; HttpOnly] X-Frame-Options:[SAMEORIGIN] X-Xss-Protection:[0]] 0xc0004bae10 -1 [] false true map[] 0xc0000b8100 0xc0004fa0b0}

Trying to get current working directory
Current working directory is: /home/ubuntu/seccomp

With seccomp filter, directory listing no longer work in main but network still works for child:

ubuntu@ip-172-31-28-239:~/seccomp$ ./main "arch_prctl,read,write,pread64,clone,clone3,close,dup3,epoll_create1,epoll_ctl,epoll_pwait,execve,exit,exit_group,futex,mprotect,nanosleep,newfstatat,openat,pipe2,rt_sigaction,rt_sigprocmask,rt_sigreturn,sendmmsg,setsockopt,sigaltstack,socket,getsockopt,getpeername,connect,fstat,mmap,recvfrom,poll" ./network
>>>>>>>> Applying seccomp filter <<<<<<<
[+] Starting child process....
[+] Done with child process....
Printing to stdout from inside child process

Perform GET to https://google.com

&{200 OK 200 HTTP/2.0 2 0 map[Alt-Svc:[h3=":443"; ma=2592000,h3-29=":443"; ma=2592000] Cache-Control:[private, max-age=0] Content-Security-Policy-Report-Only:[object-src 'none';base-uri 'self';script-src 'nonce-sZ925fL_mVbWh9tvZHaWKQ' 'strict-dynamic' 'report-sample' 'unsafe-eval' 'unsafe-inline' https: http:;report-uri https://csp.withgoogle.com/csp/gws/other-hp] Content-Type:[text/html; charset=ISO-8859-1] Date:[Wed, 14 Feb 2024 05:14:57 GMT] Expires:[-1] P3p:[CP="This is not a P3P policy! See g.co/p3phelp for more info."] Server:[gws] Set-Cookie:[1P_JAR=2024-02-14-05; expires=Fri, 15-Mar-2024 05:14:57 GMT; path=/; domain=.google.com; Secure AEC=Ae3NU9NOynuQQgAh8QxmGMSXbKEIFz16wFa-QEMOk8CnhiwOZNVzzcaJ8w; expires=Mon, 12-Aug-2024 05:14:57 GMT; path=/; domain=.google.com; Secure; HttpOnly; SameSite=lax NID=511=coo2uposops3hvUjG-sOfBaqoC4-MaL1E5tsjORtcGAkJwe2IanulEIe7bKdnsPueQltXPFmz37UL98Oy2SdTEKQPmNY2v1FgzulIAdmg_RCwkS5v3oc_PL-85B0GJAg7hBUBzq0xYbCAEDStpCq5Eb9RMMyo1G5ox7E_zn81qw; expires=Thu, 15-Aug-2024 05:14:57 GMT; path=/; domain=.google.com; HttpOnly] X-Frame-Options:[SAMEORIGIN] X-Xss-Protection:[0]] 0xc00027e2a0 -1 [] false true map[] 0xc0000c8400 0xc0000a86e0}

Trying to get current working directory
Failed getting current working directory: operation not permitted

And with a seccomp that remove recvfrom - nothing works:

ubuntu@ip-172-31-28-239:~/seccomp$ ./main "arch_prctl,read,write,pread64,clone,clone3,close,dup3,epoll_create1,epoll_ctl,epoll_pwait,execve,exit,exit_group,futex,mprotect,nanosleep,newfstatat,openat,pipe2,rt_sigaction,rt_sigprocmask,rt_sigreturn,sendmmsg,setsockopt,sigaltstack,socket,getsockopt,getpeername,connect,fstat,mmap,poll" ./network
>>>>>>>> Applying seccomp filter <<<<<<<
[+] Starting child process....
[+] Done with child process....
Printing to stdout from inside child process

Perform GET to https://google.com

2024/02/14 05:13:38 Get "https://google.com": dial tcp: lookup google.com: Temporary failure in name resolution

Trying to get current working directory
Failed getting current working directory: operation not permitted
// Check seccomp is available: cat /boot/config-`uname -r` | grep CONFIG_SECCOMP=
// Install libseccomp-dev
package main
import (
"fmt"
seccomp "github.com/seccomp/libseccomp-golang"
"syscall"
"os/exec"
"log"
"bufio"
"os"
"strings"
)
func main() {
if (len(os.Args) < 2){
fmt.Println("Usage: ./main [comma seperated seccomp filters] <binary to fork>")
return
}
childprogram := os.Args[1]
if (len(os.Args) > 2) {
fmt.Println(">>>>>>>> Applying seccomp filter <<<<<<<")
// Applying seccomp filter to this running process if any argument is set
if err := loadSeccompFilter(os.Args[1]); err != nil {
fmt.Println(fmt.Sprintf("Failed to load seccomp filter: %v", err))
return
}
childprogram = os.Args[2]
} else {
fmt.Println("[-] Seccomp filter is not applied")
}
// Now we fork untrusted code so it inherits our filters
fmt.Println("[+] Starting child process....")
cmd := exec.Command(childprogram)
pipe, err := cmd.StdoutPipe()
cmd.Stderr = cmd.Stdout
if err != nil {
log.Fatal(err)
}
if err := cmd.Start(); err != nil {
log.Fatal(err)
}
fmt.Println("[+] Done with child process....")
reader := bufio.NewReader(pipe)
line, err := reader.ReadString('\n')
for err == nil {
fmt.Println(line)
line, err = reader.ReadString('\n')
}
// Trying to run non whitelist syscall
fmt.Println("Trying to get current working directory")
wd, err := syscall.Getwd()
if err != nil {
fmt.Printf("Failed getting current working directory: %v\n", err)
return
}
fmt.Printf("Current working directory is: %s\n", wd)
}
func loadSeccompFilter(filters string) error {
whitelist := strings.Split(filters,",")
// The filter defaults to fail all syscalls
filter, err := seccomp.NewFilter(seccomp.ActErrno.SetReturnCode(int16(syscall.EPERM)))
if err != nil {
return err
}
// Whitelist relevant syscalls and load the filter
for _, name := range whitelist {
syscallID, err := seccomp.GetSyscallFromName(name)
if err != nil {
return err
}
err = filter.AddRule(syscallID, seccomp.ActAllow)
if err != nil {
return err
}
}
return filter.Load()
}
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
fmt.Println("Printing to stdout from inside child process")
fmt.Println("Perform GET to https://google.com")
resp, err := http.Get("https://google.com")
if err != nil {
log.Fatalln(err)
}
fmt.Println(resp)
return
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment