freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

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

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

FreeBuf+小程序

FreeBuf+小程序

有趣的黑掉卫星Hack-A-Sat CTF比赛——模拟卫星视角beckley
2022-11-11 22:48:47
所属地 甘肃省

以下内容是通过阅读《Hack-A-Sat太空信息安全挑战赛深度解题》做的测试。

题目介绍

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信息。

编译及测试

这道挑战题的代码位于beckley目录下,在该目录下打开终端,执行如下命令:

sudo make build

接着执行make test命令进行测试,输出如图2-2所示,可以发现测试中是使用curl工具访问Google Earth的,通过解析返回的信息,最终得到flag。

图2-2  beckley挑战题测试输出

为了更加清晰地显示解题过程,可以分开测试:

(1)打开一个终端,执行如下命令,其中端口号、flag值都可以随意设置,该命令的作用是运行一个beckley挑战题服务端容器。

socat -v tcp-listen:19020,reuseaddr exec:"docker run --rm -i -e SERVICE_HOST=172.17.0.1 -e SERVICE_PORT=19021 -e SEED=1000 -e FLAG=flag{zulu49225delta\:GG1EnNVMK3-hPvlNKAdEJxcujvp9WK

4rEchuEdlDp3yv_Wh_uvB5ehGq-fyRowvwkWpdAMTKbidqhK4JhFsaz1k} -p 19021\:80 beckley\:challenge"

(2)打开另一个终端,模拟参赛者,执行命令nc 172.17.0.1 19020,其中地址、端口就是第(1)步中启动服务端容器时设置的参数,其输出如图2-1所示,会给出题目进一步的提示。

(3)再打开一个终端,执行如下命令,该命令使用curl工具访问在第(2)步中提示的URL地址,其实是服务端容器模拟的Google Earth服务器地址。

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参数,可以发现其由5个数字组成。在主办方提供的remote.kml文件中有如下描述,与curl工具使用的CAMERA参数很像,这是重点,具体含义会在下文分析中涉及到。

CAMERA=[lookatLon],[lookatLat],[lookatRange],[lookatTilt],[lookatHeading]

命令执行后,会返回KML格式的结果,如图2-3所示,从图中可以看出,在其中的<Placemark>标签的子标签<description>内给出了flag信息。

图2-3  beckley挑战题获取到的flag

相关背景知识

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数据为例,数据如下:

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)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文件如下:

<?xml version="1.0" encoding="UTF-8"?>

<kml xmlns="http://www.opengis.net/kml/2.2">

<Folder>

<name>HackASatCompetition</name>

<visibility>0</visibility>

<open>0</open>

<description>HackASatComp1</description>

<NetworkLink>

<name>View Centered Placemark</name>

<visibility>0</visibility>

<open>0</open>

<description>This is where the satellite was located when we saw it.</description>

<refreshVisibility>0</refreshVisibility>

<flyToView>0</flyToView>

<LookAt id="ID">

<!-- specific to LookAt -->

<longitude>FILL ME IN</longitude>           <!-- kml:angle180 -->

<latitude>FILL ME IN TOO</latitude>         <!-- kml:angle90 -->

<altitude>FILL ME IN AS WELL</altitude>      <!-- double -->

<heading>FILL IN THIS VALUE</heading>         <!-- kml:angle360 -->

<tilt>FILL IN THIS VALUE TOO</tilt>           <!-- kml:anglepos90 -->

<range>FILL IN THIS VALUE ALSO</range>        <!-- double -->

<altitudeMode>clampToGround</altitudeMode>

</LookAt>

<Link>

<href>http://FILL ME IN:FILL ME IN/cgi-bin/HSCKML.py</href>

<refreshInterval>1</refreshInterval>

<viewRefreshMode>onStop</viewRefreshMode>

<viewRefreshTime>1</viewRefreshTime>

<viewFormat>BBOX=[bboxWest],[bboxSouth],[bboxEast],[bboxNorth];CAMERA= [lookatLon],

[lookatLat],[lookatRange],[lookatTilt],[lookatHeading];VIEW=[horizFov],[vertFov],[horizPixels],[vertPixels],[terrainEnabled]</viewFormat>

</Link>

</NetworkLink>

</Folder>

</kml>

为避免读者被太多信息干扰,本书只重点介绍在remote.kml文件中出现的<NetworkLink>元素及其子元素<LookAt>、<Link>的含义和用法,这也是解答beckley挑战题需要用到的背景知识。

1)<NetworkLink>元素

<NetworkLink>用于引用本地或远程服务器上的KML文件。可使用<Link>指定KML文件的位置。

2)<LookAt>元素

<LookAt>用于定义一个虚拟相机,指定地球上正被查看的景点(对于本题,读者可以将景点理解为华盛顿纪念碑)与视点(对于本题,读者可以将视点理解为卫星)间的距离及视图的角度。该元素的语法如下:

<LookAt id="ID">

<longitude></longitude>                      <!-- kml:angle180 -->

<latitude></latitude>                           <!-- kml:angle90 -->

<altitude>0</altitude>                          <!-- double -->

<range></range>                                  <!-- double -->

<tilt>0</tilt>                                   <!-- float -->

<heading>0</heading>                            <!-- float -->

<altitudeMode>clampToGround</altitudeMode>

<!--kml:altitudeModeEnum:clampToGround, relativeToGround, absolute -->

<!-- or, gx:altitudeMode can be substituted: clampToSeaFloor, relativeToSeaFloor -->

</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文件的位置。该元素的语法如下:

<Link id="ID">

<!-- specific to Link -->

<href>...</href>                         <!-- string -->

<refreshMode>onChange</refreshMode>

<!-- refreshModeEnum: onChange, onInterval, or onExpire -->

<refreshInterval>4</refreshInterval>   <!-- float -->

<viewRefreshMode>never</viewRefreshMode>

<!-- viewRefreshModeEnum: never, onStop, onRequest, onRegion -->

<viewRefreshTime>4</viewRefreshTime>   <!-- float -->

<viewBoundScale>1</viewBoundScale>     <!-- float -->

<viewFormat>BBOX=[bboxWest],[bboxSouth],[bboxEast],[bboxNorth]</viewFormat>

<!-- string -->

<httpQuery>...</httpQuery>                 <!-- string -->

</Link>

<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>标签时,将自动附加下面的查询字符串:

BBOX=[bboxWest],[bboxSouth],[bboxEast],[bboxNorth]

若<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坐标的代码如下:

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所示,以观察者为中心建立坐标系,3个坐标轴分别指向相互垂直的东向、北向和天向,可以计算出卫星在此坐标系中的高度角altitude和方位角azimuth及卫星到观察者的距离distance。高度角从地平线的0°到天顶正上方的90°,负高度角表示卫星在观察者所在地平线以下。方位角是围绕地平线顺时针测量的,就像指南针上显示的度数一样,从地理上的北(0°)到东(90°)、南(180°)和西(270°),然后返回北,从359°回到0°。

图2-7  卫星在观察者坐标系中的表示

具体实现代码如下:

from skyfield.api import Topos


bluffton = Topos('38.8894838 N', '77.0352791 W')

difference = satellite - bluffton

topocentric = difference.at(t)

alt, az, distance = topocentric.altaz()

题目解析

这道题目其实就是让参赛者在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°,也可通过换算求得。

具体实现代码如下:

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文件,其<LookAt>应为:

<LookAt id="ID">

<longitude>-77.0352791</longitude>

<latitude>38.8894838</latitude>

<altitude>0</altitude>

<heading>60.186614</heading>

<tilt>49.966588</tilt>

<range>625347</range>

<altitudeMode>clampToGround</altitudeMode>

</LookAt>

将主办方所给出的服务器IP地址和端口号写入remote.kml文件的<herf>中,打开Google Earth Pro客户端软件,导入更新后的remote.kml文件,获得一个名为CLICK FOR FLAG的地标,如图2-9所示。

图2-9 Google Earth Pro客户端软件导入KML文件后的界面

单击CLICK FOR FLAG地标,最终获取到flag值,如图2-10所示。

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

# CTF # 太空网络安全 # 太空 # 太空安全 # 太空战
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录