目录
没作几个题,网站太慢了,经常题都不出。
忘了记名字了,是个远程题,e=5不变,n,c在变化,显然是用中国剩余定理。然后再开5次幂。
- n1=10482537034616502990056118030126164434407037176718331962667011326955491120566031634285535049167438082826079349272253648544730225816672178907764563795724843238117833575393198105750393276477056062212621581826908061516664802589223889385525044351279674490228268440747101433020011881495784429621597371307426622757779128699745573729906521433559644189341958800662044774541
- c1=6087004369946053227982494913706901186274614577662910050380033779616661997035829135770453917032222963288513864576850581583066480871865034839084616393770636880369071627374934883683905306826847313587047467574498166973462816444236751014698316815611495234751053545484591628748764097916135305447550851423345959821240953597530179672401858302119597171603198037366269233719
- n2 =12367732114126301913737674911174659623260421701922083115463688097892335835832137676235926929476836047205277037213556311855697316742401499464166580788816568220539558161216494644597740553321733102039206472053356162972506585408259141048898509380926861285805055391399828624294182942246152692738571838819392996502010209610177387578042322991636983388504268335500249420617
- c2 =6598110242539995863074355056158570164049216335364925288931323757253535398103184489531242032575274289060700366841161402204146875959261549401532459608455604827722243085170385981035222200389913788409648676752548513449147184508753978498499016611762538512670708489158929810784104583789226504345306015964098627253554658284373096694929056015453847074887650556440052878630
- n3 =10256038725288950855196758629933306580783576388418827903732634844615198789778181879287006217785874404464941165322121223311218355864125867810588164953430819701659125700907576823337578399226408327622582145531259253939397764804840588945160103734078760521203955556671490266695737131932977852304750132447539392473513180775946728590263319845517676125152164659427731699479
- c3 = 7307506932852480055779150743698192577518060811090089847831839584489356780048260286294057804235251817041195453111379116685659989141101142713850347634848460781996991307627778136048623024426933507486743478530416521616605247651996711033755127847375528743357717132830144403674863976913789724872493255786744573370517927939711839563307201365321241992779597973050791722751
- e=5
- #sage
- #v = crt([c1,c2,c3],[n1,n2,n3])
- v =73448690174896106135676773887969898376313644525180577635638534667360398313545968245865457044768650498073919986296816184849746808491061728181876720693332170726810820658795124493571143780153343023652595257458464865059042345641702358771008787607355295320693998300553350404027525319624789400937306774517103831179992855723955092191381869960795275997575970901077630183000778125
- from gmpy2 import iroot
- m = iroot(v,5)[0]
- #(mpz(149003617072514967705362966617328574884671140357033588603732115961358085245), True)
- bytes.fromhex(hex(m)[2:])
- b'TUCTF{0bl1g4t0ry_RSA_chall_l0l}'
从名字上看是个栅栏密码,给了密文
0x56455a7059574e7459584a685a576c756557646f59565637633364765a57647664474e305a48427965584e4464476c6c62584e6c6257463165574e3059574e7a5647687a6247567a5a6d527a636d46796233427366513d3d
尾部的3D3D应该是个hex后的base,先转bytes再base64
- >>> bytes.fromhex('56455a7059574e7459584a685a576c756557646f59565637633364765a57647664474e305a48427965584e4464476c6c62584
- e6c6257463165574e3059574e7a5647687a6247567a5a6d527a636d46796233427366513d3d')
- b'VEZpYWNtYXJhZWlueWdoYVV7c3dvZWdvdGN0ZHByeXNDdGllbXNlbWF1eWN0YWNzVGhzbGVzZmRzcmFyb3BsfQ=='
- >>> from base64 import *
- >>> b64decode('VEZpYWNtYXJhZWlueWdoYVV7c3dvZWdvdGN0ZHByeXNDdGllbXNlbWF1eWN0YWNzVGhzbGVzZmRzcmFyb3BsfQ==')
- b'TFiacmaraeinyghaU{swoegotctdprysCtiemsemauyctacsThslesfdsraropl}'
可以明显看出来头部TUCTF{所在的位置,再用栅栏
TUCTF{thisisawelcomemessagefromdatasecurityandcryptographyclass}
RSA题,只给了p没有q,q是通过算法实现,不过这个运算次数并不大,不需要用智力处理
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """
- Created on Wed Nov 23 22:26:57 2022
- @author: weiping
- """
-
- import os
- import random
- from Crypto.Util.number import *
- import gmpy2
-
- flag = b'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
-
- class RSA():
- def __init__(self):
- self.p = getPrime(512)
- self.s = 0
- for i in range(1, 18000000):
- self.s += pow(i, self.p-2, self.p) #sum i^-1
- self.s = self.s % self.p
- self.q = gmpy2.next_prime(self.s)
- self.n = self.p * self.q
- self.phi = (self.p - 1) * (self.q - 1)
- self.e = 65537
- self.d = pow(self.e, -1, self.phi)
-
- def encrypt(self, m: int):
- return pow(m, self.e, self.n)
-
-
- def main():
- rsa = RSA()
- print(f"p = {rsa.p}")
- print(f"e = {rsa.e}")
- c = rsa.encrypt(bytes_to_long(flag))
- print('c = ', c)
- '''
- p = 11545307730112922786664290405312669819594345207377186481347514368962838475959085036399074594822885814719354871659183685801279739518405830244888530641898849
- e = 65537
- c = 114894293598203268417380013863687165686775727976061560608696207173455730179934925684529986102237419507146768083815607566149240438056135058988227916482404733131796310418493418060300571541865427288945087911872630289527954636816219365941817260989104786329938318143577075200571833575709614521758701838099810751
- '''
-
-
- if __name__ == "__main__":
- main()
照着原来的样子,重复一遍拿到q就OK了,只是时间需要一点点,毕竟不是智力方法,纯暴力。
- from Crypto.Util.number import *
- from gmpy2 import next_prime,invert
-
- p = 11545307730112922786664290405312669819594345207377186481347514368962838475959085036399074594822885814719354871659183685801279739518405830244888530641898849
- e = 65537
- c = 114894293598203268417380013863687165686775727976061560608696207173455730179934925684529986102237419507146768083815607566149240438056135058988227916482404733131796310418493418060300571541865427288945087911872630289527954636816219365941817260989104786329938318143577075200571833575709614521758701838099810751
-
- s = 0
- for i in range(1, 18000000):
- s += pow(i, -1, p) #sum i^-1
- s = s % p
-
- q = next_prime(s)
- phi = (p-1)*(q-1)
- d = invert(e, phi)
- m = pow(c,d,p*q)
- print(long_to_bytes(m))
- #TUCTF{syqow82pam_%shsjQF; ^7dagsWCpsp_#aes}
不过后来一想,这个题并不需要求q,因为m很小可以直接用p求
- d = invert(e,p-1)
- long_to_bytes(pow(c,d,p))
- #TUCTF{syqow82pam_%shsjQF; ^7dagsWCpsp_#aes}
前边是类似凯撒密码的偏移转码,后边是替换
- import string
-
- upperFlag = string.ascii_uppercase[:26]
- lowerFlag = string.ascii_lowercase[:26]
- MIN_LETTER = ord("a")
- MIN_CAPLETTER = ord("A")
-
- def mix(oneLetter,num):
-
- if(oneLetter.isupper()):
- word = ord(oneLetter)-MIN_CAPLETTER
- shift = ord(num)-MIN_CAPLETTER
- return upperFlag[(word + shift)%len(upperFlag)]
- if(oneLetter.islower()):
- word = ord(oneLetter)-MIN_LETTER
- shift = ord(num)-MIN_LETTER
- return lowerFlag[(word + shift)%len(upperFlag)]
-
- def puzzled(puzzle):
- toSolveOne = ""
- for letter in puzzle:
-
- if (letter.isupper()):
- binary ="{0:015b}".format(ord(letter))
-
- toSolveOne += upperFlag[int(binary[:5],2)]
- toSolveOne += upperFlag[int(binary[5:10],2)]
- toSolveOne += upperFlag[int(binary[10:],2)]
-
- elif(letter.islower()):
- six = "{0:02x}".format(ord(letter))
- toSolveOne += lowerFlag[int(six[:1],16)]
- toSolveOne += lowerFlag[int(six[1:],16)]
- elif(letter == "_"):
- toSolveOne += "CTF"
- return toSolveOne
-
-
- flag = "Figure it Out! :)"
- numShift = "??"
- mixed = ""
-
- assert all([x in lowerFlag for x in numShift])
- assert len(numShift) == 1
-
- encoding = puzzled(flag)
- print(encoding)
- for count, alpha in enumerate(encoding):
- mixed += mix(alpha, numShift)
-
- print(mixed)
但是偏移这块用的都是num减,这导致大小写减后模26后偏移不同。
密文比较特殊,看上去是盲文,提示是8点不是6点,但用的都是6点,是盲文的标记方法不同。
⠱⠁ ⠹⠣ ⠱⠹ ⠱⠁ ⠹⠣ ⠹⠳ ⠱⠁ ⠹⠣ ⠹⠪ ⠱⠁ ⠹⠣ ⠱⠩ ⠹⠣ ⠱⠩ ⠹⠱ ⠻⠁ ⠫⠩ ⠫⠡ ⠻⠻ ⠹⠣ ⠱⠩ ⠹⠱ ⠻⠁ ⠻⠪ ⠻⠁ ⠻⠱ ⠫⠡ ⠻⠻ ⠫⠡ ⠫⠩
先来手搓,得到密文
5a42545a42485a42495a42534253457a6361774253457a797a7561776163
然后再进行偏移转码
- #a = bytes.fromhex('5a42545a42485a42495a42534253457a6361774253457a797a7561776163').decode()
- a = 'ZBTZBHZBIZBSBSEzcawBSEzyzuawac'
- for i in range(ord('a'), ord('z')+1):
- tv = ''
- for v in a:
- if v.isupper():
- tv += chr((ord(v) - i)%26 + ord('A'))
- else:
- tv += chr((ord(v) - i)%26 + ord('a'))
- print(tv)
- #ACUACIACJACTCTFgjhdCTFgfgbhdhj
后边继续手搓
- '''
- ACU ACI ACJ ACT _ gj hd _ gfgbhdhj
- 0,2,20 0,2,8 0,2,9 0,2,19 _ 后边转后是16进制 69 73 65617379
- THIS_is_easy
- TUCTF{THIS_is_easy}
- '''
这类题型原来没见过,不知道叫什么,作完应该就是叫编程。
只有远端,连上去发现是个简单算式要求输入结果。编个循环eval处理。快到出flag的时候会出个exec(...) ,这时候eval会把程序办掉(这是说eval不安全,前几天看别人的都是用另一个安全的替代),知道是啥了就好办,检查到直接跳过就行了。
- from pwn import *
- from ast import literal_eval
-
- p = remote('chals.tuctf.com', 30202)
- context.log_level = 'debug'
-
- while True:
- a = p.recvline()
- if b'exec' in a:
- a = p.recvline()
- b = eval(a)
- p.sendlineafter(b'Answer: ', str(b).encode())
- p.recvline()
-
- '''
- [DEBUG] Received 0x1ff bytes:
- b'Correct!\n'
- b'exec(\'\\nimport os\\nscript_path = os.path.realpath( __file__ )\\nnew_program = ""\\nwith open( script_path, "r" ) as f:\\n lines = f.readlines()\\n for line in lines:\\n for char in line:\\n if char.isalpha():\\n new_program += chr( ord( char ) + 1 )\\n else:\\n new_program += char\\nwith open( script_path, "w" ) as f:\\n f.write( new_program )\\nos.system( "cls" )\\nos.system( "clear" )\\n\')\n'
- b'6993 - 5654 * 1086 + 6334 + 9502 - 954 + 126\n'
- b'Answer: '
- [DEBUG] Sent 0x9 bytes:
- b'-6118243\n'
- [DEBUG] Received 0x46 bytes:
- b'Correct!\n'
- b'5766 - 5967 - 4411 - 857 + 7792 + 5427 - 1369 + 7819\n'
- b'Answer: '
- [DEBUG] Sent 0x6 bytes:
- b'14200\n'
- [DEBUG] Received 0x52 bytes:
- b'Correct!\n'
- b'Here is your flag: TUCTF{7h4nk5_f0r_74k1n6_7h1n65_4_l177l3_5l0w_4268285}\n'
- '''
第二道是个迷宫,走路的
- '''
- XOOOO###############
- ####OOOOOOOOOOOOOOO#
- ##################O#
- ##################O#
- ########OOOOOOOOOOO#
- ########OOOOOOO#####
- ##############O#####
- ##############OOO###
- ################O###
- ################O###
- ############OOOOO###
- ############OOOOOOOO
- '''
没说要走到哪,手工试了一次是走到右下角。并且只有下左右3个方向可走,应该是要写遍历程序处理。其实10关和1000关没啥区别,可以也太漫长了,复杂度在加大,感觉题没个完,去了个超市回来才出。
- from pwn import *
-
- p = remote('chals.tuctf.com', 30204)
- context.log_level = 'debug'
-
- simple = '''
- XOOOO###############
- ####OOOOOOOOOOOOOOO#
- ##################O#
- ##################O#
- ########OOOOOOOOOOO#
- ########OOOOOOO#####
- ##############O#####
- ##############OOO###
- ################O###
- ################O###
- ############OOOOO###
- ############OOOOOOOO
- '''
- ok = ''
- width = 20
- height = 11
- def get_v(m,s, plc):
- global ok
- if ok != '':
- return False
- if plc == [height-1,width-1]:
- ok = s
- return True
- x,y = plc
- #print(1, s)
- if x
1 and m[x+1][y] == 'O': - ts = s+'V'
- tm = m.copy()
- tm[x][y] = '#'
- get_v(tm,ts,[x+1,y])
- #print(2, s)
- if y
1 and m[x][y+1] == 'O': - ts = s+'>'
- tm = m.copy()
- tm[x][y] = '#'
- get_v(tm,ts,[x,y+1])
- #print(3, s)
- if y>0 and m[x][y-1] == 'O':
- ts = s+'<'
- tm = m.copy()
- tm[x][y] = '#'
- get_v(tm,ts,[x,y-1])
- return
-
- def test():
- global ok
- a = simple.split('\n')[1:]
- m = [[0 for j in range(width)] for i in range(height)]
- for i in range(height):
- for j in range(width):
- m[i][j] = a[i][j]
- print(m)
- get_v(m,'',[0,0])
- print(ok)
-
- #test()
-
- def maze():
- global ok,width,height
- a = p.recvuntil(b'Move').decode().split('\n')[:-1]
- width = len(a[0])
- height = len(a)
- print(width,height, a)
- m = [[0 for i in range(width)] for j in range(height)]
- for i in range(height):
- for j in range(width):
- m[i][j] = a[i][j]
-
- ok = ''
- get_v(m,'',[0,0])
- print(f"{ok = }")
- for v in ok:
- p.sendlineafter(b': ', v)
-
- p.recvuntil(b'down.\n')
- while True:
- maze()
- p.recvuntil(b'level...\n\n')
这个连上后跟第1个几乎一样,最后会出一堆英文表示的式子,写程序处理成算式,回答数字或者英文的都不对就卡住了。不知后事如何。
- from pwn import *
- from ast import literal_eval
- import re
- from num2words import num2words
-
- _known = {
- 'zero': 0, 'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5,
- 'six': 6, 'seven': 7, 'eight': 8, 'nine': 9, 'ten': 10, 'eleven': 11,
- 'twelve': 12, 'thirteen': 13, 'fourteen': 14, 'fifteen': 15, 'sixteen': 16,
- 'seventeen': 17, 'eighteen': 18, 'nineteen': 19, 'twenty': 20, 'thirty': 30,
- 'forty': 40, 'fifty': 50, 'sixty': 60, 'seventy': 70, 'eighty': 80, 'ninety': 90
- }
- def spoken_word_to_number(n):
- n = n.lower().strip()
- if n in _known:
- return _known[n]
- else:
- inputWordArr = re.split('[ -]', n)
- assert len(inputWordArr) > 1 #all single words are known
- #Check the pathological case where hundred is at the end or thousand is at end
- if inputWordArr[-1] == 'hundred':
- inputWordArr.append('zero')
- inputWordArr.append('zero')
- if inputWordArr[-1] == 'thousand':
- inputWordArr.append('zero')
- inputWordArr.append('zero')
- inputWordArr.append('zero')
- if inputWordArr[0] == 'hundred':
- inputWordArr.insert(0, 'one')
- if inputWordArr[0] == 'thousand':
- inputWordArr.insert(0, 'one')
- inputWordArr = [word for word in inputWordArr if word not in ['and', 'minus', 'negative']]
- currentPosition = 'unit'
- prevPosition = None
- output = 0
- for word in reversed(inputWordArr):
- if currentPosition == 'unit':
- number = _known[word]
- output += number
- if number > 9:
- currentPosition = 'hundred'
- else:
- currentPosition = 'ten'
- elif currentPosition == 'ten':
- if word != 'hundred':
- number = _known[word]
- if number < 10:
- output += number*10
- else:
- output += number
- #else: nothing special
- currentPosition = 'hundred'
- elif currentPosition == 'hundred':
- if word not in [ 'hundred', 'thousand']:
- number = _known[word]
- output += number*100
- currentPosition = 'thousand'
- elif word == 'thousand':
- currentPosition = 'thousand'
- else:
- currentPosition = 'hundred'
- elif currentPosition == 'thousand':
- assert word != 'hundred'
- if word != 'thousand':
- number = _known[word]
- output += number*1000
- else:
- assert "Can't be here" == None
- return(output)
-
- def aaa(a):
- arr = re.split('[ -]', a.replace(',',''))
- xx = {'plus':'+', 'minus':'*', 'negative':'-'}
- b = ''
- i = 0
- while i < len(arr)-1:
- if arr[i] in xx:
- b += xx[arr[i]]
- i+=1
-
- print(b)
-
- j = i
- while j< len(arr):
- if arr[j] in xx:
- break
- j+=1
- c = ' '.join(arr[i:j])
- print(c)
- b += str(spoken_word_to_number(c))
- i = j
- print(b)
- return b
-
- p = remote('chals.tuctf.com', 30200)
- context.log_level = 'debug'
-
- while True:
- a = p.recvline()
- while b'Correct!' in a or b'exec' in a or a == b'\n':
- a = p.recvline()
- open('log.txt', 'ab').write(a)
- if b'plus' in a or b'minus' in a :
- b = eval(aaa(a.decode().strip()))
- b = num2words(int(b)).encode()
- else:
- b = eval(a)
- b = str(int(b)).encode()
- p.sendlineafter(b'Answer: ', b)
- #p.recvline()
-