freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

有趣的Hack-A-Sat黑掉卫星挑战赛——发送遥控指令控制卫星goose
hackasat 2023-04-15 20:32:55 253942
所属地 甘肃省

题目介绍

LaunchDotCom has a new satellite, the Carnac 2.0. What can you do with it from its design doc?

LaunchDotCom公司有一颗新的卫星——Carnac 2.0。卫星地面站正在与其进行遥测数据接收、遥控指令发送。本挑战题要求根据卫星的设计文档,思考如何获取flag。

本挑战题给出了一个链接地址,使用netcat连接到题目给的链接后,会给出进一步提示,如图4-14所示,提示遥测服务运行在另外一个地址上,继续使用netcat连接该地址,与4.2节类似,遥测服务正在发送一系列二进制数据,如图4-15所示,显示为乱码,根据题目信息,参赛者需要研究这颗新卫星的设计文档,从中解码出flag值。

图4-14  goose题目的提示信息

图4-15  连接到遥测服务后,接收到的数据

给出的资料有:

(1)cmd_telemetry_defs.zip,其中文件就是telemetry.xtce,它是一个XTCE文件,告诉我们二进制数据包是如何编码的。

(2)LaunchDotCom_Carnac_2.zip,解压后是文件LaunchDotCom_Carnac_2.pdf,该文件是卫星的设计文档,它详细描述这颗新卫星的信息。

题目编译及测试

本挑战题的代码位于goose目录下,查看challenge、solver目录下的Dockerfile,发现其中用到的是python:3.7-slim,为了加快题目的编译进度,在goose目录下新建一个文件sources.list,内容如下:

deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye main contrib non-free

deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-updates main contrib non-free

deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-backports main contrib non-free

deb https://mirrors.tuna.tsinghua.edu.cn/debian-security bullseye-security main contrib non-free

将sources.list复制到goose、challenge、solver目录下,修改challenge、solver目录下的Dockerfile,在所有的FROM python:3.7-slim下方添加:

ADD sources.list /etc/apt/sources.list

打开终端,进入goose所在目录,执行命令:

sudo make build

使用make test命令进行测试,会顺利通过,其输出信息如图4-16所示。

图4-16  goose挑战题测试输出

题目解析

题目给出卫星设计文档LaunchDotCom_Carnac_2.pdf和遥测遥控数据格式telemetry.xtce,分别对其分析,找出获取flag的相关途径。

(1)LaunchDotCom_Carnac_2.pdf文档。

文档描述了Carnac2.0卫星系统结构,如图4-17所示。

图4-17  Carnac 2.0卫星系统结构

Carnac 2.0卫星系统由以下6个部分组成。

  • ADCS:Attitude Determination and Control System(姿态控制系统)。
  • Payload Sensors:有效载荷子系统。
  • ECS:增强型通信系统(包含Radio1和Radio2)。
  • EPS:Electrical Power System(电力系统)。
  • Flag Generation:标志生成器(存储敏感信息,也就是参赛者获取的flag)。

卫星设计文档中提到一个重要信息:“The EPS also manages low battery conditions by removing power from non-essential subsystems once a low voltage threshold is reached”表明了如果电压过低,Flag Generation模块可能会被关闭,那么就无法顺利获取flag。因此,我们需要重点关注电源模块EPS,避免因电压过低而无法启动Flag Generation模块。

LaunchDotCom_Carnac_2.pdf中给出与EPS相关的遥测遥控数据中每个参数的含义,如表4-2所示,表中缩放值指的是实际值经过一定比例进行缩放变化后的参数值。

表4-2  与EPS相关的遥测遥控数据中每个参数的含义

参 数 名 称

参    数

描    述

Battery Temp

BATT_TEMP

缩放值为BATT_TEMP / 10

Battery Voltage

BATT_VOLTAGE

缩放值为BATT_VOLT / 100 +9.0

Battery Low Voltage Threshold

LOW_PWR_THRESH

缩放值为LOW_PWR_THRESH/100+9.0

Battery Heater

BATT_HTR

电池状态为on/off

Low Power Mode

LOW_PWR_MODE

低功率模式将关闭非必要的模块

Payload Power

PAYLOAD_PWR

Payload Sensors模块电源开关

Flag Power

FLAG_PWR

Flag Generation模块的电源开关

续表

参 数 名 称

参    数

描    述

ADCS Power

ADCS_PWR

ADCS的电源开关

Radio1 Power

RADIO1_PWR

Radio1的电源开关

Radio2 Power

RADIO2_PWR

Radio2的电源开关

Payload Enable

PAYLOAD_ENABLE

使能Payload

Flag Enable

FLAG_ENABLE

使能Flag Generation

ADCS Enable

ADCS_ENABLE

使能ADCS

Radio1 Enable

RADIO1_ENABLE

使能Radio1

Radio2 Enable

RADIO2_ENABLE

使能Radio2

Command Error Count

CMD_ERR_CNT

收到的无效命令计数

(2)cmd_telemetry_defs.xtce。

cmd_telemetry_defs.xtce描述了卫星的遥测遥控协议。找到EPS相关部分,如下所示:

<xtce:SequenceContainer name="EPS Packet" shortDescription="packet of EPS data">

<xtce:EntryList>

<xtce:ParameterRefEntry parameterRef="BATT_TEMP"/>

<xtce:ParameterRefEntry parameterRef="BATT_VOLTAGE"/>

<xtce:ParameterRefEntry parameterRef="LOW_PWR_THRESH"/>

<xtce:ParameterRefEntry parameterRef="LOW_PWR_MODE"/>

<xtce:ParameterRefEntry parameterRef="BATT_HTR"/>

<xtce:ParameterRefEntry parameterRef="PAYLOAD_PWR"/>

<xtce:ParameterRefEntry parameterRef="FLAG_PWR"/>

<xtce:ParameterRefEntry parameterRef="ADCS_PWR"/>

<xtce:ParameterRefEntry parameterRef="RADIO1_PWR"/>

<xtce:ParameterRefEntry parameterRef="RADIO2_PWR"/>

<xtce:ParameterRefEntry parameterRef="UNUSED1"/>

<xtce:ParameterRefEntry parameterRef="PAYLOAD_ENABLE"/>

<xtce:ParameterRefEntry parameterRef="FLAG_ENABLE"/>

<xtce:ParameterRefEntry parameterRef="ADCS_ENABLE"/>

<xtce:ParameterRefEntry parameterRef="RADIO1_ENABLE"/>

<xtce:ParameterRefEntry parameterRef="RADIO2_ENABLE"/>

<xtce:ParameterRefEntry parameterRef="UNUSED3"/>

<xtce:ParameterRefEntry parameterRef="BAD_CMD_COUNT"/>

</xtce:EntryList>

<xtce:BaseContainer containerRef="AbstractTM Packet Header">

<xtce:RestrictionCriteria>

<xtce:ComparisonList>

<xtce:Comparison parameterRef="CCSDS_VERSION" value="0"/>

<xtce:Comparison parameterRef="CCSDS_TYPE" value="0"/>

<xtce:Comparison parameterRef="CCSDS_SEC_HD" value="0"/>

<xtce:Comparison parameterRef="CCSDS_APID" value="103"/>

</xtce:ComparisonList>

cmd_telemetry_defs.xtce和之前挑战类似。但之前的挑战题只是接收卫星下传的遥测数据,现在多了一个遥控部分,这意味着我们需要将遥控指令发送给卫星。注意到电源模块EPS包定义有许多信息,包括电压参数、低电量阈值等。通过和4.2节类似的解码方式,我们可以获得EPS包的结构如图4-18所示。

图4-18  EPS包结构

参考4.2节的解码方式,可以分为4步:

  • 根据XTCE格式,解码出包头APID的值。
  • 取出APID为103的数据包,就是电源模块EPS包。
  • 针对该数据包,依据图4-18分析出的包结构,提取出感兴趣的各参数值。
  • 打印各个参数,进一步得到更多信息,以便于后续分析。

关键代码如下:

import os

import sys

import socket

import random

import time

import bitstring

from pprint import pprint

FLAG_APID = 102

EPS_APID = 103

PAYLOAD_APID = 105

HOST='127.0.0.1'

class cmdSender:


def __init__(self, APID):


self.packet_version = 0

self.packet_type = 1

self.sec_header_flag = 0

self.APID = APID

self.sequence_flags = 3

self.packet_sequence_count = random.randint(1000, 10000)

self.packet_data_length = 1


if __name__ == '__main__':

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

sock.connect((HOST, 31335))

line = sock.recv(256)

sock.close()


_, Port = line.split(b" ")[-1].split(b":")

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

sock.connect((HOST, int(Port)))

time.sleep(1)




while True:


data = sock.recv(6) # 6字节的包头

s = bitstring.BitArray(data)

version, type, sec_header, apid, sequence_flags, sequence_count, data_length = s.unpack('uint:3, uint:1, uint:1, uint:11, uint:2, uint:14, uint:16')

print("APID: {}\nLength: {}\n".format(apid, data_length))


data = sock.recv(data_length+1)


if apid != EPS_APID:   # 只解析EPS相关遥测信息

print("Ignoring APID we don't care about")

continue

s = bitstring.BitArray(data)

BATT_TEMP, BATT_VOLTAGE, LOW_PWR_THRESH, LOW_PWR_MODE, BATT_HTR, PAYLOAD_PWR, FLAG_PWR, ADCS_PWR, RADIO1_PWR, RADIO2_PWR, UNUSED1, PAYLOAD_ENABLE, FLAG_ENABLE, ADCS_ENABLE, RADIO1_ENABLE, RADIO2_ENABLE= s.unpack('uint:16, uint:16, uint:16, uint:1, uint:1, uint:1, uint:1, uint:1, uint:1, uint:1, uint:1, uint:1, uint:1, uint:1, uint:1, uint:1')

print("LOW_PWR_MODE:",LOW_PWR_MODE)


#259 Scaled value: BATT_VOLT / 100 + 9.0  11.5

print("BATT_VOLTAGE:",BATT_VOLTAGE)


#400  Scaled value: LOW_PWR_THRESH  /100 + 9.0

print("LOW_PWR_THRESH:",LOW_PWR_THRESH)

print("BATT_HTR:",BATT_HTR)

print("PAYLOAD_PWR:",PAYLOAD_PWR)

print("FLAG_PWR:",FLAG_PWR)

print("ADCS_PWR:",ADCS_PWR)

print("RADIO1_PWR",RADIO1_PWR)

print("RADIO2_PWR:",RADIO2_PWR)

print("PAYLOAD_ENABLE:",PAYLOAD_ENABLE)

print("FLAG_ENABLE:",FLAG_ENABLE)

break

运行上述代码后,输出如图4-19所示,成功解析出EPS遥测数据包。

图4-19  解析遥测数据中的EPS包

我们注意到LOW_PWR_MODE=1,如表4-2所示,说明卫星处于低电量模式,可能会关闭一些非核心的系统;FLAG_PWR=0,说明Flag Generation模块的电源是关闭的。因此,首先要做的就是想办法打开Flag Generation模块的供电,进一步从图4-19分析,BATT_VOLTAGE=259,LOW_PWR_THRESH=400,说明低电量模式下电池电压(BATT_VOLTAGE:259)<电池低电压门限(LOW_PWR_THRESH:400)。查看表4-2中BATT_VOLTAGE的描述,259是经过缩放后的值,实际电压根据表中BATT_VOLT / 100 +9.0计算,可得11.59V;同理低电压门限根据表中LOW_PWR_THRESH /100+9.0计算可得,目前的低电压门限设置13V。

根据上述分析,得出解题思路:

  • 打开Flag Generation模块电源。
  • 关闭低电量模式,可以尝试即修改低电压门限,使其小于实际电压。

步骤一:打开Flag Generation模块电源。

通过查看XTCE文档的遥控指令格式可知,可以通过发送EnableFLAG命令设置FLAG_PWR=1,即打开Flag Generation模块电源。XTCE文档中EnableFLAG命令定义如下:

<xtce:MetaCommand name="AbstractCMD Packet Header" shortDescription="CCSDS CMD Packet Header" abstract="true">

<xtce:EntryList>

<xtce:ParameterRefEntry parameterRef="CCSDS_VERSION"/>

<xtce:ParameterRefEntry parameterRef="CCSDS_TYPE"/>

<xtce:ParameterRefEntry parameterRef="CCSDS_SEC_HD"/>

<xtce:ParameterRefEntry parameterRef="CCSDS_APID"/>

<xtce:ParameterRefEntry parameterRef="CCSDS_GP_FLAGS"/>

<xtce:ParameterRefEntry parameterRef="CCSDS_SSC"/>

<xtce:ParameterRefEntry parameterRef="CCSDS_PLENGTH"/>

</xtce:EntryList>

<xtce:RestrictionCriteria>

<xtce:ComparisonList>

<xtce:Comparison parameterRef="CCSDS_VERSION" value="0"/>

<xtce:Comparison parameterRef="CCSDS_TYPE" value="1"/>

<xtce:Comparison parameterRef="CCSDS_SEC_HD" value="0"/>

<xtce:Comparison parameterRef="CCSDS_GP_FLAGS" value="3"/>


</xtce:ComparisonList>

</xtce:RestrictionCriteria>

</xtce:MetaCommand>

<xtce:MetaCommand name="EnableFLAG" abstract="false">

<xtce:BaseMetaCommand metaCommandRef="AbstractCMD Packet Header">

<xtce:RestrictionCriteria>

<xtce:ComparisonList>

<xtce:Comparison parameterRef="CCSDS_APID" value="103"/>

<xtce:Comparison parameterRef="CCSDS_PLENGTH" value="2"/>

</xtce:ComparisonList>

</xtce:RestrictionCriteria>

</xtce:BaseMetaCommand>

<xtce:ArgumentList>

<xtce:Argument argumentTypeRef="EnableState" name="PowerState"/>

</xtce:ArgumentList>

<xtce:CommandContainer name="ADCSenable">

<xtce:EntryList>

<xtce:ParameterRefEntry parameterRef="CMD"/>

<xtce:ParameterRefEntry parameterRef="PARAM"/>

<xtce:ArgumentRefEntry argumentRef="PowerState"/>

</xtce:EntryList>

<xtce:RestrictionCriteria>

<xtce:Comparison parameterRef="CMD" value="0"/>

<xtce:Comparison parameterRef="PARAM" value="2"/>

</xtce:RestrictionCriteria>

由此可知,需要发送的EnableFLAG命令的结构如下,同时,从从上面定义中注意到,限制标准(RestrictionCriteria)部分,CMD=0,PARAM=2。

6字节包头(header)+CMD+PARAM+PowerState

......

<xtce:ParameterSet>

<xtce:Parameter parameterTypeRef="1ByteInteger" name="CMD" initialValue="4" readOnly="true"/>

<xtce:Parameter parameterTypeRef="1ByteInteger" name="PARAM" initialValue="4" readOnly="true"/>

</xtce:ParameterSet>


<xtce:ArgumentList>

<xtce:Argument argumentTypeRef="EnableState" name="PowerState"/>

</xtce:ArgumentList>

......

<xtce:ArgumentList>

<xtce:Argument argumentTypeRef="EnableState"name="PowerState"/>

</xtce:ArgumentList>

</xtce:IntegerArgumentType>

<xtce:EnumeratedArgumentType name="EnableState" initialValue="ENABLE">

<xtce:UnitSet/>

<xtce:IntegerDataEncoding sizeInBits="8" signed="false"/>

<xtce:EnumerationList>

<xtce:Enumeration label="ENABLE" value="1"/>

<xtce:Enumeration label="DISABLE" value="0"/>

</xtce:EnumerationList>

</xtce:EnumeratedArgumentType>

<xtce:StringArgumentType name="Enable">

<xtce:UnitSet/>

......

对于上述参数,寻找对应的参数格式,其中“CMD”和“PARAM”均为1字节。“PowerState”对应的是“EnableState”。“EnableState”为1字节的无符号参数,“PowerState”为“ENABLE”状态对应的值1。

因此需要发送的EnableFLAG命令的结构进一步明确如下:

6字节包头(header)+1字节CMD+1字节PARAM+1字节PowerState

EnableFLAG命令结构如图4-20所示。

图4-20  EnableFLAG命令结构

其中CMD=0,PARAM=2,“PowerState”为“ENABLE”状态对应的值1。最终需要发送的命令如下:

6字节包头结构+ \x00\x02\x01

步骤二:关闭低电量模式。

通过查看XTCE文档可以知道有调整低电量模式阈值的遥控指令LOW_PWR_THRES。当前电压为11.59V,需要找到合理的门限电压值,使得当前的电压11.59V大于门限电压值,从而消除低电量告警。

</xtce:MetaCommand>

<xtce:MetaCommand name="LOW_PWR_THRES" abstract="false">

<xtce:BaseMetaCommand metaCommandRef="AbstractCMD Packet Header">

<xtce:RestrictionCriteria>

<xtce:ComparisonList>

<xtce:Comparison parameterRef="CCSDS_APID" value="103"/>

<xtce:Comparison parameterRef="CCSDS_PLENGTH" value="3"/>

</xtce:ComparisonList>

</xtce:RestrictionCriteria>

</xtce:BaseMetaCommand>

<xtce:ArgumentList>

<xtce:Argument argumentTypeRef="VoltageArgType" name="LW_PWR_THRES"/>

</xtce:ArgumentList>

<xtce:CommandContainer name="ADCSenable">

<xtce:EntryList>

<xtce:ParameterRefEntry parameterRef="CMD"/>

<xtce:ParameterRefEntry parameterRef="PARAM"/>

<xtce:ArgumentRefEntry argumentRef="LW_PWR_THRES"/>

</xtce:EntryList>

<xtce:RestrictionCriteria>

<xtce:Comparison parameterRef="CMD"value="0"/>

<xtce:Comparison parameterRef="PARAM"value="12"/>

</xtce:RestrictionCriteria>

</xtce:CommandContainer>

</xtce:MetaCommand>

其中,“LW_PWR_THRES”对应的参数类型是“VoltageArgType”。因此调整低电量模式的阈值命令的结构为

6字节包头(header)+1字节“CMD+1字节“PARAM+2字节“LW_PWR_THRESVoltageArgType类型)

注意到,限制标准(RestrictionCriteria)部分中,CMD=0,PARAM=12。对于上述参数,在XTCE文档中寻找对应的参数格式,由前文得知,“CMD”和“PARAM”为1字节。提到“LW_PWR_THRES”对应的参数类型是“VoltageArgType”(其定义如下),而“VoltageArgType”为16bit的无符号参数,因此“LW_PWR_THRES”是类型“VoltageArgType”,即16bit的无符号参数。调整低电量模式阈值的包结构如图4-21所示。

<xtce:FloatArgumentType sizeInBits="32" name="VoltageArgType">

<xtce:UnitSet>

<xtce:Unit description="V">:V</xtce:Unit>

</xtce:UnitSet>

<xtce:IntegerDataEncoding sizeInBits="16" encoding="unsigned">

<xtce:DefaultCalibrator>

<xtce:PolynomialCalibrator>

<xtce:Term coefficient="-90.0" exponent="0"/>

<xtce:Term coefficient="100.0" exponent="1"/>

</xtce:PolynomialCalibrator>

图4-21  调整低电量模式阈值的包结构

结合之前观察到的限制标准(RestrictionCriteria)部分中,CMD=0,PARAM=12。进一步明确,需要发送的命令结构如下:

6字节包头(header)+ \x00\x0C+2字节LW_PWR_THRES

其中关键是“LW_PWR_THRES”的选取。已知当前电压为11.59V,需要找到合理的门限电压值,使得当前的电压11.59V大于门限电压值。经过尝试,阈值设置高于11.22V即可获取flag。本节设置阈值为11.22V,通过表4-2计算,11.22V对应的是222(十六进制是0xDE)。最终发送的命令为:

6字节包头(header)+ \x00\x0C\xDE

到此,可以给出解答本挑战题的关键代码如下:

import os

import sys

import socket

import random

import time

sys.path.append('./anaconda3/lib/python3.6')

#print(sys.path)

import bitstring

FLAG_APID = 102

EPS_APID = 103

PAYLOAD_APID = 105

HOST='127.0.0.1'

class cmdSender:


def __init__(self, APID):


self.packet_version = 0

self.packet_type = 1

self.sec_header_flag = 0

self.APID = APID

self.sequence_flags = 3

self.packet_sequence_count = random.randint(1000, 10000)

self.packet_data_length = 1


# 定义一个发送遥控指令的函数

def sendCMD(self, socket, payload):

self.packet_data_length = len(payload) - 1

packet = bitstring.pack('uint:3, uint:1, uint:1, uint:11, uint:2, uint:14, uint:16',

self.packet_version, self.packet_type, self.sec_header_flag, self.APID, self.sequence_flags,

self.packet_sequence_count, self.packet_data_length)

packethdr = packet.tobytes()

wholepacket = packethdr + payload # 包头

self.packet_sequence_count += 1

socket.send(wholepacket)

return True

if __name__ == '__main__':

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

sock.connect((HOST, 31335))

line = sock.recv(256)

sock.close()

_, Port = line.split(b" ")[-1].split(b":")

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

sock.connect((HOST, int(Port)))


# 使能Flag Generator模块

cmd = cmdSender(EPS_APID)

time.sleep(1)

cmd.sendCMD(sock, b'\x00\x02\x01') # 发送使能Flag Generator模块命令


# 选取阈值222(11.22V),发送关闭低电量模式命令

cmd.sendCMD(sock, b'\x00\x0c\x03\xde')


# 参考4.2节中的模式解析遥测数据中的flag值

while True:

data = sock.recv(6) #6字节包头

s = bitstring.BitArray(data)

version, type, sec_header, apid, sequence_flags, sequence_count, data_length = s.unpack('uint:3, uint:1, uint:1, uint:11, uint:2, uint:14, uint:16')# 从头解析包数据


print("APID: {}\nLength: {}\n".format(apid, data_length))

data = sock.recv(data_length+1)


if apid != FLAG_APID:   # 选出flag包

print("Ignoring APID we don't care about")

continue


s = bitstring.ConstBitStream(data)

char = ' '

flag = ''

while char != '}':

char = chr(s.read('uint:7')) # 取出7bit flag片段,每7bit转换为8bit字符

flag += char

print(flag)

break

# 资讯 # 网络安全 # web安全 # CTF # 网络安全技术
本文为 hackasat 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
hackasat LV.3
这家伙太懒了,还未填写个人描述!
  • 17 文章数
  • 18 关注者
从“黑掉卫星”挑战赛分析美太空安全攻击手段
2023-12-04
有趣的Hack-A-Sat黑掉卫星挑战赛——寻找恒星2(spacebook)
2023-09-08
有趣的Hack-A-Sat黑掉卫星挑战赛——寻找恒星1(centroids)
2023-05-19
文章目录