[Note to english speaking readers, aggregating this blog: The following article is written in german about gaining root on a piece of embedded server monitor hardware from Rittal and configuring ssh access. If there is demand, I'll translate this article in english as well.]
Ich hatte zuvor ja schon hier und hier ein wenig über das Rittal CMC-TC System gesprochen, dass wir verwenden um unseren Serverschrank zu überwachen.
Das System selber ist soweit ja sehr schön, und hat auch ein paar nette Features, aber leider fehlt z.B. der ssh Zugang. Telnet anzubieten ist doch schon ein wenig schwach heutzutage. Das ganze wäre ja kein Problem, würde Rittal sich an die GPL Lizenz halten, und mir den Sourcecode und die Buildumgebung zur Verfügung stellen, die gebraucht wird um sich einen eigenen sshd zu installieren.
Nunja, mal schauen was das noch wird.
Nun will ich aber dennoch einen ssh Daemon auf dem Gerät haben, was sich auch nicht als sonderlich kompliziert rausstellt. Man muss das Gerät nur booten und den vorhandenen sshd starten.
Aber fangen wir vorne an.
Schauen wir uns also mal die Bootmeldungen an:
U-Boot 1.1.3 (Jun 8 2005 - 15:08:40)
U-Boot code: 20F00000 -> 20F1A868 BSS: -> 20F1EE48
RAM Configuration:
Bank #0: 20000000 16 MB
Board: CMC-PU2 (Rittal GmbH)
Flash: 8 MB
In: serial
Out: serial
Err: serial
Hit any key to stop autoboot: 0
no DHCP
## Booting image at 10030000 ...
Image Name: ARM Linux-2.4.27
Created: 2005-04-22 4:52:03 UTC
Image Type: ARM Linux Kernel Image (gzip compressed)
Data Size: 698499 Bytes = 682.1 kB
Load Address: 20008000
Entry Point: 20008000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
Starting kernel ...
Linux version 2.4.27-vrs1 (mkr@s020403) (gcc version 2.95.4 20010319 (prerelease/franzo/20011204)) #2
Fri Apr 22 06:49:12 CEST 2005
CPU: Arm920Tid(wb) revision 0
Machine: ATMEL AT91RM9200
On node 0 totalpages: 4096
zone(0): 4096 pages.
zone(1): 0 pages.
zone(2): 0 pages.
Kernel command line: root=/dev/mtdblock3 ro ethaddr=00:d0:93:12:34:56 ip=192.168.0.190::::
CMC-TC-PU2::off console=ttyS0,9600
mtdparts=cmc_pu2:128k(uboot)ro,64k(environment),768k(linux),4096k(root),-
Calibrating delay loop... 89.70 BogoMIPS
Memory: 16MB = 16MB total
Memory: 14452KB available (1382K code, 275K data, 60K init)
Dentry cache hash table entries: 2048 (order: 2, 16384 bytes)
Inode cache hash table entries: 1024 (order: 1, 8192 bytes)
Mount cache hash table entries: 512 (order: 0, 4096 bytes)
Buffer cache hash table entries: 1024 (order: 0, 4096 bytes)
Page-cache hash table entries: 4096 (order: 2, 16384 bytes)
CPU: Testing write buffer: pass
POSIX conformance testing by UNIFIX
Linux NET4.0 for Linux 2.4
Based upon Swansea University Computer Society NET3.039
Initializing RT netlink socket
Starting kswapd
Installing knfsd (copyright (C) 1996 okir@monad.swb.de).
JFFS2 version 2.1. (C) 2001 Red Hat, Inc., designed by Axis Communications AB.
RAMDISK driver initialized: 16 RAM disks of 8192K size 1024 blocksize
Amd/Fujitsu Extended Query Table v1.3 at 0x0040
number of CFI chips: 1
cfi_cmdset_0002: Disabling fast programming due to code brokenness.
Creating 5 MTD partitions on "CMC PU2 flash":
0x00000000-0x00020000 : "uboot"
0x00020000-0x00030000 : "environment"
0x00030000-0x000f0000 : "linux"
0x000f0000-0x004f0000 : "root"
0x004f0000-0x00800000 : "Partition_004"
i2c-core.o: i2c core module version 2.6.1 (20010830)
i2c-dev.o: i2c /dev entries driver module version 2.6.1 (20010830)
ttyS0 at MMIO 0xfefc0000 (irq = 6) is a AT91_SERIAL
ttyS1 at MMIO 0xfefc4000 (irq = 7) is a AT91_SERIAL
ttyS2 at MMIO 0xfefc8000 (irq = 8) is a AT91_SERIAL
ttyS3 at MMIO 0xfefcc000 (irq = 9) is a AT91_SERIAL
ttyS4 at MMIO 0xfefff200 (irq = 1) is a AT91_SERIAL
eth0: Link now 100-FullDuplex
eth0: AT91 ethernet at 0xfefbc000 int=24 100-FullDuplex (00:d0:93:12:34:56)
eth0: Davicom 9196 PHY (Copper)
AT91 Watchdog Timer enabled (5 seconds)
Found AT91 i2c
I2C: RS5C372 RTC driver successfully loaded
CMC buzzer driver $Revision: 0.2 $
CMC digital IO driver $Revision: 0.2 $
Serial driver version 0.03 (2004-12-17) with no serial options enabled
ttyS5 at 0xc2084000 (irq = 29) is a TI16752
ttyS6 at 0xc2086000 (irq = 30) is a TI16752
NET4: Linux TCP/IP 1.0 for NET4.0
IP Protocols: ICMP, UDP, TCP
IP: routing cache hash table of 512 buckets, 4Kbytes
TCP: Hash tables configured (established 1024 bind 1024)
eth0: Link now 100-FullDuplex
IP-Config: Guessing netmask 255.255.255.0
IP-Config: Complete:
device=eth0, addr=192.168.0.190, mask=255.255.255.0, gw=255.255.255.255,
host=CMC-TC-PU2, domain=, nis-domain=(none),
bootserver=255.255.255.255, rootserver=255.255.255.255, rootpath=
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
NetWinder Floating Point Emulator V0.97 (double precision)
VFS: Mounted root (cramfs filesystem) readonly.
Freeing init memory: 60K
serial console detected. Disabling virtual terminals.
init started: BusyBox v0.60.2 (2002.10.10-17:17+0000) multi-call binary
eth0: ROVR error
eth0: ROVR error
Startup CMC
no update..
CMC Applications
rs422, Version: V2.00, Build Date: Mon Sep 19 18:01:58 2005
eeprom, Version: V2.00, Build Date: Mon Sep 19 18:00:03 2005
rs232, Version: V2.00, Build Date: Mon Sep 19 18:39:00 2005
CMC-TC-PU2 Thu Jan 1 1970 00:00:15, User 0
CMC-TC-PU2 login: VCC status = OK
cmc_main, Version: V2.15, Build Date: Wed Nov 16 15:20:38 2005
No Options..
Setting up clock 18:03:30 15.06.2006
CMC-TC-PU2 Thu Jun 15 2006 18:03:35, User 0
CMC-TC 192.168.0.190 login:
Eindeutig. Ein Linux mit einer BusyBox Shell. Eine im Embedded-Bereich sehr verbreitete Kombination. In diesem Fall leider ein Lizenzverstoss.
Jetzt stellt sich die Frage, wie man root wird. Als Login hat man naemlich nur cmc und admin zur Verfügung, die beide normale Useraccounts sind und anstelle einer Shell ein fertiges Menü starten.
Im Nachhinein, nachdem man sich auf dem Gerät umgeschaut hat, fallen mir verschiedene Möglichkeiten ein, aber die einfachste ist dem Bootloader zu sagen, dass ich gerne eine Shell hätte.
Mehr Details gibt es im Rest des Artikels.
Da das Gerät selber keinen Root-Zugang bietet, muss man sich zuerst einen "organisieren".
Dies geschieht am einfachsten durch Verbinden der Seriellen Console an der Processing Unit II mit einem Rechner. Nach dem Einschalten sieht man mit dem Terminal-Programm dann folgendes:
U-Boot 1.1.3 (Jun 8 2005 - 15:08:40)
U-Boot code: 20F00000 -> 20F1A868 BSS: -> 20F1EE48
RAM Configuration:
Bank #0: 20000000 16 MB
Board: CMC-PU2 (Rittal GmbH)
Flash: 8 MB
In: serial
Out: serial
Err: serial
Hit any key to stop autoboot: 1
Hier drücken wir dann eine beliebige Taste (schnell sein!) und befinden uns am Prompt des
U-Boot Bootloaders für (unter anderem)
Arm Systeme.
Die Eingabe von
help zeigt und eine grosse Liste von Befehlen:
=> help
? - alias for 'help'
autoscr - run script from memory
base - print or set address offset
bdinfo - print Board Info structure
boot - boot default, i.e., run 'bootcmd'
bootd - boot default, i.e., run 'bootcmd'
bootm - boot application image from memory
bootp - boot image via network using BootP/TFTP protocol
cmp - memory compare
coninfo - print console devices and information
cp - memory copy
crc32 - checksum calculation
date - get/set/reset date & time
dhcp - invoke DHCP client to obtain IP/boot params
echo - echo args to console
eeprom - EEPROM sub-system
erase - erase FLASH memory
flinfo - print FLASH memory information
go - start application at address 'addr'
help - print online help
icrc32 - checksum calculation
iloop - infinite loop on address range
imd - i2c memory display
iminfo - print header information for application image
imls - list all images found in flash
imm - i2c memory modify (auto-incrementing)
imw - memory write (fill)
inm - memory modify (constant address)
iprobe - probe to discover valid I2C chip addresses
itest - return true/false on integer compare
loadb - load binary file over serial line (kermit mode)
loads - load S-Record file over serial line
loop - infinite loop on address range
md - memory display
mm - memory modify (auto-incrementing)
mtest - simple RAM test
mw - memory write (fill)
nfs - boot image via network using NFS protocol
nm - memory modify (constant address)
printenv- print environment variables
protect - enable or disable FLASH write protection
rarpboot- boot image via network using RARP/TFTP protocol
reset - Perform RESET of the CPU
run - run commands in an environment variable
saveenv - save environment variables to persistent storage
setenv - set environment variables
sntp - synchronize RTC via network
tftpboot- boot image via network using TFTP protocol
version - print monitor version
=>
Interessante Befehle sind z.B. bdinfo, imls, flinfo und printenv. Mehr Informationen zu den Befehlen gibt es auf im DULG Wiki.
=> bdinfo
arch_number = 0x000000FB
env_t = 0x00000000
boot_params = 0x20000100
DRAM bank = 0x00000000
-> start = 0x20000000
-> size = 0x01000000
ethaddr = 00:d0:93:12:34:56
ip_addr = 192.168.0.190
baudrate = 9600 bps
=> imls
Image at 10030000:
Image Name: ARM Linux-2.4.27
Created: 2005-04-22 4:52:03 UTC
Image Type: ARM Linux Kernel Image (gzip compressed)
Data Size: 698499 Bytes = 682.1 kB
Load Address: 20008000
Entry Point: 20008000
Verifying Checksum ... OK
=> flinfo
Bank # 1: AMD S29GL064M-R6 (64Mbit, uniform sector size)
Size: 8 MB in 128 Sectors
Sector Start Addresses:
[...]
=> printenv
bootdelay=1
baudrate=9600
net_nfs=tftp $(loadaddr) $(bootfile);run nfsargs addip addcons addmtd;bootm
nfsargs=setenv bootargs root=/dev/nfs rw nfsroot=$(serverip):$(rootpath)
net_cramfs=tftp $(loadaddr) $(bootfile); run flashargs addip addcons addmtd; bootm
flash_cramfs=run flashargs addip addcons addmtd; bootm 10030000
flashargs=setenv bootargs root=/dev/mtdblock3 ro
addip=setenv bootargs $(bootargs) ethaddr=$(ethaddr) ip=$(ipaddr):$(serverip):$(gatewayip):$(netmask):$(hostname)::off
addcons=setenv bootargs $(bootargs) console=ttyS0,$(baudrate)
addmtd=setenv bootargs $(bootargs) mtdparts=cmc_pu2:128k(uboot)ro,64k(environment),768k(linux),4096k(root),-
load=tftp $(loadaddr) $(loadfile)
update=protect off 10000000 1001ffff;erase 10000000 1001ffff; cp.b $(loadaddr) 10000000 $(filesize);protect on
10000000 1001fupdatel=era 10030000 100effff;tftp $(loadaddr) $(bootfile); cp.b $(loadaddr) 10030000 $(filesize)
updatec=era 100f0000 104effff;tftp $(loadaddr) $(cramfsimage); cp.b $(loadaddr) 100f0000 $(filesize)
updatej=era 104f0000 107fffff;tftp $(loadaddr) $(jffsimage); cp.b $(loadaddr) 104f0000 $(filesize)
cramfsimage=cramfs_cmc-pu2.img
jffsimage=jffs2_cmc-pu2.img
loadfile=u-boot_cmc-pu2.bin
bootfile=uImage_cmc-pu2
loadaddr=0x20800000
hostname=CMC-TC-PU2
bootcmd=run dhcp_start;run flash_cramfs
autoload=n
dhcp_start=echo no DHCP
ipaddr=192.168.0.190
serial#=12345
ethaddr=00:d0:93:12:34:56
stdin=serial
stdout=serial
stderr=serial
Environment size: 1450/16380 bytes
Wie wir sehen ist gerade printenv ein sehr interessanter Befehl, enthält er doch sämtliche Laufzeitkonfigurationen des Bootloaders und auch die Kommandozeile des Kernels.
Um erstmal eine Shell auf dem Gerät zu bekommen, ändern wir also entsprechend die Variable "bootargs" bzw. die Variable "flashargs", die diese setzt und booten das Gerät.
=> setenv flashargs setenv bootargs root=/dev/mtdblock3 ro single
=> boot
Nun sollte das Gerät im Single User Mode booten.
Und tatsächlich, es läuft:
no DHCP
## Booting image at 10030000 ...
Image Name: ARM Linux-2.4.27
Created: 2005-04-22 4:52:03 UTC
Image Type: ARM Linux Kernel Image (gzip compressed)
Data Size: 698499 Bytes = 682.1 kB
Load Address: 20008000
Entry Point: 20008000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
Starting kernel ...
Linux version 2.4.27-vrs1 (mkr@s020403) (gcc version 2.95.4 20010319 (prerelease/franzo/20011204)) #2
Fri Apr 22 06:49:12 CE5CPU: Arm920Tid(wb) revision 0
Machine: ATMEL AT91RM9200
On node 0 totalpages: 4096
zone(0): 4096 pages.
zone(1): 0 pages.
zone(2): 0 pages.
Kernel command line: root=/dev/mtdblock3 ro single ethaddr=00:d0:93:12:34:56 ip=192.168.0.190::::
CMC-TC-PU2::off console=tty-Calibrating delay loop... 89.70 BogoMIPS
Memory: 16MB = 16MB total
Memory: 14452KB available (1382K code, 275K data, 60K init)
Dentry cache hash table entries: 2048 (order: 2, 16384 bytes)
Inode cache hash table entries: 1024 (order: 1, 8192 bytes)
Mount cache hash table entries: 512 (order: 0, 4096 bytes)
Buffer cache hash table entries: 1024 (order: 0, 4096 bytes)
Page-cache hash table entries: 4096 (order: 2, 16384 bytes)
CPU: Testing write buffer: pass
POSIX conformance testing by UNIFIX
Linux NET4.0 for Linux 2.4
Based upon Swansea University Computer Society NET3.039
Initializing RT netlink socket
Starting kswapd
Installing knfsd (copyright (C) 1996 okir@monad.swb.de).
JFFS2 version 2.1. (C) 2001 Red Hat, Inc., designed by Axis Communications AB.
RAMDISK driver initialized: 16 RAM disks of 8192K size 1024 blocksize
Amd/Fujitsu Extended Query Table v1.3 at 0x0040
number of CFI chips: 1
cfi_cmdset_0002: Disabling fast programming due to code brokenness.
Creating 5 MTD partitions on "CMC PU2 flash":
0x00000000-0x00020000 : "uboot"
0x00020000-0x00030000 : "environment"
0x00030000-0x000f0000 : "linux"
0x000f0000-0x004f0000 : "root"
0x004f0000-0x00800000 : "Partition_004"
i2c-core.o: i2c core module version 2.6.1 (20010830)
i2c-dev.o: i2c /dev entries driver module version 2.6.1 (20010830)
ttyS0 at MMIO 0xfefc0000 (irq = 6) is a AT91_SERIAL
ttyS1 at MMIO 0xfefc4000 (irq = 7) is a AT91_SERIAL
ttyS2 at MMIO 0xfefc8000 (irq = 8) is a AT91_SERIAL
ttyS3 at MMIO 0xfefcc000 (irq = 9) is a AT91_SERIAL
ttyS4 at MMIO 0xfefff200 (irq = 1) is a AT91_SERIAL
eth0: Link now 100-FullDuplex
eth0: AT91 ethernet at 0xfefbc000 int=24 100-FullDuplex (00:d0:93:12:34:56)
eth0: Davicom 9196 PHY (Copper)
AT91 Watchdog Timer enabled (5 seconds)
Found AT91 i2c
I2C: RS5C372 RTC driver successfully loaded
CMC buzzer driver $Revision: 0.2 $
CMC digital IO driver $Revision: 0.2 $
Serial driver version 0.03 (2004-12-17) with no serial options enabled
ttyS5 at 0xc2084000 (irq = 29) is a TI16752
ttyS6 at 0xc2086000 (irq = 30) is a TI16752
NET4: Linux TCP/IP 1.0 for NET4.0
IP Protocols: ICMP, UDP, TCP
IP: routing cache hash table of 512 buckets, 4Kbytes
TCP: Hash tables configured (established 1024 bind 1024)
eth0: Link now 100-FullDuplex
IP-Config: Guessing netmask 255.255.255.0
IP-Config: Complete:
device=eth0, addr=192.168.0.190, mask=255.255.255.0, gw=255.255.255.255,
host=CMC-TC-PU2, domain=, nis-domain=(none),
bootserver=255.255.255.255, rootserver=255.255.255.255, rootpath=
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
NetWinder Floating Point Emulator V0.97 (double precision)
VFS: Mounted root (cramfs filesystem) readonly.
Freeing init memory: 60K
serial console detected. Disabling virtual terminals.
init started: BusyBox v0.60.2 (2002.10.10-17:17+0000) multi-call binary
BusyBox v0.60.2 (2002.10.10-17:39+0000) Built-in shell (msh)
Enter 'help' for a list of built-in commands.
#
Jetzt ist erst einmal ein guter Zeitpunkt um ein Backup des Systems zu erstellen, falls wir nachher was kaputtmachen sollten.
Wie im Kernel Bootlog ersichtlich, gibt es 5 "Partitionen" im Flash:
Device |
Größe |
Blocksize |
Name |
Bedeutung |
/dev/mtdblock0 |
0002000 |
0001000 |
uboot |
Das Abbild des U-Boot Bootloaders |
/dev/mtdblock1 |
0001000 |
0001000 |
environment |
Der Speicherbereich der U-Boot Konfiguration, dies sind die Daten, die wir weiter oben mit printenv angezeigt hatten. |
/dev/mtdblock2 |
000c000 |
0001000 |
linux |
Das mit gzip gepackte Linux PPC Kernel-Abbild |
/dev/mtdblock3 |
0040000 |
0001000 |
root |
Die Root-Partition des Filesystems |
/dev/mtdblock4 |
0031000 |
0001000 |
Partition_004 |
Das Home-Dir und andere Konfigurations-Daten, die ein Update des Systems überleben sollten. |
Für das Backup müssen die Blockdevices mit
cat ausgelesen und anschliessend in eine normale Datei gepiped werden. Diese Files können dann irgendwohin kopiert werden. Dafür bietet sich z.B.
/usr/bin/sz an, um die Daten direkt über die Serielle Console per
Z-Modem zu kopieren.
Das ist zwar ein wenig langsam, da die Verbindung nur mit 9600bps betrieben wird, aber es ist halt installiert.
# mount none -t tmpfs /tmpfs/
# cd /tmpfs
# cat /dev/mtdblock0 > /tmpfs/mtdblock0
# /usr/bin/sz -b /tmpfs/mtdblock0
**B00
[Jetzt das File per Z-Modem empfangen]
# rm -f /tmpfs/mtdblock0
# cat /dev/mtdblock1 > /tmpfs/mtdblock1
# /usr/bin/sz -b /tmpfs/mtdblock1
**B00
[Jetzt das File per Z-Modem empfangen]
# rm -f /tmpfs/mtdblock1
# cat /dev/mtdblock2 > /tmpfs/mtdblock2
# /usr/bin/sz -b /tmpfs/mtdblock2
**B00
[Jetzt das File per Z-Modem empfangen]
# rm -f /tmpfs/mtdblock2
# cat /dev/mtdblock3 > /tmpfs/mtdblock3
# /usr/bin/sz -b /tmpfs/mtdblock3
**B00
[Jetzt das File per Z-Modem empfangen]
# rm -f /tmpfs/mtdblock3
# cat /dev/mtdblock4 > /tmpfs/mtdblock4
# /usr/bin/sz -b /tmpfs/mtdblock4
**B00
[Jetzt das File per Z-Modem empfangen]
# rm -f /tmpfs/mtdblock4
Damit sind jetzt Backups vorhanden, die im Notfall wieder eingespielt werden können.
Der nächste Schritt ist sehr einfach, da die notwendige Software wie dropbear schon installiert ist und nur noch entsprechend konfiguriert werden muss:
- Neue SSH-Host-Keys erzeugen:
- Das aktuelle Dropbear Release ziehen und kompilieren, damit das Programm dropbearkeys zum Erzeugen der Keys genutzt werden kann.
Alternativ einfach die dropbearkey executable ziehen, die für i386 kompiliert ist.
- ./dropbearkey -t rsa -f dropbear_rsa_host_key aufrufen
- ./dropbearkey -t dss -f dropbear_dss_host_key aufrufen
- SSH-Host-Keys übertragen:
- Startup-Skripte anpassen:
- /jffs/home/start.sh editieren und das Kommentarzeichen vor der Zeile mit dem Dropbear aufruf entfernen. Hierfür eignet sich z.B. vi sehr gut, da es auf dem Gerät bereits installiert ist.
Anschliessend sieht die Datei wie folgt aus:
span style="color: #666666; font-style: italic;">#!/bin/sh
#11.04.2005
#last update 15.11.05
"Startup CMC"# Start von eigenen Applikationen
- Bei Bedarf kann nun der telnet Login deaktiviert werden. Hierzu muss /jffs/etc/xinet.d/telnet mit vi editiert werden, und die Zeile disable = no auf "yes" gesetzt werden:
span style="color: #666666; font-style: italic;"># description: The telnet server serves telnet sessions; it uses \
# unencrypted username/password pairs for authentication.
Für zukünftige Änderungen kann man sich auch noch einen Rootaccount mit einem bekannten Passwort anlegen um sich direkt per SSH auf dem Gerät einloggen zu können:
- Einen MD5 String mit dem verschlüsselten Password erzeugen. Dies geht z.B. mit folgendem Programm:
#define _XOPEN_SOURCE#include <unistd.h>#include <stdio.h>int main
(int argc,
char *argv
[]) { if (argc !=
2) { {FNAMEL}.html">printf("%s <password>\n", argv
[0]);
} else { {FNAMEL}.html">printf("PWD: %s\n", crypt
(argv
[1],
"$1$SaERowiC$"));
}}
Kompiliert wird dies durch gcc -o crypt -lcrypt crypt.c und dann aufgerufen als ./crypt password
- Einfügen einer Zeile nach dem Muster myroot:<crypt-string>:0:0:root:/:/bin/sh nach /jffs/etc/passwd
Nun noch ein Reboot auslösen durch Aufrufen von
/sbin/reboot auf dem Gerät und man kann nach dem Booten per SSH darauf zugreifen.
Nächstes Mal wird dann erklärt, wie man dem Gerät ntp beibringt und den Webserver auch per https nutzen kann. Das ist nämlich auch schon alles installiert.
Und wie üblich gilt, Finger weg von dem Zeug, wenn man ungschickt ist, nix mit teuren Briefbeschwerern anfangen kann, Wert auf Garantie legt, unerfahren ist oder einfach nicht die JTAG-Kabel und Flash-Programmer hat um solch ein Gerät notfalls wieder mit neuer Firmware zu versehen, wenn man sich vertippt hat.