目录
睡一觉醒来,比赛已经结束了,还以为是48小时赛,结果是12小时的。还是一样,把没完成的也放上来,等WP
第一个题给了两个雪花的图,一猜就是异或。直接写程序,生成的文件就看着了。
- from PIL import Image
-
- im1 = Image.open('challenge.png')
- im2 = Image.open('whoami.png')
- im3 = Image.new('RGB',(602, 602))
- for i in range(602):
- for j in range(426):
- p1 = im1.getpixel((i,j))
- p2 = im2.getpixel((i,j))
- c = (p1[0]^p2[0], p1[1]^p2[1], p1[2]^p2[2])
- im3.putpixel((i,j), c)
-
- im3.save('aaa.png')
- #ptm{y0u_r34lly_7r4c3d_m3}
一个RSA的题,先看题
- # The following imports are from the pycryptodome library
- from Crypto.Util.number import isPrime, bytes_to_long
- from functools import reduce
- import random
- import os
-
-
- flag = os.getenv('FLAG', 'ptm{fake_flag}')
-
- #p-1光滑
- def getPrime() -> int:
- # Magic function to get 256 bits or more prime
- while True:
- p = random.randint(2, 2**16)
- ds = [int(d) for d in str(p)]
- r = reduce(lambda x, y: x * y, ds)
-
- if r in [1, 0]:
- continue
-
- while not isPrime(r) or r <= 2**256:
- r = r * 2 - 1
- return r
-
-
- if __name__ == '__main__':
- p, q = getPrime(), getPrime()
- N = p * q
- e = 65537
- ciphertext = pow(bytes_to_long(flag.encode()), e, N)
- print('N =', N)
- print('ciphertext =', ciphertext)
这里自制的getPrime函数是p-1只有小素因子,所以这个p-1光滑。知道这个就直接找个模板把p,q求出来就OK了
- N = 19947485316056905993931646775941987256548403731465180084945508247185642344122444186584301925382000751483279209250816790912519050540122026105676356199286065255875041514980612323221784967308146326689205858291964161149849179979371164314385332438988323302642256355694342283417841306799868619347413738695017860092178971579146235735267010603291619706159760367889906915448176629836688823504117353814051485333797705641462699567204450801352179713
- c = 3378835538025100066858189605253385186193182606568947285413151320702836498308597573504106146927194477658866999634334567520784696503261127472226506671872322090990356345087228892030181029727782257077045419267662772484081883662849307300946673299443737643159198620964876221768731320724777961634357841823079813297467591107634823086591388724216402913192084061935863891901795120253011313582433207228716480519477417177404112549120051567425697098
- e=0x10001
-
- from Crypto.Util.number import *
- import gmpy2
-
- a = 2
- n = 2
- while True:
- a = pow(a, n, N)
- res = gmpy2.gcd(a-1, N)
- if res != 1 and res != N:
- q = N // res
- print("n=",n)
- print("p=",res)
- print("q=",q)
- break
- n += 1
-
- d=gmpy2.invert(e,(res-1)*(q-1))
- m=pow(c,d,N)
- print(long_to_bytes(m))
- '''
- n= 2239
- p= 1314596710707653149311136764052831401073538306751432047628406121315154001807902076228805514345874281522125602817
- q= 15173843927632442919613635524333831862871450087005529435568948684618918269488151162306655015617114426998556243640500992982004723780891204718873910826807240165678759401233834403542378489790050812582318833145503606858757998522994930749525935943822930489425103924160896504876495676935561736709843740413805282052349714715102937089
- b'ptm{d37erm1n1s71c_pr1me5_1sn7_4_g00d_id3a}'
- '''
这题有4种操作,随机抽取(RSA仅用1次)进行20次加密
- # The following imports are from the pycryptodome library
- from Crypto.Util.number import bytes_to_long, long_to_bytes, getPrime
- import hashlib
- import base64
- import random
- import os
-
-
- def RSA(x: bytes) -> bytes:
- e = 65537
- random.seed(bytes_to_long(x[:4]))
- p = getPrime(1024, randfunc=random.randbytes)
- q = getPrime(1024, randfunc=random.randbytes)
- N = p * q
- return long_to_bytes(pow(bytes_to_long(x), e, N))
-
-
- def rot13(x: bytes) -> bytes:
- return x.translate(bytes.maketrans(
- bytes([i for i in range(256)]),
- bytes([(i + 13) % 256 for i in range(256)])
- ))
-
-
- possible_methods = [
- base64.b64encode,
- lambda x: x[::-1],
- RSA,
- rot13
- ]
- flag = os.getenv('FLAG', 'ptm{ju57' + 'X' * (64 - 8 - 6) + 'tr1ck}').encode()
- assert (
- flag.startswith(b'ptm{ju57')
- and flag.endswith(b'tr1ck}')
- and len(flag) == 64
- )
-
-
- if __name__ == '__main__':
- print('Hi challenger! I\'ll give you a flag encoded and encrypted with some magic methods that only the best cryptographers know!')
- print('If you want to get the flag, you will have to read the source code and try to invert all my special algorithms. I will give you the list of steps I have used and the result of all of them, good luck!')
- print()
-
- steps = []
- i = 0
-
- while i < 20:
- chosen = random.randint(0, len(possible_methods) - 1)
-
- if chosen == 2 and chosen in steps:
- # We don't want to use RSA twice
- continue
- steps.append(chosen)
- flag = possible_methods[chosen](flag)
- i += 1
- print(steps)
- print(flag.hex())
问题就在RSA这,它用明文的前4个字节作种子生成pq然后加密,由于已经给出初始值仅一次RSA的话,通过另外3种编码依然能得到前4个字节,只要先正向操作用fake得到前4个字节,然后再逆向操作过一遍就行了 。本来本地运行没问题,但远程不对,错在RSA这块上边,应该是取的pq不对。
- from gmpy2 import invert
- from Crypto.Util.number import bytes_to_long, long_to_bytes, getPrime
- from base64 import b64decode, b64encode
- import random
-
-
- step = [2, 3, 3, 1, 3, 3, 1, 0, 1, 3, 0, 3, 3, 3, 0, 1, 3, 3, 0, 1]
- #true
- flag = bytes.fromhex('3d3d77664b573263384a5752774a58634b5745674e42476a45714961532b58695036476748433157786c346a7252596353756b68694a3455424748546d4648694c7448684c4e4958784e3254375a59544d5a6d6878745554425347614c4e34594f36346850395554462b6b6a4f43345347716f637a70496b374648584e424964546c49676b425867444b6d6b514f58594b3655634b36346644535863413648694c424a667756325a4679305350524959444b6e634a79566b2f6449546f465869502b47684e746b6b4a4b6d6b4f324859546c55684d64596641796b6b50566f594c566b6367355853414748546c4e5954504649676a5645637a524755714259544d6832674a323159386c3453793933634336556349656f61454b6d6b396859544336346847574761414f485841533454775233654a4f5653447530554e743353437945685142326377355559744e48594757456630396f5a2f743066634a33634b6d306677563057373555526f4e49632b7845666a396b55384e58526f784863536d30674c4a6f53766c5959755634534d64576769745553447149624c783359475333674c4e31553864345352524969544e6e634f784563462b456354316e594c7849674d786b63794e6d6951535959544a466749436e66414732544a2b47694c4e486678393457384632534e426f682b356b634f393462385248584e316e594c35346678746b6a376c595874425963647831664c4e495844326b6b534258694c4a6c6648796b5a384233557842495a6f7049684a75456a794a32544e7848545347586777353354494f6d6930465963447956684d3131664143326975396e54507546667831315778526d6b4e536f634d7846676a39456b2b4e33686f42496353326e664e3930553868595275426f635061476650356f55455348644b5749692b4e586737466d5a47534861784e4963474b4a674a79466a7846336a6e466f59683548674b476e62464f47594f2b48634861476769646f5a42476e6b54426f544c43336679705952464f58522b464963474b7063693948627a523255535a6f59683547674b3247582f355559734e58594c656d684961496a4171596139786e595436576779526e557835306a634249634c75486462643156')
- '''
- from pwn import *
- p = remote('tcp.challs.m0lecon.it', 9839)
- context.log_level = 'debug'
- p.recvuntil(b'\n\n')
- step = eval(p.recvline().strip().decode())
- flag = bytes.fromhex(p.recvline().strip().decode())
- '''
-
- def rsa(c):
- random.seed(bytes_to_long(head[:4]))
- p = getPrime(1024, randfunc=random.randbytes)
- q = getPrime(1024, randfunc=random.randbytes)
- print(p,q)
- n = p*q
- phi = (p-1)*(q-1)
- e = 65537
- d = invert(e, phi)
- return long_to_bytes(pow(bytes_to_long(c),d,n))
-
- def rot_13(x: bytes) -> bytes:
- return x.translate(bytes.maketrans(
- bytes([(i + 13) % 256 for i in range(256)]),
- bytes([i for i in range(256)]),
- ))
- def rot13(x: bytes) -> bytes:
- return x.translate(bytes.maketrans(
- bytes([i for i in range(256)]),
- bytes([(i + 13) % 256 for i in range(256)])
- ))
-
- head = ('ptm{ju57' + 'X' * (64 - 8 - 6) + 'tr1ck}').encode()
-
- possible_methods = [
- b64encode,
- lambda x: x[::-1],
- rsa,
- rot13
- ]
-
- for i in step:
- if i == 2:
- print(head[:4])
- break
- head = possible_methods[i](head)
-
- possible_methods2 = [
- b64decode,
- lambda x: x[::-1],
- rsa,
- rot_13
- ]
- for i in step[::-1]:
- flag = possible_methods2[i](flag)
- #print(i, flag)
-
- print(flag)
-
数据是从无端得到的,但解密不成功。
这是个DLP问题,但是给的数字都非常小
- # The following imports are from the pycryptodome library
- from Crypto.Util.number import getPrime
- from Crypto.Util.Padding import pad
- from Crypto.Cipher import AES
- from secret import message
- import random
- import os
-
-
- if __name__ == '__main__':
- print('Welcome to the Secret Service Agency, the most secret agency in the world!')
- print('We have found out that there is a mole between our specialized agents. One of our most capable men, Agent Platypus, has found out a communication between him and his accomplice encrypted with a key that they shared using the Diffie Hellman protocol beforehead.')
- print('Can you find out the key used to encrypt the message and decrypt it, knowing that the message has been encrypted with AES-CBC and the key has been derivated with "s.to_bytes(16, \'little\')", where "s" is the shared secret between the two? We hope to find out who the mole and his accomplice are!')
- print('Here it is the communication we have been able to intercept:')
- print()
-
- g = 2
- p = getPrime(64)
- a = random.randint(1, p-1)
- A = pow(g, a, p)
-
- print('Mole:')
- print('g =', g)
- print('p =', p)
- print('A =', A)
- print()
-
- b = random.randint(1, p-1)
-
- print('Accomplice:')
- print('B =', pow(g, b, p))
- print()
-
- key = pow(A, b, p).to_bytes(16, 'little')
- iv = os.urandom(16)
- cipher = AES.new(key, AES.MODE_CBC, iv)
-
- print('Mole:')
- print('IV =', iv.hex())
- print(
- 'Message =',
- cipher.encrypt(pad(message.encode(), AES.block_size)).hex()
- )
这里 B=pow(g, b, p), 然后 key = pow(A, b, p).to_bytes(16, 'little') 作key来进行AES加密,显然是求b
先在sagemath里把b求出来
- g = 2
- p = 14929217438252597329
- A = 10501271320711541452
- b = discrete_log(A,mod(g,p))
- #b = 5021798444659061638
然后再用AES解密
- from Crypto.Cipher import AES
- import random
- import os
-
- g = 2
- p = 14929217438252597329
- A = 10501271320711541452
-
- B = 11611457301040733008
-
- IV = 'c234aca8e7d86bfa33645b6a0239476e'
- Message = 'e8c5922fcf125cbf85ceec29e69f4ec682f398715d4052b0999c13b414c03faecc817cd68c707fec78cd748c7909679719044e7e50c062d674cc50bd49942c59f2e0ed8af615da277d0093a03ee3c748ca37b434225dae0566b24dd6abfe748919ae10faad4f9e28abe11232c7b95f84b641caa8a039fb8cd820e8599a4ebeb90e7b69de41c1cb9846023bb23b32e0c67e9bcaaf4e77faa297c8541c3bcd107c89c2ecf9df144820b99dbf95653fa0118040a712bd9165cac092a6ed16c1605bb0ec65db658af5d50f8333c7aaba2681a74dda167a2d030a1210fb16a05f583d'
-
- b = 5021798444659061638
- key = pow(A, b, p).to_bytes(16, 'little')
- cipher = AES.new(key, AES.MODE_CBC, bytes.fromhex(IV))
- m = cipher.decrypt(bytes.fromhex(Message))
- #b"Hi, I'm the Agent Gabibbo, the undercover agent in the SSA, I've successfully recovered the code that is used to access the secret files stored on the agency's server, here it is: ptm{us3_pr1m3s_wi7h_en0ugh_b17s}\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"
看上去像是打包的python程序,没解开
给了密文和加密方法
- __int64 __fastcall sub_401520(__int64 a1, __int64 a2, __int64 a3, __int64 a4, int a5, int a6)
- {
- int v6; // ecx
- const char *v7; // rbp
-
- v6 = 112;
- v7 = "tm{REDACTED}";
- do
- {
- ++v7;
- dword_4A70B0 = (dword_4A70B4 + dword_4A70B0 * dword_4A70B8) % dword_4A70BC;
- printf((__int64)"%02x", v6 ^ (unsigned int)(dword_4A70B0 % 256));
- v6 = *(v7 - 1);
- }
- while ( *(v7 - 1) );
- sub_410720(0xAu);
- return 0LL;
- }
这是个流加密,只要得到流再异或就行了
- b0 = 0x1AACF60
- b4 = 0x4A
- b8 = 0x4B
- bc = 0x10001
-
- v6 = 112
- box = []
- for i in range(42):
- b0 = ((b4+b0*b8)&0xffffffff)%bc
- box.append(b0&0xff)
-
- c = bytes.fromhex('1022179cd41e2bd156c393830b79ef960a007155f79d368290ad582e7f954deb1c91c03d07705ca964a3')
- print(bytes([c[i]^box[i] for i in range(42)]))
- #ptm{1_l0ve_l1n34r_c0ngru3nt1al_g3n3r4t0r5}
醒来提交的时候已经关闭了,不清楚对不对
- __int64 __fastcall checkPassword(_BYTE *a1)
- {
- __int64 result; // rax
- int v2; // [rsp+Ch] [rbp-Ch]
- int v3; // [rsp+10h] [rbp-8h]
- int i; // [rsp+14h] [rbp-4h]
-
- v2 = 4;
- while ( 2 )
- {
- if ( v2 > 14 )
- return 0LL;
- switch ( v2 )
- {
- case 4:
- if ( (a1[v2] ^ *a1) == 30 )
- goto LABEL_28;
- result = 1LL;
- break;
- case 5:
- if ( a1[v2] == 48 )
- goto LABEL_28;
- result = 1LL;
- break;
- case 6:
- if ( ((char)a1[v2] ^ (3 * (char)a1[v2 - 2])) == 318 )
- goto LABEL_28;
- result = 1LL;
- break;
- case 7:
- if ( a1[v2] == 95 )
- goto LABEL_28;
- result = 1LL;
- break;
- case 8:
- if ( (a1[v2] ^ a1[v2 + 4]) == 71 )
- goto LABEL_28;
- result = 1LL;
- break;
- case 9:
- if ( (char)a1[v2] * (char)a1[v2] * (char)a1[v2] == 110592 )
- goto LABEL_28;
- result = 1LL;
- break;
- case 10:
- if ( (char)a1[v2 + 1] + (char)a1[v2] == (char)a1[4] + 100 )
- goto LABEL_28;
- result = 1LL;
- break;
- case 11:
- if ( (unsigned int)((char)a1[v2] * (char)a1[v2 - 3] - 13225) <= 4 )
- goto LABEL_28;
- result = 1LL;
- break;
- case 12:
- if ( 4 * (char)a1[v2] == 208 )
- goto LABEL_28;
- result = 1LL;
- break;
- case 13:
- if ( a1[v2] == 102 )
- goto LABEL_28;
- result = 1LL;
- break;
- case 14:
- v3 = 0;
- for ( i = 0; i <= 15; ++i )
- v3 ^= (char)a1[i];
- if ( v3 == 20 )
- goto LABEL_28;
- result = 1LL;
- break;
- default:
- LABEL_28:
- ++v2;
- continue;
- }
- return result;
- }
- }
几乎第个字符是多少都给了,只是10,11,14没有,14是最后异或得到的,#10+#11<210,由于没有其它限制,这会生成很多解,我用等于求出一个看上去很正点的,但不清楚对不对.
- '''
- s[0] == 112
- s[1] == 116
- s[2] == 109
- s[3] == 123
- s[15]== 125
- s[4]^s[0] == 30^112 110
- s[5] == 48
- s[6]^(3*s[4]) == 318 116
- s[7] == 95
- s[8]^s[12] == 71 115
- s[9]*s[9]*s[9] == 110592
- s[11]+s[10] == s[4]+100
- s[11]*s[8] - 13225 <= 4
- s[12]*4 == 208 52
- s[13] == 102
- s[0]^...s[15]==20
- '''
- for x in range(95,127):
- s = [112,116,109,123,110,48,116,95,115,48,x,210-x,52,102,0,125]
- v3 = 20
- for i in s:
- v3^=i
- s[14] = v3
- print(bytes(s))
-
- #ptm{n0t_s0_s4f3}
- '''
- b'ptm{n0t_s0_s4f3}' <--还有很多猜测
- b'ptm{n0t_s0s_4f3}'
- b'ptm{n0t_s0t^4f5}'
- b'ptm{n0t_s0u]4f7}'
- b'ptm{n0t_s0v\\4f5}'
- b'ptm{n0t_s0w[4f3}'
- b'ptm{n0t_s0xZ4f=}'
- b'ptm{n0t_s0yY4f?}'
- b'ptm{n0t_s0zX4f=}'
- b'ptm{n0t_s0{W4f3}'
- b'ptm{n0t_s0|V4f5}'
- b'ptm{n0t_s0}U4f7}'
- b'ptm{n0t_s0~T4f5}'
- '''
这个题很新颖.把flag按字母频排序(多到少,相同的按原顺序)然后作一次shift前排头的放到队尾,最后按flag字母对应的这个加密的表输出.远程提供自主加密和输出加密的flag
- #from flag import flag
- from random import randint
-
- flag = 'mtp{abcdeddc}'
- assert(len(flag) <= 50)
- shift = 1 #randint(1, len(set(flag)) - 1)
-
- def encrypt(data):
- charsf = {}
- for c in data:
- if c not in charsf.keys():
- charsf[c] = 1
- else:
- charsf[c] += 1
-
- chars = list(charsf.keys())
- chars.sort(reverse=True, key=lambda e: charsf[e]) #按出现频率排序
- print(chars)
- charsn = list(chars)
- for _ in range(shift):
- i = charsn.pop(0)
- charsn.append(i)
- print(charsn)
- enc = "".join(list(map(lambda c: charsn[chars.index(c)], data)))
- return enc
-
- if __name__ == "__main__":
- print("Welcome to our custom encrypting system!")
- print("1) Encrypt something")
- print("2) Get flag")
- print("3) Exit")
-
- opt = input("> ")
- while opt != "3":
- if opt == "1":
- data = input("What is your string?\n")
- print(encrypt(data))
- elif opt == "2":
- print(encrypt(flag))
- opt = input("> ")
一开始没想到怎么弄,然后想到密文.
如果不考虑shift的话,那密文的排列顺序是固定的,而加密是通过明文与密文的对应关系,那么输出的顺序就是明文对应位置的字符,通过第一个字符(flag的头几个字母是基本格式,这样就能弄到shift)
先用密文按字母频得到对应表,再按ptm{这个头得到shift后的表
- '''
- > 1
- What is your string?
- asdfghjklzxcvbnmqwertyuiopasdfghjkllko
- zxcvbnmjowertyuipklasdfgqhzxcvbnmjoojq
- > 2
- b{Da1f0gdp3q}o_umpeoqupmsfotmo3r{onyyc4
- '''
- #先按数量排序(前大后小),再作一次shift(从左弹出放右)
- #输出表里对应的内容
- '''
- aaabbcdef
- ['a', 'b', 'c', 'd', 'e', 'f']
- ['b', 'c', 'd', 'e', 'f', 'a']
- bbbccdefa
- ptm{
- [p,t,m,{, }]
- [b,{,D,a, 4]
- b{Da1f0gdp3q}o_umpeoqupmsfotmo3r{onyyc4
- ptm{ _ _ _ _ _ }
- #根据第1个字符的对应关系手调shift
- ['o', 'p', 'm', '{', 'f', '3', 'q', 'u', 'y', 'b', 'D', 'a', '1', '0', 'g', 'd', '}', '_', 'e', 's', 't', 'r', 'n', 'c', '4']
- ['y', 'b', 'D', 'a', '1', '0', 'g', 'd', '}', '_', 'e', 's', 't', 'r', 'n', 'c', '4', 'o', 'p', 'm', '{', 'f', '3', 'q', 'u']
- '''
- a = 'b{Da1f0gdp3q}o_umpeoqupmsfotmo3r{onyyc4'
- def encrypt(data):
- charsf = {}
- for c in data:
- if c not in charsf.keys():
- charsf[c] = 1
- else:
- charsf[c] += 1
-
- chars = list(charsf.keys())
- chars.sort(reverse=True, key=lambda e: charsf[e]) #按出现频率排序
- print(chars)
-
- #encrypt(a)
- v1 = ['o', 'p', 'm', '{', 'f', '3', 'q', 'u', 'y', 'b', 'D', 'a', '1', '0', 'g', 'd', '}', '_', 'e', 's', 't', 'r', 'n', 'c', '4']
- v2 = ['y', 'b', 'D', 'a', '1', '0', 'g', 'd', '}', '_', 'e', 's', 't', 'r', 'n', 'c', '4', 'o', 'p', 'm', '{', 'f', '3', 'q', 'u']
- flag = ''.join([v1[v2.index(c)] for c in a])
-
- print(flag)
- #ptm{fr3quency_b4seD_c4esar_1s_n0t_good}
流量题,说是对方给传了个图,然后删掉了,要从流量里找出来
图一般都很大,不是几个字符的,打到一个大包取出TCP流,看到是base64,解码后得到一张图
- a = open('aaa.txt').read()
- from base64 import *
- b = b64decode(a)
- open('bbb.txt', 'wb').write(b)
- #ptm{n37w0rk_ch4ll3n935_4r3_fun_2}