逛论坛发现了这本书: 好家伙,这不是日卫星吗,必须学一波
在 Github 搜了搜题目的源码:,准备复现一遍,这一关叫做模拟卫星视角,给了我们一个卫星拍摄时的TLE,我们通过谷歌地球去设置卫星视角观察得到 flag
环境搭建
进入 generator-base 之后运行docker build -t generator-base .
把基础的镜像生成出来
然后进入 beckley 文件夹把 solver 和 challenge 文件夹中的 Dockerfile 的 get-pip.py 的 url 换一下,换成:
我会把我用的最终版本放在 用这个就不用改 url 了
使用make build
生成镜像,也可以用make challenge
只生成题目镜像
使用apt install socat
安装 socat
使用以下命令运行环境
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-hPvlNKAdEJxcujvp9WK4rEchuEdlDp3yv_Wh_uvB5ehGq-fyRowvwkWpdAMTKbidqhK4JhFsaz1k} -p 19021\:80 beckley\:challenge"
咱也不知道这题是啥意思,按照 wp 先验证一下能不能拿到 flag,新开一个终端运行得到一些提示
nc 172.17.0.1 19020
然后运行下面的命令得到 flag
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'
如图所示
正式做题
按照 的描述,这道题环境搭建起来后你能看的就只有 static 文件夹里面的 remote.kml 和一个 172.17.0.1 19020 的地址
就从这两个提示开始入手,nc 连接之后获得了如下信息
We've captured data from a satellite that shows a flag located at the base of the Washington Monument.
The image was taken on March 26th, 2020, at 21:53:13
The satellite we used was:
REDACT
1 13337U 98067A 20087.38052801 -.00000452 00000-0 00000+0 0 9995
2 13337 51.6460 33.2488 0005270 61.9928 83.3154 15.48919755219337
Use a Google Earth Pro KML file to 'Link' to http://172.17.0.1:19021/cgi-bin/HSCKML.py
and 'LookAt' that spot from where the satellite when it took the photo and get us that flag!
大意是太空中有颗卫星于 2020 年 3 月 26 日 21:52:55 按照特定的视角拍到了华盛顿纪念碑,让我们通过 Google Earth Pro 的 KML 文件模拟卫星拍摄时的位置看一下华盛顿纪念碑从而获得 flag
Google Earth Pro 可以在这里下载到
KML 文件格式
可以在谷歌地球上新建一个地标,试试 kml 文件是怎么创建的,点击这个黄色的工字钉
然后随便在地图上找个点,把工字钉拖上去,随便写点名称和说明
然后将右键地图上的工字钉,保存的时候选择类型是 kml 格式
可以看到主要的位置信息就是在 LookAt 这个标签里面的,LookAt 就是你从哪个视角来观看这个地标的
对应的,在题目给的 remote.kml 文件中也是要我们修改这个位置的信息
longitude 是经度,不用解释吧
latitude 是纬度,不用解释吧
altitude 是海拔,不用解释吧
heading 是飞行器前进的方向
tilt 是卫星与地球表面法线之间的角度
range 是卫星距离目标的距离
altitudeMode 是高度模式,这个不用咱们改
还有一个在这里面没有体现出来的 <Link> 标签,这个是用来通过网络链接获取 KML 文件,那我们先把这个 link 换成 nc 连接上后获得的地址 ,选择文件 -> 打开 -> remote.kml 把临时位置的层级全部展开,可以看到一个地标是 Keep Looking... 说明咱还没找到正确的观察视角
双线元素集 (TLE)
接下来我们研究研究 LookAt 要怎么设置,就是卫星拍到华盛顿纪念碑时的位置,相关线索就是 nc 上去输出的两行信息,这个叫做双线元素集 (TLE),好家伙,专业知识来了
卫星双线元素集(TLE)是一种编码格式,用于在两行中存储卫星的轨道参数。这些轨道参数是由观测到的卫星运动数据计算得出的。TLE 可以用来预测卫星的运动,并用于各种应用,例如卫星导航和通信
REDACT
1 13337U 98067A 20087.38052801 -.00000452 00000-0 00000+0 0 9995
2 13337 51.6460 33.2488 0005270 61.9928 83.3154 15.48919755219337
我们做个表说明一下这些数据的含义(感觉给的这些数据对不太起来)
第 0 行 |
列 |
数据 |
描述 |
1-24 |
REDACT |
基于卫星目录的信息的对象的通用名称 |
第 1 行 |
列 |
数据 |
描述 |
1 |
1 |
行号 |
3-7 |
13337 |
北美防空司令部 的卫星编号 |
8 |
U |
U 非保密的,C 机密的,S 绝密的 |
10-17 |
98067A |
国际卫星标识符,98表示年,067表示这年第几次发射,A 表示卫星的第一部分 可以参考: |
19-32 |
20087.38052801 |
TLE历时,轨道数据的时间点,20 表示 20 年,087表示第 87 天(我咋算的 86 天),38052801 表示这一天的时刻 |
34-43 |
-.00000452 |
平均运动对时间的一阶导数 |
45-52 |
00000-0 |
平均运动对时间的二阶导数(假设有小数点) |
54-61 |
00000+0 |
BSTAR拖调制系数 |
63 |
0 |
美国空军空间指挥中心内部使用的为 1,美国空军空间指挥中心以外公开使用标识为 0 |
65-68 |
999 |
星历编号,星历编号是TLE数据按新发现卫星的先后顺序的编号 |
69 |
5 |
校验和,指这一行的所有非数字字符,按照“字母、空格、句点、正号= 0;负号=1”的规则换算成0和1后,将这一行中原来的全部数字加起来,以10为模计算后所得的和 |
第 2 行 |
列 |
数据 |
描述 |
1 |
2 |
行号 |
3-7 |
13337 |
北美防空司令部 的卫星编号 |
9-16 |
51.6460 |
轨道的交角度数,指天体的轨道面和地球赤道面之间的夹度 |
18-25 |
33.2488 |
升交点赤经度数,指从地球的球心点望过去,升交点的赤经坐标 |
27-33 |
0005270 |
轨道离心率,指卫星椭圆轨道的中心点到地球的球心点的距离(c)除以卫星轨道半长轴(a)得到的一个0(圆型)到1(抛物线)之间的小数值 |
35-42 |
61.9928 |
近地点角距,指在卫星的轨道平面内,从升交点到近地点按照卫星运行方向所走过的角度 |
44-51 |
83.3154 |
平近点角度数,指平近点角与真近点角和偏近点角之间的关系,即卫星在椭圆轨道上的瞬间位置 |
53-63 |
15.48919755 |
平均运动,指在一个太阳日内(24h),卫星在它的轨道上绕了多少圈 |
64-68 |
21933 |
在轨圈数,指卫星从发射到 TLE 数据记录的 TLE 历时之间卫星在轨道上绕行的总圈数 |
69 |
7 |
校验和 |
解析TLE得到卫星视角
我们需要通过给出的 TLE 数据填充 LookAt 中的信息,其中 longitude 和 latitude 是经纬度,直接在谷歌地球中找就行了,按照上面添加地标的方式添加保存为 KML 文件,再查看即可,纬度:38.88937190244597,经度:-77.03521514741283
同时因为 altitudeMode 是 clampToGround,表示可以忽略高度,因此 altitude 是 0
这意味着我们只需要解析出来 heading、tilt、range 即可,我们用 Python 来实现,参考这个库:
首先从字符集加载 TLE 数据,然后根据时间确定卫星在头顶的位置(注意这里的时间要用 nc 上去之后题目给我们的时间而不是 TLE 解析的时间),这里得到的位置是地心天球参考系中卫星的 x、y、z 坐标,也就是说是以地心为观察者视角得到的卫星的位置
from skyfield.api import EarthSatellite, load, 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'
# 从字符串加载TLE集
satellite = EarthSatellite(line1, line2, 'REDACT', ts)
print("\nsatellite:")
print(satellite)
# 通过卫星在头顶上面的时间确定卫星位置,这里按照题目提示时间 2020 年 3 月 26 日 21:52:55
t = ts.utc(2020, 3, 26, 21, 52, 55)
geocentric = satellite.at(t)
print("\ngeocentric.position.km:")
print(geocentric.position.km)
# 计算华盛顿纪念碑看卫星的角度
bluffton = Topos('38.88937190244597 N', '77.03521514741283 W')
huashengdun = bluffton.at(t)
print(huashengdun.position.km)
difference = satellite - bluffton # 这俩一减得到了华盛顿纪念碑和卫星之间的位置信息
topocentric = difference.at(t)
print(topocentric.position.km)
alt, az, distance = topocentric.altaz() # 通过altaz函数得到高度角、方位角、距离
print('\nAltitude: %f' % alt.degrees) # 高度角
print('Azimuth: %f' % az.degrees) # 方位角
print('Distance: %d' % int(distance.m)) # 距离
得到这个之后我们来看一下 heading 和 tilt 与高度角和方位角的关系,其中 tilt 与高度角是互补的,因此直接用 90 减去高度角就是 tilt
heading 是卫星前进的方向,与当前的方位角有个 180 度的差值,所以在 Azimuth 的基础上加上 180 度得到 heading(目前是这么理解的),再模 360 度是为了保证度数在 360 度之内
heading = (180 + az.degrees) % 360
print('\nHeading: %f' % heading)
tilt = 90 - alt.degrees
print('Tilt: %f' % tilt)
根据输出的结果修改 LookAt 中的值,然后用谷歌地球打开就可以看到 flag 了
<LookAt id="ID">
<longitude>-77.03</longitude>
<latitude>38.89</latitude>
<altitude>0</altitude>
<heading>63.532442</heading>
<tilt>40.371925</tilt>
<range>538562</range>
<altitudeMode>clampToGround</altitudeMode>
</LookAt>
参考