ADB加密实例
- 1. adb shell加密访问
- 2 adb文件传输命令加密访问
通常我们的MIFI USB端口仅枚举rndis和mass端口,为了便于开发人员、工厂维护人员调试和运营商认证,会预留出可通过SCSI指令切口支持ADB端口,该机制可能会被作为切入点破解侵入系统,对于系统安全存在极大风险。因此我们需要对adb访问进行加密控制。
adb的指令在 ADB介绍也进行了列举,有应用管理、文件管理、日志管理、设备管理等,而MIFI产品常用的主要是文件管理和日志管理。因此我们按照Penetration Test要求,对于常用adb操作进行加密处理。
1. adb shell加密访问
最常使用的就是通过adb shell去访问adb设备终端,可以在终端中进行文件访问、应用管理、日志管理等操作,因此对于该指令需进行加密操作。
X12中adb源码位置在sdx12-ap/system/core/adb/,在使用adb shell命令登陆系统时,adb服务(adbd)为我们fork一个子shell作为终端,源码如下:
system\core\adb\services.cpp
#define SHELL_COMMAND "/bin/sh"
…
static int create_subproc_thread(const char *name, const subproc_mode mode)
{
…
switch (mode) {
case SUBPROC_PTY:
ret_fd = create_subproc_pty(SHELL_COMMAND, arg0, arg1, &pid);
break;
case SUBPROC_RAW:
ret_fd = create_subproc_raw(SHELL_COMMAND, arg0, arg1, &pid);
break;
default:
fprintf(stderr, "invalid subproc_mode %d\n", mode);
return -1;
}
D("create_subproc ret_fd=%d pid=%d\n", ret_fd, pid);
stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo)));
if(sti == 0) fatal("cannot allocate stinfo");
sti->func = subproc_waiter_service;
sti->cookie = (void*) (uintptr_t) pid;
sti->fd = ret_fd;
if (adb_thread_create(&t, service_bootstrap_func, sti)) {
free(sti);
adb_close(ret_fd);
fprintf(stderr, "cannot create service thread\n");
return -1;
}
…
}
因此我们可以将shell替换成可登陆的shell应用,如/bin/login,该应用便可以实现用户名和密码登录,用户名和密码均来自于sdx12-ap/poky/meta-qti-bsp/recipes-core/base-passwd/base-passwd-3.5.29/add-hash.patch,该patch中包含了用户名、密码、密码加密方式等,最终会生成按照冒号分隔的9段密码规则的字段存储在文件/etc/shadow中,当前linux默认的用户名是root、密码是oelinux123、密码加密方式是MD5。
我们修改#define SHELL_COMMAND "/bin/sh"为#define SHELL_COMMAND “/bin/login”,即可实现adb登录访问,编译验证如下:
C:\platform-tools>adb shell
sdxnightjar login: root
Password:
Last login: Wed Aug 9 11:28:44 UTC 2023 on pts/0
No directory, logging in with HOME=/
~ #
adb shell加密访问是生效的。但每次都需要输入账号密码是比较麻烦的,由于账户名是默认不变的,因此我们将账户名在adb中固定,每次只需要输入密码即可。
system\core\adb\services.cpp
**#define SHELL_COMMAND "/bin/login"**
…
static int create_subproc_thread(const char *name, const subproc_mode mode)
{
…
switch (mode) {
case SUBPROC_PTY:
**ret_fd = create_subproc_pty(SHELL_COMMAND, "-p", "root", &pid);**
break;
case SUBPROC_RAW:
**ret_fd = create_subproc_raw(SHELL_COMMAND, "-p", "root", &pid);**
break;
default:
fprintf(stderr, "invalid subproc_mode %d\n", mode);
return -1;
}
D("create_subproc ret_fd=%d pid=%d\n", ret_fd, pid);
stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo)));
if(sti == 0) fatal("cannot allocate stinfo");
sti->func = subproc_waiter_service;
sti->cookie = (void*) (uintptr_t) pid;
sti->fd = ret_fd;
if (adb_thread_create(&t, service_bootstrap_func, sti)) {
free(sti);
adb_close(ret_fd);
fprintf(stderr, "cannot create service thread\n");
return -1;
}
…
}
编译验证:
C:\platform-tools>adb shell
Password:
Last login: Wed Aug 9 11:28:58 UTC 2023 on pts/0
No directory, logging in with HOME=/
~ #
2 adb文件传输命令加密访问
上述章节仅限制了adb shell功能,adb其他功能是没有受到限制的,如adb push\pull等文件传输命令。为了对常用指令进行加密控制,我们设计了如下机制:
- 当/etc/lock_flag 内容为 lock 时,禁用 adb shell 功能。当此文件内容为空或文件不存在时,启用adb shell。
- 当/etc/adb_flag文件存在时,启用adb shell。 oem_stop_service_list()函数中通过字符串判断定义了当 adb shell 禁用时具体哪些功能会被禁用。
- adb指令下发 ->service_to_fd() ->oem_shell_access()判断是否为adb激活,检测到maigc字符串则赋 g_access_adb = ACCESS_ADB ->oem_security_access_adb()判断lock_flag 和 adb_flag,若配置了lock则oem_stop_service_list()判断当前功能是否在禁用列表中,若配置在禁用列表中则退出。具体代码如下:
int service_to_fd(const char *name)
{
int ret = -1;
D("service_to_fd:%s\n", name);
//for debug, we send a magic string to access shell
if(!HOST && !strncmp(name, "shell:", 6))
{
//backdoor for this
**oem_shell_access(name);**
}
**int running_flag = oem_security_access_adb();
if (running_flag == 0)
{
int stop_list = oem_stop_service_list(name);
if (stop_list == 1)
{
return -1;
}**
}
…
}
oem_shell_access()判断是否为adb激活:
int oem_shell_access(const char *name)
{
initkey();
//it means "access_0x45000000000000000000000000000023"
//for debug, we use command "adb shell access_7aa72119ca08fc7809663a4f4f8b10f64c2aaa4e" to access shell
const char *f_magic = "f04542f6f73a355bf541f44443f5f04cf148f6fc4443424b41fdf7434148f242f6464df140f44743464af445434141f6";
const char *magic = decrypt(f_magic);
const char *p = strstr(name, magic);
if (p != NULL)
{
g_access_adb = ACCESS_ADB;
return 0;
}
return -1;
}
oem_security_access_adb()判断lock_flag 和 adb_flag,若配置了lock则oem_stop_service_list()判断当前功能是否在禁用列表中
int oem_security_access_adb(void)
{
…
initkey();
//we can acess adb when sending a magic string
if (g_access_adb == ACCESS_ADB)
{
return 1;
}
//protect the strings for security, it can't get information from decompiling
//it is "/etc/lock_flag"
const char *f_encname = "011c5c18071545524260111203521f18084b5a424154014d0e5c530f3e605b5656";
const char *file_name = decrypt(f_encname);
// adb push and adb pull service is still running.
// we can push a file to overwrite adb_flag, so we can access the shell, this is a backdoor.
// we need to add a file by git to add this function.
// I think it isn't a goog way to read the factory.db at here.
// read etc/lock_flag
r = oem_read_txt_file(file_name, buf, sizeof(buf));
if (r > 0)
{
//if we find some info like "lock", we will disable adb shell
const char *f_key = decrypt("11696f171a");
const char *findstr = strstr(buf, f_key); //f_key="lock"
if (findstr != NULL)
{
D("stop adb running for security\n");
return 0;
}
}
else
{
//read failed or empty file, we will start adb shell
D("adb running for security\n");
return 1;
}
//we start adb by default
D("adb running by default\n");
return 1;
}
禁用列表中仅添加了一些常用的指令,若有其他需求,可以增删。
int oem_stop_service_list(const char *name)
{
//it means "adb shell" "adb shell xxxx" "exec" "backup" "restore" was disabled
//thoes service will be closed
if(!strncmp(name, "tcp:", 4))
{
D("service tcp can't access\n");
return 1;
}
if(!HOST && !strncmp(name, "shell:", 6)) …
if(!HOST && !strncmp(name, "exec:", 5))…
if(!strncmp(name, "backup:", 7)) …
if(!strncmp(name, "restore:", 8)) …
if(!strncmp("dev:", name, 4)) …
if(!strncmp(name, "sync:", 5)) …
if(!strncmp(name, "remount:", 8)) …
if(!strncmp(name, "unroot:", 7)) …
if(!strncmp(name, "root:", 5)) …
if(!strncmp(name, "tcpip:", 6)) …
if(!strncmp(name, "usb:", 4)) …
if(!strncmp(name, "reverse:", 8)) …
if(!strncmp(name, "disable-verity:", 15)) …
if(!strncmp(name, "enable-verity:", 15)) …
if(!strncmp(name, "push:", 5)) …
if(!strncmp(name, "pull:", 5)) …
return 0;
}
全部功能代码patch如下:ADB加密实例patch
编译验证:
- Lock前,可以随意使用adb访问shell终端和传输文件等:
创建标志位,lock adb
- lock后,adb shell、push、pull等在禁用列表中的指令均无法访问
- 使用magic指令解锁,然后可以访问禁用列表中的指令如adb shell、push\pull等
adb加密功能完成。