第2章 天体测量信息安全挑战
2.1 模拟卫星视角——beckley
2.1.1 题目介绍
Fire up your Google Earth and brush up on your KML tutorials,we’re going to make it look at things!
题目描述得很简略,主办方希望参赛者利用Google Earth软件和KML文件找到设置的flag。给出的资料有:
(1)一个命名为static的文件夹,其中只有一个文件remote.kml,从后缀名可知,该文件是KML(Keyhole Markup Language,Keyhole标记语言)文件,KML是专门用于描述和保存地理信息的文件格式,其详细情况会在下文介绍。
(2)一个链接地址,使用nc连接到主办方给出的链接后,会得到进一步提示,如图2-1所示。
图2-1 beckley挑战题的提示信息
这段提示的内容就是告诉参赛者,当前截获了一颗卫星拍摄到的美国华盛顿纪念碑的照片,并且知道了这颗卫星的TLE(Two-Line Element,两行轨道根数)及照片的拍摄时间,要求参赛者在Google Earth中模拟卫星的拍摄角度、拍摄时间找flag信息。
2.1.2 编译及测试
这道挑战题的代码位于beckley目录下,在该目录下打开终端,执行如下命令:
接着执行make test命令进行测试,输出结果如图2-2所示,可以发现测试中是使用curl工具访问Google Earth的,通过解析返回的信息,最终得到flag。
图2-2 beckley挑战题测试输出结果
为了更加清晰地显示解题过程,可以分开测试。
(1)打开一个终端,执行如下命令,其中端口号、flag值都可以随意设置,该命令的作用是运行一个beckley挑战题服务端容器。
(2)打开另一个终端,模拟参赛者,执行命令nc 172.17.0.1 19020,其中地址、端口就是第(1)步中启动服务端容器时设置的参数,其输出结果如图2-1所示,会给出题目的进一步提示。
(3)再打开一个终端,执行如下命令,该命令使用curl工具访问在第(2)步中提示的URL地址,其实是服务端容器模拟的Google Earth服务器地址。
curl工具在URL地址后加入了很多参数,其中重要的是CAMERA参数,可以发现其由5个数字组成。在主办方提供的remote.kml文件中有如下描述,与curl工具使用的CAMERA参数很像,这是重点,具体含义会在下文分析中涉及。
命令被执行后,会返回KML格式的结果,如图2-3所示,从图中可以看出,在其中的<Placemark>标签的子标签<description>内给出了flag信息。
图2-3 beckley挑战题获取的flag
2.1.3 相关背景知识
1.卫星轨道和TLE
太空中的卫星在地球引力等各种力的作用下做周期运动,一阶近似就是一个开普勒椭圆轨道。由于其他力(如大气阻力、其他星球的引力等)的存在,实际的轨道和理想的开普勒轨道有偏离,称为“轨道摄动”。这里我们暂时不考虑摄动,只考虑理想开普勒轨道的情况。
为了确定一颗卫星的运行轨道,需要6个轨道参数,卫星运行轨道参数示意图如图2-4所示。
(1)描述轨道大小的参数——轨道半长轴a。
轨道半长轴是椭圆长轴的一半。轨道半长轴与轨道周期具有对应关系,半长轴越大,轨道周期越长。
(2)描述轨道形状的参数——轨道偏心率e。
偏心率是指椭圆两焦点的距离与长轴的比值。偏心率为0时,轨道是圆;偏心率为0~1时,轨道是椭圆;偏心率为1时,轨道是抛物线;偏心率大于1时,轨道是双曲线。
图2-4 卫星运行轨道参数示意图
(3)描述轨道平面在空间方位的参数——轨道倾角i和升交点赤经Ω。
轨道倾角是指轨道平面和地球赤道平面的夹角。倾角小于90°时,为顺行轨道,卫星总是从西(西南或西北)向东(东北或东南)运行;倾角大于90°时,为逆行轨道,卫星的运行方向与顺行轨道相反;倾角为0°时,为赤道轨道;倾角为90°时,为极轨道。
升交点赤经是指轨道升交点和春分点对地心的张角。卫星从南半球运行到北半球时穿过赤道平面的那一点称为升交点。轨道倾角和升交点赤经共同决定轨道平面在空间的方位。
(4)描述轨道在轨道平面内方位的参数——近地点幅角ω。
近地点幅角是指近地点和升交点对地心的张角。轨道倾角和升交点赤经虽然决定了轨道平面在空间的位置,但是轨道本身在轨道平面中还可以转动,而这个值则确定了轨道在轨道平面中的位置。
(5)描述卫星在轨道上位置的参数——过近地点时刻τ。
过近地点时刻是指卫星经过近地点的时刻,它以年、月、日、时、分、秒表示。卫星位置随时间的变化需要一个初值,即运动时间起算点,可以利用开普勒方程计算出卫星在τ+t时刻的轨道位置和速度。
值得注意的是,上面的6个参数并不是唯一可以描述卫星轨道情况的参数,也可以选取其他参数,上面选取的这组参数是比较自然的一组。
TLE(Two-Line Element,两行轨道根数)用来记录卫星星历信息,覆盖了气象卫星、海洋卫星、地球资源卫星、教育卫星等应用卫星。其结构为3行,首行数据为卫星名称,后面两行存储了卫星相关数据,每行69个字符,包括0~9、A~Z(大写)、空格、点和正负号。
以北斗的某颗卫星的TLE数据为例,数据如下:
第1行主要元素解析如下所述。
(1)30323U:30323是北美防空司令部给出的卫星编号。U表示不保密。我们看到的都是U,否则我们就不会看到这组TLE了。
(2)07003A:国际编号,07表示2007年;003表示这一年的第3次发射;A表示这次发射编号为A的物体,其他还有B、C、D等。国际编号就是2007-003A。
(3)07067.68277059:这组轨道数据的时间点,07表示2007年;067表示第67天,也就是3月8日;68277059表示这一天的时刻,大约是16时22分左右。
(4).00069181 13771-5 44016-2:轨道模型参数,分别表示平均运动的一阶时间导数除2、平均运动的二阶时间导数除6(0.13771E-5)、BSTAR拖调制系数(0.44016E-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:近地点幅角。
(6)102.7839:平近点角,表示这组TLE对应的时刻,卫星在轨道的什么位置。它和参数过近地点时刻可以互相推导。
(7)01.92847527:每天环绕地球的圈数。它的倒数就是卫星运行的轨道周期。可以看出,这颗北斗卫星目前的周期大约是12h(0.5天)。周期和轨道半长轴有简单的换算关系,因此TLE的关于轨道的6要素和我们前面说的6要素是完全可以互相推导的。
(8)65:发射以来飞行的圈数。
(9)0:校验位。
2.KML文件格式
KML(Keyhole Markup Language,Keyhole标记语言)最初是由Google旗下的Keyhole公司开发和维护的一种基于XML的标记语言。它利用XML语法格式描述地理空间数据(如点、线、面、多边形和模型等),适合网络环境下的地理信息协作与共享。2008年4月,KML的2.2版本被开放地理信息联盟(Open Geospatial Consortium,OGC)宣布为开放地理信息编码标准,并改由OGC 维护和发展。现在很多GIS相关企业也采用此种格式进行地理数据的交换。
KML文件可以被Google Earth和Google Maps识别并显示。Google Earth和Google Maps处理KML文件的方式与网页浏览器处理HTML和XML文件的方式类似。像HTML一样,KML使用包含名称、属性的标签来确定显示方式。因此,可将Google Earth和Google Maps视为 KML文件浏览器。
既可以使用Google Earth创建KML文件,也可以使用XML或简单的文本编辑器从头输入“原始”KML。KML文件的语法与XML的语法基本相同,有以下几点需要注意的地方。
● KML文件的标签是大小写敏感的,且必须成对使用,必须正确嵌套。
● KML文件有两种基本的标签类型——单一标签和复合标签。复合标签的标签名首字母要大写,而单一标签都是小写的;复合标签能够作为其他标签(单一标签或复合标签)的父元素,而单一标签只能是其他复合标签的子元素,自身不能包含其他元素。
● KML文件只有一个根标签,可以使用<kml></kml>、<Document></Document>、<Folder></Folder>,甚至<Placemark></Placemark>作为根标签。
beckley挑战题给出的remote.kml文件如下:
为避免读者被太多信息干扰,本书只重点介绍在remote.kml文件中出现的<NetworkLink>元素及其子元素<LookAt>、<Link>的含义和用法,这也是解答beckley挑战题需要用到的背景知识。
1)<NetworkLink>元素
<NetworkLink>用于引用本地或远程服务器上的KML文件。可使用<Link>指定KML文件的位置。
2)<LookAt>元素
<LookAt>用于定义一个虚拟相机,指定地球上正被查看的景点(对于本题,读者可以将景点理解为美国华盛顿纪念碑)与视点(对于本题,读者可以将视点理解为卫星)间的距离及视图的角度。该元素的语法如下:
图2-5展示了KML文件中<LookAt>对视点的构建方式。
图2-5 KML文件中<LookAt>对视点的构建方式
<longitude>、<latitude>、<altitude>、<altitudeMode>分别指出了被查看的景点的经度、纬度、高度和高度模式的值。<longitude>指定-180°~180°的经度值;<latitude>指定-90°~90°的纬度值;<altitude>指定景点高出地平面、海平面或海底的高度值,其单位为m。通常,<altitude>都会随附一个<altitudeMode>,该元素可告知Google Earth如何解析高度值。<altitudeMode>的取值如下所示。
● relativeToGround:表示从地球表面测量。
● absolute:表示从海平面上方测量。
● relativeToSeaFloor:表示从主水体的底部测量。
● clampToGround和clampToSeaFloor:表示高度可忽略。clampToGround模式会忽略所有高度值,并将KML地图项沿地形放置在地面上。在默认情况下,所有未指定高度模式的KML地图项都将使用clampToGround模式。
<range>指出了视点到景点的距离,其单位为m。
<tilt>指出了视点到景点的连线与景点处法线的夹角,其取值范围为[0°,90°],0°表示视点从正上方看景点,90°表示视点沿水平线看景点。
<heading>指出了视图方向是否是北面朝上,若是北面朝上,则使用默认值0°;若不是北面朝上,则指定一个0°(不含)到360°的旋转值,如图2-6所示。
图2-6 <heading>元素的含义图解
3)<Link>元素
当<Link>的父元素是<NetworkLink>时,<Link>用于指定KML文件的位置。该元素的语法如下:
<href>指定一个URL地址,当<Link>的父元素是<NetworkLink>时,<href>为KML文件的URL地址。
<refreshMode>指定一种基于时间的刷新模式,可以是以下模式之一。
● onChange(默认值):在加载文件和更改<Link>参数时刷新。
● onInterval:每n秒刷新一次(n在<refreshInterval>中指定)。
● onExpire:在达到过期时间时,将刷新该文件。
<refreshInterval>定义几秒钟刷新一次<href>指定的文件。
<viewRefreshMode>定义当相机发生变化时,<Link>如何刷新,可取如下的值。
● never(默认值):忽略视图的变化,同时忽略<viewFormat>中的参数。
● onStop:在移动停止的n秒后刷新<href>指定的文件,n由<viewRefreshTime>设置。
● onRequest:仅当用户明确请求时才刷新KML文件。
● onRegion:当Region变为active时刷新KML文件。
<viewRefreshTime>设置当<viewRefreshMode>为onStop时,或者相机移动停止后,需等待几秒再刷新KML文件。
<viewFormat>指定在获取KML文件时,附加在<href>后面的查询字符串的格式。当<viewRefreshMode>的值为onStop,但KML文件不包含<viewFormat>标签时,将自动附加下面的查询字符串:
若<viewFormat>标签的值为空,则不会附加任何查询字符串。可以自定义查询字符串替换BBOX参数,或者自定义查询字符串和BBOX参数共存。
在自定义查询字符串中,可以组合使用下列参数。
● [lookatLon]、[lookatLat]:<LookAt>观测的景点的经纬度。
● [lookatRange]、[lookatTilt]、[lookatHeading]:<LookAt>使用的几个值,相关描述见<LookAt>的<range>、<tilt>、<heading>。
● [cameraLon]、[cameraLat]、[cameraAlt]:视点的坐标。
● [horizFov]、[vertFov]:视点的水平、垂直视场。
● [horizPixels]、[vertPixels]:3D视图的像素尺寸。
● [terrainEnabled]:指定3D视图是否显示地形起伏。
<viewBoundScale>指定在将BBOX参数发送到服务器前如何对其进行缩放。小于1的值表示使用小于完整视图(屏幕)的值;大于1的值表示提取超出当前视图边缘的区域。
了解了KML文件格式,再回头观察主办方提供的remote.kml文件(前文已给出全部内容),可以看出,该文件中有8处标注“FILL IN”的位置,需要参赛者根据题目要求在这些位置处输入正确的参数值。前6处是要在<LookAt>内填写子标签<longitude>、<latitude>、<altitude>、<heading>、<tilt>和<range>的参数值,从而将卫星拍照的位置定义为视点,将美国华盛顿纪念碑作为景点。后2处是要在<Link>的子标签<href>中填写主办方所给出的服务器IP地址和端口号。
3.Python的Skyfield库
Skyfield是一个用于计算恒星、行星和在轨卫星位置的天文学Python库,其计算结果与美国海军天文台及其天文年历一致,误差在0.0005"以内。Skyfield用纯Python编写,无须任何编译即可安装,支持Python 2.6、Python 2.7和Python 3。Skyfield唯一的二进制依赖项是NumPy,NumPy是使用Python进行科学计算的一个基本包,它提供的向量计算功能使Skyfield更加高效。
Skyfield的EarthSatellite对象能够从TLE文件中加载卫星轨道元素,并通过SGP4轨道模型算法来预测地球卫星的位置。需要注意每个TLE轨道根数的epoch点(这组轨道参数最准确的时间点),因为预测仅在epoch点前后一两周内有效。对于以后的日期,需要下载一组新的TLE轨道根数来预测,而对于较早的日期,需要从存档中提取旧的TLE轨道根数来预测。
查询某一时刻卫星在地心天球参考系中X、Y、Z坐标的代码如下:
输出结果如下:
如果想查询在某一时刻,从地面上的观察者位置来看,这颗卫星是在地平线上方还是地平线下方及从哪个方向寻找它,可以先构建一个Topos对象来表示观察者的纬度和经度,然后使用向量减法来确定卫星相对于观察者的位置。
如图2-7所示,以观察者为中心建立坐标系,3个坐标轴分别指向相互垂直的东向、北向和天向,可以计算出卫星在此坐标系中的高度角altitude和方位角azimuth及卫星到观察者的距离distance。高度角从地平线的0°到天顶正上方的90°,负高度角表示卫星在观察者所在地平线以下。方位角是围绕地平线顺时针测量的,就像指南针上显示的度数一样,从地理上的北(0°)到东(90°)、南(180°)和西(270°),然后返回北,从359°回到0°。
图2-7 卫星在观察者坐标系中的表示
具体实现代码如下:
2.1.4 题目解析
这道题目其实就是让参赛者在Google Earth中利用KML文件模拟卫星的拍摄角度。具体而言,就是将卫星拍照的位置作为视点,将华盛顿纪念碑作为景点,在KML文件的<LookAt>中定义一个虚拟相机,关键是计算出<longitude>、<latitude>、<altitude>、<heading>、<tilt>和<range>的值。
<longitude>、<latitude>分别表示景点的经度、纬度,填入美国华盛顿纪念碑的经度值和纬度值即可;因为所给KML文件中<altitudeMode>的值为clampToGround,表示忽略高度,所以<altitude>的值为0。只有<heading>、<tilt>和<range>的值需要计算。
这道题目提供了拍照卫星的TLE和拍照时间,可以利用这些数据通过Skyfield计算出给出的特定时刻,以及卫星相对于美国华盛顿纪念碑的高度角altitude、方位角azimuth和卫星到观察者的距离distance。
<tilt>表示视点到景点的连线与景点处法线的夹角,<tilt>值与高度角altitude的关系如图2-8所示,所以其值为90°减去altitude的值。
图2-8 <tilt>角与高度角altitude的关系
<heading>表示的角度与方位角azimuth表示的角度正好相差180°,也可通过换算求得。
具体实现代码如下:
运行上述代码,程序输出如下所示:
更新remote.kml文件,其<LookAt>应为:
将主办方所给出的服务器IP地址和端口号写入remote.kml文件的<herf>中,打开Google Earth客户端软件,导入更新后的remote.kml文件,获得一个名为CLICK FOR FLAG的地标,如图2-9所示。
图2-9 Google Earth客户端软件导入KML文件后获得的地标
单击CLICK FOR FLAG地标,最终获取了flag值,如图2-10所示。
图2-10 beckley挑战题通过Google Earth客户端获取的flag