Taken:
/var/log/apache2/suexec.log: zie benedensuid
Werkt met binary’s.
Werkt met scripts voor dash (met optie -p), python, python3, perl, php-cgi. Werkt niet met bash.
Dingen om op te letten:
uid == euid && gid == egid dan OKuid != 33 || gid != 33 dan fout$PATH != /usr/local/bin:/usr/bin:/bin dan foutVoor scripts:
In .htaccess:
<FilesMatch ".+\.(sh|dash|py|py2|py3|pl|php)$">
SetHandler my-script
</FilesMatch>
Action my-script /kleiweg/bin/myscript
myscript.go:
package main import ( "os" "os/exec" "path/filepath" "strings" "syscall" ) var ( host = "urd2" userdir = "/net/homepages/kleiweg/www/" interpreters = map[string]string{ // ".bash": "/bin/bash", ".sh": "/bin/dash -p", ".dash": "/bin/dash -p", ".py": "/usr/bin/python3", ".py2": "/usr/bin/python", ".py3": "/usr/bin/python3", ".pl": "/usr/bin/perl", ".php": "/usr/bin/php-cgi", } environ = []string{ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "TZ=Europe/Amsterdam", } unsafeNames = map[string]bool{ "HTTP_PROXY": true, } varnames = []string{ "AUTH_TYPE", "CONTENT_LENGTH", "CONTENT_TYPE", "CONTEXT_DOCUMENT_ROOT", "CONTEXT_PREFIX", "DATE_GMT", "DATE_LOCAL", "DOCUMENT_ARGS", "DOCUMENT_NAME", "DOCUMENT_PATH_INFO", "DOCUMENT_ROOT", "DOCUMENT_URI", "GATEWAY_INTERFACE", "HTTPS", "LAST_MODIFIED", "PATH_INFO", "PATH_TRANSLATED", "QUERY_STRING", "QUERY_STRING_UNESCAPED", "REMOTE_ADDR", "REMOTE_HOST", "REMOTE_IDENT", "REMOTE_PORT", "REMOTE_USER", "REDIRECT_ERROR_NOTES", "REDIRECT_HANDLER", "REDIRECT_QUERY_STRING", "REDIRECT_REMOTE_USER", "REDIRECT_SCRIPT_FILENAME", "REDIRECT_STATUS", "REDIRECT_URL", "REQUEST_METHOD", "REQUEST_URI", "REQUEST_SCHEME", "SCRIPT_FILENAME", "SCRIPT_NAME", "SCRIPT_URI", "SCRIPT_URL", "SERVER_ADMIN", "SERVER_NAME", "SERVER_ADDR", "SERVER_PORT", "SERVER_PROTOCOL", "SERVER_SIGNATURE", "SERVER_SOFTWARE", "UNIQUE_ID", "USER_NAME", } ) func main() { // script met compleet path pathTranslated := os.Getenv("PATH_TRANSLATED") // is er geknoeid met het path van het script? if pathTranslated != filepath.Clean(pathTranslated) { return } // alleen op de juiste plek if h, _ := os.Hostname(); h != host || !strings.HasPrefix(pathTranslated, userdir) { return } // alleen als originele user:group == www-data:www-data if os.Getuid() != 33 || os.Getgid() != 33 { return } // alleen eigen scripts fi1, err1 := os.Stat(os.Args[0]) fi2, err2 := os.Stat(pathTranslated) if err1 != nil || err2 != nil || fi1.Sys().(*syscall.Stat_t).Uid != fi2.Sys().(*syscall.Stat_t).Uid { return } // wat voor script? i := strings.LastIndex(pathTranslated, ".") if i < 0 { return } interpreter, ok := interpreters[pathTranslated[i:]] if !ok { return } // script kan in andere directory staan if os.Chdir(filepath.Dir(pathTranslated)) != nil { return } // maak een veilige environment for _, name := range varnames { if value := os.Getenv(name); value != "" { environ = append(environ, name+"="+value) } } seen := make(map[string]bool) for _, s := range os.Environ() { if strings.HasPrefix(s, "HTTP_") || strings.HasPrefix(s, "SSL_") { if a := strings.SplitN(s, "=", 2); len(a) == 2 && a[1] != "" { if seen[a[0]] || unsafeNames[a[0]] { continue } environ = append(environ, s) seen[a[0]] = true } } } ii := strings.Fields(interpreter) args := ii[1:] args = append(args, pathTranslated) cmd := exec.Command(ii[0], args...) cmd.Env = environ cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Run() }
build:
go build myscript.go chmod +s myscript
Foutmeldingen in /var/log/apache2/suexec.log:
OK:
[2019-05-06 15:14:05]: uid: (10107437/gosse) gid: (10107437/p107437) cmd: verwant_twnc.py
Fout 1:
[2019-05-06 15:22:24]: uid: (10107437/p107437) gid: (10107437/p107437) cmd: verwant_twnc.py [2019-05-06 15:22:24]: cannot get docroot information (/home/p107437)
Fout 2:
[2019-05-06 16:08:55]: uid: (1006/gosse) gid: (1006/ar) cmd: verwant_twnc.py [2019-05-06 16:08:55]: target uid/gid (1006/1006) mismatch with directory (10107437/10107437) or program (10107437/10107437)