首页 > 代码库 > IIS FTP Server Anonymous Writeable Reinforcement, WEBDAV Anonymous Writeable Reinforcement(undone)
IIS FTP Server Anonymous Writeable Reinforcement, WEBDAV Anonymous Writeable Reinforcement(undone)
目录
0. 引言1. IIS 6.0 FTP匿名登录、匿名可写加固2. IIS 7.0 FTP匿名登录、匿名可写加固3. IIS 6.0 Anonymous PUT(WEBDAV匿名可写)加固4. IIS 7.0 Anonymous PUT(WEBDAV匿名可写)加固5. IIS ISAPI Filter(isapiFilters) 6. IIS Extension7. IIS FTP匿名登录的自动化修复8. IIS WEBDAV匿名访问的自动化修复9. IIS 恶意Filter/Extension的自动化修复
0. 引言
0x1: 要通过FTP进行GETSHELL需要满足的条件
基于FTP对目标主机进行GETSHELL本质上是一个写磁盘的动作,要达到这个目的,需要满足几个先决条件
1. 目标服务器开启了FTP匿名访问2. 目标服务器开启了FTP写权限(IIS FTP软件层的逻辑控制)3. 目标服务器的登录帐号(以及所在组)对指定的目录有写的权限(ACL)4. 目标服务器的"FTP根目录"同时也是"WEB服务器的WEB目录"
对于第3点,需要特别注意的是,在默认情况下,磁盘文件的ACL设置中,是没有IUSR_computername的,而在windows中,如果没有明确禁止,则隐含的条件是默认允许,从这点也可以看出,如果我们想要明确的禁止这个FTP目录遭到黑客的写入,应该明确地添加IUSR_computername,并禁止写权限
当这4点同时满足时,黑客就可以通过FTP的漏洞达到直接GETSHELL的目的
Relevant Link:
http://blog.csdn.net/luckyp/article/details/3929895
0x2: 如何进行FTP匿名登录
当目标主机开启了FTP匿名访问之后,在客户端使用
1. 帐号: anonymous、密码: 为空2. 帐号: ftp、密码: 为空
这两个账户都可以登录
0x3: 匿名FTP的来由
大量的匿名FTP站点对所有用户公开文件访问权,目的是发布它们的软件和信息(就是我们常说的下载文件)。鉴于FTP在Internet中仍占据重要的地位,故IIS集成了FTP服务器。在IIS上架构的FTP站点,用户可以用IUSRR_SERVERNAME账户试图连接该服务器,在命令行下用户名是anonymous,密码可以使用任何内容,在Internet Explorer中不用输入任何信息就能匿名登录FTP站点。
Relevant Link:
http://soft.zdnet.com.cn/software_zone/2007/0807/446657.shtml
1. IIS 6.0 FTP匿名登录、匿名可写加固
0x1: IIS 6.0 FTP匿名匿名登录原理
匿名身份验证使用户无需输入用户名或密码便可以访问 Web 或 FTP 站点的公共区域。默认情况下,IUSR_computername 帐户用于允许匿名访问。在 IIS 6.0 中,匿名身份验证不再需要"允许本地登录"用户权限,因为 NETWORK_CLEARTEXT 目前是匿名和基本身份验证的默认登录类型。在安装过程中,将 IUSR_computername 帐户添加到运行 IIS 的计算机上的 Guests 组中。默认情况下,Guest 与 User 组的成员具有相同的访问权限,但是 Guest 帐户将受到更多限制。
0x2: IIS 6.0 FTP启用匿名身份验证
在开始进行高权限操作的时候,出于最佳安全实践(Best Security Practice),我么应该遵循以下原则
只有本地计算机上 Administrators 组的成员才能执行以下过程。作为安全性最佳操作,请使用不属于 Administrators 组的帐户登录计算机,然后使用 runas 命令以管理员身份运行 IIS 管理器。在命令提示符下,
键入 runas /user:Administrative_AccountName "mmc %systemroot%\system32\inetsrv\iis.msc"。
启用匿名身份验证
1. 在 IIS 管理器中,双击本地计算机,右键单击"网站"文件夹、单个网站文件夹、虚拟目录或文件,然后单击"属性"。 1) 服务器上的所有网站均将继承在网站级别设定的配置设置。可以通过配置单个站点或站点元素来覆盖继承。2. 单击"目录安全性"或"文件安全性"选项卡,然后在"身份验证和访问控制"部分中单击"编辑"。3. 选中"启用匿名访问"复选框。4. 单击"确定"两次。
Relevant Link:
http://msdn.microsoft.com/zh-cn/library/cc780334(v=ws.10).aspxhttp://msdn.microsoft.com/zh-cn/library/cc737887(v=ws.10).aspxhttp://msdn.microsoft.com/zh-cn/library/cc740131(v=ws.10).aspxhttp://msdn.microsoft.com/zh-cn/library/cc784103(v=ws.10).aspx
2. IIS 7.0 FTP匿名登录、匿名可写加固
待研究
http://www.iis.net/learn/publish/using-the-ftp-service/configuring-ftp-user-isolation-in-iis-7
Relevant Link:
http://technet.microsoft.com/zh-cn/library/cc770966(v=ws.10).aspx
3. IIS 6.0 Anonymous PUT(WEBDAV匿名可写)加固
0x1: WebDAV简介
基于万维网的分布式创作和版本控制(WebDAV)是一组基于超文本传输协议的技术集合,有利于用户间协同编辑和管理存储在万维网服务器文档。WebDAV最重要的特性包括:
1. 锁: 防止覆盖2. 特性: 1) 创建 2) 移除 3) 查询3. 命名空间管理4. 集合 1) 创建 2) 移除 3) 列举资源
WebDAV是一种基于 HTTP 1.1协议的通信协议.它扩展了HTTP 1.1,在HTTP标准方法以外添加了一些新的方法
1. Options2. Head3. Trace主要由应用程序用来发现和跟踪服务器支持和网络行为。4. Get检索文档5. Put6. Post将文档提交到服务器7. Delete销毁资源或集合8. Mkcol创建集合9. PropFind10. PropPatch针对资源和集合检索和设置属性11. Copy12. Move管理命名空间上下文中的集合和资源13. Lock14. Unlock改写保护
WebDAV 请求的一般结构遵循 HTTP 的格式,并且由以下三个组件构成:
1. 方法声明由客户端执行的方法(Options/Head..)2. 标头描述有关如何完成此任务的指令4. 主体(可选)定义用在该指令或其他指令中的数据,用以描述如何完成此方法 在主体组件中,XML 成为整个 WebDAV 结构中的关键元素
0x2: IIS实现WebDAV原理
IIS实现Webdav是采用的其两种接口
1. CGI(Common Gateway Interface)CGI是外部应用程序(CGI程序)与Web服务器之间的接口标准,是在CGI程序和Web服务器之间传递信息的规程。CGI规范允许Web服务器执行外部程序,并将它们的输出发送给Web浏览器,CGI将Web的一组简单的静态超媒体文档变成一个完
整的新的交互式媒体2. ISAPI(ISA)接口(ISAPI Extension)ISAPI 服务器扩展是可以被 HTTP 服务器加载和调用的 DLL。Internet 服务器扩展也称为 Internet 服务器应用程序 (ISA),用于增强符合 Internet 服务器 API (ISAPI) 的服务器的功能。ISA 通过浏览器应用程序调用,并
且将相似的功能提供给通用网关接口 (CGI) 应用程序
注意和"ISAPI Filter"区分
WebDAV的解析没有采用影射的方式,所以IIS的主程序w3svc.dll本身包含了Webdav的信息,也就是说,webdav的流程和普通的http流量是混合在一起的 ,iis识别出是Webdav的请求后就调用Webdav的处理模块httpext.dll(这是一个ISAPI)
WebDAV的识别流程如下
1. 对于常见几种请求方法GET、HEAD、POST等,因为常见一些映射都支持。所以不能以请求方法作为Webdav请求的判断2. w3svc.dll根据请求头的字段的特征来识别识别 3. 如果请求头里面包含Translate:、If:、Lock-Token:中的一种,就认为是Webdav的请求 4. W3svc.dll还内置了几个别的请求方法TRACK、TRACE等5. TRACK就是用于调试错误的,如果收到这样的请求头,w3svc.dll会原样返回请求数据。相当于我们常见的ping.exe。同时,IIS对TRACK请求没有进行LOG记录,这点我们可以用于来获得banner,而不用担心留下日志记录6. 那么w3svc.dll就会认为是Webdav的请求,交给httpext.dll处理了
0x3: IIS开启WebDAV
为了安全上的考虑,IIS默认并不会启动WebDAV的功能,因此必须另外来激活它。
通过启动“IIS管理器”,展开本地计算机,选择"Web服务扩展"选择"允许"的途径来启动WebDAV功能
Relevant Link:
http://drops.wooyun.org/papers/238http://zh.wikipedia.org/wiki/WebDAVhttp://en.wikipedia.org/wiki/WebDAVhttp://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/844f5e01-4b9e-4dac-897e-2a0bb33f28af.mspx?mfr=truehttp://www.rapid7.com/db/modules/auxiliary/scanner/http/dir_webdav_unicode_bypass
0x4: 黑客如何利用IIS WebDAV进行GETSHELL
在学习各种的攻击技术之前,我们首先要明白这种技术的原理,对于IIS PUT匿名可写也一样,WebDAV本质上就是一种HTTP协议,所以我们进行GETSHELL也就是在构造一定格式的HTTP数据包,将我们的payload发送到服务端的webdav的接口上,如果服务器的webdav同时开启了匿名可写的权限,则可以完成getshell的目的
新建webdav虚拟目录
开启匿名访问
测试iis put可以使用netscan、iis put scanner这些工具来做
0x5: WEBDAV加固
1. 验证客户端配置WebDAV目录的最佳方法取决于要进行的发布类型。当通过IIS来创建虚拟目录时,匿名和集成Windows身份验证都是打开的。虽然这种默认配置对于将客户端连接到服务器、读取网页中的内容以及运行脚本来说可以工作得很好,但要
将客户端发布到目录以及操作该目录上的文件时就会无法胜任。IIS提供了以下身份验证方法: 1) Kerberos: 域内主要的安全验证协议。Kerberos是用于WebDAV客户端身份验证和文件安全性的最佳选项 2) 匿名身份验证: 允许任何人访问该目录。必须关闭对WebDAV目录的匿名访问。如果不控制访问的用户,您的目录可能会受到某些未知客户端的攻击。 3) 基本身份验证: 以明文形式通过连接发送密码。可以截取和解读明文密码。只有在通过安全套接字层加密密码时,才能打开基本身份验证。 4) 摘要式身份验证: 将信息发布到通过Internet和防火墙访问的服务器上的极佳选择,因为密码在网络上是以MD5哈希值的形式来发送的。然而,密码以明文形式保存在Active Directory中。 5) 高级摘要式身份验证: 摘要式身份验证的改进形式,因为除了以MD5哈希值形式通过网络发送密码外,密码还以MD5哈希值的形式(而不是明文形式)保存在Active Directory中。这使得高级摘要式身份验证成为将信息发布到通
过Internet和防火墙访问的服务器的最佳选择 6) 集成Windows身份验证: 在Intranet上设置WebDAV目录时,最为有效 7) .NET Passport身份验证: 使用cookies来验证用户凭据2. 控制访问 2.1 配置Web权限 1) 启用读取、写入和目录浏览:启用这些权限允许客户端查看资源列表并进行修改(除非对这些资源没有写入权限)、发布自己的资源以及处理文件 2) 启用写入;并禁用读取和目录浏览:如果只想让客户端在目录中发布私人信息,而不希望别人查看所发布的内容,可以设置写入权限,但不设置读取和目录浏览权限。该配置在客户端端提交选票或性能检查时非常有用。 3) 启用读取和写入;并禁用目录浏览:如果希望通过隐藏文件名来提高安全性,可设置该配置。然而,请注意,通过隐藏文件名来设置安全性是一种低级的安全防范措施,因为一个故意破坏者可通过试探和错误信息来猜测出文
件名。 4) 启用索引资源:如果打算让客户端搜索目录资源,请确保启用了索引服务。 2.2 使用DACL控制访问 1) WebDAV 利用了平台和Web服务器提供的安全功能,其中包括权限控制和NTFS文件系统中的随机访问控制列表(DACL) 2) 在NTFS文件系统驱动器上设置WebDAV发布目录时,请确保"Everyone"组只有读取权限。然后授予特定的个人或组写入权限。 2.3 保护脚本代码 1) 如果在发布目录中有一些不想让客户端看到的脚本文件,您可以通过不授予"脚本资源访问"权限来拒绝访问。可执行文件将作为静态 HTML文件处理,除非为该目录启用了"脚本和可执行文件"。 2) 要阻止.exe 文件下载并作为HTML文件来查看,但允许其运行,可在发布目录的"虚拟目录"属性页中,将执行权限更改为"脚本和可执行文件",这一权限级别使所有可执行文件受"脚本资源访问"设置的影响。换句话说,如
果选中了"脚本资源访问",有读取权限的客户端可以看到所有的可执行文件;有写入权限的客户端既可运行它们,也可以编辑它们。
Relevant Link:
http://longsago.blog.163.com/blog/static/168237037201111595351401/http://documents.software.dell.com/DOC223423http://msdn.microsoft.com/zh-cn/library/cc779784(v=ws.10).aspx
4. IIS 7.0 Anonymous PUT(WEBDAV匿名可写)加固
待研究
5. IIS ISAPI Filter(isapiFilters)
在IIS下,要想实现后门,或者从本质上讲要实现对HTTP请求的自定义处理,通过自定义的IIS Handler,黑客可以将攻击的payload放在正常的HTTP流量中,可以通过编写IIS Filter、或者IIS Extension来实现
0x1: ISAPI Filter简介
ISAPI filters are DLL files that can be used to modify and enhance the functionality provided by IIS. ISAPI filters always run on an IIS server, filtering every request until they
find one they need to process. The ability to examine and modify both incoming and outgoing streams of data makes ISAPI filters powerful and flexible.
IIS ISAPI Filter的作用
//ISAPI filters can be registered with IIS to modify the behavior of a server. For example, filters can perform the following tasks:1. Change request data (URLs or headers) sent by the client2. Control which physical file gets mapped to the URL(URL Mapping)3. Control the user name and password used with anonymous or basic authentication4. Modify or analyze a request after authentication is complete5. Modify a response going back to the client(Outing Package Filter)6. Run custom processing on "access denied" responses7. Run processing when a request is complete8. Run processing when a connection with the client is closed9. Perform special logging or traffic analysis.10. Perform custom authentication.11. Handle encryption and compression.
0x2: ISAPI Filter Processing Sequence
The following steps outline the interaction between ISAPI filters and IIS:
1. When IIS initially loads an ISAPI filter, it also creates and partially populates an HTTP_FILTER_VERSION structure. It then calls the filter‘s GetFilterVersion function, passing
a pointer to the new structure as a parameter.2. The ISAPI filter populates the HTTP_FILTER_VERSION structure with version information and descriptive information.More importantly, the filter also uses HTTP_FILTER_VERSION to specify which event notifications it should receive(Filter需要告诉IIS自己所关注的事件Event), and to declare the general
priority level for the filter(当多个Filter都注册了同一个事件Event的时候,需要根据Filter的Priority来进行排序). In addition, the filter also indicates whether it is interested in events from secure ports only, unsecure ports only, or both.3. Each HTTP transaction between IIS and a client browser triggers several distinct events. Every time an event occurs for which an ISAPI filter is registered, IIS calls the
filter‘s HttpFilterProc entry-point function(当HTTP事件到达时,调用对应的处理函数).If more than one ISAPI filter is registered for a given event(事件驱动模型), IIS notifies the filters that the event occurred. The filters, which are marked as high, medium, or low
priority, are notified according to priority in descending order. If more than one ISAPI filter is declared the same general priority level, IIS uses the order in which the filters
appear in the FilterLoadOrder property to resolve the tie.4. The ISAPI filter uses the notification type information, passed by IIS as a parameter to HttpFilterProc, to determine which particular data structure is pointed to by the other
HttpFilterProc parameter, pvNotification. The ISAPI filter then uses the data contained in that data structure, as well as in the context structure HTTP_FILTER_CONTEXT, to perform
any custom processing.5. Once processing is complete, the filter returns one of the SF_STATUS status codes to IIS, and IIS continues processing the HTTP request or response until another event occurs
for which ISAPI filters are registered.6. When the Web service is stopped or unloaded, IIS calls TerminateFilter in all ISAPI filters as part of its shutdown sequence, for any filters that implemented and exported the
function. TerminateFilter is typically used to perform cleanup and de-allocation of allocated resources.
0x3: ISAPI Filter Event Notifications
In general, the events that occur during the processing of a typical Internet Information Services (IIS) request and response are regular and predictable. The following list outlines the most common ordering of events.
1. SF_NOTIFY_READ_RAW_DATA: HttpFilterProc Function is passed a pointer to HTTP_FILTER_RAW_DATA Structure (IIS))When a client sends a request, one or more SF_NOTIFY_READ_RAW_DATA notifications occur. Data is read until the client has sent all of the HTTP headers associated with the request.2. SF_NOTIFY_PREPROC_HEADERS: (HttpFilterProc Function is passed a pointer to HTTP_FILTER_PREPROC_HEADERS Structure (IIS))A single SF_NOTIFY_PREPROC_HEADERS notification occurs for each request. This notification indicates that the server has completed preprocessing of the headers associated with the
request, but has not yet begun to process the information in the headers.3. SF_NOTIFY_URL_MAP: (HttpFilterProc Function is passed a pointer to HTTP_FILTER_URL_MAP Structure (IIS))An SF_NOTIFY_URL_MAP notification occurs whenever the server is converting a URL to a physical path. This notification occurs at least once after the preprocessed
header‘s notification for the request, and might occur many additional times during processing of the associated request.4. SF_NOTIFY_AUTHENTICATION: (HttpFilterProc Function is passed a pointer to HTTP_FILTER_AUTHENT Structure (IIS))An SF_NOTIFY_AUTHENTICATION notification occurs just before IIS attempts to authenticate the client. This notification occurs for every new connection
(including anonymous requests), and every time the client sends enabled user credentials for the target URL, in the form of an authorization header, to be authorized by the server.
The AuthPersistence property setting in the metabase directly affects this filter. Note that not all requests are guaranteed to trigger an authentication notification.
This notification only fires for anonymous requests and requests with an authorization header that specifies Basic authentication.5. SF_NOTIFY_AUTH_COMPLETE: (HttpFilterProc Function is passed a pointer to HTTP_FILTER_AUTH_COMPLETE_INFO Structure (IIS))This notification, new to IIS 5.0, offers functionality similar to that of SF_NOTIFY_PREPROC_HEADERS. Specifically, it allows viewing and modification of the method, URL, version,
or headers sent from the client. The key difference between this notification and preprocessed headers is that this notification occurs after the
client‘s identity has been negotiated with the client. Because of the notification‘s timing, the AUTH_USER server variable can be used to reliably obtain the identity of the user.
Also, functionality is provided to retrieve a copy of the token that IIS impersonates when processing the request.6. SF_NOTIFY_READ_RAW_DATA: (HttpFilterProc Function is passed a pointer to HTTP_FILTER_RAW_DATA Structure (IIS))As mentioned in step 1, if the client has more data to send, one or more SF_NOTIFY_READ_RAW_DATA notifications occur at this point. Each one indicates that IIS has read another
chunk whose size equals either the value of the UploadReadAheadSize metabase property (usually 48 KB), or the remaining number of bytes available (if the chunk is the last one).Because many factors can force IIS to adopt a different chunking scheme, additional raw read events are not always completely predictable. Therefore, ISAPI filters should not rely
on the exact behavior described above.NoteNote: At this point, IIS begins processing the substance of the request. This can be done by an ISAPI extension, a CGI application, a script engine such as ASP or PERL,
or by IIS itself for static files. 7. SF_NOTIFY_SEND_RESPONSE: (HttpFilterProc Function is passed a pointer to HTTP_FILTER_SEND_RESPONSE Structure)This event occurs after the request is processed and before headers are sent back to the client.8. SF_NOTIFY_SEND_RAW_DATAAs the request handler returns data to the client, one or more SF_NOTIFY_SEND_RAW_DATA notifications occur.9. SF_NOTIFY_END_OF_REQUESTAt the end of each request, the SF_NOTIFY_END_OF_REQUEST notification occurs.10. SF_NOTIFY_LOG: (HttpFilterProc Function is passed a pointer to HTTP_FILTER_LOG Structure (IIS))After the HTTP request is complete and just before IIS writes the request to its log, the SF_NOTIFY_LOG notification occurs.11. SF_NOTIFY_END_OF_NET_SESSIONWhen the connection between the client and the server is closed, the SF_NOTIFY_END_OF_NET_SESSION notification occurs. If a Keep-Alive connection has been negotiated, it is
possible for many HTTP requests to occur before this notification.
可以看到,整个IIS Event的处理流程就是一个处理状态机的逻辑流程,从一个HTTP数据报达到IIS后开始解析,到最后解析完毕这一整个流程,事件之间是遵循一定的先后顺序的
0x4: ISAPI filter编程
和apache、nginx的模块、插件、Filter编程一样,IIS ISAPI Filter也属于一种插件式编程的架构,也就是说我们在编写DLL程序的时候,需要遵循一定的函数名规范、约定,必须声明实现一些指定的函数,在满足大的框架的前提下,去利用IIS传给Filter的参数去实现自定义的HTTP数据报操作逻辑功能
Every ISAPI filter is contained in a separate DLL that must export some entry-point functions
1. BOOL WINAPI GetFilterVersion( PHTTP_FILTER_VERSION pVer); 该函数是DLL筛选器第一次被加载到站点处理进程时被调用2. DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc,DWORD notificationType,LPVOID pvNotification);该函数用于响应注册在GetFilterVersion 的形参PHTTP_FILTER_VERSION 中的dwFlags通知事件。根据所注册的通知事件进行相应的筛选处理3. BOOL WINAPI TerminateFilter(DWORD dwFlags);该函数是DLL筛选器被站点处理进程卸载时时所调用的处理
这3个函数是我们编写IIS Filter必须要实现的导出函数
The metabase property, FilterLoadOrder, contains a list of all filters that IIS loads when the Web service is started.
Example(redirects HTTP requests to HTTPS)
IIS Filter、IIS Extension本质上是一个DLL,所以我们是在进行DLL编程
使用VS2010创建一个空的DLL项目
并添加2个文件MyISAPIFilter.cpp、MyISAPIFilter.def
MyISAPIFilter.cpp:DLL源代码文件,实现了IIS Filter必须要求实现的导出函数
#define _WIN32_WINNT 0x0400#include <windows.h>#include <httpfilt.h>#define BUFFER_SIZE 2048BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer){ //char tmp[SF_MAX_FILTER_DESC_LEN] = "RedirectHttpToHttps"; // Specify the filter version and description. pVer->dwFilterVersion = HTTP_FILTER_REVISION; lstrcpy((LPWSTR)(pVer->lpszFilterDesc), (LPWSTR)"RedirectHttpToHttps"); // Specify the filter notifications. pVer->dwFlags = SF_NOTIFY_ORDER_HIGH | SF_NOTIFY_PREPROC_HEADERS; return TRUE;}DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD NotificationType, LPVOID pvNotification ){ if (NotificationType == SF_NOTIFY_PREPROC_HEADERS) { char szServerName[BUFFER_SIZE] = ""; char szSecure[2] = ""; char szLocationHeader[BUFFER_SIZE + 32] = ""; char szRequest[BUFFER_SIZE] = ""; DWORD dwBuffSize = 0; // Determine if request was sent over a secure port. dwBuffSize = 2; pfc->GetServerVariable( pfc, "SERVER_PORT_SECURE", szSecure, &dwBuffSize); // If the request is on a secure port, do not process further. if (szSecure[0] == ‘1‘) return SF_STATUS_REQ_NEXT_NOTIFICATION; // Retrieve the URL for the request. dwBuffSize = BUFFER_SIZE; pfc->GetServerVariable( pfc, "URL", szRequest, &dwBuffSize); // Retrieve the server name. dwBuffSize = BUFFER_SIZE; pfc->GetServerVariable( pfc, "SERVER_NAME", szServerName, &dwBuffSize); // Specify the redirection header. wsprintf( (LPWSTR)szLocationHeader, (LPWSTR)"Location: https://%s/%s\r\n\r\n", szServerName, &szRequest[1]); pfc->AddResponseHeaders( pfc, szLocationHeader, 0); pfc->ServerSupportFunction( pfc, SF_REQ_SEND_RESPONSE_HEADER, "302 Object Moved", (DWORD)"Please resubmit the request using a secure port.", 0); return SF_STATUS_REQ_FINISHED; } return SF_STATUS_REQ_NEXT_NOTIFICATION;}
MyISAPIFilter.def:导出函数被导出的时候不能被VC++编译器导出后函数名发生改变,所以使用定义模块文件对三个文件进行导出
LIBRARY "MyISAPIFilter"EXPORTS GetFilterVersion HttpFilterProc
编译之
加载到IIS指定的站点中
Relevant Link:
http://blog.csdn.net/mycoolx/article/details/6913048http://www.codeproject.com/Articles/2570/Discover-ISAPI-Working-with-GET-POST-datahttp://www.codeproject.com/KB/ISAPI/http://msdn.microsoft.com/en-us/library/ms525035.aspxhttp://www.iis.net/configreference/system.webserver/isapifiltershttp://blog.526net.com/?p=378http://msdn.microsoft.com/en-us/library/ms525103(v=vs.90).aspxhttp://msdn.microsoft.com/en-us/library/ms524610(v=vs.90).aspxhttp://msdn.microsoft.com/en-us/library/ms525612(v=vs.90).aspxhttp://msdn.microsoft.com/en-us/library/ms524855(v=vs.90).aspxhttp://www.hacker.com.cn/show-16-1250-1.htmlhttp://www.xfocus.net/articles/200508/813.htmlhttp://technet.microsoft.com/zh-cn/library/cc733109(v=ws.10).aspx
6. IIS Extension
我们已经学习了IIS ISAPI Filter,在继续学习IIS Extension之前,我们需要梳理一下IIS Filter和IIS Extension的概念
/*ISAPI分为两种:ISAPI extension(ISAPI扩展)和ISAPI filter(ISAPI筛选器)*/1. ISAPI服务器扩展(ISAPI extension) 1) 可以被 HTTP 服务器加载和调用的DLL 2) ISAPI扩展(extension)也称为Internet服务器应用程序(ISA),用于增强符合Internet服务器API(ISAPI)的服务器的功能 3) ISAPI扩展(extensio)通过浏览器应用程序调用,并且将相似的功能提供给通用网关接口(CGI)应用程序2. ISAPI筛选器(ISAPI Filter) 1) 在启用ISAPI的HTTP服务器上运行的DLL,用以筛选与服务器之间来回传送的数据 2) 该筛选器可以完成一些前置、后置处理,通过注册事件的通知的方式,当发生选定事件时,筛选器被调用 2.1) 登录或URL映射 2.2) 监视及更改数据(在数据从服务器传输到客户端或相反的过程中) 2.3) 使用ISAPI筛选器提供增强的HTTP请求记录(例如,跟踪登录到服务器的用户)、自定义加密、自定义压缩或其他身份验证方法
ISAPI扩展(ISAPI extension)同样需要3个导出函数(TerminateExtension是可选的):
1. BOOL WINAPI GetExtensionVersion( HSE_VERSION_INFO *pVer);该函数是扩展DLL文件第一次被加载到站点处理进程时被调用。2. DWORD WINAPI HttpExtensionProc( LPEXTENSION_CONTROL_BLOCK lpECB);该函数是IIS服务每次触发ISAPI扩展时所调用的函数。也就是IIS服务增强服务时具体的实现内容通过本函数的调用。3. BOOL WINAPI TerminateExtension( DWORD dwFlags);该函数是ISAPI扩展DLL文件从进程中被载时调用一次。
Example(validate credit number)
IIS Extension的编程和IIS Filter的编程很类似,都是在进行DLL编程
使用VS2010创建一个空的DLL项目
添加2个头文件StdAfx.cpp、StdAfx.h
StdAfx.cpp
// stdafx.cpp : source file that includes just the standard includes// validate.pch will be the pre-compiled header// stdafx.obj will contain the pre-compiled type information#include "stdafx.h"// TODO: reference any additional headers you need in STDAFX.H// and not in this file
StdAfx.h
// stdafx.h : include file for standard system include files,// or project specific include files that are used frequently, but// are changed infrequently//#if !defined(AFX_STDAFX_H__3D1F2106_3F8E_45D4_BC4E_E93F382011FC__INCLUDED_)#define AFX_STDAFX_H__3D1F2106_3F8E_45D4_BC4E_E93F382011FC__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000// Insert your headers here#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers#include <windows.h>// TODO: reference additional headers your program requires here//{{AFX_INSERT_LOCATION}}// Microsoft Visual C++ will insert additional declarations immediately before the previous line.#endif // !defined(AFX_STDAFX_H__3D1F2106_3F8E_45D4_BC4E_E93F382011FC__INCLUDED_)
添加2个源文件validate.cpp、validate.def
validate.def
; Validate.def : Declares the module parameters for the DLL.LIBRARY "Validate"DESCRIPTION ‘Validate ISAPI Extension‘EXPORTS ; Explicit exports can go here HttpExtensionProc @1 GetExtensionVersion @2
validate.cpp
// validate.cpp : Defines the entry point for the DLL application.//#include "StdAfx.h"#include "httpext.h"#include "stdio.h"#define ERR_WRONG_NUMBER_OF_DIGITS 1#define ERR_NOT_A_MASTERCARD 2#define ERR_INVALID_CC 3#define ERR_INVALID_INPUT 4void WriteContext(EXTENSION_CONTROL_BLOCK *pECB, char *pszFormat, ...);BYTE CheckCC(const char *pszNumber){ int i = 0; if(strlen(pszNumber) != 16) return ERR_WRONG_NUMBER_OF_DIGITS; for(i = 0; i < 16; i++) if(!isdigit(pszNumber[i])) return ERR_INVALID_INPUT; if(pszNumber[0] != ‘5‘ || pszNumber[1] < ‘1‘ || pszNumber[1] > ‘5‘) return ERR_NOT_A_MASTERCARD; int nSum; for(i = 0, nSum = 0; i < 16; i += 2) { int nDigit = (pszNumber[i] - 48) * 2; nSum += (nDigit < 10 ? nDigit : nDigit / 10 + nDigit % 10) + (pszNumber[i + 1] - 48); } if(nSum % 10) return ERR_INVALID_CC; return 0;}BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved){ return TRUE;}BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer){ pVer->dwExtensionVersion = HSE_VERSION; strncpy(pVer->lpszExtensionDesc, "Validate ISAPI Extension", HSE_MAX_EXT_DLL_NAME_LEN); return TRUE;}void StartContext(EXTENSION_CONTROL_BLOCK *pECB){ WriteContext(pECB, "<html>\r\n<body>\r\n");}void EndContext(EXTENSION_CONTROL_BLOCK *pECB){ WriteContext(pECB, "</body>\r\n</html>");}void WriteContext(EXTENSION_CONTROL_BLOCK *pECB, char *pszFormat, ...){ char szBuffer[1024]; va_list arg_ptr; va_start(arg_ptr, pszFormat); vsprintf(szBuffer, pszFormat, arg_ptr); va_end(arg_ptr); DWORD dwSize = strlen(szBuffer); pECB->WriteClient(pECB->ConnID, szBuffer, &dwSize, 0);}DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB){ StartContext(pECB); BYTE byRet = CheckCC(pECB->lpszQueryString); if(!byRet) { //this is a valid master card, echo a suitable string to the client WriteContext(pECB, "<p><b><font face=‘Verdana‘ color=‘#008000‘>Congratulations!</font></b></p>"); WriteContext(pECB, "<p><font size=‘2‘ face=‘Verdana‘>%s is a valid matser card #</font></p>\r\n", pECB->lpszQueryString); } else { //this is an invalid master card, echo a proper string to the client! WriteContext(pECB, "<p><b><font face=‘Verdana‘ color=‘#800000‘>Sorry!</font></b></p>"); WriteContext(pECB, "<p><font size=‘2‘ face=‘Verdana‘>What you have entered is an invalid master card#</font></p>\r\n"); } EndContext(pECB); return HSE_STATUS_SUCCESS;}
编译之
载入IIS
Relevant Link:
http://www.codeproject.com/Articles/1432/What-is-an-ISAPI-Extensionhttp://blog.csdn.net/mycoolx/article/details/6913048http://msdn.microsoft.com/en-us/cc302003.aspx
7. IIS FTP匿名登录的自动化修复
需要注意的是
1. 对于WINDOWS IIS FTP API来说,IIS 6.0和IIS 7是两套不同的API,因此针对IIS FTP的匿名访问的禁用,需要同时准备2套API调用代码,因为我们并不知道客户端的IIS是什么版本的2. 我们要修复(禁用)的是IIS FTP的匿名登录,仅仅是匿名登录,因为"可写"并不算系统配置的漏洞,这本来就是正常的功能,而匿名登录才是一个导致黑客入侵的攻击向量
0x1: 通过API方式编程实现IIS 6.0 FTP匿名登录禁用
IIS(Internet Information Service) 6.0属于windows操作系统的一部分,我们可以使用IIS Programmatic Administration SDK API去操作IIS
//IIS Programmatic Administration SDK的适用范围http://msdn.microsoft.com/en-us/library/ms525568(v=vs.90).aspx//MSDN官方的介绍http://msdn.microsoft.com/en-us/library/ms525041(v=vs.90).aspx
Technology
1. Active Directory Service Interfaces (ADSI)Automation-compliant languages like C, Visual C++, Visual Basic, Microsoft Visual Basic Scripting Edition (VBScript), Microsoft JScript, PerlScripthttp://blog.sina.com.cn/s/blog_722787fe0100md61.htmlADSI(Active Directory Services Interface)是Microsoft新推出的一项技术,它统一了许多底层服务的编程接口,程序员可以使用一致的对象技术来访问这些底层服务。 ADSI把这些服务的公共部分提取出来,同时隔离出相异的部分,程序员可以用统一的接口访问底层服务的公共部分,并延伸到底层服务的专有部分2. Windows Management Instrumentation (WMI)Automation-compliant languages like C, C++, Visual Basic, VBScript, or JScript, PerlScripthttp://blog.csdn.net/hzy694358/article/details/67170423. System.DirectoryServices.NET-compliant languages like C# and Visual Basic.NET4. Admin Base Object (ABO) interfacesC, C++, Visual Basic5. Other IIS interfaces for low-level logging and service controlC, C++, Visual Basic
由于windows的IIS API接口是一个在不断发展的体系,因此对于不同版本的操作系统、不同版本的IIS,它们所能使用的API是不同的,在编程和使用的过程中我们需要特别关注不同API对操作系统版本、IIS版本的限制
1. ADSI 1) C/C++/VB6.0 code 2) Script code2. WMI 1) C/C++/VB6.0 code 2) Script code3. ABO 1) C/C++/VB6.0 code
1. ADSI(Active Directory Service Interfaces)技术
Use ADSI to programmatically configure IIS in a script or compiled program. Changes take place immediately without a need to stop and start the server.
适用范围
1. IIS 4.02. IIS 5.03. IIS 5.14. IIS 6.0
code(disabled the ftp anonymous login switch)
// fixftp6.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <atlstr.h>#include <initguid.h>#include <objbase.h>#include <iads.h>#include <adshlp.h>#include <atlbase.h>#include <iiisext.h>#include <iisext_i.c>#include <comdef.h> #include <lm.h> #include <string>#include <sstream>#include <vector>#include <iostream>using namespace std;#pragma comment(lib, "Activeds.lib")#pragma comment(lib, "Adsiid.lib")#pragma comment(lib, "netapi32.lib")wstring logFilename;// FTP 6.0 匿名访问HRESULT SetIISFtpAnonymousState(bool anony, bool applyToAll, vector<wstring> &ftpNames){ wstring restoreNames; HRESULT hr; IADs *pADs = NULL; IADsContainer* iContainer = NULL; IUnknown *pUnk = NULL; IDispatch *pDisp = NULL; //The ADsGetObject function binds to an object given its path and a specified interface identifier. hr = ADsGetObject( L"IIS://localhost/MSFTPSVC", IID_IADsContainer, (void **)&iContainer ); if (FAILED(hr)) { wprintf(L"ADsGetObject failed %x\n", hr); return hr; } //The IADsContainer::get__NewEnum method Retrieves an enumerator object for the container. The enumerator object implements the IEnumVARIANT interface to enumerate the children
of the container object. hr = iContainer->get__NewEnum(&pUnk); if (FAILED(hr)) { wprintf(L"get__NewEnum failed\n"); return hr; } IEnumVARIANT *pEnum; //Retrieves pointers to the supported interfaces on an object. This method calls IUnknown::AddRef on the pointer it returns. hr = pUnk->QueryInterface(IID_IEnumVARIANT, (void**)&pEnum); if (FAILED(hr)) { wprintf(L"QueryInterface failed\n"); return hr; } BSTR className = NULL; IADs *iADs = NULL; ULONG lFetch; VARIANT var; //Initializes a variant. VariantInit(&var); /* Retrieves the specified items in the enumeration sequence. */ hr = pEnum->Next(1, &var, &lFetch); while(hr == S_OK) { if (lFetch == 1) { //Exposes objects, methods and properties to programming tools and other applications that support Automation. pDisp = V_DISPATCH(&var); //The IADs interface defines the basic object features, that is, properties and methods, of any ADSI object. Examples of ADSI objects include users, computers, services,
organization of user accounts and computers, file systems, and file service operations. pDisp->QueryInterface(IID_IADs, (void**)&iADs); //get the class iADs->get_Class(&className); if (wcscmp(className, L"IIsFtpServer") == 0) { BSTR name = NULL; //get the name iADs->get_Name(&name); VARIANT status; VariantInit(&status); //initialize the state V_VT(&status) = VT_BOOL; /* The IADs::Get method retrieves a property of a given name from the property cache 获取当前FTP站点的匿名登录开关状态 */ iADs->Get(L"AllowAnonymous", &status); //loads into the property cache values of the supported properties of this ADSI object from the underlying directory store. iADs->GetInfo(); //是否需要将当前设置应用到所有FTP站点 if (applyToAll) {//all V_VT(&var) = VT_BOOL; //anony:用户传入的匿名访问开关 V_BOOL(&var) = anony; //如果当前FTP站点的匿名登录开关为"打开允许状态",并且传入的参数指示为"需要关闭" if (V_BOOL(&status) && anony == false) { //将匿名访问的登录开关设置为false iADs->Put(L"AllowAnonymous", var); iADs->SetInfo(); //记录设置的FTP列表 if (restoreNames.empty()) { restoreNames = wstring(name); } else { restoreNames += L‘|‘; restoreNames += wstring(name); } wprintf(L"FTP(%s) AllowAnonymous %s\n", name, anony ? L"enabled" : L"disabled"); } } else {//single for (vector<wstring>::iterator it = ftpNames.begin(); it < ftpNames.end(); it++) { if (*it == name) { V_VT(&var) = VT_BOOL; V_BOOL(&var) = anony; iADs->Put(L"AllowAnonymous", var); iADs->SetInfo(); wprintf(L"FTP(%s) AllowAnonymous %s\n", name, anony ? L"enabled" : L"disabled"); } } } } iADs->Release(); SysFreeString(className); } VariantClear(&var); pDisp->Release(); pDisp = NULL; //继续遍历 hr = pEnum->Next(1, &var, &lFetch); } if (!restoreNames.empty()) { WritePrivateProfileString(L"restore", L"ftp", restoreNames.c_str(), logFilename.c_str()); } return hr;} int _tmain(int argc, _TCHAR* argv[]){ HRESULT hr; //ADSI 基于 com如果忽略了调用 CoInitialize 或 OleInitialize,AdsGetObject,它将返回 HRESULT 的 MK_E_SYNTAX (0x800401e4,"无效语法"), hr = CoInitializeEx( NULL, COINIT_MULTITHREADED ); if ( FAILED( hr ) ) { wprintf( L"CoInitialize failed. Error 0x%0x\n", hr ); return hr; } vector<wstring> restoreFtpNames; SetIISFtpAnonymousState(false, true, restoreFtpNames); // 禁用所有 return 0;}
编译后运行
Relevant Link:
http://msdn.microsoft.com/en-us/library/ms524767(v=vs.90).aspx
2. WMI(Windows Management Instrumentation)技术
Use WMI to programmatically configure IIS in a script or compiled program. Changes take place immediately without needing to stop and start the server.
适用范围
1. IIS 6.0
Windows Management Instrumentation是WBEM的Windows实现。通过WMI,我们可以获取关于硬件\软件的数据,也可以提供关于硬件或软件服务的数据给WMI
code(get system information)
// wmi_getsysinfo.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <iostream>#include <comdef.h>#include <Wbemidl.h># pragma comment(lib, "wbemuuid.lib")using namespace std;int _tmain(int argc, _TCHAR* argv[]){ HRESULT hres; /* Initialize COM. 由于用C++编写WMI应用是基于COM技术的,所以必须初始化COM库 */ hres = CoInitializeEx(0, COINIT_MULTITHREADED); if (FAILED(hres)) { cout << "Failed to initialize COM library. " << "Error code = 0x" << hex << hres << endl; return 1; // Program has failed. } /* Initialize 初始化COM库安全级别 */ hres = CoInitializeSecurity( NULL, -1, // COM negotiates service NULL, // Authentication services NULL, // Reserved RPC_C_AUTHN_LEVEL_DEFAULT, // authentication RPC_C_IMP_LEVEL_IMPERSONATE, // Impersonation NULL, // Authentication info EOAC_NONE, // Additional capabilities NULL // Reserved ); if (FAILED(hres)) { cout << "Failed to initialize security. " << "Error code = 0x" << hex << hres << endl; CoUninitialize(); return 1; // Program has failed. } // Obtain the initial locator to Windows Management // on a particular host computer. IWbemLocator *pLoc = 0; /* 连接到WMI命名空间 通过调用CoCreateInstance初始化WMI的定位器(IWbemLocator类型的实例) */ hres = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc); if (FAILED(hres)) { cout << "Failed to create IWbemLocator object. " << "Error code = 0x" << hex << hres << endl; CoUninitialize(); return 1; // Program has failed. } IWbemServices *pSvc = 0; // Connect to the root\cimv2 namespace with the // current user and obtain pointer pSvc // to make IWbemServices calls. /* 调用IWbemLocator::ConnectServer方法,通过这个定位器连接到WMI的命名空间,通过把一个IWbemServices的实例以参数形式传递给ConnectServer方法,就会创建这个服务。如我们需要一些BIOS信息,那么需要使用的
WMI提供程序是Win32_BIOS,则需要连接到ROOT//CIMV2命名空间中。 */ hres = pLoc->ConnectServer( _bstr_t(L"ROOT\\CIMV2"), // WMI namespace NULL, // User name NULL, // User password 0, // Locale NULL, // Security flags 0, // Authority 0, // Context object &pSvc // IWbemServices proxy ); if (FAILED(hres)) { cout << "Could not connect. Error code = 0x" << hex << hres << endl; pLoc->Release(); CoUninitialize(); return 1; // Program has failed. } cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl; // Set the IWbemServices proxy so that impersonation // of the user (client) occurs. /* 设置WMI服务的安全级别 根据上一步得到的服务,设置相应的服务安全级别。通常来说,如果我们没有设置适当的安全属性,COM安全方案不允许一个进程去访问另一个进程,因此如果我们要访问一个外部进程的对象,那么我们应该设置适当的
IWbemServices的安全级别。 */ hres = CoSetProxyBlanket( pSvc, // the proxy to set RPC_C_AUTHN_WINNT, // authentication service RPC_C_AUTHZ_NONE, // authorization service NULL, // Server principal name RPC_C_AUTHN_LEVEL_CALL, // authentication level RPC_C_IMP_LEVEL_IMPERSONATE, // impersonation level NULL, // client identity EOAC_NONE // proxy capabilities ); if (FAILED(hres)) { cout << "Could not set proxy blanket. Error code = 0x" << hex << hres << endl; pSvc->Release(); pLoc->Release(); CoUninitialize(); return 1; // Program has failed. } //通过WQL使用WMI服务 IEnumWbemClassObject* pEnumerator = NULL; hres = pSvc->ExecQuery( bstr_t("WQL"), bstr_t("SELECT * FROM Win32_OperatingSystem"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator); if (FAILED(hres)) { cout << "Query for processes failed. " << "Error code = 0x" << hex << hres << endl; pSvc->Release(); pLoc->Release(); CoUninitialize(); return 1; // Program has failed. } else { IWbemClassObject *pclsObj; ULONG uReturn = 0; while (pEnumerator) { hres = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); if(0 == uReturn) { break; } VARIANT vtProp; // Get the value of the Name property hres = pclsObj->Get(L"Name", 0, &vtProp, 0, 0); wcout << "Manufacturer Name : " << vtProp.bstrVal << endl; VariantClear(&vtProp); } } // Cleanup // ======== pSvc->Release(); pLoc->Release(); CoUninitialize(); return 0;}
Relevant Link:
http://msdn.microsoft.com/zh-cn/library/ms974579.aspxhttp://blog.csdn.net/xscarlet/article/details/1755063http://msdn.microsoft.com/en-us/library/aa394554(v=vs.85).aspx
3. System.DirectoryServices技术
4. System.Web.Management技术
5. ABO(Admin Base Objects)技术
Use ABO to programmatically configure IIS in a compiled program written in C, C++, or Visual Basic 6.0.
Using ABO is the fastest method of configuring IIS. It is faster than using ADSI or WMI because the ADSI and WMI providers are wrappers for ABO. //ADSI和WMI API本质上是对ABO的一层封装,所以使用ABO技术是最高效的一种方法
code(Creating Virtual Directories)
// abo_create_virtualpath.cpp : 定义控制台应用程序的入口点。// Precompiled headers: Not Using Precompiled Headers // (otherwise causes a C1010 error)// Preprocessor Definitions: include UNICODE // (otherwise causes multiple C2664 errors)#define STRICT#define UNICODE#define INITGUID#define WINVER 0x0400#define _WIN32_DCOM#include <WINDOWS.H>#include <OLE2.H>#include <winerror.h>#include <stdio.h>#include <stdlib.h>#include <initguid.h>#include "iadmw.h"#include "iiscnfg.h"// Just #define the data and paths to simplify the sample. // Note that all vroots of a new server must go under the root // node of the virtual server. In the following statements, // the virtual server (1) is "/lm/w3svc/1". The new vroot // will go underneath "/lm/w3svc/1/root" // Also note that these strings are UNICODE /*lm: 本地服务器名W3SVC: IIS服务器2: 第2个站点Root: 站点根目录*/#define NEW_VROOT_PATH TEXT("newvroot") #define NEW_VROOT_PARENT TEXT("/lm/w3svc/1/root") #define NEW_VROOT_FULLPATH TEXT("/lm/w3svc/1/root/newvroot") #define NEW_VROOT_DIRECTORY TEXT("C:\\TEMP") int main (int argc, char *argv[]) { HRESULT hres; IMSAdminBase *pcAdmCom = NULL; // COM interface pointer HRESULT hresError = 0; // Holds the errors returned by the IMSAdminBase API calls DWORD dwRefCount; // Holds the refcount of the IMSAdminBase object DWORD dwResult = 0; METADATA_HANDLE hmdParentHandle; // This is the handle to the parent object of the new vdir. METADATA_HANDLE hmdChildHandle; // This is the handle to the parent object of the new vdir. if (argc < 2) { puts ("Usage: Create_vdir <machine name>\n Ex: Create_Vdir adamston1\n\n"); return -1; } printf("You will be adding a new VRoot path in the metabase. \n"); printf(" Machine Name: %s\n", argv[1]); wprintf ( L" Path: %s\n" L" Full Path: %s/%s\n", NEW_VROOT_PATH, NEW_VROOT_PARENT, NEW_VROOT_PATH); // These are required for creating a COM object. IClassFactory * pcsfFactory = NULL; COSERVERINFO csiMachineName; COSERVERINFO *pcsiParam = NULL; // Fill the structure for CoGetClassObject. csiMachineName.pAuthInfo = NULL; csiMachineName.dwReserved1 = 0; csiMachineName.dwReserved2 = 0; pcsiParam = &csiMachineName; // Allocate memory for the machine name. csiMachineName.pwszName = (LPWSTR) HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, (strlen (argv[1]) + 1) * sizeof (WCHAR) ); if (csiMachineName.pwszName == NULL) { printf ("Error allocating memory for MachineName\n"); return E_OUTOFMEMORY; } // Convert Machine Name from ASCII to Unicode. dwResult = MultiByteToWideChar ( CP_ACP, 0, argv[1], strlen (argv[1]) + 1, csiMachineName.pwszName, strlen (argv[1]) + 1); if (dwResult == 0) { printf ("Error converting Machine Name to UNICODE\n"); return E_INVALIDARG; } // Initialize COM. hresError = CoInitializeEx(NULL, COINIT_MULTITHREADED); if (FAILED(hresError)) { printf ("ERROR: CoInitialize Failed! Error: %d (%#x)\n", hresError, hresError); return hresError; } hresError = CoGetClassObject(GETAdminBaseCLSID(TRUE), CLSCTX_SERVER, pcsiParam, IID_IClassFactory, (void**) &pcsfFactory); if (FAILED(hresError)) { printf ("ERROR: CoGetClassObject Failed! Error: %d (%#x)\n", hresError, hresError); return hresError; } else { hresError = pcsfFactory->CreateInstance(NULL, IID_IMSAdminBase, (void **) &pcAdmCom); if (FAILED(hresError)) { printf ("ERROR: CreateInstance Failed! Error: %d (%#x)\n", hresError, hresError); pcsfFactory->Release(); return hresError; } pcsfFactory->Release(); } /***********************************************/ /* Important Section */ // Open the path to the parent object. hresError = pcAdmCom->OpenKey ( METADATA_MASTER_ROOT_HANDLE, NEW_VROOT_PARENT, METADATA_PERMISSION_WRITE | METADATA_PERMISSION_READ, 1000, &hmdParentHandle); if (FAILED(hresError)) { printf ("ERROR: Could not open the Parent Handle! Error: %d (%#x)\n", hresError, hresError); dwRefCount = pcAdmCom->Release(); return hresError; } printf ("Path to parent successfully opened\n");
/***********************************/ /* Add the new Key for the VROOT */ hresError = pcAdmCom->AddKey ( hmdParentHandle, NEW_VROOT_PATH); if (FAILED(hresError)) { printf ("ERROR: AddKey Failed! Error: %d (%#x)\n", hresError, hresError); hresError = pcAdmCom->CloseKey(hmdParentHandle); dwRefCount = pcAdmCom->Release(); return hresError; } printf ("New Child successfully added\n"); // Close the handle to the parent and open a new one to the child. // This isn‘t required, but when the handle is open at the parent, no other // metabase client can access that part of the tree or subsequent child. // Open the child key because it is lower in the metabase and doesn‘t conflict with as many // other paths. hresError = pcAdmCom->CloseKey(hmdParentHandle); if (FAILED(hresError)) { printf ("ERROR: Could not close the Parent Handle! Error: %d (%#x)\n", hresError, hresError); dwRefCount = pcAdmCom->Release(); return hresError; } hresError = pcAdmCom->OpenKey ( METADATA_MASTER_ROOT_HANDLE, NEW_VROOT_FULLPATH, METADATA_PERMISSION_WRITE | METADATA_PERMISSION_READ, 1000, &hmdChildHandle); if (FAILED(hresError)) { printf ("ERROR: Could not open the Child Handle! Error: %d (%#x)\n", hresError, hresError); dwRefCount = pcAdmCom->Release(); return hresError; } printf ("Path to child successfully opened\n"); /***********************************/ /* The vroot needs a few properties set at the new path in order */ /* for it to work properly. These properties are MD_VR_PATH, MD_KEY_TYPE */ /* and MD_ACCESSPERM. */ METADATA_RECORD mdrNewVrootData; // First, add the MD_VR_PATH - this is required to associate the vroot with a specific // directory on the filesystem mdrNewVrootData.dwMDIdentifier = MD_VR_PATH; // The inheritable attribute means that paths that are created underneath this // path will retain the property from the parent node unless overwritten at the // new child node. mdrNewVrootData.dwMDAttributes = METADATA_INHERIT; mdrNewVrootData.dwMDUserType = IIS_MD_UT_FILE; mdrNewVrootData.dwMDDataType = STRING_METADATA; // Now, create the string. - UNICODE mdrNewVrootData.pbMDData =http://www.mamicode.com/ (PBYTE) NEW_VROOT_DIRECTORY; mdrNewVrootData.dwMDDataLen = (wcslen (NEW_VROOT_DIRECTORY) + 1) * sizeof (WCHAR); mdrNewVrootData.dwMDDataTag = 0; // datatag is a reserved field. // Now, set the property at the new path in the metabase. hresError = pcAdmCom->SetData ( hmdChildHandle, TEXT ("/"), &mdrNewVrootData); if (FAILED(hresError)) { printf ("ERROR: Setting the VR Path Failed! Error: %d (%#x)\n", hresError, hresError); hresError = pcAdmCom->CloseKey(hmdChildHandle); dwRefCount = pcAdmCom->Release(); return hresError; } printf ("Successfully set the vrpath\n"); /***********************************/ // Second, add the MD_KEY_TYPE - this indicates what type of key we are creating - // The vroot type is IISWebVirtualDir mdrNewVrootData.dwMDIdentifier = MD_KEY_TYPE; // The inheritable attribute means that paths that are created underneath this // path will retain the property from the parent node unless overwritten at the // new child node. mdrNewVrootData.dwMDAttributes = METADATA_INHERIT; mdrNewVrootData.dwMDUserType = IIS_MD_UT_FILE; mdrNewVrootData.dwMDDataType = STRING_METADATA; // Now, create the string. - UNICODE mdrNewVrootData.pbMDData = http://www.mamicode.com/(PBYTE) TEXT("IIsWebVirtualDir"); mdrNewVrootData.dwMDDataLen = (wcslen (TEXT("IIsWebVirtualDir")) + 1) * sizeof (WCHAR); mdrNewVrootData.dwMDDataTag = 0; // datatag is a reserved field. // Now, set the property at the new path in the metabase. hresError = pcAdmCom->SetData ( hmdChildHandle, TEXT ("/"), &mdrNewVrootData); if (FAILED(hresError)) { printf ("ERROR: Setting the Keytype Failed! Error: %d (%#x)\n", hresError, hresError); hresError = pcAdmCom->CloseKey(hmdChildHandle); dwRefCount = pcAdmCom->Release(); return hresError; }
printf ("Successfully set the Keytype \n"); /***********************************/ // Now, add the MD_ACCESS_PERM - this tells whether we should read, write or // execute files within the directory. For now, we will simply add // READ permissions. mdrNewVrootData.dwMDIdentifier = MD_ACCESS_PERM; // The inheritable attribute means that paths that are created underneath this // path will retain the property from the parent node unless overwritten at the // new child node. mdrNewVrootData.dwMDAttributes = METADATA_INHERIT; mdrNewVrootData.dwMDUserType = IIS_MD_UT_FILE; mdrNewVrootData.dwMDDataType = DWORD_METADATA; //Create the access perm. DWORD dwAccessPerm = 1; // 1 is read only mdrNewVrootData.pbMDData = http://www.mamicode.com/(PBYTE) &dwAccessPerm; mdrNewVrootData.dwMDDataLen = sizeof (DWORD); mdrNewVrootData.dwMDDataTag = 0; // datatag is a reserved field. // Now, set the property at the new path in the metabase. hresError = pcAdmCom->SetData ( hmdChildHandle, TEXT ("/"), &mdrNewVrootData); if (FAILED(hresError)) { printf ("ERROR: Setting the accessperm failed! Error: %d (%#x)\n", hresError, hresError); hresError = pcAdmCom->CloseKey(hmdChildHandle); dwRefCount = pcAdmCom->Release(); return hresError; } printf ("Successfully set the accessperm\n"); /************************************************/ // We‘re done!!! Just clean up. hresError = pcAdmCom->CloseKey(hmdChildHandle); if (FAILED(hresError)) { printf ("ERROR: Could not close the Child Handle! Error: %d (%#x)\n", hresError, hresError); dwRefCount = pcAdmCom->Release(); return hresError; } printf ("\nYou Have successfully installed a new VRoot at %S\n", NEW_VROOT_FULLPATH); // Release the object dwRefCount = pcAdmCom->Release(); return ERROR_SUCCESS; }
Relevant Link:
http://msdn.microsoft.com/en-us/library/ms525112(v=vs.90).aspxhttp://msdn.microsoft.com/en-us/library/ms524657(v=vs.90).aspxhttp://keicode.com/iis/iis21.phphttp://msdn.microsoft.com/en-us/library/ms524657%28v=vs.90%29.aspx
6. other IIS management interfaces in administration scripts or applications that configure IIS programmatically技术
Relevant Link:
http://msdn.microsoft.com/en-us/library/ms525885(v=vs.90).aspx
0x2: 通过API方式编程实现IIS 7 FTP匿名登录禁用
在IIS 6使用的ADSI(active directory service interface)无法在在IIS 7下使用,因此对于IIS 7的FTP匿名修复,需要使用其他的技术来实现
待研究
Relevant Link:
http://msdn.microsoft.com/en-us/library/ms525041(v=vs.90).aspxhttp://msdn.microsoft.com/en-us/library/ms525885(v=vs.90).aspxhttp://technet.microsoft.com/en-us/library/cc772200(v=ws.10).aspxhttp://forums.iis.net/t/1173524.aspxhttp://technet.microsoft.com/en-us/library/cc731244(v=ws.10).aspxhttp://blogs.msdn.com/b/robert_mcmurray/archive/2012/10/03/programmatically-starting-and-stopping-ftp-sites-in-iis-7-and-iis-8.aspxhttp://www.iis.net/downloads/community/2007/01/iis7-native-api-(cplusplus)-starter-kithttp://technet.microsoft.com/en-us/library/cc732976(v=ws.10).aspx
8. IIS WEBDAV匿名访问的自动化修复
需要明白的是,WEBDAV是一种扩展的HTTP协议,WEBDAV在IIS中本质上也是一种网站的形式存在的,而WEBDAV所共享出的文件夹就是这个网站的根目录
WEBDAV不像FTP那样,是一个独立的服务程序,WEBDAV仅仅是一个扩展协议,允许客户端通过指定的格式进行访问,所以WEBDAV没有匿名登录这一说法,但是可以采用一定的手段对WEBDAV进行加固,大致有如下几个方向
1. 直接禁用IIS WEBDAV扩展开关2. 单独针对每个WEBDAV站点进行目录读写、访问权限的细化设置
下面我们以禁用IIS WEBDAV扩展开关的为例展示修复代码
0x1: 通过API方式编程实现IIS 6 WEBDAV禁用
依然使用ADSI技术进行编程实现
// fixftp6.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <atlstr.h>#include <initguid.h>#include <objbase.h>#include <iads.h>#include <adshlp.h>#include <atlbase.h>#include <iiisext.h>#include <iisext_i.c>#include <comdef.h> #include <lm.h> #include <string>#include <sstream>#include <vector>#include <iostream>using namespace std;#pragma comment(lib, "Activeds.lib")#pragma comment(lib, "Adsiid.lib")#pragma comment(lib, "netapi32.lib")wstring logFilename; // 禁用WEBDAVHRESULT SetIISWebDAVState(bool disable) { HRESULT hr; IADs *pADs = NULL; IADsContainer* iContainer = NULL; IUnknown *pUnk = NULL; IDispatch *pDisp = NULL; hr = ADsGetObject( L"IIS://localhost/w3svc", IID_IADsContainer, (void **)&iContainer ); if (FAILED(hr)) { wprintf(L"ADsGetObject failed %x\n", hr); return hr; } //This class corresponds to the IIsWebService IIS Admin object, and contains the methods and read-only properties for the object. IISWebService* webservice = NULL; hr = iContainer->QueryInterface(IID_IISWebService, (void**)&webservice); if (FAILED(hr)) { wprintf(L"QueryInterface failed\n"); return hr; } if (!disable) { hr = webservice->DisableWebServiceExtension(L"WEBDAV"); if (FAILED(hr)) { wprintf(L"Disable WebDAV failed\n"); } else { hr = webservice->DisableExtensionFile(L"*.dll"); if (!FAILED(hr)) { wprintf(L"WebDAV disabled\n"); } } } else { hr = webservice->EnableWebServiceExtension(L"WEBDAV"); if (FAILED(hr)) { wprintf(L"EnableWebServiceExtension failed\n"); } else { wprintf(L"WebDAV enabled\n"); } } return hr;}int _tmain(int argc, _TCHAR* argv[]){ HRESULT hr; //ADSI 基于 com如果忽略了调用 CoInitialize 或 OleInitialize,AdsGetObject,它将返回 HRESULT 的 MK_E_SYNTAX (0x800401e4,"无效语法"), hr = CoInitializeEx( NULL, COINIT_MULTITHREADED ); if ( FAILED( hr ) ) { wprintf( L"CoInitialize failed. Error 0x%0x\n", hr ); return hr; } SetIISWebDAVState(false); return 0;}
0x2: 通过API方式编程实现IIS 7 WEBDAV禁用
undone
9. IIS 恶意Filter/Extension的自动化修复
undone
Copyright (c) 2014 LittleHann All rights reserved
IIS FTP Server Anonymous Writeable Reinforcement, WEBDAV Anonymous Writeable Reinforcement(undone)