Thursday, June 22, 2006

Recovering Pocket Outlook passwords, part 2

Having a BLOB

Now, it is time to recover the password from the protected BLOB. First step is to get a valid BLOB, we do that by setting a breakpoint just before and just after CryptProtectData().

Before:

BLOB = {
size=0x0A (10)
data=L"toto"
}


After:

BLOB = {
size=0x7E (126)
data=
00075C40 DCD 1
00075C44 DCD 0
00075C48 DCD 0
00075C4C DCD 0
00075C50 DCD 0
00075C54 DCD 0x20000000
00075C58 DCD 0
00075C5C DCD 0x6801
00075C60 DCD 0x10
00075C64 DCD 0x10
00075C68 DCD 0xFD7C53C
00075C6C DCD 0x5CD8C0A3
00075C70 DCD 0x7A39FA3F
00075C74 DCD 0xDA8959BD
00075C78 DCD 0
00075C7C DCD 0x8004
00075C80 DCD 0x10
00075C84 DCD 0x10
00075C88 DCD 0x65412C18
00075C8C DCD 0x6EDAE82
00075C90 DCD 0xE76ADC3
00075C94 DCD 0xC909937A
00075C98 DCD 0xA
00075C9C DCD 0x720053C6
00075CA0 DCD 0x6CD865A4
00075CA4 DCD 0x14C609
00075CA8 DCD 0xD5870000
00075CAC DCD 0x87F4EAE5
00075CB0 DCD 0xCBB1CE52
00075CB4 DCD 0x19CDF0BB
00075CB8 DCD 0xCC3F1E90
00075CBC DCD 0xCB6D

Finding password store

Since passwords survive a reboot, this BLOB has to be stored somewhere in a persistent storage area. Under Windows CE 4.2, the most common way to do this is to use a Database.

Having a look at system databases (using HPC Database Viewer for example), we quickly find that the BLOB is stored in the "pMailFolders" database, with property identifier #0x8304.

Getting the password back

There are several steps to retrieve a cleartext password:
  • Getting the BLOB out of the Database ;
  • Calling CryptUnprotectData() correctly.
Let's write a little piece of code that does both. Surprisingly, it works out of the box! That means that the CRYPTPROTECT_SYSTEM flag is not enforced by the kernel in my case!

In case CryptUnprotectData() fails, here are some tricks that could work:
  • Calling COREDLL!SetProcPermissions(-1) ;
  • Traditional WriteProcessMemory()/CreateRemoteThread() combination ;
  • Understanding the CryptoAPI BLOB format, for hand decryption.
If you want to know more ... just send me PDA's :)

Greets: mao from oxid.it

Monday, June 19, 2006

Recovering Pocket Outlook passwords, part 1

What are we doing here ?

We are trying to recover stored passwords inside a Windows Mobile PDA. The target configuration is:
  • Software: Windows Mobile 2003 1st Ed.
  • Hardware: HP iPaq 5550 w/ French ROM v1.10
  • Tools: IDA Pro 5.0 w/ WinCE Debugging Module, ITSME tools

Analysis

Looking for an entry point

"Pocket Outlook" is named internally the "TMAIL.EXE" application. One way to begin the analysis is to look for the "save password" checkbox inside resources. However, "TMAIL.EXE" has few resources and many dependencies. Having a closer look, it appears that all resources are located inside "OUTRES.DLL". This is not an explicit dependency, for it is loaded through a LoadLibraryW() call.

Two dialogs have the "save password" checkbox: #32803 and #32955.

At some point, the application will have to get the password value from the textbox. This is where debugging comes into play. There are only 10 references to GetDlgItemTextW() - it seems easy to put 10 breakpoints and narrow down the search.

Debugging TMAIL.EXE

However TMAIL.EXE is a ROM application, so no breakpoint can be set! The trick here is to kill the running TMAIL.EXE application and have the TMAIL.EXE application running from Flash memory.

Z:\TMAIL Reversing\ITSME tools\itsutils\build>pps
handle n base kern user heap exe
13878f82 1 1c000000 0.0 0.0 0 Notes.exe
1395a67e 5 16000000 0.0 0.0 0 DM_k.exe
13a27efe 2 12000000 0.0 0.0 0 BTTrayCE.exe
13c528fe 5 0a000000 0.0 0.0 0 srvtrust.exe
13cfa6de 15 06000000 0.0 0.0 0 gwes.exe
13fb7002 1 c2000000 0.0 0.0 0 NK.EXE
337a1d4a 5 22000000 0.0 0.0 0 tmail.exe -RunInBKG
33809952 3 1a000000 0.0 0.0 0 repllog.exe /remote /all /h /p:all
33ef189a 1 14000000 0.0 0.0 0 BioDetect.exe
5346547e 1 1e000000 0.0 0.0 0 calc.exe
53f47e5e 67 08000000 0.0 1.9 0 device.exe
73c578c6 5 0c000000 0.0 0.0 0 shell32.exe
73f8e822 6 04000000 0.0 0.0 0 filesys.exe
9335818e 3 26000000 0.0 0.0 0 udp2tcp.exe
93405292 1 28000000 0.0 0.0 0 cerdisp.exe
934dd936 4 20000000 0.0 13.0 0 rapisrv.exe
b395afd6 5 18000000 0.0 0.0 0 poutlook.exe
b3c577d6 2 10000000 0.0 0.0 0 connmgr.exe
f340541e 2 24000000 0.0 0.0 0 rnaapp.exe -n -m -e"`USB Default"
f3c5790e 5 0e000000 0.0 0.0 0 services.exe
60
0 ........ 0.0 14.9 0 total

Z:\TMAIL Reversing\ITSME tools\itsutils\build>pkill tmail.exe

00000000 | tmail.exe killed


Now we can see that the "good" call is coming from some sub @ 0x3AEE8.

Tracing further

GetDlgItemTextW() prototype is the following (including registers used in ARM calling convention):

UINT GetDlgItemText( [R0] HWND hDlg, [R1] int nIDDlgItem, [R2] LPTSTR lpString, [R3] int nMaxCount );

R1 will take the following values:
  • 0x805B account name
  • 0x805C login name
  • 0x805D password
Now we have to track the use of the password string. Placing a hardware read breakpoint on it, we are interrupted inside COREDLL with the following call stack: COREDLL <- wcslen() <- sub_355D8().

The heart of it all

A few lines below lays what we were looking for: a CryptProtectData() call!

CryptProtectData() prototype is the following (including registers used in ARM calling convention):

BOOL WINAPI CryptProtectData(
[R0] DATA_BLOB* pDataIn,
[R1] LPCWSTR szDataDescr,
[R2] DATA_BLOB* pOptionalEntropy,
[R3] PVOID pvReserved,
[stack] CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
[stack] DWORD dwFlags,
[stack] DATA_BLOB* pDataOut
);

Now the values are:

arg0 = input buffer (our password, in Unicode form)
arg1 = NULL
arg2 = "Software\Microsoft\Inbox\Svc" (optional entropy string, of length 0x38)
arg3 = NULL
arg4 = NULL
arg5 = 0x20000000
arg6 = some output buffer

The problem

From WINCRYPT.H, we can see that 0x20000000 corresponds to the CRYPTPROTECT_SYSTEM flag.

And there we have a problem: only a "trusted" process will be allowed to access the data. In this case, that means a ROM-based process.

Solution ? You will have to wait for the next blog entry :)

Thursday, June 08, 2006

Word "0day" : was it a 0day ?

We have all heard about the recent Word flaw that has been exploited by targeted attacks (if you are now familiar with those, read [1] and [2]). If you have an account on OpenRCE (free), you can also read Kostya's blog on the topic.

However, reading Technet Flash Volume 8/Issue 11 from Microsoft (currently available here, or later in the archives), I was wondering about the following line:
"Microsoft Security Advisory (919637): Vulnerability in Word Could Allow Remote Code Execution

Microsoft has released an advisory on a zero-day exploit that could affect users of Word Smart Tags."
So the flaw would lie in the "Smart Tags" feature of Word. This feature is in charge of converting "1. L" to "1 liter", and was not present in Office 2000, which is unaffected by the flaw.

I could not help but thinking about the following post I have discarded a few weeks ago:
Possible Overflow in MS Word 2003

I've found a bug in Word 2003, that could possibly lead to a buffer overflow.
To reproduce the bug, you have simply to create a document with a word of 32 or 33 characters (letters or numbers), followed by "." and some other character. Ex.:

01234567890123456789012345678901. Test

The text above should crash MS Word 2003, with Buffer Overrun error.
Strange coincidence, isn't it ?

PS. To be safe from this flaw, just use "winword.exe /safe". This is not a joke.

Wednesday, April 19, 2006

Recovering Netscape Communicator 4.7 POP3 passwords

Some people are still using Netscape Communicator 4.7, you know -- and they might have to recover forgotten POP3 passwords ...

Step 1 : FILEMON and REGMON

Monitoring Netscape activity, it becomes pretty obvious that passwords are stored:
  • under the following registry key, of type REG_SZ:
HKCU\Software\Netscape\Netscape Navigator\biff\users\user name\servers\server name\password
  • in two files (prefs.js and liprefs.js), located inside the following directory:
C:\Program Files\Netscape\Users\user name\

For example, let's say that both values are :
  • =pGpFLmBAYsBTTdV
  • user_pref("mail.pop_password", "IqGGOfLNOzYScTc=");

Step 2: hand decryption

At first sight, it looks like file-stored passwords are relying on Base64 encoding (because of the = sign at the end). After a few tests, it is also noticeable that:
  • Original and encoded passwords have same length
  • Same passwords give same results
So we have unsalted, fixed-key encrypted passwords. Some people have already found that the encryption scheme is plain old XOR, so it is possible to recover the beginning of the XOR stream, by encrypting a known password and XOR-ing it with the result. First bytes can be found using a trivial Python script:

import base64
import operator
input = base64.b64decode("IqGGOfLNOzYScTc=")
key = "thisisatest"
print map(operator.xor, map(ord, input), map(ord, key))

[86, 201, 239, 74, 155, 190, 90, 66, 119, 2, 67]

However, this does not work for registry-stored passwords, and is totally unsatisfactory for the mind :)

Step 3 : binary analysis

So it's time to have a closer look at NETSCAPE.EXE ... The binary file is huge (over 5 MB), but not stripped - which is really cool.

After few minutes of browsing, it becomes pretty clear that MSG_SetPasswordForMailHost() is calling SECNAV_MungeString(), which is relying on the RC4 stream cipher. RC4_CreateContext() is initialized with a fixed key, namely:
  • 0xD0869CDEC6EEEB3E
Registry-stored passwords are encrypted with the same stream, but also reversed (using the strrev() function) and scrambled using the following table:

// To be used for characters in range [0x40 ... 0x7F]
unsigned char table[] = {
0x40, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x41, 0x42,
0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x61, 0x62,
0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F
};
Using Python Crypto Toolkit, it is now possible to test our results:

from Crypto.Cipher import ARC4
import base64
input = base64.b64decode("IqGGOfLNOzYScTc=")
key = "\xD0\x86\x9C\xDE\xC6\xEE\xEB\x3E"
o=ARC4.new(key)
print o.decrypt(input)

thisisatest

Job finished!

Cryptozor & Steganozorus
or why dinosaurs disappeared

Introduction

Believe it or not, I have been told that some people rely on Cryptozor(us) software for file encryption.

Cryptozor(us) is from Thomas Nerrant. The author's primary web site seems down currently, but it is possible to find a working mirror: there are some available on [1][2][3].

First impression is that the GUI is ... poor, to say the least.

The software claims using PC1 and CARACACHS algorithms, which are mostly unknown from the community. This is often bad news ... for the software :)

First tries

First of all, let's try to encrypt a simple, plaintext file (such as "README.TXT"). The original file size is 15,331 bytes. A "README.TXT.CTZ" file is created on output. Here are the results using different passwords and the CARACACHS-128 algorithm:
  • File #1, input password "a", output file size 15,402 bytes.
  • File #2, input password "aa", output file size 15,402 bytes.
Let's compare both files using CrypTool. First, we can see that the output file distribution for #1 is far from being good:

But the really bad news is that file #2 has exactly the same distribution:

What kind of "encryption" algorithm could give such results ? Having a closer look, file #1 and #2 differ on byte ranges [0x00..0x1C] and [0x3C00..0x3C1F]. Both files are otherwise exactly the same !

At this point, we are pretty confident in the fact that the output file is "scrambled" with a fixed key, and that the encryption key is useless in the process of decryption. Now let's have a look at "CRYPTOZORUS.EXE".

Binary analysis

Having unpacked the file (upx -d cryptozorus.exe), we begin analysis. An idea to start with would be searching for a string reference to "!#? Bad Password ?#!". Such a reference can be found in the following piece of code (comments have been added later):

.text:0040314D case6_bad_password: ; CODE XREF: dispatch_sub+181j
.text:0040314D cmp ebx, 6
.text:00403150 jnz short case7_stopped
.text:00403152 mov word ptr [edi+10h], 50h
.text:00403158 mov edx, offset a?BadPassword? ; " !#? Bad Password ?#!"
.text:0040315D lea eax, [ebp+var_1C]
.text:00403160 call wrap_LStrFromPChar

The function at 0x00402F88 is clearly a switch/case related to the program's internal state. We call it "dispatch_sub()". When state == 6, "bad password" is displayed.

There are many references to dispatch_sub(), so it is better to trace the program with a debugger (namely OllyDbg) to find the caller on case 6. The result is pretty obvious:

.text:00408218 bad_password: ; CODE XREF: maybe_write_file+FFj
.text:00408218 push 6 ; 6 = BAD PASSWORD
.text:0040821A mov eax, [esi]
.text:0040821C mov edx, [eax]
.text:0040821E push edx
.text:0040821F call dispatch_sub

This piece of code is entered on the following condition:

.text:00408071 call test_password
.text:00408076 add esp, 8
.text:00408079 test al, al
.text:0040807B jz bad_password ; 6 = BAD PASSWORD

By replacing "jz bad_password" with "nop", it is possible to completly bypass password checking.

Conclusion

By patching 2 bytes inside the program file, we made a program that will decrypt any file without knowing the password. Total analysis time is under 20 minutes. Would you call that security software ?


PS. Having a closer look at test_password(), it seems that this function relies on the "CRYPTOZORUS_THOMASNERRANT.COM" string. The exact purpose of this string is left as an exercise to the reader. There are 2 possibilities:
  • This is the fixed encryption key;
  • This string, encrypted with user password, is used for password checking on decryption.