Skip to content
This repository has been archived by the owner on Jun 11, 2024. It is now read-only.

Commit

Permalink
rev/script-theory
Browse files Browse the repository at this point in the history
  • Loading branch information
Puhalenthi committed May 23, 2024
1 parent 11b23da commit f91fd75
Show file tree
Hide file tree
Showing 10 changed files with 225 additions and 0 deletions.
1 change: 1 addition & 0 deletions script-theory/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
libscript_theory_addon.node
8 changes: 8 additions & 0 deletions script-theory/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM rust:1.78-bullseye

WORKDIR /addon

COPY ./src/addon .

RUN cargo build --release && \
mv ./target/release/libscript_theory_addon.so ./libscript_theory_addon.node
21 changes: 21 additions & 0 deletions script-theory/chall.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Script Theory
categories:
- rev
value: 125
flag:
file: ./src/flag.txt
description: |-
I rewrote some of my code in Rust to make it run faster.
But where did my flag go?
deploy:
builder:
build: .
files:
- src: ./src/program.js
- src: ./output.txt
- src: /addon/libscript_theory_addon.node
dest: libscript_theory_addon.node
container: builder
authors:
- Puhalenthi
visible: true
1 change: 1 addition & 0 deletions script-theory/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Encoded: DZwOdRBBOBaBxZ7SdUHDqORNCSzNt2SkBDa5NH9xsGIGz8ufVijMgucC8fht
17 changes: 17 additions & 0 deletions script-theory/src/addon/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "script-theory-addon"
version = "1.0.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
chacha20 = "0.9.1"
rand = "0.8.5"
rand_chacha = "0.3.1"
napi = "2.16.6"
napi-derive = "2.16.4"

[build-dependencies]
napi-build = "2.1.3"
3 changes: 3 additions & 0 deletions script-theory/src/addon/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
napi_build::setup();
}
69 changes: 69 additions & 0 deletions script-theory/src/addon/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use rand::prelude::*;
use rand_chacha::ChaCha20Rng;

use chacha20::ChaCha20;
use chacha20::cipher::KeyIvInit;
use chacha20::cipher::StreamCipher;

use napi::JsNumber;
use napi::bindgen_prelude::*;

use napi_derive::napi;

pub const OIL_BASE: [u8; 30] = [
0x05, 0x14, 0x02, 0x74, 0xdd, 0xe3, 0x1c, 0xe1, 0xa7, 0xab,
0x05, 0x7e, 0xae, 0x09, 0x1b, 0x18, 0x3a, 0x03, 0xae, 0x9d,
0x8d, 0xd1, 0x4e, 0x93, 0x7e, 0x68, 0x27, 0xda, 0x79, 0x2a
];

#[napi]
fn bring_oil(value: JsNumber) -> Buffer {
let mut rng = ChaCha20Rng::seed_from_u64(452890686835);

let mut oil_key: [u8; 32] = [0; 32];
oil_key[0..30].copy_from_slice(&OIL_BASE);

let sub = value.get_int32().unwrap() as u8;

for i in 0..30 {
oil_key[i] ^= rng.gen::<u8>();

if i % 2 == 0 {
oil_key[i] = sub + 157 - oil_key[i];
} else {
oil_key[30] += oil_key[i] % 10;
}
}

oil_key[31] = oil_key[0] + (oil_key[1] % 3);

return oil_key.to_vec().into();
}

#[napi]
fn diplomat_accurate(oil_key: Buffer, data: Buffer) -> Buffer {
let n = [0x32; 12];

let key: Vec<u8> = oil_key.to_vec();

let mut cipher = ChaCha20::new(key.as_slice().into(), &n.into());

let mut plaintext = data.to_vec().clone();

cipher.apply_keystream(&mut plaintext);

for byte in &mut plaintext {
*byte = byte.reverse_bits();
}

return plaintext.into();
}

#[napi]
fn bucket_terrace(shifter: Buffer, mut data: Buffer, magic: JsNumber) -> Buffer {
for (i, byte) in shifter.iter().enumerate() {
data[i] ^= byte ^ (magic.get_uint32().unwrap() as u8);
}

return data;
}
1 change: 1 addition & 0 deletions script-theory/src/flag.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bcactf{th3_uLt1maT3_L0cKb0X_ygIyaO6iacdU74Xt}
28 changes: 28 additions & 0 deletions script-theory/src/program.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const { readFileSync } = require('fs')

const scriptTheory = require('./libscript_theory_addon.node')

const data = readFileSync('flag.txt')

const oilKey = scriptTheory.bringOil(data[0])

for (let i = 0; i < oilKey.length; i++) {
oilKey[i] = Math.abs(oilKey[i] - i)
}

const initial = scriptTheory.diplomatAccurate(oilKey, data)

const shifter = Buffer.alloc(initial.length)

for (let i = 0; i < shifter.length; i++) {
const sub = String(Math.abs(Math.E * i + 2 / 3 * 100))
shifter[i] = Number(sub.split('.')[1].slice(0, 2))
}

const value = [...shifter].map(value => value ** 2).reduce((a, b) => {
return Math.max(a + Math.sqrt(b) - 2, 1)
}, 0) % 200

const bucket = scriptTheory.bucketTerrace(shifter, initial, value)

console.log('Encoded: ' + bucket.toString('base64'))
76 changes: 76 additions & 0 deletions script-theory/src/solve.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
const scriptTheory = require('./libscript_theory_addon.node')
const crypto = require('crypto')

const ENCODED_FLAG = 'DZwOdRBBOBaBxZ7SdUHDqORNCSzNt2SkBDa5NH9xsGIGz8ufVijMgucC8fht'

const computeShifterAndValue = length => {
// these routines are extracted straight from program.js

const shifter = Buffer.alloc(length)

for (let i = 0; i < shifter.length; i++) {
const value = String(Math.abs(Math.E * i + 2 / 3 * 100))
shifter[i] = Number(value.split('.')[1].slice(0, 2))
}

const value = [...shifter].map(value => value ** 2).reduce((a, b) => {
return Math.max(a + Math.sqrt(b) - 2, 1)
}, 0) % 200

return [shifter, value]
}

const terraceBucket = (data, shifter, value) => {
// undo bucket_terrace

for (let i = 0; i < shifter.length; i++) {
data[i] ^= shifter[i] ^ value
}
}

const computeOilKey = () => {
// just like in program.js, get the oil key

// of course the flag will start with "bcactf"
const oilKey = scriptTheory.bringOil('b'.charCodeAt(0))

for (let i = 0; i < oilKey.length; i++) {
oilKey[i] = Math.abs(oilKey[i] - i)
}

return oilKey
}

const accurateDiplomat = (data, oilKey) => {
// reverse diplomat_accurate

const iv = Buffer.alloc(16)

// skip the first 4 bytes for the counter
for (let i = 4; i < iv.length; i++) {
iv[i] = 0x32
}

const cipher = crypto.createDecipheriv('chacha20', oilKey, iv)

for (let i = 0; i < data.length; i++) {
// because the lib calls reverse_bits
const bits = [...data[i].toString(2).padStart(8, '0')]
data[i] = parseInt(bits.reverse().join(''), 2)
}

return cipher.update(data).toString('utf-8')
}

const solve = () => {
const data = Buffer.from(ENCODED_FLAG, 'base64')

const [shifter, value] = computeShifterAndValue(data.length)
const oilKey = computeOilKey()

terraceBucket(data, shifter, value)

console.log(accurateDiplomat(data, oilKey))
}

solve()

0 comments on commit f91fd75

Please sign in to comment.