Datastore exploration in RES Automation Manager – Part 4
Previous queries, exploring binary fields in the datastore, skipped the tables tblResources, tblTasklets, and tblQueryImages. This assumed the columns with a binary datatype in these tables were unlikely to contain ‘hidden’ properties which started this exploration in the first place. According to the official styleguide of the internet, pretentious use of an unverified quote is in order:
“Your assumptions are your windows on the world. Scrub them off every once in a while, or the light won’t come in.”
― Isaac Asimov
Initiate scrubbing:
tblResources
This is where the resources are stored, and shows all the usual suspects in columns with predictable types; GUID, Filename, Enabled, Size, CRC, etc etc. But does it really hold resources? That imgInfo column looks suspicious.. and as it turns out contains even more XML. Apparently the lngType indicates the type of resource and they each get their own bit of XML.
Type | XML Example |
---|---|
[0] In Datastore | |
[1] On Fileshare | |
[3] Resource Package |
Another interesting use case of XML in the database, makes me wonder why resource packages are stored as they are. But wait, a password field?! It doesn’t look like my password. Is it encrypted? If so how? Quite eager to try out those techniques I read about in my cryptography 101 textbook! Considering we can input arbitrary strings and have AM convert it to it’s encrypted form, this should be relatively straightforward.
Let’s start by systematically gathering some data. I have created several resources, as a link, from the same file, using the same userid, but a different password. I put that same password in the description field for reference and with the following query we can obtain a list of plain text and encrypted passwords.
I have formatted the output a little for clarification.
PlainText | CipherText |
---|---|
a | 00D3 |
aa | 00D3 00C2 |
aa | 00D3 00C2 |
aaaaaaaaaaaaaaaa | 00D3 00C2 00CA 00CD 00A8 00D3 00C2 00CA 00CD 00A8 00D3 00C2 00CA 00CD 00A8 00D3 |
ab | 00D3 00C3 |
abc | 00D3 00C3 00CC |
abcd..xyz | 00D3 00C3 00CC 00D0 00AC 00D8 00C8 00D1 00D5 00B1 00DD 00CD 00D6 00DA 00B6 00E2 00D2 00DB 00DF 00BB 00E7 00D7 00E0 00E4 00C0 00EC |
ABCD..XYZ | 00B3 00A3 00AC 00B0 008C 00B8 00A8 00B1 00B5 0091 00BD 00AD 00B6 00BA 0096 00C2 00B2 00BB 00BF 009B 00C7 00B7 00C0 00C4 00A0 00CC |
So, immediately we can see the length of the ciphertext is 4 times that of the plain text. The ciphertext seem to be hexadecimal values and repeats every 5 characters worth of plain text. This thing has all the characteristics of a classic Vigenère cipher with a key of length 5. To figure out the key I wrote some snippets of Python. First step is having a couple of lists with plaintext and ciphertext:
So basically each character is stored as a 16-bit unit (a.k.a wyde), represented as a hexadecimal string of length 4. This helper function will transform any encrypted string with such an encoding to a list of values:
Output:
0 : 211 1 : 194 2 : 202 3 : 205 4 : 168
The next step is to take the difference of this value with the code point of the plaintext character. Although the output is not particularly nicely formatted I hope it makes some sense.
Output:
Char : Enc - Val = Diff a : 211 - 097 = 114 -> r b : 195 - 098 = 097 -> a c : 204 - 099 = 105 -> i d : 208 - 100 = 108 -> l e : 172 - 101 = 071 -> G f : 216 - 102 = 114 -> r g : 200 - 103 = 097 -> a h : 209 - 104 = 105 -> i i : 213 - 105 = 108 -> l j : 177 - 106 = 071 -> G k : 221 - 107 = 114 -> r l : 205 - 108 = 097 -> a m : 214 - 109 = 105 -> i n : 218 - 110 = 108 -> l o : 182 - 111 = 071 -> G p : 226 - 112 = 114 -> r q : 210 - 113 = 097 -> a r : 219 - 114 = 105 -> i s : 223 - 115 = 108 -> l t : 187 - 116 = 071 -> G u : 231 - 117 = 114 -> r v : 215 - 118 = 097 -> a w : 224 - 119 = 105 -> i x : 228 - 120 = 108 -> l y : 192 - 121 = 071 -> G z : 236 - 122 = 114 -> r
Bingo! I mean .. railG! but even more likely, the key is ‘Grail’ and we are just having some off by one thing going on. Because I fully expect to encounter similar encryption to be found elsewhere in the software, let’s create encryption/decryption functions, this will also help us in confirming the hypothesis. After all, our sample size is small and theoretically there could be some wildly more complex encryption going on which just happens to show this exact behavior in our chosen examples.
Output:
Encrypted : 00BA00C600E20098006700E900C200DD00CF00AF00D3008100DB00D100A800D600CA00D70093006700D800D000DB00AB Decrypted : Hey, watcha readin' for?
So, I may have upset some people with my blatant disregard for Pythonic coding standards. Perhaps, but the code runs and I made a new friend in the Jupyter iPython Notebook. Pretty cool stuff if you ask me. I mean iPython, not 16th century ciphers with a key of length 5 ‘protecting’ my passwords.
Update
Running the decryption on a bunch of stuff in the database, I found that the same cipher is used for storing credentials in modules. However not all of them use the same key, but with some help of the notebook it is trivial to figure out what they are. I created a number of different tasks in AM, using the same password and ran them through the iPython notebook I created earlier. The encrypted passwords are stored in XML in the imgTasks column in the tblModules table.
XPath in imgData1 (tblModules) | Key(s) |
---|---|
/tasks/task/settings/dbpassword | SQLScript |
/tasks/task/settings/domain/domainpassword | DomUserPass |
/tasks/task/settings/fileoperationtask/securitycontext/password | FileOps |
/tasks/task/settings/password | Grail |
17FiLeVerSioN1988 | |
77DepLoyComPoNent14 | |
ActiveDirectory | |
Dune2 | |
R3SWFsTuD10 | |
RES=Gold | |
Send@Mail | |
SSHCommands | |
TaskDomain | |
WebService |
I’ll leave it up to you to guess which tasks use which key. Also, this list is by no means exhaustive, there were some tasks I could not easily create because the target service is not available in my test environment. I looked for strings in the executable and found some other likely keys.. ‘LANDesk’, ‘SoftGrid’, ‘MicSCCM’, and ‘VirtualInfrastructure’ however since I did not test these myself I cannot be 100% certain.