标题: MSDN系列(48)--NTFS Alternate Data Streams简介 创建: 2022-03-17 11:21 更新: 2022-04-11 17:52 链接: https://scz.617.cn/windows/202203171121.txt -------------------------------------------------------------------------- 目录: ☆ 前言 ☆ NTFS ADS 操作手册 1) 向"main stream"写入数据 2) 新增ADS并写入数据 2.1) 输出转向符">" 2.2) powershell 2.3) 其他方案 3) 显示ADS 3.1) dir /R 3.2) streams from sysinternals 3.3) Get-Item 4) 查看ADS内容 4.1) 输入转向符"<" 4.2) Get-Content 5) 复制ADS内容 5.1) Get-Content + Set-Content 5.2) Get-Content + WriteAllBytes 5.3) 其他方案 6) 删除ADS 6.1) streams from sysinternals 6.2) ren + type + del 6.3) Remove-Item 6.4) NTFS->FAT32->NTFS 6.5) Win32 API DeleteFile 7) notepad受限支持ADS 8) 执行ADS中的PE 8.2) wmic process call create 8.6) psexec from sysinternals 8.7) rundll32 8.8) 利用ADS执行代码的其他讨论 9) 附加在目录上的ADS 9.1) 各盘根目录 ☆ ADS的合法用途 1) Zone.Identifier 2) favicon 3) Win32App_1 ☆ 第三方工具 1) streamtools 2) GNU utilities for Win32 3) AlternateStreamView ☆ 后记 ☆ 参考资源 -------------------------------------------------------------------------- ☆ 前言 本文在Win10企业版2016 LTSB 1607(OS Build 14393.4704)上测试。 NTFS ADS (Alternate Data Streams)当年是为了兼容Macintosh Hierarchical File System (HFS)而出场的,NT 3.1开始引入ADS。 文件、目录、根目录都可以有ADS。ADS与"main stream"共用DACLs,无权访问"main stream"时,也无权访问附在其上的ADS。目录可以有ADS,但目录没有"main stream"。 "A:B"存在歧义,OS为规避歧义,始终将之解释成A盘的B文件。若存在名为"A:B"的 ADS,为访问它,比须带上路径,比如"\A:B"。 WFP (Windows File Protection)会保护部分系统文件,但在过去,WFP不会阻止拥有 相应权限的用户向这些受保护的系统文件追加ADS。sfc.exe (SFC/System File Checker)会检查受保护的系统文件,但不会检查附在其上的ADS。不知现在情况是否 有变? Windows Defender SmartScreen会检查ADS。 ☆ NTFS ADS 操作手册 1) 向"main stream"写入数据 有个奇技淫巧,在cmd中echo,不出现结尾的\r\n,与本文无关,只是顺带演示 echo | set /p="unnamed data stream" > some.ext 2) 新增ADS并写入数据 2.1) 输出转向符">" 输出转向符">"支持ADS echo | set /p="secret data stream 0" > some.ext:any_0 echo | set /p="secret data stream 1" > some.ext:any_1 echo | set /p="secret data stream 2" > some.ext:any_2 2.2) powershell powershell -Command "Set-Content -Path '\\?\X:\path\some.ext' -Stream 'any_3' -Value 'secret data stream 3' -NoNewline" 2.3) 其他方案 下列命令或工具均是OS自带的,此处不罗列第三方工具 type some.exe > any.ext:some.exe findstr /V /L Nonexist_Magic some.exe > any.ext:some.exe expand some.exe any.ext:some.exe esentutl /y some.exe /d any.ext:some.exe powershell -Command "Get-Content -Encoding Byte -ReadCount 0 -Path some.exe | Set-Content -Encoding Byte -Path any.ext -Stream some.exe" powershell -Command "&{(Get-Content -Encoding Byte -ReadCount 0 -Path some.exe | Set-Content -Encoding Byte -Path any.ext -Stream some.exe)}" print /D:any.ext:some.exe some.exe makecab some.exe tmp.cab extrac32 /y tmp.cab any.ext:some.exe del tmp.cab 不推荐print,无法完全保持PE原样,会多一个字节,但不影响执行。 type、findstr实际依赖输出转向符">",其余命令自身支持ADS。 3) 显示ADS 3.1) dir /R 从Vista开始dir有个/R开关可以显示ADS $ dir /R some.ext 03/17/2022 11:51 19 some.ext 20 some.ext:any_0:$DATA 20 some.ext:any_1:$DATA 20 some.ext:any_2:$DATA 1 File(s) 19 bytes 注意最后一行,只显示"main stream"大小,19字节,未包含ADS大小。 3.2) streams from sysinternals 参[8] $ streams some.ext $ streams -s . some.ext: :any_0:$DATA 20 :any_1:$DATA 20 :any_2:$DATA 20 这是sysinternals的工具之一,首行是"main stream",后面各行是ADS,最后一列是 ADS大小,20字节。 3.3) Get-Item powershell -Command "Get-Item -Path some.ext -Stream * | Where-Object Stream -ne ':$DATA' | Format-Table Filename,Stream,Length" powershell -Command "Get-ChildItem | Get-Item -Stream * | Where-Object Stream -ne ':$DATA' | Format-Table Filename,Stream,Length" powershell -Command "gci -Recurse | % { gi $_.FullName -Stream * } | where Stream -ne ':$DATA' | Format-Table Filename,Stream,Length" gci、gi、where分别是Get-ChildItem、Get-Item、Where-Object的别名 4) 查看ADS内容 4.1) 输入转向符"<" more不能直接访问ADS,但输入转向符"<"支持ADS $ more < some.ext:any_2 secret data stream 2 type不支持ADS $ type some.ext:any_2 The filename, directory name, or volume label syntax is incorrect. 很多工具不支持ADS,比如UltraEdit就不支持。 4.2) Get-Content $ powershell -Command "Get-Content -Path some.ext -Stream any_2" secret data stream 2 5) 复制ADS内容 先创建any.ext,其内空是一段文本;再向其追加ADS,其内容源自PE。 echo | set /p="unnamed data stream" > any.ext type any.exe > any.ext:any.exe dir /R any.ext 03/17/2022 17:24 19 any.ext 342,392 any.ext:any.exe:$DATA 1 File(s) 19 bytes 假设在any.ext的ADS中隐藏了any.exe,现在想将any.exe还原出来。 下面这样干是不行的,因为ADS内容是二进制的、非文本的,more会破坏原始数据。 more < any.ext:any.exe > any_other.exe 看了一下more的帮助,没有保持raw格式的办法,至少Win10上如此。有人用源自 Windows Resource Kit的cat,这不是自带工具,需要额外安装,此处不考虑。 5.1) Get-Content + Set-Content Copy-Item不支持ADS,可以结合Get-Content、Set-Content复制ADS到普通文件 powershell -Command "Get-Content -Encoding Byte -ReadCount 0 -Path any.ext -Stream any.exe | Set-Content -Encoding Byte -Path any_other.exe" dir /R any_other.exe 我的powershell不够新,不支持"-AsByteStream",只支持"-Encoding Byte",二者 效果等价。"-ReadCount 0"表示一次性读取整个文件送往管道,缺省值是1。 5.2) Get-Content + WriteAllBytes powershell -Command "[IO.File]::WriteAllBytes('any_other.exe', (Get-Content -Encoding Byte -ReadCount 0 -Path any.ext -Stream any.exe))" dir /R any_other.exe 5.3) 其他方案 下列命令或工具均是OS自带的,此处不罗列第三方工具 expand any.ext:some.exe some_other.exe esentutl /y any.ext:some.exe /d some_other.exe 6) 删除ADS 先新增名为any_3的ADS $ echo | set /p="secret data stream 3" > some.ext:any_3 del可以删除"main stream",也就是some.ext,此时会一并删除附在其上的所有ADS。 但是,del没法在保持"main stream"不变的情况下删除指定ADS,del不支持ADS语法。 6.1) streams from sysinternals sysinternals的streams可以在保持"main stream"不变的情况下删除所有ADS,但做 不到删除单个指定ADS。 streams的"-s -d"可以一起用,千万不要对着系统目录用。 6.2) ren + type + del 有一种方案,只依赖cmd内部命令,不依赖其他PE,变相实现保持"main stream"不变 的情况下删除所有ADS。为接近实际用途,用二进制目标文件进行演示。 假设有PE文件any.exe,现对其追加3个ADS echo | set /p="secret data stream 0" > any.exe:any_0 echo | set /p="secret data stream 1" > any.exe:any_1 echo | set /p="secret data stream 2" > any.exe:any_2 下列操作可以变相实现保持"main stream"不变的情况下删除所有ADS ren any.exe waitdel type waitdel > any.exe del waitdel any.exe只剩下"main stream"。该方案利用了type命令只访问"main stream"的特点, 而ren、copy、move等命令会带着ADS。 6.3) Remove-Item Remove-Item可以只删除指定ADS而保留其他ADS及"main stream" powershell -Command "Remove-Item -Path some.ext -Stream any_3" 6.4) NTFS->FAT32->NTFS NTFS支持ADS,FAT32不支持,从NTFS复制文件、目录到FAT32,将自动丢弃ADS,只复 制"main stream"过去。然后再从FAT32复制回NTFS,变相实现保持"main stream"不 变的情况下删除所有ADS。现在硬盘不太可能出现FAT32了,但很多U盘格成FAT32。 6.5) Win32 API DeleteFile 标准Win32 API支持ADS语法,可以编程删除指定ADS DeleteFile( "X:\\path\\some.ext:any_3" ) 7) notepad受限支持ADS $ notepad some.ext:any_3 上述命令在ADS名未尾自动增加".txt"扩展名,实际创建"some.ext:any_3.txt",无 法改变此行为。 下列命令实际去找"some.ext:any_2.txt",但找不到,问你要不要新建,换句话说, notepad无法访问"some.ext:any_2"。 $ notepad some.ext:any_2 很奇怪,对于some.exe,notepad可以创建、访问附在其上的ADS。 $ notepad "some.exe:Zone.Identifier" [ZoneTransfer] ZoneId=3 若some.exe无此ADS,上述命令可以创建ADS,若已有此ADS,上述命令可以编辑ADS。 8) 执行ADS中的PE echo | set /p="unnamed data stream" > any.ext type calc_xp.exe > any.ext:some.exe 特意使用源自XP的calc.exe,这个版本不存在calc.exe.mui的困扰,便于演示。 8.2) wmic process call create wmic process call create X:\path\any.ext:some.exe Executing (Win32_Process)->Create() Method execution successful. Out Parameters: instance of __PARAMETERS { ProcessId = 3980; ReturnValue = 0; }; 上述输出表示成功执行位于ADS中的PE,PID为3980,计算器弹出。 用wmic执行PE时,应该用绝对路径,不要用相对路径。 8.6) psexec from sysinternals 该法依赖非自带软件,不推荐 psexec -d any.ext:some.exe 计算器弹出。psexec支持相对路径。 8.7) rundll32 del any.ext echo | set /p="unnamed data stream" > any.ext type netplwiz_xp.dll > any.ext:some.dll 特意使用源自XP的netplwiz.dll,这个版本不存在netplwiz.dll.mui的困扰,便于演 示。 在管理员级cmd中执行如下命令 rundll32.exe any.ext:some.dll,UsersRunDll 8.8) 利用ADS执行代码的其他讨论 参[9] 此处罗列了大量利用ADS执行代码的奇技淫巧。ADS内容可以是cscript、wscript所支 持的脚本代码,二者支持ADS语法。如果考虑powershell介入,可能性更广。ADS内容 是dll时,还有mavinject.exe可用。若有恶意需求,自行实践之。 9) 附加在目录上的ADS 向目录追加ADS mkdir some.dir echo | set /p="secret data stream 0" > some.dir:any_0 echo | set /p="secret data stream 1" > some.dir:any_1 echo | set /p="secret data stream 2" > some.dir:any_2 删除附加在目录上的ADS streams -d some.dir 下面是另一组演示命令 cd /d X:\path\some.dir echo | set /p="secret data stream 0" > :any_0 dir /R X:\path\some.dir more < "X:\path\some.dir:any_0" 9.1) 各盘根目录 向X盘根目录追加ADS echo | set /p="secret data stream 0" > X:\:any_0 echo | set /p="secret data stream 1" > X:\:any_1 echo | set /p="secret data stream 2" > X:\:any_2 dir /R X:\ 上述dir看不到附加在根目录上的ADS。这些ADS附加在X盘根目录下所有一级子目录的 ".."项上。 dir /R X:\subdir 03/21/2022 13:59 . 03/21/2022 13:59 .. 20 ..:any_0:$DATA 20 ..:any_1:$DATA 20 ..:any_2:$DATA 0 File(s) 0 bytes 访问附加在根目录上的ADS $ more < X:\:any_2 secret data stream 2 删除附加在根目录上的ADS $ streams.exe -d X:\ ☆ ADS的合法用途 1) Zone.Identifier 用IE、Edge、Chrome等现代浏览器下载文件会自动添加名为"Zone.Identifier"的ADS, 可以模拟这种场景。 copy calc_xp.exe some.exe (echo|set /p="[ZoneTransfer]"&echo=&echo|set /p="ZoneId=3") > some.exe:Zone.Identifier more < some.exe:Zone.Identifier ADS内容如下 -------------------------------------------------------------------------- [ZoneTransfer] ZoneId=3 -------------------------------------------------------------------------- 之后在some.exe右键General面板里出现Unlock字样,Unlock实际就是删除 "Zone.Identifier"。 ZoneId的可取值有 -------------------------------------------------------------------------- 0 My Computer 1 Local Intranet Zone 2 Trusted Sites Zone 3 Internet Zone 4 Restricted Sites Zone -------------------------------------------------------------------------- Office也认"Zone.Identifier",打开docx、xlsx、pptx时会有不同。 有时"Zone.Identifier"内容更丰富。 2) favicon 据说IE生成的some.url可能包含名为"favicon"的ADS,用于存放favicon.ico,下面 模拟一下此操作。 (echo|set /p="[InternetShortcut]"&echo=&echo|set /p="URL=https://stackoverflow.com/") > T:\path\some.url notepad T:\path\some.url some.url内容如下 -------------------------------------------------------------------------- [InternetShortcut] URL=https://stackoverflow.com/ -------------------------------------------------------------------------- type favicon.ico > "T:\path\some.url:favicon" dir /R "T:\path\some.url" 2022/04/13 10:39 50 some.url 1,406 some.url:favicon:$DATA 1 File(s) 50 bytes 3) Win32App_1 未研究其用途,备忘 ☆ 第三方工具 参[5],streamtools包含这些功能 -------------------------------------------------------------------------- cs Copy Stream cs src:srcalt dst:dstalt ds Delete Stream ds some:alt sf Strip File (Delete All Alternate Streams) sf some rs Rename Stream rs some oldalt newalt ls List Streams ls some -------------------------------------------------------------------------- 32位工具,Win10上可用 2) GNU utilities for Win32 参[6],这里有一些用Win32 API编写的GNU工具,好像全部支持ADS,我测了cat、 md5sum。 3) AlternateStreamView 参[13],GUI工具,可以对ADS进行View/Copy/Delete操作,操作方便,适合小白。 ☆ 后记 本文主要科普NTFS ADS基本操作,未就ADS恶意应用展开科普,事实上许多恶意软件 广泛使用ADS,与此同时,许多杀毒软件会检查ADS。 ☆ 参考资源 [5] NTFS Alternate Streams: What, When, and How To http://www.flexhex.com/docs/articles/alternate-streams.phtml http://www.flexhex.com/docs/articles/download/streamtools.zip http://www.flexhex.com/docs/articles/download/streams.zip (有源码) [6] GNU utilities for Win32 http://unxutils.sourceforge.net/ http://unxutils.sourceforge.net/UnxUpdates.zip Swiss Unix-in-a-box on Windows https://github.com/minoca/swiss (类似busybox) BusyBox for Windows https://frippery.org/busybox/ https://frippery.org/files/busybox/busybox.exe https://frippery.org/files/busybox/busybox64.exe https://github.com/rmyorston/busybox-w32 [8] Streams https://docs.microsoft.com/en-us/sysinternals/downloads/streams [9] Execute from Alternate Streams https://gist.github.com/api0cradle/cdd2d0d0ec9abb686f0e89306e277b8f [13] AlternateStreamView View/Copy/Delete NTFS Alternate Data Streams https://www.nirsoft.net/utils/alternate_data_streams.html https://www.nirsoft.net/utils/alternatestreamview.zip https://www.nirsoft.net/utils/alternatestreamview-x64.zip