add support for RouterOS 7.1rc4 and aarch64(arm64 - RB5009)

This commit is contained in:
Sergey Sergeev 2021-09-25 20:03:56 +03:00
parent 21d602c331
commit f08d8a4a6c
15 changed files with 172 additions and 28 deletions

View file

@ -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/

BIN
cpio-fs-aarch64/bin/busybox Executable file

Binary file not shown.

View file

@ -0,0 +1 @@
busybox скомпилен вот тут: /home/prog/openwrt/switch/mikrotik-tools-master/busybox-arm-soft-float

BIN
cpio-fs-aarch64/init Executable file

Binary file not shown.

BIN
cpio-fs-aarch64/oldinit Executable file

Binary file not shown.

View file

@ -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!

View file

@ -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;
}

View file

@ -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;

Binary file not shown.

View file

@ -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

View file

@ -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

View file

@ -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

Binary file not shown.

View file

@ -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

7
x1/README.txt Normal file
View file

@ -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
.