diff --git a/README.md b/README.md index ac7ff36..c7666f7 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,48 @@ # Mikrotik netboot/initrd jailbreak -(C) Sergey Sergeev, 2019-2020 +(C) Sergey Sergeev, 2019-2021 All that you do is at your own risk! The author has not liable for any of you actions and their consequences! -This code is presented as is and is solely for educational purposes ONLY! +This code is presented as is and is solely for educational purposes ONLY! - +to investigate the internals of a Linux distro called RouterOS. +In particular, to facilitate porting OpenWRT to new Mikrotik devices. +For injection(jailbreak) to RouterOS is used the standard(for almost any Linux) +initrd mechanism. Native binary init file is replaced with a fake one. This modified +init forks itself (spawning its daemon copy) and then pass control to the original init +process. The begotten daemon copy waits for the filesystem to initialize and installs +busybox and then launch the telnetd service. To run Linux kernel with modified init file, +uses the standard RouterBOOT ability - loading via the network using dhcp/bootp and tftp +server. dhcp/bootp server can be deployed on another device with RouterOS and OpenWRT or +even tftp32 program. For a one-time launch with tftp, You can use this commands in RouterOS: + /system/routerboard/settings/set boot-device=try-ethernet-once-then-nand + /system/reboot -0) Use RouterOS 6.44 or 6.45.6 or 7.0b1! +and after that do the following: +0) Use RouterOS 6.44 or 6.45.6 or 7.x(7.1rc4)! 1) Upload(using FTP) content of ./for_ftp_upload/pub/* to /pub (or /flash or /flash/rw/disk/pub) folder on target RouterOS device 2) Netboot(via bootp and tftp) with kernel-new.elf 3) telnet x.x.x.x 22111 +Cyrillic: Все что вы делаете, вы делаете на свой страх и риск! Автор не несет никакой ответственности за ваши действия и их последствия! -Данный код представляется as-is и исключительно в учебных целях! +Данный код представляется as-is и исключительно в учебных целях - +для исследования внутреннего устройства дистрибутива Linux под названием +RouterOS. В частностия для для облегчения портирования OpenWRT на новые +устройства от Mikrotik. Для внедрения(jailbreak-а) в RouterOS используется +стандартный(практически для любого Linux-а) механизм initrd. Родной бинарный +файл init-а заменяется на поддельный. Этот измененный init форкает себя(порождая +свою копию-демона) и дальше передает управление родному init процессу. Порожденная +копия-демон ожидает инициализации файловой системы и запускает скрипт установки +busybox с последующим запуском telnetd сервиса. Для запуска ядра Linux с измененным +init файлом используется штатный механизм RouterBOOT - загрузка через сеть +с использованием dhcp/bootp и tftp сервера. dhcp/bootp сервером может выступать +как другое устройство с RouterOS так и OpenWRT или даже программа tftp32. +Для единоразового запуска с tftp вы можете выполнить следующие команды в RouterOS: + /system/routerboard/settings/set boot-device=try-ethernet-once-then-nand + /system/reboot For Developers: Place routeros-XXX.mpk to ./ros/ diff --git a/cpio-fs-aarch64/bin/busybox b/cpio-fs-aarch64/bin/busybox new file mode 100755 index 0000000..4bf7a1a Binary files /dev/null and b/cpio-fs-aarch64/bin/busybox differ diff --git a/cpio-fs-aarch64/bin/busybox.readme b/cpio-fs-aarch64/bin/busybox.readme new file mode 100644 index 0000000..217122b --- /dev/null +++ b/cpio-fs-aarch64/bin/busybox.readme @@ -0,0 +1 @@ +busybox скомпилен вот тут: /home/prog/openwrt/switch/mikrotik-tools-master/busybox-arm-soft-float diff --git a/cpio-fs-aarch64/init b/cpio-fs-aarch64/init new file mode 100755 index 0000000..a11f2fa Binary files /dev/null and b/cpio-fs-aarch64/init differ diff --git a/cpio-fs-aarch64/oldinit b/cpio-fs-aarch64/oldinit new file mode 100755 index 0000000..fbec3a8 Binary files /dev/null and b/cpio-fs-aarch64/oldinit differ diff --git a/cpio-fs-aarch64/readme.txt b/cpio-fs-aarch64/readme.txt new file mode 100644 index 0000000..ced3b38 --- /dev/null +++ b/cpio-fs-aarch64/readme.txt @@ -0,0 +1,3 @@ +binary files from routeros arm64 7.1rc4! +routeros needs armv7 compiler! +In fact, the entire user space in it is still use 32bit! \ No newline at end of file diff --git a/finder/finder.c b/finder/finder.c index 86a31dd..8b7cecf 100644 --- a/finder/finder.c +++ b/finder/finder.c @@ -23,7 +23,9 @@ static unsigned char data[64 * 1024 * 1024]; int main(int argc, char *argv[]){ int fd; unsigned char *p; - void *last_p; + void *last_p, *end; + size_t rest_size; + size_t total_payload_size = 0; int count = 0; size_t len; if(argc !=2) @@ -38,19 +40,42 @@ int main(int argc, char *argv[]){ die(-3); printf("Successfully readed %zd bytes\n", len); printf("Begin of search...\n"); - last_p = (void*)data; + end = (void*)data + len; + last_p = data; p = (void*)data; - p += 0x2F4D; + //p += 0x2F4D; do{ - if(p[4] == 0x7F && p[3] == 0xFF && p[2] == 0x80 && p[1] == 0x00 && p[0] == 0x00){ - //if(1){ - printf("%04d: 0x%08lx: %lu: %02X %02X %02X %02X %02X\n", count++, - ((void*)p - (void*)data), - (void*)p - last_p, p[4], p[3], p[2], p[1], p[0]); + if(*(uint64_t *)p == 0x040A000000010007LLU){ //check for kernel start magic value + printf("Kernel start magic is found at: 0x%08lx\n", (void*)data - (void*)p); last_p = p; + last_p = p = (void*)p + 15; } - p = (void *)p + 1; - }while((void*)p + sizeof(data[0]) - (void*)data < len); + + //chunk header(5 bytes) + //if(p[4] == 0x7F && p[3] == 0xFF && p[2] == 0x80 && p[1] == 0x00 && p[0] == 0x00){ + //if(p[4] == 0x7F && p[3] == 0xFF && p[0] == 0x00){ + if (p[0] == 0 || p[0] == 1) { + int prev_block_size = p != last_p ? ((void*)p - last_p) - 5 : 0; + int hdr_chunk_len = p[2] << 8 | p[1]; + total_payload_size += hdr_chunk_len; + if (prev_block_size != 0x8000 && last_p != p) + printf(" !!! Unusual chunk size: %d !!!\n", prev_block_size); + printf("%04d: 0x%08lx: (%d + 5): %02X %02X %02X %02X %02X\n", count++, + ((void*)p - (void*)data), hdr_chunk_len, + p[4], p[3], p[2], p[1], p[0]); + last_p = p; + rest_size = end - ((void*)p + 5 + hdr_chunk_len); + if (p[0] == 1) + break; + p += 5 + hdr_chunk_len; + } + //p = (void *)p + 1; + }while((void*)p + 4 < end); + p = end - rest_size; + //printf("Last tailed chunk size: %d + 5: [ %02x %02x ]\n", p[2] << 8 | p[1], p[1], p[2]); + printf("Payload total size is: %zd\n", total_payload_size); + printf("Garbage(tail) size is: %zd\n", rest_size); + printf("Total blocks is: %d\n", count); printf("...search is Ended\n"); return 0; } diff --git a/finder/kernel-extractor.c b/finder/kernel-extractor.c index 4f32198..a7a5732 100644 --- a/finder/kernel-extractor.c +++ b/finder/kernel-extractor.c @@ -10,19 +10,29 @@ void die(int code){ exit(code); } +static inline uint32_t swab32(uint32_t x) +{ + return x << 24 | x >> 24 | + (x & (uint32_t)0x0000ff00UL)<<8 | + (x & (uint32_t)0x00ff0000UL)>>8; +} + static unsigned char data[64 * 1024 * 1024]; /* kernel header is 20 bytes: kernel start magic(8 bytes) - 07 00 01 00 00 00 0A 04 kernel size(4 bytes) - variable tail magic(3 bytes) - 00 78 01 - chunks header or splitter(5 bytes) - 00 00 80 FF 7F or something else(for last chunk) + chunks header-splitter(5 bytes) - 00 00 80 FF 7F or something else(for last chunk) */ void *do_kernel_start_search(unsigned char *p, void *end){ uint64_t *k; + typeof(p) start = p; do{ k = (void*)p; if(*k == 0x040A000000010007LLU){ //check for kernel start magic value + printf("Kernel header(start magic) is found at: 0x%08lx\n", (void *)p - (void*)start); + //printf("Kernel size: %u bytes\n", swab32(*(uint32_t *)(k + 1))); //TODO: !!!! ??? !!! k = (void *)k + 8 + 4; //to tail magic /* printf("0x%08lx: %02X %02X %02X, %016lX\n", ((void*)p - (void*)data), p[12], p[13], p[14], *k); */ @@ -35,7 +45,7 @@ void *do_kernel_start_search(unsigned char *p, void *end){ return NULL; } -void *do_kernel_extract(unsigned char *p, void *end, char *file_name){ +static inline void *do_kernel_extract_OLD(unsigned char *p, void *end, char *file_name){ int fd; fd = open(file_name, O_WRONLY | O_CREAT); size_t len; @@ -73,6 +83,42 @@ void *do_kernel_extract(unsigned char *p, void *end, char *file_name){ close(fd); } +void *do_kernel_extract(unsigned char *p, void *end, char *file_name){ + int fd; + typeof(p) start = p; + fd = open(file_name, O_WRONLY | O_CREAT); + size_t len, chunk_size, total_size = 0; + int count = 0; + if(fd < 0) + die(-11); + do { + int is_last_chunk = p[0] == 1; + chunk_size = p[2] << 8 | p[1]; //extract current chunk len from chunk header(5 bytes) + printf("%04d: 0x%08lx: (%zd + 5): %02X %02X %02X %02X %02X\n", count, + (void *)p - (void*)start, chunk_size, p[4], p[3], p[2], p[1], p[0]); + p += 5; //skip chunk header(splitter) + if (chunk_size > (end - (void*)p)) { + printf(" !!! Current chunk size is bigger that rest data size ! %zd > %zd !\n" + " Source file was truncated ???\n", chunk_size, (end - (void*)p)); + break; + } + len = write(fd, p, chunk_size); + //printf("writing chunk %d, len = %zd bytes\n", count, len); + count++; + if (len != chunk_size) { + fprintf(stderr, "write to result file '%s' len %zd != %zd\n", file_name, chunk_size, len); + break; + } + total_size += len; + p += chunk_size; + if (is_last_chunk) + break; + } while ((void*)p + 5 <= end); + printf("Successfully writed %d chunks(%zd bytes) to '%s'\n", count, + total_size, file_name); + close(fd); +} + int main(int argc, char *argv[]){ int fd; void *start; diff --git a/for_ftp_upload/pub/OWL/bin/busybox b/for_ftp_upload/pub/OWL/bin/busybox index a5d7f1a..4bf7a1a 100755 Binary files a/for_ftp_upload/pub/OWL/bin/busybox and b/for_ftp_upload/pub/OWL/bin/busybox differ diff --git a/globals.sh b/globals.sh index 333f364..0fe12ec 100644 --- a/globals.sh +++ b/globals.sh @@ -1,11 +1,23 @@ #!/bin/sh # -#(C) Sergey Sergeev aka adron, 2019 +#(C) Sergey Sergeev aka adron, 2019-2021 # -TARGET_ARCH="arm" +#rb5009 +TARGET_ARCH="aarch64" +#rb3011(ipq806x), rb450dx4(ipq401x) +#TARGET_ARCH="arm" +#ath79, ramips #TARGET_ARCH="mips" +TOOLS_BINS_PREFIX="openwrt-linux" + +[ ${TARGET_ARCH} = "aarch64" ] && { + OPENWRT_DIR=/home/prog/openwrt/2021-openwrt/last-openwrt/openwrt + export STAGING_DIR=$OPENWRT_DIR/staging_dir/toolchain-aarch64_cortex-a72_gcc-11.2.0_musl + TOOLS_BINS_PREFIX="$TOOLS_BINS_PREFIX-musl" +} + [ ${TARGET_ARCH} = "arm" ] && { OPENWRT_DIR=/home/prog/openwrt/lede-all/2019-openwrt-all/openwrt-ipq806x export STAGING_DIR=$OPENWRT_DIR/staging_dir/toolchain-arm_cortex-a15+neon-vfpv4_gcc-7.4.0_musl_eabi @@ -19,7 +31,7 @@ TARGET_ARCH="arm" export STAGING_DIR=$OPENWRT_DIR/staging_dir/toolchain-mips_24kc_gcc-7.3.0_musl } -GCC=$STAGING_DIR/bin/${TARGET_ARCH}-openwrt-linux-gcc -OBJDUMP=$STAGING_DIR/bin/${TARGET_ARCH}-openwrt-linux-objdump -OBJCOPY=$STAGING_DIR/bin/${TARGET_ARCH}-openwrt-linux-objcopy -LD=$STAGING_DIR/bin/${TARGET_ARCH}-openwrt-linux-ld +GCC=$STAGING_DIR/bin/${TARGET_ARCH}-${TOOLS_BINS_PREFIX}-gcc +OBJDUMP=$STAGING_DIR/bin/${TARGET_ARCH}-${TOOLS_BINS_PREFIX}-objdump +OBJCOPY=$STAGING_DIR/bin/${TARGET_ARCH}-${TOOLS_BINS_PREFIX}-objcopy +LD=$STAGING_DIR/bin/${TARGET_ARCH}-${TOOLS_BINS_PREFIX}-ld diff --git a/init/compile.sh b/init/compile.sh index 80d764d..58cc2a7 100755 --- a/init/compile.sh +++ b/init/compile.sh @@ -1,10 +1,11 @@ #!/bin/bash # -#(C) Sergey Sergeev aka adron, 2019 +#(C) Sergey Sergeev aka adron, 2019-2021 # . ../globals.sh +GCC_ARGS="-static" #for 7.0rc1 we need gcc with soft-float ONLY! #apt-get install gcc-arm-linux-gnueabi [ ${TARGET_ARCH} = "arm" ] && { @@ -12,9 +13,19 @@ OBJCOPY=arm-linux-gnueabi-objcopy } +[ ${TARGET_ARCH} = "aarch64" ] && { + GCC=arm-linux-gnueabihf-gcc + OBJCOPY=arm-linux-gnueabihf-objcopy +# GCC_ARGS="$GCC_ARGS -mfloat-abi=soft" +} + CPIO_FS="../cpio-fs-${TARGET_ARCH}" -$GCC -static ./init.c -o ${CPIO_FS}/init +#$GCC $GCC_ARGS ./test.c -o ./test +#$OBJCOPY --strip-all ./test ./test +#exit 0 + +$GCC $GCC_ARGS ./init.c -o ${CPIO_FS}/init $OBJCOPY --strip-all ${CPIO_FS}/init ${CPIO_FS}/init #exit 0 diff --git a/init/init.c b/init/init.c index e2c0844..8c208bb 100644 --- a/init/init.c +++ b/init/init.c @@ -68,8 +68,8 @@ int main(int argc, char *argv[]){ pid_t pid; argv[0] = "/oldinit"; - environ[0] = "PATH=/sbin:/bin"; - environ[1] = NULL; + //environ[0] = "PATH=/sbin:/bin"; + //environ[1] = NULL; pid = fork(); if(pid == (pid_t)0){ //child diff --git a/ready-kernels/kernel-new-7.1b4-arm64.elf b/ready-kernels/kernel-new-7.1b4-arm64.elf new file mode 100755 index 0000000..a409f82 Binary files /dev/null and b/ready-kernels/kernel-new-7.1b4-arm64.elf differ diff --git a/unpack-kernel.sh b/unpack-kernel.sh index a0f81d6..70ad877 100755 --- a/unpack-kernel.sh +++ b/unpack-kernel.sh @@ -48,6 +48,7 @@ extract_kernel_elf(){ local offsets local offset local kernel_elf_size=0 + local garbage_size=70 offsets=`kernel_bin_binwalk | sed -n 's/ELF,//p' | sed -n 's/^\([0-9]\+\).*/\1/p'` local elf_last_offset local first_xz_offset @@ -60,6 +61,7 @@ extract_kernel_elf(){ first_xz_offset=${offset} break done + echo "${elf_last_offset} - ${first_xz_offset}" #elf size without xz kernel_elf_size=$((${first_xz_offset}-${elf_last_offset})) local p @@ -68,10 +70,15 @@ extract_kernel_elf(){ size=$(get_file_size ./bins/kernel.p${p}.xz) kernel_elf_size=$((${kernel_elf_size}+${size})) done + #dd if=./bins/kernel.bin bs=1 skip=${elf_last_offset} of=./bins/kernel-all.elf dd if=./bins/kernel.bin bs=1 skip=${elf_last_offset} count=${kernel_elf_size} of=./bins/kernel.elf [ -f ./bins/p3-garbage.bin ] && { - offset=484 #[ 45 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 ] <-- ${offset} - dd if=./bins/p3-garbage.bin bs=${offset} count=1 >> ./bins/kernel.elf + size=$(get_file_size ./bins/p3-garbage.bin) + #some of this data may be related to the elf (for 64-bit kernels - RB5009, ...\) + [ $size -gt $garbage_size ] && { + offset=$((size-garbage_size)) + dd if=./bins/p3-garbage.bin bs=${offset} count=1 >> ./bins/kernel.elf + } } } } @@ -95,6 +102,10 @@ extract_kernel_cpiofs(){ cp ./init ./oldinit } +#extract_kernel_elf +#unpack_kernel_bin +#exit 0 + unpack_kernel_bin ( xz -dc --single-stream > ./bins/initramfs.cpio && cat > ./bins/p3-garbage.bin ) < ./bins/kernel.p3.xz diff --git a/x1/README.txt b/x1/README.txt new file mode 100644 index 0000000..a3d5446 --- /dev/null +++ b/x1/README.txt @@ -0,0 +1,7 @@ +These files are obtained by the following commands: +dd if=./ros/routeros-7.1rc4-arm.npk of=x1/x1-32b.bin bs=$((0x009ee000)) skip=1 +dd if=./ros/routeros-7.1rc4-arm.npk of=x1/x1-64b.bin bs=$((0x00a06000)) skip=1 +0x009ee000 and 0x00a06000 is obtained from ./unpack-npk.sh ./ros/routeros-7.1rc4-arm.npk: +.. + Kernel header(start magic) is found at: 0x009ee000 +.