Writeup CTFR PyGame

Khairu Aqsara Sudirman

Khairu Aqsara Sudirman

Mar 22, 2021 — 6 mins read

Challenge ini merupakan salah satu challenge yang cukup sulit menurut saya, bahkan mungkin sangat sulit sejauh saya mengikuti CTFR, mungkin karena ketidak tahuan saya dalam membaca petunjuk dan maksud dari challengenya, deskripsinya juga sangat sederhana, tidak banyak yang bisa diambil sebagai petunjuk, satu-satunya petunjuk hanya merujuk pada gambar yang diberikan.

Download : https://mega.nz/#!VthwnaSB!ajJ2S4MfM4UPPdoqaQXyAuGtnynRpyQWsWYPO8F3s_k

setelah didownload, terdapat 2 buah file challenge_pygame.png dan pygame_chall.py, isi dari challenge_pygame.png seperti berikut

berdasarkan keterangan dari challengenya, gambar diatas dihasilkan oleh script python challenge_pygame.py

import pygame, random, string, time
from Crypto.Util.number import inverse
from pygame.locals import *
from pygame.surface import Surface

pygame.init()
width, height = 1280, 720
screen = pygame.display.set_mode((width, height))
nonvertical = 3

def genChar():
    c = string.digits + string.ascii_letters
    return c[random.randint(0, len(c) - 1)]

def genNumber(min, max):
    res = []
    for x in range(min, max + 1):
        if x > 1:
            for i in range(2, x):
                if (x % i) == 0:
                    break
            else:
                res.append(x)
    return res

def draw(x, y, color, size):
    global screen
    s = Surface(size)
    s.fill(color)
    screen.blit(s, (x, y))
c = 0
def getObjColor(x):
    stor = ord(x)
    x = ord(x)
    if x >= 65 and x <= 90:
        x += int(time.strftime("%S"))
    elif x >= 97 and x <= 122:
        x += int(time.strftime("%M"))
    else:
        x += int(time.strftime("%H"))
    num = genNumber(stor - 64, stor)
    v1 = abs(num[4] - c)
    v2 = abs(num[6] + c)
    v3 = (v1 * v2) % 255
    return (v1 + v2, v3 ^ x, v3)

flag = "TEST"
len_flag = len(flag)
max_height = int(round(height / len_flag))
usedheight = max_height
while True:
    screen.fill(0)
    usedheight = 0
    for ch in flag:
        target = ch
        for x in range(0, width, width / max_height):
            draw(x, usedheight, getObjColor(target), (width / max_height, max_height))
            c += 1
        c = 0
        usedheight += max_height
    pygame.display.flip()
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit(0)

Awalnya saya berpikir ini mungkin manupulasi pixel warna pada sebuah gambar, tetapi ternyata saya salah, setelah melihat-lihat isi dari code yang diberikan saya sadar jika warna pada gambar yang diberikan ditentukan oleh panjang Flagnya yaituflag = "TEST" dan berdasarkan waktu pada saat proses berjalan yang ada pada fungsi def getObjColor(x)

Misalnya saja pada contoh kode diatas, flag='Test' akan digunakan sebagai penentu seberapa banyak looping yang akan diproses untuk membentuk atau menggambar sebuah warna dengan panjang dan tinggi tertentu, bisa kita lihat pada bagian kode

draw(x, usedheight, getObjColor(target), (width / max_height, max_height))

penggalan code tersebut memanggil fungsi

def draw(x, y, color, size):
    global screen
    s = Surface(size)
    s.fill(color)
    screen.blit(s, (x, y))

dari sini kita bisa melihat jika setiap perulangan sepanjang flag akan membuat sebuah object atau fill dengan posisi x dan y dan warna serta ukuranya, dimana ukuran dari object tersebut ditentukan dari max_height = int(round(height / len_flag)) , serta usedheight += max_height yang akan dirubah nilainya sepanjang perulangan, sederhanya jika kita terjemahkan dengan value flag="TEST" mungkin kira-kira akan menjadi seperti ini

len_flag = 4
max_height = int(round(720 / 4)) = 180
usedheight = max_height
for x in range(0,720,180): 
	draw(x, 180, getObjColor('T'), (1, 180))

jika kita breakdown, len_flag = 4 dimana flag hanya berupa string 'TEST' berjumlah 4 karakter, kemudian max_height=180 yang berasal dari pembulatan height/4, jika kita berasumsi pada proses perulangan for x in range(0,720,180) maka perulangan akan di awali dengan 0 dan kemudian kelipatan 180 hingga pada batas 720 nilai x jika diulang sebanyak 4 kali akan menjadi 0, 180, 360, 540, dari sini kita bisa mengambil kesimpulan pada perulangan pertama object fill dengan warna('T') akan dibuat pada koordinat x=0, y=180 dengan ukuran 1x180 pixel, sejauh ini informasi ini belum cukup membantu, karena setelah saya coba tidak jalan.

pygame 2.0.1 (SDL 2.0.14, Python 2.7.17)
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
  File ".\pygame_chal.py", line 64, in <module>
    draw(x, usedheight, getObjColor(target), (width / max_height, max_height))
  File ".\pygame_chal.py", line 31, in draw
    s.fill(color)
ValueError: invalid color argument

setelah saya telusuri ternyata proses pembuatan object pada proses draw() dipengaruhi oleh pangjang flag, sehingga pada proses def getObjColor(x) menghasilkan warna yang tidak valid alias lebih besar dari 255

(861, 0, (252, 219, 170), (7, 180))
(868, 0, (254, 217, 168), (7, 180))
(875, 0, (256, 217, 168), (7, 180)) # (R=256, G=217, B=168) pixel Red lebih besar dari 255

Jadi harus mencari tau dulu berapa panjang flag nya, cukup lama saya mantengin darimana bisa dapat panjang flagnya, setelah bolak balik melihat gambar yang diberikan dan mencoba melihat-lihat isi pixelnya, ternyata oh ternyata panjang flagnya ada didalam gambar yang diberikan, bisa teman-teman lihat pada gambar yang diberikan, jika diperhatikan baik-baik dan menghitung jumlah warna pada gambar dari posisi atas kebawah semua berjumlah 64 baris warna, dengan meberikan nilai flag = 'A' * 64 dan menjalankan programnya hasilnya

hasilnya tidak error, dan pygame berjalan dengan semestinya, masalahnya warna yang dihasilkan tidak sesuai dengan capture yang diberikan, selanjutnya harus mencari warna yang sesuai dan ukuran yang sesuai agar gambar yang dihasilkan sama dengan gambar yang diberikan, dari tahapan ini sudah jelas kalo kita harus mencari karakter by karakter yang bisa mebentuk warna yang sama, untuk itu kita coba dulu dengan karakter standar, diman kita tau bahwa format flagnya adalah CTFR{....} jadi kita mencoba memberikan flag = 'CTFR{'+'A' * (64-5) dan hasilnya adalah

dari sini kita berhasil mendapatkan titik yang sangat terang, kita berhasil mendapatkan object fill yang sesuai walaupun warnya tidak sama tetapi format penempatan lebar dan tingginya sudah sama, sesuai string yang kita berikan 5 string pertama yaitu CTFR{ membentuk 5 baris object warna, langkah selanjutnya adalah mencari tau sisa dari flagnya dengan cara brute forcing.

pada tahapan ini mungkin cara yang saya gunakan tidak efisien atau bukan cara yang seharusnya, jika teman-teman merasa ada caranya yang lebih simple bisa share di group whatsapp CTFR, saya disini melakukan brute forcing warna yang ada pada gambar yang diberikan dan mencocokan karakter apa yang sesuai dengan warna tersebut, karena gambar yang diberikan adalah gambar hasil capture-an jadi harus menghitung dulu mulai dari mana pengambilan pixel warna-nya.

sebelum melakukan brute forcing, sebaiknya kita pahami dulu sedikit tentang fungsi def getObjColor(x) karena fungsi inilah yang bertanggung jawab dalam membuat warna dari gambarnya, jika diperhatikan dengan seksama hal yang paling penting ada pada bagian v3 = (v1 * v2) % 255 dan return (v1 + v2, v3 ^ x, v3), disini warna dibuat menggunakan xor tentunya setelah beberapa proses sebelumnya, tetapi menurut saya bagian inilah yang paling penting.

jika seandainya kita memproses karakter C maka proses yang terjadi pada fungsi ini adalah, karakter c akan dirubah dulu menjadi bentuk ordinal yaitu ord('C') = 67 dan disimpan dalam variable stor dan x, kemudian pada bagian berikutnya, karena x=67 maka kondisi if x >= 65 and x <= 90 akan terpenuhi, sehingga x = x + 29 (asumsinya terjadi pada detik ke 29) dilanjutkan dengan proses num = genNumber(67- 64, 67) jika kita merujuk ke fungsi genNumber(min,max) maka num akan bernilai [3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67]

Dari hasil tersebut proses dilanjutkan dengan mendapatkan v1 = abs(num[4] - c) dimana num[4] = 13 jadinya v1 = abs(13 - 0) kita berasumsi jika perulangan ada pada 0 sehingga bisa kita simpulkan jika v1 = 13, sama halnya berlaku dengan v2, v2 akan bernilai v2 = abs(19 + 0) atau sama dengan v2=19 dan v3 = (13* 19) % 255 sehingga v3 = 247 dengan begitu nilai return dari def getObjColor(x) akan bernilai (13+19, 247 ^ 67, 247) atau sama dengan karakter C akan menghasilkan warna (32, 180, 247)

kembali ke point awal, karena operasinya menggunakan operator XOR jadi kita bisa membalikan hasilnya untuk mencari tau nilai awal sebelum penjumlahan dengan mencari tau %S %M dan %H waktu pemrosesan. disini saya mendapatkan waktu %S=38 %M=48 dan %S=8 dengan variable tersebut karakter C mendapatkan warna dan posisi yang sama dengan gambar yang diberikan

sejauh ini semua kebutuhan untuk bruteforcing sudah terpenuhi, tinggal membuat script sederhana untuk melakukan tugas mencari karakter-karakter yang memiliki warna berdasarkan penelusuran sebelumnya.

dan jika hasilnya dimasukan dalam variable flag pada script yang diberikan, pygame akan menghasilkan gambar yang sama dengan gambar yang diberikan.

Flagnya

CTFR{wh3n_y0u_h4t3_p1x3l_but_th4t_w45_t45k_y0u_mu5t_t0_s0lv3_1t}
programming writeup ctf
Read More

Polymorphism dalam PHP

Polymorphism jika kita terjemahkan dalam bahasa yang cukup sederhana adalah banyak bentuk, tetapi sayang nya makna dari Polymorphism tidaklah sesederhana itu, dalam konsep pemrograman PHP Polymorphism sendiri maksudnya adalah kita bisa menggunakan interface yang sama untuk kebutuhan yang berbeda, sederhanya satu class atau lebih bisa memiliki fungsi yang sama, parameter yang sama tetapi dengan tujuan dan implementasi yang berbeda, mungkin nanti akan sedikit lebih jelas kekita kita dihadapkan dengan masalah dan kode karena dalam Polymorphism juda ada istilah Subtype Polymorphism atau Inclusion Polymorphism

Read More

Writeup CTFR Warna Warni

Dari deskripsi challenge nya terdapat informasi "maksimal 127" dan kita diberikan satu gambar yang isinya warna acak (noise) yang tidak beraturan, jadi bisa dipastikan jika flagnya ada dalam pixel warna gambar, karena ada hint maksimal 127 jadi kita mengambil semua warna RGB, saya mencoba mengambil semua pixel pada masing-masing warna seperti RG dan B yang nilainya lebih kecil dari 127 dan merubahnya menjadi karakter, asumsinya angka pada pixel adalah ordinal dari sebuah karakter, setelah mencoba-coba karakter yang bisa terbaca ada pada pixel R (Red)