Home
System Hacking
🤕

엄준식을 해킹해보자

Type
Exploit
생성 일시
2024/02/23 04:48
종류
Program

엄준식 프로그래밍 언어를 해킹해보자!!!

들어가기에 앞서

유튜브를 보면서 누워있다가 추천 알고리즘에 이런 영상이 떴다.
엄랭이라… 이거 재미있어 보이지 않는가? 그래서 이 프로그램의 소스코드를 하나하나 뜯어보고 취약점을 찾아보고 싶어졌다.

문법

일단 해당 프로그램의 분석을 위해서는 문법을 먼저 알아야 한다고 생각을 했고 문법은 아래와 같다. github에서 확인 가능하니 참고
솔직히 나는 저거 보고도 머리 터지는 줄 알아서 그냥 github 예제보고 해당 문법을 보면서 익혔다… brainfuck
엄랭은 "엄", "준", "식", "동탄" 네개의 키워드와 "!", ".", " ", "~", "ㅋ" 다섯개의 기호로 코드가 이루어집니다. 모든 프로그램은 "어떻게"로 시작하며, 항상 "이 사람이름이냐ㅋㅋ"로 끝나야 합니다.

자료형

정수: 온점, 반점의 갯수로 나타냅니다. 온점의 갯수만큼 1을 더하며, 반점의 갯수만큼 1을 뺍니다.
... => 3 .. => 2 ,, => -2 ,,, => -3 .,., => 0
Plain Text
복사

연산자

1 증가: .
1 감소: ,
곱하기: " "(공백)
.. -> 2 ,, -> -2 ., -> 0 .. .. -> 4 .. ,, -> -4 ... ... ... -> 27
Plain Text
복사

변수

변수는 인덱싱(정수)을 통해 접근하고 대입할 수 있습니다. 지정하지 않았을경우 모든 변수의 기본값은 0입니다.

대입(엄)

연음의 갯수번째 변수에 뒤에 오는 수를 대입합니다
어어엄 => 3번째 변수에 0 지정 어엄 => 2번째 변수에 0 지정 엄.. => 1번째 변수에 2 지정 어엄. => 2번째 변수에 1 지정 엄,,, => 1번째 변수에 -3 지정
Plain Text
복사

사용(어)

연음의 갯수번째 변수를 불러옵니다
어 => 1번째 변수 어어 => 2번째 변수 어어어 => 3번째 변수
Plain Text
복사

초안/미구현 : N번째 변수에 대입 (엌ㅋ)

과  사이에 입력된 수 번째의 변수에 뒤에 오는 수를 대입합니다. 시작하는 엌은 엌ㅋㅋㅋㅋㅋㅋㅋㅋ 등으로, 끝내는 ㅋ는 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 등으로 늘려서 적을 수 있으며, 이에 따른 동작의 변화는 없습니다.
엌..ㅋ => 2번째 변수에 0 지정 엌ㅋㅋㅋㅋㅋ..ㅋㅋㅋㅋㅋ. => 2번째 변수에 1 지정 엌.ㅋ어 => 1번쨰 변수에 `어`값 지정 엌어ㅋ어어 => `어`번째 변수에 `어어` 변수의 값 지정
Plain Text
복사

초안/미구현 : N번쨰 변수 가져오기

와  사이에 입력된 수 번째의 변수의 값을 가져옵니다. 만약 마지막 문자가 이 아니라 이라면 어ㅋ으로 분해해서 평가합니다. 끝내는 ㅋ은 ㅋㅋㅋㅋㅋ등으로 늘려서 적을 수 있으며, 이에 따른 동작의 변화는 없습니다.
어..ㅋ => 2번째 변수 어,,,ㅋ => -3번째 변수 어엌 => 어어ㅋ => `어`번째 변수 어어어,,ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ => (어어 - 2)번째 변수
Plain Text
복사

초안/미구현 : 변수연산

변수 / 상수 덧셈식 뒤에 변수를 이어적으면 뒤에 따르는 변수를 더할 수 있습니다. 사칙연산의 우선순위가 적용되지 않으며, 무조건 왼쪽에서부터 연산합니다.
어, 어어 => 어 - 1 * 어어 => 어 - 어어 어.어어 => 어 + 1 + 어어 어어. 어어 => 어어 + 1 * 어어 => 어어 + 어어 어어 어어 어어 => 어어 ^ 3
Plain Text
복사
정신나갈것같아요

콘솔

식?

콘솔에서 정수를 입력받습니다.
엄식? => 콘솔을 입력받아서 1번째 변수에 대입한다. 어엄식? => 콘솔을 입력받아서 2번째 변수에 대입한다.
Plain Text
복사

식!

콘솔에 정수를 출력합니다.
식..! => 콘솔에 2 출력 식어! => 콘솔에 첫번째 변수 출력
Plain Text
복사

식ㅋ

콘솔에 문자를 출력합니다. 과 사이에 오는 정수를 유니코드 문자로 변환하여 콘솔에 출력합니다. 과 사이에 정수가 주어지지 않으면 개행합니다(식ㅋ => \n)
식........... ........ㅋ => 콘솔에 X 출력
Plain Text
복사

지시문

동탄?

동탄{정수}?{실행할 명령}으로 작성합니다. 정수가 0이라면 실행할 명령이 실행되며, 그렇지 않다면 다음줄로 넘어갑니다.

 뒤에 오는 정수번째 줄로 이동합니다. 준.. => 2번째 줄(글자)로 이동. 원라인코드의 경우에는 ~로 분리된 코드단위로 카운트하여 이동합니다.

화이팅!

화이팅!뒤에 오는 정수를 반환하며 프로그램을 종료합니다.

기타

확장자는 .umm입니다.
One-line 작성은 \n을 ~로 치환합니다. (예제: 구구단 참조)

소스 코드 분석

해당 프로그래밍 언어는 다양한 언어를 지원한다.
하지만 여기서 중점적으로 분석할 부분은 엄랭의 C언어 버전이다.

Command Injection

//83-- switch (mode) { case SRC: if (output_path[0] == 0) { strcpy(output_path, strrchr(input_path, '/') + 1); strcpy(strrchr(output_path, '.'), ".c"); } output = fopen(output_path, "w"); ispipe = 0; break; case ASM: if (output_path[0] == 0) { strcpy(output_path, strrchr(input_path, '/') + 1); strcpy(strrchr(output_path, '.'), ".s"); } sprintf(command, "gcc -S -x c - -o \"%s\"", output_path); output = popen(command, "w"); break; default: if (output_path[0] == 0) { strcpy(output_path, "a.out"); } sprintf(command, "gcc -x c - -o \"%s\"", output_path); output = popen(command, "w"); break; } //113++
C
복사
main.c 83 Line
Command Injection 취약점을 찾는건 사실 10분도 안걸린거 같다.
popen 함수를 사용하여 command에 있는 컴파일 명령어를 실행한 다는 것을 찾았고, sprintf 함수를 이용하여 output_path의 값을 넣는다.
또한 modedefault일때 추가적인 연산 없이 바로 output_path의 내용을 command 변수에 집어 넣는다. 따라서 string escape만 진행한다면 Command Injection이 가능할 것이라고 판단하여 output_path가 어디서 만들어지는지 분석했다.
//34-- else if (strcmp(argv[i], "-o") == 0 && i + 1 < argc) { strcpy(output_path, argv[++i]); } else if (strcmp(argv[i], "-c") == 0) { mode = SRC; } else if (strcmp(argv[i], "-s") == 0) { mode = ASM; } //47++
C
복사
main.c 34 Line
빙고! strcpy 함수를 이용하여 -o 옵션 뒤에 오는 문자열을 복사하여 output_path에 넣고 -c와 -s 옵션이 오는 경우 mode를 SRC, ASM으로 변경한다.

Payload

./umcc -o "payload\";id\"" ../../examples/gugudan.umm
C
복사

Stack OverFlow

Analysis

사실 위에 코드를 조금이라고 읽은 사람이 있다면 Stack OverFlow 취약점이 존재한다는 것도 확인할 수 있다.
else if (strcmp(argv[i], "-o") == 0 && i + 1 < argc) { strcpy(output_path, argv[++i]); }
C
복사
main.c 35 Line
else { strcpy(input_path, argv[i]); }
C
복사
main.c 53 Line

여담

사실, parse 부분에서 취약점을 찾아보고 싶었는데, 해당 부분에서는 문자열을 \n로 잘라서 처리하고 있고, malloc으로 문자열을 할당하고 있어서 별 문제 없었다.
기본적인 감산과 가산만 지원하고 있고, 예약된 문자열을 특정 함수나 문자, 숫자로 바꾸는 작업만 하니까 더 찾아볼만한 취약점이 없다. 솔직히 보다 보니 머리 아파서 거의 터질 뻔…
분석 결과 엄랭은 문자열을 단순 parsing하여 예약된 문자열을 ouput filefwrite하는 작업만 수행해서 해당 파일을 gcc 컴파일하기 때문에 다른 취약점을 찾지는 못했다…

도움준 사람

박현

Reference