How We Decrypt File Encryption on the TP-Link Tapo C200 Camera

Home » Hawktesters Cybersecurity Research » How We Decrypt File Encryption on the TP-Link Tapo C200 Camera

During one of our investigations on the TP-Link Tapo C200 camera, we found two files that caught our attention: /etc/sys_conf_data and /etc/usr_conf_data.
Both of these files were not directly readable and appeared to be encrypted. However, after a reverse engineering process, we managed to decrypt their contents which revealed a lot of internal information.
Here’s how we did it:

Field reconnaissance

Let’s begin by examining two particularly interesting files located in the directory tree extracted using binwalk:

└─$ find . | grep  'conf_data'
./extractions/flash_fixed.bin.extracted/5D800/squashfs-root/etc/usr_conf_data
./extractions/flash_fixed.bin.extracted/5D800/squashfs-root/etc/sys_conf_data                                           

Our first step was to identify which system binaries were accessing these files. To do so, we initiated a reverse engineering analysis.

We used the following search command:

grep -ir 'conf_data'

This revealed a match in the binary file libuc_convert.so:

grep: extractions/flash_fixed.bin.extracted/5D800/squashfs-root/usr/lib/libuc_convert.so: binary file matches                                                                                                              

libuc_convert.so and its roles

Next, we loaded the library into a disassembler and searched for references to the strings we had identified earlier: usr_conf_data and sys_conf_data.

The string usr_conf_data has an access reference and leads to the following point:

When examining references to FUN_0001301c, we finally identified a function that makes use of cryptographic routines, exactly what we were looking for.

A preliminary analysis reveals the existence of a function named doUserConfigConvert, which appears to be responsible for loading our configuration paths.

But which binary actually uses this library and calls the doUserConfigConvert function? In other words, what is the main entry point?

We performed another search using grep and found several references, including a directory named uc_convert:

─$ grep -ir 'doUserConfigConvert' 
grep: libuc_convert.so: binary file matches
grep: extractions/flash_fixed.bin.extracted/5D800/squashfs-root/usr/lib/libuc_convert.so: binary file matches
grep: extractions/flash_fixed.bin.extracted/5D800/squashfs-root/lib/libuci.so: binary file matches
grep: extractions/flash_fixed.bin.extracted/5D800/squashfs-root/bin/uc_convert: binary file matches

This suggests that the uc_convert binary is likely the main component responsible for invoking the doUserConfigConvert function, either directly or via the linked library.

Everything is starting to make sense, so let’s move forward.

After reviewing some of the string messages—such as “get encrpt key failed!”, “make hash string failed!”, and “read flash failed!”—we were able to infer the following process:

  1. Base Key Retrieval: The camera reads a string from a configuration partition within the firmware.

  2. Hash Generation: This string is then processed using a hash function to derive the decryption key.

  3. DES Decryption: The resulting hashed key is used to decrypt the files via the DES algorithm.

Looking for and putting the pieces together

Step 1: Get the key from the firmware.

Let’s see the following disassembly:

0000301c  int32_t sub_301c(int32_t arg1)
00003050      int32_t var_14 = 0
00003054      int32_t var_20 = 0
00003058      int32_t var_1c = 0
0000305c      char var_18 = 0
00003060      int32_t $v0 = sub_37e0(1, 2, &var_14)
00003070      int32_t $a1 = var_14
00003080      int32_t $v0_2
00003080      if ($v0 != 0 || ($v0 == 0 && $a1 s<= 0) || ($v0 == 0 && $a1 s> 0 && $a1 s>= 0xd))
00003090          printf(0x5e38, $a1)  {"get flash partition<firmware des…"}
0000309c          $v0_2 = 0xffffffff
00003080      if ($v0 == 0 && $a1 s> 0 && $a1 s< 0xd)
000030a0          int32_t $v0_3 = malloc($a1, $a1)
000030ac          if ($v0_3 == 0)
000030bc              puts(0x5aa0)  {"No enough memory!"}
000030c8              $v0_2 = 0xffffffff
000030cc          else
000030cc              int32_t $s1_1 = var_14
000030dc              memset($v0_3, 0, $s1_1)
000030f0              int32_t $v0_5
000030f0              int32_t $a0_3
000030f0              int32_t $a0_4
000030f0              if (sx.d(data_2e06c0) == 0)
0000311c                  $v0_5 = sub_3a8c(1, $v0_3, 2)
00003124                  if ($v0_5 != 0)
00003134                      $a0_3 = 0x5e74  {"read flash failed!"}
00003164                      label_3164:
00003164                      puts($a0_3)
00003174                      $a0_4 = $v0_3
000031a8                      label_31a8:
000031a8                      free($a0_4)
000031b0                      $v0_2 = 0xffffffff
00003100              else
00003100                  strncpy($v0_3, 0x16940, $s1_1)
00003124              if (sx.d(data_2e06c0) != 0 || (sx.d(data_2e06c0) == 0 && $v0_5 == 0))
00003140                  $a0_4 = $v0_3
0000313c                  if (sx.d(*$v0_3) == 0)
0000313c                      goto label_31a8
00003150                  if (sub_2f64($a0_4, &var_20) != 0)
0000315c                      $a0_3 = 0x5e88  {"make hash string failed!"}
0000315c                      goto label_3164
00003184                  memcpy(arg1, &var_20, 8)
00003194                  free($v0_3)
000031a0                  $v0_2 = 0
000031c4      return $v0_2

A crucial observation lies in the following snippet:

strncpy(dest, 0x16940, len);
if (sx.d(0x2e06c0) != 0 || (sx.d(0x2e06c0) == 0 && some_flag == 0))

At offset 0x2E06C0 in the firmware, we found the hardcoded string "C200 3.0". This string is copied into a buffer and later used as the base value for generating the encryption key. A conditional check ensures the presence or validity of this string before the decryption routines proceed.

This confirms that the encryption key is not generated dynamically or derived from secure user input. Instead, it is based on a static, hardcoded value that can be easily extracted from the firmware, representing a significant security weakness.

└─$ xxd -s 0x2e06c0 -l 16 flash_fixed.bin
002e06c0: 4332 3030 2033 2e30 0000 0000 0000 0000  C200 3.0........
                                                               

Let’s move to this part now.

00003124              if (sx.d(data_2e06c0) != 0 || (sx.d(data_2e06c0) == 0 && $v0_5 == 0))
00003140                  $a0_4 = $v0_3
0000313c                  if (sx.d(*$v0_3) == 0)
0000313c                      goto label_31a8
00003150                  if (sub_2f64($a0_4, &var_20) != 0)
0000315c                      $a0_3 = 0x5e88  {"make hash string failed!"}
0000315c                      goto label_3164
00003184                  memcpy(arg1, &var_20, 8)
00003194                  free($v0_3)
000031a0                  $v0_2 = 0

And let’s focus specifically on the following validation:

00003150                  if (sub_2f64($a0_4, &var_20) != 0)

Step 2: The hash generation.

Here in sub_2ec0, we see that there is a hash generation.

00002f64  int32_t sub_2f64(int32_t arg1, int32_t arg2)
00002f8c      int32_t $a0
00002f8c      if (arg1 == 0 || (arg1 != 0 && arg2 == 0))
00002f9c          $a0 = 0x5dec  {"NULL == srcStr || NULL == hashSt…"}
00002f8c      uint32_t $v0_1
00002f8c      int32_t $v0_2
00002f8c      if (arg2 != 0 && arg1 != 0)
00002fa0          $v0_1 = sub_2ec0(arg1, arg2)
00002fac          if ($v0_1 != 0)
00002fdc              memset(arg2, 0, 8)
00002ffc              snprintf(arg2, 9, 0x5e30, $v0_1, &data_1e750)  {"%08x"}
00003004              $v0_2 = 0
00002fb8          else
00002fb8              $a0 = 0x5e10  {"calculate hash value failed!"}
00002fac      if (arg1 == 0 || (arg1 != 0 && arg2 == 0) || (arg1 != 0 && arg2 != 0 && $v0_1 == 0))
00002fc0          puts($a0)
00002fcc          $v0_2 = 0xffffffff
00003014      return $v0_2

Let’s see this function to know how the hash is generated.

00002ec0  uint32_t sub_2ec0(int32_t arg1, int32_t arg2)
00002ecc      if (arg1 == 0)
00002efc          void* var_10 = &data_1e750
00002f04          puts(0x5ddc, arg2, 0x7fff0000)  {"str is null ptr"}
00002f5c          return 0
00002ed4      int32_t $a0 = arg1 + 1
00002ed8      uint32_t $v0 = 0
00002edc      int32_t $v1 = 0
00002f30      int32_t $t0_1
00002f30      do
00002f38          int32_t $a1 = sx.d(*($a0 - 1))
00002f40          $t0_1 = $a0
00002f3c          if ($a1 == 0)
00002f3c              break
00002f48          if ($v1 u>= 0xc)
00002f48              break
00002f18          int32_t $a3_1 = $v0 * 0x1f
00002f14          if ($a1 != 0x22)
00002f1c              $v1 = $v1 + 1
00002f2c              $v0 = modu.d($a3_1 + $a1, 0x7fffffff)
00002f34          $a0 = $a0 + 1
00002f34      while ($t0_1 != 0)
00002f54      $v0 = 0x7fffffff & $v0 << 0
00002f50      return $v0

The following is a pseudocode representation of the hash generation.

FUNCTION CalculateNumericHash(str_input):
IF str_input IS NULL THEN
PRINT "Error: str_input is a null pointer for CalculateNumericHash."
RETURN 0
END IF

hash_value = 0
char_count = 0
current_char_ptr = str_input
MODUL_VALUE = 0x7FFFFFFF // (2^31 - 1)

LOOP INDEFINITELY:
current_char = DEREFERENCE(current_char_ptr)

IF current_char IS NULL_CHARACTER THEN
BREAK
END IF

IF char_count IS GREATER_THAN 11 THEN
// Process a maximum of 12 relevant characters
BREAK
END IF

IF current_char IS NOT EQUAL_TO '"' THEN
// Ignore double quotes
char_count = char_count + 1

// Perform the multiplication and addition in a 32-bit context.
// Any overflow here would be implicitly handled.
intermediate_result = (hash_value * 0x1F) + current_char
hash_value = intermediate_result MODUL MODUL_VALUE
END IF

current_char_ptr = current_char_ptr + 1
END LOOP
RETURN hash_value
END FUNCTION

// Function: GenerateFinalHashString (Corresponds to sub_2f64)
// Purpose: Takes an input string, calculates its numeric hash, and formats it
// as an 8-character hexadecimal string.
//
// Parameters:
// src_string: The input string to hash.
// output_buffer: A pointer to the buffer where the final hash string will be stored.
// Must be at least 9 bytes (8 characters + null terminator).
//
// Returns:
// 0 on success.
// -1 (or 0xFFFFFFFF) on error (null input, hash calculation failure).

FUNCTION GenerateFinalHashString(src_string, output_buffer):
// 1. Validate inputs
IF src_string IS NULL OR output_buffer IS NULL THEN
PRINT "Error: src_string or output_buffer is null."
RETURN -1
END IF

// 2. Calculate the numeric hash
numeric_hash = CalculateNumericHash(src_string)

// 3. Check if the numeric hash calculation was successful (did not return 0 due to error)
IF numeric_hash IS EQUAL_TO 0 THEN
// If the numeric hash is 0, it could be a valid value or an error.
// The original pseudocode implied that a 0 return from sub_2ec0 indicated "str is null ptr" error.
// We assume here that any 0 from CalculateNumericHash is considered a failure.
PRINT "Error: Failed to calculate numeric hash value."
RETURN -1
END IF

// 4. Format the numeric hash into an 8-character hexadecimal string
// Clear the output buffer (first 8 bytes)
MEMSET(output_buffer, 0, 8)

// Format the numeric hash as a hexadecimal string with leading zeros into output_buffer,
// ensuring a maximum of 9 bytes (including the null terminator).
SNPRINTF(output_buffer, 9, "%08x", numeric_hash)

// 5. Return success
RETURN 0 // Success
END FUNCTION

Key Features:

  • Length Limitation: Only the first 12 characters of the input string are considered in the hash calculation. Any characters beyond this limit are ignored.

  • Character Filtering: Double quotation marks (", ASCII 0x22) are explicitly skipped during the hash computation. They neither contribute to the final hash value nor count toward the character limit (char_count).

  • Hashing Formula: The algorithm applies the following iterative formula:
    (previous_hash * 0x1F) + current_character
    The result is then taken modulo 0x7FFFFFFF (2,147,483,647 or 2³¹−1), ensuring the final value stays within the range of a signed 31-bit integer. The multiplier 0x1F (31 in decimal) is a small prime commonly used in lightweight hash functions to minimize collisions.

  • Output Format: The resulting numerical hash is formatted as an 8-character hexadecimal string, padded with leading zeros if necessary (e.g., 0000ABCD) to maintain a consistent length.

So the code to generate our hash from the key is as follows.

def hash_function_corrected(s: str) -> int:
    """
    Calculates a hash value based on the provided C algorithm,
    emulating 32-bit unsigned integer overflow for exact match.
    Args:
        s: The input string.
    Returns:
        The calculated hash as an unsigned integer.
    """
    if s is None:
        print("str is null ptr")
        return 0
    hash_val = 0
    char_count = 0
    # Define the 32-bit unsigned integer maximum value for overflow simulation
    UINT_MAX_32_BIT = 2**32 
    MODULO_VALUE = 0x7fffffff # 2147483647
    for char_code in map(ord, s):
        if char_count > 0xb:  # 0xb is 11 in decimal
            break
        if char_code != ord('"'):
            char_count += 1
            # Simulate C's intermediate 32-bit unsigned integer arithmetic
            # The calculation (char_code + hash_val * 0x1f) will first behave
            # as an unsigned 32-bit integer in C, which means it will wrap around
            # if it exceeds 2^32 - 1. We apply % UINT_MAX_32_BIT to simulate this.
            temp_val = (char_code + hash_val * 0x1f) % UINT_MAX_32_BIT
            # Then, apply the final modulo operation as in the C code
            hash_val = temp_val % MODULO_VALUE
    return hash_val
def main_corrected():
    buf = "C200 3.0"
    key = hash_function_corrected(buf)
    print(f"KEY: {key:08x}")
if __name__ == "__main__":
    main_corrected()

Let’s see the result.

└─$ python3 key.py                                                                                                                
KEY: 5982a825
                                                           

Step 3: The decryption mechanism.

To decrypt our information, we must pass the previous key in hexadecimal format, so our hash 5982a825 would be in hexadecimal 3539383261383235

With all this information, we will proceed to decrypt the files via the following command:

openssl enc -d -des-ecb -nopad -K 3539383261383235 -in usr_conf_data -out usr_conf_data_decrypt

Once decrypted, we identify a zlib-compressed data block.

After extraction with Binwalk, the information becomes visible:

Some configurations of interest.

The complete list:

usr_conf_data
timing_reboot
people_detection
system
luci
auto_reboot
ptz_plan
cloud_config
motion_detection
tp_manage
target_track
tapo_care
smart_msg_push_capability
pattern
smart_detection
function
cover
video_capability
audio_capability
multicast
relayd_config
playback
video
linecrossing_detection
intrusion_detection
dhcpc
msg_alarm_plan
video_message
device_info
msg_push_plan
system_state_audio
harddisk_manage
ai_enhance_capability
abnormal_events
lens_mask
unusual_detection
audio_config
plan_advance
auto_upgrade
msg_alarm
ffs_dss_pubkey
uhttpd
smart_data
sound_detection
app_component
record_control
telemetry
onvif
linkage_capability
preset
dhcpd
record_plan
protocol
wlan_runtime
cloud_iot
image
OSD_capability
tamper_detection
network
tour
wlan
msg_push
motion_detection_cloud
ucitrack
user_management
config on_off 'reboot'
        option enabled 'off'
        option day '0'
        option time '03:00:00'
        option random_range '30'
        option last_reboot_time '0'
config on_off 'detection'
        option enabled 'off'
config notify_list 'notify_list'
        option record_enabled 'on'
        option msg_push_enabled 'on'
        option light_alarm_enabled 'on'
        option sound_alarm_enabled 'on'
config plan 'arming_schedule'
        option monday '["0000-2400"]'
        option tuesday '["0000-2400"]'
        option wednesday '["0000-2400"]'
        option thursday '["0000-2400"]'
        option friday '["0000-2400"]'
        option saturday '["0000-2400"]'
        option sunday '["0000-2400"]'
config region_info 'region_info_1'
        option id '1'
        option pt1_x '0'
        option pt1_y '0'
        option pt2_x '10000'
        option pt2_y '0'
        option pt3_x '10000'
        option pt3_y '10000'
        option pt4_x '0'
        option pt4_y '10000'
        option sensitivity '50'
        option threshold '0'
        option percentage '1'
config system 'sys'
        option is_factory '1'
        option diagnose_mode 'off'
        option dev_alias 'Tapo_Camera'
        option avatar 'room'
        option makeroom_status '0'
        option append_dns '0.0.0.0'
        option network_type 'none'
config setting 'basic'
        option timezone 'UTC-00:00'
        option timing_mode 'ntp'
        option zone_id 'Europe/London'
config timing 'ntp'
        option server '0.0.0.0'
        option ntp_port '999'
        option timing_interval '1440'
config debug 'debug'
        option coredump_enabled '0'
config dst 'dst'
        option enabled '1'
        option synced '0'
        option has_rule '0'
        option dst_start_1 '---'
        option dst_end_1 '---'
        option dst_savings_1 '---'
        option dst_start_2 '---'
        option dst_end_2 '---'
        option dst_savings_2 '---'
        option dst_local_start '---'
        option dst_local_end '---'
        option dst_offset '---'
config core 'main'
config extern 'flash_keep'
config internal 'languages'
config internal 'sauth'
config internal 'ccache'
config internal 'themes'
config font_info 'font'
        option display 'ntnb'
        option size 'auto'
        option color_type 'auto'
        option color 'white'
config date_info 'date'
        option enabled 'on'
        option x_coor '0'
        option y_coor '0'
config date_info 'week'
        option enabled 'off'
        option x_coor '6000'
        option y_coor '500'
config date_info 'logo'
        option enabled 'on'
        option x_coor '0'
        option y_coor '9150'
config label_info 'label_info_1'
        option enabled 'off'
        option text 'TP IPC'
        option x_coor '0'
        option y_coor '700'
config label_info 'label_info_2'
        option enabled 'off'
        option text '
        option x_coor '1000'
        option y_coor '4000'
config label_info 'label_info_3'
        option enabled 'off'
        option text '
        option x_coor '1000'
        option y_coor '6000'
config zoom 'zoom'
        option display '2'
        option x_coor '4000'
        option y_coor '9000'
config azimuth 'azimuth'
        option display '2'
        option x_coor '1000'
        option y_coor '9000'
config preset 'preset'
        option display '2'
        option x_coor '6000'
        option y_coor '9000'
config on_off 'reboot'
        option enabled 'off'
        option day '7'
        option time '(03:00)'
config config 'plan_config'
        option enabled '0'
        option resume_time '5'
config router_post 'bind'
        option username ''
        option accountId ''
        option bindCode ''
config cloud_reply 'device_status'
        option bind_status '0'
        option reset_status '1'
config cloud_reply 'upgrade_info'
        option type ''
        option version ''
        option release_date ''
        option download_url ''
        option location ''
        option release_log ''
        option release_log_url ''
config data_collect 'onboarding'
        option lastOnboardingTimestamp '0'
config data_collect 'extra_bind'
        option need_bind '0'
        option username ''
        option password ''
config data_collect 'upgrade_status'
        option state '0'
        option lastUpgradingSuccess '0'
config on_off 'motion_det'
        option enabled 'on'
        option sensitivity 'medium'
        option digital_sensitivity '50'
config notif_list 'motion_notif_list'
        option app_enabled 'off'
        option client_enabled 'off'
        option record_enabled 'on'
        option msg_push_enabled 'on'
        option light_alarm_enabled 'on'
        option sound_alarm_enabled 'on'
config region_info 'region_info_1'
        option height '10000'
        option width '10000'
        option x_coor '0'
        option y_coor '0'
config tp_manage 'factory_mode'
        option enabled '0'
config tp_manage 'bind_info'
        option owner ''
config on_off 'roi_enable'
        option main_enabled 'off'
        option minor_enabled 'off'
config target_track_info 'target_track_info'
        option enabled 'off'
config info 'tapo_care_state'
config app_component_list 'service_list'
config info 'tapo_care_info'
        option enabled '0'
config capability 'capability'
config smart_detection 'capability'
config module-spec 'module_spec'
config wait-time 'wait_time'
config cover_info 'cover'
        option enabled 'off'
config capability 'main'
config capability 'minor'
config capability 'mjpeg'
config capability 'device_speaker'
config capability 'device_microphone'
config capability 'app_speaker'
        list sampling_rate '8'
        list sampling_rate '16'
        option channels '2'
        list decode_type 'G711'
        list decode_type 'AAC'
config capability 'app_microphone'
        list sampling_rate '8'
        list sampling_rate '16'
        option channels '2'
        list encode_type 'G711'
        list encode_type 'AAC'
config server 'main'
        option enabled 'off'
        option address '224.0.1.0'
        option port '10000'
        option random 'on'
config server 'minor'
        option enabled 'off'
        option address '224.0.1.0'
        option port '10002'
        option random 'on'
config server 'third'
        option enabled 'off'
        option address '224.0.1.0'
        option port '10004'
        option random 'on'
config relay_server 'server'
        option host 'aps1-relay-dcipc.i.tplinknbu.com'
        option port '443'
        option use_https '1'
config scale_capability 'scale_0'
config scale_capability 'scale_1'
config scale_capability 'scale_2'
config scale_capability 'scale_3'
config scale_capability 'scale_4'
config scale_capability 'scale_5'
config scale_capability 'scale_6'
config scale_capability 'scale_7'
config scale_capability 'scale_8'
config stream 'main'
        option stream_type 'general'
        option resolution '1280*720'
        option bitrate_type 'vbr'
        option frame_rate '65551'
        option quality '3'
        option bitrate '1024'
        option encode_type 'H264'
config stream 'minor'
        option resolution '640*360'
        option bitrate_type 'vbr'
        option frame_rate '65551'
        option quality '3'
        option bitrate '256'
        option encode_type 'H264'
config stream 'mjpeg'
        option resolution '640*360'
        option bitrate_type 'vbr'
        option frame_rate '65541'
        option quality '3'
        option bitrate '2560'
        option encode_type 'MJPEG'
config info 'main_conf'
config info 'minor_conf'
config info 'mjpeg_conf'
config on_off 'detection'
        option enabled 'off'
config notify_list 'notify_list'
        option record_enabled 'on'
        option msg_push_enabled 'on'
        option light_alarm_enabled 'off'
        option sound_alarm_enabled 'off'
config plan 'arming_schedule'
        option monday '["0000-2400"]'
        option tuesday '["0000-2400"]'
        option wednesday '["0000-2400"]'
        option thursday '["0000-2400"]'
        option friday '["0000-2400"]'
        option saturday '["0000-2400"]'
        option sunday '["0000-2400"]'
config on_off 'detection'
        option enabled 'off'
config notify_list 'notify_list'
        option record_enabled 'on'
        option msg_push_enabled 'on'
        option light_alarm_enabled 'off'
        option sound_alarm_enabled 'off'
config plan 'arming_schedule'
        option monday '["0000-2400"]'
        option tuesday '["0000-2400"]'
        option wednesday '["0000-2400"]'
        option thursday '["0000-2400"]'
        option friday '["0000-2400"]'
        option saturday '["0000-2400"]'
        option sunday '["0000-2400"]'
config dhcpc 'udhcpc'
        option enable '1'
        option retry '0'
        option ip_requested '0'
config plan 'chn1_msg_alarm_plan'
        option enabled 'off'
        option alarm_plan_1 '0000-0000,127'
config plan 'arming_schedule_sound'
        option monday '["0000-2400"]'
        option tuesday '["0000-2400"]'
        option wednesday '["0000-2400"]'
        option thursday '["0000-2400"]'
        option friday '["0000-2400"]'
        option saturday '["0000-2400"]'
        option sunday '["0000-2400"]'
config plan 'arming_schedule_light'
        option monday '["0000-2400"]'
        option tuesday '["0000-2400"]'
        option wednesday '["0000-2400"]'
        option thursday '["0000-2400"]'
        option friday '["0000-2400"]'
        option saturday '["0000-2400"]'
        option sunday '["0000-2400"]'
config on_off 'video_message'
config wtd 'config'
        option enabled 'on'
config info 'info'
        option device_name 'C200'
        option device_info 'C200 IPC'
        option device_model 'C200'
        option hw_version '3.0'
        option fw_description 'C200 3.0'
        option product_id '00000000'
        option sw_version '1.3.0 Build 220909 Rel.43466n'
config plan 'chn1_msg_push_plan'
        option enabled 'off'
        option push_plan_1 '0900-1700,127'
config info 'info'
        option language 'other'
config ptz 'capability'
config ptz 'basic_config'
        option speed_pan_default '0.350000'
        option speed_tilt_default '0.350000'
        option timeout_default '180000'
        option proportional_pan_enabled '1'
        option reverse_mode 'off'
        option eflip_mode 'off'
config ptz 'scan_config'
        option speed '0.7000'
config ptz 'park_config'
        option enabled '0'
        option park_time '5'
        option action_mode 'auto_scan'
        option action_id '1'
config ptz 'limit_config'
        option enabled '0'
        option key_position_pan_enabled '0'
        option key_position_pan_left '-1'
        option key_position_pan_right '1'
        option key_position_tilt_enabled '0'
        option key_position_tilt_down '-1'
        option key_position_tilt_up '1'
        option scan_position_pan_enabled '0'
        option scan_position_pan_left '-1'
        option scan_position_pan_right '1'
        option scan_position_tilt_enabled '0'
        option scan_position_tilt_down '-1'
        option scan_position_tilt_up '1'
config ptz 'poweroff_save_config'
        option enabled '1'
        option save_time '10'
config ptz 'manual_control_config'
        option speed_mode 'self_adaptive'
        option speed_level 'normal'
config ptz 'poweroff_save'
config home 'home'
        option position_pan '-1.000'
        option position_tilt '1.000'
config storage 'harddisk'
        option loop 'on'
config partition 'video'
        option ratio '100'
        option data_file_size '256M'
config partition 'picture'
        option ratio '0'
config partition 'crossline'
config partition 'msg_push'
config partition 'passenger_flow'
config manage 'harddisk_1'
config capability 'traditional_enhance'
config capability 'face_enhance'
config on_off 'login_err'
        option enabled 'on'
        option max_num_err '10'
config notif_list 'login_err_notif_list'
        option app_enabled 'off'
        option client_enabled 'off'
config on_off 'sd_missing'
config lens_mask_info 'lens_mask_info'
        option enabled 'off'
config on_off 'login_error'
        option enabled 'on'
        option max_num_err '10'
        option msg_push_enabled 'on'
        option light_alarm_enabled 'off'
config on_off 'hd_lack'
        option enabled 'on'
        option msg_push_enabled 'on'
config on_off 'hd_error'
        option enabled 'on'
        option msg_push_enabled 'on'
config audio_config 'speaker'
        option volume '100'
config audio_config 'microphone'
        option sampling_rate '8'
        option channels '1'
        option encode_type 'G711alaw'
        option volume '100'
        option mute 'off'
        option noise_cancelling 'on'
config audio_config 'record_audio'
        option enabled 'on'
config advance 'plan_advance'
        option record_time '120'
        option delay_record '60'
config on_off 'common'
        option enabled 'on'
        option time '03:00'
        option random_range '120'
config info 'chn1_msg_alarm_info'
        option enabled 'off'
        option alarm_type '0'
        option light_type '1'
        list alarm_mode 'sound'
        list alarm_mode 'light'
        option sound_alarm_enabled 'off'
        option light_alarm_enabled 'off'
config led 'config'
        option enabled 'on'
config led 'model'
config ffs 'ffs_info'
config uhttpd 'main'
        option listen_https '443'
config cert 'px5g'
config status 'status'
        option enabled 'on'
config on_off 'bcd'
        option enabled 'off'
        option sensitivity 'medium'
        option digital_sensitivity '50'
config notif_list 'bcd_notif_list'
        option app_enabled 'off'
        option client_enabled 'off'
        option record_enabled 'on'
        option msg_push_enabled 'on'
        option light_alarm_enabled 'off'
        option sound_alarm_enabled 'off'
config app_component_list 'app_component_list'
config control 'chn1_record'
        option mode 'auto'
        option stream_type 'main'
config control 'chn2_record'
config control 'chn3_record'
config control 'chn4_record'
config control 'chn5_record'
config control 'chn6_record'
config control 'chn7_record'
config control 'chn8_record'
config basic 'basic'
        option enabled 'off'
config cloud 'cloud'
        option cloudUrl 'n-da.tplinkcloud.com'
        option accessKey ''
        option accessSecret ''
config strategy 'strategy'
        option strategyID ''
        option collect_interval '15'
        option post_interval '180'
config profile 'profile_1'
config profile 'profile_2'
config vsconf 'vsconf'
config asconf 'asconf'
config discovery_mode 'dis_mode'
        option mode '0'
config scopes 'custom_scopes'
config true_false 'ffs_bind'
        option ffs '0'
        option ffs_binding '0'
config capability 'capability'
        option sound_alarm_capability '000000000000100000000000001111'
        option light_alarm_capability '000000000010100000000000001101'
        option record_capability '000000000000100000000000001101'
        option capture_capability '000000000000000000000000000000'
        option ftp_capability '000000000000000000000000000000'
        option msg_push_capability '000000001010100000000000001111'
        option email_capability '000000000000000000000000000000'
        option alarm_out_capability '000000000000000000000000000000'
config config 'preset_config'
        option image_freeze_enabled '0'
        option speed '1.0'
config dhcpd 'udhcpd'
        option enable '1'
        option pool_start '192.168.191.100'
        option pool_end '192.168.191.199'
        option lease_time '7200'
        option gateway '192.168.191.1'
        option pri_dns '192.168.191.1'
        option snd_dns '0.0.0.0'
        option auto '0'
config plan 'chn1_channel'
        option enabled 'off'
        option monday '["0000-2400:2"]'
        option tuesday '["0000-2400:2"]'
        option wednesday '["0000-2400:2"]'
        option thursday '["0000-2400:2"]'
        option friday '["0000-2400:2"]'
        option saturday '["0000-2400:2"]'
        option sunday '["0000-2400:2"]'
config interface 'wan'
        option wan_type 'static'
        option proto 'static'
        option auto '0'
        option wan_rate 'auto'
        option ifname 'br-wan'
config proto 'dhcp'
        option ifname 'br-wan'
        option mtu '1480'
        option dns_mode 'dynamic'
        option pri_dns ''
        option snd_dns ''
        option hostname 'IPC'
        option enable_broadcast '1'
config proto 'static'
        option ifname 'br-wan'
        option ipaddr '192.168.0.10'
        option netmask '255.255.255.0'
        option gateway '192.168.0.1'
        option pri_dns '114.114.114.114'
        option snd_dns '8.8.8.8'
        option mtu '1480'
config proto 'pppoe'
        option ifname 'br-wan'
        option proto 'pppoe'
        option auto '0'
        option wan_type 'pppoe'
        option connect '1'
        option parent 'wan'
        option username ''
        option password ''
        option dial_mode 'auto'
        option conn_mode 'auto'
        option demand_idle '600'
        option manual_idle ''
        option mtu '1480'
        option access ''
        option server ''
        option ip_mode 'dynamic'
        option specific_ip ''
        option dns_mode 'dynamic'
        option pri_dns ''
        option snd_dns ''
config wlan_runtime 'ap0'
        option status 'off'
        list sta_list ''
config config 'cloud'
        option server_type 'prd'
config config 'dev'
config config 'uat'
config config 'uat2'
config config 'uat3'
config config 'staging'
config config 'prd'
config switch_type 'switch'
        option switch_mode 'common'
        option schedule_start_time '21600'
        option schedule_end_time '64800'
        option flip_type 'off'
        option rotate_type 'off'
        option ldc 'off'
config para 'common'
        option luma '50'
        option contrast '50'
        option chroma '50'
        option saturation '50'
        option sharpness '50'
        option exp_type 'auto'
        option shutter '1/25'
        option focus_type 'semi_auto'
        option focus_limited '600'
        option exp_gain '0'
        option inf_type 'auto'
        option inf_start_time '64800'
        option inf_end_time '21600'
        option inf_sensitivity '1'
        option wide_dynamic 'off'
        option light_freq_mode 'auto'
        option wd_gain '50'
        option wb_type 'auto'
        option wb_R_gain '50'
        option wb_G_gain '50'
        option wb_B_gain '50'
        option lock_red_gain '0'
        option lock_gr_gain '0'
        option lock_gb_gain '0'
        option lock_blue_gain '0'
        option lock_red_colton '0'
        option lock_green_colton '0'
        option lock_blue_colton '0'
        option lock_source 'local'
        option area_compensation 'default'
        option smartir 'off'
        option smartir_level '100'
        option high_light_compensation 'off'
        option dehaze 'off'
config para 'shedday'
        option luma '50'
        option contrast '50'
        option chroma '50'
        option saturation '50'
        option sharpness '50'
        option exp_type 'auto'
        option shutter '1/25'
        option focus_type 'semi_auto'
        option focus_limited '600'
        option exp_gain '0'
        option inf_type 'off'
        option inf_sensitivity '1'
        option inf_delay '30'
        option wide_dynamic 'off'
        option wd_gain '50'
        option wb_type 'auto'
        option wb_R_gain '50'
        option wb_G_gain '50'
        option wb_B_gain '50'
        option lock_red_gain '0'
        option lock_gr_gain '0'
        option lock_gb_gain '0'
        option lock_blue_gain '0'
        option lock_red_colton '0'
        option lock_green_colton '0'
        option lock_blue_colton '0'
        option lock_source 'local'
        option area_compensation 'default'
        option smartir 'off'
        option smartir_level '100'
        option high_light_compensation 'off'
        option dehaze 'off'
config para 'shednight'
        option luma '50'
        option contrast '50'
        option chroma '50'
        option saturation '50'
        option sharpness '50'
        option exp_type 'auto'
        option shutter '1/25'
        option focus_type 'semi_auto'
        option focus_limited '600'
        option exp_gain '0'
        option inf_type 'on'
        option inf_sensitivity '1'
        option inf_delay '30'
        option wide_dynamic 'off'
        option wd_gain '50'
        option wb_type 'auto'
        option wb_R_gain '50'
        option wb_G_gain '50'
        option wb_B_gain '50'
        option lock_red_gain '0'
        option lock_gr_gain '0'
        option lock_gb_gain '0'
        option lock_blue_gain '0'
        option lock_red_colton '0'
        option lock_green_colton '0'
        option lock_blue_colton '0'
        option lock_source 'local'
        option area_compensation 'default'
        option smartir 'off'
        option smartir_level '100'
        option high_light_compensation 'off'
        option dehaze 'off'
config para 'autoday'
        option luma '50'
        option contrast '50'
        option chroma '50'
        option saturation '50'
        option sharpness '50'
        option exp_type 'auto'
        option shutter '1/25'
        option focus_type 'semi_auto'
        option focus_limited '600'
        option exp_gain '0'
        option inf_type 'auto'
        option inf_sensitivity '1'
        option inf_delay '5'
        option wide_dynamic 'off'
        option light_freq_mode 'auto'
        option wd_gain '50'
        option wb_type 'auto'
        option wb_R_gain '50'
        option wb_G_gain '50'
        option wb_B_gain '50'
        option lock_red_gain '0'
        option lock_gr_gain '0'
        option lock_gb_gain '0'
        option lock_blue_gain '0'
        option lock_red_colton '0'
        option lock_green_colton '0'
        option lock_blue_colton '0'
        option lock_source 'local'
        option area_compensation 'default'
        option smartir 'off'
        option smartir_level '100'
        option high_light_compensation 'off'
        option dehaze 'off'
config para 'autonight'
        option luma '50'
        option contrast '50'
        option chroma '50'
        option saturation '50'
        option sharpness '50'
        option exp_type 'auto'
        option shutter '1/25'
        option focus_type 'semi_auto'
        option focus_limited '600'
        option exp_gain '0'
        option inf_type 'auto'
        option inf_sensitivity '1'
        option inf_delay '5'
        option wide_dynamic 'off'
        option light_freq_mode 'auto'
        option wd_gain '50'
        option wb_type 'auto'
        option wb_R_gain '50'
        option wb_G_gain '50'
        option wb_B_gain '50'
        option lock_red_gain '0'
        option lock_gr_gain '0'
        option lock_gb_gain '0'
        option lock_blue_gain '0'
        option lock_red_colton '0'
        option lock_green_colton '0'
        option lock_blue_colton '0'
        option lock_source 'local'
        option area_compensation 'default'
        option smartir 'off'
        option smartir_level '100'
        option high_light_compensation 'off'
        option dehaze 'off'
config capability 'font_info'
config capability 'label_info'
config capability 'res_info'
config on_off 'tamper_det'
        option enabled 'off'
        option sensitivity 'medium'
        option digital_sensitivity '50'
config region_info 'region'
config notif_list 'tamper_notif_list'
        option app_enabled 'off'
        option client_enabled 'off'
        option msg_push_enabled 'on'
        option sound_alarm_enabled 'off'
config interface 'loopback'
config interface 'wan'
        option ifname 'br-wan'
        option type 'bridge'
        option wan_type 'dhcp'
        option speed_duplex 'auto'
        option proto 'dhcp'
        option mtu '1480'
        option auto '1'
        option netmask '255.255.255.0'
        option ipaddr '192.168.0.10'
        option gateway '192.168.0.1'
        option dns '0.0.0.0'
config configuration 'tour_config'
        option recurring_times_default '10'
        option recurring_duration_default '36000'
        option stay_time_default '15000'
config wlan 'basic'
        option factory_flag 'on'
config wlan 'ap0'
        option on_boot 'on'
        option ssid ''
        option broadcast_ssid 'on'
        option region 'CN'
        option band '2g'
        option channel '0'
        option hwmode 'bgn'
        option channel_width 'ht20'
        option security 'none'
        option encryption 'ccmp'
        option key ''
        option wps 'off'
        option auto_disable_time '0'
        option isolation 'off'
        option acl 'none'
        list acl_mac ''
config wlan 'sta0'
        option on_boot 'on'
        option connect_onboot 'off'
        option network_id '0'
config wlan 'default_ap'
config on_off 'chn1_msg_push_info'
        option notification_enabled 'on'
        option rich_notification_enabled 'off'
config on_off 'msg_push_event'
        option motion_detection 'on'
        option people_detection 'on'
        option sound_detection 'on'
config on_off 'motion_det'
        option enabled 'on'
        option digital_sensitivity '50'
config notif_list 'motion_notif_list'
        option app_enabled 'off'
        option client_enabled 'off'
        option record_enabled 'on'
        option msg_push_enabled 'off'
config region_info 'region_info_1'
        option height '10000'
        option width '10000'
        option x_coor '0'
        option y_coor '0'
config root 'root'
        option username 'admin'
        option passwd 'zMiVw8Kw0oxKXL0'
        option ciphertext 'dl5GoIRk+FMC/JgP5yLjA+r8PynYYSai8DSmdv1Xw7iALNEKxkE5UusQw6BMC4+FlcWv0bCPuw8DSlSk/vkmcTZ/BF/ZY1ENNJqo+uJtiGi2f1zJFjleYhPlDx4YXa3qp7oSNF8EU1BU4mOY9nEtUakFl4oVPsvlLGM3qE/zI2k='
        option sharepwd ''
        option comment ''
config third_account 'third_account'
        option username '---'
        option passwd '---'
        option ciphertext 'dl5GoIRk+FMC/JgP5yLjA+r8PynYYSai8DSmdv1Xw7iALNEKxkE5UusQw6BMC4+FlcWv0bCPuw8DSlSk/vkmcTZ/BF/ZY1ENNJqo+uJtiGi2f1zJFjleYhPlDx4YXa3qp7oSNF8EU1BU4mOY9nEtUakFl4oVPsvlLGM3qE/zI2k='
        option comment ''
config authentication 'authentication'
        option basic_enabled '0'
config server 'vhttpd'
        option port '8800'
config server 'rtsp'
        option port '554'
config URL 'URL'
config on_off 'media_encrypt'
        option enabled 'off'

The same amount of information can be obtained from the file sys_conf_data:

sys_conf_data
timing_reboot
people_detection
system
luci
auto_reboot
ptz_plan
cloud_config
motion_detection
tp_manage
target_track
tapo_care
smart_msg_push_capability
pattern
smart_detection
function
cover
video_capability
audio_capability
multicast
relayd_config
playback
video
linecrossing_detection
intrusion_detection
dhcpc
msg_alarm_plan
video_message
device_info
msg_push_plan
system_state_audio
harddisk_manage
ai_enhance_capability
abnormal_events
lens_mask
unusual_detection
audio_config
plan_advance
auto_upgrade
msg_alarm
ffs_dss_pubkey
uhttpd
smart_data
sound_detection
app_component
record_control
telemetry
onvif
linkage_capability
preset
dhcpd
record_plan
protocol
wlan_runtime
cloud_iot
image
OSD_capability
tamper_detection
network
tour
wlan
msg_push
motion_detection_cloud
ucitrack
user_management
config on_off 'reboot'
config on_off 'detection'
config notify_list 'notify_list'
config plan 'arming_schedule'
config region_info 'region_info_1'
config system 'sys'
        option hostname 'C200'
config setting 'basic'
config timing 'ntp'
        list def_server 'time.nist.gov'
        list def_server '128.138.140.44'
        list def_server '192.36.144.22'
        list def_server 'time-a.nist.gov'
        list def_server 'time-b.nist.gov'
        list def_server 'time.windows.com'
        list def_server 'time-nw.nist.gov'
        list def_server 'au.pool.ntp.org'
        list def_server 'nz.pool.ntp.org'
config debug 'debug'
config dst 'dst'
config core 'main'
        option lang 'auto'
        option mediaurlbase '/web-static'
        option resourcebase '/luci-static/resources'
config extern 'flash_keep'
        option uci '/etc/config/'
        option dropbear '/etc/dropbear/'
        option openvpn '/etc/openvpn/'
        option passwd '/etc/passwd'
        option opkg '/etc/opkg.conf'
        option firewall '/etc/firewall/firewall.user'
        option uploads '/lib/uci/upload/'
config internal 'languages'
config internal 'sauth'
        option sessionpath '/tmp/luci-sessions'
        option sessiontime '3600'
config internal 'ccache'
        option enable '1'
config internal 'themes'
        option TORCHLIGHT '/luci-static/torchlight'
config font_info 'font'
config date_info 'date'
config date_info 'week'
config date_info 'logo'
config label_info 'label_info_1'
config label_info 'label_info_2'
config label_info 'label_info_3'
config zoom 'zoom'
config azimuth 'azimuth'
config preset 'preset'
config on_off 'reboot'
config config 'plan_config'
config router_post 'bind'
config cloud_reply 'device_status'
config cloud_reply 'upgrade_info'
config data_collect 'onboarding'
config data_collect 'extra_bind'
config data_collect 'upgrade_status'
config on_off 'motion_det'
config notif_list 'motion_notif_list'
config region_info 'region_info_1'
config tp_manage 'factory_mode'
config tp_manage 'bind_info'
config on_off 'roi_enable'
config target_track_info 'target_track_info'
config info 'tapo_care_state'
        option version '1.0.0'
config app_component_list 'service_list'
        list component '{"name": "msgPush", "version": 3}'
config info 'tapo_care_info'
config capability 'capability'
        list support 'md'
        list support 'od'
        list support 'id'
        list support 'cd'
        list support 'login_error'
        list support 'hd_lack'
        list support 'hd_error'
config smart_detection 'capability'
        option linecrossing_detection '1'
        option intrusion_detection '1'
        option people_detection '1'
        option smart_data '1'
config module-spec 'module_spec'
config wait-time 'wait_time'
config cover_info 'cover'
config capability 'main'
        list encode_types 'H264'
        list frame_rates '65537'
        list frame_rates '65546'
        list frame_rates '65551'
        list bitrates '256'
        list bitrates '512'
        list bitrates '1024'
        list bitrates '2048'
        list bitrate_types 'cbr'
        list bitrate_types 'vbr'
        list resolutions '1920*1080'
        list resolutions '1280*720'
        list resolutions '640*360'
        list qualitys '1'
        list qualitys '3'
        list qualitys '5'
config capability 'minor'
        list encode_types 'H264'
        list frame_rates '65537'
        list frame_rates '65546'
        list frame_rates '65551'
        list bitrates '64'
        list bitrates '128'
        list bitrates '256'
        list bitrates '512'
        list bitrate_types 'cbr'
        list bitrate_types 'vbr'
        list resolutions '640*360'
        list qualitys '1'
        list qualitys '3'
        list qualitys '5'
config capability 'mjpeg'
        list encode_types 'MJPEG'
        list frame_rates '65537'
        list frame_rates '65546'
        list frame_rates '65551'
        list bitrates '2560'
        list bitrate_types 'vbr'
        list resolutions '640*360'
        list qualitys '1'
        list qualitys '3'
        list qualitys '5'
config capability 'device_speaker'
        list sampling_rate '8'
        option channels '1'
        list decode_type 'G711'
        option volume '1'
        option mute '0'
config capability 'device_microphone'
        list sampling_rate '8'
        option channels '1'
        list encode_type 'G711alaw'
        option volume '1'
        option mute '1'
        option aec '1'
        option noise_cancelling '1'
        option echo_cancelling '0'
        option half_duplex '1'
config capability 'app_speaker'
config capability 'app_microphone'
config server 'main'
config server 'minor'
config server 'third'
config relay_server 'server'
        option is_tums_talk '0'
config scale_capability 'scale_0'
        option value '1/16'
        option change_pts '0'
config scale_capability 'scale_1'
        option value '1/8'
        option change_pts '0'
config scale_capability 'scale_2'
        option value '1/4'
        option change_pts '0'
config scale_capability 'scale_3'
        option value '1/2'
        option change_pts '0'
config scale_capability 'scale_4'
        option value '1/1'
        option change_pts '0'
config scale_capability 'scale_5'
        option value '2/1'
        option change_pts '1'
config scale_capability 'scale_6'
        option value '4/1'
        option change_pts '1'
config scale_capability 'scale_7'
        option value '8/1'
        option change_pts '1'
config scale_capability 'scale_8'
        option value '16/1'
        option change_pts '1'
config stream 'main'
        option name 'VideoEncoder_1'
        option gop_factor '2'
config stream 'minor'
        option name 'VideoEncoder_2'
        option gop_factor '2'
config stream 'mjpeg'
        option name 'VideoEncoder_3'
        option gop_factor '2'
config info 'main_conf'
        option res_num '3'
        option res_1_w '1920'
        option res_1_h '1080'
        option res_2_w '1280'
        option res_2_h '720'
        option res_3_w '640'
        option res_3_h '360'
        option min_br '256'
        option max_br '2048'
        option min_fr '1'
        option max_fr '15'
config info 'minor_conf'
        option res_num '1'
        option res_1_w '640'
        option res_1_h '360'
        option min_br '64'
        option max_br '512'
        option min_fr '1'
        option max_fr '15'
config info 'mjpeg_conf'
        option res_num '1'
        option res_1_w '640'
        option res_1_h '368'
        option min_br '256'
        option max_br '2560'
        option min_fr '1'
        option max_fr '15'
config on_off 'detection'
config notify_list 'notify_list'
config plan 'arming_schedule'
config on_off 'detection'
config notify_list 'notify_list'
config plan 'arming_schedule'
config dhcpc 'udhcpc'
config plan 'chn1_msg_alarm_plan'
config plan 'arming_schedule_sound'
config plan 'arming_schedule_light'
config on_off 'video_message'
        option enabled 'off'
        option duration '15'
config wtd 'config'
        option init_delay '0'
config info 'info'
        option sys_software_revision '0x500a0103'
        option sys_software_revision_minor '0x0000'
        option isp_version '2'
        option device_type 'SMART.IPCAMERA'
        option features '3'
        option domain_name 'tplogin.cn'
        option language 'EN'
        option enable_dns '1'
        option manufacturer_name 'TP-LINK'
        option friendly_name 'IPC'
        option model_description 'IPC'
        option manufacturer_url 'http://www.tp-link.com'
        option vendor_id '0x00000001'
        option zone_code '0x0'
        option roi_reg_num '1'
        option cover_reg_num '4'
        option md_reg_num '32'
        option td_reg_num '1'
        option id_reg_num '4'
        option cd_reg_num '4'
        option ac_reg_num '1'
        option plugin_obtain_way 'web'
        option product_type 'ipc'
        option fw_shared_prefix 'Tapo_C200v3'
        option ext_fw_upgrade '1'
config plan 'chn1_msg_push_plan'
config info 'info'
config ptz 'capability'
        list position_pan_range '-1.000000'
        list position_pan_range '1.000000'
        list position_tilt_range '-1.000000'
        list position_tilt_range '1.000000'
        option speed_pan_max '1.00000'
        option speed_tilt_max '1.000000'
        option absolute_move_supported '1'
        option relative_move_supported '1'
        option continuous_move_supported '1'
        option preset_supported '1'
        option preset_number_max '8'
        option tour_supported '0'
        list eflip_mode 'off'
        list eflip_mode 'on'
        list reverse_mode 'off'
        list reverse_mode 'on'
        list reverse_mode 'auto'
        option scan_supported '0'
        option park_supported '0'
        option plan_supported '0'
        option poweroff_save_supported '1'
        list poweroff_save_time_range '10'
        list poweroff_save_time_range '600'
        option home_position_mode 'none'
        option pattern_supported '0'
        option limit_supported '0'
        list manual_control_mode 'compatible'
        list manual_control_mode 'pedestrian'
        list manual_control_mode 'motor_vehicle'
        list manual_control_mode 'non_motor_vehicle'
        list manual_control_mode 'self_adaptive'
        list manual_control_level 'low'
        list manual_control_level 'normal'
        list manual_control_level 'high'
        option calibrate_supported '1'
config ptz 'basic_config'
        option elevation_min '0'
        option elevation_max '90'
config ptz 'scan_config'
config ptz 'park_config'
config ptz 'limit_config'
config ptz 'poweroff_save_config'
config ptz 'manual_control_config'
config ptz 'poweroff_save'
config home 'home'
config storage 'harddisk'
config partition 'video'
        option min_event_size '1M'
        option event_overlay_factor '3'
        option event_cache_wr_intv '120'
        option event_min_duration '1'
config partition 'picture'
        option data_file_size '1M'
        option min_event_size '80K'
        option event_overlay_factor '1'
        option event_cache_wr_intv '120'
        option event_min_duration '1'
config partition 'crossline'
        option ratio '0'
        option data_file_size '256M'
        option min_event_size '512K'
        option event_overlay_factor '1'
        option event_cache_wr_intv '900'
        option event_min_duration '900'
config partition 'msg_push'
        option ratio '0'
        option data_file_size '1M'
        option min_event_size '1M'
        option event_overlay_factor '1'
        option event_cache_wr_intv '120'
        option event_min_duration '1'
config partition 'passenger_flow'
        option ratio '0'
        option data_file_size '2664960'
        option min_event_size '8B'
        option event_overlay_factor '1'
        option event_cache_wr_intv '900'
        option event_min_duration '900'
config manage 'harddisk_1'
        option type 'sdcard'
        option path '/dev/mmcblk0'
        option mnt '/tmp/mnt/harddisk_1'
config capability 'traditional_enhance'
        option people_enhance_ver '7'
config capability 'face_enhance'
config on_off 'login_err'
config notif_list 'login_err_notif_list'
config on_off 'sd_missing'
        option msg_push_enabled 'on'
config lens_mask_info 'lens_mask_info'
config on_off 'login_error'
config on_off 'hd_lack'
config on_off 'hd_error'
config audio_config 'speaker'
config audio_config 'microphone'
config audio_config 'record_audio'
config advance 'plan_advance'
        option pre_record '3'
config on_off 'common'
config info 'chn1_msg_alarm_info'
config led 'config'
config led 'model'
        option startup 'on'
config ffs 'ffs_info'
        option dss_pubkey '-----BEGIN PUBLIC KEY-----nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE++2MMSe9kWF6mJPkgsGcrqTCk8gbnvTccKPGZDL5pZcmfW+2EzRjfXhx6clwg3Wl4ClFe8+37fLNgxPYodqGQgA==n-----END PUBLIC KEY-----n'
config uhttpd 'main'
        option home '/www'
        option rfc1918_filter '1'
        option max_requests '8'
        option cert '/tmp/uhttpd.crt'
        option key '/tmp/uhttpd.key'
        option cgi_prefix '/cgi-bin'
        option lua_prefix '/luci'
        option lua_handler '/usr/lib/lua/luci/sgi/uhttpd.lua'
        option script_timeout '180'
        option network_timeout '180'
        option tcp_keepalive '0'
config cert 'px5g'
        option days '3600'
        option bits '1024'
        option country 'CN'
        option state 'China'
        option location 'China'
        option commonname 'TP-Link'
config status 'status'
config on_off 'bcd'
config notif_list 'bcd_notif_list'
config app_component_list 'app_component_list'
        list component '{"name": "sdCard", "version": 1}'
        list component '{"name": "timezone", "version": 1}'
        list component '{"name": "system", "version": 3}'
        list component '{"name": "led", "version": 1}'
        list component '{"name": "playback", "version": 3}'
        list component '{"name": "detection", "version": 1}'
        list component '{"name": "alert", "version": 1}'
        list component '{"name": "firmware", "version": 2}'
        list component '{"name": "account", "version": 1}'
        list component '{"name": "quickSetup", "version": 1}'
        list component '{"name": "ptz", "version": 1}'
        list component '{"name": "video", "version": 2}'
        list component '{"name": "lensMask", "version": 2}'
        list component '{"name": "lightFrequency", "version": 1}'
        list component '{"name": "dayNightMode", "version": 1}'
        list component '{"name": "osd", "version": 2}'
        list component '{"name": "record", "version": 1}'
        list component '{"name": "videoRotation", "version": 1}'
        list component '{"name": "audio", "version": 2}'
        list component '{"name": "diagnose", "version": 1}'
        list component '{"name": "msgPush", "version": 3}'
        list component '{"name": "deviceShare", "version": 1}'
        list component '{"name": "tapoCare", "version": 1}'
        list component '{"name": "blockZone", "version": 1}'
        list component '{"name": "personDetection", "version": 1}'
        list component '{"name": "targetTrack", "version": 1}'
        list component '{"name": "babyCryDetection", "version": 1}'
        list component '{"name": "needSubscriptionServiceList", "version": 1}'
        list component '{"name": "iotCloud", "version": 1}'
config control 'chn1_record'
config control 'chn2_record'
        option mode 'auto'
        option stream_type 'main'
config control 'chn3_record'
        option mode 'auto'
        option stream_type 'main'
config control 'chn4_record'
        option mode 'auto'
        option stream_type 'main'
config control 'chn5_record'
        option mode 'auto'
        option stream_type 'main'
config control 'chn6_record'
        option mode 'auto'
        option stream_type 'main'
config control 'chn7_record'
        option mode 'auto'
        option stream_type 'main'
config control 'chn8_record'
        option mode 'auto'
        option stream_type 'main'
config basic 'basic'
config cloud 'cloud'
config strategy 'strategy'
config profile 'profile_1'
        option name 'mainStream'
        option token 'profile_1'
        option fixed '1'
        option vsconf 'vsconf'
        option veconf 'main'
        option asconf 'asconf'
        option aeconf 'microphone'
config profile 'profile_2'
        option name 'minorStream'
        option token 'profile_2'
        option fixed '1'
        option vsconf 'vsconf'
        option veconf 'minor'
        option asconf 'asconf'
        option aeconf 'microphone'
config vsconf 'vsconf'
        option name 'VideoSourceConfig'
        option token 'vsconf'
        option sToken 'raw_vs1'
        option uCount '2'
        option bX '0'
        option bY '0'
        option bW '1920'
        option bH '1080'
config asconf 'asconf'
        option name 'AudioSourceConfig'
        option token 'asconf'
        option sToken 'raw_as1'
        option uCount '2'
config discovery_mode 'dis_mode'
config scopes 'custom_scopes'
config true_false 'ffs_bind'
config capability 'capability'
config config 'preset_config'
config dhcpd 'udhcpd'
        option interface 'wlan1'
        option lease_file '/tmp/dhcp.leases'
        option pid_file '/var/run/udhcpd.pid'
        option subnet '255.255.255.0'
config plan 'chn1_channel'
config interface 'wan'
        option type 'bridge'
config proto 'dhcp'
        option proto 'dhcp'
        option auto '1'
        option wan_type 'dhcp'
config proto 'static'
        option type 'bridge'
        option proto 'static'
        option auto '1'
        option wan_type 'static'
        option fac_ipaddr '192.168.0.10'
config proto 'pppoe'
        option keepalive '3,10'
config wlan_runtime 'ap0'
config config 'cloud'
config config 'dev'
        option cloud_gateway_domain 'device-cloudgateway-alpha.iot.i.tplinknbu.com'
        option cloud_gateway_port '443'
        option cloud_security_domain 'security-alpha.iot.i.tplinknbu.com'
        option cloud_security_port '443'
config config 'uat'
        option cloud_gateway_domain 'device-cloudgateway-beta.iot.i.tplinknbu.com'
        option cloud_gateway_port '443'
        option cloud_security_domain 'security-beta.iot.i.tplinknbu.com'
        option cloud_security_port '443'
config config 'uat2'
        option cloud_gateway_domain 'device-cloudgateway-beta2.iot.i.tplinknbu.com'
        option cloud_gateway_port '443'
        option cloud_security_domain 'security-beta2.iot.i.tplinknbu.com'
        option cloud_security_port '443'
config config 'uat3'
        option cloud_gateway_domain 'device-cloudgateway-beta3.iot.i.tplinknbu.com'
        option cloud_gateway_port '443'
        option cloud_security_domain 'security-beta3.iot.i.tplinknbu.com'
        option cloud_security_port '443'
config config 'staging'
        option cloud_gateway_domain 'device-cloudgateway-staging.iot.i.tplinknbu.com'
        option cloud_gateway_port '443'
        option cloud_security_domain 'security-staging.iot.i.tplinknbu.com'
        option cloud_security_port '443'
config config 'prd'
        option cloud_gateway_domain 'device-cloudgateway.iot.i.tplinknbu.com'
        option cloud_gateway_port '443'
        option cloud_security_domain 'security.iot.i.tplinknbu.com'
        option cloud_security_port '443'
config switch_type 'switch'
        option night_vision_mode 'inf_night_vision'
        option wtl_intensity_level '5'
config para 'common'
        option inf_delay '10'
config para 'shedday'
        option light_freq_mode 'auto'
config para 'shednight'
        option light_freq_mode 'auto'
config para 'autoday'
config para 'autonight'
config capability 'font_info'
        list display 'ntnb'
        list display 'tnb'
        list display 'ntb'
        list display 'tb'
        list size 'auto'
        list color_type 'auto'
        list color_type 'user_defined'
        list color 'black'
        list color 'white'
        option max_size '64*64'
config capability 'label_info'
        option num '3'
config capability 'res_info'
        option max_res_w '2304'
config on_off 'tamper_det'
config region_info 'region'
        option height '10000'
        option width '10000'
        option x_coor '0'
        option y_coor '0'
config notif_list 'tamper_notif_list'
config interface 'loopback'
        option ifname 'lo'
        option proto 'static'
        option ipaddr '127.0.0.1'
        option netmask '255.0.0.0'
config interface 'wan'
config configuration 'tour_config'
config wlan 'basic'
config wlan 'ap0'
config wlan 'sta0'
config wlan 'default_ap'
        option ap 'ap0'
config on_off 'chn1_msg_push_info'
config on_off 'msg_push_event'
config on_off 'motion_det'
config notif_list 'motion_notif_list'
config region_info 'region_info_1'
config network
        option init 'network'
        list affects 'dhcpd'
        list affects 'radvd'
        list affects 'ddns'
        list affects 'firewall'
config wireless
        option init 'wlan'
        list affects 'wlanwarn'
config firewall
        option init 'firewall'
        list affects 'upnpd'
        list affects 'packet_capture'
config olsr
        option init 'olsrd'
config dhcpd
        option init 'udhcpd'
config dropbear
        option init 'dropbear'
config httpd
        option init 'httpd'
config fstab
        option init 'fstab'
config system
        option init 'led'
        list affects 'luci_statistics'
config upnpd
        option init 'miniupnpd'
config ntpclient
        option init 'ntpclient'
config samba
        option init 'samba'
config tinyproxy
        option init 'tinyproxy'
config uhttpd
        option init 'uhttpd'
config ddns
        option init 'ddns'
config guest_network
        option init 'guest_network'
        list affects 'firewall'
config wlanwarn
        option init 'wlanwarn'
config packet_capture
        option init 'packet_capture'
config root 'root'
config third_account 'third_account'
config authentication 'authentication'
config server 'vhttpd'
config server 'rtsp'
config URL 'URL'
        option profile_1 'stream1'
        option profile_2 'stream2'
        option profile_3 'stream3'
config on_off 'media_encrypt'

Ciphertext, what is it?

You may wonder what sits inside those ciphertext variables, however, the content is encrypted. Thus, we have to perform the same operation and search in sl sysroot with grep by filtering by the keyword ciphertext:

config root 'root'
        option username 'admin'
        option passwd 'zMiVw8Kw0oxKXL0'
        option ciphertext 'dl5GoIRk+FMC/JgP5yLjA+r8PynYYSai8DSmdv1Xw7iALNEKxkE5UusQw6BMC4+FlcWv0bCPuw8DSlSk/vkmcTZ/BF/ZY1ENNJqo+uJtiGi2f1zJFjleYhPlDx4YXa3qp7oSNF8EU1BU4mOY9nEtUakFl4oVPsvlLGM3qE/zI2k='
        option sharepwd ''
        option comment ''
config third_account 'third_account'
        option username '---'
        option passwd '---'
        option ciphertext 'dl5GoIRk+FMC/JgP5yLjA+r8PynYYSai8DSmdv1Xw7iALNEKxkE5UusQw6BMC4+FlcWv0bCPuw8DSlSk/vkmcTZ/BF/ZY1ENNJqo+uJtiGi2f1zJFjleYhPlDx4YXa3qp7oSNF8EU1BU4mOY9nEtUakFl4oVPsvlLGM3qE/zI2k='
        option comment ''
grep -ir 'ciphertext'                                                                 
grep: dsd: binary file matches
grep: libdecrypter.so: binary file matches
grep: _usr_conf_data_decrypt.extracted/18: binary file matches
grep: extractions/flash_fixed.bin.extracted/43DA00/squashfs-root/usr/sbin/uhttpd: binary file matches
grep: extractions/flash_fixed.bin.extracted/43DA00/squashfs-root/usr/bin/dsd: binary file matches
grep: extractions/flash_fixed.bin.extracted/43DA00/squashfs-root/bin/nvid: binary file matches
grep: extractions/flash_fixed.bin.extracted/43DA00/squashfs-root/bin/cet: binary file matches
grep: extractions/flash_fixed.bin.extracted/5D800/squashfs-root/usr/sbin/wpa_supplicant: binary file matches
grep: extractions/flash_fixed.bin.extracted/5D800/squashfs-root/usr/lib/libdecrypter.so: binary file matches
                                                                                                                              

Several matches show up, so we will start to analyze the binaries libdecrypter.so and dsd.

In libdecrypter.so we see an interesting function.

000013e0  int32_t private_decrypt(char* arg1, int32_t arg2, void* arg3)
00001414      int32_t $s0_2
00001414      if (arg2 != 0xac || (arg2 == 0xac && arg1 == 0))
00001430          msglog(6, 0x1a40, 0x1b24, arg2)  {"DECRYPTER"}  {"wrong input. ciphertext_len %d.n"}
00001484          label_1484:
00001484          $s0_2 = 0
00001414      if (arg2 == 0xac && arg1 != 0)
00001450          void var_918
00001450          int32_t $v0_1 = sub_fa0(1, arg3, &var_918, arg2)
00001458          int32_t $v0_2
00001458          int32_t $a2_1
00001458          if ($v0_1 s>= 0)
00001490              $v0_2 = BIO_new_mem_buf(&var_918, 0xffffffff)
0000149c              if ($v0_2 == 0)
000014b8                  $a2_1 = 0x1a90  {"Create BIO buffer for public key…"}
000014cc              else
000014cc                  int32_t $v0_3 = PEM_read_bio_RSAPrivateKey($v0_2, 0, 0, 0)
000014d8                  if ($v0_3 == 0)
000014f4                      msglog(6, 0x1a40, 0x1a90)  {"DECRYPTER"}  {"Create BIO buffer for public key…"}
000014fc                      $s0_2 = 0
00001510                  else
00001510                      int32_t var_20 = 0x80
00001520                      void var_118
00001520                      int32_t $v0_4 = rsa_base64_decode(arg1, 0xac, &var_118, &var_20)
00001528                      int32_t $v0_5
00001528                      int32_t $a2_3
00001528                      if ($v0_4 != 0)
00001560                          void var_98
00001560                          $v0_5 = RSA_private_decrypt(var_20, &var_118, &var_98, $v0_3, 1)
0000156c                          if ($v0_5 s< 0)
00001584                              $a2_3 = 0x1abc  {"call RSA_public_encrypt failed"}
000015a4                          else
000015a4                              int32_t $v0_6 = calloc(0x75, 1)
000015ac                              $s0_2 = $v0_6
000015b0                              if ($v0_6 != 0)
000015ec                                  memcpy($v0_6, &var_98, $v0_5)
000015f8                                  *($s0_2 + $v0_5) = 0
000015cc                              else
000015cc                                  msglog(6, 0x1a40, 0x1b6c)  {"DECRYPTER"}  {"Calloc mem error.n"}
00001544                      else
00001544                          $a2_3 = 0x1b48  {"Base64 decode ciphtertext error.…"}
0000156c                      if ($v0_4 == 0 || ($v0_4 != 0 && $v0_5 s< 0))
00001590                          $s0_2 = 0
0000158c                          msglog(6, 0x1a40, $a2_3)  {"DECRYPTER"}
00001600                      RSA_free($v0_3)
00001610                  BIO_free_all($v0_2)
00001470          else
00001470              $a2_1 = 0x1a6c  {"Base64 decode public key error.n"}
0000149c          if ($v0_1 s< 0 || ($v0_1 s>= 0 && $v0_2 == 0))
00001478              msglog(6, 0x1a40, $a2_1)  {"DECRYPTER"}
00001478              goto label_1484
00001630      return $s0_2

The following points summarize how the function seems to operate:

  • Initially, it validates that the ciphertext is 172 bytes long.
  • Decodes the private key from a given buffer (arg3).
  • Uses OpenSSL internally (BIO, PEM_read_bio_RSAPrivateKey)
  • Decodes base64 ciphertext
  • Performs decryption with private RSA + PKCS#1 padding
  • Returns a buffer with the decrypted result

A probable translation to pseudocode would be:

char* private_decrypt(char* ciphertext_b64, int len, void* rsa_key_data) {
    if (len != 0xac || ciphertext_b64 == NULL)
        return NULL;
    char decoded_key[...];
    if (sub_fa0(1, rsa_key_data, &decoded_key, len) < 0)
        return NULL;
    BIO* bio = BIO_new_mem_buf(decoded_key, -1);
    if (!bio)
        return NULL;
    RSA* rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
    if (!rsa)
        return NULL;
    uint8_t ciphertext_bin[128];
    int bin_len = rsa_base64_decode(ciphertext_b64, len, ciphertext_bin, &ciphertext_len);
    if (bin_len == 0)
        return NULL;
    uint8_t plaintext[128];
    int pt_len = RSA_private_decrypt(ciphertext_len, ciphertext_bin, plaintext, rsa, RSA_PKCS1_PADDING);
    if (pt_len < 0)
        return NULL;
    char* output = calloc(1, 0x75);
    memcpy(output, plaintext, pt_len);
    output[pt_len] = '';
    RSA_free(rsa);
    BIO_free_all(bio);
    return output;
}

This function decrypts a 128-byte RSA block, which comes in base64, using a private key provided as arg3, also encrypted. It uses OpenSSL (or a similar implementation) internally and requires both the key and the message to be in the expected format (PEM + base64).

At this stage, we went hunting for the RSA private key which was found to be embedded inside the library:

-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQC4D6i0oD/Ga5qb//RfSe8MrPVIrMIGecCxkcGWGj9kxxk74qQNq8XUuXoy2PczQ30BpiRHrlkbtBEPeWLpq85tfubTUjhBz1NPNvWrC88uaYVGvzNpgzZOqDC35961uPTuvdUa8vztcUQjEZy16WbmetRjURFIiWJgFCmemyYVbQIDAQABAoGAZ7lLVR7JUcPpyOegiuJbOEVvpJjWblfGY0rEURZRizU33yuFT77xKUOsvWLPS7BIjdlWsJ5r0NTUmGfLees71DqxfedQb3kSamBMErHu/jXeRi7MaGCLTyO9Ae+0+PFAHUdld1QjX50mAZD/+fbDPv7zUebNrMkFzbl99ctYznECQQDwiHNBP51VOF2f8pRmncr5QpZmWZb3ZNPw9Qc/97kn7Xs8zGz1NBEUA9SLcF25KXv6GpVdr6X7BuhXeB9HZpNTAkEAw+WYCnB1KjYz68FiIYkA63lrvnN2IG9pllkt+az6XFdXgOdqodoi3pWvmhkU55Z2N0okuGjm93qO1pebC3JcPwJAOsn+8Yms2LFoILnXj6UtgPLHc8id32Wjb5dT6EyR0rJ2louYbe4F5pBxGIukPKdpB94Ld9SAivRLQWW4r2jgxQJBAJo1+D1nj+Rd7PuPLXfmyRGVcQrpC7m22vDfXUDqOeBNZXX1Ns0Y0lBUl3sAeaNhn8ggls2QzxlMonstt4EIUrMCQCgOhLJ1SoUw1RE+b3x5hpuibFpiknX9MAjNxMJ1vHQFgsYTIVlD9LdHc/+nGbeXhzi0BJ2h3R5tmQmIseOs9f0=
-----END RSA PRIVATE KEY-----

On the other hand, if we analyze the dsd binary we can see the following private_decrypt function call:

Lastly, we only have to start putting these pieces of information together. Firstly, we took the ciphertext and decoded it to base64 and saved it in bin format:

echo "dl5GoIRk+FMC/JgP5yLjA+r8PynYYSai8DSmdv1Xw7iALNEKxkE5UusQw6BMC4+FlcWv0bCPuw8DSlSk/vkmcTZ/BF/ZY1ENNJqo+uJtiGi2f1zJFjleYhPlDx4YXa3qp7oSNF8EU1BU4mOY9nEtUakFl4oVPsvlLGM3qE/zI2k=" 
| base64 -d > encrypted.bin

Lastly, we executed the following command:

openssl rsautl -decrypt -inkey private.pem -in encrypted.bin

Conclusion

The analysis conducted on the TP-Link Tapo C200 camera (version 3.0) revealed the encryption mechanism used in certain internal system files. Through reverse engineering, it was discovered that the decryption key is derived from a fixed string linked to the device model and firmware version —in this case, “C200 3.0″— which is hashed and used as the key for the DES algorithm in ECB mode.

This reconstruction enabled successful decryption of the protected information, demonstrating that the implemented encryption scheme does not rely on a random or secret key, but rather on predictable data embedded within the firmware itself.

Furthermore, a second encryption layer based on RSA was identified, in which specific encrypted structures are decrypted using a private RSA key embedded or accessible from the system. The process involved base64 decoding, dynamic loading of the RSA key, and decryption using PKCS#1 padding. This discovery further exposed the device’s vulnerabilities, as understanding the logic allowed successful recovery of data protected by this additional mechanism.

While functional, these mechanisms reveal significant weaknesses in data protection—especially when cryptographic keys are derived from predictable information and the firmware can be freely analyzed.

 

Samir Sánchez Garnica

Hi, Samir Sanchez Garnica is a seasoned Purple Team professional with over 12 years of expertise in ethical hacking, specializing in security testing across web environments, cloud platforms (Azure, AWS, Google Cloud), and on-premise infrastructures—with a primary focus on the banking sector. His extensive experience encompasses mobile application security, reverse engineering, network team exercises, and social engineering initiatives. A passionate programmer, Samir continually enhances his work through the automation of pentesting processes, leveraging his proficiency in SHELLSCRIPT, Python3, PHP, C, JavaScript, PowerShell, Objective-C, Node.js, Dart, and Assembly Language. Samir’s current endeavors are centered on reverse engineering, where he excels as both a reverser and shellcode writer across Windows, macOS, and GNU/Linux environments, spanning user land and kernel land. His latest research efforts delve into debugging within iOS mobile environments, IoT technologies, and the intricacies of reversing on MIPS and ARM architectures, with a specialized focus on radio frequency-based hardware exploitation.

Post navigation

Leave a Comment

Leave a Reply

Your email address will not be published. Required fields are marked *