Having built my previous Dial-Up system, I decided to try integrating all the components into one system. The journey to get one of the components working lead me to making my first jailbreak.
Index
The why
When I showed my original Dial-Up system up to a friend, he aptly pointed out that instead of custom-cutting power cables and cable routing, I could have probably fit it all in the 2620's case and run it from the power supply. That started the gears turning in my head.
Then I saw clabretro's second dial-up video (https://www.youtube.com/watch?v=xuBMaAi5wZU), I decided to upgrade my previous set-up and integrate everything into one box.
To recap, my previous system consisted of:
- Cisco 2620 router with NM-8AM modem card
- Cisco SPA8000 ATA
- Mikrotik hAP Mini
- Windows Server 2008R2
The SPA8000 converts the incoming VOIP calls to a call on a real phone wire, the hAP Mini was to VPN into my home network if away, and handle some routing style things. Finally, the Windows Server VM was my "legacy" AD Domain controller, and was acting as a RADIUS server to allow Windows' "Log on using dial up connection" feature.
This means I'd have to:
- Connect an outbound VPN (ideally wireguard or OpenVPN tunnel)
- Self-host RADIUS on or within the router, either as a proxy to an external IDM or with a local database.
- Accept incoming VOIP calls on the router itself
- Terminate incoming calls to a modem
The first two points I planned to solve with a Linux box of some kind, but I didn't want to just "put a Pi in it". Some research turned up the Cisco NM-CE-BP, a "network module" that ran Linux, and allowed you to upload some packages to it that allowed it to act as a HTTP proxy / cache, RealPlayer proxy etc.
The what
The Cisco NM-CE-BP is a module for the Cisco 2600/3600/3700 series routers that has a Pentium III at 500 Mhz, 256 or 512 MiB of memory, and a 20, 40 or 80 GiB 2.5" IDE drive, or a SCSI HBA.
Upon perusing eBay, I found that there's a few other modules that look to be the same thing:
- NM-AIR-WLC (Wireless LAN Controller)
- NM-AON (Application-Oriented Networking (??))
- NM-CIDS (Intrusion Detection System)
- NM-CUE (Cisco Unity Express, basically just voicemail and IVR for branch VOIP)
- NM-NAM (Network Analysis Module, bandwidth tracking)
I purchased a NM-NAM, and my one appeared to have the first revision firmware on it. (and lots of fun snippets in /root/.bash_history)
NM-NAM reconnaissance
Setup of the module is reasonably straight forwards - the module takes power from the router through the big backplane connector, and can communicate with the router via an internal serial and internal ethernet connection. The module also has an external ethernet port, and two USB 1.0 ports that are usually hidden behind the front panel, and a CompactFlash card slot which is the second IDE bus.
The "host" router needs some config - you need to set an IP address on the "AnalysisModule" interface, and some ACL tweaks for the serial line to allow you to manage the module. (You may need to s/AnalysisModule/ContentEngine/ etc. depending on which card you get.)
version 12.4 aaa authentication login nm-nam none ! interface Loopback0 ip address 10.1.14.1 255.255.255.255 ! interface Analysis-Module1/0 ip address 10.1.14.65 255.255.255.248 hold-queue 60 out ! line 33 login authentication nm-nam no activation-character no exec transport preferred none transport input all transport output all ! end
The IP address above (10.1.14.65) is the router's IP on that "link". The module's OS must use an IP within that range (so 10.1.14.66 in this case) and use the above address as the default gateway.
Once you've got the config in place, you can issue a service-module analysis-Module 1/0 reset, to hard-reset the module. Then issue a service-module analysis-Module 1/0 session to view the boot log.
Initializing memory. Please wait. 256 MB SDRAM detected BIOS Version: SM 02.00 BIOS Build date: 09/17/02 System Now Booting ... Booting from flash..., please wait. [BOOT-ASM] 7 Please enter '***' to change boot configuration: Filesystem type is ext2fs, partition type 0x83 kf: a1 : (hd0,0)/bzImage root=/dev/hda1 ro plat=nm kf: a2 : (hd0,0)/bzImage root=/dev/hda1 ro plat=nm in grub_open: (hd0,0)/bzImage root=/dev/hda1 ro plat=nm in grub_open1: /bzImage root=/dev/hda1 ro plat=nm in grub_open2: /bzImage root=/dev/hda1 ro plat=nm in grub_open3: /bzImage root=/dev/hda1 ro plat=nm 0 in grub_open: (hd0,0)/bzImage root=/dev/hda1 ro plat=nm in grub_open1: /bzImage root=/dev/hda1 ro plat=nm in grub_open2: /bzImage root=/dev/hda1 ro plat=nm in grub_open3: /bzImage root=/dev/hda1 ro plat=nm 0 In verify_kernel_sig Chksum: final image size: 900958 plat: 1 Debug: bl_sz: 109024 After: buf_len: 2048 After KEY_InitMem reading key: 0 reading key: 1 reading key: 2 reading key: 3 reading key: 4 reading key: 5 After karr After 2: buf_len: 2048 sig len : 172 in verifysignature_md5, MD5 hash generated now:02x02x02x02x02x02x02x02x02x02x02 x02x02x02x02x02x in verifysignature_md5, MD5 hash generated now, str format:hexmd5:d5cba1e2b4c5e a87857acfdedc5313a7 calling RSA_eay decrypt now got value i:33 verifysignature_md5, Orig MD5 hash generated during encryption:d5cba1e2b4c5ea87 857acfdedc5313a7 Kernel signature verified successfully In load_imagea1 In load_imagea2 Dbg ********* filemax/data_len/SECSIZ: 900958/2560/512 [Linux-bzImage, setup=0xa00, size=0xdb35e] kernel_func: kt: 3 in boot func: kt: 3 Linux version 2.4.21 (root@namlab-pc6.cisco.com) (gcc version 2.96 20000731 (Red Hat Linux 7.2 2.96-112.7.1)) #9 SMP Wed Jul 30 16:30:10 PDT 2003 Jetfire detected setup.c: handling flash window at [15MB..16MB)
The second thing the kernel prints is "Jetfire detected" - I believe this to be the codename for this platform, so that's what I'll use to refer to these modules.
Once the OS finish booting up, you'll get dropped at a typical login prompt. Logging in with the default root:root credentials gets you dropped into an iOS-like shell. That's easy enough to fix - just attach the disk to another machine, and update /etc/passwd:
root:x:0:0:root:/root:/bin/bash
(default has /usr/local/nam/bin/cli)
Once the system boots up again, you can poke around more. Of particular interest is the flash device:
cat /proc/mtd dev: size erasesize name mtd0: 00040000 00020000 "Bootloader" mtd1: 00020000 00020000 "Boot Parameters" mtd2: 00020000 00020000 "Signatures" mtd3: 00020000 00020000 "SYS DB" mtd4: 00c00000 00020000 "MP" mtd5: 00100000 00020000 "Diagnostics image"
- mtd0 is indeed the bootloader, more on that in a bit
- mtd1 looks to be the bootloader configuration
- mtd2 and mtd3 is probably used by the bootloader
- mtd4 is a "helper image"; a linux kernel with embedded initrd to help re-flash the module
- mtd5 I haven't looked
lspci doesn't show anything too crazy:
00:00.0 Host bridge: Intel Corporation 440BX/ZX - 82443BX/ZX Host bridge (AGP disabled) (rev 03) 00:07.0 ISA bridge: Intel Corporation 82371AB PIIX4 ISA (rev 02) 00:07.1 IDE interface: Intel Corporation 82371AB PIIX4 IDE (rev 01) 00:07.2 USB Controller: Intel Corporation 82371AB PIIX4 USB (rev 01) 00:07.3 Bridge: Intel Corporation 82371AB PIIX4 ACPI (rev 02) 00:0d.0 Ethernet controller: Intel Corporation 82557 [Ethernet Pro 100] (rev 08) 00:0e.0 Ethernet controller: Intel Corporation 82557 [Ethernet Pro 100] (rev 08)
Serving my sentence
The keen eyed among you may have noticed a couple of lines about verifying the kernel in the boot log. Since I planned to use this module with my own OS, I needed to find out what this meant.
I'd already tested the disk image in QEMU, and it booted like a normal x86 system - BIOS -> GRUB -> Kernel. I dropped in a new 6.11 kernel as /bzImage, and booted the disk in a VM. Grub showed up, booted the kernel and off we went.
So, I updated grub.cfg, put the kernel on the disk as a new file, and rebooted. It booted the normal kernel, not my modified kernel. Clearly it's not parsing the grub.cfg, so I swapped out the symlink at /bzImage to point at my new kernel:
In verify_kernel_sig Chksum: final image size: 18126516 plat: 1 Debug: bl_sz: 109024 After: buf_len: 2048 After KEY_InitMem reading key: 0 reading key: 1 reading key: 2 reading key: 3 reading key: 4 reading key: 5 After karr After 2: buf_len: 2048 sig len : 172 in verifysignature_md5, MD5 hash generated now:02x02x02x02x02x02x02x02x02x02x02 x02x02x02x02x02x in verifysignature_md5, MD5 hash generated now, str format:hexmd5:ffce7129487a7 4b3e6f1651ff8b34311 calling RSA_eay decrypt now got value i:33 verifysignature_md5, Orig MD5 hash generated during encryption:d5cba1e2b4c5ea87 857acfdedc5313a7calling RSA_eay decrypt now got value i:-1 verifysignature_md5, Orig MD5 hash generated during encryption:d5cba1e2b4c5ea87 857acfdedc5313a7calling RSA_eay decrypt now got value i:-1 verifysignature_md5, Orig MD5 hash generated during encryption:d5cba1e2b4c5ea87 857acfdedc5313a7calling RSA_eay decrypt now got value i:-1 verifysignature_md5, Orig MD5 hash generated during encryption:d5cba1e2b4c5ea87 857acfdedc5313a7calling RSA_eay decrypt now got value i:-1 verifysignature_md5, Orig MD5 hash generated during encryption:d5cba1e2b4c5ea87 857acfdedc5313a7calling RSA_eay decrypt now got value i:-1 verifysignature_md5, Orig MD5 hash generated during encryption:d5cba1e2b4c5ea87 857acfdedc5313a7 signatures do not match... Invalid Kernel Signature !!! Rebooting�
Hrm.
My kernel was a bit bigger (18MiB vs 2MiB) so I slimmed down the kernel to no avail. I ended up just hex editing the build string of the original kernel s/cisco.com/cisco.sux/, which allowed it to boot on the VM, but it failed on the real system.
Clearly the kernel was being cryptographically verified in some way, the log entries weren't just to scare me off (unlike some of Cisco's new products). [merakiuart]
So, I dumped /dev/mtd0 and, (after some help from the6p4c to get everything in the right place) loaded it into Ghidra.
Breaking the bars
I was able to make enough sense of the code that the boot flow is roughly:
- BIOS, "Booting from flash"
- 16-bit bootloader init code (@ 7600h)
- 32-bit bootloader code (@ 8000h)
- PCI Init, scans for a particular string on the chipset to detect if it's running on an AIM- or NM- module
- Reads the bootloader config from flash (mtd1 perhaps?)
- Presents the boot prompt ("Please enter '***' to change boot configuration:"), handles the menu etc.
- Builds a GRUB (-style?) command list, and runs functions to handle them (possibly just GRUB linked into the binary?)
- root (hd0,0)
- kernel (hd0,0)/bzImage root=/dev/hda1 ro plat=nm
- Detect and mount the file system, load the kernel and verify it
- boot
- Does some voodoo to jump into the kernel
After a lot of fumbling around, naming functions and variables, I found the part we'd need to change:
kern_image_size = verifysignature_md5(buf + 1,0x10,(char *)keyring,uVar4,kern_image_size); if (kern_image_size == 0) { printf("Invalid Kernel Signature !!!\n",uVar3,pbVar2,pbVar5); printf("Rebooting\n"); open_file_anyFS?(extraout_ECX_00); ??reset_82c3(); } else { printf("Kernel signature verified successfully\n",uVar3,pbVar2,pbVar5); }
Here's what that looked like in the code listing (disassembly) window:
000090e2 e8 2f b4 CALL verifysignature_md5 int verifysignature_md5(byte * h 00 00 000090e7 89 c3 MOV EBX,buf_len 000090e9 83 c4 20 ADD ESP,0x20 000090ec 85 db TEST EBX,EBX 000090ee 74 12 JZ LAB_00009102 000090f0 83 ec 0c SUB ESP,0xc 000090f3 68 e0 f1 PUSH s_Kernel_signature_verified_succes_0001f1e0 = "Kernel signature verified suc 01 00 000090f8 e8 7f 1f CALL printf void printf(char * format, ...) 00 00 000090fd 83 c4 10 ADD ESP,0x10 00009100 eb 24 JMP LAB_00009126 LAB_00009102 XREF[1]: 000090ee(j) 00009102 83 ec 0c SUB ESP,0xc 00009105 68 08 f2 PUSH s_Invalid_Kernel_Signature_!!!_0001f208 = "Invalid Kernel Signature !!!\n" 01 00 0000910a e8 6d 1f CALL printf void printf(char * format, ...) 00 00
Knowing a small amount of Z80 machine code / assembly, which is a cousin of x86, here's what's going on:
- Call (jump to and come back here on a RET instruction) verifysignature_md5
- Move the contents of buf_len into register EBX
- Add 0x20 to the stack pointer
- Bitwise AND EBX & EBX and set the Zero Flag if the result is zero
- This is how you do "if (EBX >= 1)" in x80-style assembly
- Jump, if the zero flag is set, +0x12 bytes forward, to LAB_00009102
By only changing one instruction we can always succeed - if we convert the JZ instruction to a no-op (NOP), it won't jump to the failure part of the code and it should carry on regardless.
We could perhaps disable the check entirely, but it's harder to know if the process of doing the check loads the kernel into memory, or sets some global states that we don't understand.
I used Ghidra's "Patch Instruction" tool on the JZ line. You first have to clear the value (the destination in this example) but then you can type in NOP in the left section, and Ghidra will pick the right bytes to put in.
We end up with this:
000090e7 89 c3 MOV EBX,buf_len 000090e9 83 c4 20 ADD ESP,0x20 000090ec 85 db TEST EBX,EBX 000090ee 66 90 NOP 000090f0 83 ec 0c SUB ESP,0xc 000090f3 68 e0 f1 PUSH s_Kernel_signature_verified_succes_0001f1e0 = "Kernel signature verified suc 01 00 000090f8 e8 7f 1f CALL printf void printf(char * format, ...) 00 00 000090fd 83 c4 10 ADD ESP,0x10 00009100 eb 24 JMP LAB_00009126
Clearly only the 000090ee line has changed, but the disassembly now looks like this:
verifysignature_md5(buf + 1,0x10,(char *)keyring,uVar5,kern_image_size); printf("Kernel signature verified successfully\n"); }
Now I need to test it. I didn't have any luck emulating the bootloader, so I edited the raw bootloader binary, and imported it into Ghidra as a new file to make sure I hadn't broken it. It looked fine.
As the firmware was on /dev/mtd0, this meant I couldn't just dd if=firmware.bin of=/dev/mtd0. Linux's MTD code abstracts away most of the nuances of talking to Memory Technology Devices (e.g. flash) when there's no controller. There is still one main limitation in that you have to erase a block before you write it.
Thankfully, the original OS image already had a tool to do that. /usr/local/bin/eraseall /dev/mtd0 simply erased all of the blocks in mtd0, ready for writing.
Now I could dd if=firmware.bin of=/dev/mtd0, and reboot.
With my fingers crossed, I rebooted the card from the router, just in case a normal OS reboot wasn't enough.
The system booted fine!
I shuffled the symlink at /bzImage around to point to my cisco.sux kernel, and rebooted once again...
In verify_kernel_sig Chksum: final image size: 900958 plat: 1 Debug: bl_sz: 109024 After: buf_len: 2048 After KEY_InitMem reading key: 0 reading key: 1 reading key: 2 reading key: 3 reading key: 4 reading key: 5 After karr After 2: buf_len: 2048 sig len : 172 in verifysignature_md5, MD5 hash generated now:02x02x02x02x02x02x02x02x02x02x02 x02x02x02x02x02x in verifysignature_md5, MD5 hash generated now, str format:hexmd5:2dc51fa8e3008 edb9edc8df75b56f99b calling RSA_eay decrypt now got value i:33 verifysignature_md5, Orig MD5 hash generated during encryption:d5cba1e2b4c5ea87 857acfdedc5313a7calling RSA_eay decrypt now got value i:-1 verifysignature_md5, Orig MD5 hash generated during encryption:d5cba1e2b4c5ea87 857acfdedc5313a7calling RSA_eay decrypt now got value i:-1 verifysignature_md5, Orig MD5 hash generated during encryption:d5cba1e2b4c5ea87 857acfdedc5313a7calling RSA_eay decrypt now got value i:-1 verifysignature_md5, Orig MD5 hash generated during encryption:d5cba1e2b4c5ea87 857acfdedc5313a7calling RSA_eay decrypt now got value i:-1 verifysignature_md5, Orig MD5 hash generated during encryption:d5cba1e2b4c5ea87 857acfdedc5313a7calling RSA_eay decrypt now got value i:-1 verifysignature_md5, Orig MD5 hash generated during encryption:d5cba1e2b4c5ea87 857acfdedc5313a7 psignatures do not match... Kernel signature verified successfully In load_imagea1 In load_imagea2 Dbg ********* filemax/data_len/SECSIZ: 900958/2560/512 [Linux-bzImage, setup=0xa00, size=0xdb35e] kernel_func: kt: 3 in boot func: kt: 3 Linux version 2.4.21 (root@namlab-pc6.cisco.com) (gcc version 2.96 20000731 (Red Hat Linux 7.2 2.96-112.7.1)) #9 SMP Wed Jul 30 16:30:10 PDT 2003
Success! The system was now booting a modified kernel.
The issue was however, the bootloader could only load Linux 2.4 and very very early 2.6 kernels. Anything newer would end up trapping into the BIOS debugger, which is a hilarious failure state.
Breaking in to break out
I was able to locate an update package for the NM-CUE that shipped with a 2.6.11-ish kernel. I flashed it and was able to confirm that the original kernel from the NM-NAM and the new NM-CUE kernel booted.
I now had to "port" my patch to the new version. Problem is that the code that Ghidra could understand no longer did the verification, but the kernel was still being verified..?
Long story short, Cisco moved the code around, so now the process is something like this:
- BIOS, "Booting from flash"
- 16-bit bootloader init code (@ 7600h)
- 32-bit bootloader code (@ 8000h)
- PCI Init, scans for a particular string on the chipset to detect if it's running on an AIM- or NM- module
- Reads the bootloader config from flash (mtd1 perhaps?)
- Presents the boot prompt ("Please enter '***' to change boot configuration:"), handles the menu etc.
- Builds a GRUB (-style?) command list, and runs functions to handle them (possibly just GRUB linked into the binary?)
- root (hd0,0)
- kernel (hd0,0)/bzImage root=/dev/hda1 ro plat=nm
- Detect and mount the file system, load the kernel into memory
- boot
- Does some voodoo, loads an embedded ELF and jumps into it
- ELF #1
- Verifies the kernel image, jumps into ELF #2
- ELF #2
- Some weird voodoo (moving the bzImage sections around for the Linux boot code to work propery?)
Ghidra didn't like the idea of the embedded ELFs, so I used binwalk to pull them out (before I knew they were ELFs):
binwalk nm+aim_bl_2.1.14 DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 1026 0x402 LZMA compressed data, properties: 0x9A, dictionary size: 0 bytes, uncompressed size: 207 bytes 94032 0x16F50 ELF, 32-bit LSB executable, Intel 80386, version 1 (SYSV) 152681 0x25469 ELF, 32-bit LSB executable, Intel 80386, version 1 (SYSV) file _nm+aim_bl_2.1.14.extracted/* _nm+aim_bl_2.1.14.extracted/16F50: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped _nm+aim_bl_2.1.14.extracted/25469: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped _nm+aim_bl_2.1.14.extracted/402: data _nm+aim_bl_2.1.14.extracted/402.7z: OpenPGP Public Key
Wait...
ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped
sickos.jpg
Thanks Cisco!
That makes figuring out the jailbreak a tonne easier (that and an ELF is much easier for Ghidra to understand than a raw flash image). Loading it up, I didn't have to change anything, I could just poke around and find it:
printf("sig len : %d\n",iVar3 + -1); iVar3 = VerifySignature_MD5(param_1 + 3,0x10,&swv_key_buf,iVar3 + -1,uVar1); if (iVar3 != 0) { printf("Kernel signature verified successfully\n"); return iVar3; } printf("Invalid Kernel Signature !!!\n"); return 0;
Applying the same patch...
01001486 85 c0 TEST EAX,EAX 01001488 89 c3 MOV EBX,EAX 0100148a 74 16 JZ LAB_010014a2 0100148c c7 04 24 MOV dword ptr [ESP]=>local_2c,s_Kernel_signature_v = "Kernel signature verified suc 88 b6 00 01 01001493 e8 38 ec CALL printf int printf(char * __format, ...) ff ff
to
01001486 85 c0 TEST EAX,EAX 01001488 89 c3 MOV EBX,EAX 0100148a 66 90 NOP 0100148c c7 04 24 MOV dword ptr [ESP]=>local_2c,s_Kernel_signature_v = "Kernel signature verified suc 88 b6 00 01 01001493 e8 38 ec CALL printf int printf(char * __format, ...) ff ff
I flashed it the same way as before, and the system still booted. I swapped in my patched kernel again, and it too worked fine!
Adding more layers to the onion
Now I had a newer, unlocked, bootloader that ... still couldn't load Linux 6.11. With a bit of trial and error, I was able to boot versions of Linux up to and including 2.6.22. [2.6.23changes]
Guess what was added in ~2.6.16?
Kexec for i386!
To skip a very long sidetrack that went down many dead ends, I was able to build a Linux 2.6.22 system. The constraints I had were:
- Bootloader requires Linux 2.6.22
- Linux 2.6.22 is only supported by a small number of glibc versions (and those versions suck to compile)
- Linux 2.6.22 is supported by musl 1.1.x, as 1.2.x uses 64-bit time
- Buildroot last shipped musl 1.1.x in it's 2020.02 release
- Busybox in Buildroot 2020.02 needs network, i2c, mdev and privilege applets / functions turned off to build
- Kexec in Buildroot 2020.02 is too new to build, but we can build a slightly older version
- A version of kexec released around the same time as Linux 2.6.22 doesn't build with musl libc.
- Buildroot 2020.02 still builds on a Debian 12 system perfectly happily, but can't build Linux 2.6.22, so we need to build the kernel in a Debian 4 container
- We want to embed the root filesystem into the kernel image as an initramfs
- The whole bzImage needs to be less than about 15 MiB else the bootloader gets confused
- We want to get to a fully featured set of drivers reasonably quickly, but building network or filesystem tools for such an old kernel is difficult, doubly so when you consider the size constraints.
The result is the following boot flow:
- BIOS (stage0)
- Bootloader 16-bit code (stage1)
- Bootloader 32-bit prep code (stage2)
- Bootloader ELF #1 verification code (stage3)
- Bootloader ELF #2 Linux relocation code (stage4)
- New! Linux 2.6.22 with embedded initramfs (stage5), which includes the next item in it's initramfs and kexec's it:
- New! Linux 6.11.5 with full HDD, ext4, network, HTTP support (stage6)
I'm still wrapping up the scripting for stage6 to automatically boot from disk / network based on a config file, but stage5 is done and it's quite quick. stage5 only takes about 2 seconds to init before it starts loading the stage6 kernel.
Now we've "melted the jail bars" and escaped Scott free from the jail, right?
Right???
TODO
So far we've managed to ""port"" modern Linux to this system, but like most ""ports"" there's always a few things missing.
- The stock kernels had support for the MTD flash
- I tried some basic prodding but no luck so far
- This means we can't update the bootloader, or read the settings from the flash
- The stock kernels have a cisco_rbcp.ko module
- This, along with a rbcpd daemon, communicates with the host router and allows Linux to see some information about where it is, and allows the router to see some status information.
- It also facilitates a watchdog feature, and the host router may reboot the card if it doesn't show up.
- In my Cisco 2620, the reboots are infrequent, in my 3745 it reboots approximately every 8 minutes.
- "Trying to shutdown Service Module Analysis-Module1/0"
- "Trying to reset Service Module Analysis-Module1/0"
Links
- The unlocked bootloader image
- The patch for the bootloader
- My Gitlab repo containing the buildroot external tree
[merakiuart] | Accessing the internal UART of a Cisco Meraki device usually gets a message like this printed out: "WARNING! THIS CONSOLE IS LOGGED! UNAUTHORIZED ACCESS FORBIDDEN!" It doesn't seem to be logged: https://leo.leung.xyz/wiki/Meraki_MS220-8P#Boot_Process_Overview |
[2.6.23changes] | The boot code in 2.6.23 was rewritten in C instead of assembly: https://kernelnewbies.org/Linux_2_6_23#Rewrite_the_x86_asm_setup_in_C |