Security Advisory |
This package contains BASE64, Mime, Text, and UU encode and decode RAW data string functions that encode data into a standard encoded format so that the data can be transported between hosts.
This package's objects can be used to encode the body of email text. The package also contains the decode counterpart functions of the encode functions.
The functions follow published standards for encoding to accommodate non-Oracle utilities on the sending or receiving ends. |
|
Recommended Security Rules |
NEVER
- Let any user or schema without documented justification or escalated privileges
gain access to this package by revoking EXECUTE from PUBLIC
WITH GREAT CARE
- Identify legitimate requirements for access to this package and
grant EXECUTE explicitly to only justified schemas
- Query the data dictionary after EXECUTE has been revoked from PUBLIC to verify the equivalence created is the equivalence approved by IT management and your CISO
CAUTIONS
- Some usage may be in the form of dynamic SQL so carefully verify usage requirements in source code as well as in DBA_DEPENDENCIES
|
|
How Oracle Works |
How Oracle intended UTL_ENCODE to be utilized.
The demo at right copied from Erik Wramner's blog. A few small edits made to comply with our site guidelines. |
CREATE OR REPLACE PACKAGE utl_base64 AUTHID DEFINER IS
FUNCTION decode_base64(p_clob_in IN CLOB) RETURN BLOB;
FUNCTION encode_base64(p_blob_in IN BLOB) RETURN CLOB;
END;
/
CREATE OR REPLACE PACKAGE BODY utl_base64 IS
--------------------------------------------------------
FUNCTION decode_base64(p_clob_in IN CLOB) RETURN BLOB IS;
v_buffer_size CONSTANT BINARY_INTEGER := 48;
v_blob BLOB;
v_result BLOB;
v_offset INTEGER;
v_buffer_varchar VARCHAR2(48);
v_buffer_raw RAW(48);
BEGIN
IF p_clob_in IS NULL THEN
RETURN NULL;
END IF;
dbms_lob.createtemporary(v_blob, TRUE);
v_offset := 1;
FOR i IN 1 .. ceil(dbms_lob.getlength(p_clob_in) / v_buffer_size) LOOP
dbms_lob.read(p_clob_in, v_buffer_size, v_offset, v_buffer_varchar);
v_buffer_raw := utl_raw.cast_to_raw(v_buffer_varchar);
v_buffer_raw := utl_encode.base64_decode(v_buffer_raw);
dbms_lob.writeappend(v_blob, utl_raw.length(v_buffer_raw), v_buffer_raw);
v_offset := v_offset + v_buffer_size;
END LOOP;
v_result := v_blob;
dbms_lob.freetemporary(v_blob);
RETURN v_result;
END decode_base64;
--------------------------------------------------------
FUNCTION encode_base64(p_blob_in IN BLOB) RETURN CLOB IS
v_chunk_size CONSTANT BINARY_INTEGER := (48/4)*3;
v_clob CLOB;
v_result CLOB;
v_offset INTEGER;
v_buffer_varchar VARCHAR(48);
v_buffer_raw RAW(48);
BEGIN
IF p_blob_in IS NULL THEN
RETURN NULL;
END IF;
dbms_lob.createtemporary(v_clob, TRUE);
v_offset := 1;
FOR i IN 1 .. CEIL(dbms_lob.getLength(p_blob_in) / v_chunk_size) LOOP
dbms_lob.read(p_blob_in, v_chunk_size, v_offset, v_buffer_raw);
v_buffer_raw := utl_encode.base64_encode(v_buffer_raw);
v_buffer_varchar := utl_raw.cast_to_varchar2(v_buffer_raw);
dbms_lob.writeappend(v_clob, length(v_buffer_varchar), v_buffer_varchar);
v_offset := v_offset + v_chunk_size;
END LOOP;
v_result := v_clob;
dbms_lob.freetemporary(v_clob);
RETURN v_result;
END encode_base64;
--------------------------------------------------------
END;
/ |
How UTL_ENCODE can be utilized by an attacker |
The following demo code is from the BASE 64 exploit page here at DBSecWorx
DECLARE
r RAW(32767);
sqlStr VARCHAR2(60);
BEGIN
r := utl_raw.cast_to_raw('SELECT dummy FROM dual');
dbms_output.put_line(r);
r := utl_encode.base64_encode(r);
dbms_output.put_line(r);
execute immediate
utl_raw.cast_to_varchar2(utl_encode.base64_decode(r)) INTO sqlStr;
dbms_output.put_line(sqlStr);
END;
/
53454C4543542064756D6D792046524F4D206475616C
5530564D52554E55494752316257313549455A53543030675A48566862413D3D
X
PL/SQL procedure successfully completed.
There are further examples of using this package available: Click on the Base 64 Exploit link at page bottom. |
|
UTL_ENCODE Package Information |
AUTHID |
DEFINER |
Constants |
Name |
Data Type |
Value |
base64 |
PLS_INTEGER |
1 |
complete (header & footer) |
PLS_INTEGER |
1 |
end_piece (includes footer text) |
PLS_INTEGER |
4 |
header_piece (includes heaer text) |
PLS_INTEGER |
2 |
middle_piece (body text only) |
PLS_INTEGER |
3 |
quoted_printable |
PLS_INTEGER |
2 |
|
Dependencies |
DBMS_AW_EXP |
DBMS_ISCHED_REMOTE_ACCESS |
UTL_MAIL |
DBMS_ISCHED |
UTL_ENC_LIB |
UTL_SMTP |
|
Documented |
Yes |
First Available |
9.0.1 |
Security Model |
Owned by SYS with EXECUTE granted to PUBLIC |
Source |
{ORACLE_HOME}/rdbms/admin/utlenc.sql |
Subprograms |
|
|
BASE64_DECODE |
Reads the base 64-encoded RAW input string and decodes it to its original RAW value |
utl_encode.base64_decode(r IN RAW) RETURN RAW; |
See base64_encode Demo Below |
|
BASE64_ENCODE |
Encodes the binary representation of the RAW value into base 64 elements and returns it in the form of a RAW string |
utl_encode.base64_encode(r IN RAW) RETURN RAW; |
set serveroutput on
DECLARE
r RAW(32767);
BEGIN
r := utl_raw.cast_to_raw('University of Washington');
dbms_output.put_line(r);
r := utl_encode.base64_encode(r);
dbms_output.put_line(r);
r := utl_encode.base64_decode(r);
dbms_output.put_line(r);
END;
/
556E6976657273697479206F662057617368696E67746F6E
56573570646D567963326C30655342765A69425859584E6F6157356E64473975
556E6976657273697479206F662057617368696E67746F6E
PL/SQL procedure successfully completed. |
|
MIMEHEADER_DECODE |
Decodes a string from mime header format |
utl_encode.mimeheader_decode(buf IN VARCHAR2 CHARACTER SET ANY_CS)
RETURN data VARCHAR2 CHARACTER SET buf%CHARSET; |
See mimeheader_encode Demo Below |
|
MIMEHEADER_ENCODE |
Encodes a string into mime header format |
utl_encode.mimeheader_encode(
buf IN VARCHAR2 CHARACTER SET ANY_CS,
encode_charset IN VARCHAR2 DEFAULT NULL,
encoding IN PLS_INTEGER DEFAULT NULL);
RETURN string VARCHAR2 CHARACTER SET buf%CHARSET; |
set serveroutput on
DECLARE
t VARCHAR2(100);
BEGIN
t := utl_encode.mimeheader_encode('MLIB');
dbms_output.put_line(t);
t := utl_encode.mimeheader_decode(t);
dbms_output.put_line(t);
END;
/
=?UTF-8?Q?MLIB?=
MLIB |
|
QUOTED_PRINTABLE_DECODE |
Reads the varchar2 quoted printable format input string and decodes it to the corresponding RAW string |
utl_encode.quoted_printable_decode(r IN RAW)
RETURN RAW; |
See quoted_printable_encode Demo Below |
|
QUOTED_PRINTABLE_ENCODE |
Reads the RAW input string and encodes it to the corresponding quoted printable format string |
utl_encode.quoted_printable_encode(r IN RAW)
RETURN RAW; |
set serveroutput on
DECLARE
r RAW(32767);
BEGIN
r := utl_raw.cast_to_raw('Begin' || chr(13) || 'End');
dbms_output.put_line(r);
r := utl_encode.quoted_printable_encode(r);
dbms_output.put_line(r);
r := utl_encode.quoted_printable_decode(r);
dbms_output.put_line(r);
END;
/
426567696E0D456E64
426567696E3D3044456E64
426567696E0D456E64 |
|
TEXT_DECODE |
Decodes a character set sensitive text string |
utl_encode.text_decode(
buf IN VARCHAR2 CHARACTER SET ANY_CS,
encode_charset IN VARCHAR2 DEFAULT NULL,
encoding IN PLS_INTEGER DEFAULT NULL)
RETURN string VARCHAR2 CHARACTER SET buf%CHARSET; |
See text_encode Demo Below |
|
TEXT_ENCODE |
Encodes a character set sensitive text string |
utl_encode.text_encode(
buf IN VARCHAR2 CHARACTER SET ANY_CS,
encode_charset IN VARCHAR2 DEFAULT NULL,
encoding IN PLS_INTEGER DEFAULT NULL)
RETURN string VARCHAR2 CHARACTER SET buf%CHARSET; |
set serveroutput on
DECLARE
c VARCHAR2(100);
BEGIN
c := utl_encode.text_encode('Here is some text', 'WE8ISO8859P1', UTL_ENCODE.BASE64);
dbms_output.put_line(c);
END;
/
SGVyZSBpcyBzb21lIHRleHQ=
DECLARE
c VARCHAR2(100);
BEGIN
c := utl_encode.text_decode('SGVyZSBpcyBzb21lIHRleHQ=',
'WE8ISO8859P1', UTL_ENCODE.BASE64);
dbms_output.put_line(c);
END;
/
Here is some text |
|
UUDECODE |
Reads the RAW uuencode format input string and decodes it to the corresponding RAW string |
utl_encode.uudecode(r IN RAW) RETURN RAW; |
See uuencode Demo Below |
|
UUENCODE |
Reads the RAW input string and encodes it to the corresponding uuencode format string |
utl_encode.uuencode(
r IN RAW,
type IN PLS_INTEGER DEFAULT 1,
filename IN VARCHAR2 DEFAULT NULL,
permission IN VARCHAR2 DEFAULT NULL)
RETURN RAW; |
set serveroutput on
DECLARE
r RAW(32767);
BEGIN
r := utl_encode.uuencode('ABCFED', 1, 'uuencode.txt', 0);
dbms_output.put_line('Encoded: ' || r);
r := utl_encode.uudecode(r);
dbms_output.put_line('Decoded: ' || r);
END;
/
Encoded:
626567696E2030207575656E636F64652E7478740D0A244A5C5F4D0D0A0A656E64
Decoded: ABCFED |