CVE-2022-31197 PostgreSQL JDBC SQL注入分析

admin 2023年2月16日22:08:37评论89 views字数 1968阅读6分33秒阅读模式

写在前面

偶然看到了CVE-2022-31197,是由于ResultSet.refreshRow()引发的SQL注入,感觉有点小有意思,正好之前学习了JDBC attack,决定分析一下漏洞造成的原因

漏洞分析

在官方的描述中,被修复版本有42.2.26 42.4.1

这里我们选用42.2.23版本的postgresql数据库依赖

<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.23</version>
</dependency>

在连接中,他给出了一个payload

CREATE TABLE refresh_row_example (
id int PRIMARY KEY,
"1 FROM refresh_row_example; SELECT pg_sleep(10); SELECT * " int
);

这个cve的漏洞点主要是在PgResultSet#refreshRow方法中,在该方法中打下断点,跟进代码

在这个方法中我观察到有一处执行sql语句的地方,或许那里就是漏洞触发点吧?

CVE-2022-31197 PostgreSQL JDBC SQL注入分析

言归正传,如果我们需要到达漏洞触发点位置第一个拦路虎就是else if语句中的判断

CVE-2022-31197 PostgreSQL JDBC SQL注入分析

拆分开来,第一个是需要使得this.isBeforeFirst()为false,跟进代码逻辑

CVE-2022-31197 PostgreSQL JDBC SQL注入分析

其中需要使得this.rowOffset + this.currentRow < 0但是前者为0

CVE-2022-31197 PostgreSQL JDBC SQL注入分析

只能从后者做文章了,那么this.currentRow是什么捏?

怎么才能使得其不为-1捏?

通过全局搜索对currentRow属性的赋值,我发现在next方法中,存在有其赋值操作

CVE-2022-31197 PostgreSQL JDBC SQL注入分析

所以我们需要使得这个表有数据并在调用ResultSet.refreshRow之前调用ResultSet.next才能满足条件

回到else if语句,继续分析,isAfterLast的调用

CVE-2022-31197 PostgreSQL JDBC SQL注入分析

要想返回false,因为之前需要表中存在数据,所以if语句就不能返回false, 我们就只能使得currentRow属性小于rows_size才能满足条件

接下来就是Nullness.castNonNull(this.rows, "rows")使得其返回不为空,跟进

CVE-2022-31197 PostgreSQL JDBC SQL注入分析

很简单,前面就已经满足了,只需要满足有数据就OK

接下来就是sql语句的拼接逻辑,简单看看,了解payload的构造原理

在最开始就创建了select开头的StringBuilder类,之后通过一个for循环获取表中的列名,并加以拼接

CVE-2022-31197 PostgreSQL JDBC SQL注入分析

接下来又在后面添加了from/表名/where等关键词

CVE-2022-31197 PostgreSQL JDBC SQL注入分析

之后又是获取了primary key修饰的列名,并且在后面添加了= ?这类预编译手法,如果有多个primary key,将添加and逻辑词处理

接着就在最后调用了查询语句,执行了恶意SQL

CVE-2022-31197 PostgreSQL JDBC SQL注入分析

漏洞利用

Payload构造

从上面的分析中可以知道,在获取的列名前面加上了select column1, 所以我们首先需要闭合前面的,所以payload中的第二列名是1 from dbName;开头,值得注意的是这里使用了分号进行sql语句之间的分割,那么列名中间部分就是我们需要执行的sql语句了,同样的根据上面的分析,我们知道,在列名的后面同样加上了from dbName where id = ?,所以,在payload的最后我们需要闭合后面部分,使用select *就能成功闭合

利用

  1. docker运行postgresql数据库

  2. 远程连接,首先创建一个表

    CREATE TABLE refresh_row_example3 (
    id int PRIMARY KEY,
    "1 FROM refresh_row_example3;CREATE TABLE test(id int);SELECT * " int
    );

    这里我直接创建一个表展示能够成功利用,当然还有更多的利用姿势

  3. 随便添加一组数据

CVE-2022-31197 PostgreSQL JDBC SQL注入分析

运行测试程序

CVE-2022-31197 PostgreSQL JDBC SQL注入分析

可以发现成功创建test表


CVE-2022-31197 PostgreSQL JDBC SQL注入分析

环境代码示例上传到了github

漏洞修复

根据代码对比
https://github.com/pgjdbc/pgjdbc/commit/739e599d52ad80f8dcd6efedc6157859b1a9d637

CVE-2022-31197 PostgreSQL JDBC SQL注入分析

在修复版本中,不在直接将列名写入sql语句中,而是经过了Utils.escapeIdentifier的处理

Ref

https://github.com/pgjdbc/pgjdbc/security/advisories/GHSA-r38f-c4h4-hqq2

来源先知(https://xz.aliyun.com/t/11660#toc-0)


注:如有绘画请联系删除





CVE-2022-31197 PostgreSQL JDBC SQL注入分析

欢迎大家一起加群讨论学习和交流

CVE-2022-31197 PostgreSQL JDBC SQL注入分析

快乐要懂得分享,

加倍的快乐。


原文始发于微信公众号(衡阳信安):CVE-2022-31197 PostgreSQL JDBC SQL注入分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年2月16日22:08:37
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CVE-2022-31197 PostgreSQL JDBC SQL注入分析https://cn-sec.com/archives/1279993.html

发表评论

匿名网友 填写信息