2024长城杯铁人三项初赛

前言

    很有幸可以参加这次的长城杯初赛,第三赛区多少少有点太难了(疯狂吐槽),密码写出来了两题,一题签到,一题rsa。


normalrsa

给了一个二进制文件,其实就是c,另一个文件是乱码,都导入到工具箱中可以直接得到n,c,e,然后尝试着分解n,结果真出来了,那么flag就出来了。

(就最后一点点)


challange

是一道很明显的e过大和类似于连分数类型的题目,可以去参考这个师傅博客里面的内容https://lazzzaro.github.io/2020/05/06/crypto-RSA/,当然也可以去nssctf里面去看,里面有讲解和配对的习题。

————————————

 

题目

#!/usr/bin/env python3
from Crypto.Util.number import *
from math import gcd

def keygen(nbit, dbit):
assert 2*dbit < nbit
while True:
u, v = getRandomNBitInteger(dbit), getRandomNBitInteger(nbit // 2 – dbit)
p = u * v + 1
if isPrime(p):
while True:
x, y = getRandomNBitInteger(dbit), getRandomNBitInteger(nbit // 2 – dbit)
q = u * y + 1
r = x * y + 1
if isPrime(q) and isPrime(r):
while True:
e = getRandomNBitInteger(dbit)
if gcd(e, u * v * x * y) == 1:
phi = (p – 1) * (r – 1)
d = inverse(e, phi)
k = (e * d – 1) // phi
s = k * v + 1
if isPrime(s):
n_1, n_2 = p * r, q * s
return (e, n_1, n_2)

def encrypt(msg, pubkey):
e, n = pubkey
return pow(msg, e, n)

nbit, dbit = 1024, 256

e, n_1, n_2 = keygen(nbit, dbit)

FLAG = int(FLAG.encode(“utf-8”).hex(), 16)

c_1 = encrypt(FLAG, (e, n_1))
c_2 = encrypt(FLAG, (e, n_2))

print(‘e =’, e)
print(‘n_1 =’, n_1)
print(‘n_2 =’, n_2)

print(‘enc_1 =’, c_1)
print(‘enc_2 =’, c_2)

# e = 98467641690093871695975267875795181585857989477939466388009417059131670850127
# n_1 = 64521998900946151035183250161361578590562898382852517840849876271081392030031478373013958266147661124818863160595707167944931647973532540982401464973584021447422475868642097572419813003671216480805967701734701439164191640156357221192923526468945493032975925992013636078779749848731628561181164769185524770589
# n_2 = 36054324863568917511130648763027165052886430166527588098384118258948926960785865728094271975577562345932247144759061359056537900829252352901512813929996631705102975455228713114838828313022933493627416617967097921738345054995913178996631066725890217631952233116357709092349310952226981239074912741833028864549
# enc_1 = 44409530711611323971318548112765117429254234773113032975079541538836074541902571432094967280311956244304196918788882147751568079628816573837227196431565600487906430653102753682987284091056610196645602610743599718659750856474574422459340904042648646992537529462261441494430867623023213656814387251664662129314
# enc_2 = 4839505804094209210134989537374676295205076918332316790821587122796708880477883386797213308650255056165174482638715054174457192839650288569888079975883348512160642182072963895694733760983833154108923043128161463710202982360661381008676286064498611857732239429580056063695889933346958696980759190313056536538

————————————————

分析

首先最基础的就是 p = u * v + 1,q = u * y + 1,r = x * y + 1,s = k * v + 1,那么就可以知道phi=(p-1)*(r-1)=u*v*x*y,然后这个题目一共给了两组n,那么我们只需要通过一组就可以去求出flag了。知道n2=q*s,n1=p*r,那么n2/n1=q*s/p*r=(u * y + 1)*( k * v + 1)/(u * v + 1)*(x * y + 1)≈uykv/uvxy=k/x   (类似于连分数),一个1024位,一个256位,直接看出来wiener攻击的话就不会陌生的,直接去敲代码就行了。

————————————————

exp

from Crypto.Util.number import *
from tqdm import tqdm
from sage.modules.free_module_integer import IntegerLattice
def inthroot(a, n):
    if a < 0:
        return 0
    return a.nth_root(n, truncate_mode=True)[0]
def solve(n, phi):
    tot = n – phi + 1
    dif = inthroot(Integer(tot * tot – 4 * n), 2)
    dif = int(dif)
    p = (tot + dif) // 2
    q = (tot – dif) // 2
    if p * q == n:
        return p, q
    return None, None
e = 98467641690093871695975267875795181585857989477939466388009417059131670850127
n_1 = 64521998900946151035183250161361578590562898382852517840849876271081392030031478373013958266147661124818863160595707167944931647973532540982401464973584021447422475868642097572419813003671216480805967701734701439164191640156357221192923526468945493032975925992013636078779749848731628561181164769185524770589
n_2 = 36054324863568917511130648763027165052886430166527588098384118258948926960785865728094271975577562345932247144759061359056537900829252352901512813929996631705102975455228713114838828313022933493627416617967097921738345054995913178996631066725890217631952233116357709092349310952226981239074912741833028864549
enc_1 = 44409530711611323971318548112765117429254234773113032975079541538836074541902571432094967280311956244304196918788882147751568079628816573837227196431565600487906430653102753682987284091056610196645602610743599718659750856474574422459340904042648646992537529462261441494430867623023213656814387251664662129314
enc_2 = 4839505804094209210134989537374676295205076918332316790821587122796708880477883386797213308650255056165174482638715054174457192839650288569888079975883348512160642182072963895694733760983833154108923043128161463710202982360661381008676286064498611857732239429580056063695889933346958696980759190313056536538
c = continued_fraction(Integer(n_2) / Integer(n_1))
for i in tqdm(range(1, 150)):
    k = c.numerator(i)
    x = c.denominator(i)
    if GCD(e, k) != 1:
        continue
    res = inverse(e – k, e)
    cc = crt(res, 0, e, x)
    md = e * x // GCD(e, x)
    st = cc + (n_1 // md) * md – 100 * md
    for j in range(200):
        if GCD(e, st) != 1:
            st += md
            continue
        d_1 = inverse_mod(e, st)
        flag = long_to_bytes(power_mod(enc_1, d_1, n_1))
        if b’flag’ in flag:
            print(flag)
        st += md
#flag{__Lattice-Based_atT4cK_on_RSA_V4R1aN75}
——————————————————
当然了,如果你善用搜索引擎的话是可以搜到一篇和这个题一样的题的,只有数据不同https://blog.cryptohack.org/cryptoctf2021-hard#dorsa,当然了,还是自己掌握更好,但是比赛的时候绝对能秒出flag

decrypt

题目

import random
import socketserver
import codecs
import os
import hashlib
from Crypto.Cipher import AES
from flag import flag, imessage
import signal

key = os.urandom(16)
lists = “ABCDEFGHIJKLMNOPQRSTUVWXY0123456789”

class MyCBC(object):

def encrypt(self, plaintext):
cipher_bytes = codecs.decode(plaintext, “hex”)
encrypt_plain = AES.new(key, AES.MODE_CBC, key).encrypt(cipher_bytes)
return codecs.encode(encrypt_plain, “hex”).decode()

def decrypt(self, ciphertext):
cipher_bytes = codecs.decode(ciphertext, “hex”)
decrypt_cipher = AES.new(key, AES.MODE_CBC, key).decrypt(cipher_bytes)
return codecs.encode(decrypt_cipher, “hex”).decode()

class MyCFB(object):

def encrypt(self, plaintext):
cipher = AES.new(key, AES.MODE_CFB, key, segment_size=8 * 16)
ciphertext = cipher.encrypt(codecs.encode(plaintext, ‘utf-8’))
return codecs.encode(ciphertext, “hex”).decode()

def decrypt(self, ciphertext):
cipher_hex = codecs.decode(ciphertext, “hex”)
cipher = AES.new(key, AES.MODE_CFB, key, segment_size=8 * 16)
plaintext_bytes = cipher.decrypt(cipher_hex)
plaintext = codecs.decode(plaintext_bytes, ‘utf-8′, errors=’ignore’)
return plaintext

class ForkServer(socketserver.ForkingMixIn, socketserver.TCPServer):
pass

class MyTCPHandler(socketserver.BaseRequestHandler):

def handle_timeout(self, signum, frame):
raise TimeoutError

def MyCheck(self):
list_result = ”.join(random.choices(lists.lower(), k=16))
hash_result = hashlib.md5(list_result.encode()).hexdigest()
self.request.sendall(f”hash_result: {hash_result}\nre_list: keys + {list_result[4:]}\n”.encode())
self.request.sendall(f”input keys:”.encode())
plain_text = self.request.recv(1024).strip().decode()
if len(plain_text) != 4 or hashlib.md5((plain_text + list_result[4:]).encode()).hexdigest() != hash_result:
self.request.sendall(f”error\n”.encode())
return False
return True

def handle(self):
try:
signal.signal(signal.SIGALRM, self.handle_timeout)
signal.alarm(60)
if not self.MyCheck():
return

signal.alarm(120)
self.request.sendall(
“Choose an option:\n1. Decrypt\n2. Encrypt\n3. Get message\n4. Check message\n”.encode())
user_choice = self.request.recv(1024).strip().decode()

if user_choice == “1”:
self.request.sendall(“Enter text to decrypt: “.encode())
cipher_text = self.request.recv(1024).strip().decode()
decrypted_text = MyCBC().decrypt(cipher_text)
self.request.sendall(f”Decrypted text: {decrypted_text}”.encode())

elif user_choice == “2”:
self.request.sendall(“Enter text to encrypt: “.encode())
plain_text = self.request.recv(1024).strip().decode()
encrypted_text = MyCBC().encrypt(plain_text)
self.request.sendall(f”Encrypted text: {encrypted_text}”.encode())
elif user_choice == “3”:
self.request.sendall(“Get message: “.encode())
key_text = self.request.recv(1024).strip().decode()
user_key_bytes = codecs.decode(key_text, “hex”)
if user_key_bytes == key:
self.request.sendall(f”message text: {imessage}”.encode())
else:
self.request.sendall(f”error”.encode())

elif user_choice == “4”:
for i in range(24):
self.request.sendall(“imessage: “.encode())
message_hex = self.request.recv(1024).strip().decode()
if len(message_hex) > 2048:
self.request.sendall(“too long: “.encode())
break
if len(message_hex) % 2 != 0:
self.request.sendall(“Invalid imessage length.”.encode())
break
plain_text = MyCFB().decrypt(message_hex)
self.request.sendall(f”imessage text: {plain_text}\n”.encode())
if plain_text == imessage:
self.request.sendall(f”flag: {flag}”.encode())
break
else:
self.request.sendall(“Invalid choice. Closing connection.”.encode())
except TimeoutError:
self.request.sendall(“\nConnection refused”.encode())
self.request.close()
except Exception as err:
print(err)
finally:
self.request.close()

if __name__ == “__main__”:
HOST, PORT = “0.0.0.0”, 10000
print(HOST, PORT)
with ForkServer((HOST, PORT), MyTCPHandler) as server:
server.serve_forever()

————————————————

比赛的时候并没有做出来,和交互环境第一开始没有配置好有关,后面用了我们队伍pwn手的电脑才开始去写。

————————————————

分析

首先就是这玩意的nc链接端口是10000,额,怎么说呢,直觉,或者说是上面就这一个长得像端口的数,然后整体的代码采用了基于TCP服务器的加密(TCP可以直接忽略),首先咱们要通过check这个检查代码,然后才能进入到下一步的输入1,2,3,4去和他进行加密,解密,生成message和求出flag的操作。

1.通过check

首先可以先尝试往里面输入点随意的数,然后发现返回的都是flag+什么什么的,同时咱们只要满足hashlib.md5((plain_text + list_result[4:]).encode()).hexdigest() != hash_result:这个要求就可以,那么就直接取决于我们的后四位随机字符,那就只要尝试爆破这个就行了

2.然后不会了,等官方wp出来后更新吧


总结一下,这次长城杯是我第一次参加很正规的比赛,作为一个大一新生刚学密码真的很紧张,但是表现的还行,继续加油。追逐前人步伐,开创自己的路。
心如草木,向阳而生

评论

  1. 6 月前
    2024-4-18 17:39:00

    🐮

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇