编辑
2025-03-17
hackthebox
00
请注意,本文编写于 33 天前,最后修改于 33 天前,其中某些信息可能已经过时。

目录

JavaScript 反混淆
Intro
Code Obfuscation 代码混淆
什么是混淆
Basic Obfuscation 基本混淆
运行JavaScript代码
Minifying JavaScript code(“缩小”JavaScript代码)
Packing JavaScript code 打包javascript代码
Advanced Obfuscation 高级混淆
Obfuscator 混淆器
Deobfuscation 反混淆
beautify 美化
Deofuscate 反混淆
Reverse Engineering逆向工程
Code Analysis代码分析
HTTP Requests HTTP 请求
Code Variables 代码变量
Code Functions 代码功能
Http请求
curl
Post请求
Decoding 解码
base64
base64编码
base64解码
Hex
hex编码
hex解码
Caesar/Rot13(凯撒密码)
Rot13编码
Rot13解码
其他类型编码
技能测试
summary

JavaScript 反混淆

Intro

如果我们想熟练进行代码分析和逆向工程,代码反混淆是一项需要学习的重要技能。在红/蓝团队练习中,我们经常遇到想要隐藏某些功能的混淆代码,例如利用混淆的 JavaScript 代码来检索其主要负载的恶意软件。如果不了解这段代码在做什么,我们可能不知道该代码到底在做什么,因此可能无法完成红/蓝队练习。

在本模块中,我们首先学习 HTML 页面的一般结构,然后在其中找到 JavaScript 代码。一旦我们这样做了,我们将了解什么是混淆、它是如何完成的以及它在哪里使用,并通过学习如何对此类代码进行反混淆来遵循这一点。一旦代码被反混淆,我们将尝试了解其一般用法,以复制其功能并揭示其手动执行的操作。

将讨论以下主题:

  • 定位 JavaScript 代码
  • 代码混淆简介
  • 如何对 JavaScript 代码进行反混淆
  • 如何解码编码消息
  • 基本代码分析
  • 发送基本 HTTP 请求

Code Obfuscation 代码混淆

什么是混淆

混淆是一种技术,用于使脚本更难以被人类阅读,但从技术角度来看,它可以发挥相同的功能,尽管性能可能会较慢。这通常是通过使用混淆工具自动实现的,该工具将代码作为输入,并尝试以更难以阅读的方式重写代码,具体取决于其设计

例如,代码混淆器通常将代码转换成代码中使用的所有单词和符号的字典,然后在执行期间尝试通过引用字典中的每个单词和符号来重建原始代码。以下是一个简单的 JavaScript 代码被混淆的示例:

用许多语言编写的代码无需用interpreted语言(例如PythonPHPJavaScript进行编译即可发布和执行。 PythonPHP通常驻留在服务器端,因此对最终用户隐藏,而JavaScript通常在client-side的浏览器中使用,代码发送给用户并以明文形式执行。这就是JavaScript经常使用混淆的原因。

开发人员考虑混淆代码的原因有很多。一个常见的原因是隐藏原始代码及其功能,以防止在未经开发人员许可的情况下重复使用或复制它,从而使对代码的原始功能进行逆向工程变得更加困难。另一个原因是在处理身份验证或加密时提供安全层,以防止对代码中可能发现的漏洞进行攻击。

然而,混淆最常见的用途是用于恶意行为。攻击者和恶意行为者通常会混淆其恶意脚本,以阻止入侵检测和防御系统检测其脚本。在下一节中,我们将学习如何混淆简单的 JavaScript 代码,并尝试在混淆之前和之后运行它以记录任何差异。

[!TIP]

必须注意的是,不建议在客户端进行身份验证或加密,因为这样代码更容易受到攻击

Basic Obfuscation 基本混淆

代码混淆通常不是手动完成的,因为有许多针对各种语言的工具可以自动进行代码混淆。尽管许多恶意行为者和专业开发人员开发了自己的混淆工具以使反混淆变得更加困难,但许多在线工具都可以这样做。

运行JavaScript代码

尝试混淆下面这一段代码:

javascript
console.log('HTB JavaScript Deobfuscation Module');

首先我们先测试一下未混淆前代码输出:

image-20250113084855878

Minifying JavaScript code(“缩小”JavaScript代码)

在保持 JavaScript 代码完整功能的同时降低 JavaScript 代码片段的可读性的一种常见方法是 JavaScript 缩小。 Code minification意味着将整个代码放在一行(通常很长)中。 Code minification对于较长的代码更有用,就好像我们的代码仅由一行组成,缩小后看起来不会有太大不同。

许多工具可以帮助我们缩小 JavaScript 代码,例如javascript-minifier 。我们只需复制代码,然后单击Minify ,我们就可以在右侧获得缩小的输出:

image-20250113085234418

再次,我们可以将缩小后的代码复制到JSConsole并运行它,我们看到它按预期运行。通常,缩小的 JavaScript 代码以扩展名.min.js保存。

[!CAUTION]

注意:代码压缩并非 JavaScript 所独有,它还可以应用于许多其他语言,如javascript-minifier所示。

Packing JavaScript code 打包javascript代码

我们尝试将上述源代码在BeautifyTools上混淆,然后我们再在jsconsole上执行试试:

发现输出与原代码一致。

混淆后:

javascript
eval(function(p,a,c,k,e,d){e=function(c){return c};if(!''.replace(/^/,String)){while(c--){d[c]=k[c]||c}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('1.0(\'2 3 4 5\');',6,6,'log|console|HTB|JavaScript|Deobfuscation|Module'.split('|'),0,{}))

[!CAUTION]

注意:上述类型的混淆称为“打包”,通常可以从初始函数“function(p,a,c,k,e,d)”中使用的六个函数参数来识别。

packer混淆工具通常会将代码中的所有单词和符号转换成列表或者字典,然后使用(p,a,c,k,e,d)函数引用来重新构建原始代码。当然每个打包器的(p,a,c,k,e,d)可以不同。然而,它通常包含一定的顺序。

虽然加壳器在降低代码的可读性方面做得很好,但我们仍然可以看到它的主要字符串以明文形式编写,这可能会揭示它的一些功能。这就是为什么我们可能想要寻找更好的方法来混淆我们的代码。

Advanced Obfuscation 高级混淆

目前为止,我们已经能够让我们的代码变得难以阅读且功能无缺,但是唯一的缺点就是代码仍然以明文显示,依旧可直接显示其原功能。

Obfuscator 混淆器

让我们访问https://obfuscator.io 。在单击obfuscate之前,我们将String Array Encoding更改为Base64 ,混淆结果如下所示:

javascript
function _0x252c(){var _0x336065=['nJm1mdm0ogrjA1DrDW','mtKXmti3mJHpuwTLufm','sfrciePHDMfty3jPChqGrgvVyMz1... ... (_0x38d719['shift']());}}}(_0x252c,0xefaae),console[_0x172a9b(0xa7)](_0x172a9b(0xa4)));

这段代码显然更加混乱,我们看不到原始代码的任何残余。我们现在可以尝试在https://jsconsole.com中运行它,以验证它是否仍然执行其原始功能。尝试使用https://obfuscator.io中的混淆设置来生成更多混淆代码,然后尝试在https://jsconsole.com中重新运行它以验证它仍然执行其原始功能。

image-20250113091102155

可以看到输出不变。

Deobfuscation 反混淆

现在我们了解了代码混淆的工作原理,让我们开始学习反混淆。正如有自动混淆代码的工具一样,也有自动美化和反混淆代码的工具

beautify 美化

我们看到当前的代码全部写在一行中。这称为Minified JavaScript代码。为了正确格式化代码,我们需要Beautify我们的代码。最基本的方法是通过我们的Browser Dev Tools

例如,如果我们使用的是 Firefox,我们可以使用 [ CTRL+SHIFT+Z ] 打开浏览器调试器,然后单击我们的脚本secret.js 。这将以原始格式显示脚本,但我们可以单击底部的“ { } ”按钮,这会将脚本Pretty Print为其正确的 JavaScript 格式:

此外,我们可以利用许多在线工具或代码编辑器插件,例如PrettierBeautifier

Deofuscate 反混淆

我们可以找到许多优秀的在线工具来反混淆 JavaScript 代码并将其转换为我们可以理解的东西。 UnPacker是一个很好的工具。让我们尝试复制上面的混淆代码并通过单击UnPack按钮在 UnPacker 中运行它。

[!NOTE]

提示:确保脚本前不要留下任何空行,因为它可能会影响反混淆过程并给出不准确的结果。

Reverse Engineering逆向工程

尽管到目前为止,这些工具在将代码清理成我们可以理解的内容方面做得很好,但一旦代码变得更加模糊和编码,自动化工具清理它就会变得更加困难。如果使用自定义混淆工具对代码进行混淆,则尤其如此。

我们需要手动对代码进行逆向工程,以了解它是如何被混淆的以及它在这种情况下的功能。如果您有兴趣了解有关高级 JavaScript 反混淆和逆向工程的更多信息,您可以查看安全编码 101模块,该模块应该全面涵盖该主题

Code Analysis代码分析

现在我们已经对代码进行了反混淆,我们可以开始检查它:

javascript
function generateSerial() { var flag="HTB { 1_4m_7h3_53r14l_g3n3r470r! } "; var xhr=new XMLHttpRequest(); var url="/serial.php"; xhr.open("POST",url,true); xhr.send(null) }

我们看到, secret.js文件只包含一个函数, generateSerial

HTTP Requests HTTP 请求

Code Variables 代码变量

该函数首先定义一个变量xhr ,它创建一个XMLHttpRequest对象。由于我们可能不知道XMLHttpRequest在 JavaScript 中到底做了什么,让我们 Google XMLHttpRequest来看看它的用途。

读完之后,我们发现它是一个处理 Web 请求的 JavaScript 函数。

定义的第二个变量是URL变量,其中包含/serial.php的 URL,该 URL 应该位于同一域中,因为未指定域。

Code Functions 代码功能

接下来,我们看到xhr.open"POST"URL一起使用。我们可以再次 Google 一下这个函数,我们看到它打开了定义为“ GETPOST ”的 HTTP 请求到URL ,然后下一行xhr.send将发送该请求。

因此, generateSerial所做的只是简单地向/serial.php发送POST请求,而不包含任何POST数据或检索任何返回内容

开发人员可能在需要生成序列号时实现了此功能,例如单击某个Generate Serial按钮时。不过,由于我们没有看到任何类似的生成连载的 HTML 元素,因此开发人员一定还没有使用过这个功能,并保留它以供将来使用。

Http请求

在上一节中,我们发现secret.js主函数正在向/serial.php发送一个空的POST请求。在本节中,我们将尝试使用cURL执行相同的操作,将POST请求发送到/serial.php 。要了解有关cURL和 Web 请求的更多信息,您可以查看Web 请求模块

curl

cURL是一个强大的命令行工具,可用于 Linux 发行版、macOS,甚至最新的 Windows PowerShell 版本。我们可以通过简单地提供 URL 来请求任何网站,并且我们将以文本格式获取它。

Post请求

要发送POST请求,我们应该在命令中添加-X POST标志,并且它应该发送POST请求

shell
curl -s http://SERVER_IP:PORT/ -X POST

[!NOTE]

提示:我们添加“-s”标志以减少不必要的数据使响应混乱

然而, POST请求通常包含POST数据。要发送数据,我们可以使用“ -d "param1=sample" ”标志并包含每个参数的数据,如下所示:

shell
curl -s http://SERVER_IP:PORT/ -X POST -d "param1=sample"

现在我们知道如何使用cURL发送基本的POST请求,在下一节中,我们将利用它来复制server.js正在做的事情,以更好地理解其目的

Decoding 解码

这是我们在Advanced Obfuscation部分的More Obfuscation中提到的混淆的另一个重要方面。许多技术可能会进一步混淆代码,使其难以被人类读取和被系统检测到。因此,您经常会发现包含编码文本块的混淆代码,这些文本块在执行时会被解码。我们将介绍 3 种最常用的文本编码方法

  • base64
  • hex
  • rot13

base64

base64编码通常用于减少特殊字符的使用,因为除了+/之外,以base64编码的任何字符都将以字母数字字符表示。无论输入如何,即使是二进制格式,生成的 Base64 编码字符串也只会使用它们。

base64编码的字符串很容易被发现,因为它们只包含字母数字字符。然而, base64最显着的特点是它使用=字符进行填充。 base64编码字符串的长度必须是 4 的倍数。例如,如果结果输出只有 3 个字符长,则添加额外的=作为填充,依此类推。

base64编码

要将任何文本编码为 Linux 中的base64 ,我们可以回显它并使用 ' |进行管道传输。 ' 到base64

shell
echo https://www.hackthebox.eu/ | base64 aHR0cHM6Ly93d3cuaGFja3RoZWJveC5ldS8K

base64解码

shell
Kriem@htb[/htb]$ echo aHR0cHM6Ly93d3cuaGFja3RoZWJveC5ldS8K | base64 -d https://www.hackthebox.eu/

Hex

另一种常见的编码方法是hex进制编码,它将每个字符编码为其在ASCII表中的hex顺序。例如, a为十六进制的61b62c63 ,依此类推。您可以使用man ascii命令在 Linux 中找到完整的ASCII表。

任何以hex进制编码的字符串都仅由十六进制字符组成,即只有 16 个字符:0-9 和 af。这使得识别hex进制编码的字符串就像识别base64编码的字符串一样容易。

hex编码

shell
echo xxxx | xxd -p

hex解码

要解码hex进制编码的字符串,我们可以使用xxd -p -r命令:

shell
❯ echo 6675636b750a | xxd -p -r fucku

Caesar/Rot13(凯撒密码)

另一种常见且非常古老的编码技术是凯撒密码,它将每个字母移动固定的数字。例如,移位 1 个字符使a变为bb变为c ,依此类推。凯撒密码的许多变体使用不同数量的移位,其中最常见的是rot13 ,它将每个字符向前移位 13 次。

尽管这种编码方法使任何文本看起来都是随机的,但仍然可以发现它,因为每个字符都映射到特定的字符。例如,在rot13中, http://www变为uggc://jjj ,它仍然具有一些相似之处并且可能被识别为这样。

Rot13编码

Linux 中没有特定的命令来执行rot13编码。然而,创建我们自己的命令来进行字符转换相当容易:

shell
echo https://www.hackthebox.eu/ | tr 'A-Za-z' 'N-ZA-Mn-za-m' uggcf://jjj.unpxgurobk.rh/

Rot13解码

shell
❯ echo fucku | tr 'A-Za-z' 'N-ZA-Mn-za-m' shpxh ❯ echo shpxh | tr 'A-Za-z' 'N-ZA-Mn-za-m' fucku

其他类型编码

我们可以在网上找到数百种其他编码方法。尽管这些是最常见的,但有时我们会遇到其他编码方法,这可能需要一些经验来识别和解码。

有些工具可以帮助我们自动确定编码类型,例如Cipher Identifier 。使用Cipher Identifier尝试上面的编码字符串,看看它是否可以正确识别编码方法

除了编码之外,许多混淆工具还利用加密,即使用密钥对字符串进行编码,这可能会使混淆的代码很难进行逆向工程和反混淆,特别是如果解密密钥未存储在脚本本身中的话。

[!NOTE]

注意区分编码和加密:

加密:

特点

  • 需使用密钥:加密和解密过程需要密钥。
  • 数据不可读:加密后的数据对人类和计算机是不可理解的。
  • 安全性要求高:加密算法设计需要确保即使加密数据被截获,没有密钥也无法解密。

编码:

特点

  • 无需密钥:编码和解码不需要密钥。
  • 数据可读性好:编码后的数据通常仍然是可读的或可轻松解码。
  • 强调兼容性:用于确保数据在不同环境中能正确表示。

技能测试

image-20250113105138866

summary

Congratulations on reaching the end of JavaScript Deobfuscation. We hope you can now recognize obfuscated scripts and deobfuscate them, decode their output, and replicate their functions.

The following is a summary of what we learned:

  • First, we uncovered the HTML source code of the webpage and located the JavaScript code.
  • Then, we learned about various ways to obfuscate JavaScript code.
  • After that, we learned how to beautify and deobfuscate minified and obfuscated JavaScript code.
  • Next, we went through the deobfuscated code and analyzed its main function
  • We then learned about HTTP requests and were able to replicate the main function of the obfuscated JavaScript code.
  • Finally, we learned about various methods to encode and decode strings.
如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:Hyrink

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!