有趣的黑掉卫星Hack-A-Sat CTF比赛——模拟卫星视角beckley
以下内容是通过阅读《Hack-A-Sat太空信息安全挑战赛深度解题》做的测试。
题目介绍
Launch your Google Earth and refresh your KML tutorials; our goal is to impress it with impressive visuals.
Reviewing and practicing these techniques for 30 minutes daily will help you master the tools needed to create detailed and accurate 3D models of geographic locations.
题目描述较为简略, 主办方希望参赛者借助Google Earth软件及KML文件来定位设定好的标志物. 提供的资料包括:
一个命名为static的一个目录中仅包含一个名为remote.kml的文件。通过后缀名可以看出该文档属于KML格式(即Keyhole Markup Language)。它主要用于存储和表示地理数据。其详细情况将在下文部分进行介绍。
(2)提供了相关链接地址,在通过nc连接至主办方提供的链接地址后,请注意将会引导您收到相关信息提示(如图2-1所示)。

图2-1 beckley挑战题的提示信息
向参赛者告知当前截获了一张由卫星拍摄华盛顿纪念碑的照片,并提供了该卫星的两行轨道根数(TLE)以及照片捕捉的时间信息,请参赛者在Google Earth中模拟卫星拍照的角度和时间即可定位标记信息的位置
编译及测试
该挑战题的代码存储于beckley目录中,在 beckley 目录中开启终端窗口并执行以下命令
sudo make build
随后运行make test命令以执行测试。运行结果显示如图2-2所示,并表明该测试过程中采用curl工具访问Google Earth,并通过对其返回信息的解析提取出flag。

图2-2 beckley挑战题测试输出
为了更加清晰地显示解题过程,可以分开测试:
启动一个终端窗口,请输入以下命令:其中端口号和 flag 值都可以自由设置,请注意这些参数将决定容器的运行方式。这些指令的目的在于启动一个 Beckley 挑战题服务容器。
网络传输工具通过-tc puno协议实现对指定端口的监听与通信配置文件位于本地路径并执行特定脚本该脚本包含启动一个基于Docker容器运行的服务该服务具备不可持久化特性并配置了多个环境变量包括服务主机IP地址服务端口号随机种子值以及特定标志值同时该脚本将执行 beckley 挑战模式任务
(2)调用另一个终端窗口,并在其环境中扮演参赛者的角色。其中使用的地址和端口参数与第(1)步中配置服务容器时所设定的一致。其运行结果将提供更详细的指引。(如图2-1所示)
启动一个新的终端窗口,并运行以下命令。实际上是一个服务端容器模拟的Google Earth服务器地址,在第(2)步中已经获取了该URL地址。该命令通过curl工具访问这个指定的URL地址。
curl http://172.17.0.1:19021/cgi-bin/HSCKML.py?CAMERA=-77.03,38.89,430000,40.3694166667,
63.5358055556 -H 'User-Agent: GoogleEarth/7.3.2.5815(X11;Linux (5.2.0.0);en;kml:2.2;
client:Pro;type:default)' -H 'Accept: application/vnd.google-earth.kml+xml, application/
vnd.google-earth.kmz, image/*, /' -H 'Accept-Language: en-US, *' -H 'Connection: keep-alive'
curl工具在其URL地址后增加了不少参数,在这些新增的设置当中较为关键的是CAMERA这一项配置选项,在使用过程中可以看出该CAMERA参数由五个数字构成的具体数值设置。
而在主办方发布的remote.kml文件中有所记载,在这一条款的具体内容上与curl工具所采用的设置非常相似地存在。
值得注意的是这一点至关重要,在后续分析过程中将会对此展开详细探讨并揭示其实质意义。
CAMERA=[lookatLon],[lookatLat],[lookatRange],[lookatTilt],[lookatHeading]
在执行该命令时, 程序将返回以KML格式表示的结果, 并通过查看图形文件中的数据可以看出, 在其中的

图2-3 beckley挑战题获取到的flag
相关背景知识
1.卫星轨道和TLE轨道根数
太空中的卫星受多种力的影响而进行周期性运行,从一阶近似来看,则可简化为一个开普勒椭圆轨道.其中主要存在大气阻力以及其他行星间的引力等因素的影响,这导致实际运行轨迹与理想化的开普勒椭圆轨道存在一定偏差,这种偏差被称为"轨道摄动".在此阶段我们暂且忽略这些摄动因素的影响.
为了准确确定一颗卫星的运行轨道,必须具备六个关键参数,并在图2-4中展示具体信息。
(1)描述轨道大小的参数——轨道半长轴a。
椭圆的长轴的一半相当于轨道的半长轴。在其他条件不变的情况下,随着长度增加而周期增长。
(2)描述轨道形状的参数——轨道偏心率e。
离心率是指椭圆两焦点之间的距离与其长轴长度之比。当离心率为零时,表现为圆形轨道;当离心率处于0至1之间时,表现为椭圆轨道;当离心率为1时,表现为抛物线轨道;而当离心率超过1时,则表现为双曲线轨道。

图2-4 卫星运行轨道参数示意图
(3)描述轨道平面在空间方位的参数——轨道倾角i和升交点赤经Ω。
轨道倾角被定义为其所在平面与地球赤道平面之间的夹角。当该角度低于90度时(即小于直角),卫星将沿顺行方向运行;而当超过90度(钝角)则逆行。其中,在零度情况下属于赤道轨道,在直角度情况下则是极地轨道。
该术语定义了轨道升交点与春分天文学坐标系之间的角度;当卫星从南半球穿越赤道平面返回北半球时,在该处形成的天文学坐标标记为升交点;它们共同决定了确定轨道平面在三维空间中的精确方向
(4)描述轨道在轨道平面内方位的参数——近地点幅角ω。
近地点幅角即为近地点与升交点对地心所成之夹角。尽管轨道倾角及升交点赤经虽已决定了其所在平面的空间位置,但该物体在其所在平面上仍可绕轴线旋转角度,则该值则决定了其在平面上的具体位置。
(5)描述卫星在轨道上位置的参数——过近地点时刻τ。
过近地点时刻是指卫星运行至近地点的那个特定时间点,在记录上通常采用年月日时分秒的时间单位来表示。为了精确描述卫星的位置变化情况,在计算过程中需要确定初始条件即运动时间起算点随后通过应用开普勒方程可以确定在τ+t时刻卫星所处的空间轨道及其运动速率
值得注意的是,在上述提到的6个参数中,并非仅限于能够全面描述卫星轨道情况。实际上还可以选择其他类型的参数来实现这一目的。其中所采用的这一组参数是一种较为合理的选择。
TLE(Two-Line Element)主要用于记录卫星星历信息,并涵盖气象卫星、海洋卫星、地球资源卫星及教育卫星等应用领域中的相关数据。其组成包括三部分:首先是定轨信息的第一行数据即为轨道元素参数值;其次是轨道状态向量的第二行数据;最后是轨道修正参数的第三行数据。每个字段占据69个字符的位置,并由0至9的数字、A至Z的大写字母、空格符、点号以及正负号组成。
以北斗的某颗卫星的TLE数据为例,数据如下:
BEIDOU 2A
1 30323U 07003A 07067.68277059 .00069181 13771-5 44016-2 0 587
2 30323 025.0330 358.9828 7594216 197.8808 102.7839 01.92847527 650
第1行主要元素解析如下:
(1)^{[1]}:^{[1]}是北美防空司令部指定的卫星编码标识符。“^{[1]}”代表非机密数据类别。“观察到的数据均为‘^{[1]}’类型”。若无此类数据,则将无法获取该组TLE信息。
其中,“(2)”标识为21世纪初的一次重要发射任务,“...”则用于标记特定物品的技术参数或编码信息,在本例中代表该次发射的具体技术参数编码
(3)该轨道数据的时间编码为...:其中'...'一词具体指代的是....例如'...''代表的是'...'或者....另外'...'这一编号对应的具体时间为....例如......
0.00069181\ 13771^{-5}\ 44016^{-2}:与轨道模型相关的参数值及其意义如下所示:该参数值代表的是平近点运动的一阶时间导数值除以二;而另一个参数则代表平近点运动的二阶时间导数值除以六(即-5\times 1.3771\times 10^{-6}),此外还有一个BSTAR拖放电系数为-2\times 4.4016\times 10^{-2}。
(5)0:轨道模型,0表示采用SGP41SDP4轨道模型。
(6)58:表示这是关于这个空间物体的第58组TLE。
(7)7:最后一位是校验位。
第2行主要元素解析如下:
(1)30323:北美防空司令部给出的卫星编号。
(2)025.0330:轨道倾角。
(3)358.9828:升交点赤经。
(4)7594216:轨道偏心率,0.7594216,表示这是一个椭圆。
(5)197.8808:近地点幅角。
102.7839:常用于表示卫星轨道运行状态的重要参数,在这组TLE对应的时间点上(即某一特定时间),它能够清晰地描述卫星在特定轨道上的位置特征,并与经过近地点的时间点之间也可以相互推导。
卫星运行轨道参数中的第7个元素值为01.92847527;其倒数值即为该卫星运行的轨道周期;从数据来看;这颗北斗卫星目前的运行周期约为12小时(相当于0.5天);而根据轨道力学原理;两者之间存在直接的比例关系;因此;TLE中记录的各项轨道参数与其前面所述的各项参数之间可以通过相互推导实现完全转换
(8)65:发射以来飞行的圈数。
(9)0:校验位。
2.KML文件格式
KML(Keyhole Markup Language, Keyhole标记语言)最初由Google的Keyhole公司开发和维护。它基于XML语法描述地理空间数据(包括点、线、面、多边形和模型等),适用于网络环境下的地理信息协作与共享。2008年4月,KML版本2.2经开放地理信息联盟定为标准并由其维护发展。众多GIS相关企业采用该格式交换地理数据。
KML文件能够被Google Earth和Google Maps解析并呈现其内容。
网页浏览器处理HTML和XML文件的方式类似于Google Earth和Google Maps处理KML文件的方式。
像HTML一样,KML使用带有名称、属性的标签来定义展示方式;因此,可以把Google Earth和Google Maps看作是KML文件的浏览器。
都可以采用Google Earth软件自动生成KML文件的方式,并非只能依赖于单独使用XML格式或简单文本编辑工具来完成原始KML文件的手动编写。
*KML 文件中的标记对区分大小写极为敏感,并且必须成对出现才能正确嵌套。
*KML 文件分为两种基本类型的标记:单一标记和复合标记。
其中复合标记名称的第一个字母必须大写;而单一标记全部为小写字母。
此外,在层次结构上,
复合标记能够包含其他类型(单一或复合)的子项,
但单一标签名可作为父项包含在其他复合标中,
且单个元素本身无法同时拥有多个父项。
一个 KML 文件只能拥有一个主标号,
它可以用
也可以选用
beckley挑战题给出的remote.kml文件如下:
HackASatCompetition
0
0
HackASatComp1 < NetworkLink>
View Centered Placemark
0
0
This is where the satellite was located when we saw it.
0
0 < LookAt id="ID">
FILL ME IN
FILL ME IN TOO
FILL ME IN AS WELL
FILL IN THIS VALUE
FILL IN THIS VALUE TOO
FILL IN THIS VALUE ALSO
clampToGround < /LookAt>
< Link>
http://FILL ME IN:FILL ME IN /cgi-bin/HSCKML.py
1
onStop
1
BBOX=[bboxWest],[bboxSouth],[bboxEast],[bboxNorth];CAMERA= [lookatLon], [lookatLat],[lookatRange],[lookatTilt],[lookatHeading];VIEW=[horizFov],[vertFov],[horizPixels],[vertPixels],[terrainEnabled]
< /Link>
< /NetworkLink>
为了避免读者受到过多信息的影响, 本书专门着重讲解remote.kml文件中包含其子元素
1)
该网络链接节点(
2)
0
0
0
clampToGround
图2-5展示了KML文件中

图2-5 KML文件中
longitude, latitude, altitude, altitudeMode 分别表示所查看的位置。 longitude 指定 -180° 到 180° 的经度范围; latitude 指定 -90° 到 90° 的纬度范围; altitude 表示位置相对于地平面的高度(单位:米)。 altitude 通常会附加一个 altitudeMode 元素。
- 基于地面的高度测量。
- 绝对高度测量是从海平面以上进行的。
- 相对于海底的高度测量。
- clampToGround和clampToSeaFloor均表示高度可忽略。其中,在clampToGround模式下,默认情况下所有未指定的高度值会被忽略,并使KML地图项按照地形安置在地面上。
该指标定义了视点至景点连线与景点处法线之间的夹角关系,并规定了该指标的具体取值区间限定在[0^\circ, 90^\circ]之间。具体而言,当角度为0^\circ时表明视点直立于景点上方位置;而当角度达到90^\circ时则显示视点处于水平视线位置。
明确指出视图方向是否为北面朝上:如果视图方向是北面朝上,则设置为默认值0^\circ;否则需指定一个从0^\circ到360^\circ(不包含)的角度(如图2-6所示)。

图2-6
3)元素
如果一个元素的直接父元素是
...
onChange
4
never
4
1
BBOX=[bboxWest],[bboxSouth],[bboxEast],[bboxNorth]
...
- changeOnLoadAndLinkUpdate(default value):this action is triggered during file loading and when the 's parameters are updated.
- intervalTriggered:this event occurs every n seconds, where n is specified by the
. - expiredTimeEvent:this event takes place when the element reaches its expiration time.
specifies the refresh interval for elements. defines how a view change will affect the , with possible values: - never(default setting):disables both view changes and format changes based on view updates.
- onStop:this event is triggered n seconds after stopping motion, where n is set by the
. - onRequest:this action happens only when a user explicitly requests it.
- onRegion:this event is triggered when Region becomes active.
对于获取KML文件的操作,在href后面设置了作为查询参数形式的默认值。特别地,在特定条件下即当viewRefreshMode设置为onStop且原始数据中未包含对应的format标记符时,默认会在该位置添加相应的query string。
BBOX=[bboxWest],[bboxSouth],[bboxEast],[bboxNorth]
当
在自定义查询字符串中,可以组合使用下列参数:
- 观察的位置:
目标点的具体经纬度信息。 所涉及的关键参数:通过 指定观察距离, 设定仰角, 调整朝向角度。 - 视点信息:记录视点的具体坐标数据。
- 视野参数:
与 分别表示水平方向上的视场角度和像素数量, 与 对应垂直方向的信息。 - 像素配置:
: 3D图形显示区域在水平和垂直方向上的像素尺寸设置。 - 地形显示设置:
: 确定是否启用地形起伏细节渲染选项。
The
熟悉了KML文件的基本结构后
3.Python的Skyfield库
该天文工具采用纯Python语言开发,并可用来精确计算行星、恒星以及运行中的卫星的位置信息。
其精度可与美国海军天文台及官方天文学年历相媲美。
误差不超过半个毫秒弧度。
该库完全基于Python开发。
无需额外编译步骤即可方便地安装使用。
兼容性良好,在Py2.6至Py3环境中均可运行。
该库仅以NumPy作为二进制辅助库。
而NumPy则提供了基础的数据处理功能。
这些高效的矢量化运算能力使得Skyfield成为一个强大的工具。
Skyfield中的EarthSatellite对象能够从TLE文件中获取卫星轨道参数,并采用SGP4轨道动力学模型计算地球卫星的位置。特别需要注意每组TLE轨道根数对应的epoch时刻(即该组参数最精确的时间点),因为该算法的有效时间窗口仅为一周多一点。对于未来的时间段内(这指的是未来几周内),应定期更新对应时间段的TLE数据以维持预测精度;而较早的历史时段,则需要提取存档中的相应旧版本数据来进行预测。
查询某一时刻卫星在地心天球参考系中x、y、z坐标的代码如下:
from skyfield.api import EarthSatellite
from skyfield.api import load
ts = load.timescale()
line1 = '1 25544U 98067A 14020.93268519 .00009878 00000-0 18200-3 0 5082'
line2 = '2 25544 51.6498 109.4756 0003572 55.9686 274.8005 15.49815350868473'
#从TLE数据中加载卫星轨道元素
satellite = EarthSatellite(line1, line2, 'ISS (ZARYA)', ts)
print(satellite)
t = ts.utc(2014, 1, 23, 11, 18, 7)
geocentric = satellite.at(t)
print(geocentric.position.km)
运行输出结果如下:
ISS (ZARYA) catalog #25544 epoch 2014-01-20 22:23:04 UTC
[-3918.87650458 -1887.64838745 5209.08801512]
为了了解某一时刻从地面观测者的纬度经度位置出发判断该卫星是位于地平线之上还是之下以及确定其方位我们可以采用以下方法:首先构建一个Topos对象用于表示观察者的地理位置随后通过向量减法计算出卫星相对于观测者的相对位置
在图2-7所示位置为中心点建立坐标系后,在三个坐标轴分别指向正东、正北以及正天方向的基础上进行测量和计算工作。随后可由此坐标系计算卫星的高度角(altitude)、方位角(azimuth)以及卫星与观察者的距离(distance)。其中高度角是从地平线零度延伸至天顶90度之间变化的参数值;而方位角则以顺时针方向绕地平线测量的角度值表示,在地理上通常以北方为基准点(即0°),依次向东增加至东方90°、南方180°和西方270°的位置点上。

图2-7 卫星在观察者坐标系中的表示
具体实现代码如下:
引入模块 skyfield.api 中的 Topos 类别
定义位置参数 bluffton 为地理坐标 38.8894838 北纬 和 77.0352791 西经 的 Topos 实例
计算 satellite 和 bluffton 之间的距离差值并存储于变量 difference
调用 difference 在时间 t 的天体坐标属性以获取 topocentric 对象
拆分 topocentric 的 altaz 方法返回值为 alt 角度 az 角度 和 distance 距离 变量
题目解析
这道题目旨在让参赛者在Google Earth平台内使用KML文件模拟卫星的角度拍摄。具体而言,也就是以卫星拍照位置为观察点。参赛者需要在KML文档中的LookAt字段中设置一个虚拟相机模型,关键在于通过精确计算longitude(latitude) altitude heading tilt和range参数来确定最佳拍摄视角
用
这道题目包含了拍照卫星的技术参数TLE以及拍照时间信息,并借助Skyfield软件求得了在特定时刻卫星相对于华盛顿纪念碑的高度角altitude、方位角azimuth以及卫星与观察者之间的距离distance。
我们用

图2-8 tilt角与altitude角的关系
对应于方位角azimuth所代表的角度与其对应的角度相差恰为180°, 其换算结果为...
具体实现代码如下:
from skyfield.api import EarthSatellite
from skyfield.api import load
from skyfield.api import Topos
ts = load.timescale()
line1 = '1 13337U 98067A 20087.38052801 -.00000452 00000-0 00000+0 0 9995'
line2 = '2 13337 51.6460 33.2488 0005270 61.9928 83.3154 15.48919755219337'
satellite = EarthSatellite(line1, line2, 'REDACT', ts)
EarthSatellite是一个Skyfield向量函数,使用SGP4简化模式模型,可以调用EarthSatellite的
at()方法来生成卫星在天空中的位置,也可以使用加减法来与其他向量组合
ts是一个时间刻度对象,用于生成epoch值
t = ts.utc(2020, 3, 26, 21, 52, 55)
photo = Topos('38.8894838 N', '77.0352791 W')
difference = satellite - photo
topocentric = difference.at(t)
alt, az, distance = topocentric.altaz()
print('Altitude(deg): %f' % alt.degrees)
print('Azimuth(def): %f' % az.degrees)
print('Range(m): %d' % int(distance.m))
tilt = 90 - alt.degrees
print('Tilt(deg): %f' % tilt)
heading = (180 + az.degrees) % 360
print('Heading(deg): %f' % heading)
运行上述代码,程序输出如下所示:
Altitude(deg): 40.033412
Azimuth(def): 240.186614
Range(m): 625347
Tilt(deg): 49.966588
Heading(deg): 60.186614
更新remote.kml文件,其
将主办方提供的服务器IP地址和端口号包含于remote.kml文件中的

图2-9 Google Earth Pro客户端软件导入KML文件后的界面
单击CLICK FOR FLAG地标,最终获取到flag值,如图2-10所示。

图2-10 beckley挑战题通过Google Earth Pro客户端获取到的flag
