|
| 1 | +from pwn import * |
| 2 | +from skyfield.api import load, wgs84 |
| 3 | +from skyfield.framelib import ecliptic_J2000_frame |
| 4 | +from math import floor |
| 5 | +import numpy as np |
| 6 | +from math import sin, cos, acos, sqrt |
| 7 | +from numpy.linalg import norm |
| 8 | +from numpy import sqrt, dot, cross |
| 9 | +from skyfield.framelib import \ |
| 10 | +true_equator_and_equinox_of_date as of_date |
| 11 | + |
| 12 | +def proj(u, v): |
| 13 | +v_norm = np.linalg.norm(v) |
| 14 | +return (np.dot(u, v) / v_norm**2) * v |
| 15 | + |
| 16 | +r = remote("crosslinks2.satellitesabove.me", 5400) |
| 17 | +r.recvline() |
| 18 | +r.sendline(b"ticket{oscar561388quebec3:GAaopaxYK9ldU3wbbDC6XAqeccNoornlfDo_jptrIyXfq-B-yjLnteC7KLBkgFZzzg}") |
| 19 | +data = r.recvuntil(b"What's my position").replace(b"What's my position", b"").strip() |
| 20 | + |
| 21 | +tles = data.split(b"TLE")[1].split(b"Measurements")[0].strip() |
| 22 | +with open("comms.tle", "wb") as f: |
| 23 | +f.write(tles) |
| 24 | + |
| 25 | +t = load.timescale() |
| 26 | + |
| 27 | +observations = {} |
| 28 | +for i in data.split(b"Measurements")[1].strip().split(b"\n"): |
| 29 | +if b"Observations" in i: |
| 30 | +cur_sat = int(i.split(b"-")[-1]) |
| 31 | +observations[cur_sat] = [] |
| 32 | +if b"Time, " in i: |
| 33 | +continue |
| 34 | +if i.startswith(b"2022"): |
| 35 | +date, range_, range_rate = i.split(b", ") |
| 36 | +range_ = float(range_) |
| 37 | +range_rate = float(range_rate) |
| 38 | +year = int(date.split(b"-")[0]) |
| 39 | +month = int(date.split(b"-")[1]) |
| 40 | +day = int(date.split(b"-")[2].split(b"T")[0]) |
| 41 | + |
| 42 | +hour = int(date.split(b"T")[1].split(b":")[0]) |
| 43 | +minute = int(date.split(b"T")[1].split(b":")[1]) |
| 44 | +second = float(date.split(b"T")[1].split(b":")[2].split(b"+")[0]) |
| 45 | +ts = t.utc(year, month, day, hour, minute, second) |
| 46 | +observations[cur_sat].append((ts, range_, range_rate)) |
| 47 | + |
| 48 | +print(observations) |
| 49 | + |
| 50 | +comms = load.tle_file("comms.tle") |
| 51 | + |
| 52 | +sat_dic = {} |
| 53 | + |
| 54 | +for sat in comms: |
| 55 | +print(sat) |
| 56 | +key = int(str(sat).split("-")[1].split()[0]) |
| 57 | +sat_dic[key] = sat |
| 58 | + |
| 59 | +def trilaterate(P1,P2,P3,r1,r2,r3): |
| 60 | +temp1 = P2-P1 |
| 61 | +e_x = temp1/norm(temp1) |
| 62 | +temp2 = P3-P1 |
| 63 | +i = dot(e_x,temp2) |
| 64 | +temp3 = temp2 - i*e_x |
| 65 | +e_y = temp3/norm(temp3) |
| 66 | +e_z = cross(e_x,e_y) |
| 67 | +d = norm(P2-P1) |
| 68 | +j = dot(e_y,temp2) |
| 69 | +x = (r1*r1 - r2*r2 + d*d) / (2*d) |
| 70 | +y = (r1*r1 - r3*r3 -2*i*x + i*i + j*j) / (2*j) |
| 71 | +temp4 = r1*r1 - x*x - y*y |
| 72 | +if temp4<0: |
| 73 | +return None |
| 74 | +z = sqrt(temp4) |
| 75 | +p_12_a = P1 + x*e_x + y*e_y + z*e_z |
| 76 | +p_12_b = P1 + x*e_x + y*e_y - z*e_z |
| 77 | +return p_12_a,p_12_b |
| 78 | + |
| 79 | +def compute_radius(sat, t, d): |
| 80 | +pos = sat.at(t).position.to("km") |
| 81 | +vel = sat.at(t).velocity |
| 82 | +pos = pos.value |
| 83 | +x, y, z = pos |
| 84 | +radius = d |
| 85 | +origin = np.array(pos) |
| 86 | +return radius, origin |
| 87 | + |
| 88 | +def compute_rr_error(velocities, pos, pr=False): |
| 89 | +least_error = 9999999999999999999.0 |
| 90 | +win_num = 0 |
| 91 | +results = [] |
| 92 | +for vel in velocities: |
| 93 | +error = 0.0 |
| 94 | +for observe_num in observations: |
| 95 | +# sat_num observe observe_num |
| 96 | +for observation in observations[observe_num]: |
| 97 | +if observe_num not in sat_dic: |
| 98 | +continue |
| 99 | +ts, range_, range_rate = observation |
| 100 | +sat_loc = pos |
| 101 | +observe_loc = sat_dic[observe_num].at(ts).position.to("km").value |
| 102 | + |
| 103 | +# 'au_per_d', 'km_per_s', 'm_per_s' |
| 104 | +sat_vel = vel |
| 105 | +observe_vel = sat_dic[observe_num].at(ts).velocity.km_per_s |
| 106 | + |
| 107 | +p = proj(observe_vel - sat_vel, observe_loc - sat_loc) |
| 108 | +calc_range_rate = np.linalg.norm(p) |
| 109 | +unit_vec = np.dot(observe_vel - sat_vel, observe_loc - sat_loc) |
| 110 | +unit_vec = unit_vec / abs(unit_vec) |
| 111 | +calc_range_rate = np.linalg.norm(p) * unit_vec |
| 112 | + |
| 113 | +if pr: print("RR", calc_range_rate, range_rate) |
| 114 | + |
| 115 | +error += abs((calc_range_rate) - (range_rate)) |
| 116 | +# print("{},{},{}".format(vel[0], vel[1], vel[2]), error) |
| 117 | +results.append((error, "{},{},{}".format(vel[0], vel[1], vel[2]).encode())) |
| 118 | +if error < least_error: |
| 119 | +least_error = error |
| 120 | +win_num = vel |
| 121 | +results.sort() |
| 122 | + |
| 123 | +print(results[:200]) |
| 124 | +return win_num, least_error, results |
| 125 | + |
| 126 | +def compute_error(positions): |
| 127 | +least_error = 9999999999999999999.0 |
| 128 | +win_num = 0 |
| 129 | +results = [] |
| 130 | +for pos in positions: |
| 131 | +error = 0.0 |
| 132 | +for observe_num in observations: |
| 133 | +# sat_num observe observe_num |
| 134 | +for observation in observations[observe_num]: |
| 135 | +ts, range_, range_rate = observation |
| 136 | +observe_loc = sat_dic[observe_num].at(ts) |
| 137 | + |
| 138 | +sat_vec = pos |
| 139 | +observe_vec = np.array(observe_loc.position.to("km").value) |
| 140 | +distance = np.linalg.norm(sat_vec - observe_vec) |
| 141 | +error += (distance - range_)**2 |
| 142 | +print(pos, error) |
| 143 | +results.append((error, pos)) |
| 144 | +if error < least_error: |
| 145 | +least_error = error |
| 146 | +win_num = pos |
| 147 | +results.sort() |
| 148 | +for i in results[:1000]: |
| 149 | +print(i) |
| 150 | +return win_num, least_error, results |
| 151 | + |
| 152 | +poss_pos = [] |
| 153 | + |
| 154 | +keys = list(observations.keys()) |
| 155 | +for i in range(len(keys)): |
| 156 | +for j in range(len(keys)): |
| 157 | +for k in range(len(keys)): |
| 158 | +if i != j and j != k and i != k: |
| 159 | +r1, o1 = compute_radius(sat_dic[keys[i]], observations[keys[i]][0][0], observations[keys[i]][0][1]) |
| 160 | +r2, o2 = compute_radius(sat_dic[keys[j]], observations[keys[j]][0][0], observations[keys[j]][0][1]) |
| 161 | +r3, o3 = compute_radius(sat_dic[keys[k]], observations[keys[k]][0][0], observations[keys[k]][0][1]) |
| 162 | + |
| 163 | +res = trilaterate(o1, o2, o3, r1, r2, r3) |
| 164 | +if res is not None and not np.any(np.isnan(res[0])): |
| 165 | +bad1 = False |
| 166 | +bad2 = False |
| 167 | +for l in poss_pos: |
| 168 | +if np.linalg.norm(res[0] - l) < 5: |
| 169 | +bad1 = True |
| 170 | +if np.linalg.norm(res[1] - l) < 5: |
| 171 | +bad2 = True |
| 172 | +if bad1 and bad2: |
| 173 | +break |
| 174 | +if not bad1: |
| 175 | +poss_pos.append(res[0]) |
| 176 | +if not bad2: |
| 177 | +poss_pos.append(res[1]) |
| 178 | +if len(poss_pos) > 1000: |
| 179 | +break |
| 180 | +if len(poss_pos) > 1000: |
| 181 | +break |
| 182 | +if len(poss_pos) > 1000: |
| 183 | +break |
| 184 | +print(poss_pos) |
| 185 | +pos, error, pos_results = compute_error(poss_pos) |
| 186 | +pos_error = error |
| 187 | +print(pos, error) |
| 188 | +for i in pos_results[:200]: |
| 189 | +print(i) |
| 190 | + |
| 191 | +r.close() |
| 192 | + |
| 193 | +for pos_error, pos in pos_results[::4]: |
| 194 | + |
| 195 | +poss_vel = [] |
| 196 | +keys = list(observations.keys()) |
| 197 | + |
| 198 | +for i in range(len(keys)): |
| 199 | +for j in range(len(keys)): |
| 200 | +for k in range(len(keys)): |
| 201 | +if i != j and j != k and i != k: |
| 202 | +vo1 = sat_dic[keys[i]].at(ts).velocity.km_per_s |
| 203 | +vo2 = sat_dic[keys[j]].at(ts).velocity.km_per_s |
| 204 | +vo3 = sat_dic[keys[k]].at(ts).velocity.km_per_s |
| 205 | +# vo1 = np.reshape(vo1, (3, 1)) |
| 206 | +# vo2 = np.reshape(vo1, (3, 1)) |
| 207 | +# vo3 = np.reshape(vo1, (3, 1)) |
| 208 | + |
| 209 | +r1 = observations[keys[i]][0][2] |
| 210 | +r2 = observations[keys[j]][0][2] |
| 211 | +r3 = observations[keys[k]][0][2] |
| 212 | + |
| 213 | +rso_k1 = sat_dic[keys[i]].at(ts).position.to("km").value - pos |
| 214 | +rso_k2 = sat_dic[keys[j]].at(ts).position.to("km").value - pos |
| 215 | +rso_k3 = sat_dic[keys[k]].at(ts).position.to("km").value - pos |
| 216 | +# rso_k1 = np.reshape(rso_k1, (3, 1)) |
| 217 | +# rso_k2 = np.reshape(rso_k2, (3, 1)) |
| 218 | +# rso_k3 = np.reshape(rso_k3, (3, 1)) |
| 219 | + |
| 220 | +p1 = rso_k1 / np.linalg.norm(rso_k1) * r1 |
| 221 | +p2 = rso_k2 / np.linalg.norm(rso_k2) * r2 |
| 222 | +p3 = rso_k3 / np.linalg.norm(rso_k3) * r3 |
| 223 | + |
| 224 | +# p_matrix1 = (rso_k1 * (np.transpose(rso_k1) * rso_k1)[0][0]) @ np.transpose(rso_k1) |
| 225 | +# p_rhs1 = p_matrix1 @ vo1 - p1 |
| 226 | +# p_matrix2 = (rso_k2 * (np.transpose(rso_k2) * rso_k2)[0][0]) @ np.transpose(rso_k2) |
| 227 | +# p_rhs2 = p_matrix2 @ vo2 - p2 |
| 228 | +# p_matrix3 = (rso_k3 * (np.transpose(rso_k3) * rso_k3)[0][0]) @ np.transpose(rso_k3) |
| 229 | +# p_rhs3 = p_matrix3 @ vo3 - p3 |
| 230 | + |
| 231 | +# A = np.vstack((p_matrix1, p_matrix2, p_matrix3)) |
| 232 | +# B = np.vstack((p_rhs1, p_rhs2, p_rhs3)) |
| 233 | + |
| 234 | +v1 = rso_k1 * np.dot(vo1, rso_k1) / np.dot(rso_k1, rso_k1) - p1 |
| 235 | +v2 = rso_k2 * np.dot(vo2, rso_k2) / np.dot(rso_k2, rso_k2) - p2 |
| 236 | +v3 = rso_k3 * np.dot(vo3, rso_k3) / np.dot(rso_k3, rso_k3) - p3 |
| 237 | + |
| 238 | +w1 = np.linalg.norm(v1) * np.linalg.norm(rso_k1) |
| 239 | +w2 = np.linalg.norm(v2) * np.linalg.norm(rso_k2) |
| 240 | +w3 = np.linalg.norm(v3) * np.linalg.norm(rso_k3) |
| 241 | + |
| 242 | +mat = np.array([[*rso_k1], [*rso_k2], [*rso_k3]]) |
| 243 | +vec = np.array([w1, w2, w3]) |
| 244 | +sol = np.linalg.solve(mat, vec).reshape(3) |
| 245 | + |
| 246 | +# print(A.shape) |
| 247 | +# print(B.shape) |
| 248 | +# sol = np.linalg.solve(A, B) |
| 249 | + |
| 250 | +poss_vel.append(sol) |
| 251 | + |
| 252 | +if len(poss_vel) > 1000: |
| 253 | +break |
| 254 | +if len(poss_vel) > 1000: |
| 255 | +break |
| 256 | +if len(poss_vel) > 1000: |
| 257 | +break |
| 258 | +vel, error, results = compute_rr_error(poss_vel, pos) |
| 259 | +print(vel, error) |
| 260 | + |
| 261 | +print("POS: {},{},{} ERROR:{}".format(pos[0], pos[1], pos[2], pos_error)) |
| 262 | +print("VEL: {},{},{} ERROR:{}".format(vel[0], vel[1], vel[2], error)) |
| 263 | + |
| 264 | +compute_rr_error([vel], pos, True) |
| 265 | + |
| 266 | +for i in results[:3]: |
| 267 | +r = remote("crosslinks2.satellitesabove.me", 5400) |
| 268 | +r.recvline() |
| 269 | +r.sendline(b"ticket{oscar561388quebec3:GAaopaxYK9ldU3wbbDC6XAqeccNoornlfDo_jptrIyXfq-B-yjLnteC7KLBkgFZzzg}") |
| 270 | +data = r.recvuntil(b"What's my position").replace(b"What's my position", b"").strip() |
| 271 | + |
| 272 | +# pos = b"6676.958887049956,-2070.6729547915697,-11.891150202096647" |
| 273 | +print("SEND", pos, i[1]) |
| 274 | +r.recvuntil(b": ") |
| 275 | +r.sendline("{},{},{}".format(pos[0], pos[1], pos[2]).encode()) |
| 276 | +r.recvuntil(b": ") |
| 277 | +r.sendline(i[1]) |
| 278 | + |
| 279 | +res = r.recvline() + r.recvline() + r.recvline() + r.recvline() |
| 280 | +print(res) |
| 281 | +if b"Wrong!" not in res: |
| 282 | +print(b"WIN") |
| 283 | +r.interactive() |
| 284 | +r.close() |
0 commit comments