Skip to content

Commit

Permalink
feat(scenarios): add commandeer container
Browse files Browse the repository at this point in the history
  • Loading branch information
Ric Featherstone authored and 06kellyjac committed Dec 21, 2023
1 parent 4c1b095 commit a60d226
Show file tree
Hide file tree
Showing 8 changed files with 374 additions and 0 deletions.
8 changes: 8 additions & 0 deletions scenarios/config/commandeer-container/misty-gally/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# syntax=docker/dockerfile:1

FROM controlplaneoffsec/kubectl

WORKDIR /
RUN apt update && apt install -y curl jq
RUN useradd -ms /bin/bash stowaway
USER stowaway
14 changes: 14 additions & 0 deletions scenarios/config/commandeer-container/tasks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
category: KubeCon
difficulty: KubeCon
kind: cp.simulator/scenario:1.0.0
objective: Find the treasure using kubernetes navigation
tasks:
"1":
hints:
sortOrder: 1
startingPoint:
mode: pod
podName: dark-tide
podNamespace: sea
summary: Can you find the treasure?
name: commandeer-container
30 changes: 30 additions & 0 deletions scenarios/config/commandeer-container/treasure-chest/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# syntax=docker/dockerfile:1

##
## Build
##
FROM golang:1.18-bullseye AS build

WORKDIR /chest

# Go Webapp
COPY go.mod ./
COPY *.go ./

RUN go build -o /var/www/chest -ldflags='-w -s' ./main.go

##
## Deploy
##
FROM gcr.io/distroless/base-debian10

WORKDIR /

COPY --from=build --chown=nonroot:nonroot /var/www /var/www
COPY --from=build /go/bin /usr/bin

USER nonroot:nonroot

EXPOSE 8080

CMD ["/var/www/chest"]
3 changes: 3 additions & 0 deletions scenarios/config/commandeer-container/treasure-chest/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module main

go 1.18
76 changes: 76 additions & 0 deletions scenarios/config/commandeer-container/treasure-chest/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package main

import (
"crypto/sha256"
"crypto/subtle"
"fmt"
"log"
"net/http"
"os"
"time"
)

type application struct {
auth struct {
username string
password string
}
}

func main() {
app := new(application)

app.auth.username = os.Getenv("AUTH_USERNAME")
app.auth.password = os.Getenv("AUTH_PASSWORD")

if app.auth.username == "" {
log.Fatal("basic auth username must be provided")
}

if app.auth.password == "" {
log.Fatal("basic auth password must be provided")
}

mux := http.NewServeMux()
mux.HandleFunc("/login", app.basicAuth(app.protectedHandler))
mux.Handle("/", http.RedirectHandler("/loigin", http.StatusMisdirectedRequest))

srv := &http.Server{
Addr: ":8080",
Handler: mux,
IdleTimeout: time.Minute,
ReadTimeout: 10 * time.Second,
WriteTimeout: 30 * time.Second,
}

log.Printf("starting server on %s", srv.Addr)
err := srv.ListenAndServe()
log.Fatal(err)
}

func (app *application) protectedHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, os.Getenv("FLAG"))
}

func (app *application) basicAuth(next http.HandlerFunc) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
username, password, ok := r.BasicAuth()
if ok {
usernameHash := sha256.Sum256([]byte(username))
passwordHash := sha256.Sum256([]byte(password))
expectedUsernameHash := sha256.Sum256([]byte(app.auth.username))
expectedPasswordHash := sha256.Sum256([]byte(app.auth.password))

usernameMatch := (subtle.ConstantTimeCompare(usernameHash[:], expectedUsernameHash[:]) == 1)
passwordMatch := (subtle.ConstantTimeCompare(passwordHash[:], expectedPasswordHash[:]) == 1)

if usernameMatch && passwordMatch {
next.ServeHTTP(w, r)
return
}
}

w.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized)
})
}
9 changes: 9 additions & 0 deletions scenarios/playbooks/commandeer-container.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---

- name: Commandeer Container
hosts: bastion
become: yes
vars:
state: present
roles:
- commandeer-container
207 changes: 207 additions & 0 deletions scenarios/roles/commandeer-container/files/manifests/01-scenario.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
## Attach Container
apiVersion: v1
kind: Namespace
metadata:
name: treasure-island
---
apiVersion: v1
kind: Pod
metadata:
name: buried-chest
namespace: treasure-island
labels:
app: bt
spec:
containers:
- name: treasure
image: docker.io/controlplaneoffsec/scenario-commandeer-container:treasure-chest
ports:
- containerPort: 8080
env:
- name: AUTH_USERNAME
valueFrom:
secretKeyRef:
name: map
key: username
- name: AUTH_PASSWORD
valueFrom:
secretKeyRef:
name: map
key: password
- name: FLAG
value: "flag_ctf{ATTACH_4_ACCESS_2_TREASURE_GALORE}"
securityContext:
allowPrivilegeEscalation: false
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: x
namespace: treasure-island
spec:
type: NodePort
selector:
app: bt
ports:
- port: 8080
targetPort: 8080
protocol: TCP
---
apiVersion: v1
kind: Secret
metadata:
name: map
namespace: treasure-island
type: kubernetes.io/basic-auth
stringData:
username: key
password: 6d7b235802dde35f659c76dfb67f46392407a81f8749bdbbc0ecd775abab1703
---
## Attach Container
apiVersion: v1
kind: Namespace
metadata:
name: smugglers-cove
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: cartographer
namespace: smugglers-cove
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: reader
namespace: treasure-island
rules:
- apiGroups:
- ""
resources:
- secrets
- services
verbs:
- get
- list
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: reader-binding
namespace: treasure-island
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: reader
subjects:
- kind: ServiceAccount
name: cartographer
namespace: smugglers-cove
---
apiVersion: v1
kind: Pod
metadata:
name: misty-gally
namespace: smugglers-cove
spec:
serviceAccountName: cartographer
containers:
- image: docker.io/controlplaneoffsec/scenario-commandeer-container:misty-gally
command: ["/bin/bash"]
name: hold
tty: true
stdin: true
securityContext:
allowPrivilegeEscalation: false
restartPolicy: Always
---
## JumpBox Resources
apiVersion: v1
kind: Namespace
metadata:
name: sea
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: scurvy-dog
namespace: sea
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: navigator
namespace: smugglers-cove
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- pods/attach
verbs:
- create
- patch
- delete
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: navigator-rb
namespace: smugglers-cove
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: navigator
subjects:
- kind: ServiceAccount
name: scurvy-dog
namespace: sea
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: compass
rules:
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- list
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: compass-crb
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: compass
subjects:
- kind: ServiceAccount
name: scurvy-dog
namespace: sea
---
apiVersion: v1
kind: Pod
metadata:
name: dark-tide
namespace: sea
spec:
serviceAccountName: scurvy-dog
containers:
- image: docker.io/controlplaneoffsec/kubectl:latest
command: ["sleep", "2d"]
name: harpoon
securityContext:
allowPrivilegeEscalation: false
restartPolicy: Always
27 changes: 27 additions & 0 deletions scenarios/roles/commandeer-container/tasks/main.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---

- name: Install calico network
ansible.builtin.include_role:
name: cluster-network
tasks_from: calico

- name: Apply K8s manifests
kubernetes.core.k8s:
definition: "{{ lookup('ansible.builtin.file', 'manifests/01-scenario.yaml') | from_yaml_all }}"
state: "{{ state }}"
become: no

- name: Set starting point
ansible.builtin.include_role:
name: starting-point
tasks_from: pod
vars:
namespace: sea
pod: dark-tide

- name: Copy challenge
ansible.builtin.include_role:
name: starting-point
tasks_from: challenge
vars:
challenge_content: "{{ lookup('ansible.builtin.file', 'files/challenge.txt') }}"

0 comments on commit a60d226

Please sign in to comment.