{
  "date": "2014-11-26T18:18:29",
  "slug": "12c-privilege-analysis-rocks",
  "link": "https://www.dbi-services.com/blog/12c-privilege-analysis-rocks/",
  "title": {
    "rendered": "Oracle 12c privilege analysis rocks"
  },
  "content": {
    "rendered": "<h2>By Franck Pachot</h2>\n<p>.<br />\n12c came with a very nice feature: privilege analysis. You don&#8217;t know which privileges are required? then just grant DBA, run your application, and check which minimal privileges are needed. And today, I&#8217;ve discovered how it is very powerful: you can even see privileges used internally, even when not done by SQL, and even not documented.</p>\n<p>It starts like that, with a question from Vladimir Sitnikov (who publishes very interesting stuff from his twitter account) in the tone of a challenge:</p>\n<blockquote lang=\"en\"><p><a href=\"https://twitter.com/FranckPachot\">@FranckPachot</a> Ok, ace. Do you think dbms_utility.get_parameter_value requires special grants (e.g. in current 11gR2)?</p>\n<p>— Vladimir Sitnikov (@VladimirSitnikv) <a href=\"https://twitter.com/VladimirSitnikv/status/537678463604621313\">November 26, 2014</a></p></blockquote>\n<p>So I got to the <a href=\"https://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_util.htm#i1003189\">doc</a> which has a special security model for some functions but nothing about get_parameter_value.</p>\n<p>Then I created a simple user with only CREATE SESSION privilege and got:</p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">SQL&gt; drop user TEST;\nUser dropped.\nSQL&gt; grant create session to TEST identified by TEST;\nGrant succeeded.\nSQL&gt; connect TEST/TEST\nConnected.\nSQL&gt; variable i number\nSQL&gt; variable s varchar2(1000)\nSQL&gt; variable t number\nSQL&gt; exec :t:=DBMS_UTILITY.GET_PARAMETER_VALUE('NLS_LENGTH_SEMANTICS',:i,:s);\nBEGIN :t:=DBMS_UTILITY.GET_PARAMETER_VALUE('NLS_LENGTH_SEMANTICS',:i,:s); END;\n*\nERROR at line 1:\nORA-01031: insufficient privileges\nORA-06512: at \"SYS.DBMS_UTILITY\", line 140\nORA-06512: at line 1\n\n</pre>\n<p>So, which privileges do you need? Let&#8217;s try the 12c privilege analysis:</p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">SQL&gt; grant dba to TEST;\nGrant succeeded.\n\nSQL&gt; connect / as sysdba\nConnected.\n\nSQL&gt; exec dbms_privilege_capture.create_capture (name=&gt;'demo',type =&gt;dbms_privilege_capture.g_role,roles=&gt;role_name_list('DBA'));\nPL/SQL procedure successfully completed.\n\nSQL&gt; exec dbms_privilege_capture.enable_capture (name=&gt;'demo');\nPL/SQL procedure successfully completed.\n\nSQL&gt; connect TEST/TEST\nConnected.\n\nSQL&gt; exec :t:=dbms_utility.get_parameter_value('NLS_LENGTH_SEMANTICS',:i,:s);\nPL/SQL procedure successfully completed.\n\nSQL&gt; print s\n\nS\n--------------------------------------------------------------\nBYTE\n\nSQL&gt; connect / as sysdba\nConnected.\n\nSQL&gt; exec dbms_privilege_capture.disable_capture(name=&gt;'demo');\nPL/SQL procedure successfully completed.\n\nSQL&gt; exec dbms_privilege_capture.generate_result(name=&gt;'demo');\nPL/SQL procedure successfully completed.\n\nSQL&gt; select object_owner,object_name,obj_priv from dba_used_objprivs ;\n\nOBJECT_OWN OBJECT_NAME     OBJ_PRIV\n---------- --------------- ----------\nSYS        V_$PARAMETER    SELECT\n\nSQL&gt; select path from dba_used_objprivs_path ;\n\nPATH\n--------------------------------------------------------------\nGRANT_PATH('TEST', 'DBA', 'EXP_FULL_DATABASE', 'SELECT_CATALOG_ROLE')\nGRANT_PATH('TEST', 'DBA', 'EM_EXPRESS_ALL', 'EM_EXPRESS_BASIC', 'SELECT_CATALOG_ROLE')\nGRANT_PATH('TEST', 'DBA', 'DATAPUMP_IMP_FULL_DATABASE', 'EXP_FULL_DATABASE', 'SELECT_CATALOG_ROLE')\nGRANT_PATH('TEST', 'DBA', 'DATAPUMP_EXP_FULL_DATABASE', 'EXP_FULL_DATABASE', 'SELECT_CATALOG_ROLE')\nGRANT_PATH('TEST', 'DBA', 'IMP_FULL_DATABASE', 'SELECT_CATALOG_ROLE')\nGRANT_PATH('TEST', 'DBA', 'DATAPUMP_IMP_FULL_DATABASE', 'IMP_FULL_DATABASE', 'SELECT_CATALOG_ROLE')\nGRANT_PATH('TEST', 'DBA', 'SELECT_CATALOG_ROLE')\n\nSQL&gt; exec dbms_privilege_capture.drop_capture (name=&gt;'demo');\nPL/SQL procedure successfully completed.\n\n</pre>\n<p>I&#8217;ve granted the DBA privilege and have run the privilege analysis capture on that role while calling the function. And bingo: you need to be granted SELECT on V_$PARAMETER (which come into DBA role through the SELECT_CATALOG_ROLE) &#8230; which sounds legitimate as the goal is to get a parameter value.</p>\n<p>But do you know what? DBMS_UTILITY.GET_PARAMETER_VALUE do not execute any select statement. That behavior is documented in that package for other function, but not for the GET_PARAMETER_VALUE one:</p>\n<pre class=\"brush: actionscript3; gutter: true; first-line: 1\">Rem The dbms_utility package is run-as-caller (psdicd.c) only for\nRem its name_resolve, compile_schema, analyze_schema, wait_on_pending_dml,\nRem and expand_sql_text procedures. This package is not run-as-caller\nRem w.r.t. SQL (psdpgi.c) so that the SQL works correctly (runs as\nRem SYS). The privileges are checked via dbms_ddl.</pre>\n<p>&nbsp;</p>\n<p>That function calls a C function (KSPGPNICD) so we don&#8217;t know what happens behind. If you sql_trace it, you don&#8217;t see anything about V_$PARAMETER.</p>\n<p>But privilege analysis show the required privileges anyway, and that rocks.</p>\n",
    "protected": false
  }
}
