PLC operators have detected that the test mode has been activated and intruders have sent a message through it. What message is this PLC transmitting?
Note: Find the spy PLC message and wrap with ASIS{}!
Attachment:
PROGRAM ENVMon
VAR
TempRaw AT %IW0 : INT;
HumRaw AT %IW1 : INT;
PressRaw AT %IW2 : INT;
GasRaw AT %IW3 : INT;
END_VAR
VAR CONSTANT
T_Thr_Max : INT := 1200;
H_Thr_Max : INT := 900;
P_Thr_Max : INT := 3000;
G_Thr_Max : INT := 1000;
T_Thr_Min : INT := 200;
H_Thr_Min : INT := 200;
P_Thr_Min : INT := 500;
G_Thr_Min : INT := 100;
END_VAR
VAR
StrongHeat AT %QX0.0 : BOOL;
ColdHumid AT %QX0.1 : BOOL;
HighPress AT %QX0.2 : BOOL;
LowPress AT %QX0.3 : BOOL;
LowGas AT %QX0.4 : BOOL;
HighGas AT %QX0.5 : BOOL;
HeatAndPressure AT %QX0.6 : BOOL;
DryAndGas AT %QX0.7 : BOOL;
END_VAR
VAR
TestMode : BOOL := True;
StepSelect : INT := 1;
AutoPlay : BOOL := True;
stepP : INT := 1;
Tmr : TON;
END_VAR
VAR
TT AT %MW0 : INT;
HH AT %MW1 : INT;
PP AT %MW2 : INT;
GG AT %MW3 : INT;
END_VAR
VAR
TEMP_CASES : ARRAY [1..32] OF INT := [180, 180, 1300, 1300, 1300, 180, 900, 1300, 1300, 180, 180, 400, 1300, 180, 400, 400, 900, 180, 1300, 180, 900, 1300, 400, 900, 180, 400, 1300, 180, 900, 400, 1300, 400];
HUM_CASES : ARRAY [1..32] OF INT := [150, 1000, 150, 150, 1000, 400, 150, 150, 1000, 400, 800, 400, 1000, 800, 400, 150, 150, 400, 1000, 150, 400, 1000, 150, 1000, 400, 400, 150, 400, 150, 800, 150, 400];
PRESS_CASES : ARRAY [1..32] OF INT := [1000, 400, 400, 3500, 1000, 3500, 3500, 3500, 1000, 3500, 400, 2000, 1000, 2000, 2000, 2000, 1000, 1000, 1000, 3500, 2000, 1000, 3500, 2000, 2000, 1000, 3500, 3500, 3500, 2000, 3500, 3500];
GAS_CASES : ARRAY [1..32] OF INT := [300, 300, 300, 300, 300, 50, 300, 50, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 50, 300, 300, 50, 300, 300, 300, 300, 300, 300, 300, 50, 50];
NCASES : INT := 32;
T_mid : INT;
H_mid : INT;
P_mid : INT;
G_mid : INT;
Tz : INT;
Hz : INT;
Pz : INT;
Gz : INT;
END_VAR
T_mid := (T_Thr_Min + T_Thr_Max) / 2;
H_mid := (H_Thr_Min + H_Thr_Max) / 2;
P_mid := (P_Thr_Min + P_Thr_Max) / 2;
G_mid := (G_Thr_Min + G_Thr_Max) / 2;
IF TempRaw <= T_Thr_Min THEN
Tz := 0;
ELSIF TempRaw <= T_mid THEN
Tz := 1;
ELSIF TempRaw < T_Thr_Max THEN
Tz := 2;
ELSE
Tz := 3;
END_IF;
IF HumRaw <= H_Thr_Min THEN
Hz := 0;
ELSIF HumRaw <= H_mid THEN
Hz := 1;
ELSIF HumRaw < H_Thr_Max THEN
Hz := 2;
ELSE
Hz := 3;
END_IF;
IF PressRaw <= P_Thr_Min THEN
Pz := 0;
ELSIF PressRaw <= P_mid THEN
Pz := 1;
ELSIF PressRaw < P_Thr_Max THEN
Pz := 2;
ELSE
Pz := 3;
END_IF;
IF GasRaw <= G_Thr_Min THEN
Gz := 0;
ELSIF GasRaw <= G_mid THEN
Gz := 1;
ELSIF GasRaw < G_Thr_Max THEN
Gz := 2;
ELSE
Gz := 3;
END_IF;
IF TestMode THEN
IF AutoPlay THEN
Tmr(IN:=TRUE, PT:=T#2000ms);
IF Tmr.Q THEN
stepP := stepP + 1;
IF stepP > NCASES THEN stepP := 1; END_IF;
Tmr(IN:=FALSE);
END_IF;
IF NOT Tmr.Q THEN Tmr(IN:=TRUE); END_IF;
ELSE
IF StepSelect < 1 THEN stepP := 1;
ELSIF StepSelect > NCASES THEN stepP := NCASES;
ELSE stepP := StepSelect;
END_IF;
END_IF;
TempRaw := TEMP_CASES[stepP];
HumRaw := HUM_CASES[stepP];
PressRaw := PRESS_CASES[stepP];
GasRaw := GAS_CASES[stepP];
END_IF;
StrongHeat := (Tz = 1) OR (Tz = 3);
ColdHumid := (Tz >= 2);
HighPress := (Hz = 1) OR (Hz = 3);
LowPress := (Hz >= 2);
HighGas := (Pz = 1) OR (Pz = 3);
LowGas := (Pz >= 2);
HeatAndPressure := (Gz = 1) OR (Gz = 3);
DryAndGas := (Gz >= 2);
END_PROGRAM
CONFIGURATION Config0
RESOURCE Res0 ON PLC
TASK task0(INTERVAL := T#20ms,PRIORITY := 0);
PROGRAM instance0 WITH task0 : ENVMon;
END_RESOURCE
END_CONFIGURATION
Ask ChatGPT to solve it:
Solve CTF challenge:
<attachment here>
Response:
Nice one — the program’s outputs are wired to the wrong zone variables (the boolean outputs use the wrong `*z` variables), so the 8 QX outputs per test case form bytes. I simulated the 32 test cases, read the 8 booleans per case (in the order they appear in the code), reversed each 8-bit sequence (LSB first), and converted to ASCII.
The recovered message is:
PLCs_4r3_tHe_heaRT_0f_1ndUstri35
So the CTF flag (wrapped in the usual format) is:
crew{PLCs_4r3_tHe_heaRT_0f_1ndUstri35}
If you want, I can paste the short Python simulation I used to extract it.
Flag: ASIS{PLCs_4r3_tHe_heaRT_0f_1ndUstri35}
.