1.AI安全1.1The Silent Heist题目内容 目标银行部署了一套基于 Isolation Forest (孤立森林) 的反欺诈系统。该系统不依赖传统的黑名单而是通过机器学习严密监控交易的 20 个统计学维度。系统学习了正常用户的行为模式包括资金流向、设备指纹的协方差关系等一旦发现提交的数据分布偏离了“正常模型”就会立即触发警报。 我们成功截取了一份包含 1000 条正常交易记录的流量日志 (public_ledger.csv)。请你利用统计学方法分析这份数据逆向推导其多维特征分布规律并伪造一批新的交易记录那基本上就能看出本题模拟了一个典型的对抗性机器学习场景。目标是骗过一个已经上线的异常检测系统目标系统是基于孤立森林的实时风控引擎输入数据是20 维浮点数特征金额目标孤立森林不同于传统的分类算法如 SVM 或神经网络它属于无监督学习核心逻辑就是算法随机选择特征并随机选择切分点构建二叉树且异常点往往具有“少”且“异”的特点在空间中它们远离高密度区域路径长度异常点和正常点也是不一样的异常点只需要很少次数的随机切分就能被孤立出来也就是处于树的浅层路径短正常点位于数据簇的中心需要密集的切分才能被隔绝也就是说处于树的深层路径长判定公式模型通过样本在多棵树中的平均路径长度计算异常评分。路径越长评分越低数据越正常既然孤立森林难以孤立处于数据中心的点那么我们的策略就是制造大量极其平庸的数据比如说我们通过对截获的 1000 条日志进行统计计算每一列的平均值计算每一列的标准差只要生成的数据点无限趋近于各维度的均值 它们就会落在孤立森林最难切分的深处逃过检测由题目给的附件已知 feat_0的均值 μ0≈353那么计算所需条数2,000,000/353≈5,6662,000,000/353≈5,666条也就是说我们只要生成 6,000 条数据。这不仅能稳过 2M 金额线还能通过大量的微小数据分摊风险避免单笔大额交易触发阈值告警但是如果 6000 条数据完全一样会被去重算法拦截所以应该在均值 μ的基础上注入一个尺度极小的高斯白噪声公式这里 ϵ扰动系数设为 0.01左右这保证了每行数据在二进制层面都是唯一的在统计学层面数据分布依然极度向中心靠拢所以exp.pyimport socket import numpy as np import pandas as pd import io ​ # 1. 题目提供的部分日志数据基于你提供的片段进行统计建模 # 在实际环境中如果能下载完整csv分析结果会更精确。 def generate_payload(): # 统计特征 (均值 mu 和 标准差 sigma) # 基于样本计算的近似值 means np.array([ 353.45, 27.56, 93.67, 82.78, 45.12, 4.23, 13.45, 51.67, 11.23, 30.56, 39.12, 84.78, 10.34, 82.12, 73.67, 18.89, 30.56, 41.89, 13.12, 27.56 ]) stds np.array([ 25.0, 2.5, 3.0, 3.0, 2.0, 2.5, 2.5, 2.0, 2.5, 3.0, 3.0, 3.0, 2.5, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 2.5 ]) ​ # 设定生成 6000 条记录以确保总金额 2,000,000 num_samples 6000 print(f[*] 正在生成 {num_samples} 条伪造交易记录...) # 生成数据均值 极小的随机扰动 (0.01倍标准差) # 这样可以确保数据唯一躲避去重检测且极度接近中心躲避异常检测 generated_data [] for _ in range(num_samples): noise np.random.normal(0, 0.01, size20) * stds row means noise generated_data.append(row) # 转换为 CSV 格式 df pd.DataFrame(generated_data) df.columns [ffeat_{i} for i in range(20)] csv_buffer io.StringIO() df.to_csv(csv_buffer, indexFalse, float_format%.6f) payload csv_buffer.getvalue() return payload ​ def pwn_bank(): host 182.92.11.65 port 30799 payload generate_payload() try: # 2. 建立连接 print(f[*] 正在连接到 {host}:{port}...) s socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((host, port)) # 接收服务器欢迎语 # s.recv(1024) # 3. 发送数据 print([*] 正在传输数据流并注入金额...) s.sendall(payload.encode()) # 4. 发送结束标志 s.sendall(bEOF\n) # 5. 接收返回结果Flag通常在这里 print([*] 等待银行系统响应...) response b while True: data s.recv(4096) if not data: break response data # 如果收到 flag 格式提前停止打印假设格式为 flag{...} if bflag in response.lower(): break print(\n[] 服务器响应结果:) print(response.decode(errorsignore)) s.close() except Exception as e: print(f[-] 错误: {e}) ​ if __name__ __main__: pwn_bank()2.Cry2.1 ECDSA题目给了三个东西task.py生成密钥和签名的程序signatures.txt使用弱私钥生成的 60 个签名样本public.pem与私钥对应的公钥看它task.py的代码就知道这个私钥生成有问题from ecdsa import SigningKey, NIST521p from hashlib import sha512 from Crypto.Util.number import long_to_bytes ​ # 计算固定字符串的SHA512哈希 digest_int int.from_bytes(sha512(bWelcome to this challenge!).digest(), big) ​ # 获取曲线阶数 curve_order NIST521p.order ​ # 对曲线阶数取模得到私钥 priv_int digest_int % curve_order ​ # 转换为字节格式 priv_bytes long_to_bytes(priv_int, 66) ​ # 创建私钥对象 sk SigningKey.from_string(priv_bytes, curveNIST521p)首先它私钥种子固定不变私钥的生成依赖于固定字符串Welcome to this challenge!这个字符串在代码中硬编码任何人都可以访问源代码并计算出完全相同的私钥接着算法也有问题仅使用 SHA512 哈希运算就生成私钥哈希函数是确定性的给定相同输入必然产生相同输出【----帮助网安学习以下所有学习资料免费领加vxYJ-2021-1备注 “博客园” 获取】① 网安学习成长路径思维导图② 60网安经典常用工具包③ 100SRC漏洞分析报告④ 150网安攻防实战技术电子书⑤ 最权威CISSP 认证考试指南题库⑥ 超1800页CTF实战技巧手册⑦ 最新网安大厂面试题合集含答案⑧ APP客户端安全检测指南安卓IOS所以种子字符串是公开的计算过程是确定性的无需任何额外信息即可恢复私钥from ecdsa import SigningKey, NIST521p, VerifyingKey from hashlib import sha512 from Crypto.Util.number import long_to_bytes, bytes_to_long import binascii ​ def recover_private_key(): 通过计算固定字符串的SHA512哈希值恢复私钥 message bWelcome to this challenge! digest sha512(message).digest() digest_int int.from_bytes(digest, big) curve_order NIST521p.order priv_int digest_int % curve_order priv_bytes long_to_bytes(priv_int, 66) sk SigningKey.from_string(priv_bytes, curveNIST521p) return sk ​ def generate_nonce(index): 生成指定索引的nonce值 seed sha512(bbias bytes([index])).digest() k int.from_bytes(seed, big) return k ​ def load_public_key(pem_filepublic.pem): 从PEM文件加载公钥 with open(pem_file, rb) as f: pem_data f.read() vk VerifyingKey.from_pem(pem_data) return vk ​ def extract_rs_from_der(sig_bytes): 从DER编码的签名中提取r和s值 if len(sig_bytes) 8: return None, None pos 0 if sig_bytes[pos] ! 0x30: return None, None pos 1 length_bytes sig_bytes[pos] pos 1 if sig_bytes[pos] ! 0x02: return None, None pos 1 r_length sig_bytes[pos] pos 1 r_value sig_bytes[pos:pos r_length] pos r_length if sig_bytes[pos] ! 0x02: return None, None pos 1 s_length sig_bytes[pos] pos 1 s_value sig_bytes[pos:pos s_length] r_int bytes_to_long(r_value) s_int bytes_to_long(s_value) return r_int, s_int ​ def verify_signature_ecdsa(vk, message, signature): 使用公钥验证签名 try: return vk.verify(signature, message) except: return manual_verify(vk, message, signature) ​ def manual_verify(vk, message, signature): 手动验证ECDSA签名 try: r, s extract_rs_from_der(signature) if r is None or s is None: return False msg_hash sha512(message).digest() msg_hash_int bytes_to_long(msg_hash) point vk.pubkey.point curve_order NIST521p.order # 计算 w s^(-1) mod n def modinv(a, m): if a 0: a a % m for i in range(1, m): if (a * i) % m 1: return i return 1 w modinv(s, curve_order) u1 (msg_hash_int * w) % curve_order u2 (r * w) % curve_order G NIST521p.generator point1 G * u1 point2 point * u2 result_point point1 point2 return (result_point.x() % curve_order) r except: return False ​ def sign_message_with_nonce(sk, message, nonce_index): 使用指定索引的nonce签名消息 k generate_nonce(nonce_index) signature sk.sign(message, kk) return signature ​ def main(): print( * 70) print(ECDSA 私钥恢复和签名工具) print( * 70) # 1. 恢复私钥 print(\n[1] 恢复私钥...) sk recover_private_key() print(f[✓] 私钥已恢复) print(f 私钥值: {sk.privkey.secret_multiplier}) print(f 私钥字节: {binascii.hexlify(sk.to_string()).decode()}) # 2. 加载公钥 print(\n[2] 加载公钥...) vk load_public_key() print([✓] 公钥已加载) # 3. 验证私钥正确性 print(\n[3] 验证私钥...) # 使用一个已有的签名验证 with open(signatures.txt, r) as f: first_line f.readline().strip() msg_hex, sig_hex first_line.split(:) test_msg bytes.fromhex(msg_hex) test_sig bytes.fromhex(sig_hex) if verify_signature_ecdsa(vk, test_msg, test_sig): print([✓] 私钥验证成功恢复的私钥与公钥匹配) else: print([✗] 私钥验证失败) return # 4. 尝试签名获取flag print(\n[4] 尝试生成签名...) # 尝试使用不同的nonce索引 flag_messages [ bflag, bgetflag, bsubmit flag, bgive me the flag, bCTF{, ] for msg in flag_messages: print(f\n 尝试签名消息: {msg}) # 尝试使用不同的nonce索引 (0-59) for i in range(60): try: sig sign_message_with_nonce(sk, msg, i) # 验证签名 if verify_signature_ecdsa(vk, msg, sig): print(f[✓] 成功!) print(f Nonce索引: {i}) print(f 签名: {binascii.hexlify(sig).decode()}) # 保存签名到文件 with open(flag_signature.txt, w) as f: f.write(fMessage: {msg.decode()}\n) f.write(fNonce Index: {i}\n) f.write(fSignature: {binascii.hexlify(sig).decode()}\n) print(f\n[] 签名已保存到 flag_signature.txt) # 5. 展示如何使用 print(\n * 70) print(解题步骤:) print( * 70) print(f 1. 私钥已成功恢复 私钥值: {sk.privkey.secret_multiplier} ​ 2. 使用恢复的私钥可以 - 验证任何使用该密钥签名的消息 - 为新消息生成有效签名 - 在CTF服务器上提交签名获取flag ​ 3. 生成的签名: 消息: {msg.decode()} 签名: {binascii.hexlify(sig).decode()} ​ 4. 将此签名提交给题目服务器即可获取flag ) return except Exception as e: continue print(f [-] 使用所有nonce索引签名失败) print(\n[!] 尝试其他方法...) # 如果上面的方法失败输出更多信息 print(\n[5] 输出私钥信息供手动使用...) print(f\n私钥值 (十进制):) print(sk.privkey.secret_multiplier) print(f\n私钥值 (十六进制):) print(binascii.hexlify(sk.to_string()).decode()) ​ if __name__ __main__: main()2.2 Ezflag先ida进行一个逆向找到main函数只有当输入的密码完全等于V3ryStr0ngpssw0rd时程序才会进入 else 分支生成 Flagstd::operatorstd::char_traitschar(_bss_start, flag{); v11 1LL; // 初始状态设为 1程序先打印 flag{v11 被初始化为 1for ( i 0; i 31; i ) { v9 f(v11); // 调用关键函数 f基于当前状态 v11 计算出一个字符 std::operator...((unsigned int)v9); // 打印该字符 // 格式化控制插入连字符 if ( i 7 || i 12 || i 17 || i 22 ) { std::operator...(-); } ​ // 状态更新公式 (核心数学逻辑) v11 * 8LL; v11 i 64; ​ // 延时处理 v8 1; std::this_thread::sleep_for(...); // 每秒打印一个字符增加仪式感 }程序运行一个 for 循环从 i 0 到 31总共生成32 个字符而我们也可以推导一下v11的状态初始值v11_0 1第一次迭代后v11_1 1 * 8 (0 64) 72第二次迭代后v11_2 72 * 8 (1 64) 649第三次迭代后v11_3 649 * 8 (2 64) 5256通过数学归纳法可以得出v11的通项公式v11_k 8^k * 1 Σ(i0到k-1) (i 64) * 8^(k-1-i)归纳化简之后就是v11_k 8^k Σ(j0到k-1) (64 j) * 8^(k-1-j)其中j k-1-i这个公式展示了v11的指数级增长特性。随着k的增大v11的值会变得极其庞大k 8时v11_8 ≈ 2.68 × 10^8k 16时v11_16 ≈ 7.2 × 10^16k 32时v11_32 ≈ 2.81 × 10^29这种指数级增长意味着v11的范围从1变化到约2^97f函数__int64 f(unsigned __int64 n) { v5 0; v4 1; for (i 0; i n; i) { v2 v4; v4 (v5 v4) 0xF; // mod 16 v5 v2; } return K[v5]; }这明显就是斐波那契数列取模运算函数f的输入是v11 mod 16的值记为n函数f计算斐波那契数列的第n项F(n)然后对16取模最后查表返回K[F(n) mod 16]通过计算前8个斐波那契数列值及其模16结果F(0) 0 → 0 mod 16 0F(1) 1 → 1 mod 16 1F(2) 1 → 1 mod 16 1F(3) 2 → 2 mod 16 2F(4) 3 → 3 mod 16 3F(5) 5 → 5 mod 16 5F(6) 8 → 8 mod 16 8F(7) 13 → 13 mod 16 13F(8) 21 → 21 mod 16 5对于n9及更大的值斐波那契数列的模16结果呈现周期性周期为24 这是因为斐波那契数列模m的周期在m16时为24将v11 mod 16的周期规律与f函数的映射结合得到最终的字符序列根据14周期规律v11 mod 16的序列为[8, 1, 2, 3, 4, 9, 6, 7, 8, 1, 2, 3, 4, 9, 6, 7, 8, 1, 2, 3, 4, 9, 6, 7, 8, 1, 2, 3, 4, 9, 6, 7]将每个值输入f函数f(8) → K[5]f(1) → K[1]f(2) → K[1]f(3) → K[2]f(4) → K[3]f(9) → K[2]f(6) → K[8]f(7) → K[13]以此类推应用完整的14周期规律全局字符表 K 012ab9c3478d56efdef get_period(): v5 0 v4 1 seq [0] # Pisano period for 16 is 24. for _ in range(100): v2 v4 v4 (v5 v4) 0xF v5 v2 seq.append(v5) return 24, seq ​ def solve(): period, sequence get_period() K 012ab9c3478d56ef v11 1 flag print(flag{, end) for i in range(32): # f(v11) returns K[sequence[v11 % period]] idx sequence[v11 % period] c K[idx] print(c, end) flag c if i in [7, 12, 17, 22]: print(-, end) flag - v11 v11 * 8 i 64 v11 0xFFFFFFFFFFFFFFFF # Mask to 64 bits to simulate overflow print(}) ​ if __name__ __main__: solve()2.3 RSA_NestingDoll本题的get_smooth_prime 函数是漏洞存在的地方在 get_smooth_prime(1024, 20, p1) 中生成素数 p的逻辑本质上是整理一下就会发现p−1p1×K其中 K是由一堆 20 位的小素数构成的普通 RSAp−1 是随机的包含大的随机质因子且这些因子完全不知道本题 RSAp−1虽然也包含一个巨大的质因子 p1但这个p1恰好是已知量n1的一个因子所以n1就是打开 p−1的钥匙因为 n1p1⋅q1⋅r1⋅s1所以n1必然是p1的倍数。既然 p−1包含 p1那么 p−1的绝大部分因子都已经躺在 n1里面了import math from Crypto.Util.number import * from tqdm import tqdm ​ # --- 题目数据 --- n1 16141229822582999941795528434053604024130834376743380417543848154510567941426284503974843508505293632858944676904777719167211264225017879544879766461905421764911145115313698529148118556481569662427943129906246669392285465962009760415398277861235401144473728421924300182818519451863668543279964773812681294700932779276119980976088388578080667457572761731749115242478798767995746571783659904107470270861418250270529189065684265364754871076595202944616294213418165898411332609375456093386942710433731450591144173543437880652898520275020008888364820928962186107055633582315448537508963579549702813766809204496344017389879 n 484831124108275939341366810506193994531550055695853253298115538101629337644848848341479419438032232339003236906071864005366050185096955712484824249228197577223248353640366078747360090084446361275032026781246854700074896711976487694783856878403247312312487197243272330518861346981470353394149785086635163868023866817552387681890963052199983782800993485245670437818180617561464964987316161927118605512017355921555464359512280368738197370963036482455976503266489446554327046948670215814974461717020804892983665655107351050779151227099827044949961517305345415735355361979690945791766389892262659146088374064423340675969505766640604405056526597458482705651442368165084488267428304515239897907407899916127394598273176618290300112450670040922567688605072749116061905175316975711341960774150260004939250949738836358264952590189482518415728072191137713935386026127881564386427069721229262845412925923228235712893710368875996153516581760868562584742909664286792076869106489090142359608727406720798822550560161176676501888507397207863998129261472631954482761264406483807145805232317147769145985955267206369675711834485845321043623959730914679051434102698588945009836642922614296598336035078421463808774940679339890140690147375340294139027290793 c 657984921229942454933933403447729006306657607710326864301226455143743298424203173231485254106370042482797921667656700155904329772383820736458855765136793243316671212869426397954684784861721375098512569633961083815312918123032774700110069081262242921985864796328969423527821139281310369981972743866271594590344539579191695406770264993187783060116166611986577690957583312376226071223036478908520539670631359415937784254986105845218988574365136837803183282535335170744088822352494742132919629693849729766426397683869482842748401000853783134170305075124230522253670782186531697976487673160305610021244587265868919495629 e 65537 ​