Skip to content

Commit

Permalink
post: nops ctf writeup
Browse files Browse the repository at this point in the history
  • Loading branch information
l4rzy committed Jun 3, 2024
1 parent 04ed24e commit b9dfb4e
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 0 deletions.
205 changes: 205 additions & 0 deletions _posts/2024-06-03-nops-ctf-writeups.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
---
layout: post
title: "[CTF] N0PS CTF writeups"
categories: ctf re forensics
---

## Reverse Me

```sh
> file img.jpg
img.jpg: JPEG image data
```

The file looks like a JPEG, but it does not show anything in an image viewer, let's have a closer look.
```sh
> xxd img.jpg
00000000: ffd8 ffe0 0000 0000 0000 0000 0000 0000 ................
00000010: 0000 0000 0000 0001 0000 0000 0000 0000 ................
00000020: 0000 0000 0000 010a 0000 0000 0000 303b ..............0;
00000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000040: 0000 0003 0000 0001 0000 0000 0000 0001 ................
00000050: 0000 0000 0000 0001 0000 0000 0000 0000 ................
00000060: 0000 0000 0000 002b 0000 0000 0000 3010 .......+......0.
00000070: 0000 0000 0000 0000 0000 0000 0000 0030 ...............0
...
```
The file starts with `ffd8 ffe0`, which is a signature for [Raw JPEG](https://en.wikipedia.org/wiki/List_of_file_signatures), so what could be wrong?
![raw jpeg](/assets/images/nopsctf/jpeg.png)

```sh
...
00003800: 0000 0000 0000 0318 0000 0000 0000 0318 ................
00003810: 0000 0004 0000 0003 0000 0000 0000 0008 ................
00003820: 0000 0000 0000 02d8 0000 0000 0000 02d8 ................
00003830: 0000 0000 0000 0040 0000 0000 0000 0040 .......@.......@
00003840: 0000 0000 0000 0040 0000 0004 0000 0006 .......@........
00003850: 001c 001d 0040 000d 0038 0040 0000 0000 .....@...8.@....
00003860: 0000 0000 0000 3148 0000 0000 0000 0040 ......1H.......@
00003870: 0000 0000 0000 1310 0000 0001 003e 0003 .............>..
00003880: 0000 0000 0000 0000 0001 0102 464c 457f ............FLE.
```
Scrolling to the end of the file, there is something odd. That's the ELF binary signature in reverse. Let's reverse the file back. And voila!

```python
input_file = "img.jpg"
output_file = "img.elf"

with open(input_file, 'rb') as f:
data = f.read()

reversed_data = data[::-1]

with open(output_file, 'wb') as f:
f.write(reversed_data)
```

```
> python reverse.py
> file img.elf
img.elf: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=ae64a94832a94702644e170ebf1177740605cb34, for GNU/Linux 3.2.0, stripped
```

Now, let's open the file in IDA.
![ida](/assets/images/nopsctf/ida.png)

The program reads 4 arguments and calls `sub_1460` to do some check on them. The check is quite simple.
```c
__int64 __fastcall sub_1460(int a1, int a2, int a3, int a4)
{
unsigned int v4; // r8d

v4 = 0;
if ( 3 * a4 + a3 + 4 * a2 - 10 * a1 != 28 )
return 0LL;
if ( 9 * a2 - 8 * a1 + 6 * a3 - 2 * a4 == 72 && a4 + -3 * a2 - 2 * a1 - 8 * a3 == 29 )
LOBYTE(v4) = a3 + 5 * a1 + 7 * a2 - 6 * a4 == 88;
return v4;
}
```
Let's find the 4 numbers that satisfy the check with z3.
```python
import z3
from z3 import Solver, Real
def solve_range_equation():
# Create a solver
solver = Solver()
# Define variables
a1 = Real('a1')
a2 = Real('a2')
a3 = Real('a3')
a4 = Real('a4')
# Add equation to the solver
solver.add(3 * a4 + a3 + 4 * a2 - 10 * a1 == 28)
solver.add(9 * a2 - 8 * a1 + 6 * a3 - 2 * a4 == 72)
solver.add(a4 + -3 * a2 - 2 * a1 - 8 * a3 == 29)
solver.add(a3 + 5 * a1 + 7 * a2 - 6 * a4 == 88)
# Check satisfiability and get the solution
if solver.check() == z3.sat:
model = solver.model()
print("Solution:", model[a1], model[a2], model[a3], model[a4])
else:
print("No solution found.")
if __name__ == "__main__":
solve_range_equation()
```

```
> python solve.py
Solution: -3 8 -7 -9
```

And finally solve the challenge:
```
> chmod +x img.elf
> ./img.elf -3 8 -7 -9
N0PS{r1CKUNr0111N6}
```

## HID

The challenge provides a pcapng file (Packet capture). Let's open it in Wireshark.
![wireshark](/assets/images/nopsctf/wireshark.png)

Since there are packets that are irrelevant to HID, let's filter them out with `usbhid.data`

Now we're left with all the HID packets. After scrolling up and down, we can see clearly that there are two HID devices: a keyboard, and a pointing device. The thing is, there is only one packet from the keyboard, all other packets are from the pointing device (supposedly a mouse). Let's analyze them.

![keyboard](/assets/images/nopsctf/keyboard.png)

![mouse](/assets/images/nopsctf/mouse.png)

At this point, we can forget the keyboard and focus on the mouse, since the mouse has information about its movements (x axis and y axis). Let's filter out the keyboard and export the result to another file for further processing.

![filtered](/assets/images/nopsctf/filtered.png)

Since we know the offsets in Wireshark, we will use Python to extract all the movements, and visualize it.

```python
import matplotlib.pyplot as plt
from scapy.all import *

def draw_plot(movements):
# Initialize coordinates with the root point
x_coords = [0]
y_coords = [0]

# Accumulate movements to generate coordinates
current_x = 0
current_y = 0
for movement in movements:
current_x += movement[0]
current_y += movement[1]
x_coords.append(current_x)
y_coords.append(current_y)

# Plot the points
plt.plot(x_coords, y_coords, marker='o')

# Connect all points with lines
plt.plot(x_coords, y_coords, linestyle='-', color='b')

# Add labels and title
plt.xlabel('X Coordinate')
plt.ylabel('Y Coordinate')
plt.title('Plot of Movements')

# Show the plot
plt.grid(True)
plt.show()

if __name__ == "__main__":
# Set the input pcap file path
input_file = "filtered.pcapng"
packets = rdpcap(input_file)

movements = []
for p in packets:
xb = p.load[66:68]
yb = p.load[68:70]

print(xb, yb)

x = struct.unpack('<h', xb)[0]
y = struct.unpack('<h', yb)[0]

movements.append((x,y))

# Draw mouse movement
draw_plot(movements)

```
![movements](/assets/images/nopsctf/movements.png)

It doesn't look quite right, does it? Because in computer graphics, the 2D Cartesian Coordinate System is horizontally flipped, so we have to flip the image upside down. And here's the result.

![flipped](/assets/images/nopsctf/flipped.png)

It took me a while to guess the flag due to the ugly mousewriting. `N0PS{m0Us3_dR4w1Ng}`
Binary file added assets/images/nopsctf/filtered.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/nopsctf/flipped.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/nopsctf/ida.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/nopsctf/jpeg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/nopsctf/keyboard.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/nopsctf/mouse.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/nopsctf/movements.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/nopsctf/wireshark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit b9dfb4e

Please sign in to comment.