JDBC로 인한 반서열화 공격

3155 단어
배경.
지난주 블랙하트 유로프 2019 의제인'New Exploit Technique In Java Deserialization Attack'에서는 JDBC URL을 주입해 반서열화 공격을 하는 장면을 언급해 간단하게 분석했다.
분석하다.
자바 응용 프로그램이 MySQL Connector/J(공식 JDBC 드라이브, 본고는 8.0+ 버전 기반)를 사용하여 mysql에 연결할 때 잠재적인 반서열화 공격 위험을 초래할 수 있다. JDBC URL의 형식은 다음과 같다:protocol//[hosts]/[database]?properties, mysql 공식 문서를 볼 수 있습니다. 예: jdbc:mysql://localhost:3306/test?useSSL=true
그 중에서protocol,host,database는 모두 비교적 잘 이해한다. URL의properties는MySQLConnector/J가 mysql 서버를 연결하는 구체적인 방식을 설정할 수 있다.properties의 공식 문서 주소에 대해 본고와 관련된 연결 속성은 두 가지가 있는데 그것이 바로 autoDeserialize와queryInterceptors이다. 전자는MySQLConnector/J가 BLOB 유형을 반서열화하는지 여부를 설정하는 데이터이다.후자는 차단기입니다. 조회가 실행될 때com에서 터치합니다.mysql.cj.protocol.a.NativeProtocol#sendQueryPacket 방법의 원본 코드는 검색 문장을 실행하기 전후에 차단기의preProcess와postProcess 방법을 각각 호출하는 것을 알 수 있습니다.
다음에 반서열화된 터치점을 지정하고 mysql-connector-java 구성 요소에서 전역 검색 키워드'.readObject()'를com에 지정합니다.mysql.cj.jdbc.result.ResultSetImpl 클래스에서 getObject(int columnIndex) 메서드의 핵심 코드는 다음과 같습니다.
public Object getObject(int columnIndex) throws SQLException {
……
case BLOB:
  byte[] data = getBytes(columnIndex);
  if (this.connection.getPropertySet().getBooleanProperty(PropertyDefinitions.PNAME_autoDeserialize).getValue()) {
     Object obj = data;
     // Serialized object?
     try {
       ByteArrayInputStream bytesIn = new ByteArrayInputStream(data);
       ObjectInputStream objIn = new ObjectInputStream(bytesIn);
       obj = objIn.readObject();
     }
  }
}

변수 데이터는 mysql 반환 결과 집합입니다. JDBC URL에 속성 autoDeserialize가true로 설정되었을 때bit,binary,blob 형식의 데이터를 반서열화합니다. getobject (int column Index) 방법의 호출을 어떻게 터치합니까?의제에서 제시된 호출 체인은 다음과 같다.
> com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor#preProcess/postProcess
> com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor#populateMapWithSessionStatusValues
> com.mysql.cj.jdbc.util.ResultSetUtil#resultSetToMap
> com.mysql.cj.jdbc.result.ResultSetImpl#getObject


ServerStatusDiffInterceptor는 이 전제에서 언급한 차단기입니다. JDBC URL에 속성queryInterceptors를 ServerStatusDiffInterceptor로 설정할 때, 검색어를 실행하면 차단기의preProcess와postProcess 방법을 호출하고, 상기 호출체인을 통해 getObject (int column Index) 방법을 최종적으로 호출합니다.
실제로 GetObject 방법을 최종적으로 호출한 대상은 데이터베이스에서 되돌아오는 결과 집합이고 populateMapWithSessionStatusValues 방법으로 알 수 있다.
try {
    toPopulate.clear();

    stmt = this.connection.createStatement();
    rs = stmt.executeQuery("SHOW SESSION STATUS");
    ResultSetUtil.resultSetToMap(toPopulate, rs);
}

이 결과집은 SQL 문구'SHOW SESSION STATUS'를 실행한 후 데이터베이스에서 되돌아오는 값이고, SQL 문구'SHOW SESSION STATUS'는 현재 데이터베이스 연결의 상태 값을 되돌려주며, 실제로는 시스템표 INFOR MATION 을 읽는다SCHEMA.SESSION_VARIABLES의 값, PERFORMANCESCHEMA.SESSION_VARIABLES(Mysql 버전 차이로 인한)하지만 mysql에서 INFORMATIONSCHEMA 및 PERFORMANCESCHEMA는 수정이 허용되지 않기 때문에 되돌아오는 데이터를 조작할 방법을 강구해야 한다.
이용 조건
1. 본질적으로 자바의 원생적인 반서열화 이용이기 때문에 환경에서 사용할 수 있는Gadget이 필요하다.
2. 관련 시스템 테이블의 데이터를 위조할 수 있어야 한다.'SHOW SESSION STATUS'의 실행 결과를 우리가 정성스럽게 구성한 반서열화 데이터로 설정하거나 mysql 연결 프로토콜을 바탕으로 자체적으로 데이터를 되돌려주고 나중에 시간이 있을 때 이 블록을 쓴다.
3. 제어할 수 있는 JDBC URL;

좋은 웹페이지 즐겨찾기