HSCTF의 seeded-randomizer 문제다. 자바 파일이 하나 주어져 있다.
import java.util.Random;
public class SeededRandomizer {
public static void display(char[] arr) {
for (char x: arr)
System.out.print(x);
System.out.println();
}
public static void sample() {
Random rand = new Random(79808677);
char[] test = new char[12];
int[] b = {9, 3, 4, -1, 62, 26, -37, 75, 83, 11, 30, 3};
for (int i = 0; i < test.length; i++) {
int n = rand.nextInt(128) + b[i];
test[i] = (char)n;
}
display(test);
}
public static void main(String[] args) {
// sample();
// Instantiate another seeded randomizer below (seed is integer between 0 and 1000, exclusive):
char[] flag = new char[33];
int[] c = {13, 35, 15, -18, 88, 68, -72, -51, 73, -10, 63,
1, 35, -47, 6, -18, 10, 20, -31, 100, -48, 33, -12,
13, -24, 11, 20, -16, -10, -76, -63, -18, 118};
for (int i = 0; i < flag.length; i++) {
int n = (int)(Math.random() * 128) + c[i];
flag[i] = (char)n;
}
display(flag);
}
}
문제 파일을 열어보면 위와 같은 소스 코드가 나온다. main 함수에 33크기의 char형 빈 배열 flag와 값들이 들어가 있는 int형 배열 c가 선언돼 있는데, 이 c를 for문 루프를 통해 33번 반복하며 각 요소에 0~128 범위의 값을 곱해주고 곱해져서 만들어진 값을 char형으로 변환해 flag에 저장해준다.
33번 반복이 끝났다면 display 함수를 통해서 flag에 저장된 문자들을 출력해준다.
코드에는 호출되지 않는 sample이라는 함수가 있는데, 이 sample 함수는 main 함수와 비슷한 매커니즘 같지만 Math.random 함수로 랜덤 값을 생성하는게 아닌 new Random(<value>)로 seed를 설정해준 뒤 랜덤 값을 생성한다.
어쨌든 랜덤 값이 생성되기는 하지만, 문제는 seed를 지정해준다면 완벽한 랜덤 값이 나오는게 아닌 매번 실행해줄 때마다 같은 패턴으로 값이 생성된다. 예를들어 첫 실행에서 1 9 34 2 7가 생성됐다고 하면, 두 번째 실행에서도 마찬가지로 1 9 34 2 7가 같은 순서로 생성되는 것이다.
결론적으로 sample 함수는 b의 값들이 매번 다른 값으로 암호화 되는게 아닌, 몇 번을 실행해도 똑같은 값으로 암호화된다. main 함수의 주석을 보면 main의 flag도 마찬가지로 0 ~ 1000 사이의 값을 seed로 암호화 됐다는 것 같다. 다른 좋은 수도 생각이 안났기 때문에 소스 코드를 수정함으로써 for문으로 0~1000까지의 seed를 이용해 c의 값을 바꿔보기로 했다.
package Javac;
import java.util.Random;
public class SeededRandomizer_exploit
{
public static void main(String[] args)
{
for(int k = 0; k < 1001; k++)
{
Random rand = new Random(k);
char[] flag = new char[33];
int[] c = {13, 35, 15, -18, 88, 68, -72, -51, 73, -10, 63,
1, 35, -47, 6, -18, 10, 20, -31, 100, -48, 33, -12,
13, -24, 11, 20, -16, -10, -76, -63, -18, 118};
for (int i = 0; i < flag.length; i++)
{
int n = (int)(rand.nextInt(128)) + c[i];
flag[i] = (char)n;
}
if(flag[0] == 'f' && flag[1] == 'l' && flag[2] == 'a' && flag[3] == 'g' && flag[4] == '{')
{
for (char x: flag)
System.out.print(x);
System.out.println();
}
}
}
}
main 함수의 코드를 둘러싸는 for문을 만들어 0~1000까지 루프를 돌게 했고, Random rand = new Random(k)를 작성함으로써 0~1000까지의 seed로 flag를 만들어내도록 했다.
마지막으로 결과 값이 무려 1000개가 나오기 때문에 결과를 확인하기 편하도록 연산된 값이 'flag{'로 시작하는 flag 값만 출력하도록 했다.
'CTF' 카테고리의 다른 글
[HackASet 2021] iq (0) | 2021.06.27 |
---|---|
[HSCTF 8] pwn - stonks (0) | 2021.06.20 |
ThcCTF 2021 - Living QR Code (0) | 2021.06.12 |
ThcCTF 2021 - SQL for dummies (0) | 2021.06.12 |
ThcCTF 2021 - Welcome (0) | 2021.06.12 |