This is my third blog post about DB Link encryption/decryption.In the first one i demonstrated how we can find the database link password in clear text using GDB and Intel pin tools.In the second one i have given more information about how it was encrypted/decrypted (AES in CBC encryption mode).It’s now time to reverse engineer it !
NOTE : All the test are done in oracle 12.1.0.2.6/OEL6/UEK4
Update 08/03/2017 : The script also work in oracle 12.2.0.1
As explained in my previous post to decrypt the password we need three things.
- Initialization vector
- Ciphertext
- Encryption Key
After some investigation it appeared that this parameters are not depending only on “PASSWORDX” of “sys.link$” but also in two other parameters :
- NO_USERID_VERIFIER_SALT in table sys.props$ (Database dependent).
SELECT VALUE$ FROM SYS.PROPS$ WHERE name = 'NO_USERID_VERIFIER_SALT';
- Variable “ztcshpl_v6” fixed across different databases(note:same value in 11.2.0.4 was named ztcshpl_v6.0)
readelf -s oracle | grep ztcshpl_v6
112105: 0000000010b9ee40 16384 OBJECT LOCAL DEFAULT 29 ztcshpl_v6
Here is some info about how this different parameters combine :
- Initialization vector : Using the second byte of passwordx to lookup in ztcshpl_v6
- Ciphertext : Using ztcshpl_v6 and passwordx
- Encryption Key : Calculated as a XOR between two keys :
- Key 1 : Using ztcshpl_v6 and passwordx
- Key 2 : Hash sha256 of NO_USERID_VERIFIER_SALT
Installation : (This script use Connor McDonald Package “bitops2” for bit operation like “XOR” bitops2.bitxor )
- Download and install : bitops2.sql
- Download and install : db_link_password_decrypt.sql
Update 08/03/2017 : the script bitops2.sql is not needed any more just install db_link_password_decrypt.sql
Time for a DEMO :
The procedure “db_link_password_decrypt” take two parameters :
- NO_USERID_VERIFIER_SALT of your database
- passwordx from sys.link$
Let’s create two database link and test it !
CREATE DATABASE LINK HATEM_TEST1 CONNECT TO HATEM IDENTIFIED BY "you_can_not_hide_from_me" USING 'testdb'; CREATE DATABASE LINK HATEM_TEST2 CONNECT TO HATEM IDENTIFIED BY "oups%you$found_me" USING 'testdb';
Password decryption :
First Database Link :
exec db_link_password_decrypt('17B21F905CE739E2759E6FB99745650E','076C8B8463098676 E408141A154CF4C20AAF19A52CF7FEF3CD8A99830A82F9D8F129665C2F395DF4F30EBE1 5E48D78096E9BD8AC1012D24525982CE3C828BE298EA798D6FBD8A18379DEE803692B 773B86570AB2DA90EA121124D6D0F228818D18812B42C77AE6D0F4BF257627643EEC34F B9A6C2EF6185D7302EF30673A2F4C');
Second Database Link :
exec db_link_password_decrypt('17B21F905CE739E2759E6FB99745650E','072D8692F86F55A14 96141309CBEED0DFF2F03D90B3EBF1E3AE7518DAF66B768DC171779ECB7A8546C19AD83A1CF0878667D 22EC9550AD8785E8A3A48016883C8CA085E87A6121462825FEF94866EC8869E04F0E5D73FAB39A005A 09EA98945B43C06F48B2DD8E1D6943AA693C36E945B005464EF13C257F6D085530C5D038AC');
UPDATE 25/05/2018 : The script can now be run from sqlplus and the noise from the recovered value has been eliminated. Thanks Adric Norris for you contribution.
That’s it 😀
Thanks for sharing such a wonderful information really very good points were stated in the blog
i have oracle version :
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 – Production
PL/SQL Release 11.2.0.3.0 – Production
CORE 11.2.0.3.0 Production
TNS for Linux: Version 11.2.0.3.0 – Production
NLSRTL Version 11.2.0.3.0 – Production
I Got error when I run db_link_password_decrypt.sql
“PROCEDURE HRPROD.DB_LINK_PASSWORD_DECRYPT
On line: 37
PLS-00302: component ‘HASH_SH256’ must be declared”
how to solve this ?
thanks in advance
for someone not very deep into “playing with bytes”
– how did you come from readelf output to your very long number in plsql ?
For me in 12.1.0.4 seems not to work and only the in doubt input is ztcshpl_v6″.
Hi basile , I used gdb and the command x to examine the memory address content and as stated i only tested in specific oracle versions/platform so it may need some adjustment for other versions.The idea here is to show what can be done 🙂
Just Amazing! 🙂
Tested it on a 12.1.0.2 database on windows and it worked!!
This script cannot be run using SQLPLUS which has a limit of 2000 characters per line.
I used Oracle SQLCL which doesn’t have that limitation.
Thanks ! I’m glad you like it 🙂
script returns no output. im running against 12.1.0.2 in a linux environment. procedure was created with errors.
any thoughts?
[…] existiert mittlerweile eine Möglichkeit der Entschlüsselung, da das Passwort nicht geheim zu halten […]
[…] Update 23.11.2017: Es findet eine Verschlüsselung, keine Hash-Wert-Berechnung, des Link-Passwortes statt, und diese lässt sich brechen. […]
i have oracle version :
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 – Production
PL/SQL Release 11.2.0.3.0 – Production
CORE 11.2.0.3.0 Production
TNS for Linux: Version 11.2.0.3.0 – Production
NLSRTL Version 11.2.0.3.0 – Production
I Got error when I run db_link_password_decrypt.sql
“PROCEDURE HRPROD.DB_LINK_PASSWORD_DECRYPT
On line: 37
PLS-00302: component ‘HASH_SH256’ must be declared”
how to solve this ?
thanks in advance
Hi the script was not tested in 11.2.0.3.0 also there is no HASH_SH256 in DBMS_CRYPTO in this version.
Very cool findings, congrats.
Just a comment, if the reason for learning the password is just recreating the db links under a different schema, expdp/impdp could help, pasted a link, perhaps it helps others.
http://askdba.org/weblog/2009/01/recreating-database-link/
@hatem-mahmoud
It turns out that the binary value of the first decrypted byte indicates the plaintext password length, which makes it possible to eliminate the noise from the recovered value. I’ve submitted a PR which adds this tweak.
Thanks for your contribution 🙂 i just reviewed and merged them !
Minor clarification… the length component indicates the number of *bytes* used by the plaintext password, rather than characters. So if the password is set to “€”, for example, the length will indicate 3 (since it’s a 3-byte UTF-8 character) rather than 1.
This doesn’t make any functional difference to the PR which you merged, as it already handles the scenario correctly, but does mean that my commit message was slightly misleading.
What should I do if there is no DBMS_CRYPTO.HASH_SH256 in 11.2.0.4?
The only workaround I’m aware of is to import the dblink (via datapump) into a 12.x database, and then decrypt it there.
Great stuff, I like it.
But there is no error handling in case passwordx is NULL.
Hi,
I have problem :
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at “SYS.UTL_RAW”, line 380
ORA-06512: at “SYS.DB_LINK_PASSWORD_DECRYPT”, line 92
ORA-06512: at line 1
can you help me ?
Martin
all above error need to solve like
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at “SYS.UTL_RAW”, line 380
ORA-06512: at “SYS.DB_LINK_PASSWORD_DECRYPT”, line 92
ORA-06512: at line 1
is no DBMS_CRYPTO.HASH_SH256 not available ?
nothing is working
What’s your database version? This approach only works on 12.x (and later, presumably).
Sorry for the noise… I inadvertently unsubscribed from comments on this post.
Hi ,
I’m getting eror:
Error at line 1
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at “SYS.UTL_RAW”, line 380
ORA-06512: at “SYS.DB_LINK_PASSWORD_DECRYPT”, line 99
ORA-06512: at line 1
select * from v$version;
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 – 64bit Production
PL/SQL Release 12.2.0.1.0 – Production
CORE 12.2.0.1.0 Production
TNS for Solaris: Version 12.2.0.1.0 – Production
NLSRTL Version 12.2.0.1.0 – Production
If second byte of passwordx less the 7, you will get error:
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at “SYS.UTL_RAW”, line 380
Sorry i haven’t gotten the time to check it further : Can you please try replacing this line
———————————
output_string := UTL_I18N.RAW_TO_CHAR ( utl_raw.substr( decrypted_raw, 2,
to_number( rawtohex( utl_raw.substr( decrypted_raw, 1, 1 ) ), ‘XX’ )
)
);
———————————
with
——————————–
output_string := UTL_I18N.RAW_TO_CHAR (decrypted_raw, ‘AL32UTF8’);
——————————–
and retry
Thanks for reply…
I got following error with replacing output_string :
Error at line 1
ORA-01890: NLS error detected
ORA-06512: at “SYS.UTL_I18N”, line 72
ORA-06512: at “SYS.UTL_I18N”, line 353
ORA-06512: at “SYS.DB_LINK_PASSWORD_DECRYPT”, line 100
ORA-06512: at line 1
Try removing the src_charset : output_string := UTL_I18N.RAW_TO_CHAR (decrypted_raw) ; see also (Doc ID 2456883.1) (i don’t have access to oracle support so haven’t read it)
Changing the line to: output_string := UTL_I18N.RAW_TO_CHAR (decrypted_raw);
Result on sqlplus empty screen.
With sqlclient:
coranew:/home/oracle >cat dec.sql | sql / as sysdba
SQLcl: Release 12.2.0.1.0 RC on Mon May 27 11:16:29 2019
Copyright (c) 1982, 2019, Oracle. All rights reserved.
Connected to:
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 – 64bit Production
Procedure DB_LINK_PASSWORD_DECRYPT compiled
PL/SQL procedure successfully completed.
129
Disconnected from Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 – 64bit Production
coranew:/home/oracle >
The initial problem comes from UTL_RAW I guess. I think you have to cast it.
Worked like a charm for me, Oracle 12.1.0.2.0.
Thanks, you saved my day!
Got a ORA-31603: object “SYS_HUB” of type DB_LINK not found in schema “PUBLIC” on 19.3.0.0.0. Just testing.
Thanks ! I havent tested it yet on oracle 19c i will take a closer look when i have time
Hi,
Database version —
SQL> select * from v$version;
BANNER CON_ID
——————————————————————————– ———-
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 – 64bit Production 0
PL/SQL Release 12.2.0.1.0 – Production 0
CORE 12.2.0.1.0 Production 0
TNS for 64-bit Windows: Version 12.2.0.1.0 – Production 0
NLSRTL Version 12.2.0.1.0 – Production 0
I am receving below error when i tried to decrypt after creating the procedure as it was..
output_string := UTL_I18N.RAW_TO_CHAR ( utl_raw.substr( decrypted_raw, 2,to_number( rawtohex( utl_raw.substr( decrypted_raw, 1, 1 ) ), ‘XX’ )));
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at “SYS.UTL_RAW”, line 380
ORA-06512: at “SYS.DB_LINK_PASSWORD_DECRYPT”, line 94
ORA-06512: at line 1
Per your comments and DOC ID – UTL_I18N.RAW_TO_CHAR Is Failing With ORA-01890 In 12.2 When src_charset Value Is Different From DB Character Set (Doc ID 2456883.1), I tried below options but still i don’t see the password in plain text. Please assist.
output_string := UTL_I18N.RAW_TO_CHAR (decrypted_raw, ‘AL32UTF8’);
Decrypted string: ┐┐9eA┐┐┐┐┐┐R┐┐+0┐\┐^y
output_string := UTL_I18N.RAW_TO_CHAR (decrypted_raw, ‘WE8MSWIN1252’);
Decrypted string: ┘e╟ê9eA╥╛τén∩Tó╟▌╨j╬┼Rƒü+0║\╙ÿ^y
output_string := UTL_I18N.RAW_TO_CHAR (decrypted_raw);
Decrypted string: ┘e╟ê9eA╥╛τén∩Tó╟▌╨j╬┼Rƒü+0║\╙ÿ^y
Thanks.
thanks
work perfectly on oracle 19.3
Hello guys, need some help, trying to execute, the procedure was created without errors, when i execute it returns no output and no errors.
version 12.2.0.1
Thanks
Forget it, just found the problem
set serveroutput on;
Thanks
Just for your information, the first byte of passwordx gives the version of the algorithm that generated its value : 0x05 for pre-11.2.0.2 version, 0x06 for 11.2.0.2 to 11.2.0.4 versions, and 0x07 for 12.1 to 19.8 versions.
Your code, many thanks for it, is for the 0x07 algorithm (and works all 12-19 versions) and can’t decrypt 0x06 ciphered values. It then returns the previously reported error (same one in all these versions) :
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at “SYS.UTL_RAW”, line 380
I don’t know the differences between the 0x06 and 0x07 algorithm. A clue may be that, as some saw, HASH_SHA256 did not exist in these 11.2 versions but this is not the only point (changing to SH1 or MD5 is not sufficient to get the result). Same thing when you just change for another older encryption algorithm (AES128 or AES192 for instance).
Thanks
Great ! Thanks for the info 🙂
Hi!,
I’ve tried it with Oracle 19.9 versión and it seems it doesn’t work.
set serveroutput on;
exec db_link_password_decrypt(’61FE9A498A8FB6995B77028E02D6C276′,’06661EA2BB2519883DF747A386F1045E46E8F723BB5ABBC22550A7E8F179EFDCA688F89205C5FAC18F56A8CFF797810C06B9B353CAF4655324B3A77088E288E0ACD63FE0965DF0A185BE62FD584BCDE23268B4B82678469846AFA9E06F5092A4535BFFF8D06681E0132A30CC97AF3906DA1A49CC52A8CBF25767462EAD5270F’);
SQL> ———-Decrypting DB Link password————–
Initialization_vector :
01000400010000010000000501010101
—————————————————
Ciphertext :
AC3F5DA1BEFD68B82646AFA9E0535BFFD066E0132ACC97AF06DA1ACC52574652
—————————————————
Encryption key part 1 :
A2BBF74786F10446E8F72350E879DC88C5FAC1CFF7978106B9B353CAA770E288
Encryption key part 2 :
9E551FEB0674CE5E799F17327B3D8D24B0771E289DE525E6F86A52635D05438E
—————————————————
Encryption key (Part 1 XOR Part 2) :
3CEEE8AC8085CA1891683462934451AC758DDFE76A72A4E041D901A9FA75A106
—————————————————
Decrypted string: u!?J(oc?
K` “Nca?I? G =?e ?E
Decrypted string: FBA1B24A28F2634F7F850B4B602012224E63E4069CCFB00047A03DF7EAA08745
PL/SQL procedure successfully completed.
Decrypted string isn’t the correct password.
Workaround about output_string is applied:
output_string := UTL_I18N.RAW_TO_CHAR (decrypted_raw) ;
Thanks!
I didn’t install 19.9 yet but it seems they fixed the “ORA-06502: PL/SQL: numeric or value error”.
Regards
First line of my reply hasn’t been posted here it is:
“Read my previous reply about first byte of passwordx and 0x06 algorithm.”
Regards
Michel
Hi Michel ,
Thanks for yout reply, If the workaorund with UTL_I18N.RAW_TO_CHAR is not aplied the error “ORA-06502: PL/SQL: numeric or value error” is raised in 19.9.
This database was upgraded from 11.2.0.4 to 19.9.0.0 but the db_link was created after upgrade process in 19.9.
Anyway it seems that the algorithm is 0x06 and not 0x07.
select PASSWORDX from sys.link$ where NAME=’DBL’;
PASSWORDX
——————————————————————————————————————————————-
06661EA2BB2519883DF747A386F1045E46E8F723BB5ABBC22550A7E8F179EFDCA688F89205C5FAC18F56A8CFF797810C06B9B353CAF4655324B3A77088E288E0ACD63FE0965
D06681E0132A30CC97AF3906DA1A49CC52A8CBF25767462EAD5270F
PROPERTY_NAME PROPERTY_VALUE
———————– —————————–
NO_USERID_VERIFIER_SALT 61FE9A498A8FB6995B77028E02D6C276