Skip to content

Commit

Permalink
Merge branch 'master' into bug_751
Browse files Browse the repository at this point in the history
  • Loading branch information
s3inlc committed Jun 5, 2022
2 parents 1a8b22c + 2f1183e commit 806aec0
Show file tree
Hide file tree
Showing 40 changed files with 805 additions and 105 deletions.
6 changes: 6 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
FROM php:8-apache

ARG DEV_CONTAINER_USER_CMD

# Avoid warnings by switching to noninteractive
ENV DEBIAN_FRONTEND=noninteractive

# Check for and run optional user-supplied command to enable (advanced) customizations of the dev container
RUN [ -n "${DEV_CONTAINER_USER_CMD}" ] \
&& echo "${DEV_CONTAINER_USER_CMD}" | sh

# Configure apt and install packages
RUN apt-get update \
&& apt-get -y install --no-install-recommends apt-utils zip unzip nano ncdu 2>&1 \
Expand Down
2 changes: 2 additions & 0 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ services:
build:
context: .
dockerfile: Dockerfile
args:
- DEV_CONTAINER_USER_CMD
depends_on:
- db
ports:
Expand Down
6 changes: 6 additions & 0 deletions ci/run.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@
require_once(dirname(__FILE__) . "/tests/" . $entry);
}
}
$dir = scandir(dirname(__FILE__) . "/tests/integration/");
foreach ($dir as $entry) {
if (strpos($entry, ".php") !== false) {
require_once(dirname(__FILE__) . "/tests/integration/" . $entry);
}
}

$TEST = true;

Expand Down
1 change: 1 addition & 0 deletions ci/tests/PretaskTest.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ private function testCreatePretask($name, $cmd, $assert = true, $chunksize = 600
"crackerTypeId" => $crackerTypeId,
"files" => $files,
"priority" => $priority,
"maxAgents" => 16,
"accessKey" => "mykey"
], HashtopolisTestFramework::REQUEST_UAPI
);
Expand Down
1 change: 1 addition & 0 deletions ci/tests/TaskTest.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public function testCreateTask($values = [], $assert = true) {
"crackerVersionId" => 0,
"files" => [],
"priority" => 0,
"maxAgents" => 0,
"preprocessorId" => 0,
"preprocessorCommand" => "",
"accessKey" => "mykey"
Expand Down
291 changes: 291 additions & 0 deletions ci/tests/integration/MaxAgentsTest.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,291 @@
<?php

class MaxAgentsTest extends HashtopolisTest {
protected $minVersion = "0.12.0";
protected $maxVersion = "master";
protected $runType = HashtopolisTest::RUN_FAST;

public function init($version) {
HashtopolisTestFramework::log(HashtopolisTestFramework::LOG_INFO, "Initializing " . $this->getTestName() . "...");
parent::init($version);
}

private function prepare() {
$status = true;
// add some files
$status &= $this->addFile("example.dict", 0);
$status &= $this->addFile("best64.rule", 1);

if (!$status) {
HashtopolisTestFramework::log(HashtopolisTestFramework::LOG_ERROR, "Some initialization failed, most likely tests will fail!");
}
}

public function run() {
HashtopolisTestFramework::log(HashtopolisTestFramework::LOG_INFO, "Running " . $this->getTestName() . "...");
$this->prepare();
$this->testMaxAgents();
HashtopolisTestFramework::log(HashtopolisTestFramework::LOG_INFO, $this->getTestName() . " completed");
}

private function testMaxAgents() {
$response = $this->addHashlist(["name" => "NotSecureList", "isSecure" => false]);
$hashlistId = $response["hashlistId"];

$agent1 = $this->createAgent("agent-1");
$agent2 = $this->createAgent("agent-2");

// register a single task, ready to be picked up by the agents (no limit on the amount of agents)
$response = $this->createTask([
"name" => "task-1",
"hashlistId" => $hashlistId,
"attackCmd" => "#HL# -a 0 -r best64.rule example.dict",
"priority" => 100,
"color" => "FFFFFF",
"crackerVersionId" => 1,
"files" => [1]]);

$task1Id = $response["taskId"];

// verify agent 1 is assigned to task 1
$response = HashtopolisTestFramework::doRequest(["action" => "getTask", "token" => $agent1["token"]]);
if ($response["taskId"] != $task1Id) {
$this->testFailed("MaxAgentsTest:testMaxAgents()", sprintf("Expected task with id '%d' for agent 1, instead got: %s", $task1Id, implode(", ", $response)));
return;
}

// verify agent 2 is assigned to task 1
$response = HashtopolisTestFramework::doRequest(["action" => "getTask", "token" => $agent2["token"]]);
if ($response["taskId"] != $task1Id) {
$this->testFailed("MaxAgentsTest:testMaxAgents()", sprintf("Expected task with id '%d' for agent 2, instead got: %s", $task1Id, implode(", ", $response)));
return;
}

// after the task is assigned, make sure to set the keyspace and benchmark parameters
$response = HashtopolisTestFramework::doRequest([
"action" => "sendKeyspace",
"taskId" => $task1Id,
"token" => $agent2["token"],
"keyspace" => 100]);

$response = HashtopolisTestFramework::doRequest([
"action" => "sendBenchmark",
"taskId" => $task1Id,
"token" => $agent2["token"],
"type" => "run",
"result" => 2000000000]);

// now set the task to only allow 1 agent to work on it
$response = HashtopolisTestFramework::doRequest([
"section" => "task",
"request" => "setTaskMaxAgents",
"accessKey" => "mykey",
"taskId" => $task1Id,
"maxAgents" => 1
], HashtopolisTestFramework::REQUEST_UAPI);

// verify agent 2 is NOT assigned to task 1
$response = HashtopolisTestFramework::doRequest(["action" => "getTask", "token" => $agent2["token"]]);
if ($response["taskId"] == $task1Id) {
$this->testFailed("MaxAgentsTest:testMaxAgents()", sprintf("Expected no task for agent 2, instead got: %s", implode(", ", $response)));
return;
}
// verify getting chunk by agent 2 for task 1 now fails, because the task is already saturated
$response = HashtopolisTestFramework::doRequest([
"action" => "getChunk",
"taskId" => $task1Id,
"token" => $agent2["token"]]);
if ($response["response"] !== "ERROR" || $response["message"] != "Task already saturated by other agents, no other task available!") {
$this->testFailed("MaxAgentsTest:testMaxAgents()", sprintf("Expected getChunk to fail, instead got: %s", implode(", ", $response)));
return;
}

// actually unassign agent 2
$response = HashtopolisTestFramework::doRequest([
"section" => "task",
"request" => "taskUnassignAgent",
"accessKey" => "mykey",
"agentId" => $agent2["agentId"]
], HashtopolisTestFramework::REQUEST_UAPI);

// verify agent 1 is assigned to task 1
$response = HashtopolisTestFramework::doRequest(["action" => "getTask", "token" => $agent1["token"]]);
if ($response["taskId"] != $task1Id) {
$this->testFailed("MaxAgentsTest:testMaxAgents()", sprintf("Expected task with id '%d' for agent 1, instead got: %s", $task1Id, implode(", ", $response)));
return;
}

// now create a second task
$response = $this->createTask([
"name" => "task-2",
"hashlistId" => $hashlistId,
"attackCmd" => "#HL# -a 0 -r best64.rule example.dict",
"priority" => 10,
"color" => "FFFFFF",
"crackerVersionId" => 1,
"files" => [2]
]);
$task2Id = $response["taskId"];

// verify agent 1 is assigned to task 1
$response = HashtopolisTestFramework::doRequest(["action" => "getTask", "token" => $agent1["token"]]);
if ($response["taskId"] != $task1Id) {
$this->testFailed("MaxAgentsTest:testMaxAgents()", sprintf("Expected task with id '%d' for agent 1, instead got: %s", $task1Id, implode(", ", $response)));
return;
}

// verify agent 2 is assigned to task 2
$response = HashtopolisTestFramework::doRequest(["action" => "getTask", "token" => $agent2["token"]]);
if ($response["taskId"] != $task2Id) {
$this->testFailed("MaxAgentsTest:testMaxAgents()", sprintf("Expected task with id '%d' for agent 1, instead got: %s", $task2Id, implode(", ", $response)));
return;
}

// verify getting chunk by agent 2 for task 2 succeeds
$response = HashtopolisTestFramework::doRequest([
"action" => "getChunk",
"taskId" => $task2Id,
"token" => $agent2["token"]]);
if ($response["response"] !== "SUCCESS") {
$this->testFailed("MaxAgentsTest:testMaxAgents()", sprintf("Expected getChunk to succeed, instead got: %s", implode(", ", $response)));
return;
}

// now set the task to allow any amount of agents to work on it
$response = HashtopolisTestFramework::doRequest([
"section" => "task",
"request" => "setTaskMaxAgents",
"accessKey" => "mykey",
"taskId" => $task1Id,
"maxAgents" => 0
], HashtopolisTestFramework::REQUEST_UAPI);

// verify agent 2 is assigned to task 1 (since it has higher priority than task 2)
$response = HashtopolisTestFramework::doRequest(["action" => "getTask", "token" => $agent2["token"]]);
if ($response["taskId"] != $task1Id) {
$this->testFailed("MaxAgentsTest:testMaxAgents()", sprintf("Expected task with id '%d' for agent 1, instead got: %s", $task1Id, implode(", ", $response)));
return;
}

// verify getting chunk by agent 2 for task 1 succeeds
$response = HashtopolisTestFramework::doRequest([
"action" => "getChunk",
"taskId" => $task1Id,
"token" => $agent2["token"]]);
if ($response["response"] !== "SUCCESS") {
$this->testFailed("MaxAgentsTest:testMaxAgents()", sprintf("Expected getChunk to succeed, instead got: %s", implode(", ", $response)));
return;
}
$this->testSuccess("MaxAgentsTest:testMaxAgents()");
}

private function addFile($name, $type) {
$response = HashtopolisTestFramework::doRequest([
"section" => "file",
"request" => "addFile",
"filename" => $name,
"fileType" => $type,
"source" => "inline",
"data" => base64_encode(file_get_contents(dirname(__FILE__) . "/../../files/$name")),
"accessGroupId" => 1,
"accessKey" => "mykey"
], HashtopolisTestFramework::REQUEST_UAPI
);
if ($response === false) {
return false;
}
else if ($response['response'] != 'OK') {
return false;
}
return true;
}

private function addHashlist($values = []) {
$data = base64_encode(file_get_contents(dirname(__FILE__) . "/../../files/example0.hash"));
$query = [
"section" => "hashlist",
"request" => "createHashlist",
"name" => "Test Hashlist",
"isSalted" => false,
"isSecret" => true,
"isHexSalt" => false,
"separator" => ":",
"format" => 0,
"hashtypeId" => 0,
"accessGroupId" => 1,
"data" => $data,
"useBrain" => false,
"brainFeatures" => 0,
"accessKey" => "mykey"
];
foreach ($values as $key => $value) {
$query[$key] = $value;
};
return HashtopolisTestFramework::doRequest($query, HashtopolisTestFramework::REQUEST_UAPI);
}

private function createAgent($name) {
$voucher = "voucher-" . $name;
$response = HashtopolisTestFramework::doRequest([
"section" => "agent",
"request" => "createVoucher",
"voucher" => $voucher,
"accessKey" => "mykey"
], HashtopolisTestFramework::REQUEST_UAPI);
$response = HashtopolisTestFramework::doRequest([
"action" => "register",
"voucher" => $voucher,
"name" => $name]);
$token = $response['token'];
$response = HashtopolisTestFramework::doRequest([
"section" => "agent",
"request" => "listAgents",
"accessKey" => "mykey"
], HashtopolisTestFramework::REQUEST_UAPI);
$agent = current(array_filter($response["agents"], function($a) use ($name) {
return $a["name"] == $name;
}));
$response = HashtopolisTestFramework::doRequest([
"section" => "agent",
"request" => "setTrusted",
"accessKey" => "mykey",
"agentId" => $agent["agentId"],
"trusted" => true
], HashtopolisTestFramework::REQUEST_UAPI);
return array("agentId" => $agent["agentId"], "token" => $token);
}

private function createTask($values = []) {
$query = [
"section" => "task",
"request" => "createTask",
"name" => "",
"hashlistId" => 0,
"attackCmd" => "",
"chunksize" => 600,
"statusTimer" => 5,
"benchmarkType" => "speed",
"color" => "",
"isCpuOnly" => false,
"isSmall" => false,
"skip" => 0,
"crackerVersionId" => 0,
"files" => [],
"priority" => 0,
"maxAgents" => 0,
"preprocessorId" => 0,
"preprocessorCommand" => "",
"accessKey" => "mykey"
];
foreach ($values as $key => $value) {
$query[$key] = $value;
}
return HashtopolisTestFramework::doRequest($query, HashtopolisTestFramework::REQUEST_UAPI);
}

public function getTestName() {
return "Max Agents Test";
}
}

HashtopolisTestFramework::register(new MaxAgentsTest());
5 changes: 4 additions & 1 deletion doc/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- Allow abort all chunks of a specific access group from the User API.
- Tasks can be set to top priority (to be first in the list) by the User API.
- Supertask runtime can be estimated on the supertask detail page by entering expected attack speeds for hashcat wordlist and bruteforce attacks
- Number of agents per task can be limited (pull request #764).

## Bugfixes

Expand All @@ -24,7 +25,9 @@
- Time of Zaps inserted is now saved.
- Fixed unable to unassign agent from the task detail screen.
- Fixed speed graph incorrect when status timer is different from servers default.
- Fixed sending two to headers when sending emails.
- Fixed sending two to headers when sending emails (issue #751).
- Fixed access group not being changed on Hashlist detailed screen (issue #765).
- Fixed missing check on permissions for sending notifications (issue #757).

## Enhancements

Expand Down
Loading

0 comments on commit 806aec0

Please sign in to comment.