---
# System prepended metadata

title: Google CTF 2023

---

## PAPAPA

![](https://hackmd.io/_uploads/rkTEcHdt3.png)
[Attachment](https://storage.googleapis.com/gctf-2023-attachments-project/d2e5b38d584108c2b63150e7a073b8c104972ee59b83f5ee44d9ef6ae0118b4ad57e64cb328d7e8b839989ae741f793ded5fef7f51f7ecbbaaeaa716312f18c9.zip)

Challenge này mình không có học được gì nhiều. 

Lần đầu khi mở hex của hình lên thì thấy rất nhiều byte 00, nên mình xoá thử vài byte xem có gì lạ xảy ra không thì thấy một chuỗi có vẻ là flag.
![](https://hackmd.io/_uploads/rkg6q6HuF3.png)


## Symmatrix
![](https://hackmd.io/_uploads/HkiFqS_Kh.png)
[Attachment](https://storage.googleapis.com/gctf-2023-attachments-project/aba60aa2e9c806187f88279742c2ced243dd73b142c5c5bac1327956975e4d3add04afad77cfd823dd4f00847f6334b294ab058308639f8cb52897e8f1be769e.zip)

Chall này ban đầu khi nhìn vào có vẻ như phải reverse các hàm trong C.

Nhưng khi xem kỹ lại thì mình thấy được các comment liên quan đến dòng mà code python đó được chạy

![](https://hackmd.io/_uploads/Hyqzys5Fh.png)


Script để recover python code:
```python=
with open ('encoder.c','r') as f:
    d = f.readlines()
x = ""
lmao = {}
for i in range(len(d)):
    if 'encoder.py\":' in d[i]:
        for line in d[i:i+5]:
            if "<<<<<" in line:
                lmao[int(d[i].split(":")[-1].strip("\n"))] = line[3:]
        x += "".join(d[i:i+5])
sorted_dict = dict(sorted(lmao.items()))
print(sorted_dict)
to_write = ""
for k,v in sorted_dict.items():
    to_write+=v.replace("\n * ","\n")
with open('out.py','w') as wf:
    wf.write(to_write)
```

Recovered code:
```python=
from PIL import Image
from random import randint
import binascii
def hexstr_to_binstr(hexstr):
    n = int(hexstr, 16)
    bstr = ''
    while n > 0:
        bstr = str(n % 2) + bstr
        n = n >> 1
    if len(bstr) % 8 != 0:
        bstr = '0' + bstr
    return bstr
def pixel_bit(b):
    return tuple((0, 1, b))
def embed(t1, t2):
    return tuple((t1[0] + t2[0], t1[1] + t2[1], t1[2] + t2[2]))
def full_pixel(pixel):
    return pixel[1] == 255 or pixel[2] == 255
print("Embedding file...")
bin_data = open("./flag.txt", 'rb').read()
data_to_hide = binascii.hexlify(bin_data).decode('utf-8')
base_image = Image.open("./original.png")
x_len, y_len = base_image.size
nx_len = x_len*2
new_image = Image.new("RGB", (nx_len, y_len))
base_matrix = base_image.load()
new_matrix = new_image.load()
binary_string = hexstr_to_binstr(data_to_hide)
remaining_bits = len(binary_string)
nx_len = nx_len - 1
next_position = 0
for i in range(0, y_len):
    for j in range(0, x_len):
        pixel = new_matrix[j, i] = base_matrix[j, i]
        if remaining_bits > 0 and next_position <= 0 and not full_pixel(pixel):
            new_matrix[nx_len - j, i] = embed(pixel_bit(int(binary_string[0])),pixel)
            next_position = randint(1, 17)
            binary_string = binary_string[1:]
            remaining_bits -= 1
        else:
            new_matrix[nx_len - j, i] = pixel
            next_position -= 1
new_image.save("./symatrix_new_out.png")
new_image.close()
base_image.close()
print("Work done!")
exit(1)
```

khi xem cách làm việc của của hàm thì thấy được là nó set bit của flag như sau: pixel_x = (0, 1, flag_bit) mỗi random(1,17) pixel sau đó flip cả tấm hình sang bên phải.

vậy mình tìm tấm hình bên phải pixel nào có pixel[1] = 1 thì sẽ lấy pixel[3] để làm flag. 

```python=
from PIL import Image

img = Image.open("./symatrix.png")
x_len, y_len = img.size
matrix = img.load()
flag_bin_str = ""
flag  = ""
nx_len = x_len - 1
for i in range(0, y_len):
    for j in range(0, x_len):
        pixel = matrix[nx_len - j, i]
        
        # print(pixel)
        if pixel[1]==1:
            flag_bin_str +=str(pixel[2])
            # print(flag_bin_str)
            if len(flag_bin_str)%8==0 and len(flag_bin_str)!=0:
                flag+=chr(int(flag_bin_str[-8:],2))
print(flag)
```
![](https://hackmd.io/_uploads/HkXFFscY2.png)


## NPC
![](https://hackmd.io/_uploads/S1Bs5rdFh.png)

[Attachment](https://storage.googleapis.com/gctf-2023-attachments-project/9a8f5d47fab0a460f9826c4f13aa1dff2809140e68325fb21edab674ee5ec2476b902d2797c41bd6d9311e3510c9366d739d9404e00aa9d4ffd6a0d88e5bf2ef.zip)

*Note to self: detailed wu*

Script:


Parse Graph
```python
import re
def get_word_list():
  with open('USACONST.TXT', encoding='ISO8859') as f:
    text = f.read()
  return list(set(re.sub('[^a-z]', ' ', text.lower()).split()))

word_lists = get_word_list()

numCharDict = {}
Edges = list()

with open('hint.dot','r') as f:
    a = f.readlines()

for i in a:
    if "label" in i:
        i = i.split()
        # print("label",i)
        numCharDict[int(i[0])] = i[1][-3]
    elif "--" in i:
        i = i.strip().split('--')
        print("Edges",i)
        Edges.append((int(i[0]),int(i[1][:-1])))
with open('parseGraph.txt','w') as w:
   w.writelines("letters = " + str(numCharDict) + '\nedge_list =' + str(Edges))
  # print("letters =",numCharDict)
  # print("edge_list =",Edges)
```

Get Password
```python
import re
letters = {1051081353: 'a', 66849241: 'a', 53342583: 'n', 213493562: 'd', 4385267: 'i', 261138725: 'o', 51574206: 't', 565468867: 'e', 647082638: 'r', 177014844: 'd', 894978618: 'e', 948544779: 'n', 572570465: 'n', 582531406: 'r', 264939475: 'a', 415170621: 's', 532012257: 't', 151901859: 'v', 346347468: 'g', 148496047: 'g', 125615053: 's', 723039811: 'e', 962878065: 'i', 112993293: 'w', 748275487: 'n', 120330115: 's', 76544105: 'c', 186790608: 'h'}
edge_list =[(53342583, 565468867), (582531406, 76544105), (125615053, 120330115), (264939475, 572570465), (53342583, 565468867), (532012257, 264939475), (346347468, 532012257), (125615053, 582531406), (177014844, 120330115), (264939475, 962878065), (647082638, 1051081353), (346347468, 112993293), (120330115, 151901859), (647082638, 125615053), (532012257, 66849241), (582531406, 894978618), (582531406, 572570465), (125615053, 532012257), (948544779, 261138725), (748275487, 894978618), (112993293, 177014844), (532012257, 4385267), (415170621, 962878065), (723039811, 962878065), (120330115, 151901859), (51574206, 76544105), (415170621, 532012257), (53342583, 120330115), (723039811, 582531406), (186790608, 112993293), (148496047, 582531406), (4385267, 125615053), (151901859, 962878065), (582531406, 894978618), (76544105, 748275487), (261138725, 186790608), (948544779, 346347468), (565468867, 213493562), (213493562, 261138725), (565468867, 894978618), (572570465, 264939475), (415170621, 151901859), (582531406, 962878065), (112993293, 346347468), (66849241, 1051081353), (894978618, 264939475), (647082638, 66849241), (894978618, 148496047), (213493562, 748275487), (572570465, 120330115), (565468867, 264939475), (148496047, 948544779), (186790608, 76544105), (177014844, 647082638), (125615053, 186790608), (112993293, 76544105), (582531406, 415170621), (151901859, 177014844), (346347468, 565468867), (148496047, 151901859), (723039811, 415170621), (1051081353, 415170621), (261138725, 76544105), (894978618, 723039811), (66849241, 112993293), (264939475, 112993293), (346347468, 748275487), (647082638, 948544779), (962878065, 647082638), (948544779, 962878065), (723039811, 120330115), (572570465, 51574206), (565468867, 151901859), (213493562, 76544105), (1051081353, 213493562), (962878065, 151901859), (112993293, 948544779), (186790608, 948544779), (346347468, 4385267), (565468867, 66849241), (1051081353, 177014844), (962878065, 148496047), (748275487, 264939475), (4385267, 565468867), (565468867, 1051081353), (51574206, 76544105), (532012257, 213493562), (532012257, 894978618), (723039811, 415170621), (264939475, 51574206), (572570465, 723039811), (894978618, 532012257), (66849241, 186790608), (213493562, 261138725), (415170621, 261138725), (125615053, 177014844), (186790608, 53342583), (565468867, 120330115), (51574206, 120330115), (186790608, 748275487), (213493562, 1051081353), (76544105, 53342583), (148496047, 565468867)]
ans = set()
adj = {}
for edge in edge_list:
    try:
        adj[edge[1]].append(edge[0])
    except:
        adj[edge[1]] = [edge[0]]

# print(len(adj['4385267']))
# exit(0)

def get_word_list():
  with open('USACONST.TXT', encoding='ISO8859') as f:
    text = f.read()
  return list(set(re.sub('[^a-z]', ' ', text.lower()).split()))

word_list = get_word_list()
ma = 0
for x in word_list:
    if ma < len(x):
        ma = len(x)

concat_word = ' ' + ' '.join(word_list) + ' '

def backtrack(u, list_node, w, last):
    # print(w, last, len(list_node), len(letters), sep='|')
    global concat_word, word_list, ma
    
    if (len(list_node) == len(letters)):
        # with open('ans', 'a') as f:
        #     f.write(w + '\n')
        ans.add(w.replace(' ',''))
        return

    for v in adj[u]:
        old_last = last
        if v not in list_node:
            if ' ' + last + letters[v] in concat_word and len(last) < ma:
                last += letters[v]
                w += letters[v]
                list_node.append(v)
                backtrack(v, list_node, w, last)
                list_node.pop()
                last = old_last
                w = w[:-1]
            
            if ' ' + letters[v] not in concat_word or ' ' + old_last + ' ' not in concat_word:
                continue
            last = letters[v]
            list_node.append(v)
            w += ' ' + letters[v]
            backtrack(v, list_node, w, last)
            list_node.pop()
            last = old_last
            w = w[:-2]
            

for i in letters:
    backtrack(i, [i], letters[i], letters[i])
with open('ans','w') as w:
    for i in ans:
        w.writelines(i+'\n')
```

Decrypt
```python
from pyrage import passphrase
from multiprocessing import Process

passwords = [i.strip().split('|')[0].replace(' ','') for i in open('ans','r').readlines()]

# print(passwords)
lmao = open('secret.age','rb').read()

if __name__ == '__main__':
    for passw in passwords:
        try:
            print(passphrase.decrypt(lmao,passw))
            print(passw)
        except:
            pass
```