---
# System prepended metadata

title: '[Hack.lu CTF 2022](https://flu.xxx)'

---

# [Hack.lu CTF 2022](https://flu.xxx)

![](https://i.imgur.com/EmAoPb4.png)

---

[Scrambled Packets](#Scrambled-Packets)

[Arcade 1](#Arcade-1)

[Arcade 2](#Arcade-2)

---


## Scrambled Packets

![](https://i.imgur.com/2ArmRNf.png)

Đề cho mình một biểu đồ và file `.pcapng`

![](https://i.imgur.com/M5DnSxt.png)

![](https://i.imgur.com/L8XD8cl.png)

Nhìn vào biểu đồ thì thấy được LB1 được kết nối tới LB2 và LB3. Mỗi LB đều sử dụng thuật toán Round Robin nên cách hoạt động của bài này cũng không quá khó.

Mỗi packet khi được gửi vào LB1 sẽ được chuyển tuần tự vào LB2 và LB3. Sau đó, các packet đó sẽ được chuyển tuần tự vào các Node được nối vào LB2 hoặc LB3


Mở file .pcapng lên ta thấy tất các packet đều được gửi đến 1.1.1.1 và nó là LB1 và khi nhìn sơ qua có vẻ như tất cả các packet đều không có payload. Để kiểm chứng thì mình mở Protocol Hirearchy để kiểm tra

![](https://i.imgur.com/NeL3H4a.png)

Nhưng khi nhìn vào Protocol Hirearchy thì mình thấy được có 26 packet có 'Data'. Filter nó ra thì thấy được các packet này đều có Len=4 và payload của nó là `flag`. Có vẻ đây là các ký tự của flag.

![](https://i.imgur.com/6JazkwN.png)

Bây giờ mình chỉ cần duyệt tuần tự các packet và sắp xếp nó vào đúng Node theo ảnh và in ra ký tự của packet có Len=4

```py!=
#tshark -r .\orders.pcapng > file.txt
LB2 = [chr(i) for i in range(65, 78)]
LB3 = [chr(i) for i in range(73, 91)]
LB1 = [LB2, LB3]
with open('file.txt', 'r') as f:
    i, L2, L3 = 0, 0, 0
    for line in f.readlines():
        line = line.strip()[-1]
        if line == '4':
            print(LB1[i][L3 if i == 1 else L2], end='')
        if(i % 2 == 0):
            L2 = (L2 + 1) % len(LB2)
        else:
            L3 = (L3 + 1) % len(LB3)
        i = (i + 1) % 2
```
Output:
```
YUMMYYUMMYSCRAMBLEDPACKETS
```

<details>
  <summary>Flag</summary>
    flag{YUMMYYUMMYSCRAMBLEDPACKETS}
</details>

## Arcade 1

![](https://i.imgur.com/JvSgsTV.png)



Đề cho mình folder game và folder server.

Vào game thì thấy được mình phải kết nối vào server để có thể lấy được flag. Mình thử kết nối vào server và bật wireshark lên xem có bắt được gì hay không.

Ngay khi kết nối đến server thì mình bắt được các dữ liệu:

![](https://i.imgur.com/3davTvR.png)

```
Client -> Server :  {"name":"Client 1.0","type":2}

Server -> Client :  {"type": 3, "name": "Server 1.0", "id": 1}
                    {"type": 4, "id": 1, "x": 23.0, "y": -28.0}
```

Nếu di chuyển thì mình sẽ gửi đến server các packet:
```
Client -> Server : {"id":2,"x":22.90167,"y":-28.0,"type":4}
```

Đó là những gì mình biết khi mở game và kết nối vào server. Bây giờ xem trong folder server có gì.

Sau khi đọc lướt qua thì thấy dòng code này:

![](https://i.imgur.com/bWFsFWz.png)

Vậy mình chỉ cần cho nhân vật đi tới vị trí `FLAG_TILE` mình sẽ nhận được flag và mình thấy FLAG_TILE nằm ở vị trí 87,-57

![](https://i.imgur.com/DofoQCF.png)

và nhân vật phải đứng ở vị trí 87, -56 thì sẽ đứng trên `FLAG_TILE`

![](https://i.imgur.com/mFMYBqS.png)

Nhưng vị trí 87, -57 nằm ở đâu? Lúc này mình mới nhớ trong folder còn có file `tilemap.json`. Đọc tên file có lẽ nó là file map cho cả game.

Script vẽ map:

```py!=
import matplotlib.pyplot as plt
import json

with open('tilemap.json', 'r') as f:
    tiles = json.loads(f.read())
    plt.scatter(*zip(*tiles))
    plt.show()
```

Output:
![](https://i.imgur.com/kMVZ03E.png)

Vậy flag sẽ nằm ở vị trí này 

![](https://i.imgur.com/esulf0J.png)

Và mình cũng thấy được trong source file server, thì bước đi lớn nhất của nhân vật là 1.1 tile.

![](https://i.imgur.com/lZ9qnqW.png)

Vậy thì mình sẽ có khả năng đi qua được tường có độ dày 1 tile.

Ý tưởng đã xong giờ chỉ cần viết script để chạy thôi

Đường đi theo script:

![](https://i.imgur.com/jKbtFYT.png)


```py!=
from pwn import *
import json

#template = {"id":1,"x":23.0,"y":-28.0,"type":4}

r = remote('arcade.flu.xxx', 10601)
r.sendline(b'{"name":"Client 1.0","type":2}')

id = json.loads(r.recvline())['id']
# print(id)

#Arcade 1

x = 23.0
y = -28.0

def move(des_x, des_y):
	global x, y
	payload = json.dumps({"id":id,"x":des_x,"y":des_y,"type":4}).encode()
	r.sendline(payload)
	# print('Sent:',payload)
	x = des_x
	y = des_y

def destination(des_x, des_y):
	global x, y
	while(x < des_x):
		x += 1
		move(x, y)
	while(x > des_x):
		x -= 1
		move(x, y)
	while(y < des_y):
		y += 1
		move(x, y)
	while(y > des_y):
		y -= 1
		move(x, y)
        
move(23.0,-28.0)
destination(1, 0)
#enter door
move(65, -0.5)
sleep(2)
move(65, 0)
sleep(10)
destination(52, 0)

#thru walls
move(52, 0.99)
move(52, 2)
move(52, 2.99)
move(52, 4)
destination(98, -70)
destination(68, -55)

#thru walls
move(68, -54.01)
move(68, -52.99)
move(68,-52)
destination(68, -41)

#thru walls
move(68.99, -41)
move(70, -41)
move(70.99, -41)
move(72, -41)
destination(72, -57)
destination(87, -56)
r.interactive()
```

<details>
  <summary>Flag</summary>
    flag{i_missed_something_didnt_i}
</details>

## Arcade 2

Bài này mình khá cay vì mình làm ra flag trễ mất vài phút nên không tính thêm điểm được

![](https://i.imgur.com/yvJeJg1.png)


Đọc source file server thì mình thấy đánh nhau với địch chỉ cần biết id của địch cần đánh, không cần biết đến vị trí của mình so với nó.

![](https://i.imgur.com/EFJjfii.png)

Và trong game này chỉ có 4 loại địch:
![](https://i.imgur.com/wWWv37K.png)

và thứ mình cần đánh bại là địch có id = 3.

Nếu vậy thì mình chỉ cần gửi request với player với lượng máu và damage cực lớn là được đúng không?

Không may là server kiểm tra lượng dmg của mình và trả nó về 100 nếu lớn hơn.

![](https://i.imgur.com/qGFERlB.png)

Nhưng sau khoảng thời gian rất lâu, mình để ý thấy server đang sử dụng kiểu dữ liệu float và trong python thì kiểu float có thể có giá trị là nan.

và các toán tử so sánh với nan đều trả về False

![](https://i.imgur.com/1t9SAyt.png)

Vậy thì mình chỉ cần gửi cho server damage với giá trị là nan là sẽ pass qua được điều kiện để giết địch

![](https://i.imgur.com/gWEpetf.png)

Script:

```py!=
from pwn import *
import json

#template = {"id":1,"x":23.0,"y":-28.0,"type":4}

r = remote('arcade.flu.xxx', 10601)
r.sendline(b'{"name":"Client 1.0","type":2}')

id = json.loads(r.recvline())['id']
# print(id)

payload = json.dumps({"id":id,"health":69420,"damage":'nan',"type":7}).encode()
r.sendline(payload)
payload = json.dumps({"id":3,"type":8}).encode()
r.sendline(payload)
r.interactive()
```

<details>
  <summary>Flag</summary>
    flag{is_it_a_number_or_is_it_not_a_number}
</details>


