The Sleuth Kitの使い方に触れながら Determine Window Version!
一個前の記事で、
Windowsのバージョン情報どこじゃい - 4ensiX
こんな話をした。
ていうことは、レジストリの任意のkeyを参照できればoffline imagefileのWindows Versionを判定できると思ったのでチャレンジする。 コンシュマー系のWindowsのみやってみる。
- 今回の流れ
- レジストリを取り出すWindowsイメージの用意
- The Sleuth Kitのお話
- レジストリハイヴを取り出す前準備
- レジストリハイヴをdump! バージョン判定までいっちゃうゼ
- 終わりに
今回の流れ
- イメージファイルを用意する。これは、構成された完全なrawイメージを使う。
- The Sleuth Kitで目的のレジストリハイヴファイルを取り出す。
- keyをhivexであったり、何らかの方法で持ってくる。
これでWindows Versionの判定を行う。
レジストリを取り出すWindowsイメージの用意
始めに、バージョン判定するためのwindowsイメージを用意する。ここで使うイメージは、isoではなく、インストールされて構成されたイメージである必要がある。
方針としては、検証したいWindows Versionのisoイメージを拾ってきて、ここから仮想マシンを立てる。この仮想マシンのイメージをrawイメージにして解析する。そんなメンドクサイことなんでやるのって、それは構成されたrawイメージが欲しいからなのだけど、良い方法があればご教授願いたい。
今回はこちらのサイトからイメージをお借りする
GetMyOS
ここにはMac以外なら沢山あるので、色んな環境で検証したいときはおススメ。ただ、WindowsはEnterpriseじゃないとプロダクトキーが必要で使えないので注意。
ダウンロードして見たところ、WinXPくらいまでは、何事もなくVMが動かせた。
しかし、Windows2000は、Enterpriseが見つからないし、WinMe以前は上手く動かない。しかしisoイメージがなくとも、そもそも仮想イメージを欲しているので仮想イメージがあればいいじゃない。
Windowsのバージョン情報どこじゃい - 4ensiX
Win95,Meは前回の終わりの方で示したVDIを利用する。
Windows Me
Windows98
X-MAS-CTF/A Trip To Grandmas House.md at master · RealAwesomeness/X-MAS-CTF · GitHub
Windows95
ここらで、先ほど揃えたVMの仮想イメージと拾ってきたvdiをrawに変えてから中身みる。イメージの変換はこちらを参照ドぞ。
仮想イメージからファイルを取り出す エラーを吐いたVMからファイルを救え - 4ensiX
自分はこれぐらいの容量で用意した
The Sleuth Kitのお話
The Sleuth Kitはディスクイメージ解析といえば、AutopsyとFTK Imagerを聞くと思うのですが、そのうちのAutopsyのCLI版という感じで、Cライブラリで動くイメージファイルを扱うツールセット。コマンドは、
blkcalc - Converts between unallocated disk unit numbers and regular disk unit numbers. blkcat - Display the contents of file system data unit in a disk image. blkls - List or output file system data units. blkstat - Display details of a file system data unit (i.e. block or sector). fcat - Output the contents of a file based on its name. ffind - Finds the name of the file or directory using a given inode. fiwalk - print the filesystem statistics and exit. fls - List file and directory names in a disk image. fsstat - Display general details of a file system. hfind - Lookup a hash value in a hash database. icat - Output the contents of a file based on its inode number. ifind - Find the meta-data structure that has allocated a given disk unit or file name. ils - List inode information. img_cat - Output contents of an image file. img_stat - Display details of an image file. istat - Display details of a meta-data structure (i.e. inode). jcat - Show the contents of a block in the file system journal. jls - List the contents of a file system journal. jpeg_extract - jpeg extractor. mactime - Create an ASCII time line of file activity. mmcat - Output the contents of a partition to stdout. mmls - Display the partition layout of a volume system (partition tables). (以下略)
とまあこんな感じで、ココに色々あるのだが、今回はimg_stat
,mmls
,fsstat
,fls
,icat
の5つでお送りいたす。
レジストリハイヴを取り出す前準備
基本方針
- ファイル形式を判定
img_stat -t [image file]
- パーティションレイアウトを確認
mmls [image file]
- ファイルシステムを確認
fsstat -i [file type] -o [partition start] -t [image file]
- 上記の情報で展開できるか確認
fsstat -i [file type] -f [file system] -o [partition start] [image file]
- レジストリハイヴのinode番号を捜索
fls -i [file type] -f [file system] -o [partition start] [image file] [inode number]#繰り返す
- レジストリハイヴを取り出す
icat -i [file type] -f [file system] -o [partition start] [image file] [inode number] > [registry]
という手順で進める。しかし、そう簡単にはいかない。1995から2019年のwindowsの変遷を一気に辿ろうものなら、それなりに各々に違いはあるのである。
バージョンごとイメージの違いを確認
用意したイメージはWindows 95からWindows 10から1バージョンずつである。これらはいくつかの点でバージョンによって違いがある。
バージョンごとのファイルシステム
まず、これらはファイルシステムを大まかに3種類に分けられる。
- FAT16
Windows 95 - FAT32
Windows 98, Me (,2000?) - NTFS
Windows XP, Vista, 7, 8, 10
バージョンごとのパーティション情報の違い
次に、バージョンごとのパーティション情報の違いがある。 細かい説明がメンドクサイので、以下を見てもらう。
# mmls win95.raw DOS Partition Table Offset Sector: 0 Units are in 512-byte sectors Slot Start End Length Description 000: Meta 0000000000 0000000000 0000000001 Primary Table (#0) 001: ------- 0000000000 0000000062 0000000063 Unallocated 002: 000:000 0000000063 0004193279 0004193217 DOS FAT16 (0x06) 003: ------- 0004193280 0004194303 0000001024 Unallocated # mmls win98.raw DOS Partition Table Offset Sector: 0 Units are in 512-byte sectors Slot Start End Length Description 000: Meta 0000000000 0000000000 0000000001 Primary Table (#0) 001: ------- 0000000000 0000000062 0000000063 Unallocated 002: 000:000 0000000063 0010474379 0010474317 Win95 FAT32 (0x0b) 003: ------- 0010474380 0010485759 0000011380 Unallocated # mmls winMe.raw DOS Partition Table Offset Sector: 0 Units are in 512-byte sectors Slot Start End Length Description 000: Meta 0000000000 0000000000 0000000001 Primary Table (#0) 001: ------- 0000000000 0000000062 0000000063 Unallocated 002: 000:000 0000000063 0008385929 0008385867 Win95 FAT32 (0x0b) 003: ------- 0008385930 0008388607 0000002678 Unallocated
Windows 95, 98, Meまでは、FAT16とFAT32の違いはあるが、どれもパーティションが63から始まっている。
# mmls winXPsimple.raw DOS Partition Table Offset Sector: 0 Units are in 512-byte sectors Slot Start End Length Description 000: Meta 0000000000 0000000000 0000000001 Primary Table (#0) 001: ------- 0000000000 0000000062 0000000063 Unallocated 002: 000:000 0000000063 0005233535 0005233473 NTFS / exFAT (0x07) 003: ------- 0005233536 0005242879 0000009344 Unallocated # mmls winVista.raw DOS Partition Table Offset Sector: 0 Units are in 512-byte sectors Slot Start End Length Description 000: Meta 0000000000 0000000000 0000000001 Primary Table (#0) 001: ------- 0000000000 0000002047 0000002048 Unallocated 002: 000:000 0000002048 0031455231 0031453184 NTFS / exFAT (0x07) 003: ------- 0031455232 0031457279 0000002048 Unallocated
Windows XPとWindows Vistaを比べると、どちらもNTFSであるがパーティションの始まりが63と2048と異なる。
# mmls win7simple.raw DOS Partition Table Offset Sector: 0 Units are in 512-byte sectors Slot Start End Length Description 000: Meta 0000000000 0000000000 0000000001 Primary Table (#0) 001: ------- 0000000000 0000002047 0000002048 Unallocated 002: 000:000 0000002048 0000206847 0000204800 NTFS / exFAT (0x07) 003: 000:001 0000206848 0025163775 0024956928 NTFS / exFAT (0x07) 004: ------- 0025163776 0025165823 0000002048 Unallocated # mmls win8simple.raw DOS Partition Table Offset Sector: 0 Units are in 512-byte sectors Slot Start End Length Description 000: Meta 0000000000 0000000000 0000000001 Primary Table (#0) 001: ------- 0000000000 0000002047 0000002048 Unallocated 002: 000:000 0000002048 0000718847 0000716800 NTFS / exFAT (0x07) 003: 000:001 0000718848 0025163775 0024444928 NTFS / exFAT (0x07) 004: ------- 0025163776 0025165823 0000002048 Unallocated # mmls win10simple.raw DOS Partition Table Offset Sector: 0 Units are in 512-byte sectors Slot Start End Length Description 000: Meta 0000000000 0000000000 0000000001 Primary Table (#0) 001: ------- 0000000000 0000002047 0000002048 Unallocated 002: 000:000 0000002048 0001187839 0001185792 NTFS / exFAT (0x07) 003: 000:001 0001187840 0025163775 0023975936 NTFS / exFAT (0x07) 004: ------- 0025163776 0025165823 0000002048 Unallocated
Windows 7以降では、全てNTFSであるがパーティション領域が2つある。これは、Windows 10 Drive Partitionsによると、1つ目はリカバリーパーティションらしい。OSの問題をトラブルシューティングするための回復環境を置いておく領域のようだ。セーフモードとか選ぶ青い画面はここに別パーティションで保持されているということではないだろうか。我々が解析するパーティションは2つ目のパーティションである。
目的レジストリハイブパスの違い
ファイルシステムの変遷に伴い、レジストリハイヴにも変更があったようで、バージョンを参照できる目的レジストリハイブパスは3種類ある。
- Windows 95, 98 , Me (, 2000?)
WINDOWS\SYSTEM.DAT - Windows XP
Windows\system32\config\software - Windows Vista, 7, 8, 10
Windows\System32\config\SOFTWARE
レジストリハイヴをdump! バージョン判定までいっちゃうゼ
ここでは、Windows 98とWindows 10の2つのバージョンからレジストリハイヴを取り出し、バージョン判定までを紹介する。レジストリハイブからkeyの読み込みはhivexを使うがWindowsMe以前のレジストリハイブには対応していない?ようなのでstrings | grep
する。
Windows 98からレジストリハイブを取り出してバージョン判定
基本方針に沿っていく。
1.ファイル形式を判定
# img_stat -t win98.raw raw
2.パーティションレイアウトを確認
# mmls win98.raw DOS Partition Table Offset Sector: 0 Units are in 512-byte sectors Slot Start End Length Description 000: Meta 0000000000 0000000000 0000000001 Primary Table (#0) 001: ------- 0000000000 0000000062 0000000063 Unallocated 002: 000:000 0000000063 0010474379 0010474317 Win95 FAT32 (0x0b) 003: ------- 0010474380 0010485759 0000011380 Unallocated
3.ファイルシステムを確認
# fsstat -i raw -o 63 -t win98.raw fat32
4.上記の情報で展開できるか確認
# fsstat -i raw -f fat32 -o 63 win98.raw FILE SYSTEM INFORMATION -------------------------------------------- File System Type: FAT32 OEM Name: MSWIN4.1 Volume ID: 0x187b08f7 Volume Label (Boot Sector): NO NAME Volume Label (Root Directory): File System Type Label: FAT32 Next Free Sector (FS Info): 20470 Free Sector Count (FS Info): 9003760 Sectors before file system: 63 File System Layout (in sectors) Total Range: 0 - 10474316 * Reserved: 0 - 31 ** Boot Sector: 0 ** FS Info Sector: 1 ** Backup Boot Sector: 6 * FAT 0: 32 - 10250 * FAT 1: 10251 - 20469 * Data Area: 20470 - 10474316 ** Cluster Area: 20470 - 10474309 *** Root Directory: 20470 - 20477 ** Non-clustered: 10474310 - 10474316 METADATA INFORMATION -------------------------------------------- Range: 2 - 167261558 Root Directory: 2 CONTENT INFORMATION -------------------------------------------- Sector Size: 512 Cluster Size: 4096 Total Cluster Range: 2 - 1306731 FAT CONTENTS (in sectors) -------------------------------------------- 20470-20477 (8) -> EOF 20478-20485 (8) -> EOF 20486-20493 (8) -> EOF 20494-20541 (48) -> EOF 20542-20581 (40) -> EOF 20582-20629 (48) -> 37646 20630-21261 (632) -> 21638 (以下略)
5.レジストリハイヴのinode番号を捜索
# fls -i raw -f fat32 -o 63 win98.raw r/r 3: BOOTLOG.TXT r/r 4: COMMAND.COM r/r 5: SUHDLOG.DAT r/r 6: FRUNLOG.TXT r/r 7: MSDOS.--- r/r 8: SETUPLOG.TXT d/d 9: WINDOWS r/r 10: NETLOG.TXT r/r 11: MSDOS.SYS r/r 12: VIDEOROM.BIN r/r 13: DETLOG.TXT r/r 14: CONFIG.SYS r/r 15: BOOTLOG.PRV r/r 16: AUTOEXEC.BAT r/r 17: SYSTEM.1ST r/r 18: IO.SYS d/d 20: My Documents d/d 22: Program Files r/r 24: io32.sys d/d 25: RECYCLED r/r 26: SCANDISK.LOG r/r * 27: _UTMP0.19 r/r 29: autoexec.sdd v/v 167261555: $MBR v/v 167261556: $FAT1 v/v 167261557: $FAT2 V/V 167261558: $OrphanFiles # fls -i raw -f fat32 -o 63 win98.raw | grep WINDOWS d/d 9: WINDOWS # fls -i raw -f fat32 -o 63 win98.raw 9 | grep SYSTEM.DAT r/r 494448: SYSTEM.DAT
6.レジストリハイヴを取り出す
# icat -i raw -f fat32 -o 63 win98.raw 494448 > SYSTEM.DAT
7.レジストリハイブからkeyを持ってくる。
strings SYSTEM.DAT | egrep 'ProductName' | uniq | sed -e 's/ProductName//g' | grep "Microsoft Windows" Microsoft Windows 98
Windows Version Determine!
Windows 10からレジストリハイブを取り出してバージョン判定(簡略化)
必要な部分だけ説明を加える。
# img_stat -t win10simple.raw raw # mmls win10simple.raw DOS Partition Table Offset Sector: 0 Units are in 512-byte sectors Slot Start End Length Description 000: Meta 0000000000 0000000000 0000000001 Primary Table (#0) 001: ------- 0000000000 0000002047 0000002048 Unallocated 002: 000:000 0000002048 0001187839 0001185792 NTFS / exFAT (0x07) 003: 000:001 0001187840 0025163775 0023975936 NTFS / exFAT (0x07) 004: ------- 0025163776 0025165823 0000002048 Unallocated
先ほど示した通り、参照するパーティションは2つ目の方。
# fsstat -i raw -o 1187840 -t win10simple.raw ntfs # fsstat -i raw -f ntfs -o 1187840 win10simple.raw FILE SYSTEM INFORMATION -------------------------------------------- File System Type: NTFS Volume Serial Number: DAE616D3E616B02D OEM Name: NTFS Version: Windows XP METADATA INFORMATION -------------------------------------------- First Cluster of MFT: 786432 First Cluster of MFT Mirror: 2 Size of MFT Entries: 1024 bytes Size of Index Records: 4096 bytes Range: 0 - 93440 Root Directory: 5 CONTENT INFORMATION -------------------------------------------- Sector Size: 512 Cluster Size: 4096 Total Cluster Range: 0 - 2996990 Total Sector Range: 0 - 23975934 $AttrDef Attribute Values: $STANDARD_INFORMATION (16) Size: 48-72 Flags: Resident $ATTRIBUTE_LIST (32) Size: No Limit Flags: Non-resident $FILE_NAME (48) Size: 68-578 Flags: Resident,Index $OBJECT_ID (64) Size: 0-256 Flags: Resident $SECURITY_DESCRIPTOR (80) Size: No Limit Flags: Non-resident $VOLUME_NAME (96) Size: 2-256 Flags: Resident $VOLUME_INFORMATION (112) Size: 12-12 Flags: Resident $DATA (128) Size: No Limit Flags: $INDEX_ROOT (144) Size: No Limit Flags: Resident $INDEX_ALLOCATION (160) Size: No Limit Flags: Non-resident $BITMAP (176) Size: No Limit Flags: Non-resident $REPARSE_POINT (192) Size: 0-16384 Flags: Non-resident $EA_INFORMATION (208) Size: 8-8 Flags: Resident $EA (224) Size: 0-65536 Flags: $LOGGED_UTILITY_STREAM (256) Size: 0-65536 Flags: Non-resident
何故かWindows XP判定。
# fls -i raw -f ntfs -o 1187840 win10simple.raw | grep Windows d/d 1731-144-5: Windows # fls -i raw -f ntfs -o 1187840 win10simple.raw 1731 | grep System32 d/d 3757-144-7: System32 # fls -i raw -f ntfs -o 1187840 win10simple.raw 3757 | grep config d/d 3786-144-7: config r/r 40736-128-5: configmanager2.dll r/r 41741-128-4: ipconfig.exe r/r 42325-128-4: mmc.exe.config r/r 42403-128-4: msconfig.exe r/r 43649-128-5: tetheringconfigsp.dll r/r 43750-128-1: UevAppMonitor.exe.config r/r 44447-128-5: wpr.config.xml r/r 44488-128-5: wsmanconfig_schema.xml # fls -i raw -f ntfs -o 1187840 win10simple.raw 3786 | grep SOFTWARE r/r 44905-128-5: SOFTWARE.LOG1 r/r 44863-128-5: SOFTWARE.LOG2 r/r 49608-128-4: SOFTWARE # icat -i raw -f ntfs -o 1187840 win10simple.raw 49608 > SOFTWARE
hivexの登場。
# hivexget SOFTWARE 'Microsoft\Windows NT\CurrentVersion' | egrep 'ProductName|ReleaseId|"ProductId' "ProductName"="Windows 10 Enterprise Evaluation" "ReleaseId"="1909" "ProductId"="*****-*****-*****-*****" #一応伏せとく
Windows Version Determine!
終わりに
また少しWindowsと仲良くなれました。
ついでに今回の一連の流れをシェルスクリプトにしてみました。初めて書いたシェルスクリプトであり、プログラミングも得意な方ではないので汚いかもしれませんがご査証ください。
# !/bin/sh # oschecker.sh # argument check if [ $# -ne 1 ]; then echo "Invalid argument" exit 1 fi if [ "$1" = "-h" ]; then echo "Usage: oschecker.sh [-h] [imagefile]" echo "" echo "-h print description" echo "" echo "This script can determine Windows Version (above windows 95) from offline disk image!" echo "However, only the raw format is supported." echo "In addition, tools must be pre-instaled." echo "" echo 'Tools:' echo " The Sleuth Kit" echo " (https://www.sleuthkit.org/sleuthkit/)" echo "" echo " hivex " echo " ex) sudo apt install libhivex-bin" echo "" echo "" echo "Have a nice DFIR!" exit 0 fi if [ -f "$1" -a -r "$1" ]; then echo "$1" else echo "File Error" exit 1 fi # image open setting ver="ntfs" img_type=`img_stat -t "$1"` partition_s=`mmls "$1" | grep -i FAT` tmp=`echo "$partition_s" | grep NTFS` if [ -z "$tmp" ]; then ver="fat" fi if [ `echo "$partition_s" | grep -c ''` = 2 ]; then partition_s=`echo "$partition_s" | grep "003:"` fi # image open str="$partition_s" ary=(`echo $str`) # store array partition_addr=`echo ${ary[2]}` analyze_s=`fsstat -i "$img_type" -f "$ver" -o "$partition_addr" "$1"` if [ -z "$analyze_s" ]; then echo "file open Error\n please restart" exit 1 fi # search inode number of registry hive if [ "$ver" = "fat" ]; then tmp=`fls -i "$img_type" -f "$ver" -o "$partition_addr" "$1" | grep -i WINDOWS` str="$tmp" ary=(`echo $str`) target_inode=`echo ${ary[1]} | sed -e 's/://g' | sed -e 's/-.*//'` tmp=`fls -i "$img_type" -f "$ver" -o "$partition_addr" "$1" "$target_inode" | grep -i SYSTEM.DAT` str="$tmp" ary=(`echo $str`) target_inode=`echo ${ary[1]} | sed -e 's/://g' | sed -e 's/-.*//'` icat -i "$img_type" -f "$ver" -o "$partition_addr" "$1" "$target_inode" > SYSTEM.DAT tmp=`strings SYSTEM.DAT | egrep 'ProductName' | uniq | sed -e 's/ProductName//g' | grep "Microsoft Windows"` echo '"ProductName"="'"${tmp}"'"' rm SYSTEM.DAT elif [ "$ver" = "ntfs" ]; then tmp=`fls -i "$img_type" -f "$ver" -o "$partition_addr" "$1" | grep -i WINDOWS` str="$tmp" ary=(`echo $str`) target_inode=`echo ${ary[1]} | sed -e 's/://g' | sed -e 's/-.*//'` tmp=`fls -i "$img_type" -f "$ver" -o "$partition_addr" "$1" "$target_inode" | grep -i system32` str="$tmp" ary=(`echo $str`) target_inode=`echo ${ary[1]} | sed -e 's/://g' | sed -e 's/-.*//'` tmp=`fls -i "$img_type" -f "$ver" -o "$partition_addr" "$1" "$target_inode" | grep d/d | grep config` str="$tmp" ary=(`echo $str`) target_inode=`echo ${ary[1]} | sed -e 's/://g' | sed -e 's/-.*//'` tmp=`fls -i "$img_type" -f "$ver" -o "$partition_addr" "$1" "$target_inode" | grep -i software | grep -v LOG` str="$tmp" ary=(`echo $str`) target_inode=`echo ${ary[1]} | sed -e 's/://g' | sed -e 's/-.*//'` icat -i "$img_type" -f "$ver" -o "$partition_addr" "$1" "$target_inode" > software hivexget software 'Microsoft\Windows NT\CurrentVersion' | egrep 'ProductName|CSDVersion|ReleaseId|"ProductId' rm software else echo "now making" fi
こんな感じで使えます。
# ./oschecker.sh win95.raw win95.raw "ProductName"="Microsoft Windows 95" # ./oschecker.sh win98.raw win98.raw "ProductName"="Microsoft Windows 98" # ./oschecker.sh winMe.raw winMe.raw "ProductName"="Microsoft Windows ME" # ./oschecker.sh winXPsimple.raw winXPsimple.raw "ProductName"="Microsoft Windows XP" "CSDVersion"="Service Pack 3" "ProductId"="*****-***-*******-*****" # ./oschecker.sh winVista.raw winVista.raw "ProductName"="Windows Vista (TM) Enterprise" "ProductId"="*****-***-*******-*****" "CSDVersion"="Service Pack 2" # ./oschecker.sh win7simple.raw win7simple.raw "ProductName"="Windows 7 Enterprise" "ProductId"="*****-***-*******-*****" "CSDVersion"="Service Pack 1" # ./oschecker.sh win8simple.raw win8simple.raw "ProductName"="Windows 8 Enterprise N" "ProductId"="*****-*****-*****-*****" # ./oschecker.sh win10simple.raw win10simple.raw "ProductName"="Windows 10 Enterprise Evaluation" "ReleaseId"="1909" "ProductId"="*****-*****-*****-*****"
変数名とかにツッコミどころ満載だし、なんで関数にしないのとかあると思いますがモチベが来たら直します。