This commit is contained in:
pwn
2025-12-05 11:14:59 +03:00
parent 376d0fc8ad
commit b79ef3a3f3
8 changed files with 35 additions and 18 deletions

View File

@@ -9,7 +9,7 @@ import { Project, ProjectSchema } from "./schemas/project.schema.js";
import { Function, FunctionSchema } from "./schemas/function.schema.js"; import { Function, FunctionSchema } from "./schemas/function.schema.js";
import { JwtModule } from "@nestjs/jwt"; import { JwtModule } from "@nestjs/jwt";
import { BcryptService } from "./services/bcrypt.service.js"; import { BcryptService } from "./services/bcrypt.service.js";
import { JWT_SECRET } from "./auth/const.js"; import { JWT_SECRET, MONGO_URL } from "./auth/const.js";
import { AuthController } from "./controllers/auth.controller.js"; import { AuthController } from "./controllers/auth.controller.js";
import { JwtStrategy } from "./auth/jwt.strategy.js"; import { JwtStrategy } from "./auth/jwt.strategy.js";
import { LocalStrategy } from "./auth/local.strategy.js"; import { LocalStrategy } from "./auth/local.strategy.js";
@@ -33,9 +33,7 @@ import { HealthController } from "./controllers/health.controller.js";
secret: JWT_SECRET, secret: JWT_SECRET,
signOptions: { expiresIn: "3600s" }, signOptions: { expiresIn: "3600s" },
}), }),
MongooseModule.forRoot( MongooseModule.forRoot(MONGO_URL),
process.env.MONGO_URL ?? "mongodb://sigma:supersecret@localhost:27017"
),
MongooseModule.forFeature([ MongooseModule.forFeature([
{ {
name: User.name, name: User.name,

View File

@@ -1 +1,11 @@
export const JWT_SECRET = process.env["JWT_SECRET"] ?? "supersecret"; function getRequiredEnv(name: string): string {
const value = process.env[name];
if (!value) {
throw new Error(`${name} environment variable must be set`);
}
return value;
}
export const JWT_SECRET = getRequiredEnv("JWT_SECRET");
export const MONGO_URL = getRequiredEnv("MONGO_URL");

View File

@@ -86,7 +86,7 @@ export class FunctionsService {
}); });
if (func) { if (func) {
await this.projectModel.findByIdAndUpdate(func._id, { await this.projectModel.findByIdAndUpdate(func.project, {
$inc: { $inc: {
functionsInvocationCount: 1, functionsInvocationCount: 1,
functionsErrorCount: successful ? 0 : 1, functionsErrorCount: successful ? 0 : 1,

View File

@@ -15,7 +15,9 @@ async function bootstrap() {
app.set("query parser", "extended"); app.set("query parser", "extended");
app.useGlobalPipes( app.useGlobalPipes(
new ValidationPipe({ new ValidationPipe({
whitelist: false, whitelist: true,
forbidNonWhitelisted: true,
transform: true,
}) })
); );

View File

@@ -1,9 +1,14 @@
#!/bin/sh #!/bin/sh
set -euo pipefail
# Ensure the ctf user exists (defensive in case the base image changes)
if ! id ctf >/dev/null 2>&1; then
useradd -m -u 1001 ctf
fi
# Ensure the history directory exists and has correct ownership # Ensure the history directory exists and has correct ownership
mkdir -p /app/history mkdir -p /app/history
chown -R ctf:ctf /app/history chown -R ctf:ctf /app/history
# Run the grob service as ctf user # Run the grob service as ctf user
exec runuser -u ctf /app/grob exec runuser -u ctf -- /app/grob

View File

@@ -42,14 +42,6 @@ pub fn render_hash(lua_src: &str, note: u32, velocity: u32) -> anyhow::Result<[u
let v: f64 = func let v: f64 = func
.call((i as f64 / 44_100.0, note, velocity)) .call((i as f64 / 44_100.0, note, velocity))
.context(ScriptError)?; .context(ScriptError)?;
#[allow(dead_code)]
fn vulnerable(buf: &mut [u8], idx: isize, value: u8) {
unsafe {
/* MANUAL pointer arithmetic (dangerous) */
let ptr = buf.as_mut_ptr().offset(idx); /* Write without bounds check */
std::ptr::write(ptr, value);
}
}
let normalized_v = v.clamp(-1.0, 1.0); let normalized_v = v.clamp(-1.0, 1.0);
hasher.update(normalized_v.to_le_bytes()); hasher.update(normalized_v.to_le_bytes());
} }

View File

@@ -3,6 +3,7 @@ use std::time::Duration;
use tokio::{task, time}; use tokio::{task, time};
const UDP_PORT: u16 = 5004; const UDP_PORT: u16 = 5004;
const MAX_PATCH_SIZE: usize = 8 * 1024;
const PATCH_MAX_AGE: Duration = Duration::from_secs(30 * 60); const PATCH_MAX_AGE: Duration = Duration::from_secs(30 * 60);
const CLEAN_INTERVAL: Duration = Duration::from_secs(10 * 60); const CLEAN_INTERVAL: Duration = Duration::from_secs(10 * 60);
const SYSEX_TIMEOUT: Duration = Duration::from_millis(50); const SYSEX_TIMEOUT: Duration = Duration::from_millis(50);
@@ -56,6 +57,15 @@ async fn handle_sysex(
let response = match msg { let response = match msg {
sysex::Request::Diag => sysex::Response::Diag, sysex::Request::Diag => sysex::Response::Diag,
sysex::Request::Put { data } => { sysex::Request::Put { data } => {
if data.len() > MAX_PATCH_SIZE {
let response = sysex::Response::Error(format!(
"Patch too large ({} bytes > {MAX_PATCH_SIZE})",
data.len()
));
state.udp_sock.send_to(&response.encode(), addr).await?;
return Ok(());
}
let lua_dsp = String::from_utf8_lossy(&data).to_string(); let lua_dsp = String::from_utf8_lossy(&data).to_string();
if let Err(error) = if let Err(error) =
run_blocking_with_timeout(SYSEX_TIMEOUT, move || lua_sandbox::validate(&lua_dsp)) run_blocking_with_timeout(SYSEX_TIMEOUT, move || lua_sandbox::validate(&lua_dsp))

View File

@@ -93,7 +93,7 @@ impl BankStorage {
write_tlv(&mut file, TlvTag::EncryptedDataIv, &patch.encrypted_code.iv)?; write_tlv(&mut file, TlvTag::EncryptedDataIv, &patch.encrypted_code.iv)?;
file.write_all(&[TlvTag::End as u8])?; file.write_all(&[TlvTag::End as u8])?;
} }
let permissions = std::fs::Permissions::from_mode(0o444); let permissions = std::fs::Permissions::from_mode(0o600);
std::fs::set_permissions(path, permissions)?; std::fs::set_permissions(path, permissions)?;
Ok(()) Ok(())
} }