diff --git a/.drone.yml b/.drone.yml index 0ebb7c6..ee6e6c1 100644 --- a/.drone.yml +++ b/.drone.yml @@ -86,7 +86,7 @@ platform: arch: amd64 steps: -- name: render subject +- name: compose subject image: pandoc/latex:2.17.1 commands: - sed -i s/v3.12/v3.14/ /etc/apk/repositories @@ -98,11 +98,39 @@ steps: - tar xf /tmp/FantasqueSansMono-Normal.tar.gz -C /usr/share/fonts/fantasque-sans-mono OTF/ TTF/ --strip-component=1 - mkdir dist - make -C tutorial/ansible - - mv tutorial/ansible/tutorial.pdf dist/tutorial-2.pdf + - mv tutorial/ansible/tutorial.pdf dist/tutorial-2-${DRONE_TAG##srs20??-tutorial2-}.pdf + +- name: deploy subject + image: appleboy/drone-scp + settings: + tar_tmp_path: /tmp/ + host: adlin.nemunai.re + target: /var/www/nemunai.re/adlin/subjects/ + source: dist/* + strip_components: 1 + username: + from_secret: ssh_username + key: + from_secret: deploy_key + port: + from_secret: ssh_port + +- name: link to latest subject + image: appleboy/drone-ssh + settings: + host: adlin.nemunai.re + username: + from_secret: ssh_username + key: + from_secret: deploy_key + port: + from_secret: ssh_port + script: + - ln -sf /var/www/nemunai.re/adlin/subjects/tutorial-2-${DRONE_TAG##srs20??-tutorial2-}.pdf /var/www/nemunai.re/adlin/tutorial-2.pdf trigger: ref: - - refs/tags/tutorial2-* + - refs/tags/srs20??-tutorial2-* --- kind: pipeline type: docker diff --git a/Makefile b/Makefile index 2007900..9a085fc 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ LINUXKIT ?= $(GOPATH)/bin/linuxkit -tuto1: token-validator/token-validator server.iso +tuto1: login-initrd.img challenge token-validator/token-validator server.iso -pkg/login-app: pkg/login-app/cmd/login.go pkg/login-app/cmd/dialog-checklogin.go pkg/login-app/cmd/cmd pkg/login-app/cmd/dialog-login.go pkg/login-app/cmd/login-app pkg/login-app/cmd/dialog-errmsg.go pkg/login-app/cmd/main.go pkg/login-app/cmd/stream.go pkg/login-app/cmd/cinematic.go pkg/login-app/build.yml pkg/login-app/Dockerfile - $(LINUXKIT) pkg build --platforms linux/amd64 -org nemunaire pkg/login-app/ +pkg/login-app: pkg/login-app/cmd/login.go pkg/login-app/cmd/dialog-checklogin.go pkg/login-app/cmd/dialog-login.go pkg/login-app/cmd/login-app pkg/login-app/cmd/dialog-errmsg.go pkg/login-app/cmd/main.go pkg/login-app/cmd/stream.go pkg/login-app/cmd/cinematic.go pkg/login-app/build.yml pkg/login-app/Dockerfile + $(LINUXKIT) pkg build -platforms linux/amd64 -org nemunaire pkg/login-app/ #$(LINUXKIT) pkg push -org nemunaire --sign=false pkg/login-app/ touch pkg/login-app @@ -14,10 +14,10 @@ token-validator/token-validator: token-validator/*.go go generate ./token-validator GOOS=linux GOARM=5 GOARCH=arm go build -tags netgo -ldflags '-w -extldflags "-static"' -o $@ ./token-validator -challenge: pkg/challenge/adlin pkg/challenge/issue pkg/challenge/init +pkg/challenge: pkg/challenge/adlin pkg/challenge/issue pkg/challenge/init $(LINUXKIT) pkg build --platforms linux/amd64 -org nemunaire pkg/challenge/ -challenge-initrd.img: challenge.yml subject/adlin.6.gz subject/adlin-TP1-topologie.png +challenge-initrd.img: challenge.yml subject/adlin.6.gz subject/adlin-TP1-topologie.png pkg/challenge pkg/shadow-up $(LINUXKIT) build -docker $< @@ -25,6 +25,14 @@ pkg/arp-spoofer: pkg/arp-spoofer/cmd/main.go pkg/arp-spoofer/cmd/arp.go pkg/arp- $(LINUXKIT) pkg build --platforms linux/amd64 -org nemunaire $@ touch $@ +pkg/chrony: pkg/chrony/build.yml pkg/chrony/Dockerfile + $(LINUXKIT) pkg build --platforms linux/amd64 -org nemunaire pkg/chrony/ + touch pkg/chrony + +pkg/shadow-up: pkg/shadow-up/build.yml pkg/shadow-up/Dockerfile + $(LINUXKIT) pkg build --platforms linux/amd64 -org nemunaire pkg/shadow-up/ + touch pkg/shadow-up + pkg/login-validator: pkg/login-validator/cmd/login.go pkg/login-validator/cmd/main.go pkg/login-validator/cmd/pxetpl.go pkg/login-validator/cmd/logout.go pkg/login-validator/cmd/auth.go pkg/login-validator/cmd/arp.go pkg/login-validator/cmd/auth_krb5.go pkg/login-validator/cmd/auth_ldap.go pkg/login-validator/cmd/students.go pkg/login-validator/cmd/auth_fwd.go pkg/login-validator/cmd/ssh.go pkg/login-validator/build.yml pkg/login-validator/Dockerfile $(LINUXKIT) pkg build --platforms linux/amd64 -org nemunaire pkg/login-validator/ touch pkg/login-validator @@ -49,7 +57,7 @@ pkg/wg-manager: pkg/wg-manager/cmd/register.go pkg/wg-manager/cmd/main.go pkg/wg $(LINUXKIT) pkg build --platforms linux/amd64 -org nemunaire pkg/wg-manager/ touch pkg/wg-manager -server.iso: server.yml students.csv ssl/fullchain.pem ssl/privkey.pem challenge-initrd.img pkg/arp-spoofer pkg/login-validator pkg/monit pkg/postfix pkg/tftpd pkg/unbound pkg/wg-manager challenge-kernel login-initrd.img +server.iso: server.yml students.csv ssl/fullchain.pem ssl/privkey.pem challenge-initrd.img pkg/arp-spoofer pkg/chrony pkg/login-validator pkg/monit pkg/postfix pkg/tftpd pkg/unbound pkg/wg-manager challenge-kernel login-initrd.img $(LINUXKIT) build -docker -format iso-bios $< pkg/debian-tuto2: pkg/debian-tuto2/sshd_config pkg/debian-tuto2/gai.conf pkg/debian-tuto2/isolinux.cfg pkg/debian-tuto2/build.yml pkg/debian-tuto2/default.script pkg/debian-tuto2/issue pkg/debian-tuto2/Dockerfile diff --git a/challenge.yml b/challenge.yml index 5bd5a46..267870b 100644 --- a/challenge.yml +++ b/challenge.yml @@ -1,5 +1,6 @@ init: - nemunaire/challenge:aeaf6be5e366eca943d8d37e8fb0f39d149a42cf + - nemunaire/adlin-shadow-up:8139aa212579684475310cccbaad4925a86ee4f6 files: - path: etc/motd @@ -75,9 +76,11 @@ files: contents: | #!/bin/sh - [ "$2" = "root" ] && - echo -e "\\e[01mTip: vous souvenez-vous du mot de passe root ?\\e[0m" || - echo -e "\\e[01mTip: cette machine n'est pas reliée à l'authentification de l'école.\\e[0m" + grep -q '^root:!' /etc/shadow && { + [ "$2" = "root" ] && + echo -e "\\e[01mTip: vous souvenez-vous du mot de passe root ?\\e[0m" || + echo -e "\\e[01mTip: cette machine n'est pas reliée à l'authentification de l'école.\\e[0m" + } exec login $@ mode: "0755" diff --git a/pkg/adlin-tuto1/Dockerfile b/pkg/adlin-tuto1/Dockerfile index 08f0547..5a4fea7 100644 --- a/pkg/adlin-tuto1/Dockerfile +++ b/pkg/adlin-tuto1/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:edge AS mirror +FROM alpine:3.15 AS mirror RUN mkdir -p /out/etc/apk/ && \ cp /etc/apk/repositories /out/etc/apk/ && \ diff --git a/pkg/arp-spoofer/Dockerfile b/pkg/arp-spoofer/Dockerfile index a6c975b..d673b6c 100644 --- a/pkg/arp-spoofer/Dockerfile +++ b/pkg/arp-spoofer/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:alpine as gobuild +FROM golang:1.17-alpine3.15 as gobuild RUN apk add --no-cache git @@ -6,11 +6,10 @@ WORKDIR /go/src/arp-spoofer ADD cmd ./ -RUN go get -d -v -RUN go build -v +RUN go build -v -ldflags="-s -w" -o arp-spoofer -FROM alpine +FROM alpine:3.15 MAINTAINER Pierre-Olivier Mercier COPY --from=gobuild /go/src/arp-spoofer/arp-spoofer /bin/arp-spoofer diff --git a/pkg/awx_web/Dockerfile b/pkg/awx_web/Dockerfile index ccba073..483f1b7 100644 --- a/pkg/awx_web/Dockerfile +++ b/pkg/awx_web/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine +FROM alpine:3.15 RUN apk add --no-cache \ git diff --git a/pkg/challenge/Dockerfile b/pkg/challenge/Dockerfile index 3eedf47..4b2affa 100644 --- a/pkg/challenge/Dockerfile +++ b/pkg/challenge/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine AS mirror +FROM alpine:edge AS mirror RUN mkdir -p /out/etc/apk/ && \ cp /etc/apk/repositories /out/etc/apk/ && \ @@ -7,7 +7,7 @@ RUN mkdir -p /out/etc/apk/ && \ RUN apk add --no-cache \ gcc \ linux-headers \ - mdocml-apropos \ + mandoc-apropos \ musl-dev RUN apk add --no-cache --initdb -p /out \ @@ -16,6 +16,7 @@ RUN apk add --no-cache --initdb -p /out \ bind-doc \ bind-tools \ busybox \ + busybox-doc \ ca-certificates \ curl \ curl-doc \ @@ -33,12 +34,11 @@ RUN apk add --no-cache --initdb -p /out \ kbd-bkeymaps \ kbd-doc \ kbd-vlock \ - man \ + losetup \ + mandoc \ man-pages \ musl \ nano \ - openntpd \ - openntpd-doc \ openssh-client \ openssh-doc \ openssh-keygen \ diff --git a/pkg/challenge/init b/pkg/challenge/init index 947cdb5..0f42f71 100755 --- a/pkg/challenge/init +++ b/pkg/challenge/init @@ -20,8 +20,21 @@ cmdline() { USER_LOGIN=$(cmdline adlin.login) USER_PKEY=$(cmdline adlin.key) USER_IP=$(cmdline adlin.ip) +ROOT_PASSWORD=$(cmdline adlin.rootpasswd) + +[ -f /etc/shadow_ ] && mv /etc/shadow_ /etc/shadow [ -n "${USER_IP}" ] && echo "${USER_IP}" > /root/my_ip +[ -n "${ROOT_PASSWORD}" ] && sed -i "/^root:/s@!@${ROOT_PASSWORD}@" /etc/shadow + +# Handle extra user from /etc/shadow +sed -r 's/^([^:]+):.*$/\1/' /etc/shadow | while read u; do + grep -q "^$u" /etc/passwd || { + i=$(($(wc -l /etc/passwd | cut -d ' ' -f 1) + 988)) + echo "$u:x:$i:$u" >> /etc/group + echo "$u:x:$i:$i:new user:/home:/bin/ash" >> /etc/passwd + } +done # Define hostname hostname adlin-${USER_LOGIN} @@ -45,6 +58,7 @@ done # Launch some daemons #/usr/bin/setsid /usr/sbin/crond > /dev/null & +/usr/bin/setsid /bin/shadow-up > /dev/null 2> /var/log/sup.log & # Prepare bonus 2 mkdir -p /mnt @@ -68,7 +82,7 @@ N2=$((25 + $RANDOM % 35)) sync rm /mnt/bonus2 sync -umount /mnt +umount /mnt 2> /dev/null # Launch requested init @@ -80,7 +94,7 @@ then while true do sleep $((10 + $RANDOM % 49)) - beep -f 1000 -r 2 -n -r 5 -l 10 --new + beep -f 1000 -r 2 -n -r 5 -l 10 -n done & grep console=ttyS0 /proc/cmdline > /dev/null 2> /dev/null && /usr/bin/setsid sh -c "exec '${INIT}' /dev/ttyS0 2>&1" diff --git a/pkg/challenge/issue b/pkg/challenge/issue index 06116dc..b24bb1b 100644 --- a/pkg/challenge/issue +++ b/pkg/challenge/issue @@ -7,4 +7,4 @@  o88o o8888o `Y8bod88P" o888ooooood8 o888o o888o o888o  -This is \n.pie.epita.net (\s \m) \t +This is \n.pie.epita.fr (\s \m) \t diff --git a/pkg/chrony/Dockerfile b/pkg/chrony/Dockerfile new file mode 100644 index 0000000..5f59d3b --- /dev/null +++ b/pkg/chrony/Dockerfile @@ -0,0 +1,10 @@ +FROM alpine:3.15 +MAINTAINER Pierre-Olivier Mercier + +RUN apk add --no-cache chrony + +EXPOSE 123/udp + +CMD ["/usr/sbin/chronyd","-d"] + +LABEL org.mobyproject.config='{"capabilities": ["CAP_NET_BIND_SERVICE"]}' diff --git a/pkg/chrony/build.yml b/pkg/chrony/build.yml new file mode 100644 index 0000000..52bda48 --- /dev/null +++ b/pkg/chrony/build.yml @@ -0,0 +1,4 @@ +image: chrony +network: true +arches: +- x86_64 diff --git a/pkg/debug/Dockerfile b/pkg/debug/Dockerfile index 3a549b4..76ac1c8 100644 --- a/pkg/debug/Dockerfile +++ b/pkg/debug/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine AS mirror +FROM alpine:3.15 AS mirror RUN mkdir -p /out/etc/apk/ && \ cp /etc/apk/repositories /out/etc/apk/ && \ diff --git a/pkg/login-app/.dockerignore b/pkg/login-app/.dockerignore new file mode 100644 index 0000000..a911256 --- /dev/null +++ b/pkg/login-app/.dockerignore @@ -0,0 +1 @@ +cmd/vendor/ \ No newline at end of file diff --git a/pkg/login-validator/.gitignore b/pkg/login-validator/.gitignore index 07d07ff..f96f32a 100644 --- a/pkg/login-validator/.gitignore +++ b/pkg/login-validator/.gitignore @@ -1 +1,2 @@ validator +login-validator \ No newline at end of file diff --git a/pkg/login-validator/Dockerfile b/pkg/login-validator/Dockerfile index 91d2844..9b14b9e 100644 --- a/pkg/login-validator/Dockerfile +++ b/pkg/login-validator/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:alpine as gobuild +FROM golang:1.17-alpine3.15 as gobuild RUN apk add --no-cache git @@ -9,7 +9,7 @@ ADD cmd ./ RUN go build -v -ldflags="-s -w" -o login-validator -FROM alpine +FROM alpine:3.15 MAINTAINER Pierre-Olivier Mercier EXPOSE 8081 diff --git a/pkg/login-validator/cmd/go.mod b/pkg/login-validator/cmd/go.mod index b8d09bf..7aec17b 100644 --- a/pkg/login-validator/cmd/go.mod +++ b/pkg/login-validator/cmd/go.mod @@ -3,6 +3,7 @@ module git.nemunai.re/srs/adlin/pkg/login-validator go 1.17 require ( + github.com/cavaliergopher/cpio v1.0.1 github.com/go-ldap/ldap/v3 v3.4.2 github.com/jcmturner/gokrb5/v8 v8.4.2 ) diff --git a/pkg/login-validator/cmd/go.sum b/pkg/login-validator/cmd/go.sum index eed4b73..b7561bd 100644 --- a/pkg/login-validator/cmd/go.sum +++ b/pkg/login-validator/cmd/go.sum @@ -1,5 +1,7 @@ github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28= github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/cavaliergopher/cpio v1.0.1 h1:KQFSeKmZhv0cr+kawA3a0xTQCU4QxXF1vhU7P7av2KM= +github.com/cavaliergopher/cpio v1.0.1/go.mod h1:pBdaqQjnvXxdS/6CvNDwIANIFSP0xRKI16PX4xejRQc= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-asn1-ber/asn1-ber v1.5.1 h1:pDbRAunXzIUXfx4CB2QJFv5IuPiuoW+sWvr/Us009o8= diff --git a/pkg/login-validator/cmd/login.go b/pkg/login-validator/cmd/login.go index 9126b51..298c337 100644 --- a/pkg/login-validator/cmd/login.go +++ b/pkg/login-validator/cmd/login.go @@ -169,5 +169,5 @@ func (l loginChecker) registerUser(username, remoteAddr string, ent ARPEntry) (n } func (l loginChecker) lateLoginAction(username, remoteAddr string, mac ARPEntry, ip net.IP) error { - return RegisterUserMAC(mac, ip, username) + return RegisterUserMAC(mac, ip, username, remoteAddr) } diff --git a/pkg/login-validator/cmd/main.go b/pkg/login-validator/cmd/main.go index eed5f9d..3d399e5 100644 --- a/pkg/login-validator/cmd/main.go +++ b/pkg/login-validator/cmd/main.go @@ -102,6 +102,7 @@ func main() { mux := http.NewServeMux() mux.Handle("/login", lc) mux.HandleFunc("/logout", logout) + mux.HandleFunc("/passwd", passwd) http.HandleFunc("/", mux.ServeHTTP) // Serve content diff --git a/pkg/login-validator/cmd/passwd.go b/pkg/login-validator/cmd/passwd.go new file mode 100644 index 0000000..f64ef31 --- /dev/null +++ b/pkg/login-validator/cmd/passwd.go @@ -0,0 +1,128 @@ +package main + +import ( + "compress/gzip" + "io" + "log" + "net/http" + "os" + "path" + "time" + + "github.com/cavaliergopher/cpio" +) + +func copy_challenge(fd io.Writer) error { + fdchal, err := os.Open(path.Join(tftpDir, "challenge-initrd.img")) + if err != nil { + return err + } + defer fdchal.Close() + + _, err = io.Copy(fd, fdchal) + return err +} + +func passwd(w http.ResponseWriter, r *http.Request) { + if addr := r.Header.Get("X-Forwarded-For"); addr != "" { + r.RemoteAddr = addr + } + log.Printf("%s \"%s %s\" [%s]\n", r.RemoteAddr, r.Method, r.URL.Path, r.UserAgent()) + + w.Header().Set("Content-Type", "text/plain") + + // Check request type and size + if r.Method != "POST" { + http.Error(w, + "Invalid request", + http.StatusBadRequest) + return + } else if r.ContentLength < 0 || r.ContentLength > 655360 { + http.Error(w, + "Request entity too large", + http.StatusRequestEntityTooLarge) + return + } + + // Authenticate the request + + // Retrieve the file + file, header, err := r.FormFile("shadow") + if err != nil { + log.Println("Error when retrieving shadow file from", r.RemoteAddr, err.Error()) + http.Error(w, "Unable to read your passwd file: something is wrong in your request", http.StatusBadRequest) + return + } + defer file.Close() + + // Save the file + initrd := initrd_name(r.RemoteAddr) + os.MkdirAll(path.Join(tftpDir, "shadows", initrd), 0755) + + fd, err := os.Create(path.Join(tftpDir, "shadows", initrd, "challenge-initrd.img")) + if err != nil { + log.Println("Error when creating shadow file from", r.RemoteAddr, err.Error()) + http.Error(w, "Unable to treat your passwd file, please try again later", http.StatusInternalServerError) + return + } + defer fd.Close() + + fd2, err := os.Create(path.Join(tftpDir, "shadows", initrd, "shadow")) + if err != nil { + log.Println("Error when creating shadow file from", r.RemoteAddr, err.Error()) + http.Error(w, "Unable to treat your passwd file, please try again later", http.StatusInternalServerError) + return + } + defer fd2.Close() + + // Copy the original challenge + err = copy_challenge(fd) + if err != nil { + log.Println(r.RemoteAddr, "Error when opening original challenge initramfs:", err.Error()) + http.Error(w, "Unable to treat your passwd file, please try again later", http.StatusInternalServerError) + return + } + + // Append the new cpio archive + wfd := io.MultiWriter(fd, fd2) + zw := gzip.NewWriter(wfd) + wcpio := cpio.NewWriter(zw) + + hdr := &cpio.Header{ + Name: "etc/shadow_", + Mode: 0640, + ModTime: time.Now(), + Size: header.Size, + } + if err := wcpio.WriteHeader(hdr); err != nil { + log.Println("Error when writing cpio header from", r.RemoteAddr, err.Error()) + http.Error(w, "Unable to treat your passwd file, please try again later", http.StatusInternalServerError) + return + } + body, err := io.ReadAll(file) + if err != nil { + log.Println("Error when writing cpio body from", r.RemoteAddr, err.Error()) + http.Error(w, "Unable to treat your passwd file, please try again later", http.StatusInternalServerError) + return + } + if _, err := wcpio.Write(body); err != nil { + log.Println("Error when writing cpio file from", r.RemoteAddr, err.Error()) + http.Error(w, "Unable to treat your passwd file, please try again later", http.StatusInternalServerError) + return + } + + if err := wcpio.Close(); err != nil { + log.Println("Error when closing cpio file from", r.RemoteAddr, err.Error()) + http.Error(w, "Unable to treat your passwd file, please try again later", http.StatusInternalServerError) + return + } + + if err := zw.Close(); err != nil { + log.Println("Error when closing gzip file from", r.RemoteAddr, err.Error()) + http.Error(w, "Unable to treat your passwd file, please try again later", http.StatusInternalServerError) + return + } + + log.Println("Registered shadow for", r.RemoteAddr) + http.Error(w, "Success", http.StatusOK) +} diff --git a/pkg/login-validator/cmd/pxetpl.go b/pkg/login-validator/cmd/pxetpl.go index b7674a1..61ee39e 100644 --- a/pkg/login-validator/cmd/pxetpl.go +++ b/pkg/login-validator/cmd/pxetpl.go @@ -2,9 +2,11 @@ package main import ( "crypto/hmac" + "crypto/md5" "crypto/sha512" "fmt" "io/ioutil" + "log" "net" "os" "path" @@ -15,19 +17,22 @@ const pxeUserTplPath = "pxelinux.cfg/tpl" const ipxeUserTplPath = "pxelinux.cfg/tpl.ipxe" const pxeUserPath = "pxelinux.cfg" -func RegisterUserMAC(ent ARPEntry, ip net.IP, username string) error { - if err := registerUser(ipxeUserTplPath, fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x.ipxe", ent.HWAddress[0], ent.HWAddress[1], ent.HWAddress[2], ent.HWAddress[3], ent.HWAddress[4], ent.HWAddress[5]), username, ip); err != nil { +func RegisterUserMAC(ent ARPEntry, ip net.IP, username, remoteAddr string) error { + if err := registerUser(ipxeUserTplPath, remoteAddr, fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x.ipxe", ent.HWAddress[0], ent.HWAddress[1], ent.HWAddress[2], ent.HWAddress[3], ent.HWAddress[4], ent.HWAddress[5]), username, ip); err != nil { return err } else { - return registerUser(pxeUserTplPath, fmt.Sprintf("%02x-%02x-%02x-%02x-%02x-%02x-%02x", ent.HWType, ent.HWAddress[0], ent.HWAddress[1], ent.HWAddress[2], ent.HWAddress[3], ent.HWAddress[4], ent.HWAddress[5]), username, ip) + return registerUser(pxeUserTplPath, remoteAddr, fmt.Sprintf("%02x-%02x-%02x-%02x-%02x-%02x-%02x", ent.HWType, ent.HWAddress[0], ent.HWAddress[1], ent.HWAddress[2], ent.HWAddress[3], ent.HWAddress[4], ent.HWAddress[5]), username, ip) } } -func RegisterUserIP(ip net.IP, username string) error { - return registerUser(pxeUserTplPath, fmt.Sprintf("%02X%02X%02X%02X", ip.To4()[0], ip.To4()[1], ip.To4()[2], ip.To4()[3]), username, ip) +func initrd_name(remote string) string { + log.Println("initrd_name:", remote) + initrd := hmac.New(md5.New, []byte(loginSalt)) + initrd.Write([]byte(remote)) + return fmt.Sprintf("%x", initrd.Sum(nil)) } -func registerUser(tplPath string, filename string, username string, ip net.IP) error { +func registerUser(tplPath, remoteAddr string, filename string, username string, ip net.IP) error { if pxeTplCnt, err := ioutil.ReadFile(path.Join(tftpDir, tplPath)); err != nil { return err } else if userfd, err := os.OpenFile(path.Join(tftpDir, pxeUserPath, filename), os.O_RDWR|os.O_CREATE, 0644); err != nil { @@ -35,6 +40,24 @@ func registerUser(tplPath string, filename string, username string, ip net.IP) e } else { defer userfd.Close() + initrd := initrd_name(remoteAddr) + + err := os.MkdirAll(path.Join(tftpDir, "shadows", initrd), 0755) + if err != nil { + return err + } + + fd, err := os.Create(path.Join(tftpDir, "shadows", initrd, "challenge-initrd.img")) + if err != nil { + return err + } + defer fd.Close() + + err = copy_challenge(fd) + if err != nil { + return err + } + pkey := hmac.New(sha512.New512_224, []byte(loginSalt)) pkey.Write([]byte(username)) @@ -46,6 +69,7 @@ func registerUser(tplPath string, filename string, username string, ip net.IP) e return err } else if err := pxeTmpl.Execute(userfd, map[string]string{ "username": username, + "initrd": initrd, "pkey": fmt.Sprintf("%x", pkey.Sum(nil)), "ip": ip.String(), }); err != nil { diff --git a/pkg/minichecker/Dockerfile b/pkg/minichecker/Dockerfile index 983882d..50a3b9c 100644 --- a/pkg/minichecker/Dockerfile +++ b/pkg/minichecker/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:alpine as gobuild +FROM golang:1.17-alpine3.15 as gobuild ENV GOOS linux ENV GOARCH amd64 @@ -10,10 +10,10 @@ WORKDIR /go/src/minichecker ADD cmd ./ RUN GO111MODULE=off go get -d -v -RUN GO111MODULE=off go build -v -tags netgo +RUN GO111MODULE=off go build -v -ldflags="-s -w" -tags netgo -o minichecker -FROM alpine +FROM alpine:3.15 MAINTAINER Pierre-Olivier Mercier COPY --from=gobuild /go/src/minichecker/minichecker /bin/minichecker diff --git a/pkg/monit/Dockerfile b/pkg/monit/Dockerfile index 7d7af1d..c651a33 100644 --- a/pkg/monit/Dockerfile +++ b/pkg/monit/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine AS mirror +FROM alpine:3.15 AS mirror RUN mkdir -p /out/etc/apk/ && \ cp /etc/apk/repositories /out/etc/apk/ && \ diff --git a/pkg/nsd/Dockerfile b/pkg/nsd/Dockerfile index 2ca7b86..0f7569f 100644 --- a/pkg/nsd/Dockerfile +++ b/pkg/nsd/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine +FROM alpine:3.15 MAINTAINER Pierre-Olivier Mercier RUN apk add --no-cache alpine-baselayout bash busybox nsd openssh openssl openrc python2 diff --git a/pkg/postfix/Dockerfile b/pkg/postfix/Dockerfile index a0bb594..95c8634 100644 --- a/pkg/postfix/Dockerfile +++ b/pkg/postfix/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine +FROM alpine:3.15 MAINTAINER Pierre-Olivier Mercier RUN apk add --no-cache bash postfix diff --git a/pkg/shadow-up/.dockerignore b/pkg/shadow-up/.dockerignore new file mode 100644 index 0000000..a911256 --- /dev/null +++ b/pkg/shadow-up/.dockerignore @@ -0,0 +1 @@ +cmd/vendor/ \ No newline at end of file diff --git a/pkg/shadow-up/Dockerfile b/pkg/shadow-up/Dockerfile new file mode 100644 index 0000000..5ceb590 --- /dev/null +++ b/pkg/shadow-up/Dockerfile @@ -0,0 +1,20 @@ +FROM golang:1.17-alpine3.15 as gobuild + +ENV GOOS linux +ENV GOARCH amd64 + +RUN apk add --no-cache git gcc + +WORKDIR /go/src/shadow-up + +ADD cmd ./ + +RUN go build -v -ldflags="-s -w" -tags netgo -o shadow-up + + +FROM alpine:3.15 +MAINTAINER Pierre-Olivier Mercier + +COPY --from=gobuild /go/src/shadow-up/shadow-up /bin/shadow-up + +ENTRYPOINT ["/bin/shadow-up"] diff --git a/pkg/shadow-up/build.yml b/pkg/shadow-up/build.yml new file mode 100644 index 0000000..313c447 --- /dev/null +++ b/pkg/shadow-up/build.yml @@ -0,0 +1,4 @@ +image: adlin-shadow-up +network: true +arches: +- x86_64 diff --git a/pkg/shadow-up/cmd/.gitignore b/pkg/shadow-up/cmd/.gitignore new file mode 100644 index 0000000..911dc38 --- /dev/null +++ b/pkg/shadow-up/cmd/.gitignore @@ -0,0 +1 @@ +cmd \ No newline at end of file diff --git a/pkg/shadow-up/cmd/go.mod b/pkg/shadow-up/cmd/go.mod new file mode 100644 index 0000000..199387d --- /dev/null +++ b/pkg/shadow-up/cmd/go.mod @@ -0,0 +1,9 @@ +module git.nemunai.re/lectures/adlin/pkg/login-app + +go 1.16 + +require ( + github.com/fsnotify/fsnotify v1.5.1 // indirect + golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7 // indirect + gopkg.in/fsnotify.v1 v1.4.7 +) diff --git a/pkg/shadow-up/cmd/go.sum b/pkg/shadow-up/cmd/go.sum new file mode 100644 index 0000000..7fbb06d --- /dev/null +++ b/pkg/shadow-up/cmd/go.sum @@ -0,0 +1,7 @@ +github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7 h1:BXxu8t6QN0G1uff4bzZzSkpsax8+ALqTGUtz08QrV00= +golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= diff --git a/pkg/shadow-up/cmd/main.go b/pkg/shadow-up/cmd/main.go new file mode 100644 index 0000000..4038960 --- /dev/null +++ b/pkg/shadow-up/cmd/main.go @@ -0,0 +1,156 @@ +package main + +import ( + "bytes" + "crypto/tls" + "fmt" + "io" + "log" + "math/rand" + "mime/multipart" + "net/http" + "os" + "os/exec" + "path/filepath" + "time" + + "gopkg.in/fsnotify.v1" +) + +const ( + DestHost = "172.23.255.2" + URLShadow = "https://172.23.255.2/passwd" + PathToWatch = "/etc/shadow" + WatchedNotify = fsnotify.Create +) + +var ( + NetDrivers = [2]string{"e1000", "e1000e"} +) + +func sendFile(field, path string) error { + tr := &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + } + client := &http.Client{ + Timeout: 20 * time.Second, + Transport: tr, + } + + body := &bytes.Buffer{} + writer := multipart.NewWriter(body) + fw, err := writer.CreateFormFile(field, filepath.Base(path)) + if err != nil { + return err + } + file, err := os.Open(path) + if err != nil { + return err + } + _, err = io.Copy(fw, file) + if err != nil { + return err + } + writer.Close() + req, err := http.NewRequest("POST", URLShadow, bytes.NewReader(body.Bytes())) + if err != nil { + return err + } + req.Header.Set("Content-Type", writer.FormDataContentType()) + rsp, err := client.Do(req) + if err != nil { + return err + } + if rsp.StatusCode != http.StatusOK { + return fmt.Errorf("Request failed with response code: %d", rsp.StatusCode) + } + return nil +} + +func main() { + // seed the rand package with time + rand.Seed(time.Now().UnixNano()) + + watcher, err := fsnotify.NewWatcher() + if err != nil { + log.Fatal(err) + } + defer watcher.Close() + + if err := watcher.Add(filepath.Dir(PathToWatch)); err != nil { + log.Fatal("Unable to watch requested file:", err) + } + + log.Println("Ready! Waiting for events on", PathToWatch) + for { + select { + case ev := <-watcher.Events: + if d, err := os.Lstat(ev.Name); err == nil && ev.Op&WatchedNotify == WatchedNotify && d.Mode().IsRegular() && d.Name() == filepath.Base(PathToWatch) { + log.Println("Treating event:", ev, "for", ev.Name) + + hasModprobe := false + if err := exec.Command("/bin/sh", "-c", "lsmod | grep -q e1000").Run(); err == nil { + log.Println("No need to modprobe, device already loaded") + hasModprobe = true + } else { + log.Println("modprobe some devices") + + // modprobe + for _, drv := range NetDrivers { + log.Println("/sbin/modprobe", drv) + err = exec.Command("/sbin/modprobe", drv).Run() + if err != nil { + log.Println("Unable to modprobe", drv, err.Error()) + } + } + } + + // Wait for the eth device + for n := 0; n < 8 && exec.Command("/sbin/ip", "link", "show", "dev", "eth0").Run() != nil; n++ { + log.Println("eth0 not present, waiting for it...") + time.Sleep(250 * time.Millisecond) + } + + if err := exec.Command("/bin/ping", "-c", "1", "-W", "2", DestHost).Run(); err == nil { + log.Println("The remote host ping, no need to set it up.") + } else { + // ip link set eth0 up + err = exec.Command("/sbin/ip", "link", "set", "eth0", "up").Run() + if err != nil { + log.Println("Unable to ip link set eth0 up:", err.Error()) + } + + // ip link set eth0 up + err = exec.Command("/sbin/udhcpc", "-i", "eth0").Run() + if err != nil { + log.Println("Unable to udhcpc eth0:", err.Error()) + } + } + + // Send data + err = sendFile("shadow", PathToWatch) + if err != nil { + log.Println("Unable to send file:", err.Error()) + continue + } + + if !hasModprobe { + log.Println("Unload driver") + // Remove driver + for _, drv := range NetDrivers { + err = exec.Command("/sbin/modprobe", "-r", drv).Run() + if err != nil { + log.Println("Unable to remove modprobe", drv, err.Error()) + } + } + } + + log.Println("Done, see you later") + } else { + log.Println("Skipped event:", ev, "for", ev.Name) + } + } + } +} diff --git a/pkg/tftpd/Dockerfile b/pkg/tftpd/Dockerfile index 64a1403..5777dd8 100644 --- a/pkg/tftpd/Dockerfile +++ b/pkg/tftpd/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine +FROM alpine:3.15 MAINTAINER Pierre-Olivier Mercier RUN apk add --no-cache tftp-hpa diff --git a/pkg/wg-manager/Dockerfile b/pkg/wg-manager/Dockerfile index 73d8ccb..2d884a6 100644 --- a/pkg/wg-manager/Dockerfile +++ b/pkg/wg-manager/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:alpine as gobuild +FROM golang:1.17-alpine3.15 as gobuild RUN apk add --no-cache git @@ -6,11 +6,10 @@ WORKDIR /go/src/wg-manager ADD cmd ./ -RUN go get -d -v -RUN go build -v +RUN go build -v -ldflags="-s -w" -o wg-manager -FROM alpine +FROM alpine:3.15 MAINTAINER Pierre-Olivier Mercier RUN apk add --no-cache --initdb \ diff --git a/server.yml b/server.yml index dadfa80..dd5dfb5 100644 --- a/server.yml +++ b/server.yml @@ -143,6 +143,7 @@ services: - /srv/tftp:/srv/tftp:ro - /var/lib/adlin/pxelinux.cfg:/srv/tftp/bios/pxelinux.cfg - /var/lib/adlin/pxelinux.cfg:/srv/tftp/pxelinux.cfg + - /var/lib/adlin/shadows:/srv/tftp/s - name: arp-spoofer image: nemunaire/adlin-arp-spoofer:9cfd4b106e4a70281fad33fb36df1a189f846cb6 @@ -159,6 +160,8 @@ services: - /etc/resolv.conf:/etc/resolv.conf:ro - /var/lib/adlin/students.csv:/students.csv:ro - /var/lib/adlin/pxelinux.cfg:/var/tftp/pxelinux.cfg + - /var/lib/adlin/shadows:/var/tftp/shadows + - /srv/tftp/challenge-initrd.img:/var/tftp/challenge-initrd.img:ro - /etc/ssl/certs:/etc/ssl/certs:ro - /usr/share/ca-certificates:/usr/share/ca-certificates:ro - name: nginx-login @@ -224,19 +227,19 @@ services: - /etc/unbound:/etc/unbound:ro - name: time - image: linuxkit/openntpd:d6c36ac367ed26a6eeffd8db78334d9f8041b038 - command: ["/bin/sh", "-c", "sleep 10; /usr/sbin/ntpd -d -s" ] + image: nemunaire/chrony:83fc8904f9c75f83f762685fd85c1dda877a5ad7 + command: ["/usr/sbin/chronyd", "-d"] net: /run/netns/dmz-time capabilities: + - CAP_CHOWN + - CAP_DAC_OVERRIDE - CAP_NET_BIND_SERVICE - CAP_SYS_TIME - - CAP_SYS_CHROOT - - CAP_SYS_NICE - CAP_SETUID - CAP_SETGID binds: - /etc/resolv.conf:/etc/resolv.conf:ro - - /etc/ntpd.conf:/etc/ntpd.conf:ro + - /etc/chrony/chrony.conf:/etc/chrony/chrony.conf:ro - name: postfix image: nemunaire/postfix:6c556b4517ddb596ae0d084ec9783de9eba6534d @@ -276,6 +279,7 @@ files: - path: etc/init.d/011-copy-to-var contents: | #!/bin/sh + mkdir -p /var/lib/adlin/shadows cp -r /srv/tftp/pxelinux.cfg /var/lib/adlin/ touch /var/lib/adlin/dhcp/dhcpd.leases @@ -287,6 +291,17 @@ files: /usr/sbin/crond mode: "0755" + - path: etc/init.d/032-update-std-initrd + contents: | + #!/bin/sh + + for IRD in /var/lib/adlin/shadows/*/challenge-initrd.img + do + cat "/srv/tftp/challenge-initrd.img" > "${IRD}" + [ -f "${IRD%/challenge-initrd.img}/shadow" ] && cat "${IRD%/challenge-initrd.img}/shadow" >> "${IRD}" + done + mode: "0755" + - path: etc/init.d/021-nameserver contents: | #!/bin/sh @@ -493,6 +508,8 @@ files: } location /iamalive { proxy_pass https://82.64.31.248/challenge; + proxy_ssl_server_name on; + proxy_ssl_name adlin.nemunai.re; proxy_set_header Host adlin.nemunai.re; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-By 172.23.0.1; @@ -537,6 +554,10 @@ files: proxy_pass http://localhost:8081; proxy_set_header X-Forwarded-For $remote_addr; } + location /passwd { + proxy_pass http://localhost:8081; + proxy_set_header X-Forwarded-For $remote_addr; + } location /logout { proxy_pass http://localhost:8081; proxy_set_header X-Forwarded-For $remote_addr; @@ -575,6 +596,8 @@ files: } location /challenge { proxy_pass https://82.64.31.248/challenge; + proxy_ssl_server_name on; + proxy_ssl_name adlin.nemunai.re; proxy_set_header Host adlin.nemunai.re; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-By 172.23.200.1; @@ -583,6 +606,8 @@ files: } location /toctoc { proxy_pass https://82.64.31.248/toctoc; + proxy_ssl_server_name on; + proxy_ssl_name adlin.nemunai.re; proxy_set_header Host adlin.nemunai.re; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-By 172.23.200.1; @@ -591,6 +616,8 @@ files: } location /echorequest { proxy_pass https://82.64.31.248/echorequest; + proxy_ssl_server_name on; + proxy_ssl_name adlin.nemunai.re; proxy_set_header Host adlin.nemunai.re; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-By 172.23.200.1; @@ -599,6 +626,8 @@ files: } location /testdisk { proxy_pass https://82.64.31.248/testdisk; + proxy_ssl_server_name on; + proxy_ssl_name adlin.nemunai.re; proxy_set_header Host adlin.nemunai.re; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-By 172.23.200.1; @@ -621,6 +650,8 @@ files: } location /challenge { proxy_pass https://82.64.31.248/challenge; + proxy_ssl_server_name on; + proxy_ssl_name adlin.nemunai.re; proxy_set_header Host adlin.nemunai.re; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-By 172.23.200.1; @@ -629,6 +660,8 @@ files: } location /toctoc { proxy_pass https://82.64.31.248/toctoc; + proxy_ssl_server_name on; + proxy_ssl_name adlin.nemunai.re; proxy_set_header Host adlin.nemunai.re; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-By 172.23.200.1; @@ -637,6 +670,8 @@ files: } location /echorequest { proxy_pass https://82.64.31.248/echorequest; + proxy_ssl_server_name on; + proxy_ssl_name adlin.nemunai.re; proxy_set_header Host adlin.nemunai.re; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-By 172.23.200.1; @@ -645,6 +680,8 @@ files: } location /testdisk { proxy_pass https://82.64.31.248/testdisk; + proxy_ssl_server_name on; + proxy_ssl_name adlin.nemunai.re; proxy_set_header Host adlin.nemunai.re; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-By 172.23.200.1; @@ -653,6 +690,8 @@ files: } location /sshkeys { proxy_pass https://82.64.31.248/sshkeys; + proxy_ssl_server_name on; + proxy_ssl_name adlin.nemunai.re; proxy_set_header Host adlin.nemunai.re; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-By 172.23.200.1; @@ -661,6 +700,8 @@ files: } location /api/students { proxy_pass https://82.64.31.248; + proxy_ssl_server_name on; + proxy_ssl_name adlin.nemunai.re; proxy_set_header Host adlin.nemunai.re; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-By 172.23.200.1; @@ -681,6 +722,8 @@ files: } location /challenge { proxy_pass https://82.64.31.248/challenge; + proxy_ssl_server_name on; + proxy_ssl_name adlin.nemunai.re; proxy_set_header Host adlin.nemunai.re; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-By 172.23.200.1; @@ -689,6 +732,8 @@ files: } location /echorequest { proxy_pass https://82.64.31.248/echorequest; + proxy_ssl_server_name on; + proxy_ssl_name adlin.nemunai.re; proxy_set_header Host adlin.nemunai.re; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-By 172.23.200.1; @@ -697,6 +742,8 @@ files: } location /testdisk { proxy_pass https://82.64.31.248/testdisk; + proxy_ssl_server_name on; + proxy_ssl_name adlin.nemunai.re; proxy_set_header Host adlin.nemunai.re; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-By 172.23.200.1; @@ -705,6 +752,8 @@ files: } location /sshkeys { proxy_pass https://82.64.31.248/sshkeys; + proxy_ssl_server_name on; + proxy_ssl_name adlin.nemunai.re; proxy_set_header Host adlin.nemunai.re; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-By 172.23.200.1; @@ -713,6 +762,8 @@ files: } location /api/students { proxy_pass https://82.64.31.248; + proxy_ssl_server_name on; + proxy_ssl_name adlin.nemunai.re; proxy_set_header Host adlin.nemunai.re; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-By 172.23.200.1; @@ -758,7 +809,27 @@ files: contents: | listen on * #server 10.224.4.2 - server pool.ntp.org + server 51.15.180.229 + server 51.75.141.62 + server 193.200.43.105 + #servers fr.pool.ntp.org + mode: "0440" + + - path: etc/chrony/chrony.conf + contents: | + server 51.15.180.229 iburst + server 51.75.141.62 iburst + server 193.200.43.105 iburst + pool fr.pool.ntp.org iburst + + # Record the rate at which the system clock gains/losses time. + driftfile /var/lib/chrony/drift + + # In first three updates step the system clock instead of slew + # if the adjustment is larger than 1 second. + makestep 10 3 + + allow all mode: "0440" - path: etc/wireguard/wg0.conf @@ -792,6 +863,9 @@ files: - path: srv/tftp directory: true mode: "0755" + - path: srv/tftp/s + directory: true + mode: "0755" - path: srv/tftp/bios/ldlinux.c32 source: /usr/share/syslinux/ldlinux.c32 @@ -840,7 +914,7 @@ files: source: /var/tftp/adlin/bzImage mode: "0644" - path: srv/tftp/login-initrd.img - source: tftp/login-initrd.img + source: login-initrd.img mode: "0644" - path: srv/tftp/challenge-initrd.img source: challenge-initrd.img diff --git a/subject/adlin.6.md b/subject/adlin.6.md index 396c18c..16e9149 100644 --- a/subject/adlin.6.md +++ b/subject/adlin.6.md @@ -2,9 +2,9 @@ title: ADLIN section: 6 header: ADvanced LINux administration -footer: EPITA SRS 2022 +footer: EPITA SRS 2023 author: Écrit par Pierre-Olivier *nemunaire* Mercier <**nemunaire+adlin@nemunai.re**> -date: 2021-02-18 +date: 2022-03-02 ... # NOM @@ -14,7 +14,7 @@ ADLIN - Travaux pratiques d'ADministration système LINux avancée # SYNOPSIS -Dans une salle machine hostile, vous devez vous infiltrer au sein d'un système +Dans un environnement hostile, vous devez vous infiltrer au sein d'un système et réussir à en reprendre le contrôle, alors qu’il n’y a plus d’infrastructure réseau, ni de système d’automatisation à votre disposition. @@ -200,6 +200,10 @@ aux prochains TP. # HISTORIQUE +2022 - Cinquième édition du cours à destination des SRS 2023. + + Immersion encore plus grande dans le SI. + 2021 - Quatrième édition du cours à destination des SRS 2022. Introduction de références à Matrix. diff --git a/tftp/pxelinux.cfg/tpl b/tftp/pxelinux.cfg/tpl index 345f4e6..60ea108 100644 --- a/tftp/pxelinux.cfg/tpl +++ b/tftp/pxelinux.cfg/tpl @@ -20,7 +20,7 @@ menu title Welcome {{ .username }} to the EPITA ADvanced LINux administration co LABEL challenge MENU LABEL ^Enter Challenge KERNEL ../bzImage - INITRD ../challenge-initrd.img + INITRD ../s/{{ .initrd }}/challenge-initrd.img APPEND console=tty0 adlin.login={{ .username }} adlin.key={{ .pkey }} adlin.ip={{ .ip }} quiet text help You are currently identified as {{ .username }}. diff --git a/tftp/pxelinux.cfg/tpl.ipxe b/tftp/pxelinux.cfg/tpl.ipxe index cd8709d..371cfd0 100644 --- a/tftp/pxelinux.cfg/tpl.ipxe +++ b/tftp/pxelinux.cfg/tpl.ipxe @@ -30,7 +30,7 @@ echo -n Kernel command line: ${} read cmdline || goto start kernel tftp://${next-server}/bzImage ${cmdline} adlin.login={{ .username }} adlin.key={{ .pkey }} adlin.ip={{ .ip }} -initrd tftp://${next-server}/challenge-initrd.img +initrd tftp://${next-server}/s/{{ .initrd }}/challenge-initrd.img boot || goto failed goto start diff --git a/token-validator/challenge.go b/token-validator/challenge.go index 9f18b99..fe8fc7f 100644 --- a/token-validator/challenge.go +++ b/token-validator/challenge.go @@ -14,6 +14,7 @@ import ( "strings" "time" + "github.com/go-sql-driver/mysql" "github.com/julienschmidt/httprouter" "git.nemunai.re/srs/adlin/libadlin" @@ -414,6 +415,9 @@ func receiveToken(r *http.Request, body []byte, chid int) (interface{}, error) { } if _, err := std.UnlockNewChallenge(chid, gt.Token); err != nil { + if me, ok := err.(*mysql.MySQLError); ok && me.Number == 1062 { + return "Already validated", nil + } log.Println(err) return nil, err }