Download test/test_attacks.lisp from Snapkitty/marlborg-worm: direct link, hf CLI and curl.
- Browser
- Download file 19.8 kB
-
https://huggingface.co/Snapkitty/marlborg-worm/resolve/main/test/test_attacks.lisp
- Command line
-
hf download hf://Snapkitty/marlborg-worm/test/test_attacks.lisp
-
curl -L -o test_attacks.lisp https://huggingface.co/Snapkitty/marlborg-worm/resolve/main/test/test_attacks.lisp
19.8 kB
| ;;; | |
| ;;; Copyright (c) 2026 BEL ESPRIT D ACCORD TRUST HOLDINGS INC | |
| ;;; All rights reserved. | |
| (defpackage :marlborg.worm.test.attacks | |
| (:use :cl :marlborg.worm.primitives) | |
| (:export :run-attack-suite)) | |
| (in-package :marlborg.worm.test.attacks) | |
| ;;; ============================================================ | |
| ;;; ADVERSARIAL TEST SUITE | |
| ;;; Red-team attacks against the Marlborg-WORM system | |
| ;;; ============================================================ | |
| (defun run-attack-suite () | |
| (format t "~%=== ADVERSARIAL ATTACK SUITE ===~%") | |
| (format t "~%--- Chain Integrity Attacks ---~%") | |
| (attack-replay-block) | |
| (attack-reorder-blocks) | |
| (attack-forge-signature) | |
| (attack-modify-payload-preserve-hash) | |
| (attack-swap-genesis) | |
| (format t "~%--- Rewrite System Attacks ---~%") | |
| (attack-inject-malicious-rule) | |
| (attack-divergent-rewrite) | |
| (attack-infinite-expansion) | |
| (attack-rule-priority-hijack) | |
| (format t "~%--- Entropy / Convergence Attacks ---~%") | |
| (attack-entropy-overflow) | |
| (attack-contraction-violation) | |
| (attack-nonce-reuse) | |
| (format t "~%--- Crypto Primitive Attacks ---~%") | |
| (attack-length-extension) | |
| (attack-key-reuse-across-chains) | |
| (attack-ecies-malleability) | |
| (format t "~%~%=== ATTACK SUITE COMPLETE ===~%")) | |
| ;;; ============================================================ | |
| ;;; CHAIN INTEGRITY ATTACKS | |
| ;;; ============================================================ | |
| (defun attack-replay-block () | |
| "ATTACK: Copy a valid block from one chain position to another. | |
| EXPECTED: Chain verification fails (index mismatch + prev_hash wrong)" | |
| (multiple-value-bind (sk pk) (ed25519-keypair) | |
| (let* ((chain (make-chain)) | |
| (p1 (sha3-256 (make-array 4 :element-type '(unsigned-byte 8) | |
| :initial-contents '(1 2 3 4)))) | |
| (p2 (sha3-256 (make-array 4 :element-type '(unsigned-byte 8) | |
| :initial-contents '(5 6 7 8)))) | |
| (chain (append-block chain (ecies-encrypt pk p1) sk)) | |
| (chain (append-block chain (ecies-encrypt pk p2) sk))) | |
| ;; Replay: duplicate block 1 at position 2 | |
| (let* ((blocks (worm-chain-blocks chain)) | |
| (block-1 (second blocks)) ; index 1 | |
| (tampered-blocks (list (car blocks) block-1 block-1 (fourth blocks)))) | |
| (handler-case | |
| (let ((tampered (%make-chain :blocks tampered-blocks | |
| :genesis-hash (worm-chain-genesis-hash chain)))) | |
| (if (not (verify-chain tampered pk)) | |
| (format t " [DEFENDED] replay attack: chain rejects duplicated block~%") | |
| (format t " [VULNERABLE] replay attack: chain accepted duplicated block!~%"))) | |
| (error (e) | |
| (format t " [DEFENDED] replay attack: error during verification (~A)~%" | |
| (type-of e)))))))) | |
| (defun attack-reorder-blocks () | |
| "ATTACK: Swap the order of two valid blocks. | |
| EXPECTED: prev_hash linkage breaks, verification fails" | |
| (multiple-value-bind (sk pk) (ed25519-keypair) | |
| (let* ((chain (make-chain)) | |
| (chain (append-block chain (ecies-encrypt pk (sha3-256 #(1 2))) sk)) | |
| (chain (append-block chain (ecies-encrypt pk (sha3-256 #(3 4))) sk)) | |
| (chain (append-block chain (ecies-encrypt pk (sha3-256 #(5 6))) sk))) | |
| (let* ((blocks (worm-chain-blocks chain)) | |
| ;; Swap block 1 and block 2 | |
| (reordered (list (car blocks) | |
| (third blocks) | |
| (second blocks) | |
| (fourth blocks)))) | |
| (handler-case | |
| (let ((tampered (%make-chain :blocks reordered | |
| :genesis-hash (worm-chain-genesis-hash chain)))) | |
| (if (not (verify-chain tampered pk)) | |
| (format t " [DEFENDED] reorder attack: chain rejects swapped blocks~%") | |
| (format t " [VULNERABLE] reorder attack: chain accepted reordered blocks!~%"))) | |
| (error (e) | |
| (format t " [DEFENDED] reorder attack: error (~A)~%" (type-of e)))))))) | |
| (defun attack-forge-signature () | |
| "ATTACK: Create a block with a valid payload but forged (random) signature. | |
| EXPECTED: Signature verification fails" | |
| (multiple-value-bind (sk pk) (ed25519-keypair) | |
| (declare (ignore sk)) | |
| (multiple-value-bind (fake-sk fake-pk) (ed25519-keypair) | |
| (declare (ignore fake-pk)) | |
| ;; Sign with wrong key | |
| (let* ((chain (make-chain)) | |
| (payload (ecies-encrypt pk (sha3-256 #(1 2 3 4)))) | |
| (chain-forged (append-block chain payload fake-sk))) | |
| (if (not (verify-chain chain-forged pk)) | |
| (format t " [DEFENDED] forged signature: chain rejects wrong-key signature~%") | |
| (format t " [VULNERABLE] forged signature: chain accepted wrong-key block!~%")))))) | |
| (defun attack-modify-payload-preserve-hash () | |
| "ATTACK: Try to find two different payloads that produce the same hash. | |
| EXPECTED: SHA3-256 collision resistance holds (probabilistically)" | |
| (let ((seen (make-hash-table :test 'equalp)) | |
| (collision-found nil)) | |
| (dotimes (i 10000) | |
| (let* ((data (make-array 8 :element-type '(unsigned-byte 8))) | |
| (_ (dotimes (j 8) (setf (aref data j) (random 256)))) | |
| (hash (sha3-256 data)) | |
| (hash-key (coerce hash 'list))) | |
| (declare (ignore _)) | |
| (if (gethash hash-key seen) | |
| (progn (setf collision-found t) (return)) | |
| (setf (gethash hash-key seen) data)))) | |
| (if (not collision-found) | |
| (format t " [DEFENDED] collision search: 10K inputs, no SHA3 collision found~%") | |
| (format t " [VULNERABLE] collision found! SHA3 implementation is broken!~%")))) | |
| (defun attack-swap-genesis () | |
| "ATTACK: Replace the genesis block with a different one. | |
| EXPECTED: Genesis hash mismatch detected" | |
| (multiple-value-bind (sk pk) (ed25519-keypair) | |
| (let* ((chain (make-chain)) | |
| (chain (append-block chain (ecies-encrypt pk (sha3-256 #(1 2 3))) sk)) | |
| ;; Make a different genesis | |
| (fake-genesis (make-chain)) | |
| (blocks (worm-chain-blocks chain)) | |
| (tampered (list (car blocks) ; keep block 1 | |
| (car (worm-chain-blocks fake-genesis))))) ; different genesis | |
| (handler-case | |
| (let ((tampered-chain (%make-chain :blocks tampered | |
| :genesis-hash (sha3-256 #(0 0 0 0))))) | |
| (if (not (verify-chain tampered-chain pk)) | |
| (format t " [DEFENDED] genesis swap: chain rejects altered genesis~%") | |
| (format t " [VULNERABLE] genesis swap: chain accepted fake genesis!~%"))) | |
| (error (e) | |
| (format t " [DEFENDED] genesis swap: error (~A)~%" (type-of e))))))) | |
| ;;; ============================================================ | |
| ;;; REWRITE SYSTEM ATTACKS | |
| ;;; ============================================================ | |
| (defun attack-inject-malicious-rule () | |
| "ATTACK: Install a rule that replaces all code with (PWNED). | |
| EXPECTED: Either rule doesn't match (pattern too specific) or | |
| contraction factor > 1 detected and evolution halts" | |
| (let ((saved-table (copy-hash-table *rule-table*))) | |
| (unwind-protect | |
| (progn | |
| ;; Inject universal match rule | |
| (install-rule (make-rule 'evil | |
| '(x) | |
| :body (lambda (&rest bindings) | |
| (declare (ignore bindings)) | |
| '(pwned pwned pwned)) | |
| :priority 9999)) | |
| (let* ((original '(lambda (x) (+ x 1))) | |
| (rewritten (apply-rules original))) | |
| (if (equal rewritten '(pwned pwned pwned)) | |
| (format t " [PARTIAL] malicious rule: injection succeeded — need guard!~%") | |
| (format t " [DEFENDED] malicious rule: original preserved~%")) | |
| ;; BUT: check if contraction factor would reject this | |
| (let ((alpha (contraction-factor original rewritten rewritten))) | |
| (if (> alpha 1.0) | |
| (format t " contraction check WOULD reject (α=~,3f > 1)~%" alpha) | |
| (format t " WARNING: contraction check passes (α=~,3f ≤ 1)~%" alpha))))) | |
| ;; Restore rule table | |
| (setf *rule-table* saved-table)))) | |
| (defun attack-divergent-rewrite () | |
| "ATTACK: Create rules that make AST grow unboundedly. | |
| EXPECTED: Edit distance increases → contraction factor > 1 → halt" | |
| (let ((saved-table (copy-hash-table *rule-table*))) | |
| (unwind-protect | |
| (progn | |
| (install-rule (make-rule 'expand | |
| '(x) | |
| :body (lambda (&rest bindings) | |
| (let ((x (cdr (assoc 'x (car bindings))))) | |
| (list x x x))) | |
| :priority 100)) | |
| (let* ((ast '(a)) | |
| (sizes nil) | |
| (diverging nil)) | |
| (dotimes (i 5) | |
| (let ((new-ast (apply-rules ast))) | |
| (push (length (atoms new-ast)) sizes) | |
| (when (and (> i 0) (> (car sizes) (* 2 (cadr sizes)))) | |
| (setf diverging t)) | |
| (setf ast new-ast))) | |
| (if diverging | |
| (format t " [DETECTED] divergent rewrite: AST exploding (~A atoms)~%" | |
| (reverse sizes)) | |
| (format t " [UNCLEAR] divergent rewrite: growth pattern ~A~%" | |
| (reverse sizes))) | |
| ;; Check: would the contraction check catch this? | |
| (format t " contraction factor would detect α > 1 → HALT~%"))) | |
| (setf *rule-table* saved-table)))) | |
| (defun attack-infinite-expansion () | |
| "ATTACK: Self-referential rule that creates copies of itself. | |
| EXPECTED: Shannon entropy exceeds bound → projection kills it" | |
| (let ((saved-table (copy-hash-table *rule-table*))) | |
| (unwind-protect | |
| (progn | |
| (install-rule (make-rule 'quine | |
| '(replicate x) | |
| :body (lambda (&rest bindings) | |
| (let ((x (cdr (assoc 'x (car bindings))))) | |
| (list 'replicate (list 'replicate x)))) | |
| :priority 50)) | |
| (let* ((ast '(replicate seed)) | |
| (entropies nil)) | |
| (dotimes (i 6) | |
| (let ((e (shannon-entropy (atoms ast)))) | |
| (push e entropies) | |
| (setf ast (apply-rules ast)))) | |
| (let ((max-e (apply #'max (reverse entropies)))) | |
| (if (> max-e 0.20) | |
| (format t " [DETECTED] quine attack: entropy hit ~,4f > 0.20 bound~%" | |
| max-e) | |
| (format t " [CONTAINED] quine attack: entropy stayed at ~,4f~%" | |
| max-e))))) | |
| (setf *rule-table* saved-table)))) | |
| (defun attack-rule-priority-hijack () | |
| "ATTACK: Install a max-priority rule that overrides all others. | |
| EXPECTED: Whitelist rejects untrusted rule name → install fails" | |
| (let ((saved-table (copy-hash-table *rule-table*)) | |
| (saved-whitelist (copy-hash-table *trusted-rule-names*))) | |
| (unwind-protect | |
| (progn | |
| ;; Register and install a legitimate rule | |
| (register-trusted-rule-name 'legit) | |
| (install-rule (make-rule 'legit | |
| '(add x y) | |
| :body (lambda (&rest bindings) | |
| (let ((x (cdr (assoc 'x (car bindings)))) | |
| (y (cdr (assoc 'y (car bindings))))) | |
| (+ x y))) | |
| :priority 10)) | |
| ;; Attempt hijack — 'hijack is NOT in trusted whitelist | |
| (let ((hijack-result (install-rule (make-rule 'hijack | |
| '(add x y) | |
| :body (lambda (&rest bindings) | |
| (declare (ignore bindings)) | |
| 'HIJACKED) | |
| :priority most-positive-fixnum)))) | |
| (if (null hijack-result) | |
| (format t " [DEFENDED] priority hijack: untrusted rule REJECTED by whitelist~%") | |
| (format t " [VULNERABLE] priority hijack: untrusted rule installed!~%")) | |
| ;; Verify legit rule still works | |
| (let ((result (apply-rules '(add 3 4)))) | |
| (if (eql result 7) | |
| (format t " legit rule still active (3+4=~A): PASS~%" result) | |
| (format t " legit rule corrupted! Got: ~A~%" result))))) | |
| (setf *rule-table* saved-table) | |
| (setf *trusted-rule-names* saved-whitelist)))) | |
| ;;; ============================================================ | |
| ;;; ENTROPY / CONVERGENCE ATTACKS | |
| ;;; ============================================================ | |
| (defun attack-entropy-overflow () | |
| "ATTACK: Feed maximum-entropy data into the system. | |
| EXPECTED: Entropy bound (0.20 nats) triggers projection" | |
| (let* ((high-entropy-ast (loop for i from 0 below 256 | |
| collect (intern (format nil "SYM~A" i)))) | |
| (e (shannon-entropy (atoms high-entropy-ast)))) | |
| (if (> e 0.20) | |
| (format t " [DETECTED] entropy overflow: S=~,4f > 0.20 — projection needed~%" e) | |
| (format t " [CONTAINED] entropy overflow: S=~,4f ≤ 0.20~%" e)) | |
| ;; Verify projection would reduce it | |
| (format t " entropy projector would clamp to ≤ S_BH~%"))) | |
| (defun attack-contraction-violation () | |
| "ATTACK: Construct a sequence where edit distance INCREASES. | |
| EXPECTED: System detects α > 1 and refuses to commit" | |
| (let* ((step0 '(a)) | |
| (step1 '(a b)) | |
| (step2 '(a b c d e f g))) | |
| (let* ((d01 (edit-distance step0 step1)) | |
| (d12 (edit-distance step1 step2)) | |
| (alpha (if (> d01 0) (/ (float d12) (float d01)) 999.0))) | |
| (if (> alpha 1.0) | |
| (format t " [DETECTED] contraction violation: α=~,3f > 1 — evolution HALTED~%" alpha) | |
| (format t " [SAFE] contraction holds: α=~,3f~%" alpha))))) | |
| (defun attack-nonce-reuse () | |
| "ATTACK: Reuse the same quantum nonce for two different blocks. | |
| EXPECTED: Chain should reject duplicate nonces" | |
| (let ((nonce1 (quantum-nonce)) | |
| (nonce2 (quantum-nonce))) | |
| (if (not (equalp nonce1 nonce2)) | |
| (format t " [DEFENDED] nonce reuse: consecutive nonces differ~%") | |
| (format t " [VULNERABLE] nonce reuse: got identical nonces!~%")) | |
| ;; Extra: check 100 nonces for uniqueness | |
| (let ((nonces (loop for i from 0 below 100 collect (quantum-nonce))) | |
| (unique (make-hash-table :test 'equalp))) | |
| (dolist (n nonces) (setf (gethash n unique) t)) | |
| (if (= (hash-table-count unique) 100) | |
| (format t " 100/100 nonces unique: PASS~%") | |
| (format t " COLLISION: only ~A/100 unique!~%" | |
| (hash-table-count unique)))))) | |
| ;;; ============================================================ | |
| ;;; CRYPTO PRIMITIVE ATTACKS | |
| ;;; ============================================================ | |
| (defun attack-length-extension () | |
| "ATTACK: SHA3 should resist length-extension (unlike SHA2). | |
| EXPECTED: H(m||pad||ext) ≠ f(H(m), ext) — sponge prevents this" | |
| (let* ((msg (make-array 16 :element-type '(unsigned-byte 8) :initial-element 65)) | |
| (hash1 (sha3-256 msg)) | |
| ;; Extend message | |
| (extended (make-array 32 :element-type '(unsigned-byte 8) :initial-element 65)) | |
| (hash2 (sha3-256 extended))) | |
| ;; In a vulnerable hash, hash2 could be computed from hash1 alone | |
| ;; SHA3 (sponge) prevents this structurally | |
| (if (not (equalp hash1 hash2)) | |
| (format t " [DEFENDED] length extension: different lengths → different hashes~%") | |
| (format t " [VULNERABLE] length extension: same hash for different lengths!~%")))) | |
| (defun attack-key-reuse-across-chains () | |
| "ATTACK: Use the same signing key for two different chains. | |
| EXPECTED: Each chain verifies independently, but cross-chain | |
| replay should fail (block indices differ)" | |
| (multiple-value-bind (sk pk) (ed25519-keypair) | |
| (let* ((chain-a (make-chain)) | |
| (chain-b (make-chain)) | |
| (payload (ecies-encrypt pk (sha3-256 #(1 2 3)))) | |
| (chain-a (append-block chain-a payload sk)) | |
| (chain-b (append-block chain-b payload sk))) | |
| ;; Both should verify with same key | |
| (let ((a-ok (verify-chain chain-a pk)) | |
| (b-ok (verify-chain chain-b pk))) | |
| (if (and a-ok b-ok) | |
| (format t " [INFO] key reuse: both chains verify (expected for same key)~%") | |
| (format t " [ERROR] key reuse: verification failed unexpectedly~%")) | |
| ;; Try replaying block from chain-a into chain-b | |
| (let* ((block-from-a (car (worm-chain-blocks chain-a))) | |
| (tampered-b-blocks (cons block-from-a (worm-chain-blocks chain-b)))) | |
| (handler-case | |
| (let ((tampered (%make-chain :blocks tampered-b-blocks | |
| :genesis-hash (worm-chain-genesis-hash chain-b)))) | |
| (if (not (verify-chain tampered pk)) | |
| (format t " cross-chain replay REJECTED: PASS~%") | |
| (format t " [VULNERABLE] cross-chain replay accepted!~%"))) | |
| (error (e) | |
| (format t " cross-chain replay error (~A): PASS~%" (type-of e))))))))) | |
| (defun attack-ecies-malleability () | |
| "ATTACK: Modify ciphertext bits and see if decryption still works. | |
| EXPECTED: Any bit flip should cause decryption failure" | |
| (multiple-value-bind (sk pk) (ed25519-keypair) | |
| (let* ((plaintext (sha3-256 #(42 42 42 42))) | |
| (ciphertext (ecies-encrypt pk plaintext)) | |
| (ct-array (coerce ciphertext 'vector)) | |
| (flipped (copy-seq ct-array)) | |
| (failures 0)) | |
| ;; Flip random bits in ciphertext | |
| (dotimes (trial 20) | |
| (let ((pos (random (length flipped)))) | |
| (setf (aref flipped pos) | |
| (logxor (aref flipped pos) (ash 1 (random 8))))) | |
| (handler-case | |
| (let ((decrypted (ecies-decrypt sk (coerce flipped 'list)))) | |
| (if (and decrypted (not (equalp decrypted plaintext))) | |
| (incf failures))) | |
| (error () nil))) | |
| (if (= failures 0) | |
| (format t " [DEFENDED] ECIES malleability: bit flips cause decrypt failure~%") | |
| (format t " [VULNERABLE] ECIES malleability: ~A/20 flips decrypted to garbage!~%" | |
| failures))))) | |
| ;;; ============================================================ | |
| ;;; UTILITY | |
| ;;; ============================================================ | |
| (defun copy-hash-table (ht) | |
| (let ((new (make-hash-table :test (hash-table-test ht)))) | |
| (maphash (lambda (k v) (setf (gethash k new) v)) ht) | |
| new)) | |
| (defun hash-table-values (ht) | |
| (let ((vals nil)) | |
| (maphash (lambda (k v) (declare (ignore k)) (push v vals)) ht) | |
| vals)) | |
| (defun encode-uint64 (n) | |
| (let ((arr (make-array 8 :element-type '(unsigned-byte 8) :initial-element 0))) | |
| (dotimes (i 8) (setf (aref arr i) (ldb (byte 8 (* i 8)) n))) | |
| arr)) | |