WEB

CatBank

逻辑漏洞,允许余额为负值,那么多注册几个账号后相互转账,到一百万时获得flag

image-20250517100024369

palu{0a2c13c6a72e4429a5ef89057f01ee16}

CatNet

扫目录发现/admin路由,提示本地访问,添加X-Forwarded-For:127.0.0.1,响应包中看到需要带上X-Internal-Auth:cateye-internal-000去访问/flag,但是错误,爆破数字在123时获得flag

image-20250517085905031

palu{e60ed7efcfe648b09439e4334b319e6e}

ezblog(复现)

反编译dashboard.class获得如下源码,但是不知道怎么找realkey

package com.example.demo.Controller;

import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.annotation.Param;
import org.noear.solon.core.handle.ModelAndView;
@Controller
/* loaded from: dashboard.class */
public class dashboard {
public static final String realkey = "********";

@Mapping("/")
public Object index() {
ModelAndView vm = new ModelAndView("index.ftl");
return vm;
}

@Mapping("/dashboard")
public Object dashboard() {
ModelAndView vm = new ModelAndView("dashboard.ftl");
return vm;
}

@Mapping("/backdoor")
public String backdoor(@Param("key") String key) {
if (realkey.equals(key)) {
String flag = System.getenv("FLAG");
return "flag is " + flag;
}
return "you are god";
}
}

看了wp才知道存在任意文件读取,访问/assets/../../app/app.jar就可下载源码,从而获得key

Re

PositionalXOR

1. 异或逻辑:

每个字符的加密方式是:密文字符 = 原文字符 ^ (位置 + 1)(位置从 0 开始计数,但密钥从 1 开始递增)。

例如,第一个字符 q 的 ASCII 码为 113,位置为 0,密钥为 1,解密为 113 ^ 1 = 112,对应字符 p。

2. 逐字符解密:

对每个字符按位置依次异或,恢复原始字符。

例如:

V(位置 5)异或 6 得到 P。

h(位置 6)异或 7 得到 o。

{(位置 7)异或 8 得到 s。

encrypted = "qcoq~Vh{e~bccocH^@Lgt{gt|g"
decrypted = "".join([chr(ord(c) ^ (i+1)) for i, c in enumerate(encrypted)])
print(f"Flag: {decrypted}")

image-20250518230719713

palu{PosltionalXOR_sample}

PaluFlat

附件为.com文件,改为.zip解压后得到exe文件,

exe文件丢入ida找到加密逻辑

输入存入str[]数组中经过sub_40155函数加密后与v5数组比较

sub_40155加密逻辑:

加密流程按以下顺序进行:

动态密钥选择:根据字符索引奇偶性交替使用”flat”和”palu”两个密钥
异或混淆:用密钥字节对原始字节进行异或运算
位移混淆:循环右移4位打乱bit位置
数值变换:通过减85改变数值分布
取反混淆:最终通过按位取反实现非线性变换
各步骤说明:

密钥选择策略:奇数位用flat[0],偶数位用palu[0],通过模运算循环使用密钥字符
循环移位实现:(v8 >> 4) | (v8 << 4) 完成4位右循环
减法操作使用模运算处理溢出,保证结果在0-255范围内
最终取反操作:~v8 & 0xFF 确保结果为有效字节值
这个加密算法通过多阶段非线性变换,实现了对原始字符串的混淆和扩散效果。

def decrypt_byte(encrypted_byte, key_part, index, key1_len, key2_len):
# 逆向操作步骤:取反 → 加85 → 循环移位 → 异或
v8 = ~encrypted_byte & 0xFF # 逆向取反操作
v8 = (v8 + 85) % 256 # 逆向减85操作

# 循环右移4位的逆向操作(同样是循环右移4位,因为两次移位等于原值)
v8 = ((v8 << 4) | (v8 >> 4)) & 0xFF

# 选择密钥(与加密时相同的逻辑)
if index % 2 != 0:
key = key_part[0]
key_len = key1_len
else:
key = key_part[1]
key_len = key2_len

# 逆向异或操作
v8 ^= key[index % key_len]
return v8

def decrypt_string(encrypted_str):
key_part = [b"flat", b"palu"]
key1_len = len(key_part[0])
key2_len = len(key_part[1])

decrypted = bytearray()
for i in range(len(encrypted_str)):
plain_byte = decrypt_byte(encrypted_str[i], key_part, i, key1_len, key2_len)
decrypted.append(plain_byte)
return decrypted.decode('utf-8')

# 修正后的加密数据(包含原C代码中的0x8F)
encrypted_str = [
0x54, 0x84, 0x54, 0x44, 0xA4, 0xB2, 0x84, 0x54,
0x62, 0x32, 0x8F, 0x54, 0x62, 0xB2, 0x54, 0x03,
0x14, 0x80, 0x43
]

# 解密并打印结果
decrypted_flag = decrypt_string(encrypted_str)
print("Decrypted Flag:", decrypted_flag)

image-20250518230836196

palu{Fat_N0t_Flat!}

CRYPTO

循环锁链

1. 确定起点:已知flag以palu{开头,对应的ASCII值分别为0x70, 0x61, 0x6C, 0x75, 0x7B。

2. 异或链推导:发现密文循环结构中,若以索引36(最后一个字节0x0D)为起点,并假设明文通过异或链(每个字节与前一个明文异或)生成,则:

明文[0] = cipher[36] ^ IV,其中IV = 0x0D ^ 0x70 = 0x7D。

后续明文满足:明文[i] = cipher[i] ^ 明文[i-1]。

3. 逐字节解密:从索引36开始循环遍历密文,依次异或前一个明文字节,得到完整明文。

最终解密结果即为所求flag。

palu{iC7uDoJJMAWnIhkkCNiIoCZZVmiPrk9}

欧几里得

Paillier加密

from Crypto.Util.number import long_to_bytes

# 已知的密文
c = 1426774899479339414711783875769670405758108494041927642533743607154735397076811133205075799614352194241060726689487117802867974494099614371033282640015883625484033889861

# 遍历所有可能的两个字节值(0x0000 到 0xFFFF)
for s in range(0x10000):
# 构造两个字节
high = s >> 8 # 高字节
low = s & 0xff # 低字节

# 生成m2的字节串:两个字节重复35次,共70字节
m2_bytes = bytes([high, low]) * 35

# 将字节串转换为整数
m2 = int.from_bytes(m2_bytes, 'big')

# 如果m2大于密文c,则跳过
if m2 > c:
continue

# 计算m1的候选值
m1 = c - m2

# 将m1转换为字节
m1_bytes = long_to_bytes(m1)

# 检查是否以'palu{'开头,并且所有字符可打印
if m1_bytes.startswith(b'palu{') and m1_bytes.endswith(b'}') and all(32 <= b <= 126 for b in m1_bytes):
print("Found flag:", m1_bytes.decode())
print("Seed:", hex(s))
exit()

palu{48b635a7a2474ef743e333478b67a2f5}

RSA_Quartic_Quandary

脚本跑

from Crypto.Util.number import long_to_bytes, bytes_to_long
from math import isqrt

n = 125997816345753096048865891139073286898143461169514858050232837657906289840897974068391106608902082960171083817785532702158298589600947834699494234633846206712414663927142998976208173208829799860130354978308649020815886262453865196867390105038666506017720712272359417586671917060323891124382072599746305448903
e = 65537
c = 16076213508704830809521504161524867240789661063230251272973700316524961511842110066547743812160813341691286895800830395413052502516451815705610447484880112548934311914559776633140762863945819054432492392315491109745915225117227073045171062365772401296382778452901831550773993089344837645958797206220200272941
s = 35935569267272146368441512592153486419244649035623643902985220815940198358146024590300394059909370115858091217597774010493938674472746828352595432824315405933241792789402041405932624651226442192749572918686958461029988244396875361295785103356745756304497466567342796329331150560777052588294638069488836419744297241409127729615544668547101580333420563318486256358906310909703237944327684178950282413703357020770127158209107658407007489563388980582632159120621869165333921661377997970334407786581024278698231418756106787058054355713472306409772260619117725561889350862414726861327985706773512963177174611689685575805282

# Step 1: Calculate u = sqrt(s + 2n^2)
n_squared = n * n
s_plus_2n2 = s + 2 * n_squared
u = isqrt(s_plus_2n2)
assert u * u == s_plus_2n2 # Verify perfect square

# Step 2: Calculate t = p + q
t_squared = u + 2 * n
t = isqrt(t_squared)
assert t * t == t_squared # Verify perfect square

# Step 3: Solve quadratic equation x^2 - tx + n = 0
delta = t * t - 4 * n
d = isqrt(delta)
assert d * d == delta # Verify perfect square

p = (t + d) // 2
q = (t - d) // 2
assert p * q == n # Verify p, q correct

# Step 4: Calculate phi(n) and d
phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)

# Step 5: Decrypt
m = pow(c, d, n)
flag = long_to_bytes(m)
print(f"Flag: {flag.decode()}")

# Verify
m_check = bytes_to_long(flag)
c_check = pow(m_check, e, n)
assert c_check == c

得到flag

image-20250519092056980

palu{This_is_a_fake_flag_change_it_for_real_use}

MISC

screenshot

丢工具就能看到flag

img

时间折叠(TimeFold Paradox)

img

先将数字后面的16进制提取出来

然后将每个16进制与0x8e进行异或

得到flag

palu{This_is_A_Sample_Flag_Change_Me!!}

应急响应

应急响应环境解压密码
网络拓扑环境
Skills@@@Skills@@@Skills
畸行的爱
Parloo&zgsfsys&onefox&solar**juyt

1-1

在网站目录下看到一个a.php

img

发现是一个马子

于是就去找网站日志里面谁传的a.php

img

找到这个ip,192.168.31.240

palu{192.168.31.240}

1-2

由于我们还看到了一个shell.php,于是找到shell.php的目录,看到一个日志文件,clean_jpg.log

img

我们打开之后看到里面有攻击ip,192.168.31.11

img

palu{192.168.31.11}

1-4

img

火眼直接搜

palu{pc3_zgsfqwerlkssaw}

1-5

将win10的a.bat打开

img

palu{nizhidaowoyouduoainima}

1-6

我们从网站得到的数据库密码之后

img

进入数据库

img

查到订单号

然后去网站输入订单号得到flag

img

palu{sqlaabbccsbwindows}

1-7

img

要找钓鱼文件hash

我在win10的回收站里面看到了简历.exe文件,还原之后被杀软杀了,然后丢云沙箱,看这个名字都是钓鱼文件

img

img

palu{2977CDAB8F3EE5EFDDAE61AD9F6CF203}

1-8

从日志中看出攻击者还传入了一个shell.php文件

img

hack这个就是第一个webshell的密码

palu{hack}

1-10

在webserver机器里面有攻击者穿的a.php,里面有

img

所以连接密码是00232

palu{00232}

1-11

有一个影子用户,火眼直接识别

img

palu{wmx_love}

2-1

image-20250517153152229

palu{2025_qiandao_flag}

2-2

通过火眼分析获得flag,自己找了老半天没找到flag

9d54303f0004b2467b88751b38c29468

palu{2025_waf}


看wp发现grep命令可以出来,直接grep -r "palu{" /*就行,这个命令是匹配文件内容,我之前的find / -name "palu{"是匹配文件目录及名字

2-3

image-20250517113158872

palu{Mysql_@2025}

2-4

image-20250517140810328

palu{192.168.20.107}

2-5

waf日志进行分析

image-20250518224911450

palu{2025-05-05-00:04:40}

2-6

在防火墙监控中找到关键文件

image-20250517172238100

palu{key.txt}

2-7

在key.txt中找到泄露邮箱

image-20250517172442241

palu{parloo@parloo.com}

2-8

通过waf的ip攻击分类,找到立足的服务器为ssh服务器即192.168.20.108

palu{192.168.20.108}

2-9

提权的用户就是为后门用户parloo,访问/etc/shadow得到密码加盐值parloo:$y$j9T$bLw/vAsrL.71gbi6NQPhI/$lpN9vHI0MYS/YL19ERrpaRpdrC37f5ya520xeG9BGiC:20212:0:99999:7:::

john爆破得到密码为parloo

palu{parloo/parloo}

2-10

ssh服务器上找到parloo账户下文件

image-20250517174736962

palu{hi_2025_parloo_is_hack}

2-14

通过waf中看到信息泄露在8081端口

image-20250517235811120

palu{8081}

2-15

访问server服务器http://192.168.20.103:8081/找到员工信息

image-20250517135558463

palu{310105198512123456}

2-17

在近源机中找到疑似恶意文件svhost.exe.exe,尝试提交后正确

image-20250518112853196

palu{0f80a82621b8c4c3303d198d13776b34}

2-18

palu03找到账户heike,提交MD5值

palu{d78b6f30225cdc811adfe8d4e7c9fd34}

2-19

内网通中群聊的聊天记录

image-20250517123117051

palu{nbq_nbq_parloo}

2-20

审日志发现flag

image-20250518195739889

palu{Server_Parloo_2025}

2-21

http://192.168.20.102:8081/admin/parloo看日志command.log找到首次攻击时间

image-20250518155033884

palu{2025-05-04:15:30:38}

2-22

审日志发现攻击者ip和端口

image-20250518195838290

palu{10.12.12.13:9999}

2-27

waf筛选反序列化的

image-20250517140224618

palu{9999}

2-30

用户名为parloohack

image-20250517152318578

密码加盐了,但是经过尝试和猜测发现密码为123456时可以登录

palu{parloohack/123456}

2-36

访问palu01,发现有99个用户

palu{99}

2-38

gitea的数据库中找到密码,即为攻击者留下的信息

palu{crP1ZIVfqrkfdhGy}

2-44

看第二个的聊天记录发现被钓鱼了,即为该用户

image-20250518225359051

palu{Parloo-子怡}

2-45

文件路径同上

image-20250518225448953

palu{C:\Users\Public\Nwt\cache\recv\Parloo-沉沉}

2-46

看ssh服务器上的网络外联情况

image-20250518174552979

palu{47.101.213.153:8084}