네번째 문제 orc
<?php
include "./config.php";
login_chk();
$db = dbconnect();
if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
$query = "select id from prob_orc where id='admin' 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 admin</h2>";
$_GET[pw] = addslashes($_GET[pw]);
$query = "select pw from prob_orc where id='admin' and pw='{$_GET[pw]}'";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("orc");
highlight_file(__FILE__);
?>
이번 문제는 음..쿼리문을 보니까 id값은 admin이 들어가 있고, 패스워드는 GET방식으로 받아오게 돼 있다.
if($result['id']) echo "<h2>Hello admin</h2>";
admin에 알맞는 패스워드가 GET방식으로 들어오면 Hello Admin이 출력되고
빨간색으로 표시된 addslashes()는 이름 그대로 안에 변수에 싱글쿼트('), 더블쿼트("), 백슬래쉬(\), NULL이 포함돼 있다면
그 앞에 슬래쉬(/)를 추가해주는 녀석이다. 이름 그대로 기능을 가졌군.
DB에 INSERT or UPDATE할 때는 필수적으로해줘야 한다는데, SQL Inejction막기 위해서인가?그리고 해당변수를 출력할 때는 stripslashes()를 사용하여 슬래쉬를 없애고 출력해줘야 한다.
음 처음엔 인증과 식별을 동시에 하고 있어서 pw부분을 주석으로 날려 버릴까 했으나아래의 문제를 해결하기 위한 조건을 보니 id가 아니라 내가 입력한 pw값과 DB에 질의해서 가져온 pw값이 일치해야 한다.난감하네, 패스워드를 알아내야 한다.
if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("orc");
패스워드를 알아 내야 한다!
난감하지만 우리에겐 방법이 있지 패스워드의 길이를 알아보자
패스워드 길이를 알아보기위한 방법은 length() 함수를 사용하면 된다.
where id='admin' and pw=' ';
위의 쿼리 조건이다. 우리는 아래와 같이 바꿔주겠다.
where id='admin' and pw='' or id='admin' and length(pw)<10#'; (알다 시피 #는 주소표시줄에 적고 싶으면 %23으로 적자.)
가운데 'or' 연산자를 기준으로 좌측은
id='admin' and pw=' ' 으로 거짓이 되기에 아무것도 출력되지 않고
우측의 id='admin' and length(pw) < 10이 참이 된다면
admin이 있는 행이 출력되기에 $result['id']값에 admin이 들어가 Hello admin이 출력된다.
조건을 <10 / < 9/ < 8 이런식으로 바꿔가며 admin의 패스워드 길이를 알아 낼 수 있다.
이게 귀찮다면 아래와 같이 반복문을 만들어 사용하자.
필자는 파이썬으로 만들었고, request 설치가 안돼 있다면 구글에 검색해보자.
패스워드의 길이를 알아 냈으니 다음은 패스워드를 알아낼 차례이다.
패스워드를 알기 위해선 substr()함수를 사용할줄 알아야 한다.
설명은 아래와 같다.
substr(string,start_index,length)
string : 추출의 대상이 되는 문자열 or 문자열을 저장한 변수
start_index : 추출을 시작하는 위치
length : index로 부터 추출할 문자의 개수 (생략하면 문자열 끝까지 추출)
Ex) substr('korea',3,1) = r / 문자열의 3번째인 r부터 1개의 문자를 추출한다.
Ex)substr('computer',4,2) = pu / 문자열의 4번째인 p부터 2개의 문자를 추출한다.
이 방법을 이용해 비밀번호를 직접 구하려면 8자리를 전부 직접 입력해가며 찾아야 하기에 오래 걸릴 것이다.
?pw=' or id='admin' and substr(pw,0,1)=0 // 어드민의 패스워드 첫번째자리가 0이냐 라고 묻는 것
0~9 / A~Z / a~z / 알파뱃 대소문자 52개, 숫자 10개 한 자리마다 62번을 비교하려면 62* 8 ... 안해
장난이다. 이것 역시 파이썬 반복문으로 돌리자.
우리가 패스워드 8자리의 각 자리마다 비교해야할 것은 0~9 / A~Z / a~z / 이다.
반복할 범위는 아스키값으로 반복하겠다. 48~57 : 0~9 / 65~90 : A~Z / 97~122 : a~z
아래와 같이 각 인덱스별 패스워드를 알아낼 수 있다.
다행히 패스워드 7글자가 숫자라서 직접 대입했어도... 생각보다 오래 걸리지?!는 않았겠다.
'LoSi' 카테고리의 다른 글
6_LoSi_darkelf (0) | 2022.11.23 |
---|---|
5_LoSi_wolfman with whitespace 우회 (0) | 2022.11.23 |
3_LoSi_goblin (0) | 2022.11.22 |
2_LoSi_cobolt (0) | 2022.11.22 |
1_LoSi_gremlin (0) | 2022.11.22 |