⏪
CTFs
TwitterGithub
  • 👋Introduction
  • 📚Write Up
    • 2024
      • 📖1337UP LIVE CTF
        • Reverse Engineering
        • Mobile
        • Forensic
        • Misc
      • 📖HKCERT CTF Quals
        • Reverse Engineering
        • Binary Exploitation
      • 📖Flare-On 11
        • Challenge #1 - frog
      • 📖Intechfest
        • Reverse Engineering
        • Forensic
        • Cryptography
        • Mobile
      • 📖Cyber Breaker Competition (1v1)
        • Reverse Engineering
        • Web Exploitation
        • Cryptography
        • Binary Exploitation
      • 📖Cyber Breaker Competition Quals
        • Reverse Engineering
        • Web Exploitation
        • Cryptography
      • 📖BlackHat MEA Quals
        • Reverse Engineering
        • Forensic
      • 📖TFC CTF
        • Reverse Engineering
        • Forensic
        • Misc
      • 📖DeadSec CTF
        • Reverse Engineering
        • Web Exploitation
      • 📖Aptos - Code Collision CTF
        • Reverse Engineering
        • Misc
      • 📖DownUnder CTF
        • Reverse Engineering
      • 📖JustCTF
        • Reverse Engineering
        • Forensic
        • Misc
      • 📖Akasec CTF
        • Reverse Engineering
        • Forensic
      • 📖Codegate CTF Preliminary
        • Reverse Engineering
      • 📖NahamCon CTF
        • Cryptography
        • Reverse Engineering
        • Malware
        • Misc
        • Mobile
        • Scripting
        • Web Exploitation
        • Forensic
      • 📖SAS CTF Quals
        • Reverse Engineering
      • 📖SwampCTF
        • Reverse Engineering
        • Misc
        • Cryptography
      • 📖UNbreakable International
        • Reverse Engineering
        • Network
        • Cryptography
      • 📖ACSC
        • Reverse Engineering
        • Hardware
        • Web Exploitation
      • 📖0xL4ugh
        • Mobile
    • 2023
      • 📖BlackHat MEA Final
        • Reverse Engineering
        • Web Exploitation
      • 📖Flare-On 10
        • Challenge #1 - X
        • Challenge #2 - ItsOnFire
        • Challenge #3 - mypassion
        • Challenge #4 - aimbot
        • Challenge #5 - where_am_i
        • Challenge #6 - FlareSay
        • Challenge #7 - flake
        • Challenge #8 - AmongRust
        • Challenge #9 - mbransom
        • Challenge #10 - kupo
        • Challenge #11 - over_the_rainbow
        • Challenge #12 - HVM
        • Challenge #13 - y0da
      • 📖LakeCTF Quals
        • Reverse Engineering
        • Cryptography
      • 📖TSG CTF
        • Reverse Engineering
        • Cryptography
      • 📖ISITDTU Quals
        • Web Exploitation
        • Misc
        • Reverse Engineering
      • 📖BlackHat MEA Quals
        • Reverse Engineering
      • 📖ASCIS Final
        • Reverse Engineering
        • Web Exploitation
        • Cryptography
      • 📖ASCIS Quals
        • Reverse Engineering
        • Forensic
        • Cryptography
      • 📖IFest
        • Reverse Engineering
        • Cryptography
        • Misc
      • 📖Cyber Jawara International
        • Reverse Engineering
        • Forensic
        • Cryptography
        • Web Exploitation
      • 📖Intechfest
        • Reverse Engineering
        • Forensic
        • Cryptography
        • Mobile
      • 📖CSAW Quals
        • Reverse Engineering
      • 📖SECCON Quals
        • Reverse Engineering
      • 📖CTFZone Quals
        • Reverse Engineering
      • 📖Securinets Quals
        • Reverse Engineering
      • 📖Compfest Final (Attack Defense)
        • Web Exploitation
        • Cryptography
      • 📖Compfest Quals
        • Reverse Engineering
        • Cryptography
        • Forensic
        • Misc
      • 📖Tenable
        • Reverse Engineering
        • Cryptography
        • Steganography
      • 📖ASCWG Quals
        • Reverse Engineering
        • Cryptography
      • 📖Gemastik Quals
        • Reverse Engineering
      • 📖BSides Indore
        • Reverse Engineering
        • Cryptography
      • 📖NahamCon CTF
        • Cryptography
      • 📖HSCTF
        • Reverse Engineering
        • Cryptography
        • Web Exploitation
        • Misc
      • 📖ACSC
        • Reverse Engineering
      • 📖HackTM Quals
        • Reverse Engineering
    • 2022
      • 📖Intechfest
        • Reverse Engineering
        • Mobile
        • Cryptography
      • 📖NCW Final
        • Reverse Engineering
      • 📖NCW Quals
        • Reverse Engineering
        • Misc
        • Cryptography
      • 📖Compfest Final
        • Reverse Engineering
        • Forensic
      • 📖Compfest Quals
        • Reverse Engineering
        • Cryptography
      • 📖IFest
        • Reverse Engineering
        • Cryptography
        • Forensic
    • 2021
      • 📖Cyber Jawara Final
        • Reverse Engineering
      • 📖Cyber Jawara Quals
        • Reverse Engineering
        • Cryptography
      • 📖DarkCon CTF
        • Reverse Engineering
      • 📖Wreck IT Quals
        • Mobile
      • 📖MDT4.0 Final
        • Reverse Engineering
        • Cryptography
        • Forensic
      • 📖MDT4.0 Quals
        • Reverse Engineering
        • Cryptography
      • 📖IFest
        • Reverse Engineering
        • Cryptography
      • 📖Compfest Final
        • Reverse Engineering
      • 📖Compfest Quals
        • Reverse Engineering
        • Cryptography
    • 2020
      • 📖Deep CTF
        • Reverse Engineering
  • 🚩Lifetime CTF
    • 📖Hack The Box
      • Reverse Engineering
        • TBU
Powered by GitBook
On this page
  • sabeb64 (331 pts)
  • Description
  • Solution
  • Cakemath (451 pts)
  • Description
  • Solution
  • Turmoil (491 pts)
  • Description
  • Solution
  1. Write Up
  2. 2022
  3. NCW Quals

Cryptography

Challenge
Link

sabeb64 (331 pts)

Cakemath (451 pts)

Turmoil (491 pts)

sabeb64 (331 pts)

Description

-

Solution

Diberikan file sabeb.py sebagai berikut dan akses ke service.

import binascii
import random

charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
charset2 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

def generateSecret():
	secret = "".join(random.choices(charset2, k=30))
	return secret.encode()

def sabebencode(text):
    ####################################
    ####################################
    ####################################
    ##ceritanya ini rusak kesiram kopi##
    ####################################
    ####################################
    ####################################

if __name__ == '__main__':
	print('Hi! I am Decoda, your personal base64 encoder 0_0')
	print('People said my calculations a little bit something... dunno. But, i\'ll do my best 0_0')
	print("My boss said bruteforce isn't needed, so you're only given 10 chances to use the encoder")
	print('====================================================')
	print('Please make a choice from the options below:')
	count = 0
	secret = generateSecret()
	while True:
		if count == 10:
			print("You've reached your limit")
			print("Thank you and have a good time! ^_^")
			break
		print(f"Encode remaining: {10 - count}")
		print('1. Print encoded secret')
		print('2. Encode plaintext')
		print('3. Submit secret and get flag')
		inputan = input('>> ')
		if inputan == '1':
			print('Here\'s your encoded secret sir:')
			res = sabebencode(secret)
			print(res)
			print('')
			print('Anything else? 0_0')
		elif inputan =='2':
			print('Please input your plaintext in hex 0_0.')
			text = input('>>')
			try:
				text = binascii.unhexlify(text)
				res = sabebencode(text)
				print('Beep boop... here\'s the result sir:')
				print(res)
				print('')
				print('Anything else? 0_0')
				count+=1
			except:
				print('Sorry sir... weird input detected 0_0\n')
		elif inputan == '3':
			print("Please submit the administrator's secret")
			secretsubmit = input('>>').encode()
			try:
				if secretsubmit == secret:
					flag = 'REDACTED'
					print(f"Welcome back, admin. Here's your flag: {flag}\n")
				else:
					print("Wrong secret! You are not admin >:[\n");
			except:
				print('Sorry sir... weird input detected 0_0\n')
		else:
			print('Sorry sir... weird input detected 0_0\n')

Jadi intinya kita disuruh mengetahui value dari secretsubmit, namun disini kode dari sabebencode di hilangkan. Disini kita bisa melakukan analisis terhadap input dan output guna menentukan seperti apa algoritma yang ada pada sabebencode.

Bisa kita lihat dari input dan output diatas bahwa terdapat perbedaan antara encode aa dan aaaa pada base64 biasa dan sabeb64. Setelah kami validasi ternyata asumsi kami benar bahwa input di encode setiap 2 bytes, karena 2 bytes printable tidak terlalu banyak maka kita bisa petakan semua nilai dan decrypt secretsubmit dengan memetakannya kembali ke value aslinya.

from pwn import *
from itertools import product

dicc = {}
r = remote("103.167.136.75",9988)
for i in product(string.printable[:-6],repeat=2):
	tmp = ''.join(i)
	try:
		r.recvuntil(b">> ")
		r.sendline(b"2")
		r.sendline(tmp.encode().hex().encode())
		r.recvuntil(b":\n")
		res = r.recvline().strip().decode()
		dicc[res] = tmp
	except Exception as e:
		r.close()
		r = remote("103.167.136.75",9988)
		r.recvuntil(b">> ")
		r.sendline(b"2")
		r.sendline(tmp.encode().hex().encode())
		r.recvuntil(b":\n")
		res = r.recvline().strip().decode()
		dicc[res] = tmp
r.close()
print("nice")

# backup
import json  
with open('dicc.txt', 'w') as convert_file:
     convert_file.write(json.dumps(dicc))

r = remote("103.167.136.75",9988)
r.recvuntil(b">> ")
r.sendline(b"1")
r.recvuntil(b":\n")
ct_secret = r.recvline().strip().decode()
list_ct = []
for i in range(0,len(ct_secret),3):
	list_ct.append(ct_secret[i:i+3])
secc = ""
for i in list_ct:
	secc += dicc[i]
r.recvuntil(b">> ")
r.sendline(b"3")
r.recvuntil(b">>")
r.sendline(secc.encode())
r.interactive()

Flag : NCW22{jusT_a_littl3_d1ff3r3nt_C0ncept_0f_base_6nam_emp4t_x1x1x1_1be1ec3c3ea96b983a75e17dd3d44e8b}

Cakemath (451 pts)

Description

-

Solution

Diberikan file dessert.py sebagai berikut

import random,math,os
from Crypto.Util.number import *

flag = os.getenv("NCW_FLAG")
c_n1 = random.getrandbits(512)
c_n2 = random.getrandbits(512)

assert c_n1 != c_n2
encrypted = []
bittersweet = [int(r) for r in "{:b}".format(bytes_to_long(flag))]
for sugar in bittersweet:
	while True:
		gc_c = random.randint(65536, c_n1)
		if math.gcd(gc_c, c_n1) == 1:
			encrypted.append((pow(c_n2,sugar)*pow(gc_c,2)) % c_n1)
			break

print("c_n1 =",str(c_n1))
print("c_n2 =",str(c_n2))
print("encrypted = ", end='')
print(encrypted)

Flag dikonversi ke binary jadi ada 2 kemungkinan yakni 1 atau 0 untuk variable sugar. Disini kita bisa mengembalikan nilai dari binary tersebut dengan cara mengecek apakah nilai pada encrypted merupakan bilangan square atau bukan , karena c_n1 dan g_c relatif prima namun c_n1 bukan prima maka kita bisa gunakan jacobi symbol untuk mengetahui apakah suatu bilangan square atau bukan. Berikut solver yang kami gunakan

from Crypto.Util.number import *
from libnum import *

c_n1 = 3855144799899048327534121215306941141185997589420691125094911911082597963257300429096794014315805279596530735439263764994759442420373314885435640329972555
c_n2 = 5299396373535953706628077154342198627748435935987447573061077335778202151741165833985790411265547771371574434052556785516415658261684773030001154912306733
encrypted = [507104000732472450402938437721529021378564745838604181711052463510983043412099070337891206768987338263502149153936534933899109822282227342709312445026628,...SNIPPET…, 1983121417614455624787082919584128947462950990156463566859101453080668678780641745395775761769267205914558434913337236643284756856405940720684555555234672]

res = ""
for i in encrypted:
	if(jacobi(i,c_n1)==0):
		res += "1"
	else:
		res += "0"
print(long_to_bytes(int(''.join(res),2)))

Flag : NCW22{j4c0bi_symb0ls_101_w!th_c0mposit3_numbers}

Turmoil (491 pts)

Description

-

Solution

Diberikan file soal.py sebagai berikut

from Crypto.Util.number import *
import random
import math
m = bytes_to_long(b"REDACTED")

def primevalue(value):
	ind = 0
	while not isPrime(value):
		value += 1
		ind += 1
	print(f"added {ind}")
	return value

def generatePrimes():
	print("generating random numbers...")
	p = random.getrandbits(512)
	q = random.getrandbits(512)
	print("calculating next prime...")
	p = primevalue(p)
	q = primevalue(q)
	print("comparing values...")
	print("=======| > |=======") if p > q else print("=======| < |=======")
	return p, q

while True:
	try:
		print("==================================")
		print("J&M's EncRSAyption MacRSAhine 3000")
		print("==================================")
		print("1. Spill Administrator's message")
		print("2. Encrypt your own message")
		pilihan = input("[?] ")
		if pilihan == "1":
			p, q = generatePrimes()
			e = primevalue(random.randint(3, 100000))
			n = p*q
			c = long_to_bytes(pow(m, e, n))
			print("\nToo bad this part is highly confidential, only the ciphertext are allowed to be displayed.")
			print(f"[>] {c.hex()}\n")
		elif pilihan == "2":
			p, q = generatePrimes()
			n = p * q
			phi  = (p-1)*(q-1)
			print("")
			print("Input plaintext")
			message = bytes_to_long(input("[?] ").encode())
			while True:
				print("Input your exponent")
				e = int(input("[?] "))
				if math.gcd(e, phi) != 1:
					print('Error! exponent and totient have same factor(s)')
				else:
					d = inverse(e, phi)
					print("Imma just show this to you, you already know your own message anyway")
					print(f"d = {d}")
					print("Use this exponent? (Y/N)")
					choice = input("[?] ")
					if choice == "Y" or choice == "y":
						break
					elif choice == "N" or choice == "n":
						pass
			c = pow(message, e, n)
			print("Here's the result:")
			print(f"[>] n = {n}\n[>] e = {e}\n[>] c = {c}\n")
	except:
		print('Error\n')
from math import gcd
from randcrack import RandCrack
from pwn import *
from Crypto.Util.number import *

# import fractions  # for gcd function (or easily implementable to avoid import)
import random  # for random elements drawing in RecoverPrimeFactors


def failFunction():
    print("Prime factors not found")


def outputPrimes(a, n):
    p = gcd(a, n)
    q = int(n // p)
    if p > q:
        p, q = q, p
    # print("Found factors p and q")
    # print("p = {0}".format(str(p)))
    # print("q = {0}".format(str(q)))
    return p, q


def RecoverPrimeFactors(n, e, d):
    k = d * e - 1
    if k % 2 == 1:
        failFunction()
        return 0, 0
    else:
        t = 0
        r = k
        while(r % 2 == 0):
            r = int(r // 2)
            t += 1
        for i in range(1, 101):
            g = random.randint(0, n)  # random g in [0, n-1]
            y = pow(g, r, n)
            if y == 1 or y == n - 1:
                continue
            else:
                for j in range(1, t):  # j \in [1, t-1]
                    x = pow(y, 2, n)
                    if x == 1:
                        p, q = outputPrimes(y - 1, n)
                        return p, q
                    elif x == n - 1:
                        continue
                    y = x
                    x = pow(y, 2, n)
                    if x == 1:
                        p, q = outputPrimes(y - 1, n)
                        return p, q

def primevalue(value):
	ind = 0
	while not isPrime(value):
		value += 1
		ind += 1
	return value

pub_exp = [65537]
def get_pq(n,list_d,p_add,q_add,cmp_val,one_factor=False):
	for i in range(len(pub_exp)):
		e = pub_exp[i]
		d = list_d[i]
		p,q = RecoverPrimeFactors(n,e,d)
	if(cmp_val):
		tmp_p = max(p,q)
		tmp_q = min(p,q)
	else:
		tmp_p = min(p,q)
		tmp_q = max(p,q)
	p = tmp_p - p_add
	q = tmp_q - q_add
	# print("p = {0}".format(str(p)))
	# print("q = {0}".format(str(q)))
	while p > 0:
		rc.submit(p % (1 << 32))
		p = p >> 32
	if(one_factor==False):
		while q > 0:
			rc.submit(q % (1 << 32))
			q = q >> 32
	
rc = RandCrack()
r = remote("103.167.136.75",9966)
# r = process("./soal.py")
for i in range(20):
	# print(i)
	r.recvuntil(b"[?] ")
	r.sendline(b"2")
	r.recvuntil(b"added ")
	p_add = int(r.recvline().strip().decode())
	r.recvuntil(b"added ")
	q_add = int(r.recvline().strip().decode())
	r.recvuntil(b"=======|")
	cmp_val = r.recvline().strip().decode()
	r.recvuntil(b"[?] ")
	r.sendline(b"a")
	list_d = []
	for e in pub_exp:
		r.recvuntil(b"[?] ")
		r.sendline(str(e).encode())
		zzz = r.recvline()
		if(b"Error!" in zzz):
			list_d.append(0)
			continue
		r.recvuntil(b"d = ")
		d = int(r.recvline().strip().decode())
		list_d.append(d)
		r.recvuntil(b"[?] ")
		# print(e)
		if(e == pub_exp[-1]):
			r.sendline(b"Y")
		else:
			r.sendline(b"N")
	r.recvuntil(b"n = ")
	n = int(r.recvline().strip().decode())
	if(i==19):
		if(">" in cmp_val):
			get_pq(n,list_d,p_add,q_add,True,True)
		else:
			get_pq(n,list_d,p_add,q_add,False,True)
	else:
		if(">" in cmp_val):
			get_pq(n,list_d,p_add,q_add,True)
		else:
			get_pq(n,list_d,p_add,q_add,False)
print("noice")
r.recvuntil(b"[?] ")
r.sendline(b"1")
r.recvuntil(b"added ")
e_add = int(r.recvline().strip().decode())
r.recvuntil(b"[>] ")
ct = bytes_to_long(bytes.fromhex(r.recvline().strip().decode()))
print("CT",ct)
r.close()
junk = rc.predict_randrange(0, 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084095)
p = rc.predict_randrange(0, 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084095)
q = rc.predict_randrange(0, 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084095)
p = primevalue(p)
q = primevalue(q)
# print(p)
# print(q)
phi = (p-1)*(q-1)
n = p*q
for e in range(3, 100000):
	if(isPrime(e)):
		try:
			d = inverse(e,phi)
			tmp = long_to_bytes(pow(ct,d,n))
			if(b"NCW" in tmp):
				print(e,tmp)
				break
			if(tmp.decode()):
				print(e,tmp)
				break
		except:
			continue

Flag : NCW22{ReCoVer_PriMes_tO_dIsCoVEr_PriMes}

PreviousMiscNextCompfest Final

Last updated 9 months ago

Intinya kita bisa melakukan predict terhadap nilai prime karena digenerate berdasarkan getrandbits. Untuk nilai state sebelumnya kita bisa dapatkan karena kita mengetahui nilai d,e,n dan bisa melakukan recover terhadap p,q dimana p,q bisa kita kembalikan ke nilai state (getrandbits) dengan mengurangkan sesuai dengan penambahannya. Dan untuk mengetahui mana p dan q bisa dari hasil recover bisa diketahui dengan keterangan tambahan mengenai nilai besar kecil dari p q pada bagian “comparing values” . Terakhir cukup brute e pada enkripsi flag karena nilai e tidak terlalu besar. Disini sempet stuck karena mencoba mengimplementasikan recovery p,q secara naive (bisa dapat bisa tidak) yang ternyata setelah mencari-cari ada scriptnya :3 . Berikut solver yang kami gunakan.

📚
📖
https://github.com/truongkma/ctf-tools/blob/master/RecoverPrimeFactors.py
Here
Here
Here