• [TUCTF 2022] 部分


    目录

    Crypto

    RSA

    A sheep jumps over fence

    More Effort

    Umix the flag

    Program

    Leisurely math

    Maze

    p3 未完成


    没作几个题,网站太慢了,经常题都不出。

    Crypto

    RSA

    忘了记名字了,是个远程题,e=5不变,n,c在变化,显然是用中国剩余定理。然后再开5次幂。

    1. n1=10482537034616502990056118030126164434407037176718331962667011326955491120566031634285535049167438082826079349272253648544730225816672178907764563795724843238117833575393198105750393276477056062212621581826908061516664802589223889385525044351279674490228268440747101433020011881495784429621597371307426622757779128699745573729906521433559644189341958800662044774541
    2. c1=6087004369946053227982494913706901186274614577662910050380033779616661997035829135770453917032222963288513864576850581583066480871865034839084616393770636880369071627374934883683905306826847313587047467574498166973462816444236751014698316815611495234751053545484591628748764097916135305447550851423345959821240953597530179672401858302119597171603198037366269233719
    3. n2 =12367732114126301913737674911174659623260421701922083115463688097892335835832137676235926929476836047205277037213556311855697316742401499464166580788816568220539558161216494644597740553321733102039206472053356162972506585408259141048898509380926861285805055391399828624294182942246152692738571838819392996502010209610177387578042322991636983388504268335500249420617
    4. c2 =6598110242539995863074355056158570164049216335364925288931323757253535398103184489531242032575274289060700366841161402204146875959261549401532459608455604827722243085170385981035222200389913788409648676752548513449147184508753978498499016611762538512670708489158929810784104583789226504345306015964098627253554658284373096694929056015453847074887650556440052878630
    5. n3 =10256038725288950855196758629933306580783576388418827903732634844615198789778181879287006217785874404464941165322121223311218355864125867810588164953430819701659125700907576823337578399226408327622582145531259253939397764804840588945160103734078760521203955556671490266695737131932977852304750132447539392473513180775946728590263319845517676125152164659427731699479
    6. c3 = 7307506932852480055779150743698192577518060811090089847831839584489356780048260286294057804235251817041195453111379116685659989141101142713850347634848460781996991307627778136048623024426933507486743478530416521616605247651996711033755127847375528743357717132830144403674863976913789724872493255786744573370517927939711839563307201365321241992779597973050791722751
    7. e=5
    8. #sage
    9. #v = crt([c1,c2,c3],[n1,n2,n3])
    10. v =73448690174896106135676773887969898376313644525180577635638534667360398313545968245865457044768650498073919986296816184849746808491061728181876720693332170726810820658795124493571143780153343023652595257458464865059042345641702358771008787607355295320693998300553350404027525319624789400937306774517103831179992855723955092191381869960795275997575970901077630183000778125
    11. from gmpy2 import iroot
    12. m = iroot(v,5)[0]
    13. #(mpz(149003617072514967705362966617328574884671140357033588603732115961358085245), True)
    14. bytes.fromhex(hex(m)[2:])
    15. b'TUCTF{0bl1g4t0ry_RSA_chall_l0l}'

    A sheep jumps over fence

    从名字上看是个栅栏密码,给了密文

    0x56455a7059574e7459584a685a576c756557646f59565637633364765a57647664474e305a48427965584e4464476c6c62584e6c6257463165574e3059574e7a5647687a6247567a5a6d527a636d46796233427366513d3d

    尾部的3D3D应该是个hex后的base,先转bytes再base64

    1. >>> bytes.fromhex('56455a7059574e7459584a685a576c756557646f59565637633364765a57647664474e305a48427965584e4464476c6c62584
    2. e6c6257463165574e3059574e7a5647687a6247567a5a6d527a636d46796233427366513d3d')
    3. b'VEZpYWNtYXJhZWlueWdoYVV7c3dvZWdvdGN0ZHByeXNDdGllbXNlbWF1eWN0YWNzVGhzbGVzZmRzcmFyb3BsfQ=='
    4. >>> from base64 import *
    5. >>> b64decode('VEZpYWNtYXJhZWlueWdoYVV7c3dvZWdvdGN0ZHByeXNDdGllbXNlbWF1eWN0YWNzVGhzbGVzZmRzcmFyb3BsfQ==')
    6. b'TFiacmaraeinyghaU{swoegotctdprysCtiemsemauyctacsThslesfdsraropl}'

    可以明显看出来头部TUCTF{所在的位置,再用栅栏

    TUCTF{thisisawelcomemessagefromdatasecurityandcryptographyclass}

    More Effort

    RSA题,只给了p没有q,q是通过算法实现,不过这个运算次数并不大,不需要用智力处理

    1. #!/usr/bin/env python3
    2. # -*- coding: utf-8 -*-
    3. """
    4. Created on Wed Nov 23 22:26:57 2022
    5. @author: weiping
    6. """
    7. import os
    8. import random
    9. from Crypto.Util.number import *
    10. import gmpy2
    11. flag = b'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    12. class RSA():
    13. def __init__(self):
    14. self.p = getPrime(512)
    15. self.s = 0
    16. for i in range(1, 18000000):
    17. self.s += pow(i, self.p-2, self.p) #sum i^-1
    18. self.s = self.s % self.p
    19. self.q = gmpy2.next_prime(self.s)
    20. self.n = self.p * self.q
    21. self.phi = (self.p - 1) * (self.q - 1)
    22. self.e = 65537
    23. self.d = pow(self.e, -1, self.phi)
    24. def encrypt(self, m: int):
    25. return pow(m, self.e, self.n)
    26. def main():
    27. rsa = RSA()
    28. print(f"p = {rsa.p}")
    29. print(f"e = {rsa.e}")
    30. c = rsa.encrypt(bytes_to_long(flag))
    31. print('c = ', c)
    32. '''
    33. p = 11545307730112922786664290405312669819594345207377186481347514368962838475959085036399074594822885814719354871659183685801279739518405830244888530641898849
    34. e = 65537
    35. c = 114894293598203268417380013863687165686775727976061560608696207173455730179934925684529986102237419507146768083815607566149240438056135058988227916482404733131796310418493418060300571541865427288945087911872630289527954636816219365941817260989104786329938318143577075200571833575709614521758701838099810751
    36. '''
    37. if __name__ == "__main__":
    38. main()

    照着原来的样子,重复一遍拿到q就OK了,只是时间需要一点点,毕竟不是智力方法,纯暴力。

    1. from Crypto.Util.number import *
    2. from gmpy2 import next_prime,invert
    3. p = 11545307730112922786664290405312669819594345207377186481347514368962838475959085036399074594822885814719354871659183685801279739518405830244888530641898849
    4. e = 65537
    5. c = 114894293598203268417380013863687165686775727976061560608696207173455730179934925684529986102237419507146768083815607566149240438056135058988227916482404733131796310418493418060300571541865427288945087911872630289527954636816219365941817260989104786329938318143577075200571833575709614521758701838099810751
    6. s = 0
    7. for i in range(1, 18000000):
    8. s += pow(i, -1, p) #sum i^-1
    9. s = s % p
    10. q = next_prime(s)
    11. phi = (p-1)*(q-1)
    12. d = invert(e, phi)
    13. m = pow(c,d,p*q)
    14. print(long_to_bytes(m))
    15. #TUCTF{syqow82pam_%shsjQF; ^7dagsWCpsp_#aes}

    不过后来一想,这个题并不需要求q,因为m很小可以直接用p求

    1. d = invert(e,p-1)
    2. long_to_bytes(pow(c,d,p))
    3. #TUCTF{syqow82pam_%shsjQF; ^7dagsWCpsp_#aes}

    Umix the flag

    前边是类似凯撒密码的偏移转码,后边是替换

    1. import string
    2. upperFlag = string.ascii_uppercase[:26]
    3. lowerFlag = string.ascii_lowercase[:26]
    4. MIN_LETTER = ord("a")
    5. MIN_CAPLETTER = ord("A")
    6. def mix(oneLetter,num):
    7. if(oneLetter.isupper()):
    8. word = ord(oneLetter)-MIN_CAPLETTER
    9. shift = ord(num)-MIN_CAPLETTER
    10. return upperFlag[(word + shift)%len(upperFlag)]
    11. if(oneLetter.islower()):
    12. word = ord(oneLetter)-MIN_LETTER
    13. shift = ord(num)-MIN_LETTER
    14. return lowerFlag[(word + shift)%len(upperFlag)]
    15. def puzzled(puzzle):
    16. toSolveOne = ""
    17. for letter in puzzle:
    18. if (letter.isupper()):
    19. binary ="{0:015b}".format(ord(letter))
    20. toSolveOne += upperFlag[int(binary[:5],2)]
    21. toSolveOne += upperFlag[int(binary[5:10],2)]
    22. toSolveOne += upperFlag[int(binary[10:],2)]
    23. elif(letter.islower()):
    24. six = "{0:02x}".format(ord(letter))
    25. toSolveOne += lowerFlag[int(six[:1],16)]
    26. toSolveOne += lowerFlag[int(six[1:],16)]
    27. elif(letter == "_"):
    28. toSolveOne += "CTF"
    29. return toSolveOne
    30. flag = "Figure it Out! :)"
    31. numShift = "??"
    32. mixed = ""
    33. assert all([x in lowerFlag for x in numShift])
    34. assert len(numShift) == 1
    35. encoding = puzzled(flag)
    36. print(encoding)
    37. for count, alpha in enumerate(encoding):
    38. mixed += mix(alpha, numShift)
    39. print(mixed)

    但是偏移这块用的都是num减,这导致大小写减后模26后偏移不同。

    密文比较特殊,看上去是盲文,提示是8点不是6点,但用的都是6点,是盲文的标记方法不同。

    ⠱⠁ ⠹⠣ ⠱⠹ ⠱⠁ ⠹⠣ ⠹⠳ ⠱⠁ ⠹⠣ ⠹⠪ ⠱⠁ ⠹⠣ ⠱⠩ ⠹⠣ ⠱⠩ ⠹⠱ ⠻⠁ ⠫⠩ ⠫⠡ ⠻⠻ ⠹⠣ ⠱⠩ ⠹⠱ ⠻⠁ ⠻⠪ ⠻⠁ ⠻⠱ ⠫⠡ ⠻⠻ ⠫⠡ ⠫⠩ 

    先来手搓,得到密文

    5a42545a42485a42495a42534253457a6361774253457a797a7561776163

    然后再进行偏移转码

    1. #a = bytes.fromhex('5a42545a42485a42495a42534253457a6361774253457a797a7561776163').decode()
    2. a = 'ZBTZBHZBIZBSBSEzcawBSEzyzuawac'
    3. for i in range(ord('a'), ord('z')+1):
    4. tv = ''
    5. for v in a:
    6. if v.isupper():
    7. tv += chr((ord(v) - i)%26 + ord('A'))
    8. else:
    9. tv += chr((ord(v) - i)%26 + ord('a'))
    10. print(tv)
    11. #ACUACIACJACTCTFgjhdCTFgfgbhdhj

    后边继续手搓

    1. '''
    2. ACU ACI ACJ ACT _ gj hd _ gfgbhdhj
    3. 0,2,20 0,2,8 0,2,9 0,2,19 _ 后边转后是16进制 69 73 65617379
    4. THIS_is_easy
    5. TUCTF{THIS_is_easy}
    6. '''

    Program

    Leisurely math

    这类题型原来没见过,不知道叫什么,作完应该就是叫编程。

    只有远端,连上去发现是个简单算式要求输入结果。编个循环eval处理。快到出flag的时候会出个exec(...) ,这时候eval会把程序办掉(这是说eval不安全,前几天看别人的都是用另一个安全的替代),知道是啥了就好办,检查到直接跳过就行了。

    1. from pwn import *
    2. from ast import literal_eval
    3. p = remote('chals.tuctf.com', 30202)
    4. context.log_level = 'debug'
    5. while True:
    6. a = p.recvline()
    7. if b'exec' in a:
    8. a = p.recvline()
    9. b = eval(a)
    10. p.sendlineafter(b'Answer: ', str(b).encode())
    11. p.recvline()
    12. '''
    13. [DEBUG] Received 0x1ff bytes:
    14. b'Correct!\n'
    15. 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'
    16. b'6993 - 5654 * 1086 + 6334 + 9502 - 954 + 126\n'
    17. b'Answer: '
    18. [DEBUG] Sent 0x9 bytes:
    19. b'-6118243\n'
    20. [DEBUG] Received 0x46 bytes:
    21. b'Correct!\n'
    22. b'5766 - 5967 - 4411 - 857 + 7792 + 5427 - 1369 + 7819\n'
    23. b'Answer: '
    24. [DEBUG] Sent 0x6 bytes:
    25. b'14200\n'
    26. [DEBUG] Received 0x52 bytes:
    27. b'Correct!\n'
    28. b'Here is your flag: TUCTF{7h4nk5_f0r_74k1n6_7h1n65_4_l177l3_5l0w_4268285}\n'
    29. '''

    Maze

    第二道是个迷宫,走路的

    1. '''
    2. XOOOO###############
    3. ####OOOOOOOOOOOOOOO#
    4. ##################O#
    5. ##################O#
    6. ########OOOOOOOOOOO#
    7. ########OOOOOOO#####
    8. ##############O#####
    9. ##############OOO###
    10. ################O###
    11. ################O###
    12. ############OOOOO###
    13. ############OOOOOOOO
    14. '''

    没说要走到哪,手工试了一次是走到右下角。并且只有下左右3个方向可走,应该是要写遍历程序处理。其实10关和1000关没啥区别,可以也太漫长了,复杂度在加大,感觉题没个完,去了个超市回来才出。 

    1. from pwn import *
    2. p = remote('chals.tuctf.com', 30204)
    3. context.log_level = 'debug'
    4. simple = '''
    5. XOOOO###############
    6. ####OOOOOOOOOOOOOOO#
    7. ##################O#
    8. ##################O#
    9. ########OOOOOOOOOOO#
    10. ########OOOOOOO#####
    11. ##############O#####
    12. ##############OOO###
    13. ################O###
    14. ################O###
    15. ############OOOOO###
    16. ############OOOOOOOO
    17. '''
    18. ok = ''
    19. width = 20
    20. height = 11
    21. def get_v(m,s, plc):
    22. global ok
    23. if ok != '':
    24. return False
    25. if plc == [height-1,width-1]:
    26. ok = s
    27. return True
    28. x,y = plc
    29. #print(1, s)
    30. if x1 and m[x+1][y] == 'O':
    31. ts = s+'V'
    32. tm = m.copy()
    33. tm[x][y] = '#'
    34. get_v(tm,ts,[x+1,y])
    35. #print(2, s)
    36. if y1 and m[x][y+1] == 'O':
    37. ts = s+'>'
    38. tm = m.copy()
    39. tm[x][y] = '#'
    40. get_v(tm,ts,[x,y+1])
    41. #print(3, s)
    42. if y>0 and m[x][y-1] == 'O':
    43. ts = s+'<'
    44. tm = m.copy()
    45. tm[x][y] = '#'
    46. get_v(tm,ts,[x,y-1])
    47. return
    48. def test():
    49. global ok
    50. a = simple.split('\n')[1:]
    51. m = [[0 for j in range(width)] for i in range(height)]
    52. for i in range(height):
    53. for j in range(width):
    54. m[i][j] = a[i][j]
    55. print(m)
    56. get_v(m,'',[0,0])
    57. print(ok)
    58. #test()
    59. def maze():
    60. global ok,width,height
    61. a = p.recvuntil(b'Move').decode().split('\n')[:-1]
    62. width = len(a[0])
    63. height = len(a)
    64. print(width,height, a)
    65. m = [[0 for i in range(width)] for j in range(height)]
    66. for i in range(height):
    67. for j in range(width):
    68. m[i][j] = a[i][j]
    69. ok = ''
    70. get_v(m,'',[0,0])
    71. print(f"{ok = }")
    72. for v in ok:
    73. p.sendlineafter(b': ', v)
    74. p.recvuntil(b'down.\n')
    75. while True:
    76. maze()
    77. p.recvuntil(b'level...\n\n')

    p3 未完成

    这个连上后跟第1个几乎一样,最后会出一堆英文表示的式子,写程序处理成算式,回答数字或者英文的都不对就卡住了。不知后事如何。

    1. from pwn import *
    2. from ast import literal_eval
    3. import re
    4. from num2words import num2words
    5. _known = {
    6. 'zero': 0, 'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5,
    7. 'six': 6, 'seven': 7, 'eight': 8, 'nine': 9, 'ten': 10, 'eleven': 11,
    8. 'twelve': 12, 'thirteen': 13, 'fourteen': 14, 'fifteen': 15, 'sixteen': 16,
    9. 'seventeen': 17, 'eighteen': 18, 'nineteen': 19, 'twenty': 20, 'thirty': 30,
    10. 'forty': 40, 'fifty': 50, 'sixty': 60, 'seventy': 70, 'eighty': 80, 'ninety': 90
    11. }
    12. def spoken_word_to_number(n):
    13. n = n.lower().strip()
    14. if n in _known:
    15. return _known[n]
    16. else:
    17. inputWordArr = re.split('[ -]', n)
    18. assert len(inputWordArr) > 1 #all single words are known
    19. #Check the pathological case where hundred is at the end or thousand is at end
    20. if inputWordArr[-1] == 'hundred':
    21. inputWordArr.append('zero')
    22. inputWordArr.append('zero')
    23. if inputWordArr[-1] == 'thousand':
    24. inputWordArr.append('zero')
    25. inputWordArr.append('zero')
    26. inputWordArr.append('zero')
    27. if inputWordArr[0] == 'hundred':
    28. inputWordArr.insert(0, 'one')
    29. if inputWordArr[0] == 'thousand':
    30. inputWordArr.insert(0, 'one')
    31. inputWordArr = [word for word in inputWordArr if word not in ['and', 'minus', 'negative']]
    32. currentPosition = 'unit'
    33. prevPosition = None
    34. output = 0
    35. for word in reversed(inputWordArr):
    36. if currentPosition == 'unit':
    37. number = _known[word]
    38. output += number
    39. if number > 9:
    40. currentPosition = 'hundred'
    41. else:
    42. currentPosition = 'ten'
    43. elif currentPosition == 'ten':
    44. if word != 'hundred':
    45. number = _known[word]
    46. if number < 10:
    47. output += number*10
    48. else:
    49. output += number
    50. #else: nothing special
    51. currentPosition = 'hundred'
    52. elif currentPosition == 'hundred':
    53. if word not in [ 'hundred', 'thousand']:
    54. number = _known[word]
    55. output += number*100
    56. currentPosition = 'thousand'
    57. elif word == 'thousand':
    58. currentPosition = 'thousand'
    59. else:
    60. currentPosition = 'hundred'
    61. elif currentPosition == 'thousand':
    62. assert word != 'hundred'
    63. if word != 'thousand':
    64. number = _known[word]
    65. output += number*1000
    66. else:
    67. assert "Can't be here" == None
    68. return(output)
    69. def aaa(a):
    70. arr = re.split('[ -]', a.replace(',',''))
    71. xx = {'plus':'+', 'minus':'*', 'negative':'-'}
    72. b = ''
    73. i = 0
    74. while i < len(arr)-1:
    75. if arr[i] in xx:
    76. b += xx[arr[i]]
    77. i+=1
    78. print(b)
    79. j = i
    80. while j< len(arr):
    81. if arr[j] in xx:
    82. break
    83. j+=1
    84. c = ' '.join(arr[i:j])
    85. print(c)
    86. b += str(spoken_word_to_number(c))
    87. i = j
    88. print(b)
    89. return b
    90. p = remote('chals.tuctf.com', 30200)
    91. context.log_level = 'debug'
    92. while True:
    93. a = p.recvline()
    94. while b'Correct!' in a or b'exec' in a or a == b'\n':
    95. a = p.recvline()
    96. open('log.txt', 'ab').write(a)
    97. if b'plus' in a or b'minus' in a :
    98. b = eval(aaa(a.decode().strip()))
    99. b = num2words(int(b)).encode()
    100. else:
    101. b = eval(a)
    102. b = str(int(b)).encode()
    103. p.sendlineafter(b'Answer: ', b)
    104. #p.recvline()

  • 相关阅读:
    Flask 接口
    leetcode——最长回文子串——百日算法成就第五天5%
    meshlab 倾斜瓦片顶层重建简化
    Python自动化测试框架pytest的详解安装与运行
    Qt插件之Qt Designer插件实现
    云数据安全:在数字时代保护您的宝贵资产
    【Proteus仿真】【STM32单片机】多功能智能台灯
    [python][nginx][https] Nginx 服务器 SSL 证书安装部署
    个人练习-Leetcode-1034. Coloring A Border
    【工具】压力测试、安全、进程、流量、磁盘、日志
  • 原文地址:https://blog.csdn.net/weixin_52640415/article/details/128187318