seeing stars
This commit is contained in:
parent
126e1e4fe0
commit
d60543a765
|
@ -0,0 +1,76 @@
|
||||||
|
# Seeing Stars
|
||||||
|
Here is the output from a CCD Camera from a star tracker, identify as many stars as you can! (in image reference coordinates)
|
||||||
|
Note: The camera prints pixels in the following order (x,y): (0,0), (1,0), (2,0)... (0,1), (1,1), (2,1)…
|
||||||
|
|
||||||
|
Note that top left corner is (0,0)
|
||||||
|
|
||||||
|
> nc stars.satellitesabove.me 5013
|
||||||
|
|
||||||
|
## Write-up
|
||||||
|
by [hazel (arcetera)](https://qtp2t.club/)
|
||||||
|
|
||||||
|
The CCD image given by the netcat is a 128x128 matrix of comma-separated values.
|
||||||
|
|
||||||
|
We read the data into a NumPy array, and pass that into OpenCV.
|
||||||
|
``` python
|
||||||
|
data = []
|
||||||
|
for line in rawdat.strip().split('\n'):
|
||||||
|
data.append([int(x) for x in line.split(',')])
|
||||||
|
|
||||||
|
x = np.array(data, dtype='uint8').T
|
||||||
|
|
||||||
|
im = x
|
||||||
|
```
|
||||||
|
|
||||||
|
We then run a filter on the data, only grabbing values in [127, 255] to filter
|
||||||
|
out data that is *obviously not* stars.
|
||||||
|
We then run two dilates on the image post-filter, because otherwise
|
||||||
|
we end up with a division by zero on centroid finding later for `M["m00"]`.
|
||||||
|
Finally, we grabbed the contour of every object visible in the image.
|
||||||
|
``` python
|
||||||
|
ret, thresh = cv2.threshold(im.copy(), 127, 255, 0)
|
||||||
|
kernel = np.ones((5, 5), np.uint8)
|
||||||
|
dilated = cv2.dilate(thresh.copy(), kernel, iterations = 2)
|
||||||
|
|
||||||
|
cnts, hier = cv2.findContours(dilated.copy(), \
|
||||||
|
cv2.RETR_TREE, \
|
||||||
|
cv2.CHAIN_APPROX_NONE)
|
||||||
|
```
|
||||||
|
|
||||||
|
For each contour, we grabbed its centroid:
|
||||||
|
``` python
|
||||||
|
solve = ''
|
||||||
|
for c in cnts:
|
||||||
|
M = cv2.moments(c)
|
||||||
|
cX = int(M["m10"] / M["m00"])
|
||||||
|
cY = int(M["m01"] / M["m00"])
|
||||||
|
|
||||||
|
solve += (str(cX) + "," + str(cY)+'\n')
|
||||||
|
return solve
|
||||||
|
```
|
||||||
|
|
||||||
|
We then automated this entire process using pwnlib to connect to the server and
|
||||||
|
read the data. Full exploit:
|
||||||
|
```{.python include=seeing-stars.py}
|
||||||
|
```
|
||||||
|
|
||||||
|
Run it:
|
||||||
|
```
|
||||||
|
λ has-writeup/aaaa/seeing-stars python seeing-stars.py
|
||||||
|
b'flag{juliet73678uniform:GDy7YZdtCL9mcLgYuLceK_zwgwSAoT6ui5aMGo1IMYcic9tiI8EXUHLfQDcUsjjt5KqsIvOWUYeM8IS6631Vppw}\n'
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "seeing-stars.py", line 42, in <module>
|
||||||
|
rawdat = r.recvuntil('Enter', drop=True)
|
||||||
|
File "/usr/lib/python3.8/site-packages/pwnlib/tubes/tube.py", line 310, in recvuntil
|
||||||
|
res = self.recv(timeout=self.timeout)
|
||||||
|
File "/usr/lib/python3.8/site-packages/pwnlib/tubes/tube.py", line 82, in recv
|
||||||
|
return self._recv(numb, timeout) or b''
|
||||||
|
File "/usr/lib/python3.8/site-packages/pwnlib/tubes/tube.py", line 160, in _recv
|
||||||
|
if not self.buffer and not self._fillbuffer(timeout):
|
||||||
|
File "/usr/lib/python3.8/site-packages/pwnlib/tubes/tube.py", line 131, in _fillbuffer
|
||||||
|
data = self.recv_raw(self.buffer.get_fill_size())
|
||||||
|
File "/usr/lib/python3.8/site-packages/pwnlib/tubes/sock.py", line 56, in recv_raw
|
||||||
|
raise EOFError
|
||||||
|
EOFError
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import cv2
|
||||||
|
import math
|
||||||
|
import numpy as np
|
||||||
|
from pwnlib import tubes
|
||||||
|
import time
|
||||||
|
|
||||||
|
def solve(rawdat):
|
||||||
|
data = []
|
||||||
|
for line in rawdat.strip().split('\n'):
|
||||||
|
data.append([int(x) for x in line.split(',')])
|
||||||
|
|
||||||
|
x = np.array(data, dtype='uint8').T
|
||||||
|
|
||||||
|
im = x # cv2.imread("output.png", cv2.IMREAD_GRAYSCALE)
|
||||||
|
ret, thresh = cv2.threshold(im.copy(), 127, 255, 0)
|
||||||
|
kernel = np.ones((5, 5), np.uint8)
|
||||||
|
dilated = cv2.dilate(thresh.copy(), kernel, iterations = 2)
|
||||||
|
|
||||||
|
cnts, hier = cv2.findContours(dilated.copy(), \
|
||||||
|
cv2.RETR_TREE, \
|
||||||
|
cv2.CHAIN_APPROX_NONE)
|
||||||
|
|
||||||
|
edit = thresh.copy()
|
||||||
|
cv2.drawContours(edit, cnts, -1, (0, 255, 0), 3)
|
||||||
|
|
||||||
|
solve = ''
|
||||||
|
for c in cnts:
|
||||||
|
M = cv2.moments(c)
|
||||||
|
cX = int(M["m10"] / M["m00"])
|
||||||
|
cY = int(M["m01"] / M["m00"])
|
||||||
|
|
||||||
|
solve += (str(cX) + "," + str(cY)+'\n')
|
||||||
|
return solve
|
||||||
|
|
||||||
|
TICKET = 'ticket{juliet73678uniform:GIE7kv0AbxY1I813dEkfLYg2PhHMnJcdqhouI2zuDG1md_2TQ1Ikgab5osJoTRFzIg}'
|
||||||
|
r = tubes.remote.remote('stars.satellitesabove.me', 5013)
|
||||||
|
r.recvline()
|
||||||
|
r.send(TICKET+'\n')
|
||||||
|
going = True
|
||||||
|
while going:
|
||||||
|
rawdat = r.recvuntil('Enter', drop=True)
|
||||||
|
time.sleep(0.5)
|
||||||
|
r.clean()
|
||||||
|
solution = solve(rawdat.decode())
|
||||||
|
r.send(solution+'\n')
|
||||||
|
time.sleep(0.1)
|
||||||
|
if r.recvuntil('Left...\n') == b'0 Left...\n':
|
||||||
|
time.sleep(0.1)
|
||||||
|
print(r.clean())
|
Loading…
Reference in New Issue