c0r3dump CTF writeups

CTF writeups by c0r3dump.

View on GitHub

SpamAndFlags 2020 - TAS

Challenge

Time to take a break from CTFing and play some videogames! How fast can you complete it??

Checker server: nc 35.242.182.148 1337

136+158+166+181+199+384 points, solved the first three (136+158+166).

Solution

Adding TAS features to game

I decided to start by adding some TAS features to the game, somewhat limited by my lack of python knowledge:

Here’s a diff for these features:

diff --git a/Game.py b/Game.py
index 8d1281b..91b7a08 100644
--- a/Game.py
+++ b/Game.py
@@ -42,9 +42,8 @@ class Game(object):
 
   def __del__(self):
     pygame.quit()
-    if (self.mode == "game"):
-      self.writeReplayFile("../replay.txt")
-      print("Wrote replay input to replay.txt", flush=True)
+    self.writeReplayFile("../replay.txt")
+    print("Wrote replay input to replay.txt", flush=True)
 
   def loadReplay(self):
     result = []
@@ -93,14 +92,16 @@ class Game(object):
         if event.type == pygame.locals.QUIT:
           return False
 
-    self.input.tick(events)
+    if self.input.tick(events) != True:
+        return True
+    
     for sprite in self.tickGroup.sprites():
       sprite.tick()
     self.map.tick()
     self.renderer.render()
 
     if self.mode != "check":
-      self.fpsClock.tick(Game.FPS)
+      self.fpsClock.tick(6000 if self.input.mode != "game" else Game.FPS)
 
     if self.won() or self.died() or self.reachedEndOfReplay():
       return False
diff --git a/Input.py b/Input.py
index 33cacb4..c25ac01 100644
--- a/Input.py
+++ b/Input.py
@@ -19,21 +19,24 @@ class KeysPressed():
 
 class Input(object):
 
-  def __init__(self, mode, replay):
+  def __init__(self, mode, inreplay):
     self.mode = mode
-    self.replay = replay
+    self.inreplay = inreplay
+    self.replay = []
     self.keysPressed = KeysPressed()
     self.pos = 0
     self.prev_progress = 0
 
   def tick(self, events):
     if self.mode == "game":
-      self.readInputFromKeyboard(events)
+      return self.readInputFromKeyboard(events)
     else:
       self.readInputFromReplay()
+      return True
 
   def readInputFromKeyboard(self, events):
     prevLeft = self.keysPressed.left
+    advance = False
     for event in events:
       if event.type == locals.KEYUP or event.type == locals.KEYDOWN:
         pressed = (event.type == locals.KEYDOWN)
@@ -47,29 +50,43 @@ class Input(object):
           self.keysPressed.right = pressed
         if event.key == locals.K_SPACE:
           self.keysPressed.space = pressed
+        if event.key == locals.K_LSHIFT and event.type == locals.KEYDOWN:
+          advance = True
 
+    if advance != True:
+      return False
+    
     # If both directions are pressed, use whichever was pressed most recently.
     if self.keysPressed.left and self.keysPressed.right:
       if prevLeft:
         self.keysPressed.left = False
       else:
         self.keysPressed.right = False
+    
+    #if self.keysPressed.asNumber() == 0:
+      #return False
 
     self.replay.append(copy(self.keysPressed))
+    
+    return True
 
   def readInputFromReplay(self):
-    keys = self.replay[self.pos] if self.pos < len(self.replay)  else 0
+    keys = self.inreplay[self.pos] if self.pos < len(self.inreplay)  else 0
     self.pos += 1
     self.keysPressed = KeysPressed(keys)
+    self.replay.append(copy(self.keysPressed))
     if self.mode == "check":
-      progress = round(self.pos / len(self.replay) * 100)
+      progress = round(self.pos / len(self.inreplay) * 100)
       if self.prev_progress != progress:
         print("%d%%" % progress, flush=True)
         self.prev_progress = progress
 
 
   def reachedEndOfReplay(self):
-    return self.mode != "game" and self.pos >= len(self.replay)
+    #return self.mode != "game" and self.pos >= len(self.inreplay)
+    if self.mode != "game" and self.pos >= len(self.inreplay):
+        self.mode = "game"
+    return False;
 
   def getKeysPressed(self):
     return copy(self.keysPressed)

Bugs abused

The only bug abused was crouching cancelling attack cooldown to kill enemies faster.

Getting the flags

To get the first 3 flags, we need to send the generated replay.txt to the server.

user@ubuntu:~/handout$ cat replay.txt - | nc 35.242.182.148 1337 
Input replay file + empty line

checking...
1%
2%
3%
4%
5%
6%
7%
8%
9%
10%
11%
12%
13%
14%
15%
16%
17%
18%
19%
20%
21%
22%
23%
24%
25%
26%
27%
28%
29%
30%
31%
32%
33%
34%
35%
36%
37%
38%
39%
40%
41%
42%
43%
44%
45%
46%
47%
48%
49%
50%
51%
52%
53%
54%
55%
56%
57%
58%
59%
60%
61%
62%
63%
64%
65%
66%
67%
68%
69%
70%
71%
72%
73%
74%
75%
76%
77%
78%
79%
80%
81%
82%
83%
84%
85%
86%
87%
88%
89%
90%
91%
92%
93%
94%
95%
96%
97%
98%
99%
100%
WON!
Your time: 1941 frames
You beat the game! Here's flag number 0:
SaF{N1ce!_N0w_m4ke_Y0uRs3lF_a_t0Ol_t0_ASs15t_yoU}
You beat the game under 2250 frames! Here's flag number 1:
SaF{GrE4t!_N0w_1Ts_tIm3_tO_F1nd_s0ME_Gl1tcH3s}
You beat the game under 2020 frames! Here's flag number 2:
SaF{WHen_y0Ur_InT3RNet_cONneCTioN_1s_g0Od_TR3x_SpENd5_h15_fR3e_T1mE_GU4rDinG_Fl4Gs}
Now try completing it under 1790 frames!

Flag 1: SaF{N1ce!_N0w_m4ke_Y0uRs3lF_a_t0Ol_t0_ASs15t_yoU}

Flag 2: SaF{GrE4t!_N0w_1Ts_tIm3_tO_F1nd_s0ME_Gl1tcH3s}

Flag 3: SaF{WHen_y0Ur_InT3RNet_cONneCTioN_1s_g0Od_TR3x_SpENd5_h15_fR3e_T1mE_GU4rDinG_Fl4Gs}

Files

Other write-ups