
RuoYi-Vue의 generator 모듈에서 발생하는 인증된 SQL 인젝션인 CVE-2024-57521에 대한 정적 코드 감사로, 소스-투-싱크 분석과 %0b 필터 우회 PoC를 포함합니다.
그림 1: CVE-2024-57521 SQL 인젝션 취약점 데이터 흐름 감사 다이어그램
본 저장소는 보안 연구 및 교육 목적으로만 사용됩니다. 본 문서의 기술을 이용하여 비인가된 공격 행위를 하지 마십시오. 모든 테스트는 로컬 정적 코드 감사 환경에서 수행되었습니다.
ruoyi-generator 모듈)ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java핵심 코드:
@PostMapping("/createTable")
public AjaxResult createTableSave(@RequestParam("sql") String sql, @RequestParam("tplWebType") String tplWebType)
{
try
{
SqlUtil.filterKeyword(sql); // 在进入业务前调用过滤器
분석: 백그라운드 관리자는 HTTP POST 요청의 sql 파라미터를 통해 임의의 데이터베이스 테이블 생성 문을 전달할 수 있다. 진입점은 사용자 입력에 대해 충분한 제한을 하지 않고 직접 후속 필터로 넘긴다.
스크린샷 증거:

· 파일 위치: ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java
핵심 결함 코드:
// 第16行:黑名单定义,注意关键词带有【尾随空格】
public static String SQL_REGEX = "\u0008|%0A|and |extractvalue|updatexml|sleep|information_schema|exec...";
// 第61-66行:过滤逻辑
String normalizedValue = value.replaceAll("\\p{Z}|\\s", ""); // 先清空了输入里的所有空格
String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|");
for (String sqlKeyword : sqlKeywords)
{
if (StringUtils.indexOfIgnoreCase(normalizedValue, sqlKeyword) > -1)
{
throw new UtilException("请求参数包含敏感关键词" + sqlKeyword + ",可能存在安全风险");
}
}
결함 분석: 필터는 먼저 replaceAll("\p{Z}|\s", "")를 실행하여 입력에서 모든 공백 문자를 제거한다. 그러나 블랙리스트 SQL_REGEX에 있는 키워드(예: "and ", "select ")는 뒤에 공백이 붙어 있다. 이로 인해 매칭이 반드시 실패하게 되며, 공격자가 키워드 뒤에 %0b(수직 탭)를 사용하여 공백을 대체하기만 하면 블랙리스트 검사를 완벽하게 우회할 수 있다.
스크린샷 증거:
· 파일 위치: ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml
핵심 코드:
<update id="createTable">
${sql}
</update>
분석: MyBatis에서 ${}는 안전한 사전 컴파일 #{}를 사용하지 않고 문자열을 직접 연결합니다. 이로 인해 필터를 우회한 악성 SQL이 데이터베이스로 전달되어 실행됩니다. 이는 전형적인 '블랙리스트 필터링 + 안전하지 않은 문자열 연결' 조합 취약점입니다.
스크린샷 증거:
· 방법: 공격자는 %0b(MySQL의 수직 탭 문자로, \s 매칭 범위에 속함)를 사용하여 SQL 문의 공백을 대체합니다.
· 탐지 원리: IF(<조건>, 1, 1/0)을 블라인드 인젝션의 탐지기로 사용합니다. · 조건이 거짓일 때: 0으로 나누기 오류가 발생하여 서버가 HTTP 500을 반환합니다. · 조건이 참일 때: 정상적으로 오류가 발생하지 않습니다. · 추출 방식: 이분법을 사용하여 데이터베이스 데이터를 비트 단위로 추측할 수 있습니다.
이 취약점은 전형적인 '불완전한 수정'으로 인한 우회입니다. 개발자는 이전의 동일한 유형의 SQL 인젝션을 수정할 때 블랙리스트 메커니즘을 도입했지만, 블랙리스트가 공백에 의존한다는 점을 간과했고, 공백을 제거하는 선행 로직이 블랙리스트의 매칭 조건을 파괴하여 결국 새로운 우회(CVE-2024-57521)를 초래했습니다.
· 블랙리스트 메커니즘 폐지: 블랙리스트에 의존하지 말고, 화이트리스트 메커니즘만이 안전의 근간입니다. · 사전 컴파일 사용: MyBatis의 ${sql}을 #{} 사전 컴파일 방식으로 변경하십시오. SQL을 동적으로 전달해야 하는 경우(예: 테이블 생성, Order By)에는 엄격한 추상 구문 트리(AST) 파싱 또는 엄격한 매개변수 검증을 사용해야 합니다. · 필터 개선: 블랙리스트를 반드시 사용해야 하는 경우, 블랙리스트 키워드의 끝 공백을 제거하고 비교 전에 통일된 정규화(예: 소문자로 통일, %0b 등을 공백으로 대체)를 수행해야 합니다.
· NVD - CVE-2024-57521 · RuoYi-Vue Gitee 저장소
poc/poc_boolean.py (참고: 이후 파일명을 실제 로직과 일치하도록 poc_error_based.py로 변경할 것을 권장합니다)extractvalue() 함수를 이용해 XPath 오류를 유발하고, 정규식으로 XPATH syntax error: '~...~'를 매칭하여 데이터를 추출합니다. Payload에서는 /**/를 사용하여 공백을 대체하여 블랙리스트 필터링을 우회합니다.
CREATE//table//{随机表名}//as//SELECT/**/extractvalue(1,concat(0x7e,({查询语句}),0x7e))
%0b를 이용한 WAF 우회 및 extractvalue 오류 기반 주입의 실행 가능성을 성공적으로 검증했으며, 스크립트가 MySQL 버전(5.7.26), 현재 데이터베이스 이름(ry), 데이터베이스 연결 사용자(root@localhost)를 안정적으로 추출했습니다.