A narrative of wifi secrets and techniques, UART lockdowns and a broken flash reminiscence chip


Dear Fellowlship, simply as we introduced in our earlier submit, our beloved God Debugger has seen match to solid his divine gentle -laden with opcodes- upon his humble servant, and we’ve got a brand new homily right here in our temple. Please, sit down and hearken to the story of how one among our owls, alongside together with his brother-in-law, moved on to dissect the subsequent part of the Eufy ecosystem: the Eufy HomeBase 2.

We targeted our evaluation in Eufy Homebase2 as a substitute of Homebase3 as a result of, as we defined in From your doorbell to your home network it’s the model that I discovered deployed in my metropolis, and in addition was the best to purchase. The firmware model we analyze right here is 3.4.2.2h (2026-06-05 18:45:48)

This is the primary time I touched one thing associated to “{hardware}”. I all the time did vuln looking on firmwares that I may obtain from web, so please forgive the sins I commited

IMPORTANT!!! You should learn first the earlier article earlier than you proceed studying this one.

Just as with the earlier article, we will probably be protecting a wide range of matters right here; consequently, some members of this fellowlship could have little interest in sure sections and would possibly want to skip straight to no matter appeals to them most. That is why we current this blessed providing: a desk of contents.

In the previous chapter of this saga, I discussed that we have been solely capable of extract the doorbell’s firmware as a result of the Homebase’s flash reminiscence was soldered on to the board and didn’t expose any pins to which we may connect check hooks to dump the firmware. Initially we didn’t wish to desolder it (though ultimately we needed to as I’ll clarify later) so I needed to wait to amass further {hardware}. Craig S. Blackie pointed me to spring clips that will go well with the dimensions wanted for the Winbond 25Q256JWEQ (WSON8 8.6mm). Once the clip arrived I created probably the most makeshift setup conceivable, utilizing rubber bands to safe the clip whereas I proceeded to take readings utilizing the Raspberry Pi’s SPI0 interface, simply as we did with the doorbell.

Setup utilizing rubber bands to learn the firmware.

I carried out three reads and the three had totally different checksums, which often is a indicator of one thing being improper. After inspecting the dumps, I rapidly realized they have been rubbish and fully ineffective. Unlike with the doorbell, on this case, the ability provided for the learn operation additionally activated different parts on the board that interacted with the reminiscence; due to this fact, to extract the firmware, we needed to desolder the chip and browse it off-board.

My brother-in-law (Óscar Lestón) was the courageous soul that desoldered the flash reminiscence (I used to be too scared to even strive it):

Desoldering
Desoldering

Although the reminiscence module seemed horrible as soon as eliminated, it was barely broken…

Chip
Extracted flash reminiscence

And lastly we replicated the identical setup utilizing the Raspberry Pi SPI 0 to dump the firmware. This time the three dumps had the identical checksum and contained “fascinating knowledge”. The solely downside was… a block of 64kbs was erased / couldn’t be learn, extremely possible as a result of we broken it when extracting the chip.

Using the Raspberry Pi to read the chip off-board
Using the Raspberry Pi to learn the chip off-board

Most of the firmware may very well be extracted utilizing Binwalk.


                                                                          /dwelling/psyconauta/analysis/Eufy/homebase2-firmware/chipoff/STUFF/extractions/homestation2_firmware00.bin
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
DECIMAL                            HEXADECIMAL                        DESCRIPTION
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
83328                              0x14580                            U-Boot model string: 1.1.3 (Jun 14 2023 - 16:18:56)
3022226                            0x2E1D92                           XZ compressed knowledge, whole dimension: 11514432 bytes
14536660                           0xDDCFD4                           XZ compressed knowledge, whole dimension: 2200 bytes
14538862                           0xDDD86E                           XZ compressed knowledge, whole dimension: 2084 bytes
14540948                           0xDDE094                           XZ compressed knowledge, whole dimension: 1868 bytes
14542818                           0xDDE7E2                           XZ compressed knowledge, whole dimension: 168 bytes
14542988                           0xDDE88C                           XZ compressed knowledge, whole dimension: 4192 bytes
14547182                           0xDDF8EE                           XZ compressed knowledge, whole dimension: 2844 bytes
14550028                           0xDE040C                           XZ compressed knowledge, whole dimension: 244 bytes
14550282                           0xDE050A                           XZ compressed knowledge, whole dimension: 1452 bytes
15138816                           0xE70000                           uImage firmware picture, header dimension: 64 bytes, knowledge dimension: 3429849 bytes, compression: lzma, CPU: MIPS32, OS: Linux, picture kind: OS Kernel Image, load tackle: 0x80000000, entry 
                                                                      level: 0x802E04F0, creation time: 2023-06-14 12:56:37, picture identify: "Linux Kernel Image"
21233664                           0x1440000                          JFFS2 filesystem, little endian, nodes: 3426, whole dimension: 12255244 bytes

Some elements have been recovered, others no. Because there was a number of XS streams, we select the silly (or possibly not so silly) thought of utilizing instantly 7z to extract all in a giant blob (and hopefully search by needles there to carve recordsdata).

➜  extractions mkdir -p 7z_mandanga  
➜  extractions 7z e -y -o7z_mandanga homestation2_firmware00.bin 

7-Zip 23.01 (x64) : Copyright (c) 1999-2023 Igor Pavlov : 2023-06-20
 64-bit locale=es_ES.UTF-8 Threads:16 OPEN_MAX:1024

Scanning the drive for archives:
1 file, 33554432 bytes (32 MiB)

Extracting archive: homestation2_firmware00.bin
         
ERRORS:
There are knowledge after the top of archive

--
Path = homestation2_firmware00.bin
Type = xz
ERRORS:
There are knowledge after the top of archive
Offset = 3022226
Physical Size = 11514432
Tail Size = 19017774
Method = LZMA2:17
Streams = 358
Blocks = 358
Characteristics = BlockPackSize BlockUnpackSize

ERROR: There are some knowledge after the top of the payload knowledge : homestation2_firmware00

Sub gadgets Errors: 1

Archives with Errors: 1

Open Errors: 1

Sub gadgets Errors: 1
➜  extractions ls -hal 7z_mandanga 
whole 42M
drwxrwxr-x 2 psyconauta psyconauta 4,0K sep 19 19:41 .
drwxrwxr-x 4 psyconauta psyconauta 4,0K sep 19 19:34 ..
-rw-rw-r-- 1 psyconauta psyconauta  42M sep 19 18:35 homestation2_firmware00

One of the important thing questions we needed to analyze through the firmware was the brand new algorithm for producing credentials for the OCEAN_XXXXXX administration Wi-Fi, as we noticed that it differed fully from what was anticipated based mostly on the 2024 paper. Specially, we have been fascinating in know if the algorithm was weak as beforehand or no.

After writing the earlier article, I noticed I had failed my brother-in-law as a mentor. I had proven him how one can use Ghidra and pseudo-C as a substitute of main him down the trail of sunshine and motive. I atoned for my sin and drew radare2.

First we checked the place the Wifi community ESSID and password may very well be discovered within the firmware. A easy grep was sufficient to determine NVRAM variables containing each wifi names and credentials (the ad-hoc wifi used to enroll the doorbell and the mangement wifi):

➜  extractions strings homestation2_firmware00.bin_83358_unknown.uncooked | grep F1VSXfNQL_ZCd3k -A5 -B5  
AuthMode=WPAPSKWPA2PSK;WPAPSKWPA2PSK
EncrypType=AES;AES
RekeyInterval=3600
RekeyMethod=TIME
PMKCachePeriod=10
WPAPSK1=F1VSXfNQL_ZCd3k
WPAPSK2=913ceac3
DefaultKeyID=2;2
Key1Type=0
Key1Str1=
Key2Type=0
➜  extractions strings homestation2_firmware00.bin_83358_unknown.uncooked | grep OCEAN_E9A5FC -A5 -B5   
DDNSPassword=
CountryRegion=0
CountryRegionABand=7
CountryCode=ES
BssidNum=2
SSID1=OCEAN_E9A5FC
SSID2=4350c372
WirelessMode=9
TxRate=0
Channel=0
BasicRate=15

Then we tried a extra broad search to attempt to determine binaries and/or scripts associated to the wifi setup:

➜  7z_mandanga strings homestation2_firmware00 | rg 'OCEAN_'   
%s,<%d>file not exist.return OCEAN_TEST_TF_CARD_NOT_FOUND.
OCEAN_MAGIC
out of reminiscence of OCEAN_TEST_DATA
OCEAN_TF_CARD_FORMAT_SUCCESSED
OCEAN_TF_CARD_FORMAT_FAIL_MOUNT
OCEAN_TF_CARD_FORMAT_FAIL
OCEAN_TF_CARD_FORMAT_IN_USE
        ssid_prefix="OCEAN_"
        ssid_prefix="OCEAN_"
CONFIG_LEDS_OCEAN_PWM=y
OCEAN_RUN=/mnt/ocean.sh
if [ -f $OCEAN_RUN  ];then
    chmod +x $OCEAN_RUN
    sh $OCEAN_RUN &

Unraveling a bit extra this thread we discovered an fascinating line that matches what we already knew: the ESSID is the concatenation of “OCEAN_” and MAC tackle:

➜  7z_mandanga strings homestation2_firmware00 | rg 'ssid_prefix'
    ssid_prefix="ocean_factory_"
        ssid_prefix="OCEAN_"
    WIFI_SSID=$ssid_prefix$SSID_MAC
    ssid_prefix="`nvram_get ssid_pre`"
    if [ "$ssid_prefix" = "" ];then
        ssid_prefix="OCEAN_"
    WIFI_SSID=$ssid_prefix$SSID_MAC

Let’s zoom out to get the total script:

➜  7z_mandanga strings homestation2_firmware00 | rg 'ssid_prefix' -B30 -A40
.sdata
.sbss
.bss
.pdr
.gnu.attributes
.mdebug.abi32
#!/bin/sh
work_mode="`cat /var/run/testmode`"
def_mode="`nvram_get 2860 work_mode`"
SSID_MAC=""
nvram_ssid="`nvram_get 2860 SSID1`"
bssid_num=`nvram_get 2860 BssidNum`
eth_state=`apcliDaemon get_eth_state`
repeater_enable=`nvram_get 2860 RepeaterEnable`
wifi_11bgn_enabled=`nvram_get 2860 wifi_11bgn_enabled`
Wireless_Mode=9
if [ "$eth_state" = "0" -a "$repeater_enable" = "1" -a "$wifi_11bgn_enabled" = "1" ]; then
    Wireless_Mode=9
get_wifi_mac()
    SSID_MAC="`ifconfig ra0 | grep HWaddr | awk '{print $5}' | awk -F ':' '{print $4$5$6}'`"
    #SSID_MAC="`ifconfig ra0 | grep HWaddr | awk '{print $5}' | awk -F ':' '{print $5$6}'`" 
    whereas [ "$SSID_MAC" = "" ]
        sleep 1
        SSID_MAC="`ifconfig ra0 | grep HWaddr | awk '{print $5}' | awk -F ':' '{print $4$5$6}'`"
        #SSID_MAC="`ifconfig ra0 | grep HWaddr | awk '{print $5}' | awk -F ':' '{print $5$6}'`"
    achieved
    echo "get mac in ssid is:$SSID_MAC"
if [ "$bssid_num" = "2" ];then
    ifconfig ra1 down>/dev/null 2>&1
if [ "$work_mode" = "1" ];then
    ssid_prefix="ocean_factory_"
    if [ "$def_mode" = "factory_mode" ];then
        ssid_prefix="OCEAN_"
    get_wifi_mac
    WIFI_SSID=$ssid_prefix$SSID_MAC
    echo "set wifi SSID:$WIFI_SSID"
    iwpriv ra0 set SSID="$WIFI_SSID"
    if [ "$def_mode" = "factory_mode" ];then
        # solely WIFI_SSID isn't equ nvram_ssid, replace nvram.
        if [ "$nvram_ssid" != $WIFI_SSID ];then
            nvram_set SSID1 $WIFI_SSID
        fi
else
    ssid_prefix="`nvram_get ssid_pre`"
    if [ "$ssid_prefix" = "" ];then
        ssid_prefix="OCEAN_"
    get_wifi_mac
    WIFI_SSID=$ssid_prefix$SSID_MAC
    echo "set wifi SSID:$WIFI_SSID"
    # solely WIFI_SSID isn't equ nvram_ssid, replace nvram.
    if [ "$nvram_ssid" != $WIFI_SSID ];then
        nvram_set SSID1 $WIFI_SSID
        iwpriv ra0 set SSID="$WIFI_SSID"
        if [ "$nvram_ssid" = "MT7628_AP" ];then
            sleep 3
            #reboot
            /sbin/umount_and_reboot.sh
        fi
    iwpriv ra0 set HtBw=0
    iwpriv ra0 set WirelessMode=$Wireless_Mode
    iwpriv ra0 set HtGi=0
    iwpriv ra0 set SCSEnable=1
    if [ "$bssid_num" = "2" ];then
        # ssid and pwd set in RT2860_default_vlan
        #iwpriv ra1 set SSID="AKDevbind"
        #iwpriv ra1 set WPAPSK="Anker39#*"
        #iwpriv ra1 set SSID="XMCONFIG"
        #iwpriv ra1 set WPAPSK="12345678"
        iwpriv ra1 set HtBw=0
        iwpriv ra1 set WirelessMode=$Wireless_Mode
        iwpriv ra1 set HtGi=0
        iwpriv ra1 set SCSEnable=1
        iwpriv ra1 set WmmCapable=1
        iwpriv ra1 set ed_chk=0
wpapsk="`nvram_get WPAPSK1`"
if [ "$wpapsk" != "" ];then
    #echo "iwpriv ra0 set WPAPSK=$wpapsk"
    iwpriv ra0 set WPAPSK=$wpapsk
# set wmm
iwpriv ra0 set WmmCapable=1
# change wan mode, 
wifi
apcli
iwpriv
home_security
if [ "$eth_state" = "0" -a "$repeater_enable" = "1" ]; then
    switch_wan_interface.sh eth2.2 apcli0 0
#!/bin/sh

So, from one aspect we discovered how the ESSID is created and from the opposite aspect we discovered that the password is learn from a NVRAM variable (wpapsk="nvram_get WPAPSK1"). Let’s do a fast search with that identify:

➜  7z_mandanga strings homestation2_firmware00 | rg -i 'WPAPSK1' -A5 -B5  
wifi channel:%d.
fail to get freq.
/dev/gpio
Error whereas opening /dev/gpio
SSID1
WPAPSK1
SSID2
ra1 SSID=%s
WPAPSK2
ra1 WIFI_PWD=%s
/sbin/chpasswd.sh eufycamera %s
--
(...)

Just within the first hit there’s something that appears like a compiled binary (that %d is suspicious). I constructed this crappy script to extract the elf that seek for the string, then search backwards to seek out the magic header and assume the next file within the blob can be an ELF:

 #!/usr/bin/env python3
 
 
 with open("homestation2_firmware00", "rb") as file:
     knowledge = file.learn()
 
 needle = knowledge.discover(b"WPAPSK1")
 magic = knowledge.rfind(b"x7fELF", 0, needle)
 finish = knowledge.discover(b"x7fELF", needle)
 binary = open("elf_wifi_01", "wb")
 binary.write(knowledge[magic:end])
 binary.shut()

And it labored flawelessly:

➜  7z_mandanga python3 carve_wifi.py
➜  7z_mandanga file elf_wifi_01     
elf_wifi_01: ELF 32-bit LSB executable, MIPS, MIPS32 rel2 model 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped

Doing a fast test on the symbols we discover a number of fascinating stuff associated to wifi, specifically that juicy set_wifi_pwd.

➜  7z_mandanga r2 elf_wifi_01
WARN: Relocs has not been utilized. Please use `-e bin.relocs.apply=true` or `-e bin.cache=true` subsequent time
 -- Use 'zoom.byte=printable' in zoom mode ('z' in Visual mode) to seek out strings
[0x0045d130]> aaa
INFO: Analyze all flags beginning with sym. and entry0 (aa)
INFO: Analyze imports (af@@@i)
INFO: Analyze entrypoint (af@ entry0)
INFO: Analyze symbols (af@@@s)
INFO: Running plugin pre-analysis hooks
INFO: Analyze all capabilities arguments/locals (afva@@F)
INFO: Analyze operate calls (aac)
INFO: Analyze len bytes of directions for references (aar)
INFO: Finding and parsing C++ vtables (avrr)
INFO: Analyzing strategies (af @@ technique.*)
INFO: Emulate capabilities to seek out computed references (aaef)
INFO: Recovering native variables (afva@@@F)
INFO: Type matching evaluation for all capabilities (aaft)
INFO: Propagate noreturn info (aanr)
INFO: Use -AA or aaaa to carry out further experimental evaluation
INFO: Finding xrefs in noncode sections (e anal.in=io.maps.x; aav)
[0x0045d130]> afl~wifi
0x006f8908    1    288 sym.eufy_setDoorbellMechanicalChimeSwitch_wifi
0x005a972c   14   1124 sym.zx_update_dev_wifi_info_by_addr
0x0054ad3c   10    316 sym.check_hub_wifi_power
0x00558fd8   18   1800 sym.quick_bind_wifi_mgmt_rcv_handler
0x0052cfac   19   1272 sym.zx_update_hub_wifi_channel
0x005e5414   93   7544 sym.netlink_wifi_connect
0x0093f1c0    6    528 sym.aws_wifi_get_mac
0x0053aff8    1     80 sym.zx_get_wifi_mac
0x004cda10   13    728 sym.zx_check_wifi_version
0x005489a0    1     16 sym.wifi_reduceTxPower
0x005a47a0   23    892 sym.zx_alloc_wifi_addr
0x00532224    4    324 sym.set_camera_wifi_rssi
0x0049c7d4   11    448 sym.wifi_check_all_devs_online
0x0049c61c   10    440 sym.wifi_get_dev_rssi
0x0049c994   20   1768 sym.wifi_get_devs_rssi_list_in_json
0x0059e8f8    3    204 sym.restart_wifi
0x0053bb04    1    144 sym.set_pair_wifi_info
0x0053b048    8    660 sym.get_wifi_info
0x006fb684  399  18808 sym.zx_wifi_send_command
0x00603514    6    484 sym.make_wifi_notify_json
0x0054ab0c    9    560 sym.convert_wifi_countrycode
0x0059df7c    1    104 sym.wifi_info_signal_init
0x0053b510   33   1524 sym.set_wifi_pwd
0x00558894    5    292 sym.zx_quick_bind_timer_stop_send_wifi_info
0x006f8094    8    304 sym.eufy_set_wifi_countrycode
0x0054ae78    7    464 sym.set_wifi_power_flag
0x004da374   54   3076 sym.zx_handle_wifi_ready
0x006f6348    8    828 sym.wifi_log_server_init
0x006f8a28    1    288 sym.eufy_setDoorbellElectronicRingtoneTime_wifi
0x0094a1f4    4    168 sym.anker_mgmt_register_get_wifi_channel_cb
0x00532368   10    396 sym.check_camera_wifi_rssi_ok
0x005580a0   28   2036 sym.zx_quick_bind_timer_send_wifi_info
0x0094a29c    4    168 sym.anker_mgmt_register_get_wifi_mac_cb
0x0053b2dc    6    564 sym.get_wifi_ra1_info
0x006f6684    8    828 sym.wifi_log_server_t40_init
0x0056dc34   15   1008 sym.repeater_update_all_dev_wifi_channel
0x0049d07c   13    636 sym.wifi_devs_rssi_test_mode_exit
0x004daf78    1    160 sym.handle_wifi_ready_thread
0x008c5ac4    7    356 sym.zx_homekit_get_wifi_ready
0x0049d2f8    9    288 sym.wifi_setManualChannel
0x004cd584   11    668 sym.eufysdk_common_msg_wifi_callback

Jumping into that operate we will see that first it builds a password based mostly on a MD5 hash that’s used domestically for the person eufycamera and it’s not associated to the wifi. The wifi-stuff begins at 0x0053b690 the place it checks one parameter from base_param (I suppose the kind of machine or mannequin) towards 0x0C. This half is essential as a result of if the worth is totally different to 0x0C, then it makes use of the MAC Address (proper block) in the meantime if it matches then it might use what returns z8GetSN() (left block). We are within the z8GetSN() case.

Radare2
Different circulate based mostly on machine mannequin.

The z8GetSN() operate communicates via i2c and sends command 0xC1 (the i2c half is inside z8SendKnowledge()) and browse 0x11 bytes from the response.

Radare2
I2C communication to extract a serial quantity (it isn’t the machine SN)

Then bytes are translated into 32 byte string and fed to a operate referred to as mac_func() which additionally receives the Homebase Serial Number (T8010...):

Radare2
The SN from the I2C communication and the machine Serial Number (obj.g_hub_sn) used as parameters for mac_func()

This mac_func calls a helper to carry out HMAC SHA256 with the earlier talked about knowledge, being the “message” the worth returned by z8GetSN and the “key” the Serial Number:

Radare2
HMAC SHA256

The result’s utilized by a operate that will encode the data into textual content.

Radare2
Encoding reminiscence contents

The zx_Memory_Encode operate calls urlsafe_b64_encode which converts the worth into base64 utilizing the next alphabet:

[0x006f0490]> px 65 @ 0xa5cb40
- offset -  4041 4243 4445 4647 4849 4A4B 4C4D 4E4F  0123456789ABCDEF
0x00a5cb40  4142 4344 4546 4748 494a 4b4c 4d4e 4f50  ABCDEFGHIJKLMNOP
0x00a5cb50  5152 5354 5556 5758 595a 6162 6364 6566  QRSTUVWXYZabcdef
0x00a5cb60  6768 696a 6b6c 6d6e 6f70 7172 7374 7576  ghijklmnopqrstuv
0x00a5cb70  7778 797a 3031 3233 3435 3637 3839 2d5f  wxyz0123456789-_
0x00a5cb80  00                                       .

Finally, the password is up to date in NVRAM and adjusted executing the exterior command iwpriv ra0 set WPAPSK=%s:

Radare2
Updating NVRAM worth

So, the one unkown knowledge to copy the password is the worth returned by z8GetSN. The different compontent, the machine serial quantity, is “predictable” as a result of it follows a recognized template based mostly on the kind of machine.

In the earlier article, we talked about that UART entry was blocked. Specifically, connecting through UART yielded a immediate asking the person to press the “Enter” key. However, doing so brought on the method to terminate and the identical program to relaunch, as soon as once more requesting the important thing press; this created an infinite loop that prevented entry to an precise shell. Logs might be seen beneath:

beginning pid 5617, tty '/dev/ttyS1': '/sbin/login.sh'

course of '/sbin/login.sh' (pid 5617) exited. Scheduling for restart.

Please press Enter to activate this console. 
setrlimit(RLIMIT_CORE, &restrict); 

beginning pid 6526, tty '/dev/ttyS1': '/sbin/login.sh'

course of '/sbin/login.sh' (pid 6526) exited. Scheduling for restart.

Please press Enter to activate this console. 
setrlimit(RLIMIT_CORE, &restrict); 

beginning pid 6608, tty '/dev/ttyS1': '/sbin/login.sh'



course of '/sbin/login.sh' (pid 6608) exited. Scheduling for restart.

On the opposite hand, attempting to interrupt U-Boot witch a escape sequence didn’t work.

After buying the firmware and resolving questions on how the Wi-Fi password algorithm labored, the subsequent goal was to know the mechanism behind the UART entry lockout and discover a method to bypass it, as we supposed to make use of the machine itself to debug key providers and seek for vulnerabilities.

In the logs the serial port is /dev/ttyS1, so let’s search references to it:

➜  extractions grep -r ttyS1 
grep: homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin: coincidencia en fichero binario
grep: homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin_3143840_aes_forward_table.uncooked: coincidencia en fichero binario
grep: homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin_3679760_unknown.uncooked: coincidencia en fichero binario
grep: homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin_3135648_aes_reverse_table.uncooked: coincidencia en fichero binario
grep: homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin.extracted/3F16A4/decompressed.bin: coincidencia en fichero binario
homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin.extracted/3F16A4/decompressed.bin.extracted/0/etc_ro/inittab:ttyS1::askfirst:/sbin/login.sh
grep: homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin.extracted/3F16A4/decompressed.bin.extracted/0/bin/recover_0_elf.uncooked: coincidencia en fichero binario
grep: homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin.extracted/3F16A4/decompressed.bin.extracted/0/bin/get well: coincidencia en fichero binario
homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin.extracted/3F16A4/decompressed.bin.extracted/0/sbin/makedevlinks.sh:mknod /dev/ttyS1 c 4 65
grep: homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin.extracted/3F16A4/decompressed.bin_0_cpio.uncooked: coincidencia en fichero binario
grep: homestation2_firmware00.bin.extracted/E70000/Linux_Kernel_Image.bin.extracted/0/decompressed.bin_3147936_aes_rcon.uncooked: coincidencia en fichero binario
grep: 7z_mandanga/homestation2_firmware00: coincidencia en fichero binario

The key’s within the inittab file, the place we will see the it triggers the execution of /sbin/login.sh script as soon as the person press “Enter” (the BusyBox askfirst motion reveals the immediate with sentence “Please press Enter to activate this console”). The script is straightforward as:

#!/bin/sh

DEBUG_LOG="`nvram_get debug_log`"
if [ "$DEBUG_LOG" = "1" -o -f "/mnt/enable_console" ];then
	echo "enter debug mode" > /dev/console
	/bin/login
fi

The script checks if debug mode is enabled by checking the NVRAM variable debug_log and based mostly on that permits the entry to the shell (effectively, to login within the shell) or exits, coming into within the loop.

We didn’t discover a straight method to allow that variable and bypass the lockdown. There are varied methods on altering the boot mode to allow “debug”, however all of them are far-off from our arms as a result of:

  1. One of them relies within the presence of a file within the filesystem. Because to have the ability to drop a file we would wish entry, it’s a chicken-egg scenario.
  2. The different technique includes a convoluted magic protocol based mostly on ARP and instructions signed by a non-public key which isn’t current within the firmware. Yes, they use encapsulate their very own protocol on ARP and trade magic signed packets to allow debug remotely. I’m not positive what crack they smoked.

It happens to me at this level that if we cannot bypass the test for whether or not it’s booting in manufacturing or debug mode, why not fully obliterate the test and soar straight to a shell?

The firmware didn’t comprise something encrypted, so ought to be straight ahead to change it to permit us direct entry via the serial port. The downside was… Do you bear in mind after I talked about that it was “barely broken”?. Well, we fucked 64kbs at 0x500000 which is the load tackle for the picture.

At first, I believed our clumsy arms had ruined the venture and that the concept of ​​utilizing the precise machine for dynamic evaluation with a debugger was slipping away (we might nonetheless have the choice of attempting to emulate some binaries, however gaining access to the unique {hardware} is all the time infinitely simpler). Fortunately, after analyzing the firmware structure a bit extra, we found a a lot smaller “restoration picture” that was nonetheless intact at 0xe70000. So, as a result of the “regular” picture was fucked, the bootloader must load this restoration picture that we will manipulate to take away the UART lockdown.

The “restoration picture” is a U-Boot image with a 64-byte header:

Header offset Length Field Original restoration worth
0x00 4 Magic 0x27051956
0x04 4 Header CRC32 0xe764e161
0x08 4 Timestamp Preserved by the builder
0x0c 4 Compressed payload size 0x3455d9 = 3,429,849
0x10 4 RAM load tackle 0x80000000
0x14 4 Entry tackle 0x802e04f0
0x18 4 Payload CRC32 0x19b650c3
0x1c 4 OS, structure, kind, compression 05 05 02 03
0x20 32 Image-name space Preserved, together with vendor-used bytes

The precise filesystem is inside a matrioska of various compression layers that may be visualized within the following diagram:

Matrioska of compression
Matrioska!

Once the filesystem was unpacked, I made the minimal modifications to permit us to leap on to the shell with root privileges. To keep away from complications, I padded the modifications to match the identical dimension it had the unique code (code is from python script I used to carry out the modifications and re-pack/repair CRCs):

old_condition = b'if [ "$DEBUG_LOG" = "1" ];then'
new_condition = b'if [ 1 = 1 ];then' + b' ' * 13

old_login = b't/bin/loginn'
new_login = b't/bin/sh   n'

After performing some native check to confirm that the modified restoration picture was appropriately modified and it might unpack/load appropriately we proceeded to overwrite it within the flash chip. In order to disable the Write Protection that appears in the documentation this connection diagram was adopted:

Diagram to disable Write Protection
Diagram to disable Write Protection

Writing the brand new restoration picture:

Writting the new recovery image
Overwriting the restoration picture with our backdoored model

Then we carried out three reads to confirm the method was achieved appropriately. After that, the chip was solded once more into the machine board:

Soldering again the chip
Soldering once more the chip

Once the chip was soldered I related once more my laptop computer to the machine utilizing a USB-TTL. First it tried to load the traditional picture, however it failed after which it jumped to backdoored restoration picture and after loading it… we bought a shell!!

UART shell
Finally entry to an admin shell!!

We lastly have a shell; the one downside is that the restoration picture could be very restricted and the file system isn’t mounted, so the binaries and libraries wanted to correctly debug the system are lacking. Furthermore, the kernel lacks sure modules-such as these chargeable for dealing with WiFi interfaces or the I2C interface used to generate the WiFi key.

The set of instructions out there within the default picture is kind of restricted, however no less than there are instruments like wget, which permits us to switch recordsdata from the laptop computer to the machine. I ready a crappy setup utilizing an outdated TP-Link router that I bought from Telefónica in 2015.

Network Setup
Not glamorous setup

I compiled a brand new BusyBox with a great deal of additional instructions that weren’t current within the authentic one. Using this new BusyBox I began to attempt to create a “staged” filesystem and bind all of the paths to this “staged” filesystem. I needed to execute providers wanted to run earlier than the large ELF in command of essential providers (homeapp_security, the identical binary that contained the WiFi logic), additionally due to reminiscence limitations I needed to modify some kernel parameters like overcommit_ratio. It was a 3 hours strategy of hit or miss till I may run the principle binary and be capable to work together with it.

Because this was a course of that I would wish to repeat every time I needed to make use of the machine (as a result of the filesystem within the restoration picture isn’t persistent, so after every boot I’ve to revive all) I shared the logs of picocom to Codex and requested it to arrange a all-in-one script that will repeat the identical steps I did (and discard the stuff that didn’t work). To be trustworthy, the next morning after that night time of taking part in with the Homebase I barely remembered what I did, so having the logs was marvelous to rebuild and automatize the method. Keep logs of all the things all the time, they are going to save your ass in some unspecified time in the future.

The diagram of actions till the homeapp_security runs is the next:

Diagram of actions
Flow diagram from the patched firmware to getting the binary working

The two most essential scripts to rebuild the filesystem are proven beneath:

#!/bin/sh
# Recovery UART bootstrap. Run with sh; don't supply into the login shell.
# Usage: sh homeapp-restore-v5.sh [http://PC:8000] [--start]
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PATH
unset LD_PRELOAD LD_LIBRARY_PATH
BASE=/media/homeapp-debug
ROOT=$BASE/rootfs
SERVER=http://192.168.90.112:8000
START=no
fail() { echo "homeapp-restore: $*" >&2; exit 1; }
for argument in "$@"; do
    case "$argument" in
        http://*) SERVER=${argument%/} ;;
        --start) START=sure ;;
        *) fail 'utilization: sh homeapp-restore-v5.sh [http://PC:8000] [--start]' ;;
    esac
achieved
case "$SERVER" in *' '*|*'?'*|*'#'*) fail 'use a plain HTTP base URL with out areas/question/fragment' ;; esac
[ "`awk '/^Uid:/ {print $3}' /proc/self/status`" = 0 ] || fail 'root efficient UID required'
[ -r /proc/self/mountinfo ] || fail '/proc/self/mountinfo is required'
[ -c /dev/gpio ] && [ -c /dev/apsoc_nvram ] || fail 'anticipated restoration machine nodes lacking'

mounted() { awk -v p="$1" '$2==p {n++} END {exit n==0}' /proc/mounts; }
check_tmpfs() {
    awk -v p="$1" -v dimension="$2" '$2==p {
        n++; if ($3=="tmpfs") {
            depend=cut up($4,a,","); for(i=1;i<=depend;i++) if(a[i]=="dimension=" dimension "ok") okay=1
        }
    } END {exit !(n==1 && okay)}' /proc/mounts
}
empty_dir()  return 1
    [ -z "`ls -A "$1"`" ]

asset_md5() {
    # BEGIN GENERATED ASSET HASHES
    case "$1" in
        busybox-extra) echo b587f623ef28b84e277fbd1b2b0b2348 ;;
        homeapp-enter) echo 8fde5ed1e3e65d07a7b9ebe672b25a5c ;;
        homeapp-mount-runtime.sh) echo 19e73a1584137c0d2150d6968cccb4c5 ;;
        homeapp-start-bounded-v4.sh) echo 19b70b8ac6751f8e161e490460ff8f3e ;;
        homeapp-control-v5.sh) echo 2fc7613db0f02a0d16c1417bb0282264 ;;
        homeapp_rootfs.tar.gz) echo bf6acaecf3301532bda2c1f6c41a3b2c ;;
        *) return 1 ;;
    esac
    # END GENERATED ASSET HASHES
}
confirm() {
    anticipated=`asset_md5 "$1"` || fail "unknown asset: $1"
    precise=`md5sum "$2" | awk '{print $1}'`
    [ "$actual" = "$expected" ] || fail "checksum mismatch: $2; cease and test the PC bundle"
}
fetch() 
stamp() { awk '{sub(/^.*) /, ""); print $20}' "/proc/$1/stat" 2>/dev/null; }
is_supervisor() {
    [ -r "/proc/$1/cmdline" ] || return 1
    tr '00' 'n' < "/proc/$1/cmdline" | awk '
        NR==1  $0=="/sbin/run_mini_system.sh")
        $0=="/sbin/run_mini_system.sh" {script=1}
        END {exit !(shell && script)}'
}
recover_pids() {
    for procdir in /proc/[0-9]*; do
        [ -e "$procdir/exe" ] || proceed
        if [ "$procdir/exe" -ef /bin/recover ] || [ "$procdir/exe" -ef /sbin/recover ]; then
            echo "${procdir#/proc/}"
        fi
    achieved
}
signal_recover() 
coordinate_recovery() {
    # Exact argv matching avoids by chance signalling grep or the UART shell.
    for procdir in /proc/[0-9]*; do
        supervisor_pid=${procdir#/proc/}
        if is_supervisor "$supervisor_pid"; then
            supervisor_stamp=`stamp "$supervisor_pid"`
            [ -n "$supervisor_stamp" ] || proceed
            kill -STOP "$supervisor_pid" || fail "can't pause restoration supervisor $supervisor_pid"
            echo "$supervisor_pid $supervisor_stamp" > "$BASE/recovery-supervisor-$supervisor_pid"
            echo "homeapp-restore: paused restoration supervisor $supervisor_pid"
        fi
    achieved
    signal_recover TERM
    sleep 2
    signal_recover KILL
    sleep 1
    [ -z "`recover_pids`" ] || fail 'restoration duties survived cease'
    pidof get well >/dev/null 2>&1 && fail 'unrecognized get well course of stays; examine ps'
    return 0
}
install_commands()  fail "can't set up $asset"
    achieved


echo 'homeapp-restore revision: v5; authentic firmware functions, RAM staging'
if [ -f "$BASE/restore-v5.ready" ]; then
    # Reusing this recipe's accomplished setup is protected; by no means extract over binds.
    check_tmpfs "$BASE" 65536 || fail 'staging mount modified or is stacked'
    check_tmpfs /media/mmcblk0p1 8192 || fail 'database mount modified or is stacked'
    confirm homeapp-enter "$BASE/homeapp-enter"
    confirm busybox-extra "$BASE/busybox-extra"
    install_commands
    sh /tmp/homeapp-mount-runtime.sh --resume || fail 'runtime mount verification failed'
    coordinate_recovery
    echo 'homeapp-restore: verified and reused accomplished setup; no archive obtain/extraction'
else
    # Fail closed on partial/handbook setups; no rm -rf, unmount or overlay of information.
    mounted "$BASE" && fail 'unrecognized/partial staging mount; examine it or reboot earlier than retrying'
    empty_dir "$BASE" || fail 'staging listing isn't empty; protect it and examine or reboot'
    mounted /media/mmcblk0p1 && fail 'database/storage path already mounted; won't cowl it'
    empty_dir /media/mmcblk0p1 || fail 'database/storage listing isn't empty; won't cowl it'
    free_kb=`awk '/^MemFree:/ {print $2}' /proc/meminfo`
    [ "${free_kb:-0}" -ge 81920 ] || fail 'lower than 80 MiB free; reboot to a contemporary restoration shell or examine reminiscence'
    # Refuse present regular providers earlier than staging/coordination.
    for service in home_security mdnsd mips_collector pushMuxer systemServer embdb_eufy; do
        pidof "$service" >/dev/null 2>&1 && fail "$service already working; use a contemporary restoration boot"
    achieved
    original_mode=`cat /proc/sys/vm/overcommit_memory`
    original_ratio=`cat /proc/sys/vm/overcommit_ratio`
    if [ "$original_mode" = 2 ] && [ "$original_ratio" -lt 75 ]; then
        echo 75 > /proc/sys/vm/overcommit_ratio || fail 'can't elevate runtime commit ratio'
        echo "homeapp-restore: strict overcommit ratio $original_ratio -> 75 (this boot solely)"
    fi
    if [ "$original_mode" = 2 ]; then
        headroom=`awk '/^CommitLimit:/ {restrict=$2} /^Committed_AS:/ {used=$2} END {print limit-used}' /proc/meminfo`
        [ "$headroom" -ge 65536 ] || fail 'lower than 64 MiB dedication headroom; no extraction tried'
    fi
    mkdir -p "$BASE" || fail 'can't create staging listing'
    mount -t tmpfs -o dimension=64m tmpfs "$BASE" || fail 'can't mount staging tmpfs'
    check_tmpfs "$BASE" 65536 || fail 'sudden staging filesystem dimension'
    echo "$original_mode $original_ratio" > "$BASE/original-overcommit"
    echo "$SERVER" > "$BASE/download-server"
    for asset in busybox-extra homeapp-enter homeapp-mount-runtime.sh homeapp-start-bounded-v4.sh homeapp-control-v5.sh; do
        fetch "$asset"
    achieved
    chmod 755 "$BASE/busybox-extra" "$BASE/homeapp-enter" || fail 'chmod failed'
    "$BASE/homeapp-enter" --check || fail 'native helper doesn't run'
    fetch homeapp_rootfs.tar.gz
    (cd "$BASE" && ./busybox-extra tar -xzf homeapp_rootfs.tar.gz) || fail 'extraction failed; protect diagnostics, then reboot earlier than retrying'
    # Only the verified non permanent archive is eliminated, earlier than any runtime binds.
    rm "$BASE/homeapp_rootfs.tar.gz" || fail 'can't take away staged archive'
    "$BASE/homeapp-enter" "$ROOT" /bin/sh -c ':' || fail 'regular loader/BusyBox doesn't execute'
    mkdir -p /media/mmcblk0p1 || fail 'can't create database path'
    mount -t tmpfs -o dimension=8m tmpfs /media/mmcblk0p1 || fail 'can't mount non permanent database'
    check_tmpfs /media/mmcblk0p1 8192 || fail 'sudden database filesystem dimension'
    mkdir -p /media/mmcblk0p1/.sqlite || fail 'can't create database listing'
    install_commands
    sh /tmp/homeapp-mount-runtime.sh --apply || fail 'runtime mount setup failed; earlier mounts preserved'
    coordinate_recovery
    echo v5 > "$BASE/restore-v5.prepared" || fail 'can't document profitable setup'
fi
echo 'homeapp-restore: READY. /tmp/homeapp begin|standing|logs|cease|shell'
echo 'Wi-Fi/I2C drivers and chronic flash configuration are usually not restored by userspace staging.'
df -k "$BASE" /media/mmcblk0p1
if [ "$START" = yes ]; then
    /tmp/homeapp begin || fail 'setup accomplished, however software startup failed; examine /tmp/homeapp standing'
fi



#!/bin/sh
# Run with `sh`, by no means supply into the interactive UART shell.
# Does not begin providers, mount flash, or change reminiscence coverage.
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PATH
BASE=/media/homeapp-debug
ROOT=/media/homeapp-debug/rootfs
fail() { echo "homeapp-mount: $*" >&2; exit 1; }
mounted() { awk -v p="$1" '$2 == p {discovered=1} END {exit !discovered}' /proc/mounts; }
same_mount_root() {
    # Compare machine ID and filesystem-root path, not simply the filesystem kind.
    awk -v s="$1" -v d="$2" '
        $5 == s {supply=$3 " " $4}
        $5 == d {goal=$3 " " $4; depend++}
        END {exit !(depend == 1 && supply != "" && supply == goal)}
    ' /proc/self/mountinfo
}

case "${1-}" in
    --inspect)
        echo '--- Mounts ---'
        cat /proc/mounts
        echo '--- Memory ---'
        cat /proc/meminfo
        echo '--- Overcommit mode / ratio ---'
        cat /proc/sys/vm/overcommit_memory /proc/sys/vm/overcommit_ratio
        echo '--- Staged executables ---'
        ls -l "$BASE/homeapp-enter" "$ROOT/bin/busybox" "$ROOT/bin/home_security"
        echo '--- Processes ---'
        ps
        exit 0
        ;;
    --apply|--resume) mode=$1 ;;
    *) fail 'utilization: sh homeapp-mount-runtime.sh --inspect|--apply|--resume' ;;
esac

mounted "$BASE" || fail 'staging filesystem isn't mounted'
[ -x "$BASE/homeapp-enter" ] || fail 'native helper lacking'
[ -x "$ROOT/bin/home_security" ] || fail 'software lacking'
mounted /media/mmcblk0p1 || fail 'put together non permanent database mount first'
[ -d /media/mmcblk0p1/.sqlite ] || fail 'database listing lacking'

# Resume solely matching binds, with one mount at every staged vacation spot.
# Leave staged /mnt (together with its authentic zx_log.conf) in place. Recovery's
# /mnt bind failed within the first try; persistent state is a separate step.
for path in dev proc sys and so forth var tmp media dev/pts media/mmcblk0p1; do
    if mounted "$ROOT/$path"; then
        [ "$mode" = --resume ] || fail "$ROOT/$path already mounted; examine partial setup first"
        same_mount_root "/$path" "$ROOT/$path" || fail "present bind doesn't match /$path, or is stacked: $ROOT/$path"
    fi
achieved

bind_path()  fail "can't create $target_path"
    echo "homeapp-mount: $source_path -> $target_path"
    mount -o bind "$source_path" "$target_path"
    rc=$?
    [ "$rc" -eq 0 ] 
for path in dev proc sys and so forth var tmp media; do
    bind_path "/$path" "$ROOT/$path"
achieved
bind_path /dev/pts "$ROOT/dev/pts"
bind_path /media/mmcblk0p1 "$ROOT/media/mmcblk0p1"
echo 'Runtime binds accomplished; no software providers began.'

Then working it from the UART shell we will see it prepares all the things and in addition launch the binary:

# wget -O /tmp/homeapp-restore-v5.sh http://192.168.90.112:8000/homeapp-restore-
v5.sh
Connecting to 192.168.90.112:8000 (192.168.90.112:8000)
homeapp-restore-v5.s 100% |*******************************|  9174  --:--:-- ETA
# sh /tmp/homeapp-restore-v5.sh http://192.168.90.112:8000 --start
homeapp-restore revision: v5; authentic firmware functions, RAM staging
homeapp-restore: strict overcommit ratio 50 -> 75 (this boot solely)
homeapp-restore: downloading busybox-extra
Connecting to 192.168.90.112:8000 (192.168.90.112:8000)
busybox-extra.half   100% |*******************************|   673k --:--:-- ETA
homeapp-restore: downloading homeapp-enter
Connecting to 192.168.90.112:8000 (192.168.90.112:8000)
homeapp-enter.half   100% |*******************************|   622k --:--:-- ETA
homeapp-restore: downloading homeapp-mount-runtime.sh
Connecting to 192.168.90.112:8000 (192.168.90.112:8000)
homeapp-mount-runtim 100% |*******************************|  3054  --:--:-- ETA
homeapp-restore: downloading homeapp-start-bounded-v4.sh
Connecting to 192.168.90.112:8000 (192.168.90.112:8000)
homeapp-start-bounde 100% |*******************************|  4383  --:--:-- ETA
homeapp-restore: downloading homeapp-control-v5.sh
Connecting to 192.168.90.112:8000 (192.168.90.112:8000)
homeapp-control-v5.s 100% |*******************************|  6488  --:--:-- ETA
homeapp-enter: working; uid=0 euid=0; static MIPS helper
homeapp-restore: downloading homeapp_rootfs.tar.gz
Connecting to 192.168.90.112:8000 (192.168.90.112:8000)
homeapp_rootfs.tar.g 100% |*******************************| 14579k 00:00:00 ETA
homeapp-mount: /dev -> /media/homeapp-debug/rootfs/dev
homeapp-mount: /proc -> /media/homeapp-debug/rootfs/proc
homeapp-mount: /sys -> /media/homeapp-debug/rootfs/sys
homeapp-mount: /and so forth -> /media/homeapp-debug/rootfs/and so forth
homeapp-mount: /var -> /media/homeapp-debug/rootfs/var
homeapp-mount: /tmp -> /media/homeapp-debug/rootfs/tmp
homeapp-mount: /media -> /media/homeapp-debug/rootfs/media
homeapp-mount: /dev/pts -> /media/homeapp-debug/rootfs/dev/pts
homeapp-mount: /media/mmcblk0p1 -> /media/homeapp-debug/rootfs/media/mmcblk0p1
Runtime binds accomplished; no software providers began.
homeapp-restore: READY. /tmp/homeapp begin|standing|logs|cease|shell
Wi-Fi/I2C drivers and chronic flash configuration are usually not restored by userspace staging.
Filesystem           1k-blocks      Used Available Use% Mounted on
tmpfs                    65536     44844     20692  68% /media/homeapp-debug
tmpfs                     8192         0      8192   0% /media/mmcblk0p1
homeapp-mount: holding verified bind /media/homeapp-debug/rootfs/dev
homeapp-mount: holding verified bind /media/homeapp-debug/rootfs/proc
homeapp-mount: holding verified bind /media/homeapp-debug/rootfs/sys
homeapp-mount: holding verified bind /media/homeapp-debug/rootfs/and so forth
homeapp-mount: holding verified bind /media/homeapp-debug/rootfs/var
homeapp-mount: holding verified bind /media/homeapp-debug/rootfs/tmp
homeapp-mount: holding verified bind /media/homeapp-debug/rootfs/media
homeapp-mount: holding verified bind /media/homeapp-debug/rootfs/dev/pts
homeapp-mount: holding verified bind /media/homeapp-debug/rootfs/media/mmcblk0p1
Runtime binds accomplished; no software providers began.
homeapp: launcher PID 5880; startup output: /media/mmcblk0p1/homeapp-launch-5565.log
homeapp: startup in progress; /tmp/homeapp standing and /tmp/homeapp logs
A working launcher isn't proof of software or enrollment readiness.

Finally we will see that the providers are uncovered!

# /media/homeapp-debug/busybox-extra netstat -lntup
Active Internet connections (solely servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program identify    
tcp        0      0 0.0.0.0:10400           0.0.0.0:*               LISTEN      6016/home_security
tcp        0      0 0.0.0.0:10402           0.0.0.0:*               LISTEN      6016/home_security
tcp        0      0 0.0.0.0:32290           0.0.0.0:*               LISTEN      6016/home_security
tcp        0      0 0.0.0.0:10404           0.0.0.0:*               LISTEN      6016/home_security
tcp        0      0 0.0.0.0:32292           0.0.0.0:*               LISTEN      6016/home_security
tcp        0      0 0.0.0.0:32293           0.0.0.0:*               LISTEN      6016/home_security
tcp        0      0 0.0.0.0:32295           0.0.0.0:*               LISTEN      6016/home_security
tcp        0      0 0.0.0.0:10600           0.0.0.0:*               LISTEN      6016/home_security
tcp        0      0 0.0.0.0:32392           0.0.0.0:*               LISTEN      6016/home_security
tcp        0      0 0.0.0.0:9000            0.0.0.0:*               LISTEN      5974/pushMuxer
tcp        0      0 127.0.0.1:5000          0.0.0.0:*               LISTEN      5963/mips_collector
tcp        0      0 0.0.0.0:554             0.0.0.0:*               LISTEN      5974/pushMuxer
tcp        0      0 0.0.0.0:53              0.0.0.0:*               LISTEN      1405/dnsmasq
tcp        0      0 0.0.0.0:23              0.0.0.0:*               LISTEN      1693/telnetd
netstat: /proc/web/tcp6: No such file or listing
udp        0      0 0.0.0.0:53              0.0.0.0:*                           1405/dnsmasq
udp        0      0 0.0.0.0:32380           0.0.0.0:*                           6016/home_security
udp        0      0 0.0.0.0:46217           0.0.0.0:*                           6456/ntpclient
udp        0      0 0.0.0.0:43466           0.0.0.0:*                           1405/dnsmasq
udp        0      0 0.0.0.0:21200           0.0.0.0:*                           6016/home_security
udp        0      0 0.0.0.0:29947           0.0.0.0:*                           6016/home_security
netstat: /proc/web/udp6: No such file or listing

The final thing was compiling a suitable model of GDB and add it to the machine to start out taking part in 🙂

GDB running on the Homebase2
GDB working on the Homebase2

Of course way more configurations modifications are wanted to make the binary work correctly (e.g. I needed to bridge an eth interface to create a br0 throughout the vary it wants for the friends -long story quick: it makes use of a peer desk with MAC addresses to reject or settle for communications), however with a debugger all the things is much simpler. Just hearth the method, test what fails, appropriate it or simply hook it to feed with the values it’s anticipating to proceed the circulate.

With the arrival of LLMs, I’ve misplaced all enthusiasm for publishing technical content material. I’ve been publishing articles on-line since 2007 sharing issues I realized or found utilizing dozens of various aliases throughout varied blogs and boards. That is sort of 20 years. And immediately, I’ve misplaced all need to share my experiences.

For one factor, there may be the lack of worth in writing if nobody goes to learn it. Nowadays, solely a minority of individuals truly cease to learn an article; most ask an AI for a abstract or just skim via with out paying consideration. There was an ecosystem the place individuals hung out checking their RSS feeds (rattling, I’m outdated) and studying articles from their favourite blogs or authors. The first main blow on this regard got here from social media, the place immediacy and “scoring Twitter factors” turned the first driving drive behind content material creation.

Then there may be the truth that the overwhelming majority of printed articles are generated instantly by AI. Even fascinating analysis items or vulnerability write-ups are churned out by automated looms, utilizing that lobotomized language that provides me a stroke each time I attempt to learn them. People appear delighted to gobble up such insubstantial crap. I suppose as a result of it follows that first level. I write in “damaged English” (yep, though I’ve been working for a UK firm for 5 years, my English continues to be horrible), but I might one million occasions fairly learn an article written by an individual in “damaged English” than the umpteenth repetition of the identical buildings and inventory phrases ChatGPT peppers its texts with.

The ultimate nail within the coffin is the truth that… does it even make sense in 2026 to maintain publishing technical content material for human readers? In the previous, you’d learn a number of materials (and even bookmark it for future reference) as a result of it was genuinely helpful. Perhaps you have been tinkering with a product’s firmware that another person had already explored; you may discover that article and comply with the path they blazed. The similar utilized to vulnerability evaluation: you’d examine others’ work so you may replicate it if you encountered the same situation. And I’m not simply speaking about particular merchandise; I’m speaking about methodologies: how somebody solved an issue, permitting you to face the identical scenario years later and apply what you had learn again then. With AI, this not is sensible; the global community is popping into a group of meat proxies prompting the most recent LLM to resolve no matter snag or scenario arises.

I clearly use AI in my skilled work, however to not sort out my “passion” initiatives (just like the issues I submit on this weblog). I must make clear that final level: I exploit it, as an illustration, after I’m reverse-engineering one thing and are available throughout a operate that performs mathematical operations (like after I used it within the earlier article to determine Reed-Solomon), or to automate a process I’ve already carried out manually (e.g., on this very article, I used it to construct a script based mostly on instructions I had executed and that have been recorded within the log). I completely take pleasure in my passion, and I don’t need automation to rob me of these hours spent banging my head towards the wall attempting to determine one thing out, or that second of delight when the penny drops and I’ve a “eureka” second.

About a decade in the past I bear in mind studying Matasano’s cryptochallenges and this sentence caught in my head since then: Breaking repeating-key XOR (“Vigenere”) statistically is clearly an educational train, a “Crypto 101” factor. But extra individuals “know the way” to interrupt it than can truly break it.

I suppose now we reside within the global community the place everybody is aware of how one can ask the LLM to hack one thing as a substitute of precise understanding how one can hack one thing.

As regular, be happy to present us suggestions at our twitter @AdeptsOf0xCC (though I misplaced the password and might’t entry to the account anymore 😀).





Source link