https://app.hackthebox.com/challenges/742

Description

The spaceship cruiser has been hit! Ramona must hurry and check if the central system is intact! The enemy must have used electromagnetic wave canons! The spaceship’s sensors are going crazy and the autopilot system broke down! There is no chance to turn back the enemy will be waiting… But there is a meteor shower ahead! In order to get through safely, the spaceship’s power and consumption need to be balanced. Both the laser canons and the thrusters are vital parts for this… And she has to control them manually! Quickly! Ramona needs to upload a valid configuration file to overwrite the values of all sensors on board. The onboard neural network will verify that the new configuration leads to the required power distribution. Attention! The values of the sensors must be at least 99.99% accurate for this to work! Hurry now, time is running out!

Exploitation

#!/usr/bin/python3
import torch
import torch.nn as nn
import numpy as np
import torch.serialization

torch.serialization._GLOBAL_ALLOW_LIST = None

class net(nn.Module):
    def __init__(self):
        super(net, self).__init__()
        self.layer1 = nn.Sequential(
            nn.Conv2d(1, 16, kernel_size=3, padding=0, stride=2),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.layer2 = nn.Sequential(
            nn.Conv2d(16, 32, kernel_size=3, padding=0, stride=2),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.fc1 = nn.Linear(5408, 10)
        self.fc2 = nn.Linear(10, 2)
        self.relu = nn.ReLU()

    def forward(self, x):
        out = self.layer1(x)
        out = self.layer2(out)
        out = out.view(out.size(0), -1)
        out = self.relu(self.fc1(out))
        out = self.fc2(out)
        out = torch.softmax(out, dim=1)
        return out

def main():
    model = torch.load('./model.pth', map_location=torch.device('cpu'))
    if not isinstance(model, net):
        if hasattr(model, 'state_dict'):
            original_net = net()
            original_net.load_state_dict(model.state_dict())
            model = original_net
    print(model)
    model.eval()
    X = np.zeros((1, 1, 224, 224))
    a = torch.tensor(X, requires_grad=True, dtype=torch.float32)
    answer = torch.tensor([[0.9569, 0.0431]])
    data_optimizer = torch.optim.Adam([a], lr=0.01)
    while True:
        y_pred = model(a)
        loss = ((y_pred - answer)**2).mean()
        data_optimizer.zero_grad()
        print(loss.item(), flush=True)
        loss.backward()
        data_optimizer.step()
        if loss.item() < 1e-14:
            print(f"Final prediction: {y_pred}")
            break
    np.save('result.npy', a.detach().numpy())

if __name__ == "__main__":
    main()

Replace answer = torch.tensor([[0.9569, 0.0431]]) with the values shown in the web interface. For example, you should use:

  • Laser Canons: 0.9569
  • Thrusters: 0.0431

So, the updated line should be:

answer = torch.tensor([[0.9569, 0.0431]])

Afterward, upload the resulting result.npy file to get the flag.

Summary

Battle in OrlOn: shape the prompt path, bypass the model guard, and recover the target output.