一、前言
本文在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,为访问它,比须带上路径,比如”<path>\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 <DIR> .
03/21/2022 13:59 <DIR> ..
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
上述情形之外的任何使用形式,均需提前向绿盟科技(010-68438880-5462)申请版权授权。如擅自使用,绿盟科技保留追责权利。同时,如因擅自使用博客内容引发法律纠纷,由使用者自行承担全部法律责任,与绿盟科技无关。