NASA was so excited to send their new unmanned rover out to pick up some stranded astronauts that they forgot to actually write the software to control it. Can you take a look at the onboard ECU software and see if you can find a way to establish communications?
If worse comes to worst, maybe they CAN BUS the astronauts back....
the server binary has been updated to not be stripped
nc chal.sunshinectf.games 25102
Decompile in IDA:
while ( 1 )
{
v58 = bufio__ptr_Reader_ReadBytes(&b, 0xAu);
if ( v58._r1.tab )
break;
v32 = v58._r0.cap;
v31 = v58._r0.len;
v40.array = v58._r0.array;
p_main_ControlMsg = (main_ControlMsg *)runtime_newobject((runtime__type_1 *)&RTYPE_main_ControlMsg);
v = (main_ControlMsg_0 *)p_main_ControlMsg;
p_main_ControlMsg->T.ptr = 0;
p_main_ControlMsg->Frame.ptr = 0;
v66.len = v31;
v66.cap = v32;
v66.array = v40.array;
v67 = main_trim(v66);
v55._type = (runtime__type_0 *)&RTYPE__ptr_main_ControlMsg;
v55.data = v;
if ( !(unsigned __int64)encoding_json_Unmarshal(v67, v55).tab )
{
str = v->T.str;
if ( v->T.len == 3 && *(_WORD *)str == 0x6163 && str[2] == 110 )
{
v65.len = v->Frame.len;
if ( v65.len )
{
v65.str = v->Frame.str;
v68 = runtime_stringtoslicebyte((runtime_tmpBuf *)buf, v65);
raw_array = v68.array;
v30 = v68.cap;
v9 = (unsigned __int128)encoding_hex_Decode(v68, v68);
if ( (unsigned __int64)v9 > v30 )
runtime_panicSliceAcap();
if ( !*((_QWORD *)&v9 + 1) && (__int64)v9 >= 3 )
{
v10 = raw_array;
v11 = *(_WORD *)raw_array;
v12 = raw_array[2] & 0xF;
if ( (unsigned __int64)v12 <= 8 && (__int64)v9 >= v12 + 3 )
{
if ( (unsigned __int64)(v12 + 3) < 3 )
runtime_panicSliceB();
v13 = rover;
v14 = ((__int64)(3 - v30) >> 63) & 3;
v15 = &raw_array[v14];
if ( _InterlockedCompareExchange((volatile signed __int32 *)&rover->mu, 1, 0) )
{
dlc = v12;
v36 = v14;
v40.len = (int)&v10[v14];
v29 = v11;
sync__ptr_Mutex_lockSlow(&v13->mu);
v13 = rover;
v14 = v36;
v10 = raw_array;
v11 = v29;
v12 = dlc;
v15 = (uint8 *)v40.len;
}
v16 = __ROL2__(v11, 8) & 0x7FF;
if ( v16 > 0x202u )
{
switch ( v16 )
{
case 0x203u:
v13->vel = v13->vel * 0.65;
v13->msg.len = 6;
if ( *(_DWORD *)&runtime_writeBarrier.enabled )
goto LABEL_58;
v13->msg.str = (uint8 *)"Brake!";
break;
case 0x204u:
v13->steerPct = 0;
v13->heading = v13->heading * 0.9;
v13->msg.len = 14;
if ( !*(_DWORD *)&runtime_writeBarrier.enabled )
{
v13->msg.str = (uint8 *)"Stabilizers on";
break;
}
L_58:
runtime_gcWriteBarrierDX();
break;
case 0x205u:
if ( v13->status.len != 2 || *(_WORD *)v13->status.str != 27503 )
{
v13->s = 0.0;
v13->x = 0.0;
v13->vel = 0.0;
*(_OWORD *)&v13->throttlePct = 0;
v13->status.len = 2;
if ( *(_DWORD *)&runtime_writeBarrier.enabled )
runtime_gcWriteBarrierDX();
else
v13->status.str = (uint8 *)"ok";
v13->msg.len = 14;
if ( *(_DWORD *)&runtime_writeBarrier.enabled )
runtime_gcWriteBarrierSI();
else
v13->msg.str = (uint8 *)"Reset to start";
}
break;
default:
L_73:
a = 0;
v23 = runtime_convT16(v16);
*(_QWORD *)&a = &RTYPE_uint16;
*((_QWORD *)&a + 1) = v23;
v61.str = (uint8 *)"Unknown CAN 0x%03X";
v61.len = 18;
v64.len = 1;
v64.cap = 1;
v64.array = (interface__0 *)&a;
v24 = fmt_Sprintf(v61, v64);
v13 = rover;
rover->msg.len = v24.len;
if ( *(_DWORD *)&runtime_writeBarrier.enabled )
runtime_gcWriteBarrier();
else
v13->msg.str = v24.str;
break;
}
}
else if ( v16 == 513 )
{
if ( v12 >= 1 )
{
v17 = v10[v14];
if ( v17 > 100 )
v17 = 100;
v13->throttlePct = v17;
a = 0;
v18 = runtime_convT64(v13->throttlePct);
*(_QWORD *)&a = &RTYPE_int;
*((_QWORD *)&a + 1) = v18;
v59.str = (uint8 *)"Throttle %d%%";
v59.len = 13;
v62.len = 1;
v62.cap = 1;
v62.array = (interface__0 *)&a;
v19 = fmt_Sprintf(v59, v62);
v13 = rover;
rover->msg.len = v19.len;
if ( *(_DWORD *)&runtime_writeBarrier.enabled )
runtime_gcWriteBarrier();
else
v13->msg.str = v19.str;
}
}
else
{
if ( v16 != 514 )
goto LABEL_73;
if ( v12 >= 1 )
{
v20 = (char)*v15;
if ( v20 >= -100 )
{
if ( v20 > 100 )
v20 = 100;
}
else
{
v20 = -100;
}
v13->steerPct = v20;
a = 0;
v21 = runtime_convT64(v13->steerPct);
*(_QWORD *)&a = &RTYPE_int;
*((_QWORD *)&a + 1) = v21;
v60.str = (uint8 *)"Steer %d%%";
v60.len = 10;
v63.len = 1;
v63.cap = 1;
v63.array = (interface__0 *)&a;
v22 = fmt_Sprintf(v60, v63);
v13 = rover;
rover->msg.len = v22.len;
if ( *(_DWORD *)&runtime_writeBarrier.enabled )
runtime_gcWriteBarrier();
else
v13->msg.str = v22.str;
}
}
v25 = _InterlockedExchangeAdd((volatile signed __int32 *)&v13->mu, 0xFFFFFFFF);
if ( v25 != 1 )
sync__ptr_Mutex_unlockSlow(&v13->mu, v25 - 1);
}
}
}
}
}
}
The JSON format to sent is shown in client.py
:
TODO: Implement the controls for the rover client!
{"t":"can","frame":"0123456789abcdef"}
Reading the code, we know that the frame format is:
Possible opcodes:
We map these opcodes to keyboard input:
elif e.key == pygame.K_LEFT:
# -100
net.sock.send((json.dumps({
"t": "can",
"frame": "0202019c"
}) + "\n").encode())
elif e.key == pygame.K_RIGHT:
# +100
net.sock.send((json.dumps({
"t": "can",
"frame": "02020164"
}) + "\n").encode())
elif e.key == pygame.K_b:
# brake
net.sock.send((json.dumps({
"t": "can",
"frame": "020300"
}) + "\n").encode())
elif e.key == pygame.K_s:
# stablizer
net.sock.send((json.dumps({
"t": "can",
"frame": "020400"
}) + "\n").encode())
elif e.key == pygame.K_r:
# throttle
net.sock.send((json.dumps({
"t": "can",
"frame": "02010164"
}) + "\n").encode())
print(e.key)
Then we can play the game by pressing r
and then Left/Right
to avoid crashing into the obstacles. After winning, the flag is shown.
Flag: sun{r3d_r0v3r_c0m3_0v3r}
.