query가 두 개 존재하는 문제이다. 잘 보면 위쪽 query 는 no 값에 아무런 quotation 이 사용되고 있지 않다. 반면에 아래의 query2는 single quotation 이 사용된 모습이다.
먼저 두 개의 query를 동시에, 동일한 query로 만들어주어야 할 것이다. 싱글쿼터와 주석을 잘 활용하면 될 것 같다. 다음과 같이 작성해보자.
no=1 union select 1#' union select '1
결과는 아래와 같다.
query : select id from prob_alien where no=1 union select 1#' union select '1
query2 : select id from prob_alien where no='1 union select 1#' union select '1'
모두 동일하게 'union select 1'을 갖게 된다. 이제 다음 코드라인들로 넘어가보자. 여기서부터가 중요한 문제이다.
코드를 순차적으로 보면 상당히 모순적인 것처럼 보인다. 첫 번째 fetch 에서는 id가 admin이 아니면 exit 된다. 이후 두 번째 fetch에서는 id가 admin이면 exit 된다. query2에서는 약간 다르지만 비슷한 양상이다. 결과적으로 각 부분에서 fetch가 될 때마다 필요한 id 값은 다음과 같다.
- admin
- not admin
- not admin
- admin
우리는 concat 함수를 이용하여 id 값이 admin이 될지, bdmin이 될지 결정할 것이다. char 함수의 인자에 'a'에 해당하는 아스키코드 값 '97'을 넣어준 뒤에 그 뒤에 합연산을 한다.
여기서 sleep 함수를 넣어주었는데, now 함수는 현재 시스템 시간을 반환하는 함수이기 때문에,
!sleep(1)&&(now()%2=1)
값이 0 또는 1이 나오기 위해서는 1초의 sleep이 필요하다. sleep 함수는 정상적으로 잠에 들 경우 '0'을 반환한다. 따라서 AND 연산의 대상으로는 적합하지 않기 때문에 이 앞에 NOT 연산을 해줌으로써 정상적으로 수행될 경우에 !sleep(1)은 '1'을 반환하게 된다.
또한 쿼터 문자에 잡혀있는 query 문은 실행되지 않는 그저 문자열밖에 되지 않는 존재이다. 이 점과 query, query2 의 특징을 분석하여 시스템 시간이 짝수일 때, 홀수일 때의 경우를 각각 차근차근 계산해보면, query2가 받는 query문 부분에서 기존의 now()%2=1 이 아닌 now()%2=0 이 되어야 한다는 것을 알 수 있다.
결과적으로 payload는 다음과 같다.
no=1 union select concat(char(97%2b(!sleep(1)%26%26(now()%2=1))),"dmin")%23' union select concat(char(97%2b(!sleep(1)%26%26(now()%2=0))),"dmin")%23
꽤나 rough 하고 흥미로운 문제였다. -_-
'Web Hacking > LOS' 카테고리의 다른 글
Lord of SQL Injection - cthulhu (1) | 2021.10.02 |
---|---|
Lord of SQL Injection - ouroborus (0) | 2021.10.02 |
Lord of SQL Injection - zombie (0) | 2021.10.02 |
Lord of SQL Injection - frankenstein (0) | 2021.09.01 |
Lord of SQL Injection - phantom (1) | 2021.09.01 |