安全矩阵

 找回密码
 立即注册
搜索
查看: 1065|回复: 0

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

[复制链接]

181

主题

182

帖子

721

积分

高级会员

Rank: 4

积分
721
发表于 2022-9-8 10:15:23 | 显示全部楼层 |阅读模式


CVE-2022-31197 PostgreSQL JDBC SQL注入分析
RoboTerh 衡阳信安
2022-09-06 00:00 发表于山东
转载自:CVE-2022-31197 PostgreSQL JDBC SQL注入分析


写在前面
偶然看到了CVE-2022-31197,是由于ResultSet.refreshRow()引发的SQL注入,感觉有点小有意思,正好之前学习了JDBC attack,决定分析一下漏洞造成的原因
漏洞分析
在官方的描述中,被修复版本有42.2.26 42.4.1
这里我们选用42.2.23版本的postgresql数据库依赖
  1. <dependency>
  2.     <groupId>org.postgresql</groupId>
  3.     <artifactId>postgresql</artifactId>
  4.     <version>42.2.23</version>
  5. </dependency>
复制代码
在连接中,他给出了一个payload
  1. CREATE TABLE refresh_row_example (
  2.   id     int PRIMARY KEY,
  3.   "1 FROM refresh_row_example; SELECT pg_sleep(10); SELECT * " int
  4. );
复制代码
这个cve的漏洞点主要是在PgResultSet#refreshRow方法中,在该方法中打下断点,跟进代码
在这个方法中我观察到有一处执行sql语句的地方,或许那里就是漏洞触发点吧?

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

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

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

只能从后者做文章了,那么this.currentRow是什么捏?
怎么才能使得其不为-1捏?
通过全局搜索对currentRow属性的赋值,我发现在next方法中,存在有其赋值操作

所以我们需要使得这个表有数据并在调用ResultSet.refreshRow之前调用ResultSet.next才能满足条件
回到else if语句,继续分析,isAfterLast的调用

要想返回false,因为之前需要表中存在数据,所以if语句就不能返回false, 我们就只能使得currentRow属性小于rows_size才能满足条件
接下来就是Nullness.castNonNull(this.rows, "rows")使得其返回不为空,跟进

很简单,前面就已经满足了,只需要满足有数据就OK
接下来就是sql语句的拼接逻辑,简单看看,了解payload的构造原理
在最开始就创建了select开头的StringBuilder类,之后通过一个for循环获取表中的列名,并加以拼接

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

之后又是获取了primary key修饰的列名,并且在后面添加了= ?这类预编译手法,如果有多个primary key,将添加and逻辑词处理
接着就在最后调用了查询语句,执行了恶意SQL

漏洞利用Payload构造
从上面的分析中可以知道,在获取的列名前面加上了select column1, 所以我们首先需要闭合前面的,所以payload中的第二列名是1 from dbName;开头,值得注意的是
这里使用了分号进行sql语句之间的分割,那么列名中间部分就是我们需要执行的sql语句了,同样的根据上面的分析,我们知道,在列名的后面同样加上了from dbName where id = ?,
所以,在payload的最后我们需要闭合后面部分,使用select *就能成功闭合
利用
  •         docker运行postgresql数据库
  •         远程连接,首先创建一个表
            
    1. CREATE TABLE refresh_row_example3 (
    2.   id     int PRIMARY KEY,
    3.   "1 FROM refresh_row_example3;CREATE TABLE test(id int);SELECT * " int
    4. );
    复制代码
    这里我直接创建一个表展示能够成功利用,当然还有更多的利用姿势
  •         随便添加一组数据

运行测试程序


可以发现成功创建test表



环境代码示例上传到了github
漏洞修复


在修复版本中,不在直接将列名写入sql语句中,而是经过了Utils.escapeIdentifier的处理
Ref
https://github.com/pgjdbc/pgjdbc/security/advisories/GHSA-r38f-c4h4-hqq2
来源:先知(https://xz.aliyun.com/t/11660#toc-0)
注:如有绘画请联系删除








回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-3-29 03:39 , Processed in 0.013569 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表