Today I Learned …

[Lord of SQL Injection] 1번 gremlin 풀이 본문

Wargame/Lord of SQL Injection

[Lord of SQL Injection] 1번 gremlin 풀이

염베리 2021. 10. 29. 23:46

* 워게임 풀이 과정을 기록합니다.


사담

음.. 너무 바쁘다..ㅠ

오늘은 간단히 워게임 1번 풀이를 해보도록 하겠다... 핳

 

Lord of SQL Injection 간단 소개

말그대로 SQL Injection의 지배자(?)가 되자는.. 그런!

노말틱님이 추천해주신 워게임으로 SQL Injection을 연습하는데 큰 도움이 되는 사이트다.

종종 풀면서 감을 익히면 좋을 것 같아서 앞으로 차곡차곡 풀이를 올려보려고 한다.


1번 문제 gremlin 분석

 

설레는 마음으로 들어가보면 아래와 같은 화면이 반겨준다.

 

 

....???

일단 워게임 경험이 거의 없는 나로서는 첫번째 당황 = 폼이 없다...?

잠시 쳐다보니 코드 중간에 GET이라는 글자가 눈에 띄었다.

GET이란 결국 url에 정보를 담아 전달하는 메소드이다.

그렇다면 = 답을 url에 적어서 넘겨주면 되는 구조라는 것을 알 수 있었다.

 

첫 줄부터 내려오다보면 낯선 함수가 보인다.

 

preg_match() 란?

인자로 전달받은 정규 표현식과 일치하는 패턴을 검색하는 php의 함수이다.

 

정규 표현식이란?

문자열을 바탕으로 검색을 수행하여 패턴과 일치하는지 조사하고, 분할하는 문자열 처리 방법이다.

(나중에 더 자세히 다룰 일이 있을 것 같다.)

 

말이 어렵지만 결국

preg_match() 함수에 인자로 들어오는 정규식 표현을 토대로

검색 대상 문자열을 싹 다 훑어서 해당 정규식 표현과 일치하는 패턴을 찾아낸다는 말이다.

 

이해가 안될때는 예시를 봐야한다 핳

 

preg_match() 는 세가지 인자를 받는다.

1. 정규식 표현

2. 검색 대상 문자열

3. 매칭된 값을 배열로 저장하고 싶을 시, 배열의 변수

 

따라서 다음과 같은 모양이다.

 

preg_match('/정규식표현/', '검색대상문자열', '배열변수')

 

또는 아래와 같다.

 

preg_match($pattern, $subject, $matches)

 

$pattern 부분에 정규식 표현을 작성하고,

$subject 부분에 검색 대상 문자열을 알려주고,

매칭된 값을 따로 배열에 저장하고 싶다면 $matches 를 적어주면 되는 것이다.

 

이제 다시 문제로 돌아가보면 다음 코드가 의미하는 바를 알 수 있다.

 

preg_match('/prob|_|\.|\(\)/i', $_GET[id])

 

GET으로 받은 id 값을 대상으로,

1. /prob

2. _

3. .

4. (

5. )

위 다섯가지 표현을 검색한다는 것이다.

 

참고로 preg_match() 함수는 검색 결과가 있을 시 1을, 없을 시 0을 반환한다.

 

여기까지 오면 아래 코드도 이해가 된다.

 

if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~");

 

결국 이 한 줄이 의미하는 바는,

GET으로 받은 id 값을 대상으로 다섯가지 표현을 검색한 후,

매칭되는 패턴이 존재하면 exit 된다는 뜻이다.

(pw 값에도 같은 필터링 규칙이 적용된다.)

 

보다시피 우리가 사용할 싱글쿼터나 더블쿼터는 필터링하고 있지 않기 때문에,

기본적인 SQL Injection으로 해결할 수 있을 것으로 보인다.

 

이제 그 아랫줄을 보겠다.

 

$query = "select id from prob_gremlin where id='{$_GET[id]}' and pw='{$_GET[pw]}'";
$result = @mysqli_fetch_array(mysqli_query($db,$query));

 

GET으로 전달받은 id와 pw가 동시에 일치하는 레코드의 id 값을 갖고 오겠다는 것이다.

 

이해에 무리가 없으니 그 아랫줄로 넘어가겠다.

 

if($result['id']) solve("gremlin");

 

아까 fetch해준 $result에 id 값이 정상적으로 존재하면 gremlin 문제가 풀린다는 것을 알 수 있다.


1번 문제 gremlin 풀이

 

위 분석을 통해,

WHERE 절 뒷부분을 True로 만들어 조건을 충족시켜주면 간단히 풀리는

가장 기본적인 예제였음을 알 수 있다.

 

쿼리문을 다시 한번 보겠다.

 

"select id from prob_gremlin where id='{$_GET[id]}' and pw='{$_GET[pw]}'"

 

저 노란색 부분에

 

' or 1 = 1 #

 

을 입력해주면 최종 쿼리문은 다음과 같이 완성된다.

 

"select id from prob_gremlin where id='' or 1 = 1 # ' and pw='{$_GET[pw]}'"

 

결과적으로 노란색 부분 (= 조건절) 이 참이 되며

prob_gremlin의 모든 id를 가져오게 된다.

(물론 mysqli_fetch_array 함수의 특성상 한번의 콜에 하나의 행만 가져온다.)

 

그렇게 되면 $result['id']에는 prob_gremlin 첫 행의 id 값이 담기게 되고, 문제는 풀리게 된다.

 

자, 그럼 처음에 언급했듯, ' or 1 = 1 # 을 url 뒤에 붙여준다.

 

 

엔터 쳐보면... 안된다 ㅎ

 

url에 직접 값을 붙여줄때는

url encoding을 거쳐줘야하기 때문이다.

 

# 은 인코딩했을 때 %23 이다.

자주 쓰기 때문에 외워두면 좋고,

구글링하면 나오는 url encoder를 사용해도 된다.

 

그럼 다시 입력해보자.

 

 

다시 엔터쳐보면!

 

 

첫 문제가 드디어 풀렸다!

 

앞으로 계속 나올 개념들이라 부연 설명이 다소 길었지만

다음 문제부터는 간략하게 핵심 위주로 기록하려고 한다.

 

간단하게 쓰려고 했는데... 끝!

프로필사진
berry
FE Developer, loves React & better DX
Comments