Find 1-day vulnerability with binary diffing

สวัสดีครับ สำหรับบทความนี้ผมจะพาทุกคนลองเล่นตั้งแต่การ Build Lab ขึ้นมาจนไปถึงการลองหาช่องโหว่เบื้องต้นด้วยวิธีการทำ Binary Diffing นะครับ
Target Selection
สำหรับเป้าหมายของเราในวันนี้ผมเลือกตัว Synology DS920+ เป็นตัวที่เคยเอาไปใช้แข่งในงาน Pwn2own Toronto 2022 โดยจะใช้ตัว OS DSM 7.1.1 Update 2 (เนื่องจากมีการ Patch ที่ Update 3) ซึ่งไม่แน่ใจว่าจะเจอช่องโหว่ตัวเดียวกันหรือเปล่านะครับ

ซึ่งตอนแรกผมว่าจะโหลดมาแค่ Patch แต่ว่าหาวิธี extract ไม่เจอเนื่องจากไปอ่านมาเขาบอกว่ามีการทำ encrypt ตัว package ทำให้ไม่สามารถแกะออกมาได้ 🥹 เลยจำเป็นต้องไปทำวิธีลง OS แล้วทำ snapshot หลังจาก upgrade แทน
OS Installation
หลังจากค้นข้อมูลเบื้องต้นพบว่ามีคนทำตัว Builder ให้แล้วสามารถไปโหลดมาใช้ได้เลยที่ https://github.com/pocopico/tinycore-redpill โดยผมจะใช้เป็นตัว QEMU บน Mac M1 ในการ build ขึ้นมานะครับ
Download image
$ wget https://github.com/pocopico/tinycore-redpill/releases/download/v0.9.4.3/tinycore-redpill.v0.9.4.3.img.gz
$ gunzip tinycore-redpill.v0.9.4.3.img.gz
Create HDD
สร้าง HDD สำหรับ Install OS
$ qemu-img create raw.img 20G
Boot with QEMU
$ qemu-system-x86_64 -smp 2 -m 4096 \
-drive if=none,id=stick,file=tinycore-redpill.v0.9.4.3.img \
-device nec-usb-xhci,id=xhci \
-device usb-storage,bus=xhci.0,drive=stick,bootindex=1 \
-netdev vmnet-bridged,id=vmnet,ifname=en0 \
-device e1000,netdev=vmnet,mac=00:11:32:08:88:4F \
-drive id=disk,file=/tmp/raw.img,if=none \
-device ich9-ahci,id=ahci \
-device ide-hd,drive=disk,bus=ahci.00
โดยคำสั่งที่ใช้ผมจะอธิบายตามด้านล่างนี้นะครับ
CPU & RAM
-smp 2 (CPU 2 Core)
-m 4096 (Memory 4 GB)
Boot Image
-drive if=none,id=stick,file=tinycore-redpill.v0.9.4.3.img
-device nec-usb-xhci,id=xhci
-device usb-storage,bus=xhci.0,drive=stick,bootindex=1
กำหนดให้ boot image ด้วย USB สำหรับ Config ขั้นตอนถัดไป
Network
-netdev vmnet-bridged,id=vmnet,ifname=en0
-device e1000,netdev=vmnet,mac=00:11:32:08:88:4F
ใช้ bridge กับ network interface ในที่นี้ผมจะใช้ en0 ซึ่งบน default iface บน Mac และกำหนด Mac address เพื่อล๊อก IP บน DHCP
Harddisk
-drive id=disk,file=/tmp/raw.img,if=none
-device ich9-ahci,id=ahci
- device ide-hd,drive=disk,bus=ahci.00
กำหนด Harddisk สำหรับ Install OS ไม่งั้นตอนลงจะเจอปัญหาไม่พบ HDD
หลังจาก boot สำเร็จจะขึ้นหน้าจอประมาณนี้

หลังจากได้ IP มา ทีนี้เราก็เข้าไปจัดการลงตัว Bootloader ผ่าน SSH Terminal ได้
$ ssh tc@
(tc/P@ssw0rd)
Building Bootloader
ทำการ Build ตามตัวอย่างด้านล่าง
$ ./rploader.sh update now
$ ./rploader.sh fullupgrade now
Should i update the sdb with your current files [Yy/Nn]
Y
$ ./rploader.sh serialgen DS920+ realmac
Should i update the user_config.json with these values ? [Yy/Nn] Y
$ ./rploader.sh identifyusb
Should i update the user_config.json with these values ? [Yy/Nn] Y
$ ./rploader.sh satamap now
Detected 6 ports/1 drives. Override # of ports or ENTER to accept <6>
Computed settings:
SataPortMap=6
DiskIdxMap=00
Should i update the user_config.json with these values ? [Yy/Nn] Y
Done.
$ ./rploader.sh backup
Should i update the sdb with your current files [Yy/Nn] Y
$ ./rploader.sh build ds920p-7.1.1–42962 auto
$ sudo reboot

หลังจาก reboot ขึ้นมาจะมี Boot option เพิ่มขึ้นมาคือ
- USB, Verbose (เลือกอันนี้)
- SATA, Verbose

พอ boot แล้วถ้าขึ้นตามรูปนี้จะถือว่าเป็นเรื่องปกติ (ตอนแรกผมหาอยู่นานทำไมมันค้างที่ Booting the kernel.)

จากนั้นเราทำการค้นหา Synology ของเราโดยเข้าไปที่ https://finds.synology.com/ ตัวเว็บจะทำการค้นหาใน network เรา และขึ้นข้อมูลประมาณนี้

จะพบว่า Status ยังเป็น Not installed หมายความว่า OS ยังไม่ได้ถูกติดตั้ง พอเลือกไปแล้วจะขึ้นหน้าจอให้กด Install

หลังจากกดไปจะมีให้เลือกไฟล์เพื่อติดตั้ง
ให้ไปโหลดที่ https://www.synology.com/en-uk/support/download/DS920+?version=7.1#system

จากนั้นกด Next จะมีแจ้งเตือนว่าจะทำการ Format HDD ก็กด continue ไป

แล้วก็รอมันลงสักครู่

ถ้าลงสำเร็จจะขึ้นนับถอยหลังตามรูปนี้

เมื่อ restart เสร็จเรียบร้อยมันจะพาไปหน้า Config ตัว Synology ของเรา

ทำการใส่ชื่อ ใส่ password ตาม step

พอมาถึงหน้านี้ก็พร้อมใช้งานแล้ว (เฮ้อออ~)

จากนั้น Login และเข้า Control Panel เพื่อไปเปิด SSH Service จะได้จัดการอะไรง่าย ๆ หน่อย

ลองเข้า SSH ด้วย user ที่สร้างไว้

เมื่อเข้าไปดู System Info จะเห็นว่า DSM Version เป็น Update 1 อยู่ เราต้องการ Update 3 เพื่อดูว่ามีการแก้ไขอะไรบ้าง

ทำการ Update OS (Update 2) โดยไปโหลดมาจาก
http://download.synology.com/download/DSM/criticalupdate/update_pack/42962-2/
เลือก synology geminilake 920+

จากนั้นไปเลือก DSM Update และใส่ไฟล์ที่ download มา

รอระบบทำการ Update สักพัก

ระหว่าง update ผมลองใช้คำสั่ง ps เพื่อดูว่ามีการทำอะไรบ้างพบว่ามีการเรียกใช้โปรแกรม smallupd@ter ซึ่งอาจจะเป็นขั้นตอนการ extract update file

เมื่อลองแกะไปเรื่อย ๆ พบว่ามีการเขียนไฟล์ที่ทำการ update ไว้ที่ /var/log/synoupdate.log ทำให้เรารู้ว่ามีไฟล์ไหนถูกเพิ่มหรือแก้ไขบ้าง

หลังจาก update เสร็จทำการ reboot เราต้องไปแก้ตัว bootloader อีกครั้ง โดยไปเลือกที่
- Tiny Core Image Build

รันคำสั่งตามด้านล่างเพื่อแก้ไข bootloader
$ ./rploader.sh update
$ ./rploader.sh postupdate ds920p-7.1.1–42962
..
..
Found Version : 7.1.1–42962–2
Do you want to use this for the loader ? [yY/nN] : y
…
…
The new smallupdate version will be : 7.1.1–42962–2
Do you want to use this for the loader ? [yY/nN] : y
$ exitcheck.sh reboot
ในขั้นตอนต่อไปเราจะ Update เป็น version 42962–3 ดังนั้นทำการ backup hdd ไฟล์ก่อนเพื่อที่ถ้ามี update อะไรเราจะสามารถโหลด version ก่อนหน้ามาเปรียบเทียบได้
$ cp hdd.img hdd-v2.img
จากนั้นทำการ update ไปสู่ version 3 และสังเกต synoupdate.log จะพบว่ามีการแก้ไข binary /usr/bin/afpd

Patch Diffing
ขั้นตอนต่อไปเราจะทำการ Diff Binary ทั้งสองตัว โดยทำการ Boot OS ด้วย image ทั้ง 2 version มาก่อน
จากนั้นทำการวิเคราะห์ด้วยโปรแกรม
Update 2

Update 3

- IDA Free 8.2 — https://hex-rays.com/ida-free/
- Bindiff 7 (https://www.zynamics.com/software.html)
- BinExport 12 (https://github.com/google/binexport/releases)
BinExport
ใช้ IDA โหลดโปรแกรมทีละ version และเลือกไปที่ Plugin > BinExport > BinExport v2…
และ export ออกมา

Binary Diff with Bindiff
เปิดโปรแกรม Bindiff และสร้าง New Workspace ไปที่ File > New Workspace

สร้าง Diff ไปที่ Diffs > New Diffs
จากนั้นเลือกไฟล์ที่ Export จาก IDA

เสร็จแล้วจะได้หน้าตาประมาณนี้

ทำการกดไปที่ Diff และเลือก Matched Function จากนั้น sort ตรง Similarity จะพบว่ามี Function ที่ไม่ตรงกัน แสดงว่ามีการ Patched

เมื่อกดเข้าไปจะได้ Control Flow Graph มีแสดงสีต่าง ๆ คือ
- สีเขียว = เหมือนเดิม
- สีเทา = มีเพิ่มขึ้นมา
- สีแดง = โดนลบออกไป
- สีเหลือง = เยลโล่วว (ล้อเล่นครับ มันคืออันที่มีการเปลี่ยนแปลงภายในบางส่วน)

เมื่อกดเข้าไปดู Node สีเทาที่เพิ่มมา

เมื่อนำไปเทียบกับ IDA และใช้ตัว Decompiler จะพบความแตกต่างดังนี้
Update 2

Update 3

วิเคราะห์ช่องโหว่เบื้องต้น
พบว่ามีการอ่านข้อมูลจากไฟล์ไป 6 bytes ใส่ใน parameter obj->oldtmp
จากนั้นมีการอ่านข้อมูล 2 bytes จาก oldtmp[4] ใส่ parameter len
และมีการเพิ่มการตรวจ parameter `len` ขึ้นมาก่อนที่จะทำการ read ข้อมูลใส่ใน oldtmp[6] ว่าค่าที่อ่านจาก oldtmp[4] ต้องไม่เกิน 4090 bytes (0x1000–6)
แสดงว่า file ดังกล่าวอาจจะถูกโจมตีโดยการใส่ค่า `len` ไปเยอะๆทำให้สามารถอ่านข้อมูลจากไฟล์ไปเข้าตัว `obj->oldtmp[6]` จนนำไปสู่การเกิด Heap Overflow ได้
และเมื่อดูข้อมูล struct AFPObj พบว่ามี Function Pointer ซะด้วย 🤔

จบแล้วครับการสร้าง Lab และการทำ Binary Diffing เพื่อหาช่องโหว่ 1-day เบื้องต้น สำหรับ Part วิเคราะห์ช่องโหว่เพื่อทำ PoC และการเขียน Exploit นั้นอาจจะมีหรือไม่มีขึ้นอยู่กับความขี้เกียจของผู้เขียนนะครับ 😅 สวัสดีครับบบบ