CurlAsAService
2 minutes to read
We are provided with this webpage, which allows us to execute curl
:
Source code analysis
We also have the PHP source code. This is index.php
:
<?php
date_default_timezone_set('UTC');
spl_autoload_register(function ($name){
if (preg_match('/Controller$/', $name))
{
$name = "controllers/${name}";
}
else if (preg_match('/Model$/', $name))
{
$name = "models/${name}";
}
include_once "${name}.php";
});
$router = new Router();
$router->new('GET', '/', 'CurlController@index');
$router->new('POST', '/api/curl', 'CurlController@execute' );
$response = $router->match();
die($response);
Here we only see two routes. The one that is most interesting is handled by CurlController.php
:
<?php
class CurlController
{
public function index($router)
{
return $router->view('index');
}
public function execute($router)
{
$url = $_POST['ip'];
if (isset($url)) {
$command = new CommandModel($url);
return json_encode([ 'message' => $command->exec() ]);
}
}
}
Here we see that it calls CommandModel
with ip
(POST parameter):
<?php
class CommandModel
{
public function __construct($url)
{
$this->command = "curl --proto =http,https -sSL " . escapeshellcmd($url) . " 2>&1";
}
public function exec()
{
$output = shell_exec($this->command);
return $output;
}
}
Our POST parameter ip
will be escaped with escapeshellcmd
. However, it is appended directly to the curl
command. We won’t be able to perform a command injection because of escapeshellcmd
, but we can add more parameters to curl
.
Parameter injection
For instance, we can override --proto =http,https
and set --proto =file
, so that we can use curl
to read the flag as a local file.
We know the flag is at /flag
, it is shown in the Dockerfile
:
# Install PHP dependencies
RUN apt update && apt install -y php7.4-fpm
# Configure php-fpm and nginx
COPY config/fpm.conf /etc/php/7.4/fpm/php-fpm.conf
COPY config/supervisord.conf /etc/supervisord.conf
COPY config/nginx.conf /etc/nginx/nginx.conf
# Copy challenge files
COPY challenge /www
# Copy flag
COPY flag /
# Setup permissions
RUN chown -R www:www /www /var/lib/nginx
# Expose the port nginx is listening on
EXPOSE 80
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]
Flag
Nice, so let’s read the flag:
HTB{f1l3_r3tr13v4l_4s_4_s3rv1c3}