Tuesday, January 13, 2015

Happy DPAPI!

Last October, I participated as speaker at the SANS DFIR Summit in Prague. It was a great meeting and I am very happy to have been able to participate. My speech was focused on DPAPI, the Windows Data Protection API, and how it could be used during a post-mortem digital investigation to access protected information: overcoming system's security it's sometimes necessary to access data otherwise not available. I like to call this "process" ODI, Offensive Digital Investigations.

I want to be brief, skipping any DPAPI introduction and only providing some links for readers who don't know what DPAPI might be. Consider simply the fact that the technology was introduced with Windows2000(!!) and you and/or your system/applications use it every day... Moreover, if you wonder how wifi passwords are protected, how IE or Chrome treats saved credentials, how Dropbox encrypts its databases, how iCloud protects user credentials, how EFS (Encrypting File System) gets unlocked and so how your private asymmetric key is safeguarded... then you need to know what DPAPI is and how it works. You can download my slides "Give Me the Password and I'll Rule the World" from here and this is the links list:

The last work is an awesome research made by Elie Bursztein and Jean-Michel Picod, who first published DPAPI intimate details. They even provided dpapick, an Open Source Python tool able to offline decrypt DPAPI blobs (aka the encrypted information) up to Windows Vista. Their work is a milestone to deeply understand this technology, and it was my entrance and reference when I started to dig inside DPAPI. For this reason I decided to try improving dpapick by adding Windows7 and Windows 8.1 support: after some nights inside WinDbg, I was able to decrypt blobs coming from these systems, just in time for the SANS conference. Then Jean-Michel took my patch, refactored the code and added some other cool features, releasing the dpapick version 0.3 in the middle of October: check the new features added in his blog post here.

Just a note on Windows 8.1: DPAPI decryption is supported only for local accounts, not for online accounts. As you can read here, "[DPAPI is] used to encrypt and decrypt static data on a single computer. Cloud computing, however, often requires that content encrypted on one computer be decrypted on another": so Microsoft introduced DPAPI-NG to allow sharing of secrets/whatever on different computers, after proper authentication and authorization. DPAPI-NG is used when working with online user accounts, and it's not currently supported by dpapick.

Ideally this post should have been published few days after the meeting, anyway it's here: some examples on how you can use dpapick to access data protected by DPAPI tech.


First, you must download the dpapick version 0.3 from bitbucket (the zip file or the mercurial clone) or (cool news) install from pypi! The pro with the installation option is that it will take care of dependencies, otherwise you must set the correct PYTHONPATH and provide the 3rd part packages: dpapick itself is pure Python, so no issues with the OS you're using. In the post examples, I used both Linux and Windows.

Second, you should have a Windows OS mounted somewhere: I'll use the vmdk virtual disk files coming from the Windows 8.1 and Windows 7 VmWare guests I used during the reverse engineering phase. Alternatively you should extract the needed files from your target Windows and place them wherever you prefer.

Besides that, you should know that user's login password is the main key that unlocks user's masterkeys and allows later blobs decryption; that the system has its own secrets protected with a system password. In the first case the password should be only in user mind; in the second case the password must be inside (or, at least, known to) the system, so no security at all...

no more (lsa) secrets

One of the cool features added is the capability to decrypt Windows7-8.1 LSA secrets (credits to mimikatz too): this feature is needed to grab the system key (DPAPI_SYSTEM) used by Windows to dpapi-protect some info. Moreover it could expose some other interesting info. Let's use the script lsasecrets in dpapick folder "examples": in the first instance use '--hex' to avoid unpleasant string conversion errors, it's not all a string there (note that command and parameters used are splitted on more lines to ease reading).


NL$KM              CurrVal     bc8b5abe12a6b772114c7f3902b25cb20813be04493f9d84...
NL$KM              CupdTime    2014-09-29 19:44:25
NL$KM              OldVal   
NL$KM              OupdTime    2014-09-29 19:44:25
DPAPI_SYSTEM       CurrVal     01000000c78f09ee4f1c5d6ccc29280313c0a63f6c83b478...
DPAPI_SYSTEM       CupdTime    2014-09-14 21:31:04
DPAPI_SYSTEM       OldVal      01000000962d3a6c963627caa8c0725b56ce7dfbe8050007...
DPAPI_SYSTEM       OupdTime    2013-08-22 14:45:11
DefaultPassword    CurrVal     66007500660066006100
DefaultPassword    CupdTime    2014-09-14 21:32:24
DefaultPassword    OldVal      52004f004f0054002300310032003300
DefaultPassword    OupdTime    2013-08-22 14:45:44

The DPAPI_SYSTEM value it's the data needed to unlock system masterkeys and to decrypt system blobs. Then we were able to get NL$KM value, used by Windows to encrypt domain cached credentials, and... what? DefaultPassword (aka user auto-logon password)? I can't figure out why it's there, perhaps VmWare easy-install? Anyway, let's get only those values.



Ok, 'fuffa' is the current user password and 'ROOT#123' the old password. That's a windfall, since getting the user password in this way it's too easy... and so we'll able to unlock DPAPI for the user. Later we'll see another way to unlock user DPAPI.

wifi credentials

Let's see an example of system's secret, wifi credentials. As you should know, when you connect to a wifi network with the right password, this data will be saved inside your os (together with other info) for later reuse: a sort of SSO. This storage is not per-user, but system wide and the passwords are protected with DPAPI: you need the DPAPI_SYSTEM "secret" to decrypt them.

I just realized the current dpapick has not scripts to handle this task, so I wrote the following one which will provide wifi credentials (just wifi name and password): I called it wiffy, to train my talent in providing cool names... As is as usual, just quick&dirty coding.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: dfirfpi - francesco.picasso@gmail.com

from DPAPI.Core import blob
from DPAPI.Core import masterkey
from DPAPI.Core import registry
from optparse import OptionParser

import re
import os
import sys

if __name__ == "__main__":
  parser = OptionParser()
  parser.add_option("--masterkey", metavar="DIRECTORY", dest="masterkeydir")
  parser.add_option("--system", metavar="HIVE", dest="system")
  parser.add_option("--security", metavar="HIVE", dest="security")
  parser.add_option("--wdir", metavar="WIFIDIR", dest="wifi_dir")

  (options, args) = parser.parse_args()

  reg = registry.Regedit()
  secrets = reg.get_lsa_secrets(options.security, options.system)
  dpapi_system = secrets.get('DPAPI_SYSTEM')["CurrVal"]

  mkp = masterkey.MasterKeyPool()
  mkp.try_credential_hash(None, None)

  for root, _, files in os.walk(options.wifi_dir):
    for file in files:
      filepath = os.path.join(root, file)
      with open(filepath, 'r') as f:
        file_data = f.read().replace('\x0a','').replace('\x0d','')
        wifi_name = re.search('<name>([^<]+)</name>', file_data).group(1)
        key_material = re.search(
            '<keyMaterial>([0-9A-F]+)</keyMaterial>', file_data).group(1)
        wblob = blob.DPAPIBlob(key_material.decode('hex'))
        wifi_pwd = '<not decrypted>'
        mks = mkp.getMasterKeys(wblob.mkguid)
        for mk in mks:
          if mk.decrypted:
            if wblob.decrypted:
              wifi_pwd = wblob.cleartext
        print 'Wifi:{} Password:{}'.format(wifi_name, wifi_pwd)

Let's execute wiffy (it sounds like a name for dogs... but it's inside the urban dictionary... no copyright then...) against my real windows8.1 installation, so results will be offuscated (you too curious).


Wifi:MyUberWifi Password:notUberTheCarButUberTheUber
Wifi:monkey Password:CuriousGeorge
Wifi:wannabe Password:lamer

from system to user secrets

If getting the system password is expected, what about the user password, needed to decrypt user's secrets? Ruled out the DefaultPassword LSA secret, you can try cracking the password hash or... you could find it in cleartext inside a RAM dump, for example an hibernation file. The awesome mimkatz is the tool, thanks to the number-one-lsass-enemy© Benjamin Delpy: refer to his blog and to my previous posts. I think this topic is already well known, but there is something more...
Our goal is not the user password, but to unlock user's DPAPI masterkeys: actually, if you have a memory dump (whatever contains the lsass process), you'll be able to (almost) always unlock user DPAPI. Sounds cool... but stay grounded. Let's recall the mimikatz matrix, next figure

As you can see in the Primary column, the SHA1 hash is always there with only one exception, the domain protected users. That SHA1 is the SHA1(UTF16LE(user_password)), which is exactly the only secret part of the pre-key needed to unlock masterkeys (refer to the slides)!

So despite the fact the Microsoft hardened Windows by removing default user password presence in some SSPs (Security Support Providers) or despite the user configuration (see this great post from Mike Pilkington) the SHA1 will allow DPAPI decryption even if the user password is not known. To the best of my knowledge you can't configure/remove (aka harden) the primary SSP (msv1_0). Result: grab that hash and enjoy with dpapick, which handles it wonderfully.

Consider the following mimikatz output, coming out from a Windows 8.1 with one local user account

As expected, no cleartext password but... the SHA1 is there! Since I know my password (do you remember the previous 'fuffa'?), that SHA1 is exaclty the SHA1(UTF16LE('fuffa'))... Rememeber, with virtualization you must know the user password to access DPAPI protected data (you can't reset the user's password): here, with dpapick, you only need the "always present" SHA1.


Since I'm talking about ODI, I'd like to show how dpapick usage could help during a digital forensics investigation. Recalling the slides, if you face an "unbreakable" (something to say here...) turned off iPhone, with no passcode provided... you will not be able to access its data. Suppose you have the suspect's laptop (but no Apple LockDown certificates) too, and iCloud installed... or suppose you have only a laptop with iCloud installed... This scenario could be called "Access to otherwise inaccessible data".

The iCloud Windows application allows the users to backup their idata on the (i)cloud (too many 'i'...), a well-known feature with some well-known issues too... but it's another story. During the installation, iCloud asks for the user credentials once and then it starts doing its job every time the computer is powered on. In other terms, single sign on in action (and autorun, btw).

The iCloud credentials are kept inside the com.Apple.AOSKit.plist file, in "\Users\<username>\AppData\Roaming\Apple Computer\Preferences\". This file contains a data section which is a large DPAPI blob: to be short, it's enough to execute the icloud.py script inside dpapick/examples folder to get the job done. For any detail, refer to slides and to the icloud.py code.

--aoskit=/mnt/win81/Users/user/AppData/Roaming/Apple\ Computer/Preferences/com.apple.AOSKit.plist

iCloud Apple token decryption
Binary PLIST file for account iFooFooFoo@icloud.com decrypted!
Decrypted plist written in file "../aoskit.plist.plist" 

(ERRATA: when using the --hash parameter instead of --password, as I do, a quick fix is needed in icloud.py code... add at line 65  "options.h.decode('hex')"... sorry, I forgot it, and it will be fixed).

icloud.py ERRATA

datablob.try_decrypt_with_hash(options.h, mkp, options.sid, aoskit=options.aoskit)

datablob.try_decrypt_with_hash(options.h.decode('hex'), mkp, options.sid, aoskit=options.aoskit)

What you get is a new decrypted plist file, which contains a lot of useful and interesting info (mailToken, cloudKitToken, etc.). The iCloud token is the pair [dsPrsID, mmeToken]: with this token you can access the user's iDevices iBackups ('i' again...) stored online. For this last task I use Elcomsoft Phone Password Breaker (see here), simply because it's the only tool providing such a cool feature in the way I like. Anyway, you could also try with another iCloud by re-encrypting the decrypted token with your current Windows user DPAPI (not providing code, but it's simple).


Dropbox obfuscated Python code it's an hard reverse engineering quest. There are at least three notable works on it, but here I want to cite the awesome one made by Nicolas Ruff and Florian Ledoux, "A critical analysis of Dropbox software security", more than two years ago! They even provide the useuful code to obtain the encrypted dbx decryption key, which is protected by DPAPI. Being brief, check their work on https://github.com/newsoft: the dpapick dropbox script is based on their findings.

So, to get that decryption key, just run dpapick dropbox script, as shown in the next example (note: the same errata as icloud applies if using the '--hash' parameter), where I used dpapick from a Windows machine.

python dropbox
--masterkey=G:\Users\user\AppData\Roaming\Microsoft\Protect\S-1-5-21-2128076315-4144300488-3078399761-1001 --credhist=G:\Users\user\AppData\Roaming\Microsoft\Protect\CREDHIST --hash=74b87ba1e12734f71fe4737990e2c420bd145bf4
Dropbox DBX password

Then? As reported in my slides, you need EE Sqlite (Encryption Extension, see here), which is not publicly available. Newsoft provided a 3.7.0 sqlite3 source code with EE, so you can grab it from their github space and use it with the extracted password.

find your blobs

If you are curious as I suppose, you can even try to find out how many DPAPI blobs you have inside your Windows. To the best of my knowledge, actually there is only one crypto provider used, whose GUID is "df9d8cd0-1501-11d1-8c7a-0c04fc297eb": so, with a simple hex-searching you will be able to spot them. Then, with a next-to-come dpapick script, it will be easy to verify the bytes found and, in case, decrypt them.


There are many secrets protected with DPAPI, for example Windows Vaults (lazy wip here). So feel free to write to me and/or to Jean-Michel providing some info regarding the usage of CryptProtectData in your target app, your scripts or whatever could help improving dpapick.

As you read, dpapick needs some tunings and addings, but it's an invaluable tool when you need to access protected data to go on with the investigation. So, Happy DPAPI(ck)!

[bonus track]

If you reached this last part of the post (without directly scrolling here, cheater!), then you deserve a bonus. When exploring LSA secrets, I pointed out the presence of the DefaultPassword old value, which surprised me.

I did some more tests on 6 different installations of Windows 7, 3 Windows 8.1 and 1 Windows Vista. All but Vista contained that DefaultPassword old value set, without having the auto-logon feature enabled: this password seems to be the first one inserted during the Windows installation and, by changing the current one, it does not change (not tested the auto-logon enabling and disabling).

The conclusion? Hardly definitive due to reduced dataset (please share your findings), but it could be said that starting from Windows 7, Windows keeps in the old DefaultPassword value your first password (assumed auto-logon disabled). The risk? It depends on you. The opportunity? It depends on them. Anyway, from today, I'll always check this value.

Sunday, June 15, 2014

Digital Forensics Tools Bookmarks

We want to share with you a list of bookmarks related to hardware and software tools for Digital Forensics acquisition and analysis. The bookmark file is in Mozilla Firefox, so it can be directly imported into it.

You can download the file from


If you are interested in adding a tool to our list, please contact me at mattia @ realitynet.it.

Friday, March 28, 2014

mimikatz offline addendum

I must admit I did not expect so many acknowledgments by writing the volatility mimikatz plugin. I want to say thanks to all people that tweeted, emailed - and so on - me: it is just a piece of the puzzle, and the big pieces are those from volatility and from mimikatz.

First, I want to say thanks to Andrew Case, for the support and for having tweeted about the plugin: probably all those acks are because Andrew is an uber-well-known DFIR expert! Then I want to say thanks to Kristinn Gudjonsson, my favorite plaso “harsh” reviewer, who spotted some “devil” (you wrote it! ;) issues in my code, as the multiple inheritance I used… lol, I will fix it! Last but not least I want to once again say thanks to Benjamin aka gentilkiwi, who wrote an e-mail to me making the congratulations for the plugin.

With this post, I want to point out some features of mimikatz that I had not considered in the first instance.

mimikatz can work offline

In the previous post I wrote “Mimikatz is "normally" used on live Windows, where it injects itself inside the lsass and then it does a lot of stuffs”. That is not entirely true: since July 2012, mimikatz uses memory reading, and this is a key point. Moreover, mimikatz deals with minidump, and mimilib with full dump/minidump. Let's start with the first reference

mimikatz minidump

Probably this could be the best approach during a pentest: do not send mimikatz on the target, use (for example) sysinternals procdump. Then, create a crash dump for the lsass process (pay attention to specify the right parameters) and get it on your machine.

Once you have the crash dump, you can load it in mimikatz by using just two commands (!!):

sekurlsa::minidump <name of the lsass crash dump file>

You’ll get all the info! Awesome!

Just a quick note: use mimikatz on a platform of the same major version and same architecture as the original dump. The following image comes from his blog.

But mimikatz has another great ODI capability, as pointed in the following post (2nd reference):

mimikatz with RAM and hiberfil

In my previous post I asked “How to do the same during post-mortem ultra-died forensics?”. Well, you can use mimikatz if you have a Windows OS! How? Benjamin explained it, and I followed his instructions to get the job done.

First, you have to convert your memory dump or hiberfil to a windows crash dump: you can do with the immense volatility or with Matthieu Suiche’s memory tools (bin2dmp and hibr2dmp).

Then, launch windbg (better if with the right architecture… x86 or x64 depending or your target) and load the target crash dump (note: I changed the target, a Windows 7 SP1 x86).

At this point you have to load – guess what? – mimikatz, and specifically mimilib.dll. It will even provide the instructions for the next steps!

Follow the instructions (red square in the next figure, pay attention to symbols) et… voilà! Logged users’ credentials.

You can even work with VmWare vmem files! Let’s say that’s awesome! Finally, some considerations.

mimikatz or volatility? mimikatz AND volatility!

Finally, you can achieve the same result directly with mimikatz and without volatility. Which is the best approach? It depends: actually mimikatz+minidump are Windows only, so, if you are working with another OS, volatility+mimikatz plugin is the way, unless virtualization. Besides that consider that the engine (I mean signatures and data structures) is the same: I have an idea to add, and I will share it with Benjamin, so they should be aligned. If in Windows, it’s up to the user.

some instructions

Some people wrote to me asking how to use the mimikatz volatility plugin. Remember, it’s a PoC, anyway, this is how I’m using it.

·         python 2.7 (www.python.org)
·         volatility >= 2.3 (python, not binaries)
I use trunk code (svn checkout http://volatility.googlecode.com/svn/trunk/ volatility)
·         volatility dependencies (https://code.google.com/p/volatility/wiki/VolatilityInstallation)
·         mimikatz plugin (https://code.google.com/p/hotoloti/)
copy the “mimikatz.py” in <volatility directory>/volatility/plugins
·         mimikatz plugin python dependencies
·         a memory dump? =)

keep updated

Actually, the volatility plugin lacks several features with respect to mimikatz: I will post when major updates are ready, meanwhile you could check the source code here:

Have fun!

Wednesday, March 26, 2014

et voilà le mimikatz offline

In one of my recent cases, I needed to recover the windows user password: I had different OSes with various levels of cryptography, mainly at file level. Usually I think it's a good approach to recover as many hints as possible, to derive a scheme and/or to find a way to access the data. 


I like to call it ODI (Offensive Digital Investigations, in Italian "odi" means hear, find out). I remember an old case where I got 500+ strong encrypted archives... too many without a password catalog. I searched for the weakest protection and I found three zip-crypto (not a strong protection) archives: I cracked them in few days and then I was able to derive the schema to access all of them. I was lucky.

This time I felt that the Windows user password was the... key. Usually the dirty work is made with rainbow tables, but no way: I was unable to crack the Windows 7 user password.


I don't remember exactly why I was playing with mimikatz (hem, coff coff) but I had a dream: mimikatz offline... why not? For the few guys who do not know what mimikatz is, this is the site: suffice to say that it's an awesome work made by Gentil Kiwi, who made a deep reverse engineering of the lsass process and discovered how to extract plaintext credentials from it. Mimikatz is "normally" used on live Windows, where it injects itself inside the lsass and then it does a lot of stuffs, not only getting logged users credentials.

it's a matter of RAM

How to do the same during post-mortem ultra-died forensics? First, usually you don't have a RAM dump (don't pull the plug! don't pull THAT plug!.... too late...) but you could get the hiberfil! The hibernation file is like an easter egg: you can't bet on it, it could be corrupted, it could be too old and so on. But, if lucky, you'll get your RAM dump. Tell me the first word that comes to mind when speaking about RAM? volatility.

volatility + old-old-style approach

I got the RAM. I got volatility. I got mimikatz. I didn't get the password. There is something to do, and the first thing is to say uber-thanks to Gentil Kiwi who published the mimikatz source code. By digging inside that code I got the anchors he found as entry points for lsass and its authentication packages. So I started by dumping lsass memory, lsasrv module and the wdigest module: then I used mimikatz anchors and I moved inside lsass, finding what I was looking for (tools used: volatility, HxD, Notepad++, calc. Definitely oooold school, apart from volatility...). So I got the user name, the domain, the encrypted password, the 3DES key and its IV: a bit of python... et voilà. Uh, a fair password! (I forgot: I drank a good beer...).

mimikatz offline

Dumping processes, modules and moving in the hex view it's not always comfortable and it's quite slow. After two rounds of refactoring, I wrote the mimikatz offline plugin for volatility, which automates the previous steps, without dumping anything apart user credentials! It's a PoC which supports only the wdigest authentication package, Windows Vista and 7 both x86 and x64 versions. You can find it on hotoloti, as usual.


I'm planning to add more authentications packages and other stuffs inside the plugin, but actually I had to freeze a bit since I'm getting fun (and loosing sleep) from another hot topic I will share as soon as possible. Basically this is the desired roadmap for the plugin: an external review on the high-level design; a consideration on plugin vs non-plugin approach ; what about rekall; adding authentication packages; testing; what else?

Windows password cracking? No thanks, I quit

Throw away those rainbow tables! Throw away dictionaries! You can get the password in few seconds! Sounds cool,  doesn't it? Unfortunately it's not always the case, but this is another possibility to be considered when you need credentials. Odi and happy hunting. 

Tuesday, December 3, 2013

3minutesOf: a bit of X-Ways and RAID

Some days ago I was working on four images coming from a QNAP storage: so, four disk whose partitions were used to build up RAID volumes. "No problem" I said to myself, knowing that QNAP are *nix based and that XWF (X-Ways Forensics) is so powerful that I'll not need to switch on Linux.

Which RAID?

That's true, but you need to instruct XWF about which type and parameters the RAID is using. Easy again, let's find the configuration raidtab file. Here is it: 

 raiddev /dev/md0
    raid-level               0
    nr-raid-disks            4
    nr-spare-disks           0
    chunk-size               4
    persistent-superblock    1
    device                   /dev/sda3
    raid-disk                0
    device                   /dev/sdb3
    raid-disk                1
    device                   /dev/sdc3
    raid-disk                2
    device                   /dev/sdd3
    raid-disk                3

The third partition of each disk is used inside a level-0 RAID (striping) with a block size of 4KB (the chunk size is expressed in kilobytes, as man says), so 8 sectors (assuming 512... bla bla bla).

chunk-size size
Sets the stripe size to size kilobytes. Has to be a power of 2 and has a compilation-time maximum of 4M. (MAX_CHUNK_SIZE in the kernel driver) typical values are anything from 4k to 128k, the best value should be determined by experimenting on a given array, alot depends on the SCSI and disk configuration.

Moreover from the first disk (the only one showing up to own a file system structure) I got an EXT4 volume. Ok, let XWF rebuild the RAID and inspect the volume.

But... at this point XWF showed up many errors about wrong inodes... hum, something weird there... The first doubt is usually about the stripe size, under the assumption that the RAID type is correct. I got that info from the only configuration file available, so where is the issue?


Following the maccO razor (the worst and complicated idea) I thought to explore the ext4 fs structure to see where there is a jump from the first disk volume to the second inside the Group Descriptors: but, luckily since easier, I opened again the raidtab file and I spot the persistent block configuration value. From the man:

persistent-superblock 0/1
newly created RAID arrays should use a persistent superblock. A persistent superblock is a small disk area allocated at the end of each RAID device, this helps the kernel to safely detect RAID devices even if disks have been moved between SCSI controllers. It can be used for RAID0/LINEAR arrays too, to protect against accidental disk mixups. (the kernel will either correctly reorder disks, or will refuse to start up an array if something has happened to any member disk. Of course for the 'fail-safe' RAID variants (RAID1/RAID5) spares are activated if any disk fails.) Every member disk/partition/device has a superblock, which carries all information necessary to start up the whole array. (for autodetection to work all the 'member' RAID partitions should be marked type 0xfd via fdisk) The superblock is not visible in the final RAID array and cannot be destroyed accidentally through usage of the md device files, all RAID data content is available for filesystem use.

That's interesting: first because if images (or disks) were wrong labeled, you can reorder the disks. Moreover you get a lot of information to verify the RAID type, the RAID UUID and... the chunk-size. Where this data is memorized? It's intuitive, but from the linux raid source code (thanks God is OSS!) and from RAID_superblock_formats, I got all the information needed to explore the RAID superblock.

let's template it

Exploring the hexadecimal is great but if you can create something that displays the data... and XWF has templates! So based on the raid source code I made a little template to get the following output:


You know where to apply the template ("The superblock is 4K long and is written into a 64K aligned block that starts at least 64K and less than 128K from the end of the device") and you know the magic value. So, in my case, the stripe size (chunk size) is 128 sectors... and XWF was able to complete its work.

Here is it the template: cut and paste inside a tpl file and use it with XWF. Note that only version 0.90 is "supported".

template "RAID superblock version 0.90"

// Template by Francesco "fpi" Picasso
// Tweet me @dfirfpi

description "To be applied to RAID superblock"
applies_to disk
requires 0x0 FC4E2BA9
requires 0x4 00000000
requires 0x8 5A000000

    hexadecimal uint32 "Signature: 0xA92B4EFC"
    uint32    "major version (want 0!)"
    uint32    "minor version (want 90!)"

    section "Generic Information"
    uint32     "patch level"
    uint32    "section words len"
    hexadecimal uint32    "Raid UIDD0 (1)"
    time_t    "Creation time"
    uint32    "RAID level"
    uint32    "Size of individual disk"
    uint32    "Number of disks"
    uint32    "Fully functional disks"
    uint32    "Preferred min MD device"
    uint32    "Persistent superblock"
    hexadecimal uint32    "Raid UUID1 (2)"
    hexadecimal uint32    "Raid UUID2 (3)"
    hexadecimal uint32    "Raid UUID3 (4)"
    move 64

    section "Generic state information"
    time_t     "Superblock update time"
    hexadecimal uint32    "State bitmask"
    uint32    "Active disks"
    uint32    "Working disks"
    uint32    "Failed disks"
    uint32    "Spare disks"
    hexadecimal uint32 "Superblock checksum"
    int64    "Superblock update count"
    int64    "Checkpoint update count"
    uint32    "Recovery sector count"
    int64    "(v>90) reshape position"
    uint32    "(v>90) new level"
    uint32    "(v>90) delta disks"
    uint32    "(v>90) new layout"
    uint32    "(v>90) new chunk size bytes"
    move 56

    section "Personality Information"
    uint32    "Array physical layout"
    uint32    "Chunk size (bytes)"
    uint32    "LV root PV"
    uint32    "LV root block"
    move 240

    section "RAID disks descriptors (first 6 of 27)"
        uint32 "Disk~ number"
        uint32 "Disk~ major"
        uint32 "Disk~ minor"
        uint32 "Disk~ raid disk"
        hexadecimal uint32 "Disk~ state"
        move 108
    move 2688

    section "Disk descriptor"
    uint32    "Number"
    uint32    "Major"
    uint32    "Minor"
    uint32    "Raid disk"
    hexadecimal uint32 "State"
    move 108


that's all!