目录

有趣的Hack-A-Sat黑掉卫星挑战赛——卫星平台内存dump

国家太空安全是国家安全在空间领域的表现。随着太空技术在政治、经济、军事、文化等各个领域的应用不断增加,太空已经成为国家赖以生存与发展的命脉之一,凝聚着巨大的国家利益,太空安全的重要性日益凸显[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/