Initial commit

This commit is contained in:
Alex Gustafsson 2020-10-27 17:36:11 +01:00
commit 3233091d32
6 changed files with 205 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
.DS_Store
firmware
dump

73
README.md Normal file
View file

@ -0,0 +1,73 @@
# D-Link DCS reversing
### An effort to simplify firmware analysis and firmware updating on D-Link's DCS line of products
***
## Project goal
The short-term goal of this project is to provide the necessary tools to easily analyze and modify D-Link's firmware for its DCS line of products (such as their network cameras).
A long-term goal is to be able to provide an alternative firmware with only the bare essentials to use the camera in order to fully disable all cloud aspects of the camera and to potentially make it HomeKit-compatible.
## What's in the box
### Scripts
#### Firmware
The `./scripts/download-firmware.sh` script downloads the firmware for a specific product. For example, one can download the latest firmware for the DCS-936L like so:
```sh
./scripts/download-firmware.sh <model> <output directory> [firmware index]
./scripts/download-firmware.sh dcs-936l firmware 1
```
The `./scripts/unpack-firmware.sh` script decrypts, unpacks and carves date from the firmware file. It can be used like so:
```sh
./scripts/unpack-firmware.sh <path to firmware> <output directory>
./scripts/unpack-firmware.sh firmware/DCS-936L_fw_revA1_1-07-04_eu_multi_20180918.zip dump
```
Example (shallow) directory structure for the unpacking script:
```
tree -L 4 -d dump/
dump/
├── carved
│   └── _update.extracted
│   ├── squashfs-root
│   └── squashfs-root-0
│   ├── empty -> /tmp
│   ├── lib -> /tmp
│   ├── lock -> /tmp
│   ├── log -> /tmp
│   ├── run -> /tmp
│   ├── shares
│   ├── tmp -> /tmp
│   └── www
└── extracted
```
### Tools
The `./tools` directory contains dockerized tools such as Binwalk. The tools can be built and used using the following script:
```sh
./tools/build.sh
docker run -it binwalk
```
## Previous art
https://github.com/bmork/defogger
## Contributing
Any contribution is welcome. If you're not able to code it yourself, perhaps someone else is - so post an issue if there's anything on your mind.
### Development
Clone the repository:
```
git clone https://github.com/AlexGustafsson/dlink-dcs-reversing && cd dlink-dcs-reversing
```

48
scripts/download-firmware.sh Executable file
View file

@ -0,0 +1,48 @@
#!/usr/bin/env bash
model="$1"
output_directory="$2"
firmware_index="$3"
function search() {
query="$1"
curl -s "https://eu.dlink.com/uk/en/search/suggestions?mode=ajax&q=$query" | grep -e 'item-listing.*href' | sed 's/.*href="\([^"]\+\)".*/\1/'
}
function find_firmware() {
page="$1"
curl -s "https://eu.dlink.com$page" | grep "href" | sed 's/.*href="\([^"]\+\)".*/\1/' | grep ".zip"
}
function find_all_firmware() {
while read -r page; do
find_firmware "$page"
done
}
search_result="$(search "$model")"
if [[ -z "$search_result" ]]; then
echo "Unable to find any matching model"
exit 1
fi
all_firmware="$(echo "$search_result" | find_all_firmware)"
if [[ -z "$all_firmware" ]]; then
echo "Unable to find any firmware for that model"
exit 1
fi
if [[ -z "$firmware_index" ]]; then
echo "Found firmware the following firmware"
echo "$all_firmware" | nl -w1 -s' '
echo -ne "\nWhich firmware do you want to download? "
read firmware_index
fi
firmware="$(echo "$all_firmware" | sed -n "${firmware_index}p")"
if [[ -z "$firmware" ]]; then
echo "No such firmware"
exit 1
fi
wget --directory-prefix="$output_directory" "$firmware"

67
scripts/unpack-firmware.sh Executable file
View file

@ -0,0 +1,67 @@
#!/usr/bin/env bash
USE_DOCKER="${USE_DOCKER:-1}"
# The input firmware zip file as downloaded from D-Link's website
firmware_zip="$1"
# Output directory
output="$2"
# The RSA private key dumped from the device using the following command:
# pibinfo PriKey
private_key="$(cat << EOF
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQC87QYtji6c0odxDs5SON+lpP0WE52WMK4OuRo8mHL0HWi0bZe0
dyDcJ6IO6EwKuIn0sJi5oY8/P0g3PAp4TTlZm6WBiwZ8XaPwnGY8Kd2lrcRvPR+0
UJ07hQ4RvhfFmanN8KEhe/myKkMldO/reyW8nwRRJwc2OHEvZ81KfAppWwIDAQAB
AoGAKGeIqrV9woxD6yn/dhYzvnlKpy4KxdQjZYKw2cTA0PR5MB1AFJhlrq/LOOT1
XlWZK3uZLhofSKeAClAM7S2W1fTbxmM8y/3g6c5Z3LbpNsvwVTWNp5ErbKMMeR+q
CnUA+NQ47f65EwUUyTIWhMcgINLjZT33Eg0DOPUVIoiDEgECQQDta5ehRLQQN8Tr
5OROwFrJA3qL4g+qmcnUrVfgDE/ro1zxcYluleg8ZCAJbhBgju7Y75voRlrZITkF
2dGFZq4PAkEAy7Xowx+az4ZU6Iw/AGmbv801digR9345UKZZNRLffLh0Hda2mPM+
25whWWTMiPcY0ty9/MZovZvVyuYuxzHb9QJBAJlbEgpdMmH3Y/9rTf2ASiPlV1bb
onrz82aowUY7LbRrRTG/wKHpuqSnl/n/WhzEtorx2qbiKvRtfUPGOowMkwkCQGgi
n9BPcbYwd2tBdlthoUrVPkUeisC399iwkN2+vhxltoYiYsmhXzqof6vRCXXiyv/P
9Bcp3hU/enT0YmlVpZkCQQDmsui42t0uup3hj6ITZa2JRkCCUI7qyU0HrE65lj88
s4IoUXr0RWUtnEbeDUbw2GtQVHNoldXVXSh30SDb6El7
-----END RSA PRIVATE KEY-----
EOF
)"
# Temporary directory used throughtout the unpacking
temp_directory="$(mktemp -d)"
# First unzip the file which contains a single tar file
unzip -p "$firmware_zip" > "$temp_directory/firmware.tar"
# Untar the file
tar --extract --directory="$temp_directory" --file="$temp_directory/firmware.tar"
rm "$temp_directory/firmware.tar"
# Decrypt the AES encryption key
echo "$private_key" > "$temp_directory/rsa.key"
openssl rsautl -decrypt -in "$temp_directory/aes.key.rsa" -out "$temp_directory/aes.key" -inkey "$temp_directory/rsa.key"
# Decrypt the update itself
openssl aes-128-cbc -v -nosalt -md md5 -d -in "$temp_directory/update.aes" -out "$temp_directory/update" -kfile "$temp_directory/aes.key"
openssl aes-128-cbc -v -nosalt -md md5 -d -in "$temp_directory/update.bin.aes" -out "$temp_directory/update.bin" -kfile "$temp_directory/aes.key"
# Move the firmware to the target directory
mkdir -p "$output/extracted"
mv "$temp_directory/update" "$output/extracted"
mv "$temp_directory/update.bin" "$output/extracted"
# Remove the temporary directory
rm -r "$temp_directory"
# Unpack the base64 encoded binary within update.bin
mkdir -p "$output/carved"
cat "$output/extracted/update.bin" | tr -d '\n' | sed 's!.*=== ddPack Boundary ===begin-base64 755 /dev/stdout!!' | rev | cut -c 5- | rev | base64 -d > "$output/carved/payload"
# Extract files from the update payload
if [[ "$USE_DOCKER" -eq 1 ]]; then
docker run --rm -it -v "$(realpath "$output"):/output" binwalk --extract --directory "/output/carved" "/output/extracted/update"
else
binwalk --extract --directory "$output/carved" "$output/extracted/update"
fi

11
tools/Dockerfile.binwalk Normal file
View file

@ -0,0 +1,11 @@
FROM debian:buster-slim
RUN apt-get update && \
apt-get install -y python3 git squashfs-tools python3-pip && \
git clone https://github.com/ReFirmLabs/binwalk.git && \
cd binwalk && \
python3 setup.py install
VOLUME /output
ENTRYPOINT ["binwalk"]

3
tools/build.sh Executable file
View file

@ -0,0 +1,3 @@
#!/usr/bin/env bash
docker build -t binwalk -f tools/Dockerfile.binwalk .