commit 9212febae27085d39f0090b51030dc9697d5a2f0 Author: Phil Bajsicki Date: Sat May 18 11:58:13 2024 +0200 Redacting 2024.05.18 diff --git a/README.org b/README.org new file mode 100644 index 0000000..3d550b0 --- /dev/null +++ b/README.org @@ -0,0 +1,183 @@ +#+title: Readme +#+author: Phil Bajsicki +#+options: finline toc:nil + +* Intro +This is a coding task from [redacted], which I found +rather fun to tinker with. + +This is an org-mode file. The code blocks are tangled using =org-babel= into =cl-secninja.lisp=. + +* Dependencies: +- curl +- sbcl with quicklisp +* Usage: +1. Load in SBCL with ~sbcl --load cl-secninja.lisp~. +2. Run ~(four)~ +3. Copy the base64 encrypted message into a file called =email=. +4. Run ~(base64)~. +5. Done. +* Code: +** Quicklisp: +#+begin_src lisp :tangle cl-secninja.lisp +(ql:quickload '(:cl-ppcre + :cl-base64 + :ironclad + :jsown)) +#+end_src + +** Defpackage and in-package +#+begin_src lisp :tangle cl-secninja.lisp +(defpackage #:cl-secninja + (:use #:common-lisp #:cl #:uiop #:cl-ppcre #:ironclad #:cl-base64)) + +(in-package #:cl-secninja) +#+end_src + +** URL var +The trailing slash is important for consolidating the URL later. +#+begin_src lisp :tangle cl-secninja.lisp +(defvar *url* "redacted") +#+end_src +** Run cURL +#+begin_src lisp :tangle cl-secninja.lisp +(defun run-curl (command) + (let* ((curl-command (concatenate 'string "curl -i " command)) + (result (uiop:run-program curl-command + :output :string + :error-output T))) + result)) + +#+end_src + +** First page +Grab first page, print out the command and result, and return the parameter string. +#+begin_src lisp :tangle cl-secninja.lisp +(defun one () + (let* ((command *url*) + (result (run-curl *url*))) + (format t "~%COMMAND: curl ~a" command) + (format t "~%RESULT: curl ~a" result) + (car (ppcre:all-matches-as-strings "\\?.*" result)))) +#+end_src +** Second page +This function calls ~(one)~, so calling it directly for seeing the second page +works. + +Concatenate the URL with the parameter string from the first function, and grab +and return the second page. + +#+begin_src lisp :tangle cl-secninja.lisp +(defun two () + (let* ((command (concatenate 'string + "\"" *url* (one) "\"")) + (result (run-curl command))) + result)) +#+end_src +** Third +This is where we get interesting. This function calls ~(two)~, which returns the +second page for processing, and then calls ~(run-curl)~ on the command it +constructs, and returns the output. + + +I wanted to see what the values of the variables are while testing, thus the +print statements and triple let. I know I could consolidate that, but I feel +like this way is more transparent than having a ~(let* (...))~ that does +everything in the background. + +The thing that was most tricky here was getting the double quotes to work +properly between this function and ~(run-curl)~, because the =command= string is +being passed around, and it itself includes quotes. + + + +#+begin_src lisp :tangle cl-secninja.lisp +(defun three () + (let ((headers (ppcre:all-matches-as-strings "X-.*" (two)))) + (print headers) + (print (car headers)) + (print (cadr headers)) + (let ((command (concatenate 'string + "\"" *url* "\?step=2" "\"" + " -H \"" (car headers) "\"" + " -H \"" (cadr headers) "\""))) + (let ((result (run-curl command))) + (format t "~%RESULT: curl ~a" result) + result)))) + +#+end_src +** Four +This was the most fun one, given all the processing. I can't say that the loop +worked the first time around. + +After running ~(four)~, your terminal will print out the base64 encoded string. +I can't say I want to mess with extracting the base64 string with another +regexp, so I just manually copied the string into a file called =email=. + +Then... + +#+begin_src lisp :tangle cl-secninja.lisp + +(defun four () + (let* + ((data (three)) + (input + (car (ppcre:all-matches-as-strings "(?sm)\{.*}$" data))) + (challenge + (string-left-trim "challenge: " (car (ppcre:all-matches-as-strings "challenge:(.*)" data)))) + (timestamp + (string-left-trim "timestamp: " (car (ppcre:all-matches-as-strings "timestamp:(.*)" data)))) + (sorted (sort (cdr (jsown:parse input)) #'string<= :key #'first)) + (connected + (string-right-trim "\&" + (format nil "~{~A~}" + (loop + for item in sorted + collect + (concatenate 'string (car item) "\=" (cdr item) "\&"))))) + (hash (sha-256 connected)) + (command + (string-right-trim "\-" + (concatenate 'string + "-X POST \"" *url* "\?step=3" "\"" + " -H \"Content-Type: application/x-www-form-urlencoded\" " + " -d \"challenge=" challenge "\"" + " -d \"timestamp=" timestamp "\"" + " -d \"hash=" hash "\"" + )))) + (terpri) + (print challenge) + (print timestamp) + (print hash) + (terpri) + (format t "~%COMMAND: curl ~a" command) + (terpri) + (let ((result (run-curl command))) + (format t "~%RESULT: curl ~a" result)) + (terpri))) + +#+end_src + +*** Sha256 +Util function for the above code. +#+begin_src lisp :tangle cl-secninja.lisp +(defun sha-256 (str) + (ironclad:byte-array-to-hex-string + (ironclad:digest-sequence :sha256 + (ironclad:ascii-string-to-byte-array str)))) + +#+end_src +** Base64 +Put the contents of the file into a variable. +#+begin_src lisp :tangle cl-secninja.lisp +(defvar *email* (alexandria:read-file-into-string "email")) +#+end_src +Then, run the base64 decoder over it until the string can't be decoded any more. +#+begin_src lisp :tangle cl-secninja.lisp +(defun base64 () + (let ((email *email*)) + (loop repeat 100 do + (if (ppcre:scan "@" email) + (print email) + (setf email (cl-base64:base64-string-to-string email)))))) +#+end_src diff --git a/cl-secninja.lisp b/cl-secninja.lisp new file mode 100644 index 0000000..31bbd8b --- /dev/null +++ b/cl-secninja.lisp @@ -0,0 +1,96 @@ +(ql:quickload '(:cl-ppcre + :cl-base64 + :ironclad + :jsown)) + +(defpackage #:cl-secninja + (:use #:common-lisp #:cl #:uiop #:cl-ppcre #:ironclad #:cl-base64)) + +(in-package #:cl-secninja) + +(defvar *url* "redacted") + +(defun run-curl (command) + (let* ((curl-command (concatenate 'string "curl -i " command)) + (result (uiop:run-program curl-command + :output :string + :error-output T))) + result)) + +(defun one () + (let* ((command *url*) + (result (run-curl *url*))) + (format t "~%COMMAND: curl ~a" command) + (format t "~%RESULT: curl ~a" result) + (car (ppcre:all-matches-as-strings "\\?.*" result)))) + +(defun two () + (let* ((command (concatenate 'string + "\"" *url* (one) "\"")) + (result (run-curl command))) + result)) + +(defun three () + (let ((headers (ppcre:all-matches-as-strings "X-.*" (two)))) + (print headers) + (print (car headers)) + (print (cadr headers)) + (let ((command (concatenate 'string + "\"" *url* "\?step=2" "\"" + " -H \"" (car headers) "\"" + " -H \"" (cadr headers) "\""))) + (let ((result (run-curl command))) + (format t "~%RESULT: curl ~a" result) + result)))) + +(defun four () + (let* + ((data (three)) + (input + (car (ppcre:all-matches-as-strings "(?sm)\{.*}$" data))) + (challenge + (string-left-trim "challenge: " (car (ppcre:all-matches-as-strings "challenge:(.*)" data)))) + (timestamp + (string-left-trim "timestamp: " (car (ppcre:all-matches-as-strings "timestamp:(.*)" data)))) + (sorted (sort (cdr (jsown:parse input)) #'string<= :key #'first)) + (connected + (string-right-trim "\&" + (format nil "~{~A~}" + (loop + for item in sorted + collect + (concatenate 'string (car item) "\=" (cdr item) "\&"))))) + (hash (sha-256 connected)) + (command + (string-right-trim "\-" + (concatenate 'string + "-X POST \"" *url* "\?step=3" "\"" + " -H \"Content-Type: application/x-www-form-urlencoded\" " + " -d \"challenge=" challenge "\"" + " -d \"timestamp=" timestamp "\"" + " -d \"hash=" hash "\"" + )))) + (terpri) + (print challenge) + (print timestamp) + (print hash) + (terpri) + (format t "~%COMMAND: curl ~a" command) + (terpri) + (let ((result (run-curl command))) + (format t "~%RESULT: curl ~a" result)) + (terpri))) + +(defun sha-256 (str) + (ironclad:byte-array-to-hex-string + (ironclad:digest-sequence :sha256 + (ironclad:ascii-string-to-byte-array str)))) + +(defvar *email* (alexandria:read-file-into-string "email")) + +(defun base64 () + (let ((email *email*)) + (loop repeat 100 do + (if (ppcre:scan "@" email) + (print email) + (setf email (cl-base64:base64-string-to-string email))))))